fix: Recovery-Rettungsweg gegen Endlosschleife, Werksreset und Fremdnetz absichern
C1: nl_recovery_try() verglich nichts mit der laufenden Firmware. Vor einer laufenden Rettungsstation - laut Spec 9 der Normalfall, solange eine Charge migriert - lud die Lampe bei jedem Boot dasselbe Image erneut und startete neu. nl_ota_start_recovery() setzt jetzt ein Flag, das nl_fwup_verify_tail() nur im Recovery-Pfad auswerten lässt: Trägt der Trailer dieselbe Version wie die laufende Firmware (nl_trailer_version(), bisher ungenutzt), wird das Image abgelehnt und der Boot läuft normal weiter. Ein absichtliches Neuflashen derselben Version über die REST-API bleibt möglich. Kein neuer Wert im last_ota_error-Vokabular (Spec 8.2); unterschieden wird über die Konsole. C1/I2: boot_ms wurde erst nach nl_recovery_try() gesetzt und der Power-Cycle-Zähler erst 5 s danach gelöscht - bei erfolgreicher Recovery also nie. Nach NL_FACTORY_RESET_BOOTS Runden folgte ein Werksreset. boot_ms startet jetzt am Anfang von app_task (damit gilt wieder das in Spec 3.4/5.5 zugesagte 5-s-Fenster statt faktisch ~8 s), und nl_app_clear_reset_counter() löscht den Zähler zusätzlich, sobald die Rettungsstation gefunden ist. I3: tls_sys_auto_mode_run() stößt direkt nach UserMain() einen SDK-eigenen Verbindungsversuch an; das dabei entstehende NETIF_IP_NET_UP war in recovery_join_event() nicht vom eigenen Join zu unterscheiden, die Lampe hätte im falschen Netz geladen. nl_wifi_disable_sdk_auto_connect() schaltet das Flag ab und kappt eine bestehende Verbindung jetzt am Anfang von nl_recovery_try(); zusätzlich prüft nl_wifi_join_blocking() über tls_wifi_get_current_bss(), dass die Verbindung wirklich zur erwarteten SSID gehört.
This commit is contained in:
+16
-7
@@ -33,6 +33,7 @@ static tls_os_mutex_t *s_store_lock; /* serialises all nl_settings_* / nl_state_
|
||||
static nl_settings_t s_settings;
|
||||
static volatile uint32_t s_light_beat;
|
||||
static volatile bool s_factory_reset_requested;
|
||||
static volatile bool s_counter_cleared;
|
||||
static u32 s_app_stack[1024];
|
||||
static u32 s_light_stack[512];
|
||||
|
||||
@@ -88,6 +89,15 @@ void nl_app_reboot(void)
|
||||
|
||||
void nl_app_request_factory_reset(void) { s_factory_reset_requested = true; }
|
||||
|
||||
void nl_app_clear_reset_counter(void)
|
||||
{
|
||||
if (s_counter_cleared)
|
||||
return;
|
||||
store_lock();
|
||||
s_counter_cleared = nl_resetcnt_clear() == 0;
|
||||
store_unlock();
|
||||
}
|
||||
|
||||
int nl_app_set_wifi_credentials(const char *ssid, const char *pass)
|
||||
{
|
||||
nl_app_lock();
|
||||
@@ -149,12 +159,15 @@ static void app_task(void *arg)
|
||||
uint32_t base = nl_flash_region_base();
|
||||
nl_engine_cfg_t cfg;
|
||||
nl_light_state_t last, initial, pending;
|
||||
bool have_last, after_ota, counter_cleared = false;
|
||||
bool have_last, after_ota;
|
||||
bool light_alive = false, net_alive = false, http_alive = false;
|
||||
uint8_t boots;
|
||||
uint32_t boot_ms, light_seen, net_seen, http_seen;
|
||||
|
||||
(void)arg;
|
||||
/* I2: the 5 s of spec 3.4 step 7 / 5.5 count from power-up, not from "after the recovery
|
||||
* scan" - otherwise the documented "< 5 s per power cycle" window silently becomes ~8 s. */
|
||||
boot_ms = nl_app_now_ms();
|
||||
nl_flash_init();
|
||||
nl_led_init(board); /* hardware init first (spec 3.4): LEDs dark before any flash/state scan */
|
||||
store_lock();
|
||||
@@ -217,7 +230,6 @@ static void app_task(void *arg)
|
||||
|
||||
nl_http_server_start(nl_app_api_ctx());
|
||||
|
||||
boot_ms = nl_app_now_ms();
|
||||
light_seen = s_light_beat;
|
||||
net_seen = nl_net_beat;
|
||||
http_seen = nl_http_beat;
|
||||
@@ -228,11 +240,8 @@ static void app_task(void *arg)
|
||||
tls_os_time_delay(HZ / 10); /* 100 ms */
|
||||
now = nl_app_now_ms();
|
||||
|
||||
if (!counter_cleared && now - boot_ms >= NL_RESETCNT_CLEAR_MS) {
|
||||
store_lock();
|
||||
counter_cleared = nl_resetcnt_clear() == 0;
|
||||
store_unlock();
|
||||
}
|
||||
if (!s_counter_cleared && now - boot_ms >= NL_RESETCNT_CLEAR_MS)
|
||||
nl_app_clear_reset_counter();
|
||||
|
||||
if (s_factory_reset_requested)
|
||||
nl_app_factory_reset(); /* does not return */
|
||||
|
||||
Reference in New Issue
Block a user