Commit Graph
19 Commits
Author SHA1 Message Date
catarrh e0134c769a Command filter: multi-select with conversation presets (v2.7.0)
- the single-command <select> becomes a checkbox dropdown: the filter is a
  set of entries (an empty set shows everything), so any number of commands
  can be shown at once instead of one
- three fixed presets select whole conversations:
  * Proactive sessions — FETCH, TERMINAL PROFILE and every command the card
    answered with SW 91xx (the proactive-session initiators)
  * Proactive + events — the same plus ENVELOPE
  * File operations — SELECT, READ BINARY, READ RECORD, UPDATE BINARY,
    UPDATE RECORD (their GET RESPONSE, which carries the data/FCP, comes
    along through the existing response_for linkage)
  presets and single commands combine as a union, and the menu lists the
  session's commands with their counts
- the button summarises the selection ("All commands" / one name /
  "{n} commands"); Escape or a click outside closes the menu; focusing an
  APDU from the Files panel/map still clears the filter first
- tests: a new filter test (the matching rules per entry kind, the GR
  linkage, the presets, the union, the summary, the menu rows, the RU keys
  and the wiring pins), and the focusMessage tests follow the new state;
  527 Python + 72 Node tests
- README/README_RUS describe the filter; PWA_VERSION/pyproject/version.py
  2.7.0, SW cache simtrace-analyser-v80
2026-10-17 23:55:28 +03:00
catarrh 009fcf2253 Files view: the update row's change link is "Show diff" (v2.6.5)
- an update row whose image changed (or whose bytes were first observed)
  offered a generic "Details" link; it now says "Show diff" — Russian
  «Изменения» — while a card-side change keeps its "Changed on card!" link
  (both open the same change modal)
- the now-unused 'Details' RU key is gone; tests update the wiring pin and
  the Russian-translation list; 527 Python + 61 Node tests
- README/README_RUS mention the new label; PWA_VERSION/pyproject/version.py
  2.6.5, SW cache simtrace-analyser-v79
2026-10-17 23:41:28 +03:00
catarrh be75be9ed2 Files view: a card-side change reads as its read, with a "Changed on card!" link (v2.6.4)
- a card-side change is discovered by a read operation, so the timeline row
  now reads "Read EF_IMSI" — the row keeps its warn colour and layout — with
  "Changed on card!" as the trailing underlined link that opens the change
  modal; an update row keeps the generic "Details" link
- the 'Changed on card' verb string is gone; the new 'Changed on card!' key
  carries the Russian «Изменено на карте!»
- tests: the verb/label cases updated (card_change -> Read, "Read EF_LOCI")
  and the Files-view wiring test pins the kind-dependent link label;
  527 Python + 61 Node tests
- README/README_RUS describe the new row wording; PWA_VERSION/pyproject/
  version.py 2.6.4, SW cache simtrace-analyser-v78
2026-10-17 23:37:30 +03:00
catarrh 475c136749 Topbar: title trim, shorter search, the view selector pinned above the panel (v2.6.3)
- the header title drops its "UICC" prefix — "GSMTAP trace analyser" is enough
- the trace topbar's search input is half its previous width (flex basis
  33.333% -> 16.667%); the session name now ellipsizes instead of wrapping
  the tighter row
- the side-panel view selector moved out of the scrollable side panel into
  the trace topbar: right-aligned over the panel at the panel's width
  (--side-panel-w: 260px, the negative right margin cancelling the topbar's
  16px padding so the edges line up), so it stays visible at all times while
  the panel scrolls
- tests: the topbar/selector position pins (the Files-view wiring test and
  style.test.js), the shared width variable, the halved search basis and the
  title; 527 Python + 61 Node tests
- README/README_RUS: the selector's new place; PWA_VERSION/pyproject/
  version.py 2.6.3, SW cache simtrace-analyser-v77
2026-10-17 23:30:37 +03:00
catarrh 76c5647dd4 Files view: the jumped-to record stays selected (v2.6.2)
- focusMessage()/scrollToType() highlighted the target and removed the class
  after 1500 ms, so a Files-row (or map/category) jump looked selected for a
  moment and then lost it; on top of that any re-render (the 500 ms live
  poll, a filter/search change) rebuilt the list and dropped the highlight —
  even for a clicked entry
