fix: Watchdog wirksam machen, Factory-Reset im App-Task, Resetzähler-Retry

- 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.
This commit is contained in:
Michael Sauer
2026-09-11 20:53:25 +02:00
parent 488dac9167
commit 4f270ad79b
8 changed files with 42 additions and 9 deletions
+7
View File
@@ -12,4 +12,11 @@ nl_settings_t *nl_app_settings(void);
int nl_app_save_settings(void);
void nl_app_factory_reset(void);
/* Only sets a volatile flag; the app task (which owns the flash stores) checks it
* once per loop iteration and calls nl_app_factory_reset() itself. This avoids the
* race with the app task's own nl_state_log_append()/nl_resetcnt_clear() calls.
* The console's `factory` command and, in a later plan, REST callers must use this
* function instead of calling nl_app_factory_reset() directly from another task. */
void nl_app_request_factory_reset(void);
#endif
+6 -1
View File
@@ -96,11 +96,16 @@ static void exec(const nl_cmd_t *c)
nl_app_unlock();
return;
case NL_CMD_FACTORY:
nl_app_factory_reset();
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;
+3 -2
View File
@@ -9,7 +9,7 @@
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";
"state | factory | reboot | wdtest | help\r\n";
static bool num(const char *s, int32_t lo, int32_t hi, int32_t *out)
{
@@ -104,7 +104,8 @@ nl_cmd_t nl_console_parse(const char *line)
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}};
{"state", NL_CMD_STATE}, {"factory", NL_CMD_FACTORY}, {"reboot", NL_CMD_REBOOT},
{"help", NL_CMD_HELP}, {"wdtest", NL_CMD_WDTEST}};
ok = false;
for (size_t i = 0; i < sizeof SIMPLE / sizeof SIMPLE[0]; i++)
if (!strcmp(tok[0], SIMPLE[i].name)) {
+1
View File
@@ -18,6 +18,7 @@ typedef enum {
NL_CMD_FACTORY,
NL_CMD_REBOOT,
NL_CMD_HELP,
NL_CMD_WDTEST,
NL_CMD_ERROR
} nl_cmd_type_t;