Low level API
The functions provided by UHDBindings covers two aspects: the high level API (with Julia calls and structures) and the low level API, which consists of the C functions provided by UHD. The bindings, generated by Clang.jl are not directly exported by UHDBindings but the functions can be used with
# High level call
using UHDBindings
radio = openUHD(700e6,4e6,50;nbAntennaRx=1,nbAntennaTx=1)
# Low level call
import UHDBindings.LibUHD as LibUHD
LibUHD.uhd_usrp_....()
In this case, it is necessary to align the parameters with the one requested by UHD. Thus
- To the get output parameters, it is necessary to define beforehand a Reference with the appropriate type and then deference the ref to get the value
- uhd functions often request parameters defined in the top structure layer of UHDBindings.
h
which is anuhd_usrp_handle
is defined inradio.rx.uhd.pointerUSRP
orradio.tx.uhd.pointerUSRP
- Streamer operations require
uhd_rx_streamer_handle
, which is in our structureradio.rx.uhd.pointerStreamer
- Metadata operation uses
uhd_rx_metadata_handle
(present by deferencingradio.rx.uhd.addressMD[]
) anduhd_tx_metadata_handle
(present by deferencingradio.tx.uhd.addressMD[]
) chan
corresponds to the index of the used channel. Be default (in SISO) it is0
- The
uhd_tune_request
calls are a little tricky and a Ref of the aligned Julia structureuhd_tune_request
should be used. An example is given in the Julia function updateCarrierFreq!
For instance, to manually get the Rx gain and set up the gain without using updateGain!
# High level call
using UHDBindings
radio = openUHD(700e6,4e6,50;nbAntennaRx=1,nbAntennaTx=1)
# Low level call
import UHDBindings.LibUHD as LibUHD
res = Ref{Cdouble}(0) # Define a ref to store the result, should be aligned with type in C UHD function.
LibUHD.uhd_usrp_get_rx_gain(radio.rx.uhd.pointerUSRP,0,"",res)
println("The gain is $(res[])") # using res[] to deference the ref and get the value of the gain
This low level calls can, be useful (and necessary) to define specific radio configurations and handle scenarios not supported by UHDBindings. This is for example the case of the following example that redefines all the layer to support MIMO. Note that this can be done by initiating openUHD
with nbAntennaRx=2
.
# ----------------------------------------------------
# --- Load packages
# ----------------------------------------------------
using UHDBindings
import UHDBindings.LibUHD as LibUHD
import UHDBindings.initRxUHD
import UHDBindings.@assert_uhd
# ----------------------------------------------------
# --- Parameters
# ----------------------------------------------------
carrierFreq = 868e6
samplingRate= 2e6
gain = 25
uhdArgs = ""
nbAntennaRx = 2
# ----------------------------------------------------
# --- Create radio
# ----------------------------------------------------
# --- Open radio, in MIMO mode
# Note the warning about the streamer. It can not be set in MIMO mode
# The configuration will be updated later, and most of the parameters overwritten
# To ensure we have what we want, we need to bypass the streamer, and deactivate all antennas
radio = openUHD(carrierFreq,samplingRate,gain;nbAntennaRx=0,nbAntennaTx=0,bypassStreamer = true)
# ----------------------------------------------------
# --- Set up Radio
# ----------------------------------------------------
# --- Channels & Antenna
channelIndexes = [0,1]
antennas = ["TX/RX","RX2"]
# --- Streamer arguments
a1 = Base.unsafe_convert(Cstring,"fc32");
a2 = Base.unsafe_convert(Cstring,"sc16");
a3 = Base.unsafe_convert(Cstring,uhdArgs);
channel = pointer(channelIndexes)
uhdArgs_0 = LibUHD.uhd_stream_args_t(a1,a2,a3,channel,nbAntennaRx);
# --- RF Configuration
for (c,currChan) in enumerate(channelIndexes[1:nbAntennaRx])
# Set the carrier frequencies
updateCarrierFreq!(radio.rx,carrierFreq,currChan)
# Set the sampling rate
updateSamplingRate!(radio.rx,samplingRate,currChan)
# Set the gains
updateGain!(radio.rx,gain,currChan)
# Set the antennas
LibUHD.uhd_usrp_set_rx_antenna(radio.rx.uhd.pointerUSRP,antennas[c],currChan)
end
# --- Subdev with 2 boards
pointerSubDev = Ref{LibUHD.uhd_subdev_spec_handle}()
@assert_uhd LibUHD.uhd_subdev_spec_make(pointerSubDev,"A:0 A:1")
@assert_uhd LibUHD.uhd_usrp_set_rx_subdev_spec(radio.rx.uhd.pointerUSRP,pointerSubDev[],0)
LibUHD.uhd_subdev_spec_free(pointerSubDev)
# --- Internal streamer and buffer config
pointerArgs = Ref{LibUHD.uhd_stream_args_t}(uhdArgs_0);
pointerSamples = Ref{Csize_t}(0);
@assert_uhd LibUHD.uhd_usrp_get_rx_stream(radio.rx.uhd.pointerUSRP,pointerArgs,radio.rx.uhd.pointerStreamer)
@assert_uhd LibUHD.uhd_rx_streamer_max_num_samps(radio.rx.uhd.pointerStreamer,pointerSamples)
println("Internal buffer size is $(pointerSamples[])")
radio.rx.packetSize= pointerSamples[]
# --- Clock source
@assert_uhd LibUHD.uhd_usrp_set_clock_source(radio.rx.uhd.pointerUSRP,"internal",0)
@assert_uhd LibUHD.uhd_usrp_set_time_now(radio.rx.uhd.pointerUSRP,0,0,0)
# ----------------------------------------------------
# --- Set up streamer
# ----------------------------------------------------
streamCmd = UHDBindings.uhd_stream_cmd_t(UHDBindings.UHD_STREAM_MODE_NUM_SAMPS_AND_MORE,radio.rx.packetSize*10_000,false,1,0.5);
pointerCmd = Ref{UHDBindings.uhd_stream_cmd_t}(streamCmd);
LibUHD.uhd_rx_streamer_issue_stream_cmd(radio.rx.uhd.pointerStreamer,pointerCmd)
sleep(0.1)
# ----------------------------------------------------
# --- Julia buffers
# ----------------------------------------------------
# Define an array to get all the buffers from all the channels
nbSamples = getBufferSize(radio)
sig = [zeros(Complex{Cfloat},radio.rx.packetSize) for n ∈ 1:nbAntennaRx]
listBuffer = [pointer(sig[n],1) for n ∈ 1 : nbAntennaRx]
ptr = listBuffer
pointerCounterSamples = Ref{Csize_t}(0);
# ----------------------------------------------------
# --- Receive data
# ----------------------------------------------------
pointerCounterSamples = Ref{Csize_t}(0);
LibUHD.uhd_rx_streamer_recv(radio.rx.uhd.pointerStreamer,ptr,nbSamples,radio.rx.uhd.addressMD,1.6,true,pointerCounterSamples)
nbReceivedSamples = pointerCounterSamples[]
println("Receive $nbReceivedSamples samples")
# ----------------------------------------------------
# --- Second call
# ----------------------------------------------------
accum = 0
for iN = 1 : 1 : 10_000
pointerCounterSamples = Ref{Csize_t}(0);
LibUHD.uhd_rx_streamer_recv(radio.rx.uhd.pointerStreamer,ptr,nbSamples,radio.rx.uhd.addressMD,0,true,pointerCounterSamples)
nbReceivedSamples = pointerCounterSamples[]
global accum += nbReceivedSamples
end
println("End of transmission, received $accum samples")
# ----------------------------------------------------
# --- Close
# ----------------------------------------------------
close(radio)