retain telemetry across transport outages
This commit is contained in:
@@ -54,5 +54,51 @@ int main(void)
|
||||
if (size == 0 || fwrite(packet, 1, size, stdout) != size) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
trikke_wire_sample_t full_packet[TRIKKE_WIRE_MAX_RECORDS] = {0};
|
||||
for (size_t i = 0; i < TRIKKE_WIRE_MAX_RECORDS; ++i) {
|
||||
full_packet[i].sequence = 2000 + (uint32_t)i;
|
||||
full_packet[i].timestamp_us = 3000000 + (int64_t)i * 10000;
|
||||
full_packet[i].accel_x = (int16_t)i;
|
||||
full_packet[i].gyro_z = -(int16_t)i;
|
||||
full_packet[i].accel_status = 0x80;
|
||||
full_packet[i].gyro_status = 0x08;
|
||||
}
|
||||
size = trikke_encode_sample_packet(
|
||||
packet, sizeof(packet), 43, 2, 3, full_packet,
|
||||
TRIKKE_WIRE_MAX_RECORDS);
|
||||
if (size != TRIKKE_WIRE_MAX_PACKET_SIZE ||
|
||||
fwrite(packet, 1, size, stdout) != size) {
|
||||
return 2;
|
||||
}
|
||||
|
||||
const trikke_wire_sample_t saturated[] = {
|
||||
{.sequence = 3000, .timestamp_us = 4000000},
|
||||
{.sequence = 3001, .timestamp_us = 4700000},
|
||||
};
|
||||
size = trikke_encode_sample_packet(packet, sizeof(packet), 44, 2, 3,
|
||||
saturated, 2);
|
||||
if (size == 0 || fwrite(packet, 1, size, stdout) != size) {
|
||||
return 3;
|
||||
}
|
||||
|
||||
if (!trikke_wire_timestamp_delta_fits(0, 655350) ||
|
||||
trikke_wire_timestamp_delta_fits(0, 655351) ||
|
||||
trikke_wire_timestamp_delta_fits(1, 0)) {
|
||||
return 4;
|
||||
}
|
||||
if (trikke_encode_metadata_packet(
|
||||
packet, TRIKKE_WIRE_HEADER_SIZE + TRIKKE_WIRE_METADATA_SIZE - 1,
|
||||
0, 0, 0, 0, &metadata) != 0 ||
|
||||
trikke_encode_sample_packet(packet, sizeof(packet), 0, 0, 0,
|
||||
samples, 0) != 0 ||
|
||||
trikke_encode_sample_packet(packet, sizeof(packet), 0, 0, 0,
|
||||
full_packet,
|
||||
TRIKKE_WIRE_MAX_RECORDS + 1) != 0 ||
|
||||
trikke_encode_sample_packet(packet, TRIKKE_WIRE_MAX_PACKET_SIZE - 1,
|
||||
0, 0, 0, full_packet,
|
||||
TRIKKE_WIRE_MAX_RECORDS) != 0) {
|
||||
return 5;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ ROOT = Path(__file__).resolve().parents[1]
|
||||
sys.path.insert(0, str(ROOT / "tools"))
|
||||
|
||||
from trikke_protocol import ( # noqa: E402
|
||||
PACKET_FLAG_TIMESTAMP_DELTA_SATURATED,
|
||||
PACKET_TYPE_METADATA,
|
||||
PACKET_TYPE_SAMPLES,
|
||||
StreamParser,
|
||||
@@ -55,8 +56,8 @@ class ProtocolContractTest(unittest.TestCase):
|
||||
for offset in range(0, len(stream), 7):
|
||||
frames.extend(parser.feed(stream[offset : offset + 7]))
|
||||
|
||||
self.assertEqual(2, len(frames))
|
||||
metadata_frame, sample_frame = frames
|
||||
self.assertEqual(4, len(frames))
|
||||
metadata_frame, sample_frame, full_frame, saturated_frame = frames
|
||||
self.assertEqual(PACKET_TYPE_METADATA, metadata_frame.packet_type)
|
||||
self.assertEqual(41, metadata_frame.packet_sequence)
|
||||
self.assertEqual(2, metadata_frame.dropped_sample_count)
|
||||
@@ -75,6 +76,20 @@ class ProtocolContractTest(unittest.TestCase):
|
||||
self.assertEqual(0xFF, sample_frame.samples[1].gyro_status)
|
||||
self.assertEqual(0, parser.crc_errors)
|
||||
self.assertEqual(len(b"startup text\r\n"), parser.skipped_bytes)
|
||||
self.assertEqual(0, parser.buffered_bytes)
|
||||
|
||||
self.assertEqual(8, len(full_frame.samples))
|
||||
self.assertEqual(43, full_frame.packet_sequence)
|
||||
self.assertEqual(2_007, full_frame.samples[-1].sequence)
|
||||
self.assertEqual(3_070_000, full_frame.samples[-1].timestamp_us)
|
||||
self.assertEqual(0, full_frame.flags)
|
||||
|
||||
self.assertEqual(44, saturated_frame.packet_sequence)
|
||||
self.assertEqual(
|
||||
PACKET_FLAG_TIMESTAMP_DELTA_SATURATED,
|
||||
saturated_frame.flags,
|
||||
)
|
||||
self.assertEqual(4_655_350, saturated_frame.samples[-1].timestamp_us)
|
||||
|
||||
row = sample_to_csv_row(
|
||||
sample_frame.samples[0], metadata_frame.metadata, 3
|
||||
@@ -91,20 +106,31 @@ class ProtocolContractTest(unittest.TestCase):
|
||||
frames = parser.feed(bytes(damaged) + self.encoded[first_size:])
|
||||
self.assertEqual(1, parser.startup_crc_errors)
|
||||
self.assertEqual(0, parser.crc_errors)
|
||||
self.assertEqual(1, len(frames))
|
||||
self.assertEqual(3, len(frames))
|
||||
self.assertEqual(PACKET_TYPE_SAMPLES, frames[0].packet_type)
|
||||
|
||||
def test_crc_failure_after_sync_is_stream_error(self) -> None:
|
||||
first_size = 36 + 48
|
||||
damaged = bytearray(self.encoded[first_size:])
|
||||
second_size = 36 + 2 * 20
|
||||
damaged = bytearray(self.encoded[first_size : first_size + second_size])
|
||||
damaged[-1] ^= 0x80
|
||||
parser = StreamParser()
|
||||
frames = parser.feed(self.encoded[:first_size] + bytes(damaged))
|
||||
frames = parser.feed(
|
||||
self.encoded[:first_size]
|
||||
+ bytes(damaged)
|
||||
+ self.encoded[first_size + second_size :]
|
||||
)
|
||||
self.assertEqual(0, parser.startup_crc_errors)
|
||||
self.assertEqual(1, parser.crc_errors)
|
||||
self.assertEqual(1, len(frames))
|
||||
self.assertEqual(3, len(frames))
|
||||
self.assertEqual(PACKET_TYPE_METADATA, frames[0].packet_type)
|
||||
|
||||
def test_trailing_partial_frame_is_observable(self) -> None:
|
||||
parser = StreamParser()
|
||||
frames = parser.feed(self.encoded[:-5])
|
||||
self.assertEqual(3, len(frames))
|
||||
self.assertEqual(36 + 2 * 20 - 5, parser.buffered_bytes)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
|
||||
Reference in New Issue
Block a user