Showing results for 
Search instead for 
Did you mean: 

Using Call Library Node to interface with a DLL for an SDRplay software defined radio.

I am attempting to write a LabVIEW Library to interface with a software defined radio made by SDRplay (specifically a RSPdx model).  I am attempting to follow a similar approach to that of Albert Lederer who wrote a library consisting of LabVIEW wrapper VIs that used the Call Library Node to call the functions available in the dll for the simpler RTL-SDR device first for windows (see Using RTL-SDR with Labview, Chapter 1: Labview on Windows) and with a goal of eventually moving it to a RT device such as a myRIO (as he did in Using RTL-SDR with Labview, Chapter 2: Labview RT).


Things started off well enough.  We've been able to call DLL functions to Open and Close the connection to the API for the SDRplay, read back correctly the version of the API, and Lock (and Unlock) the API for our use.  The next step is to query the API for a list of available devices connected to the system with a call to sdrplay_api_GetDevices.


sdrplay_api_ErrT sdrplay_api_GetDevices(sdrplay_api_DeviceT *devices, 
 unsigned int *numDevs,
 unsigned int maxDevs)


The devices parameter is described as "a pointer to an array of device enumeration structures used to return the list of available devices".  The struct definition for devices is 


typedef struct 
 char SerNo[SDRPLAY_MAX_SER_NO_LEN]; // Set by the API on return from 
                                     // sdrplay_api_GetDevices() contains the serial
                                     // number of the device
 unsigned char hwVer;                // Set by the API on return from 
                                     // sdrplay_api_GetDevices() contains the Hardware 
                                     // version of the device
 sdrplay_api_TunerSelectT tuner;     // Set by the API on return from 
                                     // sdrplay_api_GetDevices() indicating which tuners 
                                     // are available.
                                     // Set by the application and used during 
                                     // sdrplay_api_SelectDevice() to indicate which 
                                     // tuner(s) is to be used.
 sdrplay_api_RspDuoModeT rspDuoMode; // Set by the API on return from 
                                     // sdrplay_api_GetDevices() for RSPduo devices 
                                     // indicating which modes are available.
                                     // Set by the application and used during 
                                     // sdrplay_api_SelectDevice() for RSPduo device to
                                     // indicate which mode is to be used.
 double rspDuoSampleFreq;            // Set by the API on return from 
                                     // sdrplay_api_GetDevices() for RSPduo slaves 
                                     // indicating the sample rate previously set by the 
                                     // master. 
                                     // Set by the application and used during 
                                     // sdrplay_api_SelectDevice() by RSPduo masters to 
                                     // indicate required sample rate.
 HANDLE dev;                         // Set by the API on return from 
                                     // sdrplay_api_SelectDevice() for use in subsequent 
                                     // calls to the API. Do not alter!
} sdrplay_api_DeviceT;


The SerNo parameter is a fixed length string of 64 characters.  I was unsure of how to include this in my cluster definition but what I have working at the moment is to have 8 back to back U64 items that I later untangle to turn into a LabVIEW string where I'm getting back the proper serial number.  There is perhaps a better way of doing this and if so I'd love to learn about it but the SerNo is a bit low priority.   


The hwVer byte should be 0x04 for the RSPdx model that I am using and I'm getting that back OK.  The tuner and rspDuoMode parameters are defined as ENUMs and I have U32 sized enums in my cluster for them along with a DBL for the rspDuoSampleFreq parameter.  


But I have no idea how large the HANDLE parameter named 'dev' should be.  I happen to have two devices so I could call this function and get a response that included two elements in the devices array and was able to figure out that I needed to make the dev be 15 bytes long in order for the second serial number parameter to line up properly in the second entry in the array.  I made a place holder for dev consisting of a U64, U32, U16 and a U8 to make up the 15 bytes.  


Here is an image showing the devices array that I receive when calling this function with two devices connected to my system.


2021-03-15 Results from Get Devices.png


My code where I call sdrplay_api_GetDevices is shown here




And the devices parameter in the Call Library Node is set up as Adapt to Type with a Data Format of Array Data Pointer.


Screenshot 2021-03-16 074233.png


Later, when I select a device I am going to have to pass back an element of this array to a function called sdrplay_api_SelectDevice and the 'dev' HANDLE will then be populated with information that shouldn't be touched.


