Skip to content

Commit 8208b1f

Browse files
Rewrite CYW43 WiFi connection scheme (#3160)
Fixes #3157 Fixes #1837 The SDK's CYW43 WiFi connection scheme combined both link layer (WiFi net connection) and IP (getting an IP address from DHCP) into a single step. We worked around it with a hack wrapped function, but it resulted in the WiFi.begin() timeout being 2x as long as specified. Remove the SDK's cyw43_arch_wifi_connect_timeout_ms and replace with our own custom CYW43::begin which will only look at the link layer. Note that the SDK docs are hokey and the cyw43_link_status is set to 1 *while network connection attempts are underway.* This means we can't actually just look at the link state, it will be in JOIN even if it's not really joined. So, we peek at the state internal CYW43 join FSM to see we're *really* connected. This exposed a corner case which @ledereyes seems to have run into in his own app where the LwipIntfDev could potentially try and register the same netif twice because the underlying lower-level CYW43 link had failed. Ensure we netif_remove() in that case to avoid this issue. On WiFi.end(), just disconnect the network and don't deinitialize the chip in case Bluetooth is active.
1 parent cd7301c commit 8208b1f

File tree

7 files changed

+94
-73
lines changed

7 files changed

+94
-73
lines changed

cores/rp2040/freertos/freertos-lwip.cpp

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -381,10 +381,19 @@ static void lwipThread(void *params) {
381381
}
382382
case __ethernet_input: {
383383
__ethernet_input_req *r = (__ethernet_input_req *)w.req;
384-
printf("__real_ethernet_input\n");
385384
*(r->ret) = __real_ethernet_input(r->p, r->netif);
386385
break;
387386
}
387+
case __cyw43_wifi_join: {
388+
__cyw43_wifi_join_req *r = (__cyw43_wifi_join_req *)w.req;
389+
*(r->ret) = __real_cyw43_wifi_join(r->self, r->ssid_len, r->ssid, r->key_len, r->key, r->auth_type, r->bssid, r->channel);
390+
break;
391+
}
392+
case __cyw43_wifi_leave: {
393+
__cyw43_wifi_leave_req *r = (__cyw43_wifi_leave_req*)w.req;
394+
*(r->ret) = __real_cyw43_wifi_leave(r->self, r->itf);
395+
break;
396+
}
388397
case __callback: {
389398
__callback_req *r = (__callback_req *)w.req;
390399
r->cb(r->cbData);

cores/rp2040/lwip_wrap.cpp

Lines changed: 28 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -832,6 +832,34 @@ extern "C" {
832832
return __real_ethernet_input(p, netif);
833833
}
834834

835+
int __real_cyw43_wifi_join(cyw43_t *self, size_t ssid_len, const uint8_t *ssid, size_t key_len, const uint8_t *key, uint32_t auth_type, const uint8_t *bssid, uint32_t channel);
836+
int __wrap_cyw43_wifi_join(cyw43_t *self, size_t ssid_len, const uint8_t *ssid, size_t key_len, const uint8_t *key, uint32_t auth_type, const uint8_t *bssid, uint32_t channel) {
837+
#ifdef __FREERTOS
838+
if (!__isLWIPThread()) {
839+
int ret;
840+
__cyw43_wifi_join_req req = { self, ssid_len, ssid, key_len, key, auth_type, bssid, channel, &ret };
841+
__lwip(__cyw43_wifi_join, &req);
842+
return ret;
843+
}
844+
#endif
845+
return __real_cyw43_wifi_join(self, ssid_len, ssid, key_len, key, auth_type, bssid, channel);
846+
}
847+
848+
int __real_cyw43_wifi_leave(cyw43_t* self, int itf);
849+
int __wrap_cyw43_wifi_leave(cyw43_t* self, int itf) {
850+
#ifdef __FREERTOS
851+
if (!__isLWIPThread()) {
852+
int ret;
853+
__cyw43_wifi_leave_req req = { self, itf, &ret };
854+
__lwip(__cyw43_wifi_leave, &req);
855+
return ret;
856+
}
857+
#endif
858+
return __real_cyw43_wifi_leave(self, itf);
859+
}
860+
861+
862+
835863
void lwip_callback(void (*cb)(void *), void *cbData, __callback_req *buffer) {
836864
#ifdef __FREERTOS
837865
if (buffer) {
@@ -895,14 +923,6 @@ extern "C" {
895923
void __wrap_cyw43_schedule_internal_poll_dispatch(void (*func)()) {
896924
__real_cyw43_schedule_internal_poll_dispatch(func);
897925
}
898-
extern int __real_cyw43_arch_wifi_connect_bssid_timeout_ms(const char *ssid, const uint8_t *bssid, const char *pw, uint32_t auth, uint32_t timeout_ms);
899-
int __wrap_cyw43_arch_wifi_connect_bssid_timeout_ms(const char *ssid, const uint8_t *bssid, const char *pw, uint32_t auth, uint32_t timeout_ms) {
900-
return __real_cyw43_arch_wifi_connect_bssid_timeout_ms(ssid, bssid, pw, auth, timeout_ms);
901-
}
902-
extern int __real_cyw43_arch_wifi_connect_timeout_ms(const char *ssid, const char *pw, uint32_t auth, uint32_t timeout_ms);
903-
int __wrap_cyw43_arch_wifi_connect_timeout_ms(const char *ssid, const char *pw, uint32_t auth, uint32_t timeout_ms) {
904-
return __real_cyw43_arch_wifi_connect_timeout_ms(ssid, pw, auth, timeout_ms);
905-
}
906926
extern void __real_cyw43_arch_gpio_put(uint wl_gpio, bool value);
907927
void __wrap_cyw43_arch_gpio_put(uint wl_gpio, bool value) {
908928
__real_cyw43_arch_gpio_put(wl_gpio, value);

cores/rp2040/lwip_wrap.h

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,9 @@ typedef enum {
167167

168168
__ethernet_input = 9000,
169169

170+
__cyw43_wifi_join = 9500,
171+
__cyw43_wifi_leave,
172+
170173
__callback = 10000,
171174
} __lwip_op;
172175

@@ -230,6 +233,8 @@ extern void __real_raw_remove(struct raw_pcb *pcb);
230233
extern struct netif *__real_netif_add(struct netif *netif, const ip4_addr_t *ipaddr, const ip4_addr_t *netmask, const ip4_addr_t *gw, void *state, netif_init_fn init, netif_input_fn input);
231234
extern void __real_netif_remove(struct netif *netif);
232235
extern err_t __real_ethernet_input(struct pbuf *p, struct netif *netif);
236+
extern int __real_cyw43_wifi_join(cyw43_t *self, size_t ssid_len, const uint8_t *ssid, size_t key_len, const uint8_t *key, uint32_t auth_type, const uint8_t *bssid, uint32_t channel);
237+
extern int __real_cyw43_wifi_leave(cyw43_t *self, int itf);
233238

234239

235240
typedef struct {
@@ -568,6 +573,24 @@ typedef struct {
568573
err_t *ret;
569574
} __ethernet_input_req;
570575

576+
typedef struct {
577+
cyw43_t *self;
578+
size_t ssid_len;
579+
const uint8_t *ssid;
580+
size_t key_len;
581+
const uint8_t *key;
582+
uint32_t auth_type;
583+
const uint8_t *bssid;
584+
uint32_t channel;
585+
int *ret;
586+
} __cyw43_wifi_join_req;
587+
588+
typedef struct {
589+
cyw43_t *self;
590+
int itf;
591+
int *ret;
592+
} __cyw43_wifi_leave_req;
593+
571594
// Run a callback in the LWIP thread (i.e. for Ethernet device polling and packet reception)
572595
// When in an interrupt, need to pass in a heap-allocated buffer
573596
typedef struct {

cores/rp2040/sdkoverride/cyw43_driver_freertos.cpp

Lines changed: 0 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -178,54 +178,6 @@ extern "C" void __wrap_cyw43_delay_us(uint32_t us) {
178178
delayMicroseconds(us);
179179
}
180180

181-
182-
183-
static int this_cyw43_arch_wifi_connect_bssid_until(const char *ssid, const uint8_t *bssid, const char *pw, uint32_t auth, uint32_t timeout_ms) {
184-
uint32_t start = millis();
185-
int err = cyw43_arch_wifi_connect_bssid_async(ssid, bssid, pw, auth);
186-
if (err) {
187-
return err;
188-
}
189-
int status = CYW43_LINK_UP + 1;
190-
while (status >= 0 && status != CYW43_LINK_UP) {
191-
int new_status = cyw43_tcpip_link_status(&cyw43_state, CYW43_ITF_STA);
192-
// If there was no network, keep trying
193-
if (new_status == CYW43_LINK_NONET) {
194-
new_status = CYW43_LINK_JOIN;
195-
err = cyw43_arch_wifi_connect_bssid_async(ssid, bssid, pw, auth);
196-
if (err) {
197-
return err;
198-
}
199-
}
200-
if (new_status != status) {
201-
status = new_status;
202-
}
203-
uint32_t delta = millis() - start;
204-
if (delta > timeout_ms) {
205-
return PICO_ERROR_TIMEOUT;
206-
}
207-
// Do polling
208-
//cyw43_arch_poll();
209-
__wrap_cyw43_await_background_or_timeout_us((timeout_ms - delta) * 1000); //cyw43_arch_wait_for_work_until(until);
210-
}
211-
// Turn status into a pico_error_codes, CYW43_LINK_NONET shouldn't happen as we fail with PICO_ERROR_TIMEOUT instead
212-
assert(status == CYW43_LINK_UP || status == CYW43_LINK_BADAUTH || status == CYW43_LINK_FAIL);
213-
if (status == CYW43_LINK_UP) {
214-
return PICO_OK; // success
215-
} else if (status == CYW43_LINK_BADAUTH) {
216-
return PICO_ERROR_BADAUTH;
217-
} else {
218-
return PICO_ERROR_CONNECT_FAILED;
219-
}
220-
}
221-
extern "C" int __wrap_cyw43_arch_wifi_connect_bssid_timeout_ms(const char *ssid, const uint8_t *bssid, const char *pw, uint32_t auth, uint32_t timeout_ms) {
222-
return this_cyw43_arch_wifi_connect_bssid_until(ssid, bssid, pw, auth, timeout_ms); //make_timeout_time_ms(timeout_ms));
223-
}
224-
225-
extern "C" int __wrap_cyw43_arch_wifi_connect_timeout_ms(const char *ssid, const char *pw, uint32_t auth, uint32_t timeout_ms) {
226-
return __wrap_cyw43_arch_wifi_connect_bssid_timeout_ms(ssid, nullptr, pw, auth, timeout_ms);
227-
}
228-
229181
extern "C" void __real_cyw43_arch_gpio_put(uint wl_gpio, bool value);
230182
void do_cyw43_arch_gpio_put(void *data) {
231183
uint32_t d = (uint32_t)data;

lib/core_wrap.txt

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,6 @@
7474
-Wl,--wrap=cyw43_cb_process_ethernet
7575
-Wl,--wrap=cyw43_cb_tcpip_set_link_up
7676
-Wl,--wrap=cyw43_cb_tcpip_set_link_down
77-
-Wl,--wrap=cyw43_tcpip_link_status
7877
-Wl,--wrap=cyw43_cb_tcpip_init
7978
-Wl,--wrap=cyw43_cb_tcpip_deinit
8079

@@ -90,7 +89,7 @@
9089
-Wl,--wrap=cyw43_delay_us
9190
-Wl,--wrap=cyw43_post_poll_hook
9291
-Wl,--wrap=cyw43_schedule_internal_poll_dispatch
93-
-Wl,--wrap=cyw43_arch_wifi_connect_bssid_timeout_ms
94-
-Wl,--wrap=cyw43_arch_wifi_connect_timeout_ms
92+
-Wl,--wrap=cyw43_wifi_join
93+
-Wl,--wrap=cyw43_wifi_leave
9594
-Wl,--wrap=cyw43_arch_gpio_put
9695
-Wl,--wrap=btstack_run_loop_async_context_get_instance

libraries/lwIP_CYW43/src/utility/CYW43shim.cpp

Lines changed: 29 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -79,19 +79,38 @@ bool CYW43::begin(const uint8_t* address, netif* netif) {
7979
cyw43_wifi_update_multicast_filter(&cyw43_state, mdnsV6, true);
8080
#endif
8181

82-
if (_bssid[0] | _bssid[1] | _bssid[2] | _bssid[3] | _bssid[4] | _bssid[5]) {
83-
if (cyw43_arch_wifi_connect_bssid_timeout_ms(_ssid, _bssid, _password, authmode, _timeout)) {
84-
return false;
85-
} else {
82+
cyw43_wifi_join(&cyw43_state, strlen(_ssid), (const uint8_t *)_ssid, strlen(_password), (const uint8_t *)_password, authmode, (_bssid[0] | _bssid[1] | _bssid[2] | _bssid[3] | _bssid[4] | _bssid[5]) ? _bssid : nullptr, CYW43_CHANNEL_NONE);
83+
uint32_t start = millis();
84+
while (millis() - start < (long unsigned int)_timeout) {
85+
auto link = cyw43_wifi_link_status(&cyw43_state, 0);
86+
if (link != 1) {
87+
// Some error, we can retry
88+
cyw43_wifi_join(&cyw43_state, strlen(_ssid), (const uint8_t *)_ssid, strlen(_password), (const uint8_t *)_password, authmode, (_bssid[0] | _bssid[1] | _bssid[2] | _bssid[3] | _bssid[4] | _bssid[5]) ? _bssid : nullptr, CYW43_CHANNEL_NONE);
89+
} else if (cyw43_state.wifi_join_state == 1) {
90+
// Link state can == 1 even if the negotiation is ongoing. Check the internal negotiaion state. When it hits 1 we are actually connected
8691
return true;
92+
} else {
93+
delay(50);
8794
}
88-
} else {
89-
if (cyw43_arch_wifi_connect_timeout_ms(_ssid, _password, authmode, _timeout)) {
90-
return false;
95+
}
96+
if (cyw43_wifi_link_status(&cyw43_state, 0) == 1) {
97+
// Now we may have just started a retry and the work is still in progress, or we're connected
98+
if (cyw43_state.wifi_join_state == 1) {
99+
return true; // We succeeded
91100
} else {
92-
return true;
101+
// We're still trying on our last try. Wait for things to change
102+
while (true) {
103+
if (cyw43_wifi_link_status(&cyw43_state, 0) != 1) {
104+
return false;
105+
} else if (cyw43_state.wifi_join_state == 1) {
106+
return true;
107+
} else {
108+
delay(50);
109+
}
110+
}
93111
}
94112
}
113+
return false; // We ended above with a failure
95114
} else {
96115
_itf = 1;
97116
cyw43_arch_enable_ap_mode(_ssid, _password, _password ? CYW43_AUTH_WPA2_AES_PSK : CYW43_AUTH_OPEN);
@@ -102,16 +121,13 @@ bool CYW43::begin(const uint8_t* address, netif* netif) {
102121

103122
void CYW43::end() {
104123
_netif = nullptr;
105-
cyw43_deinit(&cyw43_state);
124+
cyw43_wifi_leave(&cyw43_state, _itf);
106125
}
107-
int fails = 0;
108-
int calls = 0;
126+
109127
uint16_t CYW43::sendFrame(const uint8_t* data, uint16_t datalen) {
110-
calls++;
111128
if (0 == cyw43_send_ethernet(_self, _itf, datalen, data, false)) {
112129
return datalen;
113130
}
114-
fails++;
115131
return 0;
116132
}
117133

libraries/lwIP_Ethernet/src/LwipIntfDev.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -402,6 +402,7 @@ bool LwipIntfDev<RawDev>::begin(const uint8_t* macAddress, const uint16_t mtu) {
402402
}
403403

404404
if (!RawDev::begin(_macAddress, &_netif)) {
405+
netif_remove(&_netif);
405406
return false;
406407
}
407408

@@ -420,6 +421,7 @@ bool LwipIntfDev<RawDev>::begin(const uint8_t* macAddress, const uint16_t mtu) {
420421
break;
421422

422423
case ERR_IF:
424+
netif_remove(&_netif);
423425
return false;
424426

425427
default:

0 commit comments

Comments
 (0)