[Hamlib-commits] Hamlib -- Ham radio control libraries branch master updated. fa4a96e6a6c8e2ad4fcb0
Library to control radio transceivers and receivers
Brought to you by:
n0nb
From: n0nb <n0...@us...> - 2023-01-31 13:31:49
|
This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "Hamlib -- Ham radio control libraries". The branch, master has been updated via fa4a96e6a6c8e2ad4fcb016d6034ebfc91375a1c (commit) via 6fbb0986121b8865eaf2c1bcd36082dfeb4290f3 (commit) via 29ad027b6359fda2322215bcea24150b2954b1da (commit) via 33b8c1c88db6bb87968777f6cb5bbc3f6ae5a719 (commit) via 14016be81769a4d0c8bca813f493ff5845a97cd6 (commit) via 2cec9e6d5725e73637d658648180413e9fc15137 (commit) via 9bc5c4a883ce00c419e629700c4cb247dee74398 (commit) via 8a25a3be90108e351191fcbca1d4adce91859dd0 (commit) via ff64d86fd9b7b35c37fb89dbd7ecd5bb6ed6b033 (commit) via 5c36bef6c2e94a516202555507c85246b1667c1c (commit) via 41a8a50e65a6cc85ea01b2f5e64e729f1f3cba44 (commit) via 0177d85a5d9984932c261730e3865810c511283c (commit) via 1e353191bcb9f5eb7c8b33aa2c168ffb17f8aa41 (commit) via eb049ab92dad8f79516939672bb9e78d0056da5d (commit) from 8d1eacc9cb1aa6c18f44533c292022280f02b897 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit fa4a96e6a6c8e2ad4fcb016d6034ebfc91375a1c Author: Mike Black W9MDB <mdb...@ya...> Date: Mon Jan 30 07:54:43 2023 -0600 Add rigctlsync to doc/Makefile.am diff --git a/doc/Makefile.am b/doc/Makefile.am index 7cdda5c9..85a956fa 100644 --- a/doc/Makefile.am +++ b/doc/Makefile.am @@ -2,7 +2,7 @@ EXTRA_DIST = hamlib.cfg index.doxygen hamlib.css footer.html hamlib.png dist_man_MANS = man1/ampctl.1 man1/ampctld.1 \ man1/rigctl.1 man1/rigctld.1 man1/rigmem.1 man1/rigsmtr.1 \ - man1/rigswr.1 man1/rotctl.1 man1/rotctld.1 man1/rigctlcom.1 \ + man1/rigswr.1 man1/rotctl.1 man1/rotctld.1 man1/rigctlcom.1 man1/rigctlsync.1 \ man7/hamlib.7 man7/hamlib-primer.7 man7/hamlib-utilities.7 SRCDOCLST = \ commit 6fbb0986121b8865eaf2c1bcd36082dfeb4290f3 Author: Mike Black W9MDB <mdb...@ya...> Date: Sun Jan 29 15:50:27 2023 -0600 Fix segfault using python Hamlib.rig_parse_mode(None) Argument really needed to be 'None' but now prints out better error message https://github.com/Hamlib/Hamlib/issues/1227 diff --git a/Segfault-award b/Segfault-award index e09c6749..4bf3b4be 100644 --- a/Segfault-award +++ b/Segfault-award @@ -7,6 +7,8 @@ A developer cannot apply for HSHR for segfaults on his/her own code. Here is the list of the brave fellows: +* Christoph Berg DF7CB python with Hamlib.rig_parse(None) + * Saku Nyland OH1KH v4.5.1, 10/2022, rigctld.c using ptt_type=RTS * David Kjellquist WB5NHL, v1.1.3, 09/2002, kenwood/ts570.c diff --git a/src/misc.c b/src/misc.c index a82a2360..439f8382 100644 --- a/src/misc.c +++ b/src/misc.c @@ -496,7 +496,8 @@ static const struct { RIG_MODE_IQ, "IQ"}, { RIG_MODE_ISBUSB, "ISBUSB"}, { RIG_MODE_ISBLSB, "ISBLSB"}, - { RIG_MODE_NONE, "" }, + { RIG_MODE_NONE, "None" }, // so we can reutnr None when NONE is requested + { -1, "" }, // need to end list }; @@ -513,7 +514,7 @@ rmode_t HAMLIB_API rig_parse_mode(const char *s) rig_debug(RIG_DEBUG_VERBOSE, "%s called\n", __func__); - for (i = 0 ; mode_str[i].str[0] != '\0'; i++) + for (i = 0 ; (s != NULL) && (mode_str[i].str[0] != '\0'); i++) { if (!strcmp(s, mode_str[i].str)) { @@ -521,7 +522,7 @@ rmode_t HAMLIB_API rig_parse_mode(const char *s) } } - rig_debug(RIG_DEBUG_WARN, "%s: mode '%s' not found\n", __func__, s); + rig_debug(RIG_DEBUG_WARN, "%s: mode '%s' not found...returning RIG_MODE_NONE\n", __func__, s); return RIG_MODE_NONE; } @@ -1915,7 +1916,9 @@ vfo_t HAMLIB_API vfo_fixup(RIG *rig, vfo_t vfo, split_t split) if (VFO_HAS_MAIN_SUB_ONLY) { vfo = RIG_VFO_MAIN; } - if (VFO_HAS_MAIN_SUB_A_B_ONLY) { vfo = RIG_VFO_MAIN; } + //in this case we don't change it as either VFOA/B or Main/Sub makes a difference + //ID5100 for example has to turn on dual watch mode for Main/Sub + //if (VFO_HAS_MAIN_SUB_A_B_ONLY) { vfo = RIG_VFO_MAIN; } } else if (vfo == RIG_VFO_TX) { @@ -1963,7 +1966,7 @@ vfo_t HAMLIB_API vfo_fixup(RIG *rig, vfo_t vfo, split_t split) if (VFO_HAS_MAIN_SUB_ONLY) { vfo = RIG_VFO_SUB; } - if (VFO_HAS_MAIN_SUB_A_B_ONLY) { vfo = RIG_VFO_SUB; } + //if (VFO_HAS_MAIN_SUB_A_B_ONLY) { vfo = RIG_VFO_SUB; } rig_debug(RIG_DEBUG_TRACE, "%s: final vfo=%s\n", __func__, rig_strvfo(vfo)); } commit 29ad027b6359fda2322215bcea24150b2954b1da Author: Mike Black W9MDB <mdb...@ya...> Date: Sun Jan 29 12:46:48 2023 -0600 Update simicom9700.c diff --git a/simulators/simicom9700.c b/simulators/simicom9700.c index 25f8996b..5da7d709 100644 --- a/simulators/simicom9700.c +++ b/simulators/simicom9700.c @@ -10,6 +10,7 @@ #include <string.h> #include <unistd.h> #include <fcntl.h> +#include <errno.h> #include <sys/time.h> #include <hamlib/rig.h> #include "../src/misc.h" @@ -84,7 +85,7 @@ again: } } - printf("Error???\n"); + printf("Error??? c=x%02x\n", c); return 0; } @@ -234,6 +235,26 @@ void frameParse(int fd, unsigned char *frame, int len) { static int power_level = 0; + case 0x07: + case 0x08: + if (frame[6] != 0xfd) + { + frame[6] = 0xfb; + dumphex(frame,7); + n = write(fd, frame, 7); + printf("ACK x14 x08\n"); + } + else + { + to_bcd(&frame[6], (long long)128, 2); + frame[8] = 0xfb; + dumphex(frame,9); + n = write(fd, frame, 9); + printf("SEND x14 x08\n"); + } + + break; + case 0x0a: printf("Using power level %d\n", power_level); power_level += 10; @@ -298,6 +319,12 @@ void frameParse(int fd, unsigned char *frame, int len) n = write(fd, frame, 7); break; + case 0x19: // miscellaneous things + frame[5] = 0x94; + frame[6] = 0xfd; + n = write(fd, frame, 7); + break; + case 0x1a: // miscellaneous things switch (frame[5]) { @@ -474,7 +501,7 @@ void frameParse(int fd, unsigned char *frame, int len) default: printf("cmd 0x%02x unknown\n", frame[4]); } - if (n == 0) { printf("Write failed?\n"); } + if (n == 0) { printf("Write failed=%s\n", strerror(errno)); } // don't care about the rig type yet commit 33b8c1c88db6bb87968777f6cb5bbc3f6ae5a719 Author: Mike Black W9MDB <mdb...@ya...> Date: Sat Jan 28 12:48:04 2023 -0600 Update NEWS diff --git a/NEWS b/NEWS index 4bc8c95c..767da306 100644 --- a/NEWS +++ b/NEWS @@ -14,6 +14,7 @@ Version 5.x -- future Version 4.6 * 2023-11-XX -- Planned for Nov 2023 + * Fixes for M2 Rotors * Add rigctlsync utility to synchronize frequency from a rig to SDR# (or others) * Add SDR# rig for use with SDR#'s gpredict plugin -- can only get/set freq * Add Apex Shared Loop rotator -- unidirectional only so far commit 14016be81769a4d0c8bca813f493ff5845a97cd6 Author: Mike Black W9MDB <mdb...@ya...> Date: Sat Jan 28 12:42:14 2023 -0600 Some updates to fix rc2800 operations https://github.com/Hamlib/Hamlib/commit/be72027f9a3c54b2ac086d3aca456edd503d7ecf diff --git a/rotators/m2/rc2800.c b/rotators/m2/rc2800.c index ccea70ad..f615d679 100644 --- a/rotators/m2/rc2800.c +++ b/rotators/m2/rc2800.c @@ -199,15 +199,24 @@ transaction_write: /* then comes the answer */ memset(data, 0, data_len); - retval = read_string(&rs->rotport, (unsigned char *) data, data_len, CR, - strlen(CR), 0, 1); + retval = read_string(&rs->rotport, (unsigned char *) data, data_len, CR LF, + strlen(CR LF), 0, 1); // some models seem to echo -- so we'll check and read again if echoed - if (cmdstr && strcmp(data, cmdstr) == 0) + // skip last char in case the reply is terminated with LF instead of CR + if (cmdstr && strncmp(data, cmdstr, strlen(data) - 1) == 0) { memset(data, 0, data_len); - retval = read_string(&rs->rotport, (unsigned char *) data, data_len, CR, - strlen(CR), 0, 1); + retval = read_string(&rs->rotport, (unsigned char *) data, data_len, CR LF, + strlen(CR LF), 0, 1); + } + + // some models uses both CR + LF -- so we'll check and discard the additional one + if (strlen(data) == 1) + { + memset(data, 0, data_len); + retval = read_string(&rs->rotport, (unsigned char *) data, data_len, CR LF, + strlen(CR LF), 0, 1); } if (retval < 0) @@ -234,19 +243,18 @@ rc2800_rot_set_position(ROT *rot, azimuth_t az, elevation_t el) rig_debug(RIG_DEBUG_TRACE, "%s called: %f %f\n", __func__, az, el); - if (rot->caps->rot_model == ROT_MODEL_RC2800_EARLY_AZ) + if (rot->caps->rot_model == ROT_MODEL_RC2800) // new protocol + { + // does the new protocol use decimal points? + // we'll assume no for now + num_sprintf(cmdstr, "A%.0f"CR, az); + } + else // old protocol (both AZ and AZEL) { - // we only do azimuth and this is the old protocol // we have to switch modes and then send azimuth // an extra CR gives us a response to expect num_sprintf(cmdstr, "A\r%.0f\r\r", az); } - else - { - // does the new protocol use decimal points? - // we'll assume no for now - num_sprintf(cmdstr, "A%0f"CR, az); - } retval1 = rc2800_transaction(rot, cmdstr, NULL, 0); @@ -258,17 +266,16 @@ rc2800_rot_set_position(ROT *rot, azimuth_t az, elevation_t el) /* do not overwhelm the MCU? */ hl_usleep(200 * 1000); - if (rot->caps->rot_model == ROT_MODEL_RC2800_EARLY_AZEL) + if (rot->caps->rot_model == ROT_MODEL_RC2800) // new protocol + { + num_sprintf(cmdstr, "E%.0f"CR, el); + } + else // old protocol (both AZ and AZEL) { - // this is the old protocol // we have to switch modes and then send azimuth // an extra CR gives us a response to expect num_sprintf(cmdstr, "E\r%.0f\r\r", el); } - else - { - num_sprintf(cmdstr, "E%.0f"CR, el); - } retval2 = rc2800_transaction(rot, cmdstr, NULL, 0); @@ -311,36 +318,37 @@ rc2800_rot_get_position(ROT *rot, azimuth_t *az, elevation_t *el) } } - if (rot->caps->rot_model == ROT_MODEL_RC2800) + if (rot->caps->rot_type == ROT_TYPE_AZIMUTH) + { + rig_debug(RIG_DEBUG_TRACE, "%s: (az) = (%.1f)\n", + __func__, *az); + return RIG_OK; + } + + /* do not overwhelm the MCU? */ + hl_usleep(200 * 1000); + + retval = rc2800_transaction(rot, "E" CR, posbuf, sizeof(posbuf)); + + if (retval != RIG_OK || strlen(posbuf) < 5) { - retval = rc2800_transaction(rot, "E" CR, posbuf, sizeof(posbuf)); + return retval < 0 ? retval : -RIG_EPROTO; + } - if (retval != RIG_OK || strlen(posbuf) < 5) + if (rc2800_parse(posbuf, &device, &value) == RIG_OK) + { + if (device == 'E') { - return retval < 0 ? retval : -RIG_EPROTO; + *el = (elevation_t) value; } - - if (rc2800_parse(posbuf, &device, &value) == RIG_OK) + else { - if (device == 'E') - { - *el = (elevation_t) value; - } - else - { - return -RIG_EPROTO; - } + return -RIG_EPROTO; } - - rig_debug(RIG_DEBUG_TRACE, "%s: (az, el) = (%.1f, %.1f)\n", - __func__, *az, *el); - } - else - { - rig_debug(RIG_DEBUG_TRACE, "%s: (az) = (%.1f)\n", - __func__, *az); } + rig_debug(RIG_DEBUG_TRACE, "%s: (az, el) = (%.1f, %.1f)\n", + __func__, *az, *el); return RIG_OK; } @@ -400,7 +408,7 @@ const struct rot_caps rc2800_rot_caps = ROT_MODEL(ROT_MODEL_RC2800), .model_name = "RC2800", .mfg_name = "M2", - .version = "20210129", + .version = "20230123", .copyright = "LGPL", .status = RIG_STATUS_STABLE, .rot_type = ROT_TYPE_AZEL, @@ -432,7 +440,7 @@ const struct rot_caps rc2800az_rot_caps = ROT_MODEL(ROT_MODEL_RC2800_EARLY_AZ), .model_name = "RC2800_EARLY_AZ", .mfg_name = "M2", - .version = "20201130", + .version = "20230123", .copyright = "LGPL", .status = RIG_STATUS_STABLE, .rot_type = ROT_TYPE_AZIMUTH, @@ -463,7 +471,7 @@ const struct rot_caps rc2800azel_rot_caps = ROT_MODEL(ROT_MODEL_RC2800_EARLY_AZEL), .model_name = "RC2800_EARLY_AZEL", .mfg_name = "M2", - .version = "20201130", + .version = "20230123", .copyright = "LGPL", .status = RIG_STATUS_STABLE, .rot_type = ROT_TYPE_AZEL, commit 2cec9e6d5725e73637d658648180413e9fc15137 Author: Mike Black W9MDB <mdb...@ya...> Date: Fri Jan 27 23:49:47 2023 -0600 Update rigctlsync diff --git a/doc/man1/rigctlsync.1 b/doc/man1/rigctlsync.1 index 9a9f619e..369950ad 100644 --- a/doc/man1/rigctlsync.1 +++ b/doc/man1/rigctlsync.1 @@ -264,7 +264,7 @@ with FLRig as the Hamlib model .PP .in +4n .EX -.RB $ " rigctlsync -m 4 -M 9" +.RB $ " rigctlsync -m 4 -M 9 -R 192.168.1.1:4532" .EE .in . diff --git a/tests/rigctlsync.c b/tests/rigctlsync.c index 63aa7c3c..0499d2fb 100644 --- a/tests/rigctlsync.c +++ b/tests/rigctlsync.c @@ -211,7 +211,7 @@ int main(int argc, char *argv[]) int show_conf = 0; int dump_caps_opt = 0; - const char *rig_file = NULL, *rig_file2 = NULL; + const char *rig_file = NULL, *rig_file2 = "127.0.0.1:4532"; //const char **ptt_file = NULL, *dcd_file = NULL; //ptt_type_t ptt_type = RIG_PTT_NONE; //dcd_type_t dcd_type = RIG_DCD_NONE; @@ -220,7 +220,7 @@ int main(int argc, char *argv[]) char *civaddr = NULL; /* NULL means no need to set conf */ char conf_parms[MAXCONFLEN] = ""; - printf("rigctlcom Version 1.4\n"); + printf("rigctlsync Version 1.0\n"); if (argc < 3) { @@ -494,7 +494,7 @@ int main(int argc, char *argv[]) rig_set_debug(verbose); - rig_debug(RIG_DEBUG_VERBOSE, "%s, %s\n", "rigctlcom", hamlib_version2); + rig_debug(RIG_DEBUG_VERBOSE, "%s, %s\n", "rigctlsync", hamlib_version2); rig_debug(RIG_DEBUG_VERBOSE, "%s", "Report bugs to <ham...@li...>\n\n"); @@ -550,12 +550,7 @@ int main(int argc, char *argv[]) strncpy(my_rig->state.rigport.pathname, rig_file, HAMLIB_FILPATHLEN - 1); } - if (!rig_file2) - { - fprintf(stderr, "-R com port not provided\n"); - exit(2); - } - + fprintf(stderr, "rig to send frequency to: %s\n", rig_file2); strncpy(my_rig_sync->state.rigport.pathname, rig_file2, HAMLIB_FILPATHLEN - 1); #if 0 @@ -691,7 +686,7 @@ void usage() name); printf("Example: Sync freq from rigctld to SDR#\n"); - printf("\t%s -m 2 -M 9 127.0.0.1:4532\n\n", name); + printf("\t%s -m 2 -M 9 -R 127.0.0.1:4532\n\n", name); printf("See the %s.1 manual page for complete details.\n\n", name); printf( commit 9bc5c4a883ce00c419e629700c4cb247dee74398 Author: Mike Black W9MDB <mdb...@ya...> Date: Fri Jan 27 23:35:31 2023 -0600 Add rigctlsync utility to allow synchornizing a rig to SDR# diff --git a/NEWS b/NEWS index 429aca2a..4bc8c95c 100644 --- a/NEWS +++ b/NEWS @@ -14,6 +14,7 @@ Version 5.x -- future Version 4.6 * 2023-11-XX -- Planned for Nov 2023 + * Add rigctlsync utility to synchronize frequency from a rig to SDR# (or others) * Add SDR# rig for use with SDR#'s gpredict plugin -- can only get/set freq * Add Apex Shared Loop rotator -- unidirectional only so far * Add client_version to rigctld so client can report it's version for future use/compatility/alternatives diff --git a/doc/man1/rigctlsync.1 b/doc/man1/rigctlsync.1 new file mode 100644 index 00000000..9a9f619e --- /dev/null +++ b/doc/man1/rigctlsync.1 @@ -0,0 +1,329 @@ +.\" Hey, EMACS: -*- nroff -*- +.\" +.\" For layout and available macros, see man(7), man-pages(7), groff_man(7) +.\" Please adjust the date whenever revising the manpage. +.\" +.\" Note: Please keep this page in sync with the source, rigctlsync.c +.\" +.TH RIGCTLSYNC "1" "2023-01-27" "Hamlib" "Hamlib Utilities" +. +. +.SH NAME +. +rigctlsync \- synchronize a rig to SDR# (or other rig) +. +.SH SYNOPSIS +. +. +.SY rigctlsync +.OP \-hlLuV +.OP \-m id +.OP \-r device +.OP \-R device +.OP \-s baud +.OP \-S baud +.OP \-c id +.OP \-C parm=val +.OP \-B +.RB [ \-v [ \-Z ]] +.YS +. +.SH DESCRIPTION +Allows you to synchornize frequence from a rig to SDR#. +Best when used with rigctld, FlRig, or a multiport radio. +. +.PP +Please report bugs and provide feedback at the e-mail address given in the +.B BUGS +section below. Patches and code enhancements sent to the same address are +welcome. +. +. +.SH OPTIONS +. +This program follows the usual GNU command line syntax. Short options that +take an argument may have the value follow immediately or be separated by a +space. Long options starting with two dashes (\(oq\-\(cq) require an +\(oq=\(cq between the option and any argument. +. +.PP +Here is a summary of the supported options: +. +.TP +.BR \-m ", " \-\-model = \fIid\fP +Select radio model number. +.IP +See model list (use \(lqrigctlsync -l\(rq). +.IP +.BR Note : +.B rigctlsync +(or third party software using the C API) will use radio model 2 for +.B NET rigctl +(communicating with +.BR rigctld ). +. +.TP +.BR \-r ", " \-\-rig\-file = \fIdevice\fP +Use +.I device +as the file name of the port connected to the radio. +.IP +Often a serial port, but could be a USB to serial adapter. Typically +.IR /dev/ttyS0 ", " /dev/ttyS1 ", " /dev/ttyUSB0 , +etc. on Linux, +.IR COM1 ", " COM2 , +etc. on MS Windows. The BSD flavors and Mac OS/X have their own designations. +See your system's documentation. +.IP +The special string \(lquh\-rig\(rq may be given to enable micro-ham device +support. +. +.TP +.BR \-R ", " \-\-rig\-file2 = \fIdevice\fP +Use +.I device +as the file name of one of the virtual com ports -- your program will connect +to the other com port of the virtual pair. +. +.TP +.BR \-s ", " \-\-serial\-speed = \fIbaud\fP +Set serial speed to +.I baud +rate. +.IP +Uses maximum serial speed from radio backend capabilities (set by +.B -m +above) as the default. +. +.TP +.BR \-S ", " \-\-serial\-speed2 = \fIbaud\fP +Set serial speed to +.I baud +rate for virtual com port (see +.BR -R ). +. +.IP +Uses maximum serial speed from radio backend capabilities (set by +.B -m +above) as the default. +. +.TP +.BR \-c ", " \-\-civaddr = \fIid\fP +Use +.I id +as the CI-V address to communicate with the rig. +.IP +Only useful for Icom and some Ten-Tec rigs. +.IP +.BR Note : +The +.I id +is in decimal notation, unless prefixed by +.IR 0x , +in which case it is hexadecimal. +. +.TP +.BR \-L ", " \-\-show\-conf +List all config parameters for the radio defined with +.B \-m +above. +. +.TP +.BR \-C ", " \-\-set\-conf = \fIparm=val\fP [ \fI,parm=val\fP ] +Set radio configuration parameter(s), e.g. +.IR stop_bits=2 . +.IP +Use the +.B -L +option above for a list of configuration parameters for a given model number. +. +.TP +.BR \-u ", " \-\-dump\-caps +Dump capabilities for the radio defined with +.B -m +above and exit. +. +.TP +.BR \-l ", " \-\-list +List all model numbers defined in +.B Hamlib +and exit. +.IP +The list is sorted by model number. +.IP +.BR Note : +In Linux the list can be scrolled back using +.BR Shift-PageUp / Shift-PageDown , +or using the scrollbars of a virtual terminal in X or the cmd window in +Windows. The output can be piped to +.BR more (1) +or +.BR less (1), +e.g. \(lqrigctl -l | more\(rq. +. +.TP +.BR \-n ", " \-\-no\-restore\-ai +.B rigctl +restores the state of auto information (AI) on the controlled rig. +.IP +If this is not desired, for example if you are using +.B rigctl +to turn AI mode on or off, pass this option. +. +.TP +.BR \-B ", " \-\-mapa2b +Maps set_freq on VFOA to VFOB instead. +This allows using CW skimmer with the rig in split mode and clicking on a frequency in CW skimmer +will set VFOB to the transmit frequency. +. +.TP +.BR \-v ", " \-\-verbose +Set verbose mode, cumulative (see +.B DIAGNOSTICS +below). +. +.TP +.BR \-Z ", " \-\-debug\-time\-stamps +Enable time stamps for the debug messages. +.IP +Use only in combination with the +.B -v +option as it generates no output on its own. +. +.TP +.BR \-h ", " \-\-help +Show a summary of these options and exit. +. +.TP +.BR \-V ", " \-\-version +Show version of +.B rigctl +and exit. +. +.PP +.BR Note : +Some options may not be implemented by a given backend and will return an +error. This is most likely to occur with the +.B \-\-set\-conf +and +.B \-\-show\-conf +options. +. +. +.SH DIAGNOSTICS +. +The +.BR \-v , +.B \-\-verbose +option allows different levels of diagnostics +to be output to +.B stderr +and correspond to \-v for +.BR BUG , +\-vv for +.BR ERR , +\-vvv for +.BR WARN , +\-vvvv for +.BR VERBOSE , +or \-vvvvv for +.BR TRACE . +. +.PP +A given verbose level is useful for providing needed debugging information to +the email address below. For example, TRACE output shows all of the values +sent to and received from the radio which is very useful for radio backend +library development and may be requested by the developers. +. +. +.SH EXIT STATUS +.B rigctlsync +exits with: +. +.TP +.B 0 +if all operations completed normally; +. +.TP +.B 1 +if there was an invalid command line option or argument; +. +.TP +.B 2 +if an error was returned by +.BR Hamlib . +. +. +.SH EXAMPLE +. +Start +.B rigctlsync +with FLRig as the Hamlib model +.UE +. +.PP +.in +4n +.EX +.RB $ " rigctlsync -m 4 -M 9" +.EE +.in +. +.PP +The following diagram shows the communications flow that allows N1MM Logger+ +to communicate with a radio connected to Flrig: +. +.PP +.in +4n +.EE +.in +. +. +.SH BUGS +. +.PP +Report bugs to: +.IP +.nf +.MT hamlib\-de...@li... +Hamlib Developer mailing list +.ME +.fi +. +. +.SH COPYING +. +This file is part of Hamlib, a project to develop a library that simplifies +radio, rotator, and amplifier control functions for developers of software +primarily of interest to radio amateurs and those interested in radio +communications. +. +.PP +Copyright \(co 2000-2011 Stephane Fillod +.br +Copyright \(co 2000-2018 the Hamlib Group (various contributors) +.br +Copyright \(co 2010-2020 Nate Bargmann +.br +Copyright \(co 2019 Michael Black W9MDB +. +.PP +This is free software; see the file COPYING for copying conditions. There is +NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +. +. +.SH SEE ALSO +. +.BR rigctld (1), +.BR rigctl (1), +.BR socat (1), +.BR hamlib (7) +. +. +.SH COLOPHON +. +Links to the Hamlib Wiki, Git repository, release archives, and daily snapshot +archives are available via +. +.UR http://www.hamlib.org +hamlib.org +.UE . diff --git a/tests/Makefile.am b/tests/Makefile.am index a9c5d7b1..f80b7111 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -14,7 +14,7 @@ endif DISTCLEANFILES = rigctl.log rigctl.sum testbcd.log testbcd.sum -bin_PROGRAMS = rigctl rigctld rigmem rigsmtr rigswr rotctl rotctld rigctlcom rigctltcp ampctl ampctld $(TESTLIBUSB) +bin_PROGRAMS = rigctl rigctld rigmem rigsmtr rigswr rotctl rotctld rigctlcom rigctltcp rigctlsync ampctl ampctld $(TESTLIBUSB) #check_PROGRAMS = dumpmem testrig testrigopen testrigcaps testtrn testbcd testfreq listrigs testloc rig_bench testcache cachetest cachetest2 testcookie testgrid testsecurity check_PROGRAMS = dumpmem testrig testrigopen testrigcaps testtrn testbcd testfreq listrigs testloc rig_bench testcache cachetest cachetest2 testcookie testgrid hamlibmodels @@ -27,6 +27,7 @@ rigctl_SOURCES = rigctl.c $(RIGCOMMONSRC) rigctld_SOURCES = rigctld.c $(RIGCOMMONSRC) rigctlcom_SOURCES = rigctlcom.c $(RIGCOMMONSRC) rigctltcp_SOURCES = rigctltcp.c $(RIGCOMMONSRC) +rigctlsync_SOURCES = rigctlsync.c $(RIGCOMMONSRC) rotctl_SOURCES = rotctl.c $(ROTCOMMONSRC) rotctld_SOURCES = rotctld.c $(ROTCOMMONSRC) ampctl_SOURCES = ampctl.c $(AMPCOMMONSRC) @@ -52,6 +53,7 @@ ampctl_CFLAGS = $(AM_CFLAGS) $(PTHREAD_CFLAGS) -I$(top_builddir)/src ampctld_CFLAGS = $(AM_CFLAGS) $(PTHREAD_CFLAGS) -I$(top_builddir)/src rigctlcom_CFLAGS = $(AM_CFLAGS) $(PTHREAD_CFLAGS) -I$(top_builddir)/security rigctltcp_CFLAGS = $(AM_CFLAGS) $(PTHREAD_CFLAGS) -I$(top_builddir)/security +rigctlsync_CFLAGS = $(AM_CFLAGS) $(PTHREAD_CFLAGS) -I$(top_builddir)/security if HAVE_LIBUSB rigtestlibusb_CFLAGS = $(AM_CFLAGS) $(PTHREAD_CFLAGS) $(LIBUSB_CFLAGS) endif @@ -66,6 +68,7 @@ ampctld_LDADD = $(NET_LIBS) $(PTHREAD_LIBS) $(LDADD) $(READLINE_LIBS) rigmem_LDADD = $(LIBXML2_LIBS) $(LDADD) rigctlcom_LDADD = $(NET_LIBS) $(PTHREAD_LIBS) $(LDADD) $(READLINE_LIBS) rigctltcp_LDADD = $(NET_LIBS) $(PTHREAD_LIBS) $(LDADD) $(READLINE_LIBS) +rigctlsync_LDADD = $(NET_LIBS) $(PTHREAD_LIBS) $(LDADD) $(READLINE_LIBS) if HAVE_LIBUSB rigtestlibusb_LDADD = $(LIBUSB_LIBS) endif @@ -82,6 +85,7 @@ rotctld_LDFLAGS = $(WINEXELDFLAGS) ampctld_LDFLAGS = $(WINEXELDFLAGS) rigctlcom_LDFLAGS = $(WINEXELDFLAGS) rigctltcp_LDFLAGS = $(WINEXELDFLAGS) +rigctlsync_LDFLAGS = $(WINEXELDFLAGS) if HAVE_LIBUSB rigtestlibusb_LDFLAGS = $(WINEXELDFLAGS) endif diff --git a/tests/rigctlsync.c b/tests/rigctlsync.c new file mode 100644 index 00000000..63aa7c3c --- /dev/null +++ b/tests/rigctlsync.c @@ -0,0 +1,716 @@ +/* + * rigctlsync.c - (C) Stephane Fillod 2000-2011 + * (C) The Hamlib Group 2012 + * (C) Nate Bargmann 2008,2010,2011,2012,2013 + * (C) Michael Black W9MDB 2023 - derived from rigctlcom.c + * + * This program will synchronize frequency from one rig to another + * Implemented for AirSpy SDR# to keep freq synced with a real rig + * It simply polls the real rig and when freq changes sends it to SDR# (or whatever rig is hooked up) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + */ + +#include <hamlib/config.h> + +#ifdef WIN32 +#define WIN32_LEAN_AND_MEAN +// cppcheck-suppress * +#include <windows.h> +#endif + +// cppcheck-suppress * +#include <stdio.h> +// cppcheck-suppress * +#include <stdlib.h> +// cppcheck-suppress * +#include <string.h> +// cppcheck-suppress * +// cppcheck-suppress * +#include <ctype.h> +// cppcheck-suppress * +#include <errno.h> +// cppcheck-suppress * +#include <signal.h> + +// cppcheck-suppress * +#include <getopt.h> + +// cppcheck-suppress * +#include <sys/types.h> + +#ifdef HAVE_NETINET_IN_H +// cppcheck-suppress * +# include <netinet/in.h> +#endif + +#ifdef HAVE_ARPA_INET_H +// cppcheck-suppress * +# include <arpa/inet.h> +#endif + +#ifdef HAVE_SYS_SOCKET_H +// cppcheck-suppress * +# include <sys/socket.h> +#elif HAVE_WS2TCPIP_H +# include <ws2tcpip.h> +# include <fcntl.h> +# if defined(HAVE_WSPIAPI_H) +# include <wspiapi.h> +# endif +#endif + +#include <hamlib/rig.h> +#include "misc.h" +#include "iofunc.h" +#include "serial.h" +#include "sprintflst.h" +#include "rigctl_parse.h" +#include "sleep.h" + +/* + * Reminder: when adding long options, + * keep up to date SHORT_OPTIONS, usage()'s output and man page. thanks. + * NB: do NOT use -W since it's reserved by POSIX. + * TODO: add an option to read from a file + */ +#define SHORT_OPTIONS "B:m:M:r:R:p:d:P:D:s:S:c:C:lLuvhVZ" +static struct option long_options[] = +{ + {"mapa2b", 0, 0, 'B'}, + {"model", 1, 0, 'm'}, + {"rig-file", 1, 0, 'r'}, + {"rig-file2", 1, 0, 'R'}, + {"ptt-file", 1, 0, 'p'}, + {"dcd-file", 1, 0, 'd'}, + {"ptt-type", 1, 0, 'P'}, + {"dcd-type", 1, 0, 'D'}, + {"serial-speed", 1, 0, 's'}, + {"serial-speed2", 1, 0, 'S'}, + {"civaddr", 1, 0, 'c'}, + {"set-conf", 1, 0, 'C'}, + {"list", 0, 0, 'l'}, + {"show-conf", 0, 0, 'L'}, + {"dump-caps", 0, 0, 'u'}, + {"verbose", 0, 0, 'v'}, + {"help", 0, 0, 'h'}, + {"version", 0, 0, 'V'}, + {"debug-time-stamps", 0, 0, 'Z'}, + {0, 0, 0, 0} +}; + +void usage(); +static RIG *my_rig; /* handle to rig */ +static RIG +*my_rig_sync; /* rig the gets synchronized -- freq only for now */ +static int verbose; +/* CW Skimmer can only set VFOA */ +/* IC7300 for example can run VFOA on FM and VFOB on CW */ +/* So -A/--mapa2b changes set_freq on VFOA to VFOB */ +/* This allows working CW Skimmer in split mode and transmit on VFOB */ +static int mapa2b; /* maps set_freq on VFOA to VFOB instead */ + +#ifdef HAVE_SIG_ATOMIC_T +static sig_atomic_t volatile ctrl_c; +#else +static int volatile ctrl_c; +#endif + +#define MAXCONFLEN 1024 + +#if 0 +# ifdef WIN32 +static BOOL WINAPI CtrlHandler(DWORD fdwCtrlType) +{ + rig_debug(RIG_DEBUG_VERBOSE, "CtrlHandler called\n"); + + switch (fdwCtrlType) + { + case CTRL_C_EVENT: + case CTRL_CLOSE_EVENT: + ctrl_c = 1; + return TRUE; + + default: + return FALSE; + } +} +# else +static void signal_handler(int sig) +{ + switch (sig) + { + case SIGINT: + ctrl_c = 1; + break; + + default: + /* do nothing */ + break; + } +} +# endif /* ifdef WIN32 */ +#endif /* if 0 */ + +#if 0 +static void handle_error(enum rig_debug_level_e lvl, const char *msg) +{ + int e; +# ifdef __MINGW32__ + LPVOID lpMsgBuf; + + lpMsgBuf = (LPVOID)"Unknown error"; + e = WSAGetLastError(); + + if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER + | FORMAT_MESSAGE_FROM_SYSTEM + | FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, + e, + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + // Default language + (LPTSTR)&lpMsgBuf, + 0, + NULL)) + { + + rig_debug(lvl, "%s: Network error %d: %s\n", msg, e, lpMsgBuf); + LocalFree(lpMsgBuf); + } + else + { + rig_debug(lvl, "%s: Network error %d\n", msg, e); + } + +# else + e = errno; + rig_debug(lvl, "%s: Network error %d: %s\n", msg, e, strerror(e)); +# endif /* ifdef __MINGW32__ */ +} +#endif /* if 0 */ + + +int main(int argc, char *argv[]) +{ + rig_model_t my_model[] = { RIG_MODEL_DUMMY, RIG_MODEL_SDRSHARP }; + + int retcode; /* generic return code from functions */ + + int show_conf = 0; + int dump_caps_opt = 0; + const char *rig_file = NULL, *rig_file2 = NULL; + //const char **ptt_file = NULL, *dcd_file = NULL; + //ptt_type_t ptt_type = RIG_PTT_NONE; + //dcd_type_t dcd_type = RIG_DCD_NONE; + int serial_rate = 0; + int serial_rate2 = 0; /* virtual com port default speed */ + char *civaddr = NULL; /* NULL means no need to set conf */ + char conf_parms[MAXCONFLEN] = ""; + + printf("rigctlcom Version 1.4\n"); + + if (argc < 3) + { + usage(); + return 1; + } + + while (1) + { + int c; + int option_index = 0; + char dummy[2]; + + c = getopt_long(argc, + argv, + SHORT_OPTIONS, + long_options, + &option_index); + + if (c == -1) + { + break; + } + + switch (c) + { + case 'h': + usage(); + exit(0); + + case 'V': + version(); + exit(0); + + case 'B': + mapa2b = 1; + break; + + case 'm': + case 'M': + if (!optarg) + { + usage(); /* wrong arg count */ + exit(1); + } + + if (c == 'm') + { + my_model[0] = atoi(optarg); + } + else + { + my_model[1] = atoi(optarg); + } + + break; + + case 'r': + if (!optarg) + { + usage(); /* wrong arg count */ + exit(1); + } + + rig_file = optarg; + break; + + case 'R': + if (!optarg) + { + usage(); /* wrong arg count */ + exit(1); + } + + rig_file2 = optarg; + break; + + +#if 0 + + case 'p': + if (!optarg) + { + usage(); /* wrong arg count */ + exit(1); + } + + ptt_file = optarg; + break; +#endif + +#if 0 + + case 'd': + if (!optarg) + { + usage(); /* wrong arg count */ + exit(1); + } + + dcd_file = optarg; + break; +#endif + +#if 0 + + case 'P': + if (!optarg) + { + usage(); /* wrong arg count */ + exit(1); + } + + if (!strcmp(optarg, "RIG")) + { + ptt_type = RIG_PTT_RIG; + } + else if (!strcmp(optarg, "DTR")) + { + ptt_type = RIG_PTT_SERIAL_DTR; + } + else if (!strcmp(optarg, "RTS")) + { + ptt_type = RIG_PTT_SERIAL_RTS; + } + else if (!strcmp(optarg, "PARALLEL")) + { + ptt_type = RIG_PTT_PARALLEL; + } + else if (!strcmp(optarg, "CM108")) + { + ptt_type = RIG_PTT_CM108; + } + else if (!strcmp(optarg, "NONE")) + { + ptt_type = RIG_PTT_NONE; + } + else + { + ptt_type = atoi(optarg); + } + + break; +#endif + +#if 0 + + case 'D': + if (!optarg) + { + usage(); /* wrong arg count */ + exit(1); + } + + if (!strcmp(optarg, "RIG")) + { + dcd_type = RIG_DCD_RIG; + } + else if (!strcmp(optarg, "DSR")) + { + dcd_type = RIG_DCD_SERIAL_DSR; + } + else if (!strcmp(optarg, "CTS")) + { + dcd_type = RIG_DCD_SERIAL_CTS; + } + else if (!strcmp(optarg, "CD")) + { + dcd_type = RIG_DCD_SERIAL_CAR; + } + else if (!strcmp(optarg, "PARALLEL")) + { + dcd_type = RIG_DCD_PARALLEL; + } + else if (!strcmp(optarg, "NONE")) + { + dcd_type = RIG_DCD_NONE; + } + else + { + dcd_type = atoi(optarg); + } + + break; +#endif + + case 'c': + if (!optarg) + { + usage(); /* wrong arg count */ + exit(1); + } + + civaddr = optarg; + break; + + case 's': + if (!optarg) + { + usage(); /* wrong arg count */ + exit(1); + } + + if (sscanf(optarg, "%d%1s", &serial_rate, dummy) != 1) + { + fprintf(stderr, "Invalid baud rate of %s\n", optarg); + exit(1); + } + + break; + + case 'S': + if (!optarg) + { + usage(); /* wrong arg count */ + exit(1); + } + + serial_rate2 = atoi(optarg); + break; + + + case 'C': + if (!optarg) + { + usage(); /* wrong arg count */ + exit(1); + } + + if (*conf_parms != '\0') + { + strcat(conf_parms, ","); + } + + if (strlen(conf_parms) + strlen(optarg) > MAXCONFLEN - 24) + { + printf("Length of conf_parms exceeds internal maximum of %d\n", + MAXCONFLEN - 24); + return 1; + } + + strncat(conf_parms, optarg, MAXCONFLEN - strlen(conf_parms)); + break; + + case 'v': + verbose++; + break; + + case 'L': + show_conf++; + break; + + case 'l': + rig_set_debug(verbose); + list_models(); + exit(0); + + case 'u': + dump_caps_opt++; + break; + + case 'Z': + rig_set_debug_time_stamp(1); + break; + + default: + usage(); /* unknown option? */ + exit(1); + } + } + + rig_set_debug(verbose); + + rig_debug(RIG_DEBUG_VERBOSE, "%s, %s\n", "rigctlcom", hamlib_version2); + rig_debug(RIG_DEBUG_VERBOSE, "%s", + "Report bugs to <ham...@li...>\n\n"); + + if (argc == 1) + { + usage(); + exit(2); + } + + my_rig = rig_init(my_model[0]); + + if (!my_rig) + { + fprintf(stderr, + "Unknown rig num %d, or initialization error.\n", + my_model[0]); + + fprintf(stderr, "Please check with --list option.\n"); + exit(2); + } + + my_rig_sync = rig_init(my_model[1]); + + if (!my_rig_sync) + { + fprintf(stderr, + "Unknown rig num %d, or initialization error.\n", + my_model[1]); + + fprintf(stderr, "Please check with --list option.\n"); + exit(2); + } + +#if 0 + retcode = set_conf(my_rig, conf_parms); + + if (retcode != RIG_OK) + { + fprintf(stderr, "Config parameter error: %s\n", rigerror(retcode)); + exit(2); + } + +#endif + + if (my_model[0] > 5 && !rig_file) + { + fprintf(stderr, "-r rig com port not provided\n"); + exit(2); + } + + if (rig_file) + { + strncpy(my_rig->state.rigport.pathname, rig_file, HAMLIB_FILPATHLEN - 1); + } + + if (!rig_file2) + { + fprintf(stderr, "-R com port not provided\n"); + exit(2); + } + + strncpy(my_rig_sync->state.rigport.pathname, rig_file2, HAMLIB_FILPATHLEN - 1); + +#if 0 + + /* + * ex: RIG_PTT_PARALLEL and /dev/parport0 + */ + if (ptt_type != RIG_PTT_NONE) + { + my_rig->state.pttport.type.ptt = ptt_type; + } + + if (dcd_type != RIG_DCD_NONE) + { + my_rig->state.dcdport.type.dcd = dcd_type; + } + + if (ptt_file) + { + strncpy(my_rig->state.pttport.pathname, ptt_file, HAMLIB_FILPATHLEN - 1); + } + + if (dcd_file) + { + strncpy(my_rig->state.dcdport.pathname, dcd_file, HAMLIB_FILPATHLEN - 1); + } + +#endif + + /* FIXME: bound checking and port type == serial */ + if (serial_rate != 0) + { + my_rig->state.rigport.parm.serial.rate = serial_rate; + } + + if (serial_rate2 != 0) + { + my_rig_sync->state.rigport.parm.serial.rate = serial_rate2; + } + + + if (civaddr) + { + rig_set_conf(my_rig, rig_token_lookup(my_rig, "civaddr"), civaddr); + } + + /* + * print out conf parameters + */ + if (show_conf) + { + rig_token_foreach(my_rig, print_conf_list, (rig_ptr_t)my_rig); + } + + /* + * print out conf parameters, and exits immediately + * We may be interested only in only caps, and rig_open may fail. + */ + if (dump_caps_opt) + { + dumpcaps(my_rig, stdout); + rig_cleanup(my_rig); /* if you care about memory */ + exit(0); + } + + /* open and close rig connection to check early for issues */ + retcode = rig_open(my_rig); + + if (retcode != RIG_OK) + { + fprintf(stderr, "rig_open: error = %s \n", rigerror(retcode)); + exit(2); + } + + + retcode = rig_open(my_rig_sync); + + if (retcode != RIG_OK) + { + fprintf(stderr, "rig_open sync: error = %s \n", rigerror(retcode)); + exit(2); + } + + + if (verbose > 0) + { + printf("Opened rig model %d, '%s'\n", + my_rig->caps->rig_model, + my_rig->caps->model_name); + } + + rig_debug(RIG_DEBUG_VERBOSE, "Backend version: %s, Status: %s\n", + my_rig->caps->version, rig_strstatus(my_rig->caps->status)); + + /* + * main loop + */ + do + { + freq_t freq; + int retval = rig_get_freq(my_rig, RIG_VFO_CURR, &freq); + + if (retval != RIG_OK) + { + rig_debug(RIG_DEBUG_ERR, "%s: Error in rig_get_freq: %s\n", __func__, + rigerror(retval)); + } + + if (retval != RIG_OK) + { + rig_debug(RIG_DEBUG_ERR, "%s: Error in rig_set_freq: %s\n", __func__, + rigerror(retval)); + } + + retval = rig_set_freq(my_rig_sync, RIG_VFO_CURR, freq); + + hl_usleep(400 * 1000); // fairly fast to keep up + } + while (retcode == 0 && !ctrl_c); + + rig_close(my_rig); /* close port */ + rig_cleanup(my_rig); /* if you care about memory */ + + return 0; +} + +void usage() +{ + char *name = "rigctlsync"; + printf("Usage: %s -m rignumber -r comport -s baud -M rignumber -R comport [OPTIONS]...\n\n" + "Will copy frequency from -m rig to -M rig\n" + "e.g. will keep SDR# synchronized to a rig.\n\n", + name); + + printf("Example: Sync freq from rigctld to SDR#\n"); + printf("\t%s -m 2 -M 9 127.0.0.1:4532\n\n", name); + printf("See the %s.1 manual page for complete details.\n\n", name); + + printf( + " -m, --model=ID select radio model number. See model list (-l)\n" + " -r, --rig-file=DEVICE set device of the radio to operate on\n" + " -R, --rig-file2=DEVICE set device of the virtual com port to operate on\n" + " -s, --serial-speed=BAUD set serial speed of the serial port\n" + " -S, --serial-speed2=BAUD set serial speed of the virtual com port [default=115200]\n" + " -c, --civaddr=ID set CI-V address, decimal (for Icom rigs only)\n" + " -C, --set-conf=PARM=VAL set config parameters\n" + " -L, --show-conf list all config parameters\n" + " -l, --list list all model numbers and exit\n" + " -u, --dump-caps dump capabilities and exit\n" + " -v, --verbose set verbose mode, cumulative (-v to -vvvvv)\n" + " -Z, --debug-time-stamps enable time stamps for debug messages\n" + " -h, --help display this help and exit\n" + " -V, --version output version information and exit\n\n" + ); + + printf("\nReport bugs to <ham...@li...>.\n"); + +} commit 8a25a3be90108e351191fcbca1d4adce91859dd0 Author: Mike Black W9MDB <mdb...@ya...> Date: Fri Jan 27 17:46:46 2023 -0600 Fix sdrsharp model name to show gpredict diff --git a/rigs/dummy/sdrsharp.c b/rigs/dummy/sdrsharp.c index 7b61b0e7..2eb45cdf 100644 --- a/rigs/dummy/sdrsharp.c +++ b/rigs/dummy/sdrsharp.c @@ -525,7 +525,7 @@ static int sdrsharp_get_vfo(RIG *rig, vfo_t *vfo) const struct rig_caps sdrsharp_caps = { RIG_MODEL(RIG_MODEL_SDRSHARP), - .model_name = "SDR#", + .model_name = "SDR#/gpredict", .mfg_name = "Airspy", .version = "20230127.0", .copyright = "LGPL", commit ff64d86fd9b7b35c37fb89dbd7ecd5bb6ed6b033 Author: Mike Black W9MDB <mdb...@ya...> Date: Fri Jan 27 17:44:08 2023 -0600 Fix sdrsharp manufacturer name diff --git a/rigs/dummy/sdrsharp.c b/rigs/dummy/sdrsharp.c index e8b5dace..7b61b0e7 100644 --- a/rigs/dummy/sdrsharp.c +++ b/rigs/dummy/sdrsharp.c @@ -526,7 +526,7 @@ const struct rig_caps sdrsharp_caps = { RIG_MODEL(RIG_MODEL_SDRSHARP), .model_name = "SDR#", - .mfg_name = "Hamlib", + .mfg_name = "Airspy", .version = "20230127.0", .copyright = "LGPL", .status = RIG_STATUS_STABLE, commit 5c36bef6c2e94a516202555507c85246b1667c1c Author: Mike Black W9MDB <mdb...@ya...> Date: Fri Jan 27 17:39:14 2023 -0600 Fix compile warning in sdrsharp.c diff --git a/rigs/dummy/sdrsharp.c b/rigs/dummy/sdrsharp.c index 0f95cdce..e8b5dace 100644 --- a/rigs/dummy/sdrsharp.c +++ b/rigs/dummy/sdrsharp.c @@ -39,8 +39,8 @@ #define FALSE 0 -#define MAXCMDLEN 8192 -#define MAXXMLLEN 8192 +#define MAXCMDLEN 128 +#define MAXXMLLEN 128 #define MAXARGLEN 128 #define MAXBANDWIDTHLEN 4096 commit 41a8a50e65a6cc85ea01b2f5e64e729f1f3cba44 Author: Mike Black W9MDB <mdb...@ya...> Date: Fri Jan 27 17:31:24 2023 -0600 Add SDR# rig for use with SDR#'s gpredict pluigin -- can only get/set freq diff --git a/NEWS b/NEWS index 8662ce99..429aca2a 100644 --- a/NEWS +++ b/NEWS @@ -14,6 +14,7 @@ Version 5.x -- future Version 4.6 * 2023-11-XX -- Planned for Nov 2023 + * Add SDR# rig for use with SDR#'s gpredict plugin -- can only get/set freq * Add Apex Shared Loop rotator -- unidirectional only so far * Add client_version to rigctld so client can report it's version for future use/compatility/alternatives * Add --set-conf=tuner_control_pathname=hamlib_tuner_control (default) diff --git a/include/hamlib/riglist.h b/include/hamlib/riglist.h index 6d730595..3c641856 100644 --- a/include/hamlib/riglist.h +++ b/include/hamlib/riglist.h @@ -72,6 +72,7 @@ #define RIG_MODEL_DUMMY_NOVFO RIG_MAKE_MODEL(RIG_DUMMY, 6) #define RIG_MODEL_TCI1X RIG_MAKE_MODEL(RIG_DUMMY, 7) #define RIG_MODEL_ACLOG RIG_MAKE_MODEL(RIG_DUMMY, 8) +#define RIG_MODEL_SDRSHARP RIG_MAKE_MODEL(RIG_DUMMY, 9) /* * Yaesu diff --git a/rigs/dummy/Android.mk b/rigs/dummy/Android.mk index 84054465..4108a9db 100644 --- a/rigs/dummy/Android.mk +++ b/rigs/dummy/Android.mk @@ -2,7 +2,7 @@ LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) -LOCAL_SRC_FILES := dummy.c rot_dummy.c netrigctl.c netrotctl.c flrig.c trxmanager.c dummy_common.c +LOCAL_SRC_FILES := dummy.c rot_dummy.c netrigctl.c netrotctl.c flrig.c trxmanager.c dummy_common.c sdrsharp.c LOCAL_MODULE := dummy LOCAL_CFLAGS := diff --git a/rigs/dummy/Makefile.am b/rigs/dummy/Makefile.am index 5a419d3f..f763ee87 100644 --- a/rigs/dummy/Makefile.am +++ b/rigs/dummy/Makefile.am @@ -1,4 +1,4 @@ -DUMMYSRC = dummy_common.c dummy_common.h dummy.c dummy.h rot_dummy.c rot_dummy.h netrigctl.c netrotctl.c flrig.c flrig.h trxmanager.c trxmanager.h amp_dummy.c amp_dummy.h netampctl.c tci1x.c aclog.c +DUMMYSRC = dummy_common.c dummy_common.h dummy.c dummy.h rot_dummy.c rot_dummy.h netrigctl.c netrotctl.c flrig.c flrig.h trxmanager.c trxmanager.h amp_dummy.c amp_dummy.h netampctl.c tci1x.c aclog.c sdrsharp.c noinst_LTLIBRARIES = libhamlib-dummy.la libhamlib_dummy_la_SOURCES = $(DUMMYSRC) diff --git a/rigs/dummy/dummy.c b/rigs/dummy/dummy.c index c9539053..d3f7f63b 100644 --- a/rigs/dummy/dummy.c +++ b/rigs/dummy/dummy.c @@ -2676,6 +2676,7 @@ DECLARE_INITRIG_BACKEND(dummy) rig_register(&trxmanager_caps); rig_register(&dummy_no_vfo_caps); rig_register(&aclog_caps); + rig_register(&sdrsharp_caps); // rig_register(&tci1x_caps); return RIG_OK; } diff --git a/rigs/dummy/dummy.h b/rigs/dummy/dummy.h index dc844a20..b800cfd5 100644 --- a/rigs/dummy/dummy.h +++ b/rigs/dummy/dummy.h @@ -46,6 +46,7 @@ extern const struct rig_caps flrig_caps; extern const struct rig_caps trxmanager_caps; extern const struct rig_caps tci1x_caps; extern const struct rig_caps aclog_caps; +extern const struct rig_caps sdrsharp_caps; int netrigctl_get_vfo_mode(RIG *); diff --git a/rigs/dummy/sdrsharp.c b/rigs/dummy/sdrsharp.c new file mode 100644 index 00000000..0f95cdce --- /dev/null +++ b/rigs/dummy/sdrsharp.c @@ -0,0 +1,573 @@ +/* +* Hamlib rigctld backend - works with SDR#'s gpredict plugin for example +* Copyright (c) 2023 by Michael Black W9MDB +* +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; either +* version 2.1 of the License, or (at your option) any later version. +* +* This library is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public +* License along with this library; if not, write to the Free Software +* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +* +*/ +#include <hamlib/config.h> + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include <hamlib/rig.h> +#include <serial.h> +#include <misc.h> +#include <token.h> +#include <register.h> +#include <network.h> + +#include "dummy_common.h" + +#define DEBUG 1 +#define DEBUG_TRACE DEBUG_VERBOSE +#define TRUE 1 +#define FALSE 0 + + +#define MAXCMDLEN 8192 +#define MAXXMLLEN 8192 +#define MAXARGLEN 128 +#define MAXBANDWIDTHLEN 4096 + +#define DEFAULTPATH "127.0.0.1:4532" + +#define SDRSHARP_VFOS (RIG_VFO_A) + +#define SDRSHARP_MODES (RIG_MODE_NONE) + +struct sdrsharp_priv_data +{ + vfo_t curr_vfo; + char bandwidths[MAXBANDWIDTHLEN]; /* pipe delimited set */ + int nbandwidths; + char info[8192]; + ptt_t ptt; + split_t split; + rmode_t curr_modeA; + rmode_t curr_modeB; + freq_t curr_freqA; + freq_t curr_freqB; + pbwidth_t curr_widthA; + pbwidth_t curr_widthB; + int has_get_modeA; /* True if this function is available */ + int has_get_bwA; /* True if this function is available */ + int has_set_bwA; /* True if this function is available */ + float powermeter_scale; /* So we can scale power meter to 0-1 */ + value_t parms[RIG_SETTING_MAX]; + struct ext_list *ext_parms; +}; + +/* +* check_vfo +* No assumptions +*/ +static int check_vfo(vfo_t vfo) +{ + switch (vfo) + { + case RIG_VFO_A: + break; + + case RIG_VFO_TX: + case RIG_VFO_B: + break; + + case RIG_VFO_CURR: + break; // will default to A in which_vfo + + default: + return (FALSE); + } + + return (TRUE); +} + +/* +* read_transaction +* Assumes rig!=NULL, xml!=NULL, xml_len>=MAXXMLLEN +*/ +static int read_transaction(RIG *rig, char *xml, int xml_len) +{ + int retval; + int retry; + char *delims; + char *terminator = "\n"; + struct rig_state *rs = &rig->state; + + ENTERFUNC; + + retry = 2; + delims = "\n"; + xml[0] = 0; + + do + { + char tmp_buf[MAXXMLLEN]; // plenty big for expected sdrsharp responses hopefully + + if (retry < 2) + { + rig_debug(RIG_DEBUG_WARN, "%s: retry needed? retry=%d\n", __func__, retry); + } + + int len = read_string(&rs->rigport, (unsigned char *) tmp_buf, sizeof(tmp_buf), + delims, + strlen(delims), 0, 1); + + if (len > 0) { retry = 3; } + + if (len <= 0) + { + rig_debug(RIG_DEBUG_ERR, "%s: read_string error=%d\n", __func__, len); + continue; + } + + if (strlen(xml) + strlen(tmp_buf) < xml_len - 1) + { + strncat(xml, tmp_buf, xml_len - 1); + } + else + { + rig_debug(RIG_DEBUG_ERR, + "%s: xml buffer overflow!!\nTrying to add len=%d\nTo len=%d\n", __func__, + (int)strlen(tmp_buf), (int)strlen(xml)); + RETURNFUNC(-RIG_EPROTO); + } + } + while (retry-- > 0 && strstr(xml, terminator) == NULL); + + if (retry == 0) + { + rig_debug(RIG_DEBUG_WARN, "%s: retry timeout\n", __func__); + RETURNFUNC(-RIG_ETIMEOUT); + } + + if (strstr(xml, terminator)) + { +// rig_debug(RIG_DEBUG_TRACE, "%s: got %s\n", __func__, terminator); + retval = RIG_OK; + } + else + { + rig_debug(RIG_DEBUG_VERBOSE, "%s: did not get %s\n", __func__, terminator); + retval = -(101 + RIG_EPROTO); + } + + RETURNFUNC(retval); +} + +/* +* write_transaction +* Assumes rig!=NULL, xml!=NULL, xml_len=total size of xml for response +*/ +static int write_transaction(RIG *rig, char *xml, int xml_len) +{ + + int try = rig->caps->retry; + + int retval = -RIG_EPROTO; + + struct rig_state *rs = &rig->state; + + ENTERFUNC; + + // This shouldn't ever happen...but just in case + // We need to avoid an empty write as rigctld replies with blank line + if (xml_len == 0) + { + rig_debug(RIG_DEBUG_ERR, "%s: len==0??\n", __func__); + RETURNFUNC(retval); + } + + // appears we can lose sync if we don't clear things out + // shouldn't be anything for us now anyways + rig_flush(&rig->state.rigport); + + while (try-- >= 0 && retval != RIG_OK) + { + retval = write_block(&rs->rigport, (unsigned char *) xml, strlen(xml)); + + if (retval < 0) + { + RETURNFUNC(-RIG_EIO); + } + } + + RETURNFUNC(retval); +} + +static int sdrsharp_transaction(RIG *rig, char *cmd, char *value, + int value_len) +{ + char xml[MAXXMLLEN]; + int retry = 3; + + ENTERFUNC; + ELAPSED1; + + set_transaction_active(rig); + + if (value) + { + value[0] = 0; + } + + do + { + int retval; + + if (retry != 3) + { + rig_debug(RIG_DEBUG_VERBOSE, "%s: cmd=%s, retry=%d\n", __func__, cmd, retry); + } + + retval = write_transaction(rig, cmd, strlen(cmd)); + + if (retval != RIG_OK) + { + rig_debug(RIG_DEBUG_ERR, "%s: write_transaction error=%d\n", __func__, retval); + + // if we get RIG_EIO the socket has probably disappeared + // so bubble up the error so port can re re-opened + if (retval == -RIG_EIO) { set_transaction_inactive(rig); RETURNFUNC(retval); } + + hl_usleep(50 * 1000); // 50ms sleep if error + } + + if (value) + { + read_transaction(rig, xml, sizeof(xml)); // this might time out -- that's OK + } + + if (value) { strncpy(value, xml, value_len); } + + } + while (((value && strlen(value) == 0)) + && retry--); // we'll do retries if needed + + if (value && strlen(value) == 0) + { + rig_debug(RIG_DEBUG_ERR, "%s: no value returned\n", __func__); + set_transaction_inactive(rig); RETURNFUNC(RIG_EPROTO); + } + + ELAPSED2; + set_transaction_inactive(rig); + RETURNFUNC(RIG_OK); +} + +/* +* sdrsharp_init +* Assumes rig!=NULL +*/ +static int sdrsharp_init(RIG *rig) +{ + struct sdrsharp_priv_data *priv; + + ENTERFUNC; + rig_debug(RIG_DEBUG_TRACE, "%s version %s\n", __func__, rig->caps->version); + + rig->state.priv = (struct sdrsharp_priv_data *)calloc(1, sizeof( + struct sdrsharp_priv_data)); + + if (!rig->state.priv) + { + RETURNFUNC(-RIG_ENOMEM); + } + + priv = rig->state.priv; + + memset(priv, 0, sizeof(struct sdrsharp_priv_data)); + memset(priv->parms, 0, RIG_SETTING_MAX * sizeof(value_t)); + + /* + * set arbitrary initial status + */ + rig->state.current_vfo = RIG_VFO_A; + priv->split = 0; + priv->ptt = 0; + priv->curr_modeA = -1; + priv->curr_modeB = -1; + priv->curr_widthA = -1; + priv->curr_widthB = -1; + + if (!rig->caps) + { + RETURNFUNC(-RIG_EINVAL); + } + + strncpy(rig->state.rigport.pathname, DEFAULTPATH, + sizeof(rig->state.rigport.pathname)); + + RETURNFUNC(RIG_OK); +} + +/* +* sdrsharp_get_freq +* Assumes rig!=NULL, rig->state.priv!=NULL, freq!=NULL +*/ +static int sdrsharp_get_freq(RIG *rig, vfo_t vfo, freq_t *freq) +{ + char value[MAXARGLEN]; + struct sdrsharp_priv_data *priv = (struct sdrsharp_priv_data *) rig->state.priv; + + ENTERFUNC; + rig_debug(RIG_DEBUG_TRACE, "%s: vfo=%s\n", __func__, + rig_strvfo(vfo)); + + + if (check_vfo(vfo) == FALSE) + { + rig_debug(RIG_DEBUG_ERR, "%s: unsupported VFO %s\n", + __func__, rig_strvfo(vfo)); + RETURNFUNC(-RIG_EINVAL); + } + + if (vfo == RIG_VFO_CURR) + { + vfo = rig->state.current_vfo; + rig_debug(RIG_DEBUG_TRACE, "%s: get_freq2 vfo=%s\n", + __func__, rig_strvfo(vfo)); + } + + char *cmd = "f\n"; + int retval; + + retval = sdrsharp_transaction(rig, cmd, value, sizeof(value)); + + if (retval != RIG_OK) + { + rig_debug(RIG_DEBUG_ERR, "%s: READBMF failed retval=%s\n", __func__, + rigerror(retval)); + RETURNFUNC(retval); + } + + *freq = 0; + + sscanf(value, "%lf", freq); + + if (*freq == 0) + { + rig_debug(RIG_DEBUG_ERR, "%s: freq==0??\nvalue=%s\n", __func__, + value); + RETURNFUNC(-RIG_EPROTO); + } + else + { + rig_debug(RIG_DEBUG_TRACE, "%s: freq=%.0f\n", __func__, *freq); + } + + if (vfo == RIG_VFO_A) + { + priv->curr_freqA = *freq; + } + else // future support in SDRSHARP maybe? + { + priv->curr_freqB = *freq; + } + + RETURNFUNC(RIG_OK); +} + +/* +* sdrsharp_open +* Assumes rig!=NULL, rig->state.priv!=NULL +*/ +static int sdrsharp_open(RIG *rig) +{ + int retval; + char value[MAXARGLEN]; + + ENTERFUNC; + + freq_t freq; + retval = sdrsharp_get_freq(rig, RIG_VFO_CURR, &freq); + + if (retval != RIG_OK) + { + rig_debug(RIG_DEBUG_ERR, "%s: sdrsharp_get_freq not working!!\n", __func__); + RETURNFUNC(RIG_EPROTO); + } + + rig->state.current_vfo = RIG_VFO_A; + rig_debug(RIG_DEBUG_TRACE, "%s: currvfo=%s value=%s\n", __func__, + rig_strvfo(rig->state.current_vfo), value); + + RETURNFUNC(retval); +} + +/* +* sdrsharp_close +* Assumes rig!=NULL +*/ +static int sdrsharp_close(RIG *rig) +{ + ENTERFUNC; + + RETURNFUNC(RIG_OK); +} + +/* +* sdrsharp_cleanup +* Assumes rig!=NULL, rig->state.priv!=NULL +*/ +static int sdrsharp_cleanup(RIG *rig) +{ + struct sdrsharp_priv_data *priv; + + rig_debug(RIG_DEBUG_TRACE, "%s\n", __func__); + + if (!rig) + { + RETURNFUNC2(-RIG_EINVAL); + } + + priv = (struct sdrsharp_priv_data *)rig->state.priv; + + free(priv->ext_parms); + free(rig->state.priv); + + rig->state.priv = NULL; + + // we really don't need to free this up as it's only done once + // was causing problem when cleanup was followed by rig_open + // model_sdrsharp was not getting refilled + // if we can figure out that one we can re-enable this +#if 0 + int i; + + for (i = 0; modeMap[i].mode_hamlib != 0; ++i) + { + if (modeMap[i].mode_sdrsharp) + { + ... [truncated message content] |