Rework radar system

This commit is contained in:
Ayzen
2026-10-06 12:32:26 +03:00
parent 552cdc688a
commit 5bb86b7165
299 changed files with 13537 additions and 27763 deletions
+38 -11
View File
@@ -41,6 +41,26 @@ def _valid_payload() -> dict:
class StrictNumericTypingTest(unittest.TestCase):
"""Every config integer reads strictly; null falls back to the default."""
def test_switch_driver_is_only_a_guard_for_old_h7992_profiles(self) -> None:
payload = _valid_payload()
for port in ("port1", "port2"):
switch = payload["switches"][port]
self.assertNotIn("driver", switch)
switch["driver"] = "h7992"
self.assertNotIn("driver", RunConfigModel.from_dict(payload).to_dict()["switches"][port])
for unsupported in ("hmc349a", "unknown", "", None, 1, {}, []):
switch["driver"] = unsupported
with self.subTest(port=port, driver=unsupported), self.assertRaisesRegex(ValueError, "driver"):
RunConfigModel.from_dict(payload)
switch.pop("driver")
switch["invert_logic"] = False
self.assertNotIn("invert_logic", RunConfigModel.from_dict(payload).to_dict()["switches"][port])
for unsupported in (True, None, 0, "false", {}, []):
switch["invert_logic"] = unsupported
with self.subTest(port=port, invert_logic=unsupported), self.assertRaisesRegex(ValueError, "invert_logic"):
RunConfigModel.from_dict(payload)
switch.pop("invert_logic")
def _reject_int(self, section: list[str], key: str, value: object) -> None:
payload = _valid_payload()
node = payload
@@ -109,7 +129,6 @@ class AcquisitionValidationTest(unittest.TestCase):
config.radar.sweep.points = 32
for port, switch in enumerate((config.output_switch, config.input_switch), 1):
switch.radar_port = port
switch.driver = "h7992"
switch.gpio_chip = "/dev/gpiochip0"
switch.pin_a, switch.pin_b = 17, 27
for name in ("raw", "preprocessed", "raw_tap", "preprocessed_tap"):
@@ -123,7 +142,8 @@ class AcquisitionValidationTest(unittest.TestCase):
ring = getattr(config.rings, name)
ring.name = "/test"
original = ring.slot_size_bytes
ring.slot_size_bytes = 4096
minimum_frame = 44 + len(config.combos) * (28 + 12 * config.radar.sweep.points)
ring.slot_size_bytes = (minimum_frame - 1) // 8 * 8
with self.subTest(ring=name), self.assertRaisesRegex(ValueError, f"rings.{name}"):
validate_acquisition_config(config)
ring.slot_size_bytes = original
@@ -154,7 +174,7 @@ class AcquisitionValidationTest(unittest.TestCase):
def test_bad_switch_settings_are_reported_before_hardware_open(self) -> None:
for field, value in (
("driver_mode", "typo"), ("driver", "typo"), ("default_position", 1),
("driver_mode", "typo"), ("default_position", 1),
("radar_port", 0), ("pin_a", -1), ("pin_b", 17), ("gpio_chip", ""),
):
config = self.config()
@@ -207,7 +227,9 @@ class ComboValidationTest(unittest.TestCase):
def test_direct_model_positions_cannot_be_silently_truncated(self) -> None:
for value in (0.5, True, '0'):
with self.subTest(value=value), self.assertRaisesRegex(ValueError, 'integer'):
validate_combos([ComboModel(value, 0)], input_positions=2, output_positions=2)
combo = ComboModel(0, 0)
setattr(combo, 'input', value)
validate_combos([combo], input_positions=2, output_positions=2)
def test_within_bounds_passes(self) -> None:
validate_combos(
[ComboModel(input=0, output=0), ComboModel(input=3, output=1)],
@@ -266,9 +288,10 @@ class RingValidationTest(unittest.TestCase):
class GprValidationTest(unittest.TestCase):
@staticmethod
def _gpr(**overrides: object) -> GprModel:
base = {"relative_permittivity": 4.0, "tx_geometry": [], "rx_geometry": []}
base.update(overrides)
return GprModel(**base) # type: ignore[arg-type]
model = GprModel(relative_permittivity=4.0)
for key, value in overrides.items():
setattr(model, key, value)
return model
def _validate(self, gpr: GprModel) -> None:
validate_gpr_model(gpr, input_switch_positions=4, output_switch_positions=2)
@@ -298,10 +321,14 @@ class GprValidationTest(unittest.TestCase):
rx_geometry=[GprRxGeometryModel(input_pos=0, x_m=0.0, y_m=0.0, z_m=0.0)],
))
def test_direct_geometry_positions_cannot_be_silently_truncated(self) -> None:
for value in (0.5, True, '0'):
with self.subTest(value=value), self.assertRaisesRegex(ValueError, 'integer'):
self._validate(self._gpr(tx_geometry=[GprTxGeometryModel(output_pos=value)]))
def test_direct_geometry_values_cannot_be_silently_coerced(self) -> None:
for field, values, message in (("output_pos", (0.5, True, "0"), "integer"),
("x_m", (True, "0", None, float("nan"), float("inf"), 3.5e38, 10**400), "number")):
for value in values:
with self.subTest(field=field, value=value), self.assertRaisesRegex(ValueError, message):
entry = GprTxGeometryModel()
setattr(entry, field, value)
self._validate(self._gpr(tx_geometry=[entry]))
class ParseCombosFromTextTest(unittest.TestCase):