/* packet-rdm.c
 * RDM (Remote Device Management) packet disassembly.
 *
 * This dissector is written by
 *
 *  Erwin Rol <erwin@erwinrol.com>
 *  Copyright 2003, 2011, 2012 Erwin Rol
 *
 *  Shaun Jackman <sjackman@gmail.com>
 *  Copyright 2006 Pathway Connectivity
 *
 *  Wireshark - Network traffic analyzer
 *  Gerald Combs <gerald@wireshark.org>
 *  Copyright 1999 Gerald Combs
 *
 * SPDX-License-Identifier: GPL-2.0-or-later
 */
/*
 * ANSI E1.20-2006, Entertainment Technology
 * Remote Device Management over USITT DMX512, describes a method of
 * bi-directional communications over a USITT DMX512/1990 data link
 * between an entertainment lighting controller and one or more
 * remotely controlled lighting devices. The protocol also is intended
 * to work with the ANSI E1.11-2004 control protocol. It allows
 * discovery of devices on a DMX512/E1.11 network and the remote
 * setting of DMX starting addresses, as well as status and fault
 * reporting back to the control console.
 */

#include "config.h"

#include <epan/packet.h>
#include <epan/expert.h>
#include "packet-rdm.h"

void proto_register_rdm(void);
void proto_reg_handoff_rdm(void);

#define RDM_SC_RDM				0xCC
#define RDM_SC_SUB_MESSAGE			0x01

#define RDM_CC_COMMAND_RESPONSE_FLAG		0x01

#define RDM_CC_DISCOVERY_COMMAND		0x10
#define RDM_CC_DISCOVERY_COMMAND_RESPONSE	0x11
#define RDM_CC_GET_COMMAND			0x20
#define RDM_CC_GET_COMMAND_RESPONSE		0x21
#define RDM_CC_SET_COMMAND			0x30
#define RDM_CC_SET_COMMAND_RESPONSE		0x31

static const value_string rdm_cc_vals[] = {
	{ RDM_CC_DISCOVERY_COMMAND,		"Discovery Command" },
	{ RDM_CC_DISCOVERY_COMMAND_RESPONSE,	"Discovery Command Response" },
	{ RDM_CC_GET_COMMAND,			"Get Command" },
	{ RDM_CC_GET_COMMAND_RESPONSE,		"Get Command Response" },
	{ RDM_CC_SET_COMMAND,			"Set Command" },
	{ RDM_CC_SET_COMMAND_RESPONSE,		"Set Command Response" },
	{ 0, NULL },
};

#define RDM_RESPONSE_TYPE_ACK			0x00
#define RDM_RESPONSE_TYPE_ACK_TIMER		0x01
#define RDM_RESPONSE_TYPE_NACK_REASON		0x02
#define RDM_RESPONSE_TYPE_ACK_OVERFLOW		0x03

static const value_string rdm_rt_vals[] = {
	{ RDM_RESPONSE_TYPE_ACK,		"Ack" },
	{ RDM_RESPONSE_TYPE_ACK_TIMER,		"Ack Timer" },
	{ RDM_RESPONSE_TYPE_NACK_REASON,	"Nack Reason" },
	{ RDM_RESPONSE_TYPE_ACK_OVERFLOW,	"Ack Overflow" },
	{ 0, NULL },
};

#define RDM_NR_UNKNOWN_PID			0x0000
#define RDM_NR_FORMAT_ERROR			0x0001
#define RDM_NR_HARDWARE_FAULT			0x0002
#define RDM_NR_PROXY_REJECT			0x0003
#define RDM_NR_WRITE_PROTECT			0x0004
#define RDM_NR_UNSUPPORTED_COMMAND_CLASS	0x0005
#define RDM_NR_DATA_OUT_OF_RANGE		0x0006
#define RDM_NR_BUFFER_FULL			0x0007
#define RDM_NR_PACKET_SIZE_UNSUPPORTED		0x0008
#define RDM_NR_SUB_DEVICE_OUT_OF_RANGE		0x0009
#define RDM_NR_PROXY_BUFFER_FULL		0x000A

static const value_string rdm_nr_vals[] = {
	{ RDM_NR_UNKNOWN_PID,			"Unknown PID" },
	{ RDM_NR_FORMAT_ERROR,			"Format Error" },
	{ RDM_NR_HARDWARE_FAULT,		"Hardware Fault" },
	{ RDM_NR_PROXY_REJECT,			"Proxy Reject" },
	{ RDM_NR_WRITE_PROTECT,			"Write Protect" },
	{ RDM_NR_UNSUPPORTED_COMMAND_CLASS,	"Unsupported Command Class" },
	{ RDM_NR_DATA_OUT_OF_RANGE,		"Data Out Of Range" },
	{ RDM_NR_BUFFER_FULL,			"Buffer Full" },
	{ RDM_NR_PACKET_SIZE_UNSUPPORTED,	"Packet Size Unsupported" },
	{ RDM_NR_SUB_DEVICE_OUT_OF_RANGE,	"Sub-Device Out Of Range" },
	{ RDM_NR_PROXY_BUFFER_FULL,		"Proxy Buffer Full" },
	{ 0, NULL },
};

#define RDM_PARAM_ID_DISC_UNIQUE_BRANCH			0x0001
#define RDM_PARAM_ID_DISC_MUTE				0x0002
#define RDM_PARAM_ID_DISC_UN_MUTE			0x0003
#define RDM_PARAM_ID_PROXIED_DEVICES			0x0010
#define RDM_PARAM_ID_PROXIED_DEVICE_COUNT		0x0011
#define RDM_PARAM_ID_COMMS_STATUS			0x0015
#define RDM_PARAM_ID_QUEUED_MESSAGE			0x0020
#define RDM_PARAM_ID_STATUS_MESSAGES			0x0030
#define RDM_PARAM_ID_STATUS_ID_DESCRIPTION		0x0031
#define RDM_PARAM_ID_CLEAR_STATUS_ID			0x0032
#define RDM_PARAM_ID_SUB_DEVICE_STATUS_REPORT_THRESHOLD 0x0033
#define RDM_PARAM_ID_SUPPORTED_PARAMETERS		0x0050
#define RDM_PARAM_ID_PARAMETER_DESCRIPTION		0x0051
#define RDM_PARAM_ID_DEVICE_INFO			0x0060
#define RDM_PARAM_ID_PRODUCT_DETAIL_ID_LIST		0x0070
#define RDM_PARAM_ID_DEVICE_MODEL_DESCRIPTION		0x0080
#define RDM_PARAM_ID_MANUFACTURER_LABEL			0x0081
#define RDM_PARAM_ID_DEVICE_LABEL			0x0082
#define RDM_PARAM_ID_FACTORY_DEFAULTS			0x0090
#define RDM_PARAM_ID_LANGUAGE_CAPABILITIES		0x00A0
#define RDM_PARAM_ID_LANGUAGE				0x00B0
#define RDM_PARAM_ID_SOFTWARE_VERSION_LABEL		0x00C0
#define RDM_PARAM_ID_BOOT_SOFTWARE_VERSION_ID		0x00C1
#define RDM_PARAM_ID_BOOT_SOFTWARE_VERSION_LABEL	0x00C2
#define RDM_PARAM_ID_DMX_PERSONALITY			0x00E0
#define RDM_PARAM_ID_DMX_PERSONALITY_DESCRIPTION	0x00E1
#define RDM_PARAM_ID_DMX_START_ADDRESS			0x00F0
#define RDM_PARAM_ID_SLOT_INFO				0x0120
#define RDM_PARAM_ID_SLOT_DESCRIPTION			0x0121
#define RDM_PARAM_ID_DEFAULT_SLOT_VALUE			0x0122
#define RDM_PARAM_ID_SENSOR_DEFINITION			0x0200
#define RDM_PARAM_ID_SENSOR_VALUE			0x0201
#define RDM_PARAM_ID_RECORD_SENSORS			0x0202
#define RDM_PARAM_ID_DEVICE_HOURS			0x0400
#define RDM_PARAM_ID_LAMP_HOURS				0x0401
#define RDM_PARAM_ID_LAMP_STRIKES			0x0402
#define RDM_PARAM_ID_LAMP_STATE				0x0403
#define RDM_PARAM_ID_LAMP_ON_MODE			0x0404
#define RDM_PARAM_ID_DEVICE_POWER_CYCLES		0x0405
#define RDM_PARAM_ID_DISPLAY_INVERT			0x0500
#define RDM_PARAM_ID_DISPLAY_LEVEL			0x0501
#define RDM_PARAM_ID_PAN_INVERT				0x0600
#define RDM_PARAM_ID_TILT_INVERT			0x0601
#define RDM_PARAM_ID_PAN_TILT_SWAP			0x0602
#define RDM_PARAM_ID_REAL_TIME_CLOCK			0x0603
#define RDM_PARAM_ID_IDENTIFY_DEVICE			0x1000
#define RDM_PARAM_ID_RESET_DEVICE			0x1001
#define RDM_PARAM_ID_POWER_STATE			0x1010
#define RDM_PARAM_ID_PERFORM_SELFTEST			0x1020
#define RDM_PARAM_ID_SELF_TEST_DESCRIPTION		0x1021
#define RDM_PARAM_ID_CAPTURE_PRESET			0x1030
#define RDM_PARAM_ID_PRESET_PLAYBACK			0x1031

const value_string rdm_param_id_vals[] = {
	{ RDM_PARAM_ID_DISC_UNIQUE_BRANCH,		   "DISC_UNIQUE_BRANCH" },
	{ RDM_PARAM_ID_DISC_MUTE,			   "DISC_MUTE" },
	{ RDM_PARAM_ID_DISC_UN_MUTE,			   "DISC_UN_MUTE" },
	{ RDM_PARAM_ID_PROXIED_DEVICES,			   "PROXIED_DEVICES" },
	{ RDM_PARAM_ID_PROXIED_DEVICE_COUNT,		   "PROXIED_DEVICE_COUNT" },
	{ RDM_PARAM_ID_COMMS_STATUS,			   "COMMS_STATUS" },
	{ RDM_PARAM_ID_QUEUED_MESSAGE,			   "QUEUED_MESSAGE" },
	{ RDM_PARAM_ID_STATUS_MESSAGES,			   "STATUS_MESSAGES" },
	{ RDM_PARAM_ID_STATUS_ID_DESCRIPTION,		   "STATUS_ID_DESCRIPTION" },
	{ RDM_PARAM_ID_CLEAR_STATUS_ID,			   "CLEAR_STATUS_ID" },
	{ RDM_PARAM_ID_SUB_DEVICE_STATUS_REPORT_THRESHOLD, "DEVICE_STATUS_REPORT_THRESHOLD" },
	{ RDM_PARAM_ID_SUPPORTED_PARAMETERS,		   "SUPPORTED_PARAMETERS" },
	{ RDM_PARAM_ID_PARAMETER_DESCRIPTION,		   "PARAMETER_DESCRIPTION" },
	{ RDM_PARAM_ID_DEVICE_INFO,			   "DEVICE_INFO" },
	{ RDM_PARAM_ID_PRODUCT_DETAIL_ID_LIST,		   "PRODUCT_DETAIL_ID_LIST" },
	{ RDM_PARAM_ID_DEVICE_MODEL_DESCRIPTION,	   "DEVICE_MODEL_DESCRIPTION" },
	{ RDM_PARAM_ID_MANUFACTURER_LABEL,		   "MANUFACTURER_LABEL" },
	{ RDM_PARAM_ID_DEVICE_LABEL,			   "DEVICE_LABEL" },
	{ RDM_PARAM_ID_FACTORY_DEFAULTS,		   "FACTORY_DEFAULTS" },
	{ RDM_PARAM_ID_LANGUAGE_CAPABILITIES,		   "LANGUAGE_CAPABILITIES" },
	{ RDM_PARAM_ID_LANGUAGE,			   "LANGUAGE" },
	{ RDM_PARAM_ID_SOFTWARE_VERSION_LABEL,		   "SOFTWARE_VERSION_LABEL" },
	{ RDM_PARAM_ID_BOOT_SOFTWARE_VERSION_ID,	   "BOOT_SOFTWARE_VERSION_ID" },
	{ RDM_PARAM_ID_BOOT_SOFTWARE_VERSION_LABEL,	   "BOOT_SOFTWARE_VERSION_LABEL" },
	{ RDM_PARAM_ID_DMX_PERSONALITY,			   "DMX_PERSONALITY" },
	{ RDM_PARAM_ID_DMX_PERSONALITY_DESCRIPTION,	   "DMX_PERSONALITY_DESCRIPTION" },
	{ RDM_PARAM_ID_DMX_START_ADDRESS,		   "DMX_START_ADDRESS" },
	{ RDM_PARAM_ID_SLOT_INFO,			   "SLOT_INFO" },
	{ RDM_PARAM_ID_SLOT_DESCRIPTION,		   "SLOT_DESCRIPTION" },
	{ RDM_PARAM_ID_DEFAULT_SLOT_VALUE,		   "DEFAULT_SLOT_VALUE" },
	{ RDM_PARAM_ID_SENSOR_DEFINITION,		   "SENSOR_DEFINITION" },
	{ RDM_PARAM_ID_SENSOR_VALUE,			   "SENSOR_VALUE" },
	{ RDM_PARAM_ID_RECORD_SENSORS,			   "RECORD_SENSORS" },
	{ RDM_PARAM_ID_DEVICE_HOURS,			   "DEVICE_HOURS" },
	{ RDM_PARAM_ID_LAMP_HOURS,			   "LAMP_HOURS" },
	{ RDM_PARAM_ID_LAMP_STRIKES,			   "LAMP_STRIKES" },
	{ RDM_PARAM_ID_LAMP_STATE,			   "LAMP_STATE" },
	{ RDM_PARAM_ID_LAMP_ON_MODE,			   "LAMP_ON_MODE" },
	{ RDM_PARAM_ID_DEVICE_POWER_CYCLES,		   "DEVICE_POWER_CYCLES" },
	{ RDM_PARAM_ID_DISPLAY_INVERT,			   "DISPLAY_INVERT" },
	{ RDM_PARAM_ID_DISPLAY_LEVEL,			   "DISPLAY_LEVEL" },
	{ RDM_PARAM_ID_PAN_INVERT,			   "PAN_INVERT" },
	{ RDM_PARAM_ID_TILT_INVERT,			   "TILT_INVERT" },
	{ RDM_PARAM_ID_PAN_TILT_SWAP,			   "PAN_TILT_SWAP" },
	{ RDM_PARAM_ID_REAL_TIME_CLOCK,			   "REAL_TIME_CLOCK" },
	{ RDM_PARAM_ID_IDENTIFY_DEVICE,			   "IDENTIFY_DEVICE" },
	{ RDM_PARAM_ID_RESET_DEVICE,			   "RESET_DEVICE" },
	{ RDM_PARAM_ID_POWER_STATE,			   "POWER_STATE" },
	{ RDM_PARAM_ID_PERFORM_SELFTEST,		   "PERFORM_SELFTEST" },
	{ RDM_PARAM_ID_SELF_TEST_DESCRIPTION,		   "SELF_TEST_DESCRIPTION" },
	{ RDM_PARAM_ID_CAPTURE_PRESET,			   "CAPTURE_PRESET" },
	{ RDM_PARAM_ID_PRESET_PLAYBACK,			   "PRESET_PLAYBACK" },
	{ 0, NULL },
};

value_string_ext rdm_param_id_vals_ext = VALUE_STRING_EXT_INIT(rdm_param_id_vals);

#define RDM_STATUS_NONE				0x00
#define RMD_STATUS_GET_LAST_MESSAGE		0x01
#define RDM_STATUS_ADVISORY			0x02
#define RDM_STATUS_WARNING			0x03
#define RDM_STATUS_ERROR			0x04

static const value_string rdm_status_vals[] = {
	{ RDM_STATUS_NONE,		"None" },
	{ RMD_STATUS_GET_LAST_MESSAGE,	"Get Last Message" },
	{ RDM_STATUS_ADVISORY,		"Advisory" },
	{ RDM_STATUS_WARNING,		"Warning" },
	{ RDM_STATUS_ERROR,		"Error" },
	{ 0, NULL },
};

#define RDM_PREFIX_NONE		0x00
#define RDM_PREFIX_DECI		0x01
#define RDM_PREFIX_CENTI	0x02
#define RDM_PREFIX_MILLI	0x03
#define RDM_PREFIX_MICRO	0x04
#define RDM_PREFIX_NANO		0x05
#define RDM_PREFIX_PICO		0x06
#define RDM_PREFIX_FEMPTO	0x07
#define RDM_PREFIX_ATTO		0x08
#define RDM_PREFIX_ZEPTO	0x09
#define RDM_PREFIX_YOCTO	0x0A
#define RDM_PREFIX_DECA		0x11
#define RDM_PREFIX_HECTO	0x12
#define RDM_PREFIX_KILO		0x13
#define RDM_PREFIX_MEGA		0x14
#define RDM_PREFIX_GIGA		0x15
#define RDM_PREFIX_TERRA	0x16
#define RDM_PREFIX_PETA		0x17
#define RDM_PREFIX_EXA		0x18
#define RDM_PREFIX_ZETTA	0x19
#define RDM_PREFIX_YOTTA	0x1A

