TERMINAL PROFILE: device characteristics in list + detail views

- decode.py: _decode_terminal_profile (TS 102 223 §5.2, b1 = LSB per the
  spec tables): class (declared ND/NK at byte 14 b6/b7, strict likely/
  handset rules), generation (positive-only 3G/HSDPA, 4G/E-UTRAN from
  byte 17 — never a 2G claim, real devices under-declare), BIP (byte 12
  b1, byte 13 bearers/channels, byte 17 transports), standards family
  (byte 18 IMEISV/ESN), UI facts (soft keys/screen/markup), era band
- list summary replaces raw hex: e.g. '3G/4G · BIP', 'modem · BIP',
  'no BIP', fallback '<n>-byte profile'
- detail view: tpRows() panel with class/reason, radio bits, BIP,
  standards, UI, profile length
- body row label for TERMINAL PROFILE: 'TLV data' -> 'Profile'
- tests: TERMINAL_PROFILE.md §10 regression anchors + synthetic
  declared-modem/handset vectors
- Bump 1.22.21, SW cache v52->v53
This commit is contained in:
catarrh committed 2026-09-19 01:39:34 +03:00
1 parent 2c373f50b7
commit 8441b56e99
7 files changed
+261 -6

No files matched your search

+45 -1
View File
@@ -1128,6 +1128,49 @@ const API = {
function el(id) { return document.getElementById(id); }
function $on(id, ev, fn) { el(id).addEventListener(ev, fn); }
function tpRows(tp) {
if (!tp) return '';
const rows = [];
if (tp.device_class === 'modem') {
rows.push(['Device class', 'headless/modem — ' + (tp.class_reason || '')]);
} else if (tp.device_class === 'handset') {
rows.push(['Device class', 'handset — ' + (tp.class_reason || '')]);
} else {
rows.push(['Device class', 'not determined']);
}
const gen = [];
if (tp.hsdpa) gen.push('HSDPA (3G)');
if (tp.eutran) gen.push('E-UTRAN (4G)');
rows.push(['Radio', gen.length
? 'declared: ' + gen.join(', ')
: 'no 3G/4G capability declared (under-declaration is common)']);
if (tp.utran_ps) rows.push(['UTRAN PS ext.', 'declared']);
if (tp.bip === true) {
let v = 'capable';
if (tp.bip_channels != null) {
v += ' — ' + tp.bip_channels + ' channel' + (tp.bip_channels === 1 ? '' : 's');
}
if (tp.bip_bearers && tp.bip_bearers.length) v += ' · ' + tp.bip_bearers.join(', ');
rows.push(['BIP', v]);
if (tp.bip_transports && tp.bip_transports.length) {
rows.push(['BIP transports', tp.bip_transports.join(', ')]);
}
} else if (tp.bip === false) {
rows.push(['BIP', 'not advertised (no OPEN CHANNEL)']);
}
if (tp.standards) rows.push(['Standards', tp.standards]);
const ui = [];
if (tp.soft_keys != null) ui.push('soft keys ' + tp.soft_keys);
if (tp.screen_h != null || tp.screen_w != null) {
ui.push('screen ' + (tp.screen_h || 0) + '×' + (tp.screen_w || 0) + ' chars');
}
if (tp.markup && tp.markup.length) ui.push('markup ' + tp.markup.join('/'));
if (ui.length) rows.push(['UI', ui.join(' · ')]);
rows.push(['Profile', tp.length + ' bytes — ' + (tp.era || '')]);
return `<tr><td class="label" colspan="2" style="padding-top:6px; border-top:1px solid var(--border);">Terminal profile</td></tr>` +
rows.map(([l, v]) => `<tr><td class="label">${l}</td><td class="value">${v}</td></tr>`).join('');
}
function responseRows(resp) {
if (!resp) return '';
const rows = [];
@@ -1694,6 +1737,7 @@ function showDetail(msg, entry) {
${body}
${cmdRows(decoded.cmd)}
${responseRows(decoded.response)}
${tpRows(decoded.tp)}
${fileRows(decoded.file)}
${sw}
${decoded.errors ? `<tr><td class="label">Errors</td><td class="value" style="color:var(--error)">${decoded.errors.join(', ')}</td></tr>` : ''}
@@ -2637,7 +2681,7 @@ function onFilterChange() {
}
// ──────────────────── Versioning ────────────────────
const PWA_VERSION = '1.22.20';
const PWA_VERSION = '1.22.21';
const MIN_SERVER_VERSION = '1.0.0';
function parseVersion(v) {
+1 -1
View File
@@ -1,4 +1,4 @@
const CACHE = 'simtrace-analyser-v52';
const CACHE = 'simtrace-analyser-v53';
const PRECACHE = [
'index.html',