- the selection is now persistent app state (STATE.selectedIdx): the render
  marks the entry (gap rows included), focusMessage records the index before
  rendering, showDetail records it for plain clicks, scrollToType persists it
  too (clearing the previous highlight), and a new session/capture resets it
  so a stale index cannot mark an unrelated APDU
- tests: a stub-driven focusMessage case (state + detail updated, no render
  and no timer), the filter-clearing case, and source pins for
  renderMessages, focusMessage, scrollToType, showDetail, loadSession and
  startCapture; 527 Python + 58 Node tests
- README/README_RUS: the jump leaves the record selected; PWA_VERSION/
  pyproject/version.py 2.6.2, SW cache simtrace-analyser-v76
2026-10-17 23:16:33 +03:00
catarrh 08a6446bc8 Files view: the row jump no longer scrolls to the end of the trace (v2.6.1)
- jumpToMessage() rendered the APDU list through the unqualified
  renderMessages(), whose tail pins the view to the bottom (the live-capture
  stick), and only then let focusMessage() smooth-scroll back up to the
  clicked record — the visible jump-to-end-then-back.  It now renders with
  skipScroll, so the only scroll is the focus itself
- the content-follow became conditional: shouldStickToBottom() pins the view
  to the newest messages only while the reader is already at the bottom
  (40 px slack), so the 500 ms live poll no longer pulls away a view the
  reader scrolled to — a Files/map jump is no longer yanked down by the next
  batch.  A freshly opened session or a new capture still lands at the
  bottom (renderMessages(false, true))
- tests (node): the jump's paging/render(true)/focus sequence with stubs, the
  no-session no-op, the stick decision (at bottom / within slack / scrolled
  up / explicit jump / forced / first render) and source pins for
  renderMessages, jumpToMessage, loadSession and startCapture; 527 Python +
  53 Node tests
- README/README_RUS note the follow behaviour; PWA_VERSION/pyproject/
  version.py 2.6.1, SW cache simtrace-analyser-v73
2026-10-17 23:01:40 +03:00
catarrh 64433f9739 Extended logical channels: CLA 0-19, ATR card capabilities, MANAGE CHANNEL (v2.6.0)
- CLA decode (TS 102 221 §10.1.1/§10.3): standard channels 0-3 from b2-b1
  and the extended channels 4-19 from b4-b1.  The old further-format rule
  read only b2-b1 (channel 8 read as 6, 19 as 7) and the ETSI '11x0 xxxx'
  coding (0xC0-0xEF) was not handled at all; the class ranges now follow the
  specs (0x80-0x8F UICC, 0xA0-0xAF SIM, 0xC0-0xEF ETSI extended, 0x20-0x3F
  reserved, 0xFF invalid) and SM/chain are decoded per family — the SM
  extraction and the chaining bit (b5, not b6) were off by one bit
- per-channel state: database._decode_rows/_replay_context use the shared
  cla_channel() helper — before, CLA & 0x03 with no +4, so a channel-5
  SELECT clobbered channel 1's selection and a channel-8 one channel 0's
  (the local traces already open channels: 29 MANAGE CHANNEL opens, 1-2)
- COMPRION T=0 import: the synthesized GET RESPONSE keeps the channel —
  a plain CLA for 0-3 (as real terminals do) and 01x0 for 4-19
- ATR historical bytes: the UICC's COMPACT-TLV objects (TS 102 221 §6.3.1)
  with card service data, the card capabilities (ISO 7816-4 §8.1.1.2.7
  Table 88: assignment methods and max logical channels — the workspace
  cards announce 4 and "8 or more") and the status indicator ('00' trailing
  bytes / the '8Y' TLV); a truncated ATR no longer raises