static const value_string rdm_prefix_vals[] = {
	{ RDM_PREFIX_NONE,	"NONE (x1)" },
	{ RDM_PREFIX_DECI,	"deci (x10^-1)" },
	{ RDM_PREFIX_CENTI,	"centi (x10^-2)" },
	{ RDM_PREFIX_MILLI,	"milli (x10^-3)" },
	{ RDM_PREFIX_MICRO,	"micro (x10^-6)" },
	{ RDM_PREFIX_NANO,	"nano (x10^-9)" },
	{ RDM_PREFIX_PICO,	"pico (x10^-12)" },
	{ RDM_PREFIX_FEMPTO,	"fempto (x10^-15)" },
	{ RDM_PREFIX_ATTO,	"atto (x10^-18)" },
	{ RDM_PREFIX_ZEPTO,	"zepto (x10^-21)" },
	{ RDM_PREFIX_YOCTO,	"yocto (x10^-24)" },
	{ RDM_PREFIX_DECA,	"deca (x10^1)" },
	{ RDM_PREFIX_HECTO,	"hecto (x10^2)" },
	{ RDM_PREFIX_KILO,	"kilo (x10^3)" },
	{ RDM_PREFIX_MEGA,	"mega (x10^6)" },
	{ RDM_PREFIX_GIGA,	"giga (x10^9)" },
	{ RDM_PREFIX_TERRA,	"terra (x10^12)" },
	{ RDM_PREFIX_PETA,	"peta (x10^15)" },
	{ RDM_PREFIX_EXA,	"exa (x10^18)" },
	{ RDM_PREFIX_ZETTA,	"zetta (x10^21)" },
	{ RDM_PREFIX_YOTTA,	"yotta (x10^24)" },
	{ 0, NULL },
};
static value_string_ext rdm_prefix_vals_ext = VALUE_STRING_EXT_INIT(rdm_prefix_vals);

#define RDM_UNITS_NONE			      0x00
#define RDM_UNITS_CENTIGRADE		      0x01
#define RDM_UNITS_VOLTS_DC		      0x02
#define RDM_UNITS_VOLTS_AC_PEAK		      0x03
#define RDM_UNITS_VOLTS_AC_RMS		      0x04
#define RDM_UNITS_AMPERE_DC		      0x05
#define RDM_UNITS_AMPERE_AC_PEAK	      0x06
#define RDM_UNITS_AMPERE_AC_RMS		      0x07
#define RDM_UNITS_HERTZ			      0x08
#define RDM_UNITS_OHM			      0x09
#define RDM_UNITS_WATT			      0x0A
#define RDM_UNITS_KILOGRAM		      0x0B
#define RDM_UNITS_METERS		      0x0C
#define RDM_UNITS_METERS_SQUARED	      0x0D
#define RDM_UNITS_METERS_CUBED		      0x0E
#define RDM_UNITS_KILOGRAMMES_PER_METER_CUBED 0x0F
#define RDM_UNITS_METERS_PER_SECOND	      0x10
#define RDM_UNITS_METERS_PER_SECOND_SQUARED   0x11
#define RDM_UNITS_NEWTON		      0x12
#define RDM_UNITS_JOULE			      0x13
#define RDM_UNITS_PASCAL		      0x14
#define RDM_UNITS_SECOND		      0x15
#define RDM_UNITS_DEGREE		      0x16
#define RDM_UNITS_STERADIAN		      0x17
#define RDM_UNITS_CANDELA		      0x18
#define RDM_UNITS_LUMEN			      0x19
#define RDM_UNITS_LUX			      0x1A
#define RDM_UNITS_IRE			      0x1B
#define RDM_UNITS_BYTE			      0x1C

static const value_string rdm_unit_vals[] = {
	{ RDM_UNITS_NONE,			 "NONE" },
	{ RDM_UNITS_CENTIGRADE,			 "Centigrade" },
	{ RDM_UNITS_VOLTS_DC,			 "Volts DC" },
	{ RDM_UNITS_VOLTS_AC_PEAK,		 "Volts AC Peak" },
	{ RDM_UNITS_VOLTS_AC_RMS,		 "Volts AC RMS" },
	{ RDM_UNITS_AMPERE_DC,			 "Ampere DC" },
	{ RDM_UNITS_AMPERE_AC_PEAK,		 "Ampere AC Peak" },
	{ RDM_UNITS_AMPERE_AC_RMS,		 "Ampere AC RMS" },
	{ RDM_UNITS_HERTZ,			 "Hertz" },
	{ RDM_UNITS_OHM,			 "Ohm" },
	{ RDM_UNITS_WATT,			 "Watt" },
	{ RDM_UNITS_KILOGRAM,			 "Kilogram" },
	{ RDM_UNITS_METERS,			 "Meters" },
	{ RDM_UNITS_METERS_SQUARED,		 "Meters Squared" },
	{ RDM_UNITS_METERS_CUBED,		 "Meters Cubed" },
	{ RDM_UNITS_KILOGRAMMES_PER_METER_CUBED, "Kilogrammes per Meter Cubed" },
	{ RDM_UNITS_METERS_PER_SECOND,		 "Meters per Second" },
	{ RDM_UNITS_METERS_PER_SECOND_SQUARED,	 "Meters per Second Squared" },
	{ RDM_UNITS_NEWTON,			 "Newton" },
	{ RDM_UNITS_JOULE,			 "Joule" },
	{ RDM_UNITS_PASCAL,			 "Pascal" },
	{ RDM_UNITS_SECOND,			 "Second" },
	{ RDM_UNITS_DEGREE,			 "Degree" },
	{ RDM_UNITS_STERADIAN,			 "Steradian" },
	{ RDM_UNITS_CANDELA,			 "Candela" },
	{ RDM_UNITS_LUMEN,			 "Lumen" },
	{ RDM_UNITS_LUX,			 "Lux" },
	{ RDM_UNITS_IRE,			 "Ire" },
	{ RDM_UNITS_BYTE,			 "Byte" },
	{ 0, NULL },
};
static value_string_ext rdm_unit_vals_ext = VALUE_STRING_EXT_INIT(rdm_unit_vals);

#define RDM_SENS_TEMPERATURE	    0x00
#define RDM_SENS_VOLTAGE	    0x01
#define RDM_SENS_CURRENT	    0x02
#define RDM_SENS_FREQUENCY	    0x03
#define RDM_SENS_RESISTANCE	    0x04
#define RDM_SENS_POWER		    0x05
#define RDM_SENS_MASS		    0x06
#define RDM_SENS_LENGTH		    0x07
#define RDM_SENS_AREA		    0x08
#define RDM_SENS_VOLUME		    0x09
#define RDM_SENS_DENSITY	    0x0A
#define RDM_SENS_VELOCITY	    0x0B
#define RDM_SENS_ACCELERATION	    0x0C
#define RDM_SENS_FORCE		    0x0D
#define RDM_SENS_ENERGY		    0x0E
#define RDM_SENS_PRESSURE	    0x0F
#define RDM_SENS_TIME		    0x10
#define RDM_SENS_ANGLE		    0x11
#define RDM_SENS_POSITION_X	    0x12
#define RDM_SENS_POSITION_Y	    0x13
#define RDM_SENS_POSITION_Z	    0x14
#define RDM_SENS_ANGULAR_VELOCITY   0x15
#define RDM_SENS_LUMINOUS_INTENSITY 0x16
#define RDM_SENS_LUMINOUS_FLUX	    0x17
#define RDM_SENS_ILLUMINANCE	    0x18
#define RDM_SENS_CHROMINANCE_RED    0x19
#define RDM_SENS_CHROMINANCE_GREEN  0x1A
#define RDM_SENS_CHROMINANCE_BLUE   0x1B
#define RDM_SENS_CONTACTS	    0x1C
#define RDM_SENS_MEMORY		    0x1D
#define RDM_SENS_ITEMS		    0x1E
#define RDM_SENS_HUMIDITY	    0x1F
#define RDM_SENS_COUNTER_16BIT	    0x20
#define RDM_SENS_OTHER		    0x7F

static const value_string rdm_sensor_type_vals[] = {
	{ RDM_SENS_TEMPERATURE,		"Temperature" },
	{ RDM_SENS_VOLTAGE,		"Voltage" },
	{ RDM_SENS_CURRENT,		"Current" },
	{ RDM_SENS_FREQUENCY,		"Frequency" },
	{ RDM_SENS_RESISTANCE,		"Resistance" },
	{ RDM_SENS_POWER,		"Power" },
	{ RDM_SENS_MASS,		"Mass" },
	{ RDM_SENS_LENGTH,		"Length" },
	{ RDM_SENS_AREA,		"Area" },
	{ RDM_SENS_VOLUME,		"Volume" },
	{ RDM_SENS_DENSITY,		"Density" },
	{ RDM_SENS_VELOCITY,		"Velocity" },
	{ RDM_SENS_ACCELERATION,	"Acceleration" },
	{ RDM_SENS_FORCE,		"Force" },
	{ RDM_SENS_ENERGY,		"Energy" },
	{ RDM_SENS_PRESSURE,		"Pressure" },
	{ RDM_SENS_TIME,		"Time" },
	{ RDM_SENS_ANGLE,		"Angle" },
	{ RDM_SENS_POSITION_X,		"Position X" },
	{ RDM_SENS_POSITION_Y,		"Position Y" },
	{ RDM_SENS_POSITION_Z,		"Position Z" },
	{ RDM_SENS_ANGULAR_VELOCITY,	"Angular Velocity" },
	{ RDM_SENS_LUMINOUS_INTENSITY,	"Luminous Intensity" },
	{ RDM_SENS_LUMINOUS_FLUX,	"Luminous Flux" },
	{ RDM_SENS_ILLUMINANCE,		"Illuminance" },
	{ RDM_SENS_CHROMINANCE_RED,	"Chrominance Red" },
	{ RDM_SENS_CHROMINANCE_GREEN,	"Chrominance Green" },
	{ RDM_SENS_CHROMINANCE_BLUE,	"Chrominance Blue" },
	{ RDM_SENS_CONTACTS,		"Contacts" },
	{ RDM_SENS_MEMORY,		"Memory" },
	{ RDM_SENS_ITEMS,		"Items" },
	{ RDM_SENS_HUMIDITY,		"Humidity" },
	{ RDM_SENS_COUNTER_16BIT,	"Counter 16bit" },
	{ RDM_SENS_OTHER,		"Other" },
	{ 0, NULL} ,
};
static value_string_ext rdm_sensor_type_vals_ext = VALUE_STRING_EXT_INIT(rdm_sensor_type_vals);

#define RDM_PRODUCT_CATEGORY_NOT_DECLARED		0x0000
#define RDM_PRODUCT_CATEGORY_FIXTURE			0x0100
#define RDM_PRODUCT_CATEGORY_FIXTURE_FIXED		0x0101
#define RDM_PRODUCT_CATEGORY_FIXTURE_MOVING_YOKE	0x0102
#define RDM_PRODUCT_CATEGORY_FIXTURE_MOVING_MIRROR	0x0103
#define RDM_PRODUCT_CATEGORY_FIXTURE_OTHER		0x01FF
#define RDM_PRODUCT_CATEGORY_FIXTURE_ACCESSORY		0x0200
#define RDM_PRODUCT_CATEGORY_FIXTURE_ACCESSORY_COLOR	0x0201
#define RDM_PRODUCT_CATEGORY_FIXTURE_ACCESSORY_YOKE	0x0202
#define RDM_PRODUCT_CATEGORY_FIXTURE_ACCESSORY_MIRROR	0x0203
#define RDM_PRODUCT_CATEGORY_FIXTURE_ACCESSORY_EFFECT	0x0204
#define RDM_PRODUCT_CATEGORY_FIXTURE_ACCESSORY_BEAM	0x0205
#define RDM_PRODUCT_CATEGORY_FIXTURE_ACCESSORY_OTHER	0x02FF
#define RDM_PRODUCT_CATEGORY_PROJECTOR			0x0300
#define RDM_PRODUCT_CATEGORY_PROJECTOR_FIXED		0x0301
#define RDM_PRODUCT_CATEGORY_PROJECTOR_MOVING_YOKE	0x0302
#define RDM_PRODUCT_CATEGORY_PROJECTOR_MOVING_MIRROR	0x0303
#define RDM_PRODUCT_CATEGORY_PROJECTOR_OTHER		0x03FF
#define RDM_PRODUCT_CATEGORY_ATMOSPHERIC		0x0400
#define RDM_PRODUCT_CATEGORY_ATMOSPHERIC_EFFECT		0x0401
#define RDM_PRODUCT_CATEGORY_ATMOSPHERIC_PYRO		0x0402
#define RDM_PRODUCT_CATEGORY_ATMOSPHERIC_OTHER		0x04FF
#define RDM_PRODUCT_CATEGORY_DIMMER			0x0500
#define RDM_PRODUCT_CATEGORY_DIMMER_AC_INCANDESCENT	0x0501
#define RDM_PRODUCT_CATEGORY_DIMMER_AC_FLUORESCENT	0x0502
#define RDM_PRODUCT_CATEGORY_DIMMER_AC_COLDCATHODE	0x0503
#define RDM_PRODUCT_CATEGORY_DIMMER_AC_NONDIM		0x0504
#define RDM_PRODUCT_CATEGORY_DIMMER_AC_ELV		0x0505
#define RDM_PRODUCT_CATEGORY_DIMMER_AC_OTHER		0x0506
#define RDM_PRODUCT_CATEGORY_DIMMER_DC_LEVEL		0x0507
#define RDM_PRODUCT_CATEGORY_DIMMER_DC_PWM		0x0508
#define RDM_PRODUCT_CATEGORY_DIMMER_CS_LED		0x0509
#define RDM_PRODUCT_CATEGORY_DIMMER_OTHER		0x05FF
#define RDM_PRODUCT_CATEGORY_POWER			0x0600
#define RDM_PRODUCT_CATEGORY_POWER_CONTROL		0x0601
#define RDM_PRODUCT_CATEGORY_POWER_SOURCE		0x0602
#define RDM_PRODUCT_CATEGORY_POWER_OTHER		0x06FF
#define RDM_PRODUCT_CATEGORY_SCENIC			0x0700
#define RDM_PRODUCT_CATEGORY_SCENIC_DRIVE		0x0701
#define RDM_PRODUCT_CATEGORY_SCENIC_OTHER		0x07FF
#define RDM_PRODUCT_CATEGORY_DATA			0x0800
#define RDM_PRODUCT_CATEGORY_DATA_DISTRIBUTION		0x0801
#define RDM_PRODUCT_CATEGORY_DATA_CONVERSION		0x0802
#define RDM_PRODUCT_CATEGORY_DATA_OTHER			0x08FF
#define RDM_PRODUCT_CATEGORY_AV				0x0900
#define RDM_PRODUCT_CATEGORY_AV_AUDIO			0x0901
#define RDM_PRODUCT_CATEGORY_AV_VIDEO			0x0902
#define RDM_PRODUCT_CATEGORY_AV_OTHER			0x09FF
#define RDM_PRODUCT_CATEGORY_MONITOR			0x0A00
#define RDM_PRODUCT_CATEGORY_MONITOR_ACLINEPOWER	0x0A01
#define RDM_PRODUCT_CATEGORY_MONITOR_DCPOWER		0x0A02
#define RDM_PRODUCT_CATEGORY_MONITOR_ENVIRONMENTAL	0x0A03
#define RDM_PRODUCT_CATEGORY_MONITOR_OTHER		0x0AFF
#define RDM_PRODUCT_CATEGORY_CONTROL			0x7000
#define RDM_PRODUCT_CATEGORY_CONTROL_CONTROLLER		0x7001
#define RDM_PRODUCT_CATEGORY_CONTROL_BACKUPDEVICE	0x7002
#define RDM_PRODUCT_CATEGORY_CONTROL_OTHER		0x70FF
#define RDM_PRODUCT_CATEGORY_TEST			0x7100
#define RDM_PRODUCT_CATEGORY_TEST_EQUIPMENT		0x7101
#define RDM_PRODUCT_CATEGORY_TEST_EQUIPMENT_OTHER	0x71FF
#define RDM_PRODUCT_CATEGORY_OTHER			0x7FFF

