From 4b8de5f96d548860f4cca1ab6d3db7e0d274cc15 Mon Sep 17 00:00:00 2001 From: Mikael Nousiainen Date: Wed, 10 May 2023 20:53:18 +0300 Subject: [PATCH 1/8] Change float level granularity formatting to use %f to avoid E notation. Fix AGC_TIME level range for Icom rigs. Fix listing of AGC levels in \dump_caps. Add \stop_morse and \wait_morse in \dump_caps. Add simulation of responses in \send_cmd_rx and \send_raw for dummy rig (and if rig port type is NONE). Fix other minor issues. --- rigs/dummy/dummy.c | 4 ++ rigs/icom/ic7300.c | 3 -- rigs/icom/icom.c | 4 +- rigs/icom/level_gran_icom.h | 2 +- src/misc.c | 10 ++-- src/rig.c | 99 +++++++++++++++++++++---------------- src/sprintflst.c | 10 ++-- tests/dumpcaps.c | 21 ++------ tests/rigctl_parse.c | 70 ++++++++++++++++++-------- 9 files changed, 127 insertions(+), 96 deletions(-) diff --git a/rigs/dummy/dummy.c b/rigs/dummy/dummy.c index 0479f2d7c..3a4625d91 100644 --- a/rigs/dummy/dummy.c +++ b/rigs/dummy/dummy.c @@ -2287,6 +2287,10 @@ struct rig_caps dummy_caps = .has_get_parm = DUMMY_PARM, .has_set_parm = RIG_PARM_SET(DUMMY_PARM), .level_gran = { + [LVL_RF] = { .min = { .f = 0 }, .max = { .f = 1.0f }, .step = { .f = 1.0f/255.0f } }, + [LVL_RFPOWER] = { .min = { .f = .05f }, .max = { .f = 1 }, .step = { .f = 1.0f/511.0f } }, + [LVL_RFPOWER_METER] = { .min = { .f = .0f }, .max = { .f = 1 }, .step = { .f = 1.0f/255.0f } }, + [LVL_RFPOWER_METER_WATTS] = { .min = { .f = .0f }, .max = { .f = 100 }, .step = { .f = 1.0f/255.0f } }, [LVL_CWPITCH] = { .step = { .i = 10 } }, [LVL_SPECTRUM_SPEED] = {.min = {.i = 0}, .max = {.i = 2}, .step = {.i = 1}}, [LVL_SPECTRUM_REF] = {.min = {.f = -30.0f}, .max = {.f = 10.0f}, .step = {.f = 0.5f}}, diff --git a/rigs/icom/ic7300.c b/rigs/icom/ic7300.c index 7740c18b8..7a5a1c03a 100644 --- a/rigs/icom/ic7300.c +++ b/rigs/icom/ic7300.c @@ -580,7 +580,6 @@ const struct rig_caps ic7300_caps = [LVL_SPECTRUM_REF] = {.min = {.f = -20.0f}, .max = {.f = 20.0f}, .step = {.f = 0.5f}}, [LVL_SPECTRUM_AVG] = {.min = {.i = 0}, .max = {.i = 3}, .step = {.i = 1}}, [LVL_USB_AF] = {.min = {.f = 0.0f}, .max = {.f = 1.0f}, .step = {.f = 1.0f / 255.0f }}, - [LVL_AGC_TIME] = {.min = {.f = 0.0f}, .max = {.f = 8.0f}, .step = {.f = 0.1f }}, }, .parm_gran = {}, .ext_tokens = ic7300_ext_tokens, @@ -816,7 +815,6 @@ struct rig_caps ic9700_caps = [LVL_SPECTRUM_REF] = {.min = {.f = -20.0f}, .max = {.f = 20.0f}, .step = {.f = 0.5f}}, [LVL_SPECTRUM_AVG] = {.min = {.i = 0}, .max = {.i = 3}, .step = {.i = 1}}, [LVL_USB_AF] = {.min = {.f = 0.0f}, .max = {.f = 1.0f}, .step = {.f = 1.0f / 255.0f }}, - [LVL_AGC_TIME] = {.min = {.f = 0.0f}, .max = {.f = 8.0f}, .step = {.f = 0.1f }}, }, .parm_gran = {}, .ext_tokens = ic9700_ext_tokens, @@ -1129,7 +1127,6 @@ const struct rig_caps ic705_caps = [LVL_SPECTRUM_REF] = {.min = {.f = -20.0f}, .max = {.f = 20.0f}, .step = {.f = 0.5f}}, [LVL_SPECTRUM_AVG] = {.min = {.i = 0}, .max = {.i = 3}, .step = {.i = 1}}, [LVL_USB_AF] = {.min = {.f = 0.0f}, .max = {.f = 1.0f}, .step = {.f = 1.0f / 255.0f }}, - [LVL_AGC_TIME] = {.min = {.f = 0.0f}, .max = {.f = 8.0f}, .step = {.f = 0.1f }}, }, .parm_gran = {}, .ext_tokens = ic705_ext_tokens, diff --git a/rigs/icom/icom.c b/rigs/icom/icom.c index 07e515d82..2c3bb3ce2 100644 --- a/rigs/icom/icom.c +++ b/rigs/icom/icom.c @@ -3508,13 +3508,13 @@ int icom_set_level(RIG *rig, vfo_t vfo, setting_t level, value_t val) if (rig->state.current_mode == RIG_MODE_AM) { agcp = agc_level2; } - rig_debug(RIG_DEBUG_ERR, "%s: val.f=%g\n", __func__, val.f); + rig_debug(RIG_DEBUG_ERR, "%s: val.f=%f\n", __func__, val.f); for (i = 0; i <= 13; ++i) { if (agcp[i] <= val.f) { - rig_debug(RIG_DEBUG_ERR, "%s: agcp=%g <= val.f=%g at %d\n", __func__, agcp[i], + rig_debug(RIG_DEBUG_ERR, "%s: agcp=%f <= val.f=%f at %d\n", __func__, agcp[i], val.f, i); icom_val = i; } diff --git a/rigs/icom/level_gran_icom.h b/rigs/icom/level_gran_icom.h index 0c8d2cc59..b3f8a5658 100644 --- a/rigs/icom/level_gran_icom.h +++ b/rigs/icom/level_gran_icom.h @@ -30,7 +30,7 @@ LVL_KEYSPD [LVL_VOXDELAY] = { .min = { .i = 0 }, .max = { .i = 20 }, .step = { .i = 1 } }, [LVL_BKINDL] = { .min = { .i = 30 }, .max = { .i = 3000 }, .step = { .i = 1 } }, [LVL_BKIN_DLYMS] = { .min = { .i = 30 }, .max = { .i = 3000 }, .step = { .i = 1 } }, - [LVL_AGC_TIME] = { .min = { .i = 0 }, .max = { .i = 8000 }, .step = { .i = 1 } }, + [LVL_AGC_TIME] = { .min = { .f = 0.0f }, .max = { .f = 8.0f }, .step = { .f = 0.1f } }, /* level with misc units */ [LVL_SWR] = { .min = { .f = 0 }, .max = { .f = 5.0 }, .step = { .f = 1.0f/255.0f } }, [LVL_BAND_SELECT] = { .min = { .i = 0 }, .max = { .i = 16 }, .step = { .i = 1 } }, diff --git a/src/misc.c b/src/misc.c index 518e8c250..77eaf1e0e 100644 --- a/src/misc.c +++ b/src/misc.c @@ -2156,6 +2156,11 @@ int HAMLIB_API parse_hoststr(char *hoststr, int hoststr_len, char host[256], //#define RIG_FLUSH_REMOVE int HAMLIB_API rig_flush(hamlib_port_t *port) { + if (port->type.rig == RIG_PORT_NONE) + { + return RIG_OK; + } + // Data should never be flushed when using async I/O if (port->asyncio) { @@ -2166,11 +2171,6 @@ int HAMLIB_API rig_flush(hamlib_port_t *port) rig_debug(RIG_DEBUG_TRACE, "%s: called for %s device\n", __func__, port->type.rig == RIG_PORT_SERIAL ? "serial" : "network"); - if (port->type.rig == RIG_PORT_NONE) - { - return RIG_OK; - } - if (port->type.rig == RIG_PORT_NETWORK || port->type.rig == RIG_PORT_UDP_NETWORK) { diff --git a/src/rig.c b/src/rig.c index 41fe231ad..a7ab9bdf5 100644 --- a/src/rig.c +++ b/src/rig.c @@ -7712,70 +7712,85 @@ HAMLIB_EXPORT(int) rig_send_raw(RIG *rig, const unsigned char *send, struct rig_state *rs = &rig->state; unsigned char buf[200]; int nbytes; + int retval; + int simulate = rig->caps->rig_model == RIG_MODEL_DUMMY || + rig->caps->rig_model == RIG_MODEL_NONE || + rs->rigport.rig == RIG_PORT_NONE; ENTERFUNC; - if (rig->caps->rig_model == RIG_MODEL_DUMMY - || rig->caps->rig_model == RIG_MODEL_NONE) - { - rig_debug(RIG_DEBUG_ERR, "%s: not implemented for model %s\n", __func__, - rig->caps->model_name); - return -RIG_ENAVAIL; - } - ELAPSED1; rig_debug(RIG_DEBUG_VERBOSE, "%s: writing %d bytes\n", __func__, send_len); - int retval = write_block(&rs->rigport, send, send_len); - if (retval < 0) + if (simulate) { - // TODO: error handling? can writing to a pipe really fail in ways we can recover from? - rig_debug(RIG_DEBUG_ERR, "%s: write_block_sync() failed, result=%d\n", __func__, - retval); + rig_debug(RIG_DEBUG_VERBOSE, "%s: simulating response for model %s\n", + __func__, rig->caps->model_name); + retval = send_len; + } + else + { + retval = write_block(&rs->rigport, send, send_len); + + if (retval < 0) + { + // TODO: error handling? can writing to a pipe really fail in ways we can recover from? + rig_debug(RIG_DEBUG_ERR, "%s: write_block_sync() failed, result=%d\n", __func__, + retval); + } } if (reply) { - if (term == - NULL) // we have to have terminating char or else we can't read the response + // we have to have terminating char or else we can't read the response + if (term == NULL) { rig_debug(RIG_DEBUG_ERR, "%s: term==NULL, must have terminator to read reply\n", __func__); RETURNFUNC(-RIG_EINVAL); } - if (*term == 0xfd) // then we want an Icom frame + if (simulate) { - rig_debug(RIG_DEBUG_VERBOSE, "%s: reading icom frame\n", __func__); - retval = read_icom_frame(&rs->rigport, buf, sizeof(buf)); - nbytes = retval; + // Simulate a response by copying the command + memcpy(buf, send, send_len); + nbytes = send_len + 1; } - else if (term == NULL) + else { - rig_debug(RIG_DEBUG_VERBOSE, "%s: reading binary frame\n", __func__); - nbytes = read_string_direct(&rs->rigport, buf, reply_len, (const char *)term, - 1, 0, 1); - } - else // we'll assume the provided terminator works - { - rig_debug(RIG_DEBUG_VERBOSE, "%s: reading frame terminated by '%s'\n", __func__, - term); - nbytes = read_string_direct(&rs->rigport, buf, sizeof(buf), (const char *)term, - 1, 0, 1); - } + if (*term == 0xfd) // then we want an Icom frame + { + rig_debug(RIG_DEBUG_VERBOSE, "%s: reading icom frame\n", __func__); + retval = read_icom_frame(&rs->rigport, buf, sizeof(buf)); + nbytes = retval; + } + else if (term == NULL) + { + rig_debug(RIG_DEBUG_VERBOSE, "%s: reading binary frame\n", __func__); + nbytes = read_string_direct(&rs->rigport, buf, reply_len, (const char *)term, + 1, 0, 1); + } + else // we'll assume the provided terminator works + { + rig_debug(RIG_DEBUG_VERBOSE, "%s: reading frame terminated by '%s'\n", __func__, + term); + nbytes = read_string_direct(&rs->rigport, buf, sizeof(buf), (const char *)term, + 1, 0, 1); + } - if (retval < RIG_OK) - { - rig_debug(RIG_DEBUG_ERR, "%s: read_string_direct, result=%d\n", __func__, - retval); - RETURNFUNC(retval); - } + if (retval < RIG_OK) + { + rig_debug(RIG_DEBUG_ERR, "%s: read_string_direct, result=%d\n", __func__, + retval); + RETURNFUNC(retval); + } - if (nbytes >= reply_len) - { - rig_debug(RIG_DEBUG_ERR, "%s: reply_len(%d) less than reply from rig(%d)\n", - __func__, reply_len, nbytes); - return -RIG_EINVAL; + if (nbytes >= reply_len) + { + rig_debug(RIG_DEBUG_ERR, "%s: reply_len(%d) less than reply from rig(%d)\n", + __func__, reply_len, nbytes); + return -RIG_EINVAL; + } } memcpy(reply, buf, reply_len - 1); diff --git a/src/sprintflst.c b/src/sprintflst.c index 6a6c870f0..afb344b45 100644 --- a/src/sprintflst.c +++ b/src/sprintflst.c @@ -386,7 +386,7 @@ int rig_sprintf_level_gran(char *str, int nlen, setting_t level, if (RIG_LEVEL_IS_FLOAT(rig_idx2setting(i))) { len += sprintf(str + len, - "%s(%g..%g/%g) ", + "%s(%f..%f/%f) ", ms, gran[i].min.f, gran[i].max.f, @@ -445,7 +445,7 @@ int rot_sprintf_level_gran(char *str, int nlen, setting_t level, if (ROT_LEVEL_IS_FLOAT(rig_idx2setting(i))) { len += sprintf(str + len, - "%s(%g..%g/%g) ", + "%s(%f..%f/%f) ", ms, gran[i].min.f, gran[i].max.f, @@ -564,7 +564,7 @@ int rig_sprintf_parm_gran(char *str, int nlen, setting_t parm, if (RIG_PARM_IS_FLOAT(rig_idx2setting(i))) { len += sprintf(str + len, - "%s(%g..%g/%g) ", + "%s(%f..%f/%f) ", ms, gran[i].min.f, gran[i].max.f, @@ -623,7 +623,7 @@ int rot_sprintf_parm_gran(char *str, int nlen, setting_t parm, if (ROT_PARM_IS_FLOAT(rig_idx2setting(i))) { len += sprintf(str + len, - "%s(%g..%g/%g) ", + "%s(%f..%f/%f) ", ms, gran[i].min.f, gran[i].max.f, @@ -877,7 +877,7 @@ int print_ext_param(const struct confparams *cfp, rig_ptr_t ptr) switch (cfp->type) { case RIG_CONF_NUMERIC: - fprintf((FILE *)ptr, "\t\tRange: %g..%g/%g\n", cfp->u.n.min, cfp->u.n.max, + fprintf((FILE *)ptr, "\t\tRange: %f..%f/%f\n", cfp->u.n.min, cfp->u.n.max, cfp->u.n.step); break; diff --git a/tests/dumpcaps.c b/tests/dumpcaps.c index ae6874436..5b911fba6 100644 --- a/tests/dumpcaps.c +++ b/tests/dumpcaps.c @@ -301,7 +301,7 @@ int dumpcaps(RIG *rig, FILE *fout) if (priv_caps && RIG_BACKEND_NUM(rig->caps->rig_model) == RIG_ICOM && priv_caps->agc_levels_present) { - for (i = 0; i <= RIG_AGC_LAST && priv_caps->agc_levels[i].level != RIG_AGC_LAST + for (i = 0; i < HAMLIB_MAX_AGC_LEVELS && priv_caps->agc_levels[i].level != RIG_AGC_LAST && priv_caps->agc_levels[i].icom_level >= 0; i++) { fprintf(fout, " %d=%s", priv_caps->agc_levels[i].level, @@ -310,31 +310,16 @@ int dumpcaps(RIG *rig, FILE *fout) } else { - for (i = 0; i < HAMLIB_MAX_AGC_LEVELS && i < caps->agc_level_count; i++) { fprintf(fout, " %d=%s", caps->agc_levels[i], rig_stragclevel(caps->agc_levels[i])); } - - if (i == 0) - { - fprintf(fout, " %d=%s", RIG_AGC_NONE, rig_stragclevel(RIG_AGC_NONE)); - } } - fprintf(fout, "\n"); - if (i == 0) { - rig_debug(RIG_DEBUG_WARN, - "%s: defaulting to all levels since rig does not have any\n", __func__); - - // Fall back to printing out all levels for backwards-compatibility - for (i = RIG_AGC_OFF; i <= RIG_AGC_LAST; i++) - { - fprintf(fout, " %d=%s", i, rig_stragclevel(i)); - } + fprintf(fout, " %d=%s", RIG_AGC_NONE, rig_stragclevel(RIG_AGC_NONE)); } fprintf(fout, "\n"); @@ -903,6 +888,8 @@ int dumpcaps(RIG *rig, FILE *fout) fprintf(fout, "Can send DTMF:\t%c\n", caps->send_dtmf != NULL ? 'Y' : 'N'); fprintf(fout, "Can recv DTMF:\t%c\n", caps->recv_dtmf != NULL ? 'Y' : 'N'); fprintf(fout, "Can send Morse:\t%c\n", caps->send_morse != NULL ? 'Y' : 'N'); + fprintf(fout, "Can stop Morse:\t%c\n", caps->stop_morse != NULL ? 'Y' : 'N'); + fprintf(fout, "Can wait Morse:\t%c\n", caps->wait_morse != NULL ? 'Y' : 'N'); fprintf(fout, "Can send Voice:\t%c\n", caps->send_voice_mem != NULL ? 'Y' : 'N'); diff --git a/tests/rigctl_parse.c b/tests/rigctl_parse.c index 331363ed0..f32678ab8 100644 --- a/tests/rigctl_parse.c +++ b/tests/rigctl_parse.c @@ -1747,8 +1747,7 @@ readline_repeat: rig_debug(RIG_DEBUG_WARN, "%s: command %s not allowed when rig is powered off\n", __func__, cmd_entry->name); -// retcode = -RIG_EPOWER; - retcode = RIG_OK; + retcode = -RIG_EPOWER; } else { @@ -4787,6 +4786,9 @@ declare_proto_rig(send_cmd) char eom_buf[4] = { 0xa, 0xd, 0, 0 }; int binary = 0; int rxbytes = BUFSZ; + int simulate = rig->caps->rig_model == RIG_MODEL_DUMMY || + rig->caps->rig_model == RIG_MODEL_NONE || + rs->rigport.rig == RIG_PORT_NONE; ENTERFUNC; @@ -4890,19 +4892,28 @@ declare_proto_rig(send_cmd) rs = &rig->state; - rig_flush(&rs->rigport); - rig_debug(RIG_DEBUG_TRACE, "%s: rigport=%d, bufcmd=%s, cmd_len=%d\n", __func__, rs->rigport.fd, hasbinary(bufcmd, cmd_len) ? "BINARY" : bufcmd, cmd_len); - // we don't want the 'w' command to wait too long - int save_retry = rs->rigport.retry; - rs->rigport.retry = 0; - retval = write_block(&rs->rigport, (unsigned char *) bufcmd, cmd_len); - rs->rigport.retry = save_retry; - if (retval != RIG_OK) + if (simulate) { - RETURNFUNC(retval); + rig_debug(RIG_DEBUG_VERBOSE, "%s: simulating response for model %s\n", + __func__, rig->caps->model_name); + } + else + { + rig_flush(&rs->rigport); + + // we don't want the 'w' command to wait too long + int save_retry = rs->rigport.retry; + rs->rigport.retry = 0; + retval = write_block(&rs->rigport, (unsigned char *) bufcmd, cmd_len); + rs->rigport.retry = save_retry; + + if (retval != RIG_OK) + { + RETURNFUNC(retval); + } } if ((interactive && prompt) || (interactive && !prompt && ext_resp)) @@ -4912,6 +4923,7 @@ declare_proto_rig(send_cmd) fwrite(": ", 1, 2, fout); /* i.e. "Frequency" */ } + retval = 0; do { if (arg2) { sscanf(arg2, "%d", &rxbytes); } @@ -4924,17 +4936,33 @@ declare_proto_rig(send_cmd) if (arg2[0] == ';') { eom_buf[0] = ';'; } - /* Assumes CR or LF is end of line char for all ASCII protocols. */ - retval = read_string(&rs->rigport, buf, rxbytes, eom_buf, - strlen(eom_buf), 0, 1); - - if (retval < 0) + if (simulate) { - rig_debug(RIG_DEBUG_ERR, "%s: read_string error %s\n", __func__, - rigerror(retval)); - - break; + if (retval == 0) + { + // Simulate a response by copying the command + memcpy(buf, bufcmd, cmd_len); + retval = cmd_len; + } + else + { + retval = 0; + } } + else + { + /* Assumes CR or LF is end of line char for all ASCII protocols. */ + retval = read_string(&rs->rigport, buf, rxbytes, eom_buf, + strlen(eom_buf), 0, 1); + + if (retval < 0) + { + rig_debug(RIG_DEBUG_ERR, "%s: read_string error %s\n", __func__, + rigerror(retval)); + break; + } + } + if (retval < BUFSZ) { @@ -4990,7 +5018,7 @@ declare_proto_rig(send_cmd) } while (retval > 0 && rxbytes == BUFSZ); -// we use fwrite in case of any nulls in binary return + // we use fwrite in case of any nulls in binary return if (binary) { fwrite(buf, 1, retval, fout); } if (binary) From 1596e125b61da4b495cc4fc7d8b6dde1d200f331 Mon Sep 17 00:00:00 2001 From: Mikael Nousiainen Date: Wed, 10 May 2023 20:57:33 +0300 Subject: [PATCH 2/8] Fix use of uninitialized variable --- tests/rigctl_parse.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/tests/rigctl_parse.c b/tests/rigctl_parse.c index f32678ab8..97c92f597 100644 --- a/tests/rigctl_parse.c +++ b/tests/rigctl_parse.c @@ -4778,7 +4778,7 @@ extern int flrig_cat_string(RIG *rig, const char *arg); declare_proto_rig(send_cmd) { int retval; - struct rig_state *rs; + struct rig_state *rs = &rig->state; int backend_num, cmd_len; #define BUFSZ 512 char bufcmd[BUFSZ * 5]; // allow for 5 chars for binary @@ -4890,8 +4890,6 @@ declare_proto_rig(send_cmd) tmpbuf); } - rs = &rig->state; - rig_debug(RIG_DEBUG_TRACE, "%s: rigport=%d, bufcmd=%s, cmd_len=%d\n", __func__, rs->rigport.fd, hasbinary(bufcmd, cmd_len) ? "BINARY" : bufcmd, cmd_len); From 716637c4abfba44fdb110c35873a962c035f9330 Mon Sep 17 00:00:00 2001 From: Mikael Nousiainen Date: Wed, 10 May 2023 22:35:44 +0300 Subject: [PATCH 3/8] Fix x25cmdfails logic to allow failure detection only once. Subsequent failures after an initial successful use of command 0x25 will not prevent use of the command. --- rigs/icom/icom.c | 52 ++++++++++++++++++++++++++++++++---------------- 1 file changed, 35 insertions(+), 17 deletions(-) diff --git a/rigs/icom/icom.c b/rigs/icom/icom.c index 2c3bb3ce2..68e02247d 100644 --- a/rigs/icom/icom.c +++ b/rigs/icom/icom.c @@ -869,7 +869,7 @@ static vfo_t icom_current_vfo(RIG *rig) struct rig_state *rs = &rig->state; struct icom_priv_data *priv = (struct icom_priv_data *) rs->priv; - if (priv->x25cmdfails == 0) // these newer rigs get special treatment + if (priv->x25cmdfails <= 0) // these newer rigs get special treatment { return icom_current_vfo_x25(rig); } @@ -1505,7 +1505,8 @@ int icom_get_freq(RIG *rig, vfo_t vfo, freq_t *freq) unsigned char freqbuf[MAXFRAMELEN]; int freqbuf_offset = 1; unsigned char ackbuf[MAXFRAMELEN]; - int freq_len, retval = -RIG_EINTERNAL; + int retval = RIG_OK; + int freq_len; int cmd, subcmd; int ack_len = sizeof(ackbuf); int civ_731_mode = 0; // even these rigs have 5-byte channels @@ -1629,7 +1630,7 @@ int icom_get_freq(RIG *rig, vfo_t vfo, freq_t *freq) // we'll use 0x25 command to get unselected frequency // we have to assume current_vfo is accurate to determine what "other" means - if (priv->x25cmdfails == 0) + if (priv->x25cmdfails <= 0) { int cmd2 = 0x25; int subcmd2 = 0x00; @@ -1651,9 +1652,16 @@ int icom_get_freq(RIG *rig, vfo_t vfo, freq_t *freq) retval = icom_transaction(rig, cmd2, subcmd2, NULL, 0, freqbuf, &freq_len); - if (retval != RIG_OK) + if (retval == RIG_OK) { - if (priv->x25cmdfails < 0) { priv->x25cmdfails = 1; } + priv->x25cmdfails = 0; + } + else + { + if (priv->x25cmdfails < 0) + { + priv->x25cmdfails = 1; + } rig_debug(RIG_DEBUG_TRACE, "%s: rig probe shows 0x25 CI-V cmd not available for this rig/firmware\n", @@ -1693,8 +1701,11 @@ int icom_get_freq(RIG *rig, vfo_t vfo, freq_t *freq) #endif if (retval != RIG_OK) -{ - if (vfo == RIG_VFO_MEM && civ_731_mode) { priv->civ_731_mode = 1; } + { + if (vfo == RIG_VFO_MEM && civ_731_mode) + { + priv->civ_731_mode = 1; + } RETURNFUNC(retval); } @@ -5546,11 +5557,17 @@ int icom_set_split_freq(RIG *rig, vfo_t vfo, freq_t tx_freq) if (retval == RIG_OK) // then we're done!! { + priv->x25cmdfails = 0; RETURNFUNC2(retval); } + else + { + if (priv->x25cmdfails < 0) + { + priv->x25cmdfails = 1; + } + } } - - priv->x25cmdfails = 1; } @@ -5731,7 +5748,7 @@ int icom_get_split_freq(RIG *rig, vfo_t vfo, freq_t *tx_freq) // If the rigs supports the 0x25 command we'll use it // This eliminates VFO swapping and improves split operations // This does not work in satellite mode for the 9700 - if (priv->x25cmdfails == 0) + if (priv->x25cmdfails <= 0) { int cmd, subcmd; int satmode = 0; @@ -5748,7 +5765,7 @@ int icom_get_split_freq(RIG *rig, vfo_t vfo, freq_t *tx_freq) if (satmode == 0) // only worth trying if not in satmode { - if (priv->x25cmdfails == 0) + if (priv->x25cmdfails <= 0) { int retry_save = rs->rigport.retry; rs->rigport.retry = 0; @@ -5763,11 +5780,12 @@ int icom_get_split_freq(RIG *rig, vfo_t vfo, freq_t *tx_freq) if (retval == RIG_OK) // then we're done!! { + priv->x25cmdfails = 0; *tx_freq = from_bcd(ackbuf + 2, (priv->civ_731_mode ? 4 : 5) * 2); RETURNFUNC2(retval); } -// if (priv->x25cmdfails < 0) priv->x25cmdfails = 1; + if (priv->x25cmdfails < 0) priv->x25cmdfails = 1; } } else // we're in satmode so we try another command @@ -5788,7 +5806,6 @@ int icom_get_split_freq(RIG *rig, vfo_t vfo, freq_t *tx_freq) priv->x1cx03cmdfails = 1; } } - } /* This method works also in memory mode(RIG_VFO_MEM) */ @@ -6759,7 +6776,8 @@ int icom_get_split_vfo(RIG *rig, vfo_t vfo, split_t *split, vfo_t *tx_vfo) { rig_debug(RIG_DEBUG_VERBOSE, "%s(%d): satmode changed to reset x25cmdfails\n", __func__, __LINE__); - priv->x25cmdfails = satmode; // reset this so it tries again + // Reset x25cmdfails to current status, because it fails in SATMODE + priv->x25cmdfails = satmode; } } @@ -7161,8 +7179,8 @@ int icom_set_func(RIG *rig, vfo_t vfo, setting_t func, int status) fct_sc = S_MEM_SATMODE; } - priv->x25cmdfails = - status; // we reset this to current status -- fails in SATMODE + // Reset x25cmdfails to current status, because it fails in SATMODE + priv->x25cmdfails = status; priv->x1cx03cmdfails = 0; // we reset this to try it again rig->state.cache.satmode = status; icom_satmode_fix(rig, status); @@ -7443,7 +7461,7 @@ int icom_get_func(RIG *rig, vfo_t vfo, setting_t func, int *status) *status = ackbuf[2 + fct_len]; icom_satmode_fix(rig, *status); - // we'll reset this based on current status + // Reset x25cmdfails to current status, because it fails in SATMODE priv->x25cmdfails = *status; } else From c80d45378a38bf228d10928e1f969a13d7cff394 Mon Sep 17 00:00:00 2001 From: Mikael Nousiainen Date: Wed, 10 May 2023 22:39:45 +0300 Subject: [PATCH 4/8] More fixes to command 0x25 logic --- rigs/icom/icom.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/rigs/icom/icom.c b/rigs/icom/icom.c index 68e02247d..5c40a4d1c 100644 --- a/rigs/icom/icom.c +++ b/rigs/icom/icom.c @@ -5568,6 +5568,9 @@ int icom_set_split_freq(RIG *rig, vfo_t vfo, freq_t tx_freq) } } } + + // Rig is in SATMODE and the command 0x25 fails in SATMODE + priv->x25cmdfails = 1; } From 92215dfd2ab7cbf7432792b63919260f24fc2f99 Mon Sep 17 00:00:00 2001 From: Mikael Nousiainen Date: Fri, 12 May 2023 10:01:32 +0300 Subject: [PATCH 5/8] Fix bugs in \send_raw command and add possibility to specify any command terminator character. Add \stop_morse to Dummy rig. --- rigs/dummy/dummy.c | 8 +++++++ src/rig.c | 44 +++++++++++++++++------------------- tests/rigctl_parse.c | 53 +++++++++++++++++++++++++++++++------------- 3 files changed, 66 insertions(+), 39 deletions(-) diff --git a/rigs/dummy/dummy.c b/rigs/dummy/dummy.c index 3a4625d91..e19130341 100644 --- a/rigs/dummy/dummy.c +++ b/rigs/dummy/dummy.c @@ -2125,6 +2125,13 @@ static int dummy_send_morse(RIG *rig, vfo_t vfo, const char *msg) RETURNFUNC(RIG_OK); } +static int dummy_stop_morse(RIG *rig, vfo_t vfo) +{ + ENTERFUNC; + + RETURNFUNC(RIG_OK); +} + static int dummy_send_voice_mem(RIG *rig, vfo_t vfo, int ch) { ENTERFUNC; @@ -2490,6 +2497,7 @@ struct rig_caps dummy_caps = .send_dtmf = dummy_send_dtmf, .recv_dtmf = dummy_recv_dtmf, .send_morse = dummy_send_morse, + .stop_morse = dummy_stop_morse, .send_voice_mem = dummy_send_voice_mem, .set_channel = dummy_set_channel, .get_channel = dummy_get_channel, diff --git a/src/rig.c b/src/rig.c index a7ab9bdf5..7450a5055 100644 --- a/src/rig.c +++ b/src/rig.c @@ -7722,6 +7722,8 @@ HAMLIB_EXPORT(int) rig_send_raw(RIG *rig, const unsigned char *send, rig_debug(RIG_DEBUG_VERBOSE, "%s: writing %d bytes\n", __func__, send_len); + set_transaction_active(rig); + if (simulate) { rig_debug(RIG_DEBUG_VERBOSE, "%s: simulating response for model %s\n", @@ -7735,21 +7737,12 @@ HAMLIB_EXPORT(int) rig_send_raw(RIG *rig, const unsigned char *send, if (retval < 0) { // TODO: error handling? can writing to a pipe really fail in ways we can recover from? - rig_debug(RIG_DEBUG_ERR, "%s: write_block_sync() failed, result=%d\n", __func__, - retval); + rig_debug(RIG_DEBUG_ERR, "%s: write_block_sync() failed, result=%d\n", __func__, retval); } } if (reply) { - // we have to have terminating char or else we can't read the response - if (term == NULL) - { - rig_debug(RIG_DEBUG_ERR, "%s: term==NULL, must have terminator to read reply\n", - __func__); - RETURNFUNC(-RIG_EINVAL); - } - if (simulate) { // Simulate a response by copying the command @@ -7758,37 +7751,37 @@ HAMLIB_EXPORT(int) rig_send_raw(RIG *rig, const unsigned char *send, } else { - if (*term == 0xfd) // then we want an Icom frame + if (term == NULL) + { + rig_debug(RIG_DEBUG_VERBOSE, "%s: reading binary frame\n", __func__); + retval = read_string(&rs->rigport, buf, reply_len, NULL, 0, 0, 1); + } + else if (*term == 0xfd) // then we want an Icom frame { rig_debug(RIG_DEBUG_VERBOSE, "%s: reading icom frame\n", __func__); retval = read_icom_frame(&rs->rigport, buf, sizeof(buf)); - nbytes = retval; - } - else if (term == NULL) - { - rig_debug(RIG_DEBUG_VERBOSE, "%s: reading binary frame\n", __func__); - nbytes = read_string_direct(&rs->rigport, buf, reply_len, (const char *)term, - 1, 0, 1); } else // we'll assume the provided terminator works { - rig_debug(RIG_DEBUG_VERBOSE, "%s: reading frame terminated by '%s'\n", __func__, - term); - nbytes = read_string_direct(&rs->rigport, buf, sizeof(buf), (const char *)term, + rig_debug(RIG_DEBUG_VERBOSE, "%s: reading frame terminated by 0x%x\n", __func__, *term); + retval = read_string(&rs->rigport, buf, sizeof(buf), (const char *)term, 1, 0, 1); } if (retval < RIG_OK) { - rig_debug(RIG_DEBUG_ERR, "%s: read_string_direct, result=%d\n", __func__, - retval); + rig_debug(RIG_DEBUG_ERR, "%s: read_string, result=%d\n", __func__, retval); + set_transaction_inactive(rig); RETURNFUNC(retval); } + nbytes = retval; + if (nbytes >= reply_len) { rig_debug(RIG_DEBUG_ERR, "%s: reply_len(%d) less than reply from rig(%d)\n", __func__, reply_len, nbytes); + set_transaction_inactive(rig); return -RIG_EINVAL; } } @@ -7797,12 +7790,15 @@ HAMLIB_EXPORT(int) rig_send_raw(RIG *rig, const unsigned char *send, } else { + set_transaction_inactive(rig); RETURNFUNC(retval); } + set_transaction_inactive(rig); + ELAPSED2; - RETURNFUNC(nbytes > 0 ? nbytes : -RIG_EPROTO); + RETURNFUNC(nbytes >= 0 ? nbytes : -RIG_EPROTO); } HAMLIB_EXPORT(int) rig_set_lock_mode(RIG *rig, int mode) diff --git a/tests/rigctl_parse.c b/tests/rigctl_parse.c index 97c92f597..ecddf6d25 100644 --- a/tests/rigctl_parse.c +++ b/tests/rigctl_parse.c @@ -5024,7 +5024,6 @@ declare_proto_rig(send_cmd) fwrite("\n", 1, 1, fout); } - if (retval > 0 || retval == -RIG_ETIMEOUT) { retval = RIG_OK; @@ -5421,13 +5420,15 @@ extern int netrigctl_send_raw(RIG *rig, char *s); /* 0xa4 */ declare_proto_rig(send_raw) { + int result; int reply_len; - unsigned char term[1]; - unsigned char buf[100]; - unsigned char send[100]; + unsigned char termbyte[1]; + unsigned char *term = NULL; + unsigned char buf[200]; + unsigned char send[200]; unsigned char *sendp = (unsigned char *)arg2; int arg2_len = strlen(arg2); - int hex_flag = 0; + int is_binary = 0; int buf_len = sizeof(buf); int val = 0; @@ -5441,15 +5442,31 @@ declare_proto_rig(send_raw) return retval; } - if (strcmp(arg1, ";") == 0) { term[0] = ';'; } - else if (strcasecmp(arg1, "CR")) { term[0] = 0x0d; } - else if (strcasecmp(arg1, "LF")) { term[0] = 0x0a; } - else if (strcasecmp(arg1, "ICOM")) { term[0] = 0xfd; } - else if (sscanf(arg1, "%d", &val) == 1) { term[0] = 0; buf_len = val;} + if (strcmp(arg1, ";") == 0) { termbyte[0] = ';'; term = termbyte; } + else if (strcasecmp(arg1, "CR") == 0) { termbyte[0] = 0x0d; term = termbyte; } + else if (strcasecmp(arg1, "LF") == 0) { termbyte[0] = 0x0a; term = termbyte; } + else if (strcasecmp(arg1, "ICOM") == 0) { termbyte[0] = 0xfd; term = termbyte; } + else if (sscanf(arg1, "0x%x", &val) == 1) { termbyte[0] = val; term = termbyte; } + else if (sscanf(arg1, "%d", &val) == 1) + { + if (val < buf_len - 1) + { + // Reserve one byte more to allow padding with null + buf_len = val + 1; + } + else + { + rig_debug(RIG_DEBUG_ERR, + "%s: response length %d is larger than maximum of %d bytes", + __func__, val, buf_len); + return -RIG_EINVAL; + } + } else { rig_debug(RIG_DEBUG_ERR, - "%s: unknown arg1 val=%s, expected ';' 'CR' 'LF' 'ICOM' or # of bytes where 0 means no reply and -1 means unknown", + "%s: unknown arg1 val=%s, expected ';', 'CR', 'LF', 'ICOM', 0xFF (hex byte) or " + "# of bytes where 0 means no reply and -1 means unknown", __func__, arg1); return -RIG_EINVAL; } @@ -5458,12 +5475,18 @@ declare_proto_rig(send_raw) { arg2_len = parse_hex(arg2, send, sizeof(send)); sendp = send; - hex_flag = 1; + is_binary = 1; } rig_debug(RIG_DEBUG_TRACE, "%s:\n", __func__); - reply_len = rig_send_raw(rig, (unsigned char *)sendp, arg2_len, buf, - buf_len, term); + + result = rig_send_raw(rig, (unsigned char *)sendp, arg2_len, buf,buf_len, term); + if (result < 0) + { + return result; + } + + reply_len = result; buf[buf_len + 1] = 0; // null terminate in case it's a string if ((interactive && prompt) || (interactive && !prompt && ext_resp)) @@ -5475,7 +5498,7 @@ declare_proto_rig(send_raw) { fprintf(fout, "No answer\n"); } - else if (hex_flag) + else if (is_binary) { int i; From e89687668d5b0ef501a0930a5977516d1c3a6983 Mon Sep 17 00:00:00 2001 From: Mikael Nousiainen Date: Sat, 13 May 2023 00:04:37 +0300 Subject: [PATCH 6/8] Add flushing of rig port, including async data pipes, after \send_raw and \send_cmd to drain any extra rig responses --- include/hamlib/rig.h | 3 +++ src/iofunc.c | 38 ++++++++++++++++++++++++++++++++++++++ src/iofunc.h | 2 ++ src/misc.c | 32 ++++++++++++++++++++++++++------ src/rig.c | 4 ++++ tests/rigctl_parse.c | 10 ++++++++++ 6 files changed, 83 insertions(+), 6 deletions(-) diff --git a/include/hamlib/rig.h b/include/hamlib/rig.h index 4f2c55367..d3361dc28 100644 --- a/include/hamlib/rig.h +++ b/include/hamlib/rig.h @@ -2713,6 +2713,9 @@ extern HAMLIB_EXPORT(int) rig_open HAMLIB_PARAMS((RIG *rig)); * List Set/Get functions pairs */ +extern HAMLIB_EXPORT(int) +rig_flush_force(hamlib_port_t *port, int flush_async_data); + extern HAMLIB_EXPORT(int) rig_flush(hamlib_port_t *port); diff --git a/src/iofunc.c b/src/iofunc.c index dd26497f6..bbc6bebe7 100644 --- a/src/iofunc.c +++ b/src/iofunc.c @@ -787,6 +787,12 @@ int HAMLIB_API write_block_sync_error(hamlib_port_t *p, return async_pipe_write(p->sync_data_error_pipe, txbuffer, count, p->timeout); } +int HAMLIB_API port_flush_sync_pipes(hamlib_port_t *p) +{ + // TODO: To be implemented for Windows + return RIG_OK; +} + #else /* POSIX */ @@ -970,6 +976,38 @@ int HAMLIB_API write_block_sync_error(hamlib_port_t *p, return (int) write(p->fd_sync_error_write, txbuffer, count); } +int HAMLIB_API port_flush_sync_pipes(hamlib_port_t *p) +{ + unsigned char buf[1024]; + int n; + int nbytes; + + if (!p->asyncio) + { + return RIG_OK; + } + + rig_debug(RIG_DEBUG_TRACE, "%s: flushing sync pipes\n", __func__); + + nbytes = 0; + while ((n = read(p->fd_sync_read, buf, sizeof(buf))) > 0) + { + nbytes += n; + } + + rig_debug(RIG_DEBUG_TRACE, "read flushed %d bytes from sync read pipe\n", nbytes); + + nbytes = 0; + while ((n = read(p->fd_sync_error_read, buf, sizeof(buf))) > 0) + { + nbytes += n; + } + + rig_debug(RIG_DEBUG_TRACE, "read flushed %d bytes from sync error read pipe\n", nbytes); + + return RIG_OK; +} + #endif /** diff --git a/src/iofunc.h b/src/iofunc.h index 77b9df5b5..25ce29159 100644 --- a/src/iofunc.h +++ b/src/iofunc.h @@ -49,6 +49,8 @@ extern HAMLIB_EXPORT(int) write_block_sync_error(hamlib_port_t *p, const unsigned char *txbuffer, size_t count); +extern HAMLIB_EXPORT(int) port_flush_sync_pipes(hamlib_port_t *p); + extern HAMLIB_EXPORT(int) read_string(hamlib_port_t *p, unsigned char *rxbuffer, size_t rxmax, diff --git a/src/misc.c b/src/misc.c index 77eaf1e0e..d75ea91c4 100644 --- a/src/misc.c +++ b/src/misc.c @@ -2152,19 +2152,28 @@ int HAMLIB_API parse_hoststr(char *hoststr, int hoststr_len, char host[256], return -1; } -//K3 was showing stacked command replies so re-enabling this -//#define RIG_FLUSH_REMOVE -int HAMLIB_API rig_flush(hamlib_port_t *port) + +/** + * \brief Force flush of rig communication data buffers. + * \param port communication port + * \param flush_async_data Flushes also asynchronous I/O pipes if non-zero. + * \return status code + * + * This function should be used only in special cases like after handling raw command data from Hamlib clients. + * When asynchronous I/O is enabled, responses to raw commands may disrupt processing of all commands, + * because the responses and up in the async I/O pipes. + */ +int HAMLIB_API rig_flush_force(hamlib_port_t *port, int flush_async_data) { if (port->type.rig == RIG_PORT_NONE) { return RIG_OK; } - // Data should never be flushed when using async I/O - if (port->asyncio) + // Flush also the async I/O pipes + if (port->asyncio && flush_async_data) { - return RIG_OK; + port_flush_sync_pipes(port); } #ifndef RIG_FLUSH_REMOVE @@ -2190,6 +2199,17 @@ int HAMLIB_API rig_flush(hamlib_port_t *port) #endif } +int HAMLIB_API rig_flush(hamlib_port_t *port) +{ + // Data should never be flushed when using async I/O + if (port->asyncio) + { + return RIG_OK; + } + + return rig_flush_force(port, 0); +} + static const struct { diff --git a/src/rig.c b/src/rig.c index 7450a5055..a06c38d35 100644 --- a/src/rig.c +++ b/src/rig.c @@ -7771,6 +7771,7 @@ HAMLIB_EXPORT(int) rig_send_raw(RIG *rig, const unsigned char *send, if (retval < RIG_OK) { rig_debug(RIG_DEBUG_ERR, "%s: read_string, result=%d\n", __func__, retval); + rig_flush_force(&rs->rigport, 1); set_transaction_inactive(rig); RETURNFUNC(retval); } @@ -7781,6 +7782,7 @@ HAMLIB_EXPORT(int) rig_send_raw(RIG *rig, const unsigned char *send, { rig_debug(RIG_DEBUG_ERR, "%s: reply_len(%d) less than reply from rig(%d)\n", __func__, reply_len, nbytes); + rig_flush_force(&rs->rigport, 1); set_transaction_inactive(rig); return -RIG_EINVAL; } @@ -7790,10 +7792,12 @@ HAMLIB_EXPORT(int) rig_send_raw(RIG *rig, const unsigned char *send, } else { + rig_flush_force(&rs->rigport, 1); set_transaction_inactive(rig); RETURNFUNC(retval); } + rig_flush_force(&rs->rigport, 1); set_transaction_inactive(rig); ELAPSED2; diff --git a/tests/rigctl_parse.c b/tests/rigctl_parse.c index ecddf6d25..a79e4417d 100644 --- a/tests/rigctl_parse.c +++ b/tests/rigctl_parse.c @@ -4893,6 +4893,8 @@ declare_proto_rig(send_cmd) rig_debug(RIG_DEBUG_TRACE, "%s: rigport=%d, bufcmd=%s, cmd_len=%d\n", __func__, rs->rigport.fd, hasbinary(bufcmd, cmd_len) ? "BINARY" : bufcmd, cmd_len); + set_transaction_active(rig); + if (simulate) { rig_debug(RIG_DEBUG_VERBOSE, "%s: simulating response for model %s\n", @@ -4910,6 +4912,8 @@ declare_proto_rig(send_cmd) if (retval != RIG_OK) { + rig_flush_force(&rs->rigport, 1); + set_transaction_inactive(rig); RETURNFUNC(retval); } } @@ -5002,6 +5006,9 @@ declare_proto_rig(send_cmd) strncat(hexbuf, hex, hexbufbytes - 1); } + rig_flush_force(&rs->rigport, 1); + set_transaction_inactive(rig); + rig_debug(RIG_DEBUG_TRACE, "%s: binary=%s, retval=%d\n", __func__, hexbuf, retval); fprintf(fout, "%s %d\n", hexbuf, retval); @@ -5016,6 +5023,9 @@ declare_proto_rig(send_cmd) } while (retval > 0 && rxbytes == BUFSZ); + rig_flush_force(&rs->rigport, 1); + set_transaction_inactive(rig); + // we use fwrite in case of any nulls in binary return if (binary) { fwrite(buf, 1, retval, fout); } From c75fdeb3e4a6579d9ecf841bea0c9bce9793997f Mon Sep 17 00:00:00 2001 From: Mikael Nousiainen Date: Sun, 14 May 2023 11:52:48 +0300 Subject: [PATCH 7/8] Make retries in case of read timeout optional and configurable via set-conf option. When not absolutely necessary, they will significantly slow down flushing and normal serial communications with a rig --- include/hamlib/rig.h | 5 +++-- src/conf.c | 18 ++++++++++++++++++ src/iofunc.c | 11 +++++------ src/token.h | 2 ++ 4 files changed, 28 insertions(+), 8 deletions(-) diff --git a/include/hamlib/rig.h b/include/hamlib/rig.h index d3361dc28..718b7635d 100644 --- a/include/hamlib/rig.h +++ b/include/hamlib/rig.h @@ -2292,8 +2292,8 @@ typedef struct hamlib_port { int value; /*!< Toggle PTT ON or OFF */ } gpio; /*!< GPIO attributes */ } parm; /*!< Port parameter union */ - int client_port; /*!< client socket port for tcp connection */ - RIG *rig; /*!< our parent RIG device */ + int client_port; /*!< client socket port for tcp connection */ + RIG *rig; /*!< our parent RIG device */ int asyncio; /*!< enable asynchronous data handling if true -- async collides with python keyword so _async is used */ #if defined(_WIN32) hamlib_async_pipe_t *sync_data_pipe; /*!< pipe data structure for synchronous data */ @@ -2304,6 +2304,7 @@ typedef struct hamlib_port { int fd_sync_error_write; /*!< file descriptor for writing synchronous data error codes */ int fd_sync_error_read; /*!< file descriptor for reading synchronous data error codes */ #endif + short timeout_retry; /*!< number of retries to make in case of read timeout errors, some serial interfaces may require this, 0 to disable */ } hamlib_port_t; diff --git a/src/conf.c b/src/conf.c index 7529c87c0..e26e0c077 100644 --- a/src/conf.c +++ b/src/conf.c @@ -69,6 +69,11 @@ static const struct confparams frontend_cfg_params[] = TOK_RETRY, "retry", "Retry", "Max number of retry", "0", RIG_CONF_NUMERIC, { .n = { 0, 10, 1 } } }, + { + TOK_TIMEOUT_RETRY, "timeout_retry", "Number of retries for read timeouts", + "Set the number of retries for data read timeouts that may occur especially with some serial interfaces", + "0", RIG_CONF_NUMERIC, { .n = { 0, 100, 1 } } + }, { TOK_RANGE_SELECTED, "Selected range list", "Range list#", "The tx/rx range list in use", @@ -738,6 +743,15 @@ static int frontend_set_conf(RIG *rig, token_t token, const char *val) rs->tuner_control_pathname = strdup(val); // yeah -- need to free it break; + case TOK_TIMEOUT_RETRY: + if (1 != sscanf(val, "%ld", &val_i)) + { + return -RIG_EINVAL; + } + + rs->rigport.timeout_retry = val_i; + break; + case TOK_OFFSET_VFOA: if (1 != sscanf(val, "%ld", &val_i)) { @@ -1111,6 +1125,10 @@ static int frontend_get_conf2(RIG *rig, token_t token, char *val, int val_len) SNPRINTF(val, val_len, "%d", rs->async_data_enabled); break; + case TOK_TIMEOUT_RETRY: + SNPRINTF(val, val_len, "%d", rs->rigport.timeout_retry); + break; + default: return -RIG_EINVAL; } diff --git a/src/iofunc.c b/src/iofunc.c index bbc6bebe7..7354ab53e 100644 --- a/src/iofunc.c +++ b/src/iofunc.c @@ -1321,7 +1321,7 @@ static int read_string_generic(hamlib_port_t *p, memset(rxbuffer, 0, rxmax); - int flag = 0; // we will allow one timeout + short timeout_retries = p->timeout_retry; while (total_count < rxmax - 1) // allow 1 byte for end-of-string { @@ -1332,12 +1332,11 @@ static int read_string_generic(hamlib_port_t *p, if (result == -RIG_ETIMEOUT) { - rig_debug(RIG_DEBUG_CACHE, "%s: flag=%d\n", __func__, flag); - - if (flag == 0) + if (timeout_retries > 0) { - flag = 1; - hl_usleep(50 * 1000); + rig_debug(RIG_DEBUG_CACHE, "%s: retrying read timeout %d/%d\n", __func__, + timeout_retries + 1, p->timeout_retry); + hl_usleep(10 * 1000); continue; } diff --git a/src/token.h b/src/token.h index 703dc58c3..f3c4ad648 100644 --- a/src/token.h +++ b/src/token.h @@ -95,6 +95,8 @@ #define TOK_ASYNC TOKEN_FRONTEND(37) /** \brief Tuner external control pathname */ #define TOK_TUNER_CONTROL_PATHNAME TOKEN_FRONTEND(38) +/** \brief Number of retries permitted in case of read timeouts */ +#define TOK_TIMEOUT_RETRY TOKEN_FRONTEND(39) /* * rig specific tokens From 93e8a2879d0a74c60843c9942c2759178b746383 Mon Sep 17 00:00:00 2001 From: Mikael Nousiainen Date: Sun, 14 May 2023 11:57:09 +0300 Subject: [PATCH 8/8] Fix read timeout retry logic --- src/iofunc.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/iofunc.c b/src/iofunc.c index 7354ab53e..87634badd 100644 --- a/src/iofunc.c +++ b/src/iofunc.c @@ -1163,6 +1163,8 @@ static int read_block_generic(hamlib_port_t *p, unsigned char *rxbuffer, /* Store the time of the read loop start */ gettimeofday(&start_time, NULL); + short timeout_retries = p->timeout_retry; + while (count > 0) { int result; @@ -1172,6 +1174,15 @@ static int read_block_generic(hamlib_port_t *p, unsigned char *rxbuffer, if (result == -RIG_ETIMEOUT) { + if (timeout_retries > 0) + { + timeout_retries--; + rig_debug(RIG_DEBUG_CACHE, "%s: retrying read timeout %d/%d\n", __func__, + p->timeout_retry - timeout_retries, p->timeout_retry); + hl_usleep(10 * 1000); + continue; + } + /* Record timeout time and calculate elapsed time */ gettimeofday(&end_time, NULL); timersub(&end_time, &start_time, &elapsed_time); @@ -1334,8 +1345,9 @@ static int read_string_generic(hamlib_port_t *p, { if (timeout_retries > 0) { + timeout_retries--; rig_debug(RIG_DEBUG_CACHE, "%s: retrying read timeout %d/%d\n", __func__, - timeout_retries + 1, p->timeout_retry); + p->timeout_retry - timeout_retries, p->timeout_retry); hl_usleep(10 * 1000); continue; }