2023-05-07 11:50:35 +00:00
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <errno.h>
|
|
|
|
#include <unistd.h>
|
2023-05-07 20:34:31 +00:00
|
|
|
#ifdef _WIN32
|
|
|
|
#include <winsock2.h>
|
|
|
|
#include <ws2tcpip.h>
|
|
|
|
#else
|
2023-05-07 11:50:35 +00:00
|
|
|
#include <sys/socket.h>
|
2023-05-07 20:34:31 +00:00
|
|
|
#include <netinet/in.h>
|
2023-05-07 11:50:35 +00:00
|
|
|
#include <arpa/inet.h>
|
2023-05-07 20:34:31 +00:00
|
|
|
#endif
|
2023-05-07 11:50:35 +00:00
|
|
|
#include "hamlib/rig.h"
|
|
|
|
#include "misc.h"
|
|
|
|
#include "multicast.h"
|
2023-09-16 04:22:10 +00:00
|
|
|
#include "network.h"
|
2023-05-07 11:50:35 +00:00
|
|
|
|
|
|
|
#define RIG_MULTICAST_ADDR "224.0.0.1"
|
|
|
|
#define RIG_MULTICAST_PORT 4532
|
|
|
|
|
|
|
|
#if 0
|
|
|
|
static int multicast_running;
|
|
|
|
static int sock;
|
|
|
|
static int seqnumber;
|
|
|
|
static int runflag = 0;
|
|
|
|
static struct ip_mreq mreq = {0};
|
|
|
|
static pthread_t threadid;
|
|
|
|
static struct sockaddr_in dest_addr = {0};
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
2023-09-14 13:55:21 +00:00
|
|
|
int multicast_stop(RIG *rig)
|
|
|
|
{
|
2023-09-16 04:22:10 +00:00
|
|
|
if (rig->state.multicast) { rig->state.multicast->runflag = 0; }
|
|
|
|
|
2023-09-14 13:55:21 +00:00
|
|
|
pthread_join(rig->state.multicast->threadid, NULL);
|
|
|
|
return RIG_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
#if 0
|
2023-05-07 11:50:35 +00:00
|
|
|
static int multicast_status_changed(RIG *rig)
|
|
|
|
{
|
|
|
|
int retval;
|
|
|
|
#if 0
|
|
|
|
freq_t freq, freqsave = rig->state.cache.freqMainA;
|
|
|
|
|
|
|
|
if ((retval = rig_get_freq(rig, RIG_VFO_A, &freq)) != RIG_OK)
|
|
|
|
{
|
|
|
|
rig_debug(RIG_DEBUG_ERR, "%s: rig_get_freq:%s\n", __func__, rigerror(retval));
|
|
|
|
}
|
|
|
|
|
|
|
|
if (freq != freqsave) { return 1; }
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
2023-05-08 17:16:51 +00:00
|
|
|
rmode_t modeA, modeAsave = rig->state.cache.modeMainA;
|
|
|
|
rmode_t modeB, modeBsave = rig->state.cache.modeMainB;
|
|
|
|
pbwidth_t widthA, widthAsave = rig->state.cache.widthMainA;
|
|
|
|
pbwidth_t widthB, widthBsave = rig->state.cache.widthMainB;
|
2023-05-07 11:50:35 +00:00
|
|
|
|
2023-09-14 13:55:21 +00:00
|
|
|
#if 0
|
2023-09-16 04:22:10 +00:00
|
|
|
|
2023-05-07 11:50:35 +00:00
|
|
|
if (rig->state.multicast->seqnumber % 2 == 0
|
2023-05-08 17:16:51 +00:00
|
|
|
&& (retval = rig_get_mode(rig, RIG_VFO_A, &modeA, &widthA)) != RIG_OK)
|
2023-05-07 11:50:35 +00:00
|
|
|
{
|
2023-05-08 17:16:51 +00:00
|
|
|
rig_debug(RIG_DEBUG_ERR, "%s: rig_get_modeA:%s\n", __func__, rigerror(retval));
|
|
|
|
}
|
2023-09-16 04:22:10 +00:00
|
|
|
|
2023-09-14 13:55:21 +00:00
|
|
|
#endif
|
2023-05-08 17:16:51 +00:00
|
|
|
|
|
|
|
if (modeA != modeAsave) { return 1; }
|
|
|
|
|
|
|
|
if (widthA != widthAsave) { return 1; }
|
|
|
|
|
2023-09-14 13:55:21 +00:00
|
|
|
#if 0
|
2023-09-16 04:22:10 +00:00
|
|
|
|
2023-05-08 17:16:51 +00:00
|
|
|
if (rig->state.multicast->seqnumber % 2 == 0
|
|
|
|
&& (rig->caps->targetable_vfo & RIG_TARGETABLE_MODE)
|
|
|
|
&& (retval = rig_get_mode(rig, RIG_VFO_B, &modeB, &widthB)) != RIG_OK)
|
|
|
|
{
|
|
|
|
rig_debug(RIG_DEBUG_ERR, "%s: rig_get_modeB:%s\n", __func__, rigerror(retval));
|
2023-05-07 11:50:35 +00:00
|
|
|
}
|
2023-09-16 04:22:10 +00:00
|
|
|
|
2023-09-14 13:55:21 +00:00
|
|
|
#endif
|
2023-05-07 11:50:35 +00:00
|
|
|
|
2023-05-08 17:16:51 +00:00
|
|
|
if (modeB != modeBsave) { return 1; }
|
2023-05-07 11:50:35 +00:00
|
|
|
|
2023-05-08 17:16:51 +00:00
|
|
|
if (widthB != widthBsave) { return 1; }
|
2023-05-07 11:50:35 +00:00
|
|
|
|
|
|
|
ptt_t ptt, pttsave = rig->state.cache.ptt;
|
|
|
|
|
2023-09-14 13:55:21 +00:00
|
|
|
#if 0
|
2023-09-16 04:22:10 +00:00
|
|
|
|
2023-05-07 11:50:35 +00:00
|
|
|
if (rig->state.multicast->seqnumber % 2 == 0
|
2023-05-08 17:16:51 +00:00
|
|
|
&& (retval = rig_get_ptt(rig, RIG_VFO_CURR, &ptt)) != RIG_OK)
|
2023-05-07 11:50:35 +00:00
|
|
|
if (ptt != pttsave) { return 1; }
|
|
|
|
|
|
|
|
split_t split, splitsave = rig->state.cache.split;
|
|
|
|
vfo_t txvfo;
|
|
|
|
|
|
|
|
if (rig->state.multicast->seqnumber % 2 == 0
|
2023-05-08 17:16:51 +00:00
|
|
|
&& (retval = rig_get_split_vfo(rig, RIG_VFO_CURR, &split, &txvfo)) != RIG_OK)
|
2023-05-07 11:50:35 +00:00
|
|
|
if (split != splitsave) { return 1; }
|
2023-09-16 04:22:10 +00:00
|
|
|
|
2023-09-14 13:55:21 +00:00
|
|
|
#endif
|
2023-05-07 11:50:35 +00:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
2023-09-14 13:55:21 +00:00
|
|
|
#endif
|
2023-05-07 11:50:35 +00:00
|
|
|
|
2023-05-08 22:15:26 +00:00
|
|
|
void json_add_string(char *msg, const char *key, const char *value,
|
|
|
|
int addComma)
|
2023-05-07 11:50:35 +00:00
|
|
|
{
|
|
|
|
strcat(msg, "\"");
|
|
|
|
strcat(msg, key);
|
|
|
|
strcat(msg, "\": ");
|
|
|
|
strcat(msg, "\"");
|
|
|
|
strcat(msg, value);
|
|
|
|
strcat(msg, "\"");
|
2023-05-08 22:15:26 +00:00
|
|
|
|
|
|
|
if (addComma) { strcat(msg, ",\n"); }
|
2023-05-07 11:50:35 +00:00
|
|
|
}
|
|
|
|
|
2023-05-08 22:15:26 +00:00
|
|
|
void json_add_int(char *msg, const char *key, const int number, int addComma)
|
2023-05-07 11:50:35 +00:00
|
|
|
{
|
|
|
|
|
|
|
|
strcat(msg, "\"");
|
|
|
|
strcat(msg, key);
|
|
|
|
strcat(msg, "\": ");
|
|
|
|
char tmp[64];
|
|
|
|
sprintf(tmp, "%d", number);
|
|
|
|
strcat(msg, tmp);
|
2023-05-08 22:15:26 +00:00
|
|
|
|
|
|
|
if (addComma)
|
|
|
|
{
|
|
|
|
strcat(msg, ",\n");
|
|
|
|
}
|
2023-05-07 11:50:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void json_add_double(char *msg, const char *key, const double value)
|
|
|
|
{
|
|
|
|
if (strlen(msg) != 0)
|
|
|
|
{
|
|
|
|
strcat(msg, ",\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
strcat(msg, "\"");
|
|
|
|
strcat(msg, key);
|
|
|
|
strcat(msg, "\": ");
|
|
|
|
char tmp[64];
|
|
|
|
sprintf(tmp, "%f", value);
|
|
|
|
strcat(msg, tmp);
|
|
|
|
}
|
|
|
|
|
2023-05-08 22:15:26 +00:00
|
|
|
void json_add_boolean(char *msg, const char *key, const int value, int addComma)
|
2023-05-07 11:50:35 +00:00
|
|
|
{
|
|
|
|
|
|
|
|
strcat(msg, "\"");
|
|
|
|
strcat(msg, key);
|
|
|
|
strcat(msg, "\": ");
|
|
|
|
char tmp[64];
|
2023-05-08 22:15:26 +00:00
|
|
|
sprintf(tmp, "%s", value == 0 ? "false" : "true");
|
2023-05-07 11:50:35 +00:00
|
|
|
strcat(msg, tmp);
|
2023-05-08 22:15:26 +00:00
|
|
|
|
|
|
|
if (addComma)
|
|
|
|
{
|
|
|
|
strcat(msg, ",\n");
|
|
|
|
}
|
2023-05-07 11:50:35 +00:00
|
|
|
}
|
|
|
|
|
2023-05-08 22:15:26 +00:00
|
|
|
void json_add_time(char *msg, int addComma)
|
2023-05-07 11:50:35 +00:00
|
|
|
{
|
|
|
|
char mydate[256];
|
|
|
|
date_strget(mydate, sizeof(mydate), 0);
|
|
|
|
|
2023-05-08 22:15:26 +00:00
|
|
|
|
|
|
|
strcat(msg, "\"Time\": \"");
|
|
|
|
strcat(msg, mydate);
|
|
|
|
strcat(msg, "\"");
|
|
|
|
|
|
|
|
if (addComma)
|
2023-05-07 11:50:35 +00:00
|
|
|
{
|
|
|
|
strcat(msg, ",\n");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void json_add_vfoA(RIG *rig, char *msg)
|
|
|
|
{
|
|
|
|
strcat(msg, "{\n");
|
2023-05-08 22:15:26 +00:00
|
|
|
json_add_string(msg, "Name", "VFOA", 1);
|
|
|
|
json_add_int(msg, "Freq", rig->state.cache.freqMainA, 1);
|
2023-05-07 11:50:35 +00:00
|
|
|
|
|
|
|
if (strlen(rig_strrmode(rig->state.cache.modeMainA)) > 0)
|
|
|
|
{
|
2023-05-08 22:15:26 +00:00
|
|
|
json_add_string(msg, "Mode", rig_strrmode(rig->state.cache.modeMainA), 1);
|
2023-05-07 11:50:35 +00:00
|
|
|
}
|
2023-09-16 04:22:10 +00:00
|
|
|
else
|
2023-05-07 11:50:35 +00:00
|
|
|
{
|
2023-09-16 04:22:10 +00:00
|
|
|
json_add_string(msg, "Mode", "None", 1);
|
2023-05-07 11:50:35 +00:00
|
|
|
}
|
|
|
|
|
2023-09-16 04:22:10 +00:00
|
|
|
json_add_int(msg, "Width", rig->state.cache.widthMainA, 0);
|
|
|
|
|
2023-05-09 16:46:54 +00:00
|
|
|
#if 0 // not working quite yet
|
2023-05-08 17:16:51 +00:00
|
|
|
// what about full duplex? rx_vfo would be in rx all the time?
|
2023-09-16 04:22:10 +00:00
|
|
|
rig_debug(RIG_DEBUG_ERR, "%s: rx_vfo=%s, tx_vfo=%s, split=%d\n", __func__,
|
|
|
|
rig_strvfo(rig->state.rx_vfo), rig_strvfo(rig->state.tx_vfo),
|
|
|
|
rig->state.cache.split);
|
|
|
|
printf("%s: rx_vfo=%s, tx_vfo=%s, split=%d\n", __func__,
|
|
|
|
rig_strvfo(rig->state.rx_vfo), rig_strvfo(rig->state.tx_vfo),
|
|
|
|
rig->state.cache.split);
|
|
|
|
|
2023-05-09 14:23:46 +00:00
|
|
|
if (rig->state.cache.split)
|
2023-05-08 17:16:51 +00:00
|
|
|
{
|
|
|
|
if (rig->state.tx_vfo && (RIG_VFO_B | RIG_VFO_MAIN_B))
|
|
|
|
{
|
2023-05-08 22:15:26 +00:00
|
|
|
json_add_boolean(msg, "RX", !rig->state.cache.ptt, 1);
|
|
|
|
json_add_boolean(msg, "TX", 0, 0);
|
2023-05-08 17:16:51 +00:00
|
|
|
}
|
|
|
|
else // we must be in reverse split
|
|
|
|
{
|
2023-05-08 22:15:26 +00:00
|
|
|
json_add_boolean(msg, "RX", 0, 1);
|
|
|
|
json_add_boolean(msg, "TX", rig->state.cache.ptt, 0);
|
2023-05-08 17:16:51 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (rig->state.current_vfo && (RIG_VFO_A | RIG_VFO_MAIN_A))
|
|
|
|
{
|
2023-05-08 22:15:26 +00:00
|
|
|
json_add_boolean(msg, "RX", !rig->state.cache.ptt, 1);
|
|
|
|
json_add_boolean(msg, "TX", rig->state.cache.ptt, 0);
|
2023-05-08 17:16:51 +00:00
|
|
|
}
|
|
|
|
else // VFOB must be active so never RX or TX
|
|
|
|
{
|
2023-05-08 22:15:26 +00:00
|
|
|
json_add_boolean(msg, "RX", 0, 1);
|
|
|
|
json_add_boolean(msg, "TX", 0, 0);
|
2023-05-08 17:16:51 +00:00
|
|
|
}
|
|
|
|
|
2023-05-09 14:23:46 +00:00
|
|
|
#endif
|
2023-05-08 22:15:26 +00:00
|
|
|
strcat(msg, "\n}");
|
2023-05-07 11:50:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void json_add_vfoB(RIG *rig, char *msg)
|
|
|
|
{
|
2023-05-08 22:15:26 +00:00
|
|
|
strcat(msg, ",\n{\n");
|
|
|
|
json_add_string(msg, "Name", "VFOB", 1);
|
2023-07-08 03:12:55 +00:00
|
|
|
json_add_int(msg, "Freq", rig->state.cache.freqMainB, 1);
|
2023-05-07 11:50:35 +00:00
|
|
|
|
|
|
|
if (strlen(rig_strrmode(rig->state.cache.modeMainB)) > 0)
|
|
|
|
{
|
2023-05-08 22:15:26 +00:00
|
|
|
json_add_string(msg, "Mode", rig_strrmode(rig->state.cache.modeMainB), 1);
|
2023-05-07 11:50:35 +00:00
|
|
|
}
|
2023-09-16 04:22:10 +00:00
|
|
|
else
|
2023-05-07 11:50:35 +00:00
|
|
|
{
|
2023-09-16 04:22:10 +00:00
|
|
|
json_add_string(msg, "Mode", "None", 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
json_add_int(msg, "Width", rig->state.cache.widthMainB, 0);
|
2023-05-07 11:50:35 +00:00
|
|
|
|
2023-05-09 14:23:46 +00:00
|
|
|
#if 0 // not working yet
|
2023-09-16 04:22:10 +00:00
|
|
|
|
2023-05-08 17:16:51 +00:00
|
|
|
if (rig->state.rx_vfo != rig->state.tx_vfo && rig->state.cache.split)
|
|
|
|
{
|
|
|
|
if (rig->state.tx_vfo && (RIG_VFO_B | RIG_VFO_MAIN_B))
|
|
|
|
{
|
2023-05-08 22:15:26 +00:00
|
|
|
json_add_boolean(msg, "RX", 0, 1);
|
|
|
|
json_add_boolean(msg, "TX", rig->state.cache.ptt, 0);
|
2023-05-08 17:16:51 +00:00
|
|
|
}
|
|
|
|
else // we must be in reverse split
|
|
|
|
{
|
2023-05-08 22:15:26 +00:00
|
|
|
json_add_boolean(msg, "RX", rig->state.cache.ptt, 1);
|
|
|
|
json_add_boolean(msg, "TX", 0, 0);
|
2023-05-08 17:16:51 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (rig->state.current_vfo && (RIG_VFO_A | RIG_VFO_MAIN_A))
|
|
|
|
{
|
2023-05-08 22:15:26 +00:00
|
|
|
json_add_boolean(msg, "RX", !rig->state.cache.ptt, 1);
|
|
|
|
json_add_boolean(msg, "TX", rig->state.cache.ptt, 0);
|
2023-05-08 17:16:51 +00:00
|
|
|
}
|
|
|
|
else // VFOB must be active so always RX or TX
|
|
|
|
{
|
2023-05-08 22:15:26 +00:00
|
|
|
json_add_boolean(msg, "RX", 1, 1);
|
|
|
|
json_add_boolean(msg, "TX", 1, 0);
|
2023-05-08 17:16:51 +00:00
|
|
|
}
|
2023-09-16 04:22:10 +00:00
|
|
|
|
2023-05-09 14:23:46 +00:00
|
|
|
#endif
|
2023-05-08 17:16:51 +00:00
|
|
|
|
2023-05-08 22:15:26 +00:00
|
|
|
strcat(msg, "\n}\n]\n");
|
2023-05-07 11:50:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static int multicast_send_json(RIG *rig)
|
|
|
|
{
|
|
|
|
char msg[8192]; // could be pretty big
|
|
|
|
char buf[4096];
|
|
|
|
// sprintf(msg,"%s:f=%.1f", date_strget(msg, (int)sizeof(msg), 0), f);
|
|
|
|
msg[0] = 0;
|
|
|
|
snprintf(buf, sizeof(buf), "%s:%s", rig->caps->model_name,
|
|
|
|
rig->state.rigport.pathname);
|
2023-05-08 22:15:26 +00:00
|
|
|
strcat(msg, "{\n");
|
|
|
|
json_add_string(msg, "ID", buf, 1);
|
|
|
|
json_add_time(msg, 1);
|
|
|
|
json_add_int(msg, "Sequence", rig->state.multicast->seqnumber++, 1);
|
|
|
|
json_add_string(msg, "VFOCurr", rig_strvfo(rig->state.current_vfo), 1);
|
2023-05-09 14:15:41 +00:00
|
|
|
json_add_int(msg, "PTT", rig->state.cache.ptt, 1);
|
2023-05-08 22:15:26 +00:00
|
|
|
json_add_int(msg, "Split", rig->state.cache.split, 1);
|
|
|
|
strcat(msg, "\"VFOs\": [\n");
|
2023-05-07 11:50:35 +00:00
|
|
|
json_add_vfoA(rig, msg);
|
2023-05-08 22:15:26 +00:00
|
|
|
json_add_vfoB(rig, msg);
|
|
|
|
strcat(msg, "}\n");
|
2023-05-07 11:50:35 +00:00
|
|
|
|
|
|
|
// send the thing
|
2023-05-07 22:17:50 +00:00
|
|
|
multicast_send(rig, msg, strlen(msg));
|
2023-05-07 11:50:35 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2023-09-16 04:22:10 +00:00
|
|
|
void *multicast_thread_rx(void *vrig)
|
|
|
|
{
|
|
|
|
char buf[256];
|
|
|
|
int ret = 0;
|
|
|
|
RIG *rig = (RIG *)vrig;
|
|
|
|
hamlib_port_t port;
|
|
|
|
rig->state.rig_type = RIG_TYPE_TRANSCEIVER;
|
|
|
|
rig->state.ptt_type = RIG_PTT_RIG;
|
|
|
|
rig->state.port_type = RIG_PORT_UDP_NETWORK;
|
|
|
|
strcpy(port.pathname, "127.0.0.1:4532");
|
|
|
|
rig_debug(RIG_DEBUG_TRACE, "%s: started\n", __func__);
|
|
|
|
network_open(&port, 4532);
|
|
|
|
|
|
|
|
while (rig->state.multicast->runflag && ret >= 0)
|
|
|
|
{
|
|
|
|
ret = read_string(&rig->state.rigport, (unsigned char *) buf, sizeof(buf), "\n", 1,
|
|
|
|
0, 1);
|
|
|
|
|
|
|
|
rig_debug(RIG_DEBUG_VERBOSE, "%s: read %s\n", __func__, buf);
|
|
|
|
hl_usleep(10 * 1000);
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2023-09-14 14:44:50 +00:00
|
|
|
#define LOOPCOUNT 50
|
2023-05-07 11:50:35 +00:00
|
|
|
void *multicast_thread(void *vrig)
|
|
|
|
{
|
2023-09-13 22:25:26 +00:00
|
|
|
//int retval;
|
2023-05-07 11:50:35 +00:00
|
|
|
RIG *rig = (RIG *)vrig;
|
2023-09-16 04:22:10 +00:00
|
|
|
rig_debug(RIG_DEBUG_TRACE, "%s: started\n", __func__);
|
2023-05-07 11:50:35 +00:00
|
|
|
|
|
|
|
// do the 1st packet all the time
|
2023-09-14 13:55:21 +00:00
|
|
|
//multicast_status_changed(rig);
|
|
|
|
//multicast_send_json(rig);
|
2023-09-14 14:44:50 +00:00
|
|
|
int loopcount = LOOPCOUNT;
|
2023-05-07 11:50:35 +00:00
|
|
|
|
2023-07-08 03:12:55 +00:00
|
|
|
freq_t freqA, freqAsave = 0;
|
|
|
|
freq_t freqB, freqBsave = 0;
|
2023-09-13 22:25:26 +00:00
|
|
|
mode_t modeA, modeAsave = 0;
|
|
|
|
mode_t modeB, modeBsave = 0;
|
|
|
|
ptt_t ptt, pttsave = 0;
|
|
|
|
rig->state.multicast->runflag = 1;
|
|
|
|
|
2023-05-07 11:50:35 +00:00
|
|
|
while (rig->state.multicast->runflag)
|
|
|
|
{
|
2023-09-13 22:25:26 +00:00
|
|
|
#if 0
|
2023-09-16 04:22:10 +00:00
|
|
|
|
2023-05-08 17:16:51 +00:00
|
|
|
if ((retval = rig_get_freq(rig, RIG_VFO_A, &freqA)) != RIG_OK)
|
2023-05-07 11:50:35 +00:00
|
|
|
{
|
2023-05-08 17:16:51 +00:00
|
|
|
rig_debug(RIG_DEBUG_ERR, "%s: rig_get_freqA:%s\n", __func__, rigerror(retval));
|
2023-05-07 11:50:35 +00:00
|
|
|
}
|
|
|
|
|
2023-05-08 17:16:51 +00:00
|
|
|
if ((rig->caps->targetable_vfo & RIG_TARGETABLE_FREQ)
|
|
|
|
&& (retval = rig_get_freq(rig, RIG_VFO_B, &freqB)) != RIG_OK)
|
|
|
|
{
|
|
|
|
rig_debug(RIG_DEBUG_ERR, "%s: rig_get_freqB:%s\n", __func__, rigerror(retval));
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
freqB = rig->state.cache.freqMainB;
|
|
|
|
}
|
2023-09-16 04:22:10 +00:00
|
|
|
|
2023-09-13 22:25:26 +00:00
|
|
|
#else
|
|
|
|
freqA = rig->state.cache.freqMainA;
|
|
|
|
freqB = rig->state.cache.freqMainB;
|
|
|
|
modeA = rig->state.cache.modeMainA;
|
|
|
|
modeB = rig->state.cache.modeMainB;
|
|
|
|
ptt = rig->state.cache.ptt;
|
|
|
|
#endif
|
2023-05-08 17:16:51 +00:00
|
|
|
|
2023-09-16 04:22:10 +00:00
|
|
|
if (freqA != freqAsave
|
|
|
|
|| freqB != freqBsave
|
|
|
|
|| modeA != modeAsave
|
|
|
|
|| modeB != modeBsave
|
|
|
|
|| ptt != pttsave
|
|
|
|
|| loopcount-- <= 0)
|
2023-05-07 11:50:35 +00:00
|
|
|
{
|
2023-09-16 04:43:09 +00:00
|
|
|
#if 0
|
2023-09-13 22:25:26 +00:00
|
|
|
if (loopcount <= 0)
|
2023-09-16 04:22:10 +00:00
|
|
|
{
|
|
|
|
rig_debug(RIG_DEBUG_CACHE, "%s: sending multicast packet timeout\n", __func__);
|
|
|
|
}
|
|
|
|
else { rig_debug(RIG_DEBUG_ERR, "%s: sending multicast packet due to change\n", __func__); }
|
2023-09-16 04:43:09 +00:00
|
|
|
#endif
|
2023-09-16 04:22:10 +00:00
|
|
|
|
2023-09-13 22:25:26 +00:00
|
|
|
// multicast_status_changed(rig);
|
2023-05-07 11:50:35 +00:00
|
|
|
multicast_send_json(rig);
|
2023-05-08 17:16:51 +00:00
|
|
|
freqAsave = freqA;
|
|
|
|
freqBsave = freqB;
|
2023-09-13 22:25:26 +00:00
|
|
|
modeAsave = modeA;
|
|
|
|
modeBsave = modeB;
|
|
|
|
pttsave = ptt;
|
2023-09-14 14:44:50 +00:00
|
|
|
loopcount = LOOPCOUNT;
|
2023-05-07 11:50:35 +00:00
|
|
|
}
|
2023-07-08 03:12:55 +00:00
|
|
|
else
|
|
|
|
{
|
2023-09-13 22:25:26 +00:00
|
|
|
//rig_debug(RIG_DEBUG_VERBOSE, "%s: loop\n", __func__);
|
2023-09-16 04:22:10 +00:00
|
|
|
hl_usleep(10 * 1000);
|
2023-07-08 03:12:55 +00:00
|
|
|
}
|
|
|
|
|
2023-05-07 11:50:35 +00:00
|
|
|
|
|
|
|
}
|
2023-05-08 12:37:13 +00:00
|
|
|
|
2023-05-08 04:23:01 +00:00
|
|
|
#ifdef _WIN32
|
|
|
|
WSACleanup();
|
|
|
|
#endif
|
2023-05-08 12:37:13 +00:00
|
|
|
|
2023-05-07 11:50:35 +00:00
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2023-05-08 17:16:51 +00:00
|
|
|
#ifdef WIN32
|
|
|
|
static char *GetWinsockLastError(char *errorBuffer, DWORD errorBufferSize)
|
|
|
|
{
|
2023-05-09 12:00:03 +00:00
|
|
|
int errorCode = WSAGetLastError();
|
|
|
|
|
|
|
|
FormatMessage(
|
|
|
|
FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
|
|
|
|
NULL,
|
|
|
|
errorCode,
|
|
|
|
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
|
|
|
|
errorBuffer,
|
|
|
|
errorBufferSize,
|
|
|
|
NULL
|
|
|
|
);
|
|
|
|
return errorBuffer;
|
|
|
|
}
|
2023-05-08 17:16:51 +00:00
|
|
|
#endif
|
|
|
|
|
2023-05-09 12:00:03 +00:00
|
|
|
int multicast_init(RIG *rig, char *addr, int port)
|
|
|
|
{
|
2023-09-16 04:22:10 +00:00
|
|
|
if (rig->state.multicast && rig->state.multicast->multicast_running) { return RIG_OK; }
|
|
|
|
|
2023-05-08 04:23:01 +00:00
|
|
|
#ifdef _WIN32
|
2023-05-09 12:00:03 +00:00
|
|
|
WSADATA wsaData;
|
2023-05-08 04:23:01 +00:00
|
|
|
|
2023-05-09 12:00:03 +00:00
|
|
|
if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)
|
|
|
|
{
|
|
|
|
char errorMessage[1024];
|
|
|
|
fprintf(stderr, "WSAStartup failed: %s\n", GetWinsockLastError(errorMessage,
|
|
|
|
sizeof(errorMessage)));
|
|
|
|
return 1;
|
|
|
|
}
|
2023-05-08 04:23:01 +00:00
|
|
|
|
|
|
|
#endif
|
|
|
|
|
2023-05-09 12:00:03 +00:00
|
|
|
if (rig->state.multicast == NULL)
|
|
|
|
{
|
|
|
|
rig->state.multicast = calloc(1, sizeof(struct multicast_s));
|
|
|
|
}
|
|
|
|
else if (rig->state.multicast->multicast_running) { return RIG_OK; } // we only need one port
|
2023-05-07 11:50:35 +00:00
|
|
|
|
2023-05-09 12:00:03 +00:00
|
|
|
//rig->state.multicast->mreq = {0};
|
2023-05-07 14:45:27 +00:00
|
|
|
|
2023-05-09 12:00:03 +00:00
|
|
|
if (addr == NULL) { addr = RIG_MULTICAST_ADDR; }
|
2023-05-07 11:50:35 +00:00
|
|
|
|
2023-05-09 12:00:03 +00:00
|
|
|
if (port == 0) { port = RIG_MULTICAST_PORT; }
|
2023-05-07 11:50:35 +00:00
|
|
|
|
2023-05-09 12:00:03 +00:00
|
|
|
// Create a UDP socket
|
2023-07-08 03:12:55 +00:00
|
|
|
rig->state.multicast->sock = socket(AF_INET, SOCK_DGRAM, 0);
|
2023-05-07 11:50:35 +00:00
|
|
|
|
2023-05-09 12:00:03 +00:00
|
|
|
if (rig->state.multicast->sock < 0)
|
|
|
|
{
|
2023-05-08 04:23:01 +00:00
|
|
|
#ifdef _WIN32
|
2023-05-09 12:00:03 +00:00
|
|
|
int err = WSAGetLastError();
|
|
|
|
rig_debug(RIG_DEBUG_ERR, "%s: socket: WSAGetLastError=%d\n", __func__, err);
|
2023-05-08 04:23:01 +00:00
|
|
|
#else
|
2023-05-09 12:00:03 +00:00
|
|
|
rig_debug(RIG_DEBUG_ERR, "%s: socket: %s\n", __func__, strerror(errno));
|
2023-05-08 04:23:01 +00:00
|
|
|
#endif
|
2023-05-09 12:00:03 +00:00
|
|
|
return -RIG_EIO;
|
|
|
|
}
|
2023-05-07 11:50:35 +00:00
|
|
|
|
2023-07-08 03:12:55 +00:00
|
|
|
#if 0
|
2023-05-09 12:00:03 +00:00
|
|
|
// Set the SO_REUSEADDR option to allow multiple processes to use the same address
|
|
|
|
int optval = 1;
|
2023-05-07 11:50:35 +00:00
|
|
|
|
2023-05-09 12:00:03 +00:00
|
|
|
if (setsockopt(rig->state.multicast->sock, SOL_SOCKET, SO_REUSEADDR,
|
|
|
|
(char *)&optval,
|
|
|
|
sizeof(optval)) < 0)
|
|
|
|
{
|
|
|
|
rig_debug(RIG_DEBUG_ERR, "%s: setsockopt: %s\n", __func__, strerror(errno));
|
|
|
|
return -RIG_EIO;
|
|
|
|
}
|
2023-09-16 04:22:10 +00:00
|
|
|
|
2023-07-08 03:12:55 +00:00
|
|
|
#endif
|
2023-05-07 11:50:35 +00:00
|
|
|
|
2023-05-09 12:00:03 +00:00
|
|
|
// Bind the socket to any available local address and the specified port
|
2023-07-08 03:12:55 +00:00
|
|
|
//struct sockaddr_in saddr = {0};
|
|
|
|
//saddr.sin_family = AF_INET;
|
|
|
|
//saddr.sin_addr.s_addr = inet_addr(addr);
|
|
|
|
//saddr.sin_port = htons(port);
|
2023-05-07 11:50:35 +00:00
|
|
|
|
2023-07-08 03:12:55 +00:00
|
|
|
#if 0
|
2023-09-16 04:22:10 +00:00
|
|
|
|
2023-05-09 12:00:03 +00:00
|
|
|
if (bind(rig->state.multicast->sock, (struct sockaddr *)&saddr,
|
|
|
|
sizeof(saddr)) < 0)
|
|
|
|
{
|
|
|
|
rig_debug(RIG_DEBUG_ERR, "%s: bind: %s\n", __func__, strerror(errno));
|
|
|
|
return -RIG_EIO;
|
|
|
|
}
|
2023-09-16 04:22:10 +00:00
|
|
|
|
2023-07-08 03:12:55 +00:00
|
|
|
#endif
|
2023-05-07 11:50:35 +00:00
|
|
|
|
2023-05-09 12:00:03 +00:00
|
|
|
// Construct the multicast group address
|
|
|
|
// struct ip_mreq mreq = {0};
|
|
|
|
rig->state.multicast->mreq.imr_multiaddr.s_addr = inet_addr(addr);
|
|
|
|
rig->state.multicast->mreq.imr_interface.s_addr = htonl(INADDR_ANY);
|
2023-05-07 11:50:35 +00:00
|
|
|
|
2023-05-09 12:00:03 +00:00
|
|
|
// Set the multicast TTL (time-to-live) to limit the scope of the packets
|
|
|
|
char ttl = 1;
|
2023-05-07 11:50:35 +00:00
|
|
|
|
2023-05-09 12:00:03 +00:00
|
|
|
if (setsockopt(rig->state.multicast->sock, IPPROTO_IP, IP_MULTICAST_TTL, &ttl,
|
|
|
|
sizeof(ttl)) < 0)
|
|
|
|
{
|
|
|
|
rig_debug(RIG_DEBUG_ERR, "%s: setsockopt: %s\n", __func__, strerror(errno));
|
|
|
|
return -RIG_EIO;
|
|
|
|
}
|
2023-05-07 11:50:35 +00:00
|
|
|
|
2023-07-08 03:12:55 +00:00
|
|
|
#if 0
|
2023-09-16 04:22:10 +00:00
|
|
|
|
2023-07-08 03:12:55 +00:00
|
|
|
// look like we need to implement the client in a separate thread?
|
2023-05-09 12:00:03 +00:00
|
|
|
// Join the multicast group
|
|
|
|
if (setsockopt(rig->state.multicast->sock, IPPROTO_IP, IP_ADD_MEMBERSHIP,
|
|
|
|
(char *)&rig->state.multicast->mreq, sizeof(rig->state.multicast->mreq)) < 0)
|
|
|
|
{
|
|
|
|
rig_debug(RIG_DEBUG_ERR, "%s: setsockopt: %s\n", __func__, strerror(errno));
|
2023-07-08 03:12:55 +00:00
|
|
|
//return -RIG_EIO;
|
2023-05-09 12:00:03 +00:00
|
|
|
}
|
2023-09-16 04:22:10 +00:00
|
|
|
|
2023-07-08 03:12:55 +00:00
|
|
|
#endif
|
2023-05-07 11:50:35 +00:00
|
|
|
|
2023-05-09 12:00:03 +00:00
|
|
|
// prime the dest_addr for the send routine
|
2023-09-16 04:22:10 +00:00
|
|
|
memset(&rig->state.multicast->dest_addr, 0,
|
|
|
|
sizeof(rig->state.multicast->dest_addr));
|
2023-05-09 12:00:03 +00:00
|
|
|
rig->state.multicast->dest_addr.sin_family = AF_INET;
|
|
|
|
rig->state.multicast->dest_addr.sin_addr.s_addr = inet_addr(addr);
|
|
|
|
rig->state.multicast->dest_addr.sin_port = htons(port);
|
2023-05-07 11:50:35 +00:00
|
|
|
|
2023-09-13 22:25:26 +00:00
|
|
|
#if 1
|
2023-05-09 12:00:03 +00:00
|
|
|
rig->state.multicast->runflag = 1;
|
|
|
|
pthread_create(&rig->state.multicast->threadid, NULL, multicast_thread,
|
|
|
|
(void *)rig);
|
|
|
|
//printf("threadid=%ld\n", rig->state.multicast->threadid);
|
|
|
|
rig->state.multicast->multicast_running = 1;
|
2023-09-16 04:22:10 +00:00
|
|
|
pthread_create(&rig->state.multicast->threadid, NULL, multicast_thread_rx,
|
|
|
|
(void *)rig);
|
2023-07-08 03:12:55 +00:00
|
|
|
#endif
|
2023-05-09 12:00:03 +00:00
|
|
|
return RIG_OK;
|
|
|
|
}
|
2023-05-08 22:15:26 +00:00
|
|
|
|
2023-05-09 12:00:03 +00:00
|
|
|
void multicast_close(RIG *rig)
|
|
|
|
{
|
|
|
|
int retval;
|
2023-05-08 22:15:26 +00:00
|
|
|
|
2023-05-09 12:00:03 +00:00
|
|
|
// Leave the multicast group
|
|
|
|
if ((retval = setsockopt(rig->state.multicast->sock, IPPROTO_IP,
|
|
|
|
IP_DROP_MEMBERSHIP, (char *)&rig->state.multicast->mreq,
|
|
|
|
sizeof(rig->state.multicast->mreq))) < 0)
|
|
|
|
{
|
|
|
|
rig_debug(RIG_DEBUG_ERR, "%s: setsockopt: %s\n", __func__, strerror(errno));
|
|
|
|
return;
|
2023-05-07 11:50:35 +00:00
|
|
|
}
|
|
|
|
|
2023-05-09 12:00:03 +00:00
|
|
|
// Close the socket
|
|
|
|
if ((retval = close(rig->state.multicast->sock)))
|
2023-05-08 22:15:26 +00:00
|
|
|
{
|
2023-05-09 12:00:03 +00:00
|
|
|
rig_debug(RIG_DEBUG_ERR, "%s: close: %s\n", __func__, strerror(errno));
|
|
|
|
}
|
|
|
|
}
|
2023-05-07 11:50:35 +00:00
|
|
|
|
2023-05-09 12:00:03 +00:00
|
|
|
// if msglen=0 msg is assumed to be a string
|
|
|
|
int multicast_send(RIG *rig, const char *msg, int msglen)
|
|
|
|
{
|
|
|
|
// Construct the message to send
|
|
|
|
if (msglen == 0) { msglen = strlen((char *)msg); }
|
2023-09-16 04:22:10 +00:00
|
|
|
|
2023-07-08 03:12:55 +00:00
|
|
|
struct sockaddr_in addr;
|
2023-09-16 04:22:10 +00:00
|
|
|
|
2023-07-08 03:12:55 +00:00
|
|
|
memset(&addr, 0, sizeof(addr));
|
2023-09-16 04:22:10 +00:00
|
|
|
|
2023-07-08 03:12:55 +00:00
|
|
|
addr.sin_family = AF_INET;
|
2023-09-16 04:22:10 +00:00
|
|
|
|
2023-07-08 03:12:55 +00:00
|
|
|
addr.sin_addr.s_addr = inet_addr("224.0.0.1");
|
2023-09-16 04:22:10 +00:00
|
|
|
|
2023-07-08 03:12:55 +00:00
|
|
|
addr.sin_port = htons(4532);
|
|
|
|
|
2023-05-07 11:50:35 +00:00
|
|
|
|
2023-05-09 12:00:03 +00:00
|
|
|
// Send the message to the multicast group
|
|
|
|
ssize_t num_bytes = sendto(rig->state.multicast->sock, msg, msglen, 0,
|
2023-07-08 03:12:55 +00:00
|
|
|
(struct sockaddr *)&addr,
|
|
|
|
sizeof(addr));
|
2023-05-07 11:50:35 +00:00
|
|
|
|
2023-05-09 12:00:03 +00:00
|
|
|
if (num_bytes < 0)
|
|
|
|
{
|
|
|
|
rig_debug(RIG_DEBUG_ERR, "%s: sendto: %s\n", __func__, strerror(errno));
|
|
|
|
return -RIG_EIO;
|
2023-05-08 22:15:26 +00:00
|
|
|
}
|
2023-05-07 11:50:35 +00:00
|
|
|
|
2023-05-09 12:00:03 +00:00
|
|
|
return num_bytes;
|
|
|
|
}
|
|
|
|
|
2023-05-07 20:32:43 +00:00
|
|
|
//#define TEST
|
2023-05-07 11:50:35 +00:00
|
|
|
#ifdef TEST
|
2023-05-09 12:00:03 +00:00
|
|
|
int main(int argc, char *argv[])
|
|
|
|
{
|
|
|
|
RIG *rig;
|
|
|
|
rig_model_t myrig_model;
|
|
|
|
rig_set_debug_level(RIG_DEBUG_NONE);
|
2023-05-07 11:50:35 +00:00
|
|
|
|
2023-05-09 12:00:03 +00:00
|
|
|
if (argc > 1) { myrig_model = atoi(argv[1]); }
|
|
|
|
else
|
|
|
|
{
|
|
|
|
myrig_model = 1035;
|
|
|
|
}
|
2023-05-07 11:50:35 +00:00
|
|
|
|
2023-05-09 12:00:03 +00:00
|
|
|
rig = rig_init(myrig_model);
|
2023-05-07 11:50:35 +00:00
|
|
|
|
2023-05-09 12:00:03 +00:00
|
|
|
if (rig == NULL)
|
|
|
|
{
|
2023-05-08 22:15:26 +00:00
|
|
|
|
|
|
|
}
|
2023-05-09 12:00:03 +00:00
|
|
|
|
|
|
|
strncpy(rig->state.rigport.pathname, "/dev/ttyUSB0", HAMLIB_FILPATHLEN - 1);
|
|
|
|
rig->state.rigport.parm.serial.rate = 38400;
|
|
|
|
rig_open(rig);
|
|
|
|
multicast_init(rig, "224.0.0.1", 4532);
|
|
|
|
pthread_join(rig->state.multicast->threadid, NULL);
|
|
|
|
pthread_exit(NULL);
|
|
|
|
return 0;
|
|
|
|
}
|
2023-05-07 11:50:35 +00:00
|
|
|
#endif
|