static const value_string rdm_product_cat_vals[] = {
	{ RDM_PRODUCT_CATEGORY_NOT_DECLARED,		 "Not Declared" },
	{ RDM_PRODUCT_CATEGORY_FIXTURE,			 "Fixture" },
	{ RDM_PRODUCT_CATEGORY_FIXTURE_FIXED,		 "Fixture Fixed" },
	{ RDM_PRODUCT_CATEGORY_FIXTURE_MOVING_YOKE,	 "Fixture Moving Yoke" },
	{ RDM_PRODUCT_CATEGORY_FIXTURE_MOVING_MIRROR,	 "Fixture Moving Mirror" },
	{ RDM_PRODUCT_CATEGORY_FIXTURE_OTHER,		 "Fixture Other" },
	{ RDM_PRODUCT_CATEGORY_FIXTURE_ACCESSORY,	 "Fixture Accessory" },
	{ RDM_PRODUCT_CATEGORY_FIXTURE_ACCESSORY_COLOR,	 "Fixture Accessory Color" },
	{ RDM_PRODUCT_CATEGORY_FIXTURE_ACCESSORY_YOKE,	 "Fixture Accessory Yoke" },
	{ RDM_PRODUCT_CATEGORY_FIXTURE_ACCESSORY_MIRROR, "Fixture Accessory Mirror" },
	{ RDM_PRODUCT_CATEGORY_FIXTURE_ACCESSORY_EFFECT, "Fixture Accessory Effect" },
	{ RDM_PRODUCT_CATEGORY_FIXTURE_ACCESSORY_BEAM,	 "Fixture Accessory Beam" },
	{ RDM_PRODUCT_CATEGORY_FIXTURE_ACCESSORY_OTHER,	 "Fixture Accessory Other" },
	{ RDM_PRODUCT_CATEGORY_PROJECTOR,		 "Projector" },
	{ RDM_PRODUCT_CATEGORY_PROJECTOR_FIXED,		 "Projector Fixed" },
	{ RDM_PRODUCT_CATEGORY_PROJECTOR_MOVING_YOKE,	 "Projector Moving Yoke" },
	{ RDM_PRODUCT_CATEGORY_PROJECTOR_MOVING_MIRROR,	 "Projector Moving Mirror" },
	{ RDM_PRODUCT_CATEGORY_PROJECTOR_OTHER,		 "Projector Other" },
	{ RDM_PRODUCT_CATEGORY_ATMOSPHERIC,		 "Atmospheric" },
	{ RDM_PRODUCT_CATEGORY_ATMOSPHERIC_EFFECT,	 "Atmospheric Effect" },
	{ RDM_PRODUCT_CATEGORY_ATMOSPHERIC_PYRO,	 "Atmospheric Pyro" },
	{ RDM_PRODUCT_CATEGORY_ATMOSPHERIC_OTHER,	 "Atmospheric Other" },
	{ RDM_PRODUCT_CATEGORY_DIMMER,			 "Dimmer" },
	{ RDM_PRODUCT_CATEGORY_DIMMER_AC_INCANDESCENT,	 "Dimmer AC Incandescent" },
	{ RDM_PRODUCT_CATEGORY_DIMMER_AC_FLUORESCENT,	 "Dimmer AC Fluorescent" },
	{ RDM_PRODUCT_CATEGORY_DIMMER_AC_COLDCATHODE,	 "Dimmer AC Coldcathode" },
	{ RDM_PRODUCT_CATEGORY_DIMMER_AC_NONDIM,	 "Dimmer AC Nondim" },
	{ RDM_PRODUCT_CATEGORY_DIMMER_AC_ELV,		 "Dimmer AC ELV" },
	{ RDM_PRODUCT_CATEGORY_DIMMER_AC_OTHER,		 "Dimmer AC Other" },
	{ RDM_PRODUCT_CATEGORY_DIMMER_DC_LEVEL,		 "Dimmer DC Level" },
	{ RDM_PRODUCT_CATEGORY_DIMMER_DC_PWM,		 "Dimmer DC PWM" },
	{ RDM_PRODUCT_CATEGORY_DIMMER_CS_LED,		 "Dimmer CS LED" },
	{ RDM_PRODUCT_CATEGORY_DIMMER_OTHER,		 "Dimmer Other" },
	{ RDM_PRODUCT_CATEGORY_POWER,			 "Power" },
	{ RDM_PRODUCT_CATEGORY_POWER_CONTROL,		 "Power Control" },
	{ RDM_PRODUCT_CATEGORY_POWER_SOURCE,		 "Power Source" },
	{ RDM_PRODUCT_CATEGORY_POWER_OTHER,		 "Power Other" },
	{ RDM_PRODUCT_CATEGORY_SCENIC,			 "Scenic" },
	{ RDM_PRODUCT_CATEGORY_SCENIC_DRIVE,		 "Scenic Drive" },
	{ RDM_PRODUCT_CATEGORY_SCENIC_OTHER,		 "Scenic Other" },
	{ RDM_PRODUCT_CATEGORY_DATA,			 "Data" },
	{ RDM_PRODUCT_CATEGORY_DATA_DISTRIBUTION,	 "Data Distribution" },
	{ RDM_PRODUCT_CATEGORY_DATA_CONVERSION,		 "Data Conversion" },
	{ RDM_PRODUCT_CATEGORY_DATA_OTHER,		 "Data Other" },
	{ RDM_PRODUCT_CATEGORY_AV,			 "AV" },
	{ RDM_PRODUCT_CATEGORY_AV_AUDIO,		 "AV Audio" },
	{ RDM_PRODUCT_CATEGORY_AV_VIDEO,		 "AV Video" },
	{ RDM_PRODUCT_CATEGORY_AV_OTHER,		 "AV Other" },
	{ RDM_PRODUCT_CATEGORY_MONITOR,			 "Monitor" },
	{ RDM_PRODUCT_CATEGORY_MONITOR_ACLINEPOWER,	 "Monitor AC Line Power" },
	{ RDM_PRODUCT_CATEGORY_MONITOR_DCPOWER,		 "Monitor DC Power" },
	{ RDM_PRODUCT_CATEGORY_MONITOR_ENVIRONMENTAL,	 "Monitor Environmental" },
	{ RDM_PRODUCT_CATEGORY_MONITOR_OTHER,		 "Monitor Other" },
	{ RDM_PRODUCT_CATEGORY_CONTROL,			 "Control" },
	{ RDM_PRODUCT_CATEGORY_CONTROL_CONTROLLER,	 "Control Controller" },
	{ RDM_PRODUCT_CATEGORY_CONTROL_BACKUPDEVICE,	 "Control Backup Device" },
	{ RDM_PRODUCT_CATEGORY_CONTROL_OTHER,		 "Control Other" },
	{ RDM_PRODUCT_CATEGORY_TEST,			 "Test" },
	{ RDM_PRODUCT_CATEGORY_TEST_EQUIPMENT,		 "Test Equipment" },
	{ RDM_PRODUCT_CATEGORY_TEST_EQUIPMENT_OTHER,	 "Test Equipment Other" },
	{ RDM_PRODUCT_CATEGORY_OTHER,			 "Other" },
	{ 0, NULL },
};
static value_string_ext rdm_product_cat_vals_ext = VALUE_STRING_EXT_INIT(rdm_product_cat_vals);

static int proto_rdm = -1;

static int hf_rdm_sub_start_code = -1;
static int hf_rdm_message_length = -1;
static int hf_rdm_dest_uid = -1;
static int hf_rdm_src_uid = -1;
static int hf_rdm_transaction_number = -1;
static int hf_rdm_port_id = -1;
static int hf_rdm_response_type = -1;
static int hf_rdm_message_count = -1;
static int hf_rdm_sub_device = -1;
static int hf_rdm_mdb = -1;
static int hf_rdm_command_class = -1;
static int hf_rdm_parameter_id = -1;
static int hf_rdm_parameter_data_length = -1;
static int hf_rdm_parameter_data = -1;
static int hf_rdm_parameter_data_raw = -1;
static int hf_rdm_intron = -1;
static int hf_rdm_checksum = -1;
static int hf_rdm_checksum_status = -1;
static int hf_rdm_trailer = -1;

static int hf_rdm_pd_ack_timer_estimated_response_time = -1;
static int hf_rdm_pd_ack_overflow_uid = -1;
static int hf_rdm_pd_nack_reason_code = -1;

static int hf_rdm_pd_device_label = -1;

static int hf_rdm_pd_manu_label = -1;

static int hf_rdm_pd_dmx_start_address = -1;

static int hf_rdm_pd_queued_message_status = -1;

static int hf_rdm_pd_sensor_nr = -1;
static int hf_rdm_pd_sensor_type = -1;
static int hf_rdm_pd_sensor_unit = -1;
static int hf_rdm_pd_sensor_prefix = -1;
static int hf_rdm_pd_sensor_value_pres = -1;
static int hf_rdm_pd_sensor_value_low = -1;
static int hf_rdm_pd_sensor_value_high = -1;
static int hf_rdm_pd_sensor_value_rec = -1;

static int hf_rdm_pd_sensor_range_min_value = -1;
static int hf_rdm_pd_sensor_range_max_value = -1;
static int hf_rdm_pd_sensor_normal_min_value = -1;
static int hf_rdm_pd_sensor_normal_max_value = -1;
static int hf_rdm_pd_sensor_recorded_value_support = -1;
static int hf_rdm_pd_sensor_description = -1;

static int hf_rdm_pd_device_hours = -1;
static int hf_rdm_pd_lamp_hours = -1;
static int hf_rdm_pd_lamp_strikes = -1;


static int hf_rdm_pd_proto_vers = -1;
static int hf_rdm_pd_device_model_id = -1;
static int hf_rdm_pd_product_cat = -1;
static int hf_rdm_pd_software_vers_id = -1;
static int hf_rdm_pd_dmx_footprint = -1;
static int hf_rdm_pd_dmx_pers_current = -1;
static int hf_rdm_pd_dmx_pers_total = -1;
static int hf_rdm_pd_sub_device_count = -1;
static int hf_rdm_pd_sensor_count = -1;

static int hf_rdm_pd_device_model_description = -1;

static int hf_rdm_pd_disc_unique_branch_lb_uid = -1;
static int hf_rdm_pd_disc_unique_branch_ub_uid = -1;
static int hf_rdm_pd_disc_mute_control_field = -1;
static int hf_rdm_pd_disc_mute_binding_uid = -1;
static int hf_rdm_pd_disc_unmute_control_field = -1;
static int hf_rdm_pd_disc_unmute_binding_uid = -1;
static int hf_rdm_pd_proxied_devices_uid = -1;
static int hf_rdm_pd_proxied_device_count = -1;
static int hf_rdm_pd_proxied_device_list_change = -1;
static int hf_rdm_pd_real_time_clock_year = -1;
static int hf_rdm_pd_real_time_clock_month = -1;
static int hf_rdm_pd_real_time_clock_day = -1;
static int hf_rdm_pd_real_time_clock_hour = -1;
static int hf_rdm_pd_real_time_clock_minute = -1;
static int hf_rdm_pd_real_time_clock_second = -1;
static int hf_rdm_pd_lamp_state = -1;
static int hf_rdm_pd_lamp_on_mode = -1;
static int hf_rdm_pd_device_power_cycles = -1;
static int hf_rdm_pd_display_invert = -1;
static int hf_rdm_pd_display_level = -1;
static int hf_rdm_pd_pan_invert = -1;
static int hf_rdm_pd_tilt_invert = -1;
static int hf_rdm_pd_tilt_swap = -1;
static int hf_rdm_pd_selftest_nr = -1;
static int hf_rdm_pd_selftest_state = -1;
static int hf_rdm_pd_selftest_description = -1;
static int hf_rdm_pd_language_code = -1;
static int hf_rdm_pd_identify_device = -1;
static int hf_rdm_pd_identify_device_state = -1;
static int hf_rdm_pd_reset_device = -1;
static int hf_rdm_pd_power_state = -1;
static int hf_rdm_pd_capture_preset_scene_nr = -1;
static int hf_rdm_pd_capture_preset_up_fade_time = -1;
static int hf_rdm_pd_capture_preset_down_fade_time = -1;
static int hf_rdm_pd_capture_preset_wait_time = -1;
static int hf_rdm_pd_preset_playback_mode = -1;
static int hf_rdm_pd_preset_playback_level = -1;
static int hf_rdm_pd_parameter_id = -1;
static int hf_rdm_pd_parameter_pdl_size = -1;
static int hf_rdm_pd_parameter_data_type = -1;
static int hf_rdm_pd_parameter_cmd_class = -1;
static int hf_rdm_pd_parameter_type = -1;
static int hf_rdm_pd_parameter_unit = -1;
static int hf_rdm_pd_parameter_prefix = -1;
static int hf_rdm_pd_parameter_min_value = -1;
static int hf_rdm_pd_parameter_max_value = -1;
static int hf_rdm_pd_parameter_default_value = -1;
static int hf_rdm_pd_parameter_description = -1;
static int hf_rdm_pd_software_version_label = -1;
static int hf_rdm_pd_boot_software_version_id = -1;
static int hf_rdm_pd_boot_software_version_label = -1;
static int hf_rdm_pd_comms_status_short_msg = -1;
static int hf_rdm_pd_comms_status_len_mismatch = -1;
static int hf_rdm_pd_comms_status_csum_fail = -1;
static int hf_rdm_pd_status_messages_type = -1;
static int hf_rdm_pd_status_messages_sub_device_id = -1;
static int hf_rdm_pd_status_messages_id = -1;
static int hf_rdm_pd_status_messages_data_value_1 = -1;
static int hf_rdm_pd_status_messages_data_value_2 = -1;
static int hf_rdm_pd_status_id = -1;
static int hf_rdm_pd_status_id_description = -1;
static int hf_rdm_pd_sub_device_status_report_threshold_status_type = -1;
static int hf_rdm_pd_product_detail_id_list = -1;
static int hf_rdm_pd_factory_defaults = -1;
static int hf_rdm_pd_dmx_pers_nr = -1;
static int hf_rdm_pd_dmx_pers_count = -1;
static int hf_rdm_pd_dmx_pers_requested = -1;
static int hf_rdm_pd_dmx_pers_slots = -1;
static int hf_rdm_pd_dmx_pers_text = -1;
static int hf_rdm_pd_slot_offset = -1;
static int hf_rdm_pd_slot_type = -1;
static int hf_rdm_pd_slot_label_id = -1;
static int hf_rdm_pd_slot_nr = -1;
static int hf_rdm_pd_slot_description = -1;
static int hf_rdm_pd_slot_value = -1;
static int hf_rdm_pd_rec_value_support = -1;

static int ett_rdm = -1;

static expert_field ei_rdm_checksum = EI_INIT;

static guint16
rdm_checksum(tvbuff_t *tvb, guint length)
{
	guint16 sum = RDM_SC_RDM;
	guint	i;
	for (i = 0; i < length; i++)
		sum += tvb_get_guint8(tvb, i);
	return sum;
}

static guint
dissect_rdm_pd_queued_message(tvbuff_t *tvb, guint offset, proto_tree *tree, guint8 cc, guint8 len _U_)
{
	switch(cc) {
	case RDM_CC_GET_COMMAND:
		proto_tree_add_item(tree, hf_rdm_pd_queued_message_status, tvb,
			offset, 1, ENC_BIG_ENDIAN);
		offset += 1;
		break;
	}

	return offset;
}

static guint
dissect_rdm_pd_dmx_start_address(tvbuff_t *tvb, guint offset, proto_tree *tree, guint8 cc, guint8 len _U_)
{
	switch(cc) {
	case RDM_CC_SET_COMMAND:
	case RDM_CC_GET_COMMAND_RESPONSE:
		proto_tree_add_item(tree, hf_rdm_pd_dmx_start_address, tvb,
			offset, 2, ENC_BIG_ENDIAN);
		offset +=  2;
		break;
	}

	return offset;
}

static guint
dissect_rdm_pd_device_info(tvbuff_t *tvb _U_, guint offset, proto_tree *tree _U_, guint8 cc, guint8 len _U_)
{
	switch(cc) {
	case RDM_CC_GET_COMMAND_RESPONSE:
		proto_tree_add_item(tree, hf_rdm_pd_proto_vers, tvb,
			offset, 2, ENC_BIG_ENDIAN);
		offset +=  2;

		proto_tree_add_item(tree, hf_rdm_pd_device_model_id, tvb,
			offset, 2, ENC_BIG_ENDIAN);
		offset +=  2;

		proto_tree_add_item(tree, hf_rdm_pd_product_cat, tvb,
			offset, 2, ENC_BIG_ENDIAN);
		offset +=  2;

		proto_tree_add_item(tree, hf_rdm_pd_software_vers_id, tvb,
			offset, 4, ENC_BIG_ENDIAN);
		offset +=  4;

		proto_tree_add_item(tree, hf_rdm_pd_dmx_footprint, tvb,
			offset, 2, ENC_BIG_ENDIAN);
		offset +=  2;

		proto_tree_add_item(tree, hf_rdm_pd_dmx_pers_current, tvb,
			offset, 1, ENC_BIG_ENDIAN);
		offset += 1;

		proto_tree_add_item(tree, hf_rdm_pd_dmx_pers_total, tvb,
			offset, 1, ENC_BIG_ENDIAN);
		offset += 1;

		proto_tree_add_item(tree, hf_rdm_pd_dmx_start_address, tvb,
			offset, 2, ENC_BIG_ENDIAN);
		offset +=  2;

		proto_tree_add_item(tree, hf_rdm_pd_sub_device_count, tvb,
			offset, 2, ENC_BIG_ENDIAN);
		offset +=  2;

		proto_tree_add_item(tree, hf_rdm_pd_sensor_count, tvb,
			offset, 1, ENC_BIG_ENDIAN);
		offset += 1;

		break;
	}

	return offset;
}


