Skip to content

Commit 2b6828b

Browse files
committed
[lightning-ln882h] Static IP fix + unique MAC on first boot
1 parent af7e7e8 commit 2b6828b

2 files changed

Lines changed: 100 additions & 58 deletions

File tree

cores/lightning-ln882h/arduino/libraries/WiFi/WiFiEvents.cpp

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,57 @@
11
/* Copyright (c) Etienne Le Cousin 2024-03-10. */
22

33
#include "WiFiPrivate.h"
4+
#include <lwip/dhcp.h> // dhcp_supplied_address, dhcp_release_and_stop
5+
#include <lwip/tcpip.h> // tcpip_callback
6+
7+
static void wifiEventIpReceived(struct netif *nif);
8+
9+
// ---------------------------------------------------------------------------
10+
// Async callback: scheduled via tcpip_callback() from within wifiEventIpReceived
11+
// when DHCP completes despite our best-effort stop in wifiEventStaConnected().
12+
//
13+
// Runs in the LwIP tcpip_thread AFTER dhcp_recv() has fully returned, so it
14+
// is safe to call dhcp_release_and_stop() directly here (no use-after-free).
15+
// We must NOT use netifapi_dhcp_release_and_stop() here — that function posts
16+
// a message to the tcpip_thread mailbox and waits for completion, which would
17+
// deadlock since we ARE the tcpip_thread.
18+
// ---------------------------------------------------------------------------
19+
static void wifiApplyStaticIpCallback(void *arg) {
20+
struct netif *nif = (struct netif *)arg;
21+
if (!pWiFi || !nif)
22+
return;
23+
WiFiNetworkInfo &info = pDATA->sta;
24+
if (!info.localIP)
25+
return;
26+
27+
// Stop DHCP — safe here, we're outside dhcp_recv()
28+
dhcp_release_and_stop(nif);
29+
30+
// Apply the configured static address
31+
ip4_addr_t ipaddr, netmask, gw;
32+
ipaddr.addr = info.localIP;
33+
netmask.addr = info.subnet;
34+
gw.addr = info.gateway;
35+
netif_set_addr(nif, &ipaddr, &netmask, &gw);
36+
// netif_set_addr triggers the netif status callback again, but since DHCP
37+
// is now stopped dhcp_supplied_address() returns false, so g_get_ip_cb is
38+
// NOT re-entered — no infinite recursion.
39+
40+
// Restore configured DNS servers — DHCP may have overwritten them via option 6
41+
// before we could stop it (reconnect/roam fallback path only).
42+
ip4_addr_t d1, d2;
43+
d1.addr = info.dns1;
44+
d2.addr = info.dns2;
45+
if (d1.addr)
46+
dns_setserver(0, &d1);
47+
if (d2.addr)
48+
dns_setserver(1, &d2);
49+
50+
// Emit GOT_IP with the correct static address
51+
wifiEventIpReceived(nif);
52+
}
53+
54+
// ---------------------------------------------------------------------------
455

