diff --git a/include/hamlib/riglist.h b/include/hamlib/riglist.h index 2dcd1f3a6..7bcb2b952 100644 --- a/include/hamlib/riglist.h +++ b/include/hamlib/riglist.h @@ -144,6 +144,7 @@ #define RIG_MODEL_FT990UNI RIG_MAKE_MODEL(RIG_YAESU, 48) #define RIG_MODEL_FT710 RIG_MAKE_MODEL(RIG_YAESU, 49) #define RIG_MODEL_FT9000OLD RIG_MAKE_MODEL(RIG_YAESU, 50) +#define RIG_MODEL_FTX1 RIG_MAKE_MODEL(RIG_YAESU, 51) /* * Kenwood diff --git a/rigs/yaesu/Makefile.am b/rigs/yaesu/Makefile.am index 39130a8eb..c1bdb576d 100644 --- a/rigs/yaesu/Makefile.am +++ b/rigs/yaesu/Makefile.am @@ -11,7 +11,8 @@ YAESUSRC = ft100.c ft100.h ft747.c ft747.h ft817.c ft817.h ft847.c ft847.h \ ## Yaesu radios that use the new Kenwood style CAT commands NEWCATSRC = newcat.c newcat.h ft450.c ft450.h ft950.c ft950.h ft991.c ft991.h \ ft2000.c ft2000.h ft9000.c ft9000.h ft5000.c ft5000.h ft1200.c ft1200.h \ - ft891.c ft891.h ftdx101.c ftdx101.h ftdx101mp.c ft3000.c ftdx10.c ft710.h + ft891.c ft891.h ftdx101.c ftdx101.h ftdx101mp.c ft3000.c ftdx10.c ft710.h\ + ftx1.c ftx1.h noinst_LTLIBRARIES = libhamlib-yaesu.la libhamlib_yaesu_la_SOURCES = yaesu.c yaesu.h level_gran_yaesu.h $(YAESUSRC) $(NEWCATSRC) diff --git a/rigs/yaesu/ftx1.c b/rigs/yaesu/ftx1.c new file mode 100644 index 000000000..db87a3989 --- /dev/null +++ b/rigs/yaesu/ftx1.c @@ -0,0 +1,1210 @@ +/* + * hamlib - (C) Frank Singleton 2000 (javabear at users.sourceforge.net) + * + * ftx1.c - (C) Jeremy Miller KO4SSD 2025 (ko4ssd at ko4ssd.com) + * + * The FTX-1 is very much like the FT991 except it has some different frequency ranges and features + * So the code was built using the FT991 code as a template. + * + * This shared library provides an API for communicating + * via serial interface to an FTX-1 using the "CAT" interface + * + * + * 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 + * + */ + +#include +#include +#include "hamlib/rig.h" +#include "misc.h" +#include "cache.h" +#include "newcat.h" +#include "yaesu.h" +#include "ftx1.h" + +/* Prototypes */ +static int ftx1_init(RIG *rig); +static int ftx1_set_vfo(RIG *rig, vfo_t vfo); +static int ftx1_get_vfo(RIG *rig, vfo_t *vfo); +static int ftx1_get_split_mode(RIG *rig, vfo_t vfo, rmode_t *tx_mode, + pbwidth_t *tx_width); +static int ftx1_set_split_mode(RIG *rig, vfo_t vfo, rmode_t tx_mode, + pbwidth_t tx_width); +static int ftx1_set_split_freq(RIG *rig, vfo_t vfo, freq_t tx_freq); +static int ftx1_get_split_freq(RIG *rig, vfo_t vfo, freq_t *tx_freq); +static void debug_ftx1info_data(const ftx1info *rdata); +static int ftx1_set_ctcss_tone(RIG *rig, vfo_t vfo, tone_t tone); +static int ftx1_get_ctcss_tone(RIG *rig, vfo_t vfo, tone_t *tone); +static int ftx1_set_dcs_code(RIG *rig, vfo_t vfo, tone_t code); +static int ftx1_get_dcs_code(RIG *rig, vfo_t vfo, tone_t *code); +static int ftx1_set_ctcss_sql(RIG *rig, vfo_t vfo, tone_t tone); +static int ftx1_get_ctcss_sql(RIG *rig, vfo_t vfo, tone_t *tone); +static int ftx1_get_dcs_sql(RIG *rig, vfo_t vfo, tone_t *code); +static int ftx1_set_dcs_sql(RIG *rig, vfo_t vfo, tone_t code); + +const struct confparams ftx1_ext_levels[] = +{ + { + TOK_KEYER, + "KEYER", + "Keyer", + "Keyer on/off", + NULL, + RIG_CONF_CHECKBUTTON, + }, + { + TOK_APF_FREQ, + "APF_FREQ", + "APF frequency", + "Audio peak filter frequency", + NULL, + RIG_CONF_NUMERIC, + { .n = { .min = -250, .max = 250, .step = 10 } }, + }, + { + TOK_APF_WIDTH, + "APF_WIDTH", + "APF width", + "Audio peak filter width", + NULL, + RIG_CONF_COMBO, + { .c = { .combostr = { "Narrow", "Medium", "Wide", NULL } } }, + }, + { + TOK_CONTOUR, + "CONTOUR", + "Contour", + "Contour on/off", + NULL, + RIG_CONF_CHECKBUTTON, + }, + { + TOK_CONTOUR_FREQ, + "CONTOUR_FREQ", + "Contour frequency", + "Contour frequency", + NULL, + RIG_CONF_NUMERIC, + { .n = { .min = 10, .max = 3200, .step = 1 } }, + }, + { + TOK_CONTOUR_LEVEL, + "CONTOUR_LEVEL", + "Contour level", + "Contour level (dB)", + NULL, + RIG_CONF_NUMERIC, + { .n = { .min = -40, .max = 20, .step = 1 } }, + }, + { + TOK_CONTOUR_WIDTH, + "CONTOUR_WIDTH", + "Contour width", + "Contour width", + NULL, + RIG_CONF_NUMERIC, + { .n = { .min = 1, .max = 11, .step = 1 } }, + }, + { + TOK_MAXPOWER_HF, + "MAXPOWER_HF", + "Maxpower HF", + "Maxpower HF", + NULL, + RIG_CONF_INT, + { .n = { .min = 5, .max = 100, .step = 1 } }, + }, + { + TOK_MAXPOWER_6M, + "MAXPOWER_6M", + "Maxpower 6m", + "Maxpower 6m", + NULL, + RIG_CONF_INT, + { .n = { .min = 5, .max = 100, .step = 1 } }, + }, + { + TOK_MAXPOWER_VHF, + "MAXPOWER_VHF", + "Maxpower VHF", + "Maxpower VHF", + NULL, + RIG_CONF_INT, + { .n = { .min = 5, .max = 50, .step = 1 } }, + }, + { + TOK_MAXPOWER_UHF, + "MAXPOWER_UHF", + "Maxpower UHF", + "Maxpower UHF", + NULL, + RIG_CONF_NUMERIC, + { .n = { .min = 5, .max = 50, .step = 1 } }, + }, + { RIG_CONF_END, NULL, } +}; + +int ftx1_ext_tokens[] = +{ + TOK_KEYER, TOK_APF_FREQ, TOK_APF_WIDTH, + TOK_CONTOUR, TOK_CONTOUR_FREQ, TOK_CONTOUR_LEVEL, TOK_CONTOUR_WIDTH, + TOK_MAXPOWER_HF, TOK_MAXPOWER_6M, TOK_MAXPOWER_UHF, TOK_MAXPOWER_VHF, + TOK_BACKEND_NONE +}; + +/* + * FTX-1 rig capabilities + */ +struct rig_caps ftx1_caps = +{ + RIG_MODEL(RIG_MODEL_FTX1), + .model_name = "FTX-1", + .mfg_name = "Yaesu", + .version = NEWCAT_VER ".1", + .copyright = "LGPL", + .status = RIG_STATUS_ALPHA, + .rig_type = RIG_TYPE_TRANSCEIVER, + .ptt_type = RIG_PTT_RIG, + .dcd_type = RIG_DCD_NONE, + .port_type = RIG_PORT_SERIAL, + .serial_rate_min = 4800, /* Default rate per manual */ + .serial_rate_max = 38400, + .serial_data_bits = 8, + .serial_stop_bits = 2, /* Assumed since manual makes no mention */ + .serial_parity = RIG_PARITY_NONE, + .serial_handshake = RIG_HANDSHAKE_HARDWARE, + .write_delay = FTX1_WRITE_DELAY, + .post_write_delay = FTX1_POST_WRITE_DELAY, + .timeout = 2000, + .retry = 3, + .has_get_func = FTX1_FUNCS, + .has_set_func = FTX1_FUNCS, + .has_get_level = FTX1_LEVELS, + .has_set_level = RIG_LEVEL_SET(FTX1_LEVELS), + .has_get_parm = RIG_PARM_BANDSELECT, + .has_set_parm = RIG_PARM_BANDSELECT, + .level_gran = { +#define NO_LVL_MICGAIN +#define NO_LVL_SQL +#define NO_LVL_MONITOR_GAIN +#define NO_LVL_RFPOWER +#include "level_gran_yaesu.h" +#undef NO_LVL_MICGAIN +#undef NO_LVL_SQL +#undef NO_LVL_MONITOR_GAIN +#undef NO_LVL_RFPOWER + [LVL_MICGAIN] = { .min = { .f = 0 }, .max = { .f = 1.0 }, .step = { .f = 1.0f / 100.0f } }, + [LVL_SQL] = { .min = { .f = 0 }, .max = { .f = 1.0 }, .step = { .f = 1.0f / 100.0f } }, + [LVL_MONITOR_GAIN] = { .min = { .f = 0 }, .max = { .f = 1.0 }, .step = { .f = 1.0f / 100.0f } }, + [LVL_RFPOWER] = { .min = { .f = .05 }, .max = { .f = 1.0 }, .step = { .f = 1.0f / 100.0f } }, + }, + .parm_gran = { + [PARM_BANDSELECT] = {.step = {.s = "BAND160M,BAND80M,BANDUNUSED,BAND40M,BAND30M,BAND20M,BAND17M,BAND15M,BAND12M,BAND10M,BAND6M,BANDGEN,BANDMW,BANDUNUSED,BANDAIR,BAND70CM,BAND33CM"}} + }, + + .ctcss_list = common_ctcss_list, + .dcs_list = common_dcs_list, + .preamp = { 10, 20, RIG_DBLST_END, }, + .attenuator = { 12, RIG_DBLST_END, }, + .max_rit = Hz(9999), + .max_xit = Hz(9999), + .max_ifshift = Hz(1200), + .agc_level_count = 5, + .agc_levels = { RIG_AGC_OFF, RIG_AGC_FAST, RIG_AGC_MEDIUM, RIG_AGC_SLOW, RIG_AGC_AUTO }, + .vfo_ops = FTX1_VFO_OPS, + .scan_ops = RIG_SCAN_VFO, + .targetable_vfo = RIG_TARGETABLE_FREQ, + .transceive = RIG_TRN_OFF, /* May enable later as the 950 has an Auto Info command */ + .bank_qty = 0, + .chan_desc_sz = 0, + .rfpower_meter_cal = FTX1_RFPOWER_METER_CAL, + .str_cal = FTX1_STR_CAL, + .id_meter_cal = FTX1_ID_CAL, + .vd_meter_cal = FTX1_VD_CAL, + .comp_meter_cal = FTX1_COMP_CAL, + .chan_list = { + { 1, 99, RIG_MTYPE_MEM, NEWCAT_MEM_CAP }, + { 100, 117, RIG_MTYPE_MEM, NEWCAT_MEM_CAP }, // P1L-P9U PMS channels + { 118, 127, RIG_MTYPE_MEM, NEWCAT_MEM_CAP }, // 5xx 5MHz band + { 1, 5, RIG_MTYPE_VOICE }, + { 1, 5, RIG_MTYPE_MORSE }, + RIG_CHAN_END, + }, + + // Rig only has 1 model + .rx_range_list1 = { + {kHz(30), MHz(56), FTX1_ALL_RX_MODES, -1, -1, FTX1_VFO_ALL, FTX1_ANTS, "Operating"}, + {MHz(118), MHz(164), FTX1_ALL_RX_MODES, -1, -1, FTX1_VFO_ALL, FTX1_ANTS, "Operating"}, + {MHz(420), MHz(470), FTX1_ALL_RX_MODES, -1, -1, FTX1_VFO_ALL, FTX1_ANTS, "Operating"}, + RIG_FRNG_END, + }, + + .tx_range_list1 = { + {MHz(1.8), MHz(54), FTX1_OTHER_TX_MODES, W(5), W(100), FTX1_VFO_ALL, FTX1_ANTS, "Operating"}, + {MHz(1.8), MHz(54), FTX1_AM_TX_MODES, W(2), W(25), FTX1_VFO_ALL, FTX1_ANTS, "Operating"}, /* AM class */ + {MHz(144), MHz(148), FTX1_OTHER_TX_MODES, W(5), W(50), FTX1_VFO_ALL, FTX1_ANTS, "Operating"}, + {MHz(144), MHz(148), FTX1_AM_TX_MODES, W(2), W(25), FTX1_VFO_ALL, FTX1_ANTS, "Operating"}, /* AM class */ + {MHz(430), MHz(450), FTX1_OTHER_TX_MODES, W(5), W(50), FTX1_VFO_ALL, FTX1_ANTS, "Operating"}, + {MHz(430), MHz(450), FTX1_AM_TX_MODES, W(2), W(25), FTX1_VFO_ALL, FTX1_ANTS, "Operating"}, /* AM class */ + RIG_FRNG_END, + }, + + .tuning_steps = { + {FTX1_SSB_CW_RX_MODES, Hz(10)}, /* Normal */ + {FTX1_SSB_CW_RX_MODES, Hz(100)}, /* Fast */ + + {FTX1_AM_RX_MODES, Hz(100)}, /* Normal */ + {FTX1_AM_RX_MODES, kHz(1)}, /* Fast */ + + {FTX1_FM_RX_MODES, Hz(100)}, /* Normal */ + {FTX1_FM_RX_MODES, kHz(1)}, /* Fast */ + + RIG_TS_END, + + }, + + /* mode/filter list, .remember = order matters! */ + .filters = { + {FTX1_RTTY_DATA_RX_MODES, Hz(500)}, /* Normal RTTY, DATA */ + {FTX1_RTTY_DATA_RX_MODES, Hz(300)}, /* Narrow RTTY, DATA */ + {FTX1_RTTY_DATA_RX_MODES, Hz(3000)}, /* Wide RTTY, DATA */ + {FTX1_RTTY_DATA_RX_MODES, Hz(2400)}, /* RTTY, DATA */ + {FTX1_RTTY_DATA_RX_MODES, Hz(2000)}, /* RTTY, DATA */ + {FTX1_RTTY_DATA_RX_MODES, Hz(1700)}, /* RTTY, DATA */ + {FTX1_RTTY_DATA_RX_MODES, Hz(1400)}, /* RTTY, DATA */ + {FTX1_RTTY_DATA_RX_MODES, Hz(1200)}, /* RTTY, DATA */ + {FTX1_RTTY_DATA_RX_MODES, Hz(800)}, /* RTTY, DATA */ + {FTX1_RTTY_DATA_RX_MODES, Hz(450)}, /* RTTY, DATA */ + {FTX1_RTTY_DATA_RX_MODES, Hz(400)}, /* RTTY, DATA */ + {FTX1_RTTY_DATA_RX_MODES, Hz(350)}, /* RTTY, DATA */ + {FTX1_RTTY_DATA_RX_MODES, Hz(250)}, /* RTTY, DATA */ + {FTX1_RTTY_DATA_RX_MODES, Hz(200)}, /* RTTY, DATA */ + {FTX1_RTTY_DATA_RX_MODES, Hz(150)}, /* RTTY, DATA */ + {FTX1_RTTY_DATA_RX_MODES, Hz(100)}, /* RTTY, DATA */ + {FTX1_RTTY_DATA_RX_MODES, Hz(50)}, /* RTTY, DATA */ + {FTX1_CW_RX_MODES, Hz(2400)}, /* Normal CW */ + {FTX1_CW_RX_MODES, Hz(500)}, /* Narrow CW */ + {FTX1_CW_RX_MODES, Hz(3000)}, /* Wide CW */ + {FTX1_CW_RX_MODES, Hz(2000)}, /* CW */ + {FTX1_CW_RX_MODES, Hz(1700)}, /* CW */ + {FTX1_CW_RX_MODES, Hz(1400)}, /* CW */ + {FTX1_CW_RX_MODES, Hz(1200)}, /* CW */ + {FTX1_CW_RX_MODES, Hz(800)}, /* CW */ + {FTX1_CW_RX_MODES, Hz(450)}, /* CW */ + {FTX1_CW_RX_MODES, Hz(400)}, /* CW */ + {FTX1_CW_RX_MODES, Hz(350)}, /* CW */ + {FTX1_CW_RX_MODES, Hz(300)}, /* CW */ + {FTX1_CW_RX_MODES, Hz(250)}, /* CW */ + {FTX1_CW_RX_MODES, Hz(200)}, /* CW */ + {FTX1_CW_RX_MODES, Hz(150)}, /* CW */ + {FTX1_CW_RX_MODES, Hz(100)}, /* CW */ + {FTX1_CW_RX_MODES, Hz(50)}, /* CW */ + {RIG_MODE_SSB, Hz(2400)}, /* Normal SSB */ + {RIG_MODE_SSB, Hz(1500)}, /* Narrow SSB */ + {RIG_MODE_SSB, Hz(3200)}, /* Wide SSB */ + {RIG_MODE_SSB, Hz(3000)}, /* SSB */ + {RIG_MODE_SSB, Hz(2900)}, /* SSB */ + {RIG_MODE_SSB, Hz(2800)}, /* SSB */ + {RIG_MODE_SSB, Hz(2700)}, /* SSB */ + {RIG_MODE_SSB, Hz(2600)}, /* SSB */ + {RIG_MODE_SSB, Hz(2500)}, /* SSB */ + {RIG_MODE_SSB, Hz(2300)}, /* SSB */ + {RIG_MODE_SSB, Hz(2200)}, /* SSB */ + {RIG_MODE_SSB, Hz(2100)}, /* SSB */ + {RIG_MODE_SSB, Hz(1950)}, /* SSB */ + {RIG_MODE_SSB, Hz(1650)}, /* SSB */ + {RIG_MODE_SSB, Hz(1350)}, /* SSB */ + {RIG_MODE_SSB, Hz(1100)}, /* SSB */ + {RIG_MODE_SSB, Hz(850)}, /* SSB */ + {RIG_MODE_SSB, Hz(600)}, /* SSB */ + {RIG_MODE_SSB, Hz(400)}, /* SSB */ + {RIG_MODE_SSB, Hz(200)}, /* SSB */ + {RIG_MODE_AM, Hz(9000)}, /* Normal AM */ + {RIG_MODE_AMN, Hz(6000)}, /* Narrow AM */ + {FTX1_FM_WIDE_RX_MODES, Hz(16000)}, /* Normal FM, PKTFM, C4FM */ + {RIG_MODE_FMN, Hz(9000)}, /* Narrow FM */ + + RIG_FLT_END, + }, + + .ext_tokens = ftx1_ext_tokens, + .extlevels = ftx1_ext_levels, + + .priv = NULL, /* private data FIXME: */ + + .rig_init = ftx1_init, + .rig_cleanup = newcat_cleanup, + .rig_open = newcat_open, /* port opened */ + .rig_close = newcat_close, /* port closed */ + + .set_freq = newcat_set_freq, + .get_freq = newcat_get_freq, + .set_mode = newcat_set_mode, + .get_mode = newcat_get_mode, + .set_vfo = ftx1_set_vfo, + .get_vfo = ftx1_get_vfo, + .set_ptt = newcat_set_ptt, + .get_ptt = newcat_get_ptt, + .set_split_vfo = newcat_set_split_vfo, + .get_split_vfo = newcat_get_split_vfo, + .set_split_freq = ftx1_set_split_freq, + .get_split_freq = ftx1_get_split_freq, + .get_split_mode = ftx1_get_split_mode, + .set_split_mode = ftx1_set_split_mode, + .set_rit = newcat_set_rit, + .get_rit = newcat_get_rit, + .set_xit = newcat_set_xit, + .get_xit = newcat_get_xit, + .get_func = newcat_get_func, + .set_func = newcat_set_func, + .get_parm = newcat_get_parm, + .set_parm = newcat_set_parm, + .get_level = newcat_get_level, + .set_level = newcat_set_level, + .get_mem = newcat_get_mem, + .set_mem = newcat_set_mem, + .vfo_op = newcat_vfo_op, + .get_info = newcat_get_info, + .power2mW = newcat_power2mW, + .mW2power = newcat_mW2power, + .set_rptr_shift = newcat_set_rptr_shift, + .get_rptr_shift = newcat_get_rptr_shift, + .set_rptr_offs = newcat_set_rptr_offs, + .get_rptr_offs = newcat_get_rptr_offs, + .set_ctcss_tone = ftx1_set_ctcss_tone, + .get_ctcss_tone = ftx1_get_ctcss_tone, + .set_dcs_code = ftx1_set_dcs_code, + .get_dcs_code = ftx1_get_dcs_code, + .set_ctcss_sql = ftx1_set_ctcss_sql, + .get_ctcss_sql = ftx1_get_ctcss_sql, + .set_dcs_sql = ftx1_set_dcs_sql, + .get_dcs_sql = ftx1_get_dcs_sql, + .set_powerstat = newcat_set_powerstat, + .get_powerstat = newcat_get_powerstat, + .set_ts = newcat_set_ts, + .get_ts = newcat_get_ts, + .set_trn = newcat_set_trn, + .get_trn = newcat_get_trn, + .set_channel = newcat_set_channel, + .get_channel = newcat_get_channel, + .set_ext_level = newcat_set_ext_level, + .get_ext_level = newcat_get_ext_level, + .send_morse = newcat_send_morse, + .wait_morse = rig_wait_morse, + .scan = newcat_scan, + .send_voice_mem = newcat_send_voice_mem, + .set_clock = newcat_set_clock, + .get_clock = newcat_get_clock, + .morse_qsize = 50, + .hamlib_check_rig_caps = HAMLIB_CHECK_RIG_CAPS +}; + + +static int +ftx1_get_tx_split(RIG *rig, split_t *in_split) +{ + vfo_t cur_tx_vfo; + int rval; + + rig_debug(RIG_DEBUG_VERBOSE, "%s called\n", __func__); + + if (!rig || !in_split) + { + return (-RIG_EINVAL); + } + + rval = newcat_get_tx_vfo(rig, &cur_tx_vfo); + + if (rval != RIG_OK) + { + return (rval); + } + + if (cur_tx_vfo == RIG_VFO_B || cur_tx_vfo == RIG_VFO_MEM) + { + *in_split = RIG_SPLIT_ON; + } + else if (cur_tx_vfo == RIG_VFO_A) + { + *in_split = RIG_SPLIT_OFF; + } + else + { + return (-RIG_EINVAL); + } + + return (rval); +} + +int +ftx1_set_split_freq(RIG *rig, vfo_t vfo, freq_t tx_freq) +{ + int rval; + split_t is_split; + + rig_debug(RIG_DEBUG_VERBOSE, "%s called\n", __func__); + + rval = ftx1_get_tx_split(rig, &is_split); + + if (rval != RIG_OK) + { + return (rval); + } + + if (CACHE(rig)->freqMainB == tx_freq) + { + rig_debug(RIG_DEBUG_TRACE, "%s: freq %.0f already set on VFOB\n", __func__, + tx_freq); + return RIG_OK; + } + + if (is_split == RIG_SPLIT_OFF) + { + rval = newcat_set_tx_vfo(rig, RIG_VFO_B); + + if (rval != RIG_OK) + { + return (rval); + } + } + + rval = newcat_set_freq(rig, RIG_VFO_B, tx_freq); + rig_debug(RIG_DEBUG_VERBOSE, + "%s newcat_set_freq() rval = %d freq = %f\n", + __func__, rval, tx_freq); + return (rval); +} + +int +ftx1_get_split_freq(RIG *rig, vfo_t vfo, freq_t *tx_freq) +{ + int rval; + split_t is_split; + + rig_debug(RIG_DEBUG_VERBOSE, "%s called\n", __func__); + + rval = ftx1_get_tx_split(rig, &is_split); + + if (rval != RIG_OK) + { + return (rval); + } + + if (is_split == RIG_SPLIT_OFF) + { + *tx_freq = 0.0; + return (rval); + } + + rval = newcat_get_freq(rig, RIG_VFO_B, tx_freq); + rig_debug(RIG_DEBUG_VERBOSE, + "%s newcat_get_freq() rval = %d freq = %f\n", + __func__, rval, *tx_freq); + + return (rval); +} + +/* + * rig_get_split_mode* + * + * Get the 'X1 split TX mode + * + * Parameter | Type | Accepted/expected values + * ------------------------------------------------------------------ + * *rig | input | pointer to private data + * vfo | input | currVFO, VFOA, VFOB, MEM + * *tx_mode | output | supported modes + * *tx_width | output | supported widths + * ------------------------------------------------------------------ + * Returns RIG_OK on success or an error code on failure + * + * Comments: Checks to see if the X1 is in split mode, if so it + * checks which VFO is set for TX and then gets the + * mode and passband of that VFO and stores it into *tx_mode + * and tx_width respectively. If not in split mode returns + * RIG_MODE_NONE and 0 Hz. + * + */ + +static int ftx1_get_split_mode(RIG *rig, vfo_t vfo, rmode_t *tx_mode, + pbwidth_t *tx_width) +{ + struct newcat_priv_data *priv; + int err; + ftx1info *rdata; + + rig_debug(RIG_DEBUG_VERBOSE, "%s called\n", __func__); + + if (!rig || !tx_mode || !tx_width) + { + return -RIG_EINVAL; + } + + priv = (struct newcat_priv_data *)STATE(rig)->priv; + rdata = (ftx1info *)priv->ret_data; + + SNPRINTF(priv->cmd_str, sizeof(priv->cmd_str), "OI;"); + + if (RIG_OK != (err = newcat_get_cmd(rig))) + { + return err; + } + + debug_ftx1info_data(rdata); + + *tx_mode = newcat_rmode(rdata->mode); + rig_debug(RIG_DEBUG_VERBOSE, "%s opposite mode %s\n", __func__, + rig_strrmode(*tx_mode)); + *tx_width = RIG_PASSBAND_NORMAL; + + return RIG_OK; +} + +static void debug_ftx1info_data(const ftx1info *rdata) +{ + + rig_debug(RIG_DEBUG_VERBOSE, "%s command %2.2s\n", + __func__, rdata->command); + rig_debug(RIG_DEBUG_VERBOSE, "%s memory_ch %3.3s\n", + __func__, rdata->memory_ch); + rig_debug(RIG_DEBUG_VERBOSE, "%s vfo_freq %9.9s\n", + __func__, rdata->vfo_freq); + rig_debug(RIG_DEBUG_VERBOSE, "%s clarifier %5.5s\n", + __func__, rdata->clarifier); + rig_debug(RIG_DEBUG_VERBOSE, "%s rx_clarifier %c\n", + __func__, rdata->rx_clarifier); + rig_debug(RIG_DEBUG_VERBOSE, "%s tx_clarifier %c\n", + __func__, rdata->tx_clarifier); + rig_debug(RIG_DEBUG_VERBOSE, "%s mode %c\n", + __func__, rdata->mode); + rig_debug(RIG_DEBUG_VERBOSE, "%s vfo_memory %c\n", + __func__, rdata->vfo_memory); + rig_debug(RIG_DEBUG_VERBOSE, "%s tone_mode %c\n", + __func__, rdata->tone_mode); + rig_debug(RIG_DEBUG_VERBOSE, "%s fixed %2.2s\n", + __func__, rdata->fixed); + rig_debug(RIG_DEBUG_VERBOSE, "%s repeater_offset %c\n", + __func__, rdata->repeater_offset); + rig_debug(RIG_DEBUG_VERBOSE, "%s terminator %c\n", + __func__, rdata->terminator); + +} + +/* + * rig_set_split_mode + * + * Set the 'X1 split TX mode + * + * Parameter | Type | Accepted/expected values + * ------------------------------------------------------------------ + * *rig | input | pointer to private data + * vfo | input | currVFO, VFOA, VFOB, MEM + * tx_mode | input | supported modes + * tx_width | input | supported widths + * ------------------------------------------------------------------ + * Returns RIG_OK on success or an error code on failure + * + * Comments: Pass band is not set here nor does it make sense as the + * FTX-1 cannot receive on VFO B. The FTX-1 cannot set + * VFO B mode directly so we'll just set A and swap A + * into B but we must preserve the VFO A mode and VFO B + * frequency. + * + */ + +static int ftx1_set_split_mode(RIG *rig, vfo_t vfo, rmode_t tx_mode, + pbwidth_t tx_width) +{ + struct newcat_priv_data *priv; + struct rig_state *state; + int err; + char restore_commands[NEWCAT_DATA_LEN]; + split_t is_split; + + rig_debug(RIG_DEBUG_VERBOSE, "%s called\n", __func__); + + if (!rig) + { + return -RIG_EINVAL; + } + + if (CACHE(rig)->modeMainB == tx_mode) + { + rig_debug(RIG_DEBUG_TRACE, "%s: mode %s already set on VFOB\n", __func__, + rig_strrmode(tx_mode)); + return RIG_OK; + } + + err = ftx1_get_tx_split(rig, &is_split); + + if (err != RIG_OK) + { + return (err); + } + + if (is_split == RIG_SPLIT_ON) + { + err = newcat_set_tx_vfo(rig, RIG_VFO_B); + + if (err != RIG_OK) + { + return (err); + } + } + + + state = STATE(rig); + + rig_debug(RIG_DEBUG_TRACE, "%s: passed vfo = %s\n", __func__, + rig_strvfo(vfo)); + rig_debug(RIG_DEBUG_TRACE, "%s: passed mode = %s\n", __func__, + rig_strrmode(tx_mode)); + rig_debug(RIG_DEBUG_TRACE, "%s: passed width = %d Hz\n", __func__, + (int)tx_width); + + priv = (struct newcat_priv_data *)state->priv; + + /* append VFO A mode restore command first as we want to minimize + any Rx glitches */ + SNPRINTF(priv->cmd_str, sizeof(priv->cmd_str), "MD0;"); + rig_debug(RIG_DEBUG_TRACE, "cmd_str = %s\n", priv->cmd_str); + + if (RIG_OK != (err = newcat_get_cmd(rig))) + { + return err; + } + + SNPRINTF(restore_commands, sizeof(restore_commands), "AB;%.*s", + (int)sizeof(restore_commands) - 4, priv->ret_data); + + /* append VFO B frequency restore command */ + SNPRINTF(priv->cmd_str, sizeof(priv->cmd_str), "FB;"); + rig_debug(RIG_DEBUG_TRACE, "cmd_str = %s\n", priv->cmd_str); + + if (RIG_OK != (err = newcat_get_cmd(rig))) + { + return err; + } + + size_t len = strlen(restore_commands); + SNPRINTF(restore_commands + len, sizeof(restore_commands) - len, "%.*s", + (int)(sizeof(restore_commands) - len - 1), priv->ret_data); + + /* Change mode on VFOA */ + if (RIG_OK != (err = newcat_set_mode(rig, RIG_VFO_A, tx_mode, + RIG_PASSBAND_NOCHANGE))) + { + return err; + } + + /* Send the copy VFO A to VFO B and restore commands */ + SNPRINTF(priv->cmd_str, sizeof(priv->cmd_str), "%s", restore_commands); + return newcat_set_cmd(rig); +} + +static int ftx1_init(RIG *rig) +{ + int ret; + + rig_debug(RIG_DEBUG_VERBOSE, "%s called, version %s\n", __func__, + rig->caps->version); + + ret = newcat_init(rig); + + if (ret != RIG_OK) { return ret; } + + STATE(rig)->current_vfo = RIG_VFO_A; + return RIG_OK; +} + +static int ftx1_find_current_vfo(RIG *rig, vfo_t *vfo, tone_t *enc_dec_mode, + rmode_t *mode) +{ + struct newcat_priv_data *priv = (struct newcat_priv_data *)STATE(rig)->priv; + ftx1info *info = (ftx1info *)priv->ret_data; + int err; + + rig_debug(RIG_DEBUG_TRACE, "%s called\n", __func__); + + SNPRINTF(priv->cmd_str, sizeof(priv->cmd_str), "IF;"); + + /* Get info */ + if (RIG_OK != (err = newcat_get_cmd(rig))) + { + return err; + } + + debug_ftx1info_data(info); + + if (enc_dec_mode != NULL) + { + *enc_dec_mode = info->tone_mode; + } + + if (mode != NULL) + { + *mode = newcat_rmode(info->mode); + } + + switch (info->vfo_memory) + { + case '1': // Memory + case '2': // Memory Tune + case '3': // Quick Memory + case '4': // Quick Memory Tune + *vfo = RIG_VFO_MEM; + break; + + case '0': // VFO + *vfo = RIG_VFO_A; + break; + + default: + rig_debug(RIG_DEBUG_BUG, "%s: unexpected vfo returned 0x%X\n", + __func__, info->vfo_memory); + return -RIG_EINTERNAL; + } + + return RIG_OK; +} + +static int ftx1_get_enabled_ctcss_dcs_mode(RIG *rig) +{ + struct newcat_priv_data *priv = (struct newcat_priv_data *)STATE(rig)->priv; + int err; + + rig_debug(RIG_DEBUG_TRACE, "%s called\n", __func__); + + SNPRINTF(priv->cmd_str, sizeof(priv->cmd_str), "CT0;"); + + /* Get enabled mode */ + if (RIG_OK != (err = newcat_get_cmd(rig))) + { + return err; + } + + return priv->ret_data[3]; +} + +static int ftx1_set_ctcss_tone(RIG *rig, vfo_t vfo, tone_t tone) +{ + struct newcat_priv_data *priv = (struct newcat_priv_data *)STATE(rig)->priv; + int i; + ncboolean tone_match; + + rig_debug(RIG_DEBUG_TRACE, "%s called\n", __func__); + + for (i = 0, tone_match = FALSE; rig->caps->ctcss_list[i] != 0; i++) + { + if (tone == rig->caps->ctcss_list[i]) + { + tone_match = TRUE; + break; + } + } + + rig_debug(RIG_DEBUG_TRACE, "%s: tone = %u, tone_match = %d, i = %d\n", + __func__, tone, tone_match, i); + + if (tone_match == FALSE && tone != 0) + { + return -RIG_EINVAL; + } + + if (tone == 0) /* turn off ctcss */ + { + SNPRINTF(priv->cmd_str, sizeof(priv->cmd_str), "CT00;"); + } + else + { + SNPRINTF(priv->cmd_str, sizeof(priv->cmd_str), "CN00%3.3d;CT02;", i); + } + + return newcat_set_cmd(rig); +} + +static int ftx1_get_ctcss_tone(RIG *rig, vfo_t vfo, tone_t *tone) +{ + struct newcat_priv_data *priv = (struct newcat_priv_data *)STATE(rig)->priv; + int ret; + int t; + int ret_data_len; + tone_t enc_dec_mode; + rmode_t rmode; + char *retlvl; + + rig_debug(RIG_DEBUG_TRACE, "%s called with vfo %s\n", + __func__, rig_strvfo(vfo)); + + *tone = 0; + + ret = ftx1_find_current_vfo(rig, &vfo, &enc_dec_mode, &rmode); + + if (ret < 0) + { + return ret; + } + + rig_debug(RIG_DEBUG_TRACE, "%s current vfo is %s\n", + __func__, rig_strvfo(vfo)); + + if (rmode != RIG_MODE_FM && rmode != RIG_MODE_FMN && rmode != RIG_MODE_C4FM) + { + return RIG_OK; + } + + if ((enc_dec_mode == '0') || // CTCSS and DCS Disabled + (enc_dec_mode == '3') || // DCS Encode and Decode Enabled + (enc_dec_mode == '4')) // DCS Encode only + { + return RIG_OK; // Any of the above not CTCSS return 0 + } + + /* Get CTCSS TONE */ + SNPRINTF(priv->cmd_str, sizeof(priv->cmd_str), "CN00;"); + + if (RIG_OK != (ret = newcat_get_cmd(rig))) + { + return ret; + } + + ret_data_len = strlen(priv->ret_data); + + /* skip command */ + retlvl = priv->ret_data + strlen(priv->cmd_str) - 1; + /* chop term */ + priv->ret_data[ret_data_len - 1] = '\0'; + + t = atoi(retlvl); /* tone index */ + + rig_debug(RIG_DEBUG_TRACE, "%s ctcss code %d\n", __func__, t); + + if (t < 0 || t > 49) + { + return -RIG_EINVAL; + } + + *tone = rig->caps->ctcss_list[t]; + + return RIG_OK; +} + +static int ftx1_set_ctcss_sql(RIG *rig, vfo_t vfo, tone_t tone) +{ + struct newcat_priv_data *priv = (struct newcat_priv_data *)STATE(rig)->priv; + int err; + rmode_t rmode; + + rig_debug(RIG_DEBUG_TRACE, "%s called\n", __func__); + + err = ftx1_find_current_vfo(rig, &vfo, NULL, &rmode); + + if (err != RIG_OK) + { + return err; + } + + if (rmode != RIG_MODE_FM && rmode != RIG_MODE_FMN && rmode != RIG_MODE_C4FM) + { + return -RIG_EINVAL; // Invalid mode for setting ctcss + } + + if (tone == 0) + { + SNPRINTF(priv->cmd_str, sizeof(priv->cmd_str), "CT00;"); + } + else + { + int i; + ncboolean tone_match; + + for (i = 0, tone_match = FALSE; rig->caps->ctcss_list[i] != 0; i++) + { + if (tone == rig->caps->ctcss_list[i]) + { + tone_match = TRUE; + break; + } + } + + if (tone_match == FALSE) + { + return -RIG_EINVAL; // Tone not on the list + } + + SNPRINTF(priv->cmd_str, sizeof(priv->cmd_str), "CN0%3.3d;CT01;", i); + } + + return newcat_set_cmd(rig); +} + +static int ftx1_get_ctcss_sql(RIG *rig, vfo_t vfo, tone_t *tone) +{ + struct newcat_priv_data *priv = (struct newcat_priv_data *)STATE(rig)->priv; + int ret; + int t; + int ret_data_len; + char *retlvl; + + rig_debug(RIG_DEBUG_TRACE, "%s called\n", __func__); + + *tone = 0; + + ret = ftx1_get_enabled_ctcss_dcs_mode(rig); + + if (ret < 0) + { + return ret; + } + + if (ret != '1') // If not CTCSS Encode and Decode return tone of zero. + { + return RIG_OK; + } + + /* Get CTCSS TONE */ + SNPRINTF(priv->cmd_str, sizeof(priv->cmd_str), "CN00;"); + + if (RIG_OK != (ret = newcat_get_cmd(rig))) + { + return ret; + } + + ret_data_len = strlen(priv->ret_data); + + /* skip command */ + retlvl = priv->ret_data + strlen(priv->cmd_str) - 1; + /* chop term */ + priv->ret_data[ret_data_len - 1] = '\0'; + + t = atoi(retlvl); /* tone index */ + + rig_debug(RIG_DEBUG_TRACE, "%s ctcss code %d\n", __func__, t); + + if (t < 0 || t > 49) + { + return -RIG_EINVAL; + } + + *tone = rig->caps->ctcss_list[t]; + + return RIG_OK; +} + +static int ftx1_get_dcs_code(RIG *rig, vfo_t vfo, tone_t *code) +{ + struct newcat_priv_data *priv = (struct newcat_priv_data *)STATE(rig)->priv; + int err; + int t; + tone_t enc_dec_mode; + rmode_t rmode; + int ret_data_len; + char *retlvl; + + rig_debug(RIG_DEBUG_TRACE, "%s called\n", __func__); + + *code = 0; + + err = ftx1_find_current_vfo(rig, &vfo, &enc_dec_mode, &rmode); + + if (err < 0) + { + return err; + } + + rig_debug(RIG_DEBUG_TRACE, "%s current vfo is %s\n", + __func__, rig_strvfo(vfo)); + + if (rmode != RIG_MODE_FM && rmode != RIG_MODE_FMN && rmode != RIG_MODE_C4FM) + { + return RIG_OK; + } + + if ((enc_dec_mode == '0') || // Encode off + (enc_dec_mode == '1') || // CTCSS Encode and Decode + (enc_dec_mode == '2')) // CTCSS Encode Only + { + return RIG_OK; // Any of the above not DCS return 0 + } + + SNPRINTF(priv->cmd_str, sizeof(priv->cmd_str), "CN01;"); + + /* Get DCS code */ + if (RIG_OK != (err = newcat_get_cmd(rig))) + { + return err; + } + + ret_data_len = strlen(priv->ret_data); + + /* skip command */ + retlvl = priv->ret_data + strlen(priv->cmd_str) - 1; + /* chop term */ + priv->ret_data[ret_data_len - 1] = '\0'; + + t = atoi(retlvl); /* code index */ + + if (t < 0 || t > 103) + { + return -RIG_EINVAL; + } + + *code = rig->caps->dcs_list[t]; + + rig_debug(RIG_DEBUG_TRACE, "%s dcs code %u\n", __func__, *code); + + return RIG_OK; +} + +static int ftx1_set_dcs_code(RIG *rig, vfo_t vfo, tone_t code) +{ + struct newcat_priv_data *priv = (struct newcat_priv_data *)STATE(rig)->priv; + int i; + ncboolean code_match; + + rig_debug(RIG_DEBUG_TRACE, "%s called\n", __func__); + + for (i = 0, code_match = FALSE; rig->caps->dcs_list[i] != 0; i++) + { + if (code == rig->caps->dcs_list[i]) + { + code_match = TRUE; + break; + } + } + + rig_debug(RIG_DEBUG_TRACE, "%s: code = %u, code_match = %d, i = %d\n", + __func__, code, code_match, i); + + if (code_match == FALSE && code != 0) + { + return -RIG_EINVAL; + } + + if (code == 0) /* turn off dcs */ + { + SNPRINTF(priv->cmd_str, sizeof(priv->cmd_str), "CT00;"); + } + else + { + SNPRINTF(priv->cmd_str, sizeof(priv->cmd_str), "CN01%3.3d;CT04;", i); + } + + return newcat_set_cmd(rig); +} + +static int ftx1_set_dcs_sql(RIG *rig, vfo_t vfo, tone_t code) +{ + struct newcat_priv_data *priv = (struct newcat_priv_data *)STATE(rig)->priv; + int i; + ncboolean code_match; + + rig_debug(RIG_DEBUG_TRACE, "%s called\n", __func__); + + for (i = 0, code_match = FALSE; rig->caps->dcs_list[i] != 0; i++) + { + if (code == rig->caps->dcs_list[i]) + { + code_match = TRUE; + break; + } + } + + rig_debug(RIG_DEBUG_TRACE, "%s: code = %u, code_match = %d, i = %d\n", + __func__, code, code_match, i); + + if (code_match == FALSE && code != 0) + { + return -RIG_EINVAL; + } + + if (code == 0) /* turn off dcs */ + { + SNPRINTF(priv->cmd_str, sizeof(priv->cmd_str), "CT00;"); + } + else + { + SNPRINTF(priv->cmd_str, sizeof(priv->cmd_str), "CN01%3.3d;CT03;", i); + } + + return newcat_set_cmd(rig); +} + +static int ftx1_get_dcs_sql(RIG *rig, vfo_t vfo, tone_t *code) +{ + struct newcat_priv_data *priv = (struct newcat_priv_data *)STATE(rig)->priv; + int codeindex; + int ret; + int ret_data_len; + char *retlvl; + + rig_debug(RIG_DEBUG_TRACE, "%s called\n", __func__); + + *code = 0; + + ret = ftx1_get_enabled_ctcss_dcs_mode(rig); + + if (ret < 0) + { + return ret; + } + + if (ret != '3') + { + return RIG_OK; // If not DCS Encode and Decode return zero. + } + + /* Get DCS CODE */ + SNPRINTF(priv->cmd_str, sizeof(priv->cmd_str), "CN01;"); + + if (RIG_OK != (ret = newcat_get_cmd(rig))) + { + return ret; + } + + ret_data_len = strlen(priv->ret_data); + + /* skip command */ + retlvl = priv->ret_data + strlen(priv->cmd_str) - 1; + /* chop term */ + priv->ret_data[ret_data_len - 1] = '\0'; + + codeindex = atoi(retlvl); /* code index */ + + rig_debug(RIG_DEBUG_TRACE, "%s dcs code %d\n", __func__, codeindex); + + if (codeindex < 0 || codeindex > 103) + { + return -RIG_EINVAL; + } + + *code = rig->caps->dcs_list[codeindex]; + + return RIG_OK; +} + +// VFO functions so rigctld can be used without --vfo argument +static int ftx1_set_vfo(RIG *rig, vfo_t vfo) +{ + STATE(rig)->current_vfo = vfo; + RETURNFUNC2(RIG_OK); +} + +static int ftx1_get_vfo(RIG *rig, vfo_t *vfo) +{ + *vfo = STATE(rig)->current_vfo; + RETURNFUNC2(RIG_OK); +} \ No newline at end of file diff --git a/rigs/yaesu/ftx1.h b/rigs/yaesu/ftx1.h new file mode 100644 index 000000000..142d93b46 --- /dev/null +++ b/rigs/yaesu/ftx1.h @@ -0,0 +1,195 @@ +/* + * hamlib - (C) Frank Singleton 2000 (javabear at users.sourceforge.net) + * + * ftx1.h - (C) Jeremy Miller KO4SSD 2025 (ko4ssd at ko4ssd.com) + * + * This shared library provides an API for communicating + * via USB interface to an FTX-1 using the "CAT" interface + * + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + + +#ifndef _FTX1_H +#define _FTX1_H 1 + +#define FTX1_VFO_ALL (RIG_VFO_A|RIG_VFO_B|RIG_VFO_MEM) + +/* Receiver caps */ + +#define FTX1_ALL_RX_MODES (RIG_MODE_AM|RIG_MODE_CW|RIG_MODE_CWR|RIG_MODE_SSB|\ + RIG_MODE_RTTY|RIG_MODE_RTTYR|RIG_MODE_PKTLSB|RIG_MODE_PKTUSB|RIG_MODE_PKTFM|\ + RIG_MODE_C4FM|RIG_MODE_FM|RIG_MODE_AMN|RIG_MODE_FMN) +#define FTX1_SSB_CW_RX_MODES (RIG_MODE_CW|RIG_MODE_CWR|RIG_MODE_SSB|\ + RIG_MODE_RTTY|RIG_MODE_RTTYR|RIG_MODE_PKTLSB|RIG_MODE_PKTUSB) +#define FTX1_AM_RX_MODES (RIG_MODE_AM|RIG_MODE_AMN) +#define FTX1_FM_WIDE_RX_MODES (RIG_MODE_FM|RIG_MODE_PKTFM|RIG_MODE_C4FM) +#define FTX1_FM_RX_MODES (FTX1_FM_WIDE_RX_MODES|RIG_MODE_FMN) +#define FTX1_CW_RX_MODES (RIG_MODE_CW|RIG_MODE_CWR) +#define FTX1_RTTY_DATA_RX_MODES (RIG_MODE_RTTY|RIG_MODE_RTTYR|RIG_MODE_PKTUSB|RIG_MODE_PKTLSB) + +/* TRX caps */ + +#define FTX1_OTHER_TX_MODES (RIG_MODE_CW|RIG_MODE_USB|RIG_MODE_LSB|RIG_MODE_PKTUSB|RIG_MODE_PKTLSB|\ + RIG_MODE_FM|RIG_MODE_PKTFM|RIG_MODE_FMN) /* 100 W class */ +#define FTX1_AM_TX_MODES (RIG_MODE_AM|RIG_MODE_AMN) /* set 25W max */ + +#define FTX1_LEVELS (RIG_LEVEL_ATT|RIG_LEVEL_PREAMP|RIG_LEVEL_STRENGTH|\ + RIG_LEVEL_ALC|RIG_LEVEL_RAWSTR|RIG_LEVEL_STRENGTH|RIG_LEVEL_SWR|\ + RIG_LEVEL_RFPOWER|RIG_LEVEL_RF|RIG_LEVEL_SQL|\ + RIG_LEVEL_MICGAIN|RIG_LEVEL_IF|RIG_LEVEL_CWPITCH|\ + RIG_LEVEL_KEYSPD|RIG_LEVEL_AF|RIG_LEVEL_AGC|\ + RIG_LEVEL_METER|RIG_LEVEL_BKINDL|RIG_LEVEL_BKIN_DLYMS|RIG_LEVEL_SQL|\ + RIG_LEVEL_VOXGAIN|RIG_LEVEL_VOXDELAY|RIG_LEVEL_COMP|\ + RIG_LEVEL_ANTIVOX|RIG_LEVEL_NR|RIG_LEVEL_NB|RIG_LEVEL_NOTCHF|\ + RIG_LEVEL_MONITOR_GAIN|RIG_LEVEL_RFPOWER_METER|RIG_LEVEL_RFPOWER_METER_WATTS|\ + RIG_LEVEL_COMP_METER|RIG_LEVEL_VD_METER|RIG_LEVEL_ID_METER|\ + RIG_LEVEL_BAND_SELECT) + +#define FTX1_FUNCS (RIG_FUNC_TONE|RIG_FUNC_TSQL|RIG_FUNC_CSQL|RIG_FUNC_LOCK|\ + RIG_FUNC_MON|RIG_FUNC_NB|RIG_FUNC_NR|RIG_FUNC_VOX|\ + RIG_FUNC_FBKIN|RIG_FUNC_COMP|RIG_FUNC_ANF|RIG_FUNC_MN|\ + RIG_FUNC_RIT|RIG_FUNC_XIT|\ + RIG_FUNC_TUNER|RIG_FUNC_APF) + +#define FTX1_VFO_OPS (RIG_OP_TUNE|RIG_OP_CPY|RIG_OP_XCHG|\ + RIG_OP_UP|RIG_OP_DOWN|RIG_OP_BAND_UP|RIG_OP_BAND_DOWN|\ + RIG_OP_TO_VFO|RIG_OP_FROM_VFO) + +// Borrowed from FLRig -- Thanks to Dave W1HKJ +#define FTX1_RFPOWER_METER_CAL \ + { \ + 7, \ + { \ + {0, 0.0f}, \ + {10, 0.8f}, \ + {50, 8.0f}, \ + {100, 26.0f}, \ + {150, 54.0f}, \ + {200, 92.0f}, \ + {250, 140.0f}, \ + } \ + } + +/* TBC */ +#define FTX1_STR_CAL { 16, \ + { \ + { 0, -54 }, /* S0 */ \ + { 12, -48 }, /* S1 */ \ + { 27, -42 }, /* S2 */ \ + { 40, -36 }, /* S3 */ \ + { 55, -30 }, /* S4 */ \ + { 65, -24 }, /* S5 */ \ + { 80, -18 }, /* S6 */ \ + { 95, -12 }, /* S7 */ \ + { 112, -6 }, /* S8 */ \ + { 130, 0 }, /* S9 */ \ + { 150, 10 }, /* +10 */ \ + { 172, 20 }, /* +20 */ \ + { 190, 30 }, /* +30 */ \ + { 220, 40 }, /* +40 */ \ + { 240, 50 }, /* +50 */ \ + { 255, 60 }, /* +60 */ \ + } } + + +#define FTX1_ID_CAL { 7, \ + { \ + { 0, 0.0f }, \ + { 53, 5.0f }, \ + { 65, 6.0f }, \ + { 78, 7.0f }, \ + { 86, 8.0f }, \ + { 98, 9.0f }, \ + { 107, 10.0f } \ + } \ +} + +/* TBC */ +#define FTX1_VD_CAL { 2, \ + { \ + { 0, 0.0f }, \ + { 192, 13.8f }, \ + } \ +} + +#define FTX1_COMP_CAL { 9, \ + { \ + { 0, 0.0f }, \ + { 40, 2.5f }, \ + { 60, 5.0f }, \ + { 85, 7.5f }, \ + { 135, 10.0f }, \ + { 150, 12.5f }, \ + { 175, 15.0f }, \ + { 195, 17.5f }, \ + { 220, 20.0f } \ + } \ +} + +/* + * Other features (used by rig_caps) + * + */ + +// The FTX1 does not have antenna selection +#define FTX1_ANTS (RIG_ANT_CURR) + +#define FTX1_MEM_CHNL_LENGTH 1 /* 0x10 P1 = 01 return size */ +#define FTX1_OP_DATA_LENGTH 19 /* 0x10 P1 = 03 return size */ +#define FTX1_VFO_DATA_LENGTH 18 /* 0x10 P1 = 03 return size -- A & B returned */ +#define FTX1_MEM_CHNL_DATA_LENGTH 19 /* 0x10 P1 = 04, P4 = 0x01-0x20 return size */ +#define FTX1_STATUS_FLAGS_LENGTH 5 /* 0xf7, 0xfa return size */ +#define FTX1_ALL_DATA_LENGTH 649 /* 0x10 P1 = 00 return size */ + +/* Timing values in mS */ + +// #define FTX1_PACING_INTERVAL 5 +// #define FTX1_PACING_DEFAULT_VALUE 0 + +/* Delay between bytes sent to FTX-1 + * Should not exceed value set in CAT TOT menu (rig default is 10 mSec) + */ +#define FTX1_WRITE_DELAY 0 + + +/* Delay sequential fast writes */ + +#define FTX1_POST_WRITE_DELAY 2 + +typedef struct +{ + char command[2]; /* depends on command "IF", "MR", "MW" "OI" */ + char memory_ch[3]; /* 001 -> 117 */ + char vfo_freq[9]; /* 9 digit value in Hz */ + char clarifier[5]; /* '+' | '-', 0000 -> 9999 Hz */ + char rx_clarifier; /* '0' = off, '1' = on */ + char tx_clarifier; /* '0' = off, '1' = on */ + char mode; /* '1'=LSB, '2'=USB, '3'=CW, '4'=FM, '5'=AM, */ + /* '6'=RTTY-LSB, '7'=CW-R, '8'=DATA-LSB, */ + /* '9'=RTTY-USB,'A'=DATA-FM, 'B'=FM-N, */ + /* 'C'=DATA-USB, 'D'=AM-N, 'E'=C4FM */ + char vfo_memory; /* '0'=VFO, '1'=Memory, '2'=Memory Tune, */ + /* '3'=Quick Memory Bank, '4'=QMB-MT, '5'=PMS, '6'=HOME */ + char tone_mode; /* '0' = off, CTCSS '1' ENC, '2' ENC/DEC, */ + /* '3' = DCS ENC/DEC, '4' = ENC */ + char fixed[2]; /* Always '0', '0' */ + char repeater_offset; /* '0' = Simplex, '1' Plus, '2' minus */ + char terminator; /* ';' */ +} ftx1info; + +#endif /* _FTX1_H */ \ No newline at end of file diff --git a/rigs/yaesu/newcat.c b/rigs/yaesu/newcat.c index 82ed2caf7..30613bec1 100644 --- a/rigs/yaesu/newcat.c +++ b/rigs/yaesu/newcat.c @@ -71,6 +71,7 @@ typedef enum nc_rigid_e NC_RIGID_FTDX101D = 681, NC_RIGID_FTDX101MP = 682, NC_RIGID_FT710 = 800, + NC_RIGID_FTX1 = 840, } nc_rigid_t; @@ -95,6 +96,7 @@ typedef struct _yaesu_newcat_commands ncboolean ftdx10; ncboolean ft101mp; ncboolean ft710; + ncboolean ftx1; ncboolean ft9000Old; } yaesu_newcat_commands_t; @@ -225,6 +227,7 @@ static ncboolean is_ftdx3000dm; static ncboolean is_ftdx101d; static ncboolean is_ftdx101mp; static ncboolean is_ftdx10; +static ncboolean is_ftx1; static ncboolean is_ftdx9000Old; /* @@ -245,10 +248,10 @@ static ncboolean is_ftdx9000Old; */ static const yaesu_newcat_commands_t valid_commands[] = { - /* Command FT-450 FT-950 FT-891 FT-991 FT-2000 FT-9000 FT-5000 FT-1200 FT-3000 FTDX101D FTDX10 FTDX101MP FT710 FT9000Old*/ - {"AB", FALSE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE }, - {"AC", TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE }, - {"AG", TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE }, + /* Command FT-450 FT-950 FT-891 FT-991 FT-2000 FT-9000 FT-5000 FT-1200 FT-3000 FTDX101D FTDX10 FTDX101MP FT710 FTX1 FT9000Old*/ + {"AB", FALSE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE }, + {"AC", TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE }, + {"AG", TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE }, {"AI", TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE }, {"AM", FALSE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE }, {"AN", FALSE, TRUE, FALSE, FALSE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, TRUE, FALSE, TRUE }, @@ -519,6 +522,7 @@ int newcat_init(RIG *rig) is_ftdx101mp = newcat_is_rig(rig, RIG_MODEL_FTDX101MP); is_ftdx10 = newcat_is_rig(rig, RIG_MODEL_FTDX10); is_ft710 = newcat_is_rig(rig, RIG_MODEL_FT710); + is_ftx1 = newcat_is_rig(rig, RIG_MODEL_FTX1); RETURNFUNC(RIG_OK); } @@ -8167,7 +8171,7 @@ ncboolean newcat_valid_command(RIG *rig, char const *const command) if (!is_ft450 && !is_ft950 && !is_ft891 && !is_ft991 && !is_ft2000 && !is_ftdx5000 && !is_ftdx9000 && !is_ftdx1200 && !is_ftdx3000 && !is_ftdx101d - && !is_ftdx101mp && !is_ftdx10 && !is_ft710) + && !is_ftdx101mp && !is_ftdx10 && !is_ft710 && !is_ftx1) { rig_debug(RIG_DEBUG_ERR, "%s: '%s' is unknown\n", __func__, caps->model_name); RETURNFUNC2(FALSE); @@ -8258,6 +8262,10 @@ ncboolean newcat_valid_command(RIG *rig, char const *const command) { RETURNFUNC2(TRUE); } + else if (is_ftx1 && valid_commands[search_index].ftx1) + { + RETURNFUNC2(TRUE); + } else { rig_debug(RIG_DEBUG_TRACE, "%s: '%s' command '%s' not supported\n", diff --git a/rigs/yaesu/yaesu.c b/rigs/yaesu/yaesu.c index eb27487e0..ac9923ab6 100644 --- a/rigs/yaesu/yaesu.c +++ b/rigs/yaesu/yaesu.c @@ -112,6 +112,7 @@ DECLARE_INITRIG_BACKEND(yaesu) rig_register(&vx1700_caps); rig_register(&ftdx1200_caps); rig_register(&ft991_caps); + rig_register(&ftx1_caps); rig_register(&ft891_caps); rig_register(&ft847uni_caps); rig_register(&ftdx101d_caps); diff --git a/rigs/yaesu/yaesu.h b/rigs/yaesu/yaesu.h index 088943620..049e2f678 100644 --- a/rigs/yaesu/yaesu.h +++ b/rigs/yaesu/yaesu.h @@ -69,6 +69,7 @@ extern struct rig_caps ft980_caps; extern struct rig_caps ft990_caps; extern struct rig_caps ft990uni_caps; extern struct rig_caps ft991_caps; +extern struct rig_caps ftx1_caps; extern struct rig_caps ft1000mp_caps; extern struct rig_caps ft1000mpmkv_caps; extern struct rig_caps ft1000mpmkvfld_caps;