static guint
dissect_rdm_pd_device_model_description(tvbuff_t *tvb, guint offset, proto_tree *tree, guint8 cc, guint8 len)
{
	switch(cc) {
	case RDM_CC_GET_COMMAND_RESPONSE:
		proto_tree_add_item(tree, hf_rdm_pd_device_model_description, tvb,
			offset, len, ENC_ASCII|ENC_NA);
		offset +=  len;
		break;
	}

	return offset;
}


static guint
dissect_rdm_pd_device_label(tvbuff_t *tvb, guint offset, proto_tree *tree, guint8 cc, guint8 len)
{
	switch(cc) {
	case RDM_CC_SET_COMMAND:
	case RDM_CC_GET_COMMAND_RESPONSE:
		proto_tree_add_item(tree, hf_rdm_pd_device_label, tvb,
			offset, len, ENC_ASCII|ENC_NA);
		offset +=  len;
		break;
	}

	return offset;
}


static guint
dissect_rdm_pd_device_hours(tvbuff_t *tvb, guint offset, proto_tree *tree, guint8 cc, guint8 len _U_)
{
	switch(cc) {
	case RDM_CC_SET_COMMAND:
	case RDM_CC_GET_COMMAND_RESPONSE:
		proto_tree_add_item(tree, hf_rdm_pd_device_hours, tvb,
			offset, 4, ENC_BIG_ENDIAN);
		offset +=  4;
		break;
	}

	return offset;
}


static guint
dissect_rdm_pd_lamp_hours(tvbuff_t *tvb, guint offset, proto_tree *tree, guint8 cc, guint8 len _U_)
{
	switch(cc) {
	case RDM_CC_SET_COMMAND:
	case RDM_CC_GET_COMMAND_RESPONSE:
		proto_tree_add_item(tree, hf_rdm_pd_lamp_hours, tvb,
			offset, 4, ENC_BIG_ENDIAN);
		offset +=  4;
		break;
	}

	return offset;
}


static guint
dissect_rdm_pd_lamp_strikes(tvbuff_t *tvb, guint offset, proto_tree *tree, guint8 cc, guint8 len _U_)
{
	switch(cc) {
	case RDM_CC_SET_COMMAND:
	case RDM_CC_GET_COMMAND_RESPONSE:
		proto_tree_add_item(tree, hf_rdm_pd_lamp_strikes, tvb,
			offset, 4, ENC_BIG_ENDIAN);
		offset +=  4;
		break;
	}

	return offset;
}


static guint
dissect_rdm_pd_sensor_definition(tvbuff_t *tvb, guint offset, proto_tree *tree, guint8 cc, guint8 len)
{
	switch(cc) {
	case RDM_CC_GET_COMMAND:
		proto_tree_add_item(tree, hf_rdm_pd_sensor_nr, tvb,
			offset, 1, ENC_BIG_ENDIAN);
		offset += 1;
		break;

	case RDM_CC_GET_COMMAND_RESPONSE:
		proto_tree_add_item(tree, hf_rdm_pd_sensor_nr, tvb,
			offset, 1, ENC_BIG_ENDIAN);
		offset += 1;

		proto_tree_add_item(tree, hf_rdm_pd_sensor_type, tvb,
			offset, 1, ENC_BIG_ENDIAN);
		offset += 1;

		proto_tree_add_item(tree, hf_rdm_pd_sensor_unit, tvb,
			offset, 1, ENC_BIG_ENDIAN);
		offset += 1;

		proto_tree_add_item(tree, hf_rdm_pd_sensor_prefix, tvb,
			offset, 1, ENC_BIG_ENDIAN);
		offset += 1;

		proto_tree_add_item(tree, hf_rdm_pd_sensor_range_min_value, tvb,
			offset, 2, ENC_BIG_ENDIAN);
		offset +=  2;

		proto_tree_add_item(tree, hf_rdm_pd_sensor_range_max_value, tvb,
			offset, 2, ENC_BIG_ENDIAN);
		offset +=  2;

		proto_tree_add_item(tree, hf_rdm_pd_sensor_normal_min_value, tvb,
			offset, 2, ENC_BIG_ENDIAN);
		offset +=  2;

		proto_tree_add_item(tree, hf_rdm_pd_sensor_normal_max_value, tvb,
			offset, 2, ENC_BIG_ENDIAN);
		offset +=  2;

		proto_tree_add_item(tree, hf_rdm_pd_sensor_recorded_value_support, tvb,
			offset, 1, ENC_BIG_ENDIAN);
		offset += 1;

		proto_tree_add_item(tree, hf_rdm_pd_sensor_description, tvb,
			offset, len - 13, ENC_ASCII|ENC_NA);
		offset += (len - 13);
		break;
	}

	return offset;
}

static guint
dissect_rdm_pd_sensor_value(tvbuff_t *tvb, guint offset, proto_tree *tree, guint8 cc, guint8 len)
{
	switch(cc) {
	case RDM_CC_GET_COMMAND:
	case RDM_CC_SET_COMMAND:
		proto_tree_add_item(tree, hf_rdm_pd_sensor_nr, tvb,
			offset, 1, ENC_BIG_ENDIAN);
		offset += 1;
		break;

	case RDM_CC_GET_COMMAND_RESPONSE:
	case RDM_CC_SET_COMMAND_RESPONSE:
		proto_tree_add_item(tree, hf_rdm_pd_sensor_nr, tvb,
			offset, 1, ENC_BIG_ENDIAN);
		offset += 1;
		proto_tree_add_item(tree, hf_rdm_pd_sensor_value_pres, tvb,
			offset, 2, ENC_BIG_ENDIAN);
		offset +=  2;

		if (len == 7 || len == 9) {
			proto_tree_add_item(tree, hf_rdm_pd_sensor_value_low, tvb,
				offset, 2, ENC_BIG_ENDIAN);
			offset +=  2;
			proto_tree_add_item(tree, hf_rdm_pd_sensor_value_high, tvb,
				offset, 2, ENC_BIG_ENDIAN);
			offset +=  2;
		}

		if (len == 5 || len == 9) {
			proto_tree_add_item(tree, hf_rdm_pd_sensor_value_rec, tvb,
				offset, 2, ENC_BIG_ENDIAN);
			offset +=  2;
		}

		break;
	}

	return offset;
}

static guint
dissect_rdm_pd_manufacturer_label(tvbuff_t *tvb, guint offset, proto_tree *tree, guint8 cc, guint8 len)
{
	switch(cc) {
	case RDM_CC_GET_COMMAND_RESPONSE:
		proto_tree_add_item(tree, hf_rdm_pd_manu_label, tvb,
			offset, len, ENC_ASCII|ENC_NA);
		offset +=  len;
		break;
	}

	return offset;
}

static guint
dissect_rdm_pd_disc_unique_branch(tvbuff_t *tvb, guint offset, proto_tree *tree, guint8 cc, guint8 len _U_)
{
	switch(cc) {
	case RDM_CC_DISCOVERY_COMMAND:
		proto_tree_add_item(tree, hf_rdm_pd_disc_unique_branch_lb_uid, tvb,
			offset, 6, ENC_NA);
		offset += 6;

		proto_tree_add_item(tree, hf_rdm_pd_disc_unique_branch_ub_uid, tvb,
			offset, 6, ENC_NA);
		offset += 6;
		break;
	}

	return offset;
}

static guint
dissect_rdm_pd_disc_mute(tvbuff_t *tvb, guint offset, proto_tree *tree, guint8 cc, guint8 len)
{
	switch(cc) {
	case RDM_CC_DISCOVERY_COMMAND_RESPONSE:
		proto_tree_add_item(tree, hf_rdm_pd_disc_mute_control_field, tvb,
			offset, 2, ENC_BIG_ENDIAN);
		offset += 2;
		if (len > 2) {
			proto_tree_add_item(tree, hf_rdm_pd_disc_mute_binding_uid, tvb,
				offset, 6, ENC_NA);
			offset += 6;
		}
		break;
	}

	return offset;
}

static guint
dissect_rdm_pd_disc_un_mute(tvbuff_t *tvb, guint offset, proto_tree *tree, guint8 cc, guint8 len)
{
	switch(cc) {
	case RDM_CC_DISCOVERY_COMMAND_RESPONSE:
		proto_tree_add_item(tree, hf_rdm_pd_disc_unmute_control_field, tvb,
			offset, 2, ENC_BIG_ENDIAN);
		offset += 2;
		if (len > 2) {
			proto_tree_add_item(tree, hf_rdm_pd_disc_unmute_binding_uid, tvb,
				offset, 6, ENC_NA);
			offset += 6;
		}
		break;
	}

	return offset;
}

static guint
dissect_rdm_pd_proxied_devices(tvbuff_t *tvb, guint offset, proto_tree *tree, guint8 cc, guint8 len)
{
	switch(cc) {
	case RDM_CC_GET_COMMAND_RESPONSE:
		while (len >= 6) {
			proto_tree_add_item(tree, hf_rdm_pd_proxied_devices_uid, tvb,
				offset, 6, ENC_NA);
			offset += 6;
			len    -= 6;
		}
		break;
	}

	return offset;
}

static guint
dissect_rdm_pd_proxied_device_count(tvbuff_t *tvb, guint offset, proto_tree *tree, guint8 cc, guint8 len _U_)
{
	switch(cc) {
	case RDM_CC_GET_COMMAND_RESPONSE:
		proto_tree_add_item(tree, hf_rdm_pd_proxied_device_count, tvb,
			offset, 2, ENC_BIG_ENDIAN);
		offset += 2;
		proto_tree_add_item(tree, hf_rdm_pd_proxied_device_list_change, tvb,
			offset, 1, ENC_BIG_ENDIAN);
		offset += 1;
		break;
	}

	return offset;
}

static guint
dissect_rdm_pd_comms_status(tvbuff_t *tvb, guint offset, proto_tree *tree, guint8 cc, guint8 len _U_)
{
	switch(cc) {
	case RDM_CC_GET_COMMAND_RESPONSE:
		proto_tree_add_item(tree, hf_rdm_pd_comms_status_short_msg, tvb,
			offset, 2, ENC_BIG_ENDIAN);
		offset += 2;
		proto_tree_add_item(tree, hf_rdm_pd_comms_status_len_mismatch, tvb,
			offset, 2, ENC_BIG_ENDIAN);
		offset += 2;
		proto_tree_add_item(tree, hf_rdm_pd_comms_status_csum_fail, tvb,
			offset, 2, ENC_BIG_ENDIAN);
		offset += 2;
		break;
	}

	return offset;
}

static guint
dissect_rdm_pd_status_messages(tvbuff_t *tvb, guint offset, proto_tree *tree, guint8 cc, guint8 len)
{
	switch(cc) {
	case RDM_CC_GET_COMMAND:
		proto_tree_add_item(tree, hf_rdm_pd_status_messages_type, tvb,
			offset, 1, ENC_BIG_ENDIAN);
		offset += 1;
		break;

	case RDM_CC_GET_COMMAND_RESPONSE:
		while (len >= 9) {
			proto_tree_add_item(tree, hf_rdm_pd_status_messages_sub_device_id, tvb,
				offset, 2, ENC_BIG_ENDIAN);
			offset += 2;
			len    -= 2;
			proto_tree_add_item(tree, hf_rdm_pd_status_messages_type, tvb,
				offset, 1, ENC_BIG_ENDIAN);
			offset += 1;
			len    -= 1;
			proto_tree_add_item(tree, hf_rdm_pd_status_messages_id, tvb,
				offset, 2, ENC_BIG_ENDIAN);
			offset += 2;
			len    -= 2;
			proto_tree_add_item(tree, hf_rdm_pd_status_messages_data_value_1, tvb,
				offset, 2, ENC_BIG_ENDIAN);
			offset += 2;
			len    -= 2;
			proto_tree_add_item(tree, hf_rdm_pd_status_messages_data_value_2, tvb,
				offset, 2, ENC_BIG_ENDIAN);
			offset += 2;
			len    -= 2;
		}
		break;
	}

	return offset;
}

static guint
dissect_rdm_pd_status_id_description(tvbuff_t *tvb, guint offset, proto_tree *tree, guint8 cc, guint8 len)
{
	switch(cc) {
	case RDM_CC_GET_COMMAND:
		proto_tree_add_item(tree, hf_rdm_pd_status_id, tvb,
			offset, 2, ENC_BIG_ENDIAN);
		offset += 2;
		break;

	case RDM_CC_GET_COMMAND_RESPONSE:
		proto_tree_add_item(tree, hf_rdm_pd_status_id_description, tvb,
			offset, len, ENC_ASCII|ENC_NA);
		offset += len;
		break;
	}

	return offset;
}

static guint
dissect_rdm_pd_clear_status_id(tvbuff_t *tvb _U_, guint offset, proto_tree *tree _U_, guint8 cc _U_, guint8 len _U_)
{
	return offset;
}

static guint
dissect_rdm_pd_sub_device_status_report_threshold(tvbuff_t *tvb, guint offset, proto_tree *tree, guint8 cc, guint8 len _U_)
{
	switch(cc) {
	case RDM_CC_SET_COMMAND:
	case RDM_CC_GET_COMMAND_RESPONSE:
		proto_tree_add_item(tree, hf_rdm_pd_sub_device_status_report_threshold_status_type, tvb,
			offset, 1, ENC_BIG_ENDIAN);
		offset += 1;
		break;
	}

	return offset;
}

static guint
dissect_rdm_pd_supported_parameters(tvbuff_t *tvb, guint offset, proto_tree *tree, guint8 cc, guint8 len)
{
	switch(cc) {
	case RDM_CC_GET_COMMAND_RESPONSE:
		while (len >= 2) {
			proto_tree_add_item(tree, hf_rdm_pd_parameter_id, tvb,
				offset, 2, ENC_BIG_ENDIAN);
			offset += 2;
			len    -= 2;
		}
		break;
	}

	return offset;
}

static guint
dissect_rdm_pd_parameter_description(tvbuff_t *tvb, guint offset, proto_tree *tree, guint8 cc, guint8 len)
{
	switch(cc) {
	case RDM_CC_GET_COMMAND:
		proto_tree_add_item(tree, hf_rdm_pd_parameter_id, tvb,
			offset, 2, ENC_BIG_ENDIAN);
		offset += 2;
		break;

	case RDM_CC_GET_COMMAND_RESPONSE:
		proto_tree_add_item(tree, hf_rdm_pd_parameter_id, tvb,
			offset, 2, ENC_BIG_ENDIAN);
		offset += 2;
		proto_tree_add_item(tree, hf_rdm_pd_parameter_pdl_size, tvb,
			offset, 1, ENC_BIG_ENDIAN);
		offset += 1;
		proto_tree_add_item(tree, hf_rdm_pd_parameter_data_type, tvb,
			offset, 1, ENC_BIG_ENDIAN);
		offset += 1;
		proto_tree_add_item(tree, hf_rdm_pd_parameter_cmd_class, tvb,
			offset, 1, ENC_BIG_ENDIAN);
		offset += 1;
		proto_tree_add_item(tree, hf_rdm_pd_parameter_type, tvb,
			offset, 1, ENC_BIG_ENDIAN);
		offset += 1;
		proto_tree_add_item(tree, hf_rdm_pd_parameter_unit, tvb,
			offset, 1, ENC_BIG_ENDIAN);
		offset += 1;
		proto_tree_add_item(tree, hf_rdm_pd_parameter_prefix, tvb,
			offset, 1, ENC_BIG_ENDIAN);
		offset += 1;
		proto_tree_add_item(tree, hf_rdm_pd_parameter_min_value, tvb,
			offset, 4, ENC_BIG_ENDIAN);
		offset += 4;
		proto_tree_add_item(tree, hf_rdm_pd_parameter_max_value, tvb,
			offset, 4, ENC_BIG_ENDIAN);
		offset += 4;
		proto_tree_add_item(tree, hf_rdm_pd_parameter_default_value, tvb,
			offset, 4, ENC_BIG_ENDIAN);
		offset += 4;
		proto_tree_add_item(tree, hf_rdm_pd_parameter_description, tvb,
			offset, len - 0x14, ENC_ASCII|ENC_NA);
		offset += (len - 0x14);
		break;
	}

	return offset;
}