556
void wifiEventSendArduino(EventId event) {
657
EventInfo eventInfo;
@@ -28,6 +79,28 @@ static void wifiEventStaConnected(void *arg) {
2879
memcpy(eventInfo.wifi_sta_connected.bssid, pWiFi->BSSID(), 6);
2980

3081
pWiFi->postEvent(ARDUINO_EVENT_WIFI_STA_CONNECTED, eventInfo);
82+
83+
// If static IP is configured, apply it now and stop DHCP before the SDK
84+
// starts it. wifi_sta_connect() always starts DHCP internally; we have no
85+
// way to pass dhcp_mode to it (unlike BK72XX's bk_wlan_start_sta_adv_fix).
86+
//
87+
// IMPORTANT: stop DHCP *before* calling netif_set_addr. If DHCP is already
88+
// BOUND when this event fires, netif_set_addr would trigger the netif status
89+
// callback with dhcp_supplied_address==true, which would schedule an
90+
// unnecessary wifiApplyStaticIpCallback. Stopping DHCP first ensures the
91+
// status callback sees dhcp_supplied_address==false and stays silent.
92+
WiFiNetworkInfo &info = pDATA->sta;
93+
if (info.localIP) {
94+
struct netif *ifs = netdev_get_netif(NETIF_IDX_STA);
95+
ip4_addr_t ipaddr, netmask, gw;
96+
ipaddr.addr = info.localIP;
97+
netmask.addr = info.subnet;
98+
gw.addr = info.gateway;
99+
netifapi_dhcp_release_and_stop(ifs); // Stop first — safe (wifi_manager task)
100+
netif_set_addr(ifs, &ipaddr, &netmask, &gw);
101+
// Emit GOT_IP manually — DHCP is stopped so the netdev callback won't fire
102+
wifiEventIpReceived(ifs);
103+
}
31104
}
32105

33106
static void wifiEventStaDisconnected(void *arg) {
@@ -100,6 +173,33 @@ static void wifiEventIpReceived(struct netif *nif) {
100173
if (!pWiFi || !nif)
101174
return; // failsafe
102175

176+
// Fallback: DHCP completed and assigned an address despite our attempt to
177+
// stop it in wifiEventStaConnected(). This can happen when:
178+
// (a) WIFI_MGR_EVENT_STA_CONNECTED fires before the SDK starts DHCP, so
179+
// netifapi_dhcp_release_and_stop() was a NOP and DHCP ran afterward; or
180+
// (b) a reconnect/roam caused the SDK to restart DHCP without triggering
181+
// WIFI_MGR_EVENT_STA_CONNECTED again (e.g. SDK-internal auto-reconnect).
182+
//
183+
// In this case we are being called from sta_netif_status_changed_cb(), which
184+
// is the LwIP netif status callback invoked from within dhcp_recv() in the
185+
// tcpip_thread. Two important constraints apply:
186+
// - Cannot call dhcp_release_and_stop() directly: dhcp_recv() hasn't
187+
// returned yet, freeing the dhcp struct now would be a use-after-free.
188+
// - Cannot call netifapi_dhcp_release_and_stop(): it posts a message to
189+
// the tcpip_thread mailbox and waits for a reply — deadlock because we
190+
// ARE the tcpip_thread.
191+
//
192+
// Solution: schedule wifiApplyStaticIpCallback via tcpip_callback(). It will
193+
// run in the tcpip_thread after the current message (dhcp_recv) has returned,
194+
// so neither constraint applies there.
195+
WiFiNetworkInfo &info = pDATA->sta;
196+
if (info.localIP && dhcp_supplied_address(nif)) {
197+
tcpip_callback(wifiApplyStaticIpCallback, nif);
198+
// Do not emit GOT_IP here with the wrong DHCP address.
199+
// wifiApplyStaticIpCallback will emit it with the static address.
200+
return;
201+
}
202+
103203
eventInfo.got_ip.if_index = 0;
104204
eventInfo.got_ip.ip_changed = true;
105205
eventInfo.got_ip.ip_info.ip.addr = nif->ip_addr.addr;
Lines changed: 0 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -1,58 +0,0 @@
1-
/* Copyright (c) Etienne Le Cousin 2024-02-24. */
2-
3-
#include <libretiny.h>
4-
#include <sdk_private.h>
5-
6-
extern uint8_t uart_print_port;
7-
extern Serial_t m_LogSerial;
8-
9-
static void lt_init_log(void) {
10-
// default LT print port
11-
uart_print_port = LT_UART_DEFAULT_LOGGER;
12-
// default SDK print port
13-
serial_init(&m_LogSerial, LT_UART_DEFAULT_PORT, CFG_UART_BAUDRATE_LOG, NULL);
14-
}
15-
16-
void lt_init_family() {
17-
// 0. check reboot cause
18-
ln_chip_get_reboot_cause();
19-
20-
// 1. sys clock,interrupt
21-
SetSysClock();
22-
set_interrupt_priority();
23-
switch_global_interrupt(HAL_ENABLE);
24-
ln_runtime_measure_init();
25-
26-
// 2. register os heap mem
27-
OS_DefineHeapRegions();
28-
29-
// 3. log init
30-
lt_init_log();
31-
32-
cm_backtrace_init("LibreTiny - LN882H", "HW_V1.0", "SW_V1.0");
33-
34-
if (NVDS_ERR_OK != ln_nvds_init(FLASH_NVDS_OFFSET)) {
35-
LT_E("NVDS init failed!");
36-
}
37-
38-
if (KV_ERR_NONE != ln_kv_port_init(FLASH_KV_OFFSET, (FLASH_KV_OFFSET + FLASH_KV_LENGTH))) {
39-
LT_E("KV init failed!");
40-
}
41-
42-
// init system parameter
43-
sysparam_integrity_check_all();
44-
45-
ln_pm_sleep_mode_set(ACTIVE);
46-
// ln_pm_always_clk_disable_select(CLK_G_I2S | CLK_G_WS2811 | CLK_G_SDIO);
47-
/*ln_pm_always_clk_disable_select(CLK_G_I2S | CLK_G_WS2811 | CLK_G_SDIO | CLK_G_AES);
48-
ln_pm_lightsleep_clk_disable_select(CLK_G_GPIOA | CLK_G_GPIOB | CLK_G_SPI0 | CLK_G_SPI1 | CLK_G_I2C0 |
49-
CLK_G_UART1 | CLK_G_UART2 | CLK_G_WDT | CLK_G_TIM1 | CLK_G_TIM2 | CLK_G_MAC |
50-
CLK_G_DMA | CLK_G_RF | CLK_G_ADV_TIMER| CLK_G_TRNG);*/
51-
}
52-
53-
void lt_init_arduino() {
54-
#if LT_AUTO_DOWNLOAD_REBOOT && LT_ARD_HAS_SERIAL && LT_HW_UART0
55-
// initialize auto-download-reboot parser
56-
Serial0.begin(115200);
57-
#endif
58-
}

0 commit comments

Comments
 (0)