[READ-ONLY] Mirror of https://github.com/SantaClaas/embedded-fan-control.

Split the modbus error so it cannot name a part its function never reads master

Error and Part were shared between the two functions, so the type allowed states no execution could produce: a write failing on Part::Data, a read failing on Part::Echo, InvalidResponse::Echo coming back from a read, InvalidResponse::ByteCount from a write, and Checksum(Part::Header) from anything, since the header is two bytes and carries no checksum of its own. The split follows the seam already in the code. send_request and read_header are shared, so what they can fail with is ExchangeError, and Part is now only the two parts they read, Header and Exception. Each transaction adds what only it reads: WriteError names the echo, ReadError names the byte count and the register contents. Neither can name the other's, and From<ExchangeError> for both keeps `?` reading the same at the call sites. The failure modes themselves stay shared rather than being duplicated per function. SendFailure and ReceiveFailure describe how a run of bytes failed, and whoever was reading attributes it to a part: ExchangeError::Response pairs it with a Part, while WriteError::Echo and ReadError::Contents need no part because each function has exactly one body. read_exact became receive_exact and returns ReceiveFailure instead of taking a Part, since the caller is the only one that knows which read it was. This flattens the Error/InvalidResponse nesting, which grouped transport failures apart from a device that answered wrongly. Nothing matched on it, and the grouping is still readable in the variants themselves: Request and Response are transport, the rest are the fan disagreeing. Behaviour is unchanged. Both call sites only format the error for the log, and the log now reads Exchange(Response(Header, Timeout)) or Echo(Incomplete) instead of ResponseTimeout(Header) or InvalidResponse(Incomplete(Echo)). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>


+122 -84
2 changed files