Skip to content

tools: a refused delete sends the board no path - #95

Merged
SensoriumEmbedded merged 1 commit into
SensoriumEmbedded:mainfrom
kfox:bench-delete-checks-ack
Nov 10, 2026
Merged

SensoriumEmbedded merged 1 commit into
SensoriumEmbedded:mainfrom
kfox:bench-delete-checks-ack

Conversation

@kfox

@kfox kfox commented Nov 10, 2026

Copy link
Copy Markdown
Contributor

Link.delete() in tools/bench/trlink.py sent its drive byte and path whatever the reply to its token was. While any IO handler other than the menu's is current, the full firmware answers a file command with FailToken and Busy! and reads nothing more (SerUSBIO.ino, the CurrentIOHandler != IOH_TeensyROM refusal), so the path bytes that followed were run as one-letter serial commands. Pushing /c128test/t80b.prg to a board with REU+USB Mouse/Disk as Special IO reset its EEPROM to defaults (the e in "test"), cleared the debug log (c) and started a timing command (t). post() deletes first, so every push.py to a busy board did this, and the Busy! on the post token that followed hid it.

delete() now checks its token reply with ack(), as post(), listdir() and launch() already did. A refused delete sends nothing further and fails as delete <path>: FAIL - Busy!. The delete's second reply is still not checked, because the firmware answers "File not found" for a new file, which is the usual case for a push.

The other bench tools were checked for the same pattern: spans.py already checks for the ack before each payload, and the rest send each command in one write or send nothing after a reply.

Verification

  • A new test, test_a_busy_board_is_sent_no_path_to_run_as_commands, pushes to a fake board that refuses file commands while busy and records every byte the firmware would run as a command. Before the fix it failed with b'\x01/c128test/t80b.prg\x00' != b''; after, it passes. Putting the old self.rd(2) back in place of the ack check makes it fail again.
  • python3 -m unittest discover -s tools/bench: 86 tests, OK. npm test: pass.
  • The EEPROM reset was seen on a TR+ in an NTSC C128 (the settings page showed Special IO back to None after a refused push). The fix itself is host tested only; no firmware changes.

Reviewed at low (23 changed code lines), no findings.

Link.delete() sent the drive byte and the path whatever its token's reply
was. A board with any IO handler but the menu's current answers a file
command with FailToken and "Busy!" and goes back to reading one-letter
serial commands, so it ran the path as commands: in /c128test/t80b.prg the
'e' reset its EEPROM to defaults, 'c' cleared the debug log and 't' changed
bus timing. post() deletes first, so every push to a busy board did this,
and the post token's own "Busy!" afterwards hid it.

delete() now goes through ack() like post(), listdir() and launch(), so a
refusal stops it and is reported as the delete that was refused. The fake
board in the tests refuses file commands while busy and records the bytes
the firmware would run as commands.
@kfox
kfox marked this pull request as ready for review November 10, 2026 15:05

@SensoriumEmbedded SensoriumEmbedded left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for catching this one, an EEPROM reset from a file push is a nasty one to track down!

I reviewed this merged onto current main (ac24701). Nothing to change, merging now.

Thank you!

@SensoriumEmbedded
SensoriumEmbedded merged commit c8ad12b into SensoriumEmbedded:main Nov 10, 2026
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants