add reliable BLE telemetry transport

This commit is contained in:
Jay
2026-08-18 06:24:10 -04:00
parent 00f52ecf0f
commit 7617010d8e
26 changed files with 1499 additions and 47 deletions
+37 -7
View File
@@ -7,11 +7,14 @@ This milestone does four things:
1. Detects and verifies both sensors by their identification registers.
2. Configures each sensor for a nominal 100 Hz raw output rate.
3. Emits framed, timestamped binary readings over the XIAO USB connection.
3. Emits framed, timestamped binary readings over reliable BLE, with the
audited direct-USB path retained as a build option.
4. Maps both sensors into a shared enclosure frame and carries the metadata
needed to derive calibrated readings without replacing raw data.
BLE transport and phone-side storage come after the wired sensor path is proven.
The wired sensor path is proven. This milestone adds the first reliable BLE
transport and a macOS-compatible reference capture client; phone-side storage
remains the next consumer implementation.
## Wiring
@@ -28,7 +31,7 @@ Both breakouts share SDA, SCL, 3V3, and GND. The firmware checks both possible
- ADXL345: `0x53` or `0x1D`; expected `DEVID` is `0xE5`.
- L3G4200D: `0x69` or `0x68`; expected `WHO_AM_I` is `0xD3`.
The XIAO ESP32-C3 external antenna is installed for the upcoming BLE transport.
The XIAO ESP32-C3 external antenna is installed for the BLE transport.
## Sensor configuration
@@ -73,7 +76,14 @@ records into versioned `TRK1` frames, isolating acquisition from brief transport
stalls. CRC, packet and sample sequences, timestamps, and cumulative
loss/overrun counters make permanent loss detectable by the receiver.
USB telemetry now uses ESP-IDF's interrupt-driven USB Serial/JTAG driver behind
The default build exposes a custom NimBLE GATT service named `TrikkeSensor`.
Each unchanged `TRK1` frame is fragmented as needed, persisted by the receiver,
and then acknowledged by exact packet sequence. A missing ACK causes a replay;
disconnect or subscription loss retains the same frame and restarts it from byte
zero after reconnection. The receiver deduplicates these deliberate replays.
The preserved USB telemetry option uses ESP-IDF's interrupt-driven USB
Serial/JTAG driver behind
a transport-neutral state machine. A complete frame is submitted atomically to
the driver ring and remains pending across bounded drain timeouts; firmware does
not resubmit it ambiguously or dequeue another frame. The 512-sample queue
@@ -81,8 +91,8 @@ therefore also protects a connected endpoint that temporarily stops draining.
USB drain confirms that bytes left the device endpoint, not that the capture
application persisted them. Packet/sample sequences and CRC expose loss after
the fact. End-to-end receiver acknowledgements and replay remain part of the BLE
transport milestone.
the fact. BLE `COMPLETE` instead means the receiver acknowledged the exact frame
after persistence.
Measured end-to-end framing overhead is about 2.47 kB/s at 100 Hz, or 8.47
MiB/hour before BLE link overhead.
@@ -103,7 +113,27 @@ idf.py build
idf.py -p /dev/cu.usbmodem1134101 flash
```
## USB output
BLE is the default. `idf.py menuconfig` -> `Telemetry transport` can select the
preserved direct USB transport for wired regression work. A separate build tree
can verify that selection without disturbing the normal BLE configuration:
```sh
idf.py -B build-usb -D SDKCONFIG=build-usb/sdkconfig \
-D 'SDKCONFIG_DEFAULTS=sdkconfig.defaults;sdkconfig.usb.defaults' build
```
Install the reference host dependencies and capture BLE telemetry with:
```sh
python3 -m pip install -r requirements.txt
python3 tools/capture_ble.py
```
The client scans for `TrikkeSensor`, stores only complete CRC-valid `TRK1`
frames, flushes the binary and CSV outputs, and only then writes the application
ACK. See [the BLE transport specification](docs/ble-transport-v1.md).
## TRK1 output and USB validation
After readable startup metadata, the device emits framed binary. Each sample is a
20-byte record containing mapped raw sensor counts, timing, sequence, and the two