0
1
mirror of https://github.com/radio95-rnt/rds95.git synced 2026-02-27 04:43:52 +01:00

do the cycle shift proplerly, shorten the code a bit and add a device arg

This commit is contained in:
2025-05-29 17:11:29 +02:00
parent ff2081bcb7
commit 86235ad391
4 changed files with 51 additions and 57 deletions

View File

@@ -88,8 +88,7 @@ void init_rds_modulator(RDSModulator* rdsMod, RDSEncoder* enc) {
rdsMod->enc = enc; rdsMod->enc = enc;
if(STREAMS > 0) rdsMod->data[1].symbol_shift = FILTER_SIZE / 2; if(STREAMS > 0) rdsMod->data[1].symbol_shift = M_PI;
if(modulatorsaved()) { if(modulatorsaved()) {
Modulator_loadFromFile(&rdsMod->params); Modulator_loadFromFile(&rdsMod->params);
} else { } else {
@@ -112,7 +111,7 @@ float get_rds_sample(RDSModulator* rdsMod, uint8_t stream) {
rdsMod->data[stream].cur_output = rdsMod->data[stream].prev_output ^ rdsMod->data[stream].cur_bit; rdsMod->data[stream].cur_output = rdsMod->data[stream].prev_output ^ rdsMod->data[stream].cur_bit;
} }
float sample = sinf(M_2PI * (rdsMod->data[stream].phase - rdsMod->data[stream].symbol_shift)); float sample = sinf(M_2PI * rdsMod->data[stream].phase + rdsMod->data[stream].symbol_shift);
if(rdsMod->data[stream].cur_output == 0) sample = -sample; // do bpsk if(rdsMod->data[stream].cur_output == 0) sample = -sample; // do bpsk
uint8_t tooutput = rdsMod->params.rdsgen > stream ? 1 : 0; uint8_t tooutput = rdsMod->params.rdsgen > stream ? 1 : 0;

View File

@@ -10,34 +10,35 @@ void saveToFile(RDSEncoder *enc, const char *option) {
RDSEncoder tempEncoder; RDSEncoder tempEncoder;
FILE *file = fopen(encoderPath, "rb"); FILE *file = fopen(encoderPath, "rb");
if (file != NULL) { if (file) {
fread(&tempEncoder, sizeof(RDSEncoder), 1, file); fread(&tempEncoder, sizeof(RDSEncoder), 1, file);
fclose(file); fclose(file);
} else memcpy(&tempEncoder, enc, sizeof(RDSEncoder)); } else memcpy(&tempEncoder, enc, sizeof(RDSEncoder));
if(strcmp(option, "PROGRAM") == 0) { if (strcmp(option, "PROGRAM") == 0) {
memcpy(&(tempEncoder.data[enc->program]), &(enc->data[enc->program]), sizeof(RDSData)); memcpy(&tempEncoder.data[enc->program], &enc->data[enc->program], sizeof(RDSData));
memcpy(&(tempEncoder.rtpData[enc->program]), &(enc->rtpData[enc->program]), sizeof(RDSRTPlusData)*2); memcpy(&tempEncoder.rtpData[enc->program], &enc->rtpData[enc->program], sizeof(RDSRTPlusData) * 2);
tempEncoder.program = enc->program;
} else if (strcmp(option, "ALL") == 0) { } else if (strcmp(option, "ALL") == 0) {
memcpy(&tempEncoder.data, &enc->data, sizeof(RDSData)*PROGRAMS); memcpy(tempEncoder.data, enc->data, sizeof(RDSData) * PROGRAMS);
memcpy(&tempEncoder.rtpData, &enc->rtpData, sizeof(RDSRTPlusData)*PROGRAMS*2); memcpy(tempEncoder.rtpData, enc->rtpData, sizeof(RDSRTPlusData) * PROGRAMS * 2);
memcpy(&tempEncoder.encoder_data, &enc->encoder_data, sizeof(RDSEncoderData)); memcpy(&tempEncoder.encoder_data, &enc->encoder_data, sizeof(RDSEncoderData));
tempEncoder.program = enc->program;
} else return; } else return;
tempEncoder.program = enc->program;
RDSEncoderFile rdsEncoderfile; RDSEncoderFile rdsEncoderfile = {
rdsEncoderfile.file_starter = 225; .file_starter = 225,
rdsEncoderfile.file_middle = 160; .file_middle = 160,
rdsEncoderfile.file_ender = 95; .file_ender = 95,
memcpy(&(rdsEncoderfile.data[enc->program]), &(tempEncoder.data[enc->program]), sizeof(RDSData)); .program = tempEncoder.program,
memcpy(&(rdsEncoderfile.rtpData[enc->program]), &(tempEncoder.rtpData[enc->program]), sizeof(RDSRTPlusData)*2); };
memcpy(&(rdsEncoderfile.encoder_data), &(tempEncoder.encoder_data), sizeof(RDSEncoderData)); memcpy(&rdsEncoderfile.data[enc->program], &tempEncoder.data[enc->program], sizeof(RDSData));
rdsEncoderfile.program = tempEncoder.program; memcpy(&rdsEncoderfile.rtpData[enc->program], &tempEncoder.rtpData[enc->program], sizeof(RDSRTPlusData) * 2);
rdsEncoderfile.crc = crc16_ccitt((char*)&rdsEncoderfile, offsetof(RDSEncoderFile, crc)); memcpy(&rdsEncoderfile.encoder_data, &tempEncoder.encoder_data, sizeof(RDSEncoderData));
rdsEncoderfile.crc = crc16_ccitt((char *)&rdsEncoderfile, offsetof(RDSEncoderFile, crc));
file = fopen(encoderPath, "wb"); file = fopen(encoderPath, "wb");
if (file == NULL) { if (!file) {
perror("Error opening file"); perror("Error opening file");
return; return;
} }
@@ -51,20 +52,19 @@ void loadFromFile(RDSEncoder *enc) {
RDSEncoderFile rdsEncoderfile; RDSEncoderFile rdsEncoderfile;
FILE *file = fopen(encoderPath, "rb"); FILE *file = fopen(encoderPath, "rb");
if (file == NULL) { if (!file) {
perror("Error opening file"); perror("Error opening file");
return; return;
} }
fread(&rdsEncoderfile, sizeof(RDSEncoderFile), 1, file); fread(&rdsEncoderfile, sizeof(rdsEncoderfile), 1, file);
fclose(file); fclose(file);
if (rdsEncoderfile.file_starter != 225 || rdsEncoderfile.file_ender != 95 || rdsEncoderfile.file_middle != 160) { if (rdsEncoderfile.file_starter != 225 || rdsEncoderfile.file_ender != 95 || rdsEncoderfile.file_middle != 160) {
fprintf(stderr, "[RDSENCODER-FILE] Invalid file format\n"); fprintf(stderr, "[RDSENCODER-FILE] Invalid file format\n");
return; return;
} }
uint16_t calculated_crc = crc16_ccitt((char*)&rdsEncoderfile, offsetof(RDSEncoderFile, crc)); if (crc16_ccitt((char*)&rdsEncoderfile, offsetof(RDSEncoderFile, crc)) != rdsEncoderfile.crc) {
if (calculated_crc != rdsEncoderfile.crc) {
fprintf(stderr, "[RDSENCODER-FILE] CRC mismatch! Data may be corrupted\n"); fprintf(stderr, "[RDSENCODER-FILE] CRC mismatch! Data may be corrupted\n");
return; return;
} }
@@ -77,15 +77,13 @@ void loadFromFile(RDSEncoder *enc) {
enc->program = rdsEncoderfile.program; enc->program = rdsEncoderfile.program;
} }
int rdssaved() { int isFileSaved() {
char encoderPath[128]; char encoderPath[128];
snprintf(encoderPath, sizeof(encoderPath), "%s/.rdsEncoder", getenv("HOME")); snprintf(encoderPath, sizeof(encoderPath), "%s/.rdsEncoder", getenv("HOME"));
FILE *file = fopen(encoderPath, "rb"); FILE *file = fopen(encoderPath, "rb");
if (file) { if(!file) return 0;
fclose(file); fclose(file);
return 1; return 1;
}
return 0;
} }
static uint16_t get_next_af(RDSEncoder* enc) { static uint16_t get_next_af(RDSEncoder* enc) {
@@ -160,11 +158,8 @@ static void get_rds_ps_group(RDSEncoder* enc, RDSGroup *group) {
if(enc->state[enc->program].ps_csegment == 0) group->b |= enc->data[enc->program].dpty << 2; if(enc->state[enc->program].ps_csegment == 0) group->b |= enc->data[enc->program].dpty << 2;
group->b |= enc->state[enc->program].ps_csegment; group->b |= enc->state[enc->program].ps_csegment;
group->c = get_next_af(enc); group->c = get_next_af(enc);
if(enc->data[enc->program].ta && enc->state[enc->program].tps_text[0] != '\0') { if(enc->data[enc->program].ta && enc->state[enc->program].tps_text[0] != '\0') group->d = enc->state[enc->program].tps_text[enc->state[enc->program].ps_csegment * 2] << 8 | enc->state[enc->program].tps_text[enc->state[enc->program].ps_csegment * 2 + 1];
group->d = enc->state[enc->program].tps_text[enc->state[enc->program].ps_csegment * 2] << 8 | enc->state[enc->program].tps_text[enc->state[enc->program].ps_csegment * 2 + 1]; else group->d = enc->state[enc->program].ps_text[enc->state[enc->program].ps_csegment * 2] << 8 | enc->state[enc->program].ps_text[enc->state[enc->program].ps_csegment * 2 + 1];
} else {
group->d = enc->state[enc->program].ps_text[enc->state[enc->program].ps_csegment * 2] << 8 | enc->state[enc->program].ps_text[enc->state[enc->program].ps_csegment * 2 + 1];
}
enc->state[enc->program].ps_csegment++; enc->state[enc->program].ps_csegment++;
if (enc->state[enc->program].ps_csegment == 4) enc->state[enc->program].ps_csegment = 0; if (enc->state[enc->program].ps_csegment == 4) enc->state[enc->program].ps_csegment = 0;
@@ -297,7 +292,6 @@ static void get_rds_ct_group(RDSEncoder* enc, RDSGroup *group) {
group->d = (utc->tm_hour & 0xf) << 12 | utc->tm_min << 6; group->d = (utc->tm_hour & 0xf) << 12 | utc->tm_min << 6;
local_time = localtime(&now); local_time = localtime(&now);
offset = local_time->__tm_gmtoff / (30 * 60); offset = local_time->__tm_gmtoff / (30 * 60);
if (offset < 0) group->d |= 1 << 5; if (offset < 0) group->d |= 1 << 5;
group->d |= abs(offset); group->d |= abs(offset);
@@ -806,7 +800,7 @@ void set_rds_defaults(RDSEncoder* enc, uint8_t program) {
void init_rds_encoder(RDSEncoder* enc) { 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 (rdssaved()) loadFromFile(enc); if (isFileSaved()) loadFromFile(enc);
else saveToFile(enc, "ALL"); else saveToFile(enc, "ALL");
for(int i = 0; i < PROGRAMS; i++) reset_rds_state(enc, i); for(int i = 0; i < PROGRAMS; i++) reset_rds_state(enc, i);

View File

@@ -11,8 +11,6 @@
#define GROUP_LENGTH 4 #define GROUP_LENGTH 4
#define BITS_PER_GROUP (GROUP_LENGTH * (BLOCK_SIZE + POLY_DEG)) #define BITS_PER_GROUP (GROUP_LENGTH * (BLOCK_SIZE + POLY_DEG))
#define RDS_SAMPLE_RATE 4750 #define RDS_SAMPLE_RATE 4750
#define FILTER_SIZE 4 // RDS_SAMPLE_RATE/1187.5, or the inverse i dont remember
#define STREAMS 2 #define STREAMS 2
#define RT_LENGTH 64 #define RT_LENGTH 64
@@ -238,7 +236,7 @@ typedef struct
void saveToFile(RDSEncoder *emp, const char *option); void saveToFile(RDSEncoder *emp, const char *option);
void loadFromFile(RDSEncoder *emp); void loadFromFile(RDSEncoder *emp);
int rdssaved(); 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);

View File

@@ -42,9 +42,11 @@ static void show_help(char *name) {
"\n" "\n"
"Usage: %s [options]\n" "Usage: %s [options]\n"
"\n" "\n"
" -C,--ctl FIFO control pipe\n" "\t-C,--ctl\tFIFO control pipe\n"
"\t-d,--device\tPulseAudio device to use (default: %s)\n"
"\n", "\n",
name name,
RDS_DEVICE
); );
} }
@@ -52,6 +54,7 @@ int main(int argc, char **argv) {
show_version(); show_version();
char control_pipe[51] = "\0"; char control_pipe[51] = "\0";
char rds_device_name[32] = RDS_DEVICE;
pa_simple *rds_device = NULL; pa_simple *rds_device = NULL;
pa_sample_spec format; pa_sample_spec format;
@@ -60,13 +63,12 @@ int main(int argc, char **argv) {
pthread_attr_t attr; pthread_attr_t attr;
pthread_t control_pipe_thread; pthread_t control_pipe_thread;
const char *short_opt = "C:h"; const char *short_opt = "C:d:";
struct option long_opt[] = struct option long_opt[] =
{ {
{"ctl", required_argument, NULL, 'C'}, {"ctl", required_argument, NULL, 'C'},
{"device", required_argument, NULL, 'd'},
{"help", no_argument, NULL, 'h'},
{ 0, 0, 0, 0 } { 0, 0, 0, 0 }
}; };
@@ -76,8 +78,10 @@ int main(int argc, char **argv) {
case 'C': case 'C':
memcpy(control_pipe, optarg, 50); memcpy(control_pipe, optarg, 50);
break; break;
case 'd':
case 'h': memcpy(rds_device_name, optarg, 31);
rds_device_name[31] = '\0';
break;
default: default:
show_help(argv[0]); show_help(argv[0]);
return 1; return 1;
@@ -90,18 +94,18 @@ int main(int argc, char **argv) {
signal(SIGTERM, stop); signal(SIGTERM, stop);
format.format = PA_SAMPLE_FLOAT32NE; format.format = PA_SAMPLE_FLOAT32NE;
format.channels = 2; format.channels = STREAMS;
format.rate = RDS_SAMPLE_RATE; format.rate = RDS_SAMPLE_RATE;
buffer.prebuf = 0; buffer.prebuf = 0;
buffer.tlength = NUM_MPX_FRAMES*2; buffer.tlength = NUM_MPX_FRAMES*STREAMS;
buffer.maxlength = NUM_MPX_FRAMES*2; buffer.maxlength = NUM_MPX_FRAMES*STREAMS;
rds_device = pa_simple_new( rds_device = pa_simple_new(
NULL, NULL,
"rds95", "rds95",
PA_STREAM_PLAYBACK, PA_STREAM_PLAYBACK,
RDS_DEVICE, rds_device_name,
"RDS Generator", "RDS Generator",
&format, &format,
NULL, NULL,
@@ -138,12 +142,11 @@ int main(int argc, char **argv) {
int pulse_error; int pulse_error;
float rds_buffer[NUM_MPX_FRAMES*2]; float rds_buffer[NUM_MPX_FRAMES*STREAMS];
while(!stop_rds) { while(!stop_rds) {
for (uint16_t i = 0; i < NUM_MPX_FRAMES*2; i += 2) { for (uint16_t i = 0; i < NUM_MPX_FRAMES*STREAMS; i += STREAMS) {
rds_buffer[i] = get_rds_sample(&rdsModulator, 0); for(uint8_t j = 0; j < STREAMS; j++) rds_buffer[i + j] = get_rds_sample(&rdsModulator, j);
rds_buffer[i+1] = get_rds_sample(&rdsModulator, 1);
} }
if (pa_simple_write(rds_device, rds_buffer, sizeof(rds_buffer), &pulse_error) != 0) { if (pa_simple_write(rds_device, rds_buffer, sizeof(rds_buffer), &pulse_error) != 0) {