Newer libsigrokdecode signals end-of-capture from wait() by raising
EOFError("samples exhausted"); Linux 0.5.3 instead returns None / raises
SystemError, so this only reproduced on Windows. The framework explicitly
accepts EOFError out of decode() as normal termination, but decode() caught
it in the generic except Exception handler -- printing a traceback, logging
DECODE ERROR, and resyncing up to 50 times, which flooded the log at the end
of every capture.
- decode() and the five "except SystemError: raise" guards now use
"except (SystemError, EOFError): raise", letting the end-of-stream signal
propagate for a clean exit. The critical guard is
_measure_clock_period(), whose try wraps a wait() loop.
- 2 new unit tests assert decode() re-raises EOFError and SystemError.
- 67/67 unit tests; test_8/test_7/xiaomi_phone unchanged (Linux path).
VERSION -> 1.7.1.
The decoder could end decode() early on an idle/busy live line; the frontend
symptom was a flood of "sr_session_stop: session was NULL" after the session
stopped. Harden the EOF detection and stop the capture from dropping.
pd.py:
- _at_eof(): a step that consumes only queued bytes (_replay / peeked_byte,
e.g. the invalid-INS re-frame) no longer counts as end-of-capture; bounded
to 64 consecutive no-advance steps.
- _stall_check(track=False): the idle-LEVEL wait in wait_data_falling returns
immediately at the same sample on an idle line -- not EOF. Only "pins is
None" ends the wait there; sample-stall detection is kept for the edge wait.
- resync_idle(): guard wait()==None (was an unguarded pins[...] TypeError at
stream end).
Effect: samsung_phone_sample.sr had halted at ~21.9M/320M samples with 1 APDU;
it now decodes through ~293M to a true end (939 APDUs, CHKSUM 176). The 6
CONCAT packets are real mis-framed STK bursts now reachable (known Samsung
de-concatenation family). All other traces unchanged.
start.sh:
- Auto-restart is now the default (--no-loop disables) so an intermittent
FX2 USB stop reconnects instead of ending the session.
- Per-session pcap suffix (FILE.N.ext) so a restart never overwrites the
previous capture.
- Filter the repetitive "sr_session_stop: session was NULL" teardown line
from stderr (real decoder errors still pass).
Validation: test_8 56/0/OK, test_7 65/0/OK, xiaomi_phone 640, xiaomi_cold
473, 4gmodem 327, A55 407/395, S21p 399/375, target S21p 369; 0 CONCAT;
65/65 unit tests (10 new). VERSION -> 1.7.0.
Add hunt-side live ETU recovery so a card already at a non-default F/D
(e.g. Samsung F=512/D=32 -> 16 CLK/bit) can be decoded without a 372-rate
ATR, and bound the all-0xFF hunt so an idle/unsyncable line can never loop
forever.
- _recover_etu_in_hunt(): measure the live ETU from DATA edges while still
in FIND START, then re-derive clock_skip; reuses _confirm_etu validation.
- _atr_hunt_failure_action(): pure recover/retry/resume_data decision, with
ATR_HUNT_ETU_ATTEMPTS=3 / ATR_HUNT_IDLE_RESETS=3 / ATR_HUNT_FAIL_LIMIT=12.
- Persistent counters reset only on a successful ATR parse (not RST re-arm),
so RST-cycling phones cannot starve the escape.
- 8 new unit tests (55 total).
Validated on the full trace suite (test_8 56/0/OK, test_7 65/0/OK, xiaomi
640, xiaomi_cold 473, 4gmodem 327, A55 407/395, S21p 399/375, target S21p
369; 0 CONCAT, RESULT: OK) with no regressions.
- pd.py: remove _lock_etu_from_edges (long-disabled) and the no-op
while-True FIND START wrapper.
- pd.py: re-raise SystemError (libsigrokdecode's clean EOF signal) in the
six 'except Exception: pass' guards so put()/wait() at end-of-capture
exits cleanly instead of being swallowed.
- pd.py: fix _measure_clock_period docstring (averages, not robust-min);
drop stale 'line 1633' comment; document the synthetic pcap UDP header
(zero IP checksum / fixed loopback+ports are intentional).
- signal_diagnostic.py: add --max-samples cap + document whole-capture
RAM cost; fix stale '--rst/--vcc=ignore' guidance (-> --no-rst/--no-vcc).
- tests: make test_valid_cla_interindustry_classes use subTest (was a
no-op tuple expression).
- start.sh/start.bat: note the -A multi-spec form is sigrok-cli 0.7.x.
- Remove stale tests/baseline_new.txt (v1.1.3-era, ATR-included mode).
- Add top-level LICENSE (GPL-2.0-or-later).
- pd.py ts_from_samplenum: drop c_uint32 truncation + dead sampleOverflowCount
(pcap timestamps wrapped backwards past ~4.5 min at 16 MHz).
- pd.py handle_atr: guard None reads at EOF (was TypeError (None & 0x80) on a
capture truncated mid-ATR-hunt).
- start.bat: add --protocol (+ :protocol=T=0 default) to match start.sh's
mid-session decode; correct the 'flag-for-flag' header comment.
- start.sh: reject --rst/--vcc assigned to the same pin (was unchecked).
- setup.bat: set DEVICE_MSG on blocked/skipped probe so the trailing
'unknown' message is suppressed.
- vs_reader.py: RESULT now fails on CONCAT / payload mismatch / suspicious
CLA, not just GARBAGE (OK text unchanged; clean traces stay identical).
Residual CONCAT mis-frames (4gmodem/A55_sim2/S21p_sim2) traced to a silent
5-byte drop at an invalid-INS T=0 header (0x0f 00 a4 08 04). Drop only the
stray leading byte and re-frame the remaining four via _replay so the real
command (00 a4 08 04 02 2f 00 -> 61 1c) is recovered.
- _note_discard()/_consume_first(): every consumed-but-unemitted byte is
now logged; idle 0x00/0xFF discards are rate-limited, real data always
gets an ANN_WARN annotation.
- All read-until-SW loops log skipped non-SW bytes.
- All traces: CONCAT 0; BAD_FCS/GARBAGE 0; test_8/test_7 RESULT OK;
47/47 unit tests; baseline byte-identical.
History rewritten to a single root commit so no example trace is stored
in the repo (fixtures are local-only, gitignored). README keeps only
generic <trace>.sr placeholders; AGENTS.md retains the fixture names.