mpflash 1.28.1.dev2__tar.gz → 1.28.3__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/.env +43 -0
- {mpflash-1.28.1.dev2 → mpflash-1.28.3}/.github/workflows/copilot-setup-steps.yml +1 -1
- {mpflash-1.28.1.dev2 → mpflash-1.28.3}/.github/workflows/pytest_mpflash.yml +15 -10
- {mpflash-1.28.1.dev2 → mpflash-1.28.3}/.github/workflows/release.yml +6 -6
- {mpflash-1.28.1.dev2 → mpflash-1.28.3}/.vscode/settings.json +9 -2
- {mpflash-1.28.1.dev2 → mpflash-1.28.3}/PKG-INFO +8 -1
- {mpflash-1.28.1.dev2 → mpflash-1.28.3}/docs/contributing.md +22 -11
- {mpflash-1.28.1.dev2 → mpflash-1.28.3}/docs/developer.md +35 -14
- {mpflash-1.28.1.dev2 → mpflash-1.28.3}/docs/stm32_udev_rules.md +38 -15
- mpflash-1.28.3/justfile +87 -0
- mpflash-1.28.3/mpflash/bootloader/activate.py +118 -0
- mpflash-1.28.3/mpflash/bootloader/base.py +55 -0
- mpflash-1.28.3/mpflash/bootloader/builtins/__init__.py +10 -0
- {mpflash-1.28.1.dev2/mpflash/bootloader → mpflash-1.28.3/mpflash/bootloader/builtins}/manual.py +17 -2
- mpflash-1.28.3/mpflash/bootloader/builtins/mpy.py +28 -0
- {mpflash-1.28.1.dev2/mpflash/bootloader → mpflash-1.28.3/mpflash/bootloader/builtins}/touch1200.py +17 -5
- mpflash-1.28.3/mpflash/bootloader/detect.py +70 -0
- mpflash-1.28.3/mpflash/bootloader/registry.py +115 -0
- mpflash-1.28.3/mpflash/build.py +576 -0
- {mpflash-1.28.1.dev2 → mpflash-1.28.3}/mpflash/cli_flash.py +171 -12
- {mpflash-1.28.1.dev2 → mpflash-1.28.3}/mpflash/cli_main.py +14 -0
- mpflash-1.28.3/mpflash/cli_plugins.py +64 -0
- mpflash-1.28.3/mpflash/cli_pyocd.py +248 -0
- {mpflash-1.28.1.dev2 → mpflash-1.28.3}/mpflash/common.py +39 -2
- {mpflash-1.28.1.dev2 → mpflash-1.28.3}/mpflash/custom/naming.py +1 -3
- mpflash-1.28.3/mpflash/flash/__init__.py +319 -0
- mpflash-1.28.3/mpflash/flash/base.py +151 -0
- mpflash-1.28.3/mpflash/flash/builtins/__init__.py +18 -0
- mpflash-1.28.1.dev2/mpflash/flash/stm32.py → mpflash-1.28.3/mpflash/flash/builtins/dfu/__init__.py +7 -1
- {mpflash-1.28.1.dev2/mpflash/flash → mpflash-1.28.3/mpflash/flash/builtins/dfu}/stm32_dfu.py +26 -7
- mpflash-1.28.3/mpflash/flash/builtins/dfu_backend.py +119 -0
- mpflash-1.28.1.dev2/mpflash/flash/esp.py → mpflash-1.28.3/mpflash/flash/builtins/esp/__init__.py +7 -3
- mpflash-1.28.3/mpflash/flash/builtins/esptool_backend.py +50 -0
- mpflash-1.28.3/mpflash/flash/builtins/pyocd/__init__.py +5 -0
- mpflash-1.28.3/mpflash/flash/builtins/pyocd/core.py +787 -0
- mpflash-1.28.3/mpflash/flash/builtins/pyocd/flash.py +724 -0
- mpflash-1.28.3/mpflash/flash/builtins/pyocd/probes.py +111 -0
- mpflash-1.28.3/mpflash/flash/builtins/pyocd_backend.py +90 -0
- {mpflash-1.28.1.dev2/mpflash/flash → mpflash-1.28.3/mpflash/flash/builtins}/uf2/__init__.py +28 -48
- mpflash-1.28.3/mpflash/flash/builtins/uf2/erase.py +65 -0
- mpflash-1.28.3/mpflash/flash/builtins/uf2/volume.py +101 -0
- {mpflash-1.28.1.dev2/mpflash/flash → mpflash-1.28.3/mpflash/flash/builtins}/uf2/windows.py +12 -5
- mpflash-1.28.3/mpflash/flash/builtins/uf2/wsl2.py +70 -0
- mpflash-1.28.3/mpflash/flash/builtins/uf2_backend.py +91 -0
- mpflash-1.28.3/mpflash/flash/context.py +72 -0
- mpflash-1.28.3/mpflash/flash/registry.py +154 -0
- mpflash-1.28.3/mpflash/flash/services.py +96 -0
- {mpflash-1.28.1.dev2 → mpflash-1.28.3}/mpflash/flash/worklist.py +59 -5
- {mpflash-1.28.1.dev2 → mpflash-1.28.3}/mpflash/list.py +4 -2
- {mpflash-1.28.1.dev2 → mpflash-1.28.3}/mpflash/mpboard_id/known.py +19 -0
- {mpflash-1.28.1.dev2 → mpflash-1.28.3}/mpflash/mpremoteboard/__init__.py +47 -46
- mpflash-1.28.3/mpflash/mpremoteboard/erase_bdev.py +93 -0
- {mpflash-1.28.1.dev2 → mpflash-1.28.3}/mpflash/mpremoteboard/mpy_fw_info.py +1 -0
- mpflash-1.28.3/mpflash/udev_rules/49-stlinkv2-1.rules +13 -0
- mpflash-1.28.3/mpflash/udev_rules/49-stlinkv2.rules +10 -0
- mpflash-1.28.3/mpflash/udev_rules/49-stlinkv3.rules +27 -0
- mpflash-1.28.3/mpflash/udev_rules/49-vtlinkii.rules +3 -0
- mpflash-1.28.3/mpflash/udev_rules/49-wch-link.rules +19 -0
- mpflash-1.28.3/mpflash/udev_rules/50-cmsis-dap.rules +63 -0
- mpflash-1.28.3/mpflash/udev_rules/50-picoprobe.rules +12 -0
- mpflash-1.28.3/mpflash/udev_rules/65-mpflash-stm32-dfu.rules +4 -0
- mpflash-1.28.3/mpflash/udev_rules/README.md +54 -0
- {mpflash-1.28.1.dev2 → mpflash-1.28.3}/mpflash/vendor/readme.md +1 -4
- {mpflash-1.28.1.dev2 → mpflash-1.28.3}/pyproject.toml +28 -1
- {mpflash-1.28.1.dev2 → mpflash-1.28.3}/tests/basicgit_test.py +1 -1
- mpflash-1.28.3/tests/bootloader/test_bootloader_detect.py +55 -0
- mpflash-1.28.3/tests/bootloader/test_bootloader_registry.py +85 -0
- {mpflash-1.28.1.dev2 → mpflash-1.28.3}/tests/cli/test_cli_download.py +1 -1
- {mpflash-1.28.1.dev2 → mpflash-1.28.3}/tests/cli/test_cli_flash.py +197 -2
- mpflash-1.28.3/tests/cli/test_cli_list.py +86 -0
- mpflash-1.28.3/tests/cli/test_cli_plugins.py +56 -0
- mpflash-1.28.3/tests/cli/test_cli_pyocd.py +156 -0
- mpflash-1.28.3/tests/conftest.py +268 -0
- {mpflash-1.28.1.dev2 → mpflash-1.28.3}/tests/db/test_core.py +1 -1
- {mpflash-1.28.1.dev2 → mpflash-1.28.3}/tests/db/test_loader.py +1 -1
- mpflash-1.28.3/tests/fixtures/mock_pyocd_data.py +167 -0
- {mpflash-1.28.1.dev2 → mpflash-1.28.3}/tests/flash/test_boot_touch1200.py +4 -4
- mpflash-1.28.3/tests/flash/test_dfu_backend.py +117 -0
- {mpflash-1.28.1.dev2 → mpflash-1.28.3}/tests/flash/test_flash_1.py +62 -12
- {mpflash-1.28.1.dev2 → mpflash-1.28.3}/tests/flash/test_flash_esp.py +5 -5
- {mpflash-1.28.1.dev2 → mpflash-1.28.3}/tests/flash/test_flash_tasks.py +183 -0
- mpflash-1.28.3/tests/flash/test_flash_uf2_A.py +154 -0
- mpflash-1.28.3/tests/flash/test_registry.py +334 -0
- mpflash-1.28.3/tests/flash/test_services.py +41 -0
- {mpflash-1.28.1.dev2 → mpflash-1.28.3}/tests/flash/test_stm32_dfu.py +43 -43
- {mpflash-1.28.1.dev2 → mpflash-1.28.3}/tests/flash/test_uf2_boardid.py +1 -1
- mpflash-1.28.3/tests/flash/test_uf2_erase.py +122 -0
- {mpflash-1.28.1.dev2 → mpflash-1.28.3}/tests/flash/test_uf2_linux.py +3 -3
- {mpflash-1.28.1.dev2 → mpflash-1.28.3}/tests/flash/test_uf2_mac.py +1 -1
- mpflash-1.28.3/tests/flash/test_uf2_volume.py +67 -0
- {mpflash-1.28.1.dev2 → mpflash-1.28.3}/tests/flash/test_uf2_windows.py +4 -4
- mpflash-1.28.3/tests/flash/test_uf2_wsl2.py +65 -0
- {mpflash-1.28.1.dev2 → mpflash-1.28.3}/tests/flash/test_worklist_refactored.py +71 -0
- mpflash-1.28.3/tests/hw/conftest.py +162 -0
- mpflash-1.28.3/tests/hw/test_hw_backends.py +68 -0
- mpflash-1.28.3/tests/hw/test_hw_erase.py +52 -0
- mpflash-1.28.3/tests/integration/test_cli_integration.py +430 -0
- {mpflash-1.28.1.dev2 → mpflash-1.28.3}/tests/mpboard_id/test_known_boards.py +16 -1
- {mpflash-1.28.1.dev2 → mpflash-1.28.3}/tests/mpremoteboard/test_mprb.py +89 -1
- mpflash-1.28.3/tests/test_build.py +456 -0
- {mpflash-1.28.1.dev2 → mpflash-1.28.3}/tests/test_list.py +13 -0
- mpflash-1.28.3/tests/unit/test_probe_management.py +523 -0
- mpflash-1.28.3/tests/unit/test_pyocd_flash_coverage.py +604 -0
- mpflash-1.28.3/tests/unit/test_target_detection.py +431 -0
- mpflash-1.28.3/tests.md +180 -0
- {mpflash-1.28.1.dev2 → mpflash-1.28.3}/uv.lock +451 -125
- mpflash-1.28.1.dev2/.env +0 -22
- mpflash-1.28.1.dev2/justfile +0 -48
- mpflash-1.28.1.dev2/mpflash/bootloader/activate.py +0 -60
- mpflash-1.28.1.dev2/mpflash/bootloader/detect.py +0 -84
- mpflash-1.28.1.dev2/mpflash/bootloader/micropython.py +0 -12
- mpflash-1.28.1.dev2/mpflash/flash/__init__.py +0 -83
- mpflash-1.28.1.dev2/mpflash/vendor/pico-universal-flash-nuke/LICENSE.txt +0 -21
- mpflash-1.28.1.dev2/mpflash/vendor/pico-universal-flash-nuke/universal_flash_nuke.uf2 +0 -0
- mpflash-1.28.1.dev2/tests/cli/test_cli_list.py +0 -42
- mpflash-1.28.1.dev2/tests/conftest.py +0 -125
- mpflash-1.28.1.dev2/tests/flash/test_flash_uf2_A.py +0 -177
- mpflash-1.28.1.dev2/tests.md +0 -35
- {mpflash-1.28.1.dev2 → mpflash-1.28.3}/.all-contributorsrc +0 -0
- {mpflash-1.28.1.dev2 → mpflash-1.28.3}/.github/CODEOWNERS +0 -0
- {mpflash-1.28.1.dev2 → mpflash-1.28.3}/.github/codecov.yml +0 -0
- {mpflash-1.28.1.dev2 → mpflash-1.28.3}/.github/copilot-instructions.md +0 -0
- {mpflash-1.28.1.dev2 → mpflash-1.28.3}/.github/dependabot.yml +0 -0
- {mpflash-1.28.1.dev2 → mpflash-1.28.3}/.github/workflows/dependency-review.yml +0 -0
- {mpflash-1.28.1.dev2 → mpflash-1.28.3}/.gitignore +0 -0
- {mpflash-1.28.1.dev2 → mpflash-1.28.3}/.mailmap +0 -0
- {mpflash-1.28.1.dev2 → mpflash-1.28.3}/.readthedocs.yaml +0 -0
- {mpflash-1.28.1.dev2 → mpflash-1.28.3}/.vscode/extensions.json +0 -0
- {mpflash-1.28.1.dev2 → mpflash-1.28.3}/.vscode/launch.json +0 -0
- {mpflash-1.28.1.dev2 → mpflash-1.28.3}/.vscode/micropython-dict.txt +0 -0
- {mpflash-1.28.1.dev2 → mpflash-1.28.3}/.vscode/tasks.json +0 -0
- {mpflash-1.28.1.dev2 → mpflash-1.28.3}/LICENSE +0 -0
- {mpflash-1.28.1.dev2 → mpflash-1.28.3}/README.md +0 -0
- {mpflash-1.28.1.dev2 → mpflash-1.28.3}/docs/OIG4.jpg +0 -0
- {mpflash-1.28.1.dev2 → mpflash-1.28.3}/docs/api-reference.md +0 -0
- {mpflash-1.28.1.dev2 → mpflash-1.28.3}/docs/architecture.md +0 -0
- {mpflash-1.28.1.dev2 → mpflash-1.28.3}/docs/custom_firmware_prd.md +0 -0
- {mpflash-1.28.1.dev2 → mpflash-1.28.3}/docs/index.md +0 -0
- {mpflash-1.28.1.dev2 → mpflash-1.28.3}/docs/logger_fixes.md +0 -0
- {mpflash-1.28.1.dev2 → mpflash-1.28.3}/docs/mpflash-2 (Small).jpg +0 -0
- {mpflash-1.28.1.dev2 → mpflash-1.28.3}/docs/mpflash-2.jpg +0 -0
- {mpflash-1.28.1.dev2 → mpflash-1.28.3}/docs/mpflash.jpg +0 -0
- {mpflash-1.28.1.dev2 → mpflash-1.28.3}/docs/mpflash_api_example.ipynb +0 -0
- {mpflash-1.28.1.dev2 → mpflash-1.28.3}/docs/mpremoteboard_api.md +0 -0
- {mpflash-1.28.1.dev2 → mpflash-1.28.3}/docs/startup_speed.md +0 -0
- {mpflash-1.28.1.dev2 → mpflash-1.28.3}/docs/troubleshooting.md +0 -0
- {mpflash-1.28.1.dev2 → mpflash-1.28.3}/examples/worklist_api_improvements.py +0 -0
- {mpflash-1.28.1.dev2 → mpflash-1.28.3}/mpflash/__init__.py +0 -0
- {mpflash-1.28.1.dev2 → mpflash-1.28.3}/mpflash/ask_input.py +0 -0
- {mpflash-1.28.1.dev2 → mpflash-1.28.3}/mpflash/basicgit.py +0 -0
- {mpflash-1.28.1.dev2 → mpflash-1.28.3}/mpflash/bootloader/__init__.py +0 -0
- {mpflash-1.28.1.dev2 → mpflash-1.28.3}/mpflash/cli_add.py +0 -0
- {mpflash-1.28.1.dev2 → mpflash-1.28.3}/mpflash/cli_download.py +0 -0
- {mpflash-1.28.1.dev2 → mpflash-1.28.3}/mpflash/cli_group.py +0 -0
- {mpflash-1.28.1.dev2 → mpflash-1.28.3}/mpflash/cli_list.py +0 -0
- {mpflash-1.28.1.dev2 → mpflash-1.28.3}/mpflash/config.py +0 -0
- {mpflash-1.28.1.dev2 → mpflash-1.28.3}/mpflash/connected.py +0 -0
- {mpflash-1.28.1.dev2 → mpflash-1.28.3}/mpflash/custom/__init__.py +0 -0
- {mpflash-1.28.1.dev2 → mpflash-1.28.3}/mpflash/custom/add.py +0 -0
- {mpflash-1.28.1.dev2 → mpflash-1.28.3}/mpflash/custom/copy.py +0 -0
- {mpflash-1.28.1.dev2 → mpflash-1.28.3}/mpflash/db/__init__.py +0 -0
- {mpflash-1.28.1.dev2 → mpflash-1.28.3}/mpflash/db/boards_version.txt +0 -0
- {mpflash-1.28.1.dev2 → mpflash-1.28.3}/mpflash/db/core.py +0 -0
- {mpflash-1.28.1.dev2 → mpflash-1.28.3}/mpflash/db/gather_boards.py +0 -0
- {mpflash-1.28.1.dev2 → mpflash-1.28.3}/mpflash/db/loader.py +0 -0
- {mpflash-1.28.1.dev2 → mpflash-1.28.3}/mpflash/db/meta.py +0 -0
- {mpflash-1.28.1.dev2 → mpflash-1.28.3}/mpflash/db/micropython_boards.zip +0 -0
- {mpflash-1.28.1.dev2 → mpflash-1.28.3}/mpflash/db/models.py +0 -0
- {mpflash-1.28.1.dev2 → mpflash-1.28.3}/mpflash/db/tools.py +0 -0
- {mpflash-1.28.1.dev2 → mpflash-1.28.3}/mpflash/download/__init__.py +0 -0
- {mpflash-1.28.1.dev2 → mpflash-1.28.3}/mpflash/download/from_web.py +0 -0
- {mpflash-1.28.1.dev2 → mpflash-1.28.3}/mpflash/download/fwinfo.py +0 -0
- {mpflash-1.28.1.dev2 → mpflash-1.28.3}/mpflash/download/jid.py +0 -0
- {mpflash-1.28.1.dev2 → mpflash-1.28.3}/mpflash/downloaded.py +0 -0
- {mpflash-1.28.1.dev2 → mpflash-1.28.3}/mpflash/errors.py +0 -0
- {mpflash-1.28.1.dev2/mpflash/flash → mpflash-1.28.3/mpflash/flash/builtins}/uf2/boardid.py +0 -0
- {mpflash-1.28.1.dev2/mpflash/flash → mpflash-1.28.3/mpflash/flash/builtins}/uf2/linux.py +0 -0
- {mpflash-1.28.1.dev2/mpflash/flash → mpflash-1.28.3/mpflash/flash/builtins}/uf2/macos.py +0 -0
- {mpflash-1.28.1.dev2/mpflash/flash → mpflash-1.28.3/mpflash/flash/builtins}/uf2/uf2disk.py +0 -0
- {mpflash-1.28.1.dev2 → mpflash-1.28.3}/mpflash/logger.py +0 -0
- {mpflash-1.28.1.dev2 → mpflash-1.28.3}/mpflash/mpboard_id/__init__.py +0 -0
- {mpflash-1.28.1.dev2 → mpflash-1.28.3}/mpflash/mpboard_id/alternate.py +0 -0
- {mpflash-1.28.1.dev2 → mpflash-1.28.3}/mpflash/mpboard_id/board_id.py +0 -0
- {mpflash-1.28.1.dev2 → mpflash-1.28.3}/mpflash/mpboard_id/resolve.py +0 -0
- {mpflash-1.28.1.dev2 → mpflash-1.28.3}/mpflash/mpremoteboard/runner.py +0 -0
- {mpflash-1.28.1.dev2 → mpflash-1.28.3}/mpflash/py.typed +0 -0
- {mpflash-1.28.1.dev2 → mpflash-1.28.3}/mpflash/vendor/board_database.py +0 -0
- {mpflash-1.28.1.dev2 → mpflash-1.28.3}/mpflash/vendor/click_aliases.py +0 -0
- {mpflash-1.28.1.dev2 → mpflash-1.28.3}/mpflash/vendor/dfu.py +0 -0
- {mpflash-1.28.1.dev2 → mpflash-1.28.3}/mpflash/vendor/pydfu.py +0 -0
- {mpflash-1.28.1.dev2 → mpflash-1.28.3}/mpflash/versions.py +0 -0
- {mpflash-1.28.1.dev2 → mpflash-1.28.3}/mpflash.code-workspace +0 -0
- {mpflash-1.28.1.dev2 → mpflash-1.28.3}/reporting/MicroPython_boards.ipynb +0 -0
- {mpflash-1.28.1.dev2 → mpflash-1.28.3}/reporting/build_reporting_db.py +0 -0
- {mpflash-1.28.1.dev2 → mpflash-1.28.3}/reporting/micropython_boards_reporting.sqlite3 +0 -0
- {mpflash-1.28.1.dev2 → mpflash-1.28.3}/scripts/Qry_board_id_to_versions.sqlite3-query +0 -0
- {mpflash-1.28.1.dev2 → mpflash-1.28.3}/scripts/Untitled-1.ipynb +0 -0
- {mpflash-1.28.1.dev2 → mpflash-1.28.3}/scripts/Untitled-1.sqlite3-query +0 -0
- {mpflash-1.28.1.dev2 → mpflash-1.28.3}/scripts/Untitled-2.sqlite3-query +0 -0
- {mpflash-1.28.1.dev2 → mpflash-1.28.3}/scripts/Untitled-3.sqlite3-query +0 -0
- {mpflash-1.28.1.dev2 → mpflash-1.28.3}/scripts/Untitled-4.sqlite3-query +0 -0
- {mpflash-1.28.1.dev2 → mpflash-1.28.3}/scripts/Untitled-6.sqlite3-query +0 -0
- {mpflash-1.28.1.dev2 → mpflash-1.28.3}/scripts/Untitled-7.sqlite3-query +0 -0
- {mpflash-1.28.1.dev2 → mpflash-1.28.3}/scripts/Untitled-8.sqlite3-query +0 -0
- {mpflash-1.28.1.dev2 → mpflash-1.28.3}/scripts/join_boards-downloads.sqlite3-query +0 -0
- {mpflash-1.28.1.dev2 → mpflash-1.28.3}/scripts/libusb_flash.ipynb +0 -0
- {mpflash-1.28.1.dev2 → mpflash-1.28.3}/scripts/micropython_boards.zip +0 -0
- {mpflash-1.28.1.dev2 → mpflash-1.28.3}/scripts/mpr_command.ipynb +0 -0
- {mpflash-1.28.1.dev2 → mpflash-1.28.3}/scripts/publish.py +0 -0
- {mpflash-1.28.1.dev2 → mpflash-1.28.3}/scripts/sqlite3.exe +0 -0
- {mpflash-1.28.1.dev2 → mpflash-1.28.3}/src/mpflash/db/gather_boards.py +0 -0
- {mpflash-1.28.1.dev2 → mpflash-1.28.3}/tests/basicgit/test_basicgit.py +0 -0
- {mpflash-1.28.1.dev2 → mpflash-1.28.3}/tests/cli/test_cli_options.py +0 -0
- {mpflash-1.28.1.dev2 → mpflash-1.28.3}/tests/custom/test_init.py +0 -0
- {mpflash-1.28.1.dev2 → mpflash-1.28.3}/tests/custom/test_naming.py +0 -0
- {mpflash-1.28.1.dev2 → mpflash-1.28.3}/tests/data/firmware.jsonl +0 -0
- {mpflash-1.28.1.dev2 → mpflash-1.28.3}/tests/data/mpflash.db +0 -0
- {mpflash-1.28.1.dev2 → mpflash-1.28.3}/tests/db/conftest.py +0 -0
- {mpflash-1.28.1.dev2 → mpflash-1.28.3}/tests/db/test_find_board_id.py +0 -0
- {mpflash-1.28.1.dev2 → mpflash-1.28.3}/tests/db/test_gather.py +0 -0
- {mpflash-1.28.1.dev2 → mpflash-1.28.3}/tests/db/test_meta.py +0 -0
- {mpflash-1.28.1.dev2 → mpflash-1.28.3}/tests/db/test_tools.py +0 -0
- {mpflash-1.28.1.dev2 → mpflash-1.28.3}/tests/mpboard_id/test_alternate.py +0 -0
- {mpflash-1.28.1.dev2 → mpflash-1.28.3}/tests/mpremoteboard/fake_output.py +0 -0
- {mpflash-1.28.1.dev2 → mpflash-1.28.3}/tests/mpremoteboard/fake_reset.py +0 -0
- {mpflash-1.28.1.dev2 → mpflash-1.28.3}/tests/mpremoteboard/fake_slow_output.py +0 -0
- {mpflash-1.28.1.dev2 → mpflash-1.28.3}/tests/test_ask_input.py +0 -0
- {mpflash-1.28.1.dev2 → mpflash-1.28.3}/tests/test_cli_add.py +0 -0
- {mpflash-1.28.1.dev2 → mpflash-1.28.3}/tests/test_cli_main.py +0 -0
- {mpflash-1.28.1.dev2 → mpflash-1.28.3}/tests/test_common.py +0 -0
- {mpflash-1.28.1.dev2 → mpflash-1.28.3}/tests/test_config.py +0 -0
- {mpflash-1.28.1.dev2 → mpflash-1.28.3}/tests/test_connected.py +0 -0
- {mpflash-1.28.1.dev2 → mpflash-1.28.3}/tests/test_download.py +0 -0
- {mpflash-1.28.1.dev2 → mpflash-1.28.3}/tests/test_downloaded.py +0 -0
- {mpflash-1.28.1.dev2 → mpflash-1.28.3}/tests/test_filtered_comports.py +0 -0
- {mpflash-1.28.1.dev2 → mpflash-1.28.3}/tests/test_gather_boards_additional.py +0 -0
- {mpflash-1.28.1.dev2 → mpflash-1.28.3}/tests/test_logger_fix.py +0 -0
- {mpflash-1.28.1.dev2 → mpflash-1.28.3}/tests/test_mp_board_filter.py +0 -0
- {mpflash-1.28.1.dev2 → mpflash-1.28.3}/tests/test_mpf_api.py +0 -0
- {mpflash-1.28.1.dev2 → mpflash-1.28.3}/tests/test_version_preservation_fix.py +0 -0
- {mpflash-1.28.1.dev2 → mpflash-1.28.3}/tests/test_versions.py +0 -0
mpflash-1.28.3/.env
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# Python .env file ..
|
|
2
|
+
|
|
3
|
+
# PYTHONPYCACHEPREFIX=__my_pycache
|
|
4
|
+
|
|
5
|
+
JUPYTER_PLATFORM_DIRS=1
|
|
6
|
+
PYDEVD_DISABLE_FILE_VALIDATION=1
|
|
7
|
+
# Allow tests to find sources
|
|
8
|
+
PYTHONPATH = src
|
|
9
|
+
|
|
10
|
+
# give 20 secs to complete : subprocess.getstatusoutput
|
|
11
|
+
PYDEVD_WARN_EVALUATION_TIMEOUT = 20
|
|
12
|
+
|
|
13
|
+
# stop nagging for updates
|
|
14
|
+
PIP_DISABLE_PIP_VERSION_CHECK=1
|
|
15
|
+
|
|
16
|
+
# stop neggin during debug
|
|
17
|
+
JUPYTER_PLATFORM_DIRS=1
|
|
18
|
+
PYDEVD_DISABLE_FILE_VALIDATION=1
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
MPFLASH_FIRMWARE=./scratch
|
|
22
|
+
MICROPY_DIR=~/micropython
|
|
23
|
+
|
|
24
|
+
# -----------------------------------------------------------------------------------------------
|
|
25
|
+
# HIL testing
|
|
26
|
+
# -----------------------------------------------------------------------------------------------
|
|
27
|
+
# UF2 - RPI Pico2 on WSL
|
|
28
|
+
# MPFLASH_HW_UF2_PORT=/dev/ttyACM1
|
|
29
|
+
# MPFLASH_HW_UF2_FW=/mnt/c/Users/jos_v/Downloads/firmware/rp2/RPI_PICO2-v1.28.0.uf2
|
|
30
|
+
|
|
31
|
+
# # DFU - PYBV11 on WSL
|
|
32
|
+
# MPFLASH_HW_DFU_PORT=/dev/ttyACM0
|
|
33
|
+
# MPFLASH_HW_DFU_FW=/mnt/c/Users/jos_v/Downloads/firmware/stm32/PYBV11-DP-v1.28.0.dfu
|
|
34
|
+
|
|
35
|
+
# # PYOCD - PYBV11 on WSL
|
|
36
|
+
# # MPFLASH_HW_PYOCD_PROBE=066CFF514949877187244446
|
|
37
|
+
# MPFLASH_HW_PYOCD_PROBE=auto
|
|
38
|
+
# MPFLASH_HW_PYOCD_PORT=/dev/ttyACM1
|
|
39
|
+
# MPFLASH_HW_PYOCD_FW=/mnt/c/Users/jos_v/Downloads/firmware/stm32/PYBV11-DP-v1.28.0.hex
|
|
40
|
+
|
|
41
|
+
# # esptool - ESP32 on WSL
|
|
42
|
+
# MPFLASH_HW_ESP_PORT=/dev/ttyUSB0
|
|
43
|
+
# MPFLASH_HW_ESP_FW=/mnt/c/Users/jos_v/Downloads/firmware/esp32/ESP32_GENERIC-SPIRAM-v1.28.0.bin
|
|
@@ -53,12 +53,12 @@ jobs:
|
|
|
53
53
|
# uv is not in the default image
|
|
54
54
|
#----------------------------------------------
|
|
55
55
|
- name: Install the latest version of uv
|
|
56
|
-
uses: astral-sh/setup-uv@
|
|
56
|
+
uses: astral-sh/setup-uv@v7
|
|
57
57
|
with:
|
|
58
58
|
version: "latest"
|
|
59
59
|
|
|
60
60
|
- name: Set up Python ${{ matrix.python-version }}
|
|
61
|
-
uses: actions/setup-python@
|
|
61
|
+
uses: actions/setup-python@v7
|
|
62
62
|
with:
|
|
63
63
|
python-version: ${{ matrix.python-version }}
|
|
64
64
|
# cache: "poetry"
|
|
@@ -66,14 +66,14 @@ jobs:
|
|
|
66
66
|
#----------------------------------------------
|
|
67
67
|
# install project
|
|
68
68
|
#----------------------------------------------
|
|
69
|
-
- name: Install mpflash & test dependencies
|
|
70
|
-
run: uv sync --
|
|
69
|
+
- name: Install mpflash & test dependencies (all extras)
|
|
70
|
+
run: uv sync --all-extras
|
|
71
71
|
|
|
72
72
|
- name: Test mpflash
|
|
73
73
|
run: |
|
|
74
74
|
# run once to bootstrap database (test hack)
|
|
75
75
|
uv run mpflash download --board RPI_PICO
|
|
76
|
-
uv run pytest --cov --cov-branch --cov-report=xml
|
|
76
|
+
uv run pytest --cov --cov-branch --cov-report=xml --junitxml=results/junit.xml
|
|
77
77
|
|
|
78
78
|
#----------------------------------------------
|
|
79
79
|
# upload coverage stats
|
|
@@ -81,13 +81,18 @@ jobs:
|
|
|
81
81
|
#----------------------------------------------
|
|
82
82
|
|
|
83
83
|
- name: Upload coverage-mpflash-*.xml to Codecov
|
|
84
|
-
if:
|
|
84
|
+
if: ${{ !cancelled() }}
|
|
85
85
|
continue-on-error: true
|
|
86
86
|
uses: codecov/codecov-action@v7
|
|
87
87
|
with:
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
# file: results/coverage-mpflash-${{ matrix.python-version }}-${{ matrix.os }}.xml
|
|
91
|
-
# flags: mpflash
|
|
88
|
+
token: ${{ secrets.CODECOV_TOKEN }}
|
|
89
|
+
fail_ci_if_error: false
|
|
92
90
|
|
|
91
|
+
- name: Upload test results to Codecov
|
|
92
|
+
if: ${{ !cancelled() }}
|
|
93
|
+
uses: codecov/test-results-action@v1
|
|
94
|
+
with:
|
|
95
|
+
token: ${{ secrets.CODECOV_TOKEN }}
|
|
96
|
+
files: results/junit.xml
|
|
97
|
+
fail_ci_if_error: false
|
|
93
98
|
|
|
@@ -11,10 +11,10 @@ jobs:
|
|
|
11
11
|
build:
|
|
12
12
|
runs-on: ubuntu-latest
|
|
13
13
|
steps:
|
|
14
|
-
- uses: actions/checkout@
|
|
14
|
+
- uses: actions/checkout@v7
|
|
15
15
|
|
|
16
16
|
- name: Install uv
|
|
17
|
-
uses: astral-sh/setup-uv@
|
|
17
|
+
uses: astral-sh/setup-uv@v7
|
|
18
18
|
with:
|
|
19
19
|
python-version: "3.14"
|
|
20
20
|
enable-cache: true
|
|
@@ -23,7 +23,7 @@ jobs:
|
|
|
23
23
|
run: uv build
|
|
24
24
|
|
|
25
25
|
- name: Upload distribution artefacts
|
|
26
|
-
uses: actions/upload-artifact@
|
|
26
|
+
uses: actions/upload-artifact@v7
|
|
27
27
|
with:
|
|
28
28
|
name: dist
|
|
29
29
|
path: dist/
|
|
@@ -42,7 +42,7 @@ jobs:
|
|
|
42
42
|
id-token: write
|
|
43
43
|
steps:
|
|
44
44
|
- name: Download distribution artefacts
|
|
45
|
-
uses: actions/download-artifact@
|
|
45
|
+
uses: actions/download-artifact@v8
|
|
46
46
|
with:
|
|
47
47
|
name: dist
|
|
48
48
|
path: dist/
|
|
@@ -56,13 +56,13 @@ jobs:
|
|
|
56
56
|
permissions:
|
|
57
57
|
contents: write
|
|
58
58
|
steps:
|
|
59
|
-
- uses: actions/checkout@
|
|
59
|
+
- uses: actions/checkout@v7
|
|
60
60
|
with:
|
|
61
61
|
# Full history so --generate-notes can resolve the previous tag.
|
|
62
62
|
fetch-depth: 0
|
|
63
63
|
|
|
64
64
|
- name: Download distribution artefacts
|
|
65
|
-
uses: actions/download-artifact@
|
|
65
|
+
uses: actions/download-artifact@v8
|
|
66
66
|
with:
|
|
67
67
|
name: dist
|
|
68
68
|
path: dist/
|
|
@@ -36,13 +36,20 @@
|
|
|
36
36
|
"statusBar.background": "#b30a60",
|
|
37
37
|
"statusBar.foreground": "#e7e7e7",
|
|
38
38
|
"statusBarItem.hoverBackground": "#e30d7a",
|
|
39
|
-
"statusBarItem.remoteBackground": "#
|
|
39
|
+
"statusBarItem.remoteBackground": "#101e02",
|
|
40
40
|
"statusBarItem.remoteForeground": "#e7e7e7",
|
|
41
41
|
"tab.activeBorder": "#e30d7a",
|
|
42
42
|
"titleBar.activeBackground": "#b30a60",
|
|
43
43
|
"titleBar.activeForeground": "#e7e7e7",
|
|
44
44
|
"titleBar.inactiveBackground": "#b30a6099",
|
|
45
|
-
"titleBar.inactiveForeground": "#e7e7e799"
|
|
45
|
+
"titleBar.inactiveForeground": "#e7e7e799",
|
|
46
|
+
"activityBarTop.activeBackground": "#e30d7a",
|
|
47
|
+
"activityBarTop.background": "#e30d7a",
|
|
48
|
+
"activityBarTop.foreground": "#e7e7e7",
|
|
49
|
+
"activityBarTop.inactiveForeground": "#e7e7e799",
|
|
50
|
+
"commandCenter.foreground": "#e7e7e7",
|
|
51
|
+
"statusBar.debuggingBackground": "#b30a60",
|
|
52
|
+
"statusBar.debuggingForeground": "#e7e7e7"
|
|
46
53
|
},
|
|
47
54
|
"python.terminal.activateEnvInCurrentTerminal": true,
|
|
48
55
|
"todo-tree.filtering.ignoreGitSubmodules": true,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: mpflash
|
|
3
|
-
Version: 1.28.
|
|
3
|
+
Version: 1.28.3
|
|
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
|
|
@@ -40,6 +40,7 @@ Requires-Dist: platformdirs>=4.2.0
|
|
|
40
40
|
Requires-Dist: psutil<8.0.0,>=7.0.0
|
|
41
41
|
Requires-Dist: pygithub>=2.1.1
|
|
42
42
|
Requires-Dist: pytest-cov>=7.0.0
|
|
43
|
+
Requires-Dist: python-dotenv>=1.0.0
|
|
43
44
|
Requires-Dist: pyusb>=1.2.1
|
|
44
45
|
Requires-Dist: pywin32>=310; sys_platform == 'win32'
|
|
45
46
|
Requires-Dist: questionary>=2.0.0
|
|
@@ -48,8 +49,14 @@ Requires-Dist: rich-click>=1.8.1
|
|
|
48
49
|
Requires-Dist: tenacity==9.1.4
|
|
49
50
|
Requires-Dist: tomli-w>=1.2.0
|
|
50
51
|
Requires-Dist: tomli>=2.2.1
|
|
52
|
+
Provides-Extra: build
|
|
53
|
+
Requires-Dist: mpbuild<1.0.0,>=0.5.0; (python_version < '3.12') and extra == 'build'
|
|
54
|
+
Requires-Dist: mpbuild>=1.0.0; (python_version >= '3.12') and extra == 'build'
|
|
51
55
|
Provides-Extra: dev
|
|
52
56
|
Requires-Dist: keyring>=25.6.0; extra == 'dev'
|
|
57
|
+
Provides-Extra: pyocd
|
|
58
|
+
Requires-Dist: libusb-package==1.0.26.1; (python_version >= '3.14') and extra == 'pyocd'
|
|
59
|
+
Requires-Dist: pyocd>=0.44.1; extra == 'pyocd'
|
|
53
60
|
Provides-Extra: test
|
|
54
61
|
Requires-Dist: coverage<8.0.0,>=6.4.3; extra == 'test'
|
|
55
62
|
Requires-Dist: distro>=1.8.0; extra == 'test'
|
|
@@ -527,18 +527,28 @@ To add support for a new hardware platform:
|
|
|
527
527
|
|
|
528
528
|
## Release Process
|
|
529
529
|
|
|
530
|
-
### Version Bumping
|
|
530
|
+
### Version Bumping & Tagging
|
|
531
531
|
|
|
532
|
-
MPFlash uses semantic versioning
|
|
532
|
+
MPFlash uses semantic versioning and releases are automated via GitHub Actions.
|
|
533
|
+
Pushing a `v*` tag triggers [`.github/workflows/release.yml`](../.github/workflows/release.yml),
|
|
534
|
+
which builds the sdist + wheel, publishes to PyPI (trusted publishing) and creates
|
|
535
|
+
a GitHub release with generated notes.
|
|
536
|
+
|
|
537
|
+
Use the `just release` recipe to cut a release. It runs in the safe order - tests
|
|
538
|
+
first, then version bump and tag push:
|
|
533
539
|
|
|
534
540
|
```bash
|
|
535
|
-
#
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
# bump2version major # for breaking changes
|
|
541
|
+
just release # next patch version (default)
|
|
542
|
+
just release dev # next dev prerelease
|
|
543
|
+
just release minor # next minor version
|
|
544
|
+
just release major # next major version
|
|
540
545
|
```
|
|
541
546
|
|
|
547
|
+
This runs `uv run pytest`, then `uv version --bump <bump>`, commits the change,
|
|
548
|
+
creates an annotated `vX.Y.Z` tag and pushes it with `git push --follow-tags`.
|
|
549
|
+
Accepted bump values: `major`, `minor`, `patch`, `stable`, `alpha`, `beta`, `rc`,
|
|
550
|
+
`post`, `dev`.
|
|
551
|
+
|
|
542
552
|
### Changelog
|
|
543
553
|
|
|
544
554
|
Update the changelog for releases:
|
|
@@ -564,13 +574,14 @@ Update the changelog for releases:
|
|
|
564
574
|
|
|
565
575
|
### Pre-release Checklist
|
|
566
576
|
|
|
567
|
-
Before
|
|
577
|
+
Before running `just release`:
|
|
568
578
|
|
|
569
|
-
- [ ] All tests passing
|
|
570
579
|
- [ ] Documentation updated
|
|
571
|
-
- [ ] Version bumped appropriately
|
|
572
580
|
- [ ] Changelog updated
|
|
573
|
-
- [ ]
|
|
581
|
+
- [ ] Correct bump chosen (no breaking changes without a major version bump)
|
|
582
|
+
- [ ] On the branch you intend to release from
|
|
583
|
+
|
|
584
|
+
`just release` then runs the tests, bumps the version and pushes the tag for you.
|
|
574
585
|
|
|
575
586
|
## Getting Help
|
|
576
587
|
|
|
@@ -447,26 +447,47 @@ Use the configured tasks for development:
|
|
|
447
447
|
|
|
448
448
|
## Release Process
|
|
449
449
|
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
uv
|
|
454
|
-
|
|
450
|
+
Releases are automated through GitHub Actions. Pushing a `v*` tag triggers
|
|
451
|
+
[`.github/workflows/release.yml`](../.github/workflows/release.yml), which:
|
|
452
|
+
|
|
453
|
+
1. Builds the sdist and wheel with `uv build`
|
|
454
|
+
2. Publishes them to PyPI using **trusted publishing** (OIDC, no token required)
|
|
455
|
+
3. Creates a GitHub release with auto-generated notes
|
|
456
|
+
|
|
457
|
+
### Cutting a release
|
|
458
|
+
|
|
459
|
+
The `just release` recipe drives the whole local flow in the safe order - it runs
|
|
460
|
+
the tests first, and only then bumps the version and pushes the tag:
|
|
455
461
|
|
|
456
|
-
|
|
462
|
+
```bash
|
|
463
|
+
# 1. (optional) refresh the bundled boards & descriptions before releasing
|
|
457
464
|
uv run mpflash/db/gather_boards.py --mpy-path ../micropython
|
|
458
465
|
|
|
459
|
-
#
|
|
460
|
-
|
|
466
|
+
# 2. run tests, bump the version, commit, tag and push (triggers the PyPI release)
|
|
467
|
+
just release # next patch version (default)
|
|
468
|
+
just release dev # next dev prerelease
|
|
469
|
+
just release minor # next minor version
|
|
470
|
+
```
|
|
461
471
|
|
|
462
|
-
|
|
463
|
-
# set token in environment variable
|
|
472
|
+
`just release` performs, in order:
|
|
464
473
|
|
|
465
|
-
|
|
466
|
-
uv
|
|
467
|
-
|
|
468
|
-
|
|
474
|
+
1. `uv run pytest` - abort the release if any test fails
|
|
475
|
+
2. `uv version --bump <bump>` - update `pyproject.toml` and re-lock
|
|
476
|
+
3. `git commit` the version change
|
|
477
|
+
4. `git tag -a vX.Y.Z` and `git push --follow-tags`
|
|
478
|
+
|
|
479
|
+
The accepted bump values are `major`, `minor`, `patch` (default), `stable`,
|
|
480
|
+
`alpha`, `beta`, `rc`, `post` and `dev`.
|
|
481
|
+
|
|
482
|
+
### Manual fallback
|
|
483
|
+
|
|
484
|
+
Only if the GitHub Actions publish is unavailable:
|
|
485
|
+
|
|
486
|
+
```bash
|
|
487
|
+
just build # or: uv build
|
|
488
|
+
just publish # or: uv publish (requires PyPI credentials)
|
|
469
489
|
```
|
|
490
|
+
|
|
470
491
|
### Documentation Updates
|
|
471
492
|
- Update README.md with new features
|
|
472
493
|
- Add changelog entries
|
|
@@ -1,24 +1,47 @@
|
|
|
1
|
-
## Linux permissions for
|
|
1
|
+
## Linux permissions for USB devices
|
|
2
2
|
|
|
3
|
-
In order to flash
|
|
4
|
-
|
|
3
|
+
In order to flash STM32 boards in DFU mode without `sudo`, your user needs
|
|
4
|
+
permission on the DFU USB device node.
|
|
5
5
|
|
|
6
|
-
|
|
6
|
+
Ready-to-use rule file in this repository:
|
|
7
|
+
|
|
8
|
+
- `mpflash/udev_rules/65-mpflash-stm32-dfu.rules`
|
|
9
|
+
|
|
10
|
+
### Install (copy/paste)
|
|
7
11
|
|
|
8
|
-
File: `/etc/udev/rules.d/65-mpflash.rules`
|
|
9
12
|
```bash
|
|
10
|
-
|
|
11
|
-
|
|
13
|
+
sudo cp mpflash/udev_rules/65-mpflash-stm32-dfu.rules /etc/udev/rules.d/65-mpflash-stm32-dfu.rules
|
|
14
|
+
sudo udevadm control --reload-rules
|
|
15
|
+
sudo udevadm trigger
|
|
12
16
|
```
|
|
13
|
-
|
|
17
|
+
|
|
18
|
+
Then unplug/replug the STM32 board (or re-enter DFU mode).
|
|
19
|
+
|
|
20
|
+
### Rule contents
|
|
21
|
+
|
|
22
|
+
```udev
|
|
23
|
+
# mpflash STM32 DFU access rule
|
|
24
|
+
# Device: STMicroelectronics STM Device in DFU Mode (0483:df11)
|
|
25
|
+
SUBSYSTEM=="usb", ATTR{idVendor}=="0483", ATTR{idProduct}=="df11", MODE="0660", GROUP="plugdev", TAG+="uaccess"
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
### Verify
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
lsusb | grep -i "0483:df11"
|
|
32
|
+
groups
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
If your user is not in `plugdev`, add it and log out/in once:
|
|
36
|
+
|
|
14
37
|
```bash
|
|
15
|
-
sudo
|
|
38
|
+
sudo usermod -aG plugdev "$USER"
|
|
16
39
|
```
|
|
17
|
-
Unplug and replug the usb device to apply the new rules.
|
|
18
40
|
|
|
19
41
|
|
|
20
|
-
##
|
|
21
|
-
|
|
42
|
+
## To check
|
|
43
|
+
|
|
44
|
+
Enter STM32 bootloader mode:
|
|
22
45
|
``` bash
|
|
23
46
|
mpremote bootloader
|
|
24
47
|
```
|
|
@@ -49,14 +72,14 @@ List usb devices
|
|
|
49
72
|
ID 8087:0aaa Intel Corp. Bluetooth 9460/9560 Jefferson Peak (JfP)
|
|
50
73
|
/sys/bus/usb/devices/1-10 /dev/bus/usb/001/003
|
|
51
74
|
```
|
|
52
|
-
Lookup the
|
|
53
|
-
|
|
75
|
+
Lookup the STM32 device path (`/dev/bus/usb/001/022`), and check if group
|
|
76
|
+
`plugdev` is granted access:
|
|
54
77
|
```bash
|
|
55
78
|
(.venv) jos@jvnuc:~/projects/mpflash$ ll /dev/bus/usb/001/022
|
|
56
79
|
crw-rw-r-- 1 root plugdev 189, 21 mrt 11 22:38 /dev/bus/usb/001/022
|
|
57
80
|
```
|
|
58
81
|
|
|
59
|
-
Check `groups` to see if user is in plugdev
|
|
82
|
+
Check `groups` to see if user is in `plugdev`:
|
|
60
83
|
```
|
|
61
84
|
(.venv) jos@jvnuc:~/projects/mpflash$ groups
|
|
62
85
|
jos adm disk dialout cdrom sudo dip plugdev kvm lpadmin lxd sambashare usb
|
mpflash-1.28.3/justfile
ADDED
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
|
|
2
|
+
# Set shell for Windows OSs:
|
|
3
|
+
set windows-shell := ["pwsh.exe", "-NoLogo", "-Command"]
|
|
4
|
+
|
|
5
|
+
# Show recipes
|
|
6
|
+
help:
|
|
7
|
+
@just --list
|
|
8
|
+
|
|
9
|
+
# install project in edi mode and install dev dependencies
|
|
10
|
+
sync:
|
|
11
|
+
uv sync --extra dev,test,pyocd
|
|
12
|
+
|
|
13
|
+
init:
|
|
14
|
+
@just sync
|
|
15
|
+
|
|
16
|
+
# run full pytest suite
|
|
17
|
+
test:
|
|
18
|
+
uv run pytest -v
|
|
19
|
+
|
|
20
|
+
# create coverage report, build html report
|
|
21
|
+
coverage:
|
|
22
|
+
uv run pytest --cov --cov-report=term-missing
|
|
23
|
+
coverage html
|
|
24
|
+
start coverage/index.html
|
|
25
|
+
|
|
26
|
+
# bump mpflash's version [major, minor, patch, stable, alpha, beta, rc, post, dev]
|
|
27
|
+
bump bump="patch":
|
|
28
|
+
uv version --bump {{bump}}
|
|
29
|
+
|
|
30
|
+
# build the project for distribution
|
|
31
|
+
build:
|
|
32
|
+
uv build
|
|
33
|
+
|
|
34
|
+
# -----------------------------------------------------------------------------------------------
|
|
35
|
+
# Release process
|
|
36
|
+
# Pushing a `v*` tag triggers .github/workflows/release.yml, which builds the sdist + wheel,
|
|
37
|
+
# publishes to PyPI using trusted publishing (OIDC, no token) and creates a GitHub release
|
|
38
|
+
# with auto-generated notes. Use `just release` to cut a release; do not publish manually.
|
|
39
|
+
# -----------------------------------------------------------------------------------------------
|
|
40
|
+
|
|
41
|
+
# run tests, bump the version, then commit, tag and push - triggering the PyPI release
|
|
42
|
+
# bump = major | minor | patch (default) | stable | alpha | beta | rc | post | dev
|
|
43
|
+
[confirm("Run tests, bump the version and push a new tag? This triggers a PyPI release. Continue?")]
|
|
44
|
+
release bump="patch":
|
|
45
|
+
uv run pytest
|
|
46
|
+
uv version --bump {{bump}}
|
|
47
|
+
git add pyproject.toml uv.lock
|
|
48
|
+
git commit -m "Release v$(uv version --short)"
|
|
49
|
+
git tag -a "v$(uv version --short)" -m "Release v$(uv version --short)"
|
|
50
|
+
git push --follow-tags
|
|
51
|
+
|
|
52
|
+
# manual fallback: publish to PyPI directly (normally handled by GitHub Actions on tag push)
|
|
53
|
+
[confirm("Are you sure you want to publish to PyPI directly? This is normally handled by GitHub Actions on tag push. Continue?")]
|
|
54
|
+
publish : build
|
|
55
|
+
uv publish
|
|
56
|
+
|
|
57
|
+
# delete and regen the lockfile - useful in merge conficts
|
|
58
|
+
lock:
|
|
59
|
+
del uv.lock -erroraction ignore
|
|
60
|
+
uv lock
|
|
61
|
+
|
|
62
|
+
# -----------------------------------------------------------------------------------------------
|
|
63
|
+
# HIL testing
|
|
64
|
+
# Configure environment for the port and firmware selection in the .env file, then run the test suite
|
|
65
|
+
# -----------------------------------------------------------------------------------------------
|
|
66
|
+
# export LOGURU_LEVEL := "TRACE"
|
|
67
|
+
export LOGURU_LEVEL := "INFO"
|
|
68
|
+
|
|
69
|
+
hil_uf2_pico2:
|
|
70
|
+
uv run pytest -m hw_uf2 tests/hw -v
|
|
71
|
+
|
|
72
|
+
hil_dfu_pybv11:
|
|
73
|
+
uv run pytest -m hw_dfu tests/hw -v
|
|
74
|
+
|
|
75
|
+
hil_pyocd_pybv11:
|
|
76
|
+
uv run pytest -m hw_pyocd tests/hw -v
|
|
77
|
+
|
|
78
|
+
hil_esptool_esp32:
|
|
79
|
+
uv run pytest -m hw_esptool tests/hw -v
|
|
80
|
+
|
|
81
|
+
# [script('python')]
|
|
82
|
+
# python:
|
|
83
|
+
# print('Hello from python!')
|
|
84
|
+
# from pathlib import Path
|
|
85
|
+
# print(f'Current directory: {Path.cwd()}')
|
|
86
|
+
|
|
87
|
+
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
"""Drive a board into bootloader mode using pluggable activators.
|
|
2
|
+
|
|
3
|
+
The orchestration walks the ordered list of activators returned by
|
|
4
|
+
:func:`mpflash.bootloader.registry.resolve_methods`, calling each in turn
|
|
5
|
+
and confirming with :func:`mpflash.bootloader.detect.in_bootloader` (which
|
|
6
|
+
delegates to the flash backend's ``is_board_ready`` when one is supplied).
|
|
7
|
+
|
|
8
|
+
Built-in activators register themselves on import; flash plugins can
|
|
9
|
+
contribute additional activators by calling
|
|
10
|
+
:func:`mpflash.bootloader.registry.register`.
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
from __future__ import annotations
|
|
14
|
+
|
|
15
|
+
import time
|
|
16
|
+
from typing import Optional
|
|
17
|
+
|
|
18
|
+
from mpflash.bootloader.detect import backend_for_port, in_bootloader
|
|
19
|
+
from mpflash.bootloader.registry import get_activator, resolve_methods
|
|
20
|
+
from mpflash.common import BootloaderMethod
|
|
21
|
+
from mpflash.errors import MPFlashError
|
|
22
|
+
from mpflash.logger import log
|
|
23
|
+
from mpflash.mpremoteboard import MPRemoteBoard
|
|
24
|
+
from mpflash.flash.base import FlashBackend
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def enter_bootloader(
|
|
28
|
+
mcu: MPRemoteBoard,
|
|
29
|
+
method: BootloaderMethod = BootloaderMethod.MPY,
|
|
30
|
+
timeout: int = 10,
|
|
31
|
+
wait_after: int = 2,
|
|
32
|
+
*,
|
|
33
|
+
backend: Optional[FlashBackend] = None,
|
|
34
|
+
) -> bool:
|
|
35
|
+
"""Put the board into bootloader mode.
|
|
36
|
+
|
|
37
|
+
Args:
|
|
38
|
+
mcu: The target board.
|
|
39
|
+
method: Which BootloaderMethod to try first. AUTO walks the
|
|
40
|
+
backend's preferred order. NONE skips activation entirely.
|
|
41
|
+
timeout: Per-attempt timeout in seconds.
|
|
42
|
+
wait_after: Seconds to wait between an activator call and the
|
|
43
|
+
readiness check.
|
|
44
|
+
backend: Optional flash backend used to look up the preferred
|
|
45
|
+
activator order and to confirm readiness via
|
|
46
|
+
``backend.is_board_ready``. When omitted, the flash registry is
|
|
47
|
+
consulted for a backend matching ``mcu.port``.
|
|
48
|
+
|
|
49
|
+
Returns:
|
|
50
|
+
True when the board is reported in bootloader mode, False if every
|
|
51
|
+
attempted activator failed.
|
|
52
|
+
"""
|
|
53
|
+
if method == BootloaderMethod.NONE:
|
|
54
|
+
# No bootloader requested — assume it is OK to flash.
|
|
55
|
+
return True
|
|
56
|
+
|
|
57
|
+
if backend is None:
|
|
58
|
+
backend = backend_for_port(mcu.port)
|
|
59
|
+
preferred = list(backend.get_preferred_bootloaders(mcu)) if backend else []
|
|
60
|
+
method_list = resolve_methods(method.value, preferred)
|
|
61
|
+
if not method_list:
|
|
62
|
+
log.debug(
|
|
63
|
+
f"No bootloader activators resolved for {mcu.port} (method={method.value})"
|
|
64
|
+
)
|
|
65
|
+
return True
|
|
66
|
+
|
|
67
|
+
log.info(
|
|
68
|
+
f"Entering bootloader on {mcu.serialport} using methods {method_list}"
|
|
69
|
+
)
|
|
70
|
+
|
|
71
|
+
result = False
|
|
72
|
+
for name in method_list:
|
|
73
|
+
activator = get_activator(name)
|
|
74
|
+
if activator is None:
|
|
75
|
+
log.debug(f"Unknown bootloader activator {name!r}; skipping")
|
|
76
|
+
continue
|
|
77
|
+
try:
|
|
78
|
+
result = bool(activator.activate(mcu, timeout=timeout))
|
|
79
|
+
except MPFlashError as e:
|
|
80
|
+
log.warning(
|
|
81
|
+
f"Failed to enter bootloader on {mcu.serialport} using {name}"
|
|
82
|
+
)
|
|
83
|
+
log.exception(e)
|
|
84
|
+
result = False
|
|
85
|
+
if not result:
|
|
86
|
+
continue
|
|
87
|
+
|
|
88
|
+
# todo - check every second or so for up to max wait time
|
|
89
|
+
time.sleep(wait_after)
|
|
90
|
+
if in_bootloader(mcu, backend=backend):
|
|
91
|
+
return True
|
|
92
|
+
|
|
93
|
+
serialport = mcu.serialport
|
|
94
|
+
if serialport and serialport.lower() != "auto":
|
|
95
|
+
try:
|
|
96
|
+
connected = {port.casefold() for port in MPRemoteBoard.connected_comports()}
|
|
97
|
+
except OSError:
|
|
98
|
+
connected = {serialport.casefold()}
|
|
99
|
+
if serialport.casefold() not in connected:
|
|
100
|
+
# The serial port vanished, so the board reset into its UF2
|
|
101
|
+
# bootloader. Do not fall through to touch-1200 (which would
|
|
102
|
+
# try to open a port that no longer exists). Give the UF2
|
|
103
|
+
# volume extra time to mount and confirm it is actually there
|
|
104
|
+
# before reporting success — otherwise the flash backend will
|
|
105
|
+
# abort with "Board is not in bootloader mode".
|
|
106
|
+
log.debug(
|
|
107
|
+
f"Serial port {serialport} disappeared after {name}; "
|
|
108
|
+
"waiting for the UF2 drive to mount"
|
|
109
|
+
)
|
|
110
|
+
if in_bootloader(mcu, backend=backend):
|
|
111
|
+
return True
|
|
112
|
+
log.warning(
|
|
113
|
+
f"{serialport} reset into bootloader but the UF2 drive "
|
|
114
|
+
"was not detected"
|
|
115
|
+
)
|
|
116
|
+
continue
|
|
117
|
+
|
|
118
|
+
return False
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
"""Abstract base class for pluggable bootloader activators.
|
|
2
|
+
|
|
3
|
+
An *activator* knows one way to put a board into firmware-update / bootloader
|
|
4
|
+
mode (e.g. send ``machine.bootloader()``, open the port at 1200 baud, or ask
|
|
5
|
+
the user to press a button). Built-ins live in
|
|
6
|
+
``mpflash.bootloader.builtins`` and register themselves at import time;
|
|
7
|
+
third-party flash plugins can call :func:`mpflash.bootloader.registry.register`
|
|
8
|
+
to contribute additional activators.
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
from __future__ import annotations
|
|
12
|
+
|
|
13
|
+
from abc import ABC, abstractmethod
|
|
14
|
+
from typing import TYPE_CHECKING
|
|
15
|
+
|
|
16
|
+
if TYPE_CHECKING:
|
|
17
|
+
from mpflash.mpremoteboard import MPRemoteBoard
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class BootloaderActivator(ABC):
|
|
21
|
+
"""Contract every bootloader activator must implement.
|
|
22
|
+
|
|
23
|
+
Subclasses are typically singletons; the registry instantiates each
|
|
24
|
+
activator once. The ``name`` attribute must match the corresponding
|
|
25
|
+
:class:`mpflash.common.BootloaderMethod` enum *value* for the built-in
|
|
26
|
+
activators (``"mpy"``, ``"touch1200"``, ``"manual"``); plugin-supplied
|
|
27
|
+
activators may use any unique string.
|
|
28
|
+
"""
|
|
29
|
+
|
|
30
|
+
#: Short identifier (matches ``BootloaderMethod.value`` for built-ins).
|
|
31
|
+
name: str = ""
|
|
32
|
+
|
|
33
|
+
def is_available(self, mcu: "MPRemoteBoard") -> bool:
|
|
34
|
+
"""Runtime availability check for this MCU.
|
|
35
|
+
|
|
36
|
+
Default returns ``True``. Activators with environmental
|
|
37
|
+
prerequisites (USB drivers, GUI prompts on a headless host, …)
|
|
38
|
+
should override.
|
|
39
|
+
"""
|
|
40
|
+
return True
|
|
41
|
+
|
|
42
|
+
@abstractmethod
|
|
43
|
+
def activate(self, mcu: "MPRemoteBoard", *, timeout: int = 10) -> bool:
|
|
44
|
+
"""Attempt to put ``mcu`` into bootloader mode.
|
|
45
|
+
|
|
46
|
+
Returns ``True`` if the activator believes the attempt succeeded;
|
|
47
|
+
the caller is responsible for confirming readiness afterwards.
|
|
48
|
+
"""
|
|
49
|
+
raise NotImplementedError
|
|
50
|
+
|
|
51
|
+
def __str__(self) -> str:
|
|
52
|
+
return f"{self.__class__.__name__}({self.name})"
|
|
53
|
+
|
|
54
|
+
def __repr__(self) -> str:
|
|
55
|
+
return f"<{self.__class__.__name__} name={self.name!r}>"
|