- the 'Proactive + events' preset is gone: the proactive one (FETCH,
TERMINAL PROFILE and the SW 91xx initiators) plus the individual ENVELOPE
entry cover it, and its Russian key is removed with it
- with several entries checked the filter button now reads "Selected: N"
(«Выбрано: N») instead of "N commands"; a single entry keeps showing its
name and an empty selection stays "All commands"
- tests: the removed preset's case is replaced by an absence pin in the menu
test, and the summary case follows the new wording; 527 Python + 72 Node
tests
- README/README_RUS list two presets; PWA_VERSION/pyproject/version.py 2.7.2,
SW cache simtrace-analyser-v82
- the old "FETCH: ANY PROACTIVE" grouping label is gone: filter_label() now
gives every command its own label, so the menu lists FETCH and TERMINAL
RESPONSE individually — the multi-select filter (and the presets) cover the
combinations that the grouping used to bundle
- the proactive presets keep their meaning: they name FETCH and TERMINAL
PROFILE and reach the rest (a TERMINAL RESPONSE included) through the SW
91xx rule; selecting FETCH now also brings its GET RESPONSE, which carries
the fetched proactive command
- tests: the proactive-preset case follows the split (a TERMINAL RESPONSE is
covered by 91xx, not by its name) plus a new case pinning the separate
labels and the FETCH/GR pairing; 527 Python + 73 Node tests
- PWA_VERSION/pyproject/version.py 2.7.1, SW cache simtrace-analyser-v81
- 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
- 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
- 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
- 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
- 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
- the APDU list's 12px rule is folded into the global scrollbar style, so
the side panel, APDU detail pane, dialogs (file-diff body), session
lists/grid and the hex views' horizontal bars all use the same 12px bar
with a 6px rounded thumb — no per-element overrides remain to drift,
and the horizontal bars get an explicit height instead of the browser
default
- Node test pins the global rule (12px width/height, 6px thumb radius) and
the absence of per-element overrides; 527 Python + 55 Node tests
- SW cache simtrace-analyser-v75 (cosmetic, no version bump)
- the side panel had no scrollbar rule of its own, so it fell back to the
global 6px default while the APDU list uses 12px; the two now share one
rule (width 12px, thumb radius 6px = half the bar), so they cannot drift
apart again — the other panes keep the thin global bar
- Node test pins the shared rule (and the 6px global default)
- SW cache simtrace-analyser-v74 (cosmetic, no version bump)
- 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
- 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
- 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
- modal max-width 900px -> 1100px
- the legend's swatch and label were separate flex children, so a line break
could split them and the three entries wrapped; each pair is now one
`.hex-legend-item` (nowrap, no shrink) and the legend itself is
`flex-wrap: nowrap` with `overflow-x: auto`, so it stays on a single row
- Node test: the modal test now checks the path header and that the legend
follows the views as three grouped items
- SW cache simtrace-analyser-v70 (cosmetic, no version bump)
- the before/after hex views (16 bytes per row, two side by side) had little
room at 760px; the modal's max-width is now 900px (the base `.modal` width
of 90% still keeps it inside the viewport on smaller screens)
- SW cache simtrace-analyser-v69 (cosmetic, no version bump)
- 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
- 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)
- `loadSession` begins by stopping a running capture; when there is nothing
to stop the server answers 400 'No active capture' (or 403 with capture
disabled) — and since the v2.3.1 `_fetch` status fix those answers throw, so
the whole load was skipped and the UI alerted "Failed to load session":
no session could be opened at all
- new `stopCaptureIfRunning()` swallows exactly that no-op answer; both
`loadSession` and the capture button use it, and the button now resets its
state outside the try so a tolerated stop still clears the UI
- the `_fetch` status check stays — real errors keep surfacing (an unknown
session still throws 'Session not found')
- tests: the helper resolves on a 400 and still calls once; source pins that
`loadSession` uses the tolerant helper (the regression guard) and that
`stopCapture` resets the state
- v2.4.1; SW cache simtrace-analyser-v66
- 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
- `API._fetch` never checked the HTTP status: an error body (e.g. the 404
`{"error": "Session not found"}`) was returned as data, so the Files view
rendered it as "No file operations recorded" — and, worse, that bad payload
was cached per session id, which is why only re-opening the session (which
resets the cache) appeared to fix it. It now throws with the server's
message for any non-OK response (all 13 `await API.*` call sites are inside
try/catch) and marks the server unavailable only for a real network error
- `renderFileView` accepts a payload only when it carries a `timeline` array:
a genuine `timeline_total === 0` keeps the empty state, anything else shows
"Failed to load files: <reason>"; failures are not cached, so the next visit
retries; a response that arrives after the user switched sessions is ignored
- tests: HTTP-error vs network-error behaviour of `_fetch` (network error is
the only disconnected state), the valid/empty/error render paths and the
retry-after-error, the stale-response guard
- v2.3.1; SW cache simtrace-analyser-v64
- 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
- the slot layout now wraps: the label and "Choose file…" share the first
line, the selected file name gets its own full-width line (the fixed
200 px label left only ~200 px for the name and overflowed on narrow
screens); the ellipsis styling is unchanged and only kicks in for
genuinely long names
- RU label "Импорт трассы COMPRION" -> "Импорт трейсов COMPRION" (the
button/dialog title and the PCAP-path hint that quotes it); EN strings
and LANG_RU keys unchanged
- SW cache simtrace-analyser-v62 (label/layout-only, no version bump)
- 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
- tag '18' (TS 101 220: "18 only"): one byte per item, §9.4 coding;
'00' and reserved values mean "no next action" (decoded to None)
- items[] now carry a per-item next_action; a list whose length differs
from the item count is preserved raw (spec requires X = item count)
- detail view renders "Item 0xNN: text → COMMAND"; the APDU-list summary
is unchanged — next actions are detail-only, as requested
- tests: 3 real SET UP MENU samples (local sessions 47/53/57) + a
length-mismatch tolerance case
- v2.1.2; SW cache simtrace-analyser-v57
- REFRESH '07'/'08': use the TS 31.111 §8.6 names ("Steering of Roaming" /
"... for I-WLAN", per TS 23.122 / TS 24.234) instead of "Reserved (...)"
- envelope tags 'E1'-'E3': TS 31.111 §9.1 leaves them reserved for future
usage — drop the placeholder label and decode them as unknown
- TR result '28' = Bearer Independent Protocol temporary error (TS 102 223
§8.12); '29' stays reserved
- PLI qualifier '0B' = MEID of the terminal added; '05' documented as
TS 31.111's Timing Advance (ETSI text says "Reserved for GSM")
- ISO 7816-4:2005 Table 6: add '62 86' (sensor) and '63 81' (file filled)
- drop the two fabricated '66xx' names (no such rows in the pinned specs)
- tests: add the new value tests plus a guard that no decoder table emits
a "Reserved ..." label
- v2.1.1; SW cache simtrace-analyser-v56
- 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)
- 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
- decode.py: _build_summary emits 'Data: N bytes — FCP of <file> (...)' for
STATUS responses with data (FCP already decoded into decoded.response);
_fcp_brief builds the 'FCP of MF (DF or ADF)' / 'FCP of EF_xxx (...)'
fragment
- index.html: cmd_description suppresses the raw-hex fallback for
body-less STATUS rows (nothing to describe beyond type + SW)
- tests: no-data STATUS summary None; DF/EF FCP summaries; pluralization
- Bump 1.22.19, SW cache v50->v51
- 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
- Store raw session name in STATE.currentSessionRawName
- Re-render session-name-display in toggleLang() with current translation
- Add frontend.png screenshot to README
- Bump 1.22.15, SW cache v46->v47
- Insert .splitter div between .apdu-list and .apdu-detail
- Replace flex:1 / max-height:40% with --detail-height CSS var
- Drag handler with clamp 10%-80%, persisted in localStorage
- Bump 1.22.12, SW cache v43->v44
- Toggle buttons (Tiles/List) in sessions header, preference
persisted in localStorage
- List view: table with Name, Date, Duration, Messages, Mode, Actions
columns; same fields and buttons as tiles, just tabular layout
- Refactored loadSessions() into buildGridHTML/buildListHTML helpers
with shared attachSessionListeners() for both views
- i18n: Tiles, List, Name, Date, Duration, Messages, Mode, Actions
keys added to LANG_RU
- Bump 1.22.6, SW cache v37->v38
- error_names(m) now includes 'Data length mismatch' when
decoded.length_mismatch is set, showing a ⚠ badge + tooltip
in the APDU list row (alongside existing errors like bad FCS)
- Header title: SIM-ME -> UICC
- Bump 1.22.5, SW cache v36->v37
- capture-btn moved to first child of trace-topbar (before search input)
- Button always visible: shows Start/Stop/Connect-to-server as before
- When server capture is disabled: grayed-out Start Capture with
tooltip via existing i18n key 'Capture is disabled ...'
- No more hiding button when viewing saved session or when disabled
- Bump 1.22.4, SW cache v35->v36
T=15 in the ATR is a Protocol-and-Parameter-Selection capability,
not a data protocol like T=0/T=1. Previously 'Protocols: T=0, T=15'
was misleading.
- _decode_atr: exclude T=15 from protocols, set pps=True instead
- TCK presence: only-t0 rule now also requires no PPS (T=15 implies TCK)
- PWA ATR detail: 'Protocol: T=0' + 'PPS: supported' rows
- +1 test with the real UICC ATR (3B 9F 95 80 1F C7 ...)
- Bump 1.22.2, SW cache v33->v34
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.
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.
- Pair CLA+INS and P1+P2 into single rows (halves the header rows
per C-APDU): "· CLA, INS 00 — UICC, A4 — SELECT".
- Skip the " — desc" suffix when the parser's desc merely repeats
the hex (generic Data fields showed "6F46 — 6F46").
- Restore the implied-CLA annotation on the C-APDU title row (was
dead code behind an operator-precedence bug).
Version 1.20.2, SW cache simtrace-analyser-v30.