From d7ec3a3d0a1ac0c197d2042694be3f968ee374c8 Mon Sep 17 00:00:00 2001 From: Robin Gerzaguet Date: Tue, 25 May 2021 13:43:14 +0200 Subject: [PATCH 01/11] Remove old tests --- tests/Benchmark.jl | 151 --------------------------- tests/E310.jl | 182 --------------------------------- tests/TestE310Rx.jl | 33 ------ tests/TestRadioSim.jl | 83 --------------- tests/TestRx.jl | 30 ------ tests/TraceRx.jl | 20 ---- tests/minimalTransceiver.jl | 197 ------------------------------------ 7 files changed, 696 deletions(-) delete mode 100644 tests/Benchmark.jl delete mode 100644 tests/E310.jl delete mode 100644 tests/TestE310Rx.jl delete mode 100644 tests/TestRadioSim.jl delete mode 100644 tests/TestRx.jl delete mode 100644 tests/TraceRx.jl delete mode 100644 tests/minimalTransceiver.jl diff --git a/tests/Benchmark.jl b/tests/Benchmark.jl deleted file mode 100644 index 600ce37..0000000 --- a/tests/Benchmark.jl +++ /dev/null @@ -1,151 +0,0 @@ -module Benchmark -# ---------------------------------------------------- -# --- Modules & Utils -# ---------------------------------------------------- -# --- External modules -using AbstractSDRs -# --- Functions -""" -Calculate rate based on Julia timing -""" -function getRate(tInit,tFinal,nbSamples) - return nbSamples / (tFinal-tInit); -end - - -""" -Main call to monitor Rx rate -""" -function main(radio,samplingRate,mode=:rx) - # ---------------------------------------------------- - # --- Physical layer and RF parameters - # ---------------------------------------------------- - # --- Create the radio object in function - carrierFreq = 770e6; - gain = 50.0; - updateSamplingRate!(radio,samplingRate); - # --- Print the configuration - print(radio); - # --- Init parameters - # Get the radio size for buffer pre-allocation - nbSamples = 1*radio.rx.packetSize; - # We will get complex samples from recv! method - # Fill with random value, as it will be overwritten (and not zero for tx benchmark) - sig = randn(Complex{Cfloat},nbSamples); - # --- Targeting 2 seconds acquisition - # Init counter increment - nS = 0; - # Max counter definition - nbBuffer = 2*samplingRate; - # --- Timestamp init - if mode == :rx - pInit = recv!(sig,radio); - else - pInit =send(sig,radio,true;maxNumSamp=nbBuffer); - end - timeInit = time(); - while true - # --- Direct call to avoid allocation - if mode == :rx - p = recv!(sig,radio); - # --- Update counter - nS += p; - elseif mode == :tx - p = send(sig,radio,true;maxNumSamp=nbBuffer); - nS += p; - end - # --- Interruption - if nS > nbBuffer - break - end - end - # --- Last timeStamp and rate - timeFinal = time(); - # --- Getting effective rate - radioRate = radio.rx.samplingRate; - effectiveRate = getRate(timeInit,timeFinal,nS); - # --- Free all and return - return (radioRate,effectiveRate); -end - -function test(radioName,samplingRate) - # ---------------------------------------------------- - # --- Physical layer and RF parameters - # ---------------------------------------------------- - # --- Create the radio object in function - carrierFreq = 770e6; - gain = 50.0; - radio = openSDR(radioName,carrierFreq,samplingRate,gain;args="addr=192.168.10.12"); - # --- Print the configuration - print(radio); - # --- Init parameters - # Get the radio size for buffer pre-allocation - nbSamples = radio.packetSize; - # We will get complex samples from recv! method - sig = zeros(Complex{Cfloat},nbSamples); - # --- Targeting 2 seconds acquisition - # Init counter increment - nS = 0; - # Max counter definition - nbBuffer = 2*samplingRate; - # --- Timestamp init - pInit = recv!(sig,radio); - timeInit = time(); - while true - # --- Direct call to avoid allocation - p = recv!(sig,radio); - # # --- Ensure packet is OK - # err = getError(radio); - # (p != pInit) && (print(".")); - # --- Update counter - nS += p; - # --- Interruption - if nS > nbBuffer - break - end - end - # --- Last timeStamp and rate - timeFinal = time(); - # --- Getting effective rate - radioRate = radio.samplingRate; - effectiveRate = getRate(timeInit,timeFinal,nS); - # --- Free all and return - close(radio); - return (radioRate,effectiveRate); -end - -struct Res - radio::Symbol; - carrierFreq::Float64; - gain::Float64; - rateVect::Array{Float64}; - effectiveRate::Array{Float64}; - radioRate::Array{Float64}; -end -export Res - - -function bench(mode=:rx) - # --- Set priority - # --- Configuration - radioName = :radiosim; - carrierFreq = 770e6; - gain = 50.0; - # rateVect = [1e3;100e3;500e3;1e6:1e6:8e6;16e6;32e6;64e6;80e6;100e6;200e6]; - rateVect = [1e3;100e3;500e3;1e6:1e6:8e6;16e6]; - effectiveRate = zeros(Float64,length(rateVect)); - radioRate = zeros(Float64,length(rateVect)); - # --- Setting a very first configuration - global radio = openSDR(radioName,carrierFreq,1e6,gain;ip="192.168.10.11"); - for (iR,targetRate) in enumerate(rateVect) - (rR,eR) = main(radio,targetRate,mode); - radioRate[iR] = rR; - effectiveRate[iR] = eR; - end - close(radio); - strucRes = Res(radioName,carrierFreq,gain,rateVect,effectiveRate,radioRate); - # @save "benchmark_UHD.jld2" res; - return strucRes; -end - -end diff --git a/tests/E310.jl b/tests/E310.jl deleted file mode 100644 index bc2f96c..0000000 --- a/tests/E310.jl +++ /dev/null @@ -1,182 +0,0 @@ -# using Pkg; Pkg.develop(PackageSpec(path="../UHD"));Pkg.activate("."); -module E310 - -# ---------------------------------------------------- -# --- Module loading -# ---------------------------------------------------- -# --- Module dependency -using UHD -using Sockets -# --- Constant definition -const HOST_ADDRESS = @ip_str "192.168.10.60"; -const E310_ADRESS = @ip_str "0.0.0.0"; -const PORTHE = 30000; -const PORTEH = 36000; -# --- Global variables -flag = false; -requestConfig = false; -requestMD = false; -res = Any; - - -mutable struct Configuration - carrierFreq::Float64; - samplingRate::Float64; - gain::Union{Float64,Int}; - Antenna::String; - nbSamples::Int; -end -mutable struct MD - error::Cint; - timeStamp::Timestamp; -end - -# ---------------------------------------------------- -# --- Internal functions -# ---------------------------------------------------- -# Setting max piority to avoid CPU congestion -function setMaxPiority(); - pid = getpid(); - run(`renice -n -20 -p $pid`); - run(`chrt -p 99 $pid`) -end - -# --- Socket for radio config update -function updateConfig(configHE); - # --- Container for - global res; - # --- Raising interruption for radio config - global flag - try - while(true); - # --- Waiting a new config - receiver = Sockets.recv(configHE); - # --- Updating container with new config - global res = Meta.parse(String(receiver)); - # --- Update flag - global flag = true; - end - catch exception; - @show(exception); - end -end - - -# --- To effectively update the radio config -function updateUHD!(radio,res) - # --- We update the config - eval(res); - # --- We compute the radio update based on what we receive - str = string(res); - # --- As the radio config is updated, we will send back the config to PC - global requestConfig = true; - global requestMD = false; - # --- Update radio config based on received content - if !isnothing(findfirst("carrierFreq",str)); - # --- UHD call to update carrier frequency - updateCarrierFreq!(radio,carrierFreq); - elseif !isnothing(findfirst("gain",str)); - # --- UHD call to update gain - updateGain!(radio,gain); - elseif !isnothing(findfirst("samplingRate",str)); - # --- UHD call to update sampling rate - updateSamplingRate!(radio,samplingRate); - elseif !isnothing(findfirst("requestMD",str)); - # Set the flag to send the current radio state - requestConfig = false; - global requestMD = true; - elseif !isnothing(findfirst("requestConfig",str)); - # We have ask a new config, so nothing to do - - else - # False alarm, or nothing to push back to host - requestConfig = false; - end -end - -function sendConfig(configEH,radio,nbSamples) - # --- get Configuration from radio - config = (radio.carrierFreq,radio.samplingRate,radio.gain,radio.antenna,nbSamples); - # --- Send config - strF = "$(config)"; - Sockets.send(configEH,HOST_ADDRESS,PORTEH,strF); -end -function sendMD(configEH,radio) - md = (getTimestamp(radio)...,Cint(getError(radio))); - # --- Send config - strF = "$(md)"; - Sockets.send(configEH,HOST_ADDRESS,PORTEH,strF); -end - -# ---------------------------------------------------- -# --- Main call -# ---------------------------------------------------- -function main(carrierFreq0,samplingRate0,gain0,nbSamples) - # --- Setting high priority for the process - setMaxPiority(); - # --- Global scope config - carrierFreq = carrierFreq0; - samplingRate = samplingRate0; - gain = gain0; - # --- Setting a very first configuration - radio = openUHDRx(carrierFreq,samplingRate,gain); - # --- Create socket for data transmission - dataSocket = UDPSocket(); - # --- Get samples - sig = zeros(Complex{Cfloat},nbSamples); - cnt = 0; - # --- Start sockets - # Data socket - configHE = UDPSocket(); - Sockets.setopt(dataSocket;multicast_loop=false) - # Socket to get info from Host - Sockets.bind(configHE,E310_ADRESS,PORTHE,reuseaddr=true); - # Socket to push back infos - configEH = UDPSocket(); - # Start monitoring server - @async updateConfig(configHE); - # --- Containers for radio config - global flag = false; - global requestMD = false; - global requestConfig = false; - global res = Any; - try - while(true) - # --- Interruption to update radio config - if flag - # --- Flag update - @info "Configuration for the radio"; - flag = false; - # --- UHD update - updateUHD!(radio,res); - # --- Print res (need sleep to see something) - print(radio); - sleep(0.010); - end - if requestConfig - # --- Sending the configuration to Host - sendConfig(configEH,radio,nbSamples); - requestConfig = false; - end - if requestMD - sendMD(configEH,radio); - requestMD = false; - end - # --- Direct call to avoid allocation - recv!(sig,radio); - # --- To UDP socket - Sockets.send(dataSocket,HOST_ADDRESS,2001,sig); - end - catch exception; - # --- Close UHD - close(radio); - # --- Close sockets - close(dataSocket); - close(configHE); - close(configEH); - # --- Release USRP - @show exception; - end -end - -end diff --git a/tests/TestE310Rx.jl b/tests/TestE310Rx.jl deleted file mode 100644 index 5a07e15..0000000 --- a/tests/TestE310Rx.jl +++ /dev/null @@ -1,33 +0,0 @@ -module TestE310Rx - -using AbstractSDRs - -# Testing E310 device, with the use of SDROverNetwork -function main() - - # --- Main parameters - carrierFreq = 440e6; # --- The carrier frequency - samplingRate = 4e6; # --- Targeted bandwdith - gain = 0.0; # --- Rx gain - ipAddr = "192.168.10.13"; - nbSamples = 2048; - # --- Create the E310 device - # E310 = openSDR(:e310,carrierFreq,samplingRate,gain;addr=ipAddr); - # E310 = openSDR(:e310,carrierFreq,samplingRate,gain;packetSize=1024,args="addr=$ipAddr"); - E310 = openSDR(:sdr_over_network,carrierFreq,samplingRate,gain;packetSize=1024,args="addr=$ipAddr"); - print(E310); - sleep(2); - @info "Ready" - updateCarrierFreq!(E310,770e6); - print(E310); - # - sig = recv(E310,nbSamples) - @show size(sig); - @show getError(E310) - @show getTimestamp(E310) - # - close(E310); -end - - -end diff --git a/tests/TestRadioSim.jl b/tests/TestRadioSim.jl deleted file mode 100644 index c6163e4..0000000 --- a/tests/TestRadioSim.jl +++ /dev/null @@ -1,83 +0,0 @@ -module TestRadioSim -using AbstractSDRs - - -function main() - - # --- Main parameters - carrierFreq = 440e6; # --- The carrier frequency - samplingRate = 100e6; # --- Targeted bandwdith - gain = 0.0; # --- Rx gain - sdr = :radiosim; - nbSamples = 1024; - # --- Create the E310 device - radio = openSDR(sdr,carrierFreq,samplingRate,gain;packetSize=512); - print(radio); - sleep(2); - @info "Ready" - updateCarrierFreq!(radio,770e6); - print(radio); - # - sig = recv(radio,nbSamples) - # - close(radio); -end - -function mainWithBuffer() - # --- Main parameters - carrierFreq = 440e6; # --- The carrier frequency - samplingRate = 100e6; # --- Targeted bandwdith - gain = 0.0; # --- Rx gain - sdr = :radiosim; - nbSamples = 1024; - # ---------------------------------------------------- - # --- Buffer emulation - # ---------------------------------------------------- - buffer = collect(1:4096); - # --- Create the E310 device - radio = openSDR(sdr,carrierFreq,samplingRate,gain;packetSize=512,buffer=buffer); - print(radio); - sleep(2); - # @info "Ready" - updateCarrierFreq!(radio,770e6); - print(radio); - # - sig = recv(radio,nbSamples) - sig .= 0 - sig = recv(radio,nbSamples) - # - close(radio); - return sig -end - - -function mainWithSmallBuffer() - # --- Main parameters - carrierFreq = 440e6; # --- The carrier frequency - samplingRate = 100e6; # --- Targeted bandwdith - gain = 0.0; # --- Rx gain - sdr = :radiosim; - nbSamples = 1024; - # ---------------------------------------------------- - # --- Buffer emulation - # ---------------------------------------------------- - buffer = collect(1:256); - # --- Create the E310 device - radio = openSDR(sdr,carrierFreq,samplingRate,gain;packetSize=512,buffer=buffer); - print(radio); - sleep(2); - # @info "Ready" - updateCarrierFreq!(radio,770e6); - print(radio); - # - sig = recv(radio,nbSamples) - sig .= 0 - sig = recv(radio,nbSamples) - # - close(radio); - return sig -end -end - - - diff --git a/tests/TestRx.jl b/tests/TestRx.jl deleted file mode 100644 index 816c5a7..0000000 --- a/tests/TestRx.jl +++ /dev/null @@ -1,30 +0,0 @@ -module TestRx - -using AbstractSDRs - - -function main() - - # --- Main parameters - carrierFreq = 440e6; # --- The carrier frequency - samplingRate = 100e6; # --- Targeted bandwdith - gain = 0.0; # --- Rx gain - ipAddr = "192.168.10.11"; - sdr = "UHDRx"; - nbSamples = 1024; - # --- Create the E310 device - # E310 = openE310("Rx",carrierFreq,samplingRate,gain;ip=ipAddr); - E310 = openSDR(sdr,carrierFreq,samplingRate,gain;ip=ipAddr); - print(E310); - sleep(2); - @info "Ready" - updateCarrierFreq!(E310,770e6); - print(E310); - # - sig = recv(E310,nbSamples) - # - close(E310); -end - - -end diff --git a/tests/TraceRx.jl b/tests/TraceRx.jl deleted file mode 100644 index bc994a0..0000000 --- a/tests/TraceRx.jl +++ /dev/null @@ -1,20 +0,0 @@ -using FFTW -using AbstractSDRs - -# ---------------------------------------------------- -# --- Physical layer and RF parameters -# ---------------------------------------------------- -carrierFreq = 770e6; -samplingRate = 5.33e6; -gain = 25; -nbSamples = 1016; - -# --- Setting a very first configuration -radio = openSDR("E310",carrierFreq,samplingRate,gain;ip="192.168.10.11"); -print(radio); -# --- Get samples -sig= recv(radio, nbSamples); -# --- Release USRP -close(radio); - - diff --git a/tests/minimalTransceiver.jl b/tests/minimalTransceiver.jl deleted file mode 100644 index 004c9c3..0000000 --- a/tests/minimalTransceiver.jl +++ /dev/null @@ -1,197 +0,0 @@ -# using Pkg; Pkg.develop(PackageSpec(path="../UHD"));Pkg.activate("."); -@info "Julia-based minimal transceiver"; - -using Distributed -module E310 - -# ---------------------------------------------------- -# --- Module loading -# ---------------------------------------------------- -# --- Module dependency -using UHDBindings -using Distributed -using ZMQ -@everywhere using Sockets - -mutable struct Configuration - carrierFreq::Float64; - samplingRate::Float64; - gain::Union{Float64,Int}; - Antenna::String; - nbSamples::Int; -end -mutable struct MD - error::Cint; - timeStamp::Timestamp; -end - -# Setting max piority to avoid CPU congestion -function setMaxPriority(); - pid = getpid(); - run(`renice -n -20 -p $pid`); - run(`chrt -p 99 $pid`) -end - - -# ---------------------------------------------------- -# --- Main call -# ---------------------------------------------------- -function main(mode,carrierFreq, samplingRate, gain, nbSamples) - # --- Setting a very first configuration - radio = openUHD(carrierFreq, samplingRate, gain); - # --- Configuration socket - rtcSocket = ZMQ.Socket(REP); - bind(rtcSocket, "tcp://*:5555"); - # --- RTT socket for Tx - rttSocket = ZMQ.Socket(REQ); - bind(rttSocket, "tcp://*:9999"); - # --- Socket for broadcast Rx - brSocket = ZMQ.Socket(PUB); - bind(brSocket, "tcp://*:1111"); - # --- Get samples - sig = zeros(Complex{Cfloat}, radio.rx.packetSize); - cnt = 0; - # --- Mode used - # mode = :rx; - # --- Processing - try - print(radio); - # --- Second order loop setup - flag = false; - # --- Interruption to update radio config - @async begin - while (true) - # --- We wait in this @async for a reception - receiver = ZMQ.recv(rtcSocket); - # --- Here, we have receive something - # Raise a flag because something happens - flag = true; - # we create an evaluation here - res = Meta.parse(String(receiver)); - # and we update the radio and get back the desired feeback level - (requestConfig, requestMD, mode, buffer,updateBuffer) = updateUHD!(radio, res,mode); - if requestConfig - # --- Sending the configuration to Host - sendConfig(rtcSocket, radio.rx, nbSamples); - end - if requestMD - sendMD(rtcSocket, radio.rx); - end - if updateBuffer - # --- Replace sig by obtained buffer - sig = buffer; - end - end - print(radio) - end - # if mode == :txbuffer - # --- Send data to radio - # UHDBindings.send(radio, sig,true); - # else - while (true) - if mode == :rx - # --- Direct call to avoid allocation - recv!(sig, radio); - # --- To UDP socket - ZMQ.send(brSocket, sig) - yield(); - elseif mode == :tx - # --- We now transmit data ! - # Wait for RTT from host - ZMQ.send(rttSocket,0x01); - # --- Get the data - sig = convert.(Complex{Cfloat},ZMQ.recv(rttSocket)); - # --- Send data to radio - UHDBindings.send(radio, sig,false); - yield(); - elseif mode == :txbuffer - # --- Send data to radio using cyclic mode - nbE = UHDBindings.send(radio, sig,false); - (nbE == 0) && (break); - yield(); - end - end - catch exception; - # --- Release USRP - show(exception); - end - # --- Close UHD - close(radio); - # --- Close sockets - close(rtcSocket); - close(rttSocket); - close(brSocket); - return sig; -end - - -# --- To effectively update the radio config -function updateUHD!(radio, res,mode) - # --- Default output - requestConfig = true; - requestMD = false; - updateBuffer = false; - # --- We create the dictionnary entry to update the radio config - D = eval(res); - # --- Apply the changes - buffer = zeros(Complex{Cfloat},1024); - for key in keys(D) - elem = D[key]; - if key == :requestMD - # --- We only ask for MD and not config - requestMD = true; - requestConfig = false; - elseif key == :requestConfig - # --- Nothing to do - elseif key == :updateCarrierFreq - # --- Update the carrier freq - updateCarrierFreq!(radio, elem); - elseif key == :updateSamplingRate - # --- Update sampling frequency - updateSamplingRate!(radio, elem); - elseif key == :updateGain - # --- Update Gain - println("$elem"); - updateGain!(radio, elem); - elseif key == :buffer - buffer = elem; - updateBuffer = true; - elseif key == :mode - # --- We change mode - mode = elem; - requestConfig = false; - requestMD = true; - @info "Change mode to $mode"; - else - @warn "Unknown Host order. Ask to update $key field with value $elem which is unknwown" - end - end - print(radio) - return (requestConfig, requestMD, mode, buffer, updateBuffer); -end - - -function sendConfig(rtcSocket, radio, nbSamples) - # --- get Configuration from radio - config = (radio.carrierFreq, radio.samplingRate, radio.gain, radio.antenna, nbSamples); - # --- Send config - strF = "$(config)"; - ZMQ.send(rtcSocket, strF); -end -function sendMD(rtcSocket, radio) - md = (getTimestamp(radio)..., Cint(getError(radio))); - # --- Send config - strF = "$(md)"; - ZMQ.send(rtcSocket, strF); -end - -end - -tx() = E310.main(:tx,868e6,4e6,10,(512 + 36) * 2 * 32); -txBuffer() = E310.main(:txbuffer,868e6,4e6,10,(512 + 36) * 2 * 32); -rx() = E310.main(:rx,868e6,4e6,10,(512 + 36) * 2 * 32); - - -# call main function -# E310.main(:rx,868e6,4e6,10,(512 + 36) * 2 * 32); -# E310.main(868e6,4e6,10,32768); From 96afc82663daf37c631b16d933e4b560e94fb87d Mon Sep 17 00:00:00 2001 From: Robin Gerzaguet Date: Tue, 25 May 2021 13:43:29 +0200 Subject: [PATCH 02/11] Adding new examples --- examples/Benchmark.jl | 151 ++++++++++++++++++++++++ examples/minimalTransceiver.jl | 205 +++++++++++++++++++++++++++++++++ 2 files changed, 356 insertions(+) create mode 100644 examples/Benchmark.jl create mode 100644 examples/minimalTransceiver.jl diff --git a/examples/Benchmark.jl b/examples/Benchmark.jl new file mode 100644 index 0000000..600ce37 --- /dev/null +++ b/examples/Benchmark.jl @@ -0,0 +1,151 @@ +module Benchmark +# ---------------------------------------------------- +# --- Modules & Utils +# ---------------------------------------------------- +# --- External modules +using AbstractSDRs +# --- Functions +""" +Calculate rate based on Julia timing +""" +function getRate(tInit,tFinal,nbSamples) + return nbSamples / (tFinal-tInit); +end + + +""" +Main call to monitor Rx rate +""" +function main(radio,samplingRate,mode=:rx) + # ---------------------------------------------------- + # --- Physical layer and RF parameters + # ---------------------------------------------------- + # --- Create the radio object in function + carrierFreq = 770e6; + gain = 50.0; + updateSamplingRate!(radio,samplingRate); + # --- Print the configuration + print(radio); + # --- Init parameters + # Get the radio size for buffer pre-allocation + nbSamples = 1*radio.rx.packetSize; + # We will get complex samples from recv! method + # Fill with random value, as it will be overwritten (and not zero for tx benchmark) + sig = randn(Complex{Cfloat},nbSamples); + # --- Targeting 2 seconds acquisition + # Init counter increment + nS = 0; + # Max counter definition + nbBuffer = 2*samplingRate; + # --- Timestamp init + if mode == :rx + pInit = recv!(sig,radio); + else + pInit =send(sig,radio,true;maxNumSamp=nbBuffer); + end + timeInit = time(); + while true + # --- Direct call to avoid allocation + if mode == :rx + p = recv!(sig,radio); + # --- Update counter + nS += p; + elseif mode == :tx + p = send(sig,radio,true;maxNumSamp=nbBuffer); + nS += p; + end + # --- Interruption + if nS > nbBuffer + break + end + end + # --- Last timeStamp and rate + timeFinal = time(); + # --- Getting effective rate + radioRate = radio.rx.samplingRate; + effectiveRate = getRate(timeInit,timeFinal,nS); + # --- Free all and return + return (radioRate,effectiveRate); +end + +function test(radioName,samplingRate) + # ---------------------------------------------------- + # --- Physical layer and RF parameters + # ---------------------------------------------------- + # --- Create the radio object in function + carrierFreq = 770e6; + gain = 50.0; + radio = openSDR(radioName,carrierFreq,samplingRate,gain;args="addr=192.168.10.12"); + # --- Print the configuration + print(radio); + # --- Init parameters + # Get the radio size for buffer pre-allocation + nbSamples = radio.packetSize; + # We will get complex samples from recv! method + sig = zeros(Complex{Cfloat},nbSamples); + # --- Targeting 2 seconds acquisition + # Init counter increment + nS = 0; + # Max counter definition + nbBuffer = 2*samplingRate; + # --- Timestamp init + pInit = recv!(sig,radio); + timeInit = time(); + while true + # --- Direct call to avoid allocation + p = recv!(sig,radio); + # # --- Ensure packet is OK + # err = getError(radio); + # (p != pInit) && (print(".")); + # --- Update counter + nS += p; + # --- Interruption + if nS > nbBuffer + break + end + end + # --- Last timeStamp and rate + timeFinal = time(); + # --- Getting effective rate + radioRate = radio.samplingRate; + effectiveRate = getRate(timeInit,timeFinal,nS); + # --- Free all and return + close(radio); + return (radioRate,effectiveRate); +end + +struct Res + radio::Symbol; + carrierFreq::Float64; + gain::Float64; + rateVect::Array{Float64}; + effectiveRate::Array{Float64}; + radioRate::Array{Float64}; +end +export Res + + +function bench(mode=:rx) + # --- Set priority + # --- Configuration + radioName = :radiosim; + carrierFreq = 770e6; + gain = 50.0; + # rateVect = [1e3;100e3;500e3;1e6:1e6:8e6;16e6;32e6;64e6;80e6;100e6;200e6]; + rateVect = [1e3;100e3;500e3;1e6:1e6:8e6;16e6]; + effectiveRate = zeros(Float64,length(rateVect)); + radioRate = zeros(Float64,length(rateVect)); + # --- Setting a very first configuration + global radio = openSDR(radioName,carrierFreq,1e6,gain;ip="192.168.10.11"); + for (iR,targetRate) in enumerate(rateVect) + (rR,eR) = main(radio,targetRate,mode); + radioRate[iR] = rR; + effectiveRate[iR] = eR; + end + close(radio); + strucRes = Res(radioName,carrierFreq,gain,rateVect,effectiveRate,radioRate); + # @save "benchmark_UHD.jld2" res; + return strucRes; +end + +end diff --git a/examples/minimalTransceiver.jl b/examples/minimalTransceiver.jl new file mode 100644 index 0000000..228147d --- /dev/null +++ b/examples/minimalTransceiver.jl @@ -0,0 +1,205 @@ +# ---------------------------------------------------- +# --- minimalTransceiver.jl +# ---------------------------------------------------- +# This file is intented to give an example on how we can use tree based network architecture with SDR +# This file has to be run on a SDR based SoC that communicated with a remote PC +# --------- +# | +# For instance, a USRP e310 with a julia session runs minimalTransceiver.jl +# On the PC side, the backend SDROverNetworks can be used to recover data from the E310 +@info "Julia-based minimal transceiver"; + +using Distributed +module E310 + +# ---------------------------------------------------- +# --- Module loading +# ---------------------------------------------------- +# --- Module dependency +using UHDBindings +using Distributed +using ZMQ +@everywhere using Sockets + +mutable struct Configuration + carrierFreq::Float64; + samplingRate::Float64; + gain::Union{Float64,Int}; + Antenna::String; + nbSamples::Int; +end +mutable struct MD + error::Cint; + timeStamp::Timestamp; +end + +# Setting max piority to avoid CPU congestion +function setMaxPriority(); + pid = getpid(); + run(`renice -n -20 -p $pid`); + run(`chrt -p 99 $pid`) +end + + +# ---------------------------------------------------- +# --- Main call +# ---------------------------------------------------- +function main(mode,carrierFreq, samplingRate, gain, nbSamples) + # --- Setting a very first configuration + radio = openUHD(carrierFreq, samplingRate, gain); + # --- Configuration socket + rtcSocket = ZMQ.Socket(REP); + bind(rtcSocket, "tcp://*:5555"); + # --- RTT socket for Tx + rttSocket = ZMQ.Socket(REQ); + bind(rttSocket, "tcp://*:9999"); + # --- Socket for broadcast Rx + brSocket = ZMQ.Socket(PUB); + bind(brSocket, "tcp://*:1111"); + # --- Get samples + sig = zeros(Complex{Cfloat}, radio.rx.packetSize); + cnt = 0; + # --- Mode used + # mode = :rx; + # --- Processing + try + print(radio); + # --- Second order loop setup + flag = false; + # --- Interruption to update radio config + @async begin + while (true) + # --- We wait in this @async for a reception + receiver = ZMQ.recv(rtcSocket); + # --- Here, we have receive something + # Raise a flag because something happens + flag = true; + # we create an evaluation here + res = Meta.parse(String(receiver)); + # and we update the radio and get back the desired feeback level + (requestConfig, requestMD, mode, buffer,updateBuffer) = updateUHD!(radio, res,mode); + if requestConfig + # --- Sending the configuration to Host + sendConfig(rtcSocket, radio.rx, nbSamples); + end + if requestMD + sendMD(rtcSocket, radio.rx); + end + if updateBuffer + # --- Replace sig by obtained buffer + sig = buffer; + end + end + print(radio) + end + # if mode == :txbuffer + # --- Send data to radio + # UHDBindings.send(radio, sig,true); + # else + while (true) + if mode == :rx + # --- Direct call to avoid allocation + recv!(sig, radio); + # --- To UDP socket + ZMQ.send(brSocket, sig) + yield(); + elseif mode == :tx + # --- We now transmit data ! + # Wait for RTT from host + ZMQ.send(rttSocket,0x01); + # --- Get the data + sig = convert.(Complex{Cfloat},ZMQ.recv(rttSocket)); + # --- Send data to radio + UHDBindings.send(radio, sig,false); + yield(); + elseif mode == :txbuffer + # --- Send data to radio using cyclic mode + nbE = UHDBindings.send(radio, sig,false); + (nbE == 0) && (break); + yield(); + end + end + catch exception; + # --- Release USRP + show(exception); + end + # --- Close UHD + close(radio); + # --- Close sockets + close(rtcSocket); + close(rttSocket); + close(brSocket); + return sig; +end + + +# --- To effectively update the radio config +function updateUHD!(radio, res,mode) + # --- Default output + requestConfig = true; + requestMD = false; + updateBuffer = false; + # --- We create the dictionnary entry to update the radio config + D = eval(res); + # --- Apply the changes + buffer = zeros(Complex{Cfloat},1024); + for key in keys(D) + elem = D[key]; + if key == :requestMD + # --- We only ask for MD and not config + requestMD = true; + requestConfig = false; + elseif key == :requestConfig + # --- Nothing to do + elseif key == :updateCarrierFreq + # --- Update the carrier freq + updateCarrierFreq!(radio, elem); + elseif key == :updateSamplingRate + # --- Update sampling frequency + updateSamplingRate!(radio, elem); + elseif key == :updateGain + # --- Update Gain + println("$elem"); + updateGain!(radio, elem); + elseif key == :buffer + buffer = elem; + updateBuffer = true; + elseif key == :mode + # --- We change mode + mode = elem; + requestConfig = false; + requestMD = true; + @info "Change mode to $mode"; + else + @warn "Unknown Host order. Ask to update $key field with value $elem which is unknwown" + end + end + print(radio) + return (requestConfig, requestMD, mode, buffer, updateBuffer); +end + + +function sendConfig(rtcSocket, radio, nbSamples) + # --- get Configuration from radio + config = (radio.carrierFreq, radio.samplingRate, radio.gain, radio.antenna, nbSamples); + # --- Send config + strF = "$(config)"; + ZMQ.send(rtcSocket, strF); +end +function sendMD(rtcSocket, radio) + md = (getTimestamp(radio)..., Cint(getError(radio))); + # --- Send config + strF = "$(md)"; + ZMQ.send(rtcSocket, strF); +end + +end + +tx() = E310.main(:tx,868e6,4e6,10,(512 + 36) * 2 * 32); +txBuffer() = E310.main(:txbuffer,868e6,4e6,10,(512 + 36) * 2 * 32); +rx() = E310.main(:rx,868e6,4e6,10,(512 + 36) * 2 * 32); + + +# call main function +# E310.main(:rx,868e6,4e6,10,(512 + 36) * 2 * 32); +# E310.main(868e6,4e6,10,32768); From bb6b6b27da9791e76fdc1d731bb97e24e589ac60 Mon Sep 17 00:00:00 2001 From: Robin Gerzaguet Date: Tue, 25 May 2021 13:44:40 +0200 Subject: [PATCH 03/11] Full new skeleton structure --- src/AbstractSDRs.jl | 217 +++++++------------------- src/Assessors.jl | 64 ++++++++ src/Backends.jl | 60 +++++++ src/{ => Backends}/RTLSDRBindings.jl | 4 +- src/{ => Backends}/RadioSims.jl | 9 +- src/{ => Backends}/SDROverNetworks.jl | 2 +- src/Mutators.jl | 55 +++++++ src/Printing.jl | 1 + src/Scan.jl | 72 +++++++++ src/Utils.jl | 22 +++ 10 files changed, 342 insertions(+), 164 deletions(-) create mode 100644 src/Assessors.jl create mode 100644 src/Backends.jl rename src/{ => Backends}/RTLSDRBindings.jl (97%) rename src/{ => Backends}/RadioSims.jl (97%) rename src/{ => Backends}/SDROverNetworks.jl (99%) create mode 100644 src/Mutators.jl create mode 100644 src/Scan.jl create mode 100644 src/Utils.jl diff --git a/src/AbstractSDRs.jl b/src/AbstractSDRs.jl index 98d5203..9481334 100644 --- a/src/AbstractSDRs.jl +++ b/src/AbstractSDRs.jl @@ -7,67 +7,71 @@ using Sockets using Reexport using RTLSDR - import Base:close; -# ---------------------------------------------------- -# --- UHD Bindings -# ---------------------------------------------------- -# --- -@reexport using UHDBindings -# --- Specific UHD related functions -export UHDBinding # ---------------------------------------------------- -# --- Adalm Pluto managment -# ---------------------------------------------------- -# --- -@reexport using AdalmPluto -export AdalmPluto; -export updateGainMode!; -# --- Conversion -# Adalm Pluto structure is based on Int parameters, and AbstractSDRs use massively Float. We need to convert just before dispatching. As some parameter may be float (as gain) we should round before conversion. The following function does that. -_toInt(x) = Int(round(x)); +# --- Get Supported backends +# ---------------------------------------------------- +""" +Returns an array of symbol which lists the supported SDR backends +# --- Syntax +l = getSupportedSDR() +# --- Input parameters +- +# --- Output parameters +- l : Array of symbols of supported SDRs +""" +function getSupportedSDRs() + return [:uhd;:sdr_over_network;:radiosim;:pluto;:rtlsdr]; +end +export getSupportedSDRs + -# ---------------------------------------------------- -# --- RTL-SDR bindings -# ---------------------------------------------------- -include("RTLSDRBindings.jl"); -@reexport using .RTLSDRBindings -export RTLSDRBinding # ---------------------------------------------------- -# --- Socket System -# ---------------------------------------------------- -# --- Create and load module to pilot E310 devices -# To control this device we create a pure Socket based system -# for which the AbstractSDRs package will help to bind the utils -include("SDROverNetworks.jl"); -@reexport using .SDROverNetworks -# --- Specific E310 related functions -export SDROverNetwork; +# --- Utils +# ---------------------------------------------------- +# Common generic functions and glue required for the package +# Nothing strictly related to radio here, only common stuff +include("Utils.jl") # ---------------------------------------------------- -# --- Simulation Radio +# --- Backends +# ---------------------------------------------------- +# --- Load backend +include("Backends.jl") + # ---------------------------------------------------- -# --- Create and module to emulate a radio device without any actual radio connected -include("RadioSims.jl"); -@reexport using .RadioSims -# --- Specific simulation related function -export updatePacketSize!; -export updateBuffer!; -export RadioSim; +# --- Scanning +# ---------------------------------------------------- +include("Scan.jl") +export scan # ---------------------------------------------------- -# --- Setting all methods using dispatch +# --- Radio configuration (update radio parameters) +# ---------------------------------------------------- +include("Mutators.jl") +export updateCarrierFreq! +export updateSamplingRate! +export updateGain! +export updateGainMode! + # ---------------------------------------------------- -# --- Common framework functions -# Closing resources call -# close(radio::RadioSim) = RadioSim.close(radio); -# close(radio::UHDBinding) = UHDBindings.close(radio); -# close(radio::SDROverNetwork) = SDROverNetworks.close(radio); -# close(radio::RTLSDRBinding) = RTLSDRBindings.close(radio); -# close(obj::PlutoSDR) = AdalmPluto.close(obj); -# export close; +# --- Assessors (get radio parameters) +# ---------------------------------------------------- +include("Assessors.jl") +export getError +export getTimestamp +export getSamplingRate +export getCarrierFreq +export getGain +export isClosed +export getBufferSize + + +#---------------------------------------------------- +# --- Common API +# ---------------------------------------------------- # recv call """ @@ -118,117 +122,13 @@ send(radio,buffer,cyclic=false) - nbEch : Number of samples effectively send [Csize_t]. It corresponds to the number of complex samples sent. """ -send(sig,obj::SDROverNetwork,tul...;kwarg...) = SDROverNetworks.send(sig,obj,tul...;kwarg...); -send(sig,obj::UHDBinding,tul...) = UHDBindings.send(sig,obj,tul...); -send(sig,obj::RadioSim,tul...) = RadioSims.send(sig,obj,tul...); -send(sig,obj::RTLSDRBinding,tul...) = RTLSDRBindings.send(sig,obj,tul...); +send(obj::SDROverNetwork,sig,tul...;kwarg...) = SDROverNetworks.send(obj,sig,tul...;kwarg...); +send(obj::UHDBinding,sig,tul...) = UHDBindings.send(obj,sig,tul...); +send(obj::RadioSim,sig,tul...) = RadioSims.send(obj,sig,tul...); +send(obj::RTLSDRBinding,sig,tul...) = RTLSDRBindings.send(obj,sig,tul...); export send -# Radio API -updateCarrierFreq!(obj::SDROverNetwork,tul...) = SDROverNetworks.updateCarrierFreq!(obj,tul...); -updateCarrierFreq!(obj::UHDBinding,tul...) = UHDBindings.updateCarrierFreq!(obj,tul...); -updateCarrierFreq!(obj::RadioSim,tul...) = RadioSims.updateCarrierFreq!(obj,tul...); -updateCarrierFreq!(obj::RTLSDRBinding,tul...) = RTLSDRBindings.updateCarrierFreq!(obj,tul...); -updateCarrierFreq!(obj::PlutoSDR,tul...) = AdalmPluto.updateCarrierFreq!(obj,_toInt.(tul)...); -export updateCarrierFreq!; - -""" -Update sampling rate of current radio device, and update radio object with the new obtained sampling frequency. -# --- Syntax -updateSamplingRate!(radio,samplingRate) -# --- Input parameters -- radio : SDR device -- samplingRate : New desired sampling rate -# --- Output parameters -- -""" -updateSamplingRate!(obj::SDROverNetwork,tul...) = SDROverNetworks.updateSamplingRate!(obj,tul...); -updateSamplingRate!(obj::UHDBinding,tul...) = UHDBindings.updateSamplingRate!(obj,tul...); -updateSamplingRate!(obj::RadioSim,tul...) = RadioSims.updateSamplingRate!(obj,tul...); -updateSamplingRate!(obj::RTLSDRBinding,tul...) = RTLSDRBindings.updateSamplingRate!(obj,tul...); -function updateSamplingRate!(obj::PlutoSDR,tul...) - # For Adalm Pluto we should also update the RF filter band - AdalmPluto.updateSamplingRate!(obj,_toInt.(tul)...); - AdalmPluto.updateBandwidth!(obj,_toInt.(tul)...); - return obj.rx.effectiveSamplingRate -end -export updateSamplingRate!; -""" -Update gain of current radio device, and update radio object with the new obtained gain. -If the input is a [UHDRx] or a [UHDTx] object, it updates only the Rx or Tx gain -# --- Syntax -updateGain!(radio,gain) -# --- Input parameters -- radio : SDR device -- gain : New desired gain -# --- Output parameters -- -""" -updateGain!(obj::SDROverNetwork,tul...) = SDROverNetworks.updateGain!(obj,tul...); -updateGain!(obj::UHDBinding,tul...) = UHDBindings.updateGain!(obj,tul...); -updateGain!(obj::RadioSim,tul...) = RadioSims.updateGain!(obj,tul...); -updateGain!(obj::RTLSDRBinding,tul...) = RTLSDRBindings.updateGain!(obj,tul...); -updateGain!(obj::PlutoSDR,tul...) = AdalmPluto.updateGain!(obj,_toInt.(tul)...); -export updateGain!; - -getError(obj::UHDBinding) = UHDBindings.getError(obj); -getError(obj::RadioSim) = RadioSims.getError(obj); -getError(obj::SDROverNetwork) = SDROverNetworks.getMD(obj)[3]; -getError(obj::RTLSDRBinding) = RTLSDRBindings.getError(obj); -export getError; - -getTimestamp(obj::UHDBinding) = UHDBindings.getTimestamp(obj); -getTimestamp(obj::RadioSim) = RadioSims.getTimestamp(obj); -getTimestamp(obj::SDROverNetwork) = SDROverNetworks.getMD(obj)[1:2]; -getTimestamp(obj::RTLSDRBinding) = RTLSDRBindings.getTimestamp(obj); - -""" -Get the current sampling rate of the radio device -The second parameter (optionnal) speicfies the Rx or Tx board (default : Rx) -""" -getSamplingRate(obj::UHDBinding;mode=:rx) = ((mode == :rx) ? obj.rx.samplingRate : obj.tx.samplingRate) -getSamplingRate(obj::RadioSim;mode=:rx) = ((mode == :rx) ? obj.rx.samplingRate : obj.tx.samplingRate) -getSamplingRate(obj::SDROverNetwork;mode=:rx) = ((mode == :rx) ? obj.rx.samplingRate : obj.tx.samplingRate) -getSamplingRate(obj::PlutoSDR;mode=:rx) = ((mode == :rx) ? obj.rx.effectiveSamplingRate : obj.tx.effectiveSamplingRate) -export getSamplingRate - -""" -Get the current carrier frequency of the radio device -The second parameter (optionnal) speicfies the Rx or Tx board (default : Rx) -""" -getCarrierFreq(obj::UHDBinding;mode=:rx) = (mode == :rx) ? obj.rx.samplingRate : obj.tx.samplingRate -getCarrierFreq(obj::RadioSim;mode=:rx) = (mode == :rx) ? obj.rx.samplingRate : obj.tx.samplingRate -getCarrierFreq(obj::SDROverNetwork;mode=:rx) = (mode == :rx) ? obj.rx.samplingRate : obj.tx.samplingRate -getCarrierFreq(obj::PlutoSDR;mode=:rx) = (mode == :rx) ? obj.rx.effectiveCarrierFreq : obj.tx.effectiveCarrierFreq -export getCarrierFreq - -# --- Container for Radio use -# We will have functions from different origin and different supported keywords -# This function parse the input keywords and returns the ones supported by the function, listed in iteration -function parseKeyword(kwargs,iteration) - # We populate a new dictionnary based on the input keywords and the supported ones - # In order not to create keywords that are not supported (i.e leaving the default value) - # we only evaluate the keywords defined both in the 2 dictionnaries - # This means that the default fallback should never happen - kwargs = Dict(key=>get(kwargs,key,0) for key in intersect(iteration,keys(kwargs))) - return kwargs -end - - -""" -Returns an array of symbol which lists the supported SDR backends -# --- Syntax -l = getSupportedSDR() -# --- Input parameters -- -# --- Output parameters -- l : Array of symbols of supported SDRs -""" -function getSupportedSDRs() - return [:uhd;:sdr_over_network;:radiosim;:pluto;:rtlsdr]; -end -export getSupportedSDRs """ Open a Software Defined Radio of backend 'type', tune accordingly based on input parameters and use the supported keywords. It returns a radio object, depending on the type of SDR that can be used with all AbstractSDRs supported functions @@ -287,4 +187,7 @@ function openSDR(name::Symbol,tul...;key...) end export openSDR; + + + end # module diff --git a/src/Assessors.jl b/src/Assessors.jl new file mode 100644 index 0000000..74a4661 --- /dev/null +++ b/src/Assessors.jl @@ -0,0 +1,64 @@ +# ---------------------------------------------------- +# --- Accessor.jl +# ---------------------------------------------------- +# Function to access to radio parameters + +getError(obj::UHDBinding) = UHDBindings.getError(obj); +getError(obj::RadioSim) = RadioSims.getError(obj); +getError(obj::SDROverNetwork) = SDROverNetworks.getMD(obj)[3]; +getError(obj::RTLSDRBinding) = RTLSDRBindings.getError(obj); + +getTimestamp(obj::UHDBinding) = UHDBindings.getTimestamp(obj); +getTimestamp(obj::RadioSim) = RadioSims.getTimestamp(obj); +getTimestamp(obj::SDROverNetwork) = SDROverNetworks.getMD(obj)[1:2]; +getTimestamp(obj::RTLSDRBinding) = RTLSDRBindings.getTimestamp(obj); + +""" +Get the current sampling rate of the radio device +The second parameter (optionnal) speicfies the Rx or Tx board (default : Rx) +""" +getSamplingRate(obj::AbstractSDR;mode=:rx) = ((mode == :rx) ? obj.rx.samplingRate : obj.tx.samplingRate) +getSamplingRate(obj::PlutoSDR;mode=:rx) = ((mode == :rx) ? obj.rx.effectiveSamplingRate : obj.tx.effectiveSamplingRate) + +""" +Get the current carrier frequency of the radio device +The second parameter (optionnal) speicfies the Rx or Tx board (default : Rx) +""" +getCarrierFreq(obj::AbstractSDR;mode=:rx) = (mode == :rx) ? obj.rx.carrierFreq : obj.tx.carrierFreq +getCarrierFreq(obj::PlutoSDR;mode=:rx) = (mode == :rx) ? obj.rx.effectiveCarrierFreq : obj.tx.effectiveCarrierFreq + + +""" +Get the current radio gain +The second parameter (optionnal) specifies the Rx or Tx board (default : Rx) +""" +getGain(obj::AbstractSDR;mode=:rx) = (mode == :rx) ? obj.rx.gain : obj.tx.gain +getGain(obj::PlutoSDR;mode=:rx) = (mode== :rx) ? obj.rx.iio.chn.hardwaregain : obj.rx.iio.chn.hardwaregain + + +""" +Check if a SDR has already been closed. The falg is true is the SDR ressources have been released and false otherwise. +# --- Syntax +flag = isClosed(radio) +# --- Input parameters +- radio : SDR device +# --- Output parameters +- flag : True is SDR is already closed, false otherwise +""" +isClosed(obj::AbstractSDR) = Bool(obj.tx.released) || Bool(obj.rx.released) +isClosed(obj::PlutoSDR) = Bool(obj.released) + + +""" +Returns the radio packet size. Each radio backend encapsulates the IQ samples into chunks of data. The `recv` command can be used with any size but it can be more efficient to match the desired size with the one provided by the radio +# --- Syntax +bufferSize = getBufferSize(radio) +# --- Input parameters +- radio : SDR device +# --- Output parameters +bufferSize : Size of radio internal buffer +""" +getBufferSize(obj::AbstractSDR) = obj.rx.packetSize # We get the fields +getBufferSize(obj::PlutoSDR) = obj.rx.buf.C_sample_size # For Pluto this is hidden in the buffer config + + diff --git a/src/Backends.jl b/src/Backends.jl new file mode 100644 index 0000000..cb172c2 --- /dev/null +++ b/src/Backends.jl @@ -0,0 +1,60 @@ +# --------------------------------- +# --- UHD Bindings +# ---------------------------------------------------- +# Backend to pilot USRP with UHD lib +@reexport using UHDBindings +# --- Specific UHD related functions +# We export the UHD structure +export UHDBinding + +# ---------------------------------------------------- +# --- Adalm Pluto managment +# ---------------------------------------------------- +# Backend for Adalm Pluto +@reexport using AdalmPluto +# --- Specific Pluto exportation +# We export the Adalm Pluto structure and the specific updateGainMode function +export AdalmPluto; +export updateGainMode!; + + +# ---------------------------------------------------- +# --- RTL-SDR bindings +# ---------------------------------------------------- +include("Backends/RTLSDRBindings.jl"); +@reexport using .RTLSDRBindings +export RTLSDRBinding + +# ---------------------------------------------------- +# --- Socket System +# ---------------------------------------------------- +# --- Create and load module to pilot E310 devices +# To control this device we create a pure Socket based system +# for which the AbstractSDRs package will help to bind the utils +# Have a look on minimalTransceiver.jl for the code to be ran on E310 +include("Backends/SDROverNetworks.jl"); +@reexport using .SDROverNetworks +# --- Specific E310 related functions +export SDROverNetwork; + +# ---------------------------------------------------- +# --- Simulation Radio +# ---------------------------------------------------- +# --- Create and module to emulate a radio device without any actual radio connected +include("Backends/RadioSims.jl"); +@reexport using .RadioSims +# --- Specific simulation related function +export updatePacketSize!; +export updateBuffer!; +export RadioSim; + +# ---------------------------------------------------- +# --- Define common radio type +# ---------------------------------------------------- +# We define an Union type that gathers all SDR backends +# This type will be used as default fallback methods to handle 2 things +# - In case of functions not supported in the given backend to obtain a predictible (and non error) behaviour +# - To simplify access to similar backends fields +AbstractSDR = Union{RadioSim,UHDBinding,PlutoSDR,SDROverNetwork,RTLSDRBinding} + + diff --git a/src/RTLSDRBindings.jl b/src/Backends/RTLSDRBindings.jl similarity index 97% rename from src/RTLSDRBindings.jl rename to src/Backends/RTLSDRBindings.jl index 4cfd56d..34636ed 100644 --- a/src/RTLSDRBindings.jl +++ b/src/Backends/RTLSDRBindings.jl @@ -1,7 +1,7 @@ module RTLSDRBindings # --- Print radio config -include("Printing.jl"); +include("../Printing.jl"); using .Printing using RTLSDR @@ -111,7 +111,7 @@ function updateSamplingRate!(radio,samplingRate) return samplingRate end function updateGain!(radio,gain) - @warn "Analog gain update is not supported for RTLSDR"; + # @warn "Analog gain update is not supported for RTLSDR"; end diff --git a/src/RadioSims.jl b/src/Backends/RadioSims.jl similarity index 97% rename from src/RadioSims.jl rename to src/Backends/RadioSims.jl index dbcef76..c0ed1a9 100644 --- a/src/RadioSims.jl +++ b/src/Backends/RadioSims.jl @@ -3,7 +3,7 @@ using Printf # --- Print radio config -include("Printing.jl"); +include("../Printing.jl"); using .Printing; # Methods extension @@ -169,7 +169,7 @@ end function updateSamplingRate!(radio::RadioSim,samplingRate); # --- We have to calculate the new sleeping value in μs sleepVal = Cint(floor( radio.rx.packetSize / samplingRate * radio.rx.radioSim.scaleSleep * 1e6)); - (sleepVal == 0) && @warn "Sleep val is 0 => rate may be affected"; + # (sleepVal == 0) && @warn "Sleep val is 0 => rate may be affected"; radio.rx.radioSim.sleepVal = sleepVal; radio.tx.radioSim.sleepVal = sleepVal; # --- Update the sampling rate flag of the radio @@ -258,7 +258,7 @@ function recv!(sig::Vector{Complex{Cfloat}},radio::RadioSim) return packetSize; end -function send(sig::Vector{Complex{Cfloat}},radio::RadioSim) +function send(radio::RadioSim,sig::Vector{Complex{Cfloat}},flag::Bool) usleep(radio.tx); end @@ -275,7 +275,8 @@ function updateBuffer!(radio,buffer) end function Base.close(radio::RadioSim) - radio = nothing; + radio.rx.released = true + radio.tx.released = true end function getError(radio::RadioSim) diff --git a/src/SDROverNetworks.jl b/src/Backends/SDROverNetworks.jl similarity index 99% rename from src/SDROverNetworks.jl rename to src/Backends/SDROverNetworks.jl index 1691430..94fa6b8 100644 --- a/src/SDROverNetworks.jl +++ b/src/Backends/SDROverNetworks.jl @@ -15,7 +15,7 @@ using ZMQ using Printf # --- Print radio config -include("Printing.jl"); +include("../Printing.jl"); using .Printing # --- Method extension diff --git a/src/Mutators.jl b/src/Mutators.jl new file mode 100644 index 0000000..89cbec5 --- /dev/null +++ b/src/Mutators.jl @@ -0,0 +1,55 @@ +# ---------------------------------------------------- +# --- Mutators.jl +# ---------------------------------------------------- +# Functions to update radio configuration and parameters + +updateCarrierFreq!(obj::SDROverNetwork,tul...) = SDROverNetworks.updateCarrierFreq!(obj,tul...); +updateCarrierFreq!(obj::UHDBinding,tul...) = UHDBindings.updateCarrierFreq!(obj,tul...); +updateCarrierFreq!(obj::RadioSim,tul...) = RadioSims.updateCarrierFreq!(obj,tul...); +updateCarrierFreq!(obj::RTLSDRBinding,tul...) = RTLSDRBindings.updateCarrierFreq!(obj,tul...); +updateCarrierFreq!(obj::PlutoSDR,tul...) = AdalmPluto.updateCarrierFreq!(obj,_toInt.(tul)...); + +""" +Update sampling rate of current radio device, and update radio object with the new obtained sampling frequency. +# --- Syntax +updateSamplingRate!(radio,samplingRate) +# --- Input parameters +- radio : SDR device +- samplingRate : New desired sampling rate +# --- Output parameters +- +""" +updateSamplingRate!(obj::SDROverNetwork,tul...) = SDROverNetworks.updateSamplingRate!(obj,tul...); +updateSamplingRate!(obj::UHDBinding,tul...) = UHDBindings.updateSamplingRate!(obj,tul...); +updateSamplingRate!(obj::RadioSim,tul...) = RadioSims.updateSamplingRate!(obj,tul...); +updateSamplingRate!(obj::RTLSDRBinding,tul...) = RTLSDRBindings.updateSamplingRate!(obj,tul...); +function updateSamplingRate!(obj::PlutoSDR,tul...) + # For Adalm Pluto we should also update the RF filter band + AdalmPluto.updateSamplingRate!(obj,_toInt.(tul)...); + AdalmPluto.updateBandwidth!(obj,_toInt.(tul)...); + return obj.rx.effectiveSamplingRate +end + +""" +Update gain of current radio device, and update radio object with the new obtained gain. +If the input is a [UHDRx] or a [UHDTx] object, it updates only the Rx or Tx gain +# --- Syntax +updateGain!(radio,gain) +# --- Input parameters +- radio : SDR device +- gain : New desired gain +# --- Output parameters +- +""" +updateGain!(obj::SDROverNetwork,tul...) = SDROverNetworks.updateGain!(obj,tul...); +updateGain!(obj::UHDBinding,tul...) = UHDBindings.updateGain!(obj,tul...); +updateGain!(obj::RadioSim,tul...) = RadioSims.updateGain!(obj,tul...); +updateGain!(obj::RTLSDRBinding,tul...) = RTLSDRBindings.updateGain!(obj,tul...); +updateGain!(obj::PlutoSDR,tul...) = AdalmPluto.updateGain!(obj,_toInt.(tul)...); + +""" +Define Gain policy for the SDR radio. Only supported on AdalmPluto +""" +updateGainMode!(sdr::AbstractSDR) = "manual" +# No need to redefine for Pluto backend + diff --git a/src/Printing.jl b/src/Printing.jl index 8df2ed9..54981a4 100644 --- a/src/Printing.jl +++ b/src/Printing.jl @@ -1,6 +1,7 @@ module Printing using Printf +# This module is intended to provide fancy macros to display warning export @inforx, @warnrx; export @infotx, @warntx; diff --git a/src/Scan.jl b/src/Scan.jl new file mode 100644 index 0000000..16791c1 --- /dev/null +++ b/src/Scan.jl @@ -0,0 +1,72 @@ +# ---------------------------------------------------- +# --- Find.jl +# ---------------------------------------------------- +# Methods to scan for SDR devices, based on backend specifications or parameters + + + +""" +Scan interface and returns the founded SDR +# --- Syntax +sdr = scan() +sdr = scan(backend;key...) +# Input parameter +If the function is called without parameters il will search for all avaliable backends such as UHDBindings and AdalmPluto. Otherwise the search will be limited to the desired backend +The optionnal arguments are the one supported by UHDBindings and AdalmPluto. See `uhd_find_devices()` in UHDBindings and `scan` function in AdalmPluto +# Keywords +- args : String used in UHD backend to specify USRP IP address. Example: scan(:uhd;args="addr=192.168.10.16") +- backend : Sring used in Pluto backend to specify the interface used ("local", "xml", "ip", "usb") +""" +function scan(backend::Union{Nothing,Vector{Symbol}}=nothing;key...) + # --- If call w/o argument we search for all potential backends + # Note that we can not search for SDROverNetwork, RadioSims and RTLSDR + # TODO => Scan methods for RTLSDR ? + if isnothing(backend) + backend = [:uhd;:pluto] + end + allStr = String[]; + for b in backend + if b == :uhd + println("----------------------------") + println("--- Scan for UHD devices ---") + println("----------------------------") + # ---------------------------------------------------- + # --- UHD Find device call + # ---------------------------------------------------- + # --- Restrict keywords to uhd_find_devices + key = parseKeyword(key,[:args]) + # scan keyword is uhd_find_devices parameter so we should handle empty case + (isempty(key)) && (key[:args] = "") + # --- Call scanner + e = UHDBindings.uhd_find_devices(key[:args]) + # --- Push in Vector of string + push!(allStr,e...) + elseif b == :pluto + println("------------------------------") + println("--- Scan for Pluto devices ---") + println("------------------------------") + # ---------------------------------------------------- + # --- Scan call + # ---------------------------------------------------- + # --- Restrict keywords to uhd_find_devices + key = parseKeyword(key,[:backend]) + (isempty(key)) && (key[:backend] = "usb") + # --- Call scanner + e = AdalmPluto.scan(key[:backend]) + # --- Push in Vector of string + push!(allStr,e) + elseif b == :radiosim + # ---------------------------------------------------- + # --- Radiosims backend + # ---------------------------------------------------- + # No need to worry, we always have the simulated backend + # Returns an arbitrary String with description + println("------------------------------") + println("--- Scan for RadioSims ---") + println("------------------------------") + push!(allStr,"RadioSim backend is always there !") + end + end + return allStr +end +scan(backend::Symbol;key...) = scan([backend];key...) diff --git a/src/Utils.jl b/src/Utils.jl new file mode 100644 index 0000000..288f1be --- /dev/null +++ b/src/Utils.jl @@ -0,0 +1,22 @@ +# ---------------------------------------------------- +# --- Utils.jl +# ---------------------------------------------------- +# We put here common usefull stuff for SDR managment + + + +# --- Container for Radio use +# We will have functions from different origin and different supported keywords +# This function parse the input keywords and returns the ones supported by the function, listed in iteration +function parseKeyword(kwargs,iteration) + # We populate a new dictionnary based on the input keywords and the supported ones + # In order not to create keywords that are not supported (i.e leaving the default value) + # we only evaluate the keywords defined both in the 2 dictionnaries + # This means that the default fallback should never happen + kwargs = Dict(key=>get(kwargs,key,0) for key in intersect(iteration,keys(kwargs))) + return kwargs +end + +# --- Conversion +# Adalm Pluto structure is based on Int parameters, and AbstractSDRs use massively Float. We need to convert just before dispatching. As some parameter may be float (as gain) we should round before conversion. The following function does that. +_toInt(x) = Int(round(x)); From 924550408053580e4182677c2a8981ed02263451 Mon Sep 17 00:00:00 2001 From: Robin Gerzaguet Date: Tue, 25 May 2021 13:44:59 +0200 Subject: [PATCH 04/11] Adding tests --- test/runtests.jl | 68 +++++++++++ test/test_RadioSim.jl | 181 ++++++++++++++++++++++++++++ test/test_functions.jl | 266 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 515 insertions(+) create mode 100644 test/runtests.jl create mode 100644 test/test_RadioSim.jl create mode 100644 test/test_functions.jl diff --git a/test/runtests.jl b/test/runtests.jl new file mode 100644 index 0000000..0845d12 --- /dev/null +++ b/test/runtests.jl @@ -0,0 +1,68 @@ +# Testing SDR backends +using Test +using AbstractSDRs + +# ---------------------------------------------------- +# --- Testing radioSim back end +# ---------------------------------------------------- +# This backend requires no SDR connected so we can use it by default +# Most of the test are also sone in the comon API call but set a specific test call here +# to test everything is OK on the API side and that specific RadioSim properties are OK (especially control that emulated received data is the one desired) +include("test_RadioSim.jl") + + +# ---------------------------------------------------- +# --- Test functions +# ---------------------------------------------------- +# Define here key behaviour common for all radio +# You can have a look here to find pratical examples of radio use +include("test_functions.jl") + + +# ---------------------------------------------------- +# --- Common API call for all backend +# ---------------------------------------------------- +# Issue is that we need a connected device to perform all test so we will do as follows +# => Try to scan for device. If detected then proceed to the test, otherwise drop the test +# For UHD, we need to hardcode a potential IP address in case of non broadcast ehternet address. If we detect the UHD device with scan(:uhd) the we use the associated IP address. Otherwise we use UHD_ADDRESS. It means that in case of non broadcast ethernet link, you should modify the following line according to your UHD IP address +global UHD_ADDRESS = "192.168.10.16" + +# --- Define test backend +backends = [:radiosim;:uhd;:pluto] +for sdr ∈ backends + # --- Flaging test + println("######################################") + println("# --- Testing $sdr backend ---") + println("######################################") + # --- Test scan + str = scan(sdr;args="addr=$UHD_ADDRESS") + if isempty(str) + # ---------------------------------------------------- + # --- We have find nothing, drop the rest of the tests + # ---------------------------------------------------- + @warn "Unable to detect any SDR devices based on backend $sdr\n Abandon rest of tests" + else + # ---------------------------------------------------- + # --- Testing stuff + # ---------------------------------------------------- + @testset "Opening" begin + check_open(sdr) + end + + @testset "Radio configuration" begin + check_carrierFreq(sdr) + check_samplingRate(sdr) + check_gain(sdr) + end + + @testset "Checking data retrieval" begin + check_recv(sdr) + check_recv_preAlloc(sdr) + check_recv_iterative(sdr) + end + + @testset "Checking data transmission" begin + check_send(sdr) + end + end +end diff --git a/test/test_RadioSim.jl b/test/test_RadioSim.jl new file mode 100644 index 0000000..57b79c8 --- /dev/null +++ b/test/test_RadioSim.jl @@ -0,0 +1,181 @@ +# ---------------------------------------------------- +# --- Radio Sim test file +# ---------------------------------------------------- +# This file is dedicated to RadioSim backend + +# ---------------------------------------------------- +# --- Define test routines +# ---------------------------------------------------- + +""" +Test that the device can be open, configured and closed +""" +function check_open() + # --- Main parameters + carrierFreq = 440e6; # --- The carrier frequency + samplingRate = 8e6; # --- Targeted bandwdith + gain = 0; # --- Rx gain + sdr = :radiosim + # --- Create the E310 device + global sdr =openSDR(sdr,carrierFreq,samplingRate,gain); + # Type is OK + @test typeof(sdr) == RadioSim + # SDR is not released yet + @test sdr.rx.released == false + # Configuration : Carrier Freq + @test sdr.rx.carrierFreq == carrierFreq + @test sdr.tx.carrierFreq == carrierFreq + # Configuration : Badnwidth + @test sdr.rx.samplingRate == samplingRate + @test sdr.tx.samplingRate == samplingRate + # --- We close the SDR + close(sdr) + @test isClosed(sdr) == true +end + +""" +Check the carrier frequency update of the RadioSim device +""" +function check_carrierFreq() + # --- Main parameters + carrierFreq = 440e6; # --- The carrier frequency + samplingRate = 8e6; # --- Targeted bandwdith + gain = 0; # --- Rx gain + sdr = :radiosim + # --- Create the E310 device + global sdr =openSDR(sdr,carrierFreq,samplingRate,gain); + # Classic value, should work + updateCarrierFreq!(sdr,800e6) + @test sdr.rx.carrierFreq == 800e6 + @test sdr.tx.carrierFreq == 800e6 + # Targeting WiFi, should work + updateCarrierFreq!(sdr,2400e6) + @test sdr.rx.carrierFreq == 2400e6 + @test sdr.tx.carrierFreq == 2400e6 + close(sdr); + @test isClosed(sdr) == true +end + +""" +Check the sampling frequency update of the RadioSim device +""" +function check_samplingRate() + # --- Main parameters + carrierFreq = 440e6; # --- The carrier frequency + samplingRate = 8e6; # --- Targeted bandwdith + gain = 0; # --- Rx gain + sdr = :radiosim + # --- Create the E310 device + global sdr =openSDR(sdr,carrierFreq,samplingRate,gain); + # Classic value, should work + updateSamplingRate!(sdr,8e6) + @test sdr.rx.samplingRate == 8e6 + @test sdr.tx.samplingRate == 8e6 + # Targeting WiFi, should work + updateSamplingRate!(sdr,15.36e6) + @test sdr.rx.samplingRate == 15.36e6 + @test sdr.tx.samplingRate == 15.36e6 + close(sdr); + @test isClosed(sdr) == true +end + +""" +Check the gain update for RadioSim +""" +function check_gain() + # --- Main parameters + carrierFreq = 440e6; # --- The carrier frequency + samplingRate = 8e6; # --- Targeted bandwdith + gain = 0; # --- Rx gain + sdr = :radiosim + # --- Create the E310 device + global sdr =openSDR(sdr,carrierFreq,samplingRate,gain); + # Classic value, should work + updateGain!(sdr,20) + # @test sdr.rx.samplingRate == 8e6 + # @test sdr.tx.samplingRate == 8e6 + close(sdr); + @test isClosed(sdr) == true +end + + +""" +Test that the device can received data +""" +function check_recv() + # --- Main parameters + carrierFreq = 440e6; # --- The carrier frequency + samplingRate = 8e6; # --- Targeted bandwdith + gain = 0; # --- Rx gain + sdr = :radiosim + # --- Create the E310 device + global sdr =openSDR(sdr,carrierFreq,samplingRate,gain); + sig = recv(sdr,1024) + @test length(sig) == 1024 + @test eltype(sig) == Complex{Float32} + close(sdr) + @test isClosed(sdr) == true +end + + +""" +Test that radiosim device can feed desired data +""" +function check_recv_prealloc() + # --- Main parameters + carrierFreq = 440e6; # --- The carrier frequency + samplingRate = 100e6; # --- Targeted bandwdith + gain = 0.0; # --- Rx gain + sdr = :radiosim; + nbSamples = 1024; + # ---------------------------------------------------- + # --- Buffer emulation + # ---------------------------------------------------- + buffer = collect(1:4096); + # --- Create the E310 device + global sdr =openSDR(sdr,carrierFreq,samplingRate,gain;packetSize=512,buffer=buffer); + sig = recv(sdr,1024) + @test length(sig) == 1024 + @test eltype(sig) == Complex{Float32} + # The first call should give the 1024 fist samples + @test all(sig .== collect(1:1024)) + # --- Second call give second part + sig = recv(sdr,1024) + @test length(sig) == 1024 + @test eltype(sig) == Complex{Float32} + @test all(sig .== collect(1025:2048)) + # --- Third call to have the end + sig = recv(sdr,2048) + @test length(sig) == 2048 + @test eltype(sig) == Complex{Float32} + @test all(sig .== collect(2049:4096)) + # --- Another complete call with complete buffer + sig = recv(sdr,4096) + @test length(sig) == 4096 + @test eltype(sig) == Complex{Float32} + @test all(sig .== buffer) + # --- Close radio + close(sdr) + @test isClosed(sdr) == true +end + + +# ---------------------------------------------------- +# --- Test calls +# ---------------------------------------------------- +@testset "RadioSims Backend " begin + @testset "Scanning and opening" begin + check_open() + end + + @testset "Radio configuration" begin + check_carrierFreq() + check_samplingRate() + check_gain() + end + + @testset "Checking data retrieval" begin + check_recv() + check_recv_prealloc() + end +end diff --git a/test/test_functions.jl b/test/test_functions.jl new file mode 100644 index 0000000..fed35e5 --- /dev/null +++ b/test/test_functions.jl @@ -0,0 +1,266 @@ +# --- USRP address +global USRP_ADDRESS = "192.168.10.16" +# This address may vary from time to time, not really sure how to handle dynamic testing +# +# +# ---------------------------------------------------- +# --- Define test routines +# ---------------------------------------------------- +""" +Scan with uhd_find_devices and return the USRP identifier +""" +function check_scan(b::Symbol;USRP_ADDRESS) + # --- First we use no parameter (broadcast ethernet link) + str = scan(b) + if length(str) == 0 + println("No UHD device found. Be sure that a USRP is connected to your PC, and that the ethernet link is up. We try to use the direct IP address now (which is $USRP_ADDRESS). You can change its value depending on your ethernet setup") + else + # We find a device so we update the USRP address based on what we have found + global USRP_ADDRESS = str[1][findfirst("_addr=",str[1])[end] .+ (1:13)] + end + # The direct call with the IP address should give something + str = scan(b;args="addr=$USRP_ADDRESS") + @test length(str) > 0 + return str +end + +""" +Test that the device can be open, configured and closed +""" +function check_open(sdrName) + # --- Main parameters + carrierFreq = 440e6; # --- The carrier frequency + samplingRate = 8e6; # --- Targeted bandwdith + gain = 0; # --- Rx gain + # --- Create the device + global sdr = openSDR(sdrName,carrierFreq, samplingRate, gain;args="addr=$USRP_ADDRESS"); + # Type is OK + if sdrName == :uhd + @test typeof(sdr) == UHDBinding + elseif sdrName == :pluto + @test typeof(sdr) == PlutoSDR + elseif sdrName == :radiosim + @test typeof(sdr) == RadioSim + else + @error "Untested radio backend" + end + # SDR is not released yet + @test isClosed(sdr) == false + # Configuration : Carrier Freq + @test getCarrierFreq(sdr) == carrierFreq + @test getCarrierFreq(sdr,mode=:rx) == carrierFreq + @test getCarrierFreq(sdr,mode=:tx) == carrierFreq + # Configuration : Badnwidth + @test getSamplingRate(sdr) == samplingRate + @test getSamplingRate(sdr,mode=:rx) == samplingRate + @test getSamplingRate(sdr,mode=:tx) == samplingRate + # --- We close the SDR + close(sdr) + @test isClosed(sdr) == true +end + +""" +Check the carrier frequency update of the USRP device +""" +function check_carrierFreq(sdrName) + # --- Main parameters + carrierFreq = 440e6; # --- The carrier frequency + samplingRate = 8e6; # --- Targeted bandwdith + gain = 0; # --- Rx gain + # --- Create the device + global sdr = openSDR(sdrName,carrierFreq, samplingRate, gain;args="addr=$USRP_ADDRESS"); + # Classic value, should work + updateCarrierFreq!(sdr,800e6) + @test getCarrierFreq(sdr) == 800e6 + @test getCarrierFreq(sdr,mode=:rx) == 800e6 + @test getCarrierFreq(sdr,mode=:tx) == 800e6 + # Targeting WiFi, should work + updateCarrierFreq!(sdr,2400e6) + @test getCarrierFreq(sdr) == 2400e6 + @test getCarrierFreq(sdr,mode=:rx) == 2400e6 + @test getCarrierFreq(sdr,mode=:tx) == 2400e6 + # If we specify a out of range frequency, it should bound to max val + # TODO Check that is should be max freq range, but don't know the range as different USRP may be used + # Adding tables with various ranges to check taht this is the expected value ? + # eF= updateCarrierFreq!(sdr,9e9) + # @test getCarrierFreq(sdr) != 9e9 + # @test getCarrierFreq(sdr,mode=:rx) != 9e9 + # @test getCarrierFreq(sdr,mode=:tx) != 9e9 + # @test getCarrierFreq(sdr) == eF + # @test getCarrierFreq(sdr,mode=:rx) == eF + # @test getCarrierFreq(sdr,mode=:tx) == eF + close(sdr); + @test isClosed(sdr) == true +end + +""" +Check the sampling frequency update of the USRP device +""" +function check_samplingRate(sdrName) + # --- Main parameters + carrierFreq = 440e6; # --- The carrier frequency + samplingRate = 8e6; # --- Targeted bandwdith + gain = 0; # --- Rx gain + # --- Create the device + global sdr = openSDR(sdrName,carrierFreq, samplingRate, gain;args="addr=$USRP_ADDRESS"); + # Classic value, should work + updateSamplingRate!(sdr,8e6) + @test getSamplingRate(sdr) == 8e6 + @test getSamplingRate(sdr,mode=:rx) == 8e6 + @test getSamplingRate(sdr,mode=:tx) == 8e6 + # Targeting WiFi, should work + updateSamplingRate!(sdr,15.36e6) + @test getSamplingRate(sdr) == 15.36e6 + @test getSamplingRate(sdr,mode=:rx) == 15.36e6 + @test getSamplingRate(sdr,mode=:tx) == 15.36e6 + # If we specify a out of range frequency, it should bound to max val + eS = updateSamplingRate!(sdr,100e9) + # @test getSamplingRate(sdr) != 100e9 + # @test getSamplingRate(sdr,mode=:rx) != 100e9 + # @test getSamplingRate(sdr,mode=:tx) != 100e9 + # @test getSamplingRate(sdr) == eS + # @test getSamplingRate(sdr,mode=:rx) == eS + # @test getSamplingRate(sdr,mode=:tx) == eS + close(sdr); + @test isClosed(sdr) == true +end + +""" +Check the gain update for the USRP device +""" +function check_gain(sdrName) + # --- Main parameters + carrierFreq = 440e6; # --- The carrier frequency + samplingRate = 8e6; # --- Targeted bandwdith + gain = 0; # --- Rx gain + # --- Create the device + global sdr = openSDR(sdrName,carrierFreq, samplingRate, gain;args="addr=$USRP_ADDRESS"); + # Classic value, should work + nG = updateGain!(sdr,20) + @test getGain(sdr) == 20 + @test getGain(sdr;mode=:rx) == 20 + @test getGain(sdr;mode=:tx) == 20 + @test getGain(sdr) == nG + @test getGain(sdr;mode=:rx) == nG + @test getGain(sdr;mode=:tx) == nG + close(sdr); + @test isClosed(sdr) == true +end + + +""" +Test that the device can received data +""" +function check_recv(sdrName) + # --- Main parameters + carrierFreq = 440e6; # --- The carrier frequency + samplingRate = 8e6; # --- Targeted bandwdith + gain = 0; # --- Rx gain + # --- Create the device + global sdr = openSDR(sdrName,carrierFreq, samplingRate, gain;args="addr=$USRP_ADDRESS"); + sig = recv(sdr,1024) + @test length(sig) == 1024 + @test eltype(sig) == Complex{Float32} + close(sdr) + @test isClosed(sdr) == true +end + +""" +Test that the device can received data with pre-allocation +""" +function check_recv_preAlloc(sdrName) + # --- Main parameters + carrierFreq = 440e6; # --- The carrier frequency + samplingRate = 8e6; # --- Targeted bandwdith + gain = 0; # --- Rx gain + global sdr = openSDR(sdrName,carrierFreq, samplingRate, gain;args="addr=$USRP_ADDRESS",packetSize=4096); + sig = zeros(ComplexF32,2*1024) + recv!(sig,sdr) + @test length(sig) == 1024*2 + @test eltype(sig) == Complex{Float32} + @test length(unique(sig)) > 1 # To be sure we have populated array with data + close(sdr) + @test isClosed(sdr) == true +end + +""" +Test that the device can received data several time +""" +function check_recv_iterative(sdrName) + # --- Main parameters + carrierFreq = 440e6; # --- The carrier frequency + samplingRate = 8e6; # --- Targeted bandwdith + gain = 0; # --- Rx gain + # --- Create the device + global sdr = openSDR(sdrName,carrierFreq, samplingRate, gain;args="addr=$USRP_ADDRESS",packetSize=4096); + sig = zeros(ComplexF32,2*1024) + nbPackets = 0 + maxPackets = 10_000 + for _ ∈ 1 : 1 : maxPackets + # --- Get a burst + recv!(sig,sdr) + # --- Increment packet index + nbPackets += 1 + end + @test nbPackets == maxPackets + close(sdr) + @test isClosed(sdr) == true +end + +""" +Test that the device sucessfully transmit data +""" +function check_send(sdrName) + carrierFreq = 770e6; + samplingRate = 4e6; + gain = 50.0; + nbSamples = 4096*2 + # --- Create the device + global sdr = openSDR(sdrName,carrierFreq, samplingRate, gain;args="addr=$USRP_ADDRESS",packetSize=4096); + # --- Create a sine wave + f_c = 3940; + buffer = 0.5.*[exp.(2im * π * f_c / samplingRate * n) for n ∈ (0:nbSamples-1)]; + buffer = convert.(Complex{Cfloat},buffer); + + buffer2 = 0.5.*[exp.(2im * π * 10 * f_c / samplingRate * n) for n ∈ (0:nbSamples-1)]; + buffer2 = convert.(Complex{Cfloat},buffer2); + buffer = [buffer;buffer2]; + + cntAll = 0; + maxPackets = 10_000 + nbPackets = 0 + for _ ∈ 1 : maxPackets + send(sdr,buffer,false); + # --- Increment packet index + nbPackets += 1 + end + @test nbPackets == maxPackets + close(sdr) + @test isClosed(sdr) == true +end + +# # ---------------------------------------------------- +# # --- Test calls +# # ---------------------------------------------------- +# @testset "UHDBindings backend" begin +# @testset "Scanning and opening" begin + # check_scan() + # check_open() +# end + +# @testset "Radio configuration" begin + # check_carrierFreq() + # check_samplingRate() + # check_gain() +# end + +# @testset "Checking data retrieval" begin + # check_recv() + # check_recv_preAlloc() + # check_recv_iterative() +# end + +# @testset "Checking data transmission" begin + # check_send() +# end +# end From 598ae86256f60aeb33339361aab9cabcdfe907d7 Mon Sep 17 00:00:00 2001 From: Robin Gerzaguet Date: Tue, 25 May 2021 13:45:28 +0200 Subject: [PATCH 05/11] Update UHDBindings and AdalmPluto versions --- Manifest.toml | 16 ++++++++-------- Project.toml | 3 ++- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/Manifest.toml b/Manifest.toml index 471c768..1876ff9 100644 --- a/Manifest.toml +++ b/Manifest.toml @@ -1,10 +1,10 @@ # This file is machine-generated - editing it directly is not advised [[AdalmPluto]] -deps = ["Pkg", "Reexport", "Test"] -git-tree-sha1 = "dfe2f2f230d4d53fe0692ea4f8b7bfe0325bf2e5" +deps = ["Pkg", "Printf", "Reexport", "Test"] +git-tree-sha1 = "73225c702b231beaeab8a0f10df19a1bc9b77daf" uuid = "af34ca7c-e544-47d5-a6fe-72495f08728e" -version = "0.1.1" +version = "0.1.5" [[ArgTools]] uuid = "0dad84c5-d112-42e6-8d28-ef12dabb789f" @@ -78,9 +78,9 @@ uuid = "44cfe95a-1eb2-52ea-b672-e2afdf69b78f" [[Preferences]] deps = ["TOML"] -git-tree-sha1 = "ea79e4c9077208cd3bc5d29631a26bc0cff78902" +git-tree-sha1 = "00cfd92944ca9c760982747e9a1d0d5d86ab1e5a" uuid = "21216c6a-2e73-6563-6e65-726566657250" -version = "1.2.1" +version = "1.2.2" [[Printf]] deps = ["Unicode"] @@ -126,10 +126,10 @@ deps = ["InteractiveUtils", "Logging", "Random", "Serialization"] uuid = "8dfed614-e22c-5e08-85e1-65c5234f0b40" [[UHDBindings]] -deps = ["Libdl", "Printf"] -git-tree-sha1 = "d072efd625bf9029e55559d480ef3e4c0e83ae43" +deps = ["Libdl", "Pkg", "Printf", "Test"] +git-tree-sha1 = "3f27d40fb8337445194c03e11640131abe91ad0c" uuid = "4d90b16f-829e-4b78-80d9-fb9bcf8c06e0" -version = "0.1.3" +version = "0.2.0" [[UUIDs]] deps = ["Random", "SHA"] diff --git a/Project.toml b/Project.toml index 8080eb1..539abd1 100644 --- a/Project.toml +++ b/Project.toml @@ -10,6 +10,7 @@ Printf = "de0858da-6303-5e67-8744-51eddeeeb8d7" RTLSDR = "71cfaeeb-f3e6-59e7-80b9-1b8c23d8f010" Reexport = "189a3867-3050-52da-a836-e630ba90ab69" Sockets = "6462fe0b-24de-5631-8697-dd941f90decc" +Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" UHDBindings = "4d90b16f-829e-4b78-80d9-fb9bcf8c06e0" ZMQ = "c2297ded-f4af-51ae-bb23-16f91089e4e1" @@ -17,6 +18,6 @@ ZMQ = "c2297ded-f4af-51ae-bb23-16f91089e4e1" AdalmPluto = "0.1" RTLSDR = "0.0.1" Reexport = "0.2, 1.0" -UHDBindings = "0.1" +UHDBindings = "0.2" ZMQ = "1.2" julia = "1.5,1.6" From 1937f93b762502dabd25fe3f4856dbd374305c97 Mon Sep 17 00:00:00 2001 From: Robin Gerzaguet Date: Tue, 25 May 2021 14:34:24 +0200 Subject: [PATCH 06/11] New version --- Project.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Project.toml b/Project.toml index 539abd1..10f523c 100644 --- a/Project.toml +++ b/Project.toml @@ -1,7 +1,7 @@ name = "AbstractSDRs" uuid = "0bdde9fc-719a-4dc7-8589-49ca6634fa6b" authors = ["Robin Gerzaguet "] -version = "0.1.2" +version = "0.2.0" [deps] AdalmPluto = "af34ca7c-e544-47d5-a6fe-72495f08728e" From 7d960ace2f0cb403bd581a48d32dce753d8d4376 Mon Sep 17 00:00:00 2001 From: Robin Gerzaguet Date: Wed, 26 May 2021 12:00:26 +0200 Subject: [PATCH 07/11] Use tup/kwarg in send mode --- src/AbstractSDRs.jl | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/AbstractSDRs.jl b/src/AbstractSDRs.jl index 9481334..8e45576 100644 --- a/src/AbstractSDRs.jl +++ b/src/AbstractSDRs.jl @@ -123,9 +123,10 @@ send(radio,buffer,cyclic=false) """ send(obj::SDROverNetwork,sig,tul...;kwarg...) = SDROverNetworks.send(obj,sig,tul...;kwarg...); -send(obj::UHDBinding,sig,tul...) = UHDBindings.send(obj,sig,tul...); -send(obj::RadioSim,sig,tul...) = RadioSims.send(obj,sig,tul...); -send(obj::RTLSDRBinding,sig,tul...) = RTLSDRBindings.send(obj,sig,tul...); +send(obj::UHDBinding,sig,tul...) = UHDBindings.send(obj,sig,tul...) +send(obj::RadioSim,sig,tul...) = RadioSims.send(obj,sig,tul...) +send(obj::RTLSDRBinding,sig,tul...) = RTLSDRBindings.send(obj,sig,tul...) +send(obj::PlutoSDR,sig,tul...;kwarg...) = AdalmPluto.send(obj,sig,tul...;parseKeyword(kwarg,[:use_internal_buffer])) export send From 3bd7271ddcc140055b149f7441e5705156d83c49 Mon Sep 17 00:00:00 2001 From: Robin Gerzaguet Date: Wed, 26 May 2021 12:01:00 +0200 Subject: [PATCH 08/11] use getGain from AdalmPluto to get gain of Pluto device --- src/Assessors.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Assessors.jl b/src/Assessors.jl index 74a4661..9e71feb 100644 --- a/src/Assessors.jl +++ b/src/Assessors.jl @@ -33,7 +33,7 @@ Get the current radio gain The second parameter (optionnal) specifies the Rx or Tx board (default : Rx) """ getGain(obj::AbstractSDR;mode=:rx) = (mode == :rx) ? obj.rx.gain : obj.tx.gain -getGain(obj::PlutoSDR;mode=:rx) = (mode== :rx) ? obj.rx.iio.chn.hardwaregain : obj.rx.iio.chn.hardwaregain +getGain(obj::PlutoSDR;mode=:rx) = AdalmPluto.getGain(obj) """ From 9e545ae46a38614bf571e6a96fe5fb2ddbe51f56 Mon Sep 17 00:00:00 2001 From: Robin Gerzaguet Date: Wed, 26 May 2021 12:01:29 +0200 Subject: [PATCH 09/11] use accessors to get updated parameters from Pluto device --- src/Mutators.jl | 30 ++++++++++++++++++++++++------ 1 file changed, 24 insertions(+), 6 deletions(-) diff --git a/src/Mutators.jl b/src/Mutators.jl index 89cbec5..cfdc8d5 100644 --- a/src/Mutators.jl +++ b/src/Mutators.jl @@ -2,12 +2,25 @@ # --- Mutators.jl # ---------------------------------------------------- # Functions to update radio configuration and parameters - +""" +Update carrier frequency of current radio device, and update radio object with the new obtained sampling frequency. +# --- Syntax +updateCarrierFreq!(radio,carrierFreq) +# --- Input parameters +- radio : SDR device +- carrierFreq : New desired carrier frequency +# --- Output parameters +- carrierFreq : Effective carrier frequency +""" updateCarrierFreq!(obj::SDROverNetwork,tul...) = SDROverNetworks.updateCarrierFreq!(obj,tul...); updateCarrierFreq!(obj::UHDBinding,tul...) = UHDBindings.updateCarrierFreq!(obj,tul...); updateCarrierFreq!(obj::RadioSim,tul...) = RadioSims.updateCarrierFreq!(obj,tul...); updateCarrierFreq!(obj::RTLSDRBinding,tul...) = RTLSDRBindings.updateCarrierFreq!(obj,tul...); -updateCarrierFreq!(obj::PlutoSDR,tul...) = AdalmPluto.updateCarrierFreq!(obj,_toInt.(tul)...); +function updateCarrierFreq!(obj::PlutoSDR,tul...) + # In pluto we only get a flag so we need to call to the accessor + AdalmPluto.updateCarrierFreq!(obj,_toInt.(tul)...); + return getCarrierFreq(obj) +end """ Update sampling rate of current radio device, and update radio object with the new obtained sampling frequency. @@ -17,7 +30,7 @@ updateSamplingRate!(radio,samplingRate) - radio : SDR device - samplingRate : New desired sampling rate # --- Output parameters -- +- samplingRate : Effective sampling rate """ updateSamplingRate!(obj::SDROverNetwork,tul...) = SDROverNetworks.updateSamplingRate!(obj,tul...); updateSamplingRate!(obj::UHDBinding,tul...) = UHDBindings.updateSamplingRate!(obj,tul...); @@ -27,7 +40,7 @@ function updateSamplingRate!(obj::PlutoSDR,tul...) # For Adalm Pluto we should also update the RF filter band AdalmPluto.updateSamplingRate!(obj,_toInt.(tul)...); AdalmPluto.updateBandwidth!(obj,_toInt.(tul)...); - return obj.rx.effectiveSamplingRate + return getSamplingRate(obj) end """ @@ -39,13 +52,18 @@ updateGain!(radio,gain) - radio : SDR device - gain : New desired gain # --- Output parameters -- +- gain : New gain value """ updateGain!(obj::SDROverNetwork,tul...) = SDROverNetworks.updateGain!(obj,tul...); updateGain!(obj::UHDBinding,tul...) = UHDBindings.updateGain!(obj,tul...); updateGain!(obj::RadioSim,tul...) = RadioSims.updateGain!(obj,tul...); updateGain!(obj::RTLSDRBinding,tul...) = RTLSDRBindings.updateGain!(obj,tul...); -updateGain!(obj::PlutoSDR,tul...) = AdalmPluto.updateGain!(obj,_toInt.(tul)...); +function updateGain!(obj::PlutoSDR,tul...) + # In pluto we only get a flag so we have to access to gain value to return the updated gain value + AdalmPluto.updateGain!(obj,_toInt.(tul)...); + return getGain(obj) +end + """ Define Gain policy for the SDR radio. Only supported on AdalmPluto From 71c9e614d85c9eda37269d3e98f08eb553a19923 Mon Sep 17 00:00:00 2001 From: Robin Gerzaguet Date: Wed, 26 May 2021 12:01:47 +0200 Subject: [PATCH 10/11] Correct issue when no device pluto are connected --- src/Scan.jl | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Scan.jl b/src/Scan.jl index 16791c1..36a0d36 100644 --- a/src/Scan.jl +++ b/src/Scan.jl @@ -54,7 +54,8 @@ function scan(backend::Union{Nothing,Vector{Symbol}}=nothing;key...) # --- Call scanner e = AdalmPluto.scan(key[:backend]) # --- Push in Vector of string - push!(allStr,e) + # AdalmPluto answer "" and this corresponds to nothing interessting. We push in the vector only if what we had was not empty + (!isempty(e)) && (push!(allStr,e)) elseif b == :radiosim # ---------------------------------------------------- # --- Radiosims backend From c4368a5159bc485d2a2600f08b9763f1b422eea6 Mon Sep 17 00:00:00 2001 From: Robin Gerzaguet Date: Wed, 26 May 2021 13:42:55 +0200 Subject: [PATCH 11/11] Final version with new send mode --- Manifest.toml | 4 ++-- Project.toml | 3 +-- src/AbstractSDRs.jl | 2 +- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/Manifest.toml b/Manifest.toml index 1876ff9..b831b6f 100644 --- a/Manifest.toml +++ b/Manifest.toml @@ -2,9 +2,9 @@ [[AdalmPluto]] deps = ["Pkg", "Printf", "Reexport", "Test"] -git-tree-sha1 = "73225c702b231beaeab8a0f10df19a1bc9b77daf" +git-tree-sha1 = "d3996574c75ac9ea44f94454d6c1893d6a861761" uuid = "af34ca7c-e544-47d5-a6fe-72495f08728e" -version = "0.1.5" +version = "0.2.2" [[ArgTools]] uuid = "0dad84c5-d112-42e6-8d28-ef12dabb789f" diff --git a/Project.toml b/Project.toml index 10f523c..1c99943 100644 --- a/Project.toml +++ b/Project.toml @@ -15,9 +15,8 @@ UHDBindings = "4d90b16f-829e-4b78-80d9-fb9bcf8c06e0" ZMQ = "c2297ded-f4af-51ae-bb23-16f91089e4e1" [compat] -AdalmPluto = "0.1" +AdalmPluto = "0.2" RTLSDR = "0.0.1" -Reexport = "0.2, 1.0" UHDBindings = "0.2" ZMQ = "1.2" julia = "1.5,1.6" diff --git a/src/AbstractSDRs.jl b/src/AbstractSDRs.jl index 8e45576..70008f3 100644 --- a/src/AbstractSDRs.jl +++ b/src/AbstractSDRs.jl @@ -126,7 +126,7 @@ send(obj::SDROverNetwork,sig,tul...;kwarg...) = SDROverNetworks.send(obj,sig,tul send(obj::UHDBinding,sig,tul...) = UHDBindings.send(obj,sig,tul...) send(obj::RadioSim,sig,tul...) = RadioSims.send(obj,sig,tul...) send(obj::RTLSDRBinding,sig,tul...) = RTLSDRBindings.send(obj,sig,tul...) -send(obj::PlutoSDR,sig,tul...;kwarg...) = AdalmPluto.send(obj,sig,tul...;parseKeyword(kwarg,[:use_internal_buffer])) +send(obj::PlutoSDR,sig,tul...;kwarg...) = AdalmPluto.send(obj,sig,tul...;parseKeyword(kwarg,[:use_internal_buffer])...) export send