static guint
dissect_rdm_pd_product_detail_id_list(tvbuff_t *tvb, guint offset, proto_tree *tree, guint8 cc, guint8 len)
{
	switch(cc) {
	case RDM_CC_GET_COMMAND_RESPONSE:
		while (len >= 2) {
			proto_tree_add_item(tree, hf_rdm_pd_product_detail_id_list, tvb,
				offset, 2, ENC_BIG_ENDIAN);
			offset += 2;
			len    -= 2;
		}
		break;
	}

	return offset;
}

static guint
dissect_rdm_pd_factory_defaults(tvbuff_t *tvb, guint offset, proto_tree *tree, guint8 cc, guint8 len _U_)
{
	switch(cc) {
	case RDM_CC_GET_COMMAND_RESPONSE:
		proto_tree_add_item(tree, hf_rdm_pd_factory_defaults, tvb,
			offset, 1, ENC_BIG_ENDIAN);
		offset += 1;
		break;
	}

	return offset;
}

static guint
dissect_rdm_pd_language_capabilities(tvbuff_t *tvb, guint offset, proto_tree *tree, guint8 cc, guint8 len)
{
	switch(cc) {
	case RDM_CC_GET_COMMAND_RESPONSE:
		while (len >= 2) {
			proto_tree_add_item(tree, hf_rdm_pd_language_code, tvb,
				offset, 2, ENC_ASCII|ENC_NA);
			offset += 2;
			len    -= 2;
		}
		break;
	}

	return offset;
}

static guint
dissect_rdm_pd_language(tvbuff_t *tvb, guint offset, proto_tree *tree, guint8 cc, guint8 len _U_)
{
	switch(cc) {
	case RDM_CC_SET_COMMAND:
	case RDM_CC_GET_COMMAND_RESPONSE:
		proto_tree_add_item(tree, hf_rdm_pd_language_code, tvb,
			offset, 2, ENC_ASCII|ENC_NA);
		offset += 2;
		break;
	}

	return offset;
}

static guint
dissect_rdm_pd_software_version_label(tvbuff_t *tvb, guint offset, proto_tree *tree, guint8 cc, guint8 len)
{
	switch(cc) {
	case RDM_CC_GET_COMMAND_RESPONSE:
		proto_tree_add_item(tree, hf_rdm_pd_software_version_label, tvb,
			offset, len, ENC_ASCII|ENC_NA);
		offset += len;

		break;
	}

	return offset;
}

static guint
dissect_rdm_pd_boot_software_version_id(tvbuff_t *tvb, guint offset, proto_tree *tree, guint8 cc, guint8 len _U_)
{
	switch(cc) {
	case RDM_CC_GET_COMMAND_RESPONSE:
		proto_tree_add_item(tree, hf_rdm_pd_boot_software_version_id, tvb,
			offset, 4, ENC_BIG_ENDIAN);
		offset += 4;

		break;
	}

	return offset;
}

static guint
dissect_rdm_pd_boot_software_version_label(tvbuff_t *tvb, guint offset, proto_tree *tree, guint8 cc, guint8 len)
{
	switch(cc) {
	case RDM_CC_GET_COMMAND_RESPONSE:
		proto_tree_add_item(tree, hf_rdm_pd_boot_software_version_label, tvb,
			offset, len, ENC_ASCII|ENC_NA);
		offset += len;

		break;
	}

	return offset;
}

static guint
dissect_rdm_pd_dmx_personality(tvbuff_t *tvb, guint offset, proto_tree *tree, guint8 cc, guint8 len _U_)
{
	switch(cc) {
	case RDM_CC_SET_COMMAND:
		proto_tree_add_item(tree, hf_rdm_pd_dmx_pers_nr, tvb,
			offset, 1, ENC_BIG_ENDIAN);
		offset += 1;
		break;

	case RDM_CC_GET_COMMAND_RESPONSE:
		proto_tree_add_item(tree, hf_rdm_pd_dmx_pers_current, tvb,
			offset, 1, ENC_BIG_ENDIAN);
		offset += 1;
		proto_tree_add_item(tree, hf_rdm_pd_dmx_pers_count, tvb,
			offset, 1, ENC_BIG_ENDIAN);
		offset += 1;
		break;
	}

	return offset;
}

static guint
dissect_rdm_pd_dmx_personality_description(tvbuff_t *tvb, guint offset, proto_tree *tree, guint8 cc, guint8 len)
{
	switch(cc) {
	case RDM_CC_GET_COMMAND:
		proto_tree_add_item(tree, hf_rdm_pd_dmx_pers_requested, tvb,
			offset, 1, ENC_BIG_ENDIAN);
		offset += 1;
		break;

	case RDM_CC_GET_COMMAND_RESPONSE:
		proto_tree_add_item(tree, hf_rdm_pd_dmx_pers_requested, tvb,
			offset, 1, ENC_BIG_ENDIAN);
		offset += 1;
		proto_tree_add_item(tree, hf_rdm_pd_dmx_pers_slots, tvb,
			offset, 2, ENC_BIG_ENDIAN);
		offset += 2;
		proto_tree_add_item(tree, hf_rdm_pd_dmx_pers_text, tvb,
			offset, (len - 3), ENC_ASCII|ENC_NA);
		offset += (len - 3);
		break;
	}

	return offset;
}

static guint
dissect_rdm_pd_slot_info(tvbuff_t *tvb, guint offset, proto_tree *tree, guint8 cc, guint8 len)
{
	switch(cc) {
	case RDM_CC_GET_COMMAND_RESPONSE:
		while (len >= 5) {
			proto_tree_add_item(tree, hf_rdm_pd_slot_offset, tvb,
				offset, 2, ENC_BIG_ENDIAN);
			offset += 2;
			len    -= 2;
			proto_tree_add_item(tree, hf_rdm_pd_slot_type, tvb,
				offset, 1, ENC_BIG_ENDIAN);
			offset += 1;
			len    -= 1;
			proto_tree_add_item(tree, hf_rdm_pd_slot_label_id, tvb,
				offset, 2, ENC_BIG_ENDIAN);
			offset += 2;
			len    -= 2;
		}
		break;
	}

	return offset;
}

static guint
dissect_rdm_pd_slot_description(tvbuff_t *tvb, guint offset, proto_tree *tree, guint8 cc, guint8 len)
{
	switch(cc) {
	case RDM_CC_GET_COMMAND:
		proto_tree_add_item(tree, hf_rdm_pd_slot_nr, tvb,
			offset, 2, ENC_BIG_ENDIAN);
		offset += 2;
		break;

	case RDM_CC_GET_COMMAND_RESPONSE:
		proto_tree_add_item(tree, hf_rdm_pd_slot_nr, tvb,
			offset, 2, ENC_BIG_ENDIAN);
		offset += 2;
		proto_tree_add_item(tree, hf_rdm_pd_slot_description, tvb,
			offset, (len - 2), ENC_ASCII|ENC_NA);
		offset += (len - 2);
		break;
	}

	return offset;
}

static guint
dissect_rdm_pd_slot_value(tvbuff_t *tvb, guint offset, proto_tree *tree, guint8 cc, guint8 len)
{
	switch(cc) {
	case RDM_CC_GET_COMMAND_RESPONSE:
		while (len >= 3) {
			proto_tree_add_item(tree, hf_rdm_pd_slot_offset, tvb,
				offset, 2, ENC_BIG_ENDIAN);
			offset += 2;
			len    -= 2;
			proto_tree_add_item(tree, hf_rdm_pd_slot_value, tvb,
				offset, 1, ENC_BIG_ENDIAN);
			offset += 1;
			len    -= 1;
		}
		break;
	}

	return offset;
}

static guint
dissect_rdm_pd_record_sensors(tvbuff_t *tvb, guint offset, proto_tree *tree, guint8 cc, guint8 len)
{
	switch(cc) {
	case RDM_CC_GET_COMMAND:
		proto_tree_add_item(tree, hf_rdm_pd_sensor_nr, tvb,
			offset, 1, ENC_BIG_ENDIAN);
		offset += 1;
		break;

	case RDM_CC_GET_COMMAND_RESPONSE:
		proto_tree_add_item(tree, hf_rdm_pd_sensor_nr, tvb,
			offset, 1, ENC_BIG_ENDIAN);
		offset += 1;
		proto_tree_add_item(tree, hf_rdm_pd_sensor_type, tvb,
			offset, 1, ENC_BIG_ENDIAN);
		offset += 1;
		proto_tree_add_item(tree, hf_rdm_pd_sensor_unit, tvb,
			offset, 1, ENC_BIG_ENDIAN);
		offset += 1;
		proto_tree_add_item(tree, hf_rdm_pd_sensor_prefix, tvb,
			offset, 1, ENC_BIG_ENDIAN);
		offset += 1;
		proto_tree_add_item(tree, hf_rdm_pd_sensor_range_min_value, tvb,
			offset, 2, ENC_BIG_ENDIAN);
		offset += 2;
		proto_tree_add_item(tree, hf_rdm_pd_sensor_range_max_value, tvb,
			offset, 2, ENC_BIG_ENDIAN);
		offset += 2;
		proto_tree_add_item(tree, hf_rdm_pd_sensor_normal_min_value, tvb,
			offset, 2, ENC_BIG_ENDIAN);
		offset += 2;
		proto_tree_add_item(tree, hf_rdm_pd_sensor_normal_max_value, tvb,
			offset, 2, ENC_BIG_ENDIAN);
		offset += 2;
		proto_tree_add_item(tree, hf_rdm_pd_rec_value_support, tvb,
			offset, 1, ENC_BIG_ENDIAN);
		offset += 1;
		proto_tree_add_item(tree, hf_rdm_pd_sensor_description, tvb,
			offset, (len - 13), ENC_ASCII|ENC_NA);
		offset += (len - 13);

		break;
	}

	return offset;
}

static guint
dissect_rdm_pd_lamp_state(tvbuff_t *tvb, guint offset, proto_tree *tree, guint8 cc, guint8 len _U_)
{
	switch(cc) {
	case RDM_CC_SET_COMMAND:
	case RDM_CC_GET_COMMAND_RESPONSE:
		proto_tree_add_item(tree, hf_rdm_pd_lamp_state, tvb,
			offset, 1, ENC_BIG_ENDIAN);
		offset += 1;
		break;
	}

	return offset;
}

static guint
dissect_rdm_pd_lamp_on_mode(tvbuff_t *tvb, guint offset, proto_tree *tree, guint8 cc, guint8 len _U_)
{
	switch(cc) {
	case RDM_CC_SET_COMMAND:
	case RDM_CC_GET_COMMAND_RESPONSE:
		proto_tree_add_item(tree, hf_rdm_pd_lamp_on_mode, tvb,
			offset, 1, ENC_BIG_ENDIAN);
		offset += 1;
		break;
	}

	return offset;
}

static guint
dissect_rdm_pd_device_power_cycles(tvbuff_t *tvb, guint offset, proto_tree *tree, guint8 cc, guint8 len _U_)
{
	switch(cc) {
	case RDM_CC_SET_COMMAND:
	case RDM_CC_GET_COMMAND_RESPONSE:
		proto_tree_add_item(tree, hf_rdm_pd_device_power_cycles, tvb,
			offset, 4, ENC_BIG_ENDIAN);
		offset += 4;
		break;
	}

	return offset;
}

static guint
dissect_rdm_pd_display_invert(tvbuff_t *tvb, guint offset, proto_tree *tree, guint8 cc, guint8 len _U_)
{
	switch(cc) {
	case RDM_CC_SET_COMMAND:
	case RDM_CC_GET_COMMAND_RESPONSE:
		proto_tree_add_item(tree, hf_rdm_pd_display_invert, tvb,
			offset, 1, ENC_BIG_ENDIAN);
		offset += 1;
		break;
	}

	return offset;
}

static guint
dissect_rdm_pd_display_level(tvbuff_t *tvb, guint offset, proto_tree *tree, guint8 cc, guint8 len _U_)
{
	switch(cc) {
	case RDM_CC_SET_COMMAND:
	case RDM_CC_GET_COMMAND_RESPONSE:
		proto_tree_add_item(tree, hf_rdm_pd_display_level, tvb,
			offset, 1, ENC_BIG_ENDIAN);
		offset += 1;
		break;
	}

	return offset;
}

static guint
dissect_rdm_pd_pan_invert(tvbuff_t *tvb, guint offset, proto_tree *tree, guint8 cc, guint8 len _U_)
{
	switch(cc) {
	case RDM_CC_SET_COMMAND:
	case RDM_CC_GET_COMMAND_RESPONSE:
		proto_tree_add_item(tree, hf_rdm_pd_pan_invert, tvb,
			offset, 1, ENC_BIG_ENDIAN);
		offset += 1;
		break;
	}

	return offset;
}

static guint
dissect_rdm_pd_tilt_invert(tvbuff_t *tvb, guint offset, proto_tree *tree, guint8 cc, guint8 len _U_)
{
	switch(cc) {
	case RDM_CC_SET_COMMAND:
	case RDM_CC_GET_COMMAND_RESPONSE:
		proto_tree_add_item(tree, hf_rdm_pd_tilt_invert, tvb,
			offset, 1, ENC_BIG_ENDIAN);
		offset += 1;
		break;
	}

	return offset;
}

static guint
dissect_rdm_pd_pan_tilt_swap(tvbuff_t *tvb, guint offset, proto_tree *tree, guint8 cc, guint8 len _U_)
{
	switch(cc) {
	case RDM_CC_SET_COMMAND:
	case RDM_CC_GET_COMMAND_RESPONSE:
		proto_tree_add_item(tree, hf_rdm_pd_tilt_swap, tvb,
			offset, 1, ENC_BIG_ENDIAN);
		offset += 1;
		break;
	}

	return offset;
}

static guint
dissect_rdm_pd_real_time_clock(tvbuff_t *tvb, guint offset, proto_tree *tree, guint8 cc, guint8 len _U_)
{
	switch(cc) {
	case RDM_CC_SET_COMMAND:
	case RDM_CC_GET_COMMAND_RESPONSE:
		proto_tree_add_item(tree, hf_rdm_pd_real_time_clock_year, tvb,
			offset, 2, ENC_BIG_ENDIAN);
		offset += 2;
		proto_tree_add_item(tree, hf_rdm_pd_real_time_clock_month, tvb,
			offset, 1, ENC_BIG_ENDIAN);
		offset += 1;
		proto_tree_add_item(tree, hf_rdm_pd_real_time_clock_day, tvb,
			offset, 1, ENC_BIG_ENDIAN);
		offset += 1;
		proto_tree_add_item(tree, hf_rdm_pd_real_time_clock_hour, tvb,
			offset, 1, ENC_BIG_ENDIAN);
		offset += 1;
		proto_tree_add_item(tree, hf_rdm_pd_real_time_clock_minute, tvb,
			offset, 1, ENC_BIG_ENDIAN);
		offset += 1;
		proto_tree_add_item(tree, hf_rdm_pd_real_time_clock_second, tvb,
			offset, 1, ENC_BIG_ENDIAN);
		offset += 1;
		break;
	}

	return offset;
}

static guint
dissect_rdm_pd_identify_device(tvbuff_t *tvb, guint offset, proto_tree *tree, guint8 cc, guint8 len _U_)
{
	switch(cc) {
	case RDM_CC_SET_COMMAND:
		proto_tree_add_item(tree, hf_rdm_pd_identify_device, tvb,
			offset, 1, ENC_BIG_ENDIAN);
		offset += 1;
		break;

	case RDM_CC_GET_COMMAND_RESPONSE:
		proto_tree_add_item(tree, hf_rdm_pd_identify_device_state, tvb,
			offset, 1, ENC_BIG_ENDIAN);
		offset += 1;
		break;
	}

	return offset;
}

static guint
dissect_rdm_pd_reset_device(tvbuff_t *tvb, guint offset, proto_tree *tree, guint8 cc, guint8 len _U_)
{
	switch(cc) {
	case RDM_CC_SET_COMMAND:
		proto_tree_add_item(tree, hf_rdm_pd_reset_device, tvb,
			offset, 1, ENC_BIG_ENDIAN);
		offset += 1;
		break;
	}

	return offset;
}

static guint
dissect_rdm_pd_power_state(tvbuff_t *tvb, guint offset, proto_tree *tree, guint8 cc, guint8 len _U_)
{
	switch(cc) {
	case RDM_CC_SET_COMMAND:
	case RDM_CC_GET_COMMAND_RESPONSE:
		proto_tree_add_item(tree, hf_rdm_pd_power_state, tvb,
			offset, 1, ENC_BIG_ENDIAN);
		offset += 1;
		break;
	}

	return offset;
}

