Bug fixes, UF2 hardening, A/B partition support, verified flashing, BOOTSEL reset, tests + CI#1
Open
DavidMenting wants to merge 9 commits into
Open
Bug fixes, UF2 hardening, A/B partition support, verified flashing, BOOTSEL reset, tests + CI#1DavidMenting wants to merge 9 commits into
DavidMenting wants to merge 9 commits into
Conversation
…ndpoint, honest OTP write reporting - pkg/index.js re-exported FLASH_END_RP2040/RP2350 which don't exist in constants.js, making 'import picoflash' throw at module load - checkAndClearHalts tested unawaited promises (always truthy) - bulkWrite stall recovery cleared halt on the IN endpoint instead of OUT - removed duplicate getHaltState (isEndpointHalted kept) - removed spurious resetInterface(true) argument - OTP write UI logged success while the write was commented out; now calls otpWrite (which throws its safety lockout) so the user sees the truth - JSDoc cast typos
- 20 unit tests: PICOBOOT command wire format, status parsing, UF2 reassembly, Connection framing and stall recovery (with mock USBDevice) - GitHub Actions: eslint + vitest on push/PR - root:true in .eslintrc.json, fix floating promise in footer.js
- New pkg/uf2.js: uf2ToSegments groups blocks by family, honors NOT_MAIN_FLASH and FAMILY_ID_PRESENT flags, fills sub-sector gaps with 0xFF and splits across larger gaps; rejects overlapping/corrupt blocks - validateSegmentsForTarget refuses wrong-chip families (picotool rules) and segments addressed outside the XIP flash window - uf2ToFlashBuffer kept as legacy single-image wrapper - js/uf2/uf2.js is now a re-export shim; pkg ships uf2.js - UI loads firmware as segments, logs each, validates at flash time - 16 new tests; decoder cross-checked against picotool uf2 convert output
- PicobootCmd.getInfo + Connection.getInfo (RP2350) - pkg/info.js: parseSysInfo, parsePartitionTable (Partition/PartitionTable with A/B link and accepts-family decoding), parseUf2TargetPartition, flashSizeFromDevinfo; constants from pico-sdk bootrom headers - Picoboot.getSysInfo/getPartitionTable/getUf2TargetPartition; flashSegments writes family segments to the bootrom-designated partition (the inactive A/B slot) with address translation and fit checking; rebootFlashUpdate uses the FLASH_UPDATE reboot type - UI: Device Info block (chip id, cpu, devinfo flash window, partitions) on connect; Flash uses flashSegments and logs target partitions; Reboot uses FLASH_UPDATE after a partition flash - 10 new tests; wire format cross-checked against picotool sources and the connected Pico 2 (3-partition A/B table)
- flashEraseAndWrite now erases/writes per chunk (default 64KB, sector aligned), pads the final write to a page boundary, optionally verifies each chunk by read-back (failing with the mismatch address), and reports progress via an onProgress callback - flashSegments forwards options with cumulative cross-segment progress - Connection.bulkRead/bulkWrite race against this.timeouts.endpoint, so hung transfers surface as errors and recovery resets the interface - UI: Verify checkbox (default on); flash progress bar driven by real progress instead of a time estimate - 8 new tests covering chunk sequencing, padding, progress, verify
- pkg/serial-reset.js: resetToBootsel() opens the device's CDC port at 1200 baud (pico-sdk stdio-USB reset convention) via WebSerial; waitForPicobootDevice() polls for re-enumeration of authorized devices - UI: 'Reboot to BOOTSEL (serial)' button next to Connect, disabled with explanation on browsers without WebSerial
- CHANGELOG 0.2.0 entry covering fixes and new functionality - README fork note and feature list - pkg version 0.2.0, repository URL points at datomusic/picoflash
Hardware testing on a Pico 2 found two issues: - Flashing a UF2 containing picotool's absolute-block marker (one block at 0x10ffff00) failed with an alignment error: the marker is bootrom UF2-download metadata, not image data, and sits outside fitted flash. flashSegments now skips it (and tolerates partition-table read failures by falling back to absolute addressing). - The 1200-baud WebSerial touch did not reset the device on macOS. Added resetToBootselVendor(): the pico-sdk vendor reset interface via WebUSB (class 0xFF/0x00/0x01, RESET_REQUEST_BOOTSEL class request), the same mechanism as picotool reboot -f, which is verified working with this firmware. The UI button now uses it, falling back to the serial touch when WebUSB is unavailable; the serial recipe also gained the conventional DTR-deassert + delay.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
First development pass on the datomusic fork, keeping it generic/upstream-friendly (no Dato-specific features). Eight commits, each phase separately cherry-pickable:
pkg/index.jsre-exported non-existent constants, breakingimport 'picoflash'at module load; missingawaits in endpoint-halt checks; write-stall recovery cleared the halt on the wrong (IN) endpoint; the OTP-write UI logged success while the write was disabled; misc cleanup.pkg/uf2.js: decodes into per-family segments, honorsNOT_MAIN_FLASH/FAMILY_ID_PRESENTflags, validates families against the connected chip (refuses RP2040 UF2s on RP2350 and vice versa), rejects segments outside flash. Cross-checked byte-for-byte againstpicotool uf2 convertoutput.pkg/info.jsparses SYS_INFO and partition tables (A/B links, accepted families; wire format from pico-sdk bootrom headers and picotool).flashSegmentsasks the bootrom which partition a family targets — the inactive A/B slot — translates addresses, andrebootFlashUpdateboots the new image via the FLASH_UPDATE reboot type. Device Info panel in the UI.onProgressdriving the UI bar, and per-transfer endpoint timeouts inConnection.pkg/serial-reset.js: vendor reset interface over WebUSB (same mechanism aspicotool reboot -f), with the 1200-baud WebSerial touch as fallback. UI button next to Connect.Why
Basis for a web-based firmware-update flow for an RP2350-based instrument: it needs A/B updates, verified writes, and a way to reboot a running device into the bootloader without touching the BOOTSEL button.
Verification
picotool info -a/picotool partition info; a multi-segment DRUM UF2 flashes with verify to the inactive slot (picotool's absolute-block marker at 0x10ffff00 is correctly skipped) and the FLASH_UPDATE reboot boots it.Reviewer notes
boot/picoboot_constants.h,boot/bootrom_constants.h,boot/picobin.hand picotool's usage, not guessed; constants are quoted inpkg/info.js.flash devinforeports the XIP window (16MB on unfused parts), not fitted flash size — the UI labels it "up to … (devinfo)". A mirror-detection size guess like picotool's would be a follow-up.Connection.otpWrite; the UI now surfaces that honestly instead of logging a fake success.