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:
+54
-1
@@ -116,6 +116,8 @@ Schema: `proto/esp_now_messages.proto`. Encode/decode: `esp_now_proto.c`. The ES
|
||||
| `ESPNOW_FIND_ME` | Master → slave | `EspNowFindMe` (`client_id` filter) — LED locate sequence |
|
||||
| `ESPNOW_RESTART` | Master → slave | `EspNowRestart` (`client_id` filter) — reboot slave |
|
||||
| `ESPNOW_ACCEL_SAMPLE` | Slave → master | `EspNowAccelSample` (`slave_id`, `x`, `y`, `z` raw LSB) — ~every 16 ms |
|
||||
| `ESPNOW_SET_TAP_NOTIFY` | Master → slave | `EspNowTapNotify` (`client_id`, `single`, `double_tap`, `triple`) — which tap kinds to forward |
|
||||
| `ESPNOW_TAP_EVENT` | Slave → master | `EspNowTapEvent` (`client_id`, `kind`) — on BMA456 tap interrupt if notify enabled |
|
||||
| `ESPNOW_BATTERY_REPORT` | Slave → master | `EspNowBatteryReport` (`client_id`, `lipo1/2` mV) — ~every 30 s; cached in `client_registry` |
|
||||
| `ESPNOW_OTA_START` | Master → slave (unicast) | `EspNowOtaStart` (`total_size`) |
|
||||
| `ESPNOW_OTA_PAYLOAD` | Master → slave | `EspNowOtaPayload` (`seq`, up to 200 B `data`) |
|
||||
@@ -221,6 +223,8 @@ Host and master speak nanopb-encoded `UartMessage` inside UART frames (byte 0 =
|
||||
| 22 | `FIND_ME` | Implemented (`cmd/cmd_espnow_find_me.c`) — `client_id=0` local ring, `>0` ESP-NOW to slave |
|
||||
| 23 | `RESTART` | Implemented (`cmd/cmd_restart.c`) — `client_id=0` reboot master, `>0` ESP-NOW reboot slave |
|
||||
| 24 | `ACCEL_SNAPSHOT` | Implemented (`cmd/cmd_accel_snapshot.c`) — cached slave accel from ESP-NOW stream |
|
||||
| 27 | `TAP_NOTIFY` | Implemented (`cmd/cmd_tap_notify.c`) — get/set which tap kinds notify via ESP-NOW |
|
||||
| 28 | `TAP_SNAPSHOT` | Implemented (`cmd/cmd_tap_snapshot.c`) — consume cached tap events from master registry |
|
||||
|
||||
Regenerate C code:
|
||||
|
||||
@@ -337,6 +341,52 @@ go run . -port /dev/ttyUSB0 accel
|
||||
|
||||
External API (`serve -api-addr :8081`) polls this command every 16 ms and streams JSON over WebSocket.
|
||||
|
||||
### TAP_NOTIFY command
|
||||
|
||||
Configure which BMA456 tap kinds a **slave** forwards to the master over ESP-NOW. The slave only sends `ESPNOW_TAP_EVENT` when the matching notify flag is enabled (set locally on the slave via ESP-NOW).
|
||||
|
||||
**Request:** framed `1b` (`0x1b`) + `tap_notify_request`:
|
||||
|
||||
| Field | Meaning |
|
||||
|-------|---------|
|
||||
| `write` | `false` = read, `true` = write |
|
||||
| `single`, `double_tap`, `triple` | Which tap kinds to notify (write) |
|
||||
| `client_id` | Slave id (read/write one slave) |
|
||||
| `all_clients` | Master: ESP-NOW unicast to every registered slave |
|
||||
|
||||
**Response:** `tap_notify_response` (`client_id`, `success`, `slaves_updated`, `single`, `double_tap`, `triple`).
|
||||
|
||||
Notify flags are mirrored in `ClientInfo` (`tap_notify_single/double/triple`) for the dashboard.
|
||||
|
||||
```bash
|
||||
go run . -port /dev/ttyUSB0 tap-notify -client 16 -set -single
|
||||
go run . -port /dev/ttyUSB0 tap-notify -client 16
|
||||
```
|
||||
|
||||
### TAP_SNAPSHOT command
|
||||
|
||||
Read **cached** tap events on the **master** (one pending event per slave). Slaves send `ESPNOW_TAP_EVENT` on tap; the master stores the latest value per client in `client_registry.c` for up to **16 ms** (`CLIENT_REGISTRY_TAP_MAX_AGE_MS`). Each snapshot **consumes** fresh events (cleared after read).
|
||||
|
||||
Only slaves with at least one tap-notify flag enabled are included.
|
||||
|
||||
**Request:** framed `1c` (`0x1c`) + optional `tap_snapshot_request` (`client_id`: `0` = all, `>0` = one id).
|
||||
|
||||
**Response:** `tap_snapshot_response.events[]`:
|
||||
|
||||
| Field | Meaning |
|
||||
|-------|---------|
|
||||
| `client_id` | Slave id (registry) |
|
||||
| `valid` | Fresh tap available (≤16 ms) |
|
||||
| `kind` | `TAP_SINGLE`, `TAP_DOUBLE`, or `TAP_TRIPLE` |
|
||||
| `age_ms` | Ms since tap was received on master |
|
||||
|
||||
Host tools poll this only when **receive** is enabled (dashboard tap column, WebSocket `set_tap_stream`). They keep events visible for **2 s** in the UI/API after first sight.
|
||||
|
||||
```bash
|
||||
go run . -port /dev/ttyUSB0 tap
|
||||
go run . -port /dev/ttyUSB0 tap -client 16
|
||||
```
|
||||
|
||||
### ESPNOW_UNICAST_TEST command
|
||||
|
||||
Minimal master→slave ESP-NOW unicast check (no BMA456). Use this before debugging `ACCEL_DEADZONE` unicast.
|
||||
@@ -424,7 +474,7 @@ go run . -port /dev/ttyUSB0 led-ring -mode digit -digit 5 -all
|
||||
|
||||
**Response:** payload `04` + nanopb `UartMessage` with `client_info_response.clients` — one `ClientInfo` per registered slave (from ESP-NOW `SLAVE_INFO`).
|
||||
|
||||
Fields per client: `id`, `mac`, `version`, `available`, `used`, `last_ping`, `last_success_ping` — **milliseconds since** the last packet / last successful heartbeat (computed when `CLIENT_INFO` is answered; typically 0–1000 while the slave is heartbeating every 1 s).
|
||||
Fields per client: `id`, `mac`, `version`, `available`, `used`, `last_ping`, `last_success_ping`, `tap_notify_single`, `tap_notify_double`, `tap_notify_triple` — **milliseconds since** the last packet / last successful heartbeat (computed when `CLIENT_INFO` is answered; typically 0–1000 while the slave is heartbeating every 1 s).
|
||||
|
||||
## Client registry
|
||||
|
||||
@@ -435,6 +485,7 @@ Fields per client: `id`, `mac`, `version`, `available`, `used`, `last_ping`, `la
|
||||
| `client_registry_heartbeat(mac, id, version, …)` | Same as upsert for heartbeats; reactivates inactive clients |
|
||||
| `client_registry_check_timeouts(timeout_ms)` | Mark stale clients inactive (master monitor task) |
|
||||
| `client_registry_count()` / `client_registry_at(i)` | Iterate for UART encoding |
|
||||
| `client_registry_set_tap_notify()` / `client_registry_take_tap()` | Tap notify flags + short-lived tap cache (16 ms) |
|
||||
|
||||
Slaves register when the master receives `SLAVE_INFO` on the matching network; `HEARTBEAT` keeps them marked available. The registry **MAC is always the ESP-NOW source address** (`recv_info.src_addr`), not the optional `mac` bytes in the protobuf (used only on the wire for debugging).
|
||||
|
||||
@@ -502,6 +553,8 @@ Target: ESP32-S3. Close serial monitor on the UART adapter port before running `
|
||||
| `client_registry.c/h` | Registered slave table |
|
||||
| `bosch456.c/h` | BMA456H I2C driver, accel poll, on-demand read, tap INT, deadzone filter |
|
||||
| `cmd/cmd_accel_snapshot.c` | UART `ACCEL_SNAPSHOT` — cached slave accel |
|
||||
| `cmd/cmd_tap_notify.c` | UART `TAP_NOTIFY` — ESP-NOW tap notify config |
|
||||
| `cmd/cmd_tap_snapshot.c` | UART `TAP_SNAPSHOT` — consume cached tap events |
|
||||
| `board_input.c/h` | Taster GPIO12, LiPo ADC on GPIO1 / GPIO12 |
|
||||
| `pod_settings.c/h` | NVS persistence (accel deadzone, …) |
|
||||
| `led_ring.c/h` | LED ring (digit display, progress bar) |
|
||||
|
||||
Reference in New Issue
Block a user