Files
trikkeSensors/android/README.md
T

125 lines
5.4 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Trikke Recorder for Android
Prototype v0.2 records the existing reliable BLE transport to an authoritative
`.trk` file on an Android phone. It deliberately does not filter, fuse, convert,
or upload telemetry.
The permanent Android application ID and Kotlin namespace are
`com.jsjdesigns.trikkerecorder`.
## Platform and behavior
- Android 12 (API 31) or newer
- BLE central connection to the `TrikkeSensor` service
- User-started connected-device foreground service
- Partial wake lock during an active recording
- App-private capture storage with explicit export through Android's document UI
- A `.session.json` sidecar containing phone wall/monotonic clock anchors and
final integrity counters
Every notification is reassembled using its packet sequence, offset, and total
size. A complete frame must also pass the TRK1 shape and CRC checks. For a new
frame the recorder then performs this ordering:
1. Append the unchanged frame to the `.trk` file.
2. Flush the stream and synchronize its file descriptor.
3. Update in-memory integrity state.
4. Write the exact `ACK1` packet sequence to the C3.
If the ACK is lost, the firmware replays the frame. An exact replay of the last
persisted packet is not appended again, but it is acknowledged again. The app
refuses to acknowledge a CRC-invalid frame or the same sequence carrying
different bytes.
At Start, the app generates a random session token and sends it to the Control
characteristic before subscribing. A new token makes the C3 perform one
controlled software restart. The app reconnects with the same token, after which
the C3 starts acquisition with empty queues and zeroed counters. Temporary BLE
reconnects during that recording reuse the token and therefore preserve queued
samples instead of resetting the session.
The validated phone/C3 pair takes about 10.8 seconds from tapping Start to the
first persisted frame because a new session deliberately includes a controlled
C3 restart and two connection passes. A panic, watchdog, brownout, or power-on
reset during recording invalidates the retained token; recovery adds another
controlled restart, and the resulting packet/sample sequence reset remains
visible in the sidecar integrity counters.
## Build and install
Android Studio is the easiest route: open the `android/` directory, allow the
Gradle sync, select the phone, and run the `app` configuration.
The command-line equivalent on this Mac is:
```sh
cd android
export JAVA_HOME="/Applications/Android Studio.app/Contents/jbr/Contents/Home"
export ANDROID_HOME="$HOME/Library/Android/sdk"
./gradlew testDebugUnitTest lintDebug assembleDebug
"$ANDROID_HOME/platform-tools/adb" install -r app/build/outputs/apk/debug/app-debug.apk
```
The tests exercise the Android parser against the real
`ble_mtu_race_4bf00eb.trk` hardware fixture as well as fragment replay, malformed
ordering, CRC rejection, unsigned sequence wrap, durable append, and replay
deduplication.
## Record and export
1. Power the sensor and open **Trikke Recorder**.
2. Tap **Start recording** and grant Nearby Devices and notification permission.
3. Wait for `Recording: Connected and subscribed` and confirm that the sample
count is increasing.
4. The activity may be left, the screen may be locked, and the phone may be put
in a pocket. Keep the persistent recording notification active.
5. Reopen the app and tap **Stop and close safely**.
6. After the status reaches `Stopped`, tap **Export last .trk** and select a
destination.
The app-private `.session.json` starts with `complete: false`. A normal Stop
closes and synchronizes the binary file, then rewrites the sidecar with
`complete: true`, final counts, and first/last phone-to-device clock anchors. If
Android or the user force-stops the process, every previously acknowledged frame
remains in the `.trk` file, while the incomplete sidecar makes the abnormal end
visible.
Phone receipt time is only an alignment anchor; BLE delivery latency means it is
not the sensor's physical sample time. Analysis must continue to use the device
timestamps carried by each TRK1 frame.
## First coordinated acceptance test
Do this before a ride:
1. Record for two minutes with the enclosure flat and still.
2. Lock the phone for at least one minute and verify the sample counter resumes
visibly when the app is reopened.
3. Cause a roughly three-second outage by switching Bluetooth off, switch it
back on, and wait for `Recording` again.
4. Stop and export the `.trk` file.
5. Decode it from the repository root:
```sh
python3 tools/decode_binary.py ride_YYYYMMDD_HHMMSS.trk ride.csv
```
Acceptance requires a valid complete decode, no unexplained packet or sample
gaps, and no queue overflow for the short interruption. Duplicate replays and
the firmware disconnect/replay counters may increase and are expected.
After that passes, repeat for 1530 minutes with the screen locked and include
several short real-world range/interference interruptions.
## Prototype limitations
- The BLE service is still unauthenticated and single-connection, as documented
in `docs/ble-transport-v2.md`.
- The recorder supports one active session and one known sensor.
- Only the binary capture is exported from the UI in this pass. The sidecar is
retained app-private for diagnosis.
- A phone force-stop cannot run cleanup code. The persisted binary prefix remains
useful, but the session is intentionally marked incomplete.
- No GPS, Samsung Health import, CSV rendering, or live motion analysis is in
this milestone.