kopia lustrzana https://github.com/Hamlib/Hamlib
1231 wiersze
30 KiB
C
1231 wiersze
30 KiB
C
/*
|
|
i Hamlib TRXManager backend - main file
|
|
* Copyright (c) 2018 by Michael Black W9MDB
|
|
* Derived from flrig.c
|
|
*
|
|
*
|
|
* 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 <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h> /* String function definitions */
|
|
#include <unistd.h> /* UNIX standard function definitions */
|
|
#include <math.h>
|
|
|
|
#include <hamlib/rig.h>
|
|
#include <serial.h>
|
|
#include <misc.h>
|
|
#include <cal.h>
|
|
#include <token.h>
|
|
#include <register.h>
|
|
#include <network.h>
|
|
|
|
#include "trxmanager.h"
|
|
|
|
#define DEBUG_TRACE DEBUG_VERBOSE
|
|
|
|
#define MAXCMDLEN 64
|
|
|
|
#define DEFAULTPATH "127.0.0.1:1003"
|
|
|
|
#define TRXMANAGER_VFOS (RIG_VFO_A|RIG_VFO_B)
|
|
|
|
#define TRXMANAGER_MODES (RIG_MODE_AM | RIG_MODE_CW | RIG_MODE_CWR |\
|
|
RIG_MODE_RTTY | RIG_MODE_RTTYR |\
|
|
RIG_MODE_PKTLSB | RIG_MODE_PKTUSB |\
|
|
RIG_MODE_USB | RIG_MODE_LSB | RIG_MODE_FM)
|
|
|
|
#define streq(s1,s2) (strcmp(s1,s2)==0)
|
|
|
|
#define FLRIG_MODE_LSB '1'
|
|
#define FLRIG_MODE_USB '2'
|
|
#define FLRIG_MODE_CW '3'
|
|
#define FLRIG_MODE_FM '4'
|
|
#define FLRIG_MODE_AM '5'
|
|
#define FLRIG_MODE_RTTY '6'
|
|
#define FLRIG_MODE_CWR '7'
|
|
#define FLRIG_MODE_RTTYR '9'
|
|
#define FLRIG_MODE_PKTLSB 'C'
|
|
#define FLRIG_MODE_PKTUSB 'D'
|
|
#define FLRIG_MODE_PKTFM 'E'
|
|
#define FLRIG_MODE_PKTAM 'F'
|
|
// Hamlib doesn't support D2/D3 modes in hamlib yet
|
|
// So we define them here but they aren't implemented
|
|
#define FLRIG_MODE_PKTLSB2 'G'
|
|
#define FLRIG_MODE_PKTUSB2 'H'
|
|
#define FLRIG_MODE_PKTFM2 'I'
|
|
#define FLRIG_MODE_PKTAM2 'J'
|
|
#define FLRIG_MODE_PKTLSB3 'K'
|
|
#define FLRIG_MODE_PKTUSB3 'L'
|
|
#define FLRIG_MODE_PKTFM3 'M'
|
|
#define FLRIG_MODE_PKTAM3 'N'
|
|
|
|
static int trxmanager_init(RIG *rig);
|
|
static int trxmanager_open(RIG *rig);
|
|
static int trxmanager_close(RIG *rig);
|
|
static int trxmanager_cleanup(RIG *rig);
|
|
static int trxmanager_set_freq(RIG *rig, vfo_t vfo, freq_t freq);
|
|
static int trxmanager_get_freq(RIG *rig, vfo_t vfo, freq_t *freq);
|
|
static int trxmanager_set_ptt(RIG *rig, vfo_t vfo, ptt_t ptt);
|
|
static int trxmanager_set_mode(RIG *rig, vfo_t vfo, rmode_t mode,
|
|
pbwidth_t width);
|
|
static int trxmanager_set_split_mode(RIG *rig, vfo_t vfo, rmode_t mode,
|
|
pbwidth_t width);
|
|
static int trxmanager_get_mode(RIG *rig, vfo_t vfo, rmode_t *mode,
|
|
pbwidth_t *width);
|
|
static int trxmanager_get_vfo(RIG *rig, vfo_t *vfo);
|
|
static int trxmanager_set_vfo(RIG *rig, vfo_t vfo);
|
|
static int trxmanager_set_ptt(RIG *rig, vfo_t vfo, ptt_t ptt);
|
|
static int trxmanager_get_ptt(RIG *rig, vfo_t vfo, ptt_t *ptt);
|
|
static int trxmanager_set_split_freq(RIG *rig, vfo_t vfo, freq_t tx_freq);
|
|
static int trxmanager_get_split_freq(RIG *rig, vfo_t vfo, freq_t *tx_freq);
|
|
static int trxmanager_set_split_vfo(RIG *rig, vfo_t vfo, split_t split,
|
|
vfo_t tx_vfo);
|
|
static int trxmanager_get_split_vfo(RIG *rig, vfo_t vfo, split_t *split,
|
|
vfo_t *tx_vfo);
|
|
static int trxmanager_set_split_freq_mode(RIG *rig, vfo_t vfo, freq_t freq,
|
|
rmode_t mode, pbwidth_t width);
|
|
static int trxmanager_get_split_freq_mode(RIG *rig, vfo_t vfo, freq_t *freq,
|
|
rmode_t *mode, pbwidth_t *width);
|
|
|
|
static const char *trxmanager_get_info(RIG *rig);
|
|
|
|
struct trxmanager_priv_data
|
|
{
|
|
vfo_t vfo_curr;
|
|
char info[100];
|
|
split_t split;
|
|
};
|
|
|
|
struct rig_caps trxmanager_caps =
|
|
{
|
|
RIG_MODEL(RIG_MODEL_TRXMANAGER_RIG),
|
|
.model_name = "5.7.630+",
|
|
.mfg_name = "TRXManager",
|
|
.version = BACKEND_VER ".0",
|
|
.copyright = "LGPL",
|
|
.status = RIG_STATUS_STABLE,
|
|
.rig_type = RIG_TYPE_TRANSCEIVER,
|
|
.targetable_vfo = RIG_TARGETABLE_FREQ,
|
|
.ptt_type = RIG_PTT_RIG,
|
|
.port_type = RIG_PORT_NETWORK,
|
|
.write_delay = 0,
|
|
.post_write_delay = 0,
|
|
.timeout = 10000, // long timeout to allow for antenna tuning and such
|
|
.retry = 3,
|
|
|
|
.has_get_func = RIG_FUNC_NONE,
|
|
.has_set_func = RIG_FUNC_NONE,
|
|
.has_get_level = RIG_LEVEL_NONE,
|
|
.has_set_level = RIG_LEVEL_NONE,
|
|
.has_get_parm = RIG_PARM_NONE,
|
|
.has_set_parm = RIG_PARM_NONE,
|
|
.filters = {
|
|
RIG_FLT_END
|
|
},
|
|
|
|
.rx_range_list1 = {{
|
|
.startf = kHz(1), .endf = GHz(10), .modes = TRXMANAGER_MODES,
|
|
.low_power = -1, .high_power = -1, TRXMANAGER_VFOS, RIG_ANT_1
|
|
},
|
|
RIG_FRNG_END,
|
|
},
|
|
.tx_range_list1 = {RIG_FRNG_END,},
|
|
.rx_range_list2 = {{
|
|
.startf = kHz(1), .endf = GHz(10), .modes = TRXMANAGER_MODES,
|
|
.low_power = -1, .high_power = -1, TRXMANAGER_VFOS, RIG_ANT_1
|
|
},
|
|
RIG_FRNG_END,
|
|
},
|
|
.tx_range_list2 = {RIG_FRNG_END,},
|
|
.tuning_steps = { {TRXMANAGER_MODES, 1}, {TRXMANAGER_MODES, RIG_TS_ANY}, RIG_TS_END, },
|
|
.priv = NULL, /* priv */
|
|
|
|
.rig_init = trxmanager_init,
|
|
.rig_open = trxmanager_open,
|
|
.rig_close = trxmanager_close,
|
|
.rig_cleanup = trxmanager_cleanup,
|
|
|
|
.set_freq = trxmanager_set_freq,
|
|
.get_freq = trxmanager_get_freq,
|
|
.set_mode = trxmanager_set_mode,
|
|
.get_mode = trxmanager_get_mode,
|
|
.set_vfo = trxmanager_set_vfo,
|
|
.get_vfo = trxmanager_get_vfo,
|
|
.get_info = trxmanager_get_info,
|
|
.set_ptt = trxmanager_set_ptt,
|
|
.get_ptt = trxmanager_get_ptt,
|
|
.set_split_mode = trxmanager_set_split_mode,
|
|
.set_split_freq = trxmanager_set_split_freq,
|
|
.get_split_freq = trxmanager_get_split_freq,
|
|
.set_split_vfo = trxmanager_set_split_vfo,
|
|
.get_split_vfo = trxmanager_get_split_vfo,
|
|
.set_split_freq_mode = trxmanager_set_split_freq_mode,
|
|
.get_split_freq_mode = trxmanager_get_split_freq_mode
|
|
};
|
|
|
|
/*
|
|
* check_vfo
|
|
* No assumptions
|
|
*/
|
|
static int check_vfo(vfo_t vfo)
|
|
{
|
|
switch (vfo)
|
|
{
|
|
case RIG_VFO_A:
|
|
break;
|
|
|
|
case RIG_VFO_TX:
|
|
case RIG_VFO_B:
|
|
break;
|
|
|
|
case RIG_VFO_CURR:
|
|
break; // will default to A in which_vfo
|
|
|
|
default:
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
#if 0 // looks like we don't need this but it's here just in case
|
|
/*
|
|
* vfo_curr
|
|
* Assumes rig!=NULL
|
|
*/
|
|
static int vfo_curr(RIG *rig, vfo_t vfo)
|
|
{
|
|
int retval = 0;
|
|
vfo_t vfocurr;
|
|
struct trxmanager_priv_data *priv = (struct trxmanager_priv_data *)
|
|
rig->state.priv;
|
|
|
|
// get the current VFO from trxmanager in case user changed it
|
|
if ((retval = trxmanager_get_vfo(rig, &vfocurr)) != RIG_OK)
|
|
{
|
|
return retval;
|
|
}
|
|
|
|
priv->vfo_curr = vfocurr;
|
|
retval = (vfo == vfocurr);
|
|
return retval;
|
|
}
|
|
#endif
|
|
|
|
/*
|
|
* read_transaction
|
|
* Assumes rig!=NULL, response!=NULL, response_len>=MAXCMDLEN
|
|
*/
|
|
static int read_transaction(RIG *rig, char *response, int response_len)
|
|
{
|
|
struct rig_state *rs = &rig->state;
|
|
char *delims = "\n";
|
|
int len;
|
|
|
|
rig_debug(RIG_DEBUG_TRACE, "%s\n", __func__);
|
|
|
|
len = read_string(&rs->rigport, response, response_len, delims,
|
|
strlen(delims));
|
|
|
|
if (len <= 0)
|
|
{
|
|
rig_debug(RIG_DEBUG_ERR, "%s: read_string error=%d\n", __func__, len);
|
|
return -RIG_EPROTO;
|
|
}
|
|
|
|
return RIG_OK;
|
|
}
|
|
|
|
/*
|
|
* trxmanager_init
|
|
* Assumes rig!=NULL
|
|
*/
|
|
static int trxmanager_init(RIG *rig)
|
|
{
|
|
struct trxmanager_priv_data *priv;
|
|
|
|
rig_debug(RIG_DEBUG_TRACE, "%s version %s\n", __func__, BACKEND_VER);
|
|
|
|
rig->state.priv = (struct trxmanager_priv_data *)malloc(
|
|
sizeof(struct trxmanager_priv_data));
|
|
|
|
if (!rig->state.priv)
|
|
{
|
|
return -RIG_ENOMEM;
|
|
}
|
|
|
|
priv = rig->state.priv;
|
|
|
|
memset(priv, 0, sizeof(struct trxmanager_priv_data));
|
|
|
|
/*
|
|
* set arbitrary initial status
|
|
*/
|
|
priv->vfo_curr = RIG_VFO_A;
|
|
priv->split = 0;
|
|
|
|
if (!rig->caps)
|
|
{
|
|
return -RIG_EINVAL;
|
|
}
|
|
|
|
strncpy(rig->state.rigport.pathname, DEFAULTPATH,
|
|
sizeof(rig->state.rigport.pathname));
|
|
|
|
return RIG_OK;
|
|
}
|
|
|
|
/*
|
|
* trxmanager_open
|
|
* Assumes rig!=NULL, rig->state.priv!=NULL
|
|
*/
|
|
static int trxmanager_open(RIG *rig)
|
|
{
|
|
int retval;
|
|
char *cmd;
|
|
char *saveptr;
|
|
char response[MAXCMDLEN] = "";
|
|
struct rig_state *rs = &rig->state;
|
|
struct trxmanager_priv_data *priv = (struct trxmanager_priv_data *)
|
|
rig->state.priv;
|
|
|
|
rig_debug(RIG_DEBUG_VERBOSE, "%s version %s\n", __func__, BACKEND_VER);
|
|
|
|
rs->rigport.timeout = 10000; // long timeout for antenna switching/tuning
|
|
retval = read_transaction(rig, response, sizeof(response));
|
|
|
|
if (retval != RIG_OK)
|
|
{
|
|
rig_debug(RIG_DEBUG_ERR, "%s read_transaction failed\n", __func__);
|
|
}
|
|
|
|
if (strlen(response) == 0)
|
|
{
|
|
rig_debug(RIG_DEBUG_ERR, "%s response len==0\n", __func__);
|
|
return -RIG_EPROTO;
|
|
}
|
|
|
|
// Should have rig info now
|
|
strtok_r(response, ";\r\n", &saveptr);
|
|
strncpy(priv->info, &response[2], sizeof(priv->info));
|
|
rig_debug(RIG_DEBUG_VERBOSE, "%s connected to %s\n", __func__, priv->info);
|
|
|
|
// Turn off active messages
|
|
cmd = "AI0;";
|
|
retval = write_block(&rs->rigport, cmd, strlen(cmd));
|
|
|
|
if (retval < 0)
|
|
{
|
|
return retval;
|
|
}
|
|
|
|
retval = read_transaction(rig, response, sizeof(response));
|
|
|
|
if (retval != RIG_OK)
|
|
{
|
|
rig_debug(RIG_DEBUG_ERR, "%s read_transaction failed\n", __func__);
|
|
}
|
|
|
|
if (strncmp("AI0;", response, 4) != 0)
|
|
{
|
|
rig_debug(RIG_DEBUG_ERR, "%s AI invalid response=%s\n", __func__, response);
|
|
return -RIG_EINVAL;
|
|
}
|
|
|
|
rig_debug(RIG_DEBUG_VERBOSE, "%s AI response=%s\n", __func__, response);
|
|
|
|
cmd = "FN;";
|
|
retval = write_block(&rs->rigport, cmd, strlen(cmd));
|
|
|
|
if (retval != RIG_OK)
|
|
{
|
|
rig_debug(RIG_DEBUG_ERR, "%s FN; write failed\n", __func__);
|
|
}
|
|
|
|
retval = read_transaction(rig, response, sizeof(response));
|
|
|
|
if (retval != RIG_OK)
|
|
{
|
|
rig_debug(RIG_DEBUG_ERR, "%s read_transaction failed\n", __func__);
|
|
}
|
|
|
|
rig_debug(RIG_DEBUG_VERBOSE, "%s FN response=%s\n", __func__, response);
|
|
priv->vfo_curr = RIG_VFO_A;
|
|
|
|
return retval;
|
|
}
|
|
|
|
/*
|
|
* trxmanager_close
|
|
* Assumes rig!=NULL
|
|
*/
|
|
static int trxmanager_close(RIG *rig)
|
|
{
|
|
rig_debug(RIG_DEBUG_TRACE, "%s\n", __func__);
|
|
return RIG_OK;
|
|
}
|
|
|
|
/*
|
|
* trxmanager_cleanup
|
|
* Assumes rig!=NULL, rig->state.priv!=NULL
|
|
*/
|
|
static int trxmanager_cleanup(RIG *rig)
|
|
{
|
|
|
|
if (!rig)
|
|
{
|
|
return -RIG_EINVAL;
|
|
}
|
|
|
|
free(rig->state.priv);
|
|
rig->state.priv = NULL;
|
|
|
|
return RIG_OK;
|
|
}
|
|
|
|
/*
|
|
* trxmanager_get_freq
|
|
* Assumes rig!=NULL, rig->state.priv!=NULL, freq!=NULL
|
|
*/
|
|
static int trxmanager_get_freq(RIG *rig, vfo_t vfo, freq_t *freq)
|
|
{
|
|
int retval;
|
|
int n;
|
|
char vfoab;
|
|
char cmd[MAXCMDLEN];
|
|
char response[MAXCMDLEN] = "";
|
|
struct rig_state *rs = &rig->state;
|
|
struct trxmanager_priv_data *priv = (struct trxmanager_priv_data *)
|
|
rig->state.priv;
|
|
|
|
rig_debug(RIG_DEBUG_TRACE, "%s: vfo=%s\n", __func__,
|
|
rig_strvfo(vfo));
|
|
|
|
if (check_vfo(vfo) == FALSE)
|
|
{
|
|
rig_debug(RIG_DEBUG_ERR, "%s: unsupported VFO %s\n",
|
|
__func__, rig_strvfo(vfo));
|
|
return -RIG_EINVAL;
|
|
}
|
|
|
|
if (vfo == RIG_VFO_CURR)
|
|
{
|
|
if ((retval = trxmanager_get_vfo(rig, &vfo)) != RIG_OK)
|
|
{
|
|
return retval;
|
|
}
|
|
|
|
priv->vfo_curr = vfo;
|
|
|
|
rig_debug(RIG_DEBUG_VERBOSE, "%s: get_freq2 vfo=%s\n",
|
|
__func__, rig_strvfo(vfo));
|
|
}
|
|
|
|
vfoab = vfo == RIG_VFO_A ? 'R' : 'T';
|
|
snprintf(cmd, sizeof(cmd), "X%c;", vfoab);
|
|
retval = write_block(&rs->rigport, cmd, strlen(cmd));
|
|
|
|
if (retval < 0)
|
|
{
|
|
return retval;
|
|
}
|
|
|
|
retval = read_transaction(rig, response, sizeof(response));
|
|
|
|
if (retval != RIG_OK)
|
|
{
|
|
rig_debug(RIG_DEBUG_ERR, "%s read_transaction failed\n", __func__);
|
|
}
|
|
|
|
*freq = 0;
|
|
n = sscanf(&response[2], "%lg", freq);
|
|
|
|
if (n != 1)
|
|
{
|
|
rig_debug(RIG_DEBUG_ERR, "%s: can't parse freq from %s", __func__, response);
|
|
}
|
|
|
|
if (*freq == 0)
|
|
{
|
|
rig_debug(RIG_DEBUG_ERR, "%s: freq==0??\n", __func__);
|
|
return -RIG_EPROTO;
|
|
}
|
|
|
|
return retval;
|
|
}
|
|
|
|
/*
|
|
* trxmanager_set_freq
|
|
* assumes rig!=NULL, rig->state.priv!=NULL
|
|
*/
|
|
static int trxmanager_set_freq(RIG *rig, vfo_t vfo, freq_t freq)
|
|
{
|
|
int retval;
|
|
char vfoab;
|
|
char cmd[MAXCMDLEN];
|
|
char response[MAXCMDLEN] = "";
|
|
struct rig_state *rs = &rig->state;
|
|
struct trxmanager_priv_data *priv = (struct trxmanager_priv_data *)
|
|
rig->state.priv;
|
|
|
|
|
|
rig_debug(RIG_DEBUG_TRACE, "%s: vfo=%s freq=%.1f\n", __func__,
|
|
rig_strvfo(vfo), freq);
|
|
|
|
if (check_vfo(vfo) == FALSE)
|
|
{
|
|
rig_debug(RIG_DEBUG_ERR, "%s: unsupported VFO %s\n",
|
|
__func__, rig_strvfo(vfo));
|
|
return -RIG_EINVAL;
|
|
}
|
|
|
|
if (vfo == RIG_VFO_CURR)
|
|
{
|
|
if ((retval = trxmanager_get_vfo(rig, &vfo)) != RIG_OK)
|
|
{
|
|
return retval;
|
|
}
|
|
}
|
|
else if (vfo == RIG_VFO_TX && priv->split)
|
|
{
|
|
vfo = RIG_VFO_B; // if split always TX on VFOB
|
|
}
|
|
|
|
vfoab = vfo == RIG_VFO_A ? 'A' : 'B';
|
|
snprintf(cmd, sizeof(cmd), "F%c%011lu;", vfoab, (unsigned long)freq);
|
|
retval = write_block(&rs->rigport, cmd, strlen(cmd));
|
|
|
|
if (retval < 0)
|
|
{
|
|
return retval;
|
|
}
|
|
|
|
retval = read_transaction(rig, response,
|
|
sizeof(response)); // get response but don't care
|
|
|
|
if (retval != RIG_OK)
|
|
{
|
|
rig_debug(RIG_DEBUG_ERR, "%s read_transaction failed\n", __func__);
|
|
}
|
|
|
|
return RIG_OK;
|
|
}
|
|
|
|
/*
|
|
* trxmanager_set_ptt
|
|
* Assumes rig!=NULL
|
|
*/
|
|
static int trxmanager_set_ptt(RIG *rig, vfo_t vfo, ptt_t ptt)
|
|
{
|
|
int retval;
|
|
char cmd[MAXCMDLEN];
|
|
char response[MAXCMDLEN] = "";
|
|
struct rig_state *rs = &rig->state;
|
|
|
|
rig_debug(RIG_DEBUG_TRACE, "%s: ptt=%d\n", __func__, ptt);
|
|
|
|
if (check_vfo(vfo) == FALSE)
|
|
{
|
|
rig_debug(RIG_DEBUG_ERR, "%s: unsupported VFO %s\n",
|
|
__func__, rig_strvfo(vfo));
|
|
return -RIG_EINVAL;
|
|
}
|
|
|
|
snprintf(cmd, sizeof(cmd), "%s;", ptt == 1 ? "TX" : "RX");
|
|
retval = write_block(&rs->rigport, cmd, strlen(cmd));
|
|
|
|
if (retval < 0)
|
|
{
|
|
return retval;
|
|
}
|
|
|
|
retval = read_transaction(rig, response, sizeof(response));
|
|
|
|
if (retval != RIG_OK)
|
|
{
|
|
rig_debug(RIG_DEBUG_ERR, "%s read_transaction failed\n", __func__);
|
|
}
|
|
|
|
if (strlen(response) != 5 || strstr(response, cmd) == NULL)
|
|
{
|
|
rig_debug(RIG_DEBUG_ERR, "%s invalid response='%s'\n", __func__, response);
|
|
return -RIG_EPROTO;
|
|
}
|
|
|
|
return RIG_OK;
|
|
}
|
|
|
|
/*
|
|
* trxmanager_get_ptt
|
|
* Assumes rig!=NULL ptt!=NULL
|
|
*/
|
|
static int trxmanager_get_ptt(RIG *rig, vfo_t vfo, ptt_t *ptt)
|
|
{
|
|
int retval;
|
|
char cptt;
|
|
char cmd[MAXCMDLEN];
|
|
char response[MAXCMDLEN] = "";
|
|
struct rig_state *rs = &rig->state;
|
|
|
|
rig_debug(RIG_DEBUG_TRACE, "%s: vfo=%s\n", __func__,
|
|
rig_strvfo(vfo));
|
|
|
|
snprintf(cmd, sizeof(cmd), "IF;");
|
|
retval = write_block(&rs->rigport, cmd, strlen(cmd));
|
|
|
|
if (retval < 0)
|
|
{
|
|
return retval;
|
|
}
|
|
|
|
retval = read_transaction(rig, response, sizeof(response));
|
|
|
|
if (retval != RIG_OK)
|
|
{
|
|
rig_debug(RIG_DEBUG_ERR, "%s read_transaction failed\n", __func__);
|
|
}
|
|
|
|
if (strlen(response) != 40)
|
|
{
|
|
rig_debug(RIG_DEBUG_ERR, "%s: invalid response='%s'\n", __func__, response);
|
|
return -RIG_EPROTO;
|
|
}
|
|
|
|
rig_debug(RIG_DEBUG_VERBOSE, "%s: IF response len=%d\n", __func__,
|
|
(int)strlen(response));
|
|
cptt = response[28];
|
|
*ptt = cptt == '0' ? 0 : 1;
|
|
|
|
return RIG_OK;
|
|
}
|
|
|
|
/*
|
|
* trxmanager_set_split_mode
|
|
* Assumes rig!=NULL
|
|
*/
|
|
static int trxmanager_set_split_mode(RIG *rig, vfo_t vfo, rmode_t mode,
|
|
pbwidth_t width)
|
|
{
|
|
int retval;
|
|
rig_debug(RIG_DEBUG_TRACE, "%s: vfo=%s mode=%s width=%d\n",
|
|
__func__, rig_strvfo(vfo), rig_strrmode(mode), (int)width);
|
|
retval = trxmanager_set_mode(rig, RIG_VFO_B, mode, width);
|
|
return retval;
|
|
}
|
|
|
|
/*
|
|
* trxmanager_set_mode
|
|
* Assumes rig!=NULL
|
|
*/
|
|
static int trxmanager_set_mode(RIG *rig, vfo_t vfo, rmode_t mode,
|
|
pbwidth_t width)
|
|
{
|
|
int retval;
|
|
char ttmode;
|
|
char cmd[MAXCMDLEN];
|
|
char response[MAXCMDLEN] = "";
|
|
struct rig_state *rs = &rig->state;
|
|
|
|
rig_debug(RIG_DEBUG_TRACE, "%s: vfo=%s mode=%s width=%d\n",
|
|
__func__, rig_strvfo(vfo), rig_strrmode(mode), (int)width);
|
|
|
|
if (check_vfo(vfo) == FALSE)
|
|
{
|
|
rig_debug(RIG_DEBUG_ERR, "%s: unsupported VFO %s\n",
|
|
__func__, rig_strvfo(vfo));
|
|
return -RIG_EINVAL;
|
|
}
|
|
|
|
ttmode = FLRIG_MODE_USB;
|
|
|
|
switch (mode)
|
|
{
|
|
case RIG_MODE_LSB:
|
|
ttmode = RIG_MODE_LSB;
|
|
break;
|
|
|
|
case RIG_MODE_USB:
|
|
ttmode = RIG_MODE_USB;
|
|
break;
|
|
|
|
case RIG_MODE_CW:
|
|
ttmode = FLRIG_MODE_CW;
|
|
break;
|
|
|
|
case RIG_MODE_FM:
|
|
ttmode = FLRIG_MODE_FM;
|
|
break;
|
|
|
|
case RIG_MODE_AM:
|
|
ttmode = FLRIG_MODE_AM;
|
|
break;
|
|
|
|
case RIG_MODE_RTTY:
|
|
ttmode = FLRIG_MODE_RTTY;
|
|
break;
|
|
|
|
case RIG_MODE_CWR:
|
|
ttmode = FLRIG_MODE_CWR;
|
|
break;
|
|
|
|
case RIG_MODE_RTTYR:
|
|
ttmode = FLRIG_MODE_RTTYR;
|
|
break;
|
|
|
|
case RIG_MODE_PKTLSB:
|
|
ttmode = FLRIG_MODE_PKTLSB;
|
|
break;
|
|
|
|
case RIG_MODE_PKTUSB:
|
|
ttmode = FLRIG_MODE_PKTUSB;
|
|
break;
|
|
|
|
case RIG_MODE_PKTFM:
|
|
ttmode = FLRIG_MODE_PKTFM;
|
|
break;
|
|
|
|
case RIG_MODE_PKTAM:
|
|
ttmode = FLRIG_MODE_PKTAM;
|
|
break;
|
|
|
|
default:
|
|
rig_debug(RIG_DEBUG_ERR, "%s: unsupported mode %s\n", __func__,
|
|
rig_strrmode(mode));
|
|
return -RIG_EINVAL;
|
|
|
|
}
|
|
|
|
snprintf(cmd, sizeof(cmd), "MD%c;", ttmode);
|
|
retval = write_block(&rs->rigport, cmd, strlen(cmd));
|
|
|
|
if (retval < 0)
|
|
{
|
|
return retval;
|
|
}
|
|
|
|
// Get the response
|
|
retval = read_transaction(rig, response, sizeof(response));
|
|
|
|
if (retval != RIG_OK)
|
|
{
|
|
rig_debug(RIG_DEBUG_ERR, "%s read_transaction failed\n", __func__);
|
|
}
|
|
|
|
rig_debug(RIG_DEBUG_VERBOSE, "%s: response=%s\n", __func__, response);
|
|
|
|
// Can't set BW on TRXManger as of 20180427 -- can only read it
|
|
|
|
return RIG_OK;
|
|
}
|
|
|
|
/*
|
|
* trxmanager_get_mode
|
|
* Assumes rig!=NULL, rig->state.priv!=NULL, mode!=NULL
|
|
*/
|
|
static int trxmanager_get_mode(RIG *rig, vfo_t vfo, rmode_t *mode,
|
|
pbwidth_t *width)
|
|
{
|
|
int retval;
|
|
int n;
|
|
long iwidth = 0;
|
|
char tmode;
|
|
char cmd[MAXCMDLEN];
|
|
char response[MAXCMDLEN] = "";
|
|
struct rig_state *rs = &rig->state;
|
|
struct trxmanager_priv_data *priv = (struct trxmanager_priv_data *)
|
|
rig->state.priv;
|
|
|
|
rig_debug(RIG_DEBUG_TRACE, "%s: vfo=%s\n", __func__,
|
|
rig_strvfo(vfo));
|
|
|
|
if (check_vfo(vfo) == FALSE)
|
|
{
|
|
rig_debug(RIG_DEBUG_ERR, "%s: unsupported VFO %s\n",
|
|
__func__, rig_strvfo(vfo));
|
|
return -RIG_EINVAL;
|
|
}
|
|
|
|
if (vfo == RIG_VFO_CURR)
|
|
{
|
|
if ((retval = trxmanager_get_vfo(rig, &vfo)) != RIG_OK)
|
|
{
|
|
return retval;
|
|
}
|
|
|
|
priv->vfo_curr = vfo;
|
|
}
|
|
|
|
rig_debug(RIG_DEBUG_TRACE, "%s: using vfo=%s\n", __func__,
|
|
rig_strvfo(vfo));
|
|
|
|
snprintf(cmd, sizeof(cmd), "MD;");
|
|
retval = write_block(&rs->rigport, cmd, strlen(cmd));
|
|
|
|
if (retval < 0)
|
|
{
|
|
return retval;
|
|
}
|
|
|
|
retval = read_transaction(rig, response, sizeof(response));
|
|
|
|
if (retval != RIG_OK)
|
|
{
|
|
rig_debug(RIG_DEBUG_ERR, "%s read_transaction failed\n", __func__);
|
|
}
|
|
|
|
n = sscanf(response, "MD%c;", &tmode);
|
|
|
|
if (n != 1 || strlen(response) != 6)
|
|
{
|
|
rig_debug(RIG_DEBUG_ERR, "%s: invalid response='%s'\n", __func__, response);
|
|
return -RIG_EPROTO;
|
|
}
|
|
|
|
switch (tmode)
|
|
{
|
|
case FLRIG_MODE_LSB:
|
|
*mode = RIG_MODE_LSB;
|
|
break;
|
|
|
|
case FLRIG_MODE_USB:
|
|
*mode = RIG_MODE_USB;
|
|
break;
|
|
|
|
case FLRIG_MODE_CW:
|
|
*mode = RIG_MODE_CW;
|
|
break;
|
|
|
|
case FLRIG_MODE_FM:
|
|
*mode = RIG_MODE_FM;
|
|
break;
|
|
|
|
case FLRIG_MODE_AM:
|
|
*mode = RIG_MODE_AM;
|
|
break;
|
|
|
|
case FLRIG_MODE_RTTY:
|
|
*mode = RIG_MODE_RTTY;
|
|
break;
|
|
|
|
case FLRIG_MODE_CWR:
|
|
*mode = RIG_MODE_CWR;
|
|
break;
|
|
|
|
case FLRIG_MODE_RTTYR:
|
|
*mode = RIG_MODE_RTTYR;
|
|
break;
|
|
|
|
case FLRIG_MODE_PKTLSB:
|
|
*mode = RIG_MODE_PKTLSB;
|
|
break;
|
|
|
|
case FLRIG_MODE_PKTUSB:
|
|
*mode = RIG_MODE_PKTUSB;
|
|
break;
|
|
|
|
default:
|
|
rig_debug(RIG_DEBUG_ERR, "%s: unknown mode='%c'\n", __func__, tmode);
|
|
return -RIG_ENIMPL;
|
|
}
|
|
|
|
rig_debug(RIG_DEBUG_VERBOSE, "%s: mode='%s'\n", __func__, rig_strrmode(*mode));
|
|
|
|
// now get the bandwidth
|
|
snprintf(cmd, sizeof(cmd), "BW;");
|
|
retval = write_block(&rs->rigport, cmd, strlen(cmd));
|
|
|
|
if (retval < 0)
|
|
{
|
|
return retval;
|
|
}
|
|
|
|
retval = read_transaction(rig, response, sizeof(response));
|
|
|
|
if (retval != RIG_OK)
|
|
{
|
|
rig_debug(RIG_DEBUG_ERR, "%s read_transaction failed\n", __func__);
|
|
}
|
|
|
|
if (strncmp(response, "BW", 2) != 0)
|
|
{
|
|
rig_debug(RIG_DEBUG_ERR, "%s: invalid response='%s'\n", __func__, response);
|
|
return -RIG_EPROTO;
|
|
}
|
|
|
|
n = sscanf(response, "BW%ld;", &iwidth);
|
|
|
|
if (n != 1)
|
|
{
|
|
char *saveptr;
|
|
rig_debug(RIG_DEBUG_ERR, "%s bandwidth scan failed '%s'\n", __func__,
|
|
strtok_r(response, "\r\n", &saveptr));
|
|
return -RIG_EPROTO;
|
|
}
|
|
|
|
*width = iwidth;
|
|
printf("Bandwidth=%ld\n", *width);
|
|
return RIG_OK;
|
|
}
|
|
|
|
static int trxmanager_set_vfo(RIG *rig, vfo_t vfo)
|
|
{
|
|
int retval;
|
|
char cmd[MAXCMDLEN];
|
|
char response[MAXCMDLEN] = "";
|
|
struct rig_state *rs = &rig->state;
|
|
struct trxmanager_priv_data *priv = (struct trxmanager_priv_data *)
|
|
rig->state.priv;
|
|
|
|
|
|
rig_debug(RIG_DEBUG_TRACE, "%s: vfo=%s\n", __func__,
|
|
rig_strvfo(vfo));
|
|
|
|
if (check_vfo(vfo) == FALSE)
|
|
{
|
|
rig_debug(RIG_DEBUG_ERR, "%s: unsupported VFO %s\n",
|
|
__func__, rig_strvfo(vfo));
|
|
return -RIG_EINVAL;
|
|
}
|
|
|
|
if (vfo == RIG_VFO_TX)
|
|
{
|
|
rig_debug(RIG_DEBUG_VERBOSE, "%s: RIG_VFO_TX used\n", __func__);
|
|
vfo = RIG_VFO_B; // always TX on VFOB
|
|
}
|
|
|
|
if (vfo == RIG_VFO_CURR)
|
|
{
|
|
vfo = priv->vfo_curr;
|
|
}
|
|
|
|
snprintf(cmd, sizeof(cmd), "FN%d;", vfo == RIG_VFO_A ? 0 : 1);
|
|
retval = write_block(&rs->rigport, cmd, strlen(cmd));
|
|
|
|
if (retval < 0)
|
|
{
|
|
return retval;
|
|
}
|
|
|
|
priv->vfo_curr = vfo;
|
|
rs->tx_vfo = RIG_VFO_B; // always VFOB
|
|
retval = read_transaction(rig, response, sizeof(response));
|
|
|
|
if (retval != RIG_OK)
|
|
{
|
|
rig_debug(RIG_DEBUG_ERR, "%s read_transaction failed\n", __func__);
|
|
}
|
|
|
|
return RIG_OK;
|
|
}
|
|
|
|
static int trxmanager_get_vfo(RIG *rig, vfo_t *vfo)
|
|
{
|
|
// TRXManager does not swap vfos
|
|
// So we maintain our own internal state during set_vfo
|
|
// This keeps the hamlib interface consistent with other rigs
|
|
struct trxmanager_priv_data *priv = (struct trxmanager_priv_data *)
|
|
rig->state.priv;
|
|
char vfoab;
|
|
|
|
|
|
rig_debug(RIG_DEBUG_TRACE, "%s\n", __func__);
|
|
|
|
vfoab = priv->vfo_curr;
|
|
|
|
switch (vfoab)
|
|
{
|
|
case RIG_VFO_A:
|
|
*vfo = RIG_VFO_A;
|
|
break;
|
|
|
|
case RIG_VFO_B:
|
|
*vfo = RIG_VFO_B;
|
|
break;
|
|
|
|
default:
|
|
priv->vfo_curr = *vfo;
|
|
*vfo = RIG_VFO_CURR;
|
|
return -RIG_EINVAL;
|
|
}
|
|
|
|
if (check_vfo(*vfo) == FALSE)
|
|
{
|
|
rig_debug(RIG_DEBUG_ERR, "%s: unsupported VFO %s\n",
|
|
__func__, rig_strvfo(*vfo));
|
|
return -RIG_EINVAL;
|
|
}
|
|
|
|
priv->vfo_curr = *vfo;
|
|
|
|
rig_debug(RIG_DEBUG_VERBOSE, "%s: vfo=%s\n", __func__,
|
|
rig_strvfo(*vfo));
|
|
|
|
return RIG_OK;
|
|
}
|
|
|
|
/*
|
|
* trxmanager_set_split_freq
|
|
*/
|
|
static int trxmanager_set_split_freq(RIG *rig, vfo_t vfo, freq_t tx_freq)
|
|
{
|
|
int retval;
|
|
char cmd[MAXCMDLEN];
|
|
char response[MAXCMDLEN] = "";
|
|
struct rig_state *rs = &rig->state;
|
|
|
|
rig_debug(RIG_DEBUG_TRACE, "%s: vfo=%s freq=%.1f\n", __func__,
|
|
rig_strvfo(vfo), tx_freq);
|
|
|
|
if (check_vfo(vfo) == FALSE)
|
|
{
|
|
rig_debug(RIG_DEBUG_ERR, "%s: unsupported VFO %s\n",
|
|
__func__, rig_strvfo(vfo));
|
|
return -RIG_EINVAL;
|
|
}
|
|
|
|
snprintf(cmd, sizeof(cmd), "XT%011lu;", (unsigned long) tx_freq);
|
|
retval = write_block(&rs->rigport, cmd, strlen(cmd));
|
|
|
|
if (retval < 0)
|
|
{
|
|
return retval;
|
|
}
|
|
|
|
retval = read_transaction(rig, response,
|
|
sizeof(response)); // get response but don't care
|
|
|
|
if (retval != RIG_OK)
|
|
{
|
|
rig_debug(RIG_DEBUG_ERR, "%s read_transaction failed\n", __func__);
|
|
}
|
|
|
|
return RIG_OK;
|
|
}
|
|
|
|
/*
|
|
* trxmanager_get_split_freq
|
|
* assumes rig!=NULL, tx_freq!=NULL
|
|
*/
|
|
static int trxmanager_get_split_freq(RIG *rig, vfo_t vfo, freq_t *tx_freq)
|
|
{
|
|
int retval;
|
|
rig_debug(RIG_DEBUG_TRACE, "%s: vfo=%s\n", __func__,
|
|
rig_strvfo(vfo));
|
|
retval = trxmanager_get_freq(rig, RIG_VFO_B, tx_freq);
|
|
return retval;
|
|
}
|
|
|
|
/*
|
|
* trxmanager_set_split_vfo
|
|
* assumes rig!=NULL, tx_freq!=NULL
|
|
*/
|
|
static int trxmanager_set_split_vfo(RIG *rig, vfo_t vfo, split_t split,
|
|
vfo_t tx_vfo)
|
|
{
|
|
int retval;
|
|
char cmd[MAXCMDLEN];
|
|
char response[MAXCMDLEN] = "";
|
|
split_t tsplit;
|
|
vfo_t ttx_vfo;
|
|
struct rig_state *rs = &rig->state;
|
|
|
|
rig_debug(RIG_DEBUG_TRACE, "%s: tx_vfo=%s\n", __func__,
|
|
rig_strvfo(tx_vfo));
|
|
|
|
#if 0
|
|
|
|
/* for flrig we have to be on VFOA when we set split for VFOB Tx */
|
|
/* we can keep the rig on VFOA since we can set freq by VFO now */
|
|
if (!vfo_curr(rig, RIG_VFO_A))
|
|
{
|
|
trxmanager_set_vfo(rig, RIG_VFO_A);
|
|
}
|
|
|
|
#endif
|
|
retval = trxmanager_get_split_vfo(rig, vfo, &tsplit, &ttx_vfo);
|
|
|
|
if (retval < 0)
|
|
{
|
|
return retval;
|
|
}
|
|
|
|
if (tsplit == split) { return RIG_OK; } // don't need to change it
|
|
|
|
snprintf(cmd, sizeof(cmd), "SP%c;", split ? '1' : '0');
|
|
retval = write_block(&rs->rigport, cmd, strlen(cmd));
|
|
|
|
if (retval < 0)
|
|
{
|
|
return retval;
|
|
}
|
|
|
|
retval = read_transaction(rig, response,
|
|
sizeof(response)); // get response but don't care
|
|
|
|
if (retval != RIG_OK)
|
|
{
|
|
rig_debug(RIG_DEBUG_ERR, "%s read_transaction failed\n", __func__);
|
|
}
|
|
|
|
if (strlen(response) != 6 || strstr(response, cmd) == NULL)
|
|
{
|
|
rig_debug(RIG_DEBUG_ERR, "%s invalid response='%s'\n", __func__, response);
|
|
return -RIG_EPROTO;
|
|
}
|
|
|
|
return RIG_OK;
|
|
}
|
|
|
|
/*
|
|
* trxmanager_get_split_vfo
|
|
* assumes rig!=NULL, tx_freq!=NULL
|
|
*/
|
|
static int trxmanager_get_split_vfo(RIG *rig, vfo_t vfo, split_t *split,
|
|
vfo_t *tx_vfo)
|
|
{
|
|
int retval;
|
|
int tsplit = 0;
|
|
int n;
|
|
char cmd[MAXCMDLEN];
|
|
char response[MAXCMDLEN] = "";
|
|
struct rig_state *rs = &rig->state;
|
|
struct trxmanager_priv_data *priv = (struct trxmanager_priv_data *)
|
|
rig->state.priv;
|
|
|
|
rig_debug(RIG_DEBUG_TRACE, "%s\n", __func__);
|
|
snprintf(cmd, sizeof(cmd), "SP;");
|
|
retval = write_block(&rs->rigport, cmd, strlen(cmd));
|
|
|
|
if (retval < 0)
|
|
{
|
|
return retval;
|
|
}
|
|
|
|
retval = read_transaction(rig, response,
|
|
sizeof(response)); // get response but don't care
|
|
|
|
if (retval != RIG_OK)
|
|
{
|
|
rig_debug(RIG_DEBUG_ERR, "%s read_transaction failed\n", __func__);
|
|
}
|
|
|
|
*tx_vfo = RIG_VFO_B;
|
|
n = sscanf(response, "SP%d", &tsplit);
|
|
|
|
if (n == 0)
|
|
{
|
|
rig_debug(RIG_DEBUG_ERR, "%s error getting split from '%s'\n", __func__,
|
|
response);
|
|
}
|
|
|
|
*split = tsplit;
|
|
priv->split = *split;
|
|
return RIG_OK;
|
|
}
|
|
|
|
/*
|
|
* trxmanager_set_split_freq_mode
|
|
* assumes rig!=NULL
|
|
*/
|
|
static int trxmanager_set_split_freq_mode(RIG *rig, vfo_t vfo, freq_t freq,
|
|
rmode_t mode, pbwidth_t width)
|
|
{
|
|
int retval;
|
|
char cmd[MAXCMDLEN];
|
|
char response[MAXCMDLEN] = "";
|
|
struct rig_state *rs = &rig->state;
|
|
struct trxmanager_priv_data *priv = (struct trxmanager_priv_data *)
|
|
rig->state.priv;
|
|
|
|
rig_debug(RIG_DEBUG_TRACE, "%s\n", __func__);
|
|
|
|
if (vfo != RIG_VFO_CURR && vfo != RIG_VFO_TX)
|
|
{
|
|
return -RIG_ENTARGET;
|
|
}
|
|
|
|
// assume split is on B
|
|
//
|
|
snprintf(cmd, sizeof(cmd), "XT%011lu;", (unsigned long)freq);
|
|
retval = write_block(&rs->rigport, cmd, strlen(cmd));
|
|
|
|
if (retval < 0)
|
|
{
|
|
return retval;
|
|
}
|
|
|
|
retval = read_transaction(rig, response, sizeof(response));
|
|
|
|
if (retval != RIG_OK)
|
|
{
|
|
rig_debug(RIG_DEBUG_ERR, "%s read_transaction failed\n", __func__);
|
|
}
|
|
|
|
if (strlen(response) != 16 || strstr(response, cmd) == NULL)
|
|
{
|
|
FILE *fp;
|
|
rig_debug(RIG_DEBUG_ERR, "%s invalid response='%s'\n", __func__, response);
|
|
fp = fopen("debug.txt", "w+");
|
|
fprintf(fp, "XT response=%s\n", response);
|
|
fclose(fp);
|
|
return -RIG_EPROTO;
|
|
}
|
|
|
|
priv->split = 1; // XT command also puts rig in split
|
|
|
|
return retval;
|
|
}
|
|
|
|
/*
|
|
* trxmanager_get_split_freq_mode
|
|
* assumes rig!=NULL, freq!=NULL, mode!=NULL, width!=NULL
|
|
*/
|
|
static int trxmanager_get_split_freq_mode(RIG *rig, vfo_t vfo, freq_t *freq,
|
|
rmode_t *mode, pbwidth_t *width)
|
|
{
|
|
int retval;
|
|
|
|
if (vfo != RIG_VFO_CURR && vfo != RIG_VFO_TX)
|
|
{
|
|
return -RIG_ENTARGET;
|
|
}
|
|
|
|
retval = trxmanager_get_freq(rig, RIG_VFO_B, freq);
|
|
|
|
if (RIG_OK == retval)
|
|
{
|
|
retval = trxmanager_get_mode(rig, vfo, mode, width);
|
|
}
|
|
|
|
return retval;
|
|
}
|
|
|
|
|
|
static const char *trxmanager_get_info(RIG *rig)
|
|
{
|
|
struct trxmanager_priv_data *priv = (struct trxmanager_priv_data *)
|
|
rig->state.priv;
|
|
rig_debug(RIG_DEBUG_VERBOSE, "%s called\n", __func__);
|
|
|
|
return priv->info;
|
|
}
|
|
|