static guint
dissect_rdm_pd_perform_selftest(tvbuff_t *tvb, guint offset, proto_tree *tree, guint8 cc, guint8 len _U_)
{
	switch(cc) {
	case RDM_CC_SET_COMMAND:
		proto_tree_add_item(tree, hf_rdm_pd_selftest_nr, tvb,
			offset, 1, ENC_BIG_ENDIAN);
		offset += 1;
		break;

	case RDM_CC_GET_COMMAND_RESPONSE:
		proto_tree_add_item(tree, hf_rdm_pd_selftest_state, tvb,
			offset, 1, ENC_BIG_ENDIAN);
		offset += 1;
		break;
	}

	return offset;
}

static guint
dissect_rdm_pd_self_test_description(tvbuff_t *tvb, guint offset, proto_tree *tree, guint8 cc, guint8 len)
{
	switch(cc) {
	case RDM_CC_GET_COMMAND:
		proto_tree_add_item(tree, hf_rdm_pd_selftest_nr, tvb,
			offset, 1, ENC_BIG_ENDIAN);
		offset += 1;
		break;

	case RDM_CC_GET_COMMAND_RESPONSE:
		proto_tree_add_item(tree, hf_rdm_pd_selftest_nr, tvb,
			offset, 1, ENC_BIG_ENDIAN);
		offset += 1;
		proto_tree_add_item(tree, hf_rdm_pd_selftest_description, tvb,
			offset, (len - 1), ENC_ASCII|ENC_NA);
		offset += (len - 1);
		break;
	}

	return offset;
}

static guint
dissect_rdm_pd_capture_preset(tvbuff_t *tvb, guint offset, proto_tree *tree, guint8 cc, guint8 len _U_)
{
	switch(cc) {
	case RDM_CC_SET_COMMAND:
		proto_tree_add_item(tree, hf_rdm_pd_capture_preset_scene_nr, tvb,
			offset, 2, ENC_BIG_ENDIAN);
		offset += 2;
		proto_tree_add_item(tree, hf_rdm_pd_capture_preset_up_fade_time, tvb,
			offset, 2, ENC_BIG_ENDIAN);
		offset += 2;
		proto_tree_add_item(tree, hf_rdm_pd_capture_preset_down_fade_time, tvb,
			offset, 2, ENC_BIG_ENDIAN);
		offset += 2;
		proto_tree_add_item(tree, hf_rdm_pd_capture_preset_wait_time, tvb,
			offset, 2, ENC_BIG_ENDIAN);
		offset += 2;

		break;
	}

	return offset;
}

static guint
dissect_rdm_pd_preset_playback(tvbuff_t *tvb, guint offset, proto_tree *tree, guint8 cc, guint8 len _U_)
{
	switch(cc) {
	case RDM_CC_SET_COMMAND:
	case RDM_CC_GET_COMMAND_RESPONSE:
		proto_tree_add_item(tree, hf_rdm_pd_preset_playback_mode, tvb,
			offset, 2, ENC_BIG_ENDIAN);
		offset += 2;
		proto_tree_add_item(tree, hf_rdm_pd_preset_playback_level, tvb,
			offset, 1, ENC_BIG_ENDIAN);
		offset += 1;
		break;
	}

	return offset;
}

static guint
dissect_rdm_mdb_param_data(tvbuff_t *tvb, guint offset, proto_tree *tree, guint8 cc, guint16 param_id, guint8 pdl)
{
	switch(param_id) {
	case RDM_PARAM_ID_SENSOR_VALUE:
		offset = dissect_rdm_pd_sensor_value(tvb, offset, tree, cc, pdl);
		break;

	case RDM_PARAM_ID_QUEUED_MESSAGE:
		offset = dissect_rdm_pd_queued_message(tvb, offset, tree, cc, pdl);
		break;

	case RDM_PARAM_ID_DMX_START_ADDRESS:
		offset = dissect_rdm_pd_dmx_start_address(tvb, offset, tree, cc, pdl);
		break;

	case RDM_PARAM_ID_DEVICE_INFO:
		offset = dissect_rdm_pd_device_info(tvb, offset, tree, cc, pdl);
		break;

	case RDM_PARAM_ID_DEVICE_MODEL_DESCRIPTION:
		offset = dissect_rdm_pd_device_model_description(tvb, offset, tree, cc, pdl);
		break;

	case RDM_PARAM_ID_DEVICE_LABEL:
		offset = dissect_rdm_pd_device_label(tvb, offset, tree, cc, pdl);
		break;

	case RDM_PARAM_ID_DEVICE_HOURS:
		offset = dissect_rdm_pd_device_hours(tvb, offset, tree, cc, pdl);
		break;

	case RDM_PARAM_ID_LAMP_HOURS:
		offset = dissect_rdm_pd_lamp_hours(tvb, offset, tree, cc, pdl);
		break;

	case RDM_PARAM_ID_LAMP_STRIKES:
		offset = dissect_rdm_pd_lamp_strikes(tvb, offset, tree, cc, pdl);
		break;

	case RDM_PARAM_ID_SENSOR_DEFINITION:
		offset = dissect_rdm_pd_sensor_definition(tvb, offset, tree, cc, pdl);
		break;

	case RDM_PARAM_ID_MANUFACTURER_LABEL:
		offset = dissect_rdm_pd_manufacturer_label(tvb, offset, tree, cc, pdl);
		break;

	case RDM_PARAM_ID_DISC_UNIQUE_BRANCH:
		offset = dissect_rdm_pd_disc_unique_branch(tvb, offset, tree, cc, pdl);
		break;

	case RDM_PARAM_ID_DISC_MUTE:
		offset = dissect_rdm_pd_disc_mute(tvb, offset, tree, cc, pdl);
		break;

	case RDM_PARAM_ID_DISC_UN_MUTE:
		offset = dissect_rdm_pd_disc_un_mute(tvb, offset, tree, cc, pdl);
		break;

	case RDM_PARAM_ID_PROXIED_DEVICES:
		offset = dissect_rdm_pd_proxied_devices(tvb, offset, tree, cc, pdl);
		break;

	case RDM_PARAM_ID_PROXIED_DEVICE_COUNT:
		offset = dissect_rdm_pd_proxied_device_count(tvb, offset, tree, cc, pdl);
		break;

	case RDM_PARAM_ID_COMMS_STATUS:
		offset = dissect_rdm_pd_comms_status(tvb, offset, tree, cc, pdl);
		break;

	case RDM_PARAM_ID_STATUS_MESSAGES:
		offset = dissect_rdm_pd_status_messages(tvb, offset, tree, cc, pdl);
		break;

	case RDM_PARAM_ID_STATUS_ID_DESCRIPTION:
		offset = dissect_rdm_pd_status_id_description(tvb, offset, tree, cc, pdl);
		break;

	case RDM_PARAM_ID_CLEAR_STATUS_ID:
		offset = dissect_rdm_pd_clear_status_id(tvb, offset, tree, cc, pdl);
		break;

	case RDM_PARAM_ID_SUB_DEVICE_STATUS_REPORT_THRESHOLD:
		offset = dissect_rdm_pd_sub_device_status_report_threshold(tvb, offset, tree, cc, pdl);
		break;

	case RDM_PARAM_ID_SUPPORTED_PARAMETERS:
		offset = dissect_rdm_pd_supported_parameters(tvb, offset, tree, cc, pdl);
		break;

	case RDM_PARAM_ID_PARAMETER_DESCRIPTION:
		offset = dissect_rdm_pd_parameter_description(tvb, offset, tree, cc, pdl);
		break;

	case RDM_PARAM_ID_PRODUCT_DETAIL_ID_LIST:
		offset = dissect_rdm_pd_product_detail_id_list(tvb, offset, tree, cc, pdl);
		break;

	case RDM_PARAM_ID_FACTORY_DEFAULTS:
		offset = dissect_rdm_pd_factory_defaults(tvb, offset, tree, cc, pdl);
		break;

	case RDM_PARAM_ID_LANGUAGE_CAPABILITIES:
		offset = dissect_rdm_pd_language_capabilities(tvb, offset, tree, cc, pdl);
		break;

	case RDM_PARAM_ID_LANGUAGE:
		offset = dissect_rdm_pd_language(tvb, offset, tree, cc, pdl);
		break;

	case RDM_PARAM_ID_SOFTWARE_VERSION_LABEL:
		offset = dissect_rdm_pd_software_version_label(tvb, offset, tree, cc, pdl);
		break;

	case RDM_PARAM_ID_BOOT_SOFTWARE_VERSION_ID:
		offset = dissect_rdm_pd_boot_software_version_id(tvb, offset, tree, cc, pdl);
		break;

	case RDM_PARAM_ID_BOOT_SOFTWARE_VERSION_LABEL:
		offset = dissect_rdm_pd_boot_software_version_label(tvb, offset, tree, cc, pdl);
		break;

	case RDM_PARAM_ID_DMX_PERSONALITY:
		offset = dissect_rdm_pd_dmx_personality(tvb, offset, tree, cc, pdl);
		break;

	case RDM_PARAM_ID_DMX_PERSONALITY_DESCRIPTION:
		offset = dissect_rdm_pd_dmx_personality_description(tvb, offset, tree, cc, pdl);
		break;

	case RDM_PARAM_ID_SLOT_INFO:
		offset = dissect_rdm_pd_slot_info(tvb, offset, tree, cc, pdl);
		break;

	case RDM_PARAM_ID_SLOT_DESCRIPTION:
		offset = dissect_rdm_pd_slot_description(tvb, offset, tree, cc, pdl);
		break;

	case RDM_PARAM_ID_DEFAULT_SLOT_VALUE:
		offset = dissect_rdm_pd_slot_value(tvb, offset, tree, cc, pdl);
		break;

	case RDM_PARAM_ID_RECORD_SENSORS:
		offset = dissect_rdm_pd_record_sensors(tvb, offset, tree, cc, pdl);
		break;

	case RDM_PARAM_ID_LAMP_STATE:
		offset = dissect_rdm_pd_lamp_state(tvb, offset, tree, cc, pdl);
		break;

	case RDM_PARAM_ID_LAMP_ON_MODE:
		offset = dissect_rdm_pd_lamp_on_mode(tvb, offset, tree, cc, pdl);
		break;

	case RDM_PARAM_ID_DEVICE_POWER_CYCLES:
		offset = dissect_rdm_pd_device_power_cycles(tvb, offset, tree, cc, pdl);
		break;

	case RDM_PARAM_ID_DISPLAY_INVERT:
		offset = dissect_rdm_pd_display_invert(tvb, offset, tree, cc, pdl);
		break;

	case RDM_PARAM_ID_DISPLAY_LEVEL:
		offset = dissect_rdm_pd_display_level(tvb, offset, tree, cc, pdl);
		break;

	case RDM_PARAM_ID_PAN_INVERT:
		offset = dissect_rdm_pd_pan_invert(tvb, offset, tree, cc, pdl);
		break;

	case RDM_PARAM_ID_TILT_INVERT:
		offset = dissect_rdm_pd_tilt_invert(tvb, offset, tree, cc, pdl);
		break;

	case RDM_PARAM_ID_PAN_TILT_SWAP:
		offset = dissect_rdm_pd_pan_tilt_swap(tvb, offset, tree, cc, pdl);
		break;

	case RDM_PARAM_ID_REAL_TIME_CLOCK:
		offset = dissect_rdm_pd_real_time_clock(tvb, offset, tree, cc, pdl);
		break;

	case RDM_PARAM_ID_IDENTIFY_DEVICE:
		offset = dissect_rdm_pd_identify_device(tvb, offset, tree, cc, pdl);
		break;

	case RDM_PARAM_ID_RESET_DEVICE:
		offset = dissect_rdm_pd_reset_device(tvb, offset, tree, cc, pdl);
		break;

	case RDM_PARAM_ID_POWER_STATE:
		offset = dissect_rdm_pd_power_state(tvb, offset, tree, cc, pdl);
		break;

	case RDM_PARAM_ID_PERFORM_SELFTEST:
		offset = dissect_rdm_pd_perform_selftest(tvb, offset, tree, cc, pdl);
		break;

	case RDM_PARAM_ID_SELF_TEST_DESCRIPTION:
		offset = dissect_rdm_pd_self_test_description(tvb, offset, tree, cc, pdl);
		break;

	case RDM_PARAM_ID_CAPTURE_PRESET:
		offset = dissect_rdm_pd_capture_preset(tvb, offset, tree, cc, pdl);
		break;

	case RDM_PARAM_ID_PRESET_PLAYBACK:
		offset = dissect_rdm_pd_preset_playback(tvb, offset, tree, cc, pdl);
		break;

	default:
		proto_tree_add_item(tree, hf_rdm_parameter_data_raw, tvb,
			offset, pdl, ENC_NA);
		offset += pdl;
		break;
	}

	return offset;
}

static guint
dissect_rdm_pd_ack_overflow(tvbuff_t *tvb, guint offset, proto_tree *tree, guint8 cc, guint16 param_id _U_, guint8 pdl)
{
	if (pdl > 0) {
		int i;

		switch(cc) {
		case RDM_CC_GET_COMMAND_RESPONSE:
		case RDM_CC_SET_COMMAND_RESPONSE:
			for (i = 0; i < (pdl / 6); i++) {
				proto_tree_add_item(tree, hf_rdm_pd_ack_overflow_uid, tvb,
						offset, 6, ENC_NA);
				offset += 6;
			}
			break;
		}
	}

	return offset;
}

static guint
dissect_rdm_pd_ack_timer(tvbuff_t *tvb, guint offset, proto_tree *tree, guint8 cc, guint16 param_id _U_, guint8 pdl)
{
	if (pdl == 2) {
		switch(cc) {
		case RDM_CC_GET_COMMAND_RESPONSE:
		case RDM_CC_SET_COMMAND_RESPONSE:
			proto_tree_add_item(tree, hf_rdm_pd_ack_timer_estimated_response_time, tvb,
				offset, 2, ENC_BIG_ENDIAN);
			offset += 2;
			break;
		}
	}
	return offset;
}

static guint
dissect_rdm_pd_nack_reason(tvbuff_t *tvb, guint offset, proto_tree *tree, guint8 cc, guint16 param_id _U_, guint8 pdl _U_)
{
	if (pdl == 2) {
		switch(cc) {
		case RDM_CC_GET_COMMAND_RESPONSE:
		case RDM_CC_SET_COMMAND_RESPONSE:
			proto_tree_add_item(tree, hf_rdm_pd_nack_reason_code, tvb,
				offset, 2, ENC_BIG_ENDIAN);
			offset += 2;
			break;
		}
	}

	return offset;
}

static guint
dissect_rdm_mdb(tvbuff_t *tvb, guint offset, proto_tree *tree)
{
	guint8      cc;
	guint8      rt;
	guint16	    param_id;
	guint8	    parameter_data_length;
	proto_tree *hi,*si, *mdb_tree;

	rt = tvb_get_guint8(tvb, offset);
	cc = tvb_get_guint8(tvb, offset + 4);

	if ((cc & RDM_CC_COMMAND_RESPONSE_FLAG) == RDM_CC_COMMAND_RESPONSE_FLAG) {
		proto_tree_add_item(tree, hf_rdm_response_type, tvb,
				offset, 1, ENC_BIG_ENDIAN);
	        offset += 1;

	} else {
		proto_tree_add_item(tree, hf_rdm_port_id, tvb,
		                offset, 1, ENC_BIG_ENDIAN);
	        offset += 1;
	}

	proto_tree_add_item(tree, hf_rdm_message_count, tvb,
			offset, 1, ENC_BIG_ENDIAN);
	offset += 1;

	proto_tree_add_item(tree, hf_rdm_sub_device, tvb,
			offset, 2, ENC_BIG_ENDIAN);
	offset += 2;

	hi = proto_tree_add_item(tree, hf_rdm_mdb, tvb,
			offset, -1, ENC_NA);
	mdb_tree = proto_item_add_subtree(hi,ett_rdm);

	proto_tree_add_item(mdb_tree, hf_rdm_command_class, tvb,
			offset, 1, ENC_BIG_ENDIAN);
	offset += 1;

	param_id = tvb_get_ntohs(tvb, offset);
	proto_tree_add_item(mdb_tree, hf_rdm_parameter_id, tvb,
			offset, 2, ENC_BIG_ENDIAN);
	offset += 2;

	parameter_data_length = tvb_get_guint8(tvb, offset);
	proto_tree_add_item(mdb_tree, hf_rdm_parameter_data_length, tvb,
			offset, 1, ENC_BIG_ENDIAN);
	offset += 1;
	proto_item_set_len( mdb_tree,  parameter_data_length + 4);

	if (parameter_data_length > 0) {

		hi = proto_tree_add_item(mdb_tree, hf_rdm_parameter_data, tvb,
				offset, parameter_data_length, ENC_NA);
		si = proto_item_add_subtree(hi,ett_rdm);

		if ((cc & RDM_CC_COMMAND_RESPONSE_FLAG) == RDM_CC_COMMAND_RESPONSE_FLAG) {

			switch(rt) {
			case RDM_RESPONSE_TYPE_ACK:
				offset = dissect_rdm_mdb_param_data(tvb, offset, si, cc, param_id, parameter_data_length);
				break;
			case RDM_RESPONSE_TYPE_ACK_TIMER:
				offset = dissect_rdm_pd_ack_timer(tvb, offset, si, cc, param_id, parameter_data_length);
				break;
			case RDM_RESPONSE_TYPE_NACK_REASON:
				offset = dissect_rdm_pd_nack_reason(tvb, offset, si, cc, param_id, parameter_data_length);
				break;
			case RDM_RESPONSE_TYPE_ACK_OVERFLOW:
				offset = dissect_rdm_pd_ack_overflow(tvb, offset, si, cc, param_id, parameter_data_length);
				break;
			}

		} else {
			offset = dissect_rdm_mdb_param_data(tvb, offset, si, cc, param_id, parameter_data_length);
		}
	}

	return offset;
}

