feat: Parser für die UART-Testkonsole

This commit is contained in:
Michael Sauer
2026-09-11 13:43:08 +02:00
parent 663825c165
commit 1074a8f034
4 changed files with 253 additions and 0 deletions
+120
View File
@@ -0,0 +1,120 @@
#include "sys/nl_console_cmd.h"
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
#define MAX_TOK 6
const char nl_console_help[] =
"on [ms] | off [ms] | bri <1-100> [ms] | rgb <r> <g> <b> [ms] | ct <K> [ms]\r\n"
"pob last|on|off | fade <in> <out> | blink [n] | pulse on|off\r\n"
"state | factory | reboot | help\r\n";
static bool num(const char *s, int32_t lo, int32_t hi, int32_t *out)
{
char *end;
long v = strtol(s, &end, 10);
if (*s == '\0' || *end != '\0' || v < lo || v > hi)
return false;
*out = (int32_t)v;
return true;
}
/* Parses tok[first..n-1] into arg[]: `req` required values in [lo,hi], optionally one
* trailing transition in [0,60000]. */
static bool args(nl_cmd_t *c, char **tok, int n, int req, int32_t lo, int32_t hi, bool opt_ms)
{
int given = n - 1;
if (given < req || given > req + (opt_ms ? 1 : 0))
return false;
for (int i = 0; i < req; i++)
if (!num(tok[1 + i], lo, hi, &c->arg[i]))
return false;
if (given > req && !num(tok[1 + req], 0, 60000, &c->arg[req]))
return false;
c->argc = (uint8_t)given;
return true;
}
static bool word(const char *s, const char *const *words, int count, int32_t *out)
{
for (int i = 0; i < count; i++)
if (strcmp(s, words[i]) == 0) {
*out = i;
return true;
}
return false;
}
nl_cmd_t nl_console_parse(const char *line)
{
static const char *const POB[] = {"last", "on", "off"};
static const char *const OFFON[] = {"off", "on"};
nl_cmd_t c;
char buf[64];
char *tok[MAX_TOK];
char *save = NULL;
int n = 0;
bool ok;
memset(&c, 0, sizeof c);
strncpy(buf, line, sizeof buf - 1);
buf[sizeof buf - 1] = '\0';
for (char *t = strtok_r(buf, " \t\r\n", &save); t; t = strtok_r(NULL, " \t\r\n", &save)) {
if (n == MAX_TOK) {
c.type = NL_CMD_ERROR;
return c;
}
tok[n++] = t;
}
if (n == 0)
return c; /* NL_CMD_NONE */
if (!strcmp(tok[0], "on")) {
c.type = NL_CMD_ON;
ok = args(&c, tok, n, 0, 0, 0, true);
} else if (!strcmp(tok[0], "off")) {
c.type = NL_CMD_OFF;
ok = args(&c, tok, n, 0, 0, 0, true);
} else if (!strcmp(tok[0], "bri")) {
c.type = NL_CMD_BRI;
ok = args(&c, tok, n, 1, 1, 100, true);
} else if (!strcmp(tok[0], "rgb")) {
c.type = NL_CMD_RGB;
ok = args(&c, tok, n, 3, 0, 255, true);
} else if (!strcmp(tok[0], "ct")) {
c.type = NL_CMD_CT;
ok = args(&c, tok, n, 1, 1000, 20000, true);
} else if (!strcmp(tok[0], "fade")) {
c.type = NL_CMD_FADE;
ok = args(&c, tok, n, 2, 0, 10000, false);
} else if (!strcmp(tok[0], "pob")) {
c.type = NL_CMD_POB;
ok = n == 2 && word(tok[1], POB, 3, &c.arg[0]);
c.argc = 1;
} else if (!strcmp(tok[0], "pulse")) {
c.type = NL_CMD_PULSE;
ok = n == 2 && word(tok[1], OFFON, 2, &c.arg[0]);
c.argc = 1;
} else if (!strcmp(tok[0], "blink")) {
c.type = NL_CMD_BLINK;
c.arg[0] = 3;
c.argc = 1;
ok = n == 1 || (n == 2 && num(tok[1], 1, 10, &c.arg[0]));
} else {
static const struct { const char *name; nl_cmd_type_t type; } SIMPLE[] = {
{"state", NL_CMD_STATE}, {"factory", NL_CMD_FACTORY}, {"reboot", NL_CMD_REBOOT}, {"help", NL_CMD_HELP}};
ok = false;
for (size_t i = 0; i < sizeof SIMPLE / sizeof SIMPLE[0]; i++)
if (!strcmp(tok[0], SIMPLE[i].name)) {
c.type = SIMPLE[i].type;
ok = n == 1;
}
}
if (!ok) {
memset(&c, 0, sizeof c);
c.type = NL_CMD_ERROR;
}
return c;
}
+34
View File
@@ -0,0 +1,34 @@
#ifndef NL_CONSOLE_CMD_H
#define NL_CONSOLE_CMD_H
#include <stdint.h>
typedef enum {
NL_CMD_NONE = 0,
NL_CMD_ON,
NL_CMD_OFF,
NL_CMD_BRI,
NL_CMD_RGB,
NL_CMD_CT,
NL_CMD_POB,
NL_CMD_FADE,
NL_CMD_STATE,
NL_CMD_BLINK,
NL_CMD_PULSE,
NL_CMD_FACTORY,
NL_CMD_REBOOT,
NL_CMD_HELP,
NL_CMD_ERROR
} nl_cmd_type_t;
typedef struct {
nl_cmd_type_t type;
int32_t arg[4];
uint8_t argc;
} nl_cmd_t;
nl_cmd_t nl_console_parse(const char *line);
extern const char nl_console_help[];
#endif