/* * Copyright (c) 2010-2011 by Mikhail Kshevetskiy (mikhail.kshevetskiy@gmail.com) * * Code based on VX-1700 CAT manual: * http://www.vertexstandard.com/downloadFile.cfm?FileID=3397&FileCatID=135&FileName=VX-1700_CAT_MANUAL_10_14_2008.pdf&FileContentType=application%2Fpdf * * WARNING: this manual has two errors * 1) Status Update Command (10h), U=01 returns 0..199 for channels 1..200 * 2) Frequency Data (bytes 1--4 of 9-Byte VFO Data Assignment, Status Update * Command (10h), U=02 and U=03) uses bytes 1--3 for frequency, byte 4 is * not used and always zero. Thus bytes 0x15,0xBE,0x68,0x00 means * frequency = 10 * 0x15BE68 = 10 * 1425000 = 14.25 MHz * * * 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 #include #include "idx_builtin.h" #include "hamlib/rig.h" #include "bandplan.h" #include "serial.h" #include "misc.h" #include "yaesu.h" #include "vx1700.h" static const yaesu_cmd_set_t ncmd[] = { { 0, { 0x00, 0x00, 0x00, 0x00, 0x02 } }, /* Recall Memory */ { 0, { 0x00, 0x00, 0x00, 0x00, 0x03 } }, /* VFO to MEM */ { 0, { 0x00, 0x00, 0x01, 0x00, 0x03 } }, /* Hide Memory Channel */ { 1, { 0x00, 0x00, 0x00, 0x00, 0x05 } }, /* Select VFO (A) */ { 0, { 0x00, 0x00, 0x00, 0x00, 0x0a } }, /* Set Op Freq */ { 1, { 0x00, 0x00, 0x00, 0x00, 0x0c } }, /* OP Mode Set LSB */ { 1, { 0x00, 0x00, 0x00, 0x01, 0x0c } }, /* OP Mode Set USB */ { 1, { 0x00, 0x00, 0x00, 0x02, 0x0c } }, /* OP Mode Set CW-W */ { 1, { 0x00, 0x00, 0x00, 0x03, 0x0c } }, /* OP Mode Set CW-N */ { 1, { 0x00, 0x00, 0x00, 0x04, 0x0c } }, /* OP Mode Set AM */ { 1, { 0x00, 0x00, 0x00, 0x08, 0x0c } }, /* OP Mode Set RTTY LSB-W */ { 1, { 0x00, 0x00, 0x00, 0x09, 0x0c } }, /* OP Mode Set RTTY USB-W */ { 1, { 0x00, 0x00, 0x00, 0x0d, 0x0c } }, /* OP Mode Set H3E */ { 1, { 0x00, 0x00, 0x00, 0x0e, 0x0c } }, /* OP Mode Set RTTY LSB-N */ { 1, { 0x00, 0x00, 0x00, 0x0f, 0x0c } }, /* OP Mode Set RTTY USB-N */ { 1, { 0x00, 0x00, 0x00, 0x00, 0x0f } }, /* PTT (OFF) */ { 1, { 0x00, 0x00, 0x00, 0x01, 0x0f } }, /* PTT (ON) */ { 1, { 0x00, 0x00, 0x00, 0x01, 0x10 } }, /* Update Memory Ch Number */ { 1, { 0x00, 0x00, 0x00, 0x02, 0x10 } }, /* Update Op Data */ { 1, { 0x00, 0x00, 0x00, 0x03, 0x10 } }, /* Update VFO Data */ { 1, { 0x00, 0x00, 0x00, 0x00, 0x18 } }, /* Set TX power low */ { 1, { 0x00, 0x00, 0x00, 0x00, 0x28 } }, /* Set TX power mid */ { 1, { 0x00, 0x00, 0x00, 0x00, 0x48 } }, /* Set TX power hi */ { 1, { 0x00, 0x00, 0x00, 0x00, 0x85 } }, /* Copy RX to TX */ { 0, { 0x00, 0x00, 0x00, 0x00, 0x8a } }, /* Set TX Freq only */ { 1, { 0x00, 0x00, 0x00, 0x00, 0x8e } }, /* Step Operating Frequency Up */ { 1, { 0x00, 0x00, 0x00, 0x01, 0x8e } }, /* Step Operating Frequency Down */ { 1, { 0x00, 0x00, 0x00, 0x00, 0xf7 } }, /* Read Meter */ { 1, { 0x00, 0x00, 0x00, 0x00, 0xfa } }, /* Read Status Flags */ }; /* * Private data */ struct vx1700_priv_data{ unsigned char ch; /* memory channel */ }; /* * vx1700 rigs capabilities. */ #define VX1700_MEM_CAP { \ .freq = 1, \ .tx_freq = 1, \ .mode = 1, \ .width = 1, \ } const struct rig_caps vx1700_caps = { .rig_model = RIG_MODEL_VX1700, .model_name = "VX-1700", .mfg_name = "Vertex Standard", .version = "1.1", .copyright = "LGPL", .status = RIG_STATUS_ALPHA, .rig_type = RIG_TYPE_TRANSCEIVER, .ptt_type = RIG_PTT_RIG_MICDATA, .dcd_type = RIG_DCD_NONE, /* we have DCD pin in DATA Jack, but get_dcd() is unavailable (yet?) */ .port_type = RIG_PORT_SERIAL, .serial_rate_min = 4800, .serial_rate_max = 4800, .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 = 600, .retry = 3, .has_get_func = (RIG_FUNC_LOCK|RIG_FUNC_TUNER), .has_set_func = RIG_FUNC_NONE, .has_get_level = RIG_LEVEL_NONE, .has_set_level = RIG_LEVEL_RFPOWER, .has_get_parm = RIG_PARM_NONE, .has_set_parm = RIG_PARM_NONE, .level_gran = { [LVL_RFPOWER] = { .min = { .i = 0 }, .max = { .i = 2 } }, }, .parm_gran = {}, .preamp = { RIG_DBLST_END }, .attenuator = { RIG_DBLST_END }, .max_rit = Hz(0), .max_xit = Hz(0), .max_ifshift = Hz(0), .vfo_ops = VX1700_VFO_OPS, .targetable_vfo = 0, .transceive = RIG_TRN_OFF, .bank_qty = 0, .chan_desc_sz = 0, .chan_list = { { VX1700_MIN_CHANNEL, VX1700_MAX_CHANNEL, RIG_MTYPE_MEM, VX1700_MEM_CAP }, RIG_CHAN_END }, .rx_range_list1 = { { kHz(30), MHz(30), VX1700_MODES, -1, -1, VX1700_VFO_ALL, VX1700_ANTS }, RIG_FRNG_END, }, .tx_range_list1 = { { kHz(1600), MHz(4)-1, VX1700_MODES, W(31), W(125), VX1700_VFO_ALL, VX1700_ANTS }, { kHz(4000), MHz(30), VX1700_MODES, W(25), W(100), VX1700_VFO_ALL, VX1700_ANTS }, RIG_FRNG_END, }, .rx_range_list2 = { { kHz(30), MHz(30), VX1700_MODES, -1, -1, VX1700_VFO_ALL, VX1700_ANTS }, RIG_FRNG_END, }, .tx_range_list2 = { { kHz(1600), MHz(4)-1, VX1700_MODES, W(31), W(125), VX1700_VFO_ALL, VX1700_ANTS }, { kHz(4000), MHz(30), VX1700_MODES, W(25), W(100), VX1700_VFO_ALL, VX1700_ANTS }, RIG_FRNG_END, }, .tuning_steps = { { VX1700_MODES, 100 }, RIG_TS_END, }, /* mode/filter list, remember: order matters! */ .filters = { { RIG_MODE_AM, VX1700_FILTER_WIDTH_AM }, { RIG_MODE_SSB, VX1700_FILTER_WIDTH_SSB }, { RIG_MODE_CW | RIG_MODE_RTTY | RIG_MODE_RTTYR, VX1700_FILTER_WIDTH_WIDE }, { RIG_MODE_CW | RIG_MODE_RTTY | RIG_MODE_RTTYR, VX1700_FILTER_WIDTH_NARROW }, RIG_FLT_END, }, .priv = NULL, .rig_init = vx1700_init, .rig_open = vx1700_open, .rig_cleanup = vx1700_cleanup, .set_vfo = vx1700_set_vfo, .get_vfo = vx1700_get_vfo, .set_freq = vx1700_set_freq, .get_freq = vx1700_get_freq, .set_split_freq = vx1700_set_split_freq, .get_split_freq = vx1700_get_split_freq, .set_mode = vx1700_set_mode, .get_mode = vx1700_get_mode, .get_ptt = vx1700_get_ptt, .set_ptt = vx1700_set_ptt, .get_info = vx1700_get_info, .set_func = vx1700_set_func, .get_func = vx1700_get_func, .set_level = vx1700_set_level, .get_level = vx1700_get_level, .set_mem = vx1700_set_mem, .get_mem = vx1700_get_mem, .vfo_op = vx1700_vfo_op, }; static inline freq_t vx1700_read_freq_from_buf(const unsigned char p[]){ /* WARNING: documentation bug, actually frequency stored in bytes 0..2 only, byte 3 is not used and contain zero */ return ((((((unsigned)p[0]) << 8) + p[1]) << 8) + p[2]) * 10.0; } static inline int vx1700_channel_is_ok(unsigned char channel){ return ((channel >= VX1700_MIN_CHANNEL) && (channel <= VX1700_MAX_CHANNEL)) ? 1 : 0; } /* * Function definitions below */ static int vx1700_do_transaction(RIG *rig, const unsigned char cmd[YAESU_CMD_LENGTH], unsigned char *retbuf, size_t retbuf_len){ struct rig_state *rs; unsigned char default_retbuf[1]; int retval; if (retbuf == NULL){ retbuf = default_retbuf; retbuf_len = sizeof(default_retbuf); } rs = &rig->state; memset(retbuf, 0, retbuf_len); serial_flush(&rs->rigport); retval = write_block(&rs->rigport, (const char*)cmd, YAESU_CMD_LENGTH); if (retval != RIG_OK) return retval; retval = read_block(&rs->rigport, (char*)retbuf, retbuf_len); if (retval != retbuf_len){ if ((retval == 1) && (retbuf[0] == VX1700_CMD_RETCODE_ERROR)) return -RIG_ERJCTED; return -RIG_EIO; } if (retval == 1){ if ((cmd[4] == VX1700_CMD_UPDATE) && (cmd[3] == 0x01)){ /* read memory channel number */ if (vx1700_channel_is_ok(retbuf[0] + 1)){ /* WARNING: Documentation bug, actually we got 0--199 for channels 1--200 */ return RIG_OK; } if (retbuf[0] == VX1700_CMD_RETCODE_ERROR) return -RIG_ERJCTED; return -RIG_EIO; } if (retbuf[0] == VX1700_CMD_RETCODE_OK) return RIG_OK; if (retbuf[0] == VX1700_CMD_RETCODE_ERROR) return -RIG_ERJCTED; return -RIG_EIO; } return RIG_OK; } /* * Private helper function to send a complete command sequence. * * TODO: place variant of this in yaesu.c * * Arguments: *rig Valid RIG instance * ci Command index of the ncmd struct * * Returns: RIG_OK if all called functions are successful, * otherwise returns error from called functiion */ static int vx1700_do_static_cmd(RIG *rig, unsigned char ci){ if (rig == NULL) return -RIG_EINVAL; if ( ! ncmd[ci].ncomp){ rig_debug(RIG_DEBUG_TRACE, "%s: Attempt to send incomplete sequence\n", __func__); return -RIG_EINVAL; } return vx1700_do_transaction(rig, ncmd[ci].nseq, NULL, 0); } /* * Private helper function to build and then send a complete command * sequence. * * TODO: place variant of this in yaesu.c * * Arguments: *rig Valid RIG instance * ci Command index of the ncmd struct * p1-p4 Command parameters * * Returns: RIG_OK if all called functions are successful, * otherwise returns error from called functiion */ static int vx1700_do_dynamic_cmd(RIG *rig, unsigned char ci, unsigned char p1, unsigned char p2, unsigned char p3, unsigned char p4){ unsigned char cmd[YAESU_CMD_LENGTH]; if (rig == NULL) return -RIG_EINVAL; if (ncmd[ci].ncomp){ rig_debug(RIG_DEBUG_TRACE, "%s: Attempt to modify complete sequence\n", __func__); return -RIG_EINVAL; } memcpy(&cmd, &ncmd[ci].nseq, YAESU_CMD_LENGTH); cmd[3] = p1; cmd[2] = p2; cmd[1] = p3; cmd[0] = p4; return vx1700_do_transaction(rig, cmd, NULL, 0); } static int vx1700_do_freq_cmd(RIG *rig, unsigned char ci, freq_t freq){ unsigned char cmd[YAESU_CMD_LENGTH]; if (rig == NULL) return -RIG_EINVAL; if ((ci != VX1700_NATIVE_FREQ_SET) && (ci != VX1700_NATIVE_TX_FREQ_SET)){ rig_debug(RIG_DEBUG_TRACE, "%s: Attempt to use non freqency sequence\n", __func__); return -RIG_EINVAL; } memcpy(&cmd, &ncmd[ci].nseq, YAESU_CMD_LENGTH); to_bcd(cmd, freq / 10, VX1700_BCD_DIAL); return vx1700_do_transaction(rig, cmd, NULL, 0); } static inline int vx1700_read_mem_channel_number(RIG *rig, unsigned char *channel){ int ret; unsigned char reply[VX1700_MEM_CHNL_LENGTH]; ret = vx1700_do_transaction(rig, ncmd[VX1700_NATIVE_UPDATE_MEM_CHNL].nseq, reply, VX1700_MEM_CHNL_LENGTH); if (ret == -RIG_ERJCTED){ /* we are on VFO mode, so memory channel is not available at the moment */ *channel = VX1700_MIN_CHANNEL - 1; return RIG_OK; } if (ret != RIG_OK) return ret; /* WARNING: Documentation bug, actually we got 0--199 for channels 1--200 */ *channel = VX1700_MIN_CHANNEL + reply[0]; return RIG_OK; } static inline int vx1700_read_status_flags(RIG *rig, unsigned char reply[]){ if (rig == NULL) return -RIG_EINVAL; return vx1700_do_transaction(rig, ncmd[VX1700_NATIVE_READ_FLAGS].nseq, reply, VX1700_STATUS_FLAGS_LENGTH); } static inline int vx1700_read_meter(RIG *rig, unsigned char reply[]){ if (rig == NULL) return -RIG_EINVAL; return vx1700_do_transaction(rig, ncmd[VX1700_NATIVE_READ_METER].nseq, reply, VX1700_READ_METER_LENGTH); } static inline int vx1700_read_vfo_data_raw(RIG *rig, unsigned char reply[]){ if (rig == NULL) return -RIG_EINVAL; return vx1700_do_transaction(rig, ncmd[VX1700_NATIVE_UPDATE_VFO_DATA].nseq, reply, VX1700_VFO_DATA_LENGTH); } static inline int vx1700_read_op_data_raw(RIG *rig, unsigned char reply[]){ if (rig == NULL) return -RIG_EINVAL; return vx1700_do_transaction(rig, ncmd[VX1700_NATIVE_UPDATE_OP_DATA].nseq, reply, VX1700_OP_DATA_LENGTH); } #if 0 /* unused; re-enabled as needed. */ static int vx1700_read_vfo_data(RIG *rig, unsigned char *hwmode, freq_t *rx_freq, freq_t *tx_freq){ int ret; unsigned char reply[VX1700_VFO_DATA_LENGTH]; if ((ret = vx1700_read_vfo_data_raw(rig, reply)) != RIG_OK) return ret; if (hwmode != NULL) *hwmode = reply[6]; if (rx_freq != NULL) *rx_freq = vx1700_read_freq_from_buf(reply + 1); if (tx_freq != NULL) *tx_freq = vx1700_read_freq_from_buf(reply + 10); return RIG_OK; } #endif /* unused */ static int vx1700_read_op_data(RIG *rig, unsigned char *hwmode, freq_t *rx_freq, freq_t *tx_freq){ int ret; unsigned char reply[VX1700_OP_DATA_LENGTH]; if ((ret = vx1700_read_op_data_raw(rig, reply)) != RIG_OK) return ret; if (hwmode != NULL) *hwmode = reply[7]; if (rx_freq != NULL) *rx_freq = vx1700_read_freq_from_buf(reply + 2); if (tx_freq != NULL) *tx_freq = vx1700_read_freq_from_buf(reply + 11); return RIG_OK; } static const char* vx1700_get_hwmode_str(unsigned char hwmode){ switch(hwmode){ case VX1700_MODE_AM: return "AM (A3E)"; case VX1700_MODE_LSB: return "LSB (J3E)"; case VX1700_MODE_USB: return "USB (J3E)"; case VX1700_MODE_CW_W: return "CW (A1A-W)"; case VX1700_MODE_CW_N: return "CW (A1A-N)"; case VX1700_MODE_RTTY: return "RTTY[R] (J2B)"; default: return "unknown"; } } static void vx1700_parse_vfo_data(const char *func, const unsigned char buf[VX1700_VFO_DATA_LENGTH]){ rig_debug(RIG_DEBUG_TRACE, "%s: vfo-data: rx.band_data=0x%02d\n", func, buf[0]); rig_debug(RIG_DEBUG_TRACE, "%s: vfo-data: rx.freq=%f\n", func, vx1700_read_freq_from_buf(buf + 1)); rig_debug(RIG_DEBUG_TRACE, "%s: vfo-data: rx.mode=0x%02d, %s\n", func, buf[6], vx1700_get_hwmode_str(buf[6])); rig_debug(RIG_DEBUG_TRACE, "%s: vfo-data: tx.band_data=0x%02d\n", func, buf[9]); rig_debug(RIG_DEBUG_TRACE, "%s: vfo-data: tx.freq=%f\n", func, vx1700_read_freq_from_buf(buf + 10)); rig_debug(RIG_DEBUG_TRACE, "%s: vfo-data: tx.mode=0x%02d, %s\n", func, buf[15], vx1700_get_hwmode_str(buf[15])); } static void vx1700_parse_op_data(const char *func, const unsigned char buf[VX1700_OP_DATA_LENGTH]){ rig_debug(RIG_DEBUG_TRACE, "%s: op-data: Semi Duplex Memory Channel: %s\n", func, (buf[0] & 0x20) ? "yes" : "no"); rig_debug(RIG_DEBUG_TRACE, "%s: op-data: Alpha Numeric Channel: %s\n", func, (buf[0] & 0x40) ? "yes" : "no"); rig_debug(RIG_DEBUG_TRACE, "%s: op-data: Erased Memory Channel: %s\n", func, (buf[0] & 0x80) ? "yes" : "no"); rig_debug(RIG_DEBUG_TRACE, "%s: op-data: rx.band_data=0x%02d\n", func, buf[1]); rig_debug(RIG_DEBUG_TRACE, "%s: op-data: rx.freq=%f\n", func, vx1700_read_freq_from_buf(buf + 2)); rig_debug(RIG_DEBUG_TRACE, "%s: op-data: rx.mode=0x%02d, %s\n", func, buf[7], vx1700_get_hwmode_str(buf[7])); rig_debug(RIG_DEBUG_TRACE, "%s: op-data: tx.band_data=0x%02d\n", func, buf[10]); rig_debug(RIG_DEBUG_TRACE, "%s: op-data: tx.freq=%f\n", func, vx1700_read_freq_from_buf(buf + 11)); rig_debug(RIG_DEBUG_TRACE, "%s: op-data: tx.mode=0x%02d, %s\n", func, buf[16], vx1700_get_hwmode_str(buf[16])); } static void vx1700_parse_status_flags(const char *func, const unsigned char buf[VX1700_STATUS_FLAGS_LENGTH]){ rig_debug(RIG_DEBUG_TRACE, "%s: flags: Lock: %s\n", func, (buf[0] & VX1700_SF_LOCKED) ? "yes" : "no"); rig_debug(RIG_DEBUG_TRACE, "%s: flags: Memory Mode: %s\n", func, (buf[0] & VX1700_SF_MEM) ? "yes" : "no"); rig_debug(RIG_DEBUG_TRACE, "%s: flags: VFO Mode: %s\n", func, (buf[0] & VX1700_SF_VFO) ? "yes" : "no"); rig_debug(RIG_DEBUG_TRACE, "%s: flags: PTT closed by CAT: %s\n", func, (buf[1] & VX1700_SF_PTT_BY_CAT) ? "yes" : "no"); rig_debug(RIG_DEBUG_TRACE, "%s: flags: Scanning paused: %s\n", func, (buf[1] & VX1700_SF_MEM_SCAN_PAUSE) ? "yes" : "no"); rig_debug(RIG_DEBUG_TRACE, "%s: flags: Scanning enabled: %s\n", func, (buf[1] & VX1700_SF_MEM_SCAN) ? "yes" : "no"); rig_debug(RIG_DEBUG_TRACE, "%s: flags: Narrow RTTY filter: %s\n", func, (buf[1] & VX1700_SF_RTTY_FILTER_NARROW) ? "yes" : "no"); rig_debug(RIG_DEBUG_TRACE, "%s: flags: Narrow CW filter: %s\n", func, (buf[1] & VX1700_SF_CW_FILTER_NARROW) ? "yes" : "no"); rig_debug(RIG_DEBUG_TRACE, "%s: flags: USB for RTTY: %s\n", func, (buf[1] & VX1700_SF_RTTY_USB) ? "yes" : "no"); rig_debug(RIG_DEBUG_TRACE, "%s: flags: 10 Watt TX output: %s\n", func, (buf[2] & VX1700_SF_10W_TX) ? "yes" : "no"); rig_debug(RIG_DEBUG_TRACE, "%s: flags: Antenna Tuner: %s\n", func, (buf[2] & VX1700_SF_TUNER_ON) ? "on" : "off"); rig_debug(RIG_DEBUG_TRACE, "%s: flags: Transmission: %s\n", func, (buf[2] & VX1700_SF_TRANSMISSION_ON) ? "yes" : "no"); rig_debug(RIG_DEBUG_TRACE, "%s: flags: end bytes (0x06, 0x04): 0x%02x, 0x%02x\n", func, buf[3], buf[4]); } static void vx1700_parse_meter(const char *func, const unsigned char buf[VX1700_READ_METER_LENGTH]){ rig_debug(RIG_DEBUG_TRACE, "%s: meter: data: 0x%02x, 0x%02x, 0x%02x, 0x%02x\n", __func__, buf[0], buf[1], buf[2], buf[3]); rig_debug(RIG_DEBUG_TRACE, "%s: meter: end byte (0xF7): 0x%02x\n", __func__, buf[4]); } static void dump_radio_state(RIG *rig){ unsigned char channel = 0; unsigned char reply[VX1700_OP_DATA_LENGTH]; int ret; if (rig == NULL) return; if ((ret = vx1700_read_mem_channel_number(rig, &channel)) != RIG_OK) return; if (vx1700_channel_is_ok(channel)) rig_debug(RIG_DEBUG_TRACE, "%s: Current Memory Channel %d\n", __func__, (int)channel); else rig_debug(RIG_DEBUG_TRACE, "%s: Memory Channel number is not available at the moment\n", __func__); if ((ret = vx1700_read_op_data_raw(rig, reply)) != RIG_OK) return; vx1700_parse_op_data(__func__, reply); if ((ret = vx1700_read_vfo_data_raw(rig, reply)) != RIG_OK) return; vx1700_parse_vfo_data(__func__, reply); if ((ret = vx1700_read_status_flags(rig, reply)) != RIG_OK) return; vx1700_parse_status_flags(__func__, reply); if ((ret = vx1700_read_meter(rig, reply)) != RIG_OK) return; vx1700_parse_meter(__func__, reply); } static int vx1700_init(RIG *rig){ struct vx1700_priv_data *priv; rig_debug(RIG_DEBUG_TRACE, "%s\n", __func__); priv = malloc(sizeof(struct vx1700_priv_data)); if (priv == NULL) return -RIG_ENOMEM; memset(priv, 0, sizeof(struct vx1700_priv_data)); priv->ch = 1; rig->state.priv = (rig_ptr_t)priv; return RIG_OK; } static int vx1700_open(RIG *rig){ struct vx1700_priv_data *priv = (struct vx1700_priv_data *)rig->state.priv; struct rig_state *state = &rig->state; int ret; rig_debug(RIG_DEBUG_TRACE, "%s\n", __func__); if ((ret = vx1700_get_vfo(rig, &state->current_vfo)) != RIG_OK) return ret; if ((ret = vx1700_get_mode(rig, RIG_VFO_CURR, &state->current_mode, &state->current_width)) != RIG_OK) return ret; if ((ret = vx1700_read_op_data(rig, NULL, &state->current_freq, NULL)) != RIG_OK) return ret; if ((ret = vx1700_read_mem_channel_number(rig, &priv->ch)) != RIG_OK) return ret; return RIG_OK; } static int vx1700_cleanup(RIG *rig){ rig_debug(RIG_DEBUG_TRACE, "%s\n", __func__); if (rig->state.priv != NULL) free(rig->state.priv); rig->state.priv = NULL; return RIG_OK; } static const char * vx1700_get_info(RIG *rig){ rig_debug(RIG_DEBUG_TRACE, "%s\n", __func__); dump_radio_state(rig); return "NO_INFO"; } static int vx1700_set_vfo(RIG *rig, vfo_t vfo){ struct vx1700_priv_data *priv = (struct vx1700_priv_data *)rig->state.priv; rig_debug(RIG_DEBUG_TRACE, "%s, vfo=%d\n", __func__, vfo); switch(vfo){ case RIG_VFO_CURR: return RIG_OK; case RIG_VFO_VFO: case RIG_VFO_A: return vx1700_do_static_cmd(rig, VX1700_NATIVE_VFO_A); case RIG_VFO_MEM: return vx1700_do_dynamic_cmd(rig, VX1700_NATIVE_RECALL_MEM, priv->ch, 0, 0, 0); default: return -RIG_EINVAL; } } static int vx1700_get_vfo(RIG *rig, vfo_t *vfo){ int ret; unsigned char reply[VX1700_STATUS_FLAGS_LENGTH]; rig_debug(RIG_DEBUG_TRACE, "%s\n", __func__); if ((ret = vx1700_read_status_flags(rig, reply)) != RIG_OK) return ret; *vfo = (reply[0] & VX1700_SF_MEM) ? RIG_VFO_MEM : RIG_VFO_A; return RIG_OK; } static int vx1700_set_freq(RIG *rig, vfo_t vfo, freq_t freq){ (void) vfo; rig_debug(RIG_DEBUG_TRACE, "%s: freq=%f\n", __func__, freq); return vx1700_do_freq_cmd(rig, VX1700_NATIVE_FREQ_SET, freq); } static int vx1700_get_freq(RIG *rig, vfo_t vfo, freq_t *freq){ (void) vfo; return vx1700_read_op_data(rig, NULL, freq, NULL); } static int vx1700_set_split_freq(RIG *rig, vfo_t vfo, freq_t tx_freq){ (void) vfo; rig_debug(RIG_DEBUG_TRACE, "%s: freq=%f\n", __func__, tx_freq); return vx1700_do_freq_cmd(rig, VX1700_NATIVE_TX_FREQ_SET, tx_freq); } static int vx1700_get_split_freq(RIG *rig, vfo_t vfo, freq_t *tx_freq){ (void) vfo; rig_debug(RIG_DEBUG_TRACE, "%s\n", __func__); return vx1700_read_op_data(rig, NULL, NULL, tx_freq); } static int vx1700_set_mode(RIG *rig, vfo_t vfo, rmode_t mode, pbwidth_t width){ (void) rig; (void) vfo; rig_debug(RIG_DEBUG_TRACE, "%s: mode=0x%04x, width=%d\n", __func__, (int) mode, (int) width); if (width == RIG_PASSBAND_NORMAL) width = rig_passband_normal(rig, mode); switch(mode){ case RIG_MODE_AM: return vx1700_do_static_cmd(rig, VX1700_NATIVE_MODE_SET_AM); case RIG_MODE_LSB: return vx1700_do_static_cmd(rig, VX1700_NATIVE_MODE_SET_LSB); case RIG_MODE_USB: return vx1700_do_static_cmd(rig, VX1700_NATIVE_MODE_SET_USB); case RIG_MODE_CW: if (width > (VX1700_FILTER_WIDTH_NARROW + VX1700_FILTER_WIDTH_WIDE) / 2) return vx1700_do_static_cmd(rig, VX1700_NATIVE_MODE_SET_CW_W); else return vx1700_do_static_cmd(rig, VX1700_NATIVE_MODE_SET_CW_N); case RIG_MODE_RTTY: if (width > (VX1700_FILTER_WIDTH_NARROW + VX1700_FILTER_WIDTH_WIDE) / 2) return vx1700_do_static_cmd(rig, VX1700_NATIVE_MODE_SET_RTTY_LSB_W); else return vx1700_do_static_cmd(rig, VX1700_NATIVE_MODE_SET_RTTY_LSB_N); case RIG_MODE_RTTYR: if (width > (VX1700_FILTER_WIDTH_NARROW + VX1700_FILTER_WIDTH_WIDE) / 2) return vx1700_do_static_cmd(rig, VX1700_NATIVE_MODE_SET_RTTY_USB_W); else return vx1700_do_static_cmd(rig, VX1700_NATIVE_MODE_SET_RTTY_USB_N); default: return -RIG_EINVAL; } } static int vx1700_get_mode(RIG *rig, vfo_t vfo, rmode_t *mode, pbwidth_t *width){ int ret; unsigned char hwmode; unsigned char reply[VX1700_STATUS_FLAGS_LENGTH]; (void) rig; (void) vfo; rig_debug(RIG_DEBUG_TRACE, "%s\n", __func__); if ((ret = vx1700_read_op_data(rig, &hwmode, NULL, NULL)) != RIG_OK) return ret; switch(hwmode){ case VX1700_MODE_AM: *mode = RIG_MODE_AM; *width = VX1700_FILTER_WIDTH_AM; return RIG_OK; case VX1700_MODE_LSB: *mode = RIG_MODE_LSB; *width = VX1700_FILTER_WIDTH_SSB; return RIG_OK; case VX1700_MODE_USB: *mode = RIG_MODE_USB; *width = VX1700_FILTER_WIDTH_SSB; return RIG_OK; case VX1700_MODE_CW_W: *mode = RIG_MODE_CW; *width = VX1700_FILTER_WIDTH_WIDE; return RIG_OK; case VX1700_MODE_CW_N: *mode = RIG_MODE_CW; *width = VX1700_FILTER_WIDTH_NARROW; return RIG_OK; case VX1700_MODE_RTTY: if ((ret = vx1700_read_status_flags(rig, reply)) != RIG_OK) return ret; *mode = (reply[1] & VX1700_SF_RTTY_USB) ? RIG_MODE_RTTYR : RIG_MODE_RTTY; *width = (reply[1] & VX1700_SF_RTTY_FILTER_NARROW) ? VX1700_FILTER_WIDTH_NARROW : VX1700_FILTER_WIDTH_WIDE; return RIG_OK; default: return -RIG_EPROTO; } } static int vx1700_set_ptt_gps_jack(ptt_t ptt){ (void) ptt; /* * FIXME * * We are using GPIO to manage PTT pin in GPS/Data jack. * This highly binded to our specific device, so it makes * no sense to put our code here. * On regular PC this should be managed in another way, * probably via DTR/RTS. */ return -RIG_EINVAL; } static int vx1700_set_ptt(RIG *rig, vfo_t vfo, ptt_t ptt){ rmode_t mode; pbwidth_t width; int ret; unsigned char reply[VX1700_STATUS_FLAGS_LENGTH]; rig_debug(RIG_DEBUG_TRACE, "%s, ptt=%d\n", __func__, ptt); /* * We have 3 PTT source on Vertex Standard VX-1700: * 1) ptt on radio garniture (not checked, FIXME) * 2) PTT commands inside CAT operation protocol * - select radio garniture as audio input/output source * - does not work in RTTY/RTTYR modes * 3) PTT pin in GPS/Data jack * - select GPS/Data jack as input/output source * - does not work in CW/AM modes */ if ((ret = vx1700_get_mode(rig, vfo, &mode, &width)) != RIG_OK) return ret; switch(mode){ case RIG_MODE_AM: case RIG_MODE_CW: switch(ptt){ case RIG_PTT_ON: case RIG_PTT_ON_MIC: return vx1700_do_static_cmd(rig, VX1700_NATIVE_PTT_ON); case RIG_PTT_OFF: return vx1700_do_static_cmd(rig, VX1700_NATIVE_PTT_OFF); default: return -RIG_EINVAL; } case RIG_MODE_LSB: case RIG_MODE_USB: switch(ptt){ case RIG_PTT_ON: case RIG_PTT_ON_MIC: return vx1700_do_static_cmd(rig, VX1700_NATIVE_PTT_ON); case RIG_PTT_ON_DATA: return vx1700_set_ptt_gps_jack(RIG_PTT_ON); case RIG_PTT_OFF: if ((ret = vx1700_read_status_flags(rig, reply)) != RIG_OK) return ret; if (reply[1] & VX1700_SF_PTT_BY_CAT){ /* PTT was turned on by CAT command, turn it off accordingly */ return vx1700_do_static_cmd(rig, VX1700_NATIVE_PTT_OFF); } /* PTT was turned on via special pin on GPS/DATA jack */ return vx1700_set_ptt_gps_jack(RIG_PTT_OFF); default: return -RIG_EINVAL; } case RIG_MODE_RTTY: case RIG_MODE_RTTYR: switch(ptt){ case RIG_PTT_ON: case RIG_PTT_ON_DATA: return vx1700_set_ptt_gps_jack(RIG_PTT_ON); case RIG_PTT_OFF: return vx1700_set_ptt_gps_jack(RIG_PTT_OFF); default: return -RIG_EINVAL; } default: return -RIG_EINVAL; } } static int vx1700_get_ptt(RIG *rig, vfo_t vfo, ptt_t *ptt){ int ret; unsigned char reply[VX1700_STATUS_FLAGS_LENGTH]; rig_debug(RIG_DEBUG_TRACE, "%s\n", __func__); if ((ret = vx1700_read_status_flags(rig, reply)) != RIG_OK) return ret; *ptt = (reply[2] & VX1700_SF_TRANSMISSION_ON) ? RIG_PTT_ON : RIG_PTT_OFF; return RIG_OK; } static int vx1700_set_func(RIG *rig, vfo_t vfo, setting_t func, int status){ (void) rig; (void) vfo; rig_debug(RIG_DEBUG_TRACE, "%s: func=0x%04x, status=%d\n", __func__, func, status); return -RIG_EINVAL; } static int vx1700_get_func(RIG *rig, vfo_t vfo, setting_t func, int *status){ int ret; unsigned char reply[VX1700_STATUS_FLAGS_LENGTH]; (void) rig; (void) vfo; rig_debug(RIG_DEBUG_TRACE, "%s: func=0x%04x\n", __func__, func); switch(func){ case RIG_FUNC_LOCK: if ((ret = vx1700_read_status_flags(rig, reply)) != RIG_OK) return ret; *status = (reply[0] & VX1700_SF_LOCKED) ? 1 : 0; return RIG_OK; case RIG_FUNC_TUNER: if ((ret = vx1700_read_status_flags(rig, reply)) != RIG_OK) return ret; *status = (reply[2] & VX1700_SF_TUNER_ON) ? 1 : 0; return RIG_OK; default: return -RIG_EINVAL; } } static int vx1700_set_level(RIG *rig, vfo_t vfo, setting_t level, value_t val){ (void) rig; (void) vfo; rig_debug(RIG_DEBUG_TRACE, "%s: level=0x%04x, val=???\n", __func__, level); switch(level){ case RIG_LEVEL_RFPOWER: if ((val.f < 0.0) || (val.f > 1.0)) return -RIG_EINVAL; if (val.f < (1.0 / 3.0)) return vx1700_do_static_cmd(rig, VX1700_NATIVE_TX_POWER_LOW); if (val.f < (2.0 / 3.0)) return vx1700_do_static_cmd(rig, VX1700_NATIVE_TX_POWER_MID); return vx1700_do_static_cmd(rig, VX1700_NATIVE_TX_POWER_HI); default: return -RIG_EINVAL; } } static int vx1700_get_level(RIG *rig, vfo_t vfo, setting_t level, value_t *val){ (void) rig; (void) vfo; rig_debug(RIG_DEBUG_TRACE, "%s: level=0x%04x\n", __func__, level); return -RIG_EINVAL; } static int vx1700_set_mem(RIG *rig, vfo_t vfo, int ch){ struct vx1700_priv_data *priv = (struct vx1700_priv_data *)rig->state.priv; struct rig_state *state = &rig->state; int ret; if ( ! vx1700_channel_is_ok(ch)) return -RIG_EINVAL; if (vfo == RIG_VFO_CURR) vfo = state->current_vfo; if (vfo == RIG_VFO_MEM){ ret = vx1700_do_dynamic_cmd(rig, VX1700_NATIVE_RECALL_MEM, ch, 0, 0, 0); if (ret == RIG_OK) priv->ch = ch; return ret; } priv->ch = ch; return RIG_OK; } static int vx1700_get_mem(RIG *rig, vfo_t vfo, int *ch){ struct vx1700_priv_data *priv = (struct vx1700_priv_data *)rig->state.priv; struct rig_state *state = &rig->state; unsigned char channel = 0; int ret; if (vfo == RIG_VFO_CURR) vfo = state->current_vfo; if (vfo == RIG_VFO_MEM){ ret = vx1700_read_mem_channel_number(rig, &channel); if (ret != RIG_OK) return ret; if (vx1700_channel_is_ok(channel)){ *ch = priv->ch = channel; return RIG_OK; } return -RIG_ERJCTED; } if ( ! vx1700_channel_is_ok(priv->ch)) return -RIG_ERJCTED; *ch = priv->ch; return RIG_OK; } static int vx1700_vfo_op(RIG *rig, vfo_t vfo, vfo_op_t op){ struct vx1700_priv_data *priv = (struct vx1700_priv_data *)rig->state.priv; (void) rig; (void) vfo; rig_debug(RIG_DEBUG_TRACE, "%s: op=0x%04x\n", __func__, (int) op); switch(op){ case RIG_OP_TO_VFO: return vx1700_do_dynamic_cmd(rig, VX1700_NATIVE_RECALL_MEM, priv->ch, 0, 0, 0); case RIG_OP_FROM_VFO: return vx1700_do_dynamic_cmd(rig, VX1700_NATIVE_VFO_TO_MEM, priv->ch, 0, 0, 0); case RIG_OP_UP: return vx1700_do_static_cmd(rig, VX1700_NATIVE_OP_FREQ_STEP_UP); case RIG_OP_DOWN: return vx1700_do_static_cmd(rig, VX1700_NATIVE_OP_FREQ_STEP_DOWN); default: return -RIG_EINVAL; } }