checkAPIs.pl: support for new-style dissectors in check_hf_entries
[metze/wireshark/wip.git] / epan / dissectors / packet-cipmotion.c
index ba2fddcf5fe9a3490cbee21c4ccc64a95d636927..de0d94881afd36b2bce8e4737d721f9062afcde2 100644 (file)
@@ -2,43 +2,35 @@
  * Routines for CIP (Common Industrial Protocol) Motion dissection
  * CIP Motion Home: www.odva.org
  *
+ * This dissector includes items from:
+ *    CIP Volume 9: CIP Motion, Edition 1.2
+ *
  * Copyright 2006-2007
  * Benjamin M. Stocks <bmstocks@ra.rockwell.com>
  *
- * $Id$
- *
  * Wireshark - Network traffic analyzer
  * By Gerald Combs <gerald@wireshark.org>
  * Copyright 1998 Gerald Combs
  *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * SPDX-License-Identifier: GPL-2.0-or-later
  */
 
-#ifdef HAVE_CONFIG_H
-# include "config.h"
-#endif
+#include "config.h"
 
 #include <epan/packet.h>
-#include <epan/emem.h>
-#include <epan/expert.h>
+
+#include "packet-cipmotion.h"
+
 #include "packet-cip.h"
+#include "packet-enip.h"
 
-/* The entry point to the actual disection is: dissect_cipmotion */
+void proto_register_cipmotion(void);
+/* The entry point to the actual dissection is: dissect_cipmotion */
+void proto_reg_handoff_cipmotion(void);
 
 /* Protocol handle for CIP Motion */
 static int proto_cipmotion = -1;
+static int proto_cipmotion3 = -1;
 
 /* Header field identifiers, these are registered in the
  * proto_register_cipmotion function along with the bites/bytes
@@ -71,31 +63,27 @@ static int hf_cip_data_rx_time_stamp        = -1;
 static int hf_cip_data_tx_time_stamp        = -1;
 static int hf_cip_node_fltalarms            = -1;
 static int hf_cip_motor_cntrl               = -1;
-static int hf_cip_fdbk_config               = -1;
+static int hf_cip_feedback_mode             = -1;
 static int hf_cip_axis_control              = -1;
 static int hf_cip_control_status            = -1;
+static int hf_cip_control_status_complete   = -1;
+static int hf_cip_control_status_bus_up     = -1;
+static int hf_cip_control_status_bus_unload = -1;
+static int hf_cip_control_status_power_loss = -1;
 static int hf_cip_axis_response             = -1;
 static int hf_cip_axis_resp_stat            = -1;
 static int hf_cip_cmd_data_pos_cmd          = -1;
 static int hf_cip_cmd_data_vel_cmd          = -1;
 static int hf_cip_cmd_data_acc_cmd          = -1;
 static int hf_cip_cmd_data_trq_cmd          = -1;
-static int hf_cip_cmd_data_pos_trim_cmd     = -1;
-static int hf_cip_cmd_data_vel_trim_cmd     = -1;
-static int hf_cip_cmd_data_acc_trim_cmd     = -1;
-static int hf_cip_cmd_data_trq_trim_cmd     = -1;
 static int hf_cip_act_data_pos              = -1;
 static int hf_cip_act_data_vel              = -1;
 static int hf_cip_act_data_acc              = -1;
-static int hf_cip_act_data_trq              = -1;
-static int hf_cip_act_data_crnt             = -1;
-static int hf_cip_act_data_vltg             = -1;
-static int hf_cip_act_data_fqcy             = -1;
 static int hf_cip_sts_flt                   = -1;
 static int hf_cip_sts_alrm                  = -1;
 static int hf_cip_sts_sts                   = -1;
 static int hf_cip_sts_iosts                 = -1;
-static int hf_cip_sts_safety                = -1;
+static int hf_cip_sts_axis_safety           = -1;
 static int hf_cip_intrp                     = -1;
 static int hf_cip_position_data_type        = -1;
 static int hf_cip_axis_state                = -1;
@@ -150,6 +138,7 @@ static int hf_cip_axis_sts_local_ctrl       = -1;
 static int hf_cip_axis_sts_alarm            = -1;
 static int hf_cip_axis_sts_dc_bus           = -1;
 static int hf_cip_axis_sts_pwr_struct       = -1;
+static int hf_cip_axis_sts_flux_up          = -1;
 static int hf_cip_axis_sts_tracking         = -1;
 static int hf_cip_axis_sts_pos_lock         = -1;
 static int hf_cip_axis_sts_vel_lock         = -1;
@@ -165,6 +154,11 @@ static int hf_cip_axis_sts_therm_limit      = -1;
 static int hf_cip_axis_sts_feedback_integ   = -1;
 static int hf_cip_axis_sts_shutdown         = -1;
 static int hf_cip_axis_sts_in_process       = -1;
+static int hf_cip_axis_sts_dc_bus_unload    = -1;
+static int hf_cip_axis_sts_ac_pwr_loss      = -1;
+static int hf_cip_axis_sts_pos_cntrl_mode   = -1;
+static int hf_cip_axis_sts_vel_cntrl_mode   = -1;
+static int hf_cip_axis_sts_trq_cntrl_mode   = -1;
 static int hf_cip_cyclic_wrt_data           = -1;
 static int hf_cip_cyclic_rd_data            = -1;
 static int hf_cip_cyclic_write_blk          = -1;
@@ -190,10 +184,6 @@ static int hf_cip_trq_trim                  = -1;
 static int hf_cip_act_pos                   = -1;
 static int hf_cip_act_vel                   = -1;
 static int hf_cip_act_accel                 = -1;
-static int hf_cip_act_trq                   = -1;
-static int hf_cip_act_crnt                  = -1;
-static int hf_cip_act_volts                 = -1;
-static int hf_cip_act_freq                  = -1;
 static int hf_cip_fault_type                = -1;
 static int hf_cip_fault_sub_code            = -1;
 static int hf_cip_fault_action              = -1;
@@ -206,7 +196,9 @@ static int hf_cip_axis_status               = -1;
 static int hf_cip_axis_status_mfg           = -1;
 static int hf_cip_axis_io_status            = -1;
 static int hf_cip_axis_io_status_mfg        = -1;
-static int hf_cip_safety_status             = -1;
+static int hf_cip_axis_safety_status        = -1;
+static int hf_cip_axis_safety_status_mfg    = -1;
+static int hf_cip_axis_safety_state         = -1;
 static int hf_cip_cmd_data_set              = -1;
 static int hf_cip_act_data_set              = -1;
 static int hf_cip_sts_data_set              = -1;
@@ -232,10 +224,12 @@ static int hf_var_devce_cyclic_data_block_size     = -1;
 static int hf_var_devce_cyclic_rw_block_size       = -1;
 static int hf_var_devce_event_block_size           = -1;
 static int hf_var_devce_service_block_size         = -1;
+static int hf_cip_data                             = -1;
 
 /* Subtree pointers for the dissection */
 static gint ett_cipmotion           = -1;
 static gint ett_cont_dev_header     = -1;
+static gint ett_control_status      = -1;
 static gint ett_node_control        = -1;
 static gint ett_node_status         = -1;
 static gint ett_time_data_set       = -1;
@@ -260,6 +254,9 @@ static gint ett_group_sync          = -1;
 static gint ett_axis_status_set     = -1;
 static gint ett_command_control     = -1;
 
+static dissector_handle_t cipmotion_handle;
+static dissector_handle_t cipmotion3_handle;
+
 /* These are the BITMASKS for the Time Data Set header field */
 #define TIME_DATA_SET_TIME_STAMP                0x1
 #define TIME_DATA_SET_TIME_OFFSET               0x2
@@ -271,26 +268,18 @@ static gint ett_command_control     = -1;
 #define COMMAND_DATA_SET_VELOCITY           0x02
 #define COMMAND_DATA_SET_ACCELERATION       0x04
 #define COMMAND_DATA_SET_TORQUE             0x08
-#define COMMAND_DATA_SET_POSITION_TRIM      0x10
-#define COMMAND_DATA_SET_VELOCITY_TRIM      0x20
-#define COMMAND_DATA_SET_ACCELERATION_TRIM  0x40
-#define COMMAND_DATA_SET_TORQUE_TRIM        0x80
 
 /* These are the BITMASKS for the Actual Data Set cyclic field */
 #define ACTUAL_DATA_SET_POSITION        0x01
 #define ACTUAL_DATA_SET_VELOCITY        0x02
 #define ACTUAL_DATA_SET_ACCELERATION    0x04
-#define ACTUAL_DATA_SET_TORQUE          0x08
-#define ACTUAL_DATA_SET_CURRENT         0x10
-#define ACTUAL_DATA_SET_VOLTAGE         0x20
-#define ACTUAL_DATA_SET_FREQUENCY       0x40
 
 /* These are the BITMASKS for the Status Data Set cyclic field */
 #define STATUS_DATA_SET_AXIS_FAULT              0x01
 #define STATUS_DATA_SET_AXIS_ALARM              0x02
 #define STATUS_DATA_SET_AXIS_STATUS             0x04
 #define STATUS_DATA_SET_AXIS_IO_STATUS          0x08
-#define STATUS_DATA_SET_AXIS_SAFETY             0x80
+#define STATUS_DATA_SET_AXIS_SAFETY             0x10
 
 /* These are the BITMASKS for the Command Control cyclic field */
 #define COMMAND_CONTROL_TARGET_UPDATE       0x03
@@ -303,6 +292,8 @@ static gint ett_command_control     = -1;
 #define FORMAT_VAR_CONTROL_TO_DEVICE        6
 #define FORMAT_VAR_DEVICE_TO_CONTROL        7
 
