From e68df163a9aa5f3df78628b214bea918a58a43ad 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: Wed, 12 Aug 2026 20:02:45 +0300 Subject: [PATCH] TERMINAL RESPONSE: label as 'TERMINAL RESPONSE', keep command type as context decode.py: split decode_tr_command() out of decode_cat(); TR (0x14) now stores the echoed proactive command type in 'response_to' instead of 'cat_command', so it no longer overrides the INS name. FETCH/ENVELOPE still use cat_command as the primary label. tests: TR now asserts response_to + no cat_command --- simtrace2_pysniff/server/decode.py | 28 +++++++++++++++++++++------- tests/test_decode.py | 11 ++++++----- 2 files changed, 27 insertions(+), 12 deletions(-) diff --git a/simtrace2_pysniff/server/decode.py b/simtrace2_pysniff/server/decode.py index 41ac924..8346b8f 100644 --- a/simtrace2_pysniff/server/decode.py +++ b/simtrace2_pysniff/server/decode.py @@ -497,10 +497,19 @@ def decode_cat(ins, body): return CAT_COMMAND_TYPES.get(v2[1]) elif ins == 0xC2: # ENVELOPE → envelope type return ENVELOPE_TYPES.get(body[0]) - elif ins == 0x14: # TERMINAL RESPONSE → echoes proactive command type - for tag, _length, value in parse_tlv(body): - if tag == 0x81 and len(value) >= 2: - return CAT_COMMAND_TYPES.get(value[1]) + return None + + +def decode_tr_command(body): + """Extract the proactive command type echoed in a TERMINAL RESPONSE body. + + Returns the CAT command name (context the TR is responding to), or None. + """ + if not body: + return None + for tag, _length, value in parse_tlv(body): + if tag == 0x81 and len(value) >= 2: + return CAT_COMMAND_TYPES.get(value[1]) return None @@ -575,9 +584,14 @@ def decode_message(raw_data, prev=None): if h in fids: result['body']['note'] = fids[h] - cat_command = decode_cat(ins, body) - if cat_command: - result['cat_command'] = cat_command + if ins == 0x14: + response_to = decode_tr_command(body) + if response_to: + result['response_to'] = response_to + else: + cat_command = decode_cat(ins, body) + if cat_command: + result['cat_command'] = cat_command # SW if sw_bytes: diff --git a/tests/test_decode.py b/tests/test_decode.py index 86d6c55..dac9244 100644 --- a/tests/test_decode.py +++ b/tests/test_decode.py @@ -66,11 +66,12 @@ class TestCatDecoding(unittest.TestCase): self.assertEqual(r['ins_name'], 'ENVELOPE') self.assertEqual(r['cat_command'], 'EVENT DOWNLOAD') - def test_tr_has_cat(self): + def test_tr_has_response_to(self): r = decode_message(bytes.fromhex( '801400000C8103010500020282810301009130')) self.assertEqual(r['ins_name'], 'TERMINAL RESPONSE') - self.assertEqual(r['cat_command'], 'SET UP EVENT LIST') + self.assertNotIn('cat_command', r) + self.assertEqual(r['response_to'], 'SET UP EVENT LIST') def test_select_no_cat(self): r = decode_message(bytes.fromhex('a0a40000023f009000')) @@ -124,17 +125,17 @@ class TestTerminalResponse(unittest.TestCase): r = decode_message(bytes.fromhex( '801400000C8103010500020282810301009130')) self.assertEqual(r['ins_name'], 'TERMINAL RESPONSE') - self.assertEqual(r['cat_command'], 'SET UP EVENT LIST') + self.assertEqual(r['response_to'], 'SET UP EVENT LIST') def test_tr_setup_menu(self): r = decode_message(bytes.fromhex( '801400000C810301250002028281830100910F')) - self.assertEqual(r['cat_command'], 'SET UP MENU') + self.assertEqual(r['response_to'], 'SET UP MENU') def test_tr_poll_interval(self): r = decode_message(bytes.fromhex( '80140000108103010300020282810301000402011E9000')) - self.assertEqual(r['cat_command'], 'POLL INTERVAL') + self.assertEqual(r['response_to'], 'POLL INTERVAL') class TestGetResponseContext(unittest.TestCase):