Coverage Report

Created: 2026-07-12 07:10

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/wireshark/epan/dissectors/packet-cipmotion.c
Line
Count
Source
1
/* packet-cipmotion.c
2
 * Routines for CIP (Common Industrial Protocol) Motion dissection
3
 * CIP Motion Home: www.odva.org
4
 *
5
 * This dissector includes items from:
6
 *    CIP Volume 9: CIP Motion, Edition 1.13
7
 *
8
 * Copyright 2006-2007
9
 * Benjamin M. Stocks <bmstocks@ra.rockwell.com>
10
 *
11
 * Wireshark - Network traffic analyzer
12
 * By Gerald Combs <gerald@wireshark.org>
13
 * Copyright 1998 Gerald Combs
14
 *
15
 * SPDX-License-Identifier: GPL-2.0-or-later
16
 */
17
18
#include "config.h"
19
20
#include <epan/packet.h>
21
#include <epan/expert.h>
22
#include <epan/unit_strings.h>
23
24
#include <wsutil/ws_roundup.h>
25
26
#include "packet-cipmotion.h"
27
28
#include "packet-cip.h"
29
#include "packet-enip.h"
30
31
void proto_register_cipmotion(void);
32
/* The entry point to the actual dissection is: dissect_cipmotion */
33
void proto_reg_handoff_cipmotion(void);
34
35
/* Protocol handle for CIP Motion */
36
static int proto_cipmotion;
37
static int proto_cipmotion3;
38
39
/* Header field identifiers, these are registered in the
40
 * proto_register_cipmotion function along with the bites/bytes
41
 * they represent */
42
static int hf_cip_format;
43
static int hf_cip_revision;
44
static int hf_cip_class1_seqnum;
45
static int hf_configuration_block_format_rev;
46
static int hf_configuration_block_drive_power_struct_id;
47
static int hf_cip_updateid;
48
static int hf_cip_instance_cnt;
49
static int hf_cip_last_update;
50
static int hf_cip_node_status;
51
static int hf_cip_node_control;
52
static int hf_cip_node_control_remote;
53
static int hf_cip_node_control_sync;
54
static int hf_cip_node_data_valid;
55
static int hf_cip_node_fault_reset;
56
static int hf_cip_node_device_faulted;
57
static int hf_cip_time_data_set;
58
static int hf_cip_time_data_stamp;
59
static int hf_cip_time_data_offset;
60
static int hf_cip_time_data_diag;
61
static int hf_cip_time_data_time_diag;
62
static int hf_cip_cont_time_stamp;
63
static int hf_cip_cont_time_offset;
64
static int hf_cip_devc_time_stamp;
65
static int hf_cip_devc_time_offset;
66
static int hf_cip_lost_update;
67
static int hf_cip_late_update;
68
static int hf_cip_data_rx_time_stamp;
69
static int hf_cip_data_tx_time_stamp;
70
static int hf_cip_node_fltalarms;
71
static int hf_cip_motor_cntrl;
72
static int hf_cip_feedback;
73
static int hf_cip_feedback_mode;
74
static int hf_cip_feedback_data_type;
75
static int hf_cip_controller_update_delay_high_limit;
76
static int hf_cip_controller_update_delay_low_limit;
77
static int hf_cip_sync_threshold;
78
static int hf_cip_step_threshold;
79
static int hf_cip_control_method;
80
static int hf_cip_feedback_unit_ratio;
81
static int hf_cip_velocity_threshold;
82
static int hf_cip_velocity_lock_tolerance;
83
static int hf_cip_velocity_standstill_window;
84
static int hf_cip_proving_configuration;
85
static int hf_cip_torque_prove_current;
86
static int hf_cip_brake_test_torque;
87
static int hf_cip_zero_speed;
88
static int hf_cip_zero_speed_time;
89
static int hf_cip_dc_bus_voltage;
90
static int hf_cip_bus_regulator_action;
91
static int hf_cip_inverter_capacity;
92
static int hf_cip_converter_thermal_overload_user_limit;
93
static int hf_cip_bus_undervoltage_user_limit;
94
static int hf_cip_rotary_motor_poles;
95
static int hf_cip_rotary_motor_inertia;
96
static int hf_cip_rotary_motor_max_speed;
97
98
static int hf_connection_configuration_bits;
99
static int hf_connection_configuration_bits_power;
100
static int hf_connection_configuration_bits_safety_bit_valid;
101
static int hf_connection_configuration_bits_allow_network_safety;
102
103
static int hf_cip_axis_control;
104
static int hf_cip_control_status;
105
static int hf_cip_control_status_complete;
106
static int hf_cip_control_status_bus_up;
107
static int hf_cip_control_status_bus_unload;
108
static int hf_cip_control_status_power_loss;
109
static int hf_cip_axis_response;
110
static int hf_cip_axis_resp_stat;
111
static int hf_cip_cmd_data_pos_cmd;
112
static int hf_cip_cmd_data_vel_cmd;
113
static int hf_cip_cmd_data_acc_cmd;
114
static int hf_cip_cmd_data_trq_cmd;
115
static int hf_cip_cmd_data_unwind_cycle_count;
116
static int hf_cip_cmd_data_pos_displacement;
117
static int hf_cip_act_data_pos;
118
static int hf_cip_act_data_vel;
119
static int hf_cip_act_data_acc;
120
static int hf_cip_act_unwind_cycle_count;
121
static int hf_cip_act_pos_displacement;
122
static int hf_cip_sts_flt;
123
static int hf_cip_sts_alrm;
124
static int hf_cip_sts_sts;
125
static int hf_cip_sts_iosts;
126
static int hf_cip_sts_axis_safety;
127
static int hf_cip_intrp;
128
static int hf_cip_position_data_type;
129
static int hf_cip_axis_state;
130
static int hf_cip_evnt_ctrl_reg1_pos;
131
static int hf_cip_evnt_ctrl_reg1_neg;
132
static int hf_cip_evnt_ctrl_reg2_pos;
133
static int hf_cip_evnt_ctrl_reg2_neg;
134
static int hf_cip_evnt_ctrl_reg1_posrearm;
135
static int hf_cip_evnt_ctrl_reg1_negrearm;
136
static int hf_cip_evnt_ctrl_reg2_posrearm;
137
static int hf_cip_evnt_ctrl_reg2_negrearm;
138
static int hf_cip_evnt_ctrl_marker_pos;
139
static int hf_cip_evnt_ctrl_marker_neg;
140
static int hf_cip_evnt_ctrl_home_pos;
141
static int hf_cip_evnt_ctrl_home_neg;
142
static int hf_cip_evnt_ctrl_home_pp;
143
static int hf_cip_evnt_ctrl_home_pm;
144
static int hf_cip_evnt_ctrl_home_mp;
145
static int hf_cip_evnt_ctrl_home_mm;
146
static int hf_cip_evnt_ctrl_acks;
147
static int hf_cip_evnt_extend_format;
148
static int hf_cip_evnt_sts_reg1_pos;
149
static int hf_cip_evnt_sts_reg1_neg;
150
static int hf_cip_evnt_sts_reg2_pos;
151
static int hf_cip_evnt_sts_reg2_neg;
152
static int hf_cip_evnt_sts_reg1_posrearm;
153
static int hf_cip_evnt_sts_reg1_negrearm;
154
static int hf_cip_evnt_sts_reg2_posrearm;
155
static int hf_cip_evnt_sts_reg2_negrearm;
156
static int hf_cip_evnt_sts_marker_pos;
157
static int hf_cip_evnt_sts_marker_neg;
158
static int hf_cip_evnt_sts_home_pos;
159
static int hf_cip_evnt_sts_home_neg;
160
static int hf_cip_evnt_sts_home_pp;
161
static int hf_cip_evnt_sts_home_pm;
162
static int hf_cip_evnt_sts_home_mp;
163
static int hf_cip_evnt_sts_home_mm;
164
static int hf_cip_evnt_sts_nfs;
165
static int hf_cip_evnt_sts_stat;
166
static int hf_cip_evnt_type;
167
static int hf_cip_svc_code;
168
static int hf_cip_svc_sts;
169
static int hf_cip_svc_set_axis_attr_sts;
170
static int hf_cip_svc_get_axis_attr_sts;
171
static int hf_cip_svc_transction;
172
static int hf_cip_svc_ext_status;
173
static int hf_cip_svc_data;
174
static int hf_cip_ptp_grandmaster;
175
static int hf_cip_axis_alarm;
176
static int hf_cip_axis_fault;
177
static int hf_cip_axis_sts_local_ctrl;
178
static int hf_cip_axis_sts_alarm;
179
static int hf_cip_axis_sts_dc_bus;
180
static int hf_cip_axis_sts_pwr_struct;
181
static int hf_cip_axis_sts_flux_up;
182
static int hf_cip_axis_sts_tracking;
183
static int hf_cip_axis_sts_pos_lock;
184
static int hf_cip_axis_sts_vel_lock;
185
static int hf_cip_axis_sts_vel_standstill;
186
static int hf_cip_axis_sts_vel_threshold;
187
static int hf_cip_axis_sts_vel_limit;
188
static int hf_cip_axis_sts_acc_limit;
189
static int hf_cip_axis_sts_dec_limit;
190
static int hf_cip_axis_sts_torque_threshold;
191
static int hf_cip_axis_sts_torque_limit;
192
static int hf_cip_axis_sts_cur_limit;
193
static int hf_cip_axis_sts_therm_limit;
194
static int hf_cip_axis_sts_feedback_integ;
195
static int hf_cip_axis_sts_shutdown;
196
static int hf_cip_axis_sts_in_process;
197
static int hf_cip_axis_sts_dc_bus_unload;
198
static int hf_cip_axis_sts_ac_pwr_loss;
199
static int hf_cip_axis_sts_pos_cntrl_mode;
200
static int hf_cip_axis_sts_vel_cntrl_mode;
201
static int hf_cip_axis_sts_trq_cntrl_mode;
202
203
static int hf_cip_axis_status2;
204
static int hf_cip_axis_sts2_motor;
205
static int hf_cip_axis_sts2_regenerate;
206
static int hf_cip_axis_sts2_ride_thru;
207
static int hf_cip_axis_sts2_ac_line_sync;
208
static int hf_cip_axis_sts2_bus_volt_lock;
209
static int hf_cip_axis_sts2_react_pwr_only;
210
static int hf_cip_axis_sts2_volt_ctrl_mode;
211
static int hf_cip_axis_sts2_pwr_loss;
212
static int hf_cip_axis_sts2_ac_volt_sag;
213
static int hf_cip_axis_sts2_ac_phase_loss;
214
static int hf_cip_axis_sts2_ac_freq_change;
215
static int hf_cip_axis_sts2_ac_sync_loss;
216
static int hf_cip_axis_sts2_single_phase;
217
static int hf_cip_axis_sts2_bus_volt_limit;
218
static int hf_cip_axis_sts2_bus_volt_rate_limit;
219
static int hf_cip_axis_sts2_active_current_rate_limit;
220
static int hf_cip_axis_sts2_reactive_current_rate_limit;
221
static int hf_cip_axis_sts2_reactive_pwr_limit;
222
static int hf_cip_axis_sts2_reactive_pwr_rate_limit;
223
static int hf_cip_axis_sts2_active_current_limit;
224
static int hf_cip_axis_sts2_reactive_current_limit;
225
static int hf_cip_axis_sts2_motor_pwr_limit;
226
static int hf_cip_axis_sts2_regen_pwr_limit;
227
static int hf_cip_axis_sts2_convert_therm_limit;
228
229
static int hf_cip_cyclic_wrt_data;
230
static int hf_cip_cyclic_rd_data;
231
static int hf_cip_cyclic_write_blk;
232
static int hf_cip_cyclic_read_blk;
233
static int hf_cip_cyclic_write_sts;
234
static int hf_cip_cyclic_read_sts;
235
static int hf_cip_attribute_data;
236
static int hf_cip_event_checking;
237
static int hf_cip_event_ack;
238
static int hf_cip_event_status;
239
static int hf_cip_event_id;
240
static int hf_cip_event_pos;
241
static int hf_cip_event_ts;
242
static int hf_cip_pos_cmd;
243
static int hf_cip_pos_cmd_int;
244
static int hf_cip_vel_cmd;
245
static int hf_cip_accel_cmd;
246
static int hf_cip_trq_cmd;
247
static int hf_cip_pos_trim;
248
static int hf_cip_vel_trim;
249
static int hf_cip_accel_trim;
250
static int hf_cip_trq_trim;
251
static int hf_cip_act_pos;
252
static int hf_cip_act_pos_64;
253
static int hf_cip_act_vel;
254
static int hf_cip_act_accel;
255
static int hf_cip_fault_type;
256
static int hf_cip_fault_sub_code;
257
static int hf_cip_fault_action;
258
static int hf_cip_fault_time_stamp;
259
static int hf_cip_alarm_type;
260
static int hf_cip_alarm_sub_code;
261
static int hf_cip_alarm_state;
262
static int hf_cip_alarm_time_stamp;
263
static int hf_cip_axis_status;
264
static int hf_cip_axis_status_mfg;
265
static int hf_cip_axis_io_status;
266
static int hf_cip_axis_io_status_mfg;
267
static int hf_cip_axis_safety_status;
268
static int hf_cip_axis_safety_status_mfg;
269
static int hf_cip_axis_safety_state;
270
static int hf_cip_cmd_data_set;
271
static int hf_cip_act_data_set;
272
static int hf_cip_sts_data_set;
273
static int hf_cip_group_sync;
274
static int hf_cip_command_control;
275
276
static int hf_get_axis_attr_list_attribute_cnt;
277
static int hf_get_axis_attr_list_attribute_id;
278
static int hf_get_axis_attr_list_dimension;
279
static int hf_get_axis_attr_list_element_size;
280
static int hf_get_axis_attr_list_start_index;
281
static int hf_get_axis_attr_list_data_elements;
282
static int hf_set_axis_attr_list_attribute_cnt;
283
static int hf_set_axis_attr_list_attribute_id;
284
static int hf_set_axis_attr_list_dimension;
285
static int hf_set_axis_attr_list_element_size;
286
static int hf_set_axis_attr_list_start_index;
287
static int hf_set_axis_attr_list_data_elements;
288
static int hf_set_cyclic_list_attribute_cnt;
289
static int hf_set_cyclic_list_attribute_id;
290
static int hf_set_cyclic_list_read_block_id;
291
static int hf_set_cyclic_list_attr_sts;
292
static int hf_var_devce_instance;
293
static int hf_var_devce_instance_block_size;
294
static int hf_var_devce_cyclic_block_size;
295
static int hf_var_devce_cyclic_data_block_size;
296
static int hf_var_devce_cyclic_rw_block_size;
297
static int hf_var_devce_event_block_size;
298
static int hf_var_devce_service_block_size;
299
static int hf_cip_data;
300
301
/* Subtree pointers for the dissection */
302
static int ett_cipmotion;
303
static int ett_cont_dev_header;
304
static int ett_control_status;
305
static int ett_node_control;
306
static int ett_node_status;
307
static int ett_time_data_set;
308
static int ett_inst_data_header;
309
static int ett_cyclic_data_block;
310
static int ett_cyclic_command_data;
311
static int ett_feedback_mode;
312
static int ett_connection_configuration_bits;
313
static int ett_control_mode;
314
static int ett_feedback_config;
315
static int ett_command_data_set;
316
static int ett_actual_data_set;
317
static int ett_status_data_set;
318
static int ett_interp_control;
319
static int ett_cyclic_rd_wt;
320
static int ett_event;
321
static int ett_event_check_ctrl;
322
static int ett_event_check_sts;
323
static int ett_service;
324
static int ett_get_axis_attribute;
325
static int ett_set_axis_attribute;
326
static int ett_get_axis_attr_list;
327
static int ett_set_axis_attr_list;
328
static int ett_set_cyclic_list;
329
static int ett_group_sync;
330
static int ett_axis_status_set;
331
static int ett_command_control;
332
static int ett_configuration_block;
333
334
static expert_field ei_format_rev_conn_pt;
335
336
static dissector_handle_t cipmotion_handle;
337
static dissector_handle_t cipmotion3_handle;
338
339
static bool display_full_attribute_data;
340
341
/* These are the BITMASKS for the Time Data Set header field */
342
15
#define TIME_DATA_SET_TIME_STAMP                0x1
343
15
#define TIME_DATA_SET_TIME_OFFSET               0x2
344
15
#define TIME_DATA_SET_UPDATE_DIAGNOSTICS        0x4
345
15
#define TIME_DATA_SET_TIME_DIAGNOSTICS          0x8
346
347
/* These are the BITMASKS for the Command Data Set cyclic field */
348
15
#define COMMAND_DATA_SET_POSITION           0x01
349
15
#define COMMAND_DATA_SET_VELOCITY           0x02
350
15
#define COMMAND_DATA_SET_ACCELERATION       0x04
351
15
#define COMMAND_DATA_SET_TORQUE             0x08
352
15
#define COMMAND_DATA_SET_UNWIND_CYCLE_COUNT 0x40
353
15
#define COMMAND_DATA_SET_POSITION_DISPLACE  0x80
354
355
/* These are the BITMASKS for the Actual Data Set cyclic field */
356
15
#define ACTUAL_DATA_SET_POSITION        0x01
357
15
#define ACTUAL_DATA_SET_VELOCITY        0x02
358
15
#define ACTUAL_DATA_SET_ACCELERATION    0x04
359
15
#define ACTUAL_DATA_SET_UNWIND_CYCLE_COUNT 0x40
360
15
#define ACTUAL_DATA_SET_POSITION_DISPLACE  0x80
361
362
/* These are the BITMASKS for the Status Data Set cyclic field */
363
15
#define STATUS_DATA_SET_AXIS_FAULT              0x01
364
15
#define STATUS_DATA_SET_AXIS_ALARM              0x02
365
15
#define STATUS_DATA_SET_AXIS_STATUS             0x04
366
15
#define STATUS_DATA_SET_AXIS_IO_STATUS          0x08
367
15
#define STATUS_DATA_SET_AXIS_SAFETY             0x10
368
369
/* These are the BITMASKS for the Command Control cyclic field */
370
15
#define COMMAND_CONTROL_TARGET_UPDATE       0x03
371
15
#define COMMAND_CONTROL_POSITION_DATA_TYPE  0x0C
372
373
/* These are the VALUES of the connection format header field of the
374
 * CIP Motion protocol */
375
#define FORMAT_FIXED_CONTROL_TO_DEVICE      2
376
#define FORMAT_FIXED_DEVICE_TO_CONTROL      3
377
0
#define FORMAT_VAR_CONTROL_TO_DEVICE        6
378
0
#define FORMAT_VAR_DEVICE_TO_CONTROL        7
379
380
15
#define FEEDBACK_MODE_BITS             0x0F
381
15
#define FEEDBACK_DATA_TYPE_BITS        0x30
382
383
/* Translate function to string - connection format values */
384
static const value_string cip_con_format_vals[] = {
385
   { FORMAT_FIXED_CONTROL_TO_DEVICE,       "Fixed Controller-to-Device"        },
386
   { FORMAT_FIXED_DEVICE_TO_CONTROL,       "Fixed Device-to-Controller"        },
387
   { FORMAT_VAR_CONTROL_TO_DEVICE,         "Variable Controller-to-Device"     },
388
   { FORMAT_VAR_DEVICE_TO_CONTROL,         "Variable Device-to-Controller"     },
389
   { 0,                                    NULL                                }
390
};
391
392
/* Translate function to string - motor control mode values */
393
static const value_string cip_motor_control_vals[] = {
394
   { 0,    "No Control"            },
395
   { 1,    "Position Control"      },
396
   { 2,    "Velocity Control"      },
397
   { 3,    "Acceleration Control"  },
398
   { 4,    "Torque Control"        },
399
   { 0,    NULL                    }
400
};
401
402
/* Translate function to string - feedback mode values */
403
static const value_string cip_feedback_mode_vals[] = {
404
   { 0,    "No Feedback"       },
405
   { 1,    "Master Feedback"   },
406
   { 2,    "Motor Feedback"    },
407
   { 3,    "Load Feedback"     },
408
   { 4,    "Dual Feedback"     },
409
   { 0,    NULL                }
410
};
411
412
static const value_string cip_feedback_type_vals[] = {
413
   { 0,   "DINT"               },
414
   { 1,   "LINT"               },
415
   { 0,    NULL                }
416
};
417
418
/* Translate function to string - axis control values */
419
static const value_string cip_axis_control_vals[] =
420
{
421
   { 0,    "No Request"               },
422
   { 1,    "Enable Request"           },
423
   { 2,    "Disable Request"          },
424
   { 3,    "Shutdown Request"         },
425
   { 4,    "Shutdown Reset Request"   },
426
   { 5,    "Abort Request"            },
427
   { 6,    "Fault Reset Request"      },
428
   { 7,    "Stop Process"             },
429
   { 8,    "Change Actual Pos"        },
430
   { 9,    "Change Command Pos Ref"   },
431
   { 127,  "Cancel Request"           },
432
   { 0,    NULL                       }
433
};
434
435
/* Translate function to string - group sync Status */
436
static const value_string cip_sync_status_vals[] =
437
{
438
   { 0,       "Synchronized"      },
439
   { 1,       "Not Synchronized"  },
440
   { 2,       "Wrong Grandmaster" },
441
   { 3,       "Clock Skew Detected" },
442
   { 0,       NULL }
443
};
444
445
/* Translate function to string - command target update */
446
static const value_string cip_interpolation_vals[] = {
447
   { 0,  "Immediate"         },
448
   { 1,  "Extrapolate (+1)"  },
449
   { 2,  "Interpolate (+2)"  },
450
   { 0,  NULL                }
451
};
452
453
/* These are the VALUES for the Command Position Data Type */
454
0
#define POSITION_DATA_LREAL 0x00
455
#define POSITION_DATA_DINT  0x01
456
457
/* Translate function to string - position data type */
458
static const value_string cip_pos_data_type_vals[] = {
459
   { POSITION_DATA_LREAL, "LREAL (64-bit Float)"   },
460
   { POSITION_DATA_DINT,  "DINT (32-bit Integer)"  },
461
   { 0,                   NULL                     }
462
};
463
464
/* Translate function to string - axis response values */
465
static const value_string cip_axis_response_vals[] = {
466
   { 0,    "No Acknowledge"                 },
467
   { 1,    "Enable Acknowledge"            },
468
   { 2,    "Disable Acknowledge"           },
469
   { 3,    "Shutdown Acknowledge"          },
470
   { 4,    "Shutdown Reset Acknowledge"    },
471
   { 5,    "Abort Acknowledge"             },
472
   { 6,    "Fault Reset Acknowledge"       },
473
   { 7,    "Stop Process Acknowledge"      },
474
   { 8,    "Change Actual Position Reference Acknowledge" },
475
   { 9,    "Change Command Position Reference Acknowledge" },
476
   { 127,  "Cancel Acknowledge"            },
477
   { 0,    NULL                            }
478
};
479
480
/* Translate function to string - axis state values */
481
static const value_string cip_axis_state_vals[] = {
482
   { 0,    "Initializing"      },
483
   { 1,    "Pre-Charge"        },
484
   { 2,    "Stopped"           },
485
   { 3,    "Starting"          },
486
   { 4,    "Running"           },
487
   { 5,    "Testing"           },
488
   { 6,    "Stopping"          },
489
   { 7,    "Aborting"          },
490
   { 8,    "Major Faulted"     },
491
   { 9,    "Start Inhibited"   },
492
   { 10,   "Shutdown"          },
493
   { 0,    NULL                }
494
};
495
496
/* Translate function to string - event type values */
497
static const value_string cip_event_type_vals[] = {
498
   { 0,    "Registration 1 Positive Edge"  },
499
   { 1,    "Registration 1 Negative Edge"  },
500
   { 2,    "Registration 2 Positive Edge"  },
501
   { 3,    "Registration 2 Negative Edge"  },
502
   { 4,    "Marker Positive Edge"          },
503
   { 5,    "Marker Negative Edge"          },
504
   { 6,    "Home Switch Positive Edge"     },
505
   { 7,    "Home Switch Negative Edge"     },
506
   { 8,    "Home Switch Marker ++"         },
507
   { 9,    "Home Switch Marker +-"         },
508
   { 10,   "Home Switch Marker -+"         },
509
   { 11,   "Home Switch Marker --"         },
510
   { 0,    NULL                            }
511
};
512
513
0
#define SC_GET_AXIS_ATTRIBUTE_LIST  0x4B
514
0
#define SC_SET_AXIS_ATTRIBUTE_LIST  0x4C
515
0
#define SC_SET_CYCLIC_WRITE_LIST    0x4D
516
0
#define SC_SET_CYCLIC_READ_LIST     0x4E
517
#define SC_RUN_MOTOR_TEST           0x4F
518
#define SC_GET_MOTOR_TEST_DATA      0x50
519
#define SC_RUN_INERTIA_TEST         0x51
520
#define SC_GET_INERTIA_TEST_DATA    0x52
521
#define SC_RUN_HOOKUP_TEST          0x53
522
#define SC_GET_HOOKUP_TEST_DATA     0x54
523
524
/* Translate function to string - CIP Service codes */
525
static const value_string cip_sc_vals[] = {
526
   GENERIC_SC_LIST
527
   { SC_GET_AXIS_ATTRIBUTE_LIST,   "Get Axis Attribute List"   },
528
   { SC_SET_AXIS_ATTRIBUTE_LIST,   "Set Axis Attribute List"   },
529
   { SC_SET_CYCLIC_WRITE_LIST,     "Set Cyclic Write List"     },
530
   { SC_SET_CYCLIC_READ_LIST,      "Set Cyclic Read List"      },
531
   { SC_RUN_MOTOR_TEST,            "Run Motor Test"            },
532
   { SC_GET_MOTOR_TEST_DATA,       "Get Motor Test Data"       },
533
   { SC_RUN_INERTIA_TEST,          "Run Inertia Test"          },
534
   { SC_GET_INERTIA_TEST_DATA,     "Get Inertia Test Data"     },
535
   { SC_RUN_HOOKUP_TEST,           "Run Hookup Test"           },
536
   { SC_GET_HOOKUP_TEST_DATA,      "Get Hookup Test Data"      },
537
   { 0,                            NULL                        }
538
};
539
540
static int dissect_axis_status(packet_info *pinfo _U_, proto_tree *tree, proto_item *item _U_, tvbuff_t *tvb,
541
   int offset, int total_len _U_)
