diff --git a/locale/circuitpython.pot b/locale/circuitpython.pot index 15d859bf49f..153a283d067 100644 --- a/locale/circuitpython.pot +++ b/locale/circuitpython.pot @@ -4286,10 +4286,6 @@ msgstr "" msgid "%q must be a subclass of %q" msgstr "" -#: shared-bindings/wifi/Monitor.c -msgid "%q out of bounds" -msgstr "" - #: shared-bindings/wifi/Radio.c msgid "Invalid hex password" msgstr "" diff --git a/ports/espressif/common-hal/wifi/Monitor.c b/ports/espressif/common-hal/wifi/Monitor.c index 635ba7a5a67..f6d0e6e4d8f 100644 --- a/ports/espressif/common-hal/wifi/Monitor.c +++ b/ports/espressif/common-hal/wifi/Monitor.c @@ -9,6 +9,7 @@ #include "py/mpstate.h" #include "py/runtime.h" +#include "bindings/espidf/__init__.h" #include "shared-bindings/wifi/Monitor.h" #include "shared-bindings/wifi/Packet.h" @@ -57,9 +58,26 @@ static void wifi_monitor_cb(void *recv_buf, wifi_promiscuous_pkt_type_t type) { } } +// Tune the radio and return the channel it is on afterwards. Raises +// ValueError for a channel this radio cannot use. Any other failure, for +// example while the station is associated, leaves the radio where it was. +static uint8_t set_channel(uint8_t channel) { + esp_err_t result = esp_wifi_set_channel(channel, WIFI_SECOND_CHAN_NONE); + if (result == ESP_ERR_INVALID_ARG) { + mp_arg_error_invalid(MP_QSTR_channel); + } else if (result != ESP_OK) { + wifi_second_chan_t second; + CHECK_ESP_RESULT(esp_wifi_get_channel(&channel, &second)); + } + return channel; +} + void common_hal_wifi_monitor_construct(wifi_monitor_obj_t *self, uint8_t channel, size_t queue) { mp_rom_error_text_t monitor_mode_init_error = MP_ERROR_TEXT("monitor init failed"); + // Before anything needs undoing on failure. + channel = set_channel(channel); + self->queue = xQueueCreate(queue, sizeof(monitor_packet_t)); if (!self->queue) { mp_raise_RuntimeError(monitor_mode_init_error); @@ -74,7 +92,6 @@ void common_hal_wifi_monitor_construct(wifi_monitor_obj_t *self, uint8_t channel if (esp_wifi_set_promiscuous(true) != ESP_OK) { mp_raise_RuntimeError(monitor_mode_init_error); } - esp_wifi_set_channel(channel, WIFI_SECOND_CHAN_NONE); self->channel = channel; self->queue_length = queue; @@ -105,8 +122,7 @@ void common_hal_wifi_monitor_deinit(wifi_monitor_obj_t *self) { } void common_hal_wifi_monitor_set_channel(wifi_monitor_obj_t *self, uint8_t channel) { - self->channel = channel; - esp_wifi_set_channel(channel, WIFI_SECOND_CHAN_NONE); + self->channel = set_channel(channel); } mp_obj_t common_hal_wifi_monitor_get_channel(wifi_monitor_obj_t *self) { diff --git a/shared-bindings/wifi/Monitor.c b/shared-bindings/wifi/Monitor.c index fb09c4b4f77..9350a160a07 100644 --- a/shared-bindings/wifi/Monitor.c +++ b/shared-bindings/wifi/Monitor.c @@ -19,7 +19,11 @@ //| def __init__(self, channel: Optional[int] = 1, queue: Optional[int] = 128) -> None: //| """Initialize `wifi.Monitor` singleton. //| -//| :param int channel: The WiFi channel to scan. +//| :param int channel: The WiFi channel to scan. On dual-band radios, +//| 5 GHz channels (36 and above) may also be given. A channel the +//| radio does not support raises `ValueError`. While the station is +//| connected the radio stays on the station's channel, and +//| `channel` reports that channel. //| :param int queue: The queue size for buffering the packet. //| //| """ @@ -35,7 +39,9 @@ static mp_obj_t wifi_monitor_make_new(const mp_obj_type_t *type, size_t n_args, mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); - mp_int_t channel = mp_arg_validate_int_range(args[ARG_channel].u_int, 1, 13, MP_QSTR_channel); + // 165 is the highest channel in the scan pattern. Channels the radio + // doesn't support are rejected by the port rather than here. + mp_int_t channel = mp_arg_validate_int_range(args[ARG_channel].u_int, 1, 165, MP_QSTR_channel); mp_int_t queue = mp_arg_validate_int_min(args[ARG_queue].u_int, 0, MP_QSTR_queue); wifi_monitor_obj_t *self = MP_STATE_VM(wifi_monitor_singleton); @@ -49,17 +55,16 @@ static mp_obj_t wifi_monitor_make_new(const mp_obj_type_t *type, size_t n_args, } //| channel: int -//| """The WiFi channel to scan.""" +//| """The WiFi channel to scan. A channel the radio does not support raises +//| `ValueError`. While the station is connected the radio stays on the +//| station's channel, and this reports that channel.""" static mp_obj_t wifi_monitor_obj_get_channel(mp_obj_t self_in) { return common_hal_wifi_monitor_get_channel(self_in); } MP_DEFINE_CONST_FUN_OBJ_1(wifi_monitor_get_channel_obj, wifi_monitor_obj_get_channel); static mp_obj_t wifi_monitor_obj_set_channel(mp_obj_t self_in, mp_obj_t channel) { - mp_int_t c = mp_obj_get_int(channel); - if (c < 1 || c > 13) { - mp_raise_ValueError_varg(MP_ERROR_TEXT("%q out of bounds"), MP_QSTR_channel); - } + mp_int_t c = mp_arg_validate_int_range(mp_obj_get_int(channel), 1, 165, MP_QSTR_channel); common_hal_wifi_monitor_set_channel(self_in, c); return mp_const_none; }