"""Publish LibreVNA single-device, matrix, or simulated collections to SHM.""" from __future__ import annotations import logging from contextlib import ExitStack import threading import time from python_app.hardware_full.matrix_radar_service import MatrixRadarService, create_matrix_radar_service from python_app.models.run_config_schema import RunConfigModel from python_app.scripts.producer_common import RawPublisher, close_devices, load_producer_config, retry_open logger = logging.getLogger(__name__) def _open_radar_with_retry( config: RunConfigModel, previous: MatrixRadarService | None, stop_requested: threading.Event, ) -> MatrixRadarService | None: """Recreate a failed LibreVNA service and wait interruptibly for its return.""" close_devices(previous) def attempt() -> MatrixRadarService: radar = create_matrix_radar_service(config) try: radar.open() radar.configure(config.radar.sweep) except Exception: close_devices(radar) raise return radar return retry_open(attempt, stop_requested, "LibreVNA radar") def main() -> int: """Run producer process until config or signal requests exit.""" config_path, config, stop_requested = load_producer_config("Publish LibreVNA raw sweeps to SHM rings") logger.info( "LibreVNA radar raw producer starting: config=%s, model=%s, continuous=%s", config_path, config.radar.model, config.runtime.continuous, ) radar: MatrixRadarService | None = None cleanup = ExitStack() try: publisher = RawPublisher(config.rings, cleanup) radar = _open_radar_with_retry(config, previous=None, stop_requested=stop_requested) if radar is None: return 0 # asked to stop before a device became available collection_id = 1 while not stop_requested.is_set(): collection_start = time.monotonic() try: collection = radar.acquire_collection(collection_id=collection_id) except Exception as exc: # noqa: BLE001 — reconnect forever, never give up logger.warning( "LibreVNA radar acquisition failed; reconnecting and waiting for the device: %s", exc, exc_info=True, ) radar = _open_radar_with_retry(config, previous=radar, stop_requested=stop_requested) if radar is None: break # stop requested while waiting to reconnect continue publisher.publish(collection) if not config.runtime.continuous: break collection_duration_s = time.monotonic() - collection_start if collection_id == 1 or collection_id % 20 == 0 or collection_duration_s > 2.0: logger.info( "LibreVNA radar collection %d acquired in %.3f s", collection_id, collection_duration_s, ) collection_id += 1 finally: close_devices(radar) cleanup.close() logger.info("LibreVNA radar raw producer stopped") return 0 if __name__ == "__main__": raise SystemExit(main())