python-aaronia 0.6.2__tar.gz → 0.7.1__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.6.2 → python_aaronia-0.7.1}/CHANGELOG.md +67 -0
- {python_aaronia-0.6.2 → python_aaronia-0.7.1}/Cargo.lock +2 -2
- {python_aaronia-0.6.2 → python_aaronia-0.7.1}/Cargo.toml +1 -1
- {python_aaronia-0.6.2 → python_aaronia-0.7.1}/PKG-INFO +56 -13
- {python_aaronia-0.6.2 → python_aaronia-0.7.1}/README.md +6 -10
- {python_aaronia-0.6.2 → python_aaronia-0.7.1}/docs/APPS.md +13 -8
- {python_aaronia-0.6.2 → python_aaronia-0.7.1}/docs/QUICKSTART.md +20 -11
- python_aaronia-0.7.1/packaging/homebrew/README.md +43 -0
- python_aaronia-0.7.1/packaging/homebrew/soapy-aaronia.rb +47 -0
- {python_aaronia-0.6.2 → python_aaronia-0.7.1}/pyproject.toml +5 -0
- {python_aaronia-0.6.2 → python_aaronia-0.7.1}/python-aaronia/Cargo.toml +1 -1
- {python_aaronia-0.6.2 → python_aaronia-0.7.1}/python-aaronia/README.md +55 -12
- {python_aaronia-0.6.2 → python_aaronia-0.7.1}/python-aaronia/aaronia.pyi +69 -1
- {python_aaronia-0.6.2 → python_aaronia-0.7.1}/python-aaronia/src/lib.rs +377 -0
- python_aaronia-0.7.1/python-aaronia/test_basic.py +143 -0
- {python_aaronia-0.6.2 → python_aaronia-0.7.1}/soapy-aaronia/CMakeLists.txt +28 -0
- {python_aaronia-0.6.2 → python_aaronia-0.7.1}/soapy-aaronia/README.md +20 -13
- python_aaronia-0.7.1/soapy-aaronia/build-test/CMakeCache.txt +439 -0
- python_aaronia-0.7.1/soapy-aaronia/build-test/CMakeFiles/4.4.2/CMakeCXXCompiler.cmake +103 -0
- python_aaronia-0.7.1/soapy-aaronia/build-test/CMakeFiles/4.4.2/CMakeDetermineCompilerABI_CXX.bin +0 -0
- python_aaronia-0.7.1/soapy-aaronia/build-test/CMakeFiles/4.4.2/CMakeSystem.cmake +15 -0
- python_aaronia-0.7.1/soapy-aaronia/build-test/CMakeFiles/4.4.2/CompilerIdCXX/CMakeCXXCompilerId.cpp +954 -0
- python_aaronia-0.7.1/soapy-aaronia/build-test/CMakeFiles/4.4.2/CompilerIdCXX/a.out +0 -0
- python_aaronia-0.7.1/soapy-aaronia/build-test/CMakeFiles/4.4.2/CompilerIdCXX/apple-sdk.cpp +1 -0
- python_aaronia-0.7.1/soapy-aaronia/build-test/CMakeFiles/CMakeConfigureLog.yaml +1904 -0
- python_aaronia-0.7.1/soapy-aaronia/build-test/CMakeFiles/CMakeDirectoryInformation.cmake +16 -0
- python_aaronia-0.7.1/soapy-aaronia/build-test/CMakeFiles/CMakeRuleHashes.txt +3 -0
- python_aaronia-0.7.1/soapy-aaronia/build-test/CMakeFiles/InstallScripts.json +7 -0
- python_aaronia-0.7.1/soapy-aaronia/build-test/CMakeFiles/Makefile.cmake +61 -0
- python_aaronia-0.7.1/soapy-aaronia/build-test/CMakeFiles/Makefile2 +157 -0
- python_aaronia-0.7.1/soapy-aaronia/build-test/CMakeFiles/TargetDirectories.txt +8 -0
- python_aaronia-0.7.1/soapy-aaronia/build-test/CMakeFiles/aaroniaSupport.dir/DependInfo.cmake +24 -0
- python_aaronia-0.7.1/soapy-aaronia/build-test/CMakeFiles/aaroniaSupport.dir/build.make +131 -0
- python_aaronia-0.7.1/soapy-aaronia/build-test/CMakeFiles/aaroniaSupport.dir/cmake_clean.cmake +13 -0
- python_aaronia-0.7.1/soapy-aaronia/build-test/CMakeFiles/aaroniaSupport.dir/compiler_depend.make +2 -0
- python_aaronia-0.7.1/soapy-aaronia/build-test/CMakeFiles/aaroniaSupport.dir/compiler_depend.ts +2 -0
- python_aaronia-0.7.1/soapy-aaronia/build-test/CMakeFiles/aaroniaSupport.dir/depend.make +2 -0
- python_aaronia-0.7.1/soapy-aaronia/build-test/CMakeFiles/aaroniaSupport.dir/flags.make +12 -0
- python_aaronia-0.7.1/soapy-aaronia/build-test/CMakeFiles/aaroniaSupport.dir/link.txt +1 -0
- python_aaronia-0.7.1/soapy-aaronia/build-test/CMakeFiles/aaroniaSupport.dir/progress.make +4 -0
- python_aaronia-0.7.1/soapy-aaronia/build-test/CMakeFiles/cmake.check_cache +1 -0
- python_aaronia-0.7.1/soapy-aaronia/build-test/CMakeFiles/progress.marks +1 -0
- python_aaronia-0.7.1/soapy-aaronia/build-test/CMakeFiles/sdr_aaronia_rs_static.dir/DependInfo.cmake +22 -0
- python_aaronia-0.7.1/soapy-aaronia/build-test/CMakeFiles/sdr_aaronia_rs_static.dir/build.make +94 -0
- python_aaronia-0.7.1/soapy-aaronia/build-test/CMakeFiles/sdr_aaronia_rs_static.dir/cmake_clean.cmake +9 -0
- python_aaronia-0.7.1/soapy-aaronia/build-test/CMakeFiles/sdr_aaronia_rs_static.dir/compiler_depend.make +2 -0
- python_aaronia-0.7.1/soapy-aaronia/build-test/CMakeFiles/sdr_aaronia_rs_static.dir/compiler_depend.ts +2 -0
- python_aaronia-0.7.1/soapy-aaronia/build-test/CMakeFiles/sdr_aaronia_rs_static.dir/progress.make +2 -0
- python_aaronia-0.7.1/soapy-aaronia/build-test/Makefile +271 -0
- python_aaronia-0.7.1/soapy-aaronia/build-test/cmake_install.cmake +78 -0
- python_aaronia-0.7.1/soapy-aaronia/packaging/install.ps1 +60 -0
- python_aaronia-0.7.1/soapy-aaronia/packaging/install.sh +74 -0
- python_aaronia-0.7.1/soapy-aaronia/print.cmake +1 -0
- {python_aaronia-0.6.2 → python_aaronia-0.7.1}/src/error.rs +10 -0
- {python_aaronia-0.6.2 → python_aaronia-0.7.1}/src/http_source.rs +6 -2
- {python_aaronia-0.6.2 → python_aaronia-0.7.1}/src/unified_source.rs +2 -2
- python_aaronia-0.7.1/test.cmake +1 -0
- {python_aaronia-0.6.2 → python_aaronia-0.7.1}/tests/http_resilience_test.rs +3 -3
- python_aaronia-0.6.2/python-aaronia/test_basic.py +0 -54
- {python_aaronia-0.6.2 → python_aaronia-0.7.1}/.cargo/config.toml +0 -0
- {python_aaronia-0.6.2 → python_aaronia-0.7.1}/.gitattributes +0 -0
- {python_aaronia-0.6.2 → python_aaronia-0.7.1}/.gitignore +0 -0
- {python_aaronia-0.6.2 → python_aaronia-0.7.1}/CONTRIBUTING.md +0 -0
- {python_aaronia-0.6.2 → python_aaronia-0.7.1}/DESIGN.md +0 -0
- {python_aaronia-0.6.2 → python_aaronia-0.7.1}/LICENSE +0 -0
- {python_aaronia-0.6.2 → python_aaronia-0.7.1}/PLUGINS.md +0 -0
- {python_aaronia-0.6.2 → python_aaronia-0.7.1}/benches/decompress_block.rs +0 -0
- {python_aaronia-0.6.2 → python_aaronia-0.7.1}/benches/deinterleave_dual_iq.rs +0 -0
- {python_aaronia-0.6.2 → python_aaronia-0.7.1}/benches/parse_int16_packet.rs +0 -0
- {python_aaronia-0.6.2 → python_aaronia-0.7.1}/benches/rtsa_open_and_read.rs +0 -0
- {python_aaronia-0.6.2 → python_aaronia-0.7.1}/deny.toml +0 -0
- {python_aaronia-0.6.2 → python_aaronia-0.7.1}/docs/FILESPEC.md +0 -0
- {python_aaronia-0.6.2 → python_aaronia-0.7.1}/docs/HTTPSPEC.md +0 -0
- {python_aaronia-0.6.2 → python_aaronia-0.7.1}/docs/SDKSPEC.md +0 -0
- {python_aaronia-0.6.2 → python_aaronia-0.7.1}/docs/USAGE.md +0 -0
- {python_aaronia-0.6.2 → python_aaronia-0.7.1}/docs/VERIFICATION.md +0 -0
- {python_aaronia-0.6.2 → python_aaronia-0.7.1}/examples/channel_hopping.rs +0 -0
- {python_aaronia-0.6.2 → python_aaronia-0.7.1}/examples/device_control.rs +0 -0
- {python_aaronia-0.6.2 → python_aaronia-0.7.1}/examples/dump_metadata.rs +0 -0
- {python_aaronia-0.6.2 → python_aaronia-0.7.1}/examples/http_iq_quickstart.rs +0 -0
- {python_aaronia-0.6.2 → python_aaronia-0.7.1}/examples/native_sdk_basic.rs +0 -0
- {python_aaronia-0.6.2 → python_aaronia-0.7.1}/examples/native_sdk_transmit.rs +0 -0
- {python_aaronia-0.6.2 → python_aaronia-0.7.1}/examples/noaa_scanner.rs +0 -0
- {python_aaronia-0.6.2 → python_aaronia-0.7.1}/examples/python_arrow_example.py +0 -0
- {python_aaronia-0.6.2 → python_aaronia-0.7.1}/examples/read_rtsa_file.rs +0 -0
- {python_aaronia-0.6.2 → python_aaronia-0.7.1}/examples/soapy_python_example.py +0 -0
- {python_aaronia-0.6.2 → python_aaronia-0.7.1}/include/aaronia.h +0 -0
- {python_aaronia-0.6.2 → python_aaronia-0.7.1}/scripts/ci-local.sh +0 -0
- {python_aaronia-0.6.2 → python_aaronia-0.7.1}/soapy-aaronia/AaroniaSoapyDevice.cpp +0 -0
- {python_aaronia-0.6.2 → python_aaronia-0.7.1}/soapy-aaronia/AaroniaSoapyDevice.hpp +0 -0
- {python_aaronia-0.6.2 → python_aaronia-0.7.1}/soapy-aaronia/Registration.cpp +0 -0
- {python_aaronia-0.6.2 → python_aaronia-0.7.1}/src/c_api.rs +0 -0
- {python_aaronia-0.6.2 → python_aaronia-0.7.1}/src/decompression.rs +0 -0
- {python_aaronia-0.6.2 → python_aaronia-0.7.1}/src/detection.rs +0 -0
- {python_aaronia-0.6.2 → python_aaronia-0.7.1}/src/file_source.rs +0 -0
- {python_aaronia-0.6.2 → python_aaronia-0.7.1}/src/http_endpoints.rs +0 -0
- {python_aaronia-0.6.2 → python_aaronia-0.7.1}/src/http_sink.rs +0 -0
- {python_aaronia-0.6.2 → python_aaronia-0.7.1}/src/http_streaming.rs +0 -0
- {python_aaronia-0.6.2 → python_aaronia-0.7.1}/src/lib.rs +0 -0
- {python_aaronia-0.6.2 → python_aaronia-0.7.1}/src/native_sdk.rs +0 -0
- {python_aaronia-0.6.2 → python_aaronia-0.7.1}/src/sdk_sink.rs +0 -0
- {python_aaronia-0.6.2 → python_aaronia-0.7.1}/src/sdk_source.rs +0 -0
- {python_aaronia-0.6.2 → python_aaronia-0.7.1}/src/sdr_source_impl.rs +0 -0
- {python_aaronia-0.6.2 → python_aaronia-0.7.1}/src/seify_impl.rs +0 -0
- {python_aaronia-0.6.2 → python_aaronia-0.7.1}/src/unified_sink.rs +0 -0
- {python_aaronia-0.6.2 → python_aaronia-0.7.1}/src/utils.rs +0 -0
- {python_aaronia-0.6.2 → python_aaronia-0.7.1}/tests/c_api_test.rs +0 -0
- {python_aaronia-0.6.2 → python_aaronia-0.7.1}/tests/http_mock_test.rs +0 -0
- {python_aaronia-0.6.2 → python_aaronia-0.7.1}/tests/http_sink_test.rs +0 -0
- {python_aaronia-0.6.2 → python_aaronia-0.7.1}/tests/integration_test.rs +0 -0
- {python_aaronia-0.6.2 → python_aaronia-0.7.1}/tests/live_smoke.rs +0 -0
- {python_aaronia-0.6.2 → python_aaronia-0.7.1}/tests/native_sdk_load.rs +0 -0
- {python_aaronia-0.6.2 → python_aaronia-0.7.1}/tests/properties.proptest-regressions +0 -0
- {python_aaronia-0.6.2 → python_aaronia-0.7.1}/tests/properties.rs +0 -0
- {python_aaronia-0.6.2 → python_aaronia-0.7.1}/tests/rtsa_negative_test.rs +0 -0
- {python_aaronia-0.6.2 → python_aaronia-0.7.1}/tests/sdr_source_impl_test.rs +0 -0
- {python_aaronia-0.6.2 → python_aaronia-0.7.1}/tests/spec_coverage.rs +0 -0
- {python_aaronia-0.6.2 → python_aaronia-0.7.1}/tests/test_cw_mag.rs +0 -0
- {python_aaronia-0.6.2 → python_aaronia-0.7.1}/tests/test_cw_meta.rs +0 -0
|
@@ -4,6 +4,73 @@ All notable changes to this project will be documented in this file.
|
|
|
4
4
|
|
|
5
5
|
## [Unreleased]
|
|
6
6
|
|
|
7
|
+
## [v0.7.1] - 2026-08-12
|
|
8
|
+
|
|
9
|
+
### Fixed
|
|
10
|
+
- **The published macOS SoapySDR module would not load, on any Mac.**
|
|
11
|
+
`dlopen` failed with "symbol not found in flat namespace" for a Rust
|
|
12
|
+
vtable entry. CMake links module targets on macOS with
|
|
13
|
+
`-undefined dynamic_lookup`, and the Apple linker emitted a
|
|
14
|
+
flat-namespace bind for a symbol it had already localised into the
|
|
15
|
+
same image. The module now resolves its symbols at link time, so this
|
|
16
|
+
is a build failure rather than something a user meets on first run.
|
|
17
|
+
Every 0.5.x, 0.6.x and 0.7.0 macOS archive is affected; the Linux and
|
|
18
|
+
Windows modules are not.
|
|
19
|
+
- **The packaged module's load check ran on Linux only**, which is why
|
|
20
|
+
the above shipped. It now runs on all three platforms at release
|
|
21
|
+
time, and CI builds and checks the plugin on macOS as well as Linux.
|
|
22
|
+
|
|
23
|
+
### Documentation
|
|
24
|
+
- The Linux module needs glibc 2.38 or later, so it does not load on
|
|
25
|
+
Ubuntu 22.04 or Debian 12. Said so in the plugin README.
|
|
26
|
+
|
|
27
|
+
## [v0.7.0] - 2026-08-12
|
|
28
|
+
|
|
29
|
+
### Added
|
|
30
|
+
- **`aaronia.open()`, block iteration and context-manager support in
|
|
31
|
+
Python.** The shortest working program is now three lines. `open()`
|
|
32
|
+
takes the URL, frequency and either an exact `rate` or the
|
|
33
|
+
`bandwidth` you want covered, connects, and starts streaming;
|
|
34
|
+
`for block in src.blocks(65536)` ends when the source runs out
|
|
35
|
+
instead of raising; and `with` stops the stream even when the body
|
|
36
|
+
fails, raising a failed teardown only if the body itself succeeded.
|
|
37
|
+
The old config-object path is unchanged and still the way to reach
|
|
38
|
+
every option.
|
|
39
|
+
- **`aaronia-doctor`, a command that checks an RTSA server.** It reports
|
|
40
|
+
whether the server answers, whether the mission has an input carrying
|
|
41
|
+
IQ, and what rate the device is running, and prints the fix for each
|
|
42
|
+
failure. The same checks are available as `aaronia.diagnose(url)`,
|
|
43
|
+
which returns `(ok, message, fix)` tuples, bounded at 20 seconds so a
|
|
44
|
+
stalled server cannot leave it waiting. Every failure it names is one
|
|
45
|
+
that otherwise shows up as a timeout with no explanation.
|
|
46
|
+
- **`aaronia.sample_rates()` and `aaronia.sample_rate_for_bandwidth()`**,
|
|
47
|
+
exposing the crate's rate ladder to Python so a program can ask for a
|
|
48
|
+
rate the hardware will actually run.
|
|
49
|
+
- **`Error::StreamClosed`**, separating "the stream ended" from "a read
|
|
50
|
+
failed". Both used to arrive as `Error::Protocol`, so a consumer
|
|
51
|
+
could not tell a capture that finished from one that was cut short.
|
|
52
|
+
Rust code matching on `Error::Protocol` for the closed-stream case
|
|
53
|
+
needs the new variant instead; the enum is `#[non_exhaustive]`, so
|
|
54
|
+
existing wildcard arms keep compiling. In Python the matching
|
|
55
|
+
exception is `AaroniaStreamClosed`, a subclass of
|
|
56
|
+
`AaroniaConnectionError`, so existing handlers are unaffected. It is
|
|
57
|
+
what lets `blocks()` end a loop on a finished stream while still
|
|
58
|
+
raising on a timeout or a transport failure, which would otherwise
|
|
59
|
+
make a truncated capture look like one that simply ran out.
|
|
60
|
+
- **An installer in every SoapySDR release archive.** `install.sh`
|
|
61
|
+
(`install.ps1` on Windows) finds SoapySDR's module directory, clears
|
|
62
|
+
the macOS quarantine flag, copies the module in, and confirms it
|
|
63
|
+
loads. It prints instructions rather than guessing when SoapySDR is
|
|
64
|
+
missing.
|
|
65
|
+
- **A Homebrew formula for the SoapySDR plugin**, in
|
|
66
|
+
`packaging/homebrew`. The release workflow renders it against the
|
|
67
|
+
published archives, checksums included, and attaches it to the
|
|
68
|
+
release, so updating a tap is a copy.
|
|
69
|
+
|
|
70
|
+
### Fixed
|
|
71
|
+
- The SoapySDR application guide still listed the old invented sample
|
|
72
|
+
rates for GQRX. It now describes the real ladder.
|
|
73
|
+
|
|
7
74
|
## [v0.6.2] - 2026-08-12
|
|
8
75
|
|
|
9
76
|
## [v0.6.1] - 2026-08-12
|
|
@@ -3027,7 +3027,7 @@ dependencies = [
|
|
|
3027
3027
|
|
|
3028
3028
|
[[package]]
|
|
3029
3029
|
name = "python-aaronia"
|
|
3030
|
-
version = "0.
|
|
3030
|
+
version = "0.7.1"
|
|
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.
|
|
3559
|
+
version = "0.7.1"
|
|
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.
|
|
5
|
+
version = "0.7.1"
|
|
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.
|
|
3
|
+
Version: 0.7.1
|
|
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+)
|
|
@@ -40,37 +40,66 @@ cd python-aaronia
|
|
|
40
40
|
maturin develop --release
|
|
41
41
|
```
|
|
42
42
|
|
|
43
|
+
Check your setup before writing any code:
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
aaronia-doctor http://localhost:54664
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
It reports whether the server is reachable, whether the mission has an
|
|
50
|
+
input carrying IQ, and what rate the device is running, and names the
|
|
51
|
+
fix for each failure.
|
|
52
|
+
|
|
43
53
|
## Quickstart
|
|
44
54
|
|
|
45
55
|
```python
|
|
46
56
|
import aaronia
|
|
47
57
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
58
|
+
with aaronia.open("http://localhost:54664", freq=2.44e9, bandwidth=10e6) as src:
|
|
59
|
+
for block in src.blocks(65536): # numpy complex64 arrays
|
|
60
|
+
process(block)
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
`aaronia.open()` connects and starts streaming in one call. `bandwidth`
|
|
64
|
+
asks for that much usable spectrum and picks a sample rate the hardware
|
|
65
|
+
can actually run; pass `rate=` instead to name one exactly. Use
|
|
66
|
+
`file="capture.rtsa"` in place of the URL to play back a recording.
|
|
53
67
|
|
|
54
|
-
|
|
55
|
-
|
|
68
|
+
Iterating with `blocks()` ends when the stream closes. To read on your
|
|
69
|
+
own schedule, or for Apache Arrow:
|
|
56
70
|
|
|
71
|
+
```python
|
|
72
|
+
src = aaronia.open(freq=2.44e9, rate=15.36e6, format="I16")
|
|
57
73
|
samples = src.read_samples_numpy(65536) # numpy complex64 array
|
|
58
74
|
batch = src.read_samples_arrow(65536) # pyarrow FixedSizeListArray of [re, im]
|
|
59
|
-
|
|
60
75
|
src.set_center_frequency(2.41e9) # live retune, no teardown
|
|
61
|
-
|
|
62
76
|
print(src.cumulative_drops(), src.take_overrun(), src.last_timestamp_ns())
|
|
63
77
|
src.stop_streaming()
|
|
64
78
|
```
|
|
65
79
|
|
|
66
|
-
|
|
67
|
-
`
|
|
80
|
+
For full control, build an `AaroniaConfig` and pass it to
|
|
81
|
+
`AaroniaSource.start_streaming()`; `open()` is a shorthand for the
|
|
82
|
+
common fields.
|
|
68
83
|
|
|
69
84
|
The
|
|
70
85
|
[quickstart](https://github.com/isaacbentley/sdr-aaronia-rs/blob/main/docs/QUICKSTART.md)
|
|
71
86
|
covers configuring the RTSA-Suite HTTP Server block, which everything
|
|
72
87
|
above depends on.
|
|
73
88
|
|
|
89
|
+
## Sample rates
|
|
90
|
+
|
|
91
|
+
The device runs a fixed ladder of rates: 61.44 MHz halved down to
|
|
92
|
+
120 kHz. Ask for anything else and it quietly uses the nearest rung,
|
|
93
|
+
leaving your program computing against a rate that is not in use.
|
|
94
|
+
|
|
95
|
+
```python
|
|
96
|
+
aaronia.sample_rates() # every rate, highest first
|
|
97
|
+
aaronia.sample_rate_for_bandwidth(8e6) # 15.36e6: the lowest rate covering 8 MHz
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
A rate carries only 80% of itself as alias-free bandwidth, which is why
|
|
101
|
+
8 MHz of spectrum needs 15.36 MHz of sampling.
|
|
102
|
+
|
|
74
103
|
## Configuration (`AaroniaConfig`)
|
|
75
104
|
|
|
76
105
|
Every field is readable and writable.
|
|
@@ -107,11 +136,14 @@ silently defaulting.
|
|
|
107
136
|
enabled, which is the default. The reader reopens the stream,
|
|
108
137
|
re-applies the current tuning, and flags the first read after the gap
|
|
109
138
|
through `take_overrun()`. After five failed attempts the stream ends
|
|
110
|
-
and reads raise `
|
|
139
|
+
and reads raise `AaroniaStreamClosed`.
|
|
111
140
|
- **Typed exceptions.** `AaroniaConnectionError` (unreachable endpoint),
|
|
112
141
|
`AaroniaTimeoutError`, `AaroniaHardwareError` (device and SDK errors)
|
|
113
142
|
and `ValueError` (invalid configuration), mapped from the Rust error
|
|
114
143
|
enum with the full cause chain in the message.
|
|
144
|
+
`AaroniaStreamClosed` subclasses `AaroniaConnectionError` and means
|
|
145
|
+
the stream finished rather than failed; `blocks()` ends on it, while
|
|
146
|
+
a timeout or transport failure still raises.
|
|
115
147
|
- **Dual-channel** reads (`receiver_channel = "Rx1And2"` with
|
|
116
148
|
`read_samples_dual_numpy(count)`, returning two time-aligned arrays)
|
|
117
149
|
require the native-SDK backend: Windows or Linux with the Aaronia SDK
|
|
@@ -123,6 +155,8 @@ silently defaulting.
|
|
|
123
155
|
| Method | Purpose |
|
|
124
156
|
| --- | --- |
|
|
125
157
|
| `start_streaming(cfg)` / `stop_streaming()` | Session lifecycle |
|
|
158
|
+
| `with src: ...` | Stops streaming on the way out, including after an exception |
|
|
159
|
+
| `blocks(count)` | Iterate `count`-sample arrays until the stream closes |
|
|
126
160
|
| `read_samples_numpy(count)` | NumPy `complex64` array |
|
|
127
161
|
| `read_samples_arrow(count)` | PyArrow `FixedSizeListArray` of `[re, im]` float32 pairs |
|
|
128
162
|
| `read_samples_dual_numpy(count)` | `(rx1, rx2)` NumPy arrays (dual-channel captures) |
|
|
@@ -131,3 +165,12 @@ silently defaulting.
|
|
|
131
165
|
| `take_overrun()` | True once per detected receive-side overrun |
|
|
132
166
|
| `last_timestamp_ns()` | Epoch-ns timestamp of the last received block (HTTP backend; 0 otherwise) |
|
|
133
167
|
|
|
168
|
+
## Module functions
|
|
169
|
+
|
|
170
|
+
| Function | Purpose |
|
|
171
|
+
| --- | --- |
|
|
172
|
+
| `open(url=None, *, freq, rate, bandwidth, ref_level, file, format, read_timeout)` | Configure, connect and start streaming in one call |
|
|
173
|
+
| `sample_rates()` | Every sample rate the hardware can run |
|
|
174
|
+
| `sample_rate_for_bandwidth(hz)` | Lowest rate covering that much spectrum |
|
|
175
|
+
| `diagnose(url)` | `(ok, message, fix)` for each setup check; what `aaronia-doctor` prints |
|
|
176
|
+
|
|
@@ -102,21 +102,17 @@ pip install python-aaronia
|
|
|
102
102
|
```python
|
|
103
103
|
import aaronia
|
|
104
104
|
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
cfg.sample_rate = 15.36e6
|
|
109
|
-
|
|
110
|
-
src = aaronia.AaroniaSource()
|
|
111
|
-
src.start_streaming(cfg)
|
|
112
|
-
samples = src.read_samples_numpy(65536) # numpy complex64
|
|
113
|
-
src.stop_streaming()
|
|
105
|
+
with aaronia.open("http://localhost:54664", freq=2.44e9, bandwidth=10e6) as src:
|
|
106
|
+
for block in src.blocks(65536): # numpy complex64 arrays
|
|
107
|
+
process(block)
|
|
114
108
|
```
|
|
115
109
|
|
|
116
110
|
Reads land in NumPy or PyArrow with one copy out of the receive buffer.
|
|
117
111
|
Blocking calls release the GIL, errors arrive as typed exceptions, and
|
|
118
112
|
the package ships type stubs. Wheels are abi3 for CPython 3.9 and
|
|
119
|
-
later.
|
|
113
|
+
later. The bundled `aaronia-doctor` command checks a server and names
|
|
114
|
+
the fix for whatever is wrong. Full reference:
|
|
115
|
+
[python-aaronia/README.md](python-aaronia/README.md).
|
|
120
116
|
|
|
121
117
|
### SoapySDR: GQRX, SDR++, GNU Radio and others
|
|
122
118
|
|
|
@@ -1,14 +1,20 @@
|
|
|
1
1
|
# Using a SPECTRAN from existing SDR applications
|
|
2
2
|
|
|
3
3
|
Any SoapySDR-capable application can drive a SPECTRAN through the
|
|
4
|
-
[`soapy-aaronia`](../soapy-aaronia/README.md) plugin. Install
|
|
5
|
-
|
|
6
|
-
|
|
4
|
+
[`soapy-aaronia`](../soapy-aaronia/README.md) plugin. Install it first:
|
|
5
|
+
download the archive for your platform from a
|
|
6
|
+
[release](https://github.com/isaacbentley/sdr-aaronia-rs/releases),
|
|
7
|
+
unpack it, and run the bundled installer (`./install.sh`, or
|
|
8
|
+
`.\install.ps1` in PowerShell on Windows). It finds SoapySDR's module
|
|
9
|
+
directory, copies the plugin in, and confirms it loads:
|
|
7
10
|
|
|
8
11
|
```bash
|
|
9
12
|
SoapySDRUtil --check=aaronia
|
|
10
13
|
```
|
|
11
14
|
|
|
15
|
+
The [plugin README](../soapy-aaronia/README.md#install-a-prebuilt-module)
|
|
16
|
+
covers installing by hand and building from source.
|
|
17
|
+
|
|
12
18
|
Every application below uses the same device string. In most cases the
|
|
13
19
|
RTSA-Suite HTTP server URL is the only argument needed:
|
|
14
20
|
|
|
@@ -43,11 +49,10 @@ GQRX accepts a device string directly in its configuration dialog:
|
|
|
43
49
|
driver=aaronia,url=http://localhost:54664
|
|
44
50
|
```
|
|
45
51
|
|
|
46
|
-
Select the sample rate from GQRX's list. The plugin advertises
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
necessarily unsupported.
|
|
52
|
+
Select the sample rate from GQRX's list. The plugin advertises the
|
|
53
|
+
device's real ladder: 61.44 MHz halved down to 120 kHz, which the RTSA
|
|
54
|
+
GUI labels Full through 1/512. The hardware produces no other rate, so a
|
|
55
|
+
request in between snaps to the nearest rung and logs a warning.
|
|
51
56
|
|
|
52
57
|
The single gain element is `REF`, the Aaronia reference level in dBm. It
|
|
53
58
|
is not an amplifier gain: raising it reduces sensitivity. Start near
|
|
@@ -86,30 +86,39 @@ cargo run --example http_iq_quickstart --features http -- 2440e6 15.36e6 http://
|
|
|
86
86
|
pip install python-aaronia
|
|
87
87
|
```
|
|
88
88
|
|
|
89
|
+
Check the server first. The command ships with the package and reports
|
|
90
|
+
what is wrong, and how to fix it:
|
|
91
|
+
|
|
92
|
+
```bash
|
|
93
|
+
aaronia-doctor http://localhost:54664
|
|
94
|
+
```
|
|
95
|
+
|
|
89
96
|
```python
|
|
90
97
|
import aaronia
|
|
91
98
|
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
cfg.sample_rate = 15.36e6
|
|
96
|
-
|
|
97
|
-
src = aaronia.AaroniaSource()
|
|
98
|
-
src.start_streaming(cfg)
|
|
99
|
-
samples = src.read_samples_numpy(65536) # numpy complex64
|
|
100
|
-
print(samples[:4], src.cumulative_drops())
|
|
101
|
-
src.stop_streaming()
|
|
99
|
+
with aaronia.open("http://localhost:54664", freq=2.44e9, bandwidth=10e6) as src:
|
|
100
|
+
samples = src.read_samples_numpy(65536) # numpy complex64
|
|
101
|
+
print(samples[:4], src.cumulative_drops())
|
|
102
102
|
```
|
|
103
103
|
|
|
104
|
+
`bandwidth` picks a sample rate the hardware can run. Pass `rate=` to
|
|
105
|
+
name one exactly, or build an `AaroniaConfig` for the full set of
|
|
106
|
+
options.
|
|
107
|
+
|
|
104
108
|
### SoapySDR
|
|
105
109
|
|
|
110
|
+
Download the plugin archive for your platform from a
|
|
111
|
+
[release](https://github.com/isaacbentley/sdr-aaronia-rs/releases),
|
|
112
|
+
unpack it, and run the bundled installer:
|
|
113
|
+
|
|
106
114
|
```bash
|
|
115
|
+
./install.sh
|
|
107
116
|
SoapySDRUtil --probe="driver=aaronia,url=http://localhost:54664"
|
|
108
117
|
```
|
|
109
118
|
|
|
110
119
|
[APPS.md](APPS.md) covers GQRX, SDR++ and GNU Radio.
|
|
111
120
|
[../soapy-aaronia/README.md](../soapy-aaronia/README.md) covers
|
|
112
|
-
installing
|
|
121
|
+
installing by hand and building from source.
|
|
113
122
|
|
|
114
123
|
## 4. Troubleshooting
|
|
115
124
|
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# Homebrew tap
|
|
2
|
+
|
|
3
|
+
`soapy-aaronia.rb` installs the prebuilt SoapySDR plugin from a GitHub
|
|
4
|
+
release. It is kept here so it is versioned alongside the code it
|
|
5
|
+
installs, and published from a tap repository.
|
|
6
|
+
|
|
7
|
+
## One-time setup
|
|
8
|
+
|
|
9
|
+
Create a public repository named `homebrew-tap` under the same owner as
|
|
10
|
+
this one. The name is fixed: Homebrew maps `owner/tap` to
|
|
11
|
+
`github.com/owner/homebrew-tap`. Add the formula as
|
|
12
|
+
`Formula/soapy-aaronia.rb`.
|
|
13
|
+
|
|
14
|
+
Users then install with:
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
brew install isaacbentley/tap/soapy-aaronia
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
Homebrew pulls in SoapySDR, drops the module into
|
|
21
|
+
`lib/SoapySDR/modules0.8`, and its `brew test` step confirms
|
|
22
|
+
`SoapySDRUtil --check=aaronia` reports the driver as present.
|
|
23
|
+
|
|
24
|
+
## Each release
|
|
25
|
+
|
|
26
|
+
The release workflow renders this file against the published archives
|
|
27
|
+
and attaches the result to the release as `soapy-aaronia.rb`, with the
|
|
28
|
+
version and both SHA-256 checksums filled in. Copy that file into the
|
|
29
|
+
tap repository as `Formula/soapy-aaronia.rb` and commit. Nothing needs
|
|
30
|
+
hashing by hand.
|
|
31
|
+
|
|
32
|
+
Before pushing, `brew audit --strict --online soapy-aaronia` checks the
|
|
33
|
+
formula, and `brew install --build-from-source` proves it works.
|
|
34
|
+
|
|
35
|
+
## Coverage
|
|
36
|
+
|
|
37
|
+
The formula covers macOS on Apple silicon and Linux on x86-64, matching
|
|
38
|
+
the platforms the release builds. Elsewhere, `brew` has nothing to
|
|
39
|
+
install and the plugin has to be built from source; see
|
|
40
|
+
[soapy-aaronia/README.md](../../soapy-aaronia/README.md).
|
|
41
|
+
|
|
42
|
+
The module directory is pinned to `modules0.8`, which is SoapySDR's ABI
|
|
43
|
+
0.8 path. A future SoapySDR ABI bump requires changing that line.
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# Homebrew formula for the Aaronia SoapySDR plugin.
|
|
2
|
+
#
|
|
3
|
+
# Lives here so it is versioned with the code it installs. To publish it,
|
|
4
|
+
# copy this file into a tap repository named homebrew-tap, as
|
|
5
|
+
# Formula/soapy-aaronia.rb, and users get:
|
|
6
|
+
#
|
|
7
|
+
# brew install <owner>/tap/soapy-aaronia
|
|
8
|
+
#
|
|
9
|
+
# At each release, update `version`, both `sha256` values (from the
|
|
10
|
+
# release archives) and nothing else. `brew audit --strict soapy-aaronia`
|
|
11
|
+
# checks the formula before publishing.
|
|
12
|
+
class SoapyAaronia < Formula
|
|
13
|
+
desc "SoapySDR plugin for Aaronia SPECTRAN V6 spectrum analyzers"
|
|
14
|
+
homepage "https://github.com/isaacbentley/sdr-aaronia-rs"
|
|
15
|
+
version "0.7.1"
|
|
16
|
+
license "GPL-3.0-or-later"
|
|
17
|
+
|
|
18
|
+
# Prebuilt modules: the plugin statically links its Rust core, so there
|
|
19
|
+
# is nothing to build here and no Rust toolchain to depend on.
|
|
20
|
+
on_macos do
|
|
21
|
+
on_arm do
|
|
22
|
+
url "https://github.com/isaacbentley/sdr-aaronia-rs/releases/download/v#{version}/SoapyAaronia-#{version}-macos-arm64.tar.gz"
|
|
23
|
+
sha256 "REPLACE_WITH_SHA256_OF_MACOS_ARM64_ARCHIVE"
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
on_linux do
|
|
28
|
+
on_intel do
|
|
29
|
+
url "https://github.com/isaacbentley/sdr-aaronia-rs/releases/download/v#{version}/SoapyAaronia-#{version}-linux-x86_64.tar.gz"
|
|
30
|
+
sha256 "REPLACE_WITH_SHA256_OF_LINUX_X86_64_ARCHIVE"
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
depends_on "soapysdr"
|
|
35
|
+
|
|
36
|
+
def install
|
|
37
|
+
# SoapySDR loads modules from a versioned directory under its own
|
|
38
|
+
# prefix; Homebrew links this into place for us.
|
|
39
|
+
(lib/"SoapySDR/modules0.8").install "libaaroniaSupport.so"
|
|
40
|
+
doc.install "INSTALL.md"
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
test do
|
|
44
|
+
# Proves the module loads into SoapySDR rather than merely existing.
|
|
45
|
+
assert_match "aaronia", shell_output("#{Formula["soapysdr"].bin}/SoapySDRUtil --check=aaronia")
|
|
46
|
+
end
|
|
47
|
+
end
|
|
@@ -18,6 +18,11 @@ classifiers = [
|
|
|
18
18
|
# Version comes from python-aaronia/Cargo.toml (single source of truth).
|
|
19
19
|
dynamic = ["version"]
|
|
20
20
|
|
|
21
|
+
# A real command, so checking a setup needs no code:
|
|
22
|
+
# aaronia-doctor http://localhost:54664
|
|
23
|
+
[project.scripts]
|
|
24
|
+
aaronia-doctor = "aaronia:doctor_cli"
|
|
25
|
+
|
|
21
26
|
[project.urls]
|
|
22
27
|
Repository = "https://github.com/isaacbentley/sdr-aaronia-rs"
|
|
23
28
|
Changelog = "https://github.com/isaacbentley/sdr-aaronia-rs/blob/main/CHANGELOG.md"
|
|
@@ -25,37 +25,66 @@ cd python-aaronia
|
|
|
25
25
|
maturin develop --release
|
|
26
26
|
```
|
|
27
27
|
|
|
28
|
+
Check your setup before writing any code:
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
aaronia-doctor http://localhost:54664
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
It reports whether the server is reachable, whether the mission has an
|
|
35
|
+
input carrying IQ, and what rate the device is running, and names the
|
|
36
|
+
fix for each failure.
|
|
37
|
+
|
|
28
38
|
## Quickstart
|
|
29
39
|
|
|
30
40
|
```python
|
|
31
41
|
import aaronia
|
|
32
42
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
43
|
+
with aaronia.open("http://localhost:54664", freq=2.44e9, bandwidth=10e6) as src:
|
|
44
|
+
for block in src.blocks(65536): # numpy complex64 arrays
|
|
45
|
+
process(block)
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
`aaronia.open()` connects and starts streaming in one call. `bandwidth`
|
|
49
|
+
asks for that much usable spectrum and picks a sample rate the hardware
|
|
50
|
+
can actually run; pass `rate=` instead to name one exactly. Use
|
|
51
|
+
`file="capture.rtsa"` in place of the URL to play back a recording.
|
|
38
52
|
|
|
39
|
-
|
|
40
|
-
|
|
53
|
+
Iterating with `blocks()` ends when the stream closes. To read on your
|
|
54
|
+
own schedule, or for Apache Arrow:
|
|
41
55
|
|
|
56
|
+
```python
|
|
57
|
+
src = aaronia.open(freq=2.44e9, rate=15.36e6, format="I16")
|
|
42
58
|
samples = src.read_samples_numpy(65536) # numpy complex64 array
|
|
43
59
|
batch = src.read_samples_arrow(65536) # pyarrow FixedSizeListArray of [re, im]
|
|
44
|
-
|
|
45
60
|
src.set_center_frequency(2.41e9) # live retune, no teardown
|
|
46
|
-
|
|
47
61
|
print(src.cumulative_drops(), src.take_overrun(), src.last_timestamp_ns())
|
|
48
62
|
src.stop_streaming()
|
|
49
63
|
```
|
|
50
64
|
|
|
51
|
-
|
|
52
|
-
`
|
|
65
|
+
For full control, build an `AaroniaConfig` and pass it to
|
|
66
|
+
`AaroniaSource.start_streaming()`; `open()` is a shorthand for the
|
|
67
|
+
common fields.
|
|
53
68
|
|
|
54
69
|
The
|
|
55
70
|
[quickstart](https://github.com/isaacbentley/sdr-aaronia-rs/blob/main/docs/QUICKSTART.md)
|
|
56
71
|
covers configuring the RTSA-Suite HTTP Server block, which everything
|
|
57
72
|
above depends on.
|
|
58
73
|
|
|
74
|
+
## Sample rates
|
|
75
|
+
|
|
76
|
+
The device runs a fixed ladder of rates: 61.44 MHz halved down to
|
|
77
|
+
120 kHz. Ask for anything else and it quietly uses the nearest rung,
|
|
78
|
+
leaving your program computing against a rate that is not in use.
|
|
79
|
+
|
|
80
|
+
```python
|
|
81
|
+
aaronia.sample_rates() # every rate, highest first
|
|
82
|
+
aaronia.sample_rate_for_bandwidth(8e6) # 15.36e6: the lowest rate covering 8 MHz
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
A rate carries only 80% of itself as alias-free bandwidth, which is why
|
|
86
|
+
8 MHz of spectrum needs 15.36 MHz of sampling.
|
|
87
|
+
|
|
59
88
|
## Configuration (`AaroniaConfig`)
|
|
60
89
|
|
|
61
90
|
Every field is readable and writable.
|
|
@@ -92,11 +121,14 @@ silently defaulting.
|
|
|
92
121
|
enabled, which is the default. The reader reopens the stream,
|
|
93
122
|
re-applies the current tuning, and flags the first read after the gap
|
|
94
123
|
through `take_overrun()`. After five failed attempts the stream ends
|
|
95
|
-
and reads raise `
|
|
124
|
+
and reads raise `AaroniaStreamClosed`.
|
|
96
125
|
- **Typed exceptions.** `AaroniaConnectionError` (unreachable endpoint),
|
|
97
126
|
`AaroniaTimeoutError`, `AaroniaHardwareError` (device and SDK errors)
|
|
98
127
|
and `ValueError` (invalid configuration), mapped from the Rust error
|
|
99
128
|
enum with the full cause chain in the message.
|
|
129
|
+
`AaroniaStreamClosed` subclasses `AaroniaConnectionError` and means
|
|
130
|
+
the stream finished rather than failed; `blocks()` ends on it, while
|
|
131
|
+
a timeout or transport failure still raises.
|
|
100
132
|
- **Dual-channel** reads (`receiver_channel = "Rx1And2"` with
|
|
101
133
|
`read_samples_dual_numpy(count)`, returning two time-aligned arrays)
|
|
102
134
|
require the native-SDK backend: Windows or Linux with the Aaronia SDK
|
|
@@ -108,6 +140,8 @@ silently defaulting.
|
|
|
108
140
|
| Method | Purpose |
|
|
109
141
|
| --- | --- |
|
|
110
142
|
| `start_streaming(cfg)` / `stop_streaming()` | Session lifecycle |
|
|
143
|
+
| `with src: ...` | Stops streaming on the way out, including after an exception |
|
|
144
|
+
| `blocks(count)` | Iterate `count`-sample arrays until the stream closes |
|
|
111
145
|
| `read_samples_numpy(count)` | NumPy `complex64` array |
|
|
112
146
|
| `read_samples_arrow(count)` | PyArrow `FixedSizeListArray` of `[re, im]` float32 pairs |
|
|
113
147
|
| `read_samples_dual_numpy(count)` | `(rx1, rx2)` NumPy arrays (dual-channel captures) |
|
|
@@ -115,3 +149,12 @@ silently defaulting.
|
|
|
115
149
|
| `cumulative_drops()` | Total server-reported dropped samples |
|
|
116
150
|
| `take_overrun()` | True once per detected receive-side overrun |
|
|
117
151
|
| `last_timestamp_ns()` | Epoch-ns timestamp of the last received block (HTTP backend; 0 otherwise) |
|
|
152
|
+
|
|
153
|
+
## Module functions
|
|
154
|
+
|
|
155
|
+
| Function | Purpose |
|
|
156
|
+
| --- | --- |
|
|
157
|
+
| `open(url=None, *, freq, rate, bandwidth, ref_level, file, format, read_timeout)` | Configure, connect and start streaming in one call |
|
|
158
|
+
| `sample_rates()` | Every sample rate the hardware can run |
|
|
159
|
+
| `sample_rate_for_bandwidth(hz)` | Lowest rate covering that much spectrum |
|
|
160
|
+
| `diagnose(url)` | `(ok, message, fix)` for each setup check; what `aaronia-doctor` prints |
|