feat(k1): complete primary acquisition lifecycle

This commit is contained in:
DCCONSTRUCTIONS
2026-07-17 23:03:59 +03:00
parent 9d51080d2e
commit aa3680948f
66 changed files with 6093 additions and 544 deletions
+80
View File
@@ -2,10 +2,18 @@ from __future__ import annotations
import math
import struct
from types import SimpleNamespace
import lz4.block
import pytest
from k1link.device_plugins.xgrids_k1.protocol.modeling import (
MODELING_REPORT_TOPIC,
ModelingReportDecodeError,
decode_modeling_report,
is_modeling_report_topic,
observe_modeling_report,
)
from k1link.device_plugins.xgrids_k1.protocol.protobuf_wire import (
ProtobufWireError,
decode_zigzag64,
@@ -21,6 +29,7 @@ from k1link.device_plugins.xgrids_k1.protocol.streams import (
decode_lio_pose,
decode_pre_path_array,
)
from k1link.viewer.metrics import BridgeMetrics
def _varint(value: int) -> bytes:
@@ -136,6 +145,77 @@ def test_decode_lio_pose_rejects_nonfinite_float() -> None:
decode_lio_pose(payload)
def test_decode_modeling_report_device_telemetry() -> None:
scan_status = _fixed32(1, 41.521404) + _fixed32(2, 1.375) + _uint(3, 204)
payload = _bytes(1, _header()) + _uint(2, 73) + _bytes(3, scan_status)
telemetry = decode_modeling_report(payload)
assert telemetry.move_distance_meters == pytest.approx(41.521404)
assert telemetry.move_speed_meters_per_second == pytest.approx(1.375)
assert telemetry.scan_time_ticks == 204
assert telemetry.elapsed_seconds == pytest.approx(102.0)
assert telemetry.pgo_progress == 73
assert is_modeling_report_topic(MODELING_REPORT_TOPIC)
assert not is_modeling_report_topic(f"{MODELING_REPORT_TOPIC}/extra")
metrics = BridgeMetrics()
assert observe_modeling_report(
SimpleNamespace(topic=MODELING_REPORT_TOPIC, payload=payload),
metrics,
)
snapshot = metrics.snapshot()
assert snapshot["device_elapsed_seconds"] == pytest.approx(102.0)
assert snapshot["device_route_distance_meters"] == pytest.approx(41.521)
assert snapshot["device_speed_meters_per_second"] == pytest.approx(1.375)
assert snapshot["modeling_reports"] == 1
assert snapshot["modeling_decode_errors"] == 0
def test_decode_modeling_report_fails_closed_on_invalid_status() -> None:
with pytest.raises(ModelingReportDecodeError, match="no scan_status"):
decode_modeling_report(_uint(2, 1))
with pytest.raises(ModelingReportDecodeError, match="finite and nonnegative"):
decode_modeling_report(_bytes(3, _fixed32(1, math.nan)))
with pytest.raises(ModelingReportDecodeError, match="configured limit"):
decode_modeling_report(b"x" * 5, max_payload_bytes=4)
with pytest.raises(ModelingReportDecodeError, match="pgo_progress is duplicated"):
decode_modeling_report(_uint(2, 1) + _uint(2, 2) + _bytes(3, _uint(3, 2)))
with pytest.raises(ModelingReportDecodeError, match="scan_status is duplicated"):
decode_modeling_report(_bytes(3, b"") + _bytes(3, b""))
with pytest.raises(ModelingReportDecodeError, match="move_speed is duplicated"):
decode_modeling_report(_bytes(3, _fixed32(2, 1.0) + _fixed32(2, 2.0)))
with pytest.raises(ModelingReportDecodeError, match="signed range"):
decode_modeling_report(_uint(2, 0x8000_0000) + _bytes(3, _uint(3, 2)))
def test_modeling_metrics_follow_device_scan_generation_reset() -> None:
metrics = BridgeMetrics()
before_reset = _bytes(
3,
_fixed32(1, 2.071593) + _fixed32(2, 0.2) + _uint(3, 734),
)
after_reset = _bytes(
3,
_fixed32(1, 0.0) + _fixed32(2, 0.0) + _uint(3, 2),
)
observe_modeling_report(
SimpleNamespace(topic=MODELING_REPORT_TOPIC, payload=before_reset),
metrics,
)
observe_modeling_report(
SimpleNamespace(topic=MODELING_REPORT_TOPIC, payload=after_reset),
metrics,
)
snapshot = metrics.snapshot()
assert snapshot["device_elapsed_seconds"] == 1.0
assert snapshot["device_route_distance_meters"] == 0.0
assert snapshot["device_speed_meters_per_second"] == 0.0
assert snapshot["modeling_reports"] == 2
def test_decode_legacy_pointcloud() -> None:
envelope = struct.pack("<III", 16, 123, 456)
body = struct.pack("<fffBBBB", 1.0, -2.0, 3.0, 10, 20, 30, 40)