2 * Routines for CIP (Common Industrial Protocol) Motion dissection
3 * CIP Motion Home: www.odva.org
5 * This dissector includes items from:
6 * CIP Volume 9: CIP Motion, Edition 1.7
9 * Benjamin M. Stocks <bmstocks@ra.rockwell.com>
11 * Wireshark - Network traffic analyzer
12 * By Gerald Combs <gerald@wireshark.org>
13 * Copyright 1998 Gerald Combs
15 * SPDX-License-Identifier: GPL-2.0-or-later
20 #include <epan/packet.h>
21 #include <epan/expert.h>
22 #include <epan/unit_strings.h>
24 #include "packet-cipmotion.h"
26 #include "packet-cip.h"
27 #include "packet-enip.h"
29 void proto_register_cipmotion(void);
30 /* The entry point to the actual dissection is: dissect_cipmotion */
31 void proto_reg_handoff_cipmotion(void);
33 /* Protocol handle for CIP Motion */
34 static int proto_cipmotion
;
35 static int proto_cipmotion3
;
37 /* Header field identifiers, these are registered in the
38 * proto_register_cipmotion function along with the bites/bytes
40 static int hf_cip_format
;
41 static int hf_cip_revision
;
42 static int hf_cip_class1_seqnum
;
43 static int hf_configuration_block_format_rev
;
44 static int hf_configuration_block_drive_power_struct_id
;
45 static int hf_cip_updateid
;
46 static int hf_cip_instance_cnt
;
47 static int hf_cip_last_update
;
48 static int hf_cip_node_status
;
49 static int hf_cip_node_control
;
50 static int hf_cip_node_control_remote
;
51 static int hf_cip_node_control_sync
;
52 static int hf_cip_node_data_valid
;
53 static int hf_cip_node_fault_reset
;
54 static int hf_cip_node_device_faulted
;
55 static int hf_cip_time_data_set
;
56 static int hf_cip_time_data_stamp
;
57 static int hf_cip_time_data_offset
;
58 static int hf_cip_time_data_diag
;
59 static int hf_cip_time_data_time_diag
;
60 static int hf_cip_cont_time_stamp
;
61 static int hf_cip_cont_time_offset
;
62 static int hf_cip_devc_time_stamp
;
63 static int hf_cip_devc_time_offset
;
64 static int hf_cip_lost_update
;
65 static int hf_cip_late_update
;
66 static int hf_cip_data_rx_time_stamp
;
67 static int hf_cip_data_tx_time_stamp
;
68 static int hf_cip_node_fltalarms
;
69 static int hf_cip_motor_cntrl
;
70 static int hf_cip_feedback
;
71 static int hf_cip_feedback_mode
;
72 static int hf_cip_feedback_data_type
;
74 static int hf_connection_configuration_bits
;
75 static int hf_connection_configuration_bits_power
;
76 static int hf_connection_configuration_bits_safety_bit_valid
;
77 static int hf_connection_configuration_bits_allow_network_safety
;
79 static int hf_cip_axis_control
;
80 static int hf_cip_control_status
;
81 static int hf_cip_control_status_complete
;
82 static int hf_cip_control_status_bus_up
;
83 static int hf_cip_control_status_bus_unload
;
84 static int hf_cip_control_status_power_loss
;
85 static int hf_cip_axis_response
;
86 static int hf_cip_axis_resp_stat
;
87 static int hf_cip_cmd_data_pos_cmd
;
88 static int hf_cip_cmd_data_vel_cmd
;
89 static int hf_cip_cmd_data_acc_cmd
;
90 static int hf_cip_cmd_data_trq_cmd
;
91 static int hf_cip_cmd_data_unwind_cycle_count
;
92 static int hf_cip_cmd_data_pos_displacement
;
93 static int hf_cip_act_data_pos
;
94 static int hf_cip_act_data_vel
;
95 static int hf_cip_act_data_acc
;
96 static int hf_cip_act_unwind_cycle_count
;
97 static int hf_cip_act_pos_displacement
;
98 static int hf_cip_sts_flt
;
99 static int hf_cip_sts_alrm
;
100 static int hf_cip_sts_sts
;
101 static int hf_cip_sts_iosts
;
102 static int hf_cip_sts_axis_safety
;
103 static int hf_cip_intrp
;
104 static int hf_cip_position_data_type
;
105 static int hf_cip_axis_state
;
106 static int hf_cip_evnt_ctrl_reg1_pos
;
107 static int hf_cip_evnt_ctrl_reg1_neg
;
108 static int hf_cip_evnt_ctrl_reg2_pos
;
109 static int hf_cip_evnt_ctrl_reg2_neg
;
110 static int hf_cip_evnt_ctrl_reg1_posrearm
;
111 static int hf_cip_evnt_ctrl_reg1_negrearm
;
112 static int hf_cip_evnt_ctrl_reg2_posrearm
;
113 static int hf_cip_evnt_ctrl_reg2_negrearm
;
114 static int hf_cip_evnt_ctrl_marker_pos
;
115 static int hf_cip_evnt_ctrl_marker_neg
;
116 static int hf_cip_evnt_ctrl_home_pos
;
117 static int hf_cip_evnt_ctrl_home_neg
;
118 static int hf_cip_evnt_ctrl_home_pp
;
119 static int hf_cip_evnt_ctrl_home_pm
;
120 static int hf_cip_evnt_ctrl_home_mp
;
121 static int hf_cip_evnt_ctrl_home_mm
;
122 static int hf_cip_evnt_ctrl_acks
;
123 static int hf_cip_evnt_extend_format
;
124 static int hf_cip_evnt_sts_reg1_pos
;
125 static int hf_cip_evnt_sts_reg1_neg
;
126 static int hf_cip_evnt_sts_reg2_pos
;
127 static int hf_cip_evnt_sts_reg2_neg
;
128 static int hf_cip_evnt_sts_reg1_posrearm
;
129 static int hf_cip_evnt_sts_reg1_negrearm
;
130 static int hf_cip_evnt_sts_reg2_posrearm
;
131 static int hf_cip_evnt_sts_reg2_negrearm
;
132 static int hf_cip_evnt_sts_marker_pos
;
133 static int hf_cip_evnt_sts_marker_neg
;
134 static int hf_cip_evnt_sts_home_pos
;
135 static int hf_cip_evnt_sts_home_neg
;
136 static int hf_cip_evnt_sts_home_pp
;
137 static int hf_cip_evnt_sts_home_pm
;
138 static int hf_cip_evnt_sts_home_mp
;
139 static int hf_cip_evnt_sts_home_mm
;
140 static int hf_cip_evnt_sts_nfs
;
141 static int hf_cip_evnt_sts_stat
;
142 static int hf_cip_evnt_type
;
143 static int hf_cip_svc_code
;
144 static int hf_cip_svc_sts
;
145 static int hf_cip_svc_set_axis_attr_sts
;
146 static int hf_cip_svc_get_axis_attr_sts
;
147 static int hf_cip_svc_transction
;
148 static int hf_cip_svc_ext_status
;
149 static int hf_cip_svc_data
;
150 static int hf_cip_ptp_grandmaster
;
151 static int hf_cip_axis_alarm
;
152 static int hf_cip_axis_fault
;
153 static int hf_cip_axis_sts_local_ctrl
;
154 static int hf_cip_axis_sts_alarm
;
155 static int hf_cip_axis_sts_dc_bus
;
156 static int hf_cip_axis_sts_pwr_struct
;
157 static int hf_cip_axis_sts_flux_up
;
158 static int hf_cip_axis_sts_tracking
;
159 static int hf_cip_axis_sts_pos_lock
;
160 static int hf_cip_axis_sts_vel_lock
;
161 static int hf_cip_axis_sts_vel_standstill
;
162 static int hf_cip_axis_sts_vel_threshold
;
163 static int hf_cip_axis_sts_vel_limit
;
164 static int hf_cip_axis_sts_acc_limit
;
165 static int hf_cip_axis_sts_dec_limit
;
166 static int hf_cip_axis_sts_torque_threshold
;
167 static int hf_cip_axis_sts_torque_limit
;
168 static int hf_cip_axis_sts_cur_limit
;
169 static int hf_cip_axis_sts_therm_limit
;
170 static int hf_cip_axis_sts_feedback_integ
;
171 static int hf_cip_axis_sts_shutdown
;
172 static int hf_cip_axis_sts_in_process
;
173 static int hf_cip_axis_sts_dc_bus_unload
;
174 static int hf_cip_axis_sts_ac_pwr_loss
;
175 static int hf_cip_axis_sts_pos_cntrl_mode
;
176 static int hf_cip_axis_sts_vel_cntrl_mode
;
177 static int hf_cip_axis_sts_trq_cntrl_mode
;
179 static int hf_cip_axis_status2
;
180 static int hf_cip_axis_sts2_motor
;
181 static int hf_cip_axis_sts2_regenerate
;
182 static int hf_cip_axis_sts2_ride_thru
;
183 static int hf_cip_axis_sts2_ac_line_sync
;
184 static int hf_cip_axis_sts2_bus_volt_lock
;
185 static int hf_cip_axis_sts2_react_pwr_only
;
186 static int hf_cip_axis_sts2_volt_ctrl_mode
;
187 static int hf_cip_axis_sts2_pwr_loss
;
188 static int hf_cip_axis_sts2_ac_volt_sag
;
189 static int hf_cip_axis_sts2_ac_phase_loss
;
190 static int hf_cip_axis_sts2_ac_freq_change
;
191 static int hf_cip_axis_sts2_ac_sync_loss
;
192 static int hf_cip_axis_sts2_single_phase
;
193 static int hf_cip_axis_sts2_bus_volt_limit
;
194 static int hf_cip_axis_sts2_bus_volt_rate_limit
;
195 static int hf_cip_axis_sts2_active_current_rate_limit
;
196 static int hf_cip_axis_sts2_reactive_current_rate_limit
;
197 static int hf_cip_axis_sts2_reactive_pwr_limit
;
198 static int hf_cip_axis_sts2_reactive_pwr_rate_limit
;
199 static int hf_cip_axis_sts2_active_current_limit
;
200 static int hf_cip_axis_sts2_reactive_current_limit
;
201 static int hf_cip_axis_sts2_motor_pwr_limit
;
202 static int hf_cip_axis_sts2_regen_pwr_limit
;
203 static int hf_cip_axis_sts2_convert_therm_limit
;
205 static int hf_cip_cyclic_wrt_data
;
206 static int hf_cip_cyclic_rd_data
;
207 static int hf_cip_cyclic_write_blk
;
208 static int hf_cip_cyclic_read_blk
;
209 static int hf_cip_cyclic_write_sts
;
210 static int hf_cip_cyclic_read_sts
;
211 static int hf_cip_attribute_data
;
212 static int hf_cip_event_checking
;
213 static int hf_cip_event_ack
;
214 static int hf_cip_event_status
;
215 static int hf_cip_event_id
;
216 static int hf_cip_event_pos
;
217 static int hf_cip_event_ts
;
218 static int hf_cip_pos_cmd
;
219 static int hf_cip_pos_cmd_int
;
220 static int hf_cip_vel_cmd
;
221 static int hf_cip_accel_cmd
;
222 static int hf_cip_trq_cmd
;
223 static int hf_cip_pos_trim
;
224 static int hf_cip_vel_trim
;
225 static int hf_cip_accel_trim
;
226 static int hf_cip_trq_trim
;
227 static int hf_cip_act_pos
;
228 static int hf_cip_act_pos_64
;
229 static int hf_cip_act_vel
;
230 static int hf_cip_act_accel
;
231 static int hf_cip_fault_type
;
232 static int hf_cip_fault_sub_code
;
233 static int hf_cip_fault_action
;
234 static int hf_cip_fault_time_stamp
;
235 static int hf_cip_alarm_type
;
236 static int hf_cip_alarm_sub_code
;
237 static int hf_cip_alarm_state
;
238 static int hf_cip_alarm_time_stamp
;
239 static int hf_cip_axis_status
;
240 static int hf_cip_axis_status_mfg
;
241 static int hf_cip_axis_io_status
;
242 static int hf_cip_axis_io_status_mfg
;
243 static int hf_cip_axis_safety_status
;
244 static int hf_cip_axis_safety_status_mfg
;
245 static int hf_cip_axis_safety_state
;
246 static int hf_cip_cmd_data_set
;
247 static int hf_cip_act_data_set
;
248 static int hf_cip_sts_data_set
;
249 static int hf_cip_group_sync
;
250 static int hf_cip_command_control
;
252 static int hf_get_axis_attr_list_attribute_cnt
;
253 static int hf_get_axis_attr_list_attribute_id
;
254 static int hf_get_axis_attr_list_dimension
;
255 static int hf_get_axis_attr_list_element_size
;
256 static int hf_get_axis_attr_list_start_index
;
257 static int hf_get_axis_attr_list_data_elements
;
258 static int hf_set_axis_attr_list_attribute_cnt
;
259 static int hf_set_axis_attr_list_attribute_id
;
260 static int hf_set_axis_attr_list_dimension
;
261 static int hf_set_axis_attr_list_element_size
;
262 static int hf_set_axis_attr_list_start_index
;
263 static int hf_set_axis_attr_list_data_elements
;
264 static int hf_set_cyclic_list_attribute_cnt
;
265 static int hf_set_cyclic_list_attribute_id
;
266 static int hf_set_cyclic_list_read_block_id
;
267 static int hf_set_cyclic_list_attr_sts
;
268 static int hf_var_devce_instance
;
269 static int hf_var_devce_instance_block_size
;
270 static int hf_var_devce_cyclic_block_size
;
271 static int hf_var_devce_cyclic_data_block_size
;
272 static int hf_var_devce_cyclic_rw_block_size
;
273 static int hf_var_devce_event_block_size
;
274 static int hf_var_devce_service_block_size
;
275 static int hf_cip_data
;
277 /* Subtree pointers for the dissection */
278 static int ett_cipmotion
;
279 static int ett_cont_dev_header
;
280 static int ett_control_status
;
281 static int ett_node_control
;
282 static int ett_node_status
;
283 static int ett_time_data_set
;
284 static int ett_inst_data_header
;
285 static int ett_cyclic_data_block
;
286 static int ett_cyclic_command_data
;
287 static int ett_feedback_mode
;
288 static int ett_connection_configuration_bits
;
289 static int ett_control_mode
;
290 static int ett_feedback_config
;
291 static int ett_command_data_set
;
292 static int ett_actual_data_set
;
293 static int ett_status_data_set
;
294 static int ett_interp_control
;
295 static int ett_cyclic_rd_wt
;
296 static int ett_event
;
297 static int ett_event_check_ctrl
;
298 static int ett_event_check_sts
;
299 static int ett_service
;
300 static int ett_get_axis_attribute
;
301 static int ett_set_axis_attribute
;
302 static int ett_get_axis_attr_list
;
303 static int ett_set_axis_attr_list
;
304 static int ett_set_cyclic_list
;
305 static int ett_group_sync
;
306 static int ett_axis_status_set
;
307 static int ett_command_control
;
308 static int ett_configuration_block
;
310 static expert_field ei_format_rev_conn_pt
;
312 static dissector_handle_t cipmotion_handle
;
313 static dissector_handle_t cipmotion3_handle
;
315 static bool display_full_attribute_data
;
317 /* These are the BITMASKS for the Time Data Set header field */
318 #define TIME_DATA_SET_TIME_STAMP 0x1
319 #define TIME_DATA_SET_TIME_OFFSET 0x2
320 #define TIME_DATA_SET_UPDATE_DIAGNOSTICS 0x4
321 #define TIME_DATA_SET_TIME_DIAGNOSTICS 0x8
323 /* These are the BITMASKS for the Command Data Set cyclic field */
324 #define COMMAND_DATA_SET_POSITION 0x01
325 #define COMMAND_DATA_SET_VELOCITY 0x02
326 #define COMMAND_DATA_SET_ACCELERATION 0x04
327 #define COMMAND_DATA_SET_TORQUE 0x08
328 #define COMMAND_DATA_SET_UNWIND_CYCLE_COUNT 0x40
329 #define COMMAND_DATA_SET_POSITION_DISPLACE 0x80
331 /* These are the BITMASKS for the Actual Data Set cyclic field */
332 #define ACTUAL_DATA_SET_POSITION 0x01
333 #define ACTUAL_DATA_SET_VELOCITY 0x02
334 #define ACTUAL_DATA_SET_ACCELERATION 0x04
335 #define ACTUAL_DATA_SET_UNWIND_CYCLE_COUNT 0x40
336 #define ACTUAL_DATA_SET_POSITION_DISPLACE 0x80
338 /* These are the BITMASKS for the Status Data Set cyclic field */
339 #define STATUS_DATA_SET_AXIS_FAULT 0x01
340 #define STATUS_DATA_SET_AXIS_ALARM 0x02
341 #define STATUS_DATA_SET_AXIS_STATUS 0x04
342 #define STATUS_DATA_SET_AXIS_IO_STATUS 0x08
343 #define STATUS_DATA_SET_AXIS_SAFETY 0x10
345 /* These are the BITMASKS for the Command Control cyclic field */
346 #define COMMAND_CONTROL_TARGET_UPDATE 0x03
347 #define COMMAND_CONTROL_POSITION_DATA_TYPE 0x0C
349 /* These are the VALUES of the connection format header field of the
350 * CIP Motion protocol */
351 #define FORMAT_FIXED_CONTROL_TO_DEVICE 2
352 #define FORMAT_FIXED_DEVICE_TO_CONTROL 3
353 #define FORMAT_VAR_CONTROL_TO_DEVICE 6
354 #define FORMAT_VAR_DEVICE_TO_CONTROL 7
356 #define FEEDBACK_MODE_BITS 0x0F
357 #define FEEDBACK_DATA_TYPE_BITS 0x30
359 /* Translate function to string - connection format values */
360 static const value_string cip_con_format_vals
[] = {
361 { FORMAT_FIXED_CONTROL_TO_DEVICE
, "Fixed Controller-to-Device" },
362 { FORMAT_FIXED_DEVICE_TO_CONTROL
, "Fixed Device-to-Controller" },
363 { FORMAT_VAR_CONTROL_TO_DEVICE
, "Variable Controller-to-Device" },
364 { FORMAT_VAR_DEVICE_TO_CONTROL
, "Variable Device-to-Controller" },
368 /* Translate function to string - motor control mode values */
369 static const value_string cip_motor_control_vals
[] = {
371 { 1, "Position Control" },
372 { 2, "Velocity Control" },
373 { 3, "Acceleration Control" },
374 { 4, "Torque Control" },
378 /* Translate function to string - feedback mode values */
379 static const value_string cip_feedback_mode_vals
[] = {
380 { 0, "No Feedback" },
381 { 1, "Master Feedback" },
382 { 2, "Motor Feedback" },
383 { 3, "Load Feedback" },
384 { 4, "Dual Feedback" },
388 static const value_string cip_feedback_type_vals
[] = {
394 /* Translate function to string - axis control values */
395 static const value_string cip_axis_control_vals
[] =
398 { 1, "Enable Request" },
399 { 2, "Disable Request" },
400 { 3, "Shutdown Request" },
401 { 4, "Shutdown Reset Request" },
402 { 5, "Abort Request" },
403 { 6, "Fault Reset Request" },
404 { 7, "Stop Process" },
405 { 8, "Change Actual Pos" },
406 { 9, "Change Command Pos Ref" },
407 { 127, "Cancel Request" },
411 /* Translate function to string - group sync Status */
412 static const value_string cip_sync_status_vals
[] =
414 { 0, "Synchronized" },
415 { 1, "Not Synchronized" },
416 { 2, "Wrong Grandmaster" },
417 { 3, "Clock Skew Detected" },
421 /* Translate function to string - command target update */
422 static const value_string cip_interpolation_vals
[] = {
424 { 1, "Extrapolate (+1)" },
425 { 2, "Interpolate (+2)" },
429 /* These are the VALUES for the Command Position Data Type */
430 #define POSITION_DATA_LREAL 0x00
431 #define POSITION_DATA_DINT 0x01
433 /* Translate function to string - position data type */
434 static const value_string cip_pos_data_type_vals
[] = {
435 { POSITION_DATA_LREAL
, "LREAL (64-bit Float)" },
436 { POSITION_DATA_DINT
, "DINT (32-bit Integer)" },
440 /* Translate function to string - axis response values */
441 static const value_string cip_axis_response_vals
[] = {
442 { 0, "No Acknowledge" },
443 { 1, "Enable Acknowledge" },
444 { 2, "Disable Acknowledge" },
445 { 3, "Shutdown Acknowledge" },
446 { 4, "Shutdown Reset Acknowledge" },
447 { 5, "Abort Acknowledge" },
448 { 6, "Fault Reset Acknowledge" },
449 { 7, "Stop Process Acknowledge" },
450 { 8, "Change Actual Position Reference Acknowledge" },
451 { 9, "Change Command Position Reference Acknowledge" },
452 { 127, "Cancel Acknowledge" },
456 /* Translate function to string - axis state values */
457 static const value_string cip_axis_state_vals
[] = {
458 { 0, "Initializing" },
466 { 8, "Major Faulted" },
467 { 9, "Start Inhibited" },
472 /* Translate function to string - event type values */
473 static const value_string cip_event_type_vals
[] = {
474 { 0, "Registration 1 Positive Edge" },
475 { 1, "Registration 1 Negative Edge" },
476 { 2, "Registration 2 Positive Edge" },
477 { 3, "Registration 2 Negative Edge" },
478 { 4, "Marker Positive Edge" },
479 { 5, "Marker Negative Edge" },
480 { 6, "Home Switch Positive Edge" },
481 { 7, "Home Switch Negative Edge" },
482 { 8, "Home Switch Marker ++" },
483 { 9, "Home Switch Marker +-" },
484 { 10, "Home Switch Marker -+" },
485 { 11, "Home Switch Marker --" },
489 #define SC_GET_AXIS_ATTRIBUTE_LIST 0x4B
490 #define SC_SET_AXIS_ATTRIBUTE_LIST 0x4C
491 #define SC_SET_CYCLIC_WRITE_LIST 0x4D
492 #define SC_SET_CYCLIC_READ_LIST 0x4E
493 #define SC_RUN_MOTOR_TEST 0x4F
494 #define SC_GET_MOTOR_TEST_DATA 0x50
495 #define SC_RUN_INERTIA_TEST 0x51
496 #define SC_GET_INERTIA_TEST_DATA 0x52
497 #define SC_RUN_HOOKUP_TEST 0x53
498 #define SC_GET_HOOKUP_TEST_DATA 0x54
500 /* Translate function to string - CIP Service codes */
501 static const value_string cip_sc_vals
[] = {
503 { SC_GET_AXIS_ATTRIBUTE_LIST
, "Get Axis Attribute List" },
504 { SC_SET_AXIS_ATTRIBUTE_LIST
, "Set Axis Attribute List" },
505 { SC_SET_CYCLIC_WRITE_LIST
, "Set Cyclic Write List" },
506 { SC_SET_CYCLIC_READ_LIST
, "Set Cyclic Read List" },
507 { SC_RUN_MOTOR_TEST
, "Run Motor Test" },
508 { SC_GET_MOTOR_TEST_DATA
, "Get Motor Test Data" },
509 { SC_RUN_INERTIA_TEST
, "Run Inertia Test" },
510 { SC_GET_INERTIA_TEST_DATA
, "Get Inertia Test Data" },
511 { SC_RUN_HOOKUP_TEST
, "Run Hookup Test" },
512 { SC_GET_HOOKUP_TEST_DATA
, "Get Hookup Test Data" },
516 static int dissect_axis_status(packet_info
*pinfo _U_
, proto_tree
*tree
, proto_item
*item _U_
, tvbuff_t
*tvb
,
517 int offset
, int total_len _U_
)
519 static int* const bits
[] = {
520 &hf_cip_axis_sts_local_ctrl
,
521 &hf_cip_axis_sts_alarm
,
522 &hf_cip_axis_sts_dc_bus
,
523 &hf_cip_axis_sts_pwr_struct
,
524 &hf_cip_axis_sts_flux_up
,
525 &hf_cip_axis_sts_tracking
,
526 &hf_cip_axis_sts_pos_lock
,
527 &hf_cip_axis_sts_vel_lock
,
528 &hf_cip_axis_sts_vel_standstill
,
529 &hf_cip_axis_sts_vel_threshold
,
530 &hf_cip_axis_sts_vel_limit
,
531 &hf_cip_axis_sts_acc_limit
,
532 &hf_cip_axis_sts_dec_limit
,
533 &hf_cip_axis_sts_torque_threshold
,
534 &hf_cip_axis_sts_torque_limit
,
535 &hf_cip_axis_sts_cur_limit
,
536 &hf_cip_axis_sts_therm_limit
,
537 &hf_cip_axis_sts_feedback_integ
,
538 &hf_cip_axis_sts_shutdown
,
539 &hf_cip_axis_sts_in_process
,
540 &hf_cip_axis_sts_dc_bus_unload
,
541 &hf_cip_axis_sts_ac_pwr_loss
,
542 &hf_cip_axis_sts_pos_cntrl_mode
,
543 &hf_cip_axis_sts_vel_cntrl_mode
,
544 &hf_cip_axis_sts_trq_cntrl_mode
,
548 proto_tree_add_bitmask(tree
, tvb
, offset
, hf_cip_axis_status
, ett_axis_status_set
, bits
, ENC_LITTLE_ENDIAN
);
553 static int dissect_axis_status2(packet_info
*pinfo _U_
, proto_tree
*tree
, proto_item
*item _U_
, tvbuff_t
*tvb
,
554 int offset
, int total_len _U_
)
556 static int* const bits
[] = {
557 &hf_cip_axis_sts2_motor
,
558 &hf_cip_axis_sts2_regenerate
,
559 &hf_cip_axis_sts2_ride_thru
,
560 &hf_cip_axis_sts2_ac_line_sync
,
561 &hf_cip_axis_sts2_bus_volt_lock
,
562 &hf_cip_axis_sts2_react_pwr_only
,
563 &hf_cip_axis_sts2_volt_ctrl_mode
,
564 &hf_cip_axis_sts2_pwr_loss
,
565 &hf_cip_axis_sts2_ac_volt_sag
,
566 &hf_cip_axis_sts2_ac_phase_loss
,
567 &hf_cip_axis_sts2_ac_freq_change
,
568 &hf_cip_axis_sts2_ac_sync_loss
,
569 &hf_cip_axis_sts2_single_phase
,
570 &hf_cip_axis_sts2_bus_volt_limit
,
571 &hf_cip_axis_sts2_bus_volt_rate_limit
,
572 &hf_cip_axis_sts2_active_current_rate_limit
,
573 &hf_cip_axis_sts2_reactive_current_rate_limit
,
574 &hf_cip_axis_sts2_reactive_pwr_limit
,
575 &hf_cip_axis_sts2_reactive_pwr_rate_limit
,
576 &hf_cip_axis_sts2_active_current_limit
,
577 &hf_cip_axis_sts2_reactive_current_limit
,
578 &hf_cip_axis_sts2_motor_pwr_limit
,
579 &hf_cip_axis_sts2_regen_pwr_limit
,
580 &hf_cip_axis_sts2_convert_therm_limit
,
584 proto_tree_add_bitmask(tree
, tvb
, offset
, hf_cip_axis_status2
, ett_axis_status_set
, bits
, ENC_LITTLE_ENDIAN
);
589 static int dissect_event_checking_control(packet_info
*pinfo _U_
, proto_tree
*tree
, proto_item
*item _U_
, tvbuff_t
*tvb
,
590 int offset
, int total_len _U_
)
592 static int* const bits
[] = {
593 &hf_cip_evnt_ctrl_reg1_pos
,
594 &hf_cip_evnt_ctrl_reg1_neg
,
595 &hf_cip_evnt_ctrl_reg2_pos
,
596 &hf_cip_evnt_ctrl_reg2_neg
,
597 &hf_cip_evnt_ctrl_reg1_posrearm
,
598 &hf_cip_evnt_ctrl_reg1_negrearm
,
599 &hf_cip_evnt_ctrl_reg2_posrearm
,
600 &hf_cip_evnt_ctrl_reg2_negrearm
,
601 &hf_cip_evnt_ctrl_marker_pos
,
602 &hf_cip_evnt_ctrl_marker_neg
,
603 &hf_cip_evnt_ctrl_home_pos
,
604 &hf_cip_evnt_ctrl_home_neg
,
605 &hf_cip_evnt_ctrl_home_pp
,
606 &hf_cip_evnt_ctrl_home_pm
,
607 &hf_cip_evnt_ctrl_home_mp
,
608 &hf_cip_evnt_ctrl_home_mm
,
609 &hf_cip_evnt_ctrl_acks
,
610 // The dissector will indicate if the protocol is requesting an extended event format but will not dissect it.
611 &hf_cip_evnt_extend_format
,
615 proto_tree_add_bitmask(tree
, tvb
, offset
, hf_cip_event_checking
, ett_event_check_ctrl
, bits
, ENC_LITTLE_ENDIAN
);
620 static int dissect_event_checking_status(packet_info
*pinfo _U_
, proto_tree
*tree
, proto_item
*item _U_
, tvbuff_t
*tvb
,
621 int offset
, int total_len _U_
)
623 static int* const bits
[] = {
624 &hf_cip_evnt_sts_reg1_pos
,
625 &hf_cip_evnt_sts_reg1_neg
,
626 &hf_cip_evnt_sts_reg2_pos
,
627 &hf_cip_evnt_sts_reg2_neg
,
628 &hf_cip_evnt_sts_reg1_posrearm
,
629 &hf_cip_evnt_sts_reg1_negrearm
,
630 &hf_cip_evnt_sts_reg2_posrearm
,
631 &hf_cip_evnt_sts_reg2_negrearm
,
632 &hf_cip_evnt_sts_marker_pos
,
633 &hf_cip_evnt_sts_marker_neg
,
634 &hf_cip_evnt_sts_home_pos
,
635 &hf_cip_evnt_sts_home_neg
,
636 &hf_cip_evnt_sts_home_pp
,
637 &hf_cip_evnt_sts_home_pm
,
638 &hf_cip_evnt_sts_home_mp
,
639 &hf_cip_evnt_sts_home_mm
,
640 &hf_cip_evnt_sts_nfs
,
641 // The dissector will indicate if the protocol is requesting an extended event format but will not dissect it.
642 &hf_cip_evnt_extend_format
,
646 proto_tree_add_bitmask(tree
, tvb
, offset
, hf_cip_event_status
, ett_event_check_sts
, bits
, ENC_LITTLE_ENDIAN
);
651 static int dissect_actual_data_set_bits(packet_info
*pinfo _U_
, proto_tree
*tree
, proto_item
*item _U_
, tvbuff_t
*tvb
,
652 int offset
, int total_len _U_
)
654 static int* const bits
[] = {
655 &hf_cip_act_data_pos
,
656 &hf_cip_act_data_vel
,
657 &hf_cip_act_data_acc
,
658 &hf_cip_act_unwind_cycle_count
,
659 &hf_cip_act_pos_displacement
,
663 proto_tree_add_bitmask(tree
, tvb
, offset
, hf_cip_act_data_set
, ett_actual_data_set
, bits
, ENC_LITTLE_ENDIAN
);
668 static int dissect_command_data_set_bits(packet_info
*pinfo _U_
, proto_tree
*tree
, proto_item
*item _U_
, tvbuff_t
*tvb
,
669 int offset
, int total_len _U_
)
671 static int* const bits
[] = {
672 &hf_cip_cmd_data_pos_cmd
,
673 &hf_cip_cmd_data_vel_cmd
,
674 &hf_cip_cmd_data_acc_cmd
,
675 &hf_cip_cmd_data_trq_cmd
,
676 &hf_cip_cmd_data_unwind_cycle_count
,
677 &hf_cip_cmd_data_pos_displacement
,
681 proto_tree_add_bitmask(tree
, tvb
, offset
, hf_cip_cmd_data_set
, ett_command_data_set
, bits
, ENC_LITTLE_ENDIAN
);
686 static int dissect_command_control(packet_info
*pinfo _U_
, proto_tree
*tree
, proto_item
*item _U_
, tvbuff_t
*tvb
,
687 int offset
, int total_len _U_
)
689 static int* const bits
[] = {
691 &hf_cip_position_data_type
,
695 proto_tree_add_bitmask(tree
, tvb
, offset
, hf_cip_command_control
, ett_command_control
, bits
, ENC_LITTLE_ENDIAN
);
700 static int dissect_status_data_set_bits(packet_info
*pinfo _U_
, proto_tree
*tree
, proto_item
*item _U_
, tvbuff_t
*tvb
,
701 int offset
, int total_len _U_
)
703 static int* const bits
[] = {
708 &hf_cip_sts_axis_safety
,
712 proto_tree_add_bitmask(tree
, tvb
, offset
, hf_cip_sts_data_set
, ett_status_data_set
, bits
, ENC_LITTLE_ENDIAN
);
717 static int dissect_node_control(packet_info
*pinfo _U_
, proto_tree
*tree
, proto_item
*item _U_
, tvbuff_t
*tvb
,
718 int offset
, int total_len _U_
)
720 static int* const bits
[] = {
721 &hf_cip_node_control_remote
,
722 &hf_cip_node_control_sync
,
723 &hf_cip_node_data_valid
,
724 &hf_cip_node_fault_reset
,
728 proto_tree_add_bitmask(tree
, tvb
, offset
, hf_cip_node_control
, ett_node_control
, bits
, ENC_LITTLE_ENDIAN
);
733 static int dissect_node_status(packet_info
*pinfo _U_
, proto_tree
*tree
, proto_item
*item _U_
, tvbuff_t
*tvb
,
734 int offset
, int total_len _U_
)
736 static int* const bits
[] = {
737 &hf_cip_node_control_remote
,
738 &hf_cip_node_control_sync
,
739 &hf_cip_node_data_valid
,
740 &hf_cip_node_device_faulted
,
744 proto_tree_add_bitmask(tree
, tvb
, offset
, hf_cip_node_status
, ett_node_status
, bits
, ENC_LITTLE_ENDIAN
);
749 static int dissect_time_data_set(packet_info
*pinfo _U_
, proto_tree
*tree
, proto_item
*item _U_
, tvbuff_t
*tvb
,
750 int offset
, int total_len _U_
)
752 static int* const bits
[] = {
753 &hf_cip_time_data_stamp
,
754 &hf_cip_time_data_offset
,
755 &hf_cip_time_data_diag
,
756 &hf_cip_time_data_time_diag
,
760 proto_tree_add_bitmask(tree
, tvb
, offset
, hf_cip_time_data_set
, ett_time_data_set
, bits
, ENC_LITTLE_ENDIAN
);
765 static int dissect_control_status(packet_info
*pinfo _U_
, proto_tree
*tree
, proto_item
*item _U_
, tvbuff_t
*tvb
,
766 int offset
, int total_len _U_
)
768 static int* const bits
[] = {
769 &hf_cip_control_status_complete
,
770 &hf_cip_control_status_bus_up
,
771 &hf_cip_control_status_bus_unload
,
772 &hf_cip_control_status_power_loss
,
776 proto_tree_add_bitmask(tree
, tvb
, offset
, hf_cip_control_status
, ett_control_status
, bits
, ENC_LITTLE_ENDIAN
);
781 static int dissect_feedback_mode(packet_info
*pinfo _U_
, proto_tree
*tree
, proto_item
*item _U_
, tvbuff_t
*tvb
,
782 int offset
, int total_len _U_
)
784 static int* const bits
[] = {
785 &hf_cip_feedback_mode
,
786 &hf_cip_feedback_data_type
,
790 proto_tree_add_bitmask(tree
, tvb
, offset
, hf_cip_feedback
, ett_feedback_mode
, bits
, ENC_LITTLE_ENDIAN
);
795 static int dissect_connection_configuration_bits(packet_info
* pinfo _U_
, proto_tree
* tree
, proto_item
* item _U_
, tvbuff_t
* tvb
,
796 int offset
, int total_len _U_
)
798 static int* const bits
[] = {
799 &hf_connection_configuration_bits_power
,
800 &hf_connection_configuration_bits_safety_bit_valid
,
801 &hf_connection_configuration_bits_allow_network_safety
,
805 proto_tree_add_bitmask(tree
, tvb
, offset
, hf_connection_configuration_bits
, ett_connection_configuration_bits
, bits
, ENC_LITTLE_ENDIAN
);
810 const attribute_info_t cip_motion_attribute_vals
[] = {
811 { CI_CLS_MOTION
, CIP_ATTR_CLASS
, 14, -1, "Node Control", cip_dissector_func
, NULL
, dissect_node_control
},
812 { CI_CLS_MOTION
, CIP_ATTR_CLASS
, 15, -1, "Node Status", cip_dissector_func
, NULL
, dissect_node_status
},
813 { CI_CLS_MOTION
, CIP_ATTR_CLASS
, 31, -1, "Time Data Set", cip_dissector_func
, NULL
, dissect_time_data_set
},
814 { CI_CLS_MOTION
, CIP_ATTR_CLASS
, 34, -1, "Drive Power Structure Class ID", cip_udint
, &hf_configuration_block_drive_power_struct_id
, NULL
},
815 { CI_CLS_MOTION
, CIP_ATTR_CLASS
, 36, -1, "Connection Configuration Bits", cip_dissector_func
, NULL
, dissect_connection_configuration_bits
},
816 { CI_CLS_MOTION
, CIP_ATTR_INSTANCE
, 40, -1, "Control Mode", cip_usint
, &hf_cip_motor_cntrl
, NULL
},
817 { CI_CLS_MOTION
, CIP_ATTR_INSTANCE
, 42, -1, "Feedback Mode", cip_dissector_func
, NULL
, dissect_feedback_mode
},
818 { CI_CLS_MOTION
, CIP_ATTR_INSTANCE
, 60, -1, "Event Checking Control", cip_dissector_func
, NULL
, dissect_event_checking_control
},
819 { CI_CLS_MOTION
, CIP_ATTR_INSTANCE
, 61, -1, "Event Checking Status", cip_dissector_func
, NULL
, dissect_event_checking_status
},
820 { CI_CLS_MOTION
, CIP_ATTR_INSTANCE
, 89, -1, "Control Status", cip_dissector_func
, NULL
, dissect_control_status
},
821 { CI_CLS_MOTION
, CIP_ATTR_INSTANCE
, 90, -1, "Actual Data Set", cip_dissector_func
, NULL
, dissect_actual_data_set_bits
},
822 { CI_CLS_MOTION
, CIP_ATTR_INSTANCE
, 91, -1, "Command Data Set", cip_dissector_func
, NULL
, dissect_command_data_set_bits
},
823 { CI_CLS_MOTION
, CIP_ATTR_INSTANCE
, 92, -1, "Command Control", cip_dissector_func
, NULL
, dissect_command_control
},
824 { CI_CLS_MOTION
, CIP_ATTR_INSTANCE
, 94, -1, "Status Data Set", cip_dissector_func
, NULL
, dissect_status_data_set_bits
},
825 { CI_CLS_MOTION
, CIP_ATTR_INSTANCE
, 431, -1, "Position Trim", cip_dint
, &hf_cip_pos_trim
, NULL
},
826 { CI_CLS_MOTION
, CIP_ATTR_INSTANCE
, 451, -1, "Velocity Trim", cip_real
, &hf_cip_vel_trim
, NULL
},
827 { CI_CLS_MOTION
, CIP_ATTR_INSTANCE
, 481, -1, "Acceleration Trim", cip_real
, &hf_cip_accel_trim
, NULL
},
828 { CI_CLS_MOTION
, CIP_ATTR_INSTANCE
, 491, -1, "Torque Trim", cip_real
, &hf_cip_trq_trim
, NULL
},
829 { CI_CLS_MOTION
, CIP_ATTR_INSTANCE
, 651, -1, "Axis Status", cip_dissector_func
, NULL
, dissect_axis_status
},
830 { CI_CLS_MOTION
, CIP_ATTR_INSTANCE
, 740, -1, "Axis Status 2", cip_dissector_func
, NULL
, dissect_axis_status2
},
834 * Function name: dissect_cmd_data_set
836 * Purpose: Dissect the "Cyclic Command Data" of a Controller-to-Device format message
838 * Based on the Command Data Set bits of the Cyclic Command Data Block header, display
839 * any of those command values.
841 * Returns: The number of bytes in the cyclic data used
844 dissect_cmd_data_set(uint32_t cmd_data_set
, proto_tree
* parent_tree
, tvbuff_t
* tvb
, uint32_t offset
, bool lreal_pos
)
846 // If no Command Data Set bits are set, then we don't need to display any additional data.
847 if (cmd_data_set
== 0)
852 uint32_t bytes_used
= 0;
855 proto_tree
* tree
= proto_tree_add_subtree(parent_tree
, tvb
, offset
, 0, ett_cyclic_command_data
, &item
, "Cyclic Command Data");
857 /* The order of these if statements is VERY important, this is the order the values will
858 * appear in the cyclic data */
859 if ( (cmd_data_set
& COMMAND_DATA_SET_POSITION
) == COMMAND_DATA_SET_POSITION
)
861 /* Based on the Command Position Data Type value embedded in the Command Control
862 * header field the position is either 64-bit floating or 32-bit integer */
865 /* Display the command data set position command value */
866 proto_tree_add_item(tree
, hf_cip_pos_cmd
, tvb
, offset
+ bytes_used
, 8, ENC_LITTLE_ENDIAN
);
871 /* Display the command data set position command value */
872 proto_tree_add_item(tree
, hf_cip_pos_cmd_int
, tvb
, offset
+ bytes_used
, 4, ENC_LITTLE_ENDIAN
);
877 if ( (cmd_data_set
& COMMAND_DATA_SET_VELOCITY
) == COMMAND_DATA_SET_VELOCITY
)
879 /* Display the command data set velocity command value */
880 proto_tree_add_item(tree
, hf_cip_vel_cmd
, tvb
, offset
+ bytes_used
, 4, ENC_LITTLE_ENDIAN
);
884 if ( (cmd_data_set
& COMMAND_DATA_SET_ACCELERATION
) == COMMAND_DATA_SET_ACCELERATION
)
886 /* Display the command data set acceleration command value */
887 proto_tree_add_item(tree
, hf_cip_accel_cmd
, tvb
, offset
+ bytes_used
, 4, ENC_LITTLE_ENDIAN
);
891 if ( (cmd_data_set
& COMMAND_DATA_SET_TORQUE
) == COMMAND_DATA_SET_TORQUE
)
893 /* Display the command data set torque command value */
894 proto_tree_add_item(tree
, hf_cip_trq_cmd
, tvb
, offset
+ bytes_used
, 4, ENC_LITTLE_ENDIAN
);
898 proto_item_set_len(item
, bytes_used
);
905 * Function name: dissect_act_data_set
907 * Purpose: Dissect the "Cyclic Actual Data" of a Device-to-Controller format message
909 * Based on the Actual Data Set bits of the "Cyclic Actual Data Block" header, display
910 * any of those feedback values.
912 * Returns: The number of bytes in the cyclic data used
915 dissect_act_data_set(uint32_t act_data_set
, proto_tree
* parent_tree
, tvbuff_t
* tvb
, uint32_t offset
, uint8_t feedback_mode
)
917 // If no Actual Data Set bits are set, then we don't need to display any additional data.
918 if (act_data_set
== 0)
923 uint32_t bytes_used
= 0;
926 proto_tree
* tree
= proto_tree_add_subtree(parent_tree
, tvb
, offset
, 0, ett_cyclic_command_data
, &item
, "Cyclic Actual Data");
928 /* The order of these if statements is VERY important, this is the order the values will
929 * appear in the cyclic data */
930 if ( (act_data_set
& ACTUAL_DATA_SET_POSITION
) == ACTUAL_DATA_SET_POSITION
)
932 /* Display the actual data set position feedback value in either 32 or 64 bit */
933 bool is_64_bit_position
= (feedback_mode
& FEEDBACK_DATA_TYPE_BITS
) == 0x10;
934 if (is_64_bit_position
)
936 proto_tree_add_item(tree
, hf_cip_act_pos_64
, tvb
, offset
+ bytes_used
, 8, ENC_LITTLE_ENDIAN
);
941 proto_tree_add_item(tree
, hf_cip_act_pos
, tvb
, offset
+ bytes_used
, 4, ENC_LITTLE_ENDIAN
);
946 if ( (act_data_set
& ACTUAL_DATA_SET_VELOCITY
) == ACTUAL_DATA_SET_VELOCITY
)
948 /* Display the actual data set velocity feedback value */
949 proto_tree_add_item(tree
, hf_cip_act_vel
, tvb
, offset
+ bytes_used
, 4, ENC_LITTLE_ENDIAN
);
953 if ( (act_data_set
& ACTUAL_DATA_SET_ACCELERATION
) == ACTUAL_DATA_SET_ACCELERATION
)
955 /* Display the actual data set acceleration feedback value */
956 proto_tree_add_item(tree
, hf_cip_act_accel
, tvb
, offset
+ bytes_used
, 4, ENC_LITTLE_ENDIAN
);
961 proto_item_set_len(item
, bytes_used
);
967 * Function name: dissect_status_data_set
969 * Purpose: Dissect the "Cyclic Status Data" of a Device-to-Controller format message
971 * Based on the Status Data Set bits of the "Cyclic Actual Data Block" header, display
972 * any of those status values.
974 * Returns: The number of bytes in the cyclic data used
977 dissect_status_data_set(uint32_t status_data_set
, proto_tree
* parent_tree
, tvbuff_t
* tvb
, uint32_t offset
)
979 // If no Status Data Set bits are set, then we don't need to display any additional data.
980 if (status_data_set
== 0)
985 uint32_t bytes_used
= 0;
988 proto_tree
* tree
= proto_tree_add_subtree(parent_tree
, tvb
, offset
, 0, ett_cyclic_command_data
, &item
, "Cyclic Status Data");
990 /* The order of these if statements is VERY important, this is the order the values will
991 * appear in the cyclic data */
992 if ( (status_data_set
& STATUS_DATA_SET_AXIS_FAULT
) == STATUS_DATA_SET_AXIS_FAULT
)
994 /* Display the various fault codes from the device */
995 proto_tree_add_item(tree
, hf_cip_fault_type
, tvb
, offset
+ bytes_used
, 1, ENC_LITTLE_ENDIAN
);
998 proto_tree_add_item(tree
, hf_cip_axis_fault
, tvb
, offset
+ bytes_used
, 1, ENC_LITTLE_ENDIAN
);
1001 proto_tree_add_item(tree
, hf_cip_fault_sub_code
, tvb
, offset
+ bytes_used
, 1, ENC_LITTLE_ENDIAN
);
1004 proto_tree_add_item(tree
, hf_cip_fault_action
, tvb
, offset
+ bytes_used
, 1, ENC_LITTLE_ENDIAN
);
1007 proto_tree_add_item(tree
, hf_cip_fault_time_stamp
, tvb
, offset
+ bytes_used
, 8, ENC_LITTLE_ENDIAN
);
1011 if ( (status_data_set
& STATUS_DATA_SET_AXIS_ALARM
) == STATUS_DATA_SET_AXIS_ALARM
)
1013 /* Display the various alarm codes from the device */
1014 proto_tree_add_item(tree
, hf_cip_alarm_type
, tvb
, offset
+ bytes_used
, 1, ENC_LITTLE_ENDIAN
);
1017 proto_tree_add_item(tree
, hf_cip_axis_alarm
, tvb
, offset
+ bytes_used
, 1, ENC_LITTLE_ENDIAN
);
1020 proto_tree_add_item(tree
, hf_cip_alarm_sub_code
, tvb
, offset
+ bytes_used
, 1, ENC_LITTLE_ENDIAN
);
1023 proto_tree_add_item(tree
, hf_cip_alarm_state
, tvb
, offset
+ bytes_used
, 1, ENC_LITTLE_ENDIAN
);
1026 proto_tree_add_item(tree
, hf_cip_alarm_time_stamp
, tvb
, offset
+ bytes_used
, 8, ENC_LITTLE_ENDIAN
);
1030 if ( (status_data_set
& STATUS_DATA_SET_AXIS_STATUS
) == STATUS_DATA_SET_AXIS_STATUS
)
1032 /* Display the various axis state values from the device */
1033 bytes_used
+= dissect_axis_status(NULL
, tree
, NULL
, tvb
, offset
+ bytes_used
, 4);
1035 proto_tree_add_item(tree
, hf_cip_axis_status_mfg
, tvb
, offset
+ bytes_used
, 4, ENC_LITTLE_ENDIAN
);
1039 if ( (status_data_set
& STATUS_DATA_SET_AXIS_IO_STATUS
) == STATUS_DATA_SET_AXIS_IO_STATUS
)
1041 proto_tree_add_item(tree
, hf_cip_axis_io_status
, tvb
, offset
+ bytes_used
, 4, ENC_LITTLE_ENDIAN
);
1044 proto_tree_add_item(tree
, hf_cip_axis_io_status_mfg
, tvb
, offset
+ bytes_used
, 4, ENC_LITTLE_ENDIAN
);
1048 if ( (status_data_set
& STATUS_DATA_SET_AXIS_SAFETY
) == STATUS_DATA_SET_AXIS_SAFETY
)
1050 proto_tree_add_item(tree
, hf_cip_axis_safety_status
, tvb
, offset
+ bytes_used
, 4, ENC_LITTLE_ENDIAN
);
1052 proto_tree_add_item(tree
, hf_cip_axis_safety_status_mfg
, tvb
, offset
+ bytes_used
, 4, ENC_LITTLE_ENDIAN
);
1054 proto_tree_add_item(tree
, hf_cip_axis_safety_state
, tvb
, offset
+ bytes_used
, 1, ENC_LITTLE_ENDIAN
);
1058 proto_item_set_len(item
, bytes_used
);
1064 * Function name: dissect_cntr_cyclic
1066 * Purpose: Dissect the "Cyclic Command Data Block" of a Controller-to-Device format message
1068 * Returns: The new offset into the message that follow on dissections should use
1069 * as their starting offset
1072 dissect_cntr_cyclic(tvbuff_t
* tvb
, proto_tree
* tree
, uint32_t offset
, uint32_t size
)
1074 /* Create the tree for the entire instance data header */
1075 proto_tree
* header_tree
= proto_tree_add_subtree(tree
, tvb
, offset
, size
, ett_cyclic_data_block
, NULL
, "Cyclic Command Data Block");
1077 proto_tree_add_item(header_tree
, hf_cip_motor_cntrl
, tvb
, offset
, 1, ENC_LITTLE_ENDIAN
);
1078 dissect_feedback_mode(NULL
, header_tree
, NULL
, tvb
, offset
+ 1, 1);
1079 proto_tree_add_item(header_tree
, hf_cip_axis_control
, tvb
, offset
+ 2, 1, ENC_LITTLE_ENDIAN
);
1080 dissect_control_status(NULL
, header_tree
, NULL
, tvb
, offset
+ 3, 1);
1082 dissect_command_data_set_bits(NULL
, header_tree
, NULL
, tvb
, offset
+ 4, 1);
1083 dissect_actual_data_set_bits(NULL
, header_tree
, NULL
, tvb
, offset
+ 5, 1);
1084 dissect_status_data_set_bits(NULL
, header_tree
, NULL
, tvb
, offset
+ 6, 1);
1085 dissect_command_control(NULL
, header_tree
, NULL
, tvb
, offset
+ 7, 1);
1087 uint32_t bytes_used
= 8;
1089 /* Determine if the dissector should be using an LREAL or DINT for position */
1090 uint8_t command_control
= tvb_get_uint8(tvb
, offset
+ 7);
1091 bool lreal_pos
= ((command_control
& COMMAND_CONTROL_POSITION_DATA_TYPE
) == POSITION_DATA_LREAL
);
1093 /* Cyclic Command Data: Display the command data values from the cyclic data payload, the
1094 * cyclic data starts immediately after the interpolation control field in the controller to device
1096 uint32_t command_data_set
= tvb_get_uint8(tvb
, offset
+ 4);
1097 bytes_used
+= dissect_cmd_data_set(command_data_set
, header_tree
, tvb
, offset
+ bytes_used
, lreal_pos
);
1099 /* Return the offset to the next byte in the message */
1100 return offset
+ bytes_used
;
1104 * Function name: dissect_device_cyclic
1106 * Purpose: Dissect the "Cyclic Actual Data Block" of a Device-to-Controller format message
1108 * Returns: The new offset into the message that follow on dissections should use
1109 * as their starting offset
1112 dissect_device_cyclic(tvbuff_t
* tvb
, proto_tree
* tree
, uint32_t offset
, uint32_t size
)
1114 /* Create the tree for the entire instance data header */
1115 proto_tree
* header_tree
= proto_tree_add_subtree(tree
, tvb
, offset
, size
, ett_cyclic_data_block
, NULL
, "Cyclic Actual Data Block");
1117 proto_tree_add_item(header_tree
, hf_cip_motor_cntrl
, tvb
, offset
, 1, ENC_LITTLE_ENDIAN
);
1118 dissect_feedback_mode(NULL
, header_tree
, NULL
, tvb
, offset
+ 1, 1);
1119 proto_tree_add_item(header_tree
, hf_cip_axis_response
, tvb
, offset
+ 2, 1, ENC_LITTLE_ENDIAN
);
1120 proto_tree_add_item(header_tree
, hf_cip_axis_resp_stat
, tvb
, offset
+ 3, 1, ENC_LITTLE_ENDIAN
);
1122 dissect_actual_data_set_bits(NULL
, header_tree
, NULL
, tvb
, offset
+ 5, 1);
1123 dissect_status_data_set_bits(NULL
, header_tree
, NULL
, tvb
, offset
+ 6, 1);
1124 proto_tree_add_item(header_tree
, hf_cip_axis_state
, tvb
, offset
+ 7, 1, ENC_LITTLE_ENDIAN
);
1126 uint32_t bytes_used
= 8;
1128 /* Display the "Cyclic Actual Data" values from the cyclic data payload. */
1129 uint8_t feedback_mode
= tvb_get_uint8(tvb
, offset
+ 1);
1130 uint8_t actual_data_set
= tvb_get_uint8(tvb
, offset
+ 5);
1131 bytes_used
+= dissect_act_data_set(actual_data_set
, header_tree
, tvb
, offset
+ bytes_used
, feedback_mode
);
1133 /* Display the "Cyclic Status Data" values from the cyclic data payload. */
1134 uint8_t status_data_set
= tvb_get_uint8(tvb
, offset
+ 6);
1135 bytes_used
+= dissect_status_data_set(status_data_set
, header_tree
, tvb
, offset
+ bytes_used
);
1137 /* Return the offset to the next byte in the message */
1138 return offset
+ bytes_used
;
1142 * Function name: dissect_cyclic_wt
1144 * Purpose: Dissect the "Cyclic Write Data Block" in a Controller-to-Device message
1146 * Returns: The new offset into the message that follow on dissections should use
1147 * as their starting offset
1150 dissect_cyclic_wt(tvbuff_t
* tvb
, proto_tree
* tree
, uint32_t offset
, uint32_t size
)
1152 proto_tree
*header_tree
;
1154 /* Create the tree for the entire cyclic write data block */
1155 header_tree
= proto_tree_add_subtree(tree
, tvb
, offset
, size
, ett_cyclic_rd_wt
, NULL
, "Cyclic Write Data Block");
1157 /* Display the cyclic write block id value */
1158 proto_tree_add_item(header_tree
, hf_cip_cyclic_write_blk
, tvb
, offset
, 1, ENC_LITTLE_ENDIAN
);
1160 /* Display the cyclic read block id value */
1161 proto_tree_add_item(header_tree
, hf_cip_cyclic_read_blk
, tvb
, offset
+ 2, 1, ENC_LITTLE_ENDIAN
);
1163 /* Display the remainder of the cyclic write data if there is any */
1164 if ( (size
- 4) > 0 )
1166 proto_tree_add_item(header_tree
, hf_cip_cyclic_wrt_data
, tvb
, offset
+ 4, size
- 4, ENC_NA
);
1169 return offset
+ size
;
1173 * Function name: dissect_cyclic_rd
1175 * Purpose: Dissect the "Cyclic Read Data Block" in a Device-to-Controller message
1177 * Returns: The new offset into the message that follow on dissections should use
1178 * as their starting offset
1181 dissect_cyclic_rd(tvbuff_t
* tvb
, proto_tree
* tree
, uint32_t offset
, uint32_t size
)
1183 proto_tree
*header_tree
;
1185 /* Create the tree for the entire cyclic write data block */
1186 header_tree
= proto_tree_add_subtree(tree
, tvb
, offset
, size
, ett_cyclic_rd_wt
, NULL
, "Cyclic Read Data Block");
1188 /* Display the cyclic write block id value */
1189 proto_tree_add_item(header_tree
, hf_cip_cyclic_write_blk
, tvb
, offset
, 1, ENC_LITTLE_ENDIAN
);
1191 /* Display the cyclic write status value */
1192 proto_tree_add_item(header_tree
, hf_cip_cyclic_write_sts
, tvb
, offset
+ 1, 1, ENC_LITTLE_ENDIAN
);
1194 /* Display the cyclic read block id value */
1195 proto_tree_add_item(header_tree
, hf_cip_cyclic_read_blk
, tvb
, offset
+ 2, 1, ENC_LITTLE_ENDIAN
);
1197 /* Display the cyclic read status value */
1198 proto_tree_add_item(header_tree
, hf_cip_cyclic_read_sts
, tvb
, offset
+ 3, 1, ENC_LITTLE_ENDIAN
);
1200 /* Display the remainder of the cyclic read data if there is any*/
1203 proto_tree_add_item(header_tree
, hf_cip_cyclic_rd_data
, tvb
, offset
+ 4, size
- 4, ENC_NA
);
1206 return offset
+ size
;
1210 * Function name: dissect_cntr_event
1212 * Purpose: Dissect the "Event Data Block" in a Controller-to-Device message
1214 * Returns: The new offset into the message that follow on dissections should use
1215 * as their starting offset
1218 dissect_cntr_event(tvbuff_t
* tvb
, proto_tree
* tree
, uint32_t offset
, uint32_t size
)
1220 proto_tree
*header_tree
;
1221 uint32_t acks
, cur_ack
;
1222 uint32_t bytes_used
= 0;
1224 /* Create the tree for the entire cyclic write data block */
1225 header_tree
= proto_tree_add_subtree(tree
, tvb
, offset
, size
, ett_event
, NULL
, "Event Data Block");
1227 uint32_t event_checking_control
= tvb_get_letohl(tvb
, offset
);
1228 dissect_event_checking_control(NULL
, header_tree
, NULL
, tvb
, offset
, 4);
1230 /* The event checking control value is 4 bytes long */
1233 /* The final 4 bits of the event checking control value are the number of acknowledgements in the message */
1234 acks
= (event_checking_control
>> 28) & 0x0F;
1236 /* Each acknowledgement contains and id and a status value */
1237 for (cur_ack
= 0; cur_ack
< acks
; cur_ack
++)
1239 /* Display the current acknowledgement id */
1240 proto_tree_add_item(header_tree
, hf_cip_event_ack
, tvb
, offset
+ bytes_used
, 1, ENC_LITTLE_ENDIAN
);
1243 /* Display the current event status */
1244 proto_tree_add_item(header_tree
, hf_cip_evnt_sts_stat
, tvb
, offset
+ bytes_used
, 1, ENC_LITTLE_ENDIAN
);
1248 return offset
+ size
;
1252 * Function name: dissect_devce_event
1254 * Purpose: Dissect the "Event Data Block" in a Device-to-Controller message
1256 * Returns: The new offset into the message that follow on dissections should use
1257 * as their starting offset
1260 dissect_devce_event(tvbuff_t
* tvb
, proto_tree
* tree
, uint32_t offset
, uint32_t size
)
1262 proto_tree
*header_tree
;
1263 uint64_t nots
, cur_not
;
1264 uint32_t bytes_used
= 0;
1266 /* Create the tree for the entire cyclic write data block */
1267 header_tree
= proto_tree_add_subtree(tree
, tvb
, offset
, size
, ett_event
, NULL
, "Event Data Block");
1269 uint32_t event_checking_status
= tvb_get_letohl(tvb
, offset
);
1270 dissect_event_checking_status(NULL
, header_tree
, NULL
, tvb
, offset
, 4);
1272 /* The event status control value is 4 bytes long */
1275 /* The final 4 bits of the event status control value are the number of notifications in the message */
1276 nots
= (event_checking_status
>> 28) & 0x0F;
1278 /* Each notification contains and id, status value, event type, position and time stamp */
1279 for (cur_not
= 0; cur_not
< nots
; cur_not
++)
1281 /* Display the current event id */
1282 proto_tree_add_item(header_tree
, hf_cip_event_id
, tvb
, offset
+ bytes_used
, 1, ENC_LITTLE_ENDIAN
);
1285 /* Display the current event status */
1286 proto_tree_add_item(header_tree
, hf_cip_evnt_sts_stat
, tvb
, offset
+ bytes_used
, 1, ENC_LITTLE_ENDIAN
);
1289 /* Display the current event type */
1290 proto_tree_add_item(header_tree
, hf_cip_evnt_type
, tvb
, offset
+ bytes_used
, 1, ENC_LITTLE_ENDIAN
);
1291 bytes_used
+= 2; /* Increment by 2 to jump the reserved byte */
1293 /* Display the event position value */
1294 proto_tree_add_item(header_tree
, hf_cip_event_pos
, tvb
, offset
+ bytes_used
, 4, ENC_LITTLE_ENDIAN
);
1297 /* Display the event time stamp value */
1298 proto_tree_add_item(header_tree
, hf_cip_event_ts
, tvb
, offset
+ bytes_used
, 8, ENC_LITTLE_ENDIAN
);
1302 return size
+ offset
;
1306 * Function name: dissect_get_axis_attr_list_request
1308 * Purpose: Dissect the get axis attribute list service request
1313 dissect_get_axis_attr_list_request(tvbuff_t
* tvb
, proto_tree
* tree
, uint32_t offset
, uint32_t size
, uint32_t instance_id
)
1315 proto_item
*attr_item
;
1316 proto_tree
*header_tree
, *attr_tree
;
1317 uint32_t local_offset
;
1319 /* Create the tree for the get axis attribute list request */
1320 header_tree
= proto_tree_add_subtree(tree
, tvb
, offset
, size
, ett_get_axis_attribute
, NULL
, "Get Axis Attribute List Request");
1322 /* Read the number of attributes that are contained within the request */
1323 uint32_t attribute_cnt
;
1324 proto_tree_add_item_ret_uint(header_tree
, hf_get_axis_attr_list_attribute_cnt
, tvb
, offset
, 2, ENC_LITTLE_ENDIAN
, &attribute_cnt
);
1326 /* Start the attribute loop at the beginning of the first attribute in the list */
1327 local_offset
= offset
+ 4;
1329 /* For each attribute display the associated fields */
1330 for (uint32_t attribute
= 0; attribute
< attribute_cnt
; attribute
++)
1332 /* At a minimum the local offset needs will need to be incremented by 4 bytes to reach the next attribute */
1333 uint8_t increment_size
= 4;
1335 /* Create the tree for this attribute within the request */
1336 uint32_t attribute_id
;
1337 attr_item
= proto_tree_add_item_ret_uint(header_tree
, hf_get_axis_attr_list_attribute_id
, tvb
, local_offset
, 2, ENC_LITTLE_ENDIAN
, &attribute_id
);
1338 attr_tree
= proto_item_add_subtree(attr_item
, ett_get_axis_attr_list
);
1341 proto_tree_add_item_ret_uint(attr_tree
, hf_get_axis_attr_list_dimension
, tvb
, local_offset
+ 2, 1, ENC_LITTLE_ENDIAN
, &dimension
);
1342 proto_tree_add_item(attr_tree
, hf_get_axis_attr_list_element_size
, tvb
, local_offset
+ 3, 1, ENC_LITTLE_ENDIAN
);
1346 /* Display the start index and start index from the request */
1347 proto_tree_add_item(attr_tree
, hf_get_axis_attr_list_start_index
, tvb
, local_offset
+ 4, 2, ENC_LITTLE_ENDIAN
);
1348 proto_tree_add_item(attr_tree
, hf_get_axis_attr_list_data_elements
, tvb
, local_offset
+ 6, 2, ENC_LITTLE_ENDIAN
);
1350 /* Modify the amount to update the local offset by and the start of the data to include the index and elements field */
1351 increment_size
+= 4;
1354 const attribute_info_t
* pattribute
= cip_get_attribute(CI_CLS_MOTION
, instance_id
, attribute_id
);
1355 if (pattribute
!= NULL
)
1357 proto_item_append_text(attr_item
, " (%s)", pattribute
->text
);
1360 /* Move the local offset to the next attribute */
1361 local_offset
+= increment_size
;
1365 static int dissect_motion_attribute(packet_info
*pinfo
, tvbuff_t
* tvb
, int offset
, uint32_t attribute_id
,
1366 uint32_t instance_id
, proto_item
* attr_item
, proto_tree
* attr_tree
, uint8_t dimension
, uint32_t attribute_size
)
1368 const attribute_info_t
* pattribute
= cip_get_attribute(CI_CLS_MOTION
, instance_id
, attribute_id
);
1371 if (pattribute
!= NULL
)
1373 proto_item_append_text(attr_item
, " (%s)", pattribute
->text
);
1375 // TODO: Handle more dimensions. Unsure about the format when there is more than 1 item.
1378 parsed_len
= dissect_cip_attribute(pinfo
, attr_tree
, attr_item
, tvb
, pattribute
, offset
, attribute_size
);
1386 * Function name: dissect_set_axis_attr_list_request
1388 * Purpose: Dissect the set axis attribute list service request
1393 dissect_set_axis_attr_list_request(packet_info
*pinfo
, tvbuff_t
* tvb
, proto_tree
* tree
, uint32_t offset
, uint32_t size
, uint32_t instance_id
)
1395 proto_item
*attr_item
;
1396 proto_tree
*header_tree
, *attr_tree
;
1397 uint32_t local_offset
;
1399 /* Create the tree for the set axis attribute list request */
1400 header_tree
= proto_tree_add_subtree(tree
, tvb
, offset
, size
, ett_set_axis_attribute
, NULL
, "Set Axis Attribute List Request");
1402 /* Read the number of attributes that are contained within the request */
1403 uint32_t attribute_cnt
;
1404 proto_tree_add_item_ret_uint(header_tree
, hf_set_axis_attr_list_attribute_cnt
, tvb
, offset
, 2, ENC_LITTLE_ENDIAN
, &attribute_cnt
);
1406 /* Start the attribute loop at the beginning of the first attribute in the list */
1407 local_offset
= offset
+ 4;
1409 /* For each attribute display the associated fields */
1410 for (uint32_t attribute
= 0; attribute
< attribute_cnt
; attribute
++)
1412 /* At a minimum the local offset needs to be incremented by 4 bytes to reach the next attribute */
1413 uint8_t increment_size
= 4;
1415 /* Pull the fields for this attribute from the payload, all fields are needed to make some calculations before
1416 * properly displaying of the attribute is possible */
1417 uint8_t attribute_start
= 4;
1419 /* Create the tree for this attribute in the get axis attribute list request */
1420 uint32_t attribute_id
;
1421 attr_item
= proto_tree_add_item_ret_uint(header_tree
, hf_set_axis_attr_list_attribute_id
, tvb
, local_offset
, 2, ENC_LITTLE_ENDIAN
, &attribute_id
);
1422 attr_tree
= proto_item_add_subtree(attr_item
, ett_set_axis_attr_list
);
1425 proto_tree_add_item_ret_uint(attr_tree
, hf_set_axis_attr_list_dimension
, tvb
, local_offset
+ 2, 1, ENC_LITTLE_ENDIAN
, &dimension
);
1427 uint32_t attribute_size
;
1428 proto_tree_add_item_ret_uint(attr_tree
, hf_set_axis_attr_list_element_size
, tvb
, local_offset
+ 3, 1, ENC_LITTLE_ENDIAN
, &attribute_size
);
1432 uint32_t data_elements
;
1434 /* Display the start index and start index from the request if the request is an array */
1435 proto_tree_add_item(attr_tree
, hf_set_axis_attr_list_start_index
, tvb
, local_offset
+ 4, 2, ENC_LITTLE_ENDIAN
);
1436 proto_tree_add_item_ret_uint(attr_tree
, hf_set_axis_attr_list_data_elements
, tvb
, local_offset
+ 6, 2, ENC_LITTLE_ENDIAN
, &data_elements
);
1438 /* Modify the size of the attribute data by the number of elements if the request is an array request */
1439 attribute_size
*= data_elements
;
1441 /* Modify the amount to update the local offset by and the start of the data to include the index and elements field */
1442 increment_size
+= 4;
1443 attribute_start
+= 4;
1446 int parsed_len
= dissect_motion_attribute(pinfo
, tvb
, local_offset
+ attribute_start
, attribute_id
,
1447 instance_id
, attr_item
, attr_tree
, dimension
, attribute_size
);
1449 // Display the raw attribute data if configured. Otherwise, just show the remaining unparsed data.
1450 if (display_full_attribute_data
)
1452 proto_tree_add_item(attr_tree
, hf_cip_attribute_data
, tvb
, local_offset
+ attribute_start
, attribute_size
, ENC_NA
);
1454 else if ((attribute_size
- parsed_len
) > 0)
1456 proto_tree_add_item(attr_tree
, hf_cip_attribute_data
, tvb
, local_offset
+ attribute_start
+ parsed_len
, attribute_size
- parsed_len
, ENC_NA
);
1459 /* Round the attribute size up so the next attribute lines up on a 32-bit boundary */
1460 if (attribute_size
% 4 != 0)
1462 attribute_size
= attribute_size
+ (4 - (attribute_size
% 4));
1465 /* Move the local offset to the next attribute */
1466 local_offset
+= (attribute_size
+ increment_size
);
1471 * Function name: dissect_group_sync_request
1473 * Purpose: Dissect the group sync service request
1478 dissect_group_sync_request (tvbuff_t
* tvb
, proto_tree
* tree
, uint32_t offset
, uint32_t size
)
1480 proto_tree
*header_tree
;
1482 /* Create the tree for the group sync request */
1483 header_tree
= proto_tree_add_subtree(tree
, tvb
, offset
, size
, ett_group_sync
, NULL
, "Group Sync Request");
1485 /* Read the grandmaster id from the payload */
1486 proto_tree_add_item(header_tree
, hf_cip_ptp_grandmaster
, tvb
, offset
, 8, ENC_LITTLE_ENDIAN
);
1489 static void dissect_set_cyclic_list_request(tvbuff_t
* tvb
, proto_tree
* tree
, uint32_t offset
, uint32_t size
, uint32_t instance_id
, const char* service_name
)
1491 proto_tree
* header_tree
= proto_tree_add_subtree(tree
, tvb
, offset
, size
, ett_set_cyclic_list
, NULL
, service_name
);
1493 uint32_t attribute_cnt
;
1494 proto_tree_add_item_ret_uint(header_tree
, hf_set_cyclic_list_attribute_cnt
, tvb
, offset
, 2, ENC_LITTLE_ENDIAN
, &attribute_cnt
);
1496 // Skip Number of Attributes and Reserved field.
1499 for (uint32_t attribute
= 0; attribute
< attribute_cnt
; attribute
++)
1501 uint32_t attribute_id
;
1502 proto_item
* attr_item
= proto_tree_add_item_ret_uint(header_tree
, hf_set_cyclic_list_attribute_id
, tvb
, offset
, 2, ENC_LITTLE_ENDIAN
, &attribute_id
);
1504 const attribute_info_t
* pattribute
= cip_get_attribute(CI_CLS_MOTION
, instance_id
, attribute_id
);
1505 if (pattribute
!= NULL
)
1507 proto_item_append_text(attr_item
, " (%s)", pattribute
->text
);
1514 static void dissect_set_cyclic_list_respone(tvbuff_t
* tvb
, proto_tree
* tree
, uint32_t offset
, uint32_t size
, uint32_t instance_id
, const char* service_name
)
1516 proto_tree
* header_tree
= proto_tree_add_subtree(tree
, tvb
, offset
, size
, ett_set_cyclic_list
, NULL
, service_name
);
1518 uint32_t attribute_cnt
;
1519 proto_tree_add_item_ret_uint(header_tree
, hf_set_cyclic_list_attribute_cnt
, tvb
, offset
, 2, ENC_LITTLE_ENDIAN
, &attribute_cnt
);
1521 proto_tree_add_item(header_tree
, hf_set_cyclic_list_read_block_id
, tvb
, offset
+ 2, 2, ENC_LITTLE_ENDIAN
);
1523 // Skip Number of Attributes and Cyclic Read Block ID field.
1526 for (uint32_t attribute
= 0; attribute
< attribute_cnt
; attribute
++)
1528 uint32_t attribute_id
;
1529 proto_item
* attr_item
= proto_tree_add_item_ret_uint(header_tree
, hf_set_cyclic_list_attribute_id
, tvb
, offset
, 2, ENC_LITTLE_ENDIAN
, &attribute_id
);
1531 const attribute_info_t
* pattribute
= cip_get_attribute(CI_CLS_MOTION
, instance_id
, attribute_id
);
1532 if (pattribute
!= NULL
)
1534 proto_item_append_text(attr_item
, " (%s)", pattribute
->text
);
1539 proto_tree_add_item(header_tree
, hf_set_cyclic_list_attr_sts
, tvb
, offset
, 1, ENC_LITTLE_ENDIAN
);
1541 // Skip over Attribute Status and Reserved field.
1547 * Function name: dissect_cntr_service
1549 * Purpose: Dissect the "Service Data Block" in a Controller-to-Device message
1551 * Returns: The new offset into the message that follow on dissections should use
1552 * as their starting offset
1555 dissect_cntr_service(tvbuff_t
* tvb
, packet_info
* pinfo
, proto_tree
* tree
, uint32_t offset
, uint32_t size
, uint32_t instance_id
)
1557 proto_tree
*header_tree
;
1560 /* Create the tree for the entire service data block */
1562 header_tree
= proto_tree_add_subtree(tree
, tvb
, offset
, size
, ett_service
, &item
, "Service Data Block");
1564 /* Display the transaction id value */
1565 proto_tree_add_item(header_tree
, hf_cip_svc_transction
, tvb
, offset
, 1, ENC_LITTLE_ENDIAN
);
1567 /* Display the service code */
1568 proto_tree_add_item_ret_uint(header_tree
, hf_cip_svc_code
, tvb
, offset
+ 1, 1, ENC_LITTLE_ENDIAN
, &service
);
1570 /* If the service is a set axis, get axis attribute or group sync request dissect it as well */
1575 case SC_GET_AXIS_ATTRIBUTE_LIST
:
1576 dissect_get_axis_attr_list_request(tvb
, header_tree
, offset
+ 4, size
- 4, instance_id
);
1578 case SC_SET_AXIS_ATTRIBUTE_LIST
:
1579 dissect_set_axis_attr_list_request(pinfo
, tvb
, header_tree
, offset
+ 4, size
- 4, instance_id
);
1582 dissect_group_sync_request(tvb
, header_tree
, offset
+ 4, size
- 4);
1584 case SC_SET_CYCLIC_WRITE_LIST
:
1585 dissect_set_cyclic_list_request(tvb
, header_tree
, offset
+ 4, size
- 4, instance_id
, "Set Cyclic Write List Request");
1587 case SC_SET_CYCLIC_READ_LIST
:
1588 dissect_set_cyclic_list_request(tvb
, header_tree
, offset
+ 4, size
- 4, instance_id
, "Set Cyclic Read List Request");
1590 case SC_SET_ATT_LIST
:
1592 cip_simple_request_info_t motion_path
;
1593 motion_path
.iClass
= CI_CLS_MOTION
;
1594 motion_path
.iInstance
= instance_id
;
1596 tvbuff_t
* tvb_set_attr
= tvb_new_subset_length(tvb
, offset
+ 4, size
- 4);
1597 int parsed_len
= dissect_cip_set_attribute_list_req(tvb_set_attr
, pinfo
, header_tree
, item
, 0, &motion_path
);
1599 // Display any remaining unparsed data.
1600 int remain_len
= tvb_reported_length_remaining(tvb
, offset
+ 4 + parsed_len
);
1603 proto_tree_add_item(header_tree
, hf_cip_attribute_data
, tvb
, offset
+ 4 + parsed_len
, size
- 4 - parsed_len
, ENC_NA
);
1609 /* Display the remainder of the service channel data */
1610 proto_tree_add_item(header_tree
, hf_cip_svc_data
, tvb
, offset
+ 4, size
- 4, ENC_NA
);
1614 return offset
+ size
;
1618 * Function name: dissect_set_axis_attr_list_response
1620 * Purpose: Dissect the set axis attribute list service response
1625 dissect_set_axis_attr_list_response(tvbuff_t
* tvb
, proto_tree
* tree
, uint32_t offset
, uint32_t size
, uint32_t instance_id
)
1627 proto_item
*attr_item
;
1628 proto_tree
*header_tree
, *attr_tree
;
1629 uint32_t local_offset
;
1631 /* Create the tree for the set axis attribute list response */
1632 header_tree
= proto_tree_add_subtree(tree
, tvb
, offset
, size
, ett_get_axis_attribute
, NULL
, "Set Axis Attribute List Response");
1634 /* Read the number of attributes that are contained within the response */
1635 uint32_t attribute_cnt
;
1636 proto_tree_add_item_ret_uint(header_tree
, hf_set_axis_attr_list_attribute_cnt
, tvb
, offset
, 2, ENC_LITTLE_ENDIAN
, &attribute_cnt
);
1638 /* Start the attribute loop at the beginning of the first attribute in the list */
1639 local_offset
= offset
+ 4;
1641 /* For each attribute display the associated fields */
1642 for (uint32_t attribute
= 0; attribute
< attribute_cnt
; attribute
++)
1644 /* Create the tree for the current attribute in the set axis attribute list response */
1645 uint32_t attribute_id
;
1646 attr_item
= proto_tree_add_item_ret_uint(header_tree
, hf_set_axis_attr_list_attribute_id
, tvb
, local_offset
, 2, ENC_LITTLE_ENDIAN
, &attribute_id
);
1647 attr_tree
= proto_item_add_subtree(attr_item
, ett_get_axis_attr_list
);
1649 /* Add the response status to the tree */
1650 proto_tree_add_item(attr_tree
, hf_cip_svc_set_axis_attr_sts
, tvb
, local_offset
+ 2, 1, ENC_LITTLE_ENDIAN
);
1652 const attribute_info_t
* pattribute
= cip_get_attribute(CI_CLS_MOTION
, instance_id
, attribute_id
);
1653 if (pattribute
!= NULL
)
1655 proto_item_append_text(attr_item
, " (%s)", pattribute
->text
);
1658 /* Move the local offset to the next attribute */
1664 * Function name: dissect_get_axis_attr_list_response
1666 * Purpose: Dissect the get axis attribute list service response
1671 dissect_get_axis_attr_list_response(packet_info
* pinfo
, tvbuff_t
* tvb
, proto_tree
* tree
, uint32_t offset
, uint32_t size
, uint32_t instance_id
)
1673 proto_item
*attr_item
;
1674 proto_tree
*header_tree
, *attr_tree
;
1675 uint32_t local_offset
;
1677 /* Create the tree for the get axis attribute list response */
1678 header_tree
= proto_tree_add_subtree(tree
, tvb
, offset
, size
, ett_get_axis_attribute
, NULL
, "Get Axis Attribute List Response");
1680 /* Read the number of attributes that are contained within the request */
1681 uint32_t attribute_cnt
;
1682 proto_tree_add_item_ret_uint(header_tree
, hf_get_axis_attr_list_attribute_cnt
, tvb
, offset
, 2, ENC_LITTLE_ENDIAN
, &attribute_cnt
);
1684 /* Start the attribute loop at the beginning of the first attribute in the list */
1685 local_offset
= offset
+ 4;
1687 /* For each attribute display the associated fields */
1688 for (uint32_t attribute
= 0; attribute
< attribute_cnt
; attribute
++)
1690 /* At a minimum the local offset needs to be incremented by 4 bytes to reach the next attribute */
1691 uint8_t increment_size
= 4;
1693 /* Pull the fields for this attribute from the payload, all fields are needed to make some calculations before
1694 * properly displaying of the attribute is possible */
1695 uint8_t dimension
= tvb_get_uint8(tvb
, local_offset
+ 2);
1696 uint32_t attribute_size
= tvb_get_uint8(tvb
, local_offset
+ 3);
1697 uint8_t attribute_start
= 4;
1701 uint16_t data_elements
= tvb_get_letohs(tvb
, local_offset
+ 6);
1703 /* Modify the size of the attribute data by the number of elements if the request is an array request */
1704 attribute_size
*= data_elements
;
1706 /* Modify the amount to update the local offset by and the start of the data to include the index and elements field */
1707 increment_size
+= 4;
1708 attribute_start
+= 4;
1711 /* Display the fields associated with the get axis attribute list response */
1712 uint32_t attribute_id
;
1713 attr_item
= proto_tree_add_item_ret_uint(header_tree
, hf_get_axis_attr_list_attribute_id
, tvb
, local_offset
, 2, ENC_LITTLE_ENDIAN
, &attribute_id
);
1714 attr_tree
= proto_item_add_subtree(attr_item
, ett_get_axis_attr_list
);
1716 if (dimension
== 0xFF)
1718 /* Display the element size as an error code if the dimension field indicates an error */
1719 proto_tree_add_item(attr_tree
, hf_cip_svc_get_axis_attr_sts
, tvb
, local_offset
+ 3, 1, ENC_LITTLE_ENDIAN
);
1721 /* No attribute data so no attribute size */
1726 proto_tree_add_item(attr_tree
, hf_get_axis_attr_list_dimension
, tvb
, local_offset
+ 2, 1, ENC_LITTLE_ENDIAN
);
1727 proto_tree_add_item(attr_tree
, hf_get_axis_attr_list_element_size
, tvb
, local_offset
+ 3, 1, ENC_LITTLE_ENDIAN
);
1731 /* Display the start index and start index from the request */
1732 proto_tree_add_item(attr_tree
, hf_get_axis_attr_list_start_index
, tvb
, local_offset
+ 4, 2, ENC_LITTLE_ENDIAN
);
1733 proto_tree_add_item(attr_tree
, hf_get_axis_attr_list_data_elements
, tvb
, local_offset
+ 6, 2, ENC_LITTLE_ENDIAN
);
1736 int parsed_len
= dissect_motion_attribute(pinfo
, tvb
, local_offset
+ attribute_start
, attribute_id
,
1737 instance_id
, attr_item
, attr_tree
, dimension
, attribute_size
);
1739 // Display the raw attribute data if configured. Otherwise, just show the remaining unparsed data
1740 if (display_full_attribute_data
)
1742 proto_tree_add_item(attr_tree
, hf_cip_attribute_data
, tvb
, local_offset
+ attribute_start
, attribute_size
, ENC_NA
);
1744 else if ((attribute_size
- parsed_len
) > 0)
1746 proto_tree_add_item(attr_tree
, hf_cip_attribute_data
, tvb
, local_offset
+ attribute_start
+ parsed_len
, attribute_size
- parsed_len
, ENC_NA
);
1749 /* Round the attribute size up so the next attribute lines up on a 32-bit boundary */
1750 if (attribute_size
% 4 != 0)
1752 attribute_size
= attribute_size
+ (4 - (attribute_size
% 4));
1756 /* Move the local offset to the next attribute */
1757 local_offset
+= (attribute_size
+ increment_size
);
1762 * Function name: dissect_group_sync_response
1764 * Purpose: Dissect the group sync service response
1769 dissect_group_sync_response (tvbuff_t
* tvb
, proto_tree
* tree
, uint32_t offset
)
1771 proto_tree_add_item(tree
, hf_cip_group_sync
, tvb
, offset
, 1, ENC_LITTLE_ENDIAN
);
1775 * Function name: dissect_devce_service
1777 * Purpose: Dissect the "Service Data Block" in a Device-to-Controller message
1779 * Returns: The new offset into the message that follow on dissections should use
1780 * as their starting offset
1783 dissect_devce_service(tvbuff_t
* tvb
, packet_info
* pinfo
, proto_tree
* tree
, uint32_t offset
, uint32_t size
, uint32_t instance_id
)
1785 proto_tree
*header_tree
;
1787 /* Create the tree for the entire service data block */
1789 header_tree
= proto_tree_add_subtree(tree
, tvb
, offset
, size
, ett_service
, &item
, "Service Data Block");
1791 /* Display the transaction id value */
1792 proto_tree_add_item(header_tree
, hf_cip_svc_transction
, tvb
, offset
, 1, ENC_LITTLE_ENDIAN
);
1794 /* Display the service code */
1795 uint32_t service_code
;
1796 proto_tree_add_item_ret_uint(header_tree
, hf_cip_svc_code
, tvb
, offset
+ 1, 1, ENC_LITTLE_ENDIAN
, &service_code
);
1798 /* Display the general status code */
1799 proto_tree_add_item(header_tree
, hf_cip_svc_sts
, tvb
, offset
+ 2, 1, ENC_LITTLE_ENDIAN
);
1801 /* Display the extended status code */
1802 proto_tree_add_item(header_tree
, hf_cip_svc_ext_status
, tvb
, offset
+ 3, 1, ENC_LITTLE_ENDIAN
);
1804 /* If the service is a set axis, get axis attribute response or group sync dissect it as well */
1807 switch (service_code
)
1809 case SC_GET_AXIS_ATTRIBUTE_LIST
:
1810 dissect_get_axis_attr_list_response(pinfo
, tvb
, header_tree
, offset
+ 4, size
- 4, instance_id
);
1812 case SC_SET_AXIS_ATTRIBUTE_LIST
:
1813 dissect_set_axis_attr_list_response(tvb
, header_tree
, offset
+ 4, size
- 4, instance_id
);
1816 dissect_group_sync_response(tvb
, header_tree
, offset
+ 4);
1818 case SC_SET_CYCLIC_WRITE_LIST
:
1819 dissect_set_cyclic_list_respone(tvb
, header_tree
, offset
+ 4, size
- 4, instance_id
, "Set Cyclic Write List Response");
1821 case SC_SET_CYCLIC_READ_LIST
:
1822 dissect_set_cyclic_list_respone(tvb
, header_tree
, offset
+ 4, size
- 4, instance_id
, "Set Cyclic Read List Response");
1824 case SC_SET_ATT_LIST
:
1826 cip_simple_request_info_t motion_path
;
1827 motion_path
.iClass
= CI_CLS_MOTION
;
1828 motion_path
.iInstance
= instance_id
;
1830 tvbuff_t
* tvb_set_attr
= tvb_new_subset_length(tvb
, offset
+ 4, size
- 4);
1831 dissect_cip_set_attribute_list_rsp(tvb_set_attr
, pinfo
, header_tree
, item
, 0, &motion_path
);
1835 /* Display the remainder of the service channel data */
1836 proto_tree_add_item(header_tree
, hf_cip_svc_data
, tvb
, offset
+ 4, size
- 4, ENC_NA
);
1841 return offset
+ size
;
1845 * Function name: dissect_var_inst_header
1847 * Purpose: Dissect the instance data header of a variable controller to device or
1848 * device to controller message
1853 dissect_var_inst_header(tvbuff_t
* tvb
, proto_tree
* tree
, uint32_t offset
, uint8_t* inst_number
, uint32_t* cyc_size
,
1854 uint32_t* cyc_blk_size
, uint32_t* evnt_size
, uint32_t* servc_size
)
1856 proto_tree
*header_tree
;
1858 /* Create the tree for the entire instance data header */
1859 *inst_number
= tvb_get_uint8(tvb
, offset
);
1861 header_tree
= proto_tree_add_subtree_format(tree
, tvb
, offset
, 8, ett_inst_data_header
, NULL
,
1862 "Instance Data Header - Instance: %d", *inst_number
);
1864 /* Read the instance number field from the instance data header */
1865 proto_tree_add_item(header_tree
, hf_var_devce_instance
, tvb
, offset
, 1, ENC_LITTLE_ENDIAN
);
1867 /* The "size" fields in the instance data block header are all stored as number of 32-bit words the
1868 * block uses since all blocks should pad up to 32-bits so to convert to bytes each is multiplied by 4 */
1870 /* Read the instance block size field in bytes from the instance data header */
1871 proto_tree_add_item(header_tree
, hf_var_devce_instance_block_size
, tvb
, offset
+ 2, 1, ENC_NA
);
1873 /* Read the cyclic block size field in bytes from the instance data header */
1874 proto_tree_add_item(header_tree
, hf_var_devce_cyclic_block_size
, tvb
, offset
+ 3, 1, ENC_NA
);
1876 /* Read the cyclic command block size field in bytes from the instance data header */
1877 *cyc_size
= (tvb_get_uint8(tvb
, offset
+ 4) * 4);
1878 proto_tree_add_item(header_tree
, hf_var_devce_cyclic_data_block_size
, tvb
, offset
+ 4, 1, ENC_NA
);
1880 /* Read the cyclic write block size field in bytes from the instance data header */
1881 *cyc_blk_size
= (tvb_get_uint8(tvb
, offset
+ 5) * 4);
1882 proto_tree_add_item(header_tree
, hf_var_devce_cyclic_rw_block_size
, tvb
, offset
+ 5, 1, ENC_NA
);
1884 /* Read the event block size in bytes from the instance data header */
1885 *evnt_size
= (tvb_get_uint8(tvb
, offset
+ 6) * 4);
1886 proto_tree_add_item(header_tree
, hf_var_devce_event_block_size
, tvb
, offset
+ 6, 1, ENC_NA
);
1888 /* Read the service block size in bytes from the instance data header */
1889 *servc_size
= (tvb_get_uint8(tvb
, offset
+ 7) * 4);
1890 proto_tree_add_item(header_tree
, hf_var_devce_service_block_size
, tvb
, offset
+ 7, 1, ENC_NA
);
1894 * Function name: dissect_var_cont_conn_header
1896 * Purpose: Dissect the connection header of a variable controller to device message
1898 * Returns: Offset to the start of the instance data block
1901 dissect_var_cont_conn_header(tvbuff_t
* tvb
, proto_tree
* tree
, uint32_t* inst_count
, uint32_t offset
)
1903 uint32_t header_size
;
1904 proto_tree
*header_tree
;
1906 /* Calculate the header size, start with the basic header size */
1909 uint32_t time_data_set
= tvb_get_uint8(tvb
, offset
+ 7);
1911 /* Check the time data set field for enabled bits. If either update period or
1912 * update time stamp fields are set, bump the header size by the appropriate size */
1913 if ( (time_data_set
& TIME_DATA_SET_TIME_STAMP
) == TIME_DATA_SET_TIME_STAMP
)
1917 if ( (time_data_set
& TIME_DATA_SET_TIME_OFFSET
) == TIME_DATA_SET_TIME_OFFSET
)
1922 /* Create the tree for the entire connection header */
1923 header_tree
= proto_tree_add_subtree(tree
, tvb
, offset
, header_size
, ett_cont_dev_header
, NULL
, "Connection Header");
1925 /* Add the connection header fields that are common to all types of messages */
1926 proto_tree_add_item(header_tree
, hf_cip_format
, tvb
, offset
, 1, ENC_LITTLE_ENDIAN
);
1927 proto_tree_add_item(header_tree
, hf_cip_revision
, tvb
, offset
+ 1, 1, ENC_LITTLE_ENDIAN
);
1928 proto_tree_add_item(header_tree
, hf_cip_updateid
, tvb
, offset
+ 2, 1, ENC_LITTLE_ENDIAN
);
1930 dissect_node_control(NULL
, header_tree
, NULL
, tvb
, offset
+ 3, 1);
1932 /* Add the instance count and last update id to the connection header tree */
1933 proto_tree_add_item_ret_uint(header_tree
, hf_cip_instance_cnt
, tvb
, offset
+ 4, 1, ENC_LITTLE_ENDIAN
, inst_count
);
1934 proto_tree_add_item(header_tree
, hf_cip_last_update
, tvb
, offset
+ 6, 1, ENC_LITTLE_ENDIAN
);
1936 dissect_time_data_set(NULL
, header_tree
, NULL
, tvb
, offset
+ 7, 1);
1938 /* Move the offset to the byte just beyond the time data set field */
1939 offset
= (offset
+ 7 + 1);
1941 /* Add the time values if they are present in the time data set header field */
1942 if ( (time_data_set
& TIME_DATA_SET_TIME_STAMP
) == TIME_DATA_SET_TIME_STAMP
)
1944 proto_tree_add_item(header_tree
, hf_cip_cont_time_stamp
, tvb
, offset
, 8, ENC_LITTLE_ENDIAN
);
1945 offset
= (offset
+ 8);
1948 if ( (time_data_set
& TIME_DATA_SET_TIME_OFFSET
) == TIME_DATA_SET_TIME_OFFSET
)
1950 proto_tree_add_item(header_tree
, hf_cip_cont_time_offset
, tvb
, offset
, 8, ENC_LITTLE_ENDIAN
);
1951 offset
= (offset
+ 8);
1954 /* Return the number of bytes used so it can be used as an offset in the following dissections */
1959 * Function name: dissect_var_devce_conn_header
1961 * Purpose: Dissect the connection header of a variable device to controller message
1963 * Returns: Offset to the start of the instance data block
1966 dissect_var_devce_conn_header(tvbuff_t
* tvb
, proto_tree
* tree
, uint32_t* inst_count
, uint32_t offset
)
1968 uint32_t header_size
;
1969 proto_tree
*header_tree
;
1971 /* Calculate the header size, start with the basic header size */
1974 uint32_t time_data_set
= tvb_get_uint8(tvb
, offset
+ 7);
1975 if ( (time_data_set
& TIME_DATA_SET_TIME_STAMP
) == TIME_DATA_SET_TIME_STAMP
)
1979 if ( (time_data_set
& TIME_DATA_SET_TIME_OFFSET
) == TIME_DATA_SET_TIME_OFFSET
)
1983 if ( (time_data_set
& TIME_DATA_SET_UPDATE_DIAGNOSTICS
) == TIME_DATA_SET_UPDATE_DIAGNOSTICS
)
1987 if ( (time_data_set
& TIME_DATA_SET_TIME_DIAGNOSTICS
) == TIME_DATA_SET_TIME_DIAGNOSTICS
)
1992 /* Create the tree for the entire connection header */
1993 header_tree
= proto_tree_add_subtree(tree
, tvb
, offset
, header_size
, ett_cont_dev_header
, NULL
, "Connection Header");
1995 /* Add the connection header fields that are common to all types of messages */
1996 proto_tree_add_item(header_tree
, hf_cip_format
, tvb
, offset
, 1, ENC_LITTLE_ENDIAN
);
1997 proto_tree_add_item(header_tree
, hf_cip_revision
, tvb
, offset
+ 1, 1, ENC_LITTLE_ENDIAN
);
1998 proto_tree_add_item(header_tree
, hf_cip_updateid
, tvb
, offset
+ 2, 1, ENC_LITTLE_ENDIAN
);
2000 dissect_node_status(NULL
, header_tree
, NULL
, tvb
, offset
+ 3, 1);
2002 /* Add the instance count to the connection header tree */
2003 proto_tree_add_item_ret_uint(header_tree
, hf_cip_instance_cnt
, tvb
, offset
+ 4, 1, ENC_LITTLE_ENDIAN
, inst_count
);
2005 /* The device to controller header contains the node alarms and node faults fields as well. */
2006 proto_tree_add_item(header_tree
, hf_cip_node_fltalarms
, tvb
, offset
+ 5, 1, ENC_LITTLE_ENDIAN
);
2008 /* Add the last update id to the connection header tree */
2009 proto_tree_add_item(header_tree
, hf_cip_last_update
, tvb
, offset
+ 6, 1, ENC_LITTLE_ENDIAN
);
2011 dissect_time_data_set(NULL
, header_tree
, NULL
, tvb
, offset
+ 7, 1);
2013 /* Move the offset to the byte just beyond the time data set field */
2014 offset
= (offset
+ 7 + 1);
2016 /* Add the time values if they are present in the time data set header field */
2017 if ( (time_data_set
& TIME_DATA_SET_TIME_STAMP
) == TIME_DATA_SET_TIME_STAMP
)
2019 proto_tree_add_item(header_tree
, hf_cip_devc_time_stamp
, tvb
, offset
, 8, ENC_LITTLE_ENDIAN
);
2020 offset
= (offset
+ 8);
2023 if ( (time_data_set
& TIME_DATA_SET_TIME_OFFSET
) == TIME_DATA_SET_TIME_OFFSET
)
2025 proto_tree_add_item(header_tree
, hf_cip_devc_time_offset
, tvb
, offset
, 8, ENC_LITTLE_ENDIAN
);
2026 offset
= (offset
+ 8);
2029 if ( (time_data_set
& TIME_DATA_SET_UPDATE_DIAGNOSTICS
) == TIME_DATA_SET_UPDATE_DIAGNOSTICS
)
2031 /* If the time diagnostic bit is set then the header contains the count of lost updates, late updates, data
2032 * received time stamp and data transmit time stamp */
2033 proto_tree_add_item(header_tree
, hf_cip_lost_update
, tvb
, offset
, 1, ENC_LITTLE_ENDIAN
);
2034 offset
= (offset
+ 1);
2036 /* Add the reserved bytes to the offset after adding the late updates to the display */
2037 proto_tree_add_item(header_tree
, hf_cip_late_update
, tvb
, offset
, 1, ENC_LITTLE_ENDIAN
);
2038 offset
= (offset
+ 3);
2041 if ( (time_data_set
& TIME_DATA_SET_TIME_DIAGNOSTICS
) == TIME_DATA_SET_TIME_DIAGNOSTICS
)
2043 proto_tree_add_item(header_tree
, hf_cip_data_rx_time_stamp
, tvb
, offset
, 8, ENC_LITTLE_ENDIAN
);
2046 proto_tree_add_item(header_tree
, hf_cip_data_tx_time_stamp
, tvb
, offset
, 8, ENC_LITTLE_ENDIAN
);
2050 /* Return the number of bytes used so it can be used as an offset in the following dissections */
2056 * Function name: dissect_cipmotion
2058 * Purpose: Perform the top level dissection of the CIP Motion datagram, it is called by
2059 * Wireshark when the dissection rule registered in proto_reg_handoff_cipmotion is fired
2064 dissect_cipmotion(tvbuff_t
* tvb
, packet_info
* pinfo
, proto_tree
* tree
, void* data
)
2066 cip_io_data_input
* io_data_input
= (cip_io_data_input
*)data
;
2068 uint32_t con_format
;
2070 proto_item
*proto_item_top
;
2071 proto_tree
*proto_tree_top
;
2072 uint32_t offset
= 0;
2074 uint8_t ConnPoint
= 2;
2075 if (io_data_input
&& io_data_input
->conn_info
)
2077 ConnPoint
= io_data_input
->conn_info
->connection_path
.iConnPoint
;
2080 /* Create display subtree for the protocol by creating an item and then
2081 * creating a subtree from the item, the subtree must have been registered
2082 * in proto_register_cipmotion already */
2083 proto_item_top
= proto_tree_add_item(tree
, proto_cipmotion
, tvb
, 0, -1, ENC_NA
);
2084 proto_tree_top
= proto_item_add_subtree(proto_item_top
, ett_cipmotion
);
2086 /* Add the CIP class 1 sequence number to the tree */
2087 proto_tree_add_item(proto_tree_top
, hf_cip_class1_seqnum
, tvb
, offset
, 2, ENC_LITTLE_ENDIAN
);
2088 offset
= (offset
+ 2);
2092 dissect_cip_run_idle(tvb
, offset
, proto_tree_top
);
2096 /* Pull the actual values for the connection format and update id from the
2097 * incoming message to be used in the column info */
2098 con_format
= tvb_get_uint8(tvb
, offset
);
2099 update_id
= tvb_get_uint8(tvb
, offset
+ 2);
2101 /* Make entries in Protocol column and Info column on summary display */
2102 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, "CIP Motion");
2104 /* Add connection format and update number to the info column */
2105 col_add_fstr( pinfo
->cinfo
, COL_INFO
, "%s, Update Id: %d",
2106 val_to_str(con_format
, cip_con_format_vals
, "Unknown connection format (%x)"), update_id
);
2108 /* Attempt to classify the incoming header */
2109 if (( con_format
== FORMAT_VAR_CONTROL_TO_DEVICE
) ||
2110 ( con_format
== FORMAT_VAR_DEVICE_TO_CONTROL
))
2112 /* Sizes of the individual channels within the connection */
2113 uint32_t cyc_size
, cyc_blk_size
, evnt_size
, servc_size
;
2114 uint32_t inst_count
= 0, inst
;
2115 uint32_t format_rev
= 0;
2117 /* Dissect the header fields */
2120 case FORMAT_VAR_CONTROL_TO_DEVICE
:
2121 format_rev
= tvb_get_uint8(tvb
, offset
+ 1);
2122 offset
= dissect_var_cont_conn_header(tvb
, proto_tree_top
, &inst_count
, offset
);
2124 case FORMAT_VAR_DEVICE_TO_CONTROL
:
2125 format_rev
= tvb_get_uint8(tvb
, offset
+ 1);
2126 offset
= dissect_var_devce_conn_header(tvb
, proto_tree_top
, &inst_count
, offset
);
2130 if (format_rev
!= ConnPoint
)
2132 expert_add_info(pinfo
, proto_item_top
, &ei_format_rev_conn_pt
);
2135 /* Repeat the following dissections for each instance within the payload */
2136 for( inst
= 0; inst
< inst_count
; inst
++ )
2138 /* Actual instance number from header field */
2141 /* Dissect the instance data header */
2142 dissect_var_inst_header( tvb
, proto_tree_top
, offset
, &instance
,
2143 &cyc_size
, &cyc_blk_size
, &evnt_size
, &servc_size
);
2145 /* Increment the offset to just beyond the instance header */
2148 /* Dissect the cyclic command (actual) data if any exists */
2149 /* Dissect the cyclic write (read) data if any exists */
2150 /* Dissect the event data block if there is any event data */
2153 case FORMAT_VAR_CONTROL_TO_DEVICE
:
2155 offset
= dissect_cntr_cyclic(tvb
, proto_tree_top
, offset
, cyc_size
);
2156 if ( cyc_blk_size
> 0 )
2157 offset
= dissect_cyclic_wt(tvb
, proto_tree_top
, offset
, cyc_blk_size
);
2158 if ( evnt_size
> 0 )
2159 offset
= dissect_cntr_event(tvb
, proto_tree_top
, offset
, evnt_size
);
2160 if ( servc_size
> 0 )
2161 offset
= dissect_cntr_service(tvb
, pinfo
, proto_tree_top
, offset
, servc_size
, instance
);
2163 case FORMAT_VAR_DEVICE_TO_CONTROL
:
2165 offset
= dissect_device_cyclic(tvb
, proto_tree_top
, offset
, cyc_size
);
2166 if ( cyc_blk_size
> 0 )
2167 offset
= dissect_cyclic_rd( tvb
, proto_tree_top
, offset
, cyc_blk_size
);
2168 if ( evnt_size
> 0 )
2169 offset
= dissect_devce_event(tvb
, proto_tree_top
, offset
, evnt_size
);
2170 if ( servc_size
> 0 )
2171 offset
= dissect_devce_service(tvb
, pinfo
, proto_tree_top
, offset
, servc_size
, instance
);
2175 } /* End of instance for( ) loop */
2178 // Display any remaining unparsed data.
2179 int remain_len
= tvb_reported_length_remaining(tvb
, offset
);
2182 proto_tree_add_item(proto_tree_top
, hf_cip_data
, tvb
, offset
, remain_len
, ENC_NA
);
2185 return tvb_captured_length(tvb
);
2188 static int dissect_cipmotion3(tvbuff_t
* tvb
, packet_info
* pinfo
, proto_tree
* tree
, void* data _U_
)
2190 cip_conn_info_t conn_info
;
2191 memset(&conn_info
, 0, sizeof(conn_info
));
2192 conn_info
.connection_path
.iConnPoint
= 3;
2194 cip_io_data_input io_data_input
;
2195 io_data_input
.conn_info
= &conn_info
;
2197 return dissect_cipmotion(tvb
, pinfo
, tree
, &io_data_input
);
2200 int dissect_motion_configuration_block(tvbuff_t
* tvb
, packet_info
* pinfo
, proto_tree
* tree
, proto_item
* item
, int offset
)
2202 proto_item
* config_item
;
2203 proto_tree
* config_tree
= proto_tree_add_subtree(tree
, tvb
, offset
, 0, ett_configuration_block
, &config_item
, "Motion Configuration Block");
2205 proto_tree_add_item(config_tree
, hf_configuration_block_format_rev
, tvb
, offset
, 1, ENC_LITTLE_ENDIAN
);
2208 parsed_len
+= dissect_connection_configuration_bits(pinfo
, config_tree
, item
, tvb
, offset
+ parsed_len
, 1);
2213 proto_tree_add_item(config_tree
, hf_configuration_block_drive_power_struct_id
, tvb
, offset
+ parsed_len
, 4, ENC_LITTLE_ENDIAN
);
2216 proto_item_set_len(config_item
, parsed_len
);
2222 * Function name: proto_register_cipmotion
2224 * Purpose: Register the protocol with Wireshark, a script will add this protocol
2225 * to the list of protocols during the build process. This function is where the
2226 * header fields and subtree identifiers are registered.
2231 proto_register_cipmotion(void)
2233 /* This is a list of header fields that can be used in the dissection or
2234 * to use in a filter expression */
2235 static hf_register_info hf
[] =
2237 /* Connection format header field, the first byte in the message which
2238 * determines if the message is fixed or variable, controller to device,
2239 * device to controller, etc. */
2241 { "Connection Format", "cipm.format",
2242 FT_UINT8
, BASE_DEC
, VALS(cip_con_format_vals
), 0,
2243 "Message connection format", HFILL
}
2246 /* Connection format revision header field */
2248 { "Format Revision", "cipm.revision",
2249 FT_UINT8
, BASE_DEC
, NULL
, 0,
2250 "Message format revision", HFILL
}
2253 { &hf_cip_class1_seqnum
,
2254 { "CIP Class 1 Sequence Count", "cipm.class1seqnum",
2255 FT_UINT16
, BASE_DEC
, NULL
, 0,
2259 { &hf_configuration_block_format_rev
,
2260 { "Format Revision", "cipm.config.format_rev",
2261 FT_UINT8
, BASE_DEC
, NULL
, 0,
2265 { &hf_configuration_block_drive_power_struct_id
,
2266 { "Drive Power Structure Class ID", "cipm.config.drive_class_id",
2267 FT_UINT32
, BASE_DEC
, NULL
, 0,
2272 { "Update Id", "cipm.updateid",
2273 FT_UINT8
, BASE_DEC
, NULL
, 0,
2274 "Cyclic Transaction Number", HFILL
}
2276 { &hf_cip_instance_cnt
,
2277 { "Instance Count", "cipm.instancecount",
2278 FT_UINT8
, BASE_DEC
, NULL
, 0,
2281 { &hf_cip_last_update
,
2282 { "Last Update Id", "cipm.lastupdate",
2283 FT_UINT8
, BASE_DEC
, NULL
, 0,
2286 { &hf_cip_node_status
,
2287 { "Node Status", "cipm.nodestatus",
2288 FT_UINT8
, BASE_HEX
, NULL
, 0,
2291 { &hf_cip_node_control
,
2292 { "Node Control", "cipm.nodecontrol",
2293 FT_UINT8
, BASE_HEX
, NULL
, 0,
2296 { &hf_cip_node_control_remote
,
2297 { "Remote Control", "cipm.remote",
2298 FT_BOOLEAN
, 8, NULL
, 0x01,
2299 "Node Control: Remote Control", HFILL
}
2301 { &hf_cip_node_control_sync
,
2302 { "Sync Control", "cipm.sync",
2303 FT_BOOLEAN
, 8, NULL
, 0x02,
2304 "Node Control: Synchronous Operation", HFILL
}
2306 { &hf_cip_node_data_valid
,
2307 { "Data Valid", "cipm.valid",
2308 FT_BOOLEAN
, 8, NULL
, 0x04,
2309 "Node Control: Data Valid", HFILL
}
2311 { &hf_cip_node_fault_reset
,
2312 { "Node Fault Reset", "cipm.fltrst",
2313 FT_BOOLEAN
, 8, NULL
, 0x08,
2314 "Node Control: Node Fault Reset", HFILL
}
2316 { &hf_cip_node_device_faulted
,
2317 { "Faulted", "cipm.flt",
2318 FT_BOOLEAN
, 8, NULL
, 0x08,
2319 "Node Control: Device Faulted", HFILL
}
2321 { &hf_cip_node_fltalarms
,
2322 { "Node Faults and Alarms", "cipm.fltalarms",
2323 FT_UINT8
, BASE_DEC
, NULL
, 0,
2326 { &hf_cip_time_data_set
,
2327 { "Time Data Set", "cipm.timedataset",
2328 FT_UINT8
, BASE_HEX
, NULL
, 0,
2331 { &hf_cip_time_data_stamp
,
2332 { "Time Stamp", "cipm.time.stamp",
2333 FT_BOOLEAN
, 8, NULL
, TIME_DATA_SET_TIME_STAMP
,
2334 "Time Data Set: Time Stamp", HFILL
}
2336 { &hf_cip_time_data_offset
,
2337 { "Time Offset", "cipm.time.offset",
2338 FT_BOOLEAN
, 8, NULL
, TIME_DATA_SET_TIME_OFFSET
,
2339 "Time Data Set: Time Offset", HFILL
}
2341 { &hf_cip_time_data_diag
,
2342 { "Update Diagnostics", "cipm.time.update",
2343 FT_BOOLEAN
, 8, NULL
, TIME_DATA_SET_UPDATE_DIAGNOSTICS
,
2344 "Time Data Set: Update Diagnostics", HFILL
}
2346 { &hf_cip_time_data_time_diag
,
2347 { "Time Diagnostics", "cipm.time.diag",
2348 FT_BOOLEAN
, 8, NULL
, TIME_DATA_SET_TIME_DIAGNOSTICS
,
2349 "Time Data Set: Time Diagnostics", HFILL
}
2352 { &hf_cip_cont_time_stamp
,
2353 { "Controller Time Stamp", "cipm.ctrltimestamp",
2354 FT_UINT64
, BASE_DEC
, NULL
, 0,
2355 "Time Data Set: Controller Time Stamp", HFILL
}
2357 { &hf_cip_cont_time_offset
,
2358 { "Controller Time Offset", "cipm.ctrltimeoffser",
2359 FT_UINT64
, BASE_DEC
, NULL
, 0,
2360 "Time Data Set: Controller Time Offset", HFILL
}
2362 { &hf_cip_data_rx_time_stamp
,
2363 { "Data Received Time Stamp", "cipm.rxtimestamp",
2364 FT_UINT64
, BASE_DEC
, NULL
, 0,
2365 "Time Data Set: Data Received Time Stamp", HFILL
}
2367 { &hf_cip_data_tx_time_stamp
,
2368 { "Data Transmit Time Stamp", "cipm.txtimestamp",
2369 FT_UINT64
, BASE_DEC
, NULL
, 0,
2370 "Time Data Set: Data Transmit Time Offset", HFILL
}
2372 { &hf_cip_devc_time_stamp
,
2373 { "Device Time Stamp", "cipm.devctimestamp",
2374 FT_UINT64
, BASE_DEC
|BASE_UNIT_STRING
, UNS(&units_nanosecond_nanoseconds
), 0,
2375 "Time Data Set: Device Time Stamp", HFILL
}
2377 { &hf_cip_devc_time_offset
,
2378 { "Device Time Offset", "cipm.devctimeoffser",
2379 FT_UINT64
, BASE_DEC
, NULL
, 0,
2380 "Time Data Set: Device Time Offset", HFILL
}
2382 { &hf_cip_lost_update
,
2383 { "Lost Updates", "cipm.lostupdates",
2384 FT_UINT8
, BASE_DEC
, NULL
, 0,
2385 "Time Data Set: Lost Updates", HFILL
}
2387 { &hf_cip_late_update
,
2388 { "Lost Updates", "cipm.lateupdates",
2389 FT_UINT8
, BASE_DEC
, NULL
, 0,
2390 "Time Data Set: Late Updates", HFILL
}
2393 { &hf_cip_motor_cntrl
,
2394 { "Control Mode", "cipm.ctrlmode",
2395 FT_UINT8
, BASE_DEC
, VALS(cip_motor_control_vals
), 0,
2396 "Cyclic Data Block: Motor Control Mode", HFILL
}
2400 { "Feedback Information", "cipm.feedback",
2401 FT_UINT8
, BASE_HEX
, NULL
, 0,
2404 { &hf_cip_feedback_mode
,
2405 { "Feedback Mode", "cipm.feedback_mode",
2406 FT_UINT8
, BASE_DEC
, VALS(cip_feedback_mode_vals
), FEEDBACK_MODE_BITS
,
2409 { &hf_cip_feedback_data_type
,
2410 { "Feedback Data Type", "cipm.feedback_data_type",
2411 FT_UINT8
, BASE_DEC
, VALS(cip_feedback_type_vals
), FEEDBACK_DATA_TYPE_BITS
,
2415 { &hf_connection_configuration_bits
,
2416 { "Connection Configuration Bits", "cipm.ccb",
2417 FT_UINT8
, BASE_DEC
, NULL
, 0,
2420 { &hf_connection_configuration_bits_power
,
2421 { "Verify Power Ratings", "cipm.ccb.verify_power_ratings",
2422 FT_BOOLEAN
, 8, NULL
, 0x01,
2424 { &hf_connection_configuration_bits_safety_bit_valid
,
2425 { "Networked Safety Bit Valid", "cipm.ccb.networked_safety_bit_valid",
2426 FT_BOOLEAN
, 8, NULL
, 0x02,
2428 { &hf_connection_configuration_bits_allow_network_safety
,
2429 { "Allow Networked Safety", "cipm.ccb.allow_networked_safety",
2430 FT_BOOLEAN
, 8, NULL
, 0x04,
2433 { &hf_cip_axis_control
,
2434 { "Axis Control", "cipm.axisctrl",
2435 FT_UINT8
, BASE_DEC
, VALS(cip_axis_control_vals
), 0,
2436 "Cyclic Data Block: Axis Control", HFILL
}
2438 { &hf_cip_control_status
,
2439 { "Control Status", "cipm.csts",
2440 FT_UINT8
, BASE_DEC
, NULL
, 0,
2441 "Cyclic Data Block: Axis Control Status", HFILL
}
2443 { &hf_cip_control_status_complete
,
2444 { "Configuration Complete", "cipm.control_status.complete",
2445 FT_BOOLEAN
, 8, NULL
, 0x01,
2447 { &hf_cip_control_status_bus_up
,
2448 { "Converter Bus Up", "cipm.control_status.bus_up",
2449 FT_BOOLEAN
, 8, NULL
, 0x04,
2451 { &hf_cip_control_status_bus_unload
,
2452 { "Converter Bus Unload", "cipm.control_status.bus_unload",
2453 FT_BOOLEAN
, 8, NULL
, 0x08,
2455 { &hf_cip_control_status_power_loss
,
2456 { "Converter AC Power Loss", "cipm.control_status.power_loss",
2457 FT_BOOLEAN
, 8, NULL
, 0x10,
2459 { &hf_cip_axis_response
,
2460 { "Axis Response", "cipm.axisresp",
2461 FT_UINT8
, BASE_DEC
, VALS(cip_axis_response_vals
), 0,
2462 "Cyclic Data Block: Axis Response", HFILL
}
2464 { &hf_cip_axis_resp_stat
,
2465 { "Response Status", "cipm.respstat",
2466 FT_UINT8
, BASE_DEC
|BASE_EXT_STRING
, &cip_gs_vals_ext
, 0,
2467 "Cyclic Data Block: Axis Response Status", HFILL
}
2469 { &hf_cip_group_sync
,
2470 { "Group Sync Status", "cipm.syncstatus",
2471 FT_UINT8
, BASE_HEX
, VALS(cip_sync_status_vals
), 0,
2474 { &hf_cip_cmd_data_set
,
2475 { "Command Data Set", "cipm.cmdset",
2476 FT_UINT8
, BASE_HEX
, NULL
, 0,
2479 { &hf_cip_act_data_set
,
2480 { "Actual Data Set", "cipm.actset",
2481 FT_UINT8
, BASE_HEX
, NULL
, 0,
2484 { &hf_cip_sts_data_set
,
2485 { "Status Data Set", "cipm.stsset",
2486 FT_UINT8
, BASE_HEX
, NULL
, 0,
2491 { &hf_cip_cmd_data_pos_cmd
,
2492 { "Command Position", "cipm.cmd.pos",
2493 FT_BOOLEAN
, 8, NULL
, COMMAND_DATA_SET_POSITION
,
2494 "Command Data Set: Command Position", HFILL
}
2496 { &hf_cip_cmd_data_vel_cmd
,
2497 { "Command Velocity", "cipm.cmd.vel",
2498 FT_BOOLEAN
, 8, NULL
, COMMAND_DATA_SET_VELOCITY
,
2499 "Command Data Set: Command Velocity", HFILL
}
2501 { &hf_cip_cmd_data_acc_cmd
,
2502 { "Command Acceleration", "cipm.cmd.acc",
2503 FT_BOOLEAN
, 8, NULL
, COMMAND_DATA_SET_ACCELERATION
,
2504 "Command Data Set: Command Acceleration", HFILL
}
2506 { &hf_cip_cmd_data_trq_cmd
,
2507 { "Command Torque", "cipm.cmd.trq",
2508 FT_BOOLEAN
, 8, NULL
, COMMAND_DATA_SET_TORQUE
,
2509 "Command Data Set: Command Torque", HFILL
}
2511 { &hf_cip_cmd_data_unwind_cycle_count
,
2512 { "Unwind Cycle Count", "cipm.cmd.unwind",
2513 FT_BOOLEAN
, 8, NULL
, COMMAND_DATA_SET_UNWIND_CYCLE_COUNT
,
2514 "Command Data Set: Unwind Cycle Count", HFILL
}
2516 { &hf_cip_cmd_data_pos_displacement
,
2517 { "Position Displacement", "cipm.cmd.pos_displacement",
2518 FT_BOOLEAN
, 8, NULL
, COMMAND_DATA_SET_POSITION_DISPLACE
,
2519 "Command Data Set: Position Displacement", HFILL
}
2523 { &hf_cip_act_data_pos
,
2524 { "Actual Position", "cipm.act.pos",
2525 FT_BOOLEAN
, 8, NULL
, ACTUAL_DATA_SET_POSITION
,
2526 "Actual Data Set: Actual Position", HFILL
}
2528 { &hf_cip_act_data_vel
,
2529 { "Actual Velocity", "cipm.act.vel",
2530 FT_BOOLEAN
, 8, NULL
, ACTUAL_DATA_SET_VELOCITY
,
2531 "Actual Data Set: Actual Velocity", HFILL
}
2533 { &hf_cip_act_data_acc
,
2534 { "Actual Acceleration", "cipm.act.acc",
2535 FT_BOOLEAN
, 8, NULL
, ACTUAL_DATA_SET_ACCELERATION
,
2536 "Actual Data Set: Actual Acceleration", HFILL
}
2538 { &hf_cip_act_unwind_cycle_count
,
2539 { "Unwind Cycle Count", "cipm.act.unwind",
2540 FT_BOOLEAN
, 8, NULL
, ACTUAL_DATA_SET_UNWIND_CYCLE_COUNT
,
2541 "Actual Data Set: Unwind Cycle Count", HFILL
}
2543 { &hf_cip_act_pos_displacement
,
2544 { "Position Displacement", "cipm.act.pos_displacement",
2545 FT_BOOLEAN
, 8, NULL
, ACTUAL_DATA_SET_POSITION_DISPLACE
,
2546 "Actual Data Set: Position Displacement", HFILL
}
2549 { &hf_cip_axis_fault
,
2550 { "Axis Fault Code", "cipm.fault.code",
2551 FT_UINT8
, BASE_DEC
, NULL
, 0,
2552 "Status Data Set: Fault Code", HFILL
}
2554 { &hf_cip_fault_type
,
2555 { "Axis Fault Type", "cipm.flttype",
2556 FT_UINT8
, BASE_DEC
, NULL
, 0,
2557 "Axis Status: Axis Fault Type", HFILL
}
2559 { &hf_cip_fault_sub_code
,
2560 { "Axis Fault Sub Code", "cipm.fltsubcode",
2561 FT_UINT8
, BASE_DEC
, NULL
, 0,
2562 "Axis Status: Axis Fault Sub Code", HFILL
}
2564 { &hf_cip_fault_action
,
2565 { "Axis Fault Action", "cipm.fltaction",
2566 FT_UINT8
, BASE_DEC
, NULL
, 0,
2567 "Axis Status: Axis Fault Action", HFILL
}
2569 { &hf_cip_fault_time_stamp
,
2570 { "Axis Fault Time Stamp", "cipm.flttimestamp",
2571 FT_UINT64
, BASE_DEC
, NULL
, 0,
2572 "Axis Status: Axis Fault Time Stamp", HFILL
}
2574 { &hf_cip_alarm_type
,
2575 { "Axis Fault Type", "cipm.alarmtype",
2576 FT_UINT8
, BASE_DEC
, NULL
, 0,
2577 "Axis Status: Axis Alarm Type", HFILL
}
2579 { &hf_cip_alarm_sub_code
,
2580 { "Axis Alarm Sub Code", "cipm.alarmsubcode",
2581 FT_UINT8
, BASE_DEC
, NULL
, 0,
2582 "Axis Status: Axis Alarm Sub Code", HFILL
}
2584 { &hf_cip_alarm_state
,
2585 { "Axis Alarm State", "cipm.alarmstate",
2586 FT_UINT8
, BASE_DEC
, NULL
, 0,
2587 "Axis Status: Axis Alarm State", HFILL
}
2589 { &hf_cip_alarm_time_stamp
,
2590 { "Axis Fault Time Stamp", "cipm.alarmtimestamp",
2591 FT_UINT64
, BASE_DEC
, NULL
, 0,
2592 "Axis Status: Axis Alarm Time Stamp", HFILL
}
2594 { &hf_cip_axis_status
,
2595 { "Axis Status", "cipm.axisstatus",
2596 FT_UINT32
, BASE_HEX
, NULL
, 0,
2599 { &hf_cip_axis_status_mfg
,
2600 { "Axis Status Mfg", "cipm.axisstatusmfg",
2601 FT_UINT32
, BASE_HEX
, NULL
, 0,
2602 "Axis Status, Manufacturer Specific", HFILL
}
2604 { &hf_cip_axis_io_status
,
2605 { "Axis I/O Status", "cipm.axisiostatus",
2606 FT_UINT32
, BASE_HEX
, NULL
, 0,
2609 { &hf_cip_axis_io_status_mfg
,
2610 { "Axis I/O Status Mfg", "cipm.axisiostatusmfg",
2611 FT_UINT32
, BASE_HEX
, NULL
, 0,
2612 "Axis I/O Status, Manufacturer Specific", HFILL
}
2614 { &hf_cip_axis_safety_status
,
2615 { "Axis Safety Status", "cipm.safetystatus",
2616 FT_UINT32
, BASE_HEX
, NULL
, 0,
2619 { &hf_cip_axis_safety_status_mfg
,
2620 { "Axis Safety Status Mfg", "cipm.safetystatusmfg",
2621 FT_UINT32
, BASE_HEX
, NULL
, 0,
2622 "Axis Safety Status, Manufacturer Specific", HFILL
}
2624 { &hf_cip_axis_safety_state
,
2625 { "Axis Safety State", "cipm.safetystate",
2626 FT_UINT8
, BASE_HEX
, NULL
, 0,
2627 "Axis Safety Sate", HFILL
}
2630 { "Axis Fault Codes", "cipm.sts.flt",
2631 FT_BOOLEAN
, 8, NULL
, STATUS_DATA_SET_AXIS_FAULT
,
2632 "Status Data Set: Axis Fault Codes", HFILL
}
2635 { "Axis Alarm Codes", "cipm.sts.alarm",
2636 FT_BOOLEAN
, 8, NULL
, STATUS_DATA_SET_AXIS_ALARM
,
2637 "Status Data Set: Axis Alarm Codes", HFILL
}
2640 { "Axis Status", "cipm.sts.sts",
2641 FT_BOOLEAN
, 8, NULL
, STATUS_DATA_SET_AXIS_STATUS
,
2642 "Status Data Set: Axis Status", HFILL
}
2644 { &hf_cip_sts_iosts
,
2645 { "Axis I/O Status", "cipm.sts.iosts",
2646 FT_BOOLEAN
, 8, NULL
, STATUS_DATA_SET_AXIS_IO_STATUS
,
2647 "Status Data Set: Axis I/O Status", HFILL
}
2649 { &hf_cip_sts_axis_safety
,
2650 { "Axis Safety Status", "cipm.sts.safety",
2651 FT_BOOLEAN
, 8, NULL
, STATUS_DATA_SET_AXIS_SAFETY
,
2652 "Status Data Set: Axis Safety Status", HFILL
}
2655 { "Command Target Update", "cipm.intrp",
2656 FT_UINT8
, BASE_DEC
, VALS(cip_interpolation_vals
), COMMAND_CONTROL_TARGET_UPDATE
,
2657 "Cyclic Data Block: Command Target Update", HFILL
}
2659 { &hf_cip_position_data_type
,
2660 { "Command Position Data Type", "cipm.posdatatype",
2661 FT_UINT8
, BASE_DEC
, VALS(cip_pos_data_type_vals
), COMMAND_CONTROL_POSITION_DATA_TYPE
,
2662 "Cyclic Data Block: Command Position Data Type", HFILL
}
2664 { &hf_cip_axis_state
,
2665 { "Axis State", "cipm.axste",
2666 FT_UINT8
, BASE_DEC
, VALS(cip_axis_state_vals
), 0,
2667 "Cyclic Data Block: Axis State", HFILL
}
2669 { &hf_cip_command_control
,
2670 { "Command Control", "cipm.cmdcontrol",
2671 FT_UINT8
, BASE_DEC
, NULL
, 0,
2672 "Cyclic Data Block: Command Control", HFILL
}
2674 { &hf_cip_cyclic_wrt_data
,
2675 { "Write Data", "cipm.writedata",
2676 FT_BYTES
, BASE_NONE
, NULL
, 0,
2677 "Cyclic Write: Data", HFILL
}
2679 { &hf_cip_cyclic_rd_data
,
2680 { "Read Data", "cipm.readdata",
2681 FT_BYTES
, BASE_NONE
, NULL
, 0,
2682 "Cyclic Read: Data", HFILL
}
2684 { &hf_cip_cyclic_write_blk
,
2685 { "Write Block", "cipm.writeblk",
2686 FT_UINT8
, BASE_DEC
, NULL
, 0,
2687 "Cyclic Data Block: Write Block Id", HFILL
}
2689 { &hf_cip_cyclic_read_blk
,
2690 { "Read Block", "cipm.readblk",
2691 FT_UINT8
, BASE_DEC
, NULL
, 0,
2692 "Cyclic Data Block: Read Block Id", HFILL
}
2694 { &hf_cip_cyclic_write_sts
,
2695 { "Write Status", "cipm.writests",
2696 FT_UINT8
, BASE_DEC
, NULL
, 0,
2697 "Cyclic Data Block: Write Status", HFILL
}
2699 { &hf_cip_cyclic_read_sts
,
2700 { "Read Status", "cipm.readsts",
2701 FT_UINT8
, BASE_DEC
, NULL
, 0,
2702 "Cyclic Data Block: Read Status", HFILL
}
2704 { &hf_cip_event_checking
,
2705 { "Event Checking Control", "cipm.evntchkcontrol",
2706 FT_UINT32
, BASE_HEX
, NULL
, 0,
2707 "Event Channel: Event Checking Control", HFILL
}
2709 { &hf_cip_event_ack
,
2710 { "Event Acknowledgement", "cipm.evntack",
2711 FT_UINT8
, BASE_DEC
, NULL
, 0,
2712 "Event Channel: Event Acknowledgement", HFILL
}
2714 { &hf_cip_event_status
,
2715 { "Event Checking Status", "cipm.evntchkstatus",
2716 FT_UINT32
, BASE_HEX
, NULL
, 0,
2717 "Event Channel: Event Checking Status", HFILL
}
2720 { "Event Id", "cipm.evntid",
2721 FT_UINT8
, BASE_DEC
, NULL
, 0,
2722 "Event Channel: Event Id", HFILL
}
2724 { &hf_cip_event_pos
,
2725 { "Event Position", "cipm.evntpos",
2726 FT_INT32
, BASE_DEC
, NULL
, 0,
2727 "Event Channel: Event Position", HFILL
}
2730 { "Event Time Stamp", "cipm.evntimestamp",
2731 FT_UINT64
, BASE_DEC
|BASE_UNIT_STRING
, UNS(&units_nanosecond_nanoseconds
), 0,
2732 "Event Channel: Time Stamp", HFILL
}
2735 { &hf_cip_evnt_ctrl_reg1_pos
,
2736 { "Reg 1 Pos Edge", "cipm.evnt.ctrl.reg1posedge",
2737 FT_BOOLEAN
, 32, NULL
, 0x00000001,
2738 "Event Checking Control: Reg 1 Pos Edge", HFILL
}
2740 { &hf_cip_evnt_ctrl_reg1_neg
,
2741 { "Reg 1 Neg Edge", "cipm.evnt.ctrl.reg1negedge",
2742 FT_BOOLEAN
, 32, NULL
, 0x00000002,
2743 "Event Checking Control: Reg 1 Neg Edge", HFILL
}
2745 { &hf_cip_evnt_ctrl_reg2_pos
,
2746 { "Reg 2 Pos Edge", "cipm.evnt.ctrl.reg2posedge",
2747 FT_BOOLEAN
, 32, NULL
, 0x00000004,
2748 "Event Checking Control: Reg 2 Pos Edge", HFILL
}
2750 { &hf_cip_evnt_ctrl_reg2_neg
,
2751 { "Reg 2 Neg Edge", "cipm.evnt.ctrl.reg2negedge",
2752 FT_BOOLEAN
, 32, NULL
, 0x00000008,
2753 "Event Checking Control: Reg 2 Neg Edge", HFILL
}
2755 { &hf_cip_evnt_ctrl_reg1_posrearm
,
2756 { "Reg 1 Pos Rearm", "cipm.evnt.ctrl.reg1posrearm",
2757 FT_BOOLEAN
, 32, NULL
, 0x00000100,
2758 "Event Checking Control: Reg 1 Pos Rearm", HFILL
}
2760 { &hf_cip_evnt_ctrl_reg1_negrearm
,
2761 { "Reg 1 Neg Rearm", "cipm.evnt.ctrl.reg1negrearm",
2762 FT_BOOLEAN
, 32, NULL
, 0x00000200,
2763 "Event Checking Control: Reg 1 Neg Rearm", HFILL
}
2765 { &hf_cip_evnt_ctrl_reg2_posrearm
,
2766 { "Reg 2 Pos Rearm", "cipm.evnt.ctrl.reg2posrearm",
2767 FT_BOOLEAN
, 32, NULL
, 0x00000400,
2768 "Event Checking Control: Reg 2 Pos Rearm", HFILL
}
2770 { &hf_cip_evnt_ctrl_reg2_negrearm
,
2771 { "Reg 2 Neg Rearm", "cipm.evnt.ctrl.reg2negrearm",
2772 FT_BOOLEAN
, 32, NULL
, 0x00000800,
2773 "Event Checking Control: Reg 2 Neg Rearm", HFILL
}
2775 { &hf_cip_evnt_ctrl_marker_pos
,
2776 { "Marker Pos Edge", "cipm.evnt.ctrl.mrkrpos",
2777 FT_BOOLEAN
, 32, NULL
, 0x00010000,
2778 "Event Checking Control: Marker Pos Edge", HFILL
}
2780 { &hf_cip_evnt_ctrl_marker_neg
,
2781 { "Marker Neg Edge", "cipm.evnt.ctrl.mrkrneg",
2782 FT_BOOLEAN
, 32, NULL
, 0x00020000,
2783 "Event Checking Control: Marker Neg Edge", HFILL
}
2785 { &hf_cip_evnt_ctrl_home_pos
,
2786 { "Home Pos Edge", "cipm.evnt.ctrl.homepos",
2787 FT_BOOLEAN
, 32, NULL
, 0x00040000,
2788 "Event Checking Control: Home Pos Edge", HFILL
}
2790 { &hf_cip_evnt_ctrl_home_neg
,
2791 { "Home Neg Edge", "cipm.evnt.ctrl.homeneg",
2792 FT_BOOLEAN
, 32, NULL
, 0x00080000,
2793 "Event Checking Control: Home Neg Edge", HFILL
}
2795 { &hf_cip_evnt_ctrl_home_pp
,
2796 { "Home-Switch-Marker Plus Plus", "cipm.evnt.ctrl.homepp",
2797 FT_BOOLEAN
, 32, NULL
, 0x00100000,
2798 "Event Checking Control: Home-Switch-Marker Plus Plus", HFILL
}
2800 { &hf_cip_evnt_ctrl_home_pm
,
2801 { "Home-Switch-Marker Plus Minus", "cipm.evnt.ctrl.homepm",
2802 FT_BOOLEAN
, 32, NULL
, 0x00200000,
2803 "Event Checking Control: Home-Switch-Marker Plus Minus", HFILL
}
2805 { &hf_cip_evnt_ctrl_home_mp
,
2806 { "Home-Switch-Marker Minus Plus", "cipm.evnt.ctrl.homemp",
2807 FT_BOOLEAN
, 32, NULL
, 0x00400000,
2808 "Event Checking Control: Home-Switch-Marker Minus Plus", HFILL
}
2810 { &hf_cip_evnt_ctrl_home_mm
,
2811 { "Home-Switch-Marker Minus Minus", "cipm.evnt.ctrl.homemm",
2812 FT_BOOLEAN
, 32, NULL
, 0x00800000,
2813 "Event Checking Control: Home-Switch-Marker Minus Minus", HFILL
}
2815 { &hf_cip_evnt_ctrl_acks
,
2816 { "Event Block Count", "cipm.evnt.ctrl.acks",
2817 FT_UINT32
, BASE_DEC
, NULL
, 0x70000000,
2818 "Event Checking Control: Event Block Count", HFILL
}
2820 { &hf_cip_evnt_extend_format
,
2821 { "Extended Event Format", "cipm.evnt.extend",
2822 FT_BOOLEAN
, 32, NULL
, 0x80000000,
2823 "Event Checking Control: Extended Event Format", HFILL
}
2826 { &hf_cip_evnt_sts_reg1_pos
,
2827 { "Reg 1 Pos Edge", "cipm.evnt.sts.reg1posedge",
2828 FT_BOOLEAN
, 32, NULL
, 0x00000001,
2829 "Event Checking Status: Reg 1 Pos Edge", HFILL
}
2831 { &hf_cip_evnt_sts_reg1_neg
,
2832 { "Reg 1 Neg Edge", "cipm.evnt.sts.reg1negedge",
2833 FT_BOOLEAN
, 32, NULL
, 0x00000002,
2834 "Event Checking Status: Reg 1 Neg Edge", HFILL
}
2836 { &hf_cip_evnt_sts_reg2_pos
,
2837 { "Reg 2 Pos Edge", "cipm.evnt.sts.reg2posedge",
2838 FT_BOOLEAN
, 32, NULL
, 0x00000004,
2839 "Event Checking Status: Reg 2 Pos Edge", HFILL
}
2841 { &hf_cip_evnt_sts_reg2_neg
,
2842 { "Reg 2 Neg Edge", "cipm.evnt.sts.reg2negedge",
2843 FT_BOOLEAN
, 32, NULL
, 0x00000008,
2844 "Event Checking Status: Reg 2 Neg Edge", HFILL
}
2846 { &hf_cip_evnt_sts_reg1_posrearm
,
2847 { "Reg 1 Pos Rearm", "cipm.evnt.sts.reg1posrearm",
2848 FT_BOOLEAN
, 32, NULL
, 0x00000100,
2849 "Event Checking Status: Reg 1 Pos Rearm", HFILL
}
2851 { &hf_cip_evnt_sts_reg1_negrearm
,
2852 { "Reg 1 Neg Rearm", "cipm.evnt.sts.reg1negrearm",
2853 FT_BOOLEAN
, 32, NULL
, 0x00000200,
2854 "Event Checking Status: Reg 1 Neg Rearm", HFILL
}
2856 { &hf_cip_evnt_sts_reg2_posrearm
,
2857 { "Reg 2 Pos Rearm", "cipm.evnt.sts.reg2posrearm",
2858 FT_BOOLEAN
, 32, NULL
, 0x00000400,
2859 "Event Checking Status: Reg 2 Pos Rearm", HFILL
}
2861 { &hf_cip_evnt_sts_reg2_negrearm
,
2862 { "Reg 2 Neg Rearm", "cipm.evnt.sts.reg2negrearm",
2863 FT_BOOLEAN
, 32, NULL
, 0x00000800,
2864 "Event Checking Status: Reg 2 Neg Rearm", HFILL
}
2866 { &hf_cip_evnt_sts_marker_pos
,
2867 { "Marker Pos Edge", "cipm.evnt.sts.mrkrpos",
2868 FT_BOOLEAN
, 32, NULL
, 0x00010000,
2869 "Event Checking Status: Marker Pos Edge", HFILL
}
2871 { &hf_cip_evnt_sts_marker_neg
,
2872 { "Marker Neg Edge", "cipm.evnt.sts.mrkrneg",
2873 FT_BOOLEAN
, 32, NULL
, 0x00020000,
2874 "Event Checking Status: Marker Neg Edge", HFILL
}
2876 { &hf_cip_evnt_sts_home_pos
,
2877 { "Home Pos Edge", "cipm.evnt.sts.homepos",
2878 FT_BOOLEAN
, 32, NULL
, 0x00040000,
2879 "Event Checking Status: Home Pos Edge", HFILL
}
2881 { &hf_cip_evnt_sts_home_neg
,
2882 { "Home Neg Edge", "cipm.evnt.sts.homeneg",
2883 FT_BOOLEAN
, 32, NULL
, 0x00080000,
2884 "Event Checking Status: Home Neg Edge", HFILL
}
2886 { &hf_cip_evnt_sts_home_pp
,
2887 { "Home-Switch-Marker Plus Plus", "cipm.evnt.sts.homepp",
2888 FT_BOOLEAN
, 32, NULL
, 0x00100000,
2889 "Event Checking Status: Home-Switch-Marker Plus Plus", HFILL
}
2891 { &hf_cip_evnt_sts_home_pm
,
2892 { "Home-Switch-Marker Plus Minus", "cipm.evnt.sts.homepm",
2893 FT_BOOLEAN
, 32, NULL
, 0x00200000,
2894 "Event Checking Status: Home-Switch-Marker Plus Minus", HFILL
}
2896 { &hf_cip_evnt_sts_home_mp
,
2897 { "Home-Switch-Marker Minus Plus", "cipm.evnt.sts.homemp",
2898 FT_BOOLEAN
, 32, NULL
, 0x00400000,
2899 "Event Checking Status: Home-Switch-Marker Minus Plus", HFILL
}
2901 { &hf_cip_evnt_sts_home_mm
,
2902 { "Home-Switch-Marker Minus Minus", "cipm.evnt.sts.homemm",
2903 FT_BOOLEAN
, 32, NULL
, 0x00800000,
2904 "Event Checking Status: Home-Switch-Marker Minus Minus", HFILL
}
2906 { &hf_cip_evnt_sts_nfs
,
2907 { "Event Block Count", "cipm.evnt.sts.nfs",
2908 FT_UINT32
, BASE_DEC
, NULL
, 0x70000000,
2909 "Event Checking Status: Event Block Count", HFILL
}
2912 { &hf_cip_evnt_sts_stat
,
2913 { "Event Status", "cipm.evnt.stat",
2914 FT_UINT8
, BASE_DEC
|BASE_EXT_STRING
, &cip_gs_vals_ext
, 0,
2915 "Event Data Block: Event Status", HFILL
}
2917 { &hf_cip_evnt_type
,
2918 { "Event Type", "cipm.evnt.type",
2919 FT_UINT8
, BASE_DEC
, VALS(cip_event_type_vals
), 0,
2920 "Event Data Block: Event Type", HFILL
}
2923 { "Service Code", "cipm.svc.code",
2924 FT_UINT8
, BASE_HEX
, VALS(cip_sc_vals
), 0,
2925 "Service Data Block: Service Code", HFILL
}
2928 { "General Status", "cipm.svc.sts",
2929 FT_UINT8
, BASE_DEC
|BASE_EXT_STRING
, &cip_gs_vals_ext
, 0,
2930 "Service Data Block: General Status", HFILL
}
2932 { &hf_cip_svc_transction
,
2933 { "Transaction Id", "cipm.svc.tranid",
2934 FT_UINT8
, BASE_DEC
, NULL
, 0,
2935 "Service Data Block: Transaction Id", HFILL
}
2937 { &hf_cip_svc_ext_status
,
2938 { "Extended Status", "cipm.svc.extstatus",
2939 FT_UINT8
, BASE_DEC
, NULL
, 0,
2940 "Service Data Block: Extended Status", HFILL
}
2943 { "Service Data", "cipm.svc.data",
2944 FT_BYTES
, BASE_NONE
, NULL
, 0,
2945 "Service Data Block: Data", HFILL
}
2947 { &hf_cip_attribute_data
,
2948 { "Attribute Data", "cipm.attrdata",
2949 FT_BYTES
, BASE_NONE
, NULL
, 0,
2950 "Attribute Service: Data", HFILL
}
2952 { &hf_cip_ptp_grandmaster
,
2953 { "Grandmaster", "cipm.grandmaster",
2954 FT_UINT64
, BASE_HEX
, NULL
, 0,
2955 "Group Sync: Grandmaster Id", HFILL
}
2958 { &hf_cip_svc_get_axis_attr_sts
,
2959 { "Attribute Status", "cipm.getaxisattr.sts",
2960 FT_UINT8
, BASE_DEC
|BASE_EXT_STRING
, &cip_gs_vals_ext
, 0,
2961 "Service Channel: Get Axis Attribute List Response Status", HFILL
}
2963 { &hf_get_axis_attr_list_attribute_cnt
,
2964 { "Number of attributes", "cipm.getaxisattr.cnt",
2965 FT_UINT16
, BASE_DEC
, NULL
, 0,
2966 "Service Channel: Get Axis Attribute List Attribute Count", HFILL
}
2968 { &hf_get_axis_attr_list_attribute_id
,
2969 { "Attribute ID", "cipm.getaxisattr.id",
2970 FT_UINT16
, BASE_DEC
, NULL
, 0,
2971 "Service Channel: Get Axis Attribute List Attribute ID", HFILL
}
2973 { &hf_get_axis_attr_list_dimension
,
2974 { "Dimension", "cipm.getaxisattr.dimension",
2975 FT_UINT8
, BASE_DEC
, NULL
, 0,
2976 "Service Channel: Get Axis Attribute List Dimension", HFILL
}
2978 { &hf_get_axis_attr_list_element_size
,
2979 { "Element size", "cipm.getaxisattr.element_size",
2980 FT_UINT8
, BASE_DEC
, NULL
, 0,
2981 "Service Channel: Get Axis Attribute List Element Size", HFILL
}
2983 { &hf_get_axis_attr_list_start_index
,
2984 { "Start index", "cipm.getaxisattr.start_index",
2985 FT_UINT16
, BASE_DEC
, NULL
, 0,
2986 "Service Channel: Get Axis Attribute List Start index", HFILL
}
2988 { &hf_get_axis_attr_list_data_elements
,
2989 { "Data elements", "cipm.getaxisattr.data_elements",
2990 FT_UINT16
, BASE_DEC
, NULL
, 0,
2991 "Service Channel: Get Axis Attribute List Data elements", HFILL
}
2994 { &hf_cip_svc_set_axis_attr_sts
,
2995 { "Attribute Status", "cipm.setaxisattr.sts",
2996 FT_UINT8
, BASE_DEC
|BASE_EXT_STRING
, &cip_gs_vals_ext
, 0,
2997 "Service Channel: Set Axis Attribute List Response Status", HFILL
}
2999 { &hf_set_axis_attr_list_attribute_cnt
,
3000 { "Number of attributes", "cipm.setaxisattr.cnt",
3001 FT_UINT16
, BASE_DEC
, NULL
, 0,
3002 "Service Channel: Set Axis Attribute List Attribute Count", HFILL
}
3004 { &hf_set_axis_attr_list_attribute_id
,
3005 { "Attribute ID", "cipm.setaxisattr.id",
3006 FT_UINT16
, BASE_DEC
, NULL
, 0,
3007 "Service Channel: Set Axis Attribute List Attribute ID", HFILL
}
3009 { &hf_set_axis_attr_list_dimension
,
3010 { "Dimension", "cipm.setaxisattr.dimension",
3011 FT_UINT8
, BASE_DEC
, NULL
, 0,
3012 "Service Channel: Set Axis Attribute List Dimension", HFILL
}
3014 { &hf_set_axis_attr_list_element_size
,
3015 { "Element size", "cipm.setaxisattr.element_size",
3016 FT_UINT8
, BASE_DEC
, NULL
, 0,
3017 "Service Channel: Set Axis Attribute List Element Size", HFILL
}
3019 { &hf_set_axis_attr_list_start_index
,
3020 { "Start index", "cipm.setaxisattr.start_index",
3021 FT_UINT16
, BASE_DEC
, NULL
, 0,
3022 "Service Channel: Set Axis Attribute List Start index", HFILL
}
3024 { &hf_set_axis_attr_list_data_elements
,
3025 { "Data elements", "cipm.setaxisattr.data_elements",
3026 FT_UINT16
, BASE_DEC
, NULL
, 0,
3027 "Service Channel: Set Axis Attribute List Data elements", HFILL
}
3030 { &hf_set_cyclic_list_attribute_cnt
,
3031 { "Number of attributes", "cipm.set_cyclic.cnt",
3032 FT_UINT16
, BASE_DEC
, NULL
, 0,
3035 { &hf_set_cyclic_list_attribute_id
,
3036 { "Attribute ID", "cipm.set_cyclic.id",
3037 FT_UINT16
, BASE_DEC
, NULL
, 0,
3040 { &hf_set_cyclic_list_read_block_id
,
3041 { "Cyclic Read Block ID", "cipm.set_cyclic.read_block_id",
3042 FT_UINT16
, BASE_DEC
, NULL
, 0,
3045 { &hf_set_cyclic_list_attr_sts
,
3046 { "Attribute Status", "cipm.set_cyclic.sts",
3047 FT_UINT8
, BASE_DEC
| BASE_EXT_STRING
, &cip_gs_vals_ext
, 0,
3051 { &hf_var_devce_instance
,
3052 { "Instance Number", "cipm.var_devce.header.instance",
3053 FT_UINT8
, BASE_DEC
, NULL
, 0,
3054 "Variable Device Header: Instance Number", HFILL
}
3056 { &hf_var_devce_instance_block_size
,
3057 { "Instance Block Size", "cipm.var_devce.header.instance_block_size",
3058 FT_UINT8
, BASE_DEC
|BASE_UNIT_STRING
, UNS(&units_word_words
), 0,
3059 "Variable Device Header: Instance Block Size", HFILL
}
3061 { &hf_var_devce_cyclic_block_size
,
3062 { "Cyclic Block Size", "cipm.var_devce.header.cyclic_block_size",
3063 FT_UINT8
, BASE_DEC
|BASE_UNIT_STRING
, UNS(&units_word_words
), 0,
3064 "Variable Device Header: Cyclic Block Size", HFILL
}
3066 { &hf_var_devce_cyclic_data_block_size
,
3067 { "Cyclic Data Block Size", "cipm.var_devce.header.cyclic_data_block_size",
3068 FT_UINT8
, BASE_DEC
|BASE_UNIT_STRING
, UNS(&units_word_words
), 0,
3069 "Variable Device Header: Cyclic Data Block Size", HFILL
}
3071 { &hf_var_devce_cyclic_rw_block_size
,
3072 { "Cyclic Read/Write Block Size", "cipm.var_devce.header.cyclic_rw_block_size",
3073 FT_UINT8
, BASE_DEC
|BASE_UNIT_STRING
, UNS(&units_word_words
), 0,
3074 "Variable Device Header: Cyclic Read/Write Block Size", HFILL
}
3076 { &hf_var_devce_event_block_size
,
3077 { "Event Block Size", "cipm.var_devce.header.event_block_size",
3078 FT_UINT8
, BASE_DEC
|BASE_UNIT_STRING
, UNS(&units_word_words
), 0,
3079 "Variable Device Header: Event Block Size", HFILL
}
3081 { &hf_var_devce_service_block_size
,
3082 { "Service Block Size", "cipm.var_devce.header.service_block_size",
3083 FT_UINT8
, BASE_DEC
|BASE_UNIT_STRING
, UNS(&units_word_words
), 0,
3084 "Variable Device Header: Service Block Size", HFILL
}
3087 { &hf_cip_axis_alarm
,
3088 { "Axis Alarm Code", "cipm.alarm.code",
3089 FT_UINT8
, BASE_DEC
, NULL
, 0,
3090 "Status Data Set: Alarm Code", HFILL
}
3092 { &hf_cip_axis_sts_local_ctrl
,
3093 { "Local Control", "cipm.axis.local",
3094 FT_BOOLEAN
, 32, NULL
, 0x00000001,
3095 "Axis Status Data Set: Local Control", HFILL
}
3097 { &hf_cip_axis_sts_alarm
,
3098 { "Alarm", "cipm.axis.alarm",
3099 FT_BOOLEAN
, 32, NULL
, 0x00000002,
3100 "Axis Status Data Set: Alarm", HFILL
}
3102 { &hf_cip_axis_sts_dc_bus
,
3103 { "DC Bus", "cipm.axis.bus",
3104 FT_BOOLEAN
, 32, NULL
, 0x00000004,
3105 "Axis Status Data Set: DC Bus", HFILL
}
3107 { &hf_cip_axis_sts_pwr_struct
,
3108 { "Power Struct", "cipm.axis.pwr",
3109 FT_BOOLEAN
, 32, NULL
, 0x00000008,
3110 "Axis Status Data Set: Power Struct", HFILL
}
3112 { &hf_cip_axis_sts_flux_up
,
3113 { "Motor Flux Up", "cipm.axis.flx",
3114 FT_BOOLEAN
, 32, NULL
, 0x00000010,
3115 "Axis Status Data Set: Motor Flux Up", HFILL
}
3117 { &hf_cip_axis_sts_tracking
,
3118 { "Tracking", "cipm.axis.track",
3119 FT_BOOLEAN
, 32, NULL
, 0x00000020,
3120 "Axis Status Data Set: Tracking", HFILL
}
3122 { &hf_cip_axis_sts_pos_lock
,
3123 { "Pos Lock", "cipm.axis.poslock",
3124 FT_BOOLEAN
, 32, NULL
, 0x00000040,
3125 "Axis Status Data Set: Pos Lock", HFILL
}
3127 { &hf_cip_axis_sts_vel_lock
,
3128 { "Vel Lock", "cipm.axis.vellock",
3129 FT_BOOLEAN
, 32, NULL
, 0x00000080,
3130 "Axis Status Data Set: Vel Lock", HFILL
}
3132 { &hf_cip_axis_sts_vel_standstill
,
3133 { "Vel Standstill", "cipm.axis.nomo",
3134 FT_BOOLEAN
, 32, NULL
, 0x00000100,
3135 "Axis Status Data Set: Vel Standstill", HFILL
}
3137 { &hf_cip_axis_sts_vel_threshold
,
3138 { "Vel Threshold", "cipm.axis.vthresh",
3139 FT_BOOLEAN
, 32, NULL
, 0x00000200,
3140 "Axis Status Data Set: Vel Threshold", HFILL
}
3142 { &hf_cip_axis_sts_vel_limit
,
3143 { "Vel Limit", "cipm.axis.vlim",
3144 FT_BOOLEAN
, 32, NULL
, 0x00000400,
3145 "Axis Status Data Set: Vel Limit", HFILL
}
3147 { &hf_cip_axis_sts_acc_limit
,
3148 { "Acc Limit", "cipm.axis.alim",
3149 FT_BOOLEAN
, 32, NULL
, 0x00000800,
3150 "Axis Status Data Set: Acc Limit", HFILL
}
3152 { &hf_cip_axis_sts_dec_limit
,
3153 { "Decel Limit", "cipm.axis.dlim",
3154 FT_BOOLEAN
, 32, NULL
, 0x00001000,
3155 "Axis Status Data Set: Decel Limit", HFILL
}
3157 { &hf_cip_axis_sts_torque_threshold
,
3158 { "Torque Threshold", "cipm.axis.tthresh",
3159 FT_BOOLEAN
, 32, NULL
, 0x00002000,
3160 "Axis Status Data Set: Torque Threshold", HFILL
}
3162 { &hf_cip_axis_sts_torque_limit
,
3163 { "Torque Limit", "cipm.axis.tlim",
3164 FT_BOOLEAN
, 32, NULL
, 0x00004000,
3165 "Axis Status Data Set: Torque Limit", HFILL
}
3167 { &hf_cip_axis_sts_cur_limit
,
3168 { "Current Limit", "cipm.axis.ilim",
3169 FT_BOOLEAN
, 32, NULL
, 0x00008000,
3170 "Axis Status Data Set: Current Limit", HFILL
}
3172 { &hf_cip_axis_sts_therm_limit
,
3173 { "Thermal Limit", "cipm.axis.hot",
3174 FT_BOOLEAN
, 32, NULL
, 0x00010000,
3175 "Axis Status Data Set: Thermal Limit", HFILL
}
3177 { &hf_cip_axis_sts_feedback_integ
,
3178 { "Feedback Integrity", "cipm.axis.fgood",
3179 FT_BOOLEAN
, 32, NULL
, 0x00020000,
3180 "Axis Status Data Set: Feedback Integrity", HFILL
}
3182 { &hf_cip_axis_sts_shutdown
,
3183 { "Shutdown", "cipm.axis.sdwn",
3184 FT_BOOLEAN
, 32, NULL
, 0x00040000,
3185 "Axis Status Data Set: Shutdown", HFILL
}
3187 { &hf_cip_axis_sts_in_process
,
3188 { "In Process", "cipm.axis.inp",
3189 FT_BOOLEAN
, 32, NULL
, 0x00080000,
3190 "Axis Status Data Set: In Process", HFILL
}
3192 { &hf_cip_axis_sts_dc_bus_unload
,
3193 { "DC Bus Unload", "cipm.axis.dcunload",
3194 FT_BOOLEAN
, 32, NULL
, 0x00100000,
3195 "Axis Status Data Set: DC Bus Unload", HFILL
}
3197 { &hf_cip_axis_sts_ac_pwr_loss
,
3198 { "AC Power Loss", "cipm.axis.acpwrloss",
3199 FT_BOOLEAN
, 32, NULL
, 0x00200000,
3200 "Axis Status Data Set: AC Power Loss", HFILL
}
3202 { &hf_cip_axis_sts_pos_cntrl_mode
,
3203 { "Pos Control Mode", "cipm.axis.poscntrl",
3204 FT_BOOLEAN
, 32, NULL
, 0x00400000,
3205 "Axis Status Data Set: Position Control Mode", HFILL
}
3207 { &hf_cip_axis_sts_vel_cntrl_mode
,
3208 { "Vel Control Mode", "cipm.axis.velcntrl",
3209 FT_BOOLEAN
, 32, NULL
, 0x00800000,
3210 "Axis Status Data Set: Velocity Control Mode", HFILL
}
3212 { &hf_cip_axis_sts_trq_cntrl_mode
,
3213 { "Torque Control Mode", "cipm.axis.trqcntrl",
3214 FT_BOOLEAN
, 32, NULL
, 0x01000000,
3215 "Axis Status Data Set: Torque Control Mode", HFILL
}
3218 // Attribute #740 - Axis Status 2.
3219 { &hf_cip_axis_status2
,
3220 { "Axis Status 2", "cipm.axisstatus2",
3221 FT_UINT32
, BASE_HEX
, NULL
, 0,
3224 { &hf_cip_axis_sts2_motor
,
3225 { "Motoring", "cipm.axis2.motor",
3226 FT_BOOLEAN
, 32, NULL
, 0x00000001,
3229 { &hf_cip_axis_sts2_regenerate
,
3230 { "Regenerating", "cipm.axis2.regen",
3231 FT_BOOLEAN
, 32, NULL
, 0x00000002,
3234 { &hf_cip_axis_sts2_ride_thru
,
3235 { "Ride Thru", "cipm.axis2.ridethru",
3236 FT_BOOLEAN
, 32, NULL
, 0x00000004,
3239 { &hf_cip_axis_sts2_ac_line_sync
,
3240 { "AC Line Sync", "cipm.axis2.acsync",
3241 FT_BOOLEAN
, 32, NULL
, 0x00000008,
3244 { &hf_cip_axis_sts2_bus_volt_lock
,
3245 { "Bus Voltage Lock", "cipm.axis2.voltlock",
3246 FT_BOOLEAN
, 32, NULL
, 0x00000010,
3249 { &hf_cip_axis_sts2_react_pwr_only
,
3250 { "Reactive Power Only Mode", "cipm.axis2.reactpwr",
3251 FT_BOOLEAN
, 32, NULL
, 0x00000020,
3254 { &hf_cip_axis_sts2_volt_ctrl_mode
,
3255 { "Voltage Control Mode", "cipm.axis2.voltmode",
3256 FT_BOOLEAN
, 32, NULL
, 0x00000040,
3259 { &hf_cip_axis_sts2_pwr_loss
,
3260 { "Power Loss", "cipm.axis2.pwrloss",
3261 FT_BOOLEAN
, 32, NULL
, 0x00000080,
3264 { &hf_cip_axis_sts2_ac_volt_sag
,
3265 { "AC Line Voltage Sag", "cipm.axis2.voltsag",
3266 FT_BOOLEAN
, 32, NULL
, 0x00000100,
3269 { &hf_cip_axis_sts2_ac_phase_loss
,
3270 { "AC Line Phase Loss", "cipm.axis2.phaseloss",
3271 FT_BOOLEAN
, 32, NULL
, 0x00000200,
3274 { &hf_cip_axis_sts2_ac_freq_change
,
3275 { "AC Line Frequency Change", "cipm.axis2.freqchange",
3276 FT_BOOLEAN
, 32, NULL
, 0x00000400,
3279 { &hf_cip_axis_sts2_ac_sync_loss
,
3280 { "AC Line Sync Loss", "cipm.axis2.syncloss",
3281 FT_BOOLEAN
, 32, NULL
, 0x00000800,
3284 { &hf_cip_axis_sts2_single_phase
,
3285 { "Single Phase", "cipm.axis2.singlephase",
3286 FT_BOOLEAN
, 32, NULL
, 0x00001000,
3290 { &hf_cip_axis_sts2_bus_volt_limit
,
3291 { "Bus Voltage Limit", "cipm.axis2.bus_volt_limit",
3292 FT_BOOLEAN
, 32, NULL
, 0x00002000,
3295 { &hf_cip_axis_sts2_bus_volt_rate_limit
,
3296 { "Bus Voltage Rate Limit", "cipm.axis2.bus_volt_rate_limit",
3297 FT_BOOLEAN
, 32, NULL
, 0x00004000,
3300 { &hf_cip_axis_sts2_active_current_rate_limit
,
3301 { "Active Current Rate Limit", "cipm.axis2.active_current_rate_limit",
3302 FT_BOOLEAN
, 32, NULL
, 0x00008000,
3305 { &hf_cip_axis_sts2_reactive_current_rate_limit
,
3306 { "Reactive Current Rate Limit", "cipm.axis2.reactive_current_rate_limit",
3307 FT_BOOLEAN
, 32, NULL
, 0x00010000,
3310 { &hf_cip_axis_sts2_reactive_pwr_limit
,
3311 { "Reactive Power Limit", "cipm.axis2.reactive_pwr_limit",
3312 FT_BOOLEAN
, 32, NULL
, 0x00020000,
3315 { &hf_cip_axis_sts2_reactive_pwr_rate_limit
,
3316 { "Reactive Power Rate Limit", "cipm.axis2.reactive_pwr_rate_limit",
3317 FT_BOOLEAN
, 32, NULL
, 0x00040000,
3320 { &hf_cip_axis_sts2_active_current_limit
,
3321 { "Active Current Limit", "cipm.axis2.active_current_limit",
3322 FT_BOOLEAN
, 32, NULL
, 0x00080000,
3325 { &hf_cip_axis_sts2_reactive_current_limit
,
3326 { "Reactive Current Limit", "cipm.axis2.reactive_current_limit",
3327 FT_BOOLEAN
, 32, NULL
, 0x00100000,
3330 { &hf_cip_axis_sts2_motor_pwr_limit
,
3331 { "Motoring Power Limit", "cipm.axis2.motor_pwr_limit",
3332 FT_BOOLEAN
, 32, NULL
, 0x00200000,
3335 { &hf_cip_axis_sts2_regen_pwr_limit
,
3336 { "Regenerative Power Limit", "cipm.axis2.regen_pwr_limit",
3337 FT_BOOLEAN
, 32, NULL
, 0x00400000,
3340 { &hf_cip_axis_sts2_convert_therm_limit
,
3341 { "Converter Thermal Limit", "cipm.axis2.convert_therm_limit",
3342 FT_BOOLEAN
, 32, NULL
, 0x00800000,
3347 { "Actual Position", "cipm.actpos",
3348 FT_INT32
, BASE_DEC
, NULL
, 0,
3349 "Cyclic Data Set: Actual Position", HFILL
}
3351 { &hf_cip_act_pos_64
,
3352 { "Actual Position", "cipm.actpos_64",
3353 FT_INT64
, BASE_DEC
, NULL
, 0,
3354 "Cyclic Data Set: Actual Position", HFILL
}
3357 { "Actual Velocity", "cipm.actvel",
3358 FT_FLOAT
, BASE_NONE
, NULL
, 0,
3359 "Cyclic Data Set: Actual Velocity", HFILL
}
3361 { &hf_cip_act_accel
,
3362 { "Actual Acceleration", "cipm.actaccel",
3363 FT_FLOAT
, BASE_NONE
, NULL
, 0,
3364 "Cyclic Data Set: Actual Acceleration", HFILL
}
3367 { "Position Command", "cipm.posfcmd",
3368 FT_DOUBLE
, BASE_NONE
, NULL
, 0,
3369 "Cyclic Data Set: Position Command (LREAL)", HFILL
}
3371 { &hf_cip_pos_cmd_int
,
3372 { "Position Command", "cipm.posicmd",
3373 FT_INT32
, BASE_DEC
, NULL
, 0,
3374 "Cyclic Data Set: Position Command (DINT)", HFILL
}
3377 { "Velocity Command", "cipm.velcmd",
3378 FT_FLOAT
, BASE_NONE
, NULL
, 0,
3379 "Cyclic Data Set: Velocity Command", HFILL
}
3381 { &hf_cip_accel_cmd
,
3382 { "Acceleration Command", "cipm.accelcmd",
3383 FT_FLOAT
, BASE_NONE
, NULL
, 0,
3384 "Cyclic Data Set: Acceleration Command", HFILL
}
3387 { "Torque Command", "cipm.torquecmd",
3388 FT_FLOAT
, BASE_NONE
, NULL
, 0,
3389 "Cyclic Data Set: Torque Command", HFILL
}
3392 { "Position Trim", "cipm.postrim",
3393 FT_INT32
, BASE_DEC
, NULL
, 0,
3397 { "Velocity Trim", "cipm.veltrim",
3398 FT_FLOAT
, BASE_NONE
, NULL
, 0,
3401 { &hf_cip_accel_trim
,
3402 { "Acceleration Trim", "cipm.acceltrim",
3403 FT_FLOAT
, BASE_NONE
, NULL
, 0,
3407 { "Torque Trim", "cipm.trqtrim",
3408 FT_FLOAT
, BASE_NONE
, NULL
, 0,
3412 { "Data", "cipm.data",
3413 FT_BYTES
, BASE_NONE
, NULL
, 0,
3418 /* Setup protocol subtree array, these will help Wireshark remember
3419 * if the subtree should be expanded as the user moves through packets */
3420 static int *ett
[] = {
3422 &ett_cont_dev_header
,
3423 &ett_control_status
,
3427 &ett_inst_data_header
,
3428 &ett_cyclic_data_block
,
3429 &ett_cyclic_command_data
,
3431 &ett_connection_configuration_bits
,
3433 &ett_feedback_config
,
3434 &ett_command_data_set
,
3435 &ett_actual_data_set
,
3436 &ett_status_data_set
,
3437 &ett_interp_control
,
3440 &ett_event_check_ctrl
,
3441 &ett_event_check_sts
,
3443 &ett_get_axis_attribute
,
3444 &ett_set_axis_attribute
,
3445 &ett_get_axis_attr_list
,
3446 &ett_set_axis_attr_list
,
3447 &ett_set_cyclic_list
,
3449 &ett_axis_status_set
,
3450 &ett_command_control
,
3451 &ett_configuration_block
3454 static ei_register_info ei
[] = {
3455 { &ei_format_rev_conn_pt
, { "cipm.malformed.format_revision_mismatch", PI_MALFORMED
, PI_WARN
, "Format Revision does not match Connection Point", EXPFILL
} },
3458 /* Create a CIP Motion protocol handle */
3459 proto_cipmotion
= proto_register_protocol("Common Industrial Protocol, Motion", "CIP Motion", "cipm");
3461 proto_cipmotion3
= proto_register_protocol_in_name_only(
3462 "Common Industrial Protocol, Motion - Rev 3",
3463 "CIP Motion - Rev 3",
3468 /* Register the header fields with the protocol */
3469 proto_register_field_array(proto_cipmotion
, hf
, array_length(hf
));
3471 /* Register the subtrees for the protocol dissection */
3472 proto_register_subtree_array(ett
, array_length(ett
));
3474 expert_module_t
* expert_cipm
= expert_register_protocol(proto_cipmotion
);
3475 expert_register_field_array(expert_cipm
, ei
, array_length(ei
));
3477 module_t
* cipm_module
= prefs_register_protocol(proto_cipmotion
, NULL
);
3478 prefs_register_bool_preference(cipm_module
, "display_full_attribute_data",
3479 "Display full attribute data in the Service Data Block",
3480 "Whether the CIP Motion dissector always display the full raw attribute data bytes",
3481 &display_full_attribute_data
);
3483 cipmotion_handle
= register_dissector("cipmotion", dissect_cipmotion
, proto_cipmotion
);
3484 cipmotion3_handle
= register_dissector("cipmotion3", dissect_cipmotion3
, proto_cipmotion3
);
3487 void proto_reg_handoff_cipmotion(void)
3489 dissector_add_for_decode_as("cip.io", cipmotion_handle
);
3490 dissector_add_for_decode_as("cip.io", cipmotion3_handle
);
3492 dissector_add_uint("cip.io.iface", CI_CLS_MOTION
, cipmotion_handle
);
3496 * Editor modelines - https://www.wireshark.org/tools/modelines.html
3501 * indent-tabs-mode: nil
3504 * ex: set shiftwidth=3 tabstop=8 expandtab:
3505 * :indentSize=3:tabSize=8:noTabs=true: