Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SoapyAudio hamlib control not working for Softrock and presumably other radios with USB control #16

Open
RDPowerz opened this issue Dec 10, 2020 · 3 comments

Comments

@RDPowerz
Copy link
Contributor

--------------------------------------------------------------------------------
Problem statement:

I tried to use SoapyAudio with Hamlib support enabled to control the
SoftRock Si570 AVR-USB radio.  I found that SoapyAudio forced me to
provide a serial rate even though USB devices don't have a settable
serial rate.  It seems SoapyAudio was coded presuming all devices are
controlled via serial ports, which may not be the case these days.

I found hamlib works when serial rate is set to zero for this radio. See
below for example of my trial and error efforts.  I found I had to make
small changes to SoapyAudio for its hamlib calls to work with a serial
rate of zero.  See below for code diffs.  

I am hopeful these changes enable all USB-controlled audio 'soundcard'
radios to work.  I improved the error message to help debug things when
they do not work.

Debug environment was Ubuntu 20.04, Hamlib 3.3, gqrx top of tree
(v2.14.1-7-ga98411f-dirty), SoapySDR info is shown below.  I did 
not test on anything but this environment with this radio. The scope
of the changes is limited to the hamlib portions of SoapyAudio so
they should not impact anything else.

--------------------------------------------------------------------------------
Initial build of SoapyAudio: Note use of 'cmake -DUSE_HAMLIB=ON ..'

user@host:~/code/sdr$ git clone https://github.com/pothosware/SoapyAudio
Cloning into 'SoapyAudio'...
remote: Enumerating objects: 165, done.
remote: Total 165 (delta 0), reused 0 (delta 0), pack-reused 165
Receiving objects: 100% (165/165), 194.88 KiB | 2.35 MiB/s, done.
Resolving deltas: 100% (80/80), done.
user@host:~/code/sdr$ cd SoapyAudio
user@host:~/code/sdr/SoapyAudio$ mkdir build; cd build
user@host:~/code/sdr/SoapyAudio/build$ cmake -DUSE_HAMLIB=ON ..
-- The CXX compiler identification is GNU 9.3.0
-- Check for working CXX compiler: /usr/bin/c++
-- Check for working CXX compiler: /usr/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 PkgConfig: /usr/bin/pkg-config (found version "0.29.1") 
-- Checking for module 'hamlib'
--   Found hamlib, version 3.3
-- Found hamlib 
-- Found hamlib: /usr/include  
-- Performing Test HAS_STD_CXX11
-- Performing Test HAS_STD_CXX11 - Success
-- Checking for module 'rtaudio'
--   Found rtaudio, version 5.0.0
-- Found RtAudio: /usr/lib/x86_64-linux-gnu/librtaudio.so (found version "5.0.0") 
-- Found Git: /usr/bin/git (found version "2.25.1") 
-- Module audioSupport configured with version: 0.1.1-2ae84e3
-- Configuring done
-- Generating done
-- Build files have been written to: ~/code/sdr/SoapyAudio/build
user@host:~/code/sdr/SoapyAudio/build$ (make && sudo make install && sudo ldconfig) |& tee make.log

--------------------------------------------------------------------------------
Finding SoapyAudio's device strings:

Reference: SoapyAudio/Settings.cpp

#ifdef USE_HAMLIB
    t_Rig = nullptr;
    rigThread = nullptr;
    rigModel = 0;
    rigFile = "";
    rigSerialRate = 0;
    
    if (args.count("rig") != 0 && args.at("rig") != "") {
        try {
            rigModel = std::stoi(args.at("rig"));
        } catch (const std::invalid_argument &) {
            throw std::runtime_error("rig is invalid.");
        }
        if (!args.count("rig_rate")) {
            throw std::runtime_error("rig_rate missing.");
        }
        try {
            rigSerialRate = std::stoi(args.at("rig_rate"));
        } catch (const std::invalid_argument &) {
            throw std::runtime_error("rig_rate is invalid.");
        }

        if (!args.count("rig_port")) {
            throw std::runtime_error("rig_port missing.");
        }
        rigFile = args.at("rig_port");
        checkRigThread();
    }
#endif

This shows that:
  - "rig" must be present and must be an integer
  - "rig_rate" must be present and must be an integer
  - "rig_port" must be present and is a file name

