Skip to content

Commit 49b83ed

Browse files
projectgusdpgeorge
authored andcommitted
extmod/network_cyw43: Allow configuring active AP interface.
Configuring the AP for cyw43 writes to some buffers that are only sent to the modem when the interface is brought up. This means you can't configure the AP after calling active(True), the new settings seem to be accepted but the radio doesn't change. This is different to the WLAN behaviour on other ports. The esp8266 port requires calling active(True) on the AP before configuring, even. Fix this by bouncing the AP interface after a config change, if it's active. Configuring with active(False) still works the same as before. Adds a static variable to track interface active state, rather than relying on the LWIP interface state. This is because the interface state is updated by a driver callback and there's a race: if code calls active(True) and then config(a=b) then the driver doesn't know it's active yet and the changes aren't correctly applied. It is possible this pattern will cause the AP to come up briefly with the default "PICOabcd" SSID before being reconfigured, however (due to the aforementioned race condition) it seems like this may not happen at all before the new config is applied. This work was funded through GitHub Sponsors. Signed-off-by: Angus Gratton <[email protected]>
1 parent 4f4d683 commit 49b83ed

File tree

1 file changed

+27
-3
lines changed

1 file changed

+27
-3
lines changed

extmod/network_cyw43.c

+27-3
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,10 @@ typedef struct _network_cyw43_obj_t {
6060
static const network_cyw43_obj_t network_cyw43_wl_sta = { { &mp_network_cyw43_type }, &cyw43_state, CYW43_ITF_STA };
6161
static const network_cyw43_obj_t network_cyw43_wl_ap = { { &mp_network_cyw43_type }, &cyw43_state, CYW43_ITF_AP };
6262

63+
// Avoid race conditions with callbacks by tracking the last up or down request
64+
// we have made for each interface.
65+
static bool if_active[2];
66+
6367
static void network_cyw43_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
6468
network_cyw43_obj_t *self = MP_OBJ_TO_PTR(self_in);
6569
struct netif *netif = &self->cyw->netif[self->itf];
@@ -122,6 +126,10 @@ static MP_DEFINE_CONST_FUN_OBJ_3(network_cyw43_ioctl_obj, network_cyw43_ioctl);
122126
/*******************************************************************************/
123127
// network API
124128

129+
static uint32_t get_country_code(void) {
130+
return CYW43_COUNTRY(mod_network_country_code[0], mod_network_country_code[1], 0);
131+
}
132+
125133
static mp_obj_t network_cyw43_deinit(mp_obj_t self_in) {
126134
network_cyw43_obj_t *self = MP_OBJ_TO_PTR(self_in);
127135
cyw43_deinit(self->cyw);
@@ -132,10 +140,11 @@ static MP_DEFINE_CONST_FUN_OBJ_1(network_cyw43_deinit_obj, network_cyw43_deinit)
132140
static mp_obj_t network_cyw43_active(size_t n_args, const mp_obj_t *args) {
133141
network_cyw43_obj_t *self = MP_OBJ_TO_PTR(args[0]);
134142
if (n_args == 1) {
135-
return mp_obj_new_bool(cyw43_tcpip_link_status(self->cyw, self->itf));
143+
return mp_obj_new_bool(if_active[self->itf]);
136144
} else {
137-
uint32_t country = CYW43_COUNTRY(mod_network_country_code[0], mod_network_country_code[1], 0);
138-
cyw43_wifi_set_up(self->cyw, self->itf, mp_obj_is_true(args[1]), country);
145+
bool value = mp_obj_is_true(args[1]);
146+
cyw43_wifi_set_up(self->cyw, self->itf, value, get_country_code());
147+
if_active[self->itf] = value;
139148
return mp_const_none;
140149
}
141150
}
@@ -457,6 +466,10 @@ static mp_obj_t network_cyw43_config(size_t n_args, const mp_obj_t *args, mp_map
457466
mp_raise_TypeError(MP_ERROR_TEXT("can't specify pos and kw args"));
458467
}
459468

469+
// A number of these options only update buffers in memory, and
470+
// won't do anything until the interface is cycled down and back up
471+
bool cycle_active = false;
472+
460473
for (size_t i = 0; i < kwargs->alloc; ++i) {
461474
if (MP_MAP_SLOT_IS_FILLED(kwargs, i)) {
462475
mp_map_elem_t *e = &kwargs->table[i];
@@ -469,13 +482,15 @@ static mp_obj_t network_cyw43_config(size_t n_args, const mp_obj_t *args, mp_map
469482
}
470483
case MP_QSTR_channel: {
471484
cyw43_wifi_ap_set_channel(self->cyw, mp_obj_get_int(e->value));
485+
cycle_active = true;
472486
break;
473487
}
474488
case MP_QSTR_ssid:
475489
case MP_QSTR_essid: {
476490
size_t len;
477491
const char *str = mp_obj_str_get_data(e->value, &len);
478492
cyw43_wifi_ap_set_ssid(self->cyw, len, (const uint8_t *)str);
493+
cycle_active = true;
479494
break;
480495
}
481496
case MP_QSTR_monitor: {
@@ -495,13 +510,15 @@ static mp_obj_t network_cyw43_config(size_t n_args, const mp_obj_t *args, mp_map
495510
}
496511
case MP_QSTR_security: {
497512
cyw43_wifi_ap_set_auth(self->cyw, mp_obj_get_int(e->value));
513+
cycle_active = true;
498514
break;
499515
}
500516
case MP_QSTR_key:
501517
case MP_QSTR_password: {
502518
size_t len;
503519
const char *str = mp_obj_str_get_data(e->value, &len);
504520
cyw43_wifi_ap_set_password(self->cyw, len, (const uint8_t *)str);
521+
cycle_active = true;
505522
break;
506523
}
507524
case MP_QSTR_pm: {
@@ -531,6 +548,13 @@ static mp_obj_t network_cyw43_config(size_t n_args, const mp_obj_t *args, mp_map
531548
}
532549
}
533550

551+
// If the interface is already active, cycle it down and up
552+
if (cycle_active && if_active[self->itf]) {
553+
uint32_t country = get_country_code();
554+
cyw43_wifi_set_up(self->cyw, self->itf, false, country);
555+
cyw43_wifi_set_up(self->cyw, self->itf, true, country);
556+
}
557+
534558
return mp_const_none;
535559
}
536560
}

0 commit comments

Comments
 (0)