2 * Routines for Landis & Gyr (Telegyr) 8979 Protocol (lg8979) Dissection
3 * By Chris Bontje (cbontje[AT]gmail.com
6 ************************************************************************************************
7 * Wireshark - Network traffic analyzer
8 * By Gerald Combs <gerald@wireshark.org>
9 * Copyright 1998 Gerald Combs
11 * SPDX-License-Identifier: GPL-2.0-or-later
16 #include <epan/packet.h>
17 #include "packet-tcp.h"
18 #include <epan/prefs.h>
20 void proto_register_lg8979(void);
22 /* Initialize the protocol and registered fields */
23 static int proto_lg8979
;
24 static int hf_lg8979_header
;
25 static int hf_lg8979_flags
;
26 static int hf_lg8979_shr
;
27 static int hf_lg8979_mfc
;
28 static int hf_lg8979_ack
;
29 static int hf_lg8979_con
;
30 static int hf_lg8979_frz
;
31 static int hf_lg8979_ind
;
32 static int hf_lg8979_sch
;
33 static int hf_lg8979_slg
;
34 static int hf_lg8979_address
;
35 static int hf_lg8979_lastblock
;
36 static int hf_lg8979_funccode
;
37 static int hf_lg8979_length
;
38 static int hf_lg8979_start_ptnum16
;
39 static int hf_lg8979_start_ptnum8
;
40 static int hf_lg8979_stop_ptnum16
;
41 static int hf_lg8979_stop_ptnum8
;
42 static int hf_lg8979_ang_point
;
43 static int hf_lg8979_adc_ref_zero
;
44 static int hf_lg8979_adc_ref_neg90
;
45 static int hf_lg8979_adc_ref_pos90
;
46 static int hf_lg8979_ind_chgrpt_ptnum
;
47 static int hf_lg8979_ind_chgrpt_status
;
48 static int hf_lg8979_ind_chgrpt_change
;
49 static int hf_lg8979_ind_frcrpt_status_b0
;
50 static int hf_lg8979_ind_frcrpt_status_b1
;
51 static int hf_lg8979_ind_frcrpt_status_b2
;
52 static int hf_lg8979_ind_frcrpt_status_b3
;
53 static int hf_lg8979_ind_frcrpt_status_b4
;
54 static int hf_lg8979_ind_frcrpt_status_b5
;
55 static int hf_lg8979_ind_frcrpt_status_b6
;
56 static int hf_lg8979_ind_frcrpt_status_b7
;
57 static int hf_lg8979_ind_frcrpt_change_b0
;
58 static int hf_lg8979_ind_frcrpt_change_b1
;
59 static int hf_lg8979_ind_frcrpt_change_b2
;
60 static int hf_lg8979_ind_frcrpt_change_b3
;
61 static int hf_lg8979_ind_frcrpt_change_b4
;
62 static int hf_lg8979_ind_frcrpt_change_b5
;
63 static int hf_lg8979_ind_frcrpt_change_b6
;
64 static int hf_lg8979_ind_frcrpt_change_b7
;
65 static int hf_lg8979_soe_chgrpt_ptnum
;
66 static int hf_lg8979_soe_chgrpt_status
;
67 static int hf_lg8979_soe_chgrpt_change
;
68 static int hf_lg8979_soe_frcrpt_status_b0
;
69 static int hf_lg8979_soe_frcrpt_status_b1
;
70 static int hf_lg8979_soe_frcrpt_status_b2
;
71 static int hf_lg8979_soe_frcrpt_status_b3
;
72 static int hf_lg8979_soe_frcrpt_status_b4
;
73 static int hf_lg8979_soe_frcrpt_status_b5
;
74 static int hf_lg8979_soe_frcrpt_status_b6
;
75 static int hf_lg8979_soe_frcrpt_status_b7
;
76 static int hf_lg8979_soe_frcrpt_change_b0
;
77 static int hf_lg8979_soe_frcrpt_change_b1
;
78 static int hf_lg8979_soe_frcrpt_change_b2
;
79 static int hf_lg8979_soe_frcrpt_change_b3
;
80 static int hf_lg8979_soe_frcrpt_change_b4
;
81 static int hf_lg8979_soe_frcrpt_change_b5
;
82 static int hf_lg8979_soe_frcrpt_change_b6
;
83 static int hf_lg8979_soe_frcrpt_change_b7
;
84 static int hf_lg8979_digin_b0
;
85 static int hf_lg8979_digin_b1
;
86 static int hf_lg8979_digin_b2
;
87 static int hf_lg8979_digin_b3
;
88 static int hf_lg8979_digin_b4
;
89 static int hf_lg8979_digin_b5
;
90 static int hf_lg8979_digin_b6
;
91 static int hf_lg8979_digin_b7
;
92 static int hf_lg8979_digin_b8
;
93 static int hf_lg8979_digin_b9
;
94 static int hf_lg8979_digin_b10
;
95 static int hf_lg8979_digin_b11
;
96 static int hf_lg8979_digin_b12
;
97 static int hf_lg8979_digin_b13
;
98 static int hf_lg8979_digin_b14
;
99 static int hf_lg8979_digin_b15
;
100 static int hf_lg8979_acc_point
;
101 static int hf_lg8979_soe_logchg_ptnum
;
102 static int hf_lg8979_soe_logchg_newstat
;
103 static int hf_lg8979_soe_logchg_mon
;
104 static int hf_lg8979_soe_logchg_day
;
105 static int hf_lg8979_soe_logchg_hour
;
106 static int hf_lg8979_soe_logchg_min
;
107 static int hf_lg8979_soe_logchg_sec
;
108 static int hf_lg8979_soe_logchg_msec
;
109 static int hf_lg8979_ang_output_val
;
110 static int hf_lg8979_sbo_tripclose
;
111 static int hf_lg8979_sbo_timercnt
;
112 static int hf_lg8979_digout_data
;
113 static int hf_lg8979_pul_output_base
;
114 static int hf_lg8979_pul_output_dur
;
115 static int hf_lg8979_pul_output_rl
;
116 static int hf_lg8979_ang_deadband
;
117 static int hf_lg8979_ang_group
;
118 static int hf_lg8979_ang_group_pts
;
119 static int hf_lg8979_acc_preset
;
120 static int hf_lg8979_rtucfg_num_chassis
;
121 static int hf_lg8979_rtucfg_chassis_num
;
122 static int hf_lg8979_rtucfg_card_slot
;
123 static int hf_lg8979_timesync_mon
;
124 static int hf_lg8979_timesync_day
;
125 static int hf_lg8979_timesync_hour
;
126 static int hf_lg8979_timesync_min
;
127 static int hf_lg8979_timesync_sec
;
128 static int hf_lg8979_timesync_msec
;
129 static int hf_lg8979_timebias_value
;
130 static int hf_lg8979_timebias_proctime
;
131 static int hf_lg8979_firmware_ver
;
132 static int hf_lg8979_exprpt_code
;
133 static int hf_lg8979_exprpt_parm
;
134 static int hf_lg8979_disallowed_func
;
135 static int hf_lg8979_crc16
;
137 /* Initialize the subtree pointers */
138 static int ett_lg8979
;
139 static int ett_lg8979_flags
;
140 static int ett_lg8979_funccode
;
141 static int ett_lg8979_point
;
142 static int ett_lg8979_ts
;
144 /* Globals for L&G 8979 Protocol Preferences */
145 static bool lg8979_desegment
= true;
147 #define LG8979_HEADER 0xFF
149 #define LG8979_DIR_INDETERMINATE 0
150 #define LG8979_DIR_MASTER_TO_RTU 1
151 #define LG8979_DIR_RTU_TO_MASTER 2
154 #define LG8979_FC_ANG_CHGRPT 0
155 #define LG8979_FC_ANG_FRCRPT 1
156 #define LG8979_FC_ANGGRP_CHGRPT 2
157 #define LG8979_FC_ANGGRP_FRCRPT 3
158 #define LG8979_FC_ADC_FRCRPT 5
159 #define LG8979_FC_IND_CHGRPT 6
160 #define LG8979_FC_IND_FRCRPT 7
161 #define LG8979_FC_SOE_CHGRPT 8
162 #define LG8979_FC_SOE_FRCRPT 9
163 #define LG8979_FC_DIG_FRCRPT 11
164 #define LG8979_FC_ACC_CHGRPT 12
165 #define LG8979_FC_ACC_FRCRPT 13
166 #define LG8979_FC_SOELOG_CHGRPT 14
167 #define LG8979_FC_ANG_OUTPUT 20
168 #define LG8979_FC_SBO_SELECT 21
169 #define LG8979_FC_SBO_OPERATE 22
170 #define LG8979_FC_DIG_OUTPUT 23
171 #define LG8979_FC_ACC_FREEZE 24
172 #define LG8979_FC_PUL_OUTPUT 25
173 #define LG8979_FC_PULTR_OUTPUT 26
174 #define LG8979_FC_SBO_IMEXECUTE 28
175 #define LG8979_FC_RTU_RESTART 30
176 #define LG8979_FC_RTU_CONFIG 31
177 #define LG8979_FC_TIME_SYNC 32
178 #define LG8979_FC_TIME_BIAS 33
179 #define LG8979_FC_ANG_DEADBAND 34
180 #define LG8979_FC_ANGGRP_DEFINE 35
181 #define LG8979_FC_ACC_PRESET 36
182 #define LG8979_FC_CONT_REQUEST 37
183 #define LG8979_FC_REPEAT_MSG 38
184 #define LG8979_FC_FIRMWARE_CFG 39
185 #define LG8979_FC_TABLE_READ 47
186 #define LG8979_FC_TABLE_WRITE 48
187 #define LG8979_FC_SPRPT_INT 50
188 #define LG8979_FC_SPRPT_SEQNUM 51
189 #define LG8979_FC_EXP_RPT 63
191 static const value_string lg8979_funccode_vals
[] = {
192 { LG8979_FC_ANG_CHGRPT
, "Analog Change Report" },
193 { LG8979_FC_ANG_FRCRPT
, "Analog Force Report" },
194 { LG8979_FC_ANGGRP_CHGRPT
, "Analog Group Change Report" },
195 { LG8979_FC_ANGGRP_FRCRPT
, "Analog Group Force Report" },
196 { 4, "Unknown/Invalid Function" },
197 { LG8979_FC_ADC_FRCRPT
, "ADC Reference Force Report" },
198 { LG8979_FC_IND_CHGRPT
, "Indication Change Report" },
199 { LG8979_FC_IND_FRCRPT
, "Indication Force Report" },
200 { LG8979_FC_SOE_CHGRPT
, "SOE Change Report" },
201 { LG8979_FC_SOE_FRCRPT
, "SOE Force Report" },
202 { 10, "Unknown/Invalid Function" },
203 { LG8979_FC_DIG_FRCRPT
, "Digital Input Force Report" },
204 { LG8979_FC_ACC_CHGRPT
, "Accumulator Change Report" },
205 { LG8979_FC_ACC_FRCRPT
, "Accumulator Force Report" },
206 { LG8979_FC_SOELOG_CHGRPT
, "SOE Log Change Report" },
207 { 15, "Unknown/Invalid Function" },
208 { 16, "Unknown/Invalid Function" },
209 { 17, "Unknown/Invalid Function" },
210 { 18, "Unknown/Invalid Function" },
211 { 19, "Unknown/Invalid Function" },
212 { LG8979_FC_ANG_OUTPUT
, "Analog Output" },
213 { LG8979_FC_SBO_SELECT
, "SBO Select" },
214 { LG8979_FC_SBO_OPERATE
, "SBO Operate" },
215 { LG8979_FC_DIG_OUTPUT
, "Digital Output" },
216 { LG8979_FC_ACC_FREEZE
, "Accumulator Freeze" },
217 { LG8979_FC_PUL_OUTPUT
, "Pulse Output" },
218 { LG8979_FC_PULTR_OUTPUT
, "Pulse Train Output" },
219 { 27, "Unknown/Invalid Function" },
220 { LG8979_FC_SBO_IMEXECUTE
, "SBO Immediate Execute" },
221 { 29, "Unknown/Invalid Function" },
222 { LG8979_FC_RTU_RESTART
, "Restart RTU" },
223 { LG8979_FC_RTU_CONFIG
, "RTU Configuration" },
224 { LG8979_FC_TIME_SYNC
, "Time Synchronization" },
225 { LG8979_FC_TIME_BIAS
, "Time Bias" },
226 { LG8979_FC_ANG_DEADBAND
, "Analog Deadbands" },
227 { LG8979_FC_ANGGRP_DEFINE
, "Analog Group Define" },
228 { LG8979_FC_ACC_PRESET
, "Accumulator Preset" },
229 { LG8979_FC_CONT_REQUEST
, "Continuation Request" },
230 { LG8979_FC_REPEAT_MSG
, "Repeat Last Message" },
231 { LG8979_FC_FIRMWARE_CFG
, "Firmware Configuration" },
232 { 40, "Unknown/Invalid Function" },
233 { 41, "Unknown/Invalid Function" },
234 { 42, "Unknown/Invalid Function" },
235 { 43, "Unknown/Invalid Function" },
236 { 44, "Unknown/Invalid Function" },
237 { 45, "Unknown/Invalid Function" },
238 { 46, "Unknown/Invalid Function" },
239 { LG8979_FC_TABLE_READ
, "Table Read" },
240 { LG8979_FC_TABLE_WRITE
, "Table Write" },
241 { 49, "Unknown/Invalid Function" },
242 { LG8979_FC_SPRPT_INT
, "Spontaneous Report Interval" },
243 { LG8979_FC_SPRPT_SEQNUM
, "Spontaneous Report Sequence Number" },
244 { 52, "Unknown/Invalid Function" },
245 { 53, "Unknown/Invalid Function" },
246 { 54, "Unknown/Invalid Function" },
247 { 55, "Unknown/Invalid Function" },
248 { 56, "Unknown/Invalid Function" },
249 { 57, "Unknown/Invalid Function" },
250 { 58, "Unknown/Invalid Function" },
251 { 59, "Unknown/Invalid Function" },
252 { 60, "Unknown/Invalid Function" },
253 { 61, "Unknown/Invalid Function" },
254 { 62, "Unknown/Invalid Function" },
255 { LG8979_FC_EXP_RPT
, "Exception Report" },
258 static value_string_ext lg8979_funccode_vals_ext
= VALUE_STRING_EXT_INIT(lg8979_funccode_vals
);
260 static const value_string lg8979_cardcode_vals
[] = {
261 { 0, "Non-Existent Slot" },
262 { 1, "Analog Input" },
263 { 2, "A/D Converter" },
264 { 3, "Analog Output" },
265 { 4, "Indication Input" },
266 { 5, "24-Bit Digital Output" },
267 { 7, "SBO Control Output" },
268 { 8, "Accumulator, Form A" },
269 { 11, "32-Bit Digital Output" },
270 { 12, "Accumulator, Form C" },
271 { 15, "Pulse Output" },
274 { 30, "Serial Data Collector" },
275 { 31, "Empty Slot" },
279 static const value_string lg8979_exprpt_code_vals
[] = {
280 { 0x00, "Warm Restart" },
281 { 0x01, "Cold Start" },
282 { 0x02, "Insufficient Ram" },
283 { 0x03, "Bus Failure" },
284 { 0x04, "SBO Failure" },
285 { 0x05, "Analog Failure" },
286 { 0x06, "Indication/SOE Failure" },
287 { 0x07, "Card Placement Error" },
288 { 0x08, "Not Used" },
289 { 0x09, "Invalid Function Code" },
290 { 0x0A, "Invalid Block Length" },
291 { 0x0B, "Non-Existent Point" },
292 { 0x0C, "Invalid Parameter" },
293 { 0x0D, "Select/Execute Mismatch" },
294 { 0x0E, "Function Not Allowed" },
295 { 0x0F, "Not Used" },
296 { 0x10, "Database Setup has Changed" },
297 { 0x11, "Indication Change Sequence" },
301 static const value_string lg8979_exprpt_parm_vals
[] = {
303 { 0x01, "1=Requested CLDSTRT" },
306 { 0x04, "Unit/Slot" },
307 { 0x05, "Unit/Slot" },
308 { 0x06, "Unit/Slot" },
309 { 0x07, "Unit/Slot" },
311 { 0x09, "Function Code" },
312 { 0x0A, "Block Length" },
314 { 0x0C, "Parameter" },
315 { 0x0D, "Execute Point" },
316 { 0x0E, "Function Code" },
319 { 0x11, "1=Time Order (0=Not T/O)" },
323 static const value_string lg8979_sbo_tripclose_vals
[] = {
329 static const value_string lg8979_pul_output_base_vals
[] = {
331 { 0x01, "100 msec" },
337 static const value_string lg8979_pul_output_rl_vals
[] = {
343 /*************************************************************/
344 /* Try to determine "direction" of message. */
345 /* Check the data length within the packet and compare */
346 /* vs. the function code. Master->RTU messages will have a */
347 /* fixed length that can be used to determine the direction */
349 /*************************************************************/
351 classify_lg8979_packet(tvbuff_t
*tvb
)
353 uint8_t func
, len
, data_len
, flags
;
355 len
= tvb_reported_length(tvb
);
356 /* If TVB length is equal to 5, this is classified as a 'short response message' */
357 /* and is guaranteed to be RTU->Master only */
359 return LG8979_DIR_RTU_TO_MASTER
;
362 /* If TVB length is greater than 5, let's dig deeper */
365 flags
= tvb_get_uint8(tvb
, 1);
367 /* Flags vary between message types, so let's try those first to determine the message direction */
368 /* If both bit 3 and bit 4 are set, this is almost certainly a RTU->Master message */
369 if ( (flags
& 0x04) && (flags
& 0x08) ){
370 return LG8979_DIR_RTU_TO_MASTER
;
372 /* If anything is in bits 3-6 without bit 7, this is a RTU->Master message */
373 else if ( (flags
& 0x78) && !(flags
& 0x80) ){
374 return LG8979_DIR_RTU_TO_MASTER
;
377 func
= tvb_get_uint8(tvb
, 3) & 0x7F;
378 data_len
= tvb_get_uint8(tvb
, 4);
380 /* If we have more data in the tvb then should be there, this is a stacked RTU->Master response */
381 if (len
> (data_len
+ 5 + 2)) {
382 return LG8979_DIR_RTU_TO_MASTER
;
386 case LG8979_FC_ANG_CHGRPT
:
387 case LG8979_FC_ADC_FRCRPT
:
388 case LG8979_FC_IND_CHGRPT
:
389 case LG8979_FC_SOE_CHGRPT
:
390 case LG8979_FC_ACC_CHGRPT
:
391 case LG8979_FC_SOELOG_CHGRPT
:
392 case LG8979_FC_REPEAT_MSG
:
393 case LG8979_FC_RTU_CONFIG
:
394 case LG8979_FC_FIRMWARE_CFG
:
396 return LG8979_DIR_MASTER_TO_RTU
;
399 return LG8979_DIR_RTU_TO_MASTER
;
403 case LG8979_FC_ANGGRP_CHGRPT
:
404 case LG8979_FC_ANGGRP_FRCRPT
:
406 return LG8979_DIR_MASTER_TO_RTU
;
409 return LG8979_DIR_RTU_TO_MASTER
;
414 case LG8979_FC_DIG_FRCRPT
:
415 case LG8979_FC_ACC_FRCRPT
:
416 case LG8979_FC_TIME_BIAS
:
418 return LG8979_DIR_MASTER_TO_RTU
;
421 return LG8979_DIR_RTU_TO_MASTER
;
425 case LG8979_FC_ANG_FRCRPT
:
426 case LG8979_FC_IND_FRCRPT
:
427 case LG8979_FC_SOE_FRCRPT
:
429 return LG8979_DIR_MASTER_TO_RTU
;
432 return LG8979_DIR_RTU_TO_MASTER
;
436 /* These are either totally or mostly master->RTU operations */
437 case LG8979_FC_ANG_OUTPUT
:
438 case LG8979_FC_SBO_SELECT
:
439 case LG8979_FC_SBO_OPERATE
:
440 case LG8979_FC_DIG_OUTPUT
:
441 case LG8979_FC_ACC_FREEZE
:
442 case LG8979_FC_PUL_OUTPUT
:
443 case LG8979_FC_PULTR_OUTPUT
:
444 case LG8979_FC_SBO_IMEXECUTE
:
445 case LG8979_FC_TIME_SYNC
:
446 case LG8979_FC_ANG_DEADBAND
:
447 case LG8979_FC_ANGGRP_DEFINE
:
448 case LG8979_FC_ACC_PRESET
:
449 case LG8979_FC_CONT_REQUEST
:
451 return LG8979_DIR_MASTER_TO_RTU
;
453 case LG8979_FC_EXP_RPT
:
454 return LG8979_DIR_RTU_TO_MASTER
;
457 return LG8979_DIR_INDETERMINATE
;
461 /* else, cannot classify */
462 return LG8979_DIR_INDETERMINATE
;
465 /******************************************************************************************************/
466 /* Code to dissect L&G 8979 Protocol packets */
467 /******************************************************************************************************/
469 dissect_lg8979(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void* data _U_
)
471 /* Set up structures needed to add the protocol subtree and manage it */
472 proto_item
*lg8979_item
, *lg8979_point_item
= NULL
;
473 proto_item
*lg8979_slot_item
= NULL
, *lg8979_ang_group_pts_item
= NULL
;
474 proto_tree
*lg8979_tree
, *lg8979_fc_tree
= NULL
;
475 proto_tree
*lg8979_point_tree
= NULL
, *lg8979_ts_tree
= NULL
;
477 uint8_t rtu_addr
, func
, packet_type
, data_len
, ptnum8
, tripclose
, rl
, exp_code
, num_chassis
;
478 uint8_t ts_mon
, ts_day
, ts_hr
, ts_min
, ts_sec
;
479 uint16_t ptnum
, ptval
, ana12_val
;
481 int num_points
= 0, cnt
= 0, cnt1
= 0;
482 bool shr
, new_status
, change
;
484 /* Make entries in Protocol column on summary display */
485 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, "L&G 8979");
486 col_clear(pinfo
->cinfo
, COL_INFO
);
488 lg8979_item
= proto_tree_add_item(tree
, proto_lg8979
, tvb
, 0, -1, ENC_NA
);
489 lg8979_tree
= proto_item_add_subtree(lg8979_item
, ett_lg8979
);
491 /* Add 0xFF Header to Protocol Tree */
492 proto_tree_add_item(lg8979_tree
, hf_lg8979_header
, tvb
, offset
, 1, ENC_LITTLE_ENDIAN
);
495 /* "Request" or "Response" */
496 packet_type
= classify_lg8979_packet(tvb
);
498 /* This packet type is classified as a "Request" and is deemed in the direction of "master -> RTU" */
499 if (packet_type
== LG8979_DIR_MASTER_TO_RTU
) {
500 static int * const request_flags
[] = {
507 col_set_str(pinfo
->cinfo
, COL_INFO
, "Master -> RTU");
509 /* Add Flags to Protocol Tree */
510 shr
= tvb_get_uint8(tvb
, offset
) & 0x80;
512 proto_tree_add_bitmask(lg8979_tree
, tvb
, offset
, hf_lg8979_flags
, ett_lg8979_flags
, request_flags
, ENC_LITTLE_ENDIAN
);
515 /* Add RTU Address to Protocol Tree */
516 rtu_addr
= tvb_get_uint8(tvb
, offset
);
517 col_append_sep_fstr(pinfo
->cinfo
, COL_INFO
, NULL
, "Address: %d", rtu_addr
);
519 proto_tree_add_item(lg8979_tree
, hf_lg8979_address
, tvb
, offset
, 1, ENC_LITTLE_ENDIAN
);
523 /* Add Function Code & last Mark Block to Protocol Tree */
524 /* Function code is 7 lower bits of byte , LMB is 8th bit*/
525 func
= tvb_get_uint8(tvb
, offset
) & 0x7f;
527 col_append_sep_str(pinfo
->cinfo
, COL_INFO
, NULL
,
528 val_to_str_const(func
, lg8979_funccode_vals
, "Unknown Function Code"));
530 lg8979_fc_tree
= proto_tree_add_subtree_format(
531 lg8979_tree
, tvb
, offset
, 1, ett_lg8979_funccode
, NULL
,
532 "Function Code: %s (%d)",
533 val_to_str_const(func
, lg8979_funccode_vals
, "Unknown Function Code"), func
);
535 proto_tree_add_item(lg8979_fc_tree
, hf_lg8979_lastblock
, tvb
, offset
, 1, ENC_LITTLE_ENDIAN
);
536 proto_tree_add_item(lg8979_fc_tree
, hf_lg8979_funccode
, tvb
, offset
, 1, ENC_LITTLE_ENDIAN
);
539 data_len
= tvb_get_uint8(tvb
, offset
);
540 proto_tree_add_item(lg8979_tree
, hf_lg8979_length
, tvb
, offset
, 1, ENC_LITTLE_ENDIAN
);
544 /* Function Code 0 Analog Change Report */
545 /* Function Code 7 Indication Force Report */
546 /* Function Code 9 SOE Force Report */
547 case LG8979_FC_ANG_FRCRPT
:
548 case LG8979_FC_IND_FRCRPT
:
549 case LG8979_FC_SOE_FRCRPT
:
550 proto_tree_add_item(lg8979_tree
, hf_lg8979_start_ptnum16
, tvb
, offset
, 2, ENC_LITTLE_ENDIAN
);
551 proto_tree_add_item(lg8979_tree
, hf_lg8979_stop_ptnum16
, tvb
, offset
+2, 2, ENC_LITTLE_ENDIAN
);
555 /* Function Code 2 Analog Group Change Report */
556 case LG8979_FC_ANGGRP_CHGRPT
:
557 proto_tree_add_item(lg8979_tree
, hf_lg8979_ang_group
, tvb
, offset
, 1, ENC_LITTLE_ENDIAN
);
561 /* Function Code 11 Digital Input Force Report */
562 /* Function Code 13 Accumulator Force Report */
563 case LG8979_FC_DIG_FRCRPT
:
564 case LG8979_FC_ACC_FRCRPT
:
565 proto_tree_add_item(lg8979_tree
, hf_lg8979_start_ptnum8
, tvb
, offset
, 1, ENC_LITTLE_ENDIAN
);
566 proto_tree_add_item(lg8979_tree
, hf_lg8979_stop_ptnum8
, tvb
, offset
+1, 1, ENC_LITTLE_ENDIAN
);
570 /* Function Code 20 Analog Output */
571 case LG8979_FC_ANG_OUTPUT
:
572 proto_tree_add_item(lg8979_tree
, hf_lg8979_start_ptnum8
, tvb
, offset
, 1, ENC_LITTLE_ENDIAN
);
573 proto_tree_add_item(lg8979_tree
, hf_lg8979_ang_output_val
, tvb
, offset
+1, 2, ENC_LITTLE_ENDIAN
);
577 /* Function Code 21 SBO Select */
578 case LG8979_FC_SBO_SELECT
:
580 /* Get 8-bit point number and trip/close command-code */
581 ptnum
= tvb_get_uint8(tvb
, offset
);
582 tripclose
= (tvb_get_uint8(tvb
, offset
+1) & 0x80) >> 7;
584 lg8979_point_tree
= proto_tree_add_subtree_format(
585 lg8979_tree
, tvb
, offset
, 2,
586 ett_lg8979_point
, NULL
,
587 "SBO Command, Pt.Num: %u, Code: %s",
589 val_to_str_const(tripclose
, lg8979_sbo_tripclose_vals
, "Unknown Control Code"));
591 /* Update the Information Column with Command Details */
592 col_append_sep_fstr(pinfo
->cinfo
, COL_INFO
, NULL
, "Output: %u, Code: %s",
593 ptnum
, val_to_str_const(tripclose
, lg8979_sbo_tripclose_vals
, "Unknown Control Code"));
595 /* Add SBO Select Details to tree */
596 proto_tree_add_item(lg8979_point_tree
, hf_lg8979_start_ptnum8
, tvb
, offset
, 1, ENC_LITTLE_ENDIAN
);
597 proto_tree_add_item(lg8979_point_tree
, hf_lg8979_sbo_tripclose
, tvb
, offset
+1, 1, ENC_LITTLE_ENDIAN
);
598 proto_tree_add_item(lg8979_point_tree
, hf_lg8979_sbo_timercnt
, tvb
, offset
+1, 1, ENC_LITTLE_ENDIAN
);
602 /* Function Code 22 SBO Operate */
603 case LG8979_FC_SBO_OPERATE
:
605 /* Get 8-bit point number */
606 ptnum
= tvb_get_uint8(tvb
, offset
);
608 /* Update the Information Column with Command Details */
609 col_append_sep_fstr(pinfo
->cinfo
, COL_INFO
, NULL
, "Output: %u", ptnum
);
611 /* Add 8-bit point number to tree */
612 proto_tree_add_item(lg8979_tree
, hf_lg8979_start_ptnum8
, tvb
, offset
, 1, ENC_LITTLE_ENDIAN
);
616 /* Function Code 23 Digital Output */
617 case LG8979_FC_DIG_OUTPUT
:
619 /* Add Digital Output Details to tree */
620 proto_tree_add_item(lg8979_tree
, hf_lg8979_start_ptnum8
, tvb
, offset
, 1, ENC_LITTLE_ENDIAN
);
621 proto_tree_add_item(lg8979_tree
, hf_lg8979_digout_data
, tvb
, offset
+1, 3, ENC_LITTLE_ENDIAN
);
625 /* Function Code 25 Pulse Output */
626 case LG8979_FC_PUL_OUTPUT
:
628 ptnum
= tvb_get_uint8(tvb
, offset
);
629 rl
= (tvb_get_uint8(tvb
, offset
+1) & 0x80) >> 7;
631 lg8979_point_tree
= proto_tree_add_subtree_format(lg8979_tree
, tvb
, offset
, 2,
632 ett_lg8979_point
, NULL
, "Pulse Output, Pt.Num: %u, Code: %s",
633 ptnum
, val_to_str_const(rl
, lg8979_pul_output_rl_vals
, "Unknown Control Code"));
635 /* Add Pulse Output Details to tree */
636 proto_tree_add_item(lg8979_point_tree
, hf_lg8979_start_ptnum8
, tvb
, offset
, 1, ENC_LITTLE_ENDIAN
);
637 proto_tree_add_item(lg8979_point_tree
, hf_lg8979_pul_output_base
, tvb
, offset
+1, 1, ENC_LITTLE_ENDIAN
);
638 proto_tree_add_item(lg8979_point_tree
, hf_lg8979_pul_output_dur
, tvb
, offset
+1, 1, ENC_LITTLE_ENDIAN
);
639 proto_tree_add_item(lg8979_point_tree
, hf_lg8979_pul_output_rl
, tvb
, offset
+1, 1, ENC_LITTLE_ENDIAN
);
643 /* Function Code 32 Time Synchronization */
644 case LG8979_FC_TIME_SYNC
:
646 /* Add 7-byte time-sync value to tree */
647 ts_mon
= tvb_get_uint8(tvb
, offset
);
648 ts_day
= tvb_get_uint8(tvb
, offset
+1);
649 ts_hr
= tvb_get_uint8(tvb
, offset
+2);
650 ts_min
= tvb_get_uint8(tvb
, offset
+3);
651 ts_sec
= tvb_get_uint8(tvb
, offset
+4);
652 ts_ms
= tvb_get_letohs(tvb
, offset
+5);
654 lg8979_ts_tree
= proto_tree_add_subtree_format(lg8979_tree
, tvb
, offset
, 7, ett_lg8979_ts
, NULL
,
655 "Time-Sync Value: %02d/%02d %02d:%02d:%02d.%03d",
656 ts_mon
, ts_day
, ts_hr
, ts_min
, ts_sec
, ts_ms
);
658 proto_tree_add_item(lg8979_ts_tree
, hf_lg8979_timesync_mon
, tvb
, offset
, 1, ENC_LITTLE_ENDIAN
);
659 proto_tree_add_item(lg8979_ts_tree
, hf_lg8979_timesync_day
, tvb
, offset
+1, 1, ENC_LITTLE_ENDIAN
);
660 proto_tree_add_item(lg8979_ts_tree
, hf_lg8979_timesync_hour
, tvb
, offset
+2, 1, ENC_LITTLE_ENDIAN
);
661 proto_tree_add_item(lg8979_ts_tree
, hf_lg8979_timesync_min
, tvb
, offset
+3, 1, ENC_LITTLE_ENDIAN
);
662 proto_tree_add_item(lg8979_ts_tree
, hf_lg8979_timesync_sec
, tvb
, offset
+4, 1, ENC_LITTLE_ENDIAN
);
663 proto_tree_add_item(lg8979_ts_tree
, hf_lg8979_timesync_msec
, tvb
, offset
+5, 2, ENC_LITTLE_ENDIAN
);
667 /* Function Code 33 Time Bias */
668 case LG8979_FC_TIME_BIAS
:
669 proto_tree_add_item(lg8979_tree
, hf_lg8979_timebias_value
, tvb
, offset
, 2, ENC_LITTLE_ENDIAN
);
673 /* Function Code 34 Analog Deadband Write */
674 case LG8979_FC_ANG_DEADBAND
:
676 /* Get analog point number base and add to tree */
677 ptnum
= tvb_get_letohs(tvb
, offset
);
678 proto_tree_add_item(lg8979_tree
, hf_lg8979_start_ptnum16
, tvb
, offset
, 2, ENC_LITTLE_ENDIAN
);
681 num_points
= (data_len
-2);
683 for (cnt
=0; cnt
<num_points
; cnt
++) {
685 ptval
= tvb_get_uint8(tvb
, offset
);
686 proto_tree_add_uint_format(lg8979_tree
, hf_lg8979_ang_deadband
, tvb
, offset
, 1,
687 ptnum
, "Point Number %u: New Deadband: %u", ptnum
, ptval
);
694 /* Function Code 35 Analog Group Define */
695 case LG8979_FC_ANGGRP_DEFINE
:
697 proto_tree_add_item(lg8979_tree
, hf_lg8979_ang_group
, tvb
, offset
, 1, ENC_LITTLE_ENDIAN
);
698 proto_tree_add_item(lg8979_tree
, hf_lg8979_start_ptnum16
, tvb
, offset
+1, 2, ENC_LITTLE_ENDIAN
);
701 num_points
= (data_len
-3);
703 for (cnt
=0; cnt
<num_points
; cnt
++) {
704 lg8979_ang_group_pts_item
= proto_tree_add_item(lg8979_tree
, hf_lg8979_ang_group_pts
, tvb
, offset
, 1, ENC_LITTLE_ENDIAN
);
705 proto_item_append_text(lg8979_ang_group_pts_item
, " (%d - %d), ", (cnt
*8), ((cnt
*8)+7));
711 /* Function Code 36 Accumulator Preset */
712 case LG8979_FC_ACC_PRESET
:
714 /* Each qty to follow has a 8-bit point number followed by a 16-bit value */
715 num_points
= ((data_len
)/3);
717 for (cnt
=0; cnt
<num_points
; cnt
++) {
719 ptnum8
= tvb_get_uint8(tvb
, offset
);
720 ptval
= tvb_get_letohs(tvb
, offset
+1);
721 proto_tree_add_uint_format(lg8979_tree
, hf_lg8979_acc_preset
, tvb
, offset
, 3,
722 ptnum8
, "Acc Point Number %u: Preset: %u", ptnum8
, ptval
);
735 proto_tree_add_item(lg8979_tree
, hf_lg8979_crc16
, tvb
, offset
, 2, ENC_BIG_ENDIAN
);
738 /* This packet type is classified as a "Response" and is deemed in the direction of "RTU -> master" */
739 else if (packet_type
== LG8979_DIR_RTU_TO_MASTER
) {
741 static int * const response_flags
[] = {
751 col_set_str(pinfo
->cinfo
, COL_INFO
, "RTU -> Master");
753 /* Retrieve and add Flags to Protocol Tree */
754 shr
= tvb_get_uint8(tvb
, offset
) & 0x80;
756 proto_tree_add_bitmask(lg8979_tree
, tvb
, offset
, hf_lg8979_flags
, ett_lg8979_flags
, response_flags
, ENC_LITTLE_ENDIAN
);
759 /* Add RTU Address to Protocol Tree */
760 rtu_addr
= tvb_get_uint8(tvb
, offset
);
761 col_append_sep_fstr(pinfo
->cinfo
, COL_INFO
, NULL
, "Address: %d", rtu_addr
);
763 proto_tree_add_item(lg8979_tree
, hf_lg8979_address
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
766 /* If this is not a short response, and there are at least 2 bytes remaining continue to process function codes */
767 while ((!shr
) && (tvb_reported_length_remaining(tvb
, offset
) > 2)){
769 /* Add Function Code & last Mark Block to Protocol Tree */
770 /* Function code is 7 lower bits of byte , LMB is 8th bit*/
771 func
= tvb_get_uint8(tvb
, offset
) & 0x7f;
772 col_append_sep_str(pinfo
->cinfo
, COL_INFO
, NULL
,
773 val_to_str_const(func
, lg8979_funccode_vals
, "Unknown Function Code"));
775 lg8979_fc_tree
= proto_tree_add_subtree_format(
776 lg8979_tree
, tvb
, offset
, 1, ett_lg8979_funccode
, NULL
,
777 "Function Code: %s (%d)", val_to_str_const(func
, lg8979_funccode_vals
, "Unknown Function Code"), func
);
779 proto_tree_add_item(lg8979_fc_tree
, hf_lg8979_lastblock
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
780 proto_tree_add_item(lg8979_fc_tree
, hf_lg8979_funccode
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
783 data_len
= tvb_get_uint8(tvb
, offset
);
784 proto_tree_add_item(lg8979_tree
, hf_lg8979_length
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
788 /* Function Code 0 Analog Change Report */
789 /* Function Code 2 Analog Group Change Report */
790 case LG8979_FC_ANG_CHGRPT
:
791 case LG8979_FC_ANGGRP_CHGRPT
:
793 num_points
= (data_len
/ 3);
795 for (cnt
=0; cnt
<num_points
; cnt
++) {
797 ptnum
= ( tvb_get_uint8(tvb
, offset
) | ((tvb_get_uint8(tvb
, offset
+1) & 0x0F) << 8) );
798 ptval
= ( ((tvb_get_uint8(tvb
, offset
+1) & 0xF0) >> 4) | (tvb_get_uint8(tvb
, offset
+2) << 4) );
799 proto_tree_add_uint_format(lg8979_tree
, hf_lg8979_ang_point
, tvb
, offset
, 3, ptnum
,
800 "Point Number %u: %u", ptnum
, ptval
);
805 /* Function Code 1 Analog Force Report */
806 case LG8979_FC_ANG_FRCRPT
:
808 ptnum
= tvb_get_letohs(tvb
, offset
);
809 proto_tree_add_item(lg8979_tree
, hf_lg8979_start_ptnum16
, tvb
, offset
, 2, ENC_LITTLE_ENDIAN
);
812 /* Decode 12-bit analog data following this 3-byte bit pattern.
813 * Byte 1: PtVal 'N' LSB
814 * Byte 2: PtVal 'N+1' LSB : PtVal 'N' MSB
815 * Byte 3: PtVal 'N+1' MSB
816 * To determine the number of points based on the data bytes, we need to know
817 * if we have an even or odd number of data bytes.
820 /* even number of data bytes */
821 if (((data_len
-2) % 3) == 0) {
822 num_points
= (((data_len
-2) / 3) * 2);
824 /* odd number of data bytes */
826 num_points
= ((((data_len
-2) / 3) * 2) + 1);
829 /* loop through the data bytes decoding 12-bit analogs.
830 When on an even count, offset by 1 and on an odd, offset by 2. */
831 for (cnt
=0; cnt
< num_points
; cnt
++) {
834 ana12_val
= ( tvb_get_uint8(tvb
, offset
) | ((tvb_get_uint8(tvb
, offset
+1) & 0x0F) << 8) );
835 proto_tree_add_uint_format(lg8979_tree
, hf_lg8979_ang_point
, tvb
, offset
, 2, ptnum
,
836 "Point Number %u: %u", ptnum
, ana12_val
);
839 /* If we are in the last run through the for loop, increment the offset by 1 more byte than normal */
840 if (cnt
== (num_points
- 1)) {
846 ana12_val
= ( ((tvb_get_uint8(tvb
, offset
) & 0xF0) >> 4) | (tvb_get_uint8(tvb
, offset
+1) << 4) );
847 proto_tree_add_uint_format(lg8979_tree
, hf_lg8979_ang_point
, tvb
, offset
, 2, ptnum
,
848 "Point Number %u: %u", ptnum
, ana12_val
);
856 /* Function Code 5 ADC Reference Force Report */
857 /* Same byte pattern as 3 sequential analogs in a Force Report would follow */
858 case LG8979_FC_ADC_FRCRPT
:
860 proto_tree_add_item(lg8979_tree
, hf_lg8979_start_ptnum16
, tvb
, offset
, 2, ENC_LITTLE_ENDIAN
);
863 /* Retrieve the 0 and -90% references */
864 ana12_val
= ( tvb_get_uint8(tvb
, offset
) | ((tvb_get_uint8(tvb
, offset
+1) & 0x0F) << 8) );
865 proto_tree_add_uint(lg8979_tree
, hf_lg8979_adc_ref_zero
, tvb
, offset
, 2, ana12_val
);
867 ana12_val
= ( ((tvb_get_uint8(tvb
, offset
+1) & 0xF0) >> 4) | (tvb_get_uint8(tvb
, offset
+2) << 4) );
868 proto_tree_add_uint(lg8979_tree
, hf_lg8979_adc_ref_neg90
, tvb
, offset
+1, 2, ana12_val
);
872 /* Retrieve the +90% reference */
873 ana12_val
= ( tvb_get_uint8(tvb
, offset
) | ((tvb_get_uint8(tvb
, offset
+1) & 0x0F) << 8) );
874 proto_tree_add_uint(lg8979_tree
, hf_lg8979_adc_ref_pos90
, tvb
, offset
, 2, ana12_val
);
879 /* Function Code 6 Indication Change Report */
880 case LG8979_FC_IND_CHGRPT
:
882 num_points
= (data_len
/ 2);
884 for (cnt
=0; cnt
<num_points
; cnt
++) {
885 /* Get 12-bit point number and new status / change bits */
886 ptnum
= tvb_get_letohs(tvb
, offset
) & 0xFFF;
887 new_status
= (tvb_get_uint8(tvb
, offset
+1) & 0x80) >> 7;
888 change
= (tvb_get_uint8(tvb
, offset
+1) & 0x40) >> 6;
890 lg8979_point_tree
= proto_tree_add_subtree_format(lg8979_tree
, tvb
, offset
, 2, ett_lg8979_point
, NULL
,
891 "Indication Change Report, Point Number: %u, Status: %u, Change %u", ptnum
, new_status
, change
);
893 proto_tree_add_item(lg8979_point_tree
, hf_lg8979_ind_chgrpt_ptnum
, tvb
, offset
, 2, ENC_LITTLE_ENDIAN
);
894 proto_tree_add_item(lg8979_point_tree
, hf_lg8979_ind_chgrpt_status
, tvb
, offset
, 2, ENC_LITTLE_ENDIAN
);
895 proto_tree_add_item(lg8979_point_tree
, hf_lg8979_ind_chgrpt_change
, tvb
, offset
, 2, ENC_LITTLE_ENDIAN
);
902 /* Function Code 7 Indication Force Report */
903 case LG8979_FC_IND_FRCRPT
:
905 ptnum
= tvb_get_letohs(tvb
, offset
);
906 proto_tree_add_item(lg8979_tree
, hf_lg8979_start_ptnum16
, tvb
, offset
, 2, ENC_LITTLE_ENDIAN
);
909 num_points
= ((data_len
- 2) / 2);
911 for (cnt
=0; cnt
<num_points
; cnt
++) {
912 lg8979_point_tree
= proto_tree_add_subtree_format(lg8979_tree
, tvb
, offset
, 1,
913 ett_lg8979_point
, NULL
, "Indication Status, Base Point Num %d", ptnum
);
915 proto_tree_add_item(lg8979_point_tree
, hf_lg8979_ind_frcrpt_status_b0
, tvb
, offset
, 1, ENC_LITTLE_ENDIAN
);
916 proto_tree_add_item(lg8979_point_tree
, hf_lg8979_ind_frcrpt_status_b1
, tvb
, offset
, 1, ENC_LITTLE_ENDIAN
);
917 proto_tree_add_item(lg8979_point_tree
, hf_lg8979_ind_frcrpt_status_b2
, tvb
, offset
, 1, ENC_LITTLE_ENDIAN
);
918 proto_tree_add_item(lg8979_point_tree
, hf_lg8979_ind_frcrpt_status_b3
, tvb
, offset
, 1, ENC_LITTLE_ENDIAN
);
919 proto_tree_add_item(lg8979_point_tree
, hf_lg8979_ind_frcrpt_status_b4
, tvb
, offset
, 1, ENC_LITTLE_ENDIAN
);
920 proto_tree_add_item(lg8979_point_tree
, hf_lg8979_ind_frcrpt_status_b5
, tvb
, offset
, 1, ENC_LITTLE_ENDIAN
);
921 proto_tree_add_item(lg8979_point_tree
, hf_lg8979_ind_frcrpt_status_b6
, tvb
, offset
, 1, ENC_LITTLE_ENDIAN
);
922 proto_tree_add_item(lg8979_point_tree
, hf_lg8979_ind_frcrpt_status_b7
, tvb
, offset
, 1, ENC_LITTLE_ENDIAN
);
925 lg8979_point_tree
= proto_tree_add_subtree_format(lg8979_tree
, tvb
, offset
, 1,
926 ett_lg8979_point
, NULL
, "Indication Change, Base Point Num %d", ptnum
);
928 proto_tree_add_item(lg8979_point_tree
, hf_lg8979_ind_frcrpt_change_b0
, tvb
, offset
, 1, ENC_LITTLE_ENDIAN
);
929 proto_tree_add_item(lg8979_point_tree
, hf_lg8979_ind_frcrpt_change_b1
, tvb
, offset
, 1, ENC_LITTLE_ENDIAN
);
930 proto_tree_add_item(lg8979_point_tree
, hf_lg8979_ind_frcrpt_change_b2
, tvb
, offset
, 1, ENC_LITTLE_ENDIAN
);
931 proto_tree_add_item(lg8979_point_tree
, hf_lg8979_ind_frcrpt_change_b3
, tvb
, offset
, 1, ENC_LITTLE_ENDIAN
);
932 proto_tree_add_item(lg8979_point_tree
, hf_lg8979_ind_frcrpt_change_b4
, tvb
, offset
, 1, ENC_LITTLE_ENDIAN
);
933 proto_tree_add_item(lg8979_point_tree
, hf_lg8979_ind_frcrpt_change_b5
, tvb
, offset
, 1, ENC_LITTLE_ENDIAN
);
934 proto_tree_add_item(lg8979_point_tree
, hf_lg8979_ind_frcrpt_change_b6
, tvb
, offset
, 1, ENC_LITTLE_ENDIAN
);
935 proto_tree_add_item(lg8979_point_tree
, hf_lg8979_ind_frcrpt_change_b7
, tvb
, offset
, 1, ENC_LITTLE_ENDIAN
);
943 /* Function Code 8 SOE Change Report */
944 case LG8979_FC_SOE_CHGRPT
:
946 num_points
= (data_len
/ 2);
948 for (cnt
=0; cnt
<num_points
; cnt
++) {
949 /* Get 12-bit point number and new status / change bits */
950 ptnum
= tvb_get_letohs(tvb
, offset
) & 0xFFF;
951 new_status
= (tvb_get_uint8(tvb
, offset
+1) & 0x80) >> 7;
952 change
= (tvb_get_uint8(tvb
, offset
+1) & 0x40) >> 6;
954 lg8979_point_tree
= proto_tree_add_subtree_format(lg8979_tree
, tvb
, offset
, 2, ett_lg8979_point
, NULL
,
955 "SOE Change Report, Point Number: %u, Status: %u, Change %u", ptnum
, new_status
, change
);
957 proto_tree_add_item(lg8979_point_tree
, hf_lg8979_soe_chgrpt_ptnum
, tvb
, offset
, 2, ENC_LITTLE_ENDIAN
);
958 proto_tree_add_item(lg8979_point_tree
, hf_lg8979_soe_chgrpt_status
, tvb
, offset
, 2, ENC_LITTLE_ENDIAN
);
959 proto_tree_add_item(lg8979_point_tree
, hf_lg8979_soe_chgrpt_change
, tvb
, offset
, 2, ENC_LITTLE_ENDIAN
);
966 /* Function Code 9 SOE Force Report */
967 case LG8979_FC_SOE_FRCRPT
:
969 ptnum
= tvb_get_letohs(tvb
, offset
);
970 proto_tree_add_item(lg8979_tree
, hf_lg8979_start_ptnum16
, tvb
, offset
, 2, ENC_LITTLE_ENDIAN
);
973 num_points
= ((data_len
- 2) / 2);
975 for (cnt
=0; cnt
<num_points
; cnt
++) {
976 lg8979_point_tree
= proto_tree_add_subtree_format(lg8979_tree
, tvb
, offset
, 1,
977 ett_lg8979_point
, NULL
, "SOE Status, Base Point Num %d", ptnum
);
979 proto_tree_add_item(lg8979_point_tree
, hf_lg8979_soe_frcrpt_status_b0
, tvb
, offset
, 1, ENC_LITTLE_ENDIAN
);
980 proto_tree_add_item(lg8979_point_tree
, hf_lg8979_soe_frcrpt_status_b1
, tvb
, offset
, 1, ENC_LITTLE_ENDIAN
);
981 proto_tree_add_item(lg8979_point_tree
, hf_lg8979_soe_frcrpt_status_b2
, tvb
, offset
, 1, ENC_LITTLE_ENDIAN
);
982 proto_tree_add_item(lg8979_point_tree
, hf_lg8979_soe_frcrpt_status_b3
, tvb
, offset
, 1, ENC_LITTLE_ENDIAN
);
983 proto_tree_add_item(lg8979_point_tree
, hf_lg8979_soe_frcrpt_status_b4
, tvb
, offset
, 1, ENC_LITTLE_ENDIAN
);
984 proto_tree_add_item(lg8979_point_tree
, hf_lg8979_soe_frcrpt_status_b5
, tvb
, offset
, 1, ENC_LITTLE_ENDIAN
);
985 proto_tree_add_item(lg8979_point_tree
, hf_lg8979_soe_frcrpt_status_b6
, tvb
, offset
, 1, ENC_LITTLE_ENDIAN
);
986 proto_tree_add_item(lg8979_point_tree
, hf_lg8979_soe_frcrpt_status_b7
, tvb
, offset
, 1, ENC_LITTLE_ENDIAN
);
989 lg8979_point_tree
= proto_tree_add_subtree_format(lg8979_tree
, tvb
, offset
, 1,
990 ett_lg8979_point
, NULL
, "SOE Change, Base Point Num %d", ptnum
);
992 proto_tree_add_item(lg8979_point_tree
, hf_lg8979_soe_frcrpt_change_b0
, tvb
, offset
, 1, ENC_LITTLE_ENDIAN
);
993 proto_tree_add_item(lg8979_point_tree
, hf_lg8979_soe_frcrpt_change_b1
, tvb
, offset
, 1, ENC_LITTLE_ENDIAN
);
994 proto_tree_add_item(lg8979_point_tree
, hf_lg8979_soe_frcrpt_change_b2
, tvb
, offset
, 1, ENC_LITTLE_ENDIAN
);
995 proto_tree_add_item(lg8979_point_tree
, hf_lg8979_soe_frcrpt_change_b3
, tvb
, offset
, 1, ENC_LITTLE_ENDIAN
);
996 proto_tree_add_item(lg8979_point_tree
, hf_lg8979_soe_frcrpt_change_b4
, tvb
, offset
, 1, ENC_LITTLE_ENDIAN
);
997 proto_tree_add_item(lg8979_point_tree
, hf_lg8979_soe_frcrpt_change_b5
, tvb
, offset
, 1, ENC_LITTLE_ENDIAN
);
998 proto_tree_add_item(lg8979_point_tree
, hf_lg8979_soe_frcrpt_change_b6
, tvb
, offset
, 1, ENC_LITTLE_ENDIAN
);
999 proto_tree_add_item(lg8979_point_tree
, hf_lg8979_soe_frcrpt_change_b7
, tvb
, offset
, 1, ENC_LITTLE_ENDIAN
);
1007 /* Function Code 11 Digital Input Force Report */
1008 case LG8979_FC_DIG_FRCRPT
:
1010 ptnum8
= tvb_get_uint8(tvb
, offset
);
1011 proto_tree_add_item(lg8979_tree
, hf_lg8979_start_ptnum8
, tvb
, offset
, 1, ENC_LITTLE_ENDIAN
);
1014 /* 1 byte per start block and 2 bytes per 16-bit block to follow */
1015 num_points
= ((data_len
-1)/2);
1017 for (cnt
=0; cnt
<num_points
; cnt
++) {
1019 lg8979_point_tree
= proto_tree_add_subtree_format(lg8979_tree
, tvb
, offset
, 2,
1020 ett_lg8979_point
, NULL
, "Digital Input Block %d", ptnum8
);
1022 proto_tree_add_item(lg8979_point_tree
, hf_lg8979_digin_b0
, tvb
, offset
, 2, ENC_LITTLE_ENDIAN
);
1023 proto_tree_add_item(lg8979_point_tree
, hf_lg8979_digin_b1
, tvb
, offset
, 2, ENC_LITTLE_ENDIAN
);
1024 proto_tree_add_item(lg8979_point_tree
, hf_lg8979_digin_b2
, tvb
, offset
, 2, ENC_LITTLE_ENDIAN
);
1025 proto_tree_add_item(lg8979_point_tree
, hf_lg8979_digin_b3
, tvb
, offset
, 2, ENC_LITTLE_ENDIAN
);
1026 proto_tree_add_item(lg8979_point_tree
, hf_lg8979_digin_b4
, tvb
, offset
, 2, ENC_LITTLE_ENDIAN
);
1027 proto_tree_add_item(lg8979_point_tree
, hf_lg8979_digin_b5
, tvb
, offset
, 2, ENC_LITTLE_ENDIAN
);
1028 proto_tree_add_item(lg8979_point_tree
, hf_lg8979_digin_b6
, tvb
, offset
, 2, ENC_LITTLE_ENDIAN
);
1029 proto_tree_add_item(lg8979_point_tree
, hf_lg8979_digin_b7
, tvb
, offset
, 2, ENC_LITTLE_ENDIAN
);
1030 proto_tree_add_item(lg8979_point_tree
, hf_lg8979_digin_b8
, tvb
, offset
, 2, ENC_LITTLE_ENDIAN
);
1031 proto_tree_add_item(lg8979_point_tree
, hf_lg8979_digin_b9
, tvb
, offset
, 2, ENC_LITTLE_ENDIAN
);
1032 proto_tree_add_item(lg8979_point_tree
, hf_lg8979_digin_b10
, tvb
, offset
, 2, ENC_LITTLE_ENDIAN
);
1033 proto_tree_add_item(lg8979_point_tree
, hf_lg8979_digin_b11
, tvb
, offset
, 2, ENC_LITTLE_ENDIAN
);
1034 proto_tree_add_item(lg8979_point_tree
, hf_lg8979_digin_b12
, tvb
, offset
, 2, ENC_LITTLE_ENDIAN
);
1035 proto_tree_add_item(lg8979_point_tree
, hf_lg8979_digin_b13
, tvb
, offset
, 2, ENC_LITTLE_ENDIAN
);
1036 proto_tree_add_item(lg8979_point_tree
, hf_lg8979_digin_b14
, tvb
, offset
, 2, ENC_LITTLE_ENDIAN
);
1037 proto_tree_add_item(lg8979_point_tree
, hf_lg8979_digin_b15
, tvb
, offset
, 2, ENC_LITTLE_ENDIAN
);
1046 /* Function Code 12 Accumulator Change Report */
1047 /* Function Code 13 Accumulator Force Report */
1048 case LG8979_FC_ACC_CHGRPT
:
1049 case LG8979_FC_ACC_FRCRPT
:
1051 ptnum8
= tvb_get_uint8(tvb
, offset
);
1052 proto_tree_add_item(lg8979_tree
, hf_lg8979_start_ptnum8
, tvb
, offset
, 1, ENC_LITTLE_ENDIAN
);
1055 /* 1 byte for start point number and 2 bytes for each 16-bit accumulator value */
1056 num_points
= ((data_len
-1) / 2);
1058 for (cnt
=0; cnt
<num_points
; cnt
++) {
1060 lg8979_point_item
= proto_tree_add_item(lg8979_tree
, hf_lg8979_acc_point
, tvb
, offset
, 2, ENC_LITTLE_ENDIAN
);
1061 proto_item_prepend_text(lg8979_point_item
, "Point Number %u, ", ptnum8
);
1070 /* Function Code 14 SOE Log Change Report */
1071 case LG8979_FC_SOELOG_CHGRPT
:
1073 /* 9 bytes for each SOE Record */
1074 num_points
= (data_len
/ 9);
1076 for (cnt
=0; cnt
<num_points
; cnt
++) {
1078 /* Get 12-bit point number and new status bit */
1079 ptnum
= tvb_get_letohs(tvb
, offset
) & 0xFFF;
1080 new_status
= (tvb_get_uint8(tvb
, offset
+1) & 0x80) >> 7;
1082 lg8979_point_tree
= proto_tree_add_subtree_format(lg8979_tree
, tvb
, offset
, 9, ett_lg8979_point
, NULL
,
1083 "SOE Log Change Report, Point Number: %u, New Status: %u", ptnum
, new_status
);
1085 /* Add 12-bit point number and "new status" bit to tree */
1086 proto_tree_add_item(lg8979_point_tree
, hf_lg8979_soe_logchg_ptnum
, tvb
, offset
, 2, ENC_LITTLE_ENDIAN
);
1087 proto_tree_add_item(lg8979_point_tree
, hf_lg8979_soe_logchg_newstat
, tvb
, offset
, 2, ENC_LITTLE_ENDIAN
);
1090 /* Add 7-byte time-stamp to tree */
1091 ts_mon
= tvb_get_uint8(tvb
, offset
);
1092 ts_day
= tvb_get_uint8(tvb
, offset
+1);
1093 ts_hr
= tvb_get_uint8(tvb
, offset
+2);
1094 ts_min
= tvb_get_uint8(tvb
, offset
+3);
1095 ts_sec
= tvb_get_uint8(tvb
, offset
+4);
1096 ts_ms
= tvb_get_letohs(tvb
, offset
+5);
1098 lg8979_ts_tree
= proto_tree_add_subtree_format(lg8979_point_tree
, tvb
, offset
, 7, ett_lg8979_ts
, NULL
,
1099 "SOE Time Stamp: [%02d/%02d %02d:%02d:%02d.%03d]", ts_mon
, ts_day
, ts_hr
, ts_min
, ts_sec
, ts_ms
);
1101 proto_tree_add_item(lg8979_ts_tree
, hf_lg8979_soe_logchg_mon
, tvb
, offset
, 1, ENC_LITTLE_ENDIAN
);
1102 proto_tree_add_item(lg8979_ts_tree
, hf_lg8979_soe_logchg_day
, tvb
, offset
+1, 1, ENC_LITTLE_ENDIAN
);
1103 proto_tree_add_item(lg8979_ts_tree
, hf_lg8979_soe_logchg_hour
, tvb
, offset
+2, 1, ENC_LITTLE_ENDIAN
);
1104 proto_tree_add_item(lg8979_ts_tree
, hf_lg8979_soe_logchg_min
, tvb
, offset
+3, 1, ENC_LITTLE_ENDIAN
);
1105 proto_tree_add_item(lg8979_ts_tree
, hf_lg8979_soe_logchg_sec
, tvb
, offset
+4, 1, ENC_LITTLE_ENDIAN
);
1106 proto_tree_add_item(lg8979_ts_tree
, hf_lg8979_soe_logchg_msec
, tvb
, offset
+5, 2, ENC_LITTLE_ENDIAN
);
1112 /* Function Code 21 SBO Select - Echo of Master->RTU Message */
1113 case LG8979_FC_SBO_SELECT
:
1115 /* Get 8-bit point number and trip/close command-code */
1116 ptnum
= tvb_get_uint8(tvb
, offset
);
1117 tripclose
= (tvb_get_uint8(tvb
, offset
+1) & 0x80) >> 7;
1119 lg8979_point_tree
= proto_tree_add_subtree_format(
1120 lg8979_tree
, tvb
, offset
, 2,
1121 ett_lg8979_point
, NULL
,
1122 "SBO Command, Pt.Num: %u, Code: %s",
1124 val_to_str_const(tripclose
, lg8979_sbo_tripclose_vals
, "Unknown Control Code"));
1126 /* Update the Information Column with Command Details */
1127 col_append_sep_fstr(pinfo
->cinfo
, COL_INFO
, NULL
, "Output: %u, Code: %s",
1128 ptnum
, val_to_str_const(tripclose
, lg8979_sbo_tripclose_vals
, "Unknown Control Code"));
1130 /* Add SBO Select Details to tree */
1131 proto_tree_add_item(lg8979_point_tree
, hf_lg8979_start_ptnum8
, tvb
, offset
, 1, ENC_LITTLE_ENDIAN
);
1132 proto_tree_add_item(lg8979_point_tree
, hf_lg8979_sbo_tripclose
, tvb
, offset
+1, 1, ENC_LITTLE_ENDIAN
);
1133 proto_tree_add_item(lg8979_point_tree
, hf_lg8979_sbo_timercnt
, tvb
, offset
+1, 1, ENC_LITTLE_ENDIAN
);
1137 /* Function Code 22 SBO Operate - Echo of Master->RTU Message */
1138 case LG8979_FC_SBO_OPERATE
:
1140 /* Get 8-bit point number */
1141 ptnum
= tvb_get_uint8(tvb
, offset
);
1143 /* Update the Information Column with Command Details */
1144 col_append_sep_fstr(pinfo
->cinfo
, COL_INFO
, NULL
, "Output: %u", ptnum
);
1146 /* Add 8-bit point number to tree */
1147 proto_tree_add_item(lg8979_tree
, hf_lg8979_start_ptnum8
, tvb
, offset
, 1, ENC_LITTLE_ENDIAN
);
1151 /* Function Code 31 RTU Configuration */
1152 case LG8979_FC_RTU_CONFIG
:
1154 /* Number of IO Chassis */
1155 num_chassis
= tvb_get_uint8(tvb
, offset
);
1156 proto_tree_add_item(lg8979_tree
, hf_lg8979_rtucfg_num_chassis
, tvb
, offset
, 1, ENC_LITTLE_ENDIAN
);
1159 for (cnt
=0; cnt
<num_chassis
; cnt
++) {
1160 /* Chassis Number */
1161 proto_tree_add_item(lg8979_tree
, hf_lg8979_rtucfg_chassis_num
, tvb
, offset
, 1, ENC_LITTLE_ENDIAN
);
1164 /* Card Codes For Each Slot (0-15) */
1165 for (cnt1
=0; cnt1
<16; cnt1
++) {
1166 lg8979_slot_item
= proto_tree_add_item(lg8979_tree
, hf_lg8979_rtucfg_card_slot
, tvb
, offset
, 1, ENC_LITTLE_ENDIAN
);
1167 proto_item_prepend_text(lg8979_slot_item
, "Slot %d, ", cnt1
);
1174 /* Function Code 33 Time Bias */
1175 case LG8979_FC_TIME_BIAS
:
1176 /* Add Time Bias "Processing Time" to tree */
1177 proto_tree_add_item(lg8979_tree
, hf_lg8979_timebias_proctime
, tvb
, offset
, 1, ENC_LITTLE_ENDIAN
);
1181 /* Function Code 39 Firmware Configuration */
1182 case LG8979_FC_FIRMWARE_CFG
:
1183 proto_tree_add_item(lg8979_tree
, hf_lg8979_firmware_ver
, tvb
, offset
, 2, ENC_LITTLE_ENDIAN
);
1187 /* Function Code 63 Exception Report */
1188 /* Parameter byte is context-sensitive to the Code byte used */
1189 /* For example, if the Code byte is 0x01 (Cold Start) the parameter byte is always 0 */
1190 /* If the code byte is 0x09 (Function Code), the parameter byte is the value of the disallowed function code */
1191 case LG8979_FC_EXP_RPT
:
1193 exp_code
= tvb_get_uint8(tvb
, offset
);
1195 proto_tree_add_item(lg8979_tree
, hf_lg8979_exprpt_code
, tvb
, offset
, 1, ENC_LITTLE_ENDIAN
);
1196 proto_tree_add_item(lg8979_tree
, hf_lg8979_exprpt_parm
, tvb
, offset
+1, 1, ENC_LITTLE_ENDIAN
);
1197 /* Function code lookup, if required */
1198 if (exp_code
== 14) {
1199 proto_item
*lg8979_dfc_item
;
1200 lg8979_dfc_item
= proto_tree_add_item(lg8979_tree
, hf_lg8979_disallowed_func
, tvb
, offset
+1, 1, ENC_NA
);
1201 proto_item_set_generated(lg8979_dfc_item
);
1214 col_append_sep_str(pinfo
->cinfo
, COL_INFO
, NULL
, "Short Response");
1218 proto_tree_add_item(lg8979_tree
, hf_lg8979_crc16
, tvb
, offset
, 2, ENC_BIG_ENDIAN
);
1222 return tvb_reported_length(tvb
);
1226 /******************************************************************************************************/
1227 /* Return length of L&G 8979 Protocol over TCP message (used for re-assembly) */
1228 /******************************************************************************************************/
1230 get_lg8979_len(packet_info
*pinfo _U_
, tvbuff_t
*tvb
, int offset _U_
, void *data _U_
)
1234 len
= tvb_reported_length(tvb
); /* XXX: should really be some minimum length ?? */
1239 /******************************************************************************************************/
1240 /* Dissect (and possibly Re-assemble) L&G 8979 protocol payload data */
1241 /******************************************************************************************************/
1243 dissect_lg8979_tcp(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data _U_
)
1246 int length
= tvb_reported_length(tvb
);
1248 /* Check for a L&G8979 packet. It should begin with 0xFF */
1249 if(length
< 2 || tvb_get_uint8(tvb
, 0) != 0xFF) {
1250 /* Not a L&G 8979 Protocol packet, just happened to use the same port */
1254 tcp_dissect_pdus(tvb
, pinfo
, tree
, lg8979_desegment
, 1,
1255 get_lg8979_len
, dissect_lg8979
, data
);
1261 /******************************************************************************************************/
1262 /* Dissect "simple" L&G 8979 protocol payload (no TCP re-assembly) */
1263 /******************************************************************************************************/
1265 dissect_lg8979_simple(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data _U_
)
1267 int length
= tvb_reported_length(tvb
);
1269 /* Check for a L&G8979 packet. It should begin with 0xFF */
1270 if(length
< 2 || tvb_get_uint8(tvb
, 0) != 0xFF) {
1271 /* Not a L&G 8979 Protocol packet ... */
1275 dissect_lg8979(tvb
, pinfo
, tree
, data
);
1280 /******************************************************************************************************/
1281 /* Register the protocol with Wireshark */
1282 /******************************************************************************************************/
1283 void proto_reg_handoff_lg8979(void);
1286 proto_register_lg8979(void)
1288 /* L&G 8979 Protocol header fields */
1289 static hf_register_info lg8979_hf
[] = {
1290 { &hf_lg8979_header
,
1291 { "Header", "lg8979.header", FT_UINT8
, BASE_HEX
, NULL
, 0x0, NULL
, HFILL
}},
1293 { "Flags", "lg8979.flags", FT_UINT8
, BASE_HEX
, NULL
, 0x00, NULL
, HFILL
}},
1295 { "SHR", "lg8979.shr", FT_UINT8
, BASE_DEC
, NULL
, 0x80, "Short Response Flag", HFILL
}},
1297 { "MFC", "lg8979.mfc", FT_UINT8
, BASE_DEC
, NULL
, 0x78, "Multi Function Code", HFILL
}},
1299 { "ACK", "lg8979.ack", FT_UINT8
, BASE_DEC
, NULL
, 0x04, "Acknowledge Flag", HFILL
}},
1301 { "CON", "lg8979.con", FT_UINT8
, BASE_DEC
, NULL
, 0x40, "Continuation Flag", HFILL
}},
1303 { "FRZ", "lg8979.frz", FT_UINT8
, BASE_DEC
, NULL
, 0x20, "Accumulator Freeze Flag", HFILL
}},
1305 { "IND", "lg8979.ind", FT_UINT8
, BASE_DEC
, NULL
, 0x10, "Indication Change Flag", HFILL
}},
1307 { "SCH", "lg8979.sch", FT_UINT8
, BASE_DEC
, NULL
, 0x08, "SOE Change Flag", HFILL
}},
1309 { "SLG", "lg8979.slg", FT_UINT8
, BASE_DEC
, NULL
, 0x04, "SOE Log Flag", HFILL
}},
1310 { &hf_lg8979_address
,
1311 { "RTU Address", "lg8979.address", FT_UINT8
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
1312 { &hf_lg8979_lastblock
,
1313 { "Last Block Mark", "lg8979.lastblock", FT_UINT8
, BASE_DEC
, NULL
, 0x80, NULL
, HFILL
}},
1314 { &hf_lg8979_funccode
,
1315 { "Function Code", "lg8979.funccode", FT_UINT8
, BASE_DEC
|BASE_EXT_STRING
, &lg8979_funccode_vals_ext
, 0x7F, NULL
, HFILL
}},
1316 { &hf_lg8979_length
,
1317 { "Data Length", "lg8979.length", FT_UINT8
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
1318 { &hf_lg8979_start_ptnum16
,
1319 { "Start Point Number (16-bit)", "lg8979.start_ptnum16", FT_UINT16
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
1320 { &hf_lg8979_start_ptnum8
,
1321 { "Start Point Number (8-bit)", "lg8979.start_ptnum8", FT_UINT8
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
1322 { &hf_lg8979_stop_ptnum16
,
1323 { "Stop Point Number (16-bit)", "lg8979.stop_ptnum16", FT_UINT16
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
1324 { &hf_lg8979_stop_ptnum8
,
1325 { "Stop Point Number (8-bit)", "lg8979.stop_ptnum8", FT_UINT8
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
1326 { &hf_lg8979_ang_point
,
1327 { "Analog Point", "lg8979.ang_point", FT_UINT24
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
1328 { &hf_lg8979_adc_ref_zero
,
1329 { "ADC Reference (0%)", "lg8979.adc_ref_zero", FT_UINT16
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
1330 { &hf_lg8979_adc_ref_neg90
,
1331 { "ADC Reference (-90%)", "lg8979.adc_ref_neg90", FT_UINT16
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
1332 { &hf_lg8979_adc_ref_pos90
,
1333 { "ADC Reference (+90%)", "lg8979.adc_ref_pos90", FT_UINT16
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
1334 { &hf_lg8979_ind_chgrpt_ptnum
,
1335 { "Point Number (12-bit)", "lg8979.ind_chgrpt_ptnum", FT_UINT16
, BASE_DEC
, NULL
, 0x0FFF, NULL
, HFILL
}},
1336 { &hf_lg8979_ind_chgrpt_status
,
1337 { "Status Bit", "lg8979.ind_chgrpt_status", FT_UINT16
, BASE_DEC
, NULL
, 0x8000, NULL
, HFILL
}},
1338 { &hf_lg8979_ind_chgrpt_change
,
1339 { "Change Bit", "lg8979.ind_chgrpt_change", FT_UINT16
, BASE_DEC
, NULL
, 0x4000, NULL
, HFILL
}},
1340 { &hf_lg8979_ind_frcrpt_status_b0
,
1341 { "Status Bit 0", "lg8979.ind.frcrpt.status_b0", FT_BOOLEAN
, 8, NULL
, 0x01, NULL
, HFILL
}},
1342 { &hf_lg8979_ind_frcrpt_status_b1
,
1343 { "Status Bit 1", "lg8979.ind.frcrpt.status_b1", FT_BOOLEAN
, 8, NULL
, 0x02, NULL
, HFILL
}},
1344 { &hf_lg8979_ind_frcrpt_status_b2
,
1345 { "Status Bit 2", "lg8979.ind.frcrpt.status_b2", FT_BOOLEAN
, 8, NULL
, 0x04, NULL
, HFILL
}},
1346 { &hf_lg8979_ind_frcrpt_status_b3
,
1347 { "Status Bit 3", "lg8979.ind.frcrpt.status_b3", FT_BOOLEAN
, 8, NULL
, 0x08, NULL
, HFILL
}},
1348 { &hf_lg8979_ind_frcrpt_status_b4
,
1349 { "Status Bit 4", "lg8979.ind.frcrpt.status_b4", FT_BOOLEAN
, 8, NULL
, 0x10, NULL
, HFILL
}},
1350 { &hf_lg8979_ind_frcrpt_status_b5
,
1351 { "Status Bit 5", "lg8979.ind.frcrpt.status_b5", FT_BOOLEAN
, 8, NULL
, 0x20, NULL
, HFILL
}},
1352 { &hf_lg8979_ind_frcrpt_status_b6
,
1353 { "Status Bit 6", "lg8979.ind.frcrpt.status_b6", FT_BOOLEAN
, 8, NULL
, 0x40, NULL
, HFILL
}},
1354 { &hf_lg8979_ind_frcrpt_status_b7
,
1355 { "Status Bit 7", "lg8979.ind.frcrpt.status_b7", FT_BOOLEAN
, 8, NULL
, 0x80, NULL
, HFILL
}},
1356 { &hf_lg8979_ind_frcrpt_change_b0
,
1357 { "Change Bit 0", "lg8979.ind.frcrpt.change_b0", FT_BOOLEAN
, 8, NULL
, 0x01, NULL
, HFILL
}},
1358 { &hf_lg8979_ind_frcrpt_change_b1
,
1359 { "Change Bit 1", "lg8979.ind.frcrpt.change_b1", FT_BOOLEAN
, 8, NULL
, 0x02, NULL
, HFILL
}},
1360 { &hf_lg8979_ind_frcrpt_change_b2
,
1361 { "Change Bit 2", "lg8979.ind.frcrpt.change_b2", FT_BOOLEAN
, 8, NULL
, 0x04, NULL
, HFILL
}},
1362 { &hf_lg8979_ind_frcrpt_change_b3
,
1363 { "Change Bit 3", "lg8979.ind.frcrpt.change_b3", FT_BOOLEAN
, 8, NULL
, 0x08, NULL
, HFILL
}},
1364 { &hf_lg8979_ind_frcrpt_change_b4
,
1365 { "Change Bit 4", "lg8979.ind.frcrpt.change_b4", FT_BOOLEAN
, 8, NULL
, 0x10, NULL
, HFILL
}},
1366 { &hf_lg8979_ind_frcrpt_change_b5
,
1367 { "Change Bit 5", "lg8979.ind.frcrpt.change_b5", FT_BOOLEAN
, 8, NULL
, 0x20, NULL
, HFILL
}},
1368 { &hf_lg8979_ind_frcrpt_change_b6
,
1369 { "Change Bit 6", "lg8979.ind.frcrpt.change_b6", FT_BOOLEAN
, 8, NULL
, 0x40, NULL
, HFILL
}},
1370 { &hf_lg8979_ind_frcrpt_change_b7
,
1371 { "Change Bit 7", "lg8979.ind.frcrpt.change_b7", FT_BOOLEAN
, 8, NULL
, 0x80, NULL
, HFILL
}},
1372 { &hf_lg8979_soe_chgrpt_ptnum
,
1373 { "Point Number (12-bit)", "lg8979.soe_chgrpt_ptnum", FT_UINT16
, BASE_DEC
, NULL
, 0x0FFF, NULL
, HFILL
}},
1374 { &hf_lg8979_soe_chgrpt_status
,
1375 { "Status Bit", "lg8979.soe_chgrpt_status", FT_UINT16
, BASE_DEC
, NULL
, 0x8000, NULL
, HFILL
}},
1376 { &hf_lg8979_soe_chgrpt_change
,
1377 { "Change Bit", "lg8979.soe_chgrpt_change", FT_UINT16
, BASE_DEC
, NULL
, 0x4000, NULL
, HFILL
}},
1378 { &hf_lg8979_soe_frcrpt_status_b0
,
1379 { "Status Bit 0", "lg8979.soe.frcrpt.status_b0", FT_BOOLEAN
, 8, NULL
, 0x01, NULL
, HFILL
}},
1380 { &hf_lg8979_soe_frcrpt_status_b1
,
1381 { "Status Bit 1", "lg8979.soe.frcrpt.status_b1", FT_BOOLEAN
, 8, NULL
, 0x02, NULL
, HFILL
}},
1382 { &hf_lg8979_soe_frcrpt_status_b2
,
1383 { "Status Bit 2", "lg8979.soe.frcrpt.status_b2", FT_BOOLEAN
, 8, NULL
, 0x04, NULL
, HFILL
}},
1384 { &hf_lg8979_soe_frcrpt_status_b3
,
1385 { "Status Bit 3", "lg8979.soe.frcrpt.status_b3", FT_BOOLEAN
, 8, NULL
, 0x08, NULL
, HFILL
}},
1386 { &hf_lg8979_soe_frcrpt_status_b4
,
1387 { "Status Bit 4", "lg8979.soe.frcrpt.status_b4", FT_BOOLEAN
, 8, NULL
, 0x10, NULL
, HFILL
}},
1388 { &hf_lg8979_soe_frcrpt_status_b5
,
1389 { "Status Bit 5", "lg8979.soe.frcrpt.status_b5", FT_BOOLEAN
, 8, NULL
, 0x20, NULL
, HFILL
}},
1390 { &hf_lg8979_soe_frcrpt_status_b6
,
1391 { "Status Bit 6", "lg8979.soe.frcrpt.status_b6", FT_BOOLEAN
, 8, NULL
, 0x40, NULL
, HFILL
}},
1392 { &hf_lg8979_soe_frcrpt_status_b7
,
1393 { "Status Bit 7", "lg8979.soe.frcrpt.status_b7", FT_BOOLEAN
, 8, NULL
, 0x80, NULL
, HFILL
}},
1394 { &hf_lg8979_soe_frcrpt_change_b0
,
1395 { "Change Bit 0", "lg8979.soe.frcrpt.change_b0", FT_BOOLEAN
, 8, NULL
, 0x01, NULL
, HFILL
}},
1396 { &hf_lg8979_soe_frcrpt_change_b1
,
1397 { "Change Bit 1", "lg8979.soe.frcrpt.change_b1", FT_BOOLEAN
, 8, NULL
, 0x02, NULL
, HFILL
}},
1398 { &hf_lg8979_soe_frcrpt_change_b2
,
1399 { "Change Bit 2", "lg8979.soe.frcrpt.change_b2", FT_BOOLEAN
, 8, NULL
, 0x04, NULL
, HFILL
}},
1400 { &hf_lg8979_soe_frcrpt_change_b3
,
1401 { "Change Bit 3", "lg8979.soe.frcrpt.change_b3", FT_BOOLEAN
, 8, NULL
, 0x08, NULL
, HFILL
}},
1402 { &hf_lg8979_soe_frcrpt_change_b4
,
1403 { "Change Bit 4", "lg8979.soe.frcrpt.change_b4", FT_BOOLEAN
, 8, NULL
, 0x10, NULL
, HFILL
}},
1404 { &hf_lg8979_soe_frcrpt_change_b5
,
1405 { "Change Bit 5", "lg8979.soe.frcrpt.change_b5", FT_BOOLEAN
, 8, NULL
, 0x20, NULL
, HFILL
}},
1406 { &hf_lg8979_soe_frcrpt_change_b6
,
1407 { "Change Bit 6", "lg8979.soe.frcrpt.change_b6", FT_BOOLEAN
, 8, NULL
, 0x40, NULL
, HFILL
}},
1408 { &hf_lg8979_soe_frcrpt_change_b7
,
1409 { "Change Bit 7", "lg8979.soe.frcrpt.change_b7", FT_BOOLEAN
, 8, NULL
, 0x80, NULL
, HFILL
}},
1410 { &hf_lg8979_digin_b0
,
1411 { "Digital Input Bit 0", "lg8979.digin_b0", FT_BOOLEAN
, 16, NULL
, 0x0001, NULL
, HFILL
}},
1412 { &hf_lg8979_digin_b1
,
1413 { "Digital Input Bit 1", "lg8979.digin_b1", FT_BOOLEAN
, 16, NULL
, 0x0002, NULL
, HFILL
}},
1414 { &hf_lg8979_digin_b2
,
1415 { "Digital Input Bit 2", "lg8979.digin_b2", FT_BOOLEAN
, 16, NULL
, 0x0004, NULL
, HFILL
}},
1416 { &hf_lg8979_digin_b3
,
1417 { "Digital Input Bit 3", "lg8979.digin_b3", FT_BOOLEAN
, 16, NULL
, 0x0008, NULL
, HFILL
}},
1418 { &hf_lg8979_digin_b4
,
1419 { "Digital Input Bit 4", "lg8979.digin_b4", FT_BOOLEAN
, 16, NULL
, 0x0010, NULL
, HFILL
}},
1420 { &hf_lg8979_digin_b5
,
1421 { "Digital Input Bit 5", "lg8979.digin_b5", FT_BOOLEAN
, 16, NULL
, 0x0020, NULL
, HFILL
}},
1422 { &hf_lg8979_digin_b6
,
1423 { "Digital Input Bit 6", "lg8979.digin_b6", FT_BOOLEAN
, 16, NULL
, 0x0040, NULL
, HFILL
}},
1424 { &hf_lg8979_digin_b7
,
1425 { "Digital Input Bit 7", "lg8979.digin_b7", FT_BOOLEAN
, 16, NULL
, 0x0080, NULL
, HFILL
}},
1426 { &hf_lg8979_digin_b8
,
1427 { "Digital Input Bit 8", "lg8979.digin_b8", FT_BOOLEAN
, 16, NULL
, 0x0100, NULL
, HFILL
}},
1428 { &hf_lg8979_digin_b9
,
1429 { "Digital Input Bit 9", "lg8979.digin_b9", FT_BOOLEAN
, 16, NULL
, 0x0200, NULL
, HFILL
}},
1430 { &hf_lg8979_digin_b10
,
1431 { "Digital Input Bit 10", "lg8979.digin_b10", FT_BOOLEAN
, 16, NULL
, 0x0400, NULL
, HFILL
}},
1432 { &hf_lg8979_digin_b11
,
1433 { "Digital Input Bit 11", "lg8979.digin_b11", FT_BOOLEAN
, 16, NULL
, 0x0800, NULL
, HFILL
}},
1434 { &hf_lg8979_digin_b12
,
1435 { "Digital Input Bit 12", "lg8979.digin_b12", FT_BOOLEAN
, 16, NULL
, 0x1000, NULL
, HFILL
}},
1436 { &hf_lg8979_digin_b13
,
1437 { "Digital Input Bit 13", "lg8979.digin_b13", FT_BOOLEAN
, 16, NULL
, 0x2000, NULL
, HFILL
}},
1438 { &hf_lg8979_digin_b14
,
1439 { "Digital Input Bit 14", "lg8979.digin_b14", FT_BOOLEAN
, 16, NULL
, 0x4000, NULL
, HFILL
}},
1440 { &hf_lg8979_digin_b15
,
1441 { "Digital Input Bit 15", "lg8979.digin_b15", FT_BOOLEAN
, 16, NULL
, 0x8000, NULL
, HFILL
}},
1442 { &hf_lg8979_acc_point
,
1443 { "Value", "lg8979.acc_point", FT_UINT16
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
1444 { &hf_lg8979_soe_logchg_ptnum
,
1445 { "Point Number", "lg8979.soe_logchg_ptnum", FT_UINT16
, BASE_DEC
, NULL
, 0x0FFF, NULL
, HFILL
}},
1446 { &hf_lg8979_soe_logchg_newstat
,
1447 { "New Status", "lg8979.soe_logchg_newstat", FT_UINT16
, BASE_DEC
, NULL
, 0x8000, NULL
, HFILL
}},
1448 { &hf_lg8979_soe_logchg_mon
,
1449 { "Month", "lg8979.soe_logchg_mon", FT_UINT8
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
1450 { &hf_lg8979_soe_logchg_day
,
1451 { "Day", "lg8979.soe_logchg_day", FT_UINT8
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
1452 { &hf_lg8979_soe_logchg_hour
,
1453 { "Hours", "lg8979.soe_logchg_hour", FT_UINT8
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
1454 { &hf_lg8979_soe_logchg_min
,
1455 { "Minute", "lg8979.soe_logchg_min", FT_UINT8
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
1456 { &hf_lg8979_soe_logchg_sec
,
1457 { "Second", "lg8979.soe_logchg_sec", FT_UINT8
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
1458 { &hf_lg8979_soe_logchg_msec
,
1459 { "Milli-Second", "lg8979.soe_logchg_msec", FT_UINT16
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
1460 { &hf_lg8979_ang_output_val
,
1461 { "Point Value", "lg8979.ang_output_val", FT_UINT16
, BASE_DEC
, NULL
, 0x0FFF, NULL
, HFILL
}},
1462 { &hf_lg8979_sbo_tripclose
,
1463 { "Trip/Close Control Code", "lg8979.sbo_tripclose", FT_UINT8
, BASE_DEC
, VALS(lg8979_sbo_tripclose_vals
), 0x80, NULL
, HFILL
}},
1464 { &hf_lg8979_sbo_timercnt
,
1465 { "Timer Count", "lg8979.sbo_timercnt", FT_UINT8
, BASE_DEC
, NULL
, 0x7F, NULL
, HFILL
}},
1466 { &hf_lg8979_digout_data
,
1467 { "Data", "lg8979.digout_data", FT_UINT24
, BASE_HEX
, NULL
, 0x0, NULL
, HFILL
}},
1468 { &hf_lg8979_pul_output_base
,
1469 { "Base Time", "lg8979.pul_output_base", FT_UINT8
, BASE_HEX
, VALS(lg8979_pul_output_base_vals
), 0x03, NULL
, HFILL
}},
1470 { &hf_lg8979_pul_output_dur
,
1471 { "Duration", "lg8979.pul_output_dur", FT_UINT8
, BASE_HEX
, NULL
, 0x7C, NULL
, HFILL
}},
1472 { &hf_lg8979_pul_output_rl
,
1473 { "Raise/Lower", "lg8979.pul_output_rl", FT_UINT8
, BASE_HEX
, VALS(lg8979_pul_output_rl_vals
), 0x80, NULL
, HFILL
}},
1474 { &hf_lg8979_ang_deadband
,
1475 { "Deadband", "lg8979.ang_deadband", FT_UINT8
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
1476 { &hf_lg8979_ang_group
,
1477 { "Analog Group", "lg8979.ang_group", FT_UINT8
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
1478 { &hf_lg8979_ang_group_pts
,
1479 { "Analog Group Points Mask", "lg8979.ang_group_pts", FT_UINT8
, BASE_HEX
, NULL
, 0x0, NULL
, HFILL
}},
1480 { &hf_lg8979_acc_preset
,
1481 { "Preset Value", "lg8979.acc_preset", FT_UINT16
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
1482 { &hf_lg8979_rtucfg_num_chassis
,
1483 { "Number of I/O Chassis in RTU", "lg8979.rtucfg_num_chassis", FT_UINT8
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
1484 { &hf_lg8979_rtucfg_chassis_num
,
1485 { "Chassis Number", "lg8979.rtucfg_chassis_num", FT_UINT8
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
1486 { &hf_lg8979_rtucfg_card_slot
,
1487 { "Card Code", "lg8979.rtucfg_card_slot", FT_UINT8
, BASE_DEC
, VALS(lg8979_cardcode_vals
), 0x0, NULL
, HFILL
}},
1488 { &hf_lg8979_timesync_mon
,
1489 { "Month", "lg8979.timesync_mon", FT_UINT8
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
1490 { &hf_lg8979_timesync_day
,
1491 { "Day", "lg8979.timesync_day", FT_UINT8
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
1492 { &hf_lg8979_timesync_hour
,
1493 { "Hours", "lg8979.timesync_hour", FT_UINT8
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
1494 { &hf_lg8979_timesync_min
,
1495 { "Minute", "lg8979.timesync_min", FT_UINT8
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
1496 { &hf_lg8979_timesync_sec
,
1497 { "Second", "lg8979.timesync_sec", FT_UINT8
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
1498 { &hf_lg8979_timesync_msec
,
1499 { "Milli-Second", "lg8979.timesync_msec", FT_UINT16
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
1500 { &hf_lg8979_timebias_value
,
1501 { "Time Bias Value", "lg8979.timebias_value", FT_UINT16
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
1502 { &hf_lg8979_firmware_ver
,
1503 { "Firmware Version", "lg8979.firmware_ver", FT_UINT16
, BASE_HEX
, NULL
, 0x0, NULL
, HFILL
}},
1504 { &hf_lg8979_timebias_proctime
,
1505 { "Time Bias Processing Time (ms)", "lg8979.timebias_proctime", FT_UINT8
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
1506 { &hf_lg8979_exprpt_code
,
1507 { "Exception Report Code", "lg8979.exprpt_code", FT_UINT8
, BASE_DEC
, VALS(lg8979_exprpt_code_vals
), 0x0, NULL
, HFILL
}},
1508 { &hf_lg8979_exprpt_parm
,
1509 { "Value", "lg8979.exprpt_parm", FT_UINT8
, BASE_DEC
, VALS(lg8979_exprpt_parm_vals
), 0x0, NULL
, HFILL
}},
1510 { &hf_lg8979_disallowed_func
,
1511 { "Disallowed Function Code", "lg8979.disallowed_func", FT_UINT8
, BASE_DEC
|BASE_EXT_STRING
, &lg8979_funccode_vals_ext
, 0x0, NULL
, HFILL
}},
1513 { "CRC-16", "lg8979.crc16", FT_UINT16
, BASE_HEX
, NULL
, 0x0, NULL
, HFILL
}},
1517 /* Setup protocol subtree array */
1518 static int *ett
[] = {
1521 &ett_lg8979_funccode
,
1526 module_t
*lg8979_module
;
1528 /* Register the protocol name and description */
1529 proto_lg8979
= proto_register_protocol("Landis & Gyr Telegyr 8979", "L&G 8979", "lg8979");
1531 /* Registering protocol to be called by another dissector */
1532 register_dissector("lg8979", dissect_lg8979_simple
, proto_lg8979
);
1534 /* Required function calls to register the header fields and subtrees used */
1535 proto_register_field_array(proto_lg8979
, lg8979_hf
, array_length(lg8979_hf
));
1536 proto_register_subtree_array(ett
, array_length(ett
));
1539 /* Register required preferences for L&G 8979 register decoding */
1540 lg8979_module
= prefs_register_protocol(proto_lg8979
, NULL
);
1542 /* L&G 8979 - Desegmentmentation; defaults to true for TCP desegmentation*/
1543 prefs_register_bool_preference(lg8979_module
, "desegment",
1544 "Desegment all L&G 8979 Protocol packets spanning multiple TCP segments",
1545 "Whether the L&G 8979 dissector should desegment all messages spanning multiple TCP segments",
1549 /******************************************************************************************************/
1551 proto_reg_handoff_lg8979(void)
1553 dissector_handle_t lg8979_handle
;
1555 /* Make sure to use L&G 8979 Protocol Preferences field to determine default TCP port */
1556 lg8979_handle
= create_dissector_handle(dissect_lg8979_tcp
, proto_lg8979
);
1558 dissector_add_for_decode_as_with_preference("tcp.port", lg8979_handle
);
1559 dissector_add_for_decode_as("rtacser.data", lg8979_handle
);
1563 * Editor modelines - https://www.wireshark.org/tools/modelines.html
1568 * indent-tabs-mode: nil
1571 * vi: set shiftwidth=4 tabstop=8 expandtab:
1572 * :indentSize=4:tabSize=8:noTabs=true: