-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathprotocol_decoder.py
More file actions
154 lines (125 loc) · 4.84 KB
/
Copy pathprotocol_decoder.py
File metadata and controls
154 lines (125 loc) · 4.84 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
"""
Protocol Decoder Module
Supports multiple decoding formats: ASCII, HEX, JSON, and custom frame protocols.
"""
import json
import re
from datetime import datetime
class PacketDecoder:
"""Handles decoding of received data packets in various formats."""
@staticmethod
def decode_ascii(data):
"""Decode data as ASCII text."""
try:
return data.decode('ascii', errors='replace')
except Exception as e:
return f"<Decode Error: {str(e)}>"
@staticmethod
def decode_hex(data):
"""Decode data as hexadecimal."""
return ' '.join(f'{b:02X}' for b in data)
@staticmethod
def decode_hex_compact(data):
"""Decode data as compact hexadecimal (no spaces)."""
return ''.join(f'{b:02X}' for b in data)
@staticmethod
def decode_binary(data):
"""Decode data as binary."""
return ' '.join(f'{b:08b}' for b in data)
@staticmethod
def decode_json(data):
"""Try to decode data as JSON."""
try:
text = data.decode('utf-8', errors='replace')
parsed = json.loads(text)
return json.dumps(parsed, indent=2)
except Exception as e:
return f"<Not valid JSON: {str(e)}>"
@staticmethod
def decode_mixed(data):
"""Decode as ASCII with hex for non-printable characters."""
result = []
for b in data:
if 32 <= b <= 126: # Printable ASCII
result.append(chr(b))
else:
result.append(f'<{b:02X}>')
return ''.join(result)
class CustomFrameDecoder:
"""Decoder for custom frame protocols with configurable delimiters."""
def __init__(self, start_delimiter=b'\x02', end_delimiter=b'\x03',
include_delimiters=True):
self.start_delimiter = start_delimiter
self.end_delimiter = end_delimiter
self.include_delimiters = include_delimiters
self.buffer = b''
def feed_data(self, data):
"""Feed data to the decoder and extract complete frames."""
self.buffer += data
frames = []
while True:
# Find start delimiter
start_idx = self.buffer.find(self.start_delimiter)
if start_idx == -1:
break
# Find end delimiter after start
end_idx = self.buffer.find(self.end_delimiter, start_idx + len(self.start_delimiter))
if end_idx == -1:
break
# Extract frame
if self.include_delimiters:
frame = self.buffer[start_idx:end_idx + len(self.end_delimiter)]
else:
frame = self.buffer[start_idx + len(self.start_delimiter):end_idx]
frames.append(frame)
# Remove processed data from buffer
self.buffer = self.buffer[end_idx + len(self.end_delimiter):]
return frames
def reset(self):
"""Clear the internal buffer."""
self.buffer = b''
class ProtocolParser:
"""Parse protocol-specific data based on configurable rules."""
def __init__(self, profile_name="default"):
self.profile_name = profile_name
self.rules = []
def add_rule(self, name, pattern, description=""):
"""Add a parsing rule with regex pattern."""
self.rules.append({
'name': name,
'pattern': re.compile(pattern),
'description': description
})
def parse(self, data_str):
"""Parse data string against all rules."""
matches = []
for rule in self.rules:
match = rule['pattern'].search(data_str)
if match:
matches.append({
'rule': rule['name'],
'match': match.group(0),
'groups': match.groups(),
'description': rule['description']
})
return matches
class DataPacket:
"""Represents a single data packet with metadata."""
def __init__(self, raw_data, timestamp, port, direction='RX'):
self.raw_data = raw_data
self.timestamp = timestamp
self.port = port
self.direction = direction # 'RX' for received, 'TX' for transmitted
self.decoded_ascii = PacketDecoder.decode_ascii(raw_data)
self.decoded_hex = PacketDecoder.decode_hex(raw_data)
self.size = len(raw_data)
def to_dict(self):
"""Convert packet to dictionary for export."""
return {
'timestamp': self.timestamp,
'port': self.port,
'direction': self.direction,
'size': self.size,
'raw_hex': self.decoded_hex,
'ascii': self.decoded_ascii
}