diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 8dc31a3ff6..94837e4082 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -143,7 +143,7 @@ jobs: mpy-cross-mac: - runs-on: macos-10.15 + runs-on: macos-11 steps: - name: Dump GitHub context env: @@ -176,27 +176,25 @@ jobs: run: make -C mpy-cross -j2 - uses: actions/upload-artifact@v2 with: - name: mpy-cross-macos-catalina + name: mpy-cross-macos-11-x64 path: mpy-cross/mpy-cross - - name: Select SDK for M1 build - run: sudo xcode-select -switch /Applications/Xcode_12.3.app - name: Build mpy-cross (arm64) run: make -C mpy-cross -j2 -f Makefile.m1 V=2 - uses: actions/upload-artifact@v2 with: - name: mpy-cross-macos-bigsur-arm64 + name: mpy-cross-macos-11-arm64 path: mpy-cross/mpy-cross-arm64 - name: Make universal binary - run: lipo -create -output mpy-cross-macos-universal mpy-cross/mpy-cross mpy-cross/mpy-cross-arm64 + run: lipo -create -output mpy-cross-macos-11-universal mpy-cross/mpy-cross mpy-cross/mpy-cross-arm64 - uses: actions/upload-artifact@v2 with: - name: mpy-cross-macos-universal - path: mpy-cross-macos-universal + name: mpy-cross-macos-11-universal + path: mpy-cross-macos-11-universal - name: Upload mpy-cross build to S3 run: | - [ -z "$AWS_ACCESS_KEY_ID" ] || aws s3 cp mpy-cross-macos-universal s3://adafruit-circuit-python/bin/mpy-cross/mpy-cross-macos-universal-${{ env.CP_VERSION }} --no-progress --region us-east-1 - [ -z "$AWS_ACCESS_KEY_ID" ] || aws s3 cp mpy-cross/mpy-cross-arm64 s3://adafruit-circuit-python/bin/mpy-cross/mpy-cross-macos-bigsur-${{ env.CP_VERSION }}-arm64 --no-progress --region us-east-1 - [ -z "$AWS_ACCESS_KEY_ID" ] || aws s3 cp mpy-cross/mpy-cross s3://adafruit-circuit-python/bin/mpy-cross/mpy-cross-macos-catalina-${{ env.CP_VERSION }} --no-progress --region us-east-1 + [ -z "$AWS_ACCESS_KEY_ID" ] || aws s3 cp mpy-cross-macos-universal s3://adafruit-circuit-python/bin/mpy-cross/mpy-cross-macos-11-${{ env.CP_VERSION }}-universal --no-progress --region us-east-1 + [ -z "$AWS_ACCESS_KEY_ID" ] || aws s3 cp mpy-cross/mpy-cross-arm64 s3://adafruit-circuit-python/bin/mpy-cross/mpy-cross-macos-11-${{ env.CP_VERSION }}-arm64 --no-progress --region us-east-1 + [ -z "$AWS_ACCESS_KEY_ID" ] || aws s3 cp mpy-cross/mpy-cross s3://adafruit-circuit-python/bin/mpy-cross/mpy-cross-macos-11-${{ env.CP_VERSION }}-x64 --no-progress --region us-east-1 env: AWS_PAGER: '' AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} diff --git a/conf.py b/conf.py index 145bed4d7b..b7e2f29914 100644 --- a/conf.py +++ b/conf.py @@ -33,25 +33,6 @@ from sphinx import addnodes tools_describe = str(pathlib.Path(__file__).parent / "tools/describe") -# Monkeypatch autoapi -def _format_args(args_info, include_annotations=True, ignore_self=None): - result = [] - - for i, (prefix, name, annotation, default) in enumerate(args_info): - if i == 0 and ignore_self is not None and name == ignore_self: - continue - formatted = "{}{}{}{}".format( - prefix or "", - name or "", - ": {}".format(annotation) if annotation and include_annotations else "", - (" = {}" if annotation else "={}").format(default) if default else "", - ) - result.append(formatted) - return ", ".join(result) - -import autoapi.mappers.python.objects as objects -objects._format_args = _format_args - # If extensions (or modules to document with autodoc) are in another directory, # add these directories to sys.path here. If the directory is relative to the # documentation root, use os.path.abspath to make it absolute, like shown here. @@ -71,8 +52,8 @@ subprocess.check_output(["make", "stubs"]) #modules_support_matrix = shared_bindings_matrix.support_matrix_excluded_boards() modules_support_matrix = shared_bindings_matrix.support_matrix_by_board() modules_support_matrix_reverse = defaultdict(list) -for board, modules in modules_support_matrix.items(): - for module in modules[0]: +for board, matrix_info in modules_support_matrix.items(): + for module in matrix_info["modules"]: modules_support_matrix_reverse[module].append(board) modules_support_matrix_reverse = dict( diff --git a/docs/environment.rst b/docs/environment.rst index 4d12009848..b1619f37bf 100644 --- a/docs/environment.rst +++ b/docs/environment.rst @@ -39,6 +39,10 @@ CIRCUITPY_WEB_API_PASSWORD ~~~~~~~~~~~~~~~~~~~~~~~~~~ Password required to make modifications to the board from the Web Workflow. +CIRCUITPY_WEB_API_PORT +~~~~~~~~~~~~~~~~~~~~~~ +TCP port number used for the web HTTP API. Defaults to 80 when omitted. + CIRCUITPY_WIFI_PASSWORD ~~~~~~~~~~~~~~~~~~~~~~~ Wi-Fi password used to auto connect to CIRCUITPY_WIFI_SSID. diff --git a/docs/shared_bindings_matrix.py b/docs/shared_bindings_matrix.py index 961b38370d..daa8d9f8b8 100644 --- a/docs/shared_bindings_matrix.py +++ b/docs/shared_bindings_matrix.py @@ -32,7 +32,7 @@ from concurrent.futures import ThreadPoolExecutor SUPPORTED_PORTS = ['atmel-samd', 'broadcom', 'cxd56', 'espressif', 'litex', 'mimxrt10xx', 'nrf', 'raspberrypi', 'stm'] -aliases_by_board = { +ALIASES_BY_BOARD = { "circuitplayground_express": [ "circuitplayground_express_4h", "circuitplayground_express_digikey_pycon2019", @@ -43,7 +43,7 @@ aliases_by_board = { "pewpew10": ["pewpew13"], } -aliases_brand_names = { +ALIASES_BRAND_NAMES = { "circuitplayground_express_4h": "Adafruit Circuit Playground Express 4-H", "circuitplayground_express_digikey_pycon2019": @@ -58,7 +58,7 @@ aliases_brand_names = { "PewPew 13", } -additional_modules = { +ADDITIONAL_MODULES = { "fontio": "CIRCUITPY_DISPLAYIO", "terminalio": "CIRCUITPY_DISPLAYIO", "adafruit_bus_device": "CIRCUITPY_BUSDEVICE", @@ -66,7 +66,7 @@ additional_modules = { "usb": "CIRCUITPY_USB_HOST", } -frozen_excludes = ["examples", "docs", "tests", "utils", "conf.py", "setup.py"] +FROZEN_EXCLUDES = ["examples", "docs", "tests", "utils", "conf.py", "setup.py"] """Files and dirs at the root of a frozen directory that should be ignored. This is the same list as in the preprocess_frozen_modules script.""" @@ -74,7 +74,7 @@ repository_urls = {} """Cache of repository URLs for frozen modules.""" def get_circuitpython_root_dir(): - """ The path to the root './circuitpython' directory + """ The path to the root './circuitpython' directory. """ file_path = pathlib.Path(__file__).resolve() root_dir = file_path.parent.parent @@ -82,12 +82,40 @@ def get_circuitpython_root_dir(): return root_dir def get_shared_bindings(): - """ Get a list of modules in shared-bindings based on folder names + """ Get a list of modules in shared-bindings based on folder names. """ shared_bindings_dir = get_circuitpython_root_dir() / "shared-bindings" return [item.name for item in shared_bindings_dir.iterdir()] + ["binascii", "errno", "json", "re", "ulab"] +def get_board_mapping(): + """ + Compiles the list of boards from the directories, with aliases and mapping + to the port. + """ + boards = {} + for port in SUPPORTED_PORTS: + board_path = os.path.join("../ports", port, "boards") + for board_path in os.scandir(board_path): + if board_path.is_dir(): + board_files = os.listdir(board_path.path) + board_id = board_path.name + aliases = ALIASES_BY_BOARD.get(board_path.name, []) + boards[board_id] = { + "port": port, + "download_count": 0, + "aliases": aliases, + } + for alias in aliases: + boards[alias] = { + "port": port, + "download_count": 0, + "alias": True, + "aliases": [], + } + return boards + + def read_mpconfig(): """ Open 'circuitpy_mpconfig.mk' and return the contents. """ @@ -112,8 +140,8 @@ def build_module_map(): full_build = False for module in modules: full_name = module - if module in additional_modules: - search_identifier = additional_modules[module] + if module in ADDITIONAL_MODULES: + search_identifier = ADDITIONAL_MODULES[module] else: search_identifier = 'CIRCUITPY_'+module.lstrip("_").upper() re_pattern = f"{re.escape(search_identifier)}\s*\??=\s*(.+)" @@ -204,27 +232,33 @@ def get_repository_url(directory): repository_urls[directory] = path return path -def frozen_modules_from_dirs(frozen_mpy_dirs): +def frozen_modules_from_dirs(frozen_mpy_dirs, withurl): """ Go through the list of frozen directories and extract the python modules. Paths are of the type: $(TOP)/frozen/Adafruit_CircuitPython_CircuitPlayground $(TOP)/frozen/circuitpython-stage/meowbit Python modules are at the root of the path, and are python files or directories - containing python files. Except the ones in the frozen_excludes list. + containing python files. Except the ones in the FROZEN_EXCLUDES list. """ frozen_modules = [] for frozen_path in filter(lambda x: x, frozen_mpy_dirs.split(" ")): source_dir = get_circuitpython_root_dir() / frozen_path[7:] url_repository = get_repository_url(source_dir) for sub in source_dir.glob("*"): - if sub.name in frozen_excludes: + if sub.name in FROZEN_EXCLUDES: continue if sub.name.endswith(".py"): - frozen_modules.append((sub.name[:-3], url_repository)) + if withurl: + frozen_modules.append((sub.name[:-3], url_repository)) + else: + frozen_modules.append(sub.name[:-3]) continue if next(sub.glob("**/*.py"), None): # tests if not empty - frozen_modules.append((sub.name, url_repository)) + if withurl: + frozen_modules.append((sub.name, url_repository)) + else: + frozen_modules.append(sub.name) return frozen_modules def lookup_setting(settings, key, default=''): @@ -244,7 +278,7 @@ def all_ports_all_boards(ports=SUPPORTED_PORTS): continue yield (port, entry) -def support_matrix_by_board(use_branded_name=True): +def support_matrix_by_board(use_branded_name=True, withurl=True): """ Compiles a list of the available core modules available for each board. """ @@ -272,29 +306,49 @@ def support_matrix_by_board(use_branded_name=True): board_modules.append(base[module]['name']) board_modules.sort() + if "CIRCUITPY_BUILD_EXTENSIONS" in settings: + board_extensions = [ + extension.strip() for extension in + settings["CIRCUITPY_BUILD_EXTENSIONS"].split(",") + ] + else: + raise OSError(f"Board extensions undefined: {board_name}.") + frozen_modules = [] if "FROZEN_MPY_DIRS" in settings: - frozen_modules = frozen_modules_from_dirs(settings["FROZEN_MPY_DIRS"]) + frozen_modules = frozen_modules_from_dirs(settings["FROZEN_MPY_DIRS"], withurl) if frozen_modules: frozen_modules.sort() # generate alias boards too - board_matrix = [(board_name, (board_modules, frozen_modules))] - if entry.name in aliases_by_board: - for alias in aliases_by_board[entry.name]: + board_matrix = [( + board_name, { + "modules": board_modules, + "frozen_libraries": frozen_modules, + "extensions": board_extensions, + } + )] + if entry.name in ALIASES_BY_BOARD: + for alias in ALIASES_BY_BOARD[entry.name]: if use_branded_name: - if alias in aliases_brand_names: - alias = aliases_brand_names[alias] + if alias in ALIASES_BRAND_NAMES: + alias = ALIASES_BRAND_NAMES[alias] else: alias = alias.replace("_"," ").title() - board_matrix.append( (alias, (board_modules, frozen_modules)) ) + board_matrix.append(( + alias, { + "modules": board_modules, + "frozen_libraries": frozen_modules, + "extensions": board_extensions, + }, + )) return board_matrix # this is now a list of (board,modules) executor = ThreadPoolExecutor(max_workers=os.cpu_count()) mapped_exec = executor.map(support_matrix, all_ports_all_boards()) # flatmap with comprehensions - boards = dict(sorted([board for matrix in mapped_exec for board in matrix])) + boards = dict(sorted([board for matrix in mapped_exec for board in matrix], key=lambda x: x[0])) return boards diff --git a/docs/workflows.md b/docs/workflows.md index 2196d1111a..8530269534 100644 --- a/docs/workflows.md +++ b/docs/workflows.md @@ -72,7 +72,7 @@ Read-only characteristic that returns the UTF-8 encoded version string. The web workflow is depends on adding Wi-Fi credentials into the `/.env` file. The keys are `CIRCUITPY_WIFI_SSID` and `CIRCUITPY_WIFI_PASSWORD`. Once these are defined, CircuitPython will automatically connect to the network and start the webserver used for the workflow. The webserver -is on port 80. It also enables MDNS. +is on port 80 unless overridden by `CIRCUITPY_WEB_API_PORT`. It also enables MDNS. Here is an example `/.env`: @@ -83,6 +83,8 @@ CIRCUITPY_WIFI_PASSWORD='secretpassword' # To enable modifying files from the web. Change this too! CIRCUITPY_WEB_API_PASSWORD='passw0rd' + +CIRCUITPY_WEB_API_PORT=80 ``` MDNS is used to resolve [`circuitpython.local`](http://circuitpython.local) to a device specific diff --git a/frozen/circuitpython-stage b/frozen/circuitpython-stage index 3bdd335452..f993d5fac6 160000 --- a/frozen/circuitpython-stage +++ b/frozen/circuitpython-stage @@ -1 +1 @@ -Subproject commit 3bdd335452ff14a53d1e840de043e3159cb3b829 +Subproject commit f993d5fac69f3a0cfa33988268666c462b72c0ec diff --git a/locale/pt_BR.po b/locale/pt_BR.po index 5d9c4517ec..38cf9c7ff0 100644 --- a/locale/pt_BR.po +++ b/locale/pt_BR.po @@ -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-15 21:21+0000\n" +"PO-Revision-Date: 2022-07-24 22:22+0000\n" "Last-Translator: Wellington Terumi Uemura \n" "Language-Team: \n" "Language: pt_BR\n" @@ -216,7 +216,7 @@ msgstr "todos os %q, %q, e %q devem ter mesmo comprimento" #: py/objint.c msgid "%q=%q" -msgstr "" +msgstr "%q=%q" #: ports/espressif/bindings/espidf/__init__.c ports/espressif/esp_error.c #, c-format diff --git a/mpy-cross/Makefile.m1 b/mpy-cross/Makefile.m1 index 34e9841540..13431f708b 100644 --- a/mpy-cross/Makefile.m1 +++ b/mpy-cross/Makefile.m1 @@ -7,4 +7,4 @@ BUILD=build-arm64 include mpy-cross.mk # Because mpy-cross.mk unconditionally overwrites CC for Darwin, we must set it BELOW the inclusion -CC := $(shell xcrun --sdk macosx11.1 --find clang) -isysroot $(shell xcrun --sdk macosx11.1 --show-sdk-path) -target arm64-apple-macos11 +CC := $(shell xcrun --find clang) -isysroot $(shell xcrun --show-sdk-path) -target arm64-apple-macos11 diff --git a/ports/atmel-samd/boards/arduino_mkr1300/mpconfigboard.mk b/ports/atmel-samd/boards/arduino_mkr1300/mpconfigboard.mk index c3d75202bf..261e30d7e5 100644 --- a/ports/atmel-samd/boards/arduino_mkr1300/mpconfigboard.mk +++ b/ports/atmel-samd/boards/arduino_mkr1300/mpconfigboard.mk @@ -6,6 +6,8 @@ USB_MANUFACTURER = "Arduino" CHIP_VARIANT = SAMD21G18A CHIP_FAMILY = samd21 +CIRCUITPY_BUILD_EXTENSIONS = bin,uf2 + INTERNAL_FLASH_FILESYSTEM = 1 LONGINT_IMPL = NONE CIRCUITPY_FULL_BUILD = 0 diff --git a/ports/atmel-samd/boards/arduino_mkrzero/mpconfigboard.mk b/ports/atmel-samd/boards/arduino_mkrzero/mpconfigboard.mk index eea3a27f13..4f058e4f2a 100644 --- a/ports/atmel-samd/boards/arduino_mkrzero/mpconfigboard.mk +++ b/ports/atmel-samd/boards/arduino_mkrzero/mpconfigboard.mk @@ -6,6 +6,8 @@ USB_MANUFACTURER = "Arduino" CHIP_VARIANT = SAMD21G18A CHIP_FAMILY = samd21 +CIRCUITPY_BUILD_EXTENSIONS = bin,uf2 + INTERNAL_FLASH_FILESYSTEM = 1 LONGINT_IMPL = NONE CIRCUITPY_FULL_BUILD = 0 diff --git a/ports/atmel-samd/boards/arduino_nano_33_iot/mpconfigboard.mk b/ports/atmel-samd/boards/arduino_nano_33_iot/mpconfigboard.mk index 895c027ee5..f289aad065 100644 --- a/ports/atmel-samd/boards/arduino_nano_33_iot/mpconfigboard.mk +++ b/ports/atmel-samd/boards/arduino_nano_33_iot/mpconfigboard.mk @@ -6,6 +6,8 @@ USB_MANUFACTURER = "Arduino" CHIP_VARIANT = SAMD21G18A CHIP_FAMILY = samd21 +CIRCUITPY_BUILD_EXTENSIONS = bin,uf2 + INTERNAL_FLASH_FILESYSTEM = 1 LONGINT_IMPL = NONE CIRCUITPY_FULL_BUILD = 0 diff --git a/ports/atmel-samd/boards/arduino_zero/mpconfigboard.mk b/ports/atmel-samd/boards/arduino_zero/mpconfigboard.mk index f1c3631dcb..a347b70a63 100644 --- a/ports/atmel-samd/boards/arduino_zero/mpconfigboard.mk +++ b/ports/atmel-samd/boards/arduino_zero/mpconfigboard.mk @@ -6,6 +6,8 @@ USB_MANUFACTURER = "Arduino" CHIP_VARIANT = SAMD21G18A CHIP_FAMILY = samd21 +CIRCUITPY_BUILD_EXTENSIONS = bin,uf2 + INTERNAL_FLASH_FILESYSTEM = 1 LONGINT_IMPL = NONE CIRCUITPY_FULL_BUILD = 0 diff --git a/ports/atmel-samd/boards/feather_m0_adalogger/mpconfigboard.mk b/ports/atmel-samd/boards/feather_m0_adalogger/mpconfigboard.mk index 62336ecf50..b0e01e43a5 100644 --- a/ports/atmel-samd/boards/feather_m0_adalogger/mpconfigboard.mk +++ b/ports/atmel-samd/boards/feather_m0_adalogger/mpconfigboard.mk @@ -6,6 +6,8 @@ USB_MANUFACTURER = "Adafruit Industries LLC" CHIP_VARIANT = SAMD21G18A CHIP_FAMILY = samd21 +CIRCUITPY_BUILD_EXTENSIONS = bin,uf2 + INTERNAL_FLASH_FILESYSTEM = 1 LONGINT_IMPL = NONE CIRCUITPY_FULL_BUILD = 0 diff --git a/ports/atmel-samd/boards/feather_m0_basic/mpconfigboard.mk b/ports/atmel-samd/boards/feather_m0_basic/mpconfigboard.mk index cfd1f63cb3..f54da83f11 100644 --- a/ports/atmel-samd/boards/feather_m0_basic/mpconfigboard.mk +++ b/ports/atmel-samd/boards/feather_m0_basic/mpconfigboard.mk @@ -6,6 +6,8 @@ USB_MANUFACTURER = "Adafruit Industries LLC" CHIP_VARIANT = SAMD21G18A CHIP_FAMILY = samd21 +CIRCUITPY_BUILD_EXTENSIONS = bin,uf2 + INTERNAL_FLASH_FILESYSTEM = 1 LONGINT_IMPL = NONE CIRCUITPY_FULL_BUILD = 0 diff --git a/ports/atmel-samd/boards/feather_m0_rfm69/mpconfigboard.mk b/ports/atmel-samd/boards/feather_m0_rfm69/mpconfigboard.mk index 48c0f47064..a1891f972e 100644 --- a/ports/atmel-samd/boards/feather_m0_rfm69/mpconfigboard.mk +++ b/ports/atmel-samd/boards/feather_m0_rfm69/mpconfigboard.mk @@ -6,6 +6,8 @@ USB_MANUFACTURER = "Adafruit Industries LLC" CHIP_VARIANT = SAMD21G18A CHIP_FAMILY = samd21 +CIRCUITPY_BUILD_EXTENSIONS = bin,uf2 + INTERNAL_FLASH_FILESYSTEM = 1 LONGINT_IMPL = NONE CIRCUITPY_FULL_BUILD = 0 diff --git a/ports/atmel-samd/boards/feather_m0_rfm9x/mpconfigboard.mk b/ports/atmel-samd/boards/feather_m0_rfm9x/mpconfigboard.mk index 4003dd67f0..3bc3fa3ed0 100644 --- a/ports/atmel-samd/boards/feather_m0_rfm9x/mpconfigboard.mk +++ b/ports/atmel-samd/boards/feather_m0_rfm9x/mpconfigboard.mk @@ -6,6 +6,8 @@ USB_MANUFACTURER = "Adafruit Industries LLC" CHIP_VARIANT = SAMD21G18A CHIP_FAMILY = samd21 +CIRCUITPY_BUILD_EXTENSIONS = bin,uf2 + INTERNAL_FLASH_FILESYSTEM = 1 LONGINT_IMPL = NONE CIRCUITPY_FULL_BUILD = 0 diff --git a/ports/atmel-samd/boards/pewpew_m4/mpconfigboard.mk b/ports/atmel-samd/boards/pewpew_m4/mpconfigboard.mk index cffbaf619a..06346b43de 100644 --- a/ports/atmel-samd/boards/pewpew_m4/mpconfigboard.mk +++ b/ports/atmel-samd/boards/pewpew_m4/mpconfigboard.mk @@ -33,6 +33,8 @@ CIRCUITPY_USB_CDC = 0 CIRCUITPY_USB_HID = 0 CIRCUITPY_USB_MIDI = 0 CIRCUITPY_VECTORIO = 0 +CIRCUITPY_BUSDEVICE = 0 +CIRCUITPY_BITMAPTOOLS = 0 CIRCUITPY_ANALOGIO = 1 CIRCUITPY_AUDIOIO = 1 @@ -42,6 +44,7 @@ CIRCUITPY_KEYPAD = 1 CIRCUITPY_MATH = 1 CIRCUITPY_STAGE = 1 CIRCUITPY_SYNTHIO = 1 +CIRCUITPY_ZLIB = 1 FROZEN_MPY_DIRS += $(TOP)/frozen/circuitpython-stage/pewpew_m4 CIRCUITPY_DISPLAY_FONT = $(TOP)/ports/atmel-samd/boards/ugame10/brutalist-6.bdf diff --git a/ports/atmel-samd/boards/uchip/mpconfigboard.mk b/ports/atmel-samd/boards/uchip/mpconfigboard.mk index 90b5600dcb..543007ce11 100644 --- a/ports/atmel-samd/boards/uchip/mpconfigboard.mk +++ b/ports/atmel-samd/boards/uchip/mpconfigboard.mk @@ -6,6 +6,8 @@ USB_MANUFACTURER = "Itaca Innovation" CHIP_VARIANT = SAMD21E18A CHIP_FAMILY = samd21 +CIRCUITPY_BUILD_EXTENSIONS = bin,uf2 + INTERNAL_FLASH_FILESYSTEM = 1 LONGINT_IMPL = NONE CIRCUITPY_FULL_BUILD = 0 diff --git a/ports/atmel-samd/mpconfigport.mk b/ports/atmel-samd/mpconfigport.mk index 3ea6c44049..56cde4964b 100644 --- a/ports/atmel-samd/mpconfigport.mk +++ b/ports/atmel-samd/mpconfigport.mk @@ -133,3 +133,5 @@ CIRCUITPY_RGBMATRIX ?= $(CIRCUITPY_FRAMEBUFFERIO) endif # same51 ###################################################################### + +CIRCUITPY_BUILD_EXTENSIONS ?= uf2 diff --git a/ports/broadcom/boards/raspberrypi_zero/mpconfigboard.mk b/ports/broadcom/boards/raspberrypi_zero/mpconfigboard.mk index 74f8511c2d..b6adb5d6bb 100644 --- a/ports/broadcom/boards/raspberrypi_zero/mpconfigboard.mk +++ b/ports/broadcom/boards/raspberrypi_zero/mpconfigboard.mk @@ -4,3 +4,5 @@ USB_PRODUCT = "Zero" USB_MANUFACTURER = "Raspberry Pi" CHIP_VARIANT = "bcm2835" + +CIRCUITPY_BUILD_EXTENSIONS = disk.img.zip,kernel.img diff --git a/ports/broadcom/boards/raspberrypi_zero_w/mpconfigboard.mk b/ports/broadcom/boards/raspberrypi_zero_w/mpconfigboard.mk index 24d09e0530..cd55f73ee8 100644 --- a/ports/broadcom/boards/raspberrypi_zero_w/mpconfigboard.mk +++ b/ports/broadcom/boards/raspberrypi_zero_w/mpconfigboard.mk @@ -4,3 +4,5 @@ USB_PRODUCT = "Zero W" USB_MANUFACTURER = "Raspberry Pi" CHIP_VARIANT = "bcm2835" + +CIRCUITPY_BUILD_EXTENSIONS = disk.img.zip,kernel.img diff --git a/ports/broadcom/mpconfigport.mk b/ports/broadcom/mpconfigport.mk index 7296461d1f..d0c6acf408 100644 --- a/ports/broadcom/mpconfigport.mk +++ b/ports/broadcom/mpconfigport.mk @@ -24,3 +24,5 @@ INTERNAL_FLASH_FILESYSTEM = 1 USB_NUM_ENDPOINT_PAIRS = 8 USB_HIGHSPEED = 1 + +CIRCUITPY_BUILD_EXTENSIONS ?= disk.img.zip,kernel8.img diff --git a/ports/cxd56/mpconfigport.mk b/ports/cxd56/mpconfigport.mk index 813d85d4a7..2f0cd90c7f 100644 --- a/ports/cxd56/mpconfigport.mk +++ b/ports/cxd56/mpconfigport.mk @@ -25,3 +25,5 @@ CIRCUITPY_TOUCHIO = 0 CIRCUITPY_USB_HID = 0 CIRCUITPY_USB_MIDI = 0 INTERNAL_LIBM = 1 + +CIRCUITPY_BUILD_EXTENSIONS ?= spk diff --git a/ports/espressif/boards/adafruit_feather_esp32s3_4mbflash_2mbpsram/mpconfigboard.mk b/ports/espressif/boards/adafruit_feather_esp32s3_4mbflash_2mbpsram/mpconfigboard.mk index 39804bad26..1b4c4015f5 100644 --- a/ports/espressif/boards/adafruit_feather_esp32s3_4mbflash_2mbpsram/mpconfigboard.mk +++ b/ports/espressif/boards/adafruit_feather_esp32s3_4mbflash_2mbpsram/mpconfigboard.mk @@ -16,4 +16,4 @@ CIRCUITPY_ESP_FLASH_MODE = qio CIRCUITPY_ESP_FLASH_FREQ = 40m CIRCUITPY_ESP_FLASH_SIZE = 4MB -CIRCUITPY_PS2IO = 0 +OPTIMIZATION_FLAGS = -Os diff --git a/ports/espressif/boards/adafruit_magtag_2.9_grayscale/pins.c b/ports/espressif/boards/adafruit_magtag_2.9_grayscale/pins.c index 2aa2b11b06..1df28f8e05 100644 --- a/ports/espressif/boards/adafruit_magtag_2.9_grayscale/pins.c +++ b/ports/espressif/boards/adafruit_magtag_2.9_grayscale/pins.c @@ -37,6 +37,8 @@ STATIC const mp_rom_map_elem_t board_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_BUTTON_D), MP_ROM_PTR(&pin_GPIO11) }, { MP_ROM_QSTR(MP_QSTR_D11), MP_ROM_PTR(&pin_GPIO11) }, + { MP_ROM_QSTR(MP_QSTR_BOOT0), MP_ROM_PTR(&pin_GPIO0) }, + { MP_ROM_QSTR(MP_QSTR_LIGHT), MP_ROM_PTR(&pin_GPIO3) }, { MP_ROM_QSTR(MP_QSTR_A3), MP_ROM_PTR(&pin_GPIO3) }, diff --git a/ports/espressif/boards/beetle-esp32-c3/README.md b/ports/espressif/boards/beetle-esp32-c3/README.md new file mode 100644 index 0000000000..e69de29bb2 diff --git a/ports/espressif/boards/beetle-esp32-c3/board.c b/ports/espressif/boards/beetle-esp32-c3/board.c new file mode 100644 index 0000000000..8bca964dc7 --- /dev/null +++ b/ports/espressif/boards/beetle-esp32-c3/board.c @@ -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) { +} diff --git a/ports/espressif/boards/beetle-esp32-c3/mpconfigboard.h b/ports/espressif/boards/beetle-esp32-c3/mpconfigboard.h new file mode 100644 index 0000000000..3db8a44463 --- /dev/null +++ b/ports/espressif/boards/beetle-esp32-c3/mpconfigboard.h @@ -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) diff --git a/ports/espressif/boards/beetle-esp32-c3/mpconfigboard.mk b/ports/espressif/boards/beetle-esp32-c3/mpconfigboard.mk new file mode 100644 index 0000000000..c76ee76120 --- /dev/null +++ b/ports/espressif/boards/beetle-esp32-c3/mpconfigboard.mk @@ -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 diff --git a/ports/espressif/boards/beetle-esp32-c3/pins.c b/ports/espressif/boards/beetle-esp32-c3/pins.c new file mode 100644 index 0000000000..f9060cc306 --- /dev/null +++ b/ports/espressif/boards/beetle-esp32-c3/pins.c @@ -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); diff --git a/ports/espressif/boards/beetle-esp32-c3/sdkconfig b/ports/espressif/boards/beetle-esp32-c3/sdkconfig new file mode 100644 index 0000000000..129c537108 --- /dev/null +++ b/ports/espressif/boards/beetle-esp32-c3/sdkconfig @@ -0,0 +1,7 @@ +# +# LWIP +# +CONFIG_LWIP_LOCAL_HOSTNAME="beetle-esp32-c3 +# end of LWIP + + diff --git a/ports/espressif/boards/seeed_xiao_esp32c3/board.c b/ports/espressif/boards/seeed_xiao_esp32c3/board.c new file mode 100644 index 0000000000..f5fd5702c3 --- /dev/null +++ b/ports/espressif/boards/seeed_xiao_esp32c3/board.c @@ -0,0 +1,26 @@ +#include "shared-bindings/microcontroller/Pin.h" +#include "supervisor/board.h" + +#include "components/driver/include/driver/gpio.h" + +void board_init(void) { + // Debug UART + #ifdef DEBUG + common_hal_never_reset_pin(&pin_GPIO20); + common_hal_never_reset_pin(&pin_GPIO21); + #endif +} + +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) { +} diff --git a/ports/espressif/boards/seeed_xiao_esp32c3/mpconfigboard.h b/ports/espressif/boards/seeed_xiao_esp32c3/mpconfigboard.h new file mode 100644 index 0000000000..638be9d197 --- /dev/null +++ b/ports/espressif/boards/seeed_xiao_esp32c3/mpconfigboard.h @@ -0,0 +1,14 @@ +#define MICROPY_HW_BOARD_NAME "Seeed Studio XIAO ESP32C3" +#define MICROPY_HW_MCU_NAME "ESP32-C3FN4" + +#define DEFAULT_I2C_BUS_SCL (&pin_GPIO7) +#define DEFAULT_I2C_BUS_SDA (&pin_GPIO6) + +#define DEFAULT_SPI_BUS_SCK (&pin_GPIO8) +#define DEFAULT_SPI_BUS_MOSI (&pin_GPIO10) +#define DEFAULT_SPI_BUS_MISO (&pin_GPIO9) + +#define DEFAULT_UART_BUS_RX (&pin_GPIO20) +#define DEFAULT_UART_BUS_TX (&pin_GPIO21) + +#define CIRCUITPY_ESP_USB_SERIAL_JTAG (1) diff --git a/ports/espressif/boards/seeed_xiao_esp32c3/mpconfigboard.mk b/ports/espressif/boards/seeed_xiao_esp32c3/mpconfigboard.mk new file mode 100644 index 0000000000..9e14c9ac7f --- /dev/null +++ b/ports/espressif/boards/seeed_xiao_esp32c3/mpconfigboard.mk @@ -0,0 +1,10 @@ +CIRCUITPY_CREATOR_ID = 0x000C2886 +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 diff --git a/ports/espressif/boards/seeed_xiao_esp32c3/pins.c b/ports/espressif/boards/seeed_xiao_esp32c3/pins.c new file mode 100644 index 0000000000..5fc475d564 --- /dev/null +++ b/ports/espressif/boards/seeed_xiao_esp32c3/pins.c @@ -0,0 +1,43 @@ +#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_D0), MP_ROM_PTR(&pin_GPIO2) }, + { MP_ROM_QSTR(MP_QSTR_A0), MP_ROM_PTR(&pin_GPIO2) }, + + { MP_ROM_QSTR(MP_QSTR_D1), MP_ROM_PTR(&pin_GPIO3) }, + { MP_ROM_QSTR(MP_QSTR_A1), MP_ROM_PTR(&pin_GPIO3) }, + + { MP_ROM_QSTR(MP_QSTR_D2), MP_ROM_PTR(&pin_GPIO4) }, + { MP_ROM_QSTR(MP_QSTR_A2), MP_ROM_PTR(&pin_GPIO4) }, + + { MP_ROM_QSTR(MP_QSTR_D3), MP_ROM_PTR(&pin_GPIO5) }, + { MP_ROM_QSTR(MP_QSTR_A3), MP_ROM_PTR(&pin_GPIO5) }, + + { MP_ROM_QSTR(MP_QSTR_D4), MP_ROM_PTR(&pin_GPIO6) }, + { MP_ROM_QSTR(MP_QSTR_SDA), MP_ROM_PTR(&pin_GPIO6) }, + + { MP_ROM_QSTR(MP_QSTR_D5), MP_ROM_PTR(&pin_GPIO7) }, + { MP_ROM_QSTR(MP_QSTR_SCL), MP_ROM_PTR(&pin_GPIO7) }, + + { MP_ROM_QSTR(MP_QSTR_D6), MP_ROM_PTR(&pin_GPIO21) }, + { MP_ROM_QSTR(MP_QSTR_TX), MP_ROM_PTR(&pin_GPIO21) }, + + { MP_ROM_QSTR(MP_QSTR_D7), MP_ROM_PTR(&pin_GPIO20) }, + { MP_ROM_QSTR(MP_QSTR_RX), MP_ROM_PTR(&pin_GPIO20) }, + + { MP_ROM_QSTR(MP_QSTR_D8), MP_ROM_PTR(&pin_GPIO8) }, + { MP_ROM_QSTR(MP_QSTR_SCK), MP_ROM_PTR(&pin_GPIO8) }, + + { MP_ROM_QSTR(MP_QSTR_D9), MP_ROM_PTR(&pin_GPIO9) }, + { MP_ROM_QSTR(MP_QSTR_MISO), MP_ROM_PTR(&pin_GPIO9) }, + + { MP_ROM_QSTR(MP_QSTR_D10), MP_ROM_PTR(&pin_GPIO10) }, + { MP_ROM_QSTR(MP_QSTR_MOSI), MP_ROM_PTR(&pin_GPIO10) }, + + { 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); diff --git a/ports/espressif/boards/seeed_xiao_esp32c3/sdkconfig b/ports/espressif/boards/seeed_xiao_esp32c3/sdkconfig new file mode 100644 index 0000000000..b2c9bc0fe6 --- /dev/null +++ b/ports/espressif/boards/seeed_xiao_esp32c3/sdkconfig @@ -0,0 +1,5 @@ +# +# LWIP +# +CONFIG_LWIP_LOCAL_HOSTNAME="seeed-xiao-esp32c3" +# end of LWIP diff --git a/ports/espressif/common-hal/mdns/Server.c b/ports/espressif/common-hal/mdns/Server.c index c6c2a748a9..d657a84eb7 100644 --- a/ports/espressif/common-hal/mdns/Server.c +++ b/ports/espressif/common-hal/mdns/Server.c @@ -204,5 +204,9 @@ mp_obj_t common_hal_mdns_server_find(mdns_server_obj_t *self, const char *servic } void common_hal_mdns_server_advertise_service(mdns_server_obj_t *self, const char *service_type, const char *protocol, mp_int_t port) { - mdns_service_add(NULL, service_type, protocol, port, NULL, 0); + if (mdns_service_exists(service_type, protocol, NULL)) { + mdns_service_port_set(service_type, protocol, port); + } else { + mdns_service_add(NULL, service_type, protocol, port, NULL, 0); + } } diff --git a/ports/espressif/common-hal/socketpool/Socket.c b/ports/espressif/common-hal/socketpool/Socket.c index 45d5f1fea0..f6025d329c 100644 --- a/ports/espressif/common-hal/socketpool/Socket.c +++ b/ports/espressif/common-hal/socketpool/Socket.c @@ -60,32 +60,35 @@ STATIC void socket_select_task(void *arg) { 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) { + int sockfd = open_socket_fds[i]; + if (sockfd < 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); + max_fd = MAX(max_fd, sockfd); + FD_SET(sockfd, &readfds); + FD_SET(sockfd, &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; - } - } + // Check for bad file descriptor and queue up the background task before + // circling around. + if (num_triggered == -1 && errno == EBADF) { + // One for the change fd and one for the closed socket. + num_triggered = 2; + } + // Try and find the bad file and remove it from monitoring. + for (size_t i = 0; i < MP_ARRAY_SIZE(open_socket_fds); i++) { + int sockfd = open_socket_fds[i]; + if (sockfd < 0) { + continue; + } + 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; + // Raise num_triggered so that we skip the assert and queue the background task. + num_triggered = 2; } } assert(num_triggered >= 0); @@ -117,13 +120,13 @@ void socket_user_reset(void) { 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. + // Run this at the same priority as CP so that the web workflow background task can be + // queued while CP is running. Both tasks can still sleep and, therefore, sleep overall. (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). + uxTaskPriorityGet(NULL), socket_select_stack, &socket_select_task_handle, xPortGetCoreID()); diff --git a/ports/espressif/mpconfigport.mk b/ports/espressif/mpconfigport.mk index 457dd21a3d..f390cbb21a 100644 --- a/ports/espressif/mpconfigport.mk +++ b/ports/espressif/mpconfigport.mk @@ -40,6 +40,7 @@ CIRCUITPY_PARALLELDISPLAY = 0 # Protomatter needs to support ESP32. CIRCUITPY_RGBMATRIX = 0 CIRCUITPY_USB = 0 +CIRCUITPY_BUILD_EXTENSIONS ?= bin else ifeq ($(IDF_TARGET),esp32c3) CIRCUITPY_AESIO = 0 @@ -57,17 +58,20 @@ CIRCUITPY_ROTARYIO = 0 CIRCUITPY_TOUCHIO ?= 1 CIRCUITPY_TOUCHIO_USE_NATIVE = 0 CIRCUITPY_USB = 0 +CIRCUITPY_BUILD_EXTENSIONS ?= bin else ifeq ($(IDF_TARGET),esp32s3) CIRCUITPY_BLEIO = 1 CIRCUITPY_BLEIO_HCI = 0 CIRCUITPY_IMAGECAPTURE = 0 CIRCUITPY_PARALLELDISPLAY = 0 +CIRCUITPY_BUILD_EXTENSIONS ?= bin,uf2 else ifeq ($(IDF_TARGET),esp32s2) # No BLE on S2 CIRCUITPY_BLEIO = 0 CIRCUITPY_BLEIO_HCI = 0 +CIRCUITPY_BUILD_EXTENSIONS ?= bin,uf2 endif # From ESP32-S2/S3 Technical Reference Manual: diff --git a/ports/espressif/supervisor/usb_serial_jtag.c b/ports/espressif/supervisor/usb_serial_jtag.c index 064d7d668c..33f0ec3a8e 100644 --- a/ports/espressif/supervisor/usb_serial_jtag.c +++ b/ports/espressif/supervisor/usb_serial_jtag.c @@ -98,14 +98,23 @@ bool usb_serial_jtag_bytes_available(void) { } void usb_serial_jtag_write(const char *text, uint32_t length) { - if (USB_SERIAL_JTAG.fram_num.sof_frame_index > 0) { - size_t total_written = 0; - uint32_t start_time = supervisor_ticks_ms32(); - // Time out after 5 milliseconds in case usb isn't actually reading CDC. - while (total_written < length && start_time - supervisor_ticks_ms32() < 5) { - total_written += usb_serial_jtag_ll_write_txfifo((const uint8_t *)(text + total_written), length - total_written); - RUN_BACKGROUND_TASKS; - } - usb_serial_jtag_ll_txfifo_flush(); + if (!usb_serial_jtag_connected()) { + return; } + size_t total_written = 0; + while (total_written < length) { + uint32_t start_time = supervisor_ticks_ms32(); + // Wait until we can write to the FIFO again. If it takes too long, then + // assume we're disconnected. + while (!usb_serial_jtag_ll_txfifo_writable()) { + uint32_t now = supervisor_ticks_ms32(); + if (now - start_time > 200) { + connected = false; + return; + } + } + total_written += usb_serial_jtag_ll_write_txfifo((const uint8_t *)(text + total_written), length - total_written); + RUN_BACKGROUND_TASKS; + } + usb_serial_jtag_ll_txfifo_flush(); } diff --git a/ports/litex/mpconfigport.mk b/ports/litex/mpconfigport.mk index 57f5113b69..2e342db47d 100644 --- a/ports/litex/mpconfigport.mk +++ b/ports/litex/mpconfigport.mk @@ -29,3 +29,5 @@ CIRCUITPY_SDCARDIO = 0 # Enable USB support CIRCUITPY_USB_HID = 1 CIRCUITPY_USB_MIDI = 1 + +CIRCUITPY_BUILD_EXTENSIONS ?= dfu diff --git a/ports/mimxrt10xx/mpconfigport.mk b/ports/mimxrt10xx/mpconfigport.mk index e7e7abe141..5ffec18cfb 100644 --- a/ports/mimxrt10xx/mpconfigport.mk +++ b/ports/mimxrt10xx/mpconfigport.mk @@ -21,3 +21,5 @@ CIRCUITPY_PULSEIO = 0 CIRCUITPY_ROTARYIO = 0 CIRCUITPY_USB_MIDI = 1 LONGINT_IMPL = MPZ + +CIRCUITPY_BUILD_EXTENSIONS ?= hex,uf2 diff --git a/ports/nrf/boards/challenger_840/mpconfigboard.mk b/ports/nrf/boards/challenger_840/mpconfigboard.mk index 61af9ac029..ddb55ce705 100644 --- a/ports/nrf/boards/challenger_840/mpconfigboard.mk +++ b/ports/nrf/boards/challenger_840/mpconfigboard.mk @@ -6,4 +6,4 @@ USB_MANUFACTURER = "Invector Labs AB" MCU_CHIP = nrf52840 SPI_FLASH_FILESYSTEM = 1 -EXTERNAL_FLASH_DEVICES = "W25Q16JVxQ,W25Q32FV" +EXTERNAL_FLASH_DEVICES = "W25Q16JVxQ,W25Q32FV,W25Q64FV" diff --git a/ports/nrf/boards/electronut_labs_blip/mpconfigboard.mk b/ports/nrf/boards/electronut_labs_blip/mpconfigboard.mk index 2b46f4397a..0e3b1b9048 100644 --- a/ports/nrf/boards/electronut_labs_blip/mpconfigboard.mk +++ b/ports/nrf/boards/electronut_labs_blip/mpconfigboard.mk @@ -5,6 +5,8 @@ USB_MANUFACTURER = "Electronut Labs" MCU_CHIP = nrf52840 +CIRCUITPY_BUILD_EXTENSIONS = hex + INTERNAL_FLASH_FILESYSTEM = 1 CIRCUITPY_AUDIOIO = 0 CIRCUITPY_DISPLAYIO = 1 diff --git a/ports/nrf/boards/makerdiary_nrf52840_mdk/mpconfigboard.mk b/ports/nrf/boards/makerdiary_nrf52840_mdk/mpconfigboard.mk index 7da9ed1896..887bf0a7da 100644 --- a/ports/nrf/boards/makerdiary_nrf52840_mdk/mpconfigboard.mk +++ b/ports/nrf/boards/makerdiary_nrf52840_mdk/mpconfigboard.mk @@ -5,5 +5,7 @@ USB_MANUFACTURER = "makerdiary" MCU_CHIP = nrf52840 +CIRCUITPY_BUILD_EXTENSIONS = hex + QSPI_FLASH_FILESYSTEM = 1 EXTERNAL_FLASH_DEVICES = "MX25R6435F" diff --git a/ports/nrf/boards/makerdiary_nrf52840_mdk_usb_dongle/mpconfigboard.mk b/ports/nrf/boards/makerdiary_nrf52840_mdk_usb_dongle/mpconfigboard.mk index c4fa121744..1a650d5d4d 100644 --- a/ports/nrf/boards/makerdiary_nrf52840_mdk_usb_dongle/mpconfigboard.mk +++ b/ports/nrf/boards/makerdiary_nrf52840_mdk_usb_dongle/mpconfigboard.mk @@ -5,4 +5,6 @@ USB_MANUFACTURER = "makerdiary" MCU_CHIP = nrf52840 +CIRCUITPY_BUILD_EXTENSIONS = hex,uf2 + INTERNAL_FLASH_FILESYSTEM = 1 diff --git a/ports/nrf/boards/microbit_v2/mpconfigboard.mk b/ports/nrf/boards/microbit_v2/mpconfigboard.mk index 78e76d3b53..d0430ea403 100644 --- a/ports/nrf/boards/microbit_v2/mpconfigboard.mk +++ b/ports/nrf/boards/microbit_v2/mpconfigboard.mk @@ -3,6 +3,8 @@ CIRCUITPY_CREATION_ID = 0x80D8 MCU_CHIP = nrf52833 +CIRCUITPY_BUILD_EXTENSIONS = combined.hex + INTERNAL_FLASH_FILESYSTEM = 1 # USB pins aren't used. diff --git a/ports/nrf/boards/pca10056/mpconfigboard.mk b/ports/nrf/boards/pca10056/mpconfigboard.mk index 48f68a30ae..b30e6ee7a2 100644 --- a/ports/nrf/boards/pca10056/mpconfigboard.mk +++ b/ports/nrf/boards/pca10056/mpconfigboard.mk @@ -5,5 +5,7 @@ USB_MANUFACTURER = "Nordic Semiconductor" MCU_CHIP = nrf52840 +CIRCUITPY_BUILD_EXTENSIONS = bin,uf2 + QSPI_FLASH_FILESYSTEM = 1 EXTERNAL_FLASH_DEVICES = "MX25R6435F" diff --git a/ports/nrf/boards/pca10059/mpconfigboard.mk b/ports/nrf/boards/pca10059/mpconfigboard.mk index 9dc3cc71ed..fe702a50c9 100644 --- a/ports/nrf/boards/pca10059/mpconfigboard.mk +++ b/ports/nrf/boards/pca10059/mpconfigboard.mk @@ -5,4 +5,6 @@ USB_MANUFACTURER = "Nordic Semiconductor" MCU_CHIP = nrf52840 +CIRCUITPY_BUILD_EXTENSIONS = bin,uf2 + INTERNAL_FLASH_FILESYSTEM = 1 diff --git a/ports/nrf/mpconfigport.mk b/ports/nrf/mpconfigport.mk index 6aff88b289..c1d3dce6e5 100644 --- a/ports/nrf/mpconfigport.mk +++ b/ports/nrf/mpconfigport.mk @@ -4,6 +4,8 @@ LD_TEMPLATE_FILE = boards/common.template.ld INTERNAL_LIBM = 1 +CIRCUITPY_BUILD_EXTENSIONS ?= uf2 + # Number of USB endpoint pairs. USB_NUM_ENDPOINT_PAIRS = 8 diff --git a/ports/raspberrypi/boards/bwshockley_figpi/board.c b/ports/raspberrypi/boards/bwshockley_figpi/board.c new file mode 100644 index 0000000000..de6e424ed9 --- /dev/null +++ b/ports/raspberrypi/boards/bwshockley_figpi/board.c @@ -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) { +} diff --git a/ports/raspberrypi/boards/bwshockley_figpi/mpconfigboard.h b/ports/raspberrypi/boards/bwshockley_figpi/mpconfigboard.h new file mode 100644 index 0000000000..fbd03379dd --- /dev/null +++ b/ports/raspberrypi/boards/bwshockley_figpi/mpconfigboard.h @@ -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}} diff --git a/ports/raspberrypi/boards/bwshockley_figpi/mpconfigboard.mk b/ports/raspberrypi/boards/bwshockley_figpi/mpconfigboard.mk new file mode 100644 index 0000000000..95bd9715d6 --- /dev/null +++ b/ports/raspberrypi/boards/bwshockley_figpi/mpconfigboard.mk @@ -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" diff --git a/ports/raspberrypi/boards/bwshockley_figpi/pico-sdk-configboard.h b/ports/raspberrypi/boards/bwshockley_figpi/pico-sdk-configboard.h new file mode 100644 index 0000000000..a41131dd22 --- /dev/null +++ b/ports/raspberrypi/boards/bwshockley_figpi/pico-sdk-configboard.h @@ -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 diff --git a/ports/raspberrypi/boards/bwshockley_figpi/pins.c b/ports/raspberrypi/boards/bwshockley_figpi/pins.c new file mode 100644 index 0000000000..1bec6fd91b --- /dev/null +++ b/ports/raspberrypi/boards/bwshockley_figpi/pins.c @@ -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); diff --git a/ports/raspberrypi/boards/pimoroni_interstate75/pins.c b/ports/raspberrypi/boards/pimoroni_interstate75/pins.c index 2460ebc76a..801a418015 100644 --- a/ports/raspberrypi/boards/pimoroni_interstate75/pins.c +++ b/ports/raspberrypi/boards/pimoroni_interstate75/pins.c @@ -22,6 +22,7 @@ STATIC const mp_rom_map_elem_t board_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_SW_A), MP_ROM_PTR(&pin_GPIO14) }, + { MP_ROM_QSTR(MP_QSTR_LED), MP_ROM_PTR(&pin_GPIO16) }, { MP_ROM_QSTR(MP_QSTR_LED_R), MP_ROM_PTR(&pin_GPIO16) }, { MP_ROM_QSTR(MP_QSTR_LED_G), MP_ROM_PTR(&pin_GPIO17) }, { MP_ROM_QSTR(MP_QSTR_LED_B), MP_ROM_PTR(&pin_GPIO18) }, diff --git a/ports/raspberrypi/boards/wiznet_w5500_evb_pico/board.c b/ports/raspberrypi/boards/wiznet_w5500_evb_pico/board.c new file mode 100644 index 0000000000..de6e424ed9 --- /dev/null +++ b/ports/raspberrypi/boards/wiznet_w5500_evb_pico/board.c @@ -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) { +} diff --git a/ports/raspberrypi/boards/wiznet_w5500_evb_pico/mpconfigboard.h b/ports/raspberrypi/boards/wiznet_w5500_evb_pico/mpconfigboard.h new file mode 100644 index 0000000000..00faa83742 --- /dev/null +++ b/ports/raspberrypi/boards/wiznet_w5500_evb_pico/mpconfigboard.h @@ -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) diff --git a/ports/raspberrypi/boards/wiznet_w5500_evb_pico/mpconfigboard.mk b/ports/raspberrypi/boards/wiznet_w5500_evb_pico/mpconfigboard.mk new file mode 100644 index 0000000000..3789a76e0b --- /dev/null +++ b/ports/raspberrypi/boards/wiznet_w5500_evb_pico/mpconfigboard.mk @@ -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 diff --git a/ports/raspberrypi/boards/wiznet_w5500_evb_pico/pico-sdk-configboard.h b/ports/raspberrypi/boards/wiznet_w5500_evb_pico/pico-sdk-configboard.h new file mode 100644 index 0000000000..36da55d457 --- /dev/null +++ b/ports/raspberrypi/boards/wiznet_w5500_evb_pico/pico-sdk-configboard.h @@ -0,0 +1 @@ +// Put board-specific pico-sdk definitions here. This file must exist. diff --git a/ports/raspberrypi/boards/wiznet_w5500_evb_pico/pins.c b/ports/raspberrypi/boards/wiznet_w5500_evb_pico/pins.c new file mode 100644 index 0000000000..87ff27fa46 --- /dev/null +++ b/ports/raspberrypi/boards/wiznet_w5500_evb_pico/pins.c @@ -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); diff --git a/ports/raspberrypi/mpconfigport.mk b/ports/raspberrypi/mpconfigport.mk index 32666ed9ea..65e39ee99d 100644 --- a/ports/raspberrypi/mpconfigport.mk +++ b/ports/raspberrypi/mpconfigport.mk @@ -36,6 +36,8 @@ CIRCUITPY_AUDIOMIXER = 1 INTERNAL_LIBM = 1 +CIRCUITPY_BUILD_EXTENSIONS ?= uf2 + # Number of USB endpoint pairs. USB_NUM_ENDPOINT_PAIRS = 8 diff --git a/ports/stm/boards/meowbit_v121/mpconfigboard.mk b/ports/stm/boards/meowbit_v121/mpconfigboard.mk index 77b046ada7..3bbfb7eec8 100644 --- a/ports/stm/boards/meowbit_v121/mpconfigboard.mk +++ b/ports/stm/boards/meowbit_v121/mpconfigboard.mk @@ -13,6 +13,8 @@ MCU_SERIES = F4 MCU_VARIANT = STM32F401xE MCU_PACKAGE = LQFP64 +CIRCUITPY_BUILD_EXTENSIONS = uf2 + OPTIMIZATION_FLAGS = -Os LD_COMMON = boards/common_default.ld diff --git a/ports/stm/boards/sparkfun_stm32_thing_plus/mpconfigboard.mk b/ports/stm/boards/sparkfun_stm32_thing_plus/mpconfigboard.mk index 62d0136be5..24505eb23d 100644 --- a/ports/stm/boards/sparkfun_stm32_thing_plus/mpconfigboard.mk +++ b/ports/stm/boards/sparkfun_stm32_thing_plus/mpconfigboard.mk @@ -19,3 +19,5 @@ LD_BOOT = boards/STM32F405_boot.ld UF2_OFFSET = 0x8010000 CIRCUITPY_RGBMATRIX ?= 1 + +CIRCUITPY_BUILD_EXTENSIONS = bin,uf2 diff --git a/ports/stm/boards/swan_r5/mpconfigboard.mk b/ports/stm/boards/swan_r5/mpconfigboard.mk index 5d51c9406b..ee17f65f7c 100644 --- a/ports/stm/boards/swan_r5/mpconfigboard.mk +++ b/ports/stm/boards/swan_r5/mpconfigboard.mk @@ -71,3 +71,5 @@ CIRCUITPY_BUSDEVICE = 0 CIRCUITPY_KEYPAD = 1 CIRCUITPY_RGBMATRIX = 0 CIRCUITPY_RTC = 1 + +CIRCUITPY_BUILD_EXTENSIONS = bin,uf2 diff --git a/ports/stm/mpconfigport.mk b/ports/stm/mpconfigport.mk index dd83e0d7bc..9705dcd0a0 100644 --- a/ports/stm/mpconfigport.mk +++ b/ports/stm/mpconfigport.mk @@ -88,3 +88,4 @@ ifeq ($(MCU_SERIES),L4) endif CIRCUITPY_PARALLELDISPLAY := 0 +CIRCUITPY_BUILD_EXTENSIONS ?= bin diff --git a/requirements-dev.txt b/requirements-dev.txt index 3b4411bd3a..f65c13fa69 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -17,6 +17,7 @@ polib # For pre-commit pyyaml black +pre-commit # for combining the Nordic SoftDevice with CircuitPython intelhex diff --git a/shared-bindings/mdns/Server.c b/shared-bindings/mdns/Server.c index 97574ff0e2..bcf761d72a 100644 --- a/shared-bindings/mdns/Server.c +++ b/shared-bindings/mdns/Server.c @@ -161,6 +161,9 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_KW(mdns_server_find_obj, 1, _mdns_server_find); //| def advertise_service(self, *, service_type: str, protocol: str, port: int) -> None: //| """Respond to queries for the given service with the given port. //| +//| ``service_type`` and ``protocol`` can only occur on one port. Any call after the first +//| will update the entry's port. +//| //| :param str service_type: The service type such as "_http" //| :param str protocol: The service protocol such as "_tcp" //| :param int port: The port used by the service""" diff --git a/shared-bindings/support_matrix.rst b/shared-bindings/support_matrix.rst index e007e27b47..c54bfa94e1 100644 --- a/shared-bindings/support_matrix.rst +++ b/shared-bindings/support_matrix.rst @@ -21,9 +21,9 @@ capable board, as well as each :term:`frozen module` included on it. {% for key, value in support_matrix|dictsort %} {{ '.. _' ~ key|replace(" ", "-") ~ ':' }} * - {{ key }} - - {{ ':py:mod:`' ~ value[0]|join("`, :py:mod:`") ~ '`' }} + - {{ ':py:mod:`' ~ value.modules|join("`, :py:mod:`") ~ '`' }} - {% for module in value[1] %}\ + {% for module in value.frozen_libraries %}\ {% if loop.index == 1 %}**Frozen Modules:** {% endif %}\ {% if loop.index > 1 %}, {% endif %}\ {% if module[1] %}{{ '`' ~ module[0] ~ ' <' ~ module[1] ~ '>`__' }}\ diff --git a/supervisor/shared/web_workflow/static/welcome.js b/supervisor/shared/web_workflow/static/welcome.js index 79efb7e9a8..d53950d37c 100644 --- a/supervisor/shared/web_workflow/static/welcome.js +++ b/supervisor/shared/web_workflow/static/welcome.js @@ -44,7 +44,7 @@ async function find_devices() { li.appendChild(a); var port = ""; if (device.port != 80) { - port = ":" + version_info.port; + port = ":" + device.port; } var server; if (mdns_works) { diff --git a/supervisor/shared/web_workflow/web_workflow.c b/supervisor/shared/web_workflow/web_workflow.c index 81730c92d0..bd7b150765 100644 --- a/supervisor/shared/web_workflow/web_workflow.c +++ b/supervisor/shared/web_workflow/web_workflow.c @@ -98,6 +98,7 @@ typedef struct { static wifi_radio_error_t wifi_status = WIFI_RADIO_ERROR_NONE; static mdns_server_obj_t mdns; +static uint32_t web_api_port = 80; static socketpool_socketpool_obj_t pool; static socketpool_socket_obj_t listening; @@ -189,6 +190,9 @@ void supervisor_web_workflow_status(void) { } mp_printf(&mp_plat_print, "%s", _our_ip_encoded); + if (web_api_port != 80) { + mp_printf(&mp_plat_print, ":%d", web_api_port); + } // TODO: Use these unicode to show signal strength: ▂▄▆█ } } else { @@ -199,11 +203,6 @@ void supervisor_web_workflow_status(void) { void supervisor_start_web_workflow(void) { #if CIRCUITPY_WEB_WORKFLOW && CIRCUITPY_WIFI - if (common_hal_wifi_radio_get_enabled(&common_hal_wifi_radio_obj) && - wifi_radio_get_ipv4_address(&common_hal_wifi_radio_obj) != 0) { - // Already started. - return; - } char ssid[33]; char password[64]; @@ -218,8 +217,10 @@ void supervisor_start_web_workflow(void) { password_len <= 0 || (size_t)password_len >= sizeof(password)) { return; } - common_hal_wifi_init(false); - common_hal_wifi_radio_set_enabled(&common_hal_wifi_radio_obj, true); + if (!common_hal_wifi_radio_get_enabled(&common_hal_wifi_radio_obj)) { + common_hal_wifi_init(false); + common_hal_wifi_radio_set_enabled(&common_hal_wifi_radio_obj, true); + } // TODO: Do our own scan so that we can find the channel we want before calling connect. // Otherwise, connect will do a full slow scan to pick the best AP. @@ -227,6 +228,9 @@ void supervisor_start_web_workflow(void) { // NUL terminate the strings because dotenv doesn't. ssid[ssid_len] = '\0'; password[password_len] = '\0'; + // We can all connect again because it will return early if we're already connected to the + // network. If we are connected to a different network, then it will disconnect before + // attempting to connect to the given network. wifi_status = common_hal_wifi_radio_connect( &common_hal_wifi_radio_obj, (uint8_t *)ssid, ssid_len, (uint8_t *)password, password_len, 0, 0.1, NULL, 0); @@ -236,21 +240,47 @@ void supervisor_start_web_workflow(void) { return; } - mdns_server_construct(&mdns, true); - common_hal_mdns_server_set_instance_name(&mdns, MICROPY_HW_BOARD_NAME); - common_hal_mdns_server_advertise_service(&mdns, "_circuitpython", "_tcp", 80); + char port_encoded[6]; + size_t port_len = 0; + size_t new_port = web_api_port; + #if CIRCUITPY_DOTENV + port_len = dotenv_get_key("/.env", "CIRCUITPY_WEB_API_PORT", port_encoded, sizeof(port_encoded) - 1); + #endif + if (0 < port_len && port_len < sizeof(port_encoded)) { + port_encoded[port_len] = '\0'; + new_port = strtoul(port_encoded, NULL, 10); + } - pool.base.type = &socketpool_socketpool_type; - common_hal_socketpool_socketpool_construct(&pool, &common_hal_wifi_radio_obj); + bool first_start = mdns.base.type != &mdns_server_type; + bool port_changed = new_port != web_api_port; - ESP_LOGI(TAG, "Starting web workflow"); - listening.base.type = &socketpool_socket_type; - socketpool_socket(&pool, SOCKETPOOL_AF_INET, SOCKETPOOL_SOCK_STREAM, &listening); - common_hal_socketpool_socket_settimeout(&listening, 0); - // Bind to any ip. - // TODO: Make this port .env configurable. - common_hal_socketpool_socket_bind(&listening, "", 0, 80); - common_hal_socketpool_socket_listen(&listening, 1); + if (first_start) { + ESP_LOGI(TAG, "Starting web workflow"); + mdns_server_construct(&mdns, true); + mdns.base.type = &mdns_server_type; + common_hal_mdns_server_set_instance_name(&mdns, MICROPY_HW_BOARD_NAME); + pool.base.type = &socketpool_socketpool_type; + common_hal_socketpool_socketpool_construct(&pool, &common_hal_wifi_radio_obj); + + listening.base.type = &socketpool_socket_type; + active.base.type = &socketpool_socket_type; + active.num = -1; + active.connected = false; + + websocket_init(); + } + if (port_changed) { + common_hal_socketpool_socket_close(&listening); + } + if (first_start || port_changed) { + web_api_port = new_port; + common_hal_mdns_server_advertise_service(&mdns, "_circuitpython", "_tcp", web_api_port); + socketpool_socket(&pool, SOCKETPOOL_AF_INET, SOCKETPOOL_SOCK_STREAM, &listening); + common_hal_socketpool_socket_settimeout(&listening, 0); + // Bind to any ip. + common_hal_socketpool_socket_bind(&listening, "", 0, web_api_port); + common_hal_socketpool_socket_listen(&listening, 1); + } mp_int_t api_password_len = dotenv_get_key("/.env", "CIRCUITPY_WEB_API_PASSWORD", _api_password + 1, sizeof(_api_password) - 2); if (api_password_len > 0) { @@ -259,12 +289,6 @@ void supervisor_start_web_workflow(void) { _base64_in_place(_api_password, api_password_len + 1, sizeof(_api_password)); } - active.base.type = &socketpool_socket_type; - active.num = -1; - active.connected = false; - - websocket_init(); - // TODO: // GET /cp/serial.txt // - Most recent 1k of serial output. @@ -283,6 +307,10 @@ static void _send_raw(socketpool_socket_obj_t *socket, const uint8_t *buf, int l } } +STATIC void _print_raw(void *env, const char *str, size_t len) { + _send_raw((socketpool_socket_obj_t *)env, (const uint8_t *)str, (size_t)len); +} + static void _send_str(socketpool_socket_obj_t *socket, const char *str) { _send_raw(socket, (const uint8_t *)str, strlen(str)); } @@ -301,14 +329,19 @@ static void _send_strs(socketpool_socket_obj_t *socket, ...) { } static void _send_chunk(socketpool_socket_obj_t *socket, const char *chunk) { - char encoded_len[sizeof(size_t) * 2 + 1]; - int len = snprintf(encoded_len, sizeof(encoded_len), "%X", strlen(chunk)); - _send_raw(socket, (const uint8_t *)encoded_len, len); - _send_raw(socket, (const uint8_t *)"\r\n", 2); + mp_print_t _socket_print = {socket, _print_raw}; + mp_printf(&_socket_print, "%X\r\n", strlen(chunk)); _send_raw(socket, (const uint8_t *)chunk, strlen(chunk)); _send_raw(socket, (const uint8_t *)"\r\n", 2); } +STATIC void _print_chunk(void *env, const char *str, size_t len) { + mp_print_t _socket_print = {env, _print_raw}; + mp_printf(&_socket_print, "%X\r\n", len); + _send_raw((socketpool_socket_obj_t *)env, (const uint8_t *)str, len); + _send_raw((socketpool_socket_obj_t *)env, (const uint8_t *)"\r\n", 2); +} + // A bit of a misnomer because it sends all arguments as one chunk. // The last argument must be NULL! Otherwise, it won't stop. static void _send_chunks(socketpool_socket_obj_t *socket, ...) { @@ -326,9 +359,9 @@ static void _send_chunks(socketpool_socket_obj_t *socket, ...) { } va_end(strs_to_count); - char encoded_len[sizeof(size_t) * 2 + 1]; - snprintf(encoded_len, sizeof(encoded_len), "%X", chunk_len); - _send_strs(socket, encoded_len, "\r\n", NULL); + + mp_print_t _socket_print = {socket, _print_raw}; + mp_printf(&_socket_print, "%X\r\n", chunk_len); str = va_arg(strs_to_send, const char *); while (str != NULL) { @@ -350,38 +383,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; } } @@ -529,7 +564,12 @@ static void _reply_redirect(socketpool_socket_obj_t *socket, _request *request, _send_str(socket, "http"); } - _send_strs(socket, "://", hostname, ".local", path, "\r\n", NULL); + _send_strs(socket, "://", hostname, ".local", NULL); + if (web_api_port != 80) { + mp_print_t _socket_print = {socket, _print_raw}; + mp_printf(&_socket_print, ":%d", web_api_port); + } + _send_strs(socket, path, "\r\n", NULL); _cors_header(socket, request); _send_str(socket, "\r\n"); } @@ -538,6 +578,7 @@ static void _reply_directory_json(socketpool_socket_obj_t *socket, _request *req socketpool_socket_send(socket, (const uint8_t *)OK_JSON, strlen(OK_JSON)); _cors_header(socket, request); _send_str(socket, "\r\n"); + mp_print_t _socket_print = {socket, _print_chunk}; _send_chunk(socket, "["); bool first = true; @@ -558,7 +599,7 @@ static void _reply_directory_json(socketpool_socket_obj_t *socket, _request *req } // We use nanoseconds past Jan 1, 1970 for consistency with BLE API and // LittleFS. - _send_chunk(socket, ", \"modified_ns\": "); + _send_chunk(socket, ", "); uint64_t truncated_time = timeutils_mktime(1980 + (file_info.fdate >> 9), (file_info.fdate >> 5) & 0xf, @@ -567,15 +608,17 @@ static void _reply_directory_json(socketpool_socket_obj_t *socket, _request *req (file_info.ftime >> 5) & 0x1f, (file_info.ftime & 0x1f) * 2) * 1000000000ULL; - char encoded_number[32]; - snprintf(encoded_number, sizeof(encoded_number), "%lld", truncated_time); - _send_chunks(socket, encoded_number, ", \"file_size\": ", NULL); + // Use snprintf because mp_printf doesn't support 64 bit numbers by + // default. + char encoded_time[32]; + snprintf(encoded_time, sizeof(encoded_time), "%llu", truncated_time); + mp_printf(&_socket_print, "\"modified_ns\": %s, ", encoded_time); size_t file_size = 0; if ((file_info.fattrib & AM_DIR) == 0) { file_size = file_info.fsize; } - snprintf(encoded_number, sizeof(encoded_number), "%d", file_size); - _send_chunks(socket, encoded_number, "}", NULL); + mp_printf(&_socket_print, "\"file_size\": %d }", file_size); + first = false; res = f_readdir(dir, &file_info); } @@ -585,12 +628,10 @@ static void _reply_directory_json(socketpool_socket_obj_t *socket, _request *req static void _reply_with_file(socketpool_socket_obj_t *socket, _request *request, const char *filename, FIL *active_file) { uint32_t total_length = f_size(active_file); - char encoded_len[10]; - snprintf(encoded_len, sizeof(encoded_len), "%d", total_length); - _send_strs(socket, - "HTTP/1.1 200 OK\r\n", - "Content-Length: ", encoded_len, "\r\n", NULL); + _send_str(socket, "HTTP/1.1 200 OK\r\n"); + mp_print_t _socket_print = {socket, _print_raw}; + mp_printf(&_socket_print, "Content-Length: %d\r\n", total_length); // TODO: Make this a table to save space. if (_endswith(filename, ".txt") || _endswith(filename, ".py")) { _send_str(socket, "Content-Type: text/plain\r\n"); @@ -638,27 +679,23 @@ static void _reply_with_devices_json(socketpool_socket_obj_t *socket, _request * socketpool_socket_send(socket, (const uint8_t *)OK_JSON, strlen(OK_JSON)); _cors_header(socket, request); _send_str(socket, "\r\n"); - char total_encoded[4]; - snprintf(total_encoded, sizeof(total_encoded), "%d", total_results); - _send_chunks(socket, "{\"total\": ", total_encoded, ", \"devices\": [", NULL); + mp_print_t _socket_print = {socket, _print_chunk}; + + mp_printf(&_socket_print, "{\"total\": %d, \"devices\": [", total_results); for (size_t i = 0; i < count; i++) { if (i > 0) { _send_chunk(socket, ","); } const char *hostname = common_hal_mdns_remoteservice_get_hostname(&found_devices[i]); const char *instance_name = common_hal_mdns_remoteservice_get_instance_name(&found_devices[i]); - char port_encoded[4]; int port = common_hal_mdns_remoteservice_get_port(&found_devices[i]); - snprintf(port_encoded, sizeof(port_encoded), "%d", port); - char ip_encoded[4 * 4]; uint32_t ipv4_address = mdns_remoteservice_get_ipv4_address(&found_devices[i]); uint8_t *octets = (uint8_t *)&ipv4_address; - snprintf(ip_encoded, sizeof(ip_encoded), "%d.%d.%d.%d", octets[0], octets[1], octets[2], octets[3]); - _send_chunks(socket, - "{\"hostname\": \"", hostname, "\", ", - "\"instance_name\": \"", instance_name, "\", ", - "\"port\": ", port_encoded, ", ", - "\"ip\": \"", ip_encoded, "\"}", NULL); + mp_printf(&_socket_print, + "{\"hostname\": \"%s\", " + "\"instance_name\": \"%s\", " + "\"port\": %d, " + "\"ip\": \"%d.%d.%d.%d\"}", hostname, instance_name, port, octets[0], octets[1], octets[2], octets[3]); common_hal_mdns_remoteservice_deinit(&found_devices[i]); } _send_chunk(socket, "]}"); @@ -670,24 +707,22 @@ static void _reply_with_version_json(socketpool_socket_obj_t *socket, _request * _send_str(socket, OK_JSON); _cors_header(socket, request); _send_str(socket, "\r\n"); - char encoded_creator_id[11]; // 2 ** 32 is 10 decimal digits plus one for \0 - snprintf(encoded_creator_id, sizeof(encoded_creator_id), "%u", CIRCUITPY_CREATOR_ID); - char encoded_creation_id[11]; // 2 ** 32 is 10 decimal digits plus one for \0 - snprintf(encoded_creation_id, sizeof(encoded_creation_id), "%u", CIRCUITPY_CREATION_ID); + mp_print_t _socket_print = {socket, _print_chunk}; + const char *hostname = common_hal_mdns_server_get_hostname(&mdns); - _send_chunks(socket, - "{\"web_api_version\": 1, ", - "\"version\": \"", MICROPY_GIT_TAG, "\", ", - "\"build_date\": \"", MICROPY_BUILD_DATE, "\", ", - "\"board_name\": \"", MICROPY_HW_BOARD_NAME, "\", ", - "\"mcu_name\": \"", MICROPY_HW_MCU_NAME, "\", ", - "\"board_id\": \"", CIRCUITPY_BOARD_ID, "\", ", - "\"creator_id\": ", encoded_creator_id, ", ", - "\"creation_id\": ", encoded_creation_id, ", ", - "\"hostname\": \"", hostname, "\", ", - "\"port\": 80, ", - "\"ip\": \"", _our_ip_encoded, - "\"}", NULL); + // Note: this leverages the fact that C concats consecutive string literals together. + mp_printf(&_socket_print, + "{\"web_api_version\": 1, " + "\"version\": \"" MICROPY_GIT_TAG "\", " + "\"build_date\": \"" MICROPY_BUILD_DATE "\", " + "\"board_name\": \"" MICROPY_HW_BOARD_NAME "\", " + "\"mcu_name\": \"" MICROPY_HW_MCU_NAME "\", " + "\"board_id\": \"" CIRCUITPY_BOARD_ID "\", " + "\"creator_id\": %u, " + "\"creation_id\": %u, " + "\"hostname\": \"%s\", " + "\"port\": %d, " + "\"ip\": \"%s\"}", CIRCUITPY_CREATOR_ID, CIRCUITPY_CREATION_ID, hostname, web_api_port, _our_ip_encoded); // Empty chunk signals the end of the response. _send_chunk(socket, ""); } @@ -908,8 +943,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 { @@ -930,9 +968,7 @@ 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); return false; @@ -962,7 +998,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. @@ -982,7 +1018,7 @@ 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); return false; @@ -1011,7 +1047,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); @@ -1022,15 +1058,18 @@ 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; } } } - } 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); @@ -1051,7 +1090,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) { @@ -1168,27 +1207,32 @@ 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) { - request->redirect = strcmp(request->header_value, "circuitpython.local") == 0; - } else if (strcmp(request->header_key, "Content-Length") == 0) { + } else if (strcasecmp(request->header_key, "Host") == 0) { + // Do a prefix check so that port is ignored. Length must be the same or the + // header ends in :. + const char *cp_local = "circuitpython.local"; + request->redirect = strncmp(request->header_value, cp_local, strlen(cp_local)) == 0 && + (strlen(request->header_value) == strlen(cp_local) || + request->header_value[strlen(cp_local)] == ':'); + } 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); } @@ -1259,6 +1303,9 @@ void supervisor_web_workflow_background(void) { // If we have a request in progress, continue working on it. if (common_hal_socketpool_socket_get_connected(&active)) { _process_request(&active, &active_request); + } else { + // Close the active socket if it is no longer connected. + common_hal_socketpool_socket_close(&active); } } diff --git a/tools/build_board_info.py b/tools/build_board_info.py index c58dc42a9d..f810d942a7 100755 --- a/tools/build_board_info.py +++ b/tools/build_board_info.py @@ -19,75 +19,11 @@ import adabot.github_requests as github sys.path.append("../docs") from shared_bindings_matrix import ( SUPPORTED_PORTS, - aliases_by_board, support_matrix_by_board, + get_board_mapping, ) -BIN = ("bin",) -UF2 = ("uf2",) -BIN_UF2 = ("bin", "uf2") -HEX = ("hex",) -HEX_UF2 = ("hex", "uf2") -SPK = ("spk",) -DFU = ("dfu",) -BIN_DFU = ("bin", "dfu") -COMBINED_HEX = ("combined.hex",) -KERNEL8_IMG = ("disk.img.zip", "kernel8.img") -KERNEL_IMG = ("disk.img.zip", "kernel.img") - -# Default extensions -extension_by_port = { - "atmel-samd": UF2, - "broadcom": KERNEL8_IMG, - "cxd56": SPK, - "espressif": BIN_UF2, - "litex": DFU, - "mimxrt10xx": HEX_UF2, - "nrf": UF2, - "raspberrypi": UF2, - "stm": BIN, -} - -# Per board overrides -extension_by_board = { - # samd - "arduino_mkr1300": BIN_UF2, - "arduino_mkrzero": BIN_UF2, - "arduino_nano_33_iot": BIN_UF2, - "arduino_zero": BIN_UF2, - "feather_m0_adalogger": BIN_UF2, - "feather_m0_basic": BIN_UF2, - "feather_m0_rfm69": BIN_UF2, - "feather_m0_rfm9x": BIN_UF2, - "uchip": BIN_UF2, - # nRF52840 dev kits that may not have UF2 bootloaders, - "makerdiary_nrf52840_mdk": HEX, - "makerdiary_nrf52840_mdk_usb_dongle": HEX_UF2, - "pca10056": BIN_UF2, - "pca10059": BIN_UF2, - "electronut_labs_blip": HEX, - "microbit_v2": COMBINED_HEX, - # stm32 - "meowbit_v121": UF2, - "sparkfun_stm32_thing_plus": BIN_UF2, - "swan_r5": BIN_UF2, - # esp32 - "adafruit_feather_esp32_v2": BIN, - # esp32c3 - "adafruit_qtpy_esp32c3": BIN, - "ai_thinker_esp32-c3s": BIN, - "ai_thinker_esp32-c3s-2m": BIN, - "espressif_esp32c3_devkitm_1_n4": BIN, - "lilygo_ttgo_t-01c3": BIN, - "lolin_c3_mini": BIN, - "microdev_micro_c3": BIN, - "lilygo_ttgo_t-oi-plus": BIN, - # broadcom - "raspberrypi_zero": KERNEL_IMG, - "raspberrypi_zero_w": KERNEL_IMG, -} - -language_allow_list = set( +LANGUAGE_ALLOW_LIST = set( [ "ID", "de_DE", @@ -116,38 +52,10 @@ def get_languages(list_all=False): if f.name.endswith(".po"): languages.add(f.name[:-3]) if not list_all: - languages = languages & language_allow_list + languages = languages & LANGUAGE_ALLOW_LIST return sorted(list(languages), key=str.casefold) -def get_board_mapping(): - boards = {} - for port in SUPPORTED_PORTS: - board_path = os.path.join("../ports", port, "boards") - for board_path in os.scandir(board_path): - if board_path.is_dir(): - board_files = os.listdir(board_path.path) - board_id = board_path.name - extensions = extension_by_port[port] - extensions = extension_by_board.get(board_path.name, extensions) - aliases = aliases_by_board.get(board_path.name, []) - boards[board_id] = { - "port": port, - "extensions": extensions, - "download_count": 0, - "aliases": aliases, - } - for alias in aliases: - boards[alias] = { - "port": port, - "extensions": extensions, - "download_count": 0, - "alias": True, - "aliases": [], - } - return boards - - def get_version_info(): version = None sha = git("rev-parse", "--short", "HEAD").stdout.decode("utf-8") @@ -282,7 +190,7 @@ def generate_download_info(): languages = get_languages() - support_matrix = support_matrix_by_board(use_branded_name=False) + support_matrix = support_matrix_by_board(use_branded_name=False, withurl=False) new_stable = "-" not in new_tag @@ -309,20 +217,19 @@ def generate_download_info(): board_files = os.listdir(board_path.path) board_id = board_path.name board_info = board_mapping[board_id] - for alias in [board_id] + board_info["aliases"]: alias_info = board_mapping[alias] if alias not in current_info: changes["new_boards"].append(alias) current_info[alias] = {"downloads": 0, "versions": []} - new_version = { "stable": new_stable, "version": new_tag, - "modules": support_matrix[alias][0], "languages": languages, - "extensions": board_info["extensions"], - "frozen_libraries": [frozen[0] for frozen in support_matrix[alias][1]], + # add modules, extensions, frozen_libraries explicitly + "modules": support_matrix[alias]["modules"], + "extensions": support_matrix[alias]["extensions"], + "frozen_libraries": support_matrix[alias]["frozen_libraries"], } current_info[alias]["downloads"] = alias_info["download_count"] current_info[alias]["versions"].append(new_version) @@ -332,9 +239,10 @@ def generate_download_info(): if changes["new_release"] and user: create_pr(changes, current_info, git_info, user) else: - print("No new release to update") if "DEBUG" in os.environ: print(create_json(current_info).decode("utf8")) + else: + print("No new release to update") if __name__ == "__main__": diff --git a/tools/build_release_files.py b/tools/build_release_files.py index 3fe714e393..309d91c368 100755 --- a/tools/build_release_files.py +++ b/tools/build_release_files.py @@ -12,6 +12,9 @@ import shutil import build_board_info as build_info import time +sys.path.append("../docs") +from shared_bindings_matrix import get_settings_from_makefile + for port in build_info.SUPPORTED_PORTS: result = subprocess.run("rm -rf ../ports/{port}/build*".format(port=port), shell=True) @@ -39,6 +42,7 @@ for board in build_boards: bin_directory = "../bin/{}/".format(board) os.makedirs(bin_directory, exist_ok=True) board_info = all_boards[board] + board_settings = get_settings_from_makefile("../ports/" + board_info["port"], board) for language in languages: bin_directory = "../bin/{board}/{language}".format(board=board, language=language) @@ -82,8 +86,12 @@ for board in build_boards: success = "\033[31mfailed\033[0m" other_output = "" + extensions = [ + extension.strip() + for extension in board_settings["CIRCUITPY_BUILD_EXTENSIONS"].split(",") + ] - for extension in board_info["extensions"]: + for extension in extensions: temp_filename = "../ports/{port}/{build}/firmware.{extension}".format( port=board_info["port"], build=build_dir, extension=extension ) diff --git a/tools/ci_set_matrix.py b/tools/ci_set_matrix.py index efb4427e7e..03aa362632 100644 --- a/tools/ci_set_matrix.py +++ b/tools/ci_set_matrix.py @@ -21,6 +21,7 @@ import json import yaml import build_board_info +from shared_bindings_matrix import get_settings_from_makefile PORT_TO_ARCH = { "atmel-samd": "arm", @@ -53,6 +54,7 @@ def set_boards_to_build(build_all): all_board_ids = set() port_to_boards = {} board_to_port = {} + board_settings = {} for board_id in boards_info_json: info = boards_info_json[board_id] if info.get("alias", False): @@ -70,6 +72,9 @@ def set_boards_to_build(build_all): boards_to_build = set() board_pattern = re.compile(r"^ports/[^/]+/boards/([^/]+)/") port_pattern = re.compile(r"^ports/([^/]+)/") + module_pattern = re.compile( + r"^(ports/[^/]+/common-hal|shared-bindings|shared-module)/([^/]+)/" + ) for p in changed_files: # See if it is board specific board_matches = board_pattern.search(p) @@ -80,7 +85,8 @@ def set_boards_to_build(build_all): # See if it is port specific port_matches = port_pattern.search(p) - if port_matches: + module_matches = module_pattern.search(p) + if port_matches and not module_matches: port = port_matches.group(1) if port != "unix": boards_to_build.update(port_to_boards[port]) @@ -94,6 +100,48 @@ def set_boards_to_build(build_all): if p.startswith("tests"): continue + # As a (nearly) last resort, for some certain files, we compute the settings from the + # makefile for each board and determine whether to build them that way. + if p.startswith("frozen") or p.startswith("supervisor") or module_matches: + for board in all_board_ids: + if board not in board_settings: + board_settings[board] = get_settings_from_makefile( + "../ports/" + board_to_port[board], board + ) + settings = board_settings[board] + + # Check frozen files to see if they are in each board. + frozen = settings.get("FROZEN_MPY_DIRS", "") + if frozen and p.startswith("frozen") and p in frozen: + boards_to_build.add(board) + continue + + # Check supervisor files. This is useful for limiting workflow changes to the + # relevant boards. + supervisor = settings["SRC_SUPERVISOR"] + if p.startswith("supervisor"): + if p in supervisor: + boards_to_build.add(board) + continue + + web_workflow = settings["CIRCUITPY_WEB_WORKFLOW"] + while web_workflow.startswith("$("): + web_workflow = settings[web_workflow[2:-1]] + if ( + p.startswith("supervisor/shared/web_workflow/static/") + and web_workflow != "0" + ): + boards_to_build.add(board) + continue + + # Check module matches + if module_matches: + module = module_matches.group(2) + "/" + if module in settings["SRC_PATTERNS"]: + boards_to_build.add(board) + continue + continue + # Otherwise build it all boards_to_build = all_board_ids break @@ -101,7 +149,7 @@ def set_boards_to_build(build_all): # Split boards by architecture. print("Building boards:") arch_to_boards = {"aarch": [], "arm": [], "riscv": [], "espressif": []} - for board in boards_to_build: + for board in sorted(boards_to_build): print(" ", board) port = board_to_port.get(board) # A board can appear due to its _deletion_ (rare)