70 lines
3.1 KiB
Python
70 lines
3.1 KiB
Python
"""Collector packets preserve whole sweeps, source windows and pair identity."""
|
|
|
|
import struct
|
|
import unittest
|
|
|
|
import numpy as np
|
|
|
|
from python_app.hardware_full.rph_radar.protocol import RphRadarStreamParser
|
|
|
|
|
|
def packet(*, source_id=1, cycle_id=1, start=100, end=200, combo=(1, 2), dirty=0, points=None):
|
|
if points is None:
|
|
points = [(0xA, 1, 10, -1), (0xA8, 1, 100, 5)]
|
|
payload = b"".join(struct.pack("<HHhh", *point) for point in points)
|
|
return struct.pack("<4sIQQQQHHI", b"RPH1", len(payload), source_id, cycle_id,
|
|
start, end, *combo, dirty) + payload
|
|
|
|
|
|
class RphRadarStreamParserTest(unittest.TestCase):
|
|
def test_fragmented_packets_keep_source_window_and_identity(self):
|
|
parser = RphRadarStreamParser()
|
|
sweeps = []
|
|
for byte in b"preroll" + packet(source_id=73, cycle_id=9):
|
|
sweeps.extend(parser.feed(bytes([byte])))
|
|
self.assertEqual(len(sweeps), 1)
|
|
sweep = sweeps[0]
|
|
self.assertEqual((sweep.source_id, sweep.cycle_id, sweep.capture_start_ns, sweep.capture_end_ns),
|
|
(73, 9, 100, 200))
|
|
self.assertEqual(sweep.combo, (1, 2))
|
|
self.assertEqual(sweep.main.tolist(), [10-1j])
|
|
self.assertEqual(sweep.reference.tolist(), [100+5j])
|
|
self.assertEqual(sweep.main.dtype, np.complex64)
|
|
|
|
def test_whole_packet_loss_does_not_merge_pairs(self):
|
|
parser = RphRadarStreamParser()
|
|
first, last = parser.feed(packet(source_id=1) + packet(source_id=3, combo=(2, 3),
|
|
points=[(0xA, 2, 20, 0), (0xA8, 2, 200, 0)]))
|
|
self.assertEqual((first.combo, first.steps.tolist()), ((1, 2), [1]))
|
|
self.assertEqual((last.combo, last.steps.tolist()), ((2, 3), [2]))
|
|
self.assertEqual(last.source_id, 3)
|
|
|
|
def test_aligns_both_channels_and_keeps_only_shared_steps(self):
|
|
parser = RphRadarStreamParser()
|
|
(sweep,) = parser.feed(packet(points=[(0xA, 3, 3, 0), (0xA8, 3, 30, 0),
|
|
(0xA, 1, 1, 0), (0xA8, 1, 10, 0), (0xA, 2, 2, 0)]))
|
|
self.assertEqual(sweep.steps.tolist(), [1, 3])
|
|
self.assertEqual(sweep.main.real.tolist(), [1, 3])
|
|
self.assertEqual(sweep.reference.real.tolist(), [10, 30])
|
|
|
|
def test_bad_window_size_flags_and_point_marker_fail_fast(self):
|
|
for encoded in (packet(start=0), packet(start=200, end=100), packet(dirty=2),
|
|
packet(source_id=0), packet(cycle_id=0),
|
|
packet(points=[(0x1A, 1, 1, 1)]),
|
|
b"RPH1" + struct.pack("<I", 0xFFFFFFFF) + bytes(40)):
|
|
with self.subTest(encoded=encoded), self.assertRaisesRegex(ValueError, "protocol"):
|
|
RphRadarStreamParser().feed(encoded)
|
|
|
|
def test_reset_discards_partial_packet(self):
|
|
parser = RphRadarStreamParser()
|
|
self.assertEqual(parser.feed(packet()[:53]), [])
|
|
parser.reset()
|
|
(sweep,) = parser.feed(packet(source_id=2, dirty=1, combo=(65535, 65535)))
|
|
self.assertEqual(sweep.source_id, 2)
|
|
self.assertIsNone(sweep.combo)
|
|
self.assertTrue(sweep.dirty)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
unittest.main()
|