python-aaronia 0.5.0__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.5.0/.cargo/config.toml +2 -0
- python_aaronia-0.5.0/.gitattributes +1 -0
- python_aaronia-0.5.0/.gitignore +24 -0
- python_aaronia-0.5.0/CHANGELOG.md +363 -0
- python_aaronia-0.5.0/CONTRIBUTING.md +184 -0
- python_aaronia-0.5.0/Cargo.lock +5254 -0
- python_aaronia-0.5.0/Cargo.toml +136 -0
- python_aaronia-0.5.0/DESIGN.md +101 -0
- python_aaronia-0.5.0/LICENSE +674 -0
- python_aaronia-0.5.0/PKG-INFO +116 -0
- python_aaronia-0.5.0/PLUGINS.md +138 -0
- python_aaronia-0.5.0/README.md +503 -0
- python_aaronia-0.5.0/benches/decompress_block.rs +61 -0
- python_aaronia-0.5.0/benches/deinterleave_dual_iq.rs +48 -0
- python_aaronia-0.5.0/benches/parse_int16_packet.rs +75 -0
- python_aaronia-0.5.0/benches/rtsa_open_and_read.rs +102 -0
- python_aaronia-0.5.0/deny.toml +42 -0
- python_aaronia-0.5.0/docs/FILESPEC.md +911 -0
- python_aaronia-0.5.0/docs/HTTPSPEC.md +707 -0
- python_aaronia-0.5.0/docs/SDKSPEC.md +878 -0
- python_aaronia-0.5.0/examples/channel_hopping.rs +82 -0
- python_aaronia-0.5.0/examples/device_control.rs +29 -0
- python_aaronia-0.5.0/examples/dump_metadata.rs +65 -0
- python_aaronia-0.5.0/examples/http_iq_quickstart.rs +70 -0
- python_aaronia-0.5.0/examples/native_sdk_basic.rs +132 -0
- python_aaronia-0.5.0/examples/native_sdk_transmit.rs +145 -0
- python_aaronia-0.5.0/examples/noaa_scanner.rs +333 -0
- python_aaronia-0.5.0/examples/python_arrow_example.py +41 -0
- python_aaronia-0.5.0/examples/read_rtsa_file.rs +34 -0
- python_aaronia-0.5.0/examples/soapy_python_example.py +60 -0
- python_aaronia-0.5.0/include/aaronia.h +192 -0
- python_aaronia-0.5.0/pyproject.toml +28 -0
- python_aaronia-0.5.0/python-aaronia/Cargo.toml +25 -0
- python_aaronia-0.5.0/python-aaronia/README.md +100 -0
- python_aaronia-0.5.0/python-aaronia/src/lib.rs +491 -0
- python_aaronia-0.5.0/python-aaronia/test_basic.py +54 -0
- python_aaronia-0.5.0/scripts/ci-local.sh +203 -0
- python_aaronia-0.5.0/soapy-aaronia/AaroniaSoapyDevice.cpp +577 -0
- python_aaronia-0.5.0/soapy-aaronia/AaroniaSoapyDevice.hpp +132 -0
- python_aaronia-0.5.0/soapy-aaronia/CMakeLists.txt +76 -0
- python_aaronia-0.5.0/soapy-aaronia/README.md +85 -0
- python_aaronia-0.5.0/soapy-aaronia/Registration.cpp +153 -0
- python_aaronia-0.5.0/src/c_api.rs +1526 -0
- python_aaronia-0.5.0/src/decompression.rs +704 -0
- python_aaronia-0.5.0/src/detection.rs +259 -0
- python_aaronia-0.5.0/src/error.rs +79 -0
- python_aaronia-0.5.0/src/file_source.rs +4580 -0
- python_aaronia-0.5.0/src/http_endpoints.rs +2086 -0
- python_aaronia-0.5.0/src/http_sink.rs +378 -0
- python_aaronia-0.5.0/src/http_source.rs +1481 -0
- python_aaronia-0.5.0/src/http_streaming.rs +1646 -0
- python_aaronia-0.5.0/src/lib.rs +123 -0
- python_aaronia-0.5.0/src/native_sdk.rs +3246 -0
- python_aaronia-0.5.0/src/sdk_sink.rs +375 -0
- python_aaronia-0.5.0/src/sdk_source.rs +544 -0
- python_aaronia-0.5.0/src/sdr_source_impl.rs +542 -0
- python_aaronia-0.5.0/src/seify_impl.rs +437 -0
- python_aaronia-0.5.0/src/unified_sink.rs +294 -0
- python_aaronia-0.5.0/src/unified_source.rs +1971 -0
- python_aaronia-0.5.0/src/utils.rs +533 -0
- python_aaronia-0.5.0/tests/c_api_test.rs +72 -0
- python_aaronia-0.5.0/tests/http_mock_test.rs +501 -0
- python_aaronia-0.5.0/tests/http_sink_test.rs +100 -0
- python_aaronia-0.5.0/tests/integration_test.rs +532 -0
- python_aaronia-0.5.0/tests/live_smoke.rs +604 -0
- python_aaronia-0.5.0/tests/native_sdk_load.rs +47 -0
- python_aaronia-0.5.0/tests/properties.proptest-regressions +8 -0
- python_aaronia-0.5.0/tests/properties.rs +407 -0
- python_aaronia-0.5.0/tests/rtsa_negative_test.rs +104 -0
- python_aaronia-0.5.0/tests/sdr_source_impl_test.rs +420 -0
- python_aaronia-0.5.0/tests/spec_coverage.rs +281 -0
- python_aaronia-0.5.0/tests/test_cw_mag.rs +69 -0
- python_aaronia-0.5.0/tests/test_cw_meta.rs +67 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
*.rtsa filter=lfs diff=lfs merge=lfs -text
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/target/
|
|
2
|
+
**/*.rs.bk
|
|
3
|
+
.DS_Store
|
|
4
|
+
|
|
5
|
+
# Proprietary Aaronia SDK artifacts (header/DLL/import lib) used for local
|
|
6
|
+
# FFI-conformance verification only. Marked CONFIDENTIAL AND PROPRIETARY by
|
|
7
|
+
# Aaronia — must not be redistributed in this public repository.
|
|
8
|
+
tests/sdk/
|
|
9
|
+
|
|
10
|
+
# Local agent configuration/memory
|
|
11
|
+
.agents/
|
|
12
|
+
|
|
13
|
+
# CMake build directory for SoapySDR plugin
|
|
14
|
+
soapy-aaronia/build/
|
|
15
|
+
python-aaronia/__pycache__/test_basic.cpython-314-pytest-9.1.1.pyc
|
|
16
|
+
python-aaronia/err.txt
|
|
17
|
+
python-aaronia/check_errors.txt
|
|
18
|
+
branch_diff.txt
|
|
19
|
+
|
|
20
|
+
# Python bindings dev environment and local plugin builds
|
|
21
|
+
python-aaronia/venv/
|
|
22
|
+
python-aaronia/**/__pycache__/
|
|
23
|
+
soapy-aaronia/build/
|
|
24
|
+
dist/
|
|
@@ -0,0 +1,363 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented in this file.
|
|
4
|
+
|
|
5
|
+
## [v0.5.0] - 2026-08-11
|
|
6
|
+
|
|
7
|
+
Breaking 0.x release combining the RTSA file-format verification work
|
|
8
|
+
with the new binding/plugin surfaces. (The recorded floor for this
|
|
9
|
+
range was 0.4.0; it ships as 0.5.0 to reflect the added Python/SoapySDR/
|
|
10
|
+
TX/GPS feature scope. A branch briefly relabelled it 1.0.0 — a 1.0
|
|
11
|
+
stability commitment on top of never-hardware-verified TX and freshly
|
|
12
|
+
reviewed bindings is exactly what 1.0 must not be.) The new surfaces
|
|
13
|
+
(Python bindings, SoapySDR plugin, TX, GPS time) shipped through a
|
|
14
|
+
six-stream production review with live-hardware validation of the RX
|
|
15
|
+
paths; hardware-facing TX/dual-channel paths remain
|
|
16
|
+
**hardware-unverified** where noted in the docs.
|
|
17
|
+
|
|
18
|
+
### Breaking
|
|
19
|
+
- `RtsaMetadata` lost `device_name`, `stream_sample_rate`, and
|
|
20
|
+
`stream_center_frequency`; `RtsaSource::stream_info()` now returns a
|
|
21
|
+
3-tuple. These fields were only ever populated by a fabricated
|
|
22
|
+
"proximity" STRM layout that no spec revision or capture uses; real
|
|
23
|
+
files always produced `None`.
|
|
24
|
+
- `SdkConfig` and `AaroniaConfig` gained a public `receiver_channel`
|
|
25
|
+
field (breaks struct-literal construction);
|
|
26
|
+
`NativeSdkSource::configure_iq_receiver` takes the channel as a
|
|
27
|
+
fourth parameter so retunes re-apply it.
|
|
28
|
+
|
|
29
|
+
### Added
|
|
30
|
+
- **Python bindings (`python-aaronia`)**: PyO3 bindings (module
|
|
31
|
+
`aaronia`, abi3 wheels for CPython 3.9+) with typed exceptions mapped
|
|
32
|
+
from the crate's error enum, readable/settable config covering HTTP
|
|
33
|
+
URL, file playback, serial, format, scale, reference level and
|
|
34
|
+
receiver channel, GIL-released blocking calls, live retuning, and
|
|
35
|
+
single-copy reads into NumPy or PyArrow arrays (including
|
|
36
|
+
dual-channel reads).
|
|
37
|
+
- **SoapySDR plugin (`soapy-aaronia`)**: C++ plugin over the C API —
|
|
38
|
+
RX streaming in CF32/CS16 with honoured `timeoutUs` and partial
|
|
39
|
+
reads, retune-safe locking, per-direction stream handles, discrete
|
|
40
|
+
sample-rate listing, device args (`url`, `file`, `serial`, `freq`,
|
|
41
|
+
`rate`, `ref_level`, `format`, `scale`, `rx_channel`), truthful
|
|
42
|
+
GPS hardware-time probing, and TX (hardware-unverified) via the
|
|
43
|
+
native SDK on Windows/Linux.
|
|
44
|
+
- **Transmit support**: `UnifiedSink` + `aaronia_sink_*` C API driving
|
|
45
|
+
the native-SDK TX path (device open/configure/start, master-clock
|
|
46
|
+
burst timing, caller-controlled packet-boundary flags).
|
|
47
|
+
**Hardware-unverified**; unavailable off Windows/Linux and errors
|
|
48
|
+
clearly there.
|
|
49
|
+
- **GPS time**: `get_gps_time` from the SDK telemetry tree, over FFI,
|
|
50
|
+
with validity gating; native-SDK backend only.
|
|
51
|
+
- **Release automation**: maturin wheels + PyPI trusted publishing and
|
|
52
|
+
SoapySDR plugin packaging in release.yml (first exercised on this
|
|
53
|
+
branch's CI, not at tag time).
|
|
54
|
+
- Receiver-channel selection (`RxChannel`: `Rx1`/`Rx2`/`Rx1And2`) on
|
|
55
|
+
every native-SDK config surface, and true dual-channel capture via
|
|
56
|
+
`read_samples_dual` on `NativeSdkSource`, `SdkSource`, and
|
|
57
|
+
`AaroniaSource`, with a read-mode latch preventing silent mono/dual
|
|
58
|
+
mixing.
|
|
59
|
+
- `StrmChunk::capture_start_offset`: RTSA files' undocumented STRM
|
|
60
|
+
trailing double, verified as the stream-relative capture start;
|
|
61
|
+
`start_time_ns` is now anchored with it so reported spans match the
|
|
62
|
+
recorded data.
|
|
63
|
+
- `scripts/ci-local.sh`: local CI-parity gate incl. cross-target and
|
|
64
|
+
Linux-VM coverage of the OS-gated native-SDK modules (the VM step
|
|
65
|
+
runs CI's exact ubuntu-leg commands).
|
|
66
|
+
- `benches/deinterleave_dual_iq`: criterion bench pinning the
|
|
67
|
+
dual-channel demux hot path (~1.5 Gsamples/s per core baseline).
|
|
68
|
+
- Parser-robustness property tests: `RtsaSource::open` on arbitrary
|
|
69
|
+
byte soup and on structured DSFH/DSFT chunk soup must never panic.
|
|
70
|
+
|
|
71
|
+
### Fixed
|
|
72
|
+
- RTSA chunk parsing verified against the vendor spec and real
|
|
73
|
+
captures: STRT alignment padding and size-versioned tail offsets,
|
|
74
|
+
SPRV/ANTA fixed-field sizes, single standard STRM layout, official
|
|
75
|
+
`DSST`/`DSSU`/`DSPT` enum numbering with `Unknown` degradation, and
|
|
76
|
+
`mEndTime` treated as stream-relative duration.
|
|
77
|
+
- Compressed `DSPT_SPECTRA` chunks now error explicitly instead of
|
|
78
|
+
returning compressed bytes reinterpreted as f32 spectra.
|
|
79
|
+
- Native SDK: corrupt-packet guards consume the packet before erroring
|
|
80
|
+
(previously a corrupt head-of-queue packet livelocked every
|
|
81
|
+
subsequent read); carry buffers are flushed on `stop_streaming`.
|
|
82
|
+
|
|
83
|
+
## [v0.3.5] - 2026-08-06
|
|
84
|
+
|
|
85
|
+
Documentation-and-polish release: every Markdown doc was audited against
|
|
86
|
+
the implementation and corrected. No library API changes (the only `src/`
|
|
87
|
+
edits are doc comments).
|
|
88
|
+
|
|
89
|
+
### Changed
|
|
90
|
+
- DESIGN.md restructured and de-duplicated; verified claim-by-claim
|
|
91
|
+
against the code (external `sdr-source` crate not "vendored", settle
|
|
92
|
+
timing attribution, real module/function names, HTTP format defaults,
|
|
93
|
+
feature-gating and platform caveats).
|
|
94
|
+
- README corrected: install snippet version, builder capabilities,
|
|
95
|
+
`futuresdr` feature-gating of `HttpSource`/`HttpSink`, Windows/Linux-only
|
|
96
|
+
`native-sdk` note, `AARONIA_SDK_PATH` macOS scope, links to the `docs/`
|
|
97
|
+
specifications and changelog.
|
|
98
|
+
- CONTRIBUTING now matches CI: pinned Miri nightly, the `cargo-deny` /
|
|
99
|
+
`cargo-hack` / `cargo-machete` gates, mutants/ASAN cron schedules,
|
|
100
|
+
toolchain floor (edition 2024), and the full test-suite inventory.
|
|
101
|
+
- docs/HTTPSPEC, docs/SDKSPEC, docs/FILESPEC corrected against the
|
|
102
|
+
implementation (wire-format details, endpoint coverage including
|
|
103
|
+
`GET /samples` and the `POST /sample` TX push, `sweepsa` open strings,
|
|
104
|
+
real API paths, enum numeric values, parser limits) with explicit
|
|
105
|
+
"known divergence" notes where only hardware can settle the truth.
|
|
106
|
+
- Clarified that HTTP retuning uses the license-free `/control` endpoint;
|
|
107
|
+
the "Remote Config" license gates only `/remoteconfig` writes
|
|
108
|
+
(stale doc comment on `set_center_frequency` fixed to match).
|
|
109
|
+
- Examples cleaned up: emoji removed, `noaa_scanner` doc header rewritten,
|
|
110
|
+
`http_iq_quickstart` now takes the server URL as an argument instead of
|
|
111
|
+
hardcoding a private hostname.
|
|
112
|
+
- Five assertion-free tests now actually assert.
|
|
113
|
+
|
|
114
|
+
### Fixed
|
|
115
|
+
- Stale comments: `native_sdk_load` symbol count, `spec_coverage` row
|
|
116
|
+
pointing at a renamed property test, bench comments describing mmap and
|
|
117
|
+
inverted `?scale=` semantics (the `parse_int16_packet` bench now passes
|
|
118
|
+
an encode-side scale, matching live-verified server behavior).
|
|
119
|
+
|
|
120
|
+
## [v0.3.4] - 2026-07-31
|
|
121
|
+
|
|
122
|
+
### Fixed
|
|
123
|
+
- **Native SDK: the tail of every oversized IQ packet was discarded.**
|
|
124
|
+
`NativeSdkSource::read_samples` copied `min(packet.num, max_samples)`
|
|
125
|
+
samples and then consumed the *whole* packet via
|
|
126
|
+
`AARTSAAPI_ConsumePackets`. The SDK picks its own packet size, unrelated
|
|
127
|
+
to the caller's `max_samples`, so anything past the request was lost
|
|
128
|
+
permanently — consuming returns the buffer to the SDK. `block_size` is
|
|
129
|
+
caller-set with only a 1024 floor, so a modest block size against
|
|
130
|
+
`AARTSAAPI_MEMORY_MEDIUM` packets left the IQ stream full of holes, which
|
|
131
|
+
breaks the phase continuity downstream ZC correlation and CFO tracking
|
|
132
|
+
depend on. Excess samples are now retained in the (previously dead)
|
|
133
|
+
`sample_buffer` and returned by subsequent calls, mirroring the HTTP
|
|
134
|
+
path's remainder handling. See `read_samples`' new "Carry-over" section;
|
|
135
|
+
`get_sample_buffer_size()` now reports something real.
|
|
136
|
+
- **Native SDK: `read_samples(.., 0)` destroyed a packet.** A zero-sized
|
|
137
|
+
request used to fetch a packet, copy nothing out of it, and consume it.
|
|
138
|
+
It now returns early without polling.
|
|
139
|
+
- **`sdk_sink`: TX bursts were scheduled at the Unix epoch.** The FutureSDR
|
|
140
|
+
sink block built every `TxBurst` with `start_time: 0.0`, contradicting
|
|
141
|
+
`TxBurst`'s own documentation that the device schedules against its
|
|
142
|
+
master stream clock. Timestamps are now derived from
|
|
143
|
+
`AARTSAAPI_GetMasterStreamTime` with a 10 ms lead, falling back to the
|
|
144
|
+
documented `PUSH` immediate-dispatch flag when the clock is unreadable.
|
|
145
|
+
Hardware-unverified, like the rest of the TX path.
|
|
146
|
+
- **`http_source`: reported buffer capacity disagreed with the enforced
|
|
147
|
+
one.** The cap was written twice — `saturating_mul(2).max(1)` where it
|
|
148
|
+
was enforced, a bare `* 2` where `StreamStats` reported it. With
|
|
149
|
+
`buffer_size: 0` (which the builder accepts) `buffer_level` could exceed
|
|
150
|
+
`buffer_capacity`, and a consumer computing a fill ratio divided by zero.
|
|
151
|
+
- **Diagnostic previews truncated on byte offsets, not char boundaries.**
|
|
152
|
+
`&text[..n]` panics when `n` lands inside a multi-byte UTF-8 character,
|
|
153
|
+
and these previews print raw RTSA responses carrying device/mission/
|
|
154
|
+
antenna names straight from user configuration — one non-ASCII character
|
|
155
|
+
in a mission title was enough to panic a diagnostic run.
|
|
156
|
+
|
|
157
|
+
### Changed
|
|
158
|
+
- **`cargo clippy --all-targets` now compiles on a default checkout.**
|
|
159
|
+
`tests/http_sink_test.rs` needs the `futuresdr` feature but declared no
|
|
160
|
+
`required-features`, so the documented lint command failed with `cannot
|
|
161
|
+
find module or crate futuresdr`.
|
|
162
|
+
- **`SdkConfig::timeout` and `SdkSinkConfig::timeout` documented as
|
|
163
|
+
inert.** Neither is read by any code path; the only timeout in force on
|
|
164
|
+
the read path is the fixed 500 ms `NativeSdkSource::READ_POLL_DEADLINE`.
|
|
165
|
+
Both fields are kept — they are `pub` on a published crate — but now say
|
|
166
|
+
so. Honouring them would change `read_samples`' signature, so that is
|
|
167
|
+
left as a deliberate decision for a future major.
|
|
168
|
+
|
|
169
|
+
## [v0.3.3] - 2026-07-31
|
|
170
|
+
|
|
171
|
+
### Fixed
|
|
172
|
+
- **`broad_search_for_chunk` could loop forever.** The RTSA chunk scan did
|
|
173
|
+
not terminate at EOF, so a file whose signature was absent and whose
|
|
174
|
+
search bound exceeded its length spun indefinitely — reachable from
|
|
175
|
+
`RtsaSource::open` on an untrusted file.
|
|
176
|
+
- **`verify_config_changes` leaked probed device state.** A failed
|
|
177
|
+
read-back returned early without restoring the parameter it had just
|
|
178
|
+
offset, leaving the device 1 dB from where it started. The restore now
|
|
179
|
+
runs on every path out, and logs when both the read-back and the restore
|
|
180
|
+
fail.
|
|
181
|
+
|
|
182
|
+
## [v0.3.2] - 2026-07-13
|
|
183
|
+
|
|
184
|
+
### Added
|
|
185
|
+
- **`DwellAdvice::channel_override` is now honored**, and the Remote Config
|
|
186
|
+
license gate was dropped from hop mode — channel hopping works on
|
|
187
|
+
unlicensed devices via the free `/control` endpoint.
|
|
188
|
+
|
|
189
|
+
## [v0.3.1] - 2026-07-11
|
|
190
|
+
|
|
191
|
+
### Fixed
|
|
192
|
+
- **Decompression: out-of-range `compression_factor` rejected up front.**
|
|
193
|
+
`Decompressor::decompress` now rejects `compression_factor > 31` (the
|
|
194
|
+
documented range per `docs/FILESPEC.md`, "1 to 31 for lossy factor")
|
|
195
|
+
instead of letting it reach `dequantize`'s `1i32 << (compression_factor -
|
|
196
|
+
1)`, which overflows the sign bit at 32 (silently producing a negative
|
|
197
|
+
quantizer) and panics on overflow at 33+ in debug builds. This value can
|
|
198
|
+
originate from a parsed HTTP-stream packet, so a malformed/corrupt header
|
|
199
|
+
could previously reach the panic.
|
|
200
|
+
- **Decompression: over-produced coefficients truncated, not just
|
|
201
|
+
under-produced ones.** `decompress` already zero-padded a coefficient
|
|
202
|
+
stream shorter than `num_rows * num_cols`; it now also truncates a longer
|
|
203
|
+
one, since `wave_transform_step` derives its own row count from the raw
|
|
204
|
+
buffer length rather than the caller's declared dimensions and would
|
|
205
|
+
otherwise silently operate on more rows than requested.
|
|
206
|
+
- **Aaronia capture thread now panic-guarded**, matching the driver crates
|
|
207
|
+
(USRP/HackRF/Pluto): the `AaroniaSdrSource::start` capture thread body is
|
|
208
|
+
wrapped in `catch_unwind`, so a panic inside it is logged instead of
|
|
209
|
+
silently unwinding the thread with no diagnostic.
|
|
210
|
+
- **HTTP overrun detection wired to `IqPacket::overrun`.** The HTTP reader
|
|
211
|
+
task now runs a `DropDetector` over each packet's timing metadata; a
|
|
212
|
+
detected gap latches a flag that `AaroniaSource::take_overrun()` surfaces
|
|
213
|
+
on the next `read_samples` call. `single_channel_pump`/`hop_pump` in
|
|
214
|
+
`sdr_source_impl.rs` now report real overrun status instead of
|
|
215
|
+
hardcoding `false`. The native-SDK and file backends still report `false`
|
|
216
|
+
(unchanged).
|
|
217
|
+
- **`aaronia_source_read_samples` (C API) copy bound hardened.** The FFI
|
|
218
|
+
sample-copy now clamps to `temp_samples.len()` in addition to the
|
|
219
|
+
caller-supplied capacity, so a hypothetical future miscount from
|
|
220
|
+
`read_samples` can't cause an out-of-bounds read; added a compile-time
|
|
221
|
+
size assertion between `FfiComplex` and `Complex32` guarding the
|
|
222
|
+
reinterpret cast.
|
|
223
|
+
- **`orecchiette-sdr-source-rs` dependency floor** bumped from `0.1.0` to
|
|
224
|
+
`0.1.2` to match every sibling crate's declared floor.
|
|
225
|
+
|
|
226
|
+
## [v0.3.0] - 2026-07-11
|
|
227
|
+
|
|
228
|
+
### Removed
|
|
229
|
+
- **BREAKING: `file_performance` module removed** (`MmapRtsaReader`,
|
|
230
|
+
`AdaptiveChunkReader`, `AccessStats`, `CacheStats`, `ChunkType`, and the
|
|
231
|
+
`memmap2` dependency). This tiered-cache, adaptive-read-ahead
|
|
232
|
+
memory-mapped reader was never wired into the crate's actual file-reading
|
|
233
|
+
path — `RtsaSource` (the real hot path, used by every file-source
|
|
234
|
+
consumer) has always read via buffered `std::io` and never touched this
|
|
235
|
+
module. It had zero callers anywhere in the crate outside its own tests.
|
|
236
|
+
If you were depending on these types directly, buffered access through
|
|
237
|
+
`RtsaSource` covers the same file-reading needs; there is no drop-in
|
|
238
|
+
replacement for the standalone mmap/cache API itself.
|
|
239
|
+
|
|
240
|
+
### Fixed
|
|
241
|
+
- **`HttpSourceBuilder` doc comment misplacement:** the "no-op kept for
|
|
242
|
+
backward compatibility" doc comment was attached to `with_shared_stats`
|
|
243
|
+
(which is not a no-op — it wires up the retune/stats-sharing mechanism)
|
|
244
|
+
instead of `with_native_sdk` (the actual no-op immediately below it).
|
|
245
|
+
Moved to the correct method and gave `with_shared_stats` an accurate doc.
|
|
246
|
+
- **`HttpSink` dropped-sample accounting:** `push_batch` now counts a batch
|
|
247
|
+
as dropped when the background sender task's channel is closed (e.g. the
|
|
248
|
+
task panicked), not just on a failed/timed-out HTTP push. Previously this
|
|
249
|
+
failure mode silently discarded samples without incrementing
|
|
250
|
+
`dropped_samples()` — the documented way to detect a persistently broken
|
|
251
|
+
TX link. `HttpSink` also now aborts its background sender task on drop
|
|
252
|
+
instead of relying on the channel closing to signal it.
|
|
253
|
+
|
|
254
|
+
### Changed
|
|
255
|
+
- **Native SDK error handling finished:** the last four `NativeSdkClient`
|
|
256
|
+
methods that still hand-rolled their own `AARTSAAPI_Result` check
|
|
257
|
+
(`enum_device`, `config_first`, `config_next`, `get_packet`) now route
|
|
258
|
+
through the `check_res`/`Error::SdkApi` path introduced in v0.2.6,
|
|
259
|
+
matching every other method in the client. Behavior is unchanged for
|
|
260
|
+
callers (`AARTSAAPI_EMPTY` still maps to `Ok(None)`/`Ok(false)`); failures
|
|
261
|
+
now carry a structured `SdkError` instead of a formatted string.
|
|
262
|
+
- **De-duplicated `device_family`/`device_open_mode`:** `SdkConfig` and
|
|
263
|
+
`SdkSinkConfig` shared byte-for-byte identical device-type-splitting
|
|
264
|
+
logic (differing only in the default open-mode suffix, `raw` vs.
|
|
265
|
+
`iqtransmitter`). Extracted into `native_sdk::split_device_type`; both
|
|
266
|
+
public methods keep their existing signatures.
|
|
267
|
+
|
|
268
|
+
## [v0.2.6] - 2026-07-10
|
|
269
|
+
|
|
270
|
+
### Added
|
|
271
|
+
- **Native SDK Transmitter (TX):** Added transmit capabilities through the C++ Native SDK (`SdkSink` and `SdkSinkConfig`). This provides TX path parity with the `SdkSource` and includes FutureSDR integration (`SdkSinkBlock`).
|
|
272
|
+
- **Examples:** Added `examples/native_sdk_transmit.rs` to demonstrate programmatic device configuration, master stream time-driven packet pacing, and sending a continuous LoRa-like CSS up-chirp.
|
|
273
|
+
|
|
274
|
+
### Changed
|
|
275
|
+
- **Granular Errors:** Migrated the opaque `Error::Sdk(String)` to a structured `Error::SdkApi { operation: &'static str, code: SdkError }` to allow programmatic error recovery.
|
|
276
|
+
- **Warning Isolation:** The Native SDK C++ FFI bindings now correctly categorize and log warnings (codes with the `0x40000000` bit set) rather than escalating them to fatal errors, mapping closely to the official Aaronia Java/C++ driver behaviors.
|
|
277
|
+
|
|
278
|
+
## [v0.2.4] - 2026-07-10
|
|
279
|
+
|
|
280
|
+
### Performance
|
|
281
|
+
- **HTTP stream parser:** binary formats (int16/float16/float32) now
|
|
282
|
+
deserialize `PacketMetadata` straight from the header bytes instead of
|
|
283
|
+
building — and discarding — a full `serde_json::Value` DOM per packet.
|
|
284
|
+
`parse_int16_packet` improves ~41% at 256 samples/packet down to ~6% at
|
|
285
|
+
64k (the header cost amortizes over larger payloads). The pure-JSON
|
|
286
|
+
stream still uses the DOM, since it reads sample values from it.
|
|
287
|
+
- **Float32 IQ parse:** on little-endian hosts the payload is bulk-copied
|
|
288
|
+
in one `memcpy` into an aligned `Vec<Complex32>` instead of decoding each
|
|
289
|
+
`f32` individually (portable per-element fallback on big-endian).
|
|
290
|
+
- **RTSA file replay:** IQ/spectra sample reads now do one bulk `read_exact`
|
|
291
|
+
+ in-memory decode instead of two `read_f32`/`read_i16` calls per sample.
|
|
292
|
+
- **Native SDK `read_samples`** logs per-read at `trace!` instead of
|
|
293
|
+
`info!`, so an enabled info subscriber no longer pays formatting cost on
|
|
294
|
+
the hot path.
|
|
295
|
+
- Minor: `HttpSource` bulk-`extend`s its sample ring buffer rather than
|
|
296
|
+
pushing element-by-element; the unified HTTP source reuses one
|
|
297
|
+
connection-pooled client for its reader task instead of building a
|
|
298
|
+
second.
|
|
299
|
+
|
|
300
|
+
### Fixed
|
|
301
|
+
- **Native SDK `read_samples` soundness:** the wide-stride (`stride > 2`) IQ
|
|
302
|
+
gather path underflowed `usize` when `max_samples == 0`, handing
|
|
303
|
+
`slice::from_raw_parts` a ~`usize::MAX` length (UB). It now skips the empty
|
|
304
|
+
case, `packet.num` is bound-checked before the `* 2` to avoid an `i64`
|
|
305
|
+
overflow on a malformed packet count, and `packet.stride` is sanity-bounded
|
|
306
|
+
(a corrupt oversized stride would otherwise size an out-of-bounds slice).
|
|
307
|
+
- **`AaroniaSource` HTTP streaming-task leak:** the background `/stream` reader
|
|
308
|
+
is now aborted on `stop_streaming()` and on drop, instead of lingering
|
|
309
|
+
(holding the open connection, so the device kept streaming) until the next
|
|
310
|
+
packet arrived.
|
|
311
|
+
- **`Decompressor::decompress`** rejects zero `num_rows`/`num_cols` instead of
|
|
312
|
+
spinning the inverse-wavelet loop forever / dividing by zero.
|
|
313
|
+
- **`MmapRtsaReader::read_chunk`** bounds check uses `checked_add`, so a
|
|
314
|
+
pathological offset can't wrap past it into an out-of-bounds slice.
|
|
315
|
+
- **`HttpSourceBuilder`** default reference level corrected from `+20 dBm` to
|
|
316
|
+
`-20 dBm` (matching `AaroniaConfig`); the old default desensitized the
|
|
317
|
+
receiver. The mislabeled "dB" unit comment is fixed too.
|
|
318
|
+
- **`HttpSource::work`** now requests re-scheduling (`io.call_again`) after a
|
|
319
|
+
stream-error reconnect.
|
|
320
|
+
|
|
321
|
+
### Changed
|
|
322
|
+
- **`HttpSink` `timeout_ms`** is now honored: each transmit push is bounded by
|
|
323
|
+
it (timed-out batches count as dropped) and `HttpSinkBuilder::timeout_ms`
|
|
324
|
+
exposes the knob. Previously the value was silently ignored.
|
|
325
|
+
- README install snippet updated to the current `0.2` version line.
|
|
326
|
+
|
|
327
|
+
## [v0.2.3] - 2026-07-05
|
|
328
|
+
|
|
329
|
+
### Fixed
|
|
330
|
+
- **HTTP source now tunes the device on startup.** `init_http_source` was opening `/stream` without first sending a `/control` capture-configuration request, so the SDR always streamed whatever frequency the RTSA Suite happened to be configured to (typically 300 MHz) — completely ignoring the caller's `center_frequency` and `span_frequency`. A `configure_capture` call is now issued before the stream is opened, matching the Native SDK path's behaviour.
|
|
331
|
+
|
|
332
|
+
### Changed
|
|
333
|
+
- `http_iq_quickstart` example: added CLI arguments for frequency and sample rate, periodic signal-power logging to stderr, and fixed a clippy `needless_borrow` lint.
|
|
334
|
+
|
|
335
|
+
## [v0.2.2] - 2026-07-05
|
|
336
|
+
|
|
337
|
+
### Changed
|
|
338
|
+
- Dropped explicit MSRV (Minimum Supported Rust Version) policy to track the latest `stable` Rust compiler.
|
|
339
|
+
- Updated `.github/workflows/ci.yml` to compile tests, clippy, and coverage against `stable` instead of hardcoding an older MSRV. This prevents transitive dependencies that bump their MSRVs from breaking CI.
|
|
340
|
+
|
|
341
|
+
## [v0.2.1] - 2026-07-05
|
|
342
|
+
|
|
343
|
+
### Added
|
|
344
|
+
- Native SDK support for configurable receiver channel (`Rx1`, `Rx2`, `Rx1And2`).
|
|
345
|
+
- Support for setting HTTP wire format and stream scale in `AaroniaConfig` and `AaroniaSourceBuilder`.
|
|
346
|
+
- Updated `README.md` with a quickstart guide and more detailed examples.
|
|
347
|
+
|
|
348
|
+
### Fixed
|
|
349
|
+
- Fixed CI build failures by bumping MSRV to 1.86 and allowing the `Zlib` license in cargo-deny.
|
|
350
|
+
- Changed default HTTP streaming format to `Float32` instead of `Json` to fix high-bandwidth crashes.
|
|
351
|
+
- Resolved `FutureSDR` block execution deadlocks inside `HttpSink` by offloading `reqwest` synchronous HTTP I/O into a detached `tokio` background task.
|
|
352
|
+
|
|
353
|
+
## [v0.1.1] - 2026-07-03
|
|
354
|
+
|
|
355
|
+
### Changed
|
|
356
|
+
- Disable `futuresdr` on docs.rs and bump to 0.1.1
|
|
357
|
+
- Fix license badge by using GitHub endpoint instead of crates.io
|
|
358
|
+
- Update Cargo.lock for 0.1.1
|
|
359
|
+
|
|
360
|
+
## [v0.1.0] - 2026-07-03
|
|
361
|
+
|
|
362
|
+
### Added
|
|
363
|
+
- Initial release.
|
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
# Contributing to sdr-aaronia-rs
|
|
2
|
+
|
|
3
|
+
First off, thank you for considering contributing to `sdr-aaronia-rs`! This document explains how the test suite is organized, which tools you'll need, and how to verify your changes locally before opening a pull request.
|
|
4
|
+
|
|
5
|
+
**Toolchain:** the crate uses the 2024 edition, so you need Rust 1.85 or newer. There is no pinned `rust-toolchain.toml`; CI tracks the latest `stable`.
|
|
6
|
+
|
|
7
|
+
## Quick Start
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
git clone https://github.com/isaacbentley/sdr-aaronia-rs.git
|
|
11
|
+
cd sdr-aaronia-rs
|
|
12
|
+
|
|
13
|
+
# Run the standard validation suite
|
|
14
|
+
cargo test # unit + integration + properties (default features)
|
|
15
|
+
cargo test --test spec_coverage -- --nocapture # spec inventory report
|
|
16
|
+
cargo clippy --all-features --all-targets -- -D warnings
|
|
17
|
+
cargo fmt --all --check
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
Note that a plain `cargo test` builds with the default features; suites gated on non-default features (e.g. `http_sink_test`, which needs `futuresdr`) are skipped. CI runs `cargo test --all-features`.
|
|
21
|
+
|
|
22
|
+
## Pre-push: mirror CI locally
|
|
23
|
+
|
|
24
|
+
Before pushing (or opening a PR), run the CI-parity script:
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
scripts/ci-local.sh
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
It reproduces the **exact** command each GitHub Actions job runs — fmt,
|
|
31
|
+
clippy, `cargo test --all-features`, `cargo deny --all-features check`,
|
|
32
|
+
`cargo hack check --each-feature --no-dev-deps`, `cargo machete`, and
|
|
33
|
+
the pinned-nightly Miri module suite — and fails fast with install
|
|
34
|
+
hints for any missing tool. Skip individual steps with e.g.
|
|
35
|
+
`SKIP="miri hack" scripts/ci-local.sh` when iterating.
|
|
36
|
+
|
|
37
|
+
The `--all-features` flags matter: several CI jobs validate the
|
|
38
|
+
*all-features* dependency graph and feature set, so a default-features
|
|
39
|
+
`cargo test` / `cargo deny check` passing locally does **not** imply CI
|
|
40
|
+
will pass. If you edit `.github/workflows/ci.yml`, update
|
|
41
|
+
`scripts/ci-local.sh` in the same commit (and vice versa), and run
|
|
42
|
+
`actionlint .github/workflows/ci.yml`.
|
|
43
|
+
|
|
44
|
+
Two steps exist because macOS builds skip the OS-gated native-SDK
|
|
45
|
+
modules entirely (`cfg(any(windows, linux))`), which CI's ubuntu and
|
|
46
|
+
windows legs do compile:
|
|
47
|
+
|
|
48
|
+
- **cross** — `cargo clippy --target x86_64-unknown-linux-gnu` /
|
|
49
|
+
`x86_64-pc-windows-msvc` with `--features native-sdk`, via the rustup
|
|
50
|
+
`stable` toolchain (install the targets with `rustup target add
|
|
51
|
+
<triple> --toolchain stable`). Lib only — the gated *test* code needs
|
|
52
|
+
a real Linux environment.
|
|
53
|
+
- **vm** — runs `cargo test --features native-sdk --lib` inside a Linux
|
|
54
|
+
VM via Apple's `container` CLI (`container system start` first; the
|
|
55
|
+
step auto-skips when the tooling isn't running). This is the only
|
|
56
|
+
local step that compiles and runs `#[cfg(test)]` code inside the
|
|
57
|
+
gated modules — a missed struct field in exactly such a test once
|
|
58
|
+
shipped red to CI past every other local check.
|
|
59
|
+
|
|
60
|
+
Tiers 1–4 below are the core of the suite; the later tiers are optional but recommended if your pull request touches the parser, decompressor, or FFI surface.
|
|
61
|
+
|
|
62
|
+
## Test Pyramid
|
|
63
|
+
|
|
64
|
+
The crate is modeled on a layered test pyramid. Each tier catches a different class of bug; together they form the "definition of done" for our releases.
|
|
65
|
+
|
|
66
|
+
### 1. Unit Tests
|
|
67
|
+
|
|
68
|
+
Located alongside the code they test in `src/**/*.rs`. These cover format conversion, frequency parsing, builder defaults, struct sizes, and other basic utilities.
|
|
69
|
+
|
|
70
|
+
Run: `cargo test --lib`
|
|
71
|
+
|
|
72
|
+
### 2. Integration Tests (`tests/integration_test.rs`)
|
|
73
|
+
|
|
74
|
+
End-to-end tests against bundled `.rtsa` captures stored in Git LFS. The fixtures gracefully skip when LFS content isn't available. To run them fully, ensure you pull the LFS files:
|
|
75
|
+
|
|
76
|
+
```bash
|
|
77
|
+
git lfs pull
|
|
78
|
+
cargo test --test integration_test
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
Beyond the tiers named here, `tests/` also contains focused suites for the HTTP mock server (`http_mock_test.rs`), the HTTP sink (`http_sink_test.rs`, requires `futuresdr`), the C API (`c_api_test.rs`), the `sdr-source` implementation (`sdr_source_impl_test.rs`), RTSA negative cases (`rtsa_negative_test.rs`), CW fixtures (`test_cw_mag.rs`, `test_cw_meta.rs`), SDK library loading (`native_sdk_load.rs`), and opt-in live-hardware smoke tests (`live_smoke.rs`). All of these run as part of `cargo test` where their features and environment allow.
|
|
82
|
+
|
|
83
|
+
### 3. Property Tests (`tests/properties.rs`)
|
|
84
|
+
|
|
85
|
+
We use `proptest` to verify invariants of the parser, decompressor, and validator surfaces.
|
|
86
|
+
|
|
87
|
+
Run: `cargo test --test properties`
|
|
88
|
+
|
|
89
|
+
For a deeper verification pass (useful before submitting a PR):
|
|
90
|
+
```bash
|
|
91
|
+
PROPTEST_CASES=4096 cargo test --test properties --release
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
### 4. Invariant-Coverage Inventory (`tests/spec_coverage.rs`)
|
|
95
|
+
|
|
96
|
+
A single page enumerating which documented invariants the test suite enforces. **If you are adding a new invariant-bound test, please add a row to `ENFORCED` in `tests/spec_coverage.rs`.**
|
|
97
|
+
|
|
98
|
+
Run: `cargo test --test spec_coverage -- --nocapture`
|
|
99
|
+
|
|
100
|
+
### 5. Miri (Nightly)
|
|
101
|
+
|
|
102
|
+
Catches undefined behavior in safe Rust code. Because Miri refuses to interpret FFI, we only run it on the pure-Rust modules. CI pins `nightly-2026-01-01` because newer nightlies changed the `fadd_fast` intrinsic signature, which breaks the `futuredsp` dependency's build — use the same pin locally:
|
|
103
|
+
|
|
104
|
+
```bash
|
|
105
|
+
rustup toolchain install nightly-2026-01-01 --component miri
|
|
106
|
+
cargo +nightly-2026-01-01 miri test --lib decompression
|
|
107
|
+
cargo +nightly-2026-01-01 miri test --lib http_streaming
|
|
108
|
+
cargo +nightly-2026-01-01 miri test --lib utils
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
### 6. Code Coverage
|
|
112
|
+
|
|
113
|
+
Code coverage is reported to Codecov on PRs targeting `main` (uploaded from the Linux CI leg). Coverage is informational only and will not fail your build. To check coverage locally:
|
|
114
|
+
|
|
115
|
+
```bash
|
|
116
|
+
cargo install cargo-llvm-cov
|
|
117
|
+
cargo llvm-cov --html
|
|
118
|
+
open target/llvm-cov/html/index.html # xdg-open on Linux, start on Windows
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
### 7. Criterion Benchmarks (`benches/`)
|
|
122
|
+
|
|
123
|
+
Three benchmark harnesses track the hot paths across releases. Benchmarks are run on demand to investigate performance implications of a PR.
|
|
124
|
+
|
|
125
|
+
```bash
|
|
126
|
+
cargo bench # Run all benchmarks
|
|
127
|
+
cargo bench --bench parse_int16_packet # Run a specific harness
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
### 8. Mutation Testing
|
|
131
|
+
|
|
132
|
+
`cargo mutants` runs in CI on a weekly cron (Mondays) and on manual dispatch, advisory-only. To run it locally:
|
|
133
|
+
|
|
134
|
+
```bash
|
|
135
|
+
cargo install cargo-mutants
|
|
136
|
+
cargo mutants --no-shuffle --in-place=false --timeout=180
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
### 9. ASAN / UBSAN
|
|
140
|
+
|
|
141
|
+
The C FFI boundary is exercised under AddressSanitizer and UndefinedBehaviorSanitizer via `tests/asan/c_smoke.c`. CI runs this on a weekly cron (Tuesdays).
|
|
142
|
+
|
|
143
|
+
```bash
|
|
144
|
+
rustup toolchain install nightly
|
|
145
|
+
rustup component add rust-src --toolchain nightly
|
|
146
|
+
# On Debian/Ubuntu, the sanitizer runtimes are also needed:
|
|
147
|
+
sudo apt-get install llvm libubsan1
|
|
148
|
+
bash tests/asan/run_asan.sh
|
|
149
|
+
```
|
|
150
|
+
*(Note: ASAN scripts currently require a Linux environment.)*
|
|
151
|
+
|
|
152
|
+
### 10. Dependency Hygiene (CI-enforced)
|
|
153
|
+
|
|
154
|
+
Three additional CI jobs gate every PR; run their tools locally if your change touches dependencies or features:
|
|
155
|
+
|
|
156
|
+
```bash
|
|
157
|
+
cargo install cargo-deny cargo-hack cargo-machete
|
|
158
|
+
cargo deny check # licenses/advisories/bans, driven by deny.toml
|
|
159
|
+
cargo hack check --each-feature --no-dev-deps # every feature combination compiles
|
|
160
|
+
cargo machete # no unused dependencies
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
## Adding a New Spec Invariant
|
|
164
|
+
|
|
165
|
+
When you encounter a documented invariant in `docs/*.md` that the test suite doesn't currently enforce:
|
|
166
|
+
1. Name the test `prop_<short_description>` or `spec_<area>_<behavior>`.
|
|
167
|
+
2. Add a `///` doc comment describing the invariant the test pins.
|
|
168
|
+
3. Add a row to the `ENFORCED` table in `tests/spec_coverage.rs`.
|
|
169
|
+
4. Run `cargo test --test spec_coverage -- --nocapture` and confirm your row appears.
|
|
170
|
+
|
|
171
|
+
## Code Style
|
|
172
|
+
|
|
173
|
+
We use standard `rustfmt` defaults. Please run `cargo fmt --all` before pushing.
|
|
174
|
+
|
|
175
|
+
Clippy is run with `-D warnings` in CI. If a lint is genuinely wrong for the situation, use a targeted `#[allow(...)]` with a brief comment explaining why. `unsafe` blocks carry the usual `// SAFETY:` invariant comments.
|
|
176
|
+
|
|
177
|
+
## Pull Requests
|
|
178
|
+
|
|
179
|
+
- **Commit messages:** Conventional-commits style is preferred but not required. Describe *why* the change is needed and *what* it changes.
|
|
180
|
+
- **Templates:** Please fill out the Pull Request template when opening a PR. It includes checkboxes for the CI validations and a mandatory AI-usage disclosure section.
|
|
181
|
+
|
|
182
|
+
## License
|
|
183
|
+
|
|
184
|
+
By contributing, you agree your contributions will be licensed under GPL-3.0-or-later, the same as the rest of the project.
|