diff --git a/.vscode/.server-controller-port.log b/.vscode/.server-controller-port.log index 6487a5a..3104da3 100644 --- a/.vscode/.server-controller-port.log +++ b/.vscode/.server-controller-port.log @@ -1,5 +1,5 @@ { "port": 13452, - "time": 1751819046475, + "time": 1752334981843, "version": "0.0.3" } \ No newline at end of file diff --git a/inih b/inih index 57188e8..498f34b 160000 --- a/inih +++ b/inih @@ -1 +1 @@ -Subproject commit 57188e8acd8051b39a503faa30d27c50b94d8770 +Subproject commit 498f34b78610cf9e42197d22730c91f942431ea4 diff --git a/src/rds95.c b/src/rds95.c index 2df1454..1315621 100644 --- a/src/rds95.c +++ b/src/rds95.c @@ -9,6 +9,7 @@ #include "rds.h" #include "modulator.h" #include "control_pipe.h" +#include "udp_server.h" #include "lib.h" #include "ascii_cmd.h" @@ -37,6 +38,16 @@ static void *control_pipe_worker(void* modulator) { pthread_exit(NULL); } +static void *udp_server_worker() { + while (!stop_rds) { + poll_udp_server(); + msleep(READ_TIMEOUT_MS); + } + + close_udp_server(); + pthread_exit(NULL); +} + static inline void show_help(char *name) { printf( "\n" @@ -52,27 +63,32 @@ static inline void show_help(char *name) { typedef struct { char control_pipe[51]; + uint16_t udp_port; char rds_device_name[32]; uint8_t num_streams; } RDS95_Config; static int config_handler(void* user, const char* section, const char* name, const char* value) { - RDS95_Config* config = (RDS95_Config*)user; + RDS95_Config* config = (RDS95_Config*)user; - #define MATCH(s, n) strcmp(section, s) == 0 && strcmp(name, n) == 0 - if(MATCH("rds95", "control_pipe")) { - strncpy(config->control_pipe, value, 49); - config->control_pipe[50] = '\0'; - } else if(MATCH("devices", "rds95")) { - strncpy(config->rds_device_name, value, 30); - config->rds_device_name[31] = '\0'; - } else if(MATCH("rds95", "streams")) { - config->num_streams = atoi(value); - if(config->num_streams > MAX_STREAMS || config->num_streams == 0) return 1; - } else { - return 0; - } - return 1; + #define MATCH(s, n) (strcmp(section, s) == 0 && strcmp(name, n) == 0) + + if (MATCH("rds95", "control_pipe")) { + strncpy(config->control_pipe, value, sizeof(config->control_pipe) - 1); + config->control_pipe[sizeof(config->control_pipe) - 1] = '\0'; + } else if (MATCH("rds95", "udp_port")) { + config->udp_port = (uint16_t)atoi(value); + } else if (MATCH("devices", "rds95")) { + strncpy(config->rds_device_name, value, sizeof(config->rds_device_name) - 1); + config->rds_device_name[sizeof(config->rds_device_name) - 1] = '\0'; + } else if (MATCH("rds95", "streams")) { + int streams = atoi(value); + if (streams > MAX_STREAMS || streams == 0) return 0; + config->num_streams = (uint8_t)streams; + } else { + return 0; // Unknown config key + } + return 1; } int main(int argc, char **argv) { @@ -81,6 +97,7 @@ int main(int argc, char **argv) { char config_path[64] = DEFAULT_CONFIG_PATH; RDS95_Config config = { .control_pipe = "\0", + .udp_port = 0, .rds_device_name = RDS_DEVICE, .num_streams = DEFAULT_STREAMS }; @@ -91,6 +108,7 @@ int main(int argc, char **argv) { pthread_attr_t attr; pthread_t control_pipe_thread; + pthread_t udp_server_thread; const char *short_opt = "c:h"; @@ -174,6 +192,21 @@ int main(int argc, char **argv) { } } + if(config.udp_port) { + if(open_udp_server(config.udp_port, &rdsModulator) == 0) { + fprintf(stderr, "Reading control commands on UDP:%d.\n", config.udp_port); + int r = pthread_create(&udp_server_thread, &attr, udp_server_worker, NULL); + if (r < 0) { + fprintf(stderr, "Could not create UDP server thread.\n"); + config.udp_port = 0; + goto exit; + } else fprintf(stderr, "Created UDP server thread.\n"); + } else { + fprintf(stderr, "Failed to open UDP server\n"); + config.udp_port = 0; + } + } + int pulse_error; // Dynamically allocate buffer based on stream count @@ -202,6 +235,11 @@ exit: pthread_join(control_pipe_thread, NULL); } + if(config.udp_port) { + fprintf(stderr, "Waiting for UDP thread to shut down.\n"); + pthread_join(udp_server_thread, NULL); + } + cleanup_rds_modulator(&rdsModulator); // Clean up dynamically allocated memory pthread_attr_destroy(&attr); if (rds_device != NULL) pa_simple_free(rds_device); diff --git a/src/udp_server.c b/src/udp_server.c new file mode 100644 index 0000000..0e4931e --- /dev/null +++ b/src/udp_server.c @@ -0,0 +1,83 @@ +#include "udp_server.h" + +#define BUF_SIZE 512 +#define UDP_READ_TIMEOUT_MS 500 + +static int sockfd = -1; +static struct pollfd poller; +static struct sockaddr_in client_addr; +static socklen_t client_len = sizeof(client_addr); + +static RDSModulator* mod = NULL; // Store modulator pointer globally or pass it somehow + +int open_udp_server(int port, RDSModulator* rds_mod) { + sockfd = socket(AF_INET, SOCK_DGRAM, 0); + if (sockfd < 0) return -1; + + struct sockaddr_in server_addr; + memset(&server_addr, 0, sizeof(server_addr)); + + server_addr.sin_family = AF_INET; + server_addr.sin_addr.s_addr = INADDR_ANY; + server_addr.sin_port = htons(port); + + if (bind(sockfd, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) { + close(sockfd); + sockfd = -1; + return -1; + } + + poller.fd = sockfd; + poller.events = POLLIN; + + mod = rds_mod; // Save mod pointer + + return 0; +} + +void poll_udp_server() { + static char buf[BUF_SIZE]; + static char cmd_buf[BUF_SIZE]; + static char cmd_output[BUF_SIZE]; // Buffer to collect output from process_ascii_cmd + ssize_t bytes_read; + + if (poll(&poller, 1, UDP_READ_TIMEOUT_MS) <= 0) return; + if (!(poller.revents & POLLIN)) return; + + memset(buf, 0, BUF_SIZE); + client_len = sizeof(client_addr); + bytes_read = recvfrom(sockfd, buf, BUF_SIZE - 1, 0, + (struct sockaddr *)&client_addr, &client_len); + if (bytes_read <= 0) return; + + buf[bytes_read] = '\0'; + + char *token = strtok(buf, "\r\n"); + while (token != NULL) { + size_t len = strlen(token); + if (len > 0 && len < BUF_SIZE) { + memset(cmd_buf, 0, BUF_SIZE); + strncpy(cmd_buf, token, BUF_SIZE - 1); + + memset(cmd_output, 0, BUF_SIZE); + // Pass cmd_output buffer to collect output from the command processor + process_ascii_cmd(mod, cmd_buf, cmd_output); + + // Send cmd_output back to client (even if empty, send it) + size_t out_len = strlen(cmd_output); + if (out_len > 0) { + ssize_t sent = sendto(sockfd, cmd_output, out_len, 0, + (struct sockaddr *)&client_addr, client_len); + if (sent == -1) { + perror("sendto"); + } + } + } + token = strtok(NULL, "\r\n"); + } +} + +void close_udp_server() { + if (sockfd >= 0) close(sockfd); + sockfd = -1; +} diff --git a/src/udp_server.h b/src/udp_server.h new file mode 100644 index 0000000..999752c --- /dev/null +++ b/src/udp_server.h @@ -0,0 +1,19 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "modulator.h" +#include "ascii_cmd.h" + +int open_udp_server(int port, RDSModulator *rds_mod); + +void poll_udp_server(); + +void close_udp_server();