diff --git a/rigs/kenwood/kenwood.c b/rigs/kenwood/kenwood.c index f317fe204..84db82d17 100644 --- a/rigs/kenwood/kenwood.c +++ b/rigs/kenwood/kenwood.c @@ -3143,7 +3143,15 @@ int kenwood_set_level(RIG *rig, vfo_t vfo, setting_t level, value_t val) case RIG_LEVEL_AF: { - int vfo_set = vfo == RIG_VFO_A || vfo == RIG_VFO_MAIN ? 0 : 1; + int vfo_num; + if (RIG_IS_TS2000) + { + vfo_num = (vfo == RIG_VFO_C) ? 1 : 0; + } + else + { + vfo_num = (vfo == RIG_VFO_A || vfo == RIG_VFO_MAIN) ? 0 : 1; + } // some rigs only recognize 0 for vfo_set // https://github.com/Hamlib/Hamlib/issues/304 @@ -3161,7 +3169,7 @@ int kenwood_set_level(RIG *rig, vfo_t vfo, setting_t level, value_t val) break; case 3: - SNPRINTF(levelbuf, sizeof(levelbuf), "AG%d%03d", vfo_set, kenwood_val); + SNPRINTF(levelbuf, sizeof(levelbuf), "AG%d%03d", vfo_num, kenwood_val); break; default: @@ -3202,10 +3210,21 @@ int kenwood_set_level(RIG *rig, vfo_t vfo, setting_t level, value_t val) SNPRINTF(levelbuf, sizeof(levelbuf), "RG%03d", kenwood_val); break; - case RIG_LEVEL_SQL: - /* Default to RX#0 */ - SNPRINTF(levelbuf, sizeof(levelbuf), "SQ0%03d", kenwood_val); + case RIG_LEVEL_SQL: { + int vfo_num; + if (RIG_IS_TS2000) + { + vfo_num = (vfo == RIG_VFO_C) ? 1 : 0; + } + else + { + /* Default to RX#0 */ + vfo_num = 0; + } + + SNPRINTF(levelbuf, sizeof(levelbuf), "SQ%d%03d", vfo_num, kenwood_val); break; + } case RIG_LEVEL_AGC: SNPRINTF(levelbuf, sizeof(levelbuf), "GT%03d", 84 * kenwood_val); @@ -3419,6 +3438,7 @@ int get_kenwood_level(RIG *rig, const char *cmd, float *fval, int *ival) */ int kenwood_get_level(RIG *rig, vfo_t vfo, setting_t level, value_t *val) { + char cmdbuf[8]; char lvlbuf[KENWOOD_MAX_BUF_LEN]; char *cmd; int retval; @@ -3444,6 +3464,18 @@ int kenwood_get_level(RIG *rig, vfo_t vfo, setting_t level, value_t *val) cmd = "SM0"; len = 3; } + else if (RIG_IS_TS2000) + { + len = 3; + if (vfo == RIG_VFO_C) + { + cmd = "SM1"; + } + else + { + cmd = "SM0"; + } + } else { cmd = "SM"; @@ -3457,16 +3489,31 @@ int kenwood_get_level(RIG *rig, vfo_t vfo, setting_t level, value_t *val) RETURNFUNC(retval); } - /* XXX atoi ? */ - sscanf(lvlbuf + len, "%d", &val->i); /* rawstr */ + sscanf(lvlbuf + len, "%d", &val->i); break; - case RIG_LEVEL_STRENGTH: + case RIG_LEVEL_STRENGTH: { + int multiplier = 1; + if (RIG_IS_TS590S || RIG_IS_TS590SG || RIG_IS_TS480) { cmd = "SM0"; len = 3; } + else if (RIG_IS_TS2000) + { + len = 3; + if (vfo == RIG_VFO_C) + { + cmd = "SM1"; + // TS-2000 sub-transceiver S-meter range is half of the main one + multiplier = 2; + } + else + { + cmd = "SM0"; + } + } else { cmd = "SM"; @@ -3480,7 +3527,8 @@ int kenwood_get_level(RIG *rig, vfo_t vfo, setting_t level, value_t *val) RETURNFUNC(retval); } - sscanf(lvlbuf + len, "%d", &val->i); /* rawstr */ + sscanf(lvlbuf + len, "%d", &val->i); + val->i *= multiplier; if (rig->caps->str_cal.size) { @@ -3490,8 +3538,47 @@ int kenwood_get_level(RIG *rig, vfo_t vfo, setting_t level, value_t *val) { val->i = (val->i * 4) - 54; } - break; + } + + case RIG_LEVEL_SQL: { + int ack_len; + int vfo_num; + + if (RIG_IS_TS2000) + { + vfo_num = (vfo == RIG_VFO_C) ? 1 : 0; + } + else + { + /* Default to RX#0 */ + vfo_num = 0; + } + + SNPRINTF(cmdbuf, sizeof(cmdbuf), "SQ%c", vfo_num); + retval = kenwood_transaction(rig, cmdbuf, lvlbuf, sizeof(lvlbuf)); + len = 6; + + if (retval != RIG_OK) + { + return retval; + } + + ack_len = strlen(lvlbuf); + + if (ack_len != len) + { + return -RIG_EPROTO; + } + + if (sscanf(&lvlbuf[len - 3], "%d", &lvl) != 1) + { + return -RIG_EPROTO; + } + + val->f = (float) lvl / 255.f; + return RIG_OK; + } case RIG_LEVEL_ATT: len = RIG_IS_TS890S ? 3 : 6; @@ -3585,8 +3672,8 @@ int kenwood_get_level(RIG *rig, vfo_t vfo, setting_t level, value_t *val) val->f = (power_now - power_min) / (float)(power_max - power_min); RETURNFUNC(RIG_OK); - case RIG_LEVEL_AF: - + case RIG_LEVEL_AF: { + int vfo_num; // first time through we'll determine the AG format // Can be "AG" "AG0" or "AG0/1" // This could be done by rig but easy enough to make it automagic @@ -3643,6 +3730,15 @@ int kenwood_get_level(RIG *rig, vfo_t vfo, setting_t level, value_t *val) RETURNFUNC(RIG_OK); // this is non-fatal for no))w } + if (RIG_IS_TS2000) + { + vfo_num = (vfo == RIG_VFO_C) ? 1 : 0; + } + else + { + vfo_num = (vfo == RIG_VFO_A || vfo == RIG_VFO_MAIN) ? 0 : 1; + } + switch (priv->ag_format) { case 0: @@ -3651,16 +3747,16 @@ int kenwood_get_level(RIG *rig, vfo_t vfo, setting_t level, value_t *val) break; case 1: - RETURNFUNC(get_kenwood_level(rig, "AG", &val->f, NULL)); + retval = get_kenwood_level(rig, "AG", &val->f, NULL); break; case 2: - RETURNFUNC(get_kenwood_level(rig, "AG0", &val->f, NULL)); + retval = get_kenwood_level(rig, "AG0", &val->f, NULL); break; case 3: - RETURNFUNC(get_kenwood_level(rig, vfo == RIG_VFO_MAIN ? "AG0" : "AG1", &val->f, - NULL)); + SNPRINTF(cmdbuf, sizeof(cmdbuf), "AG%d", vfo_num); + retval = get_kenwood_level(rig, cmdbuf, &val->f,NULL); break; default: @@ -3669,11 +3765,12 @@ int kenwood_get_level(RIG *rig, vfo_t vfo, setting_t level, value_t *val) RETURNFUNC(-RIG_EPROTO); } + RETURNFUNC(retval); + } + case RIG_LEVEL_RF: RETURNFUNC(get_kenwood_level(rig, "RG", &val->f, NULL)); - - case RIG_LEVEL_MICGAIN: { int micgain_now; @@ -4463,7 +4560,7 @@ int kenwood_get_ctcss_sql(RIG *rig, vfo_t vfo, tone_t *tone) } else { - SNPRINTF(cmd, sizeof(cmd), "CT"); + SNPRINTF(cmd, sizeof(cmd), "CN"); offs = 2; } @@ -4599,6 +4696,7 @@ int kenwood_get_ant(RIG *rig, vfo_t vfo, ant_t dummy, value_t *option, char ackbuf[8]; int offs; int retval; + char antenna; ENTERFUNC; @@ -4623,12 +4721,22 @@ int kenwood_get_ant(RIG *rig, vfo_t vfo, ant_t dummy, value_t *option, RETURNFUNC(retval); } - if (ackbuf[offs] < '1' || ackbuf[offs] > '9') + antenna = ackbuf[offs]; + + if (antenna < '0' || antenna > '9') { RETURNFUNC(-RIG_EPROTO); } - *ant_curr = RIG_ANT_N(ackbuf[offs] - '1'); + if (antenna == '0') + { + // At least TS-2000 return AN0 on VHF/UHF bands + *ant_curr = RIG_ANT_1; + } + else + { + *ant_curr = RIG_ANT_N(ackbuf[offs] - '1'); + } /* XXX check that the returned antenna is valid for the current rig */ @@ -4669,17 +4777,41 @@ int kenwood_set_ptt(RIG *rig, vfo_t vfo, ptt_t ptt) ENTERFUNC; rig_debug(RIG_DEBUG_VERBOSE, "%s: ptt=%d\n", __func__, ptt); - switch (ptt) + if (RIG_IS_TS2000) { - case RIG_PTT_ON: ptt_cmd = "TX"; break; - - case RIG_PTT_ON_MIC: ptt_cmd = "TX0"; break; - - case RIG_PTT_ON_DATA: ptt_cmd = "TX1"; break; - - case RIG_PTT_OFF: ptt_cmd = "RX"; break; - - default: RETURNFUNC(-RIG_EINVAL); + switch (ptt) + { + case RIG_PTT_ON: + case RIG_PTT_ON_MIC: + case RIG_PTT_ON_DATA: + ptt_cmd = (vfo == RIG_VFO_C) ? "TX1" : "TX0"; + break; + case RIG_PTT_OFF: + ptt_cmd = "RX"; + break; + default: + RETURNFUNC(-RIG_EINVAL); + } + } + else + { + switch (ptt) + { + case RIG_PTT_ON: + ptt_cmd = "TX"; + break; + case RIG_PTT_ON_MIC: + ptt_cmd = "TX0"; + break; + case RIG_PTT_ON_DATA: + ptt_cmd = "TX1"; + break; + case RIG_PTT_OFF: + ptt_cmd = "RX"; + break; + default: + RETURNFUNC(-RIG_EINVAL); + } } int retval = kenwood_transaction(rig, ptt_cmd, NULL, 0); @@ -4747,8 +4879,8 @@ int kenwood_get_dcd(RIG *rig, vfo_t vfo, dcd_t *dcd) RETURNFUNC(retval); } - if ((RIG_IS_TS990S && RIG_VFO_SUB == vfo) || (RIG_IS_TS2000 - && RIG_VFO_SUB == vfo)) + if ((RIG_IS_TS990S && RIG_VFO_SUB == vfo) || + (RIG_IS_TS2000 && RIG_VFO_C == vfo)) { offs = 3; } diff --git a/rigs/kenwood/ts2000.c b/rigs/kenwood/ts2000.c index a9008cd09..6f0a605d1 100644 --- a/rigs/kenwood/ts2000.c +++ b/rigs/kenwood/ts2000.c @@ -1,7 +1,7 @@ /* * Hamlib Kenwood backend - TS2000 description * Copyright (c) 2000-2011 by Stephane Fillod - * + * Copyright (c) 2023 by Mikael Nousiainen * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -25,19 +25,31 @@ #include #include "kenwood.h" +#include "token.h" +#include "misc.h" +#include "iofunc.h" +#include "cal.h" -#define TS2000_ALL_MODES (RIG_MODE_AM|RIG_MODE_CW|RIG_MODE_SSB|RIG_MODE_FM|RIG_MODE_RTTY) +#define TS2000_ALL_MODES (RIG_MODE_AM|RIG_MODE_CW|RIG_MODE_CWR|RIG_MODE_SSB|RIG_MODE_FM|RIG_MODE_RTTY|RIG_MODE_RTTYR) #define TS2000_OTHER_TX_MODES (RIG_MODE_CW|RIG_MODE_SSB|RIG_MODE_FM|RIG_MODE_RTTY) #define TS2000_AM_TX_MODES RIG_MODE_AM -#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|RIG_FUNC_RIT|RIG_FUNC_XIT) +#define TS2000_LEVEL_GET (RIG_LEVEL_RFPOWER|RIG_LEVEL_AF|RIG_LEVEL_RF|RIG_LEVEL_SQL|RIG_LEVEL_AGC|RIG_LEVEL_MICGAIN|RIG_LEVEL_STRENGTH|RIG_LEVEL_KEYSPD|RIG_LEVEL_CWPITCH| \ + RIG_LEVEL_MONITOR_GAIN|RIG_LEVEL_NB|RIG_LEVEL_NR|RIG_LEVEL_PREAMP|RIG_LEVEL_COMP|RIG_LEVEL_ATT|RIG_LEVEL_VOXDELAY|RIG_LEVEL_VOXGAIN|RIG_LEVEL_BKIN_DLYMS| \ + RIG_LEVEL_METER|RIG_LEVEL_SWR|RIG_LEVEL_COMP_METER|RIG_LEVEL_ALC|RIG_LEVEL_RFPOWER_METER|RIG_LEVEL_SLOPE_HIGH|RIG_LEVEL_SLOPE_LOW) -#define TS2000_LEVEL_ALL (RIG_LEVEL_PREAMP|RIG_LEVEL_ATT|RIG_LEVEL_VOXDELAY|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 TS2000_LEVEL_SET (RIG_LEVEL_RFPOWER|RIG_LEVEL_AF|RIG_LEVEL_RF|RIG_LEVEL_SQL|RIG_LEVEL_AGC|RIG_LEVEL_MICGAIN|RIG_LEVEL_KEYSPD|RIG_LEVEL_CWPITCH| \ + RIG_LEVEL_MONITOR_GAIN|RIG_LEVEL_NB|RIG_LEVEL_NR|RIG_LEVEL_PREAMP|RIG_LEVEL_COMP|RIG_LEVEL_ATT|RIG_LEVEL_VOXDELAY|RIG_LEVEL_VOXGAIN|RIG_LEVEL_BKIN_DLYMS| \ + RIG_LEVEL_METER|RIG_LEVEL_SLOPE_HIGH|RIG_LEVEL_SLOPE_LOW) + +#define TS2000_FUNC_ALL (RIG_FUNC_NB|RIG_FUNC_COMP|RIG_FUNC_VOX|RIG_FUNC_NR|RIG_FUNC_NR|RIG_FUNC_BC|RIG_FUNC_BC2|RIG_FUNC_RIT|RIG_FUNC_XIT| \ + RIG_FUNC_TUNER|RIG_FUNC_MON|RIG_FUNC_FBKIN|RIG_FUNC_LOCK|RIG_FUNC_TONE|RIG_FUNC_TSQL|RIG_FUNC_ANF) #define TS2000_MAINVFO (RIG_VFO_A|RIG_VFO_B) #define TS2000_SUBVFO (RIG_VFO_C) -#define TS2000_VFO_OP (RIG_OP_UP|RIG_OP_DOWN|RIG_OP_BAND_UP|RIG_OP_BAND_DOWN) +#define TS2000_VFO_OPS (RIG_OP_UP|RIG_OP_DOWN|RIG_OP_BAND_UP|RIG_OP_BAND_DOWN|RIG_OP_CPY|RIG_OP_TUNE) + #define TS2000_SCAN_OP (RIG_SCAN_VFO) #define TS2000_ANTS (RIG_ANT_1|RIG_ANT_2) @@ -53,11 +65,21 @@ {0x1E, 60}}\ } -/* prototypes */ -static int ts2000_get_level(RIG *rig, vfo_t vfo, setting_t level, value_t *val); -static int ts2000_get_channel(RIG *rig, vfo_t vfo, channel_t *chan, - int read_only); -static int ts2000_set_channel(RIG *rig, vfo_t vfo, const channel_t *chan); +#define TS2000_SWR_CAL { 5, \ + { \ + { 0, 1.0f }, \ + { 4, 1.5f }, \ + { 8, 2.0f }, \ + { 12, 3.0f }, \ + { 20, 10.0f } \ + } } + +#define TOK_FUNC_NOISE_REDUCTION_2 TOKEN_BACKEND(102) +#define TOK_LEVEL_DSP_RX_EQUALIZER TOKEN_BACKEND(104) +#define TOK_LEVEL_DSP_TX_EQUALIZER TOKEN_BACKEND(105) +#define TOK_LEVEL_DSP_TX_BANDWIDTH TOKEN_BACKEND(106) +#define TOK_LEVEL_BEEP_VOLUME TOKEN_BACKEND(107) +#define TOK_LEVEL_TX_SIDETONE_VOLUME TOKEN_BACKEND(108) /* * 38 CTCSS sub-audible tones + 1750 tone @@ -71,8 +93,6 @@ tone_t ts2000_ctcss_list[] = 0, }; - - /* * 103 available DCS codes */ @@ -90,9 +110,128 @@ tone_t ts2000_dcs_list[] = 0, }; +int ts2000_ext_tokens[] = +{ + TOK_FUNC_NOISE_REDUCTION_2, TOK_FUNC_FILTER_WIDTH_DATA, + TOK_LEVEL_DSP_RX_EQUALIZER, TOK_LEVEL_DSP_TX_EQUALIZER, TOK_LEVEL_DSP_TX_BANDWIDTH, + TOK_LEVEL_BEEP_VOLUME, TOK_LEVEL_TX_SIDETONE_VOLUME, + TOK_BACKEND_NONE, +}; + +const struct confparams ts2000_ext_funcs[] = +{ + { + TOK_FUNC_NOISE_REDUCTION_2, "NR2", "Noise reduction 2", "Noise reduction 2", + NULL, RIG_CONF_CHECKBUTTON, + }, + { RIG_CONF_END, NULL, } +}; + +const struct confparams ts2000_ext_levels[] = +{ + { + TOK_LEVEL_DSP_RX_EQUALIZER, "DSP_RX_EQUALIZER", "DSP RX equalizer", "DSP RX equalizer type", + NULL, RIG_CONF_COMBO, { .c = { .combostr = { "OFF", "H BOOST", "F PASS", "B BOOST", "CONV-EN", "USER", NULL } } } + }, + { + TOK_LEVEL_DSP_TX_EQUALIZER, "DSP_TX_EQUALIZER", "DSP TX equalizer", "DSP TX equalizer type", + NULL, RIG_CONF_COMBO, { .c = { .combostr = { "OFF", "H BOOST", "F PASS", "B BOOST", "CONV-EN", "USER", NULL } } } + }, + { + TOK_LEVEL_DSP_TX_BANDWIDTH, "DSP_TX_BANDWIDTH", "DSP TX bandwidth", "DSP TX bandwidth for SSB and AM", + NULL, RIG_CONF_COMBO, { .c = { .combostr = { "2.0 kHz", "2.2 kHz", "2.4 kHz", "2.6 kHz", "2.8 kHz", "3.0 kHz", NULL } } } + }, + { + TOK_LEVEL_BEEP_VOLUME, "BEEP_VOLUME", "Beep volume", "Beep volume", + NULL, RIG_CONF_NUMERIC, { .n = { .min = 0, .max = 9, .step = 1 } } + }, + { + TOK_LEVEL_TX_SIDETONE_VOLUME, "TX_SIDETONE_VOLUME", "TX sidetone volume", "TX sidetone volume", + NULL, RIG_CONF_NUMERIC, { .n = { .min = 0, .max = 9, .step = 1 } } + }, + { RIG_CONF_END, NULL, } +}; + +static struct kenwood_filter_width ts2000_filter_width[] = +{ + { RIG_MODE_CW | RIG_MODE_CWR, 50, 50 }, + { RIG_MODE_CW | RIG_MODE_CWR, 80, 80 }, + { RIG_MODE_CW | RIG_MODE_CWR, 100, 100 }, + { RIG_MODE_CW | RIG_MODE_CWR, 150, 150 }, + { RIG_MODE_CW | RIG_MODE_CWR, 200, 200 }, + { RIG_MODE_CW | RIG_MODE_CWR, 300, 300 }, + { RIG_MODE_CW | RIG_MODE_CWR, 400, 400 }, + { RIG_MODE_CW | RIG_MODE_CWR, 500, 500 }, + { RIG_MODE_CW | RIG_MODE_CWR, 600, 600 }, + { RIG_MODE_CW | RIG_MODE_CWR, 1000, 1000 }, + { RIG_MODE_CW | RIG_MODE_CWR, 2000, 2000 }, + { RIG_MODE_RTTY | RIG_MODE_RTTYR, 250, 250 }, + { RIG_MODE_RTTY | RIG_MODE_RTTYR, 500, 500 }, + { RIG_MODE_RTTY | RIG_MODE_RTTYR, 1000, 1000 }, + { RIG_MODE_RTTY | RIG_MODE_RTTYR, 1500, 1500 }, + { RIG_MODE_SSB, 0, 2400 }, + { RIG_MODE_SSB, 1, 500 }, // NAR1 optional filter + { RIG_MODE_SSB, 2, 270 }, // NAR2 optional filter + { RIG_MODE_FM, 0, 6000 }, + { RIG_MODE_FM, 1, 12000 }, + { RIG_MODE_AM, 0, 2400 }, + { RIG_MODE_AM, 1, 6000 }, // NAR1 optional filter (?) + { RIG_MODE_NONE, -1, -1 }, +}; + +static struct kenwood_slope_filter ts2000_slope_filter_high[] = +{ + { RIG_MODE_SSB | RIG_MODE_FM | RIG_MODE_RTTY | RIG_MODE_RTTYR, 0, 0, 1400 }, + { RIG_MODE_SSB | RIG_MODE_FM | RIG_MODE_RTTY | RIG_MODE_RTTYR, 0, 1, 1600 }, + { RIG_MODE_SSB | RIG_MODE_FM | RIG_MODE_RTTY | RIG_MODE_RTTYR, 0, 2, 1800 }, + { RIG_MODE_SSB | RIG_MODE_FM | RIG_MODE_RTTY | RIG_MODE_RTTYR, 0, 3, 2000 }, + { RIG_MODE_SSB | RIG_MODE_FM | RIG_MODE_RTTY | RIG_MODE_RTTYR, 0, 4, 2200 }, + { RIG_MODE_SSB | RIG_MODE_FM | RIG_MODE_RTTY | RIG_MODE_RTTYR, 0, 5, 2400 }, + { RIG_MODE_SSB | RIG_MODE_FM | RIG_MODE_RTTY | RIG_MODE_RTTYR, 0, 6, 2600 }, + { RIG_MODE_SSB | RIG_MODE_FM | RIG_MODE_RTTY | RIG_MODE_RTTYR, 0, 7, 2800 }, + { RIG_MODE_SSB | RIG_MODE_FM | RIG_MODE_RTTY | RIG_MODE_RTTYR, 0, 8, 3000 }, + { RIG_MODE_SSB | RIG_MODE_FM | RIG_MODE_RTTY | RIG_MODE_RTTYR, 0, 9, 3400 }, + { RIG_MODE_SSB | RIG_MODE_FM | RIG_MODE_RTTY | RIG_MODE_RTTYR, 0, 10, 4000 }, + { RIG_MODE_SSB | RIG_MODE_FM | RIG_MODE_RTTY | RIG_MODE_RTTYR, 0, 11, 5000 }, + { RIG_MODE_AM, 0, 0, 2500 }, + { RIG_MODE_AM, 0, 1, 3000 }, + { RIG_MODE_AM, 0, 2, 4000 }, + { RIG_MODE_AM, 0, 3, 5000 }, + { RIG_MODE_SSB | RIG_MODE_RTTY | RIG_MODE_RTTYR | RIG_MODE_FM | RIG_MODE_AM, 1, 0, 170 }, + { RIG_MODE_SSB | RIG_MODE_RTTY | RIG_MODE_RTTYR | RIG_MODE_FM | RIG_MODE_AM, 1, 1, 1930 }, + { RIG_MODE_SSB | RIG_MODE_RTTY | RIG_MODE_RTTYR | RIG_MODE_FM | RIG_MODE_AM, 1, 2, 2160 }, + { RIG_MODE_NONE, 0, -1, -1 }, +}; + +static struct kenwood_slope_filter ts2000_slope_filter_low[] = +{ + { RIG_MODE_SSB | RIG_MODE_FM | RIG_MODE_RTTY | RIG_MODE_RTTYR, 0, 0, 0 }, + { RIG_MODE_SSB | RIG_MODE_FM | RIG_MODE_RTTY | RIG_MODE_RTTYR, 0, 1, 50 }, + { RIG_MODE_SSB | RIG_MODE_FM | RIG_MODE_RTTY | RIG_MODE_RTTYR, 0, 2, 100 }, + { RIG_MODE_SSB | RIG_MODE_FM | RIG_MODE_RTTY | RIG_MODE_RTTYR, 0, 3, 200 }, + { RIG_MODE_SSB | RIG_MODE_FM | RIG_MODE_RTTY | RIG_MODE_RTTYR, 0, 4, 300 }, + { RIG_MODE_SSB | RIG_MODE_FM | RIG_MODE_RTTY | RIG_MODE_RTTYR, 0, 5, 400 }, + { RIG_MODE_SSB | RIG_MODE_FM | RIG_MODE_RTTY | RIG_MODE_RTTYR, 0, 6, 500 }, + { RIG_MODE_SSB | RIG_MODE_FM | RIG_MODE_RTTY | RIG_MODE_RTTYR, 0, 7, 600 }, + { RIG_MODE_SSB | RIG_MODE_FM | RIG_MODE_RTTY | RIG_MODE_RTTYR, 0, 8, 700 }, + { RIG_MODE_SSB | RIG_MODE_FM | RIG_MODE_RTTY | RIG_MODE_RTTYR, 0, 9, 800 }, + { RIG_MODE_SSB | RIG_MODE_FM | RIG_MODE_RTTY | RIG_MODE_RTTYR, 0, 10, 900 }, + { RIG_MODE_SSB | RIG_MODE_FM | RIG_MODE_RTTY | RIG_MODE_RTTYR, 10, 1, 1000 }, + { RIG_MODE_AM, 0, 0, 0 }, + { RIG_MODE_AM, 0, 1, 100 }, + { RIG_MODE_AM, 0, 2, 200 }, + { RIG_MODE_AM, 0, 3, 500 }, + { RIG_MODE_SSB | RIG_MODE_RTTY | RIG_MODE_RTTYR | RIG_MODE_FM | RIG_MODE_AM, 1, 0, 2500 }, + { RIG_MODE_SSB | RIG_MODE_RTTY | RIG_MODE_RTTYR | RIG_MODE_FM | RIG_MODE_AM, 1, 1, 1000 }, + { RIG_MODE_NONE, 0, -1, -1 }, +}; + static struct kenwood_priv_caps ts2000_priv_caps = { .cmdtrm = EOM_KEN, + .filter_width = ts2000_filter_width, + .slope_filter_high = ts2000_slope_filter_high, + .slope_filter_low = ts2000_slope_filter_low, }; /* memory capabilities */ @@ -116,224 +255,930 @@ static struct kenwood_priv_caps ts2000_priv_caps = } -/* - * ts2000 rig capabilities. - * - * part of infos comes from http://www.kenwood.net/ - */ -const struct rig_caps ts2000_caps = -{ - RIG_MODEL(RIG_MODEL_TS2000), - .model_name = "TS-2000", - .mfg_name = "Kenwood", - .version = BACKEND_VER ".0", - .copyright = "LGPL", - .status = RIG_STATUS_STABLE, - .rig_type = RIG_TYPE_TRANSCEIVER, - .ptt_type = RIG_PTT_RIG, - .dcd_type = RIG_DCD_RIG, - .port_type = RIG_PORT_SERIAL, - .serial_rate_min = 1200, - .serial_rate_max = 57600, - .serial_data_bits = 8, - .serial_stop_bits = 1, - .serial_parity = RIG_PARITY_NONE, - .serial_handshake = RIG_HANDSHAKE_NONE, - .write_delay = 0, - .post_write_delay = 0, /* ms */ - .timeout = 200, - .retry = 10, - - .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 = - { -#include "level_gran_kenwood.h" - }, - .parm_gran = {}, - .vfo_ops = TS2000_VFO_OP, - .scan_ops = TS2000_SCAN_OP, - .ctcss_list = ts2000_ctcss_list, - .dcs_list = ts2000_dcs_list, - .preamp = { 20, RIG_DBLST_END, }, /* FIXME: real preamp? */ - .attenuator = { 20, RIG_DBLST_END, }, - .max_rit = kHz(20), - .max_xit = kHz(20), - .max_ifshift = kHz(1), - .targetable_vfo = RIG_TARGETABLE_FREQ, - .transceive = RIG_TRN_RIG, - .agc_level_count = 5, - .agc_levels = { RIG_AGC_OFF, RIG_AGC_SLOW, RIG_AGC_MEDIUM, RIG_AGC_FAST, RIG_AGC_ON }, - .bank_qty = 0, - .chan_desc_sz = 7, - - .chan_list = { - { 0, 299, RIG_MTYPE_MEM, TS2000_MEM_CAP }, - RIG_CHAN_END, - }, - - .rx_range_list1 = { - {kHz(300), MHz(60), TS2000_ALL_MODES, -1, -1, TS2000_MAINVFO, TS2000_ANTS}, - {MHz(144), MHz(146), TS2000_ALL_MODES, -1, -1, TS2000_MAINVFO}, - {MHz(430), MHz(440), TS2000_ALL_MODES, -1, -1, TS2000_MAINVFO}, - {MHz(144), MHz(146), TS2000_ALL_MODES, -1, -1, TS2000_SUBVFO}, - {MHz(430), MHz(440), TS2000_ALL_MODES, -1, -1, TS2000_SUBVFO}, - RIG_FRNG_END, - }, /* rx range */ - .tx_range_list1 = { - {kHz(1830), kHz(1850), TS2000_OTHER_TX_MODES, W(5), W(100), TS2000_MAINVFO, TS2000_ANTS}, - {kHz(1830), kHz(1850), TS2000_AM_TX_MODES, 2000, 25000, TS2000_MAINVFO, TS2000_ANTS}, - {kHz(3500), kHz(3800), TS2000_OTHER_TX_MODES, W(5), W(100), TS2000_MAINVFO, TS2000_ANTS}, - {kHz(3500), kHz(3800), TS2000_AM_TX_MODES, W(5), W(25), TS2000_MAINVFO, TS2000_ANTS}, - {MHz(7), kHz(7100), TS2000_OTHER_TX_MODES, W(5), W(100), TS2000_MAINVFO, TS2000_ANTS}, - {MHz(7), kHz(7100), TS2000_AM_TX_MODES, W(5), W(25), TS2000_MAINVFO, TS2000_ANTS}, - {MHz(10.1), MHz(10.15), TS2000_OTHER_TX_MODES, W(5), W(100), TS2000_MAINVFO, TS2000_ANTS}, - {MHz(10.1), MHz(10.15), TS2000_AM_TX_MODES, W(5), W(25), TS2000_MAINVFO, TS2000_ANTS}, - {MHz(14), kHz(14350), TS2000_OTHER_TX_MODES, W(5), W(100), TS2000_MAINVFO, TS2000_ANTS}, - {MHz(14), kHz(14350), TS2000_AM_TX_MODES, W(5), W(25), TS2000_MAINVFO, TS2000_ANTS}, - {kHz(18068), kHz(18168), TS2000_OTHER_TX_MODES, W(5), W(100), TS2000_MAINVFO, TS2000_ANTS}, - {kHz(18068), kHz(18168), TS2000_AM_TX_MODES, W(5), W(25), TS2000_MAINVFO, TS2000_ANTS}, - {MHz(21), kHz(21450), TS2000_OTHER_TX_MODES, W(5), W(100), TS2000_MAINVFO, TS2000_ANTS}, - {MHz(21), kHz(21450), TS2000_AM_TX_MODES, W(5), W(25), TS2000_MAINVFO, TS2000_ANTS}, - {kHz(24890), kHz(24990), TS2000_OTHER_TX_MODES, W(5), W(100), TS2000_MAINVFO, TS2000_ANTS}, - {kHz(24890), kHz(24990), TS2000_AM_TX_MODES, W(5), W(25), TS2000_MAINVFO, TS2000_ANTS}, - {MHz(28), kHz(29700), TS2000_OTHER_TX_MODES, W(5), W(100), TS2000_MAINVFO, TS2000_ANTS}, - {MHz(28), kHz(29700), TS2000_AM_TX_MODES, W(5), W(25), TS2000_MAINVFO, TS2000_ANTS}, - {MHz(50), MHz(50.2), TS2000_OTHER_TX_MODES, W(5), W(100), TS2000_MAINVFO, TS2000_ANTS}, - {MHz(50), MHz(50.2), TS2000_AM_TX_MODES, W(5), W(25), TS2000_MAINVFO, TS2000_ANTS}, - {MHz(144), MHz(146), TS2000_OTHER_TX_MODES, W(5), W(100), TS2000_MAINVFO}, - {MHz(144), MHz(146), TS2000_AM_TX_MODES, W(5), W(25), TS2000_MAINVFO}, - {MHz(430), MHz(440), TS2000_OTHER_TX_MODES, W(5), W(50), TS2000_MAINVFO}, - {MHz(430), MHz(440), TS2000_AM_TX_MODES, W(5), W(12.5), TS2000_MAINVFO}, - RIG_FRNG_END, - }, /* tx range */ - - .rx_range_list2 = { - {kHz(300), MHz(60), TS2000_ALL_MODES, -1, -1, TS2000_MAINVFO, TS2000_ANTS}, - {MHz(142), MHz(152), TS2000_ALL_MODES, -1, -1, TS2000_MAINVFO}, - {MHz(420), MHz(450), TS2000_ALL_MODES, -1, -1, TS2000_MAINVFO}, - {MHz(118), MHz(174), TS2000_ALL_MODES, -1, -1, TS2000_SUBVFO}, - {MHz(220), MHz(512), TS2000_ALL_MODES, -1, -1, TS2000_SUBVFO}, - RIG_FRNG_END, - }, /* rx range */ - .tx_range_list2 = { - {kHz(1800), MHz(2), TS2000_OTHER_TX_MODES, W(5), W(100), TS2000_MAINVFO, TS2000_ANTS}, - {kHz(1800), MHz(2), TS2000_AM_TX_MODES, 2000, 25000, TS2000_MAINVFO, TS2000_ANTS}, - {kHz(3500), MHz(4), TS2000_OTHER_TX_MODES, W(5), W(100), TS2000_MAINVFO, TS2000_ANTS}, - {kHz(3500), MHz(4), TS2000_AM_TX_MODES, W(5), W(25), TS2000_MAINVFO, TS2000_ANTS}, - {MHz(7), kHz(7300), TS2000_OTHER_TX_MODES, W(5), W(100), TS2000_MAINVFO, TS2000_ANTS}, - {MHz(7), kHz(7300), TS2000_AM_TX_MODES, W(5), W(25), TS2000_MAINVFO, TS2000_ANTS}, - {MHz(10.1), MHz(10.15), TS2000_OTHER_TX_MODES, W(5), W(100), TS2000_MAINVFO, TS2000_ANTS}, - {MHz(10.1), MHz(10.15), TS2000_AM_TX_MODES, W(5), W(25), TS2000_MAINVFO, TS2000_ANTS}, - {MHz(14), kHz(14350), TS2000_OTHER_TX_MODES, W(5), W(100), TS2000_MAINVFO, TS2000_ANTS}, - {MHz(14), kHz(14350), TS2000_AM_TX_MODES, W(5), W(25), TS2000_MAINVFO, TS2000_ANTS}, - {kHz(18068), kHz(18168), TS2000_OTHER_TX_MODES, W(5), W(100), TS2000_MAINVFO, TS2000_ANTS}, - {kHz(18068), kHz(18168), TS2000_AM_TX_MODES, W(5), W(25), TS2000_MAINVFO, TS2000_ANTS}, - {MHz(21), kHz(21450), TS2000_OTHER_TX_MODES, W(5), W(100), TS2000_MAINVFO, TS2000_ANTS}, - {MHz(21), kHz(21450), TS2000_AM_TX_MODES, W(5), W(25), TS2000_MAINVFO, TS2000_ANTS}, - {kHz(24890), kHz(24990), TS2000_OTHER_TX_MODES, W(5), W(100), TS2000_MAINVFO, TS2000_ANTS}, - {kHz(24890), kHz(24990), TS2000_AM_TX_MODES, W(5), W(25), TS2000_MAINVFO, TS2000_ANTS}, - {MHz(28), kHz(29700), TS2000_OTHER_TX_MODES, W(5), W(100), TS2000_MAINVFO, TS2000_ANTS}, - {MHz(28), kHz(29700), TS2000_AM_TX_MODES, W(5), W(25), TS2000_MAINVFO, TS2000_ANTS}, - {MHz(50), MHz(54), TS2000_OTHER_TX_MODES, W(5), W(100), TS2000_MAINVFO, TS2000_ANTS}, - {MHz(50), MHz(54), TS2000_AM_TX_MODES, W(5), W(25), TS2000_MAINVFO, TS2000_ANTS}, - {MHz(144), MHz(148), TS2000_OTHER_TX_MODES, W(5), W(100), TS2000_MAINVFO}, - {MHz(144), MHz(148), TS2000_AM_TX_MODES, W(5), W(25), TS2000_MAINVFO}, - {MHz(430), MHz(450), TS2000_OTHER_TX_MODES, W(5), W(50), TS2000_MAINVFO}, - {MHz(430), MHz(450), TS2000_AM_TX_MODES, W(5), W(12.5), TS2000_MAINVFO}, - RIG_FRNG_END, - }, /* tx range */ - .tuning_steps = { - {RIG_MODE_SSB | RIG_MODE_CW | RIG_MODE_RTTY, 1}, - {TS2000_ALL_MODES, 10}, - {TS2000_ALL_MODES, 100}, - {TS2000_ALL_MODES, kHz(1)}, - {TS2000_ALL_MODES, kHz(2.5)}, - {TS2000_ALL_MODES, kHz(5)}, - {RIG_MODE_AM | RIG_MODE_FM, kHz(6.25)}, - {TS2000_ALL_MODES, kHz(10)}, - {RIG_MODE_AM | RIG_MODE_FM, kHz(12.5)}, - {RIG_MODE_AM | RIG_MODE_FM, kHz(12.5)}, - {RIG_MODE_AM | RIG_MODE_FM, kHz(15)}, - {RIG_MODE_AM | RIG_MODE_FM, kHz(20)}, - {RIG_MODE_AM | RIG_MODE_FM, kHz(25)}, - {RIG_MODE_AM | RIG_MODE_FM, kHz(30)}, - {RIG_MODE_AM | RIG_MODE_FM, kHz(50)}, - {RIG_MODE_AM | RIG_MODE_FM, kHz(100)}, - {TS2000_ALL_MODES, MHz(1)}, - {TS2000_ALL_MODES, 0}, /* any tuning step */ - RIG_TS_END, - }, - - /* mode/filter list, remember: order matters! */ - .filters = { - {RIG_MODE_SSB, kHz(2.2)}, - {RIG_MODE_CW, Hz(600)}, - {RIG_MODE_RTTY, Hz(1500)}, - {RIG_MODE_AM, kHz(6)}, - {RIG_MODE_FM | RIG_MODE_AM, kHz(12)}, - RIG_FLT_END, - }, - - .str_cal = TS2000_STR_CAL, - - .priv = (void *)& ts2000_priv_caps, - - .rig_init = kenwood_init, - .rig_open = kenwood_open, - .rig_close = kenwood_close, - .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, - .get_vfo = kenwood_get_vfo_if, - .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, - .get_ptt = kenwood_get_ptt, - .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 = ts2000_get_level, - .set_ant = kenwood_set_ant, - .get_ant = kenwood_get_ant, - .send_morse = kenwood_send_morse, - .wait_morse = rig_wait_morse, - .vfo_op = kenwood_vfo_op, - .scan = kenwood_scan, - .set_mem = kenwood_set_mem, - .get_mem = kenwood_get_mem, - .get_channel = ts2000_get_channel, - .set_channel = ts2000_set_channel, - .set_trn = kenwood_set_trn, - .get_trn = kenwood_get_trn, - .set_powerstat = kenwood_set_powerstat, - .get_powerstat = kenwood_get_powerstat, - .get_info = kenwood_get_info, - .reset = kenwood_reset, - - .hamlib_check_rig_caps = HAMLIB_CHECK_RIG_CAPS -}; - /* * Function definitions below */ +int ts2000_init(RIG *rig) +{ + struct kenwood_priv_data *priv; + int retval; + + ENTERFUNC; + + retval = kenwood_init(rig); + + if (retval != RIG_OK) + { + return retval; + } + + priv = (struct kenwood_priv_data *) rig->state.priv; + + priv->ag_format = 3; + priv->micgain_min = 0; + priv->micgain_max = 100; + + RETURNFUNC(RIG_OK); +} + +static int ts2000_set_ex_menu(RIG *rig, int number, int value_len, int value) +{ + char buf[20]; + + ENTERFUNC; + + SNPRINTF(buf, sizeof(buf), "EX%03d0000%0*d", number, value_len, value); + + RETURNFUNC(kenwood_transaction(rig, buf, NULL, 0)); +} + +static int ts2000_get_ex_menu(RIG *rig, int number, int value_len, int *value) +{ + int retval; + char buf[20]; + char ackbuf[20]; + + rig_debug(RIG_DEBUG_TRACE, "%s called\n", __func__); + + SNPRINTF(buf, sizeof(buf), "EX%03d0000", number); + + retval = kenwood_safe_transaction(rig, buf, ackbuf, sizeof(ackbuf), + 9 + value_len); + + if (retval != RIG_OK) + { + RETURNFUNC2(retval); + } + + sscanf(ackbuf + 9, "%d", value); + + RETURNFUNC2(RIG_OK); +} + +static int ts2000_set_func(RIG *rig, vfo_t vfo, setting_t func, int status) +{ + char buf[20]; + + rig_debug(RIG_DEBUG_TRACE, "%s called\n", __func__); + + switch (func) + { + case RIG_FUNC_MON: + SNPRINTF(buf, sizeof(buf), "ML00%c", (status == 0) ? '0' : '1'); + RETURNFUNC(kenwood_transaction(rig, buf, NULL, 0)); + + case RIG_FUNC_LOCK: + SNPRINTF(buf, sizeof(buf), "LK%c%c", (status == 0) ? '0' : '1', + (status == 0) ? '0' : '1'); + RETURNFUNC(kenwood_transaction(rig, buf, NULL, 0)); + + default: + return kenwood_set_func(rig, vfo, func, status); + } +} + +static int ts2000_get_func(RIG *rig, vfo_t vfo, setting_t func, int *status) +{ + char buf[20]; + int retval; + + ENTERFUNC; + + switch (func) + { + case RIG_FUNC_MON: + { + int raw_value; + retval = kenwood_safe_transaction(rig, "ML", buf, sizeof(buf), 5); + + if (retval != RIG_OK) + { + RETURNFUNC(retval); + } + + sscanf(buf, "ML%d", &raw_value); + + *status = (raw_value > 0); + break; + } + + case RIG_FUNC_LOCK: + retval = kenwood_safe_transaction(rig, "LK", buf, sizeof(buf), 4); + + if (retval != RIG_OK) + { + RETURNFUNC(retval); + } + + *status = buf[2] != '0' || buf[3] != '0'; + break; + + default: + return kenwood_get_func(rig, vfo, func, status); + } + + RETURNFUNC(RIG_OK); +} + +/* + * WARNING: The commands differ slightly from the general versions in kenwood.c + * e.g.: "SQ"=>"SQ0" , "AG"=>"AG0" + */ +static int ts2000_set_level(RIG *rig, vfo_t vfo, setting_t level, value_t val) +{ + char levelbuf[16]; + int kenwood_val; + char vfo_num = (vfo == RIG_VFO_C) ? '1' : '0'; + + rig_debug(RIG_DEBUG_TRACE, "%s called\n", __func__); + + switch (level) + { + case RIG_LEVEL_RF: + kenwood_val = val.f * 255; + SNPRINTF(levelbuf, sizeof(levelbuf), "RG%03d", kenwood_val); + break; + + case RIG_LEVEL_AF: + return kenwood_set_level(rig, vfo, level, val); + + case RIG_LEVEL_SQL: + kenwood_val = val.f * 255; + SNPRINTF(levelbuf, sizeof(levelbuf), "SQ%c%03d", vfo_num, kenwood_val); + break; + + case RIG_LEVEL_AGC: + /* Possible values for TS-2000 are 0(=off)-020(=slow) */ + + switch (val.i) + { + case RIG_AGC_OFF: + kenwood_val = 0; + break; + + case RIG_AGC_SUPERFAST: + kenwood_val = 1; + break; + + case RIG_AGC_FAST: + kenwood_val = 5; + break; + + case RIG_AGC_MEDIUM: + kenwood_val = 10; + break; + + case RIG_AGC_SLOW: + kenwood_val = 20; + break; + + default: + rig_debug(RIG_DEBUG_ERR, "%s: unsupported agc value", __func__); + return -RIG_EINVAL; + } + + SNPRINTF(levelbuf, sizeof(levelbuf), "GT%03d", kenwood_val); + break; + + case RIG_LEVEL_MONITOR_GAIN: + kenwood_val = val.f * 9.0; + SNPRINTF(levelbuf, sizeof(levelbuf), "ML%03d", kenwood_val); + break; + + case RIG_LEVEL_NB: + kenwood_val = val.f * 10.0; + SNPRINTF(levelbuf, sizeof(levelbuf), "NL%03d", kenwood_val); + break; + + case RIG_LEVEL_NR: + kenwood_val = val.f * 9.0; + SNPRINTF(levelbuf, sizeof(levelbuf), "RL%02d", kenwood_val); + break; + + case RIG_LEVEL_PREAMP: + if (val.i != 12 && val.i != 0) + { + RETURNFUNC(-RIG_EINVAL); + } + + SNPRINTF(levelbuf, sizeof(levelbuf), "PA%c", (val.i == 12) ? '1' : '0'); + break; + + case RIG_LEVEL_ATT: + if (val.i != 12 && val.i != 0) + { + RETURNFUNC(-RIG_EINVAL); + } + + SNPRINTF(levelbuf, sizeof(levelbuf), "RA%02d", (val.i == 12) ? 1 : 0); + break; + + case RIG_LEVEL_METER: + switch (val.i) + { + case RIG_METER_SWR: + kenwood_val = 1; + break; + + case RIG_METER_COMP: + kenwood_val = 2; + break; + + case RIG_METER_ALC: + kenwood_val = 3; + break; + + default: + RETURNFUNC(-RIG_EINVAL); + } + + SNPRINTF(levelbuf, sizeof(levelbuf), "RM%d", kenwood_val); + break; + + case RIG_LEVEL_CWPITCH: + if (val.i > 1000 || val.i < 400) + { + RETURNFUNC(-RIG_EINVAL); + } + + RETURNFUNC(ts2000_set_ex_menu(rig, 31, 2, (val.i - 400) / 50)); + + default: + return kenwood_set_level(rig, vfo, level, val); + } + + return kenwood_transaction(rig, levelbuf, NULL, 0); +} + +// TS-2000 can only read one meter at a time and the user must select +// the meter using RIG_LEVEL_METER. This function returns the meter value if +// the selected meter matches the expected meter. +static int ts2000_read_meter(RIG *rig, int expected_meter, int *value) +{ + int retval; + char cmdbuf[8]; + struct rig_state *rs = &rig->state; + char ackbuf[32]; + int expected_len = 8; + int read_meter; + int read_value; + + ENTERFUNC; + + SNPRINTF(cmdbuf, sizeof(cmdbuf), "RM;"); + + retval = write_block(&rs->rigport, (unsigned char *) cmdbuf, strlen(cmdbuf)); + + rig_debug(RIG_DEBUG_TRACE, "%s: write_block retval=%d\n", __func__, retval); + + if (retval != RIG_OK) + { + RETURNFUNC(retval); + } + + // TS-2000 returns values for a single meter at the same time, for example: RM10000; + + retval = read_string(&rs->rigport, (unsigned char *) ackbuf, expected_len + 1, + NULL, 0, 0, 1); + + rig_debug(RIG_DEBUG_TRACE, "%s: read_string retval=%d\n", __func__, retval); + + if (retval < 0) + { + rig_debug(RIG_DEBUG_ERR, "%s: failed to read rig response\n", __func__); + RETURNFUNC(retval); + } + + if (retval != expected_len) + { + rig_debug(RIG_DEBUG_ERR, "%s: expected %d bytes, got %d in '%s'\n", __func__, + expected_len, retval, ackbuf); + RETURNFUNC(-RIG_EPROTO); + } + + retval = sscanf(ackbuf, "RM%1d%d;", &read_meter, &read_value); + + if (retval != 2) + { + rig_debug(RIG_DEBUG_ERR, + "%s: expected 2 values to parse for meters, got %d in '%s'\n", __func__, retval, + ackbuf); + RETURNFUNC(-RIG_EPROTO); + } + + if (read_meter == expected_meter) + { + *value = read_value; + } + else + { + *value = 0; + } + + RETURNFUNC(RIG_OK); +} + + +static int ts2000_get_level(RIG *rig, vfo_t vfo, setting_t level, value_t *val) +{ + char cmdbuf[8]; + char ackbuf[50]; + size_t ack_len, ack_len_expected; + int levelint; + int retval; + char vfo_num = (vfo == RIG_VFO_C) ? '1' : '0'; + + ENTERFUNC; + + switch (level) + { + case RIG_LEVEL_AF: + return kenwood_get_level(rig, vfo, level, val); + + case RIG_LEVEL_RF: + retval = kenwood_transaction(rig, "RG", ackbuf, sizeof(ackbuf)); + + if (RIG_OK != retval) + { + return retval; + } + + ack_len = strlen(ackbuf); + + if (5 != ack_len) + { + return -RIG_EPROTO; + } + + if (1 != sscanf(&ackbuf[2], "%d", &levelint)) + { + return -RIG_EPROTO; + } + + val->f = levelint / (float) 255; + return RIG_OK; + + case RIG_LEVEL_SQL: + SNPRINTF(cmdbuf, sizeof(cmdbuf), "SQ%c", vfo_num); + retval = kenwood_transaction(rig, cmdbuf, ackbuf, sizeof(ackbuf)); + ack_len_expected = 6; + + if (retval != RIG_OK) + { + return retval; + } + + ack_len = strlen(ackbuf); + + if (ack_len != ack_len_expected) + { + return -RIG_EPROTO; + } + + if (sscanf(&ackbuf[ack_len_expected - 3], "%d", &levelint) != 1) + { + return -RIG_EPROTO; + } + + val->f = (float) levelint / 255.f; + return RIG_OK; + + case RIG_LEVEL_AGC: + retval = kenwood_transaction(rig, "GT", ackbuf, sizeof(ackbuf)); + ack_len_expected = 5; + + if (RIG_OK != retval) + { + return retval; + } + + ack_len = strlen(ackbuf); + + if (ack_len != ack_len_expected) + { + return -RIG_EPROTO; + } + + if (1 != sscanf(&ackbuf[ack_len_expected - 3], "%d", &levelint)) + { + return -RIG_EPROTO; + } + + if (levelint == 0) + { + val->i = RIG_AGC_OFF; + } + else if (levelint <= 1) + { + val->i = RIG_AGC_SUPERFAST; + } + else if (levelint <= 5) + { + val->i = RIG_AGC_FAST; + } + else if (levelint <= 10) + { + val->i = RIG_AGC_MEDIUM; + } + else + { + val->i = RIG_AGC_SLOW; + } + + return RIG_OK; + + case RIG_LEVEL_STRENGTH: + if (rig->state.cache.ptt != RIG_PTT_OFF) + { + val->i = -9 * 6; + break; + } + + return kenwood_get_level(rig, vfo, level, val); + + case RIG_LEVEL_MONITOR_GAIN: + { + int raw_value; + retval = kenwood_safe_transaction(rig, "ML", ackbuf, sizeof(ackbuf), 5); + + if (retval != RIG_OK) + { + RETURNFUNC(retval); + } + + sscanf(ackbuf, "ML%d", &raw_value); + + val->f = (float) raw_value / 9.0f; + break; + } + + case RIG_LEVEL_NB: + { + int raw_value; + retval = kenwood_safe_transaction(rig, "NL", ackbuf, sizeof(ackbuf), 5); + + if (retval != RIG_OK) + { + RETURNFUNC(retval); + } + + sscanf(ackbuf, "NL%d", &raw_value); + + val->f = (float) raw_value / 10.0f; + break; + } + + case RIG_LEVEL_NR: + { + int raw_value; + retval = kenwood_safe_transaction(rig, "RL", ackbuf, sizeof(ackbuf), 4); + + if (retval != RIG_OK) + { + RETURNFUNC(retval); + } + + sscanf(ackbuf, "RL%d", &raw_value); + + val->f = (float) raw_value / 9.0f; + break; + } + + case RIG_LEVEL_PREAMP: + retval = kenwood_safe_transaction(rig, "PA", ackbuf, sizeof(ackbuf), 4); + + if (retval != RIG_OK) + { + RETURNFUNC(retval); + } + + val->i = ackbuf[2] == '1' ? 12 : 0; + break; + + case RIG_LEVEL_ATT: + retval = kenwood_safe_transaction(rig, "RA", ackbuf, sizeof(ackbuf), 6); + + if (retval != RIG_OK) + { + RETURNFUNC(retval); + } + + val->i = ackbuf[3] == '1' ? 12 : 0; + break; + + case RIG_LEVEL_METER: + { + int raw_value; + + // TODO: Read all meters at the same time: RM10000;RM20000;RM30000; + + retval = kenwood_safe_transaction(rig, "RM", ackbuf, sizeof(ackbuf), 7); + + if (retval != RIG_OK) + { + RETURNFUNC(retval); + } + + sscanf(ackbuf, "RM%1d", &raw_value); + + switch (raw_value) + { + case 1: + val->i = RIG_METER_SWR; + break; + + case 2: + val->i = RIG_METER_COMP; + break; + + case 3: + val->i = RIG_METER_ALC; + break; + + default: + val->i = RIG_METER_NONE; + } + + break; + } + + case RIG_LEVEL_SWR: + case RIG_LEVEL_COMP_METER: + case RIG_LEVEL_ALC: + { + int meter; + int swr; + int comp; + int *value; + int alc; + + switch (level) { + case RIG_LEVEL_SWR: + meter = 1; + value = &swr; + break; + case RIG_LEVEL_COMP_METER: + meter = 2; + value = ∁ + break; + case RIG_LEVEL_ALC: + meter = 3; + value = &alc; + break; + default: + RETURNFUNC(-RIG_EINVAL); + } + + retval = ts2000_read_meter(rig, meter, value); + if (retval != RIG_OK) + { + RETURNFUNC(retval); + } + + switch (level) + { + case RIG_LEVEL_SWR: + if (rig->caps->swr_cal.size) + { + val->f = rig_raw2val_float(swr, &rig->caps->swr_cal); + } + else + { + val->f = (float) swr / 2.0f; + } + + break; + + case RIG_LEVEL_COMP_METER: + val->f = (float) comp; // Maximum value is 20dB + break; + + case RIG_LEVEL_ALC: + // Maximum value is 20, so have the max at 5 just to be on the range where other rigs report ALC + val->f = (float) alc / 4.0f; + break; + + default: + return -RIG_ENAVAIL; + } + + break; + } + + case RIG_LEVEL_RFPOWER_METER: + { + int raw_value; + char read_vfo_num; + + if (rig->state.cache.ptt == RIG_PTT_OFF) + { + val->f = 0; + break; + } + + SNPRINTF(cmdbuf, sizeof(cmdbuf), "SM%c", vfo_num); + + retval = kenwood_safe_transaction(rig, cmdbuf, ackbuf, sizeof(ackbuf), 7); + + if (retval != RIG_OK) + { + RETURNFUNC(retval); + } + + sscanf(ackbuf, "SM%c%d", &read_vfo_num, &raw_value); + + if (vfo_num == '1') + { + val->f = (float) raw_value / 15.0f; + } + else + { + val->f = (float) raw_value / 30.0f; + } + break; + } + + case RIG_LEVEL_CWPITCH: + { + int raw_value; + retval = ts2000_get_ex_menu(rig, 31, 2, &raw_value); + + if (retval != RIG_OK) + { + RETURNFUNC(retval); + } + + val->i = 400 + raw_value * 50; + break; + } + + default: + return kenwood_get_level(rig, vfo, level, val); + } + + RETURNFUNC(RIG_OK); +} + +static int ts2000_set_rit(RIG *rig, vfo_t vfo, shortfreq_t rit) +{ + char buf[20]; + int retval; + int rit_enabled; + int xit_enabled; + + ENTERFUNC; + + if (rit < -19999 || rit > 19999) + { + RETURNFUNC(-RIG_EINVAL); + } + + // RC clear command cannot be executed if RIT/XIT is not enabled + + retval = kenwood_get_func(rig, vfo, RIG_FUNC_RIT, &rit_enabled); + + if (retval != RIG_OK) + { + RETURNFUNC(retval); + } + + if (!rit_enabled) + { + retval = kenwood_get_func(rig, vfo, RIG_FUNC_XIT, &xit_enabled); + + if (retval != RIG_OK) + { + RETURNFUNC(retval); + } + } + + if (!rit_enabled && !xit_enabled) + { + retval = kenwood_set_func(rig, vfo, RIG_FUNC_RIT, 1); + + if (retval != RIG_OK) + { + RETURNFUNC(retval); + } + } + + retval = kenwood_transaction(rig, "RC", NULL, 0); + + if (retval != RIG_OK) + { + RETURNFUNC(retval); + } + + if (!rit_enabled && !xit_enabled) + { + retval = kenwood_set_func(rig, vfo, RIG_FUNC_RIT, 0); + + if (retval != RIG_OK) + { + RETURNFUNC(retval); + } + } + + if (rit == 0) + { + RETURNFUNC(RIG_OK); + } + + SNPRINTF(buf, sizeof(buf), "R%c%05d", (rit > 0) ? 'U' : 'D', abs((int) rit)); + retval = kenwood_transaction(rig, buf, NULL, 0); + + RETURNFUNC(retval); +} + +static int ts2000_get_rit(RIG *rig, vfo_t vfo, shortfreq_t *rit) +{ + int retval; + char buf[7]; + struct kenwood_priv_data *priv = rig->state.priv; + + ENTERFUNC; + + if (!rit) + { + RETURNFUNC(-RIG_EINVAL); + } + + retval = kenwood_get_if(rig); + + if (retval != RIG_OK) + { + RETURNFUNC(retval); + } + + memcpy(buf, &priv->info[18], 5); + + buf[6] = '\0'; + *rit = atoi(buf); + + RETURNFUNC(RIG_OK); +} + +static int ts2000_set_ext_func(RIG *rig, vfo_t vfo, token_t token, int status) +{ + char cmdbuf[20]; + int retval; + + ENTERFUNC; + + switch (token) + { + case TOK_FUNC_NOISE_REDUCTION_2: + if (status < 0 || status > 1) + { + RETURNFUNC(-RIG_EINVAL); + } + + SNPRINTF(cmdbuf, sizeof(cmdbuf), "NR%d", status ? 2 : 0); + retval = kenwood_transaction(rig, cmdbuf, NULL, 0); + break; + + default: + RETURNFUNC(-RIG_EINVAL); + } + + RETURNFUNC(retval); +} + +static int ts2000_get_ext_func(RIG *rig, vfo_t vfo, token_t token, int *status) +{ + char ackbuf[20]; + int retval; + + ENTERFUNC; + + switch (token) + { + case TOK_FUNC_NOISE_REDUCTION_2: + { + int value; + + retval = kenwood_safe_transaction(rig, "NR", ackbuf, sizeof(ackbuf), 3); + + if (retval != RIG_OK) + { + RETURNFUNC(retval); + } + + sscanf(ackbuf, "NR%d", &value); + + *status = (value == 2) ? 1 : 0; + break; + } + + default: + RETURNFUNC(-RIG_EINVAL); + } + + RETURNFUNC(retval); +} + +static int ts2000_set_ext_level(RIG *rig, vfo_t vfo, token_t token, value_t val) +{ + int retval; + + ENTERFUNC; + + switch (token) + { + case TOK_LEVEL_DSP_RX_EQUALIZER: + if (val.i < 0 || val.i > 5) + { + RETURNFUNC(-RIG_EINVAL); + } + + retval = ts2000_set_ex_menu(rig, 20, 1, val.i); + break; + + case TOK_LEVEL_DSP_TX_EQUALIZER: + if (val.i < 0 || val.i > 5) + { + RETURNFUNC(-RIG_EINVAL); + } + + retval = ts2000_set_ex_menu(rig, 21, 1, val.i); + break; + + case TOK_LEVEL_DSP_TX_BANDWIDTH: + if (val.i < 0 || val.i > 5) + { + RETURNFUNC(-RIG_EINVAL); + } + + retval = ts2000_set_ex_menu(rig, 22, 1, val.i); + break; + + case TOK_LEVEL_BEEP_VOLUME: + if (val.f < 0 || val.f > 9) + { + RETURNFUNC(-RIG_EINVAL); + } + + retval = ts2000_set_ex_menu(rig, 12, 1, (int) val.f); + break; + + case TOK_LEVEL_TX_SIDETONE_VOLUME: + if (val.f < 0 || val.f > 9) + { + RETURNFUNC(-RIG_EINVAL); + } + + retval = ts2000_set_ex_menu(rig, 13, 1, (int) val.f); + break; + + default: + RETURNFUNC(-RIG_EINVAL); + } + + RETURNFUNC(retval); +} + +static int ts2000_get_ext_level(RIG *rig, vfo_t vfo, token_t token, value_t *val) +{ + int retval; + int value; + + ENTERFUNC; + + switch (token) + { + case TOK_LEVEL_DSP_RX_EQUALIZER: + retval = ts2000_get_ex_menu(rig, 20, 1, &value); + val->i = value; + break; + + case TOK_LEVEL_DSP_TX_EQUALIZER: + retval = ts2000_get_ex_menu(rig, 21, 1, &value); + val->i = value; + break; + + case TOK_LEVEL_DSP_TX_BANDWIDTH: + retval = ts2000_get_ex_menu(rig, 22, 1, &value); + val->i = value; + break; + + case TOK_LEVEL_BEEP_VOLUME: + retval = ts2000_get_ex_menu(rig, 12, 1, &value); + val->f = value; + break; + + case TOK_LEVEL_TX_SIDETONE_VOLUME: + retval = ts2000_get_ex_menu(rig, 13, 1, &value); + val->f = value; + break; + + default: + RETURNFUNC(-RIG_EINVAL); + } + + RETURNFUNC(retval); +} + /* * ts2000_get_channel * Read command format: @@ -816,360 +1661,245 @@ int ts2000_set_channel(RIG *rig, vfo_t vfo, const channel_t *chan) } /* - * ts2000_get_level - * Assumes rig!=NULL, val!=NULL + * TS-2000 rig capabilities */ - -int ts2000_get_level(RIG *rig, vfo_t vfo, setting_t level, value_t *val) +const struct rig_caps ts2000_caps = { - char lvlbuf[50]; - size_t lvl_len; - int lvl, retval, ret, agclevel; + RIG_MODEL(RIG_MODEL_TS2000), + .model_name = "TS-2000", + .mfg_name = "Kenwood", + .version = BACKEND_VER ".1", + .copyright = "LGPL", + .status = RIG_STATUS_STABLE, + .rig_type = RIG_TYPE_TRANSCEIVER, + .ptt_type = RIG_PTT_RIG, + .dcd_type = RIG_DCD_RIG, + .port_type = RIG_PORT_SERIAL, + .serial_rate_min = 1200, + .serial_rate_max = 57600, + .serial_data_bits = 8, + .serial_stop_bits = 1, + .serial_parity = RIG_PARITY_NONE, + .serial_handshake = RIG_HANDSHAKE_NONE, + .write_delay = 0, + .post_write_delay = 0, /* ms */ + .timeout = 200, + .retry = 3, - lvl_len = 50; - - switch (level) + .has_get_func = TS2000_FUNC_ALL, + .has_set_func = TS2000_FUNC_ALL, + .has_get_level = TS2000_LEVEL_GET, + .has_set_level = TS2000_LEVEL_SET, + .has_get_parm = RIG_PARM_NONE, + .has_set_parm = RIG_PARM_NONE, + .level_gran = { - - case RIG_LEVEL_PREAMP: - retval = kenwood_transaction(rig, "PA", lvlbuf, sizeof(lvlbuf)); - - if (retval != RIG_OK) - { - return retval; - } - - lvl_len = strlen(lvlbuf); - - if ((lvl_len != 4)) /*TS-2000 returns 4 chars for PA; */ - { - rig_debug(RIG_DEBUG_ERR, "%s: unexpected answer len=%d\n", - __func__, (int)lvl_len); - return -RIG_ERJCTED; - } - - sscanf(lvlbuf + 2, "%d", &lvl); - - if (lvl < 10) /* just checking for main receiver preamp setting */ - { - val->i = 0; - } - - if (lvl > 9) - { - val->i = rig->state.preamp[0]; - } - - break; - - case RIG_LEVEL_ATT: - retval = kenwood_transaction(rig, "RA", lvlbuf, sizeof(lvlbuf)); - - if (retval != RIG_OK) - { - return retval; - } - - lvl_len = strlen(lvlbuf); - - if ((lvl_len != 6)) /* TS-2000 returns 6 chars for RA; */ - { - rig_debug(RIG_DEBUG_ERR, "%s: unexpected answer len=%d\n", __func__, - (int)lvl_len); - return -RIG_ERJCTED; - } - - sscanf(lvlbuf + 2, "%d", &lvl); - - if (lvl < 100) /* just checking main band attenuator */ - { - val->i = 0; - } - - if (lvl > 99) - { - val->i = rig->state.attenuator[0]; /* Since the TS-2000 only has one step on the attenuator */ - } - - break; - - case RIG_LEVEL_VOXDELAY: - retval = kenwood_transaction(rig, "VD", lvlbuf, sizeof(lvlbuf)); - - if (retval != RIG_OK) - { - return retval; - } - - lvl_len = strlen(lvlbuf); - - if (lvl_len != 6) - { - rig_debug(RIG_DEBUG_ERR, "%s: unexpected answer len=%d\n", __func__, - (int)lvl_len); - return -RIG_ERJCTED; - } - - sscanf(lvlbuf + 2, "%d", &lvl); - val->i = lvl / 100; - break; - - case RIG_LEVEL_AF: - return kenwood_get_level(rig, vfo, level, val); - - case RIG_LEVEL_RF: - retval = kenwood_transaction(rig, "RG", lvlbuf, sizeof(lvlbuf)); - - if (retval != RIG_OK) - { - return retval; - } - - lvl_len = strlen(lvlbuf); - - if (lvl_len != 5) - { - rig_debug(RIG_DEBUG_ERR, "%s: unexpected answer len=%d\n", __func__, - (int)lvl_len); - return -RIG_ERJCTED; - } - - sscanf(lvlbuf + 2, "%d", &lvl); - val->f = lvl / 255.0; - break; - - case RIG_LEVEL_SQL: - retval = kenwood_transaction(rig, "SQ0", lvlbuf, sizeof(lvlbuf)); - - if (retval != RIG_OK) - { - return retval; - } - - lvl_len = strlen(lvlbuf); - - if (lvl_len != 6) - { - rig_debug(RIG_DEBUG_ERR, "%s: unexpected answer len=%d\n", __func__, - (int)lvl_len); - return -RIG_ERJCTED; - } - - sscanf(lvlbuf + 3, "%d", &lvl); - val->f = lvl / 255.0; - break; - - case RIG_LEVEL_CWPITCH: - retval = kenwood_transaction(rig, "EX0310000", lvlbuf, sizeof(lvlbuf)); - - if (retval != RIG_OK) - { - return retval; - } - - lvl_len = strlen(lvlbuf); - - if (lvl_len != 15) - { - rig_debug(RIG_DEBUG_ERR, "%s: unexpected answer len=%d answer=%s\n", __func__, - (int)lvl_len, lvlbuf); - return -RIG_ERJCTED; - } - - sscanf(lvlbuf + 8, "%d", &lvl); - val->i = 400 + (50 * lvl); - break; - - case RIG_LEVEL_RFPOWER: - retval = kenwood_transaction(rig, "PC", lvlbuf, sizeof(lvlbuf)); - - if (retval != RIG_OK) - { - return retval; - } - - lvl_len = strlen(lvlbuf); - - if (lvl_len != 5) - { - rig_debug(RIG_DEBUG_ERR, "%s: unexpected answer len=%d\n", __func__, - (int)lvl_len); - return -RIG_ERJCTED; - } - - sscanf(lvlbuf + 3, "%d", &lvl); - val->f = lvl / 100.0; /* FIXME: for 1.2GHZ need to divide by 10 */ - break; - - case RIG_LEVEL_MICGAIN: - return kenwood_get_level(rig, vfo, level, val); - - case RIG_LEVEL_KEYSPD: - retval = kenwood_transaction(rig, "KS", lvlbuf, sizeof(lvlbuf)); - - if (retval != RIG_OK) - { - return retval; - } - - lvl_len = strlen(lvlbuf); - - if (lvl_len != 5) - { - rig_debug(RIG_DEBUG_ERR, "%s: unexpected answer len=%d\n", __func__, - (int)lvl_len); - return -RIG_ERJCTED; - } - - sscanf(lvlbuf + 2, "%d", &lvl); - val->i = lvl; - break; - - case RIG_LEVEL_NOTCHF: - return -RIG_ENIMPL; - break; - - case RIG_LEVEL_COMP: - retval = kenwood_transaction(rig, "PL", lvlbuf, sizeof(lvlbuf)); - - if (retval != RIG_OK) - { - return retval; - } - - lvl_len = strlen(lvlbuf); - - if (lvl_len != 8) - { - rig_debug(RIG_DEBUG_ERR, "%s: unexpected answer len=%d\n", __func__, - (int)lvl_len); - return -RIG_ERJCTED; - } - - sscanf(lvlbuf + 2, "%d", &lvl); - lvl = lvl / 1000; - val->f = lvl / 100.0; - break; - - - case RIG_LEVEL_AGC: /* FIX ME: ts2000 returns 0 -20 for AGC */ - ret = get_kenwood_level(rig, "GT", &val->f, NULL); - agclevel = 255.0 * val->f; - - if (agclevel == 0) { val->i = 0; } - else if (agclevel < 85) { val->i = 1; } - else if (agclevel < 170) { val->i = 2; } - else if (agclevel <= 255) { val->i = 3; } - - return ret; - break; - - case RIG_LEVEL_BKINDL: - retval = kenwood_transaction(rig, "SD", lvlbuf, sizeof(lvlbuf)); - - if (retval != RIG_OK) - { - return retval; - } - - lvl_len = strlen(lvlbuf); - - if (lvl_len != 6) - { - rig_debug(RIG_DEBUG_ERR, "%s: unexpected answer len=%d\n", __func__, - (int)lvl_len); - return -RIG_ERJCTED; - } - - sscanf(lvlbuf + 2, "%d", &lvl); - val->i = lvl / 100; - break; - - case RIG_LEVEL_BALANCE: - return -RIG_ENIMPL; - break; - - case RIG_LEVEL_METER: - retval = kenwood_transaction(rig, "RM", lvlbuf, sizeof(lvlbuf)); - - if (retval != RIG_OK) - { - return retval; - } - - lvl_len = strlen(lvlbuf); - - if (lvl_len != 7) - { - rig_debug(RIG_DEBUG_ERR, "%s: unexpected answer len=%d\n", __func__, - (int)lvl_len); - return -RIG_ERJCTED; - } - - sscanf(lvlbuf + 2, "%d", &lvl); - val->i = lvl / 10000; - break; - - case RIG_LEVEL_VOXGAIN: - retval = kenwood_transaction(rig, "VG", lvlbuf, sizeof(lvlbuf)); - - if (retval != RIG_OK) - { - return retval; - } - - lvl_len = strlen(lvlbuf); - - if (lvl_len != 5) - { - rig_debug(RIG_DEBUG_ERR, "%s: unexpected answer len=%d\n", __func__, - (int)lvl_len); - return -RIG_ERJCTED; - } - - sscanf(lvlbuf + 2, "%d", &lvl); - val->f = lvl / 9.0; - break; - - case RIG_LEVEL_ANTIVOX: - return -RIG_ENIMPL; - break; - - case RIG_LEVEL_RAWSTR: - case RIG_LEVEL_STRENGTH: - retval = kenwood_transaction(rig, "SM0", lvlbuf, sizeof(lvlbuf)); - - if (retval != RIG_OK) - { - return retval; - } - - lvl_len = strlen(lvlbuf); - - if (((lvl_len != 7)) || lvlbuf[1] != 'M') - { - /* TS-2000 returns 8 bytes for S meter level */ - rig_debug(RIG_DEBUG_ERR, "%s: wrong answer len=%d\n", __func__, (int)lvl_len); - return -RIG_ERJCTED; - } - - /* Frontend expects: -54 = S0, 0 = S9 */ - sscanf(lvlbuf + 3, "%d", &val->i); - - /* TS-2000 main receiver returns values from 0 - 30 */ - /* so scale the value */ - if (level == RIG_LEVEL_STRENGTH) - { - val->i = (val->i * 3.6) - 54; - } - - break; - - default: - rig_debug(RIG_DEBUG_ERR, "%s: unsupported get_level %s", __func__, - rig_strlevel(level)); - return -RIG_EINVAL; - } - - return RIG_OK; -} +#include "level_gran_kenwood.h" + [LVL_RAWSTR] = { .min = { .i = 0 }, .max = { .i = 255 } }, + [LVL_VOXDELAY] = { .min = { .i = 0 }, .max = { .i = 30 }, .step = { .i = 1 } }, + [LVL_KEYSPD] = {.min = {.i = 10}, .max = {.i = 60}, .step = {.i = 1}}, + [LVL_CWPITCH] = {.min = {.i = 400}, .max = {.i = 1000}, .step = {.i = 50}}, + [LVL_BKIN_DLYMS] = {.min = {.i = 0}, .max = {.i = 1000}, .step = {.i = 50}}, + [LVL_SLOPE_LOW] = {.min = {.i = 0}, .max = {.i = 1000}, .step = {.i = 10}}, + [LVL_SLOPE_HIGH] = {.min = {.i = 0}, .max = {.i = 5000}, .step = {.i = 10}}, + }, + .parm_gran = {}, + .vfo_ops = TS2000_VFO_OPS, + .scan_ops = TS2000_SCAN_OP, + .ctcss_list = ts2000_ctcss_list, + .dcs_list = ts2000_dcs_list, + .preamp = { 12, RIG_DBLST_END, }, + .attenuator = { 12, RIG_DBLST_END, }, + .max_rit = kHz(20), + .max_xit = kHz(20), + .max_ifshift = kHz(1), + .targetable_vfo = RIG_TARGETABLE_FREQ, + .transceive = RIG_TRN_RIG, + .agc_level_count = 5, + .agc_levels = { RIG_AGC_OFF, RIG_AGC_SLOW, RIG_AGC_MEDIUM, RIG_AGC_FAST, RIG_AGC_SUPERFAST }, + .bank_qty = 0, + .chan_desc_sz = 7, + + .chan_list = { + { 0, 299, RIG_MTYPE_MEM, TS2000_MEM_CAP }, + RIG_CHAN_END, + }, + + .rx_range_list1 = { + {kHz(300), MHz(60), TS2000_ALL_MODES, -1, -1, TS2000_MAINVFO, TS2000_ANTS}, + {MHz(144), MHz(146), TS2000_ALL_MODES, -1, -1, TS2000_MAINVFO}, + {MHz(430), MHz(440), TS2000_ALL_MODES, -1, -1, TS2000_MAINVFO}, + {MHz(144), MHz(146), TS2000_ALL_MODES, -1, -1, TS2000_SUBVFO}, + {MHz(430), MHz(440), TS2000_ALL_MODES, -1, -1, TS2000_SUBVFO}, + RIG_FRNG_END, + }, /* rx range */ + .tx_range_list1 = { + {kHz(1830), kHz(1850), TS2000_OTHER_TX_MODES, W(5), W(100), TS2000_MAINVFO, TS2000_ANTS}, + {kHz(1830), kHz(1850), TS2000_AM_TX_MODES, 2000, 25000, TS2000_MAINVFO, TS2000_ANTS}, + {kHz(3500), kHz(3800), TS2000_OTHER_TX_MODES, W(5), W(100), TS2000_MAINVFO, TS2000_ANTS}, + {kHz(3500), kHz(3800), TS2000_AM_TX_MODES, W(5), W(25), TS2000_MAINVFO, TS2000_ANTS}, + {MHz(7), kHz(7100), TS2000_OTHER_TX_MODES, W(5), W(100), TS2000_MAINVFO, TS2000_ANTS}, + {MHz(7), kHz(7100), TS2000_AM_TX_MODES, W(5), W(25), TS2000_MAINVFO, TS2000_ANTS}, + {MHz(10.1), MHz(10.15), TS2000_OTHER_TX_MODES, W(5), W(100), TS2000_MAINVFO, TS2000_ANTS}, + {MHz(10.1), MHz(10.15), TS2000_AM_TX_MODES, W(5), W(25), TS2000_MAINVFO, TS2000_ANTS}, + {MHz(14), kHz(14350), TS2000_OTHER_TX_MODES, W(5), W(100), TS2000_MAINVFO, TS2000_ANTS}, + {MHz(14), kHz(14350), TS2000_AM_TX_MODES, W(5), W(25), TS2000_MAINVFO, TS2000_ANTS}, + {kHz(18068), kHz(18168), TS2000_OTHER_TX_MODES, W(5), W(100), TS2000_MAINVFO, TS2000_ANTS}, + {kHz(18068), kHz(18168), TS2000_AM_TX_MODES, W(5), W(25), TS2000_MAINVFO, TS2000_ANTS}, + {MHz(21), kHz(21450), TS2000_OTHER_TX_MODES, W(5), W(100), TS2000_MAINVFO, TS2000_ANTS}, + {MHz(21), kHz(21450), TS2000_AM_TX_MODES, W(5), W(25), TS2000_MAINVFO, TS2000_ANTS}, + {kHz(24890), kHz(24990), TS2000_OTHER_TX_MODES, W(5), W(100), TS2000_MAINVFO, TS2000_ANTS}, + {kHz(24890), kHz(24990), TS2000_AM_TX_MODES, W(5), W(25), TS2000_MAINVFO, TS2000_ANTS}, + {MHz(28), kHz(29700), TS2000_OTHER_TX_MODES, W(5), W(100), TS2000_MAINVFO, TS2000_ANTS}, + {MHz(28), kHz(29700), TS2000_AM_TX_MODES, W(5), W(25), TS2000_MAINVFO, TS2000_ANTS}, + {MHz(50), MHz(50.2), TS2000_OTHER_TX_MODES, W(5), W(100), TS2000_MAINVFO, TS2000_ANTS}, + {MHz(50), MHz(50.2), TS2000_AM_TX_MODES, W(5), W(25), TS2000_MAINVFO, TS2000_ANTS}, + {MHz(144), MHz(146), TS2000_OTHER_TX_MODES, W(5), W(100), TS2000_MAINVFO}, + {MHz(144), MHz(146), TS2000_AM_TX_MODES, W(5), W(25), TS2000_MAINVFO}, + {MHz(430), MHz(440), TS2000_OTHER_TX_MODES, W(5), W(50), TS2000_MAINVFO}, + {MHz(430), MHz(440), TS2000_AM_TX_MODES, W(5), W(12.5), TS2000_MAINVFO}, + RIG_FRNG_END, + }, /* tx range */ + + .rx_range_list2 = { + {kHz(300), MHz(60), TS2000_ALL_MODES, -1, -1, TS2000_MAINVFO, TS2000_ANTS}, + {MHz(142), MHz(152), TS2000_ALL_MODES, -1, -1, TS2000_MAINVFO}, + {MHz(420), MHz(450), TS2000_ALL_MODES, -1, -1, TS2000_MAINVFO}, + {MHz(118), MHz(174), TS2000_ALL_MODES, -1, -1, TS2000_SUBVFO}, + {MHz(220), MHz(512), TS2000_ALL_MODES, -1, -1, TS2000_SUBVFO}, + RIG_FRNG_END, + }, /* rx range */ + .tx_range_list2 = { + {kHz(1800), MHz(2), TS2000_OTHER_TX_MODES, W(5), W(100), TS2000_MAINVFO, TS2000_ANTS}, + {kHz(1800), MHz(2), TS2000_AM_TX_MODES, 2000, 25000, TS2000_MAINVFO, TS2000_ANTS}, + {kHz(3500), MHz(4), TS2000_OTHER_TX_MODES, W(5), W(100), TS2000_MAINVFO, TS2000_ANTS}, + {kHz(3500), MHz(4), TS2000_AM_TX_MODES, W(5), W(25), TS2000_MAINVFO, TS2000_ANTS}, + {MHz(7), kHz(7300), TS2000_OTHER_TX_MODES, W(5), W(100), TS2000_MAINVFO, TS2000_ANTS}, + {MHz(7), kHz(7300), TS2000_AM_TX_MODES, W(5), W(25), TS2000_MAINVFO, TS2000_ANTS}, + {MHz(10.1), MHz(10.15), TS2000_OTHER_TX_MODES, W(5), W(100), TS2000_MAINVFO, TS2000_ANTS}, + {MHz(10.1), MHz(10.15), TS2000_AM_TX_MODES, W(5), W(25), TS2000_MAINVFO, TS2000_ANTS}, + {MHz(14), kHz(14350), TS2000_OTHER_TX_MODES, W(5), W(100), TS2000_MAINVFO, TS2000_ANTS}, + {MHz(14), kHz(14350), TS2000_AM_TX_MODES, W(5), W(25), TS2000_MAINVFO, TS2000_ANTS}, + {kHz(18068), kHz(18168), TS2000_OTHER_TX_MODES, W(5), W(100), TS2000_MAINVFO, TS2000_ANTS}, + {kHz(18068), kHz(18168), TS2000_AM_TX_MODES, W(5), W(25), TS2000_MAINVFO, TS2000_ANTS}, + {MHz(21), kHz(21450), TS2000_OTHER_TX_MODES, W(5), W(100), TS2000_MAINVFO, TS2000_ANTS}, + {MHz(21), kHz(21450), TS2000_AM_TX_MODES, W(5), W(25), TS2000_MAINVFO, TS2000_ANTS}, + {kHz(24890), kHz(24990), TS2000_OTHER_TX_MODES, W(5), W(100), TS2000_MAINVFO, TS2000_ANTS}, + {kHz(24890), kHz(24990), TS2000_AM_TX_MODES, W(5), W(25), TS2000_MAINVFO, TS2000_ANTS}, + {MHz(28), kHz(29700), TS2000_OTHER_TX_MODES, W(5), W(100), TS2000_MAINVFO, TS2000_ANTS}, + {MHz(28), kHz(29700), TS2000_AM_TX_MODES, W(5), W(25), TS2000_MAINVFO, TS2000_ANTS}, + {MHz(50), MHz(54), TS2000_OTHER_TX_MODES, W(5), W(100), TS2000_MAINVFO, TS2000_ANTS}, + {MHz(50), MHz(54), TS2000_AM_TX_MODES, W(5), W(25), TS2000_MAINVFO, TS2000_ANTS}, + {MHz(144), MHz(148), TS2000_OTHER_TX_MODES, W(5), W(100), TS2000_MAINVFO}, + {MHz(144), MHz(148), TS2000_AM_TX_MODES, W(5), W(25), TS2000_MAINVFO}, + {MHz(430), MHz(450), TS2000_OTHER_TX_MODES, W(5), W(50), TS2000_MAINVFO}, + {MHz(430), MHz(450), TS2000_AM_TX_MODES, W(5), W(12.5), TS2000_MAINVFO}, + RIG_FRNG_END, + }, /* tx range */ + + .tuning_steps = { + {RIG_MODE_SSB | RIG_MODE_CW | RIG_MODE_RTTY, 1}, + {TS2000_ALL_MODES, 10}, + {TS2000_ALL_MODES, 100}, + {TS2000_ALL_MODES, kHz(1)}, + {TS2000_ALL_MODES, kHz(2.5)}, + {TS2000_ALL_MODES, kHz(5)}, + {RIG_MODE_AM | RIG_MODE_FM, kHz(6.25)}, + {TS2000_ALL_MODES, kHz(10)}, + {RIG_MODE_AM | RIG_MODE_FM, kHz(12.5)}, + {RIG_MODE_AM | RIG_MODE_FM, kHz(12.5)}, + {RIG_MODE_AM | RIG_MODE_FM, kHz(15)}, + {RIG_MODE_AM | RIG_MODE_FM, kHz(20)}, + {RIG_MODE_AM | RIG_MODE_FM, kHz(25)}, + {RIG_MODE_AM | RIG_MODE_FM, kHz(30)}, + {RIG_MODE_AM | RIG_MODE_FM, kHz(50)}, + {RIG_MODE_AM | RIG_MODE_FM, kHz(100)}, + {TS2000_ALL_MODES, MHz(1)}, + {TS2000_ALL_MODES, 0}, /* any tuning step */ + RIG_TS_END, + }, + + /* mode/filter list, remember: order matters! */ + .filters = { + {RIG_MODE_SSB, kHz(2.2)}, + {RIG_MODE_CW | RIG_MODE_CWR, Hz(200)}, + {RIG_MODE_CW | RIG_MODE_CWR, Hz(50)}, + {RIG_MODE_CW | RIG_MODE_CWR, Hz(1000)}, + {RIG_MODE_CW | RIG_MODE_CWR, Hz(80)}, + {RIG_MODE_CW | RIG_MODE_CWR, Hz(100)}, + {RIG_MODE_CW | RIG_MODE_CWR, Hz(150)}, + {RIG_MODE_CW | RIG_MODE_CWR, Hz(300)}, + {RIG_MODE_CW | RIG_MODE_CWR, Hz(400)}, + {RIG_MODE_CW | RIG_MODE_CWR, Hz(500)}, + {RIG_MODE_CW | RIG_MODE_CWR, Hz(600)}, + {RIG_MODE_CW | RIG_MODE_CWR, Hz(2000)}, + {RIG_MODE_RTTY | RIG_MODE_RTTYR, Hz(500)}, + {RIG_MODE_RTTY | RIG_MODE_RTTYR, Hz(250)}, + {RIG_MODE_RTTY | RIG_MODE_RTTYR, Hz(1000)}, + {RIG_MODE_RTTY | RIG_MODE_RTTYR, Hz(1500)}, + {RIG_MODE_AM, kHz(6)}, + {RIG_MODE_AM, kHz(2.4)}, + {RIG_MODE_FM, kHz(12)}, + {RIG_MODE_FM, kHz(6)}, + RIG_FLT_END, + }, + + .str_cal = TS2000_STR_CAL, + .swr_cal = TS2000_SWR_CAL, + + .ext_tokens = ts2000_ext_tokens, + .extfuncs = ts2000_ext_funcs, + .extlevels = ts2000_ext_levels, + + .priv = (void *)& ts2000_priv_caps, + + .rig_init = ts2000_init, + .rig_open = kenwood_open, + .rig_close = kenwood_close, + .rig_cleanup = kenwood_cleanup, + .set_freq = kenwood_set_freq, + .get_freq = kenwood_get_freq, + .set_rit = ts2000_set_rit, + .get_rit = ts2000_get_rit, + .set_xit = ts2000_set_rit, + .get_xit = ts2000_get_rit, + .set_mode = kenwood_set_mode, + .get_mode = kenwood_get_mode, + .set_vfo = kenwood_set_vfo, + .get_vfo = kenwood_get_vfo_if, + .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, + .get_ptt = kenwood_get_ptt, + .set_ptt = kenwood_set_ptt, + .get_dcd = kenwood_get_dcd, + .set_func = ts2000_set_func, + .get_func = ts2000_get_func, + .set_level = ts2000_set_level, + .get_level = ts2000_get_level, + .set_ext_func = ts2000_set_ext_func, + .get_ext_func = ts2000_get_ext_func, + .set_ext_level = ts2000_set_ext_level, + .get_ext_level = ts2000_get_ext_level, + .set_ant = kenwood_set_ant, + .get_ant = kenwood_get_ant, + .send_morse = kenwood_send_morse, + .wait_morse = rig_wait_morse, + .vfo_op = kenwood_vfo_op, + .scan = kenwood_scan, + .set_mem = kenwood_set_mem, + .get_mem = kenwood_get_mem, + .get_channel = ts2000_get_channel, + .set_channel = ts2000_set_channel, + .set_trn = kenwood_set_trn, + .get_trn = kenwood_get_trn, + .set_powerstat = kenwood_set_powerstat, + .get_powerstat = kenwood_get_powerstat, + .get_info = kenwood_get_info, + .reset = kenwood_reset, + + .hamlib_check_rig_caps = HAMLIB_CHECK_RIG_CAPS +};