Skip to content

ascii: discard stray bytes outside the frame#15

Open
andig wants to merge 2 commits into
masterfrom
fix/ascii-frame-extraction
Open

ascii: discard stray bytes outside the frame#15
andig wants to merge 2 commits into
masterfrom
fix/ascii-frame-extraction

Conversation

@andig

@andig andig commented Jun 6, 2026

Copy link
Copy Markdown
Member

Problem

Some serial adapters insert stray bytes around Modbus ASCII frames. The FTDI FT2232H based ABL Confcab adapter (used to talk to ABL eMH1 wallboxes) wraps each response in NUL (0x00) bytes before and after the frame. The ASCII driver assumed the received buffer is exactly :<CR><LF>, so these extra bytes broke:

  • the start-character check (aduResponse[0] was 0x00, not :)
  • the even-length / CRLF terminator checks
  • LRC verification

…which surfaced as timeouts when reading from the wallbox. Users have had to run an external proxy to clean the stream.

Reported in evcc-io/evcc discussion #16328.

Fix

Per @premultiply: ignore everything outside the frame. A valid frame starts with a start character (: or >), contains only hexadecimal digits and ends with <CR><LF>.

  • extractASCIIFrame skips to the start character, keeps only hex digits, and stops at the terminating CRLF — dropping any stray bytes before, after or interspersed. If no start character is present the input is returned unchanged so verification still reports the original response.
  • The read loop now detects the terminator anywhere in the buffer (bytes.Contains) instead of only at the very end, so trailing junk after CRLF no longer delays the read until timeout.

The raw bytes are still logged before sanitization.

Tests

Added TestExtractASCIIFrame (clean, leading/trailing/surrounding/interspersed NUL, > start, lone LF, no start char, no terminator) and TestASCIIDecodeDirtyFrame (NUL-wrapped frame passes Verify + Decode). All ASCII tests pass; go build ./... and go vet clean for the package.

Some serial adapters (e.g. the FTDI based ABL Confcab) inject stray bytes
such as NUL before, after or in between the Modbus ASCII frame. These broke
framing and LRC verification, causing timeouts.

Extract the frame from the raw response by skipping to the start character,
keeping only hexadecimal digits and stopping at the terminating CRLF. The
read loop now also detects the CRLF anywhere in the buffer so trailing junk
no longer delays the read.
Comment thread asciiclient.go Outdated

// isHexDigit reports whether b is an ASCII hexadecimal digit (0-9, A-F, a-f).
func isHexDigit(b byte) bool {
return b >= '0' && b <= '9' || b >= 'A' && b <= 'F' || b >= 'a' && b <= 'f'

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

only 0-9 or A-F (uppercase) is allowed inside a frame between the delimiters.

Other chars inside should instantly break as framing error.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

would be simpler to just suggest the actual change ;)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Yes, but I am currently at mobile phone.

Other chars inside should instantly break as framing error.

Is that also implemented and tested regarding data inside a frame?

Comment thread asciiclient.go Outdated
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