mirror of
https://github.com/radio95-rnt/rds95.git
synced 2026-02-26 20:33:53 +01:00
autosave on exit
This commit is contained in:
@@ -569,18 +569,6 @@ void process_ascii_cmd(RDSModulator* mod, char *str, char *cmd_output) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (upper_str[0] == '*' && !strchr((const char*)upper_str, '=')) {
|
|
||||||
const char* option_str = upper_str + 1;
|
|
||||||
char option[32] = {0};
|
|
||||||
size_t copy_len = strlen(option_str);
|
|
||||||
if (copy_len >= sizeof(option)) copy_len = sizeof(option) - 1;
|
|
||||||
memcpy(option, option_str, copy_len);
|
|
||||||
option[copy_len] = 0;
|
|
||||||
saveToFile(mod->enc, option);
|
|
||||||
Modulator_saveToFile(&mod->params, option);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
char *equals_pos = strchr(upper_str, '=');
|
char *equals_pos = strchr(upper_str, '=');
|
||||||
if (equals_pos != NULL) {
|
if (equals_pos != NULL) {
|
||||||
cmd = upper_str;
|
cmd = upper_str;
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
#include "modulator.h"
|
#include "modulator.h"
|
||||||
|
|
||||||
void Modulator_saveToFile(RDSModulatorParameters *emp, const char *option) {
|
void Modulator_saveToFile(RDSModulatorParameters *emp) {
|
||||||
char modulatorPath[128];
|
char modulatorPath[128];
|
||||||
snprintf(modulatorPath, sizeof(modulatorPath), "%s/.rdsModulator", getenv("HOME"));
|
snprintf(modulatorPath, sizeof(modulatorPath), "%s/.rdsModulator", getenv("HOME"));
|
||||||
FILE *file;
|
FILE *file;
|
||||||
@@ -20,12 +20,8 @@ void Modulator_saveToFile(RDSModulatorParameters *emp, const char *option) {
|
|||||||
}
|
}
|
||||||
memcpy(&tempMod, &tempFile.params, sizeof(RDSModulatorParameters));
|
memcpy(&tempMod, &tempFile.params, sizeof(RDSModulatorParameters));
|
||||||
|
|
||||||
if (strcmp(option, "LEVEL") == 0) tempMod.level = emp->level;
|
tempMod.level = emp->level;
|
||||||
else if (strcmp(option, "RDSGEN") == 0) tempMod.rdsgen = emp->rdsgen;
|
tempMod.rdsgen = emp->rdsgen;
|
||||||
else if (strcmp(option, "ALL") == 0) {
|
|
||||||
tempMod.level = emp->level;
|
|
||||||
tempMod.rdsgen = emp->rdsgen;
|
|
||||||
} else return;
|
|
||||||
|
|
||||||
memcpy(&tempFile.params, &tempMod, sizeof(RDSModulatorParameters));
|
memcpy(&tempFile.params, &tempMod, sizeof(RDSModulatorParameters));
|
||||||
tempFile.check = 160;
|
tempFile.check = 160;
|
||||||
@@ -96,7 +92,7 @@ void init_rds_modulator(RDSModulator* rdsMod, RDSEncoder* enc, uint8_t num_strea
|
|||||||
}
|
}
|
||||||
|
|
||||||
if(modulatorsaved()) Modulator_loadFromFile(&rdsMod->params);
|
if(modulatorsaved()) Modulator_loadFromFile(&rdsMod->params);
|
||||||
else Modulator_saveToFile(&rdsMod->params, "ALL");
|
else Modulator_saveToFile(&rdsMod->params);
|
||||||
}
|
}
|
||||||
|
|
||||||
void cleanup_rds_modulator(RDSModulator* rdsMod) {
|
void cleanup_rds_modulator(RDSModulator* rdsMod) {
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ typedef struct {
|
|||||||
uint8_t num_streams;
|
uint8_t num_streams;
|
||||||
} RDSModulator;
|
} RDSModulator;
|
||||||
|
|
||||||
void Modulator_saveToFile(RDSModulatorParameters *emp, const char *option);
|
void Modulator_saveToFile(RDSModulatorParameters *emp);
|
||||||
void Modulator_loadFromFile(RDSModulatorParameters *emp);
|
void Modulator_loadFromFile(RDSModulatorParameters *emp);
|
||||||
int modulatorsaved();
|
int modulatorsaved();
|
||||||
void init_rds_modulator(RDSModulator* rdsMod, RDSEncoder* enc, uint8_t num_streams);
|
void init_rds_modulator(RDSModulator* rdsMod, RDSEncoder* enc, uint8_t num_streams);
|
||||||
|
|||||||
80
src/rds.c
80
src/rds.c
@@ -1,86 +1,10 @@
|
|||||||
#include "common.h"
|
#include "common.h"
|
||||||
#include "rds.h"
|
#include "rds.h"
|
||||||
|
#include "rds_fs.h"
|
||||||
#include "modulator.h"
|
#include "modulator.h"
|
||||||
#include "lib.h"
|
#include "lib.h"
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
|
|
||||||
void saveToFile(RDSEncoder *enc, const char *option) {
|
|
||||||
char encoderPath[128];
|
|
||||||
snprintf(encoderPath, sizeof(encoderPath), "%s/.rdsEncoder", getenv("HOME"));
|
|
||||||
|
|
||||||
RDSEncoder tempEncoder;
|
|
||||||
FILE *file = fopen(encoderPath, "rb");
|
|
||||||
if (file) {
|
|
||||||
fread(&tempEncoder, sizeof(RDSEncoder), 1, file);
|
|
||||||
fclose(file);
|
|
||||||
} else memcpy(&tempEncoder, enc, sizeof(RDSEncoder));
|
|
||||||
|
|
||||||
if (strcmp(option, "PROGRAM") == 0) {
|
|
||||||
memcpy(&tempEncoder.data[enc->program], &enc->data[enc->program], sizeof(RDSData));
|
|
||||||
memcpy(&tempEncoder.rtpData[enc->program], &enc->rtpData[enc->program], sizeof(RDSRTPlusData) * 2);
|
|
||||||
} else if (strcmp(option, "ALL") == 0) {
|
|
||||||
memcpy(tempEncoder.data, enc->data, sizeof(RDSData) * PROGRAMS);
|
|
||||||
memcpy(tempEncoder.rtpData, enc->rtpData, sizeof(RDSRTPlusData) * PROGRAMS * 2);
|
|
||||||
memcpy(&tempEncoder.encoder_data, &enc->encoder_data, sizeof(RDSEncoderData));
|
|
||||||
} else return;
|
|
||||||
tempEncoder.program = enc->program;
|
|
||||||
|
|
||||||
RDSEncoderFile rdsEncoderfile = {.file_starter = 225, .file_middle = 160, .file_ender = 95, .program = tempEncoder.program};
|
|
||||||
memcpy(&rdsEncoderfile.data[enc->program], &tempEncoder.data[enc->program], sizeof(RDSData));
|
|
||||||
memcpy(&rdsEncoderfile.rtpData[enc->program], &tempEncoder.rtpData[enc->program], sizeof(RDSRTPlusData) * 2);
|
|
||||||
memcpy(&rdsEncoderfile.encoder_data, &tempEncoder.encoder_data, sizeof(RDSEncoderData));
|
|
||||||
|
|
||||||
rdsEncoderfile.crc = crc16_ccitt((char *)&rdsEncoderfile, offsetof(RDSEncoderFile, crc));
|
|
||||||
|
|
||||||
file = fopen(encoderPath, "wb");
|
|
||||||
if (!file) {
|
|
||||||
perror("Error opening file");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
fwrite(&rdsEncoderfile, sizeof(RDSEncoderFile), 1, file);
|
|
||||||
fclose(file);
|
|
||||||
}
|
|
||||||
|
|
||||||
void loadFromFile(RDSEncoder *enc) {
|
|
||||||
char encoderPath[128];
|
|
||||||
snprintf(encoderPath, sizeof(encoderPath), "%s/.rdsEncoder", getenv("HOME"));
|
|
||||||
|
|
||||||
RDSEncoderFile rdsEncoderfile;
|
|
||||||
FILE *file = fopen(encoderPath, "rb");
|
|
||||||
if (!file) {
|
|
||||||
perror("Error opening file");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
fread(&rdsEncoderfile, sizeof(rdsEncoderfile), 1, file);
|
|
||||||
fclose(file);
|
|
||||||
|
|
||||||
if (rdsEncoderfile.file_starter != 225 || rdsEncoderfile.file_ender != 95 || rdsEncoderfile.file_middle != 160) {
|
|
||||||
fprintf(stderr, "[RDSENCODER-FILE] Invalid file format\n");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (crc16_ccitt((char*)&rdsEncoderfile, offsetof(RDSEncoderFile, crc)) != rdsEncoderfile.crc) {
|
|
||||||
fprintf(stderr, "[RDSENCODER-FILE] CRC mismatch! Data may be corrupted\n");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 0; i < PROGRAMS; i++) {
|
|
||||||
memcpy(&(enc->data[i]), &(rdsEncoderfile.data[i]), sizeof(RDSData));
|
|
||||||
memcpy(&(enc->rtpData[i]), &(rdsEncoderfile.rtpData[i]), sizeof(RDSRTPlusData)*2);
|
|
||||||
}
|
|
||||||
memcpy(&(enc->encoder_data), &(rdsEncoderfile.encoder_data), sizeof(RDSEncoderData));
|
|
||||||
enc->program = rdsEncoderfile.program;
|
|
||||||
}
|
|
||||||
|
|
||||||
int isFileSaved() {
|
|
||||||
char encoderPath[128];
|
|
||||||
snprintf(encoderPath, sizeof(encoderPath), "%s/.rdsEncoder", getenv("HOME"));
|
|
||||||
FILE *file = fopen(encoderPath, "rb");
|
|
||||||
if(!file) return 0;
|
|
||||||
fclose(file);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static uint16_t get_next_af(RDSEncoder* enc) {
|
static uint16_t get_next_af(RDSEncoder* enc) {
|
||||||
uint16_t out;
|
uint16_t out;
|
||||||
|
|
||||||
@@ -784,7 +708,7 @@ void init_rds_encoder(RDSEncoder* enc) {
|
|||||||
for(int i = 0; i < PROGRAMS; i++) set_rds_defaults(enc, i);
|
for(int i = 0; i < PROGRAMS; i++) set_rds_defaults(enc, i);
|
||||||
|
|
||||||
if (isFileSaved()) loadFromFile(enc);
|
if (isFileSaved()) loadFromFile(enc);
|
||||||
else saveToFile(enc, "ALL");
|
else saveToFile(enc);
|
||||||
|
|
||||||
for(int i = 0; i < PROGRAMS; i++) reset_rds_state(enc, i);
|
for(int i = 0; i < PROGRAMS; i++) reset_rds_state(enc, i);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -234,10 +234,6 @@ typedef struct
|
|||||||
|
|
||||||
#define IS_TYPE_B(b) (b & 0x0800)
|
#define IS_TYPE_B(b) (b & 0x0800)
|
||||||
|
|
||||||
void saveToFile(RDSEncoder *emp, const char *option);
|
|
||||||
void loadFromFile(RDSEncoder *emp);
|
|
||||||
int isFileSaved();
|
|
||||||
|
|
||||||
void reset_rds_state(RDSEncoder* enc, uint8_t program);
|
void reset_rds_state(RDSEncoder* enc, uint8_t program);
|
||||||
void set_rds_defaults(RDSEncoder* enc, uint8_t program);
|
void set_rds_defaults(RDSEncoder* enc, uint8_t program);
|
||||||
void init_rds_encoder(RDSEncoder* enc);
|
void init_rds_encoder(RDSEncoder* enc);
|
||||||
|
|||||||
19
src/rds95.c
19
src/rds95.c
@@ -7,6 +7,7 @@
|
|||||||
#include "../inih/ini.h"
|
#include "../inih/ini.h"
|
||||||
|
|
||||||
#include "rds.h"
|
#include "rds.h"
|
||||||
|
#include "rds_fs.h"
|
||||||
#include "modulator.h"
|
#include "modulator.h"
|
||||||
#include "udp_server.h"
|
#include "udp_server.h"
|
||||||
#include "lib.h"
|
#include "lib.h"
|
||||||
@@ -59,18 +60,15 @@ 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)
|
#define MATCH(s, n) (strcmp(section, s) == 0 && strcmp(name, n) == 0)
|
||||||
|
|
||||||
if (MATCH("rds95", "udp_port")) {
|
if (MATCH("rds95", "udp_port")) config->udp_port = (uint16_t)atoi(value);
|
||||||
config->udp_port = (uint16_t)atoi(value);
|
else if (MATCH("devices", "rds95")) {
|
||||||
} else if (MATCH("devices", "rds95")) {
|
|
||||||
strncpy(config->rds_device_name, value, sizeof(config->rds_device_name) - 1);
|
strncpy(config->rds_device_name, value, sizeof(config->rds_device_name) - 1);
|
||||||
config->rds_device_name[sizeof(config->rds_device_name) - 1] = '\0';
|
config->rds_device_name[sizeof(config->rds_device_name) - 1] = '\0';
|
||||||
} else if (MATCH("rds95", "streams")) {
|
} else if (MATCH("rds95", "streams")) {
|
||||||
int streams = atoi(value);
|
int streams = atoi(value);
|
||||||
if (streams > MAX_STREAMS || streams == 0) return 0;
|
if (streams > MAX_STREAMS || streams == 0) return 0;
|
||||||
config->num_streams = (uint8_t)streams;
|
config->num_streams = (uint8_t)streams;
|
||||||
} else {
|
} else return 0
|
||||||
return 0; // Unknown config key
|
|
||||||
}
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -188,9 +186,7 @@ int main(int argc, char **argv) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
while(!stop_rds) {
|
while(!stop_rds) {
|
||||||
for (uint16_t i = 0; i < NUM_MPX_FRAMES * config.num_streams; i++) {
|
for (uint16_t i = 0; i < NUM_MPX_FRAMES * config.num_streams; i++) rds_buffer[i] = get_rds_sample(&rdsModulator, i % config.num_streams);
|
||||||
rds_buffer[i] = get_rds_sample(&rdsModulator, i % config.num_streams);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pa_simple_write(rds_device, rds_buffer, NUM_MPX_FRAMES * config.num_streams * sizeof(float), &pulse_error) != 0) {
|
if (pa_simple_write(rds_device, rds_buffer, NUM_MPX_FRAMES * config.num_streams * sizeof(float), &pulse_error) != 0) {
|
||||||
fprintf(stderr, "Error: could not play audio. (%s : %d)\n", pa_strerror(pulse_error), pulse_error);
|
fprintf(stderr, "Error: could not play audio. (%s : %d)\n", pa_strerror(pulse_error), pulse_error);
|
||||||
@@ -206,7 +202,10 @@ exit:
|
|||||||
pthread_join(udp_server_thread, NULL);
|
pthread_join(udp_server_thread, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
cleanup_rds_modulator(&rdsModulator); // Clean up dynamically allocated memory
|
saveToFile(rdsEncoder);
|
||||||
|
Modulator_saveToFile(&rdsModulator.params);
|
||||||
|
|
||||||
|
cleanup_rds_modulator(&rdsModulator);
|
||||||
pthread_attr_destroy(&attr);
|
pthread_attr_destroy(&attr);
|
||||||
if (rds_device != NULL) pa_simple_free(rds_device);
|
if (rds_device != NULL) pa_simple_free(rds_device);
|
||||||
|
|
||||||
|
|||||||
73
src/rds_fs.c
Normal file
73
src/rds_fs.c
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
#include "rds_fs.h"
|
||||||
|
|
||||||
|
void saveToFile(RDSEncoder *enc) {
|
||||||
|
char encoderPath[128];
|
||||||
|
snprintf(encoderPath, sizeof(encoderPath), "%s/.rdsEncoder", getenv("HOME"));
|
||||||
|
|
||||||
|
RDSEncoder tempEncoder;
|
||||||
|
FILE *file = fopen(encoderPath, "rb");
|
||||||
|
if (file) {
|
||||||
|
fread(&tempEncoder, sizeof(RDSEncoder), 1, file);
|
||||||
|
fclose(file);
|
||||||
|
} else memcpy(&tempEncoder, enc, sizeof(RDSEncoder));
|
||||||
|
|
||||||
|
memcpy(tempEncoder.data, enc->data, sizeof(RDSData) * PROGRAMS);
|
||||||
|
memcpy(tempEncoder.rtpData, enc->rtpData, sizeof(RDSRTPlusData) * PROGRAMS * 2);
|
||||||
|
memcpy(&tempEncoder.encoder_data, &enc->encoder_data, sizeof(RDSEncoderData));
|
||||||
|
tempEncoder.program = enc->program;
|
||||||
|
|
||||||
|
RDSEncoderFile rdsEncoderfile = {.file_starter = 225, .file_middle = 160, .file_ender = 95, .program = tempEncoder.program};
|
||||||
|
memcpy(&rdsEncoderfile.data[enc->program], &tempEncoder.data[enc->program], sizeof(RDSData));
|
||||||
|
memcpy(&rdsEncoderfile.rtpData[enc->program], &tempEncoder.rtpData[enc->program], sizeof(RDSRTPlusData) * 2);
|
||||||
|
memcpy(&rdsEncoderfile.encoder_data, &tempEncoder.encoder_data, sizeof(RDSEncoderData));
|
||||||
|
|
||||||
|
rdsEncoderfile.crc = crc16_ccitt((char *)&rdsEncoderfile, offsetof(RDSEncoderFile, crc));
|
||||||
|
|
||||||
|
file = fopen(encoderPath, "wb");
|
||||||
|
if (!file) {
|
||||||
|
perror("Error opening file");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
fwrite(&rdsEncoderfile, sizeof(RDSEncoderFile), 1, file);
|
||||||
|
fclose(file);
|
||||||
|
}
|
||||||
|
|
||||||
|
void loadFromFile(RDSEncoder *enc) {
|
||||||
|
char encoderPath[128];
|
||||||
|
snprintf(encoderPath, sizeof(encoderPath), "%s/.rdsEncoder", getenv("HOME"));
|
||||||
|
|
||||||
|
RDSEncoderFile rdsEncoderfile;
|
||||||
|
FILE *file = fopen(encoderPath, "rb");
|
||||||
|
if (!file) {
|
||||||
|
perror("Error opening file");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
fread(&rdsEncoderfile, sizeof(rdsEncoderfile), 1, file);
|
||||||
|
fclose(file);
|
||||||
|
|
||||||
|
if (rdsEncoderfile.file_starter != 225 || rdsEncoderfile.file_ender != 95 || rdsEncoderfile.file_middle != 160) {
|
||||||
|
fprintf(stderr, "[RDSENCODER-FILE] Invalid file format\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (crc16_ccitt((char*)&rdsEncoderfile, offsetof(RDSEncoderFile, crc)) != rdsEncoderfile.crc) {
|
||||||
|
fprintf(stderr, "[RDSENCODER-FILE] CRC mismatch! Data may be corrupted\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < PROGRAMS; i++) {
|
||||||
|
memcpy(&(enc->data[i]), &(rdsEncoderfile.data[i]), sizeof(RDSData));
|
||||||
|
memcpy(&(enc->rtpData[i]), &(rdsEncoderfile.rtpData[i]), sizeof(RDSRTPlusData)*2);
|
||||||
|
}
|
||||||
|
memcpy(&(enc->encoder_data), &(rdsEncoderfile.encoder_data), sizeof(RDSEncoderData));
|
||||||
|
enc->program = rdsEncoderfile.program;
|
||||||
|
}
|
||||||
|
|
||||||
|
int isFileSaved() {
|
||||||
|
char encoderPath[128];
|
||||||
|
snprintf(encoderPath, sizeof(encoderPath), "%s/.rdsEncoder", getenv("HOME"));
|
||||||
|
FILE *file = fopen(encoderPath, "rb");
|
||||||
|
if(!file) return 0;
|
||||||
|
fclose(file);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
5
src/rds_fs.h
Normal file
5
src/rds_fs.h
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
#include "rds.h"
|
||||||
|
|
||||||
|
void saveToFile(RDSEncoder *emp);
|
||||||
|
void loadFromFile(RDSEncoder *emp);
|
||||||
|
int isFileSaved();
|
||||||
Reference in New Issue
Block a user