[Hamlib-commits] Hamlib -- Ham radio control libraries branch master updated. 79c812ff4db84d44eca74
Library to control radio transceivers and receivers
Brought to you by:
n0nb
From: n0nb <n0...@us...> - 2025-07-14 11:53:50
|
This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "Hamlib -- Ham radio control libraries". The branch, master has been updated via 79c812ff4db84d44eca7414aa4f2f5f81f7ce3e1 (commit) via 7ce9d60aa68af334bc680a42a28ca5194d71ecde (commit) via 69d203fd1c2e209cda74a000977cc0b7464dc43a (commit) from 0db57035d50880893305d45ef5adbd538f0c401e (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit 79c812ff4db84d44eca7414aa4f2f5f81f7ce3e1 Author: Nate Bargmann <n0...@n0...> Date: Mon Jul 14 06:51:44 2025 -0500 Update NEWS for FTX-1 new model support diff --git a/NEWS b/NEWS index fb2b8b565..9e32531fa 100644 --- a/NEWS +++ b/NEWS @@ -29,6 +29,7 @@ Version 4.7.0 additional support add clean up code. (TNX FVsonar). * New Drake R8 backend. (TNX Mark Fine) * New AF6SA WRC rotator backend. (TNX Michael Morgan) + * New Yaesu FTX-1 model support (alpha). (TNX Jeremy Miller). Version 4.6.3 * 2025-06-10 commit 7ce9d60aa68af334bc680a42a28ca5194d71ecde Merge: 0db57035d 69d203fd1 Author: Nate Bargmann <n0...@n0...> Date: Mon Jul 14 06:17:48 2025 -0500 Merge GitHub PR #1801 commit 69d203fd1c2e209cda74a000977cc0b7464dc43a Author: jeremybox <gi...@je...> Date: Fri Jul 11 01:42:24 2025 -0400 Add FTX-1 radio support to Hamlib - Add FTX-1 rig model (ID 840) to riglist.h - Create ftx1.c and ftx1.h with FTX-1 implementation - Add FTX-1 to Yaesu Makefile.am - Integrate FTX-1 into newcat.c command validation system - Update yaesu.c and yaesu.h for FTX-1 support - Based on FT-991A CAT protocol compatibility 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 <stdlib.h> +#include <string.h> +#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; ----------------------------------------------------------------------- Summary of changes: NEWS | 1 + include/hamlib/riglist.h | 1 + rigs/yaesu/Makefile.am | 3 +- rigs/yaesu/{ft991.c => ftx1.c} | 299 ++++++++++++++++++++--------------------- rigs/yaesu/{ft991.h => ftx1.h} | 75 +++++------ rigs/yaesu/newcat.c | 18 ++- rigs/yaesu/yaesu.c | 1 + rigs/yaesu/yaesu.h | 1 + 8 files changed, 204 insertions(+), 195 deletions(-) copy rigs/yaesu/{ft991.c => ftx1.c} (76%) copy rigs/yaesu/{ft991.h => ftx1.h} (69%) hooks/post-receive -- Hamlib -- Ham radio control libraries |