diff --git a/ports/espressif/common-hal/wifi/Radio.c b/ports/espressif/common-hal/wifi/Radio.c index 51d4913926f..cc92a41705a 100644 --- a/ports/espressif/common-hal/wifi/Radio.c +++ b/ports/espressif/common-hal/wifi/Radio.c @@ -25,6 +25,7 @@ #include "components/esp_netif/include/esp_netif_net_stack.h" #include "components/esp_wifi/include/esp_wifi.h" +#include "soc/soc_caps.h" #include "components/lwip/include/apps/ping/ping_sock.h" #include "lwip/sockets.h" @@ -94,6 +95,11 @@ void common_hal_wifi_radio_set_enabled(wifi_radio_obj_t *self, bool enabled) { } if (!self->started && enabled) { ESP_ERROR_CHECK(esp_wifi_start()); + #if defined(SOC_WIFI_SUPPORT_5G) && SOC_WIFI_SUPPORT_5G + // Dual-band radios default to 2.4 GHz only. Enable both bands so that + // 5 GHz networks are visible to scans and can be connected to. + ESP_ERROR_CHECK(esp_wifi_set_band_mode(WIFI_BAND_MODE_AUTO)); + #endif self->started = true; common_hal_wifi_radio_set_tx_power(self, CIRCUITPY_WIFI_DEFAULT_TX_POWER); return; diff --git a/ports/espressif/common-hal/wifi/ScannedNetworks.c b/ports/espressif/common-hal/wifi/ScannedNetworks.c index 02edb9bd036..0a87d3ab342 100644 --- a/ports/espressif/common-hal/wifi/ScannedNetworks.c +++ b/ports/espressif/common-hal/wifi/ScannedNetworks.c @@ -18,6 +18,7 @@ #include "shared-bindings/wifi/ScannedNetworks.h" #include "components/esp_wifi/include/esp_wifi.h" +#include "soc/soc_caps.h" static void wifi_scannednetworks_done(wifi_scannednetworks_obj_t *self) { self->done = true; @@ -111,29 +112,38 @@ mp_obj_t common_hal_wifi_scannednetworks_next(wifi_scannednetworks_obj_t *self) } // We don't do a linear scan so that we look at a variety of spectrum up front. +#if defined(SOC_WIFI_SUPPORT_5G) && SOC_WIFI_SUPPORT_5G +// 2.4 GHz first, then the 5 GHz U-NII bands. DFS channels are omitted: +// they require radar detection before transmitting. +static uint8_t scan_pattern[] = {6, 1, 11, 3, 9, 13, 2, 4, 8, 12, 5, 7, 10, 14, + 36, 40, 44, 48, 149, 153, 157, 161, 165, 0}; +#else static uint8_t scan_pattern[] = {6, 1, 11, 3, 9, 13, 2, 4, 8, 12, 5, 7, 10, 14, 0}; +#endif void wifi_scannednetworks_scan_next_channel(wifi_scannednetworks_obj_t *self) { - // There is no channel 0, so use that as a flag to indicate we've run out of channels to scan. - uint8_t next_channel = 0; - while (self->current_channel_index < sizeof(scan_pattern)) { - next_channel = scan_pattern[self->current_channel_index]; - self->current_channel_index++; - // Scan only channels that are in the specified range. - if (self->start_channel <= next_channel && next_channel <= self->end_channel) { - break; + while (true) { + // There is no channel 0, so use that as a flag to indicate we've run out of channels to scan. + uint8_t next_channel = 0; + while (self->current_channel_index < sizeof(scan_pattern)) { + next_channel = scan_pattern[self->current_channel_index]; + self->current_channel_index++; + // Scan only channels that are in the specified range. + if (self->start_channel <= next_channel && next_channel <= self->end_channel) { + break; + } } - } - wifi_scan_config_t config = { 0 }; - config.channel = next_channel; - if (next_channel == 0) { - wifi_scannednetworks_done(self); - } else { - esp_err_t result = esp_wifi_scan_start(&config, false); - if (result != ESP_OK) { + if (next_channel == 0) { wifi_scannednetworks_done(self); - } else { + return; + } + wifi_scan_config_t config = { 0 }; + config.channel = next_channel; + // The radio rejects channels outside the band it is set to. Skip those + // rather than ending the scan, so the rest of the pattern still runs. + if (esp_wifi_scan_start(&config, false) == ESP_OK) { self->channel_scan_in_progress = true; + return; } } } diff --git a/shared-bindings/wifi/Radio.c b/shared-bindings/wifi/Radio.c index 9a7d445fd04..179564d5f92 100644 --- a/shared-bindings/wifi/Radio.c +++ b/shared-bindings/wifi/Radio.c @@ -254,10 +254,13 @@ MP_PROPERTY_GETTER(wifi_radio_mac_address_ap_obj, #endif //| def start_scanning_networks( -//| self, *, start_channel: int = 1, stop_channel: int = 11 +//| self, *, start_channel: int = 1, stop_channel: int = 165 //| ) -> Iterable[Network]: //| """Scans for available wifi networks over the given channel range. Make sure the channels are allowed in your country. //| +//| On dual-band radios, 5 GHz channels (36 and above) may also be given. +//| Channel numbers that the radio does not support are skipped. +//| //| .. note:: //| //| In the raspberrypi port (RP2040 CYW43), ``start_channel`` and ``stop_channel`` are ignored. @@ -268,17 +271,19 @@ static mp_obj_t wifi_radio_start_scanning_networks(size_t n_args, const mp_obj_t enum { ARG_start_channel, ARG_stop_channel }; static const mp_arg_t allowed_args[] = { { MP_QSTR_start_channel, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 1} }, - { MP_QSTR_stop_channel, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 11} }, + { MP_QSTR_stop_channel, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 165} }, }; wifi_radio_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + // 165 is the highest 5 GHz channel number. Channels the radio doesn't + // support are skipped while scanning rather than rejected here. uint8_t start_channel = - (uint8_t)mp_arg_validate_int_range(args[ARG_start_channel].u_int, 1, 14, MP_QSTR_start_channel); + (uint8_t)mp_arg_validate_int_range(args[ARG_start_channel].u_int, 1, 165, MP_QSTR_start_channel); uint8_t stop_channel = - (uint8_t)mp_arg_validate_int_range(args[ARG_stop_channel].u_int, 1, 14, MP_QSTR_stop_channel); + (uint8_t)mp_arg_validate_int_range(args[ARG_stop_channel].u_int, 1, 165, MP_QSTR_stop_channel); // Swap if in reverse order, without complaining. if (start_channel > stop_channel) { uint8_t temp = stop_channel;