All notable changes to this project will be documented in this file.
The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.
0.1.2 - 2026-05-13
adapters::{blocking,tokio}::UploadOptions.progress— optionalBox<dyn FnMut(Progress) + Send>callback fired once after each acknowledged WRITE. TheProgresspayload exposes cumulativebytes_sent,chunks_sentandsource_bytesso callers can drive their own UI / rate calculations.
UploadOptionsno longer derivesClone(the newprogressfield holds aFnMutclosure).Debugis preserved via a manual impl, so the existing..UploadOptions::default()patterns keep working.
- 0.1.1 was published with experimental
Progress::percent()/fraction()helpers and immediately yanked. 0.1.2 ships the same progress callback without those helpers.
0.1.0 - 2026-05-11
Initial public release.
file_transfer: state-gatepending_asciisetters for everyPFT:*variant. Previously a strayPFT:busy/fail/ioerror/invalid/versionline arriving whileAwaitingWriteAckwould corrupt that slot and cause the legitimateok<n>to be silently swallowed; the nextwrite()would then panic with state stillAwaitingWriteAck. Now out-of-context PFT lines are cleanly ignored.adapters::tokio: everytransport.read(..).awaitis now wrapped intokio::time::timeout(session.response_timeout(), ..). Without this, a quiet transport meant the loop never reachedsession.tick(), so the retransmit and total-budget timeouts were effectively dead code.adapters(both blocking and tokio):drive_session_until_syncednow surfacesFileError::SessionFatalError/SessionTimeout/SessionOutOfSyncinstead of always returning the genericUploadError::HandshakeFailedafter exhausting the retry budget.adapters(both blocking and tokio): send the control-plane CLOSE (proto=0, type=2) after a successful upload so the device exits binary mode and resumes accepting ASCII g-code on the same serial session. Previously the device remained in binary mode afterupload()returnedOk.
Session::response_timeout()/Session::total_timeout()andFileTransfer::response_timeout()accessors so adapters and external callers can bound their own I/O against the session's timing configuration.- Tokio's
timefeature is now enabled by thetokiofeature flag. - New integration test
tests/blocking_adapter_e2e.rsdriving the blocking adapter against an in-memoryRead+Writetransport, asserting the control CLOSE lands on the device. - Initial repository scaffold: dual MIT/Apache-2.0 license, README, CI scaffolding, module placeholders.
- Codec layer (
codec) — packet encode/decode, Fletcher-16 mod-255, full error variants, validated against the Python reference fixtures. - Sans-I/O session state machine (
session) — sync handshake, ack matching, retransmit on response timeout, total-budget timeout, resend-request and fatal-error pass-through. - File-transfer state machine (
file_transfer) — QUERY / OPEN / WRITE / CLOSE / ABORT, with compression negotiation (none, heatshrink, auto). - Optional heatshrink wrapper (
compression, behindheatshrinkfeature) usingembedded-heatshrink. - Adapters (
adapters::blocking,adapters::tokio,adapters::serialport) wrapping the sans-I/O core for the common transport choices. - Examples:
examples/upload.rs(CLI mirror of Python'stransfer.py) andexamples/inspect.rs(decoder for captured byte streams). - Criterion benches for codec encode/decode and Fletcher-16.
cargo-fuzztarget for the decoder.
The wire format and reference behaviour are taken from Marlin's
Binary File Transfer Mark II PR (#14817)
and the Python reference implementation
marlin-binary-protocol
(MIT) by Chris Pepper (@p3p). This is an independent Rust port of the
documented protocol.