From 674a9796457544359667bc94f44d430fca7c24d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D0=BD=D1=82=D0=BE=D0=BD=20=D0=A2=D1=80=D0=BE=D1=88?= =?UTF-8?q?=D0=B8=D0=BD?= Date: Thu, 27 Aug 2026 00:07:35 +0300 Subject: [PATCH] Enrich per-event RST/VCC labels (ATR STARTS / power-up) + decode server-side - decode_line_event adds human label: RST de-asserted->ATR STARTS, VCC applied->VCC ON (power-up); keep canonical event string - Enable rst/vcc in DB decode dispatch so PWA receives decoded (fixes bare RESET/VCC fallback and a latent showDetail crash) - PWA line_event_label/showDetail render decoded.label - Bump 1.22.1, SW cache v32->v33; +1 test --- frontend/index.html | 8 ++++---- frontend/sw.js | 2 +- pyproject.toml | 2 +- simtrace2_pysniff/__init__.py | 2 +- simtrace2_pysniff/server/database.py | 2 +- simtrace2_pysniff/server/decode.py | 18 ++++++++++++++++-- tests/test_decode.py | 18 ++++++++++++++++++ tests/test_pcap_import.py | 2 +- 8 files changed, 43 insertions(+), 11 deletions(-) diff --git a/frontend/index.html b/frontend/index.html index bbddcbd..a638635 100644 --- a/frontend/index.html +++ b/frontend/index.html @@ -416,8 +416,8 @@ const INS_NAMES = { // ──────────────────── UI Helpers ──────────────────── function line_event_label(msg) { const d = msg.decoded; - if (msg.type === 'rst') return d && d.event ? 'RESET ' + (d.event === 'reset asserted' ? 'ASSERTED' : 'DE-ASSERTED') : 'RESET'; - if (msg.type === 'vcc') return d && d.event ? 'VCC ' + (d.event === 'power applied' ? 'ON' : 'OFF') : 'VCC'; + if (msg.type === 'rst') return d && d.label ? d.label : 'RESET'; + if (msg.type === 'vcc') return d && d.label ? d.label : 'VCC'; return null; } @@ -1518,7 +1518,7 @@ function showDetail(msg, entry) { } if (decoded.type === 'rst' || decoded.type === 'vcc') { - const evName = decoded.event || (decoded.type === 'rst' ? 'reset event' : 'power event'); + const evName = decoded.label || decoded.event || (decoded.type === 'rst' ? 'reset event' : 'power event'); d.innerHTML = `
${ins_label(msg)}${detail_time_html(msg)}
@@ -2511,7 +2511,7 @@ function onFilterChange() { } // ──────────────────── Versioning ──────────────────── -const PWA_VERSION = '1.22.0'; +const PWA_VERSION = '1.22.1'; const MIN_SERVER_VERSION = '1.0.0'; function parseVersion(v) { diff --git a/frontend/sw.js b/frontend/sw.js index e647328..c68e36b 100644 --- a/frontend/sw.js +++ b/frontend/sw.js @@ -1,4 +1,4 @@ -const CACHE = 'simtrace-analyser-v32'; +const CACHE = 'simtrace-analyser-v33'; const PRECACHE = [ 'index.html', diff --git a/pyproject.toml b/pyproject.toml index f144262..5d5bd23 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "setuptools.backends._legacy:_Backend" [project] name = "simtrace2-pysniff" -version = "1.22.0" +version = "1.22.1" description = "Python-based sniffing tool for SIMtrace2 hardware (SIM card communication sniffer)" readme = {file = "README.md", content-type = "text/markdown"} license = {text = "GPL-2.0-or-later"} diff --git a/simtrace2_pysniff/__init__.py b/simtrace2_pysniff/__init__.py index 7efd2c1..be6f06d 100644 --- a/simtrace2_pysniff/__init__.py +++ b/simtrace2_pysniff/__init__.py @@ -6,7 +6,7 @@ from .gsmtap import GsmtapSender, GsmtapReceiver from .pcap import PcapWriter from .dump import FileDumper, format_message -__version__ = '1.22.0' +__version__ = '1.22.1' __all__ = [ 'SniffSession', 'DeviceDisconnected', diff --git a/simtrace2_pysniff/server/database.py b/simtrace2_pysniff/server/database.py index 30373c9..486705c 100644 --- a/simtrace2_pysniff/server/database.py +++ b/simtrace2_pysniff/server/database.py @@ -230,7 +230,7 @@ class Database: 'data': data_blob.hex(), 'flags': flags, } - if row[3] in ('tpdu', 'change', 'fidi', 'atr', 'pps'): + if row[3] in ('tpdu', 'change', 'fidi', 'atr', 'pps', 'rst', 'vcc'): try: from .decode import decode_sniff_msg msg['decoded'] = decode_sniff_msg(data_blob, row[3], flags, prev=prev) diff --git a/simtrace2_pysniff/server/decode.py b/simtrace2_pysniff/server/decode.py index a4c258d..f8bbb31 100644 --- a/simtrace2_pysniff/server/decode.py +++ b/simtrace2_pysniff/server/decode.py @@ -4018,14 +4018,28 @@ def decode_line_event(raw_data, kind): direction — RST: 1 = asserted (high→low), 0 = de-asserted (low→high); VCC: 1 = power applied (low→high), 0 = removed (high→low). level — resulting line level: 0 = low, 1 = high. + + ``event`` is the canonical value; ``label`` is the human-facing + summary (e.g. RST de-asserted → "ATR STARTS", VCC applied → + "VCC ON (power-up)"). """ result = {'type': kind} if raw_data and len(raw_data) >= 2: direction, level = raw_data[0], raw_data[1] if kind == 'rst': - result['event'] = 'reset asserted' if direction else 'reset de-asserted' + if direction: + result['event'] = 'reset asserted' + result['label'] = 'RESET ASSERTED' + else: + result['event'] = 'reset de-asserted' + result['label'] = 'ATR STARTS' else: - result['event'] = 'power applied' if direction else 'power removed' + if direction: + result['event'] = 'power applied' + result['label'] = 'VCC ON (power-up)' + else: + result['event'] = 'power removed' + result['label'] = 'VCC OFF (power-down)' result['level'] = 'high' if level else 'low' result['raw'] = raw_data.hex().upper() return result diff --git a/tests/test_decode.py b/tests/test_decode.py index 062ed7e..42d373d 100644 --- a/tests/test_decode.py +++ b/tests/test_decode.py @@ -2357,23 +2357,41 @@ class TestLineEvents(unittest.TestCase): r = self._dec('rst', '010000') self.assertEqual(r['type'], 'rst') self.assertEqual(r['event'], 'reset asserted') + self.assertEqual(r['label'], 'RESET ASSERTED') self.assertEqual(r['level'], 'low') def test_rst_deasserted(self): r = self._dec('rst', '000100') self.assertEqual(r['event'], 'reset de-asserted') + self.assertEqual(r['label'], 'ATR STARTS') self.assertEqual(r['level'], 'high') def test_vcc_on(self): r = self._dec('vcc', '010100') self.assertEqual(r['event'], 'power applied') + self.assertEqual(r['label'], 'VCC ON (power-up)') self.assertEqual(r['level'], 'high') def test_vcc_off(self): r = self._dec('vcc', '000000') self.assertEqual(r['event'], 'power removed') + self.assertEqual(r['label'], 'VCC OFF (power-down)') self.assertEqual(r['level'], 'low') + def test_db_roundtrip_label(self): + # rst/vcc must be decoded server-side (database.py dispatch) so the + # PWA receives decoded.label/event, not just the raw bytes. + import tempfile + from simtrace2_pysniff.server.database import Database + with tempfile.NamedTemporaryFile(suffix='.db') as tmp: + db = Database(tmp.name) + sid = db.create_session('capture') + db.insert_message(sid, 0.1, 'rst', bytes.fromhex('000100'), 0) + db.insert_message(sid, 0.2, 'vcc', bytes.fromhex('010100'), 0) + msgs = db.get_messages(sid) + self.assertEqual(msgs[0]['decoded']['label'], 'ATR STARTS') + self.assertEqual(msgs[1]['decoded']['label'], 'VCC ON (power-up)') + def test_sniff_routing(self): from simtrace2_pysniff.server.decode import decode_sniff_msg self.assertEqual(decode_sniff_msg(b'\x01\x00\x00', 'rst')['type'], 'rst') diff --git a/tests/test_pcap_import.py b/tests/test_pcap_import.py index d8011ca..84fd6e4 100644 --- a/tests/test_pcap_import.py +++ b/tests/test_pcap_import.py @@ -224,7 +224,7 @@ class TestImportEndpoint(unittest.TestCase): class TestVersion(unittest.TestCase): def test_package_version(self): from simtrace2_pysniff import __version__ - self.assertEqual(__version__, '1.22.0') + self.assertEqual(__version__, '1.22.1') def test_status_includes_version(self): import os