fventuri / gr-sdrplay

GNU Radio OutOfTree (OOT) Module for SDRplay RSP SDRs - uses SDRplay API version 3
4 stars 4 forks source link

[Not really an ISSUE] Using C++ API for creating a C++ console app #2

Open Pratik310commits opened 3 years ago

Pratik310commits commented 3 years ago

[Not really an ISSUE] Hi @fventuri, I hope you are well. I need your help in understanding, what would I need in terms of APIs and repos, for creating a C++ based console app, that also utilizes SDRPlay APIs. I am trying to create something bypassing the GNURadio Companion altogether, just using the SDRPlay API. Will it still be an OOT Module? Will I need to use this or the sdrplay3 repo (of course depending on the version I am using)? Thanks in advance.

Pratik310commits commented 3 years ago

I understand OOT Module is for building with GNURadio Companion, but will one of these sdrplay repositories be the ones for me to use in creating a C++ based application? Since your repository has all the implementation files, I was hopeful I'll use those "impl.cc" files and the headers and the APIs.

fventuri commented 3 years ago

@Pratik310commits Writing a C/C++ console application that uses directly SDRplay API and header files is actually pretty simple. I recommend that you start by just copying and pasting the example source from SDRplay API specification guide: https://www.sdrplay.com/docs/SDRplay_API_Specification_v3.07.pdf - chapter 4

That's how I started learning how SDRplay API works - to save you the time of cutting and pasting that example, you can find a zip file with the example source code and Makefile attached in this GitHub comment that I wrote yesterday: https://github.com/pothosware/SoapySDRPlay3/issues/41#issuecomment-882114787

Once you have that example working you can start making some changes to it, and see what happens and that should help you with your project.

Good luck, Franco

Pratik310commits commented 3 years ago

I have done that already. I went through the header file but it didn't have many functions like the ones your repository has, for setting frequency etc So I was wondering.

Thanks though

fventuri commented 3 years ago

@Pratik310commits The reason why you don't see actual functions to set/change RSP parameters like setting frequency, etc is because they are just assignments to device parameters; for instance to set the central frequency, you just have to write something like this:

chParams->tunerParams.rfFreq.rfHz = 100e6;

If you change the frequency while the RSP is streaming, you will also have to invoke the SDRplay API sdrplay_api_Update(), like this:

sdrplay_api_Update(device.dev, device.tuner, sdrplay_api_Update_Tuner_Frf, sdrplay_api_Update_Ext1_None);

Perhaps another useful command line application you could look at is the source code for SDRplay RSPTCPServer, which you can find here: https://github.com/SDRplay/RSPTCPServer

Franco

Pratik310commits commented 3 years ago

Hi @fventuri Thanks, this helps me a lot. I'll look into it this as well.

Best, Pratik

Pratik310commits commented 3 years ago

Hi @fventuri I am finding it difficult to understand what the example_app does. It has a piece of code that says "it will start streaming" Does that mean it will sweep the signal coming it and we can apply our own FFT functions etc? I am trying to get the signal passing through the RSP1A and then do custom processing on it, but I am still struggling to understand the purpose of this example app, with the whole "streaming"

Pratik.

fventuri commented 3 years ago

@Pratik310commits I think to have a good picture on how streaming works in the SDRplay API it is important to understand the receive callbacks (StreamACallback/StreamBCallback).

Immediately after you call sdrplay_api_Init(), the SDRplay API will start calling back the receive callback functions passing the number of samples and the actual I/Q values (in the arrays xi and xq) to them. It is then up to you, the developer, to write the receive callback functions and process those I/Q samples the way you want (FFT, filtering, demodulation, etc).

You probably want to start with something simple first (say min, max, and average) to understand how these receive callbacks work.

Franco

Pratik310commits commented 3 years ago

@fventuri Superb. I just kinda figured those call back functions and was printing out the values. And what you said just gives me an affirmation that the way I was assuming the callbacks worked is correct. thanks a lot.

Pratik

Pratik310commits commented 3 years ago

++ The function comment clearly said, process the stream callback data here so I started printing out those values and I figured this function is something I need to use. Thanks though.

Pratik310commits commented 3 years ago

Hi @fventuri The documentation says (about the callback functions) This callback is triggered when there are samples to be processed. How do I get it to stream continuously? The callback is being invoked only once when I call the init() Also, the "reset" variable Indicates if a re-initialisation has occurred within the API and that local buffering should be reset So do I need to reset any parameter?

