kopia lustrzana https://github.com/Hamlib/Hamlib
Merge branch 'master' into initial-spectrum-scope-support
commit
a7de662937
|
@ -18,7 +18,7 @@ Split=0 SatMode=0
|
|||
PTT=1 (1=On, 0=Off)
|
||||
Rig=Dummy (name of connected rig)
|
||||
App=Hamlib (name of application providing the packet)
|
||||
Version=20210429 (version YYYYMMDD) -- reverse compatibilty will be maintained
|
||||
Version=20210429 1.0.0 (version YYYYMMDD)
|
||||
Status=OK (possible values OK, Offline, Error)
|
||||
ErrorMsg=msg text (pipe delimited multi-line error message)
|
||||
CRC=0xf49f4708 (this is just an example CRC and not accurate for this example)
|
||||
|
@ -45,8 +45,10 @@ Example JSON
|
|||
"TX": false
|
||||
}],
|
||||
|
||||
"__comment_spectrum__": "Rigs that have spectrum output may include this data",
|
||||
"Spectrum": {
|
||||
"__comment_spectra__": "Rigs that have spectrum output may include this array data",
|
||||
"Spectra": [
|
||||
{
|
||||
"Name": "Main",
|
||||
"Length": 475,
|
||||
"__comment_spectrum_data__": "2-char hex bytes so data len=2*Length",
|
||||
"Data": "00AAFF75BD2AAA...",
|
||||
|
@ -64,16 +66,42 @@ Example JSON
|
|||
"LowFreq": 14000000,
|
||||
"HighFreq": 14250000
|
||||
},
|
||||
{
|
||||
"Name": "Sub",
|
||||
"Length": 475,
|
||||
"__comment_spectrum_data__": "2-char hex bytes so data len=2*Length",
|
||||
"Data": "00AAFF75BD2AAA...",
|
||||
"Type": "FIXED|CENTER",
|
||||
"MinLevel": 0,
|
||||
"MaxLevel": 140,
|
||||
"MinStrength": -100,
|
||||
"MaxStrength": 0,
|
||||
|
||||
"__comment_spectrum_center__": "If Type=CENTER, the following fields will be present:",
|
||||
"CenterFreq": 14267000,
|
||||
"Span": 25000,
|
||||
|
||||
"__comment_spectrum_fixed__": "If SpectrumType=FIXED, the following fields will be present:",
|
||||
"LowFreq": 14000000,
|
||||
"HighFreq": 14250000
|
||||
}],
|
||||
LastCommand {
|
||||
"ID": "MyApp 123",
|
||||
"Command": "set_freq VFOA 14074000".
|
||||
"Status": "OK"
|
||||
},
|
||||
"PTT" : false,
|
||||
"Split": true,
|
||||
"SatMode": false,
|
||||
"Rig": "Dummy",
|
||||
"App": "Hamlib",
|
||||
"__comment_version__": "protocol version date YYYYMMDD",
|
||||
"Version": "20210520",
|
||||
"__comment_version__": "protocol version YYYYMMDD x.x.x, 1.0.0 will be used when this is implemented",
|
||||
"Version": "20210521 0.0.0",
|
||||
"Status": "OK";
|
||||
"__comment_seq__": "Seq is 1-up sequence number 32-bit -- wraps around to 1 from 2^32-1",
|
||||
"Seq": 1,
|
||||
"__comment_crc__": "32-bit CRC of entire JSON record replacing the CRC value with 0x00000000",
|
||||
"ErrorMsg": "OK",
|
||||
"CRC": "0x00000000"
|
||||
}
|
||||
|
||||
|
@ -115,16 +143,24 @@ namespace HamlibMultiCast
|
|||
public double LowFreq;
|
||||
public double HighFreq;
|
||||
}
|
||||
LastCommand {
|
||||
public string ID; // an application name plus sequence number recommended
|
||||
public string Command;
|
||||
public string Status;
|
||||
}
|
||||
public string ID;
|
||||
public List<VFO> VFOs { get; set; }
|
||||
public bool PTT;
|
||||
public bool Split;
|
||||
public bool SatMode;
|
||||
public string Rig;
|
||||
public string App;
|
||||
public string Version;
|
||||
public string Status;
|
||||
public UInt32 Seq;
|
||||
public string CRC;
|
||||
public SpectrumClass Spectrum { get; set; }
|
||||
public string ErrorMsg;
|
||||
}
|
||||
class Program
|
||||
{
|
||||
|
|
|
@ -20,6 +20,7 @@ namespace HamlibMultiCast
|
|||
}
|
||||
public class SpectrumClass
|
||||
{
|
||||
public string Name;
|
||||
public int Length;
|
||||
public string Data;
|
||||
public string Type;
|
||||
|
@ -32,6 +33,11 @@ namespace HamlibMultiCast
|
|||
public double LowFreq;
|
||||
public double HighFreq;
|
||||
}
|
||||
public class LastCommand {
|
||||
public string ID;
|
||||
public string Command;
|
||||
public string Status;
|
||||
}
|
||||
public string ID;
|
||||
public List<VFO> VFOs { get; set; }
|
||||
public bool Split;
|
||||
|
@ -41,7 +47,7 @@ namespace HamlibMultiCast
|
|||
public string Version;
|
||||
public UInt32 Seq;
|
||||
public string CRC;
|
||||
public SpectrumClass Spectrum { get; set; }
|
||||
public List<SpectrumClass> Spectra { get; set; }
|
||||
}
|
||||
class Program
|
||||
{
|
||||
|
|
|
@ -20,7 +20,9 @@
|
|||
}],
|
||||
|
||||
"__comment_spectrum__": "Rigs that have spectrum output may include this data",
|
||||
"Spectrum": {
|
||||
"Spectra": [
|
||||
{
|
||||
"Name": "Main",
|
||||
"Length": 475,
|
||||
"__comment_spectrum_data__": "2-char hex bytes so data len=2*Length",
|
||||
"Data": "00AAFF75BD2AAA...",
|
||||
|
@ -38,6 +40,30 @@
|
|||
"LowFreq": 14000000,
|
||||
"HighFreq": 14250000
|
||||
},
|
||||
{
|
||||
"Name": "Sub",
|
||||
"Length": 475,
|
||||
"__comment_spectrum_data__": "2-char hex bytes so data len=2*Length",
|
||||
"Data": "00AAFF75BD2AAA...",
|
||||
"Type": "FIXED|CENTER",
|
||||
"MinLevel": 0,
|
||||
"MaxLevel": 140,
|
||||
"MinStrength": -100,
|
||||
"MaxStrength": 0,
|
||||
|
||||
"__comment_spectrum_center__": "If Type=CENTER, the following fields will be present:",
|
||||
"CenterFreq": 14267000,
|
||||
"Span": 25000,
|
||||
|
||||
"__comment_spectrum_fixed__": "If SpectrumType=FIXED, the following fields will be present:",
|
||||
"LowFreq": 14000000,
|
||||
"HighFreq": 14250000
|
||||
}],
|
||||
"LastCommand": {
|
||||
"ID": "MyApp 123",
|
||||
"Command": "set_freq VFOA 14074000",
|
||||
"Status": "OK"
|
||||
},
|
||||
|
||||
"Split": true,
|
||||
"SatMode": false,
|
||||
|
|
|
@ -106,6 +106,14 @@
|
|||
|
||||
__BEGIN_DECLS
|
||||
|
||||
/**
|
||||
* \brief size of cookie request buffer
|
||||
* Minimum size of cookie buffer to pass to rig_cookie
|
||||
*/
|
||||
// cookie is 26-char time code plus 10-char (2^31-1) random number
|
||||
#define HAMLIB_COOKIE_SIZE 37
|
||||
extern int cookie_use; // this is global as once one client requests it everybody needs to honor it
|
||||
|
||||
//! @cond Doxygen_Suppress
|
||||
extern HAMLIB_EXPORT_VAR(const char) hamlib_version[];
|
||||
extern HAMLIB_EXPORT_VAR(const char) hamlib_copyright[];
|
||||
|
@ -995,6 +1003,16 @@ enum cookie_e {
|
|||
RIG_COOKIE_RENEW,
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Multicast data items
|
||||
* 3 different data item can be included in the multicast JSON
|
||||
*/
|
||||
enum multicast_item_e {
|
||||
RIG_MULTICAST_POLL, // hamlib will be polling the rig for all rig items
|
||||
RIG_MULTICAST_TRANSCEIVE, // transceive will be turned on and processed
|
||||
RIG_MULTICAST_SPECTRUM // spectrum data will be included
|
||||
};
|
||||
|
||||
//! @cond Doxygen_Suppress
|
||||
#define RIG_PARM_FLOAT_LIST (RIG_PARM_BACKLIGHT|RIG_PARM_BAT|RIG_PARM_KEYLIGHT)
|
||||
#define RIG_PARM_READONLY_LIST (RIG_PARM_BAT)
|
||||
|
@ -3133,7 +3151,7 @@ extern HAMLIB_EXPORT(int) rig_get_cache(RIG *rig, vfo_t vfo, freq_t *freq, int *
|
|||
typedef unsigned long rig_useconds_t;
|
||||
extern HAMLIB_EXPORT(int) hl_usleep(rig_useconds_t msec);
|
||||
|
||||
extern HAMLIB_EXPORT(char *) rig_cookie(char *cookie, enum cookie_e cookie_cmd);
|
||||
extern HAMLIB_EXPORT(int) rig_cookie(RIG *rig, enum cookie_e cookie_cmd, char *cookie, int cookie_len);
|
||||
|
||||
//! @endcond
|
||||
|
||||
|
|
16
src/debug.c
16
src/debug.c
|
@ -186,22 +186,6 @@ void HAMLIB_API rig_set_debug_time_stamp(int flag)
|
|||
rig_debug_time_stamp = flag;
|
||||
}
|
||||
|
||||
|
||||
//! @cond Doxygen_Suppress
|
||||
char *date_strget(char *buf, int buflen)
|
||||
{
|
||||
char tmp[16];
|
||||
struct tm *mytm;
|
||||
time_t t;
|
||||
struct timeval tv;
|
||||
t = time(NULL);
|
||||
mytm = gmtime(&t);
|
||||
strftime(buf, buflen, "%Y-%m-%d:%H:%M:%S.", mytm);
|
||||
gettimeofday(&tv, NULL);
|
||||
sprintf(tmp, "%06ld", (long)tv.tv_usec);
|
||||
strcat(buf, tmp);
|
||||
return buf;
|
||||
}
|
||||
//! @endcond
|
||||
|
||||
|
||||
|
|
16
src/misc.c
16
src/misc.c
|
@ -2332,6 +2332,22 @@ uint32_t CRC32_function(uint8_t *buf, uint32_t len)
|
|||
return crc ^ 0xFFFFFFFF;
|
||||
}
|
||||
|
||||
//! @cond Doxygen_Suppress
|
||||
char *date_strget(char *buf, int buflen)
|
||||
{
|
||||
char tmp[16];
|
||||
struct tm *mytm;
|
||||
time_t t;
|
||||
struct timeval tv;
|
||||
t = time(NULL);
|
||||
mytm = gmtime(&t);
|
||||
strftime(buf, buflen, "%Y-%m-%d:%H:%M:%S.", mytm);
|
||||
gettimeofday(&tv, NULL);
|
||||
sprintf(tmp, "%06ld", (long)tv.tv_usec);
|
||||
strcat(buf, tmp);
|
||||
return buf;
|
||||
}
|
||||
|
||||
|
||||
//! @endcond
|
||||
|
||||
|
|
|
@ -112,6 +112,8 @@ extern HAMLIB_EXPORT(int) parse_hoststr(char *host, char hoststr[256], char port
|
|||
|
||||
extern HAMLIB_EXPORT(uint32_t) CRC32_function(uint8_t *buf, uint32_t len);
|
||||
|
||||
extern char *date_strget(char *buf, int buflen);
|
||||
|
||||
#ifdef PRId64
|
||||
/** \brief printf(3) format to be used for long long (64bits) type */
|
||||
# define PRIll PRId64
|
||||
|
|
|
@ -44,6 +44,7 @@
|
|||
#include <sys/time.h>
|
||||
#include <sys/types.h>
|
||||
#include <signal.h>
|
||||
#include <pthread.h>
|
||||
|
||||
#ifdef HAVE_NETINET_IN_H
|
||||
# include <netinet/in.h>
|
||||
|
@ -396,6 +397,23 @@ int network_close(hamlib_port_t *rp)
|
|||
}
|
||||
//! @endcond
|
||||
|
||||
volatile int multicast_server_run = 1;
|
||||
pthread_t multicast_server_threadId;
|
||||
|
||||
//! @cond Doxygen_Suppress
|
||||
// our multicast server loop
|
||||
static void *multicast_server(void *arg)
|
||||
{
|
||||
rig_debug(RIG_DEBUG_TRACE, "%s(%d): Starting multicast server\n", __FILE__, __LINE__);
|
||||
do {
|
||||
rig_debug(RIG_DEBUG_TRACE, "%s(%d): Multicast server poll\n", __FILE__, __LINE__);
|
||||
hl_usleep(1000*1000);
|
||||
} while(multicast_server_run);
|
||||
rig_debug(RIG_DEBUG_TRACE, "%s(%d): Stopping multicast server\n", __FILE__, __LINE__);
|
||||
return NULL;
|
||||
}
|
||||
//! @endcond
|
||||
|
||||
/**
|
||||
* \brief Open multicast server using rig.state data
|
||||
*
|
||||
|
@ -406,7 +424,7 @@ int network_close(hamlib_port_t *rp)
|
|||
* \param default_port Default network socket port
|
||||
* \return RIG_OK or < 0 if error
|
||||
*/
|
||||
int network_multicast_server(RIG *rig, const char *multicast_addr, int default_port)
|
||||
int network_multicast_server(RIG *rig, const char *multicast_addr, int default_port, enum multicast_item_e items)
|
||||
{
|
||||
int status;
|
||||
|
||||
|
@ -417,6 +435,26 @@ int network_multicast_server(RIG *rig, const char *multicast_addr, int default_p
|
|||
|
||||
if (status != RIG_OK) { RETURNFUNC(status); }
|
||||
|
||||
if (items && RIG_MULTICAST_TRANSCEIVE)
|
||||
{
|
||||
rig_debug(RIG_DEBUG_VERBOSE, "%s(%d) MULTICAST_TRANSCEIVE enabled\n", __FILE__, __LINE__);
|
||||
}
|
||||
if (items && RIG_MULTICAST_SPECTRUM)
|
||||
{
|
||||
rig_debug(RIG_DEBUG_VERBOSE, "%s(%d) MULTICAST_SPECTRUM enabled\n", __FILE__, __LINE__);
|
||||
}
|
||||
else
|
||||
{
|
||||
rig_debug(RIG_DEBUG_ERR, "%s(%d) unknown MULTICAST item requested=0x%x\n", __FILE__, __LINE__, items);
|
||||
}
|
||||
|
||||
int err = pthread_create(&multicast_server_threadId, NULL, multicast_server, NULL);
|
||||
if (err)
|
||||
{
|
||||
rig_debug(RIG_DEBUG_ERR, "%s(%d) pthread_create error %s\n", __FILE__, __LINE__, strerror(errno));
|
||||
return -RIG_EINTERNAL;
|
||||
}
|
||||
|
||||
RETURNFUNC(RIG_OK);
|
||||
}
|
||||
|
||||
|
|
|
@ -29,7 +29,7 @@ __BEGIN_DECLS
|
|||
|
||||
/* Hamlib internal use, see rig.c */
|
||||
int network_open(hamlib_port_t *p, int default_port);
|
||||
int network_multicast_server(RIG *rig, const char *multicast_addr, int default_port);
|
||||
HAMLIB_EXPORT(int) network_multicast_server(RIG *rig, const char *multicast_addr, int default_port, enum multicast_item_e items);
|
||||
int network_close(hamlib_port_t *rp);
|
||||
void network_flush(hamlib_port_t *rp);
|
||||
|
||||
|
|
234
src/rig.c
234
src/rig.c
|
@ -60,6 +60,8 @@
|
|||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <pthread.h>
|
||||
|
||||
|
||||
#include <hamlib/rig.h>
|
||||
|
@ -88,6 +90,7 @@ const char *hamlib_license = "LGPL";
|
|||
//! @cond Doxygen_Suppress
|
||||
const char hamlib_version[21] = "Hamlib " PACKAGE_VERSION;
|
||||
const char *hamlib_version2 = "Hamlib " PACKAGE_VERSION " " HAMLIBDATETIME;
|
||||
HAMLIB_EXPORT_VAR (int) cookie_use;
|
||||
//! @endcond
|
||||
|
||||
struct rig_caps caps_test;
|
||||
|
@ -861,6 +864,10 @@ int HAMLIB_API rig_open(RIG *rig)
|
|||
case RIG_PTT_CM108:
|
||||
rs->pttport.fd = cm108_open(&rs->pttport);
|
||||
|
||||
strncpy(rs->rigport.pathname, DEFAULT_CM108_PORT, HAMLIB_FILPATHLEN);
|
||||
rs->rigport.parm.cm108.ptt_bitnum = DEFAULT_CM108_PTT_BITNUM;
|
||||
rs->pttport.parm.cm108.ptt_bitnum = DEFAULT_CM108_PTT_BITNUM;
|
||||
|
||||
if (rs->pttport.fd < 0)
|
||||
{
|
||||
rig_debug(RIG_DEBUG_ERR,
|
||||
|
@ -1091,6 +1098,19 @@ int HAMLIB_API rig_close(RIG *rig)
|
|||
|
||||
ENTERFUNC;
|
||||
|
||||
// terminate the multicast server
|
||||
extern int multicast_server_run;
|
||||
multicast_server_run = 0;
|
||||
extern pthread_t multicast_server_threadId;
|
||||
int err = pthread_join(multicast_server_threadId, NULL);
|
||||
|
||||
if (err)
|
||||
{
|
||||
rig_debug(RIG_DEBUG_ERR, "%s(%d): pthread_join error %s\n", __FILE__, __LINE__,
|
||||
strerror(errno));
|
||||
// just ignore it
|
||||
}
|
||||
|
||||
if (!rig || !rig->caps)
|
||||
{
|
||||
RETURNFUNC(-RIG_EINVAL);
|
||||
|
@ -1421,10 +1441,14 @@ static int set_cache_freq(RIG *rig, vfo_t vfo, freq_t freq)
|
|||
{
|
||||
int flag = HAMLIB_ELAPSED_SET;
|
||||
|
||||
ENTERFUNC;
|
||||
rig_debug(RIG_DEBUG_TRACE, "%s: vfo=%s, current_vfo=%s\n", __func__,
|
||||
if (rig_need_debug(RIG_DEBUG_CACHE))
|
||||
{
|
||||
ENTERFUNC;
|
||||
cache_show(rig, __func__, __LINE__);
|
||||
}
|
||||
|
||||
rig_debug(RIG_DEBUG_CACHE, "%s: vfo=%s, current_vfo=%s\n", __func__,
|
||||
rig_strvfo(vfo), rig_strvfo(rig->state.current_vfo));
|
||||
cache_show(rig, __func__, __LINE__);
|
||||
|
||||
if (vfo == RIG_VFO_CURR)
|
||||
{
|
||||
|
@ -1440,8 +1464,11 @@ static int set_cache_freq(RIG *rig, vfo_t vfo, freq_t freq)
|
|||
|
||||
if (vfo == RIG_VFO_SUB && rig->state.cache.satmode) { vfo = RIG_VFO_SUB_A; };
|
||||
|
||||
rig_debug(RIG_DEBUG_TRACE, "%s: set vfo=%s to freq=%.0f\n", __func__,
|
||||
rig_strvfo(vfo), freq);
|
||||
if (rig_need_debug(RIG_DEBUG_CACHE))
|
||||
{
|
||||
rig_debug(RIG_DEBUG_CACHE, "%s: set vfo=%s to freq=%.0f\n", __func__,
|
||||
rig_strvfo(vfo), freq);
|
||||
}
|
||||
|
||||
switch (vfo)
|
||||
{
|
||||
|
@ -1510,15 +1537,24 @@ static int set_cache_freq(RIG *rig, vfo_t vfo, freq_t freq)
|
|||
RETURNFUNC(-RIG_EINVAL);
|
||||
}
|
||||
|
||||
cache_show(rig, __func__, __LINE__);
|
||||
RETURNFUNC(RIG_OK);
|
||||
if (rig_need_debug(RIG_DEBUG_CACHE))
|
||||
{
|
||||
cache_show(rig, __func__, __LINE__);
|
||||
RETURNFUNC(RIG_OK);
|
||||
}
|
||||
|
||||
return RIG_OK;
|
||||
}
|
||||
|
||||
int rig_get_cache(RIG *rig, vfo_t vfo, freq_t *freq, int *cache_ms_freq,
|
||||
rmode_t *mode, int *cache_ms_mode, pbwidth_t *width, int *cache_ms_width)
|
||||
{
|
||||
ENTERFUNC;
|
||||
rig_debug(RIG_DEBUG_TRACE, "%s: vfo=%s, current_vfo=%s\n", __func__,
|
||||
if (rig_need_debug(RIG_DEBUG_CACHE))
|
||||
{
|
||||
ENTERFUNC;
|
||||
}
|
||||
|
||||
rig_debug(RIG_DEBUG_CACHE, "%s: vfo=%s, current_vfo=%s\n", __func__,
|
||||
rig_strvfo(vfo), rig_strvfo(rig->state.current_vfo));
|
||||
|
||||
if (vfo == RIG_VFO_CURR) { vfo = rig->state.current_vfo; }
|
||||
|
@ -1624,9 +1660,15 @@ int rig_get_cache(RIG *rig, vfo_t vfo, freq_t *freq, int *cache_ms_freq,
|
|||
RETURNFUNC(-RIG_EINVAL);
|
||||
}
|
||||
|
||||
rig_debug(RIG_DEBUG_TRACE, "%s: vfo=%s, freq=%.0f\n", __func__, rig_strvfo(vfo),
|
||||
rig_debug(RIG_DEBUG_CACHE, "%s: vfo=%s, freq=%.0f\n", __func__, rig_strvfo(vfo),
|
||||
(double)*freq);
|
||||
RETURNFUNC(RIG_OK);
|
||||
|
||||
if (rig_need_debug(RIG_DEBUG_CACHE))
|
||||
{
|
||||
RETURNFUNC(RIG_OK);
|
||||
}
|
||||
|
||||
return RIG_OK;
|
||||
}
|
||||
|
||||
// detect if somebody is twiddling the VFO
|
||||
|
@ -5189,7 +5231,7 @@ int HAMLIB_API rig_power2mW(RIG *rig,
|
|||
/*
|
||||
* freq is not on the tx range!
|
||||
*/
|
||||
RETURNFUNC(-RIG_ECONF); /* could be RIG_EINVAL ? */
|
||||
RETURNFUNC(-RIG_EINVAL);
|
||||
}
|
||||
|
||||
*mwpower = (unsigned int)(power * txrange->high_power);
|
||||
|
@ -5243,7 +5285,7 @@ int HAMLIB_API rig_mW2power(RIG *rig,
|
|||
/*
|
||||
* freq is not on the tx range!
|
||||
*/
|
||||
return (-RIG_ECONF); /* could be RIG_EINVAL ? */
|
||||
return (-RIG_EINVAL); /* could be RIG_EINVAL ? */
|
||||
}
|
||||
|
||||
if (txrange->high_power == 0)
|
||||
|
@ -6290,7 +6332,6 @@ int HAMLIB_API rig_get_rig_info(RIG *rig, char *response, int max_response_len)
|
|||
int ret;
|
||||
int rxa, txa, rxb, txb;
|
||||
response[0] = 0;
|
||||
char crcstr[16];
|
||||
|
||||
vfoA = vfo_fixup(rig, RIG_VFO_A);
|
||||
vfoB = vfo_fixup(rig, RIG_VFO_B);
|
||||
|
@ -6338,7 +6379,13 @@ int HAMLIB_API rig_get_rig_info(RIG *rig, char *response, int max_response_len)
|
|||
sprintf(p, "CRC=0x%08lx\n", crc);
|
||||
}
|
||||
|
||||
strcat(response, crcstr);
|
||||
if (strlen(response) >= max_response_len - 1)
|
||||
{
|
||||
rig_debug(RIG_DEBUG_ERR, "%s(%d): response len exceeded max %d chars\n",
|
||||
__FILE__, __LINE__, max_response_len);
|
||||
RETURNFUNC(RIG_EINTERNAL);
|
||||
}
|
||||
|
||||
RETURNFUNC(RIG_OK);
|
||||
}
|
||||
|
||||
|
@ -6473,82 +6520,119 @@ const char *HAMLIB_API rig_copyright()
|
|||
* RIG_COOKIE_GET must have cookie=NULL or NULL returned
|
||||
* RIG_COOKIE_RENEW must have cookie!=NULL or NULL returned
|
||||
* RIG_COOKIE_RELEASE must have cookie!=NULL or NULL returned;
|
||||
* Cookies should only be used when needed to keep commands sequenced correctly
|
||||
* For example, when setting both VFOA and VFOB frequency and mode
|
||||
* Example to wait for cookie, do rig commands, and release
|
||||
* while((cookie=rig_cookie(NULL, RIG_COOKIE_GET)) == NULL) hl_usleep(10*1000);
|
||||
* set_freq A;set mode A;set freq B;set modeB;
|
||||
* rig_cookie(cookie,RIG_COOKIE_RELEASE);
|
||||
*/
|
||||
char *rig_cookie(char *cookie, enum cookie_e cookie_cmd)
|
||||
int HAMLIB_API rig_cookie(RIG *rig, enum cookie_e cookie_cmd, char *cookie,
|
||||
int cookie_len)
|
||||
{
|
||||
static char cookie_save[32]; // only one client can have the cookie
|
||||
double time_curr, time_last_used = 0;
|
||||
// only 1 client can have the cookie so these can be static
|
||||
// this should also prevent problems with DLLs & shared libraies
|
||||
// the debug_msg is another non-thread-safe which this will help fix
|
||||
// 27 char cookie will last until the year 10000
|
||||
static char
|
||||
cookie_save[HAMLIB_COOKIE_SIZE]; // only one client can have the 26-char cookie
|
||||
static double time_last_used;
|
||||
double time_curr;
|
||||
struct timespec tp;
|
||||
|
||||
if (cookie_len < 27)
|
||||
{
|
||||
rig_debug(RIG_DEBUG_ERR, "%s(%d): cookie_len < 32 so returning NULL!!\n",
|
||||
__FILE__, __LINE__);
|
||||
return -RIG_EINTERNAL;
|
||||
}
|
||||
|
||||
switch (cookie_cmd)
|
||||
{
|
||||
case RIG_COOKIE_RELEASE:
|
||||
if (cookie == NULL) {
|
||||
rig_debug(RIG_DEBUG_VERBOSE, "%s(%d): coookie NULL so nothing to do\n", __FILE__, __LINE__);
|
||||
return NULL; // nothing to do
|
||||
}
|
||||
if (strcmp(cookie,cookie_save)==0)
|
||||
{
|
||||
cookie_save[0] = 0;
|
||||
return NULL;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (cookie == NULL && cookie_cmd == RIG_COOKIE_GET)
|
||||
{
|
||||
// asking for a cookie but somebody may already have it
|
||||
// if we already have a cookie and somebody asks see if we should expire the old one
|
||||
printf("%d cookie_cmd=%d\n", (int)strlen(cookie_save), cookie_cmd);
|
||||
case RIG_COOKIE_RELEASE:
|
||||
if (cookie == NULL)
|
||||
{
|
||||
rig_debug(RIG_DEBUG_VERBOSE, "%s(%d): coookie NULL so nothing to do\n",
|
||||
__FILE__, __LINE__);
|
||||
return -RIG_EINVAL; // nothing to do
|
||||
}
|
||||
|
||||
if (cookie_save[0] != 0
|
||||
&& strcmp(cookie, cookie_save) == 0) // matching cookie so we'll clear it
|
||||
{
|
||||
rig_debug(RIG_DEBUG_VERBOSE, "%s(%d): %s coookie released\n",
|
||||
__FILE__, __LINE__, cookie_save);
|
||||
memset(cookie_save, 0, sizeof(cookie_save));
|
||||
return RIG_OK;
|
||||
}
|
||||
else // not the right cookie!!
|
||||
{
|
||||
rig_debug(RIG_DEBUG_ERR,
|
||||
"%s(%d): %s can't release cookie as cookie %s is active\n", __FILE__, __LINE__,
|
||||
cookie, cookie_save);
|
||||
return -RIG_BUSBUSY;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case RIG_COOKIE_RENEW:
|
||||
rig_debug(RIG_DEBUG_VERBOSE, "%s(%d): %s comparing renew request to %s==%d\n",
|
||||
__FILE__, __LINE__, cookie, cookie_save, strcmp(cookie, cookie_save));
|
||||
|
||||
if (cookie_save[0] != 0
|
||||
&& strcmp(cookie, cookie_save) == 0) // matching cookie so we'll renew it
|
||||
{
|
||||
rig_debug(RIG_DEBUG_VERBOSE, "%s(%d) %s renew request granted\n", __FILE__,
|
||||
__LINE__, cookie);
|
||||
clock_gettime(CLOCK_REALTIME, &tp);
|
||||
time_last_used = tp.tv_sec + tp.tv_nsec / 1e9;
|
||||
return RIG_OK;
|
||||
}
|
||||
|
||||
rig_debug(RIG_DEBUG_ERR,
|
||||
"%s(%d): %s renew request refused %s is active\n",
|
||||
__FILE__, __LINE__, cookie, cookie_save);
|
||||
return -RIG_EINVAL; // wrong cookie
|
||||
|
||||
break;
|
||||
|
||||
case RIG_COOKIE_GET:
|
||||
// the way we expire cookies is if somebody else asks for one and the last renewal is > 1 second ago
|
||||
// a polite client will have released the cookie
|
||||
// we are just allow for a crashed client that fails to release:q
|
||||
clock_gettime(CLOCK_REALTIME, &tp);
|
||||
time_curr = tp.tv_sec + tp.tv_nsec / 1e9;
|
||||
rig_debug(RIG_DEBUG_ERR, "%s(%d): time_curr=%f\n", __FILE__, __LINE__,
|
||||
time_curr);
|
||||
|
||||
if (time_curr - time_last_used < 1)
|
||||
if (cookie_save[0] != 0 && (strcmp(cookie_save, cookie) == 0)
|
||||
&& (time_curr - time_last_used < 1)) // then we will deny the request
|
||||
{
|
||||
printf("Cookie in use\n");
|
||||
rig_debug(RIG_DEBUG_ERR, "%s(%d): cookie==NULL but not RIG_COOKIE_GET\n",
|
||||
__FILE__, __LINE__);
|
||||
return NULL;
|
||||
printf("Cookie %s in use\n", cookie_save);
|
||||
rig_debug(RIG_DEBUG_ERR, "%s(%d): %s cookie is in use\n", __FILE__, __LINE__,
|
||||
cookie_save);
|
||||
return -RIG_BUSBUSY;
|
||||
}
|
||||
|
||||
if (cookie_save[0] != 0)
|
||||
{
|
||||
rig_debug(RIG_DEBUG_ERR,
|
||||
"%s(%d): %s cookie has expired after %.3f seconds....overriding with new cookie\n",
|
||||
__FILE__, __LINE__, cookie_save, time_curr - time_last_used);
|
||||
}
|
||||
else if (strlen(cookie_save)!=0)
|
||||
{
|
||||
rig_debug(RIG_DEBUG_VERBOSE, "%s(%d): cookie expired so we will grant\n", __FILE__, __LINE__);
|
||||
cookie_save[0] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (strlen(cookie_save) == 0 && cookie_cmd == RIG_COOKIE_GET)
|
||||
{
|
||||
date_strget(cookie_save, sizeof(cookie_save));
|
||||
clock_gettime(CLOCK_REALTIME, &tp);
|
||||
time_curr = time_last_used = tp.tv_sec + tp.tv_nsec / 1e9;
|
||||
rig_debug(RIG_DEBUG_VERBOSE, "%s(%d): cookie %s granted, time_curr=%f\n",
|
||||
__FILE__, __LINE__, cookie_save, time_curr);
|
||||
return cookie_save;
|
||||
}
|
||||
else if (strlen(cookie_save) == 0) // NULL should only be for GET
|
||||
{
|
||||
rig_debug(RIG_DEBUG_ERR, "%s(%d): cookie==NULL but not RIG_COOKIE_GET\n",
|
||||
__FILE__, __LINE__);
|
||||
return NULL;
|
||||
}
|
||||
else if (cookie_cmd == RIG_COOKIE_RENEW)
|
||||
{
|
||||
rig_debug(RIG_DEBUG_VERBOSE, "%s(%d): cookie %s renewed time_curr=%g\n",
|
||||
__FILE__, __LINE__,
|
||||
cookie, time_curr);
|
||||
return cookie;
|
||||
}
|
||||
else if (cookie_cmd == RIG_COOKIE_RELEASE)
|
||||
{
|
||||
rig_debug(RIG_DEBUG_VERBOSE, "%s(%d): cookie %s released\n", __FILE__, __LINE__,
|
||||
cookie);
|
||||
cookie_save[0] = 0;
|
||||
// add on our random number to ensure uniqueness
|
||||
snprintf(cookie, cookie_len, "%s %d\n", cookie_save, rand());
|
||||
strcpy(cookie_save, cookie);
|
||||
time_last_used = time_curr;
|
||||
rig_debug(RIG_DEBUG_VERBOSE, "%s(%d): %s new cookie request granted\n",
|
||||
__FILE__, __LINE__, cookie_save);
|
||||
return RIG_OK;
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
rig_debug(RIG_DEBUG_ERR, "%s(%d): unknown condition!!\n'", __FILE__, __LINE__);
|
||||
return NULL;
|
||||
return -RIG_EPROTO;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -8,7 +8,7 @@ DISTCLEANFILES = rigctl.log rigctl.sum testbcd.log testbcd.sum
|
|||
|
||||
bin_PROGRAMS = rigctl rigctld rigmem rigsmtr rigswr rotctl rotctld rigctlcom ampctl ampctld
|
||||
|
||||
check_PROGRAMS = dumpmem testrig testrigopen testrigcaps testtrn testbcd testfreq listrigs testloc rig_bench testcache cachetest cachetest2
|
||||
check_PROGRAMS = dumpmem testrig testrigopen testrigcaps testtrn testbcd testfreq listrigs testloc rig_bench testcache cachetest cachetest2 testcookie
|
||||
|
||||
RIGCOMMONSRC = rigctl_parse.c rigctl_parse.h dumpcaps.c uthash.h
|
||||
ROTCOMMONSRC = rotctl_parse.c rotctl_parse.h dumpcaps_rot.c uthash.h
|
||||
|
@ -76,7 +76,7 @@ endif
|
|||
EXTRA_DIST = rigmatrix_head.html rig_split_lst.awk testctld.pl testrotctld.pl
|
||||
|
||||
# Support 'make check' target for simple tests
|
||||
check_SCRIPTS = testrig.sh testfreq.sh testbcd.sh testloc.sh testrigcaps.sh testcache.sh
|
||||
check_SCRIPTS = testrig.sh testfreq.sh testbcd.sh testloc.sh testrigcaps.sh testcache.sh testcookie.sh
|
||||
|
||||
TESTS = $(check_SCRIPTS)
|
||||
|
||||
|
@ -105,4 +105,8 @@ testcache.sh:
|
|||
echo './testcache 1' > testcache.sh
|
||||
chmod +x ./testcache.sh
|
||||
|
||||
CLEANFILES = testrig.sh testfreq.sh testbcd.sh testloc.sh testrigcaps.sh testcache.sh
|
||||
testcookie.sh:
|
||||
echo './testcookie 1' > testcookie.sh
|
||||
chmod +x ./testcookie.sh
|
||||
|
||||
CLEANFILES = testrig.sh testfreq.sh testbcd.sh testloc.sh testrigcaps.sh testcache.sh testcookie.sh
|
||||
|
|
|
@ -86,7 +86,7 @@ static void usage(void);
|
|||
* NB: do NOT use -W since it's reserved by POSIX.
|
||||
* TODO: add an option to read from a file
|
||||
*/
|
||||
#define SHORT_OPTIONS "+m:r:p:d:P:D:s:c:t:lC:LuonvhVZ"
|
||||
#define SHORT_OPTIONS "+m:r:p:d:P:D:s:c:t:lC:LuonvhVZ!"
|
||||
static struct option long_options[] =
|
||||
{
|
||||
{"model", 1, 0, 'm'},
|
||||
|
@ -113,6 +113,7 @@ static struct option long_options[] =
|
|||
{"verbose", 0, 0, 'v'},
|
||||
{"help", 0, 0, 'h'},
|
||||
{"version", 0, 0, 'V'},
|
||||
{"cookie", 0, 0, '!'},
|
||||
{0, 0, 0, 0}
|
||||
|
||||
};
|
||||
|
@ -172,6 +173,9 @@ int main(int argc, char *argv[])
|
|||
|
||||
switch (c)
|
||||
{
|
||||
case '!':
|
||||
cookie_use = 1;
|
||||
break;
|
||||
case 'h':
|
||||
usage();
|
||||
exit(0);
|
||||
|
@ -716,7 +720,8 @@ void usage(void)
|
|||
" -Y, --ignore_err ignore rig_open errors\n"
|
||||
" -Z, --debug-time-stamps enable time stamps for debug messages\n"
|
||||
" -h, --help display this help and exit\n"
|
||||
" -V, --version output version information and exit\n\n"
|
||||
" -V, --version output version information and exit\n"
|
||||
" -!, --cookie use cookie control\n\n"
|
||||
);
|
||||
|
||||
usage_rig(stdout);
|
||||
|
|
|
@ -671,7 +671,7 @@ int rigctl_parse(RIG *my_rig, FILE *fin, FILE *fout, char *argv[], int argc,
|
|||
RETURNFUNC(RIGCTL_PARSE_ERROR);
|
||||
}
|
||||
|
||||
if (cmd != 0xa)
|
||||
if (cmd != 0xa && cmd !=0xd)
|
||||
{
|
||||
rig_debug(RIG_DEBUG_TRACE, "%s: cmd=%c(%02x)\n", __func__,
|
||||
isprint(cmd) ? cmd : ' ', cmd);
|
||||
|
@ -1143,7 +1143,7 @@ int rigctl_parse(RIG *my_rig, FILE *fin, FILE *fout, char *argv[], int argc,
|
|||
* argument is given, it will be parsed out later.
|
||||
*/
|
||||
result = strtok(input_line, " ");
|
||||
|
||||
readline_repeat:
|
||||
/* parsed_input stores pointers into input_line where the token strings
|
||||
* start.
|
||||
*/
|
||||
|
@ -1737,6 +1737,9 @@ int rigctl_parse(RIG *my_rig, FILE *fin, FILE *fout, char *argv[], int argc,
|
|||
fflush(fout);
|
||||
|
||||
rig_debug(RIG_DEBUG_TRACE, "%s: retcode=%d\n", __func__, retcode);
|
||||
#ifdef HAVE_LIBREADLINE
|
||||
if (input_line != NULL && (result = strtok(NULL, " "))) goto readline_repeat;
|
||||
#endif
|
||||
|
||||
if (sync_cb) { sync_cb(0); } /* unlock if necessary */
|
||||
|
||||
|
|
|
@ -746,7 +746,8 @@ int main(int argc, char *argv[])
|
|||
|
||||
saved_result = result;
|
||||
|
||||
retcode = network_multicast_server(my_rig, multicast_addr, 4532);
|
||||
enum multicast_item_e items = RIG_MULTICAST_POLL|RIG_MULTICAST_TRANSCEIVE|RIG_MULTICAST_SPECTRUM;
|
||||
retcode = network_multicast_server(my_rig, multicast_addr, 4532, items);
|
||||
|
||||
if (retcode != RIG_OK)
|
||||
{
|
||||
|
|
|
@ -0,0 +1,87 @@
|
|||
#include <hamlib/rig.h>
|
||||
|
||||
// GET tests
|
||||
int test1()
|
||||
{
|
||||
int retcode;
|
||||
// Normal get
|
||||
char cookie[HAMLIB_COOKIE_SIZE];
|
||||
retcode = rig_cookie(NULL, RIG_COOKIE_GET, cookie, sizeof(cookie));
|
||||
|
||||
if (retcode == RIG_OK) { printf("Test#1a OK\n"); }
|
||||
else {printf("Test#1a Failed\n"); return 1;}
|
||||
|
||||
// Should be able to release and get it right back
|
||||
rig_cookie(NULL, RIG_COOKIE_RELEASE, cookie, sizeof(cookie));
|
||||
retcode = rig_cookie(NULL, RIG_COOKIE_GET, cookie, sizeof(cookie));
|
||||
|
||||
if (retcode == RIG_OK) { printf("Test#1b OK\n"); }
|
||||
else {printf("Test#1b Failed\n"); return 1;}
|
||||
|
||||
|
||||
// Doing a get when another cookie is active should fail
|
||||
char cookie2[HAMLIB_COOKIE_SIZE];
|
||||
cookie2[0] = 0;
|
||||
retcode = rig_cookie(NULL, RIG_COOKIE_GET, cookie2, sizeof(cookie2));
|
||||
|
||||
if (retcode == RIG_OK) { printf("Test#1c OK\n"); }
|
||||
else {printf("Test#1c Failed\n"); return 1;}
|
||||
|
||||
// after 1 second we should be able to get a coookie
|
||||
// this means the cookie holder did not renew within 1 second
|
||||
hl_usleep(1500 * 1000); // after 1 second we should be able to get a coookie
|
||||
|
||||
retcode = rig_cookie(NULL, RIG_COOKIE_GET, cookie2, sizeof(cookie2));
|
||||
|
||||
if (retcode == RIG_OK) { printf("Test#1d OK\n"); }
|
||||
else {printf("Test#1d Failed\n"); return 1;}
|
||||
|
||||
retcode = rig_cookie(NULL, RIG_COOKIE_RELEASE, cookie2, sizeof(cookie2));
|
||||
|
||||
if (retcode == RIG_OK) { printf("Test#1e OK\n"); }
|
||||
else {printf("Test#1e Failed\n"); return 1;}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// RENEW tests
|
||||
int test2()
|
||||
{
|
||||
int retcode;
|
||||
char cookie[HAMLIB_COOKIE_SIZE];
|
||||
retcode = rig_cookie(NULL, RIG_COOKIE_GET, cookie, sizeof(cookie));
|
||||
|
||||
if (retcode == RIG_OK) { printf("Test#2a OK %s\n", cookie); }
|
||||
else {printf("Test#2a Failed\n"); return 1;}
|
||||
|
||||
retcode = rig_cookie(NULL, RIG_COOKIE_RELEASE, cookie, sizeof(cookie));
|
||||
|
||||
if (retcode == RIG_OK) { printf("Test#2b OK\n"); }
|
||||
else {printf("Test#2b Failed\n"); return 1;}
|
||||
|
||||
// get another cookie should work
|
||||
char cookie2[HAMLIB_COOKIE_SIZE];
|
||||
retcode = rig_cookie(NULL, RIG_COOKIE_GET, cookie2, sizeof(cookie2));
|
||||
|
||||
if (retcode == RIG_OK) { printf("Test#2c OK %s\n", cookie2); }
|
||||
else {printf("Test#2c Failed\n"); return 1;}
|
||||
|
||||
// should not be able to renew 1st cookie
|
||||
retcode = rig_cookie(NULL, RIG_COOKIE_RENEW, cookie, sizeof(cookie));
|
||||
|
||||
if (retcode != RIG_OK) { printf("Test#2d OK\n"); }
|
||||
else {printf("Test#2d Failed cookie=%s\n", cookie); return 1;}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int main()
|
||||
{
|
||||
rig_set_debug(RIG_DEBUG_VERBOSE);
|
||||
|
||||
if (test1()) { return 1; }
|
||||
|
||||
if (test2()) { return 1; }
|
||||
|
||||
return 0;
|
||||
}
|
Ładowanie…
Reference in New Issue