[Hamlib-commits] Hamlib -- Ham radio control libraries branch master updated. 9f0bd7b310e7d21c85705
Library to control radio transceivers and receivers
Brought to you by:
n0nb
From: n0nb <n0...@us...> - 2023-01-03 01:57:55
|
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 9f0bd7b310e7d21c857052cb6249d6210caabd61 (commit) via 0b2f0873b036b339f5f65412cc17a464cc2ef3ba (commit) via c7b33ef0b3296a88ca387db1ac3634e19075dab1 (commit) via f68d45d99b5b08ac64d19a20d8aedfc27270de3e (commit) via fa7289995c29719739edd13d3e945248adc0905a (commit) via 582686505cbbc43f2013b7b8355d1f877671ef7e (commit) via 712564a2ae97343c5ed7001f90e79716939ed1d0 (commit) via 2fc1d157baa1454307665d759ee41b9cc9e1b8da (commit) via b1fcdea72d35a3648bacf202f8614d8ac33bc197 (commit) via 1ee37d0a563de967ec0855bcd7f96bfb394e4866 (commit) via c1662ce8865c7ff585f5085a1f8ecd6c3ac8b042 (commit) via 1bb1f545ebe7cf4f1aec069598e1f2545484f0ca (commit) via 64c566cd14b743c91563c986cd70c0a3be431b9d (commit) via b6654c78cba91a2818c9380710f1af91bde8f5ab (commit) via f67a53c41c0067d495e4a30c131df94301e43d47 (commit) via 04ccccb02d2819899a2981dea219318908529d4d (commit) via 7e81e8552a6fdc121e3427e4afb97bfa31f8619a (commit) via 1fd44dcef2c17db8923f1b41c84619ddf882d8fb (commit) via 2306ee4f1dd73f942f07c34d870a891e43377d46 (commit) via 606aea1552e173a793b206cb9ec2733ff59dc322 (commit) via cfc2e28c1968638bf20802ffa188f02cb4faeb94 (commit) via a75b274f6f4dd4ef5690581d0ecce653fbd29b1a (commit) via ab511cbea65c6764410ed5a623106175675d14d3 (commit) via 0450b36c67e59403983d1170058b8fe67c949d8e (commit) via bc6c14e43048179a99805bc434e139b5e253327e (commit) via c59b5383e9371c8d638f9f8d727f1ca612ad229e (commit) via 97ef9e5beae4e30ecfa26a09f2d1bfcbb61e2184 (commit) via 5db44be3ba1bbca5da66ed23b4bd6fdad3d7d054 (commit) via e70465a9c04c16c34a4ddc0e2b811ec12f9ece4b (commit) from b61550bf6b53c0cef885ed1443967a6c9aa2fb78 (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 9f0bd7b310e7d21c857052cb6249d6210caabd61 Author: Mike Black W9MDB <mdb...@ya...> Date: Mon Jan 2 11:38:27 2023 -0600 Add rigctltcp.c -- not working yet diff --git a/tests/rigctltcp.c b/tests/rigctltcp.c new file mode 100644 index 00000000..81080ef3 --- /dev/null +++ b/tests/rigctltcp.c @@ -0,0 +1,1563 @@ +/* + * rigctltcp.c - (C) Stephane Fillod 2000-2011 + * (C) Nate Bargmann 2008,2010,2011,2012,2013 + * (C) The Hamlib Group 2012-2022 + * + * This program test/control a radio using Hamlib. + * It takes commands from a tcp network connection. + * + * + * 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 +#include <windows.h> +#endif + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <ctype.h> +#include <errno.h> +#include <signal.h> + +#include <getopt.h> + +#include <sys/types.h> /* See NOTES */ + +#ifdef HAVE_NETINET_IN_H +# include <netinet/in.h> +#endif + +#ifdef HAVE_ARPA_INET_H +# include <arpa/inet.h> +#endif + +#ifdef HAVE_SYS_SOCKET_H +# include <sys/socket.h> +#elif HAVE_WS2TCPIP_H +# include <ws2tcpip.h> +# include <fcntl.h> +# if defined(HAVE_WSPIAPI_H) +# include <wspiapi.h> +# endif +#endif + +#ifdef HAVE_NETDB_H +# include <netdb.h> +#endif + +#ifdef HAVE_PTHREAD +# include <pthread.h> +#endif + +#include <hamlib/rig.h> +#include "misc.h" +#include "iofunc.h" +#include "serial.h" +#include "sprintflst.h" +#include "network.h" + +#include "rigctl_parse.h" + + +/* + * Reminder: when adding long options, + * keep up to date SHORT_OPTIONS, usage()'s output and man page. thanks. + * TODO: add an option to read from a file + */ +#define SHORT_OPTIONS "m:r:p:d:P:D:s:S:c:T:t:C:W:w:x:z:lLuovhVZMRA:n:" +static struct option long_options[] = +{ + {"model", 1, 0, 'm'}, + {"rig-file", 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'}, + {"separator", 1, 0, 'S'}, + {"civaddr", 1, 0, 'c'}, + {"listen-addr", 1, 0, 'T'}, + {"port", 1, 0, 't'}, + {"set-conf", 1, 0, 'C'}, + {"list", 0, 0, 'l'}, + {"show-conf", 0, 0, 'L'}, + {"dump-caps", 0, 0, 'u'}, + {"vfo", 0, 0, 'o'}, + {"verbose", 0, 0, 'v'}, + {"help", 0, 0, 'h'}, + {"version", 0, 0, 'V'}, + {"twiddle_timeout", 1, 0, 'W'}, + {"twiddle_rit", 1, 0, 'w'}, + {"uplink", 1, 0, 'x'}, + {"debug-time-stamps", 0, 0, 'Z'}, + {"multicast-addr", 1, 0, 'M'}, + {"multicast-port", 1, 0, 'n'}, + {"password", 1, 0, 'A'}, + {"rigctld-idle", 0, 0, 'R'}, + {0, 0, 0, 0} +}; + + +struct handle_data +{ + RIG *rig; + int sock; + struct sockaddr_storage cli_addr; + socklen_t clilen; + int vfo_mode; + int use_password; +}; + + +void *handle_socket(void *arg); +void usage(void); + + +#ifdef HAVE_PTHREAD +static unsigned client_count; +#endif + +static RIG *my_rig; /* handle to rig (instance) */ +static volatile int rig_opened = 0; +static int verbose; + +#ifdef HAVE_SIG_ATOMIC_T +static sig_atomic_t volatile ctrl_c; +#else +static int volatile ctrl_c; +#endif + +const char *portno = "4532"; +const char *src_addr = NULL; /* INADDR_ANY */ +const char *multicast_addr = "0.0.0.0"; +int multicast_port = 4532; +extern char rigctld_password[65]; +char resp_sep = '\n'; +extern int lock_mode; +extern powerstat_t rig_powerstat; +static int rigctld_idle = + 0; // if true then rig will close when no clients are connected + +#define MAXCONFLEN 1024 + + +void mutex_rigctld(int lock) +{ +#ifdef HAVE_PTHREAD + static pthread_mutex_t client_lock = PTHREAD_MUTEX_INITIALIZER; + + if (lock) + { + pthread_mutex_lock(&client_lock); + rig_debug(RIG_DEBUG_VERBOSE, "%s: client lock engaged\n", __func__); + } + else + { + rig_debug(RIG_DEBUG_VERBOSE, "%s: client lock disengaged\n", __func__); + pthread_mutex_unlock(&client_lock); + } + +#endif +} + +#ifdef WIN32 +static BOOL WINAPI CtrlHandler(DWORD fdwCtrlType) +{ + rig_debug(RIG_DEBUG_VERBOSE, "%s: called\n", __func__); + + 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 + +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, (char *)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 +} + +int main(int argc, char *argv[]) +{ + rig_model_t my_model = RIG_MODEL_DUMMY; + + int retcode; /* generic return code from functions */ + + int show_conf = 0; + int dump_caps_opt = 0; + const char *rig_file = NULL, *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; + char *civaddr = NULL; /* NULL means no need to set conf */ + char conf_parms[MAXCONFLEN] = ""; + + struct addrinfo hints, *result, *saved_result; + int sock_listen; + int reuseaddr = 1; + int twiddle_timeout = 0; + int twiddle_rit = 0; + int uplink = 0; + char host[NI_MAXHOST]; + char serv[NI_MAXSERV]; + char rigstartup[1024]; + char vbuf[1024]; +#if HAVE_SIGACTION + struct sigaction act; +#endif + +#ifdef HAVE_PTHREAD + pthread_t thread; + pthread_attr_t attr; +#endif + struct handle_data *arg; + int vfo_mode = 0; /* vfo_mode=0 means target VFO is current VFO */ + int i; + extern int is_rigctld; + + is_rigctld = 1; + + int err = setvbuf(stderr, vbuf, _IOFBF, sizeof(vbuf)); + + if (err) { rig_debug(RIG_DEBUG_ERR, "%s: setvbuf err=%s\n", __func__, strerror(err)); } + + + 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': + printf("rigctl %s\n", hamlib_version2); + exit(0); + + case 'R': + rigctld_idle = 1; + break; + + case 'A': + strncpy(rigctld_password, optarg, sizeof(rigctld_password) - 1); + //char *md5 = rig_make_m d5(rigctld_password); + char md5[HAMLIB_SECRET_LENGTH + 1]; + rig_password_generate_secret(rigctld_password, md5); + printf("Secret key: %s\n", md5); + rig_settings_save("sharedkey", md5, e_CHAR); + break; + + case 'm': + if (!optarg) + { + usage(); /* wrong arg count */ + exit(1); + } + + my_model = atoi(optarg); + break; + + case 'r': + if (!optarg) + { + usage(); /* wrong arg count */ + exit(1); + } + + rig_file = optarg; + break; + + case 'p': + if (!optarg) + { + usage(); /* wrong arg count */ + exit(1); + } + + ptt_file = optarg; + break; + + case 'd': + if (!optarg) + { + usage(); /* wrong arg count */ + exit(1); + } + + dcd_file = optarg; + break; + + 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, "GPIO")) + { + ptt_type = RIG_PTT_GPIO; + } + else if (!strcmp(optarg, "GPION")) + { + ptt_type = RIG_PTT_GPION; + } + else if (!strcmp(optarg, "NONE")) + { + ptt_type = RIG_PTT_NONE; + } + else + { + puts("Unrecognised PTT type, using NONE"); + ptt_type = RIG_PTT_NONE; + } + + break; + + 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, "CM108")) + { + dcd_type = RIG_DCD_CM108; + } + else if (!strcmp(optarg, "GPIO")) + { + dcd_type = RIG_DCD_GPIO; + } + else if (!strcmp(optarg, "GPION")) + { + dcd_type = RIG_DCD_GPION; + } + else if (!strcmp(optarg, "NONE")) + { + dcd_type = RIG_DCD_NONE; + } + else + { + puts("Unrecognised DCD type, using NONE"); + dcd_type = RIG_DCD_NONE; + } + + break; + + case 'c': + if (!optarg) + { + usage(); /* wrong arg count */ + exit(1); + } + + civaddr = optarg; + break; + + case 'S': + if (!optarg) + { + usage(); /* wrong arg count */ + exit(1); + } + + resp_sep = *optarg; + rig_debug(RIG_DEBUG_VERBOSE, "%s: resp_sep=%c\n", __func__, resp_sep); + 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 '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 't': + if (!optarg) + { + usage(); /* wrong arg count */ + exit(1); + } + + portno = optarg; + break; + + case 'T': + if (!optarg) + { + usage(); /* wrong arg count */ + exit(1); + } + + src_addr = optarg; + break; + + case 'o': + vfo_mode++; + //rig_debug(RIG_DEBUG_ERR, "%s: #0 vfo_mode=%d\n", __func__, vfo_mode); + break; + + case 'v': + verbose++; + break; + + case 'L': + show_conf++; + break; + + case 'l': + list_models(); + exit(0); + + case 'u': + dump_caps_opt++; + break; + + case 'W': + if (!optarg) + { + usage(); /* wrong arg count */ + exit(1); + } + + twiddle_timeout = atoi(optarg); + fprintf(stderr, + "twiddle_timeout is deprecated...use e.g. --set-conf=twiddle_timeout=5\n"); + break; + + case 'w': + if (!optarg) + { + usage(); /* wrong arg count */ + exit(1); + } + + twiddle_rit = atoi(optarg); + fprintf(stderr, + "twiddle_timeout is deprecated...use e.g. --set-conf=twiddle_timeout=5\n"); + break; + + + case 'x': + if (!optarg) + { + usage(); /* wrong arg count */ + exit(1); + } + + uplink = atoi(optarg); + break; + + + case 'Z': + rig_set_debug_time_stamp(1); + break; + + case 'M': + if (!optarg) + { + usage(); /* wrong arg count */ + exit(1); + } + + multicast_addr = optarg; + break; + + case 'n': + if (!optarg) + { + usage(); /* wrong arg count */ + exit(1); + } + + multicast_port = atoi(optarg); + + if (multicast_port == 0) + { + fprintf(stderr, "Invalid multicast port: %s\n", optarg); + exit(1); + } + + break; + + default: + usage(); /* unknown option? */ + exit(1); + } + } + +#if 0 + + if (!vfo_mode) + { + printf("Recommend using --vfo switch for rigctld if client supports it\n"); + printf("rigctl and netrigctl will automatically detect vfo mode\n"); + } + +#endif + + rig_set_debug(verbose); + + SNPRINTF(rigstartup, sizeof(rigstartup), "%s(%d) Startup:", __FILE__, __LINE__); + + for (i = 0; i < argc; ++i) { strcat(rigstartup, " "); strcat(rigstartup, argv[i]); } + + rig_debug(RIG_DEBUG_VERBOSE, "%s\n", rigstartup); + + rig_debug(RIG_DEBUG_VERBOSE, "rigctld %s\n", hamlib_version2); + rig_debug(RIG_DEBUG_VERBOSE, "%s", + "Report bugs to <ham...@li...>\n\n"); + rig_debug(RIG_DEBUG_VERBOSE, "Max# of rigctld client services=%d\n", + NI_MAXSERV); + + my_rig = rig_init(my_model); + + if (!my_rig) + { + fprintf(stderr, + "Unknown rig num %u, or initialization error.\n", + my_model); + + fprintf(stderr, "Please check with --list option.\n"); + exit(2); + } + + retcode = set_conf(my_rig, conf_parms); + + if (retcode != RIG_OK) + { + fprintf(stderr, "Config parameter error: %s\n", rigerror(retcode)); + exit(2); + } + + if (rig_file) + { + strncpy(my_rig->state.rigport.pathname, rig_file, HAMLIB_FILPATHLEN - 1); + } + + my_rig->state.twiddle_timeout = twiddle_timeout; + my_rig->state.twiddle_rit = twiddle_rit; + my_rig->state.uplink = uplink; + rig_debug(RIG_DEBUG_TRACE, "%s: twiddle=%d, uplink=%d, twiddle_rit=%d\n", + __func__, + my_rig->state.twiddle_timeout, my_rig->state.uplink, my_rig->state.twiddle_rit); + + /* + * ex: RIG_PTT_PARALLEL and /dev/parport0 + */ + if (ptt_type != RIG_PTT_NONE) + { + my_rig->state.pttport.type.ptt = ptt_type; + my_rig->state.pttport_deprecated.type.ptt = ptt_type; + // This causes segfault since backend rig_caps are const + // rigctld will use the rig->state version of this for clients + //my_rig->caps->ptt_type = ptt_type; + } + + if (dcd_type != RIG_DCD_NONE) + { + my_rig->state.dcdport.type.dcd = dcd_type; + my_rig->state.dcdport_deprecated.type.dcd = dcd_type; + } + + if (ptt_file) + { + strncpy(my_rig->state.pttport.pathname, ptt_file, HAMLIB_FILPATHLEN - 1); + strncpy(my_rig->state.pttport_deprecated.pathname, ptt_file, + HAMLIB_FILPATHLEN - 1); + } + + if (dcd_file) + { + strncpy(my_rig->state.dcdport.pathname, dcd_file, HAMLIB_FILPATHLEN - 1); + strncpy(my_rig->state.dcdport_deprecated.pathname, dcd_file, + HAMLIB_FILPATHLEN - 1); + } + + /* FIXME: bound checking and port type == serial */ + if (serial_rate != 0) + { + my_rig->state.rigport.parm.serial.rate = serial_rate; + my_rig->state.rigport_deprecated.parm.serial.rate = serial_rate; + } + + 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); + } + + /* attempt to open rig to check early for issues */ + retcode = rig_open(my_rig); + rig_opened = retcode == RIG_OK ? 1 : 0; + + if (retcode != RIG_OK) + { + fprintf(stderr, "rig_open: error = %s %s %s \n", rigerror(retcode), rig_file, + strerror(errno)); + // continue even if opening the rig fails, because it may be powered off + } + + if (verbose > RIG_DEBUG_ERR) + { + printf("Opened rig model %u, '%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)); + + // Normally we keep the rig open to speed up the 1st client connect + // But some rigs like the FT-736 have to lock the rig for CAT control + // So they need to release the rig when no clients are connected + if (rigctld_idle) + { + rig_close(my_rig); /* we will reopen for clients */ + + if (verbose > RIG_DEBUG_ERR) + { + printf("Closed rig model %d, '%s - will reopen for clients'\n", + my_rig->caps->rig_model, + my_rig->caps->model_name); + } + } + +#ifdef __MINGW32__ +# ifndef SO_OPENTYPE +# define SO_OPENTYPE 0x7008 +# endif +# ifndef SO_SYNCHRONOUS_NONALERT +# define SO_SYNCHRONOUS_NONALERT 0x20 +# endif +# ifndef INVALID_SOCKET +# define INVALID_SOCKET -1 +# endif + + WSADATA wsadata; + + if (WSAStartup(MAKEWORD(1, 1), &wsadata) == SOCKET_ERROR) + { + fprintf(stderr, "WSAStartup socket error\n"); + exit(1); + } + + { + int sockopt = SO_SYNCHRONOUS_NONALERT; + setsockopt(INVALID_SOCKET, SOL_SOCKET, SO_OPENTYPE, (char *)&sockopt, + sizeof(sockopt)); + } + +#endif + + /* + * Prepare listening socket + */ + memset(&hints, 0, sizeof(struct addrinfo)); + hints.ai_family = AF_UNSPEC; /* Allow IPv4 or IPv6 */ + hints.ai_socktype = SOCK_STREAM;/* TCP socket */ + hints.ai_flags = AI_PASSIVE; /* For wildcard IP address */ + hints.ai_protocol = 0; /* Any protocol */ + + retcode = getaddrinfo(src_addr, portno, &hints, &result); + + if (retcode == 0 && result->ai_family == AF_INET6) + { + rig_debug(RIG_DEBUG_TRACE, "%s: Using IPV6\n", __func__); + } + else if (retcode == 0) + { + rig_debug(RIG_DEBUG_TRACE, "%s: Using IPV4\n", __func__); + } + else + { + fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(retcode)); + exit(2); + } + + saved_result = result; + + enum multicast_item_e items = RIG_MULTICAST_POLL | RIG_MULTICAST_TRANSCEIVE | + RIG_MULTICAST_SPECTRUM; + retcode = network_multicast_publisher_start(my_rig, multicast_addr, + multicast_port, items); + + if (retcode != RIG_OK) + { + rig_debug(RIG_DEBUG_ERR, "%s: network_multicast_server failed: %s\n", __FILE__, + rigerror(retcode)); + // we will consider this non-fatal for now + } + + do + { + sock_listen = socket(result->ai_family, + result->ai_socktype, + result->ai_protocol); + + if (sock_listen < 0) + { + handle_error(RIG_DEBUG_ERR, "socket"); + freeaddrinfo(saved_result); /* No longer needed */ + exit(2); + } + + if (setsockopt(sock_listen, + SOL_SOCKET, + SO_REUSEADDR, + (char *)&reuseaddr, + sizeof(reuseaddr)) + < 0) + { + + handle_error(RIG_DEBUG_ERR, "setsockopt"); + freeaddrinfo(saved_result); /* No longer needed */ + exit(1); + } + +#ifdef IPV6_V6ONLY + + if (AF_INET6 == result->ai_family) + { + /* allow IPv4 mapped to IPv6 clients Windows and BSD default + this to 1 (i.e. disallowed) and we prefer it off */ + int sockopt = 0; + + if (setsockopt(sock_listen, + IPPROTO_IPV6, + IPV6_V6ONLY, + (char *)&sockopt, + sizeof(sockopt)) + < 0) + { + + handle_error(RIG_DEBUG_ERR, "setsockopt"); + freeaddrinfo(saved_result); /* No longer needed */ + exit(1); + } + } + +#endif + + if (0 == bind(sock_listen, result->ai_addr, result->ai_addrlen)) + { + break; + } + + handle_error(RIG_DEBUG_WARN, "binding failed (trying next interface)"); +#ifdef __MINGW32__ + closesocket(sock_listen); +#else + close(sock_listen); +#endif + } + while ((result = result->ai_next) != NULL); + + freeaddrinfo(saved_result); /* No longer needed */ + + if (NULL == result) + { + rig_debug(RIG_DEBUG_ERR, "%s: bind error - no available interface\n", __func__); + exit(1); + } + + if (listen(sock_listen, 4) < 0) + { + handle_error(RIG_DEBUG_ERR, "listening"); + exit(1); + } + +#if HAVE_SIGACTION + +#ifdef SIGPIPE + /* Ignore SIGPIPE as we will handle it at the write()/send() calls + that will consequently fail with EPIPE. All child threads will + inherit this disposition which is what we want. */ + memset(&act, 0, sizeof act); + act.sa_handler = SIG_IGN; + act.sa_flags = SA_RESTART; + + if (sigaction(SIGPIPE, &act, NULL)) + { + handle_error(RIG_DEBUG_ERR, "sigaction SIGPIPE"); + } + +#endif + +#ifdef SIGINT + memset(&act, 0, sizeof act); + act.sa_handler = signal_handler; + + if (sigaction(SIGINT, &act, NULL)) + { + handle_error(RIG_DEBUG_ERR, "sigaction SIGINT"); + } + +#endif +#elif defined (WIN32) + + if (!SetConsoleCtrlHandler(CtrlHandler, TRUE)) + { + handle_error(RIG_DEBUG_ERR, "SetConsoleCtrlHandler"); + } + +#elif HAVE_SIGNAL +#ifdef SIGPIPE + + if (SIG_ERR == signal(SIGPIPE, SIG_IGN)) + { + handle_error(RIG_DEBUG_ERR, "signal SIGPIPE"); + } + +#endif +#ifdef SIGINT + + if (SIG_ERR == signal(SIGINT, signal_handler)) + { + handle_error(RIG_DEBUG_ERR, "signal SIGINT"); + } + +#endif +#endif + + /* + * main loop accepting connections + */ + rig_debug(RIG_DEBUG_TRACE, "%s: rigctltcp listening on port %s\n", __func__, + portno); + + do + { + fd_set set; + struct timeval timeout; + + arg = calloc(1, sizeof(struct handle_data)); + + if (!arg) + { + rig_debug(RIG_DEBUG_ERR, "calloc: %s\n", strerror(errno)); + exit(1); + } + + if (rigctld_password[0] != 0) { arg->use_password = 1; } + + /* use select to allow for periodic checks for CTRL+C */ + FD_ZERO(&set); + FD_SET(sock_listen, &set); + timeout.tv_sec = 5; + timeout.tv_usec = 0; + retcode = select(sock_listen + 1, &set, NULL, NULL, &timeout); + + if (retcode == -1) + { + int errno_stored = errno; + rig_debug(RIG_DEBUG_ERR, "%s: select() failed: %s\n", __func__, + strerror(errno_stored)); + + if (ctrl_c) + { + rig_debug(RIG_DEBUG_VERBOSE, "%s: ctrl_c when retcode==-1\n", __func__); + break; + } + + if (errno == EINTR) + { + rig_debug(RIG_DEBUG_VERBOSE, "%s: ignoring interrupted system call\n", + __func__); + retcode = 0; + } + } + else if (retcode == 0) + { + if (ctrl_c) + { + rig_debug(RIG_DEBUG_VERBOSE, "%s: ctrl_c when retcode==0\n", __func__); + break; + } + } + else + { + arg->rig = my_rig; + arg->clilen = sizeof(arg->cli_addr); + arg->vfo_mode = vfo_mode; + arg->sock = accept(sock_listen, + (struct sockaddr *)&arg->cli_addr, + &arg->clilen); + + if (arg->sock < 0) + { + handle_error(RIG_DEBUG_ERR, "accept"); + break; + } + + if ((retcode = getnameinfo((struct sockaddr const *)&arg->cli_addr, + arg->clilen, + host, + sizeof(host), + serv, + sizeof(serv), + NI_NUMERICHOST | NI_NUMERICSERV)) + < 0) + { + rig_debug(RIG_DEBUG_WARN, + "Peer lookup error: %s", + gai_strerror(retcode)); + } + + rig_debug(RIG_DEBUG_VERBOSE, + "Connection opened from %s:%s\n", + host, + serv); + +#ifdef HAVE_PTHREAD + pthread_attr_init(&attr); + pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); + + retcode = pthread_create(&thread, &attr, handle_socket, arg); + + if (retcode != 0) + { + rig_debug(RIG_DEBUG_ERR, "pthread_create: %s\n", strerror(retcode)); + break; + } + +#else + handle_socket(arg); +#endif + } + } + while (retcode == 0 && !ctrl_c); + + rig_debug(RIG_DEBUG_VERBOSE, "%s: while loop done\n", __func__); + +#ifdef HAVE_PTHREAD + /* allow threads to finish current action */ + mutex_rigctld(1); + HAMLIB_TRACE; + + if (client_count) + { + rig_debug(RIG_DEBUG_WARN, "%u outstanding client(s)\n", client_count); + } + + rig_close(my_rig); + HAMLIB_TRACE; + mutex_rigctld(0); + HAMLIB_TRACE; +#else + rig_close(my_rig); /* close port */ +#endif + + HAMLIB_TRACE; + network_multicast_publisher_stop(my_rig); + + HAMLIB_TRACE; + rig_cleanup(my_rig); /* if you care about memory */ + +#ifdef __MINGW32__ + WSACleanup(); +#endif + + return 0; +} + +static FILE *get_fsockout(struct handle_data *handle_data_arg) +{ +#ifdef __MINGW32__ + int sock_osfhandle = _open_osfhandle(handle_data_arg->sock, _O_RDONLY); + return _fdopen(sock_osfhandle, "wb"); +#else + return fdopen(handle_data_arg->sock, "wb"); +#endif +} + +static FILE *get_fsockin(struct handle_data *handle_data_arg) +{ +#ifdef __MINGW32__ + int sock_osfhandle = _open_osfhandle(handle_data_arg->sock, _O_RDONLY); + + if (sock_osfhandle == -1) + { + rig_debug(RIG_DEBUG_ERR, "_open_osfhandle error: %s\n", strerror(errno)); + return NULL; + } + + return _fdopen(sock_osfhandle, "rb"); +#else + return fdopen(handle_data_arg->sock, "rb"); +#endif +} + +/* + * This is the function run by the threads + */ +void *handle_socket(void *arg) +{ + struct handle_data *handle_data_arg = (struct handle_data *)arg; + FILE *fsockin = NULL; + FILE *fsockout = NULL; + int retcode = RIG_OK; + char host[NI_MAXHOST]; + char serv[NI_MAXSERV]; + rig_powerstat = RIG_POWER_ON; // defaults to power on + + fsockin = get_fsockin(handle_data_arg); + + if (!fsockin) + { + rig_debug(RIG_DEBUG_ERR, "%s: fdopen(0x%d) in: %s\n", __func__, + handle_data_arg->sock, + strerror(errno)); + goto handle_exit; + } + + fsockout = get_fsockout(handle_data_arg); + + if (!fsockout) + { + rig_debug(RIG_DEBUG_ERR, "%s: fdopen out: %s\n", __func__, strerror(errno)); + fclose(fsockin); + fsockin = NULL; + + goto handle_exit; + } + +#ifdef HAVE_PTHREAD + mutex_rigctld(1); + + ++client_count; +#if 0 + + if (!client_count++) + { + retcode = rig_open(my_rig); + + if (RIG_OK == retcode && verbose > RIG_DEBUG_ERR) + { + printf("Opened rig model %d, '%s'\n", + my_rig->caps->rig_model, + my_rig->caps->model_name); + } + } + +#endif + + mutex_rigctld(0); +#else + mutext_rigctld(1); + retcode = rig_open(my_rig); + mutext_rigctld(1); + + if (RIG_OK == retcode && verbose > RIG_DEBUG_ERR) + { + printf("Opened rig model %d, '%s'\n", + my_rig->caps->rig_model, + my_rig->caps->model_name); + } + +#endif + + if (my_rig->caps->get_powerstat) + { + mutex_rigctld(1); + rig_get_powerstat(my_rig, &rig_powerstat); + mutex_rigctld(0); + my_rig->state.powerstat = rig_powerstat; + } + + do + { + mutex_rigctld(1); + + if (!rig_opened) + { + retcode = rig_open(my_rig); + rig_opened = retcode == RIG_OK ? 1 : 0; + rig_debug(RIG_DEBUG_ERR, "%s: rig_open reopened retcode=%d\n", __func__, + retcode); + } + + mutex_rigctld(0); + + int nbytes = -1; + + if (rig_opened) // only do this if rig is open + { + powerstat_t powerstat; + unsigned char cmd[64]; + unsigned char reply[64]; + unsigned char *term = (unsigned char *)";"; + rig_debug(RIG_DEBUG_TRACE, "%s: doing rigctl_parse vfo_mode=%d, secure=%d\n", + __func__, + handle_data_arg->vfo_mode, handle_data_arg->use_password); +#if 0 + retcode = rigctl_parse(handle_data_arg->rig, fsockin, fsockout, NULL, 0, + mutex_rigctld, + 1, 0, &handle_data_arg->vfo_mode, send_cmd_term, &ext_resp, &resp_sep, + handle_data_arg->use_password); +#else + memset(cmd, 0, sizeof(cmd)); + nbytes = -1; + + do + { + ++nbytes; + int val = fgetc(fsockin); + + if (val == EOF) { goto client_done; } + + rig_debug(RIG_DEBUG_ERR, "%s: val=0x%02x @ %d\n", __func__, val, nbytes); + + cmd[nbytes] = val; + } + while (nbytes < sizeof(cmd) - 1 && cmd[nbytes] != ';' && cmd[nbytes] != 0xfd); + + ++nbytes; + rig_debug(RIG_DEBUG_ERR, "%s: bytes=%d, cmd=%s\n", __func__, nbytes, cmd); + + if (cmd[nbytes - 1] == ';') + { + rig_debug(RIG_DEBUG_ERR, "%s: cmd kenwood=%s\n", __func__, cmd); + term[0] = ';'; + term[1] = 0; + } + else if (cmd[0] == 0xfe && cmd[1] == 0xfe) + { + rig_debug(RIG_DEBUG_ERR, "%s: cmd#2 icom=%s\n", __func__, cmd); + dump_hex(cmd, nbytes); + term[0] = 0xfd; + term[1] = 0; + } + else + { + rig_debug(RIG_DEBUG_ERR, "%s: unknown cmd:", __func__); + dump_hex(cmd, nbytes); + cmd[0] = 0; + } + + // This should work with Icom binary cmds any ASCII cmd with last char being standard terminator + // This means some of the 5-byte rigs won't be handled correctly -- to be fixed? +#if 1 + + if (cmd[0] != 0) + { + memset(reply, 0, sizeof(reply)); + rig_flush(&my_rig->state.rigport); + retcode = rig_send_raw(my_rig, cmd, nbytes, reply, sizeof(reply), + &cmd[nbytes - 1]); + + if (retcode < 0) + { + rig_debug(RIG_DEBUG_ERR, "%s: rig_send_raw error=%s\n", __func__, + rigerror(retcode)); + } + else + { + + rig_debug(RIG_DEBUG_VERBOSE, "%s: reply(%d bytes)='%s'\n", __func__, retcode, reply); + + fwrite(reply, retcode, 1, fsockout); + fflush(fsockout); + } + } + +#endif +#if 0 + + if (strncmp(cmd, "FA", 2) == 0) + { + char *s = "FA00014074000;"; + printf("%s\n", s); + fwrite(s, strlen(s), 1, fsockout); + fflush(fsockout); + } + else if (strncmp(cmd, "FB", 2) == 0) + { + char *s = "FB00014075000;"; + printf("%s\n", s); + fwrite(s, strlen(s), 1, fsockout); + fflush(fsockout); + } + else if (strncmp(cmd, "AG0", 2) == 0) + { + char *s = "AG0000;"; + printf("%s\n", s); + fwrite(s, strlen(s), 1, fsockout); + fflush(fsockout); + } + else if (strncmp(cmd, "IF", 2) == 0) + { + char *s = "IF000101310001000+0000000000020010000;"; + printf("%s\n", s); + fwrite(s, strlen(s), 1, fsockout); + fflush(fsockout); + } + +#endif + +#endif + + if (retcode != 0) { rig_debug(RIG_DEBUG_VERBOSE, "%s: rigctl_parse retcode=%d\n", __func__, retcode); } + + // update our power stat in case power gets turned off + if (retcode == -RIG_ETIMEOUT + && my_rig->caps->get_powerstat) // if we get a timeout we might be powered off + { + rig_get_powerstat(my_rig, &powerstat); + rig_powerstat = powerstat; + + if (powerstat == RIG_POWER_OFF) { retcode = -RIG_EPOWER; } + } + } + else + { + retcode = -RIG_EIO; + } + + // if we get a hard error we try to reopen the rig again + // this should cover short dropouts that can occur + if (retcode < 0 && !RIG_IS_SOFT_ERRCODE(-retcode)) + { + int retry = 3; + rig_debug(RIG_DEBUG_ERR, "%s: i/o error\n", __func__); + + do + { + mutex_rigctld(1); + retcode = rig_close(my_rig); + rig_opened = 0; + mutex_rigctld(0); + rig_debug(RIG_DEBUG_ERR, "%s: rig_close retcode=%d\n", __func__, retcode); + + hl_usleep(1000 * 1000); + + mutex_rigctld(1); + + if (!rig_opened) + { + retcode = rig_open(my_rig); + rig_opened = retcode == RIG_OK ? 1 : 0; + rig_debug(RIG_DEBUG_ERR, "%s: rig_open retcode=%d, opened=%d\n", __func__, + retcode, rig_opened); + } + + mutex_rigctld(0); + } + while (!ctrl_c && !rig_opened && retry-- > 0 && retcode != RIG_OK); + } + } + while (!ctrl_c && (retcode == RIG_OK || RIG_IS_SOFT_ERRCODE(-retcode))); + +client_done: + + if (rigctld_idle && client_count == 1) + { + rig_close(my_rig); + + if (verbose > RIG_DEBUG_ERR) { printf("Closed rig model %s. Will reopen for new clients\n", my_rig->caps->model_name); } + } + + +#ifdef HAVE_PTHREAD + --client_count; + + if (rigctld_idle && client_count > 0) { printf("%d client%s still connected so rig remains open\n", client_count, client_count > 1 ? "s" : ""); } + +#if 0 + mutex_rigctld(1); + + /* Release rig if there are no clients */ + if (!--client_count) + { + rig_close(my_rig); + + if (verbose > RIG_DEBUG_ERR) + { + printf("Closed rig model %d, '%s - no clients, will reopen for new clients'\n", + my_rig->caps->rig_model, + my_rig->caps->model_name); + } + } + + mutex_rigctld(0); +#endif +#else + rig_close(my_rig); + + if (verbose > RIG_DEBUG_ERR) + { + printf("Closed rig model %d, '%s - will reopen for new clients'\n", + my_rig->caps->rig_model, + my_rig->caps->model_name); + } + +#endif + + if ((retcode = getnameinfo((struct sockaddr const *)&handle_data_arg->cli_addr, + handle_data_arg->clilen, + host, + sizeof(host), + serv, + sizeof(serv), + NI_NUMERICHOST | NI_NUMERICSERV)) + < 0) + { + + rig_debug(RIG_DEBUG_WARN, "Peer lookup error: %s", gai_strerror(retcode)); + } + + rig_debug(RIG_DEBUG_VERBOSE, + "Connection closed from %s:%s\n", + host, + serv); + +handle_exit: + +// for MINGW we close the handle before fclose +#ifdef __MINGW32__ + retcode = closesocket(handle_data_arg->sock); + + if (retcode != 0) { rig_debug(RIG_DEBUG_ERR, "%s: fclose(fsockin) %s\n", __func__, strerror(retcode)); } + +#endif + + if (fsockin) { fclose(fsockin); } + + if (fsockout) { fclose(fsockout); } + +// for everybody else we close the handle after fclose +#ifndef __MINGW32__ + retcode = close(handle_data_arg->sock); + + if (retcode != 0 && errno != EBADF) { rig_debug(RIG_DEBUG_ERR, "%s: close(handle_data_arg->sock) %s\n", __func__, strerror(errno)); } + +#endif + + free(arg); + +#ifdef HAVE_PTHREAD + pthread_exit(NULL); +#endif + return NULL; +} + + +void usage(void) +{ + printf("Usage: rigctld [OPTION]...\n" + "Daemon serving COMMANDs to a connected radio transceiver or receiver.\n\n"); + + + printf( + " -m, --model=ID select radio model number. See model list\n" + " -r, --rig-file=DEVICE set device of the radio to operate on\n" + " -p, --ptt-file=DEVICE set device of the PTT device to operate on\n" + " -d, --dcd-file=DEVICE set device of the DCD device to operate on\n" + " -P, --ptt-type=TYPE set type of the PTT device to operate on\n" + " -D, --dcd-type=TYPE set type of the DCD device to operate on\n" + " -s, --serial-speed=BAUD set serial speed of the serial port\n" + " -c, --civaddr=ID set CI-V address, decimal (for Icom rigs only)\n" + " -t, --port=NUM set TCP listening port, default %s\n" + " -S, --separator=CHAR set char as rigctld response separator, default is \\n\n" + " -T, --listen-addr=IPADDR set listening IP address, default ANY\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" + " -o, --vfo do not default to VFO_CURR, require extra vfo arg\n" + " -v, --verbose set verbose mode, cumulative (-v to -vvvvv)\n" + " -W, --twiddle_timeout timeout after detecting vfo manual change\n" + " -w, --twiddle_rit suppress VFOB getfreq so RIT can be twiddled\n" + " -x, --uplink set uplink get_freq ignore, 1=Sub, 2=Main\n" + " -Z, --debug-time-stamps enable time stamps for debug messages\n" + " -M, --multicast-addr=addr set multicast UDP address, default 0.0.0.0 (off), recommend 224.0.1.1\n" + " -n, --multicast-port=port set multicast UDP port, default 4532\n" + " -A, --password set password for rigctld access\n" + " -R, --rigctld-idle make rigctld close the rig when no clients are connected\n" + " -h, --help display this help and exit\n" + " -V, --version output version information and exit\n\n", + portno); + + usage_rig(stdout); + + printf("\nError codes and messages\n"); + + for (enum rig_errcode_e e = 0; e < RIG_EEND; ++e) + { + printf("-%d - %s", e, rigerror2(e)); + } + + + printf("\nReport bugs to <ham...@li...>.\n"); + +} commit 0b2f0873b036b339f5f65412cc17a464cc2ef3ba Author: Mike Black W9MDB <mdb...@ya...> Date: Mon Jan 2 11:32:18 2023 -0600 Update NEWS diff --git a/NEWS b/NEWS index 5290f313..0facc972 100644 --- a/NEWS +++ b/NEWS @@ -26,7 +26,7 @@ Version 4.6 Version 4.5.4 * 2023-XX-XX - * Remove get_powerstat from Icom ID-5100 + * Remove get_powerstat from Icom ID-5100,ID-4100,ID-31,ID-51 and fix get/set freq in all Version 4.5.3 * 2022-12-31 commit c7b33ef0b3296a88ca387db1ac3634e19075dab1 Author: Mike Black W9MDB <mdb...@ya...> Date: Mon Jan 2 11:30:52 2023 -0600 Fix ID5100 ID4100 ID31 ID51 get/set freq Remove get_powerstat from ID4100 ID31 ID51 as it they are not capable Add new rig_is_model function to help with Icom rig identification checks https://github.com/Hamlib/Hamlib/issues/1202 https://github.com/Hamlib/Hamlib/issues/1200 diff --git a/include/hamlib/rig.h b/include/hamlib/rig.h index eb3d9a0e..a55ef92f 100644 --- a/include/hamlib/rig.h +++ b/include/hamlib/rig.h @@ -3428,6 +3428,8 @@ extern HAMLIB_EXPORT(char*) rig_make_md5(char *pass); extern HAMLIB_EXPORT(int) rig_set_lock_mode(RIG *rig, int lock); extern HAMLIB_EXPORT(int) rig_get_lock_mode(RIG *rig, int *lock); +extern HAMLIB_EXPORT(int) rig_is_model(RIG *rig, rig_model_t model); + //! @endcond diff --git a/rigs/icom/icom.c b/rigs/icom/icom.c index e17d1e98..41f236f2 100644 --- a/rigs/icom/icom.c +++ b/rigs/icom/icom.c @@ -1324,7 +1324,15 @@ int icom_set_freq(RIG *rig, vfo_t vfo, freq_t freq) RETURNFUNC2(retval); } - freq_len = priv->civ_731_mode ? 4 : 5; + if (ICOM_IS_ID5100 || ICOM_IS_ID5100) + { + freq_len = 3; + } + else + { + freq_len = priv->civ_731_mode ? 4 : 5; + } + /* * to_bcd requires nibble len */ @@ -1688,7 +1696,11 @@ int icom_get_freq(RIG *rig, vfo_t vfo, freq_t *freq) RETURNFUNC(RIG_OK); } - if (freq_len != 4 && freq_len != 5) + if (freq_len == 3 && (ICOM_IS_ID5100 || ICOM_IS_ID4100 || ICOM_IS_ID31 || ICOM_IS_ID51)) + { + rig_debug(RIG_DEBUG_TRACE, "%s: 3-byte ID5100/4100 length\n", __func__); + } + else if (freq_len != 4 && freq_len != 5) { rig_debug(RIG_DEBUG_ERR, "%s: wrong frame len=%d\n", __func__, freq_len); @@ -1698,7 +1710,7 @@ int icom_get_freq(RIG *rig, vfo_t vfo, freq_t *freq) RETURNFUNC(-RIG_ERJCTED); } - if (freq_len != (priv->civ_731_mode ? 4 : 5)) + if (freq_len != 3 && freq_len != (priv->civ_731_mode ? 4 : 5)) { rig_debug(RIG_DEBUG_WARN, "%s: freq len (%d) differs from expected\n", __func__, freq_len); diff --git a/rigs/icom/icom.h b/rigs/icom/icom.h index be4475cd..0ddce378 100644 --- a/rigs/icom/icom.h +++ b/rigs/icom/icom.h @@ -31,7 +31,12 @@ #include <sys/time.h> #endif -#define BACKEND_VER "20221120" +#define BACKEND_VER "20230102" + +#define ICOM_IS_ID31 rig_is_model(rig, RIG_MODEL_ID31) +#define ICOM_IS_ID51 rig_is_model(rig, RIG_MODEL_ID51) +#define ICOM_IS_ID4100 rig_is_model(rig, RIG_MODEL_ID4100) +#define ICOM_IS_ID5100 rig_is_model(rig, RIG_MODEL_ID5100) #define ICOM_IS_SECONDARY_VFO(vfo) ((vfo) & (RIG_VFO_B | RIG_VFO_SUB | RIG_VFO_SUB_B | RIG_VFO_MAIN_B)) #define ICOM_GET_VFO_NUMBER(vfo) (ICOM_IS_SECONDARY_VFO(vfo) ? 0x01 : 0x00) diff --git a/rigs/icom/id31.c b/rigs/icom/id31.c index 26453be7..03e9e535 100644 --- a/rigs/icom/id31.c +++ b/rigs/icom/id31.c @@ -82,7 +82,7 @@ const struct rig_caps id31_caps = RIG_MODEL(RIG_MODEL_ID31), .model_name = "ID-31", .mfg_name = "Icom", - .version = BACKEND_VER ".0", + .version = BACKEND_VER ".1", .copyright = "LGPL", .status = RIG_STATUS_ALPHA, .rig_type = RIG_TYPE_HANDHELD, @@ -179,7 +179,7 @@ const struct rig_caps id31_caps = .get_mode = icom_get_mode, .set_powerstat = icom_set_powerstat, - .get_powerstat = icom_get_powerstat, +// .get_powerstat = icom_get_powerstat, // not capable .decode_event = icom_decode_event, .set_func = icom_set_func, diff --git a/rigs/icom/id4100.c b/rigs/icom/id4100.c index d46e7a6c..83efa22a 100644 --- a/rigs/icom/id4100.c +++ b/rigs/icom/id4100.c @@ -86,9 +86,9 @@ const struct rig_caps id4100_caps = RIG_MODEL(RIG_MODEL_ID4100), .model_name = "ID-4100", .mfg_name = "Icom", - .version = BACKEND_VER ".0", + .version = BACKEND_VER ".1", .copyright = "LGPL", - .status = RIG_STATUS_ALPHA, + .status = RIG_STATUS_BETA, .rig_type = RIG_TYPE_MOBILE, .ptt_type = RIG_PTT_RIG, .dcd_type = RIG_DCD_RIG, @@ -98,7 +98,7 @@ const struct rig_caps id4100_caps = .serial_data_bits = 8, .serial_stop_bits = 1, .serial_parity = RIG_PARITY_NONE, - .serial_handshake = RIG_HANDSHAKE_NONE, + .serial_handshake = RIG_HANDSHAKE_XONXOFF, .write_delay = 0, .post_write_delay = 0, .timeout = 1000, @@ -187,7 +187,7 @@ const struct rig_caps id4100_caps = .get_mode = icom_get_mode, .set_vfo = icom_set_vfo, - .set_powerstat = icom_set_powerstat, + //.set_powerstat = icom_set_powerstat, // ID-4100 does cannot query power .get_powerstat = icom_get_powerstat, .decode_event = icom_decode_event, diff --git a/rigs/icom/id51.c b/rigs/icom/id51.c index 1d10da00..25f56e7c 100644 --- a/rigs/icom/id51.c +++ b/rigs/icom/id51.c @@ -89,7 +89,7 @@ const struct rig_caps id51_caps = RIG_MODEL(RIG_MODEL_ID51), .model_name = "ID-51", .mfg_name = "Icom", - .version = BACKEND_VER ".0", + .version = BACKEND_VER ".1", .copyright = "LGPL", .status = RIG_STATUS_ALPHA, .rig_type = RIG_TYPE_HANDHELD, @@ -185,7 +185,7 @@ const struct rig_caps id51_caps = .rig_open = icom_rig_open, .rig_close = icom_rig_close, .set_powerstat = icom_set_powerstat, - .get_powerstat = icom_get_powerstat, +// .get_powerstat = icom_get_powerstat, // not capable .set_freq = icom_set_freq, .get_freq = icom_get_freq, diff --git a/src/rig.c b/src/rig.c index 87876dcb..7422fd27 100644 --- a/src/rig.c +++ b/src/rig.c @@ -7717,3 +7717,15 @@ HAMLIB_EXPORT(int) rig_get_lock_mode(RIG *rig, int *mode) return (retcode); } + +HAMLIB_EXPORT(int) rig_is_model(RIG *rig, rig_model_t model) +{ + int is_rig; + + //a bit too verbose so disable this unless needed + //rig_debug(RIG_DEBUG_TRACE, "%s(%d):%s called\n", __FILE__, __LINE__, __func__); + is_rig = (model == rig->caps->rig_model) ? 1 : 0; + + return (is_rig); // RETURN is too verbose here +} + diff --git a/tests/Makefile.am b/tests/Makefile.am index 69cd60be..cd0d8cb8 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 ampctl ampctld $(TESTLIBUSB) +bin_PROGRAMS = rigctl rigctld rigmem rigsmtr rigswr rotctl rotctld rigctlcom rigctltcp 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 @@ -26,6 +26,7 @@ AMPCOMMONSRC = ampctl_parse.c ampctl_parse.h dumpcaps_amp.c uthash.h rigctl_SOURCES = rigctl.c $(RIGCOMMONSRC) rigctld_SOURCES = rigctld.c $(RIGCOMMONSRC) rigctlcom_SOURCES = rigctlcom.c $(RIGCOMMONSRC) +rigctltcp_SOURCES = rigctltcp.c $(RIGCOMMONSRC) rotctl_SOURCES = rotctl.c $(ROTCOMMONSRC) rotctld_SOURCES = rotctld.c $(ROTCOMMONSRC) ampctl_SOURCES = ampctl.c $(AMPCOMMONSRC) @@ -50,6 +51,7 @@ rotctld_CFLAGS = $(AM_CFLAGS) $(PTHREAD_CFLAGS) -I$(top_builddir)/src 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 if HAVE_LIBUSB rigtestlibusb_CFLAGS = $(AM_CFLAGS) $(PTHREAD_CFLAGS) $(LIBUSB_CFLAGS) endif @@ -63,6 +65,7 @@ ampctl_LDADD = $(PTHREAD_LIBS) $(LDADD) $(READLINE_LIBS) 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) if HAVE_LIBUSB rigtestlibusb_LDADD = $(LIBUSB_LIBS) endif @@ -78,6 +81,7 @@ rigctld_LDFLAGS = $(WINEXELDFLAGS) rotctld_LDFLAGS = $(WINEXELDFLAGS) ampctld_LDFLAGS = $(WINEXELDFLAGS) rigctlcom_LDFLAGS = $(WINEXELDFLAGS) +rigctltcp_LDFLAGS = $(WINEXELDFLAGS) if HAVE_LIBUSB rigtestlibusb_LDFLAGS = $(WINEXELDFLAGS) endif commit f68d45d99b5b08ac64d19a20d8aedfc27270de3e Author: Mike Black W9MDB <mdb...@ya...> Date: Mon Jan 2 08:58:21 2023 -0600 Update NEWS diff --git a/NEWS b/NEWS index 8d1f0e39..5290f313 100644 --- a/NEWS +++ b/NEWS @@ -26,6 +26,7 @@ Version 4.6 Version 4.5.4 * 2023-XX-XX + * Remove get_powerstat from Icom ID-5100 Version 4.5.3 * 2022-12-31 commit fa7289995c29719739edd13d3e945248adc0905a Author: Mike Black W9MDB <mdb...@ya...> Date: Mon Jan 2 08:48:59 2023 -0600 Remove get_powerstat from Icom ID-5100 -- does not have the ability to get power status https://github.com/Hamlib/Hamlib/issues/1201 diff --git a/rigs/icom/id5100.c b/rigs/icom/id5100.c index e9769737..2448ff8f 100644 --- a/rigs/icom/id5100.c +++ b/rigs/icom/id5100.c @@ -86,7 +86,7 @@ const struct rig_caps id5100_caps = RIG_MODEL(RIG_MODEL_ID5100), .model_name = "ID-5100", .mfg_name = "Icom", - .version = BACKEND_VER ".1", + .version = BACKEND_VER ".2", .copyright = "LGPL", .status = RIG_STATUS_BETA, .rig_type = RIG_TYPE_MOBILE, @@ -189,7 +189,7 @@ const struct rig_caps id5100_caps = .set_vfo = icom_set_vfo, .set_powerstat = icom_set_powerstat, - .get_powerstat = icom_get_powerstat, + //.get_powerstat = icom_get_powerstat, // ID-5100 cannot get power status .decode_event = icom_decode_event, .set_func = icom_set_func, commit 582686505cbbc43f2013b7b8355d1f877671ef7e Author: Mike Black W9MDB <mdb...@ya...> Date: Sun Jan 1 16:40:19 2023 -0600 TS-890S query rig to find out which meter type the operator has selected Thanks to N3GB George Baltz diff --git a/rigs/kenwood/ts890s.c b/rigs/kenwood/ts890s.c index dc2781b9..cae17b1c 100644 --- a/rigs/kenwood/ts890s.c +++ b/rigs/kenwood/ts890s.c @@ -17,10 +17,12 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ #include <hamlib/config.h> #include <stdio.h> +#include <math.h> #include <hamlib/rig.h> #include "kenwood.h" @@ -366,6 +368,59 @@ int kenwood_ts890_get_level(RIG *rig, vfo_t vfo, setting_t level, value_t *val) #endif return -RIG_ENIMPL; + case RIG_LEVEL_STRENGTH: + { + cal_table_float_t *table; + /* Values taken from the TS-890S In-Depth Manual (IDM), p. 8 + * 0.03 - 21.5 MHz, Preamp 1 + */ + /* Meter Type 1 - Kenwood specific, factory default */ + static cal_table_float_t meter_type1 = + { + 9, { { 0, -28.4f}, { 3, -26}, {11, -19.5f}, + {19, -13}, {27, -6.5f}, {35, 0}, + {48, 20}, {59, 40}, {70, 60} + } }; + /* Meter Type 2 - IARU recommended */ + static cal_table_float_t meter_type2 = + { + 9, { { 0, -54}, { 3, -48}, {11, -36}, + {19, -24}, {27, -12}, {35, 0}, + {48, 20}, {59, 40}, {70, 60} + } }; + /* Find out which meter type is in use */ + retval = kenwood_safe_transaction(rig, "EX00011", ackbuf, sizeof(ackbuf), 11); + + if (retval != RIG_OK) + { + return retval; + } + if (strncmp(ackbuf + 8, "000", 3) == 0) + { + table = &meter_type1; + } + else if (strncmp(ackbuf + 8, "001", 3) == 0) + { + table = &meter_type2; + } + else + { + rig_debug(RIG_DEBUG_ERR, "%s: Unexpected meter type: %s\n", + __func__, ackbuf); + return -RIG_EPROTO; + } + retval = kenwood_safe_transaction(rig, "SM", ackbuf, 10, 6); + if (retval != RIG_OK) + { + return retval; + } + + sscanf(ackbuf + 2, "%d", &val->i); + /* Convert reading back to dB (rounded) */ + val->i = (int)floorf(rig_raw2val_float(val->i, table) + 0.5f); + return RIG_OK; + } + default: return kenwood_get_level(rig, vfo, level, val); } @@ -378,39 +433,6 @@ static struct kenwood_priv_caps ts890s_priv_caps = .cmdtrm = EOM_KEN, }; -/* S-meter calibration table - * The TS-890S has two distinct S-meter curves, selectable - * by menu option. Define both, but since Hamlib has only - * one slot, use the the IARU one. - * Values taken from TS-890S In-Depth Manual, p. 8 - */ -/* Meter Type 1 - Kenwood specific (default) */ -#define TS890_SM_CAL2 { 9, \ - { \ - { 0, -28 }, \ - { 3, -26 }, \ - { 11, -20 }, \ - { 19, -13 }, \ - { 27, -7 }, \ - { 35, 0 }, \ - { 48, 20 }, \ - { 59, 40 }, \ - { 70, 60 }, \ - } } -/* Meter Type 2 - IARU Standard */ -#define TS890_SM_CAL1 { 9, \ - { \ - { 0, -54 }, \ - { 3, -48 }, \ - { 11, -36 }, \ - { 19, -24 }, \ - { 27, -12 }, \ - { 35, 0 }, \ - { 48, 20 }, \ - { 59, 40 }, \ - { 70, 60 }, \ - } } - /* SWR meter calibration table */ /* The full scale value reads infinity, so arbitrary */ #define TS890_SWR_CAL { 5, \ @@ -543,7 +565,6 @@ const struct rig_caps ts890s_caps = }, .vfo_ops = TS890_VFO_OPS, - .str_cal = TS890_SM_CAL1, .swr_cal = TS890_SWR_CAL, .priv = (void *)& ts890s_priv_caps, commit 712564a2ae97343c5ed7001f90e79716939ed1d0 Author: Mike Black W9MDB <mdb...@ya...> Date: Sun Jan 1 16:39:25 2023 -0600 ... [truncated message content] |