Mike Black W9MDB 2023-05-08 17:15:26 -05:00
rodzic a4c10c3206
commit ca763d4ff1
2 zmienionych plików z 225 dodań i 218 usunięć

Wyświetl plik

@ -86,27 +86,21 @@ static int multicast_status_changed(RIG *rig)
return 0;
}
void json_add_string(char *msg, const char *key, const char *value)
void json_add_string(char *msg, const char *key, const char *value,
int addComma)
{
if (strlen(msg) != 0)
{
strcat(msg, ",\n");
}
strcat(msg, "\"");
strcat(msg, key);
strcat(msg, "\": ");
strcat(msg, "\"");
strcat(msg, value);
strcat(msg, "\"");
if (addComma) { strcat(msg, ",\n"); }
}
void json_add_int(char *msg, const char *key, const int number)
void json_add_int(char *msg, const char *key, const int number, int addComma)
{
if (strlen(msg) != 0)
{
strcat(msg, ",\n");
}
strcat(msg, "\"");
strcat(msg, key);
@ -114,6 +108,11 @@ void json_add_int(char *msg, const char *key, const int number)
char tmp[64];
sprintf(tmp, "%d", number);
strcat(msg, tmp);
if (addComma)
{
strcat(msg, ",\n");
}
}
void json_add_double(char *msg, const char *key, const double value)
@ -131,49 +130,52 @@ void json_add_double(char *msg, const char *key, const double value)
strcat(msg, tmp);
}
void json_add_boolean(char *msg, const char *key, const int value)
void json_add_boolean(char *msg, const char *key, const int value, int addComma)
{
if (strlen(msg) != 0)
{
strcat(msg, ",\n");
}
strcat(msg, "\"");
strcat(msg, key);
strcat(msg, "\": ");
char tmp[64];
sprintf(tmp, "%s", value == 0 ? "False" : "True");
sprintf(tmp, "%s", value == 0 ? "false" : "true");
strcat(msg, tmp);
if (addComma)
{
strcat(msg, ",\n");
}
}
void json_add_time(char *msg)
void json_add_time(char *msg, int addComma)
{
char mydate[256];
date_strget(mydate, sizeof(mydate), 0);
if (strlen(msg) != 0)
strcat(msg, "\"Time\": \"");
strcat(msg, mydate);
strcat(msg, "\"");
if (addComma)
{
strcat(msg, ",\n");
}
strcat(msg, "\"Time\": ");
strcat(msg, mydate);
}
void json_add_vfoA(RIG *rig, char *msg)
{
strcat(msg, "{\n");
json_add_string(msg, "Name", "VFOA");
json_add_int(msg, "Freq", rig->state.cache.freqMainA);
json_add_string(msg, "Name", "VFOA", 1);
json_add_int(msg, "Freq", rig->state.cache.freqMainA, 1);
if (strlen(rig_strrmode(rig->state.cache.modeMainA)) > 0)
{
json_add_string(msg, "Mode", rig_strrmode(rig->state.cache.modeMainA));
json_add_string(msg, "Mode", rig_strrmode(rig->state.cache.modeMainA), 1);
}
if (rig->state.cache.widthMainA > 0)
{
json_add_int(msg, "Width", rig->state.cache.widthMainA);
json_add_int(msg, "Width", rig->state.cache.widthMainA, 1);
}
// what about full duplex? rx_vfo would be in rx all the time?
@ -181,70 +183,70 @@ void json_add_vfoA(RIG *rig, char *msg)
{
if (rig->state.tx_vfo && (RIG_VFO_B | RIG_VFO_MAIN_B))
{
json_add_boolean(msg, "RX", !rig->state.cache.ptt);
json_add_boolean(msg, "TX", 0);
json_add_boolean(msg, "RX", !rig->state.cache.ptt, 1);
json_add_boolean(msg, "TX", 0, 0);
}
else // we must be in reverse split
{
json_add_boolean(msg, "RX", 0);
json_add_boolean(msg, "TX", rig->state.cache.ptt);
json_add_boolean(msg, "RX", 0, 1);
json_add_boolean(msg, "TX", rig->state.cache.ptt, 0);
}
}
else if (rig->state.current_vfo && (RIG_VFO_A | RIG_VFO_MAIN_A))
{
json_add_boolean(msg, "RX", !rig->state.cache.ptt);
json_add_boolean(msg, "TX", rig->state.cache.ptt);
json_add_boolean(msg, "RX", !rig->state.cache.ptt, 1);
json_add_boolean(msg, "TX", rig->state.cache.ptt, 0);
}
else // VFOB must be active so never RX or TX
{
json_add_boolean(msg, "RX", 0);
json_add_boolean(msg, "TX", 0);
json_add_boolean(msg, "RX", 0, 1);
json_add_boolean(msg, "TX", 0, 0);
}
strcat(msg, "\n}\n");
strcat(msg, "\n}");
}
void json_add_vfoB(RIG *rig, char *msg)
{
strcat(msg, "{\n");
json_add_string(msg, "Name", "VFOB");
json_add_int(msg, "Freq", rig->state.cache.freqMainB);
strcat(msg, ",\n{\n");
json_add_string(msg, "Name", "VFOB", 1);
json_add_int(msg, "Freq", rig->state.cache.freqMainB, 1);
if (strlen(rig_strrmode(rig->state.cache.modeMainB)) > 0)
{
json_add_string(msg, "Mode", rig_strrmode(rig->state.cache.modeMainB));
json_add_string(msg, "Mode", rig_strrmode(rig->state.cache.modeMainB), 1);
}
if (rig->state.cache.widthMainB > 0)
{
json_add_int(msg, "Width", rig->state.cache.widthMainB);
json_add_int(msg, "Width", rig->state.cache.widthMainB, 1);
}
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))
{
json_add_boolean(msg, "RX", 0);
json_add_boolean(msg, "TX", rig->state.cache.ptt);
json_add_boolean(msg, "RX", 0, 1);
json_add_boolean(msg, "TX", rig->state.cache.ptt, 0);
}
else // we must be in reverse split
{
json_add_boolean(msg, "RX", rig->state.cache.ptt);
json_add_boolean(msg, "TX", 0);
json_add_boolean(msg, "RX", rig->state.cache.ptt, 1);
json_add_boolean(msg, "TX", 0, 0);
}
}
else if (rig->state.current_vfo && (RIG_VFO_A | RIG_VFO_MAIN_A))
{
json_add_boolean(msg, "RX", !rig->state.cache.ptt);
json_add_boolean(msg, "TX", rig->state.cache.ptt);
json_add_boolean(msg, "RX", !rig->state.cache.ptt, 1);
json_add_boolean(msg, "TX", rig->state.cache.ptt, 0);
}
else // VFOB must be active so always RX or TX
{
json_add_boolean(msg, "RX", 1);
json_add_boolean(msg, "TX", 1);
json_add_boolean(msg, "RX", 1, 1);
json_add_boolean(msg, "TX", 1, 0);
}
strcat(msg, "\n},\n");
strcat(msg, "\n}\n]\n");
}
static int multicast_send_json(RIG *rig)
@ -255,13 +257,16 @@ static int multicast_send_json(RIG *rig)
msg[0] = 0;
snprintf(buf, sizeof(buf), "%s:%s", rig->caps->model_name,
rig->state.rigport.pathname);
json_add_string(msg, "ID", buf);
json_add_time(msg);
json_add_int(msg, "Sequence", rig->state.multicast->seqnumber++);
json_add_string(msg, "VFOCurr", rig_strvfo(rig->state.current_vfo));
json_add_int(msg, "Split", rig->state.cache.split);
strcat(msg, ",\n\"VFOs\": [\n{\n");
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);
json_add_int(msg, "Split", rig->state.cache.split, 1);
strcat(msg, "\"VFOs\": [\n");
json_add_vfoA(rig, msg);
json_add_vfoB(rig, msg);
strcat(msg, "}\n");
// send the thing
multicast_send(rig, msg, strlen(msg));
@ -322,196 +327,198 @@ void *multicast_thread(void *vrig)
#ifdef WIN32
static char *GetWinsockLastError(char *errorBuffer, DWORD errorBufferSize)
{
void GetWinsockErrorString(char *errorBuffer, DWORD errorBufferSize) {
int errorCode = WSAGetLastError();
DWORD charsWritten;
void GetWinsockErrorString(char *errorBuffer, DWORD errorBufferSize)
{
int errorCode = WSAGetLastError();
DWORD charsWritten;
FormatMessage(
FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
NULL,
errorCode,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
errorBuffer,
errorBufferSize,
NULL
);
}
FormatMessage(
FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
NULL,
errorCode,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
errorBuffer,
errorBufferSize,
NULL
);
}
#endif
int multicast_init(RIG *rig, char *addr, int port)
{
#ifdef _WIN32
WSADATA wsaData;
if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)
int multicast_init(RIG * rig, char *addr, int port)
{
char errorMessage[1024];
fprintf(stderr, "WSAStartup failed: %s\n", GetWinsockLastError(errorMessage, sizeof(errorMessage)));
return 1;
}
#ifdef _WIN32
WSADATA wsaData;
if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)
{
char errorMessage[1024];
fprintf(stderr, "WSAStartup failed: %s\n", GetWinsockLastError(errorMessage,
sizeof(errorMessage)));
return 1;
}
#endif
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
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
//rig->state.multicast->mreq = {0};
//rig->state.multicast->mreq = {0};
if (addr == NULL) { addr = RIG_MULTICAST_ADDR; }
if (addr == NULL) { addr = RIG_MULTICAST_ADDR; }
if (port == 0) { port = RIG_MULTICAST_PORT; }
if (port == 0) { port = RIG_MULTICAST_PORT; }
// Create a UDP socket
rig->state.multicast->sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
// Create a UDP socket
rig->state.multicast->sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (rig->state.multicast->sock < 0)
{
if (rig->state.multicast->sock < 0)
{
#ifdef _WIN32
int err = WSAGetLastError();
rig_debug(RIG_DEBUG_ERR, "%s: socket: WSAGetLastError=%d\n", __func__, err);
int err = WSAGetLastError();
rig_debug(RIG_DEBUG_ERR, "%s: socket: WSAGetLastError=%d\n", __func__, err);
#else
rig_debug(RIG_DEBUG_ERR, "%s: socket: %s\n", __func__, strerror(errno));
rig_debug(RIG_DEBUG_ERR, "%s: socket: %s\n", __func__, strerror(errno));
#endif
return -RIG_EIO;
return -RIG_EIO;
}
// Set the SO_REUSEADDR option to allow multiple processes to use the same address
int optval = 1;
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;
}
// Bind the socket to any available local address and the specified port
struct sockaddr_in saddr = {0};
saddr.sin_family = AF_INET;
saddr.sin_addr.s_addr = htonl(INADDR_ANY);
saddr.sin_port = htons(port);
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;
}
// 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);
// Set the multicast TTL (time-to-live) to limit the scope of the packets
char ttl = 1;
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;
}
// 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));
return -RIG_EIO;
}
// prime the dest_addr for the send routine
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);
printf("starting thread\n");
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;
return RIG_OK;
}
// Set the SO_REUSEADDR option to allow multiple processes to use the same address
int optval = 1;
if (setsockopt(rig->state.multicast->sock, SOL_SOCKET, SO_REUSEADDR,
(char *)&optval,
sizeof(optval)) < 0)
void multicast_close(RIG * rig)
{
rig_debug(RIG_DEBUG_ERR, "%s: setsockopt: %s\n", __func__, strerror(errno));
return -RIG_EIO;
int retval;
// 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;
}
// Close the socket
if ((retval = close(rig->state.multicast->sock)))
{
rig_debug(RIG_DEBUG_ERR, "%s: close: %s\n", __func__, strerror(errno));
}
}
// Bind the socket to any available local address and the specified port
struct sockaddr_in saddr = {0};
saddr.sin_family = AF_INET;
saddr.sin_addr.s_addr = htonl(INADDR_ANY);
saddr.sin_port = htons(port);
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;
}
// 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);
// Set the multicast TTL (time-to-live) to limit the scope of the packets
char ttl = 1;
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;
}
// 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));
return -RIG_EIO;
}
// prime the dest_addr for the send routine
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);
printf("starting thread\n");
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;
return RIG_OK;
}
void multicast_close(RIG *rig)
{
int retval;
// 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;
}
// Close the socket
if ((retval = close(rig->state.multicast->sock)))
{
rig_debug(RIG_DEBUG_ERR, "%s: close: %s\n", __func__, strerror(errno));
}
}
// 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); }
// Send the message to the multicast group
ssize_t num_bytes = sendto(rig->state.multicast->sock, msg, msglen, 0,
(struct sockaddr *)&rig->state.multicast->dest_addr,
sizeof(rig->state.multicast->dest_addr));
if (num_bytes < 0)
{
rig_debug(RIG_DEBUG_ERR, "%s: sendto: %s\n", __func__, strerror(errno));
return -RIG_EIO;
}
else
int multicast_send(RIG * rig, const char *msg, int msglen)
{
// Construct the message to send
if (msglen == 0) { msglen = strlen((char *)msg); }
// Send the message to the multicast group
ssize_t num_bytes = sendto(rig->state.multicast->sock, msg, msglen, 0,
(struct sockaddr *)&rig->state.multicast->dest_addr,
sizeof(rig->state.multicast->dest_addr));
if (num_bytes < 0)
{
rig_debug(RIG_DEBUG_ERR, "%s: sendto: %s\n", __func__, strerror(errno));
return -RIG_EIO;
}
else
{
// printf("Sent %zd bytes to multicast group %s:%d\n", num_bytes, MULTICAST_ADDR,
// PORT);
}
}
return num_bytes;
}
return num_bytes;
}
//#define TEST
#ifdef TEST
int main(int argc, char *argv[])
{
RIG *rig;
rig_model_t myrig_model;
rig_set_debug_level(RIG_DEBUG_NONE);
if (argc > 1) { myrig_model = atoi(argv[1]); }
else
int main(int argc, char *argv[])
{
myrig_model = 1035;
RIG *rig;
rig_model_t myrig_model;
rig_set_debug_level(RIG_DEBUG_NONE);
if (argc > 1) { myrig_model = atoi(argv[1]); }
else
{
myrig_model = 1035;
}
rig = rig_init(myrig_model);
if (rig == NULL)
{
}
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;
}
rig = rig_init(myrig_model);
if (rig == NULL)
{
}
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;
}
#endif

Wyświetl plik

@ -90,7 +90,7 @@ int main()
}
buffer[bytes_received] = '\0';
printf("Received: %s\n", buffer);
printf("%s\n", buffer);
}
// Drop membership before closing the socket