Merge branch 'main' into webflow_edit_page

# Conflicts:
#	supervisor/shared/web_workflow/web_workflow.c
This commit is contained in:
foamyguy 2022-07-25 19:20:05 -05:00
commit d0782b60cb
53 changed files with 836 additions and 170 deletions

View File

@ -211,6 +211,10 @@ msgstr "%q() mengambil posisi argumen %d tapi %d yang diberikan"
msgid "%q, %q, and %q must all be the same length"
msgstr "%q, %q, dan %q semuanya harus memiliki panjang yang sama"
#: py/objint.c
msgid "%q=%q"
msgstr ""
#: ports/espressif/bindings/espidf/__init__.c ports/espressif/esp_error.c
#, c-format
msgid "%s error 0x%x"

View File

@ -205,6 +205,10 @@ msgstr ""
msgid "%q, %q, and %q must all be the same length"
msgstr ""
#: py/objint.c
msgid "%q=%q"
msgstr ""
#: ports/espressif/bindings/espidf/__init__.c ports/espressif/esp_error.c
#, c-format
msgid "%s error 0x%x"

View File

@ -212,6 +212,10 @@ msgstr "%q() vyžaduje %d pozičních argumentů, ale %d jich bylo zadáno"
msgid "%q, %q, and %q must all be the same length"
msgstr "%q, %q, a %q musí mít všechny shodnou délku"
#: py/objint.c
msgid "%q=%q"
msgstr ""
#: ports/espressif/bindings/espidf/__init__.c ports/espressif/esp_error.c
#, c-format
msgid "%s error 0x%x"

View File

@ -214,6 +214,10 @@ msgstr ""
msgid "%q, %q, and %q must all be the same length"
msgstr "%q, %q und %q müssen alle die gleiche Länge haben"
#: py/objint.c
msgid "%q=%q"
msgstr ""
#: ports/espressif/bindings/espidf/__init__.c ports/espressif/esp_error.c
#, c-format
msgid "%s error 0x%x"

View File

@ -205,6 +205,10 @@ msgstr ""
msgid "%q, %q, and %q must all be the same length"
msgstr ""
#: py/objint.c
msgid "%q=%q"
msgstr ""
#: ports/espressif/bindings/espidf/__init__.c ports/espressif/esp_error.c
#, c-format
msgid "%s error 0x%x"

View File

@ -215,6 +215,10 @@ msgstr "%q() takes %d positional arguments but %d were given"
msgid "%q, %q, and %q must all be the same length"
msgstr "%q, %q, and %q must all be the same length"
#: py/objint.c
msgid "%q=%q"
msgstr ""
#: ports/espressif/bindings/espidf/__init__.c ports/espressif/esp_error.c
#, c-format
msgid "%s error 0x%x"

View File

@ -214,6 +214,10 @@ msgstr "%q() toma %d argumentos posicionales pero %d fueron dados"
msgid "%q, %q, and %q must all be the same length"
msgstr ""
#: py/objint.c
msgid "%q=%q"
msgstr ""
#: ports/espressif/bindings/espidf/__init__.c ports/espressif/esp_error.c
#, c-format
msgid "%s error 0x%x"

View File

@ -208,6 +208,10 @@ msgstr ""
msgid "%q, %q, and %q must all be the same length"
msgstr ""
#: py/objint.c
msgid "%q=%q"
msgstr ""
#: ports/espressif/bindings/espidf/__init__.c ports/espressif/esp_error.c
#, c-format
msgid "%s error 0x%x"

View File

@ -8,14 +8,14 @@ msgstr ""
"Project-Id-Version: 0.1\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2021-01-04 12:55-0600\n"
"PO-Revision-Date: 2022-07-06 05:15+0000\n"
"PO-Revision-Date: 2022-07-19 23:15+0000\n"
"Last-Translator: Maxime Leroy <lisacintosh@gmail.com>\n"
"Language: fr\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=n > 1;\n"
"X-Generator: Weblate 4.13.1-dev\n"
"X-Generator: Weblate 4.14-dev\n"
#: main.c
msgid ""
@ -217,6 +217,10 @@ msgstr "%q() prend %d paramètres positionnels mais %d ont été donnés"
msgid "%q, %q, and %q must all be the same length"
msgstr "%q, %q, et %q doivent tous être de la même longueur"
#: py/objint.c
msgid "%q=%q"
msgstr ""
#: ports/espressif/bindings/espidf/__init__.c ports/espressif/esp_error.c
#, c-format
msgid "%s error 0x%x"
@ -2291,7 +2295,7 @@ msgstr "Format non supporté"
#: shared-bindings/hashlib/__init__.c
msgid "Unsupported hash algorithm"
msgstr ""
msgstr "Algorithme de hachage non supporté"
#: ports/espressif/common-hal/dualbank/__init__.c
msgid "Update Failed"
@ -2459,7 +2463,7 @@ msgstr "la taille de la matrice et de l'index doivent être égaux"
#: extmod/ulab/code/numpy/io/io.c
msgid "array has too many dimensions"
msgstr ""
msgstr "la tableau à trop de dimensions"
#: py/objarray.c shared-bindings/alarm/SleepMemory.c
#: shared-bindings/nvm/ByteArray.c
@ -2840,7 +2844,7 @@ msgstr "les arguments convolve ne doivent pas être vides"
#: extmod/ulab/code/numpy/io/io.c
msgid "corrupted file"
msgstr ""
msgstr "fichier corrompu"
#: extmod/ulab/code/numpy/poly.c
msgid "could not invert Vandermonde matrix"
@ -2938,7 +2942,7 @@ msgstr "vide"
#: extmod/ulab/code/numpy/io/io.c
msgid "empty file"
msgstr ""
msgstr "fichier vide"
#: extmod/moduasyncio.c extmod/moduheapq.c extmod/modutimeq.c
msgid "empty heap"
@ -3261,7 +3265,7 @@ msgstr "la matrice d'entrée est singulière"
#: extmod/ulab/code/numpy/create.c
msgid "input must be 1- or 2-d"
msgstr ""
msgstr "l'entrée doit être 1D ou 2D"
#: extmod/ulab/code/numpy/carray/carray.c
msgid "input must be a 1D ndarray"
@ -3479,7 +3483,7 @@ msgstr "max_length doit être 0-%d lorsque fixed_length est %s"
#: extmod/ulab/code/ndarray.c
msgid "maximum number of dimensions is "
msgstr ""
msgstr "le nombre maximal de dimensions est "
#: py/runtime.c
msgid "maximum recursion depth exceeded"
@ -3883,7 +3887,7 @@ msgstr "pow() avec 3 arguments nécessite des entiers"
#: ports/espressif/boards/adafruit_feather_esp32_v2/mpconfigboard.h
msgid "pressing SW38 button at start up.\n"
msgstr ""
msgstr "presser le bouton SW38 au démarrage.\n"
#: ports/espressif/boards/adafruit_qtpy_esp32c3/mpconfigboard.h
#: ports/espressif/boards/lolin_c3_mini/mpconfigboard.h
@ -4327,11 +4331,11 @@ msgstr "types non supportés pour %q: '%q', '%q'"
#: extmod/ulab/code/numpy/io/io.c
msgid "usecols is too high"
msgstr ""
msgstr "usecols est trop grand"
#: extmod/ulab/code/numpy/io/io.c
msgid "usecols keyword must be specified"
msgstr ""
msgstr "le mot-clé \"usecols\" doit être spécifié"
#: py/objint.c
#, c-format
@ -4376,7 +4380,7 @@ msgstr "axe incorrecte spécifiée"
#: extmod/ulab/code/numpy/io/io.c
msgid "wrong dtype"
msgstr ""
msgstr "dtype invalide"
#: extmod/ulab/code/numpy/transform.c
msgid "wrong index type"
@ -4394,7 +4398,7 @@ msgstr "mauvaise taille du tableau de condition"
#: extmod/ulab/code/numpy/transform.c
msgid "wrong length of index array"
msgstr ""
msgstr "mauvaise longueur du tableau d'indices"
#: extmod/ulab/code/numpy/create.c py/objarray.c py/objstr.c
msgid "wrong number of arguments"

View File

@ -205,6 +205,10 @@ msgstr ""
msgid "%q, %q, and %q must all be the same length"
msgstr ""
#: py/objint.c
msgid "%q=%q"
msgstr ""
#: ports/espressif/bindings/espidf/__init__.c ports/espressif/esp_error.c
#, c-format
msgid "%s error 0x%x"

View File

@ -213,6 +213,10 @@ msgstr "%q() prende %d argomenti posizionali ma ne sono stati forniti %d"
msgid "%q, %q, and %q must all be the same length"
msgstr ""
#: py/objint.c
msgid "%q=%q"
msgstr ""
#: ports/espressif/bindings/espidf/__init__.c ports/espressif/esp_error.c
#, c-format
msgid "%s error 0x%x"