542
0
{
543
0
   static int* const bits[] = {
544
0
      &hf_cip_axis_sts_local_ctrl,
545
0
      &hf_cip_axis_sts_alarm,
546
0
      &hf_cip_axis_sts_dc_bus,
547
0
      &hf_cip_axis_sts_pwr_struct,
548
0
      &hf_cip_axis_sts_flux_up,
549
0
      &hf_cip_axis_sts_tracking,
550
0
      &hf_cip_axis_sts_pos_lock,
551
0
      &hf_cip_axis_sts_vel_lock,
552
0
      &hf_cip_axis_sts_vel_standstill,
553
0
      &hf_cip_axis_sts_vel_threshold,
554
0
      &hf_cip_axis_sts_vel_limit,
555
0
      &hf_cip_axis_sts_acc_limit,
556
0
      &hf_cip_axis_sts_dec_limit,
557
0
      &hf_cip_axis_sts_torque_threshold,
558
0
      &hf_cip_axis_sts_torque_limit,
559
0
      &hf_cip_axis_sts_cur_limit,
560
0
      &hf_cip_axis_sts_therm_limit,
561
0
      &hf_cip_axis_sts_feedback_integ,
562
0
      &hf_cip_axis_sts_shutdown,
563
0
      &hf_cip_axis_sts_in_process,
564
0
      &hf_cip_axis_sts_dc_bus_unload,
565
0
      &hf_cip_axis_sts_ac_pwr_loss,
566
0
      &hf_cip_axis_sts_pos_cntrl_mode,
567
0
      &hf_cip_axis_sts_vel_cntrl_mode,
568
0
      &hf_cip_axis_sts_trq_cntrl_mode,
569
0
      NULL
570
0
   };
571
572
0
   proto_tree_add_bitmask(tree, tvb, offset, hf_cip_axis_status, ett_axis_status_set, bits, ENC_LITTLE_ENDIAN);
573
574
0
   return 4;
575
0
}
576
577
static int dissect_axis_status2(packet_info *pinfo _U_, proto_tree *tree, proto_item *item _U_, tvbuff_t *tvb,
578
   int offset, int total_len _U_)
579
0
{
580
0
   static int* const bits[] = {
581
0
      &hf_cip_axis_sts2_motor,
582
0
      &hf_cip_axis_sts2_regenerate,
583
0
      &hf_cip_axis_sts2_ride_thru,
584
0
      &hf_cip_axis_sts2_ac_line_sync,
585
0
      &hf_cip_axis_sts2_bus_volt_lock,
586
0
      &hf_cip_axis_sts2_react_pwr_only,
587
0
      &hf_cip_axis_sts2_volt_ctrl_mode,
588
0
      &hf_cip_axis_sts2_pwr_loss,
589
0
      &hf_cip_axis_sts2_ac_volt_sag,
590
0
      &hf_cip_axis_sts2_ac_phase_loss,
591
0
      &hf_cip_axis_sts2_ac_freq_change,
592
0
      &hf_cip_axis_sts2_ac_sync_loss,
593
0
      &hf_cip_axis_sts2_single_phase,
594
0
      &hf_cip_axis_sts2_bus_volt_limit,
595
0
      &hf_cip_axis_sts2_bus_volt_rate_limit,
596
0
      &hf_cip_axis_sts2_active_current_rate_limit,
597
0
      &hf_cip_axis_sts2_reactive_current_rate_limit,
598
0
      &hf_cip_axis_sts2_reactive_pwr_limit,
599
0
      &hf_cip_axis_sts2_reactive_pwr_rate_limit,
600
0
      &hf_cip_axis_sts2_active_current_limit,
601
0
      &hf_cip_axis_sts2_reactive_current_limit,
602
0
      &hf_cip_axis_sts2_motor_pwr_limit,
603
0
      &hf_cip_axis_sts2_regen_pwr_limit,
604
0
      &hf_cip_axis_sts2_convert_therm_limit,
605
0
      NULL
606
0
   };
607
608
0
   proto_tree_add_bitmask(tree, tvb, offset, hf_cip_axis_status2, ett_axis_status_set, bits, ENC_LITTLE_ENDIAN);
609
610
0
   return 4;
611
0
}
612
613
static int dissect_event_checking_control(packet_info *pinfo _U_, proto_tree *tree, proto_item *item _U_, tvbuff_t *tvb,
614
   int offset, int total_len _U_)
615
0
{
616
0
   static int* const bits[] = {
617
0
      &hf_cip_evnt_ctrl_reg1_pos,
618
0
      &hf_cip_evnt_ctrl_reg1_neg,
619
0
      &hf_cip_evnt_ctrl_reg2_pos,
620
0
      &hf_cip_evnt_ctrl_reg2_neg,
621
0
      &hf_cip_evnt_ctrl_reg1_posrearm,
622
0
      &hf_cip_evnt_ctrl_reg1_negrearm,
623
0
      &hf_cip_evnt_ctrl_reg2_posrearm,
624
0
      &hf_cip_evnt_ctrl_reg2_negrearm,
625
0
      &hf_cip_evnt_ctrl_marker_pos,
626
0
      &hf_cip_evnt_ctrl_marker_neg,
627
0
      &hf_cip_evnt_ctrl_home_pos,
628
0
      &hf_cip_evnt_ctrl_home_neg,
629
0
      &hf_cip_evnt_ctrl_home_pp,
630
0
      &hf_cip_evnt_ctrl_home_pm,
631
0
      &hf_cip_evnt_ctrl_home_mp,
632
0
      &hf_cip_evnt_ctrl_home_mm,
633
0
      &hf_cip_evnt_ctrl_acks,
634
      // The dissector will indicate if the protocol is requesting an extended event format but will not dissect it.
635
0
      &hf_cip_evnt_extend_format,
636
0
      NULL
637
0
   };
638
639
0
   proto_tree_add_bitmask(tree, tvb, offset, hf_cip_event_checking, ett_event_check_ctrl, bits, ENC_LITTLE_ENDIAN);
640
641
0
   return 4;
642
0
}
643
644
static int dissect_event_checking_status(packet_info *pinfo _U_, proto_tree *tree, proto_item *item _U_, tvbuff_t *tvb,
645
   int offset, int total_len _U_)
646
0
{
647
0
   static int* const bits[] = {
648
0
      &hf_cip_evnt_sts_reg1_pos,
649
0
      &hf_cip_evnt_sts_reg1_neg,
650
0
      &hf_cip_evnt_sts_reg2_pos,
651
0
      &hf_cip_evnt_sts_reg2_neg,
652
0
      &hf_cip_evnt_sts_reg1_posrearm,
653
0
      &hf_cip_evnt_sts_reg1_negrearm,
654
0
      &hf_cip_evnt_sts_reg2_posrearm,
655
0
      &hf_cip_evnt_sts_reg2_negrearm,
656
0
      &hf_cip_evnt_sts_marker_pos,
657
0
      &hf_cip_evnt_sts_marker_neg,
658
0
      &hf_cip_evnt_sts_home_pos,
659
0
      &hf_cip_evnt_sts_home_neg,
660
0
      &hf_cip_evnt_sts_home_pp,
661
0
      &hf_cip_evnt_sts_home_pm,
662
0
      &hf_cip_evnt_sts_home_mp,
663
0
      &hf_cip_evnt_sts_home_mm,
664
0
      &hf_cip_evnt_sts_nfs,
665
      // The dissector will indicate if the protocol is requesting an extended event format but will not dissect it.
666
0
      &hf_cip_evnt_extend_format,
667
0
      NULL
668
0
   };
669
670
0
   proto_tree_add_bitmask(tree, tvb, offset, hf_cip_event_status, ett_event_check_sts, bits, ENC_LITTLE_ENDIAN);
671
672
0
   return 4;
673
0
}
674
675
static int dissect_actual_data_set_bits(packet_info *pinfo _U_, proto_tree *tree, proto_item *item _U_, tvbuff_t *tvb,
676
   int offset, int total_len _U_)
677
0
{
678
0
   static int* const bits[] = {
679
0
      &hf_cip_act_data_pos,
680
0
      &hf_cip_act_data_vel,
681
0
      &hf_cip_act_data_acc,
682
0
      &hf_cip_act_unwind_cycle_count,
683
0
      &hf_cip_act_pos_displacement,
684
0
      NULL
685
0
   };
686
687
0
   proto_tree_add_bitmask(tree, tvb, offset, hf_cip_act_data_set, ett_actual_data_set, bits, ENC_LITTLE_ENDIAN);
688
689
0
   return 1;
690
0
}
691
692
static int dissect_command_data_set_bits(packet_info *pinfo _U_, proto_tree *tree, proto_item *item _U_, tvbuff_t *tvb,
693
   int offset, int total_len _U_)
694
0
{
695
0
   static int* const bits[] = {
696
0
      &hf_cip_cmd_data_pos_cmd,
697
0
      &hf_cip_cmd_data_vel_cmd,
698
0
      &hf_cip_cmd_data_acc_cmd,
699
0
      &hf_cip_cmd_data_trq_cmd,
700
0
      &hf_cip_cmd_data_unwind_cycle_count,
701
0
      &hf_cip_cmd_data_pos_displacement,
702
0
      NULL
703
0
   };
704
705
0
   proto_tree_add_bitmask(tree, tvb, offset, hf_cip_cmd_data_set, ett_command_data_set, bits, ENC_LITTLE_ENDIAN);
706
707
0
   return 1;
708
0
}
709
710
static int dissect_command_control(packet_info *pinfo _U_, proto_tree *tree, proto_item *item _U_, tvbuff_t *tvb,
711
   int offset, int total_len _U_)
712
0
{
713
0
   static int* const bits[] = {
714
0
      &hf_cip_intrp,
715
0
      &hf_cip_position_data_type,
716
0
      NULL
717
0
   };
718
719
0
   proto_tree_add_bitmask(tree, tvb, offset, hf_cip_command_control, ett_command_control, bits, ENC_LITTLE_ENDIAN);
720
721
0
   return 1;
722
0
}
723
724
static int dissect_status_data_set_bits(packet_info *pinfo _U_, proto_tree *tree, proto_item *item _U_, tvbuff_t *tvb,
725
   int offset, int total_len _U_)
726
0
{
727
0
   static int* const bits[] = {
728
0
      &hf_cip_sts_flt,
729
0
      &hf_cip_sts_alrm,
730
0
      &hf_cip_sts_sts,
731
0
      &hf_cip_sts_iosts,
732
0
      &hf_cip_sts_axis_safety,
733
0
      NULL
734
0
   };
735
736
0
   proto_tree_add_bitmask(tree, tvb, offset, hf_cip_sts_data_set, ett_status_data_set, bits, ENC_LITTLE_ENDIAN);
737
738
0
   return 1;
739
0
}
740
741
static int dissect_node_control(packet_info *pinfo _U_, proto_tree *tree, proto_item *item _U_, tvbuff_t *tvb,
742
   int offset, int total_len _U_)
743
0
{
744
0
   static int* const bits[] = {
745
0
      &hf_cip_node_control_remote,
746
0
      &hf_cip_node_control_sync,
747
0
      &hf_cip_node_data_valid,
748
0
      &hf_cip_node_fault_reset,
749
0
      NULL
750
0
   };
751
752
0
   proto_tree_add_bitmask(tree, tvb, offset, hf_cip_node_control, ett_node_control, bits, ENC_LITTLE_ENDIAN);
753
754
0
   return 1;
755
0
}
756
757
static int dissect_node_status(packet_info *pinfo _U_, proto_tree *tree, proto_item *item _U_, tvbuff_t *tvb,
758
   int offset, int total_len _U_)
759
0
{
760
0
   static int* const bits[] = {
761
0
      &hf_cip_node_control_remote,
762
0
      &hf_cip_node_control_sync,
763
0
      &hf_cip_node_data_valid,
764
0
      &hf_cip_node_device_faulted,
765
0
      NULL
766
0
   };
767
768
0
   proto_tree_add_bitmask(tree, tvb, offset, hf_cip_node_status, ett_node_status, bits, ENC_LITTLE_ENDIAN);
769
770
0
   return 1;
771
0
}
772
773
static int dissect_time_data_set(packet_info *pinfo _U_, proto_tree *tree, proto_item *item _U_, tvbuff_t *tvb,
774
   int offset, int total_len _U_)
775
0
{
776
0
   static int* const bits[] = {
777
0
      &hf_cip_time_data_stamp,
778
0
      &hf_cip_time_data_offset,
779
0
      &hf_cip_time_data_diag,
780
0
      &hf_cip_time_data_time_diag,
781
0
      NULL
782
0
   };
783
784
0
   proto_tree_add_bitmask(tree, tvb, offset, hf_cip_time_data_set, ett_time_data_set, bits, ENC_LITTLE_ENDIAN);
785
786
0
   return 1;
787
0
}
788
789
static int dissect_control_status(packet_info *pinfo _U_, proto_tree *tree, proto_item *item _U_, tvbuff_t *tvb,
790
   int offset, int total_len _U_)
791
0
{
792
0
   static int* const bits[] = {
793
0
      &hf_cip_control_status_complete,
794
0
      &hf_cip_control_status_bus_up,
795
0
      &hf_cip_control_status_bus_unload,
796
0
      &hf_cip_control_status_power_loss,
797
0
      NULL
798
0
   };
799
800
0
   proto_tree_add_bitmask(tree, tvb, offset, hf_cip_control_status, ett_control_status, bits, ENC_LITTLE_ENDIAN);
801
802
0
   return 1;
803
0
}
804
805
static int dissect_feedback_mode(packet_info *pinfo _U_, proto_tree *tree, proto_item *item _U_, tvbuff_t *tvb,
806
   int offset, int total_len _U_)
807
0
{
808
0
   static int* const bits[] = {
809
0
      &hf_cip_feedback_mode,
810
0
      &hf_cip_feedback_data_type,
811
0
      NULL
812
0
   };
813
814
0
   proto_tree_add_bitmask(tree, tvb, offset, hf_cip_feedback, ett_feedback_mode, bits, ENC_LITTLE_ENDIAN);
815
816
0
   return 1;
817
0
}
818
819
static int dissect_connection_configuration_bits(packet_info* pinfo _U_, proto_tree* tree, proto_item* item _U_, tvbuff_t* tvb,
820
   int offset, int total_len _U_)
821
0
{
822
0
   static int* const bits[] = {
823
0
      &hf_connection_configuration_bits_power,
824
0
      &hf_connection_configuration_bits_safety_bit_valid,
825
0
      &hf_connection_configuration_bits_allow_network_safety,
826
0
      NULL
827
0
   };
828
829
0
   proto_tree_add_bitmask(tree, tvb, offset, hf_connection_configuration_bits, ett_connection_configuration_bits, bits, ENC_LITTLE_ENDIAN);
830
831
0
   return 1;
832
0
}
833
834
const attribute_info_t cip_motion_attribute_vals[] = {
835
   { CI_CLS_MOTION, CIP_ATTR_CLASS, 14, -1, "Node Control", cip_dissector_func, NULL, dissect_node_control },
836
   { CI_CLS_MOTION, CIP_ATTR_CLASS, 15, -1, "Node Status", cip_dissector_func, NULL, dissect_node_status },
837
   { CI_CLS_MOTION, CIP_ATTR_CLASS, 21, -1, "Controller Update Delay High Limit", cip_usint, &hf_cip_controller_update_delay_high_limit, NULL },
838
   { CI_CLS_MOTION, CIP_ATTR_CLASS, 22, -1, "Controller Update Delay Low Limit", cip_usint, &hf_cip_controller_update_delay_low_limit, NULL },
839
   { CI_CLS_MOTION, CIP_ATTR_CLASS, 29, -1, "Sync Threshold", cip_udint, &hf_cip_sync_threshold, NULL },
840
   { CI_CLS_MOTION, CIP_ATTR_CLASS, 31, -1, "Time Data Set", cip_dissector_func, NULL, dissect_time_data_set },
841
   { CI_CLS_MOTION, CIP_ATTR_CLASS, 34, -1, "Drive Power Structure Class ID", cip_udint, &hf_configuration_block_drive_power_struct_id, NULL },
842
   { CI_CLS_MOTION, CIP_ATTR_CLASS, 35, -1, "Step Threshold", cip_udint, &hf_cip_step_threshold, NULL },
843
   { CI_CLS_MOTION, CIP_ATTR_CLASS, 36, -1, "Connection Configuration Bits", cip_dissector_func, NULL, dissect_connection_configuration_bits },
844
   { CI_CLS_MOTION, CIP_ATTR_INSTANCE, 40, -1, "Control Mode", cip_usint, &hf_cip_motor_cntrl, NULL },
845
   { CI_CLS_MOTION, CIP_ATTR_INSTANCE, 41, -1, "Control Method", cip_usint, &hf_cip_control_method, NULL },
846
   { CI_CLS_MOTION, CIP_ATTR_INSTANCE, 42, -1, "Feedback Mode", cip_dissector_func, NULL, dissect_feedback_mode },
847
   { CI_CLS_MOTION, CIP_ATTR_INSTANCE, 44, -1, "Feedback Unit Ratio", cip_real, &hf_cip_feedback_unit_ratio, NULL },
848
   { CI_CLS_MOTION, CIP_ATTR_INSTANCE, 60, -1, "Event Checking Control", cip_dissector_func, NULL, dissect_event_checking_control },
849
   { CI_CLS_MOTION, CIP_ATTR_INSTANCE, 61, -1, "Event Checking Status", cip_dissector_func, NULL, dissect_event_checking_status },
850
   { CI_CLS_MOTION, CIP_ATTR_INSTANCE, 89, -1, "Control Status", cip_dissector_func, NULL, dissect_control_status },
851
   { CI_CLS_MOTION, CIP_ATTR_INSTANCE, 90, -1, "Actual Data Set", cip_dissector_func, NULL, dissect_actual_data_set_bits },
852
   { CI_CLS_MOTION, CIP_ATTR_INSTANCE, 91, -1, "Command Data Set", cip_dissector_func, NULL, dissect_command_data_set_bits },
853
   { CI_CLS_MOTION, CIP_ATTR_INSTANCE, 92, -1, "Command Control", cip_dissector_func, NULL, dissect_command_control },
854
   { CI_CLS_MOTION, CIP_ATTR_INSTANCE, 94, -1, "Status Data Set", cip_dissector_func, NULL, dissect_status_data_set_bits },
855
   { CI_CLS_MOTION, CIP_ATTR_INSTANCE, 431, -1, "Position Trim", cip_dint, &hf_cip_pos_trim, NULL },
856
   { CI_CLS_MOTION, CIP_ATTR_INSTANCE, 451, -1, "Velocity Trim", cip_real, &hf_cip_vel_trim, NULL },
857
   { CI_CLS_MOTION, CIP_ATTR_INSTANCE, 470, -1, "Velocity Threshold", cip_real, &hf_cip_velocity_threshold, NULL },
858
   { CI_CLS_MOTION, CIP_ATTR_INSTANCE, 471, -1, "Velocity Lock Tolerance", cip_real, &hf_cip_velocity_lock_tolerance, NULL },
859
   { CI_CLS_MOTION, CIP_ATTR_INSTANCE, 472, -1, "Velocity Standstill Window", cip_real, &hf_cip_velocity_standstill_window, NULL },
860
   { CI_CLS_MOTION, CIP_ATTR_INSTANCE, 481, -1, "Acceleration Trim", cip_real, &hf_cip_accel_trim, NULL },
861
   { CI_CLS_MOTION, CIP_ATTR_INSTANCE, 491, -1, "Torque Trim", cip_real, &hf_cip_trq_trim, NULL },
862
   { CI_CLS_MOTION, CIP_ATTR_INSTANCE, 590, -1, "Proving Configuration", cip_usint, &hf_cip_proving_configuration, NULL },
863
   { CI_CLS_MOTION, CIP_ATTR_INSTANCE, 591, -1, "Torque Prove Current", cip_real, &hf_cip_torque_prove_current, NULL },
864
   { CI_CLS_MOTION, CIP_ATTR_INSTANCE, 592, -1, "Brake Test Torque", cip_real, &hf_cip_brake_test_torque, NULL },
865
   { CI_CLS_MOTION, CIP_ATTR_INSTANCE, 608, -1, "Zero Speed", cip_real, &hf_cip_zero_speed, NULL },
866
   { CI_CLS_MOTION, CIP_ATTR_INSTANCE, 609, -1, "Zero Speed Time", cip_real, &hf_cip_zero_speed_time, NULL },
867
   { CI_CLS_MOTION, CIP_ATTR_INSTANCE, 620, -1, "DC Bus Voltage", cip_real, &hf_cip_dc_bus_voltage, NULL },
868
   { CI_CLS_MOTION, CIP_ATTR_INSTANCE, 624, -1, "Bus Regulator Action", cip_usint, &hf_cip_bus_regulator_action, NULL },
869
   { CI_CLS_MOTION, CIP_ATTR_INSTANCE, 636, -1, "Inverter Capacity", cip_real, &hf_cip_inverter_capacity, NULL },
870
   { CI_CLS_MOTION, CIP_ATTR_INSTANCE, 651, -1, "Axis Status", cip_dissector_func, NULL, dissect_axis_status },
871
   { CI_CLS_MOTION, CIP_ATTR_INSTANCE, 701, -1, "Converter Thermal Overload User Limit", cip_real, &hf_cip_converter_thermal_overload_user_limit, NULL },
872
   { CI_CLS_MOTION, CIP_ATTR_INSTANCE, 705, -1, "Bus Undervoltage User Limit", cip_real, &hf_cip_bus_undervoltage_user_limit, NULL },
873
   { CI_CLS_MOTION, CIP_ATTR_INSTANCE, 740, -1, "Axis Status 2", cip_dissector_func, NULL, dissect_axis_status2 },
874
   { CI_CLS_MOTION, CIP_ATTR_INSTANCE, 1329, -1, "Rotary Motor Poles", cip_uint, &hf_cip_rotary_motor_poles, NULL },
875
   { CI_CLS_MOTION, CIP_ATTR_INSTANCE, 1330, -1, "Rotary Motor Inertia", cip_real, &hf_cip_rotary_motor_inertia, NULL },
876
   { CI_CLS_MOTION, CIP_ATTR_INSTANCE, 1332, -1, "Rotary Motor Max Speed", cip_real, &hf_cip_rotary_motor_max_speed, NULL },
877
};
878
879
/*
880
 * Function name: dissect_cmd_data_set
881
 *
882
 * Purpose: Dissect the "Cyclic Command Data" of a Controller-to-Device format message
883
 *
884
 * Based on the Command Data Set bits of the Cyclic Command Data Block header, display
885
 * any of those command values.
886
 *
887
 * Returns: The number of bytes in the cyclic data used
888
 */
889
static uint32_t
890
dissect_cmd_data_set(uint32_t cmd_data_set, proto_tree* parent_tree, tvbuff_t* tvb, uint32_t offset, bool lreal_pos)
891
0
{
892
   // If no Command Data Set bits are set, then we don't need to display any additional data.
893
0
   if (cmd_data_set == 0)
894
0
   {
895
0
      return 0;
896
0
   }
897
898
0
   uint32_t bytes_used = 0;
899
900
0
   proto_item* item;
901
0
   proto_tree* tree = proto_tree_add_subtree(parent_tree, tvb, offset, 0, ett_cyclic_command_data, &item, "Cyclic Command Data");
902
903
   /* The order of these if statements is VERY important, this is the order the values will
904
    * appear in the cyclic data */
905
0
   if ( (cmd_data_set & COMMAND_DATA_SET_POSITION) == COMMAND_DATA_SET_POSITION )
906
0
   {
907
      /* Based on the Command Position Data Type value embedded in the Command Control
908
      * header field the position is either 64-bit floating or 32-bit integer */
909
0
      if (lreal_pos)
910
0
      {
911
         /* Display the command data set position command value */
912
0
         proto_tree_add_item(tree, hf_cip_pos_cmd, tvb, offset + bytes_used, 8, ENC_LITTLE_ENDIAN );
913
0
         bytes_used += 8;
914
0
      }
915
0
      else
916
0
      {
917
         /* Display the command data set position command value */
918
0
         proto_tree_add_item(tree, hf_cip_pos_cmd_int, tvb, offset + bytes_used, 4, ENC_LITTLE_ENDIAN );
919
0
         bytes_used += 4;
920
0
      }
921
0
   }
922
923
0
   if ( (cmd_data_set & COMMAND_DATA_SET_VELOCITY) == COMMAND_DATA_SET_VELOCITY )
924
0
   {
925
      /* Display the command data set velocity command value */
926
0
      proto_tree_add_item(tree, hf_cip_vel_cmd, tvb, offset + bytes_used, 4, ENC_LITTLE_ENDIAN );
927
0
      bytes_used += 4;
928
0
   }
929
930
0
   if ( (cmd_data_set & COMMAND_DATA_SET_ACCELERATION) == COMMAND_DATA_SET_ACCELERATION )
931
0
   {
932
      /* Display the command data set acceleration command value */
933
0
      proto_tree_add_item(tree, hf_cip_accel_cmd, tvb, offset + bytes_used, 4, ENC_LITTLE_ENDIAN );
934
0
      bytes_used += 4;
935
0
   }
936
937
0
   if ( (cmd_data_set & COMMAND_DATA_SET_TORQUE) == COMMAND_DATA_SET_TORQUE )
938
0
   {
939
      /* Display the command data set torque command value */
940
0
      proto_tree_add_item(tree, hf_cip_trq_cmd, tvb, offset + bytes_used, 4, ENC_LITTLE_ENDIAN );
941
0
      bytes_used += 4;
942
0
   }
943
944
0
   proto_item_set_len(item, bytes_used);
945
946
0
   return bytes_used;
947
0
}
948
949
950
/*
951
 * Function name: dissect_act_data_set
952
 *
953
 * Purpose: Dissect the "Cyclic Actual Data" of a Device-to-Controller format message
954
 *
955
 * Based on the Actual Data Set bits of the "Cyclic Actual Data Block" header, display
956
 * any of those feedback values.
957
 *
958
 * Returns: The number of bytes in the cyclic data used
959
 */
