diff --git a/src/multicast.c b/src/multicast.c index f322beb18..9b290ba34 100644 --- a/src/multicast.c +++ b/src/multicast.c @@ -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 diff --git a/tests/rigtestmcastrx.c b/tests/rigtestmcastrx.c index 200f45f3b..d767906f2 100644 --- a/tests/rigtestmcastrx.c +++ b/tests/rigtestmcastrx.c @@ -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