From 6e408a304861305af2f7117fad981689284eaf85 Mon Sep 17 00:00:00 2001 From: Jay Date: Thu, 20 Aug 2026 12:40:39 -0400 Subject: [PATCH] Add reliable Android BLE ride recorder --- .gitignore | 3 + README.md | 87 ++++- android/README.md | 124 ++++++ android/app/build.gradle.kts | 49 +++ android/app/proguard-rules.pro | 1 + android/app/src/main/AndroidManifest.xml | 41 ++ .../jsjdesigns/trikkerecorder/BleTransport.kt | 354 ++++++++++++++++++ .../jsjdesigns/trikkerecorder/MainActivity.kt | 256 +++++++++++++ .../trikkerecorder/TelemetryService.kt | 317 ++++++++++++++++ .../protocol/BleFrameReassembler.kt | 113 ++++++ .../trikkerecorder/protocol/TrkProtocol.kt | 168 +++++++++ .../trikkerecorder/storage/SessionRecorder.kt | 180 +++++++++ .../app/src/main/res/drawable/ic_launcher.xml | 12 + android/app/src/main/res/values/strings.xml | 5 + android/app/src/main/res/values/styles.xml | 8 + .../main/res/xml/data_extraction_rules.xml | 9 + .../protocol/ProtocolContractTest.kt | 137 +++++++ android/build.gradle.kts | 3 + android/gradle.properties | 3 + android/gradle/gradle-daemon-jvm.properties | 12 + android/gradle/wrapper/gradle-wrapper.jar | Bin 0 -> 48966 bytes .../gradle/wrapper/gradle-wrapper.properties | 7 + android/gradlew | 248 ++++++++++++ android/gradlew.bat | 93 +++++ android/settings.gradle.kts | 18 + docs/binary-record-v1.md | 19 +- docs/ble-transport-v1.md | 68 ---- docs/ble-transport-v2.md | 119 ++++++ main/trikke_ble_protocol.c | 34 ++ main/trikke_ble_protocol.h | 15 + main/trikke_ble_transport.c | 169 ++++++++- main/trikke_ble_transport.h | 14 +- main/trikke_sensor_main.c | 53 ++- tests/ble_protocol_fixture.c | 37 ++ tests/fixtures/README.md | 29 ++ .../ride_20260820_090607.session.json | 25 ++ tests/fixtures/ride_20260820_090607.trk | Bin 0 -> 495688 bytes tests/test_trikke_protocol.py | 56 ++- tools/capture_ble.py | 10 +- tools/trikke_ble.py | 5 + 40 files changed, 2781 insertions(+), 120 deletions(-) create mode 100644 android/README.md create mode 100644 android/app/build.gradle.kts create mode 100644 android/app/proguard-rules.pro create mode 100644 android/app/src/main/AndroidManifest.xml create mode 100644 android/app/src/main/kotlin/com/jsjdesigns/trikkerecorder/BleTransport.kt create mode 100644 android/app/src/main/kotlin/com/jsjdesigns/trikkerecorder/MainActivity.kt create mode 100644 android/app/src/main/kotlin/com/jsjdesigns/trikkerecorder/TelemetryService.kt create mode 100644 android/app/src/main/kotlin/com/jsjdesigns/trikkerecorder/protocol/BleFrameReassembler.kt create mode 100644 android/app/src/main/kotlin/com/jsjdesigns/trikkerecorder/protocol/TrkProtocol.kt create mode 100644 android/app/src/main/kotlin/com/jsjdesigns/trikkerecorder/storage/SessionRecorder.kt create mode 100644 android/app/src/main/res/drawable/ic_launcher.xml create mode 100644 android/app/src/main/res/values/strings.xml create mode 100644 android/app/src/main/res/values/styles.xml create mode 100644 android/app/src/main/res/xml/data_extraction_rules.xml create mode 100644 android/app/src/test/kotlin/com/jsjdesigns/trikkerecorder/protocol/ProtocolContractTest.kt create mode 100644 android/build.gradle.kts create mode 100644 android/gradle.properties create mode 100644 android/gradle/gradle-daemon-jvm.properties create mode 100644 android/gradle/wrapper/gradle-wrapper.jar create mode 100644 android/gradle/wrapper/gradle-wrapper.properties create mode 100755 android/gradlew create mode 100644 android/gradlew.bat create mode 100644 android/settings.gradle.kts delete mode 100644 docs/ble-transport-v1.md create mode 100644 docs/ble-transport-v2.md create mode 100644 tests/fixtures/ride_20260820_090607.session.json create mode 100644 tests/fixtures/ride_20260820_090607.trk diff --git a/.gitignore b/.gitignore index e01875c..8b34ee6 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,6 @@ sdkconfig.old managed_components/ __pycache__/ .DS_Store +android/.gradle/ +android/local.properties +android/app/build/ diff --git a/README.md b/README.md index f45a8ea..c37d091 100644 --- a/README.md +++ b/README.md @@ -12,9 +12,10 @@ This milestone does four things: 4. Maps both sensors into a shared enclosure frame and carries the metadata needed to derive calibrated readings without replacing raw data. -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. +The wired sensor path and reliable BLE transport are proven. The repository now +also contains an Android 12+ prototype recorder that stores the authoritative +binary stream durably before acknowledging each frame. The macOS reference +client remains available for transport diagnosis. ## Wiring @@ -70,33 +71,59 @@ Future fusion, integration, and filtering must derive each `dt` from those timestamps rather than assume a uniform 10 ms interval. Sensor DRDY/FIFO acquisition remains the later refinement for reducing the jitter itself. -The ESP32-C3 schedules nominal 100 Hz polling in a dedicated acquisition task, -but each -sensor has an independent internal +The 200-second Android acceptance capture provides the current loaded-system +characterization. Of 19,983 contiguous intervals, 8,745 (43.8%) were off-grid. +Across all intervals, absolute deviation was 0 us median, 40 us p95, 240 us p99, +and 1,630 us maximum; among off-grid intervals it was 10 us median, 60 us p95, +and 750 us p99. Cumulative error was -726 us. These timestamp statistics are a +lower bound on acquisition disturbance because firmware timestamps the poll +before performing both I2C reads. Six ADXL345 overrun flags show that preemption +between the timestamp and the physical read occasionally crossed a sensor sample +boundary even though the recorded timestamp delta did not expose the full delay. +The loss is rare (0.03%), explicitly flagged, and reinforces the planned +data-ready/FIFO acquisition refinement. + +After the BLE session handshake, the ESP32-C3 schedules nominal 100 Hz polling +in a dedicated acquisition task, but each sensor has an independent internal sample clock. The status registers are read immediately before each XYZ read so a consumer can distinguish a fresh sample from a repeated poll and identify gyro overruns. Hardware data-ready interrupts and FIFO acquisition are deferred to the later sensor-side acquisition refinement. -Completed samples enter a 1024-record RAM queue, providing 10.24 seconds of -transport-outage tolerance at 100 Hz when the transport reports backpressure or -failure accurately. A failed write retains and retries its packet while this -queue accumulates the backlog. A lower-priority output task batches up to eight -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. +Completed samples enter a statically reserved 3072-record RAM queue, providing +30.72 seconds of transport-outage tolerance at 100 Hz when the transport reports +backpressure or failure accurately. A failed write retains and retries its +packet while this queue accumulates the backlog. A lower-priority output task +batches up to eight 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. + +The 30.72-second depth is based on end-to-end phone behavior rather than the +visible Bluetooth-off interval alone. A five-second Android Bluetooth outage +produced roughly 12.5 seconds of effective transport interruption and overflowed +the prior 10.24-second queue by 223 samples. Repeating the same test with the +3,072-record queue delivered all 19,984 samples contiguously; one replay was +durably deduplicated and all loss counters remained zero. The capture and its +completed Android sidecar are preserved under `tests/fixtures/`. + +The static queue occupies 96 KiB. The BLE build leaves 132,389 bytes of DRAM for +task stacks, NimBLE runtime allocation, and future features; the 200-second +acceptance capture proves the present configuration, but another large buffer or +memory-heavy feature requires a fresh runtime and build-time memory review. 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. +Acquisition remains stopped until a valid session-token handshake establishes a +clean capture boundary. Each unchanged `TRK1` frame is then fragmented as needed, +persisted by the receiver, and 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 a same-token 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 1024-sample queue +not resubmit it ambiguously or dequeue another frame. The 3072-sample queue therefore also protects a connected endpoint that temporarily stops draining. USB drain confirms that bytes left the device endpoint, not that the capture @@ -141,7 +168,29 @@ 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). +ACK. See [the BLE transport specification](docs/ble-transport-v2.md). + +## Android recorder + +The `android/` project is the prototype ride recorder. Each new recording sends +an idempotent session token that gives the C3 a repeatable software session +boundary with empty queues, reset counters, and acquisition starting only after +the phone is ready. Reconnects reuse that token and preserve the outage backlog. +The app reassembles and validates complete frames, appends each new frame to +app-private storage, calls `fsync`, and only then sends `ACK1`. Exact replays are +acknowledged without being appended twice. Recording runs in a connected-device +foreground service with a partial wake lock so it can continue while the screen +is off. + +Build its debug APK with: + +```sh +cd android +./gradlew testDebugUnitTest lintDebug assembleDebug +``` + +See [the Android recorder guide](android/README.md) for installation, capture, +export, and the first coordinated phone test. ## TRK1 output and USB validation diff --git a/android/README.md b/android/README.md new file mode 100644 index 0000000..2978a0a --- /dev/null +++ b/android/README.md @@ -0,0 +1,124 @@ +# 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 15–30 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. diff --git a/android/app/build.gradle.kts b/android/app/build.gradle.kts new file mode 100644 index 0000000..92733db --- /dev/null +++ b/android/app/build.gradle.kts @@ -0,0 +1,49 @@ +plugins { + id("com.android.application") +} + +android { + namespace = "com.jsjdesigns.trikkerecorder" + compileSdk = 36 + + defaultConfig { + applicationId = "com.jsjdesigns.trikkerecorder" + minSdk = 31 + targetSdk = 36 + versionCode = 2 + versionName = "0.2.0" + + testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" + } + + buildTypes { + release { + isMinifyEnabled = false + proguardFiles( + getDefaultProguardFile("proguard-android-optimize.txt"), + "proguard-rules.pro", + ) + } + } + + compileOptions { + sourceCompatibility = JavaVersion.VERSION_17 + targetCompatibility = JavaVersion.VERSION_17 + } + + testOptions { + unitTests.all { + it.useJUnit() + } + } + + sourceSets { + getByName("test").resources.directories.add( + "../../tests/fixtures", + ) + } +} + +dependencies { + testImplementation("junit:junit:4.13.2") +} diff --git a/android/app/proguard-rules.pro b/android/app/proguard-rules.pro new file mode 100644 index 0000000..d6417b6 --- /dev/null +++ b/android/app/proguard-rules.pro @@ -0,0 +1 @@ +# Prototype v0 keeps release builds unobfuscated for diagnosability. diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml new file mode 100644 index 0000000..cf0ff00 --- /dev/null +++ b/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,41 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/android/app/src/main/kotlin/com/jsjdesigns/trikkerecorder/BleTransport.kt b/android/app/src/main/kotlin/com/jsjdesigns/trikkerecorder/BleTransport.kt new file mode 100644 index 0000000..04b07be --- /dev/null +++ b/android/app/src/main/kotlin/com/jsjdesigns/trikkerecorder/BleTransport.kt @@ -0,0 +1,354 @@ +package com.jsjdesigns.trikkerecorder + +import android.annotation.SuppressLint +import android.bluetooth.BluetoothAdapter +import android.bluetooth.BluetoothDevice +import android.bluetooth.BluetoothGatt +import android.bluetooth.BluetoothGattCallback +import android.bluetooth.BluetoothGattCharacteristic +import android.bluetooth.BluetoothGattDescriptor +import android.bluetooth.BluetoothManager +import android.bluetooth.BluetoothProfile +import android.bluetooth.BluetoothStatusCodes +import android.bluetooth.le.ScanCallback +import android.bluetooth.le.ScanFilter +import android.bluetooth.le.ScanResult +import android.bluetooth.le.ScanSettings +import android.content.Context +import android.os.Build +import android.os.Handler +import android.os.Looper +import android.os.ParcelUuid +import android.os.SystemClock +import com.jsjdesigns.trikkerecorder.protocol.BleFrameReassembler +import java.util.UUID + +@SuppressLint("MissingPermission") +class BleTransport( + context: Context, + private val listener: Listener, +) { + interface Listener { + fun onTransportState(state: String, detail: String) + fun onFragment(fragment: ByteArray, connectionEpoch: Long, elapsedNs: Long, wallMs: Long) + } + + private val appContext = context.applicationContext + private val handler = Handler(Looper.getMainLooper()) + private val adapter: BluetoothAdapter? = + appContext.getSystemService(BluetoothManager::class.java)?.adapter + private var scannerCallback: ScanCallback? = null + private var gatt: BluetoothGatt? = null + private var ackCharacteristic: BluetoothGattCharacteristic? = null + private var controlCharacteristic: BluetoothGattCharacteristic? = null + private var running = false + private var sessionToken = 0L + private var connectionEpoch = 0L + private var readyEpoch = -1L + + private val scanTimeout = Runnable { + stopScan() + if (running) { + listener.onTransportState("Scanning", "TrikkeSensor not seen; scanning again") + handler.postDelayed(::beginScan, SCAN_PAUSE_MS) + } + } + + fun start(sessionToken: Long) { + if (running) return + this.sessionToken = sessionToken + running = true + beginScan() + } + + fun stop() { + running = false + handler.removeCallbacksAndMessages(null) + stopScan() + readyEpoch = -1L + ackCharacteristic = null + controlCharacteristic = null + gatt?.disconnect() + gatt?.close() + gatt = null + } + + fun acknowledge(packetSequence: Long, epoch: Long) { + handler.post { + val activeGatt = gatt + val characteristic = ackCharacteristic + if (!running || epoch != readyEpoch || activeGatt == null || characteristic == null) { + return@post + } + val ack = BleFrameReassembler.encodeAck(packetSequence) + val accepted = if (Build.VERSION.SDK_INT >= 33) { + activeGatt.writeCharacteristic( + characteristic, + ack, + BluetoothGattCharacteristic.WRITE_TYPE_DEFAULT, + ) == BluetoothStatusCodes.SUCCESS + } else { + @Suppress("DEPRECATION") + characteristic.setValue(ack) + @Suppress("DEPRECATION") + characteristic.writeType = BluetoothGattCharacteristic.WRITE_TYPE_DEFAULT + @Suppress("DEPRECATION") + activeGatt.writeCharacteristic(characteristic) + } + if (!accepted) { + listener.onTransportState("Recording", "ACK enqueue delayed; awaiting replay") + } + } + } + + private fun beginScan() { + if (!running || scannerCallback != null || gatt != null) return + val scanner = adapter?.bluetoothLeScanner + if (adapter?.isEnabled != true || scanner == null) { + listener.onTransportState("Waiting", "Bluetooth is off") + handler.postDelayed(::beginScan, RETRY_MS) + return + } + + val callback = object : ScanCallback() { + override fun onScanResult(callbackType: Int, result: ScanResult) { + if (!running || scannerCallback !== this) return + stopScan() + connect(result) + } + + override fun onScanFailed(errorCode: Int) { + if (scannerCallback === this) scannerCallback = null + handler.removeCallbacks(scanTimeout) + listener.onTransportState("Waiting", "BLE scan failed ($errorCode); retrying") + if (running) handler.postDelayed(::beginScan, RETRY_MS) + } + } + scannerCallback = callback + val filter = ScanFilter.Builder().setServiceUuid(ParcelUuid(SERVICE_UUID)).build() + val settings = ScanSettings.Builder() + .setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY) + .build() + try { + scanner.startScan(listOf(filter), settings, callback) + listener.onTransportState("Scanning", "Looking for TrikkeSensor") + handler.postDelayed(scanTimeout, SCAN_WINDOW_MS) + } catch (error: RuntimeException) { + scannerCallback = null + listener.onTransportState("Waiting", "BLE scan unavailable: ${error.message}") + if (running) handler.postDelayed(::beginScan, RETRY_MS) + } + } + + private fun stopScan() { + handler.removeCallbacks(scanTimeout) + val callback = scannerCallback ?: return + scannerCallback = null + try { + adapter?.bluetoothLeScanner?.stopScan(callback) + } catch (_: RuntimeException) { + // Bluetooth may have been switched off while the scan was active. + } + } + + private fun connect(result: ScanResult) { + if (!running) return + connectionEpoch++ + val epoch = connectionEpoch + listener.onTransportState("Connecting", result.device.address) + gatt = result.device.connectGatt( + appContext, + false, + callback(epoch), + BluetoothDevice.TRANSPORT_LE, + ) + if (gatt == null) restart("Connection could not be started") + } + + private fun callback(epoch: Long) = object : BluetoothGattCallback() { + override fun onConnectionStateChange(callbackGatt: BluetoothGatt, status: Int, newState: Int) { + handler.post { + if (callbackGatt !== gatt || epoch != connectionEpoch) { + callbackGatt.close() + return@post + } + if (status == BluetoothGatt.GATT_SUCCESS && newState == BluetoothProfile.STATE_CONNECTED) { + listener.onTransportState("Connecting", "Discovering telemetry service") + callbackGatt.requestConnectionPriority(BluetoothGatt.CONNECTION_PRIORITY_HIGH) + if (!callbackGatt.discoverServices()) restart("Service discovery did not start") + } else if (newState == BluetoothProfile.STATE_DISCONNECTED || status != BluetoothGatt.GATT_SUCCESS) { + restart("Disconnected (GATT $status)") + } + } + } + + override fun onServicesDiscovered(callbackGatt: BluetoothGatt, status: Int) { + handler.post { + if (callbackGatt !== gatt || epoch != connectionEpoch) return@post + if (status != BluetoothGatt.GATT_SUCCESS) { + restart("Service discovery failed ($status)") + return@post + } + val service = callbackGatt.getService(SERVICE_UUID) + val data = service?.getCharacteristic(DATA_UUID) + ackCharacteristic = service?.getCharacteristic(ACK_UUID) + controlCharacteristic = service?.getCharacteristic(CONTROL_UUID) + if (data == null || ackCharacteristic == null || controlCharacteristic == null) { + restart("Telemetry characteristics are missing") + return@post + } + if (!callbackGatt.requestMtu(PREFERRED_MTU)) beginSession(callbackGatt, epoch) + } + } + + override fun onMtuChanged(callbackGatt: BluetoothGatt, mtu: Int, status: Int) { + handler.post { + if (callbackGatt !== gatt || epoch != connectionEpoch) return@post + beginSession(callbackGatt, epoch) + } + } + + @Deprecated("Used through Android 12") + override fun onCharacteristicChanged( + callbackGatt: BluetoothGatt, + characteristic: BluetoothGattCharacteristic, + ) { + @Suppress("DEPRECATION") + deliver(callbackGatt, characteristic, characteristic.value?.copyOf() ?: return, epoch) + } + + override fun onCharacteristicChanged( + callbackGatt: BluetoothGatt, + characteristic: BluetoothGattCharacteristic, + value: ByteArray, + ) { + deliver(callbackGatt, characteristic, value.copyOf(), epoch) + } + + override fun onDescriptorWrite(callbackGatt: BluetoothGatt, descriptor: BluetoothGattDescriptor, status: Int) { + handler.post { + if (callbackGatt !== gatt || epoch != connectionEpoch) return@post + if (descriptor.uuid != CCCD_UUID || status != BluetoothGatt.GATT_SUCCESS) { + restart("Notification subscription failed ($status)") + return@post + } + readyEpoch = epoch + listener.onTransportState("Recording", "Connected and subscribed") + } + } + + override fun onCharacteristicWrite( + callbackGatt: BluetoothGatt, + characteristic: BluetoothGattCharacteristic, + status: Int, + ) { + handler.post { + if (callbackGatt !== gatt || epoch != connectionEpoch) return@post + if (characteristic.uuid == CONTROL_UUID) { + if (status != BluetoothGatt.GATT_SUCCESS) { + restart("Session preparation failed ($status)") + return@post + } + val data = callbackGatt.getService(SERVICE_UUID)?.getCharacteristic(DATA_UUID) + if (data == null) restart("Data characteristic vanished") + else enableNotifications(callbackGatt, data, epoch) + } else if (characteristic.uuid == ACK_UUID && status != BluetoothGatt.GATT_SUCCESS) { + listener.onTransportState("Recording", "ACK write failed ($status); awaiting replay") + } + } + } + } + + private fun deliver( + callbackGatt: BluetoothGatt, + characteristic: BluetoothGattCharacteristic, + value: ByteArray, + epoch: Long, + ) { + val elapsedNs = SystemClock.elapsedRealtimeNanos() + val wallMs = System.currentTimeMillis() + handler.post { + if (callbackGatt !== gatt || epoch != readyEpoch || characteristic.uuid != DATA_UUID) return@post + listener.onFragment(value, epoch, elapsedNs, wallMs) + } + } + + private fun enableNotifications( + callbackGatt: BluetoothGatt, + data: BluetoothGattCharacteristic, + epoch: Long, + ) { + if (callbackGatt !== gatt || epoch != connectionEpoch) return + if (!callbackGatt.setCharacteristicNotification(data, true)) { + restart("Local notification registration failed") + return + } + val descriptor = data.getDescriptor(CCCD_UUID) + if (descriptor == null) { + restart("Notification descriptor is missing") + return + } + val accepted = if (Build.VERSION.SDK_INT >= 33) { + callbackGatt.writeDescriptor(descriptor, BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE) == + BluetoothStatusCodes.SUCCESS + } else { + @Suppress("DEPRECATION") + descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE) + @Suppress("DEPRECATION") + callbackGatt.writeDescriptor(descriptor) + } + if (!accepted) restart("Notification subscription did not start") + } + + private fun beginSession(callbackGatt: BluetoothGatt, epoch: Long) { + if (callbackGatt !== gatt || epoch != connectionEpoch) return + val control = controlCharacteristic + if (control == null) { + restart("Session control characteristic is missing") + return + } + listener.onTransportState("Preparing", "Establishing a clean recording session") + val command = BleFrameReassembler.encodeBeginSession(sessionToken) + val accepted = if (Build.VERSION.SDK_INT >= 33) { + callbackGatt.writeCharacteristic( + control, + command, + BluetoothGattCharacteristic.WRITE_TYPE_DEFAULT, + ) == BluetoothStatusCodes.SUCCESS + } else { + @Suppress("DEPRECATION") + control.setValue(command) + @Suppress("DEPRECATION") + control.writeType = BluetoothGattCharacteristic.WRITE_TYPE_DEFAULT + @Suppress("DEPRECATION") + callbackGatt.writeCharacteristic(control) + } + if (!accepted) restart("Session preparation did not start") + } + + private fun restart(reason: String) { + readyEpoch = -1L + ackCharacteristic = null + controlCharacteristic = null + val oldGatt = gatt + gatt = null + oldGatt?.disconnect() + oldGatt?.close() + if (running) { + listener.onTransportState("Reconnecting", reason) + handler.postDelayed(::beginScan, RETRY_MS) + } + } + + companion object { + val SERVICE_UUID: UUID = UUID.fromString("7d2ea000-f75b-4a9b-8fbe-3d4c2a1e9c10") + val DATA_UUID: UUID = UUID.fromString("7d2ea000-f75b-4a9b-8fbe-3d4c2a1e9c11") + val ACK_UUID: UUID = UUID.fromString("7d2ea000-f75b-4a9b-8fbe-3d4c2a1e9c12") + val CONTROL_UUID: UUID = UUID.fromString("7d2ea000-f75b-4a9b-8fbe-3d4c2a1e9c13") + private val CCCD_UUID: UUID = UUID.fromString("00002902-0000-1000-8000-00805f9b34fb") + private const val PREFERRED_MTU = 256 + private const val SCAN_WINDOW_MS = 10_000L + private const val SCAN_PAUSE_MS = 500L + private const val RETRY_MS = 1_000L + } +} diff --git a/android/app/src/main/kotlin/com/jsjdesigns/trikkerecorder/MainActivity.kt b/android/app/src/main/kotlin/com/jsjdesigns/trikkerecorder/MainActivity.kt new file mode 100644 index 0000000..276ffcb --- /dev/null +++ b/android/app/src/main/kotlin/com/jsjdesigns/trikkerecorder/MainActivity.kt @@ -0,0 +1,256 @@ +package com.jsjdesigns.trikkerecorder + +import android.Manifest +import android.annotation.SuppressLint +import android.app.Activity +import android.bluetooth.BluetoothAdapter +import android.content.BroadcastReceiver +import android.content.Context +import android.content.Intent +import android.content.IntentFilter +import android.content.pm.PackageManager +import android.graphics.Typeface +import android.net.Uri +import android.os.Build +import android.os.Bundle +import android.view.Gravity +import android.view.ViewGroup +import android.widget.Button +import android.widget.LinearLayout +import android.widget.ScrollView +import android.widget.TextView +import java.io.File +import java.util.Locale + +class MainActivity : Activity() { + private lateinit var phaseView: TextView + private lateinit var detailView: TextView + private lateinit var countersView: TextView + private lateinit var recordButton: Button + private lateinit var exportButton: Button + private var snapshot = RecorderSnapshot() + private var pendingStart = false + private var exportPath: String? = null + + private val stateReceiver = object : BroadcastReceiver() { + override fun onReceive(context: Context?, intent: Intent?) { + if (intent?.action != TelemetryService.ACTION_STATE) return + snapshot = RecorderSnapshot( + active = intent.getBooleanExtra(TelemetryService.EXTRA_ACTIVE, false), + phase = intent.getStringExtra(TelemetryService.EXTRA_PHASE) ?: "Idle", + detail = intent.getStringExtra(TelemetryService.EXTRA_DETAIL) ?: "", + capturePath = intent.getStringExtra(TelemetryService.EXTRA_CAPTURE_PATH), + durationSeconds = intent.getLongExtra(TelemetryService.EXTRA_DURATION_SECONDS, 0), + frameCount = intent.getLongExtra(TelemetryService.EXTRA_FRAMES, 0), + sampleCount = intent.getLongExtra(TelemetryService.EXTRA_SAMPLES, 0), + duplicateCount = intent.getLongExtra(TelemetryService.EXTRA_DUPLICATES, 0), + rejectedFragments = intent.getLongExtra(TelemetryService.EXTRA_REJECTED_FRAGMENTS, 0), + invalidFrames = intent.getLongExtra(TelemetryService.EXTRA_INVALID_FRAMES, 0), + packetGaps = intent.getLongExtra(TelemetryService.EXTRA_PACKET_GAPS, 0), + sampleGaps = intent.getLongExtra(TelemetryService.EXTRA_SAMPLE_GAPS, 0), + droppedSamples = intent.getLongExtra(TelemetryService.EXTRA_DROPPED, 0), + queueOverflows = intent.getLongExtra(TelemetryService.EXTRA_QUEUE_OVERFLOWS, -1) + .takeIf { it >= 0 }, + ) + render() + } + } + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + buildUi() + snapshot = TelemetryService.currentSnapshot + if (snapshot.capturePath == null) { + val previous = getSharedPreferences(TelemetryService.PREFERENCES, MODE_PRIVATE) + .getString(TelemetryService.LAST_CAPTURE, null) + if (previous != null) snapshot = snapshot.copy(capturePath = previous) + } + render() + } + + @SuppressLint("UnspecifiedRegisterReceiverFlag") + override fun onStart() { + super.onStart() + val filter = IntentFilter(TelemetryService.ACTION_STATE) + if (Build.VERSION.SDK_INT >= 33) registerReceiver(stateReceiver, filter, RECEIVER_NOT_EXPORTED) + else @Suppress("DEPRECATION") registerReceiver(stateReceiver, filter) + } + + override fun onStop() { + unregisterReceiver(stateReceiver) + super.onStop() + } + + override fun onRequestPermissionsResult( + requestCode: Int, + permissions: Array, + grantResults: IntArray, + ) { + super.onRequestPermissionsResult(requestCode, permissions, grantResults) + if (requestCode == REQUEST_PERMISSIONS && hasBluetoothPermissions()) ensureBluetoothAndStart() + else if (requestCode == REQUEST_PERMISSIONS) showLocalMessage("Nearby devices permission is required") + } + + @Deprecated("Used for the platform Bluetooth-enable and document-create flows") + override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { + super.onActivityResult(requestCode, resultCode, data) + when (requestCode) { + REQUEST_ENABLE_BLUETOOTH -> { + if (resultCode == RESULT_OK && pendingStart) startRecorder() + else showLocalMessage("Bluetooth must be enabled to record") + pendingStart = false + } + REQUEST_EXPORT -> if (resultCode == RESULT_OK) { + val destination = data?.data ?: return + exportCapture(destination) + } + } + } + + private fun buildUi() { + val density = resources.displayMetrics.density + val padding = (24 * density).toInt() + val content = LinearLayout(this).apply { + orientation = LinearLayout.VERTICAL + gravity = Gravity.CENTER_HORIZONTAL + setPadding(padding, padding, padding, padding) + } + phaseView = TextView(this).apply { + textSize = 30f + setTypeface(typeface, Typeface.BOLD) + } + detailView = TextView(this).apply { + textSize = 17f + gravity = Gravity.CENTER_HORIZONTAL + setPadding(0, padding / 2, 0, padding) + } + countersView = TextView(this).apply { + textSize = 17f + typeface = Typeface.MONOSPACE + setLineSpacing(0f, 1.25f) + } + recordButton = Button(this).apply { + setOnClickListener { + if (snapshot.active) stopRecorder() else requestStart() + } + } + exportButton = Button(this).apply { + text = getString(R.string.export_capture) + setOnClickListener { chooseExportDestination() } + } + content.addView(phaseView, matchWrap()) + content.addView(detailView, matchWrap()) + content.addView(countersView, matchWrap()) + content.addView(recordButton, matchWrap(topMargin = padding)) + content.addView(exportButton, matchWrap(topMargin = padding / 2)) + setContentView(ScrollView(this).apply { addView(content) }) + } + + private fun matchWrap(topMargin: Int = 0) = LinearLayout.LayoutParams( + ViewGroup.LayoutParams.MATCH_PARENT, + ViewGroup.LayoutParams.WRAP_CONTENT, + ).apply { this.topMargin = topMargin } + + private fun render() { + phaseView.text = snapshot.phase + detailView.text = snapshot.detail + countersView.text = buildString { + appendLine("duration ${formatDuration(snapshot.durationSeconds)}") + appendLine("frames ${snapshot.frameCount}") + appendLine("samples ${snapshot.sampleCount}") + appendLine("duplicate replays ${snapshot.duplicateCount}") + appendLine("fragment rejects ${snapshot.rejectedFragments}") + appendLine("invalid frames ${snapshot.invalidFrames}") + appendLine("packet gaps ${snapshot.packetGaps}") + appendLine("sample gaps ${snapshot.sampleGaps}") + appendLine("device drops ${snapshot.droppedSamples}") + append("queue overflows ${snapshot.queueOverflows ?: "waiting for status"}") + } + recordButton.text = if (snapshot.active) "Stop and close safely" else "Start recording" + recordButton.isEnabled = snapshot.phase != "Stopping" + exportButton.isEnabled = !snapshot.active && snapshot.capturePath?.let(::File)?.isFile == true + } + + private fun requestStart() { + if (!hasBluetoothPermissions()) { + val permissions = mutableListOf( + Manifest.permission.BLUETOOTH_SCAN, + Manifest.permission.BLUETOOTH_CONNECT, + ) + if (Build.VERSION.SDK_INT >= 33) permissions += Manifest.permission.POST_NOTIFICATIONS + requestPermissions(permissions.toTypedArray(), REQUEST_PERMISSIONS) + return + } + ensureBluetoothAndStart() + } + + private fun hasBluetoothPermissions(): Boolean = + checkSelfPermission(Manifest.permission.BLUETOOTH_SCAN) == PackageManager.PERMISSION_GRANTED && + checkSelfPermission(Manifest.permission.BLUETOOTH_CONNECT) == PackageManager.PERMISSION_GRANTED + + @SuppressLint("MissingPermission") + private fun ensureBluetoothAndStart() { + val adapter = getSystemService(android.bluetooth.BluetoothManager::class.java)?.adapter + if (adapter?.isEnabled != true) { + pendingStart = true + @Suppress("DEPRECATION") + startActivityForResult(Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE), REQUEST_ENABLE_BLUETOOTH) + } else { + startRecorder() + } + } + + private fun startRecorder() { + startForegroundService(Intent(this, TelemetryService::class.java).setAction(TelemetryService.ACTION_START)) + } + + private fun stopRecorder() { + startService(Intent(this, TelemetryService::class.java).setAction(TelemetryService.ACTION_STOP)) + } + + private fun chooseExportDestination() { + val source = snapshot.capturePath?.let(::File) ?: return + exportPath = source.absolutePath + @Suppress("DEPRECATION") + startActivityForResult( + Intent(Intent.ACTION_CREATE_DOCUMENT) + .addCategory(Intent.CATEGORY_OPENABLE) + .setType("application/octet-stream") + .putExtra(Intent.EXTRA_TITLE, source.name), + REQUEST_EXPORT, + ) + } + + private fun exportCapture(destination: Uri) { + val source = exportPath?.let(::File) ?: return + Thread { + try { + contentResolver.openOutputStream(destination, "wt")!!.use { output -> + source.inputStream().use { input -> input.copyTo(output) } + output.flush() + } + runOnUiThread { showLocalMessage("Exported ${source.name}") } + } catch (error: Exception) { + runOnUiThread { showLocalMessage("Export failed: ${error.message}") } + } + }.start() + } + + private fun showLocalMessage(message: String) { + detailView.text = message + } + + private fun formatDuration(seconds: Long): String = String.format( + Locale.US, + "%02d:%02d:%02d", + seconds / 3_600, + (seconds / 60) % 60, + seconds % 60, + ) + + companion object { + private const val REQUEST_PERMISSIONS = 20 + private const val REQUEST_ENABLE_BLUETOOTH = 21 + private const val REQUEST_EXPORT = 22 + } +} diff --git a/android/app/src/main/kotlin/com/jsjdesigns/trikkerecorder/TelemetryService.kt b/android/app/src/main/kotlin/com/jsjdesigns/trikkerecorder/TelemetryService.kt new file mode 100644 index 0000000..2cac617 --- /dev/null +++ b/android/app/src/main/kotlin/com/jsjdesigns/trikkerecorder/TelemetryService.kt @@ -0,0 +1,317 @@ +package com.jsjdesigns.trikkerecorder + +import android.annotation.SuppressLint +import android.app.Notification +import android.app.NotificationChannel +import android.app.NotificationManager +import android.app.PendingIntent +import android.app.Service +import android.content.Intent +import android.os.IBinder +import android.os.PowerManager +import android.os.SystemClock +import com.jsjdesigns.trikkerecorder.protocol.BleFrameReassembler +import com.jsjdesigns.trikkerecorder.protocol.TrkProtocol +import com.jsjdesigns.trikkerecorder.storage.CommitResult +import com.jsjdesigns.trikkerecorder.storage.SessionRecorder +import java.io.File +import java.text.SimpleDateFormat +import java.util.Date +import java.util.Locale +import java.security.SecureRandom +import java.util.concurrent.Executors +import java.util.concurrent.atomic.AtomicBoolean + +data class RecorderSnapshot( + val active: Boolean = false, + val phase: String = "Idle", + val detail: String = "Ready", + val capturePath: String? = null, + val durationSeconds: Long = 0, + val frameCount: Long = 0, + val sampleCount: Long = 0, + val duplicateCount: Long = 0, + val rejectedFragments: Long = 0, + val invalidFrames: Long = 0, + val packetGaps: Long = 0, + val sampleGaps: Long = 0, + val droppedSamples: Long = 0, + val queueOverflows: Long? = null, +) + +class TelemetryService : Service(), BleTransport.Listener { + private val processor = Executors.newSingleThreadExecutor() + private val stopping = AtomicBoolean(false) + private val reassembler = BleFrameReassembler() + private lateinit var transport: BleTransport + private var recorder: SessionRecorder? = null + private var phase = "Idle" + private var detail = "Ready" + private var invalidFrames = 0L + private var lastPublishMs = 0L + private var wakeLock: PowerManager.WakeLock? = null + private var recordingStartElapsedMs = 0L + private var recordingEndElapsedMs = 0L + private var sessionToken = 0L + + override fun onCreate() { + super.onCreate() + createNotificationChannel() + transport = BleTransport(this, this) + } + + override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int { + when (intent?.action) { + ACTION_STOP -> finishRecording(null) + else -> startRecording() + } + return START_NOT_STICKY + } + + override fun onBind(intent: Intent?): IBinder? = null + + override fun onDestroy() { + transport.stop() + releaseWakeLock() + if (!stopping.get()) { + recorder?.close(System.currentTimeMillis(), SystemClock.elapsedRealtimeNanos(), "Service destroyed") + } + processor.shutdown() + super.onDestroy() + } + + override fun onTransportState(state: String, detail: String) { + this.phase = state + this.detail = detail + publish(force = true) + } + + override fun onFragment(fragment: ByteArray, connectionEpoch: Long, elapsedNs: Long, wallMs: Long) { + processor.execute { + try { + val raw = reassembler.feed(fragment) ?: run { + publish() + return@execute + } + val frame = TrkProtocol.parse(raw) + if (frame == null) { + invalidFrames++ + publish(force = true) + return@execute + } + val activeRecorder = recorder ?: return@execute + when (activeRecorder.commit(frame, elapsedNs, wallMs)) { + CommitResult.PERSISTED, + CommitResult.DUPLICATE, + -> transport.acknowledge(frame.packetSequence, connectionEpoch) + CommitResult.CONFLICT -> fatal("Packet sequence replayed with different bytes") + } + publish() + } catch (error: Exception) { + fatal("Storage failure: ${error.message ?: error.javaClass.simpleName}") + } + } + } + + private fun startRecording() { + if (recorder != null || stopping.get()) return + phase = "Starting" + detail = "Opening capture" + recordingStartElapsedMs = SystemClock.elapsedRealtime() + recordingEndElapsedMs = 0L + startForeground(NOTIFICATION_ID, notification(snapshot())) + acquireWakeLock() + val startWallMs = System.currentTimeMillis() + sessionToken = SecureRandom().nextLong() + val stem = SimpleDateFormat("yyyyMMdd_HHmmss", Locale.US).format(Date(startWallMs)) + val directory = File(filesDir, "captures") + try { + recorder = SessionRecorder( + directory = directory, + stem = "ride_$stem", + startWallClockMs = startWallMs, + startElapsedRealtimeNs = SystemClock.elapsedRealtimeNanos(), + sessionToken = sessionToken, + ) + } catch (error: Exception) { + phase = "Error" + detail = "Cannot open capture: ${error.message}" + releaseWakeLock() + publish(force = true) + stopForeground(STOP_FOREGROUND_REMOVE) + stopSelf() + return + } + detail = "Capture file opened" + publish(force = true) + transport.start(sessionToken) + } + + private fun fatal(message: String) { + mainExecutor.execute { finishRecording(message) } + } + + private fun finishRecording(error: String?) { + if (recorder == null || !stopping.compareAndSet(false, true)) return + phase = "Stopping" + detail = error ?: "Closing capture" + recordingEndElapsedMs = SystemClock.elapsedRealtime() + transport.stop() + publish(force = true) + processor.execute { + val activeRecorder = recorder ?: return@execute + try { + activeRecorder.close( + endWallClockMs = System.currentTimeMillis(), + endElapsedRealtimeNs = SystemClock.elapsedRealtimeNanos(), + error = error, + ) + getSharedPreferences(PREFERENCES, MODE_PRIVATE).edit() + .putString(LAST_CAPTURE, activeRecorder.captureFile.absolutePath) + .apply() + phase = if (error == null) "Stopped" else "Error" + detail = error ?: "Capture safely closed" + } catch (closeError: Exception) { + phase = "Error" + detail = "Could not close capture: ${closeError.message}" + } + publish(force = true) + mainExecutor.execute { + releaseWakeLock() + stopForeground(STOP_FOREGROUND_REMOVE) + stopSelf() + } + } + } + + @SuppressLint("WakelockTimeout") + private fun acquireWakeLock() { + if (wakeLock?.isHeld == true) return + wakeLock = getSystemService(PowerManager::class.java) + .newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "TrikkeRecorder:RideRecording") + .apply { + setReferenceCounted(false) + acquire() + } + } + + private fun releaseWakeLock() { + wakeLock?.let { if (it.isHeld) it.release() } + wakeLock = null + } + + private fun snapshot(): RecorderSnapshot { + val activeRecorder = recorder + val stats = activeRecorder?.stats() + val elapsedEnd = recordingEndElapsedMs.takeIf { it != 0L } ?: SystemClock.elapsedRealtime() + val durationSeconds = if (recordingStartElapsedMs == 0L) 0L + else ((elapsedEnd - recordingStartElapsedMs).coerceAtLeast(0L) / 1_000L) + return RecorderSnapshot( + active = activeRecorder != null && !stopping.get(), + phase = phase, + detail = detail, + capturePath = activeRecorder?.captureFile?.absolutePath, + durationSeconds = durationSeconds, + frameCount = stats?.frameCount ?: 0, + sampleCount = stats?.sampleCount ?: 0, + duplicateCount = stats?.duplicateCount ?: 0, + rejectedFragments = reassembler.rejectedFragmentCount, + invalidFrames = invalidFrames, + packetGaps = stats?.integrity?.packetGaps ?: 0, + sampleGaps = stats?.integrity?.sampleGaps ?: 0, + droppedSamples = stats?.integrity?.droppedSamples ?: 0, + queueOverflows = stats?.integrity?.status?.queueOverflows, + ) + } + + private fun publish(force: Boolean = false) { + val now = SystemClock.elapsedRealtime() + if (!force && now - lastPublishMs < 250) return + lastPublishMs = now + val value = snapshot() + currentSnapshot = value + sendBroadcast( + Intent(ACTION_STATE) + .setPackage(packageName) + .putExtra(EXTRA_ACTIVE, value.active) + .putExtra(EXTRA_PHASE, value.phase) + .putExtra(EXTRA_DETAIL, value.detail) + .putExtra(EXTRA_CAPTURE_PATH, value.capturePath) + .putExtra(EXTRA_DURATION_SECONDS, value.durationSeconds) + .putExtra(EXTRA_FRAMES, value.frameCount) + .putExtra(EXTRA_SAMPLES, value.sampleCount) + .putExtra(EXTRA_DUPLICATES, value.duplicateCount) + .putExtra(EXTRA_REJECTED_FRAGMENTS, value.rejectedFragments) + .putExtra(EXTRA_INVALID_FRAMES, value.invalidFrames) + .putExtra(EXTRA_PACKET_GAPS, value.packetGaps) + .putExtra(EXTRA_SAMPLE_GAPS, value.sampleGaps) + .putExtra(EXTRA_DROPPED, value.droppedSamples) + .putExtra(EXTRA_QUEUE_OVERFLOWS, value.queueOverflows ?: -1L), + ) + if (value.active) { + getSystemService(NotificationManager::class.java) + .notify(NOTIFICATION_ID, notification(value)) + } + } + + private fun notification(value: RecorderSnapshot): Notification { + val openIntent = PendingIntent.getActivity( + this, + 0, + Intent(this, MainActivity::class.java), + PendingIntent.FLAG_IMMUTABLE or PendingIntent.FLAG_UPDATE_CURRENT, + ) + val stopIntent = PendingIntent.getService( + this, + 1, + Intent(this, TelemetryService::class.java).setAction(ACTION_STOP), + PendingIntent.FLAG_IMMUTABLE or PendingIntent.FLAG_UPDATE_CURRENT, + ) + return Notification.Builder(this, CHANNEL_ID) + .setSmallIcon(android.R.drawable.stat_sys_data_bluetooth) + .setContentTitle("Trikke ride recording") + .setContentText("${value.phase}: ${value.sampleCount} samples") + .setContentIntent(openIntent) + .setOngoing(true) + .addAction(Notification.Action.Builder(null, "Stop", stopIntent).build()) + .build() + } + + private fun createNotificationChannel() { + getSystemService(NotificationManager::class.java).createNotificationChannel( + NotificationChannel( + CHANNEL_ID, + getString(R.string.notification_channel_name), + NotificationManager.IMPORTANCE_LOW, + ), + ) + } + + companion object { + const val ACTION_START = "com.jsjdesigns.trikkerecorder.START" + const val ACTION_STOP = "com.jsjdesigns.trikkerecorder.STOP" + const val ACTION_STATE = "com.jsjdesigns.trikkerecorder.STATE" + const val PREFERENCES = "trikke_recorder" + const val LAST_CAPTURE = "last_capture" + const val EXTRA_ACTIVE = "active" + const val EXTRA_PHASE = "phase" + const val EXTRA_DETAIL = "detail" + const val EXTRA_CAPTURE_PATH = "capture_path" + const val EXTRA_DURATION_SECONDS = "duration_seconds" + const val EXTRA_FRAMES = "frames" + const val EXTRA_SAMPLES = "samples" + const val EXTRA_DUPLICATES = "duplicates" + const val EXTRA_REJECTED_FRAGMENTS = "rejected_fragments" + const val EXTRA_INVALID_FRAMES = "invalid_frames" + const val EXTRA_PACKET_GAPS = "packet_gaps" + const val EXTRA_SAMPLE_GAPS = "sample_gaps" + const val EXTRA_DROPPED = "dropped" + const val EXTRA_QUEUE_OVERFLOWS = "queue_overflows" + private const val CHANNEL_ID = "ride_recording" + private const val NOTIFICATION_ID = 4100 + + @Volatile + var currentSnapshot = RecorderSnapshot() + private set + } +} diff --git a/android/app/src/main/kotlin/com/jsjdesigns/trikkerecorder/protocol/BleFrameReassembler.kt b/android/app/src/main/kotlin/com/jsjdesigns/trikkerecorder/protocol/BleFrameReassembler.kt new file mode 100644 index 0000000..2cfc44d --- /dev/null +++ b/android/app/src/main/kotlin/com/jsjdesigns/trikkerecorder/protocol/BleFrameReassembler.kt @@ -0,0 +1,113 @@ +package com.jsjdesigns.trikkerecorder.protocol + +class BleFrameReassembler { + var rejectedFragmentCount: Long = 0 + private set + + private var sequence: Long? = null + private var totalSize = 0 + private var frame = ByteArray(0) + + fun reset() { + sequence = null + totalSize = 0 + frame = ByteArray(0) + } + + fun feed(fragment: ByteArray): ByteArray? { + if (fragment.size <= HEADER_SIZE) { + reject() + return null + } + + val fragmentSequence = fragment.u32(0) + val offset = fragment.u16(4) + val declaredSize = fragment.u16(6) + val dataSize = fragment.size - HEADER_SIZE + if ( + declaredSize !in MIN_FRAME_SIZE..MAX_FRAME_SIZE || + offset >= declaredSize || + offset + dataSize > declaredSize + ) { + reject() + return null + } + + if (offset == 0) { + sequence = fragmentSequence + totalSize = declaredSize + frame = ByteArray(0) + } + if ( + sequence != fragmentSequence || + totalSize != declaredSize || + offset != frame.size + ) { + reject() + return null + } + + frame += fragment.copyOfRange(HEADER_SIZE, fragment.size) + if (frame.size != totalSize) { + return null + } + val completed = frame + reset() + return completed + } + + private fun reject() { + rejectedFragmentCount++ + reset() + } + + companion object { + const val HEADER_SIZE = 8 + const val MIN_FRAME_SIZE = 36 + const val MAX_FRAME_SIZE = 196 + + fun encodeAck(packetSequence: Long): ByteArray = byteArrayOf( + 'A'.code.toByte(), + 'C'.code.toByte(), + 'K'.code.toByte(), + '1'.code.toByte(), + packetSequence.toByte(), + (packetSequence ushr 8).toByte(), + (packetSequence ushr 16).toByte(), + (packetSequence ushr 24).toByte(), + ) + + fun encodeBeginSession(sessionToken: Long): ByteArray = byteArrayOf( + 'B'.code.toByte(), + 'G'.code.toByte(), + 'N'.code.toByte(), + '1'.code.toByte(), + sessionToken.toByte(), + (sessionToken ushr 8).toByte(), + (sessionToken ushr 16).toByte(), + (sessionToken ushr 24).toByte(), + (sessionToken ushr 32).toByte(), + (sessionToken ushr 40).toByte(), + (sessionToken ushr 48).toByte(), + (sessionToken ushr 56).toByte(), + ) + } +} + +internal fun ByteArray.u16(offset: Int): Int = + (this[offset].toInt() and 0xff) or + ((this[offset + 1].toInt() and 0xff) shl 8) + +internal fun ByteArray.u32(offset: Int): Long = + (this[offset].toLong() and 0xff) or + ((this[offset + 1].toLong() and 0xff) shl 8) or + ((this[offset + 2].toLong() and 0xff) shl 16) or + ((this[offset + 3].toLong() and 0xff) shl 24) + +internal fun ByteArray.u64(offset: Int): Long { + var value = 0L + for (index in 0 until 8) { + value = value or ((this[offset + index].toLong() and 0xff) shl (index * 8)) + } + return value +} diff --git a/android/app/src/main/kotlin/com/jsjdesigns/trikkerecorder/protocol/TrkProtocol.kt b/android/app/src/main/kotlin/com/jsjdesigns/trikkerecorder/protocol/TrkProtocol.kt new file mode 100644 index 0000000..40222bc --- /dev/null +++ b/android/app/src/main/kotlin/com/jsjdesigns/trikkerecorder/protocol/TrkProtocol.kt @@ -0,0 +1,168 @@ +package com.jsjdesigns.trikkerecorder.protocol + +import java.util.zip.CRC32 + +data class TransportStatus( + val sensorReadFailures: Long, + val queueOverflows: Long, + val beginRetries: Long, + val disconnects: Long, + val sendFailures: Long, + val replays: Long, + val invalidAcks: Long, +) + +data class TrkFrame( + val raw: ByteArray, + val packetType: Int, + val flags: Int, + val packetSequence: Long, + val baseTimestampUs: Long, + val droppedSampleCount: Long, + val loopOverrunCount: Long, + val sampleSequences: LongArray, + val status: TransportStatus?, +) { + val sampleCount: Int + get() = sampleSequences.size +} + +object TrkProtocol { + const val HEADER_SIZE = 36 + const val MAX_FRAME_SIZE = 196 + const val PACKET_METADATA = 1 + const val PACKET_SAMPLES = 2 + const val PACKET_STATUS = 3 + + fun parse(raw: ByteArray): TrkFrame? { + if (raw.size !in HEADER_SIZE..MAX_FRAME_SIZE) return null + if ( + raw[0] != 'T'.code.toByte() || raw[1] != 'R'.code.toByte() || + raw[2] != 'K'.code.toByte() || raw[3] != '1'.code.toByte() + ) return null + + val version = raw[4].toInt() and 0xff + val packetType = raw[5].toInt() and 0xff + val headerSize = raw[6].toInt() and 0xff + val recordSize = raw[7].toInt() and 0xff + val recordCount = raw[8].toInt() and 0xff + val flags = raw[9].toInt() and 0xff + val payloadSize = raw.u16(10) + if (version != 1 || headerSize != HEADER_SIZE || HEADER_SIZE + payloadSize != raw.size) { + return null + } + + val validShape = when (packetType) { + PACKET_METADATA -> recordSize == 0 && recordCount == 0 && payloadSize == 48 + PACKET_SAMPLES -> + recordSize == 20 && recordCount in 1..8 && payloadSize == recordSize * recordCount + PACKET_STATUS -> recordSize == 0 && recordCount == 0 && payloadSize == 32 + else -> false + } + if (!validShape || raw.u32(32) != calculateCrc(raw)) return null + + val status = if (packetType == PACKET_STATUS) { + if (raw.u16(36) != 1 || raw.u16(38) != 32) return null + TransportStatus( + sensorReadFailures = raw.u32(40), + queueOverflows = raw.u32(44), + beginRetries = raw.u32(48), + disconnects = raw.u32(52), + sendFailures = raw.u32(56), + replays = raw.u32(60), + invalidAcks = raw.u32(64), + ) + } else { + null + } + + val sampleSequences = if (packetType == PACKET_SAMPLES) { + LongArray(recordCount) { index -> raw.u32(HEADER_SIZE + index * recordSize) } + } else { + LongArray(0) + } + return TrkFrame( + raw = raw, + packetType = packetType, + flags = flags, + packetSequence = raw.u32(12), + baseTimestampUs = raw.u64(16), + droppedSampleCount = raw.u32(24), + loopOverrunCount = raw.u32(28), + sampleSequences = sampleSequences, + status = status, + ) + } + + private fun calculateCrc(raw: ByteArray): Long { + val crc = CRC32() + crc.update(raw, 4, 28) + crc.update(raw, HEADER_SIZE, raw.size - HEADER_SIZE) + return crc.value + } +} + +data class IntegritySnapshot( + val packetGaps: Long, + val packetResets: Long, + val sampleGaps: Long, + val sampleResets: Long, + val droppedSamples: Long, + val loopOverruns: Long, + val status: TransportStatus?, +) + +class IntegrityTracker { + private var previousPacket: Long? = null + private var previousSample: Long? = null + private var packetGaps = 0L + private var packetResets = 0L + private var sampleGaps = 0L + private var sampleResets = 0L + private var droppedSamples = 0L + private var loopOverruns = 0L + private var status: TransportStatus? = null + + fun observe(frame: TrkFrame) { + previousPacket?.let { previous -> + val result = classify(previous, frame.packetSequence) + packetGaps += result.first + packetResets += result.second + } + previousPacket = frame.packetSequence + droppedSamples = frame.droppedSampleCount + loopOverruns = frame.loopOverrunCount + frame.status?.let { status = it } + + frame.sampleSequences.forEach { sequence -> + previousSample?.let { previous -> + val result = classify(previous, sequence) + sampleGaps += result.first + sampleResets += result.second + } + previousSample = sequence + } + } + + fun snapshot() = IntegritySnapshot( + packetGaps = packetGaps, + packetResets = packetResets, + sampleGaps = sampleGaps, + sampleResets = sampleResets, + droppedSamples = droppedSamples, + loopOverruns = loopOverruns, + status = status, + ) + + companion object { + fun classify(previous: Long, current: Long): Pair { + val expected = (previous + 1) and 0xffff_ffffL + val forward = (current - expected) and 0xffff_ffffL + return when { + forward == 0L -> 0L to 0L + forward < 0x8000_0000L -> forward to 0L + else -> 0L to 1L + } + } + } +} diff --git a/android/app/src/main/kotlin/com/jsjdesigns/trikkerecorder/storage/SessionRecorder.kt b/android/app/src/main/kotlin/com/jsjdesigns/trikkerecorder/storage/SessionRecorder.kt new file mode 100644 index 0000000..15706d4 --- /dev/null +++ b/android/app/src/main/kotlin/com/jsjdesigns/trikkerecorder/storage/SessionRecorder.kt @@ -0,0 +1,180 @@ +package com.jsjdesigns.trikkerecorder.storage + +import com.jsjdesigns.trikkerecorder.protocol.IntegritySnapshot +import com.jsjdesigns.trikkerecorder.protocol.IntegrityTracker +import com.jsjdesigns.trikkerecorder.protocol.TrkFrame +import java.io.File +import java.io.FileOutputStream + +enum class CommitResult { + PERSISTED, + DUPLICATE, + CONFLICT, +} + +data class RecorderStats( + val frameCount: Long, + val sampleCount: Long, + val duplicateCount: Long, + val integrity: IntegritySnapshot, +) + +class SessionRecorder( + directory: File, + stem: String, + private val startWallClockMs: Long, + private val startElapsedRealtimeNs: Long, + private val sessionToken: Long, +) : AutoCloseable { + val captureFile = File(directory, "$stem.trk") + val summaryFile = File(directory, "$stem.session.json") + + private val output: FileOutputStream + private val integrity = IntegrityTracker() + private var lastSequence: Long? = null + private var lastRaw: ByteArray? = null + private var frameCount = 0L + private var sampleCount = 0L + private var duplicateCount = 0L + private var firstFrame: FrameClock? = null + private var lastFrame: FrameClock? = null + private var closed = false + + init { + check(directory.exists() || directory.mkdirs()) { "Cannot create ${directory.path}" } + output = FileOutputStream(captureFile, false) + writeSummary(complete = false, endWallClockMs = null, endElapsedRealtimeNs = null, error = null) + } + + @Synchronized + fun commit( + frame: TrkFrame, + receivedElapsedRealtimeNs: Long, + receivedWallClockMs: Long, + ): CommitResult { + check(!closed) { "Recorder is closed" } + if (lastSequence == frame.packetSequence) { + if (lastRaw!!.contentEquals(frame.raw)) { + duplicateCount++ + return CommitResult.DUPLICATE + } + return CommitResult.CONFLICT + } + + output.write(frame.raw) + output.flush() + output.fd.sync() + + integrity.observe(frame) + frameCount++ + sampleCount += frame.sampleCount + lastSequence = frame.packetSequence + lastRaw = frame.raw.copyOf() + val clock = FrameClock( + packetSequence = frame.packetSequence, + deviceBaseTimestampUs = frame.baseTimestampUs, + phoneElapsedRealtimeNs = receivedElapsedRealtimeNs, + phoneWallClockMs = receivedWallClockMs, + ) + if (firstFrame == null) firstFrame = clock + lastFrame = clock + return CommitResult.PERSISTED + } + + @Synchronized + fun stats(): RecorderStats = RecorderStats( + frameCount = frameCount, + sampleCount = sampleCount, + duplicateCount = duplicateCount, + integrity = integrity.snapshot(), + ) + + @Synchronized + fun close(endWallClockMs: Long, endElapsedRealtimeNs: Long, error: String? = null) { + if (closed) return + closed = true + output.flush() + output.fd.sync() + output.close() + writeSummary( + complete = error == null, + endWallClockMs = endWallClockMs, + endElapsedRealtimeNs = endElapsedRealtimeNs, + error = error, + ) + } + + override fun close() { + close(System.currentTimeMillis(), System.nanoTime()) + } + + private fun writeSummary( + complete: Boolean, + endWallClockMs: Long?, + endElapsedRealtimeNs: Long?, + error: String?, + ) { + val stats = stats() + val status = stats.integrity.status + val json = buildString { + append("{\n") + append(" \"schema\": 1,\n") + append(" \"captureFile\": \"").append(captureFile.name).append("\",\n") + append(" \"sessionTokenHex\": \"") + .append(java.lang.Long.toUnsignedString(sessionToken, 16).padStart(16, '0')) + .append("\",\n") + append(" \"complete\": ").append(complete).append(",\n") + append(" \"startWallClockMs\": ").append(startWallClockMs).append(",\n") + append(" \"startElapsedRealtimeNs\": ").append(startElapsedRealtimeNs).append(",\n") + append(" \"endWallClockMs\": ").append(endWallClockMs ?: "null").append(",\n") + append(" \"endElapsedRealtimeNs\": ").append(endElapsedRealtimeNs ?: "null").append(",\n") + append(" \"firstFrame\": ").append(firstFrame?.json() ?: "null").append(",\n") + append(" \"lastFrame\": ").append(lastFrame?.json() ?: "null").append(",\n") + append(" \"frames\": ").append(stats.frameCount).append(",\n") + append(" \"samples\": ").append(stats.sampleCount).append(",\n") + append(" \"duplicateReplays\": ").append(stats.duplicateCount).append(",\n") + append(" \"packetGaps\": ").append(stats.integrity.packetGaps).append(",\n") + append(" \"packetResets\": ").append(stats.integrity.packetResets).append(",\n") + append(" \"sampleGaps\": ").append(stats.integrity.sampleGaps).append(",\n") + append(" \"sampleResets\": ").append(stats.integrity.sampleResets).append(",\n") + append(" \"droppedSamples\": ").append(stats.integrity.droppedSamples).append(",\n") + append(" \"loopOverruns\": ").append(stats.integrity.loopOverruns).append(",\n") + append(" \"queueOverflows\": ").append(status?.queueOverflows ?: "null").append(",\n") + append(" \"transportDisconnects\": ").append(status?.disconnects ?: "null").append(",\n") + append(" \"transportReplays\": ").append(status?.replays ?: "null").append(",\n") + append(" \"error\": ").append(error?.let { "\"${escape(it)}\"" } ?: "null").append("\n") + append("}\n") + } + FileOutputStream(summaryFile, false).use { summary -> + summary.write(json.toByteArray(Charsets.UTF_8)) + summary.flush() + summary.fd.sync() + } + } + + private fun escape(value: String): String = buildString { + value.forEach { character -> + when (character) { + '\\' -> append("\\\\") + '"' -> append("\\\"") + '\n' -> append("\\n") + '\r' -> append("\\r") + '\t' -> append("\\t") + else -> append(character) + } + } + } + + private data class FrameClock( + val packetSequence: Long, + val deviceBaseTimestampUs: Long, + val phoneElapsedRealtimeNs: Long, + val phoneWallClockMs: Long, + ) { + fun json(): String = + "{\"packetSequence\":$packetSequence," + + "\"deviceBaseTimestampUs\":$deviceBaseTimestampUs," + + "\"phoneElapsedRealtimeNs\":$phoneElapsedRealtimeNs," + + "\"phoneWallClockMs\":$phoneWallClockMs}" + } +} diff --git a/android/app/src/main/res/drawable/ic_launcher.xml b/android/app/src/main/res/drawable/ic_launcher.xml new file mode 100644 index 0000000..32f5e62 --- /dev/null +++ b/android/app/src/main/res/drawable/ic_launcher.xml @@ -0,0 +1,12 @@ + + + + diff --git a/android/app/src/main/res/values/strings.xml b/android/app/src/main/res/values/strings.xml new file mode 100644 index 0000000..ae57448 --- /dev/null +++ b/android/app/src/main/res/values/strings.xml @@ -0,0 +1,5 @@ + + Trikke Recorder + Ride recording + Export last .trk + diff --git a/android/app/src/main/res/values/styles.xml b/android/app/src/main/res/values/styles.xml new file mode 100644 index 0000000..3f97def --- /dev/null +++ b/android/app/src/main/res/values/styles.xml @@ -0,0 +1,8 @@ + + + diff --git a/android/app/src/main/res/xml/data_extraction_rules.xml b/android/app/src/main/res/xml/data_extraction_rules.xml new file mode 100644 index 0000000..2130cfd --- /dev/null +++ b/android/app/src/main/res/xml/data_extraction_rules.xml @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/android/app/src/test/kotlin/com/jsjdesigns/trikkerecorder/protocol/ProtocolContractTest.kt b/android/app/src/test/kotlin/com/jsjdesigns/trikkerecorder/protocol/ProtocolContractTest.kt new file mode 100644 index 0000000..f5ae2af --- /dev/null +++ b/android/app/src/test/kotlin/com/jsjdesigns/trikkerecorder/protocol/ProtocolContractTest.kt @@ -0,0 +1,137 @@ +package com.jsjdesigns.trikkerecorder.protocol + +import com.jsjdesigns.trikkerecorder.storage.CommitResult +import com.jsjdesigns.trikkerecorder.storage.SessionRecorder +import java.nio.file.Files +import org.junit.Assert.assertArrayEquals +import org.junit.Assert.assertEquals +import org.junit.Assert.assertFalse +import org.junit.Assert.assertNotNull +import org.junit.Assert.assertNull +import org.junit.Assert.assertTrue +import org.junit.Test + +class ProtocolContractTest { + private val fixture: ByteArray by lazy { + checkNotNull(javaClass.classLoader?.getResourceAsStream("ble_mtu_race_4bf00eb.trk")) { + "Hardware fixture was not packaged as a test resource" + }.use { it.readBytes() } + } + + @Test + fun hardwareFixtureMatchesAndroidParserContract() { + val frames = splitFrames(fixture) + assertTrue(frames.size > 100) + assertTrue(frames.all { TrkProtocol.parse(it) != null }) + assertTrue(frames.any { TrkProtocol.parse(it)?.packetType == TrkProtocol.PACKET_METADATA }) + assertTrue(frames.any { TrkProtocol.parse(it)?.packetType == TrkProtocol.PACKET_SAMPLES }) + assertTrue(frames.any { TrkProtocol.parse(it)?.packetType == TrkProtocol.PACKET_STATUS }) + } + + @Test + fun crcDamageIsRejected() { + val raw = splitFrames(fixture).first().copyOf() + raw[raw.lastIndex] = (raw.last().toInt() xor 0x80).toByte() + assertNull(TrkProtocol.parse(raw)) + } + + @Test + fun fragmentReplayRestartsAndCompletesExactFrame() { + val raw = splitFrames(fixture).first() + val sequence = raw.u32(12) + val reassembler = BleFrameReassembler() + + assertNull(reassembler.feed(fragment(raw, sequence, 0, 20))) + assertNull(reassembler.feed(fragment(raw, sequence, 0, 40))) + val completed = reassembler.feed(fragment(raw, sequence, 40, raw.size - 40)) + + assertArrayEquals(raw, completed) + assertEquals(0, reassembler.rejectedFragmentCount) + assertArrayEquals( + byteArrayOf('A'.code.toByte(), 'C'.code.toByte(), 'K'.code.toByte(), '1'.code.toByte()) + + raw.copyOfRange(12, 16), + BleFrameReassembler.encodeAck(sequence), + ) + } + + @Test + fun missingOrOutOfOrderFragmentIsRejected() { + val raw = splitFrames(fixture).first() + val sequence = raw.u32(12) + val reassembler = BleFrameReassembler() + assertNull(reassembler.feed(fragment(raw, sequence, 20, 20))) + assertEquals(1, reassembler.rejectedFragmentCount) + } + + @Test + fun persistencePrecedesDedupeAndSummaryClosure() { + val parsed = checkNotNull(TrkProtocol.parse(splitFrames(fixture).first())) + val directory = Files.createTempDirectory("trikke-recorder-test").toFile() + try { + val recorder = SessionRecorder(directory, "ride_test", 1_000, 2_000, 0x0102030405060708) + assertFalse(recorder.summaryFile.readText().contains("\"complete\": true")) + assertEquals(CommitResult.PERSISTED, recorder.commit(parsed, 3_000, 4_000)) + assertEquals(CommitResult.DUPLICATE, recorder.commit(parsed, 5_000, 6_000)) + assertArrayEquals(parsed.raw, recorder.captureFile.readBytes()) + + val conflicting = parsed.copy(raw = parsed.raw.copyOf().also { it[it.lastIndex]++ }) + assertEquals(CommitResult.CONFLICT, recorder.commit(conflicting, 7_000, 8_000)) + assertArrayEquals(parsed.raw, recorder.captureFile.readBytes()) + + recorder.close(9_000, 10_000) + val summary = recorder.summaryFile.readText() + assertTrue(summary.contains("\"complete\": true")) + assertTrue(summary.contains("\"sessionTokenHex\": \"0102030405060708\"")) + assertTrue(summary.contains("\"frames\": 1")) + assertTrue(summary.contains("\"duplicateReplays\": 1")) + } finally { + directory.deleteRecursively() + } + } + + @Test + fun unsignedSequenceClassificationHandlesWrapAndReset() { + assertEquals(0L to 0L, IntegrityTracker.classify(0xffff_ffffL, 0)) + assertEquals(2L to 0L, IntegrityTracker.classify(0xffff_fffeL, 1)) + assertEquals(0L to 1L, IntegrityTracker.classify(1_000, 0)) + } + + @Test + fun beginSessionCommandCarriesStableUnsignedToken() { + assertArrayEquals( + byteArrayOf( + 'B'.code.toByte(), 'G'.code.toByte(), 'N'.code.toByte(), '1'.code.toByte(), + 0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, + ), + BleFrameReassembler.encodeBeginSession(0x0102030405060708), + ) + } + + private fun splitFrames(stream: ByteArray): List { + val frames = mutableListOf() + var offset = 0 + while (offset < stream.size) { + assertTrue("truncated header at $offset", offset + TrkProtocol.HEADER_SIZE <= stream.size) + val payloadSize = stream.u16(offset + 10) + val size = TrkProtocol.HEADER_SIZE + payloadSize + assertTrue("truncated frame at $offset", offset + size <= stream.size) + frames += stream.copyOfRange(offset, offset + size) + offset += size + } + assertEquals(stream.size, offset) + return frames + } + + private fun fragment(raw: ByteArray, sequence: Long, offset: Int, size: Int): ByteArray { + val envelope = ByteArray(BleFrameReassembler.HEADER_SIZE) + envelope[0] = sequence.toByte() + envelope[1] = (sequence ushr 8).toByte() + envelope[2] = (sequence ushr 16).toByte() + envelope[3] = (sequence ushr 24).toByte() + envelope[4] = offset.toByte() + envelope[5] = (offset ushr 8).toByte() + envelope[6] = raw.size.toByte() + envelope[7] = (raw.size ushr 8).toByte() + return envelope + raw.copyOfRange(offset, offset + size) + } +} diff --git a/android/build.gradle.kts b/android/build.gradle.kts new file mode 100644 index 0000000..fd4b881 --- /dev/null +++ b/android/build.gradle.kts @@ -0,0 +1,3 @@ +plugins { + id("com.android.application") version "9.2.1" apply false +} diff --git a/android/gradle.properties b/android/gradle.properties new file mode 100644 index 0000000..e696167 --- /dev/null +++ b/android/gradle.properties @@ -0,0 +1,3 @@ +org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8 +android.useAndroidX=true +kotlin.code.style=official diff --git a/android/gradle/gradle-daemon-jvm.properties b/android/gradle/gradle-daemon-jvm.properties new file mode 100644 index 0000000..fa4ed51 --- /dev/null +++ b/android/gradle/gradle-daemon-jvm.properties @@ -0,0 +1,12 @@ +#This file is generated by updateDaemonJvm +toolchainUrl.FREE_BSD.AARCH64=https\://api.foojay.io/disco/v3.0/ids/cf726b4a1c84b50457225f9bba6d7650/redirect +toolchainUrl.FREE_BSD.X86_64=https\://api.foojay.io/disco/v3.0/ids/fa1e318c287360478e3c83a9a3ef1007/redirect +toolchainUrl.LINUX.AARCH64=https\://api.foojay.io/disco/v3.0/ids/cf726b4a1c84b50457225f9bba6d7650/redirect +toolchainUrl.LINUX.X86_64=https\://api.foojay.io/disco/v3.0/ids/fa1e318c287360478e3c83a9a3ef1007/redirect +toolchainUrl.MAC_OS.AARCH64=https\://api.foojay.io/disco/v3.0/ids/c2dd35c9d0aaf0ba6ad0791320f99dfc/redirect +toolchainUrl.MAC_OS.X86_64=https\://api.foojay.io/disco/v3.0/ids/e5810bd7fd1f8a586644409d395a7e55/redirect +toolchainUrl.UNIX.AARCH64=https\://api.foojay.io/disco/v3.0/ids/cf726b4a1c84b50457225f9bba6d7650/redirect +toolchainUrl.UNIX.X86_64=https\://api.foojay.io/disco/v3.0/ids/fa1e318c287360478e3c83a9a3ef1007/redirect +toolchainUrl.WINDOWS.AARCH64=https\://api.foojay.io/disco/v3.0/ids/7b3c4877c0749019e6805bb61e421497/redirect +toolchainUrl.WINDOWS.X86_64=https\://api.foojay.io/disco/v3.0/ids/d76df094a9cbbabd3b08251f9e61444a/redirect +toolchainVersion=25 diff --git a/android/gradle/wrapper/gradle-wrapper.jar b/android/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000000000000000000000000000000000000..d997cfc60f4cff0e7451d19d49a82fa986695d07 GIT binary patch literal 48966 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

