diff --git a/src/ascii_cmd.c b/src/ascii_cmd.c index 2a737e0..aa48c52 100644 --- a/src/ascii_cmd.c +++ b/src/ascii_cmd.c @@ -61,6 +61,17 @@ static void handle_rtp(char *arg, RDSModulator* mod, char* output) { } } +static void handle_ertp(char *arg, RDSModulator* mod, char* output) { + uint8_t tags[6]; + + if (sscanf((char *)arg, "%hhu,%hhu,%hhu,%hhu,%hhu,%hhu", &tags[0], &tags[1], &tags[2], &tags[3], &tags[4], &tags[5]) == 6) { + set_rds_ertplus_tags(mod->enc, tags); + strcpy(output, "+\0"); + } else { + strcpy(output, "-\0"); + } +} + static void handle_lps(char *arg, RDSModulator* mod, char* output) { arg[LPS_LENGTH * 2] = 0; set_rds_lps(mod->enc, arg); @@ -198,13 +209,24 @@ static void handle_rtprun(char *arg, RDSModulator* mod, char* output) { int flag1, flag2; if (sscanf(arg, "%d,%d", &flag1, &flag2) == 2) { set_rds_rtplus_flags(mod->enc, flag1); - if(flag2) mod->enc->rtpState[mod->enc->program].toggle ^= 1; + if(flag2) mod->enc->rtpState[mod->enc->program][0].toggle ^= 1; } else { set_rds_rtplus_flags(mod->enc, atoi(arg)); } strcpy(output, "+\0"); } +static void handle_ertprun(char *arg, RDSModulator* mod, char* output) { + int flag1, flag2; + if (sscanf(arg, "%d,%d", &flag1, &flag2) == 2) { + set_rds_ertplus_flags(mod->enc, flag1); + if(flag2) mod->enc->rtpState[mod->enc->program][1].toggle ^= 1; + } else { + set_rds_ertplus_flags(mod->enc, atoi(arg)); + } + strcpy(output, "+\0"); +} + static void handle_program(char *arg, RDSModulator* mod, char* output) { int16_t program = atoi(arg)-1; if(program == '\0') { @@ -435,6 +457,7 @@ static const command_handler_t commands_eq5[] = { {"PTYN", handle_ptyn, 4}, {"DPTY", handle_dpty, 4}, {"SLCD", handle_slcd, 4}, + {"ERTP", handle_ertp, 4}, }; static const command_handler_t commands_eq2[] = { @@ -461,6 +484,7 @@ static const command_handler_t commands_eq8[] = { {"RDS2MOD", handle_rds2mod, 7}, {"GRPSEQ2", handle_grpseq2, 7}, {"DTTMOUT", handle_dttmout, 7}, + {"ERTPRUN", handle_ertprun, 7}, }; static const command_handler_t commands_exact[] = { {"INIT", handle_init, 4}, diff --git a/src/rds.c b/src/rds.c index 730ffc3..5e29472 100644 --- a/src/rds.c +++ b/src/rds.c @@ -20,11 +20,11 @@ void saveToFile(RDSEncoder *emp, const char *option) { if(strcmp(option, "PROGRAM") == 0) { 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)*2); tempEncoder.program = emp->program; } else if (strcmp(option, "ALL") == 0) { memcpy(&tempEncoder.data, &emp->data, sizeof(RDSData)*PROGRAMS); - memcpy(&tempEncoder.rtpData, &emp->rtpData, sizeof(RDSRTPlusData)*PROGRAMS); + memcpy(&tempEncoder.rtpData, &emp->rtpData, sizeof(RDSRTPlusData)*PROGRAMS*2); memcpy(&tempEncoder.encoder_data, &emp->encoder_data, sizeof(RDSEncoderData)); tempEncoder.program = emp->program; } else { @@ -36,7 +36,7 @@ void saveToFile(RDSEncoder *emp, const char *option) { rdsEncoderfile.file_middle = 160; rdsEncoderfile.file_ender = 95; memcpy(&(rdsEncoderfile.data[emp->program]), &(tempEncoder.data[emp->program]), sizeof(RDSData)); - memcpy(&(rdsEncoderfile.rtpData[emp->program]), &(tempEncoder.rtpData[emp->program]), sizeof(RDSRTPlusData)); + memcpy(&(rdsEncoderfile.rtpData[emp->program]), &(tempEncoder.rtpData[emp->program]), sizeof(RDSRTPlusData)*2); memcpy(&(rdsEncoderfile.encoder_data), &(tempEncoder.encoder_data), sizeof(RDSEncoderData)); rdsEncoderfile.program = tempEncoder.program; rdsEncoderfile.crc = crc16_ccitt((char*)&rdsEncoderfile, sizeof(RDSEncoderFile) - sizeof(uint16_t)); @@ -77,7 +77,7 @@ void loadFromFile(RDSEncoder *enc) { 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)); + memcpy(&(enc->rtpData[i]), &(rdsEncoderfile.rtpData[i]), sizeof(RDSRTPlusData)*2); } memcpy(&(enc->encoder_data), &(rdsEncoderfile.encoder_data), sizeof(RDSEncoderData)); enc->program = rdsEncoderfile.program; @@ -240,6 +240,14 @@ static void get_rds_rtp_oda_group(RDSEncoder* enc, RDSGroup *group) { group->d = ODA_AID_RTPLUS; } +static void get_rds_ertp_oda_group(RDSEncoder* enc, RDSGroup *group) { + (void)enc; + group->b |= 3 << 12; + + group->b |= 13 << 1; + group->d = ODA_AID_ERTPLUS; +} + static void get_rds_ert_oda_group(RDSEncoder* enc, RDSGroup *group) { (void)enc; group->b |= 3 << 12; @@ -323,17 +331,32 @@ static void get_rds_slcdata_group(RDSEncoder* enc, RDSGroup *group) { static void get_rds_rtplus_group(RDSEncoder* enc, RDSGroup *group) { group->b |= 11 << 12; - group->b |= enc->rtpState[enc->program].toggle << 4 | enc->rtpData[enc->program].running << 3; - group->b |= (enc->rtpData[enc->program].type[0] & 0xf8) >> 3; + 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].type[0] & 0x07) << 13; - group->c |= (enc->rtpData[enc->program].start[0] & 0x3f) << 7; - group->c |= (enc->rtpData[enc->program].len[0] & 0x3f) << 1; - group->c |= (enc->rtpData[enc->program].type[1] & 0xe0) >> 5; + 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].type[1] & 0x1f) << 11; - group->d |= (enc->rtpData[enc->program].start[1] & 0x3f) << 5; - group->d |= enc->rtpData[enc->program].len[1] & 0x1f; + 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) { @@ -486,6 +509,14 @@ static void get_rds_sequence_group(RDSEncoder* enc, RDSGroup *group, char* grp, } enc->state[enc->program].rtp_oda ^= 1; goto group_coded; + case 'P': + if(enc->state[enc->program].ert_oda == 0) { + get_rds_ertplus_group(enc, group); + } else { + get_rds_ertp_oda_group(enc, group); + } + enc->state[enc->program].ert_oda ^= 1; + goto group_coded; case 'S': if(enc->state[enc->program].ert_oda == 0) { get_rds_ert_group(enc, group); @@ -524,7 +555,8 @@ 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 == '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][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; @@ -691,7 +723,7 @@ 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)); + memset(&(tempCoder.rtpState[program]), 0, sizeof(RDSRTPlusState)*2); tempCoder.state[program].rt_ab = 1; tempCoder.state[program].ptyn_ab = 1; @@ -711,8 +743,6 @@ void reset_rds_state(RDSEncoder* enc, uint8_t program) { utc = gmtime(&now); tempCoder.state[program].last_minute = utc->tm_min; - tempCoder.rtpState[program].toggle = 0; - for(int i = 0; i < 4; i++) { tempCoder.data[program].eon[i].ta = 0; } @@ -723,7 +753,7 @@ void reset_rds_state(RDSEncoder* enc, uint8_t program) { void set_rds_defaults(RDSEncoder* enc, uint8_t program) { memset(&(enc->data[program]), 0, sizeof(RDSData)); - memset(&(enc->rtpData[program]), 0, sizeof(RDSRTPlusData)); + memset(&(enc->rtpData[program]), 0, sizeof(RDSRTPlusData)*2); memset(&(enc->encoder_data), 0, sizeof(RDSEncoderData)); enc->encoder_data.encoder_addr[0] = 255; @@ -742,8 +772,6 @@ void set_rds_defaults(RDSEncoder* enc, uint8_t program) { reset_rds_state(enc, program); - enc->rtpData[program].enabled = 0; - enc->encoder_data.ascii_data.expected_encoder_addr = 255; enc->encoder_data.ascii_data.expected_site_addr = 255; } @@ -889,21 +917,39 @@ void set_rds_ert(RDSEncoder* enc, char *ert) { } void set_rds_rtplus_flags(RDSEncoder* enc, uint8_t flags) { - enc->rtpData[enc->program].enabled = (flags==2); - enc->rtpData[enc->program].running = flags & 1; + enc->rtpData[enc->program][0].enabled = (flags==2); + enc->rtpData[enc->program][0].running = flags & 1; +} + +void set_rds_ertplus_flags(RDSEncoder* enc, uint8_t flags) { + enc->rtpData[enc->program][1].enabled = (flags==2); + enc->rtpData[enc->program][1].running = flags & 1; } void set_rds_rtplus_tags(RDSEncoder* enc, uint8_t *tags) { - enc->rtpData[enc->program].type[0] = tags[0] & 0x3f; - enc->rtpData[enc->program].start[0] = tags[1] & 0x3f; - enc->rtpData[enc->program].len[0] = tags[2] & 0x3f; - enc->rtpData[enc->program].type[1] = tags[3] & 0x3f; - enc->rtpData[enc->program].start[1] = tags[4] & 0x3f; - enc->rtpData[enc->program].len[1] = tags[5] & 0x1f; + 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].toggle ^= 1; - enc->rtpData[enc->program].running = 1; - enc->rtpData[enc->program].enabled = 1; + enc->rtpState[enc->program][0].toggle ^= 1; + enc->rtpData[enc->program][0].running = 1; + enc->rtpData[enc->program][0].enabled = 1; +} + +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) { diff --git a/src/rds.h b/src/rds.h index f0f2320..bb350e4 100644 --- a/src/rds.h +++ b/src/rds.h @@ -34,6 +34,7 @@ // List of ODAs: https://www.nrscstandards.org/committees/dsm/archive/rds-oda-aids.pdf #define ODA_AID_RTPLUS 0x4bd7 #define ODA_AID_ERT 0x6552 +#define ODA_AID_ERTPLUS 0x4BD8 typedef struct { uint8_t num_entries : 6; @@ -139,11 +140,12 @@ typedef struct { uint16_t custom_group2[GROUP_LENGTH + 1]; uint8_t rtp_oda : 1; + uint8_t ertp_oda : 1; uint8_t ert_oda : 1; uint8_t data_ecc : 1; uint8_t grp_seq_idx[4]; uint8_t udg_idxs[2]; - + uint8_t fasttuning_state : 3; uint8_t last_minute : 6; @@ -192,14 +194,14 @@ typedef struct { RDSEncoderData encoder_data; RDSData data[PROGRAMS]; RDSState state[PROGRAMS]; - RDSRTPlusData rtpData[PROGRAMS]; - RDSRTPlusState rtpState[PROGRAMS]; + RDSRTPlusData rtpData[PROGRAMS][2]; + RDSRTPlusState rtpState[PROGRAMS][2]; uint8_t program : 3; } RDSEncoder; typedef struct { uint8_t file_starter; // Always is 225 first polish radio programme am frequency RDSData data[PROGRAMS]; - RDSRTPlusData rtpData[PROGRAMS]; + RDSRTPlusData rtpData[PROGRAMS][2]; uint8_t file_middle; // Always is 160, average of both RDSEncoderData encoder_data; uint8_t program : 3; @@ -233,8 +235,10 @@ void set_rds_tps(RDSEncoder* enc, char *tps); void set_rds_lps(RDSEncoder* enc, char *lps); 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_ptyn(RDSEncoder* enc, char *ptyn); +void set_rds_ertplus_flags(RDSEncoder *enc, uint8_t flags); +void set_rds_rtplus_tags(RDSEncoder *enc, uint8_t *tags); +void set_rds_ertplus_tags(RDSEncoder *enc, uint8_t *tags); +void set_rds_ptyn(RDSEncoder *enc, char *ptyn); void set_rds_grpseq(RDSEncoder* enc, char *grpseq); void set_rds_grpseq2(RDSEncoder* enc, char *grpseq2);