mirror of
https://github.com/radio95-rnt/rds95.git
synced 2026-02-26 20:33:53 +01:00
implement eon in the encoder
This commit is contained in:
2
.vscode/.server-controller-port.log
vendored
2
.vscode/.server-controller-port.log
vendored
@@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"port": 13452,
|
"port": 13452,
|
||||||
"time": 1742320940023,
|
"time": 1742327656502,
|
||||||
"version": "0.0.3"
|
"version": "0.0.3"
|
||||||
}
|
}
|
||||||
@@ -406,6 +406,12 @@ static void handle_init(char *arg, RDSModulator* mod, char* output) {
|
|||||||
strcpy(output, "+\0");
|
strcpy(output, "+\0");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void handle_ver(char *arg, RDSModulator* mod, char* output) {
|
||||||
|
(void)arg;
|
||||||
|
(void)mod;
|
||||||
|
strcpy(output, "Firmware v. 0.0a - (C) 2025 radio95\0");
|
||||||
|
}
|
||||||
|
|
||||||
static const command_handler_t commands_eq3[] = {
|
static const command_handler_t commands_eq3[] = {
|
||||||
{"MS", handle_ms, 2},
|
{"MS", handle_ms, 2},
|
||||||
{"PS", handle_ps, 2},
|
{"PS", handle_ps, 2},
|
||||||
@@ -427,6 +433,7 @@ static const command_handler_t commands_eq4[] = {
|
|||||||
{"LPS", handle_lps, 3},
|
{"LPS", handle_lps, 3},
|
||||||
{"PIN", handle_pin, 3},
|
{"PIN", handle_pin, 3},
|
||||||
{"DPS", handle_dps1, 3},
|
{"DPS", handle_dps1, 3},
|
||||||
|
{"VER", handle_ver, 3},
|
||||||
};
|
};
|
||||||
|
|
||||||
static const command_handler_t commands_eq5[] = {
|
static const command_handler_t commands_eq5[] = {
|
||||||
|
|||||||
73
src/rds.c
73
src/rds.c
@@ -101,7 +101,7 @@ void saveToFile(RDSEncoder *emp, const char *option) {
|
|||||||
} else if(strcmp(option, "PROGRAM") == 0) {
|
} else if(strcmp(option, "PROGRAM") == 0) {
|
||||||
tempEncoder.program = emp->program;
|
tempEncoder.program = emp->program;
|
||||||
} else if(strcmp(option, "EON") == 0) {
|
} else if(strcmp(option, "EON") == 0) {
|
||||||
memcpy(&(tempEncoder.data[emp->program].eon), &(emp->data[emp->program].eon), sizeof(RDSEONs)*4);
|
memcpy(&(tempEncoder.data[emp->program].eon), &(emp->data[emp->program].eon), sizeof(RDSEON)*EONS);
|
||||||
} else if (strcmp(option, "ALL") == 0) {
|
} else if (strcmp(option, "ALL") == 0) {
|
||||||
memcpy(&(tempEncoder.data[emp->program]), &(emp->data[emp->program]), sizeof(RDSData));
|
memcpy(&(tempEncoder.data[emp->program]), &(emp->data[emp->program]), sizeof(RDSData));
|
||||||
memcpy(&(tempEncoder.rtpData[emp->program]), &(emp->rtpData[emp->program]), sizeof(RDSRTPlusData));
|
memcpy(&(tempEncoder.rtpData[emp->program]), &(emp->rtpData[emp->program]), sizeof(RDSRTPlusData));
|
||||||
@@ -305,7 +305,7 @@ encode:
|
|||||||
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint8_t get_rds_rt_group(RDSEncoder* enc, uint16_t *blocks) {
|
static void get_rds_rt_group(RDSEncoder* enc, uint16_t *blocks) {
|
||||||
if (enc->state[enc->program].rt_update) {
|
if (enc->state[enc->program].rt_update) {
|
||||||
memcpy(enc->state[enc->program].rt_text, enc->data[enc->program].rt1, RT_LENGTH);
|
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_ab ^= 1;
|
||||||
@@ -323,7 +323,6 @@ static uint8_t get_rds_rt_group(RDSEncoder* enc, uint16_t *blocks) {
|
|||||||
|
|
||||||
enc->state[enc->program].rt_state++;
|
enc->state[enc->program].rt_state++;
|
||||||
if (enc->state[enc->program].rt_state >= enc->state[enc->program].rt_segments) enc->state[enc->program].rt_state = 0;
|
if (enc->state[enc->program].rt_state >= enc->state[enc->program].rt_segments) enc->state[enc->program].rt_state = 0;
|
||||||
return 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void get_rds_oda_group(RDSEncoder* enc, uint16_t *blocks) {
|
static void get_rds_oda_group(RDSEncoder* enc, uint16_t *blocks) {
|
||||||
@@ -429,6 +428,7 @@ static void get_rds_lic_group(RDSEncoder* enc, uint16_t *blocks) {
|
|||||||
blocks[3] |= enc->data[enc->program].pin[3]; // minute
|
blocks[3] |= enc->data[enc->program].pin[3]; // minute
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void get_rds_rtplus_group(RDSEncoder* enc, uint16_t *blocks) {
|
static void get_rds_rtplus_group(RDSEncoder* enc, uint16_t *blocks) {
|
||||||
blocks[1] |= GET_GROUP_TYPE(enc->rtpData[enc->program].group) << 12;
|
blocks[1] |= GET_GROUP_TYPE(enc->rtpData[enc->program].group) << 12;
|
||||||
blocks[1] |= GET_GROUP_VER(enc->rtpData[enc->program].group) << 11;
|
blocks[1] |= GET_GROUP_VER(enc->rtpData[enc->program].group) << 11;
|
||||||
@@ -444,6 +444,50 @@ static void get_rds_rtplus_group(RDSEncoder* enc, uint16_t *blocks) {
|
|||||||
blocks[3] |= (enc->rtpData[enc->program].start[1] & 0x3f) << 5;
|
blocks[3] |= (enc->rtpData[enc->program].start[1] & 0x3f) << 5;
|
||||||
blocks[3] |= enc->rtpData[enc->program].len[1] & 0x1f;
|
blocks[3] |= enc->rtpData[enc->program].len[1] & 0x1f;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void get_rds_eon_group(RDSEncoder* enc, uint16_t *blocks) {
|
||||||
|
RDSEON eon = enc->data[enc->program].eon[enc->state[enc->program].eon_index];
|
||||||
|
blocks[1] |= 14 << 12;
|
||||||
|
blocks[1] |= eon.tp << 4;
|
||||||
|
|
||||||
|
blocks[1] |= enc->state[enc->program].eon_state;
|
||||||
|
switch (enc->state[enc->program].eon_state)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
case 1:
|
||||||
|
case 2:
|
||||||
|
case 3:
|
||||||
|
blocks[2] = eon.ps[enc->state[enc->program].eon_state*2] << 8;
|
||||||
|
blocks[2] |= eon.ps[enc->state[enc->program].eon_state*2 + 1];
|
||||||
|
break;
|
||||||
|
case 4: // 13
|
||||||
|
blocks[2] = eon.pty << 11;
|
||||||
|
if(eon.tp) blocks[2] |= eon.ta;
|
||||||
|
break;
|
||||||
|
case 5: // 14
|
||||||
|
blocks[2] = eon.pin[1] << 11;
|
||||||
|
blocks[2] |= eon.pin[2] << 6;
|
||||||
|
blocks[2] |= eon.pin[3];
|
||||||
|
break;
|
||||||
|
// TODO: Add AF
|
||||||
|
}
|
||||||
|
|
||||||
|
blocks[3] = eon.pi;
|
||||||
|
|
||||||
|
if(enc->state[enc->program].eon_state == 5) {
|
||||||
|
enc->state[enc->program].eon_index++;
|
||||||
|
uint8_t is_enabled = 1;
|
||||||
|
uint8_t i = 0;
|
||||||
|
while(!is_enabled) {
|
||||||
|
is_enabled = enc->data[enc->program].eon[enc->state[enc->program].eon_index].enabled;
|
||||||
|
i++;
|
||||||
|
if(i > EONS*2) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
enc->state[enc->program].eon_state++;
|
||||||
|
}
|
||||||
// #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) {
|
||||||
@@ -460,8 +504,7 @@ static uint8_t get_rds_custom_groups(RDSEncoder* enc, uint16_t *blocks) {
|
|||||||
|
|
||||||
static void get_rds_group(RDSEncoder* enc, uint16_t *blocks) {
|
static void get_rds_group(RDSEncoder* enc, uint16_t *blocks) {
|
||||||
blocks[0] = enc->data[enc->program].pi;
|
blocks[0] = enc->data[enc->program].pi;
|
||||||
blocks[1] = enc->data[enc->program].tp << 10;
|
blocks[1] = 0;
|
||||||
blocks[1] |= enc->data[enc->program].pty << 5;
|
|
||||||
blocks[2] = 0;
|
blocks[2] = 0;
|
||||||
blocks[3] = 0;
|
blocks[3] = 0;
|
||||||
|
|
||||||
@@ -489,6 +532,14 @@ static void get_rds_group(RDSEncoder* enc, uint16_t *blocks) {
|
|||||||
if(grp == '1' && enc->data[enc->program].ecclic_enabled) good_group = 1;
|
if(grp == '1' && enc->data[enc->program].ecclic_enabled) good_group = 1;
|
||||||
if(grp == '2' && enc->data[enc->program].rt1_enabled) good_group = 1;
|
if(grp == '2' && enc->data[enc->program].rt1_enabled) good_group = 1;
|
||||||
if(grp == 'A' && enc->data[enc->program].ptyn_enabled) good_group = 1;
|
if(grp == 'A' && enc->data[enc->program].ptyn_enabled) good_group = 1;
|
||||||
|
if(grp == 'E') {
|
||||||
|
for (int i = 0; i < EONS; 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 == '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;
|
||||||
@@ -550,7 +601,9 @@ static void get_rds_group(RDSEncoder* enc, uint16_t *blocks) {
|
|||||||
case 'A':
|
case 'A':
|
||||||
get_rds_ptyn_group(enc, blocks);
|
get_rds_ptyn_group(enc, blocks);
|
||||||
goto group_coded;
|
goto group_coded;
|
||||||
// TODO: Add EON
|
case 'E':
|
||||||
|
get_rds_eon_group(enc, blocks);
|
||||||
|
goto group_coded;
|
||||||
case 'X':
|
case 'X':
|
||||||
udg_idx = enc->state[enc->program].udg_idxs[0];
|
udg_idx = enc->state[enc->program].udg_idxs[0];
|
||||||
for(int i = 0; i < 3; i++) blocks[i+1] = enc->data[enc->program].udg1[udg_idx][i];
|
for(int i = 0; i < 3; i++) blocks[i+1] = enc->data[enc->program].udg1[udg_idx][i];
|
||||||
@@ -582,6 +635,8 @@ static void get_rds_group(RDSEncoder* enc, uint16_t *blocks) {
|
|||||||
|
|
||||||
|
|
||||||
group_coded:
|
group_coded:
|
||||||
|
blocks[1] |= enc->data[enc->program].tp << 10;
|
||||||
|
blocks[1] |= enc->data[enc->program].pty << 5;
|
||||||
if (IS_TYPE_B(blocks)) {
|
if (IS_TYPE_B(blocks)) {
|
||||||
blocks[2] = enc->data[enc->program].pi;
|
blocks[2] = enc->data[enc->program].pi;
|
||||||
}
|
}
|
||||||
@@ -621,7 +676,11 @@ void reset_rds_state(RDSEncoder* enc, uint8_t program) {
|
|||||||
time_t now;
|
time_t now;
|
||||||
time(&now);
|
time(&now);
|
||||||
utc = gmtime(&now);
|
utc = gmtime(&now);
|
||||||
enc->state[enc->program].last_ct_minute = utc->tm_min;
|
enc->state[program].last_ct_minute = utc->tm_min;
|
||||||
|
|
||||||
|
for(int i = 0; i < EONS; i++) {
|
||||||
|
tempCoder.data[program].eon[i].ta = 0;
|
||||||
|
}
|
||||||
|
|
||||||
memcpy(&(enc->state[program]), &(tempCoder.state[program]), sizeof(RDSState));
|
memcpy(&(enc->state[program]), &(tempCoder.state[program]), sizeof(RDSState));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,6 +30,7 @@
|
|||||||
#define AF_CODE_LFMF_FOLLOWS 250
|
#define AF_CODE_LFMF_FOLLOWS 250
|
||||||
|
|
||||||
#define PROGRAMS 2
|
#define PROGRAMS 2
|
||||||
|
#define EONS 4
|
||||||
|
|
||||||
#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
|
||||||
@@ -46,10 +47,11 @@ typedef struct {
|
|||||||
uint8_t enabled : 1;
|
uint8_t enabled : 1;
|
||||||
uint8_t ta : 1;
|
uint8_t ta : 1;
|
||||||
uint8_t tp : 1;
|
uint8_t tp : 1;
|
||||||
|
uint8_t pty : 5;
|
||||||
uint8_t pin[4];
|
uint8_t pin[4];
|
||||||
char ps[8];
|
char ps[8];
|
||||||
RDSAFs af;
|
RDSAFs af;
|
||||||
} RDSEONs;
|
} RDSEON;
|
||||||
typedef struct {
|
typedef struct {
|
||||||
uint8_t destination : 4;
|
uint8_t destination : 4;
|
||||||
char text[255];
|
char text[255];
|
||||||
@@ -138,7 +140,8 @@ typedef struct {
|
|||||||
uint16_t udg1[8][3];
|
uint16_t udg1[8][3];
|
||||||
uint16_t udg2[8][3];
|
uint16_t udg2[8][3];
|
||||||
|
|
||||||
RDSEONs eon[4];
|
RDSEON eon[EONS];
|
||||||
|
|
||||||
RDSMessages messages;
|
RDSMessages messages;
|
||||||
RDSScheduler schedule;
|
RDSScheduler schedule;
|
||||||
} RDSData;
|
} RDSData;
|
||||||
@@ -193,6 +196,7 @@ typedef struct {
|
|||||||
uint8_t last_ct_minute : 6;
|
uint8_t last_ct_minute : 6;
|
||||||
|
|
||||||
uint8_t eon_index : 3;
|
uint8_t eon_index : 3;
|
||||||
|
uint8_t eon_state : 4;
|
||||||
} RDSState;
|
} RDSState;
|
||||||
typedef struct {
|
typedef struct {
|
||||||
uint8_t group;
|
uint8_t group;
|
||||||
|
|||||||
Reference in New Issue
Block a user