diff --git a/yaesu/Makefile.am b/yaesu/Makefile.am index 8a9453999..153a1fc8f 100644 --- a/yaesu/Makefile.am +++ b/yaesu/Makefile.am @@ -1,5 +1,5 @@ YAESUSRC = ft100.c ft747.c ft817.c ft847.c ft890.c ft900.c ft920.c \ - ft1000mp.c ft857.c ft990.c + ft1000mp.c ft857.c ft897.c ft990.c lib_LTLIBRARIES = hamlib-yaesu.la hamlib_yaesu_la_SOURCES = $(YAESUSRC) yaesu.c @@ -8,4 +8,4 @@ hamlib_yaesu_la_LIBADD = $(top_builddir)/lib/libmisc.la \ $(top_builddir)/src/libhamlib.la noinst_HEADERS = ft100.h ft747.h ft817.h ft847.h ft890.h ft900.h ft920.h \ - ft1000mp.h ft857.h ft990.h yaesu.h yaesu_tones.h + ft1000mp.h ft857.h ft897.h ft990.h yaesu.h yaesu_tones.h diff --git a/yaesu/ft897.c b/yaesu/ft897.c new file mode 100644 index 000000000..1b48bcf41 --- /dev/null +++ b/yaesu/ft897.c @@ -0,0 +1,934 @@ +/* -*- mode: c; c-basic-offset: 2; indent-tabs-mode: nil; -*- + * + * ft897.h - (C) Tomi Manninen 2003 (oh2bns@sral.fi) + * + * ...derived but heavily modified from: + * + * ft817.h - (C) Chris Karpinsky 2001 (aa1vl@arrl.net) + * + * This shared library provides an API for communicating + * via serial interface to an FT-897 using the "CAT" interface. + * The starting point for this code was Frank's ft847 implementation. + * + * + * $Id: ft897.c,v 1.1 2004-02-08 17:08:46 fillods Exp $ + * + * + * 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 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +/* + * Unimplemented features supported by the FT-897: + * + * - RIT ON/OFF without touching the RIT offset. This would + * need frontend support (eg. a new RIG_FUNC_xxx) + * + * - VFO A/B toggle. Needs frontend support (RIG_FUNC_xxx) + * + * - Split ON/OFF. Maybe some sort of split operation could + * be supported with this and the above??? + * + * - DCS encoder/squelch ON/OFF, similar to RIG_FUNC_TONE/TSQL. + * Needs frontend support. + * + * - RX status command returns info that is not used: + * + * - discriminator centered (yes/no flag) + * - received ctcss/dcs matched (yes/no flag) + * + * - TX status command returns info that is not used: + * + * - split on/off flag + * - high swr flag + * + * The manual also indicates that CTCSS and DCS codes can be set + * separately for tx and rx, but this doesn't seem to work. It + * doesn't work from front panel either. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include /* String function definitions */ +#include /* UNIX standard function definitions */ + +#include "hamlib/rig.h" +#include "serial.h" +#include "yaesu.h" +#include "ft897.h" +#include "misc.h" +#include "tones.h" +#include "bandplan.h" + +/* Native ft897 cmd set prototypes. These are READ ONLY as each */ +/* rig instance will copy from these and modify if required . */ +/* Complete sequences (1) can be read and used directly as a cmd sequence . */ +/* Incomplete sequences (0) must be completed with extra parameters */ +/* eg: mem number, or freq etc.. */ + +static const yaesu_cmd_set_t ncmd[] = { + { 1, { 0x00, 0x00, 0x00, 0x00, 0x00 } }, /* lock on */ + { 1, { 0x00, 0x00, 0x00, 0x00, 0x80 } }, /* lock off */ + { 1, { 0x00, 0x00, 0x00, 0x00, 0x08 } }, /* ptt on */ + { 1, { 0x00, 0x00, 0x00, 0x01, 0x88 } }, /* ptt off */ + { 0, { 0x00, 0x00, 0x00, 0x00, 0x01 } }, /* set freq */ + { 1, { 0x00, 0x00, 0x00, 0x00, 0x07 } }, /* mode set main LSB */ + { 1, { 0x01, 0x00, 0x00, 0x00, 0x07 } }, /* mode set main USB */ + { 1, { 0x02, 0x00, 0x00, 0x00, 0x07 } }, /* mode set main CW */ + { 1, { 0x03, 0x00, 0x00, 0x00, 0x07 } }, /* mode set main CWR */ + { 1, { 0x04, 0x00, 0x00, 0x00, 0x07 } }, /* mode set main AM */ + { 1, { 0x08, 0x00, 0x00, 0x00, 0x07 } }, /* mode set main FM */ + { 1, { 0x88, 0x00, 0x00, 0x00, 0x07 } }, /* mode set main FM-N */ + { 1, { 0x0a, 0x00, 0x00, 0x00, 0x07 } }, /* mode set main DIG */ + { 1, { 0x0c, 0x00, 0x00, 0x00, 0x07 } }, /* mode set main PKT */ + { 1, { 0x00, 0x00, 0x00, 0x00, 0x05 } }, /* clar on */ + { 1, { 0x00, 0x00, 0x00, 0x00, 0x85 } }, /* clar off */ + { 0, { 0x00, 0x00, 0x00, 0x00, 0xf5 } }, /* set clar freq */ + { 1, { 0x00, 0x00, 0x00, 0x00, 0x81 } }, /* toggle vfo a/b */ + { 1, { 0x00, 0x00, 0x00, 0x00, 0x02 } }, /* split on */ + { 1, { 0x00, 0x00, 0x00, 0x00, 0x82 } }, /* split off */ + { 1, { 0x09, 0x00, 0x00, 0x00, 0x09 } }, /* set RPT shift MINUS */ + { 1, { 0x49, 0x00, 0x00, 0x00, 0x09 } }, /* set RPT shift PLUS */ + { 1, { 0x89, 0x00, 0x00, 0x00, 0x09 } }, /* set RPT shift SIMPLEX */ + { 0, { 0x00, 0x00, 0x00, 0x00, 0xf9 } }, /* set RPT offset freq */ + { 1, { 0x0a, 0x00, 0x00, 0x00, 0x0a } }, /* set DCS on */ + { 1, { 0x0b, 0x00, 0x00, 0x00, 0x0a } }, /* set DCS decoder on */ + { 1, { 0x0c, 0x00, 0x00, 0x00, 0x0a } }, /* set DCS encoder on */ + { 1, { 0x2a, 0x00, 0x00, 0x00, 0x0a } }, /* set CTCSS on */ + { 1, { 0x3a, 0x00, 0x00, 0x00, 0x0a } }, /* set CTCSS decoder on */ + { 1, { 0x4a, 0x00, 0x00, 0x00, 0x0a } }, /* set CTCSS encoder on */ + { 1, { 0x8a, 0x00, 0x00, 0x00, 0x0a } }, /* set CTCSS/DCS off */ + { 0, { 0x00, 0x00, 0x00, 0x00, 0x0b } }, /* set CTCSS tone */ + { 0, { 0x00, 0x00, 0x00, 0x00, 0x0c } }, /* set DCS code */ + { 1, { 0x00, 0x00, 0x00, 0x00, 0xe7 } }, /* get RX status */ + { 1, { 0x00, 0x00, 0x00, 0x00, 0xf7 } }, /* get TX status */ + { 1, { 0x00, 0x00, 0x00, 0x00, 0x03 } }, /* get FREQ and MODE status */ + { 1, { 0x00, 0x00, 0x00, 0x00, 0x00 } }, /* pwr wakeup sequence */ + { 1, { 0x00, 0x00, 0x00, 0x00, 0x0f } }, /* pwr on */ + { 1, { 0x00, 0x00, 0x00, 0x00, 0x8f } }, /* pwr off */ +}; + + +#define FT897_ALL_RX_MODES (RIG_MODE_AM|RIG_MODE_CW|RIG_MODE_USB|\ + RIG_MODE_LSB|RIG_MODE_RTTY|RIG_MODE_FM) +#define FT897_SSB_CW_RX_MODES (RIG_MODE_CW|RIG_MODE_USB|RIG_MODE_LSB) +#define FT897_AM_FM_RX_MODES (RIG_MODE_AM|RIG_MODE_FM) + +#define FT897_OTHER_TX_MODES (RIG_MODE_AM|RIG_MODE_CW|RIG_MODE_USB|\ + RIG_MODE_LSB|RIG_MODE_RTTY|RIG_MODE_FM) +#define FT897_AM_TX_MODES (RIG_MODE_AM) + +#define FT897_VFO_ALL (RIG_VFO_A|RIG_VFO_B) +#define FT897_ANTS 0 + +const struct rig_caps ft897_caps = { + .rig_model = RIG_MODEL_FT897, + .model_name = "FT-897", + .mfg_name = "Yaesu", + .version = "0.1", + .copyright = "LGPL", + .status = RIG_STATUS_ALPHA, + .rig_type = RIG_TYPE_TRANSCEIVER, + .ptt_type = RIG_PTT_RIG, + .dcd_type = RIG_DCD_RIG, + .port_type = RIG_PORT_SERIAL, + .serial_rate_min = 4800, + .serial_rate_max = 38400, + .serial_data_bits = 8, + .serial_stop_bits = 2, + .serial_parity = RIG_PARITY_NONE, + .serial_handshake = RIG_HANDSHAKE_NONE, + .write_delay = FT897_WRITE_DELAY, + .post_write_delay = FT897_POST_WRITE_DELAY, + .timeout = FT897_TIMEOUT, + .retry = 0, + .has_get_func = RIG_FUNC_NONE, + .has_set_func = RIG_FUNC_LOCK | RIG_FUNC_TONE | RIG_FUNC_TSQL, + .has_get_level = RIG_LEVEL_STRENGTH | RIG_LEVEL_RFPOWER | RIG_LEVEL_SQLSTAT, + .has_set_level = RIG_LEVEL_NONE, + .has_get_parm = RIG_PARM_NONE, + .has_set_parm = RIG_PARM_NONE, + .level_gran = {}, /* granularity */ + .parm_gran = {}, + .ctcss_list = static_common_ctcss_list, + .dcs_list = static_full_dcs_list, /* FIXME: only 104 supported */ + .preamp = { RIG_DBLST_END, }, + .attenuator = { RIG_DBLST_END, }, + .max_rit = Hz(9990), + .max_xit = Hz(0), + .max_ifshift = Hz(0), + .targetable_vfo = 0, + .transceive = RIG_TRN_OFF, + .bank_qty = 0, + .chan_desc_sz = 0, + .chan_list = { RIG_CHAN_END, }, + + .rx_range_list1 = { + {kHz(100),MHz(56), FT897_ALL_RX_MODES,-1,-1}, + {MHz(76), MHz(108),RIG_MODE_WFM, -1,-1}, + {MHz(118),MHz(164),FT897_ALL_RX_MODES,-1,-1}, + {MHz(420),MHz(470),FT897_ALL_RX_MODES,-1,-1}, + RIG_FRNG_END, + }, + .tx_range_list1 = { + FRQ_RNG_HF(1,FT897_OTHER_TX_MODES, W(10),W(100),FT897_VFO_ALL,FT897_ANTS), + /* AM class */ + FRQ_RNG_HF(1,FT897_AM_TX_MODES, W(2.5),W(25),FT897_VFO_ALL,FT897_ANTS), + FRQ_RNG_2m(1,FT897_OTHER_TX_MODES, W(5),W(50),FT897_VFO_ALL,FT897_ANTS), + /* AM class */ + FRQ_RNG_2m(1,FT897_AM_TX_MODES, W(2.5),W(25),FT897_VFO_ALL,FT897_ANTS), + FRQ_RNG_70cm(1,FT897_OTHER_TX_MODES, W(2),W(20),FT897_VFO_ALL,FT897_ANTS), + /* AM class */ + FRQ_RNG_70cm(1,FT897_AM_TX_MODES, W(0.5),W(5),FT897_VFO_ALL,FT897_ANTS), + RIG_FRNG_END, + }, + + + .rx_range_list2 = { + {kHz(100),MHz(56), FT897_ALL_RX_MODES,-1,-1}, + {MHz(76), MHz(108),RIG_MODE_WFM, -1,-1}, + {MHz(118),MHz(164),FT897_ALL_RX_MODES,-1,-1}, + {MHz(420),MHz(470),FT897_ALL_RX_MODES,-1,-1}, + RIG_FRNG_END, + }, + .tx_range_list2 = { + FRQ_RNG_HF(2,FT897_OTHER_TX_MODES, W(10),W(100),FT897_VFO_ALL,FT897_ANTS), + /* AM class */ + FRQ_RNG_HF(2,FT897_AM_TX_MODES, W(2.5),W(25),FT897_VFO_ALL,FT897_ANTS), + FRQ_RNG_2m(2,FT897_OTHER_TX_MODES, W(5),W(50),FT897_VFO_ALL,FT897_ANTS), + /* AM class */ + FRQ_RNG_2m(2,FT897_AM_TX_MODES, W(2.5),W(25),FT897_VFO_ALL,FT897_ANTS), + FRQ_RNG_70cm(2,FT897_OTHER_TX_MODES, W(2),W(20),FT897_VFO_ALL,FT897_ANTS), + /* AM class */ + FRQ_RNG_70cm(2,FT897_AM_TX_MODES, W(0.5),W(5),FT897_VFO_ALL,FT897_ANTS), + RIG_FRNG_END, + }, + + .tuning_steps = { + {FT897_SSB_CW_RX_MODES,10}, + {FT897_SSB_CW_RX_MODES,100}, + {FT897_AM_FM_RX_MODES,10}, + {FT897_AM_FM_RX_MODES,100}, + RIG_TS_END, + }, + + .filters = { + RIG_FLT_END, + }, + + .priv = NULL, + .rig_init = ft897_init, + .rig_cleanup = ft897_cleanup, + .rig_open = ft897_open, + .rig_close = ft897_close, + .set_freq = ft897_set_freq, + .get_freq = ft897_get_freq, + .set_mode = ft897_set_mode, + .get_mode = ft897_get_mode, + .set_vfo = NULL, + .get_vfo = NULL, + .set_ptt = ft897_set_ptt, + .get_ptt = ft897_get_ptt, + .get_dcd = ft897_get_dcd, + .set_rptr_shift = ft897_set_rptr_shift, + .get_rptr_shift = NULL, + .set_rptr_offs = ft897_set_rptr_offs, + .get_rptr_offs = NULL, + .set_split_freq = NULL, + .get_split_freq = NULL, + .set_split_mode = NULL, + .get_split_mode = NULL, + .set_split_vfo = NULL, + .get_split_vfo = NULL, + .set_rit = ft897_set_rit, + .get_rit = NULL, + .set_xit = NULL, + .get_xit = NULL, + .set_ts = NULL, + .get_ts = NULL, + .set_dcs_code = ft897_set_dcs_code, + .get_dcs_code = NULL, + .set_ctcss_tone = ft897_set_ctcss_tone, + .get_ctcss_tone = NULL, + .set_dcs_sql = ft897_set_dcs_sql, + .get_dcs_sql = NULL, + .set_ctcss_sql = ft897_set_ctcss_sql, + .get_ctcss_sql = NULL, + .set_powerstat = NULL, + .get_powerstat = NULL, + .reset = NULL, + .set_ant = NULL, + .get_ant = NULL, + .set_level = NULL, + .get_level = ft897_get_level, + .set_func = ft897_set_func, + .get_func = NULL, + .set_parm = NULL, + .get_parm = NULL, +}; + +/* ---------------------------------------------------------------------- */ + +int ft897_init(RIG *rig) +{ + struct ft897_priv_data *p; + + rig_debug(RIG_DEBUG_VERBOSE,"ft897:ft897_init called \n"); + + if ((p = calloc(1, sizeof(struct ft897_priv_data))) == NULL) + return -RIG_ENOMEM; + + /* Copy complete native cmd set to private cmd storage area */ + memcpy(p->pcs, ncmd, sizeof(ncmd)); + + rig->state.priv = (void*) p; + + return RIG_OK; +} + +int ft897_cleanup(RIG *rig) +{ + rig_debug(RIG_DEBUG_VERBOSE,"ft897:ft897_cleanup called \n"); + + if (rig->state.priv) + free(rig->state.priv); + rig->state.priv = NULL; + + return RIG_OK; +} + +int ft897_open(RIG *rig) +{ + rig_debug(RIG_DEBUG_VERBOSE,"ft897:ft897_open called \n"); + + return RIG_OK; +} + +int ft897_close(RIG *rig) +{ + rig_debug(RIG_DEBUG_VERBOSE,"ft897:ft897_close called \n"); + + return RIG_OK; +} + +/* ---------------------------------------------------------------------- */ + +static inline long timediff(struct timeval *tv1, struct timeval *tv2) +{ + struct timeval tv; + + tv.tv_usec = tv1->tv_usec - tv2->tv_usec; + tv.tv_sec = tv1->tv_sec - tv2->tv_sec; + + return ((tv.tv_sec * 1000L) + (tv.tv_usec / 1000L)); +} + +static int check_cache_timeout(struct timeval *tv) +{ + struct timeval curr; + long t; + + if (tv->tv_sec == 0 && tv->tv_usec == 0) { + rig_debug(RIG_DEBUG_VERBOSE, "ft897: cache invalid\n"); + return 1; + } + + gettimeofday(&curr, NULL); + + if ((t = timediff(&curr, tv)) < FT897_CACHE_TIMEOUT) { + rig_debug(RIG_DEBUG_VERBOSE, "ft897: using cache (%ld ms)\n", t); + return 0; + } else { + rig_debug(RIG_DEBUG_VERBOSE, "ft897: cache timed out (%ld ms)\n", t); + return 1; + } +} + +static int ft897_get_status(RIG *rig, int status) +{ + struct ft897_priv_data *p = (struct ft897_priv_data *) rig->state.priv; + struct timeval *tv; + unsigned char *data; + int len; + int n; + + switch (status) { + case FT897_NATIVE_CAT_GET_FREQ_MODE_STATUS: + data = p->fm_status; + len = YAESU_CMD_LENGTH; + tv = &p->fm_status_tv; + break; + case FT897_NATIVE_CAT_GET_RX_STATUS: + data = &p->rx_status; + len = 1; + tv = &p->rx_status_tv; + break; + case FT897_NATIVE_CAT_GET_TX_STATUS: + data = &p->tx_status; + len = 1; + tv = &p->tx_status_tv; + break; + default: + rig_debug(RIG_DEBUG_ERR, "ft897_get_status: Internal error!\n"); + return RIG_EINTERNAL; + } + + serial_flush(&rig->state.rigport); + + write_block(&rig->state.rigport, p->pcs[status].nseq, YAESU_CMD_LENGTH); + + if ((n = read_block(&rig->state.rigport, data, len)) < 0) + return n; + + if (n != len) + return -RIG_EIO; + + gettimeofday(tv, NULL); + + return RIG_OK; +} + +/* ---------------------------------------------------------------------- */ + +int ft897_get_freq(RIG *rig, vfo_t vfo, freq_t *freq) +{ + struct ft897_priv_data *p = (struct ft897_priv_data *) rig->state.priv; + int n; + + if (vfo != RIG_VFO_CURR) + return -RIG_ENTARGET; + + if (check_cache_timeout(&p->fm_status_tv)) + if ((n = ft897_get_status(rig, FT897_NATIVE_CAT_GET_FREQ_MODE_STATUS)) < 0) + return n; + + *freq = from_bcd_be(p->fm_status, 8) * 10; + + return -RIG_OK; +} + +int ft897_get_mode(RIG *rig, vfo_t vfo, rmode_t *mode, pbwidth_t *width) +{ + struct ft897_priv_data *p = (struct ft897_priv_data *) rig->state.priv; + int n; + + if (vfo != RIG_VFO_CURR) + return -RIG_ENTARGET; + + if (check_cache_timeout(&p->fm_status_tv)) + if ((n = ft897_get_status(rig, FT897_NATIVE_CAT_GET_FREQ_MODE_STATUS)) < 0) + return n; + + switch (p->fm_status[4]) { + case 0x00: + *mode = RIG_MODE_LSB; + break; + case 0x01: + *mode = RIG_MODE_USB; + break; + case 0x02: + *mode = RIG_MODE_CW; + break; + case 0x03: + *mode = RIG_MODE_CWR; + break; + case 0x04: + *mode = RIG_MODE_AM; + break; + case 0x06: + *mode = RIG_MODE_WFM; + break; + case 0x08: + *mode = RIG_MODE_FM; + break; + case 0x0a: + *mode = RIG_MODE_RTTY; + break; + default: + *mode = RIG_MODE_NONE; + } + + *width = RIG_PASSBAND_NORMAL; + + return RIG_OK; +} + +int ft897_get_ptt(RIG *rig, vfo_t vfo, ptt_t *ptt) +{ + struct ft897_priv_data *p = (struct ft897_priv_data *) rig->state.priv; + int n; + + if (vfo != RIG_VFO_CURR) + return -RIG_ENTARGET; + + if (check_cache_timeout(&p->tx_status_tv)) + if ((n = ft897_get_status(rig, FT897_NATIVE_CAT_GET_TX_STATUS)) < 0) + return n; + + *ptt = ((p->tx_status & 0x80) == 0); + + return RIG_OK; +} + +static int ft897_get_pometer_level(RIG *rig, value_t *val) +{ + struct ft897_priv_data *p = (struct ft897_priv_data *) rig->state.priv; + int n; + + if (check_cache_timeout(&p->tx_status_tv)) + if ((n = ft897_get_status(rig, FT897_NATIVE_CAT_GET_TX_STATUS)) < 0) + return n; + + /* Valid only if PTT is on */ + if ((p->tx_status & 0x80) == 0) + val->f = ((p->tx_status & 0x0F) / 15.0); + else + val->f = 0.0; + + return RIG_OK; +} + +static int ft897_get_smeter_level(RIG *rig, value_t *val) +{ + struct ft897_priv_data *p = (struct ft897_priv_data *) rig->state.priv; + int n; + + if (check_cache_timeout(&p->rx_status_tv)) + if ((n = ft897_get_status(rig, FT897_NATIVE_CAT_GET_RX_STATUS)) < 0) + return n; + + n = (p->rx_status & 0x0F) - 9; + + val->i = n * ((n > 0) ? 10 : 6); + + return RIG_OK; +} + +int ft897_get_level(RIG *rig, vfo_t vfo, setting_t level, value_t *val) +{ + dcd_t dcd; + int n; + + if (vfo != RIG_VFO_CURR) + return -RIG_ENTARGET; + + switch (level) { + case RIG_LEVEL_STRENGTH: + return ft897_get_smeter_level(rig, val); + + case RIG_LEVEL_RFPOWER: + return ft897_get_pometer_level(rig, val); + + case RIG_LEVEL_SQLSTAT: + if ((n = ft897_get_dcd(rig, vfo, &dcd)) < 0) + return n; + val->i = dcd; + break; + + default: + return -RIG_EINVAL; + } + + return RIG_OK; +} + +int ft897_get_dcd(RIG *rig, vfo_t vfo, dcd_t *dcd) +{ + struct ft897_priv_data *p = (struct ft897_priv_data *) rig->state.priv; + int n; + + if (vfo != RIG_VFO_CURR) + return -RIG_ENTARGET; + + if (check_cache_timeout(&p->rx_status_tv)) + if ((n = ft897_get_status(rig, FT897_NATIVE_CAT_GET_RX_STATUS)) < 0) + return n; + + /* TODO: consider bit 6 too ??? (CTCSS/DCS code match) */ + if (p->rx_status & 0x80) + *dcd = RIG_DCD_OFF; + else + *dcd = RIG_DCD_ON; + + return RIG_OK; +} + +/* ---------------------------------------------------------------------- */ + +static int ft897_read_ack(RIG *rig) +{ +#if (FT897_POST_WRITE_DELAY == 0) + unsigned char dummy; + int n; + + if ((n = read_block(&rig->state.rigport, &dummy, 1)) < 0) { + rig_debug(RIG_DEBUG_ERR, "ft897: error reading ack\n"); + return n; + } + + rig_debug(RIG_DEBUG_TRACE,"ft897: ack received (%d)\n", dummy); + + if (dummy != 0) + return -RIG_ERJCTED; +#endif + + return RIG_OK; +} + +/* + * private helper function to send a private command sequence. + * Must only be complete sequences. + */ +static int ft897_send_cmd(RIG *rig, int index) +{ + struct ft897_priv_data *p = (struct ft897_priv_data *) rig->state.priv; + + if (p->pcs[index].ncomp == 0) { + rig_debug(RIG_DEBUG_VERBOSE, "ft897: Incomplete sequence\n"); + return -RIG_EINTERNAL; + } + + write_block(&rig->state.rigport, p->pcs[index].nseq, YAESU_CMD_LENGTH); + return ft897_read_ack(rig); +} + +/* + * The same for incomplete commands. + */ +static int ft897_send_icmd(RIG *rig, int index, unsigned char *data) +{ + struct ft897_priv_data *p = (struct ft897_priv_data *) rig->state.priv; + unsigned char cmd[YAESU_CMD_LENGTH]; + + if (p->pcs[index].ncomp == 1) { + rig_debug(RIG_DEBUG_VERBOSE, "ft897: Complete sequence\n"); + return -RIG_EINTERNAL; + } + + cmd[YAESU_CMD_LENGTH - 1] = p->pcs[index].nseq[YAESU_CMD_LENGTH - 1]; + memcpy(cmd, data, YAESU_CMD_LENGTH - 1); + + write_block(&rig->state.rigport, cmd, YAESU_CMD_LENGTH); + return ft897_read_ack(rig); +} + +/* ---------------------------------------------------------------------- */ + +int ft897_set_freq(RIG *rig, vfo_t vfo, freq_t freq) +{ + unsigned char data[YAESU_CMD_LENGTH - 1]; + + if (vfo != RIG_VFO_CURR) + return -RIG_ENTARGET; + + rig_debug(RIG_DEBUG_VERBOSE,"ft897: requested freq = %lli Hz\n", freq); + + /* fill in the frequency */ + to_bcd_be(data, (freq + 5) / 10, 8); + + return ft897_send_icmd(rig, FT897_NATIVE_CAT_SET_FREQ, data); +} + +int ft897_set_mode(RIG *rig, vfo_t vfo, rmode_t mode, pbwidth_t width) +{ + int index; /* index of sequence to send */ + + if (vfo != RIG_VFO_CURR) + return -RIG_ENTARGET; + + rig_debug(RIG_DEBUG_VERBOSE,"ft897: generic mode = %x \n", mode); + + switch(mode) { + case RIG_MODE_AM: + index = FT897_NATIVE_CAT_SET_MODE_AM; + break; + case RIG_MODE_CW: + index = FT897_NATIVE_CAT_SET_MODE_CW; + break; + case RIG_MODE_USB: + index = FT897_NATIVE_CAT_SET_MODE_USB; + break; + case RIG_MODE_LSB: + index = FT897_NATIVE_CAT_SET_MODE_LSB; + break; + case RIG_MODE_RTTY: + index = FT897_NATIVE_CAT_SET_MODE_DIG; + break; + case RIG_MODE_FM: + index = FT897_NATIVE_CAT_SET_MODE_FM; + break; + case RIG_MODE_WFM: + index = FT897_NATIVE_CAT_SET_MODE_FM; + break; + case RIG_MODE_CWR: + index = FT897_NATIVE_CAT_SET_MODE_CWR; + break; + default: + return -RIG_EINVAL; + } + + if (width != RIG_PASSBAND_NORMAL) + return -RIG_EINVAL; + + return ft897_send_cmd(rig, index); +} + +int ft897_set_ptt(RIG *rig, vfo_t vfo, ptt_t ptt) +{ + int index, n; + + if (vfo != RIG_VFO_CURR) + return -RIG_ENTARGET; + + rig_debug(RIG_DEBUG_VERBOSE, "ft897: ft897_set_ptt called\n"); + + switch(ptt) { + case RIG_PTT_ON: + index = FT897_NATIVE_CAT_PTT_ON; + break; + case RIG_PTT_OFF: + index = FT897_NATIVE_CAT_PTT_OFF; + break; + default: + return -RIG_EINVAL; + } + + n = ft897_send_cmd(rig, index); + + if (n < 0 && n != -RIG_ERJCTED) + return n; + + return RIG_OK; +} + +int ft897_set_func(RIG *rig, vfo_t vfo, setting_t func, int status) +{ + if (vfo != RIG_VFO_CURR) + return -RIG_ENTARGET; + + switch (func) { + case RIG_FUNC_LOCK: + if (status) + return ft897_send_cmd(rig, FT897_NATIVE_CAT_LOCK_ON); + else + return ft897_send_cmd(rig, FT897_NATIVE_CAT_LOCK_OFF); + + case RIG_FUNC_TONE: + if (status) + return ft897_send_cmd(rig, FT897_NATIVE_CAT_SET_CTCSS_ENC_ON); + else + return ft897_send_cmd(rig, FT897_NATIVE_CAT_SET_CTCSS_DCS_OFF); + + case RIG_FUNC_TSQL: + if (status) + return ft897_send_cmd(rig, FT897_NATIVE_CAT_SET_CTCSS_ON); + else + return ft897_send_cmd(rig, FT897_NATIVE_CAT_SET_CTCSS_DCS_OFF); + +#if 0 + case RIG_FUNC_CODE: /* this doesn't exist */ + if (status) + return ft897_send_cmd(rig, FT897_NATIVE_CAT_SET_DCS_ENC_ON); + else + return ft897_send_cmd(rig, FT897_NATIVE_CAT_SET_CTCSS_DCS_OFF); + + case RIG_FUNC_DSQL: /* this doesn't exist */ + if (status) + return ft897_send_cmd(rig, FT897_NATIVE_CAT_SET_DCS_ON); + else + return ft897_send_cmd(rig, FT897_NATIVE_CAT_SET_CTCSS_DCS_OFF); +#endif + + default: + return -RIG_EINVAL; + } +} + +int ft897_set_dcs_code(RIG *rig, vfo_t vfo, tone_t code) +{ + unsigned char data[YAESU_CMD_LENGTH - 1]; + int n; + + if (vfo != RIG_VFO_CURR) + return -RIG_ENTARGET; + + rig_debug(RIG_DEBUG_VERBOSE, "ft897: set DCS code (%d)\n", code); + + if (code == 0) + return ft897_send_cmd(rig, FT897_NATIVE_CAT_SET_CTCSS_DCS_OFF); + + /* fill in the DCS code - the rig doesn't support separate codes... */ + to_bcd_be(data, code, 4); + to_bcd_be(data + 2, code, 4); + + if ((n = ft897_send_icmd(rig, FT897_NATIVE_CAT_SET_DCS_CODE, data)) < 0) + return n; + + return ft897_send_cmd(rig, FT897_NATIVE_CAT_SET_DCS_ENC_ON); +} + +int ft897_set_ctcss_tone(RIG *rig, vfo_t vfo, tone_t tone) +{ + unsigned char data[YAESU_CMD_LENGTH - 1]; + int n; + + if (vfo != RIG_VFO_CURR) + return -RIG_ENTARGET; + + rig_debug(RIG_DEBUG_VERBOSE, "ft897: set CTCSS tone (%.1f)\n", tone / 10.0); + + if (tone == 0) + return ft897_send_cmd(rig, FT897_NATIVE_CAT_SET_CTCSS_DCS_OFF); + + /* fill in the CTCSS freq - the rig doesn't support separate tones... */ + to_bcd_be(data, tone, 4); + to_bcd_be(data + 2, tone, 4); + + if ((n = ft897_send_icmd(rig, FT897_NATIVE_CAT_SET_CTCSS_FREQ, data)) < 0) + return n; + + return ft897_send_cmd(rig, FT897_NATIVE_CAT_SET_CTCSS_ENC_ON); +} + +int ft897_set_dcs_sql(RIG *rig, vfo_t vfo, tone_t code) +{ + unsigned char data[YAESU_CMD_LENGTH - 1]; + int n; + + if (vfo != RIG_VFO_CURR) + return -RIG_ENTARGET; + + rig_debug(RIG_DEBUG_VERBOSE, "ft897: set DCS sql (%d)\n", code); + + if (code == 0) + return ft897_send_cmd(rig, FT897_NATIVE_CAT_SET_CTCSS_DCS_OFF); + + /* fill in the DCS code - the rig doesn't support separate codes... */ + to_bcd_be(data, code, 4); + to_bcd_be(data + 2, code, 4); + + if ((n = ft897_send_icmd(rig, FT897_NATIVE_CAT_SET_DCS_CODE, data)) < 0) + return n; + + return ft897_send_cmd(rig, FT897_NATIVE_CAT_SET_DCS_ON); +} + +int ft897_set_ctcss_sql(RIG *rig, vfo_t vfo, tone_t tone) +{ + unsigned char data[YAESU_CMD_LENGTH - 1]; + int n; + + if (vfo != RIG_VFO_CURR) + return -RIG_ENTARGET; + + rig_debug(RIG_DEBUG_VERBOSE, "ft897: set CTCSS sql (%.1f)\n", tone / 10.0); + + if (tone == 0) + return ft897_send_cmd(rig, FT897_NATIVE_CAT_SET_CTCSS_DCS_OFF); + + /* fill in the CTCSS freq - the rig doesn't support separate tones... */ + to_bcd_be(data, tone, 4); + to_bcd_be(data + 2, tone, 4); + + if ((n = ft897_send_icmd(rig, FT897_NATIVE_CAT_SET_CTCSS_FREQ, data)) < 0) + return n; + + return ft897_send_cmd(rig, FT897_NATIVE_CAT_SET_CTCSS_ON); +} + +int ft897_set_rptr_shift(RIG *rig, vfo_t vfo, rptr_shift_t shift) +{ + if (vfo != RIG_VFO_CURR) + return -RIG_ENTARGET; + + rig_debug(RIG_DEBUG_VERBOSE, "ft897: set repeter shift = %i\n", shift); + + switch (shift) { + case RIG_RPT_SHIFT_NONE: + return ft897_send_cmd(rig, FT897_NATIVE_CAT_SET_RPT_SHIFT_SIMPLEX); + case RIG_RPT_SHIFT_MINUS: + return ft897_send_cmd(rig, FT897_NATIVE_CAT_SET_RPT_SHIFT_MINUS); + case RIG_RPT_SHIFT_PLUS: + return ft897_send_cmd(rig, FT897_NATIVE_CAT_SET_RPT_SHIFT_PLUS); + } + + return -RIG_EINVAL; +} + +int ft897_set_rptr_offs(RIG *rig, vfo_t vfo, shortfreq_t offs) +{ + unsigned char data[YAESU_CMD_LENGTH - 1]; + + if (vfo != RIG_VFO_CURR) + return -RIG_ENTARGET; + + rig_debug(RIG_DEBUG_VERBOSE, "ft897: set repeter offs = %li\n", offs); + + /* fill in the offset freq */ + to_bcd_be(data, offs / 10, 8); + + return ft897_send_icmd(rig, FT897_NATIVE_CAT_SET_RPT_OFFSET, data); +} + +int ft897_set_rit(RIG *rig, vfo_t vfo, shortfreq_t rit) +{ + unsigned char data[YAESU_CMD_LENGTH - 1]; + int n; + + if (vfo != RIG_VFO_CURR) + return -RIG_ENTARGET; + + rig_debug(RIG_DEBUG_VERBOSE, "ft897: set rit = %li)\n", rit); + + /* fill in the RIT freq */ + data[0] = (rit < 0) ? 255 : 0; + data[1] = 0; + to_bcd_be(data + 2, labs(rit) / 10, 4); + + if ((n = ft897_send_icmd(rig, FT897_NATIVE_CAT_SET_CLAR_FREQ, data)) < 0) + return n; + + /* the rig rejects if these are repeated - don't confuse user with retcode */ + if (rit == 0) + ft897_send_cmd(rig, FT897_NATIVE_CAT_CLAR_OFF); + else + ft897_send_cmd(rig, FT897_NATIVE_CAT_CLAR_ON); + + return RIG_OK; +} + +#if 0 +/* + * This doesn't seem to work on FT897. It might work with FT817 though. + */ +int ft897_set_powerstat(RIG *rig, powerstat_t status) +{ + switch (status) { + case RIG_POWER_OFF: + return ft897_send_cmd(rig, FT897_NATIVE_CAT_PWR_OFF); + case RIG_POWER_ON: + return ft897_send_cmd(rig, FT897_NATIVE_CAT_PWR_ON); + case RIG_POWER_STANDBY: + default: + return -RIG_EINVAL; + } +} +#endif + +/* ---------------------------------------------------------------------- */ + diff --git a/yaesu/ft897.h b/yaesu/ft897.h new file mode 100644 index 000000000..d4e8b146d --- /dev/null +++ b/yaesu/ft897.h @@ -0,0 +1,166 @@ +/* + * ft897.h - (C) Tomi Manninen 2003 (oh2bns@sral.fi) + * + * ...derived but heavily modified from: + * + * ft817.h - (C) Chris Karpinsky 2001 (aa1vl@arrl.net) + * + * This shared library provides an API for communicating + * via serial interface to an FT-817 using the "CAT" interface. + * The starting point for this code was Frank's ft847 implementation. + * + * + * $Id: ft897.h,v 1.1 2004-02-08 17:08:46 fillods Exp $ + * + * + * 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 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#ifndef _FT897_H +#define _FT897_H 1 + +/* + * No need to wait between written characters. + */ +#define FT897_WRITE_DELAY 0 + +/* + * Wait 'delay' milliseconds after writing a command sequence. + * + * Setting this to zero means no delay but wait for an acknowledgement + * from the rig after a command. This is undocumented but seems to work. + * It's also the most optimal way as long as it works... + * + * A non-zero value disables waiting for the ack. Processing a command + * seems to take about 60 ms so set this to 80 or so to be safe. + */ +#define FT897_POST_WRITE_DELAY 0 + +/* + * Read timeout. + */ +#define FT897_TIMEOUT 200 + +/* + * The time the TX, RX and FREQ/MODE status are cached (in millisec). + * This optimises the common case of doing eg. rig_get_freq() and + * rig_get_mode() in a row. + * + * The timeout is deliberately set lower than the time taken to process + * a single command (~ 60 ms) so that a sequence + * + * rig_get_freq(); + * rig_set_freq(); + * rig_get_freq(); + * + * doesn't return a bogus (cached) value in the last rig_get_freq(). + */ +#define FT897_CACHE_TIMEOUT 50 + + +enum ft897_native_cmd_e { + FT897_NATIVE_CAT_LOCK_ON = 0, + FT897_NATIVE_CAT_LOCK_OFF, + FT897_NATIVE_CAT_PTT_ON, + FT897_NATIVE_CAT_PTT_OFF, + FT897_NATIVE_CAT_SET_FREQ, + FT897_NATIVE_CAT_SET_MODE_LSB, + FT897_NATIVE_CAT_SET_MODE_USB, + FT897_NATIVE_CAT_SET_MODE_CW, + FT897_NATIVE_CAT_SET_MODE_CWR, + FT897_NATIVE_CAT_SET_MODE_AM, + FT897_NATIVE_CAT_SET_MODE_FM, + FT897_NATIVE_CAT_SET_MODE_FM_N, + FT897_NATIVE_CAT_SET_MODE_DIG, + FT897_NATIVE_CAT_SET_MODE_PKT, + FT897_NATIVE_CAT_CLAR_ON, + FT897_NATIVE_CAT_CLAR_OFF, + FT897_NATIVE_CAT_SET_CLAR_FREQ, + FT897_NATIVE_CAT_SET_VFOAB, + FT897_NATIVE_CAT_SPLIT_ON, + FT897_NATIVE_CAT_SPLIT_OFF, + FT897_NATIVE_CAT_SET_RPT_SHIFT_MINUS, + FT897_NATIVE_CAT_SET_RPT_SHIFT_PLUS, + FT897_NATIVE_CAT_SET_RPT_SHIFT_SIMPLEX, + FT897_NATIVE_CAT_SET_RPT_OFFSET, + FT897_NATIVE_CAT_SET_DCS_ON, + FT897_NATIVE_CAT_SET_DCS_DEC_ON, + FT897_NATIVE_CAT_SET_DCS_ENC_ON, + FT897_NATIVE_CAT_SET_CTCSS_ON, + FT897_NATIVE_CAT_SET_CTCSS_DEC_ON, + FT897_NATIVE_CAT_SET_CTCSS_ENC_ON, + FT897_NATIVE_CAT_SET_CTCSS_DCS_OFF, + FT897_NATIVE_CAT_SET_CTCSS_FREQ, + FT897_NATIVE_CAT_SET_DCS_CODE, + FT897_NATIVE_CAT_GET_RX_STATUS, + FT897_NATIVE_CAT_GET_TX_STATUS, + FT897_NATIVE_CAT_GET_FREQ_MODE_STATUS, + FT897_NATIVE_CAT_PWR_WAKE, + FT897_NATIVE_CAT_PWR_ON, + FT897_NATIVE_CAT_PWR_OFF, + FT897_NATIVE_SIZE /* end marker */ +}; + + +typedef enum ft897_native_cmd_e ft897_native_cmd_t; + + +struct ft897_priv_data { + yaesu_cmd_set_t pcs[FT897_NATIVE_SIZE]; /* TODO: why? */ + + /* rx status */ + struct timeval rx_status_tv; + unsigned char rx_status; + + /* tx status */ + struct timeval tx_status_tv; + unsigned char tx_status; + + /* freq & mode status */ + struct timeval fm_status_tv; + unsigned char fm_status[YAESU_CMD_LENGTH]; +}; + + +int ft897_init(RIG *rig); +int ft897_open(RIG *rig); +int ft897_cleanup(RIG *rig); +int ft897_close(RIG *rig); +int ft897_set_freq(RIG *rig, vfo_t vfo, freq_t freq); +int ft897_get_freq(RIG *rig, vfo_t vfo, freq_t *freq); +int ft897_set_mode(RIG *rig, vfo_t vfo, rmode_t mode, pbwidth_t width); +int ft897_get_mode(RIG *rig, vfo_t vfo, rmode_t *mode, pbwidth_t *width); +// int ft897_set_vfo(RIG *rig, vfo_t vfo); +// int ft897_get_vfo(RIG *rig, vfo_t *vfo); +int ft897_set_ptt(RIG *rig, vfo_t vfo, ptt_t ptt); +int ft897_get_ptt(RIG *rig, vfo_t vfo, ptt_t *ptt); +// int ft897_set_level(RIG *rig, vfo_t vfo, setting_t level, value_t val); +int ft897_get_level(RIG *rig, vfo_t vfo, setting_t level, value_t *val); +int ft897_set_func(RIG *rig, vfo_t vfo, setting_t func, int status); +// int ft897_get_func(RIG *rig, vfo_t vfo, setting_t func, int *status); +// int ft897_set_parm(RIG *rig, setting_t parm, value_t val); +// int ft897_get_parm(RIG *rig, setting_t parm, value_t *val); +int ft897_set_dcs_code(RIG *rig, vfo_t vfo, tone_t code); +int ft897_set_ctcss_tone(RIG *rig, vfo_t vfo, tone_t code); +int ft897_set_dcs_sql(RIG *rig, vfo_t vfo, tone_t code); +int ft897_set_ctcss_sql(RIG *rig, vfo_t vfo, tone_t tone); +int ft897_set_rptr_shift(RIG *rig, vfo_t vfo, rptr_shift_t rptr_shift); +int ft897_set_rptr_offs(RIG *rig, vfo_t vfo, shortfreq_t offs); +int ft897_set_rit(RIG *rig, vfo_t vfo, shortfreq_t rit); +int ft897_get_dcd(RIG *rig, vfo_t vfo, dcd_t *dcd); +// int ft897_set_powerstat(RIG *rig, powerstat_t status); + +#endif /* _FT897_H */ diff --git a/yaesu/yaesu.c b/yaesu/yaesu.c index e728fd951..ea8e1f8c8 100644 --- a/yaesu/yaesu.c +++ b/yaesu/yaesu.c @@ -7,7 +7,7 @@ * via serial interface to a Yaesu rig * * - * $Id: yaesu.c,v 1.16 2003-10-12 18:04:02 fillods Exp $ + * $Id: yaesu.c,v 1.17 2004-02-08 17:08:46 fillods Exp $ * * * This library is free software; you can redistribute it and/or @@ -55,6 +55,7 @@ DECLARE_INITRIG_BACKEND(yaesu) rig_register(&ft817_caps); rig_register(&ft847_caps); rig_register(&ft857_caps); + rig_register(&ft897_caps); rig_register(&ft890_caps); rig_register(&ft900_caps); rig_register(&ft920_caps); diff --git a/yaesu/yaesu.h b/yaesu/yaesu.h index dacc9c98d..cbc812729 100644 --- a/yaesu/yaesu.h +++ b/yaesu/yaesu.h @@ -6,7 +6,7 @@ * * Common yaesu declarations for hamlib * - * $Id: yaesu.h,v 1.18 2003-10-12 18:04:02 fillods Exp $ + * $Id: yaesu.h,v 1.19 2004-02-08 17:08:46 fillods Exp $ * * * @@ -51,6 +51,7 @@ extern const struct rig_caps ft100_caps; extern const struct rig_caps ft747_caps; extern const struct rig_caps ft817_caps; extern const struct rig_caps ft857_caps; +extern const struct rig_caps ft897_caps; extern const struct rig_caps ft847_caps; extern const struct rig_caps ft890_caps; extern const struct rig_caps ft900_caps;