Merge branch 'main' into webflow_edit_page
# Conflicts: # supervisor/shared/web_workflow/web_workflow.c
This commit is contained in:
commit
d0782b60cb
@ -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"
|
msgid "%q, %q, and %q must all be the same length"
|
||||||
msgstr "%q, %q, dan %q semuanya harus memiliki panjang yang sama"
|
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
|
#: ports/espressif/bindings/espidf/__init__.c ports/espressif/esp_error.c
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "%s error 0x%x"
|
msgid "%s error 0x%x"
|
||||||
|
@ -205,6 +205,10 @@ msgstr ""
|
|||||||
msgid "%q, %q, and %q must all be the same length"
|
msgid "%q, %q, and %q must all be the same length"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#: py/objint.c
|
||||||
|
msgid "%q=%q"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: ports/espressif/bindings/espidf/__init__.c ports/espressif/esp_error.c
|
#: ports/espressif/bindings/espidf/__init__.c ports/espressif/esp_error.c
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "%s error 0x%x"
|
msgid "%s error 0x%x"
|
||||||
|
@ -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"
|
msgid "%q, %q, and %q must all be the same length"
|
||||||
msgstr "%q, %q, a %q musí mít všechny shodnou délku"
|
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
|
#: ports/espressif/bindings/espidf/__init__.c ports/espressif/esp_error.c
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "%s error 0x%x"
|
msgid "%s error 0x%x"
|
||||||
|
@ -214,6 +214,10 @@ msgstr ""
|
|||||||
msgid "%q, %q, and %q must all be the same length"
|
msgid "%q, %q, and %q must all be the same length"
|
||||||
msgstr "%q, %q und %q müssen alle die gleiche Länge haben"
|
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
|
#: ports/espressif/bindings/espidf/__init__.c ports/espressif/esp_error.c
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "%s error 0x%x"
|
msgid "%s error 0x%x"
|
||||||
|
@ -205,6 +205,10 @@ msgstr ""
|
|||||||
msgid "%q, %q, and %q must all be the same length"
|
msgid "%q, %q, and %q must all be the same length"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#: py/objint.c
|
||||||
|
msgid "%q=%q"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: ports/espressif/bindings/espidf/__init__.c ports/espressif/esp_error.c
|
#: ports/espressif/bindings/espidf/__init__.c ports/espressif/esp_error.c
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "%s error 0x%x"
|
msgid "%s error 0x%x"
|
||||||
|
@ -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"
|
msgid "%q, %q, and %q must all be the same length"
|
||||||
msgstr "%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
|
#: ports/espressif/bindings/espidf/__init__.c ports/espressif/esp_error.c
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "%s error 0x%x"
|
msgid "%s error 0x%x"
|
||||||
|
@ -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"
|
msgid "%q, %q, and %q must all be the same length"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#: py/objint.c
|
||||||
|
msgid "%q=%q"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: ports/espressif/bindings/espidf/__init__.c ports/espressif/esp_error.c
|
#: ports/espressif/bindings/espidf/__init__.c ports/espressif/esp_error.c
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "%s error 0x%x"
|
msgid "%s error 0x%x"
|
||||||
|
@ -208,6 +208,10 @@ msgstr ""
|
|||||||
msgid "%q, %q, and %q must all be the same length"
|
msgid "%q, %q, and %q must all be the same length"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#: py/objint.c
|
||||||
|
msgid "%q=%q"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: ports/espressif/bindings/espidf/__init__.c ports/espressif/esp_error.c
|
#: ports/espressif/bindings/espidf/__init__.c ports/espressif/esp_error.c
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "%s error 0x%x"
|
msgid "%s error 0x%x"
|
||||||
|
30
locale/fr.po
30
locale/fr.po
@ -8,14 +8,14 @@ msgstr ""
|
|||||||
"Project-Id-Version: 0.1\n"
|
"Project-Id-Version: 0.1\n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2021-01-04 12:55-0600\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"
|
"Last-Translator: Maxime Leroy <lisacintosh@gmail.com>\n"
|
||||||
"Language: fr\n"
|
"Language: fr\n"
|
||||||
"MIME-Version: 1.0\n"
|
"MIME-Version: 1.0\n"
|
||||||
"Content-Type: text/plain; charset=utf-8\n"
|
"Content-Type: text/plain; charset=utf-8\n"
|
||||||
"Content-Transfer-Encoding: 8bit\n"
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
"Plural-Forms: nplurals=2; plural=n > 1;\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
|
#: main.c
|
||||||
msgid ""
|
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"
|
msgid "%q, %q, and %q must all be the same length"
|
||||||
msgstr "%q, %q, et %q doivent tous être de la même longueur"
|
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
|
#: ports/espressif/bindings/espidf/__init__.c ports/espressif/esp_error.c
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "%s error 0x%x"
|
msgid "%s error 0x%x"
|
||||||
@ -2291,7 +2295,7 @@ msgstr "Format non supporté"
|
|||||||
|
|
||||||
#: shared-bindings/hashlib/__init__.c
|
#: shared-bindings/hashlib/__init__.c
|
||||||
msgid "Unsupported hash algorithm"
|
msgid "Unsupported hash algorithm"
|
||||||
msgstr ""
|
msgstr "Algorithme de hachage non supporté"
|
||||||
|
|
||||||
#: ports/espressif/common-hal/dualbank/__init__.c
|
#: ports/espressif/common-hal/dualbank/__init__.c
|
||||||
msgid "Update Failed"
|
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
|
#: extmod/ulab/code/numpy/io/io.c
|
||||||
msgid "array has too many dimensions"
|
msgid "array has too many dimensions"
|
||||||
msgstr ""
|
msgstr "la tableau à trop de dimensions"
|
||||||
|
|
||||||
#: py/objarray.c shared-bindings/alarm/SleepMemory.c
|
#: py/objarray.c shared-bindings/alarm/SleepMemory.c
|
||||||
#: shared-bindings/nvm/ByteArray.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
|
#: extmod/ulab/code/numpy/io/io.c
|
||||||
msgid "corrupted file"
|
msgid "corrupted file"
|
||||||
msgstr ""
|
msgstr "fichier corrompu"
|
||||||
|
|
||||||
#: extmod/ulab/code/numpy/poly.c
|
#: extmod/ulab/code/numpy/poly.c
|
||||||
msgid "could not invert Vandermonde matrix"
|
msgid "could not invert Vandermonde matrix"
|
||||||
@ -2938,7 +2942,7 @@ msgstr "vide"
|
|||||||
|
|
||||||
#: extmod/ulab/code/numpy/io/io.c
|
#: extmod/ulab/code/numpy/io/io.c
|
||||||
msgid "empty file"
|
msgid "empty file"
|
||||||
msgstr ""
|
msgstr "fichier vide"
|
||||||
|
|
||||||
#: extmod/moduasyncio.c extmod/moduheapq.c extmod/modutimeq.c
|
#: extmod/moduasyncio.c extmod/moduheapq.c extmod/modutimeq.c
|
||||||
msgid "empty heap"
|
msgid "empty heap"
|
||||||
@ -3261,7 +3265,7 @@ msgstr "la matrice d'entrée est singulière"
|
|||||||
|
|
||||||
#: extmod/ulab/code/numpy/create.c
|
#: extmod/ulab/code/numpy/create.c
|
||||||
msgid "input must be 1- or 2-d"
|
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
|
#: extmod/ulab/code/numpy/carray/carray.c
|
||||||
msgid "input must be a 1D ndarray"
|
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
|
#: extmod/ulab/code/ndarray.c
|
||||||
msgid "maximum number of dimensions is "
|
msgid "maximum number of dimensions is "
|
||||||
msgstr ""
|
msgstr "le nombre maximal de dimensions est "
|
||||||
|
|
||||||
#: py/runtime.c
|
#: py/runtime.c
|
||||||
msgid "maximum recursion depth exceeded"
|
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
|
#: ports/espressif/boards/adafruit_feather_esp32_v2/mpconfigboard.h
|
||||||
msgid "pressing SW38 button at start up.\n"
|
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/adafruit_qtpy_esp32c3/mpconfigboard.h
|
||||||
#: ports/espressif/boards/lolin_c3_mini/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
|
#: extmod/ulab/code/numpy/io/io.c
|
||||||
msgid "usecols is too high"
|
msgid "usecols is too high"
|
||||||
msgstr ""
|
msgstr "usecols est trop grand"
|
||||||
|
|
||||||
#: extmod/ulab/code/numpy/io/io.c
|
#: extmod/ulab/code/numpy/io/io.c
|
||||||
msgid "usecols keyword must be specified"
|
msgid "usecols keyword must be specified"
|
||||||
msgstr ""
|
msgstr "le mot-clé \"usecols\" doit être spécifié"
|
||||||
|
|
||||||
#: py/objint.c
|
#: py/objint.c
|
||||||
#, c-format
|
#, c-format
|
||||||
@ -4376,7 +4380,7 @@ msgstr "axe incorrecte spécifiée"
|
|||||||
|
|
||||||
#: extmod/ulab/code/numpy/io/io.c
|
#: extmod/ulab/code/numpy/io/io.c
|
||||||
msgid "wrong dtype"
|
msgid "wrong dtype"
|
||||||
msgstr ""
|
msgstr "dtype invalide"
|
||||||
|
|
||||||
#: extmod/ulab/code/numpy/transform.c
|
#: extmod/ulab/code/numpy/transform.c
|
||||||
msgid "wrong index type"
|
msgid "wrong index type"
|
||||||
@ -4394,7 +4398,7 @@ msgstr "mauvaise taille du tableau de condition"
|
|||||||
|
|
||||||
#: extmod/ulab/code/numpy/transform.c
|
#: extmod/ulab/code/numpy/transform.c
|
||||||
msgid "wrong length of index array"
|
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
|
#: extmod/ulab/code/numpy/create.c py/objarray.c py/objstr.c
|
||||||
msgid "wrong number of arguments"
|
msgid "wrong number of arguments"
|
||||||
|
@ -205,6 +205,10 @@ msgstr ""
|
|||||||
msgid "%q, %q, and %q must all be the same length"
|
msgid "%q, %q, and %q must all be the same length"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#: py/objint.c
|
||||||
|
msgid "%q=%q"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: ports/espressif/bindings/espidf/__init__.c ports/espressif/esp_error.c
|
#: ports/espressif/bindings/espidf/__init__.c ports/espressif/esp_error.c
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "%s error 0x%x"
|
msgid "%s error 0x%x"
|
||||||
|
@ -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"
|
msgid "%q, %q, and %q must all be the same length"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#: py/objint.c
|
||||||
|
msgid "%q=%q"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: ports/espressif/bindings/espidf/__init__.c ports/espressif/esp_error.c
|
#: ports/espressif/bindings/espidf/__init__.c ports/espressif/esp_error.c
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "%s error 0x%x"
|
msgid "%s error 0x%x"
|
||||||
|
@ -210,6 +210,10 @@ msgstr "%q() は %d 個の位置引数を取りますが、%d 個与えられま
|
|||||||
msgid "%q, %q, and %q must all be the same length"
|
msgid "%q, %q, and %q must all be the same length"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#: py/objint.c
|
||||||
|
msgid "%q=%q"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: ports/espressif/bindings/espidf/__init__.c ports/espressif/esp_error.c
|
#: ports/espressif/bindings/espidf/__init__.c ports/espressif/esp_error.c
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "%s error 0x%x"
|
msgid "%s error 0x%x"
|
||||||
|
@ -206,6 +206,10 @@ msgstr ""
|
|||||||
msgid "%q, %q, and %q must all be the same length"
|
msgid "%q, %q, and %q must all be the same length"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#: py/objint.c
|
||||||
|
msgid "%q=%q"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: ports/espressif/bindings/espidf/__init__.c ports/espressif/esp_error.c
|
#: ports/espressif/bindings/espidf/__init__.c ports/espressif/esp_error.c
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "%s error 0x%x"
|
msgid "%s error 0x%x"
|
||||||
|
@ -208,6 +208,10 @@ msgstr "%q() verwacht %d positionele argumenten maar kreeg %d"
|
|||||||
msgid "%q, %q, and %q must all be the same length"
|
msgid "%q, %q, and %q must all be the same length"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#: py/objint.c
|
||||||
|
msgid "%q=%q"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: ports/espressif/bindings/espidf/__init__.c ports/espressif/esp_error.c
|
#: ports/espressif/bindings/espidf/__init__.c ports/espressif/esp_error.c
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "%s error 0x%x"
|
msgid "%s error 0x%x"
|
||||||
|
@ -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"
|
msgid "%q, %q, and %q must all be the same length"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#: py/objint.c
|
||||||
|
msgid "%q=%q"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: ports/espressif/bindings/espidf/__init__.c ports/espressif/esp_error.c
|
#: ports/espressif/bindings/espidf/__init__.c ports/espressif/esp_error.c
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "%s error 0x%x"
|
msgid "%s error 0x%x"
|
||||||
|
@ -6,7 +6,7 @@ msgstr ""
|
|||||||
"Project-Id-Version: PACKAGE VERSION\n"
|
"Project-Id-Version: PACKAGE VERSION\n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2021-01-04 12:55-0600\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"
|
"Last-Translator: Wellington Terumi Uemura <wellingtonuemura@gmail.com>\n"
|
||||||
"Language-Team: \n"
|
"Language-Team: \n"
|
||||||
"Language: pt_BR\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"
|
msgid "%q, %q, and %q must all be the same length"
|
||||||
msgstr "todos os %q, %q, e %q devem ter mesmo comprimento"
|
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
|
#: ports/espressif/bindings/espidf/__init__.c ports/espressif/esp_error.c
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "%s error 0x%x"
|
msgid "%s error 0x%x"
|
||||||
@ -2273,7 +2277,7 @@ msgstr "Formato não suportado"
|
|||||||
|
|
||||||
#: shared-bindings/hashlib/__init__.c
|
#: shared-bindings/hashlib/__init__.c
|
||||||
msgid "Unsupported hash algorithm"
|
msgid "Unsupported hash algorithm"
|
||||||
msgstr ""
|
msgstr "Sem compatibilidade com o algoritmo de hash"
|
||||||
|
|
||||||
#: ports/espressif/common-hal/dualbank/__init__.c
|
#: ports/espressif/common-hal/dualbank/__init__.c
|
||||||
msgid "Update Failed"
|
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
|
#: ports/espressif/boards/adafruit_feather_esp32_v2/mpconfigboard.h
|
||||||
msgid "pressing SW38 button at start up.\n"
|
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/adafruit_qtpy_esp32c3/mpconfigboard.h
|
||||||
#: ports/espressif/boards/lolin_c3_mini/mpconfigboard.h
|
#: ports/espressif/boards/lolin_c3_mini/mpconfigboard.h
|
||||||
|
@ -213,6 +213,10 @@ msgstr "%q() принимает %d позиционных аргументов,
|
|||||||
msgid "%q, %q, and %q must all be the same length"
|
msgid "%q, %q, and %q must all be the same length"
|
||||||
msgstr "%q, %q, и %q должны быть одной длинны"
|
msgstr "%q, %q, и %q должны быть одной длинны"
|
||||||
|
|
||||||
|
#: py/objint.c
|
||||||
|
msgid "%q=%q"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: ports/espressif/bindings/espidf/__init__.c ports/espressif/esp_error.c
|
#: ports/espressif/bindings/espidf/__init__.c ports/espressif/esp_error.c
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "%s error 0x%x"
|
msgid "%s error 0x%x"
|
||||||
|
@ -6,7 +6,7 @@ msgstr ""
|
|||||||
"Project-Id-Version: PACKAGE VERSION\n"
|
"Project-Id-Version: PACKAGE VERSION\n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2021-01-04 12:55-0600\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"
|
"Last-Translator: Jonny Bergdahl <jonny@bergdahl.it>\n"
|
||||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||||
"Language: sv\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"
|
msgid "%q, %q, and %q must all be the same length"
|
||||||
msgstr "%q, %q och %q måste vara lika långa"
|
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
|
#: ports/espressif/bindings/espidf/__init__.c ports/espressif/esp_error.c
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "%s error 0x%x"
|
msgid "%s error 0x%x"
|
||||||
|
@ -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"
|
msgid "%q, %q, and %q must all be the same length"
|
||||||
msgstr "%q, %q ve %q aynı uzunlukta olmalıdır"
|
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
|
#: ports/espressif/bindings/espidf/__init__.c ports/espressif/esp_error.c
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "%s error 0x%x"
|
msgid "%s error 0x%x"
|
||||||
|
@ -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"
|
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"
|
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
|
#: ports/espressif/bindings/espidf/__init__.c ports/espressif/esp_error.c
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "%s error 0x%x"
|
msgid "%s error 0x%x"
|
||||||
|
@ -61,17 +61,12 @@ endif
|
|||||||
|
|
||||||
MICROPY_PY_ASYNC_AWAIT = 0
|
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,
|
# so turn off terminalio, and if it's off and displayio is on,
|
||||||
# force a clean build.
|
# force a clean build.
|
||||||
# Note that we cannot test $(CIRCUITPY_DISPLAYIO) directly with an
|
# Note that we cannot test $(CIRCUITPY_DISPLAYIO) directly with an
|
||||||
# ifeq, because it's not set yet.
|
# ifeq, because it's not set yet.
|
||||||
ifeq ($(TRANSLATION), ja)
|
ifneq (,$(filter $(TRANSLATION),ja ko ru))
|
||||||
CIRCUITPY_TERMINALIO = 0
|
|
||||||
RELEASE_NEEDS_CLEAN_BUILD = $(CIRCUITPY_DISPLAYIO)
|
|
||||||
endif
|
|
||||||
|
|
||||||
ifeq ($(TRANSLATION), ko)
|
|
||||||
CIRCUITPY_TERMINALIO = 0
|
CIRCUITPY_TERMINALIO = 0
|
||||||
RELEASE_NEEDS_CLEAN_BUILD = $(CIRCUITPY_DISPLAYIO)
|
RELEASE_NEEDS_CLEAN_BUILD = $(CIRCUITPY_DISPLAYIO)
|
||||||
endif
|
endif
|
||||||
|
@ -40,20 +40,12 @@
|
|||||||
#include "common-hal/pulseio/PulseIn.h"
|
#include "common-hal/pulseio/PulseIn.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if CIRCUITPY_WEB_WORKFLOW
|
|
||||||
#include "supervisor/shared/web_workflow/web_workflow.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
void port_background_task(void) {
|
void port_background_task(void) {
|
||||||
// Zero delay in case FreeRTOS wants to switch to something else.
|
// Zero delay in case FreeRTOS wants to switch to something else.
|
||||||
vTaskDelay(0);
|
vTaskDelay(0);
|
||||||
#if CIRCUITPY_PULSEIO
|
#if CIRCUITPY_PULSEIO
|
||||||
pulsein_background();
|
pulsein_background();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if CIRCUITPY_WEB_WORKFLOW
|
|
||||||
supervisor_web_workflow_background();
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void port_start_background_task(void) {
|
void port_start_background_task(void) {
|
||||||
|
@ -15,3 +15,5 @@ CFLAGS += -DCFG_TUD_TASK_QUEUE_SZ=32
|
|||||||
CIRCUITPY_ESP_FLASH_MODE = qio
|
CIRCUITPY_ESP_FLASH_MODE = qio
|
||||||
CIRCUITPY_ESP_FLASH_FREQ = 40m
|
CIRCUITPY_ESP_FLASH_FREQ = 40m
|
||||||
CIRCUITPY_ESP_FLASH_SIZE = 4MB
|
CIRCUITPY_ESP_FLASH_SIZE = 4MB
|
||||||
|
|
||||||
|
CIRCUITPY_PS2IO = 0
|
||||||
|
@ -16,3 +16,5 @@ CFLAGS += -DCFG_TUD_TASK_QUEUE_SZ=32
|
|||||||
CIRCUITPY_ESP_FLASH_MODE = dio
|
CIRCUITPY_ESP_FLASH_MODE = dio
|
||||||
CIRCUITPY_ESP_FLASH_FREQ = 40m
|
CIRCUITPY_ESP_FLASH_FREQ = 40m
|
||||||
CIRCUITPY_ESP_FLASH_SIZE = 4MB
|
CIRCUITPY_ESP_FLASH_SIZE = 4MB
|
||||||
|
|
||||||
|
OPTIMIZATION_FLAGS = -Os
|
||||||
|
0
ports/espressif/boards/beetle-esp32-c3/README.md
Normal file
0
ports/espressif/boards/beetle-esp32-c3/README.md
Normal file
47
ports/espressif/boards/beetle-esp32-c3/board.c
Normal file
47
ports/espressif/boards/beetle-esp32-c3/board.c
Normal 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) {
|
||||||
|
}
|
47
ports/espressif/boards/beetle-esp32-c3/mpconfigboard.h
Normal file
47
ports/espressif/boards/beetle-esp32-c3/mpconfigboard.h
Normal 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)
|
11
ports/espressif/boards/beetle-esp32-c3/mpconfigboard.mk
Normal file
11
ports/espressif/boards/beetle-esp32-c3/mpconfigboard.mk
Normal 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
|
66
ports/espressif/boards/beetle-esp32-c3/pins.c
Normal file
66
ports/espressif/boards/beetle-esp32-c3/pins.c
Normal 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);
|
7
ports/espressif/boards/beetle-esp32-c3/sdkconfig
Normal file
7
ports/espressif/boards/beetle-esp32-c3/sdkconfig
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
#
|
||||||
|
# LWIP
|
||||||
|
#
|
||||||
|
CONFIG_LWIP_LOCAL_HOSTNAME="beetle-esp32-c3
|
||||||
|
# end of LWIP
|
||||||
|
|
||||||
|
|
@ -394,6 +394,11 @@ STATIC void discover_remote_services(bleio_connection_internal_t *self, mp_obj_t
|
|||||||
? service->end_handle
|
? service->end_handle
|
||||||
: next_characteristic->def_handle - 1;
|
: 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;
|
_last_discovery_status = BLE_ERR_SUCCESS;
|
||||||
CHECK_NIMBLE_ERROR(ble_gattc_disc_all_dscs(self->conn_handle, characteristic->handle,
|
CHECK_NIMBLE_ERROR(ble_gattc_disc_all_dscs(self->conn_handle, characteristic->handle,
|
||||||
end_handle,
|
end_handle,
|
||||||
|
@ -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) {
|
void common_hal_mdns_server_set_hostname(mdns_server_obj_t *self, const char *hostname) {
|
||||||
mdns_hostname_set(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;
|
self->hostname = hostname;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -30,38 +30,213 @@
|
|||||||
#include "shared/runtime/interrupt_char.h"
|
#include "shared/runtime/interrupt_char.h"
|
||||||
#include "py/mperrno.h"
|
#include "py/mperrno.h"
|
||||||
#include "py/runtime.h"
|
#include "py/runtime.h"
|
||||||
|
#include "shared-bindings/socketpool/SocketPool.h"
|
||||||
|
#include "supervisor/port.h"
|
||||||
#include "supervisor/shared/tick.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/err.h"
|
||||||
#include "components/lwip/lwip/src/include/lwip/sockets.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/sys.h"
|
||||||
#include "components/lwip/lwip/src/include/lwip/netdb.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) {
|
void socket_user_reset(void) {
|
||||||
for (size_t i = 0; i < MP_ARRAY_SIZE(open_socket_handles); i++) {
|
if (socket_change_fd < 0) {
|
||||||
if (open_socket_handles[i]) {
|
esp_vfs_eventfd_config_t config = ESP_VFS_EVENTD_CONFIG_DEFAULT();
|
||||||
if (open_socket_handles[i]->num > 0) {
|
ESP_ERROR_CHECK(esp_vfs_eventfd_register(&config));
|
||||||
// Close automatically clears socket handle
|
|
||||||
common_hal_socketpool_socket_close(open_socket_handles[i]);
|
for (size_t i = 0; i < MP_ARRAY_SIZE(open_socket_fds); i++) {
|
||||||
} else {
|
open_socket_fds[i] = -1;
|
||||||
open_socket_handles[i] = NULL;
|
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) {
|
// The writes below send an event to the socket select task so that it redoes the
|
||||||
for (size_t i = 0; i < MP_ARRAY_SIZE(open_socket_handles); i++) {
|
// select with the new open socket set.
|
||||||
if (open_socket_handles[i] == NULL) {
|
|
||||||
open_socket_handles[i] = self;
|
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 true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
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) {
|
int socketpool_socket_accept(socketpool_socket_obj_t *self, uint8_t *ip, uint32_t *port) {
|
||||||
struct sockaddr_in accept_addr;
|
struct sockaddr_in accept_addr;
|
||||||
socklen_t socklen = sizeof(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) {
|
if (newsoc < 0) {
|
||||||
return -MP_EBADF;
|
return -MP_EBADF;
|
||||||
}
|
}
|
||||||
|
if (!register_open_socket(newsoc)) {
|
||||||
|
lwip_close(newsoc);
|
||||||
|
return -MP_EBADF;
|
||||||
|
}
|
||||||
return newsoc;
|
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);
|
int newsoc = socketpool_socket_accept(self, ip, port);
|
||||||
|
|
||||||
if (newsoc > 0) {
|
if (newsoc > 0) {
|
||||||
|
mark_user_socket(newsoc);
|
||||||
// Create the socket
|
// Create the socket
|
||||||
socketpool_socket_obj_t *sock = m_new_obj_with_finaliser(socketpool_socket_obj_t);
|
socketpool_socket_obj_t *sock = m_new_obj_with_finaliser(socketpool_socket_obj_t);
|
||||||
sock->base.type = &socketpool_socket_type;
|
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->pool = self->pool;
|
||||||
sock->connected = true;
|
sock->connected = true;
|
||||||
|
|
||||||
if (!register_open_socket(sock)) {
|
|
||||||
mp_raise_OSError(MP_EBADF);
|
|
||||||
}
|
|
||||||
|
|
||||||
lwip_fcntl(newsoc, F_SETFL, O_NONBLOCK);
|
lwip_fcntl(newsoc, F_SETFL, O_NONBLOCK);
|
||||||
return sock;
|
return sock;
|
||||||
} else {
|
} else {
|
||||||
@ -150,18 +326,13 @@ void socketpool_socket_close(socketpool_socket_obj_t *self) {
|
|||||||
if (self->num >= 0) {
|
if (self->num >= 0) {
|
||||||
lwip_shutdown(self->num, SHUT_RDWR);
|
lwip_shutdown(self->num, SHUT_RDWR);
|
||||||
lwip_close(self->num);
|
lwip_close(self->num);
|
||||||
|
unregister_open_socket(self->num);
|
||||||
self->num = -1;
|
self->num = -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void common_hal_socketpool_socket_close(socketpool_socket_obj_t *self) {
|
void common_hal_socketpool_socket_close(socketpool_socket_obj_t *self) {
|
||||||
socketpool_socket_close(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,
|
void common_hal_socketpool_socket_connect(socketpool_socket_obj_t *self,
|
||||||
|
@ -46,6 +46,5 @@ typedef struct {
|
|||||||
} socketpool_socket_obj_t;
|
} socketpool_socket_obj_t;
|
||||||
|
|
||||||
void socket_user_reset(void);
|
void socket_user_reset(void);
|
||||||
bool register_open_socket(socketpool_socket_obj_t *self);
|
|
||||||
|
|
||||||
#endif // MICROPY_INCLUDED_ESPRESSIF_COMMON_HAL_SOCKETPOOL_SOCKET_H
|
#endif // MICROPY_INCLUDED_ESPRESSIF_COMMON_HAL_SOCKETPOOL_SOCKET_H
|
||||||
|
@ -40,61 +40,7 @@ void common_hal_socketpool_socketpool_construct(socketpool_socketpool_obj_t *sel
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool socketpool_socket(socketpool_socketpool_obj_t *self,
|
// common_hal_socketpool_socket is in socketpool/Socket.c to centralize open socket tracking.
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
mp_obj_t common_hal_socketpool_socketpool_gethostbyname(socketpool_socketpool_obj_t *self,
|
mp_obj_t common_hal_socketpool_socketpool_gethostbyname(socketpool_socketpool_obj_t *self,
|
||||||
const char *host) {
|
const char *host) {
|
||||||
|
@ -1 +1 @@
|
|||||||
Subproject commit 171e5af9c5b9b126c5f81f217c7b1ff931d54863
|
Subproject commit 0180c0cb80f052919badc15df164e8edde6344ad
|
@ -53,6 +53,7 @@
|
|||||||
#include "shared-bindings/microcontroller/__init__.h"
|
#include "shared-bindings/microcontroller/__init__.h"
|
||||||
#include "shared-bindings/microcontroller/RunMode.h"
|
#include "shared-bindings/microcontroller/RunMode.h"
|
||||||
#include "shared-bindings/rtc/__init__.h"
|
#include "shared-bindings/rtc/__init__.h"
|
||||||
|
#include "shared-bindings/socketpool/__init__.h"
|
||||||
|
|
||||||
#include "peripherals/rmt.h"
|
#include "peripherals/rmt.h"
|
||||||
#include "peripherals/timer.h"
|
#include "peripherals/timer.h"
|
||||||
@ -296,6 +297,10 @@ void reset_port(void) {
|
|||||||
rtc_reset();
|
rtc_reset();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if CIRCUITPY_SOCKETPOOL
|
||||||
|
socketpool_user_reset();
|
||||||
|
#endif
|
||||||
|
|
||||||
#if CIRCUITPY_TOUCHIO_USE_NATIVE
|
#if CIRCUITPY_TOUCHIO_USE_NATIVE
|
||||||
peripherals_touch_reset();
|
peripherals_touch_reset();
|
||||||
#endif
|
#endif
|
||||||
|
@ -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_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) {
|
if (init_bufinfo.len % 2 != 0) {
|
||||||
mp_raise_ValueError(translate("Init program size invalid"));
|
mp_raise_ValueError(translate("Init program size invalid"));
|
||||||
}
|
}
|
||||||
|
40
ports/raspberrypi/boards/bwshockley_figpi/board.c
Normal file
40
ports/raspberrypi/boards/bwshockley_figpi/board.c
Normal 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) {
|
||||||
|
}
|
15
ports/raspberrypi/boards/bwshockley_figpi/mpconfigboard.h
Normal file
15
ports/raspberrypi/boards/bwshockley_figpi/mpconfigboard.h
Normal 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}}
|
@ -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"
|
@ -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
|
62
ports/raspberrypi/boards/bwshockley_figpi/pins.c
Normal file
62
ports/raspberrypi/boards/bwshockley_figpi/pins.c
Normal 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);
|
40
ports/raspberrypi/boards/wiznet_w5500_evb_pico/board.c
Normal file
40
ports/raspberrypi/boards/wiznet_w5500_evb_pico/board.c
Normal 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) {
|
||||||
|
}
|
@ -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)
|
@ -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
|
@ -0,0 +1 @@
|
|||||||
|
// Put board-specific pico-sdk definitions here. This file must exist.
|
54
ports/raspberrypi/boards/wiznet_w5500_evb_pico/pins.c
Normal file
54
ports/raspberrypi/boards/wiznet_w5500_evb_pico/pins.c
Normal 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);
|
@ -37,8 +37,8 @@ INC += -I$(BUILD)
|
|||||||
|
|
||||||
# compiler settings
|
# compiler settings
|
||||||
CWARN = -Wall -Werror
|
CWARN = -Wall -Werror
|
||||||
CWARN += -Wextra -Wno-unused-parameter -Wpointer-arith -Wdouble-promotion -Wfloat-conversion
|
CWARN += -Wextra -Wno-unused-parameter -Wno-missing-field-initializers -Wpointer-arith -Wdouble-promotion -Wfloat-conversion
|
||||||
CFLAGS += $(INC) $(CWARN) -std=gnu99 -DUNIX $(CFLAGS_MOD) $(COPT) -I$(VARIANT_DIR) $(CFLAGS_EXTRA)
|
CFLAGS += $(INC) $(CWARN) -std=gnu11 -DUNIX $(CFLAGS_MOD) $(COPT) -I$(VARIANT_DIR) $(CFLAGS_EXTRA)
|
||||||
|
|
||||||
# Debugging/Optimization
|
# Debugging/Optimization
|
||||||
ifdef DEBUG
|
ifdef DEBUG
|
||||||
|
26
py/objint.c
26
py/objint.c
@ -480,19 +480,33 @@ MP_DEFINE_CONST_FUN_OBJ_1(int_bit_length_obj, int_bit_length);
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
// this is a classmethod
|
// 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)
|
// 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
|
// get the buffer info
|
||||||
mp_buffer_info_t bufinfo;
|
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;
|
const byte *buf = (const byte *)bufinfo.buf;
|
||||||
int delta = 1;
|
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;
|
buf += bufinfo.len - 1;
|
||||||
delta = -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;
|
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 MICROPY_LONGINT_IMPL != MICROPY_LONGINT_IMPL_NONE
|
||||||
if (value > (MP_SMALL_INT_MAX >> 8)) {
|
if (value > (MP_SMALL_INT_MAX >> 8)) {
|
||||||
// Result will overflow a small-int so construct a big-int
|
// 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
|
#endif
|
||||||
value = (value << 8) | *buf;
|
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);
|
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_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) {
|
STATIC mp_obj_t int_to_bytes(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
|
||||||
|
@ -350,38 +350,40 @@ static bool _endswith(const char *str, const char *suffix) {
|
|||||||
return strcmp(str + (strlen(str) - strlen(suffix)), suffix) == 0;
|
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) {
|
static bool _origin_ok(const char *origin) {
|
||||||
const char *http = "http://";
|
const char *http = "http://";
|
||||||
const char *local = ".local";
|
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;
|
return false;
|
||||||
}
|
}
|
||||||
// These are prefix checks up to : so that any port works.
|
// These are prefix checks up to : so that any port works.
|
||||||
const char *hostname = common_hal_mdns_server_get_hostname(&mdns);
|
const char *hostname = common_hal_mdns_server_get_hostname(&mdns);
|
||||||
const char *end = origin + strlen(http) + strlen(hostname) + strlen(local);
|
const char *end = origin + strlen(http) + strlen(hostname) + strlen(local);
|
||||||
if (memcmp(origin + strlen(http), hostname, strlen(hostname)) == 0 &&
|
if (strncmp(origin + strlen(http), hostname, strlen(hostname)) == 0 &&
|
||||||
memcmp(origin + strlen(http) + strlen(hostname), local, strlen(local)) == 0 &&
|
strncmp(origin + strlen(http) + strlen(hostname), local, strlen(local)) == 0 &&
|
||||||
(end[0] == '\0' || end[0] == ':')) {
|
(end[0] == '\0' || end[0] == ':')) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
end = origin + strlen(http) + strlen(_our_ip_encoded);
|
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] == ':')) {
|
(end[0] == '\0' || end[0] == ':')) {
|
||||||
return true;
|
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++) {
|
for (size_t i = 0; i < MP_ARRAY_SIZE(ok_hosts); i++) {
|
||||||
// This checks exactly.
|
// Allows any port
|
||||||
if (strcmp(origin + strlen(http), ok_hosts[i]) == 0) {
|
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;
|
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) {
|
static void _cors_header(socketpool_socket_obj_t *socket, _request *request) {
|
||||||
_send_strs(socket,
|
_send_strs(socket,
|
||||||
"Access-Control-Allow-Credentials: true\r\n",
|
"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",
|
"Access-Control-Allow-Origin: ", request->origin, "\r\n",
|
||||||
NULL);
|
NULL);
|
||||||
}
|
}
|
||||||
@ -440,10 +442,10 @@ static void _reply_access_control(socketpool_socket_obj_t *socket, _request *req
|
|||||||
"Access-Control-Allow-Methods:GET, OPTIONS", NULL);
|
"Access-Control-Allow-Methods:GET, OPTIONS", NULL);
|
||||||
if (!_usb_active()) {
|
if (!_usb_active()) {
|
||||||
_send_str(socket, ", PUT, DELETE");
|
_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");
|
_send_str(socket, "\r\n");
|
||||||
_cors_header(socket, request);
|
_cors_header(socket, request);
|
||||||
_send_str(socket, "\r\n");
|
_send_str(socket, "\r\n");
|
||||||
@ -740,14 +742,25 @@ STATIC uint64_t truncate_time(uint64_t input_time, DWORD *fattime) {
|
|||||||
return truncated_time;
|
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) {
|
static void _write_file_and_reply(socketpool_socket_obj_t *socket, _request *request, FATFS *fs, const TCHAR *path) {
|
||||||
FIL active_file;
|
FIL active_file;
|
||||||
|
|
||||||
if (_usb_active()) {
|
if (_usb_active()) {
|
||||||
|
_discard_incoming(socket, request->content_length);
|
||||||
_reply_conflict(socket, request);
|
_reply_conflict(socket, request);
|
||||||
#if CIRCUITPY_USB_MSC
|
|
||||||
usb_msc_unlock();
|
|
||||||
#endif
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (request->timestamp_ms > 0) {
|
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) {
|
if (result == FR_NO_PATH) {
|
||||||
override_fattime(0);
|
override_fattime(0);
|
||||||
|
#if CIRCUITPY_USB_MSC
|
||||||
|
usb_msc_unlock();
|
||||||
|
#endif
|
||||||
|
_discard_incoming(socket, request->content_length);
|
||||||
_reply_missing(socket, request);
|
_reply_missing(socket, request);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (result != FR_OK) {
|
if (result != FR_OK) {
|
||||||
ESP_LOGE(TAG, "file write error %d %s", result, path);
|
ESP_LOGE(TAG, "file write error %d %s", result, path);
|
||||||
override_fattime(0);
|
override_fattime(0);
|
||||||
|
#if CIRCUITPY_USB_MSC
|
||||||
|
usb_msc_unlock();
|
||||||
|
#endif
|
||||||
|
_discard_incoming(socket, request->content_length);
|
||||||
_reply_server_error(socket, request);
|
_reply_server_error(socket, request);
|
||||||
return;
|
return;
|
||||||
} else if (request->expect) {
|
} 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
|
#if CIRCUITPY_USB_MSC
|
||||||
usb_msc_unlock();
|
usb_msc_unlock();
|
||||||
#endif
|
#endif
|
||||||
|
_discard_incoming(socket, request->content_length);
|
||||||
// Too large.
|
// Too large.
|
||||||
if (request->expect) {
|
if (request->expect) {
|
||||||
_reply_expectation_failed(socket, request);
|
_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)) {
|
} else if (strlen(request->origin) > 0 && !_origin_ok(request->origin)) {
|
||||||
ESP_LOGE(TAG, "bad origin %s", request->origin);
|
ESP_LOGE(TAG, "bad origin %s", request->origin);
|
||||||
_reply_forbidden(socket, request);
|
_reply_forbidden(socket, request);
|
||||||
} else if (memcmp(request->path, "/fs/", 4) == 0) {
|
} else if (strncmp(request->path, "/fs/", 4) == 0) {
|
||||||
if (!request->authenticated) {
|
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') {
|
if (_api_password[0] != '\0') {
|
||||||
_reply_unauthorized(socket, request);
|
_reply_unauthorized(socket, request);
|
||||||
} else {
|
} 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
|
// Delete is almost identical for files and directories so share the
|
||||||
// implementation.
|
// implementation.
|
||||||
if (strcmp(request->method, "OPTIONS") == 0) {
|
if (strcasecmp(request->method, "DELETE") == 0) {
|
||||||
_reply_access_control(socket, request);
|
|
||||||
} else if (strcmp(request->method, "DELETE") == 0) {
|
|
||||||
if (_usb_active()) {
|
if (_usb_active()) {
|
||||||
_reply_conflict(socket, request);
|
_reply_conflict(socket, request);
|
||||||
#if CIRCUITPY_USB_MSC
|
|
||||||
usb_msc_unlock();
|
|
||||||
#endif
|
|
||||||
return false;
|
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) {
|
if (result == FR_NO_PATH || result == FR_NO_FILE) {
|
||||||
_reply_missing(socket, request);
|
_reply_missing(socket, request);
|
||||||
} else if (result != FR_OK) {
|
} else if (result != FR_OK) {
|
||||||
@ -944,7 +967,7 @@ static bool _reply(socketpool_socket_obj_t *socket, _request *request) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
} else if (directory) {
|
} else if (directory) {
|
||||||
if (strcmp(request->method, "GET") == 0) {
|
if (strcasecmp(request->method, "GET") == 0) {
|
||||||
FF_DIR dir;
|
FF_DIR dir;
|
||||||
FRESULT res = f_opendir(fs, &dir, path);
|
FRESULT res = f_opendir(fs, &dir, path);
|
||||||
// Put the / back for replies.
|
// Put the / back for replies.
|
||||||
@ -964,12 +987,9 @@ static bool _reply(socketpool_socket_obj_t *socket, _request *request) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
f_closedir(&dir);
|
f_closedir(&dir);
|
||||||
} else if (strcmp(request->method, "PUT") == 0) {
|
} else if (strcasecmp(request->method, "PUT") == 0) {
|
||||||
if (_usb_active()) {
|
if (_usb_active()) {
|
||||||
_reply_conflict(socket, request);
|
_reply_conflict(socket, request);
|
||||||
#if CIRCUITPY_USB_MSC
|
|
||||||
usb_msc_unlock();
|
|
||||||
#endif
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -996,7 +1016,7 @@ static bool _reply(socketpool_socket_obj_t *socket, _request *request) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else { // Dealing with a file.
|
} else { // Dealing with a file.
|
||||||
if (strcmp(request->method, "GET") == 0) {
|
if (strcasecmp(request->method, "GET") == 0) {
|
||||||
FIL active_file;
|
FIL active_file;
|
||||||
FRESULT result = f_open(fs, &active_file, path, FA_READ);
|
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);
|
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);
|
_write_file_and_reply(socket, request, fs, path);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -1023,9 +1043,12 @@ static bool _reply(socketpool_socket_obj_t *socket, _request *request) {
|
|||||||
} else {
|
} else {
|
||||||
_REPLY_STATIC(socket, request, edit_html);
|
_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;
|
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);
|
_reply_method_not_allowed(socket, request);
|
||||||
} else if (strcmp(path, "/devices.json") == 0) {
|
} else if (strcmp(path, "/devices.json") == 0) {
|
||||||
_reply_with_devices_json(socket, request);
|
_reply_with_devices_json(socket, request);
|
||||||
@ -1046,7 +1069,7 @@ static bool _reply(socketpool_socket_obj_t *socket, _request *request) {
|
|||||||
} else {
|
} else {
|
||||||
_reply_missing(socket, request);
|
_reply_missing(socket, request);
|
||||||
}
|
}
|
||||||
} else if (strcmp(request->method, "GET") != 0) {
|
} else if (strcasecmp(request->method, "GET") != 0) {
|
||||||
_reply_method_not_allowed(socket, request);
|
_reply_method_not_allowed(socket, request);
|
||||||
} else {
|
} else {
|
||||||
if (strcmp(request->path, "/") == 0) {
|
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->header_value[request->offset - 1] = '\0';
|
||||||
request->offset = 0;
|
request->offset = 0;
|
||||||
request->state = STATE_HEADER_KEY;
|
request->state = STATE_HEADER_KEY;
|
||||||
if (strcmp(request->header_key, "Authorization") == 0) {
|
if (strcasecmp(request->header_key, "Authorization") == 0) {
|
||||||
const char *prefix = "Basic ";
|
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;
|
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;
|
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);
|
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;
|
request->expect = strcmp(request->header_value, "100-continue") == 0;
|
||||||
} else if (strcmp(request->header_key, "Accept") == 0) {
|
} else if (strcasecmp(request->header_key, "Accept") == 0) {
|
||||||
request->json = strcmp(request->header_value, "application/json") == 0;
|
request->json = strcasecmp(request->header_value, "application/json") == 0;
|
||||||
} else if (strcmp(request->header_key, "Origin") == 0) {
|
} else if (strcasecmp(request->header_key, "Origin") == 0) {
|
||||||
strcpy(request->origin, request->header_value);
|
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);
|
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;
|
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);
|
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) {
|
strlen(request->header_value) == 24) {
|
||||||
strcpy(request->websocket_key, request->header_value);
|
strcpy(request->websocket_key, request->header_value);
|
||||||
}
|
}
|
||||||
|
@ -66,6 +66,10 @@ static void workflow_background(void *data) {
|
|||||||
#if CIRCUITPY_STATUS_BAR
|
#if CIRCUITPY_STATUS_BAR
|
||||||
supervisor_workflow_update_status_bar();
|
supervisor_workflow_update_status_bar();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if CIRCUITPY_WEB_WORKFLOW
|
||||||
|
supervisor_web_workflow_background();
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
// Called during a VM reset. Doesn't actually reset things.
|
// Called during a VM reset. Doesn't actually reset things.
|
||||||
|
@ -77,6 +77,7 @@ extension_by_board = {
|
|||||||
"adafruit_qtpy_esp32c3": BIN,
|
"adafruit_qtpy_esp32c3": BIN,
|
||||||
"ai_thinker_esp32-c3s": BIN,
|
"ai_thinker_esp32-c3s": BIN,
|
||||||
"ai_thinker_esp32-c3s-2m": BIN,
|
"ai_thinker_esp32-c3s-2m": BIN,
|
||||||
|
"beetle-esp32-c3": BIN,
|
||||||
"espressif_esp32c3_devkitm_1_n4": BIN,
|
"espressif_esp32c3_devkitm_1_n4": BIN,
|
||||||
"lilygo_ttgo_t-01c3": BIN,
|
"lilygo_ttgo_t-01c3": BIN,
|
||||||
"lolin_c3_mini": BIN,
|
"lolin_c3_mini": BIN,
|
||||||
|
Loading…
Reference in New Issue
Block a user