MSWSP: fix dissect_mswsp_smb()
[wireshark-wip.git] / epan / dissectors / packet-cipmotion.c
blob2af404373c1d8054f4812f23249f6c5bf09c4c3d
1 /* packet-cipmotion.c
2 * Routines for CIP (Common Industrial Protocol) Motion dissection
3 * CIP Motion Home: www.odva.org
5 * Copyright 2006-2007
6 * Benjamin M. Stocks <bmstocks@ra.rockwell.com>
8 * $Id$
10 * Wireshark - Network traffic analyzer
11 * By Gerald Combs <gerald@wireshark.org>
12 * Copyright 1998 Gerald Combs
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
29 #include "config.h"
31 #include <epan/packet.h>
32 #include "packet-cip.h"
34 void proto_register_cipmotion(void);
35 /* The entry point to the actual disection is: dissect_cipmotion */
37 /* Protocol handle for CIP Motion */
38 static int proto_cipmotion = -1;
40 /* Header field identifiers, these are registered in the
41 * proto_register_cipmotion function along with the bites/bytes
42 * they represent */
43 static int hf_cip_format = -1;
44 static int hf_cip_revision = -1;
45 static int hf_cip_class1_seqnum = -1;
46 static int hf_cip_updateid = -1;
47 static int hf_cip_instance_cnt = -1;
48 static int hf_cip_last_update = -1;
49 static int hf_cip_node_status = -1;
50 static int hf_cip_node_control = -1;
51 static int hf_cip_node_control_remote = -1;
52 static int hf_cip_node_control_sync = -1;
53 static int hf_cip_node_data_valid = -1;
54 static int hf_cip_node_fault_reset = -1;
55 static int hf_cip_node_device_faulted = -1;
56 static int hf_cip_time_data_set = -1;
57 static int hf_cip_time_data_stamp = -1;
58 static int hf_cip_time_data_offset = -1;
59 static int hf_cip_time_data_diag = -1;
60 static int hf_cip_time_data_time_diag = -1;
61 static int hf_cip_cont_time_stamp = -1;
62 static int hf_cip_cont_time_offset = -1;
63 static int hf_cip_devc_time_stamp = -1;
64 static int hf_cip_devc_time_offset = -1;
65 static int hf_cip_lost_update = -1;
66 static int hf_cip_late_update = -1;
67 static int hf_cip_data_rx_time_stamp = -1;
68 static int hf_cip_data_tx_time_stamp = -1;
69 static int hf_cip_node_fltalarms = -1;
70 static int hf_cip_motor_cntrl = -1;
71 static int hf_cip_fdbk_config = -1;
72 static int hf_cip_axis_control = -1;
73 static int hf_cip_control_status = -1;
74 static int hf_cip_axis_response = -1;
75 static int hf_cip_axis_resp_stat = -1;
76 static int hf_cip_cmd_data_pos_cmd = -1;
77 static int hf_cip_cmd_data_vel_cmd = -1;
78 static int hf_cip_cmd_data_acc_cmd = -1;
79 static int hf_cip_cmd_data_trq_cmd = -1;
80 static int hf_cip_cmd_data_pos_trim_cmd = -1;
81 static int hf_cip_cmd_data_vel_trim_cmd = -1;
82 static int hf_cip_cmd_data_acc_trim_cmd = -1;
83 static int hf_cip_cmd_data_trq_trim_cmd = -1;
84 static int hf_cip_act_data_pos = -1;
85 static int hf_cip_act_data_vel = -1;
86 static int hf_cip_act_data_acc = -1;
87 static int hf_cip_act_data_trq = -1;
88 static int hf_cip_act_data_crnt = -1;
89 static int hf_cip_act_data_vltg = -1;
90 static int hf_cip_act_data_fqcy = -1;
91 static int hf_cip_sts_flt = -1;
92 static int hf_cip_sts_alrm = -1;
93 static int hf_cip_sts_sts = -1;
94 static int hf_cip_sts_iosts = -1;
95 static int hf_cip_sts_safety = -1;
96 static int hf_cip_intrp = -1;
97 static int hf_cip_position_data_type = -1;
98 static int hf_cip_axis_state = -1;
99 static int hf_cip_evnt_ctrl_reg1_pos = -1;
100 static int hf_cip_evnt_ctrl_reg1_neg = -1;
101 static int hf_cip_evnt_ctrl_reg2_pos = -1;
102 static int hf_cip_evnt_ctrl_reg2_neg = -1;
103 static int hf_cip_evnt_ctrl_reg1_posrearm = -1;
104 static int hf_cip_evnt_ctrl_reg1_negrearm = -1;
105 static int hf_cip_evnt_ctrl_reg2_posrearm = -1;
106 static int hf_cip_evnt_ctrl_reg2_negrearm = -1;
107 static int hf_cip_evnt_ctrl_marker_pos = -1;
108 static int hf_cip_evnt_ctrl_marker_neg = -1;
109 static int hf_cip_evnt_ctrl_home_pos = -1;
110 static int hf_cip_evnt_ctrl_home_neg = -1;
111 static int hf_cip_evnt_ctrl_home_pp = -1;
112 static int hf_cip_evnt_ctrl_home_pm = -1;
113 static int hf_cip_evnt_ctrl_home_mp = -1;
114 static int hf_cip_evnt_ctrl_home_mm = -1;
115 static int hf_cip_evnt_ctrl_acks = -1;
116 static int hf_cip_evnt_extend_format = -1;
117 static int hf_cip_evnt_sts_reg1_pos = -1;
118 static int hf_cip_evnt_sts_reg1_neg = -1;
119 static int hf_cip_evnt_sts_reg2_pos = -1;
120 static int hf_cip_evnt_sts_reg2_neg = -1;
121 static int hf_cip_evnt_sts_reg1_posrearm = -1;
122 static int hf_cip_evnt_sts_reg1_negrearm = -1;
123 static int hf_cip_evnt_sts_reg2_posrearm = -1;
124 static int hf_cip_evnt_sts_reg2_negrearm = -1;
125 static int hf_cip_evnt_sts_marker_pos = -1;
126 static int hf_cip_evnt_sts_marker_neg = -1;
127 static int hf_cip_evnt_sts_home_pos = -1;
128 static int hf_cip_evnt_sts_home_neg = -1;
129 static int hf_cip_evnt_sts_home_pp = -1;
130 static int hf_cip_evnt_sts_home_pm = -1;
131 static int hf_cip_evnt_sts_home_mp = -1;
132 static int hf_cip_evnt_sts_home_mm = -1;
133 static int hf_cip_evnt_sts_nfs = -1;
134 static int hf_cip_evnt_sts_stat = -1;
135 static int hf_cip_evnt_type = -1;
136 static int hf_cip_svc_code = -1;
137 static int hf_cip_svc_sts = -1;
138 static int hf_cip_svc_set_axis_attr_sts = -1;
139 static int hf_cip_svc_get_axis_attr_sts = -1;
140 static int hf_cip_svc_transction = -1;
141 static int hf_cip_svc_ext_status = -1;
142 static int hf_cip_svc_data = -1;
143 static int hf_cip_ptp_grandmaster = -1;
144 static int hf_cip_axis_alarm = -1;
145 static int hf_cip_axis_fault = -1;
146 static int hf_cip_axis_sts_local_ctrl = -1;
147 static int hf_cip_axis_sts_alarm = -1;
148 static int hf_cip_axis_sts_dc_bus = -1;
149 static int hf_cip_axis_sts_pwr_struct = -1;
150 static int hf_cip_axis_sts_tracking = -1;
151 static int hf_cip_axis_sts_pos_lock = -1;
152 static int hf_cip_axis_sts_vel_lock = -1;
153 static int hf_cip_axis_sts_vel_standstill = -1;
154 static int hf_cip_axis_sts_vel_threshold = -1;
155 static int hf_cip_axis_sts_vel_limit = -1;
156 static int hf_cip_axis_sts_acc_limit = -1;
157 static int hf_cip_axis_sts_dec_limit = -1;
158 static int hf_cip_axis_sts_torque_threshold = -1;
159 static int hf_cip_axis_sts_torque_limit = -1;
160 static int hf_cip_axis_sts_cur_limit = -1;
161 static int hf_cip_axis_sts_therm_limit = -1;
162 static int hf_cip_axis_sts_feedback_integ = -1;
163 static int hf_cip_axis_sts_shutdown = -1;
164 static int hf_cip_axis_sts_in_process = -1;
165 static int hf_cip_cyclic_wrt_data = -1;
166 static int hf_cip_cyclic_rd_data = -1;
167 static int hf_cip_cyclic_write_blk = -1;
168 static int hf_cip_cyclic_read_blk = -1;
169 static int hf_cip_cyclic_write_sts = -1;
170 static int hf_cip_cyclic_read_sts = -1;
171 static int hf_cip_attribute_data = -1;
172 static int hf_cip_event_checking = -1;
173 static int hf_cip_event_ack = -1;
174 static int hf_cip_event_status = -1;
175 static int hf_cip_event_id = -1;
176 static int hf_cip_event_pos = -1;
177 static int hf_cip_event_ts = -1;
178 static int hf_cip_pos_cmd = -1;
179 static int hf_cip_pos_cmd_int = -1;
180 static int hf_cip_vel_cmd = -1;
181 static int hf_cip_accel_cmd = -1;
182 static int hf_cip_trq_cmd = -1;
183 static int hf_cip_pos_trim = -1;
184 static int hf_cip_vel_trim = -1;
185 static int hf_cip_accel_trim = -1;
186 static int hf_cip_trq_trim = -1;
187 static int hf_cip_act_pos = -1;
188 static int hf_cip_act_vel = -1;
189 static int hf_cip_act_accel = -1;
190 static int hf_cip_act_trq = -1;
191 static int hf_cip_act_crnt = -1;
192 static int hf_cip_act_volts = -1;
193 static int hf_cip_act_freq = -1;
194 static int hf_cip_fault_type = -1;
195 static int hf_cip_fault_sub_code = -1;
196 static int hf_cip_fault_action = -1;
197 static int hf_cip_fault_time_stamp = -1;
198 static int hf_cip_alarm_type = -1;
199 static int hf_cip_alarm_sub_code = -1;
200 static int hf_cip_alarm_state = -1;
201 static int hf_cip_alarm_time_stamp = -1;
202 static int hf_cip_axis_status = -1;
203 static int hf_cip_axis_status_mfg = -1;
204 static int hf_cip_axis_io_status = -1;
205 static int hf_cip_axis_io_status_mfg = -1;
206 static int hf_cip_safety_status = -1;
207 static int hf_cip_cmd_data_set = -1;
208 static int hf_cip_act_data_set = -1;
209 static int hf_cip_sts_data_set = -1;
210 static int hf_cip_group_sync = -1;
211 static int hf_cip_command_control = -1;
213 static int hf_get_axis_attr_list_attribute_cnt = -1;
214 static int hf_get_axis_attr_list_attribute_id = -1;
215 static int hf_get_axis_attr_list_dimension = -1;
216 static int hf_get_axis_attr_list_element_size = -1;
217 static int hf_get_axis_attr_list_start_index = -1;
218 static int hf_get_axis_attr_list_data_elements = -1;
219 static int hf_set_axis_attr_list_attribute_cnt = -1;
220 static int hf_set_axis_attr_list_attribute_id = -1;
221 static int hf_set_axis_attr_list_dimension = -1;
222 static int hf_set_axis_attr_list_element_size = -1;
223 static int hf_set_axis_attr_list_start_index = -1;
224 static int hf_set_axis_attr_list_data_elements = -1;
225 static int hf_var_devce_instance = -1;
226 static int hf_var_devce_instance_block_size = -1;
227 static int hf_var_devce_cyclic_block_size = -1;
228 static int hf_var_devce_cyclic_data_block_size = -1;
229 static int hf_var_devce_cyclic_rw_block_size = -1;
230 static int hf_var_devce_event_block_size = -1;
231 static int hf_var_devce_service_block_size = -1;
233 /* Subtree pointers for the dissection */
234 static gint ett_cipmotion = -1;
235 static gint ett_cont_dev_header = -1;
236 static gint ett_node_control = -1;
237 static gint ett_node_status = -1;
238 static gint ett_time_data_set = -1;
239 static gint ett_inst_data_header = -1;
240 static gint ett_cyclic_data_block = -1;
241 static gint ett_control_mode = -1;
242 static gint ett_feedback_config = -1;
243 static gint ett_command_data_set = -1;
244 static gint ett_actual_data_set = -1;
245 static gint ett_status_data_set = -1;
246 static gint ett_interp_control = -1;
247 static gint ett_cyclic_rd_wt = -1;
248 static gint ett_event = -1;
249 static gint ett_event_check_ctrl = -1;
250 static gint ett_event_check_sts = -1;
251 static gint ett_service = -1;
252 static gint ett_get_axis_attribute = -1;
253 static gint ett_set_axis_attribute = -1;
254 static gint ett_get_axis_attr_list = -1;
255 static gint ett_set_axis_attr_list = -1;
256 static gint ett_group_sync = -1;
257 static gint ett_axis_status_set = -1;
258 static gint ett_command_control = -1;
260 /* These are the BITMASKS for the Time Data Set header field */
261 #define TIME_DATA_SET_TIME_STAMP 0x1
262 #define TIME_DATA_SET_TIME_OFFSET 0x2
263 #define TIME_DATA_SET_UPDATE_DIAGNOSTICS 0x4
264 #define TIME_DATA_SET_TIME_DIAGNOSTICS 0x8
266 /* These are the BITMASKS for the Command Data Set cyclic field */
267 #define COMMAND_DATA_SET_POSITION 0x01
268 #define COMMAND_DATA_SET_VELOCITY 0x02
269 #define COMMAND_DATA_SET_ACCELERATION 0x04
270 #define COMMAND_DATA_SET_TORQUE 0x08
271 #define COMMAND_DATA_SET_POSITION_TRIM 0x10
272 #define COMMAND_DATA_SET_VELOCITY_TRIM 0x20
273 #define COMMAND_DATA_SET_ACCELERATION_TRIM 0x40
274 #define COMMAND_DATA_SET_TORQUE_TRIM 0x80
276 /* These are the BITMASKS for the Actual Data Set cyclic field */
277 #define ACTUAL_DATA_SET_POSITION 0x01
278 #define ACTUAL_DATA_SET_VELOCITY 0x02
279 #define ACTUAL_DATA_SET_ACCELERATION 0x04
280 #define ACTUAL_DATA_SET_TORQUE 0x08
281 #define ACTUAL_DATA_SET_CURRENT 0x10
282 #define ACTUAL_DATA_SET_VOLTAGE 0x20
283 #define ACTUAL_DATA_SET_FREQUENCY 0x40
285 /* These are the BITMASKS for the Status Data Set cyclic field */
286 #define STATUS_DATA_SET_AXIS_FAULT 0x01
287 #define STATUS_DATA_SET_AXIS_ALARM 0x02
288 #define STATUS_DATA_SET_AXIS_STATUS 0x04
289 #define STATUS_DATA_SET_AXIS_IO_STATUS 0x08
290 #define STATUS_DATA_SET_AXIS_SAFETY 0x80
292 /* These are the BITMASKS for the Command Control cyclic field */
293 #define COMMAND_CONTROL_TARGET_UPDATE 0x03
294 #define COMMAND_CONTROL_POSITION_DATA_TYPE 0x0C
296 /* These are the VALUES of the connection format header field of the
297 * CIP Motion protocol */
298 #define FORMAT_FIXED_CONTROL_TO_DEVICE 2
299 #define FORMAT_FIXED_DEVICE_TO_CONTROL 3
300 #define FORMAT_VAR_CONTROL_TO_DEVICE 6
301 #define FORMAT_VAR_DEVICE_TO_CONTROL 7
303 /* Translate function to string - connection format values */
304 static const value_string cip_con_format_vals[] = {
305 { FORMAT_FIXED_CONTROL_TO_DEVICE, "Fixed Controller-to-Device" },
306 { FORMAT_FIXED_DEVICE_TO_CONTROL, "Fixed Device-to-Controller" },
307 { FORMAT_VAR_CONTROL_TO_DEVICE, "Variable Controller-to-Device" },
308 { FORMAT_VAR_DEVICE_TO_CONTROL, "Variable Device-to-Controller" },
309 { 0, NULL }
312 /* Translate function to string - motor control mode values */
313 static const value_string cip_motor_control_vals[] = {
314 { 0, "No Control" },
315 { 1, "Position Control" },
316 { 2, "Velocity Control" },
317 { 3, "Acceleration Control" },
318 { 4, "Torque Control" },
319 { 5, "Current Control" },
320 { 0, NULL }
323 /* Translate function to string - feedback config values */
324 static const value_string cip_fdbk_config_vals[] = {
325 { 0, "No Feedback" },
326 { 1, "Master Feedback" },
327 { 2, "Motor Feedback" },
328 { 3, "Load Feedback" },
329 { 4, "Dual Feedback" },
330 { 0, NULL }
333 /* Translate function to string - axis control values */
334 static const value_string cip_axis_control_vals[] =
336 { 0, "No Request" },
337 { 1, "Enable Request" },
338 { 2, "Disble Request" },
339 { 3, "Shutdown Request" },
340 { 4, "Shutdown Reset Request" },
341 { 5, "Abort Request" },
342 { 6, "Fault Reset Request" },
343 { 7, "Stop Process" },
344 { 8, "Change Actual Pos" },
345 { 9, "Change Command Pos Ref" },
346 { 127, "Cancel Request" },
347 { 0, NULL }
350 /* Translate function to string - control status values */
351 static const value_string cip_control_status_vals[] =
353 { 1, "Configuration Complete" },
354 { 0, NULL }
357 /* Translate function to string - group sync Status */
358 static const value_string cip_sync_status_vals[] =
360 { 0, "Synchronized" },
361 { 1, "Not Synchronized" },
362 { 2, "Wrong Grandmaster" },
363 { 0, NULL }
366 /* Translate function to string - command target update */
367 static const value_string cip_interpolation_vals[] = {
368 { 0, "Immediate" },
369 { 1, "Extrapolate (+1)" },
370 { 2, "Interpolate (+2)" },
371 { 0, NULL }
374 /* These are the VALUES for the Command Position Data Type */
375 #define POSITION_DATA_LREAL 0x00
376 #define POSITION_DATA_DINT 0x01
378 /* Translate function to string - position data type */
379 static const value_string cip_pos_data_type_vals[] = {
380 { POSITION_DATA_LREAL, "LREAL (64-bit Float)" },
381 { POSITION_DATA_DINT, "DINT (32-bit Integer)" },
382 { 0, NULL }
385 /* Translate function to string - axis response values */
386 static const value_string cip_axis_response_vals[] = {
387 { 0, "No Acknowledge" },
388 { 1, "Enable Acknowledge" },
389 { 2, "Disable Acknowledge" },
390 { 3, "Shutdown Acknowledge" },
391 { 4, "Shutdown Reset Acknowledge" },
392 { 5, "Abort Acknowledge" },
393 { 6, "Fault Reset Acknowledge" },
394 { 0, NULL }
397 /* Translate function to string - axis state values */
398 static const value_string cip_axis_state_vals[] = {
399 { 0, "Initializing" },
400 { 1, "Pre-charging" },
401 { 2, "Stopped" },
402 { 3, "Starting" },
403 { 4, "Running" },
404 { 5, "Testing" },
405 { 6, "Stopping" },
406 { 7, "Aborting" },
407 { 8, "Major Faulted" },
408 { 9, "Start Inhibited" },
409 { 10, "Shutdown" },
410 { 0, NULL }
413 /* Translate function to string - event type values */
414 static const value_string cip_event_type_vals[] = {
415 { 0, "Registration 1 Positive Edge" },
416 { 1, "Registration 1 Negative Edge" },
417 { 2, "Registration 2 Positive Edge" },
418 { 3, "Registration 2 Negative Edge" },
419 { 4, "Marker Positive Edge" },
420 { 5, "Marker Negative Edge" },
421 { 6, "Home Switch Positive Edge" },
422 { 7, "Home Switch Negative Edge" },
423 { 8, "Home Switch Marker ++" },
424 { 9, "Home Switch Marker +-" },
425 { 10, "Home Switch Marker -+" },
426 { 11, "Home Switch Marker --" },
427 { 0, NULL }
430 #define SC_GET_AXIS_ATTRIBUTE_LIST 0x4B
431 #define SC_SET_AXIS_ATTRIBUTE_LIST 0x4C
432 #define SC_SET_CYCLIC_WRITE_LIST 0x4D
433 #define SC_SET_CYCLIC_READ_LIST 0x4E
434 #define SC_RUN_MOTOR_TEST 0x4F
435 #define SC_GET_MOTOR_TEST_DATA 0x50
436 #define SC_RUN_INERTIA_TEST 0x51
437 #define SC_GET_INERTIA_TEST_DATA 0x52
438 #define SC_RUN_HOOKUP_TEST 0x53
439 #define SC_GET_HOOKUP_TEST_DATA 0x53
441 /* Translate function to string - CIP Service codes */
442 static const value_string cip_sc_vals[] = {
443 GENERIC_SC_LIST
444 { SC_GET_AXIS_ATTRIBUTE_LIST, "Get Axis Attribute List" },
445 { SC_SET_AXIS_ATTRIBUTE_LIST, "Set Axis Attribute List" },
446 { SC_SET_CYCLIC_WRITE_LIST, "Set Cyclic Write List" },
447 { SC_SET_CYCLIC_READ_LIST, "Set Cyclic Read List" },
448 { SC_RUN_MOTOR_TEST, "Run Motor Test" },
449 { SC_GET_MOTOR_TEST_DATA, "Get Motor Test Data" },
450 { SC_RUN_INERTIA_TEST, "Run Inertia Test" },
451 { SC_GET_INERTIA_TEST_DATA, "Get Intertia Test Data" },
452 { SC_RUN_HOOKUP_TEST, "Run Hookup Test" },
453 { SC_GET_HOOKUP_TEST_DATA, "Get Hookup Test Data" },
454 { 0, NULL }
458 * Function name: dissect_cmd_data_set
460 * Purpose: Dissect the command data set field of the cyclic data block header and if any
461 * of the command value bits are set to retrieve and display those command values
463 * Returns: The number of bytes in the cyclic data used
465 static guint32
466 dissect_cmd_data_set(guint32 cmd_data_set, proto_tree* tree, tvbuff_t* tvb, guint32 offset, gboolean lreal_pos)
468 guint32 bytes_used = 0;
470 /* The order of these if statements is VERY important, this is the order the values will
471 * appear in the cyclic data */
472 if ( (cmd_data_set & COMMAND_DATA_SET_POSITION) == COMMAND_DATA_SET_POSITION )
474 /* Based on the Command Position Data Type value embedded in the Command Control
475 * header field the position is either 64-bit floating or 32-bit integer */
476 if (lreal_pos)
478 /* Display the command data set position command value */
479 proto_tree_add_item(tree, hf_cip_pos_cmd, tvb, offset + bytes_used, 8, ENC_LITTLE_ENDIAN );
480 bytes_used += 8;
482 else
484 /* Display the command data set position command value */
485 proto_tree_add_item(tree, hf_cip_pos_cmd_int, tvb, offset + bytes_used, 4, ENC_LITTLE_ENDIAN );
486 bytes_used += 4;
490 if ( (cmd_data_set & COMMAND_DATA_SET_VELOCITY) == COMMAND_DATA_SET_VELOCITY )
492 /* Display the command data set velocity command value */
493 proto_tree_add_item(tree, hf_cip_vel_cmd, tvb, offset + bytes_used, 4, ENC_LITTLE_ENDIAN );
494 bytes_used += 4;
497 if ( (cmd_data_set & COMMAND_DATA_SET_ACCELERATION) == COMMAND_DATA_SET_ACCELERATION )
499 /* Display the command data set acceleration command value */
500 proto_tree_add_item(tree, hf_cip_accel_cmd, tvb, offset + bytes_used, 4, ENC_LITTLE_ENDIAN );
501 bytes_used += 4;
504 if ( (cmd_data_set & COMMAND_DATA_SET_TORQUE) == COMMAND_DATA_SET_TORQUE )
506 /* Display the command data set torque command value */
507 proto_tree_add_item(tree, hf_cip_trq_cmd, tvb, offset + bytes_used, 4, ENC_LITTLE_ENDIAN );
508 bytes_used += 4;
511 if ( (cmd_data_set & COMMAND_DATA_SET_POSITION_TRIM) == COMMAND_DATA_SET_POSITION_TRIM )
513 /* Display the command data set position trim value */
514 proto_tree_add_item(tree, hf_cip_pos_trim, tvb, offset + bytes_used, 4, ENC_LITTLE_ENDIAN );
515 bytes_used += 4;
518 if ( (cmd_data_set & COMMAND_DATA_SET_VELOCITY_TRIM) == COMMAND_DATA_SET_VELOCITY_TRIM )
520 /* Display the command data set velocity trim value */
521 proto_tree_add_item(tree, hf_cip_vel_trim, tvb, offset + bytes_used, 4, ENC_LITTLE_ENDIAN );
522 bytes_used += 4;
525 if ( (cmd_data_set & COMMAND_DATA_SET_ACCELERATION_TRIM) == COMMAND_DATA_SET_ACCELERATION_TRIM )
527 /* Display the command data set acceleration trim value */
528 proto_tree_add_item(tree, hf_cip_accel_trim, tvb, offset + bytes_used, 4, ENC_LITTLE_ENDIAN );
529 bytes_used += 4;
532 if ( (cmd_data_set & COMMAND_DATA_SET_TORQUE_TRIM) == COMMAND_DATA_SET_TORQUE_TRIM )
534 /* Display the command data set torque trim value */
535 proto_tree_add_item(tree, hf_cip_trq_trim, tvb, offset + bytes_used, 4, ENC_LITTLE_ENDIAN );
536 bytes_used += 4;
539 return bytes_used;
544 * Function name: dissect_act_data_set
546 * Purpose: Dissect the actual data set field of the cyclic data block header and if any
547 * of the actual value bits are set to retrieve and display those feedback values
549 * Returns: The number of bytes in the cyclic data used
551 static guint32
552 dissect_act_data_set(guint32 act_data_set, proto_tree* tree, tvbuff_t* tvb, guint32 offset)
554 guint32 bytes_used = 0;
556 /* The order of these if statements is VERY important, this is the order the values will
557 * appear in the cyclic data */
558 if ( (act_data_set & ACTUAL_DATA_SET_POSITION) == ACTUAL_DATA_SET_POSITION )
560 /* Display the actual data set position feedback value */
561 proto_tree_add_item(tree, hf_cip_act_pos, tvb, offset + bytes_used, 4, ENC_LITTLE_ENDIAN );
562 bytes_used += 4;
565 if ( (act_data_set & ACTUAL_DATA_SET_VELOCITY) == ACTUAL_DATA_SET_VELOCITY )
567 /* Display the actual data set velocity feedback value */
568 proto_tree_add_item(tree, hf_cip_act_vel, tvb, offset + bytes_used, 4, ENC_LITTLE_ENDIAN );
569 bytes_used += 4;
572 if ( (act_data_set & ACTUAL_DATA_SET_ACCELERATION) == ACTUAL_DATA_SET_ACCELERATION )
574 /* Display the actual data set acceleration feedback value */
575 proto_tree_add_item(tree, hf_cip_act_accel, tvb, offset + bytes_used, 4, ENC_LITTLE_ENDIAN );
576 bytes_used += 4;
579 if ( (act_data_set & ACTUAL_DATA_SET_TORQUE) == ACTUAL_DATA_SET_TORQUE )
581 /* Display the actual data set torque feedback value */
582 proto_tree_add_item(tree, hf_cip_act_trq, tvb, offset + bytes_used, 4, ENC_LITTLE_ENDIAN );
583 bytes_used += 4;
585 if ( (act_data_set & ACTUAL_DATA_SET_CURRENT) == ACTUAL_DATA_SET_CURRENT )
587 /* Display the actual data set current feedback value */
588 proto_tree_add_item(tree, hf_cip_act_crnt, tvb, offset + bytes_used, 4, ENC_LITTLE_ENDIAN );
589 bytes_used += 4;
592 if ( (act_data_set & ACTUAL_DATA_SET_VOLTAGE) == ACTUAL_DATA_SET_VOLTAGE )
594 /* Display the actual data set voltage feedback value */
595 proto_tree_add_item(tree, hf_cip_act_volts, tvb, offset + bytes_used, 4, ENC_LITTLE_ENDIAN );
596 bytes_used += 4;
599 if ( (act_data_set & ACTUAL_DATA_SET_FREQUENCY) == ACTUAL_DATA_SET_FREQUENCY )
601 /* Display the actual data set frequency feedback value */
602 proto_tree_add_item(tree, hf_cip_act_freq, tvb, offset + bytes_used, 4, ENC_LITTLE_ENDIAN );
603 bytes_used += 4;
606 return bytes_used;
610 * Function name: dissect_status_data_set
612 * Purpose: Dissect the status data set field of the cyclic data block header and if any
613 * of the status value bits are set to retrieve and display those status values
615 * Returns: The number of bytes in the cyclic data used
617 static guint32
618 dissect_status_data_set(guint32 status_data_set, proto_tree* tree, tvbuff_t* tvb, guint32 offset)
620 guint32 bytes_used = 0;
621 proto_item *temp_proto_item;
622 proto_tree *temp_proto_tree;
624 /* The order of these if statements is VERY important, this is the order the values will
625 * appear in the cyclic data */
626 if ( (status_data_set & STATUS_DATA_SET_AXIS_FAULT) == STATUS_DATA_SET_AXIS_FAULT )
628 /* Display the various fault codes from the device */
629 proto_tree_add_item(tree, hf_cip_fault_type, tvb, offset + bytes_used, 1, ENC_LITTLE_ENDIAN);
630 bytes_used += 1;
632 proto_tree_add_item(tree, hf_cip_axis_fault, tvb, offset + bytes_used, 1, ENC_LITTLE_ENDIAN);
633 bytes_used += 1;
635 proto_tree_add_item(tree, hf_cip_fault_sub_code, tvb, offset + bytes_used, 1, ENC_LITTLE_ENDIAN);
636 bytes_used += 1;
638 proto_tree_add_item(tree, hf_cip_fault_action, tvb, offset + bytes_used, 1, ENC_LITTLE_ENDIAN);
639 bytes_used += 1;
641 proto_tree_add_item(tree, hf_cip_fault_time_stamp, tvb, offset + bytes_used, 8, ENC_LITTLE_ENDIAN);
642 bytes_used += 8;
645 if ( (status_data_set & STATUS_DATA_SET_AXIS_ALARM) == STATUS_DATA_SET_AXIS_ALARM )
647 /* Display the various alarm codes from the device */
648 proto_tree_add_item(tree, hf_cip_alarm_type, tvb, offset + bytes_used, 1, ENC_LITTLE_ENDIAN);
649 bytes_used += 1;
651 proto_tree_add_item(tree, hf_cip_axis_alarm, tvb, offset + bytes_used, 1, ENC_LITTLE_ENDIAN);
652 bytes_used += 1;
654 proto_tree_add_item(tree, hf_cip_alarm_sub_code, tvb, offset + bytes_used, 1, ENC_LITTLE_ENDIAN);
655 bytes_used += 1;
657 proto_tree_add_item(tree, hf_cip_alarm_state, tvb, offset + bytes_used, 1, ENC_LITTLE_ENDIAN);
658 bytes_used += 1;
660 proto_tree_add_item(tree, hf_cip_alarm_time_stamp, tvb, offset + bytes_used, 8, ENC_LITTLE_ENDIAN);
661 bytes_used += 8;
664 if ( (status_data_set & STATUS_DATA_SET_AXIS_STATUS) == STATUS_DATA_SET_AXIS_STATUS )
666 /* Display the various axis state values from the device */
667 temp_proto_item = proto_tree_add_item(tree, hf_cip_axis_status, tvb, offset + bytes_used, 4, ENC_LITTLE_ENDIAN);
668 temp_proto_tree = proto_item_add_subtree( temp_proto_item, ett_axis_status_set );
669 proto_tree_add_item( temp_proto_tree, hf_cip_axis_sts_local_ctrl, tvb, offset + bytes_used, 4, ENC_LITTLE_ENDIAN );
670 proto_tree_add_item( temp_proto_tree, hf_cip_axis_sts_alarm, tvb, offset + bytes_used, 4, ENC_LITTLE_ENDIAN );
671 proto_tree_add_item( temp_proto_tree, hf_cip_axis_sts_dc_bus, tvb, offset + bytes_used, 4, ENC_LITTLE_ENDIAN );
672 proto_tree_add_item( temp_proto_tree, hf_cip_axis_sts_pwr_struct, tvb, offset + bytes_used, 4, ENC_LITTLE_ENDIAN );
673 proto_tree_add_item( temp_proto_tree, hf_cip_axis_sts_tracking, tvb, offset + bytes_used, 4, ENC_LITTLE_ENDIAN );
674 proto_tree_add_item( temp_proto_tree, hf_cip_axis_sts_pos_lock, tvb, offset + bytes_used, 4, ENC_LITTLE_ENDIAN );
675 proto_tree_add_item( temp_proto_tree, hf_cip_axis_sts_vel_lock, tvb, offset + bytes_used, 4, ENC_LITTLE_ENDIAN );
676 proto_tree_add_item( temp_proto_tree, hf_cip_axis_sts_vel_standstill, tvb, offset + bytes_used, 4, ENC_LITTLE_ENDIAN );
677 proto_tree_add_item( temp_proto_tree, hf_cip_axis_sts_vel_threshold, tvb, offset + bytes_used, 4, ENC_LITTLE_ENDIAN );
678 proto_tree_add_item( temp_proto_tree, hf_cip_axis_sts_vel_limit, tvb, offset + bytes_used, 4, ENC_LITTLE_ENDIAN );
679 proto_tree_add_item( temp_proto_tree, hf_cip_axis_sts_acc_limit, tvb, offset + bytes_used, 4, ENC_LITTLE_ENDIAN );
680 proto_tree_add_item( temp_proto_tree, hf_cip_axis_sts_dec_limit, tvb, offset + bytes_used, 4, ENC_LITTLE_ENDIAN );
681 proto_tree_add_item( temp_proto_tree, hf_cip_axis_sts_torque_threshold, tvb, offset + bytes_used, 4, ENC_LITTLE_ENDIAN );
682 proto_tree_add_item( temp_proto_tree, hf_cip_axis_sts_torque_limit, tvb, offset + bytes_used, 4, ENC_LITTLE_ENDIAN );
683 proto_tree_add_item( temp_proto_tree, hf_cip_axis_sts_cur_limit, tvb, offset + bytes_used, 4, ENC_LITTLE_ENDIAN );
684 proto_tree_add_item( temp_proto_tree, hf_cip_axis_sts_therm_limit, tvb, offset + bytes_used, 4, ENC_LITTLE_ENDIAN );
685 proto_tree_add_item( temp_proto_tree, hf_cip_axis_sts_feedback_integ, tvb, offset + bytes_used, 4, ENC_LITTLE_ENDIAN );
686 proto_tree_add_item( temp_proto_tree, hf_cip_axis_sts_shutdown, tvb, offset + bytes_used, 4, ENC_LITTLE_ENDIAN );
687 proto_tree_add_item( temp_proto_tree, hf_cip_axis_sts_in_process, tvb, offset + bytes_used, 4, ENC_LITTLE_ENDIAN );
688 bytes_used += 4;
690 proto_tree_add_item(tree, hf_cip_axis_status_mfg, tvb, offset + bytes_used, 4, ENC_LITTLE_ENDIAN);
691 bytes_used += 4;
694 if ( (status_data_set & STATUS_DATA_SET_AXIS_IO_STATUS) == STATUS_DATA_SET_AXIS_IO_STATUS )
696 proto_tree_add_item(tree, hf_cip_axis_io_status, tvb, offset + bytes_used, 4, ENC_LITTLE_ENDIAN);
697 bytes_used += 4;
699 proto_tree_add_item(tree, hf_cip_axis_io_status_mfg, tvb, offset + bytes_used, 4, ENC_LITTLE_ENDIAN);
700 bytes_used += 4;
703 if ( (status_data_set & STATUS_DATA_SET_AXIS_SAFETY) == STATUS_DATA_SET_AXIS_SAFETY )
705 proto_tree_add_item(tree, hf_cip_safety_status, tvb, offset + bytes_used, 4, ENC_LITTLE_ENDIAN);
706 bytes_used += 4;
709 return bytes_used;
713 * Function name: dissect_cntr_cyclic
715 * Purpose: Dissect the cyclic data block of a controller to device format message
717 * Returns: The new offset into the message that follow on dissections should use
718 * as their starting offset
720 static guint32
721 dissect_cntr_cyclic(guint32 con_format _U_, tvbuff_t* tvb, proto_tree* tree, guint32 offset, guint32 size, guint32 instance _U_)
723 proto_item *header_item, *temp_proto_item;
724 proto_tree *header_tree, *temp_proto_tree;
725 guint32 temp_data;
726 gboolean lreal_pos;
727 guint32 bytes_used = 0;
729 /* Create the tree for the entire instance data header */
730 header_item = proto_tree_add_text(tree, tvb, offset, size, "Cyclic Data Block");
731 header_tree = proto_item_add_subtree(header_item, ett_cyclic_data_block);
733 /* Add the control mode header field to the tree */
734 proto_tree_add_item(header_tree, hf_cip_motor_cntrl, tvb, offset, 1, ENC_LITTLE_ENDIAN);
736 /* Add the feedback config header field to the tree */
737 proto_tree_add_item(header_tree, hf_cip_fdbk_config, tvb, offset + 1, 1, ENC_LITTLE_ENDIAN);
739 /* Add the axis control field to the tree */
740 proto_tree_add_item(header_tree, hf_cip_axis_control, tvb, offset + 2, 1, ENC_LITTLE_ENDIAN);
742 /* Add the control status to the tree */
743 proto_tree_add_item(header_tree, hf_cip_control_status, tvb, offset + 3, 1, ENC_LITTLE_ENDIAN);
745 /* Read the command control header field from the packet into memory and determine if the dissector
746 * should be using an LREAL or DINT for position */
747 temp_data = tvb_get_guint8(tvb, offset + 7);
748 lreal_pos = ( (temp_data & COMMAND_CONTROL_POSITION_DATA_TYPE) == POSITION_DATA_LREAL );
750 /* Read the command data set header field from the packet into memory */
751 temp_data = tvb_get_guint8(tvb, offset + 4);
753 /* Create the tree for the command data set header field */
754 temp_proto_item = proto_tree_add_item(header_tree, hf_cip_cmd_data_set, tvb, offset + 4, 1, ENC_LITTLE_ENDIAN);
755 temp_proto_tree = proto_item_add_subtree(temp_proto_item, ett_command_data_set);
756 proto_tree_add_item(temp_proto_tree, hf_cip_cmd_data_pos_cmd, tvb, offset + 4, 1, ENC_LITTLE_ENDIAN);
757 proto_tree_add_item(temp_proto_tree, hf_cip_cmd_data_vel_cmd, tvb, offset + 4, 1, ENC_LITTLE_ENDIAN);
758 proto_tree_add_item(temp_proto_tree, hf_cip_cmd_data_acc_cmd, tvb, offset + 4, 1, ENC_LITTLE_ENDIAN);
759 proto_tree_add_item(temp_proto_tree, hf_cip_cmd_data_trq_cmd, tvb, offset + 4, 1, ENC_LITTLE_ENDIAN);
760 proto_tree_add_item(temp_proto_tree, hf_cip_cmd_data_pos_trim_cmd, tvb, offset + 4, 1, ENC_LITTLE_ENDIAN);
761 proto_tree_add_item(temp_proto_tree, hf_cip_cmd_data_vel_trim_cmd, tvb, offset + 4, 1, ENC_LITTLE_ENDIAN);
762 proto_tree_add_item(temp_proto_tree, hf_cip_cmd_data_acc_trim_cmd, tvb, offset + 4, 1, ENC_LITTLE_ENDIAN);
763 proto_tree_add_item(temp_proto_tree, hf_cip_cmd_data_trq_trim_cmd, tvb, offset + 4, 1, ENC_LITTLE_ENDIAN);
765 /* Display the command data values from the cyclic data payload within the command data set tree, the
766 * cyclic data starts immediately after the interpolation control field in the controller to device
767 * direction */
768 bytes_used += dissect_cmd_data_set(temp_data, temp_proto_tree, tvb, offset + 8 + bytes_used, lreal_pos);
770 /* Create the tree for the actual data set header field */
771 temp_proto_item = proto_tree_add_item(header_tree, hf_cip_act_data_set, tvb, offset + 5, 1, ENC_LITTLE_ENDIAN);
772 temp_proto_tree = proto_item_add_subtree(temp_proto_item, ett_actual_data_set);
773 proto_tree_add_item(temp_proto_tree, hf_cip_act_data_pos, tvb, offset + 5, 1, ENC_LITTLE_ENDIAN);
774 proto_tree_add_item(temp_proto_tree, hf_cip_act_data_vel, tvb, offset + 5, 1, ENC_LITTLE_ENDIAN);
775 proto_tree_add_item(temp_proto_tree, hf_cip_act_data_acc, tvb, offset + 5, 1, ENC_LITTLE_ENDIAN);
776 proto_tree_add_item(temp_proto_tree, hf_cip_act_data_trq, tvb, offset + 5, 1, ENC_LITTLE_ENDIAN);
777 proto_tree_add_item(temp_proto_tree, hf_cip_act_data_crnt, tvb, offset + 5, 1, ENC_LITTLE_ENDIAN);
778 proto_tree_add_item(temp_proto_tree, hf_cip_act_data_vltg, tvb, offset + 5, 1, ENC_LITTLE_ENDIAN);
779 proto_tree_add_item(temp_proto_tree, hf_cip_act_data_fqcy, tvb, offset + 5, 1, ENC_LITTLE_ENDIAN);
781 /* Create the tree for the status data set header field */
782 temp_proto_item = proto_tree_add_item(header_tree, hf_cip_sts_data_set, tvb, offset + 6, 1, ENC_LITTLE_ENDIAN);
783 temp_proto_tree = proto_item_add_subtree(temp_proto_item, ett_status_data_set);
784 proto_tree_add_item(temp_proto_tree, hf_cip_sts_flt, tvb, offset + 6, 1, ENC_LITTLE_ENDIAN);
785 proto_tree_add_item(temp_proto_tree, hf_cip_sts_alrm, tvb, offset + 6, 1, ENC_LITTLE_ENDIAN);
786 proto_tree_add_item(temp_proto_tree, hf_cip_sts_sts, tvb, offset + 6, 1, ENC_LITTLE_ENDIAN);
787 proto_tree_add_item(temp_proto_tree, hf_cip_sts_iosts, tvb, offset + 6, 1, ENC_LITTLE_ENDIAN);
788 proto_tree_add_item(temp_proto_tree, hf_cip_sts_safety, tvb, offset + 6, 1, ENC_LITTLE_ENDIAN);
790 /* Create the tree for the command control header field */
791 temp_proto_item = proto_tree_add_item(header_tree, hf_cip_command_control, tvb, offset + 7, 1, ENC_LITTLE_ENDIAN);
792 temp_proto_tree = proto_item_add_subtree(temp_proto_item, ett_command_control);
794 /* Display the interpolation control and position format fields */
795 proto_tree_add_item(temp_proto_tree, hf_cip_intrp, tvb, offset + 7, 1, ENC_LITTLE_ENDIAN);
796 proto_tree_add_item(temp_proto_tree, hf_cip_position_data_type, tvb, offset + 7, 1, ENC_LITTLE_ENDIAN);
798 /* Return the offset to the next byte in the message */
799 return offset + 8 + bytes_used;
803 * Function name: dissect_devce_cyclic
805 * Purpose: Dissect the cyclic data block of a device to controller format message
807 * Returns: The new offset into the message that follow on dissections should use
808 * as their starting offset
810 static guint32
811 dissect_devce_cyclic(guint32 con_format _U_, tvbuff_t* tvb, proto_tree* tree, guint32 offset, guint32 size, guint32 instance _U_)
813 proto_item *header_item, *temp_proto_item;
814 proto_tree *header_tree, *temp_proto_tree;
815 guint32 temp_data;
816 guint32 bytes_used = 0;
818 /* Create the tree for the entire instance data header */
819 header_item = proto_tree_add_text(tree, tvb, offset, size, "Cyclic Data Block");
820 header_tree = proto_item_add_subtree(header_item, ett_cyclic_data_block);
822 /* Add the control mode header field to the tree */
823 proto_tree_add_item(header_tree, hf_cip_motor_cntrl, tvb, offset, 1, ENC_LITTLE_ENDIAN);
825 /* Add the feedback config header field to the tree */
826 proto_tree_add_item(header_tree, hf_cip_fdbk_config, tvb, offset + 1, 1, ENC_LITTLE_ENDIAN);
828 /* Add the axis response field to the tree */
829 proto_tree_add_item(header_tree, hf_cip_axis_response, tvb, offset + 2, 1, ENC_LITTLE_ENDIAN);
831 /* Add the axis response status to the tree */
832 proto_tree_add_item(header_tree, hf_cip_axis_resp_stat, tvb, offset + 3, 1, ENC_LITTLE_ENDIAN);
834 /* Read the actual data set header field from the packet into memory */
835 temp_data = tvb_get_guint8(tvb, offset + 5);
837 /* Create the tree for the actual data set header field */
838 temp_proto_item = proto_tree_add_item(header_tree, hf_cip_act_data_set, tvb, offset + 5, 1, ENC_LITTLE_ENDIAN);
839 temp_proto_tree = proto_item_add_subtree(temp_proto_item, ett_actual_data_set);
840 proto_tree_add_item(temp_proto_tree, hf_cip_act_data_pos, tvb, offset + 5, 1, ENC_LITTLE_ENDIAN);
841 proto_tree_add_item(temp_proto_tree, hf_cip_act_data_vel, tvb, offset + 5, 1, ENC_LITTLE_ENDIAN);
842 proto_tree_add_item(temp_proto_tree, hf_cip_act_data_acc, tvb, offset + 5, 1, ENC_LITTLE_ENDIAN);
843 proto_tree_add_item(temp_proto_tree, hf_cip_act_data_trq, tvb, offset + 5, 1, ENC_LITTLE_ENDIAN);
844 proto_tree_add_item(temp_proto_tree, hf_cip_act_data_crnt, tvb, offset + 5, 1, ENC_LITTLE_ENDIAN);
845 proto_tree_add_item(temp_proto_tree, hf_cip_act_data_vltg, tvb, offset + 5, 1, ENC_LITTLE_ENDIAN);
846 proto_tree_add_item(temp_proto_tree, hf_cip_act_data_fqcy, tvb, offset + 5, 1, ENC_LITTLE_ENDIAN);
848 /* Display the actual data values from the cyclic data payload within the command data set tree, the
849 * cyclic data starts immediately after the interpolation control field in the controller to device
850 * direction and the actual data starts immediately after the cyclic data */
851 bytes_used += dissect_act_data_set(temp_data, temp_proto_tree, tvb, offset + 8 + bytes_used);
853 /* Read the status data set header field from the packet into memory */
854 temp_data = tvb_get_guint8(tvb, offset + 6);
856 /* Create the tree for the status data set header field */
857 temp_proto_item = proto_tree_add_item(header_tree, hf_cip_sts_data_set, tvb, offset + 6, 1, ENC_LITTLE_ENDIAN);
858 temp_proto_tree = proto_item_add_subtree(temp_proto_item, ett_status_data_set);
859 proto_tree_add_item(temp_proto_tree, hf_cip_sts_flt, tvb, offset + 6, 1, ENC_LITTLE_ENDIAN);
860 proto_tree_add_item(temp_proto_tree, hf_cip_sts_alrm, tvb, offset + 6, 1, ENC_LITTLE_ENDIAN);
861 proto_tree_add_item(temp_proto_tree, hf_cip_sts_sts, tvb, offset + 6, 1, ENC_LITTLE_ENDIAN);
862 proto_tree_add_item(temp_proto_tree, hf_cip_sts_iosts, tvb, offset + 6, 1, ENC_LITTLE_ENDIAN);
863 proto_tree_add_item(temp_proto_tree, hf_cip_sts_safety, tvb, offset + 6, 1, ENC_LITTLE_ENDIAN);
865 /* Display the status data values from the cyclic data payload within the status data set tree, the
866 * cyclic data starts immediately after the axis state field in the device to controller
867 * direction and the status data starts immediately after the cyclic data */
868 bytes_used += dissect_status_data_set(temp_data, temp_proto_tree, tvb, offset + 8 + bytes_used);
870 /* Display the axis state control field */
871 proto_tree_add_item(header_tree, hf_cip_axis_state, tvb, offset + 7, 1, ENC_LITTLE_ENDIAN);
873 /* Return the offset to the next byte in the message */
874 return offset + 8 + bytes_used;
878 * Function name: dissect_cyclic_wt
880 * Purpose: Dissect the cyclic write data block in a controller to device message
882 * Returns: The new offset into the message that follow on dissections should use
883 * as their starting offset
885 static guint32
886 dissect_cyclic_wt(tvbuff_t* tvb, proto_tree* tree, guint32 offset, guint32 size)
888 proto_item *header_item;
889 proto_tree *header_tree;
891 /* Create the tree for the entire cyclic write data block */
892 header_item = proto_tree_add_text(tree, tvb, offset, size, "Cyclic Write Data Block");
893 header_tree = proto_item_add_subtree(header_item, ett_cyclic_rd_wt);
895 /* Display the cyclic write block id value */
896 proto_tree_add_item(header_tree, hf_cip_cyclic_write_blk, tvb, offset, 1, ENC_LITTLE_ENDIAN);
898 /* Display the cyclic read block id value */
899 proto_tree_add_item(header_tree, hf_cip_cyclic_read_blk, tvb, offset + 2, 1, ENC_LITTLE_ENDIAN);
901 /* Display the remainder of the cyclic write data if there is any */
902 if ( (size - 4) > 0 )
904 proto_tree_add_item(header_tree, hf_cip_cyclic_wrt_data, tvb, offset + 4, size - 4, ENC_NA);
907 return offset + size;
911 * Function name: dissect_cyclic_rd
913 * Purpose: Dissect the cyclic read data block in a device to controller message
915 * Returns: The new offset into the message that follow on dissections should use
916 * as their starting offset
918 static guint32
919 dissect_cyclic_rd(tvbuff_t* tvb, proto_tree* tree, guint32 offset, guint32 size)
921 proto_item *header_item;
922 proto_tree *header_tree;
924 /* Create the tree for the entire cyclic write data block */
925 header_item = proto_tree_add_text(tree, tvb, offset, size, "Cyclic Read Data Block");
926 header_tree = proto_item_add_subtree(header_item, ett_cyclic_rd_wt);
928 /* Display the cyclic write block id value */
929 proto_tree_add_item(header_tree, hf_cip_cyclic_write_blk, tvb, offset, 1, ENC_LITTLE_ENDIAN);
931 /* Display the cyclic write status value */
932 proto_tree_add_item(header_tree, hf_cip_cyclic_write_sts, tvb, offset + 1, 1, ENC_LITTLE_ENDIAN);
934 /* Display the cyclic read block id value */
935 proto_tree_add_item(header_tree, hf_cip_cyclic_read_blk, tvb, offset + 2, 1, ENC_LITTLE_ENDIAN);
937 /* Display the cyclic read status value */
938 proto_tree_add_item(header_tree, hf_cip_cyclic_read_sts, tvb, offset + 3, 1, ENC_LITTLE_ENDIAN);
940 /* Display the remainder of the cyclic read data if there is any*/
941 if ( (size - 4) > 0 )
943 proto_tree_add_item(header_tree, hf_cip_cyclic_rd_data, tvb, offset + 4, size - 4, ENC_NA);
946 return offset + size;
950 * Function name: dissect_cntr_event
952 * Purpose: Dissect the event data block in a controller to device message
954 * Returns: The new offset into the message that follow on dissections should use
955 * as their starting offset
957 static guint32
958 dissect_cntr_event(tvbuff_t* tvb, proto_tree* tree, guint32 offset, guint32 size)
960 proto_item *header_item, *temp_proto_item;
961 proto_tree *header_tree, *temp_proto_tree;
962 guint32 temp_data;
963 guint32 acks, cur_ack;
964 guint32 bytes_used = 0;
966 /* Create the tree for the entire cyclic write data block */
967 header_item = proto_tree_add_text(tree, tvb, offset, size, "Event Data Block");
968 header_tree = proto_item_add_subtree(header_item, ett_event);
970 /* Read the event checking control header field from the packet into memory */
971 temp_data = tvb_get_letohl(tvb, offset);
973 /* Create the tree for the event checking control header field */
974 temp_proto_item = proto_tree_add_item(header_tree, hf_cip_event_checking, tvb, offset, 4, ENC_LITTLE_ENDIAN);
975 temp_proto_tree = proto_item_add_subtree(temp_proto_item, ett_event_check_ctrl);
977 /* Add the individual elements of the event checking control */
978 proto_tree_add_item(temp_proto_tree, hf_cip_evnt_ctrl_reg1_pos, tvb, offset, 4, ENC_LITTLE_ENDIAN);
979 proto_tree_add_item(temp_proto_tree, hf_cip_evnt_ctrl_reg1_neg, tvb, offset, 4, ENC_LITTLE_ENDIAN);
980 proto_tree_add_item(temp_proto_tree, hf_cip_evnt_ctrl_reg2_pos, tvb, offset, 4, ENC_LITTLE_ENDIAN);
981 proto_tree_add_item(temp_proto_tree, hf_cip_evnt_ctrl_reg2_neg, tvb, offset, 4, ENC_LITTLE_ENDIAN);
982 proto_tree_add_item(temp_proto_tree, hf_cip_evnt_ctrl_reg1_posrearm, tvb, offset, 4, ENC_LITTLE_ENDIAN);
983 proto_tree_add_item(temp_proto_tree, hf_cip_evnt_ctrl_reg1_negrearm, tvb, offset, 4, ENC_LITTLE_ENDIAN);
984 proto_tree_add_item(temp_proto_tree, hf_cip_evnt_ctrl_reg2_posrearm, tvb, offset, 4, ENC_LITTLE_ENDIAN);
985 proto_tree_add_item(temp_proto_tree, hf_cip_evnt_ctrl_reg2_negrearm, tvb, offset, 4, ENC_LITTLE_ENDIAN);
986 proto_tree_add_item(temp_proto_tree, hf_cip_evnt_ctrl_marker_pos, tvb, offset, 4, ENC_LITTLE_ENDIAN);
987 proto_tree_add_item(temp_proto_tree, hf_cip_evnt_ctrl_marker_neg, tvb, offset, 4, ENC_LITTLE_ENDIAN);
988 proto_tree_add_item(temp_proto_tree, hf_cip_evnt_ctrl_home_pos, tvb, offset, 4, ENC_LITTLE_ENDIAN);
989 proto_tree_add_item(temp_proto_tree, hf_cip_evnt_ctrl_home_neg, tvb, offset, 4, ENC_LITTLE_ENDIAN);
990 proto_tree_add_item(temp_proto_tree, hf_cip_evnt_ctrl_home_pp, tvb, offset, 4, ENC_LITTLE_ENDIAN);
991 proto_tree_add_item(temp_proto_tree, hf_cip_evnt_ctrl_home_pm, tvb, offset, 4, ENC_LITTLE_ENDIAN);
992 proto_tree_add_item(temp_proto_tree, hf_cip_evnt_ctrl_home_mp, tvb, offset, 4, ENC_LITTLE_ENDIAN);
993 proto_tree_add_item(temp_proto_tree, hf_cip_evnt_ctrl_home_mm, tvb, offset, 4, ENC_LITTLE_ENDIAN);
994 proto_tree_add_item(temp_proto_tree, hf_cip_evnt_ctrl_acks, tvb, offset, 4, ENC_LITTLE_ENDIAN);
995 /* The dissector will indicate if the protocol is requesting an extended event format but will not dissect it,
996 * to date no products actually support this format */
997 proto_tree_add_item(temp_proto_tree, hf_cip_evnt_extend_format, tvb, offset, 4, ENC_LITTLE_ENDIAN);
999 /* The event checking control value is 4 bytes long */
1000 bytes_used = 4;
1002 /* The final 4 bits of the event checking control value are the number of acknowledgements in the message */
1003 acks = (temp_data >> 28) & 0x0F;
1005 /* Each acknowledgement contains and id and a status value */
1006 for (cur_ack = 0; cur_ack < acks; cur_ack++)
1008 /* Display the current acknowledgement id */
1009 proto_tree_add_item(header_tree, hf_cip_event_ack, tvb, offset + bytes_used, 1, ENC_LITTLE_ENDIAN);
1010 bytes_used += 1;
1012 /* Display the current event status */
1013 proto_tree_add_item(header_tree, hf_cip_evnt_sts_stat, tvb, offset + bytes_used, 1, ENC_LITTLE_ENDIAN);
1014 bytes_used += 1;
1017 return offset + size;
1021 * Function name: dissect_devce_event
1023 * Purpose: Dissect the event data block in a device to controller message
1025 * Returns: The new offset into the message that follow on dissections should use
1026 * as their starting offset
1028 static guint32
1029 dissect_devce_event(tvbuff_t* tvb, proto_tree* tree, guint32 offset, guint32 size)
1031 proto_item *header_item, *temp_proto_item;
1032 proto_tree *header_tree, *temp_proto_tree;
1033 guint64 temp_data;
1034 guint64 nots, cur_not;
1035 guint32 bytes_used = 0;
1037 /* Create the tree for the entire cyclic write data block */
1038 header_item = proto_tree_add_text(tree, tvb, offset, size, "Event Data Block");
1039 header_tree = proto_item_add_subtree(header_item, ett_event);
1041 /* Read the event checking control header field from the packet into memory */
1042 temp_data = tvb_get_letohl(tvb, offset);
1044 /* Create the tree for the event checking control header field */
1045 temp_proto_item = proto_tree_add_item(header_tree, hf_cip_event_status, tvb, offset, 4, ENC_LITTLE_ENDIAN);
1046 temp_proto_tree = proto_item_add_subtree(temp_proto_item, ett_event_check_sts);
1048 /* Add the individual elements of the event checking control */
1049 proto_tree_add_item(temp_proto_tree, hf_cip_evnt_sts_reg1_pos, tvb, offset, 4, ENC_LITTLE_ENDIAN);
1050 proto_tree_add_item(temp_proto_tree, hf_cip_evnt_sts_reg1_neg, tvb, offset, 4, ENC_LITTLE_ENDIAN);
1051 proto_tree_add_item(temp_proto_tree, hf_cip_evnt_sts_reg2_pos, tvb, offset, 4, ENC_LITTLE_ENDIAN);
1052 proto_tree_add_item(temp_proto_tree, hf_cip_evnt_sts_reg2_neg, tvb, offset, 4, ENC_LITTLE_ENDIAN);
1053 proto_tree_add_item(temp_proto_tree, hf_cip_evnt_sts_reg1_posrearm, tvb, offset, 4, ENC_LITTLE_ENDIAN);
1054 proto_tree_add_item(temp_proto_tree, hf_cip_evnt_sts_reg1_negrearm, tvb, offset, 4, ENC_LITTLE_ENDIAN);
1055 proto_tree_add_item(temp_proto_tree, hf_cip_evnt_sts_reg2_posrearm, tvb, offset, 4, ENC_LITTLE_ENDIAN);
1056 proto_tree_add_item(temp_proto_tree, hf_cip_evnt_sts_reg2_negrearm, tvb, offset, 4, ENC_LITTLE_ENDIAN);
1057 proto_tree_add_item(temp_proto_tree, hf_cip_evnt_sts_marker_pos, tvb, offset, 4, ENC_LITTLE_ENDIAN);
1058 proto_tree_add_item(temp_proto_tree, hf_cip_evnt_sts_marker_neg, tvb, offset, 4, ENC_LITTLE_ENDIAN);
1059 proto_tree_add_item(temp_proto_tree, hf_cip_evnt_sts_home_pos, tvb, offset, 4, ENC_LITTLE_ENDIAN);
1060 proto_tree_add_item(temp_proto_tree, hf_cip_evnt_sts_home_neg, tvb, offset, 4, ENC_LITTLE_ENDIAN);
1061 proto_tree_add_item(temp_proto_tree, hf_cip_evnt_sts_home_pp, tvb, offset, 4, ENC_LITTLE_ENDIAN);
1062 proto_tree_add_item(temp_proto_tree, hf_cip_evnt_sts_home_pm, tvb, offset, 4, ENC_LITTLE_ENDIAN);
1063 proto_tree_add_item(temp_proto_tree, hf_cip_evnt_sts_home_mp, tvb, offset, 4, ENC_LITTLE_ENDIAN);
1064 proto_tree_add_item(temp_proto_tree, hf_cip_evnt_sts_home_mm, tvb, offset, 4, ENC_LITTLE_ENDIAN);
1065 proto_tree_add_item(temp_proto_tree, hf_cip_evnt_sts_nfs, tvb, offset, 4, ENC_LITTLE_ENDIAN);
1066 /* The dissector will indicate if the protocol is requesting an extended event format but will not dissect it,
1067 * to date no products actually support this format */
1068 proto_tree_add_item(temp_proto_tree, hf_cip_evnt_extend_format, tvb, offset, 4, ENC_LITTLE_ENDIAN);
1070 /* The event status control value is 4 bytes long */
1071 bytes_used = 4;
1073 /* The final 4 bits of the event status control value are the number of notifications in the message */
1074 nots = (temp_data >> 28) & 0x0F;
1076 /* Each notification contains and id, status value, event type, position and time stamp */
1077 for (cur_not = 0; cur_not < nots; cur_not++)
1079 /* Display the current event id */
1080 proto_tree_add_item(header_tree, hf_cip_event_id, tvb, offset + bytes_used, 1, ENC_LITTLE_ENDIAN);
1081 bytes_used += 1;
1083 /* Display the current event status */
1084 proto_tree_add_item(header_tree, hf_cip_evnt_sts_stat, tvb, offset + bytes_used, 1, ENC_LITTLE_ENDIAN);
1085 bytes_used += 1;
1087 /* Display the current event type */
1088 proto_tree_add_item(header_tree, hf_cip_evnt_type, tvb, offset + bytes_used, 1, ENC_LITTLE_ENDIAN);
1089 bytes_used += 2; /* Increment by 2 to jump the reserved byte */
1091 /* Display the event position value */
1092 proto_tree_add_item(header_tree, hf_cip_event_pos, tvb, offset + bytes_used, 4, ENC_LITTLE_ENDIAN);
1093 bytes_used += 4;
1095 /* Display the event time stamp value */
1096 proto_tree_add_item(header_tree, hf_cip_event_ts, tvb, offset + bytes_used, 8, ENC_LITTLE_ENDIAN);
1097 bytes_used += 8;
1100 return size + offset;
1104 * Function name: dissect_get_axis_attr_list_request
1106 * Purpose: Dissect the get axis attribute list service request
1108 * Returns: None
1110 static void
1111 dissect_get_axis_attr_list_request (tvbuff_t* tvb, proto_tree* tree, guint32 offset, guint32 size)
1113 proto_item *header_item, *attr_item;
1114 proto_tree *header_tree, *attr_tree;
1115 guint16 attribute, attribute_cnt;
1116 guint32 local_offset;
1117 guint8 increment_size, dimension;
1119 /* Create the tree for the get axis attribute list request */
1120 header_item = proto_tree_add_text(tree, tvb, offset, size, "Get Axis Attribute List Request");
1121 header_tree = proto_item_add_subtree(header_item, ett_get_axis_attribute);
1123 /* Read the number of attributes that are contained within the request */
1124 attribute_cnt = tvb_get_letohs(tvb, offset);
1125 proto_tree_add_item(header_tree, hf_get_axis_attr_list_attribute_cnt, tvb, offset, 2, ENC_LITTLE_ENDIAN);
1127 /* Start the attribute loop at the beginning of the first attribute in the list */
1128 local_offset = offset + 4;
1130 /* For each attribute display the associated fields */
1131 for (attribute = 0; attribute < attribute_cnt; attribute++)
1133 /* At a minimum the local offset needs will need to be incremented by 4 bytes to reach the next attribute */
1134 increment_size = 4;
1136 /* Pull the fields for this attribute from the payload, all fields are needed to make some calculations before
1137 * properly displaying of the attribute is possible */
1138 dimension = tvb_get_guint8(tvb, local_offset + 2);
1140 /* Create the tree for this attribute within the request */
1141 attr_item = proto_tree_add_item(header_tree, hf_get_axis_attr_list_attribute_id, tvb, local_offset, 2, ENC_LITTLE_ENDIAN);
1142 attr_tree = proto_item_add_subtree(attr_item, ett_get_axis_attr_list);
1144 proto_tree_add_item(attr_tree, hf_get_axis_attr_list_dimension, tvb, local_offset + 2, 1, ENC_LITTLE_ENDIAN);
1145 proto_tree_add_item(attr_tree, hf_get_axis_attr_list_element_size, tvb, local_offset + 3, 1, ENC_LITTLE_ENDIAN);
1147 if (dimension == 1)
1149 /* Display the start index and start index from the request if this is an array request */
1150 proto_tree_add_item(attr_tree, hf_get_axis_attr_list_start_index, tvb, local_offset + 4, 2, ENC_LITTLE_ENDIAN);
1151 proto_tree_add_item(attr_tree, hf_get_axis_attr_list_data_elements, tvb, local_offset + 6, 2, ENC_LITTLE_ENDIAN);
1153 /* Modify the amount to update the local offset by and the start of the data to include the index and elements field */
1154 increment_size += 4;
1157 /* Move the local offset to the next attribute */
1158 local_offset += increment_size;
1163 * Function name: dissect_set_axis_attr_list_request
1165 * Purpose: Dissect the set axis attribute list service request
1167 * Returns: None
1169 static void
1170 dissect_set_axis_attr_list_request (tvbuff_t* tvb, proto_tree* tree, guint32 offset, guint32 size)
1172 proto_item *header_item, *attr_item;
1173 proto_tree *header_tree, *attr_tree;
1174 guint16 attribute, attribute_cnt, data_elements;
1175 guint32 local_offset;
1176 guint32 attribute_size;
1177 guint8 dimension, attribute_start, increment_size;
1179 /* Create the tree for the set axis attribute list request */
1180 header_item = proto_tree_add_text(tree, tvb, offset, size, "Set Axis Attribute List Request");
1181 header_tree = proto_item_add_subtree(header_item, ett_set_axis_attribute);
1183 /* Read the number of attributes that are contained within the request */
1184 attribute_cnt = tvb_get_letohs(tvb, offset);
1185 proto_tree_add_item(header_tree, hf_set_axis_attr_list_attribute_cnt, tvb, offset, 2, ENC_LITTLE_ENDIAN);
1187 /* Start the attribute loop at the beginning of the first attribute in the list */
1188 local_offset = offset + 4;
1190 /* For each attribute display the associated fields */
1191 for (attribute = 0; attribute < attribute_cnt; attribute++)
1193 /* At a minimum the local offset needs to be incremented by 4 bytes to reach the next attribute */
1194 increment_size = 4;
1196 /* Pull the fields for this attribute from the payload, all fields are needed to make some calculations before
1197 * properly displaying of the attribute is possible */
1198 dimension = tvb_get_guint8(tvb, local_offset + 2);
1199 attribute_size = tvb_get_guint8(tvb, local_offset + 3);
1200 attribute_start = 4;
1202 if (dimension == 1)
1204 data_elements = tvb_get_letohs(tvb, local_offset + 6);
1206 /* Modify the size of the attribute data by the number of elements if the request is an array request */
1207 attribute_size *= data_elements;
1209 /* Modify the amount to update the local offset by and the start of the data to include the index and elements field */
1210 increment_size += 4;
1211 attribute_start += 4;
1214 /* Create the tree for this attribute in the get axis attribute list request */
1215 attr_item = proto_tree_add_item(header_tree, hf_set_axis_attr_list_attribute_id, tvb, local_offset, 2, ENC_LITTLE_ENDIAN);
1216 attr_tree = proto_item_add_subtree(attr_item, ett_set_axis_attr_list);
1218 proto_tree_add_item(attr_tree, hf_set_axis_attr_list_dimension, tvb, local_offset + 2, 1, ENC_LITTLE_ENDIAN);
1219 proto_tree_add_item(attr_tree, hf_set_axis_attr_list_element_size, tvb, local_offset + 3, 1, ENC_LITTLE_ENDIAN);
1221 if (dimension == 1)
1223 /* Display the start index and start index from the request if the request is an array */
1224 proto_tree_add_item(attr_tree, hf_set_axis_attr_list_start_index, tvb, local_offset + 4, 2, ENC_LITTLE_ENDIAN);
1225 proto_tree_add_item(attr_tree, hf_set_axis_attr_list_data_elements, tvb, local_offset + 6, 2, ENC_LITTLE_ENDIAN);
1228 /* Display the value of this attribute */
1229 proto_tree_add_item(attr_tree, hf_cip_attribute_data, tvb, local_offset + attribute_start, attribute_size, ENC_NA);
1231 /* Round the attribute size up so the next attribute lines up on a 32-bit boundary */
1232 if (attribute_size % 4 != 0)
1234 attribute_size = attribute_size + (4 - (attribute_size % 4));
1237 /* Move the local offset to the next attribute */
1238 local_offset += (attribute_size + increment_size);
1243 * Function name: dissect_group_sync_request
1245 * Purpose: Dissect the group sync service request
1247 * Returns: None
1249 static void
1250 dissect_group_sync_request (tvbuff_t* tvb, proto_tree* tree, guint32 offset, guint32 size)
1252 proto_item *header_item;
1253 proto_tree *header_tree;
1255 /* Create the tree for the group sync request */
1256 header_item = proto_tree_add_text(tree, tvb, offset, size, "Group Sync Request");
1257 header_tree = proto_item_add_subtree(header_item, ett_group_sync);
1259 /* Read the grandmaster id from the payload */
1260 proto_tree_add_item(header_tree, hf_cip_ptp_grandmaster, tvb, offset, 8, ENC_LITTLE_ENDIAN);
1265 * Function name: dissect_cntr_service
1267 * Purpose: Dissect the service data block in a controller to device message
1269 * Returns: The new offset into the message that follow on dissections should use
1270 * as their starting offset
1272 static guint32
1273 dissect_cntr_service(tvbuff_t* tvb, proto_tree* tree, guint32 offset, guint32 size)
1275 proto_item *header_item;
1276 proto_tree *header_tree;
1277 guint8 service;
1279 /* Create the tree for the entire service data block */
1280 header_item = proto_tree_add_text(tree, tvb, offset, size, "Service Data Block");
1281 header_tree = proto_item_add_subtree(header_item, ett_service);
1283 /* Display the transaction id value */
1284 proto_tree_add_item(header_tree, hf_cip_svc_transction, tvb, offset, 1, ENC_LITTLE_ENDIAN);
1286 /* Display the service code */
1287 service = tvb_get_guint8(tvb, offset + 1);
1288 proto_tree_add_item(header_tree, hf_cip_svc_code, tvb, offset + 1, 1, ENC_LITTLE_ENDIAN);
1290 /* If the service is a set axis, get axis attribute or group sync request dissect it as well */
1291 switch(service)
1293 case SC_GET_AXIS_ATTRIBUTE_LIST:
1294 dissect_get_axis_attr_list_request(tvb, header_tree, offset + 4, size);
1295 break;
1296 case SC_SET_AXIS_ATTRIBUTE_LIST:
1297 dissect_set_axis_attr_list_request(tvb, header_tree, offset + 4, size);
1298 break;
1299 case SC_GROUP_SYNC:
1300 dissect_group_sync_request(tvb, header_tree, offset + 4, size);
1301 break;
1302 default:
1303 /* Display the remainder of the service channel data */
1304 proto_tree_add_item(header_tree, hf_cip_svc_data, tvb, offset + 4, size - 4, ENC_NA);
1307 return offset + size;
1311 * Function name: dissect_set_axis_attr_list_response
1313 * Purpose: Dissect the set axis attribute list service response
1315 * Returns: None
1317 static void
1318 dissect_set_axis_attr_list_response (tvbuff_t* tvb, proto_tree* tree, guint32 offset, guint32 size)
1320 proto_item *header_item, *attr_item;
1321 proto_tree *header_tree, *attr_tree;
1322 guint16 attribute, attribute_cnt;
1323 guint32 local_offset;
1325 /* Create the tree for the set axis attribute list response */
1326 header_item = proto_tree_add_text(tree, tvb, offset, size, "Set Axis Attribute List Response");
1327 header_tree = proto_item_add_subtree(header_item, ett_get_axis_attribute);
1329 /* Read the number of attributes that are contained within the response */
1330 attribute_cnt = tvb_get_letohs(tvb, offset);
1331 proto_tree_add_item(header_tree, hf_set_axis_attr_list_attribute_cnt, tvb, offset, 2, ENC_LITTLE_ENDIAN);
1333 /* Start the attribute loop at the beginning of the first attribute in the list */
1334 local_offset = offset + 4;
1336 /* For each attribute display the associated fields */
1337 for (attribute = 0; attribute < attribute_cnt; attribute++)
1339 /* Create the tree for the current attribute in the set axis attribute list response */
1340 attr_item = proto_tree_add_item(header_tree, hf_set_axis_attr_list_attribute_id, tvb, local_offset, 2, ENC_LITTLE_ENDIAN);
1341 attr_tree = proto_item_add_subtree(attr_item, ett_get_axis_attr_list);
1343 /* Add the response status to the tree */
1344 proto_tree_add_item(attr_tree, hf_cip_svc_set_axis_attr_sts, tvb, local_offset + 2, 1, ENC_LITTLE_ENDIAN);
1346 /* Move the local offset to the next attribute */
1347 local_offset += 4;
1352 * Function name: dissect_get_axis_attr_list_response
1354 * Purpose: Dissect the get axis attribute list service response
1356 * Returns: None
1358 static void
1359 dissect_get_axis_attr_list_response (tvbuff_t* tvb, proto_tree* tree, guint32 offset, guint32 size)
1361 proto_item *header_item, *attr_item;
1362 proto_tree *header_tree, *attr_tree;
1363 guint16 attribute, attribute_cnt, data_elements;
1364 guint32 attribute_size;
1365 guint8 dimension, attribute_start, increment_size;
1366 guint32 local_offset;
1368 /* Create the tree for the get axis attribute list response */
1369 header_item = proto_tree_add_text(tree, tvb, offset, size, "Get Axis Attribute List Response");
1370 header_tree = proto_item_add_subtree(header_item, ett_get_axis_attribute);
1372 /* Read the number of attributes that are contained within the request */
1373 attribute_cnt = tvb_get_letohs(tvb, offset);
1374 proto_tree_add_item(header_tree, hf_get_axis_attr_list_attribute_cnt, tvb, offset, 2, ENC_LITTLE_ENDIAN);
1376 /* Start the attribute loop at the beginning of the first attribute in the list */
1377 local_offset = offset + 4;
1379 /* For each attribute display the associated fields */
1380 for (attribute = 0; attribute < attribute_cnt; attribute++)
1382 /* At a minimum the local offset needs to be incremented by 4 bytes to reach the next attribute */
1383 increment_size = 4;
1385 /* Pull the fields for this attribute from the payload, all fields are need to make some calculations before
1386 * properly displaying of the attribute is possible */
1387 dimension = tvb_get_guint8(tvb, local_offset + 2);
1388 attribute_size = tvb_get_guint8(tvb, local_offset + 3);
1389 attribute_start = 4;
1391 if (dimension == 1)
1393 data_elements = tvb_get_letohs(tvb, local_offset + 6);
1395 /* Modify the size of the attribute data by the number of elements if the request is an array request */
1396 attribute_size *= data_elements;
1398 /* Modify the amount to update the local offset by and the start of the data to include the index and elements field */
1399 increment_size += 4;
1400 attribute_start += 4;
1403 /* Display the fields associated with the get axis attribute list response */
1404 attr_item = proto_tree_add_item(header_tree, hf_get_axis_attr_list_attribute_id, tvb, local_offset, 2, ENC_LITTLE_ENDIAN);
1405 attr_tree = proto_item_add_subtree(attr_item, ett_get_axis_attr_list);
1407 if (dimension == 0xFF)
1409 /* Display the element size as an error code if the dimension field indicates an error */
1410 proto_tree_add_item(attr_tree, hf_cip_svc_get_axis_attr_sts, tvb, local_offset + 3, 1, ENC_LITTLE_ENDIAN);
1412 /* No attribute data so no attribute size */
1413 attribute_size = 0;
1415 else
1417 proto_tree_add_item(attr_tree, hf_get_axis_attr_list_dimension, tvb, local_offset + 2, 1, ENC_LITTLE_ENDIAN);
1418 proto_tree_add_item(attr_tree, hf_get_axis_attr_list_element_size, tvb, local_offset + 3, 1, ENC_LITTLE_ENDIAN);
1420 if (dimension == 1)
1422 /* Display the start index and start indexfrom the request */
1423 proto_tree_add_item(attr_tree, hf_get_axis_attr_list_start_index, tvb, local_offset + 4, 2, ENC_LITTLE_ENDIAN);
1424 proto_tree_add_item(attr_tree, hf_get_axis_attr_list_data_elements, tvb, local_offset + 6, 2, ENC_LITTLE_ENDIAN);
1427 /* Display the remainder of the service channel data */
1428 proto_tree_add_item(attr_tree, hf_cip_attribute_data, tvb, offset + attribute_start, attribute_size, ENC_NA);
1430 /* Round the attribute size up so the next attribute lines up on a 32-bit boundary */
1431 if (attribute_size % 4 != 0)
1433 attribute_size = attribute_size + (4 - (attribute_size % 4));
1437 /* Move the local offset to the next attribute */
1438 local_offset += (attribute_size + increment_size);
1443 * Function name: dissect_group_sync_response
1445 * Purpose: Dissect the group sync service response
1447 * Returns: None
1449 static void
1450 dissect_group_sync_response (tvbuff_t* tvb, proto_tree* tree, guint32 offset, guint32 size _U_)
1452 proto_tree_add_item(tree, hf_cip_group_sync, tvb, offset, 1, ENC_LITTLE_ENDIAN);
1456 * Function name: dissect_devce_service
1458 * Purpose: Dissect the service data block in a device to controller message
1460 * Returns: The new offset into the message that follow on dissections should use
1461 * as their starting offset
1463 static guint32
1464 dissect_devce_service(tvbuff_t* tvb, proto_tree* tree, guint32 offset, guint32 size)
1466 proto_item *header_item;
1467 proto_tree *header_tree;
1469 /* Create the tree for the entire service data block */
1470 header_item = proto_tree_add_text(tree, tvb, offset, size, "Service Data Block");
1471 header_tree = proto_item_add_subtree(header_item, ett_service);
1473 /* Display the transaction id value */
1474 proto_tree_add_item(header_tree, hf_cip_svc_transction, tvb, offset, 1, ENC_LITTLE_ENDIAN);
1476 /* Display the service code */
1477 proto_tree_add_item(header_tree, hf_cip_svc_code, tvb, offset + 1, 1, ENC_LITTLE_ENDIAN);
1479 /* Display the general status code */
1480 proto_tree_add_item(header_tree, hf_cip_svc_sts, tvb, offset + 2, 1, ENC_LITTLE_ENDIAN);
1482 /* Display the extended status code */
1483 proto_tree_add_item(header_tree, hf_cip_svc_ext_status, tvb, offset + 3, 1, ENC_LITTLE_ENDIAN);
1485 /* If the service is a set axis, get axis attribute response or group sync dissect it as well */
1486 switch(tvb_get_guint8(tvb, offset + 1))
1488 case SC_GET_AXIS_ATTRIBUTE_LIST:
1489 dissect_get_axis_attr_list_response(tvb, header_tree, offset + 4, size);
1490 break;
1491 case SC_SET_AXIS_ATTRIBUTE_LIST:
1492 dissect_set_axis_attr_list_response(tvb, header_tree, offset + 4, size);
1493 break;
1494 case SC_GROUP_SYNC:
1495 dissect_group_sync_response(tvb, header_tree, offset + 4, size);
1496 break;
1497 default:
1498 /* Display the remainder of the service channel data */
1499 proto_tree_add_item(header_tree, hf_cip_svc_data, tvb, offset + 4, size - 4, ENC_NA);
1502 return offset + size;
1506 * Function name: dissect_var_inst_header
1508 * Purpose: Dissect the instance data header of a variable controller to device or
1509 * device to controller message
1511 * Returns: void
1513 static void
1514 dissect_var_inst_header(tvbuff_t* tvb, proto_tree* tree, guint32 offset, guint8* inst_number, guint32* cyc_size,
1515 guint32* cyc_blk_size, guint32* evnt_size, guint32* servc_size)
1517 guint8 temp_data;
1518 proto_item *header_item;
1519 proto_tree *header_tree;
1521 /* Create the tree for the entire instance data header */
1522 *inst_number = tvb_get_guint8(tvb, offset);
1524 header_item = proto_tree_add_text(tree, tvb, offset, 8, "Instance Data Header - Instance: %d", *inst_number);
1525 header_tree = proto_item_add_subtree(header_item, ett_inst_data_header);
1527 /* Read the instance number field from the instance data header */
1528 proto_tree_add_item(header_tree, hf_var_devce_instance, tvb, offset, 1, ENC_LITTLE_ENDIAN);
1530 /* The "size" fields in the instance data block header are all stored as number of 32-bit words the
1531 * block uses since all blocks should pad up to 32-bits so to convert to bytes each is mulitplied by 4 */
1533 /* Read the instance block size field in bytes from the instance data header */
1534 temp_data = tvb_get_guint8(tvb, offset + 2);
1535 proto_tree_add_uint_format_value(header_tree, hf_var_devce_instance_block_size,
1536 tvb, offset + 2, 1, temp_data, "%d words", temp_data);
1538 /* Read the cyclic block size field in bytes from the instance data header */
1539 temp_data = tvb_get_guint8(tvb, offset + 3);
1540 proto_tree_add_uint_format_value(header_tree, hf_var_devce_cyclic_block_size,
1541 tvb, offset + 3, 1, temp_data, "%d words", temp_data);
1543 /* Read the cyclic command block size field in bytes from the instance data header */
1544 *cyc_size = (tvb_get_guint8(tvb, offset + 4) * 4);
1545 proto_tree_add_uint_format_value(header_tree, hf_var_devce_cyclic_data_block_size,
1546 tvb, offset + 4, 1, (*cyc_size)/4, "%d words", (*cyc_size)/4);
1548 /* Read the cyclic write block size field in bytes from the instance data header */
1549 *cyc_blk_size = (tvb_get_guint8(tvb, offset + 5) * 4);
1550 proto_tree_add_uint_format_value(header_tree, hf_var_devce_cyclic_rw_block_size,
1551 tvb, offset + 5, 1, (*cyc_blk_size)/4, "%d words", (*cyc_blk_size)/4);
1553 /* Read the event block size in bytes from the instance data header */
1554 *evnt_size = (tvb_get_guint8(tvb, offset + 6) * 4);
1555 proto_tree_add_uint_format_value(header_tree, hf_var_devce_event_block_size,
1556 tvb, offset + 6, 1, (*evnt_size)/4, "%d words", (*evnt_size)/4);
1558 /* Read the service block size in bytes from the instance data header */
1559 *servc_size = (tvb_get_guint8(tvb, offset + 7) * 4);
1560 proto_tree_add_uint_format_value(header_tree, hf_var_devce_service_block_size,
1561 tvb, offset + 7, 1, (*servc_size)/4, "%d words", (*servc_size)/4);
1565 * Function name: dissect_var_cont_conn_header
1567 * Purpose: Dissect the connection header of a variable controller to device message
1569 * Returns: Offset to the start of the instance data block
1571 static guint32
1572 dissect_var_cont_conn_header(tvbuff_t* tvb, proto_tree* tree, guint32* inst_count, guint32 offset)
1574 guint32 header_size;
1575 guint32 temp_data;
1576 proto_item *header_item, *temp_proto_item;
1577 proto_tree *header_tree, *temp_proto_tree;
1579 /* Calculate the header size, start with the basic header size */
1580 header_size = 8;
1582 temp_data = tvb_get_guint8(tvb, offset + 7);
1584 /* Check the time data set field for enabled bits. If either update period or
1585 * update time stamp fields are set, bump the header size by the appropriate size */
1586 if ( (temp_data & TIME_DATA_SET_TIME_STAMP) == TIME_DATA_SET_TIME_STAMP )
1588 header_size += 8;
1590 if ( (temp_data & TIME_DATA_SET_TIME_OFFSET) == TIME_DATA_SET_TIME_OFFSET )
1592 header_size += 8;
1595 /* Create the tree for the entire connection header */
1596 header_item = proto_tree_add_text(tree, tvb, offset, header_size, "Connection Header");
1597 header_tree = proto_item_add_subtree(header_item, ett_cont_dev_header);
1599 /* Add the connection header fields that are common to all types of messages */
1600 proto_tree_add_item(header_tree, hf_cip_format, tvb, offset, 1, ENC_LITTLE_ENDIAN);
1601 proto_tree_add_item(header_tree, hf_cip_revision, tvb, offset + 1, 1, ENC_LITTLE_ENDIAN);
1602 proto_tree_add_item(header_tree, hf_cip_updateid, tvb, offset + 2, 1, ENC_LITTLE_ENDIAN);
1604 /* Create the tree for the node control header field */
1605 temp_proto_item = proto_tree_add_item(header_tree, hf_cip_node_control, tvb, offset + 3, 1, ENC_LITTLE_ENDIAN);
1606 temp_proto_tree = proto_item_add_subtree(temp_proto_item, ett_node_control);
1608 /* Add the individual data elements to the node control tree */
1609 proto_tree_add_item(temp_proto_tree, hf_cip_node_control_remote, tvb, offset + 3, 1, ENC_LITTLE_ENDIAN);
1610 proto_tree_add_item(temp_proto_tree, hf_cip_node_control_sync, tvb, offset + 3, 1, ENC_LITTLE_ENDIAN);
1611 proto_tree_add_item(temp_proto_tree, hf_cip_node_data_valid, tvb, offset + 3, 1, ENC_LITTLE_ENDIAN);
1612 proto_tree_add_item(temp_proto_tree, hf_cip_node_fault_reset, tvb, offset + 3, 1, ENC_LITTLE_ENDIAN);
1614 /* Read the instance count field from the packet into memory, this gets passed back out of the method */
1615 *inst_count = tvb_get_guint8(tvb, offset + 4);
1617 /* Add the instance count and last update id to the connection header tree */
1618 proto_tree_add_item(header_tree, hf_cip_instance_cnt, tvb, offset + 4, 1, ENC_LITTLE_ENDIAN);
1619 proto_tree_add_item(header_tree, hf_cip_last_update, tvb, offset + 6, 1, ENC_LITTLE_ENDIAN);
1621 /* Read the time data set from the packet into memory */
1622 temp_data = tvb_get_guint8(tvb, offset + 7);
1624 /* Create the tree for the time data set field */
1625 temp_proto_item = proto_tree_add_item(header_tree, hf_cip_time_data_set, tvb, offset + 7, 1, ENC_LITTLE_ENDIAN);
1626 temp_proto_tree = proto_item_add_subtree(temp_proto_item, ett_time_data_set);
1628 /* Add the individual data elements to the time data set header field */
1629 proto_tree_add_item(temp_proto_tree, hf_cip_time_data_stamp, tvb, offset + 7, 1, ENC_LITTLE_ENDIAN);
1630 proto_tree_add_item(temp_proto_tree, hf_cip_time_data_offset, tvb, offset + 7, 1, ENC_LITTLE_ENDIAN);
1631 proto_tree_add_item(temp_proto_tree, hf_cip_time_data_diag, tvb, offset + 7, 1, ENC_LITTLE_ENDIAN);
1632 proto_tree_add_item(temp_proto_tree, hf_cip_time_data_time_diag, tvb, offset + 7, 1, ENC_LITTLE_ENDIAN);
1634 /* Move the offset to the byte just beyond the time data set field */
1635 offset = (offset + 7 + 1);
1637 /* Add the time values if they are present in the time data set header field */
1638 if ( (temp_data & TIME_DATA_SET_TIME_STAMP) == TIME_DATA_SET_TIME_STAMP )
1640 proto_tree_add_item(header_tree, hf_cip_cont_time_stamp, tvb, offset, 8, ENC_LITTLE_ENDIAN);
1641 offset = (offset + 8);
1644 if ( (temp_data & TIME_DATA_SET_TIME_OFFSET) == TIME_DATA_SET_TIME_OFFSET )
1646 proto_tree_add_item(header_tree, hf_cip_cont_time_offset, tvb, offset, 8, ENC_LITTLE_ENDIAN);
1647 offset = (offset + 8);
1650 /* Return the number of bytes used so it can be used as an offset in the following dissections */
1651 return offset;
1655 * Function name: dissect_var_devce_conn_header
1657 * Purpose: Dissect the connection header of a variable device to controller message
1659 * Returns: Offset to the start of the instance data block
1661 static guint32
1662 dissect_var_devce_conn_header(tvbuff_t* tvb, proto_tree* tree, guint32* inst_count, guint32 offset)
1664 guint32 header_size;
1665 guint32 temp_data;
1666 proto_item *header_item, *temp_proto_item;
1667 proto_tree *header_tree, *temp_proto_tree;
1669 /* Calculate the header size, start with the basic header size */
1670 header_size = 8;
1672 temp_data = tvb_get_guint8(tvb, offset + 7);
1673 if ( (temp_data & TIME_DATA_SET_TIME_STAMP) == TIME_DATA_SET_TIME_STAMP )
1675 header_size += 8;
1677 if ( (temp_data & TIME_DATA_SET_TIME_OFFSET) == TIME_DATA_SET_TIME_OFFSET )
1679 header_size += 8;
1681 if ( (temp_data & TIME_DATA_SET_UPDATE_DIAGNOSTICS) == TIME_DATA_SET_UPDATE_DIAGNOSTICS )
1683 header_size += 4;
1685 if ( (temp_data & TIME_DATA_SET_TIME_DIAGNOSTICS) == TIME_DATA_SET_TIME_DIAGNOSTICS )
1687 header_size += 16;
1690 /* Create the tree for the entire connection header */
1691 header_item = proto_tree_add_text(tree, tvb, offset, header_size, "Connection Header");
1692 header_tree = proto_item_add_subtree(header_item, ett_cont_dev_header);
1694 /* Add the connection header fields that are common to all types of messages */
1695 proto_tree_add_item(header_tree, hf_cip_format, tvb, offset, 1, ENC_LITTLE_ENDIAN);
1696 proto_tree_add_item(header_tree, hf_cip_revision, tvb, offset + 1, 1, ENC_LITTLE_ENDIAN);
1697 proto_tree_add_item(header_tree, hf_cip_updateid, tvb, offset + 2, 1, ENC_LITTLE_ENDIAN);
1699 /* Create the tree for the node status header field */
1700 temp_proto_item = proto_tree_add_item(header_tree, hf_cip_node_status, tvb, offset + 3, 1, ENC_LITTLE_ENDIAN);
1701 temp_proto_tree = proto_item_add_subtree(temp_proto_item, ett_node_status);
1703 /* Add the individual data elements to the node control tree */
1704 proto_tree_add_item(temp_proto_tree, hf_cip_node_control_remote, tvb, offset + 3, 1, ENC_LITTLE_ENDIAN);
1705 proto_tree_add_item(temp_proto_tree, hf_cip_node_control_sync, tvb, offset + 3, 1, ENC_LITTLE_ENDIAN);
1706 proto_tree_add_item(temp_proto_tree, hf_cip_node_data_valid, tvb, offset + 3, 1, ENC_LITTLE_ENDIAN);
1707 proto_tree_add_item(temp_proto_tree, hf_cip_node_device_faulted, tvb, offset + 3, 1, ENC_LITTLE_ENDIAN);
1709 /* Read the instance count field from the packet into memory, this gets passed back out of the method */
1710 *inst_count = tvb_get_guint8(tvb, offset + 4);
1712 /* Add the instance count to the connection header tree */
1713 proto_tree_add_item(header_tree, hf_cip_instance_cnt, tvb, offset + 4, 1, ENC_LITTLE_ENDIAN);
1715 /* The device to controller header contains the node alarms and node faults fields as well. */
1716 proto_tree_add_item(header_tree, hf_cip_node_fltalarms, tvb, offset + 5, 1, ENC_LITTLE_ENDIAN);
1718 /* Add the last update id to the connection header tree */
1719 proto_tree_add_item(header_tree, hf_cip_last_update, tvb, offset + 6, 1, ENC_LITTLE_ENDIAN);
1721 /* Read the time data set from the packet into memory */
1722 temp_data = tvb_get_guint8(tvb, offset + 7);
1724 /* Create the tree for the time data set field */
1725 temp_proto_item = proto_tree_add_item(header_tree, hf_cip_time_data_set, tvb, offset + 7, 1, ENC_LITTLE_ENDIAN);
1726 temp_proto_tree = proto_item_add_subtree(temp_proto_item, ett_time_data_set);
1728 /* Add the individual data elements to the time data set header field */
1729 proto_tree_add_item(temp_proto_tree, hf_cip_time_data_stamp, tvb, offset + 7, 1, ENC_LITTLE_ENDIAN);
1730 proto_tree_add_item(temp_proto_tree, hf_cip_time_data_offset, tvb, offset + 7, 1, ENC_LITTLE_ENDIAN);
1731 proto_tree_add_item(temp_proto_tree, hf_cip_time_data_diag, tvb, offset + 7, 1, ENC_LITTLE_ENDIAN);
1732 proto_tree_add_item(temp_proto_tree, hf_cip_time_data_time_diag, tvb, offset + 7, 1, ENC_LITTLE_ENDIAN);
1734 /* Move the offset to the byte just beyond the time data set field */
1735 offset = (offset + 7 + 1);
1737 /* Add the time values if they are present in the time data set header field */
1738 if ( (temp_data & TIME_DATA_SET_TIME_STAMP) == TIME_DATA_SET_TIME_STAMP )
1740 proto_tree_add_item(header_tree, hf_cip_devc_time_stamp, tvb, offset, 8, ENC_LITTLE_ENDIAN);
1741 offset = (offset + 8);
1744 if ( (temp_data & TIME_DATA_SET_TIME_OFFSET) == TIME_DATA_SET_TIME_OFFSET )
1746 proto_tree_add_item(header_tree, hf_cip_devc_time_offset, tvb, offset, 8, ENC_LITTLE_ENDIAN);
1747 offset = (offset + 8);
1750 if ( (temp_data & TIME_DATA_SET_UPDATE_DIAGNOSTICS) == TIME_DATA_SET_UPDATE_DIAGNOSTICS )
1752 /* If the time diagnostic bit is set then the header contains the count of lost updates, late updates, data
1753 * received time stamp and data transmit time stamp */
1754 proto_tree_add_item(header_tree, hf_cip_lost_update, tvb, offset, 1, ENC_LITTLE_ENDIAN);
1755 offset = (offset + 1);
1757 /* Add the reserved bytes to the offset after adding the late updates to the display */
1758 proto_tree_add_item(header_tree, hf_cip_late_update, tvb, offset, 1, ENC_LITTLE_ENDIAN);
1759 offset = (offset + 3);
1762 if ( (temp_data & TIME_DATA_SET_TIME_DIAGNOSTICS) == TIME_DATA_SET_TIME_DIAGNOSTICS )
1764 proto_tree_add_item(header_tree, hf_cip_data_rx_time_stamp, tvb, offset, 8, ENC_LITTLE_ENDIAN);
1765 offset += 8;
1767 proto_tree_add_item(header_tree, hf_cip_data_tx_time_stamp, tvb, offset, 8, ENC_LITTLE_ENDIAN);
1768 offset += 8;
1771 /* Return the number of bytes used so it can be used as an offset in the following dissections */
1772 return offset;
1777 * Function name: dissect_cipmotion
1779 * Purpose: Perform the top level dissection of the CIP Motion datagram, it is called by
1780 * Wireshark when the dissection rule registered in proto_reg_handoff_cipmotion is fired
1782 * Returns: void
1784 static void
1785 dissect_cipmotion(tvbuff_t* tvb, packet_info* pinfo, proto_tree* tree)
1787 guint32 con_format;
1788 /* guint32 seq_number; */
1789 guint32 update_id;
1790 proto_item *proto_item_top;
1791 proto_tree *proto_tree_top;
1792 guint32 offset = 0;
1794 /* Pull the CIP class 1 sequence number from the incoming message */
1795 /* seq_number = tvb_get_letohs(tvb, offset); */
1796 offset = (offset + 2);
1798 /* Pull the actual values for the connection format and update id from the
1799 * incoming message to be used in the column info */
1800 con_format = tvb_get_guint8(tvb, offset);
1801 update_id = tvb_get_guint8(tvb, offset + 2);
1803 /* Make entries in Protocol column and Info column on summary display */
1804 col_set_str(pinfo->cinfo, COL_PROTOCOL, "Motion");
1806 /* Add connection format and update number to the info column */
1807 col_add_fstr( pinfo->cinfo, COL_INFO, "%s, Update Id: %d",
1808 val_to_str(con_format, cip_con_format_vals, "Unknown connection format (%x)"), update_id );
1810 /* If tree is not NULL then Wireshark is requesting that the dissection
1811 * panel be updated with the dissected packet, if tree is NULL then only
1812 * the summary protocol and info columns need to be updated */
1813 if ( tree )
1815 /* Create display subtree for the protocol by creating an item and then
1816 * creating a subtree from the item, the subtree must have been registered
1817 * in proto_register_cipmotion already */
1818 proto_item_top = proto_tree_add_item( tree, proto_cipmotion, tvb, 0, -1, ENC_NA );
1819 proto_tree_top = proto_item_add_subtree( proto_item_top, ett_cipmotion );
1821 /* Add the CIP class 1 sequence number to the tree */
1822 proto_tree_add_item( proto_tree_top, hf_cip_class1_seqnum, tvb, 0, 2, ENC_LITTLE_ENDIAN );
1824 /* Attempt to classify the incoming header */
1825 if (( con_format == FORMAT_VAR_CONTROL_TO_DEVICE ) ||
1826 ( con_format == FORMAT_VAR_DEVICE_TO_CONTROL ))
1828 /* Sizes of the individual channels within the connection */
1829 guint32 cyc_size, cyc_blk_size, evnt_size, servc_size;
1830 guint32 inst_count = 0, inst;
1832 /* Dissect the header fields */
1833 switch(con_format)
1835 case FORMAT_VAR_CONTROL_TO_DEVICE:
1836 offset = dissect_var_cont_conn_header(tvb, proto_tree_top, &inst_count, offset);
1837 break;
1838 case FORMAT_VAR_DEVICE_TO_CONTROL:
1839 offset = dissect_var_devce_conn_header(tvb, proto_tree_top, &inst_count, offset);
1840 break;
1843 /* Repeat the following dissections for each instance within the payload */
1844 for( inst = 0; inst < inst_count; inst++ )
1846 /* Actual instance number from header field */
1847 guint8 instance;
1849 /* Dissect the instance data header */
1850 dissect_var_inst_header( tvb, proto_tree_top, offset, &instance,
1851 &cyc_size, &cyc_blk_size, &evnt_size, &servc_size );
1853 /* Increment the offset to just beyond the instance header */
1854 offset += 8;
1856 /* Dissect the cyclic command (actual) data if any exists */
1857 /* Dissect the cyclic write (read) data if any exists */
1858 /* Dissect the event data block if there is any event data */
1859 switch(con_format)
1861 case FORMAT_VAR_CONTROL_TO_DEVICE:
1862 if ( cyc_size > 0 )
1863 offset = dissect_cntr_cyclic( con_format, tvb, proto_tree_top, offset, cyc_size, instance );
1864 if ( cyc_blk_size > 0 )
1865 offset = dissect_cyclic_wt(tvb, proto_tree_top, offset, cyc_blk_size);
1866 if ( evnt_size > 0 )
1867 offset = dissect_cntr_event(tvb, proto_tree_top, offset, evnt_size);
1868 if ( servc_size > 0 )
1869 offset = dissect_cntr_service(tvb, proto_tree_top, offset, servc_size);
1870 break;
1871 case FORMAT_VAR_DEVICE_TO_CONTROL:
1872 if ( cyc_size > 0 )
1873 offset = dissect_devce_cyclic( con_format, tvb, proto_tree_top, offset, cyc_size, instance );
1874 if ( cyc_blk_size > 0 )
1875 offset = dissect_cyclic_rd( tvb, proto_tree_top, offset, cyc_blk_size );
1876 if ( evnt_size > 0 )
1877 offset = dissect_devce_event(tvb, proto_tree_top, offset, evnt_size);
1878 if ( servc_size > 0 )
1879 offset = dissect_devce_service(tvb, proto_tree_top, offset, servc_size);
1880 break;
1883 } /* End of instance for( ) loop */
1889 * Function name: proto_register_cipmotion
1891 * Purpose: Register the protocol with Wireshark, a script will add this protocol
1892 * to the list of protocols during the build process. This function is where the
1893 * header fields and subtree identifiers are registered.
1895 * Returns: void
1897 void
1898 proto_register_cipmotion(void)
1900 /* This is a list of header fields that can be used in the dissection or
1901 * to use in a filter expression */
1902 static hf_register_info hf[] =
1904 /* Connection format header field, the first byte in the message which
1905 * determines if the message is fixed or variable, controller to device,
1906 * device to controller, etc. */
1907 { &hf_cip_format,
1908 { "Connection Format", "cipm.format",
1909 FT_UINT8, BASE_DEC, VALS(cip_con_format_vals), 0,
1910 "Message connection format", HFILL }
1913 /* Connection format revision header field */
1914 { &hf_cip_revision,
1915 { "Format Revision", "cipm.revision",
1916 FT_UINT8, BASE_DEC, NULL, 0,
1917 "Message format revision", HFILL }
1920 { &hf_cip_class1_seqnum,
1921 { "CIP Class 1 Sequence Number", "cipm.class1seqnum",
1922 FT_UINT16, BASE_DEC, NULL, 0,
1923 NULL, HFILL }
1925 { &hf_cip_updateid,
1926 { "Update Id", "cipm.updateid",
1927 FT_UINT8, BASE_DEC, NULL, 0,
1928 "Cyclic Transaction Number", HFILL }
1930 { &hf_cip_instance_cnt,
1931 { "Instance Count", "cipm.instancecount",
1932 FT_UINT8, BASE_DEC, NULL, 0,
1933 NULL, HFILL }
1935 { &hf_cip_last_update,
1936 { "Last Update Id", "cipm.lastupdate",
1937 FT_UINT8, BASE_DEC, NULL, 0,
1938 NULL, HFILL }
1940 { &hf_cip_node_status,
1941 { "Node Status", "cipm.nodestatus",
1942 FT_UINT8, BASE_HEX, NULL, 0,
1943 NULL, HFILL}
1945 { &hf_cip_node_control,
1946 { "Node Control", "cipm.nodecontrol",
1947 FT_UINT8, BASE_HEX, NULL, 0,
1948 NULL, HFILL}
1950 { &hf_cip_node_control_remote,
1951 { "Remote Control", "cipm.remote",
1952 FT_BOOLEAN, 8, TFS(&tfs_true_false), 0x01,
1953 "Node Control: Remote Control", HFILL}
1955 { &hf_cip_node_control_sync,
1956 { "Sync Control", "cipm.sync",
1957 FT_BOOLEAN, 8, TFS(&tfs_true_false), 0x02,
1958 "Node Control: Synchronous Operation", HFILL}
1960 { &hf_cip_node_data_valid,
1961 { "Data Valid", "cipm.valid",
1962 FT_BOOLEAN, 8, TFS(&tfs_true_false), 0x04,
1963 "Node Control: Data Valid", HFILL}
1965 { &hf_cip_node_fault_reset,
1966 { "Fault Reset", "cipm.fltrst",
1967 FT_BOOLEAN, 8, TFS(&tfs_true_false), 0x08,
1968 "Node Control: Device Fault Reset", HFILL}
1970 { &hf_cip_node_device_faulted,
1971 { "Faulted", "cipm.flt",
1972 FT_BOOLEAN, 8, TFS(&tfs_true_false), 0x08,
1973 "Node Control: Device Faulted", HFILL}
1975 { &hf_cip_node_fltalarms,
1976 { "Node Faults and Alarms", "cipm.fltalarms",
1977 FT_UINT8, BASE_DEC, NULL, 0,
1978 NULL, HFILL }
1980 { &hf_cip_time_data_set,
1981 { "Time Data Set", "cipm.timedataset",
1982 FT_UINT8, BASE_HEX, NULL, 0,
1983 NULL, HFILL}
1985 { &hf_cip_time_data_stamp,
1986 { "Time Stamp", "cipm.time.stamp",
1987 FT_BOOLEAN, 8, TFS(&tfs_true_false), TIME_DATA_SET_TIME_STAMP,
1988 "Time Data Set: Time Stamp", HFILL}
1990 { &hf_cip_time_data_offset,
1991 { "Time Offset", "cipm.time.offset",
1992 FT_BOOLEAN, 8, TFS(&tfs_true_false), TIME_DATA_SET_TIME_OFFSET,
1993 "Time Data Set: Time Offset", HFILL}
1995 { &hf_cip_time_data_diag,
1996 { "Time Update Diagnostics", "cipm.time.update",
1997 FT_BOOLEAN, 8, TFS(&tfs_true_false), TIME_DATA_SET_UPDATE_DIAGNOSTICS,
1998 "Time Data Set: Time Update Diagnostics", HFILL}
2000 { &hf_cip_time_data_time_diag,
2001 { "Time Diagnostics", "cipm.time.diag",
2002 FT_BOOLEAN, 8, TFS(&tfs_true_false), TIME_DATA_SET_TIME_DIAGNOSTICS,
2003 "Time Data Set: Time Diagnostics", HFILL}
2006 { &hf_cip_cont_time_stamp,
2007 { "Controller Time Stamp", "cipm.ctrltimestamp",
2008 FT_UINT64, BASE_DEC, NULL, 0,
2009 "Time Data Set: Controller Time Stamp", HFILL}
2011 { &hf_cip_cont_time_offset,
2012 { "Controller Time Offset", "cipm.ctrltimeoffser",
2013 FT_UINT64, BASE_DEC, NULL, 0,
2014 "Time Data Set: Controller Time Offset", HFILL}
2016 { &hf_cip_data_rx_time_stamp,
2017 { "Data Received Time Stamp", "cipm.rxtimestamp",
2018 FT_UINT64, BASE_DEC, NULL, 0,
2019 "Time Data Set: Data Received Time Stamp", HFILL}
2021 { &hf_cip_data_tx_time_stamp,
2022 { "Data Transmit Time Stamp", "cipm.txtimestamp",
2023 FT_UINT64, BASE_DEC, NULL, 0,
2024 "Time Data Set: Data Transmit Time Offset", HFILL}
2026 { &hf_cip_devc_time_stamp,
2027 { "Device Time Stamp", "cipm.devctimestamp",
2028 FT_UINT64, BASE_DEC, NULL, 0,
2029 "Time Data Set: Device Time Stamp", HFILL}
2031 { &hf_cip_devc_time_offset,
2032 { "Device Time Offset", "cipm.devctimeoffser",
2033 FT_UINT64, BASE_DEC, NULL, 0,
2034 "Time Data Set: Device Time Offset", HFILL}
2036 { &hf_cip_lost_update,
2037 { "Lost Updates", "cipm.lostupdates",
2038 FT_UINT8, BASE_DEC, NULL, 0,
2039 "Time Data Set: Lost Updates", HFILL}
2041 { &hf_cip_late_update,
2042 { "Lost Updates", "cipm.lateupdates",
2043 FT_UINT8, BASE_DEC, NULL, 0,
2044 "Time Data Set: Late Updates", HFILL}
2047 { &hf_cip_motor_cntrl,
2048 { "Control Mode", "cipm.ctrlmode",
2049 FT_UINT8, BASE_DEC, VALS(cip_motor_control_vals), 0,
2050 "Cyclic Data Block: Motor Control Mode", HFILL }
2052 { &hf_cip_fdbk_config,
2053 { "Feedback Config", "cipm.fdbkcfg",
2054 FT_UINT8, BASE_DEC, VALS(cip_fdbk_config_vals), 0,
2055 "Cyclic Data Block: Feedback Configuration", HFILL }
2057 { &hf_cip_axis_control,
2058 { "Axis Control", "cipm.axisctrl",
2059 FT_UINT8, BASE_DEC, VALS(cip_axis_control_vals), 0,
2060 "Cyclic Data Block: Axis Control", HFILL }
2062 { &hf_cip_control_status,
2063 { "Control Status", "cipm.csts",
2064 FT_UINT8, BASE_DEC, VALS(cip_control_status_vals), 0,
2065 "Cyclic Data Block: Axis Control Status", HFILL }
2067 { &hf_cip_axis_response,
2068 { "Axis Response", "cipm.axisresp",
2069 FT_UINT8, BASE_DEC, VALS(cip_axis_response_vals), 0,
2070 "Cyclic Data Block: Axis Response", HFILL }
2072 { &hf_cip_axis_resp_stat,
2073 { "Response Status", "cipm.respstat",
2074 FT_UINT8, BASE_DEC|BASE_EXT_STRING, &cip_gs_vals_ext, 0,
2075 "Cyclic Data Block: Axis Response Status", HFILL }
2077 { &hf_cip_group_sync,
2078 { "Group Sync Status", "cipm.syncstatus",
2079 FT_UINT8, BASE_HEX, VALS(cip_sync_status_vals), 0,
2080 NULL, HFILL }
2082 { &hf_cip_cmd_data_set,
2083 { "Command Data Set", "cipm.cmdset",
2084 FT_UINT8, BASE_HEX, NULL, 0,
2085 NULL, HFILL}
2087 { &hf_cip_act_data_set,
2088 { "Actual Data Set", "cipm.actset",
2089 FT_UINT8, BASE_HEX, NULL, 0,
2090 NULL, HFILL}
2092 { &hf_cip_sts_data_set,
2093 { "Status Data Set", "cipm.stsset",
2094 FT_UINT8, BASE_HEX, NULL, 0,
2095 NULL, HFILL}
2097 { &hf_cip_cmd_data_pos_cmd,
2098 { "Command Position", "cipm.cmd.pos",
2099 FT_BOOLEAN, 8, TFS(&tfs_true_false), COMMAND_DATA_SET_POSITION,
2100 "Command Data Set: Command Position", HFILL}
2102 { &hf_cip_cmd_data_vel_cmd,
2103 { "Command Velocity", "cipm.cmd.vel",
2104 FT_BOOLEAN, 8, TFS(&tfs_true_false), COMMAND_DATA_SET_VELOCITY,
2105 "Command Data Set: Command Velocity", HFILL}
2107 { &hf_cip_cmd_data_acc_cmd,
2108 { "Command Acceleration", "cipm.cmd.acc",
2109 FT_BOOLEAN, 8, TFS(&tfs_true_false), COMMAND_DATA_SET_ACCELERATION,
2110 "Command Data Set: Command Acceleration", HFILL}
2112 { &hf_cip_cmd_data_trq_cmd,
2113 { "Command Torque", "cipm.cmd.trq",
2114 FT_BOOLEAN, 8, TFS(&tfs_true_false), COMMAND_DATA_SET_TORQUE,
2115 "Command Data Set: Command Torque", HFILL}
2117 { &hf_cip_cmd_data_pos_trim_cmd,
2118 { "Position Trim", "cipm.cmd.postrm",
2119 FT_BOOLEAN, 8, TFS(&tfs_true_false), COMMAND_DATA_SET_POSITION_TRIM,
2120 "Command Data Set: Position Trim", HFILL}
2122 { &hf_cip_cmd_data_vel_trim_cmd,
2123 { "Velocity Trim", "cipm.cmd.veltrm",
2124 FT_BOOLEAN, 8, TFS(&tfs_true_false), COMMAND_DATA_SET_VELOCITY_TRIM,
2125 "Command Data Set: Velocity Trim", HFILL}
2127 { &hf_cip_cmd_data_acc_trim_cmd,
2128 { "Acceleration Trim", "cipm.cmd.acctrm",
2129 FT_BOOLEAN, 8, TFS(&tfs_true_false), COMMAND_DATA_SET_ACCELERATION_TRIM,
2130 "Command Data Set: Acceleration Trim", HFILL}
2132 { &hf_cip_cmd_data_trq_trim_cmd,
2133 { "Torque Trim", "cipm.cmd.trqtrm",
2134 FT_BOOLEAN, 8, TFS(&tfs_true_false), COMMAND_DATA_SET_TORQUE_TRIM,
2135 "Command Data Set: Torque Trim", HFILL}
2138 { &hf_cip_act_data_pos,
2139 { "Actual Position", "cipm.act.pos",
2140 FT_BOOLEAN, 8, TFS(&tfs_true_false), ACTUAL_DATA_SET_POSITION,
2141 "Acutal Data Set: Actual Position", HFILL}
2143 { &hf_cip_act_data_vel,
2144 { "Actual Velocity", "cipm.act.vel",
2145 FT_BOOLEAN, 8, TFS(&tfs_true_false), ACTUAL_DATA_SET_VELOCITY,
2146 "Actual Data Set: Actual Velocity", HFILL}
2148 { &hf_cip_act_data_acc,
2149 { "Actual Acceleration", "cipm.act.acc",
2150 FT_BOOLEAN, 8, TFS(&tfs_true_false), ACTUAL_DATA_SET_ACCELERATION,
2151 "Actual Data Set: Actual Acceleration", HFILL}
2153 { &hf_cip_act_data_trq,
2154 { "Actual Torque", "cipm.act.trq",
2155 FT_BOOLEAN, 8, TFS(&tfs_true_false), ACTUAL_DATA_SET_TORQUE,
2156 "Actual Data Set: Actual Torque", HFILL}
2158 { &hf_cip_act_data_crnt,
2159 { "Actual Current", "cipm.act.crnt",
2160 FT_BOOLEAN, 8, TFS(&tfs_true_false), ACTUAL_DATA_SET_CURRENT,
2161 "Actual Data Set: Actual Current", HFILL}
2163 { &hf_cip_act_data_vltg,
2164 { "Actual Voltage", "cipm.act.vltg",
2165 FT_BOOLEAN, 8, TFS(&tfs_true_false), ACTUAL_DATA_SET_VOLTAGE,
2166 "Actual Data Set: Actual Voltage", HFILL}
2168 { &hf_cip_act_data_fqcy,
2169 { "Actual Frequency", "cipm.act.fqcy",
2170 FT_BOOLEAN, 8, TFS(&tfs_true_false), ACTUAL_DATA_SET_FREQUENCY,
2171 "Actual Data Set: Actual Frequency", HFILL}
2174 { &hf_cip_axis_fault,
2175 { "Axis Fault Code", "cipm.fault.code",
2176 FT_UINT8, BASE_DEC, NULL, 0,
2177 "Status Data Set: Fault Code", HFILL }
2179 { &hf_cip_fault_type,
2180 { "Axis Fault Type", "cipm.flttype",
2181 FT_UINT8, BASE_DEC, NULL, 0,
2182 "Axis Status: Axis Fault Type", HFILL}
2184 { &hf_cip_fault_sub_code,
2185 { "Axis Fault Sub Code", "cipm.fltsubcode",
2186 FT_UINT8, BASE_DEC, NULL, 0,
2187 "Axis Status: Axis Fault Sub Code", HFILL}
2189 { &hf_cip_fault_action,
2190 { "Axis Fault Action", "cipm.fltaction",
2191 FT_UINT8, BASE_DEC, NULL, 0,
2192 "Axis Status: Axis Fault Action", HFILL}
2194 { &hf_cip_fault_time_stamp,
2195 { "Axis Fault Time Stamp", "cipm.flttimestamp",
2196 FT_UINT64, BASE_DEC, NULL, 0,
2197 "Axis Status: Axis Fault Time Stamp", HFILL}
2199 { &hf_cip_alarm_type,
2200 { "Axis Fault Type", "cipm.alarmtype",
2201 FT_UINT8, BASE_DEC, NULL, 0,
2202 "Axis Status: Axis Alarm Type", HFILL}
2204 { &hf_cip_alarm_sub_code,
2205 { "Axis Alarm Sub Code", "cipm.alarmsubcode",
2206 FT_UINT8, BASE_DEC, NULL, 0,
2207 "Axis Status: Axis Alarm Sub Code", HFILL}
2209 { &hf_cip_alarm_state,
2210 { "Axis Alarm State", "cipm.alarmstate",
2211 FT_UINT8, BASE_DEC, NULL, 0,
2212 "Axis Status: Axis Alarm State", HFILL }
2214 { &hf_cip_alarm_time_stamp,
2215 { "Axis Fault Time Stamp", "cipm.alarmtimestamp",
2216 FT_UINT64, BASE_DEC, NULL, 0,
2217 "Axis Status: Axis Alarm Time Stamp", HFILL}
2219 { &hf_cip_axis_status,
2220 { "Axis Status", "cipm.axisstatus",
2221 FT_UINT32, BASE_HEX, NULL, 0,
2222 NULL, HFILL}
2224 { &hf_cip_axis_status_mfg,
2225 { "Axis Status Mfg", "cipm.axisstatusmfg",
2226 FT_UINT32, BASE_HEX, NULL, 0,
2227 "Axis Status, Manufacturer Specific", HFILL}
2229 { &hf_cip_axis_io_status,
2230 { "Axis I/O Status", "cipm.axisiostatus",
2231 FT_UINT32, BASE_HEX, NULL, 0,
2232 NULL, HFILL}
2234 { &hf_cip_axis_io_status_mfg,
2235 { "Axis I/O Status Mfg", "cipm.axisiostatusmfg",
2236 FT_UINT32, BASE_HEX, NULL, 0,
2237 "Axis I/O Status, Manufacturer Specific", HFILL}
2239 { &hf_cip_safety_status,
2240 { "Axis Safety Status", "cipm.safetystatus",
2241 FT_UINT32, BASE_HEX, NULL, 0,
2242 NULL, HFILL}
2244 { &hf_cip_sts_flt,
2245 { "Axis Fault Codes", "cipm.sts.flt",
2246 FT_BOOLEAN, 8, TFS(&tfs_true_false), STATUS_DATA_SET_AXIS_FAULT,
2247 "Status Data Set: Axis Fault Codes", HFILL}
2249 { &hf_cip_sts_alrm,
2250 { "Axis Alarm Codes", "cipm.sts.alarm",
2251 FT_BOOLEAN, 8, TFS(&tfs_true_false), STATUS_DATA_SET_AXIS_ALARM,
2252 "Status Data Set: Axis Alarm Codes", HFILL}
2254 { &hf_cip_sts_sts,
2255 { "Axis Status", "cipm.sts.sts",
2256 FT_BOOLEAN, 8, TFS(&tfs_true_false), STATUS_DATA_SET_AXIS_STATUS,
2257 "Status Data Set: Axis Status", HFILL}
2259 { &hf_cip_sts_iosts,
2260 { "Axis I/O Status", "cipm.sts.iosts",
2261 FT_BOOLEAN, 8, TFS(&tfs_true_false), STATUS_DATA_SET_AXIS_IO_STATUS,
2262 "Status Data Set: Axis I/O Status", HFILL}
2264 { &hf_cip_sts_safety,
2265 { "Axis Safety Status", "cipm.sts.safety",
2266 FT_BOOLEAN, 8, TFS(&tfs_true_false), STATUS_DATA_SET_AXIS_SAFETY,
2267 "Status Data Set: Axis Safety Status", HFILL}
2270 { &hf_cip_intrp,
2271 { "Interpolation Control", "cipm.intrp",
2272 FT_UINT8, BASE_DEC, VALS(cip_interpolation_vals), COMMAND_CONTROL_TARGET_UPDATE,
2273 "Cyclic Data Block: Interpolation Control", HFILL}
2275 { &hf_cip_position_data_type,
2276 { "Position Data Type", "cipm.posdatatype",
2277 FT_UINT8, BASE_DEC, VALS(cip_pos_data_type_vals), COMMAND_CONTROL_POSITION_DATA_TYPE,
2278 "Cyclic Data Block: Position Data Type", HFILL }
2280 { &hf_cip_axis_state,
2281 { "Axis State", "cipm.axste",
2282 FT_UINT8, BASE_DEC, VALS(cip_axis_state_vals), 0,
2283 "Cyclic Data Block: Axis State", HFILL}
2285 { &hf_cip_command_control,
2286 { "Command Control", "cipm.cmdcontrol",
2287 FT_UINT8, BASE_DEC, NULL, 0,
2288 "Cyclic Data Block: Command Control", HFILL }
2290 { &hf_cip_cyclic_wrt_data,
2291 { "Write Data", "cipm.writedata",
2292 FT_BYTES, BASE_NONE, NULL, 0,
2293 "Cyclic Write: Data", HFILL }
2295 { &hf_cip_cyclic_rd_data,
2296 { "Read Data", "cipm.readdata",
2297 FT_BYTES, BASE_NONE, NULL, 0,
2298 "Cyclic Read: Data", HFILL }
2300 { &hf_cip_cyclic_write_blk,
2301 { "Write Block", "cipm.writeblk",
2302 FT_UINT8, BASE_DEC, NULL, 0,
2303 "Cyclic Data Block: Write Block Id", HFILL }
2305 { &hf_cip_cyclic_read_blk,
2306 { "Read Block", "cipm.readblk",
2307 FT_UINT8, BASE_DEC, NULL, 0,
2308 "Cyclic Data Block: Read Block Id", HFILL}
2310 { &hf_cip_cyclic_write_sts,
2311 { "Write Status", "cipm.writests",
2312 FT_UINT8, BASE_DEC, NULL, 0,
2313 "Cyclic Data Block: Write Status", HFILL }
2315 { &hf_cip_cyclic_read_sts,
2316 { "Read Status", "cipm.readsts",
2317 FT_UINT8, BASE_DEC, NULL, 0,
2318 "Cyclic Data Block: Read Status", HFILL }
2320 { &hf_cip_event_checking,
2321 { "Event Control", "cipm.evntchkcontrol",
2322 FT_UINT32, BASE_HEX, NULL, 0,
2323 "Event Channel: Event Checking Control", HFILL}
2325 { &hf_cip_event_ack,
2326 { "Event Acknowledgement", "cipm.evntack",
2327 FT_UINT8, BASE_DEC, NULL, 0,
2328 "Event Channel: Event Acknowledgement", HFILL}
2330 { &hf_cip_event_status,
2331 { "Event Status", "cipm.evntchkstatus",
2332 FT_UINT32, BASE_HEX, NULL, 0,
2333 "Event Channel: Event Checking Status", HFILL}
2335 { &hf_cip_event_id,
2336 { "Event Id", "cipm.evntack",
2337 FT_UINT8, BASE_DEC, NULL, 0,
2338 "Event Channel: Event Id", HFILL }
2340 { &hf_cip_event_pos,
2341 { "Event Position", "cipm.evntpos",
2342 FT_INT32, BASE_DEC, NULL, 0,
2343 "Event Channel: Event Position", HFILL}
2345 { &hf_cip_event_ts,
2346 { "Event Time Stamp", "cipm.evntimestamp",
2347 FT_UINT64, BASE_DEC, NULL, 0,
2348 "Event Channel: Time Stamp", HFILL}
2351 { &hf_cip_evnt_ctrl_reg1_pos,
2352 { "Reg 1 Pos Edge", "cipm.evnt.ctrl.reg1posedge",
2353 FT_BOOLEAN, 32, TFS(&tfs_true_false), 0x00000001,
2354 "Event Checking Control: Reg 1 Pos Edge", HFILL}
2356 { &hf_cip_evnt_ctrl_reg1_neg,
2357 { "Reg 1 Neg Edge", "cipm.evnt.ctrl.reg1negedge",
2358 FT_BOOLEAN, 32, TFS(&tfs_true_false), 0x00000002,
2359 "Event Checking Control: Reg 1 Neg Edge", HFILL}
2361 { &hf_cip_evnt_ctrl_reg2_pos,
2362 { "Reg 2 Pos Edge", "cipm.evnt.ctrl.reg2posedge",
2363 FT_BOOLEAN, 32, TFS(&tfs_true_false), 0x00000004,
2364 "Event Checking Control: Reg 2 Pos Edge", HFILL}
2366 { &hf_cip_evnt_ctrl_reg2_neg,
2367 { "Reg 2 Neg Edge", "cipm.evnt.ctrl.reg2negedge",
2368 FT_BOOLEAN, 32, TFS(&tfs_true_false), 0x00000008,
2369 "Event Checking Control: Reg 2 Neg Edge", HFILL}
2371 { &hf_cip_evnt_ctrl_reg1_posrearm,
2372 { "Reg 1 Pos Rearm", "cipm.evnt.ctrl.reg1posrearm",
2373 FT_BOOLEAN, 32, TFS(&tfs_true_false), 0x00000100,
2374 "Event Checking Control: Reg 1 Pos Rearm", HFILL}
2376 { &hf_cip_evnt_ctrl_reg1_negrearm,
2377 { "Reg 1 Neg Rearm", "cipm.evnt.ctrl.reg1negrearm",
2378 FT_BOOLEAN, 32, TFS(&tfs_true_false), 0x00000200,
2379 "Event Checking Control: Reg 1 Neg Rearm", HFILL}
2381 { &hf_cip_evnt_ctrl_reg2_posrearm,
2382 { "Reg 2 Pos Rearm", "cipm.evnt.ctrl.reg2posrearm",
2383 FT_BOOLEAN, 32, TFS(&tfs_true_false), 0x00000400,
2384 "Event Checking Control: Reg 2 Pos Rearm", HFILL}
2386 { &hf_cip_evnt_ctrl_reg2_negrearm,
2387 { "Reg 2 Neg Rearm", "cipm.evnt.ctrl.reg2negrearm",
2388 FT_BOOLEAN, 32, TFS(&tfs_true_false), 0x00000800,
2389 "Event Checking Control: Reg 2 Neg Rearm", HFILL}
2391 { &hf_cip_evnt_ctrl_marker_pos,
2392 { "Marker Pos Edge", "cipm.evnt.ctrl.mrkrpos",
2393 FT_BOOLEAN, 32, TFS(&tfs_true_false), 0x00010000,
2394 "Event Checking Control: Marker Pos Edge", HFILL}
2396 { &hf_cip_evnt_ctrl_marker_neg,
2397 { "Marker Neg Edge", "cipm.evnt.ctrl.mrkrneg",
2398 FT_BOOLEAN, 32, TFS(&tfs_true_false), 0x00020000,
2399 "Event Checking Control: Marker Neg Edge", HFILL}
2401 { &hf_cip_evnt_ctrl_home_pos,
2402 { "Home Pos Edge", "cipm.evnt.ctrl.homepos",
2403 FT_BOOLEAN, 32, TFS(&tfs_true_false), 0x00040000,
2404 "Event Checking Control: Home Pos Edge", HFILL}
2406 { &hf_cip_evnt_ctrl_home_neg,
2407 { "Home Neg Edge", "cipm.evnt.ctrl.homeneg",
2408 FT_BOOLEAN, 32, TFS(&tfs_true_false), 0x00080000,
2409 "Event Checking Control: Home Neg Edge", HFILL}
2411 { &hf_cip_evnt_ctrl_home_pp,
2412 { "Home-Switch-Marker Plus Plus", "cipm.evnt.ctrl.homepp",
2413 FT_BOOLEAN, 32, TFS(&tfs_true_false), 0x00100000,
2414 "Event Checking Control: Home-Switch-Marker Plus Plus", HFILL}
2416 { &hf_cip_evnt_ctrl_home_pm,
2417 { "Home-Switch-Marker Plus Minus", "cipm.evnt.ctrl.homepm",
2418 FT_BOOLEAN, 32, TFS(&tfs_true_false), 0x00200000,
2419 "Event Checking Control: Home-Switch-Marker Plus Minus", HFILL}
2421 { &hf_cip_evnt_ctrl_home_mp,
2422 { "Home-Switch-Marker Minus Plus", "cipm.evnt.ctrl.homemp",
2423 FT_BOOLEAN, 32, TFS(&tfs_true_false), 0x00400000,
2424 "Event Checking Control: Home-Switch-Marker Minus Plus", HFILL}
2426 { &hf_cip_evnt_ctrl_home_mm,
2427 { "Home-Switch-Marker Minus Minus", "cipm.evnt.ctrl.homemm",
2428 FT_BOOLEAN, 32, TFS(&tfs_true_false), 0x00800000,
2429 "Event Checking Control: Home-Switch-Marker Minus Minus", HFILL}
2431 { &hf_cip_evnt_ctrl_acks,
2432 { "Event Acknowledge Blocks", "cipm.evnt.ctrl.acks",
2433 FT_UINT32, BASE_DEC, NULL, 0x70000000,
2434 "Event Checking Control: Event Acknowledge Blocks", HFILL}
2436 { &hf_cip_evnt_extend_format,
2437 { "Extended Event Format", "cipm.evnt.extend",
2438 FT_BOOLEAN, 32, TFS(&tfs_true_false), 0x80000000,
2439 "Event Checking Control: Extended Event Format", HFILL}
2442 { &hf_cip_evnt_sts_reg1_pos,
2443 { "Reg 1 Pos Edge", "cipm.evnt.sts.reg1posedge",
2444 FT_BOOLEAN, 32, TFS(&tfs_true_false), 0x00000001,
2445 "Event Checking Status: Reg 1 Pos Edge", HFILL}
2447 { &hf_cip_evnt_sts_reg1_neg,
2448 { "Reg 1 Neg Edge", "cipm.evnt.sts.reg1negedge",
2449 FT_BOOLEAN, 32, TFS(&tfs_true_false), 0x00000002,
2450 "Event Checking Status: Reg 1 Neg Edge", HFILL }
2452 { &hf_cip_evnt_sts_reg2_pos,
2453 { "Reg 2 Pos Edge", "cipm.evnt.sts.reg2posedge",
2454 FT_BOOLEAN, 32, TFS(&tfs_true_false), 0x00000004,
2455 "Event Checking Status: Reg 2 Pos Edge", HFILL}
2457 { &hf_cip_evnt_sts_reg2_neg,
2458 { "Reg 2 Neg Edge", "cipm.evnt.sts.reg2negedge",
2459 FT_BOOLEAN, 32, TFS(&tfs_true_false), 0x00000008,
2460 "Event Checking Status: Reg 2 Neg Edge", HFILL}
2462 { &hf_cip_evnt_sts_reg1_posrearm,
2463 { "Reg 1 Pos Rearm", "cipm.evnt.sts.reg1posrearm",
2464 FT_BOOLEAN, 32, TFS(&tfs_true_false), 0x00000100,
2465 "Event Checking Status: Reg 1 Pos Rearm", HFILL}
2467 { &hf_cip_evnt_sts_reg1_negrearm,
2468 { "Reg 1 Neg Rearm", "cipm.evnt.sts.reg1negrearm",
2469 FT_BOOLEAN, 32, TFS(&tfs_true_false), 0x00000200,
2470 "Event Checking Status: Reg 1 Neg Rearm", HFILL}
2472 { &hf_cip_evnt_sts_reg2_posrearm,
2473 { "Reg 2 Pos Rearm", "cipm.evnt.sts.reg2posrearm",
2474 FT_BOOLEAN, 32, TFS(&tfs_true_false), 0x00000400,
2475 "Event Checking Status: Reg 2 Pos Rearm", HFILL}
2477 { &hf_cip_evnt_sts_reg2_negrearm,
2478 { "Reg 2 Neg Rearm", "cipm.evnt.sts.reg2negrearm",
2479 FT_BOOLEAN, 32, TFS(&tfs_true_false), 0x00000800,
2480 "Event Checking Status: Reg 2 Neg Rearm", HFILL}
2482 { &hf_cip_evnt_sts_marker_pos,
2483 { "Marker Pos Edge", "cipm.evnt.sts.mrkrpos",
2484 FT_BOOLEAN, 32, TFS(&tfs_true_false), 0x00010000,
2485 "Event Checking Status: Marker Pos Edge", HFILL}
2487 { &hf_cip_evnt_sts_marker_neg,
2488 { "Marker Neg Edge", "cipm.evnt.sts.mrkrneg",
2489 FT_BOOLEAN, 32, TFS(&tfs_true_false), 0x00020000,
2490 "Event Checking Status: Marker Neg Edge", HFILL }
2492 { &hf_cip_evnt_sts_home_pos,
2493 { "Home Pos Edge", "cipm.evnt.sts.homepos",
2494 FT_BOOLEAN, 32, TFS(&tfs_true_false), 0x00040000,
2495 "Event Checking Status: Home Pos Edge", HFILL}
2497 { &hf_cip_evnt_sts_home_neg,
2498 { "Home Neg Edge", "cipm.evnt.sts.homeneg",
2499 FT_BOOLEAN, 32, TFS(&tfs_true_false), 0x00080000,
2500 "Event Checking Status: Home Neg Edge", HFILL }
2502 { &hf_cip_evnt_sts_home_pp,
2503 { "Home-Switch-Marker Plus Plus", "cipm.evnt.sts.homepp",
2504 FT_BOOLEAN, 32, TFS(&tfs_true_false), 0x00100000,
2505 "Event Checking Status: Home-Switch-Marker Plus Plus", HFILL}
2507 { &hf_cip_evnt_sts_home_pm,
2508 { "Home-Switch-Marker Plus Minus", "cipm.evnt.sts.homepm",
2509 FT_BOOLEAN, 32, TFS(&tfs_true_false), 0x00200000,
2510 "Event Checking Status: Home-Switch-Marker Plus Minus", HFILL}
2512 { &hf_cip_evnt_sts_home_mp,
2513 { "Home-Switch-Marker Minus Plus", "cipm.evnt.sts.homemp",
2514 FT_BOOLEAN, 32, TFS(&tfs_true_false), 0x00400000,
2515 "Event Checking Status: Home-Switch-Marker Minus Plus", HFILL}
2517 { &hf_cip_evnt_sts_home_mm,
2518 { "Home-Switch-Marker Minus Minus", "cipm.evnt.sts.homemm",
2519 FT_BOOLEAN, 32, TFS(&tfs_true_false), 0x00800000,
2520 "Event Checking Status: Home-Switch-Marker Minus Minus", HFILL}
2522 { &hf_cip_evnt_sts_nfs,
2523 { "Event Notification Blocks", "cipm.evnt.sts.nfs",
2524 FT_UINT32, BASE_DEC, NULL, 0x70000000,
2525 "Event Checking Status: Event Notification Blocks", HFILL}
2528 { &hf_cip_evnt_sts_stat,
2529 { "Event Status", "cipm.evnt.stat",
2530 FT_UINT8, BASE_DEC|BASE_EXT_STRING, &cip_gs_vals_ext, 0,
2531 "Event Data Block: Event Status", HFILL }
2533 { &hf_cip_evnt_type,
2534 { "Event Type", "cipm.evnt.type",
2535 FT_UINT8, BASE_DEC, VALS(cip_event_type_vals), 0,
2536 "Event Data Block: Event Type", HFILL}
2538 { &hf_cip_svc_code,
2539 { "Service Code", "cipm.svc.code",
2540 FT_UINT8, BASE_DEC, VALS(cip_sc_vals), 0,
2541 "Service Data Block: Service Code", HFILL}
2543 { &hf_cip_svc_sts,
2544 { "General Status", "cipm.svc.sts",
2545 FT_UINT8, BASE_DEC|BASE_EXT_STRING, &cip_gs_vals_ext, 0,
2546 "Service Data Block: General Status", HFILL }
2548 { &hf_cip_svc_transction,
2549 { "Transaction Id", "cipm.svc.tranid",
2550 FT_UINT8, BASE_DEC, NULL, 0,
2551 "Service Data Block: Transaction Id", HFILL }
2553 { &hf_cip_svc_ext_status,
2554 { "Extended Status", "cipm.svc.extstatus",
2555 FT_UINT8, BASE_DEC, NULL, 0,
2556 "Service Data Block: Extended Status", HFILL }
2558 { &hf_cip_svc_data,
2559 { "Service Data", "cipm.svc.data",
2560 FT_BYTES, BASE_NONE, NULL, 0,
2561 "Service Data Block: Data", HFILL }
2563 { &hf_cip_attribute_data,
2564 { "Attribute Data", "cipm.attrdata",
2565 FT_BYTES, BASE_NONE, NULL, 0,
2566 "Attribute Service: Data", HFILL }
2568 { &hf_cip_ptp_grandmaster,
2569 { "Grandmaster", "cipm.grandmaster",
2570 FT_UINT64, BASE_HEX, NULL, 0,
2571 "Group Sync: Grandmaster Id", HFILL}
2574 { &hf_cip_svc_get_axis_attr_sts,
2575 { "Attribute Status", "cipm.getaxisattr.sts",
2576 FT_UINT8, BASE_DEC|BASE_EXT_STRING, &cip_gs_vals_ext, 0,
2577 "Service Channel: Get Axis Attribute List Response Status", HFILL }
2579 { &hf_get_axis_attr_list_attribute_cnt,
2580 { "Number of attributes", "cipm.getaxisattr.cnt",
2581 FT_UINT16, BASE_DEC, NULL, 0,
2582 "Service Channel: Get Axis Attribute List Attribute Count", HFILL}
2584 { &hf_get_axis_attr_list_attribute_id,
2585 { "Attribute ID", "cipm.getaxisattr.id",
2586 FT_UINT16, BASE_DEC, NULL, 0,
2587 "Service Channel: Get Axis Attribute List Attribute ID", HFILL}
2589 { &hf_get_axis_attr_list_dimension,
2590 { "Dimension", "cipm.getaxisattr.dimension",
2591 FT_UINT8, BASE_DEC, NULL, 0,
2592 "Service Channel: Get Axis Attribute List Dimension", HFILL}
2594 { &hf_get_axis_attr_list_element_size,
2595 { "Element size", "cipm.getaxisattr.element_size",
2596 FT_UINT8, BASE_DEC, NULL, 0,
2597 "Service Channel: Get Axis Attribute List Element Size", HFILL}
2599 { &hf_get_axis_attr_list_start_index,
2600 { "Start index", "cipm.getaxisattr.start_index",
2601 FT_UINT16, BASE_DEC, NULL, 0,
2602 "Service Channel: Get Axis Attribute List Start index", HFILL}
2604 { &hf_get_axis_attr_list_data_elements,
2605 { "Data elements", "cipm.getaxisattr.data_elements",
2606 FT_UINT16, BASE_DEC, NULL, 0,
2607 "Service Channel: Get Axis Attribute List Data elements", HFILL}
2610 { &hf_cip_svc_set_axis_attr_sts,
2611 { "Attribute Status", "cipm.setaxisattr.sts",
2612 FT_UINT8, BASE_DEC|BASE_EXT_STRING, &cip_gs_vals_ext, 0,
2613 "Service Channel: Set Axis Attribute List Response Status", HFILL }
2615 { &hf_set_axis_attr_list_attribute_cnt,
2616 { "Number of attributes", "cipm.setaxisattr.cnt",
2617 FT_UINT16, BASE_DEC, NULL, 0,
2618 "Service Channel: Set Axis Attribute List Attribute Count", HFILL}
2620 { &hf_set_axis_attr_list_attribute_id,
2621 { "Attribute ID", "cipm.setaxisattr.id",
2622 FT_UINT16, BASE_DEC, NULL, 0,
2623 "Service Channel: Set Axis Attribute List Attribute ID", HFILL}
2625 { &hf_set_axis_attr_list_dimension,
2626 { "Dimension", "cipm.setaxisattr.dimension",
2627 FT_UINT8, BASE_DEC, NULL, 0,
2628 "Service Channel: Set Axis Attribute List Dimension", HFILL}
2630 { &hf_set_axis_attr_list_element_size,
2631 { "Element size", "cipm.setaxisattr.element_size",
2632 FT_UINT8, BASE_DEC, NULL, 0,
2633 "Service Channel: Set Axis Attribute List Element Size", HFILL}
2635 { &hf_set_axis_attr_list_start_index,
2636 { "Start index", "cipm.setaxisattr.start_index",
2637 FT_UINT16, BASE_DEC, NULL, 0,
2638 "Service Channel: Set Axis Attribute List Start index", HFILL}
2640 { &hf_set_axis_attr_list_data_elements,
2641 { "Data elements", "cipm.setaxisattr.data_elements",
2642 FT_UINT16, BASE_DEC, NULL, 0,
2643 "Service Channel: Set Axis Attribute List Data elements", HFILL}
2646 { &hf_var_devce_instance,
2647 { "Instance Number", "cipm.var_devce.header.instance",
2648 FT_UINT8, BASE_DEC, NULL, 0,
2649 "Variable Device Header: Instance Number", HFILL}
2651 { &hf_var_devce_instance_block_size,
2652 { "Instance Block Size", "cipm.var_devce.header.instance_block_size",
2653 FT_UINT8, BASE_DEC, NULL, 0,
2654 "Variable Device Header: Instance Block Size", HFILL}
2656 { &hf_var_devce_cyclic_block_size,
2657 { "Cyclic Block Size", "cipm.var_devce.header.cyclic_block_size",
2658 FT_UINT8, BASE_DEC, NULL, 0,
2659 "Variable Device Header: Cyclic Block Size", HFILL}
2661 { &hf_var_devce_cyclic_data_block_size,
2662 { "Cyclic Data Block Size", "cipm.var_devce.header.cyclic_data_block_size",
2663 FT_UINT8, BASE_DEC, NULL, 0,
2664 "Variable Device Header: Cyclic Data Block Size", HFILL}
2666 { &hf_var_devce_cyclic_rw_block_size,
2667 { "Cyclic Read/Write Block Size", "cipm.var_devce.header.cyclic_rw_block_size",
2668 FT_UINT8, BASE_DEC, NULL, 0,
2669 "Variable Device Header: Cyclic Read/Write Block Size", HFILL}
2671 { &hf_var_devce_event_block_size,
2672 { "Event Block Size", "cipm.var_devce.header.event_block_size",
2673 FT_UINT8, BASE_DEC, NULL, 0,
2674 "Variable Device Header: Event Block Size", HFILL}
2676 { &hf_var_devce_service_block_size,
2677 { "Service Block Size", "cipm.var_devce.header.service_block_size",
2678 FT_UINT8, BASE_DEC, NULL, 0,
2679 "Variable Device Header: Service Block Size", HFILL}
2682 { &hf_cip_axis_alarm,
2683 { "Axis Alarm Code", "cipm.alarm.code",
2684 FT_UINT8, BASE_DEC, NULL, 0,
2685 "Status Data Set: Alarm Code", HFILL }
2687 { &hf_cip_axis_sts_local_ctrl,
2688 { "Local Control", "cipm.axis.local",
2689 FT_BOOLEAN, 32, TFS(&tfs_true_false), 0x00000001,
2690 "Axis Status Data Set: Local Contol", HFILL }
2692 { &hf_cip_axis_sts_alarm,
2693 { "Alarm", "cipm.axis.alarm",
2694 FT_BOOLEAN, 32, TFS(&tfs_true_false), 0x00000002,
2695 "Axis Status Data Set: Alarm", HFILL }
2697 { &hf_cip_axis_sts_dc_bus,
2698 { "DC Bus", "cipm.axis.bus",
2699 FT_BOOLEAN, 32, TFS(&tfs_true_false), 0x00000004,
2700 "Axis Status Data Set: DC Bus", HFILL }
2702 { &hf_cip_axis_sts_pwr_struct,
2703 { "Power Struct", "cipm.axis.pwr",
2704 FT_BOOLEAN, 32, TFS(&tfs_true_false), 0x00000008,
2705 "Axis Status Data Set: Power Struct", HFILL }
2707 { &hf_cip_axis_sts_tracking,
2708 { "Tracking", "cipm.axis.track",
2709 FT_BOOLEAN, 32, TFS(&tfs_true_false), 0x00000020,
2710 "Axis Status Data Set: Tracking", HFILL }
2712 { &hf_cip_axis_sts_pos_lock,
2713 { "Pos Lock", "cipm.axis.poslock",
2714 FT_BOOLEAN, 32, TFS(&tfs_true_false), 0x00000040,
2715 "Axis Status Data Set: Pos Lock", HFILL }
2717 { &hf_cip_axis_sts_vel_lock,
2718 { "Vel Lock", "cipm.axis.vellock",
2719 FT_BOOLEAN, 32, TFS(&tfs_true_false), 0x00000080,
2720 "Axis Status Data Set: Vel Lock", HFILL }
2722 { &hf_cip_axis_sts_vel_standstill,
2723 { "Standstill", "cipm.axis.nomo",
2724 FT_BOOLEAN, 32, TFS(&tfs_true_false), 0x00000100,
2725 "Axis Status Data Set: Standstill", HFILL }
2727 { &hf_cip_axis_sts_vel_threshold,
2728 { "Vel Threshold", "cipm.axis.vthresh",
2729 FT_BOOLEAN, 32, TFS(&tfs_true_false), 0x00000200,
2730 "Axis Status Data Set: Vel Threshold", HFILL }
2732 { &hf_cip_axis_sts_vel_limit,
2733 { "Vel Limit", "cipm.axis.vlim",
2734 FT_BOOLEAN, 32, TFS(&tfs_true_false), 0x00000400,
2735 "Axis Status Data Set: Vel Limit", HFILL }
2737 { &hf_cip_axis_sts_acc_limit,
2738 { "Acc Limit", "cipm.axis.alim",
2739 FT_BOOLEAN, 32, TFS(&tfs_true_false), 0x00000800,
2740 "Axis Status Data Set: Acc Limit", HFILL }
2742 { &hf_cip_axis_sts_dec_limit,
2743 { "Dec Limit", "cipm.axis.dlim",
2744 FT_BOOLEAN, 32, TFS(&tfs_true_false), 0x00001000,
2745 "Axis Status Data Set: Dec Limit", HFILL }
2747 { &hf_cip_axis_sts_torque_threshold,
2748 { "Torque Threshold", "cipm.axis.tthresh",
2749 FT_BOOLEAN, 32, TFS(&tfs_true_false), 0x00002000,
2750 "Axis Status Data Set: Torque Threshold", HFILL }
2752 { &hf_cip_axis_sts_torque_limit,
2753 { "Torque Limit", "cipm.axis.tlim",
2754 FT_BOOLEAN, 32, TFS(&tfs_true_false), 0x00004000,
2755 "Axis Status Data Set: Torque Limit", HFILL }
2757 { &hf_cip_axis_sts_cur_limit,
2758 { "Current Limit", "cipm.axis.ilim",
2759 FT_BOOLEAN, 32, TFS(&tfs_true_false), 0x00008000,
2760 "Axis Status Data Set: Current Limit", HFILL }
2762 { &hf_cip_axis_sts_therm_limit,
2763 { "Thermal Limit", "cipm.axis.hot",
2764 FT_BOOLEAN, 32, TFS(&tfs_true_false), 0x00010000,
2765 "Axis Status Data Set: Thermal Limit", HFILL }
2767 { &hf_cip_axis_sts_feedback_integ,
2768 { "Feedback Integrity", "cipm.axis.fgood",
2769 FT_BOOLEAN, 32, TFS(&tfs_true_false), 0x00020000,
2770 "Axis Status Data Set: Feedback Integrity", HFILL }
2772 { &hf_cip_axis_sts_shutdown,
2773 { "Shutdown", "cipm.axis.sdwn",
2774 FT_BOOLEAN, 32, TFS(&tfs_true_false), 0x00040000,
2775 "Axis Status Data Set: Shutdown", HFILL }
2777 { &hf_cip_axis_sts_in_process,
2778 { "In Process", "cipm.axis.inp",
2779 FT_BOOLEAN, 32, TFS(&tfs_true_false), 0x00080000,
2780 "Axis Status Data Set: In Process", HFILL }
2783 { &hf_cip_act_pos,
2784 { "Actual Position", "cipm.actpos",
2785 FT_INT32, BASE_DEC, NULL, 0,
2786 "Cyclic Data Set: Actual Position", HFILL }
2788 { &hf_cip_act_vel,
2789 { "Actual Velocity", "cipm.actvel",
2790 FT_FLOAT, BASE_NONE, NULL, 0,
2791 "Cyclic Data Set: Actual Velocity", HFILL }
2793 { &hf_cip_act_accel,
2794 { "Actual Acceleration", "cipm.actaccel",
2795 FT_FLOAT, BASE_NONE, NULL, 0,
2796 "Cyclic Data Set: Actual Acceleration", HFILL }
2798 { &hf_cip_act_trq,
2799 { "Actual Torque", "cipm.acttrq",
2800 FT_FLOAT, BASE_NONE, NULL, 0,
2801 "Cyclic Data Set: Actual Torque", HFILL }
2803 { &hf_cip_act_crnt,
2804 { "Actual Current", "cipm.actcrnt",
2805 FT_FLOAT, BASE_NONE, NULL, 0,
2806 "Cyclic Data Set: Actual Current", HFILL }
2808 { &hf_cip_act_volts,
2809 { "Actual Volts", "cipm.actvolts",
2810 FT_FLOAT, BASE_NONE, NULL, 0,
2811 "Cyclic Data Set: Actual Volts", HFILL }
2813 { &hf_cip_act_freq,
2814 { "Actual Frequency", "cipm.actfreq",
2815 FT_FLOAT, BASE_NONE, NULL, 0,
2816 "Cyclic Data Set: Actual Frequency", HFILL }
2818 { &hf_cip_pos_cmd,
2819 { "Position Command", "cipm.posfcmd",
2820 FT_DOUBLE, BASE_NONE, NULL, 0,
2821 "Cyclic Data Set: Position Command (LREAL)", HFILL }
2823 { &hf_cip_pos_cmd_int,
2824 { "Position Command", "cipm.posicmd",
2825 FT_INT32, BASE_DEC, NULL, 0,
2826 "Cyclic Data Set: Position Command (DINT)", HFILL }
2828 { &hf_cip_vel_cmd,
2829 { "Velocity Command", "cipm.velcmd",
2830 FT_FLOAT, BASE_NONE, NULL, 0,
2831 "Cyclic Data Set: Velocity Command", HFILL }
2833 { &hf_cip_accel_cmd,
2834 { "Acceleration Command", "cipm.accelcmd",
2835 FT_FLOAT, BASE_NONE, NULL, 0,
2836 "Cyclic Data Set: Acceleration Command", HFILL }
2838 { &hf_cip_trq_cmd,
2839 { "Torque Command", "cipm.torquecmd",
2840 FT_FLOAT, BASE_NONE, NULL, 0,
2841 "Cyclic Data Set: Torque Command", HFILL }
2843 { &hf_cip_pos_trim,
2844 { "Position Trim", "cipm.postrim",
2845 FT_FLOAT, BASE_NONE, NULL, 0,
2846 "Cyclic Data Set: Position Trim", HFILL }
2848 { &hf_cip_vel_trim,
2849 { "Velocity Trim", "cipm.veltrim",
2850 FT_FLOAT, BASE_NONE, NULL, 0,
2851 "Cyclic Data Set: Velocity Trim", HFILL }
2853 { &hf_cip_accel_trim,
2854 { "Acceleration Trim", "cipm.acceltrim",
2855 FT_FLOAT, BASE_NONE, NULL, 0,
2856 "Cyclic Data Set: Acceleration Trim", HFILL }
2858 { &hf_cip_trq_trim,
2859 { "Torque Trim", "cipm.trqtrim",
2860 FT_FLOAT, BASE_NONE, NULL, 0,
2861 "Cyclic Data Set: Torque Trim", HFILL }
2865 /* Setup protocol subtree array, these will help Wireshark remember
2866 * if the subtree should be expanded as the user moves through packets */
2867 static gint *cip_subtree[] = {
2868 &ett_cipmotion,
2869 &ett_cont_dev_header,
2870 &ett_node_control,
2871 &ett_node_status,
2872 &ett_time_data_set,
2873 &ett_inst_data_header,
2874 &ett_cyclic_data_block,
2875 &ett_control_mode,
2876 &ett_feedback_config,
2877 &ett_command_data_set,
2878 &ett_actual_data_set,
2879 &ett_status_data_set,
2880 &ett_interp_control,
2881 &ett_cyclic_rd_wt,
2882 &ett_event,
2883 &ett_event_check_ctrl,
2884 &ett_event_check_sts,
2885 &ett_service,
2886 &ett_get_axis_attribute,
2887 &ett_set_axis_attribute,
2888 &ett_get_axis_attr_list,
2889 &ett_set_axis_attr_list,
2890 &ett_group_sync,
2891 &ett_axis_status_set,
2892 &ett_command_control
2895 /* Create a CIP Motion protocol handle */
2896 proto_cipmotion = proto_register_protocol(
2897 "Common Industrial Protocol, Motion", /* Full name of protocol */
2898 "CIP Motion", /* Short name of protocol */
2899 "cipm"); /* Abbreviated name of protocol */
2901 /* Register the header fields with the protocol */
2902 proto_register_field_array(proto_cipmotion, hf, array_length(hf));
2904 /* Register the subtrees for the protocol dissection */
2905 proto_register_subtree_array(cip_subtree, array_length(cip_subtree));
2907 register_dissector( "cipmotion", dissect_cipmotion, proto_cipmotion);
2911 * Editor modelines - http://www.wireshark.org/tools/modelines.html
2913 * Local variables:
2914 * c-basic-offset: 3
2915 * tab-width: 8
2916 * indent-tabs-mode: nil
2917 * End:
2919 * ex: set shiftwidth=3 tabstop=8 expandtab:
2920 * :indentSize=3:tabSize=8:noTabs=true: