- SW column now shows green (success 90/92-9F), blue (pending 61/91/6C),
amber (warning 62/63), red (error 64-6F) per ISO 7816-4 / TS 102 221.
- _decode_nai: treat all-FF records as empty instead of emitting
replacement characters; strip FF padding before the ASCII fallback.
- Only update the selected-file state on a successful SELECT (SW1 in
61/62/63/90/91/92/9E/9F); a failed SELECT (e.g. 6A82) leaves the
current file unchanged.
- Track the file structure from the FCP (GET RESPONSE after SELECT).
- Skip file decoding for record ops (READ/UPDATE/SEARCH RECORD) when the
selected file is transparent/DF, marking the result 'stale' instead of
decoding garbage — this catches silently-dropped SELECTs.
- Track the currently selected file (SELECT by FID/path) across the
session and pass it to the decoder; reset on ATR/card change; seed via
a bounded backward scan on paged views.
- Decode READ BINARY/RECORD, UPDATE BINARY/RECORD and (via GET RESPONSE)
SEARCH RECORD bodies using a FILE_DECODERS registry: IMSI, ICCID,
LI/PL, ADN-format (MSISDN/SDN/FDN/...), SMS records (SMSC + TPDU),
UST/SST/IST service tables, PLMN lists (+access tech), EF_DIR,
CBMI/R, ARR, PNN, ECC, SPN, LOCI, ACC, Phase, ISIM IMPI/DOMAIN/IMPU.
- File formats verified against TS 51.011 / TS 102 221 / TS 31.102
(PLMNwAcT is 5-byte entries; EF_SMS = status + SMSC + TPDU; ISIM
identities are 0x80 TLV).
- Offset != 0 READ BINARY/UPDATE BINARY is skipped (fragment reads).
- SEARCH RECORD results (record numbers) decoded in GET RESPONSE.
- GET RESPONSE summary now shows FCP file type/structure/size.
- New 'File data' section in the detail view.
The selected row was white (--bg-input) in light theme, nearly
indistinguishable from the unselected/hover rows. Use a blue-100 tint
(#dbeafe) in light theme only; dark theme unchanged.
Frontend:
- trace empty-state now shows connection status + capture mode (boxed,
colored) in the center, updated live via checkConnection
- capture-mode uses amber warning style (gsmtap/disabled), green for direct
- stopCapture clears currentSessionId
Server:
- gsmtap read_packet catches OSError on socket close (no more EBADF
traceback on stop)
- stop_session joins the loop and discards a session with zero messages;
/api/capture/stop reports discarded
- startup prints server version
Tests: 122 (gsmtap close, empty/non-empty capture lifecycle).
- pcap.py: _parse_tsresol now pads options to a 32-bit boundary
((-length) % 4) and uses 2** for the MSB-set (power-of-2) case, so
nanosecond if_tsresol is read correctly (was defaulting to µs and
scaling timestamps 1000x)
- database/server: set imported session started/ended from the first/last
packet timestamps (falling back to wall-clock for synthetic SPB)
- frontend: formatDuration renders hours
- tests: tsresol (ns after padded option, default µs, ns round-trip) and
session-window/fallback (119 total)