{{ message }}
Repository navigation
Discard what a failed remote transfer still sends, and don't block on flush - #40
Merged
SensoriumEmbedded merged 8 commits intoOct 23, 2026
Merged
Conversation
Owner
kfox
marked this pull request as draft
September 29, 2026 15:21
Contributor
Author
|
This may be rewritten or closed later. A small subset of the changes in this PR will be added to another PR as a requirement to support the PR#43 changes. |
Contributor
@kfox Why don't you rebase this branch with main and I will do some testing. Seems you have some conflicts to resolve at the moment. |
A transfer's only bound was the per-byte timeout, so a peer trickling one byte just inside it held loop() -- and with it the C64 menu -- for as long as it liked: 65535 x 500 mS for a WriteC64Mem, and longer for a file. Receiving and sending a file and WriteC64Mem now stop at TransferCeilingmS(len), a floor plus the length at a rate well under what each channel really does, and answer FailToken with how far they got. After a failed receive, DrainCmdChannel discards what the peer is still sending, bounded itself, so the rest of the payload is not read as the next command. And the flushes on these paths go through FlushCmdChannel, which does not block: EthernetClient::flush() and the USB host serial's flush wait with no deadline for a peer to acknowledge.
kfox
force-pushed
the
fw-transfer-deadlines
branch
from
October 9, 2026 03:29
a18d4a1 to
08c44a5
Compare
No peer has been seen trickling bytes just under the per-byte timeout, and one that could already has full control of the board. A failed receive now discards the rest of its payload through the existing DiscardCmdInput instead of a second drain helper.
# Conflicts: # Source/Teensy/SerUSBIO.ino
kfox
marked this pull request as ready for review
October 22, 2026 03:15
Owner
…ommand start DiscardCmdInput stops 2 S past SpansCeilingmS(Bytes), measured from Began. ReceiveFileData and WriteC64Mem passed the command's start and its whole length, so a transfer averaging under 2 bytes/mS that failed late was already past the ceiling: the drain returned at once and the rest of the payload ran as commands. They now pass millis() and the bytes still owed, so the ceiling is the remainder's time at 2 bytes/mS from the failure. The no-memory-to-stage drain in WriteC64Mem is the same shape and gets the same arguments. The comments over SpansCeilingmS and DiscardCmdInput described a command deadline that only WriteC64Spans still has.
ReceiveFileData closes the file and returns false on a timeout and on a checksum failure, leaving a truncated or corrupt file on the card. GetFileStream refuses a file that already exists, so the client's retry got "File already exists", and the broken file could be launched as a cart or program. PostFileCommand now removes it on either failure. GetFileStream only ever creates a new file, so this cannot delete anything the user already had.
SensoriumEmbedded
added a commit
that referenced
this pull request
Oct 24, 2026
The responses posted on PR #39 and PR #40, copied from GitHub, as references for the shape of a draft. Both predate the current tone rules, so the skill says the rules win where an example differs. The tone rules change with them: - The first response thanks the author for the work itself, not only its testing. - Memory improvements are requested changes before merging, each its own bullet (the lever, what it saves, why it's safe). - The hardware-testing heading carries the framing: for one of us to possibly get to before release, not gates, with anything unlisted covered or fine. The "everything else" line and the offer of a hand are gone. - When one author gets responses on several related PRs at once, the shared lines go only in the first.
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.

Split out of #37 and independent of the extension work. Based on
main.The problem.
WriteC64Memhits the per-byte timeout (the PC pauses for more than 500 mS, for example), the bytes the peer still sends are parsed as the next commands.EthernetClient::flush()and the USB host serial'sflush()wait for the peer to acknowledge, with no deadline, so a peer that disappears mid-transfer can hangloop(). The writes themselves can block too (see the follow-ups).The fix.
WriteC64Memnow discard what the peer is still owed through the existingDiscardCmdInput, which is itself bounded. It andSpansCeilingmSmove out of#ifdef Fab04_FullDMACapableso the plain TR build has them too.millis()and the bytes still owed, so the ceiling is the remainder's time at 2 bytes/mS plus the slack.PostFileCommandremoves the file whenReceiveFileDatafails, on a timeout or a checksum failure.GetFileStreamonly creates new files, so it cannot delete anything that was there before.FlushCmdChannel, which does not block.Merging alongside the others
FlushCmdChannel, at the same spot. Git merges the two into one definition (git merge-tree).WriteC64Memcommand. That merges cleanly too.Measured on this branch
--target tr-plusand--target trboth build clean.npm testpasses 167/167.18e299f7. AWriteC64Memand aPostFileeach declared 1000 bytes. Each sent 100 bytes, stalled 0.7 s, then sent the rest asVersionInfotokens.Timeout!with its failure, then nothing, and the next command was answered once.Not measured: the Ethernet and USB-host channels, and the no-deadline
flush()claim against those libraries' source. The upload removal and the drain-from-failure change (the commits after18e299f7) are built and unit-tested only; no hardware run yet, including a plain TR.Proposed follow-ups
EthernetClass::socketSendwaits for room in the send buffer, andUSBSerialBase::writein USBHost_t36 does the same, so a reply larger than the free buffer can still hangloop()when the peer has vanished. This belongs with the overall deadline below.loop(), and with it the C64 menu, for 65535 × 500 mS (9.1 hours) on aWriteC64Mem, and longer for a file. Left out because no real client has been seen doing it, and a peer that can open the command channel can already launch files, write C64 memory and flash firmware. A per-channel version of this was measured in an earlier revision of this PR: 1000 bytes at one byte every 300 mS answeredToo slow, 18 of 1000 bytesafter about 5.4 s.