terminal profile at runtime + canonical custom-file paths (v2.2.3)

TERMINAL PROFILE:
- GET /api/terminal-profile returns the profile in effect + the CLI default;
  POST /api/terminal-profile validates ({profile}, hex, even, 1-255 bytes),
  stores it in memory and re-sends it, resetting the STK session like
  /api/rescue (the shared _resend_terminal_profile helper; rescue now
  delegates to it). __main__ keeps server.cli_terminal_profile.
- Phone tab: a TERMINAL PROFILE block next to STATUS and Polling with the
  current hex/byte count, Send (re-send) and Configure. The Configure
  dialog has a device-model preset selector, a hex field and a per-bit
  form generated from a 264-entry table for TS 102 223 V18.3.0 5.2 bytes
  1-33 (pySim's table as scaffold, later bytes/3GPP bits added from the
  spec; beyond the table generic RFU labels). Form <-> hex sync both
  ways, hex authoritative, bits preserved. Apply posts the new value.
- Presets: Xiaomi Mi A1 (project default), Quectel GSM module example.
  In-memory only, no persistence.

Custom files:
- Canonical paths rooted at MF / ADF.USIM / ADF.ISIM; entries are
  {path, name, kind}. The editor now uses root + parent-DF selector +
  4-hex FID + alias, requires the parent DF to be defined first, rejects
  duplicates, rewrites descendants when a DF's path changes and cascades
  deletes after a confirmation.
- Legacy forms are normalized on load/import (3F00/... -> MF/..., relative
  a153/4954 resolved against the custom DFs); unresolvable entries are
  dropped and reported in the list.
- Tree injection matches by exact parent path via the new pysimFsNodePath
  (same-FID DFs under different parents no longer collide);
  profilerCustomNameForPath uses the same normalization.

SW cache otaman-v167; help EN/RU + docs/api.md + AGENTS updated.
Tests: 236 Python + 371 frontend.
This commit is contained in:
2026-09-16 20:46:40 +03:00
parent 20fbfd99a5
commit aa33d25466
15 changed files with 1057 additions and 180 deletions
+4 -2
View File
@@ -27,7 +27,8 @@ const code = extractFunc(html, 'phoneSwitchSubtab') + '\n' +
'globalThis.pysimEventsRender = () => { globalThis._events = (globalThis._events || 0) + 1; };\n' +
'globalThis.pysimProactiveLogRender = () => { globalThis._log = (globalThis._log || 0) + 1; };\n' +
'globalThis.pysimPollStatusInit = () => { globalThis._poll = (globalThis._poll || 0) + 1; };\n' +
'globalThis.pysimPliRender = () => { globalThis._pli = (globalThis._pli || 0) + 1; };\n';
'globalThis.pysimPliRender = () => { globalThis._pli = (globalThis._pli || 0) + 1; };\n' +
'globalThis.tpRefresh = () => { globalThis._tp = (globalThis._tp || 0) + 1; };\n';
eval(code);
function makeClassList() {
@@ -52,7 +53,7 @@ function setup() {
getElementById: id => panels[id] || null,
};
globalThis._anchor = null;
globalThis._stk = globalThis._events = globalThis._log = globalThis._poll = globalThis._pli = 0;
globalThis._stk = globalThis._events = globalThis._log = globalThis._poll = globalThis._pli = globalThis._tp = 0;
return { buttons, panels };
}
@@ -80,4 +81,5 @@ test('Phone pill shows the phone panel and renders CAT views', () => {
assert.strictEqual(globalThis._log, 1);
assert.strictEqual(globalThis._poll, 1);
assert.strictEqual(globalThis._pli, 0);
assert.strictEqual(globalThis._tp, 1);
});