-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathHighLevelAnalyzer.py
204 lines (176 loc) · 8.08 KB
/
HighLevelAnalyzer.py
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
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
# High Level Analyzer
# For more information and documentation, please go to https://support.saleae.com/extensions/high-level-analyzer-extensions
from saleae.analyzers import HighLevelAnalyzer, AnalyzerFrame
from copy import deepcopy
from CC1101SpiProtocol import CC1101SpiProtocol, ProtocolFrameType, MARC_STATE
SPI_DATA_FRAME = {"mosi": 0, "miso": 0}
class SpiFrameType:
error = "error"
enable = "enable"
disable = "disable"
result = "result"
class SpiFrameState:
idle = 0
start = 1
active = 2
end = 3
error = 4
# High level analyzers must subclass the HighLevelAnalyzer class.
class Hla(HighLevelAnalyzer):
# An optional list of types this analyzer produces, providing a way to customize the way frames are displayed in Logic 2.
result_types = {
'spi error': {
'format': 'Error: {{type}}'
},
ProtocolFrameType.ERROR: {
'format': 'Error: {{type}} | {{data.error_details}}'
},
ProtocolFrameType.REGISTER: {
'format': 'Register: {{data.access}} | {{data.register}} = {{data.focus_data}}'
},
ProtocolFrameType.COMMAND: {
'format': 'Command: {{data.register}}'
},
ProtocolFrameType.STATUS: {
'format': 'Status: {{data.register}} = {{data.focus_data}}'
},
ProtocolFrameType.PA_TABLE: {
'format': 'PA Table: {{data.access}} = {{data.focus_data}}'
},
ProtocolFrameType.FIFO: {
'format': 'FIFO: {{data.access}} = {{data.focus_data}}'
},
}
def __init__(self):
'''
Initialize HLA.
Settings can be accessed using the same name used above.
'''
self.state = SpiFrameState.idle
self.spi_frame_queue = []
self.protocol = CC1101SpiProtocol()
self.start_time = 0
self.end_time = 0
def decode(self, frame: AnalyzerFrame):
'''
Process a frame from the input analyzer, and optionally return a single `AnalyzerFrame` or a list of `AnalyzerFrame`s.
The type and data values in `frame` will depend on the input analyzer.
'''
# Return the data frame itself
return self.frame_state_machine(frame)
def frame_state_machine(self, frame):
return_frame = None
# Check for error frames
if frame.type == SpiFrameType.error:
self.state = SpiFrameState.error
return_frame = AnalyzerFrame("spi error", frame.start_time, frame.end_time, {"error_details": "clock in wrong state when enable signal became active"})
# Check Idle state
if self.state == SpiFrameState.idle:
if frame.type == SpiFrameType.enable:
self.start_time = frame.start_time # Log start time
self.state = SpiFrameState.start
else:
self.state = SpiFrameState.error
# Check Start state
elif self.state == SpiFrameState.start:
if frame.type == SpiFrameType.result:
self.start_time = frame.start_time # Log start time
self.end_time = frame.end_time # Log end time
self.state = SpiFrameState.active
elif frame.type == SpiFrameType.disable:
self.end_time = frame.end_time # Log end time
self.state = SpiFrameState.error
return_frame = AnalyzerFrame("spi error", self.start_time, self.end_time, {"error_details": "no SPI frame"})
else:
self.state = SpiFrameState.error
# Check Active state
elif self.state == SpiFrameState.active:
if frame.type == SpiFrameType.disable:
self.state = SpiFrameState.end
elif frame.type == SpiFrameType.result:
self.end_time = frame.end_time # Log end time
else:
self.state = SpiFrameState.error
# Execute Active state
if self.state == SpiFrameState.active:
self.spi_frame_queue.append(self.get_spi_data_frame(frame))
# Execute End state
if self.state == SpiFrameState.end:
if len(self.spi_frame_queue) > 0:
protocol_msg = self.protocol.process_frame(self.spi_frame_queue)
frame_type, frame_data = self.construct_table(protocol_msg)
return_frame = AnalyzerFrame(frame_type, self.start_time, self.end_time, frame_data)
self.spi_frame_queue.clear()
# Automatic transition
self.state = SpiFrameState.idle
# Execute Error state
elif self.state == SpiFrameState.error:
# Automatic transition
self.state = SpiFrameState.idle
return return_frame
def construct_table(self, protocol_msg):
frame_type = protocol_msg["request"]["type"]
access = protocol_msg["request"]["access"]
burst = protocol_msg["request"]["burst"]
register = protocol_msg["request"]["register"]
request_data = protocol_msg["request"]["data"]
write_data = "" if request_data is None else " ".join(["{:02X}".format(x) for x in request_data])
response = protocol_msg["response"]
chip_ready = "" if response is None else "OK" if response["status"]["chip_rdy"] else "NOT RDY"
state = "" if response is None else response["status"]["state"]
fifo_bytes_available = "" if response is None else "{}".format(response["status"]["fifo_bytes_available"])
read_data = "" if response is None else " ".join(["{:02X}".format(x) for x in response["data"]])
description = protocol_msg["request"]["description"]
focus_data = ""
error_details = ""
# Focus Data is used mainly for the Protocol UI labels
if frame_type == ProtocolFrameType.ERROR:
error_details = protocol_msg["request"]["error"]
elif frame_type == ProtocolFrameType.REGISTER:
focus_data = write_data if access == "W" else read_data
elif frame_type == ProtocolFrameType.COMMAND:
pass
elif frame_type == ProtocolFrameType.STATUS:
if register == "MARCSTATE":
marc_state = response["data"][0]
if marc_state <= 0x16:
focus_data = MARC_STATE[response["data"][0]]["state"]
else:
# See [SWRZ020E] CC1101 Silicon Errata
frame_type = ProtocolFrameType.ERROR
error_details = "Invalid MARCSTATE"
else:
focus_data = read_data
elif frame_type == ProtocolFrameType.PA_TABLE:
focus_data = write_data if access == "W" else read_data
elif frame_type == ProtocolFrameType.FIFO:
focus_data = write_data if access == "W" else read_data
return (
frame_type,
{
"raw_data": self.raw_data(),
"access": access,
"burst": burst,
"register": register,
"write_data": write_data,
"chip_ready": chip_ready,
"state": state,
"fifo_bytes_available": fifo_bytes_available,
"read_data": read_data,
"register_description": description,
"focus_data": focus_data,
"error_details": error_details,
}
)
def from_byte(self, data_raw):
return int.from_bytes(data_raw, "big")
def get_spi_data_frame(self, frame):
spi_data_frame = deepcopy(SPI_DATA_FRAME)
spi_data_frame["mosi"] = self.from_byte(frame.data["mosi"])
spi_data_frame["miso"] = self.from_byte(frame.data["miso"])
return spi_data_frame
def raw_data(self):
content = "["
for frame in self.spi_frame_queue:
content += "({:02X}, {:02X}) ".format(frame["mosi"], frame["miso"])
return content.rstrip() + "]"