Refactor radar system
This commit is contained in:
@@ -3,7 +3,7 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
from contextlib import suppress
|
||||
from contextlib import ExitStack, suppress
|
||||
import logging
|
||||
from pathlib import Path
|
||||
import signal
|
||||
@@ -131,42 +131,46 @@ def main() -> int:
|
||||
args.config, len(config.combos), config.runtime.continuous,
|
||||
)
|
||||
|
||||
raw_writer = ShmRingWriter(
|
||||
config.rings.raw.name,
|
||||
config.rings.raw.capacity,
|
||||
config.rings.raw.slot_size_bytes,
|
||||
)
|
||||
raw_tap_writer = ShmRingWriter(
|
||||
config.rings.raw_tap.name,
|
||||
config.rings.raw_tap.capacity,
|
||||
config.rings.raw_tap.slot_size_bytes,
|
||||
)
|
||||
logger.debug(
|
||||
"Opened SHM ring writers: raw=%s, raw_tap=%s",
|
||||
config.rings.raw.name, config.rings.raw_tap.name,
|
||||
)
|
||||
# Switch-aware mode: with native switches the collector drives the RF switches
|
||||
# itself, in the hardware gap between sweeps, and tags each sweep with its combo
|
||||
# — no sweep lost at a switch boundary. The producer then only reads tagged
|
||||
# sweeps and must not touch the GPIO lines the collector owns. With mock switches
|
||||
# (dev/tests) we keep the Python-driven path, which is fine where speed and the
|
||||
# in-gap timing do not matter.
|
||||
collector_driven = (
|
||||
config.input_switch.driver_mode == "native"
|
||||
and config.output_switch.driver_mode == "native"
|
||||
)
|
||||
radar = KamilAdcService(
|
||||
config,
|
||||
switch_config_path=str(args.config) if collector_driven else None,
|
||||
)
|
||||
input_switch = None if collector_driven else SwitchService.from_model(config.input_switch)
|
||||
output_switch = None if collector_driven else SwitchService.from_model(config.output_switch)
|
||||
logger.info(
|
||||
"Kamil ADC switch control: %s",
|
||||
"collector-driven (in-gap, lossless)" if collector_driven else "producer-driven",
|
||||
)
|
||||
|
||||
radar = input_switch = output_switch = None
|
||||
cleanup = ExitStack()
|
||||
try:
|
||||
raw_writer = ShmRingWriter(
|
||||
config.rings.raw.name,
|
||||
config.rings.raw.capacity,
|
||||
config.rings.raw.slot_size_bytes,
|
||||
)
|
||||
cleanup.callback(raw_writer.close)
|
||||
raw_tap_writer = ShmRingWriter(
|
||||
config.rings.raw_tap.name,
|
||||
config.rings.raw_tap.capacity,
|
||||
config.rings.raw_tap.slot_size_bytes,
|
||||
)
|
||||
cleanup.callback(raw_tap_writer.close)
|
||||
logger.debug(
|
||||
"Opened SHM ring writers: raw=%s, raw_tap=%s",
|
||||
config.rings.raw.name, config.rings.raw_tap.name,
|
||||
)
|
||||
# Switch-aware mode: with native switches the collector drives the RF switches
|
||||
# itself, in the hardware gap between sweeps, and tags each sweep with its combo
|
||||
# — no sweep lost at a switch boundary. The producer then only reads tagged
|
||||
# sweeps and must not touch the GPIO lines the collector owns. With mock switches
|
||||
# (dev/tests) we keep the Python-driven path, which is fine where speed and the
|
||||
# in-gap timing do not matter.
|
||||
collector_driven = (
|
||||
config.input_switch.driver_mode == "native"
|
||||
and config.output_switch.driver_mode == "native"
|
||||
)
|
||||
radar = KamilAdcService(
|
||||
config,
|
||||
switch_config_path=str(args.config) if collector_driven else None,
|
||||
)
|
||||
input_switch = None if collector_driven else SwitchService.from_model(config.input_switch)
|
||||
output_switch = None if collector_driven else SwitchService.from_model(config.output_switch)
|
||||
logger.info(
|
||||
"Kamil ADC switch control: %s",
|
||||
"collector-driven (in-gap, lossless)" if collector_driven else "producer-driven",
|
||||
)
|
||||
|
||||
if not _open_radar_with_retry(config, radar, input_switch, output_switch, stop_requested):
|
||||
return 0 # asked to stop before a device became available
|
||||
|
||||
@@ -187,10 +191,12 @@ def main() -> int:
|
||||
sweep_start_ns = time.monotonic_ns()
|
||||
sweep = radar.acquire(combo=(combo.input, combo.output))
|
||||
else:
|
||||
if input_switch is None or output_switch is None:
|
||||
raise RuntimeError("Producer-driven switches are not initialized")
|
||||
output_switch.switch_to(combo.output)
|
||||
input_switch.switch_to(combo.input)
|
||||
if config.runtime.settling_ms > 0:
|
||||
time.sleep(config.runtime.settling_ms / 1000.0)
|
||||
if config.runtime.settling_ms > 0 and stop_requested.wait(config.runtime.settling_ms / 1000.0):
|
||||
break
|
||||
# Stamped after switching and settling so the window covers
|
||||
# the sweep alone, not the dead time before it.
|
||||
sweep_start_ns = time.monotonic_ns()
|
||||
@@ -264,10 +270,10 @@ def main() -> int:
|
||||
if input_switch is not None:
|
||||
with suppress(Exception):
|
||||
input_switch.close()
|
||||
with suppress(Exception):
|
||||
radar.close()
|
||||
raw_tap_writer.close()
|
||||
raw_writer.close()
|
||||
if radar is not None:
|
||||
with suppress(Exception):
|
||||
radar.close()
|
||||
cleanup.close()
|
||||
|
||||
logger.info("Kamil ADC raw producer stopped")
|
||||
return 0
|
||||
|
||||
Reference in New Issue
Block a user