`Lem|V$A>eR0uN8Y&sdjtu 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

1bvi{DS7E@q1{$_8->K{_OWv2 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 literal 0 HcmV?d00001 diff --git a/android/gradle/wrapper/gradle-wrapper.properties b/android/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000..c61a118 --- /dev/null +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,7 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-9.4.1-bin.zip +networkTimeout=10000 +validateDistributionUrl=true +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/android/gradlew b/android/gradlew new file mode 100755 index 0000000..739907d --- /dev/null +++ b/android/gradlew @@ -0,0 +1,248 @@ +#!/bin/sh + +# +# Copyright © 2015 the original authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# SPDX-License-Identifier: Apache-2.0 +# + +############################################################################## +# +# Gradle start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/2d6327017519d23b96af35865dc997fcb544fb40/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# +############################################################################## + +# Attempt to set APP_HOME + +# Resolve links: $0 may be a link +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac +done + +# This is normally unused +# shellcheck disable=SC2034 +APP_BASE_NAME=${0##*/} +# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) +APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD=maximum + +warn () { + echo "$*" +} >&2 + +die () { + echo + echo "$*" + echo + exit 1 +} >&2 + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; +esac + + + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD=$JAVA_HOME/jre/sh/java + else + JAVACMD=$JAVA_HOME/bin/java + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD=java + if ! command -v java >/dev/null 2>&1 + then + die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +fi + +# Increase the maximum file descriptors if we can. +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac +fi + +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. + +# For Cygwin or MSYS, switch paths to Windows format before running java +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + + # Now convert the arguments - kludge to limit ourselves to /bin/sh + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) + fi + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg + done +fi + + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Collect all arguments for the java command: +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, +# and any embedded shellness will be escaped. +# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be +# treated as '${Hostname}' itself on the command line. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \ + "$@" + +# Stop when "xargs" is not available. +if ! command -v xargs >/dev/null 2>&1 +then + die "xargs is not available" +fi + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# + +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' + +exec "$JAVACMD" "$@" diff --git a/android/gradlew.bat b/android/gradlew.bat new file mode 100644 index 0000000..c4bdd3a --- /dev/null +++ b/android/gradlew.bat @@ -0,0 +1,93 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem +@rem SPDX-License-Identifier: Apache-2.0 +@rem + +@if "%DEBUG%"=="" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%"=="" set DIRNAME=. +@rem This is normally unused +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if %ERRORLEVEL% equ 0 goto execute + +echo. 1>&2 +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. 1>&2 +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 + +goto fail + +:execute +@rem Setup the command line + + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %* + +:end +@rem End local scope for the variables with windows NT shell +if %ERRORLEVEL% equ 0 goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +set EXIT_CODE=%ERRORLEVEL% +if %EXIT_CODE% equ 0 set EXIT_CODE=1 +if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% +exit /b %EXIT_CODE% + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/android/settings.gradle.kts b/android/settings.gradle.kts new file mode 100644 index 0000000..cf4ad7e --- /dev/null +++ b/android/settings.gradle.kts @@ -0,0 +1,18 @@ +pluginManagement { + repositories { + google() + mavenCentral() + gradlePluginPortal() + } +} + +dependencyResolutionManagement { + repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS) + repositories { + google() + mavenCentral() + } +} + +rootProject.name = "TrikkeRecorder" +include(":app") diff --git a/docs/binary-record-v1.md b/docs/binary-record-v1.md index 49bc2d1..a6d5943 100644 --- a/docs/binary-record-v1.md +++ b/docs/binary-record-v1.md @@ -106,15 +106,17 @@ does not by itself prove corruption or a hostile receiver. ## Buffering -Acquisition runs in a dedicated higher-priority task and writes complete samples -to a 1024-entry RAM queue. The lower-priority output task batches up to eight -records per frame. At 100 Hz this queue represents about 10.24 seconds of +Under BLE, acquisition does not start until the version-2 session handshake has +established a clean capture boundary. Once started, the dedicated +higher-priority acquisition task writes complete samples to a statically +reserved 3072-entry RAM queue. The lower-priority output task batches up to eight +records per frame. At 100 Hz this queue represents about 30.72 seconds of decoupling when the transport reports backpressure or failure accurately. A failed write retains and retries the same encoded packet rather than dequeuing -more samples, so the queue accumulates the outage backlog. After reconnection, -the oldest retained data is sent first. If the queue fills, acquisition drops -new samples rather than overwriting older ones; sequence gaps and the cumulative -lost-sample counter expose that permanent loss. +more samples, so the queue accumulates the outage backlog. After a same-token +reconnection, the oldest retained data is sent first. If the queue fills, +acquisition drops new samples rather than overwriting older ones; sequence gaps +and the cumulative lost-sample counter expose that permanent loss. The shared transport state machine distinguishes three nonfatal states. `RETRY` is valid only from initial submission: it means zero bytes were accepted and the @@ -136,7 +138,8 @@ the endpoint accepts them. CRC and sequence checks make resulting loss visible, but an application acknowledgement and replay window are still required to guarantee receipt. Accordingly, USB `COMPLETE` means endpoint drain, while reliable BLE reserves `COMPLETE` for an application ACK of the exact frame. See -`ble-transport-v1.md` for fragmentation, replay, and UUIDs. +`ble-transport-v2.md` for session establishment, fragmentation, replay, and +UUIDs. Receivers report bytes left in an incomplete trailing frame when capture ends. Those bytes cannot pass CRC validation and are not silently admitted as samples. diff --git a/docs/ble-transport-v1.md b/docs/ble-transport-v1.md deleted file mode 100644 index e17e926..0000000 --- a/docs/ble-transport-v1.md +++ /dev/null @@ -1,68 +0,0 @@ -# Reliable BLE Transport — Version 1 - -BLE carries the unchanged, CRC-protected `TRK1` frames defined in -`binary-record-v1.md`. The default peripheral name is `TrikkeSensor`. - -## GATT service - -| Purpose | UUID | Properties | -| --- | --- | --- | -| Service | `7d2ea000-f75b-4a9b-8fbe-3d4c2a1e9c10` | Primary service | -| Data | `7d2ea000-f75b-4a9b-8fbe-3d4c2a1e9c11` | Notify | -| ACK | `7d2ea000-f75b-4a9b-8fbe-3d4c2a1e9c12` | Write, write without response | - -The firmware prefers a 256-byte ATT MTU, allowing the largest 196-byte `TRK1` -frame and its eight-byte BLE envelope to fit in one notification. Smaller MTUs -remain protocol-compatible; firmware sends at most eight fragments per bounded -poll, although sustained 100 Hz delivery still depends on the negotiated link. - -## Data notification envelope - -Every notification starts with an eight-byte little-endian envelope: - -| Offset | Size | Field | -| ---: | ---: | --- | -| 0 | 4 | `TRK1` packet sequence | -| 4 | 2 | Byte offset within the complete `TRK1` frame | -| 6 | 2 | Complete `TRK1` frame size | -| 8 | remaining | Consecutive frame bytes at that offset | - -Offset zero starts or restarts a frame. A receiver appends only consecutive -offsets for the same sequence and total size, then validates the complete -`TRK1` header and CRC. A malformed or missing fragment is not acknowledged. - -## Application ACK and replay - -After validating and persisting a frame, the receiver writes exactly eight bytes -to the ACK characteristic: ASCII `ACK1`, then the acknowledged packet sequence -as little-endian uint32. Firmware accepts an ACK only for the frame it currently -owns and only from the active subscribed connection. - -`COMPLETE` is not reported to the output task until that ACK arrives. Until then: - -- a one-second ACK timeout replays the frame from offset zero; -- disconnect or notification unsubscription preserves the frame; -- the next subscription replays it from offset zero; -- BLE polling returns `PENDING`, never `RETRY`, after ownership begins. - -The ACK itself can be lost after the receiver persisted the frame. Receivers -therefore compare the sequence and raw bytes with their last persisted frame, -avoid writing a duplicate, and ACK the replay again. The reference -`tools/capture_ble.py` implements this ordering. - -The rejected-ACK counter is diagnostic, not a pure corruption count. A valid -duplicate ACK can arrive after the output task has already completed that frame -and begun the next one; firmware then rejects and counts the now-stale write. - -BLE notification success only means the fragment entered the stack. The `ACK1` -write is the end-to-end boundary. It deliberately confirms application -persistence rather than radio or ATT delivery alone. - -Version 1 is an unauthenticated, single-connection prototype service. It does -not yet provide pairing, authorization, or confidentiality against a nearby -peer; those are separate from the loss/replay guarantees above. A nearby peer -can also deny availability by subscribing and never acknowledging: firmware -correctly retains and replays the owned frame, but the RAM queue eventually -fills while the legitimate receiver remains excluded. Pairing and connection -authorization are required before treating this as a hostile-environment -logger. diff --git a/docs/ble-transport-v2.md b/docs/ble-transport-v2.md new file mode 100644 index 0000000..ebaaa6d --- /dev/null +++ b/docs/ble-transport-v2.md @@ -0,0 +1,119 @@ +# Reliable BLE Transport — Version 2 + +BLE carries the unchanged, CRC-protected `TRK1` frames defined in +`binary-record-v1.md`. The default peripheral name is `TrikkeSensor`. Version 2 +adds a mandatory, idempotent recording-session handshake; the data envelope and +application ACK remain unchanged from version 1. + +## GATT service + +| Purpose | UUID | Properties | +| --- | --- | --- | +| Service | `7d2ea000-f75b-4a9b-8fbe-3d4c2a1e9c10` | Primary service | +| Data | `7d2ea000-f75b-4a9b-8fbe-3d4c2a1e9c11` | Notify | +| ACK | `7d2ea000-f75b-4a9b-8fbe-3d4c2a1e9c12` | Write, write without response | +| Control | `7d2ea000-f75b-4a9b-8fbe-3d4c2a1e9c13` | Write | + +The firmware prefers a 256-byte ATT MTU, allowing the largest 196-byte `TRK1` +frame and its eight-byte BLE envelope to fit in one notification. Smaller MTUs +remain protocol-compatible; firmware sends at most eight fragments per bounded +poll, although sustained 100 Hz delivery still depends on the negotiated link. + +## Recording-session handshake + +Every new capture generates a random uint64 session token. The reference +receivers first write exactly 12 bytes to Control—ASCII `BGN1`, then that token +as little-endian uint64—and enable data notifications after that write succeeds. +Firmware also accepts the reverse order: it tracks the raw CCCD state separately +from session authorization and treats the connection as subscribed as soon as +both conditions are true. Notifications never flow before authorization. + +When the token differs from the C3's active token, firmware stores it in +RTC-retained memory and performs a controlled software restart. Acquisition and +output tasks remain stopped after boot. The receiver reconnects and repeats the +same `BGN1` write; firmware recognizes the retained token, authorizes that BLE +connection, starts acquisition with empty queues and zeroed volatile counters, +and accepts the subsequent notification subscription. + +The Android acceptance capture measured 10.797 seconds from the user's Start +action to the first durably persisted frame. That includes the initial control +write, controlled restart, advertising and scan latency, GATT reconnection, +same-token authorization, notification subscription, and first frame delivery. +This startup interval is expected and is not part of the recorded sensor stream. + +The same token must be written on every reconnect during one recording. That +write is idempotent: it authorizes the new connection without restarting or +discarding the in-flight frame and sample backlog. A different token is an +explicit new-session boundary and deliberately discards all prior volatile +state through the controlled restart. + +Firmware does not start acquisition after boot and does not honor a notification +subscription until a valid control write authorizes the connection. This avoids +pre-session queue overflow and prevents an older client from bypassing the +session boundary. The token provides idempotence, not authentication or secrecy. + +RTC token recovery is intentionally accepted only after `ESP_RST_SW`. A panic, +watchdog, brownout, or power-on reset discards the token and all volatile stream +state. When the still-recording receiver reconnects and rewrites its unchanged +token, firmware treats it as a new token, performs one additional controlled +restart, and authorizes the following same-token reconnect. Packet and sample +sequences restart at zero inside the receiver's existing file, where the reset is +observable through integrity tracking. This favors a known clean state over +silently treating an uncontrolled reset as continuation of the old session. + +## Data notification envelope + +Every notification starts with an eight-byte little-endian envelope: + +| Offset | Size | Field | +| ---: | ---: | --- | +| 0 | 4 | `TRK1` packet sequence | +| 4 | 2 | Byte offset within the complete `TRK1` frame | +| 6 | 2 | Complete `TRK1` frame size | +| 8 | remaining | Consecutive frame bytes at that offset | + +Offset zero starts or restarts a frame. A receiver appends only consecutive +offsets for the same sequence and total size, then validates the complete +`TRK1` header and CRC. A malformed or missing fragment is not acknowledged. + +## Application ACK and replay + +After validating and persisting a frame, the receiver writes exactly eight bytes +to the ACK characteristic: ASCII `ACK1`, then the acknowledged packet sequence +as little-endian uint32. Firmware accepts an ACK only for the frame it currently +owns and only from the active subscribed connection. + +`COMPLETE` is not reported to the output task until that ACK arrives. Until then: + +- a one-second ACK timeout replays the frame from offset zero; +- disconnect or notification unsubscription preserves the frame; +- the next subscription, after the same-token control write, replays it from + offset zero; +- BLE polling returns `PENDING`, never `RETRY`, after ownership begins. + +The ACK itself can be lost after the receiver persisted the frame. Receivers +therefore compare the sequence and raw bytes with their last persisted frame, +avoid writing a duplicate, and ACK the replay again. Both reference receivers +implement this ordering. + +The rejected-ACK counter is diagnostic, not a pure corruption count. A valid +duplicate ACK can arrive after the output task has already completed that frame +and begun the next one; firmware then rejects and counts the now-stale write. + +BLE notification success only means the fragment entered the stack. The `ACK1` +write is the end-to-end boundary. It deliberately confirms application +persistence rather than radio or ATT delivery alone. + +The current firmware reserves a 3072-sample acquisition queue, providing 30.72 +seconds of transport-outage tolerance at the nominal 100 Hz rate. This interval +includes link-loss detection, scanning, GATT reconnection, session +reauthorization, notification subscription, and replay—not merely the time a +phone's Bluetooth control is visibly off. Longer interruptions remain bounded +and detectable through sample-sequence gaps and the queue-overflow counter. + +Version 2 remains an unauthenticated, single-connection prototype service. It +does not yet provide pairing, authorization, or confidentiality against a nearby +peer; those are separate from the session and replay guarantees above. A nearby +peer can also deny availability by connecting and withholding the control write, +or by subscribing and never acknowledging. Pairing and connection authorization +are required before treating this as a hostile-environment logger. diff --git a/main/trikke_ble_protocol.c b/main/trikke_ble_protocol.c index 72a66a9..a7da91a 100644 --- a/main/trikke_ble_protocol.c +++ b/main/trikke_ble_protocol.c @@ -15,6 +15,12 @@ static uint32_t get_u32_le(const uint8_t *input) ((uint32_t)input[2] << 16) | ((uint32_t)input[3] << 24); } +static uint64_t get_u64_le(const uint8_t *input) +{ + return (uint64_t)get_u32_le(input) | + ((uint64_t)get_u32_le(input + 4) << 32); +} + static void put_u16_le(uint8_t *output, uint16_t value) { output[0] = (uint8_t)value; @@ -89,3 +95,31 @@ bool trikke_ble_decode_ack( *packet_sequence = get_u32_le(ack + 4); return true; } + +bool trikke_ble_decode_begin_session( + const uint8_t *command, + size_t command_size, + uint64_t *session_token) +{ + if (command == NULL || session_token == NULL || + command_size != TRIKKE_BLE_BEGIN_SESSION_SIZE || + memcmp(command, "BGN1", 4) != 0) { + return false; + } + *session_token = get_u64_le(command + 4); + return true; +} + +bool trikke_ble_update_subscription( + bool notify_enabled, + bool session_connection_ready, + bool *subscribed) +{ + if (subscribed == NULL) { + return false; + } + const bool effective = notify_enabled && session_connection_ready; + const bool changed = effective != *subscribed; + *subscribed = effective; + return changed; +} diff --git a/main/trikke_ble_protocol.h b/main/trikke_ble_protocol.h index ae01823..ec2d0fa 100644 --- a/main/trikke_ble_protocol.h +++ b/main/trikke_ble_protocol.h @@ -10,6 +10,7 @@ extern "C" { #define TRIKKE_BLE_FRAGMENT_HEADER_SIZE 8 #define TRIKKE_BLE_ACK_SIZE 8 +#define TRIKKE_BLE_BEGIN_SESSION_SIZE 12 // BLE data notifications carry a little-endian packet sequence, byte offset, // total TRK1 frame size, then the frame bytes at that offset. The unchanged @@ -29,6 +30,20 @@ bool trikke_ble_decode_ack( size_t ack_size, uint32_t *packet_sequence); +// A session begin is ASCII "BGN1" followed by a receiver-generated uint64 +// token. Repeating the same token is idempotent across BLE reconnects. +bool trikke_ble_decode_begin_session( + const uint8_t *command, + size_t command_size, + uint64_t *session_token); + +// Notification delivery is active only after both the CCCD and session +// authorization are ready. Returns true when the effective state changes. +bool trikke_ble_update_subscription( + bool notify_enabled, + bool session_connection_ready, + bool *subscribed); + #ifdef __cplusplus } #endif diff --git a/main/trikke_ble_transport.c b/main/trikke_ble_transport.c index d1764bb..6a691a2 100644 --- a/main/trikke_ble_transport.c +++ b/main/trikke_ble_transport.c @@ -8,6 +8,8 @@ #include "host/ble_hs.h" #include "host/ble_uuid.h" #include "host/util/util.h" +#include "esp_attr.h" +#include "esp_system.h" #include "esp_timer.h" #include "nimble/nimble_port.h" #include "nimble/nimble_port_freertos.h" @@ -22,11 +24,24 @@ #define TRIKKE_BLE_MAX_ATT_PAYLOAD 253 #define TRIKKE_BLE_FRAGMENTS_PER_POLL 8 #define TRIKKE_BLE_ACK_TIMEOUT_US 1000000 +#define TRIKKE_BLE_SESSION_RTC_MAGIC UINT32_C(0x54524b53) +#define TRIKKE_BLE_SESSION_RTC_XOR UINT32_C(0xa93cf17e) +#define TRIKKE_BLE_SESSION_RESET_DELAY_MS 50 static trikke_ble_transport_t *s_ble; static uint8_t s_own_address_type; static uint16_t s_data_value_handle; static uint16_t s_ack_value_handle; +static uint16_t s_control_value_handle; + +typedef struct { + uint32_t token_low; + uint32_t token_high; + uint32_t checksum; + uint32_t magic; +} trikke_ble_rtc_session_t; + +RTC_NOINIT_ATTR static trikke_ble_rtc_session_t s_rtc_session; // 7d2ea000-f75b-4a9b-8fbe-3d4c2a1e9c10 and adjacent characteristic UUIDs. static const ble_uuid128_t TRIKKE_SERVICE_UUID = @@ -38,6 +53,9 @@ static const ble_uuid128_t TRIKKE_DATA_UUID = static const ble_uuid128_t TRIKKE_ACK_UUID = BLE_UUID128_INIT(0x12, 0x9c, 0x1e, 0x2a, 0x4c, 0x3d, 0xbe, 0x8f, 0x9b, 0x4a, 0x5b, 0xf7, 0x00, 0xa0, 0x2e, 0x7d); +static const ble_uuid128_t TRIKKE_CONTROL_UUID = + BLE_UUID128_INIT(0x13, 0x9c, 0x1e, 0x2a, 0x4c, 0x3d, 0xbe, 0x8f, + 0x9b, 0x4a, 0x5b, 0xf7, 0x00, 0xa0, 0x2e, 0x7d); static uint32_t get_u32_le(const uint8_t *input) { @@ -45,6 +63,63 @@ static uint32_t get_u32_le(const uint8_t *input) ((uint32_t)input[2] << 16) | ((uint32_t)input[3] << 24); } +// Caller must hold ble->lock. Keep the raw CCCD state independent from session +// authorization so either legal write order converges on the same effective +// subscription state. +static void update_subscribed_locked(trikke_ble_transport_t *ble) +{ + if (trikke_ble_update_subscription( + ble->notify_enabled, + ble->session_connection_ready, + &ble->subscribed)) { + ++ble->delivery_epoch; + } +} + +static uint32_t rtc_session_checksum(uint32_t low, uint32_t high) +{ + return TRIKKE_BLE_SESSION_RTC_MAGIC ^ low ^ high ^ + TRIKKE_BLE_SESSION_RTC_XOR; +} + +static void rtc_session_clear(void) +{ + s_rtc_session.magic = 0; + s_rtc_session.token_low = 0; + s_rtc_session.token_high = 0; + s_rtc_session.checksum = 0; +} + +static void rtc_session_store(uint64_t token) +{ + const uint32_t low = (uint32_t)token; + const uint32_t high = (uint32_t)(token >> 32); + s_rtc_session.magic = 0; + s_rtc_session.token_low = low; + s_rtc_session.token_high = high; + s_rtc_session.checksum = rtc_session_checksum(low, high); + s_rtc_session.magic = TRIKKE_BLE_SESSION_RTC_MAGIC; +} + +static bool rtc_session_load(uint64_t *token) +{ + if (token == NULL || s_rtc_session.magic != TRIKKE_BLE_SESSION_RTC_MAGIC || + s_rtc_session.checksum != rtc_session_checksum( + s_rtc_session.token_low, s_rtc_session.token_high)) { + return false; + } + *token = (uint64_t)s_rtc_session.token_low | + ((uint64_t)s_rtc_session.token_high << 32); + return true; +} + +static void session_restart_task(void *argument) +{ + (void)argument; + vTaskDelay(pdMS_TO_TICKS(TRIKKE_BLE_SESSION_RESET_DELAY_MS)); + esp_restart(); +} + static int data_access( uint16_t connection_handle, uint16_t attribute_handle, @@ -102,6 +177,69 @@ static int ack_access( return accepted ? 0 : BLE_ATT_ERR_UNLIKELY; } +static int session_access( + uint16_t connection_handle, + uint16_t attribute_handle, + struct ble_gatt_access_ctxt *context, + void *argument) +{ + (void)attribute_handle; + (void)argument; + trikke_ble_transport_t *ble = s_ble; + if (ble == NULL || context->op != BLE_GATT_ACCESS_OP_WRITE_CHR) { + return BLE_ATT_ERR_UNLIKELY; + } + + uint8_t command[TRIKKE_BLE_BEGIN_SESSION_SIZE] = {0}; + uint16_t command_size = 0; + uint64_t requested_token = 0; + if (OS_MBUF_PKTLEN(context->om) != sizeof(command) || + ble_hs_mbuf_to_flat( + context->om, command, sizeof(command), &command_size) != 0 || + !trikke_ble_decode_begin_session( + command, command_size, &requested_token)) { + return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN; + } + + bool notify_session_ready = false; + bool restart = false; + portENTER_CRITICAL(&ble->lock); + if (!ble->connected || ble->connection_handle != connection_handle || + ble->session_restart_pending) { + portEXIT_CRITICAL(&ble->lock); + return BLE_ATT_ERR_UNLIKELY; + } + if (ble->session_token_valid && ble->session_token == requested_token) { + ble->session_connection_ready = true; + update_subscribed_locked(ble); + if (!ble->session_started) { + ble->session_started = true; + notify_session_ready = true; + } + } else { + ble->session_connection_ready = false; + update_subscribed_locked(ble); + ble->session_restart_pending = true; + rtc_session_store(requested_token); + restart = true; + } + portEXIT_CRITICAL(&ble->lock); + + if (notify_session_ready && ble->session_ready != NULL) { + ble->session_ready(ble->session_ready_context); + } + if (restart && xTaskCreate( + session_restart_task, "trikke_session_reset", 2048, NULL, + configMAX_PRIORITIES - 1, NULL) != pdPASS) { + rtc_session_clear(); + portENTER_CRITICAL(&ble->lock); + ble->session_restart_pending = false; + portEXIT_CRITICAL(&ble->lock); + return BLE_ATT_ERR_UNLIKELY; + } + return 0; +} + static const struct ble_gatt_svc_def TRIKKE_GATT_SERVICES[] = { { .type = BLE_GATT_SVC_TYPE_PRIMARY, @@ -119,6 +257,12 @@ static const struct ble_gatt_svc_def TRIKKE_GATT_SERVICES[] = { .flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_WRITE_NO_RSP, .val_handle = &s_ack_value_handle, }, + { + .uuid = &TRIKKE_CONTROL_UUID.u, + .access_cb = session_access, + .flags = BLE_GATT_CHR_F_WRITE, + .val_handle = &s_control_value_handle, + }, {0}, }, }, @@ -169,7 +313,9 @@ static void on_reset(int reason) ++ble->counters.disconnect_count; } ble->connected = false; + ble->notify_enabled = false; ble->subscribed = false; + ble->session_connection_ready = false; ble->connection_handle = BLE_HS_CONN_HANDLE_NONE; ++ble->delivery_epoch; portEXIT_CRITICAL(&ble->lock); @@ -197,7 +343,9 @@ static int gap_event(struct ble_gap_event *event, void *argument) if (event->connect.status == 0) { portENTER_CRITICAL(&ble->lock); ble->connected = true; + ble->notify_enabled = false; ble->subscribed = false; + ble->session_connection_ready = false; ble->connection_handle = event->connect.conn_handle; ++ble->delivery_epoch; portEXIT_CRITICAL(&ble->lock); @@ -212,7 +360,9 @@ static int gap_event(struct ble_gap_event *event, void *argument) ++ble->counters.disconnect_count; } ble->connected = false; + ble->notify_enabled = false; ble->subscribed = false; + ble->session_connection_ready = false; ble->connection_handle = BLE_HS_CONN_HANDLE_NONE; ++ble->delivery_epoch; portEXIT_CRITICAL(&ble->lock); @@ -222,11 +372,8 @@ static int gap_event(struct ble_gap_event *event, void *argument) case BLE_GAP_EVENT_SUBSCRIBE: if (event->subscribe.attr_handle == s_data_value_handle) { portENTER_CRITICAL(&ble->lock); - const bool subscribed = event->subscribe.cur_notify != 0; - if (subscribed != ble->subscribed) { - ble->subscribed = subscribed; - ++ble->delivery_epoch; - } + ble->notify_enabled = event->subscribe.cur_notify != 0; + update_subscribed_locked(ble); portEXIT_CRITICAL(&ble->lock); } return 0; @@ -431,7 +578,9 @@ static trikke_transport_status_t ble_poll_packet(void *context) esp_err_t trikke_ble_transport_init( trikke_ble_transport_t *ble, - trikke_transport_t *transport) + trikke_transport_t *transport, + trikke_ble_session_ready_fn session_ready, + void *session_ready_context) { if (ble == NULL || transport == NULL) { return ESP_ERR_INVALID_ARG; @@ -443,6 +592,14 @@ esp_err_t trikke_ble_transport_init( memset(ble, 0, sizeof(*ble)); ble->lock = (portMUX_TYPE)portMUX_INITIALIZER_UNLOCKED; ble->connection_handle = BLE_HS_CONN_HANDLE_NONE; + ble->session_ready = session_ready; + ble->session_ready_context = session_ready_context; + if (esp_reset_reason() == ESP_RST_SW && + rtc_session_load(&ble->session_token)) { + ble->session_token_valid = true; + } else { + rtc_session_clear(); + } s_ble = ble; esp_err_t error = nvs_flash_init(); diff --git a/main/trikke_ble_transport.h b/main/trikke_ble_transport.h index 7b49ce0..0d52d4e 100644 --- a/main/trikke_ble_transport.h +++ b/main/trikke_ble_transport.h @@ -19,15 +19,23 @@ typedef struct { uint32_t invalid_ack_count; } trikke_ble_transport_counters_t; +typedef void (*trikke_ble_session_ready_fn)(void *context); + typedef struct { portMUX_TYPE lock; bool initialized; bool connected; + bool notify_enabled; bool subscribed; bool frame_active; bool frame_fully_sent_once; bool ack_received; + bool session_token_valid; + bool session_connection_ready; + bool session_started; + bool session_restart_pending; uint16_t connection_handle; + uint64_t session_token; uint32_t delivery_epoch; uint32_t frame_epoch; uint32_t frame_sequence; @@ -35,12 +43,16 @@ typedef struct { size_t frame_size; size_t next_offset; int64_t ack_deadline_us; + trikke_ble_session_ready_fn session_ready; + void *session_ready_context; trikke_ble_transport_counters_t counters; } trikke_ble_transport_t; esp_err_t trikke_ble_transport_init( trikke_ble_transport_t *ble, - trikke_transport_t *transport); + trikke_transport_t *transport, + trikke_ble_session_ready_fn session_ready, + void *session_ready_context); void trikke_ble_transport_get_counters( trikke_ble_transport_t *ble, diff --git a/main/trikke_sensor_main.c b/main/trikke_sensor_main.c index a6ae728..678d31a 100644 --- a/main/trikke_sensor_main.c +++ b/main/trikke_sensor_main.c @@ -28,7 +28,7 @@ #define TRIKKE_I2C_FREQ_HZ 400000 #define TRIKKE_SAMPLE_RATE_HZ 100 #define TRIKKE_SAMPLE_TICKS pdMS_TO_TICKS(1000 / TRIKKE_SAMPLE_RATE_HZ) -#define TRIKKE_SAMPLE_QUEUE_DEPTH 1024 +#define TRIKKE_SAMPLE_QUEUE_DEPTH 3072 #define TRIKKE_METADATA_INTERVAL_PACKETS 64 #define TRIKKE_STATUS_INTERVAL_PACKETS 64 #define TRIKKE_TRANSPORT_RETRY_DELAY_MS 10 @@ -59,9 +59,14 @@ typedef struct { adxl345_t accelerometer; l3g4200d_t gyroscope; QueueHandle_t sample_queue; + StaticQueue_t sample_queue_control; + uint8_t sample_queue_storage[ + TRIKKE_SAMPLE_QUEUE_DEPTH * sizeof(trikke_wire_sample_t)]; atomic_uint_least32_t sensor_read_failure_count; atomic_uint_least32_t queue_overflow_count; atomic_uint_least32_t loop_overrun_count; + TaskHandle_t output_task_handle; + TaskHandle_t acquisition_task_handle; trikke_transport_t transport; #if CONFIG_TRIKKE_TRANSPORT_BLE trikke_ble_transport_t ble_transport; @@ -147,6 +152,18 @@ static trikke_wire_status_t status_snapshot( return status; } +#if CONFIG_TRIKKE_TRANSPORT_BLE +static void session_ready(void *argument) +{ + trikke_context_t *context = argument; + if (context == NULL) { + return; + } + xTaskNotifyGive(context->output_task_handle); + xTaskNotifyGive(context->acquisition_task_handle); +} +#endif + static void acquisition_task(void *argument) { trikke_context_t *context = argument; @@ -407,8 +424,11 @@ void app_main(void) usb_serial_jtag_vfs_set_tx_line_endings(ESP_LINE_ENDINGS_LF); #endif - s_context.sample_queue = - xQueueCreate(TRIKKE_SAMPLE_QUEUE_DEPTH, sizeof(trikke_wire_sample_t)); + s_context.sample_queue = xQueueCreateStatic( + TRIKKE_SAMPLE_QUEUE_DEPTH, + sizeof(trikke_wire_sample_t), + s_context.sample_queue_storage, + &s_context.sample_queue_control); if (s_context.sample_queue == NULL) { ESP_LOGE(TAG, "sample queue allocation failed"); l3g4200d_deinit(&s_context.gyroscope); @@ -417,17 +437,15 @@ void app_main(void) return; } - TaskHandle_t output_task_handle = NULL; - TaskHandle_t acquisition_task_handle = NULL; if (xTaskCreate(output_task, "trikke_output", 4096, &s_context, 5, - &output_task_handle) != pdPASS || + &s_context.output_task_handle) != pdPASS || xTaskCreate(acquisition_task, "trikke_acquire", 4096, &s_context, 10, - &acquisition_task_handle) != pdPASS) { - if (output_task_handle != NULL) { - vTaskDelete(output_task_handle); + &s_context.acquisition_task_handle) != pdPASS) { + if (s_context.output_task_handle != NULL) { + vTaskDelete(s_context.output_task_handle); } - if (acquisition_task_handle != NULL) { - vTaskDelete(acquisition_task_handle); + if (s_context.acquisition_task_handle != NULL) { + vTaskDelete(s_context.acquisition_task_handle); } vQueueDelete(s_context.sample_queue); ESP_LOGE(TAG, "telemetry task creation failed"); @@ -439,14 +457,15 @@ void app_main(void) #if CONFIG_TRIKKE_TRANSPORT_BLE err = trikke_ble_transport_init( - &s_context.ble_transport, &s_context.transport); + &s_context.ble_transport, &s_context.transport, + session_ready, &s_context); #else err = trikke_usb_transport_init( &s_context.usb_transport, &s_context.transport); #endif if (err != ESP_OK) { - vTaskDelete(output_task_handle); - vTaskDelete(acquisition_task_handle); + vTaskDelete(s_context.output_task_handle); + vTaskDelete(s_context.acquisition_task_handle); vQueueDelete(s_context.sample_queue); #if CONFIG_TRIKKE_TRANSPORT_BLE ESP_LOGE(TAG, "BLE transport initialization failed: %s", @@ -463,6 +482,8 @@ void app_main(void) // No text may share the byte stream once framed binary output begins. esp_log_level_set("*", ESP_LOG_NONE); - xTaskNotifyGive(output_task_handle); - xTaskNotifyGive(acquisition_task_handle); +#if !CONFIG_TRIKKE_TRANSPORT_BLE + xTaskNotifyGive(s_context.output_task_handle); + xTaskNotifyGive(s_context.acquisition_task_handle); +#endif } diff --git a/tests/ble_protocol_fixture.c b/tests/ble_protocol_fixture.c index 45e8e54..d546beb 100644 --- a/tests/ble_protocol_fixture.c +++ b/tests/ble_protocol_fixture.c @@ -66,5 +66,42 @@ int main(void) sizeof(packet), 0, 8) != 0) { return fail(4, "invalid input rejection"); } + + const uint8_t begin[TRIKKE_BLE_BEGIN_SESSION_SIZE] = { + 'B', 'G', 'N', '1', 0x08, 0x07, 0x06, 0x05, + 0x04, 0x03, 0x02, 0x01, + }; + uint64_t session_token = 0; + if (!trikke_ble_decode_begin_session( + begin, sizeof(begin), &session_token) || + session_token != UINT64_C(0x0102030405060708)) { + return fail(5, "begin-session decoding"); + } + uint8_t invalid_begin[TRIKKE_BLE_BEGIN_SESSION_SIZE] = {0}; + memcpy(invalid_begin, begin, sizeof(begin)); + invalid_begin[3] = '2'; + if (trikke_ble_decode_begin_session( + invalid_begin, sizeof(invalid_begin), &session_token) || + trikke_ble_decode_begin_session( + begin, sizeof(begin) - 1, &session_token)) { + return fail(6, "invalid begin-session rejection"); + } + + bool subscribed = false; + if (trikke_ble_update_subscription(true, false, &subscribed) || + subscribed || + !trikke_ble_update_subscription(true, true, &subscribed) || + !subscribed) { + return fail(7, "CCCD-before-control subscription ordering"); + } + subscribed = false; + if (trikke_ble_update_subscription(false, true, &subscribed) || + subscribed || + !trikke_ble_update_subscription(true, true, &subscribed) || + !subscribed || + !trikke_ble_update_subscription(false, true, &subscribed) || + subscribed) { + return fail(8, "control-before-CCCD subscription ordering"); + } return 0; } diff --git a/tests/fixtures/README.md b/tests/fixtures/README.md index 8ec6bb3..39d4cd9 100644 --- a/tests/fixtures/README.md +++ b/tests/fixtures/README.md @@ -78,6 +78,35 @@ removed before production firmware was built and flashed. beyond the 10.24-second queue window, so sequences 1,024 through 4,021 were intentionally lost; the single 2,998-sample gap, matching queue-overflow total, demonstrates bounded buffer exhaustion rather than a suspended output task. +- `ride_20260820_090607.trk` — SHA-256 + `c938934c0905748d2f8d8be61cff1ff446d8415b34850628654967398fd7d91f`. + This is the Android recorder acceptance capture after increasing the firmware + queue to 3,072 samples (30.72 seconds). Bluetooth was deliberately disabled + from the phone for five seconds and then restored. The completed capture + contains 2,578 consecutive packets and 19,984 consecutive samples, both + starting at sequence zero, with zero CRC/header errors, packet/sample gaps, + sensor failures, queue overflows, transport send failures, invalid ACKs, + loop overruns, or trailing bytes. Firmware status records one disconnect and + one replay. The Android recorder durably deduplicated that exact replay, as + recorded in `ride_20260820_090607.session.json` (SHA-256 + `b16a8f0c213a14fd2760b6efba1c6288f3631e57a331c553893e281dce047888`), + and closed the session with `complete=true` and no error. + + All 19,983 sample intervals are contiguous. Of those, 8,745 differ from + exactly 10 ms. Across all intervals, absolute deviation is 0 us median, 40 us + p95, 240 us p99, and 1,630 us maximum; among only the off-grid intervals it is + 10 us median, 60 us p95, and 750 us p99. Cumulative error is -726 us over + 199.83 seconds. The capture also has six explicitly flagged ADXL345 overruns; + timestamps are taken before both I2C reads and therefore understate delays + caused by preemption between the timestamp and physical sensor access. + +The post-rename phone smoke test for application ID +`com.jsjdesigns.trikkerecorder` was verified live but not retained as a fixture. +It closed cleanly with 366 consecutive frames and 2,832 consecutive samples, +zero CRC/header errors, packet/sample gaps, drops, queue overflows, loop +overruns, or trailing bytes. The package-only rename did not change the Android +protocol or storage implementation, and the retained outage fixture above +remains the authoritative end-to-end acceptance artifact. `tests/test_trikke_protocol.py` verifies the hashes, parses the captures in fragmented chunks, and asserts these signatures so the hardware evidence remains diff --git a/tests/fixtures/ride_20260820_090607.session.json b/tests/fixtures/ride_20260820_090607.session.json new file mode 100644 index 0000000..f1db9b1 --- /dev/null +++ b/tests/fixtures/ride_20260820_090607.session.json @@ -0,0 +1,25 @@ +{ + "schema": 1, + "captureFile": "ride_20260820_090607.trk", + "sessionTokenHex": "77f213814e3c41da", + "complete": true, + "startWallClockMs": 1787231167523, + "startElapsedRealtimeNs": 2415494841543927, + "endWallClockMs": 1787231378168, + "endElapsedRealtimeNs": 2415705485735774, + "firstFrame": {"packetSequence":0,"deviceBaseTimestampUs":7652604,"phoneElapsedRealtimeNs":2415505638698090,"phoneWallClockMs":1787231178321}, + "lastFrame": {"packetSequence":2577,"deviceBaseTimestampUs":207411553,"phoneElapsedRealtimeNs":2415705468358690,"phoneWallClockMs":1787231378150}, + "frames": 2578, + "samples": 19984, + "duplicateReplays": 1, + "packetGaps": 0, + "packetResets": 0, + "sampleGaps": 0, + "sampleResets": 0, + "droppedSamples": 0, + "loopOverruns": 0, + "queueOverflows": 0, + "transportDisconnects": 1, + "transportReplays": 1, + "error": null +} diff --git a/tests/fixtures/ride_20260820_090607.trk b/tests/fixtures/ride_20260820_090607.trk new file mode 100644 index 0000000000000000000000000000000000000000..8f65b1195ad4bbce5b99c6e37a27450fd4479255 GIT binary patch literal 495688 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 z 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≪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 Aga7~l literal 0 HcmV?d00001 diff --git a/tests/test_trikke_protocol.py b/tests/test_trikke_protocol.py index d27cd6e..ef12ea6 100644 --- a/tests/test_trikke_protocol.py +++ b/tests/test_trikke_protocol.py @@ -1,4 +1,5 @@ import hashlib +import json import shutil import subprocess import sys @@ -18,7 +19,7 @@ from trikke_protocol import ( # noqa: E402 StreamParser, sample_to_csv_row, ) -from trikke_ble import BleFrameReassembler, encode_ack # noqa: E402 +from trikke_ble import BleFrameReassembler, encode_ack, encode_begin_session # noqa: E402 class ProtocolContractTest(unittest.TestCase): @@ -197,6 +198,10 @@ class ProtocolContractTest(unittest.TestCase): self.assertIsNone(reassembler.feed(fragment(0, 40))) self.assertEqual(frame, reassembler.feed(fragment(40, len(frame) - 40))) self.assertEqual(b"ACK1" + sequence.to_bytes(4, "little"), encode_ack(sequence)) + self.assertEqual( + b"BGN1\x08\x07\x06\x05\x04\x03\x02\x01", + encode_begin_session(0x0102030405060708), + ) self.assertEqual(0, reassembler.rejected_fragment_count) self.assertIsNone(reassembler.feed(fragment(20, 20))) @@ -327,6 +332,25 @@ class ProtocolContractTest(unittest.TestCase): "transport_invalid_ack_count": 0, }, }, + "ride_20260820_090607.trk": { + "sha256": "c938934c0905748d2f8d8be61cff1ff446d8415b34850628654967398fd7d91f", + "sample_count": 19984, + "first_sequence": 0, + "last_sequence": 19983, + "max_dropped": 0, + "timing_anomalies": 8745, + "accel_overruns": 6, + "gaps": [], + "final_status": { + "sensor_read_failure_count": 0, + "queue_overflow_count": 0, + "transport_begin_retry_count": 2, + "transport_disconnect_count": 1, + "transport_send_failure_count": 0, + "transport_replay_count": 1, + "transport_invalid_ack_count": 0, + }, + }, } for name, contract in expected.items(): @@ -379,6 +403,11 @@ class ProtocolContractTest(unittest.TestCase): contract["timing_anomalies"], integrity.timing_anomaly_count, ) + if "accel_overruns" in contract: + self.assertEqual( + contract["accel_overruns"], + integrity.accel_overrun_count, + ) self.assertEqual( contract["max_dropped"], integrity.final_dropped_sample_count, @@ -403,6 +432,31 @@ class ProtocolContractTest(unittest.TestCase): ] self.assertEqual(contract["gaps"], gaps) + def test_android_reconnect_session_sidecar(self) -> None: + data = ( + ROOT + / "tests" + / "fixtures" + / "ride_20260820_090607.session.json" + ).read_bytes() + self.assertEqual( + "b16a8f0c213a14fd2760b6efba1c6288f3631e57a331c553893e281dce047888", + hashlib.sha256(data).hexdigest(), + ) + summary = json.loads(data) + self.assertTrue(summary["complete"]) + self.assertIsNone(summary["error"]) + self.assertEqual("ride_20260820_090607.trk", summary["captureFile"]) + self.assertEqual(2578, summary["frames"]) + self.assertEqual(19984, summary["samples"]) + self.assertEqual(1, summary["duplicateReplays"]) + self.assertEqual(0, summary["packetGaps"]) + self.assertEqual(0, summary["sampleGaps"]) + self.assertEqual(0, summary["droppedSamples"]) + self.assertEqual(0, summary["queueOverflows"]) + self.assertEqual(1, summary["transportDisconnects"]) + self.assertEqual(1, summary["transportReplays"]) + def test_exact_usb_raw_wire_evidence(self) -> None: expected = { "direct_usb_3c95f3d": { diff --git a/tools/capture_ble.py b/tools/capture_ble.py index 9fe122c..c13a402 100644 --- a/tools/capture_ble.py +++ b/tools/capture_ble.py @@ -7,12 +7,13 @@ import argparse import asyncio import csv import os +import secrets import signal from contextlib import ExitStack from datetime import datetime from pathlib import Path -from trikke_ble import BleFrameReassembler, encode_ack +from trikke_ble import BleFrameReassembler, encode_ack, encode_begin_session from trikke_protocol import ( CSV_COLUMNS, PACKET_TYPE_METADATA, @@ -27,6 +28,7 @@ DEVICE_NAME = "TrikkeSensor" SERVICE_UUID = "7d2ea000-f75b-4a9b-8fbe-3d4c2a1e9c10" DATA_UUID = "7d2ea000-f75b-4a9b-8fbe-3d4c2a1e9c11" ACK_UUID = "7d2ea000-f75b-4a9b-8fbe-3d4c2a1e9c12" +CONTROL_UUID = "7d2ea000-f75b-4a9b-8fbe-3d4c2a1e9c13" def parse_args() -> argparse.Namespace: @@ -86,6 +88,7 @@ async def capture(args: argparse.Namespace) -> int: last_persisted_raw: bytes | None = None sample_count = 0 frame_count = 0 + session_token = secrets.randbits(64) with ExitStack() as stack: raw_capture = stack.enter_context(output.open("wb")) @@ -110,6 +113,11 @@ async def capture(args: argparse.Namespace) -> int: reassembler.reset() while not fragments.empty(): fragments.get_nowait() + await client.write_gatt_char( + CONTROL_UUID, + encode_begin_session(session_token), + response=True, + ) await client.start_notify(DATA_UUID, on_fragment) print("BLE connected and subscribed") while not stop.is_set() and client.is_connected: diff --git a/tools/trikke_ble.py b/tools/trikke_ble.py index de7c114..b583472 100644 --- a/tools/trikke_ble.py +++ b/tools/trikke_ble.py @@ -6,6 +6,7 @@ import struct BLE_FRAGMENT_HEADER = struct.Struct(" bytes: return BLE_ACK.pack(b"ACK1", packet_sequence & 0xFFFFFFFF) + + +def encode_begin_session(session_token: int) -> bytes: + return BLE_BEGIN_SESSION.pack(b"BGN1", session_token & 0xFFFFFFFFFFFFFFFF)