From 6c3cdceb45677d0914d2411fe7e2f245ce465c5a Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Wed, 31 Aug 2022 10:13:39 -0500 Subject: [PATCH] Implement scan, connect, ping My pings go out, and then they come back ```py import os import wifi import ipaddress wifi.radio.connect(os.getenv('WIFI_SSID'), os.getenv('WIFI_PASSWORD')) ipv4 = ipaddress.ip_address("8.8.4.4") print("Ping google.com: %f ms" % (wifi.radio.ping(ipv4)*1000)) ``` --- frozen/circuitpython-stage | 2 +- locale/circuitpython.pot | 19 +- mpy-cross/Makefile | 2 + ports/espressif/esp32-camera | 2 +- ports/raspberrypi/Makefile | 22 +- .../raspberry_pi_pico_w/mpconfigboard.mk | 1 + ports/raspberrypi/common-hal/wifi/Monitor.c | 74 ++++ ports/raspberrypi/common-hal/wifi/Monitor.h | 40 ++ ports/raspberrypi/common-hal/wifi/Network.c | 81 ++++ ports/raspberrypi/common-hal/wifi/Network.h | 36 ++ ports/raspberrypi/common-hal/wifi/Radio.c | 311 ++++++++++++++ ports/raspberrypi/common-hal/wifi/Radio.h | 39 ++ .../common-hal/wifi/ScannedNetworks.c | 120 ++++++ .../common-hal/wifi/ScannedNetworks.h | 42 ++ ports/raspberrypi/common-hal/wifi/__init__.c | 124 ++++++ ports/raspberrypi/common-hal/wifi/__init__.h | 37 ++ ports/raspberrypi/lwip_inc/arch/sys_arch.h | 1 + ports/raspberrypi/lwip_inc/lwipopts.h | 92 +++++ ports/raspberrypi/lwip_src/ping.c | 390 ++++++++++++++++++ ports/raspberrypi/lwip_src/ping.h | 25 ++ ports/raspberrypi/mpconfigport.h | 8 + ports/raspberrypi/supervisor/port.c | 15 +- py/objgenerator.c | 3 +- shared-bindings/wifi/Monitor.h | 2 +- shared-bindings/wifi/Network.h | 2 +- shared-bindings/wifi/Radio.c | 2 +- shared-bindings/wifi/Radio.h | 2 +- tools/codeformat.py | 2 + tools/describe | 2 +- 29 files changed, 1472 insertions(+), 26 deletions(-) create mode 100644 ports/raspberrypi/common-hal/wifi/Monitor.c create mode 100644 ports/raspberrypi/common-hal/wifi/Monitor.h create mode 100644 ports/raspberrypi/common-hal/wifi/Network.c create mode 100644 ports/raspberrypi/common-hal/wifi/Network.h create mode 100644 ports/raspberrypi/common-hal/wifi/Radio.c create mode 100644 ports/raspberrypi/common-hal/wifi/Radio.h create mode 100644 ports/raspberrypi/common-hal/wifi/ScannedNetworks.c create mode 100644 ports/raspberrypi/common-hal/wifi/ScannedNetworks.h create mode 100644 ports/raspberrypi/common-hal/wifi/__init__.c create mode 100644 ports/raspberrypi/common-hal/wifi/__init__.h create mode 100644 ports/raspberrypi/lwip_inc/arch/sys_arch.h create mode 100644 ports/raspberrypi/lwip_inc/lwipopts.h create mode 100644 ports/raspberrypi/lwip_src/ping.c create mode 100644 ports/raspberrypi/lwip_src/ping.h diff --git a/frozen/circuitpython-stage b/frozen/circuitpython-stage index 4124dfbdaa..9a8338b3bd 160000 --- a/frozen/circuitpython-stage +++ b/frozen/circuitpython-stage @@ -1 +1 @@ -Subproject commit 4124dfbdaadce1966f457d7d6c6984e9832999bf +Subproject commit 9a8338b3bdaeac9eeb5b74d147107c67db33fdac diff --git a/locale/circuitpython.pot b/locale/circuitpython.pot index 01db150b3f..c38548a90f 100644 --- a/locale/circuitpython.pot +++ b/locale/circuitpython.pot @@ -303,7 +303,7 @@ msgstr "" msgid "'%s' object doesn't support item deletion" msgstr "" -#: py/runtime.c +#: ports/raspberrypi/common-hal/wifi/Radio.c py/runtime.c msgid "'%s' object has no attribute '%q'" msgstr "" @@ -489,6 +489,7 @@ msgid "Already running" msgstr "" #: ports/espressif/common-hal/wifi/Radio.c +#: ports/raspberrypi/common-hal/wifi/Radio.c msgid "Already scanning for wifi networks" msgstr "" @@ -2208,6 +2209,11 @@ msgstr "" msgid "Unknown system firmware error: %d" msgstr "" +#: ports/raspberrypi/common-hal/wifi/__init__.c +#, c-format +msgid "Unkown error code %d" +msgstr "" + #: shared-bindings/adafruit_pixelbuf/PixelBuf.c #, c-format msgid "Unmatched number of items on RHS (expected %d, got %d)." @@ -4137,14 +4143,10 @@ msgstr "" msgid "type is not an acceptable base type" msgstr "" -#: py/runtime.c +#: py/objgenerator.c py/runtime.c msgid "type object '%q' has no attribute '%q'" msgstr "" -#: py/objgenerator.c -msgid "type object 'generator' has no attribute '__await__'" -msgstr "" - #: py/objtype.c msgid "type takes 1 or 3 arguments" msgstr "" @@ -4276,9 +4278,14 @@ msgid "width must be greater than zero" msgstr "" #: ports/espressif/common-hal/wifi/Radio.c +#: ports/raspberrypi/common-hal/wifi/Radio.c msgid "wifi is not enabled" msgstr "" +#: ports/raspberrypi/common-hal/wifi/Monitor.c +msgid "wifi.Monitor not available" +msgstr "" + #: shared-bindings/_bleio/Adapter.c msgid "window must be <= interval" msgstr "" diff --git a/mpy-cross/Makefile b/mpy-cross/Makefile index 6e4d7ef316..4858cb25c7 100644 --- a/mpy-cross/Makefile +++ b/mpy-cross/Makefile @@ -20,3 +20,5 @@ override undefine PROG endif include mpy-cross.mk +CFLAGS += -g +STRIP = : diff --git a/ports/espressif/esp32-camera b/ports/espressif/esp32-camera index 54c3f61c86..28804391c0 160000 --- a/ports/espressif/esp32-camera +++ b/ports/espressif/esp32-camera @@ -1 +1 @@ -Subproject commit 54c3f61c864c3d3ffd779042454554045b9dd9d2 +Subproject commit 28804391c002f6a3ea5ce6a55aee3b191be3ecde diff --git a/ports/raspberrypi/Makefile b/ports/raspberrypi/Makefile index 313005932c..bdfdb9a9b7 100644 --- a/ports/raspberrypi/Makefile +++ b/ports/raspberrypi/Makefile @@ -59,20 +59,30 @@ HAL_DIR=hal/$(MCU_SERIES) ifeq ($(CIRCUITPY_CYW43),1) INC_CYW43 := \ - -isystem sdk/src/rp2_common/pico_cyw43_arch/include/ \ - -isystem sdk/lib/cyw43-driver/src \ -isystem sdk/lib/cyw43-driver/firmware \ + -isystem sdk/lib/cyw43-driver/src \ + -isystem sdk/lib/lwip/src/include \ + -isystem sdk/src/rp2_common/pico_cyw43_arch/include/ \ + -isystem sdk/src/rp2_common/pico_lwip/include/ \ -CFLAGS_CYW43 := -DCYW43_LWIP=0 -DPICO_CYW43_ARCH_THREADSAFE_BACKGROUND=1 -DCYW43_USE_SPI -DIGNORE_GPIO25 +CFLAGS_CYW43 := -DCYW43_LWIP=1 -DPICO_CYW43_ARCH_THREADSAFE_BACKGROUND=1 -DCYW43_USE_SPI -DIGNORE_GPIO25 SRC_SDK_CYW43 := \ lib/cyw43-driver/src/cyw43_ctrl.c \ lib/cyw43-driver/src/cyw43_ll.c \ lib/cyw43-driver/src/cyw43_lwip.c \ lib/cyw43-driver/src/cyw43_stats.c \ src/common/pico_sync/sem.c \ + src/rp2_common/cyw43_driver/cyw43_bus_pio_spi.c \ src/rp2_common/pico_cyw43_arch/cyw43_arch.c \ src/rp2_common/pico_cyw43_arch/cyw43_arch_threadsafe_background.c \ - src/rp2_common/cyw43_driver/cyw43_bus_pio_spi.c \ + src/rp2_common/pico_lwip/nosys.c \ + src/rp2_common/pico_lwip/random.c \ + +SRC_LWIP := \ + $(wildcard sdk/lib/lwip/src/core/*.c) \ + $(wildcard sdk/lib/lwip/src/core/ipv4/*.c) \ + sdk/lib/lwip/src/netif/ethernet.c \ + $(wildcard lwip_src/*.c) \ SRC_CYW43 := $(wildcard bindings/cyw43/*.c) @@ -114,16 +124,17 @@ OBJ_CYW43 := $(BUILD)/cyw43_resource.o ### ) ### else -$(error y u no y fi) INC_CYW43 := CFLAGS_CYW43 := SRC_SDK_CYW43 := SRC_CYW43 := OBJ_CYW43 := +SRC_LWIP := endif INC += \ -I. \ + -Ilwip_inc \ -I../.. \ -I../lib/mp-readline \ -I../shared/timeutils \ @@ -276,6 +287,7 @@ SRC_C += \ lib/tinyusb/src/portable/raspberrypi/rp2040/rp2040_usb.c \ mphalport.c \ $(SRC_CYW43) \ + $(SRC_LWIP) \ SRC_COMMON_HAL_EXPANDED = $(addprefix shared-bindings/, $(SRC_COMMON_HAL)) \ $(addprefix shared-bindings/, $(SRC_BINDINGS_ENUMS)) \ diff --git a/ports/raspberrypi/boards/raspberry_pi_pico_w/mpconfigboard.mk b/ports/raspberrypi/boards/raspberry_pi_pico_w/mpconfigboard.mk index 0b3ce5ef00..7acd728bcc 100644 --- a/ports/raspberrypi/boards/raspberry_pi_pico_w/mpconfigboard.mk +++ b/ports/raspberrypi/boards/raspberry_pi_pico_w/mpconfigboard.mk @@ -16,5 +16,6 @@ CIRCUITPY_HASHLIB = 0 CIRCUITPY_WEB_WORKFLOW = 0 CIRCUITPY_MDNS = 0 CIRCUITPY_SOCKETPOOL = 0 +CIRCUITPY_WIFI = 1 CFLAGS += -DCYW43_PIN_WL_HOST_WAKE=24 -DCYW43_PIN_WL_REG_ON=23 -DCYW43_WL_GPIO_COUNT=3 -DCYW43_WL_GPIO_LED_PIN=0 diff --git a/ports/raspberrypi/common-hal/wifi/Monitor.c b/ports/raspberrypi/common-hal/wifi/Monitor.c new file mode 100644 index 0000000000..f288cd1ea1 --- /dev/null +++ b/ports/raspberrypi/common-hal/wifi/Monitor.c @@ -0,0 +1,74 @@ +/* + * 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" + + +#define MONITOR_PAYLOAD_FCS_LEN (4) +#define MONITOR_QUEUE_TIMEOUT_TICK (0) + +typedef struct { +} monitor_packet_t; + +void common_hal_wifi_monitor_construct(wifi_monitor_obj_t *self, uint8_t channel, size_t queue) { + mp_raise_NotImplementedError(translate("wifi.Monitor not available")); +} + +bool common_hal_wifi_monitor_deinited(void) { + return true; +} + +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) { +} + +mp_obj_t common_hal_wifi_monitor_get_channel(wifi_monitor_obj_t *self) { + return MP_OBJ_NEW_SMALL_INT(0); +} + +mp_obj_t common_hal_wifi_monitor_get_queue(wifi_monitor_obj_t *self) { + return mp_obj_new_int_from_uint(0); +} + +mp_obj_t common_hal_wifi_monitor_get_lost(wifi_monitor_obj_t *self) { + return mp_obj_new_int_from_uint(0); +} + +mp_obj_t common_hal_wifi_monitor_get_queued(wifi_monitor_obj_t *self) { + return mp_obj_new_int_from_uint(0); +} + +mp_obj_t common_hal_wifi_monitor_get_packet(wifi_monitor_obj_t *self) { + return mp_const_none; +} diff --git a/ports/raspberrypi/common-hal/wifi/Monitor.h b/ports/raspberrypi/common-hal/wifi/Monitor.h new file mode 100644 index 0000000000..14ee685bbd --- /dev/null +++ b/ports/raspberrypi/common-hal/wifi/Monitor.h @@ -0,0 +1,40 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2021 microDev + * Copyright (c) 2022 Jeff Epler for Adafruit Industries + * + * 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" + +typedef struct { + mp_obj_base_t base; + uint8_t channel; + size_t lost; + size_t queue_length; +} wifi_monitor_obj_t; + +#endif // MICROPY_INCLUDED_ESPRESSIF_COMMON_HAL_WIFI_MONITOR_H diff --git a/ports/raspberrypi/common-hal/wifi/Network.c b/ports/raspberrypi/common-hal/wifi/Network.c new file mode 100644 index 0000000000..8db42e962c --- /dev/null +++ b/ports/raspberrypi/common-hal/wifi/Network.c @@ -0,0 +1,81 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2020 Scott Shawcroft for Adafruit Industries + * + * 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 "shared-bindings/wifi/Network.h" +#include "shared-bindings/wifi/AuthMode.h" + +mp_obj_t common_hal_wifi_network_get_ssid(wifi_network_obj_t *self) { + const char *cstr = (const char *)self->record.ssid; + return mp_obj_new_str(cstr, self->record.ssid_len); +} + +#define MAC_ADDRESS_LENGTH 6 + +mp_obj_t common_hal_wifi_network_get_bssid(wifi_network_obj_t *self) { + return mp_obj_new_bytes(self->record.bssid, MAC_ADDRESS_LENGTH); +} + +mp_obj_t common_hal_wifi_network_get_rssi(wifi_network_obj_t *self) { + return mp_obj_new_int(self->record.rssi); +} + +mp_obj_t common_hal_wifi_network_get_channel(wifi_network_obj_t *self) { + return mp_obj_new_int(self->record.channel); +} + +mp_obj_t common_hal_wifi_network_get_country(wifi_network_obj_t *self) { + return (mp_obj_t)MP_QSTR_; +} + +mp_obj_t common_hal_wifi_network_get_authmode(wifi_network_obj_t *self) { + uint8_t authmode_mask = 0; + if (self->record.auth_mode == 0) { + authmode_mask = (1 << AUTHMODE_OPEN); + } + if (self->record.auth_mode & 1) { + authmode_mask |= (1 << AUTHMODE_PSK); + } + ; + if (self->record.auth_mode & 2) { + authmode_mask |= (1 << AUTHMODE_WPA); + } + ; + if (self->record.auth_mode & 4) { + authmode_mask |= (1 << AUTHMODE_WPA2); + } + ; + mp_obj_t authmode_list = mp_obj_new_list(0, NULL); + if (authmode_mask != 0) { + for (uint8_t i = 0; i < 8; i++) { + if ((authmode_mask >> i) & 1) { + mp_obj_list_append(authmode_list, cp_enum_find(&wifi_authmode_type, i)); + } + } + } + return authmode_list; +} diff --git a/ports/raspberrypi/common-hal/wifi/Network.h b/ports/raspberrypi/common-hal/wifi/Network.h new file mode 100644 index 0000000000..8e4e7bd310 --- /dev/null +++ b/ports/raspberrypi/common-hal/wifi/Network.h @@ -0,0 +1,36 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2020 Scott Shawcroft for Adafruit Industries + * + * 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. + */ + +#pragma once + +#include "py/obj.h" + +#include "pico/cyw43_arch.h" + +typedef struct { + mp_obj_base_t base; + cyw43_ev_scan_result_t record; +} wifi_network_obj_t; diff --git a/ports/raspberrypi/common-hal/wifi/Radio.c b/ports/raspberrypi/common-hal/wifi/Radio.c new file mode 100644 index 0000000000..f614d3185f --- /dev/null +++ b/ports/raspberrypi/common-hal/wifi/Radio.c @@ -0,0 +1,311 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2020 Scott Shawcroft for Adafruit Industries + * + * 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 "supervisor/port.h" +#include "shared-bindings/wifi/Radio.h" +#include "shared-bindings/wifi/Network.h" + +#include +#include + +#include "common-hal/wifi/__init__.h" +#include "shared/runtime/interrupt_char.h" +#include "py/gc.h" +#include "py/runtime.h" +#include "shared-bindings/ipaddress/IPv4Address.h" +#include "shared-bindings/wifi/ScannedNetworks.h" +#include "shared-bindings/wifi/AuthMode.h" +#include "shared-bindings/time/__init__.h" +#include "shared-module/ipaddress/__init__.h" + +#if CIRCUITPY_MDNS +#include "components/mdns/include/mdns.h" +#endif + +#include "lwip/dns.h" +#include "lwip/icmp.h" +#include "lwip/raw.h" +#include "lwip_src/ping.h" + +#ifndef PING_ID +#define PING_ID 0xAFAF +#endif + +#define MAC_ADDRESS_LENGTH 6 + +#define NETIF_STA (&cyw43_state.netif[CYW43_ITF_STA]) +#define NETIF_AP (&cyw43_state.netif[CYW43_ITF_AP]) + +NORETURN static void ro_attribute(int attr) { + mp_raise_msg_varg(&mp_type_AttributeError, MP_ERROR_TEXT("'%s' object has no attribute '%q'"), "Radio", attr); +} + +bool common_hal_wifi_radio_get_enabled(wifi_radio_obj_t *self) { + return true; +} + +void common_hal_wifi_radio_set_enabled(wifi_radio_obj_t *self, bool enabled) { + if (!enabled) { + ro_attribute(MP_QSTR_enabled); + } +} + +mp_obj_t common_hal_wifi_radio_get_hostname(wifi_radio_obj_t *self) { + if (!NETIF_STA->hostname) { + return mp_const_none; + } + return mp_obj_new_str(NETIF_STA->hostname, strlen(NETIF_STA->hostname)); +} + +void common_hal_wifi_radio_set_hostname(wifi_radio_obj_t *self, const char *hostname) { + ro_attribute(MP_QSTR_hostname); +} + +mp_obj_t common_hal_wifi_radio_get_mac_address(wifi_radio_obj_t *self) { + return mp_obj_new_bytes(cyw43_state.mac, MAC_ADDRESS_LENGTH); +} + +void common_hal_wifi_radio_set_mac_address(wifi_radio_obj_t *self, const uint8_t *mac) { + ro_attribute(MP_QSTR_mac_address); +} + +mp_float_t common_hal_wifi_radio_get_tx_power(wifi_radio_obj_t *self) { + return MICROPY_FLOAT_CONST(0.); +} + +void common_hal_wifi_radio_set_tx_power(wifi_radio_obj_t *self, const mp_float_t tx_power) { + ro_attribute(MP_QSTR_tx_power); + +} + +mp_obj_t common_hal_wifi_radio_get_mac_address_ap(wifi_radio_obj_t *self) { + return common_hal_wifi_radio_get_mac_address(self); +} + +void common_hal_wifi_radio_set_mac_address_ap(wifi_radio_obj_t *self, const uint8_t *mac) { + ro_attribute(MP_QSTR_mac_address_ap); +} + +mp_obj_t common_hal_wifi_radio_start_scanning_networks(wifi_radio_obj_t *self) { + if (self->current_scan) { + mp_raise_RuntimeError(translate("Already scanning for wifi networks")); + } + if (!common_hal_wifi_radio_get_enabled(self)) { + mp_raise_RuntimeError(translate("wifi is not enabled")); + } + wifi_scannednetworks_obj_t *scan = m_new_obj(wifi_scannednetworks_obj_t); + scan->base.type = &wifi_scannednetworks_type; + mp_obj_t args[] = { mp_const_empty_tuple, MP_OBJ_NEW_SMALL_INT(16) }; + scan->results = mp_type_deque.make_new(&mp_type_deque, 2, 0, args); + self->current_scan = scan; + wifi_scannednetworks_start_scan(scan); + return scan; +} + +void common_hal_wifi_radio_stop_scanning_networks(wifi_radio_obj_t *self) { + self->current_scan = NULL; +} + +void common_hal_wifi_radio_start_station(wifi_radio_obj_t *self) { + cyw43_arch_enable_sta_mode(); +} + +void common_hal_wifi_radio_stop_station(wifi_radio_obj_t *self) { +} + +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, uint8_t max_connections) { + mp_raise_NotImplementedError(NULL); +} + +void common_hal_wifi_radio_stop_ap(wifi_radio_obj_t *self) { +} + +wifi_radio_error_t common_hal_wifi_radio_connect(wifi_radio_obj_t *self, uint8_t *ssid, size_t ssid_len, uint8_t *password, size_t password_len, uint8_t channel, mp_float_t timeout, uint8_t *bssid, size_t bssid_len) { + if (!common_hal_wifi_radio_get_enabled(self)) { + mp_raise_RuntimeError(translate("wifi is not enabled")); + } + unsigned timeout_ms = timeout <= 0 ? 8000 : (unsigned)MAX(0, MICROPY_FLOAT_C_FUN(ceil)(timeout * 1000)); + // TODO use connect_async so we can service bg tasks & check for ctrl-c during + // connect + int result = cyw43_arch_wifi_connect_timeout_ms((const char *)ssid, (const char *)password, CYW43_AUTH_WPA2_AES_PSK, timeout_ms); + switch (result) { + case 0: + return WIFI_RADIO_ERROR_NONE; + // case CYW43_LINK_DOWN: + // case CYW43_LINK_JOIN: + // case CYW43_LINK_NOIP: + // case CYW43_LINK_UP: + case CYW43_LINK_FAIL: + return WIFI_RADIO_ERROR_CONNECTION_FAIL; + case CYW43_LINK_NONET: + return WIFI_RADIO_ERROR_NO_AP_FOUND; + case CYW43_LINK_BADAUTH: + return WIFI_RADIO_ERROR_AUTH_FAIL; + + default: + return WIFI_RADIO_ERROR_UNSPECIFIED; + } +} + +mp_obj_t common_hal_wifi_radio_get_ap_info(wifi_radio_obj_t *self) { + mp_raise_NotImplementedError(NULL); +} + +mp_obj_t common_hal_wifi_radio_get_ipv4_gateway(wifi_radio_obj_t *self) { + if (!netif_is_up(NETIF_STA)) { + return mp_const_none; + } + return common_hal_ipaddress_new_ipv4address(NETIF_STA->gw.addr); +} + +mp_obj_t common_hal_wifi_radio_get_ipv4_gateway_ap(wifi_radio_obj_t *self) { + if (!netif_is_up(NETIF_AP)) { + return mp_const_none; + } + return common_hal_ipaddress_new_ipv4address(NETIF_AP->gw.addr); +} + +mp_obj_t common_hal_wifi_radio_get_ipv4_subnet(wifi_radio_obj_t *self) { + if (!netif_is_up(NETIF_STA)) { + return mp_const_none; + } + return common_hal_ipaddress_new_ipv4address(NETIF_STA->netmask.addr); +} + +mp_obj_t common_hal_wifi_radio_get_ipv4_subnet_ap(wifi_radio_obj_t *self) { + if (!netif_is_up(NETIF_AP)) { + return mp_const_none; + } + return common_hal_ipaddress_new_ipv4address(NETIF_AP->netmask.addr); +} + +mp_obj_t common_hal_wifi_radio_get_ipv4_address(wifi_radio_obj_t *self) { + if (!netif_is_up(NETIF_STA)) { + return mp_const_none; + } + return common_hal_ipaddress_new_ipv4address(NETIF_STA->ip_addr.addr); +} + +mp_obj_t common_hal_wifi_radio_get_ipv4_address_ap(wifi_radio_obj_t *self) { + if (!netif_is_up(NETIF_AP)) { + return mp_const_none; + } + return common_hal_ipaddress_new_ipv4address(NETIF_AP->ip_addr.addr); +} + +mp_obj_t common_hal_wifi_radio_get_ipv4_dns(wifi_radio_obj_t *self) { + uint32_t addr = dns_getserver(0)->addr; + if (!netif_is_up(NETIF_STA) || addr == 0) { + return mp_const_none; + } + return common_hal_ipaddress_new_ipv4address(addr); +} + +void common_hal_wifi_radio_set_ipv4_dns(wifi_radio_obj_t *self, mp_obj_t ipv4_dns_addr) { + mp_raise_NotImplementedError(NULL); +} + +void common_hal_wifi_radio_start_dhcp_client(wifi_radio_obj_t *self) { +} + +void common_hal_wifi_radio_stop_dhcp_client(wifi_radio_obj_t *self) { + mp_raise_NotImplementedError(NULL); +} + +void common_hal_wifi_radio_set_ipv4_address(wifi_radio_obj_t *self, mp_obj_t ipv4, mp_obj_t netmask, mp_obj_t gateway, mp_obj_t ipv4_dns) { + mp_raise_NotImplementedError(NULL); +} + +volatile bool ping_received; + +static u8_t +ping_recv(void *arg, struct raw_pcb *pcb, struct pbuf *p, const ip_addr_t *addr) { + struct icmp_echo_hdr *iecho; + LWIP_ASSERT("p != NULL", p != NULL); + + if ((p->tot_len >= (PBUF_IP_HLEN + sizeof(struct icmp_echo_hdr))) && + pbuf_remove_header(p, PBUF_IP_HLEN) == 0) { + iecho = (struct icmp_echo_hdr *)p->payload; + + if ((iecho->id == PING_ID) && (iecho->seqno == lwip_htons(ping_seq_num))) { + LWIP_DEBUGF(PING_DEBUG, ("ping: recv ")); + ip_addr_debug_print(PING_DEBUG, addr); + LWIP_DEBUGF(PING_DEBUG, (" %"U32_F " ms\n", (sys_now() - ping_time))); + + /* do some ping result processing */ + ping_received = true; + pbuf_free(p); + return 1; /* eat the packet */ + } + /* not eaten, restore original packet */ + pbuf_add_header(p, PBUF_IP_HLEN); + } + return 0; /* don't eat the packet */ +} + +mp_int_t common_hal_wifi_radio_ping(wifi_radio_obj_t *self, mp_obj_t ip_address, mp_float_t timeout) { + ip_addr_t ping_addr; + ipaddress_ipaddress_to_lwip(ip_address, &ping_addr); + + struct raw_pcb *ping_pcb; + MICROPY_PY_LWIP_ENTER(); + ping_pcb = raw_new(IP_PROTO_ICMP); + if (!ping_pcb) { + MICROPY_PY_LWIP_EXIT(); + return -1; + } + raw_recv(ping_pcb, ping_recv, NULL); + raw_bind(ping_pcb, IP_ADDR_ANY); + MICROPY_PY_LWIP_EXIT(); + + ping_received = false; + ping_send(ping_pcb, &ping_addr); + size_t timeout_ms = (size_t)MICROPY_FLOAT_C_FUN(ceil)(timeout * 1000); + uint64_t start = port_get_raw_ticks(NULL); + uint64_t deadline = start + timeout_ms; + while (port_get_raw_ticks(NULL) < deadline && !ping_received) { + RUN_BACKGROUND_TASKS; + if (mp_hal_is_interrupted()) { + break; + } + } + mp_int_t result = -1; + if (ping_received) { + uint64_t now = port_get_raw_ticks(NULL); + result = now - start; + } + + MICROPY_PY_LWIP_ENTER(); + raw_remove(ping_pcb); + MICROPY_PY_LWIP_EXIT(); + + return result; +} + +void common_hal_wifi_radio_gc_collect(wifi_radio_obj_t *self) { + // Only bother to scan the actual object references. + gc_collect_ptr(self->current_scan); +} diff --git a/ports/raspberrypi/common-hal/wifi/Radio.h b/ports/raspberrypi/common-hal/wifi/Radio.h new file mode 100644 index 0000000000..e919c5d718 --- /dev/null +++ b/ports/raspberrypi/common-hal/wifi/Radio.h @@ -0,0 +1,39 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2022 Jeff Epler for Adafruit Industries + * + * 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. + */ + +#pragma once + +#include "py/obj.h" + +#include "shared-bindings/wifi/ScannedNetworks.h" +#include "shared-bindings/wifi/Network.h" + +typedef struct { + mp_obj_base_t base; + wifi_scannednetworks_obj_t *current_scan; +} wifi_radio_obj_t; + +extern void common_hal_wifi_radio_gc_collect(wifi_radio_obj_t *self); diff --git a/ports/raspberrypi/common-hal/wifi/ScannedNetworks.c b/ports/raspberrypi/common-hal/wifi/ScannedNetworks.c new file mode 100644 index 0000000000..fd180da3b1 --- /dev/null +++ b/ports/raspberrypi/common-hal/wifi/ScannedNetworks.c @@ -0,0 +1,120 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2019 Dan Halbert for Adafruit Industries + * Copyright (c) 2018 Artur Pacholec + * Copyright (c) 2017 Glenn Ruben Bakke + * + * 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 "shared/runtime/interrupt_char.h" +#include "py/gc.h" +#include "py/objstr.h" +#include "py/runtime.h" +#include "common-hal/wifi/__init__.h" +#include "shared-bindings/wifi/__init__.h" +#include "shared-bindings/wifi/Network.h" +#include "shared-bindings/wifi/Radio.h" +#include "shared-bindings/wifi/ScannedNetworks.h" + +#define NUM_SCAN (16) +static cyw43_ev_scan_result_t scan_results[NUM_SCAN]; +static uint8_t scan_put, scan_get; +static bool scan_full; + + +static void scan_result_clear() { + scan_put = scan_get = 0; + scan_full = false; +} + +static void scan_result_put(const cyw43_ev_scan_result_t *result) { + if (!scan_full) { + scan_results[scan_put] = *result; + scan_put = (scan_put + 1) % NUM_SCAN; + scan_full = (scan_put == scan_get); + } +} + +static bool scan_result_available() { + return scan_full || (scan_get != scan_put); +} + +static cyw43_ev_scan_result_t *scan_result_get(cyw43_ev_scan_result_t *result) { + if (!scan_result_available()) { + return NULL; + } + + *result = scan_results[scan_get]; + scan_get = (scan_get + 1) % NUM_SCAN; + scan_full = false; + return result; +} + +// Note: It's not OK to allocate memory in here, we can be called at a bad time +// which messes up the gc allocator +static int scan_result(void *env, const cyw43_ev_scan_result_t *result) { + wifi_scannednetworks_obj_t *self = common_hal_wifi_radio_obj.current_scan; + // scan ended or something + if (!self) { + return 0; + } + + scan_result_put(result); + + return 0; +} + +mp_obj_t common_hal_wifi_scannednetworks_next(wifi_scannednetworks_obj_t *self) { + // no results available, wait for some + while (!scan_result_available(self) && cyw43_wifi_scan_active(&cyw43_state)) { + RUN_BACKGROUND_TASKS; + if (mp_hal_is_interrupted()) { + return mp_const_none; + } + cyw43_arch_poll(); + } + + if (!scan_result_available(self)) { + common_hal_wifi_radio_obj.current_scan = NULL; + return mp_const_none; + } + + + wifi_network_obj_t *entry = m_new_obj(wifi_network_obj_t); + entry->base.type = &wifi_network_type; + scan_result_get(&entry->record); + + return MP_OBJ_FROM_PTR(entry); +} + +void wifi_scannednetworks_deinit(wifi_scannednetworks_obj_t *self) { + // there's actually no way to stop an ongoing scan in cyw43! + common_hal_wifi_radio_obj.current_scan = NULL; +} + +void wifi_scannednetworks_start_scan(wifi_scannednetworks_obj_t *self) { + cyw43_wifi_scan_options_t scan_options = {0}; + CHECK_CYW_RESULT(cyw43_wifi_scan(&cyw43_state, &scan_options, NULL, scan_result)); +} diff --git a/ports/raspberrypi/common-hal/wifi/ScannedNetworks.h b/ports/raspberrypi/common-hal/wifi/ScannedNetworks.h new file mode 100644 index 0000000000..eae783ca4e --- /dev/null +++ b/ports/raspberrypi/common-hal/wifi/ScannedNetworks.h @@ -0,0 +1,42 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2019 Dan Halbert for Adafruit Industries + * Copyright (c) 2018 Artur Pacholec + * + * 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. + */ + +#pragma once + +#include + +#include "py/obj.h" +#include "cyw43.h" + +typedef struct { + mp_obj_base_t base; + mp_obj_t results; + bool done; +} wifi_scannednetworks_obj_t; + +void wifi_scannednetworks_deinit(wifi_scannednetworks_obj_t *self); +void wifi_scannednetworks_start_scan(wifi_scannednetworks_obj_t *self); diff --git a/ports/raspberrypi/common-hal/wifi/__init__.c b/ports/raspberrypi/common-hal/wifi/__init__.c new file mode 100644 index 0000000000..9a42320cf5 --- /dev/null +++ b/ports/raspberrypi/common-hal/wifi/__init__.c @@ -0,0 +1,124 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2020 Scott Shawcroft for Adafruit Industries + * + * 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 "common-hal/wifi/__init__.h" +#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/mperrno.h" +#include "py/mpstate.h" +#include "py/runtime.h" + +wifi_radio_obj_t common_hal_wifi_radio_obj; + +#include "supervisor/port.h" +#include "supervisor/shared/status_bar.h" +#include "supervisor/workflow.h" + +static bool wifi_inited; +static bool wifi_ever_inited; +static bool wifi_user_initiated; + +void common_hal_wifi_init(bool user_initiated) { + wifi_radio_obj_t *self = &common_hal_wifi_radio_obj; + + if (wifi_inited) { + if (user_initiated && !wifi_user_initiated) { + common_hal_wifi_radio_set_enabled(self, true); + } + return; + } + wifi_inited = true; + wifi_user_initiated = user_initiated; + common_hal_wifi_radio_obj.base.type = &wifi_radio_type; + common_hal_wifi_radio_obj.current_scan = NULL; + + if (!wifi_ever_inited) { + } + wifi_ever_inited = true; + + // set station mode to avoid the default SoftAP + common_hal_wifi_radio_start_station(self); + // start wifi + common_hal_wifi_radio_set_enabled(self, true); +} + +void wifi_user_reset(void) { + if (wifi_user_initiated) { + // wifi_reset(); + wifi_user_initiated = false; + } +} + +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_obj.current_scan = NULL; + // common_hal_wifi_radio_set_enabled(radio, false); + supervisor_workflow_request_background(); +} + +void common_hal_wifi_gc_collect(void) { + common_hal_wifi_radio_gc_collect(&common_hal_wifi_radio_obj); +} + +void raise_cyw_error(int err) { + int mp_errno; + switch (err) { + case -CYW43_EIO: + mp_errno = MP_EIO; + break; + case -CYW43_EPERM: + mp_errno = MP_EPERM; + break; + case -CYW43_EINVAL: + mp_errno = MP_EINVAL; + break; + case -CYW43_ETIMEDOUT: + mp_errno = MP_ETIMEDOUT; + break; + default: + mp_raise_OSError_msg_varg(translate("Unkown error code %d"), err); + } + mp_raise_OSError(mp_errno); +} + +void ipaddress_ipaddress_to_lwip(mp_obj_t ip_address, ip_addr_t *lwip_ip_address) { + if (!mp_obj_is_type(ip_address, &ipaddress_ipv4address_type)) { + mp_raise_ValueError(translate("Only IPv4 addresses supported")); + } + mp_obj_t packed = common_hal_ipaddress_ipv4address_get_packed(ip_address); + size_t len; + const char *bytes = mp_obj_str_get_data(packed, &len); + + IP_ADDR4(lwip_ip_address, bytes[0], bytes[1], bytes[2], bytes[3]); +} diff --git a/ports/raspberrypi/common-hal/wifi/__init__.h b/ports/raspberrypi/common-hal/wifi/__init__.h new file mode 100644 index 0000000000..d34d631089 --- /dev/null +++ b/ports/raspberrypi/common-hal/wifi/__init__.h @@ -0,0 +1,37 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2022 Jeff Epler for Adafruit Industries + * + * 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. + */ + +#pragma once + +#include "py/obj.h" +#include "py/mpconfig.h" +#include "lwip/ip_addr.h" + +void wifi_reset(void); +NORETURN void raise_cyw_error(int err); +#define CHECK_CYW_RESULT(x) do { int res = (x); if (res != 0) raise_cyw_error(res); } while (0) + +void ipaddress_ipaddress_to_lwip(mp_obj_t ip_address, ip_addr_t *lwip_ip_address); diff --git a/ports/raspberrypi/lwip_inc/arch/sys_arch.h b/ports/raspberrypi/lwip_inc/arch/sys_arch.h new file mode 100644 index 0000000000..8b1a393741 --- /dev/null +++ b/ports/raspberrypi/lwip_inc/arch/sys_arch.h @@ -0,0 +1 @@ +// empty diff --git a/ports/raspberrypi/lwip_inc/lwipopts.h b/ports/raspberrypi/lwip_inc/lwipopts.h new file mode 100644 index 0000000000..993e675d6b --- /dev/null +++ b/ports/raspberrypi/lwip_inc/lwipopts.h @@ -0,0 +1,92 @@ +#ifndef _LWIPOPTS_EXAMPLE_COMMONH_H +#define _LWIPOPTS_EXAMPLE_COMMONH_H + + +// Common settings used in most of the pico_w examples +// (see https://www.nongnu.org/lwip/2_1_x/group__lwip__opts.html for details) + +// allow override in some examples +#ifndef NO_SYS +#define NO_SYS 1 +#endif +// allow override in some examples +#ifndef LWIP_SOCKET +#define LWIP_SOCKET 0 +#endif +#if PICO_CYW43_ARCH_POLL +#define MEM_LIBC_MALLOC 1 +#else +// MEM_LIBC_MALLOC is incompatible with non polling versions +#define MEM_LIBC_MALLOC 0 +#endif +#define MEM_ALIGNMENT 4 +#define MEM_SIZE 4000 +#define MEMP_NUM_TCP_SEG 32 +#define MEMP_NUM_ARP_QUEUE 10 +#define PBUF_POOL_SIZE 24 +#define LWIP_ARP 1 +#define LWIP_ETHERNET 1 +#define LWIP_ICMP 1 +#define LWIP_RAW 1 +#define TCP_WND (8 * TCP_MSS) +#define TCP_MSS 1460 +#define TCP_SND_BUF (8 * TCP_MSS) +#define TCP_SND_QUEUELEN ((4 * (TCP_SND_BUF) + (TCP_MSS - 1)) / (TCP_MSS)) +#define LWIP_NETIF_STATUS_CALLBACK 1 +#define LWIP_NETIF_LINK_CALLBACK 1 +#define LWIP_NETIF_HOSTNAME 1 +#define LWIP_NETCONN 0 +#define MEM_STATS 0 +#define SYS_STATS 0 +#define MEMP_STATS 0 +#define LINK_STATS 0 +// #define ETH_PAD_SIZE 2 +#define LWIP_CHKSUM_ALGORITHM 3 +#define LWIP_DHCP 1 +#define LWIP_IPV4 1 +#define LWIP_TCP 1 +#define LWIP_UDP 1 +#define LWIP_DNS 1 +#define LWIP_TCP_KEEPALIVE 1 +#define LWIP_NETIF_TX_SINGLE_PBUF 1 +#define DHCP_DOES_ARP_CHECK 0 +#define LWIP_DHCP_DOES_ACD_CHECK 0 + +#ifndef NDEBUG +#define LWIP_DEBUG 1 +#define LWIP_STATS 1 +#define LWIP_STATS_DISPLAY 1 +#endif + +#define ETHARP_DEBUG LWIP_DBG_OFF +#define NETIF_DEBUG LWIP_DBG_OFF +#define PBUF_DEBUG LWIP_DBG_OFF +#define API_LIB_DEBUG LWIP_DBG_OFF +#define API_MSG_DEBUG LWIP_DBG_OFF +#define SOCKETS_DEBUG LWIP_DBG_OFF +#define ICMP_DEBUG LWIP_DBG_OFF +#define INET_DEBUG LWIP_DBG_OFF +#define IP_DEBUG LWIP_DBG_OFF +#define IP_REASS_DEBUG LWIP_DBG_OFF +#define RAW_DEBUG LWIP_DBG_OFF +#define MEM_DEBUG LWIP_DBG_OFF +#define MEMP_DEBUG LWIP_DBG_OFF +#define SYS_DEBUG LWIP_DBG_OFF +#define TCP_DEBUG LWIP_DBG_OFF +#define TCP_INPUT_DEBUG LWIP_DBG_OFF +#define TCP_OUTPUT_DEBUG LWIP_DBG_OFF +#define TCP_RTO_DEBUG LWIP_DBG_OFF +#define TCP_CWND_DEBUG LWIP_DBG_OFF +#define TCP_WND_DEBUG LWIP_DBG_OFF +#define TCP_FR_DEBUG LWIP_DBG_OFF +#define TCP_QLEN_DEBUG LWIP_DBG_OFF +#define TCP_RST_DEBUG LWIP_DBG_OFF +#define UDP_DEBUG LWIP_DBG_OFF +#define TCPIP_DEBUG LWIP_DBG_OFF +#define PPP_DEBUG LWIP_DBG_OFF +#define SLIP_DEBUG LWIP_DBG_OFF +#define DHCP_DEBUG LWIP_DBG_OFF + +#define LWIP_TIMEVAL_PRIVATE 0 + +#endif /* __LWIPOPTS_H__ */ diff --git a/ports/raspberrypi/lwip_src/ping.c b/ports/raspberrypi/lwip_src/ping.c new file mode 100644 index 0000000000..d5173cab96 --- /dev/null +++ b/ports/raspberrypi/lwip_src/ping.c @@ -0,0 +1,390 @@ +/** + * @file + * Ping sender module + * + */ + +/* + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + */ + +/** + * This is an example of a "ping" sender (with raw API and socket API). + * It can be used as a start point to maintain opened a network connection, or + * like a network "watchdog" for your device. + * + */ + +#include "lwip/opt.h" + +#if LWIP_RAW /* don't build if not configured for use in lwipopts.h */ + +#include "ping.h" + +#include "lwip/mem.h" +#include "lwip/raw.h" +#include "lwip/icmp.h" +#include "lwip/netif.h" +#include "lwip/sys.h" +#include "lwip/timeouts.h" +#include "lwip/inet_chksum.h" +#include "lwip/prot/ip4.h" + +#if PING_USE_SOCKETS +#include "lwip/sockets.h" +#include "lwip/inet.h" +#include +#endif /* PING_USE_SOCKETS */ + + +/** + * PING_DEBUG: Enable debugging for PING. + */ +#ifndef PING_DEBUG +#define PING_DEBUG LWIP_DBG_ON +#endif + +/** ping receive timeout - in milliseconds */ +#ifndef PING_RCV_TIMEO +#define PING_RCV_TIMEO 1000 +#endif + +/** ping delay - in milliseconds */ +#ifndef PING_DELAY +#define PING_DELAY 1000 +#endif + +/** ping identifier - must fit on a u16_t */ +#ifndef PING_ID +#define PING_ID 0xAFAF +#endif + +/** ping additional data size to include in the packet */ +#ifndef PING_DATA_SIZE +#define PING_DATA_SIZE 32 +#endif + +/** ping result action - no default action */ +#ifndef PING_RESULT +#define PING_RESULT(ping_ok) +#endif + +/* ping variables */ +static const ip_addr_t *ping_target; +u16_t ping_seq_num; +#ifdef LWIP_DEBUG +static u32_t ping_time; +#endif /* LWIP_DEBUG */ +#if !PING_USE_SOCKETS +static struct raw_pcb *ping_pcb; +#endif /* PING_USE_SOCKETS */ + +/** Prepare a echo ICMP request */ +void +ping_prepare_echo(struct icmp_echo_hdr *iecho, u16_t len) { + size_t i; + size_t data_len = len - sizeof(struct icmp_echo_hdr); + + ICMPH_TYPE_SET(iecho, ICMP_ECHO); + ICMPH_CODE_SET(iecho, 0); + iecho->chksum = 0; + iecho->id = PING_ID; + iecho->seqno = lwip_htons(++ping_seq_num); + + /* fill the additional data buffer with some data */ + for (i = 0; i < data_len; i++) { + ((char *)iecho)[sizeof(struct icmp_echo_hdr) + i] = (char)i; + } + + iecho->chksum = inet_chksum(iecho, len); +} + +#if PING_USE_SOCKETS + +/* Ping using the socket ip */ +err_t +ping_send(int s, const ip_addr_t *addr) { + int err; + struct icmp_echo_hdr *iecho; + struct sockaddr_storage to; + size_t ping_size = sizeof(struct icmp_echo_hdr) + PING_DATA_SIZE; + LWIP_ASSERT("ping_size is too big", ping_size <= 0xffff); + + #if LWIP_IPV6 + if (IP_IS_V6(addr) && !ip6_addr_isipv4mappedipv6(ip_2_ip6(addr))) { + /* todo: support ICMP6 echo */ + return ERR_VAL; + } + #endif /* LWIP_IPV6 */ + + iecho = (struct icmp_echo_hdr *)mem_malloc((mem_size_t)ping_size); + if (!iecho) { + return ERR_MEM; + } + + ping_prepare_echo(iecho, (u16_t)ping_size); + + #if LWIP_IPV4 + if (IP_IS_V4(addr)) { + struct sockaddr_in *to4 = (struct sockaddr_in *)&to; + to4->sin_len = sizeof(*to4); + to4->sin_family = AF_INET; + inet_addr_from_ip4addr(&to4->sin_addr, ip_2_ip4(addr)); + } + #endif /* LWIP_IPV4 */ + + #if LWIP_IPV6 + if (IP_IS_V6(addr)) { + struct sockaddr_in6 *to6 = (struct sockaddr_in6 *)&to; + to6->sin6_len = sizeof(*to6); + to6->sin6_family = AF_INET6; + inet6_addr_from_ip6addr(&to6->sin6_addr, ip_2_ip6(addr)); + } + #endif /* LWIP_IPV6 */ + + err = lwip_sendto(s, iecho, ping_size, 0, (struct sockaddr *)&to, sizeof(to)); + + mem_free(iecho); + + return err ? ERR_OK : ERR_VAL; +} + +static void +ping_recv(int s) { + char buf[64]; + int len; + struct sockaddr_storage from; + int fromlen = sizeof(from); + + while ((len = lwip_recvfrom(s, buf, sizeof(buf), 0, (struct sockaddr *)&from, (socklen_t *)&fromlen)) > 0) { + if (len >= (int)(sizeof(struct ip_hdr) + sizeof(struct icmp_echo_hdr))) { + ip_addr_t fromaddr; + memset(&fromaddr, 0, sizeof(fromaddr)); + + #if LWIP_IPV4 + if (from.ss_family == AF_INET) { + struct sockaddr_in *from4 = (struct sockaddr_in *)&from; + inet_addr_to_ip4addr(ip_2_ip4(&fromaddr), &from4->sin_addr); + IP_SET_TYPE_VAL(fromaddr, IPADDR_TYPE_V4); + } + #endif /* LWIP_IPV4 */ + + #if LWIP_IPV6 + if (from.ss_family == AF_INET6) { + struct sockaddr_in6 *from6 = (struct sockaddr_in6 *)&from; + inet6_addr_to_ip6addr(ip_2_ip6(&fromaddr), &from6->sin6_addr); + IP_SET_TYPE_VAL(fromaddr, IPADDR_TYPE_V6); + } + #endif /* LWIP_IPV6 */ + + LWIP_DEBUGF(PING_DEBUG, ("ping: recv ")); + ip_addr_debug_print_val(PING_DEBUG, fromaddr); + LWIP_DEBUGF(PING_DEBUG, (" %"U32_F " ms\n", (sys_now() - ping_time))); + + /* todo: support ICMP6 echo */ + #if LWIP_IPV4 + if (IP_IS_V4_VAL(fromaddr)) { + struct ip_hdr *iphdr; + struct icmp_echo_hdr *iecho; + + iphdr = (struct ip_hdr *)buf; + iecho = (struct icmp_echo_hdr *)(buf + (IPH_HL(iphdr) * 4)); + if ((iecho->id == PING_ID) && (iecho->seqno == lwip_htons(ping_seq_num))) { + /* do some ping result processing */ + PING_RESULT((ICMPH_TYPE(iecho) == ICMP_ER)); + return; + } else { + LWIP_DEBUGF(PING_DEBUG, ("ping: drop\n")); + } + } + #endif /* LWIP_IPV4 */ + } + fromlen = sizeof(from); + } + + if (len == 0) { + LWIP_DEBUGF(PING_DEBUG, ("ping: recv - %"U32_F " ms - timeout\n", (sys_now() - ping_time))); + } + + /* do some ping result processing */ + PING_RESULT(0); +} + +static void +ping_thread(void *arg) { + int s; + int ret; + + #if LWIP_SO_SNDRCVTIMEO_NONSTANDARD + int timeout = PING_RCV_TIMEO; + #else + struct timeval timeout; + timeout.tv_sec = PING_RCV_TIMEO / 1000; + timeout.tv_usec = (PING_RCV_TIMEO % 1000) * 1000; + #endif + LWIP_UNUSED_ARG(arg); + + #if LWIP_IPV6 + if (IP_IS_V4(ping_target) || ip6_addr_isipv4mappedipv6(ip_2_ip6(ping_target))) { + s = lwip_socket(AF_INET6, SOCK_RAW, IP_PROTO_ICMP); + } else { + s = lwip_socket(AF_INET6, SOCK_RAW, IP6_NEXTH_ICMP6); + } + #else + s = lwip_socket(AF_INET, SOCK_RAW, IP_PROTO_ICMP); + #endif + if (s < 0) { + return; + } + + ret = lwip_setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout)); + LWIP_ASSERT("setting receive timeout failed", ret == 0); + LWIP_UNUSED_ARG(ret); + + while (1) { + if (ping_send(s, ping_target) == ERR_OK) { + LWIP_DEBUGF(PING_DEBUG, ("ping: send ")); + ip_addr_debug_print(PING_DEBUG, ping_target); + LWIP_DEBUGF(PING_DEBUG, ("\n")); + + #ifdef LWIP_DEBUG + ping_time = sys_now(); + #endif /* LWIP_DEBUG */ + ping_recv(s); + } else { + LWIP_DEBUGF(PING_DEBUG, ("ping: send ")); + ip_addr_debug_print(PING_DEBUG, ping_target); + LWIP_DEBUGF(PING_DEBUG, (" - error\n")); + } + sys_msleep(PING_DELAY); + } +} + +#else /* PING_USE_SOCKETS */ + +/* Ping using the raw ip */ +static u8_t +ping_recv(void *arg, struct raw_pcb *pcb, struct pbuf *p, const ip_addr_t *addr) { + struct icmp_echo_hdr *iecho; + LWIP_UNUSED_ARG(arg); + LWIP_UNUSED_ARG(pcb); + LWIP_UNUSED_ARG(addr); + LWIP_ASSERT("p != NULL", p != NULL); + + if ((p->tot_len >= (PBUF_IP_HLEN + sizeof(struct icmp_echo_hdr))) && + pbuf_remove_header(p, PBUF_IP_HLEN) == 0) { + iecho = (struct icmp_echo_hdr *)p->payload; + + if ((iecho->id == PING_ID) && (iecho->seqno == lwip_htons(ping_seq_num))) { + LWIP_DEBUGF(PING_DEBUG, ("ping: recv ")); + ip_addr_debug_print(PING_DEBUG, addr); + LWIP_DEBUGF(PING_DEBUG, (" %"U32_F " ms\n", (sys_now() - ping_time))); + + /* do some ping result processing */ + PING_RESULT(1); + pbuf_free(p); + return 1; /* eat the packet */ + } + /* not eaten, restore original packet */ + pbuf_add_header(p, PBUF_IP_HLEN); + } + + return 0; /* don't eat the packet */ +} + +int +ping_send(struct raw_pcb *raw, const ip_addr_t *addr) { + struct pbuf *p; + struct icmp_echo_hdr *iecho; + size_t ping_size = sizeof(struct icmp_echo_hdr) + PING_DATA_SIZE; + + LWIP_DEBUGF(PING_DEBUG, ("ping: send ")); + ip_addr_debug_print(PING_DEBUG, addr); + LWIP_DEBUGF(PING_DEBUG, ("\n")); + LWIP_ASSERT("ping_size <= 0xffff", ping_size <= 0xffff); + + p = pbuf_alloc(PBUF_IP, (u16_t)ping_size, PBUF_RAM); + if (!p) { + return 0; + } + if ((p->len == p->tot_len) && (p->next == NULL)) { + iecho = (struct icmp_echo_hdr *)p->payload; + + ping_prepare_echo(iecho, (u16_t)ping_size); + + raw_sendto(raw, p, addr); + #ifdef LWIP_DEBUG + ping_time = sys_now(); + #endif /* LWIP_DEBUG */ + } + pbuf_free(p); + return 1; +} + +static void +ping_timeout(void *arg) { + struct raw_pcb *pcb = (struct raw_pcb *)arg; + + LWIP_ASSERT("ping_timeout: no pcb given!", pcb != NULL); + + ping_send(pcb, ping_target); + + sys_timeout(PING_DELAY, ping_timeout, pcb); +} + +static void +ping_raw_init(void) { + if (ping_pcb) { + return; + } + ping_pcb = raw_new(IP_PROTO_ICMP); + LWIP_ASSERT("ping_pcb != NULL", ping_pcb != NULL); + + raw_recv(ping_pcb, ping_recv, NULL); + raw_bind(ping_pcb, IP_ADDR_ANY); + sys_timeout(PING_DELAY, ping_timeout, ping_pcb); +} + +static void +ping_send_now(void) { + LWIP_ASSERT("ping_pcb != NULL", ping_pcb != NULL); + ping_send(ping_pcb, ping_target); +} + +#endif /* PING_USE_SOCKETS */ + +void +ping_init(const ip_addr_t *ping_addr) { + ping_target = ping_addr; + + #if PING_USE_SOCKETS + sys_thread_new("ping_thread", ping_thread, NULL, DEFAULT_THREAD_STACKSIZE, DEFAULT_THREAD_PRIO); + #else /* PING_USE_SOCKETS */ + ping_raw_init(); + #endif /* PING_USE_SOCKETS */ +} + +#endif /* LWIP_RAW */ diff --git a/ports/raspberrypi/lwip_src/ping.h b/ports/raspberrypi/lwip_src/ping.h new file mode 100644 index 0000000000..abbae9d086 --- /dev/null +++ b/ports/raspberrypi/lwip_src/ping.h @@ -0,0 +1,25 @@ +#ifndef LWIP_PING_H +#define LWIP_PING_H + +#include "lwip/raw.h" +#include "lwip/ip_addr.h" +#include "lwip/prot/icmp.h" + +/** + * PING_USE_SOCKETS: Set to 1 to use sockets, otherwise the raw api is used + */ +#ifndef PING_USE_SOCKETS +#define PING_USE_SOCKETS LWIP_SOCKET +#endif + +void ping_init(const ip_addr_t *ping_addr); +void ping_prepare_echo(struct icmp_echo_hdr *iecho, u16_t len); + +extern u16_t ping_seq_num; +#if !PING_USE_SOCKETS +void ping_set_target(const ip_addr_t *ping_addr); +int ping_send(struct raw_pcb *raw, const ip_addr_t *addr); +// u8_t ping_recv(void *arg, struct raw_pcb *pcb, struct pbuf *p, const ip_addr_t *addr); +#endif /* !PING_USE_SOCKETS */ + +#endif /* LWIP_PING_H */ diff --git a/ports/raspberrypi/mpconfigport.h b/ports/raspberrypi/mpconfigport.h index fd09d8a9ac..9bc97f6a78 100644 --- a/ports/raspberrypi/mpconfigport.h +++ b/ports/raspberrypi/mpconfigport.h @@ -49,4 +49,12 @@ mp_obj_t background_pio[NUM_DMA_CHANNELS]; \ CIRCUITPY_COMMON_ROOT_POINTERS; +#if CIRCUITPY_CYW43 +#include "pico/cyw43_arch.h" +#undef _L // interferes with ulab, indirectly defined in ctype.h, is ulab bug to use identifier _L +#define MICROPY_PY_LWIP_ENTER cyw43_arch_lwip_begin +#define MICROPY_PY_LWIP_REENTER MICROPY_PY_LWIP_ENTER +#define MICROPY_PY_LWIP_EXIT cyw43_arch_lwip_end +#endif + #endif // __INCLUDED_MPCONFIGPORT_H diff --git a/ports/raspberrypi/supervisor/port.c b/ports/raspberrypi/supervisor/port.c index 2e1fed7a25..94e57c2028 100644 --- a/ports/raspberrypi/supervisor/port.c +++ b/ports/raspberrypi/supervisor/port.c @@ -41,6 +41,10 @@ #include "shared-bindings/rtc/__init__.h" #include "shared-bindings/pwmio/PWMOut.h" +#if CIRCUITPY_WIFI +#include "common-hal/wifi/__init__.h" +#endif + #include "common-hal/rtc/RTC.h" #include "common-hal/busio/UART.h" @@ -134,15 +138,8 @@ safe_mode_t port_init(void) { never_reset_pin_number(29); if (cyw43_arch_init()) { serial_write("WiFi init failed\n"); - return -1; } else { cyw_ever_init = true; - for (int i = 3; i--;) { - cyw43_arch_gpio_put(0, 1); - sleep_ms(100); - cyw43_arch_gpio_put(0, 0); - sleep_ms(100); - } } #endif if (board_requests_safe_mode()) { @@ -182,6 +179,10 @@ void reset_port(void) { audio_dma_reset(); #endif + #if CIRCUITPY_WIFI + wifi_reset(); + #endif + reset_all_pins(); } diff --git a/py/objgenerator.c b/py/objgenerator.c index b18101cfa1..c9af11fbb5 100644 --- a/py/objgenerator.c +++ b/py/objgenerator.c @@ -330,7 +330,8 @@ STATIC mp_obj_t gen_instance_await(mp_obj_t self_in) { if (!self->coroutine_generator) { // Pretend like a generator does not have this coroutine behavior. // Pay no attention to the dir() behind the curtain - mp_raise_AttributeError(MP_ERROR_TEXT("type object 'generator' has no attribute '__await__'")); + mp_raise_msg_varg(&mp_type_AttributeError, MP_ERROR_TEXT("type object '%q' has no attribute '%q'"), + MP_QSTR_generator, MP_QSTR___await__); } // You can directly call send on a coroutine generator or you can __await__ then send on the return of that. return self; diff --git a/shared-bindings/wifi/Monitor.h b/shared-bindings/wifi/Monitor.h index 38c52a05e7..b828616ddb 100644 --- a/shared-bindings/wifi/Monitor.h +++ b/shared-bindings/wifi/Monitor.h @@ -29,7 +29,7 @@ #include "common-hal/wifi/Monitor.h" -const mp_obj_type_t wifi_monitor_type; +extern 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); diff --git a/shared-bindings/wifi/Network.h b/shared-bindings/wifi/Network.h index 0f07e7b555..574d690f37 100644 --- a/shared-bindings/wifi/Network.h +++ b/shared-bindings/wifi/Network.h @@ -33,7 +33,7 @@ #include "py/objstr.h" -const mp_obj_type_t wifi_network_type; +extern const mp_obj_type_t wifi_network_type; extern mp_obj_t common_hal_wifi_network_get_ssid(wifi_network_obj_t *self); extern mp_obj_t common_hal_wifi_network_get_bssid(wifi_network_obj_t *self); diff --git a/shared-bindings/wifi/Radio.c b/shared-bindings/wifi/Radio.c index bcd998d806..aecb1b561f 100644 --- a/shared-bindings/wifi/Radio.c +++ b/shared-bindings/wifi/Radio.c @@ -89,7 +89,7 @@ STATIC mp_obj_t wifi_radio_set_hostname(mp_obj_t self_in, mp_obj_t hostname_in) mp_arg_validate_length_range(hostname.len, 1, 253, MP_QSTR_hostname); - #ifndef CONFIG_IDF_TARGET_ESP32C3 + #if 0 // ndef 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)) { diff --git a/shared-bindings/wifi/Radio.h b/shared-bindings/wifi/Radio.h index 312e9e5395..479ce1a1b3 100644 --- a/shared-bindings/wifi/Radio.h +++ b/shared-bindings/wifi/Radio.h @@ -33,7 +33,7 @@ #include "py/objstr.h" -const mp_obj_type_t wifi_radio_type; +extern const mp_obj_type_t wifi_radio_type; typedef enum { // 0 is circuitpython-specific; 1-53 are IEEE; 200+ are Espressif diff --git a/tools/codeformat.py b/tools/codeformat.py index edefbc8ddc..3965e838a2 100644 --- a/tools/codeformat.py +++ b/tools/codeformat.py @@ -67,6 +67,8 @@ EXCLUSIONS = [ "tests/**/repl_*.py", # needs careful attention before applying automatic formatting "tests/basics/*.py", + # don't reindent this third-party code we vendored in + "ports/raspberrypi/lwip_src", ] # None of the standard Python path matching routines implement the matching diff --git a/tools/describe b/tools/describe index 7fd624abe3..e20c2ffa44 100755 --- a/tools/describe +++ b/tools/describe @@ -1,3 +1,3 @@ #!/bin/sh # Add any supplied arguments. -git describe --first-parent --dirty --tags --always --match "[1-9].*" "$@" +git describe --first-parent --dirty --tags --match "[1-9].*" "$@"