From: <fi...@us...> - 2010-03-28 16:38:14
|
Revision: 2859 http://hamlib.svn.sourceforge.net/hamlib/?rev=2859&view=rev Author: fillods Date: 2010-03-28 16:38:05 +0000 (Sun, 28 Mar 2010) Log Message: ----------- flesh out Paragon (585) Modified Paths: -------------- trunk/tentec/paragon.c Modified: trunk/tentec/paragon.c =================================================================== --- trunk/tentec/paragon.c 2010-03-28 16:33:03 UTC (rev 2858) +++ trunk/tentec/paragon.c 2010-03-28 16:38:05 UTC (rev 2859) @@ -1,8 +1,7 @@ /* * Hamlib TenTenc backend - TT-585 Paragon description - * Copyright (c) 2003-2009 by Stephane Fillod + * Copyright (c) 2003-2010 by Stephane Fillod * - * $Id: jupiter.c,v 1.4 2006-10-07 17:38:05 csete 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 @@ -27,13 +26,19 @@ #include <stdio.h> #include <string.h> #include <stdlib.h> +#include <unistd.h> -#include <hamlib/rig.h> +#include "hamlib/rig.h" #include "tentec.h" #include "bandplan.h" +#include "iofunc.h" +#include "serial.h" +#include "misc.h" struct tt585_priv_data { - char status[30]; + unsigned char status_data[30]; + struct timeval status_tv; + int channel_num; }; @@ -46,14 +51,17 @@ #define TT585_ANTS (RIG_ANT_1) -#define TT585_PARMS (RIG_PARM_NONE) +#define TT585_PARMS (RIG_PARM_ANN|RIG_PARM_TIME) #define TT585_VFO (RIG_VFO_A|RIG_VFO_B) #define TT585_VFO_OPS (RIG_OP_TO_VFO|RIG_OP_FROM_VFO|\ - RIG_OP_CPY|RIG_OP_MCL|RIG_OP_TOGGLE\ - RIG_OP_UP|RIG_OP_DOWN|RIG_OP_BAND_UP|RIG_OP_BAND_DOWN) + RIG_OP_CPY|RIG_OP_MCL|RIG_OP_TOGGLE|\ + RIG_OP_UP|RIG_OP_DOWN|RIG_OP_BAND_UP|RIG_OP_BAND_DOWN|\ + RIG_OP_TUNE) +#define TT585_CACHE_TIMEOUT 500 /* ms */ + /* * Mem caps to be checked.. */ @@ -70,20 +78,24 @@ static int tt585_set_freq(RIG *rig, vfo_t vfo, freq_t freq); static int tt585_set_vfo(RIG *rig, vfo_t vfo); static int tt585_get_vfo(RIG *rig, vfo_t *vfo); +static int tt585_set_split_vfo(RIG *rig, vfo_t vfo, split_t split, vfo_t txvfo); +static int tt585_get_split_vfo(RIG *rig, vfo_t vfo, split_t *split, vfo_t *txvfo); static int tt585_get_mode(RIG *rig, vfo_t vfo, rmode_t *mode, pbwidth_t *width); static int tt585_set_mode(RIG *rig, vfo_t vfo, rmode_t mode, pbwidth_t width); +static int tt585_vfo_op(RIG *rig, vfo_t vfo, vfo_op_t op); +static int tt585_set_parm(RIG *rig, setting_t parm, value_t val); +static int tt585_get_status_data(RIG *rig); + /* * tt585 transceiver capabilities, * with the optional model 258 RS232 Interface board. - * - * This is a skelton. */ const struct rig_caps tt585_caps = { .rig_model = RIG_MODEL_TT585, .model_name = "TT-585 Paragon", .mfg_name = "Ten-Tec", -.version = "0.1", +.version = "0.2", .copyright = "LGPL", .status = RIG_STATUS_ALPHA, .rig_type = RIG_TYPE_TRANSCEIVER, @@ -96,10 +108,10 @@ .serial_stop_bits = 1, .serial_parity = RIG_PARITY_NONE, .serial_handshake = RIG_HANDSHAKE_NONE, -.write_delay = 50, -.post_write_delay = 0, -.timeout = 500, -.retry = 3, +.write_delay = 20, +.post_write_delay = 100, /* TODO: FOR T=1 TO 200 on a 4.77 MHz PC */ +.timeout = 1000, +.retry = 0, .has_get_func = TT585_FUNCS, .has_set_func = TT585_FUNCS, @@ -107,7 +119,7 @@ .has_set_level = RIG_LEVEL_SET(TT585_LEVELS), .has_get_parm = TT585_PARMS, .has_set_parm = TT585_PARMS, -.level_gran = {}, /* FIXME: granularity */ +.level_gran = {}, .parm_gran = {}, .ctcss_list = NULL, .dcs_list = NULL, @@ -120,6 +132,7 @@ .transceive = RIG_TRN_OFF, .bank_qty = 0, .chan_desc_sz = 7, +.vfo_ops = TT585_VFO_OPS, .chan_list = { { 0, 61, RIG_MTYPE_MEM, TT585_MEM_CAP }, @@ -146,15 +159,21 @@ .tuning_steps = { {TT585_RXMODES,10}, + {TT585_RXMODES,20}, + {TT585_RXMODES,50}, + {TT585_RXMODES,100}, + {TT585_RXMODES,500}, RIG_TS_END, }, /* mode/filter list, remember: order matters! */ .filters = { {RIG_MODE_AM, kHz(6)}, - {RIG_MODE_CW|RIG_MODE_SSB|RIG_MODE_RTTY|RIG_MODE_AM, kHz(2.4)}, - {RIG_MODE_CW|RIG_MODE_SSB|RIG_MODE_AM, kHz(1.8)}, - {RIG_MODE_CW|RIG_MODE_SSB|RIG_MODE_AM, 500}, - {RIG_MODE_CW|RIG_MODE_SSB|RIG_MODE_AM, 250}, + {RIG_MODE_CW, kHz(1.8)}, + {RIG_MODE_SSB|RIG_MODE_RTTY|RIG_MODE_AM, kHz(2.4)}, + {RIG_MODE_CW|RIG_MODE_SSB|RIG_MODE_RTTY|RIG_MODE_AM, kHz(1.8)}, + {RIG_MODE_CW|RIG_MODE_SSB|RIG_MODE_RTTY|RIG_MODE_AM, 500}, + {RIG_MODE_CW|RIG_MODE_SSB|RIG_MODE_RTTY|RIG_MODE_AM, 250}, + {RIG_MODE_CW|RIG_MODE_SSB|RIG_MODE_RTTY|RIG_MODE_AM, kHz(6)}, {RIG_MODE_FM, kHz(15)}, RIG_FLT_END, }, @@ -166,8 +185,12 @@ .get_freq = tt585_get_freq, .set_vfo = tt585_set_vfo, .get_vfo = tt585_get_vfo, +.set_split_vfo = tt585_set_split_vfo, +.get_split_vfo = tt585_get_split_vfo, +.vfo_op = tt585_vfo_op, .set_mode = tt585_set_mode, .get_mode = tt585_get_mode, +.set_parm = tt585_set_parm, }; @@ -206,11 +229,18 @@ return RIG_OK; } -int tt585_get_vfo(RIG *rig, vfo_t *vfo) { +int tt585_get_vfo(RIG *rig, vfo_t *vfo) +{ + struct tt585_priv_data *priv = (struct tt585_priv_data *) rig->state.priv; + int ret; - struct tt585_priv_data *priv = (struct tt585_priv_data *) rig->state.priv; + ret = tt585_get_status_data(rig); + if (ret < 0) + return ret; - return -RIG_ENIMPL; + *vfo = priv->status_data[9] & 0x08 ? RIG_VFO_A : RIG_VFO_B; + + return RIG_OK; } /* @@ -219,20 +249,78 @@ */ int tt585_set_vfo(RIG *rig, vfo_t vfo) { + vfo_t curr_vfo; + int ret; + + ret = tt585_get_vfo(rig, &curr_vfo); + if (ret < 0) + return ret; + + if (vfo == curr_vfo || vfo == RIG_VFO_CURR || vfo == RIG_VFO_VFO) + return RIG_OK; + + /* toggle VFOs */ + return write_block(&rig->state.rigport, "F", 1); +} + +int tt585_set_split_vfo(RIG *rig, vfo_t vfo, split_t split, vfo_t txvfo) +{ + split_t curr_split; + vfo_t curr_txvfo; + int ret; + + ret = tt585_get_split_vfo(rig, vfo, &curr_split, &curr_txvfo); + if (ret < 0) + return ret; + + if (split == curr_split) + return RIG_OK; + + /* toggle split mode */ + return write_block(&rig->state.rigport, "J", 1); +} + +int tt585_get_split_vfo(RIG *rig, vfo_t vfo, split_t *split, vfo_t *txvfo) +{ struct tt585_priv_data *priv = (struct tt585_priv_data *)rig->state.priv; + int ret; - return -RIG_ENIMPL; + ret = tt585_get_status_data(rig); + if (ret < 0) + return ret; + + *split = priv->status_data[9] & 0x02 ? RIG_SPLIT_ON : RIG_SPLIT_OFF; + *txvfo = RIG_VFO_B; + + return RIG_OK; } + /* * tt585_get_freq * Assumes rig!=NULL, freq!=NULL */ int tt585_get_freq(RIG *rig, vfo_t vfo, freq_t *freq) { - struct tt585_priv_data *priv = (struct tt585_priv_data *)rig->state.priv; + struct tt585_priv_data *priv = (struct tt585_priv_data *)rig->state.priv; + int ret; + unsigned char *p; - return -RIG_ENIMPL; + ret = tt585_get_status_data(rig); + if (ret < 0) + return ret; + + p = priv->status_data; + + *freq = ((((((p[0]*10 + + p[1])*10 + + p[2])*10 + + p[3])*10 + + p[4])*10 + + p[5])*10 + + p[6])*10; + + return RIG_OK; } /* @@ -243,7 +331,21 @@ int tt585_set_freq(RIG *rig, vfo_t vfo, freq_t freq) { - return -RIG_ENIMPL; + struct tt585_priv_data *priv = (struct tt585_priv_data *)rig->state.priv; +#define FREQBUFSZ 16 + char buf[FREQBUFSZ], *p; + int ret; + + ret = snprintf(buf, FREQBUFSZ-1, "%.5f@", (double)freq/MHz(1)); + buf[FREQBUFSZ-1] = '\0'; + + /* replace decimal point with W */ + p = strchr(buf, '.'); + *p = 'W'; + + rig_force_cache_timeout(&priv->status_tv); + + return write_block(&rig->state.rigport, buf, ret); } /* @@ -252,9 +354,42 @@ */ int tt585_get_mode(RIG *rig, vfo_t vfo, rmode_t *mode, pbwidth_t *width) { - struct tt585_priv_data *priv = (struct tt585_priv_data *)rig->state.priv; + struct tt585_priv_data *priv = (struct tt585_priv_data *)rig->state.priv; + int ret; - return -RIG_ENIMPL; + ret = tt585_get_status_data(rig); + if (ret < 0) + return ret; + + if (priv->status_data[7] & 0x02) + *mode = RIG_MODE_CW; + else if (priv->status_data[7] & 0x04) + *mode = RIG_MODE_USB; + else if (priv->status_data[7] & 0x08) + *mode = RIG_MODE_LSB; + else if (priv->status_data[7] & 0x10) + *mode = RIG_MODE_AM; + else if (priv->status_data[7] & 0x20) + *mode = RIG_MODE_FM; + else if (priv->status_data[7] & 0x40) + *mode = RIG_MODE_RTTY; + else + *mode = RIG_MODE_NONE; + + if (priv->status_data[8] & 0x08) + *width = 250; + else if (priv->status_data[8] & 0x10) + *width = 500; + else if (priv->status_data[8] & 0x20) + *width = 1800; + else if (priv->status_data[8] & 0x40) + *width = 2400; + else if (priv->status_data[8] & 0x80) + *width = 6000; + else + *width = 0; + + return RIG_OK; } /* @@ -263,7 +398,178 @@ */ int tt585_set_mode(RIG *rig, vfo_t vfo, rmode_t mode, pbwidth_t width) { - return -RIG_ENIMPL; + struct tt585_priv_data *priv = (struct tt585_priv_data *)rig->state.priv; + const char *mcmd, *wcmd; + int ret; + + if (width == RIG_PASSBAND_NORMAL) + width = rig_passband_normal(rig, mode); + + switch(mode) { + case RIG_MODE_LSB: mcmd = "N"; break; + case RIG_MODE_USB: mcmd = "O"; break; + case RIG_MODE_CW: mcmd = "P"; break; + case RIG_MODE_FM: mcmd = "L"; break; + case RIG_MODE_AM: mcmd = "M"; break; + case RIG_MODE_RTTY:mcmd = "XP"; break; + default: + return -RIG_EINVAL; /* sorry, wrong MODE */ + } + + rig_force_cache_timeout(&priv->status_tv); + + ret = write_block(&rig->state.rigport, mcmd, strlen(mcmd)); + if (ret < 0) + return ret; + + if (width <= 250) + wcmd = "V"; + else if (width <= 500) + wcmd = "U"; + else if (width <= 1800) + wcmd = "T"; + else if (width <= 2400) + wcmd = "S"; + else /* 6000 (or FM?) */ + wcmd = "R"; + + return write_block(&rig->state.rigport, wcmd, strlen(mcmd)); } +int tt585_set_mem(RIG *rig, vfo_t vfo, int ch) +{ + struct tt585_priv_data *priv = (struct tt585_priv_data *)rig->state.priv; + char buf[16]; + int ret; + if (ch < 0 || ch > 61) + return -RIG_EINVAL; + + priv->channel_num = ch; + + /* does it work without a command after the channel number? */ + ret = sprintf(buf, ":%02d", ch); + + return write_block(&rig->state.rigport, buf, ret); +} + +int tt585_get_mem(RIG *rig, vfo_t vfo, int *ch) +{ + struct tt585_priv_data *priv = (struct tt585_priv_data *) rig->state.priv; + int ret; + + ret = tt585_get_status_data(rig); + if (ret < 0) + return ret; + + /* 63 means not in MEM mode, 0xfe means mem full */ + if (priv->status_data[11] > 61) + return -RIG_ERJCTED; + + *ch = priv->status_data[11]; + + return RIG_OK; +} + + +/* + * private helper function. Retrieves status data from rig. + * using buffer indicated in *priv struct. + * + * need to use this when doing tt585_get_* stuff + */ +int tt585_get_status_data(RIG *rig) +{ + struct tt585_priv_data *priv = (struct tt585_priv_data *)rig->state.priv; + hamlib_port_t *rigport; + int ret; + + rigport = &rig->state.rigport; + + if (!rig_check_cache_timeout(&priv->status_tv, TT585_CACHE_TIMEOUT)) + return RIG_OK; + + serial_flush(rigport); + + /* send STATUS comand to fetch data*/ + + ret = write_block(rigport, "\\", 1); + if (ret < 0) + return ret; + + ret = read_block(rigport, (char *) priv->status_data, + sizeof(priv->status_data)); + if (ret < 0) + return ret; + + /* update cache date */ + gettimeofday(&priv->status_tv, NULL); + + return RIG_OK; +} + +int tt585_set_parm(RIG *rig, setting_t parm, value_t val) +{ + int ret; + + switch (parm) { + case RIG_PARM_ANN: + /* FIXME: > is a toggle command only */ + ret = write_block(&rig->state.rigport, ">", 1); + if (ret < 0) + return ret; + /* exact addional delay TBC */ + sleep(1); + return RIG_OK; + + /* TODO: RIG_PARM_TIME */ + + default: + rig_debug (RIG_DEBUG_ERR, "%s: unsupported parm %#x\n", __func__, parm); + return -RIG_EINVAL; + } + + return RIG_OK; +} + +/* + * tt585_vfo_op + * Assumes rig!=NULL + */ +int tt585_vfo_op(RIG *rig, vfo_t vfo, vfo_op_t op) +{ + struct tt585_priv_data *priv = (struct tt585_priv_data *)rig->state.priv; + const char *cmd; + char buf[16]; + + switch (op) + { + case RIG_OP_TUNE: cmd = "Q"; break; + case RIG_OP_MCL: + sprintf(buf, ":%02dXD", priv->channel_num); + cmd = buf; + break; + case RIG_OP_TO_VFO: + sprintf(buf, ":%02d", priv->channel_num); + cmd = buf; + break; + case RIG_OP_FROM_VFO: + sprintf(buf, "<%02d", priv->channel_num); + cmd = buf; + break; + case RIG_OP_CPY: cmd = "E"; break; + case RIG_OP_TOGGLE: cmd = "F"; break; + case RIG_OP_DOWN: cmd = "]"; break; + case RIG_OP_UP: cmd = "["; break; + case RIG_OP_BAND_DOWN: cmd = "XY"; break; + case RIG_OP_BAND_UP: cmd = "XZ"; break; + default: + rig_debug (RIG_DEBUG_ERR, "%s: unsupported op %#x\n", __func__, op); + return -RIG_EINVAL; + } + + rig_force_cache_timeout(&priv->status_tv); + + return write_block(&rig->state.rigport, cmd, strlen(cmd)); +} + This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |