decode.py:
- _decode_fcp: FCP/FCI/FMD template — full bit-level file descriptor
(TS 102 221 Table 11.5: file type, structure, shareable, data coding,
record length, num records), file ID (+ KNOWN_FIDS name), DF name,
SFI, life cycle
- _decode_auth: GSM SRES+Kc, or 3G tag DB (RES/CK/IK/KC) / DC (AUTS)
- _decode_tr_result: TERMINAL RESPONSE Result TLV (code + name)
- _decode_response_for(ins, data): GET RESPONSE decodes its body using
the previous command's INS (SELECT→FCP, AUTHENTICATE→auth)
- decode_message wires response decoding for TR and GET RESPONSE
database.py: prev context now carries 'ins' (INS byte) via
_context_from_decoded, used by GET RESPONSE response decoding
tests: FCP, AUTH (GSM/3G), TR result, GET RESPONSE wiring (57 total)
decode.py: split decode_tr_command() out of decode_cat(); TR (0x14)
now stores the echoed proactive command type in 'response_to' instead
of 'cat_command', so it no longer overrides the INS name.
FETCH/ENVELOPE still use cat_command as the primary label.
tests: TR now asserts response_to + no cat_command
decode.py:
- decode_cat: TERMINAL RESPONSE (0x14) now extracts the proactive
command type from its echoed Command Details (tag 81) — no history
lookup needed since TR carries its own type
- decode_message gains prev param; GET RESPONSE (0xC0) resolves
'response_for' from the previous command when its SW1 was 0x61,
else None (orphaned)
- decode_sniff_msg threads prev through
database.py:
- _row_to_message accepts prev; new _decode_rows tracks previous-TPDU
context in sequence; get_messages/get_messages_after seed context
from the message before the window/cursor
tests: TR cat_command + GET RESPONSE context/orphaned cases (49 total)
Decode errors now log to stderr instead of crashing the entire
API response. This prevents a single malformed message from hiding
all subsequent messages in the same query.
decode_sniff_msg() dispatches to type-specific decoders:
- change: 4-byte flags bitmask → card insert/eject/reset/timeout
- fidi: 1-byte Fi/Di index → decoded values
- atr/pps: raw hex value
database.py now decodes all message types, not just tpdu.
Pure Python, no dependencies. Decodes raw TPDU bytes into
structured JSON: CLA bitfield, INS->name via APDU_SPEC table,
P1/P2 field breakdown, body extraction, SW name lookup.
~40 command types, 40+ SW codes, known FID notes.
database.py: _row_to_message() calls decode_message() for tpdu
messages, adding 'decoded' field to API responses.
Decoding happens at query time, not storage time — no schema
migration, all past sessions get decode retroactively.
Add simtrace2-pysniff-server CLI — HTTP API for simtrace-analyser PWA.
Two capture modes: GSMTAP UDP listener (compatible with simtrace2-sniff)
or direct SIMtrace2 hardware capture. SQLite storage with sessions +
messages tables. REST API with CORS.
server/ sub-package: database.py, capture.py, server.py, __main__.py
README updated with server usage section.
pyproject.toml: simtrace2-pysniff-server script entry added.
UDP socket on port 4729, parses GSMTAP header, validates
GSMTAP_TYPE_SIM, returns (sub_type, data). Compatible with
simtrace2-sniff and pySim's GsmtapApduSource.
Use sys.stdin.isatty() to auto-detect: foreground sessions still
respond to SIGHUP (terminal close kills the process as expected),
background/piped processes ignore it and survive.
__main__.py: add signal.SIGHUP → SIG_IGN before setting up
SIGINT/SIGTERM handlers. Sniffer no longer dies when the terminal
closes or the shell session ends.
README: add Background / Daemon section with nohup examples.
dump.py: tpdu_timestamp_prefix(), tpdu_atr_time_prefix(),
format_message() accepts tpdu_prefix parameter,
FileDumper supports fmt + ATR time tracking
__main__.py: --format/-f flag (hex|timestamp|atr-time),
atr_time_start tracking in message loop
sniff-start.sh: pass through --format/-f and FORMAT env var