--------------------------------------------------------------------------------
Finding hamlib settings using rigctl

1) Find rig type

user@host:~/soapy-debug$ rigctl --l | grep Soft
  2509  SoftRock               Si570 AVR-USB           0.3             Beta

So Softrock is 2509.  Note all the 25xx radios use similar designs.

2) Find the radio's defaults: only one that is relevant is 'rig_pathname'

user@host:~/soapy-debug$ rigctl -m 2509 -L
...
rig_pathname: "Path name to the device file of the rig"
	Default: /dev/rig, Value: 
	String.
...
<CTRL-D>

At this point, try the following to get the rig to open.

Configure 'gqrx' to use the following device string (all one line):

device="default_input=True,default_output=False,device_id=0,
driver=audio,soapy=0,rig=2509,rig_rate=9600,rig_port=/dev/ttyS0

gives (in red):

[ERROR] Rig failed to init.

3) Try to get frequency using rig 2509, rig_port /dev/rig, rig_rate 9600 baud

user@host:~/soapy-debug$ rigctl -m 2509 -r /dev/rig -s 9600 f
rig_open: error = IO error 

4) Try lots of different common rig serial rates, the only one that works is 0

user@host:~/soapy-debug$ rigctl -m 2509 -r /dev/rig -s 0 f
7050099

5) Now we can set the frequency to 10.0 MHz and read it back

user@host:~/soapy-debug$ rigctl -m 2509 -r /dev/rig -s 0 F 10000000
user@host:~/soapy-debug$ rigctl -m 2509 -r /dev/rig -s 0 f
10000000

6) Start gqxr with device strings as below:

device="default_input=True,default_output=False,device_id=0,
driver=audio,soapy=0,rig=2509,rig_rate=0,rig_port=/dev/rig

7) Now gqrx starts and we receive WWV at 10.0 MHz even though the frequency 
displayed is wrong. Also, changing frequency does nothing, and we also see:

[ERROR] Rig failed to init.

8) Change code to support rig_rate=0 because rigctl shows that serial rate 0
is what works for USB controlled radios, diff below

--------------------------------------------------------------------------------
Code changes:

Notes:
  - Allow rig_rate (serialRate) to be 0 since this works for Softrock as
    shown via the rigctl command
  - When serialRate is 0 don't update the serial rate data structure, this
    seems to be union and writing it for USB radios causes the open call
    to fail 
  - Enhance the error handling for hamlib open and init calls
  - When rig open fails, show the settings made it into SoapyAudio along with 
    the hamlib error string
  - Eliminate unused 'status' variable so warnings go away

