Skip to content

Commit ea45531

Browse files
committed
ZGW-3430: Add Z-Wave API serial logs
Add a decoder to parse the SAPI logs generated by the Z/IP Gateway. The original script works on ZPC. This commit adapts the script to parse traces generated by the Z/IP Gateway. Original script available at https://github.com/SiliconLabs/UnifySDK/blob/ver_1.6.0/scripts/serial_decode_zpc.py
1 parent c6c87c6 commit ea45531

File tree

1 file changed

+304
-0
lines changed

1 file changed

+304
-0
lines changed
Lines changed: 304 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,304 @@
1+
#!/usr/bin/env python3
2+
# SPDX-License-Identifier: LicenseRef-MSLA
3+
# SPDX-FileCopyrightText: Silicon Laboratories Inc. https://www.silabs.com
4+
'''
5+
Created on 08/11/2011
6+
7+
@author: aes
8+
9+
Original version:
10+
https://github.com/SiliconLabs/UnifySDK/blob/ver_1.6.0/scripts/serial_decode_zpc.py
11+
'''
12+
13+
import shutil
14+
import sys
15+
16+
# Frame format Z-Wave Host API Specification, version 0.7.2. Section 3.2
17+
18+
SOF = 0x01
19+
ACK = 0x06
20+
CAN = 0x18
21+
NAK = 0x15
22+
23+
# frame_type = {
24+
# 'SOF': 0x01,
25+
# 'ACK': 0x06,
26+
# 'CAN': 0x18,
27+
# 'NAK': 0x15,
28+
# }
29+
30+
funcids=dict()
31+
32+
funcids[0x01] = "FUNC_ID_SERIAL_API_HELO"
33+
funcids[0x02] = "FUNC_ID_SERIAL_API_GET_INIT_DATA"
34+
funcids[0x03] = "FUNC_ID_SERIAL_API_APPL_NODE_INFORMATION"
35+
funcids[0x04] = "FUNC_ID_APPLICATION_COMMAND_HANDLER"
36+
funcids[0x05] = "FUNC_ID_ZW_GET_CONTROLLER_CAPABILITIES"
37+
funcids[0x06] = "FUNC_ID_SERIAL_API_SET_TIMEOUTS"
38+
funcids[0x07] = "FUNC_ID_SERIAL_API_GET_CAPABILITIES"
39+
funcids[0x08] = "FUNC_ID_SERIAL_API_SOFT_RESET"
40+
funcids[0x09] = "FUNC_ID_ZW_GET_PROTOCOL_VERSION"
41+
funcids[0x10] = "FUNC_ID_ZW_SET_RF_RECEIVE_MODE"
42+
funcids[0x0a] = "FUNC_ID_SERIALAPI_STARTED"
43+
funcids[0x0b] = "FUNC_ID_SERIALAPI_SETUP"
44+
funcids[0x11] = "FUNC_ID_ZW_SET_SLEEP_MODE"
45+
funcids[0x12] = "FUNC_ID_ZW_SEND_NODE_INFORMATION"
46+
funcids[0x13] = "FUNC_ID_ZW_SEND_DATA"
47+
funcids[0x14] = "FUNC_ID_ZW_SEND_DATA_MULTI"
48+
funcids[0x15] = "FUNC_ID_ZW_GET_VERSION"
49+
funcids[0x16] = "FUNC_ID_ZW_SEND_DATA_ABORT"
50+
funcids[0x17] = "FUNC_ID_ZW_RF_POWER_LEVEL_SET"
51+
funcids[0x18] = "FUNC_ID_ZW_SEND_DATA_META"
52+
funcids[0x19] = "FUNC_ID_ZW_RESERVED_SD"
53+
funcids[0x1A] = "FUNC_ID_ZW_RESERVED_SDM"
54+
funcids[0x1B] = "FUNC_ID_ZW_RESERVED_SRI"
55+
funcids[0x1B] = "FUNC_ID_ZW_SET_ROUTING_INFO"
56+
funcids[0x1C] = "FUNC_ID_ZW_GET_RANDOM"
57+
funcids[0x1D] = "FUNC_ID_ZW_RANDOM"
58+
funcids[0x1E] = "FUNC_ID_ZW_RF_POWER_LEVEL_REDISCOVERY_SET"
59+
funcids[0x20] = "FUNC_ID_MEMORY_GET_ID"
60+
funcids[0x21] = "FUNC_ID_MEMORY_GET_BYTE"
61+
funcids[0x22] = "FUNC_ID_MEMORY_PUT_BYTE"
62+
funcids[0x23] = "FUNC_ID_MEMORY_GET_BUFFER"
63+
funcids[0x24] = "FUNC_ID_MEMORY_PUT_BUFFER"
64+
funcids[0x25] = "FUNC_ID_SERIAL_API_GET_APPL_HOST_MEMORY_OFFSET"
65+
funcids[0x26] = "FUNC_ID_DEBUG_OUTPUT"
66+
funcids[0x27] = "FUNC_ID_AUTO_PROGRAMMING"
67+
funcids[0x28] = "FUNC_ID_NVR_GET_VALUE"
68+
funcids[0x29] = "FUNC_ID_NVM_GET_ID"
69+
funcids[0x2A] = "FUNC_ID_NVM_EXT_READ_LONG_BUFFER"
70+
funcids[0x2B] = "FUNC_ID_NVM_EXT_WRITE_LONG_BUFFER"
71+
funcids[0x2C] = "FUNC_ID_NVM_EXT_READ_LONG_BYTE"
72+
funcids[0x2D] = "FUNC_ID_NVM_EXT_WRITE_LONG_BYTE"
73+
funcids[0x2E] = "FUNC_ID_NVM_BACKUP_RESTORE"
74+
funcids[0x30] = "FUNC_ID_CLOCK_SET"
75+
funcids[0x31] = "FUNC_ID_CLOCK_GET"
76+
funcids[0x32] = "FUNC_ID_CLOCK_CMP"
77+
funcids[0x33] = "FUNC_ID_RTC_TIMER_CREATE"
78+
funcids[0x34] = "FUNC_ID_RTC_TIMER_READ"
79+
funcids[0x35] = "FUNC_ID_RTC_TIMER_DELETE"
80+
funcids[0x36] = "FUNC_ID_RTC_TIMER_CALL"
81+
funcids[0x37] = "FUNC_ID_CLEAR_TX_TIMERS"
82+
funcids[0x38] = "FUNC_ID_GET_TX_TIMERS"
83+
funcids[0x3B] = "FUNC_ID_ZW_GET_BACKGROUND_RSSI"
84+
funcids[0x3F] = "FUNC_ID_ZW_REMOVE_NODE_ID_FROM_NETWORK"
85+
funcids[0x40] = "FUNC_ID_ZW_SET_LEARN_NODE_STATE"
86+
funcids[0x41] = "FUNC_ID_ZW_GET_NODE_PROTOCOL_INFO"
87+
funcids[0x42] = "FUNC_ID_ZW_SET_DEFAULT"
88+
funcids[0x43] = "FUNC_ID_ZW_NEW_CONTROLLER"
89+
funcids[0x44] = "FUNC_ID_ZW_REPLICATION_COMMAND_COMPLETE"
90+
funcids[0x45] = "FUNC_ID_ZW_REPLICATION_SEND_DATA"
91+
funcids[0x46] = "FUNC_ID_ZW_ASSIGN_RETURN_ROUTE"
92+
funcids[0x47] = "FUNC_ID_ZW_DELETE_RETURN_ROUTE"
93+
funcids[0x48] = "FUNC_ID_ZW_REQUEST_NODE_NEIGHBOR_UPDATE"
94+
funcids[0x49] = "FUNC_ID_ZW_APPLICATION_UPDATE"
95+
funcids[0x49] = "FUNC_ID_ZW_APPLICATION_CONTROLLER_UPDATE"
96+
funcids[0x4A] = "FUNC_ID_ZW_ADD_NODE_TO_NETWORK"
97+
funcids[0x4B] = "FUNC_ID_ZW_REMOVE_NODE_FROM_NETWORK"
98+
funcids[0x4C] = "FUNC_ID_ZW_CREATE_NEW_PRIMARY"
99+
funcids[0x4D] = "FUNC_ID_ZW_CONTROLLER_CHANGE"
100+
funcids[0x4E] = "FUNC_ID_ZW_RESERVED_FN"
101+
funcids[0x4F] = "FUNC_ID_ZW_RESERVED_AR"
102+
funcids[0x50] = "FUNC_ID_ZW_SET_LEARN_MODE"
103+
funcids[0x51] = "FUNC_ID_ZW_ASSIGN_SUC_RETURN_ROUTE"
104+
funcids[0x52] = "FUNC_ID_ZW_ENABLE_SUC"
105+
funcids[0x53] = "FUNC_ID_ZW_REQUEST_NETWORK_UPDATE"
106+
funcids[0x54] = "FUNC_ID_ZW_SET_SUC_NODE_ID"
107+
funcids[0x55] = "FUNC_ID_ZW_DELETE_SUC_RETURN_ROUTE"
108+
funcids[0x56] = "FUNC_ID_ZW_GET_SUC_NODE_ID"
109+
funcids[0x57] = "FUNC_ID_ZW_SEND_SUC_ID"
110+
funcids[0x58] = "FUNC_ID_ZW_RESERVED_ASR"
111+
funcids[0x59] = "FUNC_ID_ZW_REDISCOVERY_NEEDED"
112+
funcids[0x5A] = "FUNC_ID_ZW_REQUEST_NODE_NEIGHBOR_UPDATE_OPTION"
113+
funcids[0x5B] = "FUNC_ID_ZW_SUPPORT9600_ONLY"
114+
funcids[0x5C] = "FUNC_ID_ZW_REQUEST_NEW_ROUTE_DESTINATIONS"
115+
funcids[0x5D] = "FUNC_ID_ZW_IS_NODE_WITHIN_DIRECT_RANGE"
116+
funcids[0x5E] = "FUNC_ID_ZW_EXPLORE_REQUEST_INCLUSION"
117+
funcids[0x5F] = "FUNC_ID_ZW_EXPLORE_REQUEST_EXCLUSION"
118+
funcids[0x60] = "FUNC_ID_ZW_REQUEST_NODE_INFO"
119+
funcids[0x61] = "FUNC_ID_ZW_REMOVE_FAILED_NODE_ID"
120+
funcids[0x62] = "FUNC_ID_ZW_IS_FAILED_NODE_ID"
121+
funcids[0x63] = "FUNC_ID_ZW_REPLACE_FAILED_NODE"
122+
funcids[0x65] = "FUNC_ID_ZW_SET_ROUTING_MAX_6_00"
123+
funcids[0x66] = "FUNC_ID_ZW_IS_PRIMARY_CTRL"
124+
funcids[0x67] = "FUNC_ID_ZW_AES_ECB"
125+
funcids[0x70] = "FUNC_ID_TIMER_START"
126+
funcids[0x71] = "FUNC_ID_TIMER_RESTART"
127+
funcids[0x72] = "FUNC_ID_TIMER_CANCEL"
128+
funcids[0x73] = "FUNC_ID_TIMER_CALL"
129+
funcids[0x80] = "FUNC_ID_GET_ROUTING_TABLE_LINE"
130+
funcids[0x81] = "FUNC_ID_GET_TX_COUNTER"
131+
funcids[0x82] = "FUNC_ID_RESET_TX_COUNTER"
132+
funcids[0x83] = "FUNC_ID_STORE_NODEINFO"
133+
funcids[0x84] = "FUNC_ID_STORE_HOMEID"
134+
funcids[0x90] = "FUNC_ID_LOCK_ROUTE_RESPONSE"
135+
funcids[0x91] = "FUNC_ID_ZW_SEND_DATA_ROUTE_DEMO"
136+
funcids[0x92] = "FUNC_ID_ZW_GET_LAST_WORKING_ROUTE"
137+
funcids[0x93] = "FUNC_ID_ZW_SET_LAST_WORKING_ROUTE"
138+
funcids[0x95] = "FUNC_ID_SERIAL_API_TEST"
139+
funcids[0x98] = "FUNC_ID_SERIAL_API_EXT"
140+
funcids[0xA0] = "FUNC_ID_SERIAL_API_APPL_SLAVE_NODE_INFORMATION"
141+
funcids[0xA1] = "FUNC_ID_APPLICATION_SLAVE_COMMAND_HANDLER"
142+
funcids[0xA2] = "FUNC_ID_ZW_SEND_SLAVE_NODE_INFORMATION"
143+
funcids[0xA3] = "FUNC_ID_ZW_SEND_SLAVE_DATA"
144+
funcids[0xA4] = "FUNC_ID_ZW_SET_SLAVE_LEARN_MODE"
145+
funcids[0xA5] = "FUNC_ID_ZW_GET_VIRTUAL_NODES"
146+
funcids[0xA6] = "FUNC_ID_ZW_IS_VIRTUAL_NODE"
147+
funcids[0xA7] = "FUNC_ID_ZW_RESERVED_SSD"
148+
funcids[0xA8] = "FUNC_ID_APPLICATION_COMMAND_HANDLER_BRIDGE"
149+
funcids[0xA9] = "FUNC_ID_ZW_SEND_DATA_BRIDGE"
150+
funcids[0xAA] = "FUNC_ID_ZW_SEND_DATA_META_BRIDGE"
151+
funcids[0xAB] = "FUNC_ID_ZW_SEND_DATA_MULTI_BRIDGE"
152+
funcids[0xB0] = "FUNC_ID_PWR_SETSTOPMODE"
153+
funcids[0xB1] = "FUNC_ID_PWR_CLK_PD"
154+
funcids[0xB2] = "FUNC_ID_PWR_CLK_PUP"
155+
funcids[0xB3] = "FUNC_ID_PWR_SELECT_CLK"
156+
funcids[0xB4] = "FUNC_ID_ZW_SET_WUT_TIMEOUT"
157+
funcids[0xB5] = "FUNC_ID_ZW_IS_WUT_KICKED"
158+
funcids[0xB6] = "FUNC_ID_ZW_WATCHDOG_ENABLE"
159+
funcids[0xB7] = "FUNC_ID_ZW_WATCHDOG_DISABLE"
160+
funcids[0xB8] = "FUNC_ID_ZW_WATCHDOG_KICK"
161+
funcids[0xB9] = "FUNC_ID_ZW_SET_EXT_INT_LEVEL"
162+
funcids[0xB9] = "FUNC_ID_ZW_INT_EXT_LEVEL_SET"
163+
funcids[0xBA] = "FUNC_ID_ZW_RF_POWER_LEVEL_GET"
164+
funcids[0xBB] = "FUNC_ID_ZW_GET_NEIGHBOR_COUNT"
165+
funcids[0xBC] = "FUNC_ID_ZW_ARE_NODES_NEIGHBOURS"
166+
funcids[0xBD] = "FUNC_ID_ZW_TYPE_LIBRARY"
167+
funcids[0xBE] = "FUNC_ID_ZW_SEND_TEST_FRAME"
168+
funcids[0xBF] = "FUNC_ID_ZW_GET_PROTOCOL_STATUS"
169+
funcids[0xD0] = "FUNC_ID_ZW_SET_PROMISCUOUS_MODE"
170+
funcids[0xD1] = "FUNC_ID_PROMISCUOUS_APPLICATION_COMMAND_HANDLER"
171+
funcids[0xD2] = "FUNC_ID_ZW_WATCHDOG_START"
172+
funcids[0xD3] = "FUNC_ID_ZW_WATCHDOG_STOP"
173+
funcids[0xD4] = "FUNC_ID_ZW_SET_ROUTING_MAX"
174+
funcids[0xD5] = "FUNC_ID_ZW_GET_ROUTING_MAX"
175+
funcids[0xE0] = "FUNC_ID_ZW_NUNIT_CMD"
176+
funcids[0xE1] = "FUNC_ID_ZW_NUNIT_INIT"
177+
funcids[0xE2] = "FUNC_ID_ZW_NUNIT_LIST"
178+
funcids[0xE3] = "FUNC_ID_ZW_NUNIT_RUN"
179+
funcids[0xE4] = "FUNC_ID_ZW_NUNIT_END"
180+
funcids[0xE5] = "FUNC_ID_IO_PORT_STATUS"
181+
funcids[0xE6] = "FUNC_ID_IO_PORT"
182+
funcids[0xEE] = "FUNC_ID_SERIAL_API_POWER_MANAGEMENT"
183+
funcids[0xEF] = "FUNC_ID_SERIAL_API_READY"
184+
funcids[0xF0] = "FUNC_ID_PROPRIETARY_0"
185+
funcids[0xF1] = "FUNC_ID_PROPRIETARY_1"
186+
funcids[0xF2] = "FUNC_ID_PROPRIETARY_2"
187+
funcids[0xF3] = "FUNC_ID_PROPRIETARY_3"
188+
funcids[0xF4] = "FUNC_ID_PROPRIETARY_4"
189+
funcids[0xF5] = "FUNC_ID_PROPRIETARY_5"
190+
funcids[0xF6] = "FUNC_ID_PROPRIETARY_6"
191+
funcids[0xF7] = "FUNC_ID_PROPRIETARY_7"
192+
funcids[0xF8] = "FUNC_ID_PROPRIETARY_8"
193+
funcids[0xF9] = "FUNC_ID_PROPRIETARY_9"
194+
funcids[0xFA] = "FUNC_ID_PROPRIETARY_A"
195+
funcids[0xFB] = "FUNC_ID_PROPRIETARY_B"
196+
funcids[0xFC] = "FUNC_ID_PROPRIETARY_C"
197+
funcids[0xFD] = "FUNC_ID_PROPRIETARY_D"
198+
funcids[0xFE] = "FUNC_ID_PROPRIETARY_E"
199+
funcids[0xFF] = "FUNC_ID_UNKNOWN"
200+
201+
def frame_tostring(frame):
202+
if len(frame) < 2:
203+
return "EEE"
204+
try:
205+
req = int(frame[0],16)
206+
fid = int(frame[1],16)
207+
except ValueError:
208+
return ""
209+
210+
if req==0x00:
211+
s="\033[34;1m REQ "
212+
else:
213+
s="\033[33;1m RES "
214+
215+
try:
216+
return s + funcids[fid]+"("+hex(fid)+") "+ str(frame[2:-1]) + "\033[0m"
217+
except KeyError:
218+
return s + "Unknown(%2.2x) " % fid + str(frame[2:-1]) + "\033[0m"
219+
220+
221+
def perror(*args, **kwargs):
222+
print('Error: ', *args, file=sys.stderr, **kwargs)
223+
224+
225+
if __name__ == '__main__':
226+
POS_FRAME_START = 1
227+
MIN_FRAME_LEN = 2
228+
229+
term_columns = shutil.get_terminal_size((80, 20)).columns
230+
231+
if len(sys.argv) < 2:
232+
print("Usage:")
233+
print("{} <path-to-serial-log-file>".format(sys.argv[0]))
234+
sys.exit()
235+
236+
try:
237+
f = open(sys.argv[1], "r")
238+
except OSError:
239+
perror("Could not open file:", sys.argv[1])
240+
sys.exit()
241+
242+
t0 = 0
243+
n=0
244+
try:
245+
lines = f.readlines()
246+
except OSError:
247+
print("Could not read file:", sys.argv[1])
248+
sys.exit()
249+
250+
for line in lines:
251+
print('-' * term_columns)
252+
253+
t = line.split(' ')
254+
255+
if "Start of new log" in line:
256+
continue
257+
258+
if len(t) < MIN_FRAME_LEN:
259+
perror(line)
260+
continue
261+
262+
print(line.strip())
263+
264+
n=n+1
265+
try:
266+
# hdr = "%4.4i %s %s " % (n,t[0],t[1])
267+
hdr = "%4.4i %s " % (n, t[0])
268+
except ValueError:
269+
sys.exit()
270+
271+
if t[1] == "W":
272+
hdr+= " TX--> "
273+
if t[1] == "R":
274+
hdr+= " RX<-- "
275+
276+
p=2
277+
while p< len(t)-1:
278+
try:
279+
cmd = int(t[p],16)
280+
except ValueError:
281+
cmd = 0xff
282+
283+
if cmd == ACK:
284+
print (hdr + "ACK")
285+
p = p +1
286+
elif cmd == CAN:
287+
print (hdr + "CAN")
288+
p = p +1
289+
elif cmd == NAK:
290+
print (hdr + "NAK")
291+
p = p +1
292+
elif cmd == SOF:
293+
try:
294+
framelen= int(t[p+1],16)
295+
except ValueError:
296+
break
297+
print (hdr + frame_tostring(t[p+2:p+2+framelen]))
298+
p = p + framelen + 2
299+
else:
300+
print ("BAD Token %x" % cmd)
301+
p = p +1
302+
f.close()
303+
304+
# ts=4:sts=4

0 commit comments

Comments
 (0)