diff --git a/locale/circuitpython.pot b/locale/circuitpython.pot index 14b0b77019..70432cff8e 100644 --- a/locale/circuitpython.pot +++ b/locale/circuitpython.pot @@ -148,6 +148,10 @@ msgstr "" msgid "%q must be power of 2" msgstr "" +#: shared-bindings/wifi/Monitor.c +msgid "%q out of bounds" +msgstr "" + #: ports/raspberrypi/common-hal/rp2pio/StateMachine.c #: shared-bindings/canio/Match.c msgid "%q out of range" @@ -3570,6 +3574,10 @@ msgstr "" msgid "module not found" msgstr "" +#: ports/espressif/common-hal/wifi/Monitor.c +msgid "monitor init failed" +msgstr "" + #: extmod/ulab/code/numpy/poly.c msgid "more degrees of freedom than data points" msgstr "" diff --git a/ports/espressif/common-hal/wifi/Monitor.c b/ports/espressif/common-hal/wifi/Monitor.c new file mode 100644 index 0000000000..b37219d67b --- /dev/null +++ b/ports/espressif/common-hal/wifi/Monitor.c @@ -0,0 +1,169 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2021 microDev + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include + +#include "py/mpstate.h" +#include "py/runtime.h" + +#include "shared-bindings/wifi/Monitor.h" +#include "shared-bindings/wifi/Packet.h" + +#include "esp_log.h" + +#define MONITOR_PAYLOAD_FCS_LEN (4) +#define MONITOR_QUEUE_TIMEOUT_TICK (0) + +typedef struct { + void *payload; + unsigned channel; + uint32_t length; + signed rssi; +} monitor_packet_t; + +static const char *TAG = "monitor"; + +static void wifi_monitor_cb(void *recv_buf, wifi_promiscuous_pkt_type_t type) { + wifi_promiscuous_pkt_t *pkt = (wifi_promiscuous_pkt_t *)recv_buf; + + // prepare packet + monitor_packet_t packet = { + .channel = pkt->rx_ctrl.channel, + .length = pkt->rx_ctrl.sig_len, + .rssi = pkt->rx_ctrl.rssi, + }; + + // for now, the monitor only dumps the length of the MISC type frame + if (type != WIFI_PKT_MISC && !pkt->rx_ctrl.rx_state) { + packet.length -= MONITOR_PAYLOAD_FCS_LEN; + packet.payload = malloc(packet.length); + if (packet.payload) { + memcpy(packet.payload, pkt->payload, packet.length); + wifi_monitor_obj_t *self = MP_STATE_VM(wifi_monitor_singleton); + if (self->queue) { + // send packet + if (xQueueSendFromISR(self->queue, &packet, NULL) != pdTRUE) { + self->lost++; + free(packet.payload); + ESP_LOGE(TAG, "packet queue full"); + } + } + } else { + ESP_LOGE(TAG, "not enough memory for packet"); + } + } +} + +void common_hal_wifi_monitor_construct(wifi_monitor_obj_t *self, uint8_t channel, size_t queue) { + const compressed_string_t *monitor_mode_init_error = translate("monitor init failed"); + + self->queue = xQueueCreate(queue, sizeof(monitor_packet_t)); + if (!self->queue) { + mp_raise_RuntimeError(monitor_mode_init_error); + } + + // start wifi promicuous mode + wifi_promiscuous_filter_t wifi_filter = { + .filter_mask = WIFI_PROMIS_FILTER_MASK_MGMT, + }; + esp_wifi_set_promiscuous_filter(&wifi_filter); + esp_wifi_set_promiscuous_rx_cb(wifi_monitor_cb); + 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; +} + +bool common_hal_wifi_monitor_deinited(void) { + bool enabled; + return (esp_wifi_get_promiscuous(&enabled) == ESP_ERR_WIFI_NOT_INIT) ? true : !enabled; +} + +void common_hal_wifi_monitor_deinit(wifi_monitor_obj_t *self) { + if (common_hal_wifi_monitor_deinited()) { + return; + } + + // disable wifi promiscuous mode + esp_wifi_set_promiscuous(false); + + // make sure to free all resources in the left items + UBaseType_t left_items = uxQueueMessagesWaiting(self->queue); + monitor_packet_t packet; + while (left_items--) { + xQueueReceive(self->queue, &packet, MONITOR_QUEUE_TIMEOUT_TICK); + free(packet.payload); + } + vQueueDelete(self->queue); + self->queue = NULL; +} + +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); +} + +mp_obj_t common_hal_wifi_monitor_get_channel(wifi_monitor_obj_t *self) { + return MP_OBJ_NEW_SMALL_INT(self->channel); +} + +mp_obj_t common_hal_wifi_monitor_get_queue(wifi_monitor_obj_t *self) { + return mp_obj_new_int_from_uint(self->queue_length); +} + +mp_obj_t common_hal_wifi_monitor_get_lost(wifi_monitor_obj_t *self) { + size_t lost = self->lost; + self->lost = 0; + return mp_obj_new_int_from_uint(lost); +} + +mp_obj_t common_hal_wifi_monitor_get_queued(wifi_monitor_obj_t *self) { + return mp_obj_new_int_from_uint(uxQueueMessagesWaiting(self->queue)); +} + +mp_obj_t common_hal_wifi_monitor_get_packet(wifi_monitor_obj_t *self) { + monitor_packet_t packet; + + if (xQueueReceive(self->queue, &packet, MONITOR_QUEUE_TIMEOUT_TICK) != pdTRUE) { + return (mp_obj_t)&mp_const_empty_dict_obj; + } + + mp_obj_dict_t *dict = MP_OBJ_TO_PTR(mp_obj_new_dict(4)); + + mp_obj_dict_store(dict, cp_enum_find(&wifi_packet_type, PACKET_CH), MP_OBJ_NEW_SMALL_INT(packet.channel)); + + mp_obj_dict_store(dict, cp_enum_find(&wifi_packet_type, PACKET_LEN), MP_OBJ_NEW_SMALL_INT(packet.length)); + + mp_obj_dict_store(dict, cp_enum_find(&wifi_packet_type, PACKET_RAW), mp_obj_new_bytes(packet.payload, packet.length)); + free(packet.payload); + + mp_obj_dict_store(dict, cp_enum_find(&wifi_packet_type, PACKET_RSSI), MP_OBJ_NEW_SMALL_INT(packet.rssi)); + + return MP_OBJ_FROM_PTR(dict); +} diff --git a/ports/espressif/common-hal/wifi/Monitor.h b/ports/espressif/common-hal/wifi/Monitor.h new file mode 100644 index 0000000000..e4e50dddc1 --- /dev/null +++ b/ports/espressif/common-hal/wifi/Monitor.h @@ -0,0 +1,41 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2021 microDev + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef MICROPY_INCLUDED_ESPRESSIF_COMMON_HAL_WIFI_MONITOR_H +#define MICROPY_INCLUDED_ESPRESSIF_COMMON_HAL_WIFI_MONITOR_H + +#include "py/obj.h" +#include "components/esp_wifi/include/esp_wifi.h" + +typedef struct { + mp_obj_base_t base; + uint8_t channel; + size_t lost; + size_t queue_length; + QueueHandle_t queue; +} wifi_monitor_obj_t; + +#endif // MICROPY_INCLUDED_ESPRESSIF_COMMON_HAL_WIFI_MONITOR_H diff --git a/ports/espressif/common-hal/wifi/Radio.c b/ports/espressif/common-hal/wifi/Radio.c index d3849b28b2..bf75cb7624 100644 --- a/ports/espressif/common-hal/wifi/Radio.c +++ b/ports/espressif/common-hal/wifi/Radio.c @@ -101,6 +101,19 @@ void common_hal_wifi_radio_set_enabled(wifi_radio_obj_t *self, bool enabled) { } } +mp_obj_t common_hal_wifi_radio_get_hostname(wifi_radio_obj_t *self) { + const char *hostname = NULL; + esp_netif_get_hostname(self->netif, &hostname); + if (hostname == NULL) { + return mp_const_none; + } + return mp_obj_new_str(hostname, strlen(hostname)); +} + +void common_hal_wifi_radio_set_hostname(wifi_radio_obj_t *self, const char *hostname) { + esp_netif_set_hostname(self->netif, hostname); +} + mp_obj_t common_hal_wifi_radio_get_mac_address(wifi_radio_obj_t *self) { uint8_t mac[MAC_ADDRESS_LENGTH]; esp_wifi_get_mac(ESP_IF_WIFI_STA, mac); @@ -142,19 +155,6 @@ void common_hal_wifi_radio_stop_scanning_networks(wifi_radio_obj_t *self) { self->current_scan = NULL; } -mp_obj_t common_hal_wifi_radio_get_hostname(wifi_radio_obj_t *self) { - const char *hostname = NULL; - esp_netif_get_hostname(self->netif, &hostname); - if (hostname == NULL) { - return mp_const_none; - } - return mp_obj_new_str(hostname, strlen(hostname)); -} - -void common_hal_wifi_radio_set_hostname(wifi_radio_obj_t *self, const char *hostname) { - esp_netif_set_hostname(self->netif, hostname); -} - void common_hal_wifi_radio_start_station(wifi_radio_obj_t *self) { set_mode_station(self, true); } diff --git a/ports/espressif/common-hal/wifi/Radio.h b/ports/espressif/common-hal/wifi/Radio.h index 3f53329324..3c0828bf0b 100644 --- a/ports/espressif/common-hal/wifi/Radio.h +++ b/ports/espressif/common-hal/wifi/Radio.h @@ -57,7 +57,6 @@ typedef struct { uint8_t retries_left; uint8_t starting_retries; uint8_t last_disconnect_reason; - wifi_config_t ap_config; esp_netif_ip_info_t ap_ip_info; esp_netif_t *ap_netif; diff --git a/ports/espressif/common-hal/wifi/__init__.c b/ports/espressif/common-hal/wifi/__init__.c index a39103ce0a..469b379dee 100644 --- a/ports/espressif/common-hal/wifi/__init__.c +++ b/ports/espressif/common-hal/wifi/__init__.c @@ -28,8 +28,10 @@ #include "shared-bindings/wifi/__init__.h" #include "shared-bindings/ipaddress/IPv4Address.h" +#include "shared-bindings/wifi/Monitor.h" #include "shared-bindings/wifi/Radio.h" +#include "py/mpstate.h" #include "py/runtime.h" #include "components/esp_wifi/include/esp_wifi.h" @@ -159,6 +161,7 @@ void wifi_reset(void) { if (!wifi_inited) { return; } + common_hal_wifi_monitor_deinit(MP_STATE_VM(wifi_monitor_singleton)); wifi_radio_obj_t *radio = &common_hal_wifi_radio_obj; common_hal_wifi_radio_set_enabled(radio, false); ESP_ERROR_CHECK(esp_event_handler_instance_unregister(WIFI_EVENT, @@ -172,6 +175,7 @@ void wifi_reset(void) { radio->netif = NULL; esp_netif_destroy(radio->ap_netif); radio->ap_netif = NULL; + wifi_inited = false; } void ipaddress_ipaddress_to_esp_idf(mp_obj_t ip_address, ip_addr_t *esp_ip_address) { diff --git a/py/circuitpy_defns.mk b/py/circuitpy_defns.mk index d4980d78fe..fec2512baf 100644 --- a/py/circuitpy_defns.mk +++ b/py/circuitpy_defns.mk @@ -436,6 +436,7 @@ SRC_COMMON_HAL_ALL = \ watchdog/WatchDogMode.c \ watchdog/WatchDogTimer.c \ watchdog/__init__.c \ + wifi/Monitor.c \ wifi/Network.c \ wifi/Radio.c \ wifi/ScannedNetworks.c \ @@ -480,6 +481,7 @@ $(filter $(SRC_PATTERNS), \ paralleldisplay/ParallelBus.c \ supervisor/RunReason.c \ wifi/AuthMode.c \ + wifi/Packet.c \ ) SRC_BINDINGS_ENUMS += \ diff --git a/py/circuitpy_mpconfig.h b/py/circuitpy_mpconfig.h index ad5797b4d8..a17d0183b1 100644 --- a/py/circuitpy_mpconfig.h +++ b/py/circuitpy_mpconfig.h @@ -328,6 +328,12 @@ extern const struct _mp_obj_module_t nvm_module; #endif #endif +#if CIRCUITPY_WIFI +#define WIFI_MONITOR_ROOT_POINTERS mp_obj_t wifi_monitor_singleton; +#else +#define WIFI_MONITOR_ROOT_POINTERS +#endif + // Define certain native modules with weak links so they can be replaced with Python // implementations. This list may grow over time. @@ -451,6 +457,7 @@ struct _supervisor_allocation_node; KEYPAD_ROOT_POINTERS \ GAMEPAD_ROOT_POINTERS \ BOARD_UART_ROOT_POINTER \ + WIFI_MONITOR_ROOT_POINTERS \ MEMORYMONITOR_ROOT_POINTERS \ vstr_t *repl_line; \ mp_obj_t pew_singleton; \ diff --git a/shared-bindings/wifi/Monitor.c b/shared-bindings/wifi/Monitor.c new file mode 100644 index 0000000000..a9998e7410 --- /dev/null +++ b/shared-bindings/wifi/Monitor.c @@ -0,0 +1,174 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2021 microDev + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "py/mpstate.h" +#include "py/runtime.h" +#include "py/objproperty.h" + +#include "shared-bindings/util.h" +#include "shared-bindings/wifi/Packet.h" +#include "shared-bindings/wifi/Monitor.h" + +//| class Monitor: +//| """For monitoring WiFi packets.""" +//| + +//| 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 queue: The queue size for buffering the packet. +//| +//| """ +//| ... +//| +STATIC mp_obj_t wifi_monitor_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { + enum { ARG_channel, ARG_queue }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_channel, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 1} }, + { MP_QSTR_queue, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 128} }, + }; + + 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); + + if (args[ARG_channel].u_int < 0 || args[ARG_channel].u_int > 13) { + mp_raise_ValueError_varg(translate("%q out of bounds"), MP_QSTR_channel); + } + + if (args[ARG_queue].u_int < 0) { + mp_raise_ValueError_varg(translate("%q out of bounds"), MP_QSTR_channel); + } + + wifi_monitor_obj_t *self = MP_STATE_VM(wifi_monitor_singleton); + if (common_hal_wifi_monitor_deinited()) { + self = m_new_obj(wifi_monitor_obj_t); + self->base.type = &wifi_monitor_type; + common_hal_wifi_monitor_construct(self, args[ARG_channel].u_int, args[ARG_queue].u_int); + MP_STATE_VM(wifi_monitor_singleton) = self; + } + + return MP_OBJ_FROM_PTR(self); +} + +//| channel: int +//| """The WiFi channel to scan.""" +//| +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) { + common_hal_wifi_monitor_set_channel(self_in, mp_obj_get_int(channel)); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_2(wifi_monitor_set_channel_obj, wifi_monitor_obj_set_channel); + +const mp_obj_property_t wifi_monitor_channel_obj = { + .base.type = &mp_type_property, + .proxy = { (mp_obj_t)&wifi_monitor_get_channel_obj, + (mp_obj_t)&wifi_monitor_set_channel_obj, + MP_ROM_NONE }, +}; + +//| queue: int +//| """The queue size for buffering the packet.""" +//| +STATIC mp_obj_t wifi_monitor_obj_get_queue(mp_obj_t self_in) { + return common_hal_wifi_monitor_get_queue(self_in); +} +MP_DEFINE_CONST_FUN_OBJ_1(wifi_monitor_get_queue_obj, wifi_monitor_obj_get_queue); + +const mp_obj_property_t wifi_monitor_queue_obj = { + .base.type = &mp_type_property, + .proxy = { (mp_obj_t)&wifi_monitor_get_queue_obj, + MP_ROM_NONE, + MP_ROM_NONE }, +}; + +//| def deinit(self) -> None: +//| """De-initialize `wifi.Monitor` singleton.""" +//| ... +//| +STATIC mp_obj_t wifi_monitor_obj_deinit(mp_obj_t self_in) { + common_hal_wifi_monitor_deinit(self_in); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(wifi_monitor_deinit_obj, wifi_monitor_obj_deinit); + +//| def lost(self) -> int: +//| """Returns the packet loss count. The counter resets after each poll.""" +//| ... +//| +STATIC mp_obj_t wifi_monitor_obj_get_lost(mp_obj_t self_in) { + return common_hal_wifi_monitor_get_lost(self_in); +} +MP_DEFINE_CONST_FUN_OBJ_1(wifi_monitor_lost_obj, wifi_monitor_obj_get_lost); + +//| def queued(self) -> int: +//| """Returns the packet queued count.""" +//| ... +//| +STATIC mp_obj_t wifi_monitor_obj_get_queued(mp_obj_t self_in) { + if (common_hal_wifi_monitor_deinited()) { + return mp_obj_new_int_from_uint(0); + } + return common_hal_wifi_monitor_get_queued(self_in); +} +MP_DEFINE_CONST_FUN_OBJ_1(wifi_monitor_queued_obj, wifi_monitor_obj_get_queued); + +//| def packet(self) -> dict: +//| """Returns the monitor packet.""" +//| ... +//| +STATIC mp_obj_t wifi_monitor_obj_get_packet(mp_obj_t self_in) { + if (common_hal_wifi_monitor_deinited()) { + raise_deinited_error(); + } + return common_hal_wifi_monitor_get_packet(self_in); +} +MP_DEFINE_CONST_FUN_OBJ_1(wifi_monitor_packet_obj, wifi_monitor_obj_get_packet); + +STATIC const mp_rom_map_elem_t wifi_monitor_locals_dict_table[] = { + // properties + { MP_ROM_QSTR(MP_QSTR_channel), MP_ROM_PTR(&wifi_monitor_channel_obj) }, + { MP_ROM_QSTR(MP_QSTR_queue), MP_ROM_PTR(&wifi_monitor_queue_obj) }, + + // functions + { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&wifi_monitor_deinit_obj) }, + { MP_ROM_QSTR(MP_QSTR_lost), MP_ROM_PTR(&wifi_monitor_lost_obj) }, + { MP_ROM_QSTR(MP_QSTR_queued), MP_ROM_PTR(&wifi_monitor_queued_obj) }, + { MP_ROM_QSTR(MP_QSTR_packet), MP_ROM_PTR(&wifi_monitor_packet_obj) }, +}; +STATIC MP_DEFINE_CONST_DICT(wifi_monitor_locals_dict, wifi_monitor_locals_dict_table); + +const mp_obj_type_t wifi_monitor_type = { + .base = { &mp_type_type }, + .name = MP_QSTR_Monitor, + .make_new = wifi_monitor_make_new, + .locals_dict = (mp_obj_t)&wifi_monitor_locals_dict, +}; diff --git a/shared-bindings/wifi/Monitor.h b/shared-bindings/wifi/Monitor.h new file mode 100644 index 0000000000..38c52a05e7 --- /dev/null +++ b/shared-bindings/wifi/Monitor.h @@ -0,0 +1,50 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2021 microDev + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_WIFI_MONITOR_H +#define MICROPY_INCLUDED_SHARED_BINDINGS_WIFI_MONITOR_H + +#include "common-hal/wifi/Monitor.h" + +const mp_obj_type_t wifi_monitor_type; + +void common_hal_wifi_monitor_construct(wifi_monitor_obj_t *self, + uint8_t channel, size_t queue); +void common_hal_wifi_monitor_deinit(wifi_monitor_obj_t *self); +bool common_hal_wifi_monitor_deinited(void); + +void common_hal_wifi_monitor_set_channel(wifi_monitor_obj_t *self, uint8_t channel); +mp_obj_t common_hal_wifi_monitor_get_channel(wifi_monitor_obj_t *self); + +mp_obj_t common_hal_wifi_monitor_get_queue(wifi_monitor_obj_t *self); + +mp_obj_t common_hal_wifi_monitor_get_lost(wifi_monitor_obj_t *self); + +mp_obj_t common_hal_wifi_monitor_get_queued(wifi_monitor_obj_t *self); + +mp_obj_t common_hal_wifi_monitor_get_packet(wifi_monitor_obj_t *self); + +#endif // MICROPY_INCLUDED_SHARED_BINDINGS_WIFI_MONITOR_H diff --git a/shared-bindings/wifi/Packet.c b/shared-bindings/wifi/Packet.c new file mode 100644 index 0000000000..d21c8b0639 --- /dev/null +++ b/shared-bindings/wifi/Packet.c @@ -0,0 +1,70 @@ +/* + * This file is part of the Micro Python project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2021 microDev + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "py/enum.h" + +#include "shared-bindings/wifi/Packet.h" + +MAKE_ENUM_VALUE(wifi_packet_type, packet, CH, PACKET_CH); +MAKE_ENUM_VALUE(wifi_packet_type, packet, LEN, PACKET_LEN); +MAKE_ENUM_VALUE(wifi_packet_type, packet, RAW, PACKET_RAW); +MAKE_ENUM_VALUE(wifi_packet_type, packet, RSSI, PACKET_RSSI); + +//| class Packet: +//| """The packet parameters.""" +//| +//| CH: object +//| """The packet's channel.""" +//| +//| LEN: object +//| """The packet's length.""" +//| +//| RAW: object +//| """The packet's payload.""" +//| +//| RSSI: object +//| """The packet's rssi.""" +//| +MAKE_ENUM_MAP(wifi_packet) { + MAKE_ENUM_MAP_ENTRY(packet, CH), + MAKE_ENUM_MAP_ENTRY(packet, LEN), + MAKE_ENUM_MAP_ENTRY(packet, RAW), + MAKE_ENUM_MAP_ENTRY(packet, RSSI), +}; +STATIC MP_DEFINE_CONST_DICT(wifi_packet_locals_dict, wifi_packet_locals_table); + +MAKE_PRINTER(wifi, wifi_packet); + +const mp_obj_type_t wifi_packet_type = { + { &mp_type_type }, + .name = MP_QSTR_Packet, + .print = wifi_packet_print, + .locals_dict = (mp_obj_t)&wifi_packet_locals_dict, + .flags = MP_TYPE_FLAG_EXTENDED, + MP_TYPE_EXTENDED_FIELDS( + .unary_op = mp_generic_unary_op, + ), +}; diff --git a/shared-bindings/wifi/Packet.h b/shared-bindings/wifi/Packet.h new file mode 100644 index 0000000000..09dfddfc98 --- /dev/null +++ b/shared-bindings/wifi/Packet.h @@ -0,0 +1,41 @@ +/* + * This file is part of the Micro Python project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2021 microDev + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_WIFI_PACKET_H +#define MICROPY_INCLUDED_SHARED_BINDINGS_WIFI_PACKET_H + +#include "py/enum.h" + +typedef enum { + PACKET_CH, + PACKET_LEN, + PACKET_RAW, + PACKET_RSSI, +} wifi_packet_t; + +extern const mp_obj_type_t wifi_packet_type; + +#endif // MICROPY_INCLUDED_SHARED_BINDINGS_WIFI_PACKET_H diff --git a/shared-bindings/wifi/Radio.c b/shared-bindings/wifi/Radio.c index 0983706919..9f6c62fce9 100644 --- a/shared-bindings/wifi/Radio.c +++ b/shared-bindings/wifi/Radio.c @@ -74,6 +74,47 @@ const mp_obj_property_t wifi_radio_enabled_obj = { MP_ROM_NONE }, }; +//| hostname: ReadableBuffer +//| """Hostname for wifi interface. When the hostname is altered after interface started/connected +//| the changes would only be reflected once the interface restarts/reconnects.""" +//| +STATIC mp_obj_t wifi_radio_get_hostname(mp_obj_t self_in) { + wifi_radio_obj_t *self = MP_OBJ_TO_PTR(self_in); + return common_hal_wifi_radio_get_hostname(self); +} +MP_DEFINE_CONST_FUN_OBJ_1(wifi_radio_get_hostname_obj, wifi_radio_get_hostname); + +STATIC mp_obj_t wifi_radio_set_hostname(mp_obj_t self_in, mp_obj_t hostname_in) { + mp_buffer_info_t hostname; + mp_get_buffer_raise(hostname_in, &hostname, MP_BUFFER_READ); + + if (hostname.len < 1 || hostname.len > 253) { + mp_raise_ValueError(translate("Hostname must be between 1 and 253 characters")); + } + + #ifndef CONFIG_IDF_TARGET_ESP32C3 + regex_t regex; // validate hostname according to RFC 1123 + regcomp(®ex,"^(([a-z0-9]|[a-z0-9][a-z0-9\\-]{0,61}[a-z0-9])\\.)*([a-z0-9]|[a-z0-9][a-z0-9\\-]{0,61}[a-z0-9])$", REG_EXTENDED | REG_ICASE | REG_NOSUB); + if (regexec(®ex, hostname.buf, 0, NULL, 0)) { + mp_raise_ValueError(translate("invalid hostname")); + } + regfree(®ex); + #endif + + wifi_radio_obj_t *self = MP_OBJ_TO_PTR(self_in); + common_hal_wifi_radio_set_hostname(self, hostname.buf); + + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_2(wifi_radio_set_hostname_obj, wifi_radio_set_hostname); + +const mp_obj_property_t wifi_radio_hostname_obj = { + .base.type = &mp_type_property, + .proxy = {(mp_obj_t)&wifi_radio_get_hostname_obj, + (mp_obj_t)&wifi_radio_set_hostname_obj, + MP_ROM_NONE}, +}; + //| mac_address: bytes //| """MAC address of the wifi radio station. (read-only)""" //| @@ -132,47 +173,6 @@ STATIC mp_obj_t wifi_radio_stop_scanning_networks(mp_obj_t self_in) { } STATIC MP_DEFINE_CONST_FUN_OBJ_1(wifi_radio_stop_scanning_networks_obj, wifi_radio_stop_scanning_networks); -//| hostname: ReadableBuffer -//| """Hostname for wifi interface. When the hostname is altered after interface started/connected -//| the changes would only be reflected once the interface restarts/reconnects.""" -//| -STATIC mp_obj_t wifi_radio_get_hostname(mp_obj_t self_in) { - wifi_radio_obj_t *self = MP_OBJ_TO_PTR(self_in); - return common_hal_wifi_radio_get_hostname(self); -} -MP_DEFINE_CONST_FUN_OBJ_1(wifi_radio_get_hostname_obj, wifi_radio_get_hostname); - -STATIC mp_obj_t wifi_radio_set_hostname(mp_obj_t self_in, mp_obj_t hostname_in) { - mp_buffer_info_t hostname; - mp_get_buffer_raise(hostname_in, &hostname, MP_BUFFER_READ); - - if (hostname.len < 1 || hostname.len > 253) { - mp_raise_ValueError(translate("Hostname must be between 1 and 253 characters")); - } - - #ifndef CONFIG_IDF_TARGET_ESP32C3 - regex_t regex; // validate hostname according to RFC 1123 - regcomp(®ex,"^(([a-z0-9]|[a-z0-9][a-z0-9\\-]{0,61}[a-z0-9])\\.)*([a-z0-9]|[a-z0-9][a-z0-9\\-]{0,61}[a-z0-9])$", REG_EXTENDED | REG_ICASE | REG_NOSUB); - if (regexec(®ex, hostname.buf, 0, NULL, 0)) { - mp_raise_ValueError(translate("invalid hostname")); - } - regfree(®ex); - #endif - - wifi_radio_obj_t *self = MP_OBJ_TO_PTR(self_in); - common_hal_wifi_radio_set_hostname(self, hostname.buf); - - return mp_const_none; -} -MP_DEFINE_CONST_FUN_OBJ_2(wifi_radio_set_hostname_obj, wifi_radio_set_hostname); - -const mp_obj_property_t wifi_radio_hostname_obj = { - .base.type = &mp_type_property, - .proxy = {(mp_obj_t)&wifi_radio_get_hostname_obj, - (mp_obj_t)&wifi_radio_set_hostname_obj, - MP_ROM_NONE}, -}; - //| def start_station(self) -> None: //| """Starts a Station.""" //| ... @@ -503,18 +503,20 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_KW(wifi_radio_ping_obj, 1, wifi_radio_ping); STATIC const mp_rom_map_elem_t wifi_radio_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_enabled), MP_ROM_PTR(&wifi_radio_enabled_obj) }, + + { MP_ROM_QSTR(MP_QSTR_hostname), MP_ROM_PTR(&wifi_radio_hostname_obj) }, + { MP_ROM_QSTR(MP_QSTR_mac_address), MP_ROM_PTR(&wifi_radio_mac_address_obj) }, { MP_ROM_QSTR(MP_QSTR_mac_address_ap), MP_ROM_PTR(&wifi_radio_mac_address_ap_obj) }, { MP_ROM_QSTR(MP_QSTR_start_scanning_networks), MP_ROM_PTR(&wifi_radio_start_scanning_networks_obj) }, { MP_ROM_QSTR(MP_QSTR_stop_scanning_networks), MP_ROM_PTR(&wifi_radio_stop_scanning_networks_obj) }, - { MP_ROM_QSTR(MP_QSTR_hostname), MP_ROM_PTR(&wifi_radio_hostname_obj) }, - { MP_ROM_QSTR(MP_QSTR_start_station), MP_ROM_PTR(&wifi_radio_start_station_obj) }, { MP_ROM_QSTR(MP_QSTR_stop_station), MP_ROM_PTR(&wifi_radio_stop_station_obj) }, - { MP_ROM_QSTR(MP_QSTR_stop_ap), MP_ROM_PTR(&wifi_radio_stop_ap_obj) }, + { MP_ROM_QSTR(MP_QSTR_start_ap), MP_ROM_PTR(&wifi_radio_start_ap_obj) }, + { MP_ROM_QSTR(MP_QSTR_stop_ap), MP_ROM_PTR(&wifi_radio_stop_ap_obj) }, { MP_ROM_QSTR(MP_QSTR_connect), MP_ROM_PTR(&wifi_radio_connect_obj) }, // { MP_ROM_QSTR(MP_QSTR_connect_to_enterprise), MP_ROM_PTR(&wifi_radio_connect_to_enterprise_obj) }, diff --git a/shared-bindings/wifi/Radio.h b/shared-bindings/wifi/Radio.h index 5716d155f4..eeeffa2f94 100644 --- a/shared-bindings/wifi/Radio.h +++ b/shared-bindings/wifi/Radio.h @@ -85,6 +85,7 @@ extern void common_hal_wifi_radio_stop_scanning_networks(wifi_radio_obj_t *self) extern void common_hal_wifi_radio_start_station(wifi_radio_obj_t *self); extern void common_hal_wifi_radio_stop_station(wifi_radio_obj_t *self); + extern void common_hal_wifi_radio_start_ap(wifi_radio_obj_t *self, uint8_t *ssid, size_t ssid_len, uint8_t *password, size_t password_len, uint8_t channel, uint8_t authmode); extern void common_hal_wifi_radio_stop_ap(wifi_radio_obj_t *self); diff --git a/shared-bindings/wifi/__init__.c b/shared-bindings/wifi/__init__.c index ef72dced1f..0f9dee8462 100644 --- a/shared-bindings/wifi/__init__.c +++ b/shared-bindings/wifi/__init__.c @@ -24,11 +24,11 @@ * THE SOFTWARE. */ -#include "py/objexcept.h" -#include "py/runtime.h" #include "shared-bindings/wifi/__init__.h" #include "shared-bindings/wifi/AuthMode.h" #include "shared-bindings/wifi/Network.h" +#include "shared-bindings/wifi/Monitor.h" +#include "shared-bindings/wifi/Packet.h" #include "shared-bindings/wifi/Radio.h" //| """ @@ -40,7 +40,6 @@ //| This object is the sole instance of `wifi.Radio`.""" //| - // Called when wifi is imported. STATIC mp_obj_t wifi___init__(void) { common_hal_wifi_init(); @@ -48,24 +47,25 @@ STATIC mp_obj_t wifi___init__(void) { } STATIC MP_DEFINE_CONST_FUN_OBJ_0(wifi___init___obj, wifi___init__); - STATIC const mp_rom_map_elem_t wifi_module_globals_table[] = { + // Name { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_wifi) }, - { MP_ROM_QSTR(MP_QSTR_Radio), MP_ROM_PTR(&wifi_radio_type) }, - { MP_ROM_QSTR(MP_QSTR_Network), MP_ROM_PTR(&wifi_network_type) }, - { MP_ROM_QSTR(MP_QSTR_AuthMode), MP_ROM_PTR(&wifi_authmode_type) }, - - // Properties - { MP_ROM_QSTR(MP_QSTR_radio), MP_ROM_PTR(&common_hal_wifi_radio_obj) }, // Initialization { MP_ROM_QSTR(MP_QSTR___init__), MP_ROM_PTR(&wifi___init___obj) }, + // Classes + { MP_ROM_QSTR(MP_QSTR_AuthMode), MP_ROM_PTR(&wifi_authmode_type) }, + { MP_ROM_QSTR(MP_QSTR_Monitor), MP_ROM_PTR(&wifi_monitor_type) }, + { MP_ROM_QSTR(MP_QSTR_Network), MP_ROM_PTR(&wifi_network_type) }, + { MP_ROM_QSTR(MP_QSTR_Packet), MP_ROM_PTR(&wifi_packet_type) }, + { MP_ROM_QSTR(MP_QSTR_Radio), MP_ROM_PTR(&wifi_radio_type) }, + + // Properties + { MP_ROM_QSTR(MP_QSTR_radio), MP_ROM_PTR(&common_hal_wifi_radio_obj) }, }; - STATIC MP_DEFINE_CONST_DICT(wifi_module_globals, wifi_module_globals_table); - const mp_obj_module_t wifi_module = { .base = { &mp_type_module }, .globals = (mp_obj_dict_t *)&wifi_module_globals, diff --git a/shared-bindings/wifi/__init__.h b/shared-bindings/wifi/__init__.h index 124c0bc491..e626727e77 100644 --- a/shared-bindings/wifi/__init__.h +++ b/shared-bindings/wifi/__init__.h @@ -27,8 +27,6 @@ #ifndef MICROPY_INCLUDED_SHARED_BINDINGS_WIFI___INIT___H #define MICROPY_INCLUDED_SHARED_BINDINGS_WIFI___INIT___H -#include "py/objlist.h" - #include "shared-bindings/wifi/Radio.h" extern wifi_radio_obj_t common_hal_wifi_radio_obj;