0
1
mirror of https://github.com/radio95-rnt/rds95.git synced 2026-02-27 04:43:52 +01:00
Files
rds95/src/rds.c
2025-06-15 11:59:05 +02:00

966 lines
34 KiB
C

#include "common.h"
#include "rds.h"
#include "modulator.h"
#include "lib.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) {
uint16_t out;
if (enc->data[enc->program].af.num_afs) {
if (enc->state[enc->program].af_state == 0) {
out = (AF_CODE_NUM_AFS_BASE + enc->data[enc->program].af.num_afs) << 8 | enc->data[enc->program].af.afs[0];
enc->state[enc->program].af_state++;
} else {
out = enc->data[enc->program].af.afs[enc->state[enc->program].af_state] << 8;
if (enc->data[enc->program].af.afs[enc->state[enc->program].af_state + 1]) out |= enc->data[enc->program].af.afs[enc->state[enc->program].af_state + 1];
else out |= AF_CODE_FILLER;
enc->state[enc->program].af_state += 2;
}
if (enc->state[enc->program].af_state >= enc->data[enc->program].af.num_entries) enc->state[enc->program].af_state = 0;
} else out = AF_CODE_NUM_AFS_BASE << 8 | AF_CODE_FILLER;
return out;
}
static void get_next_af_oda(RDSEncoder* enc, uint16_t* af_group) {
uint8_t offset = 0;
if (enc->state[enc->program].af_oda_state == 0) af_group[0] = (AF_CODE_NUM_AFS_BASE + enc->data[enc->program].af_oda.num_afs);
else {
af_group[0] = enc->data[enc->program].af_oda.afs[enc->state[enc->program].af_oda_state++];
offset++;
}
for(int i = 0; i < 3; i++) {
if (enc->data[enc->program].af_oda.afs[enc->state[enc->program].af_oda_state + offset]) af_group[i + 1] = enc->data[enc->program].af_oda.afs[enc->state[enc->program].af_oda_state + offset];
else af_group[i + 1] = AF_CODE_FILLER;
enc->state[enc->program].af_oda_state++;
}
if (enc->state[enc->program].af_oda_state >= enc->data[enc->program].af_oda.num_entries) enc->state[enc->program].af_oda_state = 0;
}
static uint16_t get_next_af_eon(RDSEncoder* enc, uint8_t eon_index) {
uint16_t out;
if (enc->data[enc->program].eon[eon_index].af.num_afs) {
if (enc->state[enc->program].eon_states[eon_index].af_state == 0) {
out = (AF_CODE_NUM_AFS_BASE + enc->data[enc->program].af.num_afs) << 8 | enc->data[enc->program].eon[eon_index].af.afs[0];
enc->state[enc->program].eon_states[eon_index].af_state += 1;
} else {
out = enc->data[enc->program].eon[eon_index].af.afs[enc->state[enc->program].eon_states[eon_index].af_state] << 8;
if (enc->data[enc->program].eon[eon_index].af.afs[enc->state[enc->program].eon_states[eon_index].af_state + 1]) out |= enc->data[enc->program].eon[eon_index].af.afs[enc->state[enc->program].eon_states[eon_index].af_state + 1];
else {
out |= AF_CODE_FILLER;
enc->state[enc->program].eon_states[eon_index].af_state += 2;
}
}
if (enc->state[enc->program].eon_states[eon_index].af_state >= enc->data[enc->program].eon[eon_index].af.num_entries) enc->state[enc->program].eon_states[eon_index].af_state = 0;
} else out = AF_CODE_NUM_AFS_BASE << 8 | AF_CODE_FILLER;
return out;
}
static void get_rds_ps_group(RDSEncoder* enc, RDSGroup *group) {
if(enc->state[enc->program].ps_csegment == 0) {
if(enc->state[enc->program].ps_update) {
memcpy(enc->state[enc->program].ps_text, enc->data[enc->program].ps, PS_LENGTH);
enc->state[enc->program].ps_update = 0;
}
if(enc->state[enc->program].tps_update) {
memcpy(enc->state[enc->program].tps_text, enc->data[enc->program].tps, PS_LENGTH);
enc->state[enc->program].tps_update = 0;
}
}
group->b |= enc->data[enc->program].ta << 4;
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];
enc->state[enc->program].ps_csegment++;
if (enc->state[enc->program].ps_csegment == 4) enc->state[enc->program].ps_csegment = 0;
}
static void get_rds_fasttuning_group(RDSEncoder* enc, RDSGroup *group) {
group->b |= 15 << 12;
group->b |= 1 << 11;
group->is_type_b = 1;
group->b |= enc->data[enc->program].ta << 4;
if(enc->state[enc->program].fasttuning_state == 0) group->b |= enc->data[enc->program].dpty << 2;
group->b |= enc->state[enc->program].fasttuning_state;
group->d = group->b;
enc->state[enc->program].fasttuning_state++;
if (enc->state[enc->program].fasttuning_state == 4) enc->state[enc->program].fasttuning_state = 0;
}
static void get_rds_rt_group(RDSEncoder* enc, RDSGroup *group) {
if (enc->state[enc->program].rt_update && enc->data[enc->program].rt1_enabled && !enc->data[enc->program].current_rt) {
memcpy(enc->state[enc->program].rt_text, enc->data[enc->program].rt1, RT_LENGTH);
enc->state[enc->program].rt_ab ^= 1;
enc->state[enc->program].rt_update = 0;
enc->state[enc->program].rt_state = 0;
enc->data[enc->program].current_rt = 0;
}
if(enc->state[enc->program].rt2_update && enc->data[enc->program].rt2_enabled && enc->data[enc->program].current_rt) {
memcpy(enc->state[enc->program].rt_text, enc->data[enc->program].rt2, RT_LENGTH);
enc->state[enc->program].rt_ab ^= 1;
enc->state[enc->program].rt2_update = 0;
enc->state[enc->program].rt_state = 0;
enc->data[enc->program].current_rt = 1;
}
uint8_t ab = enc->state[enc->program].rt_ab;
switch (enc->data[enc->program].rt_type)
{
case 0:
ab = 0;
break;
case 1:
ab = (enc->data[enc->program].current_rt == 0) ? 0 : 1;
break;
default: break;
}
group->b |= 2 << 12;
group->b |= ab << 4;
group->b |= enc->state[enc->program].rt_state;
group->c = enc->state[enc->program].rt_text[enc->state[enc->program].rt_state * 4 ] << 8;
group->c |= enc->state[enc->program].rt_text[enc->state[enc->program].rt_state * 4 + 1];
group->d = enc->state[enc->program].rt_text[enc->state[enc->program].rt_state * 4 + 2] << 8;
group->d |= enc->state[enc->program].rt_text[enc->state[enc->program].rt_state * 4 + 3];
uint8_t segments = (enc->data[enc->program].current_rt == 1) ? enc->state[enc->program].rt2_segments : enc->state[enc->program].rt_segments;
enc->state[enc->program].rt_state++;
if (enc->state[enc->program].rt_state == segments) enc->state[enc->program].rt_state = 0;
}
static void get_rdsp_rtp_oda_group(RDSGroup *group) {
group->b |= 3 << 12;
group->b |= 11 << 1;
group->d = ODA_AID_RTPLUS;
}
static void get_rdsp_ertp_oda_group(RDSGroup *group) {
group->b |= 3 << 12;
group->b |= 13 << 1;
group->d = ODA_AID_ERTPLUS;
}
static void get_rdsp_ert_oda_group(RDSGroup *group) {
group->b |= 3 << 12;
group->b |= 12 << 1;
group->c = 1; // UTF-8
group->d = ODA_AID_ERT;
}
static void get_rdsp_oda_af_oda_group(RDSGroup *group) {
group->b |= 3 << 12;
group->b |= 7 << 1;
group->d = ODA_AID_ODAAF;
}
static void get_rds_oda_af_group(RDSEncoder* enc, RDSGroup *group) {
uint16_t af[4];
get_next_af_oda(enc, af);
group->b |= 7 << 12;
for (int i = 0; i < 4; i++) group->b |= ((af[i] >> 8) & 1) << i;
group->c = af[0] & 0xFF;
group->c <<= 8;
group->c |= af[1] & 0xFF;
group->d = af[2] & 0xFF;
group->d <<= 8;
group->d |= af[3] & 0xFF;
}
static void get_rdsp_ct_group(RDSGroup *group, time_t now) {
struct tm *utc, *local_time;
uint8_t l;
uint32_t mjd;
int16_t offset;
utc = gmtime(&now);
l = utc->tm_mon <= 1 ? 1 : 0;
mjd = 14956 + utc->tm_mday +
(uint32_t)((utc->tm_year - l) * 365.25f) +
(uint32_t)((utc->tm_mon + (1+1) + l * 12) * 30.6001f);
group->b |= 4 << 12 | (mjd >> 15);
group->c = (mjd << 1) | (utc->tm_hour >> 4);
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);
}
static void get_rds_ptyn_group(RDSEncoder* enc, RDSGroup *group) {
if (enc->state[enc->program].ptyn_state == 0 && enc->state[enc->program].ptyn_update) {
memcpy(enc->state[enc->program].ptyn_text, enc->data[enc->program].ptyn, PTYN_LENGTH);
enc->state[enc->program].ptyn_ab ^= 1;
enc->state[enc->program].ptyn_update = 0;
}
group->b |= 10 << 12 | enc->state[enc->program].ptyn_state;
group->b |= enc->state[enc->program].ptyn_ab << 4;
group->c = enc->state[enc->program].ptyn_text[enc->state[enc->program].ptyn_state * 4] << 8;
group->c |= enc->state[enc->program].ptyn_text[enc->state[enc->program].ptyn_state * 4 + 1];
group->d = enc->state[enc->program].ptyn_text[enc->state[enc->program].ptyn_state * 4 + 2] << 8;
group->d |= enc->state[enc->program].ptyn_text[enc->state[enc->program].ptyn_state * 4 + 3];
enc->state[enc->program].ptyn_state++;
if (enc->state[enc->program].ptyn_state == 2) enc->state[enc->program].ptyn_state = 0;
}
static void get_rds_lps_group(RDSEncoder* enc, RDSGroup *group) {
if (enc->state[enc->program].lps_state == 0 && enc->state[enc->program].lps_update) {
memcpy(enc->state[enc->program].lps_text, enc->data[enc->program].lps, LPS_LENGTH);
enc->state[enc->program].lps_update = 0;
}
group->b |= 15 << 12 | enc->state[enc->program].lps_state;
group->c = enc->state[enc->program].lps_text[enc->state[enc->program].lps_state * 4] << 8;
group->c |= enc->state[enc->program].lps_text[enc->state[enc->program].lps_state * 4 + 1];
group->d = enc->state[enc->program].lps_text[enc->state[enc->program].lps_state * 4 + 2] << 8;
group->d |= enc->state[enc->program].lps_text[enc->state[enc->program].lps_state * 4 + 3];
enc->state[enc->program].lps_state++;
if (enc->state[enc->program].lps_state == enc->state[enc->program].lps_segments) enc->state[enc->program].lps_state = 0;
}
static void get_rds_ecc_group(RDSEncoder* enc, RDSGroup *group) {
group->b |= 1 << 12;
group->c = enc->state[enc->program].eon_linkage << 15;
group->c |= enc->data[enc->program].ecc;
}
static void get_rds_slcdata_group(RDSEncoder* enc, RDSGroup *group) {
group->b |= 1 << 12;
group->c = enc->state[enc->program].eon_linkage << 15;
group->c |= 0x6000;
group->c |= enc->data[enc->program].slc_data;
}
static void get_rds_rtplus_group(RDSEncoder* enc, RDSGroup *group) {
group->b |= 11 << 12;
group->b |= enc->rtpState[enc->program][0].toggle << 4 | enc->rtpData[enc->program][0].running << 3;
group->b |= (enc->rtpData[enc->program][0].type[0] & 0xf8) >> 3;
group->c = (enc->rtpData[enc->program][0].type[0] & 0x07) << 13;
group->c |= (enc->rtpData[enc->program][0].start[0] & 0x3f) << 7;
group->c |= (enc->rtpData[enc->program][0].len[0] & 0x3f) << 1;
group->c |= (enc->rtpData[enc->program][0].type[1] & 0xe0) >> 5;
group->d = (enc->rtpData[enc->program][0].type[1] & 0x1f) << 11;
group->d |= (enc->rtpData[enc->program][0].start[1] & 0x3f) << 5;
group->d |= enc->rtpData[enc->program][0].len[1] & 0x1f;
}
static void get_rds_ertplus_group(RDSEncoder* enc, RDSGroup *group) {
group->b |= 13 << 12;
group->b |= enc->rtpState[enc->program][1].toggle << 4 | enc->rtpData[enc->program][1].running << 3;
group->b |= (enc->rtpData[enc->program][1].type[0] & 0xf8) >> 3;
group->c = (enc->rtpData[enc->program][1].type[0] & 0x07) << 13;
group->c |= (enc->rtpData[enc->program][1].start[0] & 0x3f) << 7;
group->c |= (enc->rtpData[enc->program][1].len[0] & 0x3f) << 1;
group->c |= (enc->rtpData[enc->program][1].type[1] & 0xe0) >> 5;
group->d = (enc->rtpData[enc->program][1].type[1] & 0x1f) << 11;
group->d |= (enc->rtpData[enc->program][1].start[1] & 0x3f) << 5;
group->d |= enc->rtpData[enc->program][1].len[1] & 0x1f;
}
static void get_rds_eon_group(RDSEncoder* enc, RDSGroup *group) {
RDSEON eon;
eon = enc->data[enc->program].eon[enc->state[enc->program].eon_index];
while(1) {
group->b |= 14 << 12;
group->b |= eon.tp << 4;
switch (enc->state[enc->program].eon_state)
{
case 0:
case 1:
case 2:
case 3:
group->c = eon.ps[enc->state[enc->program].eon_state*2] << 8;
group->c |= eon.ps[enc->state[enc->program].eon_state*2+1];
group->b |= enc->state[enc->program].eon_state;
break;
case 4:
group->c = get_next_af_eon(enc, enc->state[enc->program].eon_index);
group->b |= enc->state[enc->program].eon_state;
break;
case 5: // 13
group->c = eon.pty << 11;
if(eon.tp) group->c |= eon.ta;
group->b |= 13;
break;
case 6: // 15
group->c = eon.data;
group->b |= 15;
break;
}
group->d = eon.pi;
if(enc->state[enc->program].eon_state == 6) {
enc->state[enc->program].eon_index++;
uint8_t i = 0;
while(i < 4 && !enc->data[enc->program].eon[enc->state[enc->program].eon_index].enabled) {
enc->state[enc->program].eon_index++;
if(enc->state[enc->program].eon_index == 4) {
enc->state[enc->program].eon_index = 0;
}
eon = enc->data[enc->program].eon[enc->state[enc->program].eon_index];
i++;
}
enc->state[enc->program].eon_state = 0;
} else {
enc->state[enc->program].eon_state++;
break;
}
}
}
static void get_rds_ert_group(RDSEncoder* enc, RDSGroup *group) {
if (enc->state[enc->program].ert_state == 0 && enc->state[enc->program].ert_update) {
memcpy(enc->state[enc->program].ert_text, enc->data[enc->program].ert, ERT_LENGTH);
enc->state[enc->program].ert_update = 0;
}
group->b |= 12 << 12 | (enc->state[enc->program].ert_state & 31);
group->c = enc->state[enc->program].ert_text[enc->state[enc->program].ert_state * 4] << 8;
group->c |= enc->state[enc->program].ert_text[enc->state[enc->program].ert_state * 4 + 1];
group->d = enc->state[enc->program].ert_text[enc->state[enc->program].ert_state * 4 + 2] << 8;
group->d |= enc->state[enc->program].ert_text[enc->state[enc->program].ert_state * 4 + 3];
enc->state[enc->program].ert_state++;
if (enc->state[enc->program].ert_state == enc->state[enc->program].ert_segments) enc->state[enc->program].ert_state = 0;
}
static uint8_t get_rds_custom_groups(RDSEncoder* enc, RDSGroup *group) {
if(enc->state[enc->program].custom_group[0] == 1) {
enc->state[enc->program].custom_group[0] = 0;
group->a = enc->data[enc->program].pi;
group->b = enc->state[enc->program].custom_group[1];
group->c = enc->state[enc->program].custom_group[2];
group->d = enc->state[enc->program].custom_group[3];
group->is_type_b = (IS_TYPE_B(group->b) != 0);
return 1;
}
return 0;
}
static uint8_t get_rds_custom_groups2(RDSEncoder* enc, RDSGroup *group) {
if(enc->state[enc->program].custom_group2[0] == 1) {
enc->state[enc->program].custom_group2[0] = 0;
group->a = enc->state[enc->program].custom_group2[1];
group->b = enc->state[enc->program].custom_group2[2];
group->c = enc->state[enc->program].custom_group2[3];
group->d = enc->state[enc->program].custom_group2[4];
group->is_type_b = (group->a == 0 && IS_TYPE_B(group->b));
return 1;
}
return 0;
}
static void get_rds_sequence_group(RDSEncoder* enc, RDSGroup *group, char* grp, uint8_t stream) {
uint8_t udg_idx;
uint8_t ps_seq_idx = (stream == 0) ? 1 : 3;
uint8_t grp_seq_idx = (stream == 0) ? 0 : 2;
switch (*grp)
{
default:
case '0':
if(enc->state[enc->program].grp_seq_idx[ps_seq_idx] < 4) enc->state[enc->program].grp_seq_idx[grp_seq_idx]--;
else enc->state[enc->program].grp_seq_idx[ps_seq_idx] = 0;
enc->state[enc->program].grp_seq_idx[ps_seq_idx]++;
get_rds_ps_group(enc, group);
break;
case '1':
if(enc->state[enc->program].data_ecc == 0 && enc->data[enc->program].slc_data != 0) get_rds_slcdata_group(enc, group);
else get_rds_ecc_group(enc, group);
enc->state[enc->program].data_ecc ^= 1;
break;
case '2':
get_rds_rt_group(enc, group);
break;
case 'A':
get_rds_ptyn_group(enc, group);
break;
case 'E':
get_rds_eon_group(enc, group);
break;
case 'X':
if(stream != 0) {
udg_idx = enc->state[enc->program].udg_idxs_rds2[0];
group->a = enc->data[enc->program].udg1_rds2[udg_idx][0];
group->b = enc->data[enc->program].udg1_rds2[udg_idx][1];
group->c = enc->data[enc->program].udg1_rds2[udg_idx][2];
group->d = enc->data[enc->program].udg1_rds2[udg_idx][3];
enc->state[enc->program].udg_idxs_rds2[0]++;
if(enc->state[enc->program].udg_idxs_rds2[0] == enc->data[enc->program].udg1_len_rds2) enc->state[enc->program].udg_idxs_rds2[0] = 0;
group->is_type_b = (group->a == 0 && IS_TYPE_B(group->b));
break;
}
udg_idx = enc->state[enc->program].udg_idxs[0];
group->b = enc->data[enc->program].udg1[udg_idx][0];
group->c = enc->data[enc->program].udg1[udg_idx][1];
group->d = enc->data[enc->program].udg1[udg_idx][2];
enc->state[enc->program].udg_idxs[0]++;
if(enc->state[enc->program].udg_idxs[0] == enc->data[enc->program].udg1_len) enc->state[enc->program].udg_idxs[0] = 0;
group->is_type_b = (IS_TYPE_B(group->b) != 0);
break;
case 'Y':
if(stream != 0) {
udg_idx = enc->state[enc->program].udg_idxs_rds2[1];
group->a = enc->data[enc->program].udg2_rds2[udg_idx][0];
group->b = enc->data[enc->program].udg2_rds2[udg_idx][1];
group->c = enc->data[enc->program].udg2_rds2[udg_idx][2];
group->d = enc->data[enc->program].udg2_rds2[udg_idx][3];
enc->state[enc->program].udg_idxs_rds2[1]++;
if(enc->state[enc->program].udg_idxs_rds2[1] == enc->data[enc->program].udg2_len_rds2) enc->state[enc->program].udg_idxs_rds2[1] = 0;
group->is_type_b = (group->a == 0 && IS_TYPE_B(group->b));
break;
}
udg_idx = enc->state[enc->program].udg_idxs[1];
group->b = enc->data[enc->program].udg2[udg_idx][0];
group->c = enc->data[enc->program].udg2[udg_idx][1];
group->d = enc->data[enc->program].udg2[udg_idx][2];
enc->state[enc->program].udg_idxs[1]++;
if(enc->state[enc->program].udg_idxs[1] == enc->data[enc->program].udg2_len) enc->state[enc->program].udg_idxs[1] = 0;
group->is_type_b = (IS_TYPE_B(group->b) != 0);
break;
case 'R':
if(enc->state[enc->program].rtp_oda == 0) get_rds_rtplus_group(enc, group);
else get_rdsp_rtp_oda_group(group);
enc->state[enc->program].rtp_oda ^= 1;
break;
case 'P':
if(enc->state[enc->program].ert_oda == 0) get_rds_ertplus_group(enc, group);
else get_rdsp_ertp_oda_group(group);
enc->state[enc->program].ert_oda ^= 1;
break;
case 'S':
if(enc->state[enc->program].ert_oda == 0) get_rds_ert_group(enc, group);
else get_rdsp_ert_oda_group(group);
enc->state[enc->program].ert_oda ^= 1;
break;
case 'F':
get_rds_lps_group(enc, group);
break;
case 'T':
get_rds_fasttuning_group(enc, group);
break;
case 'U':
if(enc->state[enc->program].af_oda == 0) get_rds_oda_af_group(enc, group);
else get_rdsp_oda_af_oda_group(group);
enc->state[enc->program].af_oda ^= 1;
break;
}
}
static uint8_t check_rds_good_group(RDSEncoder* enc, char* grp) {
uint8_t good_group = 0;
if(*grp == '0') good_group = 1;
if(*grp == '1' && (enc->data[enc->program].ecc != 0 || enc->data[enc->program].slc_data != 0)) good_group = 1;
if(*grp == '2' && (enc->data[enc->program].rt1_enabled || enc->data[enc->program].rt2_enabled)) good_group = 1;
if(*grp == 'A' && enc->data[enc->program].ptyn_enabled) good_group = 1;
if(*grp == 'E') {
for (int i = 0; i < 4; i++) {
if (enc->data[enc->program].eon[i].enabled) {
good_group = 1;
break;
}
}
}
if(*grp == 'X' && enc->data[enc->program].udg1_len != 0) good_group = 1;
if(*grp == 'Y' && enc->data[enc->program].udg2_len != 0) good_group = 1;
if(*grp == 'R' && enc->rtpData[enc->program][0].enabled) good_group = 1;
if(*grp == 'P' && enc->rtpData[enc->program][1].enabled && (_strnlen(enc->data[enc->program].ert, 65) < 64)) good_group = 1;
if(*grp == 'S' && enc->data[enc->program].ert[0] != '\0') good_group = 1;
if(*grp == 'F' && enc->data[enc->program].lps[0] != '\0') good_group = 1;
if(*grp == 'T') good_group = 1;
if(*grp == 'U' && enc->data[enc->program].af_oda.num_afs) good_group = 1;
return good_group;
}
static void get_rds_group(RDSEncoder* enc, RDSGroup *group, uint8_t stream) {
group->a = enc->data[enc->program].pi;
group->b = 0;
group->c = 0;
group->d = 0;
struct tm *utc;
time_t now;
time(&now);
utc = gmtime(&now);
if (utc->tm_min != enc->state[enc->program].last_minute) {
enc->state[enc->program].last_minute = utc->tm_min;
uint8_t eon_has_ta = 0;
for (int i = 0; i < 4; i++) {
if (enc->data[enc->program].eon[i].enabled && enc->data[enc->program].eon[i].ta) {
eon_has_ta = 1;
break;
}
}
if(enc->data[enc->program].tp && enc->data[enc->program].ta && enc->state[enc->program].ta_timeout && !eon_has_ta) {
enc->state[enc->program].ta_timeout--;
if(enc->state[enc->program].ta_timeout == 0) {
enc->data[enc->program].ta = 0;
enc->state[enc->program].ta_timeout_state = enc->state[enc->program].ta_timeout;
};
}
if(enc->data[enc->program].rt1_enabled && enc->data[enc->program].rt2_enabled && enc->state[enc->program].rt_switching_period_state) {
enc->state[enc->program].rt_switching_period_state--;
if(enc->state[enc->program].rt_switching_period_state == 0) {
enc->data[enc->program].current_rt ^= 1;
if (enc->data[enc->program].current_rt == 1) memcpy(enc->state[enc->program].rt_text, enc->data[enc->program].rt2, RT_LENGTH);
else memcpy(enc->state[enc->program].rt_text, enc->data[enc->program].rt1, RT_LENGTH);
enc->state[enc->program].rt_state = 0;
enc->state[enc->program].rt_switching_period_state = enc->data[enc->program].rt_switching_period;
}
}
if(enc->data[enc->program].rt1_enabled && enc->data[enc->program].current_rt == 0 && enc->state[enc->program].rt_text_timeout_state) {
enc->state[enc->program].rt_text_timeout_state--;
if(enc->state[enc->program].rt_text_timeout_state == 0) {
enc->state[enc->program].rt_update = 1;
memcpy(enc->state[enc->program].rt_text, enc->data[enc->program].default_rt, RT_LENGTH);
}
}
if(enc->data[enc->program].ct && stream == 0) {
get_rdsp_ct_group(group, now);
goto group_coded;
}
}
uint8_t good_group = 0;
uint8_t cant_find_group = 0;
uint8_t grp_sqc_idx = 0;
char grp;
if(stream != 0) {
group->a = 0;
if(get_rds_custom_groups2(enc, group)) goto group_coded_rds2;
if(enc->encoder_data.rds2_mode == 0) {
group->b = enc->state[enc->program].last_stream0_group[0];
group->c = enc->state[enc->program].last_stream0_group[1];
group->d = enc->state[enc->program].last_stream0_group[2];
group->is_type_b = enc->state[enc->program].last_stream0_group_type_b;
goto group_coded_rds2;
} else if(enc->encoder_data.rds2_mode == 1) {
while(good_group == 0) {
grp_sqc_idx = enc->state[enc->program].grp_seq_idx[2];
if(enc->data[enc->program].grp_sqc_rds2[grp_sqc_idx] == '\0') {
enc->state[enc->program].grp_seq_idx[2] = 0;
grp_sqc_idx = 0;
}
grp = enc->data[enc->program].grp_sqc_rds2[grp_sqc_idx];
good_group = check_rds_good_group(enc, &grp);
if(!good_group) cant_find_group++;
else cant_find_group = 0;
if(!good_group && cant_find_group == 23) {
cant_find_group = 0;
break;
}
enc->state[enc->program].grp_seq_idx[2]++;
}
if(!good_group) grp = '0';
get_rds_sequence_group(enc, group, &grp, stream);
goto group_coded_rds2;
}
}
if(get_rds_custom_groups(enc, group)) goto group_coded;
while(good_group == 0) {
grp_sqc_idx = enc->state[enc->program].grp_seq_idx[0];
if(enc->data[enc->program].grp_sqc[grp_sqc_idx] == '\0') {
enc->state[enc->program].grp_seq_idx[0] = 0;
grp_sqc_idx = 0;
}
grp = enc->data[enc->program].grp_sqc[grp_sqc_idx];
good_group = check_rds_good_group(enc, &grp);
if(!good_group) cant_find_group++;
else cant_find_group = 0;
if(!good_group && cant_find_group == 23) {
cant_find_group = 0;
break;
}
enc->state[enc->program].grp_seq_idx[0]++;
}
if(!good_group) grp = '0';
get_rds_sequence_group(enc, group, &grp, stream);
group_coded_rds2:
if (group->a == 0 && stream != 0) {
if(group->is_type_b) group->c = enc->data[enc->program].pi;
group->b |= enc->data[enc->program].tp << 10;
group->b |= enc->data[enc->program].pty << 5;
} else if(stream == 0) goto group_coded;
return;
group_coded:
if(stream != 0) goto group_coded_rds2;
group->b |= enc->data[enc->program].tp << 10;
group->b |= enc->data[enc->program].pty << 5;
if(group->is_type_b) group->c = enc->data[enc->program].pi;
enc->state[enc->program].last_stream0_group[0] = group->b;
enc->state[enc->program].last_stream0_group[1] = group->c;
enc->state[enc->program].last_stream0_group[2] = group->d;
enc->state[enc->program].last_stream0_group_type_b = group->is_type_b;
return;
}
void get_rds_bits(RDSEncoder* enc, uint8_t *bits, uint8_t stream) {
RDSGroup group;
get_rds_group(enc, &group, stream);
add_checkwords(&group, bits);
}
void reset_rds_state(RDSEncoder* enc, uint8_t program) {
RDSEncoder tempCoder;
tempCoder.program = program;
memset(&(tempCoder.state[program]), 0, sizeof(RDSState));
memset(&(tempCoder.rtpState[program]), 0, sizeof(RDSRTPlusState)*2);
tempCoder.state[program].rt_ab = 1;
tempCoder.state[program].ptyn_ab = 1;
set_rds_rt1(&tempCoder, enc->data[program].rt1);
set_rds_rt2(&tempCoder, enc->data[program].rt2);
set_rds_ert(&tempCoder, enc->data[program].ert);
set_rds_ps(&tempCoder, enc->data[program].ps);
set_rds_tps(&tempCoder, enc->data[program].tps);
set_rds_ptyn(&tempCoder, enc->data[program].ptyn);
set_rds_lps(&tempCoder, enc->data[program].lps);
set_rds_grpseq(&tempCoder, enc->data[program].grp_sqc);
set_rds_grpseq2(&tempCoder, enc->data[program].grp_sqc_rds2);
struct tm *utc;
time_t now;
time(&now);
utc = gmtime(&now);
tempCoder.state[program].last_minute = utc->tm_min;
for(int i = 0; i < 4; i++) tempCoder.data[program].eon[i].ta = 0;
memcpy(&(enc->state[program]), &(tempCoder.state[program]), sizeof(RDSState));
memcpy(&(enc->rtpState[program]), &(tempCoder.rtpState[program]), sizeof(RDSRTPlusState));
}
void set_rds_defaults(RDSEncoder* enc, uint8_t program) {
memset(&(enc->data[program]), 0, sizeof(RDSData));
memset(&(enc->rtpData[program]), 0, sizeof(RDSRTPlusData)*2);
memset(&(enc->encoder_data), 0, sizeof(RDSEncoderData));
enc->encoder_data.encoder_addr[0] = 255;
enc->encoder_data.encoder_addr[1] = 255;
enc->data[program].ct = 1;
strcpy((char *)enc->data[program].grp_sqc, DEFAULT_GRPSQC);
enc->data[program].tp = 1;
enc->data[program].pi = 0xFFFF;
strcpy((char *)enc->data[program].ps, "* RDS * ");
enc->data[program].rt1_enabled = 1;
memset(enc->data[program].rt1, ' ', 59);
enc->data[program].rt_type = 2;
reset_rds_state(enc, program);
enc->encoder_data.ascii_data.expected_encoder_addr = 255; // Unknown
}
void init_rds_encoder(RDSEncoder* enc) {
for(int i = 0; i < PROGRAMS; i++) set_rds_defaults(enc, i);
if (isFileSaved()) loadFromFile(enc);
else saveToFile(enc, "ALL");
for(int i = 0; i < PROGRAMS; i++) reset_rds_state(enc, i);
}
void set_rds_rt1(RDSEncoder* enc, char *rt1) {
uint8_t i = 0, len = 0;
enc->state[enc->program].rt_text_timeout_state = enc->data[enc->program].rt_text_timeout;
enc->state[enc->program].rt_update = 1;
memset(enc->data[enc->program].rt1, ' ', RT_LENGTH);
while (*rt1 != 0 && len < RT_LENGTH) enc->data[enc->program].rt1[len++] = *rt1++;
while (len > 0 && enc->data[enc->program].rt1[len - 1] == ' ') len--;
if (len < RT_LENGTH) {
enc->state[enc->program].rt_segments = 0;
enc->data[enc->program].rt1[len++] = '\r';
while (i < len) {
i += 4;
enc->state[enc->program].rt_segments++;
}
} else enc->state[enc->program].rt_segments = 16;
}
void set_rds_rt2(RDSEncoder* enc, char *rt2) {
uint8_t i = 0, len = 0;
enc->state[enc->program].rt2_update = 1;
memset(enc->data[enc->program].rt2, ' ', RT_LENGTH);
while (*rt2 != 0 && len < RT_LENGTH) enc->data[enc->program].rt2[len++] = *rt2++;
while (len > 0 && enc->data[enc->program].rt2[len - 1] == ' ') len--;
if (len < RT_LENGTH) {
enc->state[enc->program].rt2_segments = 0;
enc->data[enc->program].rt2[len++] = '\r';
while (i < len) {
i += 4;
enc->state[enc->program].rt2_segments++;
}
} else enc->state[enc->program].rt2_segments = 16;
}
void set_rds_ps(RDSEncoder* enc, char *ps) {
uint8_t len = 0;
enc->state[enc->program].ps_update = 1;
memset(enc->data[enc->program].ps, ' ', PS_LENGTH);
while (*ps != 0 && len < PS_LENGTH) enc->data[enc->program].ps[len++] = *ps++;
}
void set_rds_tps(RDSEncoder* enc, char *tps) {
uint8_t len = 0;
enc->state[enc->program].tps_update = 1;
if(tps[0] == '\0') {
memset(enc->data[enc->program].tps, 0, PS_LENGTH);
return;
}
memset(enc->data[enc->program].tps, ' ', PS_LENGTH);
while (*tps != 0 && len < PS_LENGTH) enc->data[enc->program].tps[len++] = *tps++;
}
void set_rds_lps(RDSEncoder* enc, char *lps) {
uint8_t i = 0, len = 0;
enc->state[enc->program].lps_update = 1;
if(lps[0] == '\0') {
memset(enc->data[enc->program].lps, 0, LPS_LENGTH);
return;
}
memset(enc->data[enc->program].lps, ' ', LPS_LENGTH);
while (*lps != 0 && len < LPS_LENGTH) enc->data[enc->program].lps[len++] = *lps++;
if (len < LPS_LENGTH) {
enc->state[enc->program].lps_segments = 0;
enc->data[enc->program].lps[len++] = '\r';
while (i < len) {
i += 4;
enc->state[enc->program].lps_segments++;
}
} else enc->state[enc->program].lps_segments = 8;
}
void set_rds_ert(RDSEncoder* enc, char *ert) {
uint8_t i = 0, len = 0;
enc->state[enc->program].ert_update = 1;
memset(enc->data[enc->program].ert, ' ', ERT_LENGTH);
while (*ert != 0 && len < ERT_LENGTH) enc->data[enc->program].ert[len++] = *ert++;
while (len > 0 && enc->data[enc->program].ert[len - 1] == ' ') len--;
if (len < ERT_LENGTH) {
enc->state[enc->program].ert_segments = 0;
enc->data[enc->program].ert[len++] = '\r';
while (i < len) {
i += 4;
enc->state[enc->program].ert_segments++;
}
} else enc->state[enc->program].ert_segments = 32;
}
inline void set_rds_rtplus_tags(RDSEncoder* enc, uint8_t *tags) {
enc->rtpData[enc->program][0].type[0] = tags[0] & 0x3f;
enc->rtpData[enc->program][0].start[0] = tags[1] & 0x3f;
enc->rtpData[enc->program][0].len[0] = tags[2] & 0x3f;
enc->rtpData[enc->program][0].type[1] = tags[3] & 0x3f;
enc->rtpData[enc->program][0].start[1] = tags[4] & 0x3f;
enc->rtpData[enc->program][0].len[1] = tags[5] & 0x1f;
enc->rtpState[enc->program][0].toggle ^= 1;
enc->rtpData[enc->program][0].running = 1;
enc->rtpData[enc->program][0].enabled = 1;
}
inline void set_rds_ertplus_tags(RDSEncoder* enc, uint8_t *tags) {
enc->rtpData[enc->program][1].type[0] = tags[0] & 0x3f;
enc->rtpData[enc->program][1].start[0] = tags[1] & 0x3f;
enc->rtpData[enc->program][1].len[0] = tags[2] & 0x3f;
enc->rtpData[enc->program][1].type[1] = tags[3] & 0x3f;
enc->rtpData[enc->program][1].start[1] = tags[4] & 0x3f;
enc->rtpData[enc->program][1].len[1] = tags[5] & 0x1f;
enc->rtpState[enc->program][1].toggle ^= 1;
enc->rtpData[enc->program][1].running = 1;
enc->rtpData[enc->program][1].enabled = 1;
}
void set_rds_ptyn(RDSEncoder* enc, char *ptyn) {
uint8_t len = 0;
enc->state[enc->program].ptyn_update = 1;
if(ptyn[0] == '\0') {
memset(enc->data[enc->program].ptyn, 0, PTYN_LENGTH);
return;
}
memset(enc->data[enc->program].ptyn, ' ', PTYN_LENGTH);
while (*ptyn != 0 && len < PTYN_LENGTH) enc->data[enc->program].ptyn[len++] = *ptyn++;
}
void set_rds_grpseq(RDSEncoder* enc, char *grpseq) {
uint8_t len = 0;
if(grpseq[0] == '\0') {
while (DEFAULT_GRPSQC[len] != 0 && len < 24) {
enc->data[enc->program].grp_sqc[len] = DEFAULT_GRPSQC[len];
len++;
}
return;
}
memset(enc->data[enc->program].grp_sqc, 0, 24);
while (*grpseq != 0 && len < 24) enc->data[enc->program].grp_sqc[len++] = *grpseq++;
}
void set_rds_grpseq2(RDSEncoder* enc, char *grpseq2) {
uint8_t len = 0;
if(grpseq2[0] == '\0') {
memset(enc->data[enc->program].grp_sqc_rds2, 0, 24);
memcpy(enc->data[enc->program].grp_sqc_rds2, enc->data[enc->program].grp_sqc, 24);
return;
}
memset(enc->data[enc->program].grp_sqc_rds2, 0, 24);
while (*grpseq2 != 0 && len < 24) enc->data[enc->program].grp_sqc_rds2[len++] = *grpseq2++;
}