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:
Michael Sauer
2026-09-12 03:14:16 +02:00
parent 1822014e48
commit cf1e6a351c
7 changed files with 119 additions and 19 deletions
+5
View File
@@ -21,6 +21,11 @@ extern volatile uint32_t nl_net_beat;
/* Starts the network task. An empty ssid starts the onboarding AP. Strings are copied. */
void nl_wifi_start(const char *ssid, const char *pass, const char *ap_pass);
/* Switches the SDK's own auto-connect off and drops any connection it may already have brought
* up on its own. nl_wifi_start() does this too, but the boot recovery path runs before that and
* must not have the SDK joining its stored AP in parallel (I3, final review). Safe to call any
* number of times; only writes the SDK parameter when it is actually set. */
void nl_wifi_disable_sdk_auto_connect(void);
/* Joins a station directly (no nl_wifi_sm) and blocks until it gets an IP or timeout_ms
* elapses; returns true on success. For use before nl_wifi_start() only - e.g. the boot
* recovery path in nl_recovery.c - since it drives the SDK Wi-Fi calls itself instead of