python-aaronia 0.7.2__tar.gz → 0.7.4__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {python_aaronia-0.7.2 → python_aaronia-0.7.4}/CHANGELOG.md +89 -4
- {python_aaronia-0.7.2 → python_aaronia-0.7.4}/Cargo.lock +2 -2
- {python_aaronia-0.7.2 → python_aaronia-0.7.4}/Cargo.toml +1 -1
- {python_aaronia-0.7.2 → python_aaronia-0.7.4}/PKG-INFO +1 -1
- {python_aaronia-0.7.2 → python_aaronia-0.7.4}/docs/HTTPSPEC.md +231 -8
- {python_aaronia-0.7.2 → python_aaronia-0.7.4}/docs/SDKSPEC.md +10 -6
- {python_aaronia-0.7.2 → python_aaronia-0.7.4}/packaging/homebrew/soapy-aaronia.rb +1 -1
- {python_aaronia-0.7.2 → python_aaronia-0.7.4}/python-aaronia/Cargo.toml +1 -1
- {python_aaronia-0.7.2 → python_aaronia-0.7.4}/soapy-aaronia/Registration.cpp +15 -1
- {python_aaronia-0.7.2 → python_aaronia-0.7.4}/src/http_endpoints.rs +15 -1
- {python_aaronia-0.7.2 → python_aaronia-0.7.4}/src/utils.rs +12 -2
- {python_aaronia-0.7.2 → python_aaronia-0.7.4}/.cargo/config.toml +0 -0
- {python_aaronia-0.7.2 → python_aaronia-0.7.4}/.gitattributes +0 -0
- {python_aaronia-0.7.2 → python_aaronia-0.7.4}/.gitignore +0 -0
- {python_aaronia-0.7.2 → python_aaronia-0.7.4}/CONTRIBUTING.md +0 -0
- {python_aaronia-0.7.2 → python_aaronia-0.7.4}/DESIGN.md +0 -0
- {python_aaronia-0.7.2 → python_aaronia-0.7.4}/LICENSE +0 -0
- {python_aaronia-0.7.2 → python_aaronia-0.7.4}/PLUGINS.md +0 -0
- {python_aaronia-0.7.2 → python_aaronia-0.7.4}/README.md +0 -0
- {python_aaronia-0.7.2 → python_aaronia-0.7.4}/benches/decompress_block.rs +0 -0
- {python_aaronia-0.7.2 → python_aaronia-0.7.4}/benches/deinterleave_dual_iq.rs +0 -0
- {python_aaronia-0.7.2 → python_aaronia-0.7.4}/benches/parse_int16_packet.rs +0 -0
- {python_aaronia-0.7.2 → python_aaronia-0.7.4}/benches/rtsa_open_and_read.rs +0 -0
- {python_aaronia-0.7.2 → python_aaronia-0.7.4}/deny.toml +0 -0
- {python_aaronia-0.7.2 → python_aaronia-0.7.4}/docs/APPS.md +0 -0
- {python_aaronia-0.7.2 → python_aaronia-0.7.4}/docs/FILESPEC.md +0 -0
- {python_aaronia-0.7.2 → python_aaronia-0.7.4}/docs/QUICKSTART.md +0 -0
- {python_aaronia-0.7.2 → python_aaronia-0.7.4}/docs/USAGE.md +0 -0
- {python_aaronia-0.7.2 → python_aaronia-0.7.4}/docs/VERIFICATION.md +0 -0
- {python_aaronia-0.7.2 → python_aaronia-0.7.4}/examples/channel_hopping.rs +0 -0
- {python_aaronia-0.7.2 → python_aaronia-0.7.4}/examples/device_control.rs +0 -0
- {python_aaronia-0.7.2 → python_aaronia-0.7.4}/examples/dump_metadata.rs +0 -0
- {python_aaronia-0.7.2 → python_aaronia-0.7.4}/examples/http_iq_quickstart.rs +0 -0
- {python_aaronia-0.7.2 → python_aaronia-0.7.4}/examples/native_sdk_basic.rs +0 -0
- {python_aaronia-0.7.2 → python_aaronia-0.7.4}/examples/native_sdk_transmit.rs +0 -0
- {python_aaronia-0.7.2 → python_aaronia-0.7.4}/examples/noaa_scanner.rs +0 -0
- {python_aaronia-0.7.2 → python_aaronia-0.7.4}/examples/python_arrow_example.py +0 -0
- {python_aaronia-0.7.2 → python_aaronia-0.7.4}/examples/read_rtsa_file.rs +0 -0
- {python_aaronia-0.7.2 → python_aaronia-0.7.4}/examples/soapy_python_example.py +0 -0
- {python_aaronia-0.7.2 → python_aaronia-0.7.4}/include/aaronia.h +0 -0
- {python_aaronia-0.7.2 → python_aaronia-0.7.4}/packaging/homebrew/README.md +0 -0
- {python_aaronia-0.7.2 → python_aaronia-0.7.4}/pyproject.toml +0 -0
- {python_aaronia-0.7.2 → python_aaronia-0.7.4}/python-aaronia/README.md +0 -0
- {python_aaronia-0.7.2 → python_aaronia-0.7.4}/python-aaronia/aaronia.pyi +0 -0
- {python_aaronia-0.7.2 → python_aaronia-0.7.4}/python-aaronia/src/lib.rs +0 -0
- {python_aaronia-0.7.2 → python_aaronia-0.7.4}/python-aaronia/test_basic.py +0 -0
- {python_aaronia-0.7.2 → python_aaronia-0.7.4}/scripts/ci-local.sh +0 -0
- {python_aaronia-0.7.2 → python_aaronia-0.7.4}/soapy-aaronia/AaroniaSoapyDevice.cpp +0 -0
- {python_aaronia-0.7.2 → python_aaronia-0.7.4}/soapy-aaronia/AaroniaSoapyDevice.hpp +0 -0
- {python_aaronia-0.7.2 → python_aaronia-0.7.4}/soapy-aaronia/CMakeLists.txt +0 -0
- {python_aaronia-0.7.2 → python_aaronia-0.7.4}/soapy-aaronia/README.md +0 -0
- {python_aaronia-0.7.2 → python_aaronia-0.7.4}/soapy-aaronia/build-test/CMakeCache.txt +0 -0
- {python_aaronia-0.7.2 → python_aaronia-0.7.4}/soapy-aaronia/build-test/CMakeFiles/4.4.2/CMakeCXXCompiler.cmake +0 -0
- {python_aaronia-0.7.2 → python_aaronia-0.7.4}/soapy-aaronia/build-test/CMakeFiles/4.4.2/CMakeDetermineCompilerABI_CXX.bin +0 -0
- {python_aaronia-0.7.2 → python_aaronia-0.7.4}/soapy-aaronia/build-test/CMakeFiles/4.4.2/CMakeSystem.cmake +0 -0
- {python_aaronia-0.7.2 → python_aaronia-0.7.4}/soapy-aaronia/build-test/CMakeFiles/4.4.2/CompilerIdCXX/CMakeCXXCompilerId.cpp +0 -0
- {python_aaronia-0.7.2 → python_aaronia-0.7.4}/soapy-aaronia/build-test/CMakeFiles/4.4.2/CompilerIdCXX/a.out +0 -0
- {python_aaronia-0.7.2 → python_aaronia-0.7.4}/soapy-aaronia/build-test/CMakeFiles/4.4.2/CompilerIdCXX/apple-sdk.cpp +0 -0
- {python_aaronia-0.7.2 → python_aaronia-0.7.4}/soapy-aaronia/build-test/CMakeFiles/CMakeConfigureLog.yaml +0 -0
- {python_aaronia-0.7.2 → python_aaronia-0.7.4}/soapy-aaronia/build-test/CMakeFiles/CMakeDirectoryInformation.cmake +0 -0
- {python_aaronia-0.7.2 → python_aaronia-0.7.4}/soapy-aaronia/build-test/CMakeFiles/CMakeRuleHashes.txt +0 -0
- {python_aaronia-0.7.2 → python_aaronia-0.7.4}/soapy-aaronia/build-test/CMakeFiles/InstallScripts.json +0 -0
- {python_aaronia-0.7.2 → python_aaronia-0.7.4}/soapy-aaronia/build-test/CMakeFiles/Makefile.cmake +0 -0
- {python_aaronia-0.7.2 → python_aaronia-0.7.4}/soapy-aaronia/build-test/CMakeFiles/Makefile2 +0 -0
- {python_aaronia-0.7.2 → python_aaronia-0.7.4}/soapy-aaronia/build-test/CMakeFiles/TargetDirectories.txt +0 -0
- {python_aaronia-0.7.2 → python_aaronia-0.7.4}/soapy-aaronia/build-test/CMakeFiles/aaroniaSupport.dir/DependInfo.cmake +0 -0
- {python_aaronia-0.7.2 → python_aaronia-0.7.4}/soapy-aaronia/build-test/CMakeFiles/aaroniaSupport.dir/build.make +0 -0
- {python_aaronia-0.7.2 → python_aaronia-0.7.4}/soapy-aaronia/build-test/CMakeFiles/aaroniaSupport.dir/cmake_clean.cmake +0 -0
- {python_aaronia-0.7.2 → python_aaronia-0.7.4}/soapy-aaronia/build-test/CMakeFiles/aaroniaSupport.dir/compiler_depend.make +0 -0
- {python_aaronia-0.7.2 → python_aaronia-0.7.4}/soapy-aaronia/build-test/CMakeFiles/aaroniaSupport.dir/compiler_depend.ts +0 -0
- {python_aaronia-0.7.2 → python_aaronia-0.7.4}/soapy-aaronia/build-test/CMakeFiles/aaroniaSupport.dir/depend.make +0 -0
- {python_aaronia-0.7.2 → python_aaronia-0.7.4}/soapy-aaronia/build-test/CMakeFiles/aaroniaSupport.dir/flags.make +0 -0
- {python_aaronia-0.7.2 → python_aaronia-0.7.4}/soapy-aaronia/build-test/CMakeFiles/aaroniaSupport.dir/link.txt +0 -0
- {python_aaronia-0.7.2 → python_aaronia-0.7.4}/soapy-aaronia/build-test/CMakeFiles/aaroniaSupport.dir/progress.make +0 -0
- {python_aaronia-0.7.2 → python_aaronia-0.7.4}/soapy-aaronia/build-test/CMakeFiles/cmake.check_cache +0 -0
- {python_aaronia-0.7.2 → python_aaronia-0.7.4}/soapy-aaronia/build-test/CMakeFiles/progress.marks +0 -0
- {python_aaronia-0.7.2 → python_aaronia-0.7.4}/soapy-aaronia/build-test/CMakeFiles/sdr_aaronia_rs_static.dir/DependInfo.cmake +0 -0
- {python_aaronia-0.7.2 → python_aaronia-0.7.4}/soapy-aaronia/build-test/CMakeFiles/sdr_aaronia_rs_static.dir/build.make +0 -0
- {python_aaronia-0.7.2 → python_aaronia-0.7.4}/soapy-aaronia/build-test/CMakeFiles/sdr_aaronia_rs_static.dir/cmake_clean.cmake +0 -0
- {python_aaronia-0.7.2 → python_aaronia-0.7.4}/soapy-aaronia/build-test/CMakeFiles/sdr_aaronia_rs_static.dir/compiler_depend.make +0 -0
- {python_aaronia-0.7.2 → python_aaronia-0.7.4}/soapy-aaronia/build-test/CMakeFiles/sdr_aaronia_rs_static.dir/compiler_depend.ts +0 -0
- {python_aaronia-0.7.2 → python_aaronia-0.7.4}/soapy-aaronia/build-test/CMakeFiles/sdr_aaronia_rs_static.dir/progress.make +0 -0
- {python_aaronia-0.7.2 → python_aaronia-0.7.4}/soapy-aaronia/build-test/Makefile +0 -0
- {python_aaronia-0.7.2 → python_aaronia-0.7.4}/soapy-aaronia/build-test/cmake_install.cmake +0 -0
- {python_aaronia-0.7.2 → python_aaronia-0.7.4}/soapy-aaronia/packaging/install.ps1 +0 -0
- {python_aaronia-0.7.2 → python_aaronia-0.7.4}/soapy-aaronia/packaging/install.sh +0 -0
- {python_aaronia-0.7.2 → python_aaronia-0.7.4}/soapy-aaronia/print.cmake +0 -0
- {python_aaronia-0.7.2 → python_aaronia-0.7.4}/src/c_api.rs +0 -0
- {python_aaronia-0.7.2 → python_aaronia-0.7.4}/src/decompression.rs +0 -0
- {python_aaronia-0.7.2 → python_aaronia-0.7.4}/src/detection.rs +0 -0
- {python_aaronia-0.7.2 → python_aaronia-0.7.4}/src/error.rs +0 -0
- {python_aaronia-0.7.2 → python_aaronia-0.7.4}/src/file_source.rs +0 -0
- {python_aaronia-0.7.2 → python_aaronia-0.7.4}/src/http_sink.rs +0 -0
- {python_aaronia-0.7.2 → python_aaronia-0.7.4}/src/http_source.rs +0 -0
- {python_aaronia-0.7.2 → python_aaronia-0.7.4}/src/http_streaming.rs +0 -0
- {python_aaronia-0.7.2 → python_aaronia-0.7.4}/src/lib.rs +0 -0
- {python_aaronia-0.7.2 → python_aaronia-0.7.4}/src/native_sdk.rs +0 -0
- {python_aaronia-0.7.2 → python_aaronia-0.7.4}/src/sdk_sink.rs +0 -0
- {python_aaronia-0.7.2 → python_aaronia-0.7.4}/src/sdk_source.rs +0 -0
- {python_aaronia-0.7.2 → python_aaronia-0.7.4}/src/sdr_source_impl.rs +0 -0
- {python_aaronia-0.7.2 → python_aaronia-0.7.4}/src/seify_impl.rs +0 -0
- {python_aaronia-0.7.2 → python_aaronia-0.7.4}/src/unified_sink.rs +0 -0
- {python_aaronia-0.7.2 → python_aaronia-0.7.4}/src/unified_source.rs +0 -0
- {python_aaronia-0.7.2 → python_aaronia-0.7.4}/test.cmake +0 -0
- {python_aaronia-0.7.2 → python_aaronia-0.7.4}/tests/c_api_test.rs +0 -0
- {python_aaronia-0.7.2 → python_aaronia-0.7.4}/tests/http_mock_test.rs +0 -0
- {python_aaronia-0.7.2 → python_aaronia-0.7.4}/tests/http_resilience_test.rs +0 -0
- {python_aaronia-0.7.2 → python_aaronia-0.7.4}/tests/http_sink_test.rs +0 -0
- {python_aaronia-0.7.2 → python_aaronia-0.7.4}/tests/integration_test.rs +0 -0
- {python_aaronia-0.7.2 → python_aaronia-0.7.4}/tests/live_smoke.rs +0 -0
- {python_aaronia-0.7.2 → python_aaronia-0.7.4}/tests/native_sdk_load.rs +0 -0
- {python_aaronia-0.7.2 → python_aaronia-0.7.4}/tests/properties.proptest-regressions +0 -0
- {python_aaronia-0.7.2 → python_aaronia-0.7.4}/tests/properties.rs +0 -0
- {python_aaronia-0.7.2 → python_aaronia-0.7.4}/tests/rtsa_negative_test.rs +0 -0
- {python_aaronia-0.7.2 → python_aaronia-0.7.4}/tests/sdr_source_impl_test.rs +0 -0
- {python_aaronia-0.7.2 → python_aaronia-0.7.4}/tests/spec_coverage.rs +0 -0
- {python_aaronia-0.7.2 → python_aaronia-0.7.4}/tests/test_cw_mag.rs +0 -0
- {python_aaronia-0.7.2 → python_aaronia-0.7.4}/tests/test_cw_meta.rs +0 -0
|
@@ -4,6 +4,90 @@ All notable changes to this project will be documented in this file.
|
|
|
4
4
|
|
|
5
5
|
## [Unreleased]
|
|
6
6
|
|
|
7
|
+
## [v0.7.4] - 2026-08-12
|
|
8
|
+
|
|
9
|
+
### Fixed
|
|
10
|
+
- **The SoapySDR plugin ignored an unrecognised `format=` silently.**
|
|
11
|
+
A device string carrying `format=int16` — the wire name rather than
|
|
12
|
+
the plugin's `I16` — streamed the default format while claiming
|
|
13
|
+
otherwise. It now warns and continues. The server behaves the same
|
|
14
|
+
way and worse: an unrecognised `format=` on `/stream` serves the
|
|
15
|
+
RTSA file format with HTTP 200 rather than an error, so a typo
|
|
16
|
+
changes the wire format entirely. `raw16`, which Aaronia's own Qt
|
|
17
|
+
reference client sends, is a working alias for `int16`.
|
|
18
|
+
|
|
19
|
+
### Documentation
|
|
20
|
+
- Checked Aaronia's V6 remote control notes (rev 4, May 2026) against
|
|
21
|
+
the hardware. `/remoteconfig` enum fields take an index as well as a
|
|
22
|
+
label; one `simpleconfig` PUT can carry several groups, and groups
|
|
23
|
+
other than `main` work; and a PUT naming a block that is not in the
|
|
24
|
+
mission returns 200 and changes nothing, which
|
|
25
|
+
`simple_remote_config` now warns about since it reports `Ok(())` for
|
|
26
|
+
a write that did not happen. In the config-tree form the receiver
|
|
27
|
+
name is ignored altogether — the write is routed by `config.name`.
|
|
28
|
+
- Documented loading a mission over `/control`, and that every
|
|
29
|
+
`/control` payload needs its `type` or the server answers `400`.
|
|
30
|
+
Loading a mission is deliberately not exposed by the crate: swapping
|
|
31
|
+
the mission under a running capture should be a caller's decision,
|
|
32
|
+
not a side effect.
|
|
33
|
+
- Noted that RTSA-Suite has no status endpoint. Aaronia's own liveness
|
|
34
|
+
check reads the `404` from `/api/status` as proof the server is up.
|
|
35
|
+
- **What "Full" means on a full V6 is unresolved.** A V6 ECO follows the
|
|
36
|
+
SDK's `spanfreq <= receiverclock / 1.5`, measured. Aaronia's Remote
|
|
37
|
+
Config screenshots show a full V6 at a 92 MHz clock delivering
|
|
38
|
+
92.16 MHz of IQ samples per second at span "Full" — the clock itself.
|
|
39
|
+
`iq_sample_rates_for_clock` may therefore understate the top of the
|
|
40
|
+
ladder by 1.5x for a full V6 at a non-default clock; it says so now.
|
|
41
|
+
Settling it needs a full V6.
|
|
42
|
+
- HTTPSPEC contradicted itself on the Remote Config licence, asserting
|
|
43
|
+
in one section that writes need it and in another that a live
|
|
44
|
+
unlicensed system accepts them. The second is what the hardware does,
|
|
45
|
+
re-confirmed for centre frequency, decimation, reference level and
|
|
46
|
+
the preamplifier.
|
|
47
|
+
- SDKSPEC still gave the V6 ECO's receiver clock as 61.44 MHz, which
|
|
48
|
+
0.6.2 corrected in code to 92.16 MHz. 61.44 MHz is the ECO's top IQ
|
|
49
|
+
rate, that clock over 1.5; the document had the two confused.
|
|
50
|
+
- **A marker stream is not a categories packet**, which the previous
|
|
51
|
+
draft of this entry got wrong. Aaronia's example declares
|
|
52
|
+
`payload: "spectra"`, and spectra samples are a 2D array, so its
|
|
53
|
+
nesting is correct for what it says it is. Its three frequency fields
|
|
54
|
+
are all zero, so the category names and ranges are the only
|
|
55
|
+
description of what the numbers mean.
|
|
56
|
+
- Aaronia's endpoint specification (rev 11) settles several things this
|
|
57
|
+
document had only inferred, and their support answers go further.
|
|
58
|
+
`/control` takes PUT only, and a command reaches every block that
|
|
59
|
+
understands it unless `receiverUUID` or `receiverName` scopes it —
|
|
60
|
+
the specification says such commands cannot be addressed to a block,
|
|
61
|
+
which their support corrected in 2024. The per-type settings are now
|
|
62
|
+
listed in full, including `deviceconnect` and `camera`, which this
|
|
63
|
+
crate does not model. Zones cannot be configured remotely at all.
|
|
64
|
+
The server starts dropping data once its outbound TCP buffer passes
|
|
65
|
+
8 MB, which is the mechanism behind most unexplained gaps.
|
|
66
|
+
`/healthstatus` is organised as `info`, `status`, `health`,
|
|
67
|
+
`settings` and `components`, the last being how satellites attached
|
|
68
|
+
over HTTP appear in a local tree.
|
|
69
|
+
- **`status/iqsamples` is the native rate, not the delivered one.** It
|
|
70
|
+
held at 61.44 MHz while the same device delivered 15.36, then 7.68,
|
|
71
|
+
then 61.44 MS/s. It looks like a sample rate and is not the one your
|
|
72
|
+
stream is running at; read `sampleFrequency` from packet metadata.
|
|
73
|
+
Documented the other fields a V6 ECO reports alongside it.
|
|
74
|
+
- **One HTTP Server and one HTTP Client connection are free**;
|
|
75
|
+
additional instances and connections are licensed separately, as are
|
|
76
|
+
Stream Merger and Stream Splitter. Running this crate and a second
|
|
77
|
+
client against one server at the same time is a second connection —
|
|
78
|
+
the licence limit most likely to be met in practice, and unrelated to
|
|
79
|
+
Remote Config.
|
|
80
|
+
|
|
81
|
+
## [v0.7.3] - 2026-08-12
|
|
82
|
+
|
|
83
|
+
### Fixed
|
|
84
|
+
- The Windows leg of the new module load check could not run: vcpkg's
|
|
85
|
+
SoapySDR port ships no `SoapySDRUtil`, so the check failed rather
|
|
86
|
+
than verifying anything, and 0.7.2 published no release archives.
|
|
87
|
+
Where the tool is absent the packaged DLL is now loaded directly,
|
|
88
|
+
which still catches a module whose dependencies do not resolve away
|
|
89
|
+
from the build machine.
|
|
90
|
+
|
|
7
91
|
## [v0.7.2] - 2026-08-12
|
|
8
92
|
|
|
9
93
|
### Fixed
|
|
@@ -31,10 +115,11 @@ All notable changes to this project will be documented in this file.
|
|
|
31
115
|
|
|
32
116
|
## [v0.7.1] - 2026-08-12
|
|
33
117
|
|
|
34
|
-
An incomplete fix for the macOS module, superseded by 0.7.2.
|
|
35
|
-
crates.io and PyPI but published no
|
|
36
|
-
refused to ship a macOS module that would
|
|
37
|
-
|
|
118
|
+
An incomplete fix for the macOS module, superseded by 0.7.2. Like
|
|
119
|
+
0.7.2, it reached crates.io and PyPI but published no release archives,
|
|
120
|
+
because the new load check refused to ship a macOS module that would
|
|
121
|
+
not open. Its crate and wheels are sound and identical in content to
|
|
122
|
+
0.7.3.
|
|
38
123
|
|
|
39
124
|
## [v0.7.0] - 2026-08-12
|
|
40
125
|
|
|
@@ -3027,7 +3027,7 @@ dependencies = [
|
|
|
3027
3027
|
|
|
3028
3028
|
[[package]]
|
|
3029
3029
|
name = "python-aaronia"
|
|
3030
|
-
version = "0.7.
|
|
3030
|
+
version = "0.7.4"
|
|
3031
3031
|
dependencies = [
|
|
3032
3032
|
"arrow",
|
|
3033
3033
|
"num-complex",
|
|
@@ -3556,7 +3556,7 @@ checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
|
|
|
3556
3556
|
|
|
3557
3557
|
[[package]]
|
|
3558
3558
|
name = "sdr-aaronia-rs"
|
|
3559
|
-
version = "0.7.
|
|
3559
|
+
version = "0.7.4"
|
|
3560
3560
|
dependencies = [
|
|
3561
3561
|
"anyhow",
|
|
3562
3562
|
"bitflags 2.13.1",
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
name = "sdr-aaronia-rs"
|
|
3
3
|
description = "Unified Rust interface for Aaronia Spectran Spectrum Analyzers / SDRs, featuring Python bindings, a SoapySDR plugin, HTTP streaming, and native SDK support."
|
|
4
4
|
license = "GPL-3.0-or-later"
|
|
5
|
-
version = "0.7.
|
|
5
|
+
version = "0.7.4"
|
|
6
6
|
edition = "2024"
|
|
7
7
|
repository = "https://github.com/isaacbentley/sdr-aaronia-rs"
|
|
8
8
|
readme = "README.md"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: python-aaronia
|
|
3
|
-
Version: 0.7.
|
|
3
|
+
Version: 0.7.4
|
|
4
4
|
Classifier: Programming Language :: Rust
|
|
5
5
|
Classifier: Programming Language :: Python :: Implementation :: CPython
|
|
6
6
|
Classifier: License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)
|
|
@@ -161,6 +161,43 @@ http://localhost:54664/stream?format=int16&scale=1000000
|
|
|
161
161
|
http://localhost:54664/stream?rate_reduction=10
|
|
162
162
|
```
|
|
163
163
|
|
|
164
|
+
### An unknown `format` is not an error
|
|
165
|
+
|
|
166
|
+
`format=` accepts `json`, `int16`, `float16` and `float32`. `raw16` is
|
|
167
|
+
an accepted alias for `int16` — Aaronia's own Qt reference client
|
|
168
|
+
defaults to it — and produces byte-identical framing.
|
|
169
|
+
|
|
170
|
+
Anything the server does not recognise serves **the RTSA file format**
|
|
171
|
+
instead: a `DSFH` header followed by `STRM`/`ANTA` chunks, with HTTP
|
|
172
|
+
200 and no warning. A typo in `format=` therefore yields a completely
|
|
173
|
+
different wire format rather than an error, and a parser expecting
|
|
174
|
+
JSON-plus-binary will fail somewhere well past the point that would
|
|
175
|
+
have identified the cause. Verified against a live server: `format=`
|
|
176
|
+
with a nonsense value returned `DSFH`.
|
|
177
|
+
|
|
178
|
+
This crate builds the string from an enum, so it cannot typo, and the
|
|
179
|
+
SoapySDR plugin now warns on an unrecognised `format=` device argument
|
|
180
|
+
rather than silently falling back to the default.
|
|
181
|
+
|
|
182
|
+
### When the server drops data
|
|
183
|
+
|
|
184
|
+
The HTTP server block starts dropping data once its outbound TCP
|
|
185
|
+
buffer passes **8 MB**. Nothing announces it; the loss shows up as a
|
|
186
|
+
gap between the timestamps of two adjacent packets, which is what
|
|
187
|
+
`DropDetector` watches for. A slow consumer, a slow link, or a rate
|
|
188
|
+
the network cannot carry all end here, so reducing the wire format
|
|
189
|
+
(`format=int16`) or the rate (`rate_reduction=n`) is the fix rather
|
|
190
|
+
than a larger client-side buffer.
|
|
191
|
+
|
|
192
|
+
### Liveness
|
|
193
|
+
|
|
194
|
+
There is no status endpoint. Aaronia's own remote control notes probe
|
|
195
|
+
with `curl -v http://127.0.0.1:54664/api/status` and treat the `404 Not
|
|
196
|
+
Found` as the answer: a reply of any kind proves the port is open, the
|
|
197
|
+
mission is loaded and the HTTP Server block is running. A connection
|
|
198
|
+
refused or a timeout means it is not. `/info` serves the same purpose
|
|
199
|
+
and returns something useful, which is what this crate uses.
|
|
200
|
+
|
|
164
201
|
### Application Process Control
|
|
165
202
|
**URL**: `/app/process`
|
|
166
203
|
**Method**: PUT
|
|
@@ -250,6 +287,42 @@ packet-metadata object, so `payload`, `minPower`, `maxPower`, and
|
|
|
250
287
|
`stepFrequency` (the sample rate) is optional; `push: true` marks the packet for immediate transmission.
|
|
251
288
|
|
|
252
289
|
### Control Endpoint
|
|
290
|
+
|
|
291
|
+
`/control` accepts **PUT only**. A GET — which is what a browser does
|
|
292
|
+
with the URL — is not supported.
|
|
293
|
+
|
|
294
|
+
**A command reaches every block that understands it, unless you scope
|
|
295
|
+
it.** Aaronia's 2022 specification says control commands "are not
|
|
296
|
+
addressed to a specific RTSA block and will be processed from all RTSA
|
|
297
|
+
blocks in the block graph", which is true as a default. Their support
|
|
298
|
+
staff refined it in 2024: `receiverUUID` and `receiverName` "can be
|
|
299
|
+
used to limit the requested setting to individual blocks", and "in some
|
|
300
|
+
cases it may be necessary to specify them". Read the names or UUIDs
|
|
301
|
+
from `/remoteconfig` first if you need to target one block.
|
|
302
|
+
|
|
303
|
+
These are one-off requests. Aaronia's own words: if they cannot be
|
|
304
|
+
executed, or conflict with the local configuration, the behaviour is
|
|
305
|
+
undefined — nothing reports the conflict.
|
|
306
|
+
|
|
307
|
+
**The settings each `type` accepts**, per Aaronia support (January
|
|
308
|
+
2024), which goes well beyond the published specification:
|
|
309
|
+
|
|
310
|
+
| `type` | Settings |
|
|
311
|
+
| :--- | :--- |
|
|
312
|
+
| `capture` | `receiverUUID`, `receiverName`, `frequencyCenter`, `frequencyStart`, `frequencyBins`, `referenceLevel`, `start` — plus `frequencySpan` and `frequencyEnd`, which the specification documents and this crate uses |
|
|
313
|
+
| `deviceconnect` | `receiverUUID`, `receiverName`, `start` — connect or disconnect a device |
|
|
314
|
+
| `streaming` | `receiverUUID`, `receiverName`, `filename`, `start` |
|
|
315
|
+
| `recording` | `receiverUUID`, `receiverName`, `filename`, `start` |
|
|
316
|
+
| `mission` | `save`, `reload`, `load` (with the path in `file`) |
|
|
317
|
+
| `antenna` | `receiverUUID`, `receiverName`, `latitude`+`longitude` (both or neither), `azimuth`+`declination`, `rotate` |
|
|
318
|
+
| `camera` | `receiverUUID`, `receiverName`, `latitude`+`longitude`, `azimuth`+`declination`, `aperture`, `channel`, `altitude`, `start` |
|
|
319
|
+
|
|
320
|
+
`start`, `rotate`, `save`, `load` and `reload` are booleans. A
|
|
321
|
+
`filename` must be an absolute path **on the machine running
|
|
322
|
+
RTSA-Suite**, with forward slashes.
|
|
323
|
+
|
|
324
|
+
Zones cannot be configured this way; Aaronia state that remote
|
|
325
|
+
configuration of zones is not supported.
|
|
253
326
|
**URL**: `/control`
|
|
254
327
|
**Method**: PUT
|
|
255
328
|
**Description**: Send commands to the RTSA suite
|
|
@@ -320,7 +393,7 @@ packet-metadata object, so `payload`, `minPower`, `maxPower`, and
|
|
|
320
393
|
}
|
|
321
394
|
```
|
|
322
395
|
|
|
323
|
-
#### Save/Reload Mission
|
|
396
|
+
#### Save/Reload/Load Mission
|
|
324
397
|
```json
|
|
325
398
|
{
|
|
326
399
|
"save": true,
|
|
@@ -328,6 +401,28 @@ packet-metadata object, so `payload`, `minPower`, `maxPower`, and
|
|
|
328
401
|
}
|
|
329
402
|
```
|
|
330
403
|
|
|
404
|
+
A mission can also be swapped outright, which is how a headless station
|
|
405
|
+
changes what it is running. `load` takes an absolute path to an `.rmix`
|
|
406
|
+
on the machine running RTSA-Suite, not on the client:
|
|
407
|
+
```json
|
|
408
|
+
{
|
|
409
|
+
"type": "mission",
|
|
410
|
+
"load": true,
|
|
411
|
+
"file": "C:/Aaronia/Recordings/HTTP streaming/http_test.rmix"
|
|
412
|
+
}
|
|
413
|
+
```
|
|
414
|
+
A mission carrying an HTTP Server block must already be running, or
|
|
415
|
+
there is nothing listening to accept the request. Aaronia's remote
|
|
416
|
+
control notes (rev 4, May 2026) give this as a `curl` invocation from
|
|
417
|
+
an elevated prompt. This crate does not expose it: swapping the mission
|
|
418
|
+
out from under a running capture is the caller's decision to make
|
|
419
|
+
deliberately, not a side effect of a library call.
|
|
420
|
+
|
|
421
|
+
**Every `/control` payload needs its `type`.** A body without one is
|
|
422
|
+
rejected with `400` and the text `Type argument missing`, so a
|
|
423
|
+
hand-built payload that omits it fails loudly rather than silently —
|
|
424
|
+
unlike a partial capture request, which is accepted and ignored.
|
|
425
|
+
|
|
331
426
|
### Configuration Endpoints
|
|
332
427
|
|
|
333
428
|
#### Server Info (`/info`)
|
|
@@ -430,8 +525,18 @@ Notes verified against a live V6 ECO:
|
|
|
430
525
|
and `frequencySpan` are both present.
|
|
431
526
|
- **The `receiverName` key is case-tolerant.** `receivername` was accepted
|
|
432
527
|
identically.
|
|
433
|
-
- Enum-valued settings
|
|
434
|
-
`decimation` as `"1 / 128"
|
|
528
|
+
- **Enum-valued settings take either the label string or the index.**
|
|
529
|
+
Aaronia's example writes `decimation` as `"1 / 128"`; writing
|
|
530
|
+
`decimation0` as the integer `3` was accepted and applied identically
|
|
531
|
+
(verified against `/sample`: index 3 gave 7.68 MHz, index 2 gave
|
|
532
|
+
15.36 MHz). Indices are positions in the `values` list that
|
|
533
|
+
`GET /remoteconfig` reports for that item.
|
|
534
|
+
- **Groups other than `main` work**, and several can go in one PUT:
|
|
535
|
+
`{"main": {...}, "calibration": {"preamp": 1}}` applied both.
|
|
536
|
+
- **An unknown block name is a silent no-op.** A `simpleconfig` PUT
|
|
537
|
+
naming a block that is not in the mission returns HTTP 200 and changes
|
|
538
|
+
nothing. There is no error to catch, so read the value back if it
|
|
539
|
+
matters.
|
|
435
540
|
- Other keys the example writes: `run` (bool), `preamp` (`"Auto"`),
|
|
436
541
|
`reflevel` (float), and `filerecord` (bool) plus a filename template on
|
|
437
542
|
a FileWriter block, which is how it starts and stops recording.
|
|
@@ -445,7 +550,15 @@ Notes verified against a live V6 ECO:
|
|
|
445
550
|
}
|
|
446
551
|
}
|
|
447
552
|
```
|
|
448
|
-
`receiverName` must match a block in the running mission;
|
|
553
|
+
`receiverName` must match a block in the running mission;
|
|
554
|
+
`HttpEndpointsClient::find_iq_demodulator_block_name` auto-discovers it.
|
|
555
|
+
A name that matches nothing still returns 200 (see above).
|
|
556
|
+
|
|
557
|
+
In the full `{request, config}` form the receiver name is ignored
|
|
558
|
+
altogether: the write is routed by `config.name`. Sending
|
|
559
|
+
`receivername`, `receiverName` or no name at all applied the same
|
|
560
|
+
change. Nothing depends on getting that key right, and nothing warns
|
|
561
|
+
when it is wrong.
|
|
449
562
|
|
|
450
563
|
**Configuration Item Fields**:
|
|
451
564
|
| Field | Description |
|
|
@@ -469,6 +582,28 @@ configuration tree (`HealthStatus` is an alias for `ConfigItem`) rather
|
|
|
469
582
|
than the typed shape below, which describes the upstream block-health
|
|
470
583
|
fields.
|
|
471
584
|
|
|
585
|
+
**Subgroups** per health-aware block, per Aaronia's specification:
|
|
586
|
+
`info`, `status`, `health`, `settings`, and `components` — the last a
|
|
587
|
+
recursive list of sub-blocks when satellites are attached over HTTP,
|
|
588
|
+
which is how a remote station's devices show up in a local tree.
|
|
589
|
+
|
|
590
|
+
**What a V6 ECO actually reports** under `status` and `health`,
|
|
591
|
+
alongside the `info` fields below:
|
|
592
|
+
|
|
593
|
+
| Item | Example | Meaning |
|
|
594
|
+
| :--- | :--- | :--- |
|
|
595
|
+
| `status/iqsamples` | 61439323 | **Native** IQ rate in Hz, not the delivered one. Measured constant at 61.44 MHz while the same device delivered 15.36, then 7.68, then 61.44 MS/s — it does not follow the decimation setting |
|
|
596
|
+
| `status/usbbuffer` | 0.0625 | USB buffer fill, fraction |
|
|
597
|
+
| `status/adcrange` | 17.16 | ADC headroom in dB |
|
|
598
|
+
| `status/strmtimedist` | 5.96e-06 | Stream time distance in seconds |
|
|
599
|
+
| `health/fronttemp` | 64.7 | Frontend temperature, °C |
|
|
600
|
+
| `health/fpgatemp` | 52.5 | FPGA temperature, °C |
|
|
601
|
+
| `health/boardpower` | 8.975 | Board power draw, W |
|
|
602
|
+
|
|
603
|
+
`iqsamples` is the one to be careful with: it looks like a sample rate
|
|
604
|
+
and is not the one your stream is running at. Read `sampleFrequency`
|
|
605
|
+
from packet metadata for that.
|
|
606
|
+
|
|
472
607
|
**Health Status Fields**:
|
|
473
608
|
| Field | Description |
|
|
474
609
|
| :--- | :--- |
|
|
@@ -577,7 +712,35 @@ The samples in a category ordered packet have one measurement per category.
|
|
|
577
712
|
}
|
|
578
713
|
```
|
|
579
714
|
|
|
580
|
-
As with histograms, category samples are a flat number array (one value
|
|
715
|
+
As with histograms, category samples are a flat number array (one value
|
|
716
|
+
per category) — that is what a live server produced.
|
|
717
|
+
|
|
718
|
+
**A marker stream is not a categories packet.** Aaronia's remote
|
|
719
|
+
control notes show the Spectrum block's `Marker` output wired to an
|
|
720
|
+
HTTP Server, and the result looks like this:
|
|
721
|
+
|
|
722
|
+
```json
|
|
723
|
+
{
|
|
724
|
+
"payload": "spectra",
|
|
725
|
+
"startFrequency": 0, "endFrequency": 0, "sampleFrequency": 0,
|
|
726
|
+
"sampleSize": 4, "sampleDepth": 1,
|
|
727
|
+
"categories": [
|
|
728
|
+
{ "name": "Slow Sine(R)", "startFrequency": 2403000000, "endFrequency": 2405000000 },
|
|
729
|
+
{ "name": "Marker", "startFrequency": 2412852325.3, "endFrequency": 2412852335.3 }
|
|
730
|
+
],
|
|
731
|
+
"samples": [[-78.6, -57.26, -47.28, -114.25]]
|
|
732
|
+
}
|
|
733
|
+
```
|
|
734
|
+
|
|
735
|
+
It carries a `categories` array but declares `payload: "spectra"`, and
|
|
736
|
+
spectra samples are a 2D array — one row per frame — so the nesting is
|
|
737
|
+
correct for what it says it is, not a contradiction of the flat
|
|
738
|
+
categories form above. `sampleSize` is the number of values in a row,
|
|
739
|
+
here one per category.
|
|
740
|
+
|
|
741
|
+
What is worth knowing before parsing one: all three frequency fields
|
|
742
|
+
are `0`, so nothing can be derived from them, and the category names
|
|
743
|
+
and ranges are the only description of what the numbers mean.
|
|
581
744
|
|
|
582
745
|
### Antenna Data
|
|
583
746
|
Data captured using antennas with location or directional information.
|
|
@@ -614,7 +777,44 @@ and `Location and Time`; `sclksource` offers `Consumer`, `Oscillator`,
|
|
|
614
777
|
|
|
615
778
|
`decimation0` takes the same labels as the SDK's `main/decimation`,
|
|
616
779
|
`"Full"` through `"1 / 512"`, verified by writing one over HTTP. Both
|
|
617
|
-
transports drive the same divider.
|
|
780
|
+
transports drive the same divider. Over HTTP the index works as well as
|
|
781
|
+
the label: writing `3` and reading `/sample` back gave 7.68 MHz, and `2`
|
|
782
|
+
gave 15.36 MHz, which is 61.44 MHz halved that many times on a V6 ECO.
|
|
783
|
+
|
|
784
|
+
#### Unresolved: the full V6's top rate
|
|
785
|
+
|
|
786
|
+
The SDK constrains `spanfreq * 1.5 <= receiverclock`, and a V6 ECO
|
|
787
|
+
follows it: its top IQ rate measures 61.44 MHz against the 92.16 MHz
|
|
788
|
+
clock the crate assumes for it. `iq_sample_rates_for_clock` takes that
|
|
789
|
+
ratio as the rule, so it puts a full V6 on the `245MHz` clock at
|
|
790
|
+
163.84 MHz.
|
|
791
|
+
|
|
792
|
+
Aaronia's own figures do not agree. Their endpoint specification closes
|
|
793
|
+
with a note about achieving "the full 250M samples of IQ data", their
|
|
794
|
+
block documentation advertises "a real-time bandwidth of up to 245MHz
|
|
795
|
+
each" for the V6's two inputs, and both round to the 245.76 MHz that
|
|
796
|
+
the `245MHz` clock label denotes — the clock itself, not two thirds of
|
|
797
|
+
it.
|
|
798
|
+
|
|
799
|
+
There is a reading that reconciles them. The clock list runs past
|
|
800
|
+
`245MHz` to `492MHz` (491.52 MHz), and 245.76 MHz of span satisfies the
|
|
801
|
+
1.5 rule against that clock with room to spare. On that reading 245 MHz
|
|
802
|
+
of real-time bandwidth is real but needs the fastest clock, and the
|
|
803
|
+
`245MHz` label tops out at 163.84 MHz exactly as the crate computes.
|
|
804
|
+
|
|
805
|
+
What does not fit either reading is the Remote Config panel Aaronia
|
|
806
|
+
published in 2021 and again in 2022: a full V6 with the clock set to
|
|
807
|
+
`92MHz` reporting roughly 92.16 MHz of IQ samples per second. That
|
|
808
|
+
counter is not the delivered rate — measured on an ECO, `iqsamples`
|
|
809
|
+
held at 61.44 MHz while the device was actually delivering 15.36 and
|
|
810
|
+
then 7.68 MHz, so it reports the native undecimated rate. Taken at face
|
|
811
|
+
value it says a full V6 at a 92 MHz clock has a native rate of
|
|
812
|
+
92.16 MHz, which the 1.5 rule forbids.
|
|
813
|
+
|
|
814
|
+
No full V6 has been available to measure, so this stays open. The
|
|
815
|
+
practical guidance is unchanged: the ECO path is verified rung by rung,
|
|
816
|
+
and for anything else read the rate the device reports in its stream
|
|
817
|
+
metadata rather than trusting a computed ladder.
|
|
618
818
|
|
|
619
819
|
### Two things that do not carry over
|
|
620
820
|
|
|
@@ -638,6 +838,20 @@ transports drive the same divider.
|
|
|
638
838
|
- `/info` - Device information
|
|
639
839
|
- `/healthstatus` - Device health monitoring
|
|
640
840
|
|
|
841
|
+
**HTTP Server and Client blocks are themselves licensed, and the free
|
|
842
|
+
tier is one of each.** Aaronia's staff put it plainly in the HTTP
|
|
843
|
+
Server thread: only one HTTP Server instance is included in the free
|
|
844
|
+
RTSA-Suite PRO licence and additional instances must be licensed
|
|
845
|
+
separately, the same going for the HTTP Client, where only one
|
|
846
|
+
connection is free. Stream Merger and Stream Splitter, the blocks that
|
|
847
|
+
would otherwise let several streams share one connection, are not in
|
|
848
|
+
the free licence either.
|
|
849
|
+
|
|
850
|
+
This is the licence limit most likely to be met in practice: running
|
|
851
|
+
this crate and a second client — a SoapySDR application, say — against
|
|
852
|
+
one server at the same time is a second connection. It has nothing to
|
|
853
|
+
do with the Remote Config licence discussed below.
|
|
854
|
+
|
|
641
855
|
**Remote Configuration** (`/remoteconfig`):
|
|
642
856
|
- Device parameter configuration.
|
|
643
857
|
- Aaronia sells a "Remote Config" license, and this document previously
|
|
@@ -655,10 +869,17 @@ transports drive the same divider.
|
|
|
655
869
|
and may be what actually matters.
|
|
656
870
|
- This crate does not depend on the answer: it tunes through `/control`,
|
|
657
871
|
which needs no license.
|
|
872
|
+
- Re-confirmed 2026-08-12 against RTSA-Suite PRO and a V6 ECO on the
|
|
873
|
+
same unlicensed system, in both payload forms, for `centerfreq0`,
|
|
874
|
+
`decimation0`, `reflevel0` and `calibration/preamp`.
|
|
658
875
|
|
|
659
876
|
**License Detection Methods**:
|
|
660
877
|
|
|
661
|
-
**Important**:
|
|
878
|
+
**Important**: reads of `/remoteconfig` are license-free, so a read-only
|
|
879
|
+
check cannot prove write capability either way — only a write test can.
|
|
880
|
+
It cannot prove the *license* either: writes succeeded on an unlicensed
|
|
881
|
+
system (see above), so a successful probe means "this server accepts
|
|
882
|
+
writes", not "this server is licensed".
|
|
662
883
|
|
|
663
884
|
The client therefore exposes two methods:
|
|
664
885
|
|
|
@@ -793,8 +1014,10 @@ fn parse_iq_int16(data: &[u8], metadata_scale: f32) -> Vec<Complex32> {
|
|
|
793
1014
|
|---------|------|---------|
|
|
794
1015
|
| 1.0 | 2025-01-11 | Initial HTTP specification from original documentation |
|
|
795
1016
|
| 2.0 | 2025-01-11 | Enhanced with comprehensive streaming protocol specification and implementation guidelines |
|
|
1017
|
+
| 2.4 | 2026-08-12 | Added Aaronia support's full `/control` settings list (`deviceconnect`, `camera`, per-type fields, `receiverUUID`/`receiverName` scoping), which supersedes the specification's claim that commands cannot be addressed to a block; documented that an unrecognised `format=` silently serves the RTSA file format and that `raw16` aliases `int16`, both verified live |
|
|
1018
|
+
| 2.3 | 2026-08-12 | Folded in Aaronia's endpoint specification (rev 11) and the block forum threads: `/control` broadcasts to every block and is PUT-only, the server drops data past an 8 MB outbound buffer, `/healthstatus` subgroups and the fields a V6 ECO reports, and the one-server/one-client free-licence limit. Measured that `status/iqsamples` is the native rate, not the delivered one. Corrected the marker-stream entry: it declares `payload: "spectra"`, so its nested samples are the spectra form and not a counter-example to flat categories |
|
|
1019
|
+
| 2.2 | 2026-08-12 | Verified Aaronia's V6 remote control notes (rev 4) against hardware: enum writes by index, multi-group and non-`main` `simpleconfig` PUTs, the silent no-op on an unknown block name, the ignored receiver name in the config-tree form; documented mission loading and the `type` requirement on `/control`, the absence of a status endpoint, and the unresolved conflict over what "Full" means on a full V6; resolved a contradiction over what the Remote Config licence gates |
|
|
796
1020
|
| 2.1 | 2026-08-06 | Live-hardware corrections folded in (two-byte separator, spectra frame counting, `scale` inversion); documented `/samples`, the `/sample` TX push, and the `simpleconfig` PUT form; corrected `limit` semantics, field types, and flat histogram/categories sample arrays; removed decorative icons |
|
|
797
|
-
|
|
798
1021
|
---
|
|
799
1022
|
|
|
800
1023
|
## Sources and Attribution
|
|
@@ -52,9 +52,9 @@ The Aaronia RTSA Vendor SDK provides low-level, high-performance access to Aaron
|
|
|
52
52
|
* **SpectranV6 ECO**: `spectranv6eco/raw`, `spectranv6eco/iqreceiver`, `spectranv6eco/iqtransceiver`, `spectranv6eco/iqtransmitter`, `spectranv6eco/sweepsa`
|
|
53
53
|
* **Configuration Tree**: Hierarchical configuration system with verified parameters:
|
|
54
54
|
* **Clock Rates** (V6): 46MHz (46.08), 61MHz (61.44), 76MHz (76.80), 92MHz (92.16), 122MHz (122.88), 184MHz (184.32), 245MHz (245.76), 492MHz (491.52) — see the full label table under [Rust Binding Notes](#rust-binding-notes)
|
|
55
|
-
* **Clock Rates** (V6 ECO):
|
|
55
|
+
* **Clock Rates** (V6 ECO): fixed at 92.16 MHz. Its top IQ rate is 61.44 MHz, which is that clock over 1.5 — the two are easy to confuse and this document once recorded the rate as the clock
|
|
56
56
|
* **Decimation**: Full, 1/2, 1/4, 1/8, 1/16, 1/32, 1/64, 1/128, 1/256, 1/512
|
|
57
|
-
* **IQ Mode Sample Rate**: equal to `spanfreq` (constraint: `spanfreq ≤ receiverclock / 1.5`)
|
|
57
|
+
* **IQ Mode Sample Rate**: equal to `spanfreq` (constraint: `spanfreq ≤ receiverclock / 1.5`). Measured on a V6 ECO, untested on a full V6, and not obviously consistent with Aaronia's own 245 MHz / 250 Msample figures for the V6 — see [HTTPSPEC](HTTPSPEC.md#unresolved-the-full-v6s-top-rate)
|
|
58
58
|
* **Health Monitoring**: Real-time device status including temperatures, sample rates, power levels, USB statistics, GPS data
|
|
59
59
|
|
|
60
60
|
The SDK is designed for building custom spectrum analysis applications, SDR integration, and specialized RF measurement tools.
|
|
@@ -256,8 +256,8 @@ source.open_device("spectranv6/raw", &serial_wide)?;
|
|
|
256
256
|
`NativeSdkSource::configure_iq_receiver` calls
|
|
257
257
|
`utils::validate_iq_mode(span, clock)` after applying the config,
|
|
258
258
|
where `clock` is read live from `device/receiverclock` via
|
|
259
|
-
`AARTSAAPI_ConfigGetString` (or
|
|
260
|
-
such key and run at a fixed clock). The check enforces
|
|
259
|
+
`AARTSAAPI_ConfigGetString` (or `DEFAULT_RECEIVER_CLOCK_HZ`, 92.16 MHz,
|
|
260
|
+
on eco devices, which expose no such key and run at a fixed clock). The check enforces
|
|
261
261
|
`span * 1.5 <= clock` and returns a typed error before the device starts.
|
|
262
262
|
|
|
263
263
|
The ConfigItem labels the SDK exposes are *rounded* — `"92MHz"` is
|
|
@@ -911,8 +911,12 @@ reads a single stream and deinterleaves it, so it writes `Rx12`.
|
|
|
911
911
|
| Raw-mode open string | `spectranv6/raw` | `spectranv6eco/rtsa` |
|
|
912
912
|
|
|
913
913
|
The clock matters beyond configuration: with `span * 1.5 <=
|
|
914
|
-
receiverclock`, a V6 on the
|
|
915
|
-
where the ECO's fixed clock allows 61.44 MHz.
|
|
914
|
+
receiverclock`, a V6 on the `245MHz` clock reaches roughly 163 MHz of
|
|
915
|
+
span where the ECO's fixed clock allows 61.44 MHz. Aaronia advertise
|
|
916
|
+
245 MHz of real-time bandwidth per input, which under this rule would
|
|
917
|
+
need the `492MHz` clock; see
|
|
918
|
+
[HTTPSPEC](HTTPSPEC.md#unresolved-the-full-v6s-top-rate) for why that
|
|
919
|
+
is not settled.
|
|
916
920
|
|
|
917
921
|
### Sample rates
|
|
918
922
|
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
class SoapyAaronia < Formula
|
|
13
13
|
desc "SoapySDR plugin for Aaronia SPECTRAN V6 spectrum analyzers"
|
|
14
14
|
homepage "https://github.com/isaacbentley/sdr-aaronia-rs"
|
|
15
|
-
version "0.7.
|
|
15
|
+
version "0.7.4"
|
|
16
16
|
license "GPL-3.0-or-later"
|
|
17
17
|
|
|
18
18
|
# Prebuilt modules: the plugin statically links its Rust core, so there
|
|
@@ -111,8 +111,22 @@ static SoapySDR::Device *makeAaronia(const SoapySDR::Kwargs &args) {
|
|
|
111
111
|
}
|
|
112
112
|
// format=I16 enables the genuine low-bandwidth HTTP wire mode
|
|
113
113
|
// (int16 from the server), optionally with scale=N.
|
|
114
|
+
//
|
|
115
|
+
// Checked here rather than left to the C API, which ignores a value
|
|
116
|
+
// it does not recognise and returns nothing to say so. A typo would
|
|
117
|
+
// otherwise stream the default format while the device string
|
|
118
|
+
// claims something else — and the server is no help either: it
|
|
119
|
+
// answers an unknown `format=` with the RTSA file format rather
|
|
120
|
+
// than an error.
|
|
114
121
|
if (args.count("format") != 0) {
|
|
115
|
-
|
|
122
|
+
const std::string &fmt = args.at("format");
|
|
123
|
+
if (fmt != "F32" && fmt != "F16" && fmt != "I16") {
|
|
124
|
+
SoapySDR::logf(SOAPY_SDR_WARNING,
|
|
125
|
+
"aaronia: ignoring format=%s; expected F32, F16 or I16",
|
|
126
|
+
fmt.c_str());
|
|
127
|
+
} else {
|
|
128
|
+
aaronia_source_builder_stream_format(builder, fmt.c_str());
|
|
129
|
+
}
|
|
116
130
|
}
|
|
117
131
|
if (args.count("scale") != 0) {
|
|
118
132
|
aaronia_source_builder_stream_scale(builder, parseArgDouble(args, "scale"));
|
|
@@ -838,7 +838,21 @@ impl HttpEndpointsClient {
|
|
|
838
838
|
/// `main` is the typical group, but any subset of the block's
|
|
839
839
|
/// configuration tree may be passed via `config_groups`. Keys are
|
|
840
840
|
/// group names ("main", "device", "calibration"); values are field
|
|
841
|
-
/// → `serde_json::Value` maps.
|
|
841
|
+
/// → `serde_json::Value` maps. Several groups in one call are
|
|
842
|
+
/// applied together.
|
|
843
|
+
///
|
|
844
|
+
/// Enum fields take either the label the device reports or its
|
|
845
|
+
/// index in that item's `values` list.
|
|
846
|
+
///
|
|
847
|
+
/// **A wrong `receiver_name` is silently accepted.** Naming a block
|
|
848
|
+
/// that is not in the running mission returns HTTP 200 and changes
|
|
849
|
+
/// nothing, so this returns `Ok(())` for a write that did not
|
|
850
|
+
/// happen. The server offers nothing to check against, so resolve
|
|
851
|
+
/// the name once from [`Self::get_config`] (or
|
|
852
|
+
/// [`Self::find_iq_demodulator_block_name`]) when the session
|
|
853
|
+
/// starts, rather than hard-coding a block name and trusting the
|
|
854
|
+
/// status code. Read the value back afterwards when a write has to
|
|
855
|
+
/// be certain.
|
|
842
856
|
pub async fn simple_remote_config(
|
|
843
857
|
&self,
|
|
844
858
|
receiver_name: &str,
|
|
@@ -333,8 +333,18 @@ pub fn iq_sample_rates() -> [f64; 10] {
|
|
|
333
333
|
/// [`DEFAULT_RECEIVER_CLOCK_HZ`], verified rung by rung. A full V6 can
|
|
334
334
|
/// select other clocks — Aaronia's own samples use `"92MHz"` and
|
|
335
335
|
/// `"245MHz"` — and the rates there follow the same constraint but have
|
|
336
|
-
/// not been confirmed against hardware.
|
|
337
|
-
///
|
|
336
|
+
/// not been confirmed against hardware.
|
|
337
|
+
///
|
|
338
|
+
/// **The 1.5 may be wrong for a full V6.** Aaronia advertise 245 MHz of
|
|
339
|
+
/// real-time bandwidth per input and "the full 250M samples of IQ
|
|
340
|
+
/// data", which is the `245MHz` clock label itself rather than the
|
|
341
|
+
/// 163.84 MHz this returns for it. That may simply mean the fastest
|
|
342
|
+
/// rate needs the `492MHz` clock, where 245.76 MHz of span does
|
|
343
|
+
/// satisfy the 1.5 rule; a published Remote Config panel showing a
|
|
344
|
+
/// full V6 at a `92MHz` clock with a 92.16 MHz native rate fits
|
|
345
|
+
/// neither reading. Until one can be measured, treat this as the ECO's
|
|
346
|
+
/// ladder and prefer the rate a device reports in its stream metadata
|
|
347
|
+
/// over the one computed here.
|
|
338
348
|
pub fn iq_sample_rates_for_clock(receiver_clock_hz: f64) -> [f64; 10] {
|
|
339
349
|
let top = receiver_clock_hz / 1.5;
|
|
340
350
|
let mut rates = [0.0; 10];
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{python_aaronia-0.7.2 → python_aaronia-0.7.4}/soapy-aaronia/build-test/CMakeFiles/Makefile.cmake
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{python_aaronia-0.7.2 → python_aaronia-0.7.4}/soapy-aaronia/build-test/CMakeFiles/cmake.check_cache
RENAMED
|
File without changes
|
{python_aaronia-0.7.2 → python_aaronia-0.7.4}/soapy-aaronia/build-test/CMakeFiles/progress.marks
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|