python-aaronia 0.13.1__tar.gz → 0.13.3__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.13.1 → python_aaronia-0.13.3}/CHANGELOG.md +31 -0
- {python_aaronia-0.13.1 → python_aaronia-0.13.3}/Cargo.lock +14 -14
- {python_aaronia-0.13.1 → python_aaronia-0.13.3}/Cargo.toml +58 -10
- {python_aaronia-0.13.1 → python_aaronia-0.13.3}/PKG-INFO +4 -1
- {python_aaronia-0.13.1 → python_aaronia-0.13.3}/examples/native_sdk_basic.rs +4 -2
- {python_aaronia-0.13.1 → python_aaronia-0.13.3}/examples/native_sdk_qualification.rs +4 -2
- {python_aaronia-0.13.1 → python_aaronia-0.13.3}/examples/native_sdk_transmit.rs +4 -2
- {python_aaronia-0.13.1 → python_aaronia-0.13.3}/include/spectran.h +33 -16
- python_aaronia-0.13.3/packaging/homebrew/soapy-aaronia.rb +76 -0
- {python_aaronia-0.13.1 → python_aaronia-0.13.3}/pyproject.toml +4 -0
- {python_aaronia-0.13.1 → python_aaronia-0.13.3}/python-aaronia/Cargo.toml +1 -1
- {python_aaronia-0.13.1 → python_aaronia-0.13.3}/python-aaronia/aaronia.pyi +7 -2
- {python_aaronia-0.13.1 → python_aaronia-0.13.3}/python-aaronia/src/lib.rs +309 -159
- {python_aaronia-0.13.1 → python_aaronia-0.13.3}/python-aaronia/test_basic.py +31 -0
- {python_aaronia-0.13.1 → python_aaronia-0.13.3}/scripts/ci-local.sh +2 -1
- {python_aaronia-0.13.1 → python_aaronia-0.13.3}/soapy-aaronia/CMakeLists.txt +12 -4
- {python_aaronia-0.13.1 → python_aaronia-0.13.3}/soapy-aaronia/README.md +1 -1
- {python_aaronia-0.13.1 → python_aaronia-0.13.3}/soapy-aaronia/Registration.cpp +26 -2
- {python_aaronia-0.13.1 → python_aaronia-0.13.3}/soapy-aaronia/SpectranSoapyDevice.cpp +163 -53
- {python_aaronia-0.13.1 → python_aaronia-0.13.3}/soapy-aaronia/SpectranSoapyDevice.hpp +5 -0
- {python_aaronia-0.13.1 → python_aaronia-0.13.3}/src/c_api.rs +1524 -964
- {python_aaronia-0.13.1 → python_aaronia-0.13.3}/src/capabilities.rs +2 -1
- {python_aaronia-0.13.1 → python_aaronia-0.13.3}/src/decompression.rs +10 -10
- {python_aaronia-0.13.1 → python_aaronia-0.13.3}/src/detection.rs +84 -31
- {python_aaronia-0.13.1 → python_aaronia-0.13.3}/src/file_source.rs +162 -36
- {python_aaronia-0.13.1 → python_aaronia-0.13.3}/src/http_endpoints.rs +24 -1
- {python_aaronia-0.13.1 → python_aaronia-0.13.3}/src/http_sink.rs +45 -37
- {python_aaronia-0.13.1 → python_aaronia-0.13.3}/src/http_source.rs +182 -84
- {python_aaronia-0.13.1 → python_aaronia-0.13.3}/src/http_streaming.rs +154 -49
- {python_aaronia-0.13.1 → python_aaronia-0.13.3}/src/lib.rs +48 -17
- {python_aaronia-0.13.1 → python_aaronia-0.13.3}/src/link_budget.rs +1 -0
- {python_aaronia-0.13.1 → python_aaronia-0.13.3}/src/native_sdk.rs +593 -208
- {python_aaronia-0.13.1 → python_aaronia-0.13.3}/src/native_sdk_lifecycle_tests.rs +82 -13
- {python_aaronia-0.13.1 → python_aaronia-0.13.3}/src/sdk_sink.rs +152 -27
- {python_aaronia-0.13.1 → python_aaronia-0.13.3}/src/sdk_source.rs +84 -28
- {python_aaronia-0.13.1 → python_aaronia-0.13.3}/src/seify_impl.rs +145 -57
- {python_aaronia-0.13.1 → python_aaronia-0.13.3}/src/stream_geometry.rs +16 -2
- {python_aaronia-0.13.1 → python_aaronia-0.13.3}/src/unified_sink.rs +148 -18
- {python_aaronia-0.13.1 → python_aaronia-0.13.3}/src/unified_source.rs +523 -306
- {python_aaronia-0.13.1 → python_aaronia-0.13.3}/src/utils.rs +165 -27
- {python_aaronia-0.13.1 → python_aaronia-0.13.3}/tests/abi_drift.rs +32 -10
- python_aaronia-0.13.3/tests/c_api_test.rs +228 -0
- {python_aaronia-0.13.1 → python_aaronia-0.13.3}/tests/http_sink_test.rs +33 -0
- {python_aaronia-0.13.1 → python_aaronia-0.13.3}/tests/native_sdk_live.rs +2 -1
- {python_aaronia-0.13.1 → python_aaronia-0.13.3}/tests/native_sdk_load.rs +2 -1
- python_aaronia-0.13.1/packaging/homebrew/soapy-aaronia.rb +0 -47
- python_aaronia-0.13.1/tests/c_api_test.rs +0 -107
- {python_aaronia-0.13.1 → python_aaronia-0.13.3}/.cargo/config.toml +0 -0
- {python_aaronia-0.13.1 → python_aaronia-0.13.3}/.gitattributes +0 -0
- {python_aaronia-0.13.1 → python_aaronia-0.13.3}/.gitignore +0 -0
- {python_aaronia-0.13.1 → python_aaronia-0.13.3}/CONTRIBUTING.md +0 -0
- {python_aaronia-0.13.1 → python_aaronia-0.13.3}/DESIGN.md +0 -0
- {python_aaronia-0.13.1 → python_aaronia-0.13.3}/LICENSE +0 -0
- {python_aaronia-0.13.1 → python_aaronia-0.13.3}/PLUGINS.md +0 -0
- {python_aaronia-0.13.1 → python_aaronia-0.13.3}/README.md +0 -0
- {python_aaronia-0.13.1 → python_aaronia-0.13.3}/benches/decompress_block.rs +0 -0
- {python_aaronia-0.13.1 → python_aaronia-0.13.3}/benches/deinterleave_dual_iq.rs +0 -0
- {python_aaronia-0.13.1 → python_aaronia-0.13.3}/benches/parse_int16_packet.rs +0 -0
- {python_aaronia-0.13.1 → python_aaronia-0.13.3}/benches/rtsa_open_and_read.rs +0 -0
- {python_aaronia-0.13.1 → python_aaronia-0.13.3}/deny.toml +0 -0
- {python_aaronia-0.13.1 → python_aaronia-0.13.3}/docs/APPS.md +0 -0
- {python_aaronia-0.13.1 → python_aaronia-0.13.3}/docs/FILESPEC.md +0 -0
- {python_aaronia-0.13.1 → python_aaronia-0.13.3}/docs/HTTPSPEC.md +0 -0
- {python_aaronia-0.13.1 → python_aaronia-0.13.3}/docs/NATIVE_SDK_COMPATIBILITY.md +0 -0
- {python_aaronia-0.13.1 → python_aaronia-0.13.3}/docs/QUICKSTART.md +0 -0
- {python_aaronia-0.13.1 → python_aaronia-0.13.3}/docs/SDKSPEC.md +0 -0
- {python_aaronia-0.13.1 → python_aaronia-0.13.3}/docs/SYNC.md +0 -0
- {python_aaronia-0.13.1 → python_aaronia-0.13.3}/docs/USAGE.md +0 -0
- {python_aaronia-0.13.1 → python_aaronia-0.13.3}/docs/VERIFICATION.md +0 -0
- {python_aaronia-0.13.1 → python_aaronia-0.13.3}/examples/device_control.rs +0 -0
- {python_aaronia-0.13.1 → python_aaronia-0.13.3}/examples/dump_metadata.rs +0 -0
- {python_aaronia-0.13.1 → python_aaronia-0.13.3}/examples/http_iq_quickstart.rs +0 -0
- {python_aaronia-0.13.1 → python_aaronia-0.13.3}/examples/noaa_scanner.rs +0 -0
- {python_aaronia-0.13.1 → python_aaronia-0.13.3}/examples/python_arrow_example.py +0 -0
- {python_aaronia-0.13.1 → python_aaronia-0.13.3}/examples/read_rtsa_file.rs +0 -0
- {python_aaronia-0.13.1 → python_aaronia-0.13.3}/examples/soapy_python_example.py +0 -0
- {python_aaronia-0.13.1 → python_aaronia-0.13.3}/packaging/homebrew/README.md +0 -0
- {python_aaronia-0.13.1 → python_aaronia-0.13.3}/python-aaronia/README.md +0 -0
- {python_aaronia-0.13.1 → python_aaronia-0.13.3}/scripts/fake-rtsa-server.py +0 -0
- {python_aaronia-0.13.1 → python_aaronia-0.13.3}/scripts/native-sdk-validate.ps1 +0 -0
- {python_aaronia-0.13.1 → python_aaronia-0.13.3}/scripts/sdk-container-test.sh +0 -0
- {python_aaronia-0.13.1 → python_aaronia-0.13.3}/scripts/validate-iq-live.py +0 -0
- {python_aaronia-0.13.1 → python_aaronia-0.13.3}/soapy-aaronia/packaging/install.ps1 +0 -0
- {python_aaronia-0.13.1 → python_aaronia-0.13.3}/soapy-aaronia/packaging/install.sh +0 -0
- {python_aaronia-0.13.1 → python_aaronia-0.13.3}/src/error.rs +0 -0
- {python_aaronia-0.13.1 → python_aaronia-0.13.3}/src/stream_break.rs +0 -0
- {python_aaronia-0.13.1 → python_aaronia-0.13.3}/tests/http_mock_test.rs +0 -0
- {python_aaronia-0.13.1 → python_aaronia-0.13.3}/tests/http_resilience_test.rs +0 -0
- {python_aaronia-0.13.1 → python_aaronia-0.13.3}/tests/integration_test.rs +0 -0
- {python_aaronia-0.13.1 → python_aaronia-0.13.3}/tests/live_smoke.rs +0 -0
- {python_aaronia-0.13.1 → python_aaronia-0.13.3}/tests/properties.proptest-regressions +0 -0
- {python_aaronia-0.13.1 → python_aaronia-0.13.3}/tests/properties.rs +0 -0
- {python_aaronia-0.13.1 → python_aaronia-0.13.3}/tests/rtsa_negative_test.rs +0 -0
- {python_aaronia-0.13.1 → python_aaronia-0.13.3}/tests/spec_coverage.rs +0 -0
- {python_aaronia-0.13.1 → python_aaronia-0.13.3}/tests/test_cw_mag.rs +0 -0
- {python_aaronia-0.13.1 → python_aaronia-0.13.3}/tests/test_cw_meta.rs +0 -0
- {python_aaronia-0.13.1 → python_aaronia-0.13.3}/tests/wire_contract.rs +0 -0
|
@@ -4,6 +4,37 @@ All notable changes to this project will be documented in this file.
|
|
|
4
4
|
|
|
5
5
|
## [Unreleased]
|
|
6
6
|
|
|
7
|
+
## [v0.13.3] - 2026-11-10
|
|
8
|
+
|
|
9
|
+
### Added
|
|
10
|
+
- `SpectranSource::new_with_options`, `SpectranSourceBuilder::listen_only`, `spectran_source_builder_listen_only`, SoapySDR `listen_only` device arg, and Python `SpectranSource.listen_only` to connect to HTTP streams without issuing `/remoteconfig` or `/control` tuning writes.
|
|
11
|
+
- `SdkSink` and `SpectranSink` serial selection (`device_serial` / `spectran_sink_builder_device_serial`) plus C ABI TX controls (`spectran_sink_set_center_frequency_hz`, `spectran_sink_set_sample_rate_hz`, `spectran_sink_set_trans_gain_db`, `spectran_sink_get_master_stream_time_ns`) and full SoapySDR TX frequency, sample-rate, gain, serial, and burst-timestamp support.
|
|
12
|
+
- `AARONIA_NATIVE_SDK=ON` enabled by default on 64-bit Linux and Windows SoapySDR builds (including CI and release artifacts), and crate-root re-exports completed across `sdr-aaronia-rs`.
|
|
13
|
+
|
|
14
|
+
### Fixed
|
|
15
|
+
- Wrapped all 48 `extern "C" spectran_*` entry points in `catch_unwind`, made `FFI_RUNTIME` initialization fallible and `LocalSet`-safe, saturated `Instant` read deadlines, and tightened `SpectranSource *` pointer typing and alignment checks in `include/spectran.h` and `src/c_api.rs`.
|
|
16
|
+
- Serialized concurrent `&self` C++ config-tree queries on `NativeSdk` via `device_query_lock`, bounded `num * stride` and validated `fp32` alignment and negative `packet.size` in `read_samples_within`, guarded null config nodes and NUL-terminated device serials, preserved SDK refcounts and intentionally leaked `libloading::Library` on failed teardown, rolled back partial device/packet state on errors, supported `iqtransceiver` RX mode, and reset carry buffers on `set_rf_span_hz`.
|
|
17
|
+
- Replaced `PySpectranSource` `RefCell` state with a `Mutex` acquired exclusively inside `py.detach(...)` and detached the GIL with a bounded `shutdown_timeout` in `Drop`, eliminating re-entrant borrow panics, `pyo3-log` ABBA GIL deadlocks, and runtime teardown hangs; declared `numpy` and optional `pyarrow` dependencies in `python-aaronia/pyproject.toml`.
|
|
18
|
+
- Eliminated the `StreamParser::skip_bytes` black-hole DoS when binary packet headers exceed `MAX_BINARY_PAYLOAD` by resynchronizing via `find_next_header`, sanitized `NaN`/`±Inf` binary floats to `0.0`, trimmed trailing URL slashes, validated `http`/`https` schemes, skipped redundant `/remoteconfig` writes + 500 ms sleeps on HTTP reconnect, dynamically discovered `Block_*` nodes while tolerating unlicensed `/remoteconfig`, and supported wideband V6 HTTP sample rates.
|
|
19
|
+
- Flushed queued HTTP TX batches before `FutureSDR` sink teardown instead of aborting in-flight frames, and fixed `SdkSinkBlock` zero-burst livelocks, monotonic burst timestamp scheduling, and `io.call_again` signaling.
|
|
20
|
+
- Added single-wavelet-block decompression support for compressed `.rtsa` `Spectra` chunks, pinned default multi-substream file cursor reads/seeks to the primary sub-stream, skipped non-IQ `Spectra` chunks in `SpectranSource` file reads, and stepped up out of `<install>/sdk` when locating RTSA XML configs and `RTSAFileTool`.
|
|
21
|
+
- Mounted `.dmg` disk images via `hdiutil` in `packaging/homebrew/soapy-aaronia.rb` with architecture guards and dynamic SoapySDR module ABI detection.
|
|
22
|
+
- Updated `rustls` (`0.23.46`), `rustls-webpki` (`0.103.16`), `tokio` (`1.54.1`), `webpki-root-certs` (`1.0.12`), and `async-executor` (`1.14.1`) in `Cargo.lock` to resolve RustSec advisories and yanked crate entries.
|
|
23
|
+
|
|
24
|
+
## [v0.13.2] - 2026-10-15
|
|
25
|
+
|
|
26
|
+
### Fixed
|
|
27
|
+
- `HttpEndpointsClient` now configures `.no_proxy()` on `reqwest::Client`, preventing corporate/system `HTTP_PROXY` environment variables from hijacking localhost or LAN RTSA-Suite connections.
|
|
28
|
+
- `HttpSource` (`FutureSDR` block) wraps its async `init`/`work` bodies in a poll-scoped Tokio context guard (`WithTokioHandle`) instead of calling `Handle::block_on`, preventing nested runtime panics when driven inside a Tokio worker thread.
|
|
29
|
+
- `HttpSource::apply_initial_tune` now falls back to `/control` (`configure_capture`) when `/remoteconfig` returns HTTP 200 without applying `center_frequency_hz` or `decimation_index` (unlicensed `/remoteconfig`; see https://aaronia.com/en/software-licence-remote-config) as well as on transport errors.
|
|
30
|
+
- Guarded HTTP streaming metadata and sample payloads (`float16`, `float32`, spectrum, and JSON paths) against non-finite (`NaN`/`±Inf`) values so corrupt headers or sample words cannot poison downstream DSP state or observed stream geometry.
|
|
31
|
+
- `NativeSdkSource` now clears carry-over sample buffers on `configure_iq_receiver_with_options`, uses precision-preserving `epoch_seconds_to_nanos` for `last_timestamp_ns`, populates `device_mode` in `device_capabilities`, and prevents empty or invalid-stride packets from prematurely latching `got_packet` during deadline reads.
|
|
32
|
+
- `SpectranSource::read_samples` now honours `config.read_timeout` on the `NativeSdk` backend via `read_samples_deadline`, validates finite tuning inputs across all backends, and clears stale `rf_span_hz`/`decimation_factor` overrides when `set_sample_rate_hz` is called.
|
|
33
|
+
- Hardened RTSA chunk parsers (`STRM`, `SAMP`, `SSTR`, `ANTA`, `MDTT`) with minimum header size checks to reject truncated chunk headers before seeking.
|
|
34
|
+
- `SpectranSeifyDevice` now uses `tokio::task::block_in_place` when called from a multi-thread Tokio runtime, recovers poisoned mutex locks, and reports observed file/stream frequencies in `frequency()`.
|
|
35
|
+
- `python-aaronia` now clears `force_source_type` when `http_base_url` or `file_path` is reset to `None`, and stops any active stream on `start_streaming` re-entry or `Drop`.
|
|
36
|
+
- macOS SoapySDR release artifacts are now packaged as `.dmg` disk images instead of `.tar.gz`, and macOS Python wheels build cleanly without the Linux/Windows-only `native-sdk` feature.
|
|
37
|
+
|
|
7
38
|
## [v0.13.1] - 2026-10-08
|
|
8
39
|
|
|
9
40
|
### Added
|
|
@@ -376,9 +376,9 @@ dependencies = [
|
|
|
376
376
|
|
|
377
377
|
[[package]]
|
|
378
378
|
name = "async-executor"
|
|
379
|
-
version = "1.14.
|
|
379
|
+
version = "1.14.1"
|
|
380
380
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
381
|
-
checksum = "
|
|
381
|
+
checksum = "f426a31126c735126297bc5ea7a521263c9faff4f63ca415267ee625651c4f37"
|
|
382
382
|
dependencies = [
|
|
383
383
|
"async-task",
|
|
384
384
|
"concurrent-queue",
|
|
@@ -703,9 +703,9 @@ checksum = "f079e83a288787bcd14a6aea84cee5c87a67c5a3e660c30f557a3d24761b3527"
|
|
|
703
703
|
|
|
704
704
|
[[package]]
|
|
705
705
|
name = "chacha20"
|
|
706
|
-
version = "0.10.
|
|
706
|
+
version = "0.10.2"
|
|
707
707
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
708
|
-
checksum = "
|
|
708
|
+
checksum = "65c35e4b699c7e15ccbe7ee35c005e4fc0a278d22238a2857e6ce2dadeda1b06"
|
|
709
709
|
dependencies = [
|
|
710
710
|
"cfg-if",
|
|
711
711
|
"cpufeatures 0.3.0",
|
|
@@ -3049,7 +3049,7 @@ dependencies = [
|
|
|
3049
3049
|
|
|
3050
3050
|
[[package]]
|
|
3051
3051
|
name = "python-aaronia"
|
|
3052
|
-
version = "0.13.
|
|
3052
|
+
version = "0.13.3"
|
|
3053
3053
|
dependencies = [
|
|
3054
3054
|
"arrow",
|
|
3055
3055
|
"num-complex",
|
|
@@ -3431,9 +3431,9 @@ dependencies = [
|
|
|
3431
3431
|
|
|
3432
3432
|
[[package]]
|
|
3433
3433
|
name = "rustls"
|
|
3434
|
-
version = "0.23.
|
|
3434
|
+
version = "0.23.46"
|
|
3435
3435
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
3436
|
-
checksum = "
|
|
3436
|
+
checksum = "48e13bd8c0e9365c43cfa5c9e8f9ad49d3c8444926c9aac819e0e4dc503c8fdf"
|
|
3437
3437
|
dependencies = [
|
|
3438
3438
|
"aws-lc-rs",
|
|
3439
3439
|
"once_cell",
|
|
@@ -3494,9 +3494,9 @@ checksum = "f87165f0995f63a9fbeea62b64d10b4d9d8e78ec6d7d51fb2125fda7bb36788f"
|
|
|
3494
3494
|
|
|
3495
3495
|
[[package]]
|
|
3496
3496
|
name = "rustls-webpki"
|
|
3497
|
-
version = "0.103.
|
|
3497
|
+
version = "0.103.16"
|
|
3498
3498
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
3499
|
-
checksum = "
|
|
3499
|
+
checksum = "4443b1b6d39d7c663139942cc4558262562d2c84123bb6282ef177009ca8b281"
|
|
3500
3500
|
dependencies = [
|
|
3501
3501
|
"aws-lc-rs",
|
|
3502
3502
|
"ring",
|
|
@@ -3578,7 +3578,7 @@ checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
|
|
|
3578
3578
|
|
|
3579
3579
|
[[package]]
|
|
3580
3580
|
name = "sdr-aaronia-rs"
|
|
3581
|
-
version = "0.13.
|
|
3581
|
+
version = "0.13.3"
|
|
3582
3582
|
dependencies = [
|
|
3583
3583
|
"anyhow",
|
|
3584
3584
|
"bitflags 2.13.1",
|
|
@@ -4289,9 +4289,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
|
|
|
4289
4289
|
|
|
4290
4290
|
[[package]]
|
|
4291
4291
|
name = "tokio"
|
|
4292
|
-
version = "1.
|
|
4292
|
+
version = "1.54.1"
|
|
4293
4293
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
4294
|
-
checksum = "
|
|
4294
|
+
checksum = "b52fd3255258d26fac7264ab5a76b53c13367136dc011d3d6ad4f8ed070396a3"
|
|
4295
4295
|
dependencies = [
|
|
4296
4296
|
"bytes",
|
|
4297
4297
|
"libc",
|
|
@@ -4784,9 +4784,9 @@ dependencies = [
|
|
|
4784
4784
|
|
|
4785
4785
|
[[package]]
|
|
4786
4786
|
name = "webpki-root-certs"
|
|
4787
|
-
version = "1.0.
|
|
4787
|
+
version = "1.0.12"
|
|
4788
4788
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
4789
|
-
checksum = "
|
|
4789
|
+
checksum = "293198dcebfb821155b5092ab94b5a82ff180eddd7241df3bd6e66a4ffd1a585"
|
|
4790
4790
|
dependencies = [
|
|
4791
4791
|
"rustls-pki-types",
|
|
4792
4792
|
]
|
|
@@ -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.13.
|
|
5
|
+
version = "0.13.3"
|
|
6
6
|
edition = "2024"
|
|
7
7
|
repository = "https://github.com/isaacbentley/sdr-aaronia-rs"
|
|
8
8
|
readme = "README.md"
|
|
@@ -75,6 +75,7 @@ tokio = { version = "1.43", features = ["rt-multi-thread", "macros", "time", "sy
|
|
|
75
75
|
[[bench]]
|
|
76
76
|
name = "parse_int16_packet"
|
|
77
77
|
harness = false
|
|
78
|
+
required-features = ["http"]
|
|
78
79
|
|
|
79
80
|
[[bench]]
|
|
80
81
|
name = "deinterleave_dual_iq"
|
|
@@ -83,21 +84,64 @@ harness = false
|
|
|
83
84
|
[[bench]]
|
|
84
85
|
name = "decompress_block"
|
|
85
86
|
harness = false
|
|
87
|
+
required-features = ["file"]
|
|
86
88
|
|
|
87
89
|
[[bench]]
|
|
88
90
|
name = "rtsa_open_and_read"
|
|
89
91
|
harness = false
|
|
92
|
+
required-features = ["file"]
|
|
93
|
+
|
|
94
|
+
# Feature guards for integration tests so `cargo check/test --all-targets`
|
|
95
|
+
# succeeds under every isolated `--no-default-features --features <feat>`
|
|
96
|
+
# permutation.
|
|
97
|
+
[[test]]
|
|
98
|
+
name = "c_api_test"
|
|
99
|
+
required-features = ["ffi"]
|
|
100
|
+
|
|
101
|
+
[[test]]
|
|
102
|
+
name = "http_mock_test"
|
|
103
|
+
required-features = ["http"]
|
|
104
|
+
|
|
105
|
+
[[test]]
|
|
106
|
+
name = "http_resilience_test"
|
|
107
|
+
required-features = ["http", "file"]
|
|
90
108
|
|
|
91
|
-
# `http_sink_test` drives a FutureSDR flowgraph and imports
|
|
92
|
-
# `sdr_aaronia_rs::http_sink`, both of which only exist under the
|
|
93
|
-
# `futuresdr` feature. Without this guard `cargo clippy --all-targets` and
|
|
94
|
-
# `cargo test --all-targets` fail to compile on a default checkout with
|
|
95
|
-
# `cannot find module or crate futuresdr`. (`tests/native_sdk_load.rs`
|
|
96
|
-
# needs no entry — it guards itself with an inner `#![cfg(...)]`.)
|
|
97
109
|
[[test]]
|
|
98
110
|
name = "http_sink_test"
|
|
99
111
|
required-features = ["futuresdr"]
|
|
100
112
|
|
|
113
|
+
[[test]]
|
|
114
|
+
name = "integration_test"
|
|
115
|
+
required-features = ["http", "file"]
|
|
116
|
+
|
|
117
|
+
[[test]]
|
|
118
|
+
name = "live_smoke"
|
|
119
|
+
required-features = ["http", "file"]
|
|
120
|
+
|
|
121
|
+
[[test]]
|
|
122
|
+
name = "native_sdk_live"
|
|
123
|
+
required-features = ["native-sdk", "http", "file", "ffi"]
|
|
124
|
+
|
|
125
|
+
[[test]]
|
|
126
|
+
name = "properties"
|
|
127
|
+
required-features = ["http", "file"]
|
|
128
|
+
|
|
129
|
+
[[test]]
|
|
130
|
+
name = "rtsa_negative_test"
|
|
131
|
+
required-features = ["file"]
|
|
132
|
+
|
|
133
|
+
[[test]]
|
|
134
|
+
name = "test_cw_mag"
|
|
135
|
+
required-features = ["file"]
|
|
136
|
+
|
|
137
|
+
[[test]]
|
|
138
|
+
name = "test_cw_meta"
|
|
139
|
+
required-features = ["file"]
|
|
140
|
+
|
|
141
|
+
[[test]]
|
|
142
|
+
name = "wire_contract"
|
|
143
|
+
required-features = ["http"]
|
|
144
|
+
|
|
101
145
|
[features]
|
|
102
146
|
default = ["http", "file", "ffi"]
|
|
103
147
|
http = ["dep:reqwest", "dep:tokio", "dep:serde", "dep:serde_json",
|
|
@@ -110,12 +154,16 @@ native-sdk = ["dep:libloading", "dep:widestring"]
|
|
|
110
154
|
|
|
111
155
|
[[example]]
|
|
112
156
|
name = "noaa_scanner"
|
|
113
|
-
required-features = ["futuresdr", "http"]
|
|
157
|
+
required-features = ["futuresdr", "http", "file"]
|
|
114
158
|
|
|
115
159
|
[[example]]
|
|
116
160
|
name = "native_sdk_basic"
|
|
117
161
|
required-features = ["native-sdk"]
|
|
118
162
|
|
|
163
|
+
[[example]]
|
|
164
|
+
name = "native_sdk_transmit"
|
|
165
|
+
required-features = ["native-sdk"]
|
|
166
|
+
|
|
119
167
|
[[example]]
|
|
120
168
|
name = "dump_metadata"
|
|
121
169
|
required-features = ["file"]
|
|
@@ -126,11 +174,11 @@ required-features = ["http"]
|
|
|
126
174
|
|
|
127
175
|
[[example]]
|
|
128
176
|
name = "http_iq_quickstart"
|
|
129
|
-
required-features = ["http"]
|
|
177
|
+
required-features = ["http", "file"]
|
|
130
178
|
|
|
131
179
|
[[example]]
|
|
132
180
|
name = "read_rtsa_file"
|
|
133
|
-
required-features = ["file"]
|
|
181
|
+
required-features = ["http", "file"]
|
|
134
182
|
|
|
135
183
|
|
|
136
184
|
[target.'cfg(any(target_os = "windows", target_os = "linux"))'.dependencies]
|
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: python-aaronia
|
|
3
|
-
Version: 0.13.
|
|
3
|
+
Version: 0.13.3
|
|
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+)
|
|
7
7
|
Classifier: Topic :: Communications :: Ham Radio
|
|
8
8
|
Classifier: Topic :: Scientific/Engineering
|
|
9
|
+
Requires-Dist: numpy>=1.24
|
|
10
|
+
Requires-Dist: pyarrow>=14.0 ; extra == 'arrow'
|
|
11
|
+
Provides-Extra: arrow
|
|
9
12
|
Summary: Python bindings for sdr-aaronia-rs (Aaronia SPECTRAN V6 SDR source)
|
|
10
13
|
License: GPL-3.0-or-later
|
|
11
14
|
Requires-Python: >=3.9
|
|
@@ -15,7 +15,8 @@
|
|
|
15
15
|
|
|
16
16
|
#[cfg(all(
|
|
17
17
|
feature = "native-sdk",
|
|
18
|
-
any(target_os = "windows", target_os = "linux")
|
|
18
|
+
any(target_os = "windows", target_os = "linux"),
|
|
19
|
+
target_pointer_width = "64"
|
|
19
20
|
))]
|
|
20
21
|
fn main() -> anyhow::Result<()> {
|
|
21
22
|
use sdr_aaronia_rs::native_sdk::NativeSdkSource;
|
|
@@ -129,7 +130,8 @@ fn main() -> anyhow::Result<()> {
|
|
|
129
130
|
|
|
130
131
|
#[cfg(not(all(
|
|
131
132
|
feature = "native-sdk",
|
|
132
|
-
any(target_os = "windows", target_os = "linux")
|
|
133
|
+
any(target_os = "windows", target_os = "linux"),
|
|
134
|
+
target_pointer_width = "64"
|
|
133
135
|
)))]
|
|
134
136
|
fn main() {
|
|
135
137
|
println!("This example requires the 'native-sdk' feature and Windows or Linux.");
|
|
@@ -2,7 +2,8 @@
|
|
|
2
2
|
//! Run only with the radio released by other apps; no TX is opened.
|
|
3
3
|
#[cfg(all(
|
|
4
4
|
feature = "native-sdk",
|
|
5
|
-
any(target_os = "windows", target_os = "linux")
|
|
5
|
+
any(target_os = "windows", target_os = "linux"),
|
|
6
|
+
target_pointer_width = "64"
|
|
6
7
|
))]
|
|
7
8
|
#[tokio::main(flavor = "current_thread")]
|
|
8
9
|
async fn main() -> anyhow::Result<()> {
|
|
@@ -87,7 +88,8 @@ async fn main() -> anyhow::Result<()> {
|
|
|
87
88
|
}
|
|
88
89
|
#[cfg(not(all(
|
|
89
90
|
feature = "native-sdk",
|
|
90
|
-
any(target_os = "windows", target_os = "linux")
|
|
91
|
+
any(target_os = "windows", target_os = "linux"),
|
|
92
|
+
target_pointer_width = "64"
|
|
91
93
|
)))]
|
|
92
94
|
fn main() {
|
|
93
95
|
eprintln!("Requires native-sdk on Windows or Linux");
|
|
@@ -11,7 +11,8 @@
|
|
|
11
11
|
|
|
12
12
|
#[cfg(all(
|
|
13
13
|
feature = "native-sdk",
|
|
14
|
-
any(target_os = "windows", target_os = "linux")
|
|
14
|
+
any(target_os = "windows", target_os = "linux"),
|
|
15
|
+
target_pointer_width = "64"
|
|
15
16
|
))]
|
|
16
17
|
#[tokio::main]
|
|
17
18
|
async fn main() -> anyhow::Result<()> {
|
|
@@ -139,7 +140,8 @@ async fn main() -> anyhow::Result<()> {
|
|
|
139
140
|
|
|
140
141
|
#[cfg(not(all(
|
|
141
142
|
feature = "native-sdk",
|
|
142
|
-
any(target_os = "windows", target_os = "linux")
|
|
143
|
+
any(target_os = "windows", target_os = "linux"),
|
|
144
|
+
target_pointer_width = "64"
|
|
143
145
|
)))]
|
|
144
146
|
fn main() {
|
|
145
147
|
println!("This example requires the 'native-sdk' feature and Windows or Linux.");
|
|
@@ -142,8 +142,8 @@ void spectran_source_builder_device_serial(SpectranSourceBuilder* builder, const
|
|
|
142
142
|
void spectran_source_builder_force_source_type(SpectranSourceBuilder *builder,
|
|
143
143
|
int source_type);
|
|
144
144
|
|
|
145
|
-
/* Whether the native SDK
|
|
146
|
-
*
|
|
145
|
+
/* Whether the native SDK backend is compiled into this binary and the
|
|
146
|
+
* vendor SDK library is present on disk; does not load it. */
|
|
147
147
|
bool spectran_sdk_installed(void);
|
|
148
148
|
|
|
149
149
|
/* Alias-free bandwidth (Hz) delivered at an IQ sample rate; smaller than
|
|
@@ -169,10 +169,19 @@ void spectran_source_builder_read_timeout_us(SpectranSourceBuilder* builder, uin
|
|
|
169
169
|
// Automatic reconnection of the HTTP sample stream (default true). When
|
|
170
170
|
// false, a dropped stream ends the session and later reads error out.
|
|
171
171
|
void spectran_source_builder_auto_reconnect(SpectranSourceBuilder* builder, bool enabled);
|
|
172
|
+
// Passive HTTP mode (default false). When true, never writes to /control or
|
|
173
|
+
// /remoteconfig, allowing read-only attachment to shared or unlicensed servers.
|
|
174
|
+
void spectran_source_builder_listen_only(SpectranSourceBuilder* builder, bool enabled);
|
|
172
175
|
SpectranSource* spectran_source_build(SpectranSourceBuilder* builder);
|
|
173
176
|
|
|
174
177
|
// --- SpectranSource FFI --- //
|
|
175
178
|
//
|
|
179
|
+
// Thread-safety contract: a `SpectranSource*` handle is NOT internally
|
|
180
|
+
// synchronized. All calls targeting the same `SpectranSource*` (including
|
|
181
|
+
// reads, retunes, capability/sensor queries, and free) MUST be serialized
|
|
182
|
+
// by the caller (single thread at a time). Separate `SpectranSource*` or
|
|
183
|
+
// `HttpEndpointsClient*` handles may be used concurrently on separate threads.
|
|
184
|
+
//
|
|
176
185
|
// Read return codes: >= 0 samples read; -1 generic error (details via
|
|
177
186
|
// spectran_last_error); -3 timeout — a private convention of this API,
|
|
178
187
|
// chosen so SoapySDR wrappers can map it 1:1 onto SOAPY_SDR_TIMEOUT.
|
|
@@ -218,12 +227,11 @@ SpectranFfiError spectran_source_set_clock_source(SpectranSource* source, const
|
|
|
218
227
|
FfiSourceInfo* spectran_source_get_source_info(SpectranSource* source);
|
|
219
228
|
void spectran_source_info_free(FfiSourceInfo* info);
|
|
220
229
|
|
|
221
|
-
// Read the device's declared capabilities. BLOCKING:
|
|
222
|
-
//
|
|
223
|
-
// or when called from a current-thread tokio runtime; a device
|
|
224
|
-
// cannot be asked yields a struct with every field absent. Answers
|
|
225
|
-
// the HTTP
|
|
226
|
-
// no equivalent surface to ask.
|
|
230
|
+
// Read the device's declared capabilities. BLOCKING: control-plane or
|
|
231
|
+
// SDK queries, so call it once and cache. Returns NULL only for a null
|
|
232
|
+
// source or when called from a current-thread tokio runtime; a device
|
|
233
|
+
// that cannot be asked yields a struct with every field absent. Answers
|
|
234
|
+
// for both the HTTP and native-SDK backends; file sources report nothing.
|
|
227
235
|
FfiDeviceCapabilities* spectran_source_get_capabilities(SpectranSource* source);
|
|
228
236
|
void spectran_source_capabilities_free(FfiDeviceCapabilities* caps);
|
|
229
237
|
|
|
@@ -269,16 +277,25 @@ void spectran_sink_builder_free(SpectranSinkBuilder* builder);
|
|
|
269
277
|
void spectran_sink_builder_center_frequency_hz(SpectranSinkBuilder* builder, double hz);
|
|
270
278
|
void spectran_sink_builder_sample_rate_hz(SpectranSinkBuilder* builder, double hz);
|
|
271
279
|
void spectran_sink_builder_trans_gain_db(SpectranSinkBuilder* builder, double db);
|
|
280
|
+
void spectran_sink_builder_device_serial(SpectranSinkBuilder* builder, const char* serial);
|
|
272
281
|
SpectranSink* spectran_sink_build(SpectranSinkBuilder* builder);
|
|
273
282
|
void spectran_sink_free(SpectranSink* sink);
|
|
274
|
-
//
|
|
283
|
+
// Thread-safety contract: like SpectranSource*, a SpectranSink* handle has no
|
|
284
|
+
// internal lock and must be accessed by at most one thread at a time.
|
|
285
|
+
//
|
|
286
|
+
// Loads the native SDK, opens the matching device, configures
|
|
275
287
|
// the IQ transmitter from the builder settings, and starts the TX
|
|
276
288
|
// stream. Blocking.
|
|
277
289
|
SpectranFfiError spectran_sink_initialize(SpectranSink* sink);
|
|
278
290
|
SpectranFfiError spectran_sink_stop_streaming(SpectranSink* sink);
|
|
291
|
+
SpectranFfiError spectran_sink_set_center_frequency_hz(SpectranSink* sink, double hz);
|
|
292
|
+
SpectranFfiError spectran_sink_set_sample_rate_hz(SpectranSink* sink, double hz);
|
|
293
|
+
SpectranFfiError spectran_sink_set_trans_gain_db(SpectranSink* sink, double db);
|
|
294
|
+
bool spectran_sink_get_master_stream_time_ns(SpectranSink* sink, int64_t* out_time_ns);
|
|
279
295
|
// start_time_s / end_time_s are in device MASTER STREAM TIME seconds,
|
|
280
296
|
// not wall-clock epoch time. Samples use the same FfiComplex layout as
|
|
281
|
-
// the read path.
|
|
297
|
+
// the read path. Pass samples == NULL with num_samples == 0 for a 0-sample
|
|
298
|
+
// startup/shutdown sync packet.
|
|
282
299
|
SpectranFfiError spectran_sink_write_samples(
|
|
283
300
|
SpectranSink* sink,
|
|
284
301
|
int32_t channel,
|
|
@@ -295,9 +312,9 @@ HttpEndpointsClient* spectran_endpoints_client_new(const char* base_url);
|
|
|
295
312
|
void spectran_endpoints_client_free(HttpEndpointsClient* client);
|
|
296
313
|
FfiServerInfo* spectran_endpoints_client_get_info(HttpEndpointsClient* client);
|
|
297
314
|
|
|
298
|
-
/* Fill *out with the device's live sensors through a standalone client
|
|
299
|
-
*
|
|
300
|
-
* as spectran_source_get_sensors. */
|
|
315
|
+
/* Fill *out with the device's live sensors through a standalone client
|
|
316
|
+
* (safe to call concurrently while another thread owns a SpectranSource*).
|
|
317
|
+
* Same reading and return contract as spectran_source_get_sensors. */
|
|
301
318
|
bool spectran_endpoints_client_get_sensors(HttpEndpointsClient* client, FfiDeviceSensors* out);
|
|
302
319
|
void spectran_server_info_free(FfiServerInfo* info);
|
|
303
320
|
SpectranFfiError spectran_endpoints_client_control_streaming(HttpEndpointsClient* client, bool start);
|
|
@@ -306,9 +323,9 @@ SpectranFfiError spectran_endpoints_client_control_recording(HttpEndpointsClient
|
|
|
306
323
|
// --- General FFI Utilities --- //
|
|
307
324
|
|
|
308
325
|
/* Additive native SDK APIs; existing struct layouts remain unchanged. */
|
|
309
|
-
char *spectran_source_capabilities_json(
|
|
310
|
-
SpectranFfiError spectran_source_rf_span_range(
|
|
311
|
-
SpectranFfiError spectran_source_set_rf_span_hz(
|
|
326
|
+
char *spectran_source_capabilities_json(SpectranSource *source);
|
|
327
|
+
SpectranFfiError spectran_source_rf_span_range(SpectranSource *source, double *min_hz, double *max_hz);
|
|
328
|
+
SpectranFfiError spectran_source_set_rf_span_hz(SpectranSource *source, double hz);
|
|
312
329
|
SpectranFfiError spectran_source_builder_native_options(SpectranSourceBuilder *builder,
|
|
313
330
|
const char *family, const char *mode, double rf_span_hz, const char *clock, uint32_t decimation);
|
|
314
331
|
|
|
@@ -0,0 +1,76 @@
|
|
|
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.13.3"
|
|
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
|
+
depends_on arch: :arm64
|
|
22
|
+
|
|
23
|
+
on_arm do
|
|
24
|
+
url "https://github.com/isaacbentley/sdr-aaronia-rs/releases/download/v#{version}/SoapyAaronia-#{version}-macos-arm64.dmg",
|
|
25
|
+
using: :nounzip
|
|
26
|
+
sha256 "REPLACE_WITH_SHA256_OF_MACOS_ARM64_ARCHIVE"
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
on_linux do
|
|
31
|
+
depends_on arch: :x86_64
|
|
32
|
+
|
|
33
|
+
on_intel do
|
|
34
|
+
url "https://github.com/isaacbentley/sdr-aaronia-rs/releases/download/v#{version}/SoapyAaronia-#{version}-linux-x86_64.tar.gz"
|
|
35
|
+
sha256 "REPLACE_WITH_SHA256_OF_LINUX_X86_64_ARCHIVE"
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
depends_on "soapysdr"
|
|
40
|
+
|
|
41
|
+
def install
|
|
42
|
+
# Discover SoapySDR's module ABI version dynamically rather than
|
|
43
|
+
# hardcoding "0.8" across future SoapySDR releases.
|
|
44
|
+
info = Utils.safe_popen_read(Formula["soapysdr"].opt_bin/"SoapySDRUtil", "--info")
|
|
45
|
+
abi = info[/ABI Version:\s*v?([0-9]+\.[0-9]+)/i, 1] || "0.8"
|
|
46
|
+
mod_dir = lib/"SoapySDR/modules#{abi}"
|
|
47
|
+
|
|
48
|
+
if OS.mac?
|
|
49
|
+
dmg = Dir["*.dmg"].first
|
|
50
|
+
odie "No .dmg archive found in buildpath" unless dmg
|
|
51
|
+
mountpoint = buildpath/"dmg_mount"
|
|
52
|
+
mountpoint.mkpath
|
|
53
|
+
system "hdiutil", "attach", "-nobrowse", "-readonly", "-mountpoint", mountpoint, dmg
|
|
54
|
+
begin
|
|
55
|
+
so_file = Pathname.glob(mountpoint/"**/libaaroniaSupport.so").first
|
|
56
|
+
odie "libaaroniaSupport.so not found inside mounted DMG" unless so_file
|
|
57
|
+
mod_dir.install so_file
|
|
58
|
+
install_doc = Pathname.glob(mountpoint/"**/INSTALL.md").first
|
|
59
|
+
doc.install install_doc if install_doc
|
|
60
|
+
ensure
|
|
61
|
+
system "hdiutil", "detach", mountpoint, "-force"
|
|
62
|
+
end
|
|
63
|
+
else
|
|
64
|
+
so_file = Pathname.glob("**/libaaroniaSupport.so").first
|
|
65
|
+
odie "libaaroniaSupport.so not found in archive" unless so_file
|
|
66
|
+
mod_dir.install so_file
|
|
67
|
+
install_doc = Pathname.glob("**/INSTALL.md").first
|
|
68
|
+
doc.install install_doc if install_doc
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
test do
|
|
73
|
+
# Proves the module loads into SoapySDR rather than merely existing.
|
|
74
|
+
assert_match "aaronia", shell_output("#{Formula["soapysdr"].opt_bin}/SoapySDRUtil --check=aaronia")
|
|
75
|
+
end
|
|
76
|
+
end
|
|
@@ -17,6 +17,10 @@ classifiers = [
|
|
|
17
17
|
]
|
|
18
18
|
# Version comes from python-aaronia/Cargo.toml (single source of truth).
|
|
19
19
|
dynamic = ["version"]
|
|
20
|
+
dependencies = ["numpy>=1.24"]
|
|
21
|
+
|
|
22
|
+
[project.optional-dependencies]
|
|
23
|
+
arrow = ["pyarrow>=14.0"]
|
|
20
24
|
|
|
21
25
|
# A real command, so checking a setup needs no code:
|
|
22
26
|
# aaronia-doctor http://localhost:54664
|
|
@@ -108,6 +108,9 @@ class SpectranConfig:
|
|
|
108
108
|
(default 30.0). Must be positive and finite."""
|
|
109
109
|
auto_reconnect: bool
|
|
110
110
|
"""Reconnect the HTTP stream after a drop (default ``True``)."""
|
|
111
|
+
listen_only: bool
|
|
112
|
+
"""Stream from an HTTP server without issuing ``/control`` or
|
|
113
|
+
``/remoteconfig`` writes (default ``False``)."""
|
|
111
114
|
|
|
112
115
|
class SpectranSource:
|
|
113
116
|
"""A streaming IQ source.
|
|
@@ -136,8 +139,9 @@ class SpectranSource:
|
|
|
136
139
|
a truncated capture is not mistaken for a finished one.
|
|
137
140
|
"""
|
|
138
141
|
|
|
139
|
-
def start_streaming(self, config: SpectranConfig) -> None:
|
|
140
|
-
"""Connect to the backend selected by ``config``
|
|
142
|
+
def start_streaming(self, config: Optional[SpectranConfig] = None) -> None:
|
|
143
|
+
"""Connect to the backend selected by ``config`` (or the previous
|
|
144
|
+
configuration when omitted) and start streaming.
|
|
141
145
|
|
|
142
146
|
Raises ``SpectranConnectionError`` if the endpoint is
|
|
143
147
|
unreachable, ``ValueError`` for invalid configuration, and
|
|
@@ -234,6 +238,7 @@ def open(
|
|
|
234
238
|
format: Optional[WireFormat] = None,
|
|
235
239
|
scale: Optional[float] = None,
|
|
236
240
|
read_timeout_s: Optional[float] = None,
|
|
241
|
+
listen_only: bool = False,
|
|
237
242
|
) -> SpectranSource:
|
|
238
243
|
"""Open a source and start streaming, in one call.
|
|
239
244
|
|