From 87a83ffbb196fa9c16a779d7a6d79104ca7fbdf7 Mon Sep 17 00:00:00 2001
From: Michael Black W9MDB <mdblack98@yahoo.com>
Date: Wed, 27 May 2020 12:21:41 -0500
Subject: [PATCH] rigctld now works with rigctl in vfo mode
 https://github.com/Hamlib/Hamlib/issues/259 set_vfo_opt can now dynamically
 change vfo mode on rigctld So this example now works...does some non-vfo
 stuff then switches to vfo mode rigctl -m 2 F 14074000 V VFOB F 14076000 V
 VFOA f V VFOB f set_vfo_opt 1 f VFOA rigctl commands v,V and S have been
 changed to not require VFO arguments New API function rig_set_vfo_opt -- only
 implemented for Net rigctl as it doesn't apply to any other rigs

---
 doc/man1/rigctl.1    | 18 +++++++++++++++++
 doc/man1/rigctld.1   |  9 +++++++++
 dummy/netrigctl.c    | 40 +++++++++++++++++++++++++++++-------
 include/hamlib/rig.h |  4 ++++
 src/rig.c            | 19 ++++++++++++++++++
 tests/example.c      | 10 ++++++++-
 tests/rigctl.c       |  1 -
 tests/rigctl_parse.c | 48 ++++++++++++++++++++++++++++----------------
 8 files changed, 123 insertions(+), 26 deletions(-)

diff --git a/doc/man1/rigctl.1 b/doc/man1/rigctl.1
index 471d5ca1a..9a3cd6792 100644
--- a/doc/man1/rigctl.1
+++ b/doc/man1/rigctl.1
@@ -1114,6 +1114,24 @@ option above, will terminate each command string sent to the radio.  This
 character should not be a part of the input string.
 .
 .TP
