forked from osmocom/wireshark
![Michael Mann](/assets/img/avatar_default.png)
Change-Id: I6b6a05ec242e4798fb56ffa43c661ec277aca955 Reviewed-on: https://code.wireshark.org/review/3984 Reviewed-by: Chris Bontje <cbontje@gmail.com> Petri-Dish: Michael Mann <mmann78@netscape.net> Tested-by: Petri Dish Buildbot <buildbot-no-reply@wireshark.org> Reviewed-by: Michael Mann <mmann78@netscape.net>
1567 lines
78 KiB
C
1567 lines
78 KiB
C
/* packet-lg8979.c
|
|
* Routines for Landis & Gyr (Telegyr) 8979 Protocol (lg8979) Dissection
|
|
* By Chris Bontje (cbontje[AT]gmail.com
|
|
* Copyright 2013-2014
|
|
*
|
|
************************************************************************************************
|
|
* Wireshark - Network traffic analyzer
|
|
* By Gerald Combs <gerald@wireshark.org>
|
|
* Copyright 1998 Gerald Combs
|
|
*
|
|
* This program is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU General Public License
|
|
* as published by the Free Software Foundation; either version 2
|
|
* of the License, or (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
*/
|
|
|
|
#include "config.h"
|
|
|
|
#include <epan/packet.h>
|
|
#include "packet-tcp.h"
|
|
#include <epan/prefs.h>
|
|
#include "packet-rtacser.h"
|
|
|
|
void proto_register_lg8979(void);
|
|
|
|
/* Initialize the protocol and registered fields */
|
|
static int proto_lg8979 = -1;
|
|
static int hf_lg8979_header = -1;
|
|
static int hf_lg8979_shr = -1;
|
|
static int hf_lg8979_mfc = -1;
|
|
static int hf_lg8979_ack = -1;
|
|
static int hf_lg8979_con = -1;
|
|
static int hf_lg8979_frz = -1;
|
|
static int hf_lg8979_ind = -1;
|
|
static int hf_lg8979_sch = -1;
|
|
static int hf_lg8979_slg = -1;
|
|
static int hf_lg8979_address = -1;
|
|
static int hf_lg8979_lastblock = -1;
|
|
static int hf_lg8979_funccode = -1;
|
|
static int hf_lg8979_length = -1;
|
|
static int hf_lg8979_start_ptnum16 = -1;
|
|
static int hf_lg8979_start_ptnum8 = -1;
|
|
static int hf_lg8979_stop_ptnum16 = -1;
|
|
static int hf_lg8979_stop_ptnum8 = -1;
|
|
static int hf_lg8979_ang_point = -1;
|
|
static int hf_lg8979_adc_ref_zero = -1;
|
|
static int hf_lg8979_adc_ref_neg90 = -1;
|
|
static int hf_lg8979_adc_ref_pos90 = -1;
|
|
static int hf_lg8979_ind_chgrpt_ptnum = -1;
|
|
static int hf_lg8979_ind_chgrpt_status = -1;
|
|
static int hf_lg8979_ind_chgrpt_change = -1;
|
|
static int hf_lg8979_ind_frcrpt_status_b0 = -1;
|
|
static int hf_lg8979_ind_frcrpt_status_b1 = -1;
|
|
static int hf_lg8979_ind_frcrpt_status_b2 = -1;
|
|
static int hf_lg8979_ind_frcrpt_status_b3 = -1;
|
|
static int hf_lg8979_ind_frcrpt_status_b4 = -1;
|
|
static int hf_lg8979_ind_frcrpt_status_b5 = -1;
|
|
static int hf_lg8979_ind_frcrpt_status_b6 = -1;
|
|
static int hf_lg8979_ind_frcrpt_status_b7 = -1;
|
|
static int hf_lg8979_ind_frcrpt_change_b0 = -1;
|
|
static int hf_lg8979_ind_frcrpt_change_b1 = -1;
|
|
static int hf_lg8979_ind_frcrpt_change_b2 = -1;
|
|
static int hf_lg8979_ind_frcrpt_change_b3 = -1;
|
|
static int hf_lg8979_ind_frcrpt_change_b4 = -1;
|
|
static int hf_lg8979_ind_frcrpt_change_b5 = -1;
|
|
static int hf_lg8979_ind_frcrpt_change_b6 = -1;
|
|
static int hf_lg8979_ind_frcrpt_change_b7 = -1;
|
|
static int hf_lg8979_soe_chgrpt_ptnum = -1;
|
|
static int hf_lg8979_soe_chgrpt_status = -1;
|
|
static int hf_lg8979_soe_chgrpt_change = -1;
|
|
static int hf_lg8979_soe_frcrpt_status_b0 = -1;
|
|
static int hf_lg8979_soe_frcrpt_status_b1 = -1;
|
|
static int hf_lg8979_soe_frcrpt_status_b2 = -1;
|
|
static int hf_lg8979_soe_frcrpt_status_b3 = -1;
|
|
static int hf_lg8979_soe_frcrpt_status_b4 = -1;
|
|
static int hf_lg8979_soe_frcrpt_status_b5 = -1;
|
|
static int hf_lg8979_soe_frcrpt_status_b6 = -1;
|
|
static int hf_lg8979_soe_frcrpt_status_b7 = -1;
|
|
static int hf_lg8979_soe_frcrpt_change_b0 = -1;
|
|
static int hf_lg8979_soe_frcrpt_change_b1 = -1;
|
|
static int hf_lg8979_soe_frcrpt_change_b2 = -1;
|
|
static int hf_lg8979_soe_frcrpt_change_b3 = -1;
|
|
static int hf_lg8979_soe_frcrpt_change_b4 = -1;
|
|
static int hf_lg8979_soe_frcrpt_change_b5 = -1;
|
|
static int hf_lg8979_soe_frcrpt_change_b6 = -1;
|
|
static int hf_lg8979_soe_frcrpt_change_b7 = -1;
|
|
static int hf_lg8979_digin_b0 = -1;
|
|
static int hf_lg8979_digin_b1 = -1;
|
|
static int hf_lg8979_digin_b2 = -1;
|
|
static int hf_lg8979_digin_b3 = -1;
|
|
static int hf_lg8979_digin_b4 = -1;
|
|
static int hf_lg8979_digin_b5 = -1;
|
|
static int hf_lg8979_digin_b6 = -1;
|
|
static int hf_lg8979_digin_b7 = -1;
|
|
static int hf_lg8979_digin_b8 = -1;
|
|
static int hf_lg8979_digin_b9 = -1;
|
|
static int hf_lg8979_digin_b10 = -1;
|
|
static int hf_lg8979_digin_b11 = -1;
|
|
static int hf_lg8979_digin_b12 = -1;
|
|
static int hf_lg8979_digin_b13 = -1;
|
|
static int hf_lg8979_digin_b14 = -1;
|
|
static int hf_lg8979_digin_b15 = -1;
|
|
static int hf_lg8979_acc_point = -1;
|
|
static int hf_lg8979_soe_logchg_ptnum = -1;
|
|
static int hf_lg8979_soe_logchg_newstat = -1;
|
|
static int hf_lg8979_soe_logchg_mon = -1;
|
|
static int hf_lg8979_soe_logchg_day = -1;
|
|
static int hf_lg8979_soe_logchg_hour = -1;
|
|
static int hf_lg8979_soe_logchg_min = -1;
|
|
static int hf_lg8979_soe_logchg_sec = -1;
|
|
static int hf_lg8979_soe_logchg_msec = -1;
|
|
static int hf_lg8979_ang_output_val = -1;
|
|
static int hf_lg8979_sbo_tripclose = -1;
|
|
static int hf_lg8979_sbo_timercnt = -1;
|
|
static int hf_lg8979_digout_data = -1;
|
|
static int hf_lg8979_pul_output_base = -1;
|
|
static int hf_lg8979_pul_output_dur = -1;
|
|
static int hf_lg8979_pul_output_rl = -1;
|
|
static int hf_lg8979_ang_deadband = -1;
|
|
static int hf_lg8979_acc_preset = -1;
|
|
static int hf_lg8979_rtucfg_num_chassis = -1;
|
|
static int hf_lg8979_rtucfg_chassis_num = -1;
|
|
static int hf_lg8979_rtucfg_card_slot = -1;
|
|
static int hf_lg8979_timesync_mon = -1;
|
|
static int hf_lg8979_timesync_day = -1;
|
|
static int hf_lg8979_timesync_hour = -1;
|
|
static int hf_lg8979_timesync_min = -1;
|
|
static int hf_lg8979_timesync_sec = -1;
|
|
static int hf_lg8979_timesync_msec = -1;
|
|
static int hf_lg8979_timebias_value = -1;
|
|
static int hf_lg8979_timebias_proctime = -1;
|
|
static int hf_lg8979_firmware_ver = -1;
|
|
static int hf_lg8979_exprpt_code = -1;
|
|
static int hf_lg8979_exprpt_parm = -1;
|
|
static int hf_lg8979_disallowed_func = -1;
|
|
static int hf_lg8979_crc16 = -1;
|
|
|
|
/* Initialize the subtree pointers */
|
|
static gint ett_lg8979 = -1;
|
|
static gint ett_lg8979_flags = -1;
|
|
static gint ett_lg8979_funccode = -1;
|
|
static gint ett_lg8979_point = -1;
|
|
static gint ett_lg8979_ts = -1;
|
|
|
|
#define PORT_LG8979 0
|
|
|
|
/* Globals for L&G 8979 Protocol Preferences */
|
|
static gboolean lg8979_desegment = TRUE;
|
|
static guint global_lg8979_tcp_port = PORT_LG8979; /* Port 0, by default */
|
|
|
|
#define LG8979_HEADER 0xFF
|
|
|
|
#define LG8979_DIR_INDETERMINATE 0
|
|
#define LG8979_DIR_MASTER_TO_RTU 1
|
|
#define LG8979_DIR_RTU_TO_MASTER 2
|
|
|
|
/* Function Codes */
|
|
#define LG8979_FC_ANG_CHGRPT 0
|
|
#define LG8979_FC_ANG_FRCRPT 1
|
|
#define LG8979_FC_ANGGRP_CHGRPT 2
|
|
#define LG8979_FC_ANGGRP_FRCRPT 3
|
|
#define LG8979_FC_ADC_FRCRPT 5
|
|
#define LG8979_FC_IND_CHGRPT 6
|
|
#define LG8979_FC_IND_FRCRPT 7
|
|
#define LG8979_FC_SOE_CHGRPT 8
|
|
#define LG8979_FC_SOE_FRCRPT 9
|
|
#define LG8979_FC_DIG_FRCRPT 11
|
|
#define LG8979_FC_ACC_CHGRPT 12
|
|
#define LG8979_FC_ACC_FRCRPT 13
|
|
#define LG8979_FC_SOELOG_CHGRPT 14
|
|
#define LG8979_FC_ANG_OUTPUT 20
|
|
#define LG8979_FC_SBO_SELECT 21
|
|
#define LG8979_FC_SBO_OPERATE 22
|
|
#define LG8979_FC_DIG_OUTPUT 23
|
|
#define LG8979_FC_ACC_FREEZE 24
|
|
#define LG8979_FC_PUL_OUTPUT 25
|
|
#define LG8979_FC_PULTR_OUTPUT 26
|
|
#define LG8979_FC_SBO_IMEXECUTE 28
|
|
#define LG8979_FC_RTU_RESTART 30
|
|
#define LG8979_FC_RTU_CONFIG 31
|
|
#define LG8979_FC_TIME_SYNC 32
|
|
#define LG8979_FC_TIME_BIAS 33
|
|
#define LG8979_FC_ANG_DEADBAND 34
|
|
#define LG8979_FC_ANGGRP_DEFINE 35
|
|
#define LG8979_FC_ACC_PRESET 36
|
|
#define LG8979_FC_CONT_REQUEST 37
|
|
#define LG8979_FC_REPEAT_MSG 38
|
|
#define LG8979_FC_FIRMWARE_CFG 39
|
|
#define LG8979_FC_TABLE_READ 47
|
|
#define LG8979_FC_TABLE_WRITE 48
|
|
#define LG8979_FC_SPRPT_INT 50
|
|
#define LG8979_FC_SPRPT_SEQNUM 51
|
|
#define LG8979_FC_EXP_RPT 63
|
|
|
|
static const value_string lg8979_funccode_vals[] = {
|
|
{ LG8979_FC_ANG_CHGRPT, "Analog Change Report" },
|
|
{ LG8979_FC_ANG_FRCRPT, "Analog Force Report" },
|
|
{ LG8979_FC_ANGGRP_CHGRPT, "Analog Group Change Report" },
|
|
{ LG8979_FC_ANGGRP_FRCRPT, "Analog Group Force Report" },
|
|
{ 4, "Unknown/Invalid Function" },
|
|
{ LG8979_FC_ADC_FRCRPT, "ADC Reference Force Report" },
|
|
{ LG8979_FC_IND_CHGRPT, "Indication Change Report" },
|
|
{ LG8979_FC_IND_FRCRPT, "Indication Force Report" },
|
|
{ LG8979_FC_SOE_CHGRPT, "SOE Change Report" },
|
|
{ LG8979_FC_SOE_FRCRPT, "SOE Force Report" },
|
|
{ 10, "Unknown/Invalid Function" },
|
|
{ LG8979_FC_DIG_FRCRPT, "Digital Input Force Report" },
|
|
{ LG8979_FC_ACC_CHGRPT, "Accumulator Change Report" },
|
|
{ LG8979_FC_ACC_FRCRPT, "Accumulator Force Report" },
|
|
{ LG8979_FC_SOELOG_CHGRPT, "SOE Log Change Report" },
|
|
{ 15, "Unknown/Invalid Function" },
|
|
{ 16, "Unknown/Invalid Function" },
|
|
{ 17, "Unknown/Invalid Function" },
|
|
{ 18, "Unknown/Invalid Function" },
|
|
{ 19, "Unknown/Invalid Function" },
|
|
{ LG8979_FC_ANG_OUTPUT, "Analog Output" },
|
|
{ LG8979_FC_SBO_SELECT, "SBO Select" },
|
|
{ LG8979_FC_SBO_OPERATE, "SBO Operate" },
|
|
{ LG8979_FC_DIG_OUTPUT, "Digital Output" },
|
|
{ LG8979_FC_ACC_FREEZE, "Accumulator Freeze" },
|
|
{ LG8979_FC_PUL_OUTPUT, "Pulse Output" },
|
|
{ LG8979_FC_PULTR_OUTPUT, "Pulse Train Output" },
|
|
{ 27, "Unknown/Invalid Function" },
|
|
{ LG8979_FC_SBO_IMEXECUTE, "SBO Immediate Execute" },
|
|
{ 29, "Unknown/Invalid Function" },
|
|
{ LG8979_FC_RTU_RESTART, "Restart RTU" },
|
|
{ LG8979_FC_RTU_CONFIG, "RTU Configuration" },
|
|
{ LG8979_FC_TIME_SYNC, "Time Synchronization" },
|
|
{ LG8979_FC_TIME_BIAS, "Time Bias" },
|
|
{ LG8979_FC_ANG_DEADBAND, "Analog Deadbands" },
|
|
{ LG8979_FC_ANGGRP_DEFINE, "Analog Group Define" },
|
|
{ LG8979_FC_ACC_PRESET, "Accumulator Preset" },
|
|
{ LG8979_FC_CONT_REQUEST, "Continuation Request" },
|
|
{ LG8979_FC_REPEAT_MSG, "Repeat Last Message" },
|
|
{ LG8979_FC_FIRMWARE_CFG, "Firmware Configuration" },
|
|
{ 40, "Unknown/Invalid Function" },
|
|
{ 41, "Unknown/Invalid Function" },
|
|
{ 42, "Unknown/Invalid Function" },
|
|
{ 43, "Unknown/Invalid Function" },
|
|
{ 44, "Unknown/Invalid Function" },
|
|
{ 45, "Unknown/Invalid Function" },
|
|
{ 46, "Unknown/Invalid Function" },
|
|
{ LG8979_FC_TABLE_READ, "Table Read" },
|
|
{ LG8979_FC_TABLE_WRITE, "Table Write" },
|
|
{ 49, "Unknown/Invalid Function" },
|
|
{ LG8979_FC_SPRPT_INT, "Spontaneous Report Interval" },
|
|
{ LG8979_FC_SPRPT_SEQNUM, "Spontaneous Report Sequence Number" },
|
|
{ 52, "Unknown/Invalid Function" },
|
|
{ 53, "Unknown/Invalid Function" },
|
|
{ 54, "Unknown/Invalid Function" },
|
|
{ 55, "Unknown/Invalid Function" },
|
|
{ 56, "Unknown/Invalid Function" },
|
|
{ 57, "Unknown/Invalid Function" },
|
|
{ 58, "Unknown/Invalid Function" },
|
|
{ 59, "Unknown/Invalid Function" },
|
|
{ 60, "Unknown/Invalid Function" },
|
|
{ 61, "Unknown/Invalid Function" },
|
|
{ 62, "Unknown/Invalid Function" },
|
|
{ LG8979_FC_EXP_RPT, "Exception Report" },
|
|
{ 0, NULL }
|
|
};
|
|
static value_string_ext lg8979_funccode_vals_ext = VALUE_STRING_EXT_INIT(lg8979_funccode_vals);
|
|
|
|
static const value_string lg8979_cardcode_vals[] = {
|
|
{ 0, "Non-Existent Slot" },
|
|
{ 1, "Analog Input" },
|
|
{ 2, "A/D Converter" },
|
|
{ 3, "Analog Output" },
|
|
{ 4, "Indication Input" },
|
|
{ 5, "24-Bit Digital Output" },
|
|
{ 7, "SBO Control Output" },
|
|
{ 8, "Accumulator, Form A" },
|
|
{ 11, "32-Bit Digital Output" },
|
|
{ 12, "Accumulator, Form C" },
|
|
{ 15, "Pulse Output" },
|
|
{ 28, "SOE Input" },
|
|
{ 29, "KWH Input" },
|
|
{ 30, "Serial Data Collector" },
|
|
{ 31, "Empty Slot" },
|
|
{ 0, NULL }
|
|
};
|
|
|
|
static const value_string lg8979_exprpt_code_vals[] = {
|
|
{ 0x00, "Warm Restart" },
|
|
{ 0x01, "Cold Start" },
|
|
{ 0x02, "Insufficient Ram" },
|
|
{ 0x03, "Bus Failure" },
|
|
{ 0x04, "SBO Failure" },
|
|
{ 0x05, "Analog Failure" },
|
|
{ 0x06, "Indication/SOE Failure" },
|
|
{ 0x07, "Card Placement Error" },
|
|
{ 0x08, "Not Used" },
|
|
{ 0x09, "Invalid Function Code" },
|
|
{ 0x0A, "Invalid Block Length" },
|
|
{ 0x0B, "Non-Existent Point" },
|
|
{ 0x0C, "Invalid Parameter" },
|
|
{ 0x0D, "Select/Execute Mismatch" },
|
|
{ 0x0E, "Function Not Allowed" },
|
|
{ 0x0F, "Not Used" },
|
|
{ 0x10, "Database Setup has Changed" },
|
|
{ 0x11, "Indication Change Sequence" },
|
|
{ 0, NULL }
|
|
};
|
|
|
|
static const value_string lg8979_exprpt_parm_vals[] = {
|
|
{ 0x00, "N/A" },
|
|
{ 0x01, "1=Requested CLDSTRT" },
|
|
{ 0x02, "N/A" },
|
|
{ 0x03, "Unit" },
|
|
{ 0x04, "Unit/Slot" },
|
|
{ 0x05, "Unit/Slot" },
|
|
{ 0x06, "Unit/Slot" },
|
|
{ 0x07, "Unit/Slot" },
|
|
{ 0x08, "N/A" },
|
|
{ 0x09, "Function Code" },
|
|
{ 0x0A, "Block Length" },
|
|
{ 0x0B, "Point" },
|
|
{ 0x0C, "Parameter" },
|
|
{ 0x0D, "Execute Point" },
|
|
{ 0x0E, "Function Code" },
|
|
{ 0x0F, "N/A" },
|
|
{ 0x10, "N/A" },
|
|
{ 0x11, "1=Time Order (0=Not T/O)" },
|
|
{ 0, NULL }
|
|
};
|
|
|
|
static const value_string lg8979_sbo_tripclose_vals[] = {
|
|
{ 0x00, "Trip" },
|
|
{ 0x01, "Close" },
|
|
{ 0, NULL }
|
|
};
|
|
|
|
static const value_string lg8979_pul_output_base_vals[] = {
|
|
{ 0x00, "10 msec" },
|
|
{ 0x01, "100 msec" },
|
|
{ 0x02, "1 sec" },
|
|
{ 0x03, "10 sec" },
|
|
{ 0, NULL }
|
|
};
|
|
|
|
static const value_string lg8979_pul_output_rl_vals[] = {
|
|
{ 0x00, "Lower" },
|
|
{ 0x01, "Raise" },
|
|
{ 0, NULL }
|
|
};
|
|
|
|
|
|
/*****************************************************************/
|
|
/* Adds text to item, with trailing "," if required */
|
|
/*****************************************************************/
|
|
static gboolean
|
|
add_item_text(proto_item *item, const gchar *text, gboolean comma_needed)
|
|
{
|
|
if (comma_needed) {
|
|
proto_item_append_text(item, ", ");
|
|
}
|
|
proto_item_append_text(item, "%s", text);
|
|
return TRUE;
|
|
}
|
|
|
|
/*************************************************************/
|
|
/* Try to determine "direction" of message. */
|
|
/* Check the data length within the packet and compare */
|
|
/* vs. the function code. Master->RTU messages will have a */
|
|
/* fixed length that can be used to determine the direction */
|
|
/* of the message */
|
|
/*************************************************************/
|
|
static int
|
|
classify_lg8979_packet(tvbuff_t *tvb)
|
|
{
|
|
guint8 func, len, data_len, flags;
|
|
|
|
len = tvb_reported_length(tvb);
|
|
/* If TVB length is equal to 5, this is classifed as a 'short response message' */
|
|
/* and is guaranteed to be RTU->Master only */
|
|
if (len == 5) {
|
|
return LG8979_DIR_RTU_TO_MASTER;
|
|
}
|
|
|
|
/* If TVB length is greater than 5, let's dig deeper */
|
|
if (len > 5) {
|
|
|
|
flags = tvb_get_guint8(tvb, 1);
|
|
|
|
/* Flags vary between message types, so let's try those first to determine the message direction */
|
|
/* If both bit 3 and bit 4 are set, this is almost certainly a RTU->Master message */
|
|
if ( (flags & 0x04) && (flags & 0x08) ){
|
|
return LG8979_DIR_RTU_TO_MASTER;
|
|
}
|
|
/* If anything is in bits 3-6 without bit 7, this is a RTU->Master message */
|
|
else if ( (flags & 0x78) && !(flags & 0x80) ){
|
|
return LG8979_DIR_RTU_TO_MASTER;
|
|
}
|
|
|
|
func = tvb_get_guint8(tvb, 3) & 0x7F;
|
|
data_len = tvb_get_guint8(tvb, 4);
|
|
|
|
/* If we have more data in the tvb then should be there, this is a stacked RTU->Master response */
|
|
if (len > (data_len + 5 + 2)) {
|
|
return LG8979_DIR_RTU_TO_MASTER;
|
|
}
|
|
|
|
switch (func) {
|
|
case LG8979_FC_ANG_CHGRPT:
|
|
case LG8979_FC_ADC_FRCRPT:
|
|
case LG8979_FC_IND_CHGRPT:
|
|
case LG8979_FC_SOE_CHGRPT:
|
|
case LG8979_FC_ACC_CHGRPT:
|
|
case LG8979_FC_SOELOG_CHGRPT:
|
|
case LG8979_FC_REPEAT_MSG:
|
|
case LG8979_FC_RTU_CONFIG:
|
|
case LG8979_FC_FIRMWARE_CFG:
|
|
if (data_len == 0) {
|
|
return LG8979_DIR_MASTER_TO_RTU;
|
|
}
|
|
else {
|
|
return LG8979_DIR_RTU_TO_MASTER;
|
|
}
|
|
break;
|
|
|
|
case LG8979_FC_ANGGRP_CHGRPT:
|
|
case LG8979_FC_ANGGRP_FRCRPT:
|
|
if (data_len == 1) {
|
|
return LG8979_DIR_MASTER_TO_RTU;
|
|
}
|
|
else {
|
|
return LG8979_DIR_RTU_TO_MASTER;
|
|
}
|
|
break;
|
|
|
|
|
|
case LG8979_FC_DIG_FRCRPT:
|
|
case LG8979_FC_ACC_FRCRPT:
|
|
case LG8979_FC_TIME_BIAS:
|
|
if (data_len == 2) {
|
|
return LG8979_DIR_MASTER_TO_RTU;
|
|
}
|
|
else {
|
|
return LG8979_DIR_RTU_TO_MASTER;
|
|
}
|
|
break;
|
|
|
|
case LG8979_FC_ANG_FRCRPT:
|
|
case LG8979_FC_IND_FRCRPT:
|
|
case LG8979_FC_SOE_FRCRPT:
|
|
if (data_len == 4) {
|
|
return LG8979_DIR_MASTER_TO_RTU;
|
|
}
|
|
else {
|
|
return LG8979_DIR_RTU_TO_MASTER;
|
|
}
|
|
break;
|
|
|
|
/* These are either totally or mostly master->RTU operations */
|
|
case LG8979_FC_ANG_OUTPUT:
|
|
case LG8979_FC_SBO_SELECT:
|
|
case LG8979_FC_SBO_OPERATE:
|
|
case LG8979_FC_DIG_OUTPUT:
|
|
case LG8979_FC_ACC_FREEZE:
|
|
case LG8979_FC_PUL_OUTPUT:
|
|
case LG8979_FC_PULTR_OUTPUT:
|
|
case LG8979_FC_SBO_IMEXECUTE:
|
|
case LG8979_FC_TIME_SYNC:
|
|
case LG8979_FC_ANG_DEADBAND:
|
|
case LG8979_FC_ACC_PRESET:
|
|
case LG8979_FC_CONT_REQUEST:
|
|
|
|
return LG8979_DIR_MASTER_TO_RTU;
|
|
break;
|
|
|
|
case LG8979_FC_EXP_RPT:
|
|
return LG8979_DIR_RTU_TO_MASTER;
|
|
break;
|
|
|
|
default:
|
|
return LG8979_DIR_INDETERMINATE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* else, cannot classify */
|
|
return LG8979_DIR_INDETERMINATE;
|
|
}
|
|
|
|
/******************************************************************************************************/
|
|
/* Code to dissect L&G 8979 Protocol packets */
|
|
/******************************************************************************************************/
|
|
static int
|
|
dissect_lg8979(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_)
|
|
{
|
|
/* Set up structures needed to add the protocol subtree and manage it */
|
|
proto_item *lg8979_item, *lg8979_flags_item = NULL, *lg8979_point_item = NULL;
|
|
proto_item *lg8979_slot_item = NULL;
|
|
proto_tree *lg8979_tree, *lg8979_flags_tree = NULL, *lg8979_fc_tree = NULL;
|
|
proto_tree *lg8979_point_tree = NULL, *lg8979_ts_tree = NULL;
|
|
int offset = 0;
|
|
guint8 rtu_addr, func, packet_type, data_len, ptnum8, tripclose, rl, exp_code;
|
|
guint8 ts_mon, ts_day, ts_hr, ts_min, ts_sec;
|
|
guint16 ptnum, ptval, ana12_val;
|
|
guint16 ts_ms;
|
|
gint num_points = 0, cnt = 0;
|
|
gboolean shr, con, frz, ind, sch, slg, ack, comma_needed = FALSE, new_status, change;
|
|
|
|
/* Make entries in Protocol column on summary display */
|
|
col_set_str(pinfo->cinfo, COL_PROTOCOL, "L&G 8979");
|
|
col_clear(pinfo->cinfo, COL_INFO);
|
|
|
|
lg8979_item = proto_tree_add_item(tree, proto_lg8979, tvb, 0, -1, ENC_NA);
|
|
lg8979_tree = proto_item_add_subtree(lg8979_item, ett_lg8979);
|
|
|
|
/* Add 0xFF Header to Protocol Tree */
|
|
proto_tree_add_item(lg8979_tree, hf_lg8979_header, tvb, offset, 1, ENC_LITTLE_ENDIAN);
|
|
offset += 1;
|
|
|
|
/* "Request" or "Response" */
|
|
packet_type = classify_lg8979_packet(tvb);
|
|
|
|
/* This packet type is classified as a "Request" and is deemed in the direction of "master -> RTU" */
|
|
if (packet_type == LG8979_DIR_MASTER_TO_RTU) {
|
|
|
|
col_add_str(pinfo->cinfo, COL_INFO, "Master -> RTU");
|
|
|
|
/* Add Flags to Protocol Tree */
|
|
shr = tvb_get_guint8(tvb, offset) & 0x80;
|
|
ack = tvb_get_guint8(tvb, offset) & 0x04;
|
|
|
|
lg8979_flags_tree = proto_tree_add_subtree(lg8979_tree, tvb, offset, 1,
|
|
ett_lg8979_flags, &lg8979_flags_item, "Flags");
|
|
|
|
proto_item_append_text(lg8979_flags_item, " (");
|
|
if (shr) comma_needed = add_item_text(lg8979_flags_item, "SHR", comma_needed);
|
|
if (ack) add_item_text(lg8979_flags_item, "ACK", comma_needed);
|
|
proto_item_append_text(lg8979_flags_item, ")");
|
|
|
|
proto_tree_add_item(lg8979_flags_tree, hf_lg8979_shr, tvb, offset, 1, ENC_LITTLE_ENDIAN);
|
|
proto_tree_add_item(lg8979_flags_tree, hf_lg8979_mfc, tvb, offset, 1, ENC_LITTLE_ENDIAN);
|
|
proto_tree_add_item(lg8979_flags_tree, hf_lg8979_ack, tvb, offset, 1, ENC_LITTLE_ENDIAN);
|
|
offset += 1;
|
|
|
|
/* Add RTU Address to Protocol Tree */
|
|
rtu_addr = tvb_get_guint8(tvb, offset);
|
|
col_append_sep_fstr(pinfo->cinfo, COL_INFO, NULL, "Address: %d", rtu_addr);
|
|
|
|
proto_tree_add_item(lg8979_tree, hf_lg8979_address, tvb, offset, 1, ENC_LITTLE_ENDIAN);
|
|
offset += 1;
|
|
|
|
if (!shr) {
|
|
/* Add Function Code & last Mark Block to Protocol Tree */
|
|
/* Function code is 7 lower bits of byte , LMB is 8th bit*/
|
|
func = tvb_get_guint8(tvb, offset) & 0x7f;
|
|
|
|
col_append_sep_fstr(pinfo->cinfo, COL_INFO, NULL, "%s",
|
|
val_to_str_const(func, lg8979_funccode_vals, "Unknown Function Code"));
|
|
|
|
lg8979_fc_tree = proto_tree_add_subtree_format(
|
|
lg8979_tree, tvb, offset, 1, ett_lg8979_funccode, NULL,
|
|
"Function Code: %s (%d)",
|
|
val_to_str_const(func, lg8979_funccode_vals, "Unknown Function Code"), func);
|
|
|
|
proto_tree_add_item(lg8979_fc_tree, hf_lg8979_lastblock, tvb, offset, 1, ENC_LITTLE_ENDIAN);
|
|
proto_tree_add_item(lg8979_fc_tree, hf_lg8979_funccode, tvb, offset, 1, ENC_LITTLE_ENDIAN);
|
|
offset += 1;
|
|
|
|
data_len = tvb_get_guint8(tvb, offset);
|
|
proto_tree_add_item(lg8979_tree, hf_lg8979_length, tvb, offset, 1, ENC_LITTLE_ENDIAN);
|
|
offset += 1;
|
|
|
|
switch (func) {
|
|
/* Function Code 0 Analog Change Report */
|
|
/* Function Code 7 Indication Force Report */
|
|
/* Function Code 9 SOE Force Report */
|
|
case LG8979_FC_ANG_FRCRPT:
|
|
case LG8979_FC_IND_FRCRPT:
|
|
case LG8979_FC_SOE_FRCRPT:
|
|
proto_tree_add_item(lg8979_tree, hf_lg8979_start_ptnum16, tvb, offset, 2, ENC_LITTLE_ENDIAN);
|
|
proto_tree_add_item(lg8979_tree, hf_lg8979_stop_ptnum16, tvb, offset+2, 2, ENC_LITTLE_ENDIAN);
|
|
offset += 4;
|
|
break;
|
|
|
|
/* Function Code 11 Digital Input Force Report */
|
|
/* Function Code 13 Accumulator Force Report */
|
|
case LG8979_FC_DIG_FRCRPT:
|
|
case LG8979_FC_ACC_FRCRPT:
|
|
proto_tree_add_item(lg8979_tree, hf_lg8979_start_ptnum8, tvb, offset, 1, ENC_LITTLE_ENDIAN);
|
|
proto_tree_add_item(lg8979_tree, hf_lg8979_stop_ptnum8, tvb, offset+1, 1, ENC_LITTLE_ENDIAN);
|
|
offset += 2;
|
|
break;
|
|
|
|
/* Function Code 20 Analog Output */
|
|
case LG8979_FC_ANG_OUTPUT:
|
|
proto_tree_add_item(lg8979_tree, hf_lg8979_start_ptnum8, tvb, offset, 1, ENC_LITTLE_ENDIAN);
|
|
proto_tree_add_item(lg8979_tree, hf_lg8979_ang_output_val, tvb, offset+1, 2, ENC_LITTLE_ENDIAN);
|
|
offset += 3;
|
|
break;
|
|
|
|
/* Function Code 21 SBO Select */
|
|
case LG8979_FC_SBO_SELECT:
|
|
|
|
/* Get 8-bit point number and trip/close command-code */
|
|
ptnum = tvb_get_guint8(tvb, offset);
|
|
tripclose = (tvb_get_guint8(tvb, offset+1) & 0x80) >> 7;
|
|
|
|
lg8979_point_tree = proto_tree_add_subtree_format(
|
|
lg8979_tree, tvb, offset, 2,
|
|
ett_lg8979_point, NULL,
|
|
"SBO Command, Pt.Num: %u, Code: %s",
|
|
ptnum,
|
|
val_to_str_const(tripclose, lg8979_sbo_tripclose_vals, "Unknown Control Code"));
|
|
|
|
/* Update the Information Column with Command Details */
|
|
col_append_sep_fstr(pinfo->cinfo, COL_INFO, NULL, "Output: %u, Code: %s",
|
|
ptnum, val_to_str_const(tripclose, lg8979_sbo_tripclose_vals, "Unknown Control Code"));
|
|
|
|
/* Add SBO Select Details to tree */
|
|
proto_tree_add_item(lg8979_point_tree, hf_lg8979_start_ptnum8, tvb, offset, 1, ENC_LITTLE_ENDIAN);
|
|
proto_tree_add_item(lg8979_point_tree, hf_lg8979_sbo_tripclose, tvb, offset+1, 1, ENC_LITTLE_ENDIAN);
|
|
proto_tree_add_item(lg8979_point_tree, hf_lg8979_sbo_timercnt, tvb, offset+1, 1, ENC_LITTLE_ENDIAN);
|
|
offset += 2;
|
|
break;
|
|
|
|
/* Function Code 22 SBO Operate */
|
|
case LG8979_FC_SBO_OPERATE:
|
|
|
|
/* Get 8-bit point number */
|
|
ptnum = tvb_get_guint8(tvb, offset);
|
|
|
|
/* Update the Information Column with Command Details */
|
|
col_append_sep_fstr(pinfo->cinfo, COL_INFO, NULL, "Output: %u", ptnum);
|
|
|
|
/* Add 8-bit point number to tree */
|
|
proto_tree_add_item(lg8979_tree, hf_lg8979_start_ptnum8, tvb, offset, 1, ENC_LITTLE_ENDIAN);
|
|
offset += 1;
|
|
break;
|
|
|
|
/* Function Code 23 Digital Output */
|
|
case LG8979_FC_DIG_OUTPUT:
|
|
|
|
/* Add Digital Output Details to tree */
|
|
proto_tree_add_item(lg8979_tree, hf_lg8979_start_ptnum8, tvb, offset, 1, ENC_LITTLE_ENDIAN);
|
|
proto_tree_add_item(lg8979_tree, hf_lg8979_digout_data, tvb, offset+1, 3, ENC_LITTLE_ENDIAN);
|
|
offset += 4;
|
|
break;
|
|
|
|
/* Function Code 25 Pulse Output */
|
|
case LG8979_FC_PUL_OUTPUT:
|
|
|
|
ptnum = tvb_get_guint8(tvb, offset);
|
|
rl = (tvb_get_guint8(tvb, offset+1) & 0x80) >> 7;
|
|
|
|
lg8979_point_tree = proto_tree_add_subtree_format(lg8979_tree, tvb, offset, 2,
|
|
ett_lg8979_point, NULL, "Pulse Output, Pt.Num: %u, Code: %s",
|
|
ptnum, val_to_str_const(rl, lg8979_pul_output_rl_vals, "Unknown Control Code"));
|
|
|
|
/* Add Pulse Output Details to tree */
|
|
proto_tree_add_item(lg8979_point_tree, hf_lg8979_start_ptnum8, tvb, offset, 1, ENC_LITTLE_ENDIAN);
|
|
proto_tree_add_item(lg8979_point_tree, hf_lg8979_pul_output_base, tvb, offset+1, 1, ENC_LITTLE_ENDIAN);
|
|
proto_tree_add_item(lg8979_point_tree, hf_lg8979_pul_output_dur, tvb, offset+1, 1, ENC_LITTLE_ENDIAN);
|
|
proto_tree_add_item(lg8979_point_tree, hf_lg8979_pul_output_rl, tvb, offset+1, 1, ENC_LITTLE_ENDIAN);
|
|
offset += 2;
|
|
break;
|
|
|
|
/* Function Code 32 Time Synchronization */
|
|
case LG8979_FC_TIME_SYNC:
|
|
|
|
/* Add 7-byte time-sync value to tree */
|
|
ts_mon = tvb_get_guint8(tvb, offset);
|
|
ts_day = tvb_get_guint8(tvb, offset+1);
|
|
ts_hr = tvb_get_guint8(tvb, offset+2);
|
|
ts_min = tvb_get_guint8(tvb, offset+3);
|
|
ts_sec = tvb_get_guint8(tvb, offset+4);
|
|
ts_ms = tvb_get_letohs(tvb, offset+5);
|
|
|
|
lg8979_ts_tree = proto_tree_add_subtree_format(lg8979_tree, tvb, offset, 7, ett_lg8979_ts, NULL,
|
|
"Time-Sync Value: %02d/%02d %02d:%02d:%02d.%03d",
|
|
ts_mon, ts_day, ts_hr, ts_min, ts_sec, ts_ms);
|
|
|
|
proto_tree_add_item(lg8979_ts_tree, hf_lg8979_timesync_mon, tvb, offset, 1, ENC_LITTLE_ENDIAN);
|
|
proto_tree_add_item(lg8979_ts_tree, hf_lg8979_timesync_day, tvb, offset+1, 1, ENC_LITTLE_ENDIAN);
|
|
proto_tree_add_item(lg8979_ts_tree, hf_lg8979_timesync_hour, tvb, offset+2, 1, ENC_LITTLE_ENDIAN);
|
|
proto_tree_add_item(lg8979_ts_tree, hf_lg8979_timesync_min, tvb, offset+3, 1, ENC_LITTLE_ENDIAN);
|
|
proto_tree_add_item(lg8979_ts_tree, hf_lg8979_timesync_sec, tvb, offset+4, 1, ENC_LITTLE_ENDIAN);
|
|
proto_tree_add_item(lg8979_ts_tree, hf_lg8979_timesync_msec, tvb, offset+5, 2, ENC_LITTLE_ENDIAN);
|
|
offset += 7;
|
|
break;
|
|
|
|
/* Function Code 33 Time Bias */
|
|
case LG8979_FC_TIME_BIAS:
|
|
proto_tree_add_item(lg8979_tree, hf_lg8979_timebias_value, tvb, offset, 2, ENC_LITTLE_ENDIAN);
|
|
offset += 2;
|
|
break;
|
|
|
|
/* Function Code 34 Analog Deadband Write */
|
|
case LG8979_FC_ANG_DEADBAND:
|
|
|
|
/* Get analog point number base and add to tree */
|
|
ptnum = tvb_get_letohs(tvb, offset);
|
|
proto_tree_add_item(lg8979_tree, hf_lg8979_start_ptnum16, tvb, offset, 2, ENC_LITTLE_ENDIAN);
|
|
offset += 2;
|
|
|
|
num_points = (data_len-2);
|
|
|
|
for (cnt=0; cnt<num_points; cnt++) {
|
|
|
|
ptval = tvb_get_guint8(tvb, offset);
|
|
proto_tree_add_uint_format(lg8979_tree, hf_lg8979_ang_deadband, tvb, offset, 1,
|
|
ptnum, "Point Number %u: New Deadband: %u", ptnum, ptval);
|
|
ptnum += 1;
|
|
offset += 1;
|
|
}
|
|
|
|
break;
|
|
|
|
/* Function Code 36 Accumulator Preset */
|
|
case LG8979_FC_ACC_PRESET:
|
|
|
|
/* Each qty to follow has a 8-bit point number followed by a 16-bit value */
|
|
num_points = ((data_len)/3);
|
|
|
|
for (cnt=0; cnt<num_points; cnt++) {
|
|
|
|
ptnum8 = tvb_get_guint8(tvb, offset);
|
|
ptval = tvb_get_letohs(tvb, offset+1);
|
|
proto_tree_add_uint_format(lg8979_tree, hf_lg8979_acc_preset, tvb, offset, 3,
|
|
ptnum8, "Acc Point Number %u: Preset: %u", ptnum8, ptval);
|
|
offset += 3;
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
} /* func */
|
|
|
|
} /* !shr */
|
|
|
|
/* Add CRC-16 */
|
|
proto_tree_add_item(lg8979_tree, hf_lg8979_crc16, tvb, offset, 2, ENC_BIG_ENDIAN);
|
|
|
|
}
|
|
/* This packet type is classified as a "Response" and is deemed in the direction of "RTU -> master" */
|
|
else if (packet_type == LG8979_DIR_RTU_TO_MASTER) {
|
|
|
|
col_add_str(pinfo->cinfo, COL_INFO, "RTU -> Master");
|
|
|
|
/* Retrieve and add Flags to Protocol Tree */
|
|
shr = tvb_get_guint8(tvb, offset) & 0x80;
|
|
con = tvb_get_guint8(tvb, offset) & 0x40;
|
|
frz = tvb_get_guint8(tvb, offset) & 0x20;
|
|
ind = tvb_get_guint8(tvb, offset) & 0x10;
|
|
sch = tvb_get_guint8(tvb, offset) & 0x08;
|
|
slg = tvb_get_guint8(tvb, offset) & 0x04;
|
|
|
|
lg8979_flags_tree = proto_tree_add_subtree(lg8979_tree, tvb, offset, 1, ett_lg8979_flags, &lg8979_flags_item, "Flags");
|
|
|
|
proto_item_append_text(lg8979_flags_item, " (");
|
|
if (shr) comma_needed = add_item_text(lg8979_flags_item, "SHR", comma_needed);
|
|
if (con) comma_needed = add_item_text(lg8979_flags_item, "CON", comma_needed);
|
|
if (frz) comma_needed = add_item_text(lg8979_flags_item, "FRZ", comma_needed);
|
|
if (ind) comma_needed = add_item_text(lg8979_flags_item, "IND", comma_needed);
|
|
if (sch) comma_needed = add_item_text(lg8979_flags_item, "SCH", comma_needed);
|
|
if (slg) add_item_text(lg8979_flags_item, "SLG", comma_needed);
|
|
proto_item_append_text(lg8979_flags_item, ")");
|
|
|
|
proto_tree_add_item(lg8979_flags_tree, hf_lg8979_shr, tvb, offset, 1, ENC_BIG_ENDIAN);
|
|
proto_tree_add_item(lg8979_flags_tree, hf_lg8979_con, tvb, offset, 1, ENC_BIG_ENDIAN);
|
|
proto_tree_add_item(lg8979_flags_tree, hf_lg8979_frz, tvb, offset, 1, ENC_BIG_ENDIAN);
|
|
proto_tree_add_item(lg8979_flags_tree, hf_lg8979_ind, tvb, offset, 1, ENC_BIG_ENDIAN);
|
|
proto_tree_add_item(lg8979_flags_tree, hf_lg8979_sch, tvb, offset, 1, ENC_BIG_ENDIAN);
|
|
proto_tree_add_item(lg8979_flags_tree, hf_lg8979_slg, tvb, offset, 1, ENC_BIG_ENDIAN);
|
|
offset += 1;
|
|
|
|
/* Add RTU Address to Protocol Tree */
|
|
rtu_addr = tvb_get_guint8(tvb, offset);
|
|
col_append_sep_fstr(pinfo->cinfo, COL_INFO, NULL, "Address: %d", rtu_addr);
|
|
|
|
proto_tree_add_item(lg8979_tree, hf_lg8979_address, tvb, offset, 1, ENC_BIG_ENDIAN);
|
|
offset += 1;
|
|
|
|
/* If this is not a short response, and there are at least 2 bytes remaining continue to process function codes */
|
|
while ((!shr) && (tvb_reported_length_remaining(tvb, offset) > 2)){
|
|
|
|
/* Add Function Code & last Mark Block to Protocol Tree */
|
|
/* Function code is 7 lower bits of byte , LMB is 8th bit*/
|
|
func = tvb_get_guint8(tvb, offset) & 0x7f;
|
|
col_append_sep_fstr(pinfo->cinfo, COL_INFO, NULL, "%s",
|
|
val_to_str_const(func, lg8979_funccode_vals, "Unknown Function Code"));
|
|
|
|
lg8979_fc_tree = proto_tree_add_subtree_format(
|
|
lg8979_tree, tvb, offset, 1, ett_lg8979_funccode, NULL,
|
|
"Function Code: %s (%d)", val_to_str_const(func, lg8979_funccode_vals, "Unknown Function Code"), func);
|
|
|
|
proto_tree_add_item(lg8979_fc_tree, hf_lg8979_lastblock, tvb, offset, 1, ENC_BIG_ENDIAN);
|
|
proto_tree_add_item(lg8979_fc_tree, hf_lg8979_funccode, tvb, offset, 1, ENC_BIG_ENDIAN);
|
|
offset += 1;
|
|
|
|
data_len = tvb_get_guint8(tvb, offset);
|
|
proto_tree_add_item(lg8979_tree, hf_lg8979_length, tvb, offset, 1, ENC_BIG_ENDIAN);
|
|
offset += 1;
|
|
|
|
switch (func) {
|
|
/* Function Code 0 Analog Change Report */
|
|
case LG8979_FC_ANG_CHGRPT:
|
|
|
|
num_points = (data_len / 3);
|
|
|
|
for (cnt=0; cnt<num_points; cnt++) {
|
|
|
|
ptnum = ( tvb_get_guint8(tvb, offset) | ((tvb_get_guint8(tvb, offset+1) & 0x0F) << 8) );
|
|
ptval = ( ((tvb_get_guint8(tvb, offset+1) & 0xF0) >> 4) | (tvb_get_guint8(tvb, offset+2) << 4) );
|
|
proto_tree_add_uint_format(lg8979_tree, hf_lg8979_ang_point, tvb, offset, 3, ptnum,
|
|
"Point Number %u: %u", ptnum, ptval);
|
|
offset += 3;
|
|
}
|
|
break;
|
|
|
|
/* Function Code 1 Analog Force Report */
|
|
case LG8979_FC_ANG_FRCRPT:
|
|
|
|
ptnum = tvb_get_letohs(tvb, offset);
|
|
proto_tree_add_item(lg8979_tree, hf_lg8979_start_ptnum16, tvb, offset, 2, ENC_LITTLE_ENDIAN);
|
|
offset += 2;
|
|
|
|
/* Decode 12-bit analog data following this 3-byte bit pattern.
|
|
* Byte 1: PtVal 'N' LSB
|
|
* Byte 2: PtVal 'N+1' LSB : PtVal 'N' MSB
|
|
* Byte 3: PtVal 'N+1' MSB
|
|
* To determine the number of points based on the data bytes, we need to know
|
|
* if we have an even or odd number of data bytes.
|
|
*/
|
|
|
|
/* even number of data bytes */
|
|
if (((data_len-2) % 3) == 0) {
|
|
num_points = (((data_len-2) / 3) * 2);
|
|
}
|
|
/* odd number of data bytes */
|
|
else {
|
|
num_points = ((((data_len-2) / 3) * 2) + 1);
|
|
}
|
|
|
|
/* loop through the data bytes decoding 12-bit analogs.
|
|
When on an even count, offset by 1 and on an odd, offset by 2. */
|
|
for (cnt=0; cnt < num_points; cnt++) {
|
|
if (cnt%2 == 0) {
|
|
|
|
ana12_val = ( tvb_get_guint8(tvb, offset) | ((tvb_get_guint8(tvb, offset+1) & 0x0F) << 8) );
|
|
proto_tree_add_uint_format(lg8979_tree, hf_lg8979_ang_point, tvb, offset, 2, ptnum,
|
|
"Point Number %u: %u", ptnum, ana12_val);
|
|
offset += 1;
|
|
|
|
/* If we are in the last run through the for loop, increment the offset by 1 more byte than normal */
|
|
if (cnt == (num_points - 1)) {
|
|
offset += 1;
|
|
}
|
|
}
|
|
else {
|
|
|
|
ana12_val = ( ((tvb_get_guint8(tvb, offset) & 0xF0) >> 4) | (tvb_get_guint8(tvb, offset+1) << 4) );
|
|
proto_tree_add_uint_format(lg8979_tree, hf_lg8979_ang_point, tvb, offset, 2, ptnum,
|
|
"Point Number %u: %u", ptnum, ana12_val);
|
|
offset += 2;
|
|
}
|
|
ptnum += 1;
|
|
}
|
|
|
|
break;
|
|
|
|
/* Function Code 5 ADC Reference Force Report */
|
|
/* Same byte pattern as 3 sequential analogs in a Force Report would follow */
|
|
case LG8979_FC_ADC_FRCRPT:
|
|
|
|
proto_tree_add_item(lg8979_tree, hf_lg8979_start_ptnum16, tvb, offset, 2, ENC_LITTLE_ENDIAN);
|
|
offset += 2;
|
|
|
|
/* Retrieve the 0 and -90% references */
|
|
ana12_val = ( tvb_get_guint8(tvb, offset) | ((tvb_get_guint8(tvb, offset+1) & 0x0F) << 8) );
|
|
proto_tree_add_uint(lg8979_tree, hf_lg8979_adc_ref_zero, tvb, offset, 2, ana12_val);
|
|
|
|
ana12_val = ( ((tvb_get_guint8(tvb, offset+1) & 0xF0) >> 4) | (tvb_get_guint8(tvb, offset+2) << 4) );
|
|
proto_tree_add_uint(lg8979_tree, hf_lg8979_adc_ref_neg90, tvb, offset+1, 2, ana12_val);
|
|
|
|
offset += 3;
|
|
|
|
/* Retreive the +90% reference */
|
|
ana12_val = ( tvb_get_guint8(tvb, offset) | ((tvb_get_guint8(tvb, offset+1) & 0x0F) << 8) );
|
|
proto_tree_add_uint(lg8979_tree, hf_lg8979_adc_ref_pos90, tvb, offset, 2, ana12_val);
|
|
offset += 2;
|
|
|
|
break;
|
|
|
|
/* Function Code 6 Indication Change Report */
|
|
case LG8979_FC_IND_CHGRPT:
|
|
|
|
num_points = (data_len / 2);
|
|
|
|
for (cnt=0; cnt<num_points; cnt++) {
|
|
/* Get 12-bit point number and new status / change bits */
|
|
ptnum = tvb_get_letohs(tvb, offset) & 0xFFF;
|
|
new_status = (tvb_get_guint8(tvb, offset+1) & 0x80) >> 7;
|
|
change = (tvb_get_guint8(tvb, offset+1) & 0x40) >> 6;
|
|
|
|
lg8979_point_tree = proto_tree_add_subtree_format(lg8979_tree, tvb, offset, 2, ett_lg8979_point, NULL,
|
|
"Indication Change Report, Point Number: %u, Status: %u, Change %u", ptnum, new_status, change);
|
|
|
|
proto_tree_add_item(lg8979_point_tree, hf_lg8979_ind_chgrpt_ptnum, tvb, offset, 2, ENC_LITTLE_ENDIAN);
|
|
proto_tree_add_item(lg8979_point_tree, hf_lg8979_ind_chgrpt_status, tvb, offset, 2, ENC_LITTLE_ENDIAN);
|
|
proto_tree_add_item(lg8979_point_tree, hf_lg8979_ind_chgrpt_change, tvb, offset, 2, ENC_LITTLE_ENDIAN);
|
|
|
|
offset += 2;
|
|
}
|
|
|
|
break;
|
|
|
|
/* Function Code 7 Indication Force Report */
|
|
case LG8979_FC_IND_FRCRPT:
|
|
|
|
ptnum = tvb_get_letohs(tvb, offset);
|
|
proto_tree_add_item(lg8979_tree, hf_lg8979_start_ptnum16, tvb, offset, 2, ENC_LITTLE_ENDIAN);
|
|
offset += 2;
|
|
|
|
num_points = ((data_len - 2) / 2);
|
|
|
|
for (cnt=0; cnt<num_points; cnt++) {
|
|
lg8979_point_tree = proto_tree_add_subtree_format(lg8979_tree, tvb, offset, 1,
|
|
ett_lg8979_point, NULL, "Indication Status, Base Point Num %d", ptnum);
|
|
|
|
proto_tree_add_item(lg8979_point_tree, hf_lg8979_ind_frcrpt_status_b0, tvb, offset, 1, ENC_LITTLE_ENDIAN);
|
|
proto_tree_add_item(lg8979_point_tree, hf_lg8979_ind_frcrpt_status_b1, tvb, offset, 1, ENC_LITTLE_ENDIAN);
|
|
proto_tree_add_item(lg8979_point_tree, hf_lg8979_ind_frcrpt_status_b2, tvb, offset, 1, ENC_LITTLE_ENDIAN);
|
|
proto_tree_add_item(lg8979_point_tree, hf_lg8979_ind_frcrpt_status_b3, tvb, offset, 1, ENC_LITTLE_ENDIAN);
|
|
proto_tree_add_item(lg8979_point_tree, hf_lg8979_ind_frcrpt_status_b4, tvb, offset, 1, ENC_LITTLE_ENDIAN);
|
|
proto_tree_add_item(lg8979_point_tree, hf_lg8979_ind_frcrpt_status_b5, tvb, offset, 1, ENC_LITTLE_ENDIAN);
|
|
proto_tree_add_item(lg8979_point_tree, hf_lg8979_ind_frcrpt_status_b6, tvb, offset, 1, ENC_LITTLE_ENDIAN);
|
|
proto_tree_add_item(lg8979_point_tree, hf_lg8979_ind_frcrpt_status_b7, tvb, offset, 1, ENC_LITTLE_ENDIAN);
|
|
offset += 1;
|
|
|
|
lg8979_point_tree = proto_tree_add_subtree_format(lg8979_tree, tvb, offset, 1,
|
|
ett_lg8979_point, NULL, "Indication Change, Base Point Num %d", ptnum);
|
|
|
|
proto_tree_add_item(lg8979_point_tree, hf_lg8979_ind_frcrpt_change_b0, tvb, offset, 1, ENC_LITTLE_ENDIAN);
|
|
proto_tree_add_item(lg8979_point_tree, hf_lg8979_ind_frcrpt_change_b1, tvb, offset, 1, ENC_LITTLE_ENDIAN);
|
|
proto_tree_add_item(lg8979_point_tree, hf_lg8979_ind_frcrpt_change_b2, tvb, offset, 1, ENC_LITTLE_ENDIAN);
|
|
proto_tree_add_item(lg8979_point_tree, hf_lg8979_ind_frcrpt_change_b3, tvb, offset, 1, ENC_LITTLE_ENDIAN);
|
|
proto_tree_add_item(lg8979_point_tree, hf_lg8979_ind_frcrpt_change_b4, tvb, offset, 1, ENC_LITTLE_ENDIAN);
|
|
proto_tree_add_item(lg8979_point_tree, hf_lg8979_ind_frcrpt_change_b5, tvb, offset, 1, ENC_LITTLE_ENDIAN);
|
|
proto_tree_add_item(lg8979_point_tree, hf_lg8979_ind_frcrpt_change_b6, tvb, offset, 1, ENC_LITTLE_ENDIAN);
|
|
proto_tree_add_item(lg8979_point_tree, hf_lg8979_ind_frcrpt_change_b7, tvb, offset, 1, ENC_LITTLE_ENDIAN);
|
|
offset += 1;
|
|
|
|
ptnum += 8;
|
|
}
|
|
|
|
break;
|
|
|
|
/* Function Code 8 SOE Change Report */
|
|
case LG8979_FC_SOE_CHGRPT:
|
|
|
|
num_points = (data_len / 2);
|
|
|
|
for (cnt=0; cnt<num_points; cnt++) {
|
|
/* Get 12-bit point number and new status / change bits */
|
|
ptnum = tvb_get_letohs(tvb, offset) & 0xFFF;
|
|
new_status = (tvb_get_guint8(tvb, offset+1) & 0x80) >> 7;
|
|
change = (tvb_get_guint8(tvb, offset+1) & 0x40) >> 6;
|
|
|
|
lg8979_point_tree = proto_tree_add_subtree_format(lg8979_tree, tvb, offset, 2, ett_lg8979_point, NULL,
|
|
"SOE Change Report, Point Number: %u, Status: %u, Change %u", ptnum, new_status, change);
|
|
|
|
proto_tree_add_item(lg8979_point_tree, hf_lg8979_soe_chgrpt_ptnum, tvb, offset, 2, ENC_LITTLE_ENDIAN);
|
|
proto_tree_add_item(lg8979_point_tree, hf_lg8979_soe_chgrpt_status, tvb, offset, 2, ENC_LITTLE_ENDIAN);
|
|
proto_tree_add_item(lg8979_point_tree, hf_lg8979_soe_chgrpt_change, tvb, offset, 2, ENC_LITTLE_ENDIAN);
|
|
|
|
offset += 2;
|
|
}
|
|
|
|
break;
|
|
|
|
/* Function Code 9 SOE Force Report */
|
|
case LG8979_FC_SOE_FRCRPT:
|
|
|
|
ptnum = tvb_get_letohs(tvb, offset);
|
|
proto_tree_add_item(lg8979_tree, hf_lg8979_start_ptnum16, tvb, offset, 2, ENC_LITTLE_ENDIAN);
|
|
offset += 2;
|
|
|
|
num_points = ((data_len - 2) / 2);
|
|
|
|
for (cnt=0; cnt<num_points; cnt++) {
|
|
lg8979_point_tree = proto_tree_add_subtree_format(lg8979_tree, tvb, offset, 1,
|
|
ett_lg8979_point, NULL, "SOE Status, Base Point Num %d", ptnum);
|
|
|
|
proto_tree_add_item(lg8979_point_tree, hf_lg8979_soe_frcrpt_status_b0, tvb, offset, 1, ENC_LITTLE_ENDIAN);
|
|
proto_tree_add_item(lg8979_point_tree, hf_lg8979_soe_frcrpt_status_b1, tvb, offset, 1, ENC_LITTLE_ENDIAN);
|
|
proto_tree_add_item(lg8979_point_tree, hf_lg8979_soe_frcrpt_status_b2, tvb, offset, 1, ENC_LITTLE_ENDIAN);
|
|
proto_tree_add_item(lg8979_point_tree, hf_lg8979_soe_frcrpt_status_b3, tvb, offset, 1, ENC_LITTLE_ENDIAN);
|
|
proto_tree_add_item(lg8979_point_tree, hf_lg8979_soe_frcrpt_status_b4, tvb, offset, 1, ENC_LITTLE_ENDIAN);
|
|
proto_tree_add_item(lg8979_point_tree, hf_lg8979_soe_frcrpt_status_b5, tvb, offset, 1, ENC_LITTLE_ENDIAN);
|
|
proto_tree_add_item(lg8979_point_tree, hf_lg8979_soe_frcrpt_status_b6, tvb, offset, 1, ENC_LITTLE_ENDIAN);
|
|
proto_tree_add_item(lg8979_point_tree, hf_lg8979_soe_frcrpt_status_b7, tvb, offset, 1, ENC_LITTLE_ENDIAN);
|
|
offset += 1;
|
|
|
|
lg8979_point_tree = proto_tree_add_subtree_format(lg8979_tree, tvb, offset, 1,
|
|
ett_lg8979_point, NULL, "SOE Change, Base Point Num %d", ptnum);
|
|
|
|
proto_tree_add_item(lg8979_point_tree, hf_lg8979_soe_frcrpt_change_b0, tvb, offset, 1, ENC_LITTLE_ENDIAN);
|
|
proto_tree_add_item(lg8979_point_tree, hf_lg8979_soe_frcrpt_change_b1, tvb, offset, 1, ENC_LITTLE_ENDIAN);
|
|
proto_tree_add_item(lg8979_point_tree, hf_lg8979_soe_frcrpt_change_b2, tvb, offset, 1, ENC_LITTLE_ENDIAN);
|
|
proto_tree_add_item(lg8979_point_tree, hf_lg8979_soe_frcrpt_change_b3, tvb, offset, 1, ENC_LITTLE_ENDIAN);
|
|
proto_tree_add_item(lg8979_point_tree, hf_lg8979_soe_frcrpt_change_b4, tvb, offset, 1, ENC_LITTLE_ENDIAN);
|
|
proto_tree_add_item(lg8979_point_tree, hf_lg8979_soe_frcrpt_change_b5, tvb, offset, 1, ENC_LITTLE_ENDIAN);
|
|
proto_tree_add_item(lg8979_point_tree, hf_lg8979_soe_frcrpt_change_b6, tvb, offset, 1, ENC_LITTLE_ENDIAN);
|
|
proto_tree_add_item(lg8979_point_tree, hf_lg8979_soe_frcrpt_change_b7, tvb, offset, 1, ENC_LITTLE_ENDIAN);
|
|
offset += 1;
|
|
|
|
ptnum += 8;
|
|
}
|
|
|
|
break;
|
|
|
|
/* Function Code 11 Digital Input Force Report */
|
|
case LG8979_FC_DIG_FRCRPT:
|
|
|
|
ptnum8 = tvb_get_guint8(tvb, offset);
|
|
proto_tree_add_item(lg8979_tree, hf_lg8979_start_ptnum8, tvb, offset, 1, ENC_LITTLE_ENDIAN);
|
|
offset += 1;
|
|
|
|
/* 1 byte per start block and 2 bytes per 16-bit block to follow */
|
|
num_points = ((data_len-1)/2);
|
|
|
|
for (cnt=0; cnt<num_points; cnt++) {
|
|
|
|
lg8979_point_tree = proto_tree_add_subtree_format(lg8979_tree, tvb, offset, 2,
|
|
ett_lg8979_point, NULL, "Digital Input Block %d", ptnum8);
|
|
|
|
proto_tree_add_item(lg8979_point_tree, hf_lg8979_digin_b0, tvb, offset, 2, ENC_LITTLE_ENDIAN);
|
|
proto_tree_add_item(lg8979_point_tree, hf_lg8979_digin_b1, tvb, offset, 2, ENC_LITTLE_ENDIAN);
|
|
proto_tree_add_item(lg8979_point_tree, hf_lg8979_digin_b2, tvb, offset, 2, ENC_LITTLE_ENDIAN);
|
|
proto_tree_add_item(lg8979_point_tree, hf_lg8979_digin_b3, tvb, offset, 2, ENC_LITTLE_ENDIAN);
|
|
proto_tree_add_item(lg8979_point_tree, hf_lg8979_digin_b4, tvb, offset, 2, ENC_LITTLE_ENDIAN);
|
|
proto_tree_add_item(lg8979_point_tree, hf_lg8979_digin_b5, tvb, offset, 2, ENC_LITTLE_ENDIAN);
|
|
proto_tree_add_item(lg8979_point_tree, hf_lg8979_digin_b6, tvb, offset, 2, ENC_LITTLE_ENDIAN);
|
|
proto_tree_add_item(lg8979_point_tree, hf_lg8979_digin_b7, tvb, offset, 2, ENC_LITTLE_ENDIAN);
|
|
proto_tree_add_item(lg8979_point_tree, hf_lg8979_digin_b8, tvb, offset, 2, ENC_LITTLE_ENDIAN);
|
|
proto_tree_add_item(lg8979_point_tree, hf_lg8979_digin_b9, tvb, offset, 2, ENC_LITTLE_ENDIAN);
|
|
proto_tree_add_item(lg8979_point_tree, hf_lg8979_digin_b10, tvb, offset, 2, ENC_LITTLE_ENDIAN);
|
|
proto_tree_add_item(lg8979_point_tree, hf_lg8979_digin_b11, tvb, offset, 2, ENC_LITTLE_ENDIAN);
|
|
proto_tree_add_item(lg8979_point_tree, hf_lg8979_digin_b12, tvb, offset, 2, ENC_LITTLE_ENDIAN);
|
|
proto_tree_add_item(lg8979_point_tree, hf_lg8979_digin_b13, tvb, offset, 2, ENC_LITTLE_ENDIAN);
|
|
proto_tree_add_item(lg8979_point_tree, hf_lg8979_digin_b14, tvb, offset, 2, ENC_LITTLE_ENDIAN);
|
|
proto_tree_add_item(lg8979_point_tree, hf_lg8979_digin_b15, tvb, offset, 2, ENC_LITTLE_ENDIAN);
|
|
|
|
ptnum8 += 1;
|
|
offset += 2;
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
/* Function Code 12 Accumulator Change Report */
|
|
/* Function Code 13 Accumulator Force Report */
|
|
case LG8979_FC_ACC_CHGRPT:
|
|
case LG8979_FC_ACC_FRCRPT:
|
|
|
|
ptnum8 = tvb_get_guint8(tvb, offset);
|
|
proto_tree_add_item(lg8979_tree, hf_lg8979_start_ptnum8, tvb, offset, 1, ENC_LITTLE_ENDIAN);
|
|
offset += 1;
|
|
|
|
/* 1 byte for start point number and 2 bytes for each 16-bit accumulator value */
|
|
num_points = ((data_len-1) / 2);
|
|
|
|
for (cnt=0; cnt<num_points; cnt++) {
|
|
|
|
lg8979_point_item = proto_tree_add_item(lg8979_tree, hf_lg8979_acc_point, tvb, offset, 2, ENC_LITTLE_ENDIAN);
|
|
proto_item_prepend_text(lg8979_point_item, "Point Number %u, ", ptnum8);
|
|
|
|
offset += 2;
|
|
ptnum8 += 1;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
/* Function Code 14 SOE Log Change Report */
|
|
case LG8979_FC_SOELOG_CHGRPT:
|
|
|
|
/* 9 bytes for each SOE Record */
|
|
num_points = (data_len / 9);
|
|
|
|
for (cnt=0; cnt<num_points; cnt++) {
|
|
|
|
/* Get 12-bit point number and new status bit */
|
|
ptnum = tvb_get_letohs(tvb, offset) & 0xFFF;
|
|
new_status = (tvb_get_guint8(tvb, offset+1) & 0x80) >> 7;
|
|
|
|
lg8979_point_tree = proto_tree_add_subtree_format(lg8979_tree, tvb, offset, 9, ett_lg8979_point, NULL,
|
|
"SOE Log Change Report, Point Number: %u, New Status: %u", ptnum, new_status);
|
|
|
|
/* Add 12-bit point number and "new status" bit to tree */
|
|
proto_tree_add_item(lg8979_point_tree, hf_lg8979_soe_logchg_ptnum, tvb, offset, 2, ENC_LITTLE_ENDIAN);
|
|
proto_tree_add_item(lg8979_point_tree, hf_lg8979_soe_logchg_newstat, tvb, offset, 2, ENC_LITTLE_ENDIAN);
|
|
offset += 2;
|
|
|
|
/* Add 7-byte time-stamp to tree */
|
|
ts_mon = tvb_get_guint8(tvb, offset);
|
|
ts_day = tvb_get_guint8(tvb, offset+1);
|
|
ts_hr = tvb_get_guint8(tvb, offset+2);
|
|
ts_min = tvb_get_guint8(tvb, offset+3);
|
|
ts_sec = tvb_get_guint8(tvb, offset+4);
|
|
ts_ms = tvb_get_letohs(tvb, offset+5);
|
|
|
|
lg8979_ts_tree = proto_tree_add_subtree_format(lg8979_point_tree, tvb, offset, 7, ett_lg8979_ts, NULL,
|
|
"SOE Time Stamp: [%02d/%02d %02d:%02d:%02d.%03d]", ts_mon, ts_day, ts_hr, ts_min, ts_sec, ts_ms);
|
|
|
|
proto_tree_add_item(lg8979_ts_tree, hf_lg8979_soe_logchg_mon, tvb, offset, 1, ENC_LITTLE_ENDIAN);
|
|
proto_tree_add_item(lg8979_ts_tree, hf_lg8979_soe_logchg_day, tvb, offset+1, 1, ENC_LITTLE_ENDIAN);
|
|
proto_tree_add_item(lg8979_ts_tree, hf_lg8979_soe_logchg_hour, tvb, offset+2, 1, ENC_LITTLE_ENDIAN);
|
|
proto_tree_add_item(lg8979_ts_tree, hf_lg8979_soe_logchg_min, tvb, offset+3, 1, ENC_LITTLE_ENDIAN);
|
|
proto_tree_add_item(lg8979_ts_tree, hf_lg8979_soe_logchg_sec, tvb, offset+4, 1, ENC_LITTLE_ENDIAN);
|
|
proto_tree_add_item(lg8979_ts_tree, hf_lg8979_soe_logchg_msec, tvb, offset+5, 2, ENC_LITTLE_ENDIAN);
|
|
offset += 7;
|
|
}
|
|
|
|
break;
|
|
|
|
/* Function Code 31 RTU Configuration */
|
|
case LG8979_FC_RTU_CONFIG:
|
|
|
|
/* Number of IO Chassis */
|
|
proto_tree_add_item(lg8979_tree, hf_lg8979_rtucfg_num_chassis, tvb, offset, 1, ENC_LITTLE_ENDIAN);
|
|
offset += 1;
|
|
|
|
/* Chassis Number */
|
|
proto_tree_add_item(lg8979_tree, hf_lg8979_rtucfg_chassis_num, tvb, offset, 1, ENC_LITTLE_ENDIAN);
|
|
offset += 1;
|
|
|
|
/* Card Codes For Each Slot (0-15) */
|
|
for (cnt=0; cnt<16; cnt++) {
|
|
lg8979_slot_item = proto_tree_add_item(lg8979_tree, hf_lg8979_rtucfg_card_slot, tvb, offset, 1, ENC_LITTLE_ENDIAN);
|
|
proto_item_prepend_text(lg8979_slot_item, "Slot %d, ", cnt);
|
|
offset += 1;
|
|
}
|
|
|
|
break;
|
|
|
|
/* Function Code 33 Time Bias */
|
|
case LG8979_FC_TIME_BIAS:
|
|
/* Add Time Bias "Processing Time" to tree */
|
|
proto_tree_add_item(lg8979_tree, hf_lg8979_timebias_proctime, tvb, offset, 1, ENC_LITTLE_ENDIAN);
|
|
offset += 1;
|
|
break;
|
|
|
|
/* Function Code 39 Firmware Configuration */
|
|
case LG8979_FC_FIRMWARE_CFG:
|
|
proto_tree_add_item(lg8979_tree, hf_lg8979_firmware_ver, tvb, offset, 2, ENC_LITTLE_ENDIAN);
|
|
offset += 2;
|
|
break;
|
|
|
|
/* Function Code 63 Exception Report */
|
|
/* Parameter byte is context-sensitive to the Code byte used */
|
|
/* For example, if the Code byte is 0x01 (Cold Start) the parameter byte is always 0 */
|
|
/* If the code byte is 0x09 (Function Code), the parameter byte is the value of the disallowed function code */
|
|
case LG8979_FC_EXP_RPT:
|
|
|
|
exp_code = tvb_get_guint8(tvb, offset);
|
|
|
|
proto_tree_add_item(lg8979_tree, hf_lg8979_exprpt_code, tvb, offset, 1, ENC_LITTLE_ENDIAN);
|
|
proto_tree_add_item(lg8979_tree, hf_lg8979_exprpt_parm, tvb, offset+1, 1, ENC_LITTLE_ENDIAN);
|
|
/* Function code lookup, if required */
|
|
if (exp_code == 14) {
|
|
proto_item *lg8979_dfc_item;
|
|
lg8979_dfc_item = proto_tree_add_item(lg8979_tree, hf_lg8979_disallowed_func, tvb, offset+1, 1, ENC_NA);
|
|
PROTO_ITEM_SET_GENERATED(lg8979_dfc_item);
|
|
}
|
|
|
|
offset += 2;
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
} /* !shr */
|
|
|
|
if (shr) {
|
|
col_append_sep_fstr(pinfo->cinfo, COL_INFO, NULL, "Short Response");
|
|
}
|
|
|
|
/* Add CRC-16 */
|
|
proto_tree_add_item(lg8979_tree, hf_lg8979_crc16, tvb, offset, 2, ENC_BIG_ENDIAN);
|
|
|
|
} /* packet type */
|
|
|
|
return tvb_reported_length(tvb);
|
|
|
|
}
|
|
|
|
/******************************************************************************************************/
|
|
/* Return length of L&G 8979 Protocol over TCP message (used for re-assembly) */
|
|
/******************************************************************************************************/
|
|
static guint
|
|
get_lg8979_len(packet_info *pinfo _U_, tvbuff_t *tvb, int offset _U_)
|
|
{
|
|
|
|
guint len;
|
|
len = tvb_reported_length(tvb); /* XXX: should really be some minimum length ?? */
|
|
|
|
return len;
|
|
}
|
|
|
|
/******************************************************************************************************/
|
|
/* Dissect (and possibly Re-assemble) L&G 8979 protocol payload data */
|
|
/******************************************************************************************************/
|
|
static int
|
|
dissect_lg8979_tcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
|
|
{
|
|
|
|
gint length = tvb_reported_length(tvb);
|
|
|
|
/* Check for a L&G8979 packet. It should begin with 0xFF */
|
|
if(length < 2 || tvb_get_guint8(tvb, 0) != 0xFF) {
|
|
/* Not a L&G 8979 Protocol packet, just happened to use the same port */
|
|
return 0;
|
|
}
|
|
|
|
tcp_dissect_pdus(tvb, pinfo, tree, lg8979_desegment, 1,
|
|
get_lg8979_len, dissect_lg8979, data);
|
|
|
|
return length;
|
|
}
|
|
|
|
|
|
/******************************************************************************************************/
|
|
/* Dissect "simple" L&G 8979 protocol payload (no TCP re-assembly) */
|
|
/******************************************************************************************************/
|
|
static int
|
|
dissect_lg8979_simple(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
|
|
{
|
|
gint length = tvb_reported_length(tvb);
|
|
|
|
/* Check for a L&G8979 packet. It should begin with 0xFF */
|
|
if(length < 2 || tvb_get_guint8(tvb, 0) != 0xFF) {
|
|
/* Not a L&G 8979 Protocol packet ... */
|
|
return 0;
|
|
}
|
|
|
|
dissect_lg8979(tvb, pinfo, tree, data);
|
|
|
|
return length;
|
|
}
|
|
|
|
/******************************************************************************************************/
|
|
/* Register the protocol with Wireshark */
|
|
/******************************************************************************************************/
|
|
void proto_reg_handoff_lg8979(void);
|
|
|
|
void
|
|
proto_register_lg8979(void)
|
|
{
|
|
/* L&G 8979 Protocol header fields */
|
|
static hf_register_info lg8979_hf[] = {
|
|
{ &hf_lg8979_header,
|
|
{ "Header", "lg8979.header", FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL }},
|
|
{ &hf_lg8979_shr,
|
|
{ "SHR: Short Response Flag", "lg8979.shr", FT_UINT8, BASE_DEC, NULL, 0x80, NULL, HFILL }},
|
|
{ &hf_lg8979_mfc,
|
|
{ "MFC: Multi Function Code", "lg8979.mfc", FT_UINT8, BASE_DEC, NULL, 0x78, NULL, HFILL }},
|
|
{ &hf_lg8979_ack,
|
|
{ "ACK: Acknowledge Flag", "lg8979.ack", FT_UINT8, BASE_DEC, NULL, 0x04, NULL, HFILL }},
|
|
{ &hf_lg8979_con,
|
|
{ "CON: Continuation Flag", "lg8979.con", FT_UINT8, BASE_DEC, NULL, 0x40, NULL, HFILL }},
|
|
{ &hf_lg8979_frz,
|
|
{ "FRZ: Accumulator Freeze Flag", "lg8979.frz", FT_UINT8, BASE_DEC, NULL, 0x20, NULL, HFILL }},
|
|
{ &hf_lg8979_ind,
|
|
{ "IND: Indication Change Flag", "lg8979.ind", FT_UINT8, BASE_DEC, NULL, 0x10, NULL, HFILL }},
|
|
{ &hf_lg8979_sch,
|
|
{ "SCH: SOE Change Flag", "lg8979.sch", FT_UINT8, BASE_DEC, NULL, 0x08, NULL, HFILL }},
|
|
{ &hf_lg8979_slg,
|
|
{ "SLG: SOE Log Flag", "lg8979.slg", FT_UINT8, BASE_DEC, NULL, 0x04, NULL, HFILL }},
|
|
{ &hf_lg8979_address,
|
|
{ "RTU Address", "lg8979.address", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
|
|
{ &hf_lg8979_lastblock,
|
|
{ "Last Block Mark", "lg8979.lastblock", FT_UINT8, BASE_DEC, NULL, 0x80, NULL, HFILL }},
|
|
{ &hf_lg8979_funccode,
|
|
{ "Function Code", "lg8979.funccode", FT_UINT8, BASE_DEC|BASE_EXT_STRING, &lg8979_funccode_vals_ext, 0x7F, NULL, HFILL }},
|
|
{ &hf_lg8979_length,
|
|
{ "Data Length", "lg8979.length", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
|
|
{ &hf_lg8979_start_ptnum16,
|
|
{ "Start Point Number (16-bit)", "lg8979.start_ptnum16", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
|
|
{ &hf_lg8979_start_ptnum8,
|
|
{ "Start Point Number (8-bit)", "lg8979.start_ptnum8", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
|
|
{ &hf_lg8979_stop_ptnum16,
|
|
{ "Stop Point Number (16-bit)", "lg8979.stop_ptnum16", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
|
|
{ &hf_lg8979_stop_ptnum8,
|
|
{ "Stop Point Number (8-bit)", "lg8979.stop_ptnum8", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
|
|
{ &hf_lg8979_ang_point,
|
|
{ "Analog Point", "lg8979.ang_point", FT_UINT24, BASE_DEC, NULL, 0x0, NULL, HFILL }},
|
|
{ &hf_lg8979_adc_ref_zero,
|
|
{ "ADC Reference (0%)", "lg8979.adc_ref_zero", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
|
|
{ &hf_lg8979_adc_ref_neg90,
|
|
{ "ADC Reference (-90%)", "lg8979.adc_ref_neg90", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
|
|
{ &hf_lg8979_adc_ref_pos90,
|
|
{ "ADC Reference (+90%)", "lg8979.adc_ref_pos90", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
|
|
{ &hf_lg8979_ind_chgrpt_ptnum,
|
|
{ "Point Number (12-bit)", "lg8979.ind_chgrpt_ptnum", FT_UINT16, BASE_DEC, NULL, 0x0FFF, NULL, HFILL }},
|
|
{ &hf_lg8979_ind_chgrpt_status,
|
|
{ "Status Bit", "lg8979.ind_chgrpt_status", FT_UINT16, BASE_DEC, NULL, 0x8000, NULL, HFILL }},
|
|
{ &hf_lg8979_ind_chgrpt_change,
|
|
{ "Change Bit", "lg8979.ind_chgrpt_change", FT_UINT16, BASE_DEC, NULL, 0x4000, NULL, HFILL }},
|
|
{ &hf_lg8979_ind_frcrpt_status_b0,
|
|
{ "Status Bit 0", "lg8979.ind.frcrpt.status_b0", FT_BOOLEAN, 8, NULL, 0x01, NULL, HFILL }},
|
|
{ &hf_lg8979_ind_frcrpt_status_b1,
|
|
{ "Status Bit 1", "lg8979.ind.frcrpt.status_b1", FT_BOOLEAN, 8, NULL, 0x02, NULL, HFILL }},
|
|
{ &hf_lg8979_ind_frcrpt_status_b2,
|
|
{ "Status Bit 2", "lg8979.ind.frcrpt.status_b2", FT_BOOLEAN, 8, NULL, 0x04, NULL, HFILL }},
|
|
{ &hf_lg8979_ind_frcrpt_status_b3,
|
|
{ "Status Bit 3", "lg8979.ind.frcrpt.status_b3", FT_BOOLEAN, 8, NULL, 0x08, NULL, HFILL }},
|
|
{ &hf_lg8979_ind_frcrpt_status_b4,
|
|
{ "Status Bit 4", "lg8979.ind.frcrpt.status_b4", FT_BOOLEAN, 8, NULL, 0x10, NULL, HFILL }},
|
|
{ &hf_lg8979_ind_frcrpt_status_b5,
|
|
{ "Status Bit 5", "lg8979.ind.frcrpt.status_b5", FT_BOOLEAN, 8, NULL, 0x20, NULL, HFILL }},
|
|
{ &hf_lg8979_ind_frcrpt_status_b6,
|
|
{ "Status Bit 6", "lg8979.ind.frcrpt.status_b6", FT_BOOLEAN, 8, NULL, 0x40, NULL, HFILL }},
|
|
{ &hf_lg8979_ind_frcrpt_status_b7,
|
|
{ "Status Bit 7", "lg8979.ind.frcrpt.status_b7", FT_BOOLEAN, 8, NULL, 0x80, NULL, HFILL }},
|
|
{ &hf_lg8979_ind_frcrpt_change_b0,
|
|
{ "Change Bit 0", "lg8979.ind.frcrpt.change_b0", FT_BOOLEAN, 8, NULL, 0x01, NULL, HFILL }},
|
|
{ &hf_lg8979_ind_frcrpt_change_b1,
|
|
{ "Change Bit 1", "lg8979.ind.frcrpt.change_b1", FT_BOOLEAN, 8, NULL, 0x02, NULL, HFILL }},
|
|
{ &hf_lg8979_ind_frcrpt_change_b2,
|
|
{ "Change Bit 2", "lg8979.ind.frcrpt.change_b2", FT_BOOLEAN, 8, NULL, 0x04, NULL, HFILL }},
|
|
{ &hf_lg8979_ind_frcrpt_change_b3,
|
|
{ "Change Bit 3", "lg8979.ind.frcrpt.change_b3", FT_BOOLEAN, 8, NULL, 0x08, NULL, HFILL }},
|
|
{ &hf_lg8979_ind_frcrpt_change_b4,
|
|
{ "Change Bit 4", "lg8979.ind.frcrpt.change_b4", FT_BOOLEAN, 8, NULL, 0x10, NULL, HFILL }},
|
|
{ &hf_lg8979_ind_frcrpt_change_b5,
|
|
{ "Change Bit 5", "lg8979.ind.frcrpt.change_b5", FT_BOOLEAN, 8, NULL, 0x20, NULL, HFILL }},
|
|
{ &hf_lg8979_ind_frcrpt_change_b6,
|
|
{ "Change Bit 6", "lg8979.ind.frcrpt.change_b6", FT_BOOLEAN, 8, NULL, 0x40, NULL, HFILL }},
|
|
{ &hf_lg8979_ind_frcrpt_change_b7,
|
|
{ "Change Bit 7", "lg8979.ind.frcrpt.change_b7", FT_BOOLEAN, 8, NULL, 0x80, NULL, HFILL }},
|
|
{ &hf_lg8979_soe_chgrpt_ptnum,
|
|
{ "Point Number (12-bit)", "lg8979.soe_chgrpt_ptnum", FT_UINT16, BASE_DEC, NULL, 0x0FFF, NULL, HFILL }},
|
|
{ &hf_lg8979_soe_chgrpt_status,
|
|
{ "Status Bit", "lg8979.soe_chgrpt_status", FT_UINT16, BASE_DEC, NULL, 0x8000, NULL, HFILL }},
|
|
{ &hf_lg8979_soe_chgrpt_change,
|
|
{ "Change Bit", "lg8979.soe_chgrpt_change", FT_UINT16, BASE_DEC, NULL, 0x4000, NULL, HFILL }},
|
|
{ &hf_lg8979_soe_frcrpt_status_b0,
|
|
{ "Status Bit 0", "lg8979.soe.frcrpt.status_b0", FT_BOOLEAN, 8, NULL, 0x01, NULL, HFILL }},
|
|
{ &hf_lg8979_soe_frcrpt_status_b1,
|
|
{ "Status Bit 1", "lg8979.soe.frcrpt.status_b1", FT_BOOLEAN, 8, NULL, 0x02, NULL, HFILL }},
|
|
{ &hf_lg8979_soe_frcrpt_status_b2,
|
|
{ "Status Bit 2", "lg8979.soe.frcrpt.status_b2", FT_BOOLEAN, 8, NULL, 0x04, NULL, HFILL }},
|
|
{ &hf_lg8979_soe_frcrpt_status_b3,
|
|
{ "Status Bit 3", "lg8979.soe.frcrpt.status_b3", FT_BOOLEAN, 8, NULL, 0x08, NULL, HFILL }},
|
|
{ &hf_lg8979_soe_frcrpt_status_b4,
|
|
{ "Status Bit 4", "lg8979.soe.frcrpt.status_b4", FT_BOOLEAN, 8, NULL, 0x10, NULL, HFILL }},
|
|
{ &hf_lg8979_soe_frcrpt_status_b5,
|
|
{ "Status Bit 5", "lg8979.soe.frcrpt.status_b5", FT_BOOLEAN, 8, NULL, 0x20, NULL, HFILL }},
|
|
{ &hf_lg8979_soe_frcrpt_status_b6,
|
|
{ "Status Bit 6", "lg8979.soe.frcrpt.status_b6", FT_BOOLEAN, 8, NULL, 0x40, NULL, HFILL }},
|
|
{ &hf_lg8979_soe_frcrpt_status_b7,
|
|
{ "Status Bit 7", "lg8979.soe.frcrpt.status_b7", FT_BOOLEAN, 8, NULL, 0x80, NULL, HFILL }},
|
|
{ &hf_lg8979_soe_frcrpt_change_b0,
|
|
{ "Change Bit 0", "lg8979.soe.frcrpt.change_b0", FT_BOOLEAN, 8, NULL, 0x01, NULL, HFILL }},
|
|
{ &hf_lg8979_soe_frcrpt_change_b1,
|
|
{ "Change Bit 1", "lg8979.soe.frcrpt.change_b1", FT_BOOLEAN, 8, NULL, 0x02, NULL, HFILL }},
|
|
{ &hf_lg8979_soe_frcrpt_change_b2,
|
|
{ "Change Bit 2", "lg8979.soe.frcrpt.change_b2", FT_BOOLEAN, 8, NULL, 0x04, NULL, HFILL }},
|
|
{ &hf_lg8979_soe_frcrpt_change_b3,
|
|
{ "Change Bit 3", "lg8979.soe.frcrpt.change_b3", FT_BOOLEAN, 8, NULL, 0x08, NULL, HFILL }},
|
|
{ &hf_lg8979_soe_frcrpt_change_b4,
|
|
{ "Change Bit 4", "lg8979.soe.frcrpt.change_b4", FT_BOOLEAN, 8, NULL, 0x10, NULL, HFILL }},
|
|
{ &hf_lg8979_soe_frcrpt_change_b5,
|
|
{ "Change Bit 5", "lg8979.soe.frcrpt.change_b5", FT_BOOLEAN, 8, NULL, 0x20, NULL, HFILL }},
|
|
{ &hf_lg8979_soe_frcrpt_change_b6,
|
|
{ "Change Bit 6", "lg8979.soe.frcrpt.change_b6", FT_BOOLEAN, 8, NULL, 0x40, NULL, HFILL }},
|
|
{ &hf_lg8979_soe_frcrpt_change_b7,
|
|
{ "Change Bit 7", "lg8979.soe.frcrpt.change_b7", FT_BOOLEAN, 8, NULL, 0x80, NULL, HFILL }},
|
|
{ &hf_lg8979_digin_b0,
|
|
{ "Digital Input Bit 0", "lg8979.digin_b0", FT_BOOLEAN, 16, NULL, 0x0001, NULL, HFILL }},
|
|
{ &hf_lg8979_digin_b1,
|
|
{ "Digital Input Bit 1", "lg8979.digin_b1", FT_BOOLEAN, 16, NULL, 0x0002, NULL, HFILL }},
|
|
{ &hf_lg8979_digin_b2,
|
|
{ "Digital Input Bit 2", "lg8979.digin_b2", FT_BOOLEAN, 16, NULL, 0x0004, NULL, HFILL }},
|
|
{ &hf_lg8979_digin_b3,
|
|
{ "Digital Input Bit 3", "lg8979.digin_b3", FT_BOOLEAN, 16, NULL, 0x0008, NULL, HFILL }},
|
|
{ &hf_lg8979_digin_b4,
|
|
{ "Digital Input Bit 4", "lg8979.digin_b4", FT_BOOLEAN, 16, NULL, 0x0010, NULL, HFILL }},
|
|
{ &hf_lg8979_digin_b5,
|
|
{ "Digital Input Bit 5", "lg8979.digin_b5", FT_BOOLEAN, 16, NULL, 0x0020, NULL, HFILL }},
|
|
{ &hf_lg8979_digin_b6,
|
|
{ "Digital Input Bit 6", "lg8979.digin_b6", FT_BOOLEAN, 16, NULL, 0x0040, NULL, HFILL }},
|
|
{ &hf_lg8979_digin_b7,
|
|
{ "Digital Input Bit 7", "lg8979.digin_b7", FT_BOOLEAN, 16, NULL, 0x0080, NULL, HFILL }},
|
|
{ &hf_lg8979_digin_b8,
|
|
{ "Digital Input Bit 8", "lg8979.digin_b8", FT_BOOLEAN, 16, NULL, 0x0100, NULL, HFILL }},
|
|
{ &hf_lg8979_digin_b9,
|
|
{ "Digital Input Bit 9", "lg8979.digin_b9", FT_BOOLEAN, 16, NULL, 0x0200, NULL, HFILL }},
|
|
{ &hf_lg8979_digin_b10,
|
|
{ "Digital Input Bit 10", "lg8979.digin_b10", FT_BOOLEAN, 16, NULL, 0x0400, NULL, HFILL }},
|
|
{ &hf_lg8979_digin_b11,
|
|
{ "Digital Input Bit 11", "lg8979.digin_b11", FT_BOOLEAN, 16, NULL, 0x0800, NULL, HFILL }},
|
|
{ &hf_lg8979_digin_b12,
|
|
{ "Digital Input Bit 12", "lg8979.digin_b12", FT_BOOLEAN, 16, NULL, 0x1000, NULL, HFILL }},
|
|
{ &hf_lg8979_digin_b13,
|
|
{ "Digital Input Bit 13", "lg8979.digin_b13", FT_BOOLEAN, 16, NULL, 0x2000, NULL, HFILL }},
|
|
{ &hf_lg8979_digin_b14,
|
|
{ "Digital Input Bit 14", "lg8979.digin_b14", FT_BOOLEAN, 16, NULL, 0x4000, NULL, HFILL }},
|
|
{ &hf_lg8979_digin_b15,
|
|
{ "Digital Input Bit 15", "lg8979.digin_b15", FT_BOOLEAN, 16, NULL, 0x8000, NULL, HFILL }},
|
|
{ &hf_lg8979_acc_point,
|
|
{ "Value", "lg8979.acc_point", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
|
|
{ &hf_lg8979_soe_logchg_ptnum,
|
|
{ "Point Number", "lg8979.soe_logchg_ptnum", FT_UINT16, BASE_DEC, NULL, 0x0FFF, NULL, HFILL }},
|
|
{ &hf_lg8979_soe_logchg_newstat,
|
|
{ "New Status", "lg8979.soe_logchg_newstat", FT_UINT16, BASE_DEC, NULL, 0x8000, NULL, HFILL }},
|
|
{ &hf_lg8979_soe_logchg_mon,
|
|
{ "Month", "lg8979.soe_logchg_mon", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
|
|
{ &hf_lg8979_soe_logchg_day,
|
|
{ "Day", "lg8979.soe_logchg_day", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
|
|
{ &hf_lg8979_soe_logchg_hour,
|
|
{ "Hours", "lg8979.soe_logchg_hour", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
|
|
{ &hf_lg8979_soe_logchg_min,
|
|
{ "Minute", "lg8979.soe_logchg_min", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
|
|
{ &hf_lg8979_soe_logchg_sec,
|
|
{ "Second", "lg8979.soe_logchg_sec", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
|
|
{ &hf_lg8979_soe_logchg_msec,
|
|
{ "Milli-Second", "lg8979.soe_logchg_msec", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
|
|
{ &hf_lg8979_ang_output_val,
|
|
{ "Point Value", "lg8979.ang_output_val", FT_UINT16, BASE_DEC, NULL, 0x0FFF, NULL, HFILL }},
|
|
{ &hf_lg8979_sbo_tripclose,
|
|
{ "Trip/Close Control Code", "lg8979.sbo_tripclose", FT_UINT8, BASE_DEC, VALS(lg8979_sbo_tripclose_vals), 0x80, NULL, HFILL }},
|
|
{ &hf_lg8979_sbo_timercnt,
|
|
{ "Timer Count", "lg8979.sbo_timercnt", FT_UINT8, BASE_DEC, NULL, 0x7F, NULL, HFILL }},
|
|
{ &hf_lg8979_digout_data,
|
|
{ "Data", "lg8979.digout_data", FT_UINT24, BASE_HEX, NULL, 0x0, NULL, HFILL }},
|
|
{ &hf_lg8979_pul_output_base,
|
|
{ "Base Time", "lg8979.pul_output_base", FT_UINT8, BASE_HEX, VALS(lg8979_pul_output_base_vals), 0x03, NULL, HFILL }},
|
|
{ &hf_lg8979_pul_output_dur,
|
|
{ "Duration", "lg8979.pul_output_dur", FT_UINT8, BASE_HEX, NULL, 0x7C, NULL, HFILL }},
|
|
{ &hf_lg8979_pul_output_rl,
|
|
{ "Raise/Lower", "lg8979.pul_output_rl", FT_UINT8, BASE_HEX, VALS(lg8979_pul_output_rl_vals), 0x80, NULL, HFILL }},
|
|
{ &hf_lg8979_ang_deadband,
|
|
{ "Deadband", "lg8979.ang_deadband", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
|
|
{ &hf_lg8979_acc_preset,
|
|
{ "Preset Value", "lg8979.acc_preset", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
|
|
{ &hf_lg8979_rtucfg_num_chassis,
|
|
{ "Number of I/O Chassis in RTU", "lg8979.rtucfg_num_chassis", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
|
|
{ &hf_lg8979_rtucfg_chassis_num,
|
|
{ "Chassis Number", "lg8979.rtucfg_chassis_num", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
|
|
{ &hf_lg8979_rtucfg_card_slot,
|
|
{ "Card Code", "lg8979.rtucfg_card_slot", FT_UINT8, BASE_DEC, VALS(lg8979_cardcode_vals), 0x0, NULL, HFILL }},
|
|
{ &hf_lg8979_timesync_mon,
|
|
{ "Month", "lg8979.timesync_mon", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
|
|
{ &hf_lg8979_timesync_day,
|
|
{ "Day", "lg8979.timesync_day", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
|
|
{ &hf_lg8979_timesync_hour,
|
|
{ "Hours", "lg8979.timesync_hour", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
|
|
{ &hf_lg8979_timesync_min,
|
|
{ "Minute", "lg8979.timesync_min", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
|
|
{ &hf_lg8979_timesync_sec,
|
|
{ "Second", "lg8979.timesync_sec", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
|
|
{ &hf_lg8979_timesync_msec,
|
|
{ "Milli-Second", "lg8979.timesync_msec", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
|
|
{ &hf_lg8979_timebias_value,
|
|
{ "Time Bias Value", "lg8979.timebias_value", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
|
|
{ &hf_lg8979_firmware_ver,
|
|
{ "Firmware Version", "lg8979.firmware_ver", FT_UINT16, BASE_HEX, NULL, 0x0, NULL, HFILL }},
|
|
{ &hf_lg8979_timebias_proctime,
|
|
{ "Time Bias Processing Time (ms)", "lg8979.timebias_proctime", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
|
|
{ &hf_lg8979_exprpt_code,
|
|
{ "Exception Report Code", "lg8979.exprpt_code", FT_UINT8, BASE_DEC, VALS(lg8979_exprpt_code_vals), 0x0, NULL, HFILL }},
|
|
{ &hf_lg8979_exprpt_parm,
|
|
{ "Value", "lg8979.exprpt_parm", FT_UINT8, BASE_DEC, VALS(lg8979_exprpt_parm_vals), 0x0, NULL, HFILL }},
|
|
{ &hf_lg8979_disallowed_func,
|
|
{ "Disallowed Function Code", "lg8979.disallowed_func", FT_UINT8, BASE_DEC|BASE_EXT_STRING, &lg8979_funccode_vals_ext, 0x0, NULL, HFILL }},
|
|
{ &hf_lg8979_crc16,
|
|
{ "CRC-16", "lg8979.crc16", FT_UINT16, BASE_HEX, NULL, 0x0, NULL, HFILL }},
|
|
|
|
};
|
|
|
|
/* Setup protocol subtree array */
|
|
static gint *ett[] = {
|
|
&ett_lg8979,
|
|
&ett_lg8979_flags,
|
|
&ett_lg8979_funccode,
|
|
&ett_lg8979_point,
|
|
&ett_lg8979_ts,
|
|
};
|
|
|
|
module_t *lg8979_module;
|
|
|
|
/* Register the protocol name and description */
|
|
proto_lg8979 = proto_register_protocol("Landis & Gyr Telegyr 8979", "L&G 8979", "lg8979");
|
|
|
|
/* Registering protocol to be called by another dissector */
|
|
new_register_dissector("lg8979", dissect_lg8979_simple, proto_lg8979);
|
|
|
|
/* Required function calls to register the header fields and subtrees used */
|
|
proto_register_field_array(proto_lg8979, lg8979_hf, array_length(lg8979_hf));
|
|
proto_register_subtree_array(ett, array_length(ett));
|
|
|
|
|
|
/* Register required preferences for L&G 8979 register decoding */
|
|
lg8979_module = prefs_register_protocol(proto_lg8979, proto_reg_handoff_lg8979);
|
|
|
|
/* L&G 8979 - Desegmentmentation; defaults to TRUE for TCP desegmentation*/
|
|
prefs_register_bool_preference(lg8979_module, "desegment",
|
|
"Desegment all L&G 8979 Protocol packets spanning multiple TCP segments",
|
|
"Whether the L&G 8979 dissector should desegment all messages spanning multiple TCP segments",
|
|
&lg8979_desegment);
|
|
|
|
|
|
/* L&G 8979 Preference - Default TCP Port, allows for "user" port either than 0. */
|
|
prefs_register_uint_preference(lg8979_module, "tcp.port",
|
|
"L&G 8979 Protocol Port",
|
|
"Set the TCP port for L&G 8979 Protocol packets (if other than the default of 0)",
|
|
10, &global_lg8979_tcp_port);
|
|
}
|
|
|
|
/******************************************************************************************************/
|
|
void
|
|
proto_reg_handoff_lg8979(void)
|
|
{
|
|
static int lg8979_prefs_initialized = FALSE;
|
|
static dissector_handle_t lg8979_handle;
|
|
static unsigned int lg8979_port;
|
|
|
|
/* Make sure to use L&G 8979 Protocol Preferences field to determine default TCP port */
|
|
if (! lg8979_prefs_initialized) {
|
|
lg8979_handle = new_create_dissector_handle(dissect_lg8979_tcp, proto_lg8979);
|
|
lg8979_prefs_initialized = TRUE;
|
|
}
|
|
|
|
if(lg8979_port != 0 && lg8979_port != global_lg8979_tcp_port){
|
|
dissector_delete_uint("tcp.port", lg8979_port, lg8979_handle);
|
|
}
|
|
|
|
if(global_lg8979_tcp_port != 0 && lg8979_port != global_lg8979_tcp_port) {
|
|
dissector_add_uint("tcp.port", global_lg8979_tcp_port, lg8979_handle);
|
|
}
|
|
|
|
lg8979_port = global_lg8979_tcp_port;
|
|
|
|
dissector_add_uint("rtacser.data", RTACSER_PAYLOAD_LG8979, lg8979_handle);
|
|
}
|
|
|
|
/*
|
|
* Editor modelines - http://www.wireshark.org/tools/modelines.html
|
|
*
|
|
* Local variables:
|
|
* c-basic-offset: 4
|
|
* tab-width: 8
|
|
* indent-tabs-mode: nil
|
|
* End:
|
|
*
|
|
* vi: set shiftwidth=4 tabstop=8 expandtab:
|
|
* :indentSize=4:tabSize=8:noTabs=true:
|
|
*/
|