diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-10 20:34:10 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-10 20:34:10 +0000 |
commit | e4ba6dbc3f1e76890b22773807ea37fe8fa2b1bc (patch) | |
tree | 68cb5ef9081156392f1dd62a00c6ccc1451b93df /epan/dissectors/packet-z21.c | |
parent | Initial commit. (diff) | |
download | wireshark-e4ba6dbc3f1e76890b22773807ea37fe8fa2b1bc.tar.xz wireshark-e4ba6dbc3f1e76890b22773807ea37fe8fa2b1bc.zip |
Adding upstream version 4.2.2.upstream/4.2.2
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'epan/dissectors/packet-z21.c')
-rw-r--r-- | epan/dissectors/packet-z21.c | 2218 |
1 files changed, 2218 insertions, 0 deletions
diff --git a/epan/dissectors/packet-z21.c b/epan/dissectors/packet-z21.c new file mode 100644 index 00000000..2be95db7 --- /dev/null +++ b/epan/dissectors/packet-z21.c @@ -0,0 +1,2218 @@ +/* packet-z21.c + * Routines for Z21 LAN protocol dissection + * Copyright 2023, Markku Leiniö <markku.leinio@gmail.com> + * + * Wireshark - Network traffic analyzer + * By Gerald Combs <gerald@wireshark.org> + * Copyright 1998 Gerald Combs + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +/* + * Z21 LAN protocol specification can be found at: + * https://www.z21.eu/en/downloads/manuals + */ + +#include "config.h" +#define WS_LOG_DOMAIN "Z21" + +#include <epan/packet.h> +#include <epan/expert.h> +#include <epan/prefs.h> +#include "packet-udp.h" + +void proto_register_z21(void); +void proto_reg_handoff_z21(void); + +/* Initialize the protocol and registered fields */ +static int proto_z21 = -1; +static int hf_z21_datalen = -1; +static int hf_z21_command = -1; +static int hf_z21_x_bus = -1; +static int hf_z21_serial_number = -1; +static int hf_z21_checksum = -1; +static int hf_z21_main_current = -1; +static int hf_z21_prog_current = -1; +static int hf_z21_filtered_main_current = -1; +static int hf_z21_temperature = -1; +static int hf_z21_supply_voltage = -1; +static int hf_z21_track_voltage = -1; +static int hf_z21_central_state = -1; +static int hf_z21_central_state_ex = -1; +static int hf_z21_systemstate_reserved = -1; +static int hf_z21_capabilities = -1; +static int hf_z21_status = -1; +static int hf_z21_loco_address = -1; +static int hf_z21_loco_direction_and_speed = -1; +static int hf_z21_loco_direction = -1; +static int hf_z21_loco_speed = -1; +static int hf_z21_loco_info_mm = -1; +static int hf_z21_loco_info_busy = -1; +static int hf_z21_loco_info_speed_steps = -1; +static int hf_z21_loco_info_direction = -1; +static int hf_z21_loco_info_speed = -1; +static int hf_z21_loco_info_double_traction = -1; +static int hf_z21_loco_info_smartsearch = -1; +static int hf_z21_loco_info_f0 = -1; +static int hf_z21_loco_info_f1 = -1; +static int hf_z21_loco_info_f2 = -1; +static int hf_z21_loco_info_f3 = -1; +static int hf_z21_loco_info_f4 = -1; +static int hf_z21_loco_info_f5 = -1; +static int hf_z21_loco_info_f6 = -1; +static int hf_z21_loco_info_f7 = -1; +static int hf_z21_loco_info_f8 = -1; +static int hf_z21_loco_info_f9 = -1; +static int hf_z21_loco_info_f10 = -1; +static int hf_z21_loco_info_f11 = -1; +static int hf_z21_loco_info_f12 = -1; +static int hf_z21_loco_info_f13 = -1; +static int hf_z21_loco_info_f14 = -1; +static int hf_z21_loco_info_f15 = -1; +static int hf_z21_loco_info_f16 = -1; +static int hf_z21_loco_info_f17 = -1; +static int hf_z21_loco_info_f18 = -1; +static int hf_z21_loco_info_f19 = -1; +static int hf_z21_loco_info_f20 = -1; +static int hf_z21_loco_info_f21 = -1; +static int hf_z21_loco_info_f22 = -1; +static int hf_z21_loco_info_f23 = -1; +static int hf_z21_loco_info_f24 = -1; +static int hf_z21_loco_info_f25 = -1; +static int hf_z21_loco_info_f26 = -1; +static int hf_z21_loco_info_f27 = -1; +static int hf_z21_loco_info_f28 = -1; +static int hf_z21_loco_info_f29 = -1; +static int hf_z21_loco_info_f30 = -1; +static int hf_z21_loco_info_f31 = -1; +static int hf_z21_loco_info_extensions = -1; +static int hf_z21_loco_func_switch_type = -1; +static int hf_z21_loco_func_index = -1; +static int hf_z21_speed_steps = -1; +static int hf_z21_firmware_version = -1; +static int hf_z21_state_emergency_stop = -1; +static int hf_z21_state_track_voltage_off = -1; +static int hf_z21_state_short_circuit = -1; +static int hf_z21_state_programming_mode = -1; +static int hf_z21_state_high_temperature = -1; +static int hf_z21_state_power_lost = -1; +static int hf_z21_state_short_circuit_external = -1; +static int hf_z21_state_short_circuit_internal = -1; +static int hf_z21_state_rcn_213 = -1; +static int hf_z21_capability_dcc = -1; +static int hf_z21_capability_mm = -1; +static int hf_z21_capability_reserved = -1; +static int hf_z21_capability_railcom = -1; +static int hf_z21_capability_loco_cmds = -1; +static int hf_z21_capability_accessory_cmds = -1; +static int hf_z21_capability_detector_cmds = -1; +static int hf_z21_capability_needs_unlock_code = -1; +static int hf_z21_function_address = -1; +static int hf_z21_turnout_state = -1; +static int hf_z21_turnout_activate_bit = -1; +static int hf_z21_turnout_output_bit = -1; +static int hf_z21_turnout_queue_bit = -1; +static int hf_z21_accessory_address = -1; +static int hf_z21_accessory_state = -1; +static int hf_z21_accessory_status = -1; +static int hf_z21_cv_address = -1; +static int hf_z21_cv_value = -1; +static int hf_z21_register = -1; +static int hf_z21_register_value = -1; +static int hf_z21_pom_operation = -1; +static int hf_z21_cv_bit_position = -1; +static int hf_z21_cv_bit_value = -1; +static int hf_z21_rmbus_group = -1; +static int hf_z21_rmbus_feedbacks = -1; +static int hf_z21_rmbus_address = -1; +static int hf_z21_railcom_receive_counter = -1; +static int hf_z21_railcom_error_counter = -1; +static int hf_z21_railcom_reserved1 = -1; +static int hf_z21_railcom_options = -1; +static int hf_z21_railcom_speed = -1; +static int hf_z21_railcom_qos = -1; +static int hf_z21_railcom_reserved2 = -1; +static int hf_z21_railcom_type = -1; +static int hf_z21_loconet_message = -1; +static int hf_z21_loconet_result = -1; +static int hf_z21_loconet_type = -1; +static int hf_z21_loconet_report_address = -1; +static int hf_z21_loconet_feedback_address = -1; +static int hf_z21_loconet_info = -1; +static int hf_z21_can_type = -1; +static int hf_z21_can_network_id = -1; +static int hf_z21_can_module_address = -1; +static int hf_z21_can_port = -1; +static int hf_z21_can_value1 = -1; +static int hf_z21_can_value2 = -1; +static int hf_z21_can_booster_name = -1; +static int hf_z21_can_booster_output_port = -1; +static int hf_z21_can_booster_state = -1; +static int hf_z21_can_booster_state_bg_active = -1; +static int hf_z21_can_booster_state_short_circuit = -1; +static int hf_z21_can_booster_state_track_voltage_off = -1; +static int hf_z21_can_booster_state_railcom_active = -1; +static int hf_z21_can_booster_state_output_disabled = -1; +static int hf_z21_can_booster_vcc = -1; +static int hf_z21_can_booster_current = -1; +static int hf_z21_can_booster_power = -1; +static int hf_z21_zlink_message_type = -1; +static int hf_z21_zlink_hwid = -1; +static int hf_z21_zlink_fw_major = -1; +static int hf_z21_zlink_fw_minor = -1; +static int hf_z21_zlink_fw_build = -1; +static int hf_z21_zlink_mac = -1; +static int hf_z21_zlink_name = -1; +static int hf_z21_zlink_reserved = -1; +static int hf_z21_booster_name = -1; +static int hf_z21_booster_port = -1; +static int hf_z21_booster_port_state = -1; +static int hf_z21_booster_state_data = -1; +static int hf_z21_decoder_name = -1; +static int hf_z21_decoder_state_data = -1; +static int hf_z21_data = -1; + +static dissector_handle_t z21_handle; + +#define Z21_UDP_PORTS "21105,21106" +static range_t *udp_port_range; + +/* Initialize the subtree pointers */ +static int ett_z21 = -1; + +/* Initialize expert fields */ +static expert_field ei_z21_invalid_checksum = EI_INIT; + +#define Z21_MIN_LENGTH 4 + +/* All commands are here defined as big-endian even though the + * specifications are all little-endian. That's fine as we are + * not comparing the values numerically, just matching them + * in the packets. */ +#define Z21_LAN_GET_SERIAL_NUMBER 0x1000 +#define Z21_LAN_LOGOFF 0x3000 +#define Z21_X_BUS 0x4000 +#define Z21_LAN_RMBUS_DATACHANGED 0x8000 +#define Z21_LAN_RMBUS_GETDATA 0x8100 +#define Z21_LAN_RMBUS_PROGRAMMODULE 0x8200 +#define Z21_LAN_SYSTEMSTATE_DATACHANGED 0x8400 +#define Z21_LAN_RAILCOM_DATACHANGED 0x8800 +#define Z21_LAN_RAILCOM_GETDATA 0x8900 +#define Z21_LAN_LOCONET_Z21_RX 0xA000 +#define Z21_LAN_LOCONET_Z21_TX 0xA100 +#define Z21_LAN_LOCONET_FROM_LAN 0xA200 +#define Z21_LAN_LOCONET_DISPATCH_ADDR 0xA300 +#define Z21_LAN_LOCONET_DETECTOR 0xA400 +#define Z21_LAN_BOOSTER_SET_POWER 0xB200 +#define Z21_LAN_BOOSTER_GET_DESCRIPTION 0xB800 +#define Z21_LAN_BOOSTER_SET_DESCRIPTION 0xB900 +#define Z21_LAN_BOOSTER_SYSTEMSTATE_DATACHANGED 0xBA00 +#define Z21_LAN_BOOSTER_SYSTEMSTATE_GETDATA 0xBB00 +#define Z21_LAN_CAN_DETECTOR 0xC400 +#define Z21_LAN_CAN_DEVICE_GET_DESCRIPTION 0xC800 +#define Z21_LAN_CAN_DEVICE_SET_DESCRIPTION 0xC900 +#define Z21_LAN_CAN_BOOSTER_SYSTEMSTATE_CHGD 0xCA00 +#define Z21_LAN_CAN_BOOSTER_SET_TRACKPOWER 0xCB00 +#define Z21_LAN_FAST_CLOCK_CONTROL 0xCC00 +#define Z21_LAN_FAST_CLOCK_DATA 0xCD00 +#define Z21_LAN_FAST_CLOCK_SETTINGS_GET 0xCE00 +#define Z21_LAN_FAST_CLOCK_SETTINGS_SET 0xCF00 +#define Z21_LAN_DECODER_GET_DESCRIPTION 0xD800 +#define Z21_LAN_DECODER_SET_DESCRIPTION 0xD900 +#define Z21_LAN_DECODER_SYSTEMSTATE_DATACHANGED 0xDA00 +#define Z21_LAN_DECODER_SYSTEMSTATE_GETDATA 0xDB00 +#define Z21_LAN_ZLINK_GET_HWINFO 0xE800 +/* X-BUS commands are listed as 32-bit big-endian */ +#define Z21_LAN_X_GET_VERSION_REQUEST 0x40002121 +#define Z21_LAN_X_GET_VERSION_REPLY 0x40006321 +#define Z21_LAN_X_GET_STATUS_REQUEST 0x40002124 +#define Z21_LAN_X_SET_TRACK_POWER_OFF 0x40002180 +#define Z21_LAN_X_SET_TRACK_POWER_ON 0x40002181 +#define Z21_LAN_X_DCC_READ_REGISTER 0x40002211 +#define Z21_LAN_X_CV_READ 0x40002311 +#define Z21_LAN_X_DCC_WRITE_REGISTER 0x40002312 +#define Z21_LAN_X_CV_WRITE 0x40002412 +#define Z21_LAN_X_MM_WRITE_BYTE 0x400024FF +#define Z21_LAN_X_GET_TURNOUT_INFO 0x400043 +#define Z21_LAN_X_TURNOUT_INFO 0x40FF43 /* To be set manually */ +#define Z21_LAN_X_GET_EXT_ACCESSORY_INFO 0x400044 +#define Z21_LAN_X_EXT_ACCESSORY_INFO 0x40FF44 /* To be set manually */ +#define Z21_LAN_X_SET_TURNOUT 0x400053 +#define Z21_LAN_X_SET_EXT_ACCESSORY 0x400054 +#define Z21_LAN_X_BC_TRACK_POWER_OFF 0x40006100 +#define Z21_LAN_X_BC_TRACK_POWER_ON 0x40006101 +#define Z21_LAN_X_BC_PROGRAMMING_MODE 0x40006102 +#define Z21_LAN_X_BC_TRACK_SHORT_CIRCUIT 0x40006108 +#define Z21_LAN_X_CV_NACK_SC 0x40006112 +#define Z21_LAN_X_CV_NACK 0x40006113 +#define Z21_LAN_X_UNKNOWN_COMMAND 0x40006182 +#define Z21_LAN_X_STATUS_CHANGED 0x40006222 +#define Z21_LAN_X_CV_RESULT 0x40006414 +#define Z21_LAN_X_SET_STOP 0x400080 +#define Z21_LAN_X_BC_STOPPED 0x40008100 +#define Z21_LAN_X_SET_LOCO_E_STOP 0x400092 +#define Z21_LAN_X_PURGE_LOCO 0x4000E344 +#define Z21_LAN_X_GET_LOCO_INFO 0x4000E3F0 +#define Z21_LAN_X_SET_LOCO_DRIVE_DCC14 0x4000E410 +#define Z21_LAN_X_SET_LOCO_DRIVE_DCC28 0x4000E412 +#define Z21_LAN_X_SET_LOCO_DRIVE_DCC128 0x4000E413 +#define Z21_LAN_X_SET_LOCO_FUNCTION 0x4000E4F8 +#define Z21_LAN_X_SET_LOCO_BINARY_STATE 0x4000E55F +#define Z21_LAN_X_CV_POM_COMMANDS 0x4000E630 +#define Z21_LAN_X_CV_POM_WRITE_BYTE 0x40FFE630 /* To be set manually */ +#define Z21_LAN_X_CV_POM_WRITE_BIT 0x40FEE630 /* To be set manually */ +#define Z21_LAN_X_CV_POM_READ_BYTE 0x40FDE630 /* To be set manually */ +#define Z21_LAN_X_CV_POM_ACCESSORY_COMMANDS 0x4000E631 +#define Z21_LAN_X_CV_POM_ACCESSORY_WRITE_BYTE 0x40FFE631 /* To be set manually */ +#define Z21_LAN_X_CV_POM_ACCESSORY_WRITE_BIT 0x40FEE631 /* To be set manually */ +#define Z21_LAN_X_CV_POM_ACCESSORY_READ_BYTE 0x40FDE631 /* To be set manually */ +#define Z21_LAN_X_LOCO_INFO 0x4000EF +#define Z21_LAN_X_GET_FIRMWARE_VERSION_REQUEST 0x4000F10A +#define Z21_LAN_X_GET_FIRMWARE_VERSION_REPLY 0x4000F30A + +static const value_string z21_command_vals[] = { + { Z21_LAN_CAN_BOOSTER_SET_TRACKPOWER, "LAN_CAN_BOOSTER_SET_TRACKPOWER" }, + { Z21_LAN_CAN_BOOSTER_SYSTEMSTATE_CHGD, "LAN_CAN_BOOSTER_SYSTEMSTATE_CHGD" }, + { Z21_LAN_CAN_DETECTOR, "LAN_CAN_DETECTOR" }, + { Z21_LAN_CAN_DEVICE_GET_DESCRIPTION, "LAN_CAN_DEVICE_GET_DESCRIPTION" }, + { Z21_LAN_CAN_DEVICE_SET_DESCRIPTION, "LAN_CAN_DEVICE_SET_DESCRIPTION" }, + { Z21_LAN_BOOSTER_GET_DESCRIPTION, "LAN_BOOSTER_GET_DESCRIPTION" }, + { Z21_LAN_BOOSTER_SET_DESCRIPTION, "LAN_BOOSTER_SET_DESCRIPTION" }, + { Z21_LAN_BOOSTER_SET_POWER, "LAN_BOOSTER_SET_POWER" }, + { Z21_LAN_BOOSTER_SYSTEMSTATE_DATACHANGED, "LAN_BOOSTER_SYSTEMSTATE_DATACHANGED" }, + { Z21_LAN_BOOSTER_SYSTEMSTATE_GETDATA, "LAN_BOOSTER_SYSTEMSTATE_GETDATA" }, + { Z21_LAN_DECODER_GET_DESCRIPTION, "LAN_DECODER_GET_DESCRIPTION" }, + { Z21_LAN_DECODER_SET_DESCRIPTION, "LAN_DECODER_SET_DESCRIPTION" }, + { Z21_LAN_DECODER_SYSTEMSTATE_DATACHANGED, "LAN_DECODER_SYSTEMSTATE_DATACHANGED" }, + { Z21_LAN_DECODER_SYSTEMSTATE_GETDATA, "LAN_DECODER_SYSTEMSTATE_GETDATA" }, + { Z21_LAN_FAST_CLOCK_CONTROL, "LAN_FAST_CLOCK_CONTROL" }, + { Z21_LAN_FAST_CLOCK_DATA, "LAN_FAST_CLOCK_DATA" }, + { Z21_LAN_FAST_CLOCK_SETTINGS_GET, "LAN_FAST_CLOCK_SETTINGS_GET" }, + { Z21_LAN_FAST_CLOCK_SETTINGS_SET, "LAN_FAST_CLOCK_SETTINGS_SET" }, + { Z21_LAN_GET_SERIAL_NUMBER, "LAN_GET_SERIAL_NUMBER" }, + { Z21_LAN_LOCONET_DETECTOR, "LAN_LOCONET_DETECTOR" }, + { Z21_LAN_LOCONET_DISPATCH_ADDR, "LAN_LOCONET_DISPATCH_ADDR" }, + { Z21_LAN_LOCONET_FROM_LAN, "LAN_LOCONET_FROM_LAN" }, + { Z21_LAN_LOCONET_Z21_RX, "LAN_LOCONET_Z21_RX" }, + { Z21_LAN_LOCONET_Z21_TX, "LAN_LOCONET_Z21_TX" }, + { Z21_LAN_LOGOFF, "LAN_LOGOFF" }, + { Z21_LAN_RAILCOM_GETDATA, "LAN_RAILCOM_GETDATA" }, + { Z21_LAN_RAILCOM_DATACHANGED, "LAN_RAILCOM_DATACHANGED" }, + { Z21_LAN_RMBUS_DATACHANGED, "LAN_RMBUS_DATACHANGED" }, + { Z21_LAN_RMBUS_GETDATA, "LAN_RMBUS_GETDATA" }, + { Z21_LAN_RMBUS_PROGRAMMODULE, "LAN_RMBUS_PROGRAMMODULE" }, + { Z21_LAN_SYSTEMSTATE_DATACHANGED, "LAN_SYSTEMSTATE_DATACHANGED" }, + { Z21_LAN_X_BC_PROGRAMMING_MODE, "LAN_X_BC_PROGRAMMING_MODE" }, + { Z21_LAN_X_BC_STOPPED, "LAN_X_BC_STOPPED" }, + { Z21_LAN_X_BC_TRACK_POWER_OFF, "LAN_X_BC_TRACK_POWER_OFF" }, + { Z21_LAN_X_BC_TRACK_POWER_ON, "LAN_X_BC_TRACK_POWER_ON" }, + { Z21_LAN_X_BC_TRACK_SHORT_CIRCUIT, "LAN_X_BC_TRACK_SHORT_CIRCUIT" }, + { Z21_LAN_X_CV_NACK, "LAN_X_CV_NACK" }, + { Z21_LAN_X_CV_NACK_SC, "LAN_X_CV_NACK_SC" }, + { Z21_LAN_X_CV_POM_ACCESSORY_READ_BYTE, "LAN_X_CV_POM_ACCESSORY_READ_BYTE" }, + { Z21_LAN_X_CV_POM_ACCESSORY_WRITE_BIT, "LAN_X_CV_POM_ACCESSORY_WRITE_BIT" }, + { Z21_LAN_X_CV_POM_ACCESSORY_WRITE_BYTE, "LAN_X_CV_POM_ACCESSORY_WRITE_BYTE" }, + { Z21_LAN_X_CV_POM_READ_BYTE, "LAN_X_CV_POM_READ_BYTE" }, + { Z21_LAN_X_CV_POM_WRITE_BIT, "LAN_X_CV_POM_WRITE_BIT" }, + { Z21_LAN_X_CV_POM_WRITE_BYTE, "LAN_X_CV_POM_WRITE_BYTE" }, + { Z21_LAN_X_CV_READ, "LAN_X_CV_READ" }, + { Z21_LAN_X_CV_RESULT, "LAN_X_CV_RESULT" }, + { Z21_LAN_X_CV_WRITE, "LAN_X_CV_WRITE" }, + { Z21_LAN_X_DCC_READ_REGISTER, "LAN_X_DCC_READ_REGISTER" }, + { Z21_LAN_X_DCC_WRITE_REGISTER, "LAN_X_DCC_WRITE_REGISTER" }, + { Z21_LAN_X_EXT_ACCESSORY_INFO, "LAN_X_EXT_ACCESSORY_INFO" }, + { Z21_LAN_X_GET_EXT_ACCESSORY_INFO, "LAN_X_GET_EXT_ACCESSORY_INFO" }, + { Z21_LAN_X_GET_FIRMWARE_VERSION_REQUEST, "LAN_X_GET_FIRMWARE_VERSION" }, + { Z21_LAN_X_GET_FIRMWARE_VERSION_REPLY, "LAN_X_GET_FIRMWARE_VERSION" }, + { Z21_LAN_X_GET_LOCO_INFO, "LAN_X_GET_LOCO_INFO" }, + { Z21_LAN_X_GET_TURNOUT_INFO, "LAN_X_GET_TURNOUT_INFO" }, + { Z21_LAN_X_GET_VERSION_REQUEST, "LAN_X_GET_VERSION" }, + { Z21_LAN_X_GET_VERSION_REPLY, "LAN_X_GET_VERSION" }, + { Z21_LAN_X_GET_STATUS_REQUEST, "LAN_X_GET_STATUS" }, + { Z21_LAN_X_LOCO_INFO, "LAN_X_LOCO_INFO" }, + { Z21_LAN_X_MM_WRITE_BYTE, "LAN_X_MM_WRITE_BYTE" }, + { Z21_LAN_X_PURGE_LOCO, "LAN_X_PURGE_LOCO" }, + { Z21_LAN_X_SET_EXT_ACCESSORY, "LAN_X_SET_EXT_ACCESSORY" }, + { Z21_LAN_X_SET_LOCO_BINARY_STATE, "LAN_X_SET_LOCO_BINARY_STATE" }, + { Z21_LAN_X_SET_LOCO_DRIVE_DCC14, "LAN_X_SET_LOCO_DRIVE" }, + { Z21_LAN_X_SET_LOCO_DRIVE_DCC28, "LAN_X_SET_LOCO_DRIVE" }, + { Z21_LAN_X_SET_LOCO_DRIVE_DCC128, "LAN_X_SET_LOCO_DRIVE" }, + { Z21_LAN_X_SET_LOCO_E_STOP, "LAN_X_SET_LOCO_E_STOP" }, + { Z21_LAN_X_SET_LOCO_FUNCTION, "LAN_X_SET_LOCO_FUNCTION" }, + { Z21_LAN_X_SET_STOP, "LAN_X_SET_STOP" }, + { Z21_LAN_X_SET_TRACK_POWER_OFF, "LAN_X_SET_TRACK_POWER_OFF" }, + { Z21_LAN_X_SET_TRACK_POWER_ON, "LAN_X_SET_TRACK_POWER_ON" }, + { Z21_LAN_X_SET_TURNOUT, "LAN_X_SET_TURNOUT" }, + { Z21_LAN_X_STATUS_CHANGED, "LAN_X_STATUS_CHANGED" }, + { Z21_LAN_X_TURNOUT_INFO, "LAN_X_TURNOUT_INFO" }, + { Z21_LAN_X_UNKNOWN_COMMAND, "LAN_X_UNKNOWN_COMMAND" }, + { Z21_LAN_ZLINK_GET_HWINFO, "LAN_ZLINK_GET_HWINFO" }, + { 0, NULL }, +}; + +static const value_string z21_loco_info_speed_steps_vals[] = { + { 0, "14 speed steps" }, + { 2, "28 speed steps" }, + { 4, "128 speed steps" }, + { 0, NULL }, +}; + +static const value_string z21_loco_func_vals[] = { + { 0, "Off" }, + { 1, "On" }, + { 2, "Toggle" }, + { 3, "Not allowed" }, + { 0, NULL }, +}; + +static const value_string z21_turnout_state_vals[] = { + { 0, "Not switched yet" }, + { 1, "Turnout is in position \"P=0\"" }, + { 2, "Turnout is in position \"P=1\"" }, + { 3, "Invalid combination" }, + { 0, NULL }, +}; + +static const value_string z21_pom_operation_vals[] = { + { 0x39, "Read byte" }, /* 111001 */ + { 0x3a, "Write bit" }, /* 111010 */ + { 0x3b, "Write byte" }, /* 111011 */ + { 0, NULL }, +}; + +static const value_string z21_zlink_message_type_vals[] = { + { 0x06, "ZLINK_MSG_TYPE_HW_INFO" }, + { 0, NULL }, +}; + +static const true_false_string tfs_forward_reverse = { "Forward", "Reverse" }; +static const true_false_string tfs_turnout_command = { "Activate", "Deactivate" }; +static const true_false_string tfs_turnout_output = { "Output 2", "Output 1" }; + + +static void +update_command_field(proto_item *ti, unsigned command) +{ + int width = 8; + if (command <= 0xff) + width = 2; + else if (command <= 0xffff) + width = 4; + else if (command <= 0xffffff) + width = 6; + proto_item_append_text(ti, ": %s (0x%0*x)", + val_to_str_const(command, z21_command_vals, "unknown"), + width, command); +} + + +/* Code to actually dissect the packets */ + +static int +dissect_z21_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_) +{ + proto_item *ti, *temp_ti, *command_ti; + proto_tree *z21_tree; + unsigned offset = 0, datalen, command; + unsigned checksum, calculated_checksum, one_byte, version, temp_uint; + unsigned address_bytes, addr, speed_steps = 0, cv_addr; + guint64 status, direction_and_speed, temp_guint64; + gint32 main_current, temp_gint32; + char *buffer; + float temp_float; + static int * const state_bits_byte1[] = { + &hf_z21_state_programming_mode, + &hf_z21_state_short_circuit, + &hf_z21_state_track_voltage_off, + &hf_z21_state_emergency_stop, + NULL + }; + static int * const state_bits_byte2[] = { + &hf_z21_state_rcn_213, + &hf_z21_state_short_circuit_internal, + &hf_z21_state_short_circuit_external, + &hf_z21_state_power_lost, + &hf_z21_state_high_temperature, + NULL + }; + static int * const capability_bits[] = { + &hf_z21_capability_needs_unlock_code, + &hf_z21_capability_detector_cmds, + &hf_z21_capability_accessory_cmds, + &hf_z21_capability_loco_cmds, + &hf_z21_capability_railcom, + &hf_z21_capability_reserved, + &hf_z21_capability_mm, + &hf_z21_capability_dcc, + NULL + }; + static int * const speed_bits[] = { + &hf_z21_loco_direction, + &hf_z21_loco_speed, + NULL + }; + static int * const loco_info_bits1[] = { + &hf_z21_loco_info_mm, + &hf_z21_loco_info_busy, + &hf_z21_loco_info_speed_steps, + NULL + }; + static int * const loco_info_bits2[] = { + &hf_z21_loco_info_direction, + &hf_z21_loco_info_speed, + NULL + }; + static int * const loco_info_bits3[] = { + &hf_z21_loco_info_double_traction, + &hf_z21_loco_info_smartsearch, + &hf_z21_loco_info_f0, + &hf_z21_loco_info_f4, + &hf_z21_loco_info_f3, + &hf_z21_loco_info_f2, + &hf_z21_loco_info_f1, + NULL + }; + static int * const loco_info_bits4[] = { + &hf_z21_loco_info_f12, + &hf_z21_loco_info_f11, + &hf_z21_loco_info_f10, + &hf_z21_loco_info_f9, + &hf_z21_loco_info_f8, + &hf_z21_loco_info_f7, + &hf_z21_loco_info_f6, + &hf_z21_loco_info_f5, + NULL + }; + static int * const loco_info_bits5[] = { + &hf_z21_loco_info_f20, + &hf_z21_loco_info_f19, + &hf_z21_loco_info_f18, + &hf_z21_loco_info_f17, + &hf_z21_loco_info_f16, + &hf_z21_loco_info_f15, + &hf_z21_loco_info_f14, + &hf_z21_loco_info_f13, + NULL + }; + static int * const loco_info_bits6[] = { + &hf_z21_loco_info_f28, + &hf_z21_loco_info_f27, + &hf_z21_loco_info_f26, + &hf_z21_loco_info_f25, + &hf_z21_loco_info_f24, + &hf_z21_loco_info_f23, + &hf_z21_loco_info_f22, + &hf_z21_loco_info_f21, + NULL + }; + static int * const loco_info_bits7[] = { + &hf_z21_loco_info_f31, + &hf_z21_loco_info_f30, + &hf_z21_loco_info_f29, + NULL + }; + static int * const loco_func_bits[] = { + &hf_z21_loco_func_switch_type, + &hf_z21_loco_func_index, + NULL + }; + static int * const turnout_state_bits[] = { + &hf_z21_turnout_state, + NULL + }; + static int * const turnout_set_bits[] = { + &hf_z21_turnout_queue_bit, + &hf_z21_turnout_activate_bit, + &hf_z21_turnout_output_bit, + NULL + }; + static int * const cv_bits[] = { + &hf_z21_cv_bit_value, + &hf_z21_cv_bit_position, + NULL + }; + static int * const booster_state_bits[] = { + &hf_z21_can_booster_state_railcom_active, + &hf_z21_can_booster_state_output_disabled, + &hf_z21_can_booster_state_track_voltage_off, + &hf_z21_can_booster_state_short_circuit, + &hf_z21_can_booster_state_bg_active, + NULL + }; + + /* Check that the packet is long enough for it to belong to us. */ + if (tvb_reported_length(tvb) < Z21_MIN_LENGTH) + return 0; + + col_set_str(pinfo->cinfo, COL_PROTOCOL, "Z21"); + + ti = proto_tree_add_item(tree, proto_z21, tvb, 0, -1, ENC_NA); + z21_tree = proto_item_add_subtree(ti, ett_z21); + proto_tree_add_item_ret_uint(z21_tree, hf_z21_datalen, + tvb, offset, 2, ENC_LITTLE_ENDIAN, &datalen); + offset += 2; + command = tvb_get_guint16(tvb, offset, ENC_BIG_ENDIAN); + if (command == Z21_X_BUS) { + proto_tree_add_boolean(z21_tree, hf_z21_x_bus, tvb, offset, 2, true); + /* Note that we do not increment the offset yet */ + + /* Strategy: + * 1. Read two bytes of the data (as big-endian) + * 2. Prepend it with 0x4000 (the header bytes for X-BUS) + * 3. If the three MSBs are one of the "one-byte commands", + * set x_bus_command accordingly and run with that + * 4. Otherwise run with "two-byte commands"... + * 5. ... except that there are some commands that need more data to + * determine the exact command (as their two "command bytes" are the + * same), so check for those and set x_bus_command manually for them. + */ + temp_uint = 0x40000000 + tvb_get_guint16(tvb, offset+2, ENC_BIG_ENDIAN); + unsigned x_bus_command = temp_uint >> 8; + /* Check for all the "one-byte" commands */ + if (x_bus_command == Z21_LAN_X_SET_STOP || + x_bus_command == Z21_LAN_X_SET_LOCO_E_STOP || + x_bus_command == Z21_LAN_X_GET_EXT_ACCESSORY_INFO || + x_bus_command == Z21_LAN_X_SET_EXT_ACCESSORY || + x_bus_command == Z21_LAN_X_GET_TURNOUT_INFO || + x_bus_command == Z21_LAN_X_SET_TURNOUT || + x_bus_command == Z21_LAN_X_LOCO_INFO) { + /* Initialize the checksum without the 0x4000 prefix */ + calculated_checksum = x_bus_command & 0xff; + /* Check for these that are actually another command */ + if (x_bus_command == Z21_LAN_X_GET_TURNOUT_INFO && datalen == 9) { + x_bus_command = Z21_LAN_X_TURNOUT_INFO; + } else if (x_bus_command == Z21_LAN_X_GET_EXT_ACCESSORY_INFO && datalen == 10) { + x_bus_command = Z21_LAN_X_EXT_ACCESSORY_INFO; + } + command_ti = proto_tree_add_uint(z21_tree, hf_z21_command, tvb, offset, 3, x_bus_command); + offset += 3; + } + else { + /* First assume "two-byte command", then check for exceptions */ + x_bus_command = temp_uint; + if (x_bus_command == Z21_LAN_X_CV_POM_COMMANDS || + x_bus_command == Z21_LAN_X_CV_POM_ACCESSORY_COMMANDS) { + /* Read DB3 from data, get the two interesting bits */ + temp_uint = tvb_get_guint8(tvb, offset + 6) >> 2 & 0x3; + switch (x_bus_command) { + case Z21_LAN_X_CV_POM_COMMANDS: + if (temp_uint == 0x1) + x_bus_command = Z21_LAN_X_CV_POM_READ_BYTE; + else if (temp_uint == 0x2) + x_bus_command = Z21_LAN_X_CV_POM_WRITE_BIT; + else if (temp_uint == 0x3) + x_bus_command = Z21_LAN_X_CV_POM_WRITE_BYTE; + break; + case Z21_LAN_X_CV_POM_ACCESSORY_COMMANDS: + if (temp_uint == 0x1) + x_bus_command = Z21_LAN_X_CV_POM_ACCESSORY_READ_BYTE; + else if (temp_uint == 0x2) + x_bus_command = Z21_LAN_X_CV_POM_ACCESSORY_WRITE_BIT; + else if (temp_uint == 0x3) + x_bus_command = Z21_LAN_X_CV_POM_ACCESSORY_WRITE_BYTE; + break; + } + } + command_ti = proto_tree_add_uint(z21_tree, hf_z21_command, + tvb, offset, 4, x_bus_command); + offset += 4; + /* Initialize the checksum with the two LSBs */ + calculated_checksum = ((x_bus_command & 0xff00) >> 8) ^ (x_bus_command & 0x00ff); + } + update_command_field(command_ti, x_bus_command); + col_add_fstr(pinfo->cinfo, COL_INFO, "Command=%s", + val_to_str_const(x_bus_command, z21_command_vals, "unknown")); + proto_item_append_text(z21_tree, ", Command: %s", + val_to_str_const(x_bus_command, z21_command_vals, "unknown")); + switch (x_bus_command) { + case Z21_LAN_X_STATUS_CHANGED: + proto_tree_add_bitmask_ret_uint64(z21_tree, tvb, offset, hf_z21_status, + ett_z21, state_bits_byte1, ENC_NA, &status); + offset += 1; + calculated_checksum ^= (unsigned)status; + break; + case Z21_LAN_X_SET_LOCO_DRIVE_DCC14: + case Z21_LAN_X_SET_LOCO_DRIVE_DCC28: + case Z21_LAN_X_SET_LOCO_DRIVE_DCC128: + address_bytes = tvb_get_guint16(tvb, offset, ENC_BIG_ENDIAN); + addr = address_bytes & 0x3FFF; + proto_tree_add_uint(z21_tree, hf_z21_loco_address, tvb, offset, 2, addr); + switch (x_bus_command) { + case Z21_LAN_X_SET_LOCO_DRIVE_DCC14: speed_steps = 14; break; + case Z21_LAN_X_SET_LOCO_DRIVE_DCC28: speed_steps = 28; break; + case Z21_LAN_X_SET_LOCO_DRIVE_DCC128: speed_steps = 128; break; + } + proto_tree_add_uint(z21_tree, hf_z21_speed_steps, tvb, offset-1, 1, speed_steps); + offset += 2; + calculated_checksum ^= address_bytes >> 8; + calculated_checksum ^= address_bytes & 0xFF; + col_append_fstr(pinfo->cinfo, COL_INFO, ", Loco=%d (%d SS)", + addr, speed_steps); + temp_ti = proto_tree_add_bitmask_ret_uint64(z21_tree, tvb, offset, hf_z21_loco_direction_and_speed, + ett_z21, speed_bits, ENC_NA, &direction_and_speed); + offset += 1; + calculated_checksum ^= (unsigned)direction_and_speed; + if (direction_and_speed & 0x80) { + proto_item_set_text(temp_ti, + "Locomotive direction and speed: Forward, 0x%02" PRIx64, + direction_and_speed & 0x7F); + col_append_fstr(pinfo->cinfo, COL_INFO, ", Forward"); + } + else { + proto_item_set_text(temp_ti, + "Locomotive direction and speed: Reverse, 0x%02" PRIx64, + direction_and_speed & 0x7F); + col_append_fstr(pinfo->cinfo, COL_INFO, ", Reverse"); + } + col_append_fstr(pinfo->cinfo, COL_INFO, ", Speed=0x%02" PRIx64, + direction_and_speed & 0x7F); + break; + case Z21_LAN_X_GET_LOCO_INFO: + address_bytes = tvb_get_guint16(tvb, offset, ENC_BIG_ENDIAN); + addr = address_bytes & 0x3FFF; + proto_tree_add_uint(z21_tree, hf_z21_loco_address, tvb, offset, 2, addr); + offset += 2; + calculated_checksum ^= address_bytes >> 8; + calculated_checksum ^= address_bytes & 0xFF; + col_append_fstr(pinfo->cinfo, COL_INFO, ", Loco=%d", addr); + break; + case Z21_LAN_X_LOCO_INFO: + address_bytes = tvb_get_guint16(tvb, offset, ENC_BIG_ENDIAN); + addr = address_bytes & 0x3FFF; + proto_tree_add_uint(z21_tree, hf_z21_loco_address, tvb, offset, 2, addr); + offset += 2; + calculated_checksum ^= address_bytes >> 8; + calculated_checksum ^= address_bytes & 0xFF; + col_append_fstr(pinfo->cinfo, COL_INFO, ", Loco=%d", addr); + proto_item_append_text(z21_tree, ", Loco: %d", addr); + + proto_tree_add_bitmask_list_ret_uint64(z21_tree, tvb, offset, 1, + loco_info_bits1, ENC_NA, &temp_guint64); + offset += 1; + calculated_checksum ^= temp_guint64; + col_append_fstr(pinfo->cinfo, COL_INFO, " (%s)", + val_to_str_const((guint32)temp_guint64 & 0x07, + z21_loco_info_speed_steps_vals, "unknown")); + + proto_tree_add_bitmask_list_ret_uint64(z21_tree, tvb, offset, 1, + loco_info_bits2, ENC_NA, &temp_guint64); + offset += 1; + calculated_checksum ^= temp_guint64; + col_append_fstr(pinfo->cinfo, COL_INFO, ", %s", + tfs_get_string((gboolean)temp_guint64 >> 7, &tfs_forward_reverse)); + col_append_fstr(pinfo->cinfo, COL_INFO, ", Speed=0x%02" PRIx64, + temp_guint64 & 0x7f); + + proto_tree_add_bitmask_list_ret_uint64(z21_tree, tvb, offset, 1, + loco_info_bits3, ENC_NA, &temp_guint64); + offset += 1; + calculated_checksum ^= temp_guint64; + if (temp_guint64 & 0x40) { + col_append_str(pinfo->cinfo, COL_INFO, ", in double traction"); + } + + proto_tree_add_bitmask_list_ret_uint64(z21_tree, tvb, offset, 1, + loco_info_bits4, ENC_NA, &temp_guint64); + offset += 1; + calculated_checksum ^= temp_guint64; + + proto_tree_add_bitmask_list_ret_uint64(z21_tree, tvb, offset, 1, + loco_info_bits5, ENC_NA, &temp_guint64); + offset += 1; + calculated_checksum ^= temp_guint64; + + /* The following bytes are not always there it seems */ + if (offset < datalen-1) { + proto_tree_add_bitmask_list_ret_uint64(z21_tree, tvb, offset, 1, + loco_info_bits6, ENC_NA, &temp_guint64); + offset += 1; + calculated_checksum ^= temp_guint64; + } + if (offset < datalen-1) { + proto_tree_add_bitmask_list_ret_uint64(z21_tree, tvb, offset, 1, + loco_info_bits7, ENC_NA, &temp_guint64); + offset += 1; + calculated_checksum ^= temp_guint64; + } + /* If still something, dissect as bytes */ + if (offset < datalen-1) { + proto_tree_add_item(z21_tree, hf_z21_loco_info_extensions, + tvb, offset, datalen-1-offset, ENC_NA); + /* Note: Do not increment offset because the checksum + * will be calculated below! */ + } + break; + case Z21_LAN_X_PURGE_LOCO: + address_bytes = tvb_get_guint16(tvb, offset, ENC_BIG_ENDIAN); + addr = address_bytes & 0x3FFF; + proto_tree_add_uint(z21_tree, hf_z21_loco_address, tvb, offset, 2, addr); + offset += 2; + calculated_checksum ^= address_bytes >> 8; + calculated_checksum ^= address_bytes & 0xFF; + col_append_fstr(pinfo->cinfo, COL_INFO, ", Loco=%d", addr); + proto_item_append_text(z21_tree, ", Loco: %d", addr); + break; + case Z21_LAN_X_SET_LOCO_E_STOP: + address_bytes = tvb_get_guint16(tvb, offset, ENC_BIG_ENDIAN); + addr = address_bytes & 0x3FFF; + proto_tree_add_uint(z21_tree, hf_z21_loco_address, tvb, offset, 2, addr); + offset += 2; + calculated_checksum ^= address_bytes >> 8; + calculated_checksum ^= address_bytes & 0xFF; + col_append_fstr(pinfo->cinfo, COL_INFO, ", Loco=%d", addr); + proto_item_append_text(z21_tree, ", Loco: %d", addr); + break; + case Z21_LAN_X_SET_LOCO_BINARY_STATE: + col_append_str(pinfo->cinfo, COL_INFO, ", TO BE COMPLETED"); + break; + case Z21_LAN_X_SET_LOCO_FUNCTION: + address_bytes = tvb_get_guint16(tvb, offset, ENC_BIG_ENDIAN); + addr = address_bytes & 0x3FFF; + proto_tree_add_uint(z21_tree, hf_z21_loco_address, tvb, offset, 2, addr); + offset += 2; + calculated_checksum ^= address_bytes >> 8; + calculated_checksum ^= address_bytes & 0xFF; + col_append_fstr(pinfo->cinfo, COL_INFO, ", Loco=%d", addr); + proto_item_append_text(z21_tree, ", Loco: %d", addr); + proto_tree_add_bitmask_list_ret_uint64(z21_tree, tvb, offset, 1, + loco_func_bits, ENC_NA, &temp_guint64); + offset += 1; + calculated_checksum ^= temp_guint64; + col_append_fstr(pinfo->cinfo, COL_INFO, ", Function=%" PRIu64 ", State=%s", + temp_guint64 & 0x3f, + val_to_str_const((guint32)temp_guint64 >> 6, z21_loco_func_vals, "unknown")); + proto_item_append_text(z21_tree, ", Function: %" PRIu64 ", State: %s", + temp_guint64 & 0x3f, + val_to_str_const((guint32)temp_guint64 >> 6, z21_loco_func_vals, "unknown")); + break; + case Z21_LAN_X_GET_TURNOUT_INFO: + addr = tvb_get_guint16(tvb, offset, ENC_BIG_ENDIAN); + proto_tree_add_uint(z21_tree, hf_z21_function_address, + tvb, offset, 2, addr); + offset += 2; + calculated_checksum ^= addr >> 8; + calculated_checksum ^= addr & 0xFF; + col_append_fstr(pinfo->cinfo, COL_INFO, ", Function=%d", addr); + proto_item_append_text(z21_tree, ", Function: %d", addr); + break; + case Z21_LAN_X_TURNOUT_INFO: + addr = tvb_get_guint16(tvb, offset, ENC_BIG_ENDIAN); + proto_tree_add_uint(z21_tree, hf_z21_function_address, + tvb, offset, 2, addr); + offset += 2; + calculated_checksum ^= addr >> 8; + calculated_checksum ^= addr & 0xFF; + proto_tree_add_bitmask_list_ret_uint64(z21_tree, tvb, offset, 1, + turnout_state_bits, ENC_NA, &temp_guint64); + offset += 1; + calculated_checksum ^= temp_guint64; + col_append_fstr(pinfo->cinfo, COL_INFO, ", Address=%d, State=%s", + addr, + val_to_str_const((guint32)temp_guint64 & 0x03, z21_turnout_state_vals, "unknown")); + proto_item_append_text(z21_tree, ", Address: %d, State: %s", + addr, + val_to_str_const((guint32)temp_guint64 & 0x03, z21_turnout_state_vals, "unknown")); + break; + case Z21_LAN_X_SET_TURNOUT: + addr = tvb_get_guint16(tvb, offset, ENC_BIG_ENDIAN); + proto_tree_add_uint(z21_tree, hf_z21_function_address, + tvb, offset, 2, addr); + offset += 2; + calculated_checksum ^= addr >> 8; + calculated_checksum ^= addr & 0xFF; + col_append_fstr(pinfo->cinfo, COL_INFO, ", Address=%d", addr); + proto_item_append_text(z21_tree, ", Address: %d", addr); + proto_tree_add_bitmask_list_ret_uint64(z21_tree, tvb, offset, 1, + turnout_set_bits, ENC_NA, &temp_guint64); + offset += 1; + calculated_checksum ^= temp_guint64; + col_append_fstr(pinfo->cinfo, COL_INFO, ", Address=%d, %s, Output=%s", + addr, + tfs_get_string((gboolean)temp_guint64 & 0x08, &tfs_turnout_command), + tfs_get_string((gboolean)temp_guint64 & 0x01, &tfs_turnout_output)); + proto_item_append_text(z21_tree, ", Address: %d, %s, Output: %s", + addr, + tfs_get_string((gboolean)temp_guint64 & 0x08, &tfs_turnout_command), + tfs_get_string((gboolean)temp_guint64 & 0x01, &tfs_turnout_output)); + break; + case Z21_LAN_X_GET_EXT_ACCESSORY_INFO: + addr = tvb_get_guint16(tvb, offset, ENC_BIG_ENDIAN); + proto_tree_add_uint(z21_tree, hf_z21_accessory_address, + tvb, offset, 2, addr); + offset += 2; + calculated_checksum ^= addr >> 8; + calculated_checksum ^= addr & 0xFF; + col_append_fstr(pinfo->cinfo, COL_INFO, ", Address=%d", addr); + proto_item_append_text(z21_tree, ", Address: %d", addr); + break; + case Z21_LAN_X_EXT_ACCESSORY_INFO: + addr = tvb_get_guint16(tvb, offset, ENC_BIG_ENDIAN); + proto_tree_add_uint(z21_tree, hf_z21_accessory_address, + tvb, offset, 2, addr); + offset += 2; + calculated_checksum ^= addr >> 8; + calculated_checksum ^= addr & 0xFF; + temp_uint = tvb_get_guint16(tvb, offset, ENC_BIG_ENDIAN); + proto_tree_add_uint(z21_tree, hf_z21_accessory_state, + tvb, offset, 1, temp_uint >> 8); + offset += 1; + calculated_checksum ^= temp_uint >> 8; + proto_tree_add_uint(z21_tree, hf_z21_accessory_status, + tvb, offset, 1, temp_uint & 0xff); + offset += 1; + calculated_checksum ^= temp_uint & 0xff; + col_append_fstr(pinfo->cinfo, COL_INFO, ", Address=%d, State=%d, Status=0x%02x", + addr, temp_uint >> 8, temp_uint & 0xff); + proto_item_append_text(z21_tree, ", Address: %d, State: %d, Status: 0x%02x", + addr, temp_uint >> 8, temp_uint & 0xff); + break; + case Z21_LAN_X_SET_EXT_ACCESSORY: + addr = tvb_get_guint16(tvb, offset, ENC_BIG_ENDIAN); + proto_tree_add_uint(z21_tree, hf_z21_accessory_address, + tvb, offset, 2, addr); + offset += 2; + calculated_checksum ^= addr >> 8; + calculated_checksum ^= addr & 0xFF; + temp_uint = tvb_get_guint8(tvb, offset); + proto_tree_add_uint(z21_tree, hf_z21_accessory_state, + tvb, offset, 1, temp_uint); + offset += 1; + calculated_checksum ^= temp_uint; + col_append_fstr(pinfo->cinfo, COL_INFO, ", Address=%d, State=%d", + addr, temp_uint); + proto_item_append_text(z21_tree, ", Address: %d, State: %d", + addr, temp_uint); + break; + case Z21_LAN_X_CV_READ: + cv_addr = tvb_get_guint16(tvb, offset, ENC_BIG_ENDIAN); + /* CV addresses are 1-based, update checksum first */ + calculated_checksum ^= cv_addr >> 8; + calculated_checksum ^= cv_addr & 0xFF; + cv_addr += 1; + proto_tree_add_uint(z21_tree, hf_z21_cv_address, + tvb, offset, 2, cv_addr); + offset += 2; + col_append_fstr(pinfo->cinfo, COL_INFO, ", CV%d", cv_addr); + proto_item_append_text(z21_tree, ", CV%d", cv_addr); + break; + case Z21_LAN_X_CV_WRITE: + cv_addr = tvb_get_guint16(tvb, offset, ENC_BIG_ENDIAN); + /* CV addresses are 1-based, update checksum first */ + calculated_checksum ^= cv_addr >> 8; + calculated_checksum ^= cv_addr & 0xFF; + cv_addr += 1; + proto_tree_add_uint(z21_tree, hf_z21_cv_address, + tvb, offset, 2, cv_addr); + offset += 2; + temp_uint = tvb_get_guint8(tvb, offset); + proto_tree_add_uint(z21_tree, hf_z21_cv_value, + tvb, offset, 1, temp_uint); + offset += 1; + calculated_checksum ^= temp_uint; + col_append_fstr(pinfo->cinfo, COL_INFO, ", CV%d, Value=%d", + cv_addr, temp_uint); + proto_item_append_text(z21_tree, ", CV%d, Value: %d", + cv_addr, temp_uint); + break; + case Z21_LAN_X_CV_RESULT: + cv_addr = tvb_get_guint16(tvb, offset, ENC_BIG_ENDIAN); + /* CV addresses are 1-based, update checksum first */ + calculated_checksum ^= cv_addr >> 8; + calculated_checksum ^= cv_addr & 0xFF; + cv_addr += 1; + proto_tree_add_uint(z21_tree, hf_z21_cv_address, + tvb, offset, 2, cv_addr); + offset += 2; + temp_uint = tvb_get_guint8(tvb, offset); + proto_tree_add_uint(z21_tree, hf_z21_cv_value, + tvb, offset, 1, temp_uint); + offset += 1; + calculated_checksum ^= temp_uint; + col_append_fstr(pinfo->cinfo, COL_INFO, ", CV%d, Value=%d", + cv_addr, temp_uint); + proto_item_append_text(z21_tree, ", CV%d, Value: %d", + cv_addr, temp_uint); + break; + case Z21_LAN_X_CV_POM_WRITE_BYTE: + address_bytes = tvb_get_guint16(tvb, offset, ENC_BIG_ENDIAN); + addr = address_bytes & 0x3FFF; + proto_tree_add_uint(z21_tree, hf_z21_loco_address, tvb, offset, 2, addr); + offset += 2; + calculated_checksum ^= address_bytes >> 8; + calculated_checksum ^= address_bytes & 0xFF; + temp_uint = tvb_get_guint16(tvb, offset, ENC_BIG_ENDIAN); + calculated_checksum ^= temp_uint >> 8; + calculated_checksum ^= temp_uint & 0xff; + proto_tree_add_uint(z21_tree, hf_z21_pom_operation, + tvb, offset, 1, temp_uint >> 2); + cv_addr = (temp_uint & 0x03ff) + 1; + proto_tree_add_uint(z21_tree, hf_z21_cv_address, + tvb, offset, 2, cv_addr); + offset += 2; + proto_tree_add_item_ret_uint(z21_tree, hf_z21_cv_value, + tvb, offset, 1, ENC_NA, &temp_uint); + offset += 1; + calculated_checksum ^= temp_uint; + col_append_fstr(pinfo->cinfo, COL_INFO, ", Loco=%d, CV%d, Value=%d", + addr, cv_addr, temp_uint); + proto_item_append_text(z21_tree, ", Loco: %d, CV%d, Value: %d", + addr, cv_addr, temp_uint); + break; + case Z21_LAN_X_CV_POM_WRITE_BIT: + address_bytes = tvb_get_guint16(tvb, offset, ENC_BIG_ENDIAN); + addr = address_bytes & 0x3FFF; + proto_tree_add_uint(z21_tree, hf_z21_loco_address, tvb, offset, 2, addr); + offset += 2; + calculated_checksum ^= address_bytes >> 8; + calculated_checksum ^= address_bytes & 0xFF; + temp_uint = tvb_get_guint16(tvb, offset, ENC_BIG_ENDIAN); + calculated_checksum ^= temp_uint >> 8; + calculated_checksum ^= temp_uint & 0xff; + proto_tree_add_uint(z21_tree, hf_z21_pom_operation, + tvb, offset, 1, temp_uint >> 2); + cv_addr = (temp_uint & 0x03ff) + 1; + proto_tree_add_uint(z21_tree, hf_z21_cv_address, + tvb, offset, 2, cv_addr); + offset += 2; + proto_tree_add_bitmask_list_ret_uint64(z21_tree, tvb, offset, 1, + cv_bits, ENC_NA, &temp_guint64); + offset += 1; + calculated_checksum ^= (unsigned)temp_guint64; + col_append_fstr(pinfo->cinfo, COL_INFO, ", Loco=%d, CV%d, Bit position=%" PRIu64 ", Value=%" PRIu64, + addr, cv_addr, temp_guint64 & 0x07, temp_guint64 >> 3 & 0x01); + proto_item_append_text(z21_tree, ", Loco: %d, CV%d, Bit position: %" PRIu64 ", Value: %" PRIu64, + addr, cv_addr, temp_guint64 & 0x07, temp_guint64 >> 3 & 0x01); + break; + case Z21_LAN_X_CV_POM_READ_BYTE: + address_bytes = tvb_get_guint16(tvb, offset, ENC_BIG_ENDIAN); + addr = address_bytes & 0x3FFF; + proto_tree_add_uint(z21_tree, hf_z21_loco_address, tvb, offset, 2, addr); + offset += 2; + calculated_checksum ^= address_bytes >> 8; + calculated_checksum ^= address_bytes & 0xFF; + temp_uint = tvb_get_guint16(tvb, offset, ENC_BIG_ENDIAN); + calculated_checksum ^= temp_uint >> 8; + calculated_checksum ^= temp_uint & 0xff; + proto_tree_add_uint(z21_tree, hf_z21_pom_operation, + tvb, offset, 1, temp_uint >> 2); + cv_addr = (temp_uint & 0x03ff) + 1; + proto_tree_add_uint(z21_tree, hf_z21_cv_address, + tvb, offset, 2, cv_addr); + offset += 2; + col_append_fstr(pinfo->cinfo, COL_INFO, ", Loco=%d, CV%d", + addr, cv_addr); + proto_item_append_text(z21_tree, ", Loco: %d, CV%d", + addr, cv_addr); + break; + case Z21_LAN_X_CV_POM_ACCESSORY_WRITE_BYTE: + case Z21_LAN_X_CV_POM_ACCESSORY_WRITE_BIT: + case Z21_LAN_X_CV_POM_ACCESSORY_READ_BYTE: + col_append_fstr(pinfo->cinfo, COL_INFO, ", *** TO BE COMPLETED ***"); + break; + case Z21_LAN_X_DCC_READ_REGISTER: + temp_uint = tvb_get_guint8(tvb, offset); + proto_tree_add_uint(z21_tree, hf_z21_register, + tvb, offset, 1, temp_uint); + offset += 1; + calculated_checksum ^= temp_uint; + col_append_fstr(pinfo->cinfo, COL_INFO, ", Register%d", + temp_uint); + proto_item_append_text(z21_tree, ", Register%d", + temp_uint); + break; + case Z21_LAN_X_DCC_WRITE_REGISTER: + temp_uint = tvb_get_guint16(tvb, offset, ENC_BIG_ENDIAN); + proto_tree_add_uint(z21_tree, hf_z21_register, + tvb, offset, 1, temp_uint >> 8); + offset += 1; + calculated_checksum ^= temp_uint >> 8; + proto_tree_add_uint(z21_tree, hf_z21_register_value, + tvb, offset, 1, temp_uint & 0xff); + offset += 1; + calculated_checksum ^= temp_uint & 0xff; + col_append_fstr(pinfo->cinfo, COL_INFO, ", Register%d, Value=%d", + temp_uint >> 8, temp_uint & 0xff); + proto_item_append_text(z21_tree, ", Register%d, Value: %d", + temp_uint >> 8, temp_uint & 0xff); + break; + case Z21_LAN_X_MM_WRITE_BYTE: + /* Skip one zero byte */ + offset += 1; + temp_uint = tvb_get_guint16(tvb, offset, ENC_BIG_ENDIAN); + proto_tree_add_uint(z21_tree, hf_z21_register, + tvb, offset, 1, temp_uint >> 8); + offset += 1; + calculated_checksum ^= temp_uint >> 8; + proto_tree_add_uint(z21_tree, hf_z21_register_value, + tvb, offset, 1, temp_uint & 0xff); + offset += 1; + calculated_checksum ^= temp_uint & 0xff; + col_append_fstr(pinfo->cinfo, COL_INFO, ", Register%d, Value=%d", + temp_uint >> 8, temp_uint & 0xff); + proto_item_append_text(z21_tree, ", Register%d, Value: %d", + temp_uint >> 8, temp_uint & 0xff); + break; + case Z21_LAN_X_GET_FIRMWARE_VERSION_REPLY: + version = tvb_get_guint16(tvb, offset, ENC_BIG_ENDIAN); + buffer = wmem_strdup_printf(pinfo->pool, "%x.%02x", + version >> 8, version & 0xff); + proto_tree_add_string(z21_tree, hf_z21_firmware_version, + tvb, offset, 2, buffer); + offset += 2; + calculated_checksum ^= version >> 8; + calculated_checksum ^= version & 0xFF; + col_append_fstr(pinfo->cinfo, COL_INFO, ", Version=%s", + buffer); + } + + /* Calculate checksum for the rest of the bytes (if any) for now */ + while (offset < datalen-1) { + one_byte = tvb_get_guint8(tvb, offset); + offset += 1; + calculated_checksum ^= one_byte; + } + /* No more data in the X-BUS command, read the checksum */ + temp_ti = proto_tree_add_item_ret_uint(z21_tree, hf_z21_checksum, + tvb, offset, 1, ENC_NA, &checksum); + if (checksum != calculated_checksum) { + expert_add_info_format(pinfo, temp_ti, &ei_z21_invalid_checksum, + "Invalid checksum, calculated: 0x%02x", calculated_checksum); + } + } + else { + /* Not X-BUS */ + command_ti = proto_tree_add_uint(z21_tree, hf_z21_command, + tvb, offset, 2, command); + offset += 2; + update_command_field(command_ti, command); + col_add_fstr(pinfo->cinfo, COL_INFO, "Command=%s", + val_to_str_const(command, z21_command_vals, "unknown")); + proto_item_append_text(z21_tree, ", Command: %s", + val_to_str_const(command, z21_command_vals, "unknown")); + switch (command) { + case Z21_LAN_GET_SERIAL_NUMBER: + if (datalen == 8) { + unsigned serial; + proto_tree_add_item_ret_uint(z21_tree, hf_z21_serial_number, + tvb, offset, 4, ENC_LITTLE_ENDIAN, &serial); + offset += 4; + col_append_fstr(pinfo->cinfo, COL_INFO, ", Serial number: %d", + serial); + } + break; + case Z21_LAN_SYSTEMSTATE_DATACHANGED: + main_current = tvb_get_gint16(tvb, offset, ENC_LITTLE_ENDIAN); + proto_tree_add_int_format_value(z21_tree, hf_z21_main_current, + tvb, offset, 2, main_current, "%d mA", main_current); + offset += 2; + + temp_gint32 = tvb_get_gint16(tvb, offset, ENC_LITTLE_ENDIAN); + proto_tree_add_int_format_value(z21_tree, hf_z21_prog_current, + tvb, offset, 2, temp_gint32, "%d mA", temp_gint32); + offset += 2; + + temp_gint32 = tvb_get_gint16(tvb, offset, ENC_LITTLE_ENDIAN); + proto_tree_add_int_format_value(z21_tree, hf_z21_filtered_main_current, + tvb, offset, 2, temp_gint32, "%d mA", temp_gint32); + offset += 2; + + temp_gint32 = tvb_get_gint16(tvb, offset, ENC_LITTLE_ENDIAN); + proto_tree_add_int_format_value(z21_tree, hf_z21_temperature, + tvb, offset, 2, temp_gint32, "%d°C", temp_gint32); + offset += 2; + col_append_fstr(pinfo->cinfo, COL_INFO, + ", Temperature=%d°C", temp_gint32); + + temp_uint = tvb_get_guint16(tvb, offset, ENC_LITTLE_ENDIAN); + temp_float = (float)temp_uint / 1000; + proto_tree_add_float_format_value(z21_tree, hf_z21_supply_voltage, + tvb, offset, 2, temp_float, "%.3f V", temp_float); + offset += 2; + col_append_fstr(pinfo->cinfo, COL_INFO, + ", Track=%.3f V/%d mA", temp_float, main_current); + + temp_uint = tvb_get_guint16(tvb, offset, ENC_LITTLE_ENDIAN); + temp_float = (float)temp_uint / 1000; + proto_tree_add_float_format_value(z21_tree, hf_z21_track_voltage, + tvb, offset, 2, temp_float, "%.3f V", temp_float); + offset += 2; + + proto_tree_add_bitmask(z21_tree, tvb, offset, hf_z21_central_state, + ett_z21, state_bits_byte1, ENC_NA); + offset += 1; + proto_tree_add_bitmask(z21_tree, tvb, offset, hf_z21_central_state_ex, + ett_z21, state_bits_byte2, ENC_NA); + offset += 1; + proto_tree_add_item(z21_tree, hf_z21_systemstate_reserved, + tvb, offset, 1, ENC_NA); + offset += 1; + temp_uint = tvb_get_guint8(tvb, offset); + if (temp_uint == 0) { + /* Don't interpret the flags */ + proto_tree_add_uint_format_value(z21_tree, hf_z21_capabilities, + tvb, offset, 1, 0, "0x00 (Capability flags not supported)"); + } + else { + proto_tree_add_bitmask(z21_tree, tvb, offset, hf_z21_capabilities, + ett_z21, capability_bits, ENC_NA); + } + offset += 1; + break; + case Z21_LAN_RMBUS_GETDATA: + proto_tree_add_item_ret_uint(z21_tree, hf_z21_rmbus_group, + tvb, offset, 1, ENC_NA, &temp_uint); + offset += 1; + col_append_fstr(pinfo->cinfo, COL_INFO, ", Group=%d", temp_uint); + proto_item_append_text(z21_tree, ", Group: %d", temp_uint); + break; + case Z21_LAN_RMBUS_DATACHANGED: + proto_tree_add_item_ret_uint(z21_tree, hf_z21_rmbus_group, + tvb, offset, 1, ENC_NA, &temp_uint); + offset += 1; + col_append_fstr(pinfo->cinfo, COL_INFO, ", Group=%d", temp_uint); + proto_item_append_text(z21_tree, ", Group: %d", temp_uint); + proto_tree_add_item(z21_tree, hf_z21_rmbus_feedbacks, tvb, offset, 10, ENC_NA); + offset += 10; + break; + case Z21_LAN_RMBUS_PROGRAMMODULE: + proto_tree_add_item_ret_uint(z21_tree, hf_z21_rmbus_address, + tvb, offset, 1, ENC_NA, &temp_uint); + col_append_fstr(pinfo->cinfo, COL_INFO, ", Address=%d", temp_uint); + proto_item_append_text(z21_tree, ", Address: %d", temp_uint); + offset += 1; + break; + case Z21_LAN_RAILCOM_DATACHANGED: + proto_tree_add_item_ret_uint(z21_tree, hf_z21_loco_address, + tvb, offset, 2, ENC_LITTLE_ENDIAN, &temp_uint); + offset += 2; + col_append_fstr(pinfo->cinfo, COL_INFO, ", Loco=%d", temp_uint); + proto_item_append_text(z21_tree, ", Loco: %d", temp_uint); + proto_tree_add_item(z21_tree, hf_z21_railcom_receive_counter, tvb, offset, 4, ENC_LITTLE_ENDIAN); + offset += 4; + proto_tree_add_item(z21_tree, hf_z21_railcom_error_counter, tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; + proto_tree_add_item(z21_tree, hf_z21_railcom_reserved1, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(z21_tree, hf_z21_railcom_options, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(z21_tree, hf_z21_railcom_speed, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(z21_tree, hf_z21_railcom_qos, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(z21_tree, hf_z21_railcom_reserved2, tvb, offset, 1, ENC_NA); + offset += 1; + break; + case Z21_LAN_RAILCOM_GETDATA: + proto_tree_add_item(z21_tree, hf_z21_railcom_type, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(z21_tree, hf_z21_loco_address, tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; + break; + case Z21_LAN_LOCONET_FROM_LAN: + case Z21_LAN_LOCONET_Z21_RX: + case Z21_LAN_LOCONET_Z21_TX: + proto_tree_add_item(z21_tree, hf_z21_loconet_message, + tvb, offset, datalen-4, ENC_NA); + offset += datalen-4; + break; + case Z21_LAN_LOCONET_DISPATCH_ADDR: + proto_tree_add_item_ret_uint(z21_tree, hf_z21_loco_address, + tvb, offset, 2, ENC_LITTLE_ENDIAN, &temp_uint); + offset += 2; + col_append_fstr(pinfo->cinfo, COL_INFO, ", Loco=%d", temp_uint); + proto_item_append_text(z21_tree, ", Loco: %d", temp_uint); + if (datalen > 6) { + /* Response from Z21 */ + proto_tree_add_item(z21_tree, hf_z21_loconet_result, tvb, offset, 1, ENC_NA); + offset += 1; + } + break; + case Z21_LAN_LOCONET_DETECTOR: + proto_tree_add_item(z21_tree, hf_z21_loconet_type, tvb, offset, 1, ENC_NA); + offset += 1; + if (datalen == 7) { + /* This is request */ + proto_tree_add_item(z21_tree, hf_z21_loconet_report_address, + tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; + } + else { + /* This is reply */ + proto_tree_add_item(z21_tree, hf_z21_loconet_feedback_address, + tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; + proto_tree_add_item(z21_tree, hf_z21_loconet_info, + tvb, offset, datalen-7, ENC_NA); + offset += datalen-7; + } + break; + case Z21_LAN_CAN_DETECTOR: + if (datalen == 7) { + /* This is request */ + proto_tree_add_item(z21_tree, hf_z21_can_type, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item_ret_uint(z21_tree, hf_z21_can_network_id, + tvb, offset, 2, ENC_LITTLE_ENDIAN, &temp_uint); + offset += 2; + col_append_fstr(pinfo->cinfo, COL_INFO, ", NetworkID=%d", temp_uint); + proto_item_append_text(z21_tree, ", NetworkID: %d", temp_uint); + } + else { + /* This is reply */ + proto_tree_add_item_ret_uint(z21_tree, hf_z21_can_network_id, + tvb, offset, 2, ENC_LITTLE_ENDIAN, &temp_uint); + offset += 2; + col_append_fstr(pinfo->cinfo, COL_INFO, ", NetworkID=%d", temp_uint); + proto_item_append_text(z21_tree, ", NetworkID: %d", temp_uint); + proto_tree_add_item(z21_tree, hf_z21_can_module_address, + tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; + proto_tree_add_item(z21_tree, hf_z21_can_port, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(z21_tree, hf_z21_can_type, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(z21_tree, hf_z21_can_value1, + tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; + proto_tree_add_item(z21_tree, hf_z21_can_value2, + tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; + } + break; + case Z21_LAN_CAN_DEVICE_GET_DESCRIPTION: + case Z21_LAN_CAN_DEVICE_SET_DESCRIPTION: + proto_tree_add_item_ret_uint(z21_tree, hf_z21_can_network_id, + tvb, offset, 2, ENC_LITTLE_ENDIAN, &temp_uint); + offset += 2; + col_append_fstr(pinfo->cinfo, COL_INFO, ", NetworkID=%d", temp_uint); + proto_item_append_text(z21_tree, ", NetworkID: %d", temp_uint); + if (datalen > 6) { + proto_tree_add_item(z21_tree, hf_z21_can_booster_name, + tvb, offset, 16, ENC_ISO_8859_1); + offset += 16; + } + break; + case Z21_LAN_CAN_BOOSTER_SYSTEMSTATE_CHGD: + proto_tree_add_item_ret_uint(z21_tree, hf_z21_can_network_id, + tvb, offset, 2, ENC_LITTLE_ENDIAN, &temp_uint); + offset += 2; + col_append_fstr(pinfo->cinfo, COL_INFO, ", NetworkID=%d", temp_uint); + proto_item_append_text(z21_tree, ", NetworkID: %d", temp_uint); + proto_tree_add_item(z21_tree, hf_z21_can_booster_output_port, + tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; + proto_tree_add_bitmask(z21_tree, tvb, offset, + hf_z21_can_booster_state, ett_z21, booster_state_bits, ENC_LITTLE_ENDIAN); + offset += 2; + temp_uint = tvb_get_gint16(tvb, offset, ENC_LITTLE_ENDIAN); + proto_tree_add_uint_format_value(z21_tree, hf_z21_can_booster_vcc, + tvb, offset, 2, temp_uint, "%d mV", temp_uint); + offset += 2; + temp_uint = tvb_get_gint16(tvb, offset, ENC_LITTLE_ENDIAN); + proto_tree_add_uint_format_value(z21_tree, hf_z21_can_booster_current, + tvb, offset, 2, temp_uint, "%d mA", temp_uint); + offset += 2; + break; + case Z21_LAN_CAN_BOOSTER_SET_TRACKPOWER: + proto_tree_add_item_ret_uint(z21_tree, hf_z21_can_network_id, + tvb, offset, 2, ENC_LITTLE_ENDIAN, &temp_uint); + offset += 2; + col_append_fstr(pinfo->cinfo, COL_INFO, ", NetworkID=%d", temp_uint); + proto_item_append_text(z21_tree, ", NetworkID: %d", temp_uint); + proto_tree_add_item(z21_tree, hf_z21_can_booster_power, tvb, offset, 1, ENC_NA); + offset += 1; + break; + case Z21_LAN_ZLINK_GET_HWINFO: + proto_tree_add_item(z21_tree, hf_z21_zlink_message_type, tvb, offset, 1, ENC_NA); + offset += 1; + if (datalen > 5) { + proto_tree_add_item(z21_tree, hf_z21_zlink_hwid, + tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; + proto_tree_add_item(z21_tree, hf_z21_zlink_fw_major, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(z21_tree, hf_z21_zlink_fw_minor, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(z21_tree, hf_z21_zlink_fw_build, tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; + proto_tree_add_item(z21_tree, hf_z21_zlink_mac, tvb, offset, 18, ENC_ASCII); + offset += 18; + proto_tree_add_item(z21_tree, hf_z21_zlink_name, tvb, offset, 33, ENC_ISO_8859_1); + offset += 18; + proto_tree_add_item(z21_tree, hf_z21_zlink_reserved, tvb, offset, 1, ENC_NA); + offset += 1; + } + break; + case Z21_LAN_BOOSTER_GET_DESCRIPTION: + case Z21_LAN_BOOSTER_SET_DESCRIPTION: + if (datalen > 4) { + /* SET_DESCRIPTION or reply to GET_DESCRIPTION */ + guint8 *buf = tvb_get_stringz_enc(pinfo->pool, tvb, offset, NULL, ENC_ISO_8859_1); + if (buf[0] == 0xff) { + /* Interpreted as an empty name */ + proto_tree_add_string(z21_tree, hf_z21_booster_name, tvb, offset, 32, ""); + } + else { + proto_tree_add_string(z21_tree, hf_z21_booster_name, tvb, offset, 32, buf); + } + offset += 32; + } + break; + case Z21_LAN_BOOSTER_SYSTEMSTATE_GETDATA: + case Z21_LAN_DECODER_SYSTEMSTATE_GETDATA: + break; + case Z21_LAN_DECODER_GET_DESCRIPTION: + case Z21_LAN_DECODER_SET_DESCRIPTION: + if (datalen > 4) { + /* SET_DESCRIPTION or reply to GET_DESCRIPTION */ + guint8 *buf = tvb_get_stringz_enc(pinfo->pool, tvb, offset, NULL, ENC_ISO_8859_1); + if (buf[0] == 0xff) { + /* Interpreted as an empty name */ + proto_tree_add_string(z21_tree, hf_z21_decoder_name, tvb, offset, 32, ""); + } + else { + proto_tree_add_string(z21_tree, hf_z21_decoder_name, tvb, offset, 32, buf); + } + offset += 32; + } + break; + case Z21_LAN_BOOSTER_SET_POWER: + proto_tree_add_item_ret_uint(z21_tree, hf_z21_booster_port, + tvb, offset, 1, ENC_NA, &temp_uint); + offset += 1; + col_append_fstr(pinfo->cinfo, COL_INFO, ", Port=%d", temp_uint); + proto_item_append_text(z21_tree, ", Port: %d", temp_uint); + proto_tree_add_item_ret_uint(z21_tree, hf_z21_booster_port_state, + tvb, offset, 1, ENC_NA, &temp_uint); + offset += 1; + col_append_fstr(pinfo->cinfo, COL_INFO, ", State=%d", temp_uint); + proto_item_append_text(z21_tree, ", State: %d", temp_uint); + break; + case Z21_LAN_BOOSTER_SYSTEMSTATE_DATACHANGED: + /* To be expanded later... */ + proto_tree_add_item(z21_tree, hf_z21_booster_state_data, + tvb, offset, 24, ENC_NA); + offset += 24; + break; + case Z21_LAN_DECODER_SYSTEMSTATE_DATACHANGED: + /* To be expanded later... */ + /* Data is variable length */ + proto_tree_add_item(z21_tree, hf_z21_decoder_state_data, + tvb, offset, datalen-4, ENC_NA); + offset += datalen-4; + break; + } + if (offset < datalen) { + /* Just dump all the rest, if any */ + proto_tree_add_item(z21_tree, hf_z21_data, tvb, offset, datalen-offset, ENC_NA); + offset += datalen-offset; + } + } + return offset; +} + +static unsigned +get_z21_pdu_len(packet_info *pinfo _U_, tvbuff_t *tvb, int offset, void *data _U_) +{ + return tvb_get_guint16(tvb, offset, ENC_LITTLE_ENDIAN); +} + +static gboolean +check_z21_header(packet_info *pinfo _U_, tvbuff_t *tvb _U_, int offset _U_, void *data _U_) +{ + return TRUE; +} + +static int +dissect_z21(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data) +{ + return udp_dissect_pdus(tvb, pinfo, tree, Z21_MIN_LENGTH, + check_z21_header, get_z21_pdu_len, dissect_z21_pdu, data); +} + +/* Register the protocol with Wireshark. + * + * This format is required because a script is used to build the C function that + * calls all the protocol registration. + */ +void +proto_register_z21(void) +{ + expert_module_t *expert_z21; + + static hf_register_info hf[] = { + { &hf_z21_datalen, + { "Data length", "z21.datalen", + FT_UINT16, BASE_DEC, NULL, 0x0, + NULL, HFILL } + }, + { &hf_z21_command, + { "Command", "z21.command", + FT_UINT32, BASE_HEX|BASE_NO_DISPLAY_VALUE, VALS(z21_command_vals), 0x0, + NULL, HFILL } + }, + { &hf_z21_x_bus, + { "X-BUS", "z21.xbus", + FT_BOOLEAN, BASE_NONE, NULL, 0x0, + NULL, HFILL } + }, + { &hf_z21_serial_number, + { "Serial number", "z21.serialnumber", + FT_UINT32, BASE_DEC, NULL, 0x0, + NULL, HFILL } + }, + { &hf_z21_checksum, + { "Checksum", "z21.checksum", + FT_UINT8, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_z21_main_current, + { "Main track current", "z21.maincurrent", + FT_INT16, BASE_DEC, NULL, 0x0, + NULL, HFILL } + }, + { &hf_z21_prog_current, + { "Programming track current", "z21.progcurrent", + FT_INT16, BASE_DEC, NULL, 0x0, + NULL, HFILL } + }, + { &hf_z21_filtered_main_current, + { "Filtered main track current", "z21.filteredmaincurrent", + FT_INT16, BASE_DEC, NULL, 0x0, + NULL, HFILL } + }, + { &hf_z21_temperature, + { "Command station temperature", "z21.temperature", + FT_INT16, BASE_DEC, NULL, 0x0, + NULL, HFILL } + }, + { &hf_z21_supply_voltage, + { "Supply voltage", "z21.supplyvoltage", + FT_FLOAT, BASE_DEC, NULL, 0x0, + NULL, HFILL } + }, + { &hf_z21_track_voltage, + { "Track voltage", "z21.trackvoltage", + FT_FLOAT, BASE_DEC, NULL, 0x0, + NULL, HFILL } + }, + { &hf_z21_central_state, + { "Central state, first byte", "z21.centralstate1", + FT_UINT8, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_z21_central_state_ex, + { "Central state, second byte", "z21.centralstate2", + FT_UINT8, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_z21_systemstate_reserved, + { "Reserved", "z21.systemstatereserved", + FT_UINT8, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_z21_capabilities, + { "Capabilities", "z21.capabilities", + FT_UINT8, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_z21_status, + { "Status", "z21.status", + FT_UINT8, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_z21_state_emergency_stop, + { "Emergency stop", "z21.state.emergencystop", + FT_BOOLEAN, 8, TFS(&tfs_yes_no), 0x01, + NULL, HFILL } + }, + { &hf_z21_state_track_voltage_off, + { "Track voltage off", "z21.state.trackvoltageoff", + FT_BOOLEAN, 8, TFS(&tfs_yes_no), 0x02, + NULL, HFILL } + }, + { &hf_z21_state_short_circuit, + { "Short circuit", "z21.state.shortcircuit", + FT_BOOLEAN, 8, TFS(&tfs_yes_no), 0x04, + NULL, HFILL } + }, + { &hf_z21_state_programming_mode, + { "Programming mode", "z21.state.programmingmode", + FT_BOOLEAN, 8, TFS(&tfs_yes_no), 0x20, + NULL, HFILL } + }, + { &hf_z21_state_high_temperature, + { "High temperature", "z21.state.hightemperature", + FT_BOOLEAN, 8, TFS(&tfs_yes_no), 0x01, + NULL, HFILL } + }, + { &hf_z21_state_power_lost, + { "Power lost", "z21.state.powerlost", + FT_BOOLEAN, 8, TFS(&tfs_yes_no), 0x02, + NULL, HFILL } + }, + { &hf_z21_state_short_circuit_external, + { "External short circuit", "z21.state.externalshortcircuit", + FT_BOOLEAN, 8, TFS(&tfs_yes_no), 0x04, + NULL, HFILL } + }, + { &hf_z21_state_short_circuit_internal, + { "Internal short circuit", "z21.state.internalshortcircuit", + FT_BOOLEAN, 8, TFS(&tfs_yes_no), 0x08, + NULL, HFILL } + }, + { &hf_z21_state_rcn_213, + { "RCN-213 turnout addressing", "z21.state.rcn213addressing", + FT_BOOLEAN, 8, TFS(&tfs_yes_no), 0x20, + NULL, HFILL } + }, + { &hf_z21_capability_dcc, + { "DCC capability", "z21.capability.dcc", + FT_BOOLEAN, 8, TFS(&tfs_yes_no), 0x01, + NULL, HFILL } + }, + { &hf_z21_capability_mm, + { "MM capability", "z21.capability.mm", + FT_BOOLEAN, 8, TFS(&tfs_yes_no), 0x02, + NULL, HFILL } + }, + { &hf_z21_capability_reserved, + { "Reserved capability", "z21.capability.reserved", + FT_BOOLEAN, 8, TFS(&tfs_yes_no), 0x04, + NULL, HFILL } + }, + { &hf_z21_capability_railcom, + { "RailCom capability", "z21.capability.railcom", + FT_BOOLEAN, 8, TFS(&tfs_yes_no), 0x08, + NULL, HFILL } + }, + { &hf_z21_capability_loco_cmds, + { "Accepts LAN commands for locomotive decoders", "z21.capability.lococmds", + FT_BOOLEAN, 8, TFS(&tfs_yes_no), 0x10, + NULL, HFILL } + }, + { &hf_z21_capability_accessory_cmds, + { "Accepts LAN commands for accessory decoders", "z21.capability.accessorycmds", + FT_BOOLEAN, 8, TFS(&tfs_yes_no), 0x20, + NULL, HFILL } + }, + { &hf_z21_capability_detector_cmds, + { "Accepts LAN commands for detectors", "z21.capability.detectorcmds", + FT_BOOLEAN, 8, TFS(&tfs_yes_no), 0x40, + NULL, HFILL } + }, + { &hf_z21_capability_needs_unlock_code, + { "Needs unlock code", "z21.capability.needsunlockcode", + FT_BOOLEAN, 8, TFS(&tfs_yes_no), 0x80, + NULL, HFILL } + }, + { &hf_z21_loco_address, + { "Locomotive address", "z21.locoaddress", + FT_UINT16, BASE_DEC, NULL, 0x0, + NULL, HFILL } + }, + { &hf_z21_loco_direction_and_speed, + { "Locomotive direction and speed", "z21.locodirectionandspeed", + FT_UINT8, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_z21_loco_direction, + { "Locomotive direction", "z21.locodirection", + FT_BOOLEAN, 8, TFS(&tfs_forward_reverse), 0x80, + NULL, HFILL } + }, + { &hf_z21_loco_speed, + { "Locomotive speed", "z21.locospeed", + FT_UINT8, BASE_HEX, NULL, 0x7F, + NULL, HFILL } + }, + { &hf_z21_loco_info_mm, + { "Locomotive is MM (Märklin-Motorola)", "z21.locomm", + FT_BOOLEAN, 8, TFS(&tfs_yes_no), 0x10, + NULL, HFILL } + }, + { &hf_z21_loco_info_busy, + { "Locomotive is busy", "z21.locoinfobusy", + FT_BOOLEAN, 8, TFS(&tfs_yes_no), 0x08, + "Locomotive is controlled by another X-BUS handset controller", HFILL } + }, + { &hf_z21_loco_info_speed_steps, + { "Locomotive speed steps", "z21.locoinfospeedsteps", + FT_UINT8, BASE_DEC, VALS(z21_loco_info_speed_steps_vals), 0x07, + NULL, HFILL } + }, + { &hf_z21_loco_info_direction, + { "Locomotive direction", "z21.locoinfodirection", + FT_BOOLEAN, 8, TFS(&tfs_forward_reverse), 0x80, + NULL, HFILL } + }, + { &hf_z21_loco_info_speed, + { "Locomotive speed", "z21.locoinfospeed", + FT_UINT8, BASE_HEX, NULL, 0x7f, + NULL, HFILL } + }, + { &hf_z21_loco_info_double_traction, + { "Double traction", "z21.locoinfodoubletraction", + FT_BOOLEAN, 8, TFS(&tfs_yes_no), 0x40, + NULL, HFILL } + }, + { &hf_z21_loco_info_smartsearch, + { "Smartsearch", "z21.locoinfosmartsearch", + FT_BOOLEAN, 8, TFS(&tfs_yes_no), 0x20, + NULL, HFILL } + }, + { &hf_z21_loco_info_f0, + { "Function F0 (lights)", "z21.locoinfof0", + FT_BOOLEAN, 8, TFS(&tfs_yes_no), 0x10, + NULL, HFILL } + }, + { &hf_z21_loco_info_f4, + { "Function F4", "z21.locoinfof4", + FT_BOOLEAN, 8, TFS(&tfs_yes_no), 0x08, + NULL, HFILL } + }, + { &hf_z21_loco_info_f3, + { "Function F3", "z21.locoinfof3", + FT_BOOLEAN, 8, TFS(&tfs_yes_no), 0x04, + NULL, HFILL } + }, + { &hf_z21_loco_info_f2, + { "Function F2", "z21.locoinfof2", + FT_BOOLEAN, 8, TFS(&tfs_yes_no), 0x02, + NULL, HFILL } + }, + { &hf_z21_loco_info_f1, + { "Function F1", "z21.locoinfof1", + FT_BOOLEAN, 8, TFS(&tfs_yes_no), 0x01, + NULL, HFILL } + }, + { &hf_z21_loco_info_f12, + { "Function F12", "z21.locoinfof12", + FT_BOOLEAN, 8, TFS(&tfs_yes_no), 0x80, + NULL, HFILL } + }, + { &hf_z21_loco_info_f11, + { "Function F11", "z21.locoinfof11", + FT_BOOLEAN, 8, TFS(&tfs_yes_no), 0x40, + NULL, HFILL } + }, + { &hf_z21_loco_info_f10, + { "Function F10", "z21.locoinfof10", + FT_BOOLEAN, 8, TFS(&tfs_yes_no), 0x20, + NULL, HFILL } + }, + { &hf_z21_loco_info_f9, + { "Function F9", "z21.locoinfof9", + FT_BOOLEAN, 8, TFS(&tfs_yes_no), 0x10, + NULL, HFILL } + }, + { &hf_z21_loco_info_f8, + { "Function F8", "z21.locoinfof8", + FT_BOOLEAN, 8, TFS(&tfs_yes_no), 0x08, + NULL, HFILL } + }, + { &hf_z21_loco_info_f7, + { "Function F7", "z21.locoinfof7", + FT_BOOLEAN, 8, TFS(&tfs_yes_no), 0x04, + NULL, HFILL } + }, + { &hf_z21_loco_info_f6, + { "Function F6", "z21.locoinfof6", + FT_BOOLEAN, 8, TFS(&tfs_yes_no), 0x02, + NULL, HFILL } + }, + { &hf_z21_loco_info_f5, + { "Function F5", "z21.locoinfof5", + FT_BOOLEAN, 8, TFS(&tfs_yes_no), 0x01, + NULL, HFILL } + }, + { &hf_z21_loco_info_f20, + { "Function F20", "z21.locoinfof20", + FT_BOOLEAN, 8, TFS(&tfs_yes_no), 0x80, + NULL, HFILL } + }, + { &hf_z21_loco_info_f19, + { "Function F19", "z21.locoinfof19", + FT_BOOLEAN, 8, TFS(&tfs_yes_no), 0x40, + NULL, HFILL } + }, + { &hf_z21_loco_info_f18, + { "Function F18", "z21.locoinfof18", + FT_BOOLEAN, 8, TFS(&tfs_yes_no), 0x20, + NULL, HFILL } + }, + { &hf_z21_loco_info_f17, + { "Function F17", "z21.locoinfof17", + FT_BOOLEAN, 8, TFS(&tfs_yes_no), 0x10, + NULL, HFILL } + }, + { &hf_z21_loco_info_f16, + { "Function F16", "z21.locoinfof16", + FT_BOOLEAN, 8, TFS(&tfs_yes_no), 0x08, + NULL, HFILL } + }, + { &hf_z21_loco_info_f15, + { "Function F15", "z21.locoinfof15", + FT_BOOLEAN, 8, TFS(&tfs_yes_no), 0x04, + NULL, HFILL } + }, + { &hf_z21_loco_info_f14, + { "Function F14", "z21.locoinfof14", + FT_BOOLEAN, 8, TFS(&tfs_yes_no), 0x02, + NULL, HFILL } + }, + { &hf_z21_loco_info_f13, + { "Function F13", "z21.locoinfof13", + FT_BOOLEAN, 8, TFS(&tfs_yes_no), 0x01, + NULL, HFILL } + }, + { &hf_z21_loco_info_f28, + { "Function F28", "z21.locoinfof28", + FT_BOOLEAN, 8, TFS(&tfs_yes_no), 0x80, + NULL, HFILL } + }, + { &hf_z21_loco_info_f27, + { "Function F27", "z21.locoinfof27", + FT_BOOLEAN, 8, TFS(&tfs_yes_no), 0x40, + NULL, HFILL } + }, + { &hf_z21_loco_info_f26, + { "Function F26", "z21.locoinfof26", + FT_BOOLEAN, 8, TFS(&tfs_yes_no), 0x20, + NULL, HFILL } + }, + { &hf_z21_loco_info_f25, + { "Function F25", "z21.locoinfof25", + FT_BOOLEAN, 8, TFS(&tfs_yes_no), 0x10, + NULL, HFILL } + }, + { &hf_z21_loco_info_f24, + { "Function F24", "z21.locoinfof24", + FT_BOOLEAN, 8, TFS(&tfs_yes_no), 0x08, + NULL, HFILL } + }, + { &hf_z21_loco_info_f23, + { "Function F23", "z21.locoinfof23", + FT_BOOLEAN, 8, TFS(&tfs_yes_no), 0x04, + NULL, HFILL } + }, + { &hf_z21_loco_info_f22, + { "Function F22", "z21.locoinfof22", + FT_BOOLEAN, 8, TFS(&tfs_yes_no), 0x02, + NULL, HFILL } + }, + { &hf_z21_loco_info_f21, + { "Function F21", "z21.locoinfof21", + FT_BOOLEAN, 8, TFS(&tfs_yes_no), 0x01, + NULL, HFILL } + }, + { &hf_z21_loco_info_f31, + { "Function F31", "z21.locoinfof31", + FT_BOOLEAN, 8, TFS(&tfs_yes_no), 0x04, + NULL, HFILL } + }, + { &hf_z21_loco_info_f30, + { "Function F30", "z21.locoinfof30", + FT_BOOLEAN, 8, TFS(&tfs_yes_no), 0x02, + NULL, HFILL } + }, + { &hf_z21_loco_info_f29, + { "Function F29", "z21.locoinfof29", + FT_BOOLEAN, 8, TFS(&tfs_yes_no), 0x01, + NULL, HFILL } + }, + { &hf_z21_loco_info_extensions, + { "Extensions", "z21.locoinfoextensions", + FT_BYTES, BASE_NONE, NULL, 0x0, + NULL, HFILL } + }, + { &hf_z21_speed_steps, + { "Speed steps", "z21.speedsteps", + FT_UINT8, BASE_DEC, NULL, 0x0, + NULL, HFILL } + }, + { &hf_z21_firmware_version, + { "Firmware version", "z21.firmwareversion", + FT_STRING, BASE_NONE, NULL, 0x0, + NULL, HFILL } + }, + { &hf_z21_loco_func_switch_type, + { "Locomotive function switch type", "z21.locofunctionswitchtype", + FT_UINT8, BASE_DEC, VALS(z21_loco_func_vals), 0xc0, + NULL, HFILL } + }, + { &hf_z21_loco_func_index, + { "Locomotive function index", "z21.locofunctionindex", + FT_UINT8, BASE_DEC, NULL, 0x3f, + NULL, HFILL } + }, + { &hf_z21_function_address, + { "Function address", "z21.functionaddress", + FT_UINT16, BASE_DEC, NULL, 0x0, + NULL, HFILL } + }, + { &hf_z21_turnout_state, + { "Turnout state", "z21.turnoutstate", + FT_UINT8, BASE_DEC, VALS(z21_turnout_state_vals), 0x03, + NULL, HFILL } + }, + { &hf_z21_turnout_queue_bit, + { "Queue the turnout command", "z21.turnoutqueue", + FT_BOOLEAN, 8, TFS(&tfs_yes_no), 0x20, + NULL, HFILL } + }, + { &hf_z21_turnout_activate_bit, + { "Turnout command", "z21.turnoutcommand", + FT_BOOLEAN, 8, TFS(&tfs_turnout_command), 0x08, + NULL, HFILL } + }, + { &hf_z21_turnout_output_bit, + { "Select turnout output", "z21.turnoutoutput", + FT_BOOLEAN, 8, TFS(&tfs_turnout_output), 0x01, + NULL, HFILL } + }, + { &hf_z21_accessory_address, + { "Accessory address", "z21.accessoryaddress", + FT_UINT16, BASE_DEC, NULL, 0x0, + NULL, HFILL } + }, + { &hf_z21_accessory_state, + { "Accessory state", "z21.accessorystate", + FT_UINT8, BASE_DEC, NULL, 0x0, + NULL, HFILL } + }, + { &hf_z21_accessory_status, + { "Accessory status", "z21.accessorystatus", + FT_UINT8, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_z21_cv_address, + { "CV address", "z21.cvaddress", + FT_UINT16, BASE_DEC, NULL, 0x0, + NULL, HFILL } + }, + { &hf_z21_cv_value, + { "CV value", "z21.cvvalue", + FT_UINT8, BASE_DEC, NULL, 0x0, + NULL, HFILL } + }, + { &hf_z21_register, + { "Register", "z21.register", + FT_UINT8, BASE_DEC, NULL, 0x0, + NULL, HFILL } + }, + { &hf_z21_register_value, + { "Register value", "z21.registervalue", + FT_UINT8, BASE_DEC, NULL, 0x0, + NULL, HFILL } + }, + { &hf_z21_pom_operation, + { "POM operation", "z21.pomoperation", + FT_UINT16, BASE_HEX, VALS(z21_pom_operation_vals), 0x0, + NULL, HFILL } + }, + { &hf_z21_cv_bit_position, + { "CV bit position", "z21.cvbitposition", + FT_UINT8, BASE_DEC, NULL, 0x07, + NULL, HFILL } + }, + { &hf_z21_cv_bit_value, + { "CV bit value", "z21.cvbitvalue", + FT_BOOLEAN, 8, TFS(&tfs_set_notset), 0x08, + NULL, HFILL } + }, + { &hf_z21_rmbus_group, + { "R-BUS group index", "z21.rbusgroup", + FT_UINT8, BASE_DEC, NULL, 0x0, + NULL, HFILL } + }, + { &hf_z21_rmbus_feedbacks, + { "R-BUS feedbacks", "z21.rbusfeedbacks", + FT_BYTES, BASE_NONE|SEP_SPACE, NULL, 0x0, + NULL, HFILL } + }, + { &hf_z21_rmbus_address, + { "R-BUS feedback module address", "z21.rbusaddress", + FT_UINT8, BASE_DEC, NULL, 0x0, + NULL, HFILL } + }, + { &hf_z21_railcom_receive_counter, + { "RailCom receive counter", "z21.railcomreceives", + FT_UINT32, BASE_DEC, NULL, 0x0, + NULL, HFILL } + }, + { &hf_z21_railcom_error_counter, + { "RailCom error counter", "z21.railcomerrors", + FT_UINT16, BASE_DEC, NULL, 0x0, + NULL, HFILL } + }, + { &hf_z21_railcom_reserved1, + { "RailCom reserved 1", "z21.railcomreserved1", + FT_UINT8, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_z21_railcom_reserved2, + { "RailCom reserved 2", "z21.railcomreserved2", + FT_UINT8, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_z21_railcom_options, + { "RailCom options", "z21.railcomoptions", + FT_UINT8, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_z21_railcom_speed, + { "RailCom speed", "z21.railcomspeed", + FT_UINT8, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_z21_railcom_qos, + { "RailCom QoS", "z21.railcomqos", + FT_UINT8, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_z21_railcom_type, + { "RailCom type", "z21.railcomtype", + FT_UINT8, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_z21_loconet_message, + { "LocoNet message", "z21.loconetmessage", + FT_BYTES, BASE_NONE|SEP_SPACE, NULL, 0x0, + NULL, HFILL } + }, + { &hf_z21_loconet_result, + { "LocoNet result", "z21.loconetresult", + FT_UINT8, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_z21_loconet_type, + { "LocoNet type", "z21.loconettype", + FT_UINT8, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_z21_loconet_report_address, + { "LocoNet report address", "z21.loconetreportaddress", + FT_UINT16, BASE_DEC, NULL, 0x0, + NULL, HFILL } + }, + { &hf_z21_loconet_feedback_address, + { "LocoNet feedback address", "z21.loconetfeedbackaddress", + FT_UINT16, BASE_DEC, NULL, 0x0, + NULL, HFILL } + }, + { &hf_z21_loconet_info, + { "LocoNet info", "z21.loconetinfo", + FT_BYTES, BASE_NONE|SEP_SPACE, NULL, 0x0, + NULL, HFILL } + }, + { &hf_z21_can_type, + { "CAN type", "z21.cantype", + FT_UINT8, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_z21_can_network_id, + { "CAN network ID", "z21.cannetworkid", + FT_UINT16, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_z21_can_module_address, + { "CAN module address", "z21.canmoduleaddress", + FT_UINT16, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_z21_can_port, + { "CAN input port (pin)", "z21.canport", + FT_UINT8, BASE_DEC, NULL, 0x0, + NULL, HFILL } + }, + { &hf_z21_can_value1, + { "CAN value 1", "z21.canvalue1", + FT_UINT16, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_z21_can_value2, + { "CAN value 2", "z21.canvalue2", + FT_UINT16, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_z21_can_booster_name, + { "CAN booster name", "z21.canboostername", + FT_STRINGZ, BASE_NONE, NULL, 0x0, + NULL, HFILL } + }, + { &hf_z21_can_booster_output_port, + { "CAN booster output port", "z21.canboosteroutputport", + FT_UINT16, BASE_DEC, NULL, 0x0, + NULL, HFILL } + }, + { &hf_z21_can_booster_state, + { "CAN booster state", "z21.canboosterstate", + FT_UINT16, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_z21_can_booster_state_bg_active, + { "CAN booster brake generator active", "z21.canboosterbrakegenerator", + FT_BOOLEAN, 16, NULL, 0x0001, + NULL, HFILL } + }, + { &hf_z21_can_booster_state_short_circuit, + { "CAN booster short circuit", "z21.canboostershortcircuit", + FT_BOOLEAN, 16, NULL, 0x0020, + NULL, HFILL } + }, + { &hf_z21_can_booster_state_track_voltage_off, + { "CAN booster track voltage off", "z21.canboostertrackvoltageoff", + FT_BOOLEAN, 16, NULL, 0x0080, + NULL, HFILL } + }, + { &hf_z21_can_booster_state_railcom_active, + { "CAN booster RailCom cutout active", "z21.canboosterrailcomactive", + FT_BOOLEAN, 16, NULL, 0x0800, + NULL, HFILL } + }, + { &hf_z21_can_booster_state_output_disabled, + { "CAN booster output disabled", "z21.canboosteroutputdisabled", + FT_BOOLEAN, 16, NULL, 0x0100, + NULL, HFILL } + }, + { &hf_z21_can_booster_vcc, + { "CAN booster VCC voltage", "z21.canboostervoltage", + FT_UINT16, BASE_DEC, NULL, 0x0, + NULL, HFILL } + }, + { &hf_z21_can_booster_current, + { "CAN booster current", "z21.canboostercurrent", + FT_UINT16, BASE_DEC, NULL, 0x0, + NULL, HFILL } + }, + { &hf_z21_can_booster_power, + { "CAN booster power", "z21.canboosterpower", + FT_UINT16, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_z21_zlink_message_type, + { "zLink message type", "z21.zlinkmessagetype", + FT_UINT8, BASE_HEX, VALS(z21_zlink_message_type_vals), 0x0, + NULL, HFILL } + }, + { &hf_z21_zlink_hwid, + { "zLink hardware ID", "z21.zlinkhwid", + FT_UINT16, BASE_DEC_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_z21_zlink_fw_major, + { "zLink firmware major version", "z21.zlinkmajorversion", + FT_UINT8, BASE_DEC, NULL, 0x0, + NULL, HFILL } + }, + { &hf_z21_zlink_fw_minor, + { "zLink firmware minor version", "z21.zlinkminorversion", + FT_UINT8, BASE_DEC, NULL, 0x0, + NULL, HFILL } + }, + { &hf_z21_zlink_fw_build, + { "zLink firmware build version", "z21.zlinkbuildversion", + FT_UINT16, BASE_DEC, NULL, 0x0, + NULL, HFILL } + }, + { &hf_z21_zlink_mac, + { "zLink MAC address", "z21.zlinkmac", + FT_STRINGZ, BASE_NONE, NULL, 0x0, + NULL, HFILL } + }, + { &hf_z21_zlink_name, + { "zLink name", "z21.zlinkname", + FT_STRINGZ, BASE_NONE, NULL, 0x0, + NULL, HFILL } + }, + { &hf_z21_zlink_reserved, + { "zLink reserved", "z21.zlinkreserved", + FT_UINT8, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_z21_booster_name, + { "Booster name", "z21.boostername", + FT_STRINGZ, BASE_NONE, NULL, 0x0, + NULL, HFILL } + }, + { &hf_z21_booster_port, + { "Booster port", "z21.boosterport", + FT_UINT8, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_z21_booster_port_state, + { "Booster port state", "z21.boosterportstate", + FT_UINT8, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_z21_booster_state_data, + { "Booster state data", "z21.boosterstatedata", + FT_BYTES, BASE_NONE|SEP_SPACE, NULL, 0x0, + NULL, HFILL } + }, + { &hf_z21_decoder_name, + { "Decoder name", "z21.decodername", + FT_STRINGZ, BASE_NONE, NULL, 0x0, + NULL, HFILL } + }, + { &hf_z21_decoder_state_data, + { "Decoder state data", "z21.decoderstatedata", + FT_BYTES, BASE_NONE|SEP_SPACE, NULL, 0x0, + NULL, HFILL } + }, + { &hf_z21_data, + { "Undecoded data", "z21.data", + FT_BYTES, BASE_NONE|SEP_SPACE, NULL, 0x0, + NULL, HFILL } + }, + }; + + /* Setup protocol subtree array */ + static int *ett[] = { + &ett_z21, + }; + + /* Setup protocol expert items */ + static ei_register_info ei[] = { + { &ei_z21_invalid_checksum, + { "z21.invalidchecksum", PI_CHECKSUM, PI_WARN, + "Invalid XOR checksum", EXPFILL } + }, + }; + + /* Register the protocol name and description */ + proto_z21 = proto_register_protocol("Z21 LAN Protocol", "Z21", "z21"); + + /* Required function calls to register the header fields and subtrees */ + proto_register_field_array(proto_z21, hf, array_length(hf)); + proto_register_subtree_array(ett, array_length(ett)); + + /* Required function calls to register expert items */ + expert_z21 = expert_register_protocol(proto_z21); + expert_register_field_array(expert_z21, ei, array_length(ei)); + + z21_handle = register_dissector("z21", dissect_z21, proto_z21); + + /* Register a preferences module (see section 2.6 of README.dissector + * for more details). Registration of a prefs callback is not required + * if there are no preferences that affect protocol registration (an example + * of a preference that would affect registration is a port preference). + * If the prefs callback is not needed, use NULL instead of + * proto_reg_handoff_z21 in the following. + */ + prefs_register_protocol(proto_z21, proto_reg_handoff_z21); +} + +void +proto_reg_handoff_z21(void) +{ + static bool initialized = false; + + if (!initialized) { + dissector_add_uint_range_with_preference("udp.port", Z21_UDP_PORTS, z21_handle); + initialized = true; + } + udp_port_range = prefs_get_range_value("Z21", "udp.port"); +} |