Stream slave accel via ESP-NOW with master snapshot cache.

Slaves push BMA456 samples at 16ms when enabled; the master caches per
client and exposes ACCEL_SNAPSHOT and ACCEL_STREAM over UART. goTool adds
dashboard stream controls, HTTP accel-stream routes, and an external
WebSocket API with per-connection receive/interval and slave stream commands.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-05-29 19:11:36 +02:00
co-authored by Cursor
parent ba20544762
commit 47c75110c9
35 changed files with 2409 additions and 300 deletions
+79
View File
@@ -241,6 +241,85 @@ size_t client_registry_set_accel_deadzone_all(uint32_t deadzone) {
return n;
}
static void clear_client_accel(client_slot_t *slot) {
if (slot == NULL) {
return;
}
slot->info.accel_valid = false;
slot->info.accel_x = 0;
slot->info.accel_y = 0;
slot->info.accel_z = 0;
slot->info.accel_updated_at = 0;
}
esp_err_t client_registry_set_accel_stream(uint32_t client_id, bool enabled) {
for (size_t i = 0; i < CLIENT_REGISTRY_MAX; i++) {
if (!s_clients[i].active || s_clients[i].info.id != client_id) {
continue;
}
s_clients[i].info.accel_stream_enabled = enabled;
if (!enabled) {
clear_client_accel(&s_clients[i]);
}
return ESP_OK;
}
return ESP_ERR_NOT_FOUND;
}
esp_err_t client_registry_get_accel_stream(uint32_t client_id,
bool *enabled_out) {
if (enabled_out == NULL) {
return ESP_ERR_INVALID_ARG;
}
const client_info_t *info = client_registry_find_by_id(client_id);
if (info == NULL) {
return ESP_ERR_NOT_FOUND;
}
*enabled_out = info->accel_stream_enabled;
return ESP_OK;
}
size_t client_registry_set_accel_stream_all(bool enabled) {
size_t n = 0;
for (size_t i = 0; i < CLIENT_REGISTRY_MAX; i++) {
if (!s_clients[i].active) {
continue;
}
s_clients[i].info.accel_stream_enabled = enabled;
if (!enabled) {
clear_client_accel(&s_clients[i]);
}
n++;
}
return n;
}
esp_err_t client_registry_update_accel(const uint8_t mac[CLIENT_MAC_LEN],
uint32_t slave_id, int16_t x, int16_t y,
int16_t z) {
if (mac == NULL) {
return ESP_ERR_INVALID_ARG;
}
client_slot_t *slot = find_slot(mac);
if (slot == NULL) {
return ESP_ERR_NOT_FOUND;
}
if (slot->info.id != slave_id) {
return ESP_ERR_INVALID_ARG;
}
if (!slot->info.accel_stream_enabled) {
return ESP_ERR_INVALID_STATE;
}
slot->info.accel_x = x;
slot->info.accel_y = y;
slot->info.accel_z = z;
slot->info.accel_valid = true;
slot->info.accel_updated_at = now_ms();
return ESP_OK;
}
const client_info_t *client_registry_at(size_t index) {
size_t n = 0;
for (size_t i = 0; i < CLIENT_REGISTRY_MAX; i++) {