Fix pcap timestamp wrap, ATR-hunt EOF crash, start.bat protocol; tighten launchers + vs_reader
- 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).
This commit is contained in:
1 parent
9d00827837
commit
e6ff3a2e14
5 files changed
+46
-12
No files matched your search
@@ -20,7 +20,6 @@ import struct
|
|||||||
import sys
|
import sys
|
||||||
import time
|
import time
|
||||||
import codecs
|
import codecs
|
||||||
import ctypes
|
|
||||||
import traceback
|
import traceback
|
||||||
from collections import deque
|
from collections import deque
|
||||||
|
|
||||||
@@ -450,7 +449,6 @@ class Decoder(srd.Decoder):
|
|||||||
# card was already in reset" indistinguishable from a live session.
|
# card was already in reset" indistinguishable from a live session.
|
||||||
self._primed = False
|
self._primed = False
|
||||||
self.lastSamplePositive = True
|
self.lastSamplePositive = True
|
||||||
self.sampleOverflowCount = 0
|
|
||||||
# Rolling parity-error monitor: warns when the wire degrades
|
# Rolling parity-error monitor: warns when the wire degrades
|
||||||
# (e.g. GSM TX bursts coupling into the probe wiring).
|
# (e.g. GSM TX bursts coupling into the probe wiring).
|
||||||
self.parity_hist = deque(maxlen=64)
|
self.parity_hist = deque(maxlen=64)
|
||||||
@@ -755,9 +753,12 @@ class Decoder(srd.Decoder):
|
|||||||
self.wrote_pcap_header = True
|
self.wrote_pcap_header = True
|
||||||
|
|
||||||
def ts_from_samplenum(self, sample):
|
def ts_from_samplenum(self, sample):
|
||||||
x = ctypes.c_uint32(sample).value;
|
# Use the full sample number. The previous c_uint32 truncation (plus
|
||||||
ovrflow = ctypes.c_uint32(int(self.sampleOverflowCount * 0xFFFFFFFF * self.secs_per_sample)).value
|
# an overflow counter that was never incremented) made pcap timestamps
|
||||||
ts = float(x) * self.secs_per_sample + ovrflow + self._pcap_base_time
|
# wrap and go backwards once a capture passed 2^32 samples (~4.5 min
|
||||||
|
# at 16 MHz). float64 holds sample numbers well past 2^53, so the
|
||||||
|
# whole sample domain is representable.
|
||||||
|
ts = float(sample) * self.secs_per_sample + self._pcap_base_time
|
||||||
return (int(ts), int((ts % 1.0) * 1e6))
|
return (int(ts), int((ts % 1.0) * 1e6))
|
||||||
|
|
||||||
def signal_quality(self, err):
|
def signal_quality(self, err):
|
||||||
@@ -1556,6 +1557,10 @@ class Decoder(srd.Decoder):
|
|||||||
self.put(atr_start, self.samplenum, self.out_ann,
|
self.put(atr_start, self.samplenum, self.out_ann,
|
||||||
[Ann.ANN_WARN, ["Invalid TS byte 0x{byte:02x} - skipped".format(byte=byte)]])
|
[Ann.ANN_WARN, ["Invalid TS byte 0x{byte:02x} - skipped".format(byte=byte)]])
|
||||||
byte = self.read_byte()
|
byte = self.read_byte()
|
||||||
|
if byte is None:
|
||||||
|
# End of capture mid-hunt: stop cleanly instead of raising
|
||||||
|
# TypeError (None & 0x80) in the next loop iteration.
|
||||||
|
return
|
||||||
atr_start = self.ss
|
atr_start = self.ss
|
||||||
ts_attempts += 1
|
ts_attempts += 1
|
||||||
if (byte not in (0x3b, 0x3f)):
|
if (byte not in (0x3b, 0x3f)):
|
||||||
@@ -1599,6 +1604,8 @@ class Decoder(srd.Decoder):
|
|||||||
ts=byte, conv="inverse" if self._inverse_convention else "direct"))
|
ts=byte, conv="inverse" if self._inverse_convention else "direct"))
|
||||||
|
|
||||||
t0 = self.read_byte()
|
t0 = self.read_byte()
|
||||||
|
if t0 is None:
|
||||||
|
return
|
||||||
self.ATR.append(t0)
|
self.ATR.append(t0)
|
||||||
# Lock ETU from the first two ATR bytes (TS + T0). The ATR is sent
|
# Lock ETU from the first two ATR bytes (TS + T0). The ATR is sent
|
||||||
# at the default ETU, so its edge spacings are the authoritative
|
# at the default ETU, so its edge spacings are the authoritative
|
||||||
|
|||||||
@@ -106,10 +106,12 @@ for %%r in (1M 2M 4M 8M 12M 16M 20M 24M) do (
|
|||||||
-P "iso7816:clk=D0:data=D1" >"%TEMP%\iso7816-probe.txt" 2>&1
|
-P "iso7816:clk=D0:data=D1" >"%TEMP%\iso7816-probe.txt" 2>&1
|
||||||
type "%TEMP%\iso7816-probe.txt" | findstr /c:"Unable to claim" >nul && (
|
type "%TEMP%\iso7816-probe.txt" | findstr /c:"Unable to claim" >nul && (
|
||||||
echo blocked - another program holds the device
|
echo blocked - another program holds the device
|
||||||
|
set "DEVICE_MSG=1"
|
||||||
goto :probedone
|
goto :probedone
|
||||||
)
|
)
|
||||||
type "%TEMP%\iso7816-probe.txt" | findstr /c:"Failed to open" /c:"No devices found" >nul && (
|
type "%TEMP%\iso7816-probe.txt" | findstr /c:"Failed to open" /c:"No devices found" >nul && (
|
||||||
echo skipped - no FX2 device connected
|
echo skipped - no FX2 device connected
|
||||||
|
set "DEVICE_MSG=1"
|
||||||
goto :probedone
|
goto :probedone
|
||||||
)
|
)
|
||||||
type "%TEMP%\iso7816-probe.txt" | findstr /r /c:"invalid argument" /c:"Unable to sample" /c:"Could not start" >nul || set MAX_RATE=%%r
|
type "%TEMP%\iso7816-probe.txt" | findstr /r /c:"invalid argument" /c:"Unable to sample" /c:"Could not start" >nul || set MAX_RATE=%%r
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
@echo off
|
@echo off
|
||||||
rem sigrok_iso7816_stream launcher (Windows): capture ISO 7816 and stream
|
rem sigrok_iso7816_stream launcher (Windows): capture ISO 7816 and stream
|
||||||
rem GSMTAP to :4729. Flag-for-flag equivalent of start.sh.
|
rem GSMTAP to :4729. Mirrors the core start.sh flags (channel/samplerate/
|
||||||
|
rem clock/gsmtap/pcap/protocol/debug); start.sh has the full flag set.
|
||||||
|
|
||||||
setlocal EnableExtensions EnableDelayedExpansion
|
setlocal EnableExtensions EnableDelayedExpansion
|
||||||
|
|
||||||
@@ -15,6 +16,7 @@ set "PORT=4729"
|
|||||||
set "PCAP="
|
set "PCAP="
|
||||||
set "DEBUG="
|
set "DEBUG="
|
||||||
set "ANNOT=iso7816=apdus,iso7816=warnings"
|
set "ANNOT=iso7816=apdus,iso7816=warnings"
|
||||||
|
set "PROTOCOL=T=0"
|
||||||
|
|
||||||
:argloop
|
:argloop
|
||||||
if "%~1"=="" goto :argsdone
|
if "%~1"=="" goto :argsdone
|
||||||
@@ -28,6 +30,7 @@ if /i "%~1"=="--host" ( set "HOST=%~2" & shift & shift & goto :arg
|
|||||||
if /i "%~1"=="--port" ( set "PORT=%~2" & shift & shift & goto :argloop )
|
if /i "%~1"=="--port" ( set "PORT=%~2" & shift & shift & goto :argloop )
|
||||||
if /i "%~1"=="--pcap" ( set "PCAP=%~2" & shift & shift & goto :argloop )
|
if /i "%~1"=="--pcap" ( set "PCAP=%~2" & shift & shift & goto :argloop )
|
||||||
if /i "%~1"=="--debug" ( set "DEBUG=1" & set "ANNOT=iso7816" & shift & goto :argloop )
|
if /i "%~1"=="--debug" ( set "DEBUG=1" & set "ANNOT=iso7816" & shift & goto :argloop )
|
||||||
|
if /i "%~1"=="--protocol" ( set "PROTOCOL=%~2" & shift & shift & goto :argloop )
|
||||||
if /i "%~1"=="--no-rst" ( set "RST=" & shift & goto :argloop )
|
if /i "%~1"=="--no-rst" ( set "RST=" & shift & goto :argloop )
|
||||||
if /i "%~1"=="--no-vcc" ( set "VCC=" & shift & goto :argloop )
|
if /i "%~1"=="--no-vcc" ( set "VCC=" & shift & goto :argloop )
|
||||||
if /i "%~1"=="-h" ( goto :usage )
|
if /i "%~1"=="-h" ( goto :usage )
|
||||||
@@ -49,6 +52,7 @@ echo --pcap=FILE Also write decoded events to FILE (no spaces in path)
|
|||||||
echo --debug Full decoder + sigrok output (all annotation rows + -l 4).
|
echo --debug Full decoder + sigrok output (all annotation rows + -l 4).
|
||||||
echo
|
echo
|
||||||
echo By default only decoded APDUs and decoder warnings/errors are shown.
|
echo By default only decoded APDUs and decoder warnings/errors are shown.
|
||||||
|
echo --protocol=MODE T=0 (default), T=1, or auto (mid-session decode)
|
||||||
echo --no-rst Disable RST tracking
|
echo --no-rst Disable RST tracking
|
||||||
echo --no-vcc Disable VCC tracking
|
echo --no-vcc Disable VCC tracking
|
||||||
echo.
|
echo.
|
||||||
@@ -82,11 +86,17 @@ exit /b 1
|
|||||||
|
|
||||||
:found
|
:found
|
||||||
|
|
||||||
|
rem Normalize --protocol to the decoder's accepted form (T=0 / T=1 / auto).
|
||||||
|
if /i "%PROTOCOL%"=="T0" set "PROTOCOL=T=0"
|
||||||
|
if /i "%PROTOCOL%"=="T1" set "PROTOCOL=T=1"
|
||||||
|
if /i "%PROTOCOL%"=="AUTO" set "PROTOCOL=auto"
|
||||||
|
|
||||||
set "OPTS=clk=%CLK%:data=%DATA%:clock_option=%CLOCK%"
|
set "OPTS=clk=%CLK%:data=%DATA%:clock_option=%CLOCK%"
|
||||||
set "OPTS=%OPTS%:gsmtap_host=%HOST%:gsmtap_port=%PORT%"
|
set "OPTS=%OPTS%:gsmtap_host=%HOST%:gsmtap_port=%PORT%"
|
||||||
if defined RST set "OPTS=%OPTS%:rst=%RST%:rst_detect=true"
|
if defined RST set "OPTS=%OPTS%:rst=%RST%:rst_detect=true"
|
||||||
if defined VCC set "OPTS=%OPTS%:vcc=%VCC%:vcc_detect=true"
|
if defined VCC set "OPTS=%OPTS%:vcc=%VCC%:vcc_detect=true"
|
||||||
if defined PCAP set "OPTS=%OPTS%:pcap_file=%PCAP%"
|
if defined PCAP set "OPTS=%OPTS%:pcap_file=%PCAP%"
|
||||||
|
set "OPTS=%OPTS%:protocol=%PROTOCOL%"
|
||||||
|
|
||||||
set "CMDLINE=sigrok-cli -d fx2lafw --config samplerate=%SAMPLERATE% --continuous -C D0,D1,D2,D3,D4,D5,D6,D7"
|
set "CMDLINE=sigrok-cli -d fx2lafw --config samplerate=%SAMPLERATE% --continuous -C D0,D1,D2,D3,D4,D5,D6,D7"
|
||||||
if defined DEBUG set "CMDLINE=%CMDLINE% -l 4"
|
if defined DEBUG set "CMDLINE=%CMDLINE% -l 4"
|
||||||
|
|||||||
@@ -189,6 +189,7 @@ check_dup clk "${CLK}" rst "${RST}"
|
|||||||
check_dup clk "${CLK}" vcc "${VCC}"
|
check_dup clk "${CLK}" vcc "${VCC}"
|
||||||
check_dup data "${DATA}" rst "${RST}"
|
check_dup data "${DATA}" rst "${RST}"
|
||||||
check_dup data "${DATA}" vcc "${VCC}"
|
check_dup data "${DATA}" vcc "${VCC}"
|
||||||
|
check_dup rst "${RST}" vcc "${VCC}"
|
||||||
|
|
||||||
echo "Channels: clk=${CLK} data=${DATA}${RST:+ rst=${RST}}${VCC:+ vcc=${VCC}}"
|
echo "Channels: clk=${CLK} data=${DATA}${RST:+ rst=${RST}}${VCC:+ vcc=${VCC}}"
|
||||||
|
|
||||||
|
|||||||
+20
-6
@@ -380,12 +380,26 @@ def main():
|
|||||||
print('\nWARNING: capture contains 0 APDUs but reader log has %d exchange(s).'
|
print('\nWARNING: capture contains 0 APDUs but reader log has %d exchange(s).'
|
||||||
% len(reader))
|
% len(reader))
|
||||||
|
|
||||||
ok = (len(pcap_garbage) == 0 and not no_apdu_failure)
|
ok = (len(pcap_garbage) == 0
|
||||||
print('\nRESULT: %s' % ('OK - capture fully explained (reader + CAT + valid retries)'
|
and len(concat_indices) == 0
|
||||||
if ok else
|
and len(payload_mismatches) == 0
|
||||||
'UNCLEAN - %d mis-framed capture APDU(s)%s'
|
and len(suspicious_cla) == 0
|
||||||
% (len(pcap_garbage),
|
and not no_apdu_failure)
|
||||||
', 0 capture APDUs' if no_apdu_failure else '')))
|
if ok:
|
||||||
|
print('\nRESULT: OK - capture fully explained (reader + CAT + valid retries)')
|
||||||
|
else:
|
||||||
|
problems = []
|
||||||
|
if pcap_garbage:
|
||||||
|
problems.append('%d garbage APDU(s)' % len(pcap_garbage))
|
||||||
|
if concat_indices:
|
||||||
|
problems.append('%d CONCAT packet(s)' % len(concat_indices))
|
||||||
|
if payload_mismatches:
|
||||||
|
problems.append('%d payload mismatch(es)' % len(payload_mismatches))
|
||||||
|
if suspicious_cla:
|
||||||
|
problems.append('%d suspicious CLA' % len(suspicious_cla))
|
||||||
|
if no_apdu_failure:
|
||||||
|
problems.append('0 capture APDUs')
|
||||||
|
print('\nRESULT: UNCLEAN - %s' % ', '.join(problems))
|
||||||
sys.exit(0 if ok else 1)
|
sys.exit(0 if ok else 1)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in new issue
Block a user