"""Unit tests for H32 Medulla dlog → V1 export helpers.""" from __future__ import annotations import struct from pathlib import Path import numpy as np from tools.h32_dlog.difop import CHANNELS, HORIZONTAL_START, VERTICAL_START, parse_difop_angles from tools.h32_dlog.dobject import discover_records, iter_payloads, resolve_dlog_root from tools.h32_dlog.load_session import load_h32_dlog_lidar from tools.h32_dlog.payload_v1 import ( MsopPacketItem, build_difop_payload, build_msop_batch_payload, parse_difop_payload, parse_msop_batch_payload, ) from tools.rscap_v2.h32_msop import PACKET_LENGTH, iter_h32_frames_from_packets def _make_msop_packet(*, seconds: int = 100, microseconds: int = 5000, az_deg: float = 10.0) -> bytes: packet = bytearray(PACKET_LENGTH) packet[17] = 1 packet[20:26] = int(seconds).to_bytes(6, "big") packet[26:30] = int(microseconds).to_bytes(4, "big") az_raw = int(round(az_deg * 100)) for block in range(12): offset = 42 + block * 100 packet[offset] = 255 packet[offset + 1] = 238 packet[offset + 2] = (az_raw >> 8) & 0xFF packet[offset + 3] = az_raw & 0xFF idx = offset + 4 for _ch in range(CHANNELS): packet[idx] = (1600 >> 8) & 0xFF packet[idx + 1] = 1600 & 0xFF packet[idx + 2] = 10 idx += 3 return bytes(packet) def _write_signed_angle(buf: bytearray, index: int, degrees: float) -> None: sign = 1 if degrees < 0 else 0 raw = int(round(abs(degrees) * 100)) buf[index] = sign buf[index + 1] = (raw >> 8) & 0xFF buf[index + 2] = raw & 0xFF def _make_difop_packet(*, vertical: list[float], horizontal: list[float] | None = None) -> bytes: packet = bytearray(1248) horiz = horizontal if horizontal is not None else [0.0] * CHANNELS for channel, angle in enumerate(vertical): _write_signed_angle(packet, VERTICAL_START + channel * 3, angle) for channel, angle in enumerate(horiz): _write_signed_angle(packet, HORIZONTAL_START + channel * 3, angle) return bytes(packet) def _write_dorec_record( path: Path, *, object_name: str, ticks: int, record_id: str, payload: bytes, offset: int = 0, ) -> int: """Append one DObject record; return file offset of the record start.""" path.parent.mkdir(parents=True, exist_ok=True) name_b = object_name.encode("ascii") id_b = record_id.encode("ascii") blob = ( bytes([len(name_b)]) + name_b + struct.pack(" 0