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:
@@ -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;
|
||||||
|
|||||||
66
src/rds.c
66
src/rds.c
@@ -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);
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
33
src/rds95.c
33
src/rds95.c
@@ -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) {
|
||||||
|
|||||||
Reference in New Issue
Block a user