960
static uint32_t
961
dissect_act_data_set(uint32_t act_data_set, proto_tree* parent_tree, tvbuff_t* tvb, uint32_t offset, uint8_t feedback_mode)
962
0
{
963
   // If no Actual Data Set bits are set, then we don't need to display any additional data.
964
0
   if (act_data_set == 0)
965
0
   {
966
0
      return 0;
967
0
   }
968
969
0
   uint32_t bytes_used = 0;
970
971
0
   proto_item* item;
972
0
   proto_tree* tree = proto_tree_add_subtree(parent_tree, tvb, offset, 0, ett_cyclic_command_data, &item, "Cyclic Actual Data");
973
974
   /* The order of these if statements is VERY important, this is the order the values will
975
   * appear in the cyclic data */
976
0
   if ( (act_data_set & ACTUAL_DATA_SET_POSITION) == ACTUAL_DATA_SET_POSITION )
977
0
   {
978
      /* Display the actual data set position feedback value in either 32 or 64 bit */
979
0
      bool is_64_bit_position = (feedback_mode & FEEDBACK_DATA_TYPE_BITS) == 0x10;
980
0
      if (is_64_bit_position)
981
0
      {
982
0
         proto_tree_add_item(tree, hf_cip_act_pos_64, tvb, offset + bytes_used, 8, ENC_LITTLE_ENDIAN);
983
0
         bytes_used += 8;
984
0
      }
985
0
      else
986
0
      {
987
0
         proto_tree_add_item(tree, hf_cip_act_pos, tvb, offset + bytes_used, 4, ENC_LITTLE_ENDIAN);
988
0
         bytes_used += 4;
989
0
      }
990
0
   }
991
992
0
   if ( (act_data_set & ACTUAL_DATA_SET_VELOCITY) == ACTUAL_DATA_SET_VELOCITY )
993
0
   {
994
      /* Display the actual data set velocity feedback value */
995
0
      proto_tree_add_item(tree, hf_cip_act_vel, tvb, offset + bytes_used, 4, ENC_LITTLE_ENDIAN );
996
0
      bytes_used += 4;
997
0
   }
998
999
0
   if ( (act_data_set & ACTUAL_DATA_SET_ACCELERATION) == ACTUAL_DATA_SET_ACCELERATION )
1000
0
   {
1001
      /* Display the actual data set acceleration feedback value */
1002
0
      proto_tree_add_item(tree, hf_cip_act_accel, tvb, offset + bytes_used, 4, ENC_LITTLE_ENDIAN );
1003
0
      bytes_used += 4;
1004
0
   }
1005
1006
1007
0
   proto_item_set_len(item, bytes_used);
1008
1009
0
   return bytes_used;
1010
0
}
1011
1012
/*
1013
 * Function name: dissect_status_data_set
1014
 *
1015
 * Purpose: Dissect the "Cyclic Status Data" of a Device-to-Controller format message
1016
 *
1017
 * Based on the Status Data Set bits of the "Cyclic Actual Data Block" header, display
1018
 * any of those status values.
1019
 *
1020
 * Returns: The number of bytes in the cyclic data used
1021
 */
1022
static uint32_t
1023
dissect_status_data_set(uint32_t status_data_set, proto_tree* parent_tree, tvbuff_t* tvb, uint32_t offset)
1024
0
{
1025
   // If no Status Data Set bits are set, then we don't need to display any additional data.
1026
0
   if (status_data_set == 0)
1027
0
   {
1028
0
      return 0;
1029
0
   }
1030
1031
0
   uint32_t bytes_used = 0;
1032
1033
0
   proto_item* item;
1034
0
   proto_tree* tree = proto_tree_add_subtree(parent_tree, tvb, offset, 0, ett_cyclic_command_data, &item, "Cyclic Status Data");
1035
1036
   /* The order of these if statements is VERY important, this is the order the values will
1037
    * appear in the cyclic data */
1038
0
   if ( (status_data_set & STATUS_DATA_SET_AXIS_FAULT) == STATUS_DATA_SET_AXIS_FAULT )
1039
0
   {
1040
      /* Display the various fault codes from the device */
1041
0
      proto_tree_add_item(tree, hf_cip_fault_type, tvb, offset + bytes_used, 1, ENC_LITTLE_ENDIAN);
1042
0
      bytes_used += 1;
1043
1044
0
      proto_tree_add_item(tree, hf_cip_axis_fault, tvb, offset + bytes_used, 1, ENC_LITTLE_ENDIAN);
1045
0
      bytes_used += 1;
1046
1047
0
      proto_tree_add_item(tree, hf_cip_fault_sub_code, tvb, offset + bytes_used, 1, ENC_LITTLE_ENDIAN);
1048
0
      bytes_used += 1;
1049
1050
0
      proto_tree_add_item(tree, hf_cip_fault_action, tvb, offset + bytes_used, 1, ENC_LITTLE_ENDIAN);
1051
0
      bytes_used += 1;
1052
1053
0
      proto_tree_add_item(tree, hf_cip_fault_time_stamp, tvb, offset + bytes_used, 8, ENC_LITTLE_ENDIAN);
1054
0
      bytes_used += 8;
1055
0
   }
1056
1057
0
   if ( (status_data_set & STATUS_DATA_SET_AXIS_ALARM) == STATUS_DATA_SET_AXIS_ALARM )
1058
0
   {
1059
      /* Display the various alarm codes from the device */
1060
0
      proto_tree_add_item(tree, hf_cip_alarm_type, tvb, offset + bytes_used, 1, ENC_LITTLE_ENDIAN);
1061
0
      bytes_used += 1;
1062
1063
0
      proto_tree_add_item(tree, hf_cip_axis_alarm, tvb, offset + bytes_used, 1, ENC_LITTLE_ENDIAN);
1064
0
      bytes_used += 1;
1065
1066
0
      proto_tree_add_item(tree, hf_cip_alarm_sub_code, tvb, offset + bytes_used, 1, ENC_LITTLE_ENDIAN);
1067
0
      bytes_used += 1;
1068
1069
0
      proto_tree_add_item(tree, hf_cip_alarm_state, tvb, offset + bytes_used, 1, ENC_LITTLE_ENDIAN);
1070
0
      bytes_used += 1;
1071
1072
0
      proto_tree_add_item(tree, hf_cip_alarm_time_stamp, tvb, offset + bytes_used, 8, ENC_LITTLE_ENDIAN);
1073
0
      bytes_used += 8;
1074
0
   }
1075
1076
0
   if ( (status_data_set & STATUS_DATA_SET_AXIS_STATUS) == STATUS_DATA_SET_AXIS_STATUS )
1077
0
   {
1078
      /* Display the various axis state values from the device */
1079
0
      bytes_used += dissect_axis_status(NULL, tree, NULL, tvb, offset + bytes_used, 4);
1080
1081
0
      proto_tree_add_item(tree, hf_cip_axis_status_mfg, tvb, offset + bytes_used, 4, ENC_LITTLE_ENDIAN);
1082
0
      bytes_used += 4;
1083
0
   }
1084
1085
0
   if ( (status_data_set & STATUS_DATA_SET_AXIS_IO_STATUS) == STATUS_DATA_SET_AXIS_IO_STATUS )
1086
0
   {
1087
0
      proto_tree_add_item(tree, hf_cip_axis_io_status, tvb, offset + bytes_used, 4, ENC_LITTLE_ENDIAN);
1088
0
      bytes_used += 4;
1089
1090
0
      proto_tree_add_item(tree, hf_cip_axis_io_status_mfg, tvb, offset + bytes_used, 4, ENC_LITTLE_ENDIAN);
1091
0
      bytes_used += 4;
1092
0
   }
1093
1094
0
   if ( (status_data_set & STATUS_DATA_SET_AXIS_SAFETY) == STATUS_DATA_SET_AXIS_SAFETY )
1095
0
   {
1096
0
      proto_tree_add_item(tree, hf_cip_axis_safety_status, tvb, offset + bytes_used, 4, ENC_LITTLE_ENDIAN);
1097
0
      bytes_used += 4;
1098
0
      proto_tree_add_item(tree, hf_cip_axis_safety_status_mfg, tvb, offset + bytes_used, 4, ENC_LITTLE_ENDIAN);
1099
0
      bytes_used += 4;
1100
0
      proto_tree_add_item(tree, hf_cip_axis_safety_state, tvb, offset + bytes_used, 1, ENC_LITTLE_ENDIAN);
1101
0
      bytes_used += 4;
1102
0
   }
1103
1104
0
   proto_item_set_len(item, bytes_used);
1105
1106
0
   return bytes_used;
1107
0
}
1108
1109
/*
1110
 * Function name: dissect_cntr_cyclic
1111
 *
1112
 * Purpose: Dissect the "Cyclic Command Data Block" of a Controller-to-Device format message
1113
 *
1114
 * Returns: The new offset into the message that follow on dissections should use
1115
 * as their starting offset
1116
 */
1117
static uint32_t
1118
dissect_cntr_cyclic(tvbuff_t* tvb, proto_tree* tree, uint32_t offset, uint32_t size)
1119
0
{
1120
   /* Create the tree for the entire instance data header */
1121
0
   proto_tree* header_tree = proto_tree_add_subtree(tree, tvb, offset, size, ett_cyclic_data_block, NULL, "Cyclic Command Data Block");
1122
1123
0
   proto_tree_add_item(header_tree, hf_cip_motor_cntrl, tvb, offset, 1, ENC_LITTLE_ENDIAN);
1124
0
   dissect_feedback_mode(NULL, header_tree, NULL, tvb, offset + 1, 1);
1125
0
   proto_tree_add_item(header_tree, hf_cip_axis_control, tvb, offset + 2, 1, ENC_LITTLE_ENDIAN);
1126
0
   dissect_control_status(NULL, header_tree, NULL, tvb, offset + 3, 1);
1127
1128
0
   dissect_command_data_set_bits(NULL, header_tree, NULL, tvb, offset + 4, 1);
1129
0
   dissect_actual_data_set_bits(NULL, header_tree, NULL, tvb, offset + 5, 1);
1130
0
   dissect_status_data_set_bits(NULL, header_tree, NULL, tvb, offset + 6, 1);
1131
0
   dissect_command_control(NULL, header_tree, NULL, tvb, offset + 7, 1);
1132
1133
0
   uint32_t bytes_used = 8;
1134
1135
   /* Determine if the dissector should be using an LREAL or DINT for position */
1136
0
   uint8_t command_control = tvb_get_uint8(tvb, offset + 7);
1137
0
   bool lreal_pos = ((command_control & COMMAND_CONTROL_POSITION_DATA_TYPE) == POSITION_DATA_LREAL);
1138
1139
   /* Cyclic Command Data: Display the command data values from the cyclic data payload, the
1140
    * cyclic data starts immediately after the interpolation control field in the controller to device
1141
    * direction */
1142
0
   uint32_t command_data_set = tvb_get_uint8(tvb, offset + 4);
1143
0
   bytes_used += dissect_cmd_data_set(command_data_set, header_tree, tvb, offset + bytes_used, lreal_pos);
1144
1145
   /* Return the offset to the next byte in the message */
1146
0
   return offset + bytes_used;
1147
0
}
1148
1149
/*
1150
 * Function name: dissect_device_cyclic
1151
 *
1152
 * Purpose: Dissect the "Cyclic Actual Data Block" of a Device-to-Controller format message
1153
 *
1154
 * Returns: The new offset into the message that follow on dissections should use
1155
 * as their starting offset
1156
 */
1157
static uint32_t
1158
dissect_device_cyclic(tvbuff_t* tvb, proto_tree* tree, uint32_t offset, uint32_t size)
1159
0
{
1160
   /* Create the tree for the entire instance data header */
1161
0
   proto_tree* header_tree = proto_tree_add_subtree(tree, tvb, offset, size, ett_cyclic_data_block, NULL, "Cyclic Actual Data Block");
1162
1163
0
   proto_tree_add_item(header_tree, hf_cip_motor_cntrl, tvb, offset, 1, ENC_LITTLE_ENDIAN);
1164
0
   dissect_feedback_mode(NULL, header_tree, NULL, tvb, offset + 1, 1);
1165
0
   proto_tree_add_item(header_tree, hf_cip_axis_response, tvb, offset + 2, 1, ENC_LITTLE_ENDIAN);
1166
0
   proto_tree_add_item(header_tree, hf_cip_axis_resp_stat, tvb, offset + 3, 1, ENC_LITTLE_ENDIAN);
1167
1168
0
   dissect_actual_data_set_bits(NULL, header_tree, NULL, tvb, offset + 5, 1);
1169
0
   dissect_status_data_set_bits(NULL, header_tree, NULL, tvb, offset + 6, 1);
1170
0
   proto_tree_add_item(header_tree, hf_cip_axis_state, tvb, offset + 7, 1, ENC_LITTLE_ENDIAN);
1171
1172
0
   uint32_t bytes_used = 8;
1173
1174
   /* Display the "Cyclic Actual Data" values from the cyclic data payload. */
1175
0
   uint8_t feedback_mode = tvb_get_uint8(tvb, offset + 1);
1176
0
   uint8_t actual_data_set = tvb_get_uint8(tvb, offset + 5);
1177
0
   bytes_used += dissect_act_data_set(actual_data_set, header_tree, tvb, offset + bytes_used, feedback_mode);
1178
1179
   /* Display the "Cyclic Status Data" values from the cyclic data payload. */
1180
0
   uint8_t status_data_set = tvb_get_uint8(tvb, offset + 6);
1181
0
   bytes_used += dissect_status_data_set(status_data_set, header_tree, tvb, offset + bytes_used);
1182
1183
   /* Return the offset to the next byte in the message */
1184
0
   return offset + bytes_used;
1185
0
}
1186
1187
/*
1188
 * Function name: dissect_cyclic_wt
1189
 *
1190
 * Purpose: Dissect the "Cyclic Write Data Block" in a Controller-to-Device message
1191
 *
1192
 * Returns: The new offset into the message that follow on dissections should use
1193
 * as their starting offset
1194
 */
1195
static uint32_t
1196
dissect_cyclic_wt(tvbuff_t* tvb, proto_tree* tree, uint32_t offset, uint32_t size)
1197
0
{
1198
0
   proto_tree *header_tree;
1199
1200
   /* Create the tree for the entire cyclic write data block */
1201
0
   header_tree = proto_tree_add_subtree(tree, tvb, offset, size, ett_cyclic_rd_wt, NULL, "Cyclic Write Data Block");
1202
1203
   /* Display the cyclic write block id value */
1204
0
   proto_tree_add_item(header_tree, hf_cip_cyclic_write_blk, tvb, offset, 1, ENC_LITTLE_ENDIAN);
1205
1206
   /* Display the cyclic read block id value */
1207
0
   proto_tree_add_item(header_tree, hf_cip_cyclic_read_blk, tvb, offset + 2, 1, ENC_LITTLE_ENDIAN);
1208
1209
   /* Display the remainder of the cyclic write data if there is any */
1210
0
   if ( size > 4 )
1211
0
   {
1212
0
      proto_tree_add_item(header_tree, hf_cip_cyclic_wrt_data, tvb, offset + 4, size - 4, ENC_NA);
1213
0
   }
1214
1215
0
   return offset + size;
1216
0
}
1217
1218
/*
1219
 * Function name: dissect_cyclic_rd
1220
 *
1221
 * Purpose: Dissect the "Cyclic Read Data Block" in a Device-to-Controller message
1222
 *
1223
 * Returns: The new offset into the message that follow on dissections should use
1224
 * as their starting offset
1225
 */
1226
static uint32_t
1227
dissect_cyclic_rd(tvbuff_t* tvb, proto_tree* tree, uint32_t offset, uint32_t size)
1228
0
{
1229
0
   proto_tree *header_tree;
1230
1231
   /* Create the tree for the entire cyclic write data block */
1232
0
   header_tree = proto_tree_add_subtree(tree, tvb, offset, size, ett_cyclic_rd_wt, NULL, "Cyclic Read Data Block");
1233
1234
   /* Display the cyclic write block id value */
1235
0
   proto_tree_add_item(header_tree, hf_cip_cyclic_write_blk, tvb, offset, 1, ENC_LITTLE_ENDIAN);
1236
1237
   /* Display the cyclic write status value */
1238
0
   proto_tree_add_item(header_tree, hf_cip_cyclic_write_sts, tvb, offset + 1, 1, ENC_LITTLE_ENDIAN);
1239
1240
   /* Display the cyclic read block id value */
1241
0
   proto_tree_add_item(header_tree, hf_cip_cyclic_read_blk, tvb, offset + 2, 1, ENC_LITTLE_ENDIAN);
1242
1243
   /* Display the cyclic read status value */
1244
0
   proto_tree_add_item(header_tree, hf_cip_cyclic_read_sts, tvb, offset + 3, 1, ENC_LITTLE_ENDIAN);
1245
1246
   /* Display the remainder of the cyclic read data if there is any*/
1247
0
   if ( size > 4 )
1248
0
   {
1249
0
      proto_tree_add_item(header_tree, hf_cip_cyclic_rd_data, tvb, offset + 4, size - 4, ENC_NA);
1250
0
   }
1251
1252
0
   return offset + size;
1253
0
}
1254
1255
/*
1256
 * Function name: dissect_cntr_event
1257
 *
1258
 * Purpose: Dissect the "Event Data Block" in a Controller-to-Device message
1259
 *
1260
 * Returns: The new offset into the message that follow on dissections should use
1261
 * as their starting offset
1262
 */
1263
static uint32_t
1264
dissect_cntr_event(tvbuff_t* tvb, proto_tree* tree, uint32_t offset, uint32_t size)
1265
0
{
1266
0
   proto_tree *header_tree;
1267
0
   uint32_t acks, cur_ack;
1268
0
   uint32_t bytes_used = 0;
1269
1270
   /* Create the tree for the entire cyclic write data block */
1271
0
   header_tree = proto_tree_add_subtree(tree, tvb, offset, size, ett_event, NULL, "Event Data Block");
1272
1273
0
   uint32_t event_checking_control = tvb_get_letohl(tvb, offset);
1274
0
   dissect_event_checking_control(NULL, header_tree, NULL, tvb, offset, 4);
1275
1276
   /* The event checking control value is 4 bytes long */
1277
0
   bytes_used = 4;
1278
1279
   /* The final 4 bits of the event checking control value are the number of acknowledgements in the message */
1280
0
   acks = (event_checking_control >> 28) & 0x0F;
1281
1282
   /* Each acknowledgement contains and id and a status value */
1283
0
   for (cur_ack = 0; cur_ack < acks; cur_ack++)
1284
0
   {
1285
     /* Display the current acknowledgement id */
1286
0
     proto_tree_add_item(header_tree, hf_cip_event_ack, tvb, offset + bytes_used, 1, ENC_LITTLE_ENDIAN);
1287
0
     bytes_used += 1;
1288
1289
     /* Display the current event status */
1290
0
     proto_tree_add_item(header_tree, hf_cip_evnt_sts_stat, tvb, offset + bytes_used, 1, ENC_LITTLE_ENDIAN);
1291
0
     bytes_used += 1;
1292
0
   }
1293
1294
0
   return offset + size;
1295
0
}
1296
1297
/*
1298
 * Function name: dissect_devce_event
1299
 *
1300
 * Purpose: Dissect the "Event Data Block" in a Device-to-Controller message
1301
 *
1302
 * Returns: The new offset into the message that follow on dissections should use
1303
 * as their starting offset
1304
 */
1305
static uint32_t
1306
dissect_devce_event(tvbuff_t* tvb, proto_tree* tree, uint32_t offset, uint32_t size)
1307
0
{
1308
0
   proto_tree *header_tree;
1309
0
   uint64_t    nots, cur_not;
1310
0
   uint32_t    bytes_used = 0;
1311
1312
   /* Create the tree for the entire cyclic write data block */
1313
0
   header_tree = proto_tree_add_subtree(tree, tvb, offset, size, ett_event, NULL, "Event Data Block");
1314
1315
0
   uint32_t event_checking_status = tvb_get_letohl(tvb, offset);
1316
0
   dissect_event_checking_status(NULL, header_tree, NULL, tvb, offset, 4);
1317
1318
   /* The event status control value is 4 bytes long */
1319
0
   bytes_used = 4;
1320
1321
   /* The final 4 bits of the event status control value are the number of notifications in the message */
1322
0
   nots = (event_checking_status >> 28) & 0x0F;
1323
1324
   /* Each notification contains and id, status value, event type, position and time stamp */
1325
0
   for (cur_not = 0; cur_not < nots; cur_not++)
1326
0
   {
1327
      /* Display the current event id */
1328
0
      proto_tree_add_item(header_tree, hf_cip_event_id, tvb, offset + bytes_used, 1, ENC_LITTLE_ENDIAN);
1329
0
      bytes_used += 1;
1330
1331
      /* Display the current event status */
1332
0
      proto_tree_add_item(header_tree, hf_cip_evnt_sts_stat, tvb, offset + bytes_used, 1, ENC_LITTLE_ENDIAN);
1333
0
      bytes_used += 1;
1334
1335
      /* Display the current event type */
1336
0
      proto_tree_add_item(header_tree, hf_cip_evnt_type, tvb, offset + bytes_used, 1, ENC_LITTLE_ENDIAN);
1337
0
      bytes_used += 2;    /* Increment by 2 to jump the reserved byte */
1338
1339
      /* Display the event position value */
1340
0
      proto_tree_add_item(header_tree, hf_cip_event_pos, tvb, offset + bytes_used, 4, ENC_LITTLE_ENDIAN);
1341
0
      bytes_used += 4;
1342
1343
      /* Display the event time stamp value */
1344
0
      proto_tree_add_item(header_tree, hf_cip_event_ts, tvb, offset + bytes_used, 8, ENC_LITTLE_ENDIAN);
1345
0
      bytes_used += 8;
1346
0
   }
1347
1348
0
   return size + offset;
1349
0
}
1350
1351
/*
1352
 * Function name: dissect_get_axis_attr_list_request
1353
 *
1354
 * Purpose: Dissect the get axis attribute list service request
1355
 *
1356
 * Returns: None
1357
 */
1358
static void
1359
dissect_get_axis_attr_list_request(tvbuff_t* tvb, proto_tree* tree, uint32_t offset, uint32_t size, uint32_t instance_id)
1360
0
{
1361
0
   proto_item *attr_item;
1362
0
   proto_tree *header_tree, *attr_tree;
1363
0
   uint32_t    local_offset;
1364
1365
   /* Create the tree for the get axis attribute list request */
1366
0
   header_tree = proto_tree_add_subtree(tree, tvb, offset, size, ett_get_axis_attribute, NULL, "Get Axis Attribute List Request");
1367
1368
   /* Read the number of attributes that are contained within the request */
1369
0
   uint32_t attribute_cnt;
1370
0
   proto_tree_add_item_ret_uint(header_tree, hf_get_axis_attr_list_attribute_cnt, tvb, offset, 2, ENC_LITTLE_ENDIAN, &attribute_cnt);
1371
1372
   /* Start the attribute loop at the beginning of the first attribute in the list */
1373
0
   local_offset = offset + 4;
1374
1375
   /* For each attribute display the associated fields */
1376
0
   for (uint32_t attribute = 0; attribute < attribute_cnt; attribute++)
1377
0
   {
1378
      /* At a minimum the local offset needs will need to be incremented by 4 bytes to reach the next attribute */
1379
0
      uint8_t increment_size = 4;
1380
1381
      /* Create the tree for this attribute within the request */
1382
0
      uint32_t attribute_id;
1383
0
      attr_item = proto_tree_add_item_ret_uint(header_tree, hf_get_axis_attr_list_attribute_id, tvb, local_offset, 2, ENC_LITTLE_ENDIAN, &attribute_id);
1384
0
      attr_tree = proto_item_add_subtree(attr_item, ett_get_axis_attr_list);
1385
1386
0
      uint32_t dimension;
1387
0
      proto_tree_add_item_ret_uint(attr_tree, hf_get_axis_attr_list_dimension, tvb, local_offset + 2, 1, ENC_LITTLE_ENDIAN, &dimension);
1388
0
      proto_tree_add_item(attr_tree, hf_get_axis_attr_list_element_size, tvb, local_offset + 3, 1, ENC_LITTLE_ENDIAN);
1389
1390
0
      if (dimension == 1)
1391
0
      {
1392
         /* Display the start index and start index from the request */
1393
0
         proto_tree_add_item(attr_tree, hf_get_axis_attr_list_start_index, tvb, local_offset + 4, 2, ENC_LITTLE_ENDIAN);
1394
0
         proto_tree_add_item(attr_tree, hf_get_axis_attr_list_data_elements, tvb, local_offset + 6, 2, ENC_LITTLE_ENDIAN);
1395
1396
         /* Modify the amount to update the local offset by and the start of the data to include the index and elements field */
1397
0
         increment_size += 4;
1398
0
      }
1399
1400
0
      const attribute_info_t* pattribute = cip_get_attribute(CI_CLS_MOTION, instance_id, attribute_id);
1401
0
      if (pattribute != NULL)
1402
0
      {
1403
0
         proto_item_append_text(attr_item, " (%s)", pattribute->text);
1404
0
      }
1405
1406
      /* Move the local offset to the next attribute */
1407
0
      local_offset += increment_size;
1408
0
   }
1409
0
}
1410
1411
static unsigned dissect_motion_attribute(packet_info *pinfo, tvbuff_t* tvb, int offset, uint32_t attribute_id,
1412
   uint32_t instance_id, proto_item* attr_item, proto_tree* attr_tree, uint8_t dimension, uint32_t attribute_size)