View File

@ -210,6 +210,10 @@ msgstr "%q() は %d 個の位置引数を取りますが、%d 個与えられま
msgid "%q, %q, and %q must all be the same length"
msgstr ""
#: py/objint.c
msgid "%q=%q"
msgstr ""
#: ports/espressif/bindings/espidf/__init__.c ports/espressif/esp_error.c
#, c-format
msgid "%s error 0x%x"

View File

@ -206,6 +206,10 @@ msgstr ""
msgid "%q, %q, and %q must all be the same length"
msgstr ""
#: py/objint.c
msgid "%q=%q"
msgstr ""
#: ports/espressif/bindings/espidf/__init__.c ports/espressif/esp_error.c
#, c-format
msgid "%s error 0x%x"

View File

@ -208,6 +208,10 @@ msgstr "%q() verwacht %d positionele argumenten maar kreeg %d"
msgid "%q, %q, and %q must all be the same length"
msgstr ""
#: py/objint.c
msgid "%q=%q"
msgstr ""
#: ports/espressif/bindings/espidf/__init__.c ports/espressif/esp_error.c
#, c-format
msgid "%s error 0x%x"

View File

@ -210,6 +210,10 @@ msgstr "%q() bierze %d argumentów pozycyjnych, lecz podano %d"
msgid "%q, %q, and %q must all be the same length"
msgstr ""
#: py/objint.c
msgid "%q=%q"
msgstr ""
#: ports/espressif/bindings/espidf/__init__.c ports/espressif/esp_error.c
#, c-format
msgid "%s error 0x%x"

View File

@ -6,7 +6,7 @@ msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2021-01-04 12:55-0600\n"
"PO-Revision-Date: 2022-07-12 13:10+0000\n"
"PO-Revision-Date: 2022-07-24 22:22+0000\n"
"Last-Translator: Wellington Terumi Uemura <wellingtonuemura@gmail.com>\n"
"Language-Team: \n"
"Language: pt_BR\n"
@ -214,6 +214,10 @@ msgstr "%q() recebe %d argumentos posicionais, porém %d foram informados"
msgid "%q, %q, and %q must all be the same length"
msgstr "todos os %q, %q, e %q devem ter mesmo comprimento"
#: py/objint.c
msgid "%q=%q"
msgstr "%q=%q"
#: ports/espressif/bindings/espidf/__init__.c ports/espressif/esp_error.c
#, c-format
msgid "%s error 0x%x"
@ -2273,7 +2277,7 @@ msgstr "Formato não suportado"
#: shared-bindings/hashlib/__init__.c
msgid "Unsupported hash algorithm"
msgstr ""
msgstr "Sem compatibilidade com o algoritmo de hash"
#: ports/espressif/common-hal/dualbank/__init__.c
msgid "Update Failed"
@ -3860,7 +3864,7 @@ msgstr "o pow() com 3 argumentos requer números inteiros"
#: ports/espressif/boards/adafruit_feather_esp32_v2/mpconfigboard.h
msgid "pressing SW38 button at start up.\n"
msgstr ""
msgstr "pressionando o botão SW38 na inicialização.\n"
#: ports/espressif/boards/adafruit_qtpy_esp32c3/mpconfigboard.h
#: ports/espressif/boards/lolin_c3_mini/mpconfigboard.h

View File

@ -213,6 +213,10 @@ msgstr "%q() принимает %d позиционных аргументов,
msgid "%q, %q, and %q must all be the same length"
msgstr "%q, %q, и %q должны быть одной длинны"
#: py/objint.c
msgid "%q=%q"
msgstr ""
#: ports/espressif/bindings/espidf/__init__.c ports/espressif/esp_error.c
#, c-format
msgid "%s error 0x%x"

View File

@ -6,7 +6,7 @@ msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2021-01-04 12:55-0600\n"
"PO-Revision-Date: 2022-07-14 18:05+0000\n"
"PO-Revision-Date: 2022-07-21 20:15+0000\n"
"Last-Translator: Jonny Bergdahl <jonny@bergdahl.it>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"Language: sv\n"
@ -213,6 +213,10 @@ msgstr "% q() tar %d positionsargument men %d gavs"
msgid "%q, %q, and %q must all be the same length"
msgstr "%q, %q och %q måste vara lika långa"
#: py/objint.c
msgid "%q=%q"
msgstr "%q=%q"
#: ports/espressif/bindings/espidf/__init__.c ports/espressif/esp_error.c
#, c-format
msgid "%s error 0x%x"

View File

@ -217,6 +217,10 @@ msgstr "%q(), %d konumsal argümanını alır ancak %d verildi"
msgid "%q, %q, and %q must all be the same length"
msgstr "%q, %q ve %q aynı uzunlukta olmalıdır"
#: py/objint.c
msgid "%q=%q"
msgstr ""
#: ports/espressif/bindings/espidf/__init__.c ports/espressif/esp_error.c
#, c-format
msgid "%s error 0x%x"

View File

@ -216,6 +216,10 @@ msgstr "%q() yāoqiú shūrù %d gè wèizhì cānshù, dàn mùqián shūrù le
msgid "%q, %q, and %q must all be the same length"
msgstr "%q, %q, hé %q bì xū cháng dù xiāng tóng"
#: py/objint.c
msgid "%q=%q"
msgstr ""
#: ports/espressif/bindings/espidf/__init__.c ports/espressif/esp_error.c
#, c-format
msgid "%s error 0x%x"

View File

@ -61,17 +61,12 @@ endif
MICROPY_PY_ASYNC_AWAIT = 0
# We don't have room for the fonts for terminalio for ja and ko
# We don't have room for the fonts for terminalio for certain languages,
# so turn off terminalio, and if it's off and displayio is on,
# force a clean build.
# Note that we cannot test $(CIRCUITPY_DISPLAYIO) directly with an
# ifeq, because it's not set yet.
ifeq ($(TRANSLATION), ja)
CIRCUITPY_TERMINALIO = 0
RELEASE_NEEDS_CLEAN_BUILD = $(CIRCUITPY_DISPLAYIO)
endif
ifeq ($(TRANSLATION), ko)
ifneq (,$(filter $(TRANSLATION),ja ko ru))
CIRCUITPY_TERMINALIO = 0
RELEASE_NEEDS_CLEAN_BUILD = $(CIRCUITPY_DISPLAYIO)
endif

View File

