Revert "TODO epan/dissectors/asn1/kerberos/packet-kerberos-template.c new GSS flags"
[wireshark-sm.git] / epan / dissectors / packet-canopen.c
blob74fd2fad68c4d81c2106865502bcf03765645cd9
1 /* packet-canopen.c
2 * Routines for CANopen dissection
3 * Copyright 2011, Yegor Yefremov <yegorslists@googlemail.com>
5 * Wireshark - Network traffic analyzer
6 * By Gerald Combs <gerald@wireshark.org>
7 * Copyright 1998 Gerald Combs
9 * SPDX-License-Identifier: GPL-2.0-or-later
12 #include "config.h"
14 #include <epan/packet.h>
16 #include "packet-socketcan.h"
18 void proto_register_canopen(void);
19 void proto_reg_handoff_canopen(void);
21 static dissector_handle_t canopen_handle;
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
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
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;
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
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
127 /* Initiate upload request (ccs=2) decode mask */
128 static int * const sdo_cmd_fields_ccs2[] = {
129 &hf_canopen_sdo_cmd_ccs,
130 NULL
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
138 /* */
139 static int * const sdo_cmd_fields_ccs4[] = {
140 &hf_canopen_sdo_cmd_ccs,
141 NULL
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
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
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
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
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,
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
188 static int * const *_sdo_cmd_fields_ccs6[] = {
189 sdo_cmd_fields_ccs6_subcommand0,
190 sdo_cmd_fields_ccs6_subcommand1
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
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
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
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
228 /* (scs=3) decode mask */
229 static int * const sdo_cmd_fields_scs3[] = {
230 &hf_canopen_sdo_cmd_scs,
231 NULL
233 /* (scs=4) decode mask */
234 static int * const sdo_cmd_fields_scs4[] = {
235 &hf_canopen_sdo_cmd_scs,
236 NULL
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
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
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
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
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
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,
283 static int * const *_sdo_cmd_fields_scs6[] = {
284 sdo_cmd_fields_scs6_subcommand0,
285 sdo_cmd_fields_scs6_subcommand1
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;
295 /* broadcast messages */
296 #define FC_NMT 0x0
297 #define FC_SYNC 0x1
298 #define FC_TIME_STAMP 0x2
300 /* point-to-point messages */
301 #define FC_EMERGENCY 0x1
302 #define FC_PDO1_TX 0x3
303 #define FC_PDO1_RX 0x4
304 #define FC_PDO2_TX 0x5
305 #define FC_PDO2_RX 0x6
306 #define FC_PDO3_TX 0x7
307 #define FC_PDO3_RX 0x8
308 #define FC_PDO4_TX 0x9
309 #define FC_PDO4_RX 0xA
310 #define FC_DEFAULT_SDO_TX 0xB
311 #define FC_DEFAULT_SDO_RX 0xC
312 #define FC_NMT_ERR_CONTROL 0xE
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}
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}
337 /* message types */
338 #define MT_UNKNOWN 0
339 #define MT_NMT_CTRL 1
340 #define MT_SYNC 2
341 #define MT_TIME_STAMP 3
342 #define MT_EMERGENCY 4
343 #define MT_PDO 5
344 #define MT_SDO 6
345 #define MT_NMT_ERR_CTRL 7
346 #define MT_LSS_MASTER 10
347 #define MT_LSS_SLAVE 11
349 /* TIME STAMP conversion defines */
350 #define TS_DAYS_BETWEEN_1970_AND_1984 5113
351 #define TS_SECONDS_IN_PER_DAY 86400
352 #define TS_NANOSEC_PER_MSEC 1000000
354 /* SDO command specifier */
355 #define SDO_CCS_DOWN_SEG_REQ 0
356 #define SDO_CCS_INIT_DOWN_REQ 1
357 #define SDO_CCS_INIT_UP_REQ 2
358 #define SDO_CCS_UP_SEQ_REQ 3
359 #define SDO_CCS_BLOCK_UP 5
360 #define SDO_CCS_BLOCK_DOWN 6
362 #define SDO_SCS_UP_SEQ_RESP 0
363 #define SDO_SCS_DOWN_SEG_RESP 1
364 #define SDO_SCS_INIT_UP_RESP 2
365 #define SDO_SCS_INIT_DOWN_RESP 3
366 #define SDO_SCS_BLOCK_DOWN 5
367 #define SDO_SCS_BLOCK_UP 6
369 #define SDO_CS_ABORT_TRANSFER 4
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}
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}
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}
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}
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}
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}
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}
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}
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}
586 /* LSS COB-IDs */
587 #define LSS_MASTER_CAN_ID 0x7E5
588 #define LSS_SLAVE_CAN_ID 0x7E4
590 /* LSS Switch state services */
591 #define LSS_CS_SWITCH_GLOBAL 0x04
592 #define LSS_CS_SWITCH_SELECTIVE_VENDOR 0x40
593 #define LSS_CS_SWITCH_SELECTIVE_PRODUCT 0x41
594 #define LSS_CS_SWITCH_SELECTIVE_REVISION 0x42
595 #define LSS_CS_SWITCH_SELECTIVE_SERIAL 0x43
596 #define LSS_CS_SWITCH_SELECTIVE_RESP 0x44
597 /* LSS Configuration services */
598 #define LSS_CS_CONF_NODE_ID 0x11
599 #define LSS_CS_CONF_BIT_TIMING 0x13
600 #define LSS_CS_CONF_ACT_BIT_TIMING 0x15
601 #define LSS_CS_CONF_STORE 0x17
602 /* LSS Inquire services */
603 #define LSS_CS_INQ_VENDOR_ID 0x5A
604 #define LSS_CS_INQ_PRODUCT_CODE 0x5B
605 #define LSS_CS_INQ_REV_NUMBER 0x5C
606 #define LSS_CS_INQ_SERIAL_NUMBER 0x5D
607 #define LSS_CS_INQ_NODE_ID 0x5E
608 /* LSS Identification services */
609 #define LSS_CS_IDENT_REMOTE_VENDOR 0x46
610 #define LSS_CS_IDENT_REMOTE_PRODUCT 0x47
611 #define LSS_CS_IDENT_REMOTE_REV_LOW 0x48
612 #define LSS_CS_IDENT_REMOTE_REV_HIGH 0x49
613 #define LSS_CS_IDENT_REMOTE_SERIAL_LOW 0x4A
614 #define LSS_CS_IDENT_REMOTE_SERIAL_HIGH 0x4B
615 #define LSS_CS_IDENT_REMOTE_NON_CONF 0x4C
616 #define LSS_CS_IDENT_SLAVE 0x4F
617 #define LSS_CS_IDENT_NON_CONF_SLAVE 0x50
618 #define LSS_CS_IDENT_FASTSCAN 0x51
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}
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}
659 static const value_string lss_switch_mode[] = {
660 { 0x0, "Waiting state"},
661 { 0x1, "Configuration state"},
662 { 0, NULL}
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}
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}
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}
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}
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}
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}
721 static unsigned
722 canopen_detect_msg_type(unsigned function_code, unsigned node_id)
724 switch (function_code) {
725 case FC_NMT:
726 return MT_NMT_CTRL;
727 case FC_SYNC:
728 if (node_id == 0) {
729 return MT_SYNC;
730 } else {
731 return MT_EMERGENCY;
733 break;
734 case FC_TIME_STAMP:
735 return MT_TIME_STAMP;
736 case FC_PDO1_TX:
737 return MT_PDO;
738 case FC_PDO1_RX:
739 return MT_PDO;
740 case FC_PDO2_TX:
741 return MT_PDO;
742 case FC_PDO2_RX:
743 return MT_PDO;
744 case FC_PDO3_TX:
745 return MT_PDO;
746 case FC_PDO3_RX:
747 return MT_PDO;
748 case FC_PDO4_TX:
749 return MT_PDO;
750 case FC_PDO4_RX:
751 return MT_PDO;
752 case FC_DEFAULT_SDO_TX:
753 return MT_SDO;
754 case FC_DEFAULT_SDO_RX:
755 return MT_SDO;
756 case FC_NMT_ERR_CONTROL:
757 return MT_NMT_ERR_CTRL;
758 case LSS_MASTER_CAN_ID >> 7:
759 if (node_id == (LSS_MASTER_CAN_ID & 0x7F)) {
760 return MT_LSS_MASTER;
761 } else if (node_id == (LSS_SLAVE_CAN_ID & 0x7F)) {
762 return MT_LSS_SLAVE;
764 return MT_UNKNOWN;
765 default:
766 return MT_UNKNOWN;
771 static inline int * const *
772 sdo_cmd_fields_scs(unsigned cs, unsigned subcommand)
774 if (cs < array_length(_sdo_cmd_fields_scs))
775 return _sdo_cmd_fields_scs[cs];
776 else if(cs == SDO_SCS_BLOCK_DOWN && subcommand < array_length(_sdo_cmd_fields_scs5))
777 return _sdo_cmd_fields_scs5[subcommand];
778 else if(cs == SDO_SCS_BLOCK_UP && subcommand < array_length(_sdo_cmd_fields_scs6))
779 return _sdo_cmd_fields_scs6[subcommand];
780 return NULL;
783 static inline int * const *
784 sdo_cmd_fields_ccs(unsigned cs, unsigned subcommand)
786 if (cs < array_length(_sdo_cmd_fields_ccs))
787 return _sdo_cmd_fields_ccs[cs];
788 else if (cs == SDO_CCS_BLOCK_UP && subcommand < array_length(_sdo_cmd_fields_ccs5))
789 return _sdo_cmd_fields_ccs5[subcommand];
790 else if (cs == SDO_CCS_BLOCK_DOWN && subcommand < array_length(_sdo_cmd_fields_ccs6))
791 return _sdo_cmd_fields_ccs6[subcommand];
792 return NULL;
795 static void
796 dissect_sdo(tvbuff_t *tvb, packet_info *pinfo, proto_tree *canopen_type_tree, unsigned function_code)
798 int offset = 0;
799 /*number of data bytes*/
800 uint8_t sdo_data = 0;
801 /*Field existence*/
802 uint8_t sdo_mux = 0, sdo_pst = 0;
803 /*sdo values used to choose dissector*/
804 uint8_t sdo_cs = 0, sdo_subcommand = 0;
805 int * const *sdo_cmd_fields;
807 /* get SDO command specifier */
808 sdo_cs = tvb_get_bits8(tvb, 0, 3);
810 if (function_code == FC_DEFAULT_SDO_RX) {
811 col_append_fstr(pinfo->cinfo, COL_INFO,
812 ": %s", val_to_str(sdo_cs, sdo_ccs,
813 "Unknown (0x%x)"));
815 switch (sdo_cs) {
816 case SDO_CCS_DOWN_SEG_REQ:
817 sdo_mux = 0;
818 sdo_data = 7;
819 break;
820 case SDO_CCS_INIT_DOWN_REQ:
821 sdo_mux = 1;
822 sdo_data = 4;
823 break;
824 case SDO_CCS_INIT_UP_REQ:
825 sdo_mux = 1;
826 sdo_data = 0;
827 break;
828 case SDO_CCS_UP_SEQ_REQ:
829 sdo_mux = 0;
830 sdo_data = 0;
831 break;
832 case SDO_CS_ABORT_TRANSFER:
833 sdo_mux = 1;
834 sdo_data = 4;
835 break;
836 case SDO_CCS_BLOCK_UP:
837 sdo_subcommand = tvb_get_bits8(tvb, 6, 2);
838 if(sdo_subcommand == 0)
840 sdo_mux = 1;
841 /*only the client sends pst*/
842 sdo_pst = 1;
844 /*check unused field is empty, otherwise it could be a data block segment
845 (TODO: add segment decoding)*/
846 if(tvb_get_bits8(tvb, 3, 3) != 0)
847 return;
848 break;
849 case SDO_CCS_BLOCK_DOWN:
850 sdo_subcommand = tvb_get_bits8(tvb, 7, 1);
851 if(sdo_subcommand == 0)
853 sdo_mux = 1;
854 sdo_data = 4;
855 /*check unused field is empty, otherwise it could be a data block segment
856 (TODO: add segment decoding)*/
857 if(tvb_get_bits8(tvb, 3, 3) != 0)
858 return;
860 else
862 sdo_data = 2;
863 /*check unused field is empty, otherwise it could be a data block segment
864 (TODO: add segment decoding)*/
865 if(tvb_get_bits8(tvb, 6, 1) != 0)
866 return;
868 break;
869 default:
870 return;
873 sdo_cmd_fields = sdo_cmd_fields_ccs(sdo_cs,sdo_subcommand);
875 } else {
876 col_append_fstr(pinfo->cinfo, COL_INFO,
877 ": %s", val_to_str(sdo_cs, sdo_scs,
878 "Unknown (0x%x)"));
880 switch (sdo_cs) {
881 case SDO_SCS_UP_SEQ_RESP:
882 sdo_mux = 0;
883 sdo_data = 7;
884 break;
885 case SDO_SCS_DOWN_SEG_RESP:
886 sdo_mux = 0;
887 sdo_data = 0;
888 break;
889 case SDO_SCS_INIT_UP_RESP:
890 sdo_mux = 1;
891 sdo_data = 4;
892 break;
893 case SDO_SCS_INIT_DOWN_RESP:
894 sdo_mux = 1;
895 sdo_data = 0;
896 break;
897 case SDO_CS_ABORT_TRANSFER:
898 sdo_mux = 1;
899 sdo_data = 4;
900 break;
901 case SDO_SCS_BLOCK_DOWN:
902 sdo_subcommand = tvb_get_bits8(tvb, 6, 2);
903 if(sdo_subcommand == 0)
905 sdo_mux = 1;
907 /*check unused field is empty, otherwise it could be a data block segment
908 (TODO: add segment decoding)*/
909 if(tvb_get_bits8(tvb, 3, 3) != 0)
910 return;
911 break;
912 case SDO_SCS_BLOCK_UP:
913 sdo_subcommand = tvb_get_bits8(tvb, 7, 1);
914 if(sdo_subcommand == 0)
916 sdo_mux = 1;
917 sdo_data = 4;
918 /*check unused field is empty, otherwise it could be a data block segment
919 (TODO: add segment decoding)*/
920 if(tvb_get_bits8(tvb, 3, 3) != 0)
921 return;
923 else
925 sdo_data = 2;
926 /*check unused field is empty, otherwise it could be a data block segment
927 (TODO: add segment decoding)*/
928 if(tvb_get_bits8(tvb, 6, 1) != 0)
929 return;
931 break;
932 default:
933 return;
936 sdo_cmd_fields = sdo_cmd_fields_scs(sdo_cs,sdo_subcommand);
939 if (sdo_cmd_fields == NULL) {
940 proto_tree_add_item(canopen_type_tree, hf_canopen_sdo_cmd, tvb, 0, 1, ENC_LITTLE_ENDIAN);
941 /* XXX Add expert info */
942 return;
945 proto_tree_add_bitmask(canopen_type_tree, tvb, offset,
946 hf_canopen_sdo_cmd, ett_canopen_sdo_cmd, sdo_cmd_fields, ENC_LITTLE_ENDIAN);
948 offset++;
950 if (sdo_mux) {
951 /* decode mux */
952 proto_tree_add_item(canopen_type_tree,
953 hf_canopen_sdo_main_idx, tvb, offset, 2, ENC_LITTLE_ENDIAN);
954 offset += 2;
956 proto_tree_add_item(canopen_type_tree,
957 hf_canopen_sdo_sub_idx, tvb, offset, 1, ENC_LITTLE_ENDIAN);
958 offset++;
961 if (sdo_cs == SDO_CS_ABORT_TRANSFER) {
962 /* SDO abort transfer */
963 proto_tree_add_item(canopen_type_tree,
964 hf_canopen_sdo_abort_code, tvb, offset, 4, ENC_LITTLE_ENDIAN);
965 return;
968 if (sdo_cs == 5) {
969 /*SDO_SCS_BLOCK_DOWN or SDO_CCS_BLOCK_UP*/
970 if(sdo_subcommand == 2)
972 /*decode ackseq byte)*/
973 proto_tree_add_item(canopen_type_tree,
974 hf_canopen_sdo_cmd_block_ackseq, tvb, offset, 1, ENC_LITTLE_ENDIAN);
975 offset++;
978 if(sdo_subcommand == 0 || sdo_subcommand == 2)
980 /*decode blksize byte)*/
981 proto_tree_add_item(canopen_type_tree,
982 hf_canopen_sdo_cmd_block_blksize, tvb, offset, 1, ENC_LITTLE_ENDIAN);
983 offset++;
987 if (sdo_pst) {
988 /*decode pst byte)*/
989 proto_tree_add_item(canopen_type_tree,
990 hf_canopen_sdo_cmd_block_pst, tvb, offset, 1, ENC_LITTLE_ENDIAN);
991 offset++;
994 if (sdo_data) {
995 proto_tree_add_item(canopen_type_tree,
996 hf_canopen_sdo_data, tvb, offset, sdo_data, ENC_NA);
997 offset += sdo_data;
1000 if(offset < 8)
1002 /* Reserved */
1003 proto_tree_add_item(canopen_type_tree,
1004 hf_canopen_reserved, tvb, offset, 8 - offset, ENC_NA);
1008 static void
1009 dissect_lss(tvbuff_t *tvb, packet_info *pinfo, proto_tree *canopen_type_tree, unsigned msg_type_id)
1011 int offset = 0;
1012 int reserved = 0;
1013 uint8_t lss_cs;
1014 uint8_t lss_bc_mask;
1015 uint16_t lss_abt_delay;
1017 proto_tree_add_item(canopen_type_tree,
1018 hf_canopen_lss_cs, tvb, offset, 1, ENC_LITTLE_ENDIAN);
1020 /* LSS command specifier */
1021 lss_cs = tvb_get_uint8(tvb, offset);
1022 col_append_fstr(pinfo->cinfo, COL_INFO, ": %s", val_to_str(lss_cs, lss_cs_code, "Unknown (0x%x)"));
1023 offset++;
1025 if (msg_type_id == MT_LSS_MASTER) {
1027 /* Master commands */
1028 switch (lss_cs) {
1029 case LSS_CS_SWITCH_GLOBAL:
1030 col_append_fstr(pinfo->cinfo, COL_INFO,
1031 ": %s", val_to_str(tvb_get_uint8(tvb, offset), lss_switch_mode, "Unknown (0x%x)"));
1033 proto_tree_add_item(canopen_type_tree,
1034 hf_canopen_lss_switch_mode, tvb, offset, 1, ENC_LITTLE_ENDIAN);
1035 offset++;
1036 reserved = 6;
1037 break;
1038 case LSS_CS_SWITCH_SELECTIVE_VENDOR:
1039 proto_tree_add_item(canopen_type_tree,
1040 hf_canopen_lss_addr_vendor, tvb, offset, 4, ENC_LITTLE_ENDIAN);
1041 offset += 4;
1042 reserved = 3;
1043 break;
1044 case LSS_CS_SWITCH_SELECTIVE_PRODUCT:
1045 proto_tree_add_item(canopen_type_tree,
1046 hf_canopen_lss_addr_product, tvb, offset, 4, ENC_LITTLE_ENDIAN);
1047 offset += 4;
1048 reserved = 3;
1049 break;
1050 case LSS_CS_SWITCH_SELECTIVE_REVISION:
1051 proto_tree_add_item(canopen_type_tree,
1052 hf_canopen_lss_addr_revision, tvb, offset, 4, ENC_LITTLE_ENDIAN);
1053 offset += 4;
1054 reserved = 3;
1055 break;
1056 case LSS_CS_SWITCH_SELECTIVE_SERIAL:
1057 proto_tree_add_item(canopen_type_tree,
1058 hf_canopen_lss_addr_serial, tvb, offset, 4, ENC_LITTLE_ENDIAN);
1059 offset += 4;
1060 reserved = 3;
1061 break;
1062 case LSS_CS_CONF_NODE_ID:
1063 col_append_fstr(pinfo->cinfo, COL_INFO, ": 0x%02x", tvb_get_uint8(tvb, offset));
1065 proto_tree_add_item(canopen_type_tree,
1066 hf_canopen_lss_nid, tvb, offset, 1, ENC_LITTLE_ENDIAN);
1067 offset++;
1068 reserved = 6;
1069 break;
1070 case LSS_CS_CONF_BIT_TIMING:
1071 proto_tree_add_item(canopen_type_tree,
1072 hf_canopen_lss_bt_tbl_selector, tvb, offset, 1, ENC_LITTLE_ENDIAN);
1073 offset++;
1075 /* XXX Note that current dissector only works for table selector 0x00 (CiA 301 Table 1) */
1076 col_append_fstr(pinfo->cinfo, COL_INFO,
1077 ": %s", val_to_str(tvb_get_uint8(tvb, offset), bit_timing_tbl, "Unknown (0x%x)"));
1078 proto_tree_add_item(canopen_type_tree,
1079 hf_canopen_lss_bt_tbl_index, tvb, offset, 1, ENC_LITTLE_ENDIAN);
1080 offset++;
1081 reserved = 5;
1082 break;
1083 case LSS_CS_CONF_ACT_BIT_TIMING:
1084 lss_abt_delay = tvb_get_letohl(tvb, offset);
1086 col_append_fstr(pinfo->cinfo, COL_INFO, ": %d ms", lss_abt_delay);
1088 proto_tree_add_uint_format_value(canopen_type_tree,
1089 hf_canopen_lss_abt_delay, tvb, offset, 2, lss_abt_delay,
1090 "%d ms (0x%02x)", lss_abt_delay, lss_abt_delay);
1093 offset += 2;
1094 reserved = 5;
1095 break;
1096 case LSS_CS_CONF_STORE:
1097 case LSS_CS_INQ_VENDOR_ID:
1098 case LSS_CS_INQ_PRODUCT_CODE:
1099 case LSS_CS_INQ_REV_NUMBER:
1100 case LSS_CS_INQ_SERIAL_NUMBER:
1101 case LSS_CS_INQ_NODE_ID:
1102 reserved = 7;
1103 break;
1104 case LSS_CS_IDENT_REMOTE_VENDOR:
1105 case LSS_CS_IDENT_REMOTE_PRODUCT:
1106 case LSS_CS_IDENT_REMOTE_REV_LOW:
1107 case LSS_CS_IDENT_REMOTE_REV_HIGH:
1108 case LSS_CS_IDENT_REMOTE_SERIAL_LOW:
1109 case LSS_CS_IDENT_REMOTE_SERIAL_HIGH:
1110 col_append_fstr(pinfo->cinfo, COL_INFO, ", %s 0x%08x",
1111 val_to_str_const(lss_cs, lss_id_remote_slave, "(Unknown)"), tvb_get_letohl(tvb, offset));
1113 proto_tree_add_item(canopen_type_tree,
1114 *hf_canopen_lss_addr_ident[lss_cs - LSS_CS_IDENT_REMOTE_VENDOR], tvb, offset, 4, ENC_LITTLE_ENDIAN);
1115 offset += 4;
1116 reserved = 3;
1117 break;
1118 case LSS_CS_IDENT_REMOTE_NON_CONF:
1119 reserved = 7;
1120 break;
1121 case LSS_CS_IDENT_FASTSCAN:
1122 proto_tree_add_item(canopen_type_tree,
1123 hf_canopen_lss_fastscan_id, tvb, offset, 4, ENC_LITTLE_ENDIAN);
1124 offset += 4;
1125 lss_bc_mask = tvb_get_uint8(tvb, offset);
1126 if (lss_bc_mask == 0x80) {
1127 proto_tree_add_uint_format_value(canopen_type_tree,
1128 hf_canopen_lss_fastscan_check, tvb, offset, 1, lss_bc_mask,
1129 "All LSS slaves (0x%02x)", lss_bc_mask);
1130 } else if (lss_bc_mask < 32) {
1131 proto_tree_add_uint_format_value(canopen_type_tree,
1132 hf_canopen_lss_fastscan_check, tvb, offset, 1,
1133 lss_bc_mask, "0x%x (0x%02x)",
1134 ~((1 << lss_bc_mask) - 1),
1135 lss_bc_mask);
1136 } else {
1137 proto_tree_add_uint_format_value(canopen_type_tree,
1138 hf_canopen_lss_fastscan_check, tvb, offset, 1, lss_bc_mask,
1139 "Reserved (0x%02x)", lss_bc_mask);
1141 offset++;
1142 proto_tree_add_item(canopen_type_tree,
1143 hf_canopen_lss_fastscan_sub, tvb, offset, 1, ENC_LITTLE_ENDIAN);
1144 offset++;
1145 proto_tree_add_item(canopen_type_tree,
1146 hf_canopen_lss_fastscan_next, tvb, offset, 1, ENC_LITTLE_ENDIAN);
1147 break;
1148 default: /* invalid command specifier */
1149 return;
1152 } else {
1154 /* Slave commands */
1155 switch (lss_cs) {
1156 case LSS_CS_SWITCH_SELECTIVE_RESP:
1157 reserved = 7;
1158 break;
1159 case LSS_CS_CONF_NODE_ID:
1160 proto_tree_add_item(canopen_type_tree,
1161 hf_canopen_lss_conf_id_err_code, tvb, offset, 1, ENC_LITTLE_ENDIAN);
1162 offset++;
1163 proto_tree_add_item(canopen_type_tree,
1164 hf_canopen_lss_spec_err, tvb, offset, 1, ENC_LITTLE_ENDIAN);
1165 offset++;
1166 reserved = 5;
1167 break;
1168 case LSS_CS_CONF_BIT_TIMING:
1169 proto_tree_add_item(canopen_type_tree,
1170 hf_canopen_lss_conf_bt_err_code, tvb, offset, 1, ENC_LITTLE_ENDIAN);
1172 offset++;
1173 proto_tree_add_item(canopen_type_tree,
1174 hf_canopen_lss_spec_err, tvb, offset, 1, ENC_LITTLE_ENDIAN);
1176 offset++;
1177 reserved = 5;
1178 break;
1179 case LSS_CS_CONF_STORE:
1180 proto_tree_add_item(canopen_type_tree,
1181 hf_canopen_lss_store_conf_err_code, tvb, offset, 1, ENC_LITTLE_ENDIAN);
1182 offset++;
1183 proto_tree_add_item(canopen_type_tree,
1184 hf_canopen_lss_spec_err, tvb, offset, 1, ENC_LITTLE_ENDIAN);
1185 offset++;
1186 reserved = 5;
1187 break;
1188 case LSS_CS_INQ_VENDOR_ID:
1189 case LSS_CS_INQ_PRODUCT_CODE:
1190 case LSS_CS_INQ_REV_NUMBER:
1191 case LSS_CS_INQ_SERIAL_NUMBER:
1192 col_append_fstr(pinfo->cinfo, COL_INFO,
1193 ", %s 0x%08x", val_to_str_const(lss_cs, lss_inquire_id, "(Unknown)"), tvb_get_letohl(tvb, offset));
1195 proto_tree_add_item(canopen_type_tree,
1196 *hf_canopen_lss_addr_inquire[lss_cs - LSS_CS_INQ_VENDOR_ID], tvb, offset, 4, ENC_LITTLE_ENDIAN);
1197 offset += 4;
1198 reserved = 3;
1199 break;
1200 case LSS_CS_INQ_NODE_ID:
1201 col_append_fstr(pinfo->cinfo, COL_INFO,
1202 ", %s 0x%08x", val_to_str_const(lss_cs, lss_inquire_id, "(Unknown)"), tvb_get_letohl(tvb, offset));
1204 proto_tree_add_item(canopen_type_tree,
1205 hf_canopen_lss_nid, tvb, offset, 1, ENC_LITTLE_ENDIAN);
1206 offset++;
1207 reserved = 6;
1208 break;
1209 case LSS_CS_IDENT_SLAVE:
1210 reserved = 7;
1211 break;
1212 case LSS_CS_IDENT_NON_CONF_SLAVE:
1213 reserved = 7;
1214 break;
1215 default: /* invalid command specifier */
1216 return;
1221 if (reserved) {
1222 proto_tree_add_item(canopen_type_tree,
1223 hf_canopen_reserved, tvb, offset, reserved, ENC_NA);
1228 /* Code to actually dissect the packets */
1229 static int
1230 dissect_canopen(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data)
1232 unsigned function_code;
1233 unsigned node_id;
1234 uint32_t time_stamp_msec;
1235 uint32_t time_stamp_days;
1236 struct can_info can_info;
1237 unsigned msg_type_id;
1238 nstime_t time_stamp;
1239 int can_data_len = tvb_reported_length(tvb);
1240 const char *function_code_str;
1241 int offset = 0;
1242 uint8_t nmt_node_id;
1244 proto_item *ti, *cob_ti;
1245 proto_tree *canopen_tree;
1246 proto_tree *canopen_cob_tree;
1247 proto_tree *canopen_type_tree;
1249 DISSECTOR_ASSERT(data);
1250 can_info = *((struct can_info*)data);
1252 if (can_info.id & (CAN_ERR_FLAG | CAN_RTR_FLAG | CAN_EFF_FLAG))
1254 /* Error, RTR and frames with extended ids are not for us. */
1255 return 0;
1258 col_set_str(pinfo->cinfo, COL_PROTOCOL, "CANopen");
1259 col_clear(pinfo->cinfo, COL_INFO);
1261 node_id = can_info.id & 0x7F;
1262 function_code = (can_info.id >> 7) & 0x0F;
1264 msg_type_id = canopen_detect_msg_type(function_code, node_id);
1266 if (msg_type_id == MT_LSS_MASTER) {
1267 function_code_str = "LSS (Master)";
1268 col_add_str(pinfo->cinfo, COL_INFO, function_code_str);
1269 } else if (msg_type_id == MT_LSS_SLAVE) {
1270 function_code_str = "LSS (Slave)";
1271 col_add_str(pinfo->cinfo, COL_INFO, function_code_str);
1272 } else {
1274 if (node_id == 0 ) {
1275 /* broadcast */
1276 function_code_str = val_to_str(function_code, CAN_open_bcast_msg_type_vals, "Unknown (%u)");
1277 col_add_str(pinfo->cinfo, COL_INFO, function_code_str);
1278 } else {
1279 /* point-to-point */
1280 function_code_str = val_to_str(function_code, CAN_open_p2p_msg_type_vals, "Unknown (%u)");
1281 col_add_str(pinfo->cinfo, COL_INFO, function_code_str);
1285 ti = proto_tree_add_item(tree, proto_canopen, tvb, 0, tvb_reported_length(tvb), ENC_NA);
1286 canopen_tree = proto_item_add_subtree(ti, ett_canopen);
1288 /* add COB-ID with function code and node id */
1289 cob_ti = proto_tree_add_uint(canopen_tree, hf_canopen_cob_id, tvb, 0, 0, can_info.id);
1290 canopen_cob_tree = proto_item_add_subtree(cob_ti, ett_canopen_cob);
1292 /* add function code */
1293 ti = proto_tree_add_uint(canopen_cob_tree, hf_canopen_function_code, tvb, 0, 0, can_info.id);
1294 proto_item_set_generated(ti);
1296 /* add node id */
1297 ti = proto_tree_add_uint(canopen_cob_tree, hf_canopen_node_id, tvb, 0, 0, can_info.id);
1298 proto_item_set_generated(ti);
1300 /* add CANopen frame type */
1302 canopen_type_tree = proto_tree_add_subtree_format(canopen_tree, tvb, 0,
1303 tvb_reported_length(tvb),
1304 ett_canopen_type, NULL, "Type: %s", function_code_str);
1305 switch(msg_type_id)
1307 case MT_NMT_CTRL:
1308 col_append_fstr(pinfo->cinfo, COL_INFO, ": %s", val_to_str(tvb_get_uint8(tvb, offset), nmt_ctrl_cs, "Unknown (0x%x)"));
1310 proto_tree_add_item(canopen_type_tree,
1311 hf_canopen_nmt_ctrl_cs, tvb, offset, 1, ENC_LITTLE_ENDIAN);
1312 offset++;
1314 nmt_node_id = tvb_get_uint8(tvb, offset);
1315 if (nmt_node_id == 0x00) {
1316 col_append_str(pinfo->cinfo, COL_INFO, " [All]");
1317 } else {
1318 col_append_fstr(pinfo->cinfo, COL_INFO, " [0x%x]", nmt_node_id);
1321 proto_tree_add_item(canopen_type_tree,
1322 hf_canopen_nmt_ctrl_node_id, tvb, offset, 1, ENC_LITTLE_ENDIAN);
1323 break;
1324 case MT_NMT_ERR_CTRL:
1325 if (tvb_reported_length(tvb) > 0) {
1326 col_append_fstr(pinfo->cinfo, COL_INFO, ": %s", val_to_str_const(tvb_get_bits8(tvb, 1, 7), nmt_guard_state, "(Unknown)"));
1328 proto_tree_add_item(canopen_type_tree,
1329 hf_canopen_nmt_guard_toggle, tvb, offset, 1, ENC_LITTLE_ENDIAN);
1330 proto_tree_add_item(canopen_type_tree,
1331 hf_canopen_nmt_guard_state, tvb, offset, 1, ENC_LITTLE_ENDIAN);
1334 col_append_fstr(pinfo->cinfo, COL_INFO, " [0x%x]", node_id);
1335 break;
1336 case MT_SYNC:
1337 /* Show optional counter parameter if present */
1338 if (tvb_reported_length(tvb) > 0) {
1339 col_append_fstr(pinfo->cinfo, COL_INFO, " [%d]", tvb_get_uint8(tvb, offset));
1341 proto_tree_add_item(canopen_type_tree,
1342 hf_canopen_sync_counter, tvb, offset, 1, ENC_LITTLE_ENDIAN);
1344 break;
1345 case MT_TIME_STAMP:
1346 /* calculate the real time stamp */
1347 time_stamp_msec = tvb_get_letohl(tvb, offset);
1348 time_stamp_days = tvb_get_letohs(tvb, offset + 4);
1349 time_stamp.secs = (time_stamp_days + TS_DAYS_BETWEEN_1970_AND_1984)
1350 * TS_SECONDS_IN_PER_DAY + (time_stamp_msec / 1000);
1351 time_stamp.nsecs = (time_stamp_msec % 1000) * TS_NANOSEC_PER_MSEC;
1353 proto_tree_add_time(canopen_type_tree,
1354 hf_canopen_time_stamp, tvb, offset, 6, &time_stamp);
1356 proto_tree_add_uint(canopen_type_tree,
1357 hf_canopen_time_stamp_ms, tvb, offset, 4, time_stamp_msec);
1358 offset += 4;
1360 proto_tree_add_uint(canopen_type_tree,
1361 hf_canopen_time_stamp_days, tvb, offset, 2, time_stamp_days);
1363 break;
1364 case MT_EMERGENCY:
1365 proto_tree_add_item(canopen_type_tree,
1366 hf_canopen_em_err_code, tvb, offset, 2, ENC_LITTLE_ENDIAN);
1367 offset += 2;
1369 proto_tree_add_bitmask(canopen_type_tree, tvb, offset,
1370 hf_canopen_em_err_reg, ett_canopen_em_er, em_err_reg_fields, ENC_LITTLE_ENDIAN);
1371 offset++;
1373 proto_tree_add_item(canopen_type_tree,
1374 hf_canopen_em_err_field, tvb, offset, 5, ENC_NA);
1375 break;
1376 case MT_PDO:
1377 if (can_data_len != 0) {
1378 proto_tree_add_item(canopen_type_tree,
1379 hf_canopen_pdo_data, tvb, offset, can_data_len, ENC_NA);
1381 else {
1382 proto_tree_add_string(canopen_type_tree,
1383 hf_canopen_pdo_data_string, tvb, offset, 0, "empty");
1385 break;
1386 case MT_SDO:
1388 dissect_sdo(tvb, pinfo, canopen_type_tree, function_code);
1390 break;
1391 case MT_LSS_MASTER:
1392 case MT_LSS_SLAVE:
1394 dissect_lss(tvb, pinfo, canopen_type_tree, msg_type_id);
1396 break;
1399 return tvb_reported_length(tvb);
1403 /* Register the protocol with Wireshark */
1404 void
1405 proto_register_canopen(void)
1407 static hf_register_info hf[] = {
1408 /* COB-ID */
1409 { &hf_canopen_cob_id,
1410 { "COB-ID", "canopen.cob_id",
1411 FT_UINT32, BASE_HEX, NULL, 0x0,
1412 NULL, HFILL }
1414 { &hf_canopen_function_code,
1415 { "Function code", "canopen.function_code",
1416 FT_UINT32, BASE_HEX, NULL, 0x00000780,
1417 NULL, HFILL }
1419 { &hf_canopen_node_id,
1420 { "Node-ID", "canopen.node_id",
1421 FT_UINT32, BASE_HEX, NULL, 0x7F,
1422 NULL, HFILL }
1424 { &hf_canopen_pdo_data,
1425 { "Data", "canopen.pdo.data.bytes",
1426 FT_BYTES, BASE_NONE, NULL, 0x0,
1427 NULL, HFILL }
1429 { &hf_canopen_pdo_data_string,
1430 { "Data", "canopen.pdo.data.string",
1431 FT_STRINGZ, BASE_NONE, NULL, 0x0,
1432 NULL, HFILL }
1434 /* SDO */
1435 { &hf_canopen_sdo_cmd,
1436 { "SDO command byte", "canopen.sdo.cmd",
1437 FT_UINT8, BASE_HEX, NULL, 0x0,
1438 NULL, HFILL }
1440 { &hf_canopen_sdo_cmd_ccs,
1441 { "Client command specifier", "canopen.sdo.ccs",
1442 FT_UINT8, BASE_DEC, VALS(sdo_ccs), 0xE0,
1443 NULL, HFILL }
1445 { &hf_canopen_sdo_cmd_scs,
1446 { "Server command specifier", "canopen.sdo.scs",
1447 FT_UINT8, BASE_DEC, VALS(sdo_scs), 0xE0,
1448 NULL, HFILL }
1450 { &hf_canopen_sdo_cmd_ccs5_subcommand,
1451 { "Client subcommand", "canopen.sdo.cs",
1452 FT_UINT8, BASE_DEC, VALS(sdo_client_subcommand_meaning), 0x03,
1453 NULL, HFILL }
1455 { &hf_canopen_sdo_cmd_scs5_subcommand,
1456 { "Server command specifier", "canopen.sdo.ss",
1457 FT_UINT8, BASE_DEC, VALS(sdo_server_subcommand_meaning), 0x03,
1458 NULL, HFILL }
1460 { &hf_canopen_sdo_cmd_ccs6_subcommand,
1461 { "Client subcommand", "canopen.sdo.cs",
1462 FT_UINT8, BASE_DEC, VALS(sdo_client_subcommand_meaning), 0x01,
1463 NULL, HFILL }
1465 { &hf_canopen_sdo_cmd_scs6_subcommand,
1466 { "Server command specifier", "canopen.sdo.ss",
1467 FT_UINT8, BASE_DEC, VALS(sdo_server_subcommand_meaning), 0x01,
1468 NULL, HFILL }
1470 { &hf_canopen_sdo_cmd_block_crc_support,
1471 { "CRC support", "canopen.sdo.crc_support",
1472 FT_BOOLEAN, 8, NULL, 0x04,
1473 "toggle", HFILL }
1475 { &hf_canopen_sdo_cmd_block_s,
1476 { "Data set size indicated", "canopen.sdo.s",
1477 FT_BOOLEAN, 8, NULL, 0x02,
1478 "toggle", HFILL }
1480 { &hf_canopen_sdo_cmd_block_n,
1481 { "Non-data byte", "canopen.sdo.n",
1482 FT_UINT8, BASE_DEC, NULL, 0x1C,
1483 "toggle", HFILL }
1485 { &hf_canopen_sdo_cmd_block_ackseq,
1486 { "Number of segments acknowledged", "canopen.sdo.ackseq",
1487 FT_UINT8, BASE_DEC, NULL, 0x0,
1488 NULL, HFILL }
1490 { &hf_canopen_sdo_cmd_block_blksize,
1491 { "Number of segments per block", "canopen.sdo.blksize",
1492 FT_UINT8, BASE_DEC, NULL, 0x0,
1493 NULL, HFILL }
1495 { &hf_canopen_sdo_cmd_block_pst,
1496 { "Protocol switch threshold (bytes)", "canopen.sdo.pst",
1497 FT_UINT8, BASE_DEC, NULL, 0x0,
1498 NULL, HFILL }
1500 { &hf_canopen_sdo_cmd_toggle,
1501 { "Toggle bit", "canopen.sdo.toggle",
1502 FT_UINT8, BASE_DEC, NULL, 0x10,
1503 NULL, HFILL }},
1504 { &hf_canopen_sdo_cmd_updown_n,
1505 { "Non-data bytes", "canopen.sdo.n",
1506 FT_UINT8, BASE_DEC, NULL, 0x0E,
1507 "toggle", HFILL }},
1508 { &hf_canopen_sdo_cmd_updown_c,
1509 { "No more segments", "canopen.sdo.c",
1510 FT_BOOLEAN, 8, NULL, 0x01,
1511 "toggle", HFILL }},
1512 { &hf_canopen_sdo_cmd_init_n,
1513 { "Non-data bytes", "canopen.sdo.n",
1514 FT_UINT8, BASE_DEC, NULL, 0x0C,
1515 "toggle", HFILL }},
1516 { &hf_canopen_sdo_cmd_init_e,
1517 { "Expedited transfer", "canopen.sdo.e",
1518 FT_BOOLEAN, 8, NULL, 0x02,
1519 "toggle", HFILL }},
1520 { &hf_canopen_sdo_cmd_init_s,
1521 { "Data set size indicated", "canopen.sdo.s",
1522 FT_BOOLEAN, 8, NULL, 0x01,
1523 "toggle", HFILL }},
1524 { &hf_canopen_sdo_main_idx,
1525 { "OD main-index", "canopen.sdo.main_idx",
1526 FT_UINT16, BASE_HEX|BASE_RANGE_STRING, RVALS(obj_dict), 0x0,
1527 NULL, HFILL }
1529 { &hf_canopen_sdo_sub_idx,
1530 { "OD sub-index", "canopen.sdo.sub_idx",
1531 FT_UINT8, BASE_HEX, NULL, 0x0,
1532 NULL, HFILL }
1534 { &hf_canopen_sdo_data,
1535 { "Data", "canopen.sdo.data.bytes",
1536 FT_BYTES, BASE_NONE, NULL, 0x0,
1537 NULL, HFILL }
1539 { &hf_canopen_sdo_abort_code,
1540 { "Abort code", "canopen.sdo.abort_code",
1541 FT_UINT32, BASE_HEX, VALS(sdo_abort_code), 0x0,
1542 NULL, HFILL }
1544 { &hf_canopen_reserved,
1545 { "Reserved", "canopen.reserved",
1546 FT_BYTES, BASE_NONE, NULL, 0x00,
1547 NULL, HFILL }
1549 { &hf_canopen_em_err_code,
1550 { "Error code", "canopen.em.err_code",
1551 FT_UINT16, BASE_HEX|BASE_RANGE_STRING, RVALS(em_err_code), 0x0,
1552 NULL, HFILL }
1554 { &hf_canopen_em_err_reg,
1555 { "Error register", "canopen.em.err_reg",
1556 FT_UINT8, BASE_HEX, NULL, 0x0,
1557 NULL, HFILL }
1559 { &hf_canopen_em_err_reg_ge,
1560 { "Generic error", "canopen.em.err_reg_ge",
1561 FT_BOOLEAN, 8, NULL, 0x01,
1562 NULL, HFILL }
1564 { &hf_canopen_em_err_reg_cu,
1565 { "Current", "canopen.em.err_reg_cu",
1566 FT_BOOLEAN, 8, NULL, 0x02,
1567 NULL, HFILL }
1569 { &hf_canopen_em_err_reg_vo,
1570 { "Voltage", "canopen.em.err_reg_vo",
1571 FT_BOOLEAN, 8, NULL, 0x04,
1572 NULL, HFILL }
1574 { &hf_canopen_em_err_reg_te,
1575 { "Temperature", "canopen.em.err_reg_te",
1576 FT_BOOLEAN, 8, NULL, 0x08,
1577 NULL, HFILL }
1579 { &hf_canopen_em_err_reg_co,
1580 { "Communication error (overrun, error state)", "canopen.em.err_reg_co",
1581 FT_BOOLEAN, 8, NULL, 0x10,
1582 NULL, HFILL }
1584 { &hf_canopen_em_err_reg_de,
1585 { "Device profile specific", "canopen.em.err_reg_de",
1586 FT_BOOLEAN, 8, NULL, 0x20,
1587 NULL, HFILL }
1589 { &hf_canopen_em_err_reg_re,
1590 { "Reserved (must be false)", "canopen.em.err_reg_re",
1591 FT_BOOLEAN, 8, NULL, 0x40,
1592 NULL, HFILL }
1594 { &hf_canopen_em_err_reg_ma,
1595 { "Manufacturer specific", "canopen.em.err_reg_ma",
1596 FT_BOOLEAN, 8, NULL, 0x80,
1597 NULL, HFILL }
1599 { &hf_canopen_em_err_field,
1600 { "Manufacturer specific error field", "canopen.em.err_field",
1601 FT_BYTES, BASE_NONE, NULL, 0x0,
1602 NULL, HFILL }
1604 { &hf_canopen_nmt_ctrl_cs,
1605 { "Command specifier", "canopen.nmt_ctrl.cd",
1606 FT_UINT8, BASE_HEX, VALS(nmt_ctrl_cs), 0x0,
1607 NULL, HFILL }
1609 { &hf_canopen_nmt_ctrl_node_id,
1610 { "Node-ID", "canopen.nmt_ctrl.node_id",
1611 FT_UINT8, BASE_HEX, NULL, 0x0,
1612 NULL, HFILL }
1614 { &hf_canopen_nmt_guard_toggle,
1615 { "Reserved/Toggle", "canopen.nmt_guard.toggle",
1616 FT_UINT8, BASE_DEC, NULL, 0x80,
1617 NULL, HFILL }
1619 { &hf_canopen_nmt_guard_state,
1620 { "State", "canopen.nmt_guard.state",
1621 FT_UINT8, BASE_HEX, VALS(nmt_guard_state), 0x7F,
1622 NULL, HFILL }
1624 /* SYNC */
1625 { &hf_canopen_sync_counter,
1626 { "Counter", "canopen.sync.counter",
1627 FT_UINT8, BASE_DEC, NULL, 0x0,
1628 NULL, HFILL }
1630 /* LSS */
1631 { &hf_canopen_lss_cs,
1632 { "Command specifier", "canopen.lss.cs",
1633 FT_UINT8, BASE_HEX, VALS(lss_cs_code), 0x0,
1634 NULL, HFILL }
1636 { &hf_canopen_lss_addr_vendor,
1637 { "Vendor-ID", "canopen.lss.addr.vendor",
1638 FT_UINT32, BASE_HEX, NULL, 0x0,
1639 NULL, HFILL }
1641 { &hf_canopen_lss_addr_product,
1642 { "Product-code", "canopen.lss.addr.product",
1643 FT_UINT32, BASE_HEX, NULL, 0x0,
1644 NULL, HFILL }
1646 { &hf_canopen_lss_addr_revision,
1647 { "Revision-number", "canopen.lss.addr.revision",
1648 FT_UINT32, BASE_HEX, NULL, 0x0,
1649 NULL, HFILL }
1651 { &hf_canopen_lss_addr_revision_low,
1652 { "Revision-number (low)", "canopen.lss.addr.revision_low",
1653 FT_UINT32, BASE_HEX, NULL, 0x0,
1654 NULL, HFILL }
1656 { &hf_canopen_lss_addr_revision_high,
1657 { "Revision-number (high)", "canopen.lss.addr.revision_high",
1658 FT_UINT32, BASE_HEX, NULL, 0x0,
1659 NULL, HFILL }
1661 { &hf_canopen_lss_addr_serial,
1662 { "Serial-number", "canopen.lss.addr.serial",
1663 FT_UINT32, BASE_HEX, NULL, 0x0,
1664 NULL, HFILL }
1666 { &hf_canopen_lss_addr_serial_low,
1667 { "Serial-number (low)", "canopen.lss.addr.serial_low",
1668 FT_UINT32, BASE_HEX, NULL, 0x0,
1669 NULL, HFILL }
1671 { &hf_canopen_lss_addr_serial_high,
1672 { "Serial-number (high)", "canopen.lss.addr.serial_high",
1673 FT_UINT32, BASE_HEX, NULL, 0x0,
1674 NULL, HFILL }
1676 { &hf_canopen_lss_fastscan_id,
1677 { "IDNumber", "canopen.lss.fastscan.id",
1678 FT_UINT32, BASE_HEX, NULL, 0x0,
1679 NULL, HFILL }
1681 { &hf_canopen_lss_fastscan_check,
1682 { "Bit Check", "canopen.lss.fastscan.check",
1683 FT_UINT8, BASE_HEX, NULL, 0x0,
1684 NULL, HFILL }
1686 { &hf_canopen_lss_fastscan_sub,
1687 { "LSS Sub", "canopen.lss.fastscan.sub",
1688 FT_UINT8, BASE_HEX, VALS(lss_fastscan_subnext), 0x0,
1689 NULL, HFILL }
1691 { &hf_canopen_lss_fastscan_next,
1692 { "LSS Next", "canopen.lss.fastscan.next",
1693 FT_UINT8, BASE_HEX, VALS(lss_fastscan_subnext), 0x0,
1694 NULL, HFILL }
1696 { &hf_canopen_lss_switch_mode,
1697 { "Mode", "canopen.lss.switch.mode",
1698 FT_UINT8, BASE_HEX, VALS(lss_switch_mode), 0x0,
1699 NULL, HFILL }
1701 { &hf_canopen_lss_nid,
1702 { "NID", "canopen.lss.nid",
1703 FT_UINT8, BASE_HEX, NULL, 0x0,
1704 NULL, HFILL }
1706 { &hf_canopen_lss_conf_id_err_code,
1707 { "Error code", "canopen.lss.conf_id.err_code",
1708 FT_UINT8, BASE_HEX, VALS(lss_conf_id_err_code), 0x0,
1709 NULL, HFILL }
1711 { &hf_canopen_lss_conf_bt_err_code,
1712 { "Error code", "canopen.lss.conf_bt.err_code",
1713 FT_UINT8, BASE_HEX, VALS(lss_conf_bt_err_code), 0x0,
1714 NULL, HFILL }
1716 { &hf_canopen_lss_store_conf_err_code,
1717 { "Error code", "canopen.lss.store_conf.err_code",
1718 FT_UINT8, BASE_HEX, VALS(lss_store_conf_err_code), 0x0,
1719 NULL, HFILL }
1721 { &hf_canopen_lss_spec_err,
1722 { "Spec-error", "canopen.lss.spec_err",
1723 FT_UINT8, BASE_HEX, NULL, 0x0,
1724 NULL, HFILL }
1726 { &hf_canopen_lss_bt_tbl_selector,
1727 { "Table selector", "canopen.lss.bt.tbl_selector",
1728 FT_UINT8, BASE_HEX, NULL, 0x0,
1729 NULL, HFILL }
1731 { &hf_canopen_lss_bt_tbl_index,
1732 { "Table index", "canopen.lss.bt.tbl_index",
1733 FT_UINT8, BASE_HEX, VALS(bit_timing_tbl), 0x0,
1734 NULL, HFILL }
1736 { &hf_canopen_lss_abt_delay,
1737 { "Switch delay", "canopen.lss.abt_delay",
1738 FT_UINT16, BASE_DEC, NULL, 0x0,
1739 NULL, HFILL }
1743 { &hf_canopen_time_stamp,
1744 { "Time stamp", "canopen.time_stamp",
1745 FT_ABSOLUTE_TIME, ABSOLUTE_TIME_UTC, NULL, 0x0,
1746 NULL, HFILL }
1748 { &hf_canopen_time_stamp_ms,
1749 { "Time, after Midnight in Milliseconds", "canopen.time_stamp_ms",
1750 FT_UINT32, BASE_DEC, NULL, 0x0,
1751 NULL, HFILL }
1753 { &hf_canopen_time_stamp_days,
1754 { "Current day since 1 Jan 1984", "canopen.time_stamp_days",
1755 FT_UINT16, BASE_DEC, NULL, 0x0,
1756 NULL, HFILL }
1760 static int *ett[] = {
1761 &ett_canopen,
1762 &ett_canopen_cob,
1763 &ett_canopen_type,
1764 &ett_canopen_sdo_cmd,
1765 &ett_canopen_em_er
1768 proto_canopen = proto_register_protocol("CANopen", "CANOPEN", "canopen");
1770 proto_register_field_array(proto_canopen, hf, array_length(hf));
1771 proto_register_subtree_array(ett, array_length(ett));
1773 canopen_handle = register_dissector("canopen", dissect_canopen, proto_canopen );
1776 void
1777 proto_reg_handoff_canopen(void)
1779 dissector_add_for_decode_as("can.subdissector", canopen_handle );
1783 * Editor modelines - https://www.wireshark.org/tools/modelines.html
1785 * Local variables:
1786 * c-basic-offset: 4
1787 * tab-width: 8
1788 * indent-tabs-mode: nil
1789 * End:
1791 * vi: set shiftwidth=4 tabstop=8 expandtab:
1792 * :indentSize=4:tabSize=8:noTabs=true: