feat: Recovery-Download beim Booten
This commit is contained in:
@@ -0,0 +1,98 @@
|
||||
#include "net/nl_recovery.h"
|
||||
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "wm_include.h"
|
||||
#include "wm_watchdog.h"
|
||||
|
||||
#include "net/nl_wifi.h"
|
||||
#include "sys/nl_ota.h"
|
||||
|
||||
#define NL_RECOVERY_SCAN_MS 3000u
|
||||
#define NL_RECOVERY_JOIN_MS 15000u
|
||||
#define NL_RECOVERY_BUF 2048u
|
||||
|
||||
static volatile bool s_scan_done;
|
||||
|
||||
/* tls_wifi_scan_result_cb_register() takes a plain void(void) callback (see
|
||||
sdk/Include/WiFi/wm_wifi.h) - it carries no status/result argument. */
|
||||
static void scan_done_cb(void)
|
||||
{
|
||||
s_scan_done = true;
|
||||
}
|
||||
|
||||
static bool recovery_ap_present(void)
|
||||
{
|
||||
char *buf = tls_mem_alloc(NL_RECOVERY_BUF);
|
||||
struct tls_scan_bss_t *res;
|
||||
const char *want = NINLIGHT_RECOVERY_SSID;
|
||||
uint32_t want_len = (uint32_t)strlen(want);
|
||||
uint32_t waited = 0;
|
||||
uint32_t max_entries, n;
|
||||
bool found = false;
|
||||
u32 i;
|
||||
|
||||
if (buf == NULL)
|
||||
return false;
|
||||
s_scan_done = false;
|
||||
tls_wifi_scan_result_cb_register(scan_done_cb);
|
||||
if (tls_wifi_scan() != WM_SUCCESS) {
|
||||
tls_wifi_scan_result_cb_register(NULL);
|
||||
tls_mem_free(buf);
|
||||
return false;
|
||||
}
|
||||
while (!s_scan_done && waited < NL_RECOVERY_SCAN_MS) {
|
||||
tls_watchdog_clr(); /* boot phase: only this path runs, the light_task heartbeat
|
||||
gate in app_task() does not watch us yet */
|
||||
tls_os_time_delay(HZ / 10);
|
||||
waited += 100;
|
||||
}
|
||||
if (s_scan_done && tls_wifi_get_scan_rslt((u8 *)buf, NL_RECOVERY_BUF) == WM_SUCCESS) {
|
||||
res = (struct tls_scan_bss_t *)buf;
|
||||
/* struct tls_bss_info_t has no length field - res->bss is a fixed-size-element
|
||||
array (struct tls_scan_bss_t::bss[1] is a flexible-array-style head), so index
|
||||
it directly. Cap by what actually fits in buf in case res->count ever reports
|
||||
more entries than tls_wifi_get_scan_rslt() copied into this buffer size. */
|
||||
max_entries = (uint32_t)((NL_RECOVERY_BUF - offsetof(struct tls_scan_bss_t, bss))
|
||||
/ sizeof(struct tls_bss_info_t));
|
||||
n = res->count < max_entries ? res->count : max_entries;
|
||||
for (i = 0; i < n; i++) {
|
||||
struct tls_bss_info_t *bss = &res->bss[i];
|
||||
if (bss->ssid_len == want_len && memcmp(bss->ssid, want, want_len) == 0) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
tls_wifi_scan_result_cb_register(NULL);
|
||||
tls_mem_free(buf);
|
||||
return found;
|
||||
}
|
||||
|
||||
void nl_recovery_try(void)
|
||||
{
|
||||
char url[128];
|
||||
|
||||
if (!recovery_ap_present())
|
||||
return;
|
||||
printf("recovery: station found, joining\r\n");
|
||||
if (!nl_wifi_join_blocking(NINLIGHT_RECOVERY_SSID, NINLIGHT_RECOVERY_PASSWORD, NL_RECOVERY_JOIN_MS)) {
|
||||
printf("recovery: join failed\r\n");
|
||||
nl_ota_set_error("download");
|
||||
return;
|
||||
}
|
||||
snprintf(url, sizeof url, "http://192.168.8.1/ninlight_%s_ota.img", NINLIGHT_DEVICE_ID);
|
||||
printf("recovery: fetching %s\r\n", url);
|
||||
if (nl_ota_start(url) != 0) {
|
||||
printf("recovery: cannot start download\r\n");
|
||||
return;
|
||||
}
|
||||
/* Give the download task the boot phase; on success the SDK resets the chip. */
|
||||
while (nl_ota_busy()) {
|
||||
tls_watchdog_clr();
|
||||
tls_os_time_delay(HZ / 2);
|
||||
}
|
||||
printf("recovery: update failed (%s), continuing normal boot\r\n",
|
||||
nl_ota_last_error() ? nl_ota_last_error() : "unknown");
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
#ifndef NL_RECOVERY_H
|
||||
#define NL_RECOVERY_H
|
||||
|
||||
/* Looks for the recovery station for at most 3 s. When it is there, joins it and
|
||||
starts the recovery download; the chip resets on success, so this call may not return.
|
||||
Must run before nl_wifi_start(): it drives the SDK Wi-Fi APIs directly, without the
|
||||
nl_wifi_sm state machine, and feeds the watchdog itself while it waits. */
|
||||
void nl_recovery_try(void);
|
||||
|
||||
#endif
|
||||
@@ -21,6 +21,12 @@ 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);
|
||||
/* 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
|
||||
* going through the state machine, and must not race nl_wifi_start()'s own netif status
|
||||
* event registration and s_lock/s_queue setup. Feeds the watchdog itself while it waits. */
|
||||
bool nl_wifi_join_blocking(const char *ssid, const char *pass, uint32_t timeout_ms);
|
||||
/* Starts an onboarding test with new credentials (from the HTTP task). 0 = queued. */
|
||||
int nl_wifi_request_onboard(const char *ssid, const char *pass);
|
||||
/* True while the unconfigured onboarding AP is open (API without token). */
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
#include "wm_include.h"
|
||||
#include "wm_efuse.h"
|
||||
#include "wm_watchdog.h"
|
||||
#include "lwip/ip_addr.h"
|
||||
#include "lwip/netif.h" /* struct netif is only forward-declared by wm_netif2.0.3.h */
|
||||
|
||||
@@ -324,3 +325,42 @@ void nl_wifi_status(nl_wifi_status_t *out)
|
||||
const char *nl_wifi_hostname(void) { return s_hostname; }
|
||||
|
||||
void nl_wifi_mac(uint8_t mac[6]) { memcpy(mac, s_mac, 6); }
|
||||
|
||||
/* --- boot recovery: join a station directly, ahead of nl_wifi_start()/nl_wifi_sm --- */
|
||||
|
||||
static volatile bool s_recovery_join_done;
|
||||
static volatile bool s_recovery_join_ok;
|
||||
|
||||
static void recovery_join_event(u8 status)
|
||||
{
|
||||
if (status == NETIF_IP_NET_UP) {
|
||||
s_recovery_join_ok = true;
|
||||
s_recovery_join_done = true;
|
||||
} else if (status == NETIF_WIFI_JOIN_FAILED) {
|
||||
s_recovery_join_done = true;
|
||||
}
|
||||
}
|
||||
|
||||
bool nl_wifi_join_blocking(const char *ssid, const char *pass, uint32_t timeout_ms)
|
||||
{
|
||||
uint32_t waited = 0;
|
||||
|
||||
s_recovery_join_done = false;
|
||||
s_recovery_join_ok = false;
|
||||
tls_netif_add_status_event(recovery_join_event);
|
||||
if (tls_wifi_connect((u8 *)ssid, (u8)strlen(ssid), (u8 *)pass, (u8)strlen(pass)) != WM_SUCCESS) {
|
||||
tls_netif_remove_status_event(recovery_join_event);
|
||||
return false;
|
||||
}
|
||||
while (!s_recovery_join_done && waited < timeout_ms) {
|
||||
tls_watchdog_clr(); /* boot phase: called before app_task's own heartbeat gate exists */
|
||||
tls_os_time_delay(HZ / 10);
|
||||
waited += 100;
|
||||
}
|
||||
tls_netif_remove_status_event(recovery_join_event);
|
||||
if (!s_recovery_join_ok) {
|
||||
tls_wifi_disconnect(); /* cancel a stuck/timed-out join attempt */
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user