terminal profile: fix the per-byte bit order (b1 = LSB), add the inference notes (v2.2.20)
The spec tables (TS 102 223 5.2) list b1 - the least significant bit - first:
verified from the PDF connector geometry (label row 1 connects to the
rightmost cell) and from Wireshark's packet-gsm_sim.c masks ('Profile
download' = 0x01, 'E-UTRAN bearer' = 0x40, 'HSDPA bearer' = 0x80). The
Configure dialog had it mirrored: TP_BITS[n] was matched with 0x80 >> (n%8)
and displayed as b8..b1, so every label toggled the wrong physical bit
(our own BIP-capable default proved it: byte 12 = 0x1F read as DECLARE
SERVICE.. instead of OPEN/CLOSE/RECEIVE/SEND/GET CHANNEL STATUS).
- tpGetBit/tpSetBit now use 1 << (n%8); the form lists b1 first, matching
the spec; tpBitLabel names the RFU fallback bit accordingly.
- Tests pin the new mapping and the corrected spot-check indices, and the
project default is asserted to decode as BIP-capable (OPEN/SEND DATA,
E-UTRAN, HSDPA).
- docs/TERMINAL_PROFILE.md (in projects/docs): everything gathered about
inferring device characteristics from a TP - bit order, profile-length era
bands, headless/modem markers (Annex S ND/NK plus the byte 11/screen-size
heuristics), radio generation (byte 17 b7/b8 with the 'capability, not
attach' caveat), standards family (ESN/IMEISV/TIA/CCAT), BIP capability,
UI paradigm, and a suggested inference model. Corpus: samples/tp_db.csv
(185 profiles, CC-BY-SA, kept out of the repo).
- Help EN/RU note the bit order and point at the new document; AGENTS
records the mapping rule and the doc location.
This commit is contained in:
+12
-12
@@ -18,7 +18,7 @@
|
||||
<div class="max-w-7xl mx-auto px-6 py-2">
|
||||
|
||||
<div class="flex items-center justify-between mb-3">
|
||||
<h1 class="text-2xl font-bold text-heading">OTAMan <span id="slogan" class="text-sm font-normal text-gray-500 dark:text-slate-400 ml-2" data-l10n="SIM OTA with a Human Face">SIM OTA with a Human Face</span> <span class="text-xs text-gray-400 dark:text-slate-500 ml-1">v2.2.19</span></h1>
|
||||
<h1 class="text-2xl font-bold text-heading">OTAMan <span id="slogan" class="text-sm font-normal text-gray-500 dark:text-slate-400 ml-2" data-l10n="SIM OTA with a Human Face">SIM OTA with a Human Face</span> <span class="text-xs text-gray-400 dark:text-slate-500 ml-1">v2.2.20</span></h1>
|
||||
<div class="flex items-center gap-4">
|
||||
<span id="state-indicator" class="flex items-center select-none" style="cursor:default" title="Connecting...">
|
||||
<span id="state-indicator-dot" class="text-xs text-gray-400" title="Connecting...">●</span>
|
||||
@@ -7170,15 +7170,11 @@ const PLI_QUALIFIERS = [
|
||||
{code:'1A',name:'Supported Radio Access Technologies'},
|
||||
];
|
||||
|
||||
// TERMINAL PROFILE bit allocation (TS 102 223 V18.3.0 5.2 + 3GPP
|
||||
// annex bits; bytes 1..33). Index 0 = bit 1 = first byte b8; bit n is
|
||||
// byte floor(n/8)+1, mask 0x80 >> (n%8). Bytes beyond 33 fall back to
|
||||
// generic labels in the UI.
|
||||
// TERMINAL PROFILE bit allocation: bytes 1..39 per ETSI TS 102 223
|
||||
// V18.3.0 5.2, 3GPP-defined bits named per ETSI TS 131 111 V18.12.0 5.2
|
||||
// (no "reserved by 3GPP" placeholders). Index 0 = bit 1 = first byte b8;
|
||||
// bit n is byte floor(n/8)+1, mask 0x80 >> (n%8). Bytes beyond the
|
||||
// table fall back to generic labels in the UI.
|
||||
// (no "reserved by 3GPP" placeholders). Index 0 = the first spec table row
|
||||
// = byte 1 b1 (the LSB); bit n is byte floor(n/8)+1, mask 1 << (n%8).
|
||||
// Bytes beyond the table fall back to generic labels in the UI.
|
||||
const TP_BITS = [
|
||||
'Profile download', 'SMS-PP data download', 'Cell Broadcast data download', 'Menu selection',
|
||||
'SMS-PP data download', 'Timer expiration', 'USSD string data object support in Call Control by USIM', 'Call Control by NAA',
|
||||
@@ -7278,11 +7274,15 @@ function tpNorm(hex) { return (hex || '').toUpperCase().replace(/[^0-9A-F]/g, ''
|
||||
|
||||
function tpValid(hex) { return hex.length > 0 && hex.length % 2 === 0 && hex.length <= 510; }
|
||||
|
||||
// Bit numbering follows TS 102 223 5.2 exactly: within a byte the spec tables
|
||||
// list b1 (the least significant bit) first, so TP_BITS[n] is bit b((n % 8)+1)
|
||||
// of byte (n >> 3)+1. tpGetBit/tpSetBit therefore use the LSB-first mask
|
||||
// (cross-checked against Wireshark's packet-gsm_sim.c: "Profile download"=0x01).
|
||||
function tpGetBit(hex, n) {
|
||||
const byteIdx = n >> 3;
|
||||
if (byteIdx * 2 + 2 > hex.length) return null;
|
||||
const b = parseInt(hex.substr(byteIdx * 2, 2), 16);
|
||||
return !!(b & (0x80 >> (n & 7)));
|
||||
return !!(b & (1 << (n & 7)));
|
||||
}
|
||||
|
||||
function tpSetBit(hex, n, on) {
|
||||
@@ -7290,7 +7290,7 @@ function tpSetBit(hex, n, on) {
|
||||
const byteIdx = n >> 3;
|
||||
while (bytes.length <= byteIdx) bytes.push('00');
|
||||
let b = parseInt(bytes[byteIdx], 16);
|
||||
const mask = 0x80 >> (n & 7);
|
||||
const mask = 1 << (n & 7);
|
||||
b = on ? (b | mask) : (b & ~mask);
|
||||
bytes[byteIdx] = b.toString(16).padStart(2, '0').toUpperCase();
|
||||
return bytes.join('');
|
||||
@@ -7298,7 +7298,7 @@ function tpSetBit(hex, n, on) {
|
||||
|
||||
function tpBitLabel(n) {
|
||||
if (n < TP_BITS.length) return TP_BITS[n];
|
||||
return 'RFU (byte ' + ((n >> 3) + 1) + ' b' + (8 - (n & 7)) + ')';
|
||||
return 'RFU (byte ' + ((n >> 3) + 1) + ' b' + ((n & 7) + 1) + ')';
|
||||
}
|
||||
|
||||
// Fixed byte-block layout: [firstByte, lastByte, columns] with 1-based
|
||||
@@ -7340,7 +7340,7 @@ function tpRenderForm() {
|
||||
html += '<div class="text-gray-500 dark:text-slate-400 mb-0.5">' + esc(t('Byte')) + ' ' + (bi + 1) + '</div>';
|
||||
for (let k = 0; k < 8; k++) {
|
||||
const n = bi * 8 + k;
|
||||
const mask = 'b' + (8 - k);
|
||||
const mask = 'b' + (k + 1); // b1 first, matching the spec tables
|
||||
const label = tpBitLabel(n);
|
||||
html += '<label class="flex items-start gap-1 mb-0.5">' +
|
||||
'<input type="checkbox" class="mt-0.5 shrink-0" ' +
|
||||
|
||||
Reference in New Issue
Block a user