Commit Graph
11 Commits
Author SHA1 Message Date
catarrh a46667d93f Decode standard PPS sub-types + RST CLK extension → ATR data rate
- capture.py: map GSMTAP PPS request/response (0x02/0x03) to 'pps',
  matching the pcap-import mapping (was decoded as TPDU live)
- decode.py: parse the optional RST CLK extension (sigrok v1.9.0+,
  payload flag bit 0); ATR gains clk_hz/data_rate/etu_us derived from
  TA1 Fi/Di (data_rate = clk_hz × D / F)
- database.py: CLK state is consumed by the next ATR (no stale rate
  for an ATR without preceding RST); a late-arriving RST measurement
  is backfilled onto the ATR it belongs to; replay context carries
  the CLK across pagination/live polling
- PWA: ATR detail shows CLK/Data rate/ETU; RST event detail shows CLK
- tests: PPS mapping, CLK parse with/without flag, rate math,
  DB consume + backfill round-trips
- README/RUS updated
- Bump 1.22.18, SW cache v49->v50
2026-09-18 00:30:26 +03:00
catarrh 7d8dca1ffd Fix GSMTAP capture restart: recreate UDP socket on start after stop
GsmtapListener.stop() closed the UDP socket permanently, but start()
only set _running=True without recreating it. Second capture session
would silently spin on the dead socket (OSError → None → continue).

- Add _closed flag to GsmtapReceiver, set in close()
- Store bind_port in GsmtapListener for socket recreation
- start() recreates GsmtapReceiver only if previous one was closed
- Uses getattr for backward compat with test fakes
2026-09-06 21:09:04 +03:00
catarrh 6887e53144 Add --log-interval flag and timestamp capture logs
Follow-ups from the capture-reliability review:
- All server-side capture log lines are now prefixed with a local
  timestamp (YYYY-MM-DD HH:MM:SS) for easier correlation.
- New --log-interval SECONDS CLI flag (default 60) tunes the
  "Capture alive" heartbeat interval; passed through to CaptureManager.

Stays on 1.22.0 (backend-only). 369 tests pass.
2026-08-26 22:35:59 +03:00
catarrh 51e1b4ae08 Keep GSMTAP capture alive + server-side liveness logging
The GSMTAP capture thread died silently whenever a single non-SIM or
truncated GSMTAP datagram arrived (read_packet() raises ValueError,
uncaught in the loop, killing the daemon thread while UDP kept
flowing) — matching the "stops listening after a sniffer restart"
symptom.

Fixes:
- GsmtapListener.iter_messages() now catches ValueError/struct.error
  from read_packet(), drops the offending datagram (counted via a new
  `dropped` counter) and keeps listening.
- CaptureManager._capture_loop() guards the DB insert so a transient
  error can't kill the thread; a top-level guard logs
  "ERROR: capture thread stopped on error …" + traceback and clears
  the session so /api/status no longer reports a stuck "active".
- Server now logs capture liveness to stderr: "Capture started", a
  periodic "Capture alive: session=N messages=M bytes=B dropped=D"
  heartbeat (default every 60 s, configurable via log_interval), and
  "Capture stopped" (or "empty session discarded").

Tests: +5 (listener survives non-SIM/short packet, capture loop
survives insert error, logs stop-on-error, heartbeat+stop log).
Stays on 1.22.0 (backend-only).
2026-08-26 22:21:14 +03:00
catarrh 66094a0114 Surface GSMTAP BAD_FCS desync flag end-to-end
sigrok-iso7816-stream sets GSMTAP_FLAG_BAD_FCS (0x01) in the GSMTAP
header `res` byte on desynced TPDUs (mis-framed exchanges kept for
forensics). Propagate that flag through the whole pipeline so such
packets are explicitly surfaced instead of decoding as garbage:

- gsmtap.py: GSMTAP_FLAG_BAD_FCS const; GsmtapReceiver.read_packet()
  now returns (sub_type, data, flags) from the res byte.
