Fix direct-write upload hanging on stall or error frame (MJ-19)#28
Merged
jonasniesner merged 1 commit intoJul 6, 2026
Merged
Conversation
The direct-write flow had no ACK timeout and ignored mid-stream error
frames, so a stalled transfer or a firmware error left the UI stuck at
"Uploading N%" forever with onComplete/onError never firing.
- Add a per-ACK timeout (DIRECT_WRITE_ACK_TIMEOUT_MS, 8s, matching the
config-write path) armed when sending the start command, chunks, and
the end command, and re-armed on each recognized ack. On expiry the
upload aborts via _abortDirectWrite, firing onComplete(false, err) and
clearing directWriteState so a later upload isn't blocked by a stuck
active flag. The timer is cleared once the end command acks (0x72), so
the display-refresh phase stays bounded by the firmware's own refresh
timeout (0x74) rather than the ack timer.
- handleDirectWriteNotification now recognizes mid-stream error frames at
any point in the flow: a 4-byte {0xFF,cmd,err,0x00} NACK for any
direct-write opcode, and the 2-byte {0xFF,0xFF} compressed-error frame.
Both abort the operation cleanly with a descriptive message. The
existing partial-start NACK fallback-to-full behavior is preserved.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012g2e8mr132vcizx92WsgiR
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.
Problem
The BLE direct-write flow in
httpdocs/js/ble-common.jshad no ACK timeout and ignored mid-stream error frames. As a result a stalled transfer or a firmware error frame left the UI stuck at "Uploading N%" forever, withonComplete/onErrornever firing. BecausedirectWriteState.activestayedtrue, a subsequent upload was also blocked by "Direct write already in progress".Two concrete gaps:
sendNextDirectWriteChunk/_activateFullDirectWrite) had no timer, so silence from the device hung indefinitely.handleDirectWriteNotificationonly recognized a NACK whileawaitingPartialStart, so a mid-stream{0xFF,0x71,err,0x00}NACK or the 2-byte{0xFF,0xFF}compressed-error frame matched no pattern →pendingAcksnever drained.Fix
DIRECT_WRITE_ACK_TIMEOUT_MS = 8000, matching the existing config-write ack timeout) armed when sending the start command, chunks, and the end command, and re-armed on each recognized ack. On expiry the upload aborts via the existing_abortDirectWritepath, firingonComplete(false, err)and clearingdirectWriteState. The timer is cleared once the end command acks (0x72), so the display-refresh phase remains bounded by the firmware's own refresh timeout (0x74) rather than the short ack timer.handleDirectWriteNotificationrecognize mid-stream error frames at any point in the flow: a 4-byte{0xFF,cmd,err,0x00}NACK for any direct-write opcode, and the 2-byte{0xFF,0xFF}frame. Both fail the operation cleanly with a descriptive message. The existing partial-start NACK fallback-to-full behavior is preserved.The change is scoped to the direct-write send/notification path; encoding/image code is untouched.
Verification
node --check httpdocs/js/ble-common.jspasses.handleDirectWriteNotificationin a small Node/VM harness: a{0xFF,0xFF}frame and a mid-stream{0xFF,0x71,err,0x00}NACK each returntrue, fireonComplete(false, err)once with a descriptive message, and resetdirectWriteStatetonull. Confirmed the partial-start NACK still falls back to full (no hard abort), and that the ack-timeout path aborts a stalled transfer and cleans up state.