updated tags for new release #25
1
.gitignore
vendored
1
.gitignore
vendored
|
|
@ -52,6 +52,7 @@ tests/sdr/
|
|||
|
||||
# Sphinx documentation
|
||||
docs/build/
|
||||
docs/_build/
|
||||
|
||||
# Jupyter Notebook
|
||||
.ipynb_checkpoints
|
||||
|
|
|
|||
1083
docs/_build/html/_sources/intro/getting_started.rst.txt
vendored
Normal file
1083
docs/_build/html/_sources/intro/getting_started.rst.txt
vendored
Normal file
File diff suppressed because it is too large
Load Diff
29
docs/source/_static/custom.css
Normal file
29
docs/source/_static/custom.css
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
/* Change the hex values below to customize heading colours */
|
||||
|
||||
.rst-content h1 { color: #2c3e50; }
|
||||
.rst-content h2,
|
||||
.rst-content h2 a { color: #ffffff !important; font-size: 22px !important; }
|
||||
|
||||
.rst-content h3,
|
||||
.rst-content h3 a { color: #ffffff !important; font-size: 16px !important; }
|
||||
|
||||
.rst-content h3 code { font-size: inherit !important; }
|
||||
|
||||
.rst-content .admonition.warning {
|
||||
background: #1a1a2e !important;
|
||||
border-left: 4px solid #c0392b !important;
|
||||
}
|
||||
|
||||
.rst-content .admonition.warning .admonition-title {
|
||||
background: #c0392b !important;
|
||||
color: #ffffff !important;
|
||||
}
|
||||
|
||||
.rst-content .admonition.warning p {
|
||||
color: #ffffff !important;
|
||||
}
|
||||
.rst-content h4 { color: #404040; }
|
||||
|
||||
.highlight * { color: #ffffff !important; }
|
||||
|
||||
.ria-cmd { color: #2980b9 !important; }
|
||||
8
docs/source/_static/custom.js
Normal file
8
docs/source/_static/custom.js
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
document.addEventListener('DOMContentLoaded', function () {
|
||||
document.querySelectorAll('.highlight pre').forEach(function (pre) {
|
||||
pre.innerHTML = pre.innerHTML.replace(
|
||||
/((?:^|\n|>))(ria)(?=[ \t]|<)/g,
|
||||
'$1<span class="ria-cmd">$2</span>'
|
||||
);
|
||||
});
|
||||
});
|
||||
|
|
@ -14,7 +14,7 @@ sys.path.insert(0, os.path.abspath(os.path.join('..', '..')))
|
|||
project = 'ria-toolkit-oss'
|
||||
copyright = '2025, Qoherent Inc'
|
||||
author = 'Qoherent Inc.'
|
||||
release = '0.1.4'
|
||||
release = '0.1.5'
|
||||
|
||||
# -- General configuration ---------------------------------------------------
|
||||
# https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration
|
||||
|
|
@ -73,3 +73,6 @@ def setup(app):
|
|||
# https://www.sphinx-doc.org/en/master/usage/configuration.html#options-for-html-output
|
||||
|
||||
html_theme = 'sphinx_rtd_theme'
|
||||
html_static_path = ['_static']
|
||||
html_css_files = ['custom.css']
|
||||
html_js_files = ['custom.js']
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
901
poetry.lock
generated
901
poetry.lock
generated
File diff suppressed because it is too large
Load Diff
|
|
@ -1,2 +0,0 @@
|
|||
[virtualenvs.options]
|
||||
system-site-packages = true
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
[project]
|
||||
name = "ria-toolkit-oss"
|
||||
version = "0.1.4"
|
||||
version = "0.1.5"
|
||||
description = "An open-source version of the RIA Toolkit, including the fundamental tools to get started developing, testing, and deploying radio intelligence applications"
|
||||
license = { text = "AGPL-3.0-only" }
|
||||
readme = "README.md"
|
||||
|
|
@ -49,7 +49,8 @@ dependencies = [
|
|||
"pyzmq (>=27.1.0,<28.0.0)",
|
||||
"pyyaml (>=6.0.3,<7.0.0)",
|
||||
"click (>=8.1.0,<9.0.0)",
|
||||
"matplotlib (>=3.8.0,<4.0.0)"
|
||||
"matplotlib (>=3.8.0,<4.0.0)",
|
||||
"paramiko (>=4.0.0)"
|
||||
]
|
||||
|
||||
# [project.optional-dependencies] Commented out to prevent Tox tests from failing
|
||||
|
|
@ -87,7 +88,7 @@ pytest = "^8.0.0"
|
|||
tox = "^4.19.0"
|
||||
fastapi = ">=0.111,<1.0"
|
||||
uvicorn = {version = ">=0.29,<1.0", extras = ["standard"]}
|
||||
onnxruntime = ">=1.17,<2.0"
|
||||
onnxruntime = {version = ">=1.17,<2.0", python = ">=3.11"}
|
||||
httpx = ">=0.27,<1.0"
|
||||
|
||||
[tool.poetry.group.docs.dependencies]
|
||||
|
|
@ -121,7 +122,7 @@ ria-agent = "ria_toolkit_oss.agent:main"
|
|||
[tool.poetry.group.server.dependencies]
|
||||
fastapi = ">=0.111,<1.0"
|
||||
uvicorn = {version = ">=0.29,<1.0", extras = ["standard"]}
|
||||
onnxruntime = ">=1.17,<2.0"
|
||||
onnxruntime = {version = ">=1.17,<2.0", python = ">=3.11"}
|
||||
|
||||
[tool.black]
|
||||
line-length = 119
|
||||
|
|
|
|||
|
|
@ -40,15 +40,19 @@ class RemoteTransmitter:
|
|||
try:
|
||||
if radio_str in ("pluto", "plutosdr"):
|
||||
from ria_toolkit_oss.sdr.pluto import Pluto
|
||||
|
||||
self._sdr = Pluto(identifier)
|
||||
elif radio_str in ("usrp",):
|
||||
from ria_toolkit_oss.sdr.usrp import USRP
|
||||
|
||||
self._sdr = USRP(identifier)
|
||||
elif radio_str in ("hackrf", "hackrf_one"):
|
||||
from ria_toolkit_oss.sdr.hackrf import HackRF
|
||||
|
||||
self._sdr = HackRF(identifier)
|
||||
elif radio_str in ("bladerf", "blade"):
|
||||
from ria_toolkit_oss.sdr.blade import Blade
|
||||
|
||||
self._sdr = Blade(identifier)
|
||||
else:
|
||||
raise ValueError(f"Unknown SDR type: {radio_str!r}")
|
||||
|
|
@ -77,6 +81,7 @@ class RemoteTransmitter:
|
|||
if self._sdr is None:
|
||||
raise RuntimeError("Call set_radio() and init_tx() before transmit()")
|
||||
import time
|
||||
|
||||
# Transmit in a loop until duration has elapsed
|
||||
end = time.monotonic() + duration_s
|
||||
while time.monotonic() < end:
|
||||
|
|
|
|||
|
|
@ -14,6 +14,9 @@ import logging
|
|||
import threading
|
||||
import time
|
||||
|
||||
import paramiko
|
||||
import zmq
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
_STARTUP_WAIT_S = 2.0 # seconds to wait for remote ZMQ server to bind
|
||||
|
|
@ -158,16 +161,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.
|
||||
|
|
|
|||
|
|
@ -12,7 +12,6 @@ import pytest
|
|||
|
||||
from ria_toolkit_oss.remote_control.remote_transmitter import RemoteTransmitter
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Helpers
|
||||
# ---------------------------------------------------------------------------
|
||||
|
|
@ -63,14 +62,18 @@ class TestSetRadio:
|
|||
def test_hackrf_alias(self):
|
||||
tx = RemoteTransmitter()
|
||||
mock_sdr = _make_mock_sdr()
|
||||
with patch("ria_toolkit_oss.sdr.hackrf.HackRF", return_value=mock_sdr):
|
||||
mock_module = MagicMock()
|
||||
mock_module.HackRF = MagicMock(return_value=mock_sdr)
|
||||
with patch.dict("sys.modules", {"ria_toolkit_oss.sdr.hackrf": mock_module}):
|
||||
tx.set_radio("hackrf", "")
|
||||
assert tx._sdr is mock_sdr
|
||||
|
||||
def test_hackrf_one_alias(self):
|
||||
tx = RemoteTransmitter()
|
||||
mock_sdr = _make_mock_sdr()
|
||||
with patch("ria_toolkit_oss.sdr.hackrf.HackRF", return_value=mock_sdr):
|
||||
mock_module = MagicMock()
|
||||
mock_module.HackRF = MagicMock(return_value=mock_sdr)
|
||||
with patch.dict("sys.modules", {"ria_toolkit_oss.sdr.hackrf": mock_module}):
|
||||
tx.set_radio("hackrf_one", "")
|
||||
assert tx._sdr is mock_sdr
|
||||
|
||||
|
|
@ -241,34 +244,40 @@ class TestRunFunction:
|
|||
|
||||
def test_init_tx_without_radio_returns_failure(self):
|
||||
tx = RemoteTransmitter()
|
||||
resp = tx.run_function({
|
||||
resp = tx.run_function(
|
||||
{
|
||||
"function_name": "init_tx",
|
||||
"center_frequency": 2.4e9,
|
||||
"sample_rate": 20e6,
|
||||
"gain": 0,
|
||||
})
|
||||
}
|
||||
)
|
||||
assert resp["status"] is False
|
||||
assert resp["error_message"]
|
||||
|
||||
def test_init_tx_with_radio_success(self):
|
||||
tx = self._tx_with_mock_sdr()
|
||||
resp = tx.run_function({
|
||||
resp = tx.run_function(
|
||||
{
|
||||
"function_name": "init_tx",
|
||||
"center_frequency": 2.4e9,
|
||||
"sample_rate": 20e6,
|
||||
"gain": 30,
|
||||
})
|
||||
}
|
||||
)
|
||||
assert resp["status"] is True
|
||||
|
||||
def test_transmit_runs_for_short_duration(self):
|
||||
tx = self._tx_with_mock_sdr()
|
||||
tx._sdr.init_tx = MagicMock()
|
||||
resp = tx.run_function({
|
||||
resp = tx.run_function(
|
||||
{
|
||||
"function_name": "init_tx",
|
||||
"center_frequency": 2.4e9,
|
||||
"sample_rate": 20e6,
|
||||
"gain": 0,
|
||||
})
|
||||
}
|
||||
)
|
||||
resp = tx.run_function({"function_name": "transmit", "duration_s": 0.02})
|
||||
assert resp["status"] is True
|
||||
|
||||
|
|
|
|||
|
|
@ -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