From 8f6536aa1effd614a618cce134c0aa6f53d736fa Mon Sep 17 00:00:00 2001 From: KubaPro010 Date: Sat, 22 Mar 2025 10:15:03 +0100 Subject: [PATCH] add eon and ta timeout with the --- .vscode/.server-controller-port.log | 2 +- gen_wave.py | 10 +- src/ascii_cmd.c | 171 +++++++++++++++++++++------- src/rds.c | 90 ++++++++++----- src/rds.h | 1 + 5 files changed, 196 insertions(+), 78 deletions(-) diff --git a/.vscode/.server-controller-port.log b/.vscode/.server-controller-port.log index 90b992e..d549be0 100644 --- a/.vscode/.server-controller-port.log +++ b/.vscode/.server-controller-port.log @@ -1,5 +1,5 @@ { "port": 13452, - "time": 1742417504877, + "time": 1742632427298, "version": "0.0.3" } \ No newline at end of file diff --git a/gen_wave.py b/gen_wave.py index ecd4cc1..cce0c4b 100644 --- a/gen_wave.py +++ b/gen_wave.py @@ -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") diff --git a/src/ascii_cmd.c b/src/ascii_cmd.c index 9176104..6f2cbd4 100644 --- a/src/ascii_cmd.c +++ b/src/ascii_cmd.c @@ -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); + } } \ No newline at end of file diff --git a/src/rds.c b/src/rds.c index da61dc7..811c845 100644 --- a/src/rds.c +++ b/src/rds.c @@ -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; diff --git a/src/rds.h b/src/rds.h index d094e35..274888b 100644 --- a/src/rds.h +++ b/src/rds.h @@ -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;