From cb9ff777120f91523d02e76f1d2f206f07a1bb0f Mon Sep 17 00:00:00 2001 From: KubaPro010 Date: Mon, 24 Mar 2025 16:42:11 +0100 Subject: [PATCH] add doc, remove di, add symbol_shifting --- .vscode/.server-controller-port.log | 2 +- doc.md | 106 ++++++++++++++++++++++++++++ src/ascii_cmd.c | 6 +- src/modulator.c | 12 +++- src/modulator.h | 8 +++ src/rds.c | 8 +-- src/rds.h | 2 +- 7 files changed, 133 insertions(+), 11 deletions(-) create mode 100644 doc.md diff --git a/.vscode/.server-controller-port.log b/.vscode/.server-controller-port.log index 141ec3b..956a339 100644 --- a/.vscode/.server-controller-port.log +++ b/.vscode/.server-controller-port.log @@ -1,5 +1,5 @@ { "port": 13452, - "time": 1742754117510, + "time": 1742823978722, "version": "0.0.3" } \ No newline at end of file diff --git a/doc.md b/doc.md new file mode 100644 index 0000000..69451d9 --- /dev/null +++ b/doc.md @@ -0,0 +1,106 @@ +# RDS95 + +RDS95 is a ligth software RDS encoder for linux + +RDS95 follows the IEC 62106 standard (available at the RDS Forum website) + +## Diffrences between IEC 62106 and EN 50067 + +The newer standard which is the IEC one, removes these features: + +- MS +- PIN +- LIC +- DI (partially, only dynamic pty is left) + +## Commands + +### PS + +Sets the Program Service: `PS=* RDS *` + +### PI + +Sets the PI code: `PI=FFFF` + +### TP + +Sets the TP flag: `TP=1` + +### TA + +Sets the TA flag and triggers Traffic PS: `TA=0` +*May be overridden by EON* + +### DPTY + +Sets the DPTY flag: `DPTY=1` +*Formerly DI* + +### CT + +Toggles the transmission of CT groups: `CT=1` + +### AF + +Sets the AF frequencies: `AF=95,89.1` +Clears the AF: `AF=` + +### TPS + +Sets the Traffic PS: `TPS=Traffic!` (default not set) +*TPS is transmitted instead of PS when TA flag is on* + +### RT1 + +Sets the first radio text: `RT1=Currently Playing: Jessie Ware - Remember Where You Are` or `TEXT=Currently Playing: Jessie Ware - Remember Where You Are` + +### RT2 + +Sets the second radio text: `RT2=Radio Nova - Best Hits around!` + +### PTY + +Sets the programme type flag: `PTY=11` + +PTY values are diffrent for RDS and RDBS, look for them online + +### ECC + +Sets the extended country code: `ECC=E2` +*Note that the ECC is depended on the first letter of the PI, for example PI:3 and ECC:E2 is poland, but PI:1 would be the czech republic* + +### RTP + +TODO: RTP + +### LPS + +Sets the LPS: `LPS=NovaFM❤️` +*Note that LPS does UTF-8, while PS, RT don't* + +### PTYN + +Sets the programme type name: `PTYN=Football` + +### AFCH + +TODO: AFCH + +### UDG1 + +Sets the user defined group, max 8 groups: `UDG1=6000FFFFFFFF` + +### UDG2 + +See [UDG1](#udg1) + +### G + +Sends a custom group to the next group available: `G=F100FFFFFFFF` or `G=00002000AAAAAAAA` for RDS2 + +### RT1EN + +Enables RT 1: `RT1EN=1` + +TODO: Rest of commands diff --git a/src/ascii_cmd.c b/src/ascii_cmd.c index 693d1d0..97fa7d0 100644 --- a/src/ascii_cmd.c +++ b/src/ascii_cmd.c @@ -118,8 +118,8 @@ static void handle_ct(char *arg, RDSModulator* mod, char* output) { strcpy(output, "+\0"); } -static void handle_di(char *arg, RDSModulator* mod, char* output) { - mod->enc->data[mod->enc->program].di = atoi(arg); +static void handle_dpty(char *arg, RDSModulator* mod, char* output) { + mod->enc->data[mod->enc->program].dpty = atoi(arg); strcpy(output, "+\0"); } @@ -504,7 +504,6 @@ static const command_handler_t commands_eq3[] = { {"PI", handle_pi, 2}, {"TP", handle_tp, 2}, {"TA", handle_ta, 2}, - {"DI", handle_di, 2}, {"CT", handle_ct, 2}, {"AF", handle_af, 2} }; @@ -525,6 +524,7 @@ static const command_handler_t commands_eq5[] = { {"AFCH", handle_afch, 4}, {"UDG1", handle_udg1, 4}, {"UDG2", handle_udg2, 4}, + {"DPTY", handle_dpty, 4}, }; static const command_handler_t commands_eq2[] = { diff --git a/src/modulator.c b/src/modulator.c index d192caa..b9900a5 100644 --- a/src/modulator.c +++ b/src/modulator.c @@ -66,6 +66,8 @@ void init_rds_modulator(RDSModulator* rdsMod, RDSEncoder* enc) { rdsMod->enc = enc; + if(STREAMS > 0) rdsMod->data[1].symbol_shifting.symbol_shift = SAMPLES_PER_BIT / 2; + for (uint8_t i = 0; i < 2; i++) { for (uint16_t j = 0; j < FILTER_SIZE; j++) { waveform[i][j] = i ? @@ -109,7 +111,15 @@ float get_rds_sample(RDSModulator* rdsMod, uint8_t stream) { } rdsMod->data[stream].sample_count++; - sample = rdsMod->data[stream].sample_buffer[rdsMod->data[stream].out_sample_index]; + if(rdsMod->data[stream].symbol_shifting.symbol_shift != 0) { + rdsMod->data[stream].symbol_shifting.sample_buffer[rdsMod->data[stream].symbol_shifting.sample_buffer_idx++] = rdsMod->data[stream].sample_buffer[rdsMod->data[stream].out_sample_index]; + + if (rdsMod->data[stream].symbol_shifting.sample_buffer_idx == rdsMod->data[stream].symbol_shifting.symbol_shift) rdsMod->data[stream].symbol_shifting.sample_buffer_idx = 0; + + sample = rdsMod->data[stream].symbol_shifting.sample_buffer[rdsMod->data[stream].symbol_shifting.sample_buffer_idx]; + } else { + sample = rdsMod->data[stream].sample_buffer[rdsMod->data[stream].out_sample_index]; + } rdsMod->data[stream].sample_buffer[rdsMod->data[stream].out_sample_index++] = 0; if (rdsMod->data[stream].out_sample_index == SAMPLE_BUFFER_SIZE) diff --git a/src/modulator.h b/src/modulator.h index ac50b54..bf626c0 100644 --- a/src/modulator.h +++ b/src/modulator.h @@ -11,6 +11,13 @@ typedef struct uint8_t rdsgen : 2; } RDSModulatorParameters; +typedef struct +{ + uint8_t symbol_shift: 7; + float sample_buffer[SAMPLE_BUFFER_SIZE]; + uint8_t sample_buffer_idx : 7; +} RDSModulatorSymbolShifting; + typedef struct { uint8_t bit_buffer[BITS_PER_GROUP]; @@ -22,6 +29,7 @@ typedef struct uint8_t sample_count; uint16_t in_sample_index; uint16_t out_sample_index; + RDSModulatorSymbolShifting symbol_shifting; } RDSModulatorModulationData; typedef struct { diff --git a/src/rds.c b/src/rds.c index f4203b8..64c0da1 100644 --- a/src/rds.c +++ b/src/rds.c @@ -28,8 +28,8 @@ void saveToFile(RDSEncoder *emp, const char *option) { tempEncoder.data[emp->program].tp = emp->data[emp->program].tp; } else if (strcmp(option, "TA") == 0) { tempEncoder.data[emp->program].ta = emp->data[emp->program].ta; - } else if (strcmp(option, "DI") == 0) { - tempEncoder.data[emp->program].di = emp->data[emp->program].di; + } else if (strcmp(option, "DPTY") == 0) { + tempEncoder.data[emp->program].dpty = emp->data[emp->program].dpty; } else if (strcmp(option, "CT") == 0) { tempEncoder.data[emp->program].ct = emp->data[emp->program].ct; } else if (strcmp(option, "RT1") == 0 || strcmp(option, "TEXT") == 0) { @@ -201,8 +201,7 @@ static void get_rds_ps_group(RDSEncoder* enc, uint16_t *blocks) { } blocks[1] |= enc->data[enc->program].ta << 4; - blocks[1] |= 1 << 3; // MS was removed from the standard, this is to keep compatibility with old receivers - blocks[1] |= ((enc->data[enc->program].di >> (3 - enc->state[enc->program].ps_csegment)) & 1) << 2; + if(enc->state[enc->program].ps_csegment == 0) blocks[1] |= enc->data[enc->program].dpty << 2; blocks[1] |= enc->state[enc->program].ps_csegment; blocks[2] = get_next_af(enc); if(enc->data[enc->program].ta && enc->state[enc->program].tps_text[0] != '\0') { @@ -712,7 +711,6 @@ void set_rds_defaults(RDSEncoder* enc, uint8_t program) { enc->encoder_data.encoder_addr[1] = 255; enc->data[program].ct = 1; - enc->data[program].di = 1; strcpy((char *)enc->data[program].grp_sqc, DEFAULT_GRPSQC); enc->data[program].tp = 1; enc->data[program].pi = 0xFFFF; diff --git a/src/rds.h b/src/rds.h index b0a3deb..c05df50 100644 --- a/src/rds.h +++ b/src/rds.h @@ -76,7 +76,7 @@ typedef struct { uint8_t ta : 1; uint8_t pty : 5; uint8_t tp : 1; - uint8_t di : 4; + uint8_t dpty : 1; char tps[PS_LENGTH];