- vApplicationIdleHook() füttert den Watchdog nicht mehr (sdk/Platform/Sys/wm_main.c, dokumentiert als Patch 4 in sdk/PATCHES.md). Bisher fütterte der Idle-Task den Watchdog bei jedem Leerlauf, auch wenn ein Task deadlockt (z.B. nl_app_lock() hält und nie freigibt) - der Watchdog konnte so nie greifen. - Neues Konsolenkommando `wdtest` (Parser in nl_console_cmd.c/.h, Ausführung in nl_console.c, Host-Test in test_console_cmd.c): hält nl_app_lock() für immer, damit light_task und app_task blockieren und nur der Watchdog-Reset den Chip retten kann. - nl_app_request_factory_reset() (nl_app.h) setzt nur ein volatile Flag; app_task prüft es in der Hauptschleife und ruft nl_app_factory_reset() selbst auf, da nur der App-Task die Flash-Stores besitzt. Das Konsolenkommando `factory` ruft jetzt diese Funktion statt nl_app_factory_reset() direkt aufzurufen, um die Race mit nl_state_log_append()/nl_resetcnt_clear() im App-Task zu vermeiden. Der Bootpfad (Bootzähler >= 5) ruft weiterhin direkt nl_app_factory_reset() auf. - nl_resetcnt_clear() wird nur noch als erledigt markiert, wenn es 0 zurückgibt, damit ein fehlgeschlagener Clear in der nächsten Schleifeniteration erneut versucht wird.
160 lines
4.3 KiB
C
160 lines
4.3 KiB
C
#include <stdio.h>
|
|
#include <string.h>
|
|
|
|
#include "wm_include.h"
|
|
#include "wm_watchdog.h"
|
|
|
|
#include "light/nl_control.h"
|
|
#include "light/nl_engine.h"
|
|
#include "sys/nl_app.h"
|
|
#include "sys/nl_console.h"
|
|
#include "sys/nl_console_cmd.h"
|
|
|
|
#define NL_CONSOLE_PRIO 45
|
|
static u32 s_stack[768];
|
|
|
|
static void print_state(void)
|
|
{
|
|
nl_light_state_t s;
|
|
nl_settings_t *cfg = nl_app_settings();
|
|
nl_app_lock();
|
|
nl_ctrl_get(&s);
|
|
nl_app_unlock();
|
|
printf("state: %s bri=%u mode=%s rgb=%u,%u,%u ct=%u | pob=%u fade=%u/%u\r\n",
|
|
s.on ? "on" : "off", s.brightness, s.mode == NL_MODE_COLOR ? "color" : "white",
|
|
s.r, s.g, s.b, s.ct, cfg->power_on_behaviour, cfg->fade_in_ms, cfg->fade_out_ms);
|
|
}
|
|
|
|
static void set_transition(nl_light_change_t *ch, const nl_cmd_t *c, uint8_t index)
|
|
{
|
|
if (c->argc > index) {
|
|
ch->has_transition = true;
|
|
ch->transition_ms = (uint32_t)c->arg[index];
|
|
}
|
|
}
|
|
|
|
static void exec(const nl_cmd_t *c)
|
|
{
|
|
nl_light_change_t ch;
|
|
nl_ctrl_err_t err;
|
|
nl_settings_t *cfg = nl_app_settings();
|
|
|
|
memset(&ch, 0, sizeof ch);
|
|
switch (c->type) {
|
|
case NL_CMD_NONE:
|
|
return;
|
|
case NL_CMD_ON:
|
|
case NL_CMD_OFF:
|
|
ch.has_on = true;
|
|
ch.on = c->type == NL_CMD_ON;
|
|
set_transition(&ch, c, 0);
|
|
break;
|
|
case NL_CMD_BRI:
|
|
ch.has_brightness = true;
|
|
ch.brightness = (uint8_t)c->arg[0];
|
|
set_transition(&ch, c, 1);
|
|
break;
|
|
case NL_CMD_RGB:
|
|
ch.has_color = true;
|
|
ch.r = (uint8_t)c->arg[0];
|
|
ch.g = (uint8_t)c->arg[1];
|
|
ch.b = (uint8_t)c->arg[2];
|
|
set_transition(&ch, c, 3);
|
|
break;
|
|
case NL_CMD_CT:
|
|
ch.has_ct = true;
|
|
ch.ct = (uint16_t)c->arg[0];
|
|
set_transition(&ch, c, 1);
|
|
break;
|
|
case NL_CMD_POB:
|
|
nl_app_lock();
|
|
cfg->power_on_behaviour = (uint8_t)c->arg[0];
|
|
nl_app_unlock();
|
|
printf(nl_app_save_settings() == 0 ? "ok\r\n" : "error: save failed\r\n");
|
|
print_state();
|
|
return;
|
|
case NL_CMD_FADE:
|
|
nl_app_lock();
|
|
cfg->fade_in_ms = (uint16_t)c->arg[0];
|
|
cfg->fade_out_ms = (uint16_t)c->arg[1];
|
|
nl_ctrl_set_fades(cfg->fade_in_ms, cfg->fade_out_ms);
|
|
nl_app_unlock();
|
|
printf(nl_app_save_settings() == 0 ? "ok\r\n" : "error: save failed\r\n");
|
|
print_state();
|
|
return;
|
|
case NL_CMD_STATE:
|
|
print_state();
|
|
return;
|
|
case NL_CMD_BLINK:
|
|
nl_app_lock();
|
|
nl_engine_blink((uint8_t)c->arg[0]);
|
|
nl_app_unlock();
|
|
return;
|
|
case NL_CMD_PULSE:
|
|
nl_app_lock();
|
|
nl_engine_pulse(c->arg[0] != 0);
|
|
nl_app_unlock();
|
|
return;
|
|
case NL_CMD_FACTORY:
|
|
nl_app_request_factory_reset();
|
|
return;
|
|
case NL_CMD_REBOOT:
|
|
tls_sys_reset();
|
|
return;
|
|
case NL_CMD_WDTEST:
|
|
printf("wdtest: holding app lock forever\r\n");
|
|
nl_app_lock(); /* deliberately never released: light_task and app_task stall on it,
|
|
* so only the watchdog reset can recover the chip */
|
|
return;
|
|
case NL_CMD_HELP:
|
|
printf("%s", nl_console_help);
|
|
return;
|
|
default:
|
|
printf("error: unknown command or bad argument (try help)\r\n");
|
|
return;
|
|
}
|
|
|
|
nl_app_lock();
|
|
err = nl_ctrl_apply(&ch, nl_app_now_ms());
|
|
nl_app_unlock();
|
|
if (err == NL_CTRL_OK)
|
|
printf("ok\r\n");
|
|
else
|
|
printf("error %d\r\n", (int)err);
|
|
print_state();
|
|
}
|
|
|
|
static void console_task(void *arg)
|
|
{
|
|
char line[64];
|
|
int len = 0;
|
|
u8 buf[16];
|
|
|
|
(void)arg;
|
|
printf("console ready, type help\r\n");
|
|
for (;;) {
|
|
int n = tls_uart_read(TLS_UART_0, buf, sizeof buf);
|
|
for (int i = 0; i < n; i++) {
|
|
char c = (char)buf[i];
|
|
if (c == '\r' || c == '\n') {
|
|
if (len) {
|
|
nl_cmd_t cmd;
|
|
line[len] = '\0';
|
|
cmd = nl_console_parse(line);
|
|
exec(&cmd);
|
|
len = 0;
|
|
}
|
|
} else if (len < (int)sizeof(line) - 1) {
|
|
line[len++] = c;
|
|
}
|
|
}
|
|
tls_os_time_delay(HZ / 50); /* 20 ms */
|
|
}
|
|
}
|
|
|
|
void nl_console_start(void)
|
|
{
|
|
tls_uart_port_init(TLS_UART_0, NULL, 0);
|
|
tls_os_task_create(NULL, "nl_con", console_task, NULL, (u8 *)s_stack, sizeof(s_stack), NL_CONSOLE_PRIO, 0);
|
|
}
|