fventuri commented 3 years ago

@Pratik310commits Pratik, I am not really sure I understand what you are observing there.

To get started I would just run the example code with the receive callback printing out a line every time it is called (nothing else), like this:

void StreamACallback(short *xi, short *xq, sdrplay_api_StreamCbParamsT *params, unsigned int numSamples, unsigned int reset, void *cbContext)
{
    printf("sdrplay_api_StreamACallback: numSamples=%d\n", numSamples);
    return;
}

If everything works as expected, you should see that line on your terminal many many times, one after another, which should confirm that the receive callback is working correctly.

As per the reset argument, I wouldn't worry about it at this stage, since you are still trying to figure out how the receive callbacks work. Once you have that part well understood, you can add another print statement when the argument reset is true and see what needs to be done in your code when it occurs.

Franco

Pratik310commits commented 3 years ago

@fventuri , yes I realized that the reset sets to 1 only once at the start, and hence the print inside if(reset){ } wasn't being printed in the subsequent calls. So I started printing irrespective of the reset variable. I almost got what I wanted, just still don't know when or how the reset actually resets to 1.

Pratik310commits commented 3 years ago

Hi @fventuri Like you said, to update the frequency I need to write something like this:

chParams->tunerParams.rfFreq.rfHz = 100e6; If I want to change the frequency while the RSP is streaming, I will also have to invoke the SDRplay API sdrplay_api_Update(), like this:

sdrplay_api_Update(device.dev, device.tuner, sdrplay_api_Update_Tuner_Frf, sdrplay_api_Update_Ext1_None);

When I try to invoke it from one of the stream callback functions, it gives me the error "Api Update Failed" Do I have to uninitialize it before changing the frequency if I am changing it using another thread? Or I can update it using another thread at all?

fventuri commented 3 years ago

@Pratik310commits as you pointed out, I suspect the problem comes from trying to update the frequency from the receive callback functions=. Since those callbacks happen in the context of the SDRplay API library thread, I usually try to keep them to a minimum, i.e. just having them copy the streaming data to a buffer (or a queue of buffers) with minimal (say short to float conversion) or no processing at all in the callback function, to avoid losing samples.

In the main thread (or in an another thread created for this purpose), you can then process the samples, trigger frequency updates and other changes, but you should not have to unitialize and reinitialize the streaming; the call to the sdrplay_api_Update() function should be enough. Please be aware that it takes a few milliseconds after your call to sdrplay_api_Update() for the frequency to actually change; to find out when it does change you have to check the variable rfChanged for a non-zero value. To see how it can be done, please take a look at the code changes in this commit: https://github.com/pothosware/SoapySDRPlay3/commit/7ffab93ac31438b54cfb27bd9515b3dc251c25d9

Also since you'll be working with multiple threads exchanging the buffers with the sample data, you may want to make sure you put mutexes (or semaphores) around the critical parts of the code for synchronization, in order to avoid race conditions and other unpleasant "surprises" (if you are not familiar with mutexes and semaphores, and other multithreading issues, there are a number of resources out there that can help you).

Franco

Pratik310commits commented 3 years ago

@fventuri Yes, I am familiar with multithreading and mutexes and semaphores. Thanks though. I changed frequencies through a different thread as well as the main thread actually earlier today and it worked in both cases.

Pratik

Pratik310commits commented 3 years ago

Hi @fventuri I worked on the console app and got the desired results.However I noticed that I couldn't find the option to change gain (when AGC is disabled) using python blocks. This python file is the one that gets created while executing the project on GNURadio companion. On the console app, I was able to change grdB gain, lnagain, etc. I am unable to get the same thing on the python project. Is it ecven possible to do that in python? Does the python access the entire SDRPlay API and can access these functionalities of changing gain?

Pratik310commits commented 3 years ago

I realised that _if_attendb is what I wanted to change, and I am doing so by using"self.sdrplay_rsp1a_source_0.set_if_atten_db(value)" However, I still want to be sure of that, but I am unable to find a getter function for that

fventuri commented 3 years ago

@Pratik310commits

I just looked at the pybind11 Python bindings for the GNU Radio OOT module gr-sdrplay3, and I think that the functions you are looking for are:

The number and name of the arguments for each function should be obvious from the source code in the links above.

Franco