kopia lustrzana https://github.com/Hamlib/Hamlib
1010 wiersze
24 KiB
C
1010 wiersze
24 KiB
C
/*
|
|
* Hamlib DttSP backend - main file
|
|
* Copyright (c) 2001-2012 by Stephane Fillod
|
|
*
|
|
* Some code derived from DttSP
|
|
* Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009 by Frank Brickle, AB2KT and Bob McGwier, N4HY
|
|
*
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
* License as published by the Free Software Foundation; either
|
|
* version 2.1 of the License, or (at your option) any later version.
|
|
*
|
|
* This library is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with this library; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
*
|
|
*/
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
#include "config.h"
|
|
#endif
|
|
|
|
#include <stdlib.h>
|
|
#include <stdio.h> /* Standard input/output definitions */
|
|
#include <string.h> /* String function definitions */
|
|
#include <unistd.h> /* UNIX standard function definitions */
|
|
#include <fcntl.h> /* File control definitions */
|
|
#include <errno.h> /* Error number definitions */
|
|
#include <math.h>
|
|
|
|
#include "hamlib/rig.h"
|
|
#include "iofunc.h"
|
|
#include "misc.h"
|
|
#include "token.h"
|
|
#include "register.h"
|
|
#include "cal.h"
|
|
#include "flexradio.h"
|
|
|
|
/*
|
|
* This backend is a two layer rig control: DttSP core over a mundane tuner
|
|
*
|
|
* 2 interfaces of DttSP are supported: IPC & UDP
|
|
*
|
|
* TODO: Transmit setup
|
|
* http://openhpsdr.org/wiki/index.php?title=Ghpsdr
|
|
*/
|
|
|
|
#define DEFAULT_DTTSP_CMD_PATH "/dev/shm/SDRcommands"
|
|
#define DEFAULT_DTTSP_CMD_NET_ADDR "127.0.0.1:19001"
|
|
#define DEFAULT_SAMPLE_RATE 48000
|
|
|
|
/* DttSP constants */
|
|
#define MAXRX 4
|
|
#define RXMETERPTS 5
|
|
#define TXMETERPTS 9
|
|
#define MAXMETERPTS 9
|
|
|
|
#define DTTSP_PORT_CLIENT_COMMAND 19001
|
|
#define DTTSP_PORT_CLIENT_SPECTRUM 19002
|
|
#define DTTSP_PORT_CLIENT_METER 19003
|
|
#define DTTSP_PORT_CLIENT_BUFSIZE 65536
|
|
|
|
|
|
struct dttsp_priv_data
|
|
{
|
|
/* tuner providing IF */
|
|
rig_model_t tuner_model;
|
|
RIG *tuner;
|
|
shortfreq_t IF_center_freq;
|
|
|
|
int sample_rate;
|
|
int rx_delta_f;
|
|
|
|
hamlib_port_t meter_port;
|
|
};
|
|
|
|
static int dttsp_init(RIG *rig);
|
|
static int dttsp_cleanup(RIG *rig);
|
|
static int dttsp_open(RIG *rig);
|
|
static int dttsp_close(RIG *rig);
|
|
|
|
static int dttsp_set_freq(RIG *rig, vfo_t vfo, freq_t freq);
|
|
static int dttsp_get_freq(RIG *rig, vfo_t vfo, freq_t *freq);
|
|
static int dttsp_set_mode(RIG *rig, vfo_t vfo, rmode_t mode, pbwidth_t width);
|
|
|
|
static int dttsp_set_conf(RIG *rig, token_t token, const char *val);
|
|
static int dttsp_get_conf(RIG *rig, token_t token, char *val);
|
|
static int dttsp_set_level(RIG *rig, vfo_t vfo, setting_t level, value_t val);
|
|
static int dttsp_get_level(RIG *rig, vfo_t vfo, setting_t level, value_t *val);
|
|
static int dttsp_set_func(RIG *rig, vfo_t vfo, setting_t func, int status);
|
|
static int dttsp_set_ant(RIG *rig, vfo_t vfo, ant_t ant, value_t option);
|
|
|
|
static int dttsp_set_rit(RIG *rig, vfo_t vfo, shortfreq_t rit);
|
|
static int dttsp_get_rit(RIG *rig, vfo_t vfo, shortfreq_t *rit);
|
|
|
|
|
|
|
|
#define TOK_TUNER_MODEL TOKEN_BACKEND(1)
|
|
#define TOK_SAMPLE_RATE TOKEN_BACKEND(2)
|
|
|
|
const struct confparams dttsp_cfg_params[] =
|
|
{
|
|
{
|
|
TOK_TUNER_MODEL, "tuner_model", "Tuner model", "Hamlib rig tuner model number",
|
|
"1" /* RIG_MODEL_DUMMY */, RIG_CONF_NUMERIC, { /* .n = */ { 0, 100000, 1 } }
|
|
},
|
|
{
|
|
TOK_SAMPLE_RATE, "sample_rate", "Sample rate", "DttSP sample rate in Spls/sec",
|
|
"48000", RIG_CONF_NUMERIC, { /* .n = */ { 8000, 192000, 1 } }
|
|
},
|
|
/*
|
|
* TODO: IF_center_freq, etc.
|
|
*/
|
|
{ RIG_CONF_END, NULL, }
|
|
};
|
|
|
|
|
|
/*
|
|
* DttSP dsr-core rig capabilities.
|
|
*/
|
|
|
|
#define DTTSP_FUNC (RIG_FUNC_NB|RIG_FUNC_ANF|RIG_FUNC_NR|RIG_FUNC_MUTE)
|
|
#define DTTSP_LEVEL (RIG_LEVEL_RAWSTR|RIG_LEVEL_STRENGTH|RIG_LEVEL_AGC)
|
|
#define DTTSP_PARM RIG_PARM_NONE
|
|
#define DTTSP_VFO_OP RIG_OP_NONE
|
|
#define DTTSP_SCAN RIG_SCAN_NONE
|
|
|
|
#define DTTSP_VFO (RIG_VFO_A)
|
|
|
|
#define DTTSP_MODES (RIG_MODE_FM|RIG_MODE_AM|RIG_MODE_SAM|RIG_MODE_DSB| \
|
|
RIG_MODE_CW|RIG_MODE_CWR|RIG_MODE_SSB)
|
|
|
|
enum dttsp_mode_e
|
|
{ LSB, USB, DSB, CWL, CWU, FMN, AM, DIGU, SPEC, DIGL, SAM, DRM };
|
|
|
|
static const struct hamlib_vs_dttsp
|
|
{
|
|
rmode_t hamlib_mode;
|
|
enum dttsp_mode_e dttsp_mode;
|
|
} hamlib_vs_dttsp_modes[] =
|
|
{
|
|
{ RIG_MODE_USB, USB },
|
|
{ RIG_MODE_LSB, LSB },
|
|
{ RIG_MODE_CW, CWU },
|
|
{ RIG_MODE_CWR, CWL },
|
|
{ RIG_MODE_AM, AM },
|
|
{ RIG_MODE_SAM, SAM },
|
|
{ RIG_MODE_FM, FMN },
|
|
{ RIG_MODE_DSB, DSB },
|
|
};
|
|
|
|
#define HAMLIB_VS_DTTSP_MODES_COUNT (sizeof(hamlib_vs_dttsp_modes)/sizeof(struct hamlib_vs_dttsp))
|
|
|
|
#define DTTSP_REAL_STR_CAL { 16, \
|
|
{ \
|
|
{ -73, -73 }, /* S0 */ \
|
|
{ 50, 40 }, /* +40 */ \
|
|
} }
|
|
|
|
const struct rig_caps dttsp_rig_caps =
|
|
{
|
|
RIG_MODEL(RIG_MODEL_DTTSP),
|
|
.model_name = "DttSP IPC",
|
|
.mfg_name = "DTTS Microwave Society",
|
|
.version = "20200319.0",
|
|
.copyright = "LGPL",
|
|
.status = RIG_STATUS_ALPHA,
|
|
.rig_type = RIG_TYPE_COMPUTER,
|
|
.targetable_vfo = RIG_TARGETABLE_ALL,
|
|
.ptt_type = RIG_PTT_RIG,
|
|
.dcd_type = RIG_DCD_RIG,
|
|
.port_type = RIG_PORT_DEVICE,
|
|
.has_get_func = DTTSP_FUNC,
|
|
.has_set_func = DTTSP_FUNC,
|
|
.has_get_level = DTTSP_LEVEL,
|
|
.has_set_level = RIG_LEVEL_SET(DTTSP_LEVEL),
|
|
.has_get_parm = DTTSP_PARM,
|
|
.has_set_parm = RIG_PARM_SET(DTTSP_PARM),
|
|
.ctcss_list = NULL,
|
|
.dcs_list = NULL,
|
|
.chan_list = {
|
|
RIG_CHAN_END,
|
|
},
|
|
.scan_ops = DTTSP_SCAN,
|
|
.vfo_ops = DTTSP_VFO_OP,
|
|
.transceive = RIG_TRN_OFF,
|
|
.attenuator = { RIG_DBLST_END, },
|
|
.preamp = { RIG_DBLST_END, },
|
|
/* In fact, RX and TX ranges are dependent on the tuner */
|
|
.rx_range_list1 = { {
|
|
.startf = kHz(150), .endf = MHz(1500), .modes = DTTSP_MODES,
|
|
.low_power = -1, .high_power = -1, DTTSP_VFO
|
|
},
|
|
RIG_FRNG_END,
|
|
},
|
|
.tx_range_list1 = { RIG_FRNG_END, }, /* TODO */
|
|
.rx_range_list2 = { {
|
|
.startf = kHz(150), .endf = MHz(1500), .modes = DTTSP_MODES,
|
|
.low_power = -1, .high_power = -1, DTTSP_VFO
|
|
},
|
|
RIG_FRNG_END,
|
|
},
|
|
.tx_range_list2 = { RIG_FRNG_END, }, /* TODO */
|
|
.tuning_steps = { {DTTSP_MODES, 1}, {DTTSP_MODES, RIG_TS_ANY}, RIG_TS_END, },
|
|
.filters = {
|
|
{RIG_MODE_SSB | RIG_MODE_CW | RIG_MODE_CWR, kHz(2.4)},
|
|
{RIG_MODE_AM | RIG_MODE_DSB | RIG_MODE_SAM, kHz(8)},
|
|
{RIG_MODE_FM, kHz(15)},
|
|
{DTTSP_MODES, RIG_FLT_ANY},
|
|
RIG_FLT_END,
|
|
},
|
|
|
|
.str_cal = DTTSP_REAL_STR_CAL,
|
|
|
|
.priv = NULL,
|
|
|
|
.rig_init = dttsp_init,
|
|
.rig_cleanup = dttsp_cleanup,
|
|
.rig_open = dttsp_open,
|
|
.rig_close = dttsp_close,
|
|
|
|
.cfgparams = dttsp_cfg_params,
|
|
.set_conf = dttsp_set_conf,
|
|
.get_conf = dttsp_get_conf,
|
|
|
|
.set_freq = dttsp_set_freq,
|
|
.get_freq = dttsp_get_freq,
|
|
|
|
.set_mode = dttsp_set_mode,
|
|
|
|
.set_level = dttsp_set_level,
|
|
.get_level = dttsp_get_level,
|
|
|
|
.set_func = dttsp_set_func,
|
|
|
|
.set_rit = dttsp_set_rit,
|
|
.get_rit = dttsp_get_rit,
|
|
|
|
.set_ant = dttsp_set_ant,
|
|
};
|
|
|
|
/*
|
|
* The same as the previous IPC, but of type RIG_PORT_UDP_NETWORK
|
|
*/
|
|
const struct rig_caps dttsp_udp_rig_caps =
|
|
{
|
|
RIG_MODEL(RIG_MODEL_DTTSP_UDP),
|
|
.model_name = "DttSP UDP",
|
|
.mfg_name = "DTTS Microwave Society",
|
|
.version = "20200319.0",
|
|
.copyright = "LGPL",
|
|
.status = RIG_STATUS_ALPHA,
|
|
.rig_type = RIG_TYPE_COMPUTER,
|
|
.targetable_vfo = RIG_TARGETABLE_ALL,
|
|
.ptt_type = RIG_PTT_RIG,
|
|
.dcd_type = RIG_DCD_RIG,
|
|
.port_type = RIG_PORT_UDP_NETWORK,
|
|
.timeout = 500,
|
|
.has_get_func = DTTSP_FUNC,
|
|
.has_set_func = DTTSP_FUNC,
|
|
.has_get_level = DTTSP_LEVEL,
|
|
.has_set_level = RIG_LEVEL_SET(DTTSP_LEVEL),
|
|
.has_get_parm = DTTSP_PARM,
|
|
.has_set_parm = RIG_PARM_SET(DTTSP_PARM),
|
|
.ctcss_list = NULL,
|
|
.dcs_list = NULL,
|
|
.chan_list = { RIG_CHAN_END, },
|
|
.scan_ops = DTTSP_SCAN,
|
|
.vfo_ops = DTTSP_VFO_OP,
|
|
.transceive = RIG_TRN_OFF,
|
|
.attenuator = { RIG_DBLST_END, },
|
|
.preamp = { RIG_DBLST_END, },
|
|
/* In fact, RX and TX ranges are dependent on the tuner */
|
|
.rx_range_list1 = { {
|
|
.startf = kHz(150), .endf = MHz(1500), .modes = DTTSP_MODES,
|
|
.low_power = -1, .high_power = -1, DTTSP_VFO
|
|
},
|
|
RIG_FRNG_END,
|
|
},
|
|
.tx_range_list1 = { RIG_FRNG_END, }, /* TODO */
|
|
.rx_range_list2 = { {
|
|
.startf = kHz(150), .endf = MHz(1500), .modes = DTTSP_MODES,
|
|
.low_power = -1, .high_power = -1, DTTSP_VFO
|
|
},
|
|
RIG_FRNG_END,
|
|
},
|
|
.tx_range_list2 = { RIG_FRNG_END, }, /* TODO */
|
|
.tuning_steps = { {DTTSP_MODES, 1}, {DTTSP_MODES, RIG_TS_ANY}, RIG_TS_END, },
|
|
.filters = {
|
|
{RIG_MODE_SSB | RIG_MODE_CW | RIG_MODE_CWR, kHz(2.4)},
|
|
{RIG_MODE_AM | RIG_MODE_DSB | RIG_MODE_SAM, kHz(8)},
|
|
{RIG_MODE_FM, kHz(15)},
|
|
{DTTSP_MODES, RIG_FLT_ANY},
|
|
RIG_FLT_END,
|
|
},
|
|
|
|
.str_cal = DTTSP_REAL_STR_CAL,
|
|
|
|
.priv = NULL,
|
|
|
|
.rig_init = dttsp_init,
|
|
.rig_cleanup = dttsp_cleanup,
|
|
.rig_open = dttsp_open,
|
|
.rig_close = dttsp_close,
|
|
|
|
.cfgparams = dttsp_cfg_params,
|
|
.set_conf = dttsp_set_conf,
|
|
.get_conf = dttsp_get_conf,
|
|
|
|
.set_freq = dttsp_set_freq,
|
|
.get_freq = dttsp_get_freq,
|
|
|
|
.set_mode = dttsp_set_mode,
|
|
|
|
.set_level = dttsp_set_level,
|
|
.get_level = dttsp_get_level,
|
|
|
|
.set_func = dttsp_set_func,
|
|
|
|
.set_rit = dttsp_set_rit,
|
|
.get_rit = dttsp_get_rit,
|
|
|
|
.set_ant = dttsp_set_ant,
|
|
};
|
|
|
|
|
|
static int send_command(RIG *rig, const char *cmdstr, size_t buflen)
|
|
{
|
|
int ret;
|
|
|
|
ret = write_block(&rig->state.rigport, cmdstr, buflen);
|
|
|
|
return ret;
|
|
}
|
|
|
|
static int fetch_meter(RIG *rig, int *label, float *data, int npts)
|
|
{
|
|
struct dttsp_priv_data *priv = (struct dttsp_priv_data *)rig->state.priv;
|
|
int ret, buf_len;
|
|
|
|
if (priv->meter_port.type.rig == RIG_PORT_UDP_NETWORK)
|
|
{
|
|
char buf[sizeof(float)*MAXMETERPTS * MAXRX];
|
|
buf_len = sizeof(buf);
|
|
|
|
ret = read_block(&priv->meter_port, buf, buf_len);
|
|
|
|
if (ret != buf_len)
|
|
{
|
|
ret = -RIG_EIO;
|
|
}
|
|
|
|
/* copy payload back to client space */
|
|
memcpy((void *) label, buf, sizeof(int));
|
|
memcpy((void *) data, buf + sizeof(int), npts * sizeof(float));
|
|
|
|
}
|
|
else
|
|
{
|
|
/* IPC */
|
|
buf_len = sizeof(int);
|
|
ret = read_block(&priv->meter_port, (char *)label, buf_len);
|
|
|
|
if (ret != buf_len)
|
|
{
|
|
ret = -RIG_EIO;
|
|
}
|
|
|
|
if (ret < 0)
|
|
{
|
|
return ret;
|
|
}
|
|
|
|
buf_len = sizeof(float) * npts;
|
|
|
|
if (sizeof(float) != 4)
|
|
{
|
|
rig_debug(RIG_DEBUG_ERR, "%s: sizeof(float)!=4, instead = %d\n", __func__,
|
|
(int)sizeof(float));
|
|
return -RIG_EINTERNAL;
|
|
}
|
|
|
|
ret = read_block(&priv->meter_port, (char *)(void *)data, buf_len);
|
|
|
|
if (ret != buf_len)
|
|
{
|
|
ret = -RIG_EIO;
|
|
}
|
|
|
|
if (ret < 0)
|
|
{
|
|
return ret;
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
|
|
/*
|
|
* Assumes rig!=NULL, rig->state.priv!=NULL
|
|
*/
|
|
int dttsp_set_conf(RIG *rig, token_t token, const char *val)
|
|
{
|
|
struct dttsp_priv_data *priv;
|
|
struct rig_state *rs;
|
|
|
|
rs = &rig->state;
|
|
priv = (struct dttsp_priv_data *)rs->priv;
|
|
|
|
switch (token)
|
|
{
|
|
case TOK_TUNER_MODEL:
|
|
priv->tuner_model = atoi(val);
|
|
break;
|
|
|
|
case TOK_SAMPLE_RATE:
|
|
priv->sample_rate = atoi(val);
|
|
break;
|
|
|
|
default:
|
|
|
|
/* if it's not for the dttsp backend, maybe it's for the tuner */
|
|
if (priv->tuner)
|
|
{
|
|
return rig_set_conf(priv->tuner, token, val);
|
|
}
|
|
else
|
|
{
|
|
return -RIG_EINVAL;
|
|
}
|
|
}
|
|
|
|
return RIG_OK;
|
|
}
|
|
|
|
/*
|
|
* assumes rig!=NULL,
|
|
* Assumes rig!=NULL, rig->state.priv!=NULL
|
|
* and val points to a buffer big enough to hold the conf value.
|
|
*/
|
|
int dttsp_get_conf(RIG *rig, token_t token, char *val)
|
|
{
|
|
struct dttsp_priv_data *priv;
|
|
struct rig_state *rs;
|
|
|
|
rs = &rig->state;
|
|
priv = (struct dttsp_priv_data *)rs->priv;
|
|
|
|
switch (token)
|
|
{
|
|
case TOK_TUNER_MODEL:
|
|
sprintf(val, "%u", priv->tuner_model);
|
|
break;
|
|
|
|
case TOK_SAMPLE_RATE:
|
|
sprintf(val, "%d", priv->sample_rate);
|
|
break;
|
|
|
|
default:
|
|
|
|
/* if it's not for the dttsp backend, maybe it's for the tuner */
|
|
if (priv->tuner)
|
|
{
|
|
return rig_get_conf(priv->tuner, token, val);
|
|
}
|
|
else
|
|
{
|
|
return -RIG_EINVAL;
|
|
}
|
|
}
|
|
|
|
return RIG_OK;
|
|
}
|
|
|
|
int dttsp_init(RIG *rig)
|
|
{
|
|
struct dttsp_priv_data *priv;
|
|
const char *cmdpath;
|
|
char *p;
|
|
|
|
rig_debug(RIG_DEBUG_VERBOSE, "%s called\n", __func__);
|
|
|
|
rig->state.priv = (struct dttsp_priv_data *)calloc(1,
|
|
sizeof(struct dttsp_priv_data));
|
|
|
|
if (!rig->state.priv)
|
|
{
|
|
return -RIG_ENOMEM;
|
|
}
|
|
|
|
priv = rig->state.priv;
|
|
|
|
priv->tuner = NULL;
|
|
priv->tuner_model = RIG_MODEL_DUMMY;
|
|
priv->IF_center_freq = 0;
|
|
|
|
|
|
p = getenv("SDR_DEFRATE");
|
|
|
|
if (p)
|
|
{
|
|
priv->sample_rate = atoi(p);
|
|
}
|
|
else
|
|
{
|
|
priv->sample_rate = DEFAULT_SAMPLE_RATE;
|
|
}
|
|
|
|
cmdpath = getenv("SDR_PARMPATH");
|
|
|
|
if (!cmdpath)
|
|
cmdpath = rig->state.rigport.type.rig == RIG_PORT_UDP_NETWORK ?
|
|
DEFAULT_DTTSP_CMD_NET_ADDR : DEFAULT_DTTSP_CMD_PATH;
|
|
|
|
strncpy(rig->state.rigport.pathname, cmdpath, HAMLIB_FILPATHLEN - 1);
|
|
|
|
return RIG_OK;
|
|
}
|
|
|
|
|
|
int dttsp_open(RIG *rig)
|
|
{
|
|
struct dttsp_priv_data *priv = (struct dttsp_priv_data *)rig->state.priv;
|
|
int ret;
|
|
char *p;
|
|
char *meterpath;
|
|
|
|
|
|
rig_debug(RIG_DEBUG_TRACE, "%s called\n", __func__);
|
|
|
|
/*
|
|
* prevent l8ps
|
|
*/
|
|
if (priv->tuner_model == RIG_MODEL_DTTSP ||
|
|
priv->tuner_model == RIG_MODEL_DTTSP_UDP)
|
|
{
|
|
return -RIG_ECONF;
|
|
}
|
|
|
|
priv->tuner = rig_init(priv->tuner_model);
|
|
|
|
if (!priv->tuner)
|
|
{
|
|
/* FIXME: wrong rig model? */
|
|
return -RIG_ENOMEM;
|
|
}
|
|
|
|
ret = rig_open(priv->tuner);
|
|
|
|
if (ret != RIG_OK)
|
|
{
|
|
rig_cleanup(priv->tuner);
|
|
priv->tuner = NULL;
|
|
return ret;
|
|
}
|
|
|
|
/* open DttSP meter pipe */
|
|
priv->meter_port.post_write_delay = rig->state.rigport.post_write_delay;
|
|
priv->meter_port.timeout = rig->state.rigport.timeout;
|
|
priv->meter_port.retry = rig->state.rigport.retry;
|
|
|
|
p = getenv("SDR_METERPATH");
|
|
|
|
if (!p)
|
|
{
|
|
meterpath = priv->meter_port.pathname;
|
|
snprintf(meterpath, HAMLIB_FILPATHLEN, "%s", rig->state.rigport.pathname);
|
|
|
|
if (rig->state.rigport.type.rig == RIG_PORT_UDP_NETWORK)
|
|
{
|
|
p = strrchr(meterpath, ':');
|
|
|
|
if (p)
|
|
{
|
|
strcpy(p + 1, "19003");
|
|
}
|
|
else
|
|
{
|
|
strcat(meterpath, ":19003");
|
|
}
|
|
|
|
p = meterpath;
|
|
}
|
|
else
|
|
{
|
|
p = strrchr(meterpath, '/');
|
|
|
|
if (p)
|
|
{
|
|
strcpy(p + 1, "SDRmeter");
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!p)
|
|
{
|
|
/* disabled */
|
|
priv->meter_port.fd = -1;
|
|
}
|
|
else
|
|
{
|
|
priv->meter_port.type.rig = rig->state.rigport.type.rig;
|
|
ret = port_open(&priv->meter_port);
|
|
|
|
if (ret < 0)
|
|
{
|
|
return ret;
|
|
}
|
|
}
|
|
|
|
|
|
/* TODO:
|
|
* copy priv->tuner->rx_range/tx_range to rig->state
|
|
*/
|
|
|
|
#if 1
|
|
rig->state.has_set_func |= priv->tuner->state.has_set_func;
|
|
rig->state.has_get_func |= priv->tuner->state.has_get_func;
|
|
rig->state.has_set_level |= priv->tuner->state.has_set_level;
|
|
rig->state.has_get_level |= priv->tuner->state.has_get_level;
|
|
rig->state.has_set_parm |= priv->tuner->state.has_set_parm;
|
|
rig->state.has_get_parm |= priv->tuner->state.has_get_parm;
|
|
#endif
|
|
|
|
|
|
/* Because model dummy has funky init value */
|
|
if (priv->tuner_model == RIG_MODEL_DUMMY)
|
|
{
|
|
dttsp_set_freq(rig, RIG_VFO_CURR, priv->IF_center_freq);
|
|
}
|
|
|
|
dttsp_set_func(rig, RIG_VFO_CURR, RIG_FUNC_MUTE, 0);
|
|
|
|
return RIG_OK;
|
|
}
|
|
|
|
|
|
int dttsp_close(RIG *rig)
|
|
{
|
|
struct dttsp_priv_data *priv = (struct dttsp_priv_data *)rig->state.priv;
|
|
|
|
rig_debug(RIG_DEBUG_VERBOSE, "%s called\n", __func__);
|
|
|
|
port_close(&priv->meter_port, priv->meter_port.type.rig);
|
|
rig_close(priv->tuner);
|
|
|
|
return RIG_OK;
|
|
}
|
|
|
|
int dttsp_cleanup(RIG *rig)
|
|
{
|
|
struct dttsp_priv_data *priv = (struct dttsp_priv_data *)rig->state.priv;
|
|
|
|
rig_debug(RIG_DEBUG_VERBOSE, "%s called\n", __func__);
|
|
|
|
if (priv && priv->tuner)
|
|
{
|
|
rig_cleanup(priv->tuner);
|
|
}
|
|
|
|
priv->tuner = NULL;
|
|
|
|
if (rig->state.priv)
|
|
{
|
|
free(rig->state.priv);
|
|
}
|
|
|
|
rig->state.priv = NULL;
|
|
|
|
return RIG_OK;
|
|
}
|
|
|
|
|
|
/*
|
|
* rig_set_freq is a good candidate for the GNUradio GUI setFrequency callback?
|
|
*/
|
|
int dttsp_set_freq(RIG *rig, vfo_t vfo, freq_t freq)
|
|
{
|
|
struct dttsp_priv_data *priv = (struct dttsp_priv_data *)rig->state.priv;
|
|
freq_t tuner_freq;
|
|
int ret;
|
|
char fstr[20];
|
|
char buf[32];
|
|
int buf_len;
|
|
shortfreq_t max_delta;
|
|
freq_t freq_offset;
|
|
|
|
max_delta = priv->sample_rate / 2 - kHz(2);
|
|
|
|
sprintf_freq(fstr, sizeof(fstr), freq);
|
|
rig_debug(RIG_DEBUG_TRACE, "%s called: %s %s\n",
|
|
__func__, rig_strvfo(vfo), fstr);
|
|
|
|
ret = rig_get_freq(priv->tuner, RIG_VFO_CURR, &tuner_freq);
|
|
|
|
if (ret != RIG_OK)
|
|
{
|
|
return ret;
|
|
}
|
|
|
|
freq_offset = freq - tuner_freq;
|
|
|
|
/* TODO: take into account the mode width and the IF dead zone */
|
|
if (fabs(freq_offset) > max_delta)
|
|
{
|
|
tuner_freq = priv->IF_center_freq + freq - kHz(6);
|
|
ret = rig_set_freq(priv->tuner, RIG_VFO_CURR, tuner_freq);
|
|
|
|
if (ret != RIG_OK)
|
|
{
|
|
return ret;
|
|
}
|
|
|
|
/* reread the tuner freq because some rigs can't tune to exact frequency.
|
|
* The rx_delta_f will correct that */
|
|
ret = rig_get_freq(priv->tuner, RIG_VFO_CURR, &tuner_freq);
|
|
|
|
if (ret != RIG_OK)
|
|
{
|
|
return ret;
|
|
}
|
|
}
|
|
|
|
priv->rx_delta_f = freq - tuner_freq;
|
|
|
|
sprintf_freq(fstr, sizeof(fstr), tuner_freq);
|
|
rig_debug(RIG_DEBUG_TRACE, "%s: tuner=%s, rx_delta=%d Hz\n",
|
|
__func__, fstr, priv->rx_delta_f);
|
|
|
|
/* setRxFrequenc */
|
|
buf_len = sprintf(buf, "setOsc %d\n", priv->rx_delta_f);
|
|
ret = send_command(rig, buf, buf_len);
|
|
|
|
return ret;
|
|
}
|
|
|
|
|
|
int dttsp_get_freq(RIG *rig, vfo_t vfo, freq_t *freq)
|
|
{
|
|
struct dttsp_priv_data *priv = (struct dttsp_priv_data *)rig->state.priv;
|
|
freq_t tuner_freq;
|
|
int ret;
|
|
|
|
ret = rig_get_freq(priv->tuner, RIG_VFO_CURR, &tuner_freq);
|
|
|
|
if (ret != RIG_OK)
|
|
{
|
|
return ret;
|
|
}
|
|
|
|
rig_debug(RIG_DEBUG_TRACE, "%s called\n", __func__);
|
|
|
|
*freq = tuner_freq - priv->rx_delta_f;
|
|
|
|
return RIG_OK;
|
|
}
|
|
|
|
static enum dttsp_mode_e rmode2dttsp(rmode_t mode)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < HAMLIB_VS_DTTSP_MODES_COUNT; i++)
|
|
{
|
|
if (hamlib_vs_dttsp_modes[i].hamlib_mode == mode)
|
|
{
|
|
return hamlib_vs_dttsp_modes[i].dttsp_mode;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* WIP
|
|
*/
|
|
int dttsp_set_mode(RIG *rig, vfo_t vfo, rmode_t mode, pbwidth_t width)
|
|
{
|
|
char buf[32];
|
|
int buf_len;
|
|
int ret = RIG_OK;
|
|
int filter_l, filter_h;
|
|
|
|
/* DttSP set mode */
|
|
|
|
buf_len = sprintf(buf, "setMode %d\n", rmode2dttsp(mode));
|
|
ret = send_command(rig, buf, buf_len);
|
|
|
|
rig_debug(RIG_DEBUG_VERBOSE, "%s: %s\n",
|
|
__func__, buf);
|
|
|
|
if (ret != RIG_OK || RIG_PASSBAND_NOCHANGE == width) { return ret; }
|
|
|
|
if (width == RIG_PASSBAND_NORMAL)
|
|
{
|
|
width = rig_passband_normal(rig, mode);
|
|
}
|
|
|
|
sprintf_freq(buf, sizeof(buf), width);
|
|
rig_debug(RIG_DEBUG_VERBOSE, "%s called: %s %s\n",
|
|
__func__, rig_strrmode(mode), buf);
|
|
|
|
switch (mode)
|
|
{
|
|
case RIG_MODE_USB:
|
|
case RIG_MODE_CW:
|
|
filter_l = 10;
|
|
filter_h = width;
|
|
break;
|
|
|
|
case RIG_MODE_LSB:
|
|
case RIG_MODE_CWR:
|
|
filter_l = -width;
|
|
filter_h = -10;
|
|
break;
|
|
|
|
case RIG_MODE_AM:
|
|
case RIG_MODE_SAM:
|
|
case RIG_MODE_FM:
|
|
case RIG_MODE_DSB:
|
|
filter_l = -width / 2;
|
|
filter_h = width / 2;
|
|
break;
|
|
|
|
default:
|
|
return -RIG_EINVAL;
|
|
}
|
|
|
|
buf_len = sprintf(buf, "setFilter %d %d\n", filter_l, filter_h);
|
|
ret = send_command(rig, buf, buf_len);
|
|
|
|
rig_debug(RIG_DEBUG_VERBOSE, "%s: %s\n",
|
|
__func__, buf);
|
|
|
|
return ret;
|
|
}
|
|
|
|
|
|
static int agc_level2dttsp(enum agc_level_e agc)
|
|
{
|
|
switch (agc)
|
|
{
|
|
case RIG_AGC_OFF: return 0;
|
|
|
|
case RIG_AGC_SLOW: return 2;
|
|
|
|
case RIG_AGC_MEDIUM: return 3;
|
|
|
|
case RIG_AGC_FAST: return 4;
|
|
|
|
default:
|
|
return 0;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
/*
|
|
*/
|
|
int dttsp_set_level(RIG *rig, vfo_t vfo, setting_t level, value_t val)
|
|
{
|
|
struct dttsp_priv_data *priv = (struct dttsp_priv_data *)rig->state.priv;
|
|
int ret = RIG_OK;
|
|
int buf_len;
|
|
char buf[32];
|
|
|
|
switch (level)
|
|
{
|
|
case RIG_LEVEL_AGC:
|
|
buf_len = sprintf(buf, "setRXAGC %d\n", agc_level2dttsp(val.i));
|
|
ret = send_command(rig, buf, buf_len);
|
|
break;
|
|
|
|
default:
|
|
rig_debug(RIG_DEBUG_TRACE, "%s: level %s, try tuner\n",
|
|
__func__, rig_strlevel(level));
|
|
return rig_set_level(priv->tuner, vfo, level, val);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
|
|
int dttsp_get_level(RIG *rig, vfo_t vfo, setting_t level, value_t *val)
|
|
{
|
|
struct dttsp_priv_data *priv = (struct dttsp_priv_data *)rig->state.priv;
|
|
int ret = RIG_OK;
|
|
int buf_len;
|
|
char buf[32];
|
|
float rxm[MAXRX][RXMETERPTS];
|
|
|
|
rig_debug(RIG_DEBUG_VERBOSE, "%s called: %s\n", __func__,
|
|
rig_strlevel(level));
|
|
|
|
switch (level)
|
|
{
|
|
case RIG_LEVEL_RAWSTR:
|
|
case RIG_LEVEL_STRENGTH:
|
|
buf_len = sprintf(buf, "reqRXMeter %d\n", getpid());
|
|
ret = send_command(rig, buf, buf_len);
|
|
|
|
if (ret < 0)
|
|
{
|
|
return ret;
|
|
}
|
|
|
|
ret = fetch_meter(rig, (int *)buf, (float *)rxm, MAXRX * RXMETERPTS);
|
|
|
|
if (ret < 0)
|
|
{
|
|
return ret;
|
|
}
|
|
|
|
val->i = (int)rxm[0][0];
|
|
|
|
if (level == RIG_LEVEL_STRENGTH)
|
|
{
|
|
val->i = (int)rig_raw2val(val->i, &rig->state.str_cal);
|
|
}
|
|
|
|
ret = RIG_OK;
|
|
break;
|
|
|
|
default:
|
|
rig_debug(RIG_DEBUG_TRACE, "%s: level %s, try tuner\n",
|
|
__func__, rig_strlevel(level));
|
|
return rig_get_level(priv->tuner, vfo, level, val);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
int dttsp_set_func(RIG *rig, vfo_t vfo, setting_t func, int status)
|
|
{
|
|
struct dttsp_priv_data *priv = (struct dttsp_priv_data *)rig->state.priv;
|
|
char buf[32];
|
|
const char *cmd;
|
|
int buf_len;
|
|
int ret;
|
|
|
|
status = status ? 1 : 0;
|
|
|
|
switch (func)
|
|
{
|
|
case RIG_FUNC_MUTE:
|
|
cmd = "setRunState";
|
|
status = status ? 0 : 2;
|
|
break;
|
|
|
|
case RIG_FUNC_NB:
|
|
cmd = "setNB";
|
|
break;
|
|
|
|
case RIG_FUNC_ANF:
|
|
cmd = "setANF";
|
|
break;
|
|
|
|
case RIG_FUNC_NR:
|
|
cmd = "setNR";
|
|
break;
|
|
|
|
default:
|
|
rig_debug(RIG_DEBUG_TRACE, "%s: func %s, try tuner\n",
|
|
__func__, rig_strfunc(func));
|
|
return rig_set_func(priv->tuner, vfo, func, status);
|
|
}
|
|
|
|
buf_len = sprintf(buf, "%s %d\n", cmd, status);
|
|
ret = send_command(rig, buf, buf_len);
|
|
|
|
return ret;
|
|
}
|
|
|
|
|
|
/*
|
|
* TODO
|
|
*/
|
|
int dttsp_set_rit(RIG *rig, vfo_t vfo, shortfreq_t rit)
|
|
{
|
|
rig_debug(RIG_DEBUG_VERBOSE, "%s called\n", __func__);
|
|
|
|
|
|
return -RIG_ENIMPL;
|
|
}
|
|
|
|
|
|
int dttsp_get_rit(RIG *rig, vfo_t vfo, shortfreq_t *rit)
|
|
{
|
|
rig_debug(RIG_DEBUG_VERBOSE, "%s called\n", __func__);
|
|
|
|
return -RIG_ENIMPL;
|
|
}
|
|
|
|
|
|
int dttsp_set_ant(RIG *rig, vfo_t vfo, ant_t ant, value_t option)
|
|
{
|
|
struct dttsp_priv_data *priv = (struct dttsp_priv_data *)rig->state.priv;
|
|
|
|
rig_debug(RIG_DEBUG_TRACE, "%s: ant %u, try tuner\n",
|
|
__func__, ant);
|
|
|
|
return rig_set_ant(priv->tuner, vfo, ant, option);
|
|
}
|
|
|