/src/wireshark/epan/dissectors/packet-canopen.c
Line | Count | Source |
1 | | /* packet-canopen.c |
2 | | * Routines for CANopen dissection |
3 | | * Copyright 2011, Yegor Yefremov <yegorslists@googlemail.com> |
4 | | * |
5 | | * Wireshark - Network traffic analyzer |
6 | | * By Gerald Combs <gerald@wireshark.org> |
7 | | * Copyright 1998 Gerald Combs |
8 | | * |
9 | | * SPDX-License-Identifier: GPL-2.0-or-later |
10 | | */ |
11 | | |
12 | | #include "config.h" |
13 | | |
14 | | #include <epan/packet.h> |
15 | | |
16 | | #include "packet-socketcan.h" |
17 | | |
18 | | void proto_register_canopen(void); |
19 | | void proto_reg_handoff_canopen(void); |
20 | | |
21 | | static dissector_handle_t canopen_handle; |
22 | | |
23 | | /* Initialize the protocol and registered fields */ |
24 | | static int proto_canopen; |
25 | | static int hf_canopen_cob_id; |
26 | | static int hf_canopen_function_code; |
27 | | static int hf_canopen_node_id; |
28 | | static int hf_canopen_pdo_data; |
29 | | static int hf_canopen_pdo_data_string; |
30 | | static int hf_canopen_sdo_cmd; |
31 | | static int hf_canopen_sdo_cmd_ccs; |
32 | | static int hf_canopen_sdo_cmd_scs; |
33 | | static int hf_canopen_sdo_cmd_ccs5_subcommand; |
34 | | static int hf_canopen_sdo_cmd_scs5_subcommand; |
35 | | static int hf_canopen_sdo_cmd_ccs6_subcommand; |
36 | | static int hf_canopen_sdo_cmd_scs6_subcommand; |
37 | | static int hf_canopen_sdo_cmd_block_crc_support; |
38 | | static int hf_canopen_sdo_cmd_block_s; |
39 | | static int hf_canopen_sdo_cmd_block_n; |
40 | | static int hf_canopen_sdo_cmd_block_blksize; |
41 | | static int hf_canopen_sdo_cmd_block_pst; |
42 | | static int hf_canopen_sdo_cmd_block_ackseq; |
43 | | static int hf_canopen_sdo_cmd_toggle; |
44 | | static int hf_canopen_sdo_cmd_updown_n; |
45 | | static int hf_canopen_sdo_cmd_updown_c; |
46 | | static int hf_canopen_sdo_cmd_init_n; |
47 | | static int hf_canopen_sdo_cmd_init_e; |
48 | | static int hf_canopen_sdo_cmd_init_s; |
49 | | static int hf_canopen_sdo_main_idx; |
50 | | static int hf_canopen_sdo_sub_idx; |
51 | | static int hf_canopen_sdo_data; |
52 | | static int hf_canopen_sdo_abort_code; |
53 | | static int hf_canopen_reserved; |
54 | | static int hf_canopen_em_err_code; |
55 | | static int hf_canopen_em_err_reg; |
56 | | static int hf_canopen_em_err_reg_ge; |
57 | | static int hf_canopen_em_err_reg_cu; |
58 | | static int hf_canopen_em_err_reg_vo; |
59 | | static int hf_canopen_em_err_reg_te; |
60 | | static int hf_canopen_em_err_reg_co; |
61 | | static int hf_canopen_em_err_reg_de; |
62 | | static int hf_canopen_em_err_reg_re; |
63 | | static int hf_canopen_em_err_reg_ma; |
64 | | static int hf_canopen_em_err_field; |
65 | | static int hf_canopen_nmt_ctrl_cs; |
66 | | static int hf_canopen_nmt_ctrl_node_id; |
67 | | static int hf_canopen_nmt_guard_state; |
68 | | static int hf_canopen_nmt_guard_toggle; |
69 | | static int hf_canopen_sync_counter; |
70 | | static int hf_canopen_lss_cs; |
71 | | static int hf_canopen_lss_addr_vendor; |
72 | | static int hf_canopen_lss_addr_product; |
73 | | static int hf_canopen_lss_addr_revision; |
74 | | static int hf_canopen_lss_addr_revision_low; |
75 | | static int hf_canopen_lss_addr_revision_high; |
76 | | static int hf_canopen_lss_addr_serial; |
77 | | static int hf_canopen_lss_addr_serial_low; |
78 | | static int hf_canopen_lss_addr_serial_high; |
79 | | static int* hf_canopen_lss_addr_ident[] = { |
80 | | &hf_canopen_lss_addr_vendor, |
81 | | &hf_canopen_lss_addr_product, |
82 | | &hf_canopen_lss_addr_revision_low, |
83 | | &hf_canopen_lss_addr_revision_high, |
84 | | &hf_canopen_lss_addr_serial_low, |
85 | | &hf_canopen_lss_addr_serial_high |
86 | | }; |
87 | | static int* hf_canopen_lss_addr_inquire[] = { |
88 | | &hf_canopen_lss_addr_vendor, |
89 | | &hf_canopen_lss_addr_product, |
90 | | &hf_canopen_lss_addr_revision, |
91 | | &hf_canopen_lss_addr_serial |
92 | | }; |
93 | | static int hf_canopen_lss_fastscan_id; |
94 | | static int hf_canopen_lss_fastscan_check; |
95 | | static int hf_canopen_lss_fastscan_sub; |
96 | | static int hf_canopen_lss_fastscan_next; |
97 | | static int hf_canopen_lss_switch_mode; |
98 | | static int hf_canopen_lss_nid; |
99 | | static int hf_canopen_lss_conf_id_err_code; |
100 | | static int hf_canopen_lss_conf_bt_err_code; |
101 | | static int hf_canopen_lss_store_conf_err_code; |
102 | | static int hf_canopen_lss_spec_err; |
103 | | static int hf_canopen_lss_bt_tbl_selector; |
104 | | static int hf_canopen_lss_bt_tbl_index; |
105 | | static int hf_canopen_lss_abt_delay; |
106 | | static int hf_canopen_time_stamp; |
107 | | static int hf_canopen_time_stamp_ms; |
108 | | static int hf_canopen_time_stamp_days; |
109 | | |
110 | | |
111 | | /* Download segment request (ccs=0) decode mask */ |
112 | | static int * const sdo_cmd_fields_ccs0[] = { |
113 | | &hf_canopen_sdo_cmd_ccs, |
114 | | &hf_canopen_sdo_cmd_toggle, |
115 | | &hf_canopen_sdo_cmd_updown_n, |
116 | | &hf_canopen_sdo_cmd_updown_c, |
117 | | NULL |
118 | | }; |
119 | | /* Initiate download request (ccs=1) decode mask */ |
120 | | static int * const sdo_cmd_fields_ccs1[] = { |
121 | | &hf_canopen_sdo_cmd_ccs, |
122 | | &hf_canopen_sdo_cmd_init_n, |
123 | | &hf_canopen_sdo_cmd_init_e, |
124 | | &hf_canopen_sdo_cmd_init_s, |
125 | | NULL |
126 | | }; |
127 | | /* Initiate upload request (ccs=2) decode mask */ |
128 | | static int * const sdo_cmd_fields_ccs2[] = { |
129 | | &hf_canopen_sdo_cmd_ccs, |
130 | | NULL |
131 | | }; |
132 | | /* Download segment request (ccs=3) decode mask */ |
133 | | static int * const sdo_cmd_fields_ccs3[] = { |
134 | | &hf_canopen_sdo_cmd_ccs, |
135 | | &hf_canopen_sdo_cmd_toggle, |
136 | | NULL |
137 | | }; |
138 | | /* */ |
139 | | static int * const sdo_cmd_fields_ccs4[] = { |
140 | | &hf_canopen_sdo_cmd_ccs, |
141 | | NULL |
142 | | }; |
143 | | /* Block upload (ccs=5,cs=0) decode mask */ |
144 | | static int * const sdo_cmd_fields_ccs5_subcommand0[] = { |
145 | | &hf_canopen_sdo_cmd_ccs, |
146 | | &hf_canopen_sdo_cmd_block_crc_support, |
147 | | &hf_canopen_sdo_cmd_ccs5_subcommand, |
148 | | NULL |
149 | | }; |
150 | | /* Block upload (ccs=5,cs=1,2,3) decode mask */ |
151 | | static int * const sdo_cmd_fields_ccs5_subcommand1[] = { |
152 | | &hf_canopen_sdo_cmd_ccs, |
153 | | &hf_canopen_sdo_cmd_ccs5_subcommand, |
154 | | NULL |
155 | | }; |
156 | | |
157 | | /* Block download (ccs=6,cs=0) decode mask */ |
158 | | static int * const sdo_cmd_fields_ccs6_subcommand0[] = { |
159 | | &hf_canopen_sdo_cmd_ccs, |
160 | | &hf_canopen_sdo_cmd_block_crc_support, |
161 | | &hf_canopen_sdo_cmd_block_s, |
162 | | &hf_canopen_sdo_cmd_ccs6_subcommand, |
163 | | NULL |
164 | | }; |
165 | | /* Block download (ccs=6,cs=1) decode mask */ |
166 | | static int * const sdo_cmd_fields_ccs6_subcommand1[] = { |
167 | | &hf_canopen_sdo_cmd_ccs, |
168 | | &hf_canopen_sdo_cmd_block_n, |
169 | | &hf_canopen_sdo_cmd_ccs6_subcommand, |
170 | | NULL |
171 | | }; |
172 | | |
173 | | static int * const *_sdo_cmd_fields_ccs[] = { |
174 | | sdo_cmd_fields_ccs0, |
175 | | sdo_cmd_fields_ccs1, |
176 | | sdo_cmd_fields_ccs2, |
177 | | sdo_cmd_fields_ccs3, |
178 | | sdo_cmd_fields_ccs4, |
179 | | }; |
180 | | |
181 | | static int * const *_sdo_cmd_fields_ccs5[] = { |
182 | | sdo_cmd_fields_ccs5_subcommand0, |
183 | | sdo_cmd_fields_ccs5_subcommand1, |
184 | | sdo_cmd_fields_ccs5_subcommand1, |
185 | | sdo_cmd_fields_ccs5_subcommand1 |
186 | | }; |
187 | | |
188 | | static int * const *_sdo_cmd_fields_ccs6[] = { |
189 | | sdo_cmd_fields_ccs6_subcommand0, |
190 | | sdo_cmd_fields_ccs6_subcommand1 |
191 | | }; |
192 | | |
193 | | /* Emergency error register decode mask */ |
194 | | static int * const em_err_reg_fields[] = { |
195 | | &hf_canopen_em_err_reg_ge, |
196 | | &hf_canopen_em_err_reg_cu, |
197 | | &hf_canopen_em_err_reg_vo, |
198 | | &hf_canopen_em_err_reg_te, |
199 | | &hf_canopen_em_err_reg_co, |
200 | | &hf_canopen_em_err_reg_de, |
201 | | &hf_canopen_em_err_reg_re, |
202 | | &hf_canopen_em_err_reg_ma, |
203 | | NULL |
204 | | }; |
205 | | |
206 | | /* (scs=0) decode mask */ |
207 | | static int * const sdo_cmd_fields_scs0[] = { |
208 | | &hf_canopen_sdo_cmd_scs, |
209 | | &hf_canopen_sdo_cmd_toggle, |
210 | | &hf_canopen_sdo_cmd_updown_n, |
211 | | &hf_canopen_sdo_cmd_updown_c, |
212 | | NULL |
213 | | }; |
214 | | /* (scs=1) decode mask */ |
215 | | static int * const sdo_cmd_fields_scs1[] = { |
216 | | &hf_canopen_sdo_cmd_scs, |
217 | | &hf_canopen_sdo_cmd_toggle, |
218 | | NULL |
219 | | }; |
220 | | /* (scs=2) decode mask */ |
221 | | static int * const sdo_cmd_fields_scs2[] = { |
222 | | &hf_canopen_sdo_cmd_scs, |
223 | | &hf_canopen_sdo_cmd_init_n, |
224 | | &hf_canopen_sdo_cmd_init_e, |
225 | | &hf_canopen_sdo_cmd_init_s, |
226 | | NULL |
227 | | }; |
228 | | /* (scs=3) decode mask */ |
229 | | static int * const sdo_cmd_fields_scs3[] = { |
230 | | &hf_canopen_sdo_cmd_scs, |
231 | | NULL |
232 | | }; |
233 | | /* (scs=4) decode mask */ |
234 | | static int * const sdo_cmd_fields_scs4[] = { |
235 | | &hf_canopen_sdo_cmd_scs, |
236 | | NULL |
237 | | }; |
238 | | /* (scs=5,ss=0) decode mask */ |
239 | | static int * const sdo_cmd_fields_scs5_subcommand0[] = { |
240 | | &hf_canopen_sdo_cmd_scs, |
241 | | &hf_canopen_sdo_cmd_block_crc_support, |
242 | | &hf_canopen_sdo_cmd_scs5_subcommand, |
243 | | NULL |
244 | | }; |
245 | | /* (scs=5,ss=1,2) decode mask */ |
246 | | static int * const sdo_cmd_fields_scs5_subcommand1[] = { |
247 | | &hf_canopen_sdo_cmd_scs, |
248 | | &hf_canopen_sdo_cmd_scs5_subcommand, |
249 | | NULL |
250 | | }; |
251 | | |
252 | | /* (scs=6,ss=0) decode mask */ |
253 | | static int * const sdo_cmd_fields_scs6_subcommand0[] = { |
254 | | &hf_canopen_sdo_cmd_scs, |
255 | | &hf_canopen_sdo_cmd_block_crc_support, |
256 | | &hf_canopen_sdo_cmd_block_s, |
257 | | &hf_canopen_sdo_cmd_scs6_subcommand, |
258 | | NULL |
259 | | }; |
260 | | /* (scs=6,ss=1) decode mask */ |
261 | | static int * const sdo_cmd_fields_scs6_subcommand1[] = { |
262 | | &hf_canopen_sdo_cmd_scs, |
263 | | &hf_canopen_sdo_cmd_block_n, |
264 | | &hf_canopen_sdo_cmd_scs6_subcommand, |
265 | | NULL |
266 | | }; |
267 | | |
268 | | |
269 | | static int * const *_sdo_cmd_fields_scs[] = { |
270 | | sdo_cmd_fields_scs0, |
271 | | sdo_cmd_fields_scs1, |
272 | | sdo_cmd_fields_scs2, |
273 | | sdo_cmd_fields_scs3, |
274 | | sdo_cmd_fields_scs4 |
275 | | }; |
276 | | |
277 | | static int * const *_sdo_cmd_fields_scs5[] = { |
278 | | sdo_cmd_fields_scs5_subcommand0, |
279 | | sdo_cmd_fields_scs5_subcommand1, |
280 | | sdo_cmd_fields_scs5_subcommand1, |
281 | | }; |
282 | | |
283 | | static int * const *_sdo_cmd_fields_scs6[] = { |
284 | | sdo_cmd_fields_scs6_subcommand0, |
285 | | sdo_cmd_fields_scs6_subcommand1 |
286 | | }; |
287 | | |
288 | | /* Initialize the subtree pointers */ |
289 | | static int ett_canopen; |
290 | | static int ett_canopen_cob; |
291 | | static int ett_canopen_type; |
292 | | static int ett_canopen_sdo_cmd; |
293 | | static int ett_canopen_em_er; |
294 | | |
295 | | /* broadcast messages */ |
296 | 0 | #define FC_NMT 0x0 |
297 | 0 | #define FC_SYNC 0x1 |
298 | 0 | #define FC_TIME_STAMP 0x2 |
299 | | |
300 | | /* point-to-point messages */ |
301 | | #define FC_EMERGENCY 0x1 |
302 | 0 | #define FC_PDO1_TX 0x3 |
303 | 0 | #define FC_PDO1_RX 0x4 |
304 | 0 | #define FC_PDO2_TX 0x5 |
305 | 0 | #define FC_PDO2_RX 0x6 |
306 | 0 | #define FC_PDO3_TX 0x7 |
307 | 0 | #define FC_PDO3_RX 0x8 |
308 | 0 | #define FC_PDO4_TX 0x9 |
309 | 0 | #define FC_PDO4_RX 0xA |
310 | 0 | #define FC_DEFAULT_SDO_TX 0xB |
311 | 0 | #define FC_DEFAULT_SDO_RX 0xC |
312 | 0 | #define FC_NMT_ERR_CONTROL 0xE |
313 | | |
314 | | static const value_string CAN_open_bcast_msg_type_vals[] = { |
315 | | { FC_NMT, "NMT"}, |
316 | | { FC_SYNC, "SYNC"}, |
317 | | { FC_TIME_STAMP, "TIME STAMP"}, |
318 | | { 0, NULL} |
319 | | }; |
320 | | |
321 | | static const value_string CAN_open_p2p_msg_type_vals[] = { |
322 | | { FC_EMERGENCY, "EMCY"}, |
323 | | { FC_PDO1_TX, "PDO1 (tx)"}, |
324 | | { FC_PDO1_RX, "PDO1 (rx)"}, |
325 | | { FC_PDO2_TX, "PDO2 (tx)"}, |
326 | | { FC_PDO2_RX, "PDO2 (rx)"}, |
327 | | { FC_PDO3_TX, "PDO3 (tx)"}, |
328 | | { FC_PDO3_RX, "PDO3 (rx)"}, |
329 | | { FC_PDO4_TX, "PDO4 (tx)"}, |
330 | | { FC_PDO4_RX, "PDO4 (rx)"}, |
331 | | { FC_DEFAULT_SDO_TX, "Default-SDO (tx)"}, |
332 | | { FC_DEFAULT_SDO_RX, "Default-SDO (rx)"}, |
333 | | { FC_NMT_ERR_CONTROL, "NMT Error Control"}, |
334 | | { 0, NULL} |
335 | | }; |
336 | | |
337 | | /* message types */ |
338 | 0 | #define MT_UNKNOWN 0 |
339 | 0 | #define MT_NMT_CTRL 1 |
340 | 0 | #define MT_SYNC 2 |
341 | 0 | #define MT_TIME_STAMP 3 |
342 | 0 | #define MT_EMERGENCY 4 |
343 | 0 | #define MT_PDO 5 |
344 | 0 | #define MT_SDO 6 |
345 | 0 | #define MT_NMT_ERR_CTRL 7 |
346 | 0 | #define MT_LSS_MASTER 10 |
347 | 0 | #define MT_LSS_SLAVE 11 |
348 | | |
349 | | /* TIME STAMP conversion defines */ |
350 | 0 | #define TS_DAYS_BETWEEN_1970_AND_1984 5113 |
351 | 0 | #define TS_SECONDS_IN_PER_DAY 86400 |
352 | 0 | #define TS_NANOSEC_PER_MSEC 1000000 |
353 | | |
354 | | /* SDO command specifier */ |
355 | 0 | #define SDO_CCS_DOWN_SEG_REQ 0 |
356 | 0 | #define SDO_CCS_INIT_DOWN_REQ 1 |
357 | 0 | #define SDO_CCS_INIT_UP_REQ 2 |
358 | 0 | #define SDO_CCS_UP_SEQ_REQ 3 |
359 | 0 | #define SDO_CCS_BLOCK_UP 5 |
360 | 0 | #define SDO_CCS_BLOCK_DOWN 6 |
361 | | |
362 | 0 | #define SDO_SCS_UP_SEQ_RESP 0 |
363 | 0 | #define SDO_SCS_DOWN_SEG_RESP 1 |
364 | 0 | #define SDO_SCS_INIT_UP_RESP 2 |
365 | 0 | #define SDO_SCS_INIT_DOWN_RESP 3 |
366 | 0 | #define SDO_SCS_BLOCK_DOWN 5 |
367 | 0 | #define SDO_SCS_BLOCK_UP 6 |
368 | | |
369 | 0 | #define SDO_CS_ABORT_TRANSFER 4 |
370 | | |
371 | | static const range_string obj_dict[] = { |
372 | | { 0x0000, 0x0000, "not used"}, |
373 | | { 0x0001, 0x001F, "Static data types"}, |
374 | | { 0x0020, 0x003F, "Complex data types"}, |
375 | | { 0x0040, 0x005F, "Manufacturer-specific complex data types"}, |
376 | | { 0x0060, 0x025F, "Device profile specific data types"}, |
377 | | { 0x0260, 0x03FF, "reserved"}, |
378 | | { 0x0400, 0x0FFF, "reserved"}, |
379 | | { 0x1000, 0x1000, "Device type"}, |
380 | | { 0x1001, 0x1001, "Error register"}, |
381 | | { 0x1002, 0x1002, "Manufacturer status register"}, |
382 | | { 0x1003, 0x1003, "Pre-defined error field"}, |
383 | | { 0x1004, 0x1004, "Communication profile area"}, |
384 | | { 0x1005, 0x1005, "COB-ID SYNC message"}, |
385 | | { 0x1006, 0x1006, "Communication cycle period"}, |
386 | | { 0x1007, 0x1007, "Synchronous window length"}, |
387 | | { 0x1008, 0x1008, "Manufacturer device name"}, |
388 | | { 0x1009, 0x1009, "Manufacturer hardware version"}, |
389 | | { 0x100A, 0x100A, "Manufacturer software version"}, |
390 | | { 0x100B, 0x100B, "Communication profile area"}, |
391 | | { 0x100C, 0x100C, "Guard time"}, |
392 | | { 0x100D, 0x100D, "Life time factor"}, |
393 | | { 0x100E, 0x100F, "Communication profile area"}, |
394 | | { 0x1010, 0x1010, "Store parameters"}, |
395 | | { 0x1011, 0x1011, "Restore default parameters"}, |
396 | | { 0x1012, 0x1012, "COB-ID time stamp object"}, |
397 | | { 0x1013, 0x1013, "High resolution time stamp"}, |
398 | | { 0x1014, 0x1014, "COB-ID EMCY"}, |
399 | | { 0x1015, 0x1015, "Inhibit time EMCY"}, |
400 | | { 0x1016, 0x1016, "Consumer heartbeat time"}, |
401 | | { 0x1017, 0x1017, "Producer heartbeat time"}, |
402 | | { 0x1018, 0x1018, "Identity object"}, |
403 | | { 0x1019, 0x1019, "Synchronous counter overflow value"}, |
404 | | { 0x101A, 0x101F, "Communication profile area"}, |
405 | | { 0x1020, 0x1020, "Verify configuration"}, |
406 | | { 0x1021, 0x1021, "Store EDS"}, |
407 | | { 0x1022, 0x1022, "Store format"}, |
408 | | { 0x1023, 0x1023, "OS command"}, |
409 | | { 0x1024, 0x1024, "OS command mode"}, |
410 | | { 0x1025, 0x1025, "OS debugger interface"}, |
411 | | { 0x1026, 0x1026, "OS prompt"}, |
412 | | { 0x1027, 0x1027, "Module list"}, |
413 | | { 0x1028, 0x1028, "Emergency consumer object"}, |
414 | | { 0x1029, 0x1029, "Error behavior object"}, |
415 | | { 0x102A, 0x11FF, "Communication profile area"}, |
416 | | { 0x1200, 0x127F, "SDO server parameter"}, |
417 | | { 0x1280, 0x12FF, "SDO client parameter"}, |
418 | | { 0x1300, 0x13FF, "Communication profile area"}, |
419 | | { 0x1400, 0x15FF, "RPDO communication parameter"}, |
420 | | { 0x1600, 0x17FF, "RPDO mapping parameter"}, |
421 | | { 0x1800, 0x19FF, "TPDO communication parameter"}, |
422 | | { 0x1A00, 0x1BFF, "TPDO mapping parameter"}, |
423 | | { 0x1C00, 0x1FBF, "Communication profile area"}, |
424 | | { 0x1FA0, 0x1FCF, "Object scanner list"}, |
425 | | { 0x1FD0, 0x1FFF, "Object dispatching list"}, |
426 | | { 0x2000, 0x5FFF, "Manufacturer-specific profile area"}, |
427 | | { 0x6000, 0x67FF, "Standardized profile area 1st logical device"}, |
428 | | { 0x6800, 0x6FFF, "Standardized profile area 2nd logical device"}, |
429 | | { 0x7000, 0x77FF, "Standardized profile area 3rd logical device"}, |
430 | | { 0x7800, 0x7FFF, "Standardized profile area 4th logical device"}, |
431 | | { 0x8000, 0x87FF, "Standardized profile area 5th logical device"}, |
432 | | { 0x8800, 0x8FFF, "Standardized profile area 6th logical device"}, |
433 | | { 0x9000, 0x97FF, "Standardized profile area 7th logical device"}, |
434 | | { 0x9800, 0x9FFF, "Standardized profile area 8th logical device"}, |
435 | | { 0xA000, 0xAFFF, "Standardized network variable area"}, |
436 | | { 0xB000, 0xBFFF, "Standardized system variable area"}, |
437 | | { 0xC000, 0xFFFF, "reserved"}, |
438 | | { 0, 0, NULL} |
439 | | }; |
440 | | |
441 | | /* EMCY error codes */ |
442 | | static const range_string em_err_code[] = { |
443 | | { 0x0000, 0x00FF, "Error reset or no error"}, |
444 | | { 0x1000, 0x10FF, "Generic error"}, |
445 | | { 0x2000, 0x20FF, "Current"}, |
446 | | { 0x2100, 0x21FF, "Current, CANopen device input side"}, |
447 | | { 0x2200, 0x22FF, "Current inside the CANopen device"}, |
448 | | { 0x2300, 0x23FF, "Current, CANopen device output side"}, |
449 | | { 0x3000, 0x30FF, "Voltage"}, |
450 | | { 0x3100, 0x31FF, "Mains voltage"}, |
451 | | { 0x3200, 0x32FF, "Voltage inside the CANopen device"}, |
452 | | { 0x3300, 0x33FF, "Output voltage"}, |
453 | | { 0x4000, 0x40FF, "Temperature"}, |
454 | | { 0x4100, 0x41FF, "Ambient temperature"}, |
455 | | { 0x4200, 0x42FF, "CANopen device temperature"}, |
456 | | { 0x5000, 0x50FF, "CANopen device hardware"}, |
457 | | { 0x6000, 0x60FF, "CANopen device software"}, |
458 | | { 0x6100, 0x61FF, "Internal software"}, |
459 | | { 0x6200, 0x62FF, "User software"}, |
460 | | { 0x6300, 0x63FF, "Data set"}, |
461 | | { 0x7000, 0x70FF, "Additional modules"}, |
462 | | { 0x8000, 0x80FF, "Monitoring"}, |
463 | | { 0x8100, 0x810F, "Communication"}, |
464 | | { 0x8110, 0x8110, "Communication - CAN overrun (objects lost)"}, |
465 | | { 0x8111, 0x811F, "Communication"}, |
466 | | { 0x8120, 0x8120, "Communication - CAN in error passive mode"}, |
467 | | { 0x8121, 0x812F, "Communication"}, |
468 | | { 0x8130, 0x8130, "Communication - Life guard error or heartbeat error"}, |
469 | | { 0x8131, 0x813F, "Communication"}, |
470 | | { 0x8140, 0x8140, "Communication - recovered from bus off"}, |
471 | | { 0x8141, 0x814F, "Communication"}, |
472 | | { 0x8150, 0x8150, "Communication - CAN-ID collision"}, |
473 | | { 0x8151, 0x81FF, "Communication"}, |
474 | | { 0x8200, 0x820F, "Protocol error"}, |
475 | | { 0x8210, 0x8210, "Protocol error - PDO not processed due to length error"}, |
476 | | { 0x8211, 0x821F, "Protocol error"}, |
477 | | { 0x8220, 0x8220, "Protocol error - PDO length exceeded"}, |
478 | | { 0x8221, 0x822F, "Protocol error"}, |
479 | | { 0x8230, 0x8230, "Protocol error - DAM MPDO not processed, destination object not available"}, |
480 | | { 0x8231, 0x823F, "Protocol error"}, |
481 | | { 0x8240, 0x8240, "Protocol error - Unexpected SYNC data length"}, |
482 | | { 0x8241, 0x824F, "Protocol error"}, |
483 | | { 0x8250, 0x8250, "Protocol error - RPDO timeout"}, |
484 | | { 0x8251, 0x82FF, "Protocol error"}, |
485 | | { 0x9000, 0x90FF, "External error"}, |
486 | | { 0xF000, 0xF0FF, "Additional functions"}, |
487 | | { 0xFF00, 0xFFFF, "CANopen device specific"}, |
488 | | { 0, 0, NULL} |
489 | | }; |
490 | | |
491 | | /* NMT command specifiers */ |
492 | | static const value_string nmt_ctrl_cs[] = { |
493 | | { 0x01, "Start remote node"}, |
494 | | { 0x02, "Stop remote node"}, |
495 | | { 0x80, "Enter pre-operational state"}, |
496 | | { 0x81, "Reset node"}, |
497 | | { 0x82, "Reset communication"}, |
498 | | { 0, NULL} |
499 | | }; |
500 | | |
501 | | /* NMT states */ |
502 | | static const value_string nmt_guard_state[] = { |
503 | | { 0x00, "Boot-up"}, |
504 | | { 0x04, "Stopped"}, |
505 | | { 0x05, "Operational"}, |
506 | | { 0x7F, "Pre-operational"}, |
507 | | { 0, NULL} |
508 | | }; |
509 | | |
510 | | /* SDO Client command specifier */ |
511 | | static const value_string sdo_ccs[] = { |
512 | | { 0x00, "Download segment request"}, |
513 | | { 0x01, "Initiate download request"}, |
514 | | { 0x02, "Initiate upload request"}, |
515 | | { 0x03, "Upload segment request"}, |
516 | | { 0x04, "Abort transfer"}, |
517 | | { 0x05, "Block upload"}, |
518 | | { 0x06, "Block download"}, |
519 | | { 0, NULL} |
520 | | }; |
521 | | |
522 | | /* SDO Server command specifier */ |
523 | | static const value_string sdo_scs[] = { |
524 | | { 0x00, "Upload segment response"}, |
525 | | { 0x01, "Download segment response"}, |
526 | | { 0x02, "Initiate upload response"}, |
527 | | { 0x03, "Initiate download response"}, |
528 | | { 0x04, "Abort transfer"}, |
529 | | { 0x05, "Block download"}, |
530 | | { 0x06, "Block upload"}, |
531 | | { 0, NULL} |
532 | | }; |
533 | | |
534 | | /* SDO client subcommand meaning */ |
535 | | static const value_string sdo_client_subcommand_meaning[] = { |
536 | | { 0x00, "Initiate upload/download request"}, |
537 | | { 0x01, "End block upload/download request"}, |
538 | | { 0x02, "Block upload response"}, |
539 | | { 0x03, "Start upload"}, |
540 | | { 0, NULL} |
541 | | }; |
542 | | |
543 | | /* SDO server subcommand meaning */ |
544 | | static const value_string sdo_server_subcommand_meaning[] = { |
545 | | { 0x00, "Initiate upload/download response"}, |
546 | | { 0x01, "End block upload/download response"}, |
547 | | { 0x02, "Block download response"}, |
548 | | { 0, NULL} |
549 | | }; |
550 | | |
551 | | static const value_string sdo_abort_code[] = { |
552 | | { 0x05030000, "Toggle bit not alternated"}, |
553 | | { 0x05040000, "SDO protocol timed out"}, |
554 | | { 0x05040001, "Client/server command specifier not valid or unknown"}, |
555 | | { 0x05040002, "Invalid block size"}, |
556 | | { 0x05040003, "Invalid sequence number"}, |
557 | | { 0x05040004, "CRC error"}, |
558 | | { 0x05040005, "Out of memory"}, |
559 | | { 0x06010000, "Unsupported access to an object"}, |
560 | | { 0x06010001, "Attempt to read a write only object"}, |
561 | | { 0x06010002, "Attempt to write a read only object"}, |
562 | | { 0x06020000, "Object does not exist in the object dictionary"}, |
563 | | { 0x06040041, "Object cannot be mapped to the PDO"}, |
564 | | { 0x06040042, "The number and length of the objects to be mapped would exceed PDO length"}, |
565 | | { 0x06040043, "General parameter incompatibility reason"}, |
566 | | { 0x06040047, "General internal incompatibility in the device"}, |
567 | | { 0x06060000, "Access failed due to an hardware error"}, |
568 | | { 0x06070010, "Data type does not match, length of service parameter does not match"}, |
569 | | { 0x06070012, "Data type does not match, length of service parameter too high"}, |
570 | | { 0x06070013, "Data type does not match, length of service parameter too low"}, |
571 | | { 0x06090011, "Sub-index does not exist"}, |
572 | | { 0x06090030, "Invalid value for parameter"}, |
573 | | { 0x06090031, "Value of parameter written too high"}, |
574 | | { 0x06090032, "Value of parameter written too low"}, |
575 | | { 0x06090036, "Maximum value is less than minimum value"}, |
576 | | { 0x060A0023, "Resource not available: SDO connection"}, |
577 | | { 0x08000000, "General error"}, |
578 | | { 0x08000020, "Data cannot be transferred or stored to the application"}, |
579 | | { 0x08000021, "Data cannot be transferred or stored to the application because of local control"}, |
580 | | { 0x08000022, "Data cannot be transferred or stored to the application because of the present device state"}, |
581 | | { 0x08000023, "Object dictionary dynamic generation fails or no object dictionary is present"}, |
582 | | { 0x08000024, "No data available"}, |
583 | | { 0, NULL} |
584 | | }; |
585 | | |
586 | | /* LSS COB-IDs */ |
587 | 0 | #define LSS_MASTER_CAN_ID 0x7E5 |
588 | 0 | #define LSS_SLAVE_CAN_ID 0x7E4 |
589 | | |
590 | | /* LSS Switch state services */ |
591 | 0 | #define LSS_CS_SWITCH_GLOBAL 0x04 |
592 | 0 | #define LSS_CS_SWITCH_SELECTIVE_VENDOR 0x40 |
593 | 0 | #define LSS_CS_SWITCH_SELECTIVE_PRODUCT 0x41 |
594 | 0 | #define LSS_CS_SWITCH_SELECTIVE_REVISION 0x42 |
595 | 0 | #define LSS_CS_SWITCH_SELECTIVE_SERIAL 0x43 |
596 | 0 | #define LSS_CS_SWITCH_SELECTIVE_RESP 0x44 |
597 | | /* LSS Configuration services */ |
598 | 0 | #define LSS_CS_CONF_NODE_ID 0x11 |
599 | 0 | #define LSS_CS_CONF_BIT_TIMING 0x13 |
600 | 0 | #define LSS_CS_CONF_ACT_BIT_TIMING 0x15 |
601 | 0 | #define LSS_CS_CONF_STORE 0x17 |
602 | | /* LSS Inquire services */ |
603 | 0 | #define LSS_CS_INQ_VENDOR_ID 0x5A |
604 | 0 | #define LSS_CS_INQ_PRODUCT_CODE 0x5B |
605 | 0 | #define LSS_CS_INQ_REV_NUMBER 0x5C |
606 | 0 | #define LSS_CS_INQ_SERIAL_NUMBER 0x5D |
607 | 0 | #define LSS_CS_INQ_NODE_ID 0x5E |
608 | | /* LSS Identification services */ |
609 | 0 | #define LSS_CS_IDENT_REMOTE_VENDOR 0x46 |
610 | 0 | #define LSS_CS_IDENT_REMOTE_PRODUCT 0x47 |
611 | 0 | #define LSS_CS_IDENT_REMOTE_REV_LOW 0x48 |
612 | 0 | #define LSS_CS_IDENT_REMOTE_REV_HIGH 0x49 |
613 | 0 | #define LSS_CS_IDENT_REMOTE_SERIAL_LOW 0x4A |
614 | 0 | #define LSS_CS_IDENT_REMOTE_SERIAL_HIGH 0x4B |
615 | 0 | #define LSS_CS_IDENT_REMOTE_NON_CONF 0x4C |
616 | 0 | #define LSS_CS_IDENT_SLAVE 0x4F |
617 | 0 | #define LSS_CS_IDENT_NON_CONF_SLAVE 0x50 |
618 | 0 | #define LSS_CS_IDENT_FASTSCAN 0x51 |
619 | | |
620 | | |
621 | | /* LSS command specifier */ |
622 | | static const value_string lss_cs_code[] = { |
623 | | { 0x04, "Switch state global protocol"}, |
624 | | { 0x11, "Configure node-ID protocol"}, |
625 | | { 0x13, "Configure bit timing protocol"}, |
626 | | { 0x15, "Activate bit timing parameters protocol"}, |
627 | | { 0x17, "Store configuration protocol"}, |
628 | | { 0x40, "Switch state selective protocol"}, |
629 | | { 0x41, "Switch state selective protocol"}, |
630 | | { 0x42, "Switch state selective protocol"}, |
631 | | { 0x43, "Switch state selective protocol"}, |
632 | | { 0x44, "Switch state selective protocol"}, |
633 | | { 0x46, "Identify remote slave protocol"}, |
634 | | { 0x47, "Identify remote slave protocol"}, |
635 | | { 0x48, "Identify remote slave protocol"}, |
636 | | { 0x49, "Identify remote slave protocol"}, |
637 | | { 0x4A, "Identify remote slave protocol"}, |
638 | | { 0x4B, "Identify remote slave protocol"}, |
639 | | { 0x4C, "Identify non-configured remote slave protocol"}, |
640 | | { 0x4F, "Identify slave protocol"}, |
641 | | { 0x50, "Identify non-configured slave protocol"}, |
642 | | { 0x51, "LSS Fastscan protocol"}, |
643 | | { 0x5A, "Inquire identity vendor-ID protocol"}, |
644 | | { 0x5B, "Inquire identity product code protocol"}, |
645 | | { 0x5C, "Inquire identity revision number protocol"}, |
646 | | { 0x5D, "Inquire identity serial number protocol"}, |
647 | | { 0x5E, "Inquire node-ID protocol"}, |
648 | | { 0, NULL} |
649 | | }; |
650 | | |
651 | | static const value_string lss_fastscan_subnext[] = { |
652 | | { 0x0, "Vendor-ID"}, |
653 | | { 0x1, "Product code"}, |
654 | | { 0x2, "Revision number"}, |
655 | | { 0x3, "Serial number"}, |
656 | | { 0, NULL} |
657 | | }; |
658 | | |
659 | | static const value_string lss_switch_mode[] = { |
660 | | { 0x0, "Waiting state"}, |
661 | | { 0x1, "Configuration state"}, |
662 | | { 0, NULL} |
663 | | }; |
664 | | |
665 | | static const value_string lss_conf_id_err_code[] = { |
666 | | { 0x00, "Protocol successfully completed"}, |
667 | | { 0x01, "NID out of range"}, |
668 | | { 0xFF, "Implementation specific error"}, |
669 | | { 0, NULL} |
670 | | }; |
671 | | |
672 | | static const value_string lss_conf_bt_err_code[] = { |
673 | | { 0x00, "Protocol successfully completed"}, |
674 | | { 0x01, "Bit rate not supported"}, |
675 | | { 0xFF, "Implementation specific error"}, |
676 | | { 0, NULL} |
677 | | }; |
678 | | |
679 | | static const value_string lss_store_conf_err_code[] = { |
680 | | { 0x00, "Protocol successfully completed"}, |
681 | | { 0x01, "Store configuration not supported"}, |
682 | | { 0x02, "Storage media access erro"}, |
683 | | { 0xFF, "Implementation specific error"}, |
684 | | { 0, NULL} |
685 | | }; |
686 | | |
687 | | static const value_string bit_timing_tbl[] = { |
688 | | { 0x00, "1000 kbit/s"}, |
689 | | { 0x01, "800 kbit/s"}, |
690 | | { 0x02, "500 kbit/s"}, |
691 | | { 0x03, "250 kbit/s"}, |
692 | | { 0x04, "125 kbit/s"}, |
693 | | { 0x05, "Reserved"}, |
694 | | { 0x06, "50 kbit/s"}, |
695 | | { 0x07, "20 kbit/s"}, |
696 | | { 0x08, "10 kbit/s"}, |
697 | | { 0x09, "Auto bit rate detection"}, |
698 | | { 0, NULL} |
699 | | }; |
700 | | |
701 | | |
702 | | static const value_string lss_id_remote_slave[] = { |
703 | | { 0x46, "Vendor-ID"}, |
704 | | { 0x47, "Product-code"}, |
705 | | { 0x48, "Revision-number (low)"}, |
706 | | { 0x49, "Revision-number (high)"}, |
707 | | { 0x4A, "Serial-number (low)"}, |
708 | | { 0x4B, "Serial-number (high)"}, |
709 | | { 0, NULL} |
710 | | }; |
711 | | |
712 | | static const value_string lss_inquire_id[] = { |
713 | | { 0x5A, "Vendor-ID"}, |
714 | | { 0x5B, "Product-code"}, |
715 | | { 0x5C, "Revision-number"}, |
716 | | { 0x5D, "Serial-number"}, |
717 | | { 0x5E, "Node-ID"}, |
718 | | { 0, NULL} |
719 | | }; |
720 | | |
721 | | static unsigned |
722 | | canopen_detect_msg_type(unsigned function_code, unsigned node_id) |
723 | 0 | { |
724 | 0 | switch (function_code) { |
725 | 0 | case FC_NMT: |
726 | 0 | return MT_NMT_CTRL; |
727 | 0 | case FC_SYNC: |
728 | 0 | if (node_id == 0) { |
729 | 0 | return MT_SYNC; |
730 | 0 | } else { |
731 | 0 | return MT_EMERGENCY; |
732 | 0 | } |
733 | 0 | break; |
734 | 0 | case FC_TIME_STAMP: |
735 | 0 | return MT_TIME_STAMP; |
736 | 0 | case FC_PDO1_TX: |
737 | 0 | return MT_PDO; |
738 | 0 | case FC_PDO1_RX: |
739 | 0 | return MT_PDO; |
740 | 0 | case FC_PDO2_TX: |
741 | 0 | return MT_PDO; |
742 | 0 | case FC_PDO2_RX: |
743 | 0 | return MT_PDO; |
744 | 0 | case FC_PDO3_TX: |
745 | 0 | return MT_PDO; |
746 | 0 | case FC_PDO3_RX: |
747 | 0 | return MT_PDO; |
748 | 0 | case FC_PDO4_TX: |
749 | 0 | return MT_PDO; |
750 | 0 | case FC_PDO4_RX: |
751 | 0 | return MT_PDO; |
752 | 0 | case FC_DEFAULT_SDO_TX: |
753 | 0 | return MT_SDO; |
754 | 0 | case FC_DEFAULT_SDO_RX: |
755 | 0 | return MT_SDO; |
756 | 0 | case FC_NMT_ERR_CONTROL: |
757 | 0 | return MT_NMT_ERR_CTRL; |
758 | 0 | case LSS_MASTER_CAN_ID >> 7: |
759 | 0 | if (node_id == (LSS_MASTER_CAN_ID & 0x7F)) { |
760 | 0 | return MT_LSS_MASTER; |
761 | 0 | } else if (node_id == (LSS_SLAVE_CAN_ID & 0x7F)) { |
762 | 0 | return MT_LSS_SLAVE; |
763 | 0 | } |
764 | 0 | return MT_UNKNOWN; |
765 | 0 | default: |
766 | 0 | return MT_UNKNOWN; |
767 | 0 | } |
768 | 0 | } |
769 | | |
770 | | |
771 | | static inline int * const * |
772 | | sdo_cmd_fields_scs(unsigned cs, unsigned subcommand) |
773 | 0 | { |
774 | 0 | if (cs < array_length(_sdo_cmd_fields_scs)) |
775 | 0 | return _sdo_cmd_fields_scs[cs]; |
776 | 0 | else if(cs == SDO_SCS_BLOCK_DOWN && subcommand < array_length(_sdo_cmd_fields_scs5)) |
777 | 0 | return _sdo_cmd_fields_scs5[subcommand]; |
778 | 0 | else if(cs == SDO_SCS_BLOCK_UP && subcommand < array_length(_sdo_cmd_fields_scs6)) |
779 | 0 | return _sdo_cmd_fields_scs6[subcommand]; |
780 | 0 | return NULL; |
781 | 0 | } |
782 | | |
783 | | static inline int * const * |
784 | | sdo_cmd_fields_ccs(unsigned cs, unsigned subcommand) |
785 | 0 | { |
786 | 0 | if (cs < array_length(_sdo_cmd_fields_ccs)) |
787 | 0 | return _sdo_cmd_fields_ccs[cs]; |
788 | 0 | else if (cs == SDO_CCS_BLOCK_UP && subcommand < array_length(_sdo_cmd_fields_ccs5)) |
789 | 0 | return _sdo_cmd_fields_ccs5[subcommand]; |
790 | 0 | else if (cs == SDO_CCS_BLOCK_DOWN && subcommand < array_length(_sdo_cmd_fields_ccs6)) |
791 | 0 | return _sdo_cmd_fields_ccs6[subcommand]; |
792 | 0 | return NULL; |
793 | 0 | } |
794 | | |
795 | | static void |
796 | | dissect_sdo(tvbuff_t *tvb, packet_info *pinfo, proto_tree *canopen_type_tree, unsigned function_code) |
797 | 0 | { |
798 | 0 | unsigned offset = 0; |
799 | | /*number of data bytes*/ |
800 | 0 | uint8_t sdo_data = 0; |
801 | | /*Field existence*/ |
802 | 0 | uint8_t sdo_mux = 0, sdo_pst = 0; |
803 | | /*sdo values used to choose dissector*/ |
804 | 0 | uint8_t sdo_cs = 0, sdo_subcommand = 0; |
805 | 0 | int * const *sdo_cmd_fields; |
806 | | |
807 | | /* get SDO command specifier */ |
808 | 0 | sdo_cs = tvb_get_bits8(tvb, 0, 3); |
809 | |
|
810 | 0 | if (function_code == FC_DEFAULT_SDO_RX) { |
811 | 0 | col_append_fstr(pinfo->cinfo, COL_INFO, |
812 | 0 | ": %s", val_to_str(pinfo->pool, sdo_cs, sdo_ccs, |
813 | 0 | "Unknown (0x%x)")); |
814 | |
|
815 | 0 | switch (sdo_cs) { |
816 | 0 | case SDO_CCS_DOWN_SEG_REQ: |
817 | 0 | sdo_mux = 0; |
818 | 0 | sdo_data = 7; |
819 | 0 | break; |
820 | 0 | case SDO_CCS_INIT_DOWN_REQ: |
821 | 0 | sdo_mux = 1; |
822 | 0 | sdo_data = 4; |
823 | 0 | break; |
824 | 0 | case SDO_CCS_INIT_UP_REQ: |
825 | 0 | sdo_mux = 1; |
826 | 0 | sdo_data = 0; |
827 | 0 | break; |
828 | 0 | case SDO_CCS_UP_SEQ_REQ: |
829 | 0 | sdo_mux = 0; |
830 | 0 | sdo_data = 0; |
831 | 0 | break; |
832 | 0 | case SDO_CS_ABORT_TRANSFER: |
833 | 0 | sdo_mux = 1; |
834 | 0 | sdo_data = 4; |
835 | 0 | break; |
836 | 0 | case SDO_CCS_BLOCK_UP: |
837 | 0 | sdo_subcommand = tvb_get_bits8(tvb, 6, 2); |
838 | 0 | if(sdo_subcommand == 0) |
839 | 0 | { |
840 | 0 | sdo_mux = 1; |
841 | | /*only the client sends pst*/ |
842 | 0 | sdo_pst = 1; |
843 | 0 | } |
844 | | /*check unused field is empty, otherwise it could be a data block segment |
845 | | (TODO: add segment decoding)*/ |
846 | 0 | if(tvb_get_bits8(tvb, 3, 3) != 0) |
847 | 0 | return; |
848 | 0 | break; |
849 | 0 | case SDO_CCS_BLOCK_DOWN: |
850 | 0 | sdo_subcommand = tvb_get_bits8(tvb, 7, 1); |
851 | 0 | if(sdo_subcommand == 0) |
852 | 0 | { |
853 | 0 | sdo_mux = 1; |
854 | 0 | sdo_data = 4; |
855 | | /*check unused field is empty, otherwise it could be a data block segment |
856 | | (TODO: add segment decoding)*/ |
857 | 0 | if(tvb_get_bits8(tvb, 3, 3) != 0) |
858 | 0 | return; |
859 | 0 | } |
860 | 0 | else |
861 | 0 | { |
862 | 0 | sdo_data = 2; |
863 | | /*check unused field is empty, otherwise it could be a data block segment |
864 | | (TODO: add segment decoding)*/ |
865 | 0 | if(tvb_get_bits8(tvb, 6, 1) != 0) |
866 | 0 | return; |
867 | 0 | } |
868 | 0 | break; |
869 | 0 | default: |
870 | 0 | return; |
871 | 0 | } |
872 | | |
873 | 0 | sdo_cmd_fields = sdo_cmd_fields_ccs(sdo_cs,sdo_subcommand); |
874 | |
|
875 | 0 | } else { |
876 | 0 | col_append_fstr(pinfo->cinfo, COL_INFO, |
877 | 0 | ": %s", val_to_str(pinfo->pool, sdo_cs, sdo_scs, |
878 | 0 | "Unknown (0x%x)")); |
879 | |
|
880 | 0 | switch (sdo_cs) { |
881 | 0 | case SDO_SCS_UP_SEQ_RESP: |
882 | 0 | sdo_mux = 0; |
883 | 0 | sdo_data = 7; |
884 | 0 | break; |
885 | 0 | case SDO_SCS_DOWN_SEG_RESP: |
886 | 0 | sdo_mux = 0; |
887 | 0 | sdo_data = 0; |
888 | 0 | break; |
889 | 0 | case SDO_SCS_INIT_UP_RESP: |
890 | 0 | sdo_mux = 1; |
891 | 0 | sdo_data = 4; |
892 | 0 | break; |
893 | 0 | case SDO_SCS_INIT_DOWN_RESP: |
894 | 0 | sdo_mux = 1; |
895 | 0 | sdo_data = 0; |
896 | 0 | break; |
897 | 0 | case SDO_CS_ABORT_TRANSFER: |
898 | 0 | sdo_mux = 1; |
899 | 0 | sdo_data = 4; |
900 | 0 | break; |
901 | 0 | case SDO_SCS_BLOCK_DOWN: |
902 | 0 | sdo_subcommand = tvb_get_bits8(tvb, 6, 2); |
903 | 0 | if(sdo_subcommand == 0) |
904 | 0 | { |
905 | 0 | sdo_mux = 1; |
906 | 0 | } |
907 | | /*check unused field is empty, otherwise it could be a data block segment |
908 | | (TODO: add segment decoding)*/ |
909 | 0 | if(tvb_get_bits8(tvb, 3, 3) != 0) |
910 | 0 | return; |
911 | 0 | break; |
912 | 0 | case SDO_SCS_BLOCK_UP: |
913 | 0 | sdo_subcommand = tvb_get_bits8(tvb, 7, 1); |
914 | 0 | if(sdo_subcommand == 0) |
915 | 0 | { |
916 | 0 | sdo_mux = 1; |
917 | 0 | sdo_data = 4; |
918 | | /*check unused field is empty, otherwise it could be a data block segment |
919 | | (TODO: add segment decoding)*/ |
920 | 0 | if(tvb_get_bits8(tvb, 3, 3) != 0) |
921 | 0 | return; |
922 | 0 | } |
923 | 0 | else |
924 | 0 | { |
925 | 0 | sdo_data = 2; |
926 | | /*check unused field is empty, otherwise it could be a data block segment |
927 | | (TODO: add segment decoding)*/ |
928 | 0 | if(tvb_get_bits8(tvb, 6, 1) != 0) |
929 | 0 | return; |
930 | 0 | } |
931 | 0 | break; |
932 | 0 | default: |
933 | 0 | return; |
934 | 0 | } |
935 | | |
936 | 0 | sdo_cmd_fields = sdo_cmd_fields_scs(sdo_cs,sdo_subcommand); |
937 | 0 | } |
938 | | |
939 | 0 | if (sdo_cmd_fields == NULL) { |
940 | 0 | proto_tree_add_item(canopen_type_tree, hf_canopen_sdo_cmd, tvb, 0, 1, ENC_LITTLE_ENDIAN); |
941 | | /* XXX Add expert info */ |
942 | 0 | return; |
943 | 0 | } |
944 | | |
945 | 0 | proto_tree_add_bitmask(canopen_type_tree, tvb, offset, |
946 | 0 | hf_canopen_sdo_cmd, ett_canopen_sdo_cmd, sdo_cmd_fields, ENC_LITTLE_ENDIAN); |
947 | |
|
948 | 0 | offset++; |
949 | |
|
950 | 0 | if (sdo_mux) { |
951 | | /* decode mux */ |
952 | 0 | proto_tree_add_item(canopen_type_tree, |
953 | 0 | hf_canopen_sdo_main_idx, tvb, offset, 2, ENC_LITTLE_ENDIAN); |
954 | 0 | offset += 2; |
955 | |
|
956 | 0 | proto_tree_add_item(canopen_type_tree, |
957 | 0 | hf_canopen_sdo_sub_idx, tvb, offset, 1, ENC_LITTLE_ENDIAN); |
958 | 0 | offset++; |
959 | 0 | } |
960 | |
|
961 | 0 | if (sdo_cs == SDO_CS_ABORT_TRANSFER) { |
962 | | /* SDO abort transfer */ |
963 | 0 | proto_tree_add_item(canopen_type_tree, |
964 | 0 | hf_canopen_sdo_abort_code, tvb, offset, 4, ENC_LITTLE_ENDIAN); |
965 | 0 | return; |
966 | 0 | } |
967 | | |
968 | 0 | if (sdo_cs == 5) { |
969 | | /*SDO_SCS_BLOCK_DOWN or SDO_CCS_BLOCK_UP*/ |
970 | 0 | if(sdo_subcommand == 2) |
971 | 0 | { |
972 | | /*decode ackseq byte)*/ |
973 | 0 | proto_tree_add_item(canopen_type_tree, |
974 | 0 | hf_canopen_sdo_cmd_block_ackseq, tvb, offset, 1, ENC_LITTLE_ENDIAN); |
975 | 0 | offset++; |
976 | 0 | } |
977 | |
|
978 | 0 | if(sdo_subcommand == 0 || sdo_subcommand == 2) |
979 | 0 | { |
980 | | /*decode blksize byte)*/ |
981 | 0 | proto_tree_add_item(canopen_type_tree, |
982 | 0 | hf_canopen_sdo_cmd_block_blksize, tvb, offset, 1, ENC_LITTLE_ENDIAN); |
983 | 0 | offset++; |
984 | 0 | } |
985 | 0 | } |
986 | |
|
987 | 0 | if (sdo_pst) { |
988 | | /*decode pst byte)*/ |
989 | 0 | proto_tree_add_item(canopen_type_tree, |
990 | 0 | hf_canopen_sdo_cmd_block_pst, tvb, offset, 1, ENC_LITTLE_ENDIAN); |
991 | 0 | offset++; |
992 | 0 | } |
993 | |
|
994 | 0 | if (sdo_data) { |
995 | 0 | proto_tree_add_item(canopen_type_tree, |
996 | 0 | hf_canopen_sdo_data, tvb, offset, sdo_data, ENC_NA); |
997 | 0 | offset += sdo_data; |
998 | 0 | } |
999 | |
|
1000 | 0 | if(offset < 8) |
1001 | 0 | { |
1002 | | /* Reserved */ |
1003 | 0 | proto_tree_add_item(canopen_type_tree, |
1004 | 0 | hf_canopen_reserved, tvb, offset, 8 - offset, ENC_NA); |
1005 | 0 | } |
1006 | 0 | } |
1007 | | |
1008 | | static void |
1009 | | dissect_lss(tvbuff_t *tvb, packet_info *pinfo, proto_tree *canopen_type_tree, unsigned msg_type_id) |
1010 | 0 | { |
1011 | 0 | unsigned offset = 0; |
1012 | 0 | int reserved = 0; |
1013 | 0 | uint8_t lss_cs; |
1014 | 0 | uint8_t lss_bc_mask; |
1015 | 0 | uint16_t lss_abt_delay; |
1016 | | |
1017 | | /* LSS command specifier */ |
1018 | 0 | proto_tree_add_item_ret_uint8(canopen_type_tree, |
1019 | 0 | hf_canopen_lss_cs, tvb, offset, 1, ENC_LITTLE_ENDIAN, &lss_cs); |
1020 | 0 | col_append_fstr(pinfo->cinfo, COL_INFO, ": %s", val_to_str(pinfo->pool, lss_cs, lss_cs_code, "Unknown (0x%x)")); |
1021 | 0 | offset++; |
1022 | |
|
1023 | 0 | if (msg_type_id == MT_LSS_MASTER) { |
1024 | | |
1025 | | /* Master commands */ |
1026 | 0 | switch (lss_cs) { |
1027 | 0 | case LSS_CS_SWITCH_GLOBAL: |
1028 | 0 | col_append_fstr(pinfo->cinfo, COL_INFO, |
1029 | 0 | ": %s", val_to_str(pinfo->pool, tvb_get_uint8(tvb, offset), lss_switch_mode, "Unknown (0x%x)")); |
1030 | |
|
1031 | 0 | proto_tree_add_item(canopen_type_tree, |
1032 | 0 | hf_canopen_lss_switch_mode, tvb, offset, 1, ENC_LITTLE_ENDIAN); |
1033 | 0 | offset++; |
1034 | 0 | reserved = 6; |
1035 | 0 | break; |
1036 | 0 | case LSS_CS_SWITCH_SELECTIVE_VENDOR: |
1037 | 0 | proto_tree_add_item(canopen_type_tree, |
1038 | 0 | hf_canopen_lss_addr_vendor, tvb, offset, 4, ENC_LITTLE_ENDIAN); |
1039 | 0 | offset += 4; |
1040 | 0 | reserved = 3; |
1041 | 0 | break; |
1042 | 0 | case LSS_CS_SWITCH_SELECTIVE_PRODUCT: |
1043 | 0 | proto_tree_add_item(canopen_type_tree, |
1044 | 0 | hf_canopen_lss_addr_product, tvb, offset, 4, ENC_LITTLE_ENDIAN); |
1045 | 0 | offset += 4; |
1046 | 0 | reserved = 3; |
1047 | 0 | break; |
1048 | 0 | case LSS_CS_SWITCH_SELECTIVE_REVISION: |
1049 | 0 | proto_tree_add_item(canopen_type_tree, |
1050 | 0 | hf_canopen_lss_addr_revision, tvb, offset, 4, ENC_LITTLE_ENDIAN); |
1051 | 0 | offset += 4; |
1052 | 0 | reserved = 3; |
1053 | 0 | break; |
1054 | 0 | case LSS_CS_SWITCH_SELECTIVE_SERIAL: |
1055 | 0 | proto_tree_add_item(canopen_type_tree, |
1056 | 0 | hf_canopen_lss_addr_serial, tvb, offset, 4, ENC_LITTLE_ENDIAN); |
1057 | 0 | offset += 4; |
1058 | 0 | reserved = 3; |
1059 | 0 | break; |
1060 | 0 | case LSS_CS_CONF_NODE_ID: |
1061 | 0 | col_append_fstr(pinfo->cinfo, COL_INFO, ": 0x%02x", tvb_get_uint8(tvb, offset)); |
1062 | |
|
1063 | 0 | proto_tree_add_item(canopen_type_tree, |
1064 | 0 | hf_canopen_lss_nid, tvb, offset, 1, ENC_LITTLE_ENDIAN); |
1065 | 0 | offset++; |
1066 | 0 | reserved = 6; |
1067 | 0 | break; |
1068 | 0 | case LSS_CS_CONF_BIT_TIMING: |
1069 | 0 | proto_tree_add_item(canopen_type_tree, |
1070 | 0 | hf_canopen_lss_bt_tbl_selector, tvb, offset, 1, ENC_LITTLE_ENDIAN); |
1071 | 0 | offset++; |
1072 | | |
1073 | | /* XXX Note that current dissector only works for table selector 0x00 (CiA 301 Table 1) */ |
1074 | 0 | col_append_fstr(pinfo->cinfo, COL_INFO, |
1075 | 0 | ": %s", val_to_str(pinfo->pool, tvb_get_uint8(tvb, offset), bit_timing_tbl, "Unknown (0x%x)")); |
1076 | 0 | proto_tree_add_item(canopen_type_tree, |
1077 | 0 | hf_canopen_lss_bt_tbl_index, tvb, offset, 1, ENC_LITTLE_ENDIAN); |
1078 | 0 | offset++; |
1079 | 0 | reserved = 5; |
1080 | 0 | break; |
1081 | 0 | case LSS_CS_CONF_ACT_BIT_TIMING: |
1082 | 0 | lss_abt_delay = tvb_get_letohl(tvb, offset); |
1083 | |
|
1084 | 0 | col_append_fstr(pinfo->cinfo, COL_INFO, ": %d ms", lss_abt_delay); |
1085 | |
|
1086 | 0 | proto_tree_add_uint_format_value(canopen_type_tree, |
1087 | 0 | hf_canopen_lss_abt_delay, tvb, offset, 2, lss_abt_delay, |
1088 | 0 | "%d ms (0x%02x)", lss_abt_delay, lss_abt_delay); |
1089 | | |
1090 | |
|
1091 | 0 | offset += 2; |
1092 | 0 | reserved = 5; |
1093 | 0 | break; |
1094 | 0 | case LSS_CS_CONF_STORE: |
1095 | 0 | case LSS_CS_INQ_VENDOR_ID: |
1096 | 0 | case LSS_CS_INQ_PRODUCT_CODE: |
1097 | 0 | case LSS_CS_INQ_REV_NUMBER: |
1098 | 0 | case LSS_CS_INQ_SERIAL_NUMBER: |
1099 | 0 | case LSS_CS_INQ_NODE_ID: |
1100 | 0 | reserved = 7; |
1101 | 0 | break; |
1102 | 0 | case LSS_CS_IDENT_REMOTE_VENDOR: |
1103 | 0 | case LSS_CS_IDENT_REMOTE_PRODUCT: |
1104 | 0 | case LSS_CS_IDENT_REMOTE_REV_LOW: |
1105 | 0 | case LSS_CS_IDENT_REMOTE_REV_HIGH: |
1106 | 0 | case LSS_CS_IDENT_REMOTE_SERIAL_LOW: |
1107 | 0 | case LSS_CS_IDENT_REMOTE_SERIAL_HIGH: |
1108 | 0 | col_append_fstr(pinfo->cinfo, COL_INFO, ", %s 0x%08x", |
1109 | 0 | val_to_str_const(lss_cs, lss_id_remote_slave, "(Unknown)"), tvb_get_letohl(tvb, offset)); |
1110 | |
|
1111 | 0 | proto_tree_add_item(canopen_type_tree, |
1112 | 0 | *hf_canopen_lss_addr_ident[lss_cs - LSS_CS_IDENT_REMOTE_VENDOR], tvb, offset, 4, ENC_LITTLE_ENDIAN); |
1113 | 0 | offset += 4; |
1114 | 0 | reserved = 3; |
1115 | 0 | break; |
1116 | 0 | case LSS_CS_IDENT_REMOTE_NON_CONF: |
1117 | 0 | reserved = 7; |
1118 | 0 | break; |
1119 | 0 | case LSS_CS_IDENT_FASTSCAN: |
1120 | 0 | proto_tree_add_item(canopen_type_tree, |
1121 | 0 | hf_canopen_lss_fastscan_id, tvb, offset, 4, ENC_LITTLE_ENDIAN); |
1122 | 0 | offset += 4; |
1123 | 0 | lss_bc_mask = tvb_get_uint8(tvb, offset); |
1124 | 0 | if (lss_bc_mask == 0x80) { |
1125 | 0 | proto_tree_add_uint_format_value(canopen_type_tree, |
1126 | 0 | hf_canopen_lss_fastscan_check, tvb, offset, 1, lss_bc_mask, |
1127 | 0 | "All LSS slaves (0x%02x)", lss_bc_mask); |
1128 | 0 | } else if (lss_bc_mask < 32) { |
1129 | 0 | proto_tree_add_uint_format_value(canopen_type_tree, |
1130 | 0 | hf_canopen_lss_fastscan_check, tvb, offset, 1, |
1131 | 0 | lss_bc_mask, "0x%x (0x%02x)", |
1132 | 0 | ~((1 << lss_bc_mask) - 1), |
1133 | 0 | lss_bc_mask); |
1134 | 0 | } else { |
1135 | 0 | proto_tree_add_uint_format_value(canopen_type_tree, |
1136 | 0 | hf_canopen_lss_fastscan_check, tvb, offset, 1, lss_bc_mask, |
1137 | 0 | "Reserved (0x%02x)", lss_bc_mask); |
1138 | 0 | } |
1139 | 0 | offset++; |
1140 | 0 | proto_tree_add_item(canopen_type_tree, |
1141 | 0 | hf_canopen_lss_fastscan_sub, tvb, offset, 1, ENC_LITTLE_ENDIAN); |
1142 | 0 | offset++; |
1143 | 0 | proto_tree_add_item(canopen_type_tree, |
1144 | 0 | hf_canopen_lss_fastscan_next, tvb, offset, 1, ENC_LITTLE_ENDIAN); |
1145 | 0 | break; |
1146 | 0 | default: /* invalid command specifier */ |
1147 | 0 | return; |
1148 | 0 | } |
1149 | |
|
1150 | 0 | } else { |
1151 | | |
1152 | | /* Slave commands */ |
1153 | 0 | switch (lss_cs) { |
1154 | 0 | case LSS_CS_SWITCH_SELECTIVE_RESP: |
1155 | 0 | reserved = 7; |
1156 | 0 | break; |
1157 | 0 | case LSS_CS_CONF_NODE_ID: |
1158 | 0 | proto_tree_add_item(canopen_type_tree, |
1159 | 0 | hf_canopen_lss_conf_id_err_code, tvb, offset, 1, ENC_LITTLE_ENDIAN); |
1160 | 0 | offset++; |
1161 | 0 | proto_tree_add_item(canopen_type_tree, |
1162 | 0 | hf_canopen_lss_spec_err, tvb, offset, 1, ENC_LITTLE_ENDIAN); |
1163 | 0 | offset++; |
1164 | 0 | reserved = 5; |
1165 | 0 | break; |
1166 | 0 | case LSS_CS_CONF_BIT_TIMING: |
1167 | 0 | proto_tree_add_item(canopen_type_tree, |
1168 | 0 | hf_canopen_lss_conf_bt_err_code, tvb, offset, 1, ENC_LITTLE_ENDIAN); |
1169 | |
|
1170 | 0 | offset++; |
1171 | 0 | proto_tree_add_item(canopen_type_tree, |
1172 | 0 | hf_canopen_lss_spec_err, tvb, offset, 1, ENC_LITTLE_ENDIAN); |
1173 | |
|
1174 | 0 | offset++; |
1175 | 0 | reserved = 5; |
1176 | 0 | break; |
1177 | 0 | case LSS_CS_CONF_STORE: |
1178 | 0 | proto_tree_add_item(canopen_type_tree, |
1179 | 0 | hf_canopen_lss_store_conf_err_code, tvb, offset, 1, ENC_LITTLE_ENDIAN); |
1180 | 0 | offset++; |
1181 | 0 | proto_tree_add_item(canopen_type_tree, |
1182 | 0 | hf_canopen_lss_spec_err, tvb, offset, 1, ENC_LITTLE_ENDIAN); |
1183 | 0 | offset++; |
1184 | 0 | reserved = 5; |
1185 | 0 | break; |
1186 | 0 | case LSS_CS_INQ_VENDOR_ID: |
1187 | 0 | case LSS_CS_INQ_PRODUCT_CODE: |
1188 | 0 | case LSS_CS_INQ_REV_NUMBER: |
1189 | 0 | case LSS_CS_INQ_SERIAL_NUMBER: |
1190 | 0 | col_append_fstr(pinfo->cinfo, COL_INFO, |
1191 | 0 | ", %s 0x%08x", val_to_str_const(lss_cs, lss_inquire_id, "(Unknown)"), tvb_get_letohl(tvb, offset)); |
1192 | |
|
1193 | 0 | proto_tree_add_item(canopen_type_tree, |
1194 | 0 | *hf_canopen_lss_addr_inquire[lss_cs - LSS_CS_INQ_VENDOR_ID], tvb, offset, 4, ENC_LITTLE_ENDIAN); |
1195 | 0 | offset += 4; |
1196 | 0 | reserved = 3; |
1197 | 0 | break; |
1198 | 0 | case LSS_CS_INQ_NODE_ID: |
1199 | 0 | col_append_fstr(pinfo->cinfo, COL_INFO, |
1200 | 0 | ", %s 0x%08x", val_to_str_const(lss_cs, lss_inquire_id, "(Unknown)"), tvb_get_letohl(tvb, offset)); |
1201 | |
|
1202 | 0 | proto_tree_add_item(canopen_type_tree, |
1203 | 0 | hf_canopen_lss_nid, tvb, offset, 1, ENC_LITTLE_ENDIAN); |
1204 | 0 | offset++; |
1205 | 0 | reserved = 6; |
1206 | 0 | break; |
1207 | 0 | case LSS_CS_IDENT_SLAVE: |
1208 | 0 | reserved = 7; |
1209 | 0 | break; |
1210 | 0 | case LSS_CS_IDENT_NON_CONF_SLAVE: |
1211 | 0 | reserved = 7; |
1212 | 0 | break; |
1213 | 0 | default: /* invalid command specifier */ |
1214 | 0 | return; |
1215 | 0 | } |
1216 | |
|
1217 | 0 | } |
1218 | | |
1219 | 0 | if (reserved) { |
1220 | 0 | proto_tree_add_item(canopen_type_tree, |
1221 | 0 | hf_canopen_reserved, tvb, offset, reserved, ENC_NA); |
1222 | 0 | } |
1223 | |
|
1224 | 0 | } |
1225 | | |
1226 | | /* Code to actually dissect the packets */ |
1227 | | static int |
1228 | | dissect_canopen(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data) |
1229 | 0 | { |
1230 | 0 | unsigned function_code; |
1231 | 0 | unsigned node_id; |
1232 | 0 | uint32_t time_stamp_msec; |
1233 | 0 | uint32_t time_stamp_days; |
1234 | 0 | struct can_info can_info; |
1235 | 0 | unsigned msg_type_id; |
1236 | 0 | nstime_t time_stamp; |
1237 | 0 | int can_data_len = tvb_reported_length(tvb); |
1238 | 0 | const char *function_code_str; |
1239 | 0 | unsigned offset = 0; |
1240 | 0 | uint8_t nmt_node_id; |
1241 | |
|
1242 | 0 | proto_item *ti, *cob_ti; |
1243 | 0 | proto_tree *canopen_tree; |
1244 | 0 | proto_tree *canopen_cob_tree; |
1245 | 0 | proto_tree *canopen_type_tree; |
1246 | |
|
1247 | 0 | DISSECTOR_ASSERT(data); |
1248 | 0 | can_info = *((struct can_info*)data); |
1249 | |
|
1250 | 0 | if (can_info.id & (CAN_ERR_FLAG | CAN_RTR_FLAG | CAN_EFF_FLAG)) |
1251 | 0 | { |
1252 | | /* Error, RTR and frames with extended ids are not for us. */ |
1253 | 0 | return 0; |
1254 | 0 | } |
1255 | | |
1256 | 0 | col_set_str(pinfo->cinfo, COL_PROTOCOL, "CANopen"); |
1257 | 0 | col_clear(pinfo->cinfo, COL_INFO); |
1258 | |
|
1259 | 0 | node_id = can_info.id & 0x7F; |
1260 | 0 | function_code = (can_info.id >> 7) & 0x0F; |
1261 | |
|
1262 | 0 | msg_type_id = canopen_detect_msg_type(function_code, node_id); |
1263 | |
|
1264 | 0 | if (msg_type_id == MT_LSS_MASTER) { |
1265 | 0 | function_code_str = "LSS (Master)"; |
1266 | 0 | col_add_str(pinfo->cinfo, COL_INFO, function_code_str); |
1267 | 0 | } else if (msg_type_id == MT_LSS_SLAVE) { |
1268 | 0 | function_code_str = "LSS (Slave)"; |
1269 | 0 | col_add_str(pinfo->cinfo, COL_INFO, function_code_str); |
1270 | 0 | } else { |
1271 | |
|
1272 | 0 | if (node_id == 0 ) { |
1273 | | /* broadcast */ |
1274 | 0 | function_code_str = val_to_str(pinfo->pool, function_code, CAN_open_bcast_msg_type_vals, "Unknown (%u)"); |
1275 | 0 | col_add_str(pinfo->cinfo, COL_INFO, function_code_str); |
1276 | 0 | } else { |
1277 | | /* point-to-point */ |
1278 | 0 | function_code_str = val_to_str(pinfo->pool, function_code, CAN_open_p2p_msg_type_vals, "Unknown (%u)"); |
1279 | 0 | col_add_str(pinfo->cinfo, COL_INFO, function_code_str); |
1280 | 0 | } |
1281 | 0 | } |
1282 | |
|
1283 | 0 | ti = proto_tree_add_item(tree, proto_canopen, tvb, 0, tvb_reported_length(tvb), ENC_NA); |
1284 | 0 | canopen_tree = proto_item_add_subtree(ti, ett_canopen); |
1285 | | |
1286 | | /* add COB-ID with function code and node id */ |
1287 | 0 | cob_ti = proto_tree_add_uint(canopen_tree, hf_canopen_cob_id, tvb, 0, 0, can_info.id); |
1288 | 0 | canopen_cob_tree = proto_item_add_subtree(cob_ti, ett_canopen_cob); |
1289 | | |
1290 | | /* add function code */ |
1291 | 0 | ti = proto_tree_add_uint(canopen_cob_tree, hf_canopen_function_code, tvb, 0, 0, can_info.id); |
1292 | 0 | proto_item_set_generated(ti); |
1293 | | |
1294 | | /* add node id */ |
1295 | 0 | ti = proto_tree_add_uint(canopen_cob_tree, hf_canopen_node_id, tvb, 0, 0, can_info.id); |
1296 | 0 | proto_item_set_generated(ti); |
1297 | | |
1298 | | /* add CANopen frame type */ |
1299 | |
|
1300 | 0 | canopen_type_tree = proto_tree_add_subtree_format(canopen_tree, tvb, 0, |
1301 | 0 | tvb_reported_length(tvb), |
1302 | 0 | ett_canopen_type, NULL, "Type: %s", function_code_str); |
1303 | 0 | switch(msg_type_id) |
1304 | 0 | { |
1305 | 0 | case MT_NMT_CTRL: |
1306 | 0 | col_append_fstr(pinfo->cinfo, COL_INFO, ": %s", val_to_str(pinfo->pool, tvb_get_uint8(tvb, offset), nmt_ctrl_cs, "Unknown (0x%x)")); |
1307 | |
|
1308 | 0 | proto_tree_add_item(canopen_type_tree, |
1309 | 0 | hf_canopen_nmt_ctrl_cs, tvb, offset, 1, ENC_LITTLE_ENDIAN); |
1310 | 0 | offset++; |
1311 | |
|
1312 | 0 | nmt_node_id = tvb_get_uint8(tvb, offset); |
1313 | 0 | if (nmt_node_id == 0x00) { |
1314 | 0 | col_append_str(pinfo->cinfo, COL_INFO, " [All]"); |
1315 | 0 | } else { |
1316 | 0 | col_append_fstr(pinfo->cinfo, COL_INFO, " [0x%x]", nmt_node_id); |
1317 | 0 | } |
1318 | |
|
1319 | 0 | proto_tree_add_item(canopen_type_tree, |
1320 | 0 | hf_canopen_nmt_ctrl_node_id, tvb, offset, 1, ENC_LITTLE_ENDIAN); |
1321 | 0 | break; |
1322 | 0 | case MT_NMT_ERR_CTRL: |
1323 | 0 | if (tvb_reported_length(tvb) > 0) { |
1324 | 0 | col_append_fstr(pinfo->cinfo, COL_INFO, ": %s", val_to_str_const(tvb_get_bits8(tvb, 1, 7), nmt_guard_state, "(Unknown)")); |
1325 | |
|
1326 | 0 | proto_tree_add_item(canopen_type_tree, |
1327 | 0 | hf_canopen_nmt_guard_toggle, tvb, offset, 1, ENC_LITTLE_ENDIAN); |
1328 | 0 | proto_tree_add_item(canopen_type_tree, |
1329 | 0 | hf_canopen_nmt_guard_state, tvb, offset, 1, ENC_LITTLE_ENDIAN); |
1330 | 0 | } |
1331 | |
|
1332 | 0 | col_append_fstr(pinfo->cinfo, COL_INFO, " [0x%x]", node_id); |
1333 | 0 | break; |
1334 | 0 | case MT_SYNC: |
1335 | | /* Show optional counter parameter if present */ |
1336 | 0 | if (tvb_reported_length(tvb) > 0) { |
1337 | 0 | col_append_fstr(pinfo->cinfo, COL_INFO, " [%d]", tvb_get_uint8(tvb, offset)); |
1338 | |
|
1339 | 0 | proto_tree_add_item(canopen_type_tree, |
1340 | 0 | hf_canopen_sync_counter, tvb, offset, 1, ENC_LITTLE_ENDIAN); |
1341 | 0 | } |
1342 | 0 | break; |
1343 | 0 | case MT_TIME_STAMP: |
1344 | | /* calculate the real time stamp */ |
1345 | 0 | time_stamp_msec = tvb_get_letohl(tvb, offset); |
1346 | 0 | time_stamp_days = tvb_get_letohs(tvb, offset + 4); |
1347 | 0 | time_stamp.secs = (time_stamp_days + TS_DAYS_BETWEEN_1970_AND_1984) |
1348 | 0 | * TS_SECONDS_IN_PER_DAY + (time_stamp_msec / 1000); |
1349 | 0 | time_stamp.nsecs = (time_stamp_msec % 1000) * TS_NANOSEC_PER_MSEC; |
1350 | |
|
1351 | 0 | proto_tree_add_time(canopen_type_tree, |
1352 | 0 | hf_canopen_time_stamp, tvb, offset, 6, &time_stamp); |
1353 | |
|
1354 | 0 | proto_tree_add_uint(canopen_type_tree, |
1355 | 0 | hf_canopen_time_stamp_ms, tvb, offset, 4, time_stamp_msec); |
1356 | 0 | offset += 4; |
1357 | |
|
1358 | 0 | proto_tree_add_uint(canopen_type_tree, |
1359 | 0 | hf_canopen_time_stamp_days, tvb, offset, 2, time_stamp_days); |
1360 | |
|
1361 | 0 | break; |
1362 | 0 | case MT_EMERGENCY: |
1363 | 0 | proto_tree_add_item(canopen_type_tree, |
1364 | 0 | hf_canopen_em_err_code, tvb, offset, 2, ENC_LITTLE_ENDIAN); |
1365 | 0 | offset += 2; |
1366 | |
|
1367 | 0 | proto_tree_add_bitmask(canopen_type_tree, tvb, offset, |
1368 | 0 | hf_canopen_em_err_reg, ett_canopen_em_er, em_err_reg_fields, ENC_LITTLE_ENDIAN); |
1369 | 0 | offset++; |
1370 | |
|
1371 | 0 | proto_tree_add_item(canopen_type_tree, |
1372 | 0 | hf_canopen_em_err_field, tvb, offset, 5, ENC_NA); |
1373 | 0 | break; |
1374 | 0 | case MT_PDO: |
1375 | 0 | if (can_data_len != 0) { |
1376 | 0 | proto_tree_add_item(canopen_type_tree, |
1377 | 0 | hf_canopen_pdo_data, tvb, offset, can_data_len, ENC_NA); |
1378 | 0 | } |
1379 | 0 | else { |
1380 | 0 | proto_tree_add_string(canopen_type_tree, |
1381 | 0 | hf_canopen_pdo_data_string, tvb, offset, 0, "empty"); |
1382 | 0 | } |
1383 | 0 | break; |
1384 | 0 | case MT_SDO: |
1385 | |
|
1386 | 0 | dissect_sdo(tvb, pinfo, canopen_type_tree, function_code); |
1387 | |
|
1388 | 0 | break; |
1389 | 0 | case MT_LSS_MASTER: |
1390 | 0 | case MT_LSS_SLAVE: |
1391 | |
|
1392 | 0 | dissect_lss(tvb, pinfo, canopen_type_tree, msg_type_id); |
1393 | |
|
1394 | 0 | break; |
1395 | 0 | } |
1396 | | |
1397 | 0 | return tvb_reported_length(tvb); |
1398 | 0 | } |
1399 | | |
1400 | | |
1401 | | /* Register the protocol with Wireshark */ |
1402 | | void |
1403 | | proto_register_canopen(void) |
1404 | 14 | { |
1405 | 14 | static hf_register_info hf[] = { |
1406 | | /* COB-ID */ |
1407 | 14 | { &hf_canopen_cob_id, |
1408 | 14 | { "COB-ID", "canopen.cob_id", |
1409 | 14 | FT_UINT32, BASE_HEX, NULL, 0x0, |
1410 | 14 | NULL, HFILL } |
1411 | 14 | }, |
1412 | 14 | { &hf_canopen_function_code, |
1413 | 14 | { "Function code", "canopen.function_code", |
1414 | 14 | FT_UINT32, BASE_HEX, NULL, 0x00000780, |
1415 | 14 | NULL, HFILL } |
1416 | 14 | }, |
1417 | 14 | { &hf_canopen_node_id, |
1418 | 14 | { "Node-ID", "canopen.node_id", |
1419 | 14 | FT_UINT32, BASE_HEX, NULL, 0x7F, |
1420 | 14 | NULL, HFILL } |
1421 | 14 | }, |
1422 | 14 | { &hf_canopen_pdo_data, |
1423 | 14 | { "Data", "canopen.pdo.data.bytes", |
1424 | 14 | FT_BYTES, BASE_NONE, NULL, 0x0, |
1425 | 14 | NULL, HFILL } |
1426 | 14 | }, |
1427 | 14 | { &hf_canopen_pdo_data_string, |
1428 | 14 | { "Data", "canopen.pdo.data.string", |
1429 | 14 | FT_STRINGZ, BASE_NONE, NULL, 0x0, |
1430 | 14 | NULL, HFILL } |
1431 | 14 | }, |
1432 | | /* SDO */ |
1433 | 14 | { &hf_canopen_sdo_cmd, |
1434 | 14 | { "SDO command byte", "canopen.sdo.cmd", |
1435 | 14 | FT_UINT8, BASE_HEX, NULL, 0x0, |
1436 | 14 | NULL, HFILL } |
1437 | 14 | }, |
1438 | 14 | { &hf_canopen_sdo_cmd_ccs, |
1439 | 14 | { "Client command specifier", "canopen.sdo.ccs", |
1440 | 14 | FT_UINT8, BASE_DEC, VALS(sdo_ccs), 0xE0, |
1441 | 14 | NULL, HFILL } |
1442 | 14 | }, |
1443 | 14 | { &hf_canopen_sdo_cmd_scs, |
1444 | 14 | { "Server command specifier", "canopen.sdo.scs", |
1445 | 14 | FT_UINT8, BASE_DEC, VALS(sdo_scs), 0xE0, |
1446 | 14 | NULL, HFILL } |
1447 | 14 | }, |
1448 | 14 | { &hf_canopen_sdo_cmd_ccs5_subcommand, |
1449 | 14 | { "Client subcommand", "canopen.sdo.cs", |
1450 | 14 | FT_UINT8, BASE_DEC, VALS(sdo_client_subcommand_meaning), 0x03, |
1451 | 14 | NULL, HFILL } |
1452 | 14 | }, |
1453 | 14 | { &hf_canopen_sdo_cmd_scs5_subcommand, |
1454 | 14 | { "Server command specifier", "canopen.sdo.ss", |
1455 | 14 | FT_UINT8, BASE_DEC, VALS(sdo_server_subcommand_meaning), 0x03, |
1456 | 14 | NULL, HFILL } |
1457 | 14 | }, |
1458 | 14 | { &hf_canopen_sdo_cmd_ccs6_subcommand, |
1459 | 14 | { "Client subcommand", "canopen.sdo.cs", |
1460 | 14 | FT_UINT8, BASE_DEC, VALS(sdo_client_subcommand_meaning), 0x01, |
1461 | 14 | NULL, HFILL } |
1462 | 14 | }, |
1463 | 14 | { &hf_canopen_sdo_cmd_scs6_subcommand, |
1464 | 14 | { "Server command specifier", "canopen.sdo.ss", |
1465 | 14 | FT_UINT8, BASE_DEC, VALS(sdo_server_subcommand_meaning), 0x01, |
1466 | 14 | NULL, HFILL } |
1467 | 14 | }, |
1468 | 14 | { &hf_canopen_sdo_cmd_block_crc_support, |
1469 | 14 | { "CRC support", "canopen.sdo.crc_support", |
1470 | 14 | FT_BOOLEAN, 8, NULL, 0x04, |
1471 | 14 | "toggle", HFILL } |
1472 | 14 | }, |
1473 | 14 | { &hf_canopen_sdo_cmd_block_s, |
1474 | 14 | { "Data set size indicated", "canopen.sdo.s", |
1475 | 14 | FT_BOOLEAN, 8, NULL, 0x02, |
1476 | 14 | "toggle", HFILL } |
1477 | 14 | }, |
1478 | 14 | { &hf_canopen_sdo_cmd_block_n, |
1479 | 14 | { "Non-data byte", "canopen.sdo.n", |
1480 | 14 | FT_UINT8, BASE_DEC, NULL, 0x1C, |
1481 | 14 | "toggle", HFILL } |
1482 | 14 | }, |
1483 | 14 | { &hf_canopen_sdo_cmd_block_ackseq, |
1484 | 14 | { "Number of segments acknowledged", "canopen.sdo.ackseq", |
1485 | 14 | FT_UINT8, BASE_DEC, NULL, 0x0, |
1486 | 14 | NULL, HFILL } |
1487 | 14 | }, |
1488 | 14 | { &hf_canopen_sdo_cmd_block_blksize, |
1489 | 14 | { "Number of segments per block", "canopen.sdo.blksize", |
1490 | 14 | FT_UINT8, BASE_DEC, NULL, 0x0, |
1491 | 14 | NULL, HFILL } |
1492 | 14 | }, |
1493 | 14 | { &hf_canopen_sdo_cmd_block_pst, |
1494 | 14 | { "Protocol switch threshold (bytes)", "canopen.sdo.pst", |
1495 | 14 | FT_UINT8, BASE_DEC, NULL, 0x0, |
1496 | 14 | NULL, HFILL } |
1497 | 14 | }, |
1498 | 14 | { &hf_canopen_sdo_cmd_toggle, |
1499 | 14 | { "Toggle bit", "canopen.sdo.toggle", |
1500 | 14 | FT_UINT8, BASE_DEC, NULL, 0x10, |
1501 | 14 | NULL, HFILL }}, |
1502 | 14 | { &hf_canopen_sdo_cmd_updown_n, |
1503 | 14 | { "Non-data bytes", "canopen.sdo.n", |
1504 | 14 | FT_UINT8, BASE_DEC, NULL, 0x0E, |
1505 | 14 | "toggle", HFILL }}, |
1506 | 14 | { &hf_canopen_sdo_cmd_updown_c, |
1507 | 14 | { "No more segments", "canopen.sdo.c", |
1508 | 14 | FT_BOOLEAN, 8, NULL, 0x01, |
1509 | 14 | "toggle", HFILL }}, |
1510 | 14 | { &hf_canopen_sdo_cmd_init_n, |
1511 | 14 | { "Non-data bytes", "canopen.sdo.n", |
1512 | 14 | FT_UINT8, BASE_DEC, NULL, 0x0C, |
1513 | 14 | "toggle", HFILL }}, |
1514 | 14 | { &hf_canopen_sdo_cmd_init_e, |
1515 | 14 | { "Expedited transfer", "canopen.sdo.e", |
1516 | 14 | FT_BOOLEAN, 8, NULL, 0x02, |
1517 | 14 | "toggle", HFILL }}, |
1518 | 14 | { &hf_canopen_sdo_cmd_init_s, |
1519 | 14 | { "Data set size indicated", "canopen.sdo.s", |
1520 | 14 | FT_BOOLEAN, 8, NULL, 0x01, |
1521 | 14 | "toggle", HFILL }}, |
1522 | 14 | { &hf_canopen_sdo_main_idx, |
1523 | 14 | { "OD main-index", "canopen.sdo.main_idx", |
1524 | 14 | FT_UINT16, BASE_HEX|BASE_RANGE_STRING, RVALS(obj_dict), 0x0, |
1525 | 14 | NULL, HFILL } |
1526 | 14 | }, |
1527 | 14 | { &hf_canopen_sdo_sub_idx, |
1528 | 14 | { "OD sub-index", "canopen.sdo.sub_idx", |
1529 | 14 | FT_UINT8, BASE_HEX, NULL, 0x0, |
1530 | 14 | NULL, HFILL } |
1531 | 14 | }, |
1532 | 14 | { &hf_canopen_sdo_data, |
1533 | 14 | { "Data", "canopen.sdo.data.bytes", |
1534 | 14 | FT_BYTES, BASE_NONE, NULL, 0x0, |
1535 | 14 | NULL, HFILL } |
1536 | 14 | }, |
1537 | 14 | { &hf_canopen_sdo_abort_code, |
1538 | 14 | { "Abort code", "canopen.sdo.abort_code", |
1539 | 14 | FT_UINT32, BASE_HEX, VALS(sdo_abort_code), 0x0, |
1540 | 14 | NULL, HFILL } |
1541 | 14 | }, |
1542 | 14 | { &hf_canopen_reserved, |
1543 | 14 | { "Reserved", "canopen.reserved", |
1544 | 14 | FT_BYTES, BASE_NONE, NULL, 0x00, |
1545 | 14 | NULL, HFILL } |
1546 | 14 | }, |
1547 | 14 | { &hf_canopen_em_err_code, |
1548 | 14 | { "Error code", "canopen.em.err_code", |
1549 | 14 | FT_UINT16, BASE_HEX|BASE_RANGE_STRING, RVALS(em_err_code), 0x0, |
1550 | 14 | NULL, HFILL } |
1551 | 14 | }, |
1552 | 14 | { &hf_canopen_em_err_reg, |
1553 | 14 | { "Error register", "canopen.em.err_reg", |
1554 | 14 | FT_UINT8, BASE_HEX, NULL, 0x0, |
1555 | 14 | NULL, HFILL } |
1556 | 14 | }, |
1557 | 14 | { &hf_canopen_em_err_reg_ge, |
1558 | 14 | { "Generic error", "canopen.em.err_reg_ge", |
1559 | 14 | FT_BOOLEAN, 8, NULL, 0x01, |
1560 | 14 | NULL, HFILL } |
1561 | 14 | }, |
1562 | 14 | { &hf_canopen_em_err_reg_cu, |
1563 | 14 | { "Current", "canopen.em.err_reg_cu", |
1564 | 14 | FT_BOOLEAN, 8, NULL, 0x02, |
1565 | 14 | NULL, HFILL } |
1566 | 14 | }, |
1567 | 14 | { &hf_canopen_em_err_reg_vo, |
1568 | 14 | { "Voltage", "canopen.em.err_reg_vo", |
1569 | 14 | FT_BOOLEAN, 8, NULL, 0x04, |
1570 | 14 | NULL, HFILL } |
1571 | 14 | }, |
1572 | 14 | { &hf_canopen_em_err_reg_te, |
1573 | 14 | { "Temperature", "canopen.em.err_reg_te", |
1574 | 14 | FT_BOOLEAN, 8, NULL, 0x08, |
1575 | 14 | NULL, HFILL } |
1576 | 14 | }, |
1577 | 14 | { &hf_canopen_em_err_reg_co, |
1578 | 14 | { "Communication error (overrun, error state)", "canopen.em.err_reg_co", |
1579 | 14 | FT_BOOLEAN, 8, NULL, 0x10, |
1580 | 14 | NULL, HFILL } |
1581 | 14 | }, |
1582 | 14 | { &hf_canopen_em_err_reg_de, |
1583 | 14 | { "Device profile specific", "canopen.em.err_reg_de", |
1584 | 14 | FT_BOOLEAN, 8, NULL, 0x20, |
1585 | 14 | NULL, HFILL } |
1586 | 14 | }, |
1587 | 14 | { &hf_canopen_em_err_reg_re, |
1588 | 14 | { "Reserved (must be false)", "canopen.em.err_reg_re", |
1589 | 14 | FT_BOOLEAN, 8, NULL, 0x40, |
1590 | 14 | NULL, HFILL } |
1591 | 14 | }, |
1592 | 14 | { &hf_canopen_em_err_reg_ma, |
1593 | 14 | { "Manufacturer specific", "canopen.em.err_reg_ma", |
1594 | 14 | FT_BOOLEAN, 8, NULL, 0x80, |
1595 | 14 | NULL, HFILL } |
1596 | 14 | }, |
1597 | 14 | { &hf_canopen_em_err_field, |
1598 | 14 | { "Manufacturer specific error field", "canopen.em.err_field", |
1599 | 14 | FT_BYTES, BASE_NONE, NULL, 0x0, |
1600 | 14 | NULL, HFILL } |
1601 | 14 | }, |
1602 | 14 | { &hf_canopen_nmt_ctrl_cs, |
1603 | 14 | { "Command specifier", "canopen.nmt_ctrl.cd", |
1604 | 14 | FT_UINT8, BASE_HEX, VALS(nmt_ctrl_cs), 0x0, |
1605 | 14 | NULL, HFILL } |
1606 | 14 | }, |
1607 | 14 | { &hf_canopen_nmt_ctrl_node_id, |
1608 | 14 | { "Node-ID", "canopen.nmt_ctrl.node_id", |
1609 | 14 | FT_UINT8, BASE_HEX, NULL, 0x0, |
1610 | 14 | NULL, HFILL } |
1611 | 14 | }, |
1612 | 14 | { &hf_canopen_nmt_guard_toggle, |
1613 | 14 | { "Reserved/Toggle", "canopen.nmt_guard.toggle", |
1614 | 14 | FT_UINT8, BASE_DEC, NULL, 0x80, |
1615 | 14 | NULL, HFILL } |
1616 | 14 | }, |
1617 | 14 | { &hf_canopen_nmt_guard_state, |
1618 | 14 | { "State", "canopen.nmt_guard.state", |
1619 | 14 | FT_UINT8, BASE_HEX, VALS(nmt_guard_state), 0x7F, |
1620 | 14 | NULL, HFILL } |
1621 | 14 | }, |
1622 | | /* SYNC */ |
1623 | 14 | { &hf_canopen_sync_counter, |
1624 | 14 | { "Counter", "canopen.sync.counter", |
1625 | 14 | FT_UINT8, BASE_DEC, NULL, 0x0, |
1626 | 14 | NULL, HFILL } |
1627 | 14 | }, |
1628 | | /* LSS */ |
1629 | 14 | { &hf_canopen_lss_cs, |
1630 | 14 | { "Command specifier", "canopen.lss.cs", |
1631 | 14 | FT_UINT8, BASE_HEX, VALS(lss_cs_code), 0x0, |
1632 | 14 | NULL, HFILL } |
1633 | 14 | }, |
1634 | 14 | { &hf_canopen_lss_addr_vendor, |
1635 | 14 | { "Vendor-ID", "canopen.lss.addr.vendor", |
1636 | 14 | FT_UINT32, BASE_HEX, NULL, 0x0, |
1637 | 14 | NULL, HFILL } |
1638 | 14 | }, |
1639 | 14 | { &hf_canopen_lss_addr_product, |
1640 | 14 | { "Product-code", "canopen.lss.addr.product", |
1641 | 14 | FT_UINT32, BASE_HEX, NULL, 0x0, |
1642 | 14 | NULL, HFILL } |
1643 | 14 | }, |
1644 | 14 | { &hf_canopen_lss_addr_revision, |
1645 | 14 | { "Revision-number", "canopen.lss.addr.revision", |
1646 | 14 | FT_UINT32, BASE_HEX, NULL, 0x0, |
1647 | 14 | NULL, HFILL } |
1648 | 14 | }, |
1649 | 14 | { &hf_canopen_lss_addr_revision_low, |
1650 | 14 | { "Revision-number (low)", "canopen.lss.addr.revision_low", |
1651 | 14 | FT_UINT32, BASE_HEX, NULL, 0x0, |
1652 | 14 | NULL, HFILL } |
1653 | 14 | }, |
1654 | 14 | { &hf_canopen_lss_addr_revision_high, |
1655 | 14 | { "Revision-number (high)", "canopen.lss.addr.revision_high", |
1656 | 14 | FT_UINT32, BASE_HEX, NULL, 0x0, |
1657 | 14 | NULL, HFILL } |
1658 | 14 | }, |
1659 | 14 | { &hf_canopen_lss_addr_serial, |
1660 | 14 | { "Serial-number", "canopen.lss.addr.serial", |
1661 | 14 | FT_UINT32, BASE_HEX, NULL, 0x0, |
1662 | 14 | NULL, HFILL } |
1663 | 14 | }, |
1664 | 14 | { &hf_canopen_lss_addr_serial_low, |
1665 | 14 | { "Serial-number (low)", "canopen.lss.addr.serial_low", |
1666 | 14 | FT_UINT32, BASE_HEX, NULL, 0x0, |
1667 | 14 | NULL, HFILL } |
1668 | 14 | }, |
1669 | 14 | { &hf_canopen_lss_addr_serial_high, |
1670 | 14 | { "Serial-number (high)", "canopen.lss.addr.serial_high", |
1671 | 14 | FT_UINT32, BASE_HEX, NULL, 0x0, |
1672 | 14 | NULL, HFILL } |
1673 | 14 | }, |
1674 | 14 | { &hf_canopen_lss_fastscan_id, |
1675 | 14 | { "IDNumber", "canopen.lss.fastscan.id", |
1676 | 14 | FT_UINT32, BASE_HEX, NULL, 0x0, |
1677 | 14 | NULL, HFILL } |
1678 | 14 | }, |
1679 | 14 | { &hf_canopen_lss_fastscan_check, |
1680 | 14 | { "Bit Check", "canopen.lss.fastscan.check", |
1681 | 14 | FT_UINT8, BASE_HEX, NULL, 0x0, |
1682 | 14 | NULL, HFILL } |
1683 | 14 | }, |
1684 | 14 | { &hf_canopen_lss_fastscan_sub, |
1685 | 14 | { "LSS Sub", "canopen.lss.fastscan.sub", |
1686 | 14 | FT_UINT8, BASE_HEX, VALS(lss_fastscan_subnext), 0x0, |
1687 | 14 | NULL, HFILL } |
1688 | 14 | }, |
1689 | 14 | { &hf_canopen_lss_fastscan_next, |
1690 | 14 | { "LSS Next", "canopen.lss.fastscan.next", |
1691 | 14 | FT_UINT8, BASE_HEX, VALS(lss_fastscan_subnext), 0x0, |
1692 | 14 | NULL, HFILL } |
1693 | 14 | }, |
1694 | 14 | { &hf_canopen_lss_switch_mode, |
1695 | 14 | { "Mode", "canopen.lss.switch.mode", |
1696 | 14 | FT_UINT8, BASE_HEX, VALS(lss_switch_mode), 0x0, |
1697 | 14 | NULL, HFILL } |
1698 | 14 | }, |
1699 | 14 | { &hf_canopen_lss_nid, |
1700 | 14 | { "NID", "canopen.lss.nid", |
1701 | 14 | FT_UINT8, BASE_HEX, NULL, 0x0, |
1702 | 14 | NULL, HFILL } |
1703 | 14 | }, |
1704 | 14 | { &hf_canopen_lss_conf_id_err_code, |
1705 | 14 | { "Error code", "canopen.lss.conf_id.err_code", |
1706 | 14 | FT_UINT8, BASE_HEX, VALS(lss_conf_id_err_code), 0x0, |
1707 | 14 | NULL, HFILL } |
1708 | 14 | }, |
1709 | 14 | { &hf_canopen_lss_conf_bt_err_code, |
1710 | 14 | { "Error code", "canopen.lss.conf_bt.err_code", |
1711 | 14 | FT_UINT8, BASE_HEX, VALS(lss_conf_bt_err_code), 0x0, |
1712 | 14 | NULL, HFILL } |
1713 | 14 | }, |
1714 | 14 | { &hf_canopen_lss_store_conf_err_code, |
1715 | 14 | { "Error code", "canopen.lss.store_conf.err_code", |
1716 | 14 | FT_UINT8, BASE_HEX, VALS(lss_store_conf_err_code), 0x0, |
1717 | 14 | NULL, HFILL } |
1718 | 14 | }, |
1719 | 14 | { &hf_canopen_lss_spec_err, |
1720 | 14 | { "Spec-error", "canopen.lss.spec_err", |
1721 | 14 | FT_UINT8, BASE_HEX, NULL, 0x0, |
1722 | 14 | NULL, HFILL } |
1723 | 14 | }, |
1724 | 14 | { &hf_canopen_lss_bt_tbl_selector, |
1725 | 14 | { "Table selector", "canopen.lss.bt.tbl_selector", |
1726 | 14 | FT_UINT8, BASE_HEX, NULL, 0x0, |
1727 | 14 | NULL, HFILL } |
1728 | 14 | }, |
1729 | 14 | { &hf_canopen_lss_bt_tbl_index, |
1730 | 14 | { "Table index", "canopen.lss.bt.tbl_index", |
1731 | 14 | FT_UINT8, BASE_HEX, VALS(bit_timing_tbl), 0x0, |
1732 | 14 | NULL, HFILL } |
1733 | 14 | }, |
1734 | 14 | { &hf_canopen_lss_abt_delay, |
1735 | 14 | { "Switch delay", "canopen.lss.abt_delay", |
1736 | 14 | FT_UINT16, BASE_DEC, NULL, 0x0, |
1737 | 14 | NULL, HFILL } |
1738 | 14 | }, |
1739 | | |
1740 | | |
1741 | 14 | { &hf_canopen_time_stamp, |
1742 | 14 | { "Time stamp", "canopen.time_stamp", |
1743 | 14 | FT_ABSOLUTE_TIME, ABSOLUTE_TIME_UTC, NULL, 0x0, |
1744 | 14 | NULL, HFILL } |
1745 | 14 | }, |
1746 | 14 | { &hf_canopen_time_stamp_ms, |
1747 | 14 | { "Time, after Midnight in Milliseconds", "canopen.time_stamp_ms", |
1748 | 14 | FT_UINT32, BASE_DEC, NULL, 0x0, |
1749 | 14 | NULL, HFILL } |
1750 | 14 | }, |
1751 | 14 | { &hf_canopen_time_stamp_days, |
1752 | 14 | { "Current day since 1 Jan 1984", "canopen.time_stamp_days", |
1753 | 14 | FT_UINT16, BASE_DEC, NULL, 0x0, |
1754 | 14 | NULL, HFILL } |
1755 | 14 | }, |
1756 | 14 | }; |
1757 | | |
1758 | 14 | static int *ett[] = { |
1759 | 14 | &ett_canopen, |
1760 | 14 | &ett_canopen_cob, |
1761 | 14 | &ett_canopen_type, |
1762 | 14 | &ett_canopen_sdo_cmd, |
1763 | 14 | &ett_canopen_em_er |
1764 | 14 | }; |
1765 | | |
1766 | 14 | proto_canopen = proto_register_protocol("CANopen", "CANOPEN", "canopen"); |
1767 | | |
1768 | 14 | proto_register_field_array(proto_canopen, hf, array_length(hf)); |
1769 | 14 | proto_register_subtree_array(ett, array_length(ett)); |
1770 | | |
1771 | 14 | canopen_handle = register_dissector("canopen", dissect_canopen, proto_canopen ); |
1772 | 14 | } |
1773 | | |
1774 | | void |
1775 | | proto_reg_handoff_canopen(void) |
1776 | 14 | { |
1777 | 14 | dissector_add_for_decode_as("can.subdissector", canopen_handle ); |
1778 | 14 | } |
1779 | | |
1780 | | /* |
1781 | | * Editor modelines - https://www.wireshark.org/tools/modelines.html |
1782 | | * |
1783 | | * Local variables: |
1784 | | * c-basic-offset: 4 |
1785 | | * tab-width: 8 |
1786 | | * indent-tabs-mode: nil |
1787 | | * End: |
1788 | | * |
1789 | | * vi: set shiftwidth=4 tabstop=8 expandtab: |
1790 | | * :indentSize=4:tabSize=8:noTabs=true: |
1791 | | */ |