0
1
mirror of https://github.com/radio95-rnt/rds95.git synced 2026-02-26 20:33:53 +01:00

add doc, remove di, add symbol_shifting

This commit is contained in:
2025-03-24 16:42:11 +01:00
parent 009649acd7
commit cb9ff77712
7 changed files with 133 additions and 11 deletions

View File

@@ -1,5 +1,5 @@
{
"port": 13452,
"time": 1742754117510,
"time": 1742823978722,
"version": "0.0.3"
}

106
doc.md Normal file
View File

@@ -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

View File

@@ -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[] = {

View File

@@ -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)

View File

@@ -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 {

View File

@@ -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;

View File

@@ -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];