0
1
mirror of https://github.com/radio95-rnt/rds95.git synced 2026-02-26 20:33:53 +01:00

ascii g tcp server

This commit is contained in:
2026-01-03 16:29:53 +01:00
parent b4bdd36332
commit 5377125cf1
3 changed files with 213 additions and 11 deletions

View File

@@ -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;
}
}

170
src/tcp_server.c Normal file
View File

@@ -0,0 +1,170 @@
#include "tcp_server.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <fcntl.h>
#include <errno.h>
#include <pthread.h>
#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");
}

10
src/tcp_server.h Normal file
View File

@@ -0,0 +1,10 @@
#pragma once
#include <stdint.h>
#include <stddef.h>
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);