static int
dissect_rdm(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_)
{
	col_set_str(pinfo->cinfo, COL_PROTOCOL, "RDM");
	col_clear(pinfo->cinfo, COL_INFO);

	if (tree) {
		gint	    padding_size;
		guint16	    man_id;
		guint32	    dev_id;
		guint       message_length, offset = 0;

		proto_tree *ti = proto_tree_add_item(tree, proto_rdm, tvb,
				offset, -1, ENC_NA);
		proto_tree *rdm_tree = proto_item_add_subtree(ti, ett_rdm);

		proto_tree_add_item(rdm_tree, hf_rdm_sub_start_code, tvb,
				offset, 1, ENC_BIG_ENDIAN);
		offset += 1;

		message_length = tvb_get_guint8(tvb, offset);
		proto_tree_add_item(rdm_tree, hf_rdm_message_length, tvb,
				offset, 1, ENC_BIG_ENDIAN);
		offset += 1;

		man_id = tvb_get_ntohs(tvb, offset);
		dev_id = tvb_get_ntohl(tvb, offset + 2);
		proto_item_append_text(ti, ", Dst UID: %04x:%08x", man_id, dev_id);
		proto_tree_add_item(rdm_tree, hf_rdm_dest_uid, tvb,
				offset, 6, ENC_NA);
		offset += 6;


		man_id = tvb_get_ntohs(tvb, offset);
		dev_id = tvb_get_ntohl(tvb, offset + 2);
		proto_item_append_text(ti, ", Src UID: %04x:%08x", man_id, dev_id);
		proto_tree_add_item(rdm_tree, hf_rdm_src_uid, tvb,
				offset, 6, ENC_NA);
		offset += 6;

		proto_tree_add_item(rdm_tree, hf_rdm_transaction_number, tvb,
				offset, 1, ENC_BIG_ENDIAN);
		offset += 1;

		offset = dissect_rdm_mdb(tvb, offset, rdm_tree);

		padding_size = offset - (message_length - 1);
		if (padding_size > 0) {
			proto_tree_add_item(rdm_tree, hf_rdm_intron, tvb,
					offset, padding_size, ENC_NA);
			offset += padding_size;
		}

		proto_tree_add_checksum(rdm_tree, tvb, offset, hf_rdm_checksum, hf_rdm_checksum_status, &ei_rdm_checksum, pinfo, rdm_checksum(tvb, offset),
							ENC_BIG_ENDIAN, PROTO_CHECKSUM_VERIFY);
		offset += 2;

		if (offset < tvb_reported_length(tvb))
			proto_tree_add_item(rdm_tree, hf_rdm_trailer, tvb,
					offset, -1, ENC_NA);
	}
	return tvb_captured_length(tvb);
}

