fix: drop the "Reserved for 3GPP" event-name cross-reference (v3.6.22)

The event list tables carried labels like
"12  Reserved for 3GPP - Network rejection (TS 31.111 7.5.2)".  The phrase is
an ETSI-to-3GPP document pointer, not a usage restriction, and it is not
what a user needs - the event name is.

- EVENT_NAMES (PWA + server mirror): the 3GPP-assigned codings carry their
  plain TS 31.111 7.5 name ((I-)WLAN access status, Network rejection, CSG
  cell selection, IMS registration, Incoming IMS data, Data connection
  status change, CAG cell selection, Slices status change).
- 0x20-0x22: "Reserved (future usage)" (no attribution).
- 0x0B/0x14: the spec's full "(single access technology)" / "(multiple
  access technologies)" wording instead of the cryptic "(single)/(multiple)".
- tests pin the exact names and that no name contains the cross-reference.

652 frontend / 500 Python green; version 3.6.22; sw simple-v295.
This commit is contained in:
2026-09-28 21:54:28 +03:00
parent 5372a770eb
commit 3c104f5685
6 changed files with 68 additions and 59 deletions
+18 -17
View File
@@ -1711,7 +1711,7 @@
// ===== Version =====
// Single source of truth for the PWA version: shown in the header and used
// by the server version check in pysimConnect().
const SIMPLE_VERSION = '3.6.21';
const SIMPLE_VERSION = '3.6.22';
document.getElementById('app-version').textContent = 'v' + SIMPLE_VERSION;
// ===== Tab switching =====
@@ -10730,34 +10730,35 @@ function pysimFsResetEdit() {
}
// ===== proactive UICC events =====
// Event list codings (TS 102 223 v18.3.0 8.25). Values the CAT spec leaves
// "Reserved for 3GPP" carry the concrete 3GPP event name where TS 31.111
// defines one (clause in parentheses), so the list stays informative.
// Event list codings (TS 102 223 v18.3.0 8.25). The values the CAT spec only
// points at 3GPP for carry their TS 31.111 7.5 event name; "Reserved for
// 3GPP" is a spec cross-reference, not a usage restriction, so it never
// appears in the user-facing names.
const EVENT_NAMES = {
0x00: 'MT call', 0x01: 'Call connected', 0x02: 'Call disconnected',
0x03: 'Location status', 0x04: 'User activity', 0x05: 'Idle screen available',
0x06: 'Card reader status', 0x07: 'Language selection',
0x08: 'Browser termination', 0x09: 'Data available',
0x0A: 'Channel status', 0x0B: 'Access technology change (single)',
0x0A: 'Channel status', 0x0B: 'Access technology change (single access technology)',
0x0C: 'Display parameters changed', 0x0D: 'Local connection',
0x0E: 'Network search mode change', 0x0F: 'Browsing status',
0x10: 'Frames information change',
0x11: 'Reserved for 3GPP — (I-)WLAN access status (TS 31.111 7.5.1)',
0x12: 'Reserved for 3GPP — Network rejection (TS 31.111 7.5.2)',
0x11: '(I-)WLAN access status',
0x12: 'Network rejection',
0x13: 'HCI connectivity',
0x14: 'Access technology change (multiple)',
0x15: 'Reserved for 3GPP — CSG cell selection (TS 31.111 7.5.3)',
0x14: 'Access technology change (multiple access technologies)',
0x15: 'CSG cell selection',
0x16: 'Contactless state request',
0x17: 'Reserved for 3GPP — IMS registration (TS 31.111 7.5.21)',
0x18: 'Reserved for 3GPP — Incoming IMS data (TS 31.111 7.5.20)',
0x17: 'IMS registration',
0x18: 'Incoming IMS data',
0x19: 'Profile container', 0x1A: 'Void', 0x1B: 'Secured profile container',
0x1C: 'Poll interval negotiation',
0x1D: 'Reserved for 3GPP — Data connection status change (TS 31.111 7.5.25)',
0x1E: 'Reserved for 3GPP — CAG cell selection (TS 31.111 7.5.26)',
0x1F: 'Reserved for 3GPP — Slices status change (TS 31.111 7.5.27)',
0x20: 'Reserved for 3GPP (future usage)',
0x21: 'Reserved for 3GPP (future usage)',
0x22: 'Reserved for 3GPP (future usage)',
0x1D: 'Data connection status change',
0x1E: 'CAG cell selection',
0x1F: 'Slices status change',
0x20: 'Reserved (future usage)',
0x21: 'Reserved (future usage)',
0x22: 'Reserved (future usage)',
};
const REJECTION_CAUSES = [
+1 -1
View File
@@ -1,4 +1,4 @@
const CACHE = 'simple-v294';
const CACHE = 'simple-v295';
const URLS = [
'index.html',
'help.html',
+9 -5
View File
@@ -66,15 +66,19 @@ test('cmdQualifierShort returns empty for unknown types', () => {
});
test('EVENT_NAMES follows the pinned CAT spec and names the 3GPP events', () => {
assert.strictEqual(EVENT_NAMES[0x0B], 'Access technology change (single)');
assert.strictEqual(EVENT_NAMES[0x14], 'Access technology change (multiple)');
assert.strictEqual(EVENT_NAMES[0x0B], 'Access technology change (single access technology)');
assert.strictEqual(EVENT_NAMES[0x14], 'Access technology change (multiple access technologies)');
assert.strictEqual(EVENT_NAMES[0x19], 'Profile container');
assert.strictEqual(EVENT_NAMES[0x1C], 'Poll interval negotiation');
for (const [v, frag] of [[0x11, '(I-)WLAN access status'], [0x12, 'Network rejection'],
for (const [v, name] of [[0x11, '(I-)WLAN access status'], [0x12, 'Network rejection'],
[0x15, 'CSG cell selection'], [0x17, 'IMS registration'], [0x18, 'Incoming IMS data'],
[0x1D, 'Data connection status change'], [0x1E, 'CAG cell selection'],
[0x1F, 'Slices status change']]) {
assert.ok(EVENT_NAMES[v].includes(frag), '0x' + v.toString(16) + ': ' + EVENT_NAMES[v]);
[0x1F, 'Slices status change'], [0x20, 'Reserved (future usage)']]) {
assert.strictEqual(EVENT_NAMES[v], name, '0x' + v.toString(16));
}
// the "Reserved for 3GPP" spec cross-reference is never user-facing
for (const [v, name] of Object.entries(EVENT_NAMES)) {
assert.ok(!name.includes('Reserved for 3GPP'), v + ': ' + name);
}
});
+1 -1
View File
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
[project]
name = "pysim-simple-server"
version = "3.6.21"
version = "3.6.22"
description = "HTTP REST server wrapping pysim for the SIMple PWA"
requires-python = ">=3.8"
# pysim is a git-only dependency installed explicitly by setup.bat/setup.sh.
+18 -17
View File
@@ -31,7 +31,7 @@ from osmocom.tlv import BER_TLV_IE
from osmocom.utils import rpad
VERSION = '3.6.21'
VERSION = '3.6.22'
MAX_ENVELOPE_SEGMENTS = 5 # max SMS segments for outgoing C-APDU in ENVELOPE
@@ -1769,34 +1769,35 @@ def _tr_data_only(tr_tlv):
return bytes(data)
# Event list codings (TS 102 223 v18.3.0 8.25). Values the CAT spec leaves
# "Reserved for 3GPP" carry the concrete 3GPP event name where TS 31.111
# defines one (clauses in parentheses), so the list stays informative.
# Event list codings (TS 102 223 v18.3.0 8.25). The values the CAT spec only
# points at 3GPP for carry their TS 31.111 7.5 event name; "Reserved for
# 3GPP" is a spec cross-reference, not a usage restriction, so it never
# appears in the user-facing names.
EVENT_NAMES = {
0x00: 'MT call', 0x01: 'Call connected', 0x02: 'Call disconnected',
0x03: 'Location status', 0x04: 'User activity', 0x05: 'Idle screen available',
0x06: 'Card reader status', 0x07: 'Language selection',
0x08: 'Browser termination', 0x09: 'Data available',
0x0A: 'Channel status', 0x0B: 'Access technology change (single)',
0x0A: 'Channel status', 0x0B: 'Access technology change (single access technology)',
0x0C: 'Display parameters changed', 0x0D: 'Local connection',
0x0E: 'Network search mode change', 0x0F: 'Browsing status',
0x10: 'Frames information change',
0x11: 'Reserved for 3GPP \u2014 (I-)WLAN access status (TS 31.111 7.5.1)',
0x12: 'Reserved for 3GPP \u2014 Network rejection (TS 31.111 7.5.2)',
0x11: '(I-)WLAN access status',
0x12: 'Network rejection',
0x13: 'HCI connectivity',
0x14: 'Access technology change (multiple)',
0x15: 'Reserved for 3GPP \u2014 CSG cell selection (TS 31.111 7.5.3)',
0x14: 'Access technology change (multiple access technologies)',
0x15: 'CSG cell selection',
0x16: 'Contactless state request',
0x17: 'Reserved for 3GPP \u2014 IMS registration (TS 31.111 7.5.21)',
0x18: 'Reserved for 3GPP \u2014 Incoming IMS data (TS 31.111 7.5.20)',
0x17: 'IMS registration',
0x18: 'Incoming IMS data',
0x19: 'Profile container', 0x1A: 'Void', 0x1B: 'Secured profile container',
0x1C: 'Poll interval negotiation',
0x1D: 'Reserved for 3GPP \u2014 Data connection status change (TS 31.111 7.5.25)',
0x1E: 'Reserved for 3GPP \u2014 CAG cell selection (TS 31.111 7.5.26)',
0x1F: 'Reserved for 3GPP \u2014 Slices status change (TS 31.111 7.5.27)',
0x20: 'Reserved for 3GPP (future usage)',
0x21: 'Reserved for 3GPP (future usage)',
0x22: 'Reserved for 3GPP (future usage)',
0x1D: 'Data connection status change',
0x1E: 'CAG cell selection',
0x1F: 'Slices status change',
0x20: 'Reserved (future usage)',
0x21: 'Reserved (future usage)',
0x22: 'Reserved (future usage)',
}
ACCESSTECH_NAMES = {
+21 -18
View File
@@ -36,35 +36,38 @@ class ProactiveTypeNamesTests(unittest.TestCase):
class EventNamesTests(unittest.TestCase):
"""Event list names follow TS 102 223 v18.3.0 8.25; the values the CAT
spec leaves "Reserved for 3GPP" carry the TS 31.111 event name."""
spec points at 3GPP for carry their TS 31.111 7.5 event name."""
def test_reassigned_values_match_the_pinned_spec(self):
for value, name in [
(0x0B, 'Access technology change (single)'),
(0x14, 'Access technology change (multiple)'),
(0x0B, 'Access technology change (single access technology)'),
(0x14, 'Access technology change (multiple access technologies)'),
(0x19, 'Profile container'),
(0x1A, 'Void'),
(0x1B, 'Secured profile container'),
(0x1C, 'Poll interval negotiation'),
(0x20, 'Reserved for 3GPP (future usage)'),
(0x20, 'Reserved (future usage)'),
]:
self.assertEqual(EVENT_NAMES[value], name, hex(value))
def test_3gpp_reserved_events_carry_their_3gpp_name(self):
for value, fragment, clause in [
(0x11, '(I-)WLAN access status', 'TS 31.111 7.5.1'),
(0x12, 'Network rejection', 'TS 31.111 7.5.2'),
(0x15, 'CSG cell selection', 'TS 31.111 7.5.3'),
(0x17, 'IMS registration', 'TS 31.111 7.5.21'),
(0x18, 'Incoming IMS data', 'TS 31.111 7.5.20'),
(0x1D, 'Data connection status change', 'TS 31.111 7.5.25'),
(0x1E, 'CAG cell selection', 'TS 31.111 7.5.26'),
(0x1F, 'Slices status change', 'TS 31.111 7.5.27'),
def test_3gpp_assigned_events_carry_their_name(self):
for value, name in [
(0x11, '(I-)WLAN access status'),
(0x12, 'Network rejection'),
(0x15, 'CSG cell selection'),
(0x17, 'IMS registration'),
(0x18, 'Incoming IMS data'),
(0x1D, 'Data connection status change'),
(0x1E, 'CAG cell selection'),
(0x1F, 'Slices status change'),
]:
name = EVENT_NAMES[value]
self.assertIn('Reserved for 3GPP', name, hex(value))
self.assertIn(fragment, name, hex(value))
self.assertIn(clause, name, hex(value))
self.assertEqual(EVENT_NAMES[value], name, hex(value))
def test_no_reserved_for_3gpp_wording(self):
# a spec cross-reference, not a usage restriction - it must never
# reach the user-facing names
for value, name in EVENT_NAMES.items():
self.assertNotIn('Reserved for 3GPP', name, hex(value))
def test_names_are_nonempty_strings(self):
for value, name in EVENT_NAMES.items():