sdrplay_api_ErrT sdrplay_api_SelectDevice(sdrplay_api_DeviceT *device)


And even later I will have to pass just the 'dev' HANDLE to some routines as in ...


sdrplay_api_ErrT sdrplay_api_GetDeviceParams(HANDLE dev,sdrplay_api_DeviceParamsT **deviceParams)


So, what I'm looking for is advice for how to set up 'dev' in my LabVIEW cluster to make this work for these future calls.  It seems odd to me that 'dev' would really be 15 bytes but that is what seemed to be required to make the GetDevices function work properly when I had more than one device connected.  Is it possible that the HANDLE is a different number of byte (maybe 12) and the extra bytes (3 perhaps) are there for alignment of the cluster on a 4-byte boundary within the array?  Still, I'm unsure how to define 'dev' in my LabVIEW cluster.


Another question, much further down the road, is that after selecting a device and setting the parameters properly this API sends data back using callback functions.  At first I saw a mechanism for callback functions in the Call Library Node dialogs and thought I was going to be OK here.  But after reading Rolfk's solution at this post I'm worried that this will not be possible, at least for me with my limited knowledge of C.


I'm attaching the API specification for this device and am happy to share anything else in my code that I may have not described well above.  



Doug Harper


0 Kudos
Message 1 of 4

64 characters serial number doesn't always mean U64, an unsigned 8 Byte number. What if its a 4 byte (32bit) signed? The documentation is not clear. 


It appears HANDLE is an enumeration, 0 to some number... . Could be 32bit also. 


Your picture above, your showing number in hex format.. for serial numbers etc.  


Looking at your pic, your sdrplay_api_GetDevices function prototype "devices" are not "Array Data Pointer" for Data Format. A pointer, so likely 32bit number or even maybe 64bit number, U32 or U64.  This will take some trail and error to work out despite what documentation says. 

0 Kudos
Message 2 of 4

Thanks for your reply.  


I should have mentioned that the typedef struct I showed for device in my original post was for a single element of an array that gets returned when one calls GetDevices.  As I mentioned, when I connect two devices to the system I can tell that there must be some padding at the end of this struct to make it align on (I guess) an 8-byte boundary.  I can tell this because the serial numbers at the start of the struct align up in multiple elements of the devices array and I can decode these bytes and I get the proper serial numbers.


I'm now suspecting that HANDLE is 32-bits as you mention but that there must be some padding at the before dev to make it align at an 8-byte boundary also.  The next function that one would call after GetDevices is SelectDevice where you pass in a single instance of the devices array that you wish to select. 


sdrplay_api_ErrT sdrplay_api_SelectDevice(sdrplay_api_DeviceT *device)


Among other things, it populates the dev HANDLE in this struct with information that is needed later.  When I do this with my current iteration of the device cluster, the values in the device cluster before and after calling the SelectDevice function are shown below.


2021-03-18 Understanding Device Structure - Small.png


There are 4 bytes that are changed by the SelectDevice function call.  They are underlined in the before and after versions of this cluster shown above.  I'm wondering if I should rearrange this cluster so that there are 7 bytes of padding between SampleFrequency and dev and then 4 bytes of padding at the end of dev to align the entire cluster on an 8-byte boundary.  As you can see, my cluster is now 96 bytes long so it is divisible by 8.  I flattened it to string and found the string length to find this value.  I guess that this makes sense and I'm going to give it a try.  As I said in my original post, I need to be able to pass just the dev HANDLE to subsequent function calls in the DLL.  Unfortunately I don't have access to the full header file, but I'm asking for it from the manufacturer of the device.  


BTW, I'm running on a 64-bit machine (of course) and the API for the SDRplay is 64 bit.  I'm using 32-bit LabVIEW.


Thanks for any advice from the experts out there ...


Doug Harper



0 Kudos
Message 3 of 4

I think serial number is easiest to tackle. Looking at your Serial No 00 and Serial No 01, they don't appear to be correctly parsed.  If you know the serial numbers you can easily verify for correctness of parse then move onto SelectDevices().


Your initial post shows a 10 digit hex serial number (some leading zeros not shown), does this match your SDR documentation your saying?


The API is 64bit then you'll need 64bit Labview I would think... 32bit does not handle the memory address of 64bit SW..



0 Kudos
Message 4 of 4