mpflash 1.28.3__tar.gz → 1.28.4__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {mpflash-1.28.3 → mpflash-1.28.4}/.github/workflows/pytest_mpflash.yml +2 -1
- mpflash-1.28.4/CHANGELOG.md +179 -0
- {mpflash-1.28.3 → mpflash-1.28.4}/PKG-INFO +16 -29
- {mpflash-1.28.3 → mpflash-1.28.4}/README.md +15 -28
- {mpflash-1.28.3 → mpflash-1.28.4}/justfile +1 -1
- {mpflash-1.28.3 → mpflash-1.28.4}/mpflash/basicgit.py +5 -0
- mpflash-1.28.4/mpflash/cli_erase.py +114 -0
- {mpflash-1.28.3 → mpflash-1.28.4}/mpflash/cli_flash.py +12 -0
- mpflash-1.28.4/mpflash/cli_format.py +115 -0
- {mpflash-1.28.3 → mpflash-1.28.4}/mpflash/cli_main.py +4 -0
- {mpflash-1.28.3 → mpflash-1.28.4}/mpflash/common.py +1 -0
- {mpflash-1.28.3 → mpflash-1.28.4}/mpflash/flash/__init__.py +8 -0
- {mpflash-1.28.3 → mpflash-1.28.4}/mpflash/flash/builtins/uf2/__init__.py +3 -1
- mpflash-1.28.4/mpflash/flash/builtins/uf2/boardid.py +36 -0
- {mpflash-1.28.3 → mpflash-1.28.4}/mpflash/flash/builtins/uf2/erase.py +3 -3
- mpflash-1.28.4/mpflash/flash/format_fs.py +55 -0
- mpflash-1.28.4/mpflash/mpremoteboard/erase_bdev.py +118 -0
- mpflash-1.28.4/mpflash/mpremoteboard/format_bdev.py +159 -0
- {mpflash-1.28.3 → mpflash-1.28.4}/pyproject.toml +1 -1
- {mpflash-1.28.3 → mpflash-1.28.4}/tests/basicgit/test_basicgit.py +12 -0
- mpflash-1.28.4/tests/cli/test_cli_erase.py +105 -0
- {mpflash-1.28.3 → mpflash-1.28.4}/tests/cli/test_cli_flash.py +48 -0
- mpflash-1.28.4/tests/cli/test_cli_format.py +92 -0
- {mpflash-1.28.3 → mpflash-1.28.4}/tests/flash/test_flash_tasks.py +42 -0
- {mpflash-1.28.3 → mpflash-1.28.4}/tests/flash/test_flash_uf2_A.py +2 -0
- mpflash-1.28.4/tests/flash/test_format_fs.py +167 -0
- {mpflash-1.28.3 → mpflash-1.28.4}/tests/flash/test_uf2_boardid.py +17 -1
- {mpflash-1.28.3 → mpflash-1.28.4}/tests/flash/test_uf2_erase.py +10 -1
- {mpflash-1.28.3 → mpflash-1.28.4}/tests/test_cli_main.py +3 -3
- {mpflash-1.28.3 → mpflash-1.28.4}/uv.lock +1 -1
- mpflash-1.28.3/mpflash/flash/builtins/uf2/boardid.py +0 -15
- mpflash-1.28.3/mpflash/mpremoteboard/erase_bdev.py +0 -93
- {mpflash-1.28.3 → mpflash-1.28.4}/.all-contributorsrc +0 -0
- {mpflash-1.28.3 → mpflash-1.28.4}/.env +0 -0
- {mpflash-1.28.3 → mpflash-1.28.4}/.github/CODEOWNERS +0 -0
- {mpflash-1.28.3 → mpflash-1.28.4}/.github/codecov.yml +0 -0
- {mpflash-1.28.3 → mpflash-1.28.4}/.github/copilot-instructions.md +0 -0
- {mpflash-1.28.3 → mpflash-1.28.4}/.github/dependabot.yml +0 -0
- {mpflash-1.28.3 → mpflash-1.28.4}/.github/workflows/copilot-setup-steps.yml +0 -0
- {mpflash-1.28.3 → mpflash-1.28.4}/.github/workflows/dependency-review.yml +0 -0
- {mpflash-1.28.3 → mpflash-1.28.4}/.github/workflows/release.yml +0 -0
- {mpflash-1.28.3 → mpflash-1.28.4}/.gitignore +0 -0
- {mpflash-1.28.3 → mpflash-1.28.4}/.mailmap +0 -0
- {mpflash-1.28.3 → mpflash-1.28.4}/.readthedocs.yaml +0 -0
- {mpflash-1.28.3 → mpflash-1.28.4}/.vscode/extensions.json +0 -0
- {mpflash-1.28.3 → mpflash-1.28.4}/.vscode/launch.json +0 -0
- {mpflash-1.28.3 → mpflash-1.28.4}/.vscode/micropython-dict.txt +0 -0
- {mpflash-1.28.3 → mpflash-1.28.4}/.vscode/settings.json +0 -0
- {mpflash-1.28.3 → mpflash-1.28.4}/.vscode/tasks.json +0 -0
- {mpflash-1.28.3 → mpflash-1.28.4}/LICENSE +0 -0
- {mpflash-1.28.3 → mpflash-1.28.4}/docs/OIG4.jpg +0 -0
- {mpflash-1.28.3 → mpflash-1.28.4}/docs/api-reference.md +0 -0
- {mpflash-1.28.3 → mpflash-1.28.4}/docs/architecture.md +0 -0
- {mpflash-1.28.3 → mpflash-1.28.4}/docs/contributing.md +0 -0
- {mpflash-1.28.3 → mpflash-1.28.4}/docs/custom_firmware_prd.md +0 -0
- {mpflash-1.28.3 → mpflash-1.28.4}/docs/developer.md +0 -0
- {mpflash-1.28.3 → mpflash-1.28.4}/docs/index.md +0 -0
- {mpflash-1.28.3 → mpflash-1.28.4}/docs/logger_fixes.md +0 -0
- {mpflash-1.28.3 → mpflash-1.28.4}/docs/mpflash-2 (Small).jpg +0 -0
- {mpflash-1.28.3 → mpflash-1.28.4}/docs/mpflash-2.jpg +0 -0
- {mpflash-1.28.3 → mpflash-1.28.4}/docs/mpflash.jpg +0 -0
- {mpflash-1.28.3 → mpflash-1.28.4}/docs/mpflash_api_example.ipynb +0 -0
- {mpflash-1.28.3 → mpflash-1.28.4}/docs/mpremoteboard_api.md +0 -0
- {mpflash-1.28.3 → mpflash-1.28.4}/docs/startup_speed.md +0 -0
- {mpflash-1.28.3 → mpflash-1.28.4}/docs/stm32_udev_rules.md +0 -0
- {mpflash-1.28.3 → mpflash-1.28.4}/docs/troubleshooting.md +0 -0
- {mpflash-1.28.3 → mpflash-1.28.4}/examples/worklist_api_improvements.py +0 -0
- {mpflash-1.28.3 → mpflash-1.28.4}/mpflash/__init__.py +0 -0
- {mpflash-1.28.3 → mpflash-1.28.4}/mpflash/ask_input.py +0 -0
- {mpflash-1.28.3 → mpflash-1.28.4}/mpflash/bootloader/__init__.py +0 -0
- {mpflash-1.28.3 → mpflash-1.28.4}/mpflash/bootloader/activate.py +0 -0
- {mpflash-1.28.3 → mpflash-1.28.4}/mpflash/bootloader/base.py +0 -0
- {mpflash-1.28.3 → mpflash-1.28.4}/mpflash/bootloader/builtins/__init__.py +0 -0
- {mpflash-1.28.3 → mpflash-1.28.4}/mpflash/bootloader/builtins/manual.py +0 -0
- {mpflash-1.28.3 → mpflash-1.28.4}/mpflash/bootloader/builtins/mpy.py +0 -0
- {mpflash-1.28.3 → mpflash-1.28.4}/mpflash/bootloader/builtins/touch1200.py +0 -0
- {mpflash-1.28.3 → mpflash-1.28.4}/mpflash/bootloader/detect.py +0 -0
- {mpflash-1.28.3 → mpflash-1.28.4}/mpflash/bootloader/registry.py +0 -0
- {mpflash-1.28.3 → mpflash-1.28.4}/mpflash/build.py +0 -0
- {mpflash-1.28.3 → mpflash-1.28.4}/mpflash/cli_add.py +0 -0
- {mpflash-1.28.3 → mpflash-1.28.4}/mpflash/cli_download.py +0 -0
- {mpflash-1.28.3 → mpflash-1.28.4}/mpflash/cli_group.py +0 -0
- {mpflash-1.28.3 → mpflash-1.28.4}/mpflash/cli_list.py +0 -0
- {mpflash-1.28.3 → mpflash-1.28.4}/mpflash/cli_plugins.py +0 -0
- {mpflash-1.28.3 → mpflash-1.28.4}/mpflash/cli_pyocd.py +0 -0
- {mpflash-1.28.3 → mpflash-1.28.4}/mpflash/config.py +0 -0
- {mpflash-1.28.3 → mpflash-1.28.4}/mpflash/connected.py +0 -0
- {mpflash-1.28.3 → mpflash-1.28.4}/mpflash/custom/__init__.py +0 -0
- {mpflash-1.28.3 → mpflash-1.28.4}/mpflash/custom/add.py +0 -0
- {mpflash-1.28.3 → mpflash-1.28.4}/mpflash/custom/copy.py +0 -0
- {mpflash-1.28.3 → mpflash-1.28.4}/mpflash/custom/naming.py +0 -0
- {mpflash-1.28.3 → mpflash-1.28.4}/mpflash/db/__init__.py +0 -0
- {mpflash-1.28.3 → mpflash-1.28.4}/mpflash/db/boards_version.txt +0 -0
- {mpflash-1.28.3 → mpflash-1.28.4}/mpflash/db/core.py +0 -0
- {mpflash-1.28.3 → mpflash-1.28.4}/mpflash/db/gather_boards.py +0 -0
- {mpflash-1.28.3 → mpflash-1.28.4}/mpflash/db/loader.py +0 -0
- {mpflash-1.28.3 → mpflash-1.28.4}/mpflash/db/meta.py +0 -0
- {mpflash-1.28.3 → mpflash-1.28.4}/mpflash/db/micropython_boards.zip +0 -0
- {mpflash-1.28.3 → mpflash-1.28.4}/mpflash/db/models.py +0 -0
- {mpflash-1.28.3 → mpflash-1.28.4}/mpflash/db/tools.py +0 -0
- {mpflash-1.28.3 → mpflash-1.28.4}/mpflash/download/__init__.py +0 -0
- {mpflash-1.28.3 → mpflash-1.28.4}/mpflash/download/from_web.py +0 -0
- {mpflash-1.28.3 → mpflash-1.28.4}/mpflash/download/fwinfo.py +0 -0
- {mpflash-1.28.3 → mpflash-1.28.4}/mpflash/download/jid.py +0 -0
- {mpflash-1.28.3 → mpflash-1.28.4}/mpflash/downloaded.py +0 -0
- {mpflash-1.28.3 → mpflash-1.28.4}/mpflash/errors.py +0 -0
- {mpflash-1.28.3 → mpflash-1.28.4}/mpflash/flash/base.py +0 -0
- {mpflash-1.28.3 → mpflash-1.28.4}/mpflash/flash/builtins/__init__.py +0 -0
- {mpflash-1.28.3 → mpflash-1.28.4}/mpflash/flash/builtins/dfu/__init__.py +0 -0
- {mpflash-1.28.3 → mpflash-1.28.4}/mpflash/flash/builtins/dfu/stm32_dfu.py +0 -0
- {mpflash-1.28.3 → mpflash-1.28.4}/mpflash/flash/builtins/dfu_backend.py +0 -0
- {mpflash-1.28.3 → mpflash-1.28.4}/mpflash/flash/builtins/esp/__init__.py +0 -0
- {mpflash-1.28.3 → mpflash-1.28.4}/mpflash/flash/builtins/esptool_backend.py +0 -0
- {mpflash-1.28.3 → mpflash-1.28.4}/mpflash/flash/builtins/pyocd/__init__.py +0 -0
- {mpflash-1.28.3 → mpflash-1.28.4}/mpflash/flash/builtins/pyocd/core.py +0 -0
- {mpflash-1.28.3 → mpflash-1.28.4}/mpflash/flash/builtins/pyocd/flash.py +0 -0
- {mpflash-1.28.3 → mpflash-1.28.4}/mpflash/flash/builtins/pyocd/probes.py +0 -0
- {mpflash-1.28.3 → mpflash-1.28.4}/mpflash/flash/builtins/pyocd_backend.py +0 -0
- {mpflash-1.28.3 → mpflash-1.28.4}/mpflash/flash/builtins/uf2/linux.py +0 -0
- {mpflash-1.28.3 → mpflash-1.28.4}/mpflash/flash/builtins/uf2/macos.py +0 -0
- {mpflash-1.28.3 → mpflash-1.28.4}/mpflash/flash/builtins/uf2/uf2disk.py +0 -0
- {mpflash-1.28.3 → mpflash-1.28.4}/mpflash/flash/builtins/uf2/volume.py +0 -0
- {mpflash-1.28.3 → mpflash-1.28.4}/mpflash/flash/builtins/uf2/windows.py +0 -0
- {mpflash-1.28.3 → mpflash-1.28.4}/mpflash/flash/builtins/uf2/wsl2.py +0 -0
- {mpflash-1.28.3 → mpflash-1.28.4}/mpflash/flash/builtins/uf2_backend.py +0 -0
- {mpflash-1.28.3 → mpflash-1.28.4}/mpflash/flash/context.py +0 -0
- {mpflash-1.28.3 → mpflash-1.28.4}/mpflash/flash/registry.py +0 -0
- {mpflash-1.28.3 → mpflash-1.28.4}/mpflash/flash/services.py +0 -0
- {mpflash-1.28.3 → mpflash-1.28.4}/mpflash/flash/worklist.py +0 -0
- {mpflash-1.28.3 → mpflash-1.28.4}/mpflash/list.py +0 -0
- {mpflash-1.28.3 → mpflash-1.28.4}/mpflash/logger.py +0 -0
- {mpflash-1.28.3 → mpflash-1.28.4}/mpflash/mpboard_id/__init__.py +0 -0
- {mpflash-1.28.3 → mpflash-1.28.4}/mpflash/mpboard_id/alternate.py +0 -0
- {mpflash-1.28.3 → mpflash-1.28.4}/mpflash/mpboard_id/board_id.py +0 -0
- {mpflash-1.28.3 → mpflash-1.28.4}/mpflash/mpboard_id/known.py +0 -0
- {mpflash-1.28.3 → mpflash-1.28.4}/mpflash/mpboard_id/resolve.py +0 -0
- {mpflash-1.28.3 → mpflash-1.28.4}/mpflash/mpremoteboard/__init__.py +0 -0
- {mpflash-1.28.3 → mpflash-1.28.4}/mpflash/mpremoteboard/mpy_fw_info.py +0 -0
- {mpflash-1.28.3 → mpflash-1.28.4}/mpflash/mpremoteboard/runner.py +0 -0
- {mpflash-1.28.3 → mpflash-1.28.4}/mpflash/py.typed +0 -0
- {mpflash-1.28.3 → mpflash-1.28.4}/mpflash/udev_rules/49-stlinkv2-1.rules +0 -0
- {mpflash-1.28.3 → mpflash-1.28.4}/mpflash/udev_rules/49-stlinkv2.rules +0 -0
- {mpflash-1.28.3 → mpflash-1.28.4}/mpflash/udev_rules/49-stlinkv3.rules +0 -0
- {mpflash-1.28.3 → mpflash-1.28.4}/mpflash/udev_rules/49-vtlinkii.rules +0 -0
- {mpflash-1.28.3 → mpflash-1.28.4}/mpflash/udev_rules/49-wch-link.rules +0 -0
- {mpflash-1.28.3 → mpflash-1.28.4}/mpflash/udev_rules/50-cmsis-dap.rules +0 -0
- {mpflash-1.28.3 → mpflash-1.28.4}/mpflash/udev_rules/50-picoprobe.rules +0 -0
- {mpflash-1.28.3 → mpflash-1.28.4}/mpflash/udev_rules/65-mpflash-stm32-dfu.rules +0 -0
- {mpflash-1.28.3 → mpflash-1.28.4}/mpflash/udev_rules/README.md +0 -0
- {mpflash-1.28.3 → mpflash-1.28.4}/mpflash/vendor/board_database.py +0 -0
- {mpflash-1.28.3 → mpflash-1.28.4}/mpflash/vendor/click_aliases.py +0 -0
- {mpflash-1.28.3 → mpflash-1.28.4}/mpflash/vendor/dfu.py +0 -0
- {mpflash-1.28.3 → mpflash-1.28.4}/mpflash/vendor/pydfu.py +0 -0
- {mpflash-1.28.3 → mpflash-1.28.4}/mpflash/vendor/readme.md +0 -0
- {mpflash-1.28.3 → mpflash-1.28.4}/mpflash/versions.py +0 -0
- {mpflash-1.28.3 → mpflash-1.28.4}/mpflash.code-workspace +0 -0
- {mpflash-1.28.3 → mpflash-1.28.4}/reporting/MicroPython_boards.ipynb +0 -0
- {mpflash-1.28.3 → mpflash-1.28.4}/reporting/build_reporting_db.py +0 -0
- {mpflash-1.28.3 → mpflash-1.28.4}/reporting/micropython_boards_reporting.sqlite3 +0 -0
- {mpflash-1.28.3 → mpflash-1.28.4}/scripts/Qry_board_id_to_versions.sqlite3-query +0 -0
- {mpflash-1.28.3 → mpflash-1.28.4}/scripts/Untitled-1.ipynb +0 -0
- {mpflash-1.28.3 → mpflash-1.28.4}/scripts/Untitled-1.sqlite3-query +0 -0
- {mpflash-1.28.3 → mpflash-1.28.4}/scripts/Untitled-2.sqlite3-query +0 -0
- {mpflash-1.28.3 → mpflash-1.28.4}/scripts/Untitled-3.sqlite3-query +0 -0
- {mpflash-1.28.3 → mpflash-1.28.4}/scripts/Untitled-4.sqlite3-query +0 -0
- {mpflash-1.28.3 → mpflash-1.28.4}/scripts/Untitled-6.sqlite3-query +0 -0
- {mpflash-1.28.3 → mpflash-1.28.4}/scripts/Untitled-7.sqlite3-query +0 -0
- {mpflash-1.28.3 → mpflash-1.28.4}/scripts/Untitled-8.sqlite3-query +0 -0
- {mpflash-1.28.3 → mpflash-1.28.4}/scripts/join_boards-downloads.sqlite3-query +0 -0
- {mpflash-1.28.3 → mpflash-1.28.4}/scripts/libusb_flash.ipynb +0 -0
- {mpflash-1.28.3 → mpflash-1.28.4}/scripts/micropython_boards.zip +0 -0
- {mpflash-1.28.3 → mpflash-1.28.4}/scripts/mpr_command.ipynb +0 -0
- {mpflash-1.28.3 → mpflash-1.28.4}/scripts/publish.py +0 -0
- {mpflash-1.28.3 → mpflash-1.28.4}/scripts/sqlite3.exe +0 -0
- {mpflash-1.28.3 → mpflash-1.28.4}/src/mpflash/db/gather_boards.py +0 -0
- {mpflash-1.28.3 → mpflash-1.28.4}/tests/basicgit_test.py +0 -0
- {mpflash-1.28.3 → mpflash-1.28.4}/tests/bootloader/test_bootloader_detect.py +0 -0
- {mpflash-1.28.3 → mpflash-1.28.4}/tests/bootloader/test_bootloader_registry.py +0 -0
- {mpflash-1.28.3 → mpflash-1.28.4}/tests/cli/test_cli_download.py +0 -0
- {mpflash-1.28.3 → mpflash-1.28.4}/tests/cli/test_cli_list.py +0 -0
- {mpflash-1.28.3 → mpflash-1.28.4}/tests/cli/test_cli_options.py +0 -0
- {mpflash-1.28.3 → mpflash-1.28.4}/tests/cli/test_cli_plugins.py +0 -0
- {mpflash-1.28.3 → mpflash-1.28.4}/tests/cli/test_cli_pyocd.py +0 -0
- {mpflash-1.28.3 → mpflash-1.28.4}/tests/conftest.py +0 -0
- {mpflash-1.28.3 → mpflash-1.28.4}/tests/custom/test_init.py +0 -0
- {mpflash-1.28.3 → mpflash-1.28.4}/tests/custom/test_naming.py +0 -0
- {mpflash-1.28.3 → mpflash-1.28.4}/tests/data/firmware.jsonl +0 -0
- {mpflash-1.28.3 → mpflash-1.28.4}/tests/data/mpflash.db +0 -0
- {mpflash-1.28.3 → mpflash-1.28.4}/tests/db/conftest.py +0 -0
- {mpflash-1.28.3 → mpflash-1.28.4}/tests/db/test_core.py +0 -0
- {mpflash-1.28.3 → mpflash-1.28.4}/tests/db/test_find_board_id.py +0 -0
- {mpflash-1.28.3 → mpflash-1.28.4}/tests/db/test_gather.py +0 -0
- {mpflash-1.28.3 → mpflash-1.28.4}/tests/db/test_loader.py +0 -0
- {mpflash-1.28.3 → mpflash-1.28.4}/tests/db/test_meta.py +0 -0
- {mpflash-1.28.3 → mpflash-1.28.4}/tests/db/test_tools.py +0 -0
- {mpflash-1.28.3 → mpflash-1.28.4}/tests/fixtures/mock_pyocd_data.py +0 -0
- {mpflash-1.28.3 → mpflash-1.28.4}/tests/flash/test_boot_touch1200.py +0 -0
- {mpflash-1.28.3 → mpflash-1.28.4}/tests/flash/test_dfu_backend.py +0 -0
- {mpflash-1.28.3 → mpflash-1.28.4}/tests/flash/test_flash_1.py +0 -0
- {mpflash-1.28.3 → mpflash-1.28.4}/tests/flash/test_flash_esp.py +0 -0
- {mpflash-1.28.3 → mpflash-1.28.4}/tests/flash/test_registry.py +0 -0
- {mpflash-1.28.3 → mpflash-1.28.4}/tests/flash/test_services.py +0 -0
- {mpflash-1.28.3 → mpflash-1.28.4}/tests/flash/test_stm32_dfu.py +0 -0
- {mpflash-1.28.3 → mpflash-1.28.4}/tests/flash/test_uf2_linux.py +0 -0
- {mpflash-1.28.3 → mpflash-1.28.4}/tests/flash/test_uf2_mac.py +0 -0
- {mpflash-1.28.3 → mpflash-1.28.4}/tests/flash/test_uf2_volume.py +0 -0
- {mpflash-1.28.3 → mpflash-1.28.4}/tests/flash/test_uf2_windows.py +0 -0
- {mpflash-1.28.3 → mpflash-1.28.4}/tests/flash/test_uf2_wsl2.py +0 -0
- {mpflash-1.28.3 → mpflash-1.28.4}/tests/flash/test_worklist_refactored.py +0 -0
- {mpflash-1.28.3 → mpflash-1.28.4}/tests/hw/conftest.py +0 -0
- {mpflash-1.28.3 → mpflash-1.28.4}/tests/hw/test_hw_backends.py +0 -0
- {mpflash-1.28.3 → mpflash-1.28.4}/tests/hw/test_hw_erase.py +0 -0
- {mpflash-1.28.3 → mpflash-1.28.4}/tests/integration/test_cli_integration.py +0 -0
- {mpflash-1.28.3 → mpflash-1.28.4}/tests/mpboard_id/test_alternate.py +0 -0
- {mpflash-1.28.3 → mpflash-1.28.4}/tests/mpboard_id/test_known_boards.py +0 -0
- {mpflash-1.28.3 → mpflash-1.28.4}/tests/mpremoteboard/fake_output.py +0 -0
- {mpflash-1.28.3 → mpflash-1.28.4}/tests/mpremoteboard/fake_reset.py +0 -0
- {mpflash-1.28.3 → mpflash-1.28.4}/tests/mpremoteboard/fake_slow_output.py +0 -0
- {mpflash-1.28.3 → mpflash-1.28.4}/tests/mpremoteboard/test_mprb.py +0 -0
- {mpflash-1.28.3 → mpflash-1.28.4}/tests/test_ask_input.py +0 -0
- {mpflash-1.28.3 → mpflash-1.28.4}/tests/test_build.py +0 -0
- {mpflash-1.28.3 → mpflash-1.28.4}/tests/test_cli_add.py +0 -0
- {mpflash-1.28.3 → mpflash-1.28.4}/tests/test_common.py +0 -0
- {mpflash-1.28.3 → mpflash-1.28.4}/tests/test_config.py +0 -0
- {mpflash-1.28.3 → mpflash-1.28.4}/tests/test_connected.py +0 -0
- {mpflash-1.28.3 → mpflash-1.28.4}/tests/test_download.py +0 -0
- {mpflash-1.28.3 → mpflash-1.28.4}/tests/test_downloaded.py +0 -0
- {mpflash-1.28.3 → mpflash-1.28.4}/tests/test_filtered_comports.py +0 -0
- {mpflash-1.28.3 → mpflash-1.28.4}/tests/test_gather_boards_additional.py +0 -0
- {mpflash-1.28.3 → mpflash-1.28.4}/tests/test_list.py +0 -0
- {mpflash-1.28.3 → mpflash-1.28.4}/tests/test_logger_fix.py +0 -0
- {mpflash-1.28.3 → mpflash-1.28.4}/tests/test_mp_board_filter.py +0 -0
- {mpflash-1.28.3 → mpflash-1.28.4}/tests/test_mpf_api.py +0 -0
- {mpflash-1.28.3 → mpflash-1.28.4}/tests/test_version_preservation_fix.py +0 -0
- {mpflash-1.28.3 → mpflash-1.28.4}/tests/test_versions.py +0 -0
- {mpflash-1.28.3 → mpflash-1.28.4}/tests/unit/test_probe_management.py +0 -0
- {mpflash-1.28.3 → mpflash-1.28.4}/tests/unit/test_pyocd_flash_coverage.py +0 -0
- {mpflash-1.28.3 → mpflash-1.28.4}/tests/unit/test_target_detection.py +0 -0
- {mpflash-1.28.3 → mpflash-1.28.4}/tests.md +0 -0
|
@@ -90,8 +90,9 @@ jobs:
|
|
|
90
90
|
|
|
91
91
|
- name: Upload test results to Codecov
|
|
92
92
|
if: ${{ !cancelled() }}
|
|
93
|
-
uses: codecov/
|
|
93
|
+
uses: codecov/codecov-action@v7
|
|
94
94
|
with:
|
|
95
|
+
report_type: test_results
|
|
95
96
|
token: ${{ secrets.CODECOV_TOKEN }}
|
|
96
97
|
files: results/junit.xml
|
|
97
98
|
fail_ci_if_error: false
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to mpflash are documented in this file.
|
|
4
|
+
|
|
5
|
+
## [Unreleased]
|
|
6
|
+
|
|
7
|
+
### Added
|
|
8
|
+
|
|
9
|
+
- **`--format` option for `mpflash flash`** — reformats the board's filesystem after
|
|
10
|
+
flashing, recreating an empty filesystem of the same type (`VfsLfs2` or `VfsFat`) via
|
|
11
|
+
the MicroPython block device. Supported on `rp2`, `esp32`, `esp8266`, `samd`, `stm32`,
|
|
12
|
+
`nrf` and `mimxrt`. The mount point and filesystem type are detected at runtime using
|
|
13
|
+
the same `vfs.mount()` enumeration as `mpremote df`.
|
|
14
|
+
- **`mpflash format` command** — reformats the filesystem of connected boards without
|
|
15
|
+
flashing new firmware. Asks for confirmation before erasing (skip with `--yes`) and
|
|
16
|
+
supports the same ports as `flash --format`.
|
|
17
|
+
- **`mpflash erase` command** — erases the filesystem of connected boards via the
|
|
18
|
+
MicroPython block device and reboots them, without flashing new firmware. Reuses the
|
|
19
|
+
`flash --erase` implementation. Asks for confirmation before erasing (skip with
|
|
20
|
+
`--yes`). Supported on `rp2`, `samd` and `nrf`.
|
|
21
|
+
|
|
22
|
+
## [1.28.3] - 2026-07-26
|
|
23
|
+
|
|
24
|
+
This release is a major internal refactor of how mpflash flashes boards and enters
|
|
25
|
+
bootloaders, turning both into pluggable, port-agnostic backends — plus two big new
|
|
26
|
+
capabilities: local firmware builds via [**mpbuild**](https://github.com/mattytrentini/mpbuild#mpbuild) and SWD/JTAG flashing via [**pyOCD**](https://pyocd.io/).
|
|
27
|
+
|
|
28
|
+
### Highlights
|
|
29
|
+
|
|
30
|
+
- **Pluggable flash backends and bootloader activation** shared across MicroPython ports (UF2, DFU, esptool, pyOCD).
|
|
31
|
+
- **mpbuild integration** — build firmware locally right before flashing. *(Andrew Leech & Jos Verlinde)*
|
|
32
|
+
- **pyOCD integration** — flash STM32 / RP2040 / SAMD over a debug probe. *(Andrew Leech & Jos Verlinde)*
|
|
33
|
+
- **`--erase` now uses the MicroPython block device** instead of vendored flash-nuke images.
|
|
34
|
+
|
|
35
|
+
### Flash backend architecture
|
|
36
|
+
|
|
37
|
+
The monolithic flash logic (`mpflash/flash/stm32.py`, `esp.py`, `uf2/`) has been
|
|
38
|
+
reorganized into a registry of self-describing backends under `mpflash/flash/builtins/`
|
|
39
|
+
(`uf2_backend`, `dfu_backend`, `esptool_backend`, `pyocd_backend`), each declaring the
|
|
40
|
+
ports and firmware formats it supports and a priority. New `flash/registry.py`,
|
|
41
|
+
`flash/base.py`, `flash/context.py` and `flash/services.py` provide the shared plumbing,
|
|
42
|
+
and `flash_mcu(..., method=FlashMethod.<X>)` selects a backend automatically.
|
|
43
|
+
|
|
44
|
+
- New **`mpflash plugins`** command lists every registered backend and its support matrix (`--format table|plain`).
|
|
45
|
+
- `FlashMethod` enum added to `common.py`; `--method / --flash-method` gains `auto` (default) and `pyocd`.
|
|
46
|
+
- Third-party backends can register via entry points.
|
|
47
|
+
|
|
48
|
+
### Bootloader activation plugins
|
|
49
|
+
|
|
50
|
+
Bootloader entry has been refactored into a plugin structure (`bootloader/registry.py`,
|
|
51
|
+
`bootloader/base.py`, `bootloader/builtins/` with `manual`, `touch1200` and a new `mpy`
|
|
52
|
+
MicroPython-reset activator). Detection (`bootloader/detect.py`) was reworked, and a bug
|
|
53
|
+
was fixed where, if the serial port disappeared after an activator (board already reset
|
|
54
|
+
into its UF2 bootloader), mpflash would incorrectly fall through to a touch-1200 on a
|
|
55
|
+
now-missing port — it now re-checks bootloader state and waits for the UF2 volume to
|
|
56
|
+
mount before reporting success.
|
|
57
|
+
|
|
58
|
+
### mpbuild integration (build firmware locally) — *Andrew Leech & Jos Verlinde*
|
|
59
|
+
|
|
60
|
+
New `mpflash/build.py` with a `BuildManager` that builds MicroPython firmware on demand:
|
|
61
|
+
|
|
62
|
+
- New flash flags: **`--build`** (build with mpbuild before flashing) and **`--clean`** (run `mpbuild clean` first).
|
|
63
|
+
- Build caching, dependency validation (checks for mpbuild + Docker), and per-port
|
|
64
|
+
preferred output formats (e.g. `.bin` for esptool, `.uf2` for UF2, `.dfu/.bin` for DFU,
|
|
65
|
+
`.bin/.hex/.elf/.axf` for pyOCD).
|
|
66
|
+
- Built artifacts are imported into the mpflash firmware database and a ready-to-run
|
|
67
|
+
`mpflash flash …` command is printed so you can re-flash without rebuilding.
|
|
68
|
+
|
|
69
|
+
### pyOCD integration (SWD/JTAG flashing) — *Andrew Leech & Jos Verlinde*
|
|
70
|
+
|
|
71
|
+
Flash STM32, RP2040 and SAMD boards through a CMSIS-DAP / ST-Link / J-Link probe
|
|
72
|
+
(`flash/builtins/pyocd/`):
|
|
73
|
+
|
|
74
|
+
- New flash options: **`--method pyocd`**, **`--probe / --probe-id`**, **`--target`**
|
|
75
|
+
(explicit pyOCD target override) and **`--auto-install-packs / --no-auto-install-packs`** (default on).
|
|
76
|
+
- Probe discovery, MCU-info parsing with fuzzy target matching, dynamic target detection,
|
|
77
|
+
and automatic CMSIS pack installation for missing targets.
|
|
78
|
+
- New commands: **`mpflash list-probes`**, **`mpflash pyocd-info`**, **`mpflash pyocd-targets`**
|
|
79
|
+
(with `--board-filter` / `--target-filter`).
|
|
80
|
+
- ESP32/ESP8266 are intentionally excluded (use esptool).
|
|
81
|
+
- Extensive unit tests with mocked hardware so the suite runs without a probe or pyOCD installed.
|
|
82
|
+
|
|
83
|
+
### Filesystem erase via serial block device
|
|
84
|
+
|
|
85
|
+
`--erase` no longer relies on `universal_flash_nuke.uf2` for rp2xxx boards, or a post-flash
|
|
86
|
+
`rm -r :` on others. Instead `mpremoteboard/erase_bdev.py` erases the filesystem block
|
|
87
|
+
device using `mpremoteboard/erase_bdev.py` and calls `machine.reset()`, leaving the board with a
|
|
88
|
+
fresh filesystem. Bootloader entry is now a separate, explicit step, and `flash_uf2` only
|
|
89
|
+
copies firmware.
|
|
90
|
+
The previously vendored pico-universal-flash-nuke image by @Gadgetoid is no longer needed.
|
|
91
|
+
|
|
92
|
+
### UF2 reliability fixes
|
|
93
|
+
|
|
94
|
+
- **Windows drive detection** uses `psutil.disk_partitions(all=True)` and polls twice per
|
|
95
|
+
second so a freshly-mounted removable volume isn't filtered out or missed.
|
|
96
|
+
- **`wait_for_restart()` now returns a bool** via a bounded quiet probe, so callers can
|
|
97
|
+
detect when a board never reconnects.
|
|
98
|
+
- **No more false "copy failed" retries**: mpflash stopped copying file metadata to UF2
|
|
99
|
+
destinations — the bootloader could consume the firmware and disconnect before the
|
|
100
|
+
metadata step, causing a false failure and three useless retries.
|
|
101
|
+
|
|
102
|
+
### Board & port detection
|
|
103
|
+
|
|
104
|
+
- Added `best_matching_port` and a `sys_platform` attribute to `MPRemoteBoard`, improving
|
|
105
|
+
reconnection to the correct serial port after a reset.
|
|
106
|
+
- Additional known-board mappings.
|
|
107
|
+
|
|
108
|
+
### Configuration & environment
|
|
109
|
+
|
|
110
|
+
- Loads environment variables from a **`.env`** file and expands `~` in user-supplied paths.
|
|
111
|
+
|
|
112
|
+
### Linux / udev rules
|
|
113
|
+
|
|
114
|
+
- Bundled udev rules for ST-Link v2 / v2-1 / v3, WCH-Link, CMSIS-DAP, picoprobe and STM32
|
|
115
|
+
DFU (`mpflash/udev_rules/`, with a README), and expanded `docs/stm32_udev_rules.md` to
|
|
116
|
+
cover the debug probes needed by pyOCD.
|
|
117
|
+
|
|
118
|
+
### Security & quality
|
|
119
|
+
|
|
120
|
+
- Removed use of `eval()` in favor of safe parsing, plus reformatting/cleanups.
|
|
121
|
+
|
|
122
|
+
### Tooling, CI & docs
|
|
123
|
+
|
|
124
|
+
- **Automated release process**: pushing a `v*` tag triggers build + PyPI trusted
|
|
125
|
+
publishing + GitHub release; new `just release` recipe runs tests, bumps the version,
|
|
126
|
+
tags and pushes. Documented in `docs/developer.md` and `docs/contributing.md`.
|
|
127
|
+
- CI installs all extras and uploads coverage + JUnit test results to Codecov; new **HIL
|
|
128
|
+
testing** support (`--HIL <port>` pytest option and `just hil_*` targets) with a hardware
|
|
129
|
+
filesystem-erase test.
|
|
130
|
+
- Dependency bumps: `actions/checkout` 4→7, `actions/setup-python` 6→7,
|
|
131
|
+
`actions/upload-artifact` 4→7, `actions/download-artifact` 4→8, `astral-sh/setup-uv` 6→7.
|
|
132
|
+
|
|
133
|
+
### Dependencies
|
|
134
|
+
|
|
135
|
+
- Added `python-dotenv>=1.0.0`.
|
|
136
|
+
- New optional **`pyocd`** extra: `pyocd>=0.44.1`, `mpbuild>=1.0.0` (Python ≥ 3.12) /
|
|
137
|
+
`mpbuild>=0.5.0,<1.0.0` (Python < 3.12). Install with `uv sync --extra pyocd` or
|
|
138
|
+
`pip install "mpflash[pyocd]"`.
|
|
139
|
+
|
|
140
|
+
### Upgrade notes / breaking changes
|
|
141
|
+
|
|
142
|
+
- **Internal flash modules moved** under `mpflash/flash/builtins/…` (e.g. `flash/stm32.py`
|
|
143
|
+
→ `flash/builtins/dfu/`, `flash/esp.py` → `flash/builtins/esp/`, `flash/uf2/` →
|
|
144
|
+
`flash/builtins/uf2/`). Use the public `mpflash.flash.flash_mcu(method=…)` entry point
|
|
145
|
+
rather than importing these paths directly.
|
|
146
|
+
- **`--erase` is now a serial block-device erase** (board must be reachable on
|
|
147
|
+
MicroPython), not a flash-nuke image; the vendored `universal_flash_nuke.uf2` was removed.
|
|
148
|
+
|
|
149
|
+
## [1.26.0] - Breaking API changes
|
|
150
|
+
|
|
151
|
+
**Important for library users**: the worklist module API was completely refactored, with
|
|
152
|
+
breaking changes. Legacy worklist functions were **removed**.
|
|
153
|
+
|
|
154
|
+
### Removed
|
|
155
|
+
|
|
156
|
+
- `auto_update_worklist()`, `manual_worklist()`, `manual_board()`,
|
|
157
|
+
`single_auto_worklist()`, `full_auto_worklist()`, `filter_boards()`.
|
|
158
|
+
|
|
159
|
+
### Changed
|
|
160
|
+
|
|
161
|
+
- New modern interface with `create_worklist()`, the `FlashTask` dataclass and
|
|
162
|
+
`WorklistConfig` objects. See `docs/api-reference.md` for the migration guide.
|
|
163
|
+
- The command-line interface remains fully compatible.
|
|
164
|
+
|
|
165
|
+
## [1.25.0.post2]
|
|
166
|
+
|
|
167
|
+
### Added
|
|
168
|
+
|
|
169
|
+
- `--variant` option to select a specific board variant when flashing.
|
|
170
|
+
- SQLite database storing information on all possible MicroPython firmwares and the
|
|
171
|
+
management of downloaded firmware files, for better board identification and firmware matching.
|
|
172
|
+
- Use the MicroPython v1.25.0 `sys.implementation._build` as `board_id` when available.
|
|
173
|
+
- Automatic firmware download when not yet available locally (no longer need the `--download` option).
|
|
174
|
+
|
|
175
|
+
### Changed
|
|
176
|
+
|
|
177
|
+
- Restructured `mpboard_id` to use a SQLite database to identify more boards and variants.
|
|
178
|
+
- Vendored and adapted `board_database.py` from mpflash — kudos @mattytrentini.
|
|
179
|
+
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: mpflash
|
|
3
|
-
Version: 1.28.
|
|
3
|
+
Version: 1.28.4
|
|
4
4
|
Summary: Flash and download tool for MicroPython firmwares
|
|
5
5
|
Project-URL: Homepage, https://github.com/Josverl/mpflash
|
|
6
6
|
Project-URL: Documentation, https://github.com/Josverl/mpflash/blob/main/README.md
|
|
@@ -92,38 +92,23 @@ The interactive prompts use [**rich-inquirer**](https://pypi.org/project/rich-in
|
|
|
92
92
|
- `esp32`, using `.bin`, using esptool,
|
|
93
93
|
- `esp8266`, using `.bin`, using esptool
|
|
94
94
|
- `stm32`, using ` .dfu`, using pydfu (also in Windows)
|
|
95
|
+
- `nrf`, using `.uf2`, using filecopy
|
|
95
96
|
|
|
96
|
-
Not yet implemented: `
|
|
97
|
+
Not yet implemented: `alif`, `mimxrt`, `psoc-edge`, `renesas-ra`, `zephyr`
|
|
98
|
+
Not planned: `cc3200`, `pic16bit`
|
|
97
99
|
|
|
98
|
-
##
|
|
99
|
-
|
|
100
|
-
This release includes several new features and improvements:
|
|
101
|
-
- **New features:**
|
|
102
|
-
- Added support for `--variant` option to specify a specific variant of the board when flashing.
|
|
103
|
-
- mpflash now uses a slqlite database to store information on all possible micropython firmwares, and the management of the downloaded firmware files.
|
|
104
|
-
- This allows for a better identification of boards, and matches to the correct firmware.
|
|
105
|
-
- Use the MicroPython v1.25.0 `sys.implementation._build` to as board_id when avaialable
|
|
106
|
-
- Automatically try to download firmware if not yet available locally. No lonmger need to specify the `--download` option.
|
|
107
|
-
- Restructured mpboard_id to use a SQLite db to be able to ID more boards and variants
|
|
108
|
-
- vendored and adapted `board_database.py` from mpflash, kudos @mattytrentini
|
|
109
|
-
|
|
110
|
-
## ⚠️ Breaking API Changes (v1.26+)
|
|
111
|
-
|
|
112
|
-
**Important for Library Users**: The worklist module API has been completely refactored with breaking changes.
|
|
113
|
-
Legacy worklist functions have been **removed**.
|
|
114
|
-
|
|
115
|
-
- **Removed Functions**: `auto_update_worklist()`, `manual_worklist()`, `manual_board()`, `single_auto_worklist()`, `full_auto_worklist()`, `filter_boards()`
|
|
116
|
-
- **New API**: Modern interface with `create_worklist()`, `FlashTask` dataclass, and `WorklistConfig` objects
|
|
117
|
-
- **CLI Unchanged**: Command-line interface remains fully compatible
|
|
100
|
+
## Features
|
|
118
101
|
|
|
119
|
-
|
|
102
|
+
- **List connected boards** — show firmware details for all attached boards in a table or JSON format.
|
|
103
|
+
- **Download firmware** — fetch MicroPython firmware for a version, matched to a specified board or your attached board(s).
|
|
104
|
+
- **Flash boards** — flash one or all connected boards with a specific firmware or version, downloading it if needed.
|
|
105
|
+
- **Flash via a debug probe (pyOCD)** — program `stm32`, `rp2` and `samd` targets over SWD/JTAG using a CMSIS-DAP / ST-Link / J-Link probe with `mpflash flash --method pyocd`. CMSIS packs for missing targets are installed automatically. Install with `pip install "mpflash[pyocd]"`.
|
|
106
|
+
- **Build firmware locally (mpbuild)** — use `mpflash flash --build` to compile MicroPython with [mpbuild](https://pypi.org/project/mpbuild/) (requires Docker) right before flashing.
|
|
107
|
+
- **Pluggable flash & bootloader backends** — flashing and bootloader activation are selectable, port-agnostic plugins, and third-party backends can register their own. List them with `mpflash plugins`.
|
|
108
|
+
- **Filesystem erase over serial** — `--erase` wipes the MicroPython filesystem via its block device.
|
|
109
|
+
- **Filesystem format over serial** — `--format` recreates an empty MicroPython filesystem after flashing, keeping the same filesystem type (`VfsLfs2` or `VfsFat`).
|
|
110
|
+
- **Probe & target info** — inspect probes and supported targets with `mpflash list-probes`, `mpflash pyocd-info` and `mpflash pyocd-targets`.
|
|
120
111
|
|
|
121
|
-
|
|
122
|
-
## Features
|
|
123
|
-
1. List the connected boards including their firmware details, in a tabular or json format
|
|
124
|
-
2. Download MicroPython firmware for versions, and matching a specified board or matches your current attached board.
|
|
125
|
-
3. Flash one or all connected MicroPython boards with a specific firmware or version.
|
|
126
|
-
|
|
127
112
|
## Installation
|
|
128
113
|
To install mpflash, you can use either of the following commands:
|
|
129
114
|
- `uv tool install mpflash`
|
|
@@ -138,6 +123,8 @@ You can use mpflash to perform various operations on your MicroPython boards. He
|
|
|
138
123
|
| `mpflash list` | List the connected board(s) including their firmware details |
|
|
139
124
|
| `mpflash flash` | Flash the latest stable firmware to the connected board(s), downloading the firmware if needed |
|
|
140
125
|
| `mpflash download` | Download the MicroPython firmware(s) for the connected board(s) |
|
|
126
|
+
| `mpflash format` | Reformat the filesystem of the connected board(s) without flashing new firmware |
|
|
127
|
+
| `mpflash erase` | Erase the filesystem of the connected board(s) and reboot, without flashing new firmware |
|
|
141
128
|
|
|
142
129
|
**Listing connected boards:**
|
|
143
130
|
`mpflash list` will list all connected boards in a table , including their serial port, family, board name, CPU, version and build number.
|
|
@@ -18,38 +18,23 @@ The interactive prompts use [**rich-inquirer**](https://pypi.org/project/rich-in
|
|
|
18
18
|
- `esp32`, using `.bin`, using esptool,
|
|
19
19
|
- `esp8266`, using `.bin`, using esptool
|
|
20
20
|
- `stm32`, using ` .dfu`, using pydfu (also in Windows)
|
|
21
|
+
- `nrf`, using `.uf2`, using filecopy
|
|
21
22
|
|
|
22
|
-
Not yet implemented: `
|
|
23
|
+
Not yet implemented: `alif`, `mimxrt`, `psoc-edge`, `renesas-ra`, `zephyr`
|
|
24
|
+
Not planned: `cc3200`, `pic16bit`
|
|
23
25
|
|
|
24
|
-
##
|
|
25
|
-
|
|
26
|
-
This release includes several new features and improvements:
|
|
27
|
-
- **New features:**
|
|
28
|
-
- Added support for `--variant` option to specify a specific variant of the board when flashing.
|
|
29
|
-
- mpflash now uses a slqlite database to store information on all possible micropython firmwares, and the management of the downloaded firmware files.
|
|
30
|
-
- This allows for a better identification of boards, and matches to the correct firmware.
|
|
31
|
-
- Use the MicroPython v1.25.0 `sys.implementation._build` to as board_id when avaialable
|
|
32
|
-
- Automatically try to download firmware if not yet available locally. No lonmger need to specify the `--download` option.
|
|
33
|
-
- Restructured mpboard_id to use a SQLite db to be able to ID more boards and variants
|
|
34
|
-
- vendored and adapted `board_database.py` from mpflash, kudos @mattytrentini
|
|
35
|
-
|
|
36
|
-
## ⚠️ Breaking API Changes (v1.26+)
|
|
37
|
-
|
|
38
|
-
**Important for Library Users**: The worklist module API has been completely refactored with breaking changes.
|
|
39
|
-
Legacy worklist functions have been **removed**.
|
|
40
|
-
|
|
41
|
-
- **Removed Functions**: `auto_update_worklist()`, `manual_worklist()`, `manual_board()`, `single_auto_worklist()`, `full_auto_worklist()`, `filter_boards()`
|
|
42
|
-
- **New API**: Modern interface with `create_worklist()`, `FlashTask` dataclass, and `WorklistConfig` objects
|
|
43
|
-
- **CLI Unchanged**: Command-line interface remains fully compatible
|
|
26
|
+
## Features
|
|
44
27
|
|
|
45
|
-
|
|
28
|
+
- **List connected boards** — show firmware details for all attached boards in a table or JSON format.
|
|
29
|
+
- **Download firmware** — fetch MicroPython firmware for a version, matched to a specified board or your attached board(s).
|
|
30
|
+
- **Flash boards** — flash one or all connected boards with a specific firmware or version, downloading it if needed.
|
|
31
|
+
- **Flash via a debug probe (pyOCD)** — program `stm32`, `rp2` and `samd` targets over SWD/JTAG using a CMSIS-DAP / ST-Link / J-Link probe with `mpflash flash --method pyocd`. CMSIS packs for missing targets are installed automatically. Install with `pip install "mpflash[pyocd]"`.
|
|
32
|
+
- **Build firmware locally (mpbuild)** — use `mpflash flash --build` to compile MicroPython with [mpbuild](https://pypi.org/project/mpbuild/) (requires Docker) right before flashing.
|
|
33
|
+
- **Pluggable flash & bootloader backends** — flashing and bootloader activation are selectable, port-agnostic plugins, and third-party backends can register their own. List them with `mpflash plugins`.
|
|
34
|
+
- **Filesystem erase over serial** — `--erase` wipes the MicroPython filesystem via its block device.
|
|
35
|
+
- **Filesystem format over serial** — `--format` recreates an empty MicroPython filesystem after flashing, keeping the same filesystem type (`VfsLfs2` or `VfsFat`).
|
|
36
|
+
- **Probe & target info** — inspect probes and supported targets with `mpflash list-probes`, `mpflash pyocd-info` and `mpflash pyocd-targets`.
|
|
46
37
|
|
|
47
|
-
|
|
48
|
-
## Features
|
|
49
|
-
1. List the connected boards including their firmware details, in a tabular or json format
|
|
50
|
-
2. Download MicroPython firmware for versions, and matching a specified board or matches your current attached board.
|
|
51
|
-
3. Flash one or all connected MicroPython boards with a specific firmware or version.
|
|
52
|
-
|
|
53
38
|
## Installation
|
|
54
39
|
To install mpflash, you can use either of the following commands:
|
|
55
40
|
- `uv tool install mpflash`
|
|
@@ -64,6 +49,8 @@ You can use mpflash to perform various operations on your MicroPython boards. He
|
|
|
64
49
|
| `mpflash list` | List the connected board(s) including their firmware details |
|
|
65
50
|
| `mpflash flash` | Flash the latest stable firmware to the connected board(s), downloading the firmware if needed |
|
|
66
51
|
| `mpflash download` | Download the MicroPython firmware(s) for the connected board(s) |
|
|
52
|
+
| `mpflash format` | Reformat the filesystem of the connected board(s) without flashing new firmware |
|
|
53
|
+
| `mpflash erase` | Erase the filesystem of the connected board(s) and reboot, without flashing new firmware |
|
|
67
54
|
|
|
68
55
|
**Listing connected boards:**
|
|
69
56
|
`mpflash list` will list all connected boards in a table , including their serial port, family, board name, CPU, version and build number.
|
|
@@ -47,7 +47,7 @@ release bump="patch":
|
|
|
47
47
|
git add pyproject.toml uv.lock
|
|
48
48
|
git commit -m "Release v$(uv version --short)"
|
|
49
49
|
git tag -a "v$(uv version --short)" -m "Release v$(uv version --short)"
|
|
50
|
-
git push --follow-tags
|
|
50
|
+
git push --follow-tags --force
|
|
51
51
|
|
|
52
52
|
# manual fallback: publish to PyPI directly (normally handled by GitHub Actions on tag push)
|
|
53
53
|
[confirm("Are you sure you want to publish to PyPI directly? This is normally handled by GitHub Actions on tag push. Continue?")]
|
|
@@ -99,6 +99,11 @@ def get_local_tag(repo: Optional[Union[str, Path]] = None, abbreviate: bool = Tr
|
|
|
99
99
|
tag = tag.replace("\r", "").replace("\n", "")
|
|
100
100
|
if not abbreviate or "-" not in tag:
|
|
101
101
|
return tag
|
|
102
|
+
# A dirty working tree (e.g. modified git submodules) is a working-tree state
|
|
103
|
+
# marker added by `git describe --dirty`, not part of the version. Drop it so a
|
|
104
|
+
# checkout that is exactly on a tag is not misread as a dev/preview build.
|
|
105
|
+
if tag.endswith("-dirty"):
|
|
106
|
+
tag = tag[: -len("-dirty")]
|
|
102
107
|
if "-preview" in tag:
|
|
103
108
|
tag = tag.split("-preview")[0] + "-preview"
|
|
104
109
|
return tag
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
"""CLI command to erase the filesystem of connected MicroPython boards.
|
|
2
|
+
|
|
3
|
+
Reuses the ``--erase`` filesystem implementation: it runs the on-device erase
|
|
4
|
+
script via ``mpremote`` on each selected board, wiping the filesystem block
|
|
5
|
+
device and rebooting the board (``machine.reset()``) without flashing firmware.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from typing import List
|
|
9
|
+
|
|
10
|
+
import rich_click as click
|
|
11
|
+
|
|
12
|
+
from .cli_group import cli
|
|
13
|
+
from .config import config
|
|
14
|
+
from .logger import log
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
@cli.command(
|
|
18
|
+
"erase",
|
|
19
|
+
short_help="Erase the filesystem of connected MicroPython boards and reboot (erases all files).",
|
|
20
|
+
)
|
|
21
|
+
@click.option(
|
|
22
|
+
"--serial",
|
|
23
|
+
"--serial-port",
|
|
24
|
+
"-s",
|
|
25
|
+
"serial",
|
|
26
|
+
default=["*"],
|
|
27
|
+
multiple=True,
|
|
28
|
+
show_default=True,
|
|
29
|
+
help="Which serial port(s) (or globs) to erase.",
|
|
30
|
+
metavar="SERIALPORT",
|
|
31
|
+
)
|
|
32
|
+
@click.option(
|
|
33
|
+
"--ignore",
|
|
34
|
+
"-i",
|
|
35
|
+
is_eager=True,
|
|
36
|
+
help="Serial port(s) to ignore. Defaults to MPFLASH_IGNORE.",
|
|
37
|
+
multiple=True,
|
|
38
|
+
default=[],
|
|
39
|
+
envvar="MPFLASH_IGNORE",
|
|
40
|
+
show_default=True,
|
|
41
|
+
metavar="SERIALPORT",
|
|
42
|
+
)
|
|
43
|
+
@click.option(
|
|
44
|
+
"--bluetooth/--no-bluetooth",
|
|
45
|
+
"--bt/--no-bt",
|
|
46
|
+
is_flag=True,
|
|
47
|
+
default=False,
|
|
48
|
+
show_default=True,
|
|
49
|
+
help="""Include bluetooth ports in the list""",
|
|
50
|
+
)
|
|
51
|
+
@click.option(
|
|
52
|
+
"--yes",
|
|
53
|
+
"-y",
|
|
54
|
+
"assume_yes",
|
|
55
|
+
is_flag=True,
|
|
56
|
+
default=False,
|
|
57
|
+
show_default=True,
|
|
58
|
+
help="""Do not ask for confirmation before erasing.""",
|
|
59
|
+
)
|
|
60
|
+
@click.pass_context
|
|
61
|
+
def cli_erase_board(
|
|
62
|
+
ctx: click.Context,
|
|
63
|
+
serial: List[str],
|
|
64
|
+
ignore: List[str],
|
|
65
|
+
bluetooth: bool,
|
|
66
|
+
assume_yes: bool,
|
|
67
|
+
) -> int:
|
|
68
|
+
"""Erase the filesystem of connected MicroPython boards and reboot, without flashing firmware."""
|
|
69
|
+
from rich.prompt import Confirm
|
|
70
|
+
|
|
71
|
+
from .connected import list_mcus
|
|
72
|
+
from .flash.builtins.uf2.erase import SUPPORTED_PORTS, erase_filesystem
|
|
73
|
+
from .list import show_mcus
|
|
74
|
+
|
|
75
|
+
serial = list(serial)
|
|
76
|
+
ignore = list(ignore)
|
|
77
|
+
|
|
78
|
+
conn_mcus = [mcu for mcu in list_mcus(ignore=ignore, include=serial, bluetooth=bluetooth) if mcu.connected]
|
|
79
|
+
# ignore boards that have the [mpflash] ignore flag set
|
|
80
|
+
conn_mcus = [mcu for mcu in conn_mcus if not (mcu.toml.get("mpflash", {}).get("ignore", False))]
|
|
81
|
+
|
|
82
|
+
if not conn_mcus:
|
|
83
|
+
log.error("No connected MicroPython boards found to erase.")
|
|
84
|
+
ctx.exit(1)
|
|
85
|
+
|
|
86
|
+
# Only boards on a port with a known filesystem block device can be erased.
|
|
87
|
+
to_erase = [mcu for mcu in conn_mcus if mcu.port in SUPPORTED_PORTS]
|
|
88
|
+
for mcu in conn_mcus:
|
|
89
|
+
if mcu.port not in SUPPORTED_PORTS:
|
|
90
|
+
log.warning(f"Skipping {mcu.board} on {mcu.serialport}: erase is not supported for port {mcu.port!r}")
|
|
91
|
+
|
|
92
|
+
if not to_erase:
|
|
93
|
+
log.error(f"None of the connected boards support erasing (supported: {', '.join(sorted(SUPPORTED_PORTS))}).")
|
|
94
|
+
ctx.exit(1)
|
|
95
|
+
|
|
96
|
+
show_mcus(to_erase, title="Boards to erase", refresh=False)
|
|
97
|
+
|
|
98
|
+
if not assume_yes and config.interactive:
|
|
99
|
+
if not Confirm.ask("Erasing wipes ALL files on the selected board(s) and reboots it. Continue?", default=False):
|
|
100
|
+
log.info("Erase cancelled by user.")
|
|
101
|
+
ctx.exit(2)
|
|
102
|
+
|
|
103
|
+
erased = []
|
|
104
|
+
for mcu in to_erase:
|
|
105
|
+
if erase_filesystem(mcu):
|
|
106
|
+
erased.append(mcu)
|
|
107
|
+
else:
|
|
108
|
+
log.error(f"Failed to erase {mcu.board} on {mcu.serialport}")
|
|
109
|
+
|
|
110
|
+
if erased:
|
|
111
|
+
log.info(f"Erased {len(erased)} board(s)")
|
|
112
|
+
ctx.exit(0)
|
|
113
|
+
log.error("No boards were erased")
|
|
114
|
+
ctx.exit(1)
|
|
@@ -105,6 +105,13 @@ from mpflash.versions import clean_version
|
|
|
105
105
|
show_default=True,
|
|
106
106
|
help="""Erase flash before writing new firmware.""",
|
|
107
107
|
)
|
|
108
|
+
@click.option(
|
|
109
|
+
"--format/--no-format",
|
|
110
|
+
"format_fs",
|
|
111
|
+
default=False,
|
|
112
|
+
show_default=True,
|
|
113
|
+
help="""Reformat the board's filesystem after flashing (erases all files).""",
|
|
114
|
+
)
|
|
108
115
|
@click.option(
|
|
109
116
|
"--bootloader",
|
|
110
117
|
"--bl",
|
|
@@ -263,6 +270,10 @@ def cli_flash_board(ctx: click.Context, **kwargs) -> int:
|
|
|
263
270
|
params.bootloader = BootloaderMethod(params.bootloader)
|
|
264
271
|
reflash_commands: List[str] = []
|
|
265
272
|
|
|
273
|
+
# --erase and --format are mutually exclusive; only one makes sense at a time.
|
|
274
|
+
if params.erase and params.format_fs:
|
|
275
|
+
raise click.UsageError("--erase and --format cannot be used together; specify only one.")
|
|
276
|
+
|
|
266
277
|
# make it simple for the user to flash one board by asking for the serial port if not specified
|
|
267
278
|
if params.boards == ["?"] or params.serial == "?": # or params.variant == "?":
|
|
268
279
|
params.serial = ["?"]
|
|
@@ -474,6 +485,7 @@ def cli_flash_board(ctx: click.Context, **kwargs) -> int:
|
|
|
474
485
|
params.erase,
|
|
475
486
|
params.bootloader,
|
|
476
487
|
method=flash_method,
|
|
488
|
+
format_fs=params.format_fs,
|
|
477
489
|
probe_id=probe_id,
|
|
478
490
|
auto_install_packs=auto_install_packs,
|
|
479
491
|
target_override=pyocd_target,
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
"""CLI command to reformat the filesystem of connected MicroPython boards.
|
|
2
|
+
|
|
3
|
+
Runs the on-device format script via ``mpremote`` on each selected board,
|
|
4
|
+
recreating an empty filesystem of the same type without flashing new firmware.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from typing import List
|
|
8
|
+
|
|
9
|
+
import rich_click as click
|
|
10
|
+
|
|
11
|
+
from .cli_group import cli
|
|
12
|
+
from .config import config
|
|
13
|
+
from .errors import MPFlashError
|
|
14
|
+
from .logger import log
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
@cli.command(
|
|
18
|
+
"format",
|
|
19
|
+
short_help="Reformat the filesystem of connected MicroPython boards (erases all files).",
|
|
20
|
+
)
|
|
21
|
+
@click.option(
|
|
22
|
+
"--serial",
|
|
23
|
+
"--serial-port",
|
|
24
|
+
"-s",
|
|
25
|
+
"serial",
|
|
26
|
+
default=["*"],
|
|
27
|
+
multiple=True,
|
|
28
|
+
show_default=True,
|
|
29
|
+
help="Which serial port(s) (or globs) to format.",
|
|
30
|
+
metavar="SERIALPORT",
|
|
31
|
+
)
|
|
32
|
+
@click.option(
|
|
33
|
+
"--ignore",
|
|
34
|
+
"-i",
|
|
35
|
+
is_eager=True,
|
|
36
|
+
help="Serial port(s) to ignore. Defaults to MPFLASH_IGNORE.",
|
|
37
|
+
multiple=True,
|
|
38
|
+
default=[],
|
|
39
|
+
envvar="MPFLASH_IGNORE",
|
|
40
|
+
show_default=True,
|
|
41
|
+
metavar="SERIALPORT",
|
|
42
|
+
)
|
|
43
|
+
@click.option(
|
|
44
|
+
"--bluetooth/--no-bluetooth",
|
|
45
|
+
"--bt/--no-bt",
|
|
46
|
+
is_flag=True,
|
|
47
|
+
default=False,
|
|
48
|
+
show_default=True,
|
|
49
|
+
help="""Include bluetooth ports in the list""",
|
|
50
|
+
)
|
|
51
|
+
@click.option(
|
|
52
|
+
"--yes",
|
|
53
|
+
"-y",
|
|
54
|
+
"assume_yes",
|
|
55
|
+
is_flag=True,
|
|
56
|
+
default=False,
|
|
57
|
+
show_default=True,
|
|
58
|
+
help="""Do not ask for confirmation before formatting.""",
|
|
59
|
+
)
|
|
60
|
+
@click.pass_context
|
|
61
|
+
def cli_format_board(
|
|
62
|
+
ctx: click.Context,
|
|
63
|
+
serial: List[str],
|
|
64
|
+
ignore: List[str],
|
|
65
|
+
bluetooth: bool,
|
|
66
|
+
assume_yes: bool,
|
|
67
|
+
) -> int:
|
|
68
|
+
"""Reformat the filesystem of connected MicroPython boards without flashing firmware."""
|
|
69
|
+
from rich.prompt import Confirm
|
|
70
|
+
|
|
71
|
+
from .connected import list_mcus
|
|
72
|
+
from .flash.format_fs import SUPPORTED_FORMAT_PORTS, format_filesystem
|
|
73
|
+
from .list import show_mcus
|
|
74
|
+
|
|
75
|
+
serial = list(serial)
|
|
76
|
+
ignore = list(ignore)
|
|
77
|
+
|
|
78
|
+
conn_mcus = [mcu for mcu in list_mcus(ignore=ignore, include=serial, bluetooth=bluetooth) if mcu.connected]
|
|
79
|
+
# ignore boards that have the [mpflash] ignore flag set
|
|
80
|
+
conn_mcus = [mcu for mcu in conn_mcus if not (mcu.toml.get("mpflash", {}).get("ignore", False))]
|
|
81
|
+
|
|
82
|
+
if not conn_mcus:
|
|
83
|
+
log.error("No connected MicroPython boards found to format.")
|
|
84
|
+
ctx.exit(1)
|
|
85
|
+
|
|
86
|
+
# Only boards on a port with a known filesystem block device can be formatted.
|
|
87
|
+
to_format = [mcu for mcu in conn_mcus if mcu.port in SUPPORTED_FORMAT_PORTS]
|
|
88
|
+
for mcu in conn_mcus:
|
|
89
|
+
if mcu.port not in SUPPORTED_FORMAT_PORTS:
|
|
90
|
+
log.warning(f"Skipping {mcu.board} on {mcu.serialport}: format is not supported for port {mcu.port!r}")
|
|
91
|
+
|
|
92
|
+
if not to_format:
|
|
93
|
+
log.error(f"None of the connected boards support formatting (supported: {', '.join(sorted(SUPPORTED_FORMAT_PORTS))}).")
|
|
94
|
+
ctx.exit(1)
|
|
95
|
+
|
|
96
|
+
show_mcus(to_format, title="Boards to format", refresh=False)
|
|
97
|
+
|
|
98
|
+
if not assume_yes and config.interactive:
|
|
99
|
+
if not Confirm.ask("Formatting erases ALL files on the selected board(s). Continue?", default=False):
|
|
100
|
+
log.info("Format cancelled by user.")
|
|
101
|
+
ctx.exit(2)
|
|
102
|
+
|
|
103
|
+
formatted = []
|
|
104
|
+
for mcu in to_format:
|
|
105
|
+
try:
|
|
106
|
+
if format_filesystem(mcu):
|
|
107
|
+
formatted.append(mcu)
|
|
108
|
+
except MPFlashError as e:
|
|
109
|
+
log.error(f"Failed to format {mcu.board} on {mcu.serialport}: {e}")
|
|
110
|
+
|
|
111
|
+
if formatted:
|
|
112
|
+
log.info(f"Formatted {len(formatted)} board(s)")
|
|
113
|
+
ctx.exit(0)
|
|
114
|
+
log.error("No boards were formatted")
|
|
115
|
+
ctx.exit(1)
|
|
@@ -21,7 +21,9 @@ from mpflash.errors import MPFlashError
|
|
|
21
21
|
|
|
22
22
|
from .cli_add import cli_add_custom
|
|
23
23
|
from .cli_download import cli_download
|
|
24
|
+
from .cli_erase import cli_erase_board
|
|
24
25
|
from .cli_flash import cli_flash_board
|
|
26
|
+
from .cli_format import cli_format_board
|
|
25
27
|
from .cli_group import cli
|
|
26
28
|
from .cli_list import cli_list_mcus
|
|
27
29
|
from . import cli_pyocd # noqa: F401 - registers pyOCD subcommands via @cli.command
|
|
@@ -37,6 +39,8 @@ def mpflash():
|
|
|
37
39
|
cli.add_command(cli_download)
|
|
38
40
|
cli.add_command(cli_flash_board)
|
|
39
41
|
cli.add_command(cli_add_custom)
|
|
42
|
+
cli.add_command(cli_format_board)
|
|
43
|
+
cli.add_command(cli_erase_board)
|
|
40
44
|
|
|
41
45
|
# cli(auto_envvar_prefix="MPFLASH")
|
|
42
46
|
if False and os.environ.get("COMPUTERNAME").upper().startswith("JOSVERL"):
|
|
@@ -62,6 +62,7 @@ def flash_tasks(
|
|
|
62
62
|
erase: bool,
|
|
63
63
|
bootloader: BootloaderMethod,
|
|
64
64
|
method: FlashMethod = FlashMethod.AUTO,
|
|
65
|
+
format_fs: bool = False,
|
|
65
66
|
**kwargs,
|
|
66
67
|
):
|
|
67
68
|
"""Flash every entry in ``tasks`` and return the updated boards."""
|
|
@@ -236,6 +237,13 @@ def flash_tasks(
|
|
|
236
237
|
else:
|
|
237
238
|
mcu.toml["mpflash"].pop("custom_id", None)
|
|
238
239
|
mcu.set_board_info_toml()
|
|
240
|
+
if format_fs:
|
|
241
|
+
from mpflash.flash.format_fs import format_filesystem
|
|
242
|
+
|
|
243
|
+
try:
|
|
244
|
+
format_filesystem(updated)
|
|
245
|
+
except MPFlashError as e:
|
|
246
|
+
log.error(f"Failed to format filesystem on {mcu.serialport}: {e}")
|
|
239
247
|
flashed.append(updated)
|
|
240
248
|
else:
|
|
241
249
|
log.error(f"Failed to flash {mcu.board} on {mcu.serialport}")
|