- MANAGE CHANNEL success replies decode the assigned channel byte
- capture/import: a 'tpdu' packet that is not APDU-shaped (shorter than the
  header, CLA FF, ISO-reserved class) is skipped and counted, so a
  character-level or mis-sampled stream no longer pollutes the decode
  (the local DB's outlier sessions are exactly that)
- tests: CLA table vectors, per-channel state isolation on channels 8/12,
  COMPRION GR channels, filetrack extended channels, ATR compact-TLV and
  card-capability cases, the capture skip counter, the PWA rows; 527 Python
  + 47 Node tests
- README/README_RUS document the extended channels, card capabilities and
  the skip counter; PWA_VERSION/pyproject/version.py 2.6.0, SW v72
2026-10-17 22:42:11 +03:00
catarrh cbeeed3608 File names: the DF-scoped spec dictionary + refreshed EF/SFI tables (v2.5.0)
- the file/DF/SFI dictionaries move to simtrace_analyser/ef_tables.py and are
  extracted from the pinned specs: TS 102 221 (MF, Annex H.1), TS 31.102
  (ADF USIM 4.2 and the child DFs 4.3/4.4/4.6, the H.1-H.12 SFI annexes, the
  Annex L.6 Relay Node/certificate files; Annex A/E as the ADF/DF file
  completeness cross-check), TS 31.103 and TS 51.011 - 20 DF tables (~370
  entries) and 14 SFI tables, up from ~180 flat names and 3 SFI tables
- names are DF-scoped: a FID reused across DFs resolves to the file its DF
  context names - 4F09 is EF_SUPI_NAI under DF_5GS but EF_PROSE_GC under
  DF_ProSe, 6F07 is EF_IMSI in the USIM/SIM but EF_IST in the ISIM, 6F4E is
  EF_EXT4 in DF_TELECOM but EF_EXT5 in the USIM ADF; the flat table keeps
  only names that are identical everywhere and is the fallback when no DF is
  known (the two names the old table had wrong there are fixed: 6F0A is
  EF_AC_GBAUAPI, 6F53 EF_LOCIGPRS)
- the SELECT-path decoder resolves the 7FFF children against the USIM ADF
  table, and the Files view names files DF-first - including files first seen
  only via their FCP (a select-only file used to keep the bare FID, e.g.
  ADF/6F3C is now ADF/EF_SMS (6F3C))
- tests/data/spec_files.json pins the extracted tables; tests/test_decode.py
  asserts the DF/ADF tables cover them, the SFI tables match them exactly and
  every flat name is a spec name for that FID; tests/extract_spec_tables.py
  regenerates the fixture from the PDFs and --check re-verifies the tables
- README/README_RUS document the dictionary and its sources; PWA_VERSION and
  pyproject/version.py 2.5.0, SW cache simtrace-analyser-v71
2026-10-17 22:11:47 +03:00
catarrh 5809092175 Files view: the change-details modal shows the full file path (v2.4.2)
- the modal header showed only the flat name (EF_ICCID, 4F09); it now shows the
  path built from data already available: the tracker's DF identity named via
  KNOWN_FIDS (MF, DF_GSM_ACCESS, DF_TELECOM, …), 'ADF' for the current
  application (7FFF), DF_CHILDREN for DF-qualified EF names (4F52 →
  EF_KcGPRS) and the EF.DIR labels for AID-selected applications —
  e.g. `MF/EF_ICCID (2FE2)`, `ADF/EF_IMSI (6F07)`,
  `DF_GSM_ACCESS/EF_KcGPRS (4F52)`, `AID A00000015141434C00/4F09`
- exposed as `path` in the change-details payload and in the files entries
  (the timeline rows keep the short name — they have no room)
- the colour legend (changed / newly observed / never observed) moved below
  the two hex views
- tests: `_file_path` cases (MF, ADF, DF-qualified EF, AID with and without an
  EF.DIR label, FID-as-name) plus the payload field, and the Node modal test
  asserts the path header and that the legend follows the views
- v2.4.2; SW cache simtrace-analyser-v68
2026-10-17 21:35:41 +03:00
catarrh cbb73536f4 Files view: drop the ASCII column from the change-details hex views
- the modal's hex views carried a 16-byte ASCII column per row; file data is
  rarely text and the column halved the room for the two before/after views,
  so it is gone: `hexImageRows` no longer builds an `ascii` field,
  `hexImageHtml` no longer emits it and the `.hex-ascii` CSS rule is removed
- tests: the hex-row test asserts the field is gone (so it cannot come back
  silently); README/README_RUS wording updated
- SW cache simtrace-analyser-v67 (cosmetic, no version bump)
2026-10-17 21:29:31 +03:00
catarrh cad3999307 Files view: change details with before/after images (v2.4.0)
- the timeline's Δ glyph became a **Details** button, and it now appears on
  Update rows too (not just card-side changes); EN "Changed (card)" ->
  "Changed on card", RU "Изменено (картой)" -> "Изменено картой"
- the details modal shows the affected unit — the whole file, or the single
  record that changed — **before and after** the change as hex views (16 bytes
  per row, ASCII column, never-observed bytes as `--`), with the bytes that
  changed and the bytes the operation *first observed* highlighted in two
  different colours, plus the changed/new byte counts and the APDU reference;
  the old before/after byte table is gone
- `GET /api/sessions/<id>/files/image?key=…&change=…` returns those two views
  (segments with offsets) plus the change's metadata; the images are
  reconstructed from the current image by undoing the later changes
  (`FileTracker.change_images`), so nothing is duplicated per event — every
  value change is an event, hence the values are exact (a byte only first
  observed later can appear as known in both views)
- tracker: change events carry `observed_ranges` (bytes that were unknown
  before the operation) next to `ranges`; an update that only observes new
  bytes now records an event (so it can be inspected); record-file ranges are
  in-record byte offsets (the record number stays in its own field), which the
  previous "record number as position" could not express for a hex highlight
- tests: change-images reconstruction (before/after per event, later changes
  undone, records isolated, observation-only events, unknown gaps), the image
  endpoint (200/404/400), and Node tests for the hex-image helper (highlight
  classes, unknown gaps, ASCII, row limit) and the modal rendering
- v2.4.0; SW cache simtrace-analyser-v65
2026-10-17 21:19:14 +03:00
catarrh c494bf4111 Files view: per-file tracking (counters, image, device/card changes)
- new `simtrace_analyser/filetrack.py`: a single-pass tracker over a
  session's decoded messages, keyed by (DF, FID) and trace-wide (resets only
  wipe the per-channel selection): counters (`select`/`read`/`update`,
  successful operations only), a sparse image of the observed bytes
  (transparent files by offset, record files per record number) and the
  change log
