qac-cli-commands #26
4
poetry.lock
generated
4
poetry.lock
generated
|
|
@ -1,4 +1,4 @@
|
|||
# This file is automatically @generated by Poetry 2.3.4 and should not be changed by hand.
|
||||
# This file is automatically @generated by Poetry 2.1.2 and should not be changed by hand.
|
||||
|
||||
[[package]]
|
||||
name = "alabaster"
|
||||
|
|
@ -1096,7 +1096,7 @@ files = [
|
|||
|
||||
[package.dependencies]
|
||||
attrs = ">=22.2.0"
|
||||
jsonschema-specifications = ">=2023.3.6"
|
||||
jsonschema-specifications = ">=2023.03.6"
|
||||
referencing = ">=0.28.4"
|
||||
rpds-py = ">=0.25.0"
|
||||
|
||||
|
|
|
|||
|
|
@ -270,9 +270,7 @@ class Streamer:
|
|||
)
|
||||
self._rx = session
|
||||
await self._send_status("streaming", app_id)
|
||||
session.task = asyncio.create_task(
|
||||
self._capture_loop(session), name="ria-streamer-capture"
|
||||
)
|
||||
session.task = asyncio.create_task(self._capture_loop(session), name="ria-streamer-capture")
|
||||
|
||||
async def _handle_rx_stop(self, msg: dict) -> None:
|
||||
session = self._rx
|
||||
|
|
@ -310,9 +308,7 @@ class Streamer:
|
|||
logger.warning("Applying configure failed: %s", exc)
|
||||
|
||||
try:
|
||||
samples = await loop.run_in_executor(
|
||||
None, session.sdr.rx, session.buffer_size
|
||||
)
|
||||
samples = await loop.run_in_executor(None, session.sdr.rx, session.buffer_size)
|
||||
except Exception as exc:
|
||||
from ria_toolkit_oss.sdr import SdrDisconnectedError
|
||||
|
||||
|
|
@ -342,7 +338,7 @@ class Streamer:
|
|||
# ==================================================================
|
||||
# TX
|
||||
|
||||
async def _handle_tx_start(self, msg: dict) -> None:
|
||||
async def _handle_tx_start(self, msg: dict) -> None: # noqa: C901
|
||||
app_id = msg.get("app_id") or ""
|
||||
radio_config = dict(msg.get("radio_config") or {})
|
||||
|
||||
|
|
@ -383,9 +379,7 @@ class Streamer:
|
|||
buffer_size = int(radio_config.pop("buffer_size", _DEFAULT_BUFFER_SIZE))
|
||||
underrun_policy = str(radio_config.pop("underrun_policy", "pause"))
|
||||
if underrun_policy not in ("pause", "zero", "repeat"):
|
||||
await self._send_tx_status(
|
||||
app_id, "error", f"invalid underrun_policy {underrun_policy!r}"
|
||||
)
|
||||
await self._send_tx_status(app_id, "error", f"invalid underrun_policy {underrun_policy!r}")
|
||||
return
|
||||
if not device:
|
||||
await self._send_tx_status(app_id, "error", "tx_start missing radio_config.device")
|
||||
|
|
@ -404,15 +398,10 @@ class Streamer:
|
|||
# manifest bug and we want it surfaced immediately, not papered
|
||||
# over with stale radio state.
|
||||
if hasattr(sdr, "init_tx"):
|
||||
init_args = {
|
||||
k: radio_config.get(f"tx_{k}")
|
||||
for k in ("sample_rate", "center_frequency", "gain")
|
||||
}
|
||||
init_args = {k: radio_config.get(f"tx_{k}") for k in ("sample_rate", "center_frequency", "gain")}
|
||||
missing = [f"tx_{k}" for k, v in init_args.items() if v is None]
|
||||
if missing:
|
||||
raise ValueError(
|
||||
f"tx_start missing required radio_config keys: {missing}"
|
||||
)
|
||||
raise ValueError(f"tx_start missing required radio_config keys: {missing}")
|
||||
sdr.init_tx(
|
||||
sample_rate=init_args["sample_rate"],
|
||||
center_frequency=init_args["center_frequency"],
|
||||
|
|
@ -498,9 +487,8 @@ class Streamer:
|
|||
return _silence(n)
|
||||
|
||||
# Max-duration watchdog.
|
||||
if (
|
||||
session.max_duration_s is not None
|
||||
and (time.monotonic() - session.started_at) >= float(session.max_duration_s)
|
||||
if session.max_duration_s is not None and (time.monotonic() - session.started_at) >= float(
|
||||
session.max_duration_s
|
||||
):
|
||||
session.stop_event.set()
|
||||
try:
|
||||
|
|
@ -528,7 +516,7 @@ class Streamer:
|
|||
if arr.size < 2 or arr.size % 2 != 0:
|
||||
logger.warning("Malformed TX frame: %d floats (must be non-zero even count)", arr.size)
|
||||
return self._underrun_fill(session, n)
|
||||
samples = (arr[0::2].astype(np.complex64) + 1j * arr[1::2].astype(np.complex64))
|
||||
samples = arr[0::2].astype(np.complex64) + 1j * arr[1::2].astype(np.complex64)
|
||||
if samples.size < n:
|
||||
out = np.zeros(n, dtype=np.complex64)
|
||||
out[: samples.size] = samples
|
||||
|
|
@ -747,6 +735,7 @@ def _default_sdr_factory(device: str, identifier: str | None):
|
|||
# ---------------------------------------------------------------------------
|
||||
# Top-level entry
|
||||
|
||||
|
||||
async def run_streamer(ws_url: str, token: str, *, cfg: AgentConfig | None = None) -> None:
|
||||
"""Connect to *ws_url* and run the streamer loop until cancelled."""
|
||||
ws = WsClient(ws_url, token)
|
||||
|
|
|
|||
|
|
@ -13,6 +13,11 @@ import json
|
|||
import logging
|
||||
import threading
|
||||
import time
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
if TYPE_CHECKING:
|
||||
import paramiko
|
||||
import zmq
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
|
@ -158,16 +163,21 @@ class RemoteTransmitterController:
|
|||
"""
|
||||
logger.info(
|
||||
"init_tx: fc=%.3f MHz, fs=%.3f MHz, gain=%.1f dB, ch=%d",
|
||||
center_frequency / 1e6, sample_rate / 1e6, gain, channel,
|
||||
center_frequency / 1e6,
|
||||
sample_rate / 1e6,
|
||||
gain,
|
||||
channel,
|
||||
)
|
||||
self._send({
|
||||
self._send(
|
||||
{
|
||||
"function_name": "init_tx",
|
||||
"center_frequency": center_frequency,
|
||||
"sample_rate": sample_rate,
|
||||
"gain": gain,
|
||||
"channel": channel,
|
||||
"gain_mode": gain_mode,
|
||||
})
|
||||
}
|
||||
)
|
||||
|
||||
def transmit_async(self, duration_s: float) -> None:
|
||||
"""Start a timed CW transmission in a background thread.
|
||||
|
|
|
|||
|
|
@ -7,8 +7,6 @@ sys.modules so they run regardless of whether the packages are installed.
|
|||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
import sys
|
||||
import threading
|
||||
import time
|
||||
from types import ModuleType
|
||||
from unittest.mock import MagicMock, patch
|
||||
|
|
@ -199,15 +197,11 @@ class TestErrorHandling:
|
|||
|
||||
def test_missing_paramiko_raises_runtime_error(self):
|
||||
"""If paramiko is absent, connecting gives a clear RuntimeError."""
|
||||
import importlib
|
||||
|
||||
import ria_toolkit_oss.remote_control.remote_transmitter_controller as mod
|
||||
|
||||
with patch.dict("sys.modules", {"paramiko": None}):
|
||||
with pytest.raises((RuntimeError, ImportError)):
|
||||
mod.RemoteTransmitterController(
|
||||
host="h", ssh_user="u", ssh_key_path="/k"
|
||||
)
|
||||
mod.RemoteTransmitterController(host="h", ssh_user="u", ssh_key_path="/k")
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
from __future__ import annotations
|
||||
|
||||
from unittest.mock import MagicMock, call, patch
|
||||
from unittest.mock import MagicMock, patch
|
||||
|
||||
import pytest
|
||||
|
||||
|
|
@ -12,7 +12,6 @@ from ria_toolkit_oss.orchestration.campaign import (
|
|||
TransmitterConfig,
|
||||
)
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Helpers
|
||||
# ---------------------------------------------------------------------------
|
||||
|
|
@ -179,9 +178,7 @@ class TestInitRemoteTxControllers:
|
|||
}
|
||||
]
|
||||
executor = _make_executor(d)
|
||||
with patch(
|
||||
"ria_toolkit_oss.remote_control.RemoteTransmitterController"
|
||||
) as mock_cls:
|
||||
with patch("ria_toolkit_oss.remote_control.RemoteTransmitterController") as mock_cls:
|
||||
executor._init_remote_tx_controllers()
|
||||
mock_cls.assert_not_called()
|
||||
assert executor._remote_tx_controllers == {}
|
||||
|
|
@ -264,7 +261,7 @@ class TestStartTransmitterSdrRemote:
|
|||
tx = executor.config.transmitters[0]
|
||||
step = CaptureStep(duration=5.0, label="nochan")
|
||||
executor._start_transmitter(tx, step)
|
||||
_, kwargs = mock_ctrl_kwarg = ctrl.init_tx.call_args
|
||||
_, kwargs = ctrl.init_tx.call_args
|
||||
assert kwargs["channel"] == 0
|
||||
|
||||
def test_missing_controller_raises(self):
|
||||
|
|
@ -381,7 +378,11 @@ class TestRunWithSdrRemote:
|
|||
),
|
||||
patch.object(executor, "_close_sdr"),
|
||||
patch.object(executor, "_close_remote_tx_controllers"),
|
||||
patch.object(executor, "_execute_step", return_value=MagicMock(error=None, qa=MagicMock(flagged=False, snr_db=20.0, duration_s=10.0))),
|
||||
patch.object(
|
||||
executor,
|
||||
"_execute_step",
|
||||
return_value=MagicMock(error=None, qa=MagicMock(flagged=False, snr_db=20.0, duration_s=10.0)),
|
||||
),
|
||||
):
|
||||
executor.run()
|
||||
|
||||
|
|
@ -401,6 +402,7 @@ class TestTransmitBufferAndTimeout:
|
|||
|
||||
def _executor_with_ctrl(self):
|
||||
from ria_toolkit_oss.orchestration.executor import CampaignExecutor
|
||||
|
||||
cfg = CampaignConfig.from_dict(_FULL_CAMPAIGN_DICT)
|
||||
executor = CampaignExecutor(cfg)
|
||||
ctrl = MagicMock()
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user