0
1
mirror of https://github.com/radio95-rnt/rds95.git synced 2026-02-26 20:33:53 +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;
if(STREAMS > 0) rdsMod->data[1].symbol_shift = FILTER_SIZE / 2;
if(STREAMS > 0) rdsMod->data[1].symbol_shift = M_PI;
if(modulatorsaved()) {
Modulator_loadFromFile(&rdsMod->params);
} 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;
}
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
uint8_t tooutput = rdsMod->params.rdsgen > stream ? 1 : 0;

View File

@@ -10,34 +10,35 @@ void saveToFile(RDSEncoder *enc, const char *option) {
RDSEncoder tempEncoder;
FILE *file = fopen(encoderPath, "rb");
if (file != NULL) {
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);
tempEncoder.program = enc->program;
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.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;
} else return;
tempEncoder.program = enc->program;
RDSEncoderFile rdsEncoderfile;
rdsEncoderfile.file_starter = 225;
rdsEncoderfile.file_middle = 160;
rdsEncoderfile.file_ender = 95;
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.program = tempEncoder.program;
rdsEncoderfile.crc = crc16_ccitt((char*)&rdsEncoderfile, offsetof(RDSEncoderFile, crc));
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 == NULL) {
if (!file) {
perror("Error opening file");
return;
}
@@ -51,20 +52,19 @@ void loadFromFile(RDSEncoder *enc) {
RDSEncoderFile rdsEncoderfile;
FILE *file = fopen(encoderPath, "rb");
if (file == NULL) {
if (!file) {
perror("Error opening file");
return;
}
fread(&rdsEncoderfile, sizeof(RDSEncoderFile), 1, file);
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;
}
uint16_t calculated_crc = crc16_ccitt((char*)&rdsEncoderfile, offsetof(RDSEncoderFile, crc));
if (calculated_crc != rdsEncoderfile.crc) {
if (crc16_ccitt((char*)&rdsEncoderfile, offsetof(RDSEncoderFile, crc)) != rdsEncoderfile.crc) {
fprintf(stderr, "[RDSENCODER-FILE] CRC mismatch! Data may be corrupted\n");
return;
}
@@ -77,15 +77,13 @@ void loadFromFile(RDSEncoder *enc) {
enc->program = rdsEncoderfile.program;
}
int rdssaved() {
int isFileSaved() {
char encoderPath[128];
snprintf(encoderPath, sizeof(encoderPath), "%s/.rdsEncoder", getenv("HOME"));
FILE *file = fopen(encoderPath, "rb");
if (file) {
fclose(file);
return 1;
}
return 0;
if(!file) return 0;
fclose(file);
return 1;
}
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;
group->b |= enc->state[enc->program].ps_csegment;
group->c = get_next_af(enc);
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];
} 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];
}
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];
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++;
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;
local_time = localtime(&now);
offset = local_time->__tm_gmtoff / (30 * 60);
if (offset < 0) group->d |= 1 << 5;
group->d |= abs(offset);
@@ -806,7 +800,7 @@ void set_rds_defaults(RDSEncoder* enc, uint8_t program) {
void init_rds_encoder(RDSEncoder* enc) {
for(int i = 0; i < PROGRAMS; i++) set_rds_defaults(enc, i);
if (rdssaved()) loadFromFile(enc);
if (isFileSaved()) loadFromFile(enc);
else saveToFile(enc, "ALL");
for(int i = 0; i < PROGRAMS; i++) reset_rds_state(enc, i);

View File

@@ -11,8 +11,6 @@
#define GROUP_LENGTH 4
#define BITS_PER_GROUP (GROUP_LENGTH * (BLOCK_SIZE + POLY_DEG))
#define RDS_SAMPLE_RATE 4750
#define FILTER_SIZE 4 // RDS_SAMPLE_RATE/1187.5, or the inverse i dont remember
#define STREAMS 2
#define RT_LENGTH 64
@@ -238,7 +236,7 @@ typedef struct
void saveToFile(RDSEncoder *emp, const char *option);
void loadFromFile(RDSEncoder *emp);
int rdssaved();
int isFileSaved();
void reset_rds_state(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"
"Usage: %s [options]\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",
name
name,
RDS_DEVICE
);
}
@@ -52,6 +54,7 @@ int main(int argc, char **argv) {
show_version();
char control_pipe[51] = "\0";
char rds_device_name[32] = RDS_DEVICE;
pa_simple *rds_device = NULL;
pa_sample_spec format;
@@ -60,13 +63,12 @@ int main(int argc, char **argv) {
pthread_attr_t attr;
pthread_t control_pipe_thread;
const char *short_opt = "C:h";
const char *short_opt = "C:d:";
struct option long_opt[] =
{
{"ctl", required_argument, NULL, 'C'},
{"help", no_argument, NULL, 'h'},
{"device", required_argument, NULL, 'd'},
{ 0, 0, 0, 0 }
};
@@ -76,8 +78,10 @@ int main(int argc, char **argv) {
case 'C':
memcpy(control_pipe, optarg, 50);
break;
case 'h':
case 'd':
memcpy(rds_device_name, optarg, 31);
rds_device_name[31] = '\0';
break;
default:
show_help(argv[0]);
return 1;
@@ -90,18 +94,18 @@ int main(int argc, char **argv) {
signal(SIGTERM, stop);
format.format = PA_SAMPLE_FLOAT32NE;
format.channels = 2;
format.channels = STREAMS;
format.rate = RDS_SAMPLE_RATE;
buffer.prebuf = 0;
buffer.tlength = NUM_MPX_FRAMES*2;
buffer.maxlength = NUM_MPX_FRAMES*2;
buffer.tlength = NUM_MPX_FRAMES*STREAMS;
buffer.maxlength = NUM_MPX_FRAMES*STREAMS;
rds_device = pa_simple_new(
NULL,
"rds95",
PA_STREAM_PLAYBACK,
RDS_DEVICE,
rds_device_name,
"RDS Generator",
&format,
NULL,
@@ -138,12 +142,11 @@ int main(int argc, char **argv) {
int pulse_error;
float rds_buffer[NUM_MPX_FRAMES*2];
float rds_buffer[NUM_MPX_FRAMES*STREAMS];
while(!stop_rds) {
for (uint16_t i = 0; i < NUM_MPX_FRAMES*2; i += 2) {
rds_buffer[i] = get_rds_sample(&rdsModulator, 0);
rds_buffer[i+1] = get_rds_sample(&rdsModulator, 1);
for (uint16_t i = 0; i < NUM_MPX_FRAMES*STREAMS; i += STREAMS) {
for(uint8_t j = 0; j < STREAMS; j++) rds_buffer[i + j] = get_rds_sample(&rdsModulator, j);
}
if (pa_simple_write(rds_device, rds_buffer, sizeof(rds_buffer), &pulse_error) != 0) {