1413
0
{
1414
0
   const attribute_info_t* pattribute = cip_get_attribute(CI_CLS_MOTION, instance_id, attribute_id);
1415
0
   int parsed_len = 0;
1416
1417
0
   if (pattribute != NULL)
1418
0
   {
1419
0
      proto_item_append_text(attr_item, " (%s)", pattribute->text);
1420
1421
      // TODO: Handle more dimensions. Unsure about the format when there is more than 1 item.
1422
0
      if (dimension <= 1)
1423
0
      {
1424
0
         parsed_len = dissect_cip_attribute(pinfo, attr_tree, attr_item, tvb, pattribute, offset, attribute_size);
1425
0
      }
1426
0
   }
1427
1428
0
   return parsed_len;
1429
0
}
1430
1431
/*
1432
 * Function name: dissect_set_axis_attr_list_request
1433
 *
1434
 * Purpose: Dissect the set axis attribute list service request
1435
 *
1436
 * Returns: None
1437
 */
1438
static void
1439
dissect_set_axis_attr_list_request(packet_info *pinfo, tvbuff_t* tvb, proto_tree* tree, uint32_t offset, uint32_t size, uint32_t instance_id)
1440
0
{
1441
0
   proto_item *attr_item;
1442
0
   proto_tree *header_tree, *attr_tree;
1443
0
   uint32_t    local_offset;
1444
1445
   /* Create the tree for the set axis attribute list request */
1446
0
   header_tree = proto_tree_add_subtree(tree, tvb, offset, size, ett_set_axis_attribute, NULL, "Set Axis Attribute List Request");
1447
1448
   /* Read the number of attributes that are contained within the request */
1449
0
   uint32_t attribute_cnt;
1450
0
   proto_tree_add_item_ret_uint(header_tree, hf_set_axis_attr_list_attribute_cnt, tvb, offset, 2, ENC_LITTLE_ENDIAN, &attribute_cnt);
1451
1452
   /* Start the attribute loop at the beginning of the first attribute in the list */
1453
0
   local_offset = offset + 4;
1454
1455
   /* For each attribute display the associated fields */
1456
0
   for (uint32_t attribute = 0; attribute < attribute_cnt; attribute++)
1457
0
   {
1458
      /* At a minimum the local offset needs to be incremented by 4 bytes to reach the next attribute */
1459
0
      uint8_t increment_size = 4;
1460
1461
      /* Pull the fields for this attribute from the payload, all fields are needed to make some calculations before
1462
      *  properly displaying of the attribute is possible */
1463
0
      uint8_t attribute_start = 4;
1464
1465
      /* Create the tree for this attribute in the get axis attribute list request */
1466
0
      uint32_t attribute_id;
1467
0
      attr_item = proto_tree_add_item_ret_uint(header_tree, hf_set_axis_attr_list_attribute_id, tvb, local_offset, 2, ENC_LITTLE_ENDIAN, &attribute_id);
1468
0
      attr_tree = proto_item_add_subtree(attr_item, ett_set_axis_attr_list);
1469
1470
0
      uint32_t dimension;
1471
0
      proto_tree_add_item_ret_uint(attr_tree, hf_set_axis_attr_list_dimension, tvb, local_offset + 2, 1, ENC_LITTLE_ENDIAN, &dimension);
1472
1473
0
      uint32_t attribute_size;
1474
0
      proto_tree_add_item_ret_uint(attr_tree, hf_set_axis_attr_list_element_size, tvb, local_offset + 3, 1, ENC_LITTLE_ENDIAN, &attribute_size);
1475
1476
0
      if (dimension == 1)
1477
0
      {
1478
0
         uint32_t data_elements;
1479
1480
         /* Display the start index and start index from the request if the request is an array */
1481
0
         proto_tree_add_item(attr_tree, hf_set_axis_attr_list_start_index, tvb, local_offset + 4, 2, ENC_LITTLE_ENDIAN);
1482
0
         proto_tree_add_item_ret_uint(attr_tree, hf_set_axis_attr_list_data_elements, tvb, local_offset + 6, 2, ENC_LITTLE_ENDIAN, &data_elements);
1483
1484
         /* Modify the size of the attribute data by the number of elements if the request is an array request */
1485
0
         attribute_size *= data_elements;
1486
1487
         /* Modify the amount to update the local offset by and the start of the data to include the index and elements field */
1488
0
         increment_size  += 4;
1489
0
         attribute_start += 4;
1490
0
      }
1491
1492
0
      unsigned parsed_len = dissect_motion_attribute(pinfo, tvb, local_offset + attribute_start, attribute_id,
1493
0
         instance_id, attr_item, attr_tree, dimension, attribute_size);
1494
1495
      // Display the raw attribute data if configured. Otherwise, just show the remaining unparsed data.
1496
0
      if (display_full_attribute_data)
1497
0
      {
1498
0
         proto_tree_add_item(attr_tree, hf_cip_attribute_data, tvb, local_offset + attribute_start, attribute_size, ENC_NA);
1499
0
      }
1500
0
      else if (attribute_size > parsed_len)
1501
0
      {
1502
0
         proto_tree_add_item(attr_tree, hf_cip_attribute_data, tvb, local_offset + attribute_start + parsed_len, attribute_size - parsed_len, ENC_NA);
1503
0
      }
1504
1505
      /* Round the attribute size up so the next attribute lines up on a 32-bit boundary */
1506
0
      attribute_size = WS_ROUNDUP_4(attribute_size);
1507
1508
      /* Move the local offset to the next attribute */
1509
0
      local_offset += (attribute_size + increment_size);
1510
0
   }
1511
0
}
1512
1513
/*
1514
 * Function name: dissect_group_sync_request
1515
 *
1516
 * Purpose: Dissect the group sync service request
1517
 *
1518
 * Returns: None
1519
 */
1520
static void
1521
dissect_group_sync_request (tvbuff_t* tvb, proto_tree* tree, uint32_t offset, uint32_t size)
1522
0
{
1523
0
   proto_tree *header_tree;
1524
1525
   /* Create the tree for the group sync request */
1526
0
   header_tree = proto_tree_add_subtree(tree, tvb, offset, size, ett_group_sync, NULL, "Group Sync Request");
1527
1528
   /* Read the grandmaster id from the payload */
1529
0
   proto_tree_add_item(header_tree, hf_cip_ptp_grandmaster, tvb, offset, 8, ENC_LITTLE_ENDIAN);
1530
0
}
1531
1532
static void dissect_set_cyclic_list_request(tvbuff_t* tvb, proto_tree* tree, uint32_t offset, uint32_t size, uint32_t instance_id, const char* service_name)
1533
0
{
1534
0
   proto_tree* header_tree = proto_tree_add_subtree(tree, tvb, offset, size, ett_set_cyclic_list, NULL, service_name);
1535
1536
0
   uint32_t attribute_cnt;
1537
0
   proto_tree_add_item_ret_uint(header_tree, hf_set_cyclic_list_attribute_cnt, tvb, offset, 2, ENC_LITTLE_ENDIAN, &attribute_cnt);
1538
1539
   // Skip Number of Attributes and Reserved field.
1540
0
   offset += 4;
1541
1542
0
   for (uint32_t attribute = 0; attribute < attribute_cnt; attribute++)
1543
0
   {
1544
0
      uint32_t attribute_id;
1545
0
      proto_item* attr_item = proto_tree_add_item_ret_uint(header_tree, hf_set_cyclic_list_attribute_id, tvb, offset, 2, ENC_LITTLE_ENDIAN, &attribute_id);
1546
1547
0
      const attribute_info_t* pattribute = cip_get_attribute(CI_CLS_MOTION, instance_id, attribute_id);
1548
0
      if (pattribute != NULL)
1549
0
      {
1550
0
         proto_item_append_text(attr_item, " (%s)", pattribute->text);
1551
0
      }
1552
1553
0
      offset += 2;
1554
0
   }
1555
0
}
1556
1557
static void dissect_set_cyclic_list_respone(tvbuff_t* tvb, proto_tree* tree, uint32_t offset, uint32_t size, uint32_t instance_id, const char* service_name)
1558
0
{
1559
0
   proto_tree* header_tree = proto_tree_add_subtree(tree, tvb, offset, size, ett_set_cyclic_list, NULL, service_name);
1560
1561
0
   uint32_t attribute_cnt;
1562
0
   proto_tree_add_item_ret_uint(header_tree, hf_set_cyclic_list_attribute_cnt, tvb, offset, 2, ENC_LITTLE_ENDIAN, &attribute_cnt);
1563
1564
0
   proto_tree_add_item(header_tree, hf_set_cyclic_list_read_block_id, tvb, offset + 2, 2, ENC_LITTLE_ENDIAN);
1565
1566
   // Skip Number of Attributes and Cyclic Read Block ID field.
1567
0
   offset += 4;
1568
1569
0
   for (uint32_t attribute = 0; attribute < attribute_cnt; attribute++)
1570
0
   {
1571
0
      uint32_t attribute_id;
1572
0
      proto_item* attr_item = proto_tree_add_item_ret_uint(header_tree, hf_set_cyclic_list_attribute_id, tvb, offset, 2, ENC_LITTLE_ENDIAN, &attribute_id);
1573
1574
0
      const attribute_info_t* pattribute = cip_get_attribute(CI_CLS_MOTION, instance_id, attribute_id);
1575
0
      if (pattribute != NULL)
1576
0
      {
1577
0
         proto_item_append_text(attr_item, " (%s)", pattribute->text);
1578
0
      }
1579
1580
0
      offset += 2;
1581
1582
0
      proto_tree_add_item(header_tree, hf_set_cyclic_list_attr_sts, tvb, offset, 1, ENC_LITTLE_ENDIAN);
1583
1584
      // Skip over Attribute Status and Reserved field.
1585
0
      offset += 2;
1586
0
   }
1587
0
}
1588
1589
/*
1590
 * Function name: dissect_cntr_service
1591
 *
1592
 * Purpose: Dissect the "Service Data Block" in a Controller-to-Device message
1593
 *
1594
 * Returns: The new offset into the message that follow on dissections should use
1595
 * as their starting offset
1596
 */
1597
static uint32_t
1598
dissect_cntr_service(tvbuff_t* tvb, packet_info* pinfo, proto_tree* tree, uint32_t offset, uint32_t size, uint32_t instance_id)
1599
0
{
1600
0
   proto_tree *header_tree;
1601
0
   uint32_t     service;
1602
1603
   /* Create the tree for the entire service data block */
1604
0
   proto_item *item;
1605
0
   header_tree = proto_tree_add_subtree(tree, tvb, offset, size, ett_service, &item, "Service Data Block");
1606
1607
   /* Display the transaction id value */
1608
0
   proto_tree_add_item(header_tree, hf_cip_svc_transction, tvb, offset, 1, ENC_LITTLE_ENDIAN);
1609
1610
   /* Display the service code */
1611
0
   proto_tree_add_item_ret_uint(header_tree, hf_cip_svc_code, tvb, offset + 1, 1, ENC_LITTLE_ENDIAN, &service);
1612
1613
   /* If the service is a set axis, get axis attribute or group sync request dissect it as well */
1614
0
   if (size > 4)
1615
0
   {
1616
0
       switch (service)
1617
0
       {
1618
0
       case SC_GET_AXIS_ATTRIBUTE_LIST:
1619
0
           dissect_get_axis_attr_list_request(tvb, header_tree, offset + 4, size - 4, instance_id);
1620
0
           break;
1621
0
       case SC_SET_AXIS_ATTRIBUTE_LIST:
1622
0
           dissect_set_axis_attr_list_request(pinfo, tvb, header_tree, offset + 4, size - 4, instance_id);
1623
0
           break;
1624
0
       case SC_GROUP_SYNC:
1625
0
           dissect_group_sync_request(tvb, header_tree, offset + 4, size - 4);
1626
0
           break;
1627
0
       case SC_SET_CYCLIC_WRITE_LIST:
1628
0
           dissect_set_cyclic_list_request(tvb, header_tree, offset + 4, size - 4, instance_id, "Set Cyclic Write List Request");
1629
0
           break;
1630
0
       case SC_SET_CYCLIC_READ_LIST:
1631
0
           dissect_set_cyclic_list_request(tvb, header_tree, offset + 4, size - 4, instance_id, "Set Cyclic Read List Request");
1632
0
           break;
1633
0
       case SC_SET_ATT_LIST:
1634
0
       {
1635
0
           cip_simple_request_info_t motion_path;
1636
0
           motion_path.iClass = CI_CLS_MOTION;
1637
0
           motion_path.iInstance = instance_id;
1638
1639
0
           tvbuff_t* tvb_set_attr = tvb_new_subset_length(tvb, offset + 4, size - 4);
1640
0
           int parsed_len = dissect_cip_set_attribute_list_req(tvb_set_attr, pinfo, header_tree, item, 0, &motion_path);
1641
1642
           // Display any remaining unparsed data.
1643
0
           int remain_len = tvb_reported_length_remaining(tvb, offset + 4 + parsed_len);
1644
0
           if (remain_len > 0)
1645
0
           {
1646
0
              proto_tree_add_item(header_tree, hf_cip_attribute_data, tvb, offset + 4 + parsed_len, size - 4 - parsed_len, ENC_NA);
1647
0
           }
1648
1649
0
           break;
1650
0
       }
1651
0
       default:
1652
           /* Display the remainder of the service channel data */
1653
0
           proto_tree_add_item(header_tree, hf_cip_svc_data, tvb, offset + 4, size - 4, ENC_NA);
1654
0
       }
1655
0
   }
1656
1657
0
   return offset + size;
1658
0
}
1659
1660
/*
1661
 * Function name: dissect_set_axis_attr_list_response
1662
 *
1663
 * Purpose: Dissect the set axis attribute list service response
1664
 *
1665
 * Returns: None
1666
 */
1667
static void
1668
dissect_set_axis_attr_list_response(tvbuff_t* tvb, proto_tree* tree, uint32_t offset, uint32_t size, uint32_t instance_id)
1669
0
{
1670
0
   proto_item *attr_item;
1671
0
   proto_tree *header_tree, *attr_tree;
1672
0
   uint32_t    local_offset;
1673
1674
   /* Create the tree for the set axis attribute list response */
1675
0
   header_tree = proto_tree_add_subtree(tree, tvb, offset, size, ett_get_axis_attribute, NULL, "Set Axis Attribute List Response");
1676
1677
   /* Read the number of attributes that are contained within the response */
1678
0
   uint32_t attribute_cnt;
1679
0
   proto_tree_add_item_ret_uint(header_tree, hf_set_axis_attr_list_attribute_cnt, tvb, offset, 2, ENC_LITTLE_ENDIAN, &attribute_cnt);
1680
1681
   /* Start the attribute loop at the beginning of the first attribute in the list */
1682
0
   local_offset = offset + 4;
1683
1684
   /* For each attribute display the associated fields */
1685
0
   for (uint32_t attribute = 0; attribute < attribute_cnt; attribute++)
1686
0
   {
1687
      /* Create the tree for the current attribute in the set axis attribute list response */
1688
0
      uint32_t attribute_id;
1689
0
      attr_item = proto_tree_add_item_ret_uint(header_tree, hf_set_axis_attr_list_attribute_id, tvb, local_offset, 2, ENC_LITTLE_ENDIAN, &attribute_id);
1690
0
      attr_tree = proto_item_add_subtree(attr_item, ett_get_axis_attr_list);
1691
1692
      /* Add the response status to the tree */
1693
0
      proto_tree_add_item(attr_tree, hf_cip_svc_set_axis_attr_sts, tvb, local_offset + 2, 1, ENC_LITTLE_ENDIAN);
1694
1695
0
      const attribute_info_t* pattribute = cip_get_attribute(CI_CLS_MOTION, instance_id, attribute_id);
1696
0
      if (pattribute != NULL)
1697
0
      {
1698
0
         proto_item_append_text(attr_item, " (%s)", pattribute->text);
1699
0
      }
1700
1701
      /* Move the local offset to the next attribute */
1702
0
      local_offset += 4;
1703
0
   }
1704
0
}
1705
1706
/*
1707
 * Function name: dissect_get_axis_attr_list_response
1708
 *
1709
 * Purpose: Dissect the get axis attribute list service response
1710
 *
1711
 * Returns: None
1712
 */
1713
static void
1714
dissect_get_axis_attr_list_response(packet_info* pinfo, tvbuff_t* tvb, proto_tree* tree, uint32_t offset, uint32_t size, uint32_t instance_id)
1715
0
{
1716
0
   proto_item *attr_item;
1717
0
   proto_tree *header_tree, *attr_tree;
1718
0
   uint32_t    local_offset;
1719
1720
   /* Create the tree for the get axis attribute list response */
1721
0
   header_tree = proto_tree_add_subtree(tree, tvb, offset, size, ett_get_axis_attribute, NULL, "Get Axis Attribute List Response");
1722
1723
   /* Read the number of attributes that are contained within the request */
1724
0
   uint32_t attribute_cnt;
1725
0
   proto_tree_add_item_ret_uint(header_tree, hf_get_axis_attr_list_attribute_cnt, tvb, offset, 2, ENC_LITTLE_ENDIAN, &attribute_cnt);
1726
1727
   /* Start the attribute loop at the beginning of the first attribute in the list */
1728
0
   local_offset = offset + 4;
1729
1730
   /* For each attribute display the associated fields */
1731
0
   for (uint32_t attribute = 0; attribute < attribute_cnt; attribute++)
1732
0
   {
1733
      /* At a minimum the local offset needs to be incremented by 4 bytes to reach the next attribute */
1734
0
      uint8_t increment_size = 4;
1735
1736
      /* Pull the fields for this attribute from the payload, all fields are needed to make some calculations before
1737
      * properly displaying of the attribute is possible */
1738
0
      uint8_t dimension = tvb_get_uint8(tvb, local_offset + 2);
1739
0
      uint32_t attribute_size = tvb_get_uint8(tvb, local_offset + 3);
1740
0
      uint8_t attribute_start = 4;
1741
1742
0
      if (dimension == 1)
1743
0
      {
1744
0
         uint16_t data_elements = tvb_get_letohs(tvb, local_offset + 6);
1745
1746
         /* Modify the size of the attribute data by the number of elements if the request is an array request */
1747
0
         attribute_size *= data_elements;
1748
1749
         /* Modify the amount to update the local offset by and the start of the data to include the index and elements field */
1750
0
         increment_size  += 4;
1751
0
         attribute_start += 4;
1752
0
      }
1753
1754
      /* Display the fields associated with the get axis attribute list response */
1755
0
      uint32_t attribute_id;
1756
0
      attr_item = proto_tree_add_item_ret_uint(header_tree, hf_get_axis_attr_list_attribute_id, tvb, local_offset, 2, ENC_LITTLE_ENDIAN, &attribute_id);
1757
0
      attr_tree = proto_item_add_subtree(attr_item, ett_get_axis_attr_list);
1758
1759
0
      if (dimension == 0xFF)
1760
0
      {
1761
         /* Display the element size as an error code if the dimension field indicates an error */
1762
0
         proto_tree_add_item(attr_tree, hf_cip_svc_get_axis_attr_sts, tvb, local_offset + 3, 1, ENC_LITTLE_ENDIAN);
1763
1764
         /* No attribute data so no attribute size */
1765
0
         attribute_size = 0;
1766
0
      }
1767
0
      else
1768
0
      {
1769
0
         proto_tree_add_item(attr_tree, hf_get_axis_attr_list_dimension, tvb, local_offset + 2, 1, ENC_LITTLE_ENDIAN);
1770
0
         proto_tree_add_item(attr_tree, hf_get_axis_attr_list_element_size, tvb, local_offset + 3, 1, ENC_LITTLE_ENDIAN);
1771
1772
0
         if (dimension == 1)
1773
0
         {
1774
            /* Display the start index and start index from the request */
1775
0
            proto_tree_add_item(attr_tree, hf_get_axis_attr_list_start_index, tvb, local_offset + 4, 2, ENC_LITTLE_ENDIAN);
1776
0
            proto_tree_add_item(attr_tree, hf_get_axis_attr_list_data_elements, tvb, local_offset + 6, 2, ENC_LITTLE_ENDIAN);
1777
0
         }
1778
1779
0
         unsigned parsed_len = dissect_motion_attribute(pinfo, tvb, local_offset + attribute_start, attribute_id,
1780
0
            instance_id, attr_item, attr_tree, dimension, attribute_size);
1781
1782
         // Display the raw attribute data if configured. Otherwise, just show the remaining unparsed data
1783
0
         if (display_full_attribute_data)
1784
0
         {
1785
0
            proto_tree_add_item(attr_tree, hf_cip_attribute_data, tvb, local_offset + attribute_start, attribute_size, ENC_NA);
1786
0
         }
1787
0
         else if (attribute_size > parsed_len)
1788
0
         {
1789
0
            proto_tree_add_item(attr_tree, hf_cip_attribute_data, tvb, local_offset + attribute_start + parsed_len, attribute_size - parsed_len, ENC_NA);
1790
0
         }
1791
1792
         /* Round the attribute size up so the next attribute lines up on a 32-bit boundary */
1793
0
         attribute_size = WS_ROUNDUP_4(attribute_size);
1794
0
      }
1795
1796
      /* Move the local offset to the next attribute */
1797
0
      local_offset += (attribute_size + increment_size);
1798
0
   }
1799
0
}
1800
1801
/*
1802
 * Function name: dissect_group_sync_response
1803
 *
1804
 * Purpose: Dissect the group sync service response
1805
 *
1806
 * Returns: None
1807
 */
1808
static void
1809
dissect_group_sync_response (tvbuff_t* tvb, proto_tree* tree, uint32_t offset)
1810
0
{
1811
0
   proto_tree_add_item(tree, hf_cip_group_sync, tvb, offset, 1, ENC_LITTLE_ENDIAN);
1812
0
}
1813
1814
/*
1815
 * Function name: dissect_devce_service
1816
 *
1817
 * Purpose: Dissect the "Service Data Block" in a Device-to-Controller message
1818
 *
1819
 * Returns: The new offset into the message that follow on dissections should use
1820
 * as their starting offset
1821
 */
1822
static uint32_t
1823
dissect_devce_service(tvbuff_t* tvb, packet_info* pinfo, proto_tree* tree, uint32_t offset, uint32_t size, uint32_t instance_id)
1824
0
{
1825
0
   proto_tree *header_tree;
1826
1827
   /* Create the tree for the entire service data block */
1828
0
   proto_item* item;
1829
0
   header_tree = proto_tree_add_subtree(tree, tvb, offset, size, ett_service, &item, "Service Data Block");
1830
1831
   /* Display the transaction id value */
1832
0
   proto_tree_add_item(header_tree, hf_cip_svc_transction, tvb, offset, 1, ENC_LITTLE_ENDIAN);
1833
1834
   /* Display the service code */
1835
0
   uint32_t service_code;
1836
0
   proto_tree_add_item_ret_uint(header_tree, hf_cip_svc_code, tvb, offset + 1, 1, ENC_LITTLE_ENDIAN, &service_code);
1837
1838
   /* Display the general status code */
1839
0
   proto_tree_add_item(header_tree, hf_cip_svc_sts, tvb, offset + 2, 1, ENC_LITTLE_ENDIAN);
1840
1841
   /* Display the extended status code */
1842
0
   proto_tree_add_item(header_tree, hf_cip_svc_ext_status, tvb, offset + 3, 1, ENC_LITTLE_ENDIAN);
1843
1844
   /* If the service is a set axis, get axis attribute response or group sync dissect it as well */
1845
0
   if (size > 4)
1846
0
   {
1847
0
       switch (service_code)
1848
0
       {
1849
0
       case SC_GET_AXIS_ATTRIBUTE_LIST:
1850
0
           dissect_get_axis_attr_list_response(pinfo, tvb, header_tree, offset + 4, size - 4, instance_id);
1851
0
           break;
1852
0
       case SC_SET_AXIS_ATTRIBUTE_LIST:
1853
0
           dissect_set_axis_attr_list_response(tvb, header_tree, offset + 4, size - 4, instance_id);
1854
0
           break;
1855
0
       case SC_GROUP_SYNC:
1856
0
           dissect_group_sync_response(tvb, header_tree, offset + 4);
1857
0
           break;
1858
0
       case SC_SET_CYCLIC_WRITE_LIST:
1859
0
          dissect_set_cyclic_list_respone(tvb, header_tree, offset + 4, size - 4, instance_id, "Set Cyclic Write List Response");
1860
0
          break;
1861
0
       case SC_SET_CYCLIC_READ_LIST:
1862
0
          dissect_set_cyclic_list_respone(tvb, header_tree, offset + 4, size - 4, instance_id, "Set Cyclic Read List Response");
1863
0
          break;
1864
0
       case SC_SET_ATT_LIST:
1865
0
       {
1866
0
          cip_simple_request_info_t motion_path;
1867
0
          motion_path.iClass = CI_CLS_MOTION;
1868
0
          motion_path.iInstance = instance_id;
1869
1870
0
          tvbuff_t* tvb_set_attr = tvb_new_subset_length(tvb, offset + 4, size - 4);
1871
0
          dissect_cip_set_attribute_list_rsp(tvb_set_attr, pinfo, header_tree, item, 0, &motion_path);
1872
0
          break;
1873
0
       }
1874
0
       default:
1875
           /* Display the remainder of the service channel data */
1876
0
           proto_tree_add_item(header_tree, hf_cip_svc_data, tvb, offset + 4, size - 4, ENC_NA);
1877
0
           break;
1878
0
       }
1879
0
   }
1880
1881
0
   return offset + size;
1882
0
}
1883
1884
/*
1885
 * Function name: dissect_var_inst_header
1886
 *
1887
 * Purpose: Dissect the instance data header of a variable controller to device or
1888
 * device to controller message
1889
 *
1890
 * Returns: void
1891
 */
