From b16c10a90e721b6a12d689f3fcc5d65d08511fdf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Fillod=2C=20F8CFE?= Date: Mon, 9 Feb 2004 22:11:08 +0000 Subject: [PATCH] TT550 patch from Ken, N7IPB git-svn-id: https://hamlib.svn.sourceforge.net/svnroot/hamlib/trunk@1684 7ae35d74-ebe9-4afe-98af-79ac388436b8 --- tentec/Makefile.am | 2 +- tentec/README | 26 + tentec/pegasus.c | 259 ++++--- tentec/tt550.c | 1622 ++++++++++++++++++++++++++++++++++++++++++++ tentec/tt550.h | 153 +++++ 5 files changed, 1963 insertions(+), 99 deletions(-) create mode 100644 tentec/README create mode 100644 tentec/tt550.c create mode 100644 tentec/tt550.h diff --git a/tentec/Makefile.am b/tentec/Makefile.am index f9f590169..a9d0394b6 100644 --- a/tentec/Makefile.am +++ b/tentec/Makefile.am @@ -1,7 +1,7 @@ TENTECSRCLIST = rx320.c pegasus.c argonaut.c lib_LTLIBRARIES = hamlib-tentec.la -hamlib_tentec_la_SOURCES = $(TENTECSRCLIST) tentec.c tentec2.c +hamlib_tentec_la_SOURCES = $(TENTECSRCLIST) tentec.c tentec2.c tt550.c hamlib_tentec_la_LDFLAGS = -no-undefined -module -avoid-version hamlib_tentec_la_LIBADD = $(top_builddir)/src/libhamlib.la diff --git a/tentec/README b/tentec/README new file mode 100644 index 000000000..38ec9c602 --- /dev/null +++ b/tentec/README @@ -0,0 +1,26 @@ +tt550 TODO (Ken, N7IPB): + Support for multiple VFO's and Memories. The TT550 doesn't + really have VFO's or Memories since it's strictly a software + controlled radio, but they can easily be simulated in software. + I already support a split mode since the TX and RX control is + separate. Adding support for VFO-A, VFO-B and memory channels + will be done next. + + The optional encoder with keypad is supported for changing frequency + only, along with F1 changing the stepsize. The other function keys + have no current assignments. I can add hard-coded Function keys as + I did with F1 but maybe a more generic solution can be determined. + + In addition the keypad is not supported. Hamlib has no apparent way + to make use of the numeric keys. We probably need to add a callback + for key data. + + IF-Shift: IF-Shift code is in place but I see no way in hamlib to make + use of it. The Icom dual pass-band tuning is supported, but not just + simple IF shift. Or maybe I just missed something. + + TX Audio Monitor Volume - no hamlib support - RIG_LEVEL_TX_MON? + CW Sidetone Volume - no hamlib support - RIG_LEVEL_SIDETONE? + Transmit Audio Source and Volume select - no hamlib support - RIG_LEVEL_LINEIN? + CW Spot Level - no hamlib support - RIG_LEVEL_CW_SPOT? + Enable/Disable Amplifier keying loop - no hamlib support - RIG_FUNC_AMP? diff --git a/tentec/pegasus.c b/tentec/pegasus.c index ced5dc241..df7cc412c 100644 --- a/tentec/pegasus.c +++ b/tentec/pegasus.c @@ -1,8 +1,8 @@ /* * Hamlib TenTenc backend - TT-550 PC-Radio description - * Copyright (c) 2002-2003 by Stephane Fillod + * Copyright (c) 2002-2004 by Stephane Fillod * - * $Id: pegasus.c,v 1.5 2003-12-08 08:38:18 fillods Exp $ + * $Id: pegasus.c,v 1.6 2004-02-09 22:10:21 fillods Exp $ * * This library is free software; you can redistribute it and/or modify * it under the terms of the GNU Library General Public License as @@ -29,21 +29,30 @@ #include #include "idx_builtin.h" #include "tentec.h" +#include "tt550.h" -#define TT550_MODES (RIG_MODE_FM|RIG_MODE_CW|RIG_MODE_SSB|RIG_MODE_RTTY) -#define TT550_RXMODES (TT550_MODES|RIG_MODE_AM) +#define TT550_MODES (RIG_MODE_FM|RIG_MODE_CW|RIG_MODE_SSB|RIG_MODE_RTTY|RIG_MODE_AM) +#define TT550_RXMODES (TT550_MODES) -#define TT550_FUNCS (RIG_FUNC_FAGC|RIG_FUNC_VOX|RIG_FUNC_ANF| \ - RIG_FUNC_NR|RIG_FUNC_NB|RIG_FUNC_COMP) +#define TT550_FUNCS (RIG_FUNC_VOX|RIG_FUNC_ANF|RIG_FUNC_TUNER| \ + RIG_FUNC_NR|RIG_FUNC_VOX) -#define TT550_LEVELS (RIG_LEVEL_AGC|RIG_LEVEL_AF|RIG_LEVEL_RAWSTR| \ - RIG_LEVEL_RF|RIG_LEVEL_COMP|RIG_LEVEL_VOX|RIG_LEVEL_SQL| \ - RIG_LEVEL_RFPOWER|RIG_LEVEL_MICGAIN|RIG_LEVEL_KEYSPD| \ - RIG_LEVEL_SWR|RIG_LEVEL_ATT) +#ifndef RIG_LEVEL_LINEOUT +#define RIG_LEVEL_LINEOUT 0 +#endif -#define TT550_VFO (RIG_VFO_A) +#define TT550_LEVELS (RIG_LEVEL_AGC|RIG_LEVEL_AF|RIG_LEVEL_RAWSTR|RIG_LEVEL_STRENGTH| \ + RIG_LEVEL_RF|RIG_LEVEL_COMP|RIG_LEVEL_VOX|RIG_LEVEL_SQL| \ + RIG_LEVEL_RFPOWER|RIG_LEVEL_MICGAIN|RIG_LEVEL_KEYSPD| \ + RIG_LEVEL_SWR|RIG_LEVEL_ATT|RIG_LEVEL_NR| \ + RIG_LEVEL_VOXGAIN|RIG_LEVEL_VOXDELAY|RIG_LEVEL_ANTIVOX| \ + RIG_LEVEL_LINEOUT) + + +#define TT550_VFO (RIG_VFO_A ) +#define TT550_VFO_OPS (RIG_OP_TUNE) /* * a bit coarse, but I don't have a TT550, and the manual is not * verbose on the subject. Please test it and report! --SF @@ -62,102 +71,156 @@ * TODO: */ const struct rig_caps tt550_caps = { -.rig_model = RIG_MODEL_TT550, -.model_name = "TT-550", -.mfg_name = "Ten-Tec", -.version = "0.1", -.copyright = "LGPL", -.status = RIG_STATUS_UNTESTED, -.rig_type = RIG_TYPE_COMPUTER, -.ptt_type = RIG_PTT_NONE, -.dcd_type = RIG_DCD_NONE, -.port_type = RIG_PORT_SERIAL, -.serial_rate_min = 57600, -.serial_rate_max = 57600, -.serial_data_bits = 8, -.serial_stop_bits = 1, -.serial_parity = RIG_PARITY_NONE, -.serial_handshake = RIG_HANDSHAKE_HARDWARE, -.write_delay = 0, -.post_write_delay = 0, -.timeout = 200, -.retry = 3, + .rig_model = RIG_MODEL_TT550, + .model_name = "TT-550", + .mfg_name = "Ten-Tec", + .version = "0.2", + .copyright = "LGPL", + .status = RIG_STATUS_BETA, + .rig_type = RIG_TYPE_COMPUTER, + .ptt_type = RIG_PTT_RIG, + .dcd_type = RIG_DCD_NONE, + .port_type = RIG_PORT_SERIAL, + .serial_rate_min = 57600, + .serial_rate_max = 57600, + .serial_data_bits = 8, + .serial_stop_bits = 1, + .serial_parity = RIG_PARITY_NONE, + .serial_handshake = RIG_HANDSHAKE_HARDWARE, + .write_delay = 0, + .post_write_delay = 0, + .timeout = 30, + .retry = 3, -.has_get_func = TT550_FUNCS, -.has_set_func = TT550_FUNCS, -.has_get_level = TT550_LEVELS, -.has_set_level = RIG_LEVEL_SET(TT550_LEVELS), -.has_get_parm = RIG_PARM_NONE, -.has_set_parm = RIG_PARM_NONE, -.level_gran = { - [LVL_RAWSTR] = { .min = { .i = 0 }, .max = { .i = 99999 } }, -}, -.parm_gran = {}, -.ctcss_list = NULL, -.dcs_list = NULL, -.preamp = { RIG_DBLST_END }, -.attenuator = { 20, RIG_DBLST_END }, -.max_rit = Hz(0), -.max_xit = Hz(0), -.max_ifshift = Hz(0), -.targetable_vfo = 0, -.transceive = RIG_TRN_OFF, -.bank_qty = 0, -.chan_desc_sz = 0, + .has_get_func = TT550_FUNCS, + .has_set_func = TT550_FUNCS, + .has_get_level = TT550_LEVELS, + .has_set_level = RIG_LEVEL_SET (TT550_LEVELS), + .has_get_parm = RIG_PARM_NONE, + .has_set_parm = RIG_PARM_NONE, + .level_gran = { + [LVL_RAWSTR] = {.min = {.i = 0},.max = {.i = 65535}}, + }, + .parm_gran = {}, + .ctcss_list = NULL, + .dcs_list = NULL, + .preamp = {RIG_DBLST_END}, + .attenuator = {20, RIG_DBLST_END}, + .max_rit = Hz (10000), + .max_xit = Hz (10000), + .max_ifshift = Hz (2000), + .targetable_vfo = RIG_TARGETABLE_ALL, + .vfo_ops = TT550_VFO_OPS, + .transceive = RIG_TRN_RIG, + .bank_qty = 0, + .chan_desc_sz = 0, -.chan_list = { - RIG_CHAN_END, + .chan_list = { + RIG_CHAN_END, }, -.rx_range_list1 = { RIG_FRNG_END, }, /* FIXME: enter region 1 setting */ -.tx_range_list1 = { RIG_FRNG_END, }, + .rx_range_list1 = {RIG_FRNG_END,}, /* FIXME: enter region 1 setting */ + .tx_range_list1 = {RIG_FRNG_END,}, -.rx_range_list2 = { - {kHz(100),MHz(30),TT550_RXMODES,-1,-1,TT550_VFO}, - RIG_FRNG_END, - }, -.tx_range_list2 = { - {kHz(1800),MHz(2)-1,TT550_MODES,5000,100000,TT550_VFO}, - {kHz(3500),MHz(4)-1,TT550_MODES,5000,100000,TT550_VFO}, - {MHz(7),kHz(7300),TT550_MODES,5000,100000,TT550_VFO}, - {kHz(10100),kHz(10150),TT550_MODES,5000,100000,TT550_VFO}, - {MHz(14),kHz(14350),TT550_MODES,5000,100000,TT550_VFO}, - {kHz(18068),kHz(18168),TT550_MODES,5000,100000,TT550_VFO}, - {MHz(21),kHz(21450),TT550_MODES,5000,100000,TT550_VFO}, - {kHz(24890),kHz(24990),TT550_MODES,5000,100000,TT550_VFO}, - {MHz(28),kHz(29700),TT550_MODES,5000,100000,TT550_VFO}, - RIG_FRNG_END, - }, + .rx_range_list2 = { + {kHz (100), MHz (30), TT550_RXMODES, -1, -1, TT550_VFO}, + RIG_FRNG_END, + }, + .tx_range_list2 = { + {kHz (1800), MHz (2) - 1, TT550_MODES, 5000, 100000, TT550_VFO}, + {kHz (3500), MHz (4) - 1, TT550_MODES, 5000, 100000, TT550_VFO}, + {kHz (5330), kHz (5407) - 1, RIG_MODE_USB, 5000, 50000, TT550_VFO}, + {MHz (7), kHz (7300), TT550_MODES, 5000, 100000, TT550_VFO}, + {kHz (10100), kHz (10150), TT550_MODES, 5000, 100000, TT550_VFO}, + {MHz (14), kHz (14350), TT550_MODES, 5000, 100000, TT550_VFO}, + {kHz (18068), kHz (18168), TT550_MODES, 5000, 100000, TT550_VFO}, + {MHz (21), kHz (21450), TT550_MODES, 5000, 100000, TT550_VFO}, + {kHz (24890), kHz (24990), TT550_MODES, 5000, 100000, TT550_VFO}, + {MHz (28), kHz (29700), TT550_MODES, 5000, 100000, TT550_VFO}, + RIG_FRNG_END, + }, -.tuning_steps = { - {TT550_RXMODES,1}, - RIG_TS_END, - }, - /* mode/filter list, remember: order matters! */ -.filters = { - /* FIXME: add increments -> 34 filters? */ - {RIG_MODE_SSB|RIG_MODE_RTTY, kHz(3)}, - {RIG_MODE_CW, 300}, - {RIG_MODE_AM|RIG_MODE_FM, kHz(8)}, - RIG_FLT_END, - }, -.str_cal = TT550_STR_CAL, - -.rig_init = tentec_init, -.rig_cleanup = tentec_cleanup, -.rig_open = tentec_trx_open, -.set_freq = tentec_set_freq, -.get_freq = tentec_get_freq, -.set_mode = tentec_set_mode, -.get_mode = tentec_get_mode, -.set_level = tentec_set_level, -.get_level = tentec_get_level, -.get_info = tentec_get_info, + .tuning_steps = { + {TT550_RXMODES, RIG_TS_ANY}, + RIG_TS_END, + }, + /* mode/filter list, remember: order matters! */ + .filters = { + {RIG_MODE_CW, Hz (450)}, + {RIG_MODE_CW, Hz (300)}, + {RIG_MODE_CW, Hz (750)}, + {RIG_MODE_AM|RIG_MODE_FM, kHz (6)}, + {RIG_MODE_AM|RIG_MODE_FM, Hz (4200)}, + {RIG_MODE_AM|RIG_MODE_FM, kHz (8)}, + {RIG_MODE_AM|RIG_MODE_FM|RIG_MODE_SSB|RIG_MODE_RTTY|RIG_MODE_CW, Hz(2400)}, + {RIG_MODE_AM|RIG_MODE_FM|RIG_MODE_SSB|RIG_MODE_RTTY|RIG_MODE_CW, Hz(2700)}, + {RIG_MODE_AM|RIG_MODE_FM|RIG_MODE_SSB|RIG_MODE_RTTY|RIG_MODE_CW, Hz(2100)}, + {RIG_MODE_AM|RIG_MODE_FM|RIG_MODE_SSB|RIG_MODE_RTTY|RIG_MODE_CW, Hz(5700)}, + {RIG_MODE_AM|RIG_MODE_FM|RIG_MODE_SSB|RIG_MODE_RTTY|RIG_MODE_CW, Hz(5400)}, + {RIG_MODE_AM|RIG_MODE_FM|RIG_MODE_SSB|RIG_MODE_RTTY|RIG_MODE_CW, Hz(5100)}, + {RIG_MODE_AM|RIG_MODE_FM|RIG_MODE_SSB|RIG_MODE_RTTY|RIG_MODE_CW, Hz(4800)}, + {RIG_MODE_AM|RIG_MODE_FM|RIG_MODE_SSB|RIG_MODE_RTTY|RIG_MODE_CW, Hz(4500)}, + {RIG_MODE_AM|RIG_MODE_FM|RIG_MODE_SSB|RIG_MODE_RTTY|RIG_MODE_CW, Hz(4200)}, + {RIG_MODE_AM|RIG_MODE_FM|RIG_MODE_SSB|RIG_MODE_RTTY|RIG_MODE_CW, Hz(3900)}, + {RIG_MODE_AM|RIG_MODE_FM|RIG_MODE_SSB|RIG_MODE_RTTY|RIG_MODE_CW, Hz(3600)}, + {RIG_MODE_AM|RIG_MODE_FM|RIG_MODE_SSB|RIG_MODE_RTTY|RIG_MODE_CW, Hz(3300)}, + {RIG_MODE_AM|RIG_MODE_FM|RIG_MODE_SSB|RIG_MODE_RTTY|RIG_MODE_CW, Hz(2850)}, + {RIG_MODE_AM|RIG_MODE_FM|RIG_MODE_SSB|RIG_MODE_RTTY|RIG_MODE_CW, Hz(8000)}, + {RIG_MODE_AM|RIG_MODE_FM|RIG_MODE_SSB|RIG_MODE_RTTY|RIG_MODE_CW, Hz(2550)}, + {RIG_MODE_AM|RIG_MODE_FM|RIG_MODE_SSB|RIG_MODE_RTTY|RIG_MODE_CW, Hz(2400)}, + {RIG_MODE_AM|RIG_MODE_FM|RIG_MODE_SSB|RIG_MODE_RTTY|RIG_MODE_CW, Hz(2250)}, + {RIG_MODE_AM|RIG_MODE_FM|RIG_MODE_SSB|RIG_MODE_RTTY|RIG_MODE_CW, Hz(6000)}, + {RIG_MODE_AM|RIG_MODE_FM|RIG_MODE_SSB|RIG_MODE_RTTY|RIG_MODE_CW, Hz(1950)}, + {RIG_MODE_AM|RIG_MODE_FM|RIG_MODE_SSB|RIG_MODE_RTTY|RIG_MODE_CW, Hz(1800)}, + {RIG_MODE_AM|RIG_MODE_FM|RIG_MODE_SSB|RIG_MODE_RTTY|RIG_MODE_CW, Hz(1650)}, + {RIG_MODE_AM|RIG_MODE_FM|RIG_MODE_SSB|RIG_MODE_RTTY|RIG_MODE_CW, Hz(1500)}, + {RIG_MODE_AM|RIG_MODE_FM|RIG_MODE_SSB|RIG_MODE_RTTY|RIG_MODE_CW, Hz(1350)}, + {RIG_MODE_AM|RIG_MODE_FM|RIG_MODE_SSB|RIG_MODE_RTTY|RIG_MODE_CW, Hz(1200)}, + {RIG_MODE_AM|RIG_MODE_FM|RIG_MODE_SSB|RIG_MODE_RTTY|RIG_MODE_CW, Hz(1050)}, + {RIG_MODE_AM|RIG_MODE_FM|RIG_MODE_SSB|RIG_MODE_RTTY|RIG_MODE_CW, Hz(900)}, + {RIG_MODE_AM|RIG_MODE_FM|RIG_MODE_SSB|RIG_MODE_RTTY|RIG_MODE_CW, Hz(750)}, + {RIG_MODE_AM|RIG_MODE_FM|RIG_MODE_SSB|RIG_MODE_RTTY|RIG_MODE_CW, Hz(675)}, + {RIG_MODE_AM|RIG_MODE_FM|RIG_MODE_SSB|RIG_MODE_RTTY|RIG_MODE_CW, Hz(600)}, + {RIG_MODE_AM|RIG_MODE_FM|RIG_MODE_SSB|RIG_MODE_RTTY|RIG_MODE_CW, Hz(525)}, + {RIG_MODE_AM|RIG_MODE_FM|RIG_MODE_SSB|RIG_MODE_RTTY|RIG_MODE_CW, Hz(450)}, + {RIG_MODE_AM|RIG_MODE_FM|RIG_MODE_SSB|RIG_MODE_RTTY|RIG_MODE_CW, Hz(375)}, + {RIG_MODE_AM|RIG_MODE_FM|RIG_MODE_SSB|RIG_MODE_RTTY|RIG_MODE_CW, Hz(330)}, + {RIG_MODE_AM|RIG_MODE_FM|RIG_MODE_SSB|RIG_MODE_RTTY|RIG_MODE_CW, Hz(300)}, + RIG_FLT_END, + }, + .str_cal = TT550_STR_CAL, + .rig_init = tt550_init, + .rig_cleanup = tt550_cleanup, + .rig_open = tt550_trx_open, + .reset = tt550_reset, + .set_freq = tt550_set_freq, + .get_freq = tt550_get_freq, + .set_mode = tt550_set_mode, + .get_mode = tt550_get_mode, + .set_func = tt550_set_func, + .get_func = tt550_get_func, + .set_level = tt550_set_level, + .get_level = tt550_get_level, + .get_info = tt550_get_info, + .set_ptt = tt550_set_ptt, + .get_ptt = tt550_get_ptt, + .set_split_freq = tt550_set_tx_freq, + .get_split_freq = tt550_get_tx_freq, + .set_split_mode = tt550_set_tx_mode, + .get_split_mode = tt550_get_tx_mode, + .set_split_vfo = tt550_set_split_vfo, + .get_split_vfo = tt550_get_split_vfo, + .decode_event = tt550_decode_event, + .set_ts = tt550_set_tuning_step, + .get_ts = tt550_get_tuning_step, + .vfo_op = tt550_vfo_op, + .set_rit = tt550_set_rit, + .get_rit = tt550_get_rit, + .set_xit = tt550_set_xit, + .get_xit = tt550_get_xit, }; /* * Function definitions below */ - - diff --git a/tentec/tt550.c b/tentec/tt550.c new file mode 100644 index 000000000..f6c27d10a --- /dev/null +++ b/tentec/tt550.c @@ -0,0 +1,1622 @@ +/* + * Hamlib Tentec Pegasus TT550 backend - main file + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program 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 Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * + * Heavily modified for 550 support from the original tentec.c + * (c) Oct 2002, Jan,Feb 2004- Ken Koster N7IPB + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include /* Standard input/output definitions */ +#include /* String function definitions */ +#include /* UNIX standard function definitions */ +#include /* File control definitions */ +#include /* Error number definitions */ +#include /* POSIX terminal control definitions */ +#include +#include + +#include +#include +#include +#include + +#include "tt550.h" + + +/* + * Filter table for 550 reciver support + */ +static int tt550_filters[] = { + 6000, 5700, 5400, 5100, 4800, 4500, 4200, 3900, 3600, 3300, 3000, 2850, + 2700, 2550, 2400, 2250, 2100, 1950, 1800, 1650, 1500, 1350, 1200, 1050, + 900, 750, 675, 600, 525, 450, 375, 330, 300, 8000 +}; + +/* + * Filter table for 550 transmit support - The 550 allows the transmitter audio + * filter bandwidth to be changed, but the filters allowed are only a subset of the + * receive filters. This table is used to restrict the filters to the allowable + * range. + */ +static int tt550_tx_filters[] = { + 3900, 3600, 3300, 3000, 2850, 2700, 2550, 2400, 2250, 2100, 1950, 1800, + 1650, 1500, 1350, 1200, 1050 +}; + +/***************************Support Functions********************************/ + +/* + * tt550_transaction + * read exactly data_len bytes + * 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! + */ +int +tt550_transaction (RIG * rig, const char *cmd, int cmd_len, char *data, + int *data_len) +{ + int retval; + struct rig_state *rs; + + rs = &rig->state; + + /* + * Hold_Decode keeps the asynchronous decode routine from being called + * when we get data back from a normal command. + */ + Hold_Decode (rig); + + serial_flush (&rs->rigport); + + retval = write_block (&rs->rigport, cmd, cmd_len); + if (retval != RIG_OK) + { + Unhold_Decode (rig); + return retval; + } + + /* + * no data expected, TODO: flush input? + */ + if (!data || !data_len) + return 0; + + *data_len = read_string (&rs->rigport, data, *data_len, "", 0); + + Unhold_Decode (rig); + + return RIG_OK; +} + + + + /* + * tt550_tx_control - The 550 has a number of operations that control + * the transmitter. Commands like enable/disable tx, enable/disable + * amplifier loop, enable/disable keep alive, etc. + * This function provides for these commands. + */ +int +tt550_tx_control (RIG * rig, char oper) +{ + struct rig_state *rs = &rig->state; + int retval, cmd_len; + char cmdbuf[4]; + + cmd_len = sprintf (cmdbuf, "#%c" EOM, oper); + retval = write_block (&rs->rigport, cmdbuf, cmd_len); + /* + * if (retval == RIG_OK) not currently saving the state of these operations I'm + * not sure we need to, but if so, this is where it would go. + */ + return retval; + +} + + + + /* + * tt550_ldg_control - The 550 has a builtin LDG antenna tuner option. + * This function controls the tuner operations. + * + * + * The LDG tuner listens on the Pegasus' RS-232 + * Rx Data line. The interface is one-way. The tuner can't + * respond at all. The Pegasus will respond with Z when + * it sees the commands meant for the tuner. This is normal. + * The LDG tuner is only listening on the serial line + * when RF is applied. Therefore, RF must be applied before + * the tuner will do anything. + * + * $0 = Place tuner in bypass mode + * $1 = Start Tune process + * $3 = Cap Up + * $4 = Cap Dn + * $5 = Inductor Up + * $6 = Inductor Dn + * This function provides for these commands. + */ +int +tt550_ldg_control (RIG * rig, char oper) +{ + int retval, cmd_len, lvl_len; + char cmdbuf[4], lvlbuf[32]; + + cmd_len = sprintf (cmdbuf, "$%c" EOM, oper); + lvl_len = 3; + retval = tt550_transaction (rig, cmdbuf, 3, lvlbuf, &lvl_len); + /* + * if (retval == RIG_OK) not currently saving the state of these operations I'm + * not sure we need to, but if so, this is where it would go. + */ + return retval; +} + + + +/* + * Tuning Factor Calculations + * Used by both receive and transmit vfo routines + * to calculate the desired tuning parameters. + * tx - 0 for receive tuning, 1 for transmit tuning + * Thanks to the unknown author of the GPL'd windows program + * found on the Ten-Tec site. Having working examples of the + * calculations was invaluable. + */ +static void +tt550_tuning_factor_calc (RIG * rig, int tx) +{ + struct tt550_priv_data *priv; + + int Bfo = 700; + double TFreq = 0, IVal, radio_freq = 0; + int NVal, FVal; // N value/finetune value + int TBfo = 0; // temporary BFO + int IBfo = 1500; // Intermediate BFO Freq + int FilterBw; // Filter Bandwidth determined from table + int Mode, bwBFO, PbtAdj, RitAdj, XitAdj; + + priv = (struct tt550_priv_data *) rig->state.priv; + + Mode = (tx ? priv->tx_mode : priv->rx_mode); + radio_freq = ((tx ? priv->tx_freq : priv->rx_freq)) / (double) MHz (1); + FilterBw = priv->width; + PbtAdj = priv->pbtadj; + RitAdj = priv->rit; + XitAdj = priv->xit; + + if (tx) + { + bwBFO = (FilterBw / 2) + 200; + + IBfo = (bwBFO > IBfo) ? bwBFO : IBfo; + + if (Mode == RIG_MODE_USB) + { + TFreq = + radio_freq + (double) (IBfo / 1e6) + (double) (XitAdj / 1e6); + IBfo = (int) (IBfo * 2.73); + } + + + if (Mode == RIG_MODE_LSB) + { + TFreq = + radio_freq - (double) (IBfo / 1e6) + (double) (XitAdj / 1e6); + IBfo = (int) (IBfo * 2.73); + } + + + if (Mode == RIG_MODE_CW) + { + // CW Mode uses LSB Mode + IBfo = 1500; + int tt550_reset (RIG * rig, reset_t reset) + { + int retval, reset_len; + char reset_buf[32]; + + reset_len = 15; + retval = + tt550_transaction (rig, "XX" EOM, 3, reset_buf, &reset_len); + if (retval != RIG_OK) + return retval; + + reset_len = 15; + if (strstr (reset_buf, "DSP START")) + { + retval = + tt550_transaction (rig, "P1" EOM, 3, reset_buf, &reset_len); + if (retval != RIG_OK) + return retval; + } + if (!strstr (reset_buf, "RADIO START")) + { + return -RIG_EPROTO; + } + + return RIG_OK; + } + + TFreq = + radio_freq - (double) (IBfo / 1e6) + (double) (Bfo / 1e6) + + (double) (XitAdj / 1e6); + IBfo = (int) (Bfo * 2.73); + } + + if (Mode == RIG_MODE_FM) + { + IBfo = 0; + TFreq = + radio_freq - (double) (IBfo / 1e6) + (double) (Bfo / 1e6) + + (double) (XitAdj / 1e6); + IBfo = 0; + } + + if (Mode == RIG_MODE_AM) + { + IBfo = 0; + TFreq = + radio_freq - (double) (IBfo / 1e6) + (double) (Bfo / 1e6) + + (double) (XitAdj / 1e6); + IBfo = 0; + } + + + } + else + { + + radio_freq = radio_freq + (double) (RitAdj / 1e6); + + if (Mode == RIG_MODE_USB) + { + IBfo = (FilterBw / 2) + 200; + TFreq = + radio_freq + (double) (IBfo / 1e6) + (double) (PbtAdj / 1e6) + + (double) (RitAdj / 1e6); + IBfo = IBfo + (double) (PbtAdj / 1e6); + } + + + if (Mode == RIG_MODE_LSB) + { + IBfo = (FilterBw / 2) + 200; + TFreq = + radio_freq - (double) (IBfo / 1e6) - (double) (PbtAdj / 1e6) + + (double) (RitAdj / 1e6); + IBfo = IBfo + (double) (PbtAdj / 1e6); + } + if (Mode == RIG_MODE_CW) + { + /* CW Mode uses LSB Mode */ + if (((FilterBw / 2) + 300) <= Bfo) + { + IBfo = 0; + TFreq = + radio_freq - (double) (IBfo / 1e6) - (double) (PbtAdj / 1e6) + + (double) (RitAdj / 1e6); + IBfo = IBfo + Bfo + (double) (PbtAdj / 1e6); + } + else + { + + IBfo = (FilterBw / 2) + 300; + TFreq = + radio_freq - (double) (IBfo / 1e6) + (double) (Bfo / 1e6) - + (double) (PbtAdj / 1e6) + (double) (RitAdj / 1e6); + IBfo = IBfo + (double) (PbtAdj / 1e6); + } + + } + + if (Mode == RIG_MODE_FM) + { + IBfo = 0; + TFreq = + radio_freq - (double) (IBfo / 1e6) + (double) (Bfo / 1e6) - + (double) (PbtAdj / 1e6) + (double) (RitAdj / 1e6); + IBfo = 0; + } + + if (Mode == RIG_MODE_AM) + { + IBfo = 0; + TFreq = + radio_freq - (double) (IBfo / 1e6) + (double) (Bfo / 1e6) - + (double) (PbtAdj / 1e6) + (double) (RitAdj / 1e6); + IBfo = 0; + } + } + + TFreq = TFreq - 0.00125; + NVal = (int) (TFreq * 400); + IVal = (double) ((TFreq * 400.0) - NVal); + FVal = (int) (IVal * 2500.0 * 5.46); + NVal = (NVal + 18000); + TBfo = (tx ? IBfo : (int) (((double) IBfo + 8000.0) * 2.73)); + priv->ctf = NVal; + priv->ftf = FVal; + priv->btf = TBfo; +} + +/*************************End of Support Functions**************************/ + +/* + * tt550_init: + * Basically, it just sets up *priv with some sane defaults + * + */ +int +tt550_init (RIG * rig) +{ + struct tt550_priv_data *priv; + + priv = (struct tt550_priv_data *) malloc (sizeof (struct tt550_priv_data)); + + if (!priv) + { + /* + * whoops! memory shortage! + */ + return -RIG_ENOMEM; + } + + memset (priv, 0, sizeof (struct tt550_priv_data)); + + /* + * set arbitrary initial status + */ + priv->rx_freq = MHz (3.985); + priv->tx_freq = MHz (3.985); + priv->rx_mode = RIG_MODE_LSB; + priv->tx_mode = RIG_MODE_LSB; + priv->width = kHz (2.4); + priv->tx_width = kHz (2.4); + priv->tx_cwbfo = priv->cwbfo = kHz (0.7); + priv->agc = 0.5; /* medium */ + priv->lineout = priv->spkvol = 0.0; /* mute */ + priv->stepsize = 100; /* default to 100Hz tuning step */ + + rig->state.priv = (rig_ptr_t) priv; + return RIG_OK; +} + + + +/* + * Tentec generic tt550_cleanup routine + * the serial port is closed by the frontend + */ +int +tt550_cleanup (RIG * rig) +{ + if (rig->state.priv) + free (rig->state.priv); + + rig->state.priv = NULL; + + return RIG_OK; +} + + + +/* + * Software restart + */ +int +tt550_reset (RIG * rig, reset_t reset) +{ + int retval, reset_len; + char reset_buf[32]; + + reset_len = 16; + retval = tt550_transaction (rig, "XX" EOM, 3, reset_buf, &reset_len); + if (retval != RIG_OK) + return retval; + + reset_len = 16; + if (strstr (reset_buf, "DSP START")) + { + retval = tt550_transaction (rig, "P1" EOM, 3, reset_buf, &reset_len); + if (retval != RIG_OK) + return retval; + } + if (!strstr (reset_buf, "RADIO START")) + { + return -RIG_EPROTO; + } + + return RIG_OK; +} + + + +/* + * Tentec 550 transceiver open routine + * Restart and set program to execute. + */ +int +tt550_trx_open (RIG * rig) +{ + + struct tt550_priv_data *priv; + + priv = (struct tt550_priv_data *) rig->state.priv; + + /* + * Reset the radio and start it's program running + * We'll try twice to reset before giving up + */ + if (tt550_reset (rig, RIG_RESET_SOFT) != RIG_OK) + { + if (tt550_reset (rig, RIG_RESET_SOFT) != RIG_OK) + { + return -RIG_EPROTO; + } + } + +#ifdef BYPASS_KEEPALIVE + /* + * Temporarily Disable the transmitter Keep alive. The 550 expects the software + * to execute a serial command at least once every two seconds or it will + * disable TX. + */ + tt550_tx_control (rig, DISABLE_KEEPALIVE); + +#endif + + /* + * Program the radio with the default mode,freq,filter + */ + tt550_set_tx_mode (rig, RIG_VFO_CURR, priv->tx_mode, priv->tx_width); + tt550_set_rx_mode (rig, RIG_VFO_CURR, priv->rx_mode, priv->width); + tt550_set_tx_freq (rig, RIG_VFO_CURR, priv->tx_freq); + tt550_set_rx_freq (rig, RIG_VFO_CURR, priv->rx_freq); + + /* + * Enable TX + */ + tt550_tx_control (rig, ENABLE_TX); + + /* + * Bypass automatic tuner + */ + tt550_ldg_control (rig, '0'); + + return RIG_OK; +} + + + +/* + * tt550_set_freq + * Set the receive frequency to that requested and if + * Split mode is OFF do the transmitter too + */ +int +tt550_set_freq (RIG * rig, vfo_t vfo, freq_t freq) +{ + int retval; + struct tt550_priv_data *priv = (struct tt550_priv_data *) rig->state.priv; + + retval = tt550_set_rx_freq (rig, vfo, freq); + if (retval != RIG_OK) + { + return retval; + } + if (priv->split == RIG_SPLIT_OFF) + { + return tt550_set_tx_freq (rig, vfo, freq); + } + return retval; +} + + +/* + * tt550_get_freq + * Get the current receive frequency + */ +int +tt550_get_freq (RIG * rig, vfo_t vfo, freq_t * freq) +{ + struct tt550_priv_data *priv = (struct tt550_priv_data *) rig->state.priv; + + *freq = priv->rx_freq; + + return RIG_OK; +} + + +/* + * tt550_set_mode + * Set the receive mode and if NOT in split mode + * set the transmitter to the same mode/width + */ +int +tt550_set_mode (RIG * rig, vfo_t vfo, rmode_t mode, pbwidth_t width) +{ + int retval; + struct tt550_priv_data *priv = (struct tt550_priv_data *) rig->state.priv; + + retval = tt550_set_rx_mode (rig, vfo, mode, width); + if (retval != RIG_OK) + { + return retval; + } + if (priv->split == RIG_SPLIT_OFF) + { + return tt550_set_tx_mode (rig, vfo, mode, width); + } + + return retval; +} + + +/* + * tt550_get_mode + * GET the current receive mode/width + */ +int +tt550_get_mode (RIG * rig, vfo_t vfo, rmode_t * mode, pbwidth_t * width) +{ + struct tt550_priv_data *priv = (struct tt550_priv_data *) rig->state.priv; + + *mode = priv->rx_mode; + *width = priv->width; + + + return RIG_OK; +} + + +/* + * tt550_set_rx_freq + * Set the receiver to the requested frequency + */ +int +tt550_set_rx_freq (RIG * rig, vfo_t vfo, freq_t freq) +{ + struct tt550_priv_data *priv; + struct rig_state *rs = &rig->state; + int freq_len, retval; + char freqbuf[16]; + + priv = (struct tt550_priv_data *) rig->state.priv; + + priv->rx_freq = freq; + + tt550_tuning_factor_calc (rig, RECEIVE); + + freq_len = sprintf (freqbuf, "N%c%c%c%c%c%c" EOM, + priv->ctf >> 8, priv->ctf & 0xff, priv->ftf >> 8, + priv->ftf & 0xff, priv->btf >> 8, priv->btf & 0xff); + + retval = write_block (&rs->rigport, freqbuf, freq_len); + if (retval != RIG_OK) + return retval; + + return RIG_OK; +} + + + +/* + * tt550_set_tx_freq + * Set the current transmit frequency + */ +int +tt550_set_tx_freq (RIG * rig, vfo_t vfo, freq_t freq) +{ + struct tt550_priv_data *priv; + struct rig_state *rs = &rig->state; + int freq_len, retval; + char freqbuf[16]; + + priv = (struct tt550_priv_data *) rig->state.priv; + + priv->tx_freq = freq; + + tt550_tuning_factor_calc (rig, TRANSMIT); + + freq_len = sprintf (freqbuf, "T%c%c%c%c%c%c" EOM, + priv->ctf >> 8, priv->ctf & 0xff, priv->ftf >> 8, + priv->ftf & 0xff, priv->btf >> 8, priv->btf & 0xff); + + retval = write_block (&rs->rigport, freqbuf, freq_len); + if (retval != RIG_OK) + return retval; + + return RIG_OK; +} + + + +/* + * tt550_get_tx_freq + * Get the current transmit frequency + */ +int +tt550_get_tx_freq (RIG * rig, vfo_t vfo, freq_t * freq) +{ + struct tt550_priv_data *priv = (struct tt550_priv_data *) rig->state.priv; + + *freq = priv->tx_freq; + + return RIG_OK; +} + + +/* + * tt550_set_rx_mode + * SET the current receive mode + */ +int +tt550_set_rx_mode (RIG * rig, vfo_t vfo, rmode_t mode, pbwidth_t width) +{ + struct tt550_priv_data *priv = (struct tt550_priv_data *) rig->state.priv; + struct rig_state *rs = &rig->state; + char ttmode; + rmode_t saved_mode; + pbwidth_t saved_width; + int mdbuf_len, ttfilter, retval; + char mdbuf[48]; + + /* + * Find mode for receive + */ + switch (mode) + { + case RIG_MODE_USB: + ttmode = TT_USB; + break; + case RIG_MODE_LSB: + ttmode = TT_LSB; + break; + case RIG_MODE_CW: + ttmode = TT_CW; + break; + case RIG_MODE_AM: + ttmode = TT_AM; + break; + case RIG_MODE_FM: + ttmode = TT_FM; + break; + default: + rig_debug (RIG_DEBUG_ERR, "tt550_set_rxmode: unsupported mode %d\n", + mode); + return -RIG_EINVAL; + } + + + if (width == RIG_PASSBAND_NORMAL) + width = rig_passband_normal (rig, mode); + + for (ttfilter = 0; tt550_filters[ttfilter] != 0; ttfilter++) + { + if (tt550_filters[ttfilter] == width) + break; + } + if (tt550_filters[ttfilter] != width) + { + rig_debug (RIG_DEBUG_ERR, "tt550_set_mode: unsupported width %d\n", + width); + return -RIG_EINVAL; + + } + + /* + * backup current values in case we fail to write to port + */ + saved_mode = priv->rx_mode; + saved_width = priv->width; + + priv->rx_mode = mode; + priv->width = width; + + tt550_tuning_factor_calc (rig, RECEIVE); + + mdbuf_len = sprintf (mdbuf, "M%c%c" EOM, ttmode, ttmode); + retval = write_block (&rs->rigport, mdbuf, mdbuf_len); + + + mdbuf_len = sprintf (mdbuf, "W%c" EOM + "N%c%c%c%c%c%c" EOM, + ttfilter, + priv->ctf >> 8, priv->ctf & 0xff, priv->ftf >> 8, + priv->ftf & 0xff, priv->btf >> 8, priv->btf & 0xff); + retval = write_block (&rs->rigport, mdbuf, mdbuf_len); + + if (retval != RIG_OK) + { + priv->rx_mode = saved_mode; + priv->width = saved_width; + return retval; + } + + return RIG_OK; +} + + +/* + * tt550_set_tx_mode + * Set the current transmit mode/filter + * Since the transmitter uses a subset of the filters used + * by the receiver we set the filter if possible, if not we use + * the nearest value. + */ +int +tt550_set_tx_mode (RIG * rig, vfo_t vfo, rmode_t mode, pbwidth_t width) +{ + struct tt550_priv_data *priv = (struct tt550_priv_data *) rig->state.priv; + struct rig_state *rs = &rig->state; + char ttmode; + rmode_t saved_mode; + pbwidth_t saved_width; + int mdbuf_len, ttfilter, retval; + char mdbuf[48]; + + switch (mode) + { + case RIG_MODE_USB: + ttmode = TT_USB; + break; + case RIG_MODE_LSB: + ttmode = TT_LSB; + break; + case RIG_MODE_CW: + ttmode = TT_CW; + break; + case RIG_MODE_AM: + ttmode = TT_AM; + break; + case RIG_MODE_FM: + ttmode = TT_FM; + break; + default: + rig_debug (RIG_DEBUG_ERR, "tt550_set_mode: unsupported tx mode %d\n", + mode); + return -RIG_EINVAL; + } + + /* + * Limit the transmitter bandwidth - it's not the same as the receiver + */ + if (width < 1050) + width = 1050; + if (width > 3900) + width = 3900; + + if (width == RIG_PASSBAND_NORMAL) + width = rig_passband_normal (rig, mode); + + for (ttfilter = 0; tt550_tx_filters[ttfilter] != 0; ttfilter++) + { + if (tt550_tx_filters[ttfilter] == width) + break; + } + + if (tt550_tx_filters[ttfilter] != width) + { + rig_debug (RIG_DEBUG_ERR, + "tt550_set_mode: unsupported tx width %d,%d\n", width, + ttfilter); + return -RIG_EINVAL; + + } + + /* + * The tx filter array contains just the allowed filter values, but the + * command assumes that the first allowed value is at offset 7. We add + * 7 to compensate for the array difference + */ + + ttfilter += 7; + + /* + * backup current values in case we fail to write to port + */ + saved_mode = priv->tx_mode; + saved_width = priv->tx_width; + + priv->tx_mode = mode; + priv->tx_width = width; + + tt550_tuning_factor_calc (rig, TRANSMIT); + + mdbuf_len = sprintf (mdbuf, "M%c%c" EOM, ttmode, ttmode); + retval = write_block (&rs->rigport, mdbuf, mdbuf_len); + + + mdbuf_len = sprintf (mdbuf, "C%c" EOM + "T%c%c%c%c%c%c" EOM, + ttfilter, + priv->ctf >> 8, priv->ctf & 0xff, priv->ftf >> 8, + priv->ftf & 0xff, priv->btf >> 8, priv->btf & 0xff); + retval = write_block (&rs->rigport, mdbuf, mdbuf_len); + + if (retval != RIG_OK) + { + priv->tx_mode = saved_mode; + priv->tx_width = saved_width; + return retval; + } + + return RIG_OK; +} + + + /* + * tt550_get_tx_mode + */ +int +tt550_get_tx_mode (RIG * rig, vfo_t vfo, rmode_t * mode, pbwidth_t * width) +{ + struct tt550_priv_data *priv = (struct tt550_priv_data *) rig->state.priv; + + *mode = priv->tx_mode; + *width = priv->tx_width; + + return RIG_OK; +} + +/* + * Set the RIT value and force receive frequency to change + */ +int +tt550_set_rit (RIG * rig, vfo_t vfo, shortfreq_t rit) +{ + struct tt550_priv_data *priv = (struct tt550_priv_data *) rig->state.priv; + + priv->rit = rit; + tt550_set_rx_freq (rig, vfo, priv->rx_freq); + return RIG_OK; + +} + +/* + * Get The current RIT value + */ +int +tt550_get_rit (RIG * rig, vfo_t vfo, shortfreq_t * rit) +{ + struct tt550_priv_data *priv = (struct tt550_priv_data *) rig->state.priv; + + *rit = priv->rit; + + return RIG_OK; +} + +/* + * Set the XIT value and force the Transmit frequency to change + */ +int +tt550_set_xit (RIG * rig, vfo_t vfo, shortfreq_t xit) +{ + struct tt550_priv_data *priv = (struct tt550_priv_data *) rig->state.priv; + + priv->xit = xit; + tt550_set_tx_freq (rig, vfo, priv->tx_freq); + return RIG_OK; +} + + +/* + * Get the Current XIT value + */ +int +tt550_get_xit (RIG * rig, vfo_t vfo, shortfreq_t * xit) +{ + struct tt550_priv_data *priv = (struct tt550_priv_data *) rig->state.priv; + + *xit = priv->xit; + + return RIG_OK; +} + + +/* + * tt550_set_level + */ +int +tt550_set_level (RIG * rig, vfo_t vfo, setting_t level, value_t val) +{ + struct tt550_priv_data *priv = (struct tt550_priv_data *) rig->state.priv; + struct rig_state *rs = &rig->state; + int cmd_len, retval, ditfactor, dahfactor, spcfactor; + char cmdbuf[32]; + + switch (level) + { + case RIG_LEVEL_AGC: + cmd_len = + sprintf (cmdbuf, "G%c" EOM, + val.i >= 3 ? '3' : (val.i < 2 ? '1' : '2')); + retval = write_block (&rs->rigport, cmdbuf, cmd_len); + if (retval == RIG_OK) + priv->agc = val.i; + return retval; + case RIG_LEVEL_AF: + cmd_len = sprintf (cmdbuf, "V%c" EOM, (int) (val.f * 255)); + retval = write_block (&rs->rigport, cmdbuf, cmd_len); + if (retval == RIG_OK) + priv->spkvol = val.f; + return retval; +#ifdef RIG_LEVEL_LINEOUT + case RIG_LEVEL_LINEOUT: + cmd_len = sprintf (cmdbuf, "L%c" EOM, (int) (val.f * 63)); + retval = write_block (&rs->rigport, cmdbuf, cmd_len); + if (retval == RIG_OK) + priv->lineout = val.f; + return retval; +#endif + case RIG_LEVEL_RF: + cmd_len = sprintf (cmdbuf, "A%c" EOM, (int) (val.f * 255)); + retval = write_block (&rs->rigport, cmdbuf, cmd_len); + if (retval == RIG_OK) + priv->rflevel = val.f; + return retval; + + case RIG_LEVEL_SQL: + cmd_len = sprintf (cmdbuf, "S%c" EOM, (int) (val.f * 19)); + retval = write_block (&rs->rigport, cmdbuf, cmd_len); + if (retval == RIG_OK) + priv->sql = val.f; + return retval; + + case RIG_LEVEL_NR: + cmd_len = sprintf (cmdbuf, "D%c" EOM, (int) (val.f * 7)); + retval = write_block (&rs->rigport, cmdbuf, cmd_len); + if (retval == RIG_OK) + priv->nr = val.f; + return retval; + + case RIG_LEVEL_ATT: + /* + * attenuator is either on or off + */ + cmd_len = sprintf (cmdbuf, "B%c" EOM, val.i < 15 ? '0' : '1'); + retval = write_block (&rs->rigport, cmdbuf, cmd_len); + if (retval == RIG_OK) + priv->att = val.i; + return retval; + + case RIG_LEVEL_KEYSPD: + ditfactor = spcfactor = + (int) (((double) 0.50 / + (val.i * (double) 0.4166 * (double) 0.0001667))); + dahfactor = ditfactor * 3; + + cmd_len = sprintf (cmdbuf, "E%c%c%c%c%c%c" EOM, + ditfactor >> 8, ditfactor & 0xff, dahfactor >> 8, + dahfactor & 0xff, spcfactor >> 8, + spcfactor & 0xff); + retval = write_block (&rs->rigport, cmdbuf, cmd_len); + if (retval == RIG_OK) + priv->keyspd = val.i; + return retval; + + case RIG_LEVEL_RFPOWER: + cmd_len = sprintf (cmdbuf, "P%c" EOM, (int) (val.f * 255)); + retval = write_block (&rs->rigport, cmdbuf, cmd_len); + if (retval == RIG_OK) + priv->rfpower = val.f; + return retval; + + case RIG_LEVEL_VOXGAIN: + cmd_len = sprintf (cmdbuf, "UG%c" EOM, (int) (val.f * 255)); + retval = write_block (&rs->rigport, cmdbuf, cmd_len); + if (retval == RIG_OK) + priv->voxgain = val.f; + return retval; + + case RIG_LEVEL_VOXDELAY: + cmd_len = sprintf (cmdbuf, "UH%c" EOM, (int) (val.f * 255)); + retval = write_block (&rs->rigport, cmdbuf, cmd_len); + if (retval == RIG_OK) + priv->voxdelay = val.f; + return retval; + + case RIG_LEVEL_ANTIVOX: + cmd_len = sprintf (cmdbuf, "UA%c" EOM, (int) (val.f * 255)); + retval = write_block (&rs->rigport, cmdbuf, cmd_len); + if (retval == RIG_OK) + priv->antivox = val.f; + return retval; + + case RIG_LEVEL_COMP: + cmd_len = sprintf (cmdbuf, "Y%c" EOM, (int) (val.f * 127)); + retval = write_block (&rs->rigport, cmdbuf, cmd_len); + if (retval == RIG_OK) + priv->speechcomp = val.f; + return retval; + + case RIG_LEVEL_MICGAIN: + cmd_len = sprintf (cmdbuf, "O1%c%c" EOM, 0, (int) (val.f * 15)); + retval = write_block (&rs->rigport, cmdbuf, cmd_len); + if (retval == RIG_OK) + priv->mikegain = val.f; + return retval; + + case RIG_LEVEL_BKINDL: + cmd_len = sprintf (cmdbuf, "UQ%c" EOM, (int) (val.f * 255)); + retval = write_block (&rs->rigport, cmdbuf, cmd_len); + if (retval == RIG_OK) + priv->bkindl = val.f; + return retval; + + default: + rig_debug (RIG_DEBUG_ERR, "Unsupported set_level %d\n", level); + return -RIG_EINVAL; + } + + return RIG_OK; +} + + +/* + * tt550_get_level + */ +int +tt550_get_level (RIG * rig, vfo_t vfo, setting_t level, value_t * val) +{ + struct tt550_priv_data *priv = (struct tt550_priv_data *) rig->state.priv; + int retval, lvl_len; + char lvlbuf[32]; + + switch (level) + { + case RIG_LEVEL_STRENGTH: + /* + * read A/D converted value + */ + lvl_len = 7; + retval = tt550_transaction (rig, "?S" EOM, 3, lvlbuf, &lvl_len); + if (retval != RIG_OK) + return retval; + + if (lvl_len != 6) + { + rig_debug (RIG_DEBUG_ERR, + "tt550_get_level: wrong answer" "len=%d\n", lvl_len); + return -RIG_ERJCTED; + } + + /* + * Crude but it should work, the first and second digits are + * the ascii value for the S number (0x30 = S0 etc.) followed by + * a two byte fractional binary portion - We only use the first + * portion for now. + */ + val->i = (((lvlbuf[2] - 0x30) * 6) - 54); + + break; + + case RIG_LEVEL_RAWSTR: + /* + * read A/D converted value + */ + lvl_len = 6; + retval = tt550_transaction (rig, "?X" EOM, 3, lvlbuf, &lvl_len); + if (retval != RIG_OK) + return retval; + + if (lvl_len != 5) + { + rig_debug (RIG_DEBUG_ERR, + "tt550_get_level: wrong answer" "len=%d\n", lvl_len); + return -RIG_ERJCTED; + } + + val->i = (lvlbuf[1] << 8) + lvlbuf[2]; + break; + + case RIG_LEVEL_AGC: + val->f = priv->agc; + break; + + case RIG_LEVEL_AF: + val->f = priv->spkvol; + break; + +#ifdef RIG_LEVEL_LINEOUT + case RIG_LEVEL_LINEOUT: + val->f = priv->lineout; + break; +#endif + + case RIG_LEVEL_RF: + val->f = priv->rflevel; + break; + + case RIG_LEVEL_SQL: + val->f = priv->sql; + break; + case RIG_LEVEL_ATT: + val->i = priv->att; + break; + + case RIG_LEVEL_KEYSPD: + val->i = priv->keyspd; + break; + + case RIG_LEVEL_NR: + val->f = priv->nr; + break; + + case RIG_LEVEL_RFPOWER: + val->f = priv->rfpower; + break; + + case RIG_LEVEL_VOXGAIN: + val->f = priv->voxgain; + break; + + case RIG_LEVEL_VOXDELAY: + val->f = priv->voxdelay; + break; + + case RIG_LEVEL_ANTIVOX: + val->f = priv->antivox; + break; + + case RIG_LEVEL_COMP: + val->f = priv->speechcomp; + break; + + case RIG_LEVEL_MICGAIN: + val->f = priv->mikegain; + break; + + case RIG_LEVEL_BKINDL: + val->f = priv->bkindl; + break; + + default: + rig_debug (RIG_DEBUG_ERR, "Unsupported get_level %d\n", level); + return -RIG_EINVAL; + + } + + return RIG_OK; +} + + +/* + * tt550_get_info + */ +const char * +tt550_get_info (RIG * rig) +{ + static char buf[15]; + int firmware_len, retval; + + /* + * protocol version + */ + firmware_len = 10; + retval = tt550_transaction (rig, "?V" EOM, 3, buf, &firmware_len); + + if (retval != RIG_OK || firmware_len != 9) + { + rig_debug (RIG_DEBUG_ERR, "tt550_get_info: ack NG, len=%d\n", + firmware_len); + return NULL; + } + buf[firmware_len] = '\0'; + return buf; +} + + +/* + * tt550_set_ptt + */ +int +tt550_set_ptt (RIG * rig, vfo_t vfo, ptt_t ptt) +{ + struct rig_state *rs = &rig->state; + int cmd_len; + char cmdbuf[32]; + + cmd_len = sprintf (cmdbuf, "Q%c" EOM, ptt == 0 ? '0' : '1'); + return (write_block (&rs->rigport, cmdbuf, cmd_len)); + +} + +/* + * tt550_get_ptt + */ +int +tt550_get_ptt (RIG * rig, vfo_t vfo, ptt_t * ptt) +{ + static char buf[10]; + int len, retval; + + /* + * The 550 doesn't have an explicit command to return ptt status, so we fake it + * with the request for signal strength which returns a 'T' for the first + * character if we're transmitting + */ + len = 7; + retval = tt550_transaction (rig, "?S" EOM, 3, buf, &len); + if (retval != RIG_OK) + { + return retval; + } + /* + * buf should contain either Sxx for Receive Signal strenth + * or Txx for Transmit power/reflected power + */ + + *ptt = buf[0] == 'T' ? RIG_PTT_ON : RIG_PTT_OFF; + + return RIG_OK; + +} + +/* + * tt550_set_split_vfo + */ +int +tt550_set_split_vfo (RIG * rig, vfo_t vfo, split_t split, vfo_t tx_vfo) +{ + struct tt550_priv_data *priv = (struct tt550_priv_data *) rig->state.priv; + + priv->split = split; + + return RIG_OK; +} + + +/* + * tt550_get_split_vfo + */ +int +tt550_get_split_vfo (RIG * rig, vfo_t vfo, split_t * split, vfo_t * tx_vfo) +{ + struct tt550_priv_data *priv = (struct tt550_priv_data *) rig->state.priv; + + *split = priv->split; + + return RIG_OK; +} + + +int +tt550_set_func (RIG * rig, vfo_t vfo, setting_t func, int status) +{ + unsigned char fctbuf[16], ackbuf[16]; + int fct_len, ack_len; + struct tt550_priv_data *priv = (struct tt550_priv_data *) rig->state.priv; + + /* Optimize: + * sort the switch cases with the most frequent first + */ + ack_len = 0; + switch (func) + { + case RIG_FUNC_VOX: + fct_len = + sprintf (fctbuf, "U%c;", status == RIG_FUNC_VOX ? '0' : '1'); + priv->vox = status == RIG_FUNC_VOX ? '0' : '1'; + return tt550_transaction (rig, fctbuf, fct_len, ackbuf, &ack_len); + + case RIG_FUNC_NR: + fct_len = + sprintf (fctbuf, "K%c%c;", status == RIG_FUNC_NR ? '0' : '1', + priv->anf); + priv->en_nr = status == RIG_FUNC_NR ? '0' : '1'; + return tt550_transaction (rig, fctbuf, fct_len, ackbuf, &ack_len); + + case RIG_FUNC_ANF: + fct_len = + sprintf (fctbuf, "K%c%c;", priv->en_nr, + status == RIG_FUNC_ANF ? '0' : '1'); + priv->anf = status == RIG_FUNC_ANF ? '0' : '1'; + return tt550_transaction (rig, fctbuf, fct_len, ackbuf, &ack_len); + + case RIG_FUNC_TUNER: + priv->tuner = status == RIG_FUNC_TUNER ? '0' : '1'; + if (status == '0') + tt550_ldg_control (rig, 0); + return RIG_OK; + + default: + rig_debug (RIG_DEBUG_ERR, "Unsupported set_func %#x", func); + return -RIG_EINVAL; + } + + return RIG_OK; +} + +int +tt550_get_func (RIG * rig, vfo_t vfo, setting_t func, int *status) +{ + struct tt550_priv_data *priv = (struct tt550_priv_data *) rig->state.priv; + + /* Optimize: + * sort the switch cases with the most frequent first + */ + switch (func) + { + case RIG_FUNC_VOX: + *status = priv->vox; + break; + + case RIG_FUNC_NR: + *status = priv->en_nr; + break; + + case RIG_FUNC_ANF: + *status = priv->anf; + break; + + case RIG_FUNC_TUNER: + *status = priv->tuner; + break; + + default: + rig_debug (RIG_DEBUG_ERR, "Unsupported get_func %#x", func); + return -RIG_EINVAL; + } + + return RIG_OK; +} + + +/* + * tt550_set_tuning_step + */ +int +tt550_set_tuning_step (RIG * rig, vfo_t vfo, shortfreq_t stepsize) +{ + struct tt550_priv_data *priv; + struct rig_state *rs; + + rs = &rig->state; + priv = (struct tt550_priv_data *) rs->priv; + + rig_debug (RIG_DEBUG_VERBOSE, "tt550: tt550_set_tuning_step - %d\n", + stepsize); + + priv->stepsize = stepsize; + + return RIG_OK; +} + + +/* + * tt550_get_tuning_step + */ +int +tt550_get_tuning_step (RIG * rig, vfo_t vfo, shortfreq_t * stepsize) +{ + struct tt550_priv_data *priv; + struct rig_state *rs; + + rs = &rig->state; + priv = (struct tt550_priv_data *) rs->priv; + + rig_debug (RIG_DEBUG_VERBOSE, "tt550: tt550_get_tuning_step - %d\n", + priv->stepsize); + + *stepsize = priv->stepsize; + + return RIG_OK; +} + + +/* + * Tune the radio using the LDG antenna tuner + */ +int +tt550_tune (RIG * rig) +{ + value_t current_power; + rmode_t current_mode; + value_t lowpower; + struct tt550_priv_data *priv = (struct tt550_priv_data *) rig->state.priv; + + /* Set our lowpower level to about 10 Watts */ + lowpower.f = 0.12; + + /* Get the current power and save it, */ + current_power.f = priv->rfpower; + + /* Set power to approx 10w */ + tt550_set_level (rig, RIG_VFO_CURR, RIG_LEVEL_RFPOWER, lowpower); + + /* Get the current mode, and save */ + current_mode = priv->tx_mode; + + /* Set the mode to cw, keep the old frequency and bandwidth */ + tt550_set_tx_mode (rig, RIG_VFO_CURR, RIG_MODE_CW, priv->tx_width); + tt550_set_tx_freq (rig, RIG_VFO_CURR, priv->tx_freq); + + /* key the radio */ + tt550_set_ptt (rig, RIG_VFO_CURR, 1); + + /* Wait long enough for the transmitter to key up */ + sleep (1); + + /* Start the tuner */ + tt550_ldg_control (rig, '1'); + + /* + * Wait for tuner to finish + * NOTE: Using sleep and blocking like this is BAD, we + * really should have a way to tell that the tuner is finished. + * What we should be doing here is probably: + * 1. wait one second for tuner to start. + * 2. Unkey the radio - the LDG tuner will keep it keyed until + * it is done. (I think) + * NOTE: I was wrong, the LDG does not key the rig so this won't work. + * Have to come up with something else. + * 3. Keep checking for the Radio to be unkeyed + * 4. Stop the tuner and restore everything. + * The above should all be done asynchronous to this function so + * that we don't stall the calling routine. + */ + sleep (4); + + /* Unkey the Radio */ + tt550_set_ptt (rig, RIG_VFO_CURR, 0); + + /* Restore the mode and frequency */ + tt550_set_tx_mode (rig, RIG_VFO_CURR, current_mode, priv->tx_width); + tt550_set_tx_freq (rig, RIG_VFO_CURR, priv->tx_freq); + + /* Restore the original Power setting */ + tt550_set_level (rig, RIG_VFO_CURR, RIG_LEVEL_RFPOWER, current_power); + + return RIG_OK; +} + + +/* + * tt550_vfo_op + */ +int +tt550_vfo_op (RIG * rig, vfo_t vfo, vfo_op_t op) +{ + + switch (op) + { + case RIG_OP_TUNE: + tt550_tune (rig); + break; + default: + rig_debug (RIG_DEBUG_ERR, "tt550_vfo_op: unsupported op %#x\n", op); + return -RIG_EINVAL; + } + return RIG_OK; +} + + + +#define MAXFRAMELEN 7 +/* + * tt550_decode is called by sa_sigio, when asynchronous data + * has been received from the rig + * + * A lot more can be done in this routine. Things like allowing F2 + * to switch the encoder between frequency, audio, power control. Or + * letting a function key cycle thru various bands. + * For now it just handles the encoder for frequency change and F1 for + * changing the step size. + */ +int +tt550_decode_event (RIG * rig) +{ + struct tt550_priv_data *priv; + struct rig_state *rs; + unsigned char buf[MAXFRAMELEN]; + int data_len; + short movement = 0; + char key; + + + rig_debug (RIG_DEBUG_VERBOSE, "tt550: tt550_decode_event called\n"); + + rs = &rig->state; + priv = (struct tt550_priv_data *) rs->priv; + + + data_len = read_string (&rs->rigport, buf, MAXFRAMELEN, "\n\r", 2); + + + if (data_len == -RIG_ETIMEOUT) { + rig_debug (RIG_DEBUG_VERBOSE, + "tt550: tt550_decode got a timeout before the first character\n"); + return RIG_OK; + } + + rig_debug (RIG_DEBUG_VERBOSE, "tt550: tt550_decode %x\n", &buf); + + /* + * The first byte must be either 'U' for keypad operations + * or '!' for encoder operations. + */ + switch (*buf) + { + + /* + * For now we'll assume that the encoder is only used for + * frequency control, but since it's really a general purpose + * device we could later use it for other purposes. + * Tied in with priv->stepsize to allow the step rate to change + */ + case '!': + if (rig->callbacks.freq_event) + { + movement = buf[1] << 8; + movement = movement | buf[2]; + key = buf[3]; + rig_debug (RIG_DEBUG_VERBOSE, + "tt550: Step Direction = %d\n", movement); + if (movement > 0) + priv->rx_freq += priv->stepsize; + if (movement < 0) + priv->rx_freq -= priv->stepsize; + rig->callbacks.freq_event (rig, RIG_VFO_CURR, priv->rx_freq, + rig->callbacks.freq_arg); + } + + break; + + /* + * Keypad Function Key support - for now only F1 + * Numeric pad can be done later + */ + case 'U': + switch (buf[1]) + { + case KEY_F1_DOWN: + /* F1 changes the Step size from 1hz to 1mhz */ + if (priv->stepsize < 10000) + { + /* In powers of ten */ + priv->stepsize = priv->stepsize * 10; + } + else + { + priv->stepsize = 1; + } + break; + case KEY_F2_DOWN: + case KEY_F3_DOWN: + case KEY_F1_UP: + case KEY_F2_UP: + case KEY_F3_UP: + default: + rig_debug (RIG_DEBUG_VERBOSE, + "tt550_decode: KEY " "unsupported %d\n", buf[1]); + return -RIG_ENIMPL; + } + break; + default: + rig_debug (RIG_DEBUG_VERBOSE, + "tt550_decode: response " "unsupported %s\n", buf); + return -RIG_ENIMPL; + } + return RIG_OK; +} diff --git a/tentec/tt550.h b/tentec/tt550.h new file mode 100644 index 000000000..48505ac47 --- /dev/null +++ b/tentec/tt550.h @@ -0,0 +1,153 @@ +/* + * Hamlib Tentec backend - main header + * Copyright (c) 2001-2004 by Stephane Fillod + * + * $Id: tt550.h,v 1.1 2004-02-09 22:11:08 fillods Exp $ + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program 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 Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#ifndef _TT550_H +#define _TT550_H 1 + +#include +#include + + +#define EOM "\015" /* CR */ + +#define TT_AM '0' +#define TT_USB '1' +#define TT_LSB '2' +#define TT_CW '3' +#define TT_FM '4' + +/* + * Transmit and receive flags used by tt550_tuning_factor_calc + * to modify behavior for transmit versus receive vfo's + */ +#define RECEIVE 0 +#define TRANSMIT 1 + + +/* + * Transmitter control operations + */ +#define DISABLE_TX '0' +#define ENABLE_TX '1' +#define DISABLE_AMP '2' +#define ENABLE_AMP '3' +#define ENABLE_KEYER '6' +#define DISABLE_KEYER '7' +#define DISABLE_KEEPALIVE '8' +#define ENABLE_KEEPALIVE '9' + +/* This is needed until we come up with a way to guarantee that the +** KEEPALIVE mechanism of the Pegasus is met. +*/ +#define BYPASS_KEEPALIVE 1 + +#define KEY_F1_DOWN 0x11 +#define KEY_F2_DOWN 0x12 +#define KEY_F3_DOWN 0x13 +#define KEY_F1_UP 0x91 +#define KEY_F2_UP 0x92 +#define KEY_F3_UP 0x93 + +struct tt550_priv_data +{ + rmode_t tx_mode; /* transmitter mode - may be different from receiver in split mode */ + rmode_t rx_mode; /* Current RX Mode */ + freq_t tx_freq; /* tuned transmitter frequency - may be different from + * 'freq' when in split mode + */ + freq_t rx_freq; /* Current RX Frequency */ + shortfreq_t rit; /* Current RIT Value */ + shortfreq_t xit; /* Current XIT Value */ + shortfreq_t pbtadj; /* Current pass band tuning value */ + pbwidth_t width; /* filter bandwidth in Hz */ + pbwidth_t tx_width; /* transmit filter bandwidth in Hz */ + int pb; /* RX passband offset in Hz 0 [0-10000] */ + int cwbfo; /* BFO frequency: 700 [0-2000Hz] */ + int tx_cwbfo; /* TX_BFO frequency: 700 [0-2000Hz] */ + float lineout; /* line-out volume: 30 [0..63] */ + float spkvol; /* speaker volume: 30 [0..63] */ + int agc; /* AGC: medium */ + float rflevel; /* RF Gain Level: [0..255] */ + float sql; /* Squelch: [0..255] */ + int att; /* Attenuator level [0..1] */ + int keyspd; /* Keyer speed: [0..255] */ + float nr; /* Noise reduction: [0..1] */ + float autonotch; /* Autonotch filter: [0..1] */ + float rfpower; /* RF Power: [0..255] */ + float speechcomp; /* Speech compressor: [0..127] */ + float voxgain; /* Vox Gain: [0..255] */ + float voxdelay; /* Vox delay: [0..255] */ + float antivox; /* AntiVox gain: [0..255] */ + float mikegain; /* Microphone gain: [0..15] */ + float bkindl; /* CW QSK level */ + int split; /* split - ON/OFF */ + shortfreq_t stepsize; /*current step size */ + int anf; /* ANF on/off 1/0 */ + int en_nr; /* Noise Reduction on/off 1/0 */ + int tuner; /* automatic tuner on/off 1/0 */ + int vox; /* VOX on/off 1/0 */ + + /* calculated by tt550_tuning_factor_calc() */ + int ctf; /* Coarse Tune Factor */ + int ftf; /* Fine Tune Factor */ + int btf; /* Bfo Tune Factor, btval is ignored by RX-320 in AM MODE */ + + /* S-meter calibration data */ + cal_table_t str_cal; +}; + +int tt550_init (RIG * rig); +int tt550_cleanup (RIG * rig); +int tt550_trx_open (RIG * rig); +int tt550_reset(RIG * rig, reset_t reset); +int tt550_set_freq (RIG * rig, vfo_t vfo, freq_t freq); +int tt550_get_freq (RIG * rig, vfo_t vfo, freq_t * freq); +int tt550_set_mode (RIG * rig, vfo_t vfo, rmode_t mode, pbwidth_t width); +int tt550_get_mode (RIG * rig, vfo_t vfo, rmode_t * mode, pbwidth_t * width); +int tt550_set_level (RIG * rig, vfo_t vfo, setting_t level, value_t val); +int tt550_get_level (RIG * rig, vfo_t vfo, setting_t level, value_t * val); +int tt550_set_ptt (RIG * rig, vfo_t vfo, ptt_t ptt); +int tt550_get_ptt (RIG * rig, vfo_t vfo, ptt_t * ptt); +int tt550_decode_event (RIG * rig); +const char *tt550_get_info (RIG * rig); +int tt550_set_tx_freq (RIG * rig, vfo_t vfo, freq_t freq); +int tt550_get_tx_freq (RIG * rig, vfo_t vfo, freq_t * freq); +int tt550_set_rx_freq (RIG * rig, vfo_t vfo, freq_t freq); +int tt550_get_rx_freq (RIG * rig, vfo_t vfo, freq_t * freq); +int tt550_set_tx_mode (RIG * rig, vfo_t vfo, rmode_t mode, pbwidth_t width); +int tt550_get_tx_mode (RIG * rig, vfo_t vfo, rmode_t * mode, pbwidth_t * width); +int tt550_set_rx_mode (RIG * rig, vfo_t vfo, rmode_t mode, pbwidth_t width); +int tt550_get_rx_mode (RIG * rig, vfo_t vfo, rmode_t * mode, pbwidth_t * width); +int tt550_get_split_vfo (RIG * rig, vfo_t vfo, split_t * split, vfo_t * tx_vfo); +int tt550_set_split_vfo (RIG * rig, vfo_t vfo, split_t split, vfo_t tx_vfo); +int tt550_get_tuning_step (RIG * rig, vfo_t vfo, shortfreq_t * stepsize); +int tt550_set_tuning_step (RIG * rig, vfo_t vfo, shortfreq_t stepsize); +int tt550_set_func(RIG *rig, vfo_t vfo, setting_t func, int status); +int tt550_get_func(RIG *rig, vfo_t vfo, setting_t func, int *status); +int tt550_vfo_op(RIG *rig, vfo_t vfo, vfo_op_t op); +int tt550_set_rit(RIG * rig, vfo_t vfo, shortfreq_t rit); +int tt550_get_rit(RIG *rig, vfo_t vfo, shortfreq_t * rit); +int tt550_set_xit(RIG * rig, vfo_t vfo, shortfreq_t rit); +int tt550_get_xit(RIG *rig, vfo_t vfo, shortfreq_t * rit); + + +#endif /* _TT550_H */