The second line under the location (e.g. "RAI FFFE") showed only the LAC
part of the current area identity: after every dummy-writing scenario it
was the constant FFFE, and otherwise it was redundant with the
EF.LOCI/PSLOCI/EPSLOCI rows below. netStateRender no longer renders it.
The timestamp line now carries a translated "Last refresh" label
('Last refresh': 'Последнее обновление').
- frontend/index.html: remove #netstate-area (markup + render), label the
read time, LANG_RU entry
- frontend/tests: html test pins the label and the absence of the area
line; netstate test asserts the rendered timestamp
- sw.js cache simple-v208; version trio 2.7.5
- byte 30 b5-b8 were marked RFU; now Proactive UICC: ACTIVATE,
GEOGRAPHICAL LOCATION REQUEST, PROVIDE LOCAL INFORMATION (Broadcast
Network Information) and "Steering of Roaming for I-WLAN" REFRESH
support (TS 102 223 cl. 5.2; TS 31.111 cl. 5.2 names)
- byte 34 b8 "Reserved for future use" -> "Deprecated, bit = 0"
(TS 102 223 cl. 5.2)
- mirrors the UICC_SPECS.md audit fixes (byte 30/34 tables, ESN/MEID
bit positions b5/b6, Data Connection Status Change in extra events)
- SW cache simple-v207; 454 frontend / 298 Python tests green
The location line in the Phone-tab network monitor grew too long once the
status was appended (e.g. "262-01 · Germany · Telekom · Guest (roaming)
⛔ PLMN not allowed"). netStateRender now keeps the identity
(mcc-mnc · country · operator) on the first line and renders the status
elements (roaming tag + forbidden badge) in a block span on a second line;
a location without a status still renders on one line.
Also add the missing Russian translation for the monitor's Refresh button
(t() fell back to English): 'Refresh': 'Обновить'.
- frontend/index.html: two-line location render, LANG_RU Refresh, 2.7.3
- frontend/tests/netstate.test.js: pins the block-span layout and the
one-line no-status case
- sw.js cache simple-v206; version trio 2.7.3
The UICC_NAA.md C3/C3a recipes were re-checked against the corpus: the
EPSLOCI dummy tail is FF*13 + `FF FE` + status - the TAC is always FFFE
(never FF) and the status byte is 01 (not updated), not FF; the old
`<FF*16>` reading was a misparse of that tail. The rejection form
(status 02) is the C3a spec model: the only observed rejection trace never
writes 6FE3 at all.
- build_epsloci_dummy(status=ST_NOT_UPDATED, keep_plmn=None): corrected
tail; keep_plmn selects the NMR style that preserves the last visited
TAI PLMN (the guest style wipes GUTI and TAI PLMN) - both are observed
- write_dummy_locations(): drop the all-FF special case (service loss now
ends `FF FE 01`) and thread keep_plmn through
- tests: exact guest/NMR/rejection vectors, 18-byte length, runner
assertions for service_lost and roaming_denied; netstate fixture updated
- UICC_NAA.md C3a tail `<FF*15> 02` corrected to `<FF*13> FF FE 02`;
the PWA help/param text no longer claims the EPSLOCI dummy keeps the
PLMN; SW cache simple-v205
The startup init (server booted with the card already in the reader) equips
the card and reads the ICCID itself, but never created server.net_state -
only /api/command equip and the auto-equip worker did. With a card present
at boot the monitor stayed empty, net-sim responses carried net_state: null
and the panel only started updating after pressing Refresh (which lazily
created the state). Fix:
- factor _netstate_read(app) / _netstate_install() / _netstate_init() in
server.py; _apply_equipped_card uses _netstate_init()
- __main__ startup: read the monitored EFs in the same CAT-free window as
the ICCID and install the state once the server object exists
- _netstate_ensure() lazily initializes the state in the net-sim/event hooks
so any equip path predating the monitor cannot leave it dead
- netSimRun falls back to netStateFetch() when a response has no net_state
- tests: tests/test_netstate_server.py (candidate order, record vs
transparent, absent files, install, ensure); SW cache simple-v204
server:
- netsim: LOCI/PSLOCI dummy builders take a status; the EPSLOCI dummy is
wiped to 0B F6 + FF per UICC_NAA.md C3; roaming_denied now emulates the
permanent 'PLMN not allowed' rejection (C3a): status 010, EPSNSC dropped,
EF.FPLMN append with TS 31.102 4.2.16 shift semantics and a home-PLMN
guard (HPLMNwAcT/EHPLMN, IMSI fallback), optional 'Rejection: write FPLMN'
toggle; write steps carry the logical key; SCENARIO_SERVICE map;
insert_fplmn/fplmn_entries/parse_imsi helpers
- netstate.py: cached per-session monitor state for the 12 network EFs,
step-based patch, simulated service state, derived location with country/
operator (optional MCC/MNC list) and roaming class
- server: monitor read at equip right after a readable ICCID (skipped
otherwise), cleared on card removal; GET /api/net-state and POST
/api/net-state-refresh; net-sim patches the cache from the written bytes
and re-reads EF.IMSI; Location-status events set the service state and
re-read EF.IMSI (multi-IMSI applets)
frontend:
- Phone tab: 'Network state' panel next to Network simulation with the
simulated service badge (Undefined until simulated; normal/limited/no
service + rejection marker), location/roaming line, compact per-file
summaries with full-decode tooltips and a Refresh button; no card polling
- EF decoders: EF.FPLMN (FFFFFF gaps are not terminators) and EF.EHPLMN
- i18n EN/RU, help updated; SW cache simple-v203
tests: 295 Python / 453 frontend
- ADM/SCP80/SCP81 header indicators become bordered chips (neutral gray
border, rounded, px-1.5 py-0.5); SCP80/SCP81 get an even ml-1 gap, so no
separator glyph is needed
- profiler/snapshot card actions carry the equipped card's ICCID:
'Profile from card <ICCID>', 'Check card <ICCID>' (row button, arrow
dropped), 'New snapshot: <ICCID>'; pysimUpdateCardActionLabels() fills
the spans on every status poll and after a language switch
- these buttons switch to data-needs='card-iccid': disabled without a
readable ICCID ('Card equipped but its ICCID is not readable' hint)
- profiler rows wrap so the longer button cannot break the layout;
help EN/RU updated; SW cache simple-v202
- the ADM badge gains a trailing key glyph (ADM ✓ ⚿ / ADM ✗ ⚿) when the
preset matching the equipped card's ICCID carries an ADM key; the four
tooltip states cover key/no-key x verified/not-verified
- new gray SCP80/SCP81 markers after ADM, shown only when that preset has
all SCP80 fields (KIc/KID, SPI1/SPI2, counter, KIc/KID keys) or the SCP81
PSK pair filled in; hidden without a card session, a matching preset or
the fields, never color-coded
- cardsScp80Complete/cardsScp81Complete/cardsAdmPresent/cardsMatchedPreset
helpers; cardsRender reuses the SCP81 predicate
- tests: ADM four-state badge, marker show/hide, predicate whitespace
handling, header markup order; help EN/RU updated; SW cache simple-v201
- the SCP80 fieldset gains ISD TAR (000000), UICC TAR (B00000) and USIM TAR
(B00001), prefilled with the spec defaults; empty stored values mean the
default for that target (cardsTarValue)
- ADM field between "From card" and "Add", stored in the preset for later
use by the file manager (placeholder ADM (optional), spaces stripped)
- packing a chain selects the preset TAR for its target: RAM/GP -> ISD,
SIM RFM -> UICC, USIM RFM -> USIM (spec default without a preset);
_spTarKey keeps the target when the card preset is picked afterwards,
RAM card selection forces the ISD TAR
- USIM RFM 'from current DF' labelled (ADF.USIM); the list TAR column shows
all three values; help EN/RU updated
- SW cache simple-v199; new cards_form.test.js + html markup guards
(440 frontend / 281 Python tests green)
- new #state-indicator-iccid span between the card image and the ADM badge;
shows the EF.ICCID digits of the equipped card (hidden without a card
session or when the ICCID is unreadable, cleared when the server is lost)
- pysimUpdateIccidIndicator() mirrors the ADM badge pattern (no rewrite when
the value is unchanged); wired into pysimCardStateUpdate() and
pysimSetServerAvailable()
- indicator/card_state tests for show/hide and markup order;
SW cache simple-v197
- Cards and Custom files now expose only Export to file (JSON download) and
Import from file; the Export-as-JSON / Paste & import / Import-JSON-from-
clipboard buttons and their paste textareas are gone
- import feedback moves to a transient status line (new ioStatus helper);
cardsImport/pysimCustomImport no longer read the clipboard
- Network simulation parameters: note under the operator form listing the
scenarios that use the MCC/MNC (EPS/2G attach and SMS received write real
LAI/RAI/TAI; cold boot, service lost, limited service and roaming denied
write dummy files keeping the PLMN; churn/CB/AUTHENTICATE do not use it)
- i18n: removed-button entries dropped, note added EN/RU; help EN/RU updated
- guard tests for the button set and the note; SW cache simple-v196
Live-testing against a UICC without the EPS files (no USIM service 85)
and without the Kc files showed the runner aborting when EPSLOCI/Kc were
absent. write_binary/write_record now take an 'optional' flag: a missing
candidate file is logged as a skip step instead of failing the scenario
(store_epsnsc, real/dummy locations, churn and Kc writes). Also allow
POST /api/write to select by 'path' like /api/select and /api/read (the
netsim live test needed it to restore the captured file values).
Server (pysim_simple_server/netsim.py + POST /api/net-sim):
- pure builders for the observed phone write vocabulary (UICC_NAA.md §13):
EPSNSC (A0 TLV with KSI/KASME/counts/algo, padded to the card's FCP record
size; invalidate-wipe and invalidate-keep-key), LOCI/PSLOCI/EPSLOCI real
and dummy forms (PLMN kept, LAC FFFE, status 01/02), Kc/KcGPRS (9-byte
USIM and 33-byte GSM forms, 07 invalidates), EF.SMSstatus counter bump
(read-modify-write), CBMI/CBMIR, the Location status event (9B 01 <st>,
with the optional 13 07 location info for normal service) and the
AUTHENTICATE APDU (TS 31.102 7.1.2.1) with DB/DC response parsing
- scenario runner executes the recipes under _CARD_LOCK, picks the first
existing candidate path (ADF.USIM vs DF.GSM/DF.TELECOM), reads FCP/current
records where the format is card-specific, skips the event unless the card
subscribed to Location status, honours the scenario toggles and returns a
per-step log; only D6/DC, ENVELOPE and AUTHENTICATE are ever sent
- GET /api/mcc-mnc serves the optional worldwide operator list
(--mcc-mnc-list, default <workspace>/samples/mcc-mnc-list.json): ?q=
search and ?random=1&exclude= for roaming; the list stays out of the repo
PWA:
- Phone pill gains a 'Network simulation' fieldset: one button per scenario
(cold boot, EPS/2G attach, service lost, limited service, roaming denied,
churn, SMS received, CB reconfig, AUTHENTICATE), a collapsed Parameters
block (operator search + random roaming, LAC/Cell ID/TAC/RAC, optional
identities, toggles, churn count/delay) and a step log with SWs
- i18n EN/RU, help/README/api.md/AGENTS.md updated; version 2.5.0,
SW cache simple-v193
Tests: tests/test_netsim.py (19), frontend/tests/netsim.test.js (3) and
html guards - 423 frontend / 280 Python, all passing
Client-side, offline decoder layer (ported from simtrace-analyser, verified
against the pinned specs and pySim test vectors):
- file manager Decoded pill: decoded field table instead of the raw pySim
JSON dump (per-record fields for record files); the server's
read_*_decoded JSON stays behind a 'pySim JSON (server)' disclosure;
switching Raw/Decoded re-reads the open file
- snapshot view: decoded field block for transparent files and a per-record
decoded summary for record files
- profile check / snapshot comparison report: content mismatches of files
with a decoder render as a per-field decoded diff (only the differing
fields, expected | actual); the raw expected/actual pair is kept when the
decoded values match
- coverage: ICCID, IMSI/IST, UST/SST, LI/PL, SPN, PLMNsel/PLMNwAcT/
OPLMNwAcT/HPLMNwAcT, OPL, SPDI, PNN, LOCI/PSLOCI/EPSLOCI/EPSNSC/LOCIGPRS,
Kc/KcGPRS, ACC, PHASE, CBMI/CBMID/CBMIR, ECC, AD, ACL, SMSP, SMS, ARR, DIR,
IMPI/DOMAIN/IMPU, ADN/FDN/SDN/MSISDN/LND/BDN, EXT1-5, SUME (TS 51.011
§10.3.34); unknown files fall back to raw
- new frontend/tests/ef_decode.test.js (14 tests); help EN/RU + READMEs
document the decoded views; version 2.4.0, SW cache simple-v191
- also fix the README/RUS snapshot-comparison text: comparison is always
exact (no content masking)
- version check in pysimConnect() now compares the server major against
SIMPLE_VERSION (2.3.1) instead of the hardcoded 1.x assumption; the header
version is rendered from the same constant
- removed the 'SIM OTA with a Human Face' slogan (span, i18n key, translate
hook) to free header space
- broaden the PWA description in manifest.json/package.json and the help
overview (EN/RU): APDU workbench, OTA lab, CAT/STK simulator, card profiler
- version compatibility tables in README/RUS, help EN/RU and docs/api.md now
describe the major-version rule
- README/RUS: Cards promoted to a top-level section; EN duplicate
Theme/Localisation sections removed
- docs: /api/cardinfo documented; SCP81 'expose framing options' next-work
item dropped (done); local AGENTS.md not-implemented note corrected
- SW cache simple-v190