- changes: **device** = an UPDATE seen in the trace (applied to the image,
  `no_change` flags a provable no-op); **card** = a READ whose bytes differ
  from the image on bytes already known (logged at the surfacing read with
  the changed ranges and the before/after hex; never-seen bytes just fill
  the image, they are an observation, not a change)
- SFI-addressed accesses join the same entry as path/FID ones: the SFI ↔ FID
  relations come from the normative tables and from every surfaced FCP `88`
  DO (including the spec's "SFI = 5 LSBs of the FID" rule when the DO is
  absent); an SFI used before its relation is learned stays provisional and
  merges into the resolved entry
- the DF identity follows TS 102 221 §8.4/Table 8.2: `selected_df_fid()` now
  resolves an EF path selection to its parent DF and returns `aid:<hex>` for
  applications selected by an unknown AID (named from EF.DIR when the trace
  surfaced it); `Database._decode_rows` gained an `on_message` hook and
  `track_files()`
- `GET /api/sessions/<id>/files`: the operation timeline, the per-file
  counters/coverage/change log, the SFI relations and the AID labels
- PWA: the side panel's Map/Stats tabs became a view selector (Map / Stats /
  Files); the Files view is a timeline of Read / Update / Changed (card) rows
  (colour-coded, the same file names as the Map view), a row click jumps to
  the APDU (loading the pages it needs) and a card-change row's Δ opens the
  changed ranges with the previous and the new bytes; EN/RU
- bounds: the image freezes past 64 KB of observed bytes per file, the change
  log keeps the last 1000 events per file (counters keep counting)
- tests: tests/test_filetrack.py (counters, resets, channels, image/diff
  semantics, record files, SFI resolution and the provisional merge, EF.DIR
  labels, caps, the endpoint) and Node tests for the Files-view helpers and
  wiring
- v2.3.0; MIN_SERVER_VERSION 2.3.0; SW cache simtrace-analyser-v63
2026-10-17 20:51:33 +03:00
catarrh 28bc8f1f24 Import COMPRION trace exports (Protocol Layer + Application Layer time base)
- new `simtrace_analyser/comprion.py`: parses the tab-separated ISO Protocol
  Layer export (metadata block, ATR/PPS exchanges, APDUs with continuation
  rows, delays in etu) and re-encodes every exchange into the wire-shaped
  TPDUs the analyser stores — a case-4 exchange becomes the command, a
  fabricated `61 <len>` status word and a GET RESPONSE (command's logical
  channel preserved), so command/response pairing, FCP/file decoding and the
  GET RESPONSE filters work unchanged; Cold reset / Power off become RST/VCC
  line events, deliberately without the sigrok CLK extension (the export
  carries no clock measurement)
