harden sensor acquisition after audit

This commit is contained in:
Jay
2026-08-17 09:48:05 -04:00
parent f1ac20fb4f
commit b8fe233ba6
11 changed files with 376 additions and 50 deletions
+76
View File
@@ -0,0 +1,76 @@
# Audit Hardening — 2026-08-17
This pass addresses the findings from the independent prototype-v0 audit. It
does not add calibration, BLE, persistent storage, filtering beyond the selected
L3G4200D hardware filter, or sensor fusion.
## Git checkpoints
- `f1ac20f`: exact pre-hardening firmware and axis-validation baseline
- The verified hardening changes are committed separately after this report
No remote repository is configured; these are local history checkpoints.
## Changes
- A clean build now selects `esp32c3` from `sdkconfig.defaults`.
- ADXL345 `INT_SOURCE` and L3G4200D `STATUS_REG` are read immediately before
their corresponding six-byte XYZ reads.
- Raw status bytes and a cumulative loop-overrun count are appended to CSV.
- A delayed acquisition loop resynchronizes rather than issuing catch-up bursts.
- ADXL345 FIFO, interrupt enables, and hardware offset registers are explicitly
reset during initialization so warm MCU resets are deterministic.
- L3G4200D LPF2 is routed to the output with `CTRL_REG5=0x02`, making the
configured 25 Hz cutoff effective.
- Both sensor drivers remove their I2C device handles after an initialization
failure and expose deinitializers.
- Candidate-address loops use an element count rather than byte size.
- The capture utility auto-detects a single USB modem port, writes numeric CSV
only, and reports sequence gaps, resets, timestamp anomalies, malformed
records, and ignored non-record lines.
- Documentation now distinguishes the MCU poll timestamp and nominal scale from
sensor sample timing and measured per-axis scale.
## Build validation
- Normal incremental build: pass
- Clean temporary copy with no `sdkconfig` or `build/`: pass
- Clean configuration selected `CONFIG_IDF_TARGET="esp32c3"` from
`sdkconfig.defaults`
- Hardened binary size: `0x242d0` bytes; 86% of the application partition free
## Hardware validation
The hardened firmware was flashed to the assembled XIAO ESP32-C3 prototype.
Both devices initialized successfully after a USB-triggered warm reset, including
all new register writes and the L3G4200D CTRL5 readback.
The capture `captures/hardening_freshness.csv` contains:
- 3,796 consecutive records
- Sequence gaps: 0
- Sequence resets: 0
- Timestamp anomalies: 0
- Timestamp interval: 10,000 us for all 3,795 intervals
- Rejected records: 0
- Acquisition loop overruns: 0
- ADXL345 DATA_READY clear at status time: 192 records (5.058%)
- ADXL345 overrun set: 0 records
- L3G4200D ZYXDA clear: 0 records
- L3G4200D ZYXOR set: 112 records (2.950%)
The ADXL345 clear events have a coherent 27/28-poll pattern, including adjacent
clear events when a device update likely occurs between the separate status and
data transactions. A clear bit is therefore conservatively treated as
stale/untrusted; a set bit proves unread data existed before the read. The gyro
overrun pattern directly confirms that its internal output clock is faster than
the MCU poll on this unit.
These results validate the audit finding that exact 100 Hz MCU polling does not
mean either sensor is synchronized to that clock. Status labeling is the scoped
prototype fix. Interrupt/FIFO-driven acquisition remains a later buffering task.
A final post-build/post-flash smoke capture added another 1,634 consecutive
records with zero gaps, timestamp anomalies, rejected records, ADXL345 overruns,
or acquisition-loop overruns. It again exposed ADXL345 DATA_READY clear on 81
polls and L3G4200D overrun on 48 polls.