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:
@@ -43,6 +43,9 @@ static uint8_t s_wifi_channel;
|
||||
static uint8_t s_own_mac[ESP_NOW_ETH_ALEN];
|
||||
static bool s_slave_joined;
|
||||
static bool s_accel_stream_enabled;
|
||||
static bool s_tap_notify_single;
|
||||
static bool s_tap_notify_double;
|
||||
static bool s_tap_notify_triple;
|
||||
static uint8_t s_master_mac[ESP_NOW_ETH_ALEN];
|
||||
static uint32_t s_last_discover_ms;
|
||||
|
||||
@@ -138,6 +141,28 @@ static esp_err_t send_accel_sample(const uint8_t *dest_mac, uint32_t slave_id,
|
||||
return send_message(dest_mac, &msg);
|
||||
}
|
||||
|
||||
static esp_err_t send_tap_event(const uint8_t *dest_mac, uint32_t slave_id,
|
||||
uint32_t kind) {
|
||||
alox_EspNowMessage msg = alox_EspNowMessage_init_zero;
|
||||
msg.type = alox_EspNowMessageType_ESPNOW_TAP_EVENT;
|
||||
msg.which_payload = alox_EspNowMessage_tap_event_tag;
|
||||
msg.payload.tap_event.slave_id = slave_id;
|
||||
msg.payload.tap_event.kind = kind;
|
||||
return send_message(dest_mac, &msg);
|
||||
}
|
||||
|
||||
static esp_err_t send_tap_notify(const uint8_t *dest_mac, uint32_t client_id,
|
||||
bool single, bool double_tap, bool triple) {
|
||||
alox_EspNowMessage msg = alox_EspNowMessage_init_zero;
|
||||
msg.type = alox_EspNowMessageType_ESPNOW_SET_TAP_NOTIFY;
|
||||
msg.which_payload = alox_EspNowMessage_tap_notify_tag;
|
||||
msg.payload.tap_notify.client_id = client_id;
|
||||
msg.payload.tap_notify.single = single;
|
||||
msg.payload.tap_notify.double_tap = double_tap;
|
||||
msg.payload.tap_notify.triple = triple;
|
||||
return send_message(dest_mac, &msg);
|
||||
}
|
||||
|
||||
static esp_err_t send_message_ex(const uint8_t *dest_mac,
|
||||
const alox_EspNowMessage *msg, bool wait_done) {
|
||||
uint8_t buf[ESPNOW_PB_MAX_SIZE];
|
||||
@@ -455,6 +480,29 @@ esp_err_t esp_now_comm_send_accel_stream(const uint8_t mac[CLIENT_MAC_LEN],
|
||||
return err;
|
||||
}
|
||||
|
||||
esp_err_t esp_now_comm_send_tap_notify(const uint8_t mac[CLIENT_MAC_LEN],
|
||||
uint32_t client_id, bool single,
|
||||
bool double_tap, bool triple) {
|
||||
if (mac == NULL || !s_config.master) {
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
|
||||
char mac_str[18];
|
||||
mac_to_str(mac, mac_str, sizeof(mac_str));
|
||||
esp_err_t err =
|
||||
send_tap_notify(mac, client_id, single, double_tap, triple);
|
||||
if (err == ESP_OK) {
|
||||
ESP_LOGI(TAG,
|
||||
"unicast SET_TAP_NOTIFY to %s: single=%d double=%d triple=%d "
|
||||
"client_id=%lu",
|
||||
mac_str, single, double_tap, triple, (unsigned long)client_id);
|
||||
} else {
|
||||
ESP_LOGW(TAG, "unicast SET_TAP_NOTIFY to %s failed: %s", mac_str,
|
||||
esp_err_to_name(err));
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
esp_err_t esp_now_comm_send_accel_deadzone(const uint8_t mac[CLIENT_MAC_LEN],
|
||||
uint32_t client_id, uint32_t deadzone) {
|
||||
if (mac == NULL || !s_config.master) {
|
||||
@@ -705,6 +753,30 @@ static void handle_slave_accel_stream(const uint8_t *master_mac,
|
||||
cfg->enable ? "on" : "off", mac_str, (unsigned long)my_id);
|
||||
}
|
||||
|
||||
static void handle_slave_tap_notify(const uint8_t *master_mac,
|
||||
const alox_EspNowTapNotify *cfg) {
|
||||
uint32_t my_id = s_own_mac[5];
|
||||
|
||||
if (cfg->client_id != 0 && cfg->client_id != my_id) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (s_slave_joined && !mac_equal(master_mac, s_master_mac)) {
|
||||
return;
|
||||
}
|
||||
|
||||
s_tap_notify_single = cfg->single;
|
||||
s_tap_notify_double = cfg->double_tap;
|
||||
s_tap_notify_triple = cfg->triple;
|
||||
|
||||
char mac_str[18];
|
||||
mac_to_str(master_mac, mac_str, sizeof(mac_str));
|
||||
ESP_LOGI(TAG,
|
||||
"tap notify single=%d double=%d triple=%d from master %s (id=%lu)",
|
||||
cfg->single, cfg->double_tap, cfg->triple, mac_str,
|
||||
(unsigned long)my_id);
|
||||
}
|
||||
|
||||
static void handle_slave_accel_deadzone(const uint8_t *master_mac,
|
||||
const alox_EspNowAccelDeadzone *cfg) {
|
||||
uint32_t my_id = s_own_mac[5];
|
||||
@@ -749,6 +821,24 @@ static void handle_master_accel_sample(const uint8_t mac[CLIENT_MAC_LEN],
|
||||
}
|
||||
}
|
||||
|
||||
static void handle_master_tap_event(const uint8_t mac[CLIENT_MAC_LEN],
|
||||
const alox_EspNowTapEvent *event) {
|
||||
if (event == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
esp_err_t err =
|
||||
client_registry_update_tap(mac, event->slave_id, event->kind);
|
||||
if (err == ESP_ERR_NOT_FOUND) {
|
||||
return;
|
||||
}
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGW(TAG, "tap event id=%lu kind=%lu rejected from %02x:…:%02x",
|
||||
(unsigned long)event->slave_id, (unsigned long)event->kind, mac[0],
|
||||
mac[5]);
|
||||
}
|
||||
}
|
||||
|
||||
static void handle_client_presence(const alox_EspNowSlavePresence *presence,
|
||||
const uint8_t mac[CLIENT_MAC_LEN]) {
|
||||
if (presence->network != s_config.network) {
|
||||
@@ -855,6 +945,34 @@ static void slave_accel_stream_task(void *param) {
|
||||
}
|
||||
}
|
||||
|
||||
static void on_bma456_tap(bma456_tap_kind_t kind, void *ctx) {
|
||||
(void)ctx;
|
||||
|
||||
if (!s_slave_joined) {
|
||||
return;
|
||||
}
|
||||
|
||||
bool enabled = false;
|
||||
switch (kind) {
|
||||
case BMA456_TAP_SINGLE:
|
||||
enabled = s_tap_notify_single;
|
||||
break;
|
||||
case BMA456_TAP_DOUBLE:
|
||||
enabled = s_tap_notify_double;
|
||||
break;
|
||||
case BMA456_TAP_TRIPLE:
|
||||
enabled = s_tap_notify_triple;
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
if (!enabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
(void)send_tap_event(s_master_mac, s_own_mac[5], (uint32_t)kind);
|
||||
}
|
||||
|
||||
static void slave_heartbeat_task(void *param) {
|
||||
(void)param;
|
||||
uint32_t last_battery_ms = 0;
|
||||
@@ -942,6 +1060,12 @@ static void espnow_recv_cb(const esp_now_recv_info_t *info, const uint8_t *data,
|
||||
}
|
||||
handle_slave_accel_stream(info->src_addr, &msg.payload.accel_stream);
|
||||
break;
|
||||
case alox_EspNowMessage_tap_notify_tag:
|
||||
if (!s_slave_joined || !mac_equal(info->src_addr, s_master_mac)) {
|
||||
break;
|
||||
}
|
||||
handle_slave_tap_notify(info->src_addr, &msg.payload.tap_notify);
|
||||
break;
|
||||
case alox_EspNowMessage_battery_query_tag:
|
||||
if (!s_slave_joined || !mac_equal(info->src_addr, s_master_mac)) {
|
||||
break;
|
||||
@@ -1007,6 +1131,12 @@ static void espnow_recv_cb(const esp_now_recv_info_t *info, const uint8_t *data,
|
||||
return;
|
||||
}
|
||||
|
||||
if (msg.which_payload == alox_EspNowMessage_tap_event_tag) {
|
||||
ensure_peer(info->src_addr);
|
||||
handle_master_tap_event(info->src_addr, &msg.payload.tap_event);
|
||||
return;
|
||||
}
|
||||
|
||||
if (msg.which_payload == alox_EspNowMessage_battery_report_tag) {
|
||||
ensure_peer(info->src_addr);
|
||||
handle_master_battery_report(info->src_addr, &msg.payload.battery_report);
|
||||
@@ -1133,6 +1263,7 @@ esp_err_t esp_now_comm_init(const app_config_t *config) {
|
||||
ESP_LOGE(TAG, "failed to create accel stream task");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
bma456_set_tap_handler(on_bma456_tap, NULL);
|
||||
}
|
||||
|
||||
return ESP_OK;
|
||||
|
||||
Reference in New Issue
Block a user