mirror of
https://github.com/radio95-rnt/rds95.git
synced 2026-02-27 12:53:53 +01:00
overhaul of some files (i plan to overhaul the rds encoder completly)
This commit is contained in:
5
.vscode/settings.json
vendored
5
.vscode/settings.json
vendored
@@ -3,6 +3,9 @@
|
|||||||
"files.associations": {
|
"files.associations": {
|
||||||
"ascii_cmd.h": "c",
|
"ascii_cmd.h": "c",
|
||||||
"time.h": "c",
|
"time.h": "c",
|
||||||
"rds.h": "c"
|
"rds.h": "c",
|
||||||
|
"lib.h": "c",
|
||||||
|
"common.h": "c",
|
||||||
|
"modulator.h": "c"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
707
src/ascii_cmd.c
707
src/ascii_cmd.c
@@ -5,301 +5,416 @@
|
|||||||
|
|
||||||
#define CMD_MATCHES(a) (ustrcmp(cmd, (unsigned char *)a) == 0)
|
#define CMD_MATCHES(a) (ustrcmp(cmd, (unsigned char *)a) == 0)
|
||||||
|
|
||||||
void process_ascii_cmd(unsigned char *str) {
|
typedef struct {
|
||||||
unsigned char *cmd, *arg;
|
const char *cmd;
|
||||||
uint16_t cmd_len = 0;
|
void (*handler)(unsigned char *arg);
|
||||||
|
uint8_t cmd_length;
|
||||||
|
} command_handler_t;
|
||||||
|
|
||||||
cmd_len = _strnlen((const char*)str, CTL_BUFFER_SIZE);
|
// Command handlers
|
||||||
|
static void handle_cg(unsigned char *arg) {
|
||||||
if (cmd_len > 3 && str[2] == ' ') {
|
uint16_t blocks[4];
|
||||||
cmd = str;
|
int count = sscanf((const char*)arg, "%hX %hX %hX %hX",
|
||||||
cmd[2] = 0;
|
&blocks[0], &blocks[1], &blocks[2], &blocks[3]);
|
||||||
arg = str + 3;
|
if (count == 4) {
|
||||||
|
set_rds_cg(blocks);
|
||||||
if (CMD_MATCHES("CG")) {
|
}
|
||||||
/* this stays */
|
|
||||||
uint16_t blocks[4];
|
|
||||||
int count = sscanf((const char*)arg, "%hX %hX %hX %hX",
|
|
||||||
&blocks[0], &blocks[1],
|
|
||||||
&blocks[2], &blocks[3]);
|
|
||||||
if (count == 4) {
|
|
||||||
set_rds_cg(blocks);
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(cmd_len == 5) {
|
|
||||||
cmd = str;
|
|
||||||
if(CMD_MATCHES("AFCH=")) {
|
|
||||||
clear_rds_af();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (cmd_len > 5 && str[4] == '=') {
|
|
||||||
/* compatibilty with existing (standarts)*/
|
|
||||||
cmd = str;
|
|
||||||
cmd[4] = 0;
|
|
||||||
arg = str + 5;
|
|
||||||
if (CMD_MATCHES("TEXT")) {
|
|
||||||
arg[RT_LENGTH * 2] = 0;
|
|
||||||
set_rds_rt1(xlat(arg));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (CMD_MATCHES("PTYN")) {
|
|
||||||
arg[PTYN_LENGTH] = 0;
|
|
||||||
set_rds_ptyn(xlat(arg));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (CMD_MATCHES("AFCH")) {
|
|
||||||
if(arg[0] == 'A' || arg[0] == 'B') {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
clear_rds_af();
|
|
||||||
uint8_t arg_count;
|
|
||||||
rds_af_t new_af;
|
|
||||||
uint8_t af[MAX_AFS], *af_iter;
|
|
||||||
arg_count = sscanf((char *)arg,
|
|
||||||
"%hhx,%hhx,%hhx,%hhx,%hhx," /* AF list */
|
|
||||||
"%hhx,%hhx,%hhx,%hhx,%hhx,"
|
|
||||||
"%hhx,%hhx,%hhx,%hhx,%hhx,"
|
|
||||||
"%hhx,%hhx,%hhx,%hhx,%hhx,"
|
|
||||||
"%hhx,%hhx,%hhx,%hhx,%hhx",
|
|
||||||
&af[0], &af[1], &af[2], &af[3], &af[4],
|
|
||||||
&af[5], &af[6], &af[7], &af[8], &af[9],
|
|
||||||
&af[10], &af[11], &af[12], &af[13], &af[14],
|
|
||||||
&af[15], &af[16], &af[17], &af[18], &af[19],
|
|
||||||
&af[20], &af[21], &af[22], &af[23], &af[24]);
|
|
||||||
|
|
||||||
af_iter = af;
|
|
||||||
memset(&new_af, 0, sizeof(struct rds_af_t));
|
|
||||||
while (arg_count-- != 0) {
|
|
||||||
uint8_t current_value = *af_iter;
|
|
||||||
float frequency = (875.0 + current_value) / 10.0;
|
|
||||||
add_rds_af(&new_af, frequency);
|
|
||||||
af_iter++;
|
|
||||||
}
|
|
||||||
set_rds_af(new_af);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(cmd_len == 4) {
|
|
||||||
cmd = str;
|
|
||||||
if(CMD_MATCHES("TPS=")) {
|
|
||||||
set_rds_tpson(0);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if(CMD_MATCHES("LPS=")) {
|
|
||||||
set_rds_lpson(0);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (cmd_len > 4 && str[3] == '=') {
|
|
||||||
cmd = str;
|
|
||||||
cmd[3] = 0;
|
|
||||||
arg = str + 4;
|
|
||||||
if (CMD_MATCHES("TPS")) {
|
|
||||||
arg[PS_LENGTH * 2] = 0;
|
|
||||||
set_rds_tps(xlat(arg));
|
|
||||||
set_rds_tpson(1);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (CMD_MATCHES("RT1")) {
|
|
||||||
arg[RT_LENGTH * 2] = 0;
|
|
||||||
set_rds_rt1(xlat(arg));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (CMD_MATCHES("PTY")) {
|
|
||||||
arg[2] = 0;
|
|
||||||
set_rds_pty(strtoul((char *)arg, NULL, 10));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (CMD_MATCHES("ECC")) {
|
|
||||||
arg[2] = 0;
|
|
||||||
set_rds_ecc(strtoul((char *)arg, NULL, 16));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (CMD_MATCHES("LIC")) {
|
|
||||||
arg[2] = 0;
|
|
||||||
set_rds_lic(strtoul((char *)arg, NULL, 16));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef ODA_RTP
|
|
||||||
if (CMD_MATCHES("RTP")) {
|
|
||||||
char tag_names[2][32];
|
|
||||||
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_rtplus_tags(tags);
|
|
||||||
} else if (sscanf((char *)arg, "%31[^,],%hhu,%hhu,%31[^,],%hhu,%hhu",
|
|
||||||
tag_names[0], &tags[1], &tags[2],
|
|
||||||
tag_names[1], &tags[4], &tags[5]) == 6) {
|
|
||||||
tags[0] = get_rtp_tag_id(tag_names[0]);
|
|
||||||
tags[3] = get_rtp_tag_id(tag_names[1]);
|
|
||||||
set_rds_rtplus_tags(tags);
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (CMD_MATCHES("LPS")) {
|
|
||||||
arg[LPS_LENGTH] = 0;
|
|
||||||
set_rds_lpson(1);
|
|
||||||
set_rds_lps(arg);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (CMD_MATCHES("PIN")) {
|
|
||||||
uint8_t pin[3];
|
|
||||||
if (sscanf((char *)arg, "%hhu,%hhu,%hhu",
|
|
||||||
&pin[0], &pin[1], &pin[2]) == 3) {
|
|
||||||
set_rds_pin(pin[0], pin[1], pin[2]);
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(cmd_len == 3) {
|
|
||||||
cmd = str;
|
|
||||||
if(CMD_MATCHES("AF=")) {
|
|
||||||
clear_rds_af();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (cmd_len > 3 && str[2] == '=') {
|
|
||||||
cmd = str;
|
|
||||||
cmd[2] = 0;
|
|
||||||
arg = str + 3;
|
|
||||||
|
|
||||||
if (CMD_MATCHES("PS")) {
|
|
||||||
if(arg[0] == '\0') arg[0] = ' '; /* fix for strings that start with a space idk why but tps works fine with space started strings */
|
|
||||||
arg[PS_LENGTH * 2] = 0;
|
|
||||||
set_rds_ps(xlat(arg));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (CMD_MATCHES("CT")) {
|
|
||||||
set_rds_ct(arg[0]);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (CMD_MATCHES("DI")) {
|
|
||||||
arg[2] = 0;
|
|
||||||
set_rds_di(strtoul((char *)arg, NULL, 10));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (CMD_MATCHES("TP")) {
|
|
||||||
set_rds_tp(arg[0]);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (CMD_MATCHES("TA")) {
|
|
||||||
set_rds_ta(arg[0]);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (CMD_MATCHES("MS")) {
|
|
||||||
set_rds_ms(arg[0]);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (CMD_MATCHES("PI")) {
|
|
||||||
arg[4] = 0;
|
|
||||||
set_rds_pi(strtoul((char *)arg, NULL, 16));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (CMD_MATCHES("AF")) {
|
|
||||||
if(arg[0] == 'A' || arg[0] == 'B') {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
clear_rds_af();
|
|
||||||
uint8_t arg_count;
|
|
||||||
rds_af_t new_af;
|
|
||||||
float af[MAX_AFS], *af_iter;
|
|
||||||
arg_count = sscanf((char *)arg,
|
|
||||||
"%f,%f,%f,%f,%f," /* AF list */
|
|
||||||
"%f,%f,%f,%f,%f,"
|
|
||||||
"%f,%f,%f,%f,%f,"
|
|
||||||
"%f,%f,%f,%f,%f,"
|
|
||||||
"%f,%f,%f,%f,%f",
|
|
||||||
&af[0], &af[1], &af[2], &af[3], &af[4],
|
|
||||||
&af[5], &af[6], &af[7], &af[8], &af[9],
|
|
||||||
&af[10], &af[11], &af[12], &af[13], &af[14],
|
|
||||||
&af[15], &af[16], &af[17], &af[18], &af[19],
|
|
||||||
&af[20], &af[21], &af[22], &af[23], &af[24]);
|
|
||||||
af_iter = af;
|
|
||||||
memset(&new_af, 0, sizeof(struct rds_af_t));
|
|
||||||
while (arg_count-- != 0) {
|
|
||||||
add_rds_af(&new_af, *af_iter++);
|
|
||||||
}
|
|
||||||
set_rds_af(new_af);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (cmd_len > 2 && str[1] == '=') {
|
|
||||||
cmd = str;
|
|
||||||
cmd[1] = 0;
|
|
||||||
arg = str + 2;
|
|
||||||
if (CMD_MATCHES("G")) {
|
|
||||||
uint16_t blocks[4];
|
|
||||||
if(cmd_len == 14) {
|
|
||||||
/* RDS1 Group*/
|
|
||||||
blocks[0] = get_rds_pi();
|
|
||||||
int count = sscanf((char *)arg, "%4hx%4hx%4hx", &blocks[1], &blocks[2], &blocks[3]);
|
|
||||||
if(count == 3) {
|
|
||||||
set_rds_cg(blocks);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (cmd_len > 6 && str[5] == '=') {
|
|
||||||
cmd = str;
|
|
||||||
cmd[5] = 0;
|
|
||||||
arg = str + 6;
|
|
||||||
|
|
||||||
if (CMD_MATCHES("PINEN")) {
|
|
||||||
arg[1] = 0;
|
|
||||||
set_rds_pin_enabled(strtoul((char *)arg, NULL, 10));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (CMD_MATCHES("RT1EN")) {
|
|
||||||
set_rds_rt1_enabled(arg[0]);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (cmd_len > 6 && str[5] == '=') {
|
|
||||||
cmd = str;
|
|
||||||
cmd[5] = 0;
|
|
||||||
arg = str + 6;
|
|
||||||
}
|
|
||||||
if (cmd_len > 7 && str[6] == '=') {
|
|
||||||
cmd = str;
|
|
||||||
cmd[6] = 0;
|
|
||||||
arg = str + 7;
|
|
||||||
|
|
||||||
if (CMD_MATCHES("PTYNEN")) {
|
|
||||||
arg[1] = 0;
|
|
||||||
set_rds_ptyn_enabled(strtoul((char *)arg, NULL, 10));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef ODA_RTP
|
|
||||||
if (CMD_MATCHES("RTPRUN")) {
|
|
||||||
arg[1] = 0;
|
|
||||||
set_rds_rtplus_flags(strtoul((char *)arg, NULL, 10));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
if (cmd_len > 6 && str[5] == '=') {
|
|
||||||
cmd = str;
|
|
||||||
cmd[5] = 0;
|
|
||||||
arg = str + 6;
|
|
||||||
if (CMD_MATCHES("ECCEN")) {
|
|
||||||
set_rds_ecclic_toggle(arg[0]);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void handle_text(unsigned char *arg) {
|
||||||
|
arg[RT_LENGTH * 2] = 0;
|
||||||
|
set_rds_rt1(xlat(arg));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void handle_ptyn(unsigned char *arg) {
|
||||||
|
arg[PTYN_LENGTH] = 0;
|
||||||
|
set_rds_ptyn(xlat(arg));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void handle_afch(unsigned char *arg) {
|
||||||
|
if (arg[0] == 'A' || arg[0] == 'B') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
clear_rds_af();
|
||||||
|
uint8_t arg_count;
|
||||||
|
rds_af_t new_af;
|
||||||
|
uint8_t af[MAX_AFS], *af_iter;
|
||||||
|
|
||||||
|
arg_count = sscanf((char *)arg,
|
||||||
|
"%hhx,%hhx,%hhx,%hhx,%hhx,"
|
||||||
|
"%hhx,%hhx,%hhx,%hhx,%hhx,"
|
||||||
|
"%hhx,%hhx,%hhx,%hhx,%hhx,"
|
||||||
|
"%hhx,%hhx,%hhx,%hhx,%hhx,"
|
||||||
|
"%hhx,%hhx,%hhx,%hhx,%hhx",
|
||||||
|
&af[0], &af[1], &af[2], &af[3], &af[4],
|
||||||
|
&af[5], &af[6], &af[7], &af[8], &af[9],
|
||||||
|
&af[10], &af[11], &af[12], &af[13], &af[14],
|
||||||
|
&af[15], &af[16], &af[17], &af[18], &af[19],
|
||||||
|
&af[20], &af[21], &af[22], &af[23], &af[24]);
|
||||||
|
|
||||||
|
af_iter = af;
|
||||||
|
memset(&new_af, 0, sizeof(struct rds_af_t));
|
||||||
|
|
||||||
|
while (arg_count-- != 0) {
|
||||||
|
uint8_t current_value = *af_iter;
|
||||||
|
float frequency = (875.0 + current_value) / 10.0;
|
||||||
|
add_rds_af(&new_af, frequency);
|
||||||
|
af_iter++;
|
||||||
|
}
|
||||||
|
|
||||||
|
set_rds_af(new_af);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void handle_udg1(unsigned char *arg) {
|
||||||
|
// TODO: implement
|
||||||
|
}
|
||||||
|
|
||||||
|
static void handle_udg2(unsigned char *arg) {
|
||||||
|
// TODO: implement
|
||||||
|
}
|
||||||
|
|
||||||
|
static void handle_tps(unsigned char *arg) {
|
||||||
|
arg[PS_LENGTH * 2] = 0;
|
||||||
|
set_rds_tps(xlat(arg));
|
||||||
|
set_rds_tpson(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void handle_rt1(unsigned char *arg) {
|
||||||
|
arg[RT_LENGTH * 2] = 0;
|
||||||
|
set_rds_rt1(xlat(arg));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void handle_pty(unsigned char *arg) {
|
||||||
|
arg[2] = 0;
|
||||||
|
set_rds_pty(strtoul((char *)arg, NULL, 10));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void handle_ecc(unsigned char *arg) {
|
||||||
|
arg[2] = 0;
|
||||||
|
set_rds_ecc(strtoul((char *)arg, NULL, 16));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void handle_lic(unsigned char *arg) {
|
||||||
|
arg[2] = 0;
|
||||||
|
set_rds_lic(strtoul((char *)arg, NULL, 16));
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef ODA_RTP
|
||||||
|
static void handle_rtp(unsigned char *arg) {
|
||||||
|
char tag_names[2][32];
|
||||||
|
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_rtplus_tags(tags);
|
||||||
|
} else if (sscanf((char *)arg, "%31[^,],%hhu,%hhu,%31[^,],%hhu,%hhu",
|
||||||
|
tag_names[0], &tags[1], &tags[2], tag_names[1], &tags[4], &tags[5]) == 6) {
|
||||||
|
tags[0] = get_rtp_tag_id(tag_names[0]);
|
||||||
|
tags[3] = get_rtp_tag_id(tag_names[1]);
|
||||||
|
set_rds_rtplus_tags(tags);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static void handle_lps(unsigned char *arg) {
|
||||||
|
arg[LPS_LENGTH] = 0;
|
||||||
|
set_rds_lpson(1);
|
||||||
|
set_rds_lps(arg);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void handle_pin(unsigned char *arg) {
|
||||||
|
uint8_t pin[3];
|
||||||
|
if (sscanf((char *)arg, "%hhu,%hhu,%hhu", &pin[0], &pin[1], &pin[2]) == 3) {
|
||||||
|
set_rds_pin(pin[0], pin[1], pin[2]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void handle_ps(unsigned char *arg) {
|
||||||
|
if (arg[0] == '\0') arg[0] = ' '; // Fix for strings that start with a space
|
||||||
|
arg[PS_LENGTH * 2] = 0;
|
||||||
|
set_rds_ps(xlat(arg));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void handle_ct(unsigned char *arg) {
|
||||||
|
set_rds_ct(arg[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void handle_di(unsigned char *arg) {
|
||||||
|
arg[2] = 0;
|
||||||
|
set_rds_di(strtoul((char *)arg, NULL, 10));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void handle_tp(unsigned char *arg) {
|
||||||
|
set_rds_tp(arg[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void handle_ta(unsigned char *arg) {
|
||||||
|
set_rds_ta(arg[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void handle_ms(unsigned char *arg) {
|
||||||
|
set_rds_ms(arg[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void handle_pi(unsigned char *arg) {
|
||||||
|
arg[4] = 0;
|
||||||
|
set_rds_pi(strtoul((char *)arg, NULL, 16));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void handle_af(unsigned char *arg) {
|
||||||
|
if (arg[0] == 'A' || arg[0] == 'B') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
clear_rds_af();
|
||||||
|
uint8_t arg_count;
|
||||||
|
rds_af_t new_af;
|
||||||
|
float af[MAX_AFS], *af_iter;
|
||||||
|
|
||||||
|
arg_count = sscanf((char *)arg,
|
||||||
|
"%f,%f,%f,%f,%f,"
|
||||||
|
"%f,%f,%f,%f,%f,"
|
||||||
|
"%f,%f,%f,%f,%f,"
|
||||||
|
"%f,%f,%f,%f,%f,"
|
||||||
|
"%f,%f,%f,%f,%f",
|
||||||
|
&af[0], &af[1], &af[2], &af[3], &af[4],
|
||||||
|
&af[5], &af[6], &af[7], &af[8], &af[9],
|
||||||
|
&af[10], &af[11], &af[12], &af[13], &af[14],
|
||||||
|
&af[15], &af[16], &af[17], &af[18], &af[19],
|
||||||
|
&af[20], &af[21], &af[22], &af[23], &af[24]);
|
||||||
|
|
||||||
|
af_iter = af;
|
||||||
|
memset(&new_af, 0, sizeof(struct rds_af_t));
|
||||||
|
|
||||||
|
while (arg_count-- != 0) {
|
||||||
|
add_rds_af(&new_af, *af_iter++);
|
||||||
|
}
|
||||||
|
|
||||||
|
set_rds_af(new_af);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void handle_g(unsigned char *arg) {
|
||||||
|
uint16_t blocks[4];
|
||||||
|
blocks[0] = get_rds_pi();
|
||||||
|
int count = sscanf((char *)arg, "%4hx%4hx%4hx", &blocks[1], &blocks[2], &blocks[3]);
|
||||||
|
if (count == 3) {
|
||||||
|
set_rds_cg(blocks);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void handle_pinen(unsigned char *arg) {
|
||||||
|
arg[1] = 0;
|
||||||
|
set_rds_pin_enabled(strtoul((char *)arg, NULL, 10));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void handle_rt1en(unsigned char *arg) {
|
||||||
|
set_rds_rt1_enabled(arg[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void handle_ptynen(unsigned char *arg) {
|
||||||
|
arg[1] = 0;
|
||||||
|
set_rds_ptyn_enabled(strtoul((char *)arg, NULL, 10));
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef ODA_RTP
|
||||||
|
static void handle_rtprun(unsigned char *arg) {
|
||||||
|
arg[1] = 0;
|
||||||
|
set_rds_rtplus_flags(strtoul((char *)arg, NULL, 10));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static void handle_eccen(unsigned char *arg) {
|
||||||
|
set_rds_ecclic_toggle(arg[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void handle_clear_af(unsigned char *arg) {
|
||||||
|
clear_rds_af();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void handle_tps_off(unsigned char *arg) {
|
||||||
|
set_rds_tpson(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void handle_lps_off(unsigned char *arg) {
|
||||||
|
set_rds_lpson(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Command tables organized by delimiter position and command length
|
||||||
|
static const command_handler_t commands_space[] = {
|
||||||
|
{"CG", handle_cg, 2}
|
||||||
|
};
|
||||||
|
|
||||||
|
static const command_handler_t commands_eq3[] = {
|
||||||
|
{"PS", handle_ps, 2},
|
||||||
|
{"CT", handle_ct, 2},
|
||||||
|
{"DI", handle_di, 2},
|
||||||
|
{"TP", handle_tp, 2},
|
||||||
|
{"TA", handle_ta, 2},
|
||||||
|
{"MS", handle_ms, 2},
|
||||||
|
{"PI", handle_pi, 2},
|
||||||
|
{"AF", handle_af, 2}
|
||||||
|
};
|
||||||
|
|
||||||
|
static const command_handler_t commands_eq4[] = {
|
||||||
|
{"TPS", handle_tps, 3},
|
||||||
|
{"RT1", handle_rt1, 3},
|
||||||
|
{"PTY", handle_pty, 3},
|
||||||
|
{"ECC", handle_ecc, 3},
|
||||||
|
{"LIC", handle_lic, 3},
|
||||||
|
#ifdef ODA_RTP
|
||||||
|
{"RTP", handle_rtp, 3},
|
||||||
|
#endif
|
||||||
|
{"LPS", handle_lps, 3},
|
||||||
|
{"PIN", handle_pin, 3}
|
||||||
|
};
|
||||||
|
|
||||||
|
static const command_handler_t commands_eq5[] = {
|
||||||
|
{"TEXT", handle_text, 4},
|
||||||
|
{"PTYN", handle_ptyn, 4},
|
||||||
|
{"AFCH", handle_afch, 4},
|
||||||
|
{"UDG1", handle_udg1, 4}
|
||||||
|
{"UDG2", handle_udg2, 4}
|
||||||
|
};
|
||||||
|
|
||||||
|
static const command_handler_t commands_eq2[] = {
|
||||||
|
{"G", handle_g, 1}
|
||||||
|
};
|
||||||
|
|
||||||
|
static const command_handler_t commands_eq6[] = {
|
||||||
|
{"PINEN", handle_pinen, 5},
|
||||||
|
{"RT1EN", handle_rt1en, 5},
|
||||||
|
{"ECCEN", handle_eccen, 5}
|
||||||
|
};
|
||||||
|
|
||||||
|
static const command_handler_t commands_eq7[] = {
|
||||||
|
{"PTYNEN", handle_ptynen, 6},
|
||||||
|
#ifdef ODA_RTP
|
||||||
|
{"RTPRUN", handle_rtprun, 6}
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
static const command_handler_t commands_exact[] = {
|
||||||
|
{"AF=", handle_clear_af, 3},
|
||||||
|
{"TPS=", handle_tps_off, 4},
|
||||||
|
{"LPS=", handle_lps_off, 4},
|
||||||
|
{"AFCH=", handle_clear_af, 5}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Process a command using the appropriate command table
|
||||||
|
static bool process_command_table(const command_handler_t *table, int table_size,
|
||||||
|
unsigned char *cmd, unsigned char *arg) {
|
||||||
|
for (int i = 0; i < table_size; i++) {
|
||||||
|
if (ustrcmp(cmd, (unsigned char *)table[i].cmd) == 0) {
|
||||||
|
table[i].handler(arg);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void process_ascii_cmd(unsigned char *str) {
|
||||||
|
unsigned char *cmd, *arg;
|
||||||
|
uint16_t cmd_len = _strnlen((const char*)str, CTL_BUFFER_SIZE);
|
||||||
|
|
||||||
|
// Process exact command matches first
|
||||||
|
for (int i = 0; i < sizeof(commands_exact) / sizeof(command_handler_t); i++) {
|
||||||
|
const command_handler_t *handler = &commands_exact[i];
|
||||||
|
if (cmd_len == handler->cmd_length &&
|
||||||
|
ustrcmp(str, (unsigned char *)handler->cmd) == 0) {
|
||||||
|
handler->handler(NULL);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Process commands with space delimiter (format: XX y...)
|
||||||
|
if (cmd_len > 3 && str[2] == ' ') {
|
||||||
|
cmd = str;
|
||||||
|
cmd[2] = 0;
|
||||||
|
arg = str + 3;
|
||||||
|
|
||||||
|
if (process_command_table(commands_space,
|
||||||
|
sizeof(commands_space) / sizeof(command_handler_t),
|
||||||
|
cmd, arg)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Process commands with = delimiter at position 2 (format: X=y...)
|
||||||
|
if (cmd_len > 2 && str[1] == '=') {
|
||||||
|
cmd = str;
|
||||||
|
cmd[1] = 0;
|
||||||
|
arg = str + 2;
|
||||||
|
|
||||||
|
if (process_command_table(commands_eq2,
|
||||||
|
sizeof(commands_eq2) / sizeof(command_handler_t),
|
||||||
|
cmd, arg)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Process commands with = delimiter at position 3 (format: XX=y...)
|
||||||
|
if (cmd_len > 3 && str[2] == '=') {
|
||||||
|
cmd = str;
|
||||||
|
cmd[2] = 0;
|
||||||
|
arg = str + 3;
|
||||||
|
|
||||||
|
if (process_command_table(commands_eq3,
|
||||||
|
sizeof(commands_eq3) / sizeof(command_handler_t),
|
||||||
|
cmd, arg)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Process commands with = delimiter at position 4 (format: XXX=y...)
|
||||||
|
if (cmd_len > 4 && str[3] == '=') {
|
||||||
|
cmd = str;
|
||||||
|
cmd[3] = 0;
|
||||||
|
arg = str + 4;
|
||||||
|
|
||||||
|
if (process_command_table(commands_eq4,
|
||||||
|
sizeof(commands_eq4) / sizeof(command_handler_t),
|
||||||
|
cmd, arg)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Process commands with = delimiter at position 5 (format: XXXX=y...)
|
||||||
|
if (cmd_len > 5 && str[4] == '=') {
|
||||||
|
cmd = str;
|
||||||
|
cmd[4] = 0;
|
||||||
|
arg = str + 5;
|
||||||
|
|
||||||
|
if (process_command_table(commands_eq5,
|
||||||
|
sizeof(commands_eq5) / sizeof(command_handler_t),
|
||||||
|
cmd, arg)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Process commands with = delimiter at position 6 (format: XXXXX=y...)
|
||||||
|
if (cmd_len > 6 && str[5] == '=') {
|
||||||
|
cmd = str;
|
||||||
|
cmd[5] = 0;
|
||||||
|
arg = str + 6;
|
||||||
|
|
||||||
|
if (process_command_table(commands_eq6,
|
||||||
|
sizeof(commands_eq6) / sizeof(command_handler_t),
|
||||||
|
cmd, arg)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Process commands with = delimiter at position 7 (format: XXXXXX=y...)
|
||||||
|
if (cmd_len > 7 && str[6] == '=') {
|
||||||
|
cmd = str;
|
||||||
|
cmd[6] = 0;
|
||||||
|
arg = str + 7;
|
||||||
|
|
||||||
|
if (process_command_table(commands_eq7,
|
||||||
|
sizeof(commands_eq7) / sizeof(command_handler_t),
|
||||||
|
cmd, arg)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,21 +2,27 @@
|
|||||||
#include "ascii_cmd.h"
|
#include "ascii_cmd.h"
|
||||||
#include "control_pipe.h"
|
#include "control_pipe.h"
|
||||||
|
|
||||||
static int fd;
|
static int fd = -1;
|
||||||
static struct pollfd poller;
|
static struct pollfd poller;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Opens a file (pipe) to be used to control the RDS coder.
|
* Opens a file (pipe) to be used to control the RDS coder.
|
||||||
|
* Returns 0 on success, -1 on failure.
|
||||||
*/
|
*/
|
||||||
int open_control_pipe(char *filename) {
|
int open_control_pipe(char *filename) {
|
||||||
fd = open(filename, O_RDONLY | O_NONBLOCK);
|
if (!filename) return -1;
|
||||||
if (fd == -1) return -1;
|
|
||||||
|
// Close existing pipe if open
|
||||||
|
if (fd >= 0) close(fd);
|
||||||
|
|
||||||
|
fd = open(filename, O_RDONLY | O_NONBLOCK);
|
||||||
|
if (fd == -1) return -1;
|
||||||
|
|
||||||
/* setup the poller */
|
/* setup the poller */
|
||||||
poller.fd = fd;
|
poller.fd = fd;
|
||||||
poller.events = POLLIN;
|
poller.events = POLLIN;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -24,43 +30,49 @@ int open_control_pipe(char *filename) {
|
|||||||
* calls process_ascii_cmd.
|
* calls process_ascii_cmd.
|
||||||
*/
|
*/
|
||||||
void poll_control_pipe() {
|
void poll_control_pipe() {
|
||||||
static unsigned char pipe_buf[CTL_BUFFER_SIZE];
|
static unsigned char pipe_buf[CTL_BUFFER_SIZE];
|
||||||
static unsigned char cmd_buf[CMD_BUFFER_SIZE];
|
static unsigned char cmd_buf[CMD_BUFFER_SIZE];
|
||||||
struct timeval timeout;
|
char *token, *saveptr;
|
||||||
int ret;
|
int read_bytes;
|
||||||
fd_set set;
|
|
||||||
char *token;
|
|
||||||
|
|
||||||
FD_ZERO(&set);
|
// Return early if file descriptor is invalid
|
||||||
FD_SET(fd, &set);
|
if (fd < 0) return;
|
||||||
timeout.tv_sec = 0;
|
|
||||||
timeout.tv_usec = READ_TIMEOUT_MS * 1000;
|
|
||||||
|
|
||||||
/* check for new commands */
|
// Check for new commands with a single poll call
|
||||||
if (poll(&poller, 1, READ_TIMEOUT_MS) <= 0) return;
|
if (poll(&poller, 1, READ_TIMEOUT_MS) <= 0) return;
|
||||||
|
|
||||||
/* return early if there are no new commands */
|
// Return early if there are no new commands
|
||||||
if (poller.revents == 0) return;
|
if (!(poller.revents & POLLIN)) return;
|
||||||
|
|
||||||
memset(pipe_buf, 0, CTL_BUFFER_SIZE);
|
// Clear buffer before reading
|
||||||
|
memset(pipe_buf, 0, CTL_BUFFER_SIZE);
|
||||||
|
|
||||||
|
// Read data directly - select is redundant with poll already used above
|
||||||
|
read_bytes = read(fd, pipe_buf, CTL_BUFFER_SIZE - 1);
|
||||||
|
if (read_bytes <= 0) return;
|
||||||
|
|
||||||
|
// Ensure null-termination
|
||||||
|
pipe_buf[read_bytes] = '\0';
|
||||||
|
|
||||||
ret = select(fd + 1, &set, NULL, NULL, &timeout);
|
/* Process commands line by line */
|
||||||
if (ret == -1 || ret == 0) {
|
token = strtok_r((char *)pipe_buf, "\n", &saveptr);
|
||||||
return;
|
while (token != NULL) {
|
||||||
} else {
|
size_t cmd_len = strlen(token);
|
||||||
read(fd, pipe_buf, CTL_BUFFER_SIZE - 1);
|
if (cmd_len > 0 && cmd_len < CMD_BUFFER_SIZE) {
|
||||||
}
|
memset(cmd_buf, 0, CMD_BUFFER_SIZE);
|
||||||
|
memcpy(cmd_buf, token, cmd_len);
|
||||||
/* handle commands per line this is really good because if were sending text commands very quick after eachother then we can get a rt of for example 'Now its 12:00RT Now its 12:01' */
|
process_ascii_cmd(cmd_buf);
|
||||||
token = strtok((char *)pipe_buf, "\n");
|
}
|
||||||
while (token != NULL) {
|
token = strtok_r(NULL, "\n", &saveptr);
|
||||||
memset(cmd_buf, 0, CMD_BUFFER_SIZE);
|
}
|
||||||
memcpy(cmd_buf, token, CMD_BUFFER_SIZE - 1);
|
|
||||||
token = strtok(NULL, "\n");
|
|
||||||
|
|
||||||
process_ascii_cmd(cmd_buf);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Closes the control pipe.
|
||||||
|
*/
|
||||||
void close_control_pipe() {
|
void close_control_pipe() {
|
||||||
if (fd > 0) close(fd);
|
if (fd >= 0) {
|
||||||
}
|
close(fd);
|
||||||
|
fd = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -12,8 +12,8 @@ void msleep(unsigned long ms) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* just like strlen */
|
/* just like strlen */
|
||||||
size_t _strnlen(const char *s, size_t maxlen) {
|
int _strnlen(const char *s, int maxlen) {
|
||||||
size_t len = 0;
|
int len = 0;
|
||||||
while (s[len] != 0 && len < maxlen)
|
while (s[len] != 0 && len < maxlen)
|
||||||
len++;
|
len++;
|
||||||
return len;
|
return len;
|
||||||
@@ -136,8 +136,7 @@ static uint16_t offset_words[] = {
|
|||||||
/* Calculate the checkword for each block and emit the bits */
|
/* Calculate the checkword for each block and emit the bits */
|
||||||
void add_checkwords(uint16_t *blocks, uint8_t *bits)
|
void add_checkwords(uint16_t *blocks, uint8_t *bits)
|
||||||
{
|
{
|
||||||
size_t i, j;
|
uint8_t i, j, bit, msb;
|
||||||
uint8_t bit, msb;
|
|
||||||
uint16_t block, block_crc, check, offset_word;
|
uint16_t block, block_crc, check, offset_word;
|
||||||
bool group_type_b = false;
|
bool group_type_b = false;
|
||||||
if (IS_TYPE_B(blocks))
|
if (IS_TYPE_B(blocks))
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
extern void msleep(unsigned long ms);
|
extern void msleep(unsigned long ms);
|
||||||
|
|
||||||
extern size_t _strnlen(const char *s, size_t maxlen);
|
extern int _strnlen(const char *s, int maxlen);
|
||||||
extern int ustrcmp(const unsigned char *s1, const unsigned char *s2);
|
extern int ustrcmp(const unsigned char *s1, const unsigned char *s2);
|
||||||
|
|
||||||
extern uint8_t get_rtp_tag_id(char *rtp_tag_name);
|
extern uint8_t get_rtp_tag_id(char *rtp_tag_name);
|
||||||
|
|||||||
@@ -209,7 +209,7 @@ int main(int argc, char **argv) {
|
|||||||
static float mpx_buffer[NUM_MPX_FRAMES];
|
static float mpx_buffer[NUM_MPX_FRAMES];
|
||||||
|
|
||||||
while(!stop_rds) {
|
while(!stop_rds) {
|
||||||
for (size_t i = 0; i < NUM_MPX_FRAMES; i++) {
|
for (uint16_t i = 0; i < NUM_MPX_FRAMES; i++) {
|
||||||
mpx_buffer[i] = get_rds_sample();
|
mpx_buffer[i] = get_rds_sample();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user