diff --git a/src/rds95.c b/src/rds95.c index e484513..a43173d 100644 --- a/src/rds95.c +++ b/src/rds95.c @@ -10,6 +10,7 @@ #include "fs.h" #include "modulator.h" #include "udp_server.h" +#include "tcp_server.h" #include "lib.h" #define DEFAULT_CONFIG_PATH "/etc/rds95.conf" @@ -51,6 +52,7 @@ static inline void show_help(char *name) { typedef struct { uint16_t udp_port; + uint16_t tcp_port; char rds_device_name[48]; uint8_t num_streams : 3; uint8_t asciig : 1; @@ -62,6 +64,7 @@ static int config_handler(void* user, const char* section, const char* name, con #define MATCH(s, n) (strcmp(section, s) == 0 && strcmp(name, n) == 0) if (MATCH("rds95", "udp_port")) config->udp_port = (uint16_t)atoi(value); + else if (MATCH("rds95", "tcp_port")) config->tcp_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'; @@ -83,6 +86,7 @@ int main(int argc, char **argv) { char config_path[64] = DEFAULT_CONFIG_PATH; RDS95_Config config = { .udp_port = 0, + .tcp_port = 0, .rds_device_name = "\0", .num_streams = DEFAULT_STREAMS, .asciig = 0 @@ -130,7 +134,7 @@ int main(int argc, char **argv) { return res; } - if(_strnlen(config.rds_device_name, 48) == 0) { + if(_strnlen(config.rds_device_name, 48) == 0 && config.asciig == 0) { printf("Error: No output device\n"); return 1; } @@ -175,7 +179,7 @@ int main(int argc, char **argv) { RDSModulator rdsModulator = {0}; init_lua(&rdsModulator); - + RDSEncoder rdsEncoder = {0}; init_rds_modulator(&rdsModulator, &rdsEncoder, config.num_streams); init_rds_encoder(&rdsEncoder); @@ -193,6 +197,13 @@ int main(int argc, char **argv) { config.udp_port = 0; } + if(config.asciig == 1 && config.tcp_port > 0) { + if (init_tcp_server(config.tcp_port) < 0) { + fprintf(stderr, "Failed to initialize TCP server\n"); + goto exit; + } + } + if(config.asciig == 0) { int pulse_error; @@ -214,21 +225,30 @@ int main(int argc, char **argv) { free(rds_buffer); } else { RDSGroup group; - #ifdef _WIN32 - _setmode(_fileno(stderr), _O_BINARY); - #endif + char output_buffer[1024]; + setvbuf(stderr, NULL, _IONBF, 0); + while(!stop_rds) { + if (is_tcp_server_running()) accept_tcp_clients(); + char starts[4][4] = {"G:\r\n", "H:\r\n", "I:\r\n", "J:\r\n"}; for(uint8_t i = 0; i < config.num_streams; i++) { get_rds_group(&rdsEncoder, &group, i); - fwrite(starts[i], 1, 4, stderr); - for(uint8_t j = 0; j < GROUP_LENGTH; j++) { - fprintf(stderr, "%04X", get_block_from_group(&group, j)); - } - fprintf(stderr, "\r\n\r\n"); + + int offset = 0; + offset += snprintf(output_buffer + offset, sizeof(output_buffer) - offset, "%s", starts[i]); + + for(uint8_t j = 0; j < GROUP_LENGTH; j++) offset += snprintf(output_buffer + offset, sizeof(output_buffer) - offset, "%04X", get_block_from_group(&group, j)); + offset += snprintf(output_buffer + offset, sizeof(output_buffer) - offset, "\r\n\r\n"); + + fwrite(output_buffer, 1, offset, stderr); fflush(stderr); + + if (is_tcp_server_running()) send_to_tcp_clients(output_buffer, offset); } + + msleep(10); } } @@ -238,6 +258,8 @@ exit: pthread_join(udp_server_thread, NULL); } + if (is_tcp_server_running()) close_tcp_server(); + encoder_saveToFile(&rdsEncoder); Modulator_saveToFile(&rdsModulator.params); printf("Saved to file\n"); @@ -247,4 +269,4 @@ exit: if (rds_device != NULL && config.asciig == 0) pa_simple_free(rds_device); return 0; -} +} \ No newline at end of file diff --git a/src/tcp_server.c b/src/tcp_server.c new file mode 100644 index 0000000..05e97f6 --- /dev/null +++ b/src/tcp_server.c @@ -0,0 +1,170 @@ +#include "tcp_server.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define MAX_TCP_CLIENTS 10 + +typedef struct { + int socket; + struct sockaddr_in address; + uint8_t active; +} TCPClient; + +typedef struct { + int server_socket; + uint16_t port; + TCPClient clients[MAX_TCP_CLIENTS]; + pthread_mutex_t clients_mutex; + uint8_t running; +} TCPServer; + +static TCPServer tcp_server = { + .server_socket = -1, + .port = 0, + .running = 0 +}; + +int init_tcp_server(uint16_t port) { + tcp_server.server_socket = socket(AF_INET, SOCK_STREAM, 0); + if (tcp_server.server_socket < 0) { + fprintf(stderr, "Error: Could not create TCP socket\n"); + return -1; + } + + int opt = 1; + if (setsockopt(tcp_server.server_socket, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) < 0) { + fprintf(stderr, "Error: Could not set socket options\n"); + close(tcp_server.server_socket); + return -1; + } + + int flags = fcntl(tcp_server.server_socket, F_GETFL, 0); + fcntl(tcp_server.server_socket, F_SETFL, flags | O_NONBLOCK); + + struct sockaddr_in server_addr = {0}; + server_addr.sin_family = AF_INET; + server_addr.sin_addr.s_addr = INADDR_ANY; + server_addr.sin_port = htons(port); + + if (bind(tcp_server.server_socket, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) { + fprintf(stderr, "Error: Could not bind TCP socket to port %d\n", port); + close(tcp_server.server_socket); + return -1; + } + + if (listen(tcp_server.server_socket, 5) < 0) { + fprintf(stderr, "Error: Could not listen on TCP socket\n"); + close(tcp_server.server_socket); + return -1; + } + + tcp_server.port = port; + tcp_server.running = 1; + pthread_mutex_init(&tcp_server.clients_mutex, NULL); + + for (int i = 0; i < MAX_TCP_CLIENTS; i++) { + tcp_server.clients[i].socket = -1; + tcp_server.clients[i].active = 0; + } + + printf("TCP server listening on port %d\n", port); + return 0; +} + +void accept_tcp_clients(void) { + if (!tcp_server.running) return; + + struct sockaddr_in client_addr; + socklen_t addr_len = sizeof(client_addr); + + int client_socket = accept(tcp_server.server_socket, (struct sockaddr *)&client_addr, &addr_len); + if (client_socket < 0) { + if (errno != EAGAIN && errno != EWOULDBLOCK) { + fprintf(stderr, "Error accepting client: %s\n", strerror(errno)); + } + return; + } + + int flags = fcntl(client_socket, F_GETFL, 0); + fcntl(client_socket, F_SETFL, flags | O_NONBLOCK); + + pthread_mutex_lock(&tcp_server.clients_mutex); + + int slot = -1; + for (int i = 0; i < MAX_TCP_CLIENTS; i++) { + if (!tcp_server.clients[i].active) { + slot = i; + break; + } + } + + if (slot >= 0) { + tcp_server.clients[slot].socket = client_socket; + tcp_server.clients[slot].address = client_addr; + tcp_server.clients[slot].active = 1; + printf("Client connected from %s (slot %d)\n", inet_ntoa(client_addr.sin_addr), slot); + } else { + fprintf(stderr, "Max clients reached, rejecting connection\n"); + close(client_socket); + } + + pthread_mutex_unlock(&tcp_server.clients_mutex); +} + +void send_to_tcp_clients(const char *data, size_t len) { + if (!tcp_server.running) return; + + pthread_mutex_lock(&tcp_server.clients_mutex); + + for (int i = 0; i < MAX_TCP_CLIENTS; i++) { + if (!tcp_server.clients[i].active) continue; + + ssize_t sent = send(tcp_server.clients[i].socket, data, len, MSG_NOSIGNAL); + if (sent < 0) { + if (errno != EAGAIN && errno != EWOULDBLOCK) { + printf("Client disconnected (slot %d)\n", i); + close(tcp_server.clients[i].socket); + tcp_server.clients[i].socket = -1; + tcp_server.clients[i].active = 0; + } + } + } + + pthread_mutex_unlock(&tcp_server.clients_mutex); +} + +int is_tcp_server_running(void) { + return tcp_server.running; +} + +void close_tcp_server(void) { + if (!tcp_server.running) return; + + tcp_server.running = 0; + + pthread_mutex_lock(&tcp_server.clients_mutex); + for (int i = 0; i < MAX_TCP_CLIENTS; i++) { + if (tcp_server.clients[i].active) { + close(tcp_server.clients[i].socket); + tcp_server.clients[i].socket = -1; + tcp_server.clients[i].active = 0; + } + } + pthread_mutex_unlock(&tcp_server.clients_mutex); + + if (tcp_server.server_socket >= 0) { + close(tcp_server.server_socket); + tcp_server.server_socket = -1; + } + + pthread_mutex_destroy(&tcp_server.clients_mutex); + printf("TCP server closed\n"); +} \ No newline at end of file diff --git a/src/tcp_server.h b/src/tcp_server.h new file mode 100644 index 0000000..78ff017 --- /dev/null +++ b/src/tcp_server.h @@ -0,0 +1,10 @@ +#pragma once + +#include +#include + +int init_tcp_server(uint16_t port); +void accept_tcp_clients(void); +void send_to_tcp_clients(const char *data, size_t len); +int is_tcp_server_running(void); +void close_tcp_server(void); \ No newline at end of file