mirror of
https://github.com/radio95-rnt/rds95.git
synced 2026-02-27 04:43:52 +01:00
add ert
This commit is contained in:
3
doc.md
3
doc.md
@@ -143,6 +143,7 @@ Sets the group sequence for stream0, available groups:
|
|||||||
- X: UDG1
|
- X: UDG1
|
||||||
- Y: UDG2
|
- Y: UDG2
|
||||||
- R: RT+
|
- R: RT+
|
||||||
|
- S: ERT
|
||||||
- 3: ODA
|
- 3: ODA
|
||||||
- F: LPS
|
- F: LPS
|
||||||
|
|
||||||
@@ -158,4 +159,4 @@ Sets the rds generator level:
|
|||||||
|
|
||||||
`RDSGEN=1`
|
`RDSGEN=1`
|
||||||
|
|
||||||
TODO: Rest of the cmds
|
TODO: Rest of the cmds
|
||||||
|
|||||||
72
src/rds.c
72
src/rds.c
@@ -51,7 +51,6 @@ void saveToFile(RDSEncoder *emp, const char *option) {
|
|||||||
} else if (strcmp(option, "GRPSEQ") == 0) {
|
} else if (strcmp(option, "GRPSEQ") == 0) {
|
||||||
memcpy(tempEncoder.data[emp->program].grp_sqc, emp->data[emp->program].grp_sqc, sizeof(emp->data[emp->program].grp_sqc));
|
memcpy(tempEncoder.data[emp->program].grp_sqc, emp->data[emp->program].grp_sqc, sizeof(emp->data[emp->program].grp_sqc));
|
||||||
} else if (strcmp(option, "RTP") == 0) {
|
} else if (strcmp(option, "RTP") == 0) {
|
||||||
tempEncoder.rtpData[emp->program].group = emp->rtpData[emp->program].group;
|
|
||||||
memcpy(tempEncoder.rtpData[emp->program].len, emp->rtpData[emp->program].len, sizeof(emp->rtpData[emp->program].len));
|
memcpy(tempEncoder.rtpData[emp->program].len, emp->rtpData[emp->program].len, sizeof(emp->rtpData[emp->program].len));
|
||||||
memcpy(tempEncoder.rtpData[emp->program].start, emp->rtpData[emp->program].start, sizeof(emp->rtpData[emp->program].start));
|
memcpy(tempEncoder.rtpData[emp->program].start, emp->rtpData[emp->program].start, sizeof(emp->rtpData[emp->program].start));
|
||||||
memcpy(tempEncoder.rtpData[emp->program].type, emp->rtpData[emp->program].type, sizeof(emp->rtpData[emp->program].type));
|
memcpy(tempEncoder.rtpData[emp->program].type, emp->rtpData[emp->program].type, sizeof(emp->rtpData[emp->program].type));
|
||||||
@@ -274,11 +273,18 @@ static void get_rds_oda_group(RDSEncoder* enc, uint16_t *blocks, uint8_t stream)
|
|||||||
static void get_rds_rtp_oda_group(RDSEncoder* enc, uint16_t *blocks) {
|
static void get_rds_rtp_oda_group(RDSEncoder* enc, uint16_t *blocks) {
|
||||||
blocks[1] |= 3 << 12;
|
blocks[1] |= 3 << 12;
|
||||||
|
|
||||||
blocks[1] |= GET_GROUP_TYPE(enc->rtpData[enc->program].group) << 1;
|
blocks[1] |= 11 << 1;
|
||||||
blocks[1] |= GET_GROUP_VER(enc->rtpData[enc->program].group);
|
|
||||||
blocks[3] = ODA_AID_RTPLUS;
|
blocks[3] = ODA_AID_RTPLUS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void get_rds_ert_oda_group(RDSEncoder* enc, uint16_t *blocks) {
|
||||||
|
blocks[1] |= 3 << 12;
|
||||||
|
|
||||||
|
blocks[1] |= 12 << 1;
|
||||||
|
blocks[2] = 1; // UTF-8
|
||||||
|
blocks[3] = ODA_AID_ERT;
|
||||||
|
}
|
||||||
|
|
||||||
static void get_rds_ct_group(RDSEncoder* enc, uint16_t *blocks) {
|
static void get_rds_ct_group(RDSEncoder* enc, uint16_t *blocks) {
|
||||||
(void)enc;
|
(void)enc;
|
||||||
struct tm *utc, *local_time;
|
struct tm *utc, *local_time;
|
||||||
@@ -409,6 +415,22 @@ get_eon:
|
|||||||
enc->state[enc->program].eon_state++;
|
enc->state[enc->program].eon_state++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void get_rds_ert_group(RDSEncoder* enc, uint16_t *blocks) {
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
blocks[1] |= 12 << 12 | (enc->state[enc->program].ert_state & 31);
|
||||||
|
blocks[2] = enc->state[enc->program].ert_text[enc->state[enc->program].ert_state * 4 ] << 8;
|
||||||
|
blocks[2] |= enc->state[enc->program].ert_text[enc->state[enc->program].ert_state * 4 + 1];
|
||||||
|
blocks[3] = enc->state[enc->program].ert_text[enc->state[enc->program].ert_state * 4 + 2] << 8;
|
||||||
|
blocks[3] |= 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_state) enc->state[enc->program].ert_state = 0;
|
||||||
|
}
|
||||||
// #endregion
|
// #endregion
|
||||||
|
|
||||||
static uint8_t get_rds_custom_groups(RDSEncoder* enc, uint16_t *blocks) {
|
static uint8_t get_rds_custom_groups(RDSEncoder* enc, uint16_t *blocks) {
|
||||||
@@ -480,6 +502,14 @@ static void get_rds_sequence_group(RDSEncoder* enc, uint16_t *blocks, char* grp,
|
|||||||
}
|
}
|
||||||
enc->state[enc->program].rtp_oda ^= 1;
|
enc->state[enc->program].rtp_oda ^= 1;
|
||||||
goto group_coded;
|
goto group_coded;
|
||||||
|
case 'S':
|
||||||
|
if(enc->state[enc->program].ert_oda == 0) {
|
||||||
|
get_rds_ert_group(enc, blocks);
|
||||||
|
} else {
|
||||||
|
get_rds_ert_oda_group(enc, blocks);
|
||||||
|
}
|
||||||
|
enc->state[enc->program].ert_oda ^= 1;
|
||||||
|
goto group_coded;
|
||||||
// TODO: add uecp
|
// TODO: add uecp
|
||||||
case '3':
|
case '3':
|
||||||
get_rds_oda_group(enc, blocks, stream);
|
get_rds_oda_group(enc, blocks, stream);
|
||||||
@@ -509,6 +539,7 @@ static uint8_t check_rds_good_group(RDSEncoder* enc, char* grp, uint8_t stream)
|
|||||||
if(*grp == 'X' && enc->data[enc->program].udg1_len != 0) good_group = 1;
|
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 == 'Y' && enc->data[enc->program].udg2_len != 0) good_group = 1;
|
||||||
if(*grp == 'R' && enc->rtpData[enc->program].enabled) good_group = 1;
|
if(*grp == 'R' && enc->rtpData[enc->program].enabled) good_group = 1;
|
||||||
|
if(*grp == 'S' && enc->data[enc->program].ert[0] != '\0') good_group = 1;
|
||||||
if(*grp == '3' && enc->oda_state[enc->program][stream].count != 0) good_group = 1;
|
if(*grp == '3' && enc->oda_state[enc->program][stream].count != 0) good_group = 1;
|
||||||
if(*grp == 'F' && enc->data[enc->program].lps[0] != '\0') good_group = 1;
|
if(*grp == 'F' && enc->data[enc->program].lps[0] != '\0') good_group = 1;
|
||||||
return good_group;
|
return good_group;
|
||||||
@@ -662,11 +693,6 @@ void get_rds_bits(RDSEncoder* enc, uint8_t *bits, uint8_t stream) {
|
|||||||
add_checkwords(out_blocks, bits, stream);
|
add_checkwords(out_blocks, bits, stream);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void init_rtplus(RDSEncoder* enc, uint8_t group, uint8_t program) {
|
|
||||||
enc->rtpData[program].group = group;
|
|
||||||
enc->rtpData[program].enabled = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void reset_rds_state(RDSEncoder* enc, uint8_t program) {
|
void reset_rds_state(RDSEncoder* enc, uint8_t program) {
|
||||||
RDSEncoder tempCoder;
|
RDSEncoder tempCoder;
|
||||||
tempCoder.program = program;
|
tempCoder.program = program;
|
||||||
@@ -677,6 +703,7 @@ void reset_rds_state(RDSEncoder* enc, uint8_t program) {
|
|||||||
tempCoder.state[program].ptyn_ab = 1;
|
tempCoder.state[program].ptyn_ab = 1;
|
||||||
set_rds_rt1(&tempCoder, enc->data[program].rt1);
|
set_rds_rt1(&tempCoder, enc->data[program].rt1);
|
||||||
set_rds_rt2(&tempCoder, enc->data[program].rt2);
|
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_ps(&tempCoder, enc->data[program].ps);
|
||||||
set_rds_tps(&tempCoder, enc->data[program].tps);
|
set_rds_tps(&tempCoder, enc->data[program].tps);
|
||||||
set_rds_ptyn(&tempCoder, enc->data[program].ptyn);
|
set_rds_ptyn(&tempCoder, enc->data[program].ptyn);
|
||||||
@@ -718,12 +745,13 @@ void set_rds_defaults(RDSEncoder* enc, uint8_t program) {
|
|||||||
enc->data[program].rt1_enabled = 1;
|
enc->data[program].rt1_enabled = 1;
|
||||||
|
|
||||||
memset(enc->data[program].rt1, ' ', 59);
|
memset(enc->data[program].rt1, ' ', 59);
|
||||||
|
memset(enc->data[program].ert, ' ', 59);
|
||||||
|
|
||||||
enc->data[program].rt_type = 2;
|
enc->data[program].rt_type = 2;
|
||||||
|
|
||||||
reset_rds_state(enc, program);
|
reset_rds_state(enc, program);
|
||||||
|
|
||||||
init_rtplus(enc, GROUP_11A, program);
|
enc->rtpData[program].enabled = 0;
|
||||||
|
|
||||||
enc->encoder_data.ascii_data.expected_encoder_addr = 255;
|
enc->encoder_data.ascii_data.expected_encoder_addr = 255;
|
||||||
enc->encoder_data.ascii_data.expected_site_addr = 255;
|
enc->encoder_data.ascii_data.expected_site_addr = 255;
|
||||||
@@ -841,6 +869,32 @@ void set_rds_lps(RDSEncoder* enc, char *lps) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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, ' ', RT_LENGTH);
|
||||||
|
while (*ert != 0 && len < RT_LENGTH) enc->data[enc->program].ert[len++] = *ert++;
|
||||||
|
|
||||||
|
while (len > 0 && enc->data[enc->program].ert[len - 1] == ' ') {
|
||||||
|
len--;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (len < RT_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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void set_rds_rtplus_flags(RDSEncoder* enc, uint8_t flags) {
|
void set_rds_rtplus_flags(RDSEncoder* enc, uint8_t flags) {
|
||||||
enc->rtpData[enc->program].enabled = (flags==2);
|
enc->rtpData[enc->program].enabled = (flags==2);
|
||||||
enc->rtpData[enc->program].running = flags & 1;
|
enc->rtpData[enc->program].running = flags & 1;
|
||||||
|
|||||||
14
src/rds.h
14
src/rds.h
@@ -36,6 +36,7 @@
|
|||||||
#define MAX_ODAS 8
|
#define MAX_ODAS 8
|
||||||
// List of ODAs: https://www.nrscstandards.org/committees/dsm/archive/rds-oda-aids.pdf
|
// List of ODAs: https://www.nrscstandards.org/committees/dsm/archive/rds-oda-aids.pdf
|
||||||
#define ODA_AID_RTPLUS 0x4bd7
|
#define ODA_AID_RTPLUS 0x4bd7
|
||||||
|
#define ODA_AID_ERT 0x6552
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
uint8_t num_entries : 6;
|
uint8_t num_entries : 6;
|
||||||
@@ -79,11 +80,9 @@ typedef struct {
|
|||||||
char default_rt[RT_LENGTH];
|
char default_rt[RT_LENGTH];
|
||||||
char rt2[RT_LENGTH];
|
char rt2[RT_LENGTH];
|
||||||
|
|
||||||
uint8_t ert_enabled : 1;
|
|
||||||
uint8_t ert_switching_period;
|
uint8_t ert_switching_period;
|
||||||
uint8_t orignal_ert_switching_period;
|
uint8_t orignal_ert_switching_period;
|
||||||
char ert[ERT_LENGTH];
|
char ert[ERT_LENGTH];
|
||||||
char ert2[ERT_LENGTH];
|
|
||||||
|
|
||||||
uint8_t ptyn_enabled : 1;
|
uint8_t ptyn_enabled : 1;
|
||||||
char ptyn[PTYN_LENGTH];
|
char ptyn[PTYN_LENGTH];
|
||||||
@@ -123,7 +122,9 @@ typedef struct {
|
|||||||
uint8_t current_rt : 1;
|
uint8_t current_rt : 1;
|
||||||
|
|
||||||
char ert_text[ERT_LENGTH];
|
char ert_text[ERT_LENGTH];
|
||||||
// uint8_t ert_state
|
uint8_t ert_state : 6;
|
||||||
|
uint8_t ert_update : 1;
|
||||||
|
uint8_t ert_segments : 6;
|
||||||
|
|
||||||
char ptyn_text[PTYN_LENGTH];
|
char ptyn_text[PTYN_LENGTH];
|
||||||
uint8_t ptyn_state : 1;
|
uint8_t ptyn_state : 1;
|
||||||
@@ -139,6 +140,7 @@ typedef struct {
|
|||||||
uint16_t custom_group2[GROUP_LENGTH + 1];
|
uint16_t custom_group2[GROUP_LENGTH + 1];
|
||||||
|
|
||||||
uint8_t rtp_oda : 1;
|
uint8_t rtp_oda : 1;
|
||||||
|
uint8_t ert_oda : 1;
|
||||||
uint8_t grp_seq_idx[4];
|
uint8_t grp_seq_idx[4];
|
||||||
uint8_t udg_idxs[2];
|
uint8_t udg_idxs[2];
|
||||||
|
|
||||||
@@ -163,7 +165,6 @@ typedef struct {
|
|||||||
} RDSODAState;
|
} RDSODAState;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
uint8_t group;
|
|
||||||
uint8_t enabled : 1;
|
uint8_t enabled : 1;
|
||||||
uint8_t running : 1;
|
uint8_t running : 1;
|
||||||
uint8_t type[2];
|
uint8_t type[2];
|
||||||
@@ -176,7 +177,7 @@ typedef struct {
|
|||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
uint8_t expected_encoder_addr;
|
uint8_t expected_encoder_addr;
|
||||||
uint16_t expected_site_addr : 10;
|
uint16_t expected_site_addr : 10;
|
||||||
} RDSEncoderASCIIData;
|
} RDSEncoderASCIIData;
|
||||||
typedef struct
|
typedef struct
|
||||||
@@ -274,7 +275,8 @@ void set_rds_rt2(RDSEncoder* enc, char *rt2);
|
|||||||
void set_rds_ps(RDSEncoder* enc, char *ps);
|
void set_rds_ps(RDSEncoder* enc, char *ps);
|
||||||
void set_rds_tps(RDSEncoder* enc, char *tps);
|
void set_rds_tps(RDSEncoder* enc, char *tps);
|
||||||
void set_rds_lps(RDSEncoder* enc, char *lps);
|
void set_rds_lps(RDSEncoder* enc, char *lps);
|
||||||
void set_rds_rtplus_flags(RDSEncoder* enc, uint8_t flags);
|
void set_rds_ert(RDSEncoder *enc, char *ert);
|
||||||
|
void set_rds_rtplus_flags(RDSEncoder *enc, uint8_t flags);
|
||||||
void set_rds_rtplus_tags(RDSEncoder* enc, uint8_t *tags);
|
void set_rds_rtplus_tags(RDSEncoder* enc, uint8_t *tags);
|
||||||
void set_rds_ptyn(RDSEncoder* enc, char *ptyn);
|
void set_rds_ptyn(RDSEncoder* enc, char *ptyn);
|
||||||
void set_rds_grpseq(RDSEncoder* enc, char *grpseq);
|
void set_rds_grpseq(RDSEncoder* enc, char *grpseq);
|
||||||
|
|||||||
Reference in New Issue
Block a user