From 014bc04ddf7ef18b344acdb91663c58ba5156250 Mon Sep 17 00:00:00 2001 From: Mike Black W9MDB Date: Fri, 13 Aug 2021 07:42:39 -0500 Subject: [PATCH] Fix Icom rigs to use 0x25 command if capable Fixes #1 and and #2 in the issue https://github.com/Hamlib/Hamlib/issues/762 --- rigs/icom/icom.c | 176 +++++++++++++++++++++++++++++++++++++++-------- rigs/icom/icom.h | 3 +- src/rig.c | 43 +++++++++--- 3 files changed, 184 insertions(+), 38 deletions(-) diff --git a/rigs/icom/icom.c b/rigs/icom/icom.c index 3707736f9..ea506028e 100644 --- a/rigs/icom/icom.c +++ b/rigs/icom/icom.c @@ -902,6 +902,7 @@ static int icom_set_default_vfo(RIG *rig) { rig_debug(RIG_DEBUG_TRACE, "%s: setting default as MAIN/VFOA\n", __func__); + TRACE; retval = rig_set_vfo(rig, RIG_VFO_MAIN); // we'll default to Main in this case if (retval != RIG_OK) @@ -925,6 +926,7 @@ static int icom_set_default_vfo(RIG *rig) { rig_debug(RIG_DEBUG_TRACE, "%s: setting default as MAIN\n", __func__); + TRACE; retval = rig_set_vfo(rig, RIG_VFO_MAIN); // we'll default to Main in this case rig->state.current_vfo = RIG_VFO_MAIN; } @@ -932,9 +934,14 @@ static int icom_set_default_vfo(RIG *rig) { rig_debug(RIG_DEBUG_TRACE, "%s: setting default as VFOA\n", __func__); + TRACE; + retval = RIG_OK; + if (rig->state.current_vfo != RIG_VFO_A) + { retval = rig_set_vfo(rig, RIG_VFO_A); // we'll default to VFOA for all others rig->state.current_vfo = RIG_VFO_A; + } } else { @@ -1009,7 +1016,7 @@ int icom_set_freq(RIG *rig, vfo_t vfo, freq_t freq) rs = &rig->state; priv = (struct icom_priv_data *) rs->priv; - if (rig->state.current_vfo == RIG_VFO_NONE && vfo == RIG_VFO_CURR) + if (rig->state.current_vfo == RIG_VFO_NONE) { icom_set_default_vfo(rig); } @@ -1021,16 +1028,20 @@ int icom_set_freq(RIG *rig, vfo_t vfo, freq_t freq) rig_strvfo(vfo)); } - rig_debug(RIG_DEBUG_TRACE, "%s: set_vfo_curr=%s\n", __func__, - rig_strvfo(rig->state.current_vfo)); - retval = set_vfo_curr(rig, vfo, rig->state.current_vfo); - - if (retval != RIG_OK) + if (!(rig->caps->targetable_vfo & RIG_TARGETABLE_FREQ)) { - RETURNFUNC(retval); + TRACE; + rig_debug(RIG_DEBUG_TRACE, "%s: set_vfo_curr=%s\n", __func__, + rig_strvfo(rig->state.current_vfo)); + retval = set_vfo_curr(rig, vfo, rig->state.current_vfo); + + if (retval != RIG_OK) + { + RETURNFUNC(retval); + } } - retval = rig_get_freq(rig, RIG_VFO_CURR, &curr_freq); + retval = rig_get_freq(rig, vfo, &curr_freq); if (retval != RIG_OK) { @@ -1043,10 +1054,37 @@ int icom_set_freq(RIG *rig, vfo_t vfo, freq_t freq) */ to_bcd(freqbuf, freq, freq_len * 2); - cmd = C_SET_FREQ; - subcmd = -1; - retval = icom_transaction(rig, cmd, subcmd, freqbuf, freq_len, ackbuf, + // mike + if (rig->caps->targetable_vfo & RIG_TARGETABLE_FREQ) + { + vfo_t vfo_unselected = RIG_VFO_B | RIG_VFO_SUB | RIG_VFO_SUB_B | RIG_VFO_MAIN_B; + // if we are on the "other" vfo already then we have to allow for that + if (rig->state.current_vfo & vfo_unselected) + { + TRACE; + vfo_unselected = RIG_VFO_A | RIG_VFO_MAIN | RIG_VFO_SUB_A | RIG_VFO_MAIN_A; + } + + rig_debug(RIG_DEBUG_VERBOSE, "%s(%d): vfo=%s, currvfo=%s\n", __func__, __LINE__, rig_strvfo(vfo), rig_strvfo(rig->state.current_vfo)); + subcmd = 0x00; + // if we ask for unselected but we're not on unselected subcmd2 changes + if ((vfo & vfo_unselected) && !(rig->state.current_vfo & vfo_unselected)) + { + TRACE; + subcmd = 0x01; // get unselected VFO + } + + cmd = 0x25; + retval = icom_transaction(rig, cmd, subcmd, freqbuf, freq_len, ackbuf, &ack_len); + } + else + { + cmd = C_SET_FREQ; + subcmd = -1; + retval = icom_transaction(rig, cmd, subcmd, freqbuf, freq_len, ackbuf, + &ack_len); + } hl_usleep(50 * 1000); // pause for transceive message and we'll flush it if (retval != RIG_OK) @@ -1677,6 +1715,48 @@ int icom_set_dsp_flt(RIG *rig, rmode_t mode, pbwidth_t width) RETURNFUNC(RIG_OK); } +static int icom_set_mode_x26(RIG *rig, vfo_t vfo, rmode_t mode, int datamode, int filter) +{ + struct icom_priv_data *priv = rig->state.priv; + int retval; + unsigned char buf[3]; + + ENTERFUNC; + if (priv->x26cmdfails) RETURNFUNC(-RIG_ENAVAIL); + + int cmd2 = 0x26; + int subcmd2 = 0x00; + vfo_t vfo_unselected = RIG_VFO_B | RIG_VFO_SUB | RIG_VFO_SUB_B | RIG_VFO_MAIN_B; + // if we are on the "other" vfo already then we have to allow for that + if (rig->state.current_vfo & vfo_unselected) + { + vfo_unselected = RIG_VFO_A | RIG_VFO_MAIN | RIG_VFO_SUB_A | RIG_VFO_MAIN_A; + } + + // if we ask for unselected but we're not on unselected subcmd2 changes + if ((vfo & vfo_unselected) && !(rig->state.current_vfo & vfo_unselected)) + { + subcmd2 = 0x01; // get unselected VFO + } + buf[0] = mode; + buf[1] = datamode; + // filter fixed to filter 1 due to IC7300 bug defaulting to filter 2 on mode changed -- yuck!! + // buf[2] = filter // if Icom ever fixed this + buf[2] = 1; + + retval = icom_transaction(rig, cmd2, subcmd2, buf, 3, NULL, NULL); + + if (retval != RIG_OK) + { + priv->x26cmdfails = 1; + rig_debug(RIG_DEBUG_WARN, + "%s: rig does not support 0x26 CI-V cmd\n", __func__); + return -RIG_ENAVAIL; + } + + RETURNFUNC(RIG_OK); +} + /* * icom_set_mode_with_data */ @@ -1687,6 +1767,7 @@ int icom_set_mode_with_data(RIG *rig, vfo_t vfo, rmode_t mode, unsigned char ackbuf[MAXFRAMELEN]; int ack_len = sizeof(ackbuf); rmode_t icom_mode; + //struct icom_priv_data *priv = (struct icom_priv_data *) rig->state.priv; unsigned char dm_sub_cmd = rig->caps->rig_model == RIG_MODEL_IC7200 ? 0x04 : S_MEM_DATA_MODE; int filter_byte = rig->caps->rig_model == RIG_MODEL_IC7100 @@ -1728,8 +1809,8 @@ int icom_set_mode_with_data(RIG *rig, vfo_t vfo, rmode_t mode, break; } - rig_debug(RIG_DEBUG_VERBOSE, "%s mode=%d, width=%d\n", __func__, (int)icom_mode, - (int)width); + rig_debug(RIG_DEBUG_VERBOSE, "%s mode=%d, width=%d, curr_vfo=%s\n", __func__, (int)icom_mode, + (int)width, rig_strvfo(rig->state.current_vfo)); retval = icom_set_mode(rig, vfo, icom_mode, width); hl_usleep(50 * 1000); // pause for possible transceive message which we'll flush @@ -1739,21 +1820,21 @@ int icom_set_mode_with_data(RIG *rig, vfo_t vfo, rmode_t mode, unsigned char datamode[2]; unsigned char mode_icom; // Not used, we only need the width signed char width_icom; - + + TRACE; switch (mode) { case RIG_MODE_PKTUSB: case RIG_MODE_PKTLSB: case RIG_MODE_PKTFM: case RIG_MODE_PKTAM: - /* some rigs (e.g. IC-7700 & IC-7800) - have D1/2/3 but we cannot know - which to set so just set D1 */ datamode[0] = 0x01; + datamode[1] = 0x01; // default to filter 1 break; default: datamode[0] = 0x00; + datamode[1] = 0x01; // default to filter 1 break; } @@ -1761,13 +1842,20 @@ int icom_set_mode_with_data(RIG *rig, vfo_t vfo, rmode_t mode, if (filter_byte) // then we need the filter width byte too { - if (width_icom == -1) datamode[1] = 1; // default to filter 1 - else datamode[1] = width_icom; - retval = + TRACE; + if (datamode[0] == 0) datamode[1]=0; // the only good combo possible according to manual + + rig_debug(RIG_DEBUG_TRACE, "%s(%d) mode_icom=%d, datamode[0]=%d, filter=%d\n", __func__, __LINE__, mode_icom, datamode[0], datamode[1]); + retval = icom_set_mode_x26(rig, vfo, mode_icom, datamode[0], datamode[1]); + if (retval != RIG_OK) + { + retval = icom_transaction(rig, C_CTL_MEM, dm_sub_cmd, datamode, 2, ackbuf, &ack_len); + } } else { + TRACE; retval = icom_transaction(rig, C_CTL_MEM, dm_sub_cmd, datamode, 1, ackbuf, &ack_len); } @@ -1805,9 +1893,10 @@ int icom_set_mode(RIG *rig, vfo_t vfo, rmode_t mode, pbwidth_t width) unsigned char icmode; signed char icmode_ext; int ack_len = sizeof(ackbuf), retval, err; + int swapvfos = 0; - rig_debug(RIG_DEBUG_VERBOSE, "%s called vfo=%s, mode=%s, width=%d\n", __func__, - rig_strvfo(vfo), rig_strrmode(mode), (int)width); + rig_debug(RIG_DEBUG_VERBOSE, "%s called vfo=%s, mode=%s, width=%d, current_vfo=%s\n", __func__, + rig_strvfo(vfo), rig_strrmode(mode), (int)width, rig_strvfo(rig->state.current_vfo)); rs = &rig->state; priv = (struct icom_priv_data *) rs->priv; @@ -1845,12 +1934,28 @@ int icom_set_mode(RIG *rig, vfo_t vfo, rmode_t mode, pbwidth_t width) icmode_ext = -1; } + // some Icom rigs have seperate modes for VFOB/Sub + // switching to VFOB should not matter for the other rigs + // This needs to be improved for RIG_TARGETABLE_MODE rigs + if ((vfo == RIG_VFO_B || vfo == RIG_VFO_SUB) && ((rig->state.current_vfo == RIG_VFO_A || rig->state.current_vfo == RIG_VFO_MAIN) || rig->state.current_vfo == RIG_VFO_CURR)) + { + TRACE; + swapvfos = 1; + rig_set_vfo(rig,RIG_VFO_B); + } + rig_debug(RIG_DEBUG_VERBOSE, "%s: #2 icmode=%d, icmode_ext=%d\n", __func__, icmode, icmode_ext); retval = icom_transaction(rig, C_SET_MODE, icmode, (unsigned char *) &icmode_ext, (icmode_ext == -1 ? 0 : 1), ackbuf, &ack_len); + if (swapvfos) + { + TRACE; + rig_set_vfo(rig,RIG_VFO_A); + } + if (retval != RIG_OK) { RETURNFUNC(retval); @@ -2125,6 +2230,7 @@ int icom_get_mode(RIG *rig, vfo_t vfo, rmode_t *mode, pbwidth_t *width) { rig_debug(RIG_DEBUG_TRACE, "%s(%d): forcing default VFO_A\n", __func__, __LINE__); + TRACE; rig_set_vfo(rig, RIG_VFO_A); // force VFOA } @@ -2147,8 +2253,10 @@ int icom_get_mode(RIG *rig, vfo_t vfo, rmode_t *mode, pbwidth_t *width) if (vfosave != vfo) { // right now forcing VFOA/B arrangement -- reverse not supported yet - TRACE; - rig_set_vfo(rig, RIG_VFO_B); + // If VFOB width is ever different than VFOA + // we need to figure out how to read VFOB without swapping VFOs + //TRACE; + //rig_set_vfo(rig, RIG_VFO_B); retval = icom_get_dsp_flt(rig, *mode); *width = retval; @@ -2159,7 +2267,8 @@ int icom_get_mode(RIG *rig, vfo_t vfo, rmode_t *mode, pbwidth_t *width) rig->state.cache.widthMainB = retval; rig_debug(RIG_DEBUG_TRACE, "%s(%d): vfosave=%s, currvfo=%s\n", __func__, __LINE__, rig_strvfo(vfo), rig_strvfo(rig->state.current_vfo)); - rig_set_vfo(rig, RIG_VFO_A); + //TRACE; + //rig_set_vfo(rig, RIG_VFO_A); rig_debug(RIG_DEBUG_TRACE, "%s: vfo=%s returning mode=%s, width=%d\n", __func__, rig_strvfo(vfo), rig_strrmode(*mode), (int)*width); } @@ -4897,7 +5006,8 @@ int icom_set_split_freq(RIG *rig, vfo_t vfo, freq_t tx_freq) rig_debug(RIG_DEBUG_TRACE, "%s: rx_vfo=%s, tx_vfo=%s\n", __func__, rig_strvfo(rx_vfo), rig_strvfo(tx_vfo)); - if (RIG_OK != (retval = rig_set_vfo(rig, tx_vfo))) + TRACE; + if (!(rig->caps->targetable_vfo & RIG_TARGETABLE_FREQ) && RIG_OK != (retval = rig_set_vfo(rig, tx_vfo))) { RETURNFUNC(retval); } @@ -4915,13 +5025,15 @@ int icom_set_split_freq(RIG *rig, vfo_t vfo, freq_t tx_freq) __func__, priv->split_on, rig_strvfo(rx_vfo)); - if (RIG_OK != (retval = rig_set_vfo(rig, rx_vfo))) + TRACE; + if (!(rig->caps->targetable_vfo & RIG_TARGETABLE_FREQ) && RIG_OK != (retval = rig_set_vfo(rig, rx_vfo))) { RETURNFUNC(retval); } } else if (RIG_OK != (retval = rig_set_vfo(rig, rx_vfo))) { + TRACE; RETURNFUNC(retval); } @@ -5138,6 +5250,7 @@ int icom_get_split_freq(RIG *rig, vfo_t vfo, freq_t *tx_freq) rig_debug(RIG_DEBUG_TRACE, "%s: SATMODE rig so returning vfo to %s\n", __func__, rig_strvfo(rx_vfo)); + TRACE; if (RIG_OK != (retval = rig_set_vfo(rig, rx_vfo))) { RETURNFUNC(retval); @@ -5145,6 +5258,7 @@ int icom_get_split_freq(RIG *rig, vfo_t vfo, freq_t *tx_freq) } else if (RIG_OK != (retval = rig_set_vfo(rig, rx_vfo))) { + TRACE; RETURNFUNC(retval); } @@ -5254,7 +5368,8 @@ int icom_set_split_mode(RIG *rig, vfo_t vfo, rmode_t tx_mode, RETURNFUNC(retval); } - if (RIG_OK != (retval = rig_set_vfo(rig, rx_vfo))) + TRACE; + if (!(rig->caps->targetable_vfo & RIG_TARGETABLE_MODE) && RIG_OK != (retval = rig_set_vfo(rig, rx_vfo))) { RETURNFUNC(retval); } @@ -5365,6 +5480,7 @@ int icom_get_split_mode(RIG *rig, vfo_t vfo, rmode_t *tx_mode, RETURNFUNC(retval); } + TRACE; if (RIG_OK != (retval = rig_set_vfo(rig, rx_vfo))) { RETURNFUNC(retval); @@ -5515,6 +5631,7 @@ int icom_set_split_freq_mode(RIG *rig, vfo_t vfo, freq_t tx_freq, RETURNFUNC(retval); } + TRACE; if (!(rig->caps->targetable_vfo & RIG_TARGETABLE_MODE) && RIG_OK != (retval = rig_set_vfo(rig, tx_vfo))) { RETURNFUNC(retval); @@ -5526,6 +5643,7 @@ int icom_set_split_freq_mode(RIG *rig, vfo_t vfo, freq_t tx_freq, RETURNFUNC(retval); } + TRACE; if (!(rig->caps->targetable_vfo & RIG_TARGETABLE_MODE) && RIG_OK != (retval = rig_set_vfo(rig, rx_vfo))) { RETURNFUNC(retval); @@ -5647,6 +5765,7 @@ int icom_get_split_freq_mode(RIG *rig, vfo_t vfo, freq_t *tx_freq, RETURNFUNC(retval); } + TRACE; if (RIG_OK != (retval = rig_set_vfo(rig, rx_vfo))) { RETURNFUNC(retval); @@ -8567,6 +8686,7 @@ static int set_vfo_curr(RIG *rig, vfo_t vfo, vfo_t curr_vfo) { rig_debug(RIG_DEBUG_TRACE, "%s: setting new vfo=%s\n", __func__, rig_strvfo(vfo)); + TRACE; retval = rig_set_vfo(rig, vfo); if (retval != RIG_OK) diff --git a/rigs/icom/icom.h b/rigs/icom/icom.h index 11dbcd23a..606e271c9 100644 --- a/rigs/icom/icom.h +++ b/rigs/icom/icom.h @@ -30,7 +30,7 @@ #include #endif -#define BACKEND_VER "20210801" +#define BACKEND_VER "20210812" #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) @@ -258,6 +258,7 @@ struct icom_priv_data freq_t vfoa_freq; /*!< Track last setting of vfoa -- used to return last freq when ptt is asserted */ freq_t vfob_freq; /*!< Track last setting of vfob -- used to return last freq when ptt is asserted */ int x25cmdfails; /*!< This will get set if the 0x25 command fails so we try just once */ + int x26cmdfails; /*!< This will get set if the 0x26 command fails so we try just once */ int x1cx03cmdfails; /*!< This will get set if the 0x1c 0x03 command fails so we try just once */ int poweron; /*!< To prevent powering on more than once */ unsigned char filter; /*!< Current filter selected */ diff --git a/src/rig.c b/src/rig.c index c4d5da700..28043dd93 100644 --- a/src/rig.c +++ b/src/rig.c @@ -1036,10 +1036,11 @@ int HAMLIB_API rig_open(RIG *rig) } else // vfo fails so set some sensible defaults { - int backend_num = RIG_BACKEND_NUM(rig->caps->rig_model); + //int backend_num = RIG_BACKEND_NUM(rig->caps->rig_model); rs->tx_vfo = RIG_VFO_TX; rs->current_vfo = RIG_VFO_CURR; +#if 0 // done in the back end if (backend_num == RIG_ICOM) { TRACE; @@ -1047,7 +1048,8 @@ int HAMLIB_API rig_open(RIG *rig) rig_debug(RIG_DEBUG_TRACE, "%s: Icom rig so default vfo = %s\n", __func__, rig_strvfo(rs->current_vfo)); } - else if (rig->caps->set_vfo == NULL) +#endif + if (rig->caps->set_vfo == NULL) { // for non-Icom rigs if there's no set_vfo then we need to set one rs->current_vfo = vfo_fixup(rig, RIG_VFO_A, rig->state.cache.split); @@ -2587,14 +2589,23 @@ pbwidth_t HAMLIB_API rig_passband_wide(RIG *rig, rmode_t mode) * * \sa rig_get_vfo() */ +#if BUILTINFUNC +#undef rig_set_vfo +int HAMLIB_API rig_set_vfo(RIG *rig, vfo_t vfo, const char *func) +#else int HAMLIB_API rig_set_vfo(RIG *rig, vfo_t vfo) +#endif { const struct rig_caps *caps; int retcode; freq_t curr_freq; ENTERFUNC; +#if BUILTINFUNC + rig_debug(RIG_DEBUG_VERBOSE, "%s called vfo=%s, called from %s\n", __func__, rig_strvfo(vfo),func); +#else rig_debug(RIG_DEBUG_VERBOSE, "%s called vfo=%s\n", __func__, rig_strvfo(vfo)); +#endif if (vfo == RIG_VFO_B || vfo == RIG_VFO_SUB) { @@ -2647,7 +2658,7 @@ int HAMLIB_API rig_set_vfo(RIG *rig, vfo_t vfo) TRACE; vfo_t vfo_save = rig->state.current_vfo; - rig->state.current_vfo = vfo; + if (vfo != RIG_VFO_CURR) rig->state.current_vfo = vfo; retcode = caps->set_vfo(rig, vfo); if (retcode == RIG_OK) @@ -3782,7 +3793,9 @@ int HAMLIB_API rig_set_split_freq(RIG *rig, vfo_t vfo, freq_t tx_freq) if (caps->set_vfo) { TRACE; - retcode = caps->set_vfo(rig, tx_vfo); + retcode = RIG_OK; + if (!(caps->targetable_vfo & RIG_TARGETABLE_FREQ)) + retcode = caps->set_vfo(rig, tx_vfo); } else if (rig_has_vfo_op(rig, RIG_OP_TOGGLE) && caps->vfo_op) { @@ -3825,7 +3838,9 @@ int HAMLIB_API rig_set_split_freq(RIG *rig, vfo_t vfo, freq_t tx_freq) if (caps->set_vfo) { TRACE; - rc2 = caps->set_vfo(rig, curr_vfo); + rc2 = RIG_OK; + if (!(caps->targetable_vfo & RIG_TARGETABLE_FREQ)) + rc2 = caps->set_vfo(rig, curr_vfo); } else { @@ -4439,7 +4454,7 @@ int HAMLIB_API rig_set_split_vfo(RIG *rig, RETURNFUNC(-RIG_ENAVAIL); } - vfo = vfo_fixup(rig, vfo, split); + vfo = vfo_fixup(rig, tx_vfo, split); if (vfo != RIG_VFO_A && vfo != RIG_VFO_B) { @@ -4447,7 +4462,12 @@ int HAMLIB_API rig_set_split_vfo(RIG *rig, } // set rig to the the requested RX VFO TRACE; - rig_set_vfo(rig, vfo == RIG_VFO_B?RIG_VFO_B:RIG_VFO_A); + if (!(caps->targetable_vfo & RIG_TARGETABLE_FREQ)) +#if BUILTINFUNC + rig_set_vfo(rig, vfo == RIG_VFO_B?RIG_VFO_B:RIG_VFO_A, __builtin_FUNCTION()); +#else + rig_set_vfo(rig, vfo == RIG_VFO_B?RIG_VFO_B:RIG_VFO_A); +#endif if (vfo == RIG_VFO_CURR || vfo == rig->state.current_vfo) @@ -4473,24 +4493,29 @@ int HAMLIB_API rig_set_split_vfo(RIG *rig, curr_vfo = rig->state.current_vfo; TRACE; - retcode = caps->set_vfo(rig, vfo); + if (!(caps->targetable_vfo & RIG_TARGETABLE_FREQ)) + { + retcode = caps->set_vfo(rig, vfo); if (retcode != RIG_OK) { RETURNFUNC(retcode); } + } TRACE; retcode = caps->set_split_vfo(rig, vfo, split, tx_vfo); /* try and revert even if we had an error above */ - rc2 = caps->set_vfo(rig, curr_vfo); + if (!(caps->targetable_vfo & RIG_TARGETABLE_FREQ)) { + rc2 = caps->set_vfo(rig, curr_vfo); if (RIG_OK == retcode) { /* return the first error code */ retcode = rc2; } + } if (retcode == RIG_OK) {