From 7e3ed7074aa2fb94124872182a794370d71d119e Mon Sep 17 00:00:00 2001 From: Weston Bustraan Date: Tue, 16 Jun 2020 16:46:53 -0400 Subject: [PATCH 1/3] Moved Alinco DX-77-specific functions out of alinco.c and into dx77.c. The protocol used by the DX-77 is different than the DX-SR* line --- rigs/alinco/alinco.c | 1241 ----------------------------------------- rigs/alinco/dx77.c | 1247 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 1247 insertions(+), 1241 deletions(-) diff --git a/rigs/alinco/alinco.c b/rigs/alinco/alinco.c index daa2ec1fe..2699f9c3f 100644 --- a/rigs/alinco/alinco.c +++ b/rigs/alinco/alinco.c @@ -30,1246 +30,5 @@ #include #include -#include -#include -#include -#include #include "alinco.h" - - -/* Line Feed */ -#define EOM "\x0d" -#define LF "\x0a" - -#define BUFSZ 32 - -/* - * modes in use by the "2G" command - */ -#define MD_LSB '0' -#define MD_USB '1' -#define MD_CWL '2' -#define MD_CWU '3' -#define MD_AM '4' -#define MD_FM '5' - -#define AL "AL" -#define CMD_TXFREQ "0A" /* Transmit frequency */ -#define CMD_RXFREQ "0B" /* Receive frequency */ -#define CMD_VFO "1A" -#define CMD_MEMMD "1B" /* Memory mode */ -#define CMD_CHAN "1D" /* Channel Display */ -#define CMD_UPDWN "2A" /* UP/DOWN */ -#define CMD_MON "2B" /* Check Transmit Frequency */ -#define CMD_PWR "2C" /* Transmit Output Power */ -#define CMD_SCAN "2D" /* Scanning */ -#define CMD_PRIO "2E" /* Priority */ -#define CMD_SPLT "2F" /* Split */ -#define CMD_MODE "2G" /* Mode */ -#define CMD_RFGAIN "2H" /* RF Gain */ -#define CMD_AGC "2I" -#define CMD_FLTER "2J" /* Filter */ -#define CMD_NB "2K" -#define CMD_CTCSS "2L" -#define CMD_TUNE "2M" -#define CMD_SELECT "2N" -#define CMD_MCALL "2V" /* Memory Channel Call Up */ -#define CMD_SDATA "2W" /* Set Data */ - -/* Data Output Commands */ -#define CMD_SMETER "3A" /* S-meter read */ -#define CMD_PTT "3B" /* PTT status read */ -#define CMD_SQL "3C" /* Squelch status */ -#define CMD_RIT "3D" /* RIT status */ -#define CMD_RMEM "3E" /* Current Memory-channel Number read */ -#define CMD_RMV "3G" /* Memory/VFO -mode read */ -#define CMD_RDATA "3H" /* Current Data read */ -#define CMD_RSPLT "3I" /* Split read */ -#define CMD_RPOWER "3J" /* Transmitter Output read */ -#define CMD_RSELECT "3K" /* SELECT Postion read */ - - -/* - * alinco_transaction - * We assume that rig!=NULL, rig->state!= NULL, data!=NULL, data_len!=NULL - * Otherwise, you'll get a nice seg fault. You've been warned! - * TODO: error case handling - */ -int alinco_transaction(RIG *rig, - const char *cmd, - int cmd_len, - char *data, - int *data_len) -{ - int retval; - struct rig_state *rs; - char echobuf[BUFSZ + 1]; - - if (cmd == NULL) - { - rig_debug(RIG_DEBUG_ERR, - "%s: null argument for cmd?\n", __func__); - return -RIG_EINTERNAL; - } - - rs = &rig->state; - - serial_flush(&rs->rigport); - - retval = write_block(&rs->rigport, cmd, cmd_len); - - if (retval != RIG_OK) - { - return retval; - } - - /* - * Transceiver sends an echo of cmd followed by a CR/LF - * TODO: check whether cmd and echobuf match (optional) - */ - retval = read_string(&rs->rigport, echobuf, BUFSZ, LF, strlen(LF)); - - if (retval < 0) - { - return retval; - } - - if (!(data && data_len)) - { - rig_debug(RIG_DEBUG_ERR, "%s: data and datalen not both NULL??\n", __func__); - return -RIG_EINTERNAL; - } - - /* no data expected, check for OK returned */ - if (data == NULL) - { - retval = read_string(&rs->rigport, echobuf, BUFSZ, LF, strlen(LF)); - - if (retval < 0) - { - return retval; - } - - if (retval > 2) { retval -= 2; } - - echobuf[retval] = 0; - - if (strcmp(echobuf, "OK") == 0) - { - return RIG_OK; - } - else - { - return -RIG_ERJCTED; - } - } - - retval = read_string(&rs->rigport, data, BUFSZ, LF, strlen(LF)); - - if (retval < 0) - { - return retval; - } - - *data_len = retval; - - /* strip CR/LF from string - */ - data[0] = 0; - - if (*data_len > 2) - { - *data_len -= 2; - data[*data_len] = 0; - } - - return RIG_OK; -} - - -/* - * alinco_set_vfo - * Assumes rig!=NULL - */ -int alinco_set_vfo(RIG *rig, vfo_t vfo) -{ - char cmdbuf[BUFSZ]; - int cmd_len; - char vfo_num; - - switch (vfo) - { - case RIG_VFO_A: vfo_num = '1'; break; - - case RIG_VFO_B: vfo_num = '2'; break; - - case RIG_VFO_MEM: - return alinco_transaction(rig, - AL CMD_MEMMD "0" EOM, - strlen(AL CMD_MEMMD "0" EOM), - NULL, - NULL); - - default: - rig_debug(RIG_DEBUG_ERR, - "alinco_set_vfo: unsupported VFO %s\n", - rig_strvfo(vfo)); - - return -RIG_EINVAL; - } - - cmd_len = sprintf(cmdbuf, AL CMD_VFO "%c" EOM, vfo_num); - - return alinco_transaction(rig, cmdbuf, cmd_len, NULL, NULL); -} - - -/* - * alinco_get_vfo - * Assumes rig!=NULL, !vfo - */ -int alinco_get_vfo(RIG *rig, vfo_t *vfo) -{ - char vfobuf[BUFSZ]; - int vfo_len, retval; - - retval = alinco_transaction(rig, - AL CMD_RMV EOM, - strlen(AL CMD_RMV EOM), - vfobuf, - &vfo_len); - - if (retval != RIG_OK) - { - return retval; - } - - if (vfo_len != 4) - { - rig_debug(RIG_DEBUG_ERR, - "alinco_get_vfo: wrong answer %s, " - "len=%d\n", - vfobuf, - vfo_len); - - return -RIG_ERJCTED; - } - - vfobuf[vfo_len] = '\0'; - - if (!strcmp(vfobuf, "VFOA")) - { - *vfo = RIG_VFO_A; - } - else if (!strcmp(vfobuf, "VFOB")) - { - *vfo = RIG_VFO_B; - } - else if (!strcmp(vfobuf, "MEMO")) - { - *vfo = RIG_VFO_MEM; - } - else - { - rig_debug(RIG_DEBUG_ERR, - "alinco_get_vfo: unsupported VFO %s\n", - vfobuf); - - return -RIG_EPROTO; - } - - return RIG_OK; -} - - -/* - * alinco_set_freq - * Assumes rig!=NULL - */ -int alinco_set_freq(RIG *rig, vfo_t vfo, freq_t freq) -{ - char freqbuf[BUFSZ]; - int freq_len; - - /* max 10 digits */ - if (freq >= GHz(10)) - { - return -RIG_EINVAL; - } - - /* at least 6 digits */ - // cppcheck-suppress * - freq_len = sprintf(freqbuf, AL CMD_RXFREQ "%06"PRIll EOM, (int64_t)freq); - - return alinco_transaction(rig, freqbuf, freq_len, NULL, NULL); -} - - -/* - * where databuf points to a 26 char long buffer - */ -static int current_data_read(RIG *rig, char *databuf) -{ - int data_len, retval; - - retval = alinco_transaction(rig, - AL CMD_RDATA EOM, - strlen(AL CMD_RDATA EOM), - databuf, - &data_len); - - if (retval != RIG_OK) - { - return retval; - } - - if (data_len != 26) - { - rig_debug(RIG_DEBUG_ERR, - "alinco_current_data_read: wrong answer %s, len=%d\n", - databuf, - data_len); - - return -RIG_ERJCTED; - } - - return RIG_OK; -} - - -/* - * alinco_get_freq - * Assumes rig!=NULL, freq!=NULL - */ -int alinco_get_freq(RIG *rig, vfo_t vfo, freq_t *freq) -{ - int retval; - char freqbuf[BUFSZ]; - - retval = current_data_read(rig, freqbuf); - - if (retval != RIG_OK) - { - return retval; - } - - /* extract RX freq */ - freqbuf[16] = '\0'; - sscanf(freqbuf + 6, "%"SCNfreq, freq); - - return RIG_OK; -} - - -/* - * alinco_set_mode - * Assumes rig!=NULL - */ -int alinco_set_mode(RIG *rig, vfo_t vfo, rmode_t mode, pbwidth_t width) -{ - char mdbuf[BUFSZ]; - int mdbuf_len, wide_filter, retval; - char amode; - - switch (mode) - { - /* FIXME: MD_CWL or MD_CWU? */ - case RIG_MODE_CW: amode = MD_CWU; break; - - case RIG_MODE_USB: amode = MD_USB; break; - - case RIG_MODE_LSB: amode = MD_LSB; break; - - case RIG_MODE_FM: amode = MD_FM; break; - - case RIG_MODE_AM: amode = MD_AM; break; - - default: - rig_debug(RIG_DEBUG_ERR, "alinco_set_mode: unsupported mode %s\n", - rig_strrmode(mode)); - - return -RIG_EINVAL; - } - - mdbuf_len = sprintf(mdbuf, AL CMD_MODE "%c" EOM, amode); - retval = alinco_transaction(rig, mdbuf, mdbuf_len, NULL, NULL); - - if (retval != RIG_OK) - { - return retval; - } - - if (width == RIG_PASSBAND_NOCHANGE) { return retval; } - - /* - * TODO: please DX77 owners, check this, I'm not sure - * which passband is default! - */ - if (width != RIG_PASSBAND_NORMAL - && width < rig_passband_normal(rig, mode)) - { - wide_filter = 0; - } - else - { - wide_filter = 1; - } - - mdbuf_len = sprintf(mdbuf, AL CMD_FLTER "%02d" EOM, wide_filter); - retval = alinco_transaction(rig, mdbuf, mdbuf_len, NULL, NULL); - - return retval; -} - - -/* - * alinco_get_mode - * Assumes rig!=NULL, mode!=NULL - */ -int alinco_get_mode(RIG *rig, vfo_t vfo, rmode_t *mode, pbwidth_t *width) -{ - int retval; - int settings; - char modebuf[BUFSZ]; - - retval = current_data_read(rig, modebuf); - - if (retval != RIG_OK) - { - return retval; - } - - /* FIXME: CWL&CWU: what are they? CW & CWR? */ - switch (modebuf[3]) - { - case MD_CWL: - case MD_CWU: *mode = RIG_MODE_CW; break; - - case MD_USB: *mode = RIG_MODE_USB; break; - - case MD_LSB: *mode = RIG_MODE_LSB; break; - - case MD_AM: *mode = RIG_MODE_AM; break; - - case MD_FM: *mode = RIG_MODE_FM; break; - - default: - rig_debug(RIG_DEBUG_ERR, - "alinco_get_mode: unknown mode %c%c\n", - modebuf[2], - modebuf[3]); - - return -RIG_EINVAL; - } - - modebuf[2] = '\0'; - settings = strtol(modebuf, (char **)NULL, 16); - - /* - * TODO: please DX77 owners, check this, I'm not sure - * which passband is default! - */ - if (settings & 0x02) - { - *width = rig_passband_narrow(rig, *mode); - } - else - { - *width = rig_passband_normal(rig, *mode); - } - - return RIG_OK; -} - - -/* - * alinco_set_split - * Assumes rig!=NULL - */ -int alinco_set_split_vfo(RIG *rig, vfo_t vfo, split_t split, vfo_t tx_vfo) -{ - int cmd_len; - char cmdbuf[BUFSZ]; - - cmd_len = sprintf(cmdbuf, - AL CMD_SPLT "%d" EOM, - split == RIG_SPLIT_ON ? 1 : 0); - - return alinco_transaction(rig, cmdbuf, cmd_len, NULL, NULL); -} - - -/* - * alinco_get_split - * Assumes rig!=NULL, split!=NULL - */ -int alinco_get_split_vfo(RIG *rig, vfo_t vfo, split_t *split, vfo_t *tx_vfo) -{ - int splt_len, retval; - char spltbuf[BUFSZ]; - - retval = alinco_transaction(rig, - AL CMD_RSPLT EOM, - strlen(AL CMD_RSPLT EOM), - spltbuf, - &splt_len); - - if (retval != RIG_OK) - { - return retval; - } - - if (splt_len != 2) - { - rig_debug(RIG_DEBUG_ERR, - "alinco_get_split: wrong answer %s, len=%d\n", - spltbuf, - splt_len); - - return -RIG_ERJCTED; - } - - spltbuf[splt_len] = '\0'; - - if (!strcmp(spltbuf, "OF")) - { - *split = RIG_SPLIT_OFF; - } - else if (!strcmp(spltbuf, "ON")) - { - *split = RIG_SPLIT_ON; - } - else - { - rig_debug(RIG_DEBUG_ERR, - "alinco_get_split: unsupported SPLIT %s\n", - spltbuf); - - return -RIG_EPROTO; - } - - return RIG_OK; -} - - -/* - * alinco_set_split_freq - * Assumes rig!=NULL - */ -int alinco_set_split_freq(RIG *rig, vfo_t vfo, freq_t tx_freq) -{ - char freqbuf[BUFSZ]; - int freq_len; - int retval; - - /* max 10 digits */ - if (tx_freq >= GHz(10)) - { - return -RIG_EINVAL; - } - - /* at least 6 digits */ - freq_len = sprintf(freqbuf, AL CMD_TXFREQ "%06"PRIll EOM, (int64_t)tx_freq); - - retval = alinco_transaction(rig, freqbuf, freq_len, NULL, NULL); - - return retval; -} - - -/* - * alinco_get_split_freq - * Assumes rig!=NULL, rx_freq!=NULL, tx_freq!=NULL - */ -int alinco_get_split_freq(RIG *rig, vfo_t vfo, freq_t *tx_freq) -{ - int retval; - char freqbuf[BUFSZ]; - - retval = current_data_read(rig, freqbuf); - - if (retval != RIG_OK) - { - return retval; - } - - /* extract TX freq first, as RX kills freqbuf[16] */ - freqbuf[26] = '\0'; - sscanf(freqbuf + 16, "%"SCNfreq, tx_freq); - - return RIG_OK; -} - - -/* - * alinco_get_rit - * Assumes rig!=NULL, split!=NULL - */ -int alinco_get_rit(RIG *rig, vfo_t vfo, shortfreq_t *rit) -{ - int rit_len, retval; - char ritbuf[BUFSZ]; - - /* read in Hertz unit */ - retval = alinco_transaction(rig, - AL CMD_RIT "0" EOM, - strlen(AL CMD_RIT "0" EOM), - ritbuf, - &rit_len); - - if (retval != RIG_OK) - { - return retval; - } - - if (rit_len != 8) /* || (ritbuf[0] != '+' && ritbuf[0] != '-')) { */ - { - rig_debug(RIG_DEBUG_ERR, - "alinco_get_rit: wrong answer %s, len=%d\n", - ritbuf, - rit_len); - - return -RIG_ERJCTED; - } - - ritbuf[rit_len] = '\0'; - ritbuf[0] = ' '; - ritbuf[1] = ' '; - ritbuf[2] = ' '; - - *rit = atoi(ritbuf); - - return RIG_OK; -} - - -/* - * alinco_set_func - * Assumes rig!=NULL - */ -int alinco_set_func(RIG *rig, vfo_t vfo, setting_t func, int status) -{ - int cmd_len; - char cmdbuf[BUFSZ]; - - /* Optimize: - * sort the switch cases with the most frequent first - */ - switch (func) - { - case RIG_FUNC_TONE: - cmd_len = sprintf(cmdbuf, AL CMD_CTCSS "%02d" EOM, status ? 51 : 0); - - return alinco_transaction(rig, cmdbuf, cmd_len, NULL, NULL); - - case RIG_FUNC_FAGC: - cmd_len = sprintf(cmdbuf, AL CMD_AGC "%02d" EOM, status ? 1 : 2); - - return alinco_transaction(rig, cmdbuf, cmd_len, NULL, NULL); - - case RIG_FUNC_NB: - cmd_len = sprintf(cmdbuf, AL CMD_NB "%d" EOM, status ? 1 : 0); - - return alinco_transaction(rig, cmdbuf, cmd_len, NULL, NULL); - - case RIG_FUNC_COMP: - cmd_len = sprintf(cmdbuf, AL CMD_SDATA "C%d" EOM, status ? 1 : 0); - return alinco_transaction(rig, cmdbuf, cmd_len, NULL, NULL); - - case RIG_FUNC_MON: - cmd_len = sprintf(cmdbuf, AL CMD_MON "%d" EOM, status ? 1 : 0); - - return alinco_transaction(rig, cmdbuf, cmd_len, NULL, NULL); - - default: - rig_debug(RIG_DEBUG_ERR, "Unsupported set_func %d\n", (int)func); - return -RIG_EINVAL; - } - - return RIG_OK; -} - - -/* - * alinco_get_func - * Assumes rig!=NULL, status!=NULL - */ -int alinco_get_func(RIG *rig, vfo_t vfo, setting_t func, int *status) -{ - int retval; - int settings; - char funcbuf[BUFSZ]; - - /* Optimize: - * sort the switch cases with the most frequent first - */ - switch (func) - { - case RIG_FUNC_TONE: - retval = current_data_read(rig, funcbuf); - - if (retval != RIG_OK) - { - return retval; - } - - funcbuf[2] = '\0'; - settings = strtol(funcbuf, (char **)NULL, 16); - *status = (settings & 0x08) ? 1 : 0; - break; - - case RIG_FUNC_FAGC: - retval = current_data_read(rig, funcbuf); - - if (retval != RIG_OK) - { - return retval; - } - - funcbuf[2] = '\0'; - settings = strtol(funcbuf, (char **)NULL, 16); - *status = (settings & 0x01) ? 1 : 0; - break; - - case RIG_FUNC_NB: - retval = current_data_read(rig, funcbuf); - - if (retval != RIG_OK) - { - return retval; - } - - funcbuf[2] = '\0'; - settings = strtol(funcbuf, (char **)NULL, 16); - *status = (settings & 0x04) ? 1 : 0; - break; - - default: - rig_debug(RIG_DEBUG_ERR, "Unsupported get_func %d\n", (int)func); - return -RIG_EINVAL; - } - - return RIG_OK; -} - - -/* - * alinco_set_level - * Assumes rig!=NULL - * FIXME: cannot support PREAMP and ATT both at same time (make sense though) - */ -int alinco_set_level(RIG *rig, vfo_t vfo, setting_t level, value_t val) -{ - int cmd_len, lvl; - char cmdbuf[BUFSZ]; - - /* Optimize: - * sort the switch cases with the most frequent first - */ - switch (level) - { - case RIG_LEVEL_PREAMP: - switch (val.i) - { - case 0: lvl = 0; break; - - case 10: lvl = 1; break; - - default: rig_debug(RIG_DEBUG_ERR, - "Unsupported Preamp %d\n", - val.i); - - return -RIG_EINVAL; - } - - cmd_len = sprintf(cmdbuf, AL CMD_RFGAIN "%02d" EOM, lvl); - - return alinco_transaction(rig, cmdbuf, cmd_len, NULL, NULL); - - case RIG_LEVEL_ATT: - switch (val.i) - { - case 0: lvl = 0; break; - - case 10: lvl = 11; break; - - case 20: lvl = 10; break; - - default: rig_debug(RIG_DEBUG_ERR, - "Unsupported Att %d\n", - val.i); - - return -RIG_EINVAL; - } - - cmd_len = sprintf(cmdbuf, AL CMD_RFGAIN "%02d" EOM, lvl); - - return alinco_transaction(rig, cmdbuf, cmd_len, NULL, NULL); - - case RIG_LEVEL_RFPOWER: - cmd_len = sprintf(cmdbuf, AL CMD_PWR "%1d" EOM, val.f < 0.5 ? 1 : 0); - - return alinco_transaction(rig, cmdbuf, cmd_len, NULL, NULL); - - case RIG_LEVEL_KEYSPD: - if (val.i < 6) - { - lvl = 31; - } - else if (val.i >= 6 && val.i < 20) - { - lvl = val.i + 25; - } - else if (val.i >= 20 && val.i <= 50) - { - lvl = val.i - 20; - } - else - { - lvl = 30; - } - - cmd_len = sprintf(cmdbuf, AL CMD_SDATA "P%02d" EOM, lvl); - - return alinco_transaction(rig, cmdbuf, cmd_len, NULL, NULL); - - case RIG_LEVEL_CWPITCH: - lvl = 4; - - if (val.i < 426) - { - lvl = 5; - } - else if (val.i >= 426 && val.i <= 475) - { - lvl = 6; - } - else if (val.i >= 476 && val.i <= 525) - { - lvl = 7; - } - else if (val.i >= 526 && val.i <= 575) - { - lvl = 8; - } - else if (val.i >= 576 && val.i <= 625) - { - lvl = 9; - } - else if (val.i >= 626 && val.i <= 675) - { - lvl = 10; - } - else if (val.i >= 676 && val.i <= 725) - { - lvl = 11; - } - else if (val.i >= 726 && val.i <= 775) - { - lvl = 12; - } - else if (val.i >= 776 && val.i <= 825) - { - lvl = 0; - } - else if (val.i >= 826 && val.i <= 875) - { - lvl = 1; - } - else if (val.i >= 876 && val.i <= 925) - { - lvl = 2; - } - else if (val.i >= 926 && val.i <= 975) - { - lvl = 3; - } - else if (val.i >= 976 && val.i <= 1025) - { - lvl = 4; - } - - cmd_len = sprintf(cmdbuf, AL CMD_SDATA "M%02d" EOM, lvl); - - return alinco_transaction(rig, cmdbuf, cmd_len, NULL, NULL); - - default: - rig_debug(RIG_DEBUG_ERR, "Unsupported set_level %s\n", rig_strlevel(level)); - - return -RIG_EINVAL; - } - - return RIG_OK; -} - - -/* - * alinco_get_level - * Assumes rig!=NULL, val!=NULL - */ -int alinco_get_level(RIG *rig, vfo_t vfo, setting_t level, value_t *val) -{ - int retval, lvl_len; - char lvlbuf[BUFSZ]; - - /* Optimize: - * sort the switch cases with the most frequent first - */ - switch (level) - { - case RIG_LEVEL_RAWSTR: - /* read A/D converted value */ - retval = alinco_transaction(rig, - AL CMD_SMETER "1" EOM, - strlen(AL CMD_SMETER "1" EOM), - lvlbuf, - &lvl_len); - - if (retval != RIG_OK) - { - return retval; - } - - if (lvl_len != 6) - { - rig_debug(RIG_DEBUG_ERR, - "alinco_get_level: wrong answer len=%d\n", - lvl_len); - - return -RIG_ERJCTED; - } - - lvlbuf[6] = '\0'; - val->i = atoi(lvlbuf + 3); - break; - - case RIG_LEVEL_PREAMP: - retval = current_data_read(rig, lvlbuf); - - if (retval != RIG_OK) - { - return retval; - } - - switch (lvlbuf[5]) - { - case '2': - case '3': - case '0': val->i = 0; break; - - case '1': val->i = 10; break; - - default: rig_debug(RIG_DEBUG_ERR, - "Unknown RF Gain %c%c\n", - lvlbuf[4], - lvlbuf[5]); - } - - break; - - case RIG_LEVEL_ATT: - retval = current_data_read(rig, lvlbuf); - - if (retval != RIG_OK) - { - return retval; - } - - switch (lvlbuf[5]) - { - case '1': - case '0': val->i = 0; break; - - case '2': val->i = 20; break; - - case '3': val->i = 10; break; - - default: rig_debug(RIG_DEBUG_ERR, - "Unknown RF Gain %c%c\n", - lvlbuf[4], - lvlbuf[5]); - } - - break; - - case RIG_LEVEL_RFPOWER: - retval = alinco_transaction(rig, - AL CMD_RPOWER EOM, - strlen(AL CMD_RPOWER EOM), - lvlbuf, - &lvl_len); - - if (retval != RIG_OK) - { - return retval; - } - - if (lvl_len != 1) - { - rig_debug(RIG_DEBUG_ERR, - "alinco_get_level: wrong answer len=%d\n", - lvl_len); - - return -RIG_ERJCTED; - } - - /* H or L */ - val->f = lvlbuf[0] == 'H' ? 1.0 : 0.0; - break; - - default: - rig_debug(RIG_DEBUG_ERR, "Unsupported get_level %s\n", rig_strlevel(level)); - - return -RIG_EINVAL; - } - - return RIG_OK; -} - - -/* - * alinco_set_parm - */ -int alinco_set_parm(RIG *rig, setting_t parm, value_t val) -{ - int cmd_len; - char cmdbuf[BUFSZ]; - - /* Optimize: - * sort the switch cases with the most frequent first - */ - switch (parm) - { - case RIG_PARM_BEEP: - rig_debug(RIG_DEBUG_ERR, "val is %d\n", val.i); - cmd_len = sprintf(cmdbuf, AL CMD_SDATA "A%d" EOM, val.i ? 1 : 0); - return alinco_transaction(rig, cmdbuf, cmd_len, NULL, NULL); - - case RIG_PARM_BACKLIGHT: - rig_debug(RIG_DEBUG_ERR, "val is %0f\n", val.f); - cmd_len = sprintf(cmdbuf, AL CMD_SDATA "O%d" EOM, (int)(val.f * 5)); - return alinco_transaction(rig, cmdbuf, cmd_len, NULL, NULL); - - default: - rig_debug(RIG_DEBUG_ERR, "Unsupported set_parm %d\n", (int)parm); - return -RIG_EINVAL; - } - - return RIG_OK; -} - - -/* - * alinco_set_ctcss_tone - * Assumes rig!=NULL, rig->caps->ctcss_list != NULL - */ -int alinco_set_ctcss_tone(RIG *rig, vfo_t vfo, tone_t tone) -{ - const struct rig_caps *caps; - unsigned char tonebuf[BUFSZ]; - int tone_len; - int i; - - caps = rig->caps; - - for (i = 0; caps->ctcss_list[i] != 0; i++) - { - if (caps->ctcss_list[i] == tone) - { - break; - } - } - - if (caps->ctcss_list[i] != tone) - { - return -RIG_EINVAL; - } - - tone_len = sprintf((char *) tonebuf, AL CMD_CTCSS "%02d" EOM, i + 1); - - return alinco_transaction(rig, (char *) tonebuf, tone_len, NULL, NULL); -} - - -/* - * alinco_get_ptt - * Assumes rig!=NULL, ptt!=NULL - */ -int alinco_get_ptt(RIG *rig, vfo_t vfo, ptt_t *ptt) -{ - char pttbuf[BUFSZ]; - int ptt_len, retval; - - retval = alinco_transaction(rig, - AL CMD_PTT EOM, - strlen(AL CMD_PTT EOM), - pttbuf, - &ptt_len); - - if (retval != RIG_OK) - { - return retval; - } - - if (ptt_len != 3 && ptt_len != 4) - { - rig_debug(RIG_DEBUG_ERR, - "alinco_get_ptt: wrong answer %s, len=%d\n", - pttbuf, - ptt_len); - - return -RIG_ERJCTED; - } - - pttbuf[ptt_len] = '\0'; - - if (!strcmp(pttbuf, "SEND")) - { - *ptt = RIG_PTT_OFF; - } - else if (!strcmp(pttbuf, "REV")) - { - *ptt = RIG_PTT_ON; - } - else - { - rig_debug(RIG_DEBUG_ERR, - "alinco_get_ptt: unknown PTT %s\n", - pttbuf); - - return -RIG_EPROTO; - } - - return RIG_OK; -} - - -/* - * alinco_get_dcd - * Assumes rig!=NULL, dcd!=NULL - */ -int alinco_get_dcd(RIG *rig, vfo_t vfo, dcd_t *dcd) -{ - char dcdbuf[BUFSZ]; - int dcd_len, retval; - - retval = alinco_transaction(rig, - AL CMD_SQL EOM, - strlen(AL CMD_SQL EOM), - dcdbuf, - &dcd_len); - - if (retval != RIG_OK) - { - return retval; - } - - if (dcd_len != 4 && dcd_len != 5) - { - rig_debug(RIG_DEBUG_ERR, - "alinco_get_dcd: wrong answer %s, len=%d\n", - dcdbuf, - dcd_len); - - return -RIG_ERJCTED; - } - - dcdbuf[dcd_len] = '\0'; - - if (!strcmp(dcdbuf, "OPEN")) - { - *dcd = RIG_DCD_ON; - } - else if (!strcmp(dcdbuf, "CLOSE")) - { - *dcd = RIG_DCD_OFF; - } - else - { - rig_debug(RIG_DEBUG_ERR, - "alinco_get_dcd: unknown SQL %s\n", - dcdbuf); - - return -RIG_EPROTO; - } - - return RIG_OK; -} - - -/* - * alinco_set_mem - * Assumes rig!=NULL - * FIXME: check we're in memory mode first - */ -int alinco_set_mem(RIG *rig, vfo_t vfo, int ch) -{ - char cmdbuf[BUFSZ]; - int cmd_len; - - if (ch < 0 || ch > 99) - { - return -RIG_EINVAL; - } - - cmd_len = sprintf(cmdbuf, AL CMD_MCALL "%02d" EOM, ch); - - return alinco_transaction(rig, cmdbuf, cmd_len, NULL, NULL); -} - - -/* - * alinco_get_mem - * Assumes rig!=NULL, !vfo - */ -int alinco_get_mem(RIG *rig, vfo_t vfo, int *ch) -{ - char membuf[BUFSZ]; - int mem_len, retval; - - retval = alinco_transaction(rig, - AL CMD_RMEM EOM, - strlen(AL CMD_RMEM EOM), - membuf, - &mem_len); - - if (retval != RIG_OK) - { - return retval; - } - - if (mem_len != 2) - { - rig_debug(RIG_DEBUG_ERR, - "alinco_get_mem: wrong answer %s, len=%d\n", - membuf, - mem_len); - - return -RIG_ERJCTED; - } - - membuf[mem_len] = '\0'; - - *ch = atoi(membuf); - - if (*ch < 0 || *ch > 99) - { - rig_debug(RIG_DEBUG_ERR, "alinco_get_mem: unknown mem %s\n", - membuf); - return -RIG_EPROTO; - } - - return RIG_OK; -} - - -/* - * initrigs_alinco is called by rig_backend_load - */ -DECLARE_INITRIG_BACKEND(alinco) -{ - rig_register(&dx77_caps); - - return RIG_OK; -} diff --git a/rigs/alinco/dx77.c b/rigs/alinco/dx77.c index 9b945c638..9168e2256 100644 --- a/rigs/alinco/dx77.c +++ b/rigs/alinco/dx77.c @@ -23,11 +23,72 @@ # include "config.h" #endif +#include #include +#include /* String function definitions */ +#include /* UNIX standard function definitions */ +#include + #include +#include #include "idx_builtin.h" #include "alinco.h" +#include +#include +#include + +#define BUFSZ 32 + + +/* Line Feed */ +#define EOM "\x0d" +#define LF "\x0a" + +/* + * modes in use by the "2G" command + */ +#define MD_LSB '0' +#define MD_USB '1' +#define MD_CWL '2' +#define MD_CWU '3' +#define MD_AM '4' +#define MD_FM '5' + +#define AL "AL" +#define CMD_TXFREQ "0A" /* Transmit frequency */ +#define CMD_RXFREQ "0B" /* Receive frequency */ +#define CMD_VFO "1A" +#define CMD_MEMMD "1B" /* Memory mode */ +#define CMD_CHAN "1D" /* Channel Display */ +#define CMD_UPDWN "2A" /* UP/DOWN */ +#define CMD_MON "2B" /* Check Transmit Frequency */ +#define CMD_PWR "2C" /* Transmit Output Power */ +#define CMD_SCAN "2D" /* Scanning */ +#define CMD_PRIO "2E" /* Priority */ +#define CMD_SPLT "2F" /* Split */ +#define CMD_MODE "2G" /* Mode */ +#define CMD_RFGAIN "2H" /* RF Gain */ +#define CMD_AGC "2I" +#define CMD_FLTER "2J" /* Filter */ +#define CMD_NB "2K" +#define CMD_CTCSS "2L" +#define CMD_TUNE "2M" +#define CMD_SELECT "2N" +#define CMD_MCALL "2V" /* Memory Channel Call Up */ +#define CMD_SDATA "2W" /* Set Data */ + +/* Data Output Commands */ +#define CMD_SMETER "3A" /* S-meter read */ +#define CMD_PTT "3B" /* PTT status read */ +#define CMD_SQL "3C" /* Squelch status */ +#define CMD_RIT "3D" /* RIT status */ +#define CMD_RMEM "3E" /* Current Memory-channel Number read */ +#define CMD_RMV "3G" /* Memory/VFO -mode read */ +#define CMD_RDATA "3H" /* Current Data read */ +#define CMD_RSPLT "3I" /* Split read */ +#define CMD_RPOWER "3J" /* Transmitter Output read */ +#define CMD_RSELECT "3K" /* SELECT Postion read */ #define DX77_ALL_MODES (RIG_MODE_AM|RIG_MODE_CW|RIG_MODE_SSB|RIG_MODE_FM) @@ -59,6 +120,1192 @@ { 216, 60 }, \ } } +/* + * dx77_transaction + * We assume that rig!=NULL, rig->state!= NULL, data!=NULL, data_len!=NULL + * Otherwise, you'll get a nice seg fault. You've been warned! + * TODO: error case handling + */ +int dx77_transaction(RIG *rig, + const char *cmd, + int cmd_len, + char *data, + int *data_len) +{ + int retval; + struct rig_state *rs; + char echobuf[BUFSZ + 1]; + + if (cmd == NULL) + { + rig_debug(RIG_DEBUG_ERR, + "%s: null argument for cmd?\n", __func__); + return -RIG_EINTERNAL; + } + + rs = &rig->state; + + serial_flush(&rs->rigport); + + retval = write_block(&rs->rigport, cmd, cmd_len); + + if (retval != RIG_OK) + { + return retval; + } + + /* + * Transceiver sends an echo of cmd followed by a CR/LF + * TODO: check whether cmd and echobuf match (optional) + */ + retval = read_string(&rs->rigport, echobuf, BUFSZ, LF, strlen(LF)); + + if (retval < 0) + { + return retval; + } + + if (!(data && data_len)) + { + rig_debug(RIG_DEBUG_ERR, "%s: data and datalen not both NULL??\n", __func__); + return -RIG_EINTERNAL; + } + + /* no data expected, check for OK returned */ + if (data == NULL) + { + retval = read_string(&rs->rigport, echobuf, BUFSZ, LF, strlen(LF)); + + if (retval < 0) + { + return retval; + } + + if (retval > 2) { retval -= 2; } + + echobuf[retval] = 0; + + if (strcmp(echobuf, "OK") == 0) + { + return RIG_OK; + } + else + { + return -RIG_ERJCTED; + } + } + + retval = read_string(&rs->rigport, data, BUFSZ, LF, strlen(LF)); + + if (retval < 0) + { + return retval; + } + + *data_len = retval; + + /* strip CR/LF from string + */ + data[0] = 0; + + if (*data_len > 2) + { + *data_len -= 2; + data[*data_len] = 0; + } + + return RIG_OK; +} + + +/* + * dx77_set_vfo + * Assumes rig!=NULL + */ +int dx77_set_vfo(RIG *rig, vfo_t vfo) +{ + char cmdbuf[BUFSZ]; + int cmd_len; + char vfo_num; + + switch (vfo) + { + case RIG_VFO_A: vfo_num = '1'; break; + + case RIG_VFO_B: vfo_num = '2'; break; + + case RIG_VFO_MEM: + return dx77_transaction(rig, + AL CMD_MEMMD "0" EOM, + strlen(AL CMD_MEMMD "0" EOM), + NULL, + NULL); + + default: + rig_debug(RIG_DEBUG_ERR, + "dx77_set_vfo: unsupported VFO %s\n", + rig_strvfo(vfo)); + + return -RIG_EINVAL; + } + + cmd_len = sprintf(cmdbuf, AL CMD_VFO "%c" EOM, vfo_num); + + return dx77_transaction(rig, cmdbuf, cmd_len, NULL, NULL); +} + + +/* + * dx77_get_vfo + * Assumes rig!=NULL, !vfo + */ +int dx77_get_vfo(RIG *rig, vfo_t *vfo) +{ + char vfobuf[BUFSZ]; + int vfo_len, retval; + + retval = dx77_transaction(rig, + AL CMD_RMV EOM, + strlen(AL CMD_RMV EOM), + vfobuf, + &vfo_len); + + if (retval != RIG_OK) + { + return retval; + } + + if (vfo_len != 4) + { + rig_debug(RIG_DEBUG_ERR, + "dx77_get_vfo: wrong answer %s, " + "len=%d\n", + vfobuf, + vfo_len); + + return -RIG_ERJCTED; + } + + vfobuf[vfo_len] = '\0'; + + if (!strcmp(vfobuf, "VFOA")) + { + *vfo = RIG_VFO_A; + } + else if (!strcmp(vfobuf, "VFOB")) + { + *vfo = RIG_VFO_B; + } + else if (!strcmp(vfobuf, "MEMO")) + { + *vfo = RIG_VFO_MEM; + } + else + { + rig_debug(RIG_DEBUG_ERR, + "dx77_get_vfo: unsupported VFO %s\n", + vfobuf); + + return -RIG_EPROTO; + } + + return RIG_OK; +} + + +/* + * dx77_set_freq + * Assumes rig!=NULL + */ +int dx77_set_freq(RIG *rig, vfo_t vfo, freq_t freq) +{ + char freqbuf[BUFSZ]; + int freq_len; + + /* max 10 digits */ + if (freq >= GHz(10)) + { + return -RIG_EINVAL; + } + + /* at least 6 digits */ + // cppcheck-suppress * + freq_len = sprintf(freqbuf, AL CMD_RXFREQ "%06"PRIll EOM, (int64_t)freq); + + return dx77_transaction(rig, freqbuf, freq_len, NULL, NULL); +} + + +/* + * where databuf points to a 26 char long buffer + */ +static int current_data_read(RIG *rig, char *databuf) +{ + int data_len, retval; + + retval = dx77_transaction(rig, + AL CMD_RDATA EOM, + strlen(AL CMD_RDATA EOM), + databuf, + &data_len); + + if (retval != RIG_OK) + { + return retval; + } + + if (data_len != 26) + { + rig_debug(RIG_DEBUG_ERR, + "dx77_current_data_read: wrong answer %s, len=%d\n", + databuf, + data_len); + + return -RIG_ERJCTED; + } + + return RIG_OK; +} + + +/* + * dx77_get_freq + * Assumes rig!=NULL, freq!=NULL + */ +int dx77_get_freq(RIG *rig, vfo_t vfo, freq_t *freq) +{ + int retval; + char freqbuf[BUFSZ]; + + retval = current_data_read(rig, freqbuf); + + if (retval != RIG_OK) + { + return retval; + } + + /* extract RX freq */ + freqbuf[16] = '\0'; + sscanf(freqbuf + 6, "%"SCNfreq, freq); + + return RIG_OK; +} + + +/* + * dx77_set_mode + * Assumes rig!=NULL + */ +int dx77_set_mode(RIG *rig, vfo_t vfo, rmode_t mode, pbwidth_t width) +{ + char mdbuf[BUFSZ]; + int mdbuf_len, wide_filter, retval; + char amode; + + switch (mode) + { + /* FIXME: MD_CWL or MD_CWU? */ + case RIG_MODE_CW: amode = MD_CWU; break; + + case RIG_MODE_USB: amode = MD_USB; break; + + case RIG_MODE_LSB: amode = MD_LSB; break; + + case RIG_MODE_FM: amode = MD_FM; break; + + case RIG_MODE_AM: amode = MD_AM; break; + + default: + rig_debug(RIG_DEBUG_ERR, "dx77_set_mode: unsupported mode %s\n", + rig_strrmode(mode)); + + return -RIG_EINVAL; + } + + mdbuf_len = sprintf(mdbuf, AL CMD_MODE "%c" EOM, amode); + retval = dx77_transaction(rig, mdbuf, mdbuf_len, NULL, NULL); + + if (retval != RIG_OK) + { + return retval; + } + + if (width == RIG_PASSBAND_NOCHANGE) { return retval; } + + /* + * TODO: please DX77 owners, check this, I'm not sure + * which passband is default! + */ + if (width != RIG_PASSBAND_NORMAL + && width < rig_passband_normal(rig, mode)) + { + wide_filter = 0; + } + else + { + wide_filter = 1; + } + + mdbuf_len = sprintf(mdbuf, AL CMD_FLTER "%02d" EOM, wide_filter); + retval = dx77_transaction(rig, mdbuf, mdbuf_len, NULL, NULL); + + return retval; +} + + +/* + * dx77_get_mode + * Assumes rig!=NULL, mode!=NULL + */ +int dx77_get_mode(RIG *rig, vfo_t vfo, rmode_t *mode, pbwidth_t *width) +{ + int retval; + int settings; + char modebuf[BUFSZ]; + + retval = current_data_read(rig, modebuf); + + if (retval != RIG_OK) + { + return retval; + } + + /* FIXME: CWL&CWU: what are they? CW & CWR? */ + switch (modebuf[3]) + { + case MD_CWL: + case MD_CWU: *mode = RIG_MODE_CW; break; + + case MD_USB: *mode = RIG_MODE_USB; break; + + case MD_LSB: *mode = RIG_MODE_LSB; break; + + case MD_AM: *mode = RIG_MODE_AM; break; + + case MD_FM: *mode = RIG_MODE_FM; break; + + default: + rig_debug(RIG_DEBUG_ERR, + "dx77_get_mode: unknown mode %c%c\n", + modebuf[2], + modebuf[3]); + + return -RIG_EINVAL; + } + + modebuf[2] = '\0'; + settings = strtol(modebuf, (char **)NULL, 16); + + /* + * TODO: please DX77 owners, check this, I'm not sure + * which passband is default! + */ + if (settings & 0x02) + { + *width = rig_passband_narrow(rig, *mode); + } + else + { + *width = rig_passband_normal(rig, *mode); + } + + return RIG_OK; +} + + +/* + * dx77_set_split + * Assumes rig!=NULL + */ +int dx77_set_split_vfo(RIG *rig, vfo_t vfo, split_t split, vfo_t tx_vfo) +{ + int cmd_len; + char cmdbuf[BUFSZ]; + + cmd_len = sprintf(cmdbuf, + AL CMD_SPLT "%d" EOM, + split == RIG_SPLIT_ON ? 1 : 0); + + return dx77_transaction(rig, cmdbuf, cmd_len, NULL, NULL); +} + + +/* + * dx77_get_split + * Assumes rig!=NULL, split!=NULL + */ +int dx77_get_split_vfo(RIG *rig, vfo_t vfo, split_t *split, vfo_t *tx_vfo) +{ + int splt_len, retval; + char spltbuf[BUFSZ]; + + retval = dx77_transaction(rig, + AL CMD_RSPLT EOM, + strlen(AL CMD_RSPLT EOM), + spltbuf, + &splt_len); + + if (retval != RIG_OK) + { + return retval; + } + + if (splt_len != 2) + { + rig_debug(RIG_DEBUG_ERR, + "dx77_get_split: wrong answer %s, len=%d\n", + spltbuf, + splt_len); + + return -RIG_ERJCTED; + } + + spltbuf[splt_len] = '\0'; + + if (!strcmp(spltbuf, "OF")) + { + *split = RIG_SPLIT_OFF; + } + else if (!strcmp(spltbuf, "ON")) + { + *split = RIG_SPLIT_ON; + } + else + { + rig_debug(RIG_DEBUG_ERR, + "dx77_get_split: unsupported SPLIT %s\n", + spltbuf); + + return -RIG_EPROTO; + } + + return RIG_OK; +} + + +/* + * dx77_set_split_freq + * Assumes rig!=NULL + */ +int dx77_set_split_freq(RIG *rig, vfo_t vfo, freq_t tx_freq) +{ + char freqbuf[BUFSZ]; + int freq_len; + int retval; + + /* max 10 digits */ + if (tx_freq >= GHz(10)) + { + return -RIG_EINVAL; + } + + /* at least 6 digits */ + freq_len = sprintf(freqbuf, AL CMD_TXFREQ "%06"PRIll EOM, (int64_t)tx_freq); + + retval = dx77_transaction(rig, freqbuf, freq_len, NULL, NULL); + + return retval; +} + + +/* + * dx77_get_split_freq + * Assumes rig!=NULL, rx_freq!=NULL, tx_freq!=NULL + */ +int dx77_get_split_freq(RIG *rig, vfo_t vfo, freq_t *tx_freq) +{ + int retval; + char freqbuf[BUFSZ]; + + retval = current_data_read(rig, freqbuf); + + if (retval != RIG_OK) + { + return retval; + } + + /* extract TX freq first, as RX kills freqbuf[16] */ + freqbuf[26] = '\0'; + sscanf(freqbuf + 16, "%"SCNfreq, tx_freq); + + return RIG_OK; +} + + +/* + * dx77_get_rit + * Assumes rig!=NULL, split!=NULL + */ +int dx77_get_rit(RIG *rig, vfo_t vfo, shortfreq_t *rit) +{ + int rit_len, retval; + char ritbuf[BUFSZ]; + + /* read in Hertz unit */ + retval = dx77_transaction(rig, + AL CMD_RIT "0" EOM, + strlen(AL CMD_RIT "0" EOM), + ritbuf, + &rit_len); + + if (retval != RIG_OK) + { + return retval; + } + + if (rit_len != 8) /* || (ritbuf[0] != '+' && ritbuf[0] != '-')) { */ + { + rig_debug(RIG_DEBUG_ERR, + "dx77_get_rit: wrong answer %s, len=%d\n", + ritbuf, + rit_len); + + return -RIG_ERJCTED; + } + + ritbuf[rit_len] = '\0'; + ritbuf[0] = ' '; + ritbuf[1] = ' '; + ritbuf[2] = ' '; + + *rit = atoi(ritbuf); + + return RIG_OK; +} + + +/* + * dx77_set_func + * Assumes rig!=NULL + */ +int dx77_set_func(RIG *rig, vfo_t vfo, setting_t func, int status) +{ + int cmd_len; + char cmdbuf[BUFSZ]; + + /* Optimize: + * sort the switch cases with the most frequent first + */ + switch (func) + { + case RIG_FUNC_TONE: + cmd_len = sprintf(cmdbuf, AL CMD_CTCSS "%02d" EOM, status ? 51 : 0); + + return dx77_transaction(rig, cmdbuf, cmd_len, NULL, NULL); + + case RIG_FUNC_FAGC: + cmd_len = sprintf(cmdbuf, AL CMD_AGC "%02d" EOM, status ? 1 : 2); + + return dx77_transaction(rig, cmdbuf, cmd_len, NULL, NULL); + + case RIG_FUNC_NB: + cmd_len = sprintf(cmdbuf, AL CMD_NB "%d" EOM, status ? 1 : 0); + + return dx77_transaction(rig, cmdbuf, cmd_len, NULL, NULL); + + case RIG_FUNC_COMP: + cmd_len = sprintf(cmdbuf, AL CMD_SDATA "C%d" EOM, status ? 1 : 0); + return dx77_transaction(rig, cmdbuf, cmd_len, NULL, NULL); + + case RIG_FUNC_MON: + cmd_len = sprintf(cmdbuf, AL CMD_MON "%d" EOM, status ? 1 : 0); + + return dx77_transaction(rig, cmdbuf, cmd_len, NULL, NULL); + + default: + rig_debug(RIG_DEBUG_ERR, "Unsupported set_func %d\n", (int)func); + return -RIG_EINVAL; + } + + return RIG_OK; +} + + +/* + * dx77_get_func + * Assumes rig!=NULL, status!=NULL + */ +int dx77_get_func(RIG *rig, vfo_t vfo, setting_t func, int *status) +{ + int retval; + int settings; + char funcbuf[BUFSZ]; + + /* Optimize: + * sort the switch cases with the most frequent first + */ + switch (func) + { + case RIG_FUNC_TONE: + retval = current_data_read(rig, funcbuf); + + if (retval != RIG_OK) + { + return retval; + } + + funcbuf[2] = '\0'; + settings = strtol(funcbuf, (char **)NULL, 16); + *status = (settings & 0x08) ? 1 : 0; + break; + + case RIG_FUNC_FAGC: + retval = current_data_read(rig, funcbuf); + + if (retval != RIG_OK) + { + return retval; + } + + funcbuf[2] = '\0'; + settings = strtol(funcbuf, (char **)NULL, 16); + *status = (settings & 0x01) ? 1 : 0; + break; + + case RIG_FUNC_NB: + retval = current_data_read(rig, funcbuf); + + if (retval != RIG_OK) + { + return retval; + } + + funcbuf[2] = '\0'; + settings = strtol(funcbuf, (char **)NULL, 16); + *status = (settings & 0x04) ? 1 : 0; + break; + + default: + rig_debug(RIG_DEBUG_ERR, "Unsupported get_func %d\n", (int)func); + return -RIG_EINVAL; + } + + return RIG_OK; +} + + +/* + * dx77_set_level + * Assumes rig!=NULL + * FIXME: cannot support PREAMP and ATT both at same time (make sense though) + */ +int dx77_set_level(RIG *rig, vfo_t vfo, setting_t level, value_t val) +{ + int cmd_len, lvl; + char cmdbuf[BUFSZ]; + + /* Optimize: + * sort the switch cases with the most frequent first + */ + switch (level) + { + case RIG_LEVEL_PREAMP: + switch (val.i) + { + case 0: lvl = 0; break; + + case 10: lvl = 1; break; + + default: rig_debug(RIG_DEBUG_ERR, + "Unsupported Preamp %d\n", + val.i); + + return -RIG_EINVAL; + } + + cmd_len = sprintf(cmdbuf, AL CMD_RFGAIN "%02d" EOM, lvl); + + return dx77_transaction(rig, cmdbuf, cmd_len, NULL, NULL); + + case RIG_LEVEL_ATT: + switch (val.i) + { + case 0: lvl = 0; break; + + case 10: lvl = 11; break; + + case 20: lvl = 10; break; + + default: rig_debug(RIG_DEBUG_ERR, + "Unsupported Att %d\n", + val.i); + + return -RIG_EINVAL; + } + + cmd_len = sprintf(cmdbuf, AL CMD_RFGAIN "%02d" EOM, lvl); + + return dx77_transaction(rig, cmdbuf, cmd_len, NULL, NULL); + + case RIG_LEVEL_RFPOWER: + cmd_len = sprintf(cmdbuf, AL CMD_PWR "%1d" EOM, val.f < 0.5 ? 1 : 0); + + return dx77_transaction(rig, cmdbuf, cmd_len, NULL, NULL); + + case RIG_LEVEL_KEYSPD: + if (val.i < 6) + { + lvl = 31; + } + else if (val.i >= 6 && val.i < 20) + { + lvl = val.i + 25; + } + else if (val.i >= 20 && val.i <= 50) + { + lvl = val.i - 20; + } + else + { + lvl = 30; + } + + cmd_len = sprintf(cmdbuf, AL CMD_SDATA "P%02d" EOM, lvl); + + return dx77_transaction(rig, cmdbuf, cmd_len, NULL, NULL); + + case RIG_LEVEL_CWPITCH: + lvl = 4; + + if (val.i < 426) + { + lvl = 5; + } + else if (val.i >= 426 && val.i <= 475) + { + lvl = 6; + } + else if (val.i >= 476 && val.i <= 525) + { + lvl = 7; + } + else if (val.i >= 526 && val.i <= 575) + { + lvl = 8; + } + else if (val.i >= 576 && val.i <= 625) + { + lvl = 9; + } + else if (val.i >= 626 && val.i <= 675) + { + lvl = 10; + } + else if (val.i >= 676 && val.i <= 725) + { + lvl = 11; + } + else if (val.i >= 726 && val.i <= 775) + { + lvl = 12; + } + else if (val.i >= 776 && val.i <= 825) + { + lvl = 0; + } + else if (val.i >= 826 && val.i <= 875) + { + lvl = 1; + } + else if (val.i >= 876 && val.i <= 925) + { + lvl = 2; + } + else if (val.i >= 926 && val.i <= 975) + { + lvl = 3; + } + else if (val.i >= 976 && val.i <= 1025) + { + lvl = 4; + } + + cmd_len = sprintf(cmdbuf, AL CMD_SDATA "M%02d" EOM, lvl); + + return dx77_transaction(rig, cmdbuf, cmd_len, NULL, NULL); + + default: + rig_debug(RIG_DEBUG_ERR, "Unsupported set_level %s\n", rig_strlevel(level)); + + return -RIG_EINVAL; + } + + return RIG_OK; +} + + +/* + * dx77_get_level + * Assumes rig!=NULL, val!=NULL + */ +int dx77_get_level(RIG *rig, vfo_t vfo, setting_t level, value_t *val) +{ + int retval, lvl_len; + char lvlbuf[BUFSZ]; + + /* Optimize: + * sort the switch cases with the most frequent first + */ + switch (level) + { + case RIG_LEVEL_RAWSTR: + /* read A/D converted value */ + retval = dx77_transaction(rig, + AL CMD_SMETER "1" EOM, + strlen(AL CMD_SMETER "1" EOM), + lvlbuf, + &lvl_len); + + if (retval != RIG_OK) + { + return retval; + } + + if (lvl_len != 6) + { + rig_debug(RIG_DEBUG_ERR, + "dx77_get_level: wrong answer len=%d\n", + lvl_len); + + return -RIG_ERJCTED; + } + + lvlbuf[6] = '\0'; + val->i = atoi(lvlbuf + 3); + break; + + case RIG_LEVEL_PREAMP: + retval = current_data_read(rig, lvlbuf); + + if (retval != RIG_OK) + { + return retval; + } + + switch (lvlbuf[5]) + { + case '2': + case '3': + case '0': val->i = 0; break; + + case '1': val->i = 10; break; + + default: rig_debug(RIG_DEBUG_ERR, + "Unknown RF Gain %c%c\n", + lvlbuf[4], + lvlbuf[5]); + } + + break; + + case RIG_LEVEL_ATT: + retval = current_data_read(rig, lvlbuf); + + if (retval != RIG_OK) + { + return retval; + } + + switch (lvlbuf[5]) + { + case '1': + case '0': val->i = 0; break; + + case '2': val->i = 20; break; + + case '3': val->i = 10; break; + + default: rig_debug(RIG_DEBUG_ERR, + "Unknown RF Gain %c%c\n", + lvlbuf[4], + lvlbuf[5]); + } + + break; + + case RIG_LEVEL_RFPOWER: + retval = dx77_transaction(rig, + AL CMD_RPOWER EOM, + strlen(AL CMD_RPOWER EOM), + lvlbuf, + &lvl_len); + + if (retval != RIG_OK) + { + return retval; + } + + if (lvl_len != 1) + { + rig_debug(RIG_DEBUG_ERR, + "dx77_get_level: wrong answer len=%d\n", + lvl_len); + + return -RIG_ERJCTED; + } + + /* H or L */ + val->f = lvlbuf[0] == 'H' ? 1.0 : 0.0; + break; + + default: + rig_debug(RIG_DEBUG_ERR, "Unsupported get_level %s\n", rig_strlevel(level)); + + return -RIG_EINVAL; + } + + return RIG_OK; +} + + +/* + * dx77_set_parm + */ +int dx77_set_parm(RIG *rig, setting_t parm, value_t val) +{ + int cmd_len; + char cmdbuf[BUFSZ]; + + /* Optimize: + * sort the switch cases with the most frequent first + */ + switch (parm) + { + case RIG_PARM_BEEP: + rig_debug(RIG_DEBUG_ERR, "val is %d\n", val.i); + cmd_len = sprintf(cmdbuf, AL CMD_SDATA "A%d" EOM, val.i ? 1 : 0); + return dx77_transaction(rig, cmdbuf, cmd_len, NULL, NULL); + + case RIG_PARM_BACKLIGHT: + rig_debug(RIG_DEBUG_ERR, "val is %0f\n", val.f); + cmd_len = sprintf(cmdbuf, AL CMD_SDATA "O%d" EOM, (int)(val.f * 5)); + return dx77_transaction(rig, cmdbuf, cmd_len, NULL, NULL); + + default: + rig_debug(RIG_DEBUG_ERR, "Unsupported set_parm %d\n", (int)parm); + return -RIG_EINVAL; + } + + return RIG_OK; +} + + +/* + * dx77_set_ctcss_tone + * Assumes rig!=NULL, rig->caps->ctcss_list != NULL + */ +int dx77_set_ctcss_tone(RIG *rig, vfo_t vfo, tone_t tone) +{ + const struct rig_caps *caps; + unsigned char tonebuf[BUFSZ]; + int tone_len; + int i; + + caps = rig->caps; + + for (i = 0; caps->ctcss_list[i] != 0; i++) + { + if (caps->ctcss_list[i] == tone) + { + break; + } + } + + if (caps->ctcss_list[i] != tone) + { + return -RIG_EINVAL; + } + + tone_len = sprintf((char *) tonebuf, AL CMD_CTCSS "%02d" EOM, i + 1); + + return dx77_transaction(rig, (char *) tonebuf, tone_len, NULL, NULL); +} + + +/* + * dx77_get_ptt + * Assumes rig!=NULL, ptt!=NULL + */ +int dx77_get_ptt(RIG *rig, vfo_t vfo, ptt_t *ptt) +{ + char pttbuf[BUFSZ]; + int ptt_len, retval; + + retval = dx77_transaction(rig, + AL CMD_PTT EOM, + strlen(AL CMD_PTT EOM), + pttbuf, + &ptt_len); + + if (retval != RIG_OK) + { + return retval; + } + + if (ptt_len != 3 && ptt_len != 4) + { + rig_debug(RIG_DEBUG_ERR, + "dx77_get_ptt: wrong answer %s, len=%d\n", + pttbuf, + ptt_len); + + return -RIG_ERJCTED; + } + + pttbuf[ptt_len] = '\0'; + + if (!strcmp(pttbuf, "SEND")) + { + *ptt = RIG_PTT_OFF; + } + else if (!strcmp(pttbuf, "REV")) + { + *ptt = RIG_PTT_ON; + } + else + { + rig_debug(RIG_DEBUG_ERR, + "dx77_get_ptt: unknown PTT %s\n", + pttbuf); + + return -RIG_EPROTO; + } + + return RIG_OK; +} + + +/* + * dx77_get_dcd + * Assumes rig!=NULL, dcd!=NULL + */ +int dx77_get_dcd(RIG *rig, vfo_t vfo, dcd_t *dcd) +{ + char dcdbuf[BUFSZ]; + int dcd_len, retval; + + retval = dx77_transaction(rig, + AL CMD_SQL EOM, + strlen(AL CMD_SQL EOM), + dcdbuf, + &dcd_len); + + if (retval != RIG_OK) + { + return retval; + } + + if (dcd_len != 4 && dcd_len != 5) + { + rig_debug(RIG_DEBUG_ERR, + "dx77_get_dcd: wrong answer %s, len=%d\n", + dcdbuf, + dcd_len); + + return -RIG_ERJCTED; + } + + dcdbuf[dcd_len] = '\0'; + + if (!strcmp(dcdbuf, "OPEN")) + { + *dcd = RIG_DCD_ON; + } + else if (!strcmp(dcdbuf, "CLOSE")) + { + *dcd = RIG_DCD_OFF; + } + else + { + rig_debug(RIG_DEBUG_ERR, + "dx77_get_dcd: unknown SQL %s\n", + dcdbuf); + + return -RIG_EPROTO; + } + + return RIG_OK; +} + + +/* + * dx77_set_mem + * Assumes rig!=NULL + * FIXME: check we're in memory mode first + */ +int dx77_set_mem(RIG *rig, vfo_t vfo, int ch) +{ + char cmdbuf[BUFSZ]; + int cmd_len; + + if (ch < 0 || ch > 99) + { + return -RIG_EINVAL; + } + + cmd_len = sprintf(cmdbuf, AL CMD_MCALL "%02d" EOM, ch); + + return dx77_transaction(rig, cmdbuf, cmd_len, NULL, NULL); +} + + +/* + * dx77_get_mem + * Assumes rig!=NULL, !vfo + */ +int dx77_get_mem(RIG *rig, vfo_t vfo, int *ch) +{ + char membuf[BUFSZ]; + int mem_len, retval; + + retval = dx77_transaction(rig, + AL CMD_RMEM EOM, + strlen(AL CMD_RMEM EOM), + membuf, + &mem_len); + + if (retval != RIG_OK) + { + return retval; + } + + if (mem_len != 2) + { + rig_debug(RIG_DEBUG_ERR, + "dx77_get_mem: wrong answer %s, len=%d\n", + membuf, + mem_len); + + return -RIG_ERJCTED; + } + + membuf[mem_len] = '\0'; + + *ch = atoi(membuf); + + if (*ch < 0 || *ch > 99) + { + rig_debug(RIG_DEBUG_ERR, "dx77_get_mem: unknown mem %s\n", + membuf); + return -RIG_EPROTO; + } + + return RIG_OK; +} + + +/* + * initrigs_alinco is called by rig_backend_load + */ +DECLARE_INITRIG_BACKEND(alinco) +{ + rig_register(&dx77_caps); + + return RIG_OK; +} + + + /* * dx77 rig capabilities. * From 5a65ae46921a0ad3f7fe1752e6e514dcb9817913 Mon Sep 17 00:00:00 2001 From: Weston Bustraan Date: Wed, 17 Jun 2020 17:13:20 -0400 Subject: [PATCH 2/3] Initial implementation for Alinco DX-SR8T --- include/hamlib/riglist.h | 1 + rigs/alinco/Makefile.am | 2 +- rigs/alinco/alinco.c | 19 + rigs/alinco/alinco.h | 28 +- rigs/alinco/dx77.c | 336 +++++++++--------- rigs/alinco/dxsr8.c | 723 +++++++++++++++++++++++++++++++++++++++ 6 files changed, 922 insertions(+), 187 deletions(-) create mode 100644 rigs/alinco/dxsr8.c diff --git a/include/hamlib/riglist.h b/include/hamlib/riglist.h index ee75238c2..0c4c5ae63 100644 --- a/include/hamlib/riglist.h +++ b/include/hamlib/riglist.h @@ -467,6 +467,7 @@ #define RIG_ALINCO 17 #define RIG_BACKEND_ALINCO "alinco" #define RIG_MODEL_DX77 RIG_MAKE_MODEL(RIG_ALINCO, 1) +#define RIG_MODEL_DXSR8 RIG_MAKE_MODEL(RIG_ALINCO, 2) /* diff --git a/rigs/alinco/Makefile.am b/rigs/alinco/Makefile.am index 4ceadc7ee..e57ace4f0 100644 --- a/rigs/alinco/Makefile.am +++ b/rigs/alinco/Makefile.am @@ -1,4 +1,4 @@ -ALINCOSRC = dx77.c alinco.c alinco.h +ALINCOSRC = dx77.c dxsr8.c alinco.c alinco.h noinst_LTLIBRARIES = libhamlib-alinco.la libhamlib_alinco_la_SOURCES = $(ALINCOSRC) diff --git a/rigs/alinco/alinco.c b/rigs/alinco/alinco.c index 2699f9c3f..5537ffd93 100644 --- a/rigs/alinco/alinco.c +++ b/rigs/alinco/alinco.c @@ -30,5 +30,24 @@ #include #include +#include #include "alinco.h" + + + +/* + * initrigs_alinco is called by rig_backend_load + */ +DECLARE_INITRIG_BACKEND(alinco) +{ + rig_register(&dx77_caps); + rig_register(&dxsr8_caps); + + return RIG_OK; +} + +/* + * Function definitions below + */ + diff --git a/rigs/alinco/alinco.h b/rigs/alinco/alinco.h index c1210f378..ac98d2702 100644 --- a/rigs/alinco/alinco.h +++ b/rigs/alinco/alinco.h @@ -27,30 +27,12 @@ #define BACKEND_VER "20200323" -int alinco_set_vfo(RIG *rig, vfo_t vfo); -int alinco_get_vfo(RIG *rig, vfo_t *vfo); -int alinco_set_freq(RIG *rig, vfo_t vfo, freq_t freq); -int alinco_get_freq(RIG *rig, vfo_t vfo, freq_t *freq); -int alinco_set_mode(RIG *rig, vfo_t vfo, rmode_t mode, pbwidth_t width); -int alinco_get_mode(RIG *rig, vfo_t vfo, rmode_t *mode, pbwidth_t *width); -int alinco_set_split_vfo(RIG *rig, vfo_t vfo, split_t split, vfo_t tx_vfo); -int alinco_get_split_vfo(RIG *rig, vfo_t vfo, split_t *split, vfo_t *tx_vfo); -int alinco_set_split_freq(RIG *rig, vfo_t vfo, freq_t tx_freq); -int alinco_get_split_freq(RIG *rig, vfo_t vfo, freq_t *tx_freq); -int alinco_set_func(RIG *rig, vfo_t vfo, setting_t func, int status); -int alinco_get_func(RIG *rig, vfo_t vfo, setting_t func, int *status); -int alinco_set_level(RIG *rig, vfo_t vfo, setting_t level, value_t val); -int alinco_get_level(RIG *rig, vfo_t vfo, setting_t level, value_t *val); -int alinco_set_parm(RIG *rig, setting_t parm, value_t val); -int alinco_get_parm(RIG *rig, setting_t parm, value_t *val); -int alinco_set_ctcss_tone(RIG *rig, vfo_t vfo, tone_t tone); -int alinco_get_rit(RIG *rig, vfo_t vfo, shortfreq_t *rit); -int alinco_get_ptt(RIG *rig, vfo_t vfo, ptt_t *ptt); -int alinco_get_dcd(RIG *rig, vfo_t vfo, dcd_t *dcd); -int alinco_set_mem(RIG *rig, vfo_t vfo, int ch); -int alinco_get_mem(RIG *rig, vfo_t vfo, int *ch); - extern const struct rig_caps dx77_caps; +extern const struct rig_caps dxsr8_caps; + +#define BUFSZ 32 + +#define AL "AL" #endif /* _ALINCO_H */ diff --git a/rigs/alinco/dx77.c b/rigs/alinco/dx77.c index 9168e2256..d057440d7 100644 --- a/rigs/alinco/dx77.c +++ b/rigs/alinco/dx77.c @@ -31,19 +31,11 @@ #include -#include #include "idx_builtin.h" #include "alinco.h" +#include #include #include -#include - -#define BUFSZ 32 - - -/* Line Feed */ -#define EOM "\x0d" -#define LF "\x0a" /* * modes in use by the "2G" command @@ -55,7 +47,10 @@ #define MD_AM '4' #define MD_FM '5' -#define AL "AL" +/* Line Feed */ +#define EOM "\x0d" +#define LF "\x0a" + #define CMD_TXFREQ "0A" /* Transmit frequency */ #define CMD_RXFREQ "0B" /* Receive frequency */ #define CMD_VFO "1A" @@ -120,6 +115,173 @@ { 216, 60 }, \ } } + +int dx77_set_vfo(RIG *rig, vfo_t vfo); +int dx77_get_vfo(RIG *rig, vfo_t *vfo); +int dx77_set_freq(RIG *rig, vfo_t vfo, freq_t freq); +int dx77_get_freq(RIG *rig, vfo_t vfo, freq_t *freq); +int dx77_set_mode(RIG *rig, vfo_t vfo, rmode_t mode, pbwidth_t width); +int dx77_get_mode(RIG *rig, vfo_t vfo, rmode_t *mode, pbwidth_t *width); +int dx77_set_split_vfo(RIG *rig, vfo_t vfo, split_t split, vfo_t tx_vfo); +int dx77_get_split_vfo(RIG *rig, vfo_t vfo, split_t *split, vfo_t *tx_vfo); +int dx77_set_split_freq(RIG *rig, vfo_t vfo, freq_t tx_freq); +int dx77_get_split_freq(RIG *rig, vfo_t vfo, freq_t *tx_freq); +int dx77_set_func(RIG *rig, vfo_t vfo, setting_t func, int status); +int dx77_get_func(RIG *rig, vfo_t vfo, setting_t func, int *status); +int dx77_set_level(RIG *rig, vfo_t vfo, setting_t level, value_t val); +int dx77_get_level(RIG *rig, vfo_t vfo, setting_t level, value_t *val); +int dx77_set_parm(RIG *rig, setting_t parm, value_t val); +int dx77_get_parm(RIG *rig, setting_t parm, value_t *val); +int dx77_set_ctcss_tone(RIG *rig, vfo_t vfo, tone_t tone); +int dx77_get_rit(RIG *rig, vfo_t vfo, shortfreq_t *rit); +int dx77_get_ptt(RIG *rig, vfo_t vfo, ptt_t *ptt); +int dx77_get_dcd(RIG *rig, vfo_t vfo, dcd_t *dcd); +int dx77_set_mem(RIG *rig, vfo_t vfo, int ch); +int dx77_get_mem(RIG *rig, vfo_t vfo, int *ch); + + + +/* + * dx77 rig capabilities. + * + * protocol is documented at + * http://www.alinco.com/pdf.files/DX77-77_SOFTWARE_MANUAL.pdf + * + * This backend was a pleasure to develop. Documentation is clear, + * and the protocol logical. I'm wondering is the rig's good too. --SF + * + * TODO: + * - get_parm/set_parm and some LEVELs left (Set Data "2W" command). + * - tuner + * - up/down + * - scan + */ +const struct rig_caps dx77_caps = +{ + RIG_MODEL(RIG_MODEL_DX77), + .model_name = "DX-77", + .mfg_name = "Alinco", + .version = BACKEND_VER ".0", + .copyright = "LGPL", + .status = RIG_STATUS_BETA, + .rig_type = RIG_TYPE_TRANSCEIVER, + .ptt_type = RIG_PTT_NONE, + .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 = 2, + .serial_parity = RIG_PARITY_NONE, + .serial_handshake = RIG_HANDSHAKE_NONE, + .write_delay = 0, + .post_write_delay = 0, + .timeout = 200, + .retry = 3, + + .has_get_func = DX77_FUNC, + .has_set_func = DX77_FUNC | RIG_FUNC_MON | RIG_FUNC_COMP, + .has_get_level = DX77_LEVEL_ALL, + .has_set_level = RIG_LEVEL_SET(DX77_LEVEL_ALL), + .has_get_parm = RIG_PARM_NONE, + .has_set_parm = RIG_PARM_SET(DX77_PARM_ALL), + .level_gran = + { + [LVL_RAWSTR] = { .min = { .i = 0 }, .max = { .i = 255 } }, + }, + .parm_gran = {}, + .ctcss_list = common_ctcss_list, + .dcs_list = NULL, + .preamp = { 10, RIG_DBLST_END }, + .attenuator = { 10, 20, RIG_DBLST_END }, + .max_rit = kHz(1), + .max_xit = Hz(0), + .max_ifshift = Hz(0), + .targetable_vfo = 0, + .transceive = RIG_TRN_OFF, + .bank_qty = 0, + .chan_desc_sz = 0, + + .chan_list = + { + { 0, 99, RIG_MTYPE_MEM }, + RIG_CHAN_END, + }, + + .rx_range_list1 = { RIG_FRNG_END, }, /* FIXME: enter region 1 setting */ + .tx_range_list1 = { RIG_FRNG_END, }, + .rx_range_list2 = + { + {kHz(500), MHz(30), DX77_ALL_MODES, -1, -1, DX77_VFO}, + RIG_FRNG_END, + }, + .tx_range_list2 = + { + {kHz(1800), MHz(2) - 100, DX77_OTHER_TX_MODES, W(10), W(100), DX77_VFO}, + {kHz(1800), MHz(2) - 100, DX77_AM_TX_MODES, W(4), W(40), DX77_VFO}, + {kHz(3500), MHz(4) - 100, DX77_OTHER_TX_MODES, W(10), W(100), DX77_VFO}, + {kHz(3500), MHz(4) - 100, DX77_AM_TX_MODES, W(4), W(40), DX77_VFO}, + {MHz(7), kHz(7300), DX77_OTHER_TX_MODES, W(10), W(100), DX77_VFO}, + {MHz(7), kHz(7300), DX77_AM_TX_MODES, W(4), W(40), DX77_VFO}, + {kHz(10100), kHz(10150), DX77_OTHER_TX_MODES, W(10), W(100), DX77_VFO}, + {kHz(10100), kHz(10150), DX77_AM_TX_MODES, W(4), W(40), DX77_VFO}, + {MHz(14), kHz(14350), DX77_OTHER_TX_MODES, W(10), W(100), DX77_VFO}, + {MHz(14), kHz(14350), DX77_AM_TX_MODES, W(4), W(40), DX77_VFO}, + {kHz(18068), kHz(18168), DX77_OTHER_TX_MODES, W(10), W(100), DX77_VFO}, + {kHz(18068), kHz(18168), DX77_AM_TX_MODES, W(4), W(40), DX77_VFO}, + {MHz(21), kHz(21450), DX77_OTHER_TX_MODES, W(10), W(100), DX77_VFO}, + {MHz(21), kHz(21450), DX77_AM_TX_MODES, W(4), W(40), DX77_VFO}, + {kHz(24890), kHz(24990), DX77_OTHER_TX_MODES, W(10), W(100), DX77_VFO}, + {kHz(24890), kHz(24990), DX77_AM_TX_MODES, W(4), W(40), DX77_VFO}, + {MHz(28), kHz(29700), DX77_OTHER_TX_MODES, W(10), W(100), DX77_VFO}, + {MHz(28), kHz(29700), DX77_AM_TX_MODES, W(4), W(40), DX77_VFO}, + RIG_FRNG_END, + }, + .tuning_steps = + { + {DX77_ALL_MODES, 10}, /* FIXME: add other ts */ + RIG_TS_END, + }, + /* mode/filter list, remember: order matters! */ + .filters = + { + {RIG_MODE_SSB | RIG_MODE_CW, kHz(2.7)}, + {RIG_MODE_CW, kHz(0.5)}, + {RIG_MODE_AM | RIG_MODE_FM, kHz(8)}, + {RIG_MODE_AM, kHz(2.7)}, + RIG_FLT_END, + }, + .str_cal = DX77_STR_CAL, + + .set_freq = dx77_set_freq, + .get_freq = dx77_get_freq, + .set_mode = dx77_set_mode, + .get_mode = dx77_get_mode, + .set_vfo = dx77_set_vfo, + .get_vfo = dx77_get_vfo, + .set_split_vfo = dx77_set_split_vfo, + .get_split_vfo = dx77_get_split_vfo, + .set_split_freq = dx77_set_split_freq, + .get_split_freq = dx77_get_split_freq, + .set_ctcss_tone = dx77_set_ctcss_tone, + .get_rit = dx77_get_rit, + .get_ptt = dx77_get_ptt, + .get_dcd = dx77_get_dcd, + .set_func = dx77_set_func, + .get_func = dx77_get_func, + .set_parm = dx77_set_parm, + .set_level = dx77_set_level, + .get_level = dx77_get_level, + .set_mem = dx77_set_mem, + .get_mem = dx77_get_mem, + +}; + + +/* + * Function definitions below + */ + /* * dx77_transaction * We assume that rig!=NULL, rig->state!= NULL, data!=NULL, data_len!=NULL @@ -132,6 +294,7 @@ int dx77_transaction(RIG *rig, char *data, int *data_len) { + int retval; struct rig_state *rs; char echobuf[BUFSZ + 1]; @@ -217,7 +380,6 @@ int dx77_transaction(RIG *rig, return RIG_OK; } - /* * dx77_set_vfo * Assumes rig!=NULL @@ -1293,155 +1455,3 @@ int dx77_get_mem(RIG *rig, vfo_t vfo, int *ch) return RIG_OK; } - -/* - * initrigs_alinco is called by rig_backend_load - */ -DECLARE_INITRIG_BACKEND(alinco) -{ - rig_register(&dx77_caps); - - return RIG_OK; -} - - - -/* - * dx77 rig capabilities. - * - * protocol is documented at - * http://www.alinco.com/pdf.files/DX77-77_SOFTWARE_MANUAL.pdf - * - * This backend was a pleasure to develop. Documentation is clear, - * and the protocol logical. I'm wondering is the rig's good too. --SF - * - * TODO: - * - get_parm/set_parm and some LEVELs left (Set Data "2W" command). - * - tuner - * - up/down - * - scan - */ -const struct rig_caps dx77_caps = -{ - RIG_MODEL(RIG_MODEL_DX77), - .model_name = "DX-77", - .mfg_name = "Alinco", - .version = BACKEND_VER ".0", - .copyright = "LGPL", - .status = RIG_STATUS_BETA, - .rig_type = RIG_TYPE_TRANSCEIVER, - .ptt_type = RIG_PTT_NONE, - .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 = 2, - .serial_parity = RIG_PARITY_NONE, - .serial_handshake = RIG_HANDSHAKE_NONE, - .write_delay = 0, - .post_write_delay = 0, - .timeout = 200, - .retry = 3, - - .has_get_func = DX77_FUNC, - .has_set_func = DX77_FUNC | RIG_FUNC_MON | RIG_FUNC_COMP, - .has_get_level = DX77_LEVEL_ALL, - .has_set_level = RIG_LEVEL_SET(DX77_LEVEL_ALL), - .has_get_parm = RIG_PARM_NONE, - .has_set_parm = RIG_PARM_SET(DX77_PARM_ALL), - .level_gran = - { - [LVL_RAWSTR] = { .min = { .i = 0 }, .max = { .i = 255 } }, - }, - .parm_gran = {}, - .ctcss_list = common_ctcss_list, - .dcs_list = NULL, - .preamp = { 10, RIG_DBLST_END }, - .attenuator = { 10, 20, RIG_DBLST_END }, - .max_rit = kHz(1), - .max_xit = Hz(0), - .max_ifshift = Hz(0), - .targetable_vfo = 0, - .transceive = RIG_TRN_OFF, - .bank_qty = 0, - .chan_desc_sz = 0, - - .chan_list = - { - { 0, 99, RIG_MTYPE_MEM }, - RIG_CHAN_END, - }, - - .rx_range_list1 = { RIG_FRNG_END, }, /* FIXME: enter region 1 setting */ - .tx_range_list1 = { RIG_FRNG_END, }, - .rx_range_list2 = - { - {kHz(500), MHz(30), DX77_ALL_MODES, -1, -1, DX77_VFO}, - RIG_FRNG_END, - }, - .tx_range_list2 = - { - {kHz(1800), MHz(2) - 100, DX77_OTHER_TX_MODES, W(10), W(100), DX77_VFO}, - {kHz(1800), MHz(2) - 100, DX77_AM_TX_MODES, W(4), W(40), DX77_VFO}, - {kHz(3500), MHz(4) - 100, DX77_OTHER_TX_MODES, W(10), W(100), DX77_VFO}, - {kHz(3500), MHz(4) - 100, DX77_AM_TX_MODES, W(4), W(40), DX77_VFO}, - {MHz(7), kHz(7300), DX77_OTHER_TX_MODES, W(10), W(100), DX77_VFO}, - {MHz(7), kHz(7300), DX77_AM_TX_MODES, W(4), W(40), DX77_VFO}, - {kHz(10100), kHz(10150), DX77_OTHER_TX_MODES, W(10), W(100), DX77_VFO}, - {kHz(10100), kHz(10150), DX77_AM_TX_MODES, W(4), W(40), DX77_VFO}, - {MHz(14), kHz(14350), DX77_OTHER_TX_MODES, W(10), W(100), DX77_VFO}, - {MHz(14), kHz(14350), DX77_AM_TX_MODES, W(4), W(40), DX77_VFO}, - {kHz(18068), kHz(18168), DX77_OTHER_TX_MODES, W(10), W(100), DX77_VFO}, - {kHz(18068), kHz(18168), DX77_AM_TX_MODES, W(4), W(40), DX77_VFO}, - {MHz(21), kHz(21450), DX77_OTHER_TX_MODES, W(10), W(100), DX77_VFO}, - {MHz(21), kHz(21450), DX77_AM_TX_MODES, W(4), W(40), DX77_VFO}, - {kHz(24890), kHz(24990), DX77_OTHER_TX_MODES, W(10), W(100), DX77_VFO}, - {kHz(24890), kHz(24990), DX77_AM_TX_MODES, W(4), W(40), DX77_VFO}, - {MHz(28), kHz(29700), DX77_OTHER_TX_MODES, W(10), W(100), DX77_VFO}, - {MHz(28), kHz(29700), DX77_AM_TX_MODES, W(4), W(40), DX77_VFO}, - RIG_FRNG_END, - }, - .tuning_steps = - { - {DX77_ALL_MODES, 10}, /* FIXME: add other ts */ - RIG_TS_END, - }, - /* mode/filter list, remember: order matters! */ - .filters = - { - {RIG_MODE_SSB | RIG_MODE_CW, kHz(2.7)}, - {RIG_MODE_CW, kHz(0.5)}, - {RIG_MODE_AM | RIG_MODE_FM, kHz(8)}, - {RIG_MODE_AM, kHz(2.7)}, - RIG_FLT_END, - }, - .str_cal = DX77_STR_CAL, - - .set_freq = alinco_set_freq, - .get_freq = alinco_get_freq, - .set_mode = alinco_set_mode, - .get_mode = alinco_get_mode, - .set_vfo = alinco_set_vfo, - .get_vfo = alinco_get_vfo, - .set_split_vfo = alinco_set_split_vfo, - .get_split_vfo = alinco_get_split_vfo, - .set_split_freq = alinco_set_split_freq, - .get_split_freq = alinco_get_split_freq, - .set_ctcss_tone = alinco_set_ctcss_tone, - .get_rit = alinco_get_rit, - .get_ptt = alinco_get_ptt, - .get_dcd = alinco_get_dcd, - .set_func = alinco_set_func, - .get_func = alinco_get_func, - .set_parm = alinco_set_parm, - .set_level = alinco_set_level, - .get_level = alinco_get_level, - .set_mem = alinco_set_mem, - .get_mem = alinco_get_mem, - -}; - -/* - * Function definitions below - */ diff --git a/rigs/alinco/dxsr8.c b/rigs/alinco/dxsr8.c new file mode 100644 index 000000000..5d26e862d --- /dev/null +++ b/rigs/alinco/dxsr8.c @@ -0,0 +1,723 @@ +/* + * Hamlib Alinco backend - DXSR8 description + * Copyright (c) 2020 by Wes Bustraan (W8WJB) + * + * + * 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 /* String function definitions */ +#include /* UNIX standard function definitions */ + +#include +#include +#include +#include +#include +#include "idx_builtin.h" +#include "alinco.h" + + +#define DXSR8_ALL_MODES (RIG_MODE_USB|RIG_MODE_LSB|RIG_MODE_CW|RIG_MODE_CWR|RIG_MODE_AM|RIG_MODE_FM) +#define DXSR8_OTHER_TX_MODES (RIG_MODE_CW|RIG_MODE_SSB|RIG_MODE_FM) +#define DXSR8_AM_TX_MODES RIG_MODE_AM + +#define DXSR8_FUNC (RIG_FUNC_FAGC|RIG_FUNC_NB) + +#define DXSR8_LEVEL_ALL (RIG_LEVEL_RFPOWER|RIG_LEVEL_RF) + +#define DXSR8_PARM_ALL RIG_PARM_NONE + +#define DXSR8_VFO RIG_VFO_NONE + +/* Line Feed */ +#define EOM "\r\n" +#define LF "\n" + +#define MD_USB 0 +#define MD_LSB 1 +#define MD_CWU 2 +#define MD_CWL 3 +#define MD_AM 4 +#define MD_FM 5 + +int dxsr8_set_freq(RIG *rig, vfo_t vfo, freq_t freq); +int dxsr8_get_freq(RIG *rig, vfo_t vfo, freq_t *freq); +int dxsr8_set_mode(RIG *rig, vfo_t vfo, rmode_t mode, pbwidth_t width); +int dxsr8_get_mode(RIG *rig, vfo_t vfo, rmode_t *mode, pbwidth_t *width); +int dxsr8_set_func(RIG *rig, vfo_t vfo, setting_t func, int status); +int dxsr8_get_func(RIG *rig, vfo_t vfo, setting_t func, int *status); +int dxsr8_set_level(RIG *rig, vfo_t vfo, setting_t level, value_t val); +int dxsr8_get_level(RIG *rig, vfo_t vfo, setting_t level, value_t *val); +int dxsr8_get_ptt(RIG *rig, vfo_t vfo, ptt_t *ptt); +int dxsr8_set_ptt(RIG *rig, vfo_t vfo, ptt_t ptt); + + +/* + * DX-SR8 rig capabilities. + * + * thanks to + * https://yo5ptd.wordpress.com/2017/02/12/alinco-dx-sr8/ + * for a partially documented protocol + */ +const struct rig_caps dxsr8_caps = +{ + RIG_MODEL(RIG_MODEL_DXSR8), + .model_name = "DX-SR8", + .mfg_name = "Alinco", + .version = BACKEND_VER ".0", + .copyright = "LGPL", + .status = RIG_STATUS_BETA, + .rig_type = RIG_TYPE_TRANSCEIVER, + .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_NONE, + .write_delay = 0, + .post_write_delay = 0, + .timeout = 200, + .retry = 3, + + .has_get_func = DXSR8_FUNC, + .has_set_func = DXSR8_FUNC, + .has_get_level = DXSR8_LEVEL_ALL, + .has_set_level = RIG_LEVEL_SET(DXSR8_LEVEL_ALL), + .has_get_parm = RIG_PARM_NONE, + .has_set_parm = RIG_PARM_NONE, + .level_gran = + { + [LVL_RAWSTR] = { .min = { .i = 0 }, .max = { .i = 255 } }, + }, + .parm_gran = {}, + .ctcss_list = common_ctcss_list, + .dcs_list = NULL, + .preamp = { 10, RIG_DBLST_END }, + .attenuator = { 10, 20, RIG_DBLST_END }, + .max_rit = kHz(1.2), + .max_xit = kHz(1.2), + .max_ifshift = kHz(1.5), + .targetable_vfo = 0, + .transceive = RIG_TRN_OFF, + .bank_qty = 0, + .chan_desc_sz = 0, + + .chan_list = + { + { 0, 199, RIG_MTYPE_MEM }, + { 0, 199, RIG_MTYPE_MEM }, + RIG_CHAN_END, + }, + + .rx_range_list1 = + { + {kHz(135), MHz(30), DXSR8_ALL_MODES, -1, -1, DXSR8_VFO, 0, "DX-SR8T"}, + RIG_FRNG_END, + }, + .tx_range_list1 = + { + {kHz(1800), MHz(2) - 100, DXSR8_OTHER_TX_MODES, W(10), W(100), DXSR8_VFO, 0, "DX-SR8T"}, + {kHz(1800), MHz(2) - 100, DXSR8_AM_TX_MODES, W(4), W(40), DXSR8_VFO, 0, "DX-SR8T"}, + {kHz(3500), MHz(4) - 100, DXSR8_OTHER_TX_MODES, W(10), W(100), DXSR8_VFO, 0, "DX-SR8T"}, + {kHz(3500), MHz(4) - 100, DXSR8_AM_TX_MODES, W(4), W(40), DXSR8_VFO, 0, "DX-SR8T"}, + {5330500, 5330500, DXSR8_AM_TX_MODES, W(1), W(50), DXSR8_VFO, 0, "DX-SR8T"}, + {5346500, 5346500, DXSR8_AM_TX_MODES, W(1), W(50), DXSR8_VFO, 0, "DX-SR8T"}, + {5366500, 5366500, DXSR8_AM_TX_MODES, W(1), W(50), DXSR8_VFO, 0, "DX-SR8T"}, + {5371500, 5371500, DXSR8_AM_TX_MODES, W(1), W(50), DXSR8_VFO, 0, "DX-SR8T"}, + {5403500, 5403500, DXSR8_AM_TX_MODES, W(1), W(50), DXSR8_VFO, 0, "DX-SR8T"}, + {MHz(7), kHz(7300), DXSR8_OTHER_TX_MODES, W(10), W(100), DXSR8_VFO, 0, "DX-SR8T"}, + {MHz(7), kHz(7300), DXSR8_AM_TX_MODES, W(4), W(40), DXSR8_VFO, 0, "DX-SR8T"}, + {kHz(10100), kHz(10150), DXSR8_OTHER_TX_MODES, W(10), W(100), DXSR8_VFO, 0, "DX-SR8T"}, + {kHz(10100), kHz(10150), DXSR8_AM_TX_MODES, W(4), W(40), DXSR8_VFO, 0, "DX-SR8T"}, + {MHz(14), kHz(14350), DXSR8_OTHER_TX_MODES, W(10), W(100), DXSR8_VFO, 0, "DX-SR8T"}, + {MHz(14), kHz(14350), DXSR8_AM_TX_MODES, W(4), W(40), DXSR8_VFO, 0, "DX-SR8T"}, + {kHz(18068), kHz(18168), DXSR8_OTHER_TX_MODES, W(10), W(100), DXSR8_VFO, 0, "DX-SR8T"}, + {kHz(18068), kHz(18168), DXSR8_AM_TX_MODES, W(4), W(40), DXSR8_VFO, 0, "DX-SR8T"}, + {MHz(21), kHz(21450), DXSR8_OTHER_TX_MODES, W(10), W(100), DXSR8_VFO, 0, "DX-SR8T"}, + {MHz(21), kHz(21450), DXSR8_AM_TX_MODES, W(4), W(40), DXSR8_VFO, 0, "DX-SR8T"}, + {kHz(24890), kHz(24990), DXSR8_OTHER_TX_MODES, W(10), W(100), DXSR8_VFO, 0, "DX-SR8T"}, + {kHz(24890), kHz(24990), DXSR8_AM_TX_MODES, W(4), W(40), DXSR8_VFO, 0, "DX-SR8T"}, + {MHz(28), kHz(29700), DXSR8_OTHER_TX_MODES, W(10), W(100), DXSR8_VFO, 0, "DX-SR8T"}, + {MHz(28), kHz(29700), DXSR8_AM_TX_MODES, W(4), W(40), DXSR8_VFO, 0, "DX-SR8T"}, + RIG_FRNG_END, + }, + .rx_range_list2 = + { + {kHz(135), MHz(30), DXSR8_ALL_MODES, -1, -1, DXSR8_VFO, 0, "DX-SR8E"}, + RIG_FRNG_END, + }, + .tx_range_list2 = + { + {kHz(1800), MHz(2) - 100, DXSR8_OTHER_TX_MODES, W(10), W(100), DXSR8_VFO, 0, "DX-SR8E"}, + {kHz(1800), MHz(2) - 100, DXSR8_AM_TX_MODES, W(4), W(40), DXSR8_VFO, 0, "DX-SR8E"}, + {kHz(3500), MHz(4) - 100, DXSR8_OTHER_TX_MODES, W(10), W(100), DXSR8_VFO, 0, "DX-SR8E"}, + {kHz(3500), MHz(4) - 100, DXSR8_AM_TX_MODES, W(4), W(40), DXSR8_VFO, 0, "DX-SR8E"}, + {kHz(6900), kHz(7500), DXSR8_OTHER_TX_MODES, W(10), W(100), DXSR8_VFO, 0, "DX-SR8E"}, + {kHz(6900), kHz(7500), DXSR8_AM_TX_MODES, W(4), W(40), DXSR8_VFO, 0, "DX-SR8E"}, + {kHz(9900), kHz(10500), DXSR8_OTHER_TX_MODES, W(10), W(100), DXSR8_VFO, 0, "DX-SR8E"}, + {kHz(9900), kHz(10500), DXSR8_AM_TX_MODES, W(4), W(40), DXSR8_VFO, 0, "DX-SR8E"}, + {kHz(13900), kHz(14500), DXSR8_OTHER_TX_MODES, W(10), W(100), DXSR8_VFO, 0, "DX-SR8E"}, + {kHz(13900), kHz(14500), DXSR8_AM_TX_MODES, W(4), W(40), DXSR8_VFO, 0, "DX-SR8E"}, + {kHz(17900), kHz(18500), DXSR8_OTHER_TX_MODES, W(10), W(100), DXSR8_VFO, 0, "DX-SR8E"}, + {kHz(17900), kHz(18500), DXSR8_AM_TX_MODES, W(4), W(40), DXSR8_VFO, 0, "DX-SR8E"}, + {kHz(20900), kHz(21500), DXSR8_OTHER_TX_MODES, W(10), W(100), DXSR8_VFO, 0, "DX-SR8E"}, + {kHz(20900), kHz(21500), DXSR8_AM_TX_MODES, W(4), W(40), DXSR8_VFO, 0, "DX-SR8E"}, + {kHz(24400), kHz(25099), DXSR8_OTHER_TX_MODES, W(10), W(100), DXSR8_VFO, 0, "DX-SR8E"}, + {kHz(24400), kHz(25099), DXSR8_AM_TX_MODES, W(4), W(40), DXSR8_VFO, 0, "DX-SR8E"}, + {MHz(28), MHz(30), DXSR8_OTHER_TX_MODES, W(10), W(100), DXSR8_VFO, 0, "DX-SR8E"}, + {MHz(28), MHz(30), DXSR8_AM_TX_MODES, W(4), W(40), DXSR8_VFO, 0, "DX-SR8E"}, + RIG_FRNG_END, + }, + .tuning_steps = + { + {DXSR8_ALL_MODES, 10}, /* FIXME: add other ts */ + RIG_TS_END, + }, + /* mode/filter list, remember: order matters! */ + .filters = + { + {RIG_MODE_CW, kHz(1)}, + {RIG_MODE_CW, kHz(0.5)}, + {RIG_MODE_SSB, kHz(2.4)}, + {RIG_MODE_SSB, kHz(1)}, + {RIG_MODE_AM | RIG_MODE_FM, kHz(9)}, + {RIG_MODE_AM, kHz(2.4)}, + RIG_FLT_END, + }, + .set_freq = dxsr8_set_freq, // AL~RW_RXF14212000 + .get_freq = dxsr8_get_freq, // AL~RR_RXF + .set_mode = dxsr8_set_mode, // AL~RW_RFM00, AL~RW_NAR00 + .get_mode = dxsr8_get_mode, // AL~RR_RFM, AL~RR_NAR + .get_ptt = dxsr8_get_ptt, // AL~RR_PTT + .set_ptt = dxsr8_set_ptt, // AL~RW_PTT00 + .set_func = dxsr8_set_func, // AL~RW_AGC00, AL~RW_NZB00 + .get_func = dxsr8_get_func, // AL~RR_AGC, AL~RR_NZB + .set_level = dxsr8_set_level, // AL~RW_RFG00, AL~RW_PWR00 + .get_level = dxsr8_get_level, // AL~RR_RFG, AL~RR_PWR + +}; + +/* + * Function definitions below + */ + + +/* + * dxsr8_transaction + * We assume that rig!=NULL, rig->state!= NULL, data!=NULL, data_len!=NULL + * Otherwise, you'll get a nice seg fault. You've been warned! + * TODO: error case handling + */ +int dxsr8_transaction(RIG *rig, + const char *cmd, + int cmd_len, + char *data, + int *data_len) +{ + + int retval; + struct rig_state *rs; + char replybuf[BUFSZ + 1]; + int reply_len; + + if (cmd == NULL) + { + rig_debug(RIG_DEBUG_ERR, + "%s: null argument for cmd?\n", __func__); + return -RIG_EINTERNAL; + } + + rs = &rig->state; + + serial_flush(&rs->rigport); + + retval = write_block(&rs->rigport, cmd, cmd_len); + + if (retval != RIG_OK) + { + return retval; + } + + retval = read_string(&rs->rigport, replybuf, BUFSZ, LF, strlen(LF)); + + if (retval < 0) + { + return retval; + } + + /* no data expected, check for OK returned */ + if (data == NULL) + { + if (retval > 2) { retval -= 2; } + + replybuf[retval] = 0; + + if (strcmp(replybuf, "OK") == 0) + { + return RIG_OK; + } + else + { + return -RIG_ERJCTED; + } + } + + // strip CR/LF from string + reply_len = strcspn(replybuf, "\r\n"); + replybuf[reply_len] = 0; + + strcpy(data, replybuf); + *data_len = reply_len; + + return RIG_OK; +} + + +/** + * dxsr8_read_num + * Convenience function to read a numeric value from the radio + */ +int dxsr8_read_num(RIG *rig, + const char *cmd, + int *reply_num) +{ + int retval; + int reply_len; + char replybuf[10]; + + retval = dxsr8_transaction(rig, cmd, strlen(cmd), replybuf, &reply_len); + + if (retval != RIG_OK) + { + return retval; + } + + *reply_num = atoi(replybuf); + return RIG_OK; +} + +/* + * dxsr8_set_freq + * Assumes rig!=NULL + */ +int dxsr8_set_freq(RIG *rig, vfo_t vfo, freq_t freq) { + + char cmd[BUFSZ]; + int cmd_len; + + /* max 10 digits */ + if (freq >= GHz(10)) + { + return -RIG_EINVAL; + } + + cmd_len = sprintf(cmd, AL "~RW_RXF%08"PRIll EOM, (int64_t)freq); + return dxsr8_transaction(rig, cmd, cmd_len, NULL, NULL); +} + +/* + * dxsr8_get_freq + * Assumes rig!=NULL, freq!=NULL + */ +int dxsr8_get_freq(RIG *rig, vfo_t vfo, freq_t *freq) { + int retval, data_len; + + char cmd[] = AL "~RR_RXF" EOM; + char freqbuf[BUFSZ]; + + retval = dxsr8_transaction(rig, cmd, strlen(cmd), freqbuf, &data_len); + + if (retval != RIG_OK) + { + return retval; + } + + /* extract RX freq */ + retval = num_sscanf(freqbuf, "%"SCNfreq, freq); + + return RIG_OK; +} + +/* + * dxsr8_set_mode + * Assumes rig!=NULL + */ +int dxsr8_set_mode(RIG *rig, vfo_t vfo, rmode_t mode, pbwidth_t width) { + char mdbuf[BUFSZ]; + int mdbuf_len, wide_filter, retval; + int amode; + + switch (mode) + { + case RIG_MODE_CW: amode = MD_CWU; break; + case RIG_MODE_CWR: amode = MD_CWL; break; + case RIG_MODE_USB: amode = MD_USB; break; + case RIG_MODE_LSB: amode = MD_LSB; break; + case RIG_MODE_FM: amode = MD_FM; break; + case RIG_MODE_AM: amode = MD_AM; break; + + default: + rig_debug(RIG_DEBUG_ERR, "dxsr8_set_mode: unsupported mode %s\n", + rig_strrmode(mode)); + + return -RIG_EINVAL; + } + + mdbuf_len = sprintf(mdbuf, AL "~RW_RFM%02d" EOM, amode); + retval = dxsr8_transaction(rig, mdbuf, mdbuf_len, NULL, NULL); + + if (retval != RIG_OK) + { + return retval; + } + + if (width == RIG_PASSBAND_NOCHANGE) { return retval; } + + if (width != RIG_PASSBAND_NORMAL + && width < rig_passband_normal(rig, mode)) + { + wide_filter = 1; // AL~RW_NAR01 Set narrow bandwidth + } + else + { + wide_filter = 0; // AL~RW_NAR00 Set wide bandwidth + } + + mdbuf_len = sprintf(mdbuf, AL "~RW_NAR%02d" EOM, wide_filter); + retval = dxsr8_transaction(rig, mdbuf, mdbuf_len, NULL, NULL); + + return retval; +} + +/* + * dxsr8_get_mode + * Assumes rig!=NULL, mode!=NULL + */ +int dxsr8_get_mode(RIG *rig, vfo_t vfo, rmode_t *mode, pbwidth_t *width) { + + int retval; + int amode; + int filter; + + retval = dxsr8_read_num(rig, AL "~RR_RFM" EOM, &amode); + if (retval != RIG_OK) + { + return retval; + } + + switch (amode) + { + case MD_CWL: + case MD_CWU: *mode = RIG_MODE_CW; break; + case MD_USB: *mode = RIG_MODE_USB; break; + case MD_LSB: *mode = RIG_MODE_LSB; break; + case MD_AM: *mode = RIG_MODE_AM; break; + case MD_FM: *mode = RIG_MODE_FM; break; + + default: + rig_debug(RIG_DEBUG_ERR, + "dxsr8_get_mode: unknown mode %02d\n", + amode); + + return -RIG_EINVAL; + } + + retval = dxsr8_read_num(rig, AL "~RR_NAR" EOM, &filter); + + if (filter == 0) + { + *width = rig_passband_wide(rig, *mode); + } else { + *width = rig_passband_normal(rig, *mode); + } + + return RIG_OK; +} + +/* + * dxsr8_set_func + * Assumes rig!=NULL + */ +int dxsr8_set_func(RIG *rig, vfo_t vfo, setting_t func, int status) { + + int cmd_len; + char cmd[BUFSZ]; + + switch (func) + { + case RIG_FUNC_FAGC: + cmd_len = sprintf(cmd, AL "~RW_AGC%02d" EOM, status ? 0 : 1); + + return dxsr8_transaction(rig, cmd, cmd_len, NULL, NULL); + + case RIG_FUNC_NB: + cmd_len = sprintf(cmd, AL "~RW_NZB%d" EOM, status ? 1 : 0); + + return dxsr8_transaction(rig, cmd, cmd_len, NULL, NULL); + + + default: + rig_debug(RIG_DEBUG_ERR, "Unsupported set_func %d\n", (int)func); + return -RIG_EINVAL; + } + + return RIG_OK; +} + +/* + * dxsr8_get_func + * Assumes rig!=NULL, status!=NULL + */ +int dxsr8_get_func(RIG *rig, vfo_t vfo, setting_t func, int *status) { + + int retval; + int setting; + + switch (func) + { + case RIG_FUNC_FAGC: + retval = dxsr8_read_num(rig, AL "~RR_AGC" EOM, &setting); + + if (retval != RIG_OK) + { + return retval; + } + + // 00 = Fast AGC + // 01 = Slow AGC + *status = setting ? 0 : 1; + break; + + case RIG_FUNC_NB: + retval = dxsr8_read_num(rig, AL "~RR_NZB" EOM, &setting); + + if (retval != RIG_OK) + { + return retval; + } + + // 00 = noise blanker off + // 01 = noise blanker on + *status = setting ? 1 : 0; + break; + + + default: + rig_debug(RIG_DEBUG_ERR, "Unsupported get_func %d\n", (int)func); + return -RIG_EINVAL; + } + + return RIG_OK; +} + +/* + * dxsr8_set_level + * Assumes rig!=NULL + * FIXME: cannot support PREAMP and ATT both at same time (make sense though) + */ +int dxsr8_set_level(RIG *rig, vfo_t vfo, setting_t level, value_t val) { + int cmd_len, lvl; + char cmd[BUFSZ]; + + switch (level) + { + case RIG_LEVEL_PREAMP: + switch (val.i) + { + case 0: lvl = 0; break; // AL~RW_RFG00 - RF gain 0dB + case 10: lvl = 3; break; // AL~RW_RFG03 - RF gain +10dB + + default: rig_debug(RIG_DEBUG_ERR, + "Unsupported Preamp %d\n", + val.i); + + return -RIG_EINVAL; + } + + cmd_len = sprintf(cmd, AL "~RW_RFG%02d" EOM, lvl); + return dxsr8_transaction(rig, cmd, cmd_len, NULL, NULL); + + case RIG_LEVEL_ATT: + switch (val.i) + { + case 0: lvl = 0; break; // AL~RW_RFG00 - RF gain 0dB + case 10: lvl = 1; break; // AL~RW_RFG01 - RF gain -10dB + case 20: lvl = 2; break; // AL~RW_RFG02 - RF gain -20dB + + default: rig_debug(RIG_DEBUG_ERR, + "Unsupported Att %d\n", + val.i); + + return -RIG_EINVAL; + } + + cmd_len = sprintf(cmd, AL "~RW_RFG%02d" EOM, lvl); + return dxsr8_transaction(rig, cmd, cmd_len, NULL, NULL); + + case RIG_LEVEL_RFPOWER: + + if (val.f <= 0.01) { + lvl = 2; // AL~RW_PWR02 - Sub low power (QRP mode) + } else if (val.f <= 0.1) { + lvl = 1; // AL~RW_PWR01 - Low power + } else { + lvl = 0; // AL~RW_PWR00 - High power + } + + cmd_len = sprintf(cmd, AL "~RW_PWR%02d" EOM, lvl); + return dxsr8_transaction(rig, cmd, cmd_len, NULL, NULL); + + default: + rig_debug(RIG_DEBUG_ERR, "Unsupported set_level %s\n", rig_strlevel(level)); + + return -RIG_EINVAL; + } + + return RIG_OK; +} + +/* + * dxsr8_get_level + * Assumes rig!=NULL, val!=NULL + */ +int dxsr8_get_level(RIG *rig, vfo_t vfo, setting_t level, value_t *val) { + + int retval; + int lvl; + + switch (level) + { + + case RIG_LEVEL_PREAMP: + retval = dxsr8_read_num(rig, AL "~RR_RFG" EOM, &lvl); + + if (retval != RIG_OK) + { + return retval; + } + + switch (lvl) { + case 0: + val->i = 0; break; // RF gain 0dB + case 3: + val->i = 10; break; // RF gain +10dB + default: + rig_debug(RIG_DEBUG_ERR, "Unknown RF Gain %02d\n", lvl); + } + + break; + + case RIG_LEVEL_ATT: + retval = dxsr8_read_num(rig, AL "~RR_RFG" EOM, &lvl); + + if (retval != RIG_OK) + { + return retval; + } + + switch (lvl) { + case 0: + val->i = 0; break; // RF gain 0dB + case 1: + val->i = 10; break; // RF gain -10dB + case 2: + val->i = 10; break; // RF gain -20dB + default: + rig_debug(RIG_DEBUG_ERR, "Unknown RF Gain %02d\n", lvl); + } + + break; + + case RIG_LEVEL_RFPOWER: + + retval = dxsr8_read_num(rig, AL "~RR_PWR" EOM, &lvl); + + if (retval != RIG_OK) + { + return retval; + } + + switch (lvl) + { + case 0: // 00 - High power + val->f = 1.0; // 100 W + break; + + case 1: // 01 - Low power + val->f = 0.1; // 10 W + break; + + case 3: // 02 - Sub low power (QRP mode) + val->f = 0.01; // 1 W + break; + + default: + rig_debug(RIG_DEBUG_ERR, "Unknown RF Power %02d\n", lvl); + break; + } + + break; + + default: + rig_debug(RIG_DEBUG_ERR, "Unsupported get_level %s\n", rig_strlevel(level)); + + return -RIG_EINVAL; + } + + return RIG_OK; +} + +/* + * dxsr8_get_ptt + * Assumes rig!=NULL, ptt!=NULL + */ +int dxsr8_get_ptt(RIG *rig, vfo_t vfo, ptt_t *ptt) { + + int retval; + int pttval; + + retval = dxsr8_read_num(rig, AL "~RR_PTT" EOM, &pttval); + + if (retval != RIG_OK) + { + return retval; + } + + *ptt = pttval ? RIG_PTT_ON : RIG_PTT_OFF; + return RIG_OK; +} + +/* + * dxsr8_set_ptt + * Assumes rig!=NULL + */ +int dxsr8_set_ptt(RIG *rig, vfo_t vfo, ptt_t ptt) { + + char cmd[BUFSZ]; + int cmd_len; + + cmd_len = sprintf(cmd, AL "~RW_PTT%02d" EOM, ptt); + return dxsr8_transaction(rig, cmd, cmd_len, NULL, NULL); +} \ No newline at end of file From 7520a3a70289a7f973dd0416189a898ef343271a Mon Sep 17 00:00:00 2001 From: Weston Bustraan Date: Wed, 17 Jun 2020 19:59:53 -0400 Subject: [PATCH 3/3] DX-SR8 echos back the command sent to it. Need to read past that to get to the next line containing the value --- rigs/alinco/dxsr8.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/rigs/alinco/dxsr8.c b/rigs/alinco/dxsr8.c index 5d26e862d..fa5be083c 100644 --- a/rigs/alinco/dxsr8.c +++ b/rigs/alinco/dxsr8.c @@ -260,6 +260,18 @@ int dxsr8_transaction(RIG *rig, return retval; } + /* + * Transceiver sends an echo of cmd followed by a CR/LF + * TODO: check whether cmd and echobuf match (optional) + */ + retval = read_string(&rs->rigport, replybuf, BUFSZ, LF, strlen(LF)); + + if (retval < 0) + { + return retval; + } + + retval = read_string(&rs->rigport, replybuf, BUFSZ, LF, strlen(LF)); if (retval < 0)