Giter Club home page Giter Club logo

soapysdr.jl's Introduction

SoapySDR.jl

Dev Docs Coverage Status

A Julia wrapper for SoapySDR to enable SDR processing in Julia. It features a high level interface to interact with underlying SDR radios. Several radios are supported in the Julia Package manager, and may be easily installed for use with SoapySDR.jl

soapysdr.jl's People

Contributors

keno avatar maleadt avatar sjkelly avatar staticfloat avatar sygreer avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar

soapysdr.jl's Issues

Error when trying to change a Channel parameter of type Bool

On Windows 10, Julia 1.6.3, using SoapySDR
Hardware: Adalm-Pluto SDR

When I try to configure a parameter of a SoapySDR.Channel of type "Bool", I get this error:

"setfield! immutable struct of type Channel cannot be changed
Stacktrace:
[1] setproperty!(c::SoapySDR.Channel, s::Symbol, v::Bool)
@ SoapySDR C:\Users\Theo.julia\packages\SoapySDR\saW3b\src\highlevel.jl:338
[2] top-level scope
@ REPL[5]:1"

Is this a bug or do I have to transform the boolean somehow with Unitful.jl?

               _
   _       _ _(_)_     |  Documentation: https://docs.julialang.org
  (_)     | (_) (_)    |
   _ _   _| |_  __ _   |  Type "?" for help, "]?" for Pkg help.
  | | | | | | |/ _` |  |
  | | |_| | | | (_| |  |  Version 1.6.3 (2021-09-23)
 _/ |\__'_|_|_|\__'_|  |  Official https://julialang.org/ release
|__/                   |

julia> using SoapySDR, SoapyPlutoSDR_jll

julia> dev = Devices()[1]
SoapySDR ADALM-PLUTO device (driver: PlutoSDR) w/ 1 TX channels and 1 RX channels

julia> rx_chan = dev.rx[1]
RX Channel #1 on ADALM-PLUTO
  Selected Antenna [A_BALANCED]: A_BALANCED
  Bandwidth [ 200..200 kHz, 1..1 MHz, 2..2 MHz, 3..3 MHz, 4..4 MHz, 5..5 MHz, 6..6 MHz, 7..7 MHz, 8..8 MHz, 9..9 MHz, 10..10 MHz ]: 18.0 MHz
  Frequency [ 70 MHz .. 6 GHz ]: 104.3 MHz
    RF [ 70 MHz .. 6 GHz ]: 104.3 MHz
  Gain [0.0 dB .. 73.0 dB]: 73.0 dB
    PGA [0.0 dB .. 73.0 dB]: 73.0 dB
  Sample Rate [ 65.1..65.1 kHz, 1..1 MHz, 2..2 MHz, 3..3 MHz, 4..4 MHz, 5..5 MHz, 6..6 MHz, 7..7 MHz, 8..8 MHz, 9..9 MHz, 10..10 MHz ]: 30.719998999999998 MHz


julia> rx_chan.frequency = 100e6u"Hz"
1.0e8 Hz

julia> rx_chan.gain_mode = true
ERROR: setfield! immutable struct of type Channel cannot be changed
Stacktrace:
 [1] setproperty!(c::SoapySDR.Channel, s::Symbol, v::Bool)
   @ SoapySDR C:\Users\Theo\.julia\packages\SoapySDR\saW3b\src\highlevel.jl:338
 [2] top-level scope
   @ REPL[5]:1

Udev Rules and Kernel Blacklists

At least for the RTLSDR I had to handle this.

Should add a "Troubleshooting" section and add this so people aren't confused.

Also xtrx needs a kernel module which doesn't seem included/installed (I hope not)?

segfault when collecting Devices

julia> using SoapySDR

julia> collect(Devices(driver="XTRX"))
6-element Vector{Any}:

signal (11): Segmentation fault
in expression starting at none:0
unknown function (ip: 0x7f659454197d)
ijl_cstr_to_string at /cache/build/default-amdci4-3/julialang/julia-release-1-dot-8/src/array.c:529
unsafe_string at ./strings/string.jl:71 [inlined]
iterate at /home/sjkelly/xtrx_julia/software/SoapySDR.jl/src/typewrappers.jl:58 [inlined]
show at ./dict.jl:41
unknown function (ip: 0x7f657cf2b2e1)
_jl_invoke at /cache/build/default-amdci4-3/julialang/julia-release-1-dot-8/src/gf.c:2367 [inlined]
ijl_apply_generic at /cache/build/default-amdci4-3/julialang/julia-release-1-dot-8/src/gf.c:2549
#sprint#451 at ./strings/io.jl:112
sprint##kw at ./strings/io.jl:107 [inlined]
alignment at ./show.jl:2735
unknown function (ip: 0x7f657cf2a099)
_jl_invoke at /cache/build/default-amdci4-3/julialang/julia-release-1-dot-8/src/gf.c:2367 [inlined]
ijl_apply_generic at /cache/build/default-amdci4-3/julialang/julia-release-1-dot-8/src/gf.c:2549
alignment at ./arrayshow.jl:69
_print_matrix at ./arrayshow.jl:207
print_matrix at ./arrayshow.jl:171
print_matrix at ./arrayshow.jl:171 [inlined]
print_array at ./arrayshow.jl:358 [inlined]
show at ./arrayshow.jl:399
unknown function (ip: 0x7f657cf23df1)
_jl_invoke at /cache/build/default-amdci4-3/julialang/julia-release-1-dot-8/src/gf.c:2367 [inlined]
ijl_apply_generic at /cache/build/default-amdci4-3/julialang/julia-release-1-dot-8/src/gf.c:2549
#43 at /cache/build/default-amdci4-3/julialang/julia-release-1-dot-8/usr/share/julia/stdlib/v1.8/REPL/src/REPL.jl:267
unknown function (ip: 0x7f657cf1ca72)
_jl_invoke at /cache/build/default-amdci4-3/julialang/julia-release-1-dot-8/src/gf.c:2367 [inlined]
ijl_apply_generic at /cache/build/default-amdci4-3/julialang/julia-release-1-dot-8/src/gf.c:2549
with_repl_linfo at /cache/build/default-amdci4-3/julialang/julia-release-1-dot-8/usr/share/julia/stdlib/v1.8/REPL/src/REPL.jl:521
unknown function (ip: 0x7f657cf1a2a6)
_jl_invoke at /cache/build/default-amdci4-3/julialang/julia-release-1-dot-8/src/gf.c:2367 [inlined]
ijl_apply_generic at /cache/build/default-amdci4-3/julialang/julia-release-1-dot-8/src/gf.c:2549
display at /cache/build/default-amdci4-3/julialang/julia-release-1-dot-8/usr/share/julia/stdlib/v1.8/REPL/src/REPL.jl:260
display at /cache/build/default-amdci4-3/julialang/julia-release-1-dot-8/usr/share/julia/stdlib/v1.8/REPL/src/REPL.jl:272
unknown function (ip: 0x7f657cf1c2e6)
_jl_invoke at /cache/build/default-amdci4-3/julialang/julia-release-1-dot-8/src/gf.c:2367 [inlined]
ijl_apply_generic at /cache/build/default-amdci4-3/julialang/julia-release-1-dot-8/src/gf.c:2549
display at ./multimedia.jl:328
unknown function (ip: 0x7f657cf1c092)
_jl_invoke at /cache/build/default-amdci4-3/julialang/julia-release-1-dot-8/src/gf.c:2367 [inlined]
ijl_apply_generic at /cache/build/default-amdci4-3/julialang/julia-release-1-dot-8/src/gf.c:2549
jl_apply at /cache/build/default-amdci4-3/julialang/julia-release-1-dot-8/src/julia.h:1838 [inlined]
jl_f__call_latest at /cache/build/default-amdci4-3/julialang/julia-release-1-dot-8/src/builtins.c:774
#invokelatest#2 at ./essentials.jl:729 [inlined]
invokelatest at ./essentials.jl:726 [inlined]
print_response at /cache/build/default-amdci4-3/julialang/julia-release-1-dot-8/usr/share/julia/stdlib/v1.8/REPL/src/REPL.jl:296
#45 at /cache/build/default-amdci4-3/julialang/julia-release-1-dot-8/usr/share/julia/stdlib/v1.8/REPL/src/REPL.jl:278
unknown function (ip: 0x7f657cf1baa2)
_jl_invoke at /cache/build/default-amdci4-3/julialang/julia-release-1-dot-8/src/gf.c:2367 [inlined]
ijl_apply_generic at /cache/build/default-amdci4-3/julialang/julia-release-1-dot-8/src/gf.c:2549
with_repl_linfo at /cache/build/default-amdci4-3/julialang/julia-release-1-dot-8/usr/share/julia/stdlib/v1.8/REPL/src/REPL.jl:521
unknown function (ip: 0x7f657cf1a2a6)
_jl_invoke at /cache/build/default-amdci4-3/julialang/julia-release-1-dot-8/src/gf.c:2367 [inlined]
ijl_apply_generic at /cache/build/default-amdci4-3/julialang/julia-release-1-dot-8/src/gf.c:2549
print_response at /cache/build/default-amdci4-3/julialang/julia-release-1-dot-8/usr/share/julia/stdlib/v1.8/REPL/src/REPL.jl:276
do_respond at /cache/build/default-amdci4-3/julialang/julia-release-1-dot-8/usr/share/julia/stdlib/v1.8/REPL/src/REPL.jl:857
unknown function (ip: 0x7f657cf17df9)
_jl_invoke at /cache/build/default-amdci4-3/julialang/julia-release-1-dot-8/src/gf.c:2367 [inlined]
ijl_apply_generic at /cache/build/default-amdci4-3/julialang/julia-release-1-dot-8/src/gf.c:2549
jl_apply at /cache/build/default-amdci4-3/julialang/julia-release-1-dot-8/src/julia.h:1838 [inlined]
jl_f__call_latest at /cache/build/default-amdci4-3/julialang/julia-release-1-dot-8/src/builtins.c:774
#invokelatest#2 at ./essentials.jl:729 [inlined]
invokelatest at ./essentials.jl:726 [inlined]
run_interface at /cache/build/default-amdci4-3/julialang/julia-release-1-dot-8/usr/share/julia/stdlib/v1.8/REPL/src/LineEdit.jl:2510
run_frontend at /cache/build/default-amdci4-3/julialang/julia-release-1-dot-8/usr/share/julia/stdlib/v1.8/REPL/src/REPL.jl:1248
#49 at ./task.jl:484
jfptr_YY.49_67945.clone_1 at /home/sjkelly/.julia/juliaup/julia-1.8.0+0.x64/lib/julia/sys.so (unknown line)
_jl_invoke at /cache/build/default-amdci4-3/julialang/julia-release-1-dot-8/src/gf.c:2367 [inlined]
ijl_apply_generic at /cache/build/default-amdci4-3/julialang/julia-release-1-dot-8/src/gf.c:2549
jl_apply at /cache/build/default-amdci4-3/julialang/julia-release-1-dot-8/src/julia.h:1838 [inlined]
start_task at /cache/build/default-amdci4-3/julialang/julia-release-1-dot-8/src/task.c:931
Allocations: 7127450 (Pool: 7124171; Big: 3279); GC: 8

Use Clang.jl for bindings?

I've only used Clang.jl a few times to generate bindings. It does seem to do a very good job and automates much of the process.

Setting Rx- & Tx-SamplingRate individually

On Windows 10, Julia 1.6.3
Hardware: Adalm-Pluto SDR

When I set "sample_rate" to different values for the Tx and Rx Channel, then the value of both becomes the value of the sampling_rate which was changed last.

I run my AdalmPluto in a loopback-configuration, so the property "fullduplex" for both channels is true.

Is this just a limitation of the Hardware or Software, or is there some way to set the sampling rates to individual values?
Or could the fullduplex-mode force the channels to the same sampling rate?

I'm not that experienced with SDRs, sorry if the answer is obvious :)
Thanks for any help.

              _
   _       _ _(_)_     |  Documentation: https://docs.julialang.org
  (_)     | (_) (_)    |
   _ _   _| |_  __ _   |  Type "?" for help, "]?" for Pkg help.
  | | | | | | |/ _` |  |
  | | |_| | | | (_| |  |  Version 1.6.3 (2021-09-23)
 _/ |\__'_|_|_|\__'_|  |  Official https://julialang.org/ release
|__/                   |

(@v1.6) pkg> status SoapySDR
      Status `C:\Users\Theo\.julia\environments\v1.6\Project.toml`
  [4fa426e6] SoapySDR v0.2.0

(@v1.6) pkg> status SoapyPlutoSDR_jll
      Status `C:\Users\Theo\.julia\environments\v1.6\Project.toml`
  [96b01697] SoapyPlutoSDR_jll v0.2.1+0

julia> using SoapySDR

julia> using SoapyPlutoSDR_jll

julia> device = open(Devices()[1])
SoapySDR ADALM-PLUTO device
  driver: PlutoSDR
  number of TX channels:1
  number of RX channels:1
  sensors: SoapySDR.SensorComponent[xadc_temp0,xadc_voltage0,xadc_voltage1,xadc_voltage2,xadc_voltage3,xadc_voltage4,xadc_voltage5,xadc_voltage6,xadc_voltage7,xadc_voltage8,adm1177_current0,adm1177_voltage0,ad9361-phy_temp0,ad9361-phy_voltage2,]
  time_source:
  time_sources:SoapySDR.TimeSource[]
  frontendmapping_rx:
  frontendmapping_tx:


julia> tx_chan = device.tx[1]
TX Channel #1 on ADALM-PLUTO
  antenna: A
  antennas: SoapySDR.Antenna[A,]
  bandwidth [ 200..200 kHz, 1..1 MHz, 2..2 MHz, 3..3 MHz, 4..4 MHz, 5..5 MHz, 6..6 MHz, 7..7 MHz, 8..8 MHz, 9..9 MHz, 10..10 MHz ]: 1.0 MHz
  frequency [ 70 MHz .. 6 GHz ]: 1.0 GHz
    RF [ 70 MHz .. 6 GHz ]: 1.0 GHz
  gain_mode (AGC=true/false/missing): missing
  gain: 30.0 dB
  gain_elements: SoapySDR.GainElement[PGA,]
  fullduplex: true
  stream_formats: DataType[Complex{Int8}, SoapySDR.ComplexInt{12}, Complex{Int16}, ComplexF32]
  native_stream_format: Complex{Int16}
  sample_rate [ 65.1..65.1 kHz, 1..1 MHz, 2..2 MHz, 3..3 MHz, 4..4 MHz, 5..5 MHz, 6..6 MHz, 7..7 MHz, 8..8 MHz, 9..9 MHz, 10..10 MHz ]: 999.999 kHz
  dc_offset_mode (true/false/missing): missing
  dc_offset (if has dc_offset_mode): missing
  iq_balance_mode (true/false/missing): missing
  iq_balance: missing
  frequency_correction: missing ppm


julia> rx_chan = device.rx[1]
RX Channel #1 on ADALM-PLUTO
  antenna: A_BALANCED
  antennas: SoapySDR.Antenna[A_BALANCED,]
  bandwidth [ 200..200 kHz, 1..1 MHz, 2..2 MHz, 3..3 MHz, 4..4 MHz, 5..5 MHz, 6..6 MHz, 7..7 MHz, 8..8 MHz, 9..9 MHz, 10..10 MHz ]: 1.0 MHz
  frequency [ 70 MHz .. 6 GHz ]: 1.0 GHz
    RF [ 70 MHz .. 6 GHz ]: 1.0 GHz
  gain_mode (AGC=true/false/missing): false
  gain: 73.0 dB
  gain_elements: SoapySDR.GainElement[PGA,]
  fullduplex: true
  stream_formats: DataType[Complex{Int8}, SoapySDR.ComplexInt{12}, Complex{Int16}, ComplexF32]
  native_stream_format: Complex{Int16}
  sample_rate [ 65.1..65.1 kHz, 1..1 MHz, 2..2 MHz, 3..3 MHz, 4..4 MHz, 5..5 MHz, 6..6 MHz, 7..7 MHz, 8..8 MHz, 9..9 MHz, 10..10 MHz ]: 999.999 kHz
  dc_offset_mode (true/false/missing): missing
  dc_offset (if has dc_offset_mode): missing
  iq_balance_mode (true/false/missing): missing
  iq_balance: missing
  frequency_correction: missing ppm


julia>

julia> tx_chan.sample_rate = 2u"MHz"
2 MHz

julia> tx_chan.sample_rate
1.999999e6 Hz

julia>

julia> rx_chan.sample_rate = 1u"MHz"
1 MHz

julia> rx_chan.sample_rate
999999.0 Hz

julia>

julia> tx_chan.sample_rate
999999.0 Hz

julia> rx_chan.sample_rate
999999.0 Hz

julia>

julia> rx_chan.fullduplex
true

julia> tx_chan.fullduplex
true

Make Filtering Drivers easier

One current has to do:

julia> Devices(parse(KWArgs, "driver=XTRX"))
[1] "driver" => "XTRX"


julia> Devices(parse(KWArgs, "driver=lime"))
[1] "driver" => "lime", "index" => "0", "label" => "Fairwaves XTRX (over LitePCIe) [PCIe]", "media" => "PCIe", "module" => "XTRX", "name" => "Fairwaves XTRX (over LitePCIe)"

`STREAM_ERROR` on 0.2 with USRP/UHD

reported by @mbaz. This is not noticed on 0.1.2 so some bisection is needed...

I'm hitting an issue with SoapySDR and UHD. I'm running [4fa426e6] SoapySDR v0.2.0 [email protected]:JuliaTelecom/SoapySDR.jl.git#main. This is my code:

using SoapySDR, SoapyUHD_jll

# Setup
devs = Devices()
dev = open(devs[1])
c_rx = dev.rx[1]
c_rx.frequency = 2.498u"GHz"
c_rx.gain = 30u"dB"
c_rx.sample_rate = 256u"kHz"
s_rx = SoapySDR.Stream(ComplexF32, [c_rx])

# buffer for about 50 ms
data_rx_buff = zeros(ComplexF32, Int(256e3*50e-3))

# Action!
SoapySDR.activate!.((s_rx, ))
Base.read!(s_rx, (data_rx_buff, ))

# Wrap up
SoapySDR.deactivate!.((s_rx, ))
close.((s_rx, ))
close(dev)

I'm just trying to read 50 milliseconds of data. This is the error:

ERROR: LoadError: STREAM_ERROR
Stacktrace:
 [1] SoapySDRDevice_readStream(device::SoapySDR.Device, stream::SoapySDR.Stream{ComplexF32}, buffs::Base.RefValue{Tuple{Ptr{ComplexF32}}}, numElems::Int64, timeoutUs::Float64)
   @ SoapySDR ~/.julia/packages/SoapySDR/IIY7T/src/lowlevel/Device.jl:37
 [2] read!(s::SoapySDR.Stream{ComplexF32}, buffer::Tuple{Vector{ComplexF32}}; timeout::Nothing)
   @ SoapySDR ~/.julia/packages/SoapySDR/IIY7T/src/highlevel.jl:653
 [3] read!(s::SoapySDR.Stream{ComplexF32}, buffer::Tuple{Vector{ComplexF32}})
   @ SoapySDR ~/.julia/packages/SoapySDR/IIY7T/src/highlevel.jl:648
 [4] top-level scope
   @ ~/tmp/phase/distance.jl:20
 [5] include(fname::String)
   @ Base.MainInclude ./client.jl:451
 [6] top-level scope
   @ REPL[1]:1
in expression starting at /home/miguel/tmp/phase/distance.jl:20

This happens after the firmware is loaded, etc (I didn't include all that output).

`read` seems to return samples from the past

The test setup is one laptop transmitting a sine wave using a B200 with gnuradio, and a second laptop receiving using an RTLSDR and SoapySDR.jl.

Samples are read from the RTLSDR using Base.read(stream, 10_000).

This is the sequence of events:

  1. B200 transmitting; RTLSDR returns a clean sine wave.
  2. B200 off; RTLSDR returns the same sine wave.
  3. Julia restarted; RTLSDR returns noise (as expected).
  4. B200 transmitting; RTLSDR returns noise (expected a sine wave).
  5. Julia restarted; RTLSDR returns a sine wave (as expected).

One explanation is that read returns old samples stored somewhere. The ideal behavior is that samples are discarded by default; when reading, the specified number of samples are read from the device and returned; subsequent samples are discarded, until a new read is executed.

API Audit

Identification API:

GOOD.

Channels API:

GOOD.

Stream API:

  • getNativeStreamFormat
  • getStreamFormats
  • getStreamMTU
  • getStreamStatus

Direct buffer access API

Not needed. This is for driver layers. Stream interface should be used instead.

Antenna API:

  • setAntenna

Frontend corrections API

GOOD.

Gain API:

  • setGainMode
  • getGainMode
  • There may be multiple GainElements, belonging to the Channel. This is not handled in the set/getproperties, and leads to strange behavior.

There is some abstraction started for this, but I have not finished testing. I think it needs to be integrated with Channel.
For the high level API we may want to call listGains on the Channel to pre-populate.

Frequency API:

  • listFrequencies
  • Similar to GainElements.

Sample Rates API:

  • listSampleRate (optional, but seems supported in several bindings)

For high level we can likely choose the closest and warn if it is not exact. EDIT: It is deprecated.

Bandwidth API

GOOD.

ClockAPI

  • Needs implementation

TimeAPI

  • Needs implementation

SensorAPI

  • Needs implementation

SettingsAPI

  • Needs implementation

KWarg finalizer issue

error in running finalizer: MethodError(f=Base.pointer, args=(SoapySDR.OwnedKWArgs(ptr=SoapySDR.SoapySDRKwargs(size=0x0000000000000002, keys=0x0000558ebf9487c0, vals=0x0000558ebf9d0cf0)),), world=0x00000000000073c7)
jl_method_error_bare at /home/steve/Software/julia/src/gf.c:1812
jl_method_error at /home/steve/Software/julia/src/gf.c:1830
jl_lookup_generic_ at /home/steve/Software/julia/src/gf.c:2400 [inlined]
jl_apply_generic at /home/steve/Software/julia/src/gf.c:2415
SoapySDRKwargs_clear at /home/steve/.julia/dev/SoapySDR/src/highlevel.jl:60
jl_apply at /home/steve/Software/julia/src/julia.h:1703 [inlined]
run_finalizer at /home/steve/Software/julia/src/gc.c:278
jl_gc_run_finalizers_in_list at /home/steve/Software/julia/src/gc.c:365
run_finalizers at /home/steve/Software/julia/src/gc.c:394 [inlined]
run_finalizers at /home/steve/Software/julia/src/gc.c:372
jl_atexit_hook at /home/steve/Software/julia/src/init.c:240
repl_entrypoint at /home/steve/Software/julia/src/jlapi.c:703
main at /home/steve/Software/julia/cli/loader_exe.c:51
__libc_start_main at /lib/x86_64-linux-gnu/libc.so.6 (unknown line)
_start at /home/steve/Software/julia/usr/bin/julia (unknown line)

Int12 and Int4 Support

Some devices, such as the xrtrx, have native 12 bit support. There is the choice to extend to 16 bit or shift to 8 bit, either of which are typically used with bandwidth/precision tradeoffs.

It would be nice to have Int12 support so no such tradeoff has to be made in environments with a surplus of processing power, and where bandwidth can be saturated.

Large StreamBuffer requests do not block until fulfilled

julia> x=read(stream,100000000);
┌ Info: assertion debugging
│   nread = 20072
└   n = 100000000
ERROR: AssertionError: nread == n
Stacktrace:
 [1] read(s::SoapySDR.Stream{ComplexF32}, n::Int64; kwargs::Base.Iterators.Pairs{Union{}, Union{}, Tuple{}, NamedTuple{(), Tuple{}}})
   @ SoapySDR ~/.julia/packages/SoapySDR/ElzKN/src/highlevel.jl:538
 [2] read(s::SoapySDR.Stream{ComplexF32}, n::Int64)
   @ SoapySDR ~/.julia/packages/SoapySDR/ElzKN/src/highlevel.jl:534
 [3] top-level scope
   @ REPL[40]:1

Would it make sense to take the requested number of samples as a maximum, and let read return less than that?

SoapySupport Modules: API and includes

Currently we require users to load a module for their device. I think it may make sense to include these by default for our supported devices, so you get a more user friendly experience. We will also be able to regression test all the loads here as well.
I will need to audit the Yggdrasil builds. I think we only support Linux and Mac for most of these right now. We can drop an info when loading here that the device is unsupported on other platforms.

There is also a Modules API that would be helpful for additional module support. E.g if a user wanted to drop a module installed by Julia and load their own, they can do it through that API, rather than through Artifacts overrides. For example, the packaging for SoapySDR in Debian is quite extensive (though currently 0.7, we use 0.8). It may be possible to use these in the future if a user so desires. It also may help debugging and so forth.

TagBot trigger issue

This issue is used to trigger TagBot; feel free to unsubscribe.

If you haven't already, you should update your TagBot.yml to include issue comment triggers.
Please see this post on Discourse for instructions and more details.

If you'd like for me to do this for you, comment TagBot fix on this issue.
I'll open a PR within a few hours, please be patient!

UHD error when running `Devices()`

On Arch Linux, Julia 1.6.2 and SoapySDR.jl main.

It seems this error happens only when displaying a SoapySDR.Channel, and the device is actually operational.

$ julia
               _
   _       _ _(_)_     |  Documentation: https://docs.julialang.org
  (_)     | (_) (_)    |
   _ _   _| |_  __ _   |  Type "?" for help, "]?" for Pkg help.
  | | | | | | |/ _` |  |
  | | |_| | | | (_| |  |  Version 1.6.2 (2021-07-14)
 _/ |\__'_|_|_|\__'_|  |  Official https://julialang.org/ release
|__/                   |

julia> using SoapySDR, SoapyUHD_jll, Gaston

julia> channel = Devices()[1].tx[1]
[INFO] [UHD] linux; GNU C++ version 7.1.0; Boost_107600; UHD_4.1.0.HEAD-0-gf633b497
[INFO] [B200] Loading firmware image: /home/miguel/.julia/artifacts/aab01fd35ab3a7c6bbe0e50f3ae32adc1b8487c0/lib/uhd/utils/usrp_b200_fw.hex...
[INFO] [b200_impl.cpp:420] [B200] Detected Device: B200
[INFO] [B200] Detected Device: B200
[INFO] [b200_iface.cpp:568] [B200] Loading FPGA image: /home/miguel/.julia/artifacts/aab01fd35ab3a7c6bbe0e50f3ae32adc1b8487c0/lib/uhd/utils/usrp_b200_fpga.bin...
[INFO] [B200] Loading FPGA image: /home/miguel/.julia/artifacts/aab01fd35ab3a7c6bbe0e50f3ae32adc1b8487c0/lib/uhd/utils/usrp_b200_fpga.bin...
[INFO] [b200_impl.cpp:467] [B200] Operating over USB 3.
[INFO] [B200] Operating over USB 3.
[INFO] [b200_impl.cpp:522] [B200] Detecting internal GPSDO....
[INFO] [B200] Detecting internal GPSDO....
[INFO] [gps_ctrl.cpp:243] [GPS] No GPSDO found
[INFO] [GPS] No GPSDO found
[INFO] [b200_impl.cpp:618] [B200] Initialize CODEC control...
[INFO] [B200] Initialize CODEC control...
[INFO] [b200_impl.cpp:687] [B200] Initialize Radio control...
[INFO] [B200] Initialize Radio control...
[INFO] [b200_impl.cpp:1099] [B200] Performing register loopback test...
[INFO] [B200] Performing register loopback test...
[INFO] [b200_impl.cpp:1108] [B200] Register loopback test passed
[INFO] [B200] Register loopback test passed
[INFO] [b200_impl.cpp:815] [B200] Setting master clock rate selection to 'automatic'.
[INFO] [B200] Setting master clock rate selection to 'automatic'.
[INFO] [b200_impl.cpp:1149] [B200] Asking for clock rate 16.000000 MHz...
[INFO] [B200] Asking for clock rate 16.000000 MHz...
[INFO] [b200_impl.cpp:1162] [B200] Actually got clock rate 16.000000 MHz.
[INFO] [B200] Actually got clock rate 16.000000 MHz.
TX Channel #1 on B200
  Selected Antenna [TX/RX]: TX/RX
  Bandwidth [ 200 kHz .. 56 MHz ]: 56.0 MHz
  Frequency [ Error showing value of type SoapySDR.Channel:
ERROR: MethodError: no method matching print_hz_range(::IOBuffer, ::StepRangeLen{Unitful.Quantity{Float64, 𝐓^-1, Unitful.FreeUnits{(Hz,), 𝐓^-1, nothing}}, Base.TwicePrecision{Unitful.Quantity{Float64, 𝐓^-1, Unitful.FreeUnits{(Hz,), 𝐓^-1, nothing}}}, Base.TwicePrecision{Unitful.Quantity{Float64, 𝐓^-1, Unitful.FreeUnits{(Hz,), 𝐓^-1, nothing}}}})
Closest candidates are:
  print_hz_range(::IO, ::Intervals.Interval{var"#s13", Intervals.Closed, Intervals.Closed} where var"#s13") at /home/miguel/.julia/packages/SoapySDR/1PDAa/src/highlevel.jl:208
Stacktrace:
  [1] sprint(f::Function, args::StepRangeLen{Unitful.Quantity{Float64, 𝐓^-1, Unitful.FreeUnits{(Hz,), 𝐓^-1, nothing}}, Base.TwicePrecision{Unitful.Quantity{Float64, 𝐓^-1, Unitful.FreeUnits{(Hz,), 𝐓^-1, nothing}}}, Base.TwicePrecision{Unitful.Quantity{Float64, 𝐓^-1, Unitful.FreeUnits{(Hz,), 𝐓^-1, nothing}}}}; context::Nothing, sizehint::Int64)
    @ Base ./strings/io.jl:105
  [2] sprint(f::Function, args::StepRangeLen{Unitful.Quantity{Float64, 𝐓^-1, Unitful.FreeUnits{(Hz,), 𝐓^-1, nothing}}, Base.TwicePrecision{Unitful.Quantity{Float64, 𝐓^-1, Unitful.FreeUnits{(Hz,), 𝐓^-1, nothing}}}, Base.TwicePrecision{Unitful.Quantity{Float64, 𝐓^-1, Unitful.FreeUnits{(Hz,), 𝐓^-1, nothing}}}})
    @ Base ./strings/io.jl:101
  [3] (::SoapySDR.var"#2#6")(x::StepRangeLen{Unitful.Quantity{Float64, 𝐓^-1, Unitful.FreeUnits{(Hz,), 𝐓^-1, nothing}}, Base.TwicePrecision{Unitful.Quantity{Float64, 𝐓^-1, Unitful.FreeUnits{(Hz,), 𝐓^-1, nothing}}}, Base.TwicePrecision{Unitful.Quantity{Float64, 𝐓^-1, Unitful.FreeUnits{(Hz,), 𝐓^-1, nothing}}}})
    @ SoapySDR ~/.julia/packages/SoapySDR/1PDAa/src/highlevel.jl:223
  [4] iterate
    @ ./generator.jl:47 [inlined]
  [5] _collect
    @ ./array.jl:691 [inlined]
  [6] collect_similar(cont::Vector{StepRangeLen{Unitful.Quantity{Float64, 𝐓^-1, Unitful.FreeUnits{(Hz,), 𝐓^-1, nothing}}, Base.TwicePrecision{Unitful.Quantity{Float64, 𝐓^-1, Unitful.FreeUnits{(Hz,), 𝐓^-1, nothing}}}, Base.TwicePrecision{Unitful.Quantity{Float64, 𝐓^-1, Unitful.FreeUnits{(Hz,), 𝐓^-1, nothing}}}}}, itr::Base.Generator{Vector{StepRangeLen{Unitful.Quantity{Float64, 𝐓^-1, Unitful.FreeUnits{(Hz,), 𝐓^-1, nothing}}, Base.TwicePrecision{Unitful.Quantity{Float64, 𝐓^-1, Unitful.FreeUnits{(Hz,), 𝐓^-1, nothing}}}, Base.TwicePrecision{Unitful.Quantity{Float64, 𝐓^-1, Unitful.FreeUnits{(Hz,), 𝐓^-1, nothing}}}}}, SoapySDR.var"#2#6"})
    @ Base ./array.jl:606
  [7] map(f::Function, A::Vector{StepRangeLen{Unitful.Quantity{Float64, 𝐓^-1, Unitful.FreeUnits{(Hz,), 𝐓^-1, nothing}}, Base.TwicePrecision{Unitful.Quantity{Float64, 𝐓^-1, Unitful.FreeUnits{(Hz,), 𝐓^-1, nothing}}}, Base.TwicePrecision{Unitful.Quantity{Float64, 𝐓^-1, Unitful.FreeUnits{(Hz,), 𝐓^-1, nothing}}}}})
    @ Base ./abstractarray.jl:2294
  [8] show(io::IOContext{Base.TTY}, #unused#::MIME{Symbol("text/plain")}, c::SoapySDR.Channel)
    @ SoapySDR ~/.julia/packages/SoapySDR/1PDAa/src/highlevel.jl:223
  [9] (::REPL.var"#38#39"{REPL.REPLDisplay{REPL.LineEditREPL}, MIME{Symbol("text/plain")}, Base.RefValue{Any}})(io::Any)
    @ REPL /buildworker/worker/package_linux64/build/usr/share/julia/stdlib/v1.6/REPL/src/REPL.jl:220
 [10] with_repl_linfo(f::Any, repl::REPL.LineEditREPL)
    @ REPL /buildworker/worker/package_linux64/build/usr/share/julia/stdlib/v1.6/REPL/src/REPL.jl:462
 [11] display(d::REPL.REPLDisplay, mime::MIME{Symbol("text/plain")}, x::Any)
    @ REPL /buildworker/worker/package_linux64/build/usr/share/julia/stdlib/v1.6/REPL/src/REPL.jl:213
 [12] display(d::REPL.REPLDisplay, x::Any)
    @ REPL /buildworker/worker/package_linux64/build/usr/share/julia/stdlib/v1.6/REPL/src/REPL.jl:225
 [13] display(x::Any)
    @ Base.Multimedia ./multimedia.jl:328
 [14] #invokelatest#2
    @ ./essentials.jl:708 [inlined]
 [15] invokelatest
    @ ./essentials.jl:706 [inlined]
 [16] print_response(errio::IO, response::Any, show_value::Bool, have_color::Bool, specialdisplay::Union{Nothing, AbstractDisplay})
    @ REPL /buildworker/worker/package_linux64/build/usr/share/julia/stdlib/v1.6/REPL/src/REPL.jl:247
 [17] (::REPL.var"#40#41"{REPL.LineEditREPL, Pair{Any, Bool}, Bool, Bool})(io::Any)
    @ REPL /buildworker/worker/package_linux64/build/usr/share/julia/stdlib/v1.6/REPL/src/REPL.jl:231
 [18] with_repl_linfo(f::Any, repl::REPL.LineEditREPL)
    @ REPL /buildworker/worker/package_linux64/build/usr/share/julia/stdlib/v1.6/REPL/src/REPL.jl:462
 [19] print_response(repl::REPL.AbstractREPL, response::Any, show_value::Bool, have_color::Bool)
    @ REPL /buildworker/worker/package_linux64/build/usr/share/julia/stdlib/v1.6/REPL/src/REPL.jl:229
 [20] (::REPL.var"#do_respond#61"{Bool, Bool, REPL.var"#72#82"{REPL.LineEditREPL, REPL.REPLHistoryProvider}, REPL.LineEditREPL, REPL.LineEdit.Prompt})(s::REPL.LineEdit.MIState, buf::Any, ok::Bool)
    @ REPL /buildworker/worker/package_linux64/build/usr/share/julia/stdlib/v1.6/REPL/src/REPL.jl:798
 [21] #invokelatest#2
    @ ./essentials.jl:708 [inlined]
 [22] invokelatest
    @ ./essentials.jl:706 [inlined]
 [23] run_interface(terminal::REPL.Terminals.TextTerminal, m::REPL.LineEdit.ModalInterface, s::REPL.LineEdit.MIState)
    @ REPL.LineEdit /buildworker/worker/package_linux64/build/usr/share/julia/stdlib/v1.6/REPL/src/LineEdit.jl:2441
 [24] run_frontend(repl::REPL.LineEditREPL, backend::REPL.REPLBackendRef)
    @ REPL /buildworker/worker/package_linux64/build/usr/share/julia/stdlib/v1.6/REPL/src/REPL.jl:1126
 [25] (::REPL.var"#44#49"{REPL.LineEditREPL, REPL.REPLBackendRef})()
    @ REPL ./task.jl:411

julia>

Fragment issues with multiple buffers

With the highlevel_loopback.jl example, some devices with a packet interface such as the USRP fail to produce the expected result when using multiple buffers. This seems to be addressed by using a single large buffer.

cc @mbaz who reported.

Fixing to MTU is the wrong approach

#22 papered over a few issues for the sake of making progress on a few bugs and under the auspice of latency, but I realize my premise was wrong. A few short reasons:

  1. MTU may be asymmetric for read and write on the same device.
  2. It has little bearing on OS abstractions.
  3. We are not strictly optimizing for latency, but rather balancing latency, throughput, and bandwidth.
  4. We are only at the foothills of a mountain here.

--
Elaborated:

  1. A few SDR devices have different read and write MTUs which opens up a can of worms that we currently pass to the user. This can be confusing and a footgun.

  2. I started a month ago by reading transciever datasheets, then skipped about a dozen levels of abstraction up to Julia. In general it seems most protocols are not exposed as explicit duplex transfers. For USB, PCIe, etc, a read and write is done and the OS will handle the duplexing (or will pass it to hardware than can). SPI at the kernel level is anomalous with a transfer. So the abstraction is wrong for a radio transceiver IMO, but it is wrong through many layers of hardware and abstraction that we can't change (yet).

  3. Latency, throughput, and bandwidth are not simply viewed at the bus, but at the whole software-hardware integrated stack. We therefore should not strictly optimize one characteristic at the bus as it may have the opposite effect in the software.

  4. We may have top-down requirements for e.g. a filter window, that drive the transaction size. See:
    https://static.squarespace.com/static/543ae9afe4b0c3b808d72acd/543aee1fe4b09162d0863397/543aee20e4b09162d0863578/1380223973117/gr_scheduler_overview.pdf
    Aside: Dagger may be a good way to chain these things together.

So we still need to go back and handle all flags, and likely patch Soapy modules if need be. We should still expose MTU options for things like data capture with minimal processing, where high throughput are concerns. For general use, we need flexible data transfer sizes.

`read` with RTLSDR sometimes returns `TIMEOUT` or `OVERFLOW`

julia> SoapySDR.activate!(stream)

Allocating 15 zero-copy buffers
julia> x = Base.read(stream, 1000);
ERROR: TIMEOUT
Stacktrace:
 [1] SoapySDRDevice_readStream(device::SoapySDR.Device, stream::SoapySDR.Stream{ComplexF32}, buffs::Base.RefValue{Tuple{Ptr{ComplexF32}}}, numElems::Int64, timeoutUs::Float64)
   @ SoapySDR ~/.julia/packages/SoapySDR/ElzKN/src/lowlevel/Device.jl:493
 [2] #_read!#15
   @ ~/.julia/packages/SoapySDR/ElzKN/src/highlevel.jl:517 [inlined]
 [3] _read!(s::SoapySDR.Stream{ComplexF32}, buffers::Tuple{Vector{ComplexF32}})
   @ SoapySDR ~/.julia/packages/SoapySDR/ElzKN/src/highlevel.jl:513
 [4] read(s::SoapySDR.Stream{ComplexF32}, n::Int64; kwargs::Base.Iterators.Pairs{Union{}, Union{}, Tuple{}, NamedTuple{(), Tuple{}}})
   @ SoapySDR ~/.julia/packages/SoapySDR/ElzKN/src/highlevel.jl:535
 [5] read(s::SoapySDR.Stream{ComplexF32}, n::Int64)
   @ SoapySDR ~/.julia/packages/SoapySDR/ElzKN/src/highlevel.jl:534
 [6] top-level scope
   @ REPL[7]:1

This seems to happen a few times (from 1 to maybe 10) after activate!() is called. Once read succeeds, it never seems to fail again.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.