Add reliable Android BLE ride recorder
This commit is contained in:
@@ -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": {
|
||||
|
||||
Reference in New Issue
Block a user