Soapy block refactoring — ABI fix, API alignment, TX support#754
Soapy block refactoring — ABI fix, API alignment, TX support#754RalphSteinhagen wants to merge 8 commits intomainfrom
Conversation
f8df0bf to
d710f37
Compare
67ea8a3 to
3cc2aaf
Compare
|
Noticed during hardware testing with
|
|
|
|
With |
Correct, should be insufficient input samples rather than OK. The progress is reported anyway via the IO thread. Will adjust. This is the same issue for source and sink. The actual write to the HW should block if there are no samples... will investigate. |
- replace SoapySDR::Kwargs with own typedefs (no #include <SoapySDR/Device.hpp>) - Device() = default (null handle), Device::make() -> std::expected factory - all wrapper setters/activate/deactivate/setupStream return std::expected - block uses emitErrorMessage + requestStop instead of throw - fix argument evaluation order bug (GCC evaluates right-to-left) in 5 call sites that caused empty device/module lists on GCC-14/GCC-15 - fix null optionNames assertion crash with LimeSDR driver - fix null device segfault in settingsChanged during emplaceBlock - fix RAII deleters throwing in destructors (log to stderr instead) - test: expect() on all std::expected returns (41 assertions), USB reset between suites Known external issues (SoapySDR / driver bugs, not fixable on our side): - 168-byte memory leak in SoapySDR's module loader (LSAN suppressed in CTest) - RTL-SDR driver segfaults in readStream when PLL fails to lock after rapid close/reopen — mitigated by USB device reset + settle delay between suites - RTL-SDR PLL lock failure is non-deterministic and hardware-dependent - LimeSDR driver returns null optionNames in SoapySDRArgInfo (worked around) Verified with RTL-SDR + LimeSDR on GCC-14, GCC-15, Clang-20 (Debug/Release, ASAN). Signed-off-by: Ralph J. Steinhagen <r.steinhagen@gsi.de>
…names - absorbed into gr-sdr library (gr-soapy removed) - wrapper namespace: gr::blocks::sdr::soapy - SigMF-aligned renames (sigmf-schema.json v1.2.6) - direction-prefixed per-channel fields: rx_gains, rx_bandwidths, rx_antennae - Annotated<> used directly (removed using A = ... alias), Doc<> on all settings - Tensor<double> → std::vector<double> for per-channel settings - removed dead getMockDeviceSettingInfo(), added applyBandwidth() to reinitDevice() - max_fragment_count added to GR_MAKE_REFLECTABLE Signed-off-by: Ralph J. Steinhagen <r.steinhagen@gsi.de>
…_done - migrate SoapySource from synchronous processBulk to async IO thread (ioReadLoop on thread_pool::defaultIoPool, same pattern as RTL2832Source) - single-port and multi-port paths with cached writer references - overflow counter now std::atomic, with verbose_overflow setting - stream restart recovery on overflow (deactivate + reactivate) - fix disconnect_on_done for IO thread sources (both SoapySource and RTL2832Source): check hasNoDownStreamConnectedChildren() in work() so the scheduler stops when CountingSink returns DONE Signed-off-by: Ralph J. Steinhagen <r.steinhagen@gsi.de>
… DC blocker, ppm estimator - 3-param settingsChanged with forwardSettings for frequency and sample_rate - timing tags: TRIGGER_NAME, TRIGGER_TIME, TRIGGER_OFFSET per chunk - emit_timing_tags, emit_meta_info, tag_interval, trigger_name settings - emitChangedParams in TRIGGER_META_INFO (sample_rate, frequency, clock_source) - optional clk_in port for external timing (GPS/PPS) with clock-offset interpolation - drainClockInput mirrors RTL2832Source pattern - optional DC blocker (disabled by default): dc_blocker_enabled, dc_blocker_cutoff using existing iir::designFilter<float>(HIGHPASS, Butterworth), complex<float> only - optional sample rate estimator (disabled by default): ppm_estimator_cutoff using existing algorithm::SampleRateEstimator - ppm_error, corrected sample_rate and frequency emitted in timing tags when enabled Signed-off-by: Ralph J. Steinhagen <r.steinhagen@gsi.de>
implements stateless coefficient generation and stateful real-time envelope for burst TX shaping. Target-driven state machine (Off↔RampUp↔On↔RampDown) with pre-computed lookup-table, physical-unit configuration, and glitch-free mid-ramp reversal. Template storage follows HistoryBuffer pattern (dynamic vector / fixed array / PMR). Taper types: None, Linear, RaisedCosine, Tukey, Gaussian, Mushroom, MushroomSine. Mushroom/MushroomSine: zero-integral for RF cavity phase preservation (J. Tückmantel, R.J. Steinhagen, CERN). Signed-off-by: Ralph J. Steinhagen <r.steinhagen@gsi.de>
…eview fixes - LoopbackDevice: SoapySDR-compatible loopback with pluggable ChannelModel, DeviceRegistry for instance pairing, CF32/CS16/CU8 format conversion - DeviceMode enum: Loopback (TX→RX), RxOnly (tone→model→RX), TxOnly (null sink) - SoapyRaiiWrapper: ~30 new C-API wrappers (sensors, GPIO, registers, clock, frontend corrections), error returns as gr::Error - fix: writeStream returns actual count (was always numElems), TIMEOUT on backpressure - fix: null-check 8 C-API string getters, string_view→string for C null-termination - fix: per-instance stream sentinels, intentional-leak DeviceRegistry statics, assert model-set-before-activate contract - fix: getHardwareTime keeps uint64_t return with explicit cast, init 2 lengths - tests: 99 tests (4666 assertions) — concurrent TX+RX threads, backpressure, CS16/CU8 boundary values, RxOnly/TxOnly modes, full SoapySDR API coverage Signed-off-by: Ralph J. Steinhagen <r.steinhagen@gsi.de>
- qa_SoapyIntegration.cpp: 7 tests (36 assertions) wiring SoapySource through gr::scheduler::Simple with the loopback device in rxOnly mode - tests: single/2-channel sample delivery, tag propagation, clk_in with ClockSource→GPS_PPS forwarding, DC blocker on DC tone, tag_interval emission, graceful degradation (loopback without TX) Signed-off-by: Ralph J. Steinhagen <r.steinhagen@gsi.de>
3cc2aaf to
b3221b3
Compare
- SoapySink<T, nPorts>: IO-thread TX block mirroring SoapySource pattern
- soapy::DeviceRegistry: process-global shared_ptr<SoapySDRDevice> keyed
by Kwargs — Source and Sink transparently share the same device handle
- Stream::writeStream: TX wrapper with variadic + buffer-list overloads
- plugin registration: SoapySink<1/2/4> × {uint8_t, int16_t, CF32}
- fix: Device constructor routes through registry (was bypassing shared handle)
- fix: registry deleter no longer locks mutex (was deadlock risk)
- fix: work() returns 0UZ (IO thread updates progress directly)
- shared parseKwargsString in soapy:: namespace (was duplicated)
- tests: TX→RX round-trip, 2-channel, standalone sink, registry cleanup
Signed-off-by: Ralph J. Steinhagen <r.steinhagen@gsi.de>
b3221b3 to
21f4f54
Compare
|
|
N.B. Was the missing 'progress' increase and notify_all in the SoapySink in the end. Added some other reasonably common Soapy-access methods in addition to the (master/reference) clock settings, merged the duplicate commit, rebased and pushed again. |
sure, maybe this PR can help during investigations. |


Incrementally refactors SoapyBlock to match RTL2832Source quality and patterns. Single PR, independent bisectable commits.
Commits:
Out of scope (separate PR)
Known external issues (so far)