From 04af1b0553bcbdf451c1da8fd24460086a5d8918 Mon Sep 17 00:00:00 2001 From: Michael Black W9MDB Date: Tue, 1 May 2018 08:12:05 -0500 Subject: [PATCH 01/17] Add PKTAM PKTFM modes to ic7300 --- icom/ic7300.c | 18 +++++++++--------- include/hamlib/rig.h | 1 + 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/icom/ic7300.c b/icom/ic7300.c index 58f98519c..14ee59482 100644 --- a/icom/ic7300.c +++ b/icom/ic7300.c @@ -39,12 +39,12 @@ #include "tones.h" /* AM Data mode needs adding - this would require one more mode 'RIG_MODE_PKTAM' to rig.h */ -#define IC7300_ALL_RX_MODES (RIG_MODE_FM|RIG_MODE_AM|RIG_MODE_CW|RIG_MODE_CWR|RIG_MODE_SSB|RIG_MODE_RTTY|RIG_MODE_RTTYR|RIG_MODE_PKTLSB|RIG_MODE_PKTUSB) -#define IC7300_1HZ_TS_MODES (RIG_MODE_CW|RIG_MODE_CWR|RIG_MODE_SSB|RIG_MODE_RTTY|RIG_MODE_RTTYR|RIG_MODE_PKTLSB|RIG_MODE_PKTUSB) +#define IC7300_ALL_RX_MODES (RIG_MODE_FM|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_PKTAM) +#define IC7300_1HZ_TS_MODES (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_PKTAM) #define IC7300_NOT_TS_MODES (IC7300_ALL_RX_MODES &~IC7300_1HZ_TS_MODES) #define IC7300_OTHER_TX_MODES (RIG_MODE_FM|RIG_MODE_CW|RIG_MODE_CWR|RIG_MODE_SSB|RIG_MODE_RTTY|RIG_MODE_RTTYR) -#define IC7300_AM_TX_MODES (RIG_MODE_AM) +#define IC7300_AM_TX_MODES (RIG_MODE_AM|RIG_MODE_PKTAM) #define IC7300_FUNCS (RIG_FUNC_FAGC|RIG_FUNC_NB|RIG_FUNC_COMP|RIG_FUNC_VOX|RIG_FUNC_TONE|RIG_FUNC_TSQL|RIG_FUNC_SBKIN|RIG_FUNC_FBKIN|RIG_FUNC_NR|RIG_FUNC_MON|RIG_FUNC_MN|RIG_FUNC_ANF|RIG_FUNC_LOCK|RIG_FUNC_RIT|RIG_FUNC_XIT|RIG_FUNC_SCOPE) @@ -209,12 +209,12 @@ const struct rig_caps ic7300_caps = { {RIG_MODE_CW|RIG_MODE_CWR|RIG_MODE_RTTY|RIG_MODE_RTTYR, Hz(250)}, {RIG_MODE_CW|RIG_MODE_CWR, kHz(1.2)}, {RIG_MODE_RTTY|RIG_MODE_RTTYR, kHz(2.4)}, - {RIG_MODE_AM, kHz(6)}, - {RIG_MODE_AM, kHz(3)}, - {RIG_MODE_AM, kHz(9)}, - {RIG_MODE_FM, kHz(15)}, - {RIG_MODE_FM, kHz(10)}, - {RIG_MODE_FM, kHz(7)}, + {RIG_MODE_AM|RIG_MODE_PKTFM, kHz(6)}, + {RIG_MODE_AM|RIG_MODE_PKTFM, kHz(3)}, + {RIG_MODE_AM|RIG_MODE_PKTFM, kHz(9)}, + {RIG_MODE_FM|RIG_MODE_PKTFM, kHz(15)}, + {RIG_MODE_FM|RIG_MODE_PKTFM, kHz(10)}, + {RIG_MODE_FM|RIG_MODE_PKTFM, kHz(7)}, RIG_FLT_END, }, diff --git a/include/hamlib/rig.h b/include/hamlib/rig.h index 1c5b6c2e0..354ed7111 100644 --- a/include/hamlib/rig.h +++ b/include/hamlib/rig.h @@ -865,6 +865,7 @@ typedef enum { RIG_MODE_SAH = (1 << 18), /*!< \c SAH -- Synchronous AM upper (higher) sideband */ RIG_MODE_DSB = (1 << 19), /*!< \c DSB -- Double sideband suppressed carrier */ RIG_MODE_FMN = (1 << 21), /*!< \c FMN -- FM Narrow Kenwood ts990s */ + RIG_MODE_PKTAM = (1 << 22), /*!< \c PKTAM -- Packet/Digital AM mode e.g. IC7300 */ RIG_MODE_TESTS_MAX /*!< \c MUST ALWAYS BE LAST, Max Count for dumpcaps.c */ } rmode_t; From e970be435094c0a4870326b1051ca14b523917d2 Mon Sep 17 00:00:00 2001 From: "Brian G. Lucas" Date: Tue, 1 May 2018 14:41:15 -0500 Subject: [PATCH 02/17] Pretty much a complete re-write of thd72.c, since the old one didn't work at all. Many commands have been tested with real hardware. But more work remains to be done. --- kenwood/thd72.c | 667 +++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 541 insertions(+), 126 deletions(-) diff --git a/kenwood/thd72.c b/kenwood/thd72.c index b74f42802..167e2fba2 100644 --- a/kenwood/thd72.c +++ b/kenwood/thd72.c @@ -1,8 +1,7 @@ /* - * Hamlib Kenwood backend - TH-D72 description - * cloned after TH-D7 + * Hamlib Kenwood TH-D72 backend * Copyright (c) 2000-2011 by Stephane Fillod - * + * Copyright (c) 2018 by Brian Lucas * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -33,10 +32,11 @@ #include "num_stdio.h" #include "iofunc.h" #include "serial.h" +#include "misc.h" -#define THD72_MODES (RIG_MODE_FM|RIG_MODE_AM) -#define THD72_MODES_TX (RIG_MODE_FM) +#define THD72_MODES (RIG_MODE_FM|RIG_MODE_AM) +#define THD72_MODES_TX (RIG_MODE_FM) #define THD72_FUNC_ALL (RIG_FUNC_TSQL| \ RIG_FUNC_AIP| \ @@ -47,148 +47,446 @@ RIG_FUNC_LOCK| \ RIG_FUNC_ARO) -#define THD72_LEVEL_ALL (RIG_LEVEL_STRENGTH| \ - RIG_LEVEL_SQL| \ - RIG_LEVEL_AF| \ - RIG_LEVEL_RF|\ - RIG_LEVEL_MICGAIN) +#define THD72_LEVEL_ALL (RIG_LEVEL_RFPOWER|\ + RIG_LEVEL_VOXGAIN|\ + RIG_LEVEL_VOXDELAY) #define THD72_PARMS (RIG_PARM_BACKLIGHT) #define THD72_VFO_OP (RIG_OP_NONE) -/* - * TODO: Band A & B - */ #define THD72_VFO (RIG_VFO_A|RIG_VFO_B) -static rmode_t td72_mode_table[KENWOOD_MODE_TABLE_MAX] = { - [0] = RIG_MODE_FM, - [1] = RIG_MODE_AM, +static rmode_t thd72_mode_table[3] = { + [0] = RIG_MODE_WFM, + [1] = RIG_MODE_FM, + [2] = RIG_MODE_AM, +}; + +static pbwidth_t thd72_width_table[3] = { + [0] = 10000, // +-5KHz + [1] = 5000, // +-2.5KHz + [2] = 10000, // what should this be? +}; + +static rptr_shift_t thd72_rshf_table[3] = { + [0] = RIG_RPT_SHIFT_NONE, + [1] = RIG_RPT_SHIFT_PLUS, + [2] = RIG_RPT_SHIFT_MINUS, +} ; +static int thd72voxdelay[7] = { + [0] = 2500, + [1] = 5000, + [2] = 7500, + [3] = 10000, + [4] = 15000, + [5] = 20000, + [6] = 30000 }; static struct kenwood_priv_caps thd72_priv_caps = { .cmdtrm = EOM_TH, /* Command termination character */ - .mode_table = td72_mode_table, + .mode_table = thd72_mode_table, }; -static int thd72_open(RIG *rig); -static int thd72_get_chan_all_cb (RIG * rig, chan_cb_t chan_cb, rig_ptr_t arg); - - -/* - * th-d72a rig capabilities. - */ -const struct rig_caps thd72a_caps = { -.rig_model = RIG_MODEL_THD72A, -.model_name = "TH-D72A", -.mfg_name = "Kenwood", -.version = TH_VER ".1", -.copyright = "LGPL", -.status = RIG_STATUS_ALPHA, -.rig_type = RIG_TYPE_HANDHELD|RIG_FLAG_APRS|RIG_FLAG_TNC|RIG_FLAG_DXCLUSTER, -.ptt_type = RIG_PTT_RIG, -.dcd_type = RIG_DCD_RIG, -.port_type = RIG_PORT_SERIAL, -.serial_rate_min = 9600, -.serial_rate_max = 9600, -.serial_data_bits = 8, -.serial_stop_bits = 1, -.serial_parity = RIG_PARITY_NONE, -.serial_handshake = RIG_HANDSHAKE_XONXOFF, -.write_delay = 0, -.post_write_delay = 0, -.timeout = 250, -.retry = 3, - -.has_get_func = THD72_FUNC_ALL, -.has_set_func = THD72_FUNC_ALL, -.has_get_level = THD72_LEVEL_ALL, -.has_set_level = RIG_LEVEL_SET(THD72_LEVEL_ALL), -.has_get_parm = THD72_PARMS, -.has_set_parm = THD72_PARMS, /* FIXME: parms */ -.level_gran = { - [LVL_RAWSTR] = { .min = { .i = 0 }, .max = { .i = 5 } }, - [LVL_SQL] = { .min = { .i = 0 }, .max = { .i = 5 } }, - [LVL_RFPOWER] = { .min = { .i = 3 }, .max = { .i = 0 } }, -}, -.parm_gran = {}, -.ctcss_list = kenwood38_ctcss_list, -.dcs_list = NULL, -.preamp = { RIG_DBLST_END, }, -.attenuator = { RIG_DBLST_END, }, -.max_rit = Hz(0), -.max_xit = Hz(0), -.max_ifshift = Hz(0), -.vfo_ops = THD72_VFO_OP, -.targetable_vfo = RIG_TARGETABLE_FREQ, -.transceive = RIG_TRN_RIG, -.bank_qty = 0, -.chan_desc_sz = 6, /* TBC */ - -.chan_list = { - { 0, 999, RIG_MTYPE_MEM , {TH_CHANNEL_CAPS}}, /* TBC MEM */ - RIG_CHAN_END, - }, - -.rx_range_list1 = { RIG_FRNG_END, }, /* FIXME: enter region 1 setting */ -.tx_range_list1 = { RIG_FRNG_END, }, -.rx_range_list2 = { - {MHz(118),MHz(174),THD72_MODES,-1,-1,THD72_VFO}, - {MHz(320),MHz(524),THD72_MODES,-1,-1,THD72_VFO}, - RIG_FRNG_END, - }, /* rx range */ -.tx_range_list2 = { - {MHz(144),MHz(148),THD72_MODES_TX,W(0.05),W(5),THD72_VFO}, - {MHz(430),MHz(440),THD72_MODES_TX,W(0.05),W(5),THD72_VFO}, - RIG_FRNG_END, - }, /* tx range */ - -.tuning_steps = { - {THD72_MODES,kHz(5)}, - {THD72_MODES,kHz(6.25)}, - /* kHz(8.33) ?? */ - {THD72_MODES,kHz(10)}, - {THD72_MODES,kHz(12.5)}, - {THD72_MODES,kHz(15)}, - {THD72_MODES,kHz(20)}, - {THD72_MODES,kHz(25)}, - {THD72_MODES,kHz(30)}, - {THD72_MODES,kHz(50)}, - {THD72_MODES,kHz(100)}, - RIG_TS_END, - }, - /* mode/filter list, remember: order matters! */ -.filters = { - {RIG_MODE_FM, kHz(14)}, - {RIG_MODE_AM, kHz(9)}, - RIG_FLT_END, - }, -.priv = (void *)&thd72_priv_caps, - -.rig_init = kenwood_init, -.rig_cleanup = kenwood_cleanup, -.rig_open = thd72_open, -.set_vfo = th_set_vfo, -.get_vfo = th_get_vfo, - -.get_chan_all_cb = thd72_get_chan_all_cb, - -.get_info = th_get_info, - -}; int thd72_open(RIG *rig) { int ret; + struct kenwood_priv_data *priv = rig->state.priv; + strcpy (priv->verify_cmd, "ID\r"); - kenwood_transaction(rig, "", NULL, 0); + ret = kenwood_transaction(rig, "", NULL, 0); - ret = kenwood_transaction(rig, "TC1", NULL, 0); - if (ret != RIG_OK) - return ret; + return ret; +} +static int thd72_set_vfo(RIG *rig, vfo_t vfo) +{ + const char *cmd; + + rig_debug(RIG_DEBUG_TRACE, "%s: called\n", __func__); + + switch (vfo) { + case RIG_VFO_A: + case RIG_VFO_VFO: + case RIG_VFO_MAIN: + cmd = "BC 0"; + break; + + case RIG_VFO_B: + cmd = "BC 1"; + break; + default: + rig_debug(RIG_DEBUG_ERR, "%s: Unsupported VFO: %d\n", __func__, vfo); + return -RIG_ENTARGET; + } + return kenwood_simple_transaction(rig, cmd, 4); +} + +static int thd72_get_vfo(RIG *rig, vfo_t *vfo) +{ + int retval; + char buf[10], vfoc; + + rig_debug(RIG_DEBUG_TRACE, "%s: called\n", __func__); + + retval = kenwood_transaction(rig, "BC", buf, sizeof (buf)); + if (retval != RIG_OK) + return retval; + size_t length = strlen (buf); + if (length == 4) { + vfoc = buf[3]; + } else { + rig_debug(RIG_DEBUG_ERR, "%s: Unexpected answer length '%c'\n", __func__, length); + return -RIG_EPROTO; + } + switch (vfoc) { + case '0': *vfo = RIG_VFO_A; break; + case '1': *vfo = RIG_VFO_B; break; + default: + rig_debug(RIG_DEBUG_ERR, "%s: Unsupported VFO: %d\n", __func__, vfo); + return -RIG_EVFO; + } + return RIG_OK; +} + +static int thd72_vfoc(RIG *rig, vfo_t vfo, char *vfoc) +{ + vfo = (vfo == RIG_VFO_CURR) ? rig->state.current_vfo : vfo; + switch (vfo) { + case RIG_VFO_A: *vfoc = '0'; break; + case RIG_VFO_B: *vfoc = '1'; break; + default: + rig_debug(RIG_DEBUG_ERR, "%s: Unsupported VFO: %d\n", __func__, vfo); + return -RIG_ENTARGET; + } + return RIG_OK; +} + +static int thd72_get_freq_info(RIG *rig, vfo_t vfo, char *buf) +{ + int retval, length; + char vfoc, cmd[8]; + + retval = thd72_vfoc(rig, vfo, &vfoc); + if (retval != RIG_OK) + return retval; + sprintf(cmd, "FO %c", vfoc); + retval = kenwood_transaction(rig, cmd, buf, 53); + length = strlen(buf); + rig_debug(RIG_DEBUG_TRACE, "%s: length=%d\n", __func__, length); + return RIG_OK; +} + +static int thd72_set_freq(RIG *rig, vfo_t vfo, freq_t freq) +{ + int retval; + char buf[64], fbuf[11]; + + rig_debug(RIG_DEBUG_TRACE, "%s: called\n", __func__); + + retval = thd72_get_freq_info(rig, vfo, buf); + if (retval == RIG_OK) { + sprintf(fbuf, "%010ld", (int64_t)freq); + memcpy(buf+5, fbuf, 10); + retval = kenwood_simple_transaction(rig, buf, 52); + } + return retval; +} + +static int thd72_get_freq(RIG *rig, vfo_t vfo, freq_t *freq) +{ + int retval; + char buf[64]; + + rig_debug(RIG_DEBUG_TRACE, "%s: called\n", __func__); + + retval = thd72_get_freq_info(rig, vfo, buf); + if (retval == RIG_OK) + sscanf(buf+5, "%"SCNfreq, freq); + return retval; +} + +static int thd72_set_mode(RIG *rig, vfo_t vfo, rmode_t mode, pbwidth_t width) +{ + int retval; + char modec, buf[64]; + + rig_debug(RIG_DEBUG_TRACE, "%s: called\n", __func__); + + retval = thd72_get_freq_info(rig, vfo, buf); + if (retval == RIG_OK) { + switch (mode) { + case RIG_MODE_WFM: modec = '0'; break; + case RIG_MODE_FM: modec = '1'; break; + case RIG_MODE_AM: modec = '2'; break; + default: + return -RIG_EINVAL; + } + buf[51] = modec; + retval = kenwood_simple_transaction(rig, buf, 52); + } + return retval; +} + +static int thd72_get_mode(RIG *rig, vfo_t vfo, rmode_t *mode, pbwidth_t *width) +{ + int retval; + char modec, buf[64]; + + rig_debug(RIG_DEBUG_TRACE, "%s: called\n", __func__); + + retval = thd72_get_freq_info(rig, vfo, buf); + if (retval == RIG_OK) { + modec = buf[51]; + if (modec >= '0' && modec <= '2') { + *mode = thd72_mode_table[modec - '0']; + *width = thd72_width_table[modec - '0']; + } + else + return -RIG_EINVAL; + } + return retval; +} + +static int thd72_set_rptr_shft(RIG *rig, vfo_t vfo, rptr_shift_t rptr_shift) +{ + int retval; + char shftc, buf[64]; + + rig_debug(RIG_DEBUG_TRACE, "%s: called\n", __func__); + + retval = thd72_get_freq_info(rig, vfo, buf); + if (retval == RIG_OK) { + switch (rptr_shift) { + case RIG_RPT_SHIFT_NONE: shftc = '0'; break; + case RIG_RPT_SHIFT_PLUS: shftc = '1'; break; + case RIG_RPT_SHIFT_MINUS: shftc = '1'; break; + default: + return -RIG_EINVAL; + } + buf[18] = shftc; + retval = kenwood_simple_transaction(rig, buf, 52); + } + return retval; +} + +static int thd72_get_rptr_shft(RIG *rig, vfo_t vfo, rptr_shift_t *rptr_shift) +{ + int retval; + char shftc, buf[64]; + + rig_debug(RIG_DEBUG_TRACE, "%s: called\n", __func__); + + retval = thd72_get_freq_info(rig, vfo, buf); + if (retval == RIG_OK) { + shftc = buf[18]; + if (shftc >= '0' && shftc <= '2') { + *rptr_shift = thd72_rshf_table[shftc - '0']; + } + else + return -RIG_EINVAL; + } + return retval; +} + + +static int thd72_set_rptr_offs(RIG *rig, vfo_t vfo, shortfreq_t offs) +{ + int retval; + char boff[9], buf[64]; + + rig_debug(RIG_DEBUG_TRACE, "%s: called\n", __func__); + + retval = thd72_get_freq_info(rig, vfo, buf); + if (retval == RIG_OK) { + sprintf(boff, "%08ld", offs); + memcpy(buf+42, boff, 8); + retval = kenwood_simple_transaction(rig, buf, 52); + } + return retval; +} + +static int thd72_get_rptr_offs(RIG *rig, vfo_t vfo, shortfreq_t *offs) +{ + int retval; + char buf[64]; + + rig_debug(RIG_DEBUG_TRACE, "%s: called\n", __func__); + + retval = thd72_get_freq_info(rig, vfo, buf); + if (retval == RIG_OK) + sscanf(buf+42, "%ld", offs); + return retval; +} + +static int thd72_set_ctcss_tone(RIG *rig, vfo_t vfo, tone_t tone) +{ + int retval; + + retval = -RIG_EINVAL; /** TEMP **/ + return retval; +} + +static int thd72_get_ctcss_tone(RIG *rig, vfo_t vfo, tone_t *tone) +{ + int retval; + int tinx; + char buf[64]; + + rig_debug(RIG_DEBUG_TRACE, "%s: called\n", __func__); + + retval = thd72_get_freq_info(rig, vfo, buf); + if (retval == RIG_OK) { + if (buf[22] == '0') /* no tone */ + *tone = 0; + else { + sscanf(buf+30, "%d", &tinx); + if (tinx >= 0 && tinx <= 41) + *tone = kenwood42_ctcss_list[tinx]; + else + return -RIG_EINVAL; + } + } + return retval; +} + +static int thd72_get_menu_info(RIG *rig, char *buf) +{ + int retval; + + rig_debug(RIG_DEBUG_TRACE, "%s: called\n", __func__); + + retval = kenwood_transaction(rig, "MU", buf, 41); + if (retval != RIG_OK) + return retval; + if (strlen(buf) != 40) + return -RIG_ERJCTED; + return RIG_OK; +} + +static int thd72_set_level(RIG *rig, vfo_t vfo, setting_t level, value_t val) +{ + int retval; + char vfoc, lvlc, cmd[10], buf[48]; + + rig_debug(RIG_DEBUG_TRACE, "%s: called\n", __func__); + + retval = thd72_vfoc(rig, vfo, &vfoc); + if (retval != RIG_OK) + return retval; + switch (level) { + case RIG_LEVEL_RFPOWER: + if (val.f <= 0.01) lvlc = '2'; + else if (val.f <= 0.10) lvlc = '1'; + else lvlc = '0'; + sprintf(cmd, "PC %c,%c", vfoc, lvlc); + return kenwood_simple_transaction(rig, cmd, 6); + case RIG_LEVEL_VOXGAIN: + retval = thd72_get_menu_info(rig, buf); + if (retval != RIG_OK) + return retval; + buf[19] = '0' + (int)(val.f*10.0 - 0.5); + return kenwood_simple_transaction(rig, buf, 40); + case RIG_LEVEL_VOXDELAY: + retval = thd72_get_menu_info(rig, buf); + if (retval != RIG_OK) + return retval; + break; + default: + rig_debug(RIG_DEBUG_ERR, "%s: Unsupported Level %d\n", __func__, level); + return -RIG_EINVAL; + } + return retval; +} + +static int thd72_get_level(RIG *rig, vfo_t vfo, setting_t level, value_t *val) +{ + int retval, v, l; + char vfoc, cmd[10], buf[48]; + + rig_debug(RIG_DEBUG_TRACE, "%s: called\n", __func__); + + retval = thd72_vfoc(rig, vfo, &vfoc); + if (retval != RIG_OK) + return retval; + switch (level) { + case RIG_LEVEL_RFPOWER: + sprintf(cmd, "PC %c", vfoc); + retval = kenwood_transaction(rig, cmd, buf, sizeof (buf)); + if (retval != RIG_OK) + return retval; + retval = sscanf(buf, "PC %d,%d", &v, &l); + if (retval != 2 || l < 0 || l > 3) { + rig_debug(RIG_DEBUG_ERR, "%s: Unexpected reply '%s'\n", __func__, buf); + return -RIG_ERJCTED; + } + switch (l) { + case 0: val->f = 1.00; break; /* 5.0 W */ + case 1: val->f = 0.10; break; /* 500 mW */ + case 2: val->f = 0.01; break; /* 50 mW */ + } + break; + case RIG_LEVEL_VOXGAIN: + retval = thd72_get_menu_info(rig, buf); + if (retval != RIG_OK) + return retval; + /* FIXME - if VOX is off, what do we return */ + vfoc = buf[19]; + if (vfoc >= '0' && vfoc <= '9') + val->f = (vfoc - '0') / 9.0; + else { + rig_debug(RIG_DEBUG_ERR, "%s: Unexpected reply '%s'\n", __func__, buf); + return -RIG_ERJCTED; + } + break; + case RIG_LEVEL_VOXDELAY: + retval = thd72_get_menu_info(rig, buf); + if (retval != RIG_OK) + return retval; + /* FIXME - if VOX is off, what do we return */ + vfoc = buf[21]; + if (vfoc >= '0' && vfoc <= '7') + val->i = thd72voxdelay[vfoc-'0']; + else { + rig_debug(RIG_DEBUG_ERR, "%s: Unexpected reply '%s'\n", __func__, buf); + return -RIG_ERJCTED; + } + break; + default: + rig_debug(RIG_DEBUG_ERR, "%s: Unsupported Level %d\n", __func__, level); + return -RIG_EINVAL; + } + return RIG_OK; +} + +static int thd72_set_func(RIG *rig, vfo_t vfo, setting_t func, int status) +{ + return -RIG_EINVAL; +} + +static int thd72_get_func(RIG *rig, vfo_t vfo, setting_t func, int *status) +{ + int retval; + char vfoc, buf[48]; + + switch (func) { + case RIG_FUNC_AIP: + retval = thd72_vfoc(rig, vfo, &vfoc); + if (retval != RIG_OK) + return retval; + retval = thd72_get_menu_info(rig, buf); + if (retval != RIG_OK) + return retval; + if (vfoc == '0') vfoc = buf[13]; /* VHF AIP */ + else vfoc = buf[15]; /* UHF AIP */ + *status = vfoc - '0'; + break; + default: + return -RIG_EINVAL; + } return RIG_OK; } @@ -343,3 +641,120 @@ int thd72_get_chan_all_cb (RIG * rig, chan_cb_t chan_cb, rig_ptr_t arg) return RIG_OK; } +/* + * th-d72a rig capabilities. + */ +const struct rig_caps thd72a_caps = { +.rig_model = RIG_MODEL_THD72A, +.model_name = "TH-D72A", +.mfg_name = "Kenwood", +.version = TH_VER ".1", +.copyright = "LGPL", +.status = RIG_STATUS_ALPHA, +.rig_type = RIG_TYPE_HANDHELD|RIG_FLAG_APRS|RIG_FLAG_TNC|RIG_FLAG_DXCLUSTER, +.ptt_type = RIG_PTT_RIG, +.dcd_type = RIG_DCD_RIG, +.port_type = RIG_PORT_SERIAL, +.serial_rate_min = 9600, +.serial_rate_max = 9600, +.serial_data_bits = 8, +.serial_stop_bits = 1, +.serial_parity = RIG_PARITY_NONE, +.serial_handshake = RIG_HANDSHAKE_XONXOFF, +.write_delay = 0, +.post_write_delay = 0, +.timeout = 250, +.retry = 3, + +.has_get_func = THD72_FUNC_ALL, +.has_set_func = THD72_FUNC_ALL, +.has_get_level = THD72_LEVEL_ALL, +.has_set_level = RIG_LEVEL_SET(THD72_LEVEL_ALL), +.has_get_parm = THD72_PARMS, +.has_set_parm = THD72_PARMS, /* FIXME: parms */ +.level_gran = { + [LVL_RAWSTR] = { .min = { .i = 0 }, .max = { .i = 5 } }, + [LVL_SQL] = { .min = { .i = 0 }, .max = { .i = 5 } }, + [LVL_RFPOWER] = { .min = { .i = 2 }, .max = { .i = 0 } }, +}, +.parm_gran = {}, +.ctcss_list = kenwood38_ctcss_list, +.dcs_list = NULL, +.preamp = { RIG_DBLST_END, }, +.attenuator = { RIG_DBLST_END, }, +.max_rit = Hz(0), +.max_xit = Hz(0), +.max_ifshift = Hz(0), +.vfo_ops = THD72_VFO_OP, +.targetable_vfo = RIG_TARGETABLE_FREQ, +.transceive = RIG_TRN_RIG, +.bank_qty = 0, +.chan_desc_sz = 6, /* TBC */ + +.chan_list = { + { 0, 999, RIG_MTYPE_MEM , {TH_CHANNEL_CAPS}}, /* TBC MEM */ + RIG_CHAN_END, + }, + +.rx_range_list1 = { RIG_FRNG_END, }, /* FIXME: enter region 1 setting */ +.tx_range_list1 = { RIG_FRNG_END, }, +.rx_range_list2 = { + {MHz(118),MHz(174),THD72_MODES,-1,-1,THD72_VFO}, + {MHz(320),MHz(524),THD72_MODES,-1,-1,THD72_VFO}, + RIG_FRNG_END, + }, /* rx range */ +.tx_range_list2 = { + {MHz(144),MHz(148),THD72_MODES_TX,W(0.05),W(5),THD72_VFO}, + {MHz(430),MHz(440),THD72_MODES_TX,W(0.05),W(5),THD72_VFO}, + RIG_FRNG_END, + }, /* tx range */ + +.tuning_steps = { + {THD72_MODES,kHz(5)}, + {THD72_MODES,kHz(6.25)}, + /* kHz(8.33) ?? */ + {THD72_MODES,kHz(10)}, + {THD72_MODES,kHz(12.5)}, + {THD72_MODES,kHz(15)}, + {THD72_MODES,kHz(20)}, + {THD72_MODES,kHz(25)}, + {THD72_MODES,kHz(30)}, + {THD72_MODES,kHz(50)}, + {THD72_MODES,kHz(100)}, + RIG_TS_END, + }, + /* mode/filter list, remember: order matters! */ +.filters = { + {RIG_MODE_FM, kHz(14)}, + {RIG_MODE_AM, kHz(9)}, + RIG_FLT_END, + }, +.priv = (void *)&thd72_priv_caps, + +.rig_init = kenwood_init, +.rig_cleanup = kenwood_cleanup, +.rig_open = thd72_open, +.set_freq = thd72_set_freq, +.get_freq = thd72_get_freq, +.set_mode = thd72_set_mode, +.get_mode = thd72_get_mode, +.set_vfo = thd72_set_vfo, +.get_vfo = thd72_get_vfo, +.set_rptr_shift = thd72_set_rptr_shft, +.get_rptr_shift = thd72_get_rptr_shft, +.set_rptr_offs = thd72_set_rptr_offs, +.get_rptr_offs = thd72_get_rptr_offs, +.set_ctcss_tone = thd72_set_ctcss_tone, +.get_ctcss_tone = thd72_get_ctcss_tone, +// set/get dcs_code +//.set_ctcss_sql = th_set_ctcss_sql, +//.get_ctcss_sql = th_get_ctcss_sql, +.set_level = thd72_set_level, +.get_level = thd72_get_level, +.set_func = thd72_set_func, +.get_func = thd72_get_func, +.get_chan_all_cb = thd72_get_chan_all_cb, + +.get_info = th_get_info, + +}; From 84f9bfcfcf0c97ec7d889035d58b74a73e5b632e Mon Sep 17 00:00:00 2001 From: "Brian G. Lucas" Date: Wed, 2 May 2018 15:12:19 -0500 Subject: [PATCH 03/17] WIP: thd72 driver. More level, func, and parm stuff works. --- kenwood/thd72.c | 279 ++++++++++++++++++++++++++++++++++++------------ 1 file changed, 208 insertions(+), 71 deletions(-) diff --git a/kenwood/thd72.c b/kenwood/thd72.c index 167e2fba2..8ce01444b 100644 --- a/kenwood/thd72.c +++ b/kenwood/thd72.c @@ -35,8 +35,8 @@ #include "misc.h" -#define THD72_MODES (RIG_MODE_FM|RIG_MODE_AM) -#define THD72_MODES_TX (RIG_MODE_FM) +#define THD72_MODES (RIG_MODE_FM|RIG_MODE_FMN|RIG_MODE_AM) +#define THD72_MODES_TX (RIG_MODE_FM|RIG_MODE_FMN) #define THD72_FUNC_ALL (RIG_FUNC_TSQL| \ RIG_FUNC_AIP| \ @@ -48,18 +48,21 @@ RIG_FUNC_ARO) #define THD72_LEVEL_ALL (RIG_LEVEL_RFPOWER|\ + RIG_LEVEL_SQL|\ + RIG_LEVEL_BALANCE|\ RIG_LEVEL_VOXGAIN|\ RIG_LEVEL_VOXDELAY) -#define THD72_PARMS (RIG_PARM_BACKLIGHT) +#define THD72_PARMS (RIG_PARM_APO|\ + RIG_PARM_TIME) #define THD72_VFO_OP (RIG_OP_NONE) #define THD72_VFO (RIG_VFO_A|RIG_VFO_B) static rmode_t thd72_mode_table[3] = { - [0] = RIG_MODE_WFM, - [1] = RIG_MODE_FM, + [0] = RIG_MODE_FM, /* normal, but narrow compared to broadcast */ + [1] = RIG_MODE_FMN, /* what kenwood calls narrow */ [2] = RIG_MODE_AM, }; @@ -84,7 +87,23 @@ static int thd72voxdelay[7] = { [6] = 30000 }; -static struct kenwood_priv_caps thd72_priv_caps = { +static float thd72sqlevel[6] = { + [0] = 0.0, /* open */ + [1] = 0.2, + [2] = 0.4, + [3] = 0.6, + [4] = 0.8, + [5] = 1.0 +}; + +static int thd72apo[4] = { + [0] = 0, + [1] = 15, + [2] = 30, + [3] = 60 +}; + +static struct kenwood_priv_caps thd72_priv_caps = { .cmdtrm = EOM_TH, /* Command termination character */ .mode_table = thd72_mode_table, }; @@ -188,11 +207,11 @@ static int thd72_set_freq(RIG *rig, vfo_t vfo, freq_t freq) rig_debug(RIG_DEBUG_TRACE, "%s: called\n", __func__); retval = thd72_get_freq_info(rig, vfo, buf); - if (retval == RIG_OK) { - sprintf(fbuf, "%010ld", (int64_t)freq); - memcpy(buf+5, fbuf, 10); - retval = kenwood_simple_transaction(rig, buf, 52); - } + if (retval != RIG_OK) + return retval; + sprintf(fbuf, "%010ld", (int64_t)freq); + memcpy(buf+5, fbuf, 10); + retval = kenwood_simple_transaction(rig, buf, 52); return retval; } @@ -204,9 +223,10 @@ static int thd72_get_freq(RIG *rig, vfo_t vfo, freq_t *freq) rig_debug(RIG_DEBUG_TRACE, "%s: called\n", __func__); retval = thd72_get_freq_info(rig, vfo, buf); - if (retval == RIG_OK) - sscanf(buf+5, "%"SCNfreq, freq); - return retval; + if (retval != RIG_OK) + return retval; + sscanf(buf+5, "%"SCNfreq, freq); + return RIG_OK; } static int thd72_set_mode(RIG *rig, vfo_t vfo, rmode_t mode, pbwidth_t width) @@ -217,17 +237,17 @@ static int thd72_set_mode(RIG *rig, vfo_t vfo, rmode_t mode, pbwidth_t width) rig_debug(RIG_DEBUG_TRACE, "%s: called\n", __func__); retval = thd72_get_freq_info(rig, vfo, buf); - if (retval == RIG_OK) { - switch (mode) { - case RIG_MODE_WFM: modec = '0'; break; - case RIG_MODE_FM: modec = '1'; break; - case RIG_MODE_AM: modec = '2'; break; - default: - return -RIG_EINVAL; - } - buf[51] = modec; - retval = kenwood_simple_transaction(rig, buf, 52); + if (retval != RIG_OK) + return retval; + switch (mode) { + case RIG_MODE_FM: modec = '0'; break; + case RIG_MODE_FMN: modec = '1'; break; + case RIG_MODE_AM: modec = '2'; break; + default: + return -RIG_EINVAL; } + buf[51] = modec; + retval = kenwood_simple_transaction(rig, buf, 52); return retval; } @@ -239,16 +259,16 @@ static int thd72_get_mode(RIG *rig, vfo_t vfo, rmode_t *mode, pbwidth_t *width) rig_debug(RIG_DEBUG_TRACE, "%s: called\n", __func__); retval = thd72_get_freq_info(rig, vfo, buf); - if (retval == RIG_OK) { - modec = buf[51]; - if (modec >= '0' && modec <= '2') { - *mode = thd72_mode_table[modec - '0']; - *width = thd72_width_table[modec - '0']; - } - else - return -RIG_EINVAL; + if (retval != RIG_OK) + return retval; + modec = buf[51]; + if (modec >= '0' && modec <= '2') { + *mode = thd72_mode_table[modec - '0']; + *width = thd72_width_table[modec - '0']; } - return retval; + else + return -RIG_EINVAL; + return RIG_OK; } static int thd72_set_rptr_shft(RIG *rig, vfo_t vfo, rptr_shift_t rptr_shift) @@ -259,17 +279,17 @@ static int thd72_set_rptr_shft(RIG *rig, vfo_t vfo, rptr_shift_t rptr_shift) rig_debug(RIG_DEBUG_TRACE, "%s: called\n", __func__); retval = thd72_get_freq_info(rig, vfo, buf); - if (retval == RIG_OK) { - switch (rptr_shift) { - case RIG_RPT_SHIFT_NONE: shftc = '0'; break; - case RIG_RPT_SHIFT_PLUS: shftc = '1'; break; - case RIG_RPT_SHIFT_MINUS: shftc = '1'; break; - default: - return -RIG_EINVAL; - } - buf[18] = shftc; - retval = kenwood_simple_transaction(rig, buf, 52); + if (retval != RIG_OK) + return retval; + switch (rptr_shift) { + case RIG_RPT_SHIFT_NONE: shftc = '0'; break; + case RIG_RPT_SHIFT_PLUS: shftc = '1'; break; + case RIG_RPT_SHIFT_MINUS: shftc = '1'; break; + default: + return -RIG_EINVAL; } + buf[18] = shftc; + retval = kenwood_simple_transaction(rig, buf, 52); return retval; } @@ -281,14 +301,13 @@ static int thd72_get_rptr_shft(RIG *rig, vfo_t vfo, rptr_shift_t *rptr_shift) rig_debug(RIG_DEBUG_TRACE, "%s: called\n", __func__); retval = thd72_get_freq_info(rig, vfo, buf); - if (retval == RIG_OK) { - shftc = buf[18]; - if (shftc >= '0' && shftc <= '2') { - *rptr_shift = thd72_rshf_table[shftc - '0']; - } - else - return -RIG_EINVAL; - } + if (retval != RIG_OK) + return retval; + shftc = buf[18]; + if (shftc >= '0' && shftc <= '2') + *rptr_shift = thd72_rshf_table[shftc - '0']; + else + return -RIG_EINVAL; return retval; } @@ -301,11 +320,11 @@ static int thd72_set_rptr_offs(RIG *rig, vfo_t vfo, shortfreq_t offs) rig_debug(RIG_DEBUG_TRACE, "%s: called\n", __func__); retval = thd72_get_freq_info(rig, vfo, buf); - if (retval == RIG_OK) { - sprintf(boff, "%08ld", offs); - memcpy(buf+42, boff, 8); - retval = kenwood_simple_transaction(rig, buf, 52); - } + if (retval != RIG_OK) + return retval; + sprintf(boff, "%08ld", offs); + memcpy(buf+42, boff, 8); + retval = kenwood_simple_transaction(rig, buf, 52); return retval; } @@ -317,9 +336,10 @@ static int thd72_get_rptr_offs(RIG *rig, vfo_t vfo, shortfreq_t *offs) rig_debug(RIG_DEBUG_TRACE, "%s: called\n", __func__); retval = thd72_get_freq_info(rig, vfo, buf); - if (retval == RIG_OK) - sscanf(buf+42, "%ld", offs); - return retval; + if (retval != RIG_OK) + return retval; + sscanf(buf+42, "%ld", offs); + return RIG_OK; } static int thd72_set_ctcss_tone(RIG *rig, vfo_t vfo, tone_t tone) @@ -339,18 +359,18 @@ static int thd72_get_ctcss_tone(RIG *rig, vfo_t vfo, tone_t *tone) rig_debug(RIG_DEBUG_TRACE, "%s: called\n", __func__); retval = thd72_get_freq_info(rig, vfo, buf); - if (retval == RIG_OK) { - if (buf[22] == '0') /* no tone */ - *tone = 0; - else { - sscanf(buf+30, "%d", &tinx); - if (tinx >= 0 && tinx <= 41) - *tone = kenwood42_ctcss_list[tinx]; - else - return -RIG_EINVAL; - } + if (retval != RIG_OK) + return retval; + if (buf[22] == '0') /* no tone */ + *tone = 0; + else { + sscanf(buf+30, "%d", &tinx); + if (tinx >= 0 && tinx <= 41) + *tone = kenwood42_ctcss_list[tinx]; + else + return -RIG_EINVAL; } - return retval; + return RIG_OK; } static int thd72_get_menu_info(RIG *rig, char *buf) @@ -394,7 +414,17 @@ static int thd72_set_level(RIG *rig, vfo_t vfo, setting_t level, value_t val) retval = thd72_get_menu_info(rig, buf); if (retval != RIG_OK) return retval; - break; + return kenwood_simple_transaction(rig, buf, 40); + case RIG_LEVEL_SQL: + lvlc = '0' + (int)(val.f*5); + sprintf(cmd, "PC %c,%c", vfoc, lvlc; + return kenwood_simple_transaction(rig, cmd, 6); + case RIG_LEVEL_BALANCE: + retval = thd72_get_menu_info(rig, buf); + if (retval != RIG_OK) + return retval; + /* FIXME - is balance 0.0 .. 1.0 or -1.0 .. 1.0? */ + return kenwood_simple_transaction(rig, buf, 40); default: rig_debug(RIG_DEBUG_ERR, "%s: Unsupported Level %d\n", __func__, level); return -RIG_EINVAL; @@ -455,6 +485,31 @@ static int thd72_get_level(RIG *rig, vfo_t vfo, setting_t level, value_t *val) return -RIG_ERJCTED; } break; + case RIG_LEVEL_SQL: + sprintf(cmd, "SQ %c", vfoc); + retval = kenwood_transaction(rig, cmd, buf, sizeof (buf)); + if (retval != RIG_OK) + return retval; + retval = sscanf(buf, "SQ %d,%d", &v, &l); + if (retval != 2 || l < 0 || l > 6) { + rig_debug(RIG_DEBUG_ERR, "%s: Unexpected reply '%s'\n", __func__, buf); + return -RIG_ERJCTED; + } + val->f = thd72sqlevel[l]; + break; + case RIG_LEVEL_BALANCE: + retval = thd72_get_menu_info(rig, buf); + if (retval != RIG_OK) + return retval; + vfoc = buf[29]; + /* FIXME - is balance 0.0 .. 1.0 or -1.0 .. 1.0? */ + if (vfoc >= '0' && vfoc <= '4') + val->f = (float)('2'-vfoc)/('2'-'0'); + else { + rig_debug(RIG_DEBUG_ERR, "%s: Unexpected reply '%s'\n", __func__, buf); + return -RIG_ERJCTED; + } + break; default: rig_debug(RIG_DEBUG_ERR, "%s: Unsupported Level %d\n", __func__, level); return -RIG_EINVAL; @@ -464,7 +519,26 @@ static int thd72_get_level(RIG *rig, vfo_t vfo, setting_t level, value_t *val) static int thd72_set_func(RIG *rig, vfo_t vfo, setting_t func, int status) { + int retval; + char vfoc, buf[48]; + + rig_debug(RIG_DEBUG_TRACE, "%s: called\n", __func__); + + switch (func) { + case RIG_FUNC_AIP: + retval = thd72_vfoc(rig, vfo, &vfoc); + if (retval != RIG_OK) + return retval; + retval = thd72_get_menu_info(rig, buf); + if (retval != RIG_OK) + return retval; + if (vfoc == '0') buf[13] = status + '0'; /* VHF AIP */ + else buf[15] = status + '0';; /* UHF AIP */ + return kenwood_simple_transaction(rig, buf, 40); + default: return -RIG_EINVAL; + } + return RIG_OK; } static int thd72_get_func(RIG *rig, vfo_t vfo, setting_t func, int *status) @@ -472,6 +546,8 @@ static int thd72_get_func(RIG *rig, vfo_t vfo, setting_t func, int *status) int retval; char vfoc, buf[48]; + rig_debug(RIG_DEBUG_TRACE, "%s: called\n", __func__); + switch (func) { case RIG_FUNC_AIP: retval = thd72_vfoc(rig, vfo, &vfoc); @@ -490,6 +566,64 @@ static int thd72_get_func(RIG *rig, vfo_t vfo, setting_t func, int *status) return RIG_OK; } +static int thd72_set_parm(RIG *rig, setting_t parm, value_t val) +{ + int retval, hh, mm, ss; + char vfoc, buf[48]; + + rig_debug(RIG_DEBUG_TRACE, "%s: called\n", __func__); + + switch (parm) { + case RIG_PARM_APO: + retval = thd72_get_menu_info(rig, buf); + if (retval != RIG_OK) + return retval; + if (val.i == 0) vfoc = '0'; + else if (val.i <= 15) vfoc = '1'; + else if (val.i <= 30) vfoc = '2'; + else vfoc = '3'; + buf[9] = vfoc; + return kenwood_simple_transaction(rig, buf, 40); + case RIG_PARM_TIME: + default: + return -RIG_EINVAL; + } + return RIG_OK; +} + +static int thd72_get_parm(RIG *rig, setting_t parm, value_t *val) +{ + int retval, hh, mm, ss; + char vfoc, buf[48]; + + rig_debug(RIG_DEBUG_TRACE, "%s: called\n", __func__); + + switch (parm) { + case RIG_PARM_APO: + retval = thd72_get_menu_info(rig, buf); + if (retval != RIG_OK) + return retval; + vfoc = buf[9]; + if (vfoc >= '0' && vfoc <= '3') + val->i = thd72apo[vfoc-'0']; + else { + rig_debug(RIG_DEBUG_ERR, "%s: Unexpected reply '%s'\n", __func__, buf); + return -RIG_ERJCTED; + } + break; + case RIG_PARM_TIME: + retval = kenwood_transaction(rig, "RT", buf, sizeof (buf)); + if (retval != RIG_OK) + return retval; + sscanf(buf+11, "%2d%2d%2d", &hh, &mm, &ss); + val->i = ss + 60*(mm + 60*hh); + break; + default: + return -RIG_EINVAL; + } + return RIG_OK; +} + #define CMD_SZ 5 #define BLOCK_SZ 256 #define BLOCK_COUNT 256 @@ -726,6 +860,7 @@ const struct rig_caps thd72a_caps = { /* mode/filter list, remember: order matters! */ .filters = { {RIG_MODE_FM, kHz(14)}, + {RIG_MODE_FMN, kHz(7)}, {RIG_MODE_AM, kHz(9)}, RIG_FLT_END, }, @@ -753,6 +888,8 @@ const struct rig_caps thd72a_caps = { .get_level = thd72_get_level, .set_func = thd72_set_func, .get_func = thd72_get_func, +.set_parm = thd72_set_parm, +.get_parm = thd72_get_parm, .get_chan_all_cb = thd72_get_chan_all_cb, .get_info = th_get_info, From ef6a3bd8ed4e3a44ed5c4ba30422a87885f2cde2 Mon Sep 17 00:00:00 2001 From: "Brian G. Lucas" Date: Wed, 2 May 2018 16:16:12 -0500 Subject: [PATCH 04/17] WIP: thd72 driver. Try to simplify the menu based interface. --- kenwood/thd72.c | 157 ++++++++++++++++++++++-------------------------- 1 file changed, 71 insertions(+), 86 deletions(-) diff --git a/kenwood/thd72.c b/kenwood/thd72.c index 8ce01444b..c48c927c3 100644 --- a/kenwood/thd72.c +++ b/kenwood/thd72.c @@ -147,7 +147,7 @@ static int thd72_set_vfo(RIG *rig, vfo_t vfo) static int thd72_get_vfo(RIG *rig, vfo_t *vfo) { int retval; - char buf[10], vfoc; + char c, buf[10]; rig_debug(RIG_DEBUG_TRACE, "%s: called\n", __func__); @@ -156,12 +156,12 @@ static int thd72_get_vfo(RIG *rig, vfo_t *vfo) return retval; size_t length = strlen (buf); if (length == 4) { - vfoc = buf[3]; + c = buf[3]; } else { rig_debug(RIG_DEBUG_ERR, "%s: Unexpected answer length '%c'\n", __func__, length); return -RIG_EPROTO; } - switch (vfoc) { + switch (c) { case '0': *vfo = RIG_VFO_A; break; case '1': *vfo = RIG_VFO_B; break; default: @@ -187,12 +187,12 @@ static int thd72_vfoc(RIG *rig, vfo_t vfo, char *vfoc) static int thd72_get_freq_info(RIG *rig, vfo_t vfo, char *buf) { int retval, length; - char vfoc, cmd[8]; + char c, cmd[8]; - retval = thd72_vfoc(rig, vfo, &vfoc); + retval = thd72_vfoc(rig, vfo, &c); if (retval != RIG_OK) return retval; - sprintf(cmd, "FO %c", vfoc); + sprintf(cmd, "FO %c", c); retval = kenwood_transaction(rig, cmd, buf, 53); length = strlen(buf); rig_debug(RIG_DEBUG_TRACE, "%s: length=%d\n", __func__, length); @@ -387,14 +387,41 @@ static int thd72_get_menu_info(RIG *rig, char *buf) return RIG_OK; } -static int thd72_set_level(RIG *rig, vfo_t vfo, setting_t level, value_t val) +static int thd72_get_menu_item(RIG* rig, int item, char hi, char *val) { int retval; - char vfoc, lvlc, cmd[10], buf[48]; + char c, buf[48]; + + retval = thd72_get_menu_info(rig, buf); + if (retval != RIG_OK) + return retval; + c = buf[3 + 2*item]; /* "MU 0,1,2 ... */ + if (c < '0' || c > hi) + return -RIG_EPROTO; + *val = c; + return RIG_OK; +} + +static int thd72_set_menu_item(RIG* rig, int item, int val) +{ + int retval; + char buf[48]; + + retval = thd72_get_menu_info(rig, buf); + if (retval != RIG_OK) + return retval; + buf[3 + 2*item] = '0' + val; + return kenwood_simple_transaction(rig, buf, 40); +} + +static int thd72_set_level(RIG *rig, vfo_t vfo, setting_t level, value_t val) +{ + int retval, lvl; + char c, lvlc, cmd[10]; rig_debug(RIG_DEBUG_TRACE, "%s: called\n", __func__); - retval = thd72_vfoc(rig, vfo, &vfoc); + retval = thd72_vfoc(rig, vfo, &c); if (retval != RIG_OK) return retval; switch (level) { @@ -402,29 +429,23 @@ static int thd72_set_level(RIG *rig, vfo_t vfo, setting_t level, value_t val) if (val.f <= 0.01) lvlc = '2'; else if (val.f <= 0.10) lvlc = '1'; else lvlc = '0'; - sprintf(cmd, "PC %c,%c", vfoc, lvlc); + sprintf(cmd, "PC %c,%c", c, lvlc); return kenwood_simple_transaction(rig, cmd, 6); case RIG_LEVEL_VOXGAIN: - retval = thd72_get_menu_info(rig, buf); - if (retval != RIG_OK) - return retval; - buf[19] = '0' + (int)(val.f*10.0 - 0.5); - return kenwood_simple_transaction(rig, buf, 40); + return thd72_set_menu_item(rig, 8, (int)(val.f*10.0 - 0.5)); case RIG_LEVEL_VOXDELAY: - retval = thd72_get_menu_info(rig, buf); - if (retval != RIG_OK) - return retval; - return kenwood_simple_transaction(rig, buf, 40); + if (val.i > 20000) lvl = 6; + else if (val.i > 10000) lvl = val.i/10000 + 3; + else lvl = val.i/2500; + return thd72_set_menu_item(rig, 9, lvl); case RIG_LEVEL_SQL: lvlc = '0' + (int)(val.f*5); - sprintf(cmd, "PC %c,%c", vfoc, lvlc; + sprintf(cmd, "PC %c,%c", c, lvlc); return kenwood_simple_transaction(rig, cmd, 6); case RIG_LEVEL_BALANCE: - retval = thd72_get_menu_info(rig, buf); - if (retval != RIG_OK) - return retval; /* FIXME - is balance 0.0 .. 1.0 or -1.0 .. 1.0? */ - return kenwood_simple_transaction(rig, buf, 40); + lvl = (int)(val.f*4.0); + return thd72_set_menu_item(rig, 13, lvl); default: rig_debug(RIG_DEBUG_ERR, "%s: Unsupported Level %d\n", __func__, level); return -RIG_EINVAL; @@ -435,16 +456,16 @@ static int thd72_set_level(RIG *rig, vfo_t vfo, setting_t level, value_t val) static int thd72_get_level(RIG *rig, vfo_t vfo, setting_t level, value_t *val) { int retval, v, l; - char vfoc, cmd[10], buf[48]; + char c, cmd[10], buf[48]; rig_debug(RIG_DEBUG_TRACE, "%s: called\n", __func__); - retval = thd72_vfoc(rig, vfo, &vfoc); + retval = thd72_vfoc(rig, vfo, &c); if (retval != RIG_OK) return retval; switch (level) { case RIG_LEVEL_RFPOWER: - sprintf(cmd, "PC %c", vfoc); + sprintf(cmd, "PC %c", c); retval = kenwood_transaction(rig, cmd, buf, sizeof (buf)); if (retval != RIG_OK) return retval; @@ -460,33 +481,21 @@ static int thd72_get_level(RIG *rig, vfo_t vfo, setting_t level, value_t *val) } break; case RIG_LEVEL_VOXGAIN: - retval = thd72_get_menu_info(rig, buf); + retval = thd72_get_menu_item(rig, 8, '9', &c); if (retval != RIG_OK) return retval; /* FIXME - if VOX is off, what do we return */ - vfoc = buf[19]; - if (vfoc >= '0' && vfoc <= '9') - val->f = (vfoc - '0') / 9.0; - else { - rig_debug(RIG_DEBUG_ERR, "%s: Unexpected reply '%s'\n", __func__, buf); - return -RIG_ERJCTED; - } + val->f = (c - '0') / 9.0; break; case RIG_LEVEL_VOXDELAY: - retval = thd72_get_menu_info(rig, buf); + retval = thd72_get_menu_item(rig, 9, '7', &c); if (retval != RIG_OK) return retval; /* FIXME - if VOX is off, what do we return */ - vfoc = buf[21]; - if (vfoc >= '0' && vfoc <= '7') - val->i = thd72voxdelay[vfoc-'0']; - else { - rig_debug(RIG_DEBUG_ERR, "%s: Unexpected reply '%s'\n", __func__, buf); - return -RIG_ERJCTED; - } + val->i = thd72voxdelay[c-'0']; break; case RIG_LEVEL_SQL: - sprintf(cmd, "SQ %c", vfoc); + sprintf(cmd, "SQ %c", c); retval = kenwood_transaction(rig, cmd, buf, sizeof (buf)); if (retval != RIG_OK) return retval; @@ -498,17 +507,11 @@ static int thd72_get_level(RIG *rig, vfo_t vfo, setting_t level, value_t *val) val->f = thd72sqlevel[l]; break; case RIG_LEVEL_BALANCE: - retval = thd72_get_menu_info(rig, buf); + retval = thd72_get_menu_item(rig, 13, '4', &c); if (retval != RIG_OK) return retval; - vfoc = buf[29]; /* FIXME - is balance 0.0 .. 1.0 or -1.0 .. 1.0? */ - if (vfoc >= '0' && vfoc <= '4') - val->f = (float)('2'-vfoc)/('2'-'0'); - else { - rig_debug(RIG_DEBUG_ERR, "%s: Unexpected reply '%s'\n", __func__, buf); - return -RIG_ERJCTED; - } + val->f = (float)(c-'4')/4.0; break; default: rig_debug(RIG_DEBUG_ERR, "%s: Unsupported Level %d\n", __func__, level); @@ -520,21 +523,16 @@ static int thd72_get_level(RIG *rig, vfo_t vfo, setting_t level, value_t *val) static int thd72_set_func(RIG *rig, vfo_t vfo, setting_t func, int status) { int retval; - char vfoc, buf[48]; + char c; rig_debug(RIG_DEBUG_TRACE, "%s: called\n", __func__); switch (func) { case RIG_FUNC_AIP: - retval = thd72_vfoc(rig, vfo, &vfoc); + retval = thd72_vfoc(rig, vfo, &c); if (retval != RIG_OK) return retval; - retval = thd72_get_menu_info(rig, buf); - if (retval != RIG_OK) - return retval; - if (vfoc == '0') buf[13] = status + '0'; /* VHF AIP */ - else buf[15] = status + '0';; /* UHF AIP */ - return kenwood_simple_transaction(rig, buf, 40); + return thd72_set_menu_item(rig, c == '0'?5:6, status); default: return -RIG_EINVAL; } @@ -544,21 +542,19 @@ static int thd72_set_func(RIG *rig, vfo_t vfo, setting_t func, int status) static int thd72_get_func(RIG *rig, vfo_t vfo, setting_t func, int *status) { int retval; - char vfoc, buf[48]; + char c; rig_debug(RIG_DEBUG_TRACE, "%s: called\n", __func__); switch (func) { case RIG_FUNC_AIP: - retval = thd72_vfoc(rig, vfo, &vfoc); + retval = thd72_vfoc(rig, vfo, &c); if (retval != RIG_OK) return retval; - retval = thd72_get_menu_info(rig, buf); + retval = thd72_get_menu_item(rig, c == '0'?5:6, '1', &c); if (retval != RIG_OK) return retval; - if (vfoc == '0') vfoc = buf[13]; /* VHF AIP */ - else vfoc = buf[15]; /* UHF AIP */ - *status = vfoc - '0'; + *status = c - '0'; break; default: return -RIG_EINVAL; @@ -568,22 +564,17 @@ static int thd72_get_func(RIG *rig, vfo_t vfo, setting_t func, int *status) static int thd72_set_parm(RIG *rig, setting_t parm, value_t val) { - int retval, hh, mm, ss; - char vfoc, buf[48]; + int lvl; rig_debug(RIG_DEBUG_TRACE, "%s: called\n", __func__); switch (parm) { case RIG_PARM_APO: - retval = thd72_get_menu_info(rig, buf); - if (retval != RIG_OK) - return retval; - if (val.i == 0) vfoc = '0'; - else if (val.i <= 15) vfoc = '1'; - else if (val.i <= 30) vfoc = '2'; - else vfoc = '3'; - buf[9] = vfoc; - return kenwood_simple_transaction(rig, buf, 40); + if (val.i == 0) lvl = 0; + else if (val.i <= 15) lvl = 1; + else if (val.i <= 30) lvl = 2; + else lvl = 3; + return thd72_set_menu_item(rig, 3, lvl); case RIG_PARM_TIME: default: return -RIG_EINVAL; @@ -594,22 +585,16 @@ static int thd72_set_parm(RIG *rig, setting_t parm, value_t val) static int thd72_get_parm(RIG *rig, setting_t parm, value_t *val) { int retval, hh, mm, ss; - char vfoc, buf[48]; + char c, buf[48]; rig_debug(RIG_DEBUG_TRACE, "%s: called\n", __func__); switch (parm) { case RIG_PARM_APO: - retval = thd72_get_menu_info(rig, buf); + retval = thd72_get_menu_item(rig, 3, '3', &c); if (retval != RIG_OK) return retval; - vfoc = buf[9]; - if (vfoc >= '0' && vfoc <= '3') - val->i = thd72apo[vfoc-'0']; - else { - rig_debug(RIG_DEBUG_ERR, "%s: Unexpected reply '%s'\n", __func__, buf); - return -RIG_ERJCTED; - } + val->i = thd72apo[c-'0']; break; case RIG_PARM_TIME: retval = kenwood_transaction(rig, "RT", buf, sizeof (buf)); From ecc23c79ed3dc3ce0c887407ba8ba347a1490281 Mon Sep 17 00:00:00 2001 From: Michael Black W9MDB Date: Fri, 4 May 2018 10:12:39 -0500 Subject: [PATCH 05/17] Fixed PKTFM filters in ic7300 --- icom/ic7300.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/icom/ic7300.c b/icom/ic7300.c index 14ee59482..0f3020252 100644 --- a/icom/ic7300.c +++ b/icom/ic7300.c @@ -209,9 +209,9 @@ const struct rig_caps ic7300_caps = { {RIG_MODE_CW|RIG_MODE_CWR|RIG_MODE_RTTY|RIG_MODE_RTTYR, Hz(250)}, {RIG_MODE_CW|RIG_MODE_CWR, kHz(1.2)}, {RIG_MODE_RTTY|RIG_MODE_RTTYR, kHz(2.4)}, - {RIG_MODE_AM|RIG_MODE_PKTFM, kHz(6)}, - {RIG_MODE_AM|RIG_MODE_PKTFM, kHz(3)}, - {RIG_MODE_AM|RIG_MODE_PKTFM, kHz(9)}, + {RIG_MODE_AM|RIG_MODE_PKTAM, kHz(6)}, + {RIG_MODE_AM|RIG_MODE_PKTAM, kHz(3)}, + {RIG_MODE_AM|RIG_MODE_PKTAM, kHz(9)}, {RIG_MODE_FM|RIG_MODE_PKTFM, kHz(15)}, {RIG_MODE_FM|RIG_MODE_PKTFM, kHz(10)}, {RIG_MODE_FM|RIG_MODE_PKTFM, kHz(7)}, From ae072324ddd41597ede0ace7a54e5dcab097f92a Mon Sep 17 00:00:00 2001 From: "Brian G. Lucas" Date: Fri, 4 May 2018 16:56:06 -0500 Subject: [PATCH 06/17] WIP: thd72 driver. First cut at get_channel(). Other cleanup. --- kenwood/thd72.c | 212 +++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 175 insertions(+), 37 deletions(-) diff --git a/kenwood/thd72.c b/kenwood/thd72.c index c48c927c3..71452519e 100644 --- a/kenwood/thd72.c +++ b/kenwood/thd72.c @@ -76,7 +76,21 @@ static rptr_shift_t thd72_rshf_table[3] = { [0] = RIG_RPT_SHIFT_NONE, [1] = RIG_RPT_SHIFT_PLUS, [2] = RIG_RPT_SHIFT_MINUS, -} ; +}; + +static int thd72tuningstep[10] = { + [0] = 5000, + [1] = 6250, + [2] = 8330, + [3] = 10000, + [4] = 12500, + [5] = 15000, + [6] = 20000, + [7] = 25000, + [8] = 30000, + [9] = 50000, /* or 100 kHz? */ +}; + static int thd72voxdelay[7] = { [0] = 2500, [1] = 5000, @@ -387,7 +401,27 @@ static int thd72_get_menu_info(RIG *rig, char *buf) return RIG_OK; } -static int thd72_get_menu_item(RIG* rig, int item, char hi, char *val) +/* each menu item is a single hex digit */ +static int thd72_get_menu_item(RIG* rig, int item, int hi, int *val) +{ + int retval, lval; + char c, buf[48]; + + retval = thd72_get_menu_info(rig, buf); + if (retval != RIG_OK) + return retval; + c = buf[3 + 2*item]; /* "MU 0,1,2 ... */ + if (c >= '0' && c <= '9') lval = c - '0'; + else if (c >= 'A' && c <= 'F') lval = c - 'A' + 10; + else + return -RIG_EPROTO; + if (lval > hi) + return -RIG_EPROTO; + *val = lval; + return RIG_OK; +} + +static int thd72_set_menu_item(RIG* rig, int item, int val) { int retval; char c, buf[48]; @@ -395,22 +429,9 @@ static int thd72_get_menu_item(RIG* rig, int item, char hi, char *val) retval = thd72_get_menu_info(rig, buf); if (retval != RIG_OK) return retval; - c = buf[3 + 2*item]; /* "MU 0,1,2 ... */ - if (c < '0' || c > hi) - return -RIG_EPROTO; - *val = c; - return RIG_OK; -} - -static int thd72_set_menu_item(RIG* rig, int item, int val) -{ - int retval; - char buf[48]; - - retval = thd72_get_menu_info(rig, buf); - if (retval != RIG_OK) - return retval; - buf[3 + 2*item] = '0' + val; + if (val < 10) c = val + '0'; + else c = val - 10 + 'A'; + buf[3 + 2*item] = c; return kenwood_simple_transaction(rig, buf, 40); } @@ -481,18 +502,18 @@ static int thd72_get_level(RIG *rig, vfo_t vfo, setting_t level, value_t *val) } break; case RIG_LEVEL_VOXGAIN: - retval = thd72_get_menu_item(rig, 8, '9', &c); + retval = thd72_get_menu_item(rig, 8, '9', &l); if (retval != RIG_OK) return retval; /* FIXME - if VOX is off, what do we return */ - val->f = (c - '0') / 9.0; + val->f = l / 9.0; break; case RIG_LEVEL_VOXDELAY: - retval = thd72_get_menu_item(rig, 9, '7', &c); + retval = thd72_get_menu_item(rig, 9, '7', &l); if (retval != RIG_OK) return retval; /* FIXME - if VOX is off, what do we return */ - val->i = thd72voxdelay[c-'0']; + val->i = thd72voxdelay[l]; break; case RIG_LEVEL_SQL: sprintf(cmd, "SQ %c", c); @@ -507,11 +528,11 @@ static int thd72_get_level(RIG *rig, vfo_t vfo, setting_t level, value_t *val) val->f = thd72sqlevel[l]; break; case RIG_LEVEL_BALANCE: - retval = thd72_get_menu_item(rig, 13, '4', &c); + retval = thd72_get_menu_item(rig, 13, '4', &l); if (retval != RIG_OK) return retval; /* FIXME - is balance 0.0 .. 1.0 or -1.0 .. 1.0? */ - val->f = (float)(c-'4')/4.0; + val->f = (float)(l)/4.0; break; default: rig_debug(RIG_DEBUG_ERR, "%s: Unsupported Level %d\n", __func__, level); @@ -541,7 +562,7 @@ static int thd72_set_func(RIG *rig, vfo_t vfo, setting_t func, int status) static int thd72_get_func(RIG *rig, vfo_t vfo, setting_t func, int *status) { - int retval; + int retval, l; char c; rig_debug(RIG_DEBUG_TRACE, "%s: called\n", __func__); @@ -551,10 +572,10 @@ static int thd72_get_func(RIG *rig, vfo_t vfo, setting_t func, int *status) retval = thd72_vfoc(rig, vfo, &c); if (retval != RIG_OK) return retval; - retval = thd72_get_menu_item(rig, c == '0'?5:6, '1', &c); + retval = thd72_get_menu_item(rig, c == '0'?5:6, '1', &l); if (retval != RIG_OK) return retval; - *status = c - '0'; + *status = l; break; default: return -RIG_EINVAL; @@ -564,17 +585,17 @@ static int thd72_get_func(RIG *rig, vfo_t vfo, setting_t func, int *status) static int thd72_set_parm(RIG *rig, setting_t parm, value_t val) { - int lvl; + int l; rig_debug(RIG_DEBUG_TRACE, "%s: called\n", __func__); switch (parm) { case RIG_PARM_APO: - if (val.i == 0) lvl = 0; - else if (val.i <= 15) lvl = 1; - else if (val.i <= 30) lvl = 2; - else lvl = 3; - return thd72_set_menu_item(rig, 3, lvl); + if (val.i == 0) l = 0; + else if (val.i <= 15) l = 1; + else if (val.i <= 30) l = 2; + else l = 3; + return thd72_set_menu_item(rig, 3, l); case RIG_PARM_TIME: default: return -RIG_EINVAL; @@ -584,17 +605,17 @@ static int thd72_set_parm(RIG *rig, setting_t parm, value_t val) static int thd72_get_parm(RIG *rig, setting_t parm, value_t *val) { - int retval, hh, mm, ss; - char c, buf[48]; + int retval, l, hh, mm, ss; + char buf[48]; rig_debug(RIG_DEBUG_TRACE, "%s: called\n", __func__); switch (parm) { case RIG_PARM_APO: - retval = thd72_get_menu_item(rig, 3, '3', &c); + retval = thd72_get_menu_item(rig, 3, '3', &l); if (retval != RIG_OK) return retval; - val->i = thd72apo[c-'0']; + val->i = thd72apo[l]; break; case RIG_PARM_TIME: retval = kenwood_transaction(rig, "RT", buf, sizeof (buf)); @@ -609,6 +630,118 @@ static int thd72_get_parm(RIG *rig, setting_t parm, value_t *val) return RIG_OK; } +static int thd72_set_mem(RIG *rig, vfo_t vfo, int ch) +{ + int retval; + char c, cmd[10]; + + rig_debug(RIG_DEBUG_TRACE, "%s: called\n", __func__); + + retval = thd72_vfoc(rig, vfo, &c); + if (retval != RIG_OK) + return retval; + sprintf(cmd, "MR %c,%03d", c, ch); + return kenwood_simple_transaction(rig, cmd, 10); +} + +static int thd72_get_mem(RIG *rig, vfo_t vfo, int *ch) +{ + int retval; + char c, cmd[10], buf[10]; + + rig_debug(RIG_DEBUG_TRACE, "%s: called\n", __func__); + + retval = thd72_vfoc(rig, vfo, &c); + if (retval != RIG_OK) + return retval; + sprintf(cmd, "MR %c", c); + retval = kenwood_transaction(rig, cmd, buf, sizeof (buf)); + if (retval != RIG_OK) + return retval; + sscanf(buf+5, "%d", ch); + return RIG_OK; +} + +static int thd72_set_channel(RIG *rig, const channel_t *chan) +{ + rig_debug(RIG_DEBUG_TRACE, "%s: called\n", __func__); + + return -RIG_EINVAL; +} + +static int thd72_parse_channel(int kind, const char *buf, channel_t *chan) +{ + int tmp; + char c; + const char *data; + + if (kind == 0) data = buf+5; else data = buf+7; + sscanf(data, "%"SCNfreq, &chan->freq); + c = data[46]; // mode + if (c >= '0' && c <= '2') { + chan->mode = thd72_mode_table[c - '0']; + chan->width = thd72_width_table[c - '0']; + } + c = data[11]; // tuning step + if (c >= '0' && c <= '9') + chan->tuning_step = thd72tuningstep[c - '0']; + c = data[13]; // repeater shift + if (c >= '0' && c <= '2') + chan->rptr_shift = thd72_rshf_table[c - '0']; + sscanf(data+37, "%ld", &chan->rptr_offs); + c = data[17]; // Tone status + if (c != '0') { + sscanf(data+25, "%d", &tmp); + if (tmp > 0 && tmp < 42) + chan->ctcss_tone = kenwood42_ctcss_list[tmp]; + } else + chan->ctcss_tone = 0; + c = data[19]; // TSQL status + if (c != '0') { + sscanf(data+28, "%d", &tmp); + if (tmp > 0 && tmp < 42) + chan->ctcss_sql = kenwood42_ctcss_list[tmp]; + } else + chan->ctcss_sql = 0; + c = data[21]; // DCS status + if (c != '0') { + sscanf(data+31, "%d", &tmp); + chan->dcs_code = tmp; + } else + chan->dcs_code = 0; + return RIG_OK; +} + +static int thd72_get_channel(RIG *rig, channel_t *chan) +{ + int retval, len; + char cmd[8], buf[72]; + + rig_debug(RIG_DEBUG_TRACE, "%s: called\n", __func__); + + if (chan->vfo == RIG_VFO_MEM) { /* memory channel */ + sprintf(cmd, "ME %03d", chan->channel_num); + retval = kenwood_transaction(rig, cmd, buf, sizeof (buf)); + if (retval != RIG_OK) + return retval; + retval = thd72_parse_channel(1, buf, chan); + if (retval != RIG_OK) + return retval; + cmd[1] = 'N'; /* change ME to MN */ + retval = kenwood_transaction(rig, cmd, buf, sizeof (buf)); + if (retval != RIG_OK) + return retval; + len = strlen(buf); + memcpy(chan->channel_desc, buf+7, len-7); + } else { /* current channel */ + retval = thd72_get_freq_info(rig, chan->vfo, buf); + if (retval != RIG_OK) + return retval; + return thd72_parse_channel(0, buf, chan); + } + return RIG_OK; +} + #define CMD_SZ 5 #define BLOCK_SZ 256 #define BLOCK_COUNT 256 @@ -875,6 +1008,11 @@ const struct rig_caps thd72a_caps = { .get_func = thd72_get_func, .set_parm = thd72_set_parm, .get_parm = thd72_get_parm, +.set_mem = thd72_set_mem, +.get_mem = thd72_get_mem, +.set_channel = thd72_set_channel, +.get_channel = thd72_get_channel, + .get_chan_all_cb = thd72_get_chan_all_cb, .get_info = th_get_info, From 776f9ea2f68733be5d525afa96bab7e02325a021 Mon Sep 17 00:00:00 2001 From: Michael Black W9MDB Date: Tue, 8 May 2018 06:42:40 -0500 Subject: [PATCH 07/17] Added TRXManager backend --- dummy/Android.mk | 2 +- dummy/Makefile.am | 2 +- dummy/dummy.c | 1 + dummy/trxmanager.c | 974 +++++++++++++++++++++++++++++++++++++++ dummy/trxmanager.h | 41 ++ include/hamlib/riglist.h | 1 + 6 files changed, 1019 insertions(+), 2 deletions(-) create mode 100644 dummy/trxmanager.c create mode 100644 dummy/trxmanager.h diff --git a/dummy/Android.mk b/dummy/Android.mk index de390d189..8018d3ffe 100644 --- a/dummy/Android.mk +++ b/dummy/Android.mk @@ -2,7 +2,7 @@ LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) -LOCAL_SRC_FILES := dummy.c rot_dummy.c netrigctl.c netrotctl.c flrig.c +LOCAL_SRC_FILES := dummy.c rot_dummy.c netrigctl.c netrotctl.c flrig.c trxmanager.c LOCAL_MODULE := dummy LOCAL_CFLAGS := -DHAVE_CONFIG_H diff --git a/dummy/Makefile.am b/dummy/Makefile.am index 3c03de2b0..d6c8f6287 100644 --- a/dummy/Makefile.am +++ b/dummy/Makefile.am @@ -1,4 +1,4 @@ -DUMMYSRC = dummy.c dummy.h rot_dummy.c rot_dummy.h netrigctl.c netrotctl.c flrig.c flrig.h +DUMMYSRC = dummy.c dummy.h rot_dummy.c rot_dummy.h netrigctl.c netrotctl.c flrig.c flrig.h trxmanager.c trxmanager.h noinst_LTLIBRARIES = libhamlib-dummy.la libhamlib_dummy_la_SOURCES = $(DUMMYSRC) diff --git a/dummy/dummy.c b/dummy/dummy.c index d46972243..49a6a8fbc 100644 --- a/dummy/dummy.c +++ b/dummy/dummy.c @@ -1629,6 +1629,7 @@ DECLARE_INITRIG_BACKEND(dummy) rig_register(&dummy_caps); rig_register(&netrigctl_caps); rig_register(&flrig_caps); + rig_register(&trxmanager_caps); return RIG_OK; } diff --git a/dummy/trxmanager.c b/dummy/trxmanager.c new file mode 100644 index 000000000..f3644b4e1 --- /dev/null +++ b/dummy/trxmanager.c @@ -0,0 +1,974 @@ +/* + i Hamlib TRXManager backend - main file + * Copyright (c) 2018 by Michael Black W9MDB + * Derived from flrig.c + * + * + * 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 /* String function definitions */ +#include /* UNIX standard function definitions */ +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "trxmanager.h" + +#define DEBUG_TRACE DEBUG_VERBOSE + +#define MAXCMDLEN 64 + +#define DEFAULTPATH "127.0.0.1:1003" + +#define TRXMANAGER_VFOS (RIG_VFO_A|RIG_VFO_B) + +#define TRXMANAGER_MODES (RIG_MODE_AM | RIG_MODE_CW | RIG_MODE_CWR |\ + RIG_MODE_RTTY | RIG_MODE_RTTYR |\ + RIG_MODE_PKTLSB | RIG_MODE_PKTUSB |\ + RIG_MODE_SSB | RIG_MODE_FM | RIG_MODE_WFM | RIG_MODE_FMN ) + +#define streq(s1,s2) (strcmp(s1,s2)==0) + +static int trxmanager_init(RIG *rig); +static int trxmanager_open(RIG *rig); +static int trxmanager_close(RIG *rig); +static int trxmanager_cleanup(RIG *rig); +static int trxmanager_set_freq(RIG *rig, vfo_t vfo, freq_t freq); +static int trxmanager_get_freq(RIG *rig, vfo_t vfo, freq_t *freq); +static int trxmanager_set_ptt(RIG *rig, vfo_t vfo, ptt_t ptt); +static int trxmanager_set_mode(RIG *rig, vfo_t vfo, rmode_t mode, pbwidth_t width); +static int trxmanager_set_split_mode(RIG *rig, vfo_t vfo, rmode_t mode, pbwidth_t width); +static int trxmanager_get_mode(RIG *rig, vfo_t vfo, rmode_t *mode, pbwidth_t *width); +static int trxmanager_get_vfo(RIG *rig, vfo_t *vfo); +static int trxmanager_set_vfo(RIG *rig, vfo_t vfo); +static int trxmanager_set_ptt(RIG *rig, vfo_t vfo, ptt_t ptt); +static int trxmanager_get_ptt(RIG *rig, vfo_t vfo, ptt_t *ptt); +static int trxmanager_set_split_freq(RIG *rig, vfo_t vfo, freq_t tx_freq); +static int trxmanager_get_split_freq(RIG *rig, vfo_t vfo, freq_t *tx_freq); +static int trxmanager_set_split_vfo(RIG *rig, vfo_t vfo, split_t split, + vfo_t tx_vfo); +static int trxmanager_get_split_vfo(RIG *rig, vfo_t vfo, split_t *split, + vfo_t *tx_vfo); +static int trxmanager_set_split_freq_mode(RIG *rig, vfo_t vfo, freq_t freq, rmode_t mode, pbwidth_t width); +static int trxmanager_get_split_freq_mode(RIG *rig, vfo_t vfo, freq_t *freq, rmode_t *mode, pbwidth_t *width); + +static const char *trxmanager_get_info(RIG *rig); + +struct trxmanager_priv_data { + vfo_t vfo_curr; + char info[100]; + split_t split; +}; + +struct rig_caps trxmanager_caps = { + .rig_model = RIG_MODEL_TRXMANAGER_RIG, + .model_name = "5.7.630+", + .mfg_name = "TRXManager", + .version = BACKEND_VER, + .copyright = "LGPL", + .status = RIG_STATUS_STABLE, + .rig_type = RIG_TYPE_TRANSCEIVER, + .targetable_vfo = RIG_TARGETABLE_FREQ, + .ptt_type = RIG_PTT_RIG, + .port_type = RIG_PORT_NETWORK, + .write_delay = 0, + .post_write_delay = 0, + .timeout = 1000, + .retry = 3, + + .has_get_func = RIG_FUNC_NONE, + .has_set_func = RIG_FUNC_NONE, + .has_get_level = RIG_LEVEL_NONE, + .has_set_level = RIG_LEVEL_NONE, + .has_get_parm = RIG_PARM_NONE, + .has_set_parm = RIG_PARM_NONE, + .filters = { + RIG_FLT_END + }, + + .rx_range_list1 = {{ + .start = kHz(1),.end = GHz(10),.modes = TRXMANAGER_MODES, + .low_power = -1,.high_power = -1, TRXMANAGER_VFOS, RIG_ANT_1 + }, + RIG_FRNG_END, + }, + .tx_range_list1 = {RIG_FRNG_END,}, + .rx_range_list2 = {{ + .start = kHz(1),.end = GHz(10),.modes = TRXMANAGER_MODES, + .low_power = -1,.high_power = -1, TRXMANAGER_VFOS, RIG_ANT_1 + }, + RIG_FRNG_END, + }, + .tx_range_list2 = {RIG_FRNG_END,}, + .tuning_steps = { {TRXMANAGER_MODES,1}, {TRXMANAGER_MODES,RIG_TS_ANY}, RIG_TS_END, }, + .priv = NULL, /* priv */ + + .rig_init = trxmanager_init, + .rig_open = trxmanager_open, + .rig_close = trxmanager_close, + .rig_cleanup = trxmanager_cleanup, + + .set_freq = trxmanager_set_freq, + .get_freq = trxmanager_get_freq, + .set_mode = trxmanager_set_mode, + .get_mode = trxmanager_get_mode, + .set_vfo = trxmanager_set_vfo, + .get_vfo = trxmanager_get_vfo, + .get_info = trxmanager_get_info, + .set_ptt = trxmanager_set_ptt, + .get_ptt = trxmanager_get_ptt, + .set_split_mode = trxmanager_set_split_mode, + .set_split_freq = trxmanager_set_split_freq, + .get_split_freq = trxmanager_get_split_freq, + .set_split_vfo = trxmanager_set_split_vfo, + .get_split_vfo = trxmanager_get_split_vfo, + .set_split_freq_mode = trxmanager_set_split_freq_mode, + .get_split_freq_mode = trxmanager_get_split_freq_mode +}; + +/* + * vfo_curr + * No assumptions + */ +static int check_vfo(vfo_t vfo) +{ + switch (vfo) { + case RIG_VFO_A: + break; + + case RIG_VFO_TX: + case RIG_VFO_B: + break; + + case RIG_VFO_CURR: + break; // will default to A in which_vfo + + default: + return FALSE; + } + + return TRUE; +} + +/* + * vfo_curr + * Assumes rig!=NULL + */ +static int vfo_curr(RIG *rig, vfo_t vfo) +{ + int retval = 0; + vfo_t vfocurr; + struct trxmanager_priv_data *priv = (struct trxmanager_priv_data *) rig->state.priv; + + // get the current VFO from trxmanager in case user changed it + if ((retval = trxmanager_get_vfo(rig, &vfocurr)) != RIG_OK) { + return retval; + } + priv->vfo_curr = vfocurr; + retval = (vfo == vfocurr); + return retval; +} + +/* + * read_transaction + * Assumes rig!=NULL, response!=NULL, response_len>=MAXCMDLEN + */ +static int read_transaction(RIG *rig, char *response, int response_len) +{ + rig_debug(RIG_DEBUG_TRACE, "%s\n", __FUNCTION__); + + struct rig_state *rs = &rig->state; + + char *delims="\n"; + int len = read_string(&rs->rigport, response, response_len, delims, strlen(delims)); + if (len <= 0) { + rig_debug(RIG_DEBUG_ERR,"%s: read_string error=%d\n",__FUNCTION__,len); + return -RIG_EPROTO; + } + return RIG_OK; +} + +/* + * trxmanager_init + * Assumes rig!=NULL + */ +static int trxmanager_init(RIG *rig) +{ + + rig_debug(RIG_DEBUG_TRACE, "%s version %s\n", __FUNCTION__, BACKEND_VER); + + struct trxmanager_priv_data *priv = (struct trxmanager_priv_data *)malloc(sizeof(struct trxmanager_priv_data)); + + if (!priv) { + return -RIG_ENOMEM; + } + + memset(priv, 0, sizeof(struct trxmanager_priv_data)); + + /* + * set arbitrary initial status + */ + rig->state.priv = (rig_ptr_t) priv; + priv->vfo_curr = RIG_VFO_A; + priv->split = 0; + + if (!rig || !rig->caps) { + return -RIG_EINVAL; + } + + strncpy(rig->state.rigport.pathname, DEFAULTPATH, + sizeof(rig->state.rigport.pathname)); + + return RIG_OK; +} + +/* + * trxmanager_open + * Assumes rig!=NULL, rig->state.priv!=NULL + */ +static int trxmanager_open(RIG *rig) { + int retval; + char response[MAXCMDLEN] = ""; + + rig_debug(RIG_DEBUG_VERBOSE, "%s version %s\n", __FUNCTION__, BACKEND_VER); + + struct rig_state *rs = &rig->state; + struct trxmanager_priv_data *priv = (struct trxmanager_priv_data *) rig->state.priv; + + retval = read_transaction(rig, response, sizeof(response)); + if (retval != RIG_OK) { + rig_debug(RIG_DEBUG_ERR,"%s read_transaction failed\n", __FUNCTION__); + } + rig_debug(RIG_DEBUG_VERBOSE,"%s connected to %s\n", __FUNCTION__, response); + if (strlen(response)==0) { + rig_debug(RIG_DEBUG_ERR,"%s response len==0\n", __FUNCTION__); + return -RIG_EPROTO; + } + + // Should have rig info now + strtok(response,";\r\n"); + strncpy(priv->info,&response[2],sizeof(priv->info)); + + // Turn off active messages + char *cmd = "AI0;"; + retval = write_block(&rs->rigport, cmd, strlen(cmd)); + if (retval < 0) { + return retval; + } + retval = read_transaction(rig, response, sizeof(response)); + if (retval != RIG_OK) { + rig_debug(RIG_DEBUG_ERR,"%s read_transaction failed\n", __FUNCTION__); + } + if (strncmp("AI0;",response,4)!=0) { + rig_debug(RIG_DEBUG_ERR,"%s AI invalid response=%s\n", __FUNCTION__, response); + return -RIG_EINVAL; + } + rig_debug(RIG_DEBUG_VERBOSE,"%s AI response=%s\n", __FUNCTION__, response); + + cmd = "FN;"; + retval = write_block(&rs->rigport, cmd, strlen(cmd)); + if (retval != RIG_OK) { + rig_debug(RIG_DEBUG_ERR,"%s FN; write failed=%s\n", __FUNCTION__); + } + retval = read_transaction(rig, response, sizeof(response)); + if (retval != RIG_OK) { + rig_debug(RIG_DEBUG_ERR,"%s read_transaction failed\n", __FUNCTION__); + } + + rig_debug(RIG_DEBUG_VERBOSE,"%s FN response=%s\n", __FUNCTION__, response); + priv->vfo_curr = RIG_VFO_A; + + return retval; +} + +/* + * trxmanager_close + * Assumes rig!=NULL + */ +static int trxmanager_close(RIG *rig) { + rig_debug(RIG_DEBUG_TRACE, "%s\n", __FUNCTION__); + return RIG_OK; +} + +/* + * trxmanager_cleanup + * Assumes rig!=NULL, rig->state.priv!=NULL + */ +static int trxmanager_cleanup(RIG *rig) { + + if (!rig) + return -RIG_EINVAL; + + free(rig->state.priv); + rig->state.priv = NULL; + + return RIG_OK; +} + +/* + * trxmanager_get_freq + * Assumes rig!=NULL, rig->state.priv!=NULL, freq!=NULL + */ +static int trxmanager_get_freq(RIG *rig, vfo_t vfo, freq_t *freq) +{ + int retval; + + rig_debug(RIG_DEBUG_TRACE, "%s: vfo=%s\n", __FUNCTION__, + rig_strvfo(vfo)); + + struct rig_state *rs = &rig->state; + struct trxmanager_priv_data *priv = (struct trxmanager_priv_data *) rig->state.priv; + + if (check_vfo(vfo) == FALSE) { + rig_debug(RIG_DEBUG_ERR, "%s: unsupported VFO %s\n", + __FUNCTION__, rig_strvfo(vfo)); + return -RIG_EINVAL; + } + + if (vfo == RIG_VFO_CURR) { + if ((retval = trxmanager_get_vfo(rig, &vfo)) != RIG_OK) { + return retval; + } + priv->vfo_curr = vfo; + + rig_debug(RIG_DEBUG_VERBOSE, "%s: get_freq2 vfo=%s\n", + __FUNCTION__, rig_strvfo(vfo)); + } + + char cmd[MAXCMDLEN]; + char response[MAXCMDLEN]=""; + char vfoab = vfo == RIG_VFO_A ? 'R' : 'T'; + snprintf(cmd,sizeof(cmd),"X%c;",vfoab); + retval = write_block(&rs->rigport, cmd, strlen(cmd)); + if (retval < 0) { + return retval; + } + + retval = read_transaction(rig, response, sizeof(response)); + if (retval != RIG_OK) { + rig_debug(RIG_DEBUG_ERR,"%s read_transaction failed\n", __FUNCTION__); + } + *freq = 0; + int n = sscanf(&response[2],"%lg",freq); + if (n != 1) { + } + rig_debug(RIG_DEBUG_ERR, "%s: can't parse freq from %s", __FUNCTION__,response); + if (*freq == 0) { + rig_debug(RIG_DEBUG_ERR, "%s: freq==0??\n", __FUNCTION__); + return -RIG_EPROTO; + } + return retval; +} + +/* + * trxmanager_set_freq + * assumes rig!=NULL, rig->state.priv!=NULL + */ +static int trxmanager_set_freq(RIG *rig, vfo_t vfo, freq_t freq) +{ + int retval; + + rig_debug(RIG_DEBUG_TRACE, "%s: vfo=%s freq=%.1f\n", __FUNCTION__, + rig_strvfo(vfo), freq); + + struct rig_state *rs = &rig->state; + struct trxmanager_priv_data *priv = (struct trxmanager_priv_data *) rig->state.priv; + + if (check_vfo(vfo) == FALSE) { + rig_debug(RIG_DEBUG_ERR, "%s: unsupported VFO %s\n", + __FUNCTION__, rig_strvfo(vfo)); + return -RIG_EINVAL; + } + + if (vfo == RIG_VFO_CURR) { + if ((retval = trxmanager_get_vfo(rig, &vfo)) != RIG_OK) { + return retval; + } + } + else if (vfo == RIG_VFO_TX && priv->split) { + vfo = RIG_VFO_B; // if split always TX on VFOB + } + + char cmd[MAXCMDLEN]; + char response[MAXCMDLEN]=""; + char vfoab = vfo == RIG_VFO_A ? 'A' : 'B'; + snprintf(cmd,sizeof(cmd), "F%c%011ld;", vfoab, (unsigned long)freq); + retval = write_block(&rs->rigport, cmd, strlen(cmd)); + if (retval < 0) { + return retval; + } + + retval = read_transaction(rig, response, sizeof(response)); // get response but don't care + if (retval != RIG_OK) { + rig_debug(RIG_DEBUG_ERR,"%s read_transaction failed\n", __FUNCTION__); + } + + return RIG_OK; +} + +/* + * trxmanager_set_ptt + * Assumes rig!=NULL + */ +static int trxmanager_set_ptt(RIG *rig, vfo_t vfo, ptt_t ptt) +{ + int retval; + + rig_debug(RIG_DEBUG_TRACE, "%s: ptt=%d\n", __FUNCTION__, ptt); + + struct rig_state *rs = &rig->state; + + if (check_vfo(vfo) == FALSE) { + rig_debug(RIG_DEBUG_ERR, "%s: unsupported VFO %s\n", + __FUNCTION__, rig_strvfo(vfo)); + return -RIG_EINVAL; + } + + char cmd[MAXCMDLEN]; + char response[MAXCMDLEN]=""; + + snprintf(cmd,sizeof(cmd),"%s;",ptt==1?"TX":"RX"); + retval = write_block(&rs->rigport, cmd, strlen(cmd)); + + if (retval < 0) { + return retval; + } + + retval = read_transaction(rig, response, sizeof(response)); + if (retval != RIG_OK) { + rig_debug(RIG_DEBUG_ERR,"%s read_transaction failed\n", __FUNCTION__); + } + if (strlen(response)!=5 || strstr(response, cmd)==NULL) { + rig_debug(RIG_DEBUG_ERR, "%s invalid response='%s'\n", __FUNCTION__, response); + return -RIG_EPROTO; + } + + return RIG_OK; +} + +/* + * trxmanager_get_ptt + * Assumes rig!=NULL ptt!=NULL + */ +static int trxmanager_get_ptt(RIG *rig, vfo_t vfo, ptt_t *ptt) +{ + int retval; + + rig_debug(RIG_DEBUG_TRACE, "%s: vfo=%s\n", __FUNCTION__, + rig_strvfo(vfo)); + + struct rig_state *rs = &rig->state; + + char cmd[MAXCMDLEN]; + char response[MAXCMDLEN]=""; + snprintf(cmd,sizeof(cmd),"IF;"); + retval = write_block(&rs->rigport, cmd, strlen(cmd)); + if (retval < 0) { + return retval; + } + + retval = read_transaction(rig, response, sizeof(response)); + if (retval != RIG_OK) { + rig_debug(RIG_DEBUG_ERR,"%s read_transaction failed\n", __FUNCTION__); + } + if (strlen(response)!= 40) { + rig_debug(RIG_DEBUG_ERR, "%s: invalid response='%s'\n", __FUNCTION__, response); + return -RIG_EPROTO; + } + rig_debug(RIG_DEBUG_VERBOSE, "%s: IF response len='%d'\n", __FUNCTION__, strlen(response)); + char cptt = response[28]; + *ptt = cptt == '0' ? 0 : 1; + + return RIG_OK; +} + +/* + * trxmanager_set_split_mode + * Assumes rig!=NULL + */ +static int trxmanager_set_split_mode(RIG *rig, vfo_t vfo, rmode_t mode, pbwidth_t width) +{ + int retval; + rig_debug(RIG_DEBUG_TRACE, "%s: vfo=%s mode=%s width=%d\n", + __FUNCTION__, rig_strvfo(vfo), rig_strrmode(mode), width); + retval = trxmanager_set_mode(rig,RIG_VFO_B,mode,width); + return retval; +} + +/* + * trxmanager_set_mode + * Assumes rig!=NULL + */ +static int trxmanager_set_mode(RIG *rig, vfo_t vfo, rmode_t mode, pbwidth_t width) +{ + int retval; + + rig_debug(RIG_DEBUG_TRACE, "%s: vfo=%s mode=%s width=%d\n", + __FUNCTION__, rig_strvfo(vfo), rig_strrmode(mode), width); + + struct rig_state *rs = &rig->state; + + if (check_vfo(vfo) == FALSE) { + rig_debug(RIG_DEBUG_ERR, "%s: unsupported VFO %s\n", + __FUNCTION__, rig_strvfo(vfo)); + return -RIG_EINVAL; + } + + int ttmode=0; + switch(mode) { + case RIG_MODE_LSB: + ttmode=1; + break; + case RIG_MODE_USB: + ttmode=2; + break; + case RIG_MODE_CW: + ttmode=3; + break; + case RIG_MODE_FM: + ttmode=4; + break; + case RIG_MODE_PKTUSB: + ttmode=5; + break; + case RIG_MODE_CWR: + ttmode=6; + break; + case RIG_MODE_PKTLSB: + ttmode=7; + break; + default: + rig_debug(RIG_DEBUG_ERR, "%s: unsupported mode %s\n",__FUNCTION__,rig_strrmode(mode)); + return -RIG_EINVAL; + + } + + char cmd[MAXCMDLEN]; + char response[MAXCMDLEN]=""; + snprintf(cmd,sizeof(cmd), "MD%d;", ttmode); + retval = write_block(&rs->rigport, cmd, strlen(cmd)); + if (retval < 0) { + return retval; + } + + // Get the response + retval = read_transaction(rig, response, sizeof(response)); + if (retval != RIG_OK) { + rig_debug(RIG_DEBUG_ERR,"%s read_transaction failed\n", __FUNCTION__); + } + rig_debug(RIG_DEBUG_VERBOSE, "%s: response=%s\n", __FUNCTION__,response); + + // Can't set BW on TRXManger as of 20180427 -- can only read it + + return RIG_OK; +} + +/* + * trxmanager_get_mode + * Assumes rig!=NULL, rig->state.priv!=NULL, mode!=NULL + */ +static int trxmanager_get_mode(RIG *rig, vfo_t vfo, rmode_t *mode, pbwidth_t *width) +{ + int retval; + + rig_debug(RIG_DEBUG_TRACE, "%s: vfo=%s\n", __FUNCTION__, + rig_strvfo(vfo)); + + struct rig_state *rs = &rig->state; + struct trxmanager_priv_data *priv = (struct trxmanager_priv_data *) rig->state.priv; + + if (check_vfo(vfo) == FALSE) { + rig_debug(RIG_DEBUG_ERR, "%s: unsupported VFO %s\n", + __FUNCTION__, rig_strvfo(vfo)); + return -RIG_EINVAL; + } + + if (vfo == RIG_VFO_CURR) { + if ((retval = trxmanager_get_vfo(rig, &vfo)) != RIG_OK) { + return retval; + } + priv->vfo_curr = vfo; + } + rig_debug(RIG_DEBUG_TRACE, "%s: using vfo=%s\n", __FUNCTION__, + rig_strvfo(vfo)); + + char cmd[MAXCMDLEN]; + char response[MAXCMDLEN]=""; + snprintf(cmd,sizeof(cmd),"MD;"); + retval = write_block(&rs->rigport, cmd, strlen(cmd)); + if (retval < 0) { + return retval; + } + + retval = read_transaction(rig, response, sizeof(response)); + if (retval != RIG_OK) { + rig_debug(RIG_DEBUG_ERR,"%s read_transaction failed\n", __FUNCTION__); + } + char tmode; + int n = sscanf(response,"MD%c;",&tmode); + if (n != 1 || strlen(response)!=6) { + rig_debug(RIG_DEBUG_ERR, "%s: invalid response='%s'\n", __FUNCTION__, response); + return -RIG_EPROTO; + } + switch(tmode) { + case '1': + *mode=RIG_MODE_LSB; + break; + case '2': + *mode=RIG_MODE_USB; + break; + case '4': + *mode=RIG_MODE_CW; + break; + case '5': + *mode=RIG_MODE_PKTUSB; + break; + case '6': + *mode=RIG_MODE_CWR; + break; + case '7': + *mode=RIG_MODE_PKTLSB; + break; + case '9': + *mode=RIG_MODE_PKTUSB; + break; + case 'A': + *mode=RIG_MODE_PKTLSB; + break; + case 'B': + *mode=RIG_MODE_PKTUSB; + break; + default: + rig_debug(RIG_DEBUG_ERR, "%s: unknown mode='%c'\n", __FUNCTION__, tmode); + return -RIG_EINVAL; + } + rig_debug(RIG_DEBUG_VERBOSE, "%s: mode='%s'\n", __FUNCTION__, rig_strrmode(*mode)); + + // now get the bandwidth + snprintf(cmd,sizeof(cmd),"BW;"); + retval = write_block(&rs->rigport, cmd, strlen(cmd)); + if (retval < 0) { + return retval; + } + + retval = read_transaction(rig, response, sizeof(response)); + if (retval != RIG_OK) { + rig_debug(RIG_DEBUG_ERR,"%s read_transaction failed\n", __FUNCTION__); + } + + if (strncmp(response,"BW",2)!=0) { + rig_debug(RIG_DEBUG_ERR, "%s: invalid response='%s'\n", __FUNCTION__, response); + return -RIG_EPROTO; + } + long iwidth = 0; + n = sscanf(response,"BW%ld;",&iwidth); + if (n != 1) { + rig_debug(RIG_DEBUG_ERR,"%s bandwidth scan failed 's'\n", __FUNCTION__,strtok(response,"\r\n")); + return -RIG_EPROTO; + } + *width=iwidth; + printf("Bandwidth=%ld\n",*width); + return RIG_OK; +} + +static int trxmanager_set_vfo(RIG *rig, vfo_t vfo) +{ + int retval; + + rig_debug(RIG_DEBUG_TRACE, "%s: vfo=%s\n", __FUNCTION__, + rig_strvfo(vfo)); + + struct rig_state *rs = &rig->state; + struct trxmanager_priv_data *priv = (struct trxmanager_priv_data *) rig->state.priv; + + if (check_vfo(vfo) == FALSE) { + rig_debug(RIG_DEBUG_ERR, "%s: unsupported VFO %s\n", + __FUNCTION__, rig_strvfo(vfo)); + return -RIG_EINVAL; + } + if (vfo == RIG_VFO_TX) { + rig_debug(RIG_DEBUG_VERBOSE, "%s: RIG_VFO_TX used\n"); + vfo = RIG_VFO_B; // always TX on VFOB + } + + if (vfo == RIG_VFO_CURR) { + vfo = priv->vfo_curr; + } + + char cmd[MAXCMDLEN]; + char response[MAXCMDLEN]=""; + snprintf(cmd,sizeof(cmd), "FN%d;",vfo ==RIG_VFO_A ? 0 : 1); + retval = write_block(&rs->rigport, cmd, strlen(cmd)); + if (retval < 0) { + return retval; + } + + priv->vfo_curr = vfo; + rs->tx_vfo = RIG_VFO_B; // always VFOB + retval = read_transaction(rig, response, sizeof(response)); + if (retval != RIG_OK) { + rig_debug(RIG_DEBUG_ERR,"%s read_transaction failed\n", __FUNCTION__); + } + + return RIG_OK; +} + +static int trxmanager_get_vfo(RIG *rig, vfo_t *vfo) +{ + // TRXManager does not swap vfos + // So we maintain our own internal state during set_vfo + // This keeps the hamlib interface consistent with other rigs + + rig_debug(RIG_DEBUG_TRACE, "%s\n", __FUNCTION__); + + struct trxmanager_priv_data *priv = (struct trxmanager_priv_data *) rig->state.priv; + + char vfoab = priv->vfo_curr; + + switch (vfoab) { + case RIG_VFO_A: + *vfo = RIG_VFO_A; + break; + + case RIG_VFO_B: + *vfo = RIG_VFO_B; + break; + + default: + priv->vfo_curr = *vfo; + *vfo = RIG_VFO_CURR; + return -RIG_EINVAL; + } + + if (check_vfo(*vfo) == FALSE) { + rig_debug(RIG_DEBUG_ERR, "%s: unsupported VFO %s\n", + __FUNCTION__, rig_strvfo(*vfo)); + return -RIG_EINVAL; + } + + priv->vfo_curr = *vfo; + + rig_debug(RIG_DEBUG_VERBOSE, "%s: vfo=%s\n", __FUNCTION__, + rig_strvfo(*vfo)); + + return RIG_OK; +} + +/* + * trxmanager_set_split_freq + */ +static int trxmanager_set_split_freq(RIG *rig, vfo_t vfo, freq_t tx_freq) +{ + int retval; + + rig_debug(RIG_DEBUG_TRACE, "%s: vfo=%s freq=%.1f\n", __FUNCTION__, + rig_strvfo(vfo), tx_freq); + + struct rig_state *rs = &rig->state; + + if (check_vfo(vfo) == FALSE) { + rig_debug(RIG_DEBUG_ERR, "%s: unsupported VFO %s\n", + __FUNCTION__, rig_strvfo(vfo)); + return -RIG_EINVAL; + } + + char cmd[MAXCMDLEN]; + char response[MAXCMDLEN]=""; + snprintf(cmd,sizeof(cmd),"XT%011ld;", (unsigned long) tx_freq); + retval = write_block(&rs->rigport, cmd, strlen(cmd)); + if (retval < 0) { + return retval; + } + retval = read_transaction(rig, response, sizeof(response)); // get response but don't care + if (retval != RIG_OK) { + rig_debug(RIG_DEBUG_ERR,"%s read_transaction failed\n", __FUNCTION__); + } + + return RIG_OK; +} + +/* + * trxmanager_get_split_freq + * assumes rig!=NULL, tx_freq!=NULL + */ +static int trxmanager_get_split_freq(RIG *rig, vfo_t vfo, freq_t *tx_freq) +{ + rig_debug(RIG_DEBUG_TRACE, "%s: vfo=%s\n", __FUNCTION__, + rig_strvfo(vfo)); + int retval = trxmanager_get_freq(rig, RIG_VFO_B, tx_freq); + return retval; +} + +/* + * trxmanager_set_split_vfo + * assumes rig!=NULL, tx_freq!=NULL + */ +static int trxmanager_set_split_vfo(RIG *rig, vfo_t vfo, split_t split, vfo_t tx_vfo) +{ + int retval; + + rig_debug(RIG_DEBUG_TRACE, "%s: tx_vfo=%s\n", __FUNCTION__, + rig_strvfo(tx_vfo)); + + struct rig_state *rs = &rig->state; + + if (tx_vfo == RIG_VFO_SUB || tx_vfo == RIG_VFO_TX) { + tx_vfo = RIG_VFO_B; + } + + /* for flrig we have to be on VFOA when we set split for VFOB Tx */ + /* we can keep the rig on VFOA since we can set freq by VFO now */ + if (!vfo_curr(rig, RIG_VFO_A)) { + trxmanager_set_vfo(rig, RIG_VFO_A); + } + char cmd[MAXCMDLEN]; + char response[MAXCMDLEN]=""; + snprintf(cmd,sizeof(cmd),"SP%c;", split ? '1' : '0'); + retval = write_block(&rs->rigport, cmd, strlen(cmd)); + + if (retval < 0) { + return retval; + } + + retval = read_transaction(rig, response, sizeof(response)); // get response but don't care + if (retval != RIG_OK) { + rig_debug(RIG_DEBUG_ERR,"%s read_transaction failed\n", __FUNCTION__); + } + + if (strlen(response)!=6 || strstr(response, cmd)==NULL) { + rig_debug(RIG_DEBUG_ERR, "%s invalid response='%s'\n", __FUNCTION__, response); + return -RIG_EPROTO; + } + + return RIG_OK; +} + +/* + * trxmanager_get_split_vfo + * assumes rig!=NULL, tx_freq!=NULL + */ +static int trxmanager_get_split_vfo(RIG *rig, vfo_t vfo, split_t *split, vfo_t *tx_vfo) +{ + int retval; + + rig_debug(RIG_DEBUG_TRACE, "%s\n", __FUNCTION__); + struct rig_state *rs = &rig->state; + struct trxmanager_priv_data *priv = (struct trxmanager_priv_data *) rig->state.priv; + + char cmd[MAXCMDLEN]; + char response[MAXCMDLEN]=""; + snprintf(cmd,sizeof(cmd),"SP;"); + retval = write_block(&rs->rigport, cmd, strlen(cmd)); + if (retval < 0) { + return retval; + } + retval = read_transaction(rig, response, sizeof(response)); // get response but don't care + if (retval != RIG_OK) { + rig_debug(RIG_DEBUG_ERR,"%s read_transaction failed\n", __FUNCTION__); + } + + *tx_vfo = RIG_VFO_B; + int tsplit=0; + int n = sscanf(response,"SP%d",&tsplit); + if (n == 0) { + rig_debug(RIG_DEBUG_ERR, "%s error getting split from '%s'\n", __FUNCTION__,response); + } + *split = tsplit; + priv->split = *split; + return RIG_OK; +} + +/* + * trxmanager_set_split_freq_mode + * assumes rig!=NULL + */ +static int trxmanager_set_split_freq_mode(RIG *rig, vfo_t vfo, freq_t freq, rmode_t mode, pbwidth_t width) +{ + int retval; + + rig_debug(RIG_DEBUG_TRACE, "%s\n", __FUNCTION__); + + struct rig_state *rs = &rig->state; + struct trxmanager_priv_data *priv = (struct trxmanager_priv_data *) rig->state.priv; + + if (vfo != RIG_VFO_CURR && vfo != RIG_VFO_TX) + return -RIG_ENTARGET; + + // assume split is on B + // + char cmd[MAXCMDLEN]; + char response[MAXCMDLEN]=""; + snprintf(cmd,sizeof(cmd),"XT%011ld;",(unsigned long)freq); + retval = write_block(&rs->rigport, cmd, strlen(cmd)); + if (retval < 0) { + return retval; + } + retval = read_transaction(rig, response, sizeof(response)); + if (retval != RIG_OK) { + rig_debug(RIG_DEBUG_ERR,"%s read_transaction failed\n", __FUNCTION__); + } + if (strlen(response)!=16 || strstr(response, cmd)==NULL) { + rig_debug(RIG_DEBUG_ERR, "%s invalid response='%s'\n", __FUNCTION__, response); + FILE *fp=fopen("debug.txt","w+"); + fprintf(fp,"XT response=%s\n",response); + fclose(fp); + return -RIG_EPROTO; + } + priv->split = 1; // XT command also puts rig in split + + return retval; +} + +/* + * trxmanager_get_split_freq_mode + * assumes rig!=NULL, freq!=NULL, mode!=NULL, width!=NULL + */ +static int trxmanager_get_split_freq_mode(RIG *rig, vfo_t vfo, freq_t *freq, rmode_t *mode, pbwidth_t *width) +{ + int retval; + + if (vfo != RIG_VFO_CURR && vfo != RIG_VFO_TX) + return -RIG_ENTARGET; + + retval = trxmanager_get_freq (rig, RIG_VFO_B, freq); + if (RIG_OK == retval) { + retval = trxmanager_get_mode(rig,vfo,mode,width); + } + + return retval; +} + + +static const char *trxmanager_get_info(RIG *rig) +{ + struct trxmanager_priv_data *priv = (struct trxmanager_priv_data *) rig->state.priv; + rig_debug(RIG_DEBUG_VERBOSE, "%s called\n", __FUNCTION__); + + return priv->info; +} + diff --git a/dummy/trxmanager.h b/dummy/trxmanager.h new file mode 100644 index 000000000..e7e377edb --- /dev/null +++ b/dummy/trxmanager.h @@ -0,0 +1,41 @@ +/* + * Hamlib TRXManager backend - main header + * Copyright (c) 2017 by Michael Black W9MDB + * Copyright (c) 2018 by Michael Black W9MDB + * Derived from flrig.h + * + * + * 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 _TRXMANAGER_H +#define _TRXMANAGER_H 1 + +#include "hamlib/rig.h" + +#ifdef HAVE_SYS_TIME_H +#include +#endif + +#define BACKEND_VER "1.0" + +#define EOM "\r" +#define TRUE 1 +#define FALSE 0 + +extern struct rig_caps trxmanager_caps; + +#endif /* _TRXMANAGER_H */ diff --git a/include/hamlib/riglist.h b/include/hamlib/riglist.h index 923cf20ac..87ca8081f 100644 --- a/include/hamlib/riglist.h +++ b/include/hamlib/riglist.h @@ -61,6 +61,7 @@ #define RIG_MODEL_NETRIGCTL RIG_MAKE_MODEL(RIG_DUMMY, 2) #define RIG_MODEL_ARMSTRONG RIG_MAKE_MODEL(RIG_DUMMY, 3) #define RIG_MODEL_FLRIG RIG_MAKE_MODEL(RIG_DUMMY, 4) +#define RIG_MODEL_TRXMANAGER_RIG RIG_MAKE_MODEL(RIG_DUMMY, 5) /* From 8d53a025eda47074454477917cb2dfad4e168c67 Mon Sep 17 00:00:00 2001 From: Michael Black W9MDB Date: Tue, 8 May 2018 06:49:27 -0500 Subject: [PATCH 08/17] Update dummy.h for TRXManger --- dummy/dummy.h | 1 + 1 file changed, 1 insertion(+) diff --git a/dummy/dummy.h b/dummy/dummy.h index 30466a589..142f5622f 100644 --- a/dummy/dummy.h +++ b/dummy/dummy.h @@ -40,5 +40,6 @@ extern const struct rig_caps dummy_caps; extern const struct rig_caps netrigctl_caps; extern const struct rig_caps flrig_caps; +extern const struct rig_caps trxmanager_caps; #endif /* _DUMMY_H */ From 2e6877a1963df38d47e9227f99c5a327aa13c6e8 Mon Sep 17 00:00:00 2001 From: "Brian G. Lucas" Date: Tue, 8 May 2018 16:34:53 -0500 Subject: [PATCH 09/17] WIP: thd72 driver. More interfaces implemented. Other cleanup. --- kenwood/thd72.c | 217 ++++++++++++++++++++++++++++++++++++------------ 1 file changed, 165 insertions(+), 52 deletions(-) diff --git a/kenwood/thd72.c b/kenwood/thd72.c index 71452519e..e264f4fab 100644 --- a/kenwood/thd72.c +++ b/kenwood/thd72.c @@ -117,6 +117,22 @@ static int thd72apo[4] = { [3] = 60 }; +static tone_t thd72dcs_codes[104] = { + 23, 25, 26, 31, 32, 36, 43, 47, + 51, 53, 54, 65, 71, 72, 73, 74, + 114, 115, 116, 122, 125, 131, 132, 134, + 143, 145, 152, 155, 156, 162, 165, 172, + 174, 205, 212, 223, 225, 226, 243, 244, + 245, 246, 251, 252, 255, 261, 263, 265, + 266, 271, 274, 306, 311, 315, 325, 331, + 332, 343, 346, 351, 356, 364, 365, 371, + 411, 412, 413, 423, 431, 432, 445, 446, + 452, 454, 455, 462, 464, 465, 466, 503, + 506, 516, 523, 526, 532, 546, 565, 606, + 612, 624, 627, 631, 632, 654, 662, 664, + 703, 712, 723, 731, 732, 734, 743, 754 +}; + static struct kenwood_priv_caps thd72_priv_caps = { .cmdtrm = EOM_TH, /* Command termination character */ .mode_table = thd72_mode_table, @@ -200,7 +216,7 @@ static int thd72_vfoc(RIG *rig, vfo_t vfo, char *vfoc) static int thd72_get_freq_info(RIG *rig, vfo_t vfo, char *buf) { - int retval, length; + int retval; char c, cmd[8]; retval = thd72_vfoc(rig, vfo, &c); @@ -208,11 +224,40 @@ static int thd72_get_freq_info(RIG *rig, vfo_t vfo, char *buf) return retval; sprintf(cmd, "FO %c", c); retval = kenwood_transaction(rig, cmd, buf, 53); - length = strlen(buf); - rig_debug(RIG_DEBUG_TRACE, "%s: length=%d\n", __func__, length); return RIG_OK; } +/* item is an offset into reply buf that is a single char */ +static int thd72_get_freq_item(RIG *rig, vfo_t vfo, int item, int hi, int *val) +{ + int retval, lval; + char c, buf[64]; + + retval = thd72_get_freq_info(rig, vfo, buf); + if (retval != RIG_OK) + return retval; + c = buf[item]; + if (c < '0' || c > '9') + return -RIG_EPROTO; + lval = c - '0'; + if (lval > hi) + return -RIG_EPROTO; + *val = lval; + return RIG_OK; +} + +static int thd72_set_freq_item(RIG *rig, vfo_t vfo, int item, int val) +{ + int retval; + char buf[64]; + + retval = thd72_get_freq_info(rig, vfo, buf); + if (retval != RIG_OK) + return retval; + buf[item] = val + '0'; + return kenwood_simple_transaction(rig, buf, 52); +} + static int thd72_set_freq(RIG *rig, vfo_t vfo, freq_t freq) { int retval; @@ -245,84 +290,61 @@ static int thd72_get_freq(RIG *rig, vfo_t vfo, freq_t *freq) static int thd72_set_mode(RIG *rig, vfo_t vfo, rmode_t mode, pbwidth_t width) { - int retval; - char modec, buf[64]; + int val; rig_debug(RIG_DEBUG_TRACE, "%s: called\n", __func__); - retval = thd72_get_freq_info(rig, vfo, buf); - if (retval != RIG_OK) - return retval; switch (mode) { - case RIG_MODE_FM: modec = '0'; break; - case RIG_MODE_FMN: modec = '1'; break; - case RIG_MODE_AM: modec = '2'; break; + case RIG_MODE_FM: val = 0; break; + case RIG_MODE_FMN: val = 1; break; + case RIG_MODE_AM: val = 2; break; default: return -RIG_EINVAL; } - buf[51] = modec; - retval = kenwood_simple_transaction(rig, buf, 52); - return retval; + return thd72_set_freq_item(rig, vfo, 51, val); } static int thd72_get_mode(RIG *rig, vfo_t vfo, rmode_t *mode, pbwidth_t *width) { - int retval; - char modec, buf[64]; + int retval, modeinx; rig_debug(RIG_DEBUG_TRACE, "%s: called\n", __func__); - retval = thd72_get_freq_info(rig, vfo, buf); + retval = thd72_get_freq_item(rig, vfo, 51, 2, &modeinx); if (retval != RIG_OK) return retval; - modec = buf[51]; - if (modec >= '0' && modec <= '2') { - *mode = thd72_mode_table[modec - '0']; - *width = thd72_width_table[modec - '0']; - } - else - return -RIG_EINVAL; + *mode = thd72_mode_table[modeinx]; + *width = thd72_width_table[modeinx]; return RIG_OK; } static int thd72_set_rptr_shft(RIG *rig, vfo_t vfo, rptr_shift_t rptr_shift) { - int retval; - char shftc, buf[64]; + int rsinx; rig_debug(RIG_DEBUG_TRACE, "%s: called\n", __func__); - retval = thd72_get_freq_info(rig, vfo, buf); - if (retval != RIG_OK) - return retval; switch (rptr_shift) { - case RIG_RPT_SHIFT_NONE: shftc = '0'; break; - case RIG_RPT_SHIFT_PLUS: shftc = '1'; break; - case RIG_RPT_SHIFT_MINUS: shftc = '1'; break; + case RIG_RPT_SHIFT_NONE: rsinx = 0; break; + case RIG_RPT_SHIFT_PLUS: rsinx = 1; break; + case RIG_RPT_SHIFT_MINUS: rsinx = 2; break; default: return -RIG_EINVAL; } - buf[18] = shftc; - retval = kenwood_simple_transaction(rig, buf, 52); - return retval; + return thd72_set_freq_item(rig, vfo, 18, rsinx); } static int thd72_get_rptr_shft(RIG *rig, vfo_t vfo, rptr_shift_t *rptr_shift) { - int retval; - char shftc, buf[64]; + int retval, rsinx; rig_debug(RIG_DEBUG_TRACE, "%s: called\n", __func__); - retval = thd72_get_freq_info(rig, vfo, buf); + retval = thd72_get_freq_item(rig, vfo, 18, 2, &rsinx); if (retval != RIG_OK) return retval; - shftc = buf[18]; - if (shftc >= '0' && shftc <= '2') - *rptr_shift = thd72_rshf_table[shftc - '0']; - else - return -RIG_EINVAL; - return retval; + *rptr_shift = thd72_rshf_table[rsinx]; + return RIG_OK; } @@ -356,18 +378,62 @@ static int thd72_get_rptr_offs(RIG *rig, vfo_t vfo, shortfreq_t *offs) return RIG_OK; } +static int thd72_set_ts(RIG *rig, vfo_t vfo, shortfreq_t ts) +{ + int tsinx; + + rig_debug(RIG_DEBUG_TRACE, "%s: called\n", __func__); + + for (tsinx = 0; tsinx < 10; tsinx++) { + if (thd72tuningstep[tsinx] >= ts) { + thd72_set_freq_item(rig, vfo, 16, tsinx); + return RIG_OK; + } + } + return -RIG_EINVAL; +} + +static int thd72_get_ts(RIG *rig, vfo_t vfo, shortfreq_t *ts) +{ + int retval, tsinx; + + rig_debug(RIG_DEBUG_TRACE, "%s: called\n", __func__); + + retval = thd72_get_freq_item(rig, vfo, 16, 9, &tsinx); + if (retval != RIG_OK) + return retval; + *ts = thd72tuningstep[tsinx]; + return RIG_OK; +} + static int thd72_set_ctcss_tone(RIG *rig, vfo_t vfo, tone_t tone) { - int retval; + int retval, tinx; + char buf[64], tmp[4]; - retval = -RIG_EINVAL; /** TEMP **/ - return retval; + rig_debug(RIG_DEBUG_TRACE, "%s: called\n", __func__); + + tinx = 0; /* default */ + if (tone != 0) { + for (tinx = 0; tinx < 42; tinx++) { + if (tone == kenwood42_ctcss_list[tinx]) + break; + } + if (tinx >= 42) + return -RIG_EINVAL; + } + retval = thd72_get_freq_info(rig, vfo, buf); + if (retval != RIG_OK) + return retval; + buf[22] = (tone == 0) ? '0' : '1'; + sprintf(tmp, "%02d", tinx); + memcpy(buf+30, tmp, 2); + return kenwood_simple_transaction(rig, buf, 52); } static int thd72_get_ctcss_tone(RIG *rig, vfo_t vfo, tone_t *tone) { - int retval; - int tinx; + int retval, tinx; char buf[64]; rig_debug(RIG_DEBUG_TRACE, "%s: called\n", __func__); @@ -387,6 +453,50 @@ static int thd72_get_ctcss_tone(RIG *rig, vfo_t vfo, tone_t *tone) return RIG_OK; } +static int thd72_set_dcs_code(RIG *rig, vfo_t vfo, tone_t code) +{ + int retval, cinx; + char buf[64], tmp[4]; + + rig_debug(RIG_DEBUG_TRACE, "%s: called\n", __func__); + + cinx = 0; /* default */ + if (code != 0) { + for (cinx = 0; cinx < 104; cinx++) { + if (code == thd72dcs_codes[cinx]) + break; + } + if (cinx >= 104) + return -RIG_EINVAL; + } + retval = thd72_get_freq_info(rig, vfo, buf); + if (retval != RIG_OK) + return retval; + buf[26] = (code == 0) ? '0' : '1'; + sprintf(tmp, "%03d", cinx); + memcpy(buf+36, tmp, 3); + return kenwood_simple_transaction(rig, buf, 52); +} + +static int thd72_get_dcs_code(RIG *rig, vfo_t vfo, tone_t *code) +{ + int retval, cinx; + char buf[64]; + + rig_debug(RIG_DEBUG_TRACE, "%s: called\n", __func__); + + retval = thd72_get_freq_info(rig, vfo, buf); + if (retval != RIG_OK) + return retval; + if (buf[26] == '0') /* no tone */ + *code = 0; + else { + sscanf(buf+36, "%d", &cinx); + *code = thd72dcs_codes[cinx]; + } + return RIG_OK; +} + static int thd72_get_menu_info(RIG *rig, char *buf) { int retval; @@ -997,11 +1107,14 @@ const struct rig_caps thd72a_caps = { .get_rptr_shift = thd72_get_rptr_shft, .set_rptr_offs = thd72_set_rptr_offs, .get_rptr_offs = thd72_get_rptr_offs, +.set_ts = thd72_set_ts, +.get_ts = thd72_get_ts, .set_ctcss_tone = thd72_set_ctcss_tone, .get_ctcss_tone = thd72_get_ctcss_tone, -// set/get dcs_code -//.set_ctcss_sql = th_set_ctcss_sql, -//.get_ctcss_sql = th_get_ctcss_sql, +.set_dcs_code = thd72_set_dcs_code, +.get_dcs_code = thd72_get_dcs_code, +//.set_tone_sql = th_set_tone_sql, +//.get_tone_sql = th_get_tone_sql, .set_level = thd72_set_level, .get_level = thd72_get_level, .set_func = thd72_set_func, From a91e85e9fa91aa7ef8b440a9ec9d3d9b9999c5e9 Mon Sep 17 00:00:00 2001 From: Michael Black W9MDB Date: Tue, 8 May 2018 22:37:32 -0500 Subject: [PATCH 10/17] Allow rigctld to continue operating after tcp or serial rig disappears --- tests/rigctl_parse.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/tests/rigctl_parse.c b/tests/rigctl_parse.c index ba7a0f37d..b6b5a949c 100644 --- a/tests/rigctl_parse.c +++ b/tests/rigctl_parse.c @@ -593,7 +593,11 @@ extern int vfo_mode; extern char send_cmd_term; int ext_resp = 0; unsigned char resp_sep = '\n'; /* Default response separator */ - +/* Note that vfo_mode and ext_resp are not thread safe + * So to run either a vfo_mode or ext_resp mode rigctld it needs to be + * on a separate rigctld instance on a different port. One port per vfo_mode/ext_resp combination for a maximum of 4 instances/ports to cover all 4 combos + * Significant rewrite to fix this for 1 instance + */ int rigctl_parse(RIG *my_rig, FILE *fin, FILE *fout, char *argv[], int argc, sync_cb_t sync_cb) { @@ -1564,6 +1568,7 @@ int rigctl_parse(RIG *my_rig, FILE *fin, FILE *fout, char *argv[], int argc, syn if (sync_cb) sync_cb (0); /* unlock if necessary */ + if (retcode == RIG_EIO) return retcode; if (retcode != RIG_OK) { /* only for rigctld */ From cd1fdfe6cef73fda90bd821b121094a70bfde4ee Mon Sep 17 00:00:00 2001 From: Michael Black W9MDB Date: Wed, 9 May 2018 07:31:42 -0500 Subject: [PATCH 11/17] Allow rotctld to continue operationg aftr tcp or serial rig disappears --- tests/rotctl_parse.c | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/rotctl_parse.c b/tests/rotctl_parse.c index ca9e746e1..d9c9b56a7 100644 --- a/tests/rotctl_parse.c +++ b/tests/rotctl_parse.c @@ -1427,6 +1427,7 @@ int rotctl_parse(ROT *my_rot, FILE *fin, FILE *fout, char *argv[], int argc) pthread_mutex_unlock(&rot_mutex); #endif + if (retcode == RIG_EIO) return retcode; if (retcode != RIG_OK) { /* only for rotctld */ From ae30a9fb3ad8ecf0f11af2dec724e0f0acce1b76 Mon Sep 17 00:00:00 2001 From: Michael Black W9MDB Date: Wed, 9 May 2018 08:14:04 -0500 Subject: [PATCH 12/17] Fix read_string terminator length parameters --- dummy/netrigctl.c | 56 ++++++++++++++++++++++++----------------------- 1 file changed, 29 insertions(+), 27 deletions(-) diff --git a/dummy/netrigctl.c b/dummy/netrigctl.c index 0f51e18fe..823c52433 100644 --- a/dummy/netrigctl.c +++ b/dummy/netrigctl.c @@ -52,9 +52,11 @@ static int netrigctl_transaction(RIG *rig, char *cmd, int len, char *buf) { int ret; + rig_debug(RIG_DEBUG_VERBOSE,"%s: called len=%d\n",__FUNCTION__,len); + /* flush anything in the read buffer before command is sent */ if (rig->state.rigport.type.rig == RIG_PORT_NETWORK || rig->state.rigport.type.rig == RIG_PORT_UDP_NETWORK) { - network_flush(&rig->state.rigport); + network_flush(&rig->state.rigport); } else { serial_flush(&rig->state.rigport); } @@ -63,14 +65,14 @@ static int netrigctl_transaction(RIG *rig, char *cmd, int len, char *buf) if (ret != RIG_OK) return ret; - ret = read_string(&rig->state.rigport, buf, BUF_MAX, "\n", sizeof("\n")); + ret = read_string(&rig->state.rigport, buf, BUF_MAX, "\n", 1); if (ret < 0) return ret; - if (!memcmp(buf, NETRIGCTL_RET, strlen(NETRIGCTL_RET))) + if (memcmp(buf, NETRIGCTL_RET, strlen(NETRIGCTL_RET))==0) return atoi(buf+strlen(NETRIGCTL_RET)); - return ret; + return RIG_OK; } @@ -96,18 +98,18 @@ static int netrigctl_open(RIG *rig) if (prot_ver < RIGCTLD_PROT_VER) return -RIG_EPROTO; - ret = read_string(&rig->state.rigport, buf, BUF_MAX, "\n", sizeof("\n")); + ret = read_string(&rig->state.rigport, buf, BUF_MAX, "\n", 1); if (ret <= 0) return (ret < 0) ? ret : -RIG_EPROTO; - ret = read_string(&rig->state.rigport, buf, BUF_MAX, "\n", sizeof("\n")); + ret = read_string(&rig->state.rigport, buf, BUF_MAX, "\n", 1); if (ret <= 0) return (ret < 0) ? ret : -RIG_EPROTO; rs->itu_region = atoi(buf); for (i=0; istate.rigport, buf, BUF_MAX, "\n", sizeof("\n")); + ret = read_string(&rig->state.rigport, buf, BUF_MAX, "\n", 1); if (ret <= 0) return (ret < 0) ? ret : -RIG_EPROTO; @@ -126,7 +128,7 @@ static int netrigctl_open(RIG *rig) break; } for (i=0; istate.rigport, buf, BUF_MAX, "\n", sizeof("\n")); + ret = read_string(&rig->state.rigport, buf, BUF_MAX, "\n", 1); if (ret <= 0) return (ret < 0) ? ret : -RIG_EPROTO; @@ -145,7 +147,7 @@ static int netrigctl_open(RIG *rig) break; } for (i=0; istate.rigport, buf, BUF_MAX, "\n", sizeof("\n")); + ret = read_string(&rig->state.rigport, buf, BUF_MAX, "\n", 1); if (ret <= 0) return (ret < 0) ? ret : -RIG_EPROTO; @@ -159,7 +161,7 @@ static int netrigctl_open(RIG *rig) } for (i=0; istate.rigport, buf, BUF_MAX, "\n", sizeof("\n")); + ret = read_string(&rig->state.rigport, buf, BUF_MAX, "\n", 1); if (ret <= 0) return (ret < 0) ? ret : -RIG_EPROTO; @@ -177,31 +179,31 @@ static int netrigctl_open(RIG *rig) chan_t chan_list[CHANLSTSIZ]; /*!< Channel list, zero ended */ #endif - ret = read_string(&rig->state.rigport, buf, BUF_MAX, "\n", sizeof("\n")); + ret = read_string(&rig->state.rigport, buf, BUF_MAX, "\n", 1); if (ret <= 0) return (ret < 0) ? ret : -RIG_EPROTO; rs->max_rit = atol(buf); - ret = read_string(&rig->state.rigport, buf, BUF_MAX, "\n", sizeof("\n")); + ret = read_string(&rig->state.rigport, buf, BUF_MAX, "\n", 1); if (ret <= 0) return (ret < 0) ? ret : -RIG_EPROTO; rs->max_xit = atol(buf); - ret = read_string(&rig->state.rigport, buf, BUF_MAX, "\n", sizeof("\n")); + ret = read_string(&rig->state.rigport, buf, BUF_MAX, "\n", 1); if (ret <= 0) return (ret < 0) ? ret : -RIG_EPROTO; rs->max_ifshift = atol(buf); - ret = read_string(&rig->state.rigport, buf, BUF_MAX, "\n", sizeof("\n")); + ret = read_string(&rig->state.rigport, buf, BUF_MAX, "\n", 1); if (ret <= 0) return (ret < 0) ? ret : -RIG_EPROTO; rs->announces = atoi(buf); - ret = read_string(&rig->state.rigport, buf, BUF_MAX, "\n", sizeof("\n")); + ret = read_string(&rig->state.rigport, buf, BUF_MAX, "\n", 1); if (ret <= 0) return (ret < 0) ? ret : -RIG_EPROTO; @@ -214,7 +216,7 @@ chan_t chan_list[CHANLSTSIZ]; /*!< Channel list, zero ended */ ret = 0; rs->preamp[ret] = RIG_DBLST_END; - ret = read_string(&rig->state.rigport, buf, BUF_MAX, "\n", sizeof("\n")); + ret = read_string(&rig->state.rigport, buf, BUF_MAX, "\n", 1); if (ret <= 0) return (ret < 0) ? ret : -RIG_EPROTO; @@ -227,19 +229,19 @@ chan_t chan_list[CHANLSTSIZ]; /*!< Channel list, zero ended */ ret = 0; rs->attenuator[ret] = RIG_DBLST_END; - ret = read_string(&rig->state.rigport, buf, BUF_MAX, "\n", sizeof("\n")); + ret = read_string(&rig->state.rigport, buf, BUF_MAX, "\n", 1); if (ret <= 0) return (ret < 0) ? ret : -RIG_EPROTO; rs->has_get_func = strtol(buf, NULL, 0); - ret = read_string(&rig->state.rigport, buf, BUF_MAX, "\n", sizeof("\n")); + ret = read_string(&rig->state.rigport, buf, BUF_MAX, "\n", 1); if (ret <= 0) return (ret < 0) ? ret : -RIG_EPROTO; rs->has_set_func = strtol(buf, NULL, 0); - ret = read_string(&rig->state.rigport, buf, BUF_MAX, "\n", sizeof("\n")); + ret = read_string(&rig->state.rigport, buf, BUF_MAX, "\n", 1); if (ret <= 0) return (ret < 0) ? ret : -RIG_EPROTO; @@ -252,19 +254,19 @@ chan_t chan_list[CHANLSTSIZ]; /*!< Channel list, zero ended */ rs->has_get_level |= RIG_LEVEL_STRENGTH; } - ret = read_string(&rig->state.rigport, buf, BUF_MAX, "\n", sizeof("\n")); + ret = read_string(&rig->state.rigport, buf, BUF_MAX, "\n", 1); if (ret <= 0) return (ret < 0) ? ret : -RIG_EPROTO; rs->has_set_level = strtol(buf, NULL, 0); - ret = read_string(&rig->state.rigport, buf, BUF_MAX, "\n", sizeof("\n")); + ret = read_string(&rig->state.rigport, buf, BUF_MAX, "\n", 1); if (ret <= 0) return (ret < 0) ? ret : -RIG_EPROTO; rs->has_get_parm = strtol(buf, NULL, 0); - ret = read_string(&rig->state.rigport, buf, BUF_MAX, "\n", sizeof("\n")); + ret = read_string(&rig->state.rigport, buf, BUF_MAX, "\n", 1); if (ret <= 0) return (ret < 0) ? ret : -RIG_EPROTO; @@ -370,7 +372,7 @@ static int netrigctl_get_mode(RIG *rig, vfo_t vfo, rmode_t *mode, pbwidth_t *wid if (ret > 0 && buf[ret-1]=='\n') buf[ret-1] = '\0'; /* chomp */ *mode = rig_parse_mode(buf); - ret = read_string(&rig->state.rigport, buf, BUF_MAX, "\n", sizeof("\n")); + ret = read_string(&rig->state.rigport, buf, BUF_MAX, "\n", 1); if (ret <= 0) return (ret < 0) ? ret : -RIG_EPROTO; @@ -778,7 +780,7 @@ static int netrigctl_get_split_mode(RIG *rig, vfo_t vfo, rmode_t *tx_mode, pbwid if (ret > 0 && buf[ret-1]=='\n') buf[ret-1] = '\0'; /* chomp */ *tx_mode = rig_parse_mode(buf); - ret = read_string(&rig->state.rigport, buf, BUF_MAX, "\n", sizeof("\n")); + ret = read_string(&rig->state.rigport, buf, BUF_MAX, "\n", 1); if (ret <= 0) return (ret < 0) ? ret : -RIG_EPROTO; @@ -821,7 +823,7 @@ static int netrigctl_get_split_vfo(RIG *rig, vfo_t vfo, split_t *split, vfo_t *t *split = atoi(buf); - ret = read_string(&rig->state.rigport, buf, BUF_MAX, "\n", sizeof("\n")); + ret = read_string(&rig->state.rigport, buf, BUF_MAX, "\n", 1); if (ret <= 0) return (ret < 0) ? ret : -RIG_EPROTO; @@ -1343,9 +1345,9 @@ const struct rig_caps netrigctl_caps = { .rig_model = RIG_MODEL_NETRIGCTL, .model_name = "NET rigctl", .mfg_name = "Hamlib", - .version = "0.3", + .version = "1.0", .copyright = "LGPL", - .status = RIG_STATUS_BETA, + .status = RIG_STATUS_STABLE, .rig_type = RIG_TYPE_OTHER, .targetable_vfo = 0, .ptt_type = RIG_PTT_RIG_MICDATA, From 299bf17b22b05853d548dfa0f6d3c353bdf91835 Mon Sep 17 00:00:00 2001 From: Michael Black W9MDB Date: Wed, 9 May 2018 15:22:58 -0500 Subject: [PATCH 13/17] Fix modes on trxmanager --- dummy/trxmanager.c | 35 ++++++++++++++++++++++++----------- dummy/trxmanager.h | 2 +- 2 files changed, 25 insertions(+), 12 deletions(-) diff --git a/dummy/trxmanager.c b/dummy/trxmanager.c index f3644b4e1..d0771c9e1 100644 --- a/dummy/trxmanager.c +++ b/dummy/trxmanager.c @@ -50,7 +50,7 @@ #define TRXMANAGER_MODES (RIG_MODE_AM | RIG_MODE_CW | RIG_MODE_CWR |\ RIG_MODE_RTTY | RIG_MODE_RTTYR |\ RIG_MODE_PKTLSB | RIG_MODE_PKTUSB |\ - RIG_MODE_SSB | RIG_MODE_FM | RIG_MODE_WFM | RIG_MODE_FMN ) + RIG_MODE_USB | RIG_MODE_LSB | RIG_MODE_FM) #define streq(s1,s2) (strcmp(s1,s2)==0) @@ -98,7 +98,7 @@ struct rig_caps trxmanager_caps = { .port_type = RIG_PORT_NETWORK, .write_delay = 0, .post_write_delay = 0, - .timeout = 1000, + .timeout = 10000, // long timeout to allow for antenna tuning and such .retry = 3, .has_get_func = RIG_FUNC_NONE, @@ -260,6 +260,7 @@ static int trxmanager_open(RIG *rig) { struct rig_state *rs = &rig->state; struct trxmanager_priv_data *priv = (struct trxmanager_priv_data *) rig->state.priv; + rs->rigport.timeout = 10000; // long timeout for antenna switching/tuning retval = read_transaction(rig, response, sizeof(response)); if (retval != RIG_OK) { rig_debug(RIG_DEBUG_ERR,"%s read_transaction failed\n", __FUNCTION__); @@ -376,8 +377,8 @@ static int trxmanager_get_freq(RIG *rig, vfo_t vfo, freq_t *freq) *freq = 0; int n = sscanf(&response[2],"%lg",freq); if (n != 1) { + rig_debug(RIG_DEBUG_ERR, "%s: can't parse freq from %s", __FUNCTION__,response); } - rig_debug(RIG_DEBUG_ERR, "%s: can't parse freq from %s", __FUNCTION__,response); if (*freq == 0) { rig_debug(RIG_DEBUG_ERR, "%s: freq==0??\n", __FUNCTION__); return -RIG_EPROTO; @@ -553,15 +554,24 @@ static int trxmanager_set_mode(RIG *rig, vfo_t vfo, rmode_t mode, pbwidth_t widt case RIG_MODE_FM: ttmode=4; break; - case RIG_MODE_PKTUSB: + case RIG_MODE_AM: ttmode=5; break; - case RIG_MODE_CWR: + case RIG_MODE_RTTY: ttmode=6; break; - case RIG_MODE_PKTLSB: + case RIG_MODE_CWR: ttmode=7; break; + case RIG_MODE_RTTYR: + ttmode=9; + break; + case RIG_MODE_PKTLSB: + ttmode=9; + break; + case RIG_MODE_PKTUSB: + ttmode=9; + break; default: rig_debug(RIG_DEBUG_ERR, "%s: unsupported mode %s\n",__FUNCTION__,rig_strrmode(mode)); return -RIG_EINVAL; @@ -642,20 +652,23 @@ static int trxmanager_get_mode(RIG *rig, vfo_t vfo, rmode_t *mode, pbwidth_t *wi case '2': *mode=RIG_MODE_USB; break; - case '4': + case '3': *mode=RIG_MODE_CW; break; + case '4': + *mode=RIG_MODE_FM; + break; case '5': - *mode=RIG_MODE_PKTUSB; + *mode=RIG_MODE_AM; break; case '6': - *mode=RIG_MODE_CWR; + *mode=RIG_MODE_RTTY; break; case '7': - *mode=RIG_MODE_PKTLSB; + *mode=RIG_MODE_CWR; break; case '9': - *mode=RIG_MODE_PKTUSB; + *mode=RIG_MODE_RTTYR; break; case 'A': *mode=RIG_MODE_PKTLSB; diff --git a/dummy/trxmanager.h b/dummy/trxmanager.h index e7e377edb..c2fda3b3a 100644 --- a/dummy/trxmanager.h +++ b/dummy/trxmanager.h @@ -30,7 +30,7 @@ #include #endif -#define BACKEND_VER "1.0" +#define BACKEND_VER "1.1" #define EOM "\r" #define TRUE 1 From c35056ff15c70b661de5aca2ffa9ecedf6f4531b Mon Sep 17 00:00:00 2001 From: "Brian G. Lucas" Date: Wed, 9 May 2018 16:12:49 -0500 Subject: [PATCH 14/17] Implement some more interfaces. Comment out get_chan_all_cb because the block read routine doesn't work. --- kenwood/thd72.c | 207 +++++++++++++++++++++++++++++------------------- 1 file changed, 126 insertions(+), 81 deletions(-) diff --git a/kenwood/thd72.c b/kenwood/thd72.c index e264f4fab..fc4569234 100644 --- a/kenwood/thd72.c +++ b/kenwood/thd72.c @@ -38,22 +38,18 @@ #define THD72_MODES (RIG_MODE_FM|RIG_MODE_FMN|RIG_MODE_AM) #define THD72_MODES_TX (RIG_MODE_FM|RIG_MODE_FMN) -#define THD72_FUNC_ALL (RIG_FUNC_TSQL| \ - RIG_FUNC_AIP| \ - RIG_FUNC_MON| \ - RIG_FUNC_SQL| \ - RIG_FUNC_TONE| \ - RIG_FUNC_REV| \ - RIG_FUNC_LOCK| \ +#define THD72_FUNC_ALL (RIG_FUNC_TSQL| \ + RIG_FUNC_AIP| \ + RIG_FUNC_TONE| \ RIG_FUNC_ARO) -#define THD72_LEVEL_ALL (RIG_LEVEL_RFPOWER|\ - RIG_LEVEL_SQL|\ - RIG_LEVEL_BALANCE|\ - RIG_LEVEL_VOXGAIN|\ +#define THD72_LEVEL_ALL (RIG_LEVEL_RFPOWER| \ + RIG_LEVEL_SQL| \ + RIG_LEVEL_BALANCE| \ + RIG_LEVEL_VOXGAIN| \ RIG_LEVEL_VOXDELAY) -#define THD72_PARMS (RIG_PARM_APO|\ +#define THD72_PARMS (RIG_PARM_APO| \ RIG_PARM_TIME) #define THD72_VFO_OP (RIG_OP_NONE) @@ -117,7 +113,7 @@ static int thd72apo[4] = { [3] = 60 }; -static tone_t thd72dcs_codes[104] = { +static tone_t thd72dcs_list[105] = { 23, 25, 26, 31, 32, 36, 43, 47, 51, 53, 54, 65, 71, 72, 73, 74, 114, 115, 116, 122, 125, 131, 132, 134, @@ -130,7 +126,8 @@ static tone_t thd72dcs_codes[104] = { 452, 454, 455, 462, 464, 465, 466, 503, 506, 516, 523, 526, 532, 546, 565, 606, 612, 624, 627, 631, 632, 654, 662, 664, - 703, 712, 723, 731, 732, 734, 743, 754 + 703, 712, 723, 731, 732, 734, 743, 754, + 0 }; static struct kenwood_priv_caps thd72_priv_caps = { @@ -340,10 +337,11 @@ static int thd72_get_rptr_shft(RIG *rig, vfo_t vfo, rptr_shift_t *rptr_shift) rig_debug(RIG_DEBUG_TRACE, "%s: called\n", __func__); - retval = thd72_get_freq_item(rig, vfo, 18, 2, &rsinx); + retval = thd72_get_freq_item(rig, vfo, 18, 3, &rsinx); if (retval != RIG_OK) return retval; - *rptr_shift = thd72_rshf_table[rsinx]; + /* rsinx == 3 indicates split mode? */ + *rptr_shift = (rsinx == 3)? RIG_RPT_SHIFT_NONE: thd72_rshf_table[rsinx]; return RIG_OK; } @@ -463,7 +461,7 @@ static int thd72_set_dcs_code(RIG *rig, vfo_t vfo, tone_t code) cinx = 0; /* default */ if (code != 0) { for (cinx = 0; cinx < 104; cinx++) { - if (code == thd72dcs_codes[cinx]) + if (code == thd72dcs_list[cinx]) break; } if (cinx >= 104) @@ -492,7 +490,54 @@ static int thd72_get_dcs_code(RIG *rig, vfo_t vfo, tone_t *code) *code = 0; else { sscanf(buf+36, "%d", &cinx); - *code = thd72dcs_codes[cinx]; + *code = thd72dcs_list[cinx]; + } + return RIG_OK; +} + +static int thd72_set_ctcss_sql(RIG *rig, vfo_t vfo, tone_t tone) +{ + int retval, tinx; + char buf[64], tmp[4]; + + rig_debug(RIG_DEBUG_TRACE, "%s: called\n", __func__); + + tinx = 0; /* default */ + if (tone != 0) { + for (tinx = 0; tinx < 42; tinx++) { + if (tone == kenwood42_ctcss_list[tinx]) + break; + } + if (tinx >= 42) + return -RIG_EINVAL; + } + retval = thd72_get_freq_info(rig, vfo, buf); + if (retval != RIG_OK) + return retval; + buf[24] = (tone == 0) ? '0' : '1'; + sprintf(tmp, "%02d", tinx); + memcpy(buf+33, tmp, 2); + return kenwood_simple_transaction(rig, buf, 52); +} + +static int thd72_get_ctcss_sql(RIG *rig, vfo_t vfo, tone_t *tone) +{ + int retval, tinx; + char buf[64]; + + rig_debug(RIG_DEBUG_TRACE, "%s: called\n", __func__); + + retval = thd72_get_freq_info(rig, vfo, buf); + if (retval != RIG_OK) + return retval; + if (buf[24] == '0') /* no tsql */ + *tone = 0; + else { + sscanf(buf+33, "%d", &tinx); + if (tinx >= 0 && tinx <= 41) + *tone = kenwood42_ctcss_list[tinx]; + else + return -RIG_EINVAL; } return RIG_OK; } @@ -664,6 +709,12 @@ static int thd72_set_func(RIG *rig, vfo_t vfo, setting_t func, int status) if (retval != RIG_OK) return retval; return thd72_set_menu_item(rig, c == '0'?5:6, status); + case RIG_FUNC_ARO: + return thd72_set_menu_item(rig, 18, status); + case RIG_FUNC_TONE: + return thd72_set_freq_item(rig, vfo, 22, status); + case RIG_FUNC_TSQL: + return thd72_set_freq_item(rig, vfo, 24, status); default: return -RIG_EINVAL; } @@ -672,7 +723,7 @@ static int thd72_set_func(RIG *rig, vfo_t vfo, setting_t func, int status) static int thd72_get_func(RIG *rig, vfo_t vfo, setting_t func, int *status) { - int retval, l; + int retval, f; char c; rig_debug(RIG_DEBUG_TRACE, "%s: called\n", __func__); @@ -682,14 +733,23 @@ static int thd72_get_func(RIG *rig, vfo_t vfo, setting_t func, int *status) retval = thd72_vfoc(rig, vfo, &c); if (retval != RIG_OK) return retval; - retval = thd72_get_menu_item(rig, c == '0'?5:6, '1', &l); - if (retval != RIG_OK) - return retval; - *status = l; + retval = thd72_get_menu_item(rig, c == '0'?5:6, 1, &f); + break; + case RIG_FUNC_ARO: + retval = thd72_get_menu_item(rig, 18, 1, &f); + break; + case RIG_FUNC_TONE: + retval = thd72_get_freq_item(rig, vfo, 22, 1, &f); + break; + case RIG_FUNC_TSQL: + retval = thd72_get_freq_item(rig, vfo, 24, 1, &f); break; default: - return -RIG_EINVAL; + retval = -RIG_EINVAL; } + if (retval != RIG_OK) + return retval; + *status = f; return RIG_OK; } @@ -852,9 +912,11 @@ static int thd72_get_channel(RIG *rig, channel_t *chan) return RIG_OK; } +#ifdef false /* not working */ #define CMD_SZ 5 #define BLOCK_SZ 256 #define BLOCK_COUNT 256 +#define CHAN_PER_BLOCK 4 static int thd72_get_block (RIG *rig, int block_num, char *block) { @@ -872,7 +934,7 @@ static int thd72_get_block (RIG *rig, int block_num, char *block) /* read response first */ ret = read_block(rp, resp, CMD_SZ); - if (ret != RIG_OK) + if (ret != CMD_SZ) return ret; if (resp[0] != 'W' || memcmp(cmd+1, resp+1, CMD_SZ-1)) @@ -907,23 +969,21 @@ int thd72_get_chan_all_cb (RIG * rig, chan_cb_t chan_cb, rig_ptr_t arg) char block[BLOCK_SZ]; char resp[CMD_SZ]; - ret = kenwood_transaction(rig, "0M PROGRAM", NULL, 0); + ret = kenwood_transaction(rig, "0M PROGRAM", resp, CMD_SZ); if (ret != RIG_OK) return ret; + if (strlen(resp) != 2 || memcmp(resp, "0M", 2)) + return -RIG_EPROTO; rp->parm.serial.rate = 57600; - serial_setup(rp); - /* let the pcr settle and flush any remaining data*/ - usleep(100*1000); - serial_flush(rp); - /* setRTS or Hardware flow control? */ - ret = ser_set_rts(rp, 1); + usleep(100*1000); /* let the pcr settle */ + serial_flush(rp); /* flush any remaining data */ + ret = ser_set_rts(rp, 1); /* setRTS or Hardware flow control? */ if (ret != RIG_OK) return ret; - /* * setting chan to NULL means the application * has to provide a struct where to store data @@ -936,7 +996,6 @@ int thd72_get_chan_all_cb (RIG * rig, chan_cb_t chan_cb, rig_ptr_t arg) if (chan == NULL) return -RIG_ENOMEM; - for (i=0; ivfo = RIG_VFO_MEM; chan->channel_num = i*CHAN_PER_BLOCK + j; @@ -1002,7 +1057,7 @@ int thd72_get_chan_all_cb (RIG * rig, chan_cb_t chan_cb, rig_ptr_t arg) return RIG_OK; } - +#endif /* none working stuff */ /* * th-d72a rig capabilities. */ @@ -1025,9 +1080,8 @@ const struct rig_caps thd72a_caps = { .serial_handshake = RIG_HANDSHAKE_XONXOFF, .write_delay = 0, .post_write_delay = 0, -.timeout = 250, +.timeout = 500, .retry = 3, - .has_get_func = THD72_FUNC_ALL, .has_set_func = THD72_FUNC_ALL, .has_get_level = THD72_LEVEL_ALL, @@ -1040,8 +1094,8 @@ const struct rig_caps thd72a_caps = { [LVL_RFPOWER] = { .min = { .i = 2 }, .max = { .i = 0 } }, }, .parm_gran = {}, -.ctcss_list = kenwood38_ctcss_list, -.dcs_list = NULL, +.ctcss_list = kenwood42_ctcss_list, +.dcs_list = thd72dcs_list, .preamp = { RIG_DBLST_END, }, .attenuator = { RIG_DBLST_END, }, .max_rit = Hz(0), @@ -1052,48 +1106,42 @@ const struct rig_caps thd72a_caps = { .transceive = RIG_TRN_RIG, .bank_qty = 0, .chan_desc_sz = 6, /* TBC */ - .chan_list = { - { 0, 999, RIG_MTYPE_MEM , {TH_CHANNEL_CAPS}}, /* TBC MEM */ - RIG_CHAN_END, - }, - + { 0, 999, RIG_MTYPE_MEM , {TH_CHANNEL_CAPS}}, /* TBC MEM */ + RIG_CHAN_END, + }, .rx_range_list1 = { RIG_FRNG_END, }, /* FIXME: enter region 1 setting */ .tx_range_list1 = { RIG_FRNG_END, }, .rx_range_list2 = { {MHz(118),MHz(174),THD72_MODES,-1,-1,THD72_VFO}, {MHz(320),MHz(524),THD72_MODES,-1,-1,THD72_VFO}, - RIG_FRNG_END, - }, /* rx range */ + RIG_FRNG_END, + }, .tx_range_list2 = { {MHz(144),MHz(148),THD72_MODES_TX,W(0.05),W(5),THD72_VFO}, {MHz(430),MHz(440),THD72_MODES_TX,W(0.05),W(5),THD72_VFO}, - RIG_FRNG_END, - }, /* tx range */ - + RIG_FRNG_END, + }, .tuning_steps = { - {THD72_MODES,kHz(5)}, - {THD72_MODES,kHz(6.25)}, - /* kHz(8.33) ?? */ - {THD72_MODES,kHz(10)}, - {THD72_MODES,kHz(12.5)}, - {THD72_MODES,kHz(15)}, - {THD72_MODES,kHz(20)}, - {THD72_MODES,kHz(25)}, - {THD72_MODES,kHz(30)}, - {THD72_MODES,kHz(50)}, - {THD72_MODES,kHz(100)}, - RIG_TS_END, - }, - /* mode/filter list, remember: order matters! */ -.filters = { - {RIG_MODE_FM, kHz(14)}, - {RIG_MODE_FMN, kHz(7)}, - {RIG_MODE_AM, kHz(9)}, - RIG_FLT_END, - }, + {THD72_MODES,kHz(5)}, + {THD72_MODES,kHz(6.25)}, + {THD72_MODES,kHz(8.33)}, + {THD72_MODES,kHz(10)}, + {THD72_MODES,kHz(12.5)}, + {THD72_MODES,kHz(15)}, + {THD72_MODES,kHz(20)}, + {THD72_MODES,kHz(25)}, + {THD72_MODES,kHz(30)}, + {THD72_MODES,kHz(50)}, + RIG_TS_END, + }, + .filters = { /* mode/filter list, remember: order matters! */ + {RIG_MODE_FM, kHz(14)}, + {RIG_MODE_FMN, kHz(7)}, + {RIG_MODE_AM, kHz(9)}, + RIG_FLT_END, + }, .priv = (void *)&thd72_priv_caps, - .rig_init = kenwood_init, .rig_cleanup = kenwood_cleanup, .rig_open = thd72_open, @@ -1113,8 +1161,8 @@ const struct rig_caps thd72a_caps = { .get_ctcss_tone = thd72_get_ctcss_tone, .set_dcs_code = thd72_set_dcs_code, .get_dcs_code = thd72_get_dcs_code, -//.set_tone_sql = th_set_tone_sql, -//.get_tone_sql = th_get_tone_sql, +.set_ctcss_sql = thd72_set_ctcss_sql, +.get_ctcss_sql = thd72_get_ctcss_sql, .set_level = thd72_set_level, .get_level = thd72_get_level, .set_func = thd72_set_func, @@ -1125,9 +1173,6 @@ const struct rig_caps thd72a_caps = { .get_mem = thd72_get_mem, .set_channel = thd72_set_channel, .get_channel = thd72_get_channel, - -.get_chan_all_cb = thd72_get_chan_all_cb, - +//.get_chan_all_cb = thd72_get_chan_all_cb, this doesn't work yet .get_info = th_get_info, - }; From b8cd8c0a9a4b3bf613a9b3d5a586ec2e5d57c183 Mon Sep 17 00:00:00 2001 From: Michael Black W9MDB Date: Wed, 9 May 2018 23:01:55 -0500 Subject: [PATCH 15/17] FLRig thread safety improved and now works WSJT-X split mode with multiple connections --- doc/man1/rigctld.1 | 2 +- dummy/flrig.README | 10 +- dummy/flrig.c | 1369 ++++++++++++++++++++++++++++++-------------- dummy/flrig.h | 3 +- 4 files changed, 960 insertions(+), 424 deletions(-) diff --git a/doc/man1/rigctld.1 b/doc/man1/rigctld.1 index 05d86f800..ae53814e5 100644 --- a/doc/man1/rigctld.1 +++ b/doc/man1/rigctld.1 @@ -41,7 +41,7 @@ sockets. This allows multiple user programs to share one radio (this needs more development). Multiple radios can be controlled on different TCP ports by use of multiple .B rigctld -processes. The syntax of the commands are the same as +processes. Note that multiple processes/ports are also necessary if some clients use extended responses and/or vfo mode. So up to 4 processes/ports may be needed for each combination of extended response/vfo mode. The syntax of the commands are the same as .BR rigctl (1). It is hoped that .B rigctld diff --git a/dummy/flrig.README b/dummy/flrig.README index 4946c3833..47be8bfd6 100644 --- a/dummy/flrig.README +++ b/dummy/flrig.README @@ -1,5 +1,7 @@ -As of version 0.1 this works well with rigs have a full ack/nak protocol as coded in FLRig. So Kenwood, Icom and such. -But Yaesu rigs for example are not stable with applications like WSJT-X since the FLRig driver does not wait or obtain status after frequency change commands for example (fire and forget). Hamlib's Yaesu drivers always send and ID request after such commands and wait for an appropriate response but FLRig does not so can miss commands as a result. Slow operation (manual command from rigctl) works fine. -Rig drivers in FLRig will have to be changed to allow stable operation with fast comm programs like WJST-X. - +As of version 1.0 20180508 this works very well with flrig-1.3.40.50 and WSJT-X split mode. +Log4OM can be run conconcurrently connecting to "rigctld -M 4". +Note that for that Log4OM instance only clients that use extended protocol can connect to the client (since Log4OM uses extended protocol). If you want to use a client that does not have extended protocol you must run another rigctld on a separate TCP port. +The same thing holds for any vfo mode clients. +So you could end up with 4 rigctld's. One for each combination of extended/vfo mode. +Flrig can now handle numerous clients connecting at once thanks to a lot of work done by Dave W1HKJ de Mike W9MDB diff --git a/dummy/flrig.c b/dummy/flrig.c index e156076d6..a96c96426 100644 --- a/dummy/flrig.c +++ b/dummy/flrig.c @@ -1,7 +1,7 @@ - /* * Hamlib FLRig backend - main file * Copyright (c) 2017 by Michael Black W9MDB + * Copyright (c) 2018 by Michael Black W9MDB * * * This library is free software; you can redistribute it and/or @@ -40,25 +40,34 @@ #include "flrig.h" #define DEBUG 1 +#define DEBUG_TRACE DEBUG_VERBOSE #define MAXCMDLEN 8192 +#define MAXXMLLEN 8192 +#define MAXBANDWIDTHLEN 4096 -#define DEFAULTPATH "localhost:12345" +#define DEFAULTPATH "127.0.0.1:12345" -#define FLRIG_VFOS (RIG_VFO_A|RIG_VFO_B|RIG_VFO_TX) +#define FLRIG_VFOS (RIG_VFO_A|RIG_VFO_B) -#define FLRIG_MODES (RIG_MODE_AM | RIG_MODE_CW | RIG_MODE_RTTY | \ - RIG_MODE_SSB | RIG_MODE_FM) +#define FLRIG_MODES (RIG_MODE_AM | RIG_MODE_PKTAM | RIG_MODE_CW | RIG_MODE_CWR |\ + RIG_MODE_RTTY | RIG_MODE_RTTYR |\ + RIG_MODE_PKTLSB | RIG_MODE_PKTUSB |\ + RIG_MODE_SSB | RIG_MODE_LSB |\ + RIG_MODE_FM | RIG_MODE_WFM | RIG_MODE_FMN |RIG_MODE_PKTFM ) -#define RIG_DEBUG_TRACE RIG_DEBUG_VERBOSE +#define streq(s1,s2) (strcmp(s1,s2)==0) static int flrig_init(RIG *rig); -//int flrig_cleanup(RIG *rig); +static int flrig_open(RIG *rig); +static int flrig_close(RIG *rig); +static int flrig_cleanup(RIG *rig); static int flrig_set_freq(RIG *rig, vfo_t vfo, freq_t freq); static int flrig_get_freq(RIG *rig, vfo_t vfo, freq_t *freq); static int flrig_set_ptt(RIG *rig, vfo_t vfo, ptt_t ptt); -static int flrig_set_mode(RIG *rig, vfo_t vfo, rmode_t mode, - pbwidth_t width); +static int flrig_set_mode(RIG *rig, vfo_t vfo, rmode_t mode, pbwidth_t width); +static int flrig_set_split_mode(RIG *rig, vfo_t vfo, rmode_t mode, pbwidth_t width); +static int flrig_get_mode(RIG *rig, vfo_t vfo, rmode_t *mode, pbwidth_t *width); static int flrig_get_vfo(RIG *rig, vfo_t *vfo); static int flrig_set_vfo(RIG *rig, vfo_t vfo); static int flrig_set_ptt(RIG *rig, vfo_t vfo, ptt_t ptt); @@ -69,9 +78,24 @@ static int flrig_set_split_vfo(RIG *rig, vfo_t vfo, split_t split, vfo_t tx_vfo); static int flrig_get_split_vfo(RIG *rig, vfo_t vfo, split_t *split, vfo_t *tx_vfo); +static int flrig_set_split_freq_mode(RIG *rig, vfo_t vfo, freq_t freq, rmode_t mode, pbwidth_t width); +static int flrig_get_split_freq_mode(RIG *rig, vfo_t vfo, freq_t *freq, rmode_t *mode, pbwidth_t *width); + +static const char *flrig_get_info(RIG *rig); struct flrig_priv_data { - vfo_t vfo_curr; + vfo_t curr_vfo; + char bandwidths[MAXBANDWIDTHLEN]; /* pipe delimited set returned from flrig */ + int nbandwidths; + char info[8192]; + ptt_t ptt; + split_t split; + rmode_t curr_modeA; + rmode_t curr_modeB; + freq_t curr_freqA; + freq_t curr_freqB; + pbwidth_t curr_widthA; + pbwidth_t curr_widthB; }; const struct rig_caps flrig_caps = { @@ -80,131 +104,109 @@ const struct rig_caps flrig_caps = { .mfg_name = "FLRig", .version = BACKEND_VER, .copyright = "LGPL", - .status = RIG_STATUS_ALPHA, + .status = RIG_STATUS_BETA, .rig_type = RIG_TYPE_TRANSCEIVER, - .targetable_vfo = 0, + .targetable_vfo = RIG_TARGETABLE_FREQ, .ptt_type = RIG_PTT_RIG, .port_type = RIG_PORT_NETWORK, .write_delay = 0, - .post_write_delay = 50, + .post_write_delay = 0, .timeout = 1000, - .retry = 3, + .retry = 5, .has_get_func = RIG_FUNC_NONE, .has_set_func = RIG_FUNC_NONE, - .has_get_level = (RIG_LEVEL_RAWSTR | RIG_LEVEL_STRENGTH), + .has_get_level = RIG_LEVEL_NONE, .has_set_level = RIG_LEVEL_NONE, .has_get_parm = RIG_PARM_NONE, .has_set_parm = RIG_PARM_NONE, -// .level_gran = { [LVL_CWPITCH] = { .step = { .i = 10 } } }, -// .ctcss_list = common_ctcss_list, -// .dcs_list = full_dcs_list, -// .chan_list = { -// { 0, 18, RIG_MTYPE_MEM, DUMMY_MEM_CAP }, -// { 19, 19, RIG_MTYPE_CALL }, -// { 20, NB_CHAN-1, RIG_MTYPE_EDGE }, -// RIG_CHAN_END, -// }, -// .vfo_ops = DUMMY_VFO_OP, - .transceive = RIG_TRN_RIG, -// .attenuator = { 10, 20, 30, RIG_DBLST_END, }, -// .preamp = { 10, RIG_DBLST_END, }, -// .rx_range_list1 = {{.start = kHz(150),.end = MHz(1500),.modes = FLRIG_MODES, -// .low_power = -1,.high_power = -1, FLRIG_VFOS, RIG_ANT_1 | RIG_ANT_2}, -// RIG_FRNG_END,}, -// .tx_range_list1 = {RIG_FRNG_END,}, -// .rx_range_list2 = {{.start = kHz(150),.end = MHz(1500),.modes = FLRIG_MODES, -// .low_power = -1,.high_power = -1, FLRIG_VFOS, RIG_ANT_1 | RIG_ANT_2}, -// RIG_FRNG_END,}, -// .tx_range_list2 = {RIG_FRNG_END,}, -// .tuning_steps = { {DUMMY_MODES,1}, {DUMMY_MODES,RIG_TS_ANY}, RIG_TS_END, }, -// .filters = { -// {RIG_MODE_SSB | RIG_MODE_CW | RIG_MODE_RTTY, kHz(2.4)}, -// {RIG_MODE_CW, Hz(500)}, -// {RIG_MODE_AM, kHz(8)}, -// {RIG_MODE_AM, kHz(2.4)}, -// {RIG_MODE_FM, kHz(15)}, -// {RIG_MODE_FM, kHz(8)}, -// {RIG_MODE_WFM, kHz(230)}, -// RIG_FLT_END, -// }, -// .max_rit = 9990, -// .max_xit = 9990, -// .max_ifshift = 10000, + .filters = { + RIG_FLT_END + }, + + .rx_range_list1 = {{ + .start = kHz(1),.end = GHz(10),.modes = FLRIG_MODES, + .low_power = -1,.high_power = -1, FLRIG_VFOS, RIG_ANT_1 + }, + RIG_FRNG_END, + }, + .tx_range_list1 = {RIG_FRNG_END,}, + .rx_range_list2 = {{ + .start = kHz(1),.end = GHz(10),.modes = FLRIG_MODES, + .low_power = -1,.high_power = -1, FLRIG_VFOS, RIG_ANT_1 + }, + RIG_FRNG_END, + }, + .tx_range_list2 = {RIG_FRNG_END,}, + .tuning_steps = { {FLRIG_MODES,1}, {FLRIG_MODES,RIG_TS_ANY}, RIG_TS_END, }, .priv = NULL, /* priv */ -// .extlevels = dummy_ext_levels, -// .extparms = dummy_ext_parms, -// .cfgparams = dummy_cfg_params, - .rig_init = flrig_init, -// .rig_cleanup = dummy_cleanup, -// .rig_open = dummy_open, -// .rig_close = dummy_close, - -// .set_conf = dummy_set_conf, -// .get_conf = dummy_get_conf, + .rig_open = flrig_open, + .rig_close = flrig_close, + .rig_cleanup = flrig_cleanup, .set_freq = flrig_set_freq, .get_freq = flrig_get_freq, .set_mode = flrig_set_mode, -// .get_mode = dummy_get_mode, + .get_mode = flrig_get_mode, .set_vfo = flrig_set_vfo, .get_vfo = flrig_get_vfo, - -// .set_powerstat = dummy_set_powerstat, -// .get_powerstat = dummy_get_powerstat, -// .set_level = dummy_set_level, -// .get_level = dummy_get_level, -// .set_func = dummy_set_func, -// .get_func = dummy_get_func, -// .set_parm = dummy_set_parm, -// .get_parm = dummy_get_parm, -// .set_ext_level = dummy_set_ext_level, -// .get_ext_level = dummy_get_ext_level, -// .set_ext_parm = dummy_set_ext_parm, -// .get_ext_parm = dummy_get_ext_parm, - -// .get_info = dummy_get_info, - + .get_info = flrig_get_info, .set_ptt = flrig_set_ptt, .get_ptt = flrig_get_ptt, + .set_split_mode = flrig_set_split_mode, .set_split_freq = flrig_set_split_freq, .get_split_freq = flrig_get_split_freq, -// .set_split_mode = flrig_set_split_mode, -// .get_split_mode = flrig_get_split_mode, .set_split_vfo = flrig_set_split_vfo, .get_split_vfo = flrig_get_split_vfo, -// .set_ant = dummy_set_ant, -// .get_ant = dummy_get_ant, -// .set_bank = dummy_set_bank, -// .set_mem = dummy_set_mem, -// .get_mem = dummy_get_mem, -// .vfo_op = dummy_vfo_op, -// .set_trn = dummy_set_trn, -// .get_trn = dummy_get_trn, + .set_split_freq_mode = flrig_set_split_freq_mode, + .get_split_freq_mode = flrig_get_split_freq_mode }; -DECLARE_INITRIG_BACKEND(flrig) -{ +// Structure for mapping flrig dynmamic modes to hamlib modes +// flrig displays modes as the rig displays them +// hamlib displays modes in generic form +#define MAXMODELEN 8 +struct s_modeMap { + int mode_hamlib; + char mode_flrig[MAXMODELEN]; +}; - rig_debug(RIG_DEBUG_TRACE, "flrig: _init called\n"); - - rig_register(&flrig_caps); - - return RIG_OK; -} +// FLRig will provide us the modes for the selected rig +// We will then put them in this struct +static struct s_modeMap modeMap[]= { + {RIG_MODE_USB,""}, + {RIG_MODE_LSB,""}, + {RIG_MODE_PKTUSB,""}, + {RIG_MODE_PKTLSB,""}, + {RIG_MODE_PKTUSB,""}, + {RIG_MODE_PKTLSB,""}, + {RIG_MODE_AM,""}, + {RIG_MODE_FM,""}, + {RIG_MODE_FMN,""}, + {RIG_MODE_WFM,""}, + {RIG_MODE_CW,""}, + {RIG_MODE_CW,""}, + {RIG_MODE_CWR,""}, + {RIG_MODE_CWR,""}, + {RIG_MODE_RTTY,""}, + {RIG_MODE_RTTYR,""}, + {0,""} +}; +/* + * check_vfo + * No assumptions + */ static int check_vfo(vfo_t vfo) { - switch (vfo) { // Omni VII only has A & B + switch (vfo) { case RIG_VFO_A: break; - case RIG_VFO_B: - break; - case RIG_VFO_TX: + case RIG_VFO_B: break; case RIG_VFO_CURR: @@ -217,70 +219,112 @@ static int check_vfo(vfo_t vfo) return TRUE; } +/* + * vfo_curr + * Assumes rig!=NULL + */ static int vfo_curr(RIG *rig, vfo_t vfo) { int retval = 0; - struct flrig_priv_data *priv = - (struct flrig_priv_data *) rig->state.priv; - retval = (vfo == priv->vfo_curr); + vfo_t vfocurr; + struct flrig_priv_data *priv = (struct flrig_priv_data *) rig->state.priv; + + // get the current VFO from flrig in case user changed it + if ((retval = flrig_get_vfo(rig, &vfocurr)) != RIG_OK) { + return retval; + } + priv->curr_vfo = vfocurr; + retval = (vfo == vfocurr); return retval; } -// Rather than use some huge XML library we only need a few things -// So we'll hand craft them -static char *xml_build(char *cmd, char *value) +/* Rather than use some huge XML library we only need a few things + * So we'll hand craft them + * xml_build takes a value and return an xml string for FLRig + */ +static char *xml_build(char *cmd, char *value, char *xmlbuf,int xmllen) { - char xml[4096]; - char tmp[32]; - static char xmlpost[4096]; - // Standard 50ms sleep borrowed from ts200.c settings - // Tested with ANAN 100 - usleep(50 * 1000); - sprintf(xmlpost, - "POST /RPC2 HTTP/1.1\n" "User-Agent: XMLRPC++ 0.8\n" - "Host: 127.0.0.1:12345\n" "Content-type: text/xml\n"); - sprintf(xml, "\n"); + char xml[MAXXMLLEN]; + // We want at least a 4K buf to play with + if (xmllen < 4096) { + rig_debug(RIG_DEBUG_ERR, "%s: xmllen < 4096\n"); + return NULL; + } + sprintf(xmlbuf, + "POST /RPC2 HTTP/1.1\r\n" "User-Agent: XMLRPC++ 0.8\r\n" + "Host: 127.0.0.1:12345\r\n" "Content-type: text/xml\r\n"); + sprintf(xml, "\r\n"); strcat(xml, ""); strcat(xml, cmd); - strcat(xml, ""); + strcat(xml, "\r\n"); if (value && strlen(value) > 0) { strcat(xml, value); } - strcat(xml, "\n"); - strcat(xmlpost, "Content-length: "); - sprintf(tmp, "%d\n\n", (int)strlen(xml)); - strcat(xmlpost, tmp); - strcat(xmlpost, xml); - rig_debug(RIG_DEBUG_VERBOSE, "XML:\n%s", xmlpost); - return xmlpost; + strcat(xml, "\r\n"); + strcat(xmlbuf, "Content-length: "); + char tmp[32]; + sprintf(tmp, "%d\r\n\r\n", (int)strlen(xml)); + strcat(xmlbuf, tmp); + strcat(xmlbuf, xml); + return xmlbuf; } -// This is a very crude xml parse specific to what we need from FLRig -// This will not handle array returns for example yet...only simple values -// It simply grabs the first element before the first closing tag -// This works for strings, doubles, and I4-type values -char *xml_parse2(char *xml, char *value, int valueLen) +/* This is a very crude xml parse specific to what we need from FLRig + * This works for strings, doubles, I4-type values, and arrays + * Arrays are returned pipe delimited + */ +static char *xml_parse2(char *xml, char *value, int valueLen) { - char *pstart = strchr(xml, '<'); - - while (pstart[0] == '<' && pstart[1] != '/') { - char *p2 = strchr(pstart, '>') + 1; - pstart = strchr(p2, '<'); - strncpy(value, p2, pstart - p2); - value[pstart - p2] = 0; + char* delims = "<>\r\n "; + char *xmltmp = strdup(xml); + //rig_debug(RIG_DEBUG_TRACE, "%s: xml='%s'\n", __FUNCTION__,xml); + char *p = strtok(xmltmp,delims); + value[0]=0; + while(p) { + if (streq(p,"value")) { + p=strtok(NULL,delims); + if (streq(p,"array")) continue; + if (streq(p,"/value")) continue; // empty value + if (streq(p,"i4") || streq(p,"double")) { + p = strtok(NULL,delims); + } + else if (streq(p,"array")) { + p = strtok(NULL,delims); + p = strtok(NULL,delims); + } + if (strlen(value)+strlen(p)+1 < valueLen) { + if (value[0]!=0) strcat(value,"|"); + strcat(value,p); + } + else { // we'll just stop adding stuff + rig_debug(RIG_DEBUG_ERR, "%s: max value length exceeded\n", __FUNCTION__); + } + } + else { + p=strtok(NULL,delims); + } + } + rig_debug(RIG_DEBUG_TRACE, "%s: value returned='%s'\n", __FUNCTION__,value); + if (rig_need_debug(RIG_DEBUG_WARN) && value != NULL && strlen(value)==0) { + rig_debug(RIG_DEBUG_ERR, "%s: xml='%s'\n", __FUNCTION__,xml); } - return value; } +/* + * xml_parse + * Assumes xml!=NULL, value!=NULL, value_len big enough + * returns the string value contained in the xml string + */ static char *xml_parse(char *xml, char *value, int value_len) { /* first off we should have an OK on the 1st line */ if (strstr(xml, " 200 OK") == NULL) { return NULL; } + rig_debug(RIG_DEBUG_VERBOSE, "%s XML:\n%s\n", __FUNCTION__, xml); // find the xml skipping the other stuff above it char *pxml = strstr(xml, "=MAXXMLLEN + */ static int read_transaction(RIG *rig, char *xml, int xml_len) { + int retval; + char *terminator = ""; + + rig_debug(RIG_DEBUG_TRACE, "%s\n", __FUNCTION__); struct rig_state *rs = &rig->state; - int retval; - char cmd_buf[16384]; // plenty big for expected flrig responses - char delim[1]; - delim[0] = 0x0a; - xml[0] = cmd_buf[0] = 0; + rs->rigport.timeout = 4000; // 3 second read string timeout + int retry=5; + char *delims="\n"; + xml[0]=0; do { - retval = - read_string(&rs->rigport, cmd_buf, sizeof(cmd_buf), delim, - sizeof(delim)); - - if (strlen(xml) > 8192 - retval) { - return -RIG_EINVAL; + char tmp_buf[MAXXMLLEN]; // plenty big for expected flrig responses + int len = read_string(&rs->rigport, tmp_buf, sizeof(tmp_buf), delims, strlen(delims)); + rig_debug(RIG_DEBUG_WARN,"%s: string='%s'",__FUNCTION__,tmp_buf); + if (len > 0) retry = 3; + if (len <= 0) { + rig_debug(RIG_DEBUG_ERR,"%s: read_string error=%d\n",__FUNCTION__,len); + return -(100+RIG_EPROTO); } - - if (retval > 0) { - strcat(xml, cmd_buf); - } - } while (retval > 0 && strstr(cmd_buf, "") == NULL); - - return RIG_OK; + strcat(xml,tmp_buf); + } while (retry-- > 0 && strstr(xml,terminator)==NULL); + if (retry == 0) { + rig_debug(RIG_DEBUG_WARN,"%s: retry timeout\n",__FUNCTION__); + } + if (strstr(xml,terminator)) { + rig_debug(RIG_DEBUG_VERBOSE,"%s: got %s\n",__FUNCTION__,terminator); + // Testing slowing down 3 of commands per second + usleep(2*1000); + retval = RIG_OK; + } + else { + rig_debug(RIG_DEBUG_VERBOSE,"%s: did not get %s\n",__FUNCTION__,terminator); + retval = -(101+RIG_EPROTO); + } + return retval; } -int flrig_init(RIG *rig) +/* + * write_transaction + * Assumes rig!=NULL, xml!=NULL, xml_len=total size of xml for response + */ +static int write_transaction(RIG *rig, char *xml, int xml_len) { - rig_debug(RIG_DEBUG_TRACE, "%s\n", __FUNCTION__); + int try=rig->caps->retry; + int retval=-RIG_EPROTO; + char xmltmp[MAXXMLLEN]; + + struct rig_state *rs = &rig->state; + + // This shouldn't ever happen...but just in case + // We need to avoid and empty write as rigctld replies with blank line + if (xml_len == 0) { + rig_debug(RIG_DEBUG_ERR,"%s: len==0??\n",__FUNCTION__); + } + + while(try-- >= 0 && retval != RIG_OK) { + retval = write_block(&rs->rigport, xml, strlen(xml)); + if (retval < 0) { + return -RIG_EIO; + } + } + strcpy(xml,xmltmp); + return retval; +} + +/* + * flrig_init + * Assumes rig!=NULL + */ +static int flrig_init(RIG *rig) +{ + + rig_debug(RIG_DEBUG_TRACE, "%s version %s\n", __FUNCTION__, BACKEND_VER); struct flrig_priv_data *priv = (struct flrig_priv_data *)malloc(sizeof(struct flrig_priv_data)); @@ -338,8 +432,14 @@ int flrig_init(RIG *rig) /* * set arbitrary initial status */ - priv->vfo_curr = RIG_VFO_A; rig->state.priv = (rig_ptr_t) priv; + priv->curr_vfo = RIG_VFO_A; + priv->split = 0; + priv->ptt = 0; + priv->curr_modeA = -1; + priv->curr_modeB = -1; + priv->curr_widthA = -1; + priv->curr_widthB = -1; if (!rig || !rig->caps) { return -RIG_EINVAL; @@ -347,6 +447,193 @@ int flrig_init(RIG *rig) strncpy(rig->state.rigport.pathname, DEFAULTPATH, sizeof(rig->state.rigport.pathname)); + + return RIG_OK; +} + +/* + * modeMapGetFLRig + * Assumes mode!=NULL + * Return the string for FLRig for the given hamlib mode + */ +static char * modeMapGetFLRig(unsigned int modeHamlib) +{ + int i; + for(i=0; modeMap[i].mode_hamlib!=0; ++i) { + if (modeMap[i].mode_hamlib==modeHamlib) { + return modeMap[i].mode_flrig; + } + } + rig_debug(RIG_DEBUG_ERR,"%s: Unknown mode requested: %s\n",__FUNCTION__,rig_strrmode(modeHamlib)); + return "ERROR"; +} + +/* + * modeMapGetHamlib + * Assumes mode!=NULL + * Return the hamlib mode from the given FLRig string + */ +static unsigned int modeMapGetHamlib(const char *modeFLRig) +{ + int i; + rig_debug(RIG_DEBUG_VERBOSE,"%s: get hamlib mode from %s\n",__FUNCTION__,modeFLRig); + for(i=0; modeMap[i].mode_hamlib!=0; ++i) { + if (streq(modeMap[i].mode_flrig,modeFLRig)) { + rig_debug(RIG_DEBUG_VERBOSE,"%s: got hamlib mode %s\n",__FUNCTION__,rig_strrmode(modeMap[i].mode_hamlib)); + return modeMap[i].mode_hamlib; + } + } + rig_debug(RIG_DEBUG_ERR,"%s: Unknown mode requested: %s\n",__FUNCTION__,modeFLRig); + return -RIG_EINVAL; +} + + +/* + * modeMapAdd + * Assumes modes!=NULL + */ +static void modeMapAdd(unsigned int *modes,int mode_hamlib,char *mode_flrig) +{ + int i; + for(i=0; modeMap[i].mode_hamlib!=0; ++i) { + if (modeMap[i].mode_hamlib==mode_hamlib) { + *modes |= modeMap[i].mode_hamlib; + strncpy(modeMap[i].mode_flrig,mode_flrig,sizeof(modeMap[i].mode_flrig)); + return; + } + } +} + +/* + * flrig_open + * Assumes rig!=NULL, rig->state.priv!=NULL + */ +static int flrig_open(RIG *rig) { + int retval; + char xml[MAXXMLLEN]; + char value[MAXXMLLEN]; + + rig_debug(RIG_DEBUG_VERBOSE, "%s version %s\n", __FUNCTION__, BACKEND_VER); + + struct flrig_priv_data *priv = (struct flrig_priv_data *) rig->state.priv; + + char *pxml = xml_build("rig.get_xcvr", NULL,xml,sizeof(xml)); + retval = write_transaction(rig, pxml, strlen(pxml)); + if (retval < 0) { + return retval; + } + read_transaction(rig, xml, sizeof(xml)); + xml_parse(xml, value, sizeof(value)); + strncpy(priv->info,value,sizeof(priv->info)); + rig_debug(RIG_DEBUG_VERBOSE,"Transceiver=%s\n", value); + + pxml = xml_build("rig.get_AB", value, xml, sizeof(xml)); + retval = write_transaction(rig, pxml, strlen(pxml)); + read_transaction(rig, xml, sizeof(xml)); + xml_parse(xml, value, sizeof(value)); + if (streq(value,"A")) { + priv->curr_vfo = RIG_VFO_A; + } + else { + priv->curr_vfo = RIG_VFO_B; + } + rig_debug(RIG_DEBUG_VERBOSE, "%s: currvfo=%s value=%s\n",__FUNCTION__, rig_strvfo(priv->curr_vfo), value); + //vfo_t vfo=RIG_VFO_A; + //vfo_t vfo_tx=RIG_VFO_B; // split is always VFOB + //flrig_get_split_vfo(rig, vfo, &priv->split, &vfo_tx); + + /* find out available widths and modes */ + pxml = xml_build("rig.get_modes", NULL,xml,sizeof(xml)); + retval = write_transaction(rig, pxml, strlen(pxml)); + if (retval < 0) { + return retval; + } + read_transaction(rig, xml, sizeof(xml)); + xml_parse(xml, value, sizeof(value)); + rig_debug(RIG_DEBUG_VERBOSE, "%s: modes=%s\n",__FUNCTION__, value); + unsigned int modes = 0; + char *p; + for(p=strtok(value,"|"); p!=NULL; p=strtok(NULL,"|")) { + if (streq(p,"USB")) modeMapAdd(&modes,RIG_MODE_USB,p); + else if (streq(p,"LSB")) modeMapAdd(&modes,RIG_MODE_LSB,p); + else if (streq(p,"USB-D")) modeMapAdd(&modes,RIG_MODE_PKTUSB,p); + else if (streq(p,"USB-D1")) modeMapAdd(&modes,RIG_MODE_PKTUSB,p); + else if (streq(p,"USB-D2")) modeMapAdd(&modes,RIG_MODE_PKTUSB,p); + else if (streq(p,"USB-D3")) modeMapAdd(&modes,RIG_MODE_PKTUSB,p); + else if (streq(p,"LSB-D")) modeMapAdd(&modes,RIG_MODE_PKTLSB,p); + else if (streq(p,"LSB-D1")) modeMapAdd(&modes,RIG_MODE_PKTLSB,p); + else if (streq(p,"LSB-D2")) modeMapAdd(&modes,RIG_MODE_PKTLSB,p); + else if (streq(p,"LSB-D3")) modeMapAdd(&modes,RIG_MODE_PKTLSB,p); + else if (streq(p,"DATA-USB")) modeMapAdd(&modes,RIG_MODE_PKTUSB,p); + else if (streq(p,"D-USB")) modeMapAdd(&modes,RIG_MODE_PKTUSB,p); + else if (streq(p,"DATA-U")) modeMapAdd(&modes,RIG_MODE_PKTUSB,p); + else if (streq(p,"DATA-LSB")) modeMapAdd(&modes,RIG_MODE_PKTLSB,p); + else if (streq(p,"D-LSB")) modeMapAdd(&modes,RIG_MODE_PKTLSB,p); + else if (streq(p,"DATA-L")) modeMapAdd(&modes,RIG_MODE_PKTLSB,p); + else if (streq(p,"DATA-R")) modeMapAdd(&modes,RIG_MODE_PKTLSB,p); + else if (streq(p,"PKT")) modeMapAdd(&modes,RIG_MODE_PKTUSB,p); + else if (streq(p,"PKT-U")) modeMapAdd(&modes,RIG_MODE_PKTUSB,p); + else if (streq(p,"PKT(U)")) modeMapAdd(&modes,RIG_MODE_PKTUSB,p); + else if (streq(p,"PKT-L")) modeMapAdd(&modes,RIG_MODE_PKTLSB,p); + else if (streq(p,"PKT(L)")) modeMapAdd(&modes,RIG_MODE_PKTLSB,p); + else if (streq(p,"FSK")) modeMapAdd(&modes,RIG_MODE_PKTUSB,p); + else if (streq(p,"FSK-R")) modeMapAdd(&modes,RIG_MODE_PKTLSB,p); + else if (streq(p,"PSK")) modeMapAdd(&modes,RIG_MODE_PKTUSB,p); + else if (streq(p,"PSK-R")) modeMapAdd(&modes,RIG_MODE_PKTLSB,p); + else if (streq(p,"PSK-U")) modeMapAdd(&modes,RIG_MODE_PKTUSB,p); + else if (streq(p,"PSK-L")) modeMapAdd(&modes,RIG_MODE_PKTLSB,p); + else if (streq(p,"AM")) modeMapAdd(&modes,RIG_MODE_AM,p); + else if (streq(p,"FM")) modeMapAdd(&modes,RIG_MODE_FM,p); + else if (streq(p,"AM-D")) modeMapAdd(&modes,RIG_MODE_PKTAM,p); + else if (streq(p,"FM-D")) modeMapAdd(&modes,RIG_MODE_PKTFM,p); + else if (streq(p,"FMN")) modeMapAdd(&modes,RIG_MODE_FMN,p); + else if (streq(p,"FM-N")) modeMapAdd(&modes,RIG_MODE_FMN,p); + else if (streq(p,"FMW")) modeMapAdd(&modes,RIG_MODE_WFM,p); + else if (streq(p,"WFM")) modeMapAdd(&modes,RIG_MODE_WFM,p); + else if (streq(p,"W-FM")) modeMapAdd(&modes,RIG_MODE_WFM,p); + else if (streq(p,"CW")) modeMapAdd(&modes,RIG_MODE_CW,p); + else if (streq(p,"CWU")) modeMapAdd(&modes,RIG_MODE_CW,p); + else if (streq(p,"CW-USB")) modeMapAdd(&modes,RIG_MODE_CW,p); + else if (streq(p,"CW-U")) modeMapAdd(&modes,RIG_MODE_CW,p); + else if (streq(p,"CW-LSB")) modeMapAdd(&modes,RIG_MODE_CWR,p); + else if (streq(p,"CW-L")) modeMapAdd(&modes,RIG_MODE_CWR,p); + else if (streq(p,"CW-R")) modeMapAdd(&modes,RIG_MODE_CWR,p); + else if (streq(p,"CWL")) modeMapAdd(&modes,RIG_MODE_CWR,p); + else if (streq(p,"RTTY")) modeMapAdd(&modes,RIG_MODE_RTTY,p); + else if (streq(p,"RTTY-U")) modeMapAdd(&modes,RIG_MODE_RTTY,p); + else if (streq(p,"RTTY-R")) modeMapAdd(&modes,RIG_MODE_RTTYR,p); + else if (streq(p,"RTTY-L")) modeMapAdd(&modes,RIG_MODE_RTTYR,p); + else if (streq(p,"RTTY(U)")) modeMapAdd(&modes,RIG_MODE_RTTY,p); + else if (streq(p,"RTTY(R")) modeMapAdd(&modes,RIG_MODE_RTTYR,p); + else rig_debug(RIG_DEBUG_ERR,"%s: Unknown mode for this rig='%s'\n",__FUNCTION__,p); + } + rig->state.mode_list = modes; + rig_debug(RIG_DEBUG_VERBOSE, "%s: hamlib modes=0x%08x\n",__FUNCTION__, modes); + + return RIG_OK; +} + +/* + * flrig_close + * Assumes rig!=NULL + */ +static int flrig_close(RIG *rig) { + rig_debug(RIG_DEBUG_TRACE, "%s\n", __FUNCTION__); + return RIG_OK; +} + +/* + * flrig_cleanup + * Assumes rig!=NULL, rig->state.priv!=NULL + */ +static int flrig_cleanup(RIG *rig) { + + if (!rig) + return -RIG_EINVAL; + + free(rig->state.priv); + rig->state.priv = NULL; + return RIG_OK; } @@ -354,17 +641,14 @@ int flrig_init(RIG *rig) * flrig_get_freq * Assumes rig!=NULL, rig->state.priv!=NULL, freq!=NULL */ -int flrig_get_freq(RIG *rig, vfo_t vfo, freq_t *freq) +static int flrig_get_freq(RIG *rig, vfo_t vfo, freq_t *freq) { - char value[MAXCMDLEN]; - char *pxml; int retval; - struct rig_state *rs; - char xml[8192]; rig_debug(RIG_DEBUG_TRACE, "%s: vfo=%s\n", __FUNCTION__, rig_strvfo(vfo)); - rs = &rig->state; + + struct flrig_priv_data *priv = (struct flrig_priv_data *) rig->state.priv; if (check_vfo(vfo) == FALSE) { rig_debug(RIG_DEBUG_ERR, "%s: unsupported VFO %s\n", @@ -373,24 +657,49 @@ int flrig_get_freq(RIG *rig, vfo_t vfo, freq_t *freq) } if (vfo == RIG_VFO_CURR) { - vfo = RIG_VFO_A; + vfo = priv->curr_vfo; + rig_debug(RIG_DEBUG_VERBOSE, "%s: get_freq2 vfo=%s\n", + __FUNCTION__, rig_strvfo(vfo)); } - flrig_set_vfo(rig, vfo); + int retries=10; + char xml[MAXXMLLEN]; + char value[MAXCMDLEN]; + do { + char *pxml; + if (vfo == RIG_VFO_A) { + pxml = xml_build("rig.get_vfoA", NULL,xml,sizeof(xml)); + } + else { + pxml = xml_build("rig.get_vfoB", NULL,xml,sizeof(xml)); + } + retval = write_transaction(rig, pxml, strlen(pxml)); + if (retval < 0) { + return retval; + } - pxml = xml_build("rig.get_vfo", NULL); + read_transaction(rig, xml, sizeof(xml)); + xml_parse(xml, value, sizeof(value)); + if (strlen(value)==0) { + rig_debug(RIG_DEBUG_ERR, "%s: retries=%d\n",__FUNCTION__, retries); + //usleep(10*1000); + } + } while (--retries && strlen(value)==0); - retval = write_block(&rs->rigport, pxml, strlen(pxml)); - - if (retval < 0) { - return retval; - } - - read_transaction(rig, xml, sizeof(xml)); - xml_parse(xml, value, sizeof(value)); *freq = atof(value); - rig_debug(RIG_DEBUG_VERBOSE, "%s: '%s'\n", __FUNCTION__, value); - + if (*freq == 0) { + rig_debug(RIG_DEBUG_ERR, "%s: freq==0??\nvalue=%s\nxml=%s\n", __FUNCTION__,value,xml); + return -(102+RIG_EPROTO); + } + else { + rig_debug(RIG_DEBUG_VERBOSE, "%s: freq=%.0f\n", __FUNCTION__,*freq); + } + if (vfo == RIG_VFO_A) { + priv->curr_freqA = *freq; + } + else { + priv->curr_freqB = *freq; + } return RIG_OK; } @@ -398,17 +707,14 @@ int flrig_get_freq(RIG *rig, vfo_t vfo, freq_t *freq) * flrig_set_freq * assumes rig!=NULL, rig->state.priv!=NULL */ -int flrig_set_freq(RIG *rig, vfo_t vfo, freq_t freq) +static int flrig_set_freq(RIG *rig, vfo_t vfo, freq_t freq) { - char value[MAXCMDLEN]; - char *pxml; int retval; - struct rig_state *rs; - char xml[8192]; - rig_debug(RIG_DEBUG_TRACE, "%s: vfo=%s freq=%.1f\n", __FUNCTION__, + rig_debug(RIG_DEBUG_TRACE, "%s: vfo=%s freq=%.0f\n", __FUNCTION__, rig_strvfo(vfo), freq); - rs = &rig->state; + + struct flrig_priv_data *priv = (struct flrig_priv_data *) rig->state.priv; if (check_vfo(vfo) == FALSE) { rig_debug(RIG_DEBUG_ERR, "%s: unsupported VFO %s\n", @@ -417,32 +723,38 @@ int flrig_set_freq(RIG *rig, vfo_t vfo, freq_t freq) } if (vfo == RIG_VFO_CURR) { - if ((retval = flrig_get_vfo(rig, &vfo)) != RIG_OK) { - return retval; - } - - rig_debug(RIG_DEBUG_VERBOSE, "%s: set_freq2 vfo=%s\n", - __FUNCTION__, rig_strvfo(vfo)); + vfo = priv->curr_vfo; + } + else if (vfo == RIG_VFO_TX && priv->split) { + vfo = RIG_VFO_B; // if split always TX on VFOB } - if (!vfo_curr(rig, vfo)) { - flrig_set_vfo(rig, vfo); + char value[MAXXMLLEN]; + sprintf(value, "%.0f", freq); + char xml[MAXXMLLEN]; + char *pxml; + if (vfo == RIG_VFO_B) { + pxml = xml_build("rig.set_vfoB", value, xml, sizeof(xml)); + rig_debug(RIG_DEBUG_VERBOSE,"rig.set_vfoB %s",value); + priv->curr_freqB = freq; } - - sprintf(value, - "%.6f", - freq); - pxml = xml_build("rig.set_vfo", value); - retval = write_block(&rs->rigport, pxml, strlen(pxml)); - + else { + pxml = xml_build("rig.set_vfoA", value, xml, sizeof(xml)); + rig_debug(RIG_DEBUG_VERBOSE,"rig.set_vfoA %s",value); + priv->curr_freqA = freq; + } + retval = write_transaction(rig, pxml, strlen(pxml)); if (retval < 0) { return retval; } + if (vfo == RIG_VFO_B) { + priv->curr_freqB = freq; + } + else { + priv->curr_freqA = freq; + } - read_transaction(rig, xml, sizeof(xml)); - //don't care about the response right now - //xml_parse(xml, value, sizeof(value)); - flrig_set_vfo(rig, vfo); + read_transaction(rig, xml, sizeof(xml)); // get response but don't care return RIG_OK; } @@ -451,16 +763,13 @@ int flrig_set_freq(RIG *rig, vfo_t vfo, freq_t freq) * flrig_set_ptt * Assumes rig!=NULL */ -int flrig_set_ptt(RIG *rig, vfo_t vfo, ptt_t ptt) +static int flrig_set_ptt(RIG *rig, vfo_t vfo, ptt_t ptt) { int retval; - char cmd_buf[MAXCMDLEN]; - char *pxml; - char xml[8192]; - struct rig_state *rs; rig_debug(RIG_DEBUG_TRACE, "%s: ptt=%d\n", __FUNCTION__, ptt); - rs = &rig->state; + + struct flrig_priv_data *priv = (struct flrig_priv_data *) rig->state.priv; if (check_vfo(vfo) == FALSE) { rig_debug(RIG_DEBUG_ERR, "%s: unsupported VFO %s\n", @@ -468,205 +777,375 @@ int flrig_set_ptt(RIG *rig, vfo_t vfo, ptt_t ptt) return -RIG_EINVAL; } - if (vfo == RIG_VFO_CURR) { - vfo = RIG_VFO_A; - } - - if (!vfo_curr(rig, vfo)) { - flrig_set_vfo(rig, vfo); - } - + char cmd_buf[MAXCMDLEN]; sprintf(cmd_buf, "%d", ptt); - pxml = xml_build("rig.set_ptt", cmd_buf); - retval = write_block(&rs->rigport, pxml, strlen(pxml)); + char xml[MAXXMLLEN]; + char *pxml = xml_build("rig.set_ptt", cmd_buf, xml, sizeof(xml)); + retval = write_transaction(rig, pxml, strlen(pxml)); if (retval < 0) { return retval; } - read_transaction(rig, xml, sizeof(xml)); - xml_parse(xml, cmd_buf, sizeof(cmd_buf)); + read_transaction(rig, xml, sizeof(xml)); // get response but don't care + + priv->ptt = ptt; + return RIG_OK; } -int flrig_get_ptt(RIG *rig, vfo_t vfo, ptt_t *ptt) +/* + * flrig_get_ptt + * Assumes rig!=NUL, ptt!=NULL + */ +static int flrig_get_ptt(RIG *rig, vfo_t vfo, ptt_t *ptt) { - char value[MAXCMDLEN]; - char *pxml; int retval; - struct rig_state *rs; - char xml[8192]; rig_debug(RIG_DEBUG_TRACE, "%s: vfo=%s\n", __FUNCTION__, rig_strvfo(vfo)); - rs = &rig->state; - pxml = xml_build("rig.get_ptt", NULL); + struct flrig_priv_data *priv = (struct flrig_priv_data *) rig->state.priv; - retval = write_block(&rs->rigport, pxml, strlen(pxml)); + char xml[MAXXMLLEN]; + char *pxml = xml_build("rig.get_ptt", NULL, xml, sizeof(xml)); + + retval = write_transaction(rig, pxml, strlen(pxml)); if (retval < 0) { return retval; } read_transaction(rig, xml, sizeof(xml)); + char value[MAXCMDLEN]; xml_parse(xml, value, sizeof(value)); *ptt = atoi(value); rig_debug(RIG_DEBUG_VERBOSE, "%s: '%s'\n", __FUNCTION__, value); + priv->ptt = *ptt; + return RIG_OK; } +/* + * flrig_set_split_mode + * Assumes rig!=NULL + */ +static int flrig_set_split_mode(RIG *rig, vfo_t vfo, rmode_t mode, pbwidth_t width) +{ + int retval; + rig_debug(RIG_DEBUG_TRACE, "%s: vfo=%s mode=%s width=%d\n", + __FUNCTION__, rig_strvfo(vfo), rig_strrmode(mode), width); + + struct flrig_priv_data *priv = (struct flrig_priv_data *) rig->state.priv; + + switch(vfo) { + case RIG_VFO_CURR: + vfo = priv->curr_vfo; + break; + case RIG_VFO_TX: + vfo = RIG_VFO_B; + break; + } + // If no change don't do it...modes are kept up to date by client calls + // to get_mode and set_mode so should be current here + rig_debug(RIG_DEBUG_TRACE, "%s: vfoa privmode=%s\n",__FUNCTION__,rig_strrmode(priv->curr_modeA)); + rig_debug(RIG_DEBUG_TRACE, "%s: vfob privmode=%s\n",__FUNCTION__,rig_strrmode(priv->curr_modeB)); + // save some VFO swapping .. may replace with VFO specific calls that won't cause VFO change + if (vfo==RIG_VFO_A && mode==priv->curr_modeA) return RIG_OK; + if (vfo==RIG_VFO_B && mode==priv->curr_modeB) return RIG_OK; + retval = flrig_set_mode(rig,RIG_VFO_B,mode,width); + rig_debug(RIG_DEBUG_TRACE, "%s: set mode=%s\n",__FUNCTION__,rig_strrmode(mode)); + return retval; +} + /* * flrig_set_mode * Assumes rig!=NULL */ -int flrig_set_mode(RIG *rig, vfo_t vfo, rmode_t mode, pbwidth_t width) +static int flrig_set_mode(RIG *rig, vfo_t vfo, rmode_t mode, pbwidth_t width) { - char cmd_buf[32], ttmode; - int cmd_len, retval; - struct rig_state *rs; - - //struct tt588_priv_data *priv = (struct tt588_priv_data *) rig->state.priv; - - rig_debug(RIG_DEBUG_TRACE, "%s: vfo=%s mode=%d width=%d\n", - __FUNCTION__, rig_strvfo(vfo), mode, width); - rs = &rig->state; - - if (check_vfo(vfo) == FALSE) { - rig_debug(RIG_DEBUG_ERR, "%s: unsupported VFO %s\n", - __FUNCTION__, rig_strvfo(vfo)); - return -RIG_EINVAL; - } - - switch (mode) { - case RIG_MODE_USB: - ttmode = 'U'; - break; - - case RIG_MODE_LSB: - ttmode = 'L'; - break; - - case RIG_MODE_CW: - ttmode = 'C'; - break; - - case RIG_MODE_AM: - ttmode = 'A'; - break; - - //case RIG_MODE_FSK: ttmode = 'F'; break; - default: - rig_debug(RIG_DEBUG_ERR, "%s: unsupported mode %d\n", - __FUNCTION__, mode); - return -RIG_EINVAL; - } - - cmd_len = sprintf((char *) cmd_buf, "XB%c" EOM, ttmode); - - retval = write_block(&rs->rigport, cmd_buf, cmd_len); - - if (retval < 0) { - return retval; - } - - return RIG_OK; - -} - -#if 0 -static int flrig_flush(RIG *rig, vfo_t vfo) -{ - char value[MAXCMDLEN]; - char *pxml; int retval; - struct rig_state *rs; - char xml[8192]; - rig_debug(RIG_DEBUG_TRACE, "%s: vfo=%s\n", __FUNCTION__, - rig_strvfo(vfo)); - rs = &rig->state; + rig_debug(RIG_DEBUG_TRACE, "%s: vfo=%s mode=%s width=%d\n", + __FUNCTION__, rig_strvfo(vfo), rig_strrmode(mode), width); - sprintf(value, "%s", - vfo == RIG_VFO_A ? "A" : "B"); - pxml = xml_build("rig.flush", value); - network_flush(&rs->rigport); - retval = write_block(&rs->rigport, pxml, strlen(pxml)); + struct flrig_priv_data *priv = (struct flrig_priv_data *) rig->state.priv; - if (retval < 0) { - return retval; - } - - read_transaction(rig, xml, sizeof(xml)); - return RIG_OK; -} -#endif - -int flrig_set_vfo(RIG *rig, vfo_t vfo) -{ - char value[MAXCMDLEN]; - char *pxml; - int retval; - struct rig_state *rs; - char xml[8192]; - - rig_debug(RIG_DEBUG_TRACE, "%s: vfo=%s\n", __FUNCTION__, - rig_strvfo(vfo)); - rs = &rig->state; - - if (check_vfo(vfo) == FALSE) { - rig_debug(RIG_DEBUG_ERR, "%s: unsupported VFO %s\n", - __FUNCTION__, rig_strvfo(vfo)); - return -RIG_EINVAL; - } + // if ptt is on do not set mode + if (priv->ptt) return RIG_OK; if (vfo == RIG_VFO_CURR) { - struct flrig_priv_data *priv = - (struct flrig_priv_data *) rig->state.priv; - vfo = priv->vfo_curr; + vfo = priv->curr_vfo; } - sprintf(value, "%s", - vfo == RIG_VFO_A ? "A" : "B"); - pxml = xml_build("rig.set_AB", value); - retval = write_block(&rs->rigport, pxml, strlen(pxml)); + if (check_vfo(vfo) == FALSE) { + rig_debug(RIG_DEBUG_ERR, "%s: unsupported VFO %s\n", + __FUNCTION__, rig_strvfo(vfo)); + return -RIG_EINVAL; + } + // + // Don't touch mode or width if PTT=true + ptt_t ptt; + retval = flrig_get_ptt(rig,RIG_VFO_A,&ptt); + if (ptt) { + priv->ptt = 1; + rig_debug(RIG_DEBUG_ERR,"%s call not made as PTT=1\n",__FUNCTION__); + return RIG_OK; // just return OK and ignore this + } + // Switch to VFOB if appropriate since we can't set mode directly + // MDB + int vfoSwitched = 0; + rig_debug(RIG_DEBUG_WARN,"%s: curr_vfo = %s\n",__FUNCTION__,rig_strvfo(priv->curr_vfo)); + if (vfo == RIG_VFO_B && priv->curr_vfo != RIG_VFO_B) { + vfoSwitched = 1; + rig_debug(RIG_DEBUG_WARN,"%s: switch to VFOB = %d\n",__FUNCTION__,vfoSwitched); + } + + if (vfoSwitched) { // swap to B and we'll swap back later + rig_debug(RIG_DEBUG_WARN,"%s: switching to VFOB = %d\n",__FUNCTION__,vfoSwitched); + retval = flrig_set_vfo(rig, RIG_VFO_B); + if (retval < 0) { + return retval; + } + } + + // Set the mode + char *ttmode = modeMapGetFLRig(mode); + + char cmd_buf[MAXCMDLEN]; + sprintf(cmd_buf, "%s", ttmode); + char xml[MAXXMLLEN]; + char *pxml = xml_build("rig.set_mode", cmd_buf, xml, sizeof(xml)); + + retval = write_transaction(rig, pxml, strlen(pxml)); + if (retval < 0) { + return retval; + } + + // Get the response + read_transaction(rig, xml, sizeof(xml)); + rig_debug(RIG_DEBUG_VERBOSE, "%s: response=%s\n", __FUNCTION__,xml); + + // Need to update the available bandwidths for this mode + if (width > 0) { + sprintf(cmd_buf, "%ld", width); + pxml = xml_build("rig.set_bandwidth", cmd_buf, xml, sizeof(xml)); + retval = write_transaction(rig, pxml, strlen(pxml)); + if (retval < 0) { + return retval; + } + read_transaction(rig, xml, sizeof(xml)); + } + + // Return to VFOA if needed + rig_debug(RIG_DEBUG_WARN,"%s: switch to VFOA? = %d\n",__FUNCTION__,vfoSwitched); + if (vfoSwitched) { + rig_debug(RIG_DEBUG_WARN,"%s: switching to VFOA\n",__FUNCTION__); + retval = flrig_set_vfo(rig, RIG_VFO_A); + if (retval < 0) { + return retval; + } + } + + if (vfo == RIG_VFO_A) { + priv->curr_modeA = mode; + priv->curr_widthA = width; + } + else { + priv->curr_modeB = mode; + priv->curr_widthB = width; + } + + return RIG_OK; +} + +/* + * flrig_get_mode + * Assumes rig!=NULL, rig->state.priv!=NULL, mode!=NULL + */ +static int flrig_get_mode(RIG *rig, vfo_t vfo, rmode_t *mode, pbwidth_t *width) +{ + int retval; + + rig_debug(RIG_DEBUG_TRACE, "%s: vfo=%s\n", __FUNCTION__, + rig_strvfo(vfo)); + + struct flrig_priv_data *priv = (struct flrig_priv_data *) rig->state.priv; + + if (check_vfo(vfo) == FALSE) { + rig_debug(RIG_DEBUG_ERR, "%s: unsupported VFO %s\n", + __FUNCTION__, rig_strvfo(vfo)); + return -RIG_EINVAL; + } + + vfo_t curr_vfo = priv->curr_vfo; + if (vfo == RIG_VFO_CURR) { + vfo = priv->curr_vfo; + } + rig_debug(RIG_DEBUG_TRACE, "%s: using vfo=%s\n", __FUNCTION__, + rig_strvfo(vfo)); + // + // Don't touch mode or width if PTT=true + ptt_t ptt; + retval = flrig_get_ptt(rig,RIG_VFO_A,&ptt); + if (ptt) { + priv->ptt = 1; + if (vfo == RIG_VFO_A) *mode = priv->curr_modeA; + else *mode = priv->curr_modeB; + rig_debug(RIG_DEBUG_ERR,"%s call not made as PTT=1\n",__FUNCTION__); + return RIG_OK; // just return OK and ignore this + } + + // Switch to VFOB if appropriate + int vfoSwitched=0; + if (vfo == RIG_VFO_B && curr_vfo != RIG_VFO_B) { + vfoSwitched = 1; + } + + if (vfoSwitched) { + retval = flrig_set_vfo(rig, RIG_VFO_B); + if (retval < 0) { + return retval; + } + } + + char xml[MAXXMLLEN]; + char *pxml = xml_build("rig.get_mode", NULL, xml, sizeof(xml)); + retval = write_transaction(rig, pxml, strlen(pxml)); if (retval < 0) { return retval; } read_transaction(rig, xml, sizeof(xml)); - //xml_parse(xml,value,sizeof(value)); - vfo_t vfotmp; - flrig_get_vfo(rig, &vfotmp); - - return RIG_OK; - -} - -int flrig_get_vfo(RIG *rig, vfo_t *vfo) -{ char value[MAXCMDLEN]; - char *pxml; - int retval; - struct rig_state *rs; - char xml[8192]; + xml_parse(xml, value, sizeof(value)); + retval = modeMapGetHamlib(value); + if (retval < 0 ) { + return retval; + } + *mode = retval; + rig_debug(RIG_DEBUG_VERBOSE, "%s: mode='%s'\n", __FUNCTION__, rig_strrmode(*mode)); + if (vfo == RIG_VFO_A) { + priv->curr_modeA = *mode; + } + else { + priv->curr_modeB = *mode; + } - rig_debug(RIG_DEBUG_TRACE, "%s\n", __FUNCTION__); - rs = &rig->state; - - pxml = xml_build("rig.get_AB", NULL); - retval = write_block(&rs->rigport, pxml, strlen(pxml)); + // Get the bandwidth + pxml = xml_build("rig.get_bw", NULL, xml, sizeof(xml)); + retval = write_transaction(rig, pxml, strlen(pxml)); if (retval < 0) { return retval; } read_transaction(rig, xml, sizeof(xml)); xml_parse(xml, value, sizeof(value)); + rig_debug(RIG_DEBUG_VERBOSE, "%s: mode=%s width='%s'\n", __FUNCTION__, rig_strrmode(*mode), value); + // we get 2 entries pipe separated for bandwidth, lower and upper + if(strlen(value)>0) { + char *p=value; + /* we might get two values and then we want the 2nd one */ + if (strchr(value,'|')!=NULL) p=strchr(value,'|')+1; + *width = atoi(p); + } + if (vfo == RIG_VFO_A) { + priv->curr_widthA = *width; + } + else { + priv->curr_widthB = *width; + } + + // Return to VFOA if needed + if (vfoSwitched) { + retval = flrig_set_vfo(rig, RIG_VFO_A); + if (retval < 0) { + return retval; + } + } + + return RIG_OK; +} + +/* + * flrig_get_vfo + * assumes rig!=NULL + */ +static int flrig_set_vfo(RIG *rig, vfo_t vfo) +{ + int retval; + + rig_debug(RIG_DEBUG_TRACE, "%s: vfo=%s\n", __FUNCTION__, + rig_strvfo(vfo)); + + struct rig_state *rs = &rig->state; + struct flrig_priv_data *priv = (struct flrig_priv_data *) rig->state.priv; + + if (check_vfo(vfo) == FALSE) { + rig_debug(RIG_DEBUG_ERR, "%s: unsupported VFO %s\n", + __FUNCTION__, rig_strvfo(vfo)); + return -RIG_EINVAL; + } + if (vfo == RIG_VFO_TX) { + rig_debug(RIG_DEBUG_VERBOSE, "%s: RIG_VFO_TX used\n"); + vfo = RIG_VFO_B; // always TX on VFOB + } + + if (vfo == RIG_VFO_CURR) { + vfo = priv->curr_vfo; + } + + // Force PTT off + // Why were we turning off PTT here? + // flrig_set_ptt(rig,RIG_VFO_A,0); + + char value[MAXCMDLEN]; + char xml[MAXXMLLEN]; + sprintf(value, "%s", + vfo == RIG_VFO_A ? "A" : "B"); + char *pxml = xml_build("rig.set_AB", value, xml, sizeof(xml)); + retval = write_transaction(rig, pxml, strlen(pxml)); + + if (retval < 0) { + return retval; + } + //usleep(50*1000); // temporary sleep until flrig is fixed + priv->curr_vfo = vfo; + rs->tx_vfo = RIG_VFO_B; // always VFOB + read_transaction(rig, xml, sizeof(xml)); + + return RIG_OK; +} + +/* + * flrig_get_vfo + * assumes rig!=NULL, vfo != NULL + */ +static int flrig_get_vfo(RIG *rig, vfo_t *vfo) +{ + int retval; + + rig_debug(RIG_DEBUG_TRACE, "%s\n", __FUNCTION__); + + struct flrig_priv_data *priv = (struct flrig_priv_data *) rig->state.priv; + + char xml[MAXXMLLEN]; + char *pxml = xml_build("rig.get_AB", NULL, xml, sizeof(xml)); + retval = write_transaction(rig, pxml, strlen(pxml)); + + if (retval < 0) { + return retval; + } + + read_transaction(rig, xml, sizeof(xml)); + char value[MAXCMDLEN]; + xml_parse(xml, value, sizeof(value)); + rig_debug(RIG_DEBUG_VERBOSE, "%s: vfo value=%s\n", __FUNCTION__,value); switch (value[0]) { case 'A': @@ -688,10 +1167,7 @@ int flrig_get_vfo(RIG *rig, vfo_t *vfo) return -RIG_EINVAL; } - struct flrig_priv_data *priv = - (struct flrig_priv_data *) rig->state.priv; - - priv->vfo_curr = *vfo; + priv->curr_vfo = *vfo; rig_debug(RIG_DEBUG_VERBOSE, "%s: vfo=%s\n", __FUNCTION__, rig_strvfo(*vfo)); @@ -701,25 +1177,16 @@ int flrig_get_vfo(RIG *rig, vfo_t *vfo) /* * flrig_set_split_freq - * Note that split doesn't work for FLRig models that don't have reply codes - * Like most Yaesu rigs. The commands will overrun FLRig in those cases. - * Rigs that do have replies for all cat commands will work with split + * assumes rig!=NULL */ -int flrig_set_split_freq(RIG *rig, vfo_t vfo, freq_t tx_freq) +static int flrig_set_split_freq(RIG *rig, vfo_t vfo, freq_t tx_freq) { - char value[MAXCMDLEN]; - char *pxml; int retval; - struct rig_state *rs; - char xml[8192]; rig_debug(RIG_DEBUG_TRACE, "%s: vfo=%s freq=%.1f\n", __FUNCTION__, rig_strvfo(vfo), tx_freq); - rs = &rig->state; - if (vfo == RIG_VFO_SUB) { - vfo = RIG_VFO_B; - } + struct flrig_priv_data *priv = (struct flrig_priv_data *) rig->state.priv; if (check_vfo(vfo) == FALSE) { rig_debug(RIG_DEBUG_ERR, "%s: unsupported VFO %s\n", @@ -727,22 +1194,18 @@ int flrig_set_split_freq(RIG *rig, vfo_t vfo, freq_t tx_freq) return -RIG_EINVAL; } - if (!vfo_curr(rig, vfo)) { - flrig_set_vfo(rig, vfo); - } - + char xml[MAXXMLLEN]; + char value[MAXCMDLEN]; sprintf(value, - "%.6f", - tx_freq); - pxml = xml_build("rig.set_vfo", value); - retval = write_block(&rs->rigport, pxml, strlen(pxml)); - + "%.6f", tx_freq); + char *pxml = xml_build("rig.set_vfoB", value, xml, sizeof(xml)); + retval = write_transaction(rig, pxml, strlen(pxml)); if (retval < 0) { return retval; } + priv->curr_freqB = tx_freq; - read_transaction(rig, xml, sizeof(xml)); - xml_parse(xml, value, sizeof(value)); + read_transaction(rig, xml, sizeof(xml)); // get response but don't care return RIG_OK; } @@ -751,51 +1214,58 @@ int flrig_set_split_freq(RIG *rig, vfo_t vfo, freq_t tx_freq) * flrig_get_split_freq * assumes rig!=NULL, tx_freq!=NULL */ -int flrig_get_split_freq(RIG *rig, vfo_t vfo, freq_t *tx_freq) +static int flrig_get_split_freq(RIG *rig, vfo_t vfo, freq_t *tx_freq) { rig_debug(RIG_DEBUG_TRACE, "%s: vfo=%s\n", __FUNCTION__, rig_strvfo(vfo)); - return flrig_get_freq(rig, vfo, tx_freq); + int retval = flrig_get_freq(rig, RIG_VFO_B, tx_freq); + return retval; } /* * flrig_set_split_vfo * assumes rig!=NULL, tx_freq!=NULL */ -int flrig_set_split_vfo(RIG *rig, vfo_t vfo, split_t split, vfo_t tx_vfo) +static int flrig_set_split_vfo(RIG *rig, vfo_t vfo, split_t split, vfo_t tx_vfo) { - char value[MAXCMDLEN]; - char *pxml; int retval; - struct rig_state *rs; - char xml[8192]; rig_debug(RIG_DEBUG_TRACE, "%s: tx_vfo=%s\n", __FUNCTION__, rig_strvfo(tx_vfo)); - rs = &rig->state; - if (tx_vfo == RIG_VFO_SUB) { + struct flrig_priv_data *priv = (struct flrig_priv_data *) rig->state.priv; + + if (tx_vfo == RIG_VFO_SUB || tx_vfo == RIG_VFO_TX) { tx_vfo = RIG_VFO_B; } - if (!vfo_curr(rig, vfo)) { - flrig_set_vfo(rig, vfo); + + // Don't touch split if PTT=true + ptt_t ptt; + retval = flrig_get_ptt(rig,RIG_VFO_A,&ptt); + if (ptt) { + priv->ptt = 1; + rig_debug(RIG_DEBUG_ERR,"%s call not made as PTT=1\n",__FUNCTION__); + return RIG_OK; // just return OK and ignore this } - sprintf(value, - "%d", - split); - pxml = xml_build("rig.set_split", value); - retval = write_block(&rs->rigport, pxml, strlen(pxml)); + /* for flrig we have to be on VFOA when we set split for VFOB Tx */ + /* we can keep the rig on VFOA since we can set freq by VFO now */ + if (!vfo_curr(rig, RIG_VFO_A)) { + flrig_set_vfo(rig, RIG_VFO_A); + } + char xml[MAXXMLLEN]; + char value[MAXCMDLEN]; + sprintf(value, "%d", split); + char *pxml = xml_build("rig.set_split", value, xml, sizeof(xml)); + retval = write_transaction(rig, pxml, strlen(pxml)); if (retval < 0) { return retval; } - - read_transaction(rig, xml, sizeof(xml)); - //xml_parse(xml, value, sizeof(value)); - - //flrig_set_vfo(rig,RIG_VFO_A); + priv->split = split; + + read_transaction(rig, xml, sizeof(xml)); // get response but don't care return RIG_OK; } @@ -804,40 +1274,105 @@ int flrig_set_split_vfo(RIG *rig, vfo_t vfo, split_t split, vfo_t tx_vfo) * flrig_get_split_vfo * assumes rig!=NULL, tx_freq!=NULL */ -int flrig_get_split_vfo(RIG *rig, vfo_t vfo, split_t *split, - vfo_t *tx_vfo) +static int flrig_get_split_vfo(RIG *rig, vfo_t vfo, split_t *split, + vfo_t *tx_vfo) { - char value[MAXCMDLEN]; - char *pxml; int retval; - struct rig_state *rs; - char xml[8192]; rig_debug(RIG_DEBUG_TRACE, "%s\n", __FUNCTION__); - rs = &rig->state; - //flrig_set_vfo(rig,RIG_VFO_B); + struct flrig_priv_data *priv = (struct flrig_priv_data *) rig->state.priv; - pxml = xml_build("rig.get_split", NULL); - retval = write_block(&rs->rigport, pxml, strlen(pxml)); + char xml[MAXXMLLEN]; + char *pxml = xml_build("rig.get_split", NULL, xml, sizeof(xml)); + retval = write_transaction(rig, pxml, strlen(pxml)); if (retval < 0) { return retval; } + char value[MAXCMDLEN]; read_transaction(rig, xml, sizeof(xml)); xml_parse(xml, value, sizeof(value)); - //flrig_set_vfo(rig,RIG_VFO_A); - *tx_vfo = RIG_VFO_B; *split = atoi(value); - + priv->split = *split; + rig_debug(RIG_DEBUG_VERBOSE,"%s tx_vfo=%s, split=%d\n",__FUNCTION__,rig_strvfo(*tx_vfo),*split); return RIG_OK; } /* - .set_split_freq = flrig_set_split_freq, - .get_split_freq = flrig_get_split_freq, - .set_split_mode = flrig_set_split_mode, - .get_split_mode = flrig_get_split_mode, -*/ + * flrig_set_split_freq_mode + * assumes rig!=NULL + */ +static int flrig_set_split_freq_mode(RIG *rig, vfo_t vfo, freq_t freq, rmode_t mode, pbwidth_t width) +{ + int retval; + + rig_debug(RIG_DEBUG_TRACE, "%s\n", __FUNCTION__); + + struct flrig_priv_data *priv = (struct flrig_priv_data *) rig->state.priv; + + if (vfo != RIG_VFO_CURR && vfo != RIG_VFO_TX) + return -RIG_ENTARGET; + + + // Don't touch split if PTT=true + ptt_t ptt; + retval = flrig_get_ptt(rig,RIG_VFO_A,&ptt); + if (ptt) { + priv->ptt = 1; + rig_debug(RIG_DEBUG_ERR,"%s call not made as PTT=1\n",__FUNCTION__); + return RIG_OK; // just return OK and ignore this + } + + // assume split is on B + // swap to VFOB to prevent lots of vfo swapping while seting up VFOB + flrig_set_vfo(rig,RIG_VFO_B); + retval = flrig_set_freq (rig, RIG_VFO_B, freq); + if (retval != RIG_OK) { + rig_debug(RIG_DEBUG_ERR, "%s flrig_set_freq failed\n", __FUNCTION__); + return retval; + } + // Make VFOB mode match VFOA mode, keep VFOB width + retval = flrig_set_mode(rig,RIG_VFO_B,priv->curr_modeA,width); + if (retval != RIG_OK) { + rig_debug(RIG_DEBUG_ERR, "%s flrig_set_mode failed\n", __FUNCTION__); + return retval; + } + + retval = flrig_set_vfo(rig,RIG_VFO_A); + + return retval; +} + +/* + * flrig_get_split_freq_mode + * assumes rig!=NULL, freq!=NULL, mode!=NULL, width!=NULL + */ +static int flrig_get_split_freq_mode(RIG *rig, vfo_t vfo, freq_t *freq, rmode_t *mode, pbwidth_t *width) +{ + int retval; + + if (vfo != RIG_VFO_CURR && vfo != RIG_VFO_TX) + return -RIG_ENTARGET; + + retval = flrig_get_freq (rig, RIG_VFO_B, freq); + if (RIG_OK == retval) { + retval = flrig_get_mode(rig,vfo,mode,width); + } + + return retval; +} + +/* + * flrig_get_info + * assumes rig!=NULL + */ +static const char *flrig_get_info(RIG *rig) +{ + struct flrig_priv_data *priv = (struct flrig_priv_data *) rig->state.priv; + rig_debug(RIG_DEBUG_VERBOSE, "%s called\n", __FUNCTION__); + + return priv->info; +} diff --git a/dummy/flrig.h b/dummy/flrig.h index 85f5b26b3..db8d02bfe 100644 --- a/dummy/flrig.h +++ b/dummy/flrig.h @@ -28,12 +28,11 @@ #include #endif -#define BACKEND_VER "0.1" +#define BACKEND_VER "1.0" #define EOM "\r" #define TRUE 1 #define FALSE 0 -#define BUF_MAX 32768 extern const struct rig_caps flrig_caps; From 29e976878fd1b7913498ba64a824c9f68d938142 Mon Sep 17 00:00:00 2001 From: "Brian G. Lucas" Date: Thu, 10 May 2018 11:55:55 -0500 Subject: [PATCH 16/17] Fix a format so that it works with Windows. Can't test it because I have no Windows machines. --- kenwood/thd72.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kenwood/thd72.c b/kenwood/thd72.c index fc4569234..13e3f09fc 100644 --- a/kenwood/thd72.c +++ b/kenwood/thd72.c @@ -265,7 +265,7 @@ static int thd72_set_freq(RIG *rig, vfo_t vfo, freq_t freq) retval = thd72_get_freq_info(rig, vfo, buf); if (retval != RIG_OK) return retval; - sprintf(fbuf, "%010ld", (int64_t)freq); + sprintf(fbuf, "%010"PRIll, (int64_t)freq); memcpy(buf+5, fbuf, 10); retval = kenwood_simple_transaction(rig, buf, 52); return retval; From 9a0ad97e836df399003aa7bdc1d69f1b5290058f Mon Sep 17 00:00:00 2001 From: Michael Black W9MDB Date: Thu, 10 May 2018 16:52:47 -0500 Subject: [PATCH 17/17] Another fix for gettings modes correct --- dummy/trxmanager.c | 90 +++++++++++++++++++++++++++++++++------------- dummy/trxmanager.h | 2 +- 2 files changed, 66 insertions(+), 26 deletions(-) diff --git a/dummy/trxmanager.c b/dummy/trxmanager.c index d0771c9e1..70402ea33 100644 --- a/dummy/trxmanager.c +++ b/dummy/trxmanager.c @@ -54,6 +54,29 @@ #define streq(s1,s2) (strcmp(s1,s2)==0) +#define FLRIG_MODE_LSB '1' +#define FLRIG_MODE_USB '2' +#define FLRIG_MODE_CW '3' +#define FLRIG_MODE_FM '4' +#define FLRIG_MODE_AM '5' +#define FLRIG_MODE_RTTY '6' +#define FLRIG_MODE_CWR '7' +#define FLRIG_MODE_RTTYR '9' +#define FLRIG_MODE_PKTLSB 'C' +#define FLRIG_MODE_PKTUSB 'D' +#define FLRIG_MODE_PKTFM 'E' +#define FLRIG_MODE_PKTAM 'F' +// Hamlib doesn't support D2/D3 modes in hamlib yet +// So we define them here but they aren't implmented +#define FLRIG_MODE_PKTLSB2 'G' +#define FLRIG_MODE_PKTUSB2 'H' +#define FLRIG_MODE_PKTFM2 'I' +#define FLRIG_MODE_PKTAM2 'J' +#define FLRIG_MODE_PKTLSB3 'K' +#define FLRIG_MODE_PKTUSB3 'L' +#define FLRIG_MODE_PKTFM3 'M' +#define FLRIG_MODE_PKTAM3 'N' + static int trxmanager_init(RIG *rig); static int trxmanager_open(RIG *rig); static int trxmanager_close(RIG *rig); @@ -152,7 +175,7 @@ struct rig_caps trxmanager_caps = { }; /* - * vfo_curr + * check_vfo * No assumptions */ static int check_vfo(vfo_t vfo) @@ -175,6 +198,7 @@ static int check_vfo(vfo_t vfo) return TRUE; } +#if 0 // looks like we don't need this but it's here just in case /* * vfo_curr * Assumes rig!=NULL @@ -193,6 +217,7 @@ static int vfo_curr(RIG *rig, vfo_t vfo) retval = (vfo == vfocurr); return retval; } +#endif /* * read_transaction @@ -265,7 +290,6 @@ static int trxmanager_open(RIG *rig) { if (retval != RIG_OK) { rig_debug(RIG_DEBUG_ERR,"%s read_transaction failed\n", __FUNCTION__); } - rig_debug(RIG_DEBUG_VERBOSE,"%s connected to %s\n", __FUNCTION__, response); if (strlen(response)==0) { rig_debug(RIG_DEBUG_ERR,"%s response len==0\n", __FUNCTION__); return -RIG_EPROTO; @@ -274,6 +298,7 @@ static int trxmanager_open(RIG *rig) { // Should have rig info now strtok(response,";\r\n"); strncpy(priv->info,&response[2],sizeof(priv->info)); + rig_debug(RIG_DEBUG_VERBOSE,"%s connected to %s\n", __FUNCTION__, priv->info); // Turn off active messages char *cmd = "AI0;"; @@ -540,37 +565,43 @@ static int trxmanager_set_mode(RIG *rig, vfo_t vfo, rmode_t mode, pbwidth_t widt return -RIG_EINVAL; } - int ttmode=0; + char ttmode=FLRIG_MODE_USB; switch(mode) { case RIG_MODE_LSB: - ttmode=1; + ttmode=RIG_MODE_LSB; break; case RIG_MODE_USB: - ttmode=2; + ttmode=RIG_MODE_USB; break; case RIG_MODE_CW: - ttmode=3; + ttmode=FLRIG_MODE_CW; break; case RIG_MODE_FM: - ttmode=4; + ttmode=FLRIG_MODE_FM; break; case RIG_MODE_AM: - ttmode=5; + ttmode=FLRIG_MODE_AM; break; case RIG_MODE_RTTY: - ttmode=6; + ttmode=FLRIG_MODE_RTTY; break; case RIG_MODE_CWR: - ttmode=7; + ttmode=FLRIG_MODE_CWR; break; case RIG_MODE_RTTYR: - ttmode=9; + ttmode=FLRIG_MODE_RTTYR; break; case RIG_MODE_PKTLSB: - ttmode=9; + ttmode=FLRIG_MODE_PKTLSB; break; case RIG_MODE_PKTUSB: - ttmode=9; + ttmode=FLRIG_MODE_PKTUSB; + break; + case RIG_MODE_PKTFM: + ttmode=FLRIG_MODE_PKTFM; + break; + case RIG_MODE_PKTAM: + ttmode=FLRIG_MODE_PKTAM; break; default: rig_debug(RIG_DEBUG_ERR, "%s: unsupported mode %s\n",__FUNCTION__,rig_strrmode(mode)); @@ -580,7 +611,7 @@ static int trxmanager_set_mode(RIG *rig, vfo_t vfo, rmode_t mode, pbwidth_t widt char cmd[MAXCMDLEN]; char response[MAXCMDLEN]=""; - snprintf(cmd,sizeof(cmd), "MD%d;", ttmode); + snprintf(cmd,sizeof(cmd), "MD%c;", ttmode); retval = write_block(&rs->rigport, cmd, strlen(cmd)); if (retval < 0) { return retval; @@ -646,39 +677,39 @@ static int trxmanager_get_mode(RIG *rig, vfo_t vfo, rmode_t *mode, pbwidth_t *wi return -RIG_EPROTO; } switch(tmode) { - case '1': + case FLRIG_MODE_LSB: *mode=RIG_MODE_LSB; break; - case '2': + case FLRIG_MODE_USB: *mode=RIG_MODE_USB; break; - case '3': + case FLRIG_MODE_CW: *mode=RIG_MODE_CW; break; - case '4': + case FLRIG_MODE_FM: *mode=RIG_MODE_FM; break; - case '5': + case FLRIG_MODE_AM: *mode=RIG_MODE_AM; break; - case '6': + case FLRIG_MODE_RTTY: *mode=RIG_MODE_RTTY; break; - case '7': + case FLRIG_MODE_CWR: *mode=RIG_MODE_CWR; break; - case '9': + case FLRIG_MODE_RTTYR: *mode=RIG_MODE_RTTYR; break; - case 'A': + case FLRIG_MODE_PKTLSB: *mode=RIG_MODE_PKTLSB; break; - case 'B': + case FLRIG_MODE_PKTUSB: *mode=RIG_MODE_PKTUSB; break; default: rig_debug(RIG_DEBUG_ERR, "%s: unknown mode='%c'\n", __FUNCTION__, tmode); - return -RIG_EINVAL; + return -RIG_ENIMPL; } rig_debug(RIG_DEBUG_VERBOSE, "%s: mode='%s'\n", __FUNCTION__, rig_strrmode(*mode)); @@ -854,11 +885,20 @@ static int trxmanager_set_split_vfo(RIG *rig, vfo_t vfo, split_t split, vfo_t tx tx_vfo = RIG_VFO_B; } +#if 0 /* for flrig we have to be on VFOA when we set split for VFOB Tx */ /* we can keep the rig on VFOA since we can set freq by VFO now */ if (!vfo_curr(rig, RIG_VFO_A)) { trxmanager_set_vfo(rig, RIG_VFO_A); } +#endif + split_t tsplit; + vfo_t ttx_vfo; + retval = trxmanager_get_split_vfo(rig, vfo, &tsplit, &ttx_vfo); + if (retval < 0) { + return retval; + } + if (tsplit == split) return RIG_OK; // don't need to change it char cmd[MAXCMDLEN]; char response[MAXCMDLEN]=""; snprintf(cmd,sizeof(cmd),"SP%c;", split ? '1' : '0'); diff --git a/dummy/trxmanager.h b/dummy/trxmanager.h index c2fda3b3a..37fa8f1cf 100644 --- a/dummy/trxmanager.h +++ b/dummy/trxmanager.h @@ -30,7 +30,7 @@ #include #endif -#define BACKEND_VER "1.1" +#define BACKEND_VER "1.2" #define EOM "\r" #define TRUE 1