diff --git a/include/hamlib/rig.h b/include/hamlib/rig.h index 3842cb91b..c35d722c1 100644 --- a/include/hamlib/rig.h +++ b/include/hamlib/rig.h @@ -139,7 +139,7 @@ typedef struct rig RIG; #define FRQRANGESIZ 30 #define MAXCHANDESC 30 /* describe channel eg: "WWV 5Mhz" */ #define TSLSTSIZ 20 /* max tuning step list size, zero ended */ -#define FLTLSTSIZ 42 /* max mode/filter list size, zero ended */ +#define FLTLSTSIZ 60 /* max mode/filter list size, zero ended */ #define MAXDBLSTSIZ 8 /* max preamp/att levels supported, zero ended */ #define CHANLSTSIZ 16 /* max mem_list size, zero ended */ #define MAX_CAL_LENGTH 32 /* max calibration plots in cal_table_t */ @@ -805,6 +805,7 @@ typedef enum { RIG_MODE_SAL = (1<<17),/*!< \c SAL -- Synchronous AM lower sideband */ RIG_MODE_SAH = (1<<18),/*!< \c SAH -- Synchronous AM upper (higher) sideband */ RIG_MODE_DSB = (1<<19),/*!< \c DSB -- Double sideband suppressed carrier */ + RIG_MODE_FMN = (1<<21),/*!< \c FMN -- FM Narrow Kenwood ts990s */ RIG_MODE_TESTS_MAX /*!< \c MUST ALWAYS BE LAST, Max Count for dumpcaps.c */ } rmode_t; diff --git a/include/hamlib/riglist.h b/include/hamlib/riglist.h index 8e90c1c5f..fa7fb23f2 100644 --- a/include/hamlib/riglist.h +++ b/include/hamlib/riglist.h @@ -141,6 +141,7 @@ #define RIG_MODEL_F6K RIG_MAKE_MODEL(RIG_KENWOOD, 36) /* Flex 6000 Series */ #define RIG_MODEL_TS590SG RIG_MAKE_MODEL(RIG_KENWOOD, 37) #define RIG_MODEL_XG3 RIG_MAKE_MODEL(RIG_KENWOOD, 38) +#define RIG_MODEL_TS990S RIG_MAKE_MODEL(RIG_KENWOOD, 39) /* * Icom diff --git a/kenwood/Makefile.am b/kenwood/Makefile.am index 2aa5232c3..8526be00e 100644 --- a/kenwood/Makefile.am +++ b/kenwood/Makefile.am @@ -2,7 +2,7 @@ TSSRC = ts850.c ts870s.c ts570.c ts450s.c ts950.c ts50s.c \ ts790.c ts2000.c k2.c k3.c xg3.c ts930.c \ ts680.c ts690.c ts140.c ts480.c trc80.c ts590.c \ - flex6xxx.c + ts990s.c ts990s.h flex6xxx.c IC10SRC = ts440.c ts940.c ts711.c ts811.c r5000.c diff --git a/kenwood/kenwood.c b/kenwood/kenwood.c index 2fcde74f9..a58f48c40 100644 --- a/kenwood/kenwood.c +++ b/kenwood/kenwood.c @@ -39,6 +39,7 @@ #include "cal.h" #include "kenwood.h" +#include "ts990s.h" #ifndef max #define max(a,b) (((a) (b)) ? (a) : (b)) @@ -82,6 +83,7 @@ static const struct kenwood_id kenwood_id_list[] = { { RIG_MODEL_TS2000, 19 }, { RIG_MODEL_TS480, 20 }, { RIG_MODEL_TS590S, 21 }, + { RIG_MODEL_TS990S, 22 }, { RIG_MODEL_TS590SG, 23 }, { RIG_MODEL_NONE, UNKNOWN_ID }, /* end marker */ }; @@ -104,6 +106,7 @@ static const struct kenwood_id_string kenwood_id_string_list[] = { { RIG_MODEL_TS2000, "019" }, { RIG_MODEL_TS480, "020" }, { RIG_MODEL_TS590S, "021" }, + { RIG_MODEL_TS990S, "022" }, { RIG_MODEL_TS590SG, "023" }, { RIG_MODEL_THD7A, "TH-D7" }, { RIG_MODEL_THD7AG, "TH-D7G" }, @@ -672,7 +675,6 @@ int kenwood_set_vfo(RIG *rig, vfo_t vfo) char vfo_function; switch (vfo) { - case RIG_VFO_VFO: case RIG_VFO_A: vfo_function = '0'; break; @@ -717,7 +719,66 @@ int kenwood_set_vfo(RIG *rig, vfo_t vfo) } -/* FR FT +/* CB + * Sets the operating VFO, does not set split + * VFO, but leaves it unchanged if in split VFO mode. + * + */ +int kenwood_set_vfo_main_sub(RIG *rig, vfo_t vfo) +{ + rig_debug(RIG_DEBUG_VERBOSE, "%s called\n", __func__); + + if (!rig) + return -RIG_EINVAL; + + char cmdbuf[6]; + char vfo_function; + + switch (vfo) { + case RIG_VFO_MAIN: + vfo_function = '0'; + break; + + case RIG_VFO_SUB: + vfo_function = '1'; + break; + + case RIG_VFO_CURR: + return RIG_OK; + + default: + rig_debug(RIG_DEBUG_ERR, "%s: unsupported VFO %d\n", __func__, vfo); + return -RIG_EINVAL; + } + + sprintf(cmdbuf, "CB%c", vfo_function); + return kenwood_transaction(rig, cmdbuf, NULL, 0); +} + + +/* CB + * Gets the operating VFO + * + */ +int kenwood_get_vfo_main_sub(RIG *rig, vfo_t * vfo) +{ + char buf[4]; + int rc; + + rig_debug(RIG_DEBUG_VERBOSE, "%s called\n", __func__); + + if (!rig || !vfo) + return -RIG_EINVAL; + + if (RIG_OK == (rc = kenwood_safe_transaction(rig, "CB", buf, sizeof (buf), 3))) + { + *vfo = buf[2] == '1' ? RIG_VFO_SUB : RIG_VFO_MAIN; + } + return rc; +} + + +/* FR FT TB * Sets the split RX/TX VFO or M.CH mode of the transceiver. * */ @@ -733,9 +794,20 @@ int kenwood_set_split_vfo(RIG *rig, vfo_t vfo, split_t split, vfo_t txvfo) int retval; unsigned char vfo_function; + if (RIG_MODEL_TS990S == rig->caps->rig_model) + { + if (split) + { + // Rx MAIN/Tx SUB is the only split method + retval = kenwood_set_vfo_main_sub (rig, RIG_VFO_MAIN); + if (retval != RIG_OK) return retval; + } + sprintf(cmdbuf, "TB%c", RIG_SPLIT_ON == split ? '1' : '0'); + return kenwood_transaction(rig, cmdbuf, NULL, 0); + } + if(vfo != RIG_VFO_CURR) { switch (vfo) { - case RIG_VFO_VFO: case RIG_VFO_A: vfo_function = '0'; break; case RIG_VFO_B: vfo_function = '1'; break; case RIG_VFO_MEM: vfo_function = '2'; break; @@ -810,7 +882,7 @@ int kenwood_set_split(RIG *rig, vfo_t vfo, split_t split, vfo_t txvfo) } -/* IF +/* IF TB * Gets split VFO status from kenwood_get_if() * */ @@ -824,6 +896,25 @@ int kenwood_get_split_vfo_if(RIG *rig, vfo_t rxvfo, split_t *split, vfo_t *txvfo struct kenwood_priv_data *priv = rig->state.priv; int retval; + if (RIG_MODEL_TS990S == rig->caps->rig_model) + { + char buf[4]; + if (RIG_OK == (retval = kenwood_safe_transaction (rig, "TB", buf, sizeof (buf), 3))) + { + if ('1' == buf[2]) + { + *split = RIG_SPLIT_ON; + *txvfo = RIG_VFO_SUB; + } + else + { + *split = RIG_SPLIT_OFF; + *txvfo = RIG_VFO_MAIN; + } + } + return retval; + } + retval = kenwood_get_if(rig); if (retval != RIG_OK) return retval; @@ -935,9 +1026,17 @@ int kenwood_set_freq(RIG *rig, vfo_t vfo, freq_t freq) tvfo = (vfo==RIG_VFO_CURR || vfo==RIG_VFO_VFO) ? rig->state.current_vfo : vfo; switch (tvfo) { - case RIG_VFO_A: vfo_letter = 'A'; break; - case RIG_VFO_B: vfo_letter = 'B'; break; - case RIG_VFO_C: vfo_letter = 'C'; break; + case RIG_VFO_A: + case RIG_VFO_MAIN: + vfo_letter = 'A'; + break; + case RIG_VFO_B: + case RIG_VFO_SUB: + vfo_letter = 'B'; + break; + case RIG_VFO_C: + vfo_letter = 'C'; + break; default: rig_debug(RIG_DEBUG_ERR, "%s: unsupported VFO %d\n", __func__, vfo); return -RIG_EINVAL; @@ -965,20 +1064,20 @@ int kenwood_set_freq(RIG *rig, vfo_t vfo, freq_t freq) err = kenwood_get_if(rig); if (RIG_OK != err) { - return err; + return err; } if ('1' == priv->info[32] && priv->info[30] != ('A' == vfo_letter ? '0' : '1')) { - /* split mode and setting "back" VFO */ + /* split mode and setting "back" VFO */ - /* set other VFO to whatever it is at currently */ - err = kenwood_safe_transaction (rig, 'A' == vfo_letter ? "FB" : "FA", freqbuf, 16, 13); - if (RIG_OK != err) - { - return err; - } - err = kenwood_transaction (rig, freqbuf, NULL, 0); + /* set other VFO to whatever it is at currently */ + err = kenwood_safe_transaction (rig, 'A' == vfo_letter ? "FB" : "FA", freqbuf, 16, 13); + if (RIG_OK != err) + { + return err; + } + err = kenwood_transaction (rig, freqbuf, NULL, 0); } } @@ -1032,9 +1131,17 @@ int kenwood_get_freq(RIG *rig, vfo_t vfo, freq_t *freq) } switch (tvfo) { - case RIG_VFO_A: vfo_letter = 'A'; break; - case RIG_VFO_B: vfo_letter = 'B'; break; - case RIG_VFO_C: vfo_letter = 'C'; break; + case RIG_VFO_A: + case RIG_VFO_MAIN: + vfo_letter = 'A'; + break; + case RIG_VFO_B: + case RIG_VFO_SUB: + vfo_letter = 'B'; + break; + case RIG_VFO_C: + vfo_letter = 'C'; + break; default: rig_debug(RIG_DEBUG_ERR, "%s: unsupported VFO %d\n", __func__, vfo); @@ -1133,7 +1240,14 @@ int kenwood_scan(RIG *rig, vfo_t vfo, scan_t scan, int ch) if (!rig) return -RIG_EINVAL; - return kenwood_transaction(rig, scan == RIG_SCAN_STOP ? "SC0" : "SC1", NULL, 0); + if (RIG_MODEL_TS990S == rig->caps->rig_model) + { + return kenwood_transaction(rig, scan == RIG_SCAN_STOP ? "SC00" : "SC01", NULL, 0); + } + else + { + return kenwood_transaction(rig, scan == RIG_SCAN_STOP ? "SC0" : "SC1", NULL, 0); + } } /* @@ -1193,19 +1307,19 @@ int kenwood_set_mode(RIG *rig, vfo_t vfo, rmode_t mode, pbwidth_t width) switch (mode) { case RIG_MODE_PKTUSB: - data_mode = '1'; - mode = RIG_MODE_USB; - break; + data_mode = '1'; + mode = RIG_MODE_USB; + break; case RIG_MODE_PKTLSB: - data_mode = '1'; - mode = RIG_MODE_LSB; - break; + data_mode = '1'; + mode = RIG_MODE_LSB; + break; case RIG_MODE_PKTFM: - data_mode = '1'; - mode = RIG_MODE_FM; - break; + data_mode = '1'; + mode = RIG_MODE_FM; + break; default: break; } @@ -1214,34 +1328,66 @@ int kenwood_set_mode(RIG *rig, vfo_t vfo, rmode_t mode, pbwidth_t width) kmode = rmode2kenwood(mode, caps->mode_table); if (kmode < 0 ) { rig_debug(RIG_DEBUG_WARN, "%s: unsupported mode '%s'\n", - __func__, rig_strrmode(mode)); + __func__, rig_strrmode(mode)); return -RIG_EINVAL; } - sprintf(buf, "MD%c", '0' + kmode); - err = kenwood_transaction(rig, buf, NULL, 0); - if (err != RIG_OK) - return err; + if (RIG_MODEL_TS990S == rig->caps->rig_model) + { + /* The TS990s has targetable read mode but can only set the mode + of the current VFO :( So we need to toggle the operating VFO + to set the "back" VFO mode. This is done here rather than not + setting caps.targetable_vfo to not include + RIG_TARGETABLE_MODE since the toggle is not required for + reading the mode. */ + char c; + vfo_t curr_vfo; + err = kenwood_get_vfo_main_sub (rig, &curr_vfo); + if (err != RIG_OK) return err; + if (kmode <= 9) + { + c = '0' + kmode; + } + else + { + c = 'A' + kmode - 10; + } + if (vfo != RIG_VFO_CURR && vfo != curr_vfo) + { + err = kenwood_set_vfo_main_sub (rig, vfo); + if (err != RIG_OK) return err; + } + sprintf(buf, "OM0%c", c); /* target vfo is ignored */ + int err = kenwood_transaction(rig, buf, NULL, 0); + if (vfo != RIG_VFO_CURR && vfo != curr_vfo) + { + int err2 = kenwood_set_vfo_main_sub (rig, curr_vfo); + if (RIG_OK == err && err2 != RIG_OK) return err2; + } + } + else + { + sprintf(buf, "MD%c", '0' + kmode); + err = kenwood_transaction(rig, buf, NULL, 0); + } + if (err != RIG_OK) return err; if (RIG_MODEL_TS590S == rig->caps->rig_model || RIG_MODEL_TS590SG == rig->caps->rig_model) { /* supports DATA sub modes - see above */ sprintf (buf, "DA%c", data_mode); - int retval = kenwood_transaction (rig, buf, NULL, 0); - if (RIG_OK != retval) - { - return retval; - } + err = kenwood_transaction (rig, buf, NULL, 0); + if (err != RIG_OK) return err; } if (rig->caps->rig_model == RIG_MODEL_TS450S - || rig->caps->rig_model == RIG_MODEL_TS690S - || rig->caps->rig_model == RIG_MODEL_TS850 - || rig->caps->rig_model == RIG_MODEL_TS950SDX) { + || rig->caps->rig_model == RIG_MODEL_TS690S + || rig->caps->rig_model == RIG_MODEL_TS850 + || rig->caps->rig_model == RIG_MODEL_TS950SDX) { if (RIG_PASSBAND_NORMAL == width) - width = rig_passband_normal(rig, mode); + width = rig_passband_normal(rig, mode); err = kenwood_set_filter(rig, width); /* non fatal */ } @@ -1306,14 +1452,53 @@ int kenwood_get_mode(RIG *rig, vfo_t vfo, rmode_t *mode, pbwidth_t *width) return -RIG_EINVAL; struct kenwood_priv_caps *caps = kenwood_caps(rig); + char cmd[4]; char modebuf[10]; + int offs; int retval; - retval = kenwood_safe_transaction(rig, "MD", modebuf, 6, 3); + if (RIG_MODEL_TS990S == rig->caps->rig_model) + { + char c; + + if (RIG_VFO_CURR == vfo || RIG_VFO_VFO == vfo) + { + if (RIG_OK != (retval = kenwood_get_vfo_main_sub (rig, &vfo))) + { + return retval; + } + } + switch (vfo) + { + case RIG_VFO_MAIN: c = '0'; break; + case RIG_VFO_SUB: c = '1'; break; + default: + rig_debug(RIG_DEBUG_ERR, "%s: unsupported VFO %d\n", __func__, vfo); + return -RIG_EINVAL; + } + sprintf(cmd, "OM%c", c); + offs = 3; + } + else + { + sprintf(cmd, "MD"); + offs = 2; + } + + retval = kenwood_safe_transaction(rig, cmd, modebuf, 6, offs + 1); if (retval != RIG_OK) return retval; - *mode = kenwood2rmode(modebuf[2] - '0', caps->mode_table); + int kmode; + if (modebuf[offs] <= '9') + { + kmode = modebuf[offs] - '0'; + } + else + { + kmode = modebuf[offs] - 'A' + 10; + } + *mode = kenwood2rmode(kmode, caps->mode_table); if (RIG_MODEL_TS590S == rig->caps->rig_model || RIG_MODEL_TS590SG == rig->caps->rig_model) @@ -1322,17 +1507,17 @@ int kenwood_get_mode(RIG *rig, vfo_t vfo, rmode_t *mode, pbwidth_t *width) retval = kenwood_safe_transaction (rig, "DA", modebuf, 6, 3); if (retval != RIG_OK) { - return retval; + return retval; } if ('1' == modebuf[2]) { - switch (*mode) - { - case RIG_MODE_USB: *mode = RIG_MODE_PKTUSB; break; - case RIG_MODE_LSB: *mode = RIG_MODE_PKTLSB; break; - case RIG_MODE_FM: *mode = RIG_MODE_PKTFM; break; - default: break; - } + switch (*mode) + { + case RIG_MODE_USB: *mode = RIG_MODE_PKTUSB; break; + case RIG_MODE_LSB: *mode = RIG_MODE_PKTLSB; break; + case RIG_MODE_FM: *mode = RIG_MODE_PKTFM; break; + default: break; + } } } @@ -1480,7 +1665,7 @@ int kenwood_set_level(RIG *rig, vfo_t vfo, setting_t level, value_t val) return kenwood_transaction(rig, levelbuf, NULL, 0); } -int get_kenwood_level(RIG *rig, const char *cmd, int cmd_len, float *f) +int get_kenwood_level(RIG *rig, const char *cmd, float *f) { rig_debug(RIG_DEBUG_VERBOSE, "%s called\n", __func__); @@ -1490,15 +1675,15 @@ int get_kenwood_level(RIG *rig, const char *cmd, int cmd_len, float *f) char lvlbuf[10]; int retval; int lvl; + int len = strlen (cmd); - retval = kenwood_safe_transaction(rig, cmd, lvlbuf, 10, 5); + retval = kenwood_safe_transaction(rig, cmd, lvlbuf, 10, len + 3); if (retval != RIG_OK) return retval; /* 000..255 */ - sscanf(lvlbuf+2, "%d", &lvl); - *f = (float)lvl/255.0; - + sscanf(lvlbuf + len, "%d", &lvl); + *f = lvl / 255.0; return RIG_OK; }; @@ -1593,22 +1778,22 @@ int kenwood_get_level(RIG *rig, vfo_t vfo, setting_t level, value_t *val) break; case RIG_LEVEL_RFPOWER: - return get_kenwood_level(rig, "PC", 3, &val->f); + return get_kenwood_level(rig, "PC", &val->f); case RIG_LEVEL_AF: - return get_kenwood_level(rig, "AG", 3, &val->f); + return get_kenwood_level(rig, "AG", &val->f); case RIG_LEVEL_RF: - return get_kenwood_level(rig, "RG", 3, &val->f); + return get_kenwood_level(rig, "RG", &val->f); case RIG_LEVEL_SQL: - return get_kenwood_level(rig, "SQ", 3, &val->f); + return get_kenwood_level(rig, "SQ", &val->f); case RIG_LEVEL_MICGAIN: - return get_kenwood_level(rig, "MG", 3, &val->f); + return get_kenwood_level(rig, "MG", &val->f); case RIG_LEVEL_AGC: - ret = get_kenwood_level(rig, "GT", 3, &val->f); + ret = get_kenwood_level(rig, "GT", &val->f); agclevel = 255 * val->f; if (agclevel == 0) val->i = 0; else if (agclevel < 85) val->i = 1; @@ -1881,7 +2066,32 @@ int kenwood_set_ctcss_tone_tn(RIG *rig, vfo_t vfo, tone_t tone) if (tone != caps->ctcss_list[i]) return -RIG_EINVAL; - sprintf(buf, "TN%02d", i + 1); + if (RIG_MODEL_TS990S == rig->caps->rig_model) + { + char c; + + if (RIG_VFO_CURR == vfo || RIG_VFO_VFO == vfo) + { + int err; + if (RIG_OK != (err = kenwood_get_vfo_main_sub (rig, &vfo))) + { + return err; + } + } + switch (vfo) + { + case RIG_VFO_MAIN: c = '0'; break; + case RIG_VFO_SUB: c = '1'; break; + default: + rig_debug(RIG_DEBUG_ERR, "%s: unsupported VFO %d\n", __func__, vfo); + return -RIG_EINVAL; + } + sprintf(buf, "TN%c%02d", c, i + 1); + } + else + { + sprintf(buf, "TN%02d", i + 1); + } return kenwood_transaction(rig, buf, NULL, 0); } @@ -1905,12 +2115,40 @@ int kenwood_get_ctcss_tone(RIG *rig, vfo_t vfo, tone_t *tone) caps = rig->caps; - retval = kenwood_get_if(rig); + if (RIG_MODEL_TS990S == caps->rig_model) + { + char cmd[4]; + char buf[6]; + char c; + + if (RIG_VFO_CURR == vfo || RIG_VFO_VFO == vfo) + { + if (RIG_OK != (retval = kenwood_get_vfo_main_sub (rig, &vfo))) + { + return retval; + } + } + switch (vfo) + { + case RIG_VFO_MAIN: c = '0'; break; + case RIG_VFO_SUB: c = '1'; break; + default: + rig_debug(RIG_DEBUG_ERR, "%s: unsupported VFO %d\n", __func__, vfo); + return -RIG_EINVAL; + } + sprintf(cmd, "TN%c", c); + retval = kenwood_safe_transaction (rig, cmd, buf, sizeof (buf), 5); + memcpy (tonebuf, &buf[3], 2); + } + else + { + retval = kenwood_get_if(rig); + memcpy(tonebuf, &priv->info[34], 2); + } + if (retval != RIG_OK) return retval; - memcpy(tonebuf, &priv->info[34], 2); - tonebuf[2] = '\0'; tone_idx = atoi(tonebuf); @@ -1952,8 +2190,32 @@ int kenwood_set_ctcss_sql(RIG *rig, vfo_t vfo, tone_t tone) if (tone != caps->ctcss_list[i]) return -RIG_EINVAL; - sprintf(buf, "CN%02d", i + 1); + if (RIG_MODEL_TS990S == rig->caps->rig_model) + { + char c; + if (RIG_VFO_CURR == vfo || RIG_VFO_VFO == vfo) + { + int err; + if (RIG_OK != (err = kenwood_get_vfo_main_sub (rig, &vfo))) + { + return err; + } + } + switch (vfo) + { + case RIG_VFO_MAIN: c = '0'; break; + case RIG_VFO_SUB: c = '1'; break; + default: + rig_debug(RIG_DEBUG_ERR, "%s: unsupported VFO %d\n", __func__, vfo); + return -RIG_EINVAL; + } + sprintf(buf, "CN%c%02d", c, i + 1); + } + else + { + sprintf(buf, "CN%02d", i + 1); + } return kenwood_transaction(rig, buf, NULL, 0); } @@ -1965,17 +2227,47 @@ int kenwood_get_ctcss_sql(RIG *rig, vfo_t vfo, tone_t *tone) return -RIG_EINVAL; const struct rig_caps *caps; + char cmd[3]; char tonebuf[6]; + int offs; int i, retval; unsigned int tone_idx; caps = rig->caps; - retval = kenwood_safe_transaction(rig, "CT", tonebuf, 6, 4); + if (RIG_MODEL_TS990S == rig->caps->rig_model) + { + char c; + + if (RIG_VFO_CURR == vfo || RIG_VFO_VFO == vfo) + { + if (RIG_OK != (retval = kenwood_get_vfo_main_sub (rig, &vfo))) + { + return retval; + } + } + switch (vfo) + { + case RIG_VFO_MAIN: c = '0'; break; + case RIG_VFO_SUB: c = '1'; break; + default: + rig_debug(RIG_DEBUG_ERR, "%s: unsupported VFO %d\n", __func__, vfo); + return -RIG_EINVAL; + } + sprintf(cmd, "CN%c", c); + offs = 3; + } + else + { + sprintf(cmd, "CT"); + offs = 2; + } + + retval = kenwood_safe_transaction(rig, cmd, tonebuf, 6, offs + 2); if (retval != RIG_OK) return retval; - tone_idx = atoi(tonebuf+2); + tone_idx = atoi(tonebuf + offs); if (tone_idx == 0) { rig_debug(RIG_DEBUG_ERR, "%s: CTCSS is zero (%s)\n", @@ -2007,26 +2299,46 @@ int kenwood_set_ant(RIG * rig, vfo_t vfo, ant_t ant) if (!rig) return -RIG_EINVAL; - const char *cmd; + char cmd[8]; + char a; switch (ant) { - case RIG_ANT_1: - cmd = "AN1"; - break; - case RIG_ANT_2: - cmd = "AN2"; - break; - case RIG_ANT_3: - cmd = "AN3"; - break; - case RIG_ANT_4: - cmd = "AN4"; - break; + case RIG_ANT_1: a = '1'; break; + case RIG_ANT_2: a = '2'; break; + case RIG_ANT_3: a = '3'; break; + case RIG_ANT_4: a = '4'; break; default: return -RIG_EINVAL; } - return kenwood_simple_transaction(rig, cmd, 4); + if (RIG_MODEL_TS990S == rig->caps->rig_model) + { + char c; + + if (RIG_VFO_CURR == vfo || RIG_VFO_VFO == vfo) + { + int err; + if (RIG_OK != (err = kenwood_get_vfo_main_sub (rig, &vfo))) + { + return err; + } + } + switch (vfo) + { + case RIG_VFO_MAIN: c = '0'; break; + case RIG_VFO_SUB: c = '1'; break; + default: + rig_debug(RIG_DEBUG_ERR, "%s: unsupported VFO %d\n", __func__, vfo); + return -RIG_EINVAL; + } + sprintf (cmd, "AN0%c%c99", c, a); + } + else + { + sprintf (cmd, "AN%c", a); + } + + return kenwood_transaction(rig, cmd, NULL, 0); } int kenwood_set_ant_no_ack(RIG * rig, vfo_t vfo, ant_t ant) @@ -2068,17 +2380,27 @@ int kenwood_get_ant (RIG *rig, vfo_t vfo, ant_t *ant) if (!rig || !ant) return -RIG_EINVAL; - char ackbuf[6]; + char ackbuf[8]; + int offs; int retval; - retval = kenwood_safe_transaction(rig, "AN", ackbuf, 6, 3); + if (RIG_MODEL_TS990S == rig->caps->rig_model) + { + retval = kenwood_safe_transaction(rig, "AN0", ackbuf, sizeof (ackbuf), 7); + offs = 4; + } + else + { + retval = kenwood_safe_transaction(rig, "AN", ackbuf, sizeof (ackbuf), 3); + offs = 2; + } if (retval != RIG_OK) return retval; - if (ackbuf[2] < '1' || ackbuf[2] > '9') + if (ackbuf[offs] < '1' || ackbuf[offs] > '9') return -RIG_EPROTO; - *ant = RIG_ANT_N(ackbuf[2]-'1'); + *ant = RIG_ANT_N(ackbuf[offs]-'1'); /* XXX check that the returned antenna is valid for the current rig */ @@ -2165,7 +2487,12 @@ int kenwood_get_dcd(RIG *rig, vfo_t vfo, dcd_t *dcd) if (retval != RIG_OK) return retval; - *dcd = (busybuf[2] == '1') ? RIG_DCD_ON : RIG_DCD_OFF; + int offs = 2; + if (RIG_MODEL_TS990S == rig->caps->rig_model && RIG_VFO_SUB == vfo) + { + offs = 3; + } + *dcd = (busybuf[offs] == '1') ? RIG_DCD_ON : RIG_DCD_OFF; return RIG_OK; } @@ -2180,8 +2507,16 @@ int kenwood_set_trn(RIG *rig, int trn) if (!rig) return -RIG_EINVAL; - return kenwood_simple_transaction(rig, - (trn == RIG_TRN_RIG) ? "AI1" : "AI0", 0); + if (RIG_MODEL_TS990S == rig->caps->rig_model) + { + return kenwood_simple_transaction(rig, + (trn == RIG_TRN_RIG) ? "AI2" : "AI0", 0); + } + else + { + return kenwood_simple_transaction(rig, + (trn == RIG_TRN_RIG) ? "AI1" : "AI0", 0); + } } /* @@ -2255,21 +2590,31 @@ int kenwood_reset(RIG *rig, reset_t reset) char rstbuf[6]; char rst; - switch(reset) { - case RIG_RESET_VFO: - rst = '1'; - break; - - case RIG_RESET_MASTER: - rst = '2'; - break; - - default: - rig_debug(RIG_DEBUG_ERR, "%s: unsupported reset %d\n", - __func__, reset); - return -RIG_EINVAL; + if (RIG_MODEL_TS990S == rig->caps->rig_model) + { + switch (reset) + { + case RIG_RESET_SOFT: rst = '4'; break; + case RIG_RESET_VFO: rst = '3'; break; + case RIG_RESET_MCALL: rst = '2'; break; + case RIG_RESET_MASTER: rst = '5'; break; + default: + rig_debug(RIG_DEBUG_ERR, "%s: unsupported reset %d\n", + __func__, reset); + return -RIG_EINVAL; + } + } + else + { + switch(reset) { + case RIG_RESET_VFO: rst = '1'; break; + case RIG_RESET_MASTER: rst = '2'; break; + default: + rig_debug(RIG_DEBUG_ERR, "%s: unsupported reset %d\n", + __func__, reset); + return -RIG_EINVAL; + } } - sprintf(rstbuf, "SR%c", rst); /* this command has no answer */ @@ -2360,14 +2705,39 @@ int kenwood_set_mem(RIG *rig, vfo_t vfo, int ch) if (!rig) return -RIG_EINVAL; - char buf[8]; - /* - * "MCbmm;" - * where b is the bank number, mm the memory number. - * b can be a space - */ - sprintf(buf, "MC %02d", ch); + char buf[7]; + if (RIG_MODEL_TS990S == rig->caps->rig_model) + { + char c; + + if (RIG_VFO_CURR == vfo || RIG_VFO_VFO == vfo) + { + int err; + if (RIG_OK != (err = kenwood_get_vfo_main_sub (rig, &vfo))) + { + return err; + } + } + switch (vfo) + { + case RIG_VFO_MAIN: c = '0'; break; + case RIG_VFO_SUB: c = '1'; break; + default: + rig_debug(RIG_DEBUG_ERR, "%s: unsupported VFO %d\n", __func__, vfo); + return -RIG_EINVAL; + } + sprintf (buf, "MN%c%03d", c, ch); + } + else + { + /* + * "MCbmm;" + * where b is the bank number, mm the memory number. + * b can be a space + */ + sprintf(buf, "MC %02d", ch); + } return kenwood_transaction(rig, buf, NULL, 0); } @@ -2381,20 +2751,48 @@ int kenwood_get_mem(RIG *rig, vfo_t vfo, int *ch) if (!rig || !ch) return -RIG_EINVAL; + char cmd[4]; char membuf[10]; + int offs; int retval; - /* - * "MCbmm;" - * where b is the bank number, mm the memory number. - * b can be a space - */ + if (RIG_MODEL_TS990S == rig->caps->rig_model) + { + char c; - retval = kenwood_safe_transaction(rig, "MC", membuf, 10, 5); + if (RIG_VFO_CURR == vfo || RIG_VFO_VFO == vfo) + { + if (RIG_OK != (retval = kenwood_get_vfo_main_sub (rig, &vfo))) + { + return retval; + } + } + switch (vfo) + { + case RIG_VFO_MAIN: c = '0'; break; + case RIG_VFO_SUB: c = '1'; break; + default: + rig_debug(RIG_DEBUG_ERR, "%s: unsupported VFO %d\n", __func__, vfo); + return -RIG_EINVAL; + } + sprintf (cmd, "MN%c", c); + offs = 3; + } + else + { + /* + * "MCbmm;" + * where b is the bank number, mm the memory number. + * b can be a space + */ + sprintf (cmd, "MC"); + offs = 2; + } + retval = kenwood_safe_transaction(rig, cmd, membuf, sizeof (membuf), 3 + offs); if (retval != RIG_OK) return retval; - *ch = atoi(membuf+2); + *ch = atoi(membuf + offs); return RIG_OK; } @@ -2839,6 +3237,7 @@ DECLARE_INITRIG_BACKEND(kenwood) rig_register(&tmd710_caps); rig_register(&ts590_caps); + rig_register(&ts990s_caps); rig_register(&ts590sg_caps); rig_register(&ts480_caps); rig_register(&thf6a_caps); diff --git a/kenwood/kenwood.h b/kenwood/kenwood.h index 213a51f7f..436cc7664 100644 --- a/kenwood/kenwood.h +++ b/kenwood/kenwood.h @@ -32,7 +32,7 @@ #define EOM_KEN ';' #define EOM_TH '\r' -#define KENWOOD_MODE_TABLE_MAX 10 +#define KENWOOD_MODE_TABLE_MAX 24 #define KENWOOD_MAX_BUF_LEN 50 /* max answer len, arbitrary */ @@ -100,7 +100,9 @@ int kenwood_cleanup(RIG *rig); int kenwood_open(RIG *rig); int kenwood_set_vfo(RIG *rig, vfo_t vfo); +int kenwood_set_vfo_main_sub(RIG *rig, vfo_t vfo); int kenwood_get_vfo_if(RIG *rig, vfo_t *vfo); +int kenwood_get_vfo_main_sub(RIG *rig, vfo_t *vfo); int kenwood_set_split(RIG *rig, vfo_t vfo , split_t split, vfo_t txvfo); int kenwood_set_split_vfo(RIG *rig, vfo_t vfo , split_t split, vfo_t txvfo); int kenwood_get_split_vfo_if(RIG *rig, vfo_t rxvfo, split_t *split, vfo_t *txvfo); @@ -151,7 +153,7 @@ int kenwood_set_trn(RIG *rig, int trn); int kenwood_get_trn(RIG *rig, int *trn); /* only use if returned string has length 6, e.g. 'SQ011;' */ -int get_kenwood_level(RIG *rig, const char *cmd, int cmd_len, float *f); +int get_kenwood_level(RIG *rig, const char *cmd, float *f); int get_kenwood_func(RIG *rig, const char *cmd, int *status); extern const struct rig_caps ts950sdx_caps; diff --git a/kenwood/ts2000.c b/kenwood/ts2000.c index 2192b6ac7..8e02f1495 100644 --- a/kenwood/ts2000.c +++ b/kenwood/ts2000.c @@ -854,7 +854,7 @@ int ts2000_get_level(RIG *rig, vfo_t vfo, setting_t level, value_t *val) case RIG_LEVEL_AGC: /* FIX ME: ts2000 returns 0 -20 for AGC */ - ret = get_kenwood_level(rig, "GT", 2, &val->f); + ret = get_kenwood_level(rig, "GT", &val->f); agclevel = 255.0 * val->f; if (agclevel == 0) val->i = 0; else if (agclevel < 85) val->i = 1; diff --git a/kenwood/ts870s.c b/kenwood/ts870s.c index 6b880dad4..3da531b02 100644 --- a/kenwood/ts870s.c +++ b/kenwood/ts870s.c @@ -360,19 +360,19 @@ static int ts870s_get_level(RIG *rig, vfo_t vfo, setting_t level, value_t *val) case RIG_LEVEL_AF: - return get_kenwood_level(rig, "AG", 2, &val->f); + return get_kenwood_level(rig, "AG", &val->f); case RIG_LEVEL_RF: - return get_kenwood_level(rig, "RG", 2, &val->f); + return get_kenwood_level(rig, "RG", &val->f); case RIG_LEVEL_SQL: - return get_kenwood_level(rig, "SQ", 2, &val->f); + return get_kenwood_level(rig, "SQ", &val->f); case RIG_LEVEL_MICGAIN: - return get_kenwood_level(rig, "MG", 2, &val->f); + return get_kenwood_level(rig, "MG", &val->f); case RIG_LEVEL_AGC: - ret = get_kenwood_level(rig, "GT", 2, &val->f); + ret = get_kenwood_level(rig, "GT", &val->f); agclevel = 255 * val->f; if (agclevel == 0) val->i = 0; else if (agclevel < 85) val->i = 1; diff --git a/kenwood/ts990s.c b/kenwood/ts990s.c new file mode 100644 index 000000000..62f40b262 --- /dev/null +++ b/kenwood/ts990s.c @@ -0,0 +1,630 @@ +/* + * Hamlib Kenwood backend - TS990s description + * Copyright (c) 2000-2011 by Stephane Fillod + * Copyright (c) 2015 modified from ts2000.c by Bill Somerville G4WJS + * + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include + +#include +#include "kenwood.h" +#include "ts990s.h" + +#define TS990S_AM_MODES RIG_MODE_AM +#define TS990S_FM_MODES (RIG_MODE_FM|RIG_MODE_FMN) +#define TS990S_OTHER_MODES (RIG_MODE_CW|RIG_MODE_CWR|RIG_MODE_SSB|RIG_MODE_FM|RIG_MODE_RTTY|RIG_MODE_RTTYR|RIG_MODE_PKTUSB|RIG_MODE_PKTLSB) +#define TS990S_HP_MODES (TS990S_OTHER_MODES|TS990S_FM_MODES) +#define TS990S_ALL_MODES (TS990S_OTHER_MODES|TS990S_AM_MODES|TS990S_FM_MODES) + +#define TS990S_VFOS (RIG_VFO_MAIN|RIG_VFO_SUB) + +#define TS2000_FUNC_ALL (RIG_FUNC_TONE|RIG_FUNC_TSQL|RIG_FUNC_BC|RIG_FUNC_NB|RIG_FUNC_NR|RIG_FUNC_ANF|RIG_FUNC_COMP) + +#define TS2000_LEVEL_ALL (RIG_LEVEL_PREAMP|RIG_LEVEL_ATT|RIG_LEVEL_VOX|RIG_LEVEL_AF|RIG_LEVEL_RF|RIG_LEVEL_SQL|RIG_LEVEL_CWPITCH|RIG_LEVEL_RFPOWER|RIG_LEVEL_MICGAIN|RIG_LEVEL_KEYSPD|RIG_LEVEL_COMP|RIG_LEVEL_AGC|RIG_LEVEL_BKINDL|RIG_LEVEL_METER|RIG_LEVEL_VOXGAIN|RIG_LEVEL_ANTIVOX|RIG_LEVEL_RAWSTR|RIG_LEVEL_STRENGTH) + +#define TS990S_VFO_OP (RIG_OP_BAND_UP|RIG_OP_BAND_DOWN) +#define TS990S_SCAN_OP (RIG_SCAN_VFO) +#define TS990S_ANTS (RIG_ANT_1|RIG_ANT_2|RIG_ANT_3|RIG_ANT_4) + +#define TS990S_STR_CAL {9, {\ + {0x00, -54},\ + {0x03, -48},\ + {0x06, -36},\ + {0x09, -24},\ + {0x0C, -12},\ + {0x0F, 0},\ + {0x14, 20},\ + {0x19, 40},\ + {0x1E, 60}}\ + } + +/* memory capabilities */ +#define TS990S_MEM_CAP { \ + .freq = 1, \ + .mode = 1, \ + .tx_freq=1, \ + .tx_mode=1, \ + .split=1, \ + .rptr_shift=1, \ + .rptr_offs=1, \ + .funcs=RIG_FUNC_REV|RIG_FUNC_TONE|RIG_FUNC_TSQL,\ + .tuning_step=1, \ + .ctcss_tone=1, \ + .ctcss_sql=1, \ + .scan_group=1, \ + .flags=1, \ + .channel_desc=1 \ +} + + +/* prototypes */ +static int ts990s_get_level(RIG *rig, vfo_t vfo, setting_t level, value_t *val); + +static rmode_t ts990s_mode_table[KENWOOD_MODE_TABLE_MAX] = + { + [0] = RIG_MODE_NONE, + [1] = RIG_MODE_LSB, + [2] = RIG_MODE_USB, + [3] = RIG_MODE_CW, + [4] = RIG_MODE_FM, + [5] = RIG_MODE_AM, + [6] = RIG_MODE_RTTY, + [7] = RIG_MODE_CWR, + [8] = RIG_MODE_NONE, + [9] = RIG_MODE_RTTYR, + [10] = RIG_MODE_NONE, /* A */ + [11] = RIG_MODE_NONE, /* B */ + [12] = RIG_MODE_PKTLSB, /* C */ + [13] = RIG_MODE_PKTUSB, /* D */ + [14] = RIG_MODE_PKTFM, /* E */ + [15] = RIG_MODE_NONE, /* F */ + [16] = RIG_MODE_PKTLSB, /* G */ + [17] = RIG_MODE_PKTUSB, /* H */ + [18] = RIG_MODE_PKTFM, /* I */ + [19] = RIG_MODE_NONE, /* J */ + [20] = RIG_MODE_PKTLSB, /* K */ + [21] = RIG_MODE_PKTUSB, /* L */ + [22] = RIG_MODE_PKTFM, /* M */ + [23] = RIG_MODE_NONE, /* N */ + }; + +static struct kenwood_priv_caps ts990s_priv_caps = + { + .cmdtrm = EOM_KEN, + .mode_table = ts990s_mode_table, + }; + + +/* + * ts990s rig capabilities. + * + * part of infos comes from http://www.kenwood.net/ + */ +const struct rig_caps ts990s_caps = { +.rig_model = RIG_MODEL_TS990S, +.model_name = "TS-990s", +.mfg_name = "Kenwood", +.version = BACKEND_VER ".1", +.copyright = "LGPL", +.status = RIG_STATUS_BETA, +.rig_type = RIG_TYPE_TRANSCEIVER, +.ptt_type = RIG_PTT_RIG_MICDATA, +.dcd_type = RIG_DCD_RIG, +.port_type = RIG_PORT_SERIAL, +.serial_rate_min = 4800, +.serial_rate_max = 115200, +.serial_data_bits = 8, +.serial_stop_bits = 1, +.serial_parity = RIG_PARITY_NONE, +.serial_handshake = RIG_HANDSHAKE_HARDWARE, +.write_delay = 0, +.post_write_delay = 50, /* ms */ +.timeout = 200, +.retry = 3, + +.has_get_func = TS2000_FUNC_ALL, +.has_set_func = TS2000_FUNC_ALL, +.has_get_level = TS2000_LEVEL_ALL, +.has_set_level = RIG_LEVEL_SET(TS2000_LEVEL_ALL), +.has_get_parm = RIG_PARM_NONE, +.has_set_parm = RIG_PARM_NONE, /* FIXME: parms */ +.level_gran = {}, /* FIXME: granularity */ +.parm_gran = {}, +.vfo_ops = TS990S_VFO_OP, +.scan_ops = TS990S_SCAN_OP, +.ctcss_list = kenwood42_ctcss_list, +.preamp = { 20, RIG_DBLST_END, }, +.attenuator = { 6, 12, 18, RIG_DBLST_END, }, +.max_rit = Hz(9990), +.max_xit = Hz(9990), +.targetable_vfo = RIG_TARGETABLE_FREQ | RIG_TARGETABLE_MODE, +.transceive = RIG_TRN_RIG, +.bank_qty = 0, +.chan_desc_sz = 7, + +.chan_list = { + { 0, 299, RIG_MTYPE_MEM, TS990S_MEM_CAP }, + RIG_CHAN_END, +}, + +.rx_range_list1 = { + {kHz(300),MHz(60),TS990S_ALL_MODES,-1,-1,TS990S_VFOS,TS990S_ANTS}, + RIG_FRNG_END, + }, /* rx range */ +.tx_range_list1 = { + {kHz(1830),kHz(1850),TS990S_HP_MODES,W(5),W(200),TS990S_VFOS,TS990S_ANTS}, + {kHz(1830),kHz(1850),TS990S_AM_MODES,W(5),W(50),TS990S_VFOS,TS990S_ANTS}, + {kHz(3500),kHz(3800),TS990S_HP_MODES,W(5),W(200),TS990S_VFOS,TS990S_ANTS}, + {kHz(3500),kHz(3800),TS990S_AM_MODES,W(5),W(50),TS990S_VFOS,TS990S_ANTS}, + {MHz(7),kHz(7100),TS990S_HP_MODES,W(5),W(200),TS990S_VFOS,TS990S_ANTS}, + {MHz(7),kHz(7100),TS990S_AM_MODES,W(5),W(50),TS990S_VFOS,TS990S_ANTS}, + {MHz(10.1),MHz(10.15),TS990S_HP_MODES,W(5),W(200),TS990S_VFOS,TS990S_ANTS}, + {MHz(10.1),MHz(10.15),TS990S_AM_MODES,W(5),W(50),TS990S_VFOS,TS990S_ANTS}, + {MHz(14),kHz(14350),TS990S_HP_MODES,W(5),W(200),TS990S_VFOS,TS990S_ANTS}, + {MHz(14),kHz(14350),TS990S_AM_MODES,W(5),W(50),TS990S_VFOS,TS990S_ANTS}, + {kHz(18068),kHz(18168),TS990S_HP_MODES,W(5),W(200),TS990S_VFOS,TS990S_ANTS}, + {kHz(18068),kHz(18168),TS990S_AM_MODES,W(5),W(50),TS990S_VFOS,TS990S_ANTS}, + {MHz(21),kHz(21450),TS990S_HP_MODES,W(5),W(200),TS990S_VFOS,TS990S_ANTS}, + {MHz(21),kHz(21450),TS990S_AM_MODES,W(5),W(50),TS990S_VFOS,TS990S_ANTS}, + {kHz(24890),kHz(24990),TS990S_HP_MODES,W(5),W(200),TS990S_VFOS,TS990S_ANTS}, + {kHz(24890),kHz(24990),TS990S_AM_MODES,W(5),W(50),TS990S_VFOS,TS990S_ANTS}, + {MHz(28),kHz(29700),TS990S_HP_MODES,W(5),W(200),TS990S_VFOS,TS990S_ANTS}, + {MHz(28),kHz(29700),TS990S_AM_MODES,W(5),W(50),TS990S_VFOS,TS990S_ANTS}, + {MHz(50),MHz(50.2),TS990S_HP_MODES,W(5),W(200),TS990S_VFOS,TS990S_ANTS}, + {MHz(50),MHz(50.2),TS990S_AM_MODES,W(5),W(50),TS990S_VFOS,TS990S_ANTS}, + RIG_FRNG_END, + }, /* tx range */ + +.rx_range_list2 = { + {kHz(300),MHz(60),TS990S_ALL_MODES,-1,-1,TS990S_VFOS,TS990S_ANTS}, + RIG_FRNG_END, + }, /* rx range */ +.tx_range_list2 = { + {kHz(1800),MHz(2),TS990S_HP_MODES,W(5),W(200),TS990S_VFOS,TS990S_ANTS}, + {kHz(1800),MHz(2),TS990S_AM_MODES,W(5),W(50),TS990S_VFOS,TS990S_ANTS}, + {kHz(3500),MHz(4),TS990S_HP_MODES,W(5),W(200),TS990S_VFOS,TS990S_ANTS}, + {kHz(3500),MHz(4),TS990S_AM_MODES,W(5),W(50),TS990S_VFOS,TS990S_ANTS}, + {MHz(7),kHz(7300),TS990S_HP_MODES,W(5),W(200),TS990S_VFOS,TS990S_ANTS}, + {MHz(7),kHz(7300),TS990S_AM_MODES,W(5),W(50),TS990S_VFOS,TS990S_ANTS}, + {MHz(10.1),MHz(10.15),TS990S_HP_MODES,W(5),W(200),TS990S_VFOS,TS990S_ANTS}, + {MHz(10.1),MHz(10.15),TS990S_AM_MODES,W(5),W(50),TS990S_VFOS,TS990S_ANTS}, + {MHz(14),kHz(14350),TS990S_HP_MODES,W(5),W(200),TS990S_VFOS,TS990S_ANTS}, + {MHz(14),kHz(14350),TS990S_AM_MODES,W(5),W(50),TS990S_VFOS,TS990S_ANTS}, + {kHz(18068),kHz(18168),TS990S_HP_MODES,W(5),W(200),TS990S_VFOS,TS990S_ANTS}, + {kHz(18068),kHz(18168),TS990S_AM_MODES,W(5),W(50),TS990S_VFOS,TS990S_ANTS}, + {MHz(21),kHz(21450),TS990S_HP_MODES,W(5),W(200),TS990S_VFOS,TS990S_ANTS}, + {MHz(21),kHz(21450),TS990S_AM_MODES,W(5),W(50),TS990S_VFOS,TS990S_ANTS}, + {kHz(24890),kHz(24990),TS990S_HP_MODES,W(5),W(200),TS990S_VFOS,TS990S_ANTS}, + {kHz(24890),kHz(24990),TS990S_AM_MODES,W(5),W(50),TS990S_VFOS,TS990S_ANTS}, + {MHz(28),kHz(29700),TS990S_HP_MODES,W(5),W(200),TS990S_VFOS,TS990S_ANTS}, + {MHz(28),kHz(29700),TS990S_AM_MODES,W(5),W(50),TS990S_VFOS,TS990S_ANTS}, + {MHz(50),MHz(54),TS990S_HP_MODES,W(5),W(200),TS990S_VFOS,TS990S_ANTS}, + {MHz(50),MHz(54),TS990S_AM_MODES,W(5),W(50),TS990S_VFOS,TS990S_ANTS}, + RIG_FRNG_END, + }, /* tx range */ +.tuning_steps = { + {TS990S_OTHER_MODES,1}, + {TS990S_OTHER_MODES,kHz(0.5)}, + {TS990S_OTHER_MODES,kHz(1)}, + {TS990S_OTHER_MODES,kHz(2.5)}, + {TS990S_OTHER_MODES,kHz(5)}, + {TS990S_OTHER_MODES,kHz(10)}, + {(TS990S_AM_MODES|TS990S_FM_MODES),kHz(5)}, + {(TS990S_AM_MODES|TS990S_FM_MODES),kHz(6.25)}, + {(TS990S_AM_MODES|TS990S_FM_MODES),kHz(10)}, + {(TS990S_AM_MODES|TS990S_FM_MODES),kHz(12.5)}, + {(TS990S_AM_MODES|TS990S_FM_MODES),kHz(15)}, + {(TS990S_AM_MODES|TS990S_FM_MODES),kHz(20)}, + {TS990S_ALL_MODES,MHz(1)}, + {TS990S_ALL_MODES,0}, /* any tuning step */ + RIG_TS_END, + }, + + /* mode/filter list, remember: order matters! */ +.filters = { + {RIG_MODE_SSB|TS990S_FM_MODES, kHz(2.6)}, /* default normal */ + {RIG_MODE_SSB|TS990S_FM_MODES, kHz(2.0)}, /* default narrow - + arbitrary choice */ + {RIG_MODE_SSB|TS990S_FM_MODES, kHz(3.2)}, /* default wide - + arbitrary choice */ + {RIG_MODE_SSB|TS990S_FM_MODES, kHz(4.8)}, + {RIG_MODE_SSB|TS990S_FM_MODES, kHz(3.8)}, + {RIG_MODE_SSB|TS990S_FM_MODES, kHz(2.8)}, + {RIG_MODE_SSB|TS990S_FM_MODES, kHz(2.4)}, + {RIG_MODE_SSB|TS990S_FM_MODES, kHz(1.8)}, + {RIG_MODE_SSB|TS990S_FM_MODES, kHz(1.4)}, + {RIG_MODE_SSB|TS990S_FM_MODES, kHz(1.2)}, + {RIG_MODE_SSB|TS990S_FM_MODES, kHz(1.0)}, + {RIG_MODE_SSB|TS990S_FM_MODES, kHz(0.8)}, + {RIG_MODE_CW|RIG_MODE_CWR, Hz(500)}, /* default normal */ + {RIG_MODE_CW|RIG_MODE_CWR, Hz(250)}, /* default narrow - + arbitrary choice */ + {RIG_MODE_CW|RIG_MODE_CWR, kHz(1.0)}, /* default wide - arbitrary choice */ + {RIG_MODE_CW|RIG_MODE_CWR, kHz(2.5)}, + {RIG_MODE_CW|RIG_MODE_CWR, kHz(2.0)}, + {RIG_MODE_CW|RIG_MODE_CWR, kHz(1.5)}, + {RIG_MODE_CW|RIG_MODE_CWR, Hz(600)}, + {RIG_MODE_CW|RIG_MODE_CWR, Hz(400)}, + {RIG_MODE_CW|RIG_MODE_CWR, Hz(300)}, + {RIG_MODE_CW|RIG_MODE_CWR, Hz(200)}, + {RIG_MODE_CW|RIG_MODE_CWR, Hz(150)}, + {RIG_MODE_CW|RIG_MODE_CWR, Hz(100)}, + {RIG_MODE_CW|RIG_MODE_CWR, Hz(80)}, + {RIG_MODE_CW|RIG_MODE_CWR, Hz(50)}, + {RIG_MODE_RTTY|RIG_MODE_RTTYR, Hz(500)}, /* default normal */ + {RIG_MODE_RTTY|RIG_MODE_RTTYR, Hz(250)}, /* default narrow - + arbitrary choice */ + {RIG_MODE_RTTY|RIG_MODE_RTTYR, Hz(1500)}, /* default wide - + arbitrary choice */ + {RIG_MODE_RTTY|RIG_MODE_RTTYR, Hz(1000)}, + {RIG_MODE_RTTY|RIG_MODE_RTTYR, Hz(400)}, + {RIG_MODE_RTTY|RIG_MODE_RTTYR, Hz(300)}, + {RIG_MODE_AM, kHz(5)}, /* default normal */ + {RIG_MODE_AM, kHz(2.5)}, /* default narrow - arbitrary choice */ + {RIG_MODE_AM, kHz(4)}, + {RIG_MODE_AM, kHz(3)}, + {RIG_MODE_PKTLSB|RIG_MODE_PKTUSB, kHz(2.6)}, /* default normal */ + {RIG_MODE_PKTLSB|RIG_MODE_PKTUSB, Hz(500)}, /* default narrow - + arbitrary choice */ + {RIG_MODE_PKTLSB|RIG_MODE_PKTUSB, kHz(13)}, /* default wide - + arbitrary choice */ + {RIG_MODE_PKTLSB|RIG_MODE_PKTUSB, kHz(2.8)}, + {RIG_MODE_PKTLSB|RIG_MODE_PKTUSB, kHz(2.4)}, + {RIG_MODE_PKTLSB|RIG_MODE_PKTUSB, kHz(2.2)}, + {RIG_MODE_PKTLSB|RIG_MODE_PKTUSB, kHz(2.0)}, + {RIG_MODE_PKTLSB|RIG_MODE_PKTUSB, kHz(1.5)}, + {RIG_MODE_PKTLSB|RIG_MODE_PKTUSB, kHz(1.0)}, + {RIG_MODE_PKTLSB|RIG_MODE_PKTUSB, Hz(600)}, + {RIG_MODE_PKTLSB|RIG_MODE_PKTUSB, Hz(400)}, + {RIG_MODE_PKTLSB|RIG_MODE_PKTUSB, Hz(300)}, + {RIG_MODE_PKTLSB|RIG_MODE_PKTUSB, Hz(200)}, + {RIG_MODE_PKTLSB|RIG_MODE_PKTUSB, Hz(150)}, + {RIG_MODE_PKTLSB|RIG_MODE_PKTUSB, Hz(100)}, + {RIG_MODE_PKTLSB|RIG_MODE_PKTUSB, Hz(80)}, + {RIG_MODE_PKTLSB|RIG_MODE_PKTUSB, Hz(50)}, + RIG_FLT_END, + }, + +.str_cal = TS990S_STR_CAL, + +.priv = (void *)&ts990s_priv_caps, + +.rig_init = kenwood_init, +.rig_open = kenwood_open, +.rig_cleanup = kenwood_cleanup, +.set_freq = kenwood_set_freq, +.get_freq = kenwood_get_freq, +.set_rit = kenwood_set_rit, +.get_rit = kenwood_get_rit, +.set_xit = kenwood_set_xit, +.get_xit = kenwood_get_xit, +.set_mode = kenwood_set_mode, +.get_mode = kenwood_get_mode, +.set_vfo = kenwood_set_vfo_main_sub, +.get_vfo = kenwood_get_vfo_main_sub, +.set_split_vfo = kenwood_set_split_vfo, +.get_split_vfo = kenwood_get_split_vfo_if, +.set_ctcss_tone = kenwood_set_ctcss_tone_tn, +.get_ctcss_tone = kenwood_get_ctcss_tone, +.set_ctcss_sql = kenwood_set_ctcss_sql, +.get_ctcss_sql = kenwood_get_ctcss_sql, +.set_ptt = kenwood_set_ptt, +.get_dcd = kenwood_get_dcd, +.set_func = kenwood_set_func, +.get_func = kenwood_get_func, +.set_level = kenwood_set_level, +.get_level = ts990s_get_level, +.set_ant = kenwood_set_ant, +.get_ant = kenwood_get_ant, +.send_morse = kenwood_send_morse, +.vfo_op = kenwood_vfo_op, +.scan = kenwood_scan, +.set_mem = kenwood_set_mem, +.get_mem = kenwood_get_mem, +.set_trn = kenwood_set_trn, +.get_trn = kenwood_get_trn, +.set_powerstat = kenwood_set_powerstat, +.get_powerstat = kenwood_get_powerstat, +.reset = kenwood_reset, + +}; + +/* + * Function definitions below + */ + +/* + * ts2000_get_level + * Assumes rig!=NULL, val!=NULL + */ + +int ts990s_get_level(RIG *rig, vfo_t vfo, setting_t level, value_t *val) +{ + char lvlbuf[50]; + int lvl, retval = RIG_OK; + + if (RIG_VFO_CURR == vfo || RIG_VFO_VFO == vfo) + { + if (RIG_OK != (retval = kenwood_get_vfo_main_sub (rig, &vfo))) + { + return retval; + } + } + + switch (level) { + + case RIG_LEVEL_PREAMP: + retval = kenwood_safe_transaction (rig, "PA", lvlbuf, sizeof (lvlbuf), 4); + if (retval != RIG_OK) + return retval; + switch (vfo) + { + case RIG_VFO_MAIN: + val->i = '1' == lvlbuf[2] ? rig->state.preamp[0] : 0; + break; + + case RIG_VFO_SUB: + val->i = '1' == lvlbuf[3] ? rig->state.preamp[0] : 0; + break; + + default: + rig_debug(RIG_DEBUG_ERR, "%s: unsupported VFO %d\n", __func__, vfo); + return -RIG_EINVAL; + } + break; + + case RIG_LEVEL_ATT: + { + char v; + char cmd[4]; + switch (vfo) + { + case RIG_VFO_MAIN: v = '0'; break; + case RIG_VFO_SUB: v = '1'; break; + default: + rig_debug(RIG_DEBUG_ERR, "%s: unsupported VFO %d\n", __func__, vfo); + return -RIG_EINVAL; + } + sprintf (cmd, "RA%c", v); + retval = kenwood_safe_transaction (rig, cmd, lvlbuf, sizeof (lvlbuf), 4); + if (retval != RIG_OK) + return retval; + + if ('0' == lvlbuf[3]) + { + val->i = 0; + } + else + { + val->i = rig->state.attenuator[lvlbuf[3] - '1']; + } + } + break; + + case RIG_LEVEL_VOX: + retval = kenwood_safe_transaction (rig, "VD0", lvlbuf, sizeof (lvlbuf), 6); + if (retval != RIG_OK) + return retval; + sscanf(lvlbuf + 3, "%d", &lvl); + val->i = lvl * 3 / 2; /* 150ms units converted to 100ms units */ + break; + + case RIG_LEVEL_AF: + { + char v; + char cmd[4]; + switch (vfo) + { + case RIG_VFO_MAIN: v = '0'; break; + case RIG_VFO_SUB: v = '1'; break; + default: + rig_debug(RIG_DEBUG_ERR, "%s: unsupported VFO %d\n", __func__, vfo); + return -RIG_EINVAL; + } + sprintf (cmd, "AG%c", v); + retval = kenwood_safe_transaction (rig, cmd, lvlbuf, sizeof (lvlbuf), 6); + if (retval != RIG_OK) + return retval; + sscanf(lvlbuf + 3, "%d", &lvl); + val->f = lvl / 255.0; + } + break; + + case RIG_LEVEL_RF: + { + char v; + char cmd[4]; + switch (vfo) + { + case RIG_VFO_MAIN: v = '0'; break; + case RIG_VFO_SUB: v = '1'; break; + default: + rig_debug(RIG_DEBUG_ERR, "%s: unsupported VFO %d\n", __func__, vfo); + return -RIG_EINVAL; + } + sprintf (cmd, "RG%c", v); + retval = kenwood_safe_transaction (rig, cmd, lvlbuf, sizeof (lvlbuf), 6); + if (retval != RIG_OK) + return retval; + sscanf(lvlbuf + 3, "%d", &lvl); + val->f = lvl / 255.0; + } + break; + + case RIG_LEVEL_SQL: + { + char v; + char cmd[4]; + switch (vfo) + { + case RIG_VFO_MAIN: v = '0'; break; + case RIG_VFO_SUB: v = '1'; break; + default: + rig_debug(RIG_DEBUG_ERR, "%s: unsupported VFO %d\n", __func__, vfo); + return -RIG_EINVAL; + } + sprintf (cmd, "SQ%c", v); + retval = kenwood_safe_transaction (rig, cmd, lvlbuf, sizeof (lvlbuf), 6); + if (retval != RIG_OK) + return retval; + sscanf(lvlbuf + 3, "%d", &lvl); + val->f = lvl / 255.0; + } + break; + + case RIG_LEVEL_CWPITCH: + retval = kenwood_safe_transaction (rig, "PT", lvlbuf, sizeof (lvlbuf), 5); + if (retval != RIG_OK) + return retval; + sscanf(lvlbuf + 2, "%d", &lvl); + val->i = 300 + lvl * 10; + break; + + case RIG_LEVEL_RFPOWER: + retval = kenwood_safe_transaction (rig, "PC", lvlbuf, sizeof (lvlbuf), 5); + if (retval != RIG_OK) + return retval; + sscanf(lvlbuf + 2, "%d", &lvl); + val->f = lvl / 200.0; /* TODO: should we detect AM and scale? */ + break; + + case RIG_LEVEL_MICGAIN: + retval = get_kenwood_level (rig, "MG", &val->f); + if (retval != RIG_OK) + return retval; + break; + + case RIG_LEVEL_KEYSPD: + retval = kenwood_safe_transaction (rig, "KS", lvlbuf, sizeof (lvlbuf), 5); + if (retval != RIG_OK) + return retval; + sscanf(lvlbuf + 2, "%d", &lvl); + val->i = lvl; + break; + + case RIG_LEVEL_COMP: + retval = kenwood_safe_transaction (rig, "PL", lvlbuf, sizeof (lvlbuf), 8); + if (retval != RIG_OK) + return retval; + sscanf(lvlbuf + 2, "%d", &lvl); + lvl = lvl / 1000; /* report input level */ + val->f = lvl / 255.0; + break; + + case RIG_LEVEL_AGC: + { + char v; + char cmd[4]; + switch (vfo) + { + case RIG_VFO_MAIN: v = '0'; break; + case RIG_VFO_SUB: v = '1'; break; + default: + rig_debug(RIG_DEBUG_ERR, "%s: unsupported VFO %d\n", __func__, vfo); + return -RIG_EINVAL; + } + sprintf (cmd, "GC%c", v); + if (RIG_OK != (retval = kenwood_safe_transaction (rig, cmd, lvlbuf, sizeof (lvlbuf), 4))) + { + return retval; + } + switch (lvlbuf[3]) + { + case '0': val->i = RIG_AGC_OFF; break; + case '1': val->i = RIG_AGC_SLOW; break; + case '2': val->i = RIG_AGC_MEDIUM; break; + case '3': val->i = RIG_AGC_FAST; break; + } + } + break; + + case RIG_LEVEL_BKINDL: + retval = kenwood_safe_transaction (rig, "SD", lvlbuf, sizeof (lvlbuf), 6); + if (retval != RIG_OK) + return retval; + sscanf(lvlbuf + 2, "%d", &lvl); + val->i = lvl / 100; + break; + + case RIG_LEVEL_METER: + retval = kenwood_safe_transaction (rig, "RM", lvlbuf, sizeof (lvlbuf), 7); + if (retval != RIG_OK) + return retval; + switch (lvlbuf[2]) + { + case '1': val->i = RIG_METER_ALC; break; + case '2': val->i = RIG_METER_SWR; break; + case '3': val->i = RIG_METER_COMP; break; + case '4': val->i = RIG_METER_IC; break; + case '5': val->i = RIG_METER_VDD; break; + default: val->i = RIG_METER_NONE; break; + } + break; + + case RIG_LEVEL_VOXGAIN: + retval = get_kenwood_level (rig, "VG00", &val->f); + if (retval != RIG_OK) + return retval; + break; + + case RIG_LEVEL_ANTIVOX: + retval = get_kenwood_level (rig, "VG00", &val->f); + if (retval != RIG_OK) + return retval; + val->f = val->f * 255. / 20.; + break; + + case RIG_LEVEL_RAWSTR: + case RIG_LEVEL_STRENGTH: + { + char v; + char cmd[4]; + switch (vfo) + { + case RIG_VFO_MAIN: v = '0'; break; + case RIG_VFO_SUB: v = '1'; break; + default: + rig_debug(RIG_DEBUG_ERR, "%s: unsupported VFO %d\n", __func__, vfo); + return -RIG_EINVAL; + } + sprintf (cmd, "SM%c", v); + retval = kenwood_safe_transaction (rig, cmd, lvlbuf, sizeof (lvlbuf), 7); + if (retval != RIG_OK) + return retval; + /* Frontend expects: -54 = S0, 0 = S9 */ + sscanf(lvlbuf + 3, "%d", &val->i); + /* TS-990s returns values from 0 - 70 */ + /* so scale the value */ + if (level == RIG_LEVEL_STRENGTH) + val->i = (val->i * 54. / 70.) - 54; + } + break; + + default: + rig_debug(RIG_DEBUG_ERR,"Unsupported get_level %d", level); + return -RIG_EINVAL; + } + + return retval; +} diff --git a/kenwood/ts990s.h b/kenwood/ts990s.h new file mode 100644 index 000000000..9245beac7 --- /dev/null +++ b/kenwood/ts990s.h @@ -0,0 +1,29 @@ +/* + * Hamlib Kenwood backend - main header + * Copyright (c) 2015 by Bill Somerville G4WJS + * + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifndef TS990S_H__ +#define TS990S_H__ + +#include "hamlib/rig.h" + +extern const struct rig_caps ts990s_caps; + +#endif