- parse_dtcs CAN branch is now message-aware: each ECU reply '<svc> <count>
<pairs>' has its header stripped per-message, instead of flattening all lines
and stripping svc+count once. With multiple ECUs the old code ate the second
header as a DTC pair -> phantom codes. Critically, it does NOT blind-scan for
svc (0x43 is a legal DTC first byte: C03xx) — a numbered ISO-TP continuation
is distinguished by its 'N:' frame-index prefix, not by value.
- _line_bytes strips hex frame indices A:-F: (ISO-TP index cycles 0-F), not just
0-9, so consecutive frames past the 10th aren't dropped.
- read_freeze_frame sends the correct '020200' (svc 02, PID 02, frame 00) and
skips SID+PID+frame (+3), fixing the off-by-one that mis-read the freeze DTC.
- tests/test_dtc_parse.py: single-frame, multi-ECU (no phantom), numbered
multiframe with a real C03xx continuation, hex index, non-CAN legacy.
Closes#9
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016yT89n4zR4qbrySoSiEyZs