- optional matching **ISO Application Layer** export as the exact time base:
  its one `Time:` row per exchange (ms precision) replaces the delay estimate
  (0-based elapsed, `started = Session Name + first Time`), guarded by a
  session-identity check (`Session Name`, falling back to `Working
  directory`; the two layers' export timestamps differ and are not compared)
  and an exchange-count check — mismatched files are refused, never mixed
- protocol-only imports keep the Delay-based timeline: card/line activity
  time (host pauses absent), the unit assuming 3.8 MHz (`CLK_HZ`); the
  estimate is not fed into the CLK/RST line-event annotation
- `POST /api/sessions/import?format=comprion` (raw text body, or a JSON
  `{text, times_text}` bundle) with stable error codes (app_layer /
  not_comprion / unsupported_layout / no_data / times_unparsable /
  session_mismatch / time_base_unverified / time_base_mismatch); a COMPRION
  file dropped on the PCAP path answers with a pointer (comprion_export);
  session mode `comprion`, window from the Session Name
- PWA: import dialog with two separate pickers (Protocol Layer required,
  Application Layer optional) whose hint switches between "activity time"
  and "exact timestamps"; errors stay in the dialog with both selections
  until fixed or cancelled (Cancel/Esc, also disabled while importing);
  EN/RU
- tests: tests/test_comprion.py (parser, wire encoding, time base + guards,
  import endpoint) and frontend/tests/comprion.test.js (file checks, slot
  validation, dialog state machine with a DOM stub, RU coverage)
- v2.2.0; MIN_SERVER_VERSION 2.2.0; SW cache simtrace-analyser-v61
2026-10-17 00:45:15 +03:00
catarrh 561801a983 TERMINAL CAPABILITY: decode the A9 template (TS 102 221 §11.1.19)
- terminal power supply (tag 80): voltage class per Table 6.1, maximum
  current in mA, clock in 0.1 MHz steps ('FF' = not indicated)
- extended logical channels (tag 81) — zero length per §11.1.19.2.2, a
  nonzero length is preserved as raw
- additional interfaces (tag 82 b1 = UICC-CLF)
- eUICC device capabilities: tag 83 per GSMA SGP.22 v2.6 §3.4.2 Table 7
  (LUId/LPDd/LDSd/LUIe-SCWS); tag 84 preserved raw (no pinned SGP.32 spec)
- unknown/private TLVs preserved via raw_tlv
- concise APDU-list summary; decoded rows in the PWA detail view
- v2.1.0; SW cache simtrace-analyser-v55
- tests: 6 real samples from the local trace sessions (49/55/58/61/206/208)
2026-09-20 00:11:41 +03:00
catarrh 38650b4797 Rename project to SIMtrace Analyser (v2.0.0)
- move the analysis server out of simtrace2_pysniff into simtrace_analyser;
  simtrace2_pysniff stays as the simtrace2-sniff replacement capture utility
- new server CLI: simtrace-analyser-server; python -m simtrace_analyser
  (simtrace2-pysniff-server and python -m simtrace2_pysniff.server dropped)
- simtrace2_pysniff lazy-imports hardware symbols, so the server no longer
  pulls PyUSB at startup; the GSMTAP/PCAP codecs work without libusb
- version 2.0.0 everywhere (was 1.22.21); PWA SW cache simtrace-analyser-v54
- frontend: server name, clone URL and i18n strings updated; vendored-parser
  reference otaman -> SIMple
- README/README_RUS reworked product-first (analyser first, utility second)
- DB dir ~/.simtrace-analyser, /api status payload and hosted PWA unchanged
2026-09-19 12:34:16 +03:00
catarrh 39ee173a7d Rename RST de-asserted label to 'RST de-asserted — ATR follows'
- More precise than 'ATR STARTS' (the ATR starts after the de-assert
  delay, not at the edge) while staying human-friendly; reads as a pair
  with 'RESET ASSERTED'
- Update tests and both READMEs (backend-only, no version bump)
2026-09-18 23:59:45 +03:00
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 c2f605a391 Add sigrok_iso7816_stream to related projects in both READMEs 2026-09-11 08:05:06 +03:00
catarrh dbaa23b3da Add Russian README (README_RUS.md) + language links
- Full Russian translation of README.md
- Cross-link English/Russian versions
- Note Windows sniff-start.bat in startup section (no longer Linux-only)
2026-09-11 08:03:34 +03:00