Add BMA456 tap detection with ESP-NOW notify and host snapshot API.
Slaves forward configured tap kinds to the master; goTool exposes CLI, dashboard, REST, and WebSocket with separate notify vs receive and 2s display cache. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -257,6 +257,31 @@ static void clear_client_accel(client_slot_t *slot) {
|
||||
slot->info.accel_updated_at = 0;
|
||||
}
|
||||
|
||||
static void clear_client_tap(client_slot_t *slot) {
|
||||
if (slot == NULL) {
|
||||
return;
|
||||
}
|
||||
slot->info.tap_valid = false;
|
||||
slot->info.tap_kind = 0;
|
||||
slot->info.tap_updated_at = 0;
|
||||
}
|
||||
|
||||
static bool tap_kind_enabled(const client_info_t *info, uint32_t kind) {
|
||||
if (info == NULL) {
|
||||
return false;
|
||||
}
|
||||
switch (kind) {
|
||||
case 1:
|
||||
return info->tap_notify_single;
|
||||
case 2:
|
||||
return info->tap_notify_double;
|
||||
case 3:
|
||||
return info->tap_notify_triple;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
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) {
|
||||
@@ -325,6 +350,124 @@ esp_err_t client_registry_update_accel(const uint8_t mac[CLIENT_MAC_LEN],
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t client_registry_set_tap_notify(uint32_t client_id, bool single,
|
||||
bool double_tap, bool triple) {
|
||||
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.tap_notify_single = single;
|
||||
s_clients[i].info.tap_notify_double = double_tap;
|
||||
s_clients[i].info.tap_notify_triple = triple;
|
||||
if (!single && !double_tap && !triple) {
|
||||
clear_client_tap(&s_clients[i]);
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
return ESP_ERR_NOT_FOUND;
|
||||
}
|
||||
|
||||
esp_err_t client_registry_get_tap_notify(uint32_t client_id, bool *single_out,
|
||||
bool *double_tap_out,
|
||||
bool *triple_out) {
|
||||
if (single_out == NULL || double_tap_out == NULL || triple_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;
|
||||
}
|
||||
*single_out = info->tap_notify_single;
|
||||
*double_tap_out = info->tap_notify_double;
|
||||
*triple_out = info->tap_notify_triple;
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
size_t client_registry_set_tap_notify_all(bool single, bool double_tap,
|
||||
bool triple) {
|
||||
size_t n = 0;
|
||||
for (size_t i = 0; i < CLIENT_REGISTRY_MAX; i++) {
|
||||
if (!s_clients[i].active) {
|
||||
continue;
|
||||
}
|
||||
s_clients[i].info.tap_notify_single = single;
|
||||
s_clients[i].info.tap_notify_double = double_tap;
|
||||
s_clients[i].info.tap_notify_triple = triple;
|
||||
if (!single && !double_tap && !triple) {
|
||||
clear_client_tap(&s_clients[i]);
|
||||
}
|
||||
n++;
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
esp_err_t client_registry_update_tap(const uint8_t mac[CLIENT_MAC_LEN],
|
||||
uint32_t slave_id, uint32_t kind) {
|
||||
if (mac == NULL || kind < 1 || kind > 3) {
|
||||
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 (!tap_kind_enabled(&slot->info, kind)) {
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
|
||||
slot->info.tap_kind = kind;
|
||||
slot->info.tap_valid = true;
|
||||
slot->info.tap_updated_at = now_ms();
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
void client_registry_expire_tap(client_info_t *info) {
|
||||
if (info == NULL || !info->tap_valid) {
|
||||
return;
|
||||
}
|
||||
if (client_registry_ms_since(info->tap_updated_at) >
|
||||
CLIENT_REGISTRY_TAP_MAX_AGE_MS) {
|
||||
info->tap_valid = false;
|
||||
info->tap_kind = 0;
|
||||
info->tap_updated_at = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void client_registry_clear_tap(client_info_t *info) {
|
||||
if (info == NULL) {
|
||||
return;
|
||||
}
|
||||
info->tap_valid = false;
|
||||
info->tap_kind = 0;
|
||||
info->tap_updated_at = 0;
|
||||
}
|
||||
|
||||
bool client_registry_take_tap(uint32_t client_id, uint32_t *kind_out,
|
||||
uint32_t *age_ms_out) {
|
||||
for (size_t i = 0; i < CLIENT_REGISTRY_MAX; i++) {
|
||||
if (!s_clients[i].active || s_clients[i].info.id != client_id) {
|
||||
continue;
|
||||
}
|
||||
client_info_t *info = &s_clients[i].info;
|
||||
client_registry_expire_tap(info);
|
||||
if (!info->tap_valid) {
|
||||
return false;
|
||||
}
|
||||
if (kind_out != NULL) {
|
||||
*kind_out = info->tap_kind;
|
||||
}
|
||||
if (age_ms_out != NULL) {
|
||||
*age_ms_out = client_registry_ms_since(info->tap_updated_at);
|
||||
}
|
||||
client_registry_clear_tap(info);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void client_registry_set_master_battery(const board_lipo_reading_t *reading) {
|
||||
if (reading == NULL) {
|
||||
return;
|
||||
|
||||
Reference in New Issue
Block a user