1892
static void
1893
dissect_var_inst_header(tvbuff_t* tvb, proto_tree* tree, uint32_t offset, uint8_t* inst_number, uint32_t* cyc_size,
1894
                        uint32_t* cyc_blk_size, uint32_t* evnt_size, uint32_t* servc_size)
1895
0
{
1896
0
   proto_tree *header_tree;
1897
1898
   /* Create the tree for the entire instance data header */
1899
0
   *inst_number = tvb_get_uint8(tvb, offset);
1900
1901
0
   header_tree = proto_tree_add_subtree_format(tree, tvb, offset, 8, ett_inst_data_header, NULL,
1902
0
                                                "Instance Data Header - Instance: %d", *inst_number);
1903
1904
   /* Read the instance number field from the instance data header */
1905
0
   proto_tree_add_item(header_tree, hf_var_devce_instance, tvb, offset, 1, ENC_LITTLE_ENDIAN);
1906
1907
   /* The "size" fields in the instance data block header are all stored as number of 32-bit words the
1908
   * block uses since all blocks should pad up to 32-bits so to convert to bytes each is multiplied by 4 */
1909
1910
   /* Read the instance block size field in bytes from the instance data header */
1911
0
   proto_tree_add_item(header_tree, hf_var_devce_instance_block_size, tvb, offset + 2, 1, ENC_NA);
1912
1913
   /* Read the cyclic block size field in bytes from the instance data header */
1914
0
   proto_tree_add_item(header_tree, hf_var_devce_cyclic_block_size, tvb, offset + 3, 1, ENC_NA);
1915
1916
   /* Read the cyclic command block size field in bytes from the instance data header */
1917
0
   *cyc_size = (tvb_get_uint8(tvb, offset + 4) * 4);
1918
0
   proto_tree_add_item(header_tree, hf_var_devce_cyclic_data_block_size, tvb, offset + 4, 1, ENC_NA);
1919
1920
   /* Read the cyclic write block size field in bytes from the instance data header */
1921
0
   *cyc_blk_size = (tvb_get_uint8(tvb, offset + 5) * 4);
1922
0
   proto_tree_add_item(header_tree, hf_var_devce_cyclic_rw_block_size, tvb, offset + 5, 1, ENC_NA);
1923
1924
   /* Read the event block size in bytes from the instance data header */
1925
0
   *evnt_size = (tvb_get_uint8(tvb, offset + 6) * 4);
1926
0
   proto_tree_add_item(header_tree, hf_var_devce_event_block_size, tvb, offset + 6, 1, ENC_NA);
1927
1928
   /* Read the service block size in bytes from the instance data header */
1929
0
   *servc_size = (tvb_get_uint8(tvb, offset + 7) * 4);
1930
0
   proto_tree_add_item(header_tree, hf_var_devce_service_block_size, tvb, offset + 7, 1, ENC_NA);
1931
0
}
1932
1933
/*
1934
 * Function name: dissect_var_cont_conn_header
1935
 *
1936
 * Purpose: Dissect the connection header of a variable controller to device message
1937
 *
1938
 * Returns: Offset to the start of the instance data block
1939
 */
1940
static uint32_t
1941
dissect_var_cont_conn_header(tvbuff_t* tvb, proto_tree* tree, uint32_t* inst_count, uint32_t offset)
1942
0
{
1943
0
   uint32_t    header_size;
1944
0
   proto_tree *header_tree;
1945
1946
   /* Calculate the header size, start with the basic header size */
1947
0
   header_size = 8;
1948
1949
0
   uint32_t time_data_set = tvb_get_uint8(tvb, offset + 7);
1950
1951
   /* Check the time data set field for enabled bits. If either update period or
1952
   * update time stamp fields are set, bump the header size by the appropriate size */
1953
0
   if ( (time_data_set & TIME_DATA_SET_TIME_STAMP) == TIME_DATA_SET_TIME_STAMP )
1954
0
   {
1955
0
      header_size += 8;
1956
0
   }
1957
0
   if ( (time_data_set & TIME_DATA_SET_TIME_OFFSET) == TIME_DATA_SET_TIME_OFFSET )
1958
0
   {
1959
0
      header_size += 8;
1960
0
   }
1961
1962
   /* Create the tree for the entire connection header */
1963
0
   header_tree = proto_tree_add_subtree(tree, tvb, offset, header_size, ett_cont_dev_header, NULL, "Connection Header");
1964
1965
   /* Add the connection header fields that are common to all types of messages */
1966
0
   proto_tree_add_item(header_tree, hf_cip_format,   tvb, offset, 1, ENC_LITTLE_ENDIAN);
1967
0
   proto_tree_add_item(header_tree, hf_cip_revision, tvb, offset + 1, 1, ENC_LITTLE_ENDIAN);
1968
0
   proto_tree_add_item(header_tree, hf_cip_updateid, tvb, offset + 2, 1, ENC_LITTLE_ENDIAN);
1969
1970
0
   dissect_node_control(NULL, header_tree, NULL, tvb, offset + 3, 1);
1971
1972
   /* Add the instance count and last update id to the connection header tree */
1973
0
   proto_tree_add_item_ret_uint(header_tree, hf_cip_instance_cnt, tvb, offset + 4, 1, ENC_LITTLE_ENDIAN, inst_count);
1974
0
   proto_tree_add_item(header_tree, hf_cip_last_update, tvb, offset + 6, 1, ENC_LITTLE_ENDIAN);
1975
1976
0
   dissect_time_data_set(NULL, header_tree, NULL, tvb, offset + 7, 1);
1977
1978
   /* Move the offset to the byte just beyond the time data set field */
1979
0
   offset = (offset + 7 + 1);
1980
1981
   /* Add the time values if they are present in the time data set header field */
1982
0
   if ( (time_data_set & TIME_DATA_SET_TIME_STAMP) == TIME_DATA_SET_TIME_STAMP )
1983
0
   {
1984
0
      proto_tree_add_item(header_tree, hf_cip_cont_time_stamp, tvb, offset, 8, ENC_LITTLE_ENDIAN);
1985
0
      offset = (offset + 8);
1986
0
   }
1987
1988
0
   if ( (time_data_set & TIME_DATA_SET_TIME_OFFSET) == TIME_DATA_SET_TIME_OFFSET )
1989
0
   {
1990
0
      proto_tree_add_item(header_tree, hf_cip_cont_time_offset, tvb, offset, 8, ENC_LITTLE_ENDIAN);
1991
0
      offset = (offset + 8);
1992
0
   }
1993
1994
   /* Return the number of bytes used so it can be used as an offset in the following dissections */
1995
0
   return offset;
1996
0
}
1997
1998
/*
1999
 * Function name: dissect_var_devce_conn_header
2000
 *
2001
 * Purpose: Dissect the connection header of a variable device to controller message
2002
 *
2003
 * Returns: Offset to the start of the instance data block
2004
 */
2005
static uint32_t
2006
dissect_var_devce_conn_header(tvbuff_t* tvb, proto_tree* tree, uint32_t* inst_count, uint32_t offset)
2007
0
{
2008
0
   uint32_t    header_size;
2009
0
   proto_tree *header_tree;
2010
2011
   /* Calculate the header size, start with the basic header size */
2012
0
   header_size = 8;
2013
2014
0
   uint32_t time_data_set = tvb_get_uint8(tvb, offset + 7);
2015
0
   if ( (time_data_set & TIME_DATA_SET_TIME_STAMP) == TIME_DATA_SET_TIME_STAMP )
2016
0
   {
2017
0
      header_size += 8;
2018
0
   }
2019
0
   if ( (time_data_set & TIME_DATA_SET_TIME_OFFSET) == TIME_DATA_SET_TIME_OFFSET )
2020
0
   {
2021
0
      header_size += 8;
2022
0
   }
2023
0
   if ( (time_data_set & TIME_DATA_SET_UPDATE_DIAGNOSTICS) == TIME_DATA_SET_UPDATE_DIAGNOSTICS )
2024
0
   {
2025
0
      header_size += 4;
2026
0
   }
2027
0
   if ( (time_data_set & TIME_DATA_SET_TIME_DIAGNOSTICS) == TIME_DATA_SET_TIME_DIAGNOSTICS )
2028
0
   {
2029
0
      header_size += 16;
2030
0
   }
2031
2032
   /* Create the tree for the entire connection header */
2033
0
   header_tree = proto_tree_add_subtree(tree, tvb, offset, header_size, ett_cont_dev_header, NULL, "Connection Header");
2034
2035
   /* Add the connection header fields that are common to all types of messages */
2036
0
   proto_tree_add_item(header_tree, hf_cip_format,   tvb, offset, 1, ENC_LITTLE_ENDIAN);
2037
0
   proto_tree_add_item(header_tree, hf_cip_revision, tvb, offset + 1, 1, ENC_LITTLE_ENDIAN);
2038
0
   proto_tree_add_item(header_tree, hf_cip_updateid, tvb, offset + 2, 1, ENC_LITTLE_ENDIAN);
2039
2040
0
   dissect_node_status(NULL, header_tree, NULL, tvb, offset + 3, 1);
2041
2042
   /* Add the instance count to the connection header tree */
2043
0
   proto_tree_add_item_ret_uint(header_tree, hf_cip_instance_cnt, tvb, offset + 4, 1, ENC_LITTLE_ENDIAN, inst_count);
2044
2045
   /* The device to controller header contains the node alarms and node faults fields as well. */
2046
0
   proto_tree_add_item(header_tree, hf_cip_node_fltalarms, tvb, offset + 5, 1, ENC_LITTLE_ENDIAN);
2047
2048
   /* Add the last update id to the connection header tree */
2049
0
   proto_tree_add_item(header_tree, hf_cip_last_update, tvb, offset + 6, 1, ENC_LITTLE_ENDIAN);
2050
2051
0
   dissect_time_data_set(NULL, header_tree, NULL, tvb, offset + 7, 1);
2052
2053
   /* Move the offset to the byte just beyond the time data set field */
2054
0
   offset = (offset + 7 + 1);
2055
2056
   /* Add the time values if they are present in the time data set header field */
2057
0
   if ( (time_data_set & TIME_DATA_SET_TIME_STAMP) == TIME_DATA_SET_TIME_STAMP )
2058
0
   {
2059
0
      proto_tree_add_item(header_tree, hf_cip_devc_time_stamp, tvb, offset, 8, ENC_LITTLE_ENDIAN);
2060
0
      offset = (offset + 8);
2061
0
   }
2062
2063
0
   if ( (time_data_set & TIME_DATA_SET_TIME_OFFSET) == TIME_DATA_SET_TIME_OFFSET )
2064
0
   {
2065
0
      proto_tree_add_item(header_tree, hf_cip_devc_time_offset, tvb, offset, 8, ENC_LITTLE_ENDIAN);
2066
0
      offset = (offset + 8);
2067
0
   }
2068
2069
0
   if ( (time_data_set & TIME_DATA_SET_UPDATE_DIAGNOSTICS) == TIME_DATA_SET_UPDATE_DIAGNOSTICS )
2070
0
   {
2071
      /* If the time diagnostic bit is set then the header contains the count of lost updates, late updates, data
2072
      * received time stamp and data transmit time stamp */
2073
0
      proto_tree_add_item(header_tree, hf_cip_lost_update, tvb, offset, 1, ENC_LITTLE_ENDIAN);
2074
0
      offset = (offset + 1);
2075
2076
      /* Add the reserved bytes to the offset after adding the late updates to the display */
2077
0
      proto_tree_add_item(header_tree, hf_cip_late_update, tvb, offset, 1, ENC_LITTLE_ENDIAN);
2078
0
      offset = (offset + 3);
2079
0
   }
2080
2081
0
   if ( (time_data_set & TIME_DATA_SET_TIME_DIAGNOSTICS) == TIME_DATA_SET_TIME_DIAGNOSTICS )
2082
0
   {
2083
0
      proto_tree_add_item(header_tree, hf_cip_data_rx_time_stamp, tvb, offset, 8, ENC_LITTLE_ENDIAN);
2084
0
      offset += 8;
2085
2086
0
      proto_tree_add_item(header_tree, hf_cip_data_tx_time_stamp, tvb, offset, 8, ENC_LITTLE_ENDIAN);
2087
0
      offset += 8;
2088
0
   }
2089
2090
   /* Return the number of bytes used so it can be used as an offset in the following dissections */
2091
0
   return offset;
2092
0
}
2093
2094
2095
/*
2096
 * Function name: dissect_cipmotion
2097
 *
2098
 * Purpose: Perform the top level dissection of the CIP Motion datagram, it is called by
2099
 * Wireshark when the dissection rule registered in proto_reg_handoff_cipmotion is fired
2100
 *
2101
 * Returns: void
2102
 */
2103
static int
2104
dissect_cipmotion(tvbuff_t* tvb, packet_info* pinfo, proto_tree* tree, void* data)
2105
0
{
2106
0
   cip_io_data_input* io_data_input = (cip_io_data_input*)data;
2107
2108
0
   uint32_t    con_format;
2109
0
   uint32_t    update_id;
2110
0
   proto_item *proto_item_top;
2111
0
   proto_tree *proto_tree_top;
2112
0
   uint32_t    offset = 0;
2113
2114
0
   uint8_t ConnPoint = 2;
2115
0
   if (io_data_input && io_data_input->conn_info)
2116
0
   {
2117
0
      ConnPoint = io_data_input->conn_info->connection_path.iConnPoint;
2118
0
   }
2119
2120
   /* Create display subtree for the protocol by creating an item and then
2121
    * creating a subtree from the item, the subtree must have been registered
2122
    * in proto_register_cipmotion already */
2123
0
   proto_item_top = proto_tree_add_item(tree, proto_cipmotion, tvb, 0, -1, ENC_NA);
2124
0
   proto_tree_top = proto_item_add_subtree(proto_item_top, ett_cipmotion);
2125
2126
   /* Add the CIP class 1 sequence number to the tree */
2127
0
   proto_tree_add_item(proto_tree_top, hf_cip_class1_seqnum, tvb, offset, 2, ENC_LITTLE_ENDIAN);
2128
0
   offset = (offset + 2);
2129
2130
0
   if (ConnPoint >= 3)
2131
0
   {
2132
0
       dissect_cip_run_idle(tvb, offset, proto_tree_top);
2133
0
       offset += 4;
2134
0
   }
2135
2136
   /* Pull the actual values for the connection format and update id from the
2137
    * incoming message to be used in the column info */
2138
0
   con_format = tvb_get_uint8(tvb, offset);
2139
0
   update_id  = tvb_get_uint8(tvb, offset + 2);
2140
2141
   /* Make entries in Protocol column and Info column on summary display */
2142
0
   col_set_str(pinfo->cinfo, COL_PROTOCOL, "CIP Motion");
2143
2144
   /* Add connection format and update number to the info column */
2145
0
   col_add_fstr( pinfo->cinfo, COL_INFO, "%s, Update Id: %d",
2146
0
                 val_to_str(pinfo->pool, con_format, cip_con_format_vals, "Unknown connection format (%x)"), update_id );
2147
2148
   /* Attempt to classify the incoming header */
2149
0
   if (( con_format == FORMAT_VAR_CONTROL_TO_DEVICE ) ||
2150
0
       ( con_format == FORMAT_VAR_DEVICE_TO_CONTROL ))
2151
0
   {
2152
      /* Sizes of the individual channels within the connection */
2153
0
      uint32_t cyc_size, cyc_blk_size, evnt_size, servc_size;
2154
0
      uint32_t inst_count = 0, inst;
2155
0
      uint32_t format_rev = 0;
2156
2157
      /* Dissect the header fields */
2158
0
      switch(con_format)
2159
0
      {
2160
0
      case FORMAT_VAR_CONTROL_TO_DEVICE:
2161
0
         format_rev = tvb_get_uint8(tvb, offset + 1);
2162
0
         offset = dissect_var_cont_conn_header(tvb, proto_tree_top, &inst_count, offset);
2163
0
         break;
2164
0
      case FORMAT_VAR_DEVICE_TO_CONTROL:
2165
0
         format_rev = tvb_get_uint8(tvb, offset + 1);
2166
0
         offset = dissect_var_devce_conn_header(tvb, proto_tree_top, &inst_count, offset);
2167
0
         break;
2168
0
      }
2169
2170
0
      if (format_rev != ConnPoint)
2171
0
      {
2172
0
         expert_add_info(pinfo, proto_item_top, &ei_format_rev_conn_pt);
2173
0
      }
2174
2175
      /* Repeat the following dissections for each instance within the payload */
2176
0
      for( inst = 0; inst < inst_count; inst++ )
2177
0
      {
2178
         /* Actual instance number from header field */
2179
0
         uint8_t instance;
2180
2181
         /* Dissect the instance data header */
2182
0
         dissect_var_inst_header( tvb, proto_tree_top, offset, &instance,
2183
0
                                    &cyc_size, &cyc_blk_size, &evnt_size, &servc_size );
2184
2185
         /* Increment the offset to just beyond the instance header */
2186
0
         offset += 8;
2187
2188
         /* Dissect the cyclic command (actual) data if any exists */
2189
         /* Dissect the cyclic write (read) data if any exists */
2190
         /* Dissect the event data block if there is any event data */
2191
0
         switch(con_format)
2192
0
         {
2193
0
         case FORMAT_VAR_CONTROL_TO_DEVICE:
2194
0
            if ( cyc_size > 0 )
2195
0
               offset = dissect_cntr_cyclic(tvb, proto_tree_top, offset, cyc_size);
2196
0
            if ( cyc_blk_size > 0 )
2197
0
               offset = dissect_cyclic_wt(tvb, proto_tree_top, offset, cyc_blk_size);
2198
0
            if ( evnt_size > 0 )
2199
0
               offset = dissect_cntr_event(tvb, proto_tree_top, offset, evnt_size);
2200
0
            if ( servc_size > 0 )
2201
0
               offset = dissect_cntr_service(tvb, pinfo, proto_tree_top, offset, servc_size, instance);
2202
0
            break;
2203
0
         case FORMAT_VAR_DEVICE_TO_CONTROL:
2204
0
            if ( cyc_size > 0 )
2205
0
               offset = dissect_device_cyclic(tvb, proto_tree_top, offset, cyc_size);
2206
0
            if ( cyc_blk_size > 0 )
2207
0
               offset = dissect_cyclic_rd( tvb, proto_tree_top, offset, cyc_blk_size );
2208
0
            if ( evnt_size > 0 )
2209
0
               offset = dissect_devce_event(tvb, proto_tree_top, offset, evnt_size);
2210
0
            if ( servc_size > 0 )
2211
0
               offset = dissect_devce_service(tvb, pinfo, proto_tree_top, offset, servc_size, instance);
2212
0
            break;
2213
0
         }
2214
2215
0
      } /* End of instance for( ) loop */
2216
0
   }
2217
2218
   // Display any remaining unparsed data.
2219
0
   int remain_len = tvb_reported_length_remaining(tvb, offset);
2220
0
   if (remain_len > 0)
2221
0
   {
2222
0
      proto_tree_add_item(proto_tree_top, hf_cip_data, tvb, offset, remain_len, ENC_NA);
2223
0
   }
2224
2225
0
   return tvb_captured_length(tvb);
2226
0
}
2227
2228
static int dissect_cipmotion3(tvbuff_t* tvb, packet_info* pinfo, proto_tree* tree, void* data _U_)
2229
0
{
2230
0
   cip_conn_info_t conn_info;
2231
0
   memset(&conn_info, 0, sizeof(conn_info));
2232
0
   conn_info.connection_path.iConnPoint = 3;
2233
2234
0
   cip_io_data_input io_data_input;
2235
0
   io_data_input.conn_info = &conn_info;
2236
2237
0
   return dissect_cipmotion(tvb, pinfo, tree, &io_data_input);
2238
0
}
2239
2240
int dissect_motion_configuration_block(tvbuff_t* tvb, packet_info* pinfo, proto_tree* tree, proto_item* item, int offset)
2241
0
{
2242
0
   proto_item* config_item;
2243
0
   proto_tree* config_tree = proto_tree_add_subtree(tree, tvb, offset, 0, ett_configuration_block, &config_item, "Motion Configuration Block");
2244
2245
0
   proto_tree_add_item(config_tree, hf_configuration_block_format_rev, tvb, offset, 1, ENC_LITTLE_ENDIAN);
2246
0
   int parsed_len = 1;
2247
2248
0
   parsed_len += dissect_connection_configuration_bits(pinfo, config_tree, item, tvb, offset + parsed_len, 1);
2249
2250
   // 2 reserved bytes
2251
0
   parsed_len += 2;
2252
2253
0
   proto_tree_add_item(config_tree, hf_configuration_block_drive_power_struct_id, tvb, offset + parsed_len, 4, ENC_LITTLE_ENDIAN);
2254
0
   parsed_len += 4;
2255
2256
0
   proto_item_set_len(config_item, parsed_len);
2257
2258
0
   return parsed_len;
2259
0
}
2260
2261
/*
2262
 * Function name: proto_register_cipmotion
2263
 *
2264
 * Purpose: Register the protocol with Wireshark, a script will add this protocol
2265
 * to the list of protocols during the build process. This function is where the
2266
 * header fields and subtree identifiers are registered.
2267
 *
2268
 * Returns: void
2269
 */