+.BR chk_vfo
+Get
+.RI \(aq Status \(aq
+.IP
+Returns Status as 1 if vfo option is on and 0 if vfo option is off.
+This command reflects the -o switch for rigctl and ritctld and can be dynamically changed by 
+.B set_vfo_opt.
+.
+.TP
+.BR set_vfo_opt " \(aq" \fIStatus\fP \(aq
+Set
+.RI \(aq Status \(aq
+.IP
+Set vfo option Status 1=on or 0=off
+This is the same as using the -o switch for rigctl and ritctld. 
+This can be dyamically changed while running.
+.
+.TP
 .BR pause " \(aq" \fISeconds\fP \(aq
 Pause for the given whole (integer) number of
 .RI \(aq Seconds \(aq
diff --git a/doc/man1/rigctld.1 b/doc/man1/rigctld.1
index 5aca5923a..5ee440db4 100644
--- a/doc/man1/rigctld.1
+++ b/doc/man1/rigctld.1
@@ -1015,6 +1015,15 @@ commands.  VFO is one of the strings defined in
 .B set_vfo
 above.
 .
+.TP
+.BR set_vfo_opt " \(aq" \fIStatus\fP \(aq
+Set
+.RI \(aq Status \(aq
+.IP
+Set vfo option Status 1=on or 0=off
+This is the same as using the -o switch for rigctl and ritctld. 
+This can be dyamically changed while running.
+.
 .
 .SH PROTOCOL
 .
diff --git a/dummy/netrigctl.c b/dummy/netrigctl.c
index 1b454eecd..c957cad6f 100644
--- a/dummy/netrigctl.c
+++ b/dummy/netrigctl.c
@@ -121,9 +121,12 @@ static int netrigctl_vfostr(RIG *rig, char *vfostr, int len, vfo_t vfo)
     if (vfo == RIG_VFO_CURR)
     {
         vfo = priv->vfo_curr;
+        if (vfo == RIG_VFO_NONE) vfo = RIG_VFO_A;
     }
 
-    if (priv->rigctld_vfo_mode)
+    rig_debug(RIG_DEBUG_TRACE, "%s: vfo_opt=%d\n", __func__, rig->state.vfo_opt);
+
+    if (rig->state.vfo_opt)
     {
         snprintf(vfostr, len, " %s", vfo == RIG_VFO_A ? "VFOA" : "VFOB");
     }
@@ -189,15 +192,18 @@ static int netrigctl_open(RIG *rig)
     len = sprintf(cmd, "\\chk_vfo\n");
     ret = netrigctl_transaction(rig, cmd, len, buf);
 
-    if (ret == RIG_OK)
+    if (ret == 2)
     {
-        if (buf[0]) { sscanf(buf, "CHKVFO %d", &priv->rigctld_vfo_mode); }
+        if (buf[0]) { sscanf(buf, "%d", &priv->rigctld_vfo_mode); }
     }
     else if (ret < 0)
     {
         rig_debug(RIG_DEBUG_WARN, "%s: chk_vfo error: %s\n", __func__,
                   rigerror(ret));
     }
+    else {
+        rig_debug(RIG_DEBUG_ERR, "%s:  unknown return from netrigctl_transaction=%d\n", __func__, ret);
+    }
 
     rig_debug(RIG_DEBUG_VERBOSE, "%s: vfo_mode=%d\n", __func__,
               priv->rigctld_vfo_mode);
@@ -578,7 +584,7 @@ static int netrigctl_set_freq(RIG *rig, vfo_t vfo, freq_t freq)
 
     rig_debug(RIG_DEBUG_VERBOSE, "%s called\n", __func__);
 
-#if 0 // implement set_freq VFO later if it can be detected
+#if 1 // implement set_freq VFO later if it can be detected
     ret = netrigctl_vfostr(rig, vfostr, sizeof(vfostr), vfo);
 
     if (ret != RIG_OK) { return ret; }
@@ -589,6 +595,7 @@ static int netrigctl_set_freq(RIG *rig, vfo_t vfo, freq_t freq)
 #endif
 
     ret = netrigctl_transaction(rig, cmd, len, buf);
+    rig_debug(RIG_DEBUG_TRACE, "%s: cmd=%s\n", __func__, strtok(cmd,"\r\n"));
 
     if (ret > 0)
     {
@@ -606,9 +613,11 @@ static int netrigctl_get_freq(RIG *rig, vfo_t vfo, freq_t *freq)
     char cmd[CMD_MAX];
     char buf[BUF_MAX];
     char vfostr[6] = "";
+#if 0 // disable until we figure out if we can do this without breaking backwards compability
     char vfotmp[16];
+#endif
 
-    rig_debug(RIG_DEBUG_VERBOSE, "%s called\n", __func__);
+    rig_debug(RIG_DEBUG_VERBOSE, "%s called, vfo=%s, freq=%.0f\n", __func__, rig_strvfo(vfo), *freq);
 
     ret = netrigctl_vfostr(rig, vfostr, sizeof(vfostr), vfo);
 
@@ -618,6 +627,8 @@ static int netrigctl_get_freq(RIG *rig, vfo_t vfo, freq_t *freq)
 
     ret = netrigctl_transaction(rig, cmd, len, buf);
 
+    rig_debug(RIG_DEBUG_TRACE, "%s: cmd=%s, reply=%s\n", __func__, strtok(cmd,"\r\n"), buf);
+
     if (ret <= 0)
     {
         return (ret < 0) ? ret : -RIG_EPROTO;
@@ -719,9 +730,9 @@ static int netrigctl_set_vfo(RIG *rig, vfo_t vfo)
 
     rig_debug(RIG_DEBUG_VERBOSE, "%s called\n", __func__);
 
-    ret = netrigctl_vfostr(rig, vfostr, sizeof(vfostr), RIG_VFO_A);
+    //ret = netrigctl_vfostr(rig, vfostr, sizeof(vfostr), RIG_VFO_A);
 
-    if (ret != RIG_OK) { return ret; }
+    //if (ret != RIG_OK) { return ret; }
 
     len = sprintf(cmd, "V%s %s\n", vfostr, rig_strvfo(vfo));
     rig_debug(RIG_DEBUG_VERBOSE, "%s: cmd='%s'\n", __func__, cmd);
@@ -2168,7 +2179,21 @@ static int netrigctl_send_morse(RIG *rig, vfo_t vfo, const char *msg)
     }
 }
 
+static int netrigctl_set_vfo_opt(RIG *rig, int status)
+{
+    char cmdbuf[32];
+    char buf[BUF_MAX];
+    int ret;
 
+    sprintf(cmdbuf, "\\set_vfo_opt %d\n", status);
+    ret = netrigctl_transaction(rig, cmdbuf, strlen(cmdbuf), buf);
+    if (ret > 0)
+    {
+        return -RIG_EPROTO;
+    }
+    rig->state.vfo_opt = status;
+    return RIG_OK;
+}
 
 /*
  * Netrigctl rig capabilities.
@@ -2277,4 +2302,5 @@ struct rig_caps netrigctl_caps =
     .send_morse =  netrigctl_send_morse,
     .set_channel =    netrigctl_set_channel,
     .get_channel =    netrigctl_get_channel,
+    .set_vfo_opt = netrigctl_set_vfo_opt,
 };
diff --git a/include/hamlib/rig.h b/include/hamlib/rig.h
index 53d0594cc..5b99b04d5 100644
--- a/include/hamlib/rig.h
+++ b/include/hamlib/rig.h
@@ -1820,6 +1820,8 @@ struct rig_caps {
                           confval_cb_t parm_cb,
                           rig_ptr_t);
 
+    int (*set_vfo_opt)(RIG *rig, int status); // only for Net Rigctl device
+
     const char *clone_combo_set;    /*!< String describing key combination to enter load cloning mode */
     const char *clone_combo_get;    /*!< String describing key combination to enter save cloning mode */
     const char *macro_name;     /*!< Rig model macro name */
@@ -2722,6 +2724,8 @@ extern HAMLIB_EXPORT(void) rig_no_restore_ai();
 extern HAMLIB_EXPORT(int) rig_get_cache_timeout_ms(RIG *rig, cache_t selection);
 extern HAMLIB_EXPORT(int) rig_set_cache_timeout_ms(RIG *rig, cache_t selection, int ms);
 
+extern HAMLIB_EXPORT(int) rig_set_vfo_opt(RIG *rig, int status);
+
 // cppcheck-suppress *
 #include <unistd.h>
 extern HAMLIB_EXPORT(int) hl_usleep(useconds_t msec);
diff --git a/src/rig.c b/src/rig.c
index 51835e1f7..1e49c4249 100644
--- a/src/rig.c
+++ b/src/rig.c
@@ -4899,6 +4899,25 @@ const freq_range_t *HAMLIB_API rig_get_range(const freq_range_t *range_list,
     return NULL;
 }
 
+/**
+ * \brief set the vfo option for rigctld
+ * \param status 1=On, 0=Off
+ *
+ *  Returns RIG_OK or -RIG_EPROTO;
+ *
+ * \return RIG_OK or -RIG_EPROTO;
+ *
+ */
+int HAMLIB_API rig_set_vfo_opt(RIG *rig, int status)
+{
+    rig_debug(RIG_DEBUG_VERBOSE, "%s called\n", __func__);
+
+    if (rig->caps->set_vfo_opt == NULL)
+    {
+        return -RIG_ENAVAIL;
+    }
+    return rig->caps->set_vfo_opt(rig, status);
+}
 
 /**
  * \brief get general information from the radio
diff --git a/tests/example.c b/tests/example.c
index 314c0384d..faddababa 100644
--- a/tests/example.c
+++ b/tests/example.c
@@ -68,6 +68,13 @@ int main()
      * operation.)
      */
 
+    if (my_rig->caps->rig_model == RIG_MODEL_NETRIGCTL)
+    {
+        status = rig_set_vfo_opt(my_rig, 1);
+        if (status != RIG_OK) { printf("set_vfo_opt failed?? Err=%s\n", rigerror(status)); }
+    }
+    status = rig_get_freq(my_rig, RIG_VFO_CURR, &freq);
+
     /* Main VFO frequency */
     status = rig_get_freq(my_rig, RIG_VFO_CURR, &freq);
 
@@ -135,7 +142,8 @@ int main()
     printf("Closing and reopening rig\n");
     rig_close(my_rig);
 
-    while (1)
+    int loops = 1;
+    while (loops--)
     {
         retcode = rig_open(my_rig);
 
diff --git a/tests/rigctl.c b/tests/rigctl.c
index fc0b543b0..f1502593a 100644
--- a/tests/rigctl.c
+++ b/tests/rigctl.c
@@ -448,7 +448,6 @@ int main(int argc, char *argv[])
     }
 
     my_rig = rig_init(my_model);
-    my_rig->state.vfo_opt = 1;
 
     if (!my_rig)
     {
diff --git a/tests/rigctl_parse.c b/tests/rigctl_parse.c
index ab892e27d..7db717817 100644
--- a/tests/rigctl_parse.c
+++ b/tests/rigctl_parse.c
@@ -119,7 +119,7 @@ struct test_table
                        FILE *,
                        int,
                        int,
-                       int,
+                       int *,
                        char,
                        int,
                        char,
@@ -144,7 +144,7 @@ struct test_table
                                                     FILE *fin,          \
                                                     int interactive,    \
                                                     int prompt,         \
-                                                    int vfo_opt,       \
+                                                    int *vfo_opt,       \
                                                     char send_cmd_term, \
                                                     int ext_resp,       \
                                                     char resp_sep,      \
@@ -222,6 +222,7 @@ declare_proto_rig(get_powerstat);
 declare_proto_rig(send_dtmf);
 declare_proto_rig(recv_dtmf);
 declare_proto_rig(chk_vfo);
+declare_proto_rig(set_vfo_opt);
 declare_proto_rig(set_twiddle);
 declare_proto_rig(get_twiddle);
 declare_proto_rig(set_cache);
@@ -281,10 +282,10 @@ static struct test_table test_list[] =
     { 0x91, "get_ctcss_sql",    ACTION(get_ctcss_sql),  ARG_OUT, "CTCSS Sql" },
     { 0x92, "set_dcs_sql",      ACTION(set_dcs_sql),    ARG_IN, "DCS Sql" },
     { 0x93, "get_dcs_sql",      ACTION(get_dcs_sql),    ARG_OUT, "DCS Sql" },
-    // 
+    //
     //{ 'V',  "set_vfo",          ACTION(set_vfo),        ARG_IN  | ARG_NOVFO | ARG_OUT, "VFO" },
     { 'V',  "set_vfo",          ACTION(set_vfo),        ARG_IN  | ARG_NOVFO, "VFO" },
-    { 'v',  "get_vfo",          ACTION(get_vfo),        ARG_OUT, "VFO" },
+    { 'v',  "get_vfo",          ACTION(get_vfo),        ARG_NOVFO | ARG_OUT, "VFO" },
     { 'T',  "set_ptt",          ACTION(set_ptt),        ARG_IN, "PTT" },
     { 't',  "get_ptt",          ACTION(get_ptt),        ARG_OUT, "PTT" },
     { 'E',  "set_mem",          ACTION(set_mem),        ARG_IN, "Memory#" },
@@ -319,8 +320,7 @@ static struct test_table test_list[] =
     { '3',  "dump_conf",        ACTION(dump_conf),      ARG_NOVFO },
     { 0x8f, "dump_state",       ACTION(dump_state),     ARG_OUT | ARG_NOVFO },
     { 0xf0, "chk_vfo",          ACTION(chk_vfo),        ARG_NOVFO, "ChkVFO" },   /* rigctld only--check for VFO mode */
-    { '(',  "set_vfo_mode_on",  ACTION(chk_vfo),        ARG_NOVFO, "SetVFOMode 1=On 2=Off" },   /* rigctld only--check for VFO mode */
-    { ')',  "set_vfo_mode_off", ACTION(chk_vfo),        ARG_NOVFO, "SetVFOMode 1=On 2=Off" },   /* rigctld only--check for VFO mode */
+    { 0xf2, "set_vfo_opt",      ACTION(set_vfo_opt),    ARG_NOVFO|ARG_IN, "Status" },   /* turn vfo option on/off */
     { 0xf1, "halt",             ACTION(halt),           ARG_NOVFO },   /* rigctld only--halt the daemon */
     { 0x8c, "pause",            ACTION(pause),          ARG_IN, "Seconds" },
     { 0x00, "", NULL },
@@ -651,9 +651,10 @@ int rigctl_parse(RIG *my_rig, FILE *fin, FILE *fout, char *argv[], int argc,
                     return -1;
                 }
 
-                if (cmd != 0xa) {
-                rig_debug(RIG_DEBUG_TRACE, "%s: cmd=%c(%02x)\n", __func__,
-                          isprint(cmd) ? cmd : ' ', cmd);
+                if (cmd != 0xa)
+                {
+                    rig_debug(RIG_DEBUG_TRACE, "%s: cmd=%c(%02x)\n", __func__,
+                              isprint(cmd) ? cmd : ' ', cmd);
                 }
 
                 /* Extended response protocol requested with leading '+' on command
@@ -766,11 +767,8 @@ int rigctl_parse(RIG *my_rig, FILE *fin, FILE *fout, char *argv[], int argc,
                 return 0;
             }
 
-            if (cmd == '(') {rig_debug(RIG_DEBUG_ERR, "%s: vfo_opt on\n", __func__); *vfo_opt = 1; return 0;}
-
-            if (cmd == ')') {rig_debug(RIG_DEBUG_ERR, "%s: vfo_opt off\n", __func__); *vfo_opt = 0; return 0;}
-
             my_rig->state.vfo_opt = *vfo_opt;
+            rig_debug(RIG_DEBUG_ERR, "%s: vfo_opt=%d\n", __func__, *vfo_opt); 
 
             if (cmd == 'Q' || cmd == 'q')
             {
@@ -1617,9 +1615,9 @@ int rigctl_parse(RIG *my_rig, FILE *fin, FILE *fout, char *argv[], int argc,
         char vfo_str[MAXARGSZ + 2];
 
         *vfo_opt == 0 ? vfo_str[0] = '\0' : snprintf(vfo_str,
-                                      sizeof(vfo_str),
-                                      " %s",
-                                      rig_strvfo(vfo));
+                                     sizeof(vfo_str),
+                                     " %s",
+                                     rig_strvfo(vfo));
 
         p1 == NULL ? a1[0] = '\0' : snprintf(a1, sizeof(a1), " %s", p1);
         p2 == NULL ? a2[0] = '\0' : snprintf(a2, sizeof(a2), " %s", p2);
@@ -1641,7 +1639,7 @@ int rigctl_parse(RIG *my_rig, FILE *fin, FILE *fout, char *argv[], int argc,
                                         fin,
                                         interactive,
                                         prompt,
-                                        *vfo_opt,
+                                        vfo_opt,
                                         send_cmd_term,
                                         *ext_resp_ptr,
                                         *resp_sep_ptr,
@@ -1651,6 +1649,7 @@ int rigctl_parse(RIG *my_rig, FILE *fin, FILE *fout, char *argv[], int argc,
                                         p2 ? p2 : "",
                                         p3 ? p3 : "");
 
+    rig_debug(RIG_DEBUG_TRACE, "%s: vfo_opt=%d\n", __func__, *vfo_opt);
     if (retcode == RIG_EIO)
     {
         rig_debug(RIG_DEBUG_ERR, "%s: RIG_EIO?\n", __func__);
@@ -1973,6 +1972,7 @@ declare_proto_rig(get_freq)
     fprintf(fout, fmt, (int64_t)freq, resp_sep);
 
 #if 0 // this extra VFO being returned was confusing Log4OM
+
     if ((interactive && prompt) || (interactive && !prompt && ext_resp))
     {
         fprintf(fout, "%s: ", cmd->arg2);    /* i.e. "Frequency" */
@@ -2122,6 +2122,7 @@ declare_proto_rig(set_vfo)
     retval = rig_set_vfo(rig, vfo);
 
 #if 0 // see if we can make this dynamic
+
     if (retval == RIG_OK)
     {
         if ((interactive && prompt) || (interactive && !prompt && ext_resp))
@@ -2131,6 +2132,7 @@ declare_proto_rig(set_vfo)
 
         fprintf(fout, "%s%c", rig_strvfo(vfo), resp_sep);
     }
+
 #endif
 
     return retval;
@@ -4516,6 +4518,18 @@ declare_proto_rig(chk_vfo)
     return RIG_OK;
 }
 
+/* '(' -- turn vfo option on */
+declare_proto_rig(set_vfo_opt)
+{
+    int opt = 0;
+    char cmdbuf[16];
+    rig_debug(RIG_DEBUG_VERBOSE, "%s: called\n", __func__ );
+    CHKSCN1ARG(sscanf(arg1, "%d", &opt));
+    *vfo_opt = rig->state.vfo_opt = opt;
+    sprintf(cmdbuf, "( %d\n", opt);
+    write_block(&rig->state.rigport, cmdbuf , strlen(cmdbuf));
+    return RIG_OK;
+}
 
 /* '0xf1'--halt rigctld daemon */
 declare_proto_rig(halt)