diff --git a/include/hamlib/rig.h b/include/hamlib/rig.h index ec4e668dc..17dcf6181 100644 --- a/include/hamlib/rig.h +++ b/include/hamlib/rig.h @@ -897,8 +897,8 @@ typedef uint64_t rig_level_e; #define RIG_LEVEL_METER CONSTANT_64BIT_FLAG(20) /*!< \c METER -- Display meter, arg int (see enum meter_level_e) */ #define RIG_LEVEL_VOXGAIN CONSTANT_64BIT_FLAG(21) /*!< \c VOXGAIN -- VOX gain level, arg float [0.0 ... 1.0] */ #define RIG_LEVEL_ANTIVOX CONSTANT_64BIT_FLAG(22) /*!< \c ANTIVOX -- anti-VOX level, arg float [0.0 ... 1.0] */ -#define RIG_LEVEL_SLOPE_LOW CONSTANT_64BIT_FLAG(23) /*!< \c SLOPE_LOW -- Slope tune, low frequency cut, */ -#define RIG_LEVEL_SLOPE_HIGH CONSTANT_64BIT_FLAG(24) /*!< \c SLOPE_HIGH -- Slope tune, high frequency cut, */ +#define RIG_LEVEL_SLOPE_LOW CONSTANT_64BIT_FLAG(23) /*!< \c SLOPE_LOW -- Slope tune, low frequency cut, arg int (Hz) */ +#define RIG_LEVEL_SLOPE_HIGH CONSTANT_64BIT_FLAG(24) /*!< \c SLOPE_HIGH -- Slope tune, high frequency cut, arg int (Hz) */ #define RIG_LEVEL_BKIN_DLYMS CONSTANT_64BIT_FLAG(25) /*!< \c BKIN_DLYMS -- BKin Delay, arg int Milliseconds */ /*!< These are not settable */ diff --git a/rigs/kenwood/Makefile.am b/rigs/kenwood/Makefile.am index 8758a8164..5c97ff0f4 100644 --- a/rigs/kenwood/Makefile.am +++ b/rigs/kenwood/Makefile.am @@ -1,7 +1,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 \ + ts680.c ts690.c ts140.c ts480.c trc80.c ts590.c ts890s.c \ ts990s.c ts990s.h flex6xxx.c pihpsdr.c IC10SRC = ts440.c ts940.c ts711.c ts811.c r5000.c diff --git a/rigs/kenwood/kenwood.c b/rigs/kenwood/kenwood.c index 12b200382..db931cc67 100644 --- a/rigs/kenwood/kenwood.c +++ b/rigs/kenwood/kenwood.c @@ -28,7 +28,6 @@ #include #include /* String function definitions */ #include /* UNIX standard function definitions */ -#include #include #include "hamlib/rig.h" @@ -994,7 +993,7 @@ int kenwood_get_id(RIG *rig, char *buf) * Retrieves the transceiver status * */ -static int kenwood_get_if(RIG *rig) +int kenwood_get_if(RIG *rig) { struct kenwood_priv_data *priv = rig->state.priv; struct kenwood_priv_caps *caps = kenwood_caps(rig); @@ -1704,6 +1703,7 @@ int kenwood_get_rit(RIG *rig, vfo_t vfo, shortfreq_t *rit) RETURNFUNC(retval); } + // TODO: Fix for different rigs memcpy(buf, &priv->info[17], 6); buf[6] = '\0'; @@ -1830,6 +1830,42 @@ static int kenwood_set_filter(RIG *rig, pbwidth_t width) RETURNFUNC(kenwood_transaction(rig, cmd, NULL, 0)); } +static int kenwood_set_filter_width(RIG *rig, rmode_t mode, pbwidth_t width) +{ + struct kenwood_priv_caps *caps = kenwood_caps(rig); + struct kenwood_filter_width *selected_filter_width = NULL; + char cmd[20]; + int i; + + rig_debug(RIG_DEBUG_VERBOSE, "%s called, width=%ld\n", __func__, width); + + if (caps->filter_width == NULL) + { + RETURNFUNC(-RIG_ENAVAIL); + } + + for (i = 0; caps->filter_width[i].value >= 0; i++) + { + if (caps->filter_width[i].modes & mode) + { + selected_filter_width = &caps->filter_width[i]; + if (caps->filter_width[i].width_hz >= width) + { + break; + } + } + } + + if (selected_filter_width == NULL) + { + RETURNFUNC(-RIG_EINVAL); + } + + snprintf(cmd, sizeof(cmd), "FW%04d", selected_filter_width->value); + + RETURNFUNC(kenwood_transaction(rig, cmd, NULL, 0)); +} + /* * kenwood_set_mode */ @@ -1975,6 +2011,15 @@ int kenwood_set_mode(RIG *rig, vfo_t vfo, rmode_t mode, pbwidth_t width) kenwood_set_filter(rig, width); /* non fatal */ } + else if (RIG_IS_TS480) + { + err = kenwood_set_filter_width(rig, mode, width); + if (err != RIG_OK) + { + // Ignore errors as non-fatal + rig_debug(RIG_DEBUG_ERR, "%s: error setting filter width, error: %d\n", __func__, err); + } + } RETURNFUNC(RIG_OK); } @@ -2039,6 +2084,44 @@ static int kenwood_get_filter(RIG *rig, pbwidth_t *width) RETURNFUNC(RIG_OK); } +static int kenwood_get_filter_width(RIG *rig, rmode_t mode, pbwidth_t *width) +{ + struct kenwood_priv_caps *caps = kenwood_caps(rig); + char ackbuf[20]; + int i; + int retval; + int filter_value; + + rig_debug(RIG_DEBUG_VERBOSE, "%s called\n", __func__); + + if (caps->filter_width == NULL) + { + RETURNFUNC(-RIG_ENAVAIL); + } + + retval = kenwood_safe_transaction(rig, "FW", ackbuf, sizeof(ackbuf), 6); + if (retval != RIG_OK) + { + RETURNFUNC(retval); + } + + sscanf(ackbuf, "FW%d", &filter_value); + + for (i = 0; caps->filter_width[i].value >= 0; i++) + { + if (caps->filter_width[i].modes & mode) + { + if (caps->filter_width[i].value == filter_value) + { + *width = caps->filter_width[i].width_hz; + RETURNFUNC(RIG_OK); + } + } + } + + RETURNFUNC(-RIG_EINVAL); +} + /* * kenwood_get_mode */ @@ -2152,8 +2235,20 @@ int kenwood_get_mode(RIG *rig, vfo_t vfo, rmode_t *mode, pbwidth_t *width) } } - /* XXX ? */ - *width = rig_passband_normal(rig, *mode); + if (RIG_IS_TS480) + { + retval = kenwood_get_filter_width(rig, *mode, width); + if (retval != RIG_OK) + { + // Ignore errors as non-fatal + rig_debug(RIG_DEBUG_ERR, "%s: error getting filter width, error: %d\n", __func__, retval); + *width = rig_passband_normal(rig, *mode); + } + } + else + { + *width = rig_passband_normal(rig, *mode); + } RETURNFUNC(RIG_OK); } @@ -2379,11 +2474,110 @@ static int kenwood_get_power_minmax(RIG *rig, int *power_now, int *power_min, RETURNFUNC(RIG_OK); } +static int kenwood_find_slope_filter_for_frequency(RIG *rig, vfo_t vfo, struct kenwood_slope_filter *filter, int frequency_hz, int *value) +{ + int retval; + int i; + struct kenwood_slope_filter *last_filter = NULL; + freq_t freq; + int cache_ms_freq; + rmode_t mode; + int cache_ms_mode; + pbwidth_t width; + int cache_ms_width; + int data_mode_filter_active; + + if (filter == NULL) + { + return -RIG_ENAVAIL; + } + + retval = rig_get_cache(rig, vfo, &freq, &cache_ms_freq, &mode, &cache_ms_mode, &width, &cache_ms_width); + if (retval != RIG_OK) + { + return -RIG_EINVAL; + } + + retval = rig_get_ext_func(rig, vfo, TOK_FUNC_FILTER_WIDTH_DATA, &data_mode_filter_active); + if (retval != RIG_OK) + { + // Ignore errors, e.g. if the command is not supported + data_mode_filter_active = 0; + } + + for (i = 0; filter[i].value >= 0; i++) + { + if (filter[i].modes & mode && filter[i].data_mode_filter == data_mode_filter_active) + { + if (filter[i].frequency_hz >= frequency_hz) + { + *value = filter[i].value; + return RIG_OK; + } + last_filter = &filter[i]; + } + } + + if (last_filter != NULL) + { + *value = last_filter->value; + return RIG_OK; + } + + return -RIG_EINVAL; +} + +static int kenwood_find_slope_filter_for_value(RIG *rig, vfo_t vfo, struct kenwood_slope_filter *filter, int value, int *frequency_hz) +{ + int retval; + int i; + freq_t freq; + int cache_ms_freq; + rmode_t mode; + int cache_ms_mode; + pbwidth_t width; + int cache_ms_width; + int data_mode_filter_active; + + if (filter == NULL) + { + return -RIG_ENAVAIL; + } + + retval = rig_get_cache(rig, vfo, &freq, &cache_ms_freq, &mode, &cache_ms_mode, &width, &cache_ms_width); + if (retval != RIG_OK) + { + return -RIG_EINVAL; + } + + retval = rig_get_ext_func(rig, vfo, TOK_FUNC_FILTER_WIDTH_DATA, &data_mode_filter_active); + if (retval != RIG_OK) + { + // Ignore errors, e.g. if the command is not supported + data_mode_filter_active = 0; + } + + for (i = 0; filter[i].value >= 0; i++) + { + if (filter[i].modes & mode && filter[i].data_mode_filter == data_mode_filter_active) + { + if (filter[i].value == value) + { + *frequency_hz = filter[i].frequency_hz; + return RIG_OK; + } + } + } + + return -RIG_EINVAL; +} + int kenwood_set_level(RIG *rig, vfo_t vfo, setting_t level, value_t val) { char levelbuf[16]; int i, kenwood_val; struct kenwood_priv_data *priv = rig->state.priv; + struct kenwood_priv_caps *caps = kenwood_caps(rig); rig_debug(RIG_DEBUG_VERBOSE, "%s called\n", __func__); @@ -2556,21 +2750,33 @@ int kenwood_set_level(RIG *rig, vfo_t vfo, setting_t level, value_t val) break; case RIG_LEVEL_SLOPE_HIGH: - if (val.i > 20 || val.i < 0) + retval = kenwood_find_slope_filter_for_frequency(rig, vfo, caps->slope_filter_high, val.i, &kenwood_val); + if (retval != RIG_OK) { - RETURNFUNC(-RIG_EINVAL); + // Fall back to using raw values + if (val.i > 20 || val.i < 0) + { + RETURNFUNC(-RIG_EINVAL); + } + kenwood_val = val.i; } - snprintf(levelbuf, sizeof(levelbuf), "SH%02d", (val.i)); + snprintf(levelbuf, sizeof(levelbuf), "SH%02d", kenwood_val); break; case RIG_LEVEL_SLOPE_LOW: - if (val.i > 20 || val.i < 0) + retval = kenwood_find_slope_filter_for_frequency(rig, vfo, caps->slope_filter_low, val.i, &kenwood_val); + if (retval != RIG_OK) { - RETURNFUNC(-RIG_EINVAL); + // Fall back to using raw values + if (val.i > 20 || val.i < 0) + { + RETURNFUNC(-RIG_EINVAL); + } + kenwood_val = val.i; } - snprintf(levelbuf, sizeof(levelbuf), "SL%02d", (val.i)); + snprintf(levelbuf, sizeof(levelbuf), "SL%02d", kenwood_val); break; case RIG_LEVEL_CWPITCH: @@ -2583,7 +2789,7 @@ int kenwood_set_level(RIG *rig, vfo_t vfo, setting_t level, value_t val) break; case RIG_LEVEL_KEYSPD: - if (val.i > 50 || val.i < 5) + if (val.i > 60 || val.i < 5) { RETURNFUNC(-RIG_EINVAL); } @@ -2591,6 +2797,41 @@ int kenwood_set_level(RIG *rig, vfo_t vfo, setting_t level, value_t val) snprintf(levelbuf, sizeof(levelbuf), "KS%03d", val.i); break; + case RIG_LEVEL_COMP: + if (RIG_IS_TS990S) + { + kenwood_val = val.f * 255.0f; + } + else + { + kenwood_val = val.f * 100.0f; + } + snprintf(levelbuf, sizeof(levelbuf), "PL%03d%03d", kenwood_val, kenwood_val); + break; + + case RIG_LEVEL_VOXDELAY: + if (val.i > 3000 || val.i < 0) + { + RETURNFUNC(-RIG_EINVAL); + } + + snprintf(levelbuf, sizeof(levelbuf), "VD%04d", val.i); + break; + + case RIG_LEVEL_VOXGAIN: + kenwood_val = val.f * 9.0f; + snprintf(levelbuf, sizeof(levelbuf), "VG%03d", kenwood_val); + break; + + case RIG_LEVEL_BKIN_DLYMS: + if (val.i > 1000 || val.i < 0) + { + RETURNFUNC(-RIG_EINVAL); + } + + snprintf(levelbuf, sizeof(levelbuf), "SD%04d", val.i); + break; + default: rig_debug(RIG_DEBUG_ERR, "%s: unsupported set_level %s", __func__, rig_strlevel(level)); @@ -2641,8 +2882,9 @@ int kenwood_get_level(RIG *rig, vfo_t vfo, setting_t level, value_t *val) char *cmd; int retval; int lvl; - int i, ret, agclevel, len; + int i, ret, agclevel, len, value; struct kenwood_priv_data *priv = rig->state.priv; + struct kenwood_priv_caps *caps = kenwood_caps(rig); rig_debug(RIG_DEBUG_VERBOSE, "%s called\n", __func__); @@ -2937,7 +3179,21 @@ int kenwood_get_level(RIG *rig, vfo_t vfo, setting_t level, value_t *val) RETURNFUNC(retval); } - val->i = atoi(&lvlbuf[2]); + value = atoi(&lvlbuf[2]); + + retval = kenwood_find_slope_filter_for_value(rig, vfo, caps->slope_filter_low, value, &val->i); + if (retval != RIG_OK) + { + if (retval == -RIG_ENAVAIL) + { + // Fall back to using raw values + val->i = value; + } + else + { + RETURNFUNC(retval); + } + } break; case RIG_LEVEL_SLOPE_HIGH: @@ -2948,7 +3204,21 @@ int kenwood_get_level(RIG *rig, vfo_t vfo, setting_t level, value_t *val) RETURNFUNC(retval); } - val->i = atoi(&lvlbuf[2]); + value = atoi(&lvlbuf[2]); + + retval = kenwood_find_slope_filter_for_value(rig, vfo, caps->slope_filter_high, value, &val->i); + if (retval != RIG_OK) + { + if (retval == -RIG_ENAVAIL) + { + // Fall back to using raw values + val->i = value; + } + else + { + RETURNFUNC(retval); + } + } break; case RIG_LEVEL_CWPITCH: @@ -2974,13 +3244,80 @@ int kenwood_get_level(RIG *rig, vfo_t vfo, setting_t level, value_t *val) sscanf(lvlbuf + 2, "%d", &val->i); break; + case RIG_LEVEL_COMP: { + int raw_value; + retval = kenwood_safe_transaction(rig, "PL", lvlbuf, 50, 8); + + if (retval != RIG_OK) + { + RETURNFUNC(retval); + } + + sscanf(lvlbuf + 2, "%3d", &raw_value); + + if (RIG_IS_TS990S) + { + val->f = (float) raw_value / 255.0f; + } + else + { + val->f = (float) raw_value / 100.0f; + } + break; + } + + case RIG_LEVEL_VOXDELAY: { + int raw_value; + retval = kenwood_safe_transaction(rig, "VD", lvlbuf, 50, 6); + + if (retval != RIG_OK) + { + RETURNFUNC(retval); + } + + sscanf(lvlbuf + 2, "%d", &raw_value); + + // Value is in milliseconds + val->i = raw_value / 100; + break; + } + + case RIG_LEVEL_VOXGAIN: { + int raw_value; + retval = kenwood_safe_transaction(rig, "VG", lvlbuf, 50, 5); + + if (retval != RIG_OK) + { + RETURNFUNC(retval); + } + + sscanf(lvlbuf + 2, "%d", &raw_value); + + val->f = (float) raw_value / 9.0f; + break; + } + + case RIG_LEVEL_BKIN_DLYMS: { + int raw_value; + retval = kenwood_safe_transaction(rig, "SD", lvlbuf, 50, 6); + + if (retval != RIG_OK) + { + RETURNFUNC(retval); + } + + sscanf(lvlbuf + 2, "%d", &raw_value); + + val->i = raw_value; + break; + } + case RIG_LEVEL_IF: case RIG_LEVEL_APF: case RIG_LEVEL_NR: case RIG_LEVEL_PBT_IN: case RIG_LEVEL_PBT_OUT: case RIG_LEVEL_NOTCHF: - case RIG_LEVEL_COMP: case RIG_LEVEL_BKINDL: case RIG_LEVEL_BALANCE: RETURNFUNC(-RIG_ENIMPL); @@ -3106,6 +3443,14 @@ int kenwood_set_func(RIG *rig, vfo_t vfo, setting_t func, int status) snprintf(buf, sizeof(buf), "XT%c", (status == 0) ? '0' : '1'); RETURNFUNC(kenwood_transaction(rig, buf, NULL, 0)); + case RIG_FUNC_TUNER: + snprintf(buf, sizeof(buf), "AC1%c0", (status == 0) ? '0' : '1'); + RETURNFUNC(kenwood_transaction(rig, buf, NULL, 0)); + + case RIG_FUNC_FBKIN: + snprintf(buf, sizeof(buf), "SD%04d", (status == 1) ? 0 : 50); + RETURNFUNC(kenwood_transaction(rig, buf, NULL, 0)); + default: rig_debug(RIG_DEBUG_ERR, "Unsupported set_func %s", rig_strfunc(func)); RETURNFUNC(-RIG_EINVAL); @@ -3152,8 +3497,9 @@ int get_kenwood_func(RIG *rig, const char *cmd, int *status) int kenwood_get_func(RIG *rig, vfo_t vfo, setting_t func, int *status) { char *cmd; - char fctbuf[20]; + char respbuf[20]; int retval; + int raw_value; rig_debug(RIG_DEBUG_VERBOSE, "%s called\n", __func__); @@ -3165,14 +3511,14 @@ int kenwood_get_func(RIG *rig, vfo_t vfo, setting_t func, int *status) switch (func) { case RIG_FUNC_FAGC: - retval = kenwood_safe_transaction(rig, "GT", fctbuf, 20, 5); + retval = kenwood_safe_transaction(rig, "GT", respbuf, 20, 5); if (retval != RIG_OK) { RETURNFUNC(retval); } - *status = fctbuf[4] != '4' ? 1 : 0; + *status = respbuf[4] != '4' ? 1 : 0; RETURNFUNC(RIG_OK); case RIG_FUNC_NB: @@ -3209,21 +3555,21 @@ int kenwood_get_func(RIG *rig, vfo_t vfo, setting_t func, int *status) /* FIXME on TS2000 */ // Check for BC #1 case RIG_FUNC_BC: // Most will return BC1 or BC0, if BC2 then BC1 is off - retval = get_kenwood_func(rig, "BC", status); + retval = get_kenwood_func(rig, "BC", &raw_value); if (retval == RIG_OK) { - *status = *status == '1' ? 1 : 0; + *status = raw_value == 1 ? 1 : 0; } RETURNFUNC(retval); case RIG_FUNC_BC2: // TS-890 check Beat Cancel 2 we return boolean true/false - retval = get_kenwood_func(rig, "BC", status); + retval = get_kenwood_func(rig, "BC", &raw_value); if (retval == RIG_OK) { - *status = *status == '2' ? 1 : 0; + *status = raw_value == 2 ? 1 : 0; } RETURNFUNC(retval); @@ -3240,6 +3586,35 @@ int kenwood_get_func(RIG *rig, vfo_t vfo, setting_t func, int *status) case RIG_FUNC_RIT: RETURNFUNC(get_kenwood_func(rig, "RT", status)); + case RIG_FUNC_XIT: + RETURNFUNC(get_kenwood_func(rig, "XT", status)); + + case RIG_FUNC_TUNER: + retval = kenwood_safe_transaction(rig, "AC", respbuf, 20, 5); + + if (retval != RIG_OK) + { + RETURNFUNC(retval); + } + + *status = respbuf[3] != '0' ? 1 : 0; + RETURNFUNC(RIG_OK); + + case RIG_FUNC_FBKIN: { + int raw_value; + + retval = kenwood_safe_transaction(rig, "SD", respbuf, 20, 6); + + if (retval != RIG_OK) + { + RETURNFUNC(retval); + } + + sscanf(respbuf + 2, "%d", &raw_value); + *status = (raw_value == 0) ? 1 : 0; + RETURNFUNC(RIG_OK); + } + default: rig_debug(RIG_DEBUG_ERR, "Unsupported get_func %s", rig_strfunc(func)); RETURNFUNC(-RIG_EINVAL); @@ -3787,7 +4162,8 @@ int kenwood_get_dcd(RIG *rig, vfo_t vfo, dcd_t *dcd) { char busybuf[10]; int retval; - int offs = 2; + int expected; + int offs; rig_debug(RIG_DEBUG_VERBOSE, "%s called\n", __func__); @@ -3796,17 +4172,30 @@ int kenwood_get_dcd(RIG *rig, vfo_t vfo, dcd_t *dcd) RETURNFUNC(-RIG_EINVAL); } - retval = kenwood_safe_transaction(rig, "BY", busybuf, 10, 3); + if (RIG_IS_TS480 || RIG_IS_TS590S || RIG_IS_TS590SG || RIG_IS_TS990S || RIG_IS_TS2000) + { + expected = 4; + } + else + { + expected = 3; + } + + retval = kenwood_safe_transaction(rig, "BY", busybuf, 10, expected); if (retval != RIG_OK) { RETURNFUNC(retval); } - if (RIG_IS_TS990S && RIG_VFO_SUB == vfo) + if ((RIG_IS_TS990S && RIG_VFO_SUB == vfo) || (RIG_IS_TS2000 && RIG_VFO_SUB == vfo)) { offs = 3; } + else + { + offs = 2; + } *dcd = (busybuf[offs] == '1') ? RIG_DCD_ON : RIG_DCD_OFF; @@ -4126,6 +4515,12 @@ int kenwood_vfo_op(RIG *rig, vfo_t vfo, vfo_op_t op) case RIG_OP_BAND_DOWN: RETURNFUNC(kenwood_transaction(rig, "BD", NULL, 0)); + case RIG_OP_TUNE: + RETURNFUNC(kenwood_transaction(rig, "AC111", NULL, 0)); + + case RIG_OP_CPY: + RETURNFUNC(kenwood_transaction(rig, "VV", NULL, 0)); + default: rig_debug(RIG_DEBUG_ERR, "%s: unsupported op %#x\n", __func__, op); diff --git a/rigs/kenwood/kenwood.h b/rigs/kenwood/kenwood.h index a2f197e41..c0deee97b 100644 --- a/rigs/kenwood/kenwood.h +++ b/rigs/kenwood/kenwood.h @@ -47,6 +47,8 @@ #define TOK_RIT TOKEN_BACKEND(4) #define TOK_NO_ID TOKEN_BACKEND(5) +#define TOK_FUNC_FILTER_WIDTH_DATA TOKEN_BACKEND(6) // Data communications mode that affects SL/SH/FW commands + /* Token structure assigned to .cfgparams in rig_caps */ extern const struct confparams kenwood_cfg_params[]; @@ -106,11 +108,29 @@ extern const struct confparams kenwood_cfg_params[]; #define RIG_IS_POWERSDR (rig->caps->rig_model == RIG_MODEL_POWERSDR) #define RIG_IS_MALACHITE (rig->caps->rig_model == RIG_MODEL_MALACHITE) +struct kenwood_filter_width +{ + rmode_t modes; + int value; + pbwidth_t width_hz; +}; + +struct kenwood_slope_filter +{ + rmode_t modes; + int data_mode_filter; + int value; + pbwidth_t frequency_hz; +}; + struct kenwood_priv_caps { char cmdtrm; /* Command termination chars (ken=';' or th='\r') */ int if_len; /* length of IF; answer excluding ';' terminator */ rmode_t *mode_table; + struct kenwood_filter_width *filter_width; /* Last entry should have value == -1 and width_hz == -1 */ + struct kenwood_slope_filter *slope_filter_high; /* Last entry should have value == -1 and frequency_hz == -1 */ + struct kenwood_slope_filter *slope_filter_low; /* Last entry should have value == -1 and frequency_hz == -1 */ }; struct kenwood_priv_data @@ -217,6 +237,7 @@ int kenwood_set_channel(RIG *rig, vfo_t vfo, const channel_t *chan); int kenwood_scan(RIG *rig, vfo_t vfo, scan_t scan, int ch); const char *kenwood_get_info(RIG *rig); int kenwood_get_id(RIG *rig, char *buf); +int kenwood_get_if(RIG *rig); int kenwood_set_trn(RIG *rig, int trn); int kenwood_get_trn(RIG *rig, int *trn); diff --git a/rigs/kenwood/ts480.c b/rigs/kenwood/ts480.c index 893b2d8cc..8ab25d768 100644 --- a/rigs/kenwood/ts480.c +++ b/rigs/kenwood/ts480.c @@ -1,7 +1,7 @@ /* - * Hamlib Kenwood backend - TS480 description - * Hamlib Kenwood backend - TS890s description + * Hamlib Kenwood backend - TS-480 description * Copyright (c) 2000-2004 by Stephane Fillod and Juergen Rinas + * Copyright (c) 2021 by Mikael Nousiainen * * * This library is free software; you can redistribute it and/or @@ -24,25 +24,134 @@ #include "config.h" #endif -#include #include +#include +#include #include +#include "cal.h" #include "idx_builtin.h" +#include "iofunc.h" +#include "token.h" #include "kenwood.h" #define TS480_ALL_MODES (RIG_MODE_AM|RIG_MODE_CW|RIG_MODE_CWR|RIG_MODE_SSB|RIG_MODE_FM|RIG_MODE_RTTY|RIG_MODE_RTTYR) #define PS8000A_ALL_MODES (RIG_MODE_AM|RIG_MODE_AMS|RIG_MODE_CW|RIG_MODE_CWR|RIG_MODE_SSB|RIG_MODE_FM|RIG_MODE_RTTY|RIG_MODE_RTTYR) -#define TS890_ALL_MODES (RIG_MODE_LSB|RIG_MODE_USB|RIG_MODE_CW|RIG_MODE_FM|RIG_MODE_AM|RIG_MODE_RTTY|RIG_MODE_CWR|RIG_MODE_RTTYR|RIG_MODE_PSK|RIG_MODE_PSKR|RIG_MODE_PKTLSB|RIG_MODE_PKTUSB|RIG_MODE_PKTFM|RIG_MODE_PKTAM) #define TS480_OTHER_TX_MODES (RIG_MODE_CW|RIG_MODE_SSB|RIG_MODE_FM|RIG_MODE_RTTY) #define TS480_AM_TX_MODES RIG_MODE_AM #define TS480_VFO (RIG_VFO_A|RIG_VFO_B) -#define TS480_LEVEL_ALL (RIG_LEVEL_RFPOWER|RIG_LEVEL_AF|RIG_LEVEL_RF|RIG_LEVEL_SQL|RIG_LEVEL_AGC|RIG_LEVEL_MICGAIN|RIG_LEVEL_STRENGTH) -#define TS480_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) -#define TS890_FUNC_ALL (RIG_FUNC_NB|RIG_FUNC_NB2|RIG_FUNC_COMP|RIG_FUNC_VOX|RIG_FUNC_NR|RIG_FUNC_NR|RIG_FUNC_BC|RIG_FUNC_BC2|RIG_FUNC_RIT|RIG_FUNC_XIT) +#define TS480_LEVEL_ALL (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 TS480_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) +#define TS480_VFO_OPS (RIG_OP_UP|RIG_OP_DOWN|RIG_OP_BAND_UP|RIG_OP_BAND_DOWN|RIG_OP_CPY|RIG_OP_TUNE) + +// TS-480 S-meter calibration table based on LCD display bars +#define TS480_STR_CAL { 9, \ + { \ + { 0, -60 }, \ + { 3, -48 }, \ + { 5, -36 }, \ + { 7, -24 }, \ + { 9, -12 }, \ + { 11, 0 }, \ + { 14, 20 }, \ + { 17, 40 }, \ + { 20, 60 } \ + } } + +// TS-480 SWR calibration table based approximately on LCD display bars +#define TS480_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_FUNC_TX_AUDIO_FROM_DATA_INPUT TOKEN_BACKEND(103) +#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) +#define TOK_LEVEL_AF_INPUT_LEVEL TOKEN_BACKEND(109) +#define TOK_LEVEL_AF_OUTPUT_LEVEL TOKEN_BACKEND(110) +#define TOK_LEVEL_DIGITAL_NOISE_LIMITER TOKEN_BACKEND(111) +#define TOK_FUNC_CW_IF_FOR_SSB_RX TOKEN_BACKEND(112) + +int ts480_ext_tokens[] = { + TOK_FUNC_NOISE_REDUCTION_2, TOK_FUNC_FILTER_WIDTH_DATA, TOK_FUNC_TX_AUDIO_FROM_DATA_INPUT, + 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_LEVEL_AF_INPUT_LEVEL, TOK_LEVEL_AF_OUTPUT_LEVEL, + TOK_LEVEL_DIGITAL_NOISE_LIMITER, TOK_FUNC_CW_IF_FOR_SSB_RX, + TOK_BACKEND_NONE, +}; + +const struct confparams ts480_ext_funcs[] = +{ + { + TOK_FUNC_NOISE_REDUCTION_2, "NR2", "Noise reduction 2", "Noise reduction 2", + NULL, RIG_CONF_CHECKBUTTON, + }, + { + TOK_FUNC_CW_IF_FOR_SSB_RX, "CW_IF_FOR_SSB_RX", "CW IF filter for SSB", "Use CW IF filter for SSB reception", + NULL, RIG_CONF_CHECKBUTTON, + }, + { + TOK_FUNC_FILTER_WIDTH_DATA, "FILTER_WIDTH_DATA", "Filter bandwidth for data", "Filter bandwidth for data communications", + NULL, RIG_CONF_CHECKBUTTON, + }, + { + TOK_FUNC_TX_AUDIO_FROM_DATA_INPUT, "TX_AUDIO_FROM_DATA_INPUT", "TX audio from data input", "Transmit with audio input from the data terminal", + NULL, RIG_CONF_CHECKBUTTON, + }, + { RIG_CONF_END, NULL, } +}; + +const struct confparams ts480_ext_levels[] = +{ + { + TOK_LEVEL_DIGITAL_NOISE_LIMITER, "DIGITAL_NOISE_LIMITER", "Digital Noise Limiter", "Digital Noise Limiter", + NULL, RIG_CONF_COMBO, { .c = { .combostr = { "OFF", "DNL Level 1", "DNL Level 2", "DNL Level 3", NULL } } } + }, + { + TOK_LEVEL_DSP_RX_EQUALIZER, "DSP_RX_EQUALIZER", "DSP RX equalizer", "DSP RX equalizer type", + NULL, RIG_CONF_COMBO, { .c = { .combostr = { "OFF", "Hb1", "Hb2", "FP", "bb1", "bb2", "c", "U", NULL } } } + }, + { + TOK_LEVEL_DSP_TX_EQUALIZER, "DSP_TX_EQUALIZER", "DSP TX equalizer", "DSP TX equalizer type", + NULL, RIG_CONF_COMBO, { .c = { .combostr = { "OFF", "Hb1", "Hb2", "FP", "bb1", "bb2", "c", "U", 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.4 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 } } + }, + { + TOK_LEVEL_AF_INPUT_LEVEL, "AF_INPUT_LEVEL", "AF input level", "AF input level for data communications", + NULL, RIG_CONF_NUMERIC, { .n = { .min = 0, .max = 9, .step = 1 } } + }, + { + TOK_LEVEL_AF_OUTPUT_LEVEL, "AF_OUTPUT_LEVEL", "AF output level", "AF output level for data communications", + NULL, RIG_CONF_NUMERIC, { .n = { .min = 0, .max = 9, .step = 1 } } + }, + { RIG_CONF_END, NULL, } +}; /* * kenwood_ts480_get_info @@ -89,135 +198,256 @@ kenwood_ts480_get_info(RIG *rig) } } +static int ts480_set_ex_menu(RIG *rig, int number, int value_len, int value) +{ + char buf[20]; + + rig_debug(RIG_DEBUG_TRACE, "%s called\n", __func__); + + snprintf(buf, 20, "EX%03d0000%0*d", number, value_len, value); + + RETURNFUNC(kenwood_transaction(rig, buf, NULL, 0)); +} + +static int ts480_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, 20, "EX%03d0000", number); + + retval = kenwood_safe_transaction(rig, buf, ackbuf, sizeof(ackbuf), 9 + value_len); + if (retval != RIG_OK) + { + RETURNFUNC(retval); + } + + sscanf(ackbuf + 9, "%d", value); + + RETURNFUNC(RIG_OK); +} + +static int ts480_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 ts480_get_func(RIG *rig, vfo_t vfo, setting_t func, int *status) +{ + char buf[20]; + int retval; + + rig_debug(RIG_DEBUG_TRACE, "%s called\n", __func__); + + 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); +} /* - * kenwood_ts480_set_level - * Assumes rig!=NULL - * - * set levels of most functions - * - * WARNING: the commands differ slightly from the general versions in kenwood.c + * WARNING: The commands differ slightly from the general versions in kenwood.c * e.g.: "SQ"=>"SQ0" , "AG"=>"AG0" */ -int -kenwood_ts480_set_level(RIG *rig, vfo_t vfo, setting_t level, value_t val) +int kenwood_ts480_set_level(RIG *rig, vfo_t vfo, setting_t level, value_t val) { char levelbuf[16]; int kenwood_val; - int rf_max_level = 100; /* 100 for TS-480 and 255 for TS-890S */ - struct kenwood_priv_data *priv = rig->state.priv; rig_debug(RIG_DEBUG_TRACE, "%s called\n", __func__); switch (level) { - case RIG_LEVEL_RFPOWER: - return kenwood_set_level(rig, vfo, level, val); - - case RIG_LEVEL_AF: - priv->ag_format = 2; - return kenwood_set_level(rig, vfo, level, val); - case RIG_LEVEL_RF: - if (RIG_IS_TS890S) - { - rf_max_level = 255; - } - - kenwood_val = val.f * - rf_max_level; /* possible values for TS480 are 000.. 100 */ + kenwood_val = val.f * 100; sprintf(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; /* possible values for TS480 are 000.. 255 */ - - if (RIG_IS_TS890S) - { - sprintf(levelbuf, "SQ%03d", kenwood_val); - } - else - { - sprintf(levelbuf, "SQ0%03d", kenwood_val); - } - + kenwood_val = val.f * 255; + sprintf(levelbuf, "SQ0%03d", kenwood_val); break; case RIG_LEVEL_AGC: - /* hamlib argument is int, possible values rig.h:enum agc_level_e */ /* possible values for TS480 000(=off), 001(=fast), 002(=slow) */ - /* possible values for TS890 0(=off), 1(=slow), 2(=mid), 3(=fast), 4(=off/Last) */ - if (RIG_IS_TS890S) + rig_debug(RIG_DEBUG_VERBOSE, "%s TS480 RIG_LEVEL_AGC\n", __func__); + + switch (val.i) { - rig_debug(RIG_DEBUG_VERBOSE, "%s TS890S RIG_LEVEL_AGC\n", __func__); + case RIG_AGC_OFF: + kenwood_val = 0; + break; - switch (val.i) - { - case RIG_AGC_OFF: - kenwood_val = 0; - break; + case RIG_AGC_FAST: + kenwood_val = 1; + break; - case RIG_AGC_SLOW: - kenwood_val = 1; - break; + case RIG_AGC_SLOW: + kenwood_val = 2; + break; - case RIG_AGC_MEDIUM: - kenwood_val = 2; - break; - - case RIG_AGC_FAST: - kenwood_val = 3; - break; - - case RIG_AGC_AUTO: - kenwood_val = 4; - break; - - default: - rig_debug(RIG_DEBUG_ERR, "%s: unsupported agc value", __func__); - return -RIG_EINVAL; - } - - sprintf(levelbuf, "GC%d", kenwood_val); - } - else - { - rig_debug(RIG_DEBUG_VERBOSE, "%s TS480 RIG_LEVEL_AGC\n", __func__); - - switch (val.i) - { - case RIG_AGC_OFF: - kenwood_val = 0; - break; - - case RIG_AGC_FAST: - kenwood_val = 1; - break; - - case RIG_AGC_SLOW: - kenwood_val = 2; - break; - - default: - rig_debug(RIG_DEBUG_ERR, "%s: unsupported agc value", __func__); - return -RIG_EINVAL; - } - - sprintf(levelbuf, "GT%03d", kenwood_val); + default: + rig_debug(RIG_DEBUG_ERR, "%s: unsupported agc value", __func__); + return -RIG_EINVAL; } + sprintf(levelbuf, "GT%03d", kenwood_val); break; + case RIG_LEVEL_MONITOR_GAIN: + kenwood_val = val.f * 9.0; + sprintf(levelbuf, "ML%03d", kenwood_val); + break; + + case RIG_LEVEL_NB: + kenwood_val = val.f * 10.0; + sprintf(levelbuf, "NL%03d", kenwood_val); + break; + + case RIG_LEVEL_NR: + kenwood_val = val.f * 9.0; + sprintf(levelbuf, "RL%02d", kenwood_val); + break; + + case RIG_LEVEL_PREAMP: + if (val.i != 12 && val.i != 0) { + RETURNFUNC(-RIG_EINVAL); + } + sprintf(levelbuf, "PA%c", (val.i == 12) ? '1' : '0'); + break; + + case RIG_LEVEL_ATT: + if (val.i != 12 && val.i != 0) { + RETURNFUNC(-RIG_EINVAL); + } + sprintf(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); + } + sprintf(levelbuf, "RM%d", kenwood_val); + break; + + case RIG_LEVEL_CWPITCH: + if (val.i > 1000 || val.i < 400) + { + RETURNFUNC(-RIG_EINVAL); + } + + RETURNFUNC(ts480_set_ex_menu(rig, 34, 2, (val.i - 400) / 50)); + default: - rig_debug(RIG_DEBUG_ERR, "%s: unsupported set_level %s", __func__, - rig_strlevel(level)); - return -RIG_EINVAL; + return kenwood_set_level(rig, vfo, level, val); } return kenwood_transaction(rig, levelbuf, NULL, 0); } +static int ts480_read_meters(RIG *rig, int *swr, int *comp, int *alc) +{ + int retval; + char *cmd = "RM;"; + struct rig_state *rs = &rig->state; + char ackbuf[32]; + int expected_len = 24; + + rig_debug(RIG_DEBUG_TRACE, "%s: called\n", __func__); + + retval = write_block(&rs->rigport, cmd, strlen(cmd)); + + rig_debug(RIG_DEBUG_TRACE, "%s: write_block retval=%d\n", __func__, retval); + + if (retval != RIG_OK) + { + RETURNFUNC(retval); + } + + // TS-480 returns values for all meters at the same time, for example: RM10000;RM20000;RM30000; + + retval = read_string(&rs->rigport, ackbuf, expected_len + 1, NULL, 0); + + 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, "RM1%d;RM2%d;RM3%d;", swr, comp, alc); + if (retval != 3) + { + rig_debug(RIG_DEBUG_ERR, "%s: expected 3 meter values to parse, got %d in '%s'\n", __func__, retval, ackbuf); + RETURNFUNC(-RIG_EPROTO); + } + + RETURNFUNC(RIG_OK); +} + /* * kenwood_ts480_get_level @@ -229,61 +459,16 @@ kenwood_ts480_get_level(RIG *rig, vfo_t vfo, setting_t level, value_t *val) char ackbuf[50]; size_t ack_len, ack_len_expected; int levelint; - int offset_level = 3; // default offset for the level return value int retval; - int rf_max_level; rig_debug(RIG_DEBUG_TRACE, "%s called\n", __func__); - if (RIG_IS_TS890S || RIG_IS_TS480) - { - rf_max_level = 255; - } - else - { - rf_max_level = 100; - } - switch (level) { case RIG_LEVEL_AF: - if (RIG_IS_TS890S) - { - retval = kenwood_transaction(rig, "AG", ackbuf, sizeof(ackbuf)); - offset_level = 2; - } - else - { - retval = kenwood_transaction(rig, "AG0", ackbuf, sizeof(ackbuf)); - offset_level = 3; - } - - if (RIG_OK != retval) - { - return retval; - } - - ack_len = strlen(ackbuf); - - if (offset_level + 3 != ack_len) - { - return -RIG_EPROTO; - } - - if (1 != sscanf(&ackbuf[offset_level], "%d", &levelint)) - { - return -RIG_EPROTO; - } - - val->f = levelint / (float) rf_max_level; - return RIG_OK; + return kenwood_get_level(rig, vfo, level, val); case RIG_LEVEL_RF: - if (RIG_IS_TS480) - { - rf_max_level = 100; - } - retval = kenwood_transaction(rig, "RG", ackbuf, sizeof(ackbuf)); if (RIG_OK != retval) @@ -303,20 +488,12 @@ kenwood_ts480_get_level(RIG *rig, vfo_t vfo, setting_t level, value_t *val) return -RIG_EPROTO; } - val->f = levelint / (float) rf_max_level; + val->f = levelint / (float) 100; return RIG_OK; case RIG_LEVEL_SQL: - if (RIG_IS_TS890S) - { - retval = kenwood_transaction(rig, "SQ", ackbuf, sizeof(ackbuf)); - ack_len_expected = 5; - } - else - { - retval = kenwood_transaction(rig, "SQ0", ackbuf, sizeof(ackbuf)); - ack_len_expected = 6; - } + retval = kenwood_transaction(rig, "SQ0", ackbuf, sizeof(ackbuf)); + ack_len_expected = 6; if (RIG_OK != retval) { @@ -339,16 +516,8 @@ kenwood_ts480_get_level(RIG *rig, vfo_t vfo, setting_t level, value_t *val) return RIG_OK; case RIG_LEVEL_AGC: - if (RIG_IS_TS890S) - { - retval = kenwood_transaction(rig, "GC", ackbuf, sizeof(ackbuf)); - ack_len_expected = 3; - } - else - { - retval = kenwood_transaction(rig, "GT", ackbuf, sizeof(ackbuf)); - ack_len_expected = 5; - } + retval = kenwood_transaction(rig, "GT", ackbuf, sizeof(ackbuf)); + ack_len_expected = 5; if (RIG_OK != retval) { @@ -369,86 +538,611 @@ kenwood_ts480_get_level(RIG *rig, vfo_t vfo, setting_t level, value_t *val) break; case '1': - if (RIG_IS_TS890S) - { - val->i = RIG_AGC_SLOW; - } - else - { - val->i = RIG_AGC_FAST; - } - - break; - - case '2': - if (RIG_IS_TS890S) - { - val->i = RIG_AGC_MEDIUM; - } - else - { - val->i = RIG_AGC_SLOW; - } - - break; - - case '3': val->i = RIG_AGC_FAST; break; - case '4': - val->i = RIG_AGC_AUTO; + case '2': + val->i = RIG_AGC_SLOW; break; default: return -RIG_EPROTO; } - return RIG_OK; case RIG_LEVEL_STRENGTH: - case RIG_LEVEL_MICGAIN: - case RIG_LEVEL_RFPOWER: + if (rig->state.cache.ptt != RIG_PTT_OFF) + { + val->i = -9 * 6; + break; + } + return kenwood_get_level(rig, vfo, level, val); - case RIG_LEVEL_PREAMP: - case RIG_LEVEL_IF: - case RIG_LEVEL_APF: - case RIG_LEVEL_NR: - case RIG_LEVEL_PBT_IN: - case RIG_LEVEL_PBT_OUT: - case RIG_LEVEL_CWPITCH: - case RIG_LEVEL_KEYSPD: - case RIG_LEVEL_NOTCHF: - case RIG_LEVEL_COMP: - case RIG_LEVEL_BKINDL: - case RIG_LEVEL_BALANCE: - return -RIG_ENIMPL; + 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); - default: - rig_debug(RIG_DEBUG_ERR, "%s: unsupported get_level %s", __func__, - rig_strlevel(level)); - return -RIG_EINVAL; + val->f = (float) raw_value / 9.0f; + break; } - return RIG_OK; /* never reached */ + 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 swr; + int comp; + int alc; + + retval = ts480_read_meters(rig, &swr, &comp, &alc); + 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; + + if (rig->state.cache.ptt == RIG_PTT_OFF) + { + val->f = 0; + break; + } + + retval = kenwood_safe_transaction(rig, "SM0", ackbuf, sizeof(ackbuf), 7); + if (retval != RIG_OK) + { + RETURNFUNC(retval); + } + + sscanf(ackbuf, "SM0%d", &raw_value); + + val->f = (float) raw_value / 20.0f; + break; + } + + case RIG_LEVEL_CWPITCH: { + int raw_value; + retval = ts480_get_ex_menu(rig, 34, 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 ts480_set_rit(RIG *rig, vfo_t vfo, shortfreq_t rit) +{ + char buf[20]; + int retval; + int rit_enabled; + int xit_enabled; + + rig_debug(RIG_DEBUG_TRACE, "%s called\n", __func__); + + if (rit < -9999 || rit > 9999) + { + 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 ts480_get_rit(RIG *rig, vfo_t vfo, shortfreq_t *rit) +{ + int retval; + char buf[7]; + struct kenwood_priv_data *priv = rig->state.priv; + + rig_debug(RIG_DEBUG_VERBOSE, "%s called\n", __func__); + + 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 ts480_set_ext_func(RIG *rig, vfo_t vfo, token_t token, int status) +{ + char cmdbuf[20]; + int retval; + + rig_debug(RIG_DEBUG_VERBOSE, "%s called\n", __func__); + + 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; + case TOK_FUNC_CW_IF_FOR_SSB_RX: + if (status < 0 || status > 1) + { + RETURNFUNC(-RIG_EINVAL); + } + retval = ts480_set_ex_menu(rig, 17, 1, status); + break; + case TOK_FUNC_FILTER_WIDTH_DATA: + if (status < 0 || status > 1) + { + RETURNFUNC(-RIG_EINVAL); + } + retval = ts480_set_ex_menu(rig, 45, 1, status); + break; + case TOK_FUNC_TX_AUDIO_FROM_DATA_INPUT: + if (status < 0 || status > 1) + { + RETURNFUNC(-RIG_EINVAL); + } + retval = ts480_set_ex_menu(rig, 60, 1, status); + break; + default: + RETURNFUNC(-RIG_EINVAL); + } + + RETURNFUNC(retval); +} + +static int ts480_get_ext_func(RIG *rig, vfo_t vfo, token_t token, int *status) +{ + char ackbuf[20]; + int retval; + + rig_debug(RIG_DEBUG_VERBOSE, "%s called\n", __func__); + + 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; + } + case TOK_FUNC_CW_IF_FOR_SSB_RX: + retval = ts480_get_ex_menu(rig, 17, 1, status); + break; + case TOK_FUNC_FILTER_WIDTH_DATA: + retval = ts480_get_ex_menu(rig, 45, 1, status); + break; + case TOK_FUNC_TX_AUDIO_FROM_DATA_INPUT: + retval = ts480_get_ex_menu(rig, 60, 1, status); + break; + default: + RETURNFUNC(-RIG_EINVAL); + } + + RETURNFUNC(retval); +} + +static int ts480_set_ext_level(RIG *rig, vfo_t vfo, token_t token, value_t val) +{ + int retval; + char cmdbuf[20]; + + rig_debug(RIG_DEBUG_VERBOSE, "%s called\n", __func__); + + switch (token) + { + case TOK_LEVEL_DIGITAL_NOISE_LIMITER: + if (val.i < 0 || val.i > 3) + { + RETURNFUNC(-RIG_EINVAL); + } + snprintf(cmdbuf, sizeof(cmdbuf), "DL%d%02d", val.i != 0 ? 1 : 0, val.i > 0 ? val.i - 1 : 0); + retval = kenwood_transaction(rig, cmdbuf, NULL, 0); + break; + case TOK_LEVEL_DSP_RX_EQUALIZER: + if (val.i < 0 || val.i > 7) + { + RETURNFUNC(-RIG_EINVAL); + } + retval = ts480_set_ex_menu(rig, 18, 1, val.i); + break; + case TOK_LEVEL_DSP_TX_EQUALIZER: + if (val.i < 0 || val.i > 7) + { + RETURNFUNC(-RIG_EINVAL); + } + retval = ts480_set_ex_menu(rig, 19, 1, val.i); + break; + case TOK_LEVEL_DSP_TX_BANDWIDTH: + if (val.i < 0 || val.i > 1) + { + RETURNFUNC(-RIG_EINVAL); + } + retval = ts480_set_ex_menu(rig, 20, 1, val.i); + break; + case TOK_LEVEL_BEEP_VOLUME: + if (val.f < 0 || val.f > 9) + { + RETURNFUNC(-RIG_EINVAL); + } + retval = ts480_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 = ts480_set_ex_menu(rig, 13, 1, (int) val.f); + break; + case TOK_LEVEL_AF_INPUT_LEVEL: + if (val.f < 0 || val.f > 9) + { + RETURNFUNC(-RIG_EINVAL); + } + retval = ts480_set_ex_menu(rig, 46, 1, (int) val.f); + break; + case TOK_LEVEL_AF_OUTPUT_LEVEL: + if (val.f < 0 || val.f > 9) + { + RETURNFUNC(-RIG_EINVAL); + } + retval = ts480_set_ex_menu(rig, 47, 1, (int) val.f); + break; + default: + RETURNFUNC(-RIG_EINVAL); + } + + RETURNFUNC(retval); +} + +static int ts480_get_ext_level(RIG *rig, vfo_t vfo, token_t token, value_t *val) +{ + char ackbuf[20]; + int retval; + int value; + + rig_debug(RIG_DEBUG_VERBOSE, "%s called\n", __func__); + + switch (token) + { + case TOK_LEVEL_DIGITAL_NOISE_LIMITER: { + int enabled; + int level; + + retval = kenwood_safe_transaction(rig, "DL", ackbuf, sizeof(ackbuf), 5); + if (retval != RIG_OK) + { + RETURNFUNC(retval); + } + + sscanf(ackbuf, "DL%1d%2d", &enabled, &level); + + val->i = enabled ? level + 1 : 0; + break; + } + case TOK_LEVEL_DSP_RX_EQUALIZER: + retval = ts480_get_ex_menu(rig, 18, 1, &value); + val->i = value; + break; + case TOK_LEVEL_DSP_TX_EQUALIZER: + retval = ts480_get_ex_menu(rig, 19, 1, &value); + val->i = value; + break; + case TOK_LEVEL_DSP_TX_BANDWIDTH: + retval = ts480_get_ex_menu(rig, 20, 1, &value); + val->i = value; + break; + case TOK_LEVEL_BEEP_VOLUME: + retval = ts480_get_ex_menu(rig, 12, 1, &value); + val->f = value; + break; + case TOK_LEVEL_TX_SIDETONE_VOLUME: + retval = ts480_get_ex_menu(rig, 13, 1, &value); + val->f = value; + break; + case TOK_LEVEL_AF_INPUT_LEVEL: + retval = ts480_get_ex_menu(rig, 46, 1, &value); + val->f = value; + break; + case TOK_LEVEL_AF_OUTPUT_LEVEL: + retval = ts480_get_ex_menu(rig, 47, 1, &value); + val->f = value; + break; + default: + RETURNFUNC(-RIG_EINVAL); + } + + RETURNFUNC(retval); +} + +static struct kenwood_filter_width ts480_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, 12000 }, + { RIG_MODE_AM, 0, 6000 }, + { RIG_MODE_AM, 1, 2400 }, // NAR1 optional filter (?) + { RIG_MODE_NONE, -1, -1 }, +}; + +static struct kenwood_slope_filter ts480_slope_filter_high[] = { + { RIG_MODE_SSB | RIG_MODE_FM | RIG_MODE_RTTY | RIG_MODE_RTTYR, 0, 0, 1000 }, + { RIG_MODE_SSB | RIG_MODE_FM | RIG_MODE_RTTY | RIG_MODE_RTTYR, 0, 1, 1200 }, + { RIG_MODE_SSB | RIG_MODE_FM | RIG_MODE_RTTY | RIG_MODE_RTTYR, 0, 2, 1400 }, + { RIG_MODE_SSB | RIG_MODE_FM | RIG_MODE_RTTY | RIG_MODE_RTTYR, 0, 3, 1600 }, + { RIG_MODE_SSB | RIG_MODE_FM | RIG_MODE_RTTY | RIG_MODE_RTTYR, 0, 4, 1800 }, + { RIG_MODE_SSB | RIG_MODE_FM | RIG_MODE_RTTY | RIG_MODE_RTTYR, 0, 5, 2000 }, + { RIG_MODE_SSB | RIG_MODE_FM | RIG_MODE_RTTY | RIG_MODE_RTTYR, 0, 6, 2200 }, + { RIG_MODE_SSB | RIG_MODE_FM | RIG_MODE_RTTY | RIG_MODE_RTTYR, 0, 7, 2400 }, + { RIG_MODE_SSB | RIG_MODE_FM | RIG_MODE_RTTY | RIG_MODE_RTTYR, 0, 8, 2600 }, + { RIG_MODE_SSB | RIG_MODE_FM | RIG_MODE_RTTY | RIG_MODE_RTTYR, 0, 9, 2800 }, + { RIG_MODE_SSB | RIG_MODE_FM | RIG_MODE_RTTY | RIG_MODE_RTTYR, 0, 10, 3000 }, + { RIG_MODE_SSB | RIG_MODE_FM | RIG_MODE_RTTY | RIG_MODE_RTTYR, 0, 11, 3400 }, + { RIG_MODE_SSB | RIG_MODE_FM | RIG_MODE_RTTY | RIG_MODE_RTTYR, 0, 12, 4000 }, + { RIG_MODE_SSB | RIG_MODE_FM | RIG_MODE_RTTY | RIG_MODE_RTTYR, 0, 13, 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, 1000 }, + { RIG_MODE_SSB | RIG_MODE_RTTY | RIG_MODE_RTTYR | RIG_MODE_FM | RIG_MODE_AM, 1, 1, 1500 }, + { RIG_MODE_SSB | RIG_MODE_RTTY | RIG_MODE_RTTYR | RIG_MODE_FM | RIG_MODE_AM, 1, 2, 2210 }, + { RIG_MODE_NONE, 0, -1, -1 }, +}; + +static struct kenwood_slope_filter ts480_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, 50 }, + { RIG_MODE_SSB | RIG_MODE_RTTY | RIG_MODE_RTTYR | RIG_MODE_FM | RIG_MODE_AM, 1, 1, 100 }, + { RIG_MODE_SSB | RIG_MODE_RTTY | RIG_MODE_RTTYR | RIG_MODE_FM | RIG_MODE_AM, 1, 2, 250 }, + { RIG_MODE_SSB | RIG_MODE_RTTY | RIG_MODE_RTTYR | RIG_MODE_FM | RIG_MODE_AM, 1, 3, 500 }, + { RIG_MODE_SSB | RIG_MODE_RTTY | RIG_MODE_RTTYR | RIG_MODE_FM | RIG_MODE_AM, 1, 4, 1000 }, + { RIG_MODE_SSB | RIG_MODE_RTTY | RIG_MODE_RTTYR | RIG_MODE_FM | RIG_MODE_AM, 1, 5, 1500 }, + { RIG_MODE_SSB | RIG_MODE_RTTY | RIG_MODE_RTTYR | RIG_MODE_FM | RIG_MODE_AM, 1, 6, 2400 }, + { RIG_MODE_NONE, 0, -1, -1 }, +}; + static struct kenwood_priv_caps ts480_priv_caps = { .cmdtrm = EOM_KEN, + .filter_width = ts480_filter_width, + .slope_filter_high = ts480_slope_filter_high, + .slope_filter_low = ts480_slope_filter_low, }; -static struct kenwood_priv_caps ts890s_priv_caps = +int ts480_init(RIG *rig) { - .cmdtrm = EOM_KEN, -}; + struct kenwood_priv_data *priv; + int retval; + rig_debug(RIG_DEBUG_TRACE, "%s called\n", __func__); + + retval = kenwood_init(rig); + if (retval != RIG_OK) + { + return retval; + } + + priv = (struct kenwood_priv_data *) rig->state.priv; + + priv->ag_format = 2; + priv->micgain_min = 0; + priv->micgain_max = 100; + + RETURNFUNC(RIG_OK); +} /* - * ts480 rig capabilities. + * TS-480 rig capabilities * Notice that some rigs share the same functions. - * Also this struct is READONLY! */ const struct rig_caps ts480_caps = { @@ -471,7 +1165,7 @@ const struct rig_caps ts480_caps = .write_delay = 0, .post_write_delay = 0, .timeout = 200, - .retry = 10, + .retry = 3, .preamp = {12, RIG_DBLST_END,}, .attenuator = {12, RIG_DBLST_END,}, .max_rit = kHz(9.99), @@ -480,7 +1174,6 @@ const struct rig_caps ts480_caps = .targetable_vfo = RIG_TARGETABLE_FREQ, .transceive = RIG_TRN_RIG, - .rx_range_list1 = { {kHz(100), Hz(59999999), TS480_ALL_MODES, -1, -1, TS480_VFO}, RIG_FRNG_END, @@ -557,22 +1250,55 @@ const struct rig_caps ts480_caps = /* mode/filter list, remember: order matters! */ .filters = { {RIG_MODE_SSB, kHz(2.4)}, - {RIG_MODE_CW, Hz(200)}, - {RIG_MODE_RTTY, Hz(500)}, - {RIG_MODE_AM, kHz(9)}, - {RIG_MODE_FM, kHz(14)}, + {RIG_MODE_SSB, Hz(270)}, + {RIG_MODE_SSB, Hz(500)}, + {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_FLT_END, }, + .vfo_ops = TS480_VFO_OPS, + .level_gran = { + [LVL_RAWSTR] = { .min = { .i = 0 }, .max = { .i = 255 } }, + [LVL_VOXDELAY] = { .min = { .i = 0 }, .max = { .i = 3000 }, .step = { .i = 150 } }, + [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 = 2400}, .step = {.i = 10}}, + [LVL_SLOPE_HIGH] = {.min = {.i = 0}, .max = {.i = 5000}, .step = {.i = 10}}, + }, + .str_cal = TS480_STR_CAL, + .swr_cal = TS480_SWR_CAL, + + .ext_tokens = ts480_ext_tokens, + .extfuncs = ts480_ext_funcs, + .extlevels = ts480_ext_levels, + .priv = (void *)& ts480_priv_caps, - .rig_init = kenwood_init, + .rig_init = ts480_init, .rig_open = kenwood_open, .rig_cleanup = kenwood_cleanup, .set_freq = kenwood_set_freq, .get_freq = kenwood_get_freq, - .set_rit = kenwood_set_rit, /* FIXME should this switch to rit mode or just set the frequency? */ - .get_rit = kenwood_get_rit, - .set_xit = kenwood_set_xit, /* FIXME should this switch to xit mode or just set the frequency? */ - .get_xit = kenwood_get_xit, + .set_rit = ts480_set_rit, + .get_rit = ts480_get_rit, + .set_xit = ts480_set_rit, + .get_xit = ts480_get_rit, .set_mode = kenwood_set_mode, .get_mode = kenwood_get_mode, .set_vfo = kenwood_set_vfo, @@ -593,16 +1319,21 @@ const struct rig_caps ts480_caps = .has_get_level = TS480_LEVEL_ALL, .set_level = kenwood_ts480_set_level, .get_level = kenwood_ts480_get_level, + .set_ext_level = ts480_set_ext_level, + .get_ext_level = ts480_get_ext_level, .has_get_func = TS480_FUNC_ALL, .has_set_func = TS480_FUNC_ALL, - .set_func = kenwood_set_func, - .get_func = kenwood_get_func, + .set_func = ts480_set_func, + .get_func = ts480_get_func, + .set_ext_func = ts480_set_ext_func, + .get_ext_func = ts480_get_ext_func, + .send_morse = kenwood_send_morse, + .vfo_op = kenwood_vfo_op, }; /* * Hilberling PS8000A TS480 emulation * Notice that some rigs share the same functions. - * Also this struct is READONLY! */ const struct rig_caps pt8000a_caps = { @@ -634,7 +1365,6 @@ const struct rig_caps pt8000a_caps = .targetable_vfo = RIG_TARGETABLE_FREQ, .transceive = RIG_TRN_RIG, - .rx_range_list1 = { // not region specific {kHz(9), MHz(30), PS8000A_ALL_MODES, -1, -1, TS480_VFO, RIG_ANT_2 | RIG_ANT_3, "Generic"}, {MHz(50), MHz(54), PS8000A_ALL_MODES, -1, -1, TS480_VFO, RIG_ANT_1, "Generic"}, @@ -730,9 +1460,9 @@ const struct rig_caps pt8000a_caps = .rig_cleanup = kenwood_cleanup, .set_freq = kenwood_set_freq, .get_freq = kenwood_get_freq, - .set_rit = kenwood_set_rit, /* FIXME should this switch to rit mode or just set the frequency? */ + .set_rit = kenwood_set_rit, .get_rit = kenwood_get_rit, - .set_xit = kenwood_set_xit, /* FIXME should this switch to xit mode or just set the frequency? */ + .set_xit = kenwood_set_xit, .get_xit = kenwood_get_xit, .set_mode = kenwood_set_mode, .get_mode = kenwood_get_mode, @@ -760,162 +1490,6 @@ const struct rig_caps pt8000a_caps = .get_func = kenwood_get_func, }; -/* - * ts890s rig capabilities. - * Copied from ts480_caps - * Where you see TS480 in this the values have not been verified - * Notice that some rigs share the same functions. - * Also this struct is READONLY! - */ -const struct rig_caps ts890s_caps = -{ - RIG_MODEL(RIG_MODEL_TS890S), - .model_name = "TS-890S", - .mfg_name = "Kenwood", - .version = BACKEND_VER ".0", - .copyright = "LGPL", - .status = RIG_STATUS_STABLE, - .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_NONE, - .write_delay = 0, - .post_write_delay = 0, - .timeout = 200, - .retry = 10, - .preamp = {12, RIG_DBLST_END,}, - .attenuator = {12, RIG_DBLST_END,}, - .max_rit = kHz(9.99), - .max_xit = kHz(9.99), - .max_ifshift = Hz(0), - .targetable_vfo = RIG_TARGETABLE_FREQ, - .transceive = RIG_TRN_RIG, - - - .rx_range_list1 = { - {kHz(100), Hz(59999999), TS890_ALL_MODES, -1, -1, TS480_VFO}, - RIG_FRNG_END, - }, /*!< Receive frequency range list for ITU region 1 */ - .tx_range_list1 = { - {kHz(1810), kHz(1850), TS480_OTHER_TX_MODES, 5000, 100000, TS480_VFO}, /* 100W class */ - {kHz(1810), kHz(1850), TS480_AM_TX_MODES, 5000, 25000, TS480_VFO}, /* 25W class */ - {kHz(3500), kHz(3800), TS480_OTHER_TX_MODES, 5000, 100000, TS480_VFO}, - {kHz(3500), kHz(3800), TS480_AM_TX_MODES, 5000, 25000, TS480_VFO}, - {MHz(7), kHz(7200), TS480_OTHER_TX_MODES, 5000, 100000, TS480_VFO}, - {MHz(7), kHz(7200), TS480_AM_TX_MODES, 5000, 25000, TS480_VFO}, - {kHz(10100), kHz(10150), TS480_OTHER_TX_MODES, 5000, 100000, TS480_VFO}, - {kHz(10100), kHz(10150), TS480_AM_TX_MODES, 5000, 25000, TS480_VFO}, - {MHz(14), kHz(14350), TS480_OTHER_TX_MODES, 5000, 100000, TS480_VFO}, - {MHz(14), kHz(14350), TS480_AM_TX_MODES, 5000, 25000, TS480_VFO}, - {kHz(18068), kHz(18168), TS480_OTHER_TX_MODES, 5000, 100000, TS480_VFO}, - {kHz(18068), kHz(18168), TS480_AM_TX_MODES, 5000, 25000, TS480_VFO}, - {MHz(21), kHz(21450), TS480_OTHER_TX_MODES, 5000, 100000, TS480_VFO}, - {MHz(21), kHz(21450), TS480_AM_TX_MODES, 5000, 25000, TS480_VFO}, - {kHz(24890), kHz(24990), TS480_OTHER_TX_MODES, 5000, 100000, TS480_VFO}, - {kHz(24890), kHz(24990), TS480_AM_TX_MODES, 5000, 25000, TS480_VFO}, - {MHz(28), kHz(29700), TS480_OTHER_TX_MODES, 5000, 100000, TS480_VFO}, - {MHz(28), kHz(29700), TS480_AM_TX_MODES, 5000, 25000, TS480_VFO}, - {MHz(50), kHz(52000), TS480_OTHER_TX_MODES, 5000, 100000, TS480_VFO}, - {MHz(50), kHz(52000), TS480_AM_TX_MODES, 5000, 25000, TS480_VFO}, - RIG_FRNG_END, - }, /*!< Transmit frequency range list for ITU region 1 */ - .rx_range_list2 = { - {kHz(100), Hz(59999999), TS890_ALL_MODES, -1, -1, TS480_VFO}, - RIG_FRNG_END, - }, /*!< Receive frequency range list for ITU region 2 */ - .tx_range_list2 = { - {kHz(1800), MHz(2) - 1, TS480_OTHER_TX_MODES, 5000, 100000, TS480_VFO}, /* 100W class */ - {kHz(1800), MHz(2) - 1, TS480_AM_TX_MODES, 5000, 25000, TS480_VFO}, /* 25W class */ - {kHz(3500), MHz(4) - 1, TS480_OTHER_TX_MODES, 5000, 100000, TS480_VFO}, - {kHz(3500), MHz(4) - 1, TS480_AM_TX_MODES, 5000, 25000, TS480_VFO}, - {kHz(5250), kHz(5450), TS480_OTHER_TX_MODES, 5000, 100000, TS480_VFO}, - {kHz(5250), kHz(5450), TS480_AM_TX_MODES, 5000, 25000, TS480_VFO}, - {MHz(7), kHz(7300), TS480_OTHER_TX_MODES, 5000, 100000, TS480_VFO}, - {MHz(7), kHz(7300), TS480_AM_TX_MODES, 5000, 25000, TS480_VFO}, - {kHz(10100), kHz(10150), TS480_OTHER_TX_MODES, 5000, 100000, TS480_VFO}, - {kHz(10100), kHz(10150), TS480_AM_TX_MODES, 5000, 25000, TS480_VFO}, - {MHz(14), kHz(14350), TS480_OTHER_TX_MODES, 5000, 100000, TS480_VFO}, - {MHz(14), kHz(14350), TS480_AM_TX_MODES, 5000, 25000, TS480_VFO}, - {kHz(18068), kHz(18168), TS480_OTHER_TX_MODES, 5000, 100000, TS480_VFO}, - {kHz(18068), kHz(18168), TS480_AM_TX_MODES, 5000, 25000, TS480_VFO}, - {MHz(21), kHz(21450), TS480_OTHER_TX_MODES, 5000, 100000, TS480_VFO}, - {MHz(21), kHz(21450), TS480_AM_TX_MODES, 5000, 25000, TS480_VFO}, - {kHz(24890), kHz(24990), TS480_OTHER_TX_MODES, 5000, 100000, TS480_VFO}, - {kHz(24890), kHz(24990), TS480_AM_TX_MODES, 5000, 25000, TS480_VFO}, - {MHz(28), kHz(29700), TS480_OTHER_TX_MODES, 5000, 100000, TS480_VFO}, - {MHz(28), kHz(29700), TS480_AM_TX_MODES, 5000, 25000, TS480_VFO}, - {MHz(50), kHz(52000), TS480_OTHER_TX_MODES, 5000, 100000, TS480_VFO}, - {MHz(50), kHz(52000), TS480_AM_TX_MODES, 5000, 25000, TS480_VFO}, - RIG_FRNG_END, - }, /*!< Transmit frequency range list for ITU region 2 */ - .tuning_steps = { - {TS890_ALL_MODES, kHz(1)}, - {TS890_ALL_MODES, Hz(2500)}, - {TS890_ALL_MODES, kHz(5)}, - {TS890_ALL_MODES, Hz(6250)}, - {TS890_ALL_MODES, kHz(10)}, - {TS890_ALL_MODES, Hz(12500)}, - {TS890_ALL_MODES, kHz(15)}, - {TS890_ALL_MODES, kHz(20)}, - {TS890_ALL_MODES, kHz(25)}, - {TS890_ALL_MODES, kHz(30)}, - {TS890_ALL_MODES, kHz(100)}, - {TS890_ALL_MODES, kHz(500)}, - {TS890_ALL_MODES, MHz(1)}, - {TS890_ALL_MODES, 0}, /* any tuning step */ - RIG_TS_END, - }, - /* mode/filter list, remember: order matters! */ - .filters = { - {RIG_MODE_SSB, kHz(2.4)}, - {RIG_MODE_CW, Hz(200)}, - {RIG_MODE_RTTY, Hz(500)}, - {RIG_MODE_AM, kHz(9)}, - {RIG_MODE_FM, kHz(15)}, - RIG_FLT_END, - }, - .priv = (void *)& ts890s_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, /* FIXME should this switch to rit mode or just set the frequency? */ - .get_rit = kenwood_get_rit, - .set_xit = kenwood_set_xit, /* FIXME should this switch to xit mode or just set the frequency? */ - .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, - .get_ptt = kenwood_get_ptt, - .set_ptt = kenwood_set_ptt, - .get_dcd = kenwood_get_dcd, - .set_powerstat = kenwood_set_powerstat, - .get_powerstat = kenwood_get_powerstat, - .get_info = kenwood_ts480_get_info, - .reset = kenwood_reset, - .set_ant = kenwood_set_ant, - .get_ant = kenwood_get_ant, - .scan = kenwood_scan, /* not working, invalid arguments using rigctl; kenwood_scan does only support on/off and not tone and CTCSS scan */ - .has_set_level = TS480_LEVEL_ALL, - .has_get_level = TS480_LEVEL_ALL, - .set_level = kenwood_ts480_set_level, - .get_level = kenwood_ts480_get_level, - .has_get_func = TS890_FUNC_ALL, - .has_set_func = TS890_FUNC_ALL, - .set_func = kenwood_set_func, - .get_func = kenwood_get_func, -}; - const struct confparams malachite_cfg_parms[] = { { @@ -1010,4 +1584,3 @@ const struct rig_caps malachite_caps = .set_powerstat = kenwood_set_powerstat, .get_powerstat = kenwood_get_powerstat, }; - diff --git a/rigs/kenwood/ts890s.c b/rigs/kenwood/ts890s.c new file mode 100644 index 000000000..093c7c370 --- /dev/null +++ b/rigs/kenwood/ts890s.c @@ -0,0 +1,374 @@ +/* + * Hamlib Kenwood backend - TS-890S description + * Copyright (c) 2000-2004 by Stephane Fillod and Juergen Rinas + * + * 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 "kenwood.h" + +// TODO: Copied from TS-480, to be verified +#define TS890_VFO (RIG_VFO_A|RIG_VFO_B) + +#define TS890_ALL_MODES (RIG_MODE_LSB|RIG_MODE_USB|RIG_MODE_CW|RIG_MODE_FM|RIG_MODE_AM|RIG_MODE_RTTY|RIG_MODE_CWR|RIG_MODE_RTTYR|RIG_MODE_PSK|RIG_MODE_PSKR|RIG_MODE_PKTLSB|RIG_MODE_PKTUSB|RIG_MODE_PKTFM|RIG_MODE_PKTAM) + +// TODO: Copied from TS-480, to be verified +#define TS890_OTHER_TX_MODES (RIG_MODE_CW|RIG_MODE_SSB|RIG_MODE_FM|RIG_MODE_RTTY) +// TODO: Copied from TS-480, to be verified +#define TS890_AM_TX_MODES RIG_MODE_AM + +// TODO: Copied from TS-480, to be verified +#define TS890_LEVEL_ALL (RIG_LEVEL_RFPOWER|RIG_LEVEL_AF|RIG_LEVEL_RF|RIG_LEVEL_SQL|RIG_LEVEL_AGC) +#define TS890_FUNC_ALL (RIG_FUNC_NB|RIG_FUNC_NB2|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) + +#define TS890_VFO_OPS (RIG_OP_UP|RIG_OP_DOWN|RIG_OP_BAND_UP|RIG_OP_BAND_DOWN|RIG_OP_CPY|RIG_OP_TUNE) + +int kenwood_ts890_set_level(RIG *rig, vfo_t vfo, setting_t level, value_t val) +{ + char levelbuf[16]; + int kenwood_val; + + rig_debug(RIG_DEBUG_TRACE, "%s called\n", __func__); + + switch (level) + { + case RIG_LEVEL_RF: + kenwood_val = val.f * 255; + sprintf(levelbuf, "RG%03d", kenwood_val); + break; + + case RIG_LEVEL_SQL: + kenwood_val = val.f * 255; + sprintf(levelbuf, "SQ%03d", kenwood_val); + break; + + case RIG_LEVEL_AGC: + /* hamlib argument is int, possible values rig.h:enum agc_level_e */ + /* possible values for TS890 0(=off), 1(=slow), 2(=mid), 3(=fast), 4(=off/Last) */ + rig_debug(RIG_DEBUG_VERBOSE, "%s TS890S RIG_LEVEL_AGC\n", __func__); + + switch (val.i) + { + case RIG_AGC_OFF: + kenwood_val = 0; + break; + + case RIG_AGC_SLOW: + kenwood_val = 1; + break; + + case RIG_AGC_MEDIUM: + kenwood_val = 2; + break; + + case RIG_AGC_FAST: + kenwood_val = 3; + break; + + case RIG_AGC_AUTO: + kenwood_val = 4; + break; + + default: + rig_debug(RIG_DEBUG_ERR, "%s: unsupported agc value", __func__); + return -RIG_EINVAL; + } + + sprintf(levelbuf, "GC%d", kenwood_val); + break; + + default: + return kenwood_set_level(rig, vfo, level, val); + } + + return kenwood_transaction(rig, levelbuf, NULL, 0); +} + + +int kenwood_ts890_get_level(RIG *rig, vfo_t vfo, setting_t level, value_t *val) +{ + char ackbuf[50]; + size_t ack_len, ack_len_expected; + int levelint; + int retval; + + rig_debug(RIG_DEBUG_TRACE, "%s called\n", __func__); + + switch (level) + { + 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: + retval = kenwood_transaction(rig, "SQ", 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; + } + + val->f = (float) levelint / 255.; + return RIG_OK; + + case RIG_LEVEL_AGC: + retval = kenwood_transaction(rig, "GC", ackbuf, sizeof(ackbuf)); + ack_len_expected = 3; + + if (RIG_OK != retval) + { + return retval; + } + + ack_len = strlen(ackbuf); + + if (ack_len != ack_len_expected) + { + return -RIG_EPROTO; + } + + switch (ackbuf[ack_len_expected - 1]) + { + 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; + + case '4': + val->i = RIG_AGC_AUTO; + break; + + default: + return -RIG_EPROTO; + } + + return RIG_OK; + + default: + return kenwood_get_level(rig, vfo, level, val); + } +} + +static struct kenwood_priv_caps ts890s_priv_caps = +{ + .cmdtrm = EOM_KEN, +}; + +/* + * TS-890S rig capabilities + * Copied from ts480_caps, many of the values have not been verified. + * Notice that some rigs share the same functions. + */ +const struct rig_caps ts890s_caps = +{ + RIG_MODEL(RIG_MODEL_TS890S), + .model_name = "TS-890S", + .mfg_name = "Kenwood", + .version = BACKEND_VER ".0", + .copyright = "LGPL", + .status = RIG_STATUS_STABLE, + .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_NONE, + .write_delay = 0, + .post_write_delay = 0, + .timeout = 200, + .retry = 10, + .preamp = {12, RIG_DBLST_END,}, + .attenuator = {12, RIG_DBLST_END,}, + .max_rit = kHz(9.99), + .max_xit = kHz(9.99), + .max_ifshift = Hz(0), + .targetable_vfo = RIG_TARGETABLE_FREQ, + .transceive = RIG_TRN_RIG, + + .rx_range_list1 = { + {kHz(100), Hz(59999999), TS890_ALL_MODES, -1, -1, TS890_VFO}, + RIG_FRNG_END, + }, /*!< Receive frequency range list for ITU region 1 */ + .tx_range_list1 = { + {kHz(1810), kHz(1850), TS890_OTHER_TX_MODES, 5000, 100000, TS890_VFO}, /* 100W class */ + {kHz(1810), kHz(1850), TS890_AM_TX_MODES, 5000, 25000, TS890_VFO}, /* 25W class */ + {kHz(3500), kHz(3800), TS890_OTHER_TX_MODES, 5000, 100000, TS890_VFO}, + {kHz(3500), kHz(3800), TS890_AM_TX_MODES, 5000, 25000, TS890_VFO}, + {MHz(7), kHz(7200), TS890_OTHER_TX_MODES, 5000, 100000, TS890_VFO}, + {MHz(7), kHz(7200), TS890_AM_TX_MODES, 5000, 25000, TS890_VFO}, + {kHz(10100), kHz(10150), TS890_OTHER_TX_MODES, 5000, 100000, TS890_VFO}, + {kHz(10100), kHz(10150), TS890_AM_TX_MODES, 5000, 25000, TS890_VFO}, + {MHz(14), kHz(14350), TS890_OTHER_TX_MODES, 5000, 100000, TS890_VFO}, + {MHz(14), kHz(14350), TS890_AM_TX_MODES, 5000, 25000, TS890_VFO}, + {kHz(18068), kHz(18168), TS890_OTHER_TX_MODES, 5000, 100000, TS890_VFO}, + {kHz(18068), kHz(18168), TS890_AM_TX_MODES, 5000, 25000, TS890_VFO}, + {MHz(21), kHz(21450), TS890_OTHER_TX_MODES, 5000, 100000, TS890_VFO}, + {MHz(21), kHz(21450), TS890_AM_TX_MODES, 5000, 25000, TS890_VFO}, + {kHz(24890), kHz(24990), TS890_OTHER_TX_MODES, 5000, 100000, TS890_VFO}, + {kHz(24890), kHz(24990), TS890_AM_TX_MODES, 5000, 25000, TS890_VFO}, + {MHz(28), kHz(29700), TS890_OTHER_TX_MODES, 5000, 100000, TS890_VFO}, + {MHz(28), kHz(29700), TS890_AM_TX_MODES, 5000, 25000, TS890_VFO}, + {MHz(50), kHz(52000), TS890_OTHER_TX_MODES, 5000, 100000, TS890_VFO}, + {MHz(50), kHz(52000), TS890_AM_TX_MODES, 5000, 25000, TS890_VFO}, + RIG_FRNG_END, + }, /*!< Transmit frequency range list for ITU region 1 */ + .rx_range_list2 = { + {kHz(100), Hz(59999999), TS890_ALL_MODES, -1, -1, TS890_VFO}, + RIG_FRNG_END, + }, /*!< Receive frequency range list for ITU region 2 */ + .tx_range_list2 = { + {kHz(1800), MHz(2) - 1, TS890_OTHER_TX_MODES, 5000, 100000, TS890_VFO}, /* 100W class */ + {kHz(1800), MHz(2) - 1, TS890_AM_TX_MODES, 5000, 25000, TS890_VFO}, /* 25W class */ + {kHz(3500), MHz(4) - 1, TS890_OTHER_TX_MODES, 5000, 100000, TS890_VFO}, + {kHz(3500), MHz(4) - 1, TS890_AM_TX_MODES, 5000, 25000, TS890_VFO}, + {kHz(5250), kHz(5450), TS890_OTHER_TX_MODES, 5000, 100000, TS890_VFO}, + {kHz(5250), kHz(5450), TS890_AM_TX_MODES, 5000, 25000, TS890_VFO}, + {MHz(7), kHz(7300), TS890_OTHER_TX_MODES, 5000, 100000, TS890_VFO}, + {MHz(7), kHz(7300), TS890_AM_TX_MODES, 5000, 25000, TS890_VFO}, + {kHz(10100), kHz(10150), TS890_OTHER_TX_MODES, 5000, 100000, TS890_VFO}, + {kHz(10100), kHz(10150), TS890_AM_TX_MODES, 5000, 25000, TS890_VFO}, + {MHz(14), kHz(14350), TS890_OTHER_TX_MODES, 5000, 100000, TS890_VFO}, + {MHz(14), kHz(14350), TS890_AM_TX_MODES, 5000, 25000, TS890_VFO}, + {kHz(18068), kHz(18168), TS890_OTHER_TX_MODES, 5000, 100000, TS890_VFO}, + {kHz(18068), kHz(18168), TS890_AM_TX_MODES, 5000, 25000, TS890_VFO}, + {MHz(21), kHz(21450), TS890_OTHER_TX_MODES, 5000, 100000, TS890_VFO}, + {MHz(21), kHz(21450), TS890_AM_TX_MODES, 5000, 25000, TS890_VFO}, + {kHz(24890), kHz(24990), TS890_OTHER_TX_MODES, 5000, 100000, TS890_VFO}, + {kHz(24890), kHz(24990), TS890_AM_TX_MODES, 5000, 25000, TS890_VFO}, + {MHz(28), kHz(29700), TS890_OTHER_TX_MODES, 5000, 100000, TS890_VFO}, + {MHz(28), kHz(29700), TS890_AM_TX_MODES, 5000, 25000, TS890_VFO}, + {MHz(50), kHz(52000), TS890_OTHER_TX_MODES, 5000, 100000, TS890_VFO}, + {MHz(50), kHz(52000), TS890_AM_TX_MODES, 5000, 25000, TS890_VFO}, + RIG_FRNG_END, + }, /*!< Transmit frequency range list for ITU region 2 */ + .tuning_steps = { + {TS890_ALL_MODES, kHz(1)}, + {TS890_ALL_MODES, Hz(2500)}, + {TS890_ALL_MODES, kHz(5)}, + {TS890_ALL_MODES, Hz(6250)}, + {TS890_ALL_MODES, kHz(10)}, + {TS890_ALL_MODES, Hz(12500)}, + {TS890_ALL_MODES, kHz(15)}, + {TS890_ALL_MODES, kHz(20)}, + {TS890_ALL_MODES, kHz(25)}, + {TS890_ALL_MODES, kHz(30)}, + {TS890_ALL_MODES, kHz(100)}, + {TS890_ALL_MODES, kHz(500)}, + {TS890_ALL_MODES, MHz(1)}, + {TS890_ALL_MODES, 0}, /* any tuning step */ + RIG_TS_END, + }, + /* mode/filter list, remember: order matters! */ + .filters = { + {RIG_MODE_SSB, kHz(2.4)}, + {RIG_MODE_CW, Hz(200)}, + {RIG_MODE_RTTY, Hz(500)}, + {RIG_MODE_AM, kHz(9)}, + {RIG_MODE_FM, kHz(15)}, + RIG_FLT_END, + }, + .vfo_ops = TS890_VFO_OPS, + + .priv = (void *)& ts890s_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, + .get_vfo = kenwood_get_vfo_if, + .set_split_vfo = kenwood_set_split_vfo, + .get_split_vfo = kenwood_get_split_vfo_if, + .get_ptt = kenwood_get_ptt, + .set_ptt = kenwood_set_ptt, + .get_dcd = kenwood_get_dcd, + .set_powerstat = kenwood_set_powerstat, + .get_powerstat = kenwood_get_powerstat, + .get_info = NULL, + .reset = kenwood_reset, + .set_ant = kenwood_set_ant, + .get_ant = kenwood_get_ant, + .scan = kenwood_scan, /* not working, invalid arguments using rigctl; kenwood_scan does only support on/off and not tone and CTCSS scan */ + .has_set_level = TS890_LEVEL_ALL, + .has_get_level = TS890_LEVEL_ALL, + .set_level = kenwood_ts890_set_level, + .get_level = kenwood_ts890_get_level, + .has_get_func = TS890_FUNC_ALL, + .has_set_func = TS890_FUNC_ALL, + .set_func = kenwood_set_func, + .get_func = kenwood_get_func, +};