pothosware / SoapySDRPlay2

Soapy SDR plugin for SDRPlay
MIT License
51 stars 11 forks source link

RSPduo support #62

Closed SDRplay closed 4 years ago

SDRplay commented 4 years ago

I made a fork under my account and created a branch called 'RSPduo_fixes' (https://github.com/fventuri/SoapySDRPlay/tree/RSPduo_fixes). I cleaned up a couple of warnings during compile and I also straightened up the code for the RSPduo mode/tunes and antennas (hopefully). I tested my changes this afternoon using 'SoapySDRUtil' with the following commands:

SoapySDRUtil --probe="driver=sdrPlay, rspduo_mode=Tuner A (Single Tuner)" SoapySDRUtil --probe="driver=sdrPlay, rspduo_mode=Tuner B (Single Tuner)" SoapySDRUtil --probe="driver=sdrPlay, rspduo_mode=Tuner A (Master/Slave)" SoapySDRUtil --probe="driver=sdrPlay, rspduo_mode=Tuner B (Master/Slave)" SoapySDRUtil --probe="driver=sdrPlay, rspduo_mode=Dual Tuner"

and in each case 'SoapySDRUtil' returned what I expected (including 2 RX channels in the last case with 'Dual Tuner').

Please give it a try and if it looks OK to you, I'll go ahead and send a pull request.

Franco

Originally posted by @fventuri in https://github.com/pothosware/SoapySDRPlay/issues/58#issuecomment-566337373

SDRplay commented 4 years ago

Hi @fventuri, this is a good start and only works for probing and not in an application - master mode has certain limits... must be only Low-IF mode, sample rate must be either 6 or 8 MHz only - IF Freq must be either 1.62 MHz or 2.048 correspondingly.

Once the first tuner is in master mode, then probe should only return or allow slave mode. If I start one instance of CubicSDR and then run probe again I get a map::at error

Slave mode cannot have any sample rate control, or IF frequency. It can have independent bw and decimation control however.

fventuri commented 4 years ago

Thanks for your feedback.

I committed several changes to the 'RSPduo_fixes' branch in my repo that should address some of the problems with the application. The application I used for my tests is CubicSDR (version 0.2.4) - I was able to have the driver run in single tuner, dual tuner, and master mode; while in master mode, I was able to launch a second instance of CubicSDR and use the slave instance.

While I was testing the code for SoapySDRPlay, I noticed that CubicSDR has a couple of quirks:

  1. it ignores the return value when calling activateStream() (in CubicSDR source code look at the file src/sdr/SoapySDRThread.cpp line 119); therefore it would ignore when the activateStream() in SoapySDRPlay returned the error SOAPY_SDR_NOT_SUPPORTED. I changed the behavior of activateStream() in the driver to throw an exception instead; this makes CubicSDR crash, but at least this way I could see there was a problem with sdrplay_api_Init()

  2. somehow CubicSDR seems to be unable to deal with a list of antennas dependent on the rspDuoMode and tuner (i.e. only 'Tuner 1 50 ohm' and 'Tuner 1 Hi-Z' should be listed if the tuner selected is Tuner A, while only 'Tuner 2 50 ohm' should be listed for Tuner B). In order for listAntennas() to list all the antennas (independent of the tuner) when using CubicSDR, I added (for now) a boolean called 'CubicSDR', which is set to true to address this quirk. In the final version of the driver, I'd like to find a better way to handle this issue.

Also the code for the driver has become more messy to handle the dual tuner and master/slave cases, but at least I was able to make it run without crashing for the most common use cases I could think of.

Please give it a try when you get a chance and let me know how it goes for you.

Franco

nmaster2042 commented 4 years ago

Hi, I tried the new Franco's branch for API v3 & RSP Duo support with a fresh built CubicSDR.

When I start CubicSDR it scans for Soapy devices and finds my RSP Duo.

I select it and the app hang and exits.

On the console windo I can see:

SDR enumerator starting. SoapySDR init.. API Version: v0.8.0 ABI Version: v0.8 Install root: /usr/local Loading modules... Available factories...netsdr, null, sdrPlay driver = sdrPlay label = SDRplay Dev0 RSPduo 1809XXXXXX Make device 0 [INFO] devIdx: 0 [INFO] hwVer: 3 sdrplay_api_api_version=3,060000 sdrplay_api_hw_version=3

Reporting enumeration complete. SDR enumerator done. [INFO] devIdx: 0 [INFO] hwVer: 3 [ERROR] Invalid RSPduo mode change: 7 -> 8 Terminating SDR thread.. ERROR: thread '9SDRThread' has not terminated in time ! (> 3000 ms)

I don't know if it's a CubicSDR issue or a SoapySDRPlay one.

fventuri commented 4 years ago

Thanks for the feedback, nmaster2042. What this line:

     [ERROR] Invalid RSPduo mode change: 7 -> 8

means is more or less the following.

RSPduo mode 7 (7=1+2+4) means that the RSPduo can run in 'single tuner', 'dual tuner' or 'master' mode (these codes are described in the enum 'sdrplay_api_RspDuoModeT' in the include file 'sdrplay_api_rspDuo.h') - this is typically the list of modes that the RSPduo accepts when no other application is using it.

On the other hand mode 8 means CubicSDR tries to run that RSPduo in 'slave' mode, which is the mode you would choose when another application is already using the same RSPduo in 'master' mode. Typically this happens because CubicSDR on exit saves its last used configuration in a config file called $HOME/.CubicSDR/config.xml.

If you look at that contents of that file, you'll see a stanza that looks more or less like this:

        <device>
            <id>SDRplay Dev0 RSPduo SERIALNUM</id>
...
            <settings>
                <agc_setpoint>-30</agc_setpoint>
                <biasT_ctrl>false</biasT_ctrl>
                <dabnotch_ctrl>false</dabnotch_ctrl>
                <extref_ctrl>false</extref_ctrl>
                <if_mode>1620kHz</if_mode>
                <iqcorr_ctrl>true</iqcorr_ctrl>
                <rfgain_sel>4</rfgain_sel>
                <rfnotch_ctrl>false</rfnotch_ctrl>
                <rspduo_mode>Tuner A (Master)</rspduo_mode>
            </settings>
...
        </device>

When you restart CubicSDR it reads that file and tries to ask the driver for the mode previously saved in the 'rspduo_mode' element. If in your case, you might have something like 'Tuner B (Slave)', that can trigger the error you saw.

A quick workaround (for now) is to edit that config file and change the 'rspduo_mode' line to something like 'Tuner A (Master)' - after that CubicSDR should work. A better way would be to exit the CubicSDR in slave mode first and then exit the CubicSDR in master mode last - this way the config file should contain an entry like mine (i.e. 'Tuner A (Master)').

Finally I should probably address this issue by making a simple change in the driver, such that in a scenario like yours it would select 'single tuner' or 'master' mode (with the same tuner in the config, or the other tuner, or always 'Tuner A'?).

Hope this helps, Franco

vsonnier commented 4 years ago

it ignores the return value when calling activateStream() (in CubicSDR source code look at the file src/sdr/SoapySDRThread.cpp line 119); therefore it would ignore when the activateStream() in SoapySDRPlay returned the error SOAPY_SDR_NOT_SUPPORTED. I changed the behavior of activateStream() in the driver to throw an exception instead; this makes CubicSDR crash, but at least this way I could see there was a problem with sdrplay_api_Init()

somehow CubicSDR seems to be unable to deal with a list of antennas dependent on the rspDuoMode and tuner (i.e. only 'Tuner 1 50 ohm' and 'Tuner 1 Hi-Z' should be listed if the tuner selected is Tuner A, while only 'Tuner 2 50 ohm' should be listed for Tuner B). In order for listAntennas() to list all the antennas (independent of the tuner) when using CubicSDR, I added (for now) a boolean called 'CubicSDR', which is set to true to address this quirk. In the final version of the driver, I'd like to find a better way to handle this issue.

That is the problem with the "pull the rug under the SDR feet" problem of the Duo. Cubic expects that Settings are obeyed and don't change dynamically because of another instance in particular. That is why I suggested in #58 that the device only present "automagically" settings that stay relatively static afterwards depending of the starting order.

Maybe presenting a reduced capability "CubicSDR"

@SDRplay suggested in #58 presenting different devices in the selection panel:

It's not as simple as always starting the first instance as the master. In master mode, Low-IF is only possible and so therefore only 2 MHz of bandwidth. So what we do in SDRuno is to always start in single tuner mode, but have a switch to allow the changing of the first instance into master mode. Then the 2nd instance would automatically start in slave mode. Then there is dual tuner mode, where both tuners are controlled by the same instance. I guess this could all be handled by a mode option in the device selection panel.

Whichever instance is using tuner 1 will still be able to switch between the HiZ port and port A in master/slave mode.

I'm not even sure other API layers using Soapy underneath like gr-osmo or such in GQRX and others would interface that dynamic settings any more kindly, so presenting different capability classes as pseudo-"Devices" may be the solution.

SDRplay commented 4 years ago

I must admit I'm a bit confused as to what the intention is with the driver. In SDRuno, we always start the RSPduo in single tuner mode EXCEPT when the RSPduo is already being used in master mode, then slave mode must be used. It's very simple, there are no variables required.

Why can't it be done like that?...

scenario 1: RSPduo connected, but neither tuner in use

scenario 2: RSPduo connected and master mode is already in use by CubicSDR

scenario 3: RSPduo connected and single tuner is in use by CubicSDR

This to me seems very simple - is there a problem with implementing it this way? By allowing variables to be passed, there seems to be an assumption that they override existing behaviour - for example if the RSPduo is already being used in master mode, would you expect that another instance of CubicSDR where "single tuner" is being passed in via the rspduo_mode variable would work - because it won't and shouldn't be expected to either.

Unless I've missed something about the way CubicSDR and the SoapySDR framework behave?

vsonnier commented 4 years ago

@SDRplay summurizes it right I think, the SoapySDR driver should only present the settings appropriate to each of the 3 scenarios above. Once in a given "mode", the list of settings is indeed frozen and CubicSDR or others should be able to run normally, being either Single, Master, or Slave exclusively. We should not try to override the auto-detected or manually chosen mode by other means like this persistent rspduo_mode.

can CubicSDR deal with multiple streams from a single driver instance ?

Alas no. Only 1 device, 1 readStream thread active at any given time. The Devices menu is always available though, and allows switching of devices without restarting CubicSDR.

fventuri commented 4 years ago

Thanks for your comments, vsonnier and SDRplay.

My perspective on the SoapySDRplay driver was to write a "general purpose" SoapySDR driver, following more or less the guidelines here: https://github.com/pothosware/SoapySDR/wiki/DriverGuide (and more specifically the API contract specified here: https://github.com/pothosware/SoapySDR/blob/master/include/SoapySDR/Device.hpp). From this point of view CubicSDR is just one of the applications using the SoapySDRplay driver (for instance there could be other applications where they would want the 'Dual Tuner' option, since the API shows that a device could have multiple channels). This point also might help explain the confusion for SDRplay, where I think the application (SDRuno) and the driver are one thing and therefore there's no 'line of demarcation' between the two.

This said, I have no problem implementing the driver as presenting multiple "virtual devices" in the RSPduo case (I don't think it should be too hard) - I have just a few high level questions to avoid possible misunderstandings in the future:

As per my initial comment about CubicSDR ignoring the return value from 'activateStream()', there could be several reasons why the call to 'sdrplay_api_Init()' fails besides the case of a wrong RSPduo mode (see the list at the bottom of page 26 in https://www.sdrplay.com/docs/SDRplay_API_Specification_v3.06.pdf) - I am not sure how's CubicSDR expects the driver to communicate this failure.

Franco

SDRplay commented 4 years ago

I don't understand the significance of the naming. If that means something to the end application then I don't have a problem with whatever it needs to be. Note that once the RSPduo is in use, then the driver (for the 2nd instance of the end application) gets all the information it needs from the API about what that instance can or can't do. So the driver will not need to query any virtual device name for that information.

It's possible for the master tuner to be either tuner, the slave is just whichever one isn't in use. Again, you can get that information from the API.

The importance about the sample rate is...

Single Tuner - sample rate can be 2 - 10 MHz in Zero-IF mode and 6 MHz (which produces a final sample rate of 2 MHz) in Low-IF mode. Other sample rates can be used in Low-IF mode but with less efficiency so we tend not to recommend them now. Delivers 1 IQ stream.

Master Tuner - Low-IF mode only either 6 MHz or 8 MHz (both produce a final sample rate of 2 MHz) - you would ONLY use 8 MHz if the other tuner was using an application like dump1090 which expects 8 MHz sample rate. Delivers 1 IQ stream.

Slave Tuner - Neither sample rate or IF mode can be set - follows whatever the Master Tuner is using. Delivers 1 IQ stream.

Dual Tuner - Low-IF mode only and only 6 MHz sample rate (produces a final sample rate of 2 MHz) - delivers 2 IQ streams.

Note that for all of these scenarios, parameters like decimation and IF Bandwidth are independent and can be used by either tuner (except dual tuner mode where you would want those parameters to be consistent).

Gain control for each tuner is also independent of these scenarios.

SDRplay commented 4 years ago

Forgot to mention that when using 6 MHz Low-IF, the IF mode should be set to 1.62 MHz and when using the 8 MHz Low-IF, the IF mode should be set to 2.048 MHz - if not this could cause the incorrect tuner mode to be selected.

fventuri commented 4 years ago

I made the changes you suggested - now the SoapySDRPlay driver can present multiple 'virtual devices' for the RSPduo depending on the available RSPduo modes. I quickly ran a couple of tests using CubicSDR a few minutes ago and I was able to run two instances, one as a master, and one as a slave. I'll run a few tests tomorrow morning, but in the meanwhile you can give it a try to see if it works as you described above.

Franco

nmaster2042 commented 4 years ago

Hi Franco.

I just rebuilt your SoapySDRPlay api3 branch.

I removed the .CubicSDR folder in order to reinitialize CubicSDR user configuration, as you explained.

Now when I start CubicSDR I can see 5 devices. From a user point of view it's more understandable like this.

But, I can't start a SDR session with any of these devices: CubicSDR crashes and I get this error in the console:

SDR thread starting. device init() [INFO] Using format CF32. [ERROR] error in activateStream() - Init() failed: sdrplay_api_Fail terminate called after throwing an instance of 'std::runtime_error' what(): error in activateStream() - Init() failed Abandon (core dumped)

One other detail, When selecting Tuner A single or master, Bias tee option has to be removed.

nmaster2042 commented 4 years ago

OK, it seems I have a small issue with the sdrplay 3 API on my system.

I'm investigating this issue and I'll make more tests.

SDRplay commented 4 years ago

5 devices?? I'm not at my desk but will take a look as soon as I can. Why is it not just 1 device and then deal with the different modes like another IF mode?...

i.e.

RSPduo = 1 device Mode (dropdown like IF mode) = Single Tuner, Master Tuner, Dual Tuner

The thing I didn't like about the rspduo_mode variable was that it was required to be set to do anything. What should happen is that the API should be queried and then the functionality presented as dropdown options to the user.

Same goes for Tuner #

Is that not possible? I'll take a look asap and provide some feedback.

vsonnier commented 4 years ago

Mode (dropdown like IF mode) = Single Tuner, Master Tuner, Dual Tuner

Can't work. Make the Mode a setting that is RW with readSetting/writeSetting like the others (RF notch, antenna choice, IF modes....etc.) will make it possible to change the Mode at any time at runtime, which we don't want. Presenting different "pseudo-Device " (ex RSPDuo-Single, RSPDuo-Master, RSPDuo-Slave) that stay stable once selected is the only way, unless I'm missing something there.

nmaster2042 commented 4 years ago

These are virtual devices.

When starting the firs CubicSDR, and no tuners are actually in use you get 5 devices (Tuner A single, Tuner B single, Dual tuner, Tuner A master and tuner B master).

When you chose device tuner A Master for example, when you start another instance of CubicSDR you only get Tnuer B slave with good IF and sample rate settings.

Let's give a try.

It's probably different than on SDRUno I never used but this way is better than the rspduo_mode option.

SDRplay commented 4 years ago

My point was I don't understand why there is 5, but there should be 3. Why is Tuner in the virtual name?

Are you saying that when you select the device, that you then can't customise the other options??

If so, then what is to stop me from selecting Tuner A master and 10 MHz sample rate with Zero IF - this is obviously not a valid combination.

If you can deal with that, then why can't the tuner also be like antenna select?

nmaster2042 commented 4 years ago

In the actual implementation, when you select RSP Duo Tuner A master you simply can't select 10 mhz sample rate and zero-if because sample rate is fixed to 6 mhz and if mode = 1620 khz to prevent user to select wrong values as I made and crashing the app.

Instead you can select Tuner A single to put 10 Mhz sample rate and Zero IF.

I think the reason why there is 5 virtual devices and not 3 is because it seems to be the way to deal with options of each tuner considering the mode (single, dual, master/slave).

In Cubic SDR, when you select a device, there is different options, but one can't be dynamically changed depending of the value of an other option.

In the first implementation with the rspduo_mode, you could select the mode but you had to manually set sample rate and if mode correctly because options couldn't be automatically modified.

It's my understanding.

I'm testing this, for now it seems to work ok.

SDRplay commented 4 years ago

In master mode, the sample rate can be either 6 MHz (1.62 MHz IF) or 8 MHz (2.048 MHz IF) - so is 8 MHz not an option?

I guess what I'm not understanding is that if you can select sample rate depending on whether you've selected master or single (as you've stated above), then I don't understand why the same is also not true of what antenna/tuner is used.

I'll try it myself later today when I'm at my desk and I'll probably get a better feel for it and get back to you.

nmaster2042 commented 4 years ago

For now, in master mode, only 6 Mhz SR with IF mode of 1620 khz is selectable. But 8 Mhz / 2048 khz can probably can be added.

The master / slave mode is actually working I can use 2 instances of CubicSDR.

Yes, the best way is to get a try by yourself to give a feedback.

nmaster2042 commented 4 years ago

But if 8 Mhz / 2048 khz is added in master mode, user will need to pay attention to adjust the 2 parameters correctly because it will be possible to select for example 6 Mhz SR and 2048 khz IF mod witch will be incorrect.

OR, for master mode it would be better to have 2 options combining the 2 parameters:

This would prevent users (like me lol) to chose incorrect combination.

fventuri commented 4 years ago

Thanks everyone for trying it and especially their feedback.

A couple of comments:

Master Tuner - Low-IF mode only either 6 MHz or 8 MHz (both produce a final sample rate of 2 MHz) - you would ONLY use 8 MHz if the other tuner was using an application like dump1090 which expects 8 MHz sample rate. Delivers 1 IQ stream.

As per when the driver is used in slave mode, in this case the driver uses the sample rate already set by the master (be it 6Ms/s or 8Ms/s), so if someone were to start say dump1090 in master mode (which would set the sample rate to 8Ms/s) and then run CubicSDR in slave mode, CubicSDR would use an 8Ms/s sample rate (and an IF mode of 2048 kHz).

Franco

nmaster2042 commented 4 years ago

You are right Franco, the simplest is the best I think.

In the particular case of app such as dump1090, the only thing to remember is to start it in master mode so it can get its 8 Mhz SR.

As we can chose witch tuner will be the master, it can serve all uses cases I think.

fventuri commented 4 years ago

OK, I think I figured out the issue with CubicSDR and the list of antennas shown. I took a look at the source code for CubicSDR and I found this code(see https://github.com/cjcliffe/CubicSDR/blob/master/src/forms/SDRDevices/SDRDevices.cpp#L136):

        //A-3) Antennas, is there are more than 1 RX antenna, else do not expose the setting.
        //get the saved setting
        const std::string& currentSetAntenna = devConfig->getAntennaName();

        //compare to the list of existing antennas
        SoapySDR::ArgInfo antennasArg;
        std::vector<std::string> antennaOpts = selDev->getAntennaNames(SOAPY_SDR_RX, 0);

        //only do something if there is more than 1 antenna
        if (antennaOpts.size() > 1) {

            //by default, choose the first of the list.
            std::string antennaToSelect = antennaOpts.front();

This explains why when I was selecting any of the tuner B cases (either in single tuner mode or in master mode), the antenna entry was not there (because there's only one choice). After understanding this, I may have to revisit my comments about the way CubicSDR handles the antenna selection (and therefore the tuner choice discussion above).

Franco

vsonnier commented 4 years ago

This is the initial Device dialog choosing. The other place where list of antennas are read and displayed is this: https://github.com/cjcliffe/CubicSDR/blob/57454e4b32040e98a6c296cbfeb1335b108a940b/src/AppFrame.cpp#L1036

But the principle is the same: there is no point, in principle, of displaying a list of antennas made of 1 entry because there is no choice. This is to have a cleaner UX, nothing more, nothing less.

For information, here is the original PR I made to support multiple antennas easily when I bought my RSP2 : https://github.com/cjcliffe/CubicSDR/pull/571

fventuri commented 4 years ago

Thanks vsonnier for the clarification about the antenna thing.

I fixed another bug I found this afternoon where in CubicSDR switching from one pseudo device (for instance Tuner A - Single) to a different pseudo device (for instance Tuner B - Single), and then back again to the first pseudo device (Tuner A - Single) causes some problems because CubicSDR tries to re-use the initial instance of that pseudo device (instead of reinitializing it), while I think the SDRplay 3.x API expects that the client goes through a full ReleaseDevice/SelectDevice cycle (+ GetDeviceParams). I added a check in readSettings() so that, if the device is not the one selected (i.e. if CubicSDR didn't initialize it), then a new function called 'reselectDevice()' is invoked, that does exactly that.

I also found out this afternoon that, when streaming in Single Tuner mode, there are quite a number of times where the time elapsed between two successive calls to 'rx_callback' is above 100,000us, which then causes timeouts in 'acquireReadBuffer()', which show up in the console as messages: 'SoapySDR read failed with code: -1'. To understand better this problem, I lowered the threshold, and I logged all the cases where the time elapsed between two successive calls to 'rx_callback' is above 90,000us - there were a lot of them, so it seems this issue needs some more research. I am not sure if you too see these messages in Single Tuner mode (I didn't try to see if it happens in Dual Tuner mode), or if it just something going on on my computer.

Franco

vsonnier commented 4 years ago

I fixed another bug I found this afternoon where in CubicSDR switching from one pseudo device (for instance Tuner A - Single) to a different pseudo device (for instance Tuner B - Single), and then back again to the first pseudo device (Tuner A - Single) causes some problems because CubicSDR tries to re-use the initial instance of that pseudo device (instead of reinitializing it), while I think the SDRplay 3.x API expects that the client goes through a full ReleaseDevice/SelectDevice cycle (+ GetDeviceParams). I added a check in readSettings() so that, if the device is not the one selected (i.e. if CubicSDR didn't initialize it), then a new function called 'reselectDevice()' is invoked, that does exactly that.

Truth be told, the Devices selection is rarely used after the intial CubicSDR startup, so it is small wonder a clean Device switch is probably not done. Now the changes you made are surely interesting for all, so a PR for CubicSDR would be greatly appreciated once the Duo problems are sorted out 👍

I'll have a look (later) at the Streaming code of the SoapySDR driver to see if there are obvious concurrency or performance problems, it has become my specialty for Cubic or Soapy drivers, so to speak (https://github.com/pothosware/SoapyPlutoSDR/pull/14).

SDRplay commented 4 years ago

The code won't build for me...

/usr/include/c++/5/bits/hashtable_policy.h:85:34: error: no match for call to ‘(const std::hash) (const sdrplay_api_RspDuoModeT&)’ noexcept(declval<const _Hash&>()(declval<const _Key&>()))>

Amongst many other errors, which I wasn't getting before. Someone point me in the right direction please.

fventuri commented 4 years ago

@vsonnier - I'll definitely plan to submit these changes as a PR once the design part is sorted out - so far everything is very 'experimental'

@SDRplay - I just tried pulling the code directly from github and recompiling and it worked for me:

$ git clone --single-branch --branch RSPduo_fixes https://github.com/fventuri/SoapySDRPlay.git
Cloning into 'SoapySDRPlay'...
remote: Enumerating objects: 39, done.
remote: Counting objects: 100% (39/39), done.
remote: Compressing objects: 100% (29/29), done.
remote: Total 459 (delta 24), reused 23 (delta 10), pack-reused 420
Receiving objects: 100% (459/459), 147.69 KiB | 1.64 MiB/s, done.
Resolving deltas: 100% (306/306), done.
$ cd SoapySDRPlay/
$ mkdir build
$ cd build
$ cmake ../
-- The CXX compiler identification is GNU 9.2.1
-- Check for working CXX compiler: /bin/c++
-- Check for working CXX compiler: /bin/c++ -- works
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Build type not specified: defaulting to release.
-- Found libsdrplay: /usr/local/include, /usr/local/lib64/libsdrplay_api.so
-- LIBSDRPLAY_INCLUDE_DIRS - /usr/local/include
-- LIBSDRPLAY_LIBRARIES - /usr/local/lib64/libsdrplay_api.so
-- Performing Test HAS_STD_CXX11
-- Performing Test HAS_STD_CXX11 - Success
-- Found Git: /bin/git (found version "2.21.0") 
-- Module sdrPlaySupport configured with version: 0.3.0-5e8a451
-- Configuring done
-- Generating done
-- Build files have been written to: /tmp/SoapySDRPlay/build
$ make
Scanning dependencies of target sdrPlaySupport
[ 20%] Building CXX object CMakeFiles/sdrPlaySupport.dir/Registration.cpp.o
[ 40%] Building CXX object CMakeFiles/sdrPlaySupport.dir/Settings.cpp.o
[ 60%] Building CXX object CMakeFiles/sdrPlaySupport.dir/Streaming.cpp.o
[ 80%] Building CXX object CMakeFiles/sdrPlaySupport.dir/Version.cpp.o
[100%] Linking CXX shared module libsdrPlaySupport.so
[100%] Built target sdrPlaySupport

Here I am running Linux Fedora 30 with gcc/g++ version 9.2.1:

$ cat /etc/os-release 
NAME=Fedora
VERSION="30 (Thirty)"
ID=fedora
VERSION_ID=30
VERSION_CODENAME=""
PLATFORM_ID="platform:f30"
PRETTY_NAME="Fedora 30 (Thirty)"
ANSI_COLOR="0;34"
LOGO=fedora-logo-icon
CPE_NAME="cpe:/o:fedoraproject:fedora:30"
HOME_URL="https://fedoraproject.org/"
DOCUMENTATION_URL="https://docs.fedoraproject.org/en-US/fedora/f30/system-administrators-guide/"
SUPPORT_URL="https://fedoraproject.org/wiki/Communicating_and_getting_help"
BUG_REPORT_URL="https://bugzilla.redhat.com/"
REDHAT_BUGZILLA_PRODUCT="Fedora"
REDHAT_BUGZILLA_PRODUCT_VERSION=30
REDHAT_SUPPORT_PRODUCT="Fedora"
REDHAT_SUPPORT_PRODUCT_VERSION=30
PRIVACY_POLICY_URL="https://fedoraproject.org/wiki/Legal:PrivacyPolicy"

$ g++ --version
g++ (GCC) 9.2.1 20190827 (Red Hat 9.2.1-1)
Copyright (C) 2019 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

Do you mind running the same commands (git clone, ..., cmake, and make) on your system? If the make step still fails for you, you can email me (my username at comcast dot net) the full output from make so I can take a look.

Franco

vsonnier commented 4 years ago

The code won't build for me...

/usr/include/c++/5/bits/hashtable_policy.h:85:34: error: no match for call to ‘(const std::hash) (const sdrplay_api_RspDuoModeT&)’ noexcept(declval<const _Hash&>()(declval<const _Key&>()))>

I would bet a C++ compatibility level. @fventuri, try to stick to C++11 only, maybe you used C++14 or C++17 contructs and recent GCCs maybe default to these recent standards. @guruofquality, what is the expected C++ standard supposed to be supported in the Pothosware ecosystem ?

nmaster2042 commented 4 years ago

@SDRplay I rebuilt with success too the rspduo_fixes branch from Franco's git repo.

SDRplay commented 4 years ago

Nope, won't build for me on Ubuntu 18.04.3 LTS - I've done everything you suggested @fventuri

gcc -v gcc version 5.5.0 20171010 (Ubuntu 5.5.0-12ubuntu1)

Updated to latest version using apt update apt upgrade etc.

vsonnier commented 4 years ago

gcc version 5.5.0

I suspect this GCC version is way too old, to support modern C++ features properly.

SDRplay commented 4 years ago

what do you do to update gcc?

SDRplay commented 4 years ago

bear in mind that almost all of our customers that want to use Linux, don't want to build anything, so to tell them that they first have to get a new compiler is going to be interesting lol

vsonnier commented 4 years ago

Let's try with this: https://linuxize.com/post/how-to-install-gcc-compiler-on-ubuntu-18-04/ installing GCC 7.xx as bare minimum.

bear in mind that almost all of our customers that want to use Linux, don't want to build anything, so to tell them that they first have to get a new compiler is going to be interesting lol

Well GCC 5.0 is an antique version w.r.t recent Ubuntus like v18.04, so they won't have to install anything most likely.

SDRplay commented 4 years ago

Interestingly build-essential has been marked for "kept back" - no idea why

Going to brute force upgrade it now

nmaster2042 commented 4 years ago

@SDRplay On my ubuntu 19.10 I have:

gcc version 9.2.1 20191008 (Ubuntu 9.2.1-9ubuntu2)

SDRplay commented 4 years ago

Just managed to get updated to gcc 7.4 - that wasn't pretty - had to uninstall packages, remove files and the contents of the status file just to get it to install build-essential correctly - nasty

Anyway, I've now built it and I can see it working.

Couple of things...

Master 6 MHz - the starting sample rate is 6 MHz, but it is 2 MHz by the time it gets to the application - CubicSDR is showing a 6 MHz sample rate, which is wrong - it should be 2 MHz

Now that there is only a single sample rate, decimation should be an option so that smaller sample rates can be used.

Master 8 MHz sample rate should also be an option.

Not sure I like the virtual devices but I understand it's a way to get this done.

I'll keep playing with it.

guruofquality commented 4 years ago

std::hash

Isnt this just a matter of the hash not being defined for a custom type, and not a feature greater than c++11.

I would bet a C++ compatibility level. @fventuri, try to stick to C++11 only, maybe you used C++14 or C++17 contructs and recent GCCs maybe default to these recent standards. @guruofquality, what is the expected C++ standard supposed to be supported in the Pothosware ecosystem ?

Ive tried not to use any C++14 and up in the common libraries, but its not really a big deal. Honestly when I started this, C++11 was just as recent as C++14 and 17 are now to the current date. Its pretty easy to have C++14 support in the latest ubuntu LTS and C++17 is mostly there.

fventuri commented 4 years ago

Thanks SDRplay and guruofquality - I just pushed a new commit that removes any use of hashes/unordered_maps from the code and uses instead 'stringTo...' and '...toString' methods (similar to the existing methods 'stringToIF' and IFtoString'). Hopefully this latest code should compile without warnings or errors on any version of gcc/g++ compiler.

As per the sample rate, I see that the exiting code for the the SoapySDRplay driver has (and I think it comes from the original code) this method called 'getInputSampleRateAndDecimation', that selects a decimation factor based on the IF mode and on the input sample rate. I assume this code is still valid when the RSPduo is running in single tuner mode, but I suspect it might need to be revisited for master (and slave mode). To make sure I understand how the RSPduo works, you are saying that in master mode, in case of a 'rspDuoSampleFreq' of 6MHz, the sample rate is actually 2 MHz with no decimation, but the user should be allowed to select a sample rate of 1 MHz with decimation factor of 2; or a sample rate of 500 kHz with a decimation factor of 4; and son on?

Finally I am also wrote (and I currently debugging) an 'hybrid' version of the driver where in the RSPduo case there's a pseudo device for each of the RSPduo modes (i.e. typically three pseudo devices - single tuner, dual tuner, master - when started first, or just one pseudo device - slave - when started as a slave), and the tuner choice (for the single tuner and master modes) is a drop down like the IF mode selection. Do you think you would like this approach better?

Franco

fventuri commented 4 years ago

As mentioned earlier, I created a new branch called 'pseudo_devices_by_RSPduo_mode' (https://github.com/fventuri/SoapySDRPlay/tree/pseudo_devices_by_RSPduo_mode), which presents a new pseudo device for each of the RSPduo modes that are available when the client application (CubicSDR in this case) is run, while the selection of the tuner is via dropdown. I ran only a couple of tests (single tuner, and one instance of CubicSDR as a master, and another instance as a slave), and they worked fine on my computer.

Please give it a try and let me know if this way looks better for you.

Franco

SDRplay commented 4 years ago

Hi @fventuri, the pseudo branch is much more what I thought it would look like - I think it looks better to the end user. Some comments...

  1. By definition, if single or master modes are available, then ALL 3 antennas should be available to be selected. Then depending on what antenna is selected, you can then automatically select the tuner - so I would be in favour of having all 3 antennas available, but removing tuner as an option. I think, again, this makes it easier for the end user.

  2. In dual tuner mode, in practice you wouldn't have any antenna select and just make tuner 1 50 Ohm and Tuner 2 50 ohm ports the ones to use. This is the way we have it set for SDRuno. For diversity reception you would want the two tuner inputs to be the same otherwise there is a mismatch in the gain control.

  3. In master mode, dual tuner mode and single tuner Low-IF mode, these are the options for sample rate...

Input: 6 MHz, Output: 2 MHz, decimation = 1, dec_enabled = false, IFBW = 1.536 MHz Input: 6 MHz, Output: 1 MHz, decimation = 2, dec_enabled = true, IFBW = 0.6 MHz Input: 6 MHz, Output: 500 kHz, decimation = 4, dec_enabled = true, IFBW = 0.6 MHz Input: 6 MHz, Output: 250 kHz, decimation = 8, dec_enabled = true, IFBW = 0.3 MHz Input: 6 MHz, Output: 125 kHz, decimation = 16, dec_enabled = true, IFBW = 0.2 MHz Input: 6 MHz, Output: 62.5 kHz, decimation = 32, dec_enabled = true, IFBW = 0.2 MHz

For master mode ONLY, you can also have:

Input: 8 MHz, Output: 2 MHz, decimation = 1, dec_enabled = false, IFBW = 1.536 MHz Input: 8 MHz, Output: 1 MHz, decimation = 2, dec_enabled = true, IFBW = 0.6 MHz Input: 8 MHz, Output: 500 kHz, decimation = 4, dec_enabled = true, IFBW = 0.6 MHz Input: 8 MHz, Output: 250 kHz, decimation = 8, dec_enabled = true, IFBW = 0.3 MHz Input: 8 MHz, Output: 125 kHz, decimation = 16, dec_enabled = true, IFBW = 0.2 MHz Input: 8 MHz, Output: 62.5 kHz, decimation = 32, dec_enabled = true, IFBW = 0.2 MHz

Note: this is for compatibility with dump1090 ONLY and shouldn't be used in normal circumstances.

For slave mode, the input sample rate is fixed by the master, but the output sample rate can be...

Output: 2 MHz, decimation = 1, dec_enabled = false, IFBW = 1.536 MHz Output: 1 MHz, decimation = 2, dec_enabled = true, IFBW = 0.6 MHz Output: 500 kHz, decimation = 4, dec_enabled = true, IFBW = 0.6 MHz Output: 250 kHz, decimation = 8, dec_enabled = true, IFBW = 0.3 MHz Output: 125 kHz, decimation = 16, dec_enabled = true, IFBW = 0.2 MHz Output: 62.5 kHz, decimation = 32, dec_enabled = true, IFBW = 0.2 MHz

Note: this is independent of what decimation is being used in the master.

SDRplay commented 4 years ago

By the way, the output sample rate should be what CubicSDR uses - not the input sample rate.

SDRplay commented 4 years ago

I've edited the comment above to add in the relevant IFBW values for each output sample rate.

vsonnier commented 4 years ago

By the way, the output sample rate should be what CubicSDR uses - not the input sample rate.

Yes indeed, it is crucial that the Sample rate the user has access to really corresponds to the final I/Q samples per second the whole processing is expecting. Now to achieve the correct behaviour of setSampleRate and getSampleRate API the right combinations of "input rate + decimation" as listed by @SDRplay has to be used for instance, and of course Decimation must not be exposed as a setting for the final user.

  1. By definition, if single or master modes are available, then ALL 3 antennas should be available to be selected. Then depending on what antenna is selected, you can then automatically select the tuner - so I would be in favour of having all 3 antennas available, but removing tuner as an option. I think, again, this makes it easier for the end user.

I agree 100% here. If the 3 antennas can be switched at runtime, it is a perfect candidate for an Antenna selection setting, as it exists for the RSP2. At the driver level, calling setAntenna API could indeed also be used to switch to the appropriate tuner if necessary, hiding all the complexity behind the SoapySDR API.

fventuri commented 4 years ago

Thanks for the very useful feedback SDRplay and vsonnier.

I just implemented all your recommendations to the SoapySDRPlay driver (branch 'pseudo_devices_by_RSPduo_mode' - https://github.com/fventuri/SoapySDRPlay/tree/pseudo_devices_by_RSPduo_mode).

A couple of notes:

I just ran a couple of tests with CubicSDR (single user and master/slave case), and it seems to work here; give it a try and let me know how it goes.

Franco

nmaster2042 commented 4 years ago

Happy new year to all !

I made some tests on your last pseudo_devices_by_RSPduo_mode branch Franco.

It's working for most, I noticed 2 small things:

In single tuner mode now, if I select Zero IF mode I can't use sample rate more than 2 Mhz. It's only while starting because during a SDR session in CubicSDR I can actually change and select other sample rate directly in CubicSDR menu (not in device selection dialog box).

So in Cubic it's not an issue but it may be for other Apps using SoapySDR ?

Second thing is about gain control. When I disable AGC I get IFGR and RFGR. I can change RFGR value is changed and it modify IFGR value.

If I change IFGR it doesn't stay at the selected level and cursor is going to another value. It's like it's reversed, I don't remember this was working like this on older soapy driver but I may be wrong.

fventuri commented 4 years ago

Happy new year to you too!

I looked into the issue about the Zero IF mode and I made a couple of changes to the SoapySDRPlay driver that should address it. I also noticed in CubicSDR these lines (https://github.com/cjcliffe/CubicSDR/blob/master/src/sdr/SDREnumerator.cpp#L281):

                for (size_t j = 0; j < settingsInfo.size(); j++) {
                    if (deviceArgs.find(settingsInfo[j].key) != deviceArgs.end()) {
                        settingsInfo[j].value = deviceArgs[settingsInfo[j].key];
                    }
                }

If my understanding is correct, this means that whatever CubicSDR finds in its config file ($HOME/.CubicSDR/config.xml) prevails over the values returned by the call to the function 'getSettinInfo()' from the SoapySDR driver - in other words, even after I changed the driver to return 'Zero-IF' for the argument 'if_mode' when in single tuner mode, I kept seeing 1,620kHz under the 'SoapySDR Device Options' header in CubicSDR; it wasn't until I manually edited the config file, found the entry for the RSPduo device in single user mode, and changed the value for 'if_mode' there, that I was able to see 'Zero-IF' under the 'SoapySDR Device Options' header in CubicSDR. Not sure if this is something that affects you too, but I thought you may want to know, just in case.

As per the question about gain control, I looked at the code for the SoapySDR driver (adapting the code for the various RSPduo modes didn't require any changes there, so what it does should be identical to the original driver), and I noticed the following:

During the holidays I also found out about another Linux SDR client: 'linhpsdr' by John Melton, G0ORX/N6LYT (his presentation at the SDR Academy 2018 is here: https://www.youtube.com/watch?v=GP0OgxfyCm0). Since it looks like linhpsdr can make use of the SoapySDR driver (https://github.com/g0orx/linhpsdr/blob/master/Makefile#L20), I thought it would be a good candidate to make sure the SoapySDRPlay driver changes I am making play nice with other clients. I made a few changes to the driver to also support linhpsdr (mainly I had the getHardwareKey() method return a good description of the RSPduo mode, not just the serial number), and I also made some changes to the linhpsdr source code itself to be able to support the 'sdrPlay' SoapySDR driver. I still have some issues to figure out with the sdrplay_api_Init() function and the value for gRdB (I am sure I am passing 0, however sdrplay_api_Init() fails complaining that gRdB is set to 59 and therefore outside its allowed range). I plan to put my changes to the linhpsdr source code out on github tonight or tomorrow in case you want to give it a try.

Franco

nmaster2042 commented 4 years ago

Thank you very much Franco, no more issue with Zero IF mode.

I'll get a try with linhpsdr I tried when soapysdr was added, but it was not a great success. I never managed to get it work with sdrplay.

I'll be happy to test your changes on it.