void
proto_register_rdm(void)
{
	static hf_register_info hf[] = {
		{ &hf_rdm_sub_start_code,
			{ "Sub-start code", "rdm.ssc",
				FT_UINT8, BASE_HEX, NULL, 0x0,
				NULL, HFILL }},

		{ &hf_rdm_message_length,
			{ "Message length", "rdm.len",
				FT_UINT8, BASE_DEC, NULL, 0x0,
				NULL, HFILL }},

		{ &hf_rdm_dest_uid,
			{ "Destination UID", "rdm.dst",
				FT_BYTES, BASE_NONE, NULL, 0x0,
				NULL, HFILL }},

		{ &hf_rdm_src_uid,
			{ "Source UID", "rdm.src",
				FT_BYTES, BASE_NONE, NULL, 0x0,
				NULL, HFILL }},

		{ &hf_rdm_transaction_number,
			{ "Transaction number", "rdm.tn",
				FT_UINT8, BASE_DEC, NULL, 0x0,
				NULL, HFILL }},

		{ &hf_rdm_port_id,
			{ "Port ID", "rdm.port_id",
				FT_UINT8, BASE_DEC, NULL, 0x0,
				NULL, HFILL }},

		{ &hf_rdm_response_type,
			{ "Response type", "rdm.rt",
				FT_UINT8, BASE_HEX, VALS(rdm_rt_vals), 0x0,
				NULL, HFILL }},

		{ &hf_rdm_message_count,
			{ "Message count", "rdm.mc",
				FT_UINT8, BASE_DEC, NULL, 0x0,
				NULL, HFILL }},

		{ &hf_rdm_sub_device,
			{ "Sub-device", "rdm.sd",
				FT_UINT16, BASE_DEC, NULL, 0x0,
				NULL, HFILL }},

		{ &hf_rdm_mdb,
			{ "Message Data Block", "rdm.mdb",
				FT_NONE, BASE_NONE, NULL, 0x0,
				NULL, HFILL }},

		{ &hf_rdm_command_class,
			{ "Command class", "rdm.cc",
				FT_UINT8, BASE_HEX, VALS(rdm_cc_vals), 0x0,
				NULL, HFILL }},

		{ &hf_rdm_parameter_id,
			{ "Parameter ID", "rdm.pid",
				FT_UINT16, BASE_HEX | BASE_EXT_STRING, &rdm_param_id_vals_ext, 0x0,
				NULL, HFILL }},

		{ &hf_rdm_parameter_data_length,
			{ "Parameter data length", "rdm.pdl",
				FT_UINT8, BASE_DEC, NULL, 0x0,
				NULL, HFILL }},

		{ &hf_rdm_parameter_data,
			{ "Parameter data", "rdm.pd",
				FT_NONE, BASE_NONE, NULL, 0x0,
				NULL, HFILL }},

		{ &hf_rdm_parameter_data_raw,
			{ "Raw Data", "rdm.pd.raw",
				FT_BYTES, BASE_NONE, NULL, 0x0,
				NULL, HFILL }},

		{ &hf_rdm_intron,
			{ "Intron", "rdm.intron",
				FT_BYTES, BASE_NONE, NULL, 0x0,
				NULL, HFILL }},

		{ &hf_rdm_checksum,
			{ "Checksum", "rdm.checksum",
				FT_UINT16, BASE_HEX, NULL, 0x0,
				NULL, HFILL }},

		{ &hf_rdm_checksum_status,
			{ "Checksum Status", "rdm.checksum.status",
				FT_UINT8, BASE_NONE, VALS(proto_checksum_vals), 0x0,
				NULL, HFILL }},

		{ &hf_rdm_trailer,
			{ "Trailer", "rdm.trailer",
				FT_BYTES, BASE_NONE, NULL, 0x0,
				NULL, HFILL }},

		{ &hf_rdm_pd_ack_overflow_uid,
			{ "UID", "rdm.pd.ack_overflow.uid",
				FT_BYTES, BASE_NONE, NULL, 0x0,
				NULL, HFILL }},

		{ &hf_rdm_pd_ack_timer_estimated_response_time,
			{ "Estimated Response Time", "rdm.pd.ack_timer.estimated_response_time",
				FT_INT16, BASE_DEC, NULL, 0x0,
				NULL, HFILL }},

		{ &hf_rdm_pd_nack_reason_code,
			{ "NACK Reason Code", "rdm.pd.nack_reason.code",
				FT_UINT16, BASE_HEX, VALS(rdm_nr_vals), 0x0,
				NULL, HFILL }},

		{ &hf_rdm_pd_queued_message_status,
			{ "Status", "rdm.pd.queued_message.status",
				FT_UINT8, BASE_HEX, VALS(rdm_status_vals), 0x0,
				NULL, HFILL }},

		{ &hf_rdm_pd_sensor_nr,
			{ "Sensor Nr.", "rdm.pd.sensor.nr",
				FT_UINT8, BASE_DEC, NULL, 0x0,
				NULL, HFILL }},

		{ &hf_rdm_pd_sensor_value_pres,
			{ "Sensor Present Value", "rdm.pd.sensor.value.present",
				FT_INT16, BASE_DEC, NULL, 0x0,
				NULL, HFILL }},

		{ &hf_rdm_pd_sensor_value_low,
			{ "Sensor Lowest Value", "rdm.pd.sensor.value.lowest",
				FT_INT16, BASE_DEC, NULL, 0x0,
				NULL, HFILL }},

		{ &hf_rdm_pd_sensor_value_high,
			{ "Sensor Highest Value", "rdm.pd.sensor.value.highest",
				FT_INT16, BASE_DEC, NULL, 0x0,
				NULL, HFILL }},

		{ &hf_rdm_pd_sensor_value_rec,
			{ "Sensor Recorded Value", "rdm.pd.sensor.value.recorded",
				FT_INT16, BASE_DEC, NULL, 0x0,
				NULL, HFILL }},

		{ &hf_rdm_pd_sensor_range_min_value,
			{ "Sensor Range Min. Value", "rdm.pd.sensor.range.min_value",
				FT_INT16, BASE_DEC, NULL, 0x0,
				NULL, HFILL }},

		{ &hf_rdm_pd_sensor_range_max_value,
			{ "Sensor Range Max. Value", "rdm.pd.sensor.range.max_value",
				FT_INT16, BASE_DEC, NULL, 0x0,
				NULL, HFILL }},

		{ &hf_rdm_pd_sensor_normal_min_value,
			{ "Sensor Normal Min. Value", "rdm.pd.sensor.normal.min_value",
				FT_INT16, BASE_DEC, NULL, 0x0,
				NULL, HFILL }},

		{ &hf_rdm_pd_sensor_normal_max_value,
			{ "Sensor Normal Max. Value", "rdm.pd.sensor.normal.max_value",
				FT_INT16, BASE_DEC, NULL, 0x0,
				NULL, HFILL }},

		{ &hf_rdm_pd_sensor_recorded_value_support,
			{ "Sensor Recorded Value Support", "rdm.pd.sensor.recorded_value_support",
				FT_UINT8, BASE_HEX, NULL, 0x0,
				NULL, HFILL }},

		{ &hf_rdm_pd_sensor_type,
			{ "Sensor Type", "rdm.pd.sensor_type",
				FT_UINT8, BASE_HEX | BASE_EXT_STRING, &rdm_sensor_type_vals_ext, 0x0,
				NULL, HFILL }},

		{ &hf_rdm_pd_sensor_unit,
			{ "Sensor Unit", "rdm.pd.sensor_unit",
				FT_UINT8, BASE_HEX | BASE_EXT_STRING, &rdm_unit_vals_ext, 0x0,
				NULL, HFILL }},

		{ &hf_rdm_pd_sensor_prefix,
			{ "Sensor Prefix", "rdm.pd.sensor_prefix",
				FT_UINT8, BASE_HEX | BASE_EXT_STRING, &rdm_prefix_vals_ext, 0x0,
				NULL, HFILL }},

		{ &hf_rdm_pd_sensor_description,
			{ "Sensor Description", "rdm.pd.sensor.description",
				FT_STRING, BASE_NONE, NULL, 0x0,
				NULL, HFILL }},

		{ &hf_rdm_pd_manu_label,
			{ "Manufacturer Label", "rdm.pd.manu_label",
				FT_STRING, BASE_NONE, NULL, 0x0,
				NULL, HFILL }},


		{ &hf_rdm_pd_device_label,
			{ "Device Label", "rdm.pd.device_label",
				FT_STRING, BASE_NONE, NULL, 0x0,
				NULL, HFILL }},

		{ &hf_rdm_pd_dmx_start_address,
			{ "DMX Start Address", "rdm.pd.dmx_start_address",
				FT_UINT16, BASE_DEC, NULL, 0x0,
				NULL, HFILL }},

		{ &hf_rdm_pd_device_hours,
			{ "Device Hours", "rdm.pd.device_hours",
				FT_UINT32, BASE_DEC, NULL, 0x0,
				NULL, HFILL }},

		{ &hf_rdm_pd_lamp_hours,
			{ "Lamp Hours", "rdm.pd.lamp_hours",
				FT_UINT32, BASE_DEC, NULL, 0x0,
				NULL, HFILL }},

		{ &hf_rdm_pd_lamp_strikes,
			{ "Lamp Strikes", "rdm.pd.lamp_strikes",
				FT_UINT32, BASE_DEC, NULL, 0x0,
				NULL, HFILL }},

		{ &hf_rdm_pd_proto_vers,
			{ "RDM Protocol Version", "rdm.pd.proto_vers",
				FT_UINT16, BASE_HEX, NULL, 0x0,
				NULL, HFILL }},

		{ &hf_rdm_pd_device_model_id,
			{ "Device Model ID", "rdm.pd.device_model_id",
				FT_UINT16, BASE_HEX, NULL, 0x0,
				NULL, HFILL }},

		{ &hf_rdm_pd_product_cat,
			{ "Product Category", "rdm.pd.product_cat",
				FT_UINT16, BASE_HEX | BASE_EXT_STRING, &rdm_product_cat_vals_ext, 0x0,
				NULL, HFILL }},

		{ &hf_rdm_pd_software_vers_id,
			{ "Software Version ID", "rdm.pd.software_version_id",
				FT_UINT32, BASE_HEX, NULL, 0x0,
				NULL, HFILL }},

		{ &hf_rdm_pd_dmx_footprint,
			{ "DMX Footprint", "rdm.pd.dmx_footprint",
				FT_UINT16, BASE_DEC, NULL, 0x0,
				NULL, HFILL }},

		{ &hf_rdm_pd_dmx_pers_current,
			{ "Current DMX Personality", "rdm.pd.dmx_pers_current",
				FT_UINT8, BASE_DEC, NULL, 0x0,
				NULL, HFILL }},

		{ &hf_rdm_pd_dmx_pers_total,
			{ "Total nr. DMX Personalities", "rdm.pd.dmx_pers_total",
				FT_UINT8, BASE_DEC, NULL, 0x0,
				NULL, HFILL }},

		{ &hf_rdm_pd_sub_device_count,
			{ "Sub-Device Count", "rdm.pd.sub_device_count",
				FT_UINT16, BASE_DEC, NULL, 0x0,
				NULL, HFILL }},

		{ &hf_rdm_pd_sensor_count,
			{ "Sensor Count", "rdm.pd.sensor_count",
				FT_UINT8, BASE_DEC, NULL, 0x0,
				NULL, HFILL }},

		{ &hf_rdm_pd_device_model_description,
			{ "Device Model Description", "rdm.pd.device_model_description",
				FT_STRING, BASE_NONE, NULL, 0x0,
				NULL, HFILL }},

		{ &hf_rdm_pd_disc_unique_branch_lb_uid,
			{ "Lower Bound UID", "rdm.pd.disc_unique_branch.lb_uid",
				FT_BYTES, BASE_NONE, NULL, 0x0,
				NULL, HFILL }},

		{ &hf_rdm_pd_disc_unique_branch_ub_uid,
			{ "Upper Bound UID", "rdm.pd.disc_unique_branch.ub_uid",
				FT_BYTES, BASE_NONE, NULL, 0x0,
				NULL, HFILL }},

		{ &hf_rdm_pd_disc_mute_control_field,
			{ "Control Field", "rdm.pd.disc_mute.control_field",
				FT_UINT8, BASE_HEX, NULL, 0x0,
				NULL, HFILL }},

		{ &hf_rdm_pd_disc_mute_binding_uid,
			{ "Binding UID", "rdm.pd.disc_mute.binding_uid",
				FT_BYTES, BASE_NONE, NULL, 0x0,
				NULL, HFILL }},

		{ &hf_rdm_pd_disc_unmute_control_field,
			{ "Control Field", "rdm.pd.disc_unmute.control_field",
				FT_UINT8, BASE_HEX, NULL, 0x0,
				NULL, HFILL }},

		{ &hf_rdm_pd_disc_unmute_binding_uid,
			{ "Binding UID", "rdm.pd.disc_unmute.binding_uid",
				FT_BYTES, BASE_NONE, NULL, 0x0,
				NULL, HFILL }},

		{ &hf_rdm_pd_proxied_devices_uid,
			{ "UID", "rdm.pd.proxied_devices.uid",
				FT_BYTES, BASE_NONE, NULL, 0x0,
				NULL, HFILL }},

		{ &hf_rdm_pd_proxied_device_count,
			{ "Device Count", "rdm.pd.device_count",
				FT_UINT16, BASE_DEC, NULL, 0x0,
				NULL, HFILL }},

		{ &hf_rdm_pd_proxied_device_list_change,
			{ "List Change", "rdm.pd.list_change",
				FT_UINT8, BASE_DEC, NULL, 0x0,
				NULL, HFILL }},

		{ &hf_rdm_pd_real_time_clock_year,
			{ "Year", "rdm.pd.real_time_clock.year",
				FT_UINT16, BASE_DEC, NULL, 0x0,
				NULL, HFILL }},

		{ &hf_rdm_pd_real_time_clock_month,
			{ "Month", "rdm.pd.real_time_clock.month",
				FT_UINT8, BASE_DEC, NULL, 0x0,
				NULL, HFILL }},

		{ &hf_rdm_pd_real_time_clock_day,
			{ "Day", "rdm.pd.real_time_clock.day",
				FT_UINT8, BASE_DEC, NULL, 0x0,
				NULL, HFILL }},

		{ &hf_rdm_pd_real_time_clock_hour,
			{ "Hour", "rdm.pd.real_time_clock.hour",
				FT_UINT8, BASE_DEC, NULL, 0x0,
				NULL, HFILL }},

		{ &hf_rdm_pd_real_time_clock_minute,
			{ "Minute", "rdm.pd.real_time_clock.minute",
				FT_UINT8, BASE_DEC, NULL, 0x0,
				NULL, HFILL }},

		{ &hf_rdm_pd_real_time_clock_second,
			{ "Second", "rdm.pd.real_time_clock.second",
				FT_UINT8, BASE_DEC, NULL, 0x0,
				NULL, HFILL }},

		{ &hf_rdm_pd_lamp_state,
			{ "Lamp State", "rdm.pd.lamp_state",
				FT_UINT8, BASE_HEX, NULL, 0x0,
				NULL, HFILL }},

		{ &hf_rdm_pd_lamp_on_mode,
			{ "Lamp On Mode", "rdm.pd.lamp_on_mode",
				FT_UINT8, BASE_HEX, NULL, 0x0,
				NULL, HFILL }},

		{ &hf_rdm_pd_device_power_cycles,
			{ "Device Power Cycles", "rdm.pd.device_power_cycles",
				FT_UINT32, BASE_DEC, NULL, 0x0,
				NULL, HFILL }},

		{ &hf_rdm_pd_display_invert,
			{ "Display Invert", "rdm.pd.display_invert",
				FT_UINT8, BASE_HEX, NULL, 0x0,
				NULL, HFILL }},

		{ &hf_rdm_pd_display_level,
			{ "Display Level", "rdm.pd.display_level",
				FT_UINT8, BASE_DEC, NULL, 0x0,
				NULL, HFILL }},

		{ &hf_rdm_pd_pan_invert,
			{ "Pan Invert", "rdm.pd.pan_invert",
				FT_UINT8, BASE_HEX, NULL, 0x0,
				NULL, HFILL }},

		{ &hf_rdm_pd_tilt_invert,
			{ "Tilt Invert", "rdm.pd.tilt_invert",
				FT_UINT8, BASE_HEX, NULL, 0x0,
				NULL, HFILL }},

		{ &hf_rdm_pd_tilt_swap,
			{ "Tilt Swap", "rdm.pd.tilt_swap",
				FT_UINT8, BASE_HEX, NULL, 0x0,
				NULL, HFILL }},

		{ &hf_rdm_pd_selftest_nr,
			{ "Selftest Nr.", "rdm.pd.selftest.nr",
				FT_UINT8, BASE_DEC, NULL, 0x0,
				NULL, HFILL }},

		{ &hf_rdm_pd_selftest_state,
			{ "Selftest State", "rdm.pd.selftest.state",
				FT_UINT8, BASE_HEX, NULL, 0x0,
				NULL, HFILL }},

		{ &hf_rdm_pd_selftest_description,
			{ "Selftest Description", "rdm.pd.selftest.description",
				FT_STRING, BASE_NONE, NULL, 0x0,
				NULL, HFILL }},

		{ &hf_rdm_pd_language_code,
			{ "Language Code", "rdm.pd.language_code",
				FT_STRING, BASE_NONE, NULL, 0x0,
				NULL, HFILL }},

		{ &hf_rdm_pd_identify_device,
			{ "Identify Device", "rdm.pd.identify_device",
				FT_UINT8, BASE_HEX, NULL, 0x0,
				NULL, HFILL }},

		{ &hf_rdm_pd_identify_device_state,
			{ "Identify Device State", "rdm.pd.identify_device.state",
				FT_UINT8, BASE_HEX, NULL, 0x0,
				NULL, HFILL }},

		{ &hf_rdm_pd_reset_device,
			{ "Reset Device", "rdm.pd.reset_device",
				FT_UINT8, BASE_HEX, NULL, 0x0,
				NULL, HFILL }},

		{ &hf_rdm_pd_power_state,
			{ "Power State", "rdm.pd.power_state",
				FT_UINT8, BASE_HEX, NULL, 0x0,
				NULL, HFILL }},

		{ &hf_rdm_pd_capture_preset_scene_nr,
			{ "Scene Nr.", "rdm.pd.capture_preset.scene_nr",
				FT_UINT16, BASE_DEC, NULL, 0x0,
				NULL, HFILL }},

		{ &hf_rdm_pd_capture_preset_up_fade_time,
			{ "Up Fade Time", "rdm.pd.capture_preset.up_fade_time",
				FT_UINT16, BASE_DEC, NULL, 0x0,
				NULL, HFILL }},

		{ &hf_rdm_pd_capture_preset_down_fade_time,
			{ "Down Fade Time", "rdm.pd.capture_preset.down_fade_time",
				FT_UINT16, BASE_DEC, NULL, 0x0,
				NULL, HFILL }},

		{ &hf_rdm_pd_capture_preset_wait_time,
			{ "Wait Time", "rdm.pd.capture_preset.wait_time",
				FT_UINT16, BASE_DEC, NULL, 0x0,
				NULL, HFILL }},

		{ &hf_rdm_pd_preset_playback_mode,
			{ "Mode", "rdm.pd.preset_playback.mode",
				FT_UINT16, BASE_DEC, NULL, 0x0,
				NULL, HFILL }},

		{ &hf_rdm_pd_preset_playback_level,
			{ "Level", "rdm.pd.preset_playback.level",
				FT_UINT8, BASE_DEC, NULL, 0x0,
				NULL, HFILL }},

		{ &hf_rdm_pd_parameter_id,
			{ "ID", "rdm.pd.parameter.id",
				FT_UINT16, BASE_HEX, VALS(rdm_param_id_vals), 0x0,
				NULL, HFILL }},

		{ &hf_rdm_pd_parameter_pdl_size,
			{ "PDL Size", "rdm.pd.parameter.pdl_size",
				FT_UINT8, BASE_DEC, NULL, 0x0,
				NULL, HFILL }},

		{ &hf_rdm_pd_parameter_data_type,
			{ "Data Type", "rdm.pd.parameter.data_type",
				FT_UINT8, BASE_DEC, NULL, 0x0,
				NULL, HFILL }},

		{ &hf_rdm_pd_parameter_cmd_class,
			{ "Command Class", "rdm.pd.parameter.cmd_class",
				FT_UINT8, BASE_DEC, NULL, 0x0,
				NULL, HFILL }},

		{ &hf_rdm_pd_parameter_type,
			{ "Type", "rdm.pd.parameter.type",
				FT_UINT8, BASE_DEC, NULL, 0x0,
				NULL, HFILL }},

		{ &hf_rdm_pd_parameter_unit,
			{ "Unit", "rdm.pd.parameter.unit",
				FT_UINT8, BASE_DEC, NULL, 0x0,
				NULL, HFILL }},

		{ &hf_rdm_pd_parameter_prefix,
			{ "Prefix", "rdm.pd.parameter.prefix",
				FT_UINT8, BASE_DEC, NULL, 0x0,
				NULL, HFILL }},

		{ &hf_rdm_pd_parameter_min_value,
			{ "Min. Value", "rdm.pd.parameter.min_value",
				FT_UINT32, BASE_DEC, NULL, 0x0,
				NULL, HFILL }},

		{ &hf_rdm_pd_parameter_max_value,
			{ "Max. Value", "rdm.pd.parameter.max_value",
				FT_UINT32, BASE_DEC, NULL, 0x0,
				NULL, HFILL }},

		{ &hf_rdm_pd_parameter_default_value,
			{ "Default Value", "rdm.pd.parameter.default_value",
				FT_UINT32, BASE_DEC, NULL, 0x0,
				NULL, HFILL }},

		{ &hf_rdm_pd_parameter_description,
			{ "Description", "rdm.pd.parameter.description",
				FT_STRING, BASE_NONE, NULL, 0x0,
				NULL, HFILL }},

		{ &hf_rdm_pd_software_version_label,
			{ "Version Label", "rdm.pd.software_version.label",
				FT_STRING, BASE_NONE, NULL, 0x0,
				NULL, HFILL }},

		{ &hf_rdm_pd_boot_software_version_id,
			{ "Version ID", "rdm.pd.boot_software_version.id",
				FT_UINT32, BASE_HEX, NULL, 0x0,
				NULL, HFILL }},

		{ &hf_rdm_pd_boot_software_version_label,
			{ "Version Label", "rdm.pd.boot_software_version.label",
				FT_STRING, BASE_NONE, NULL, 0x0,
				NULL, HFILL }},

		{ &hf_rdm_pd_comms_status_short_msg,
			{ "Short Msg", "rdm.pd.comms_status.short_msg",
				FT_UINT16, BASE_DEC, NULL, 0x0,
				NULL, HFILL }},

		{ &hf_rdm_pd_comms_status_len_mismatch,
			{ "Len Mismatch", "rdm.pd.comms_status.len_mismatch",
				FT_UINT16, BASE_DEC, NULL, 0x0,
				NULL, HFILL }},

		{ &hf_rdm_pd_comms_status_csum_fail,
			{ "Checksum Fail", "rdm.pd.comms_status.csum_fail",
				FT_UINT16, BASE_DEC, NULL, 0x0,
				NULL, HFILL }},

		{ &hf_rdm_pd_status_messages_type,
			{ "Type", "rdm.pd.status_messages.type",
				FT_UINT8, BASE_HEX, NULL, 0x0,
				NULL, HFILL }},

		{ &hf_rdm_pd_status_messages_sub_device_id,
			{ "Sub. Device ID", "rdm.pd.status_messages.sub_devices_id",
				FT_UINT16, BASE_HEX, NULL, 0x0,
				NULL, HFILL }},

		{ &hf_rdm_pd_status_messages_id,
			{ "ID", "rdm.pd.status_messages.id",
				FT_UINT16, BASE_HEX, NULL, 0x0,
				NULL, HFILL }},

		{ &hf_rdm_pd_status_messages_data_value_1,
			{ "Data Value 1", "rdm.pd.status_messages.data_value_1",
				FT_UINT16, BASE_HEX, NULL, 0x0,
				NULL, HFILL }},

		{ &hf_rdm_pd_status_messages_data_value_2,
			{ "Data Value 2", "rdm.pd.status_messages.data_value_2",
				FT_UINT16, BASE_HEX, NULL, 0x0,
				NULL, HFILL }},

		{ &hf_rdm_pd_status_id,
			{ "ID", "rdm.pd.status_id",
				FT_UINT16, BASE_DEC, NULL, 0x0,
				NULL, HFILL }},

		{ &hf_rdm_pd_status_id_description,
			{ "Description", "rdm.pd.status_id.description",
				FT_STRING, BASE_NONE, NULL, 0x0,
				NULL, HFILL }},

		{ &hf_rdm_pd_sub_device_status_report_threshold_status_type,
			{ "Status Type", "rdm.pd.sub_device_status_report_threshold.status_type",
				FT_UINT8, BASE_HEX, NULL, 0x0,
				NULL, HFILL }},

		{ &hf_rdm_pd_product_detail_id_list,
			{ "Sensor Count", "rdm.pd.product_detail_id_list",
				FT_UINT16, BASE_HEX, NULL, 0x0,
				NULL, HFILL }},

		{ &hf_rdm_pd_factory_defaults,
			{ "Factory Defaults", "rdm.pd.factory_defaults",
				FT_UINT8, BASE_DEC, NULL, 0x0,
				NULL, HFILL }},

		{ &hf_rdm_pd_dmx_pers_nr,
			{ "DMX Pers. Nr.", "rdm.pd.dmx_pers.nr",
				FT_UINT8, BASE_DEC, NULL, 0x0,
				NULL, HFILL }},

		{ &hf_rdm_pd_dmx_pers_count,
			{ "DMX Pers. Count", "rdm.pd.dmx_pers.count",
				FT_UINT8, BASE_DEC, NULL, 0x0,
				NULL, HFILL }},

		{ &hf_rdm_pd_dmx_pers_requested,
			{ "DMX Pers. Requested", "rdm.pd.dmx_pers.requested",
				FT_UINT8, BASE_DEC, NULL, 0x0,
				NULL, HFILL }},

		{ &hf_rdm_pd_dmx_pers_slots,
			{ "DMX Pers. Slots", "rdm.pd.dmx_pers.slots",
				FT_UINT16, BASE_DEC, NULL, 0x0,
				NULL, HFILL }},

		{ &hf_rdm_pd_dmx_pers_text,
			{ "DMX Pers. Text", "rdm.pd.dmx_pers.text",
				FT_STRING, BASE_NONE, NULL, 0x0,
				NULL, HFILL }},

		{ &hf_rdm_pd_slot_offset,
			{ "Slot Offset", "rdm.pd.slot_offset",
				FT_UINT16, BASE_DEC, NULL, 0x0,
				NULL, HFILL }},

		{ &hf_rdm_pd_slot_type,
			{ "Slot Type", "rdm.pd.slot_type",
				FT_UINT8, BASE_DEC, NULL, 0x0,
				NULL, HFILL }},

		{ &hf_rdm_pd_slot_label_id,
			{ "Slot Label ID", "rdm.pd.slot_label_id",
				FT_UINT16, BASE_HEX, NULL, 0x0,
				NULL, HFILL }},

		{ &hf_rdm_pd_slot_nr,
			{ "Slot Nr.", "rdm.pd.slot_nr",
				FT_UINT16, BASE_DEC, NULL, 0x0,
				NULL, HFILL }},

		{ &hf_rdm_pd_slot_description,
			{ "Slot Description", "rdm.pd.slot_description",
				FT_STRING, BASE_NONE, NULL, 0x0,
				NULL, HFILL }},

		{ &hf_rdm_pd_slot_value,
			{ "Slot Value", "rdm.pd.slot_value",
				FT_UINT8, BASE_DEC, NULL, 0x0,
				NULL, HFILL }},

		{ &hf_rdm_pd_rec_value_support,
			{ "Rec. Value Support", "rdm.pd.rec_value_support",
				FT_UINT8, BASE_HEX, NULL, 0x0,
				NULL, HFILL }}
	};

	static gint *ett[] = {
		&ett_rdm
	};

	static ei_register_info ei[] = {
		{ &ei_rdm_checksum, { "rdm.bad_checksum", PI_CHECKSUM, PI_ERROR, "Bad checksum", EXPFILL }},
	};

	expert_module_t* expert_rdm;

	proto_rdm = proto_register_protocol("Remote Device Management", "RDM", "rdm");
	proto_register_field_array(proto_rdm, hf, array_length(hf));
	proto_register_subtree_array(ett, array_length(ett));
	register_dissector("rdm", dissect_rdm, proto_rdm);
	expert_rdm = expert_register_protocol(proto_rdm);
	expert_register_field_array(expert_rdm, ei, array_length(ei));
}

void
proto_reg_handoff_rdm(void) {
	dissector_add_uint("dmx", 0xCC, create_dissector_handle(dissect_rdm, proto_rdm));
}

/*
 * Editor modelines  -  http://www.wireshark.org/tools/modelines.html
 *
 * Local variables:
 * c-basic-offset: 8
 * tab-width: 8
 * indent-tabs-mode: t
 * End:
 *
 * vi: set shiftwidth=8 tabstop=8 noexpandtab:
 * :indentSize=8:tabSize=8:noTabs=false:
 */