diff --git a/RigThread.cpp b/RigThread.cpp
index ac96cc2..cd3c03c 100644
--- a/RigThread.cpp
+++ b/RigThread.cpp
@@ -33,17 +33,28 @@ void RigThread::setup(rig_model_t rig_model, std::string rig_file, int serial_ra
 };
 
 void RigThread::run() {
-    int retcode, status;
+    int retcode;
 
     SoapySDR_log(SOAPY_SDR_DEBUG, "Rig thread starting.");    
 
     rig = rig_init(rigModel);
+    if (rig == NULL) {
+        SoapySDR_log(SOAPY_SDR_ERROR, "Rig failed to init.");
+        terminated.store(true);
+        return;
+    }
+
 	strncpy(rig->state.rigport.pathname, rigFile.c_str(), FILPATHLEN - 1);
-	rig->state.rigport.parm.serial.rate = serialRate;
+    if (serialRate > 0)  // bypass for rate 0 used for USB controlled radios
+	    rig->state.rigport.parm.serial.rate = serialRate;
+
 	retcode = rig_open(rig);
-    
     if (retcode != 0) {
-        SoapySDR_log(SOAPY_SDR_ERROR, "Rig failed to init.");
+        char s[BUFSIZ];
+        snprintf(s, BUFSIZ, "Rig failed to open, rig: %d rig_rate: %d "
+            "rig_port: %s error: %s.", 
+            rigModel, serialRate, rigFile.c_str(), rigerror(retcode));
+        SoapySDR_log(SOAPY_SDR_ERROR, s);
         terminated.store(true);
         return;
     }
@@ -57,7 +68,7 @@ void RigThread::run() {
     while (!terminated.load()) {
         std::this_thread::sleep_for(std::chrono::milliseconds(150));
         if (freqChanged.load()) {
-            status = rig_get_freq(rig, RIG_VFO_CURR, &freq);
+            rig_get_freq(rig, RIG_VFO_CURR, &freq);
             if (freq != newFreq) {
                 freq = newFreq;
                 rig_set_freq(rig, RIG_VFO_CURR, freq);
@@ -66,7 +77,7 @@ void RigThread::run() {
             
             freqChanged.store(false);
         } else {
-            status = rig_get_freq(rig, RIG_VFO_CURR, &freq);
+            rig_get_freq(rig, RIG_VFO_CURR, &freq);
         }
         
         SoapySDR_logf(SOAPY_SDR_DEBUG, "Rig Freq: %f", freq);
@@ -98,4 +109,4 @@ void RigThread::terminate() {
 bool RigThread::isTerminated() {
     return terminated.load();
 }
-#endif
\ No newline at end of file
+#endif
diff --git a/Settings.cpp b/Settings.cpp
index 172e5e4..10e0074 100644
--- a/Settings.cpp
+++ b/Settings.cpp
@@ -584,7 +584,7 @@ chanSetup SoapyAudio::chanSetupStrToEnum(std::string chanOpt) {
 
 #ifdef USE_HAMLIB
 void SoapyAudio::checkRigThread() {    
-    if (!rigModel || !rigSerialRate || rigFile == "") {
+    if (!rigModel || (rigSerialRate < 0) || rigFile == "") {
         return;
     }
     if (!rigThread) {
@@ -600,4 +600,4 @@ void SoapyAudio::checkRigThread() {
     }
 }
 
-#endif
\ No newline at end of file
+#endif

--------------------------------------------------------------------------------
SoapySDR Info

user@host:~/soapy-debug$ SoapySDRUtil --info
######################################################
##     Soapy SDR -- the SDR abstraction library     ##
######################################################

Lib Version: v0.8.0-g926c86d9
API Version: v0.8.0
ABI Version: v0.8
Install root: /usr/local
Search path:  /usr/local/lib/SoapySDR/modules0.8
Module found: /usr/local/lib/SoapySDR/modules0.8/libHackRFSupport.so   (0.3.3-7d53087)
Module found: /usr/local/lib/SoapySDR/modules0.8/libairspyhfSupport.so (0.1.1-b6cfbf5)
Module found: /usr/local/lib/SoapySDR/modules0.8/libaudioSupport.so    (0.1.1-2ae84e3)
Module found: /usr/local/lib/SoapySDR/modules0.8/libremoteSupport.so   (0.6.0-c09b2f1)
Module found: /usr/local/lib/SoapySDR/modules0.8/librtlsdrSupport.so   (0.3.1-52cb5c0)
Available factories... airspyhf, audio, hackrf, remote, rtlsdr
Available converters...
 -  CF32 -> [CF32, CS16, CS8, CU16, CU8]
 -  CS16 -> [CF32, CS16, CS8, CU16, CU8]
 -  CS32 -> [CS32]
 -   CS8 -> [CF32, CS16, CS8, CU16, CU8]
 -  CU16 -> [CF32, CS16, CS8]
 -   CU8 -> [CF32, CS16, CS8]
 -   F32 -> [F32, S16, S8, U16, U8]
 -   S16 -> [F32, S16, S8, U16, U8]
 -   S32 -> [S32]
 -    S8 -> [F32, S16, S8, U16, U8]
 -   U16 -> [F32, S16, S8]
 -    U8 -> [F32, S16, S8]
@numinit
Copy link

numinit commented Dec 21, 2020

Do you think this patch will work for FLRig control? In that case, something like a rig_port of localhost:12345 needs to be used.

@RDPowerz
Copy link
Contributor Author

RDPowerz commented Dec 22, 2020 via email

@numinit
Copy link

numinit commented Dec 23, 2020

Ah, I was referring to hamlib's "FLRig" rig :-)

$ rigctl -l | grep FLRig
     4  FLRig                  FLRig                   1.4             Stable

Instead of taking a serial port path, hamlib takes a hostname and port for flrig. I have another soundcard radio with flrig-based serial control that is currently unsupported by hamlib, a Xiegu G90. I'll give it a shot and see if this improves my use case too.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants