Hamlib/rigs/dummy/flrig.c

1865 wiersze
51 KiB
C
Czysty Zwykły widok Historia

2017-07-06 21:53:58 +00:00
/*
* Hamlib FLRig backend - main file
* Copyright (c) 2017 by Michael Black W9MDB
* Copyright (c) 2018 by Michael Black W9MDB
2017-07-06 21:53:58 +00:00
*
*
* 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 "flrig.h"
#define DEBUG 1
#define DEBUG_TRACE DEBUG_VERBOSE
2017-07-06 21:53:58 +00:00
#define MAXCMDLEN 8192
#define MAXXMLLEN 8192
#define MAXARGLEN 128
#define MAXBANDWIDTHLEN 4096
2017-07-06 21:53:58 +00:00
#define DEFAULTPATH "127.0.0.1:12345"
2017-07-06 21:53:58 +00:00
#define FLRIG_VFOS (RIG_VFO_A|RIG_VFO_B)
2017-07-06 21:53:58 +00:00
#define FLRIG_MODES (RIG_MODE_AM | RIG_MODE_PKTAM | RIG_MODE_CW | RIG_MODE_CWR |\
RIG_MODE_RTTY | RIG_MODE_RTTYR |\
RIG_MODE_PKTLSB | RIG_MODE_PKTUSB |\
RIG_MODE_SSB | RIG_MODE_LSB | RIG_MODE_USB |\
2019-11-27 17:59:14 +00:00
RIG_MODE_FM | RIG_MODE_WFM | RIG_MODE_FMN |RIG_MODE_PKTFM )
2017-07-06 21:53:58 +00:00
#define streq(s1,s2) (strcmp(s1,s2)==0)
2017-07-06 21:53:58 +00:00
static int flrig_init(RIG *rig);
static int flrig_open(RIG *rig);
static int flrig_close(RIG *rig);
static int flrig_cleanup(RIG *rig);
2017-07-06 21:53:58 +00:00
static int flrig_set_freq(RIG *rig, vfo_t vfo, freq_t freq);
static int flrig_get_freq(RIG *rig, vfo_t vfo, freq_t *freq);
static int flrig_set_ptt(RIG *rig, vfo_t vfo, ptt_t ptt);
static int flrig_set_mode(RIG *rig, vfo_t vfo, rmode_t mode, pbwidth_t width);
2019-11-27 17:59:14 +00:00
static int flrig_set_split_mode(RIG *rig, vfo_t vfo, rmode_t mode,
pbwidth_t width);
static int flrig_get_mode(RIG *rig, vfo_t vfo, rmode_t *mode, pbwidth_t *width);
2017-07-06 21:53:58 +00:00
static int flrig_get_vfo(RIG *rig, vfo_t *vfo);
static int flrig_set_vfo(RIG *rig, vfo_t vfo);
static int flrig_set_ptt(RIG *rig, vfo_t vfo, ptt_t ptt);
static int flrig_get_ptt(RIG *rig, vfo_t vfo, ptt_t *ptt);
static int flrig_set_split_freq(RIG *rig, vfo_t vfo, freq_t tx_freq);
static int flrig_get_split_freq(RIG *rig, vfo_t vfo, freq_t *tx_freq);
static int flrig_set_split_vfo(RIG *rig, vfo_t vfo, split_t split,
vfo_t tx_vfo);
static int flrig_get_split_vfo(RIG *rig, vfo_t vfo, split_t *split,
vfo_t *tx_vfo);
2019-11-27 17:59:14 +00:00
static int flrig_set_split_freq_mode(RIG *rig, vfo_t vfo, freq_t freq,
rmode_t mode, pbwidth_t width);
static int flrig_get_split_freq_mode(RIG *rig, vfo_t vfo, freq_t *freq,
rmode_t *mode, pbwidth_t *width);
static const char *flrig_get_info(RIG *rig);
2017-07-06 21:53:58 +00:00
2019-11-27 17:59:14 +00:00
struct flrig_priv_data
{
vfo_t curr_vfo;
char bandwidths[MAXBANDWIDTHLEN]; /* pipe delimited set returned from flrig */
int nbandwidths;
char info[8192];
ptt_t ptt;
split_t split;
rmode_t curr_modeA;
rmode_t curr_modeB;
freq_t curr_freqA;
freq_t curr_freqB;
pbwidth_t curr_widthA;
pbwidth_t curr_widthB;
int has_get_modeA; /* True if this function is available */
int has_get_bwA; /* True if this function is available */
2017-07-06 21:53:58 +00:00
};
2019-11-27 17:59:14 +00:00
const struct rig_caps flrig_caps =
{
RIG_MODEL(RIG_MODEL_FLRIG),
2017-07-06 21:53:58 +00:00
.model_name = "FLRig",
.mfg_name = "FLRig",
.version = BACKEND_VER ".0",
2017-07-06 21:53:58 +00:00
.copyright = "LGPL",
.status = RIG_STATUS_STABLE,
2017-07-06 21:53:58 +00:00
.rig_type = RIG_TYPE_TRANSCEIVER,
2019-11-27 17:59:14 +00:00
.targetable_vfo = RIG_TARGETABLE_FREQ | RIG_TARGETABLE_MODE,
2017-07-06 21:53:58 +00:00
.ptt_type = RIG_PTT_RIG,
.port_type = RIG_PORT_NETWORK,
.write_delay = 0,
.post_write_delay = 0,
.timeout = 2000,
.retry = 5,
2017-07-06 21:53:58 +00:00
.has_get_func = RIG_FUNC_NONE,
.has_set_func = RIG_FUNC_NONE,
.has_get_level = RIG_LEVEL_NONE,
2017-07-06 21:53:58 +00:00
.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 = {{
2019-11-27 17:59:14 +00:00
.startf = kHz(1), .endf = GHz(10), .modes = FLRIG_MODES,
.low_power = -1, .high_power = -1, FLRIG_VFOS, RIG_ANT_1
},
RIG_FRNG_END,
},
.tx_range_list1 = {RIG_FRNG_END,},
.rx_range_list2 = {{
2019-11-27 17:59:14 +00:00
.startf = kHz(1), .endf = GHz(10), .modes = FLRIG_MODES,
.low_power = -1, .high_power = -1, FLRIG_VFOS, RIG_ANT_1
},
RIG_FRNG_END,
},
.tx_range_list2 = {RIG_FRNG_END,},
2019-11-27 17:59:14 +00:00
.tuning_steps = { {FLRIG_MODES, 1}, {FLRIG_MODES, RIG_TS_ANY}, RIG_TS_END, },
2017-07-06 21:53:58 +00:00
.priv = NULL, /* priv */
.rig_init = flrig_init,
.rig_open = flrig_open,
.rig_close = flrig_close,
.rig_cleanup = flrig_cleanup,
2017-07-06 21:53:58 +00:00
.set_freq = flrig_set_freq,
.get_freq = flrig_get_freq,
.set_mode = flrig_set_mode,
.get_mode = flrig_get_mode,
2017-07-06 21:53:58 +00:00
.set_vfo = flrig_set_vfo,
.get_vfo = flrig_get_vfo,
.get_info = flrig_get_info,
2017-07-06 21:53:58 +00:00
.set_ptt = flrig_set_ptt,
.get_ptt = flrig_get_ptt,
.set_split_mode = flrig_set_split_mode,
2017-07-06 21:53:58 +00:00
.set_split_freq = flrig_set_split_freq,
.get_split_freq = flrig_get_split_freq,
.set_split_vfo = flrig_set_split_vfo,
.get_split_vfo = flrig_get_split_vfo,
.set_split_freq_mode = flrig_set_split_freq_mode,
.get_split_freq_mode = flrig_get_split_freq_mode
2017-07-06 21:53:58 +00:00
};
// Structure for mapping flrig dynmamic modes to hamlib modes
// flrig displays modes as the rig displays them
2019-11-27 17:59:14 +00:00
struct s_modeMap
{
2019-07-31 20:45:11 +00:00
rmode_t mode_hamlib;
2018-10-03 16:29:15 +00:00
char *mode_flrig;
};
2017-07-06 21:53:58 +00:00
// FLRig will provide us the modes for the selected rig
// We will then put them in this struct
2019-11-27 17:59:14 +00:00
static struct s_modeMap modeMap[] =
{
{RIG_MODE_USB, NULL},
{RIG_MODE_LSB, NULL},
{RIG_MODE_PKTUSB, NULL},
{RIG_MODE_PKTLSB, NULL},
{RIG_MODE_PKTUSB, NULL},
{RIG_MODE_PKTLSB, NULL},
{RIG_MODE_AM, NULL},
{RIG_MODE_FM, NULL},
{RIG_MODE_FMN, NULL},
{RIG_MODE_WFM, NULL},
{RIG_MODE_CW, NULL},
{RIG_MODE_CW, NULL},
{RIG_MODE_CWR, NULL},
{RIG_MODE_CWR, NULL},
{RIG_MODE_RTTY, NULL},
{RIG_MODE_RTTYR, NULL},
{0, NULL}
};
2017-07-06 21:53:58 +00:00
/*
* check_vfo
* No assumptions
*/
2017-07-06 21:53:58 +00:00
static int check_vfo(vfo_t vfo)
{
2019-11-27 17:59:14 +00:00
switch (vfo)
{
2017-07-06 21:53:58 +00:00
case RIG_VFO_A:
break;
case RIG_VFO_TX:
case RIG_VFO_B:
2017-07-06 21:53:58 +00:00
break;
case RIG_VFO_CURR:
break; // will default to A in which_vfo
default:
return FALSE;
}
return TRUE;
}
/* Rather than use some huge XML library we only need a few things
* So we'll hand craft them
* xml_build takes a value and return an xml string for FLRig
*/
2019-12-01 17:09:30 +00:00
static char *xml_build(char *cmd, char *value, char *xmlbuf, int xmlbuflen)
2017-07-06 21:53:58 +00:00
{
char xml[4096]; // we shouldn't need more the 4096 bytes for this
char tmp[32];
char *header;
int n;
2019-11-27 17:59:14 +00:00
// We want at least a 4K buf to play with
2019-12-01 17:09:30 +00:00
if (xmlbuflen < 4096)
2019-11-27 17:59:14 +00:00
{
2019-11-30 16:19:08 +00:00
rig_debug(RIG_DEBUG_ERR, "%s: xmllen < 4096\n", __func__);
return NULL;
}
2019-11-27 17:59:14 +00:00
header =
2019-12-01 17:09:30 +00:00
"POST /RPC2 HTTP/1.1\r\n" "User-Agent: XMLRPC++ 0.8\r\n"
"Host: 127.0.0.1:12345\r\n" "Content-type: text/xml\r\n";
n = snprintf(xmlbuf, xmlbuflen, "%s", header);
2019-12-01 17:09:30 +00:00
if (n != strlen(header))
{
rig_debug(RIG_DEBUG_ERR, "%s: snprintf of header failed, len=%d, got=%d\n",
__func__, (int)strlen(header), n);
}
n = snprintf(xml, sizeof(xml), "<?xml version=\"1.0\"?>\r\n");
if (n != strlen(xml))
{
rig_debug(RIG_DEBUG_ERR, "%s: snprintf of xml failed, len=%d, got=%d\n",
__func__, (int)strlen(header), n);
}
strncat(xml, "<methodCall><methodName>", sizeof(xml) - 1);
2019-12-06 22:31:54 +00:00
strncat(xml, cmd, sizeof(xml) - strlen(xml) - 1);
strncat(xml, "</methodName>\r\n", sizeof(xml) - strlen(xml) - 1);
2017-07-06 21:53:58 +00:00
2019-11-27 17:59:14 +00:00
if (value && strlen(value) > 0)
{
2019-12-01 17:09:30 +00:00
strncat(xml, value, sizeof(xml) - 1);
2017-07-06 21:53:58 +00:00
}
2019-12-01 17:09:30 +00:00
strncat(xml, "</methodCall>\r\n", sizeof(xml) - 1);
strncat(xmlbuf, "Content-length: ", xmlbuflen - 1);
snprintf(tmp, sizeof(tmp), "%d\r\n\r\n", (int)strlen(xml));
strncat(xmlbuf, tmp, xmlbuflen - 1);
strncat(xmlbuf, xml, xmlbuflen - 1);
return xmlbuf;
2017-07-06 21:53:58 +00:00
}
/* This is a very crude xml parse specific to what we need from FLRig
* This works for strings, doubles, I4-type values, and arrays
* Arrays are returned pipe delimited
*/
static char *xml_parse2(char *xml, char *value, int valueLen)
2017-07-06 21:53:58 +00:00
{
2019-11-27 17:59:14 +00:00
char *delims = "<>\r\n ";
char *xmltmp = strdup(xml);
2019-11-30 16:16:28 +00:00
//rig_debug(RIG_DEBUG_TRACE, "%s: xml='%s'\n", __func__,xml);
2019-11-27 17:58:58 +00:00
char *pr = xml;
2019-11-27 17:59:14 +00:00
char *p = strtok_r(xmltmp, delims, &pr);
value[0] = 0;
while (p)
{
if (streq(p, "value"))
{
p = strtok_r(NULL, delims, &pr);
if (streq(p, "array")) { continue; }
if (streq(p, "/value")) { continue; } // empty value
if (streq(p, "i4") || streq(p, "double"))
{
p = strtok_r(NULL, delims, &pr);
}
2019-11-27 17:59:14 +00:00
else if (streq(p, "array"))
{
2019-12-06 22:28:24 +00:00
strtok_r(NULL, delims, &pr);
2019-11-27 17:59:14 +00:00
p = strtok_r(NULL, delims, &pr);
}
2019-11-27 17:59:14 +00:00
if (strlen(value) + strlen(p) + 1 < valueLen)
{
if (value[0] != 0) { strcat(value, "|"); }
strcat(value, p);
}
2019-11-27 17:59:14 +00:00
else // we'll just stop adding stuff
{
2019-11-30 16:16:28 +00:00
rig_debug(RIG_DEBUG_ERR, "%s: max value length exceeded\n", __func__);
}
}
2019-11-27 17:59:14 +00:00
else
{
p = strtok_r(NULL, delims, &pr);
}
}
2019-11-27 17:59:14 +00:00
2019-11-30 16:16:28 +00:00
rig_debug(RIG_DEBUG_TRACE, "%s: value returned='%s'\n", __func__, value);
2019-11-27 17:59:14 +00:00
if (rig_need_debug(RIG_DEBUG_WARN) && value != NULL && strlen(value) == 0)
{
2019-11-30 16:16:28 +00:00
rig_debug(RIG_DEBUG_ERR, "%s: xml='%s'\n", __func__, xml);
2017-07-06 21:53:58 +00:00
}
2019-11-27 17:59:14 +00:00
free(xmltmp);
2017-07-06 21:53:58 +00:00
return value;
}
/*
* xml_parse
* Assumes xml!=NULL, value!=NULL, value_len big enough
* returns the string value contained in the xml string
*/
2017-07-06 21:53:58 +00:00
static char *xml_parse(char *xml, char *value, int value_len)
{
char *next;
char *pxml;
2019-12-19 04:33:06 +00:00
2017-07-06 21:53:58 +00:00
/* first off we should have an OK on the 1st line */
2019-11-27 17:59:14 +00:00
if (strstr(xml, " 200 OK") == NULL)
{
2017-07-06 21:53:58 +00:00
return NULL;
}
2019-11-27 17:59:14 +00:00
2019-11-30 16:16:28 +00:00
rig_debug(RIG_DEBUG_TRACE, "%s XML:\n%s\n", __func__, xml);
2017-07-06 21:53:58 +00:00
// find the xml skipping the other stuff above it
pxml = strstr(xml, "<?xml");
2017-07-06 21:53:58 +00:00
2019-11-27 17:59:14 +00:00
if (pxml == NULL)
{
2017-07-06 21:53:58 +00:00
return NULL;
}
next = strchr(pxml + 1, '<');
2019-11-27 17:59:14 +00:00
if (value != NULL)
{
xml_parse2(next, value, value_len);
}
2019-11-27 17:59:14 +00:00
2020-07-07 16:39:26 +00:00
if (value && strstr(value, "faultString"))
2019-11-27 17:59:14 +00:00
{
2019-11-30 16:16:28 +00:00
rig_debug(RIG_DEBUG_ERR, "%s error:\n%s\n", __func__, value);
2019-11-27 17:59:14 +00:00
value[0] = 0; /* truncate to give empty response */
}
2019-11-27 17:59:14 +00:00
2017-07-06 21:53:58 +00:00
return value;
}
/*
* read_transaction
* Assumes rig!=NULL, xml!=NULL, xml_len>=MAXXMLLEN
*/
2017-07-06 21:53:58 +00:00
static int read_transaction(RIG *rig, char *xml, int xml_len)
{
int retval;
int retry;
char *delims;
char *terminator = "</methodResponse>";
struct rig_state *rs = &rig->state;
2019-11-30 16:16:28 +00:00
rig_debug(RIG_DEBUG_TRACE, "%s\n", __func__);
2017-07-06 21:53:58 +00:00
rs->rigport.timeout = 1000; // 1 second read string timeout
2017-07-06 21:53:58 +00:00
retry = 2;
delims = "\n";
2019-11-27 17:59:14 +00:00
xml[0] = 0;
do
{
2019-12-01 17:09:30 +00:00
char tmp_buf[MAXXMLLEN]; // plenty big for expected flrig responses hopefully
if (retry < 2)
{
rig_debug(RIG_DEBUG_WARN, "%s: retry needed? retry=%d\n", __func__, retry);
}
2019-11-27 17:59:14 +00:00
int len = read_string(&rs->rigport, tmp_buf, sizeof(tmp_buf), delims,
strlen(delims));
rig_debug(RIG_DEBUG_TRACE, "%s: string='%s'\n", __func__, tmp_buf);
2019-11-27 17:59:14 +00:00
2020-05-11 03:44:34 +00:00
// if our first response we should see the HTTP header
if (strlen(xml) == 0 && strstr(tmp_buf, "HTTP/1.1 200 OK") == NULL)
{
rig_debug(RIG_DEBUG_ERR, "%s: Expected 'HTTP/1.1 200 OK', got '%s'\n", __func__,
tmp_buf);
return -1;
}
2019-11-27 17:59:14 +00:00
if (len > 0) { retry = 3; }
if (len <= 0)
{
2019-11-30 16:16:28 +00:00
rig_debug(RIG_DEBUG_ERR, "%s: read_string error=%d\n", __func__, len);
//return -(100 + RIG_EPROTO);
2020-04-25 16:28:38 +00:00
continue;
2017-07-06 21:53:58 +00:00
}
2019-11-27 17:59:14 +00:00
2019-12-01 17:09:30 +00:00
if (strlen(xml) + strlen(tmp_buf) < xml_len - 1)
{
strncat(xml, tmp_buf, xml_len - 1);
2019-12-01 17:09:30 +00:00
}
else
{
rig_debug(RIG_DEBUG_ERR,
2020-06-23 17:01:29 +00:00
"%s: xml buffer overflow!!\nTrying to add len=%d\nTo len=%d\n", __func__,
(int)strlen(tmp_buf), (int)strlen(xml));
2019-12-01 17:09:30 +00:00
return -RIG_EPROTO;
}
}
2019-11-27 17:59:14 +00:00
while (retry-- > 0 && strstr(xml, terminator) == NULL);
if (retry == 0)
{
2019-11-30 16:16:28 +00:00
rig_debug(RIG_DEBUG_WARN, "%s: retry timeout\n", __func__);
return -RIG_ETIMEOUT;
2019-11-27 17:59:14 +00:00
}
if (strstr(xml, terminator))
{
2019-11-30 16:16:28 +00:00
rig_debug(RIG_DEBUG_TRACE, "%s: got %s\n", __func__, terminator);
// Slow down just a bit -- not sure this is needed anymore but not a big deal here
hl_usleep(2 * 1000);
retval = RIG_OK;
}
2019-11-27 17:59:14 +00:00
else
{
2019-11-30 16:16:28 +00:00
rig_debug(RIG_DEBUG_VERBOSE, "%s: did not get %s\n", __func__, terminator);
2019-11-27 17:59:14 +00:00
retval = -(101 + RIG_EPROTO);
}
2019-11-27 17:59:14 +00:00
return retval;
}
2017-07-06 21:53:58 +00:00
/*
* write_transaction
* Assumes rig!=NULL, xml!=NULL, xml_len=total size of xml for response
*/
static int write_transaction(RIG *rig, char *xml, int xml_len)
{
2019-11-27 17:59:14 +00:00
int try = rig->caps->retry;
int retval = -RIG_EPROTO;
2017-07-06 21:53:58 +00:00
struct rig_state *rs = &rig->state;
// This shouldn't ever happen...but just in case
// We need to avoid an empty write as rigctld replies with blank line
2019-11-27 17:59:14 +00:00
if (xml_len == 0)
{
2019-11-30 16:16:28 +00:00
rig_debug(RIG_DEBUG_ERR, "%s: len==0??\n", __func__);
2019-07-31 20:45:11 +00:00
return retval;
}
2019-07-20 16:43:40 +00:00
// appears we can lose sync if we don't clear things out
// shouldn't be anything for us now anyways
rig_flush(&rig->state.rigport);
2019-07-20 16:43:40 +00:00
2019-11-27 17:59:14 +00:00
while (try-- >= 0 && retval != RIG_OK)
{
retval = write_block(&rs->rigport, xml, strlen(xml));
2019-11-27 17:59:14 +00:00
if (retval < 0)
{
return -RIG_EIO;
}
}
2019-11-27 17:59:14 +00:00
return retval;
2017-07-06 21:53:58 +00:00
}
static int flrig_transaction(RIG *rig, char *cmd, char *cmd_arg, char *value,
int value_len)
{
int retry = 2;
if (value)
{
value[0] = 0;
}
do
{
char xml[MAXXMLLEN];
char *pxml;
int retval;
if (retry < 2)
{
rig_debug(RIG_DEBUG_VERBOSE, "%s: cmd=%s, retry=%d\n", __func__, cmd, retry);
}
pxml = xml_build(cmd, cmd_arg, xml, sizeof(xml));
retval = write_transaction(rig, pxml, strlen(pxml));
if (retval != RIG_OK)
{
rig_debug(RIG_DEBUG_ERR, "%s: write_transaction error=%d\n", __func__, retval);
hl_usleep(50 * 1000); // 50ms sleep if error
}
read_transaction(rig, xml, sizeof(xml)); // this might time out -- that's OK
if (value)
{
xml_parse(xml, value, value_len);
}
}
while (value && strlen(value) == 0 && retry--); // we'll do retries if needed
if (value && strlen(value) == 0) { return RIG_EPROTO; }
return RIG_OK;
}
/*
* flrig_init
* Assumes rig!=NULL
*/
static int flrig_init(RIG *rig)
2017-07-06 21:53:58 +00:00
{
2020-01-13 04:43:40 +00:00
struct flrig_priv_data *priv;
2019-11-30 16:16:28 +00:00
rig_debug(RIG_DEBUG_TRACE, "%s version %s\n", __func__, BACKEND_VER);
2017-07-06 21:53:58 +00:00
2020-01-13 04:43:40 +00:00
rig->state.priv = (struct flrig_priv_data *)malloc(sizeof(
2020-02-23 17:26:09 +00:00
struct flrig_priv_data));
2017-07-10 16:13:45 +00:00
2020-01-13 04:43:40 +00:00
if (!rig->state.priv)
2019-11-27 17:59:14 +00:00
{
2017-07-10 16:13:45 +00:00
return -RIG_ENOMEM;
}
2020-01-13 04:43:40 +00:00
priv = rig->state.priv;
2017-07-06 21:53:58 +00:00
memset(priv, 0, sizeof(struct flrig_priv_data));
2017-07-10 16:13:45 +00:00
2017-07-06 21:53:58 +00:00
/*
* set arbitrary initial status
*/
rig->state.current_vfo = RIG_VFO_A;
priv->split = 0;
priv->ptt = 0;
priv->curr_modeA = -1;
priv->curr_modeB = -1;
priv->curr_widthA = -1;
priv->curr_widthB = -1;
2017-07-06 21:53:58 +00:00
2019-12-06 22:28:24 +00:00
if (!rig->caps)
2019-11-27 17:59:14 +00:00
{
2017-07-06 21:53:58 +00:00
return -RIG_EINVAL;
}
strncpy(rig->state.rigport.pathname, DEFAULTPATH,
sizeof(rig->state.rigport.pathname));
return RIG_OK;
}
/*
* modeMapGetFLRig
* Assumes mode!=NULL
* Return the string for FLRig for the given hamlib mode
*/
2019-11-27 17:59:14 +00:00
static const char *modeMapGetFLRig(rmode_t modeHamlib)
{
int i;
2019-11-27 17:59:14 +00:00
for (i = 0; modeMap[i].mode_hamlib != 0; ++i)
{
2019-12-03 15:28:43 +00:00
if (modeMap[i].mode_hamlib == modeHamlib && modeMap[i].mode_flrig != NULL)
2019-11-27 17:59:14 +00:00
{
return modeMap[i].mode_flrig;
}
}
2019-11-27 17:59:14 +00:00
2019-11-30 16:16:28 +00:00
rig_debug(RIG_DEBUG_ERR, "%s: Unknown mode requested: %s\n", __func__,
2019-11-27 17:59:14 +00:00
rig_strrmode(modeHamlib));
return "ERROR";
}
/*
* modeMapGetHamlib
* Assumes mode!=NULL
* Return the hamlib mode from the given FLRig string
*/
2019-11-27 17:59:14 +00:00
static rmode_t modeMapGetHamlib(const char *modeFLRig)
{
int i;
2018-10-03 16:29:15 +00:00
char modeFLRigCheck[64];
2019-11-27 17:59:14 +00:00
snprintf(modeFLRigCheck, sizeof(modeFLRigCheck), "|%s|", modeFLRig);
for (i = 0; modeMap[i].mode_hamlib != 0; ++i)
{
2019-11-30 16:16:28 +00:00
rig_debug(RIG_DEBUG_TRACE, "%s: find '%s' in '%s'\n", __func__,
2019-11-27 17:59:14 +00:00
modeFLRigCheck, modeMap[i].mode_flrig);
if (modeMap[i].mode_flrig
&& strcmp(modeMap[i].mode_flrig, modeFLRigCheck) == 0)
{
return modeMap[i].mode_hamlib;
}
}
2019-11-27 17:59:14 +00:00
rig_debug(RIG_DEBUG_TRACE, "%s: mode requested: %s, not in modeMap\n", __func__,
2019-11-27 17:59:14 +00:00
modeFLRig);
return RIG_MODE_NONE;
}
/*
* modeMapAdd
* Assumes modes!=NULL
*/
2019-11-27 17:59:14 +00:00
static void modeMapAdd(rmode_t *modes, rmode_t mode_hamlib, char *mode_flrig)
{
int i;
int len1;
2019-11-30 16:16:28 +00:00
rig_debug(RIG_DEBUG_TRACE, "%s:mode_flrig=%s\n", __func__, mode_flrig);
2019-07-31 20:45:11 +00:00
// if we already have it just return
// We get ERROR if the mode is not known so non-ERROR is OK
if (modeMapGetHamlib(mode_flrig) != RIG_MODE_NONE) { return; }
2019-11-30 16:19:08 +00:00
len1 = strlen(mode_flrig) + 3; /* bytes needed for allocating */
2019-11-27 17:59:14 +00:00
for (i = 0; modeMap[i].mode_hamlib != 0; ++i)
{
if (modeMap[i].mode_hamlib == mode_hamlib)
{
int len2;
*modes |= modeMap[i].mode_hamlib;
2019-11-27 17:59:14 +00:00
/* we will pipe delimit all the entries for easier matching */
/* all entries will have pipe symbol on both sides */
if (modeMap[i].mode_flrig == NULL)
{
modeMap[i].mode_flrig = calloc(1, len1);
if (modeMap[i].mode_flrig == NULL)
{
rig_debug(RIG_DEBUG_ERR, "%s: error allocating memory for modeMap\n",
2019-11-30 16:16:28 +00:00
__func__);
2019-11-27 17:59:14 +00:00
return;
}
}
len2 = strlen(modeMap[i].mode_flrig); /* current len w/o null */
2019-11-27 17:59:14 +00:00
modeMap[i].mode_flrig = realloc(modeMap[i].mode_flrig,
strlen(modeMap[i].mode_flrig) + len1);
if (strlen(modeMap[i].mode_flrig) == 0) { modeMap[i].mode_flrig[0] = '|'; }
strncat(modeMap[i].mode_flrig, mode_flrig, len1 + len2);
strncat(modeMap[i].mode_flrig, "|", len1 + len2);
2019-11-30 16:19:08 +00:00
rig_debug(RIG_DEBUG_TRACE, "%s: Adding mode=%s, index=%d, result=%s\n",
2019-11-30 16:16:28 +00:00
__func__, mode_flrig, i, modeMap[i].mode_flrig);
return;
}
}
}
/*
* flrig_open
* Assumes rig!=NULL, rig->state.priv!=NULL
*/
2019-11-27 17:59:14 +00:00
static int flrig_open(RIG *rig)
{
int retval;
char value[MAXXMLLEN];
char arg[MAXXMLLEN];
rmode_t modes;
char *p;
char *pr;
struct flrig_priv_data *priv = (struct flrig_priv_data *) rig->state.priv;
2019-11-30 16:16:28 +00:00
rig_debug(RIG_DEBUG_TRACE, "%s version %s\n", __func__, BACKEND_VER);
retval = flrig_transaction(rig, "rig.get_xcvr", NULL, value, sizeof(value));
2019-11-27 17:59:14 +00:00
if (retval != RIG_OK)
2019-11-27 17:59:14 +00:00
{
rig_debug(RIG_DEBUG_ERR, "%s: get_xcvr failed: %s\n", __func__,
rigerror(retval));
return retval;
}
2019-11-27 17:59:14 +00:00
strncpy(priv->info, value, sizeof(priv->info));
rig_debug(RIG_DEBUG_VERBOSE, "Transceiver=%s\n", value);
/* see if get_modeA is available */
retval = flrig_transaction(rig, "rig.get_modeA", NULL, value, sizeof(value));
2019-12-19 04:33:06 +00:00
if (retval != RIG_OK) { return retval; }
2019-11-27 17:59:14 +00:00
if (strlen(value) > 0) /* must have it since we got an answer */
{
priv->has_get_modeA = 1;
2019-11-30 16:16:28 +00:00
rig_debug(RIG_DEBUG_VERBOSE, "%s: getmodeA is available=%s\n", __func__,
2019-11-27 17:59:14 +00:00
value);
}
2019-11-27 17:59:14 +00:00
else
{
2019-11-30 16:16:28 +00:00
rig_debug(RIG_DEBUG_VERBOSE, "%s: getmodeA is not available\n", __func__);
}
2019-11-27 17:59:14 +00:00
/* see if get_bwA is available */
retval = flrig_transaction(rig, "rig.get_bwA", NULL, value, sizeof(value));
2019-12-06 22:28:24 +00:00
if (retval != RIG_OK) { return retval; }
2019-11-27 17:59:14 +00:00
if (strlen(value) > 0) /* must have it since we got an answer */
{
priv->has_get_bwA = 1;
2019-11-30 16:16:28 +00:00
rig_debug(RIG_DEBUG_VERBOSE, "%s: get_bwA is available=%s\n", __func__,
2019-11-27 17:59:14 +00:00
value);
}
2019-11-27 17:59:14 +00:00
else
{
2019-11-30 16:16:28 +00:00
rig_debug(RIG_DEBUG_VERBOSE, "%s: get_bwA is not available\n", __func__);
}
strcpy(arg, value);
retval = flrig_transaction(rig, "rig.get_AB", arg, value, sizeof(value));
2019-12-06 22:28:24 +00:00
if (retval != RIG_OK) { return retval; }
2019-11-27 17:59:14 +00:00
if (streq(value, "A"))
{
rig->state.current_vfo = RIG_VFO_A;
}
2019-11-27 17:59:14 +00:00
else
{
rig->state.current_vfo = RIG_VFO_B;
}
2019-11-27 17:59:14 +00:00
2019-11-30 16:16:28 +00:00
rig_debug(RIG_DEBUG_TRACE, "%s: currvfo=%s value=%s\n", __func__,
rig_strvfo(rig->state.current_vfo), value);
//vfo_t vfo=RIG_VFO_A;
//vfo_t vfo_tx=RIG_VFO_B; // split is always VFOB
//flrig_get_split_vfo(rig, vfo, &priv->split, &vfo_tx);
/* find out available widths and modes */
retval = flrig_transaction(rig, "rig.get_modes", NULL, value, sizeof(value));
2019-11-27 17:59:14 +00:00
if (retval != RIG_OK) { return retval; }
2019-11-27 17:59:14 +00:00
2019-11-30 16:16:28 +00:00
rig_debug(RIG_DEBUG_TRACE, "%s: modes=%s\n", __func__, value);
modes = 0;
pr = value;
2019-11-27 17:59:14 +00:00
2019-12-03 15:28:43 +00:00
/* The following modes in FLRig are not implemented yet
A1A
AM-2
AM6.0
AM-D1 -- doesn't appear to be read/set
AM-D2 -- doesn't appear to be read/set
AM-D3 -- doesn't appear to be read/set
AMW -- don't have mode in rig.h
CW2.4 -- could be CW
CW500 -- could be CWN but CWN not in rig.h
CW-N -- could be CWN but CWN not in rig.h
CWN -- dcould be CWN but CWN not in rig.h
CW-NR -- don't have mode in rig.h
DATA2-LSB
DV
DV-R
F1B
FM-D1 -- doesn't appear to be read/set
FM-D2 -- doesn't appear to be read/set
FM-D3 -- doesn't appear to be read/set
H3E
M11
USB-D -- doesn't appear to be read/set
USB-D1 -- doesn't appear to be read/set
USB-D2 -- doesn't appear to be read/set
USB-D3 -- doesn't appear to be read/set
USER-L -- doesn't appear to be read/set
USER-U -- doesn't appear to be read/set
*/
2019-11-27 17:59:14 +00:00
for (p = strtok_r(value, "|", &pr); p != NULL; p = strtok_r(NULL, "|", &pr))
{
2019-12-03 15:28:43 +00:00
if (streq(p, "AM-D")) { modeMapAdd(&modes, RIG_MODE_PKTAM, p); }
else if (streq(p, "AM")) { modeMapAdd(&modes, RIG_MODE_AM, p); }
else if (streq(p, "AM-N")) { modeMapAdd(&modes, RIG_MODE_AMN, p); }
else if (streq(p, "AMN")) { modeMapAdd(&modes, RIG_MODE_AMN, p); }
else if (streq(p, "CW")) { modeMapAdd(&modes, RIG_MODE_CW, p); }
else if (streq(p, "CW-L")) { modeMapAdd(&modes, RIG_MODE_CWR, p); }
else if (streq(p, "CW-LSB")) { modeMapAdd(&modes, RIG_MODE_CWR, p); }
else if (streq(p, "CW-R")) { modeMapAdd(&modes, RIG_MODE_CWR, p); }
else if (streq(p, "CW-U")) { modeMapAdd(&modes, RIG_MODE_CW, p); }
else if (streq(p, "CW-USB")) { modeMapAdd(&modes, RIG_MODE_CW, p); }
else if (streq(p, "CWL")) { modeMapAdd(&modes, RIG_MODE_CWR, p); }
else if (streq(p, "CWU")) { modeMapAdd(&modes, RIG_MODE_CW, p); }
else if (streq(p, "D-LSB")) { modeMapAdd(&modes, RIG_MODE_PKTLSB, p); }
else if (streq(p, "D-USB")) { modeMapAdd(&modes, RIG_MODE_PKTUSB, p); }
else if (streq(p, "DATA")) { modeMapAdd(&modes, RIG_MODE_PKTUSB, p); }
else if (streq(p, "DATA-FM")) { modeMapAdd(&modes, RIG_MODE_PKTFM, p); }
else if (streq(p, "DATA-LSB")) { modeMapAdd(&modes, RIG_MODE_PKTLSB, p); }
else if (streq(p, "DATA-USB")) { modeMapAdd(&modes, RIG_MODE_PKTUSB, p); }
else if (streq(p, "DATA-U")) { modeMapAdd(&modes, RIG_MODE_PKTUSB, p); }
else if (streq(p, "DIG")) { modeMapAdd(&modes, RIG_MODE_PKTUSB, p); }
else if (streq(p, "DIGI")) { modeMapAdd(&modes, RIG_MODE_PKTUSB, p); }
else if (streq(p, "DATA-L")) { modeMapAdd(&modes, RIG_MODE_PKTLSB, p); }
else if (streq(p, "DATA-R")) { modeMapAdd(&modes, RIG_MODE_PKTLSB, p); }
else if (streq(p, "FM")) { modeMapAdd(&modes, RIG_MODE_FM, p); }
else if (streq(p, "FM-D")) { modeMapAdd(&modes, RIG_MODE_PKTFM, p); }
else if (streq(p, "FMN")) { modeMapAdd(&modes, RIG_MODE_FMN, p); }
else if (streq(p, "FM-N")) { modeMapAdd(&modes, RIG_MODE_FMN, p); }
else if (streq(p, "FMW")) { modeMapAdd(&modes, RIG_MODE_WFM, p); }
else if (streq(p, "FSK")) { modeMapAdd(&modes, RIG_MODE_PKTUSB, p); }
else if (streq(p, "FSK-R")) { modeMapAdd(&modes, RIG_MODE_PKTLSB, p); }
else if (streq(p, "LCW")) { modeMapAdd(&modes, RIG_MODE_CWR, p); }
2019-11-27 17:59:14 +00:00
else if (streq(p, "LSB")) { modeMapAdd(&modes, RIG_MODE_LSB, p); }
else if (streq(p, "LSB-D")) { modeMapAdd(&modes, RIG_MODE_PKTLSB, p); }
else if (streq(p, "LSB-D1")) { modeMapAdd(&modes, RIG_MODE_PKTLSB, p); }
else if (streq(p, "LSB-D2")) { modeMapAdd(&modes, RIG_MODE_PKTLSB, p); }
else if (streq(p, "LSB-D3")) { modeMapAdd(&modes, RIG_MODE_PKTLSB, p); }
2019-12-03 15:28:43 +00:00
else if (streq(p, "NFM")) { modeMapAdd(&modes, RIG_MODE_FMN, p); }
2019-11-27 17:59:14 +00:00
else if (streq(p, "PKT")) { modeMapAdd(&modes, RIG_MODE_PKTUSB, p); }
2019-12-03 15:28:43 +00:00
else if (streq(p, "PKT-FM")) { modeMapAdd(&modes, RIG_MODE_PKTFM, p); }
2019-11-27 17:59:14 +00:00
else if (streq(p, "PKT-L")) { modeMapAdd(&modes, RIG_MODE_PKTLSB, p); }
2019-12-03 15:28:43 +00:00
else if (streq(p, "PKT-U")) { modeMapAdd(&modes, RIG_MODE_PKTUSB, p); }
2019-11-27 17:59:14 +00:00
else if (streq(p, "PKT(L)")) { modeMapAdd(&modes, RIG_MODE_PKTLSB, p); }
2019-12-03 15:28:43 +00:00
else if (streq(p, "PKT(U)")) { modeMapAdd(&modes, RIG_MODE_PKTUSB, p); }
2019-11-27 17:59:14 +00:00
else if (streq(p, "PSK")) { modeMapAdd(&modes, RIG_MODE_PKTUSB, p); }
2019-12-03 15:28:43 +00:00
else if (streq(p, "PSK-L")) { modeMapAdd(&modes, RIG_MODE_PKTLSB, p); }
2019-11-27 17:59:14 +00:00
else if (streq(p, "PSK-R")) { modeMapAdd(&modes, RIG_MODE_PKTLSB, p); }
else if (streq(p, "PSK-U")) { modeMapAdd(&modes, RIG_MODE_PKTUSB, p); }
else if (streq(p, "RTTY")) { modeMapAdd(&modes, RIG_MODE_RTTY, p); }
else if (streq(p, "RTTY-L")) { modeMapAdd(&modes, RIG_MODE_RTTYR, p); }
2019-12-03 15:28:43 +00:00
else if (streq(p, "RTTY-R")) { modeMapAdd(&modes, RIG_MODE_RTTYR, p); }
else if (streq(p, "RTTY-U")) { modeMapAdd(&modes, RIG_MODE_RTTY, p); }
2019-11-27 17:59:14 +00:00
else if (streq(p, "RTTY(U)")) { modeMapAdd(&modes, RIG_MODE_RTTY, p); }
else if (streq(p, "RTTY(R")) { modeMapAdd(&modes, RIG_MODE_RTTYR, p); }
2019-12-03 15:28:43 +00:00
else if (streq(p, "SAH")) { modeMapAdd(&modes, RIG_MODE_SAH, p); }
else if (streq(p, "SAL")) { modeMapAdd(&modes, RIG_MODE_SAL, p); }
else if (streq(p, "SAM")) { modeMapAdd(&modes, RIG_MODE_SAM, p); }
else if (streq(p, "USB")) { modeMapAdd(&modes, RIG_MODE_USB, p); }
else if (streq(p, "USB-D")) { modeMapAdd(&modes, RIG_MODE_PKTUSB, p); }
else if (streq(p, "USB-D1")) { modeMapAdd(&modes, RIG_MODE_PKTUSB, p); }
else if (streq(p, "USB-D2")) { modeMapAdd(&modes, RIG_MODE_PKTUSB, p); }
else if (streq(p, "USB-D3")) { modeMapAdd(&modes, RIG_MODE_PKTUSB, p); }
else if (streq(p, "W-FM")) { modeMapAdd(&modes, RIG_MODE_WFM, p); }
else if (streq(p, "WFM")) { modeMapAdd(&modes, RIG_MODE_WFM, p); }
else if (streq(p, "UCW")) { modeMapAdd(&modes, RIG_MODE_CW, p); }
2019-11-30 16:16:28 +00:00
else { rig_debug(RIG_DEBUG_ERR, "%s: Unknown mode (new?) for this rig='%s'\n", __func__, p); }
}
2019-11-27 17:59:14 +00:00
rig->state.mode_list = modes;
2019-12-19 04:33:06 +00:00
retval = rig_strrmodes(modes, value, sizeof(value));
2019-12-19 04:33:06 +00:00
if (retval != RIG_OK) // we might get TRUNC but we can still print the debug
{
rig_debug(RIG_DEBUG_VERBOSE, "%s: %s\n", __func__, rigerror(retval));
}
2019-12-19 04:33:06 +00:00
rig_debug(RIG_DEBUG_VERBOSE, "%s: hamlib modes=%s\n", __func__, value);
return retval;
}
/*
* flrig_close
* Assumes rig!=NULL
*/
2019-11-27 17:59:14 +00:00
static int flrig_close(RIG *rig)
{
2019-11-30 16:16:28 +00:00
rig_debug(RIG_DEBUG_TRACE, "%s\n", __func__);
2020-01-13 04:43:40 +00:00
return RIG_OK;
}
/*
* flrig_cleanup
* Assumes rig!=NULL, rig->state.priv!=NULL
*/
2019-11-27 17:59:14 +00:00
static int flrig_cleanup(RIG *rig)
{
2019-08-23 13:29:40 +00:00
int i;
if (!rig)
2019-11-27 17:59:14 +00:00
{
return -RIG_EINVAL;
2019-11-27 17:59:14 +00:00
}
free(rig->state.priv);
rig->state.priv = NULL;
2019-11-27 17:59:14 +00:00
for (i = 0; modeMap[i].mode_hamlib != 0; ++i)
{
2020-02-23 17:26:09 +00:00
if (modeMap[i].mode_flrig)
{
free(modeMap[i].mode_flrig);
modeMap[i].mode_flrig = NULL;
2020-01-18 04:22:09 +00:00
}
2019-07-31 20:45:11 +00:00
}
2017-07-06 21:53:58 +00:00
return RIG_OK;
}
/*
* flrig_get_freq
* Assumes rig!=NULL, rig->state.priv!=NULL, freq!=NULL
*/
static int flrig_get_freq(RIG *rig, vfo_t vfo, freq_t *freq)
2017-07-06 21:53:58 +00:00
{
char value[MAXARGLEN];
struct flrig_priv_data *priv = (struct flrig_priv_data *) rig->state.priv;
2019-11-30 16:16:28 +00:00
rig_debug(RIG_DEBUG_TRACE, "%s: vfo=%s\n", __func__,
2017-07-06 21:53:58 +00:00
rig_strvfo(vfo));
2017-07-06 21:53:58 +00:00
2019-11-27 17:59:14 +00:00
if (check_vfo(vfo) == FALSE)
{
2017-07-06 21:53:58 +00:00
rig_debug(RIG_DEBUG_ERR, "%s: unsupported VFO %s\n",
2019-11-30 16:16:28 +00:00
__func__, rig_strvfo(vfo));
2017-07-06 21:53:58 +00:00
return -RIG_EINVAL;
}
2019-11-27 17:59:14 +00:00
if (vfo == RIG_VFO_CURR)
{
vfo = rig->state.current_vfo;
2019-02-05 14:08:21 +00:00
rig_debug(RIG_DEBUG_TRACE, "%s: get_freq2 vfo=%s\n",
2019-11-30 16:16:28 +00:00
__func__, rig_strvfo(vfo));
2017-07-06 21:53:58 +00:00
}
char *cmd = vfo == RIG_VFO_A ? "rig.get_vfoA" : "rig.get_vfoB";
int retval;
2019-11-27 17:59:14 +00:00
retval = flrig_transaction(rig, cmd, NULL, value, sizeof(value));
2020-05-11 03:44:34 +00:00
if (retval != RIG_OK)
{
rig_debug(RIG_DEBUG_ERR, "%s: flrig_transaction failed retval=%s\n", __func__,
rigerror(retval));
return retval;
2019-11-27 17:59:14 +00:00
}
2020-05-11 03:44:34 +00:00
2017-07-06 21:53:58 +00:00
*freq = atof(value);
2019-11-27 17:59:14 +00:00
if (*freq == 0)
{
2019-11-30 16:16:28 +00:00
rig_debug(RIG_DEBUG_ERR, "%s: freq==0??\nvalue=%s\n", __func__,
value);
2019-11-27 17:59:14 +00:00
return -(102 + RIG_EPROTO);
}
2019-11-27 17:59:14 +00:00
else
{
2019-11-30 16:16:28 +00:00
rig_debug(RIG_DEBUG_TRACE, "%s: freq=%.0f\n", __func__, *freq);
}
2019-11-27 17:59:14 +00:00
if (vfo == RIG_VFO_A)
{
priv->curr_freqA = *freq;
}
2019-11-27 17:59:14 +00:00
else
{
priv->curr_freqB = *freq;
}
2019-11-27 17:59:14 +00:00
2017-07-06 21:53:58 +00:00
return RIG_OK;
}
/*
* flrig_set_freq
* assumes rig!=NULL, rig->state.priv!=NULL
*/
static int flrig_set_freq(RIG *rig, vfo_t vfo, freq_t freq)
2017-07-06 21:53:58 +00:00
{
int retval;
char cmd_arg[MAXARGLEN];
char *cmd;
struct flrig_priv_data *priv = (struct flrig_priv_data *) rig->state.priv;
2017-07-06 21:53:58 +00:00
2019-11-30 16:16:28 +00:00
rig_debug(RIG_DEBUG_TRACE, "%s: vfo=%s freq=%.0f\n", __func__,
2017-07-06 21:53:58 +00:00
rig_strvfo(vfo), freq);
2019-11-27 17:59:14 +00:00
if (check_vfo(vfo) == FALSE)
{
2017-07-06 21:53:58 +00:00
rig_debug(RIG_DEBUG_ERR, "%s: unsupported VFO %s\n",
2019-11-30 16:16:28 +00:00
__func__, rig_strvfo(vfo));
2017-07-06 21:53:58 +00:00
return -RIG_EINVAL;
}
2019-11-27 17:59:14 +00:00
if (vfo == RIG_VFO_CURR)
{
vfo = rig->state.current_vfo;
2017-07-06 21:53:58 +00:00
}
2019-11-27 17:59:14 +00:00
else if (vfo == RIG_VFO_TX && priv->split)
{
vfo = RIG_VFO_B; // if split always TX on VFOB
2017-07-06 21:53:58 +00:00
}
sprintf(cmd_arg,
2019-11-27 17:59:14 +00:00
"<params><param><value><double>%.0f</double></value></param></params>", freq);
if (vfo == RIG_VFO_A)
2019-11-27 17:59:14 +00:00
{
cmd = "rig.set_vfoA";
2020-07-02 15:45:58 +00:00
rig_debug(RIG_DEBUG_TRACE, "rig.set_vfoA %.0f", freq);
priv->curr_freqA = freq;
}
2019-11-27 17:59:14 +00:00
else
{
cmd = "rig.set_vfoB";
2020-07-02 15:45:58 +00:00
rig_debug(RIG_DEBUG_TRACE, "rig.set_vfoA %.0f", freq);
priv->curr_freqB = freq;
}
2019-11-27 17:59:14 +00:00
retval = flrig_transaction(rig, cmd, cmd_arg, NULL, 0);
2019-11-27 17:59:14 +00:00
if (retval < 0)
{
2017-07-06 21:53:58 +00:00
return retval;
}
2019-11-27 17:59:14 +00:00
2017-07-06 21:53:58 +00:00
return RIG_OK;
}
/*
* flrig_set_ptt
* Assumes rig!=NULL
*/
static int flrig_set_ptt(RIG *rig, vfo_t vfo, ptt_t ptt)
2017-07-06 21:53:58 +00:00
{
int retval;
char cmd_arg[MAXARGLEN];
struct flrig_priv_data *priv = (struct flrig_priv_data *) rig->state.priv;
2017-07-06 21:53:58 +00:00
2019-11-30 16:16:28 +00:00
rig_debug(RIG_DEBUG_TRACE, "%s: ptt=%d\n", __func__, ptt);
2017-07-06 21:53:58 +00:00
2019-11-27 17:59:14 +00:00
if (check_vfo(vfo) == FALSE)
{
2017-07-06 21:53:58 +00:00
rig_debug(RIG_DEBUG_ERR, "%s: unsupported VFO %s\n",
2019-11-30 16:16:28 +00:00
__func__, rig_strvfo(vfo));
2017-07-06 21:53:58 +00:00
return -RIG_EINVAL;
}
sprintf(cmd_arg,
2017-07-06 21:53:58 +00:00
"<params><param><value><i4>%d</i4></value></param></params>",
ptt);
retval = flrig_transaction(rig, "rig.set_ptt", cmd_arg, NULL, 0);
2017-07-06 21:53:58 +00:00
if (retval != RIG_OK)
2019-11-27 17:59:14 +00:00
{
2017-07-06 21:53:58 +00:00
return retval;
}
priv->ptt = ptt;
2017-07-06 21:53:58 +00:00
return RIG_OK;
}
/*
* flrig_get_ptt
* Assumes rig!=NUL, ptt!=NULL
*/
static int flrig_get_ptt(RIG *rig, vfo_t vfo, ptt_t *ptt)
2017-07-06 21:53:58 +00:00
{
char value[MAXCMDLEN];
char xml[MAXXMLLEN];
struct flrig_priv_data *priv = (struct flrig_priv_data *) rig->state.priv;
2017-07-06 21:53:58 +00:00
2019-11-30 16:16:28 +00:00
rig_debug(RIG_DEBUG_TRACE, "%s: vfo=%s\n", __func__,
2017-07-06 21:53:58 +00:00
rig_strvfo(vfo));
int retval;
2020-05-11 23:05:11 +00:00
retval = flrig_transaction(rig, "rig.get_ptt", NULL, value, sizeof(value));
2020-05-11 23:05:11 +00:00
if (retval != RIG_OK)
{
return retval;
2017-07-06 21:53:58 +00:00
}
xml_parse(xml, value, sizeof(value));
*ptt = atoi(value);
rig_debug(RIG_DEBUG_TRACE, "%s: '%s'\n", __func__, value);
2017-07-06 21:53:58 +00:00
priv->ptt = *ptt;
2017-07-06 21:53:58 +00:00
return RIG_OK;
}
/*
* flrig_set_split_mode
* Assumes rig!=NULL
*/
2019-11-27 17:59:14 +00:00
static int flrig_set_split_mode(RIG *rig, vfo_t vfo, rmode_t mode,
pbwidth_t width)
{
int retval;
struct flrig_priv_data *priv = (struct flrig_priv_data *) rig->state.priv;
rig_debug(RIG_DEBUG_TRACE, "%s: vfo=%s mode=%s width=%d\n",
2019-11-30 16:16:28 +00:00
__func__, rig_strvfo(vfo), rig_strrmode(mode), (int)width);
2019-11-27 17:59:14 +00:00
switch (vfo)
{
case RIG_VFO_CURR:
vfo = rig->state.current_vfo;
break;
2019-11-27 17:59:14 +00:00
case RIG_VFO_TX:
vfo = RIG_VFO_B;
break;
}
2019-11-27 17:59:14 +00:00
// If no change don't do it...modes are kept up to date by client calls
// to get_mode and set_mode so should be current here
2019-11-30 16:16:28 +00:00
rig_debug(RIG_DEBUG_TRACE, "%s: vfoa privmode=%s\n", __func__,
2019-11-27 17:59:14 +00:00
rig_strrmode(priv->curr_modeA));
2019-11-30 16:16:28 +00:00
rig_debug(RIG_DEBUG_TRACE, "%s: vfob privmode=%s\n", __func__,
2019-11-27 17:59:14 +00:00
rig_strrmode(priv->curr_modeB));
// save some VFO swapping .. may replace with VFO specific calls that won't cause VFO change
2019-11-27 17:59:14 +00:00
if (vfo == RIG_VFO_A && mode == priv->curr_modeA) { return RIG_OK; }
if (vfo == RIG_VFO_B && mode == priv->curr_modeB) { return RIG_OK; }
retval = flrig_set_mode(rig, vfo, mode, width);
2019-11-30 16:16:28 +00:00
rig_debug(RIG_DEBUG_TRACE, "%s: set mode=%s\n", __func__,
2019-11-27 17:59:14 +00:00
rig_strrmode(mode));
return retval;
}
2017-07-06 21:53:58 +00:00
/*
* flrig_set_mode
* Assumes rig!=NULL
*/
static int flrig_set_mode(RIG *rig, vfo_t vfo, rmode_t mode, pbwidth_t width)
2017-07-06 21:53:58 +00:00
{
int retval;
int needBW;
int vfoSwitched;
char cmd_arg[MAXCMDLEN];
char *p;
char *pttmode;
char *ttmode;
struct flrig_priv_data *priv = (struct flrig_priv_data *) rig->state.priv;
rig_debug(RIG_DEBUG_TRACE, "%s: vfo=%s mode=%s width=%d\n",
2019-11-30 16:16:28 +00:00
__func__, rig_strvfo(vfo), rig_strrmode(mode), (int)width);
2017-07-06 21:53:58 +00:00
// if ptt is on do not set mode
2019-11-27 17:59:14 +00:00
if (priv->ptt)
{
2019-11-30 16:19:08 +00:00
rig_debug(RIG_DEBUG_TRACE, "%s: returning because priv->ptt=%d\n", __func__,
(int)priv->ptt);
2019-11-27 17:59:14 +00:00
return RIG_OK;
}
2019-11-27 17:59:14 +00:00
if (vfo == RIG_VFO_CURR)
{
vfo = rig->state.current_vfo;
}
2017-07-06 21:53:58 +00:00
2019-11-27 17:59:14 +00:00
if (check_vfo(vfo) == FALSE)
{
2017-07-06 21:53:58 +00:00
rig_debug(RIG_DEBUG_ERR, "%s: unsupported VFO %s\n",
2019-11-30 16:16:28 +00:00
__func__, rig_strvfo(vfo));
2017-07-06 21:53:58 +00:00
return -RIG_EINVAL;
}
2019-11-27 17:59:14 +00:00
if (priv->ptt)
{
2019-11-30 16:16:28 +00:00
rig_debug(RIG_DEBUG_WARN, "%s call not made as PTT=1\n", __func__);
return RIG_OK; // just return OK and ignore this
}
2017-07-06 21:53:58 +00:00
// Switch to VFOB if appropriate since we can't set mode directly
// MDB
vfoSwitched = 0;
2019-11-30 16:16:28 +00:00
rig_debug(RIG_DEBUG_TRACE, "%s: curr_vfo = %s\n", __func__,
rig_strvfo(rig->state.current_vfo));
2019-11-27 17:59:14 +00:00
// If we don't have the get_bwA call we have to switch VFOs ourself
if (!priv->has_get_bwA && vfo == RIG_VFO_B
&& rig->state.current_vfo != RIG_VFO_B)
2019-11-27 17:59:14 +00:00
{
vfoSwitched = 1;
2019-11-30 16:16:28 +00:00
rig_debug(RIG_DEBUG_TRACE, "%s: switch to VFOB = %d\n", __func__,
2019-11-27 17:59:14 +00:00
vfoSwitched);
}
2017-07-06 21:53:58 +00:00
2019-11-27 17:59:14 +00:00
if (vfoSwitched) // swap to B and we'll swap back later
{
2019-11-30 16:16:28 +00:00
rig_debug(RIG_DEBUG_TRACE, "%s: switching to VFOB = %d\n", __func__,
2019-11-27 17:59:14 +00:00
vfoSwitched);
retval = flrig_set_vfo(rig, RIG_VFO_B);
2019-11-27 17:59:14 +00:00
if (retval < 0)
{
return retval;
}
}
2017-07-06 21:53:58 +00:00
// Set the mode
ttmode = strdup(modeMapGetFLRig(mode));
2019-11-30 16:16:28 +00:00
rig_debug(RIG_DEBUG_TRACE, "%s: got ttmode = %s\n", __func__,
2019-11-27 17:59:14 +00:00
ttmode == NULL ? "NULL" : ttmode);
2020-01-13 04:43:40 +00:00
if (ttmode == NULL)
{
rig_debug(RIG_DEBUG_ERR, "%s: strdup failed\n", __func__);
return -RIG_EINTERNAL;
}
pttmode = ttmode;
2019-11-27 17:59:14 +00:00
if (ttmode[0] == '|') { pttmode = &ttmode[1]; } // remove first pipe symbol
p = strchr(pttmode, '|');
2019-11-27 17:59:14 +00:00
if (p) { *p = 0; } // remove any other pipe
2017-07-06 21:53:58 +00:00
sprintf(cmd_arg, "<params><param><value>%s</value></param></params>", pttmode);
free(ttmode);
2019-11-27 17:59:14 +00:00
if (!priv->has_get_modeA)
{
retval = flrig_transaction(rig, "rig.set_mode", cmd_arg, NULL, 0);
}
2019-11-27 17:59:14 +00:00
else
{
char *cmd = "rig.set_modeA";
if (vfo == RIG_VFO_B)
{
cmd = "rig.set_modeB";
}
2019-12-19 04:33:06 +00:00
else
{
// we make VFO_B mode unknown so it expires the cache
priv->curr_modeB = RIG_MODE_NONE;
}
2019-11-27 17:59:14 +00:00
retval = flrig_transaction(rig, cmd, cmd_arg, NULL, 0);
}
2017-07-06 21:53:58 +00:00
2019-11-27 17:59:14 +00:00
if (retval != RIG_OK)
2019-11-27 17:59:14 +00:00
{
rig_debug(RIG_DEBUG_ERR, "%s: failed: %s\n", __func__,
rigerror(retval));
return retval;
2017-07-06 21:53:58 +00:00
}
// Determine if we need to update the bandwidth
needBW = 0;
2019-11-27 17:59:14 +00:00
if (vfo == RIG_VFO_A)
{
needBW = priv->curr_widthA != width;
rig_debug(RIG_DEBUG_TRACE, "%s: bw change on VFOA, curr width=%d needBW=%d\n",
2019-11-30 16:16:28 +00:00
__func__, (int)width, needBW);
}
2019-11-27 17:59:14 +00:00
else if (vfo == RIG_VFO_B)
{
needBW = priv->curr_widthB != width;
rig_debug(RIG_DEBUG_TRACE, "%s: bw change on VFOB, curr width=%d needBW=%d\n",
2019-11-30 16:16:28 +00:00
__func__, (int)width, needBW);
}
2019-11-27 17:59:14 +00:00
else
{
2019-11-30 16:16:28 +00:00
rig_debug(RIG_DEBUG_TRACE, "%s: needBW unknown vfo=%s\n", __func__,
2019-11-27 17:59:14 +00:00
rig_strvfo(vfo));
}
2019-11-27 17:59:14 +00:00
// Need to update the bandwidth
2019-11-27 17:59:14 +00:00
if (width > 0 && needBW)
{
sprintf(cmd_arg, "<params><param><value><i4>%ld</i4></value></param></params>",
2019-11-27 17:59:14 +00:00
width);
// if we're not on VFOB but asking for VFOB still have to switch VFOS
2019-11-27 17:59:14 +00:00
if (!vfoSwitched && vfo == RIG_VFO_B) { flrig_set_vfo(rig, RIG_VFO_B); }
if (!vfoSwitched && vfo == RIG_VFO_A) { flrig_set_vfo(rig, RIG_VFO_A); }
retval = flrig_transaction(rig, "rig.set_bandwidth", cmd_arg, NULL,
0);
2019-11-27 17:59:14 +00:00
if (retval < 0)
{
return retval;
}
2019-11-27 17:59:14 +00:00
flrig_set_vfo(rig, vfo); // ensure reset to our initial vfo
}
2017-07-06 21:53:58 +00:00
// Return to VFOA if needed
2019-11-30 16:16:28 +00:00
rig_debug(RIG_DEBUG_TRACE, "%s: switch to VFOA? = %d\n", __func__,
2019-11-27 17:59:14 +00:00
vfoSwitched);
if (vfoSwitched)
{
2019-11-30 16:16:28 +00:00
rig_debug(RIG_DEBUG_TRACE, "%s: switching to VFOA\n", __func__);
retval = flrig_set_vfo(rig, RIG_VFO_A);
2019-11-27 17:59:14 +00:00
if (retval < 0)
{
return retval;
}
}
2017-07-06 21:53:58 +00:00
2019-11-27 17:59:14 +00:00
if (vfo == RIG_VFO_A)
{
priv->curr_modeA = mode;
priv->curr_widthA = width;
}
2019-11-27 17:59:14 +00:00
else
{
priv->curr_modeB = mode;
priv->curr_widthB = width;
2017-07-06 21:53:58 +00:00
}
2019-11-27 17:59:14 +00:00
rig_debug(RIG_DEBUG_TRACE,
2019-11-30 16:16:28 +00:00
"%s: return modeA=%s, widthA=%d\n,modeB=%s, widthB=%d\n", __func__,
rig_strrmode(priv->curr_modeA), (int)priv->curr_widthA,
rig_strrmode(priv->curr_modeB), (int)priv->curr_widthB);
2017-07-06 21:53:58 +00:00
return RIG_OK;
}
/*
* flrig_get_mode
* Assumes rig!=NULL, rig->state.priv!=NULL, mode!=NULL
*/
static int flrig_get_mode(RIG *rig, vfo_t vfo, rmode_t *mode, pbwidth_t *width)
2017-07-06 21:53:58 +00:00
{
int retval;
int vfoSwitched;
char value[MAXCMDLEN];
char *cmdp;
vfo_t curr_vfo;
rmode_t my_mode;
struct flrig_priv_data *priv = (struct flrig_priv_data *) rig->state.priv;
2017-07-06 21:53:58 +00:00
2019-11-30 16:16:28 +00:00
rig_debug(RIG_DEBUG_TRACE, "%s: vfo=%s\n", __func__,
2017-07-06 21:53:58 +00:00
rig_strvfo(vfo));
2019-11-27 17:59:14 +00:00
if (check_vfo(vfo) == FALSE)
{
rig_debug(RIG_DEBUG_ERR, "%s: unsupported VFO %s\n",
2019-11-30 16:16:28 +00:00
__func__, rig_strvfo(vfo));
return -RIG_EINVAL;
}
curr_vfo = rig->state.current_vfo;
2019-11-27 17:59:14 +00:00
if (vfo == RIG_VFO_CURR)
{
vfo = rig->state.current_vfo;
}
2019-11-27 17:59:14 +00:00
2019-11-30 16:16:28 +00:00
rig_debug(RIG_DEBUG_TRACE, "%s: using vfo=%s\n", __func__,
rig_strvfo(vfo));
2019-11-27 17:59:14 +00:00
if (priv->ptt)
{
if (vfo == RIG_VFO_A) { *mode = priv->curr_modeA; }
else { *mode = priv->curr_modeB; }
2019-11-30 16:16:28 +00:00
rig_debug(RIG_DEBUG_WARN, "%s call not made as PTT=1\n", __func__);
return RIG_OK; // just return OK and ignore this
}
// Switch to VFOB if appropriate
vfoSwitched = 0;
2019-11-27 17:59:14 +00:00
if (priv->has_get_modeA == 0 && vfo == RIG_VFO_B && curr_vfo != RIG_VFO_B)
{
vfoSwitched = 1;
}
2019-11-27 17:59:14 +00:00
if (vfoSwitched)
{
2019-11-30 16:16:28 +00:00
rig_debug(RIG_DEBUG_TRACE, "%s switch to VFOB=%d\n", __func__,
2019-11-27 17:59:14 +00:00
priv->has_get_modeA);
retval = flrig_set_vfo(rig, RIG_VFO_B);
2019-11-27 17:59:14 +00:00
if (retval < 0)
{
return retval;
}
}
cmdp = "rig.get_mode"; /* default to old way */
2019-11-27 17:59:14 +00:00
if (priv->has_get_modeA) /* change to new way if we can */
{
/* calling this way reduces VFO swapping */
/* we get the cached value in flrig */
/* vfo B may not be getting polled though in FLRig */
/* so we may not be 100% accurate if op is twiddling knobs */
cmdp = "rig.get_modeA";
2019-11-27 17:59:14 +00:00
if (vfo == RIG_VFO_B) { cmdp = "rig.get_modeB"; }
}
2019-11-27 17:59:14 +00:00
retval = flrig_transaction(rig, cmdp, NULL, value, sizeof(value));
2019-11-27 17:59:14 +00:00
if (retval != RIG_OK)
2019-11-27 17:59:14 +00:00
{
rig_debug(RIG_DEBUG_ERR, "%s: %s failed: %s\n", __func__, cmdp,
rigerror(retval));
return retval;
}
my_mode = modeMapGetHamlib(value);
*mode = my_mode;
2019-11-30 16:16:28 +00:00
rig_debug(RIG_DEBUG_TRACE, "%s: mode='%s'\n", __func__,
2019-11-27 17:59:14 +00:00
rig_strrmode(*mode));
if (vfo == RIG_VFO_A)
{
priv->curr_modeA = *mode;
}
2019-11-27 17:59:14 +00:00
else
{
priv->curr_modeB = *mode;
}
/* Get the bandwidth */
2019-11-27 17:59:14 +00:00
cmdp = "rig.get_bw"; /* default to old way */
if (priv->has_get_bwA) /* change to new way if we can */
{
/* calling this way reduces VFO swapping */
/* we get the cached value in flrig */
/* vfo B may not be getting polled though in FLRig */
/* so we may not be 100% accurate if op is twiddling knobs */
cmdp = "rig.get_bwA";
2019-11-27 17:59:14 +00:00
if (vfo == RIG_VFO_B) { cmdp = "rig.get_bwB"; }
}
2019-11-27 17:59:14 +00:00
retval = flrig_transaction(rig, cmdp, NULL, value, sizeof(value));
2019-11-27 17:59:14 +00:00
if (retval != RIG_OK)
2019-11-27 17:59:14 +00:00
{
2017-07-06 21:53:58 +00:00
return retval;
}
2019-11-30 16:16:28 +00:00
rig_debug(RIG_DEBUG_TRACE, "%s: mode=%s width='%s'\n", __func__,
2019-11-27 17:59:14 +00:00
rig_strrmode(*mode), value);
// we get 2 entries pipe separated for bandwidth, lower and upper
2019-11-27 17:59:14 +00:00
if (strlen(value) > 0)
{
char *p = value;
/* we might get two values and then we want the 2nd one */
2019-11-27 17:59:14 +00:00
if (strchr(value, '|') != NULL) { p = strchr(value, '|') + 1; }
*width = atoi(p);
}
2019-11-27 17:59:14 +00:00
if (vfo == RIG_VFO_A)
{
priv->curr_widthA = *width;
}
2019-11-27 17:59:14 +00:00
else
{
priv->curr_widthB = *width;
}
// Return to VFOA if needed
2019-11-27 17:59:14 +00:00
if (vfoSwitched)
{
retval = flrig_set_vfo(rig, RIG_VFO_A);
2019-11-27 17:59:14 +00:00
if (retval != RIG_OK)
2019-11-27 17:59:14 +00:00
{
return retval;
}
}
2017-07-06 21:53:58 +00:00
return RIG_OK;
}
/*
2020-05-11 03:44:34 +00:00
* flrig_set_vfo
* assumes rig!=NULL
*/
static int flrig_set_vfo(RIG *rig, vfo_t vfo)
2017-07-06 21:53:58 +00:00
{
int retval;
char cmd_arg[MAXXMLLEN];
struct rig_state *rs = &rig->state;
struct flrig_priv_data *priv = (struct flrig_priv_data *) rig->state.priv;
2017-07-06 21:53:58 +00:00
2019-11-30 16:16:28 +00:00
rig_debug(RIG_DEBUG_TRACE, "%s: vfo=%s\n", __func__,
2017-07-06 21:53:58 +00:00
rig_strvfo(vfo));
2017-07-06 21:53:58 +00:00
2019-11-27 17:59:14 +00:00
if (check_vfo(vfo) == FALSE)
{
2017-07-06 21:53:58 +00:00
rig_debug(RIG_DEBUG_ERR, "%s: unsupported VFO %s\n",
2019-11-30 16:16:28 +00:00
__func__, rig_strvfo(vfo));
2017-07-06 21:53:58 +00:00
return -RIG_EINVAL;
}
2019-11-27 17:59:14 +00:00
if (vfo == RIG_VFO_TX)
{
2019-11-30 16:19:08 +00:00
rig_debug(RIG_DEBUG_TRACE, "%s: RIG_VFO_TX used\n", __func__);
vfo = RIG_VFO_B; // always TX on VFOB
}
2017-07-06 21:53:58 +00:00
2019-11-27 17:59:14 +00:00
if (vfo == RIG_VFO_CURR)
{
vfo = rig->state.current_vfo;
2017-07-06 21:53:58 +00:00
}
sprintf(cmd_arg, "<params><param><value>%s</value></param></params>",
2017-07-06 21:53:58 +00:00
vfo == RIG_VFO_A ? "A" : "B");
retval = flrig_transaction(rig, "rig.set_AB", cmd_arg, NULL, 0);
2017-07-06 21:53:58 +00:00
if (retval != RIG_OK)
2019-11-27 17:59:14 +00:00
{
rig_debug(RIG_DEBUG_ERR, "%s: rig.set_AB failed: %s\n", __func__,
rigerror(retval));
2017-07-06 21:53:58 +00:00
return retval;
}
2019-11-27 17:59:14 +00:00
rig->state.current_vfo = vfo;
rs->tx_vfo = RIG_VFO_B; // always VFOB
2017-07-06 21:53:58 +00:00
/* for some rigs FLRig turns off split when VFOA is selected */
/* so if we are in split and asked for A we have to turn split back on */
2019-11-27 17:59:14 +00:00
if (priv->split && vfo == RIG_VFO_A)
{
sprintf(cmd_arg, "<params><param><value><i4>%d</i4></value></param></params>",
2019-11-27 17:59:14 +00:00
priv->split);
retval = flrig_transaction(rig, "rig.set_split", cmd_arg, NULL, 0);
2019-11-27 17:59:14 +00:00
if (retval < 0)
{
return retval;
}
}
2019-11-27 17:59:14 +00:00
2017-07-06 21:53:58 +00:00
return RIG_OK;
}
/*
* flrig_get_vfo
* assumes rig!=NULL, vfo != NULL
*/
static int flrig_get_vfo(RIG *rig, vfo_t *vfo)
2017-07-06 21:53:58 +00:00
{
char value[MAXCMDLEN];
2017-07-06 21:53:58 +00:00
2019-11-30 16:16:28 +00:00
rig_debug(RIG_DEBUG_TRACE, "%s\n", __func__);
2017-07-06 21:53:58 +00:00
int retval;
retval = flrig_transaction(rig, "rig.get_AB", NULL, value, sizeof(value));
2020-05-11 23:05:11 +00:00
if (retval < 0)
{
return retval;
2017-07-06 21:53:58 +00:00
}
rig_debug(RIG_DEBUG_TRACE, "%s: vfo value=%s\n", __func__, value);
2017-07-06 21:53:58 +00:00
2019-11-27 17:59:14 +00:00
switch (value[0])
{
2017-07-06 21:53:58 +00:00
case 'A':
*vfo = RIG_VFO_A;
break;
case 'B':
*vfo = RIG_VFO_B;
break;
default:
*vfo = RIG_VFO_CURR;
return -RIG_EINVAL;
}
2019-11-27 17:59:14 +00:00
if (check_vfo(*vfo) == FALSE)
{
2017-07-06 21:53:58 +00:00
rig_debug(RIG_DEBUG_ERR, "%s: unsupported VFO %s\n",
2019-11-30 16:16:28 +00:00
__func__, rig_strvfo(*vfo));
2017-07-06 21:53:58 +00:00
return -RIG_EINVAL;
}
rig->state.current_vfo = *vfo;
2017-07-06 21:53:58 +00:00
2019-11-30 16:16:28 +00:00
rig_debug(RIG_DEBUG_TRACE, "%s: vfo=%s\n", __func__,
2017-07-06 21:53:58 +00:00
rig_strvfo(*vfo));
return RIG_OK;
}
/*
* flrig_set_split_freq
* assumes rig!=NULL
2017-07-06 21:53:58 +00:00
*/
static int flrig_set_split_freq(RIG *rig, vfo_t vfo, freq_t tx_freq)
2017-07-06 21:53:58 +00:00
{
int retval;
char cmd_arg[MAXXMLLEN];
freq_t qtx_freq;
struct flrig_priv_data *priv = (struct flrig_priv_data *) rig->state.priv;
2017-07-06 21:53:58 +00:00
2019-11-30 16:16:28 +00:00
rig_debug(RIG_DEBUG_TRACE, "%s: vfo=%s freq=%.1f\n", __func__,
2017-07-06 21:53:58 +00:00
rig_strvfo(vfo), tx_freq);
2019-11-27 17:59:14 +00:00
if (check_vfo(vfo) == FALSE)
{
2017-07-06 21:53:58 +00:00
rig_debug(RIG_DEBUG_ERR, "%s: unsupported VFO %s\n",
2019-11-30 16:16:28 +00:00
__func__, rig_strvfo(vfo));
2017-07-06 21:53:58 +00:00
return -RIG_EINVAL;
}
2019-11-27 17:59:14 +00:00
// we always split on VFOB so if no change just return
retval = flrig_get_freq(rig, RIG_VFO_B, &qtx_freq);
2019-11-27 17:59:14 +00:00
if (retval != RIG_OK) { return retval; }
if (tx_freq == qtx_freq) { return RIG_OK; }
2017-07-06 21:53:58 +00:00
sprintf(cmd_arg,
2019-11-27 17:59:14 +00:00
"<params><param><value><double>%.6f</double></value></param></params>",
tx_freq);
retval = flrig_transaction(rig, "rig.set_vfoB", cmd_arg, NULL, 0);
2019-11-27 17:59:14 +00:00
if (retval < 0)
{
2017-07-06 21:53:58 +00:00
return retval;
}
2019-11-27 17:59:14 +00:00
priv->curr_freqB = tx_freq;
2017-07-06 21:53:58 +00:00
return RIG_OK;
}
/*
* flrig_get_split_freq
* assumes rig!=NULL, tx_freq!=NULL
*/
static int flrig_get_split_freq(RIG *rig, vfo_t vfo, freq_t *tx_freq)
2017-07-06 21:53:58 +00:00
{
int retval;
struct flrig_priv_data *priv = (struct flrig_priv_data *) rig->state.priv;
2019-11-30 16:16:28 +00:00
rig_debug(RIG_DEBUG_TRACE, "%s: vfo=%s\n", __func__,
2017-07-06 21:53:58 +00:00
rig_strvfo(vfo));
retval = flrig_get_freq(rig, RIG_VFO_B, tx_freq);
priv->curr_freqB = *tx_freq;
return retval;
2017-07-06 21:53:58 +00:00
}
/*
* flrig_set_split_vfo
* assumes rig!=NULL, tx_freq!=NULL
*/
static int flrig_set_split_vfo(RIG *rig, vfo_t vfo, split_t split, vfo_t tx_vfo)
2017-07-06 21:53:58 +00:00
{
int retval;
vfo_t qtx_vfo;
split_t qsplit;
struct flrig_priv_data *priv = (struct flrig_priv_data *) rig->state.priv;
char cmd_arg[MAXXMLLEN];
2017-07-06 21:53:58 +00:00
2019-11-30 16:16:28 +00:00
rig_debug(RIG_DEBUG_TRACE, "%s: tx_vfo=%s\n", __func__,
2017-07-06 21:53:58 +00:00
rig_strvfo(tx_vfo));
retval = flrig_get_split_vfo(rig, RIG_VFO_A, &qsplit, &qtx_vfo);
2019-11-27 17:59:14 +00:00
if (retval != RIG_OK) { return retval; }
if (split == qsplit) { return RIG_OK; }
if (priv->ptt)
{
2019-11-30 16:16:28 +00:00
rig_debug(RIG_DEBUG_WARN, "%s call not made as PTT=1\n", __func__);
return RIG_OK; // just return OK and ignore this
2017-07-06 21:53:58 +00:00
}
sprintf(cmd_arg, "<params><param><value><i4>%d</i4></value></param></params>",
2019-11-27 17:59:14 +00:00
split);
retval = flrig_transaction(rig, "rig.set_split", cmd_arg, NULL, 0);
2019-11-27 17:59:14 +00:00
if (retval < 0)
{
2017-07-06 21:53:58 +00:00
return retval;
}
2019-11-27 17:59:14 +00:00
priv->split = split;
2017-07-06 21:53:58 +00:00
return RIG_OK;
}
/*
* flrig_get_split_vfo
* assumes rig!=NULL, tx_freq!=NULL
*/
static int flrig_get_split_vfo(RIG *rig, vfo_t vfo, split_t *split,
vfo_t *tx_vfo)
2017-07-06 21:53:58 +00:00
{
char value[MAXCMDLEN];
struct flrig_priv_data *priv = (struct flrig_priv_data *) rig->state.priv;
2017-07-06 21:53:58 +00:00
2019-11-30 16:16:28 +00:00
rig_debug(RIG_DEBUG_TRACE, "%s\n", __func__);
2017-07-06 21:53:58 +00:00
int retval;
retval = flrig_transaction(rig, "rig.get_split", NULL, value, sizeof(value));
2020-05-11 23:05:11 +00:00
if (retval < 0)
{
return retval;
2017-07-06 21:53:58 +00:00
}
*tx_vfo = RIG_VFO_B;
*split = atoi(value);
priv->split = *split;
2019-11-30 16:16:28 +00:00
rig_debug(RIG_DEBUG_TRACE, "%s tx_vfo=%s, split=%d\n", __func__,
2019-11-27 17:59:14 +00:00
rig_strvfo(*tx_vfo), *split);
2017-07-06 21:53:58 +00:00
return RIG_OK;
}
/*
* flrig_set_split_freq_mode
* assumes rig!=NULL
*/
2019-11-27 17:59:14 +00:00
static int flrig_set_split_freq_mode(RIG *rig, vfo_t vfo, freq_t freq,
rmode_t mode, pbwidth_t width)
{
int retval;
rmode_t qmode;
pbwidth_t qwidth;
struct flrig_priv_data *priv = (struct flrig_priv_data *) rig->state.priv;
2019-11-30 16:16:28 +00:00
rig_debug(RIG_DEBUG_TRACE, "%s\n", __func__);
if (vfo != RIG_VFO_CURR && vfo != RIG_VFO_TX)
2019-11-27 17:59:14 +00:00
{
return -RIG_ENTARGET;
2019-11-27 17:59:14 +00:00
}
2019-11-27 17:59:14 +00:00
if (priv->ptt)
{
2019-11-30 16:16:28 +00:00
rig_debug(RIG_DEBUG_WARN, "%s call not made as PTT=1\n", __func__);
return RIG_OK; // just return OK and ignore this
}
2019-11-27 17:59:14 +00:00
retval = flrig_set_freq(rig, RIG_VFO_B, freq);
if (retval != RIG_OK)
{
2019-11-30 16:16:28 +00:00
rig_debug(RIG_DEBUG_ERR, "%s flrig_set_freq failed\n", __func__);
return retval;
}
2019-11-27 17:59:14 +00:00
// Make VFOB mode match VFOA mode, keep VFOB width
2019-11-27 17:59:14 +00:00
retval = flrig_get_mode(rig, RIG_VFO_B, &qmode, &qwidth);
if (retval != RIG_OK) { return retval; }
if (qmode == priv->curr_modeA) { return RIG_OK; }
retval = flrig_set_mode(rig, RIG_VFO_B, priv->curr_modeA, width);
if (retval != RIG_OK)
{
2019-11-30 16:16:28 +00:00
rig_debug(RIG_DEBUG_ERR, "%s flrig_set_mode failed\n", __func__);
return retval;
}
2019-11-27 17:59:14 +00:00
retval = flrig_set_vfo(rig, RIG_VFO_A);
return retval;
}
/*
* flrig_get_split_freq_mode
* assumes rig!=NULL, freq!=NULL, mode!=NULL, width!=NULL
*/
2019-11-27 17:59:14 +00:00
static int flrig_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)
2019-11-27 17:59:14 +00:00
{
return -RIG_ENTARGET;
2019-11-27 17:59:14 +00:00
}
retval = flrig_get_freq(rig, RIG_VFO_B, freq);
2019-11-27 17:59:14 +00:00
if (RIG_OK == retval)
{
retval = flrig_get_mode(rig, vfo, mode, width);
}
return retval;
}
/*
* flrig_get_info
* assumes rig!=NULL
*/
static const char *flrig_get_info(RIG *rig)
{
struct flrig_priv_data *priv = (struct flrig_priv_data *) rig->state.priv;
2019-11-30 16:16:28 +00:00
rig_debug(RIG_DEBUG_TRACE, "%s called\n", __func__);
return priv->info;
}