diff --git a/Makefile b/Makefile index ea0c019..4f31fe5 100644 --- a/Makefile +++ b/Makefile @@ -1,12 +1,16 @@ -.PHONY: all modem/freedv datalink audioio common clean +.PHONY: all modem datalink_arq datalink_broadcast audioio common clean -all: modem/freedv datalink audioio common +all: datalink_arq -modem/freedv: - $(MAKE) -C modem/freedv +modem: + $(MAKE) -C modem -datalink: modem/freedv common audioio - $(MAKE) -C datalink +# main is temporarily here, will be moved to a separate directory later +datalink_arq: modem common audioio datalink_broadcast + $(MAKE) -C datalink_arq + +datalink_broadcast: modem common audioio + $(MAKE) -C datalink_broadcast audioio: $(MAKE) -C audioio @@ -15,7 +19,8 @@ common: $(MAKE) -C common clean: - $(MAKE) -C modem/freedv clean - $(MAKE) -C datalink clean + $(MAKE) -C modem clean + $(MAKE) -C datalink_arq clean + $(MAKE) -C datalink_broadcast clean $(MAKE) -C audioio clean $(MAKE) -C common clean diff --git a/audioio/audioio.c b/audioio/audioio.c index 3f7584e..35a2463 100644 --- a/audioio/audioio.c +++ b/audioio/audioio.c @@ -19,7 +19,7 @@ #include "ring_buffer_posix.h" #include "shm_posix.h" -#include "../datalink/defines.h" +#include "../common/defines_modem.h" #include "os_interop.h" #include "audioio.h" diff --git a/datalink/defines.h b/common/defines_modem.h similarity index 85% rename from datalink/defines.h rename to common/defines_modem.h index 69df50d..7005e67 100644 --- a/datalink/defines.h +++ b/common/defines_modem.h @@ -1,6 +1,6 @@ -#ifndef HAVE_DEFINES_H -#define HAVE_DEFINES_H +#ifndef HAVE_DEFINES_MODEM_H +#define HAVE_DEFINES_MODEM_H #define MAX_PATH 255 @@ -26,4 +26,4 @@ #endif -#endif // HAVE_DEFINES_H +#endif // HAVE_DEFINES_MODEM_H diff --git a/datalink/Makefile b/datalink_arq/Makefile similarity index 83% rename from datalink/Makefile rename to datalink_arq/Makefile index 666f8f7..b9f3848 100644 --- a/datalink/Makefile +++ b/datalink_arq/Makefile @@ -40,16 +40,16 @@ endif CC = gcc -CFLAGS = -Wall -O2 -std=gnu11 -pthread -D_GNU_SOURCE -I../modem/freedv -I.. -I../audioio/ffaudio -I../common +CFLAGS = -Wall -O2 -std=gnu11 -pthread -D_GNU_SOURCE -I../modem/freedv -I../modem -I../datalink_broadcast -I.. -I../audioio/ffaudio -I../common LDFLAGS=$(FFAUDIO_LINKFLAGS) -lm all: ../mercury -../mercury: main.o arq.o net.o fsm.o arith.o crc6.o modem.o broadcast.o ../modem/freedv/libfreedvdata.a ../audioio/audioio.a \ +../mercury: main.o arq.o net.o fsm.o arith.o crc6.o ../datalink_broadcast/broadcast.o ../modem/modem.o ../modem/freedv/libfreedvdata.a ../audioio/audioio.a \ ../common/os_interop.o ../common/ring_buffer_posix.o ../common/shm_posix.o $(CC) -o ../mercury \ - main.o arq.o net.o fsm.o arith.o crc6.o modem.o broadcast.o ../modem/freedv/libfreedvdata.a ../audioio/audioio.a \ + main.o arq.o net.o fsm.o arith.o crc6.o ../datalink_broadcast/broadcast.o ../modem/modem.o ../modem/freedv/libfreedvdata.a ../audioio/audioio.a \ ../common/os_interop.o ../common/ring_buffer_posix.o ../common/shm_posix.o $(LDFLAGS) main.o: main.c @@ -70,11 +70,5 @@ arith.o: arith.c crc6.o: crc6.c $(CC) $(CFLAGS) -c crc6.c -modem.o: modem.c - $(CC) $(CFLAGS) -c modem.c - -broadcast.o: broadcast.c - $(CC) $(CFLAGS) -c broadcast.c - clean: rm -f *.o diff --git a/datalink/arith.c b/datalink_arq/arith.c similarity index 100% rename from datalink/arith.c rename to datalink_arq/arith.c diff --git a/datalink/arq.c b/datalink_arq/arq.c similarity index 99% rename from datalink/arq.c rename to datalink_arq/arq.c index 8893686..8a51287 100644 --- a/datalink/arq.c +++ b/datalink_arq/arq.c @@ -25,7 +25,7 @@ #include "fsm.h" #include "../audioio/audioio.h" #include "net.h" -#include "defines.h" +#include "defines_modem.h" extern cbuf_handle_t capture_buffer; extern cbuf_handle_t playback_buffer; diff --git a/datalink/arq.h b/datalink_arq/arq.h similarity index 100% rename from datalink/arq.h rename to datalink_arq/arq.h diff --git a/datalink/crc6.c b/datalink_arq/crc6.c similarity index 100% rename from datalink/crc6.c rename to datalink_arq/crc6.c diff --git a/datalink/fsm.c b/datalink_arq/fsm.c similarity index 100% rename from datalink/fsm.c rename to datalink_arq/fsm.c diff --git a/datalink/fsm.h b/datalink_arq/fsm.h similarity index 100% rename from datalink/fsm.h rename to datalink_arq/fsm.h diff --git a/datalink/main.c b/datalink_arq/main.c similarity index 96% rename from datalink/main.c rename to datalink_arq/main.c index e23d89f..fb6ff57 100644 --- a/datalink/main.c +++ b/datalink_arq/main.c @@ -36,7 +36,7 @@ #include "arq.h" #include "modem.h" #include "broadcast.h" -#include "defines.h" +#include "defines_modem.h" #include "audioio/audioio.h" extern cbuf_handle_t capture_buffer; @@ -318,14 +318,13 @@ int main(int argc, char *argv[]) return EXIT_SUCCESS; } - struct freedv *freedv = NULL; - pthread_t radio_capture; - pthread_t radio_playback; + generic_modem_t g_modem; + pthread_t radio_capture, radio_playback; if (audio_system == AUDIO_SUBSYSTEM_SHM) { printf("Initializing I/O from Shared Memory (SHM)\n"); - init_modem(&freedv, mod_config, 1, &radio_capture, &radio_playback); // frames per burst is 1 for now + init_modem(&g_modem, mod_config, 1); // frames per burst is 1 for now } else { @@ -337,11 +336,11 @@ int main(int argc, char *argv[]) // arq_init(base_tcp_port, mod_config); // we block here - broadcast_run(freedv, broadcast_port); + broadcast_run(&g_modem, broadcast_port); if (audio_system == AUDIO_SUBSYSTEM_SHM) { - shutdown_modem(freedv, &radio_capture, &radio_playback); + shutdown_modem(&g_modem); } else { diff --git a/datalink/net.c b/datalink_arq/net.c similarity index 100% rename from datalink/net.c rename to datalink_arq/net.c diff --git a/datalink/net.h b/datalink_arq/net.h similarity index 100% rename from datalink/net.h rename to datalink_arq/net.h diff --git a/datalink_broadcast/Makefile b/datalink_broadcast/Makefile new file mode 100644 index 0000000..d5f2781 --- /dev/null +++ b/datalink_broadcast/Makefile @@ -0,0 +1,13 @@ +CC=gcc +CFLAGS=-Wall -O2 -std=gnu11 -pthread -D_GNU_SOURCE=1 -I../modem -I../modem/freedv -I../common -I../datalink_arq +all: broadcast.o kiss.o + +kiss.o: kiss.c + $(CC) $(CFLAGS) -c kiss.c + +broadcast.o: broadcast.c + $(CC) $(CFLAGS) -c broadcast.c + + +clean: + rm *.o diff --git a/datalink/broadcast.c b/datalink_broadcast/broadcast.c similarity index 93% rename from datalink/broadcast.c rename to datalink_broadcast/broadcast.c index a3eea99..277e1e4 100644 --- a/datalink/broadcast.c +++ b/datalink_broadcast/broadcast.c @@ -28,9 +28,10 @@ #include #include "modem.h" -#include "defines.h" -#include "ring_buffer_posix.h" #include "arq.h" +#include "defines_modem.h" +#include "ring_buffer_posix.h" + extern cbuf_handle_t data_tx_buffer; extern cbuf_handle_t data_rx_buffer; @@ -39,9 +40,9 @@ extern bool shutdown_; // global shutdown flag extern arq_info arq_conn; // ARQ connection info // Function to handle TX logic -void *broadcast_tx_thread(void *freedv_ptr) +void *broadcast_tx_thread(void *g_modem) { - struct freedv *freedv = (struct freedv *)freedv_ptr; + struct freedv *freedv = ((generic_modem_t *)g_modem)->freedv; size_t bytes_per_modem_frame = freedv_get_bits_per_modem_frame(freedv) / 8; uint8_t *data = (uint8_t *)malloc(bytes_per_modem_frame); @@ -65,7 +66,7 @@ void *broadcast_tx_thread(void *freedv_ptr) read_buffer(data_tx_buffer, data, bytes_per_modem_frame); // Transmit the data - send_modulated_data(freedv, data, 1); + send_modulated_data(g_modem, data, 1); usleep(5000000); // 5s for now - TODO !!! some delay for transmission } } @@ -75,9 +76,9 @@ void *broadcast_tx_thread(void *freedv_ptr) } // Function to handle RX logic -void *broadcast_rx_thread(void *freedv_ptr) +void *broadcast_rx_thread(void *g_modem) { - struct freedv *freedv = (struct freedv *)freedv_ptr; + struct freedv *freedv = ((generic_modem_t *)g_modem)->freedv; size_t bytes_per_modem_frame = freedv_get_bits_per_modem_frame(freedv) / 8; uint8_t *data = (uint8_t *)malloc(bytes_per_modem_frame); size_t nbytes_out = 0; @@ -93,7 +94,7 @@ void *broadcast_rx_thread(void *freedv_ptr) if (arq_conn.TRX == RX) { // Receive data - receive_modulated_data(freedv, data, &nbytes_out); + receive_modulated_data(g_modem, data, &nbytes_out); if (nbytes_out > 0) { write_buffer(data_rx_buffer, data, nbytes_out); @@ -156,7 +157,7 @@ void *tcp_server_thread(void *port_ptr) printf("Client connected.\n"); - uint8_t *buffer = (uint8_t *)malloc(DATA_TX_BUFFER_SIZE); + uint8_t *buffer = (uint8_t *)malloc(DATA_TX_BUFFER_SIZE);; if (!buffer) { fprintf(stderr, "Failed to allocate memory for TCP buffer.\n"); @@ -211,15 +212,15 @@ void *tcp_server_thread(void *port_ptr) } // Main function to handle broadcast operations -void broadcast_run(struct freedv *freedv, int tcp_port) +void broadcast_run(generic_modem_t *g_modem, int tcp_port) { printf("Starting broadcast system...\n"); pthread_t tx_thread, rx_thread, server_thread; // Create TX and RX threads - pthread_create(&tx_thread, NULL, broadcast_tx_thread, (void *)freedv); - pthread_create(&rx_thread, NULL, broadcast_rx_thread, (void *)freedv); + pthread_create(&tx_thread, NULL, broadcast_tx_thread, (void *)g_modem); + pthread_create(&rx_thread, NULL, broadcast_rx_thread, (void *)g_modem); // Create TCP server thread pthread_create(&server_thread, NULL, tcp_server_thread, (void *)&tcp_port); diff --git a/datalink/broadcast.h b/datalink_broadcast/broadcast.h similarity index 92% rename from datalink/broadcast.h rename to datalink_broadcast/broadcast.h index 02afe20..4d844ef 100644 --- a/datalink/broadcast.h +++ b/datalink_broadcast/broadcast.h @@ -23,7 +23,7 @@ #include #include -#include "freedv_api.h" +#include "modem.h" /* Function declarations */ @@ -33,7 +33,7 @@ * @param freedv Pointer to the FreeDV structure. * @param tcp_port The TCP port to use for the server. */ -void broadcast_run(struct freedv *freedv, int tcp_port); +void broadcast_run(generic_modem_t *g_modem, int tcp_port); #endif // BROADCAST_H_ diff --git a/datalink_broadcast/kiss.c b/datalink_broadcast/kiss.c new file mode 100644 index 0000000..72f6391 --- /dev/null +++ b/datalink_broadcast/kiss.c @@ -0,0 +1,101 @@ +/* KISS framer + * + * Copyright (C) 2020-2024 Rhizomatica + * Author: Rafael Diniz + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +#include +#include +#include +#include +#include "kiss.h" + +int frame_len; +bool IN_FRAME; +bool ESCAPE; + +uint8_t kiss_command = CMD_UNKNOWN; +uint8_t frame_buffer[MAX_PAYLOAD]; +uint8_t write_buffer[MAX_PAYLOAD*2+3]; + +void kiss_frame_received(int frame_len) +{ + // do something here... + int written = write(1, frame_buffer, frame_len); +} + +void kiss_read(uint8_t sbyte) +{ + if (IN_FRAME && sbyte == FEND && kiss_command == CMD_DATA) + { + IN_FRAME = false; + kiss_frame_received(frame_len); + return; + } + if (sbyte == FEND) + { + IN_FRAME = true; + kiss_command = CMD_UNKNOWN; + frame_len = 0; + return; + } + if (IN_FRAME && frame_len < MAX_PAYLOAD) + { + // Have a look at the command byte first + if (frame_len == 0 && kiss_command == CMD_UNKNOWN) + { + // Strip of port nibble + kiss_command = sbyte & 0x0F; + return; + } + if (kiss_command == CMD_DATA) + { + if (sbyte == FESC) + { + ESCAPE = true; + return; + } + if (ESCAPE) + { + if (sbyte == TFEND) sbyte = FEND; + if (sbyte == TFESC) sbyte = FESC; + ESCAPE = false; + } + if (frame_len < MAX_PAYLOAD) + { + frame_buffer[frame_len++] = sbyte; + } + } + } +} + +int kiss_write_frame(uint8_t* buffer, int frame_len) +{ + int write_len = 0; + write_buffer[write_len++] = FEND; + write_buffer[write_len++] = CMD_DATA; + for (int i = 0; i < frame_len; i++) + { + uint8_t byte = buffer[i]; + switch(byte) + { + case FEND: + write_buffer[write_len++] = FESC; + write_buffer[write_len++] = TFEND; + break; + case FESC: + write_buffer[write_len++] = FESC; + write_buffer[write_len++] = TFESC; + break; + default: + write_buffer[write_len++] = byte; + } + } + write_buffer[write_len++] = FEND; + + // TODO: write the buffer somewhere... + return write(1, write_buffer, write_len); +} diff --git a/datalink_broadcast/kiss.h b/datalink_broadcast/kiss.h new file mode 100644 index 0000000..ec8bc99 --- /dev/null +++ b/datalink_broadcast/kiss.h @@ -0,0 +1,38 @@ +/* KISS framer + * + * Copyright (C) 2020-2024 Rhizomatica + * Author: Rafael Diniz + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +#pragma once + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define FEND 0xC0 +#define FESC 0xDB +#define TFEND 0xDC +#define TFESC 0xDD + +#define CMD_UNKNOWN 0xFE +#define CMD_AX25 0x00 // AX25 Frame (standard) in VARA +#define CMD_AX25CALLSIGN 0x01 // AX25 Frame (7 chrs Call Signs) in VARA +#define CMD_DATA 0x02 // VARA / Mercury unformatted frame +#define CMD_RQ_CONFIG 0x03 // Mercury special fountain code configuration frame +#define CMD_RQ_PAYLOAD 0x04 // Fountain code payload + +#define MAX_PAYLOAD 756 // ~ 18 frames at VARA Level 4 + +void kiss_read(uint8_t sbyte); +int kiss_write_frame(uint8_t* buffer, int frame_len); + + +#ifdef __cplusplus +}; +#endif diff --git a/modem/Makefile b/modem/Makefile new file mode 100644 index 0000000..75a8cbf --- /dev/null +++ b/modem/Makefile @@ -0,0 +1,16 @@ +CFLAGS=-D_GNU_SOURCE=1 -I. -I../common -I../modem -I../modem/freedv -I../datalink_arq -Wall -Wno-strict-overflow -std=gnu11 -fPIC -O2 +CC=gcc + +.PHONY: all freedv + +all: freedv modem.o + +freedv: + $(MAKE) -C freedv + +modem.o: modem.c modem.h + $(CC) $(CFLAGS) -c modem.c + +clean: + $(MAKE) -C freedv clean + rm -f *.o diff --git a/datalink/modem.c b/modem/modem.c similarity index 91% rename from datalink/modem.c rename to modem/modem.c index a7d1bcf..3fadea4 100644 --- a/datalink/modem.c +++ b/modem/modem.c @@ -34,7 +34,7 @@ #include "ldpc_codes.h" #include "ofdm_internal.h" -#include "defines.h" +#include "defines_modem.h" extern bool shutdown_; // global shutdown flag @@ -45,7 +45,7 @@ cbuf_handle_t data_tx_buffer; cbuf_handle_t data_rx_buffer; -int init_modem(struct freedv **freedv, int mode, int frames_per_burst, pthread_t *radio_capture, pthread_t *radio_playback) +int init_modem(generic_modem_t *g_modem, int mode, int frames_per_burst) { // connect to shared memory buffers try_shm_connect1: @@ -72,21 +72,21 @@ try_shm_connect2: data_tx_buffer = circular_buf_init(buffer_tx, DATA_TX_BUFFER_SIZE); data_rx_buffer = circular_buf_init(buffer_rx, DATA_RX_BUFFER_SIZE); printf("Created data buffers for TX and RX.\n"); - + char codename[80] = "H_256_512_4"; struct freedv_advanced adv = {0, 2, 100, 8000, 1000, 200, codename}; if (mode == FREEDV_MODE_FSK_LDPC) - *freedv = freedv_open_advanced(mode, &adv); + g_modem->freedv = freedv_open_advanced(mode, &adv); else - *freedv = freedv_open(mode); + g_modem->freedv = freedv_open(mode); - freedv_set_frames_per_burst(*freedv, frames_per_burst); + freedv_set_frames_per_burst(g_modem->freedv, frames_per_burst); return 0; } -int shutdown_modem(struct freedv *freedv, pthread_t *radio_capture, pthread_t *radio_playback) +int shutdown_modem(generic_modem_t *g_modem) { circular_buf_destroy_shm(capture_buffer, SIGNAL_BUFFER_SIZE, SIGNAL_INPUT); circular_buf_destroy_shm(playback_buffer, SIGNAL_BUFFER_SIZE, SIGNAL_OUTPUT); @@ -98,13 +98,14 @@ int shutdown_modem(struct freedv *freedv, pthread_t *radio_capture, pthread_t *r circular_buf_free(data_tx_buffer); circular_buf_free(data_rx_buffer); - freedv_close(freedv); + freedv_close(g_modem->freedv); return 0; } -int send_modulated_data(struct freedv *freedv, uint8_t *bytes_in, int frames_per_burst) +int send_modulated_data(generic_modem_t *g_modem, uint8_t *bytes_in, int frames_per_burst) { + struct freedv *freedv = g_modem->freedv; size_t bytes_per_modem_frame = freedv_get_bits_per_modem_frame(freedv) / 8; size_t payload_bytes_per_modem_frame = bytes_per_modem_frame - 2; /* 16 bits used for the CRC */ size_t n_mod_out = freedv_get_n_tx_modem_samples(freedv); @@ -155,8 +156,9 @@ int send_modulated_data(struct freedv *freedv, uint8_t *bytes_in, int frames_per return 0; } -int receive_modulated_data(struct freedv *freedv, uint8_t *bytes_out, size_t *nbytes_out) +int receive_modulated_data(generic_modem_t *g_modem, uint8_t *bytes_out, size_t *nbytes_out) { + struct freedv *freedv = g_modem->freedv; size_t bytes_per_modem_frame = freedv_get_bits_per_modem_frame(freedv) / 8; size_t payload_bytes_per_modem_frame = bytes_per_modem_frame - 2; /* 16 bits used for the CRC */ diff --git a/datalink/modem.h b/modem/modem.h similarity index 66% rename from datalink/modem.h rename to modem/modem.h index a05c608..47c0747 100644 --- a/datalink/modem.h +++ b/modem/modem.h @@ -27,14 +27,19 @@ #include "freedv_api.h" -int init_modem(struct freedv **freedv, int mode, int frames_per_burst, pthread_t *radio_capture, pthread_t *radio_playback); +typedef struct generic_modem { + struct freedv *freedv; + void *future_extension; // Placeholder for future extensions +} generic_modem_t; -int shutdown_modem(struct freedv *freedv, pthread_t *radio_capture, pthread_t *radio_playback); +int init_modem(generic_modem_t *g_modem, int mode, int frames_per_burst); + +int shutdown_modem(generic_modem_t *g_modem); // always send the frame size in bytes_in -int send_modulated_data(struct freedv *freedv, uint8_t *bytes_in, int frames_per_burst); +int send_modulated_data(generic_modem_t *g_modem, uint8_t *bytes_in, int frames_per_burst); -int receive_modulated_data(struct freedv *freedv, uint8_t *bytes_out, size_t *nbytes_out); +int receive_modulated_data(generic_modem_t *g_modem, uint8_t *bytes_out, size_t *nbytes_out); #endif // MODEM_H