2270
void
2271
proto_register_cipmotion(void)
2272
15
{
2273
   /* This is a list of header fields that can be used in the dissection or
2274
   * to use in a filter expression */
2275
15
   static hf_register_info hf[] =
2276
15
   {
2277
      /* Connection format header field, the first byte in the message which
2278
      * determines if the message is fixed or variable, controller to device,
2279
      * device to controller, etc. */
2280
15
      { &hf_cip_format,
2281
15
        { "Connection Format", "cipm.format",
2282
15
          FT_UINT8, BASE_DEC, VALS(cip_con_format_vals), 0,
2283
15
          "Message connection format", HFILL }
2284
15
      },
2285
2286
      /* Connection format revision header field */
2287
15
      { &hf_cip_revision,
2288
15
        { "Format Revision", "cipm.revision",
2289
15
          FT_UINT8, BASE_DEC, NULL, 0,
2290
15
          "Message format revision", HFILL }
2291
15
      },
2292
2293
15
      { &hf_cip_class1_seqnum,
2294
15
        { "CIP Class 1 Sequence Count", "cipm.class1seqnum",
2295
15
          FT_UINT16, BASE_DEC, NULL, 0,
2296
15
          NULL, HFILL }
2297
15
      },
2298
2299
15
      { &hf_configuration_block_format_rev,
2300
15
        { "Format Revision", "cipm.config.format_rev",
2301
15
          FT_UINT8, BASE_DEC, NULL, 0,
2302
15
          NULL, HFILL }
2303
15
      },
2304
2305
15
      { &hf_configuration_block_drive_power_struct_id,
2306
15
        { "Drive Power Structure Class ID", "cipm.config.drive_class_id",
2307
15
          FT_UINT32, BASE_DEC, NULL, 0,
2308
15
          NULL, HFILL }
2309
15
      },
2310
2311
15
      { &hf_cip_updateid,
2312
15
        { "Update Id", "cipm.updateid",
2313
15
          FT_UINT8, BASE_DEC, NULL, 0,
2314
15
          "Cyclic Transaction Number", HFILL }
2315
15
      },
2316
15
      { &hf_cip_instance_cnt,
2317
15
        { "Instance Count", "cipm.instancecount",
2318
15
          FT_UINT8, BASE_DEC, NULL, 0,
2319
15
          NULL, HFILL }
2320
15
      },
2321
15
      { &hf_cip_last_update,
2322
15
        { "Last Update Id", "cipm.lastupdate",
2323
15
          FT_UINT8, BASE_DEC, NULL, 0,
2324
15
          NULL, HFILL }
2325
15
      },
2326
15
      { &hf_cip_node_status,
2327
15
        { "Node Status", "cipm.nodestatus",
2328
15
          FT_UINT8, BASE_HEX, NULL, 0,
2329
15
          NULL, HFILL}
2330
15
      },
2331
15
      { &hf_cip_node_control,
2332
15
        { "Node Control", "cipm.nodecontrol",
2333
15
          FT_UINT8, BASE_HEX, NULL, 0,
2334
15
          NULL, HFILL}
2335
15
      },
2336
15
      { &hf_cip_node_control_remote,
2337
15
        { "Remote Control", "cipm.remote",
2338
15
          FT_BOOLEAN, 8, NULL, 0x01,
2339
15
          "Node Control: Remote Control", HFILL}
2340
15
      },
2341
15
      { &hf_cip_node_control_sync,
2342
15
        { "Sync Control", "cipm.sync",
2343
15
          FT_BOOLEAN, 8, NULL, 0x02,
2344
15
          "Node Control: Synchronous Operation", HFILL}
2345
15
      },
2346
15
      { &hf_cip_node_data_valid,
2347
15
        { "Data Valid", "cipm.valid",
2348
15
          FT_BOOLEAN, 8, NULL, 0x04,
2349
15
          "Node Control: Data Valid", HFILL}
2350
15
      },
2351
15
      { &hf_cip_node_fault_reset,
2352
15
        { "Node Fault Reset", "cipm.fltrst",
2353
15
          FT_BOOLEAN, 8, NULL, 0x08,
2354
15
          "Node Control: Node Fault Reset", HFILL}
2355
15
      },
2356
15
      { &hf_cip_node_device_faulted,
2357
15
        { "Faulted", "cipm.flt",
2358
15
          FT_BOOLEAN, 8, NULL, 0x08,
2359
15
          "Node Control: Device Faulted", HFILL}
2360
15
      },
2361
15
      { &hf_cip_node_fltalarms,
2362
15
        { "Node Faults and Alarms", "cipm.fltalarms",
2363
15
          FT_UINT8, BASE_DEC, NULL, 0,
2364
15
          NULL, HFILL }
2365
15
      },
2366
15
      { &hf_cip_time_data_set,
2367
15
        { "Time Data Set", "cipm.timedataset",
2368
15
          FT_UINT8, BASE_HEX, NULL, 0,
2369
15
          NULL, HFILL}
2370
15
      },
2371
15
      { &hf_cip_time_data_stamp,
2372
15
        { "Time Stamp", "cipm.time.stamp",
2373
15
          FT_BOOLEAN, 8, NULL, TIME_DATA_SET_TIME_STAMP,
2374
15
          "Time Data Set: Time Stamp", HFILL}
2375
15
      },
2376
15
      { &hf_cip_time_data_offset,
2377
15
        { "Time Offset", "cipm.time.offset",
2378
15
          FT_BOOLEAN, 8, NULL, TIME_DATA_SET_TIME_OFFSET,
2379
15
          "Time Data Set: Time Offset", HFILL}
2380
15
      },
2381
15
      { &hf_cip_time_data_diag,
2382
15
        { "Update Diagnostics", "cipm.time.update",
2383
15
          FT_BOOLEAN, 8, NULL, TIME_DATA_SET_UPDATE_DIAGNOSTICS,
2384
15
          "Time Data Set: Update Diagnostics", HFILL}
2385
15
      },
2386
15
      { &hf_cip_time_data_time_diag,
2387
15
        { "Time Diagnostics", "cipm.time.diag",
2388
15
          FT_BOOLEAN, 8, NULL, TIME_DATA_SET_TIME_DIAGNOSTICS,
2389
15
          "Time Data Set: Time Diagnostics", HFILL}
2390
15
      },
2391
2392
15
      { &hf_cip_cont_time_stamp,
2393
15
        { "Controller Time Stamp", "cipm.ctrltimestamp",
2394
15
          FT_UINT64, BASE_DEC, NULL, 0,
2395
15
          "Time Data Set: Controller Time Stamp", HFILL}
2396
15
      },
2397
15
      { &hf_cip_cont_time_offset,
2398
15
        { "Controller Time Offset", "cipm.ctrltimeoffser",
2399
15
          FT_UINT64, BASE_DEC, NULL, 0,
2400
15
          "Time Data Set: Controller Time Offset", HFILL}
2401
15
      },
2402
15
      { &hf_cip_data_rx_time_stamp,
2403
15
        { "Data Received Time Stamp", "cipm.rxtimestamp",
2404
15
          FT_UINT64, BASE_DEC, NULL, 0,
2405
15
          "Time Data Set: Data Received Time Stamp", HFILL}
2406
15
      },
2407
15
      { &hf_cip_data_tx_time_stamp,
2408
15
        { "Data Transmit Time Stamp", "cipm.txtimestamp",
2409
15
          FT_UINT64, BASE_DEC, NULL, 0,
2410
15
          "Time Data Set: Data Transmit Time Offset", HFILL}
2411
15
      },
2412
15
      { &hf_cip_devc_time_stamp,
2413
15
        { "Device Time Stamp", "cipm.devctimestamp",
2414
15
          FT_UINT64, BASE_DEC|BASE_UNIT_STRING, UNS(&units_nanosecond_nanoseconds), 0,
2415
15
          "Time Data Set: Device Time Stamp", HFILL}
2416
15
      },
2417
15
      { &hf_cip_devc_time_offset,
2418
15
        { "Device Time Offset", "cipm.devctimeoffser",
2419
15
          FT_UINT64, BASE_DEC, NULL, 0,
2420
15
          "Time Data Set: Device Time Offset", HFILL}
2421
15
      },
2422
15
      { &hf_cip_lost_update,
2423
15
        { "Lost Updates", "cipm.lostupdates",
2424
15
          FT_UINT8, BASE_DEC, NULL, 0,
2425
15
          "Time Data Set: Lost Updates", HFILL}
2426
15
      },
2427
15
      { &hf_cip_late_update,
2428
15
        { "Lost Updates", "cipm.lateupdates",
2429
15
          FT_UINT8, BASE_DEC, NULL, 0,
2430
15
          "Time Data Set: Late Updates", HFILL}
2431
15
      },
2432
2433
15
      { &hf_cip_motor_cntrl,
2434
15
        { "Control Mode", "cipm.ctrlmode",
2435
15
          FT_UINT8, BASE_DEC, VALS(cip_motor_control_vals), 0,
2436
15
          "Cyclic Data Block: Motor Control Mode", HFILL }
2437
15
      },
2438
2439
15
      { &hf_cip_feedback,
2440
15
        { "Feedback Information", "cipm.feedback",
2441
15
          FT_UINT8, BASE_HEX, NULL, 0,
2442
15
          NULL, HFILL }
2443
15
      },
2444
15
      { &hf_cip_feedback_mode,
2445
15
        { "Feedback Mode", "cipm.feedback_mode",
2446
15
          FT_UINT8, BASE_DEC, VALS(cip_feedback_mode_vals), FEEDBACK_MODE_BITS,
2447
15
          NULL, HFILL }
2448
15
      },
2449
15
      { &hf_cip_feedback_data_type,
2450
15
        { "Feedback Data Type", "cipm.feedback_data_type",
2451
15
          FT_UINT8, BASE_DEC, VALS(cip_feedback_type_vals), FEEDBACK_DATA_TYPE_BITS,
2452
15
          NULL, HFILL }
2453
15
      },
2454
2455
15
      { &hf_cip_controller_update_delay_high_limit, { "Controller Update Delay High Limit", "cipm.controller_update_delay_high_limit", FT_UINT8, BASE_DEC, NULL, 0, NULL, HFILL } },
2456
15
      { &hf_cip_controller_update_delay_low_limit, { "Controller Update Delay Low Limit", "cipm.controller_update_delay_low_limit", FT_UINT8, BASE_DEC, NULL, 0, NULL, HFILL } },
2457
15
      { &hf_cip_sync_threshold, { "Sync Threshold", "cipm.sync_threshold", FT_UINT32, BASE_DEC|BASE_UNIT_STRING, UNS(&units_nanosecond_nanoseconds), 0, NULL, HFILL } },
2458
15
      { &hf_cip_step_threshold, { "Step Threshold", "cipm.step_threshold", FT_UINT32, BASE_DEC|BASE_UNIT_STRING, UNS(&units_nanosecond_nanoseconds), 0, NULL, HFILL } },
2459
15
      { &hf_cip_control_method, { "Control Method", "cipm.control_method", FT_UINT8, BASE_DEC, NULL, 0, NULL, HFILL } },
2460
15
      { &hf_cip_feedback_unit_ratio, { "Feedback Unit Ratio", "cipm.feedback_unit_ratio", FT_FLOAT, BASE_NONE, NULL, 0, NULL, HFILL } },
2461
15
      { &hf_cip_velocity_threshold, { "Velocity Threshold", "cipm.velocity_threshold", FT_FLOAT, BASE_NONE, NULL, 0, NULL, HFILL } },
2462
15
      { &hf_cip_velocity_lock_tolerance, { "Velocity Lock Tolerance", "cipm.velocity_lock_tolerance", FT_FLOAT, BASE_NONE, NULL, 0, NULL, HFILL } },
2463
15
      { &hf_cip_velocity_standstill_window, { "Velocity Standstill Window", "cipm.velocity_standstill_window", FT_FLOAT, BASE_NONE, NULL, 0, NULL, HFILL } },
2464
15
      { &hf_cip_proving_configuration, { "Proving Configuration", "cipm.proving_configuration", FT_UINT32, BASE_DEC, NULL, 0, NULL, HFILL } },
2465
15
      { &hf_cip_torque_prove_current, { "Torque Prove Current", "cipm.torque_prove_current", FT_FLOAT, BASE_NONE, NULL, 0, NULL, HFILL } },
2466
15
      { &hf_cip_brake_test_torque, { "Brake Test Torque", "cipm.brake_test_torque", FT_FLOAT, BASE_NONE, NULL, 0, NULL, HFILL } },
2467
15
      { &hf_cip_zero_speed, { "Zero Speed", "cipm.zero_speed", FT_FLOAT, BASE_NONE, NULL, 0, NULL, HFILL } },
2468
15
      { &hf_cip_zero_speed_time, { "Zero Speed Time", "cipm.zero_speed_time", FT_FLOAT, BASE_NONE, NULL, 0, NULL, HFILL } },
2469
15
      { &hf_cip_dc_bus_voltage, { "DC Bus Voltage", "cipm.dc_bus_voltage", FT_FLOAT, BASE_NONE, NULL, 0, NULL, HFILL } },
2470
15
      { &hf_cip_bus_regulator_action, { "Bus Regulator Action", "cipm.bus_regulator_action", FT_UINT8, BASE_DEC, NULL, 0, NULL, HFILL } },
2471
15
      { &hf_cip_inverter_capacity, { "Inverter Capacity", "cipm.inverter_capacity", FT_FLOAT, BASE_NONE, NULL, 0, NULL, HFILL } },
2472
15
      { &hf_cip_converter_thermal_overload_user_limit, { "Converter Thermal Overload User Limit", "cipm.converter_thermal_overload_user_limit", FT_FLOAT, BASE_NONE, NULL, 0, NULL, HFILL } },
2473
15
      { &hf_cip_bus_undervoltage_user_limit, { "Bus Undervoltage User Limit", "cipm.bus_undervoltage_user_limit", FT_FLOAT, BASE_NONE, NULL, 0, NULL, HFILL } },
2474
15
      { &hf_cip_rotary_motor_poles, { "Rotary Motor Poles", "cipm.rotary_motor_poles", FT_UINT16, BASE_DEC, NULL, 0, NULL, HFILL } },
2475
15
      { &hf_cip_rotary_motor_inertia, { "Rotary Motor Inertia", "cipm.rotary_motor_inertia", FT_FLOAT, BASE_NONE, NULL, 0, NULL, HFILL } },
2476
15
      { &hf_cip_rotary_motor_max_speed, { "Rotary Motor Max Speed", "cipm.rotary_motor_max_speed", FT_FLOAT, BASE_NONE, NULL, 0, NULL, HFILL } },
2477
2478
15
      { &hf_connection_configuration_bits,
2479
15
        { "Connection Configuration Bits", "cipm.ccb",
2480
15
          FT_UINT8, BASE_DEC, NULL, 0,
2481
15
          NULL, HFILL }
2482
15
      },
2483
15
      { &hf_connection_configuration_bits_power,
2484
15
        { "Verify Power Ratings", "cipm.ccb.verify_power_ratings",
2485
15
          FT_BOOLEAN, 8, NULL, 0x01,
2486
15
          NULL, HFILL } },
2487
15
      { &hf_connection_configuration_bits_safety_bit_valid,
2488
15
        { "Networked Safety Bit Valid", "cipm.ccb.networked_safety_bit_valid",
2489
15
          FT_BOOLEAN, 8, NULL, 0x02,
2490
15
          NULL, HFILL } },
2491
15
      { &hf_connection_configuration_bits_allow_network_safety,
2492
15
        { "Allow Networked Safety", "cipm.ccb.allow_networked_safety",
2493
15
          FT_BOOLEAN, 8, NULL, 0x04,
2494
15
          NULL, HFILL } },
2495
2496
15
      { &hf_cip_axis_control,
2497
15
        { "Axis Control", "cipm.axisctrl",
2498
15
          FT_UINT8, BASE_DEC, VALS(cip_axis_control_vals), 0,
2499
15
          "Cyclic Data Block: Axis Control", HFILL }
2500
15
      },
2501
15
      { &hf_cip_control_status,
2502
15
        { "Control Status", "cipm.csts",
2503
15
          FT_UINT8, BASE_DEC, NULL, 0,
2504
15
          "Cyclic Data Block: Axis Control Status", HFILL }
2505
15
      },
2506
15
      { &hf_cip_control_status_complete,
2507
15
        { "Configuration Complete", "cipm.control_status.complete",
2508
15
          FT_BOOLEAN, 8, NULL, 0x01,
2509
15
          NULL, HFILL } },
2510
15
      { &hf_cip_control_status_bus_up,
2511
15
        { "Converter Bus Up", "cipm.control_status.bus_up",
2512
15
          FT_BOOLEAN, 8, NULL, 0x04,
2513
15
          NULL, HFILL } },
2514
15
      { &hf_cip_control_status_bus_unload,
2515
15
        { "Converter Bus Unload", "cipm.control_status.bus_unload",
2516
15
          FT_BOOLEAN, 8, NULL, 0x08,
2517
15
          NULL, HFILL } },
2518
15
      { &hf_cip_control_status_power_loss,
2519
15
        { "Converter AC Power Loss", "cipm.control_status.power_loss",
2520
15
          FT_BOOLEAN, 8, NULL, 0x10,
2521
15
          NULL, HFILL } },
2522
15
      { &hf_cip_axis_response,
2523
15
        { "Axis Response", "cipm.axisresp",
2524
15
          FT_UINT8, BASE_DEC, VALS(cip_axis_response_vals), 0,
2525
15
          "Cyclic Data Block: Axis Response", HFILL }
2526
15
      },
2527
15
      { &hf_cip_axis_resp_stat,
2528
15
        { "Response Status", "cipm.respstat",
2529
15
          FT_UINT8, BASE_DEC|BASE_EXT_STRING, &cip_gs_vals_ext, 0,
2530
15
          "Cyclic Data Block: Axis Response Status", HFILL }
2531
15
      },
2532
15
      { &hf_cip_group_sync,
2533
15
        { "Group Sync Status", "cipm.syncstatus",
2534
15
          FT_UINT8, BASE_HEX, VALS(cip_sync_status_vals), 0,
2535
15
          NULL, HFILL }
2536
15
      },
2537
15
      { &hf_cip_cmd_data_set,
2538
15
        { "Command Data Set", "cipm.cmdset",
2539
15
          FT_UINT8, BASE_HEX, NULL, 0,
2540
15
          NULL, HFILL}
2541
15
      },
2542
15
      { &hf_cip_act_data_set,
2543
15
        { "Actual Data Set", "cipm.actset",
2544
15
          FT_UINT8, BASE_HEX, NULL, 0,
2545
15
          NULL, HFILL}
2546
15
      },
2547
15
      { &hf_cip_sts_data_set,
2548
15
        { "Status Data Set", "cipm.stsset",
2549
15
          FT_UINT8, BASE_HEX, NULL, 0,
2550
15
          NULL, HFILL}
2551
15
      },
2552
2553
      // Command Data Set
2554
15
      { &hf_cip_cmd_data_pos_cmd,
2555
15
        { "Command Position", "cipm.cmd.pos",
2556
15
          FT_BOOLEAN, 8, NULL, COMMAND_DATA_SET_POSITION,
2557
15
          "Command Data Set: Command Position", HFILL}
2558
15
      },
2559
15
      { &hf_cip_cmd_data_vel_cmd,
2560
15
        { "Command Velocity", "cipm.cmd.vel",
2561
15
          FT_BOOLEAN, 8, NULL, COMMAND_DATA_SET_VELOCITY,
2562
15
          "Command Data Set: Command Velocity", HFILL}
2563
15
      },
2564
15
      { &hf_cip_cmd_data_acc_cmd,
2565
15
        { "Command Acceleration", "cipm.cmd.acc",
2566
15
          FT_BOOLEAN, 8, NULL, COMMAND_DATA_SET_ACCELERATION,
2567
15
          "Command Data Set: Command Acceleration", HFILL}
2568
15
      },
2569
15
      { &hf_cip_cmd_data_trq_cmd,
2570
15
        { "Command Torque", "cipm.cmd.trq",
2571
15
          FT_BOOLEAN, 8, NULL, COMMAND_DATA_SET_TORQUE,
2572
15
          "Command Data Set: Command Torque", HFILL}
2573
15
      },
2574
15
      { &hf_cip_cmd_data_unwind_cycle_count,
2575
15
        { "Unwind Cycle Count", "cipm.cmd.unwind",
2576
15
          FT_BOOLEAN, 8, NULL, COMMAND_DATA_SET_UNWIND_CYCLE_COUNT,
2577
15
          "Command Data Set: Unwind Cycle Count", HFILL}
2578
15
      },
2579
15
      { &hf_cip_cmd_data_pos_displacement,
2580
15
        { "Position Displacement", "cipm.cmd.pos_displacement",
2581
15
          FT_BOOLEAN, 8, NULL, COMMAND_DATA_SET_POSITION_DISPLACE,
2582
15
          "Command Data Set: Position Displacement", HFILL}
2583
15
      },
2584
2585
      // Actual Data Set
2586
15
      { &hf_cip_act_data_pos,
2587
15
        { "Actual Position", "cipm.act.pos",
2588
15
          FT_BOOLEAN, 8, NULL, ACTUAL_DATA_SET_POSITION,
2589
15
          "Actual Data Set: Actual Position", HFILL}
2590
15
      },
2591
15
      { &hf_cip_act_data_vel,
2592
15
        { "Actual Velocity", "cipm.act.vel",
2593
15
          FT_BOOLEAN, 8, NULL, ACTUAL_DATA_SET_VELOCITY,
2594
15
          "Actual Data Set: Actual Velocity", HFILL}
2595
15
      },
2596
15
      { &hf_cip_act_data_acc,
2597
15
        { "Actual Acceleration", "cipm.act.acc",
2598
15
          FT_BOOLEAN, 8, NULL, ACTUAL_DATA_SET_ACCELERATION,
2599
15
          "Actual Data Set: Actual Acceleration", HFILL}
2600
15
      },
2601
15
      { &hf_cip_act_unwind_cycle_count,
2602
15
        { "Unwind Cycle Count", "cipm.act.unwind",
2603
15
          FT_BOOLEAN, 8, NULL, ACTUAL_DATA_SET_UNWIND_CYCLE_COUNT,
2604
15
          "Actual Data Set: Unwind Cycle Count", HFILL}
2605
15
      },
2606
15
      { &hf_cip_act_pos_displacement,
2607
15
        { "Position Displacement", "cipm.act.pos_displacement",
2608
15
          FT_BOOLEAN, 8, NULL, ACTUAL_DATA_SET_POSITION_DISPLACE,
2609
15
          "Actual Data Set: Position Displacement", HFILL}
2610
15
      },
2611
2612
15
      { &hf_cip_axis_fault,
2613
15
        { "Axis Fault Code", "cipm.fault.code",
2614
15
          FT_UINT8, BASE_DEC, NULL, 0,
2615
15
          "Status Data Set: Fault Code", HFILL }
2616
15
      },
2617
15
      { &hf_cip_fault_type,
2618
15
        { "Axis Fault Type", "cipm.flttype",
2619
15
          FT_UINT8, BASE_DEC, NULL, 0,
2620
15
          "Axis Status: Axis Fault Type", HFILL}
2621
15
      },
2622
15
      { &hf_cip_fault_sub_code,
2623
15
        { "Axis Fault Sub Code", "cipm.fltsubcode",
2624
15
          FT_UINT8, BASE_DEC, NULL, 0,
2625
15
          "Axis Status: Axis Fault Sub Code", HFILL}
2626
15
      },
2627
15
      { &hf_cip_fault_action,
2628
15
        { "Axis Fault Action", "cipm.fltaction",
2629
15
          FT_UINT8, BASE_DEC, NULL, 0,
2630
15
          "Axis Status: Axis Fault Action", HFILL}
2631
15
      },
2632
15
      { &hf_cip_fault_time_stamp,
2633
15
        { "Axis Fault Time Stamp", "cipm.flttimestamp",
2634
15
          FT_UINT64, BASE_DEC, NULL, 0,
2635
15
          "Axis Status: Axis Fault Time Stamp", HFILL}
2636
15
      },
2637
15
      { &hf_cip_alarm_type,
2638
15
        { "Axis Fault Type", "cipm.alarmtype",
2639
15
          FT_UINT8, BASE_DEC, NULL, 0,
2640
15
          "Axis Status: Axis Alarm Type", HFILL}
2641
15
      },
2642
15
      { &hf_cip_alarm_sub_code,
2643
15
        { "Axis Alarm Sub Code", "cipm.alarmsubcode",
2644
15
          FT_UINT8, BASE_DEC, NULL, 0,
2645
15
          "Axis Status: Axis Alarm Sub Code", HFILL}
2646
15
      },
2647
15
      { &hf_cip_alarm_state,
2648
15
        { "Axis Alarm State", "cipm.alarmstate",
2649
15
          FT_UINT8, BASE_DEC, NULL, 0,
2650
15
          "Axis Status: Axis Alarm State", HFILL }
2651
15
      },
2652
15
      { &hf_cip_alarm_time_stamp,
2653
15
        { "Axis Fault Time Stamp", "cipm.alarmtimestamp",
2654
15
          FT_UINT64, BASE_DEC, NULL, 0,
2655
15
          "Axis Status: Axis Alarm Time Stamp", HFILL}
2656
15
      },
2657
15
      { &hf_cip_axis_status,
2658
15
        { "Axis Status", "cipm.axisstatus",
2659
15
          FT_UINT32, BASE_HEX, NULL, 0,
2660
15
          NULL, HFILL}
2661
15
      },
2662
15
      { &hf_cip_axis_status_mfg,
2663
15
        { "Axis Status Mfg", "cipm.axisstatusmfg",
2664
15
          FT_UINT32, BASE_HEX, NULL, 0,
2665
15
          "Axis Status, Manufacturer Specific", HFILL}
2666
15
      },
2667
15
      { &hf_cip_axis_io_status,
2668
15
        { "Axis I/O Status", "cipm.axisiostatus",
2669
15
          FT_UINT32, BASE_HEX, NULL, 0,
2670
15
          NULL, HFILL}
2671
15
      },
2672
15
      { &hf_cip_axis_io_status_mfg,
2673
15
        { "Axis I/O Status Mfg", "cipm.axisiostatusmfg",
2674
15
          FT_UINT32, BASE_HEX, NULL, 0,
2675
15
          "Axis I/O Status, Manufacturer Specific", HFILL}
2676
15
      },
2677
15
      { &hf_cip_axis_safety_status,
2678
15
        { "Axis Safety Status", "cipm.safetystatus",
2679
15
          FT_UINT32, BASE_HEX, NULL, 0,
2680
15
          NULL, HFILL}
2681
15
      },
2682
15
      { &hf_cip_axis_safety_status_mfg,
2683
15
        { "Axis Safety Status Mfg", "cipm.safetystatusmfg",
2684
15
          FT_UINT32, BASE_HEX, NULL, 0,
2685
15
          "Axis Safety Status, Manufacturer Specific", HFILL}
2686
15
      },
2687
15
      { &hf_cip_axis_safety_state,
2688
15
        { "Axis Safety State", "cipm.safetystate",
2689
15
          FT_UINT8, BASE_HEX, NULL, 0,
2690
15
          "Axis Safety Sate", HFILL}
2691
15
      },
2692
15
      { &hf_cip_sts_flt,
2693
15
        { "Axis Fault Codes", "cipm.sts.flt",
2694
15
          FT_BOOLEAN, 8, NULL, STATUS_DATA_SET_AXIS_FAULT,
2695
15
          "Status Data Set: Axis Fault Codes", HFILL}
2696
15
      },
2697
15
      { &hf_cip_sts_alrm,
2698
15
        { "Axis Alarm Codes", "cipm.sts.alarm",
2699
15
          FT_BOOLEAN, 8, NULL, STATUS_DATA_SET_AXIS_ALARM,
2700
15
          "Status Data Set: Axis Alarm Codes", HFILL}
2701
15
      },
2702
15
      { &hf_cip_sts_sts,
2703
15
        { "Axis Status", "cipm.sts.sts",
2704
15
          FT_BOOLEAN, 8, NULL, STATUS_DATA_SET_AXIS_STATUS,
2705
15
          "Status Data Set: Axis Status", HFILL}
2706
15
      },
2707
15
      { &hf_cip_sts_iosts,
2708
15
        { "Axis I/O Status", "cipm.sts.iosts",
2709
15
          FT_BOOLEAN, 8, NULL, STATUS_DATA_SET_AXIS_IO_STATUS,
2710
15
          "Status Data Set: Axis I/O Status", HFILL}
2711
15
      },
2712
15
      { &hf_cip_sts_axis_safety,
2713
15
        { "Axis Safety Status", "cipm.sts.safety",
2714
15
          FT_BOOLEAN, 8, NULL, STATUS_DATA_SET_AXIS_SAFETY,
2715
15
          "Status Data Set: Axis Safety Status", HFILL}
2716
15
      },
2717
15
      { &hf_cip_intrp,
2718
15
        { "Command Target Update", "cipm.intrp",
2719
15
          FT_UINT8, BASE_DEC, VALS(cip_interpolation_vals), COMMAND_CONTROL_TARGET_UPDATE,
2720
15
          "Cyclic Data Block: Command Target Update", HFILL}
2721
15
      },
2722
15
      { &hf_cip_position_data_type,
2723
15
        { "Command Position Data Type", "cipm.posdatatype",
2724
15
          FT_UINT8, BASE_DEC, VALS(cip_pos_data_type_vals), COMMAND_CONTROL_POSITION_DATA_TYPE,
2725
15
          "Cyclic Data Block: Command Position Data Type", HFILL }
2726
15
      },
2727
15
      { &hf_cip_axis_state,
2728
15
        { "Axis State", "cipm.axste",
2729
15
          FT_UINT8, BASE_DEC, VALS(cip_axis_state_vals), 0,
2730
15
          "Cyclic Data Block: Axis State", HFILL}
2731
15
      },
2732
15
      { &hf_cip_command_control,
2733
15
        { "Command Control", "cipm.cmdcontrol",
2734
15
          FT_UINT8, BASE_DEC, NULL, 0,
2735
15
          "Cyclic Data Block: Command Control", HFILL }
2736
15
      },
2737
15
      { &hf_cip_cyclic_wrt_data,
2738
15
        { "Write Data", "cipm.writedata",
2739
15
          FT_BYTES, BASE_NONE, NULL, 0,
2740
15
          "Cyclic Write: Data", HFILL }
2741
15
      },
2742
15
      { &hf_cip_cyclic_rd_data,
2743
15
        { "Read Data", "cipm.readdata",
2744
15
          FT_BYTES, BASE_NONE, NULL, 0,
2745
15
          "Cyclic Read: Data", HFILL }
2746
15
      },
2747
15
      { &hf_cip_cyclic_write_blk,
2748
15
        { "Write Block", "cipm.writeblk",
2749
15
          FT_UINT8, BASE_DEC, NULL, 0,
2750
15
          "Cyclic Data Block: Write Block Id", HFILL }
2751
15
      },
2752
15
      { &hf_cip_cyclic_read_blk,
2753
15
        { "Read Block", "cipm.readblk",
2754
15
          FT_UINT8, BASE_DEC, NULL, 0,
2755
15
          "Cyclic Data Block: Read Block Id", HFILL}
2756
15
      },
2757
15
      { &hf_cip_cyclic_write_sts,
2758
15
        { "Write Status", "cipm.writests",
2759
15
          FT_UINT8, BASE_DEC, NULL, 0,
2760
15
          "Cyclic Data Block: Write Status", HFILL }
2761
15
      },
2762
15
      { &hf_cip_cyclic_read_sts,
2763
15
        { "Read Status", "cipm.readsts",
2764
15
          FT_UINT8, BASE_DEC, NULL, 0,
2765
15
          "Cyclic Data Block: Read Status", HFILL }
2766
15
      },
2767
15
      { &hf_cip_event_checking,
2768
15
        { "Event Checking Control", "cipm.evntchkcontrol",
2769
15
          FT_UINT32, BASE_HEX, NULL, 0,
2770
15
          "Event Channel: Event Checking Control", HFILL}
2771
15
      },
2772
15
      { &hf_cip_event_ack,
2773
15
        { "Event Acknowledgement", "cipm.evntack",
2774
15
          FT_UINT8, BASE_DEC, NULL, 0,
2775
15
          "Event Channel: Event Acknowledgement", HFILL}
2776
15
      },
2777
15
      { &hf_cip_event_status,
2778
15
        { "Event Checking Status", "cipm.evntchkstatus",
2779
15
          FT_UINT32, BASE_HEX, NULL, 0,
2780
15
          "Event Channel: Event Checking Status", HFILL}
2781
15
      },
2782
15
      { &hf_cip_event_id,
2783
15
        { "Event Id", "cipm.evntid",
2784
15
          FT_UINT8, BASE_DEC, NULL, 0,
2785
15
          "Event Channel: Event Id", HFILL }
2786
15
      },
2787
15
      { &hf_cip_event_pos,
2788
15
        { "Event Position", "cipm.evntpos",
2789
15
          FT_INT32, BASE_DEC, NULL, 0,
2790
15
          "Event Channel: Event Position", HFILL}
2791
15
      },
2792
15
      { &hf_cip_event_ts,
2793
15
        { "Event Time Stamp", "cipm.evntimestamp",
2794
15
          FT_UINT64, BASE_DEC|BASE_UNIT_STRING, UNS(&units_nanosecond_nanoseconds), 0,
2795
15
          "Event Channel: Time Stamp", HFILL}
2796
15
      },
2797
2798
15
      { &hf_cip_evnt_ctrl_reg1_pos,
2799
15
        { "Reg 1 Pos Edge", "cipm.evnt.ctrl.reg1posedge",
2800
15
          FT_BOOLEAN, 32, NULL, 0x00000001,
2801
15
          "Event Checking Control: Reg 1 Pos Edge", HFILL}
2802
15
      },
2803
15
      { &hf_cip_evnt_ctrl_reg1_neg,
2804
15
        { "Reg 1 Neg Edge", "cipm.evnt.ctrl.reg1negedge",
2805
15
          FT_BOOLEAN, 32, NULL, 0x00000002,
2806
15
          "Event Checking Control: Reg 1 Neg Edge", HFILL}
2807
15
      },
2808
15
      { &hf_cip_evnt_ctrl_reg2_pos,
2809
15
        { "Reg 2 Pos Edge", "cipm.evnt.ctrl.reg2posedge",
2810
15
          FT_BOOLEAN, 32, NULL, 0x00000004,
2811
15
          "Event Checking Control: Reg 2 Pos Edge", HFILL}
2812
15
      },
2813
15
      { &hf_cip_evnt_ctrl_reg2_neg,
2814
15
        { "Reg 2 Neg Edge", "cipm.evnt.ctrl.reg2negedge",
2815
15
          FT_BOOLEAN, 32, NULL, 0x00000008,
2816
15
          "Event Checking Control: Reg 2 Neg Edge", HFILL}
2817
15
      },
2818
15
      { &hf_cip_evnt_ctrl_reg1_posrearm,
2819
15
        { "Reg 1 Pos Rearm", "cipm.evnt.ctrl.reg1posrearm",
2820
15
          FT_BOOLEAN, 32, NULL, 0x00000100,
2821
15
          "Event Checking Control: Reg 1 Pos Rearm", HFILL}
2822
15
      },
2823
15
      { &hf_cip_evnt_ctrl_reg1_negrearm,
2824
15
        { "Reg 1 Neg Rearm", "cipm.evnt.ctrl.reg1negrearm",
2825
15
          FT_BOOLEAN, 32, NULL, 0x00000200,
2826
15
          "Event Checking Control: Reg 1 Neg Rearm", HFILL}
2827
15
      },
2828
15
      { &hf_cip_evnt_ctrl_reg2_posrearm,
2829
15
        { "Reg 2 Pos Rearm", "cipm.evnt.ctrl.reg2posrearm",
2830
15
          FT_BOOLEAN, 32, NULL, 0x00000400,
2831
15
          "Event Checking Control: Reg 2 Pos Rearm", HFILL}
2832
15
      },
2833
15
      { &hf_cip_evnt_ctrl_reg2_negrearm,
2834
15
        { "Reg 2 Neg Rearm", "cipm.evnt.ctrl.reg2negrearm",
2835
15
          FT_BOOLEAN, 32, NULL, 0x00000800,
2836
15
          "Event Checking Control: Reg 2 Neg Rearm", HFILL}
2837
15
      },
2838
15
      { &hf_cip_evnt_ctrl_marker_pos,
2839
15
        { "Marker Pos Edge", "cipm.evnt.ctrl.mrkrpos",
2840
15
          FT_BOOLEAN, 32, NULL, 0x00010000,
2841
15
          "Event Checking Control: Marker Pos Edge", HFILL}
2842
15
      },
2843
15
      { &hf_cip_evnt_ctrl_marker_neg,
2844
15
        { "Marker Neg Edge", "cipm.evnt.ctrl.mrkrneg",
2845
15
          FT_BOOLEAN, 32, NULL, 0x00020000,
2846
15
          "Event Checking Control: Marker Neg Edge", HFILL}
2847
15
      },
2848
15
      { &hf_cip_evnt_ctrl_home_pos,
2849
15
        { "Home Pos Edge", "cipm.evnt.ctrl.homepos",
2850
15
          FT_BOOLEAN, 32, NULL, 0x00040000,
2851
15
          "Event Checking Control: Home Pos Edge", HFILL}
2852
15
      },
2853
15
      { &hf_cip_evnt_ctrl_home_neg,
2854
15
        { "Home Neg Edge", "cipm.evnt.ctrl.homeneg",
2855
15
          FT_BOOLEAN, 32, NULL, 0x00080000,
2856
15
          "Event Checking Control: Home Neg Edge", HFILL}
2857
15
      },
2858
15
      { &hf_cip_evnt_ctrl_home_pp,
2859
15
        { "Home-Switch-Marker Plus Plus", "cipm.evnt.ctrl.homepp",
2860
15
          FT_BOOLEAN, 32, NULL, 0x00100000,
2861
15
          "Event Checking Control: Home-Switch-Marker Plus Plus", HFILL}
2862
15
      },
2863
15
      { &hf_cip_evnt_ctrl_home_pm,
2864
15
        { "Home-Switch-Marker Plus Minus", "cipm.evnt.ctrl.homepm",
2865
15
          FT_BOOLEAN, 32, NULL, 0x00200000,
2866
15
          "Event Checking Control: Home-Switch-Marker Plus Minus", HFILL}
2867
15
      },
2868
15
      { &hf_cip_evnt_ctrl_home_mp,
2869
15
        { "Home-Switch-Marker Minus Plus", "cipm.evnt.ctrl.homemp",
2870
15
          FT_BOOLEAN, 32, NULL, 0x00400000,
2871
15
          "Event Checking Control: Home-Switch-Marker Minus Plus", HFILL}
2872
15
      },
2873
15
      { &hf_cip_evnt_ctrl_home_mm,
2874
15
        { "Home-Switch-Marker Minus Minus", "cipm.evnt.ctrl.homemm",
2875
15
          FT_BOOLEAN, 32, NULL, 0x00800000,
2876
15
          "Event Checking Control: Home-Switch-Marker Minus Minus", HFILL}
2877
15
      },
2878
15
      { &hf_cip_evnt_ctrl_acks,
2879
15
        { "Event Block Count", "cipm.evnt.ctrl.acks",
2880
15
          FT_UINT32, BASE_DEC, NULL, 0x70000000,
2881
15
          "Event Checking Control: Event Block Count", HFILL}
2882
15
      },
2883
15
      { &hf_cip_evnt_extend_format,
2884
15
        { "Extended Event Format", "cipm.evnt.extend",
2885
15
          FT_BOOLEAN, 32, NULL, 0x80000000,
2886
15
          "Event Checking Control: Extended Event Format", HFILL}
2887
15
      },
2888
2889
15
      { &hf_cip_evnt_sts_reg1_pos,
2890
15
        { "Reg 1 Pos Edge", "cipm.evnt.sts.reg1posedge",
2891
15
          FT_BOOLEAN, 32, NULL, 0x00000001,
2892
15
          "Event Checking Status: Reg 1 Pos Edge", HFILL}
2893
15
      },
2894
15
      { &hf_cip_evnt_sts_reg1_neg,
2895
15
        { "Reg 1 Neg Edge", "cipm.evnt.sts.reg1negedge",
2896
15
          FT_BOOLEAN, 32, NULL, 0x00000002,
2897
15
          "Event Checking Status: Reg 1 Neg Edge", HFILL }
2898
15
      },
2899
15
      { &hf_cip_evnt_sts_reg2_pos,
2900
15
        { "Reg 2 Pos Edge", "cipm.evnt.sts.reg2posedge",
2901
15
          FT_BOOLEAN, 32, NULL, 0x00000004,
2902
15
          "Event Checking Status: Reg 2 Pos Edge", HFILL}
2903
15
      },
2904
15
      { &hf_cip_evnt_sts_reg2_neg,
2905
15
        { "Reg 2 Neg Edge", "cipm.evnt.sts.reg2negedge",
2906
15
          FT_BOOLEAN, 32, NULL, 0x00000008,
2907
15
          "Event Checking Status: Reg 2 Neg Edge", HFILL}
2908
15
      },
2909
15
      { &hf_cip_evnt_sts_reg1_posrearm,
2910
15
        { "Reg 1 Pos Rearm", "cipm.evnt.sts.reg1posrearm",
2911
15
          FT_BOOLEAN, 32, NULL, 0x00000100,
2912
15
          "Event Checking Status: Reg 1 Pos Rearm", HFILL}
2913
15
      },
2914
15
      { &hf_cip_evnt_sts_reg1_negrearm,
2915
15
        { "Reg 1 Neg Rearm", "cipm.evnt.sts.reg1negrearm",
2916
15
          FT_BOOLEAN, 32, NULL, 0x00000200,
2917
15
          "Event Checking Status: Reg 1 Neg Rearm", HFILL}
2918
15
      },
2919
15
      { &hf_cip_evnt_sts_reg2_posrearm,
2920
15
        { "Reg 2 Pos Rearm", "cipm.evnt.sts.reg2posrearm",
2921
15
          FT_BOOLEAN, 32, NULL, 0x00000400,
2922
15
          "Event Checking Status: Reg 2 Pos Rearm", HFILL}
2923
15
      },
2924
15
      { &hf_cip_evnt_sts_reg2_negrearm,
2925
15
        { "Reg 2 Neg Rearm", "cipm.evnt.sts.reg2negrearm",
2926
15
          FT_BOOLEAN, 32, NULL, 0x00000800,
2927
15
          "Event Checking Status: Reg 2 Neg Rearm", HFILL}
2928
15
      },
2929
15
      { &hf_cip_evnt_sts_marker_pos,
2930
15
        { "Marker Pos Edge", "cipm.evnt.sts.mrkrpos",
2931
15
          FT_BOOLEAN, 32, NULL, 0x00010000,
2932
15
          "Event Checking Status: Marker Pos Edge", HFILL}
2933
15
      },
2934
15
      { &hf_cip_evnt_sts_marker_neg,
2935
15
        { "Marker Neg Edge", "cipm.evnt.sts.mrkrneg",
2936
15
          FT_BOOLEAN, 32, NULL, 0x00020000,
2937
15
          "Event Checking Status: Marker Neg Edge", HFILL }
2938
15
      },
2939
15
      { &hf_cip_evnt_sts_home_pos,
2940
15
        { "Home Pos Edge", "cipm.evnt.sts.homepos",
2941
15
          FT_BOOLEAN, 32, NULL, 0x00040000,
2942
15
          "Event Checking Status: Home Pos Edge", HFILL}
2943
15
      },
2944
15
      { &hf_cip_evnt_sts_home_neg,
2945
15
        { "Home Neg Edge", "cipm.evnt.sts.homeneg",
2946
15
          FT_BOOLEAN, 32, NULL, 0x00080000,
2947
15
          "Event Checking Status: Home Neg Edge", HFILL }
2948
15
      },
2949
15
      { &hf_cip_evnt_sts_home_pp,
2950
15
        { "Home-Switch-Marker Plus Plus", "cipm.evnt.sts.homepp",
2951
15
          FT_BOOLEAN, 32, NULL, 0x00100000,
2952
15
          "Event Checking Status: Home-Switch-Marker Plus Plus", HFILL}
2953
15
      },
2954
15
      { &hf_cip_evnt_sts_home_pm,
2955
15
        { "Home-Switch-Marker Plus Minus", "cipm.evnt.sts.homepm",
2956
15
          FT_BOOLEAN, 32, NULL, 0x00200000,
2957
15
          "Event Checking Status: Home-Switch-Marker Plus Minus", HFILL}
2958
15
      },
2959
15
      { &hf_cip_evnt_sts_home_mp,
2960
15
        { "Home-Switch-Marker Minus Plus", "cipm.evnt.sts.homemp",
2961
15
          FT_BOOLEAN, 32, NULL, 0x00400000,
2962
15
          "Event Checking Status: Home-Switch-Marker Minus Plus", HFILL}
2963
15
      },
2964
15
      { &hf_cip_evnt_sts_home_mm,
2965
15
        { "Home-Switch-Marker Minus Minus", "cipm.evnt.sts.homemm",
2966
15
          FT_BOOLEAN, 32, NULL, 0x00800000,
2967
15
          "Event Checking Status: Home-Switch-Marker Minus Minus", HFILL}
2968
15
      },
2969
15
      { &hf_cip_evnt_sts_nfs,
2970
15
        { "Event Block Count", "cipm.evnt.sts.nfs",
2971
15
          FT_UINT32, BASE_DEC, NULL, 0x70000000,
2972
15
          "Event Checking Status: Event Block Count", HFILL}
2973
15
      },
2974
2975
15
      { &hf_cip_evnt_sts_stat,
2976
15
        { "Event Status", "cipm.evnt.stat",
2977
15
          FT_UINT8, BASE_DEC|BASE_EXT_STRING, &cip_gs_vals_ext, 0,
2978
15
          "Event Data Block: Event Status", HFILL }
2979
15
      },
2980
15
      { &hf_cip_evnt_type,
2981
15
        { "Event Type", "cipm.evnt.type",
2982
15
          FT_UINT8, BASE_DEC, VALS(cip_event_type_vals), 0,
2983
15
          "Event Data Block: Event Type", HFILL}
2984
15
      },
2985
15
      { &hf_cip_svc_code,
2986
15
        { "Service Code", "cipm.svc.code",
2987
15
          FT_UINT8, BASE_HEX, VALS(cip_sc_vals), 0,
2988
15
          "Service Data Block: Service Code", HFILL}
2989
15
      },
2990
15
      { &hf_cip_svc_sts,
2991
15
        { "General Status", "cipm.svc.sts",
2992
15
          FT_UINT8, BASE_DEC|BASE_EXT_STRING, &cip_gs_vals_ext, 0,
2993
15
          "Service Data Block: General Status", HFILL }
2994
15
      },
2995
15
      { &hf_cip_svc_transction,
2996
15
        { "Transaction Id", "cipm.svc.tranid",
2997
15
          FT_UINT8, BASE_DEC, NULL, 0,
2998
15
          "Service Data Block: Transaction Id", HFILL }
2999
15
      },
3000
15
      { &hf_cip_svc_ext_status,
3001
15
        { "Extended Status", "cipm.svc.extstatus",
3002
15
          FT_UINT8, BASE_DEC, NULL, 0,
3003
15
          "Service Data Block: Extended Status", HFILL }
3004
15
      },
3005
15
      { &hf_cip_svc_data,
3006
15
        { "Service Data", "cipm.svc.data",
3007
15
          FT_BYTES, BASE_NONE, NULL, 0,
3008
15
          "Service Data Block: Data", HFILL }
3009
15
      },
3010
15
      { &hf_cip_attribute_data,
3011
15
        { "Attribute Data", "cipm.attrdata",
3012
15
          FT_BYTES, BASE_NONE, NULL, 0,
3013
15
          "Attribute Service: Data", HFILL }
3014
15
      },
3015
15
      { &hf_cip_ptp_grandmaster,
3016
15
        { "Grandmaster", "cipm.grandmaster",
3017
15
          FT_UINT64, BASE_HEX, NULL, 0,
3018
15
          "Group Sync: Grandmaster Id", HFILL}
3019
15
      },
3020
3021
15
      { &hf_cip_svc_get_axis_attr_sts,
3022
15
        { "Attribute Status", "cipm.getaxisattr.sts",
3023
15
          FT_UINT8, BASE_DEC|BASE_EXT_STRING, &cip_gs_vals_ext, 0,
3024
15
          "Service Channel: Get Axis Attribute List Response Status", HFILL }
3025
15
      },
3026
15
      { &hf_get_axis_attr_list_attribute_cnt,
3027
15
        { "Number of attributes", "cipm.getaxisattr.cnt",
3028
15
          FT_UINT16, BASE_DEC, NULL, 0,
3029
15
          "Service Channel: Get Axis Attribute List Attribute Count", HFILL}
3030
15
      },
3031
15
      { &hf_get_axis_attr_list_attribute_id,
3032
15
        { "Attribute ID", "cipm.getaxisattr.id",
3033
15
          FT_UINT16, BASE_DEC, NULL, 0,
3034
15
          "Service Channel: Get Axis Attribute List Attribute ID", HFILL}
3035
15
      },
3036
15
      { &hf_get_axis_attr_list_dimension,
3037
15
        { "Dimension", "cipm.getaxisattr.dimension",
3038
15
          FT_UINT8, BASE_DEC, NULL, 0,
3039
15
          "Service Channel: Get Axis Attribute List Dimension", HFILL}
3040
15
      },
3041
15
      { &hf_get_axis_attr_list_element_size,
3042
15
        { "Element size", "cipm.getaxisattr.element_size",
3043
15
          FT_UINT8, BASE_DEC, NULL, 0,
3044
15
          "Service Channel: Get Axis Attribute List Element Size", HFILL}
3045
15
      },
3046
15
      { &hf_get_axis_attr_list_start_index,
3047
15
        { "Start index", "cipm.getaxisattr.start_index",
3048
15
          FT_UINT16, BASE_DEC, NULL, 0,
3049
15
          "Service Channel: Get Axis Attribute List Start index", HFILL}
3050
15
      },
3051
15
      { &hf_get_axis_attr_list_data_elements,
3052
15
        { "Data elements", "cipm.getaxisattr.data_elements",
3053
15
          FT_UINT16, BASE_DEC, NULL, 0,
3054
15
          "Service Channel: Get Axis Attribute List Data elements", HFILL}
3055
15
      },
3056
3057
15
      { &hf_cip_svc_set_axis_attr_sts,
3058
15
        { "Attribute Status", "cipm.setaxisattr.sts",
3059
15
          FT_UINT8, BASE_DEC|BASE_EXT_STRING, &cip_gs_vals_ext, 0,
3060
15
          "Service Channel: Set Axis Attribute List Response Status", HFILL }
3061
15
      },
3062
15
      { &hf_set_axis_attr_list_attribute_cnt,
3063
15
        { "Number of attributes", "cipm.setaxisattr.cnt",
3064
15
          FT_UINT16, BASE_DEC, NULL, 0,
3065
15
          "Service Channel: Set Axis Attribute List Attribute Count", HFILL}
3066
15
      },
3067
15
      { &hf_set_axis_attr_list_attribute_id,
3068
15
        { "Attribute ID", "cipm.setaxisattr.id",
3069
15
          FT_UINT16, BASE_DEC, NULL, 0,
3070
15
          "Service Channel: Set Axis Attribute List Attribute ID", HFILL}
3071
15
      },
3072
15
      { &hf_set_axis_attr_list_dimension,
3073
15
        { "Dimension", "cipm.setaxisattr.dimension",
3074
15
          FT_UINT8, BASE_DEC, NULL, 0,
3075
15
          "Service Channel: Set Axis Attribute List Dimension", HFILL}
3076
15
      },
3077
15
      { &hf_set_axis_attr_list_element_size,
3078
15
        { "Element size", "cipm.setaxisattr.element_size",
3079
15
          FT_UINT8, BASE_DEC, NULL, 0,
3080
15
          "Service Channel: Set Axis Attribute List Element Size", HFILL}
3081
15
      },
3082
15
      { &hf_set_axis_attr_list_start_index,
3083
15
        { "Start index", "cipm.setaxisattr.start_index",
3084
15
          FT_UINT16, BASE_DEC, NULL, 0,
3085
15
          "Service Channel: Set Axis Attribute List Start index", HFILL}
3086
15
      },
3087
15
      { &hf_set_axis_attr_list_data_elements,
3088
15
        { "Data elements", "cipm.setaxisattr.data_elements",
3089
15
          FT_UINT16, BASE_DEC, NULL, 0,
3090
15
          "Service Channel: Set Axis Attribute List Data elements", HFILL}
3091
15
      },
3092
3093
15
      { &hf_set_cyclic_list_attribute_cnt,
3094
15
        { "Number of attributes", "cipm.set_cyclic.cnt",
3095
15
          FT_UINT16, BASE_DEC, NULL, 0,
3096
15
          NULL, HFILL}
3097
15
      },
3098
15
      { &hf_set_cyclic_list_attribute_id,
3099
15
        { "Attribute ID", "cipm.set_cyclic.id",
3100
15
          FT_UINT16, BASE_DEC, NULL, 0,
3101
15
          NULL, HFILL}
3102
15
      },
3103
15
      { &hf_set_cyclic_list_read_block_id,
3104
15
        { "Cyclic Read Block ID", "cipm.set_cyclic.read_block_id",
3105
15
          FT_UINT16, BASE_DEC, NULL, 0,
3106
15
          NULL, HFILL}
3107
15
      },
3108
15
      { &hf_set_cyclic_list_attr_sts,
3109
15
        { "Attribute Status", "cipm.set_cyclic.sts",
3110
15
          FT_UINT8, BASE_DEC | BASE_EXT_STRING, &cip_gs_vals_ext, 0,
3111
15
          NULL, HFILL }
3112
15
      },
3113
3114
15
      { &hf_var_devce_instance,
3115
15
        { "Instance Number", "cipm.var_devce.header.instance",
3116
15
          FT_UINT8, BASE_DEC, NULL, 0,
3117
15
          "Variable Device Header: Instance Number", HFILL}
3118
15
      },
3119
15
      { &hf_var_devce_instance_block_size,
3120
15
        { "Instance Block Size", "cipm.var_devce.header.instance_block_size",
3121
15
          FT_UINT8, BASE_DEC|BASE_UNIT_STRING, UNS(&units_word_words), 0,
3122
15
          "Variable Device Header: Instance Block Size", HFILL}
3123
15
      },
3124
15
      { &hf_var_devce_cyclic_block_size,
3125
15
        { "Cyclic Block Size", "cipm.var_devce.header.cyclic_block_size",
3126
15
          FT_UINT8, BASE_DEC|BASE_UNIT_STRING, UNS(&units_word_words), 0,
3127
15
          "Variable Device Header: Cyclic Block Size", HFILL}
3128
15
      },
3129
15
      { &hf_var_devce_cyclic_data_block_size,
3130
15
        { "Cyclic Data Block Size", "cipm.var_devce.header.cyclic_data_block_size",
3131
15
          FT_UINT8, BASE_DEC|BASE_UNIT_STRING, UNS(&units_word_words), 0,
3132
15
          "Variable Device Header: Cyclic Data Block Size", HFILL}
3133
15
      },
3134
15
      { &hf_var_devce_cyclic_rw_block_size,
3135
15
        { "Cyclic Read/Write Block Size", "cipm.var_devce.header.cyclic_rw_block_size",
3136
15
          FT_UINT8, BASE_DEC|BASE_UNIT_STRING, UNS(&units_word_words), 0,
3137
15
          "Variable Device Header: Cyclic Read/Write Block Size", HFILL}
3138
15
      },
3139
15
      { &hf_var_devce_event_block_size,
3140
15
        { "Event Block Size", "cipm.var_devce.header.event_block_size",
3141
15
          FT_UINT8, BASE_DEC|BASE_UNIT_STRING, UNS(&units_word_words), 0,
3142
15
          "Variable Device Header: Event Block Size", HFILL}
3143
15
      },
3144
15
      { &hf_var_devce_service_block_size,
3145
15
        { "Service Block Size", "cipm.var_devce.header.service_block_size",
3146
15
          FT_UINT8, BASE_DEC|BASE_UNIT_STRING, UNS(&units_word_words), 0,
3147
15
          "Variable Device Header: Service Block Size", HFILL}
3148
15
      },
3149
3150
15
      { &hf_cip_axis_alarm,
3151
15
        { "Axis Alarm Code", "cipm.alarm.code",
3152
15
          FT_UINT8, BASE_DEC, NULL, 0,
3153
15
          "Status Data Set: Alarm Code", HFILL }
3154
15
      },
3155
15
      { &hf_cip_axis_sts_local_ctrl,
3156
15
        { "Local Control", "cipm.axis.local",
3157
15
          FT_BOOLEAN, 32, NULL, 0x00000001,
3158
15
          "Axis Status Data Set: Local Control", HFILL }
3159
15
      },
3160
15
      { &hf_cip_axis_sts_alarm,
3161
15
        { "Alarm", "cipm.axis.alarm",
3162
15
          FT_BOOLEAN, 32, NULL, 0x00000002,
3163
15
          "Axis Status Data Set: Alarm", HFILL }
3164
15
      },
3165
15
      { &hf_cip_axis_sts_dc_bus,
3166
15
        { "DC Bus", "cipm.axis.bus",
3167
15
          FT_BOOLEAN, 32, NULL, 0x00000004,
3168
15
          "Axis Status Data Set: DC Bus", HFILL }
3169
15
      },
3170
15
      { &hf_cip_axis_sts_pwr_struct,
3171
15
        { "Power Struct", "cipm.axis.pwr",
3172
15
          FT_BOOLEAN, 32, NULL, 0x00000008,
3173
15
          "Axis Status Data Set: Power Struct", HFILL }
3174
15
      },
3175
15
      { &hf_cip_axis_sts_flux_up,
3176
15
        { "Motor Flux Up", "cipm.axis.flx",
3177
15
          FT_BOOLEAN, 32, NULL, 0x00000010,
3178
15
          "Axis Status Data Set: Motor Flux Up", HFILL }
3179
15
      },
3180
15
      { &hf_cip_axis_sts_tracking,
3181
15
        { "Tracking", "cipm.axis.track",
3182
15
          FT_BOOLEAN, 32, NULL, 0x00000020,
3183
15
          "Axis Status Data Set: Tracking", HFILL }
3184
15
      },
3185
15
      { &hf_cip_axis_sts_pos_lock,
3186
15
        { "Pos Lock", "cipm.axis.poslock",
3187
15
          FT_BOOLEAN, 32, NULL, 0x00000040,
3188
15
          "Axis Status Data Set: Pos Lock", HFILL }
3189
15
      },
3190
15
      { &hf_cip_axis_sts_vel_lock,
3191
15
        { "Vel Lock", "cipm.axis.vellock",
3192
15
          FT_BOOLEAN, 32, NULL, 0x00000080,
3193
15
          "Axis Status Data Set: Vel Lock", HFILL }
3194
15
      },
3195
15
      { &hf_cip_axis_sts_vel_standstill,
3196
15
        { "Vel Standstill", "cipm.axis.nomo",
3197
15
          FT_BOOLEAN, 32, NULL, 0x00000100,
3198
15
          "Axis Status Data Set: Vel Standstill", HFILL }
3199
15
      },
3200
15
      { &hf_cip_axis_sts_vel_threshold,
3201
15
        { "Vel Threshold", "cipm.axis.vthresh",
3202
15
          FT_BOOLEAN, 32, NULL, 0x00000200,
3203
15
          "Axis Status Data Set: Vel Threshold", HFILL }
3204
15
      },
3205
15
      { &hf_cip_axis_sts_vel_limit,
3206
15
        { "Vel Limit", "cipm.axis.vlim",
3207
15
          FT_BOOLEAN, 32, NULL, 0x00000400,
3208
15
          "Axis Status Data Set: Vel Limit", HFILL }
3209
15
      },
3210
15
      { &hf_cip_axis_sts_acc_limit,
3211
15
        { "Acc Limit", "cipm.axis.alim",
3212
15
          FT_BOOLEAN, 32, NULL, 0x00000800,
3213
15
          "Axis Status Data Set: Acc Limit", HFILL }
3214
15
      },
3215
15
      { &hf_cip_axis_sts_dec_limit,
3216
15
        { "Decel Limit", "cipm.axis.dlim",
3217
15
          FT_BOOLEAN, 32, NULL, 0x00001000,
3218
15
          "Axis Status Data Set: Decel Limit", HFILL }
3219
15
      },
3220
15
      { &hf_cip_axis_sts_torque_threshold,
3221
15
        { "Torque Threshold", "cipm.axis.tthresh",
3222
15
          FT_BOOLEAN, 32, NULL, 0x00002000,
3223
15
          "Axis Status Data Set: Torque Threshold", HFILL }
3224
15
      },
3225
15
      { &hf_cip_axis_sts_torque_limit,
3226
15
        { "Torque Limit", "cipm.axis.tlim",
3227
15
          FT_BOOLEAN, 32, NULL, 0x00004000,
3228
15
          "Axis Status Data Set: Torque Limit", HFILL }
3229
15
      },
3230
15
      { &hf_cip_axis_sts_cur_limit,
3231
15
        { "Current Limit", "cipm.axis.ilim",
3232
15
          FT_BOOLEAN, 32, NULL, 0x00008000,
3233
15
          "Axis Status Data Set: Current Limit", HFILL }
3234
15
      },
3235
15
      { &hf_cip_axis_sts_therm_limit,
3236
15
        { "Thermal Limit", "cipm.axis.hot",
3237
15
          FT_BOOLEAN, 32, NULL, 0x00010000,
3238
15
          "Axis Status Data Set: Thermal Limit", HFILL }
3239
15
      },
3240
15
      { &hf_cip_axis_sts_feedback_integ,
3241
15
        { "Feedback Integrity", "cipm.axis.fgood",
3242
15
          FT_BOOLEAN, 32, NULL, 0x00020000,
3243
15
          "Axis Status Data Set: Feedback Integrity", HFILL }
3244
15
      },
3245
15
      { &hf_cip_axis_sts_shutdown,
3246
15
        { "Shutdown", "cipm.axis.sdwn",
3247
15
          FT_BOOLEAN, 32, NULL, 0x00040000,
3248
15
          "Axis Status Data Set: Shutdown", HFILL }
3249
15
      },
3250
15
      { &hf_cip_axis_sts_in_process,
3251
15
        { "In Process", "cipm.axis.inp",
3252
15
          FT_BOOLEAN, 32, NULL, 0x00080000,
3253
15
          "Axis Status Data Set: In Process", HFILL }
3254
15
      },
3255
15
      { &hf_cip_axis_sts_dc_bus_unload,
3256
15
        { "DC Bus Unload", "cipm.axis.dcunload",
3257
15
          FT_BOOLEAN, 32, NULL, 0x00100000,
3258
15
          "Axis Status Data Set: DC Bus Unload", HFILL }
3259
15
      },
3260
15
      { &hf_cip_axis_sts_ac_pwr_loss,
3261
15
        { "AC Power Loss", "cipm.axis.acpwrloss",
3262
15
          FT_BOOLEAN, 32, NULL, 0x00200000,
3263
15
          "Axis Status Data Set: AC Power Loss", HFILL }
3264
15
      },
3265
15
      { &hf_cip_axis_sts_pos_cntrl_mode,
3266
15
        { "Pos Control Mode", "cipm.axis.poscntrl",
3267
15
          FT_BOOLEAN, 32, NULL, 0x00400000,
3268
15
          "Axis Status Data Set: Position Control Mode", HFILL }
3269
15
      },
3270
15
      { &hf_cip_axis_sts_vel_cntrl_mode,
3271
15
        { "Vel Control Mode", "cipm.axis.velcntrl",
3272
15
          FT_BOOLEAN, 32, NULL, 0x00800000,
3273
15
          "Axis Status Data Set: Velocity Control Mode", HFILL }
3274
15
      },
3275
15
      { &hf_cip_axis_sts_trq_cntrl_mode,
3276
15
        { "Torque Control Mode", "cipm.axis.trqcntrl",
3277
15
          FT_BOOLEAN, 32, NULL, 0x01000000,
3278
15
          "Axis Status Data Set: Torque Control Mode", HFILL }
3279
15
      },
3280
3281
      // Attribute #740 - Axis Status 2.
3282
15
      { &hf_cip_axis_status2,
3283
15
      { "Axis Status 2", "cipm.axisstatus2",
3284
15
         FT_UINT32, BASE_HEX, NULL, 0,
3285
15
         NULL, HFILL }
3286
15
      },
3287
15
      { &hf_cip_axis_sts2_motor,
3288
15
      { "Motoring", "cipm.axis2.motor",
3289
15
         FT_BOOLEAN, 32, NULL, 0x00000001,
3290
15
         NULL, HFILL }
3291
15
      },
3292
15
      { &hf_cip_axis_sts2_regenerate,
3293
15
      { "Regenerating", "cipm.axis2.regen",
3294
15
         FT_BOOLEAN, 32, NULL, 0x00000002,
3295
15
         NULL, HFILL }
3296
15
      },
3297
15
      { &hf_cip_axis_sts2_ride_thru,
3298
15
      { "Ride Thru", "cipm.axis2.ridethru",
3299
15
         FT_BOOLEAN, 32, NULL, 0x00000004,
3300
15
         NULL, HFILL }
3301
15
      },
3302
15
      { &hf_cip_axis_sts2_ac_line_sync,
3303
15
      { "AC Line Sync", "cipm.axis2.acsync",
3304
15
         FT_BOOLEAN, 32, NULL, 0x00000008,
3305
15
         NULL, HFILL }
3306
15
      },
3307
15
      { &hf_cip_axis_sts2_bus_volt_lock,
3308
15
      { "Bus Voltage Lock", "cipm.axis2.voltlock",
3309
15
         FT_BOOLEAN, 32, NULL, 0x00000010,
3310
15
         NULL, HFILL }
3311
15
      },
3312
15
      { &hf_cip_axis_sts2_react_pwr_only,
3313
15
      { "Reactive Power Only Mode", "cipm.axis2.reactpwr",
3314
15
         FT_BOOLEAN, 32, NULL, 0x00000020,
3315
15
         NULL, HFILL }
3316
15
      },
3317
15
      { &hf_cip_axis_sts2_volt_ctrl_mode,
3318
15
      { "Voltage Control Mode", "cipm.axis2.voltmode",
3319
15
         FT_BOOLEAN, 32, NULL, 0x00000040,
3320
15
         NULL, HFILL }
3321
15
      },
3322
15
      { &hf_cip_axis_sts2_pwr_loss,
3323
15
      { "Power Loss", "cipm.axis2.pwrloss",
3324
15
         FT_BOOLEAN, 32, NULL, 0x00000080,
3325
15
         NULL, HFILL }
3326
15
      },
3327
15
      { &hf_cip_axis_sts2_ac_volt_sag,
3328
15
      { "AC Line Voltage Sag", "cipm.axis2.voltsag",
3329
15
         FT_BOOLEAN, 32, NULL, 0x00000100,
3330
15
         NULL, HFILL }
3331
15
      },
3332
15
      { &hf_cip_axis_sts2_ac_phase_loss,
3333
15
      { "AC Line Phase Loss", "cipm.axis2.phaseloss",
3334
15
         FT_BOOLEAN, 32, NULL, 0x00000200,
3335
15
         NULL, HFILL }
3336
15
      },
3337
15
      { &hf_cip_axis_sts2_ac_freq_change,
3338
15
      { "AC Line Frequency Change", "cipm.axis2.freqchange",
3339
15
         FT_BOOLEAN, 32, NULL, 0x00000400,
3340
15
         NULL, HFILL }
3341
15
      },
3342
15
      { &hf_cip_axis_sts2_ac_sync_loss,
3343
15
      { "AC Line Sync Loss", "cipm.axis2.syncloss",
3344
15
         FT_BOOLEAN, 32, NULL, 0x00000800,
3345
15
         NULL, HFILL }
3346
15
      },
3347
15
      { &hf_cip_axis_sts2_single_phase,
3348
15
      { "Single Phase", "cipm.axis2.singlephase",
3349
15
         FT_BOOLEAN, 32, NULL, 0x00001000,
3350
15
         NULL, HFILL }
3351
15
      },
3352
3353
15
      { &hf_cip_axis_sts2_bus_volt_limit,
3354
15
        { "Bus Voltage Limit", "cipm.axis2.bus_volt_limit",
3355
15
          FT_BOOLEAN, 32, NULL, 0x00002000,
3356
15
          NULL, HFILL }
3357
15
      },
3358
15
      { &hf_cip_axis_sts2_bus_volt_rate_limit,
3359
15
        { "Bus Voltage Rate Limit", "cipm.axis2.bus_volt_rate_limit",
3360
15
          FT_BOOLEAN, 32, NULL, 0x00004000,
3361
15
          NULL, HFILL }
3362
15
      },
3363
15
      { &hf_cip_axis_sts2_active_current_rate_limit,
3364
15
        { "Active Current Rate Limit", "cipm.axis2.active_current_rate_limit",
3365
15
          FT_BOOLEAN, 32, NULL, 0x00008000,
3366
15
          NULL, HFILL }
3367
15
      },
3368
15
      { &hf_cip_axis_sts2_reactive_current_rate_limit,
3369
15
        { "Reactive Current Rate Limit", "cipm.axis2.reactive_current_rate_limit",
3370
15
          FT_BOOLEAN, 32, NULL, 0x00010000,
3371
15
          NULL, HFILL }
3372
15
      },
3373
15
      { &hf_cip_axis_sts2_reactive_pwr_limit,
3374
15
        { "Reactive Power Limit", "cipm.axis2.reactive_pwr_limit",
3375
15
          FT_BOOLEAN, 32, NULL, 0x00020000,
3376
15
          NULL, HFILL }
3377
15
      },
3378
15
      { &hf_cip_axis_sts2_reactive_pwr_rate_limit,
3379
15
        { "Reactive Power Rate Limit", "cipm.axis2.reactive_pwr_rate_limit",
3380
15
          FT_BOOLEAN, 32, NULL, 0x00040000,
3381
15
          NULL, HFILL }
3382
15
      },
3383
15
      { &hf_cip_axis_sts2_active_current_limit,
3384
15
        { "Active Current Limit", "cipm.axis2.active_current_limit",
3385
15
          FT_BOOLEAN, 32, NULL, 0x00080000,
3386
15
          NULL, HFILL }
3387
15
      },
3388
15
      { &hf_cip_axis_sts2_reactive_current_limit,
3389
15
        { "Reactive Current Limit", "cipm.axis2.reactive_current_limit",
3390
15
          FT_BOOLEAN, 32, NULL, 0x00100000,
3391
15
          NULL, HFILL }
3392
15
      },
3393
15
      { &hf_cip_axis_sts2_motor_pwr_limit,
3394
15
        { "Motoring Power Limit", "cipm.axis2.motor_pwr_limit",
3395
15
          FT_BOOLEAN, 32, NULL, 0x00200000,
3396
15
          NULL, HFILL }
3397
15
      },
3398
15
      { &hf_cip_axis_sts2_regen_pwr_limit,
3399
15
        { "Regenerative Power Limit", "cipm.axis2.regen_pwr_limit",
3400
15
          FT_BOOLEAN, 32, NULL, 0x00400000,
3401
15
          NULL, HFILL }
3402
15
      },
3403
15
      { &hf_cip_axis_sts2_convert_therm_limit,
3404
15
        { "Converter Thermal Limit", "cipm.axis2.convert_therm_limit",
3405
15
          FT_BOOLEAN, 32, NULL, 0x00800000,
3406
15
          NULL, HFILL }
3407
15
      },
3408
3409
15
      { &hf_cip_act_pos,
3410
15
        { "Actual Position", "cipm.actpos",
3411
15
          FT_INT32, BASE_DEC, NULL, 0,
3412
15
          "Cyclic Data Set: Actual Position", HFILL }
3413
15
      },
3414
15
      { &hf_cip_act_pos_64,
3415
15
        { "Actual Position", "cipm.actpos_64",
3416
15
          FT_INT64, BASE_DEC, NULL, 0,
3417
15
          "Cyclic Data Set: Actual Position", HFILL }
3418
15
        },
3419
15
      { &hf_cip_act_vel,
3420
15
        { "Actual Velocity", "cipm.actvel",
3421
15
          FT_FLOAT, BASE_NONE, NULL, 0,
3422
15
          "Cyclic Data Set: Actual Velocity", HFILL }
3423
15
      },
3424
15
      { &hf_cip_act_accel,
3425
15
        { "Actual Acceleration", "cipm.actaccel",
3426
15
          FT_FLOAT, BASE_NONE, NULL, 0,
3427
15
          "Cyclic Data Set: Actual Acceleration", HFILL }
3428
15
      },
3429
15
      { &hf_cip_pos_cmd,
3430
15
        { "Position Command", "cipm.posfcmd",
3431
15
          FT_DOUBLE, BASE_NONE, NULL, 0,
3432
15
          "Cyclic Data Set: Position Command (LREAL)", HFILL }
3433
15
      },
3434
15
      { &hf_cip_pos_cmd_int,
3435
15
        { "Position Command", "cipm.posicmd",
3436
15
          FT_INT32, BASE_DEC, NULL, 0,
3437
15
          "Cyclic Data Set: Position Command (DINT)", HFILL }
3438
15
      },
3439
15
      { &hf_cip_vel_cmd,
3440
15
        { "Velocity Command", "cipm.velcmd",
3441
15
          FT_FLOAT, BASE_NONE, NULL, 0,
3442
15
          "Cyclic Data Set: Velocity Command", HFILL }
3443
15
      },
3444
15
      { &hf_cip_accel_cmd,
3445
15
        { "Acceleration Command", "cipm.accelcmd",
3446
15
          FT_FLOAT, BASE_NONE, NULL, 0,
3447
15
          "Cyclic Data Set: Acceleration Command", HFILL }
3448
15
      },
3449
15
      { &hf_cip_trq_cmd,
3450
15
        { "Torque Command", "cipm.torquecmd",
3451
15
          FT_FLOAT, BASE_NONE, NULL, 0,
3452
15
          "Cyclic Data Set: Torque Command", HFILL }
3453
15
      },
3454
15
      { &hf_cip_pos_trim,
3455
15
        { "Position Trim", "cipm.postrim",
3456
15
          FT_INT32, BASE_DEC, NULL, 0,
3457
15
          NULL, HFILL }
3458
15
      },
3459
15
      { &hf_cip_vel_trim,
3460
15
        { "Velocity Trim", "cipm.veltrim",
3461
15
          FT_FLOAT, BASE_NONE, NULL, 0,
3462
15
          NULL, HFILL }
3463
15
      },
3464
15
      { &hf_cip_accel_trim,
3465
15
        { "Acceleration Trim", "cipm.acceltrim",
3466
15
          FT_FLOAT, BASE_NONE, NULL, 0,
3467
15
          NULL, HFILL }
3468
15
      },
3469
15
      { &hf_cip_trq_trim,
3470
15
        { "Torque Trim", "cipm.trqtrim",
3471
15
          FT_FLOAT, BASE_NONE, NULL, 0,
3472
15
          NULL, HFILL }
3473
15
      },
3474
15
      { &hf_cip_data,
3475
15
        { "Data", "cipm.data",
3476
15
        FT_BYTES, BASE_NONE, NULL, 0,
3477
15
          NULL, HFILL }
3478
15
      }
3479
15
   };
3480
3481
   /* Setup protocol subtree array, these will help Wireshark remember
3482
   * if the subtree should be expanded as the user moves through packets */
3483
15
   static int *ett[] = {
3484
15
      &ett_cipmotion,
3485
15
      &ett_cont_dev_header,
3486
15
      &ett_control_status,
3487
15
      &ett_node_control,
3488
15
      &ett_node_status,
3489
15
      &ett_time_data_set,
3490
15
      &ett_inst_data_header,
3491
15
      &ett_cyclic_data_block,
3492
15
      &ett_cyclic_command_data,
3493
15
      &ett_feedback_mode,
3494
15
      &ett_connection_configuration_bits,
3495
15
      &ett_control_mode,
3496
15
      &ett_feedback_config,
3497
15
      &ett_command_data_set,
3498
15
      &ett_actual_data_set,
3499
15
      &ett_status_data_set,
3500
15
      &ett_interp_control,
3501
15
      &ett_cyclic_rd_wt,
3502
15
      &ett_event,
3503
15
      &ett_event_check_ctrl,
3504
15
      &ett_event_check_sts,
3505
15
      &ett_service,
3506
15
      &ett_get_axis_attribute,
3507
15
      &ett_set_axis_attribute,
3508
15
      &ett_get_axis_attr_list,
3509
15
      &ett_set_axis_attr_list,
3510
15
      &ett_set_cyclic_list,
3511
15
      &ett_group_sync,
3512
15
      &ett_axis_status_set,
3513
15
      &ett_command_control,
3514
15
      &ett_configuration_block
3515
15
   };
3516
3517
15
   static ei_register_info ei[] = {
3518
15
      { &ei_format_rev_conn_pt, { "cipm.malformed.format_revision_mismatch", PI_MALFORMED, PI_WARN, "Format Revision does not match Connection Point", EXPFILL } },
3519
15
   };
3520
3521
   /* Create a CIP Motion protocol handle */
3522
15
   proto_cipmotion = proto_register_protocol("Common Industrial Protocol, Motion", "CIP Motion", "cipm");
3523
3524
15
   proto_cipmotion3 = proto_register_protocol_in_name_only(
3525
15
     "Common Industrial Protocol, Motion - Rev 3",
3526
15
     "CIP Motion - Rev 3",
3527
15
     "cipm3",
3528
15
     proto_cipmotion,
3529
15
     FT_PROTOCOL);
3530
3531
   /* Register the header fields with the protocol */
3532
15
   proto_register_field_array(proto_cipmotion, hf, array_length(hf));
3533
3534
   /* Register the subtrees for the protocol dissection */
3535
15
   proto_register_subtree_array(ett, array_length(ett));
3536
3537
15
   expert_module_t* expert_cipm = expert_register_protocol(proto_cipmotion);
3538
15
   expert_register_field_array(expert_cipm, ei, array_length(ei));
3539
3540
15
   module_t* cipm_module = prefs_register_protocol(proto_cipmotion, NULL);
3541
15
   prefs_register_bool_preference(cipm_module, "display_full_attribute_data",
3542
15
      "Display full attribute data in the Service Data Block",
3543
15
      "Whether the CIP Motion dissector always display the full raw attribute data bytes",
3544
15
      &display_full_attribute_data);
3545
3546
15
   cipmotion_handle = register_dissector("cipmotion", dissect_cipmotion, proto_cipmotion);
3547
15
   cipmotion3_handle = register_dissector("cipmotion3", dissect_cipmotion3, proto_cipmotion3);
3548
15
}
3549
3550
void proto_reg_handoff_cipmotion(void)
3551
15
{
3552
15
   dissector_add_for_decode_as("cip.io", cipmotion_handle);
3553
15
   dissector_add_for_decode_as("cip.io", cipmotion3_handle);
3554
3555
15
   dissector_add_uint("cip.io.iface", CI_CLS_MOTION, cipmotion_handle);
3556
15
}
3557
3558
/*
3559
* Editor modelines - https://www.wireshark.org/tools/modelines.html
3560
*
3561
* Local variables:
3562
* c-basic-offset: 3
3563
* tab-width: 8
3564
* indent-tabs-mode: nil
3565
* End:
3566
*
3567
* ex: set shiftwidth=3 tabstop=8 expandtab:
3568
* :indentSize=3:tabSize=8:noTabs=true:
3569
*/