+#define FEEDBACK_MODE_BITS             0x0F
+
 /* Translate function to string - connection format values */
 static const value_string cip_con_format_vals[] = {
    { FORMAT_FIXED_CONTROL_TO_DEVICE,       "Fixed Controller-to-Device"        },
@@ -319,12 +310,11 @@ static const value_string cip_motor_control_vals[] = {
    { 2,    "Velocity Control"      },
    { 3,    "Acceleration Control"  },
    { 4,    "Torque Control"        },
-   { 5,    "Current Control"       },
    { 0,    NULL                    }
 };
 
-/* Translate function to string - feedback config values */
-static const value_string cip_fdbk_config_vals[] = {
+/* Translate function to string - feedback mode values */
+static const value_string cip_feedback_mode_vals[] = {
    { 0,    "No Feedback"       },
    { 1,    "Master Feedback"   },
    { 2,    "Motor Feedback"    },
@@ -338,7 +328,7 @@ static const value_string cip_axis_control_vals[] =
 {
    { 0,    "No Request"               },
    { 1,    "Enable Request"           },
-   { 2,    "Disble Request"           },
+   { 2,    "Disable Request"          },
    { 3,    "Shutdown Request"         },
    { 4,    "Shutdown Reset Request"   },
    { 5,    "Abort Request"            },
@@ -350,13 +340,6 @@ static const value_string cip_axis_control_vals[] =
    { 0,    NULL                       }
 };
 
-/* Translate function to string - control status values */
-static const value_string cip_control_status_vals[] =
-{
-   { 1,    "Configuration Complete"   },
-   { 0,    NULL                       }
-};
-
 /* Translate function to string - group sync Status */
 static const value_string cip_sync_status_vals[] =
 {
@@ -387,20 +370,24 @@ static const value_string cip_pos_data_type_vals[] = {
 
 /* Translate function to string - axis response values */
 static const value_string cip_axis_response_vals[] = {
-   { 0,    "No Acknowlede"                 },
+   { 0,    "No Acknowledge"                 },
    { 1,    "Enable Acknowledge"            },
    { 2,    "Disable Acknowledge"           },
    { 3,    "Shutdown Acknowledge"          },
    { 4,    "Shutdown Reset Acknowledge"    },
    { 5,    "Abort Acknowledge"             },
    { 6,    "Fault Reset Acknowledge"       },
+   { 7,    "Stop Process Acknowledge"      },
+   { 8,    "Change Actual Position Reference Acknowledge" },
+   { 9,    "Change Command Position Reference Acknowledge" },
+   { 127,  "Cancel Acknowledge"            },
    { 0,    NULL                            }
 };
 
 /* Translate function to string - axis state values */
 static const value_string cip_axis_state_vals[] = {
    { 0,    "Initializing"      },
-   { 1,    "Pre-charging"      },
+   { 1,    "Pre-Charge"        },
    { 2,    "Stopped"           },
    { 3,    "Starting"          },
    { 4,    "Running"           },
@@ -439,7 +426,7 @@ static const value_string cip_event_type_vals[] = {
 #define SC_RUN_INERTIA_TEST         0x51
 #define SC_GET_INERTIA_TEST_DATA    0x52
 #define SC_RUN_HOOKUP_TEST          0x53
-#define SC_GET_HOOKUP_TEST_DATA     0x53
+#define SC_GET_HOOKUP_TEST_DATA     0x54
 
 /* Translate function to string - CIP Service codes */
 static const value_string cip_sc_vals[] = {
@@ -451,12 +438,222 @@ static const value_string cip_sc_vals[] = {
    { SC_RUN_MOTOR_TEST,            "Run Motor Test"            },
    { SC_GET_MOTOR_TEST_DATA,       "Get Motor Test Data"       },
    { SC_RUN_INERTIA_TEST,          "Run Inertia Test"          },
-   { SC_GET_INERTIA_TEST_DATA,     "Get Intertia Test Data"    },
+   { SC_GET_INERTIA_TEST_DATA,     "Get Inertia Test Data"     },
    { SC_RUN_HOOKUP_TEST,           "Run Hookup Test"           },
    { SC_GET_HOOKUP_TEST_DATA,      "Get Hookup Test Data"      },
    { 0,                            NULL                        }
 };
 
+static int dissect_axis_status(packet_info *pinfo _U_, proto_tree *tree, proto_item *item _U_, tvbuff_t *tvb,
+   int offset, int total_len _U_)
+{
+   static const int* bits[] = {
+      &hf_cip_axis_sts_local_ctrl,
+      &hf_cip_axis_sts_alarm,
+      &hf_cip_axis_sts_dc_bus,
+      &hf_cip_axis_sts_pwr_struct,
+      &hf_cip_axis_sts_flux_up,
+      &hf_cip_axis_sts_tracking,
+      &hf_cip_axis_sts_pos_lock,
+      &hf_cip_axis_sts_vel_lock,
+      &hf_cip_axis_sts_vel_standstill,
+      &hf_cip_axis_sts_vel_threshold,
+      &hf_cip_axis_sts_vel_limit,
+      &hf_cip_axis_sts_acc_limit,
+      &hf_cip_axis_sts_dec_limit,
+      &hf_cip_axis_sts_torque_threshold,
+      &hf_cip_axis_sts_torque_limit,
+      &hf_cip_axis_sts_cur_limit,
+      &hf_cip_axis_sts_therm_limit,
+      &hf_cip_axis_sts_feedback_integ,
+      &hf_cip_axis_sts_shutdown,
+      &hf_cip_axis_sts_in_process,
+      &hf_cip_axis_sts_dc_bus_unload,
+      &hf_cip_axis_sts_ac_pwr_loss,
+      &hf_cip_axis_sts_pos_cntrl_mode,
+      &hf_cip_axis_sts_vel_cntrl_mode,
+      &hf_cip_axis_sts_trq_cntrl_mode,
+      NULL
+   };
+
+   proto_tree_add_bitmask(tree, tvb, offset, hf_cip_axis_status, ett_axis_status_set, bits, ENC_LITTLE_ENDIAN);
+
+   return 4;
+}
+
+static int dissect_event_checking_control(packet_info *pinfo _U_, proto_tree *tree, proto_item *item _U_, tvbuff_t *tvb,
+   int offset, int total_len _U_)
+{
+   static const int* bits[] = {
+      &hf_cip_evnt_ctrl_reg1_pos,
+      &hf_cip_evnt_ctrl_reg1_neg,
+      &hf_cip_evnt_ctrl_reg2_pos,
+      &hf_cip_evnt_ctrl_reg2_neg,
+      &hf_cip_evnt_ctrl_reg1_posrearm,
+      &hf_cip_evnt_ctrl_reg1_negrearm,
+      &hf_cip_evnt_ctrl_reg2_posrearm,
+      &hf_cip_evnt_ctrl_reg2_negrearm,
+      &hf_cip_evnt_ctrl_marker_pos,
+      &hf_cip_evnt_ctrl_marker_neg,
+      &hf_cip_evnt_ctrl_home_pos,
+      &hf_cip_evnt_ctrl_home_neg,
+      &hf_cip_evnt_ctrl_home_pp,
+      &hf_cip_evnt_ctrl_home_pm,
+      &hf_cip_evnt_ctrl_home_mp,
+      &hf_cip_evnt_ctrl_home_mm,
+      &hf_cip_evnt_ctrl_acks,
+      // The dissector will indicate if the protocol is requesting an extended event format but will not dissect it.
+      &hf_cip_evnt_extend_format,
+      NULL
+   };
+
+   proto_tree_add_bitmask(tree, tvb, offset, hf_cip_event_checking, ett_event_check_ctrl, bits, ENC_LITTLE_ENDIAN);
+
+   return 4;
+}
+
+static int dissect_event_checking_status(packet_info *pinfo _U_, proto_tree *tree, proto_item *item _U_, tvbuff_t *tvb,
+   int offset, int total_len _U_)
+{
+   static const int* bits[] = {
+      &hf_cip_evnt_sts_reg1_pos,
+      &hf_cip_evnt_sts_reg1_neg,
+      &hf_cip_evnt_sts_reg2_pos,
+      &hf_cip_evnt_sts_reg2_neg,
+      &hf_cip_evnt_sts_reg1_posrearm,
+      &hf_cip_evnt_sts_reg1_negrearm,
+      &hf_cip_evnt_sts_reg2_posrearm,
+      &hf_cip_evnt_sts_reg2_negrearm,
+      &hf_cip_evnt_sts_marker_pos,
+      &hf_cip_evnt_sts_marker_neg,
+      &hf_cip_evnt_sts_home_pos,
+      &hf_cip_evnt_sts_home_neg,
+      &hf_cip_evnt_sts_home_pp,
+      &hf_cip_evnt_sts_home_pm,
+      &hf_cip_evnt_sts_home_mp,
+      &hf_cip_evnt_sts_home_mm,
+      &hf_cip_evnt_sts_nfs,
+      // The dissector will indicate if the protocol is requesting an extended event format but will not dissect it.
+      &hf_cip_evnt_extend_format,
+      NULL
+   };
+
+   proto_tree_add_bitmask(tree, tvb, offset, hf_cip_event_status, ett_event_check_sts, bits, ENC_LITTLE_ENDIAN);
+
+   return 4;
+}
+
+static int dissect_actual_data_set_bits(packet_info *pinfo _U_, proto_tree *tree, proto_item *item _U_, tvbuff_t *tvb,
+   int offset, int total_len _U_)
+{
+   static const int* bits[] = {
+      &hf_cip_act_data_pos,
+      &hf_cip_act_data_vel,
+      &hf_cip_act_data_acc,
+      NULL
+   };
+
+   proto_tree_add_bitmask(tree, tvb, offset, hf_cip_act_data_set, ett_actual_data_set, bits, ENC_LITTLE_ENDIAN);
+
+   return 1;
+}
+
+static int dissect_command_data_set_bits(packet_info *pinfo _U_, proto_tree *tree, proto_item *item _U_, tvbuff_t *tvb,
+   int offset, int total_len _U_)
+{
+   static const int* bits[] = {
+      &hf_cip_cmd_data_pos_cmd,
+      &hf_cip_cmd_data_vel_cmd,
+      &hf_cip_cmd_data_acc_cmd,
+      &hf_cip_cmd_data_trq_cmd,
+      NULL
+   };
+
+   proto_tree_add_bitmask(tree, tvb, offset, hf_cip_cmd_data_set, ett_command_data_set, bits, ENC_LITTLE_ENDIAN);
+
+   return 1;
+}
+
+static int dissect_command_control(packet_info *pinfo _U_, proto_tree *tree, proto_item *item _U_, tvbuff_t *tvb,
+   int offset, int total_len _U_)
+{
+   static const int* bits[] = {
+      &hf_cip_intrp,
+      &hf_cip_position_data_type,
+      NULL
+   };
+
+   proto_tree_add_bitmask(tree, tvb, offset, hf_cip_command_control, ett_command_control, bits, ENC_LITTLE_ENDIAN);
+
+   return 1;
+}
+
+
+static int dissect_node_control(packet_info *pinfo _U_, proto_tree *tree, proto_item *item _U_, tvbuff_t *tvb,
+   int offset, int total_len _U_)
+{
+   static const int* bits[] = {
+      &hf_cip_node_control_remote,
+      &hf_cip_node_control_sync,
+      &hf_cip_node_data_valid,
+      &hf_cip_node_fault_reset,
+      NULL
+   };
+
+   proto_tree_add_bitmask(tree, tvb, offset, hf_cip_node_control, ett_node_control, bits, ENC_LITTLE_ENDIAN);
+
+   return 1;
+}
+
+static int dissect_node_status(packet_info *pinfo _U_, proto_tree *tree, proto_item *item _U_, tvbuff_t *tvb,
+   int offset, int total_len _U_)
+{
+   static const int* bits[] = {
+      &hf_cip_node_control_remote,
+      &hf_cip_node_control_sync,
+      &hf_cip_node_data_valid,
+      &hf_cip_node_device_faulted,
+      NULL
+   };
+
+   proto_tree_add_bitmask(tree, tvb, offset, hf_cip_node_status, ett_node_status, bits, ENC_LITTLE_ENDIAN);
+
+   return 1;
+}
+
+static int dissect_control_status(packet_info *pinfo _U_, proto_tree *tree, proto_item *item _U_, tvbuff_t *tvb,
+   int offset, int total_len _U_)
+{
+   static const int* bits[] = {
+      &hf_cip_control_status_complete,
+      &hf_cip_control_status_bus_up,
+      &hf_cip_control_status_bus_unload,
+      &hf_cip_control_status_power_loss,
+      NULL
+   };
+
+   proto_tree_add_bitmask(tree, tvb, offset, hf_cip_control_status, ett_control_status, bits, ENC_LITTLE_ENDIAN);
+
+   return 1;
+}
+
+attribute_info_t cip_motion_attribute_vals[] = {
+   { CI_CLS_MOTION, CIP_ATTR_CLASS, 14, -1, "Node Control", cip_dissector_func, NULL, dissect_node_control },
+   { CI_CLS_MOTION, CIP_ATTR_CLASS, 15, -1, "Node Status", cip_dissector_func, NULL, dissect_node_status },
+   { CI_CLS_MOTION, CIP_ATTR_INSTANCE, 40, -1, "Control Mode", cip_usint, &hf_cip_motor_cntrl, NULL },
+   { CI_CLS_MOTION, CIP_ATTR_INSTANCE, 60, -1, "Event Checking Control", cip_dissector_func, NULL, dissect_event_checking_control },
+   { CI_CLS_MOTION, CIP_ATTR_INSTANCE, 61, -1, "Event Checking Status", cip_dissector_func, NULL, dissect_event_checking_status },
+   { CI_CLS_MOTION, CIP_ATTR_INSTANCE, 89, -1, "Control Status", cip_dissector_func, NULL, dissect_control_status },
+   { CI_CLS_MOTION, CIP_ATTR_INSTANCE, 90, -1, "Actual Data Set", cip_dissector_func, NULL, dissect_actual_data_set_bits },
+   { CI_CLS_MOTION, CIP_ATTR_INSTANCE, 91, -1, "Command Data Set", cip_dissector_func, NULL, dissect_command_data_set_bits },
+   { CI_CLS_MOTION, CIP_ATTR_INSTANCE, 92, -1, "Command Control", cip_dissector_func, NULL, dissect_command_control },
+   { CI_CLS_MOTION, CIP_ATTR_INSTANCE, 431, -1, "Position Trim", cip_dint, &hf_cip_pos_trim, NULL },
+   { CI_CLS_MOTION, CIP_ATTR_INSTANCE, 451, -1, "Velocity Trim", cip_real, &hf_cip_vel_trim, NULL },
+   { CI_CLS_MOTION, CIP_ATTR_INSTANCE, 481, -1, "Acceleration Trim", cip_real, &hf_cip_accel_trim, NULL },
+   { CI_CLS_MOTION, CIP_ATTR_INSTANCE, 491, -1, "Torque Trim", cip_real, &hf_cip_trq_trim, NULL },
+   { CI_CLS_MOTION, CIP_ATTR_INSTANCE, 651, -1, "Axis Status", cip_dissector_func, NULL, dissect_axis_status },
+};
+
 /*
  * Function name: dissect_cmd_data_set
  *
@@ -471,7 +668,7 @@ dissect_cmd_data_set(guint32 cmd_data_set, proto_tree* tree, tvbuff_t* tvb, guin
    guint32 bytes_used = 0;
 
    /* The order of these if statements is VERY important, this is the order the values will
-   * appear in the cyclic data */
+    * appear in the cyclic data */
    if ( (cmd_data_set & COMMAND_DATA_SET_POSITION) == COMMAND_DATA_SET_POSITION )
    {
       /* Based on the Command Position Data Type value embedded in the Command Control
@@ -511,34 +708,6 @@ dissect_cmd_data_set(guint32 cmd_data_set, proto_tree* tree, tvbuff_t* tvb, guin
       bytes_used += 4;
    }
 
-   if ( (cmd_data_set & COMMAND_DATA_SET_POSITION_TRIM) == COMMAND_DATA_SET_POSITION_TRIM )
-   {
-      /* Display the command data set position trim value */
-      proto_tree_add_item(tree, hf_cip_pos_trim, tvb, offset + bytes_used, 4, ENC_LITTLE_ENDIAN );
-      bytes_used += 4;
-   }
-
-   if ( (cmd_data_set & COMMAND_DATA_SET_VELOCITY_TRIM) == COMMAND_DATA_SET_VELOCITY_TRIM )
-   {
-      /* Display the command data set velocity trim value */
-      proto_tree_add_item(tree, hf_cip_vel_trim, tvb, offset + bytes_used, 4, ENC_LITTLE_ENDIAN );
-      bytes_used += 4;
-   }
-
-   if ( (cmd_data_set & COMMAND_DATA_SET_ACCELERATION_TRIM) == COMMAND_DATA_SET_ACCELERATION_TRIM )
-   {
-      /* Display the command data set acceleration trim value */
-      proto_tree_add_item(tree, hf_cip_accel_trim, tvb, offset + bytes_used, 4, ENC_LITTLE_ENDIAN );
-      bytes_used += 4;
-   }
-
-   if ( (cmd_data_set & COMMAND_DATA_SET_TORQUE_TRIM) == COMMAND_DATA_SET_TORQUE_TRIM )
-   {
-      /* Display the command data set torque trim value */
-      proto_tree_add_item(tree, hf_cip_trq_trim, tvb, offset + bytes_used, 4, ENC_LITTLE_ENDIAN );
-      bytes_used += 4;
-   }
-
    return bytes_used;
 }
 
@@ -579,33 +748,6 @@ dissect_act_data_set(guint32 act_data_set, proto_tree* tree, tvbuff_t* tvb, guin
       bytes_used += 4;
    }
 
-   if ( (act_data_set & ACTUAL_DATA_SET_TORQUE) == ACTUAL_DATA_SET_TORQUE )
-   {
-      /* Display the actual data set torque feedback value */
-      proto_tree_add_item(tree, hf_cip_act_trq, tvb, offset + bytes_used, 4, ENC_LITTLE_ENDIAN );
-      bytes_used += 4;
-   }
-   if ( (act_data_set & ACTUAL_DATA_SET_CURRENT) == ACTUAL_DATA_SET_CURRENT )
-   {
-      /* Display the actual data set current feedback value */
-      proto_tree_add_item(tree, hf_cip_act_crnt, tvb, offset + bytes_used, 4, ENC_LITTLE_ENDIAN );
-      bytes_used += 4;
-   }
-
-   if ( (act_data_set & ACTUAL_DATA_SET_VOLTAGE) == ACTUAL_DATA_SET_VOLTAGE )
-   {
-      /* Display the actual data set voltage feedback value */
-      proto_tree_add_item(tree, hf_cip_act_volts, tvb, offset + bytes_used, 4, ENC_LITTLE_ENDIAN );
-      bytes_used += 4;
-   }
-
-   if ( (act_data_set & ACTUAL_DATA_SET_FREQUENCY) == ACTUAL_DATA_SET_FREQUENCY )
-   {
-      /* Display the actual data set frequency feedback value */
-      proto_tree_add_item(tree, hf_cip_act_freq, tvb, offset + bytes_used, 4, ENC_LITTLE_ENDIAN );
-      bytes_used += 4;
-   }
-
    return bytes_used;
 }
 
@@ -621,8 +763,6 @@ static guint32
 dissect_status_data_set(guint32 status_data_set, proto_tree* tree, tvbuff_t* tvb, guint32 offset)
 {
    guint32 bytes_used = 0;
-   proto_item *temp_proto_item;
-   proto_tree *temp_proto_tree;
 
    /* The order of these if statements is VERY important, this is the order the values will
     * appear in the cyclic data */
@@ -667,28 +807,7 @@ dissect_status_data_set(guint32 status_data_set, proto_tree* tree, tvbuff_t* tvb
    if ( (status_data_set & STATUS_DATA_SET_AXIS_STATUS) == STATUS_DATA_SET_AXIS_STATUS )
    {
       /* Display the various axis state values from the device */
-      temp_proto_item = proto_tree_add_item(tree, hf_cip_axis_status, tvb, offset + bytes_used, 4, ENC_LITTLE_ENDIAN);
-      temp_proto_tree = proto_item_add_subtree( temp_proto_item, ett_axis_status_set );
-      proto_tree_add_item( temp_proto_tree, hf_cip_axis_sts_local_ctrl, tvb, offset + bytes_used, 4, ENC_LITTLE_ENDIAN );
-      proto_tree_add_item( temp_proto_tree, hf_cip_axis_sts_alarm, tvb, offset + bytes_used, 4, ENC_LITTLE_ENDIAN );
-      proto_tree_add_item( temp_proto_tree, hf_cip_axis_sts_dc_bus, tvb, offset + bytes_used, 4, ENC_LITTLE_ENDIAN );
-      proto_tree_add_item( temp_proto_tree, hf_cip_axis_sts_pwr_struct, tvb, offset + bytes_used, 4, ENC_LITTLE_ENDIAN );
-      proto_tree_add_item( temp_proto_tree, hf_cip_axis_sts_tracking, tvb, offset + bytes_used, 4, ENC_LITTLE_ENDIAN );
-      proto_tree_add_item( temp_proto_tree, hf_cip_axis_sts_pos_lock, tvb, offset + bytes_used, 4, ENC_LITTLE_ENDIAN );
-      proto_tree_add_item( temp_proto_tree, hf_cip_axis_sts_vel_lock, tvb, offset + bytes_used, 4, ENC_LITTLE_ENDIAN );
-      proto_tree_add_item( temp_proto_tree, hf_cip_axis_sts_vel_standstill, tvb, offset + bytes_used, 4, ENC_LITTLE_ENDIAN );
-      proto_tree_add_item( temp_proto_tree, hf_cip_axis_sts_vel_threshold, tvb, offset + bytes_used, 4, ENC_LITTLE_ENDIAN );
-      proto_tree_add_item( temp_proto_tree, hf_cip_axis_sts_vel_limit, tvb, offset + bytes_used, 4, ENC_LITTLE_ENDIAN );
-      proto_tree_add_item( temp_proto_tree, hf_cip_axis_sts_acc_limit, tvb, offset + bytes_used, 4, ENC_LITTLE_ENDIAN );
-      proto_tree_add_item( temp_proto_tree, hf_cip_axis_sts_dec_limit, tvb, offset + bytes_used, 4, ENC_LITTLE_ENDIAN );
-      proto_tree_add_item( temp_proto_tree, hf_cip_axis_sts_torque_threshold, tvb, offset + bytes_used, 4, ENC_LITTLE_ENDIAN );
-      proto_tree_add_item( temp_proto_tree, hf_cip_axis_sts_torque_limit, tvb, offset + bytes_used, 4, ENC_LITTLE_ENDIAN );
-      proto_tree_add_item( temp_proto_tree, hf_cip_axis_sts_cur_limit, tvb, offset + bytes_used, 4, ENC_LITTLE_ENDIAN );
-      proto_tree_add_item( temp_proto_tree, hf_cip_axis_sts_therm_limit, tvb, offset + bytes_used, 4, ENC_LITTLE_ENDIAN );
-      proto_tree_add_item( temp_proto_tree, hf_cip_axis_sts_feedback_integ, tvb, offset + bytes_used, 4, ENC_LITTLE_ENDIAN );
-      proto_tree_add_item( temp_proto_tree, hf_cip_axis_sts_shutdown, tvb, offset + bytes_used, 4, ENC_LITTLE_ENDIAN );
-      proto_tree_add_item( temp_proto_tree, hf_cip_axis_sts_in_process, tvb, offset + bytes_used, 4, ENC_LITTLE_ENDIAN );
-      bytes_used += 4;
+      bytes_used += dissect_axis_status(NULL, tree, NULL, tvb, offset + bytes_used, 4);
 
       proto_tree_add_item(tree, hf_cip_axis_status_mfg, tvb, offset + bytes_used, 4, ENC_LITTLE_ENDIAN);
       bytes_used += 4;
@@ -705,7 +824,11 @@ dissect_status_data_set(guint32 status_data_set, proto_tree* tree, tvbuff_t* tvb
 
    if ( (status_data_set & STATUS_DATA_SET_AXIS_SAFETY) == STATUS_DATA_SET_AXIS_SAFETY )
    {
-      proto_tree_add_item(tree, hf_cip_safety_status, tvb, offset + bytes_used, 4, ENC_LITTLE_ENDIAN);
+      proto_tree_add_item(tree, hf_cip_axis_safety_status, tvb, offset + bytes_used, 4, ENC_LITTLE_ENDIAN);
+      bytes_used += 4;
+      proto_tree_add_item(tree, hf_cip_axis_safety_status_mfg, tvb, offset + bytes_used, 4, ENC_LITTLE_ENDIAN);
+      bytes_used += 4;
+      proto_tree_add_item(tree, hf_cip_axis_safety_state, tvb, offset + bytes_used, 1, ENC_LITTLE_ENDIAN);
       bytes_used += 4;
    }
 
@@ -721,29 +844,27 @@ dissect_status_data_set(guint32 status_data_set, proto_tree* tree, tvbuff_t* tvb
  * as their starting offset
  */
 static guint32
-dissect_cntr_cyclic(guint32 con_format _U_, tvbuff_t* tvb, proto_tree* tree, guint32 offset, guint32 size, guint32 instance _U_)
+dissect_cntr_cyclic(tvbuff_t* tvb, proto_tree* tree, guint32 offset, guint32 size)
 {
-   proto_item *header_item, *temp_proto_item;
+   proto_item *temp_proto_item;
    proto_tree *header_tree, *temp_proto_tree;
    guint32     temp_data;
    gboolean    lreal_pos;
    guint32     bytes_used = 0;
 
    /* Create the tree for the entire instance data header */
-   header_item = proto_tree_add_text(tree, tvb, offset, size, "Cyclic Data Block");
-   header_tree = proto_item_add_subtree(header_item, ett_cyclic_data_block);
+   header_tree = proto_tree_add_subtree(tree, tvb, offset, size, ett_cyclic_data_block, NULL, "Cyclic Data Block");
 
    /* Add the control mode header field to the tree */
    proto_tree_add_item(header_tree, hf_cip_motor_cntrl, tvb, offset, 1, ENC_LITTLE_ENDIAN);
 
-   /* Add the feedback config header field to the tree */
-   proto_tree_add_item(header_tree, hf_cip_fdbk_config, tvb, offset + 1, 1, ENC_LITTLE_ENDIAN);
+   /* Add the feedback mode header field to the tree */
+   proto_tree_add_item(header_tree, hf_cip_feedback_mode, tvb, offset + 1, 1, ENC_LITTLE_ENDIAN);
 
    /* Add the axis control field to the tree */
    proto_tree_add_item(header_tree, hf_cip_axis_control, tvb, offset + 2, 1, ENC_LITTLE_ENDIAN);
 
-   /* Add the control status to the tree */
-   proto_tree_add_item(header_tree, hf_cip_control_status, tvb, offset + 3, 1, ENC_LITTLE_ENDIAN);
+   dissect_control_status(NULL, header_tree, NULL, tvb, offset + 3, 1);
 
    /* Read the command control header field from the packet into memory and determine if the dissector
    * should be using an LREAL or DINT for position */
@@ -753,33 +874,14 @@ dissect_cntr_cyclic(guint32 con_format _U_, tvbuff_t* tvb, proto_tree* tree, gui
    /* Read the command data set header field from the packet into memory */
    temp_data = tvb_get_guint8(tvb, offset + 4);
 
-   /* Create the tree for the command data set header field */
-   temp_proto_item = proto_tree_add_item(header_tree, hf_cip_cmd_data_set, tvb, offset + 4, 1, ENC_LITTLE_ENDIAN);
-   temp_proto_tree = proto_item_add_subtree(temp_proto_item, ett_command_data_set);
-   proto_tree_add_item(temp_proto_tree, hf_cip_cmd_data_pos_cmd, tvb, offset + 4, 1, ENC_LITTLE_ENDIAN);
-   proto_tree_add_item(temp_proto_tree, hf_cip_cmd_data_vel_cmd, tvb, offset + 4, 1, ENC_LITTLE_ENDIAN);
-   proto_tree_add_item(temp_proto_tree, hf_cip_cmd_data_acc_cmd, tvb, offset + 4, 1, ENC_LITTLE_ENDIAN);
-   proto_tree_add_item(temp_proto_tree, hf_cip_cmd_data_trq_cmd, tvb, offset + 4, 1, ENC_LITTLE_ENDIAN);
-   proto_tree_add_item(temp_proto_tree, hf_cip_cmd_data_pos_trim_cmd, tvb, offset + 4, 1, ENC_LITTLE_ENDIAN);
-   proto_tree_add_item(temp_proto_tree, hf_cip_cmd_data_vel_trim_cmd, tvb, offset + 4, 1, ENC_LITTLE_ENDIAN);
-   proto_tree_add_item(temp_proto_tree, hf_cip_cmd_data_acc_trim_cmd, tvb, offset + 4, 1, ENC_LITTLE_ENDIAN);
-   proto_tree_add_item(temp_proto_tree, hf_cip_cmd_data_trq_trim_cmd, tvb, offset + 4, 1, ENC_LITTLE_ENDIAN);
+   dissect_command_data_set_bits(NULL, header_tree, NULL, tvb, offset + 4, 1);
 
    /* Display the command data values from the cyclic data payload within the command data set tree, the
    * cyclic data starts immediately after the interpolation control field in the controller to device
    * direction */
-   bytes_used += dissect_cmd_data_set(temp_data, temp_proto_tree, tvb, offset + 8 + bytes_used, lreal_pos);
-
-   /* Create the tree for the actual data set header field */
-   temp_proto_item = proto_tree_add_item(header_tree, hf_cip_act_data_set, tvb, offset + 5, 1, ENC_LITTLE_ENDIAN);
-   temp_proto_tree = proto_item_add_subtree(temp_proto_item, ett_actual_data_set);
-   proto_tree_add_item(temp_proto_tree, hf_cip_act_data_pos,  tvb, offset + 5, 1, ENC_LITTLE_ENDIAN);
-   proto_tree_add_item(temp_proto_tree, hf_cip_act_data_vel,  tvb, offset + 5, 1, ENC_LITTLE_ENDIAN);
-   proto_tree_add_item(temp_proto_tree, hf_cip_act_data_acc,  tvb, offset + 5, 1, ENC_LITTLE_ENDIAN);
-   proto_tree_add_item(temp_proto_tree, hf_cip_act_data_trq,  tvb, offset + 5, 1, ENC_LITTLE_ENDIAN);
-   proto_tree_add_item(temp_proto_tree, hf_cip_act_data_crnt, tvb, offset + 5, 1, ENC_LITTLE_ENDIAN);
-   proto_tree_add_item(temp_proto_tree, hf_cip_act_data_vltg, tvb, offset + 5, 1, ENC_LITTLE_ENDIAN);
-   proto_tree_add_item(temp_proto_tree, hf_cip_act_data_fqcy, tvb, offset + 5, 1, ENC_LITTLE_ENDIAN);
+   bytes_used += dissect_cmd_data_set(temp_data, header_tree, tvb, offset + 8 + bytes_used, lreal_pos);
+
+   dissect_actual_data_set_bits(NULL, header_tree, NULL, tvb, offset + 5, 1);
 
    /* Create the tree for the status data set header field */
    temp_proto_item = proto_tree_add_item(header_tree, hf_cip_sts_data_set, tvb, offset + 6, 1, ENC_LITTLE_ENDIAN);
@@ -788,22 +890,16 @@ dissect_cntr_cyclic(guint32 con_format _U_, tvbuff_t* tvb, proto_tree* tree, gui
    proto_tree_add_item(temp_proto_tree, hf_cip_sts_alrm,   tvb, offset + 6, 1, ENC_LITTLE_ENDIAN);
    proto_tree_add_item(temp_proto_tree, hf_cip_sts_sts,    tvb, offset + 6, 1, ENC_LITTLE_ENDIAN);
    proto_tree_add_item(temp_proto_tree, hf_cip_sts_iosts,  tvb, offset + 6, 1, ENC_LITTLE_ENDIAN);
-   proto_tree_add_item(temp_proto_tree, hf_cip_sts_safety, tvb, offset + 6, 1, ENC_LITTLE_ENDIAN);
-
-   /* Create the tree for the command control header field */
-   temp_proto_item = proto_tree_add_item(header_tree, hf_cip_command_control, tvb, offset + 7, 1, ENC_LITTLE_ENDIAN);
-   temp_proto_tree = proto_item_add_subtree(temp_proto_item, ett_command_control);
+   proto_tree_add_item(temp_proto_tree, hf_cip_sts_axis_safety, tvb, offset + 6, 1, ENC_LITTLE_ENDIAN);
 
-   /* Display the interpolation control and position format fields */
-   proto_tree_add_item(temp_proto_tree, hf_cip_intrp, tvb, offset + 7, 1, ENC_LITTLE_ENDIAN);
-   proto_tree_add_item(temp_proto_tree, hf_cip_position_data_type, tvb, offset + 7, 1, ENC_LITTLE_ENDIAN);
+   dissect_command_control(NULL, header_tree, NULL, tvb, offset + 7, 1);
 
    /* Return the offset to the next byte in the message */
    return offset + 8 + bytes_used;
 }
 
 /*
- * Function name: dissect_devce_cyclic
+ * Function name: dissect_device_cyclic
  *
  * Purpose: Dissect the cyclic data block of a device to controller format message
  *
@@ -811,22 +907,21 @@ dissect_cntr_cyclic(guint32 con_format _U_, tvbuff_t* tvb, proto_tree* tree, gui
  * as their starting offset
  */
 static guint32
-dissect_devce_cyclic(guint32 con_format _U_, tvbuff_t* tvb, proto_tree* tree, guint32 offset, guint32 size, guint32 instance _U_)
+dissect_device_cyclic(tvbuff_t* tvb, proto_tree* tree, guint32 offset, guint32 size)
 {
-   proto_item *header_item, *temp_proto_item;
+   proto_item *temp_proto_item;
    proto_tree *header_tree, *temp_proto_tree;
    guint32 temp_data;
    guint32 bytes_used = 0;
 
    /* Create the tree for the entire instance data header */
-   header_item = proto_tree_add_text(tree, tvb, offset, size, "Cyclic Data Block");
-   header_tree = proto_item_add_subtree(header_item, ett_cyclic_data_block);
+   header_tree = proto_tree_add_subtree(tree, tvb, offset, size, ett_cyclic_data_block, NULL, "Cyclic Data Block");
 
    /* Add the control mode header field to the tree */
    proto_tree_add_item(header_tree, hf_cip_motor_cntrl, tvb, offset, 1, ENC_LITTLE_ENDIAN);
 
-   /* Add the feedback config header field to the tree */
-   proto_tree_add_item(header_tree, hf_cip_fdbk_config, tvb, offset + 1, 1, ENC_LITTLE_ENDIAN);
+   /* Add the feedback mode header field to the tree */
+   proto_tree_add_item(header_tree, hf_cip_feedback_mode, tvb, offset + 1, 1, ENC_LITTLE_ENDIAN);
 
    /* Add the axis response field to the tree */
    proto_tree_add_item(header_tree, hf_cip_axis_response, tvb, offset + 2, 1, ENC_LITTLE_ENDIAN);
@@ -837,21 +932,12 @@ dissect_devce_cyclic(guint32 con_format _U_, tvbuff_t* tvb, proto_tree* tree, gu
    /* Read the actual data set header field from the packet into memory */
    temp_data = tvb_get_guint8(tvb, offset + 5);
 
-   /* Create the tree for the actual data set header field */
-   temp_proto_item = proto_tree_add_item(header_tree, hf_cip_act_data_set, tvb, offset + 5, 1, ENC_LITTLE_ENDIAN);
-   temp_proto_tree = proto_item_add_subtree(temp_proto_item, ett_actual_data_set);
-   proto_tree_add_item(temp_proto_tree, hf_cip_act_data_pos,  tvb, offset + 5, 1, ENC_LITTLE_ENDIAN);
-   proto_tree_add_item(temp_proto_tree, hf_cip_act_data_vel,  tvb, offset + 5, 1, ENC_LITTLE_ENDIAN);
-   proto_tree_add_item(temp_proto_tree, hf_cip_act_data_acc,  tvb, offset + 5, 1, ENC_LITTLE_ENDIAN);
-   proto_tree_add_item(temp_proto_tree, hf_cip_act_data_trq,  tvb, offset + 5, 1, ENC_LITTLE_ENDIAN);
-   proto_tree_add_item(temp_proto_tree, hf_cip_act_data_crnt, tvb, offset + 5, 1, ENC_LITTLE_ENDIAN);
-   proto_tree_add_item(temp_proto_tree, hf_cip_act_data_vltg, tvb, offset + 5, 1, ENC_LITTLE_ENDIAN);
-   proto_tree_add_item(temp_proto_tree, hf_cip_act_data_fqcy, tvb, offset + 5, 1, ENC_LITTLE_ENDIAN);
+   dissect_actual_data_set_bits(NULL, header_tree, NULL, tvb, offset + 5, 1);
 
    /* Display the actual data values from the cyclic data payload within the command data set tree, the
    * cyclic data starts immediately after the interpolation control field in the controller to device
    * direction and the actual data starts immediately after the cyclic data */
-   bytes_used += dissect_act_data_set(temp_data, temp_proto_tree, tvb, offset + 8 + bytes_used);
+   bytes_used += dissect_act_data_set(temp_data, header_tree, tvb, offset + 8 + bytes_used);
 
    /* Read the status data set header field from the packet into memory */
    temp_data = tvb_get_guint8(tvb, offset + 6);
@@ -863,7 +949,7 @@ dissect_devce_cyclic(guint32 con_format _U_, tvbuff_t* tvb, proto_tree* tree, gu
    proto_tree_add_item(temp_proto_tree, hf_cip_sts_alrm,   tvb, offset + 6, 1, ENC_LITTLE_ENDIAN);
    proto_tree_add_item(temp_proto_tree, hf_cip_sts_sts,    tvb, offset + 6, 1, ENC_LITTLE_ENDIAN);
    proto_tree_add_item(temp_proto_tree, hf_cip_sts_iosts,  tvb, offset + 6, 1, ENC_LITTLE_ENDIAN);
-   proto_tree_add_item(temp_proto_tree, hf_cip_sts_safety, tvb, offset + 6, 1, ENC_LITTLE_ENDIAN);
+   proto_tree_add_item(temp_proto_tree, hf_cip_sts_axis_safety, tvb, offset + 6, 1, ENC_LITTLE_ENDIAN);
 
    /* Display the status data values from the cyclic data payload within the status data set tree, the
    * cyclic data starts immediately after the axis state field in the device to controller
@@ -888,12 +974,10 @@ dissect_devce_cyclic(guint32 con_format _U_, tvbuff_t* tvb, proto_tree* tree, gu
 static guint32
 dissect_cyclic_wt(tvbuff_t* tvb, proto_tree* tree, guint32 offset, guint32 size)
 {
-   proto_item *header_item;
    proto_tree *header_tree;
 
    /* Create the tree for the entire cyclic write data block */
-   header_item = proto_tree_add_text(tree, tvb, offset, size, "Cyclic Write Data Block");
-   header_tree = proto_item_add_subtree(header_item, ett_cyclic_rd_wt);
+   header_tree = proto_tree_add_subtree(tree, tvb, offset, size, ett_cyclic_rd_wt, NULL, "Cyclic Write Data Block");
 
    /* Display the cyclic write block id value */
    proto_tree_add_item(header_tree, hf_cip_cyclic_write_blk, tvb, offset, 1, ENC_LITTLE_ENDIAN);
@@ -921,12 +1005,10 @@ dissect_cyclic_wt(tvbuff_t* tvb, proto_tree* tree, guint32 offset, guint32 size)
 static guint32
 dissect_cyclic_rd(tvbuff_t* tvb, proto_tree* tree, guint32 offset, guint32 size)
 {
-   proto_item *header_item;
    proto_tree *header_tree;
 
    /* Create the tree for the entire cyclic write data block */
-   header_item = proto_tree_add_text(tree, tvb, offset, size, "Cyclic Read Data Block");
-   header_tree = proto_item_add_subtree(header_item, ett_cyclic_rd_wt);
+   header_tree = proto_tree_add_subtree(tree, tvb, offset, size, ett_cyclic_rd_wt, NULL, "Cyclic Read Data Block");
 
    /* Display the cyclic write block id value */
    proto_tree_add_item(header_tree, hf_cip_cyclic_write_blk, tvb, offset, 1, ENC_LITTLE_ENDIAN);
@@ -960,44 +1042,18 @@ dissect_cyclic_rd(tvbuff_t* tvb, proto_tree* tree, guint32 offset, guint32 size)
 static guint32
 dissect_cntr_event(tvbuff_t* tvb, proto_tree* tree, guint32 offset, guint32 size)
 {
-   proto_item *header_item, *temp_proto_item;
-   proto_tree *header_tree, *temp_proto_tree;
+   proto_tree *header_tree;
    guint32 temp_data;
    guint32 acks, cur_ack;
    guint32 bytes_used = 0;
 
    /* Create the tree for the entire cyclic write data block */
-   header_item = proto_tree_add_text(tree, tvb, offset, size, "Event Data Block");
-   header_tree = proto_item_add_subtree(header_item, ett_event);
+   header_tree = proto_tree_add_subtree(tree, tvb, offset, size, ett_event, NULL, "Event Data Block");
 
    /* Read the event checking control header field from the packet into memory */
    temp_data = tvb_get_letohl(tvb, offset);
 
-   /* Create the tree for the event checking control header field */
-   temp_proto_item = proto_tree_add_item(header_tree, hf_cip_event_checking, tvb, offset, 4, ENC_LITTLE_ENDIAN);
-   temp_proto_tree = proto_item_add_subtree(temp_proto_item, ett_event_check_ctrl);
-
-   /* Add the individual elements of the event checking control */
-   proto_tree_add_item(temp_proto_tree, hf_cip_evnt_ctrl_reg1_pos, tvb, offset, 4, ENC_LITTLE_ENDIAN);
-   proto_tree_add_item(temp_proto_tree, hf_cip_evnt_ctrl_reg1_neg, tvb, offset, 4, ENC_LITTLE_ENDIAN);
-   proto_tree_add_item(temp_proto_tree, hf_cip_evnt_ctrl_reg2_pos, tvb, offset, 4, ENC_LITTLE_ENDIAN);
-   proto_tree_add_item(temp_proto_tree, hf_cip_evnt_ctrl_reg2_neg, tvb, offset, 4, ENC_LITTLE_ENDIAN);
-   proto_tree_add_item(temp_proto_tree, hf_cip_evnt_ctrl_reg1_posrearm, tvb, offset, 4, ENC_LITTLE_ENDIAN);
-   proto_tree_add_item(temp_proto_tree, hf_cip_evnt_ctrl_reg1_negrearm, tvb, offset, 4, ENC_LITTLE_ENDIAN);
-   proto_tree_add_item(temp_proto_tree, hf_cip_evnt_ctrl_reg2_posrearm, tvb, offset, 4, ENC_LITTLE_ENDIAN);
-   proto_tree_add_item(temp_proto_tree, hf_cip_evnt_ctrl_reg2_negrearm, tvb, offset, 4, ENC_LITTLE_ENDIAN);
-   proto_tree_add_item(temp_proto_tree, hf_cip_evnt_ctrl_marker_pos, tvb, offset, 4, ENC_LITTLE_ENDIAN);
-   proto_tree_add_item(temp_proto_tree, hf_cip_evnt_ctrl_marker_neg, tvb, offset, 4, ENC_LITTLE_ENDIAN);
-   proto_tree_add_item(temp_proto_tree, hf_cip_evnt_ctrl_home_pos,   tvb, offset, 4, ENC_LITTLE_ENDIAN);
-   proto_tree_add_item(temp_proto_tree, hf_cip_evnt_ctrl_home_neg,   tvb, offset, 4, ENC_LITTLE_ENDIAN);
-   proto_tree_add_item(temp_proto_tree, hf_cip_evnt_ctrl_home_pp,    tvb, offset, 4, ENC_LITTLE_ENDIAN);
-   proto_tree_add_item(temp_proto_tree, hf_cip_evnt_ctrl_home_pm,    tvb, offset, 4, ENC_LITTLE_ENDIAN);
-   proto_tree_add_item(temp_proto_tree, hf_cip_evnt_ctrl_home_mp,    tvb, offset, 4, ENC_LITTLE_ENDIAN);
-   proto_tree_add_item(temp_proto_tree, hf_cip_evnt_ctrl_home_mm,    tvb, offset, 4, ENC_LITTLE_ENDIAN);
-   proto_tree_add_item(temp_proto_tree, hf_cip_evnt_ctrl_acks,       tvb, offset, 4, ENC_LITTLE_ENDIAN);
-   /* The dissector will indicate if the protocol is requesting an extended event format but will not dissect it,
-   * to date no products actually support this format */
-   proto_tree_add_item(temp_proto_tree, hf_cip_evnt_extend_format,   tvb, offset, 4, ENC_LITTLE_ENDIAN);
+   dissect_event_checking_control(NULL, header_tree, NULL, tvb, offset, 4);
 
    /* The event checking control value is 4 bytes long */
    bytes_used = 4;
@@ -1031,44 +1087,18 @@ dissect_cntr_event(tvbuff_t* tvb, proto_tree* tree, guint32 offset, guint32 size
 static guint32
 dissect_devce_event(tvbuff_t* tvb, proto_tree* tree, guint32 offset, guint32 size)
 {
-   proto_item *header_item, *temp_proto_item;
-   proto_tree *header_tree, *temp_proto_tree;
+   proto_tree *header_tree;
    guint64     temp_data;
    guint64     nots, cur_not;
    guint32     bytes_used = 0;
 
    /* Create the tree for the entire cyclic write data block */
-   header_item = proto_tree_add_text(tree, tvb, offset, size, "Event Data Block");
-   header_tree = proto_item_add_subtree(header_item, ett_event);
+   header_tree = proto_tree_add_subtree(tree, tvb, offset, size, ett_event, NULL, "Event Data Block");
 
    /* Read the event checking control header field from the packet into memory */
    temp_data = tvb_get_letohl(tvb, offset);
 
-   /* Create the tree for the event checking control header field */
-   temp_proto_item = proto_tree_add_item(header_tree, hf_cip_event_status, tvb, offset, 4, ENC_LITTLE_ENDIAN);
-   temp_proto_tree = proto_item_add_subtree(temp_proto_item, ett_event_check_sts);
-
-   /* Add the individual elements of the event checking control */
-   proto_tree_add_item(temp_proto_tree, hf_cip_evnt_sts_reg1_pos, tvb, offset, 4, ENC_LITTLE_ENDIAN);
-   proto_tree_add_item(temp_proto_tree, hf_cip_evnt_sts_reg1_neg, tvb, offset, 4, ENC_LITTLE_ENDIAN);
-   proto_tree_add_item(temp_proto_tree, hf_cip_evnt_sts_reg2_pos, tvb, offset, 4, ENC_LITTLE_ENDIAN);
-   proto_tree_add_item(temp_proto_tree, hf_cip_evnt_sts_reg2_neg, tvb, offset, 4, ENC_LITTLE_ENDIAN);
-   proto_tree_add_item(temp_proto_tree, hf_cip_evnt_sts_reg1_posrearm, tvb, offset, 4, ENC_LITTLE_ENDIAN);
-   proto_tree_add_item(temp_proto_tree, hf_cip_evnt_sts_reg1_negrearm, tvb, offset, 4, ENC_LITTLE_ENDIAN);
-   proto_tree_add_item(temp_proto_tree, hf_cip_evnt_sts_reg2_posrearm, tvb, offset, 4, ENC_LITTLE_ENDIAN);
-   proto_tree_add_item(temp_proto_tree, hf_cip_evnt_sts_reg2_negrearm, tvb, offset, 4, ENC_LITTLE_ENDIAN);
-   proto_tree_add_item(temp_proto_tree, hf_cip_evnt_sts_marker_pos, tvb, offset, 4, ENC_LITTLE_ENDIAN);
-   proto_tree_add_item(temp_proto_tree, hf_cip_evnt_sts_marker_neg, tvb, offset, 4, ENC_LITTLE_ENDIAN);
-   proto_tree_add_item(temp_proto_tree, hf_cip_evnt_sts_home_pos,   tvb, offset, 4, ENC_LITTLE_ENDIAN);
-   proto_tree_add_item(temp_proto_tree, hf_cip_evnt_sts_home_neg,   tvb, offset, 4, ENC_LITTLE_ENDIAN);
-   proto_tree_add_item(temp_proto_tree, hf_cip_evnt_sts_home_pp,    tvb, offset, 4, ENC_LITTLE_ENDIAN);
-   proto_tree_add_item(temp_proto_tree, hf_cip_evnt_sts_home_pm,    tvb, offset, 4, ENC_LITTLE_ENDIAN);
-   proto_tree_add_item(temp_proto_tree, hf_cip_evnt_sts_home_mp,    tvb, offset, 4, ENC_LITTLE_ENDIAN);
-   proto_tree_add_item(temp_proto_tree, hf_cip_evnt_sts_home_mm,    tvb, offset, 4, ENC_LITTLE_ENDIAN);
-   proto_tree_add_item(temp_proto_tree, hf_cip_evnt_sts_nfs,        tvb, offset, 4, ENC_LITTLE_ENDIAN);
-   /* The dissector will indicate if the protocol is requesting an extended event format but will not dissect it,
-   * to date no products actually support this format */
-   proto_tree_add_item(temp_proto_tree, hf_cip_evnt_extend_format,  tvb, offset, 4, ENC_LITTLE_ENDIAN);
+   dissect_event_checking_status(NULL, header_tree, NULL, tvb, offset, 4);
 
    /* The event status control value is 4 bytes long */
    bytes_used = 4;
@@ -1111,45 +1141,40 @@ dissect_devce_event(tvbuff_t* tvb, proto_tree* tree, guint32 offset, guint32 siz
  * Returns: None
  */
 static void
-dissect_get_axis_attr_list_request (tvbuff_t* tvb, proto_tree* tree, guint32 offset, guint32 size)
+dissect_get_axis_attr_list_request(tvbuff_t* tvb, proto_tree* tree, guint32 offset, guint32 size, guint32 instance_id)
 {
-   proto_item *header_item, *attr_item;
+   proto_item *attr_item;
    proto_tree *header_tree, *attr_tree;
-   guint16     attribute, attribute_cnt;
    guint32     local_offset;
-   guint8      increment_size, dimension;
 
    /* Create the tree for the get axis attribute list request */
-   header_item = proto_tree_add_text(tree, tvb, offset, size, "Get Axis Attribute List Request");
-   header_tree = proto_item_add_subtree(header_item, ett_get_axis_attribute);
+   header_tree = proto_tree_add_subtree(tree, tvb, offset, size, ett_get_axis_attribute, NULL, "Get Axis Attribute List Request");
 
    /* Read the number of attributes that are contained within the request */
-   attribute_cnt = tvb_get_letohs(tvb, offset);
-   proto_tree_add_item(header_tree, hf_get_axis_attr_list_attribute_cnt, tvb, offset, 2, ENC_LITTLE_ENDIAN);
+   guint32 attribute_cnt;
+   proto_tree_add_item_ret_uint(header_tree, hf_get_axis_attr_list_attribute_cnt, tvb, offset, 2, ENC_LITTLE_ENDIAN, &attribute_cnt);
 
    /* Start the attribute loop at the beginning of the first attribute in the list */
    local_offset = offset + 4;
 
    /* For each attribute display the associated fields */
-   for (attribute = 0; attribute < attribute_cnt; attribute++)
+   for (guint32 attribute = 0; attribute < attribute_cnt; attribute++)
    {
       /* At a minimum the local offset needs will need to be incremented by 4 bytes to reach the next attribute */
-      increment_size = 4;
-
-      /* Pull the fields for this attribute from the payload, all fields are needed to make some calculations before
-      * properly displaying of the attribute is possible */
-      dimension       = tvb_get_guint8(tvb, local_offset + 2);
+      guint8 increment_size = 4;
 
       /* Create the tree for this attribute within the request */
-      attr_item = proto_tree_add_item(header_tree, hf_get_axis_attr_list_attribute_id, tvb, local_offset, 2, ENC_LITTLE_ENDIAN);
+      guint32 attribute_id;
+      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);
       attr_tree = proto_item_add_subtree(attr_item, ett_get_axis_attr_list);
 
-      proto_tree_add_item(attr_tree, hf_get_axis_attr_list_dimension, tvb, local_offset + 2, 1, ENC_LITTLE_ENDIAN);
+      guint32 dimension;
+      proto_tree_add_item_ret_uint(attr_tree, hf_get_axis_attr_list_dimension, tvb, local_offset + 2, 1, ENC_LITTLE_ENDIAN, &dimension);
       proto_tree_add_item(attr_tree, hf_get_axis_attr_list_element_size, tvb, local_offset + 3, 1, ENC_LITTLE_ENDIAN);
 
       if (dimension == 1)
       {
-         /* Display the start index and start index from the request if this is an array request */
+         /* Display the start index and start index from the request */
          proto_tree_add_item(attr_tree, hf_get_axis_attr_list_start_index, tvb, local_offset + 4, 2, ENC_LITTLE_ENDIAN);
          proto_tree_add_item(attr_tree, hf_get_axis_attr_list_data_elements, tvb, local_offset + 6, 2, ENC_LITTLE_ENDIAN);
 
@@ -1157,11 +1182,37 @@ dissect_get_axis_attr_list_request (tvbuff_t* tvb, proto_tree* tree, guint32 off
          increment_size += 4;
       }
 
+      attribute_info_t* pattribute = cip_get_attribute(CI_CLS_MOTION, instance_id, attribute_id);
+      if (pattribute != NULL)
+      {
+         proto_item_append_text(attr_item, " (%s)", pattribute->text);
+      }
+
       /* Move the local offset to the next attribute */
       local_offset += increment_size;
    }
 }
 
+static int dissect_motion_attribute(packet_info *pinfo, tvbuff_t* tvb, int offset, guint32 attribute_id,
+   guint32 instance_id, proto_item* attr_item, proto_tree* attr_tree, guint8 dimension, guint32 attribute_size)
+{
+   attribute_info_t* pattribute = cip_get_attribute(CI_CLS_MOTION, instance_id, attribute_id);
+   int parsed_len = 0;
+
+   if (pattribute != NULL)
+   {
+      proto_item_append_text(attr_item, " (%s)", pattribute->text);
+
+      // TODO: Handle more dimensions. Unsure about the format when there is more than 1 item.
+      if (dimension <= 1)
+      {
+         parsed_len = dissect_cip_attribute(pinfo, attr_tree, attr_item, tvb, pattribute, offset, attribute_size);
+      }
+   }
+
+   return parsed_len;
+}
+
 /*
  * Function name: dissect_set_axis_attr_list_request
  *
@@ -1170,41 +1221,50 @@ dissect_get_axis_attr_list_request (tvbuff_t* tvb, proto_tree* tree, guint32 off
  * Returns: None
  */
 static void
-dissect_set_axis_attr_list_request (tvbuff_t* tvb, proto_tree* tree, guint32 offset, guint32 size)
+dissect_set_axis_attr_list_request(packet_info *pinfo, tvbuff_t* tvb, proto_tree* tree, guint32 offset, guint32 size, guint32 instance_id)
 {
-   proto_item *header_item, *attr_item;
+   proto_item *attr_item;
    proto_tree *header_tree, *attr_tree;
-   guint16     attribute, attribute_cnt, data_elements;
    guint32     local_offset;
-   guint32     attribute_size;
-   guint8      dimension, attribute_start, increment_size;
 
    /* Create the tree for the set axis attribute list request */
-   header_item = proto_tree_add_text(tree, tvb, offset, size, "Set Axis Attribute List Request");
-   header_tree = proto_item_add_subtree(header_item, ett_set_axis_attribute);
+   header_tree = proto_tree_add_subtree(tree, tvb, offset, size, ett_set_axis_attribute, NULL, "Set Axis Attribute List Request");
 
    /* Read the number of attributes that are contained within the request */
-   attribute_cnt = tvb_get_letohs(tvb, offset);
-   proto_tree_add_item(header_tree, hf_set_axis_attr_list_attribute_cnt, tvb, offset, 2, ENC_LITTLE_ENDIAN);
+   guint32 attribute_cnt;
+   proto_tree_add_item_ret_uint(header_tree, hf_set_axis_attr_list_attribute_cnt, tvb, offset, 2, ENC_LITTLE_ENDIAN, &attribute_cnt);
 
    /* Start the attribute loop at the beginning of the first attribute in the list */
    local_offset = offset + 4;
 
    /* For each attribute display the associated fields */
-   for (attribute = 0; attribute < attribute_cnt; attribute++)
+   for (guint32 attribute = 0; attribute < attribute_cnt; attribute++)
    {
       /* At a minimum the local offset needs to be incremented by 4 bytes to reach the next attribute */
-      increment_size = 4;
+      guint8 increment_size = 4;
 
       /* Pull the fields for this attribute from the payload, all fields are needed to make some calculations before
-      * properly displaying of the attribute is possible */
-      dimension       = tvb_get_guint8(tvb, local_offset + 2);
-      attribute_size  = tvb_get_guint8(tvb, local_offset + 3);
-      attribute_start = 4;
+      *  properly displaying of the attribute is possible */
+      guint8 attribute_start = 4;
+
+      /* Create the tree for this attribute in the get axis attribute list request */
+      guint32 attribute_id;
+      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);
+      attr_tree = proto_item_add_subtree(attr_item, ett_set_axis_attr_list);
+
+      guint32 dimension;
+      proto_tree_add_item_ret_uint(attr_tree, hf_set_axis_attr_list_dimension, tvb, local_offset + 2, 1, ENC_LITTLE_ENDIAN, &dimension);
+
+      guint32 attribute_size;
+      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);
 
       if (dimension == 1)
       {
-         data_elements   = tvb_get_letohs(tvb, local_offset + 6);
+         guint32 data_elements;
+
+         /* Display the start index and start index from the request if the request is an array */
+         proto_tree_add_item(attr_tree, hf_set_axis_attr_list_start_index, tvb, local_offset + 4, 2, ENC_LITTLE_ENDIAN);
+         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);
 
          /* Modify the size of the attribute data by the number of elements if the request is an array request */
          attribute_size *= data_elements;
@@ -1214,23 +1274,15 @@ dissect_set_axis_attr_list_request (tvbuff_t* tvb, proto_tree* tree, guint32 off
          attribute_start += 4;
       }
 
-      /* Create the tree for this attribute in the get axis attribute list request */
-      attr_item = proto_tree_add_item(header_tree, hf_set_axis_attr_list_attribute_id, tvb, local_offset, 2, ENC_LITTLE_ENDIAN);
-      attr_tree = proto_item_add_subtree(attr_item, ett_set_axis_attr_list);
+      int parsed_len = dissect_motion_attribute(pinfo, tvb, local_offset + attribute_start, attribute_id,
+         instance_id, attr_item, attr_tree, dimension, attribute_size);
 
-      proto_tree_add_item(attr_tree, hf_set_axis_attr_list_dimension, tvb, local_offset + 2, 1, ENC_LITTLE_ENDIAN);
-      proto_tree_add_item(attr_tree, hf_set_axis_attr_list_element_size, tvb, local_offset + 3, 1, ENC_LITTLE_ENDIAN);
-
-      if (dimension == 1)
+      // Display any remaining unparsed attribute data.
+      if ((attribute_size - parsed_len) > 0)
       {
-         /* Display the start index and start index from the request if the request is an array */
-         proto_tree_add_item(attr_tree, hf_set_axis_attr_list_start_index, tvb, local_offset + 4, 2, ENC_LITTLE_ENDIAN);
-         proto_tree_add_item(attr_tree, hf_set_axis_attr_list_data_elements, tvb, local_offset + 6, 2, ENC_LITTLE_ENDIAN);
+         proto_tree_add_item(attr_tree, hf_cip_attribute_data, tvb, local_offset + attribute_start + parsed_len, attribute_size - parsed_len, ENC_NA);
       }
 
-      /* Display the value of this attribute */
-      proto_tree_add_item(attr_tree, hf_cip_attribute_data, tvb, local_offset + attribute_start, attribute_size, ENC_NA);
-
       /* Round the attribute size up so the next attribute lines up on a 32-bit boundary */
       if (attribute_size % 4 != 0)
       {
@@ -1252,12 +1304,10 @@ dissect_set_axis_attr_list_request (tvbuff_t* tvb, proto_tree* tree, guint32 off
 static void
 dissect_group_sync_request (tvbuff_t* tvb, proto_tree* tree, guint32 offset, guint32 size)
 {
-   proto_item *header_item;
    proto_tree *header_tree;
 
    /* Create the tree for the group sync request */
-   header_item = proto_tree_add_text(tree, tvb, offset, size, "Group Sync Request");
-   header_tree = proto_item_add_subtree(header_item, ett_group_sync);
+   header_tree = proto_tree_add_subtree(tree, tvb, offset, size, ett_group_sync, NULL, "Group Sync Request");
 
    /* Read the grandmaster id from the payload */
    proto_tree_add_item(header_tree, hf_cip_ptp_grandmaster, tvb, offset, 8, ENC_LITTLE_ENDIAN);
@@ -1273,38 +1323,38 @@ dissect_group_sync_request (tvbuff_t* tvb, proto_tree* tree, guint32 offset, gui
  * as their starting offset
  */
 static guint32
-dissect_cntr_service(tvbuff_t* tvb, proto_tree* tree, guint32 offset, guint32 size)
+dissect_cntr_service(tvbuff_t* tvb, packet_info* pinfo, proto_tree* tree, guint32 offset, guint32 size, guint32 instance_id)
 {
-   proto_item *header_item;
    proto_tree *header_tree;
-   guint8      service;
+   guint32      service;
 
    /* Create the tree for the entire service data block */
-   header_item = proto_tree_add_text(tree, tvb, offset, size, "Service Data Block");
-   header_tree = proto_item_add_subtree(header_item, ett_service);
+   header_tree = proto_tree_add_subtree(tree, tvb, offset, size, ett_service, NULL, "Service Data Block");
 
    /* Display the transaction id value */
    proto_tree_add_item(header_tree, hf_cip_svc_transction, tvb, offset, 1, ENC_LITTLE_ENDIAN);
 
    /* Display the service code */
-   service = tvb_get_guint8(tvb, offset + 1);
-   proto_tree_add_item(header_tree, hf_cip_svc_code, tvb, offset + 1, 1, ENC_LITTLE_ENDIAN);
+   proto_tree_add_item_ret_uint(header_tree, hf_cip_svc_code, tvb, offset + 1, 1, ENC_LITTLE_ENDIAN, &service);
 
    /* If the service is a set axis, get axis attribute or group sync request dissect it as well */
-   switch(service)
+   if (size > 4)
    {
-   case SC_GET_AXIS_ATTRIBUTE_LIST:
-      dissect_get_axis_attr_list_request(tvb, header_tree, offset + 4, size);
-      break;
-   case SC_SET_AXIS_ATTRIBUTE_LIST:
-      dissect_set_axis_attr_list_request(tvb, header_tree, offset + 4, size);
-      break;
-   case SC_GROUP_SYNC:
-      dissect_group_sync_request(tvb, header_tree, offset + 4, size);
-      break;
-   default:
-      /* Display the remainder of the service channel data */
-      proto_tree_add_item(header_tree, hf_cip_svc_data, tvb, offset + 4, size - 4, ENC_NA);
+       switch (service)
+       {
+       case SC_GET_AXIS_ATTRIBUTE_LIST:
+           dissect_get_axis_attr_list_request(tvb, header_tree, offset + 4, size - 4, instance_id);
+           break;
+       case SC_SET_AXIS_ATTRIBUTE_LIST:
+           dissect_set_axis_attr_list_request(pinfo, tvb, header_tree, offset + 4, size - 4, instance_id);
+           break;
+       case SC_GROUP_SYNC:
+           dissect_group_sync_request(tvb, header_tree, offset + 4, size - 4);
+           break;
+       default:
+           /* Display the remainder of the service channel data */
+           proto_tree_add_item(header_tree, hf_cip_svc_data, tvb, offset + 4, size - 4, ENC_NA);
+       }
    }
 
    return offset + size;
@@ -1318,34 +1368,39 @@ dissect_cntr_service(tvbuff_t* tvb, proto_tree* tree, guint32 offset, guint32 si
  * Returns: None
  */
 static void
-dissect_set_axis_attr_list_response (tvbuff_t* tvb, proto_tree* tree, guint32 offset, guint32 size)
+dissect_set_axis_attr_list_response(tvbuff_t* tvb, proto_tree* tree, guint32 offset, guint32 size, guint32 instance_id)
 {
-   proto_item *header_item, *attr_item;
+   proto_item *attr_item;
    proto_tree *header_tree, *attr_tree;
-   guint16     attribute, attribute_cnt;
    guint32     local_offset;
 
    /* Create the tree for the set axis attribute list response */
-   header_item = proto_tree_add_text(tree, tvb, offset, size, "Set Axis Attribute List Response");
-   header_tree = proto_item_add_subtree(header_item, ett_get_axis_attribute);
+   header_tree = proto_tree_add_subtree(tree, tvb, offset, size, ett_get_axis_attribute, NULL, "Set Axis Attribute List Response");
 
    /* Read the number of attributes that are contained within the response */
-   attribute_cnt = tvb_get_letohs(tvb, offset);
-   proto_tree_add_item(header_tree, hf_set_axis_attr_list_attribute_cnt, tvb, offset, 2, ENC_LITTLE_ENDIAN);
+   guint32 attribute_cnt;
+   proto_tree_add_item_ret_uint(header_tree, hf_set_axis_attr_list_attribute_cnt, tvb, offset, 2, ENC_LITTLE_ENDIAN, &attribute_cnt);
 
    /* Start the attribute loop at the beginning of the first attribute in the list */
    local_offset = offset + 4;
 
    /* For each attribute display the associated fields */
-   for (attribute = 0; attribute < attribute_cnt; attribute++)
+   for (guint32 attribute = 0; attribute < attribute_cnt; attribute++)
    {
       /* Create the tree for the current attribute in the set axis attribute list response */
-      attr_item = proto_tree_add_item(header_tree, hf_set_axis_attr_list_attribute_id, tvb, local_offset, 2, ENC_LITTLE_ENDIAN);
+      guint32 attribute_id;
+      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);
       attr_tree = proto_item_add_subtree(attr_item, ett_get_axis_attr_list);
 
       /* Add the response status to the tree */
       proto_tree_add_item(attr_tree, hf_cip_svc_set_axis_attr_sts, tvb, local_offset + 2, 1, ENC_LITTLE_ENDIAN);
 
+      attribute_info_t* pattribute = cip_get_attribute(CI_CLS_MOTION, instance_id, attribute_id);
+      if (pattribute != NULL)
+      {
+         proto_item_append_text(attr_item, " (%s)", pattribute->text);
+      }
+
       /* Move the local offset to the next attribute */
       local_offset += 4;
    }
@@ -1359,41 +1414,37 @@ dissect_set_axis_attr_list_response (tvbuff_t* tvb, proto_tree* tree, guint32 of
  * Returns: None
  */
 static void
-dissect_get_axis_attr_list_response (tvbuff_t* tvb, proto_tree* tree, guint32 offset, guint32 size)
+dissect_get_axis_attr_list_response(packet_info* pinfo, tvbuff_t* tvb, proto_tree* tree, guint32 offset, guint32 size, guint32 instance_id)
 {
-   proto_item *header_item, *attr_item;
+   proto_item *attr_item;
    proto_tree *header_tree, *attr_tree;
-   guint16     attribute, attribute_cnt, data_elements;
-   guint32     attribute_size;
-   guint8      dimension, attribute_start, increment_size;
    guint32     local_offset;
 
    /* Create the tree for the get axis attribute list response */
-   header_item = proto_tree_add_text(tree, tvb, offset, size, "Get Axis Attribute List Response");
-   header_tree = proto_item_add_subtree(header_item, ett_get_axis_attribute);
+   header_tree = proto_tree_add_subtree(tree, tvb, offset, size, ett_get_axis_attribute, NULL, "Get Axis Attribute List Response");
 
    /* Read the number of attributes that are contained within the request */
-   attribute_cnt = tvb_get_letohs(tvb, offset);
-   proto_tree_add_item(header_tree, hf_get_axis_attr_list_attribute_cnt, tvb, offset, 2, ENC_LITTLE_ENDIAN);
+   guint32 attribute_cnt;
+   proto_tree_add_item_ret_uint(header_tree, hf_get_axis_attr_list_attribute_cnt, tvb, offset, 2, ENC_LITTLE_ENDIAN, &attribute_cnt);
 
    /* Start the attribute loop at the beginning of the first attribute in the list */
    local_offset = offset + 4;
 
    /* For each attribute display the associated fields */
-   for (attribute = 0; attribute < attribute_cnt; attribute++)
+   for (guint32 attribute = 0; attribute < attribute_cnt; attribute++)
    {
       /* At a minimum the local offset needs to be incremented by 4 bytes to reach the next attribute */
-      increment_size = 4;
+      guint8 increment_size = 4;
 
-      /* Pull the fields for this attribute from the payload, all fields are need to make some calculations before
+      /* Pull the fields for this attribute from the payload, all fields are needed to make some calculations before
       * properly displaying of the attribute is possible */
-      dimension       = tvb_get_guint8(tvb, local_offset + 2);
-      attribute_size  = tvb_get_guint8(tvb, local_offset + 3);
-      attribute_start = 4;
+      guint8 dimension = tvb_get_guint8(tvb, local_offset + 2);
+      guint32 attribute_size = tvb_get_guint8(tvb, local_offset + 3);
+      guint8 attribute_start = 4;
 
       if (dimension == 1)
       {
-         data_elements   = tvb_get_letohs(tvb, local_offset + 6);
+         guint16 data_elements = tvb_get_letohs(tvb, local_offset + 6);
 
          /* Modify the size of the attribute data by the number of elements if the request is an array request */
          attribute_size *= data_elements;
@@ -1404,7 +1455,8 @@ dissect_get_axis_attr_list_response (tvbuff_t* tvb, proto_tree* tree, guint32 of
       }
 
       /* Display the fields associated with the get axis attribute list response */
-      attr_item = proto_tree_add_item(header_tree, hf_get_axis_attr_list_attribute_id, tvb, local_offset, 2, ENC_LITTLE_ENDIAN);
+      guint32 attribute_id;
+      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);
       attr_tree = proto_item_add_subtree(attr_item, ett_get_axis_attr_list);
 
       if (dimension == 0xFF)
@@ -1422,13 +1474,19 @@ dissect_get_axis_attr_list_response (tvbuff_t* tvb, proto_tree* tree, guint32 of
 
          if (dimension == 1)
          {
-            /* Display the start index and start indexfrom the request */
+            /* Display the start index and start index from the request */
             proto_tree_add_item(attr_tree, hf_get_axis_attr_list_start_index, tvb, local_offset + 4, 2, ENC_LITTLE_ENDIAN);
             proto_tree_add_item(attr_tree, hf_get_axis_attr_list_data_elements, tvb, local_offset + 6, 2, ENC_LITTLE_ENDIAN);
          }
 
+         int parsed_len = dissect_motion_attribute(pinfo, tvb, local_offset + attribute_start, attribute_id,
+            instance_id, attr_item, attr_tree, dimension, attribute_size);
+
          /* Display the remainder of the service channel data */
-         proto_tree_add_item(attr_tree, hf_cip_attribute_data, tvb, offset + attribute_start, attribute_size, ENC_NA);
+         if ((attribute_size - parsed_len) > 0)
+         {
+            proto_tree_add_item(attr_tree, hf_cip_attribute_data, tvb, local_offset + attribute_start + parsed_len, attribute_size - parsed_len, ENC_NA);
+         }
 
          /* Round the attribute size up so the next attribute lines up on a 32-bit boundary */
          if (attribute_size % 4 != 0)
@@ -1450,7 +1508,7 @@ dissect_get_axis_attr_list_response (tvbuff_t* tvb, proto_tree* tree, guint32 of
  * Returns: None
  */
 static void
-dissect_group_sync_response (tvbuff_t* tvb, proto_tree* tree, guint32 offset, guint32 size _U_)
+dissect_group_sync_response (tvbuff_t* tvb, proto_tree* tree, guint32 offset)
 {
    proto_tree_add_item(tree, hf_cip_group_sync, tvb, offset, 1, ENC_LITTLE_ENDIAN);
 }
@@ -1464,20 +1522,19 @@ dissect_group_sync_response (tvbuff_t* tvb, proto_tree* tree, guint32 offset, gu
  * as their starting offset
  */
 static guint32
-dissect_devce_service(tvbuff_t* tvb, proto_tree* tree, guint32 offset, guint32 size)
+dissect_devce_service(tvbuff_t* tvb, packet_info* pinfo, proto_tree* tree, guint32 offset, guint32 size, guint32 instance_id)
 {
-   proto_item *header_item;
    proto_tree *header_tree;
 
    /* Create the tree for the entire service data block */
-   header_item = proto_tree_add_text(tree, tvb, offset, size, "Service Data Block");
-   header_tree = proto_item_add_subtree(header_item, ett_service);
+   header_tree = proto_tree_add_subtree(tree, tvb, offset, size, ett_service, NULL, "Service Data Block");
 
    /* Display the transaction id value */
    proto_tree_add_item(header_tree, hf_cip_svc_transction, tvb, offset, 1, ENC_LITTLE_ENDIAN);
 
    /* Display the service code */
-   proto_tree_add_item(header_tree, hf_cip_svc_code, tvb, offset + 1, 1, ENC_LITTLE_ENDIAN);
+   guint32 service_code;
+   proto_tree_add_item_ret_uint(header_tree, hf_cip_svc_code, tvb, offset + 1, 1, ENC_LITTLE_ENDIAN, &service_code);
 
    /* Display the general status code */
    proto_tree_add_item(header_tree, hf_cip_svc_sts, tvb, offset + 2, 1, ENC_LITTLE_ENDIAN);
@@ -1486,20 +1543,24 @@ dissect_devce_service(tvbuff_t* tvb, proto_tree* tree, guint32 offset, guint32 s
    proto_tree_add_item(header_tree, hf_cip_svc_ext_status, tvb, offset + 3, 1, ENC_LITTLE_ENDIAN);
 
    /* If the service is a set axis, get axis attribute response or group sync dissect it as well */
-   switch(tvb_get_guint8(tvb, offset + 1))
+   if (size > 4)
    {
-   case SC_GET_AXIS_ATTRIBUTE_LIST:
-      dissect_get_axis_attr_list_response(tvb, header_tree, offset + 4, size);
-      break;
-   case SC_SET_AXIS_ATTRIBUTE_LIST:
-      dissect_set_axis_attr_list_response(tvb, header_tree, offset + 4, size);
-      break;
-   case SC_GROUP_SYNC:
-      dissect_group_sync_response(tvb, header_tree, offset + 4, size);
-      break;
-   default:
-      /* Display the remainder of the service channel data */
-      proto_tree_add_item(header_tree, hf_cip_svc_data, tvb, offset + 4, size - 4, ENC_NA);
+       switch (service_code)
+       {
+       case SC_GET_AXIS_ATTRIBUTE_LIST:
+           dissect_get_axis_attr_list_response(pinfo, tvb, header_tree, offset + 4, size - 4, instance_id);
+           break;
+       case SC_SET_AXIS_ATTRIBUTE_LIST:
+           dissect_set_axis_attr_list_response(tvb, header_tree, offset + 4, size - 4, instance_id);
+           break;
+       case SC_GROUP_SYNC:
+           dissect_group_sync_response(tvb, header_tree, offset + 4);
+           break;
+       default:
+           /* Display the remainder of the service channel data */
+           proto_tree_add_item(header_tree, hf_cip_svc_data, tvb, offset + 4, size - 4, ENC_NA);
+           break;
+       }
    }
 
    return offset + size;
@@ -1517,51 +1578,41 @@ static void
 dissect_var_inst_header(tvbuff_t* tvb, proto_tree* tree, guint32 offset, guint8* inst_number, guint32* cyc_size,
                         guint32* cyc_blk_size, guint32* evnt_size, guint32* servc_size)
 {
-   guint8      temp_data;
-   proto_item *header_item;
    proto_tree *header_tree;
 
    /* Create the tree for the entire instance data header */
    *inst_number = tvb_get_guint8(tvb, offset);
 
-   header_item = proto_tree_add_text(tree, tvb, offset, 8, "Instance Data Header - Instance: %d", *inst_number);
-   header_tree = proto_item_add_subtree(header_item, ett_inst_data_header);
+   header_tree = proto_tree_add_subtree_format(tree, tvb, offset, 8, ett_inst_data_header, NULL,
+                                                "Instance Data Header - Instance: %d", *inst_number);
 
    /* Read the instance number field from the instance data header */
    proto_tree_add_item(header_tree, hf_var_devce_instance, tvb, offset, 1, ENC_LITTLE_ENDIAN);
 
    /* The "size" fields in the instance data block header are all stored as number of 32-bit words the
-   * block uses since all blocks should pad up to 32-bits so to convert to bytes each is mulitplied by 4 */
+   * block uses since all blocks should pad up to 32-bits so to convert to bytes each is multiplied by 4 */
 
    /* Read the instance block size field in bytes from the instance data header */
-   temp_data = tvb_get_guint8(tvb, offset + 2);
-   proto_tree_add_uint_format_value(header_tree, hf_var_devce_instance_block_size,
-                                    tvb, offset + 2, 1, temp_data, "%d words", temp_data);
+   proto_tree_add_item(header_tree, hf_var_devce_instance_block_size, tvb, offset + 2, 1, ENC_NA);
 
    /* Read the cyclic block size field in bytes from the instance data header */
-   temp_data = tvb_get_guint8(tvb, offset + 3);
-   proto_tree_add_uint_format_value(header_tree, hf_var_devce_cyclic_block_size,
-                                    tvb, offset + 3, 1, temp_data, "%d words", temp_data);
+   proto_tree_add_item(header_tree, hf_var_devce_cyclic_block_size, tvb, offset + 3, 1, ENC_NA);
 
    /* Read the cyclic command block size field in bytes from the instance data header */
    *cyc_size = (tvb_get_guint8(tvb, offset + 4) * 4);
-   proto_tree_add_uint_format_value(header_tree, hf_var_devce_cyclic_data_block_size,
-                                    tvb, offset + 4, 1, (*cyc_size)/4, "%d words", (*cyc_size)/4);
+   proto_tree_add_item(header_tree, hf_var_devce_cyclic_data_block_size, tvb, offset + 4, 1, ENC_NA);
 
    /* Read the cyclic write block size field in bytes from the instance data header */
    *cyc_blk_size = (tvb_get_guint8(tvb, offset + 5) * 4);
-   proto_tree_add_uint_format_value(header_tree, hf_var_devce_cyclic_rw_block_size,
-                                    tvb, offset + 5, 1, (*cyc_blk_size)/4, "%d words", (*cyc_blk_size)/4);
+   proto_tree_add_item(header_tree, hf_var_devce_cyclic_rw_block_size, tvb, offset + 5, 1, ENC_NA);
 
    /* Read the event block size in bytes from the instance data header */
    *evnt_size = (tvb_get_guint8(tvb, offset + 6) * 4);
-   proto_tree_add_uint_format_value(header_tree, hf_var_devce_event_block_size,
-                                    tvb, offset + 6, 1, (*evnt_size)/4, "%d words", (*evnt_size)/4);
+   proto_tree_add_item(header_tree, hf_var_devce_event_block_size, tvb, offset + 6, 1, ENC_NA);
 
    /* Read the service block size in bytes from the instance data header */
    *servc_size = (tvb_get_guint8(tvb, offset + 7) * 4);
-   proto_tree_add_uint_format_value(header_tree, hf_var_devce_service_block_size,
-                                    tvb, offset + 7, 1, (*servc_size)/4, "%d words", (*servc_size)/4);
+   proto_tree_add_item(header_tree, hf_var_devce_service_block_size, tvb, offset + 7, 1, ENC_NA);
 }
 
 /*
@@ -1575,55 +1626,39 @@ static guint32
 dissect_var_cont_conn_header(tvbuff_t* tvb, proto_tree* tree, guint32* inst_count, guint32 offset)
 {
    guint32     header_size;
-   guint32     temp_data;
-   proto_item *header_item, *temp_proto_item;
+   proto_item *temp_proto_item;
    proto_tree *header_tree, *temp_proto_tree;
 
    /* Calculate the header size, start with the basic header size */
    header_size = 8;
 
-   temp_data = tvb_get_guint8(tvb, offset + 7);
+   guint32 time_data_set = tvb_get_guint8(tvb, offset + 7);
 
    /* Check the time data set field for enabled bits. If either update period or
    * update time stamp fields are set, bump the header size by the appropriate size */
-   if ( (temp_data & TIME_DATA_SET_TIME_STAMP) == TIME_DATA_SET_TIME_STAMP )
+   if ( (time_data_set & TIME_DATA_SET_TIME_STAMP) == TIME_DATA_SET_TIME_STAMP )
    {
       header_size += 8;
    }
-   if ( (temp_data & TIME_DATA_SET_TIME_OFFSET) == TIME_DATA_SET_TIME_OFFSET )
+   if ( (time_data_set & TIME_DATA_SET_TIME_OFFSET) == TIME_DATA_SET_TIME_OFFSET )
    {
       header_size += 8;
    }
 
    /* Create the tree for the entire connection header */
-   header_item = proto_tree_add_text(tree, tvb, offset, header_size, "Connection Header");
-   header_tree = proto_item_add_subtree(header_item, ett_cont_dev_header);
+   header_tree = proto_tree_add_subtree(tree, tvb, offset, header_size, ett_cont_dev_header, NULL, "Connection Header");
 
    /* Add the connection header fields that are common to all types of messages */
    proto_tree_add_item(header_tree, hf_cip_format,   tvb, offset, 1, ENC_LITTLE_ENDIAN);
    proto_tree_add_item(header_tree, hf_cip_revision, tvb, offset + 1, 1, ENC_LITTLE_ENDIAN);
    proto_tree_add_item(header_tree, hf_cip_updateid, tvb, offset + 2, 1, ENC_LITTLE_ENDIAN);
 
-   /* Create the tree for the node control header field */
-   temp_proto_item = proto_tree_add_item(header_tree, hf_cip_node_control, tvb, offset + 3, 1, ENC_LITTLE_ENDIAN);
-   temp_proto_tree = proto_item_add_subtree(temp_proto_item, ett_node_control);
-
-   /* Add the individual data elements to the node control tree */
-   proto_tree_add_item(temp_proto_tree, hf_cip_node_control_remote, tvb, offset + 3, 1, ENC_LITTLE_ENDIAN);
-   proto_tree_add_item(temp_proto_tree, hf_cip_node_control_sync, tvb, offset + 3, 1, ENC_LITTLE_ENDIAN);
-   proto_tree_add_item(temp_proto_tree, hf_cip_node_data_valid, tvb, offset + 3, 1, ENC_LITTLE_ENDIAN);
-   proto_tree_add_item(temp_proto_tree, hf_cip_node_fault_reset, tvb, offset + 3, 1, ENC_LITTLE_ENDIAN);
-
-   /* Read the instance count field from the packet into memory, this gets passed back out of the method */
-   *inst_count = tvb_get_guint8(tvb, offset + 4);
+   dissect_node_control(NULL, header_tree, NULL, tvb, offset + 3, 1);
 
    /* Add the instance count and last update id to the connection header tree */
-   proto_tree_add_item(header_tree, hf_cip_instance_cnt, tvb, offset + 4, 1, ENC_LITTLE_ENDIAN);
+   proto_tree_add_item_ret_uint(header_tree, hf_cip_instance_cnt, tvb, offset + 4, 1, ENC_LITTLE_ENDIAN, inst_count);
    proto_tree_add_item(header_tree, hf_cip_last_update, tvb, offset + 6, 1, ENC_LITTLE_ENDIAN);
 
-   /* Read the time data set from the packet into memory */
-   temp_data = tvb_get_guint8(tvb, offset + 7);
-
    /* Create the tree for the time data set field */
    temp_proto_item = proto_tree_add_item(header_tree, hf_cip_time_data_set, tvb, offset + 7, 1, ENC_LITTLE_ENDIAN);
    temp_proto_tree = proto_item_add_subtree(temp_proto_item, ett_time_data_set);
@@ -1638,13 +1673,13 @@ dissect_var_cont_conn_header(tvbuff_t* tvb, proto_tree* tree, guint32* inst_coun
    offset = (offset + 7 + 1);
 
    /* Add the time values if they are present in the time data set header field */
-   if ( (temp_data & TIME_DATA_SET_TIME_STAMP) == TIME_DATA_SET_TIME_STAMP )
+   if ( (time_data_set & TIME_DATA_SET_TIME_STAMP) == TIME_DATA_SET_TIME_STAMP )
    {
       proto_tree_add_item(header_tree, hf_cip_cont_time_stamp, tvb, offset, 8, ENC_LITTLE_ENDIAN);
       offset = (offset + 8);
    }
 
-   if ( (temp_data & TIME_DATA_SET_TIME_OFFSET) == TIME_DATA_SET_TIME_OFFSET )
+   if ( (time_data_set & TIME_DATA_SET_TIME_OFFSET) == TIME_DATA_SET_TIME_OFFSET )
    {
       proto_tree_add_item(header_tree, hf_cip_cont_time_offset, tvb, offset, 8, ENC_LITTLE_ENDIAN);
       offset = (offset + 8);
@@ -1665,55 +1700,42 @@ static guint32
 dissect_var_devce_conn_header(tvbuff_t* tvb, proto_tree* tree, guint32* inst_count, guint32 offset)
 {
    guint32     header_size;
-   guint32     temp_data;
-   proto_item *header_item, *temp_proto_item;
+   proto_item *temp_proto_item;
    proto_tree *header_tree, *temp_proto_tree;
 
    /* Calculate the header size, start with the basic header size */
    header_size = 8;
 
-   temp_data = tvb_get_guint8(tvb, offset + 7);
-   if ( (temp_data & TIME_DATA_SET_TIME_STAMP) == TIME_DATA_SET_TIME_STAMP )
+   guint32 time_data_set = tvb_get_guint8(tvb, offset + 7);
+   if ( (time_data_set & TIME_DATA_SET_TIME_STAMP) == TIME_DATA_SET_TIME_STAMP )
    {
       header_size += 8;
    }
-   if ( (temp_data & TIME_DATA_SET_TIME_OFFSET) == TIME_DATA_SET_TIME_OFFSET )
+   if ( (time_data_set & TIME_DATA_SET_TIME_OFFSET) == TIME_DATA_SET_TIME_OFFSET )
    {
       header_size += 8;
    }
-   if ( (temp_data & TIME_DATA_SET_UPDATE_DIAGNOSTICS) == TIME_DATA_SET_UPDATE_DIAGNOSTICS )
+   if ( (time_data_set & TIME_DATA_SET_UPDATE_DIAGNOSTICS) == TIME_DATA_SET_UPDATE_DIAGNOSTICS )
    {
       header_size += 4;
    }
-   if ( (temp_data & TIME_DATA_SET_TIME_DIAGNOSTICS) == TIME_DATA_SET_TIME_DIAGNOSTICS )
+   if ( (time_data_set & TIME_DATA_SET_TIME_DIAGNOSTICS) == TIME_DATA_SET_TIME_DIAGNOSTICS )
    {
       header_size += 16;
    }
 
    /* Create the tree for the entire connection header */
-   header_item = proto_tree_add_text(tree, tvb, offset, header_size, "Connection Header");
-   header_tree = proto_item_add_subtree(header_item, ett_cont_dev_header);
+   header_tree = proto_tree_add_subtree(tree, tvb, offset, header_size, ett_cont_dev_header, NULL, "Connection Header");
 
    /* Add the connection header fields that are common to all types of messages */
    proto_tree_add_item(header_tree, hf_cip_format,   tvb, offset, 1, ENC_LITTLE_ENDIAN);
    proto_tree_add_item(header_tree, hf_cip_revision, tvb, offset + 1, 1, ENC_LITTLE_ENDIAN);
    proto_tree_add_item(header_tree, hf_cip_updateid, tvb, offset + 2, 1, ENC_LITTLE_ENDIAN);
 
-   /* Create the tree for the node status header field */
-   temp_proto_item = proto_tree_add_item(header_tree, hf_cip_node_status, tvb, offset + 3, 1, ENC_LITTLE_ENDIAN);
-   temp_proto_tree = proto_item_add_subtree(temp_proto_item, ett_node_status);
-
-   /* Add the individual data elements to the node control tree */
-   proto_tree_add_item(temp_proto_tree, hf_cip_node_control_remote, tvb, offset + 3, 1, ENC_LITTLE_ENDIAN);
-   proto_tree_add_item(temp_proto_tree, hf_cip_node_control_sync, tvb, offset + 3, 1, ENC_LITTLE_ENDIAN);
-   proto_tree_add_item(temp_proto_tree, hf_cip_node_data_valid, tvb, offset + 3, 1, ENC_LITTLE_ENDIAN);
-   proto_tree_add_item(temp_proto_tree, hf_cip_node_device_faulted, tvb, offset + 3, 1, ENC_LITTLE_ENDIAN);
-
-   /* Read the instance count field from the packet into memory, this gets passed back out of the method */
-   *inst_count = tvb_get_guint8(tvb, offset + 4);
+   dissect_node_status(NULL, header_tree, NULL, tvb, offset + 3, 1);
 
    /* Add the instance count to the connection header tree */
-   proto_tree_add_item(header_tree, hf_cip_instance_cnt, tvb, offset + 4, 1, ENC_LITTLE_ENDIAN);
+   proto_tree_add_item_ret_uint(header_tree, hf_cip_instance_cnt, tvb, offset + 4, 1, ENC_LITTLE_ENDIAN, inst_count);
 
    /* The device to controller header contains the node alarms and node faults fields as well. */
    proto_tree_add_item(header_tree, hf_cip_node_fltalarms, tvb, offset + 5, 1, ENC_LITTLE_ENDIAN);
@@ -1721,9 +1743,6 @@ dissect_var_devce_conn_header(tvbuff_t* tvb, proto_tree* tree, guint32* inst_cou
    /* Add the last update id to the connection header tree */
    proto_tree_add_item(header_tree, hf_cip_last_update, tvb, offset + 6, 1, ENC_LITTLE_ENDIAN);
 
-   /* Read the time data set from the packet into memory */
-   temp_data = tvb_get_guint8(tvb, offset + 7);
-
    /* Create the tree for the time data set field */
    temp_proto_item = proto_tree_add_item(header_tree, hf_cip_time_data_set, tvb, offset + 7, 1, ENC_LITTLE_ENDIAN);
    temp_proto_tree = proto_item_add_subtree(temp_proto_item, ett_time_data_set);
@@ -1738,19 +1757,19 @@ dissect_var_devce_conn_header(tvbuff_t* tvb, proto_tree* tree, guint32* inst_cou
    offset = (offset + 7 + 1);
 
    /* Add the time values if they are present in the time data set header field */
-   if ( (temp_data & TIME_DATA_SET_TIME_STAMP) == TIME_DATA_SET_TIME_STAMP )
+   if ( (time_data_set & TIME_DATA_SET_TIME_STAMP) == TIME_DATA_SET_TIME_STAMP )
    {
       proto_tree_add_item(header_tree, hf_cip_devc_time_stamp, tvb, offset, 8, ENC_LITTLE_ENDIAN);
       offset = (offset + 8);
    }
 
-   if ( (temp_data & TIME_DATA_SET_TIME_OFFSET) == TIME_DATA_SET_TIME_OFFSET )
+   if ( (time_data_set & TIME_DATA_SET_TIME_OFFSET) == TIME_DATA_SET_TIME_OFFSET )
    {
       proto_tree_add_item(header_tree, hf_cip_devc_time_offset, tvb, offset, 8, ENC_LITTLE_ENDIAN);
       offset = (offset + 8);
    }
 
-   if ( (temp_data & TIME_DATA_SET_UPDATE_DIAGNOSTICS) == TIME_DATA_SET_UPDATE_DIAGNOSTICS )
+   if ( (time_data_set & TIME_DATA_SET_UPDATE_DIAGNOSTICS) == TIME_DATA_SET_UPDATE_DIAGNOSTICS )
    {
       /* If the time diagnostic bit is set then the header contains the count of lost updates, late updates, data
       * received time stamp and data transmit time stamp */
@@ -1762,7 +1781,7 @@ dissect_var_devce_conn_header(tvbuff_t* tvb, proto_tree* tree, guint32* inst_cou
       offset = (offset + 3);
    }
 
-   if ( (temp_data & TIME_DATA_SET_TIME_DIAGNOSTICS) == TIME_DATA_SET_TIME_DIAGNOSTICS )
+   if ( (time_data_set & TIME_DATA_SET_TIME_DIAGNOSTICS) == TIME_DATA_SET_TIME_DIAGNOSTICS )
    {
       proto_tree_add_item(header_tree, hf_cip_data_rx_time_stamp, tvb, offset, 8, ENC_LITTLE_ENDIAN);
       offset += 8;
@@ -1784,108 +1803,132 @@ dissect_var_devce_conn_header(tvbuff_t* tvb, proto_tree* tree, guint32* inst_cou
  *
  * Returns: void
  */
-static void
-dissect_cipmotion(tvbuff_t* tvb, packet_info* pinfo, proto_tree* tree)
+static int
+dissect_cipmotion(tvbuff_t* tvb, packet_info* pinfo, proto_tree* tree, void* data)
 {
+   cip_io_data_input* io_data_input = (cip_io_data_input*)data;
+
    guint32     con_format;
-/*   guint32     seq_number; */
    guint32     update_id;
    proto_item *proto_item_top;
    proto_tree *proto_tree_top;
    guint32     offset = 0;
 
-   /* Pull the CIP class 1 sequence number from the incoming message */
-/*   seq_number = tvb_get_letohs(tvb, offset); */
+   guint8 ConnPoint = 2;
+   if (io_data_input && io_data_input->conn_info)
+   {
+      ConnPoint = io_data_input->conn_info->ConnPoint;
+   }
+
+   /* Create display subtree for the protocol by creating an item and then
+    * creating a subtree from the item, the subtree must have been registered
+    * in proto_register_cipmotion already */
+   proto_item_top = proto_tree_add_item(tree, proto_cipmotion, tvb, 0, -1, ENC_NA);
+   proto_tree_top = proto_item_add_subtree(proto_item_top, ett_cipmotion);
+
+   /* Add the CIP class 1 sequence number to the tree */
+   proto_tree_add_item(proto_tree_top, hf_cip_class1_seqnum, tvb, offset, 2, ENC_LITTLE_ENDIAN);
    offset = (offset + 2);
 
+   if (ConnPoint >= 3)
+   {
+       dissect_cip_run_idle(tvb, offset, proto_tree_top);
+       offset += 4;
+   }
+
    /* Pull the actual values for the connection format and update id from the
     * incoming message to be used in the column info */
    con_format = tvb_get_guint8(tvb, offset);
    update_id  = tvb_get_guint8(tvb, offset + 2);
 
    /* Make entries in Protocol column and Info column on summary display */
-   col_set_str(pinfo->cinfo, COL_PROTOCOL, "Motion");
+   col_set_str(pinfo->cinfo, COL_PROTOCOL, "CIP Motion");
 
    /* Add connection format and update number to the info column */
    col_add_fstr( pinfo->cinfo, COL_INFO, "%s, Update Id: %d",
                  val_to_str(con_format, cip_con_format_vals, "Unknown connection format (%x)"), update_id );
 
-   /* If tree is not NULL then Wireshark is requesting that the dissection
-    * panel be updated with the dissected packet, if tree is NULL then only
-    * the summary protocol and info columns need to be updated */
-   if ( tree )
+   /* Attempt to classify the incoming header */
+   if (( con_format == FORMAT_VAR_CONTROL_TO_DEVICE ) ||
+       ( con_format == FORMAT_VAR_DEVICE_TO_CONTROL ))
    {
-      /* Create display subtree for the protocol by creating an item and then
-       * creating a subtree from the item, the subtree must have been registered
-       * in proto_register_cipmotion already */
-      proto_item_top = proto_tree_add_item( tree, proto_cipmotion, tvb, 0, -1, ENC_NA );
-      proto_tree_top = proto_item_add_subtree( proto_item_top, ett_cipmotion );
-
-      /* Add the CIP class 1 sequence number to the tree */
-      proto_tree_add_item( proto_tree_top, hf_cip_class1_seqnum, tvb, 0, 2, ENC_LITTLE_ENDIAN );
-
-      /* Attempt to classify the incoming header */
-      if (( con_format == FORMAT_VAR_CONTROL_TO_DEVICE ) ||
-          ( con_format == FORMAT_VAR_DEVICE_TO_CONTROL ))
+      /* Sizes of the individual channels within the connection */
+      guint32 cyc_size, cyc_blk_size, evnt_size, servc_size;
+      guint32 inst_count = 0, inst;
+
+      /* Dissect the header fields */
+      switch(con_format)
+      {
+      case FORMAT_VAR_CONTROL_TO_DEVICE:
+         offset = dissect_var_cont_conn_header(tvb, proto_tree_top, &inst_count, offset);
+         break;
+      case FORMAT_VAR_DEVICE_TO_CONTROL:
+         offset = dissect_var_devce_conn_header(tvb, proto_tree_top, &inst_count, offset);
+         break;
+      }
+
+      /* Repeat the following dissections for each instance within the payload */
+      for( inst = 0; inst < inst_count; inst++ )
       {
-         /* Sizes of the individual channels within the connection */
-         guint32 cyc_size, cyc_blk_size, evnt_size, servc_size;
-         guint32 inst_count = 0, inst;
+         /* Actual instance number from header field */
+         guint8 instance;
+
+         /* Dissect the instance data header */
+         dissect_var_inst_header( tvb, proto_tree_top, offset, &instance,
+                                    &cyc_size, &cyc_blk_size, &evnt_size, &servc_size );
+
+         /* Increment the offset to just beyond the instance header */
+         offset += 8;
 
-         /* Dissect the header fields */
+         /* Dissect the cyclic command (actual) data if any exists */
+         /* Dissect the cyclic write (read) data if any exists */
+         /* Dissect the event data block if there is any event data */
          switch(con_format)
          {
          case FORMAT_VAR_CONTROL_TO_DEVICE:
-            offset = dissect_var_cont_conn_header(tvb, proto_tree_top, &inst_count, offset);
+            if ( cyc_size > 0 )
+               offset = dissect_cntr_cyclic(tvb, proto_tree_top, offset, cyc_size);
+            if ( cyc_blk_size > 0 )
+               offset = dissect_cyclic_wt(tvb, proto_tree_top, offset, cyc_blk_size);
+            if ( evnt_size > 0 )
+               offset = dissect_cntr_event(tvb, proto_tree_top, offset, evnt_size);
+            if ( servc_size > 0 )
+               offset = dissect_cntr_service(tvb, pinfo, proto_tree_top, offset, servc_size, instance);
             break;
          case FORMAT_VAR_DEVICE_TO_CONTROL:
-            offset = dissect_var_devce_conn_header(tvb, proto_tree_top, &inst_count, offset);
+            if ( cyc_size > 0 )
+               offset = dissect_device_cyclic(tvb, proto_tree_top, offset, cyc_size);
+            if ( cyc_blk_size > 0 )
+               offset = dissect_cyclic_rd( tvb, proto_tree_top, offset, cyc_blk_size );
+            if ( evnt_size > 0 )
+               offset = dissect_devce_event(tvb, proto_tree_top, offset, evnt_size);
+            if ( servc_size > 0 )
+               offset = dissect_devce_service(tvb, pinfo, proto_tree_top, offset, servc_size, instance);
             break;
          }
 
-         /* Repeat the following dissections for each instance within the payload */
-         for( inst = 0; inst < inst_count; inst++ )
-         {
-            /* Actual instance number from header field */
-            guint8 instance;
-
-            /* Dissect the instance data header */
-            dissect_var_inst_header( tvb, proto_tree_top, offset, &instance,
-                                     &cyc_size, &cyc_blk_size, &evnt_size, &servc_size );
-
-            /* Increment the offset to just beyond the instance header */
-            offset += 8;
-
-            /* Dissect the cyclic command (actual) data if any exists */
-            /* Dissect the cyclic write (read) data if any exists */
-            /* Dissect the event data block if there is any event data */
-            switch(con_format)
-            {
-            case FORMAT_VAR_CONTROL_TO_DEVICE:
-               if ( cyc_size > 0 )
-                  offset = dissect_cntr_cyclic( con_format, tvb, proto_tree_top, offset, cyc_size, instance );
-               if ( cyc_blk_size > 0 )
-                  offset = dissect_cyclic_wt(tvb, proto_tree_top, offset, cyc_blk_size);
-               if ( evnt_size > 0 )
-                  offset = dissect_cntr_event(tvb, proto_tree_top, offset, evnt_size);
-               if ( servc_size > 0 )
-                  offset = dissect_cntr_service(tvb, proto_tree_top, offset, servc_size);
-               break;
-            case FORMAT_VAR_DEVICE_TO_CONTROL:
-               if ( cyc_size > 0 )
-                  offset = dissect_devce_cyclic( con_format, tvb, proto_tree_top, offset, cyc_size, instance );
-               if ( cyc_blk_size > 0 )
-                  offset = dissect_cyclic_rd( tvb, proto_tree_top, offset, cyc_blk_size );
-               if ( evnt_size > 0 )
-                  offset = dissect_devce_event(tvb, proto_tree_top, offset, evnt_size);
-               if ( servc_size > 0 )
-                  offset = dissect_devce_service(tvb, proto_tree_top, offset, servc_size);
-               break;
-            }
-
-         } /* End of instance for( ) loop */
-      }
+      } /* End of instance for( ) loop */
    }
+
+   // Display any remaining unparsed data.
+   int remain_len = tvb_reported_length_remaining(tvb, offset);
+   if (remain_len > 0)
+   {
+      proto_tree_add_item(proto_tree_top, hf_cip_data, tvb, offset, remain_len, ENC_NA);
+   }
+
+   return tvb_captured_length(tvb);
+}
+
+static int dissect_cipmotion3(tvbuff_t* tvb, packet_info* pinfo, proto_tree* tree, void* data _U_)
+{
+   enip_conn_val_t conn_info;
+   conn_info.ConnPoint = 3;
+
+   cip_io_data_input io_data_input;
+   io_data_input.conn_info = &conn_info;
+
+   return dissect_cipmotion(tvb, pinfo, tree, &io_data_input);
 }
 
 /*
@@ -1902,215 +1945,964 @@ proto_register_cipmotion(void)
 {
    /* This is a list of header fields that can be used in the dissection or
    * to use in a filter expression */
-   static hf_register_info header_fields[] =
+   static hf_register_info hf[] =
    {
       /* Connection format header field, the first byte in the message which
       * determines if the message is fixed or variable, controller to device,
       * device to controller, etc. */
-      { &hf_cip_format, { "Connection Format", "cipm.format", FT_UINT8, BASE_DEC, VALS(cip_con_format_vals), 0, "Message connection format", HFILL }},
+      { &hf_cip_format,
+        { "Connection Format", "cipm.format",
+          FT_UINT8, BASE_DEC, VALS(cip_con_format_vals), 0,
+          "Message connection format", HFILL }
+      },
 
       /* Connection format revision header field */
-      { &hf_cip_revision, { "Format Revision", "cipm.revision", FT_UINT8, BASE_DEC, NULL, 0, "Message format revision", HFILL }},
-
-      { &hf_cip_class1_seqnum, { "CIP Class 1 Sequence Number", "cipm.class1seqnum", FT_UINT16, BASE_DEC, NULL, 0, NULL, HFILL }},
-      { &hf_cip_updateid, { "Update Id", "cipm.updateid", FT_UINT8, BASE_DEC, NULL, 0, "Cyclic Transaction Number", HFILL }},
-      { &hf_cip_instance_cnt, { "Instance Count", "cipm.instancecount", FT_UINT8, BASE_DEC, NULL, 0, NULL, HFILL }},
-      { &hf_cip_last_update, { "Last Update Id", "cipm.lastupdate", FT_UINT8, BASE_DEC, NULL, 0, NULL, HFILL }},
-      { &hf_cip_node_status, { "Node Status", "cipm.nodestatus", FT_UINT8, BASE_HEX, NULL, 0, NULL, HFILL}},
-      { &hf_cip_node_control, { "Node Control", "cipm.nodecontrol", FT_UINT8, BASE_HEX, NULL, 0, NULL, HFILL}},
-      { &hf_cip_node_control_remote, { "Remote Control", "cipm.remote", FT_BOOLEAN, 8, TFS(&tfs_true_false), 0x01, "Node Control: Remote Control", HFILL}},
-      { &hf_cip_node_control_sync, { "Sync Control", "cipm.sync", FT_BOOLEAN, 8, TFS(&tfs_true_false), 0x02, "Node Control: Synchronous Operation", HFILL}},
-      { &hf_cip_node_data_valid, { "Data Valid", "cipm.valid", FT_BOOLEAN, 8, TFS(&tfs_true_false), 0x04, "Node Control: Data Valid", HFILL}},
-      { &hf_cip_node_fault_reset, { "Fault Reset", "cipm.fltrst", FT_BOOLEAN, 8, TFS(&tfs_true_false), 0x08, "Node Control: Device Fault Reset", HFILL}},
-      { &hf_cip_node_device_faulted, { "Faulted", "cipm.flt", FT_BOOLEAN, 8, TFS(&tfs_true_false), 0x08, "Node Control: Device Faulted", HFILL}},
-      { &hf_cip_node_fltalarms, { "Node Faults and Alarms", "cipm.fltalarms", FT_UINT8, BASE_DEC, NULL, 0, NULL, HFILL }},
-      { &hf_cip_time_data_set, { "Time Data Set", "cipm.timedataset", FT_UINT8, BASE_HEX, NULL, 0, NULL, HFILL}},
-      { &hf_cip_time_data_stamp, { "Time Stamp", "cipm.time.stamp", FT_BOOLEAN, 8, TFS(&tfs_true_false), TIME_DATA_SET_TIME_STAMP, "Time Data Set: Time Stamp", HFILL}},
-      { &hf_cip_time_data_offset, { "Time Offset", "cipm.time.offset", FT_BOOLEAN, 8, TFS(&tfs_true_false), TIME_DATA_SET_TIME_OFFSET, "Time Data Set: Time Offset", HFILL}},
-      { &hf_cip_time_data_diag, { "Time Update Diagnostics", "cipm.time.update", FT_BOOLEAN, 8, TFS(&tfs_true_false), TIME_DATA_SET_UPDATE_DIAGNOSTICS, "Time Data Set: Time Update Diagnostics", HFILL}},
-      { &hf_cip_time_data_time_diag, { "Time Diagnostics", "cipm.time.diag", FT_BOOLEAN, 8, TFS(&tfs_true_false), TIME_DATA_SET_TIME_DIAGNOSTICS, "Time Data Set: Time Diagnostics", HFILL}},
-
-      { &hf_cip_cont_time_stamp, { "Controller Time Stamp", "cipm.ctrltimestamp", FT_UINT64, BASE_DEC, NULL, 0, "Time Data Set: Controller Time Stamp", HFILL}},
-      { &hf_cip_cont_time_offset, { "Controller Time Offset", "cipm.ctrltimeoffser", FT_UINT64, BASE_DEC, NULL, 0, "Time Data Set: Controller Time Offset", HFILL}},
-      { &hf_cip_data_rx_time_stamp, { "Data Received Time Stamp", "cipm.rxtimestamp", FT_UINT64, BASE_DEC, NULL, 0, "Time Data Set: Data Received Time Stamp", HFILL}},
-      { &hf_cip_data_tx_time_stamp, { "Data Transmit Time Stamp", "cipm.txtimestamp", FT_UINT64, BASE_DEC, NULL, 0, "Time Data Set: Data Transmit Time Offset", HFILL}},
-      { &hf_cip_devc_time_stamp, { "Device Time Stamp", "cipm.devctimestamp", FT_UINT64, BASE_DEC, NULL, 0, "Time Data Set: Device Time Stamp", HFILL} },
-      { &hf_cip_devc_time_offset, { "Device Time Offset", "cipm.devctimeoffser", FT_UINT64, BASE_DEC, NULL, 0, "Time Data Set: Device Time Offset", HFILL}},
-      { &hf_cip_lost_update, { "Lost Updates", "cipm.lostupdates", FT_UINT8, BASE_DEC, NULL, 0, "Time Data Set: Lost Updates", HFILL}},
-      { &hf_cip_late_update, { "Lost Updates", "cipm.lateupdates", FT_UINT8, BASE_DEC, NULL, 0, "Time Data Set: Late Updates", HFILL}},
-
-      { &hf_cip_motor_cntrl, { "Control Mode", "cipm.ctrlmode", FT_UINT8, BASE_DEC, VALS(cip_motor_control_vals), 0, "Cyclic Data Block: Motor Control Mode", HFILL }},
-      { &hf_cip_fdbk_config, { "Feedback Config", "cipm.fdbkcfg", FT_UINT8, BASE_DEC, VALS(cip_fdbk_config_vals), 0, "Cyclic Data Block: Feedback Configuration", HFILL }},
-      { &hf_cip_axis_control, { "Axis Control", "cipm.axisctrl", FT_UINT8, BASE_DEC, VALS(cip_axis_control_vals), 0, "Cyclic Data Block: Axis Control", HFILL }},
-      { &hf_cip_control_status, { "Control Status", "cipm.csts", FT_UINT8, BASE_DEC, VALS(cip_control_status_vals), 0, "Cyclic Data Block: Axis Control Status", HFILL }},
-      { &hf_cip_axis_response, { "Axis Response", "cipm.axisresp", FT_UINT8, BASE_DEC, VALS(cip_axis_response_vals), 0, "Cyclic Data Block: Axis Response", HFILL }},
-      { &hf_cip_axis_resp_stat, { "Response Status", "cipm.respstat", FT_UINT8, BASE_DEC|BASE_EXT_STRING, &cip_gs_vals_ext, 0, "Cyclic Data Block: Axis Response Status", HFILL }},
-      { &hf_cip_group_sync, { "Group Sync Status", "cipm.syncstatus", FT_UINT8, BASE_HEX, VALS(cip_sync_status_vals), 0, NULL, HFILL }},
-      { &hf_cip_cmd_data_set, { "Command Data Set", "cipm.cmdset", FT_UINT8, BASE_HEX, NULL, 0, NULL, HFILL}},
-      { &hf_cip_act_data_set, { "Actual Data Set", "cipm.actset", FT_UINT8, BASE_HEX, NULL, 0, NULL, HFILL}},
-      { &hf_cip_sts_data_set, { "Status Data Set", "cipm.stsset", FT_UINT8, BASE_HEX, NULL, 0, NULL, HFILL}},
-      { &hf_cip_cmd_data_pos_cmd, { "Command Position", "cipm.cmd.pos", FT_BOOLEAN, 8, TFS(&tfs_true_false), COMMAND_DATA_SET_POSITION, "Command Data Set: Command Position", HFILL}},
-      { &hf_cip_cmd_data_vel_cmd, { "Command Velocity", "cipm.cmd.vel", FT_BOOLEAN, 8, TFS(&tfs_true_false), COMMAND_DATA_SET_VELOCITY, "Command Data Set: Command Velocity", HFILL}},
-      { &hf_cip_cmd_data_acc_cmd, { "Command Acceleration", "cipm.cmd.acc", FT_BOOLEAN, 8, TFS(&tfs_true_false), COMMAND_DATA_SET_ACCELERATION, "Command Data Set: Command Acceleration", HFILL}},
-      { &hf_cip_cmd_data_trq_cmd, { "Command Torque", "cipm.cmd.trq", FT_BOOLEAN, 8, TFS(&tfs_true_false), COMMAND_DATA_SET_TORQUE, "Command Data Set: Command Torque", HFILL}},
-      { &hf_cip_cmd_data_pos_trim_cmd, { "Position Trim", "cipm.cmd.postrm", FT_BOOLEAN, 8, TFS(&tfs_true_false), COMMAND_DATA_SET_POSITION_TRIM, "Command Data Set: Position Trim", HFILL}},
-      { &hf_cip_cmd_data_vel_trim_cmd, { "Velocity Trim", "cipm.cmd.veltrm", FT_BOOLEAN, 8, TFS(&tfs_true_false), COMMAND_DATA_SET_VELOCITY_TRIM, "Command Data Set: Velocity Trim", HFILL}},
-      { &hf_cip_cmd_data_acc_trim_cmd, { "Acceleration Trim", "cipm.cmd.acctrm", FT_BOOLEAN, 8, TFS(&tfs_true_false), COMMAND_DATA_SET_ACCELERATION_TRIM, "Command Data Set: Acceleration Trim", HFILL}},
-      { &hf_cip_cmd_data_trq_trim_cmd, { "Torque Trim", "cipm.cmd.trqtrm", FT_BOOLEAN, 8, TFS(&tfs_true_false), COMMAND_DATA_SET_TORQUE_TRIM, "Command Data Set: Torque Trim", HFILL}},
-
-      { &hf_cip_act_data_pos, { "Actual Position", "cipm.act.pos", FT_BOOLEAN, 8, TFS(&tfs_true_false), ACTUAL_DATA_SET_POSITION, "Acutal Data Set: Actual Position", HFILL}},
-      { &hf_cip_act_data_vel, { "Actual Velocity", "cipm.act.vel", FT_BOOLEAN, 8, TFS(&tfs_true_false), ACTUAL_DATA_SET_VELOCITY, "Actual Data Set: Actual Velocity", HFILL}},
-      { &hf_cip_act_data_acc, { "Actual Acceleration", "cipm.act.acc", FT_BOOLEAN, 8, TFS(&tfs_true_false), ACTUAL_DATA_SET_ACCELERATION, "Actual Data Set: Actual Acceleration", HFILL}},
-      { &hf_cip_act_data_trq, { "Actual Torque", "cipm.act.trq", FT_BOOLEAN, 8, TFS(&tfs_true_false), ACTUAL_DATA_SET_TORQUE, "Actual Data Set: Actual Torque", HFILL}},
-      { &hf_cip_act_data_crnt, { "Actual Current", "cipm.act.crnt", FT_BOOLEAN, 8, TFS(&tfs_true_false), ACTUAL_DATA_SET_CURRENT, "Actual Data Set: Actual Current", HFILL}},
-      { &hf_cip_act_data_vltg, { "Actual Voltage", "cipm.act.vltg", FT_BOOLEAN, 8, TFS(&tfs_true_false), ACTUAL_DATA_SET_VOLTAGE, "Actual Data Set: Actual Voltage", HFILL}},
-      { &hf_cip_act_data_fqcy, { "Actual Frequency", "cipm.act.fqcy", FT_BOOLEAN, 8, TFS(&tfs_true_false), ACTUAL_DATA_SET_FREQUENCY, "Actual Data Set: Actual Frequency", HFILL}},
-
-      { &hf_cip_axis_fault, { "Axis Fault Code", "cipm.fault.code", FT_UINT8, BASE_DEC, NULL, 0, "Status Data Set: Fault Code", HFILL }},
-      { &hf_cip_fault_type, { "Axis Fault Type", "cipm.flttype", FT_UINT8, BASE_DEC, NULL, 0, "Axis Status: Axis Fault Type", HFILL}},
-      { &hf_cip_fault_sub_code, { "Axis Fault Sub Code", "cipm.fltsubcode", FT_UINT8, BASE_DEC, NULL, 0, "Axis Status: Axis Fault Sub Code", HFILL}},
-      { &hf_cip_fault_action, { "Axis Fault Action", "cipm.fltaction", FT_UINT8, BASE_DEC, NULL, 0, "Axis Status: Axis Fault Action", HFILL}},
-      { &hf_cip_fault_time_stamp, { "Axis Fault Time Stamp", "cipm.flttimestamp", FT_UINT64,  BASE_DEC, NULL, 0, "Axis Status: Axis Fault Time Stamp", HFILL}},
-      { &hf_cip_alarm_type, { "Axis Fault Type", "cipm.alarmtype", FT_UINT8,  BASE_DEC, NULL, 0, "Axis Status: Axis Alarm Type", HFILL}},
-      { &hf_cip_alarm_sub_code, { "Axis Alarm Sub Code", "cipm.alarmsubcode", FT_UINT8,  BASE_DEC, NULL, 0, "Axis Status: Axis Alarm Sub Code", HFILL} },
-      { &hf_cip_alarm_state, { "Axis Alarm State", "cipm.alarmstate", FT_UINT8,  BASE_DEC, NULL, 0, "Axis Status: Axis Alarm State", HFILL }},
-      { &hf_cip_alarm_time_stamp, { "Axis Fault Time Stamp", "cipm.alarmtimestamp", FT_UINT64,  BASE_DEC, NULL, 0, "Axis Status: Axis Alarm Time Stamp", HFILL}},
-      { &hf_cip_axis_status, { "Axis Status", "cipm.axisstatus", FT_UINT32, BASE_HEX, NULL, 0, NULL, HFILL}},
-      { &hf_cip_axis_status_mfg, { "Axis Status Mfg", "cipm.axisstatusmfg", FT_UINT32, BASE_HEX, NULL, 0, "Axis Status, Manufacturer Specific", HFILL}},
-      { &hf_cip_axis_io_status, { "Axis I/O Status", "cipm.axisiostatus", FT_UINT32, BASE_HEX, NULL, 0, NULL, HFILL}},
-      { &hf_cip_axis_io_status_mfg, { "Axis I/O Status Mfg", "cipm.axisiostatusmfg", FT_UINT32, BASE_HEX, NULL, 0, "Axis I/O Status, Manufacturer Specific", HFILL}},
-      { &hf_cip_safety_status, { "Axis Safety Status", "cipm.safetystatus", FT_UINT32, BASE_HEX, NULL, 0, NULL, HFILL}},
-      { &hf_cip_sts_flt, { "Axis Fault Codes", "cipm.sts.flt", FT_BOOLEAN, 8, TFS(&tfs_true_false), STATUS_DATA_SET_AXIS_FAULT, "Status Data Set: Axis Fault Codes", HFILL}},
-      { &hf_cip_sts_alrm, { "Axis Alarm Codes", "cipm.sts.alarm", FT_BOOLEAN, 8, TFS(&tfs_true_false), STATUS_DATA_SET_AXIS_ALARM, "Status Data Set: Axis Alarm Codes", HFILL}},
-      { &hf_cip_sts_sts, { "Axis Status", "cipm.sts.sts", FT_BOOLEAN, 8, TFS(&tfs_true_false), STATUS_DATA_SET_AXIS_STATUS, "Status Data Set: Axis Status", HFILL}},
-      { &hf_cip_sts_iosts, { "Axis I/O Status", "cipm.sts.iosts", FT_BOOLEAN, 8, TFS(&tfs_true_false), STATUS_DATA_SET_AXIS_IO_STATUS, "Status Data Set: Axis I/O Status", HFILL}},
-      { &hf_cip_sts_safety, { "Axis Safety Status", "cipm.sts.safety", FT_BOOLEAN, 8, TFS(&tfs_true_false), STATUS_DATA_SET_AXIS_SAFETY, "Status Data Set: Axis Safety Status", HFILL}},
-
-      { &hf_cip_intrp, { "Interpolation Control", "cipm.intrp", FT_UINT8, BASE_DEC, VALS(cip_interpolation_vals), COMMAND_CONTROL_TARGET_UPDATE, "Cyclic Data Block: Interpolation Control", HFILL}},
-      { &hf_cip_position_data_type, { "Position Data Type", "cipm.posdatatype", FT_UINT8, BASE_DEC, VALS(cip_pos_data_type_vals), COMMAND_CONTROL_POSITION_DATA_TYPE, "Cyclic Data Block: Position Data Type", HFILL }},
-      { &hf_cip_axis_state, { "Axis State", "cipm.axste", FT_UINT8,  BASE_DEC, VALS(cip_axis_state_vals), 0, "Cyclic Data Block: Axis State", HFILL}},
-      { &hf_cip_command_control, { "Command Control", "cipm.cmdcontrol", FT_UINT8, BASE_DEC, NULL, 0, "Cyclic Data Block: Command Control", HFILL }},
-      { &hf_cip_cyclic_wrt_data, { "Write Data", "cipm.writedata", FT_BYTES, BASE_NONE, NULL, 0, "Cyclic Write: Data", HFILL }},
-      { &hf_cip_cyclic_rd_data, { "Read Data", "cipm.readdata", FT_BYTES, BASE_NONE, NULL, 0, "Cyclic Read: Data", HFILL }},
-      { &hf_cip_cyclic_write_blk, { "Write Block", "cipm.writeblk", FT_UINT8,  BASE_DEC, NULL, 0, "Cyclic Data Block: Write Block Id", HFILL }},
-      { &hf_cip_cyclic_read_blk, { "Read Block", "cipm.readblk", FT_UINT8,  BASE_DEC, NULL, 0, "Cyclic Data Block: Read Block Id", HFILL}},
-      { &hf_cip_cyclic_write_sts, { "Write Status", "cipm.writests", FT_UINT8,  BASE_DEC, NULL, 0, "Cyclic Data Block: Write Status", HFILL }},
-      { &hf_cip_cyclic_read_sts, { "Read Status", "cipm.readsts", FT_UINT8,  BASE_DEC, NULL, 0, "Cyclic Data Block: Read Status", HFILL }},
-      { &hf_cip_event_checking, { "Event Control", "cipm.evntchkcontrol", FT_UINT32,  BASE_HEX, NULL, 0, "Event Channel: Event Checking Control", HFILL}},
-      { &hf_cip_event_ack, { "Event Acknowledgement", "cipm.evntack", FT_UINT8,  BASE_DEC, NULL, 0, "Event Channel: Event Acknowledgement", HFILL} },
-      { &hf_cip_event_status, { "Event Status", "cipm.evntchkstatus", FT_UINT32, BASE_HEX, NULL, 0, "Event Channel: Event Checking Status", HFILL} },
-      { &hf_cip_event_id, { "Event Id", "cipm.evntack", FT_UINT8, BASE_DEC, NULL, 0, "Event Channel: Event Id", HFILL }},
-      { &hf_cip_event_pos, { "Event Position", "cipm.evntpos", FT_INT32,  BASE_DEC, NULL, 0, "Event Channel: Event Position", HFILL} },
-      { &hf_cip_event_ts, { "Event Time Stamp", "cipm.evntimestamp", FT_UINT64, BASE_DEC, NULL, 0, "Event Channel: Time Stamp", HFILL}},
-
-      { &hf_cip_evnt_ctrl_reg1_pos, { "Reg 1 Pos Edge", "cipm.evnt.ctrl.reg1posedge", FT_BOOLEAN, 32, TFS(&tfs_true_false), 0x00000001, "Event Checking Control: Reg 1 Pos Edge", HFILL}},
-      { &hf_cip_evnt_ctrl_reg1_neg, { "Reg 1 Neg Edge", "cipm.evnt.ctrl.reg1negedge", FT_BOOLEAN, 32, TFS(&tfs_true_false), 0x00000002, "Event Checking Control: Reg 1 Neg Edge", HFILL}},
-      { &hf_cip_evnt_ctrl_reg2_pos, { "Reg 2 Pos Edge", "cipm.evnt.ctrl.reg2posedge", FT_BOOLEAN, 32, TFS(&tfs_true_false), 0x00000004, "Event Checking Control: Reg 2 Pos Edge", HFILL}},
-      { &hf_cip_evnt_ctrl_reg2_neg, { "Reg 2 Neg Edge", "cipm.evnt.ctrl.reg2negedge", FT_BOOLEAN, 32, TFS(&tfs_true_false), 0x00000008, "Event Checking Control: Reg 2 Neg Edge", HFILL}},
-      { &hf_cip_evnt_ctrl_reg1_posrearm, { "Reg 1 Pos Rearm", "cipm.evnt.ctrl.reg1posrearm", FT_BOOLEAN, 32, TFS(&tfs_true_false), 0x00000100, "Event Checking Control: Reg 1 Pos Rearm", HFILL}},
-      { &hf_cip_evnt_ctrl_reg1_negrearm, { "Reg 1 Neg Rearm", "cipm.evnt.ctrl.reg1negrearm", FT_BOOLEAN, 32, TFS(&tfs_true_false), 0x00000200, "Event Checking Control: Reg 1 Neg Rearm", HFILL}},
-      { &hf_cip_evnt_ctrl_reg2_posrearm, { "Reg 2 Pos Rearm", "cipm.evnt.ctrl.reg2posrearm", FT_BOOLEAN, 32, TFS(&tfs_true_false), 0x00000400, "Event Checking Control: Reg 2 Pos Rearm", HFILL}},
-      { &hf_cip_evnt_ctrl_reg2_negrearm, { "Reg 2 Neg Rearm", "cipm.evnt.ctrl.reg2negrearm", FT_BOOLEAN, 32, TFS(&tfs_true_false), 0x00000800, "Event Checking Control: Reg 2 Neg Rearm", HFILL}},
-      { &hf_cip_evnt_ctrl_marker_pos, { "Marker Pos Edge", "cipm.evnt.ctrl.mrkrpos", FT_BOOLEAN, 32, TFS(&tfs_true_false), 0x00010000, "Event Checking Control: Marker Pos Edge", HFILL}},
-      { &hf_cip_evnt_ctrl_marker_neg, { "Marker Neg Edge", "cipm.evnt.ctrl.mrkrneg", FT_BOOLEAN, 32, TFS(&tfs_true_false), 0x00020000, "Event Checking Control: Marker Neg Edge", HFILL}},
-      { &hf_cip_evnt_ctrl_home_pos, { "Home Pos Edge", "cipm.evnt.ctrl.homepos", FT_BOOLEAN, 32, TFS(&tfs_true_false), 0x00040000, "Event Checking Control: Home Pos Edge", HFILL}},
-      { &hf_cip_evnt_ctrl_home_neg, { "Home Neg Edge", "cipm.evnt.ctrl.homeneg", FT_BOOLEAN, 32, TFS(&tfs_true_false), 0x00080000, "Event Checking Control: Home Neg Edge", HFILL}},
-      { &hf_cip_evnt_ctrl_home_pp, { "Home-Switch-Marker Plus Plus", "cipm.evnt.ctrl.homepp", FT_BOOLEAN, 32, TFS(&tfs_true_false), 0x00100000, "Event Checking Control: Home-Switch-Marker Plus Plus", HFILL}},
-      { &hf_cip_evnt_ctrl_home_pm, { "Home-Switch-Marker Plus Minus", "cipm.evnt.ctrl.homepm", FT_BOOLEAN, 32, TFS(&tfs_true_false), 0x00200000, "Event Checking Control: Home-Switch-Marker Plus Minus", HFILL}},
-      { &hf_cip_evnt_ctrl_home_mp,{ "Home-Switch-Marker Minus Plus", "cipm.evnt.ctrl.homemp", FT_BOOLEAN, 32, TFS(&tfs_true_false), 0x00400000, "Event Checking Control: Home-Switch-Marker Minus Plus", HFILL}},
-      { &hf_cip_evnt_ctrl_home_mm, { "Home-Switch-Marker Minus Minus", "cipm.evnt.ctrl.homemm", FT_BOOLEAN, 32, TFS(&tfs_true_false), 0x00800000, "Event Checking Control: Home-Switch-Marker Minus Minus", HFILL}},
-      { &hf_cip_evnt_ctrl_acks, { "Event Acknowledge Blocks", "cipm.evnt.ctrl.acks", FT_UINT32, BASE_DEC, NULL, 0x70000000, "Event Checking Control: Event Acknowledge Blocks", HFILL}},
-      { &hf_cip_evnt_extend_format, { "Extended Event Format", "cipm.evnt.extend", FT_BOOLEAN, 32, TFS(&tfs_true_false), 0x80000000, "Event Checking Control: Extended Event Format", HFILL}},
-
-      { &hf_cip_evnt_sts_reg1_pos,{ "Reg 1 Pos Edge", "cipm.evnt.sts.reg1posedge", FT_BOOLEAN, 32, TFS(&tfs_true_false), 0x00000001, "Event Checking Status: Reg 1 Pos Edge", HFILL}},
-      { &hf_cip_evnt_sts_reg1_neg, { "Reg 1 Neg Edge", "cipm.evnt.sts.reg1negedge", FT_BOOLEAN, 32, TFS(&tfs_true_false), 0x00000002, "Event Checking Status: Reg 1 Neg Edge", HFILL }},
-      { &hf_cip_evnt_sts_reg2_pos, { "Reg 2 Pos Edge", "cipm.evnt.sts.reg2posedge", FT_BOOLEAN, 32, TFS(&tfs_true_false), 0x00000004, "Event Checking Status: Reg 2 Pos Edge", HFILL}},
-      { &hf_cip_evnt_sts_reg2_neg, { "Reg 2 Neg Edge", "cipm.evnt.sts.reg2negedge", FT_BOOLEAN, 32, TFS(&tfs_true_false), 0x00000008, "Event Checking Status: Reg 2 Neg Edge", HFILL}},
-      { &hf_cip_evnt_sts_reg1_posrearm, { "Reg 1 Pos Rearm", "cipm.evnt.sts.reg1posrearm", FT_BOOLEAN, 32, TFS(&tfs_true_false), 0x00000100, "Event Checking Status: Reg 1 Pos Rearm", HFILL}},
-      { &hf_cip_evnt_sts_reg1_negrearm, { "Reg 1 Neg Rearm", "cipm.evnt.sts.reg1negrearm", FT_BOOLEAN, 32, TFS(&tfs_true_false), 0x00000200, "Event Checking Status: Reg 1 Neg Rearm", HFILL}},
-      { &hf_cip_evnt_sts_reg2_posrearm, { "Reg 2 Pos Rearm", "cipm.evnt.sts.reg2posrearm", FT_BOOLEAN, 32, TFS(&tfs_true_false), 0x00000400, "Event Checking Status: Reg 2 Pos Rearm", HFILL}},
-      { &hf_cip_evnt_sts_reg2_negrearm, { "Reg 2 Neg Rearm", "cipm.evnt.sts.reg2negrearm", FT_BOOLEAN, 32, TFS(&tfs_true_false), 0x00000800, "Event Checking Status: Reg 2 Neg Rearm", HFILL}},
-      { &hf_cip_evnt_sts_marker_pos, { "Marker Pos Edge", "cipm.evnt.sts.mrkrpos", FT_BOOLEAN, 32, TFS(&tfs_true_false), 0x00010000, "Event Checking Status: Marker Pos Edge", HFILL}},
-      { &hf_cip_evnt_sts_marker_neg, { "Marker Neg Edge", "cipm.evnt.sts.mrkrneg", FT_BOOLEAN, 32, TFS(&tfs_true_false), 0x00020000, "Event Checking Status: Marker Neg Edge", HFILL }},
-      { &hf_cip_evnt_sts_home_pos, { "Home Pos Edge", "cipm.evnt.sts.homepos", FT_BOOLEAN, 32, TFS(&tfs_true_false), 0x00040000, "Event Checking Status: Home Pos Edge", HFILL}},
-      { &hf_cip_evnt_sts_home_neg, { "Home Neg Edge", "cipm.evnt.sts.homeneg", FT_BOOLEAN, 32, TFS(&tfs_true_false), 0x00080000, "Event Checking Status: Home Neg Edge", HFILL }},
-      { &hf_cip_evnt_sts_home_pp, { "Home-Switch-Marker Plus Plus", "cipm.evnt.sts.homepp", FT_BOOLEAN, 32, TFS(&tfs_true_false), 0x00100000, "Event Checking Status: Home-Switch-Marker Plus Plus", HFILL}},
-      { &hf_cip_evnt_sts_home_pm, { "Home-Switch-Marker Plus Minus", "cipm.evnt.sts.homepm", FT_BOOLEAN, 32, TFS(&tfs_true_false), 0x00200000, "Event Checking Status: Home-Switch-Marker Plus Minus", HFILL}},
-      { &hf_cip_evnt_sts_home_mp, { "Home-Switch-Marker Minus Plus", "cipm.evnt.sts.homemp", FT_BOOLEAN, 32, TFS(&tfs_true_false), 0x00400000, "Event Checking Status: Home-Switch-Marker Minus Plus", HFILL}},
-      { &hf_cip_evnt_sts_home_mm, { "Home-Switch-Marker Minus Minus", "cipm.evnt.sts.homemm", FT_BOOLEAN, 32, TFS(&tfs_true_false), 0x00800000, "Event Checking Status: Home-Switch-Marker Minus Minus", HFILL}},
-      { &hf_cip_evnt_sts_nfs, { "Event Notification Blocks", "cipm.evnt.sts.nfs", FT_UINT32, BASE_DEC, NULL, 0x70000000, "Event Checking Status: Event Notification Blocks", HFILL}},
-
-      { &hf_cip_evnt_sts_stat, { "Event Status", "cipm.evnt.stat", FT_UINT8,  BASE_DEC|BASE_EXT_STRING, &cip_gs_vals_ext, 0, "Event Data Block: Event Status", HFILL }},
-      { &hf_cip_evnt_type, { "Event Type", "cipm.evnt.type", FT_UINT8,  BASE_DEC, VALS(cip_event_type_vals), 0, "Event Data Block: Event Type", HFILL}},
-      { &hf_cip_svc_code, { "Service Code", "cipm.svc.code", FT_UINT8, BASE_DEC, VALS(cip_sc_vals), 0, "Service Data Block: Service Code", HFILL}},
-      { &hf_cip_svc_sts, { "General Status", "cipm.svc.sts", FT_UINT8, BASE_DEC|BASE_EXT_STRING, &cip_gs_vals_ext, 0, "Service Data Block: General Status", HFILL }},
-      { &hf_cip_svc_transction, { "Transaction Id", "cipm.svc.tranid", FT_UINT8, BASE_DEC, NULL, 0, "Service Data Block: Transaction Id", HFILL }},
-      { &hf_cip_svc_ext_status, { "Extended Status", "cipm.svc.extstatus", FT_UINT8, BASE_DEC, NULL, 0, "Service Data Block: Extended Status", HFILL }},
-      { &hf_cip_svc_data, { "Service Data", "cipm.svc.data", FT_BYTES, BASE_NONE, NULL, 0, "Service Data Block: Data", HFILL }},
-      { &hf_cip_attribute_data, { "Attribute Data", "cipm.attrdata", FT_BYTES, BASE_NONE, NULL, 0, "Attribute Service: Data", HFILL }},
-      { &hf_cip_ptp_grandmaster, { "Grandmaster", "cipm.grandmaster", FT_UINT64, BASE_HEX, NULL, 0, "Group Sync: Grandmaster Id", HFILL}},
-
-      { &hf_cip_svc_get_axis_attr_sts, { "Attribute Status", "cipm.getaxisattr.sts", FT_UINT8, BASE_DEC|BASE_EXT_STRING, &cip_gs_vals_ext, 0, "Service Channel: Get Axis Attribute List Response Status", HFILL }},
-      { &hf_get_axis_attr_list_attribute_cnt, { "Number of attributes", "cipm.getaxisattr.cnt", FT_UINT16, BASE_DEC, NULL, 0, "Service Channel: Get Axis Attribute List Attribute Count", HFILL}},
-      { &hf_get_axis_attr_list_attribute_id, { "Attribute ID", "cipm.getaxisattr.id", FT_UINT16, BASE_DEC, NULL, 0, "Service Channel: Get Axis Attribute List Attribute ID", HFILL}},
-      { &hf_get_axis_attr_list_dimension, { "Dimension", "cipm.getaxisattr.dimension", FT_UINT8, BASE_DEC, NULL, 0, "Service Channel: Get Axis Attribute List Dimension", HFILL}},
-      { &hf_get_axis_attr_list_element_size, { "Element size", "cipm.getaxisattr.element_size", FT_UINT8, BASE_DEC, NULL, 0, "Service Channel: Get Axis Attribute List Element Size", HFILL}},
-      { &hf_get_axis_attr_list_start_index, { "Start index", "cipm.getaxisattr.start_index", FT_UINT16, BASE_DEC, NULL, 0, "Service Channel: Get Axis Attribute List Start index", HFILL}},
-      { &hf_get_axis_attr_list_data_elements, { "Data elements", "cipm.getaxisattr.data_elements", FT_UINT16, BASE_DEC, NULL, 0, "Service Channel: Get Axis Attribute List Data elements", HFILL}},
-
-      { &hf_cip_svc_set_axis_attr_sts, { "Attribute Status", "cipm.setaxisattr.sts", FT_UINT8, BASE_DEC|BASE_EXT_STRING, &cip_gs_vals_ext, 0, "Service Channel: Set Axis Attribute List Response Status", HFILL }},
-      { &hf_set_axis_attr_list_attribute_cnt, { "Number of attributes", "cipm.setaxisattr.cnt", FT_UINT16, BASE_DEC, NULL, 0, "Service Channel: Set Axis Attribute List Attribute Count", HFILL}},
-      { &hf_set_axis_attr_list_attribute_id, { "Attribute ID", "cipm.setaxisattr.id", FT_UINT16, BASE_DEC, NULL, 0, "Service Channel: Set Axis Attribute List Attribute ID", HFILL}},
-      { &hf_set_axis_attr_list_dimension, { "Dimension", "cipm.setaxisattr.dimension", FT_UINT8, BASE_DEC, NULL, 0, "Service Channel: Set Axis Attribute List Dimension", HFILL}},
-      { &hf_set_axis_attr_list_element_size, { "Element size", "cipm.setaxisattr.element_size", FT_UINT8, BASE_DEC, NULL, 0, "Service Channel: Set Axis Attribute List Element Size", HFILL}},
-      { &hf_set_axis_attr_list_start_index, { "Start index", "cipm.setaxisattr.start_index", FT_UINT16, BASE_DEC, NULL, 0, "Service Channel: Set Axis Attribute List Start index", HFILL}},
-      { &hf_set_axis_attr_list_data_elements, { "Data elements", "cipm.setaxisattr.data_elements", FT_UINT16, BASE_DEC, NULL, 0, "Service Channel: Set Axis Attribute List Data elements", HFILL}},
-
-      { &hf_var_devce_instance, { "Instance Number", "cipm.var_devce.header.instance", FT_UINT8, BASE_DEC, NULL, 0, "Variable Device Header: Instance Number", HFILL}},
-      { &hf_var_devce_instance_block_size, { "Instance Block Size", "cipm.var_devce.header.instance_block_size", FT_UINT8, BASE_DEC, NULL, 0, "Variable Device Header: Instance Block Size", HFILL}},
-      { &hf_var_devce_cyclic_block_size, { "Cyclic Block Size", "cipm.var_devce.header.cyclic_block_size", FT_UINT8, BASE_DEC, NULL, 0, "Variable Device Header: Cyclic Block Size", HFILL}},
-      { &hf_var_devce_cyclic_data_block_size, { "Cyclic Data Block Size", "cipm.var_devce.header.cyclic_data_block_size", FT_UINT8, BASE_DEC, NULL, 0, "Variable Device Header: Cyclic Data Block Size", HFILL}},
-      { &hf_var_devce_cyclic_rw_block_size, { "Cyclic Read/Write Block Size", "cipm.var_devce.header.cyclic_rw_block_size", FT_UINT8, BASE_DEC, NULL, 0, "Variable Device Header: Cyclic Read/Write Block Size", HFILL}},
-      { &hf_var_devce_event_block_size, { "Event Block Size", "cipm.var_devce.header.event_block_size", FT_UINT8, BASE_DEC, NULL, 0, "Variable Device Header: Event Block Size", HFILL}},
-      { &hf_var_devce_service_block_size, { "Service Block Size", "cipm.var_devce.header.service_block_size", FT_UINT8, BASE_DEC, NULL, 0, "Variable Device Header: Service Block Size", HFILL}},
-
-      { &hf_cip_axis_alarm, { "Axis Alarm Code", "cipm.alarm.code", FT_UINT8, BASE_DEC, NULL, 0, "Status Data Set: Alarm Code", HFILL }},
-      { &hf_cip_axis_sts_local_ctrl, { "Local Control", "cipm.axis.local", FT_BOOLEAN, 32, TFS(&tfs_true_false), 0x00000001, "Axis Status Data Set: Local Contol", HFILL }},
-      { &hf_cip_axis_sts_alarm, { "Alarm", "cipm.axis.alarm", FT_BOOLEAN, 32, TFS(&tfs_true_false), 0x00000002, "Axis Status Data Set: Alarm", HFILL }},
-      { &hf_cip_axis_sts_dc_bus, { "DC Bus", "cipm.axis.bus", FT_BOOLEAN, 32, TFS(&tfs_true_false), 0x00000004, "Axis Status Data Set: DC Bus", HFILL }},
-      { &hf_cip_axis_sts_pwr_struct, { "Power Struct", "cipm.axis.pwr", FT_BOOLEAN, 32, TFS(&tfs_true_false), 0x00000008, "Axis Status Data Set: Power Struct", HFILL }},
-      { &hf_cip_axis_sts_tracking, { "Tracking", "cipm.axis.track", FT_BOOLEAN, 32, TFS(&tfs_true_false), 0x00000020, "Axis Status Data Set: Tracking", HFILL }},
-      { &hf_cip_axis_sts_pos_lock, { "Pos Lock", "cipm.axis.poslock", FT_BOOLEAN, 32, TFS(&tfs_true_false), 0x00000040, "Axis Status Data Set: Pos Lock", HFILL }},
-      { &hf_cip_axis_sts_vel_lock, { "Vel Lock", "cipm.axis.vellock", FT_BOOLEAN, 32, TFS(&tfs_true_false), 0x00000080, "Axis Status Data Set: Vel Lock", HFILL }},
-      { &hf_cip_axis_sts_vel_standstill, { "Standstill", "cipm.axis.nomo", FT_BOOLEAN, 32, TFS(&tfs_true_false), 0x00000100, "Axis Status Data Set: Standstill", HFILL }},
-      { &hf_cip_axis_sts_vel_threshold, { "Vel Threshold", "cipm.axis.vthresh", FT_BOOLEAN, 32, TFS(&tfs_true_false), 0x00000200, "Axis Status Data Set: Vel Threshold", HFILL }},
-      { &hf_cip_axis_sts_vel_limit, { "Vel Limit", "cipm.axis.vlim", FT_BOOLEAN, 32, TFS(&tfs_true_false), 0x00000400, "Axis Status Data Set: Vel Limit", HFILL }},
-      { &hf_cip_axis_sts_acc_limit, { "Acc Limit", "cipm.axis.alim", FT_BOOLEAN, 32, TFS(&tfs_true_false), 0x00000800, "Axis Status Data Set: Acc Limit", HFILL }},
-      { &hf_cip_axis_sts_dec_limit, { "Dec Limit", "cipm.axis.dlim", FT_BOOLEAN, 32, TFS(&tfs_true_false), 0x00001000, "Axis Status Data Set: Dec Limit", HFILL }},
-      { &hf_cip_axis_sts_torque_threshold, { "Torque Threshold", "cipm.axis.tthresh", FT_BOOLEAN, 32, TFS(&tfs_true_false), 0x00002000, "Axis Status Data Set: Torque Threshold", HFILL }},
-      { &hf_cip_axis_sts_torque_limit, { "Torque Limit", "cipm.axis.tlim", FT_BOOLEAN, 32, TFS(&tfs_true_false), 0x00004000, "Axis Status Data Set: Torque Limit", HFILL }},
-      { &hf_cip_axis_sts_cur_limit, { "Current Limit", "cipm.axis.ilim", FT_BOOLEAN, 32, TFS(&tfs_true_false), 0x00008000, "Axis Status Data Set: Current Limit", HFILL }},
-      { &hf_cip_axis_sts_therm_limit, { "Thermal Limit", "cipm.axis.hot", FT_BOOLEAN, 32, TFS(&tfs_true_false), 0x00010000, "Axis Status Data Set: Thermal Limit", HFILL }},
-      { &hf_cip_axis_sts_feedback_integ, { "Feedback Integrity", "cipm.axis.fgood", FT_BOOLEAN, 32, TFS(&tfs_true_false), 0x00020000, "Axis Status Data Set: Feedback Integrity", HFILL }},
-      { &hf_cip_axis_sts_shutdown, { "Shutdown", "cipm.axis.sdwn", FT_BOOLEAN, 32, TFS(&tfs_true_false), 0x00040000, "Axis Status Data Set: Shutdown", HFILL }},
-      { &hf_cip_axis_sts_in_process, { "In Process", "cipm.axis.inp", FT_BOOLEAN, 32, TFS(&tfs_true_false), 0x00080000, "Axis Status Data Set: In Process", HFILL }},
-
-      { &hf_cip_act_pos, { "Actual Position", "cipm.actpos", FT_INT32, BASE_DEC, NULL, 0, "Cyclic Data Set: Actual Position", HFILL }},
-      { &hf_cip_act_vel, { "Actual Velocity", "cipm.actvel", FT_FLOAT, BASE_NONE, NULL, 0, "Cyclic Data Set: Actual Velocity", HFILL }},
-      { &hf_cip_act_accel, { "Actual Acceleration", "cipm.actaccel", FT_FLOAT, BASE_NONE, NULL, 0, "Cyclic Data Set: Actual Acceleration", HFILL }},
-      { &hf_cip_act_trq, { "Actual Torque", "cipm.acttrq", FT_FLOAT, BASE_NONE, NULL, 0, "Cyclic Data Set: Actual Torque", HFILL }},
-      { &hf_cip_act_crnt, { "Actual Current", "cipm.actcrnt", FT_FLOAT, BASE_NONE, NULL, 0, "Cyclic Data Set: Actual Current", HFILL }},
-      { &hf_cip_act_volts, { "Actual Volts", "cipm.actvolts", FT_FLOAT, BASE_NONE, NULL, 0, "Cyclic Data Set: Actual Volts", HFILL }},
-      { &hf_cip_act_freq, { "Actual Frequency", "cipm.actfreq", FT_FLOAT, BASE_NONE, NULL, 0, "Cyclic Data Set: Actual Frequency", HFILL }},
-      { &hf_cip_pos_cmd,  { "Position Command", "cipm.posfcmd", FT_DOUBLE, BASE_NONE, NULL, 0, "Cyclic Data Set: Position Command (LREAL)", HFILL }},
-      { &hf_cip_pos_cmd_int, { "Position Command", "cipm.posicmd", FT_INT32, BASE_DEC, NULL, 0, "Cyclic Data Set: Position Command (DINT)", HFILL }},
-      { &hf_cip_vel_cmd, { "Velocity Command", "cipm.velcmd", FT_FLOAT, BASE_NONE, NULL, 0, "Cyclic Data Set: Velocity Command", HFILL }},
-      { &hf_cip_accel_cmd, { "Acceleration Command", "cipm.accelcmd", FT_FLOAT, BASE_NONE, NULL, 0, "Cyclic Data Set: Acceleration Command", HFILL }},
-      { &hf_cip_trq_cmd, { "Torque Command", "cipm.torquecmd", FT_FLOAT, BASE_NONE, NULL, 0, "Cyclic Data Set: Torque Command", HFILL }},
-      { &hf_cip_pos_trim, { "Position Trim", "cipm.postrim", FT_FLOAT, BASE_NONE, NULL, 0, "Cyclic Data Set: Position Trim", HFILL }},
-      { &hf_cip_vel_trim, { "Velocity Trim", "cipm.veltrim", FT_FLOAT, BASE_NONE, NULL, 0, "Cyclic Data Set: Velocity Trim", HFILL }},
-      { &hf_cip_accel_trim, { "Acceleration Trim", "cipm.acceltrim", FT_FLOAT, BASE_NONE, NULL, 0, "Cyclic Data Set: Acceleration Trim", HFILL }},
-      { &hf_cip_trq_trim, { "Torque Trim", "cipm.trqtrim", FT_FLOAT, BASE_NONE, NULL, 0, "Cyclic Data Set: Torque Trim", HFILL }}
+      { &hf_cip_revision,
+        { "Format Revision", "cipm.revision",
+          FT_UINT8, BASE_DEC, NULL, 0,
+          "Message format revision", HFILL }
+      },
+
+      { &hf_cip_class1_seqnum,
+        { "CIP Class 1 Sequence Count", "cipm.class1seqnum",
+          FT_UINT16, BASE_DEC, NULL, 0,
+          NULL, HFILL }
+      },
+      { &hf_cip_updateid,
+        { "Update Id", "cipm.updateid",
+          FT_UINT8, BASE_DEC, NULL, 0,
+          "Cyclic Transaction Number", HFILL }
+      },
+      { &hf_cip_instance_cnt,
+        { "Instance Count", "cipm.instancecount",
+          FT_UINT8, BASE_DEC, NULL, 0,
+          NULL, HFILL }
+      },
+      { &hf_cip_last_update,
+        { "Last Update Id", "cipm.lastupdate",
+          FT_UINT8, BASE_DEC, NULL, 0,
+          NULL, HFILL }
+      },
+      { &hf_cip_node_status,
+        { "Node Status", "cipm.nodestatus",
+          FT_UINT8, BASE_HEX, NULL, 0,
+          NULL, HFILL}
+      },
+      { &hf_cip_node_control,
+        { "Node Control", "cipm.nodecontrol",
+          FT_UINT8, BASE_HEX, NULL, 0,
+          NULL, HFILL}
+      },
+      { &hf_cip_node_control_remote,
+        { "Remote Control", "cipm.remote",
+          FT_BOOLEAN, 8, TFS(&tfs_true_false), 0x01,
+          "Node Control: Remote Control", HFILL}
+      },
+      { &hf_cip_node_control_sync,
+        { "Sync Control", "cipm.sync",
+          FT_BOOLEAN, 8, TFS(&tfs_true_false), 0x02,
+          "Node Control: Synchronous Operation", HFILL}
+      },
+      { &hf_cip_node_data_valid,
+        { "Data Valid", "cipm.valid",
+          FT_BOOLEAN, 8, TFS(&tfs_true_false), 0x04,
+          "Node Control: Data Valid", HFILL}
+      },
+      { &hf_cip_node_fault_reset,
+        { "Node Fault Reset", "cipm.fltrst",
+          FT_BOOLEAN, 8, TFS(&tfs_true_false), 0x08,
+          "Node Control: Node Fault Reset", HFILL}
+      },
+      { &hf_cip_node_device_faulted,
+        { "Faulted", "cipm.flt",
+          FT_BOOLEAN, 8, TFS(&tfs_true_false), 0x08,
+          "Node Control: Device Faulted", HFILL}
+      },
+      { &hf_cip_node_fltalarms,
+        { "Node Faults and Alarms", "cipm.fltalarms",
+          FT_UINT8, BASE_DEC, NULL, 0,
+          NULL, HFILL }
+      },
+      { &hf_cip_time_data_set,
+        { "Time Data Set", "cipm.timedataset",
+          FT_UINT8, BASE_HEX, NULL, 0,
+          NULL, HFILL}
+      },
+      { &hf_cip_time_data_stamp,
+        { "Time Stamp", "cipm.time.stamp",
+          FT_BOOLEAN, 8, TFS(&tfs_true_false), TIME_DATA_SET_TIME_STAMP,
+          "Time Data Set: Time Stamp", HFILL}
+      },
+      { &hf_cip_time_data_offset,
+        { "Time Offset", "cipm.time.offset",
+          FT_BOOLEAN, 8, TFS(&tfs_true_false), TIME_DATA_SET_TIME_OFFSET,
+          "Time Data Set: Time Offset", HFILL}
+      },
+      { &hf_cip_time_data_diag,
+        { "Update Diagnostics", "cipm.time.update",
+          FT_BOOLEAN, 8, TFS(&tfs_true_false), TIME_DATA_SET_UPDATE_DIAGNOSTICS,
+          "Time Data Set: Update Diagnostics", HFILL}
+      },
+      { &hf_cip_time_data_time_diag,
+        { "Time Diagnostics", "cipm.time.diag",
+          FT_BOOLEAN, 8, TFS(&tfs_true_false), TIME_DATA_SET_TIME_DIAGNOSTICS,
+          "Time Data Set: Time Diagnostics", HFILL}
+      },
+
+      { &hf_cip_cont_time_stamp,
+        { "Controller Time Stamp", "cipm.ctrltimestamp",
+          FT_UINT64, BASE_DEC, NULL, 0,
+          "Time Data Set: Controller Time Stamp", HFILL}
+      },
+      { &hf_cip_cont_time_offset,
+        { "Controller Time Offset", "cipm.ctrltimeoffser",
+          FT_UINT64, BASE_DEC, NULL, 0,
+          "Time Data Set: Controller Time Offset", HFILL}
+      },
+      { &hf_cip_data_rx_time_stamp,
+        { "Data Received Time Stamp", "cipm.rxtimestamp",
+          FT_UINT64, BASE_DEC, NULL, 0,
+          "Time Data Set: Data Received Time Stamp", HFILL}
+      },
+      { &hf_cip_data_tx_time_stamp,
+        { "Data Transmit Time Stamp", "cipm.txtimestamp",
+          FT_UINT64, BASE_DEC, NULL, 0,
+          "Time Data Set: Data Transmit Time Offset", HFILL}
+      },
+      { &hf_cip_devc_time_stamp,
+        { "Device Time Stamp", "cipm.devctimestamp",
+          FT_UINT64, BASE_DEC, NULL, 0,
+          "Time Data Set: Device Time Stamp", HFILL}
+      },
+      { &hf_cip_devc_time_offset,
+        { "Device Time Offset", "cipm.devctimeoffser",
+          FT_UINT64, BASE_DEC, NULL, 0,
+          "Time Data Set: Device Time Offset", HFILL}
+      },
+      { &hf_cip_lost_update,
+        { "Lost Updates", "cipm.lostupdates",
+          FT_UINT8, BASE_DEC, NULL, 0,
+          "Time Data Set: Lost Updates", HFILL}
+      },
+      { &hf_cip_late_update,
+        { "Lost Updates", "cipm.lateupdates",
+          FT_UINT8, BASE_DEC, NULL, 0,
+          "Time Data Set: Late Updates", HFILL}
+      },
+
+      { &hf_cip_motor_cntrl,
+        { "Control Mode", "cipm.ctrlmode",
+          FT_UINT8, BASE_DEC, VALS(cip_motor_control_vals), 0,
+          "Cyclic Data Block: Motor Control Mode", HFILL }
+      },
+      { &hf_cip_feedback_mode,
+        { "Feedback Mode", "cipm.feedback_mode",
+          FT_UINT8, BASE_DEC, VALS(cip_feedback_mode_vals), FEEDBACK_MODE_BITS,
+          "Cyclic Data Block: Feedback Mode", HFILL }
+      },
+      { &hf_cip_axis_control,
+        { "Axis Control", "cipm.axisctrl",
+          FT_UINT8, BASE_DEC, VALS(cip_axis_control_vals), 0,
+          "Cyclic Data Block: Axis Control", HFILL }
+      },
+      { &hf_cip_control_status,
+        { "Control Status", "cipm.csts",
+          FT_UINT8, BASE_DEC, NULL, 0,
+          "Cyclic Data Block: Axis Control Status", HFILL }
+      },
+      { &hf_cip_control_status_complete,
+        { "Configuration Complete", "cipm.control_status.complete",
+          FT_BOOLEAN, 8, TFS(&tfs_true_false), 0x01,
+          NULL, HFILL } },
+      { &hf_cip_control_status_bus_up,
+        { "Converter Bus Up", "cipm.control_status.bus_up",
+          FT_BOOLEAN, 8, TFS(&tfs_true_false), 0x04,
+          NULL, HFILL } },
+      { &hf_cip_control_status_bus_unload,
+        { "Converter Bus Unload", "cipm.control_status.bus_unload",
+          FT_BOOLEAN, 8, TFS(&tfs_true_false), 0x08,
+          NULL, HFILL } },
+      { &hf_cip_control_status_power_loss,
+        { "Converter AC Power Loss", "cipm.control_status.power_loss",
+          FT_BOOLEAN, 8, TFS(&tfs_true_false), 0x10,
+          NULL, HFILL } },
+      { &hf_cip_axis_response,
+        { "Axis Response", "cipm.axisresp",
+          FT_UINT8, BASE_DEC, VALS(cip_axis_response_vals), 0,
+          "Cyclic Data Block: Axis Response", HFILL }
+      },
+      { &hf_cip_axis_resp_stat,
+        { "Response Status", "cipm.respstat",
+          FT_UINT8, BASE_DEC|BASE_EXT_STRING, &cip_gs_vals_ext, 0,
+          "Cyclic Data Block: Axis Response Status", HFILL }
+      },
+      { &hf_cip_group_sync,
+        { "Group Sync Status", "cipm.syncstatus",
+          FT_UINT8, BASE_HEX, VALS(cip_sync_status_vals), 0,
+          NULL, HFILL }
+      },
+      { &hf_cip_cmd_data_set,
+        { "Command Data Set", "cipm.cmdset",
+          FT_UINT8, BASE_HEX, NULL, 0,
+          NULL, HFILL}
+      },
+      { &hf_cip_act_data_set,
+        { "Actual Data Set", "cipm.actset",
+          FT_UINT8, BASE_HEX, NULL, 0,
+          NULL, HFILL}
+      },
+      { &hf_cip_sts_data_set,
+        { "Status Data Set", "cipm.stsset",
+          FT_UINT8, BASE_HEX, NULL, 0,
+          NULL, HFILL}
+      },
+      { &hf_cip_cmd_data_pos_cmd,
+        { "Command Position", "cipm.cmd.pos",
+          FT_BOOLEAN, 8, TFS(&tfs_true_false), COMMAND_DATA_SET_POSITION,
+          "Command Data Set: Command Position", HFILL}
+      },
+      { &hf_cip_cmd_data_vel_cmd,
+        { "Command Velocity", "cipm.cmd.vel",
+          FT_BOOLEAN, 8, TFS(&tfs_true_false), COMMAND_DATA_SET_VELOCITY,
+          "Command Data Set: Command Velocity", HFILL}
+      },
+      { &hf_cip_cmd_data_acc_cmd,
+        { "Command Acceleration", "cipm.cmd.acc",
+          FT_BOOLEAN, 8, TFS(&tfs_true_false), COMMAND_DATA_SET_ACCELERATION,
+          "Command Data Set: Command Acceleration", HFILL}
+      },
+      { &hf_cip_cmd_data_trq_cmd,
+        { "Command Torque", "cipm.cmd.trq",
+          FT_BOOLEAN, 8, TFS(&tfs_true_false), COMMAND_DATA_SET_TORQUE,
+          "Command Data Set: Command Torque", HFILL}
+      },
+      { &hf_cip_act_data_pos,
+        { "Actual Position", "cipm.act.pos",
+          FT_BOOLEAN, 8, TFS(&tfs_true_false), ACTUAL_DATA_SET_POSITION,
+          "Actual Data Set: Actual Position", HFILL}
+      },
+      { &hf_cip_act_data_vel,
+        { "Actual Velocity", "cipm.act.vel",
+          FT_BOOLEAN, 8, TFS(&tfs_true_false), ACTUAL_DATA_SET_VELOCITY,
+          "Actual Data Set: Actual Velocity", HFILL}
+      },
+      { &hf_cip_act_data_acc,
+        { "Actual Acceleration", "cipm.act.acc",
+          FT_BOOLEAN, 8, TFS(&tfs_true_false), ACTUAL_DATA_SET_ACCELERATION,
+          "Actual Data Set: Actual Acceleration", HFILL}
+      },
+      { &hf_cip_axis_fault,
+        { "Axis Fault Code", "cipm.fault.code",
+          FT_UINT8, BASE_DEC, NULL, 0,
+          "Status Data Set: Fault Code", HFILL }
+      },
+      { &hf_cip_fault_type,
+        { "Axis Fault Type", "cipm.flttype",
+          FT_UINT8, BASE_DEC, NULL, 0,
+          "Axis Status: Axis Fault Type", HFILL}
+      },
+      { &hf_cip_fault_sub_code,
+        { "Axis Fault Sub Code", "cipm.fltsubcode",
+          FT_UINT8, BASE_DEC, NULL, 0,
+          "Axis Status: Axis Fault Sub Code", HFILL}
+      },
+      { &hf_cip_fault_action,
+        { "Axis Fault Action", "cipm.fltaction",
+          FT_UINT8, BASE_DEC, NULL, 0,
+          "Axis Status: Axis Fault Action", HFILL}
+      },
+      { &hf_cip_fault_time_stamp,
+        { "Axis Fault Time Stamp", "cipm.flttimestamp",
+          FT_UINT64, BASE_DEC, NULL, 0,
+          "Axis Status: Axis Fault Time Stamp", HFILL}
+      },
+      { &hf_cip_alarm_type,
+        { "Axis Fault Type", "cipm.alarmtype",
+          FT_UINT8, BASE_DEC, NULL, 0,
+          "Axis Status: Axis Alarm Type", HFILL}
+      },
+      { &hf_cip_alarm_sub_code,
+        { "Axis Alarm Sub Code", "cipm.alarmsubcode",
+          FT_UINT8, BASE_DEC, NULL, 0,
+          "Axis Status: Axis Alarm Sub Code", HFILL}
+      },
+      { &hf_cip_alarm_state,
+        { "Axis Alarm State", "cipm.alarmstate",
+          FT_UINT8, BASE_DEC, NULL, 0,
+          "Axis Status: Axis Alarm State", HFILL }
+      },
+      { &hf_cip_alarm_time_stamp,
+        { "Axis Fault Time Stamp", "cipm.alarmtimestamp",
+          FT_UINT64, BASE_DEC, NULL, 0,
+          "Axis Status: Axis Alarm Time Stamp", HFILL}
+      },
+      { &hf_cip_axis_status,
+        { "Axis Status", "cipm.axisstatus",
+          FT_UINT32, BASE_HEX, NULL, 0,
+          NULL, HFILL}
+      },
+      { &hf_cip_axis_status_mfg,
+        { "Axis Status Mfg", "cipm.axisstatusmfg",
+          FT_UINT32, BASE_HEX, NULL, 0,
+          "Axis Status, Manufacturer Specific", HFILL}
+      },
+      { &hf_cip_axis_io_status,
+        { "Axis I/O Status", "cipm.axisiostatus",
+          FT_UINT32, BASE_HEX, NULL, 0,
+          NULL, HFILL}
+      },
+      { &hf_cip_axis_io_status_mfg,
+        { "Axis I/O Status Mfg", "cipm.axisiostatusmfg",
+          FT_UINT32, BASE_HEX, NULL, 0,
+          "Axis I/O Status, Manufacturer Specific", HFILL}
+      },
+      { &hf_cip_axis_safety_status,
+        { "Axis Safety Status", "cipm.safetystatus",
+          FT_UINT32, BASE_HEX, NULL, 0,
+          NULL, HFILL}
+      },
+      { &hf_cip_axis_safety_status_mfg,
+        { "Axis Safety Status Mfg", "cipm.safetystatusmfg",
+          FT_UINT32, BASE_HEX, NULL, 0,
+          "Axis Safety Status, Manufacturer Specific", HFILL}
+      },
+      { &hf_cip_axis_safety_state,
+        { "Axis Safety State", "cipm.safetystate",
+          FT_UINT8, BASE_HEX, NULL, 0,
+          "Axis Safety Sate", HFILL}
+      },
+      { &hf_cip_sts_flt,
+        { "Axis Fault Codes", "cipm.sts.flt",
+          FT_BOOLEAN, 8, TFS(&tfs_true_false), STATUS_DATA_SET_AXIS_FAULT,
+          "Status Data Set: Axis Fault Codes", HFILL}
+      },
+      { &hf_cip_sts_alrm,
+        { "Axis Alarm Codes", "cipm.sts.alarm",
+          FT_BOOLEAN, 8, TFS(&tfs_true_false), STATUS_DATA_SET_AXIS_ALARM,
+          "Status Data Set: Axis Alarm Codes", HFILL}
+      },
+      { &hf_cip_sts_sts,
+        { "Axis Status", "cipm.sts.sts",
+          FT_BOOLEAN, 8, TFS(&tfs_true_false), STATUS_DATA_SET_AXIS_STATUS,
+          "Status Data Set: Axis Status", HFILL}
+      },
+      { &hf_cip_sts_iosts,
+        { "Axis I/O Status", "cipm.sts.iosts",
+          FT_BOOLEAN, 8, TFS(&tfs_true_false), STATUS_DATA_SET_AXIS_IO_STATUS,
+          "Status Data Set: Axis I/O Status", HFILL}
+      },
+      { &hf_cip_sts_axis_safety,
+        { "Axis Safety Status", "cipm.sts.safety",
+          FT_BOOLEAN, 8, TFS(&tfs_true_false), STATUS_DATA_SET_AXIS_SAFETY,
+          "Status Data Set: Axis Safety Status", HFILL}
+      },
+      { &hf_cip_intrp,
+        { "Command Target Update", "cipm.intrp",
+          FT_UINT8, BASE_DEC, VALS(cip_interpolation_vals), COMMAND_CONTROL_TARGET_UPDATE,
+          "Cyclic Data Block: Command Target Update", HFILL}
+      },
+      { &hf_cip_position_data_type,
+        { "Command Position Data Type", "cipm.posdatatype",
+          FT_UINT8, BASE_DEC, VALS(cip_pos_data_type_vals), COMMAND_CONTROL_POSITION_DATA_TYPE,
+          "Cyclic Data Block: Command Position Data Type", HFILL }
+      },
+      { &hf_cip_axis_state,
+        { "Axis State", "cipm.axste",
+          FT_UINT8, BASE_DEC, VALS(cip_axis_state_vals), 0,
+          "Cyclic Data Block: Axis State", HFILL}
+      },
+      { &hf_cip_command_control,
+        { "Command Control", "cipm.cmdcontrol",
+          FT_UINT8, BASE_DEC, NULL, 0,
+          "Cyclic Data Block: Command Control", HFILL }
+      },
+      { &hf_cip_cyclic_wrt_data,
+        { "Write Data", "cipm.writedata",
+          FT_BYTES, BASE_NONE, NULL, 0,
+          "Cyclic Write: Data", HFILL }
+      },
+      { &hf_cip_cyclic_rd_data,
+        { "Read Data", "cipm.readdata",
+          FT_BYTES, BASE_NONE, NULL, 0,
+          "Cyclic Read: Data", HFILL }
+      },
+      { &hf_cip_cyclic_write_blk,
+        { "Write Block", "cipm.writeblk",
+          FT_UINT8, BASE_DEC, NULL, 0,
+          "Cyclic Data Block: Write Block Id", HFILL }
+      },
+      { &hf_cip_cyclic_read_blk,
+        { "Read Block", "cipm.readblk",
+          FT_UINT8, BASE_DEC, NULL, 0,
+          "Cyclic Data Block: Read Block Id", HFILL}
+      },
+      { &hf_cip_cyclic_write_sts,
+        { "Write Status", "cipm.writests",
+          FT_UINT8, BASE_DEC, NULL, 0,
+          "Cyclic Data Block: Write Status", HFILL }
+      },
+      { &hf_cip_cyclic_read_sts,
+        { "Read Status", "cipm.readsts",
+          FT_UINT8, BASE_DEC, NULL, 0,
+          "Cyclic Data Block: Read Status", HFILL }
+      },
+      { &hf_cip_event_checking,
+        { "Event Checking Control", "cipm.evntchkcontrol",
+          FT_UINT32, BASE_HEX, NULL, 0,
+          "Event Channel: Event Checking Control", HFILL}
+      },
+      { &hf_cip_event_ack,
+        { "Event Acknowledgement", "cipm.evntack",
+          FT_UINT8, BASE_DEC, NULL, 0,
+          "Event Channel: Event Acknowledgement", HFILL}
+      },
+      { &hf_cip_event_status,
+        { "Event Checking Status", "cipm.evntchkstatus",
+          FT_UINT32, BASE_HEX, NULL, 0,
+          "Event Channel: Event Checking Status", HFILL}
+      },
+      { &hf_cip_event_id,
+        { "Event Id", "cipm.evntack",
+          FT_UINT8, BASE_DEC, NULL, 0,
+          "Event Channel: Event Id", HFILL }
+      },
+      { &hf_cip_event_pos,
+        { "Event Position", "cipm.evntpos",
+          FT_INT32, BASE_DEC, NULL, 0,
+          "Event Channel: Event Position", HFILL}
+      },
+      { &hf_cip_event_ts,
+        { "Event Time Stamp", "cipm.evntimestamp",
+          FT_UINT64, BASE_DEC, NULL, 0,
+          "Event Channel: Time Stamp", HFILL}
+      },
+
+      { &hf_cip_evnt_ctrl_reg1_pos,
+        { "Reg 1 Pos Edge", "cipm.evnt.ctrl.reg1posedge",
+          FT_BOOLEAN, 32, TFS(&tfs_true_false), 0x00000001,
+          "Event Checking Control: Reg 1 Pos Edge", HFILL}
+      },
+      { &hf_cip_evnt_ctrl_reg1_neg,
+        { "Reg 1 Neg Edge", "cipm.evnt.ctrl.reg1negedge",
+          FT_BOOLEAN, 32, TFS(&tfs_true_false), 0x00000002,
+          "Event Checking Control: Reg 1 Neg Edge", HFILL}
+      },
+      { &hf_cip_evnt_ctrl_reg2_pos,
+        { "Reg 2 Pos Edge", "cipm.evnt.ctrl.reg2posedge",
+          FT_BOOLEAN, 32, TFS(&tfs_true_false), 0x00000004,
+          "Event Checking Control: Reg 2 Pos Edge", HFILL}
+      },
+      { &hf_cip_evnt_ctrl_reg2_neg,
+        { "Reg 2 Neg Edge", "cipm.evnt.ctrl.reg2negedge",
+          FT_BOOLEAN, 32, TFS(&tfs_true_false), 0x00000008,
+          "Event Checking Control: Reg 2 Neg Edge", HFILL}
+      },
+      { &hf_cip_evnt_ctrl_reg1_posrearm,
+        { "Reg 1 Pos Rearm", "cipm.evnt.ctrl.reg1posrearm",
+          FT_BOOLEAN, 32, TFS(&tfs_true_false), 0x00000100,
+          "Event Checking Control: Reg 1 Pos Rearm", HFILL}
+      },
+      { &hf_cip_evnt_ctrl_reg1_negrearm,
+        { "Reg 1 Neg Rearm", "cipm.evnt.ctrl.reg1negrearm",
+          FT_BOOLEAN, 32, TFS(&tfs_true_false), 0x00000200,
+          "Event Checking Control: Reg 1 Neg Rearm", HFILL}
+      },
+      { &hf_cip_evnt_ctrl_reg2_posrearm,
+        { "Reg 2 Pos Rearm", "cipm.evnt.ctrl.reg2posrearm",
+          FT_BOOLEAN, 32, TFS(&tfs_true_false), 0x00000400,
+          "Event Checking Control: Reg 2 Pos Rearm", HFILL}
+      },
+      { &hf_cip_evnt_ctrl_reg2_negrearm,
+        { "Reg 2 Neg Rearm", "cipm.evnt.ctrl.reg2negrearm",
+          FT_BOOLEAN, 32, TFS(&tfs_true_false), 0x00000800,
+          "Event Checking Control: Reg 2 Neg Rearm", HFILL}
+      },
+      { &hf_cip_evnt_ctrl_marker_pos,
+        { "Marker Pos Edge", "cipm.evnt.ctrl.mrkrpos",
+          FT_BOOLEAN, 32, TFS(&tfs_true_false), 0x00010000,
+          "Event Checking Control: Marker Pos Edge", HFILL}
+      },
+      { &hf_cip_evnt_ctrl_marker_neg,
+        { "Marker Neg Edge", "cipm.evnt.ctrl.mrkrneg",
+          FT_BOOLEAN, 32, TFS(&tfs_true_false), 0x00020000,
+          "Event Checking Control: Marker Neg Edge", HFILL}
+      },
+      { &hf_cip_evnt_ctrl_home_pos,
+        { "Home Pos Edge", "cipm.evnt.ctrl.homepos",
+          FT_BOOLEAN, 32, TFS(&tfs_true_false), 0x00040000,
+          "Event Checking Control: Home Pos Edge", HFILL}
+      },
+      { &hf_cip_evnt_ctrl_home_neg,
+        { "Home Neg Edge", "cipm.evnt.ctrl.homeneg",
+          FT_BOOLEAN, 32, TFS(&tfs_true_false), 0x00080000,
+          "Event Checking Control: Home Neg Edge", HFILL}
+      },
+      { &hf_cip_evnt_ctrl_home_pp,
+        { "Home-Switch-Marker Plus Plus", "cipm.evnt.ctrl.homepp",
+          FT_BOOLEAN, 32, TFS(&tfs_true_false), 0x00100000,
+          "Event Checking Control: Home-Switch-Marker Plus Plus", HFILL}
+      },
+      { &hf_cip_evnt_ctrl_home_pm,
+        { "Home-Switch-Marker Plus Minus", "cipm.evnt.ctrl.homepm",
+          FT_BOOLEAN, 32, TFS(&tfs_true_false), 0x00200000,
+          "Event Checking Control: Home-Switch-Marker Plus Minus", HFILL}
+      },
+      { &hf_cip_evnt_ctrl_home_mp,
+        { "Home-Switch-Marker Minus Plus", "cipm.evnt.ctrl.homemp",
+          FT_BOOLEAN, 32, TFS(&tfs_true_false), 0x00400000,
+          "Event Checking Control: Home-Switch-Marker Minus Plus", HFILL}
+      },
+      { &hf_cip_evnt_ctrl_home_mm,
+        { "Home-Switch-Marker Minus Minus", "cipm.evnt.ctrl.homemm",
+          FT_BOOLEAN, 32, TFS(&tfs_true_false), 0x00800000,
+          "Event Checking Control: Home-Switch-Marker Minus Minus", HFILL}
+      },
+      { &hf_cip_evnt_ctrl_acks,
+        { "Event Block Count", "cipm.evnt.ctrl.acks",
+          FT_UINT32, BASE_DEC, NULL, 0x70000000,
+          "Event Checking Control: Event Block Count", HFILL}
+      },
+      { &hf_cip_evnt_extend_format,
+        { "Extended Event Format", "cipm.evnt.extend",
+          FT_BOOLEAN, 32, TFS(&tfs_true_false), 0x80000000,
+          "Event Checking Control: Extended Event Format", HFILL}
+      },
+
+      { &hf_cip_evnt_sts_reg1_pos,
+        { "Reg 1 Pos Edge", "cipm.evnt.sts.reg1posedge",
+          FT_BOOLEAN, 32, TFS(&tfs_true_false), 0x00000001,
+          "Event Checking Status: Reg 1 Pos Edge", HFILL}
+      },
+      { &hf_cip_evnt_sts_reg1_neg,
+        { "Reg 1 Neg Edge", "cipm.evnt.sts.reg1negedge",
+          FT_BOOLEAN, 32, TFS(&tfs_true_false), 0x00000002,
+          "Event Checking Status: Reg 1 Neg Edge", HFILL }
+      },
+      { &hf_cip_evnt_sts_reg2_pos,
+        { "Reg 2 Pos Edge", "cipm.evnt.sts.reg2posedge",
+          FT_BOOLEAN, 32, TFS(&tfs_true_false), 0x00000004,
+          "Event Checking Status: Reg 2 Pos Edge", HFILL}
+      },
+      { &hf_cip_evnt_sts_reg2_neg,
+        { "Reg 2 Neg Edge", "cipm.evnt.sts.reg2negedge",
+          FT_BOOLEAN, 32, TFS(&tfs_true_false), 0x00000008,
+          "Event Checking Status: Reg 2 Neg Edge", HFILL}
+      },
+      { &hf_cip_evnt_sts_reg1_posrearm,
+        { "Reg 1 Pos Rearm", "cipm.evnt.sts.reg1posrearm",
+          FT_BOOLEAN, 32, TFS(&tfs_true_false), 0x00000100,
+          "Event Checking Status: Reg 1 Pos Rearm", HFILL}
+      },
+      { &hf_cip_evnt_sts_reg1_negrearm,
+        { "Reg 1 Neg Rearm", "cipm.evnt.sts.reg1negrearm",
+          FT_BOOLEAN, 32, TFS(&tfs_true_false), 0x00000200,
+          "Event Checking Status: Reg 1 Neg Rearm", HFILL}
+      },
+      { &hf_cip_evnt_sts_reg2_posrearm,
+        { "Reg 2 Pos Rearm", "cipm.evnt.sts.reg2posrearm",
+          FT_BOOLEAN, 32, TFS(&tfs_true_false), 0x00000400,
+          "Event Checking Status: Reg 2 Pos Rearm", HFILL}
+      },
+      { &hf_cip_evnt_sts_reg2_negrearm,
+        { "Reg 2 Neg Rearm", "cipm.evnt.sts.reg2negrearm",
+          FT_BOOLEAN, 32, TFS(&tfs_true_false), 0x00000800,
+          "Event Checking Status: Reg 2 Neg Rearm", HFILL}
+      },
+      { &hf_cip_evnt_sts_marker_pos,
+        { "Marker Pos Edge", "cipm.evnt.sts.mrkrpos",
+          FT_BOOLEAN, 32, TFS(&tfs_true_false), 0x00010000,
+          "Event Checking Status: Marker Pos Edge", HFILL}
+      },
+      { &hf_cip_evnt_sts_marker_neg,
+        { "Marker Neg Edge", "cipm.evnt.sts.mrkrneg",
+          FT_BOOLEAN, 32, TFS(&tfs_true_false), 0x00020000,
+          "Event Checking Status: Marker Neg Edge", HFILL }
+      },
+      { &hf_cip_evnt_sts_home_pos,
+        { "Home Pos Edge", "cipm.evnt.sts.homepos",
+          FT_BOOLEAN, 32, TFS(&tfs_true_false), 0x00040000,
+          "Event Checking Status: Home Pos Edge", HFILL}
+      },
+      { &hf_cip_evnt_sts_home_neg,
+        { "Home Neg Edge", "cipm.evnt.sts.homeneg",
+          FT_BOOLEAN, 32, TFS(&tfs_true_false), 0x00080000,
+          "Event Checking Status: Home Neg Edge", HFILL }
+      },
+      { &hf_cip_evnt_sts_home_pp,
+        { "Home-Switch-Marker Plus Plus", "cipm.evnt.sts.homepp",
+          FT_BOOLEAN, 32, TFS(&tfs_true_false), 0x00100000,
+          "Event Checking Status: Home-Switch-Marker Plus Plus", HFILL}
+      },
+      { &hf_cip_evnt_sts_home_pm,
+        { "Home-Switch-Marker Plus Minus", "cipm.evnt.sts.homepm",
+          FT_BOOLEAN, 32, TFS(&tfs_true_false), 0x00200000,
+          "Event Checking Status: Home-Switch-Marker Plus Minus", HFILL}
+      },
+      { &hf_cip_evnt_sts_home_mp,
+        { "Home-Switch-Marker Minus Plus", "cipm.evnt.sts.homemp",
+          FT_BOOLEAN, 32, TFS(&tfs_true_false), 0x00400000,
+          "Event Checking Status: Home-Switch-Marker Minus Plus", HFILL}
+      },
+      { &hf_cip_evnt_sts_home_mm,
+        { "Home-Switch-Marker Minus Minus", "cipm.evnt.sts.homemm",
+          FT_BOOLEAN, 32, TFS(&tfs_true_false), 0x00800000,
+          "Event Checking Status: Home-Switch-Marker Minus Minus", HFILL}
+      },
+      { &hf_cip_evnt_sts_nfs,
+        { "Event Block Count", "cipm.evnt.sts.nfs",
+          FT_UINT32, BASE_DEC, NULL, 0x70000000,
+          "Event Checking Status: Event Block Count", HFILL}
+      },
+
+      { &hf_cip_evnt_sts_stat,
+        { "Event Status", "cipm.evnt.stat",
+          FT_UINT8, BASE_DEC|BASE_EXT_STRING, &cip_gs_vals_ext, 0,
+          "Event Data Block: Event Status", HFILL }
+      },
+      { &hf_cip_evnt_type,
+        { "Event Type", "cipm.evnt.type",
+          FT_UINT8, BASE_DEC, VALS(cip_event_type_vals), 0,
+          "Event Data Block: Event Type", HFILL}
+      },
+      { &hf_cip_svc_code,
+        { "Service Code", "cipm.svc.code",
+          FT_UINT8, BASE_HEX, VALS(cip_sc_vals), 0,
+          "Service Data Block: Service Code", HFILL}
+      },
+      { &hf_cip_svc_sts,
+        { "General Status", "cipm.svc.sts",
+          FT_UINT8, BASE_DEC|BASE_EXT_STRING, &cip_gs_vals_ext, 0,
+          "Service Data Block: General Status", HFILL }
+      },
+      { &hf_cip_svc_transction,
+        { "Transaction Id", "cipm.svc.tranid",
+          FT_UINT8, BASE_DEC, NULL, 0,
+          "Service Data Block: Transaction Id", HFILL }
+      },
+      { &hf_cip_svc_ext_status,
+        { "Extended Status", "cipm.svc.extstatus",
+          FT_UINT8, BASE_DEC, NULL, 0,
+          "Service Data Block: Extended Status", HFILL }
+      },
+      { &hf_cip_svc_data,
+        { "Service Data", "cipm.svc.data",
+          FT_BYTES, BASE_NONE, NULL, 0,
+          "Service Data Block: Data", HFILL }
+      },
+      { &hf_cip_attribute_data,
+        { "Attribute Data", "cipm.attrdata",
+          FT_BYTES, BASE_NONE, NULL, 0,
+          "Attribute Service: Data", HFILL }
+      },
+      { &hf_cip_ptp_grandmaster,
+        { "Grandmaster", "cipm.grandmaster",
+          FT_UINT64, BASE_HEX, NULL, 0,
+          "Group Sync: Grandmaster Id", HFILL}
+      },
+
+      { &hf_cip_svc_get_axis_attr_sts,
+        { "Attribute Status", "cipm.getaxisattr.sts",
+          FT_UINT8, BASE_DEC|BASE_EXT_STRING, &cip_gs_vals_ext, 0,
+          "Service Channel: Get Axis Attribute List Response Status", HFILL }
+      },
+      { &hf_get_axis_attr_list_attribute_cnt,
+        { "Number of attributes", "cipm.getaxisattr.cnt",
+          FT_UINT16, BASE_DEC, NULL, 0,
+          "Service Channel: Get Axis Attribute List Attribute Count", HFILL}
+      },
+      { &hf_get_axis_attr_list_attribute_id,
+        { "Attribute ID", "cipm.getaxisattr.id",
+          FT_UINT16, BASE_DEC, NULL, 0,
+          "Service Channel: Get Axis Attribute List Attribute ID", HFILL}
+      },
+      { &hf_get_axis_attr_list_dimension,
+        { "Dimension", "cipm.getaxisattr.dimension",
+          FT_UINT8, BASE_DEC, NULL, 0,
+          "Service Channel: Get Axis Attribute List Dimension", HFILL}
+      },
+      { &hf_get_axis_attr_list_element_size,
+        { "Element size", "cipm.getaxisattr.element_size",
+          FT_UINT8, BASE_DEC, NULL, 0,
+          "Service Channel: Get Axis Attribute List Element Size", HFILL}
+      },
+      { &hf_get_axis_attr_list_start_index,
+        { "Start index", "cipm.getaxisattr.start_index",
+          FT_UINT16, BASE_DEC, NULL, 0,
+          "Service Channel: Get Axis Attribute List Start index", HFILL}
+      },
+      { &hf_get_axis_attr_list_data_elements,
+        { "Data elements", "cipm.getaxisattr.data_elements",
+          FT_UINT16, BASE_DEC, NULL, 0,
+          "Service Channel: Get Axis Attribute List Data elements", HFILL}
+      },
+
+      { &hf_cip_svc_set_axis_attr_sts,
+        { "Attribute Status", "cipm.setaxisattr.sts",
+          FT_UINT8, BASE_DEC|BASE_EXT_STRING, &cip_gs_vals_ext, 0,
+          "Service Channel: Set Axis Attribute List Response Status", HFILL }
+      },
+      { &hf_set_axis_attr_list_attribute_cnt,
+        { "Number of attributes", "cipm.setaxisattr.cnt",
+          FT_UINT16, BASE_DEC, NULL, 0,
+          "Service Channel: Set Axis Attribute List Attribute Count", HFILL}
+      },
+      { &hf_set_axis_attr_list_attribute_id,
+        { "Attribute ID", "cipm.setaxisattr.id",
+          FT_UINT16, BASE_DEC, NULL, 0,
+          "Service Channel: Set Axis Attribute List Attribute ID", HFILL}
+      },
+      { &hf_set_axis_attr_list_dimension,
+        { "Dimension", "cipm.setaxisattr.dimension",
+          FT_UINT8, BASE_DEC, NULL, 0,
+          "Service Channel: Set Axis Attribute List Dimension", HFILL}
+      },
+      { &hf_set_axis_attr_list_element_size,
+        { "Element size", "cipm.setaxisattr.element_size",
+          FT_UINT8, BASE_DEC, NULL, 0,
+          "Service Channel: Set Axis Attribute List Element Size", HFILL}
+      },
+      { &hf_set_axis_attr_list_start_index,
+        { "Start index", "cipm.setaxisattr.start_index",
+          FT_UINT16, BASE_DEC, NULL, 0,
+          "Service Channel: Set Axis Attribute List Start index", HFILL}
+      },
+      { &hf_set_axis_attr_list_data_elements,
+        { "Data elements", "cipm.setaxisattr.data_elements",
+          FT_UINT16, BASE_DEC, NULL, 0,
+          "Service Channel: Set Axis Attribute List Data elements", HFILL}
+      },
+
+      { &hf_var_devce_instance,
+        { "Instance Number", "cipm.var_devce.header.instance",
+          FT_UINT8, BASE_DEC, NULL, 0,
+          "Variable Device Header: Instance Number", HFILL}
+      },
+      { &hf_var_devce_instance_block_size,
+        { "Instance Block Size", "cipm.var_devce.header.instance_block_size",
+          FT_UINT8, BASE_DEC|BASE_UNIT_STRING, &units_word_words, 0,
+          "Variable Device Header: Instance Block Size", HFILL}
+      },
+      { &hf_var_devce_cyclic_block_size,
+        { "Cyclic Block Size", "cipm.var_devce.header.cyclic_block_size",
+          FT_UINT8, BASE_DEC|BASE_UNIT_STRING, &units_word_words, 0,
+          "Variable Device Header: Cyclic Block Size", HFILL}
+      },
+      { &hf_var_devce_cyclic_data_block_size,
+        { "Cyclic Data Block Size", "cipm.var_devce.header.cyclic_data_block_size",
+          FT_UINT8, BASE_DEC|BASE_UNIT_STRING, &units_word_words, 0,
+          "Variable Device Header: Cyclic Data Block Size", HFILL}
+      },
+      { &hf_var_devce_cyclic_rw_block_size,
+        { "Cyclic Read/Write Block Size", "cipm.var_devce.header.cyclic_rw_block_size",
+          FT_UINT8, BASE_DEC|BASE_UNIT_STRING, &units_word_words, 0,
+          "Variable Device Header: Cyclic Read/Write Block Size", HFILL}
+      },
+      { &hf_var_devce_event_block_size,
+        { "Event Block Size", "cipm.var_devce.header.event_block_size",
+          FT_UINT8, BASE_DEC|BASE_UNIT_STRING, &units_word_words, 0,
+          "Variable Device Header: Event Block Size", HFILL}
+      },
+      { &hf_var_devce_service_block_size,
+        { "Service Block Size", "cipm.var_devce.header.service_block_size",
+          FT_UINT8, BASE_DEC|BASE_UNIT_STRING, &units_word_words, 0,
+          "Variable Device Header: Service Block Size", HFILL}
+      },
+
+      { &hf_cip_axis_alarm,
+        { "Axis Alarm Code", "cipm.alarm.code",
+          FT_UINT8, BASE_DEC, NULL, 0,
+          "Status Data Set: Alarm Code", HFILL }
+      },
+      { &hf_cip_axis_sts_local_ctrl,
+        { "Local Control", "cipm.axis.local",
+          FT_BOOLEAN, 32, TFS(&tfs_true_false), 0x00000001,
+          "Axis Status Data Set: Local Control", HFILL }
+      },
+      { &hf_cip_axis_sts_alarm,
+        { "Alarm", "cipm.axis.alarm",
+          FT_BOOLEAN, 32, TFS(&tfs_true_false), 0x00000002,
+          "Axis Status Data Set: Alarm", HFILL }
+      },
+      { &hf_cip_axis_sts_dc_bus,
+        { "DC Bus", "cipm.axis.bus",
+          FT_BOOLEAN, 32, TFS(&tfs_true_false), 0x00000004,
+          "Axis Status Data Set: DC Bus", HFILL }
+      },
+      { &hf_cip_axis_sts_pwr_struct,
+        { "Power Struct", "cipm.axis.pwr",
+          FT_BOOLEAN, 32, TFS(&tfs_true_false), 0x00000008,
+          "Axis Status Data Set: Power Struct", HFILL }
+      },
+      { &hf_cip_axis_sts_flux_up,
+        { "Motor Flux Up", "cipm.axis.flx",
+          FT_BOOLEAN, 32, TFS(&tfs_true_false), 0x00000010,
+          "Axis Status Data Set: Motor Flux Up", HFILL }
+      },
+      { &hf_cip_axis_sts_tracking,
+        { "Tracking", "cipm.axis.track",
+          FT_BOOLEAN, 32, TFS(&tfs_true_false), 0x00000020,
+          "Axis Status Data Set: Tracking", HFILL }
+      },
+      { &hf_cip_axis_sts_pos_lock,
+        { "Pos Lock", "cipm.axis.poslock",
+          FT_BOOLEAN, 32, TFS(&tfs_true_false), 0x00000040,
+          "Axis Status Data Set: Pos Lock", HFILL }
+      },
+      { &hf_cip_axis_sts_vel_lock,
+        { "Vel Lock", "cipm.axis.vellock",
+          FT_BOOLEAN, 32, TFS(&tfs_true_false), 0x00000080,
+          "Axis Status Data Set: Vel Lock", HFILL }
+      },
+      { &hf_cip_axis_sts_vel_standstill,
+        { "Vel Standstill", "cipm.axis.nomo",
+          FT_BOOLEAN, 32, TFS(&tfs_true_false), 0x00000100,
+          "Axis Status Data Set: Vel Standstill", HFILL }
+      },
+      { &hf_cip_axis_sts_vel_threshold,
+        { "Vel Threshold", "cipm.axis.vthresh",
+          FT_BOOLEAN, 32, TFS(&tfs_true_false), 0x00000200,
+          "Axis Status Data Set: Vel Threshold", HFILL }
+      },
+      { &hf_cip_axis_sts_vel_limit,
+        { "Vel Limit", "cipm.axis.vlim",
+          FT_BOOLEAN, 32, TFS(&tfs_true_false), 0x00000400,
+          "Axis Status Data Set: Vel Limit", HFILL }
+      },
+      { &hf_cip_axis_sts_acc_limit,
+        { "Acc Limit", "cipm.axis.alim",
+          FT_BOOLEAN, 32, TFS(&tfs_true_false), 0x00000800,
+          "Axis Status Data Set: Acc Limit", HFILL }
+      },
+      { &hf_cip_axis_sts_dec_limit,
+        { "Decel Limit", "cipm.axis.dlim",
+          FT_BOOLEAN, 32, TFS(&tfs_true_false), 0x00001000,
+          "Axis Status Data Set: Decel Limit", HFILL }
+      },
+      { &hf_cip_axis_sts_torque_threshold,
+        { "Torque Threshold", "cipm.axis.tthresh",
+          FT_BOOLEAN, 32, TFS(&tfs_true_false), 0x00002000,
+          "Axis Status Data Set: Torque Threshold", HFILL }
+      },
+      { &hf_cip_axis_sts_torque_limit,
+        { "Torque Limit", "cipm.axis.tlim",
+          FT_BOOLEAN, 32, TFS(&tfs_true_false), 0x00004000,
+          "Axis Status Data Set: Torque Limit", HFILL }
+      },
+      { &hf_cip_axis_sts_cur_limit,
+        { "Current Limit", "cipm.axis.ilim",
+          FT_BOOLEAN, 32, TFS(&tfs_true_false), 0x00008000,
+          "Axis Status Data Set: Current Limit", HFILL }
+      },
+      { &hf_cip_axis_sts_therm_limit,
+        { "Thermal Limit", "cipm.axis.hot",
+          FT_BOOLEAN, 32, TFS(&tfs_true_false), 0x00010000,
+          "Axis Status Data Set: Thermal Limit", HFILL }
+      },
+      { &hf_cip_axis_sts_feedback_integ,
+        { "Feedback Integrity", "cipm.axis.fgood",
+          FT_BOOLEAN, 32, TFS(&tfs_true_false), 0x00020000,
+          "Axis Status Data Set: Feedback Integrity", HFILL }
+      },
+      { &hf_cip_axis_sts_shutdown,
+        { "Shutdown", "cipm.axis.sdwn",
+          FT_BOOLEAN, 32, TFS(&tfs_true_false), 0x00040000,
+          "Axis Status Data Set: Shutdown", HFILL }
+      },
+      { &hf_cip_axis_sts_in_process,
+        { "In Process", "cipm.axis.inp",
+          FT_BOOLEAN, 32, TFS(&tfs_true_false), 0x00080000,
+          "Axis Status Data Set: In Process", HFILL }
+      },
+      { &hf_cip_axis_sts_dc_bus_unload,
+        { "DC Bus Unload", "cipm.axis.dcunload",
+          FT_BOOLEAN, 32, TFS(&tfs_true_false), 0x00100000,
+          "Axis Status Data Set: DC Bus Unload", HFILL }
+      },
+      { &hf_cip_axis_sts_ac_pwr_loss,
+        { "AC Power Loss", "cipm.axis.acpwrloss",
+          FT_BOOLEAN, 32, TFS(&tfs_true_false), 0x00200000,
+          "Axis Status Data Set: AC Power Loss", HFILL }
+      },
+      { &hf_cip_axis_sts_pos_cntrl_mode,
+        { "Pos Control Mode", "cipm.axis.poscntrl",
+          FT_BOOLEAN, 32, TFS(&tfs_true_false), 0x00400000,
+          "Axis Status Data Set: Position Control Mode", HFILL }
+      },
+      { &hf_cip_axis_sts_vel_cntrl_mode,
+        { "Vel Control Mode", "cipm.axis.velcntrl",
+          FT_BOOLEAN, 32, TFS(&tfs_true_false), 0x00800000,
+          "Axis Status Data Set: Velocity Control Mode", HFILL }
+      },
+      { &hf_cip_axis_sts_trq_cntrl_mode,
+        { "Torque Control Mode", "cipm.axis.trqcntrl",
+          FT_BOOLEAN, 32, TFS(&tfs_true_false), 0x01000000,
+          "Axis Status Data Set: Torque Control Mode", HFILL }
+      },
+      { &hf_cip_act_pos,
+        { "Actual Position", "cipm.actpos",
+          FT_INT32, BASE_DEC, NULL, 0,
+          "Cyclic Data Set: Actual Position", HFILL }
+      },
+      { &hf_cip_act_vel,
+        { "Actual Velocity", "cipm.actvel",
+          FT_FLOAT, BASE_NONE, NULL, 0,
+          "Cyclic Data Set: Actual Velocity", HFILL }
+      },
+      { &hf_cip_act_accel,
+        { "Actual Acceleration", "cipm.actaccel",
+          FT_FLOAT, BASE_NONE, NULL, 0,
+          "Cyclic Data Set: Actual Acceleration", HFILL }
+      },
+      { &hf_cip_pos_cmd,
+        { "Position Command", "cipm.posfcmd",
+          FT_DOUBLE, BASE_NONE, NULL, 0,
+          "Cyclic Data Set: Position Command (LREAL)", HFILL }
+      },
+      { &hf_cip_pos_cmd_int,
+        { "Position Command", "cipm.posicmd",
+          FT_INT32, BASE_DEC, NULL, 0,
+          "Cyclic Data Set: Position Command (DINT)", HFILL }
+      },
+      { &hf_cip_vel_cmd,
+        { "Velocity Command", "cipm.velcmd",
+          FT_FLOAT, BASE_NONE, NULL, 0,
+          "Cyclic Data Set: Velocity Command", HFILL }
+      },
+      { &hf_cip_accel_cmd,
+        { "Acceleration Command", "cipm.accelcmd",
+          FT_FLOAT, BASE_NONE, NULL, 0,
+          "Cyclic Data Set: Acceleration Command", HFILL }
+      },
+      { &hf_cip_trq_cmd,
+        { "Torque Command", "cipm.torquecmd",
+          FT_FLOAT, BASE_NONE, NULL, 0,
+          "Cyclic Data Set: Torque Command", HFILL }
+      },
+      { &hf_cip_pos_trim,
+        { "Position Trim", "cipm.postrim",
+          FT_INT32, BASE_DEC, NULL, 0,
+          NULL, HFILL }
+      },
+      { &hf_cip_vel_trim,
+        { "Velocity Trim", "cipm.veltrim",
+          FT_FLOAT, BASE_NONE, NULL, 0,
+          NULL, HFILL }
+      },
+      { &hf_cip_accel_trim,
+        { "Acceleration Trim", "cipm.acceltrim",
+          FT_FLOAT, BASE_NONE, NULL, 0,
+          NULL, HFILL }
+      },
+      { &hf_cip_trq_trim,
+        { "Torque Trim", "cipm.trqtrim",
+          FT_FLOAT, BASE_NONE, NULL, 0,
+          NULL, HFILL }
+      },
+      { &hf_cip_data,
+        { "Data", "cipm.data",
+        FT_BYTES, BASE_NONE, NULL, 0,
+          NULL, HFILL }
+      }
    };
 
    /* Setup protocol subtree array, these will help Wireshark remember
@@ -2118,6 +2910,7 @@ proto_register_cipmotion(void)
    static gint *cip_subtree[] = {
       &ett_cipmotion,
       &ett_cont_dev_header,
+      &ett_control_status,
       &ett_node_control,
       &ett_node_status,
       &ett_time_data_set,
@@ -2149,28 +2942,30 @@ proto_register_cipmotion(void)
      "CIP Motion",           /* Short name of protocol       */
      "cipm");                /* Abbreviated name of protocol */
 
+   proto_cipmotion3 = proto_register_protocol_in_name_only(
+     "Common Industrial Protocol, Motion - Rev 3",
+     "CIP Motion - Rev 3",
+     "cipm3",
+     proto_cipmotion,
+     FT_PROTOCOL);
+
    /* Register the header fields with the protocol */
-   proto_register_field_array(proto_cipmotion, header_fields, array_length(header_fields));
+   proto_register_field_array(proto_cipmotion, hf, array_length(hf));
 
    /* Register the subtrees for the protocol dissection */
    proto_register_subtree_array(cip_subtree, array_length(cip_subtree));
 
-   register_dissector( "cipmotion", dissect_cipmotion, proto_cipmotion);
+   cipmotion_handle = register_dissector("cipmotion", dissect_cipmotion, proto_cipmotion);
+   cipmotion3_handle = register_dissector("cipmotion3", dissect_cipmotion3, proto_cipmotion3);
 }
 
-/*
- * Function name: proto_reg_handoff_cipmotion
- *
- * Purpose: This function will setup the automatic dissection of the CIP Motion datagram,
- * it is called by Wireshark when the protocol is registered
- *
- * Returns: void
- */
-void
-proto_reg_handoff_cipmotion(void)
+void proto_reg_handoff_cipmotion(void)
 {
-}
+   dissector_add_for_decode_as("cip.io", cipmotion_handle);
+   dissector_add_for_decode_as("cip.io", cipmotion3_handle);
 
+   dissector_add_uint("cip.io.iface", CI_CLS_MOTION, cipmotion_handle);
+}
 
 /*
 * Editor modelines - http://www.wireshark.org/tools/modelines.html