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

add eon and ta timeout with the

This commit is contained in:
2025-03-22 10:15:03 +01:00
parent be46dd93d3
commit 8f6536aa1e
5 changed files with 196 additions and 78 deletions

View File

@@ -1,5 +1,5 @@
{
"port": 13452,
"time": 1742417504877,
"time": 1742632427298,
"version": "0.0.3"
}

View File

@@ -6,8 +6,10 @@ import io, os
if PLOT: import matplotlib.pyplot as plt
if FFT: import numpy as np # Import numpy for FFT
DATA_RATE = 1187.5
ratio = 14
sample_rate = 1187.5*ratio
sample_rate = DATA_RATE*ratio
print(f"{sample_rate=}")
if not sample_rate.is_integer(): raise ValueError("Need a even value")
@@ -16,7 +18,7 @@ def rrcosfilter(NumSamples):
T_delta = 1/float(sample_rate)
sample_num = list(range(NumSamples))
h_rrc = [0.0] * NumSamples
SymbolPeriod = 1/(2*1187.5)
SymbolPeriod = 1/(2*DATA_RATE)
for x in sample_num:
t = (x-NumSamples/2)*T_delta
@@ -60,7 +62,7 @@ outc.write(header)
outh.write(header)
def generate():
l = int(sample_rate / 1187.5) // 2
l = ratio // 2
sample = [0.0] * (16*l)
sample[l] = 1
@@ -102,7 +104,7 @@ def generate():
# Plot the magnitude of the FFT
plt.figure(figsize=(10, 6))
plt.plot(fft_freqs[:N//2], np.abs(fft_out)[:N//2]) # Plot only the positive frequencies
plt.xlim(0,1187.5*3)
plt.xlim(0,DATA_RATE*3)
plt.title("FFT of the waveform")
plt.xlabel("Frequency (Hz)")
plt.ylabel("Magnitude")

View File

@@ -12,6 +12,12 @@ typedef struct {
uint8_t cmd_length;
} command_handler_t;
typedef struct {
const char *prefix;
const char *suffix;
void (*handler)(char *arg, char *pattern, RDSModulator* mod, char* output);
} pattern_command_handler_t;
static void handle_ptyn(char *arg, RDSModulator* mod, char* output) {
arg[PTYN_LENGTH] = 0;
set_rds_ptyn(mod->enc, xlat(arg));
@@ -75,14 +81,12 @@ static void handle_dps1(char *arg, RDSModulator* mod, char* output) {
strcpy(output, "+\0");
}
static void handle_dps1mod(char *arg, RDSModulator* mod, char* output) {
arg[1] = 0;
mod->enc->data[mod->enc->program].dps1_mode = strtoul((char *)arg, NULL, 10);
mod->enc->data[mod->enc->program].dps1_mode = atoi(arg);
strcpy(output, "+\0");
}
static void handle_scrlspd(char *arg, RDSModulator* mod, char* output) {
arg[1] = 0;
mod->enc->data[mod->enc->program].dps_speed = strtoul((char *)arg, NULL, 10);
mod->enc->data[mod->enc->program].dps_speed = atoi(arg);
strcpy(output, "+\0");
}
@@ -93,20 +97,17 @@ static void handle_dps1enq(char *arg, RDSModulator* mod, char* output) {
}
static void handle_pty(char *arg, RDSModulator* mod, char* output) {
arg[2] = 0;
mod->enc->data[mod->enc->program].pty = strtoul((char *)arg, NULL, 10);
mod->enc->data[mod->enc->program].pty = atoi(arg);
strcpy(output, "+\0");
}
static void handle_ecc(char *arg, RDSModulator* mod, char* output) {
arg[2] = 0;
mod->enc->data[mod->enc->program].ecc = strtoul((char *)arg, NULL, 16);
mod->enc->data[mod->enc->program].ecc = strtoul(arg, NULL, 16);
strcpy(output, "+\0");
}
static void handle_lic(char *arg, RDSModulator* mod, char* output) {
arg[3] = 0;
mod->enc->data[mod->enc->program].lic = strtoul((char *)arg, NULL, 16);
mod->enc->data[mod->enc->program].lic = strtoul(arg, NULL, 16);
strcpy(output, "+\0");
}
@@ -147,37 +148,32 @@ static void handle_ps(char *arg, RDSModulator* mod, char* output) {
static void handle_ct(char *arg, RDSModulator* mod, char* output) {
arg[2] = 1;
mod->enc->data[mod->enc->program].ct = arg[0];
mod->enc->data[mod->enc->program].ct = atoi(arg);
strcpy(output, "+\0");
}
static void handle_di(char *arg, RDSModulator* mod, char* output) {
arg[2] = 0;
mod->enc->data[mod->enc->program].di = arg[0];
mod->enc->data[mod->enc->program].di = atoi(arg);
strcpy(output, "+\0");
}
static void handle_tp(char *arg, RDSModulator* mod, char* output) {
arg[1] = 0;
mod->enc->data[mod->enc->program].tp = arg[0];
mod->enc->data[mod->enc->program].tp = atoi(arg);
strcpy(output, "+\0");
}
static void handle_ta(char *arg, RDSModulator* mod, char* output) {
arg[1] = 0;
mod->enc->data[mod->enc->program].ta = arg[0];
mod->enc->data[mod->enc->program].ta = atoi(arg);
strcpy(output, "+\0");
}
static void handle_ms(char *arg, RDSModulator* mod, char* output) {
arg[1] = 0;
mod->enc->data[mod->enc->program].ms = arg[0];
mod->enc->data[mod->enc->program].ms = atoi(arg);
strcpy(output, "+\0");
}
static void handle_pi(char *arg, RDSModulator* mod, char* output) {
arg[4] = 0;
mod->enc->data[mod->enc->program].pi = strtoul((char *)arg, NULL, 16);
mod->enc->data[mod->enc->program].pi = strtoul(arg, NULL, 16);
strcpy(output, "+\0");
}
@@ -234,60 +230,53 @@ static void handle_g(char *arg, RDSModulator* mod, char* output) {
}
static void handle_pinen(char *arg, RDSModulator* mod, char* output) {
arg[1] = 0;
mod->enc->data[mod->enc->program].pin[0] = arg[0];
mod->enc->data[mod->enc->program].pin[0] = atoi(arg);
strcpy(output, "+\0");
}
static void handle_rt1en(char *arg, RDSModulator* mod, char* output) {
arg[1] = 0;
mod->enc->data[mod->enc->program].rt1_enabled = arg[0];
mod->enc->data[mod->enc->program].rt1_enabled = atoi(arg);
strcpy(output, "+\0");
}
static void handle_dps1en(char *arg, RDSModulator* mod, char* output) {
arg[1] = 0;
mod->enc->data[mod->enc->program].dps1_enabled = arg[0];
mod->enc->data[mod->enc->program].dps1_enabled = atoi(arg);
mod->enc->state[mod->enc->program].ps_update = 1;
strcpy(output, "+\0");
}
static void handle_labper(char *arg, RDSModulator* mod, char* output) {
mod->enc->data[mod->enc->program].dps_label_period = strtoul((char *)arg, NULL, 10);
mod->enc->data[mod->enc->program].dps_label_period = atoi(arg);
strcpy(output, "+\0");
}
static void handle_spsper(char *arg, RDSModulator* mod, char* output) {
mod->enc->data[mod->enc->program].static_ps_period = strtoul((char *)arg, NULL, 10);
mod->enc->data[mod->enc->program].static_ps_period = atoi(arg);
strcpy(output, "+\0");
}
static void handle_ptynen(char *arg, RDSModulator* mod, char* output) {
arg[1] = 0;
mod->enc->data[mod->enc->program].ptyn_enabled = strtoul((char *)arg, NULL, 10);
mod->enc->data[mod->enc->program].ptyn_enabled = atoi(arg);
strcpy(output, "+\0");
}
static void handle_rtprun(char *arg, RDSModulator* mod, char* output) {
arg[1] = 0;
set_rds_rtplus_flags(mod->enc, strtoul((char *)arg, NULL, 10));
set_rds_rtplus_flags(mod->enc, atoi(arg));
strcpy(output, "+\0");
}
static void handle_eccen(char *arg, RDSModulator* mod, char* output) {
arg[1] = 0;
mod->enc->data[mod->enc->program].ecclic_enabled = arg[0];
strcpy(output, "+\0");
}
static void handle_shortrt(char *arg, RDSModulator* mod, char* output) {
arg[1] = 0;
mod->enc->data[mod->enc->program].shortrt = arg[0];
strcpy(output, "+\0");
}
static void handle_program(char *arg, RDSModulator* mod, char* output) {
int16_t program = strtol((char *)arg, NULL, 10)-1;
int16_t program = atoi(arg)-1;
if(program == '\0') {
strcpy(output, "-\0");
return;
@@ -310,7 +299,7 @@ static void handle_grpseq(char *arg, RDSModulator* mod, char* output) {
}
static void handle_level(char *arg, RDSModulator* mod, char* output) {
mod->params.level = strtoul((char *)arg, NULL, 10)/255.0f;
mod->params.level = atoi(arg)/255.0f;
strcpy(output, "+\0");
}
@@ -325,7 +314,7 @@ static void handle_reset(char *arg, RDSModulator* mod, char* output) {
}
static void handle_rdsgen(char *arg, RDSModulator* mod, char* output) {
mod->params.rdsgen = strtoul((char *)arg, NULL, 10);
mod->params.rdsgen = atoi(arg);
strcpy(output, "+\0");
}
@@ -412,6 +401,63 @@ static void handle_ver(char *arg, RDSModulator* mod, char* output) {
strcpy(output, "Firmware v. 0.0a - (C) 2025 radio95\0");
}
static void handle_eonen(char *arg, char *pattern,, RDSModulator* mod, char* output) {
mod->enc->data[mod->enc->program].eon[atoi(pattern)].enabled = atoi(arg);
strcpy(output, "+\0");
}
static void handle_eonpi(char *arg, char *pattern, RDSModulator* mod, char* output) {
mod->enc->data[mod->enc->program].eon[atoi(pattern)].pi = strtoul(arg, NULL, 16);
strcpy(output, "+\0");
}
static void handle_eonpin(char *arg, char *pattern, RDSModulator* mod, char* output) {
if (arg[0] == '\0') {
mod->enc->data[mod->enc->program].eon[atoi(pattern)].pin[0] = 0;
} else {
uint8_t pin[3];
if (sscanf((char *)arg, "%hhu,%hhu,%hhu", &pin[0], &pin[1], &pin[2]) == 3) {
for (int i = 0; i < 3; i++) {
mod->enc->data[mod->enc->program].eon[atoi(pattern)].pin[i + 1] = pin[i];
}
}
}
strcpy(output, "+\0");
}
static void handle_eonps(char *arg, char *pattern, RDSModulator* mod, char* output) {
arg[PS_LENGTH * 2] = 0;
RDSEON *eon = &mod->enc->data[mod->enc->program].eon[atoi(pattern)];
memset(eon->ps, ' ', sizeof(eon->ps));
uint16_t len = 0;
while (*arg != 0 && len < 24) eon->ps[len++] = *arg++;
strcpy(output, "+\0");
}
static void handle_eonpty(char *arg, char *pattern, RDSModulator* mod, char* output) {
mod->enc->data[mod->enc->program].eon[atoi(pattern)].pty = atoi(arg);
strcpy(output, "+\0");
}
static void handle_eonta(char *arg, char *pattern, RDSModulator* mod, char* output) {
if (!mod->enc->data[mod->enc->program].eon[atoi(pattern)].enabled ||
!mod->enc->data[mod->enc->program].eon[atoi(pattern)].tp) {
strcpy(output, "-\0");
return;
}
mod->enc->data[mod->enc->program].eon[atoi(pattern)].ta = atoi(arg);
if(mod->enc->data[mod->enc->program].eon[atoi(pattern)].ta) mod->enc->data[mod->enc->program].ta = 1;
strcpy(output, "+\0");
}
static void handle_eontp(char *arg, char *pattern, RDSModulator* mod, char* output) {
mod->enc->data[mod->enc->program].eon[atoi(pattern)].tp = atoi(arg);
strcpy(output, "+\0");
}
static const command_handler_t commands_eq3[] = {
{"MS", handle_ms, 2},
{"PS", handle_ps, 2},
@@ -433,7 +479,6 @@ static const command_handler_t commands_eq4[] = {
{"LPS", handle_lps, 3},
{"PIN", handle_pin, 3},
{"DPS", handle_dps1, 3},
{"VER", handle_ver, 3},
};
static const command_handler_t commands_eq5[] = {
@@ -479,8 +524,18 @@ static const command_handler_t commands_eq10[] = {
};
static const command_handler_t commands_exact[] = {
{"INIT", handle_init, 4}
// TODO: handle help, ver, status
{"INIT", handle_init, 4},
{"VER", handle_ver, 3},
// TODO: handle help, status
};
static const pattern_command_handler_t pattern_commands[] = {
{"EON", "EN", handle_eonen},
{"EON", "PI", handle_eonpi},
{"EON", "PIN", handle_eonpin},
{"EON", "PS", handle_eonps},
{"EON", "PTY", handle_eonpty},
{"EON", "TA", handle_eonta},
};
static bool process_command_table(const command_handler_t *table, int table_size,
@@ -494,8 +549,31 @@ static bool process_command_table(const command_handler_t *table, int table_size
return false;
}
static bool process_pattern_commands(char *cmd, char *arg, char *pattern, char *output, RDSModulator* mod) {
size_t cmd_len = strlen(cmd);
for (int i = 0; i < sizeof(pattern_commands) / sizeof(pattern_command_handler_t); i++) {
const pattern_command_handler_t *handler = &pattern_commands[i];
size_t prefix_len = strlen(handler->prefix);
size_t suffix_len = strlen(handler->suffix);
if (cmd_len >= (prefix_len + suffix_len) &&
strncmp(cmd, handler->prefix, prefix_len) == 0 &&
strcmp(cmd + cmd_len - suffix_len, handler->suffix) == 0) {
pattern = cmd + prefix_len;
pattern[cmd_len - suffix_len] = 0;
handler->handler(arg, pattern, mod, output);
return true;
}
}
return false;
}
void process_ascii_cmd(RDSModulator* mod, char *str) {
char *cmd, *arg;
char *cmd, *arg, *pattern = NULL;
char output[255];
memset(output, 0, sizeof(output));
char upper_str[CTL_BUFFER_SIZE];
@@ -623,4 +701,13 @@ void process_ascii_cmd(RDSModulator* mod, char *str) {
cmd, arg, output, mod)) {
}
}
char *equals_pos = strchr(upper_str, '=');
if (equals_pos != NULL) {
*equals_pos = 0;
cmd = upper_str;
arg = str + (equals_pos - upper_str) + 1;
process_pattern_commands(cmd, arg, pattern, output, mod);
}
}

View File

@@ -339,7 +339,7 @@ static void get_rds_oda_group(RDSEncoder* enc, uint16_t *blocks) {
if (enc->oda_state[enc->program].current >= enc->oda_state[enc->program].count) enc->oda_state[enc->program].current = 0;
}
static uint8_t get_rds_ct_group(RDSEncoder* enc, uint16_t *blocks) {
static void get_rds_ct_group(RDSEncoder* enc, uint16_t *blocks) {
struct tm *utc, *local_time;
time_t now;
uint8_t l;
@@ -349,28 +349,20 @@ static uint8_t get_rds_ct_group(RDSEncoder* enc, uint16_t *blocks) {
now = time(NULL);
utc = gmtime(&now);
if (utc->tm_min != enc->state[enc->program].last_ct_minute) {
enc->state[enc->program].last_ct_minute = utc->tm_min;
l = utc->tm_mon <= 1 ? 1 : 0;
mjd = 14956 + utc->tm_mday +
(uint32_t)((utc->tm_year - l) * 365.25f) +
(uint32_t)((utc->tm_mon + (1+1) + l * 12) * 30.6001f);
l = utc->tm_mon <= 1 ? 1 : 0;
mjd = 14956 + utc->tm_mday +
(uint32_t)((utc->tm_year - l) * 365.25f) +
(uint32_t)((utc->tm_mon + (1+1) + l * 12) * 30.6001f);
blocks[1] |= 4 << 12 | (mjd >> 15);
blocks[2] = (mjd << 1) | (utc->tm_hour >> 4);
blocks[3] = (utc->tm_hour & 0xf) << 12 | utc->tm_min << 6;
blocks[1] |= 4 << 12 | (mjd >> 15);
blocks[2] = (mjd << 1) | (utc->tm_hour >> 4);
blocks[3] = (utc->tm_hour & 0xf) << 12 | utc->tm_min << 6;
local_time = localtime(&now);
local_time = localtime(&now);
offset = local_time->__tm_gmtoff / (30 * 60);
if (offset < 0) blocks[3] |= 1 << 5;
blocks[3] |= abs(offset);
return 1;
}
return 0;
offset = local_time->__tm_gmtoff / (30 * 60);
if (offset < 0) blocks[3] |= 1 << 5;
blocks[3] |= abs(offset);
}
static void get_rds_ptyn_group(RDSEncoder* enc, uint16_t *blocks) {
@@ -446,11 +438,12 @@ static void get_rds_rtplus_group(RDSEncoder* enc, uint16_t *blocks) {
}
static void get_rds_eon_group(RDSEncoder* enc, uint16_t *blocks) {
RDSEON eon = enc->data[enc->program].eon[enc->state[enc->program].eon_index];
RDSEON eon;
get_eon:
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:
@@ -459,15 +452,26 @@ static void get_rds_eon_group(RDSEncoder* enc, uint16_t *blocks) {
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];
blocks[1] |= enc->state[enc->program].eon_state;
break;
case 4: // 13
if(eon.pty == 0 && eon.tp == 0) {
enc->state[enc->program].eon_index++;
goto get_eon;
}
blocks[2] = eon.pty << 11;
if(eon.tp) blocks[2] |= eon.ta;
blocks[1] |= 13;
break;
case 5: // 14
if(eon.pin[0] == 0) {
enc->state[enc->program].eon_index++;
goto get_eon;
}
blocks[2] = eon.pin[1] << 11;
blocks[2] |= eon.pin[2] << 6;
blocks[2] |= eon.pin[3];
blocks[1] |= 14;
break;
// TODO: Add AF
}
@@ -476,17 +480,20 @@ static void get_rds_eon_group(RDSEncoder* enc, uint16_t *blocks) {
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;
while(i < EONS && !enc->data[enc->program].eon[enc->state[enc->program].eon_index].enabled) {
enc->state[enc->program].eon_index++;
if(enc->state[enc->program].eon_index >= EONS) {
enc->state[enc->program].eon_index = 0;
}
i++;
}
enc->state[enc->program].eon_state = 0;
} else {
enc->state[enc->program].eon_state++;
}
enc->state[enc->program].eon_state++;
}
// #endregion
@@ -508,9 +515,30 @@ static void get_rds_group(RDSEncoder* enc, uint16_t *blocks) {
blocks[2] = 0;
blocks[3] = 0;
if (enc->data[enc->program].ct && get_rds_ct_group(enc, blocks)) {
goto group_coded;
struct tm *utc;
time_t now;
time(&now);
utc = gmtime(&now);
if (utc->tm_min != enc->state[enc->program].last_ct_minute) {
uint8_t eon_has_ta = 0;
for (int i = 0; i < EONS; i++) {
if (enc->data[enc->program].eon[i].enabled && enc->data[enc->program].eon[i].ta) {
eon_has_ta = 1;
break;
}
}
if(enc->data[enc->program].tp && enc->data[enc->program].ta && enc->state[enc->program].ta_timeout && !eon_has_ta) {
enc->state[enc->program].ta_timeout--;
if(enc->state[enc->program].ta_timeout == 0) enc->data[enc->program].ta = 0;
}
if(enc->data[enc->program].ct) {
get_rds_ct_group(enc, blocks);
goto group_coded;
}
}
enc->state[enc->program].last_ct_minute = utc->tm_min;
if(get_rds_custom_groups(enc, blocks)) {
goto group_coded;

View File

@@ -194,6 +194,7 @@ typedef struct {
uint8_t udg_idxs[2];
uint8_t last_ct_minute : 6;
uint8_t ta_timeout : 7;
uint8_t eon_index : 3;
uint8_t eon_state : 4;