@ -40,20 +40,12 @@
#include "common-hal/pulseio/PulseIn.h"
#endif
#if CIRCUITPY_WEB_WORKFLOW
#include "supervisor/shared/web_workflow/web_workflow.h"
#endif
void port_background_task(void) {
// Zero delay in case FreeRTOS wants to switch to something else.
vTaskDelay(0);
#if CIRCUITPY_PULSEIO
pulsein_background();
#endif
#if CIRCUITPY_WEB_WORKFLOW
supervisor_web_workflow_background();
#endif
}
void port_start_background_task(void) {

View File

@ -15,3 +15,5 @@ CFLAGS += -DCFG_TUD_TASK_QUEUE_SZ=32
CIRCUITPY_ESP_FLASH_MODE = qio
CIRCUITPY_ESP_FLASH_FREQ = 40m
CIRCUITPY_ESP_FLASH_SIZE = 4MB
CIRCUITPY_PS2IO = 0

View File

@ -16,3 +16,5 @@ CFLAGS += -DCFG_TUD_TASK_QUEUE_SZ=32
CIRCUITPY_ESP_FLASH_MODE = dio
CIRCUITPY_ESP_FLASH_FREQ = 40m
CIRCUITPY_ESP_FLASH_SIZE = 4MB
OPTIMIZATION_FLAGS = -Os

View File

@ -0,0 +1,47 @@
/*
* 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 "shared-bindings/microcontroller/Pin.h"
#include "supervisor/board.h"
#include "components/driver/include/driver/gpio.h"
void board_init(void) {
}
bool board_requests_safe_mode(void) {
return false;
}
bool espressif_board_reset_pin_number(gpio_num_t pin_number) {
return false;
}
void reset_board(void) {
}
void board_deinit(void) {
}

View File

@ -0,0 +1,47 @@
/*
* This file is part of the MicroPython project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2019 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.
*/
// Board setup
#define MICROPY_HW_BOARD_NAME "DFRobot Beetle ESP32-C3"
#define MICROPY_HW_MCU_NAME "ESP32-C3FN4"
// Status LED
#define MICROPY_HW_NEOPIXEL (&pin_GPIO10)
#define CIRCUITPY_BOARD_I2C (1)
#define CIRCUITPY_BOARD_I2C_PIN {{.scl = &pin_GPIO9, .sda = &pin_GPIO8}}
#define CIRCUITPY_BOARD_SPI (1)
#define CIRCUITPY_BOARD_SPI_PIN {{.clock = &pin_GPIO4, .mosi = &pin_GPIO6, .miso = &pin_GPIO5}}
#define CIRCUITPY_BOARD_UART (1)
#define CIRCUITPY_BOARD_UART_PIN {{.tx = &pin_GPIO21, .rx = &pin_GPIO20}}
// Explanation of how a user got into safe mode
#define BOARD_USER_SAFE_MODE_ACTION translate("pressing boot button at start up.\n")
#define CIRCUITPY_ESP_USB_SERIAL_JTAG (1)

View File

@ -0,0 +1,11 @@
# TODO
CIRCUITPY_CREATOR_ID = 0x10101010
CIRCUITPY_CREATION_ID = 0x00C30001
IDF_TARGET = esp32c3
INTERNAL_FLASH_FILESYSTEM = 1
CIRCUITPY_ESP_FLASH_MODE=qio
CIRCUITPY_ESP_FLASH_FREQ=80m
CIRCUITPY_ESP_FLASH_SIZE=4MB

View File

@ -0,0 +1,66 @@
#include "shared-bindings/board/__init__.h"
STATIC const mp_rom_map_elem_t board_module_globals_table[] = {
CIRCUITPYTHON_BOARD_DICT_STANDARD_ITEMS
{ MP_ROM_QSTR(MP_QSTR_IO0), MP_ROM_PTR(&pin_GPIO0) },
{ MP_ROM_QSTR(MP_QSTR_A0), MP_ROM_PTR(&pin_GPIO0) }, // ADC1_0
{ MP_ROM_QSTR(MP_QSTR_D0), MP_ROM_PTR(&pin_GPIO0) },
{ MP_ROM_QSTR(MP_QSTR_IO1), MP_ROM_PTR(&pin_GPIO1) },
{ MP_ROM_QSTR(MP_QSTR_A1), MP_ROM_PTR(&pin_GPIO1) }, // ADC1_1
{ MP_ROM_QSTR(MP_QSTR_D1), MP_ROM_PTR(&pin_GPIO1) },
{ MP_ROM_QSTR(MP_QSTR_IO2), MP_ROM_PTR(&pin_GPIO2) },
{ MP_ROM_QSTR(MP_QSTR_A2), MP_ROM_PTR(&pin_GPIO2) }, // ADC1_2
{ MP_ROM_QSTR(MP_QSTR_D2), MP_ROM_PTR(&pin_GPIO2) },
// Pad on Board
{ MP_ROM_QSTR(MP_QSTR_IO3), MP_ROM_PTR(&pin_GPIO3) },
{ MP_ROM_QSTR(MP_QSTR_A3), MP_ROM_PTR(&pin_GPIO3) }, // ADC1_3
{ MP_ROM_QSTR(MP_QSTR_D3), MP_ROM_PTR(&pin_GPIO3) },
{ MP_ROM_QSTR(MP_QSTR_IO4), MP_ROM_PTR(&pin_GPIO4) },
{ MP_ROM_QSTR(MP_QSTR_A4), MP_ROM_PTR(&pin_GPIO4) }, // ADC1_4, JTAG MTMS
{ MP_ROM_QSTR(MP_QSTR_SCK), MP_ROM_PTR(&pin_GPIO4) },
{ MP_ROM_QSTR(MP_QSTR_D4), MP_ROM_PTR(&pin_GPIO4) },
{ MP_ROM_QSTR(MP_QSTR_IO5), MP_ROM_PTR(&pin_GPIO5) },
{ MP_ROM_QSTR(MP_QSTR_A5), MP_ROM_PTR(&pin_GPIO5) }, // JTAG MTDI
{ MP_ROM_QSTR(MP_QSTR_MISO), MP_ROM_PTR(&pin_GPIO5) },
{ MP_ROM_QSTR(MP_QSTR_D5), MP_ROM_PTR(&pin_GPIO5) },
{ MP_ROM_QSTR(MP_QSTR_IO6), MP_ROM_PTR(&pin_GPIO6) }, // JTAG MTCK
{ MP_ROM_QSTR(MP_QSTR_MOSI), MP_ROM_PTR(&pin_GPIO6) },
{ MP_ROM_QSTR(MP_QSTR_D6), MP_ROM_PTR(&pin_GPIO6) },
{ MP_ROM_QSTR(MP_QSTR_IO7), MP_ROM_PTR(&pin_GPIO7) }, // JTAG MTDO
{ MP_ROM_QSTR(MP_QSTR_D7), MP_ROM_PTR(&pin_GPIO7) },
{ MP_ROM_QSTR(MP_QSTR_IO8), MP_ROM_PTR(&pin_GPIO8) },
{ MP_ROM_QSTR(MP_QSTR_D8), MP_ROM_PTR(&pin_GPIO8) },
{ MP_ROM_QSTR(MP_QSTR_SDA), MP_ROM_PTR(&pin_GPIO8) },
{ MP_ROM_QSTR(MP_QSTR_IO9), MP_ROM_PTR(&pin_GPIO9) },
{ MP_ROM_QSTR(MP_QSTR_D9), MP_ROM_PTR(&pin_GPIO9) },
{ MP_ROM_QSTR(MP_QSTR_SCL), MP_ROM_PTR(&pin_GPIO9) },
{ MP_ROM_QSTR(MP_QSTR_IO10), MP_ROM_PTR(&pin_GPIO10) },
{ MP_ROM_QSTR(MP_QSTR_LED), MP_ROM_PTR(&pin_GPIO10) },
{ MP_ROM_QSTR(MP_QSTR_D10), MP_ROM_PTR(&pin_GPIO10) },
{ MP_ROM_QSTR(MP_QSTR_IO20), MP_ROM_PTR(&pin_GPIO20) },
{ MP_ROM_QSTR(MP_QSTR_A7), MP_ROM_PTR(&pin_GPIO20) },
{ MP_ROM_QSTR(MP_QSTR_RX), MP_ROM_PTR(&pin_GPIO20) },
{ MP_ROM_QSTR(MP_QSTR_IO21), MP_ROM_PTR(&pin_GPIO21) },
{ MP_ROM_QSTR(MP_QSTR_A6), MP_ROM_PTR(&pin_GPIO21) },
{ MP_ROM_QSTR(MP_QSTR_TX), MP_ROM_PTR(&pin_GPIO21) },
{ MP_ROM_QSTR(MP_QSTR_I2C), MP_ROM_PTR(&board_i2c_obj) },
{ MP_ROM_QSTR(MP_QSTR_SPI), MP_ROM_PTR(&board_spi_obj) },
{ MP_ROM_QSTR(MP_QSTR_UART), MP_ROM_PTR(&board_uart_obj) },
};
MP_DEFINE_CONST_DICT(board_module_globals, board_module_globals_table);

View File

@ -0,0 +1,7 @@
#
# LWIP
#
CONFIG_LWIP_LOCAL_HOSTNAME="beetle-esp32-c3
# end of LWIP

View File

@ -394,6 +394,11 @@ STATIC void discover_remote_services(bleio_connection_internal_t *self, mp_obj_t
? service->end_handle
: next_characteristic->def_handle - 1;
// Pre-check if characteristic is empty so descriptor discovery doesn't fail
if (end_handle <= characteristic->handle) {
continue;
}
_last_discovery_status = BLE_ERR_SUCCESS;
CHECK_NIMBLE_ERROR(ble_gattc_disc_all_dscs(self->conn_handle, characteristic->handle,
end_handle,

View File

@ -90,6 +90,10 @@ const char *common_hal_mdns_server_get_hostname(mdns_server_obj_t *self) {
void common_hal_mdns_server_set_hostname(mdns_server_obj_t *self, const char *hostname) {
mdns_hostname_set(hostname);
// Wait for the mdns task to set the new hostname.
while (!mdns_hostname_exists(hostname)) {
RUN_BACKGROUND_TASKS;
}
self->hostname = hostname;
}

View File

@ -30,38 +30,213 @@
#include "shared/runtime/interrupt_char.h"
#include "py/mperrno.h"
#include "py/runtime.h"
#include "shared-bindings/socketpool/SocketPool.h"
#include "supervisor/port.h"
#include "supervisor/shared/tick.h"
#include "supervisor/workflow.h"
#include "components/lwip/lwip/src/include/lwip/err.h"
#include "components/lwip/lwip/src/include/lwip/sockets.h"
#include "components/lwip/lwip/src/include/lwip/sys.h"
#include "components/lwip/lwip/src/include/lwip/netdb.h"
#include "components/vfs/include/esp_vfs_eventfd.h"
STATIC socketpool_socket_obj_t *open_socket_handles[CONFIG_LWIP_MAX_SOCKETS];
StackType_t socket_select_stack[2 * configMINIMAL_STACK_SIZE];
STATIC int open_socket_fds[CONFIG_LWIP_MAX_SOCKETS];
STATIC bool user_socket[CONFIG_LWIP_MAX_SOCKETS];
StaticTask_t socket_select_task_handle;
STATIC int socket_change_fd = -1;
STATIC void socket_select_task(void *arg) {
uint64_t signal;
while (true) {
fd_set readfds;
fd_set errfds;
FD_ZERO(&readfds);
FD_ZERO(&errfds);
FD_SET(socket_change_fd, &readfds);
FD_SET(socket_change_fd, &errfds);
int max_fd = socket_change_fd;
for (size_t i = 0; i < MP_ARRAY_SIZE(open_socket_fds); i++) {
if (open_socket_fds[i] < 0) {
continue;
}
max_fd = MAX(max_fd, open_socket_fds[i]);
FD_SET(open_socket_fds[i], &readfds);
FD_SET(open_socket_fds[i], &errfds);
}
int num_triggered = select(max_fd + 1, &readfds, NULL, &errfds, NULL);
if (num_triggered < 0) {
// Maybe bad file descriptor
for (size_t i = 0; i < MP_ARRAY_SIZE(open_socket_fds); i++) {
int sockfd = open_socket_fds[i];
if (sockfd < 0) {
continue;
}
if (FD_ISSET(sockfd, &errfds)) {
int err;
int optlen = sizeof(int);
int ret = getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &err, (socklen_t *)&optlen);
if (ret < 0) {
open_socket_fds[i] = -1;
// Try again.
continue;
}
}
}
}
assert(num_triggered >= 0);
if (FD_ISSET(socket_change_fd, &readfds)) {
read(socket_change_fd, &signal, sizeof(signal));
num_triggered -= 1;
}
if (num_triggered > 0) {
supervisor_workflow_request_background();
// Wake up CircuitPython. We know it is asleep because we are lower
// priority.
port_wake_main_task();
}
}
close(socket_change_fd);
vTaskDelete(NULL);
}
void socket_user_reset(void) {
for (size_t i = 0; i < MP_ARRAY_SIZE(open_socket_handles); i++) {
if (open_socket_handles[i]) {
if (open_socket_handles[i]->num > 0) {
// Close automatically clears socket handle
common_hal_socketpool_socket_close(open_socket_handles[i]);
} else {
open_socket_handles[i] = NULL;
}
if (socket_change_fd < 0) {
esp_vfs_eventfd_config_t config = ESP_VFS_EVENTD_CONFIG_DEFAULT();
ESP_ERROR_CHECK(esp_vfs_eventfd_register(&config));
for (size_t i = 0; i < MP_ARRAY_SIZE(open_socket_fds); i++) {
open_socket_fds[i] = -1;
user_socket[i] = false;
}
socket_change_fd = eventfd(0, 0);
// This task runs at a lower priority than CircuitPython and is used to wake CircuitPython
// up when any open sockets have data to read. It allows us to sleep otherwise.
(void)xTaskCreateStaticPinnedToCore(socket_select_task,
"socket_select",
2 * configMINIMAL_STACK_SIZE,
NULL,
0, // Run this at IDLE priority. We only need it when CP isn't running (at 1).
socket_select_stack,
&socket_select_task_handle,
xPortGetCoreID());
}
for (size_t i = 0; i < MP_ARRAY_SIZE(open_socket_fds); i++) {
if (open_socket_fds[i] >= 0 && user_socket[i]) {
int num = open_socket_fds[i];
// Close automatically clears socket handle
lwip_shutdown(num, SHUT_RDWR);
lwip_close(num);
open_socket_fds[i] = -1;
user_socket[i] = false;
}
}
}
bool register_open_socket(socketpool_socket_obj_t *self) {
for (size_t i = 0; i < MP_ARRAY_SIZE(open_socket_handles); i++) {
if (open_socket_handles[i] == NULL) {
open_socket_handles[i] = self;
// The writes below send an event to the socket select task so that it redoes the
// select with the new open socket set.
STATIC bool register_open_socket(int fd) {
for (size_t i = 0; i < MP_ARRAY_SIZE(open_socket_fds); i++) {
if (open_socket_fds[i] == -1) {
open_socket_fds[i] = fd;
user_socket[i] = false;
uint64_t signal = 1;
write(socket_change_fd, &signal, sizeof(signal));
return true;
}
}
return false;
}
STATIC void unregister_open_socket(int fd) {
for (size_t i = 0; i < MP_ARRAY_SIZE(open_socket_fds); i++) {
if (open_socket_fds[i] == fd) {
open_socket_fds[i] = -1;
user_socket[i] = false;
write(socket_change_fd, &fd, sizeof(fd));
return;
}
}
}
STATIC void mark_user_socket(int fd) {
for (size_t i = 0; i < MP_ARRAY_SIZE(open_socket_fds); i++) {
if (open_socket_fds[i] == fd) {
user_socket[i] = true;
return;
}
}
}
bool socketpool_socket(socketpool_socketpool_obj_t *self,
socketpool_socketpool_addressfamily_t family, socketpool_socketpool_sock_t type,
socketpool_socket_obj_t *sock) {
int addr_family;
int ipproto;
if (family == SOCKETPOOL_AF_INET) {
addr_family = AF_INET;
ipproto = IPPROTO_IP;
} else { // INET6
addr_family = AF_INET6;
ipproto = IPPROTO_IPV6;
}
int socket_type;
if (type == SOCKETPOOL_SOCK_STREAM) {
socket_type = SOCK_STREAM;
} else if (type == SOCKETPOOL_SOCK_DGRAM) {
socket_type = SOCK_DGRAM;
} else { // SOCKETPOOL_SOCK_RAW
socket_type = SOCK_RAW;
}
sock->type = socket_type;
sock->family = addr_family;
sock->ipproto = ipproto;
sock->pool = self;
sock->timeout_ms = (uint)-1;
// Create LWIP socket
int socknum = -1;
socknum = lwip_socket(sock->family, sock->type, sock->ipproto);
if (socknum < 0) {
return false;
}
// This shouldn't happen since we have room for the same number of sockets as LWIP.
if (!register_open_socket(socknum)) {
lwip_close(socknum);
return false;
}
sock->num = socknum;
// Sockets should be nonblocking in most cases
lwip_fcntl(socknum, F_SETFL, O_NONBLOCK);
return true;
}
socketpool_socket_obj_t *common_hal_socketpool_socket(socketpool_socketpool_obj_t *self,
socketpool_socketpool_addressfamily_t family, socketpool_socketpool_sock_t type) {
if (family != SOCKETPOOL_AF_INET) {
mp_raise_NotImplementedError(translate("Only IPv4 sockets supported"));
}
socketpool_socket_obj_t *sock = m_new_obj_with_finaliser(socketpool_socket_obj_t);
sock->base.type = &socketpool_socket_type;
if (!socketpool_socket(self, family, type, sock)) {
mp_raise_RuntimeError(translate("Out of sockets"));
}
mark_user_socket(sock->num);
return sock;
}
int socketpool_socket_accept(socketpool_socket_obj_t *self, uint8_t *ip, uint32_t *port) {
struct sockaddr_in accept_addr;
socklen_t socklen = sizeof(accept_addr);
@ -92,6 +267,10 @@ int socketpool_socket_accept(socketpool_socket_obj_t *self, uint8_t *ip, uint32_
if (newsoc < 0) {
return -MP_EBADF;
}
if (!register_open_socket(newsoc)) {
lwip_close(newsoc);
return -MP_EBADF;
}
return newsoc;
}
@ -100,6 +279,7 @@ socketpool_socket_obj_t *common_hal_socketpool_socket_accept(socketpool_socket_o
int newsoc = socketpool_socket_accept(self, ip, port);
if (newsoc > 0) {
mark_user_socket(newsoc);
// Create the socket
socketpool_socket_obj_t *sock = m_new_obj_with_finaliser(socketpool_socket_obj_t);
sock->base.type = &socketpool_socket_type;
@ -107,10 +287,6 @@ socketpool_socket_obj_t *common_hal_socketpool_socket_accept(socketpool_socket_o
sock->pool = self->pool;
sock->connected = true;
if (!register_open_socket(sock)) {
mp_raise_OSError(MP_EBADF);
}
lwip_fcntl(newsoc, F_SETFL, O_NONBLOCK);
return sock;
} else {
@ -150,18 +326,13 @@ void socketpool_socket_close(socketpool_socket_obj_t *self) {
if (self->num >= 0) {
lwip_shutdown(self->num, SHUT_RDWR);
lwip_close(self->num);
unregister_open_socket(self->num);
self->num = -1;
}
}
void common_hal_socketpool_socket_close(socketpool_socket_obj_t *self) {
socketpool_socket_close(self);
// Remove socket record
for (size_t i = 0; i < MP_ARRAY_SIZE(open_socket_handles); i++) {
if (open_socket_handles[i] == self) {
open_socket_handles[i] = NULL;
}
}
}
void common_hal_socketpool_socket_connect(socketpool_socket_obj_t *self,

View File

@ -46,6 +46,5 @@ typedef struct {
} socketpool_socket_obj_t;
void socket_user_reset(void);
bool register_open_socket(socketpool_socket_obj_t *self);
#endif // MICROPY_INCLUDED_ESPRESSIF_COMMON_HAL_SOCKETPOOL_SOCKET_H

View File

@ -40,61 +40,7 @@ void common_hal_socketpool_socketpool_construct(socketpool_socketpool_obj_t *sel
}
}
bool socketpool_socket(socketpool_socketpool_obj_t *self,
socketpool_socketpool_addressfamily_t family, socketpool_socketpool_sock_t type,
socketpool_socket_obj_t *sock) {
int addr_family;
int ipproto;
if (family == SOCKETPOOL_AF_INET) {
addr_family = AF_INET;
ipproto = IPPROTO_IP;
} else { // INET6
addr_family = AF_INET6;
ipproto = IPPROTO_IPV6;
}
int socket_type;
if (type == SOCKETPOOL_SOCK_STREAM) {
socket_type = SOCK_STREAM;
} else if (type == SOCKETPOOL_SOCK_DGRAM) {
socket_type = SOCK_DGRAM;
} else { // SOCKETPOOL_SOCK_RAW
socket_type = SOCK_RAW;
}
sock->type = socket_type;
sock->family = addr_family;
sock->ipproto = ipproto;
sock->pool = self;
sock->timeout_ms = (uint)-1;
// Create LWIP socket
int socknum = -1;
socknum = lwip_socket(sock->family, sock->type, sock->ipproto);
if (socknum < 0) {
return false;
}
sock->num = socknum;
// Sockets should be nonblocking in most cases
lwip_fcntl(socknum, F_SETFL, O_NONBLOCK);
return true;
}
socketpool_socket_obj_t *common_hal_socketpool_socket(socketpool_socketpool_obj_t *self,
socketpool_socketpool_addressfamily_t family, socketpool_socketpool_sock_t type) {
if (family != SOCKETPOOL_AF_INET) {
mp_raise_NotImplementedError(translate("Only IPv4 sockets supported"));
}
socketpool_socket_obj_t *sock = m_new_obj_with_finaliser(socketpool_socket_obj_t);
sock->base.type = &socketpool_socket_type;
if (!socketpool_socket(self, family, type, sock) ||
!register_open_socket(sock)) {
mp_raise_RuntimeError(translate("Out of sockets"));
}
return sock;
}
// common_hal_socketpool_socket is in socketpool/Socket.c to centralize open socket tracking.
mp_obj_t common_hal_socketpool_socketpool_gethostbyname(socketpool_socketpool_obj_t *self,
const char *host) {

@ -1 +1 @@
Subproject commit 171e5af9c5b9b126c5f81f217c7b1ff931d54863
Subproject commit 0180c0cb80f052919badc15df164e8edde6344ad

View File

@ -53,6 +53,7 @@
#include "shared-bindings/microcontroller/__init__.h"
#include "shared-bindings/microcontroller/RunMode.h"
#include "shared-bindings/rtc/__init__.h"
#include "shared-bindings/socketpool/__init__.h"
#include "peripherals/rmt.h"
#include "peripherals/timer.h"
@ -296,6 +297,10 @@ void reset_port(void) {
rtc_reset();
#endif
#if CIRCUITPY_SOCKETPOOL
socketpool_user_reset();
#endif
#if CIRCUITPY_TOUCHIO_USE_NATIVE
peripherals_touch_reset();
#endif

View File

@ -247,7 +247,7 @@ STATIC mp_obj_t rp2pio_statemachine_make_new(const mp_obj_type_t *type, size_t n
mp_raise_ValueError(translate("Program size invalid"));
}
mp_arg_validate_length_range(init_bufinfo.len, 2, 64, MP_QSTR_init);
mp_arg_validate_length_range(init_bufinfo.len, 0, 64, MP_QSTR_init);
if (init_bufinfo.len % 2 != 0) {
mp_raise_ValueError(translate("Init program size invalid"));
}

View File

@ -0,0 +1,40 @@
/*
* This file is part of the MicroPython project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2021 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/board.h"
void board_init(void) {
}
bool board_requests_safe_mode(void) {
return false;
}
void reset_board(void) {
}
void board_deinit(void) {
}

View File

@ -0,0 +1,15 @@
#define MICROPY_HW_BOARD_NAME "Fig Pi"
#define MICROPY_HW_MCU_NAME "rp2040"
#define MICROPY_HW_NEOPIXEL (&pin_GPIO13)
#define CIRCUITPY_STATUS_LED_POWER (&pin_GPIO1)
#define CIRCUITPY_BOARD_I2C (2)
#define CIRCUITPY_BOARD_I2C_PIN {{.scl = &pin_GPIO17, .sda = &pin_GPIO16}, \
{.scl = &pin_GPIO19, .sda = &pin_GPIO18}}
#define CIRCUITPY_BOARD_SPI (1)
#define CIRCUITPY_BOARD_SPI_PIN {{.clock = &pin_GPIO6, .mosi = &pin_GPIO7, .miso = &pin_GPIO4}}
#define CIRCUITPY_BOARD_UART (1)
#define CIRCUITPY_BOARD_UART_PIN {{.tx = &pin_GPIO24, .rx = &pin_GPIO25}}

View File

@ -0,0 +1,9 @@
USB_VID = 0x2019
USB_PID = 0x7103
USB_PRODUCT = "Fig Pi"
USB_MANUFACTURER = "Benjamin Shockley"
CHIP_VARIANT = RP2040
CHIP_FAMILY = rp2
EXTERNAL_FLASH_DEVICES = "W25Q16JVxQ"

View File

@ -0,0 +1,4 @@
// Put board-specific pico-sdk definitions here. This file must exist.
// Allow extra time for xosc to start.
#define PICO_XOSC_STARTUP_DELAY_MULTIPLIER 64

View File

@ -0,0 +1,62 @@
#include "shared-bindings/board/__init__.h"
CIRCUITPY_BOARD_BUS_SINGLETON(stemma_i2c, i2c, 1)
STATIC const mp_rom_map_elem_t board_module_globals_table[] = {
CIRCUITPYTHON_BOARD_DICT_STANDARD_ITEMS
{ MP_ROM_QSTR(MP_QSTR_A0), MP_ROM_PTR(&pin_GPIO29) },
{ MP_ROM_QSTR(MP_QSTR_D0), MP_ROM_PTR(&pin_GPIO29) },
{ MP_ROM_QSTR(MP_QSTR_A1), MP_ROM_PTR(&pin_GPIO28) },
{ MP_ROM_QSTR(MP_QSTR_D1), MP_ROM_PTR(&pin_GPIO28) },
{ MP_ROM_QSTR(MP_QSTR_A2), MP_ROM_PTR(&pin_GPIO27) },
{ MP_ROM_QSTR(MP_QSTR_D2), MP_ROM_PTR(&pin_GPIO27) },
{ MP_ROM_QSTR(MP_QSTR_A3), MP_ROM_PTR(&pin_GPIO26) },
{ MP_ROM_QSTR(MP_QSTR_D3), MP_ROM_PTR(&pin_GPIO26) },
{ MP_ROM_QSTR(MP_QSTR_SDA), MP_ROM_PTR(&pin_GPIO16) },
{ MP_ROM_QSTR(MP_QSTR_D4), MP_ROM_PTR(&pin_GPIO16) },
{ MP_ROM_QSTR(MP_QSTR_SCL), MP_ROM_PTR(&pin_GPIO17) },
{ MP_ROM_QSTR(MP_QSTR_D5), MP_ROM_PTR(&pin_GPIO17) },
{ MP_ROM_QSTR(MP_QSTR_TX), MP_ROM_PTR(&pin_GPIO24) },
{ MP_ROM_QSTR(MP_QSTR_D6), MP_ROM_PTR(&pin_GPIO24) },
{ MP_ROM_QSTR(MP_QSTR_RX), MP_ROM_PTR(&pin_GPIO25) },
{ MP_ROM_QSTR(MP_QSTR_D7), MP_ROM_PTR(&pin_GPIO25) },
{ MP_ROM_QSTR(MP_QSTR_SCK), MP_ROM_PTR(&pin_GPIO6) },
{ MP_ROM_QSTR(MP_QSTR_D8), MP_ROM_PTR(&pin_GPIO6) },
{ MP_ROM_QSTR(MP_QSTR_MISO), MP_ROM_PTR(&pin_GPIO4) },
{ MP_ROM_QSTR(MP_QSTR_D9), MP_ROM_PTR(&pin_GPIO4) },
{ MP_ROM_QSTR(MP_QSTR_MOSI), MP_ROM_PTR(&pin_GPIO7) },
{ MP_ROM_QSTR(MP_QSTR_D10), MP_ROM_PTR(&pin_GPIO7) },
{ MP_ROM_QSTR(MP_QSTR_D11), MP_ROM_PTR(&pin_GPIO23) },
{ MP_ROM_QSTR(MP_QSTR_D12), MP_ROM_PTR(&pin_GPIO22) },
{ MP_ROM_QSTR(MP_QSTR_D14), MP_ROM_PTR(&pin_GPIO5) },
{ MP_ROM_QSTR(MP_QSTR_D15), MP_ROM_PTR(&pin_GPIO3) },
{ MP_ROM_QSTR(MP_QSTR_D16), MP_ROM_PTR(&pin_GPIO2) },
{ MP_ROM_QSTR(MP_QSTR_D17), MP_ROM_PTR(&pin_GPIO1) },
{ MP_ROM_QSTR(MP_QSTR_NEOPIXEL), MP_ROM_PTR(&pin_GPIO13) },
{ MP_ROM_QSTR(MP_QSTR_NEOPIXEL_POWER), MP_ROM_PTR(&pin_GPIO1) },
{ MP_ROM_QSTR(MP_QSTR_BUTTON), MP_ROM_PTR(&pin_GPIO20) },
{ MP_ROM_QSTR(MP_QSTR_SDA1), MP_ROM_PTR(&pin_GPIO18) },
{ MP_ROM_QSTR(MP_QSTR_SCL1), MP_ROM_PTR(&pin_GPIO19) },
{ MP_ROM_QSTR(MP_QSTR_I2C), MP_ROM_PTR(&board_i2c_obj) },
{ MP_ROM_QSTR(MP_QSTR_SPI), MP_ROM_PTR(&board_spi_obj) },
{ MP_ROM_QSTR(MP_QSTR_UART), MP_ROM_PTR(&board_uart_obj) },
{ MP_ROM_QSTR(MP_QSTR_STEMMA_I2C), MP_ROM_PTR(&board_stemma_i2c_obj) },
};
MP_DEFINE_CONST_DICT(board_module_globals, board_module_globals_table);

View File

@ -0,0 +1,40 @@
/*
* This file is part of the MicroPython project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2021 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/board.h"
void board_init(void) {
}
bool board_requests_safe_mode(void) {
return false;
}
void reset_board(void) {
}
void board_deinit(void) {
}

View File

@ -0,0 +1,9 @@
#define MICROPY_HW_BOARD_NAME "W5500-EVB-Pico"
#define MICROPY_HW_MCU_NAME "rp2040"
#define DEFAULT_SPI_BUS_SCK (&pin_GPIO18)
#define DEFAULT_SPI_BUS_MOSI (&pin_GPIO19)
#define DEFAULT_SPI_BUS_MISO (&pin_GPIO16)
#define DEFAULT_UART_BUS_RX (&pin_GPIO1)
#define DEFAULT_UART_BUS_TX (&pin_GPIO0)

View File

@ -0,0 +1,11 @@
USB_VID = 0x2E8A
USB_PID = 0x1029
USB_PRODUCT = "W5500-EVB-Pico"
USB_MANUFACTURER = "WIZnet"
CHIP_VARIANT = RP2040
CHIP_FAMILY = rp2
EXTERNAL_FLASH_DEVICES = "W25Q16JVxQ"
CIRCUITPY__EVE = 1

View File

@ -0,0 +1 @@
// Put board-specific pico-sdk definitions here. This file must exist.

View File

@ -0,0 +1,54 @@
#include "shared-bindings/board/__init__.h"
STATIC const mp_rom_map_elem_t board_module_globals_table[] = {
CIRCUITPYTHON_BOARD_DICT_STANDARD_ITEMS
{ MP_ROM_QSTR(MP_QSTR_GP0), MP_ROM_PTR(&pin_GPIO0) },
{ MP_ROM_QSTR(MP_QSTR_GP1), MP_ROM_PTR(&pin_GPIO1) },
{ MP_ROM_QSTR(MP_QSTR_GP2), MP_ROM_PTR(&pin_GPIO2) },
{ MP_ROM_QSTR(MP_QSTR_GP3), MP_ROM_PTR(&pin_GPIO3) },
{ MP_ROM_QSTR(MP_QSTR_GP4), MP_ROM_PTR(&pin_GPIO4) },
{ MP_ROM_QSTR(MP_QSTR_GP5), MP_ROM_PTR(&pin_GPIO5) },
{ MP_ROM_QSTR(MP_QSTR_GP6), MP_ROM_PTR(&pin_GPIO6) },
{ MP_ROM_QSTR(MP_QSTR_GP7), MP_ROM_PTR(&pin_GPIO7) },
{ MP_ROM_QSTR(MP_QSTR_GP8), MP_ROM_PTR(&pin_GPIO8) },
{ MP_ROM_QSTR(MP_QSTR_GP9), MP_ROM_PTR(&pin_GPIO9) },
{ MP_ROM_QSTR(MP_QSTR_GP10), MP_ROM_PTR(&pin_GPIO10) },
{ MP_ROM_QSTR(MP_QSTR_GP11), MP_ROM_PTR(&pin_GPIO11) },
{ MP_ROM_QSTR(MP_QSTR_GP12), MP_ROM_PTR(&pin_GPIO12) },
{ MP_ROM_QSTR(MP_QSTR_GP13), MP_ROM_PTR(&pin_GPIO13) },
{ MP_ROM_QSTR(MP_QSTR_GP14), MP_ROM_PTR(&pin_GPIO14) },
{ MP_ROM_QSTR(MP_QSTR_GP15), MP_ROM_PTR(&pin_GPIO15) },
{ MP_ROM_QSTR(MP_QSTR_GP16), MP_ROM_PTR(&pin_GPIO16) },
{ MP_ROM_QSTR(MP_QSTR_GP17), MP_ROM_PTR(&pin_GPIO17) },
{ MP_ROM_QSTR(MP_QSTR_GP18), MP_ROM_PTR(&pin_GPIO18) },
{ MP_ROM_QSTR(MP_QSTR_GP19), MP_ROM_PTR(&pin_GPIO19) },
{ MP_ROM_QSTR(MP_QSTR_GP20), MP_ROM_PTR(&pin_GPIO20) },
{ MP_ROM_QSTR(MP_QSTR_GP21), MP_ROM_PTR(&pin_GPIO21) },
{ MP_ROM_QSTR(MP_QSTR_GP22), MP_ROM_PTR(&pin_GPIO22) },
{ MP_ROM_QSTR(MP_QSTR_SMPS_MODE), MP_ROM_PTR(&pin_GPIO23) },
{ MP_ROM_QSTR(MP_QSTR_GP23), MP_ROM_PTR(&pin_GPIO23) },
{ MP_ROM_QSTR(MP_QSTR_VBUS_SENSE), MP_ROM_PTR(&pin_GPIO24) },
{ MP_ROM_QSTR(MP_QSTR_GP24), MP_ROM_PTR(&pin_GPIO24) },
{ MP_ROM_QSTR(MP_QSTR_LED), MP_ROM_PTR(&pin_GPIO25) },
{ MP_ROM_QSTR(MP_QSTR_GP25), MP_ROM_PTR(&pin_GPIO25) },
{ MP_ROM_QSTR(MP_QSTR_GP26_A0), MP_ROM_PTR(&pin_GPIO26) },
{ MP_ROM_QSTR(MP_QSTR_GP26), MP_ROM_PTR(&pin_GPIO26) },
{ MP_ROM_QSTR(MP_QSTR_A0), MP_ROM_PTR(&pin_GPIO26) },
{ MP_ROM_QSTR(MP_QSTR_GP27_A1), MP_ROM_PTR(&pin_GPIO27) },
{ MP_ROM_QSTR(MP_QSTR_GP27), MP_ROM_PTR(&pin_GPIO27) },
{ MP_ROM_QSTR(MP_QSTR_A1), MP_ROM_PTR(&pin_GPIO27) },
{ MP_ROM_QSTR(MP_QSTR_GP28_A2), MP_ROM_PTR(&pin_GPIO28) },
{ MP_ROM_QSTR(MP_QSTR_GP28), MP_ROM_PTR(&pin_GPIO28) },
{ MP_ROM_QSTR(MP_QSTR_A2), MP_ROM_PTR(&pin_GPIO28) },
{ MP_ROM_QSTR(MP_QSTR_A3), MP_ROM_PTR(&pin_GPIO29) },
{ MP_ROM_QSTR(MP_QSTR_VOLTAGE_MONITOR), MP_ROM_PTR(&pin_GPIO29) },
};
MP_DEFINE_CONST_DICT(board_module_globals, board_module_globals_table);

View File

@ -37,8 +37,8 @@ INC += -I$(BUILD)
# compiler settings
CWARN = -Wall -Werror
CWARN += -Wextra -Wno-unused-parameter -Wpointer-arith -Wdouble-promotion -Wfloat-conversion
CFLAGS += $(INC) $(CWARN) -std=gnu99 -DUNIX $(CFLAGS_MOD) $(COPT) -I$(VARIANT_DIR) $(CFLAGS_EXTRA)
CWARN += -Wextra -Wno-unused-parameter -Wno-missing-field-initializers -Wpointer-arith -Wdouble-promotion -Wfloat-conversion
CFLAGS += $(INC) $(CWARN) -std=gnu11 -DUNIX $(CFLAGS_MOD) $(COPT) -I$(VARIANT_DIR) $(CFLAGS_EXTRA)
# Debugging/Optimization
ifdef DEBUG

View File

@ -480,19 +480,33 @@ MP_DEFINE_CONST_FUN_OBJ_1(int_bit_length_obj, int_bit_length);
#endif
// this is a classmethod
STATIC mp_obj_t int_from_bytes(size_t n_args, const mp_obj_t *args) {
STATIC mp_obj_t int_from_bytes(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
// TODO: Support signed param (assumes signed=False at the moment)
(void)n_args;
enum { ARG_bytes, ARG_byteorder, ARG_signed };
static const mp_arg_t allowed_args[] = {
{ MP_QSTR_bytes, MP_ARG_REQUIRED | MP_ARG_OBJ },
{ MP_QSTR_byteorder, MP_ARG_REQUIRED | MP_ARG_OBJ },
{ MP_QSTR_signed, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} },
};
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
if (args[ARG_signed].u_bool) {
mp_raise_NotImplementedError_varg(MP_ERROR_TEXT("%q=%q"), MP_QSTR_signed, MP_QSTR_True);
}
// get the buffer info
mp_buffer_info_t bufinfo;
mp_get_buffer_raise(args[1], &bufinfo, MP_BUFFER_READ);
mp_get_buffer_raise(args[ARG_bytes].u_obj, &bufinfo, MP_BUFFER_READ);
const byte *buf = (const byte *)bufinfo.buf;
int delta = 1;
if (args[2] == MP_OBJ_NEW_QSTR(MP_QSTR_little)) {
if (args[ARG_byteorder].u_obj == MP_OBJ_NEW_QSTR(MP_QSTR_little)) {
buf += bufinfo.len - 1;
delta = -1;
} else if (args[ARG_byteorder].u_obj != MP_OBJ_NEW_QSTR(MP_QSTR_big)) {
mp_arg_error_invalid(MP_QSTR_byteorder);
}
mp_uint_t value = 0;
@ -501,7 +515,7 @@ STATIC mp_obj_t int_from_bytes(size_t n_args, const mp_obj_t *args) {
#if MICROPY_LONGINT_IMPL != MICROPY_LONGINT_IMPL_NONE
if (value > (MP_SMALL_INT_MAX >> 8)) {
// Result will overflow a small-int so construct a big-int
return mp_obj_int_from_bytes_impl(args[2] != MP_OBJ_NEW_QSTR(MP_QSTR_little), bufinfo.len, bufinfo.buf);
return mp_obj_int_from_bytes_impl(args[ARG_byteorder].u_obj != MP_OBJ_NEW_QSTR(MP_QSTR_little), bufinfo.len, bufinfo.buf);
}
#endif
value = (value << 8) | *buf;
@ -509,7 +523,7 @@ STATIC mp_obj_t int_from_bytes(size_t n_args, const mp_obj_t *args) {
return mp_obj_new_int_from_uint(value);
}
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(int_from_bytes_fun_obj, 3, 4, int_from_bytes);
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(int_from_bytes_fun_obj, 3, int_from_bytes);
STATIC MP_DEFINE_CONST_CLASSMETHOD_OBJ(int_from_bytes_obj, MP_ROM_PTR(&int_from_bytes_fun_obj));
STATIC mp_obj_t int_to_bytes(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {

View File

@ -350,38 +350,40 @@ static bool _endswith(const char *str, const char *suffix) {
return strcmp(str + (strlen(str) - strlen(suffix)), suffix) == 0;
}
const char *ok_hosts[] = {"code.circuitpython.org"};
const char *ok_hosts[] = {
"code.circuitpython.org",
"127.0.0.1",
"localhost",
};
static bool _origin_ok(const char *origin) {
const char *http = "http://";
const char *local = ".local";
if (memcmp(origin, http, strlen(http)) != 0) {
// note: redirected requests send an Origin of "null" and will be caught by this
if (strncmp(origin, http, strlen(http)) != 0) {
return false;
}
// These are prefix checks up to : so that any port works.
const char *hostname = common_hal_mdns_server_get_hostname(&mdns);
const char *end = origin + strlen(http) + strlen(hostname) + strlen(local);
if (memcmp(origin + strlen(http), hostname, strlen(hostname)) == 0 &&
memcmp(origin + strlen(http) + strlen(hostname), local, strlen(local)) == 0 &&
if (strncmp(origin + strlen(http), hostname, strlen(hostname)) == 0 &&
strncmp(origin + strlen(http) + strlen(hostname), local, strlen(local)) == 0 &&
(end[0] == '\0' || end[0] == ':')) {
return true;
}
end = origin + strlen(http) + strlen(_our_ip_encoded);
if (memcmp(origin + strlen(http), _our_ip_encoded, strlen(_our_ip_encoded)) == 0 &&
if (strncmp(origin + strlen(http), _our_ip_encoded, strlen(_our_ip_encoded)) == 0 &&
(end[0] == '\0' || end[0] == ':')) {
return true;
}
const char *localhost = "127.0.0.1:";
if (memcmp(origin + strlen(http), localhost, strlen(localhost)) == 0) {
return true;
}
for (size_t i = 0; i < MP_ARRAY_SIZE(ok_hosts); i++) {
// This checks exactly.
if (strcmp(origin + strlen(http), ok_hosts[i]) == 0) {
// Allows any port
end = origin + strlen(http) + strlen(ok_hosts[i]);
if (strncmp(origin + strlen(http), ok_hosts[i], strlen(ok_hosts[i])) == 0
&& (end[0] == '\0' || end[0] == ':')) {
return true;
}
}
@ -404,7 +406,7 @@ static const char *OK_JSON = "HTTP/1.1 200 OK\r\nTransfer-Encoding: chunked\r\nC
static void _cors_header(socketpool_socket_obj_t *socket, _request *request) {
_send_strs(socket,
"Access-Control-Allow-Credentials: true\r\n",
"Vary: Origin\r\n",
"Vary: Origin, Accept, Upgrade\r\n",
"Access-Control-Allow-Origin: ", request->origin, "\r\n",
NULL);
}
@ -440,10 +442,10 @@ static void _reply_access_control(socketpool_socket_obj_t *socket, _request *req
"Access-Control-Allow-Methods:GET, OPTIONS", NULL);
if (!_usb_active()) {
_send_str(socket, ", PUT, DELETE");
#if CIRCUITPY_USB_MSC
usb_msc_unlock();
#endif
}
#if CIRCUITPY_USB_MSC
usb_msc_unlock();
#endif
_send_str(socket, "\r\n");
_cors_header(socket, request);
_send_str(socket, "\r\n");
@ -740,14 +742,25 @@ STATIC uint64_t truncate_time(uint64_t input_time, DWORD *fattime) {
return truncated_time;
}
STATIC void _discard_incoming(socketpool_socket_obj_t *socket, size_t amount) {
size_t discarded = 0;
while (discarded < amount) {
uint8_t bytes[64];
size_t read_len = MIN(sizeof(bytes), amount - discarded);
int len = socketpool_socket_recv_into(socket, bytes, read_len);
if (len < 0) {
break;
}
discarded += read_len;
}
}
static void _write_file_and_reply(socketpool_socket_obj_t *socket, _request *request, FATFS *fs, const TCHAR *path) {
FIL active_file;
if (_usb_active()) {
_discard_incoming(socket, request->content_length);
_reply_conflict(socket, request);
#if CIRCUITPY_USB_MSC
usb_msc_unlock();
#endif
return;
}
if (request->timestamp_ms > 0) {
@ -765,12 +778,20 @@ static void _write_file_and_reply(socketpool_socket_obj_t *socket, _request *req
if (result == FR_NO_PATH) {
override_fattime(0);
#if CIRCUITPY_USB_MSC
usb_msc_unlock();
#endif
_discard_incoming(socket, request->content_length);
_reply_missing(socket, request);
return;
}
if (result != FR_OK) {
ESP_LOGE(TAG, "file write error %d %s", result, path);
override_fattime(0);
#if CIRCUITPY_USB_MSC
usb_msc_unlock();
#endif
_discard_incoming(socket, request->content_length);
_reply_server_error(socket, request);
return;
} else if (request->expect) {
@ -785,6 +806,7 @@ static void _write_file_and_reply(socketpool_socket_obj_t *socket, _request *req
#if CIRCUITPY_USB_MSC
usb_msc_unlock();
#endif
_discard_incoming(socket, request->content_length);
// Too large.
if (request->expect) {
_reply_expectation_failed(socket, request);
@ -890,8 +912,11 @@ static bool _reply(socketpool_socket_obj_t *socket, _request *request) {
} else if (strlen(request->origin) > 0 && !_origin_ok(request->origin)) {
ESP_LOGE(TAG, "bad origin %s", request->origin);
_reply_forbidden(socket, request);
} else if (memcmp(request->path, "/fs/", 4) == 0) {
if (!request->authenticated) {
} else if (strncmp(request->path, "/fs/", 4) == 0) {
if (strcasecmp(request->method, "OPTIONS") == 0) {
// OPTIONS is sent for CORS preflight, unauthenticated
_reply_access_control(socket, request);
} else if (!request->authenticated) {
if (_api_password[0] != '\0') {
_reply_unauthorized(socket, request);
} else {
@ -912,14 +937,9 @@ static bool _reply(socketpool_socket_obj_t *socket, _request *request) {
}
// Delete is almost identical for files and directories so share the
// implementation.
if (strcmp(request->method, "OPTIONS") == 0) {
_reply_access_control(socket, request);
} else if (strcmp(request->method, "DELETE") == 0) {
if (strcasecmp(request->method, "DELETE") == 0) {
if (_usb_active()) {
_reply_conflict(socket, request);
#if CIRCUITPY_USB_MSC
usb_msc_unlock();
#endif
return false;
}
@ -934,6 +954,9 @@ static bool _reply(socketpool_socket_obj_t *socket, _request *request) {
}
}
#if CIRCUITPY_USB_MSC
usb_msc_unlock();
#endif
if (result == FR_NO_PATH || result == FR_NO_FILE) {
_reply_missing(socket, request);
} else if (result != FR_OK) {
@ -944,7 +967,7 @@ static bool _reply(socketpool_socket_obj_t *socket, _request *request) {
return true;
}
} else if (directory) {
if (strcmp(request->method, "GET") == 0) {
if (strcasecmp(request->method, "GET") == 0) {
FF_DIR dir;
FRESULT res = f_opendir(fs, &dir, path);
// Put the / back for replies.
@ -964,12 +987,9 @@ static bool _reply(socketpool_socket_obj_t *socket, _request *request) {
}
f_closedir(&dir);
} else if (strcmp(request->method, "PUT") == 0) {
} else if (strcasecmp(request->method, "PUT") == 0) {
if (_usb_active()) {
_reply_conflict(socket, request);
#if CIRCUITPY_USB_MSC
usb_msc_unlock();
#endif
return false;
}
@ -996,7 +1016,7 @@ static bool _reply(socketpool_socket_obj_t *socket, _request *request) {
}
}
} else { // Dealing with a file.
if (strcmp(request->method, "GET") == 0) {
if (strcasecmp(request->method, "GET") == 0) {
FIL active_file;
FRESULT result = f_open(fs, &active_file, path, FA_READ);
@ -1007,7 +1027,7 @@ static bool _reply(socketpool_socket_obj_t *socket, _request *request) {
}
f_close(&active_file);
} else if (strcmp(request->method, "PUT") == 0) {
} else if (strcasecmp(request->method, "PUT") == 0) {
_write_file_and_reply(socket, request, fs, path);
return true;
}
@ -1023,9 +1043,12 @@ static bool _reply(socketpool_socket_obj_t *socket, _request *request) {
} else {
_REPLY_STATIC(socket, request, edit_html);
}
} else if (memcmp(request->path, "/cp/", 4) == 0) {
} else if (strncmp(request->path, "/cp/", 4) == 0) {
const char *path = request->path + 3;
if (strcmp(request->method, "GET") != 0) {
if (strcasecmp(request->method, "OPTIONS") == 0) {
// handle preflight requests to /cp/
_reply_access_control(socket, request);
} else if (strcasecmp(request->method, "GET") != 0) {
_reply_method_not_allowed(socket, request);
} else if (strcmp(path, "/devices.json") == 0) {
_reply_with_devices_json(socket, request);
@ -1046,7 +1069,7 @@ static bool _reply(socketpool_socket_obj_t *socket, _request *request) {
} else {
_reply_missing(socket, request);
}
} else if (strcmp(request->method, "GET") != 0) {
} else if (strcasecmp(request->method, "GET") != 0) {
_reply_method_not_allowed(socket, request);
} else {
if (strcmp(request->path, "/") == 0) {
@ -1165,27 +1188,27 @@ static void _process_request(socketpool_socket_obj_t *socket, _request *request)
request->header_value[request->offset - 1] = '\0';
request->offset = 0;
request->state = STATE_HEADER_KEY;
if (strcmp(request->header_key, "Authorization") == 0) {
if (strcasecmp(request->header_key, "Authorization") == 0) {
const char *prefix = "Basic ";
request->authenticated = memcmp(request->header_value, prefix, strlen(prefix)) == 0 &&
request->authenticated = strncmp(request->header_value, prefix, strlen(prefix)) == 0 &&
strcmp(_api_password, request->header_value + strlen(prefix)) == 0;
} else if (strcmp(request->header_key, "Host") == 0) {
} else if (strcasecmp(request->header_key, "Host") == 0) {
request->redirect = strcmp(request->header_value, "circuitpython.local") == 0;
} else if (strcmp(request->header_key, "Content-Length") == 0) {
} else if (strcasecmp(request->header_key, "Content-Length") == 0) {
request->content_length = strtoul(request->header_value, NULL, 10);
} else if (strcmp(request->header_key, "Expect") == 0) {
} else if (strcasecmp(request->header_key, "Expect") == 0) {
request->expect = strcmp(request->header_value, "100-continue") == 0;
} else if (strcmp(request->header_key, "Accept") == 0) {
request->json = strcmp(request->header_value, "application/json") == 0;
} else if (strcmp(request->header_key, "Origin") == 0) {
} else if (strcasecmp(request->header_key, "Accept") == 0) {
request->json = strcasecmp(request->header_value, "application/json") == 0;
} else if (strcasecmp(request->header_key, "Origin") == 0) {
strcpy(request->origin, request->header_value);
} else if (strcmp(request->header_key, "X-Timestamp") == 0) {
} else if (strcasecmp(request->header_key, "X-Timestamp") == 0) {
request->timestamp_ms = strtoull(request->header_value, NULL, 10);
} else if (strcmp(request->header_key, "Upgrade") == 0) {
} else if (strcasecmp(request->header_key, "Upgrade") == 0) {
request->websocket = strcmp(request->header_value, "websocket") == 0;
} else if (strcmp(request->header_key, "Sec-WebSocket-Version") == 0) {
} else if (strcasecmp(request->header_key, "Sec-WebSocket-Version") == 0) {
request->websocket_version = strtoul(request->header_value, NULL, 10);
} else if (strcmp(request->header_key, "Sec-WebSocket-Key") == 0 &&
} else if (strcasecmp(request->header_key, "Sec-WebSocket-Key") == 0 &&
strlen(request->header_value) == 24) {
strcpy(request->websocket_key, request->header_value);
}

View File

@ -66,6 +66,10 @@ static void workflow_background(void *data) {
#if CIRCUITPY_STATUS_BAR
supervisor_workflow_update_status_bar();
#endif
#if CIRCUITPY_WEB_WORKFLOW
supervisor_web_workflow_background();
#endif
}
// Called during a VM reset. Doesn't actually reset things.

View File

@ -77,6 +77,7 @@ extension_by_board = {
"adafruit_qtpy_esp32c3": BIN,
"ai_thinker_esp32-c3s": BIN,
"ai_thinker_esp32-c3s-2m": BIN,
"beetle-esp32-c3": BIN,
"espressif_esp32c3_devkitm_1_n4": BIN,
"lilygo_ttgo_t-01c3": BIN,
"lolin_c3_mini": BIN,