- server/capture.py: GsmtapListener forwards the flags to the DB.
- pcap.py: _parse_gsmtap_hdr/_scan_gsmtap/extract_gsmtap and
  parse_pcap/parse_pcapng now yield a (ts, type, payload, flags)
  tuple, so the flag survives a PCAP/PCAPNG round-trip.
- server/server.py: PCAP import stores the flags.
- server/decode.py: gsmtap_flag_names() maps bit 0x01 to
  'bad FCS (desynced)'; merged into decoded errors for tpdu/atr/pps
  and rst/vcc, so the frontend ⚠ badge + Errors row flag the entry.

User-visible: desynced TPDUs show a ⚠ "bad FCS (desynced)" marker
in the trace and detail views. Tests: +4 (decode BAD_FCS markers,
PCAP flag round-trip); existing tests updated for the new tuple
arities. Version 1.22.0, SW cache simtrace-analyser-v32.
2026-08-26 18:08:25 +03:00
catarrh 7eaf7e9b53 Decode sigrok-iso7816-stream RST/VCC line events (GSMTAP 0x10/0x11)
Support the sigrok-iso7816-stream decoder (FX2 logic-analyzer passive
SIM sniffer, github.com/anttro/sigrok_iso7816_stream) which streams
GSMTAP-SIM on UDP 4729 and adds two custom sub-types for line events.

- gsmtap.py: GSMTAP_SIM_RST_EVENT (0x10) / GSMTAP_SIM_VCC_EVENT (0x11).
- capture.py: gsmtap_msg_type() maps 0x10→'rst', 0x11→'vcc' (shared by
  the listener and tests); pcap.py _SUB_TYPE_NAMES gains the same
  entries so PCAP re-imports of these captures preserve the events.
- decode.py: decode_line_event() decodes [direction, level, reserved]
  into reset asserted/de-asserted or power applied/removed + level;
  routed through decode_sniff_msg.
- database.py: reset-assert and power-removal invalidate the per-channel
  file selection (card-level transition); de-assert / power-on are
  markers only.
- frontend: RST/VCC labels (RESET ASSERTED / VCC OFF, …), a detail-view
  branch (Event + Level + raw), and list styling (.apdu-type.rst/.vcc).

README notes the custom sub-type compatibility. Tests: +8 (line-event
vectors, sniff routing, subtype + PCAP round-trip mappings) — 359
total. Version 1.21.0, SW cache simtrace-analyser-v31.
2026-08-26 17:29:36 +03:00
catarrh 5d91450b55 Track device connection and capture gaps; surface sniff error flags 2026-08-19 18:00:52 +03:00
catarrh 86317d0105 Decode READ/UPDATE BINARY SFI vs offset; surface proactive command qualifiers; fix capture stop 2026-08-18 23:31:26 +03:00
catarrh 97a7e6034a Show status in trace empty-state; discard empty captures; polish capture-mode
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).
2026-08-15 08:48:07 +03:00
catarrh 2a58fec0a3 Fix dropped change flags + FIDI parsing
- capture.py: DirectSniffer/GsmtapListener yield (type, data, flags),
  CaptureManager passes flags to insert_message (change flags were
  previously dropped, leaving every change row with flags=0)
- protocol.py: add _parse_fidi (1-byte value) — FIDI was mis-mapped to
  _parse_change (4-byte flags), so FIDI messages were silently dropped
- database.py: pass flags into decode_sniff_msg
- decode.py: decode_change(flags) reads flags directly; decode_sniff_msg
  gains flags parameter; change messages no longer require non-empty data
- tests: fix FIDI test, add change/fidi decode tests (43 total)
2026-08-12 19:25:14 +03:00
catarrh 17eeda27f3 Merge simtrace-analyser-server into simtrace2_pysniff.server
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.
2026-08-12 15:59:51 +03:00