/src/wireshark/epan/dissectors/packet-lg8979.c
Line | Count | Source |
1 | | /* packet-lg8979.c |
2 | | * Routines for Landis & Gyr (Telegyr) 8979 Protocol (lg8979) Dissection |
3 | | * By Chris Bontje (cbontje[AT]gmail.com |
4 | | * Copyright 2013-2016 |
5 | | * |
6 | | ************************************************************************************************ |
7 | | * Wireshark - Network traffic analyzer |
8 | | * By Gerald Combs <gerald@wireshark.org> |
9 | | * Copyright 1998 Gerald Combs |
10 | | * |
11 | | * SPDX-License-Identifier: GPL-2.0-or-later |
12 | | */ |
13 | | |
14 | | #include "config.h" |
15 | | |
16 | | #include <epan/packet.h> |
17 | | #include "packet-tcp.h" |
18 | | #include <epan/prefs.h> |
19 | | |
20 | | void proto_register_lg8979(void); |
21 | | |
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; |
136 | | |
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; |
143 | | |
144 | | /* Globals for L&G 8979 Protocol Preferences */ |
145 | | static bool lg8979_desegment = true; |
146 | | |
147 | | #define LG8979_HEADER 0xFF |
148 | | |
149 | 0 | #define LG8979_DIR_INDETERMINATE 0 |
150 | 0 | #define LG8979_DIR_MASTER_TO_RTU 1 |
151 | 0 | #define LG8979_DIR_RTU_TO_MASTER 2 |
152 | | |
153 | | /* Function Codes */ |
154 | 0 | #define LG8979_FC_ANG_CHGRPT 0 |
155 | 0 | #define LG8979_FC_ANG_FRCRPT 1 |
156 | 0 | #define LG8979_FC_ANGGRP_CHGRPT 2 |
157 | 0 | #define LG8979_FC_ANGGRP_FRCRPT 3 |
158 | 0 | #define LG8979_FC_ADC_FRCRPT 5 |
159 | 0 | #define LG8979_FC_IND_CHGRPT 6 |
160 | 0 | #define LG8979_FC_IND_FRCRPT 7 |
161 | 0 | #define LG8979_FC_SOE_CHGRPT 8 |
162 | 0 | #define LG8979_FC_SOE_FRCRPT 9 |
163 | 0 | #define LG8979_FC_DIG_FRCRPT 11 |
164 | 0 | #define LG8979_FC_ACC_CHGRPT 12 |
165 | 0 | #define LG8979_FC_ACC_FRCRPT 13 |
166 | 0 | #define LG8979_FC_SOELOG_CHGRPT 14 |
167 | 0 | #define LG8979_FC_ANG_OUTPUT 20 |
168 | 0 | #define LG8979_FC_SBO_SELECT 21 |
169 | 0 | #define LG8979_FC_SBO_OPERATE 22 |
170 | 0 | #define LG8979_FC_DIG_OUTPUT 23 |
171 | 0 | #define LG8979_FC_ACC_FREEZE 24 |
172 | 0 | #define LG8979_FC_PUL_OUTPUT 25 |
173 | 0 | #define LG8979_FC_PULTR_OUTPUT 26 |
174 | 0 | #define LG8979_FC_SBO_IMEXECUTE 28 |
175 | | #define LG8979_FC_RTU_RESTART 30 |
176 | 0 | #define LG8979_FC_RTU_CONFIG 31 |
177 | 0 | #define LG8979_FC_TIME_SYNC 32 |
178 | 0 | #define LG8979_FC_TIME_BIAS 33 |
179 | 0 | #define LG8979_FC_ANG_DEADBAND 34 |
180 | 0 | #define LG8979_FC_ANGGRP_DEFINE 35 |
181 | 0 | #define LG8979_FC_ACC_PRESET 36 |
182 | 0 | #define LG8979_FC_CONT_REQUEST 37 |
183 | 0 | #define LG8979_FC_REPEAT_MSG 38 |
184 | 0 | #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 | 0 | #define LG8979_FC_EXP_RPT 63 |
190 | | |
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" }, |
256 | | { 0, NULL } |
257 | | }; |
258 | | static value_string_ext lg8979_funccode_vals_ext = VALUE_STRING_EXT_INIT(lg8979_funccode_vals); |
259 | | |
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" }, |
272 | | { 28, "SOE Input" }, |
273 | | { 29, "KWH Input" }, |
274 | | { 30, "Serial Data Collector" }, |
275 | | { 31, "Empty Slot" }, |
276 | | { 0, NULL } |
277 | | }; |
278 | | |
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" }, |
298 | | { 0, NULL } |
299 | | }; |
300 | | |
301 | | static const value_string lg8979_exprpt_parm_vals[] = { |
302 | | { 0x00, "N/A" }, |
303 | | { 0x01, "1=Requested CLDSTRT" }, |
304 | | { 0x02, "N/A" }, |
305 | | { 0x03, "Unit" }, |
306 | | { 0x04, "Unit/Slot" }, |
307 | | { 0x05, "Unit/Slot" }, |
308 | | { 0x06, "Unit/Slot" }, |
309 | | { 0x07, "Unit/Slot" }, |
310 | | { 0x08, "N/A" }, |
311 | | { 0x09, "Function Code" }, |
312 | | { 0x0A, "Block Length" }, |
313 | | { 0x0B, "Point" }, |
314 | | { 0x0C, "Parameter" }, |
315 | | { 0x0D, "Execute Point" }, |
316 | | { 0x0E, "Function Code" }, |
317 | | { 0x0F, "N/A" }, |
318 | | { 0x10, "N/A" }, |
319 | | { 0x11, "1=Time Order (0=Not T/O)" }, |
320 | | { 0, NULL } |
321 | | }; |
322 | | |
323 | | static const value_string lg8979_sbo_tripclose_vals[] = { |
324 | | { 0x00, "Trip" }, |
325 | | { 0x01, "Close" }, |
326 | | { 0, NULL } |
327 | | }; |
328 | | |
329 | | static const value_string lg8979_pul_output_base_vals[] = { |
330 | | { 0x00, "10 msec" }, |
331 | | { 0x01, "100 msec" }, |
332 | | { 0x02, "1 sec" }, |
333 | | { 0x03, "10 sec" }, |
334 | | { 0, NULL } |
335 | | }; |
336 | | |
337 | | static const value_string lg8979_pul_output_rl_vals[] = { |
338 | | { 0x00, "Lower" }, |
339 | | { 0x01, "Raise" }, |
340 | | { 0, NULL } |
341 | | }; |
342 | | |
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 */ |
348 | | /* of the message */ |
349 | | /*************************************************************/ |
350 | | static int |
351 | | classify_lg8979_packet(tvbuff_t *tvb) |
352 | 0 | { |
353 | 0 | uint8_t func, len, data_len, flags; |
354 | |
|
355 | 0 | 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 */ |
358 | 0 | if (len == 5) { |
359 | 0 | return LG8979_DIR_RTU_TO_MASTER; |
360 | 0 | } |
361 | | |
362 | | /* If TVB length is greater than 5, let's dig deeper */ |
363 | 0 | if (len > 5) { |
364 | |
|
365 | 0 | flags = tvb_get_uint8(tvb, 1); |
366 | | |
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 | 0 | if ( (flags & 0x04) && (flags & 0x08) ){ |
370 | 0 | return LG8979_DIR_RTU_TO_MASTER; |
371 | 0 | } |
372 | | /* If anything is in bits 3-6 without bit 7, this is a RTU->Master message */ |
373 | 0 | else if ( (flags & 0x78) && !(flags & 0x80) ){ |
374 | 0 | return LG8979_DIR_RTU_TO_MASTER; |
375 | 0 | } |
376 | | |
377 | 0 | func = tvb_get_uint8(tvb, 3) & 0x7F; |
378 | 0 | data_len = tvb_get_uint8(tvb, 4); |
379 | | |
380 | | /* If we have more data in the tvb then should be there, this is a stacked RTU->Master response */ |
381 | 0 | if (len > (data_len + 5 + 2)) { |
382 | 0 | return LG8979_DIR_RTU_TO_MASTER; |
383 | 0 | } |
384 | | |
385 | 0 | switch (func) { |
386 | 0 | case LG8979_FC_ANG_CHGRPT: |
387 | 0 | case LG8979_FC_ADC_FRCRPT: |
388 | 0 | case LG8979_FC_IND_CHGRPT: |
389 | 0 | case LG8979_FC_SOE_CHGRPT: |
390 | 0 | case LG8979_FC_ACC_CHGRPT: |
391 | 0 | case LG8979_FC_SOELOG_CHGRPT: |
392 | 0 | case LG8979_FC_REPEAT_MSG: |
393 | 0 | case LG8979_FC_RTU_CONFIG: |
394 | 0 | case LG8979_FC_FIRMWARE_CFG: |
395 | 0 | if (data_len == 0) { |
396 | 0 | return LG8979_DIR_MASTER_TO_RTU; |
397 | 0 | } |
398 | 0 | else { |
399 | 0 | return LG8979_DIR_RTU_TO_MASTER; |
400 | 0 | } |
401 | 0 | break; |
402 | | |
403 | 0 | case LG8979_FC_ANGGRP_CHGRPT: |
404 | 0 | case LG8979_FC_ANGGRP_FRCRPT: |
405 | 0 | if (data_len == 1) { |
406 | 0 | return LG8979_DIR_MASTER_TO_RTU; |
407 | 0 | } |
408 | 0 | else { |
409 | 0 | return LG8979_DIR_RTU_TO_MASTER; |
410 | 0 | } |
411 | 0 | break; |
412 | | |
413 | | |
414 | 0 | case LG8979_FC_DIG_FRCRPT: |
415 | 0 | case LG8979_FC_ACC_FRCRPT: |
416 | 0 | case LG8979_FC_TIME_BIAS: |
417 | 0 | if (data_len == 2) { |
418 | 0 | return LG8979_DIR_MASTER_TO_RTU; |
419 | 0 | } |
420 | 0 | else { |
421 | 0 | return LG8979_DIR_RTU_TO_MASTER; |
422 | 0 | } |
423 | 0 | break; |
424 | | |
425 | 0 | case LG8979_FC_ANG_FRCRPT: |
426 | 0 | case LG8979_FC_IND_FRCRPT: |
427 | 0 | case LG8979_FC_SOE_FRCRPT: |
428 | 0 | if (data_len == 4) { |
429 | 0 | return LG8979_DIR_MASTER_TO_RTU; |
430 | 0 | } |
431 | 0 | else { |
432 | 0 | return LG8979_DIR_RTU_TO_MASTER; |
433 | 0 | } |
434 | 0 | break; |
435 | | |
436 | | /* These are either totally or mostly master->RTU operations */ |
437 | 0 | case LG8979_FC_ANG_OUTPUT: |
438 | 0 | case LG8979_FC_SBO_SELECT: |
439 | 0 | case LG8979_FC_SBO_OPERATE: |
440 | 0 | case LG8979_FC_DIG_OUTPUT: |
441 | 0 | case LG8979_FC_ACC_FREEZE: |
442 | 0 | case LG8979_FC_PUL_OUTPUT: |
443 | 0 | case LG8979_FC_PULTR_OUTPUT: |
444 | 0 | case LG8979_FC_SBO_IMEXECUTE: |
445 | 0 | case LG8979_FC_TIME_SYNC: |
446 | 0 | case LG8979_FC_ANG_DEADBAND: |
447 | 0 | case LG8979_FC_ANGGRP_DEFINE: |
448 | 0 | case LG8979_FC_ACC_PRESET: |
449 | 0 | case LG8979_FC_CONT_REQUEST: |
450 | |
|
451 | 0 | return LG8979_DIR_MASTER_TO_RTU; |
452 | | |
453 | 0 | case LG8979_FC_EXP_RPT: |
454 | 0 | return LG8979_DIR_RTU_TO_MASTER; |
455 | | |
456 | 0 | default: |
457 | 0 | return LG8979_DIR_INDETERMINATE; |
458 | 0 | } |
459 | 0 | } |
460 | | |
461 | | /* else, cannot classify */ |
462 | 0 | return LG8979_DIR_INDETERMINATE; |
463 | 0 | } |
464 | | |
465 | | /******************************************************************************************************/ |
466 | | /* Code to dissect L&G 8979 Protocol packets */ |
467 | | /******************************************************************************************************/ |
468 | | static int |
469 | | dissect_lg8979(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_) |
470 | 0 | { |
471 | | /* Set up structures needed to add the protocol subtree and manage it */ |
472 | 0 | proto_item *lg8979_item, *lg8979_point_item = NULL; |
473 | 0 | proto_item *lg8979_slot_item = NULL, *lg8979_ang_group_pts_item = NULL; |
474 | 0 | proto_tree *lg8979_tree, *lg8979_fc_tree = NULL; |
475 | 0 | proto_tree *lg8979_point_tree = NULL, *lg8979_ts_tree = NULL; |
476 | 0 | int offset = 0; |
477 | 0 | uint8_t rtu_addr, func, packet_type, data_len, ptnum8, tripclose, rl, exp_code, num_chassis; |
478 | 0 | uint8_t ts_mon, ts_day, ts_hr, ts_min, ts_sec; |
479 | 0 | uint16_t ptnum, ptval, ana12_val; |
480 | 0 | uint16_t ts_ms; |
481 | 0 | int num_points = 0, cnt = 0, cnt1 = 0; |
482 | 0 | bool shr, new_status, change; |
483 | | |
484 | | /* Make entries in Protocol column on summary display */ |
485 | 0 | col_set_str(pinfo->cinfo, COL_PROTOCOL, "L&G 8979"); |
486 | 0 | col_clear(pinfo->cinfo, COL_INFO); |
487 | |
|
488 | 0 | lg8979_item = proto_tree_add_item(tree, proto_lg8979, tvb, 0, -1, ENC_NA); |
489 | 0 | lg8979_tree = proto_item_add_subtree(lg8979_item, ett_lg8979); |
490 | | |
491 | | /* Add 0xFF Header to Protocol Tree */ |
492 | 0 | proto_tree_add_item(lg8979_tree, hf_lg8979_header, tvb, offset, 1, ENC_LITTLE_ENDIAN); |
493 | 0 | offset += 1; |
494 | | |
495 | | /* "Request" or "Response" */ |
496 | 0 | packet_type = classify_lg8979_packet(tvb); |
497 | | |
498 | | /* This packet type is classified as a "Request" and is deemed in the direction of "master -> RTU" */ |
499 | 0 | if (packet_type == LG8979_DIR_MASTER_TO_RTU) { |
500 | 0 | static int * const request_flags[] = { |
501 | 0 | &hf_lg8979_shr, |
502 | 0 | &hf_lg8979_mfc, |
503 | 0 | &hf_lg8979_ack, |
504 | 0 | NULL |
505 | 0 | }; |
506 | |
|
507 | 0 | col_set_str(pinfo->cinfo, COL_INFO, "Master -> RTU"); |
508 | | |
509 | | /* Add Flags to Protocol Tree */ |
510 | 0 | shr = tvb_get_uint8(tvb, offset) & 0x80; |
511 | |
|
512 | 0 | proto_tree_add_bitmask(lg8979_tree, tvb, offset, hf_lg8979_flags, ett_lg8979_flags, request_flags, ENC_LITTLE_ENDIAN); |
513 | 0 | offset += 1; |
514 | | |
515 | | /* Add RTU Address to Protocol Tree */ |
516 | 0 | rtu_addr = tvb_get_uint8(tvb, offset); |
517 | 0 | col_append_sep_fstr(pinfo->cinfo, COL_INFO, NULL, "Address: %d", rtu_addr); |
518 | |
|
519 | 0 | proto_tree_add_item(lg8979_tree, hf_lg8979_address, tvb, offset, 1, ENC_LITTLE_ENDIAN); |
520 | 0 | offset += 1; |
521 | |
|
522 | 0 | if (!shr) { |
523 | | /* Add Function Code & last Mark Block to Protocol Tree */ |
524 | | /* Function code is 7 lower bits of byte , LMB is 8th bit*/ |
525 | 0 | func = tvb_get_uint8(tvb, offset) & 0x7f; |
526 | |
|
527 | 0 | col_append_sep_str(pinfo->cinfo, COL_INFO, NULL, |
528 | 0 | val_to_str_const(func, lg8979_funccode_vals, "Unknown Function Code")); |
529 | |
|
530 | 0 | lg8979_fc_tree = proto_tree_add_subtree_format( |
531 | 0 | lg8979_tree, tvb, offset, 1, ett_lg8979_funccode, NULL, |
532 | 0 | "Function Code: %s (%d)", |
533 | 0 | val_to_str_const(func, lg8979_funccode_vals, "Unknown Function Code"), func); |
534 | |
|
535 | 0 | proto_tree_add_item(lg8979_fc_tree, hf_lg8979_lastblock, tvb, offset, 1, ENC_LITTLE_ENDIAN); |
536 | 0 | proto_tree_add_item(lg8979_fc_tree, hf_lg8979_funccode, tvb, offset, 1, ENC_LITTLE_ENDIAN); |
537 | 0 | offset += 1; |
538 | |
|
539 | 0 | data_len = tvb_get_uint8(tvb, offset); |
540 | 0 | proto_tree_add_item(lg8979_tree, hf_lg8979_length, tvb, offset, 1, ENC_LITTLE_ENDIAN); |
541 | 0 | offset += 1; |
542 | |
|
543 | 0 | switch (func) { |
544 | | /* Function Code 0 Analog Change Report */ |
545 | | /* Function Code 7 Indication Force Report */ |
546 | | /* Function Code 9 SOE Force Report */ |
547 | 0 | case LG8979_FC_ANG_FRCRPT: |
548 | 0 | case LG8979_FC_IND_FRCRPT: |
549 | 0 | case LG8979_FC_SOE_FRCRPT: |
550 | 0 | proto_tree_add_item(lg8979_tree, hf_lg8979_start_ptnum16, tvb, offset, 2, ENC_LITTLE_ENDIAN); |
551 | 0 | proto_tree_add_item(lg8979_tree, hf_lg8979_stop_ptnum16, tvb, offset+2, 2, ENC_LITTLE_ENDIAN); |
552 | 0 | offset += 4; |
553 | 0 | break; |
554 | | |
555 | | /* Function Code 2 Analog Group Change Report */ |
556 | 0 | case LG8979_FC_ANGGRP_CHGRPT: |
557 | 0 | proto_tree_add_item(lg8979_tree, hf_lg8979_ang_group, tvb, offset, 1, ENC_LITTLE_ENDIAN); |
558 | 0 | offset += 1; |
559 | 0 | break; |
560 | | |
561 | | /* Function Code 11 Digital Input Force Report */ |
562 | | /* Function Code 13 Accumulator Force Report */ |
563 | 0 | case LG8979_FC_DIG_FRCRPT: |
564 | 0 | case LG8979_FC_ACC_FRCRPT: |
565 | 0 | proto_tree_add_item(lg8979_tree, hf_lg8979_start_ptnum8, tvb, offset, 1, ENC_LITTLE_ENDIAN); |
566 | 0 | proto_tree_add_item(lg8979_tree, hf_lg8979_stop_ptnum8, tvb, offset+1, 1, ENC_LITTLE_ENDIAN); |
567 | 0 | offset += 2; |
568 | 0 | break; |
569 | | |
570 | | /* Function Code 20 Analog Output */ |
571 | 0 | case LG8979_FC_ANG_OUTPUT: |
572 | 0 | proto_tree_add_item(lg8979_tree, hf_lg8979_start_ptnum8, tvb, offset, 1, ENC_LITTLE_ENDIAN); |
573 | 0 | proto_tree_add_item(lg8979_tree, hf_lg8979_ang_output_val, tvb, offset+1, 2, ENC_LITTLE_ENDIAN); |
574 | 0 | offset += 3; |
575 | 0 | break; |
576 | | |
577 | | /* Function Code 21 SBO Select */ |
578 | 0 | case LG8979_FC_SBO_SELECT: |
579 | | |
580 | | /* Get 8-bit point number and trip/close command-code */ |
581 | 0 | ptnum = tvb_get_uint8(tvb, offset); |
582 | 0 | tripclose = (tvb_get_uint8(tvb, offset+1) & 0x80) >> 7; |
583 | |
|
584 | 0 | lg8979_point_tree = proto_tree_add_subtree_format( |
585 | 0 | lg8979_tree, tvb, offset, 2, |
586 | 0 | ett_lg8979_point, NULL, |
587 | 0 | "SBO Command, Pt.Num: %u, Code: %s", |
588 | 0 | ptnum, |
589 | 0 | val_to_str_const(tripclose, lg8979_sbo_tripclose_vals, "Unknown Control Code")); |
590 | | |
591 | | /* Update the Information Column with Command Details */ |
592 | 0 | col_append_sep_fstr(pinfo->cinfo, COL_INFO, NULL, "Output: %u, Code: %s", |
593 | 0 | ptnum, val_to_str_const(tripclose, lg8979_sbo_tripclose_vals, "Unknown Control Code")); |
594 | | |
595 | | /* Add SBO Select Details to tree */ |
596 | 0 | proto_tree_add_item(lg8979_point_tree, hf_lg8979_start_ptnum8, tvb, offset, 1, ENC_LITTLE_ENDIAN); |
597 | 0 | proto_tree_add_item(lg8979_point_tree, hf_lg8979_sbo_tripclose, tvb, offset+1, 1, ENC_LITTLE_ENDIAN); |
598 | 0 | proto_tree_add_item(lg8979_point_tree, hf_lg8979_sbo_timercnt, tvb, offset+1, 1, ENC_LITTLE_ENDIAN); |
599 | 0 | offset += 2; |
600 | 0 | break; |
601 | | |
602 | | /* Function Code 22 SBO Operate */ |
603 | 0 | case LG8979_FC_SBO_OPERATE: |
604 | | |
605 | | /* Get 8-bit point number */ |
606 | 0 | ptnum = tvb_get_uint8(tvb, offset); |
607 | | |
608 | | /* Update the Information Column with Command Details */ |
609 | 0 | col_append_sep_fstr(pinfo->cinfo, COL_INFO, NULL, "Output: %u", ptnum); |
610 | | |
611 | | /* Add 8-bit point number to tree */ |
612 | 0 | proto_tree_add_item(lg8979_tree, hf_lg8979_start_ptnum8, tvb, offset, 1, ENC_LITTLE_ENDIAN); |
613 | 0 | offset += 1; |
614 | 0 | break; |
615 | | |
616 | | /* Function Code 23 Digital Output */ |
617 | 0 | case LG8979_FC_DIG_OUTPUT: |
618 | | |
619 | | /* Add Digital Output Details to tree */ |
620 | 0 | proto_tree_add_item(lg8979_tree, hf_lg8979_start_ptnum8, tvb, offset, 1, ENC_LITTLE_ENDIAN); |
621 | 0 | proto_tree_add_item(lg8979_tree, hf_lg8979_digout_data, tvb, offset+1, 3, ENC_LITTLE_ENDIAN); |
622 | 0 | offset += 4; |
623 | 0 | break; |
624 | | |
625 | | /* Function Code 25 Pulse Output */ |
626 | 0 | case LG8979_FC_PUL_OUTPUT: |
627 | |
|
628 | 0 | ptnum = tvb_get_uint8(tvb, offset); |
629 | 0 | rl = (tvb_get_uint8(tvb, offset+1) & 0x80) >> 7; |
630 | |
|
631 | 0 | lg8979_point_tree = proto_tree_add_subtree_format(lg8979_tree, tvb, offset, 2, |
632 | 0 | ett_lg8979_point, NULL, "Pulse Output, Pt.Num: %u, Code: %s", |
633 | 0 | ptnum, val_to_str_const(rl, lg8979_pul_output_rl_vals, "Unknown Control Code")); |
634 | | |
635 | | /* Add Pulse Output Details to tree */ |
636 | 0 | proto_tree_add_item(lg8979_point_tree, hf_lg8979_start_ptnum8, tvb, offset, 1, ENC_LITTLE_ENDIAN); |
637 | 0 | proto_tree_add_item(lg8979_point_tree, hf_lg8979_pul_output_base, tvb, offset+1, 1, ENC_LITTLE_ENDIAN); |
638 | 0 | proto_tree_add_item(lg8979_point_tree, hf_lg8979_pul_output_dur, tvb, offset+1, 1, ENC_LITTLE_ENDIAN); |
639 | 0 | proto_tree_add_item(lg8979_point_tree, hf_lg8979_pul_output_rl, tvb, offset+1, 1, ENC_LITTLE_ENDIAN); |
640 | 0 | offset += 2; |
641 | 0 | break; |
642 | | |
643 | | /* Function Code 32 Time Synchronization */ |
644 | 0 | case LG8979_FC_TIME_SYNC: |
645 | | |
646 | | /* Add 7-byte time-sync value to tree */ |
647 | 0 | ts_mon = tvb_get_uint8(tvb, offset); |
648 | 0 | ts_day = tvb_get_uint8(tvb, offset+1); |
649 | 0 | ts_hr = tvb_get_uint8(tvb, offset+2); |
650 | 0 | ts_min = tvb_get_uint8(tvb, offset+3); |
651 | 0 | ts_sec = tvb_get_uint8(tvb, offset+4); |
652 | 0 | ts_ms = tvb_get_letohs(tvb, offset+5); |
653 | |
|
654 | 0 | lg8979_ts_tree = proto_tree_add_subtree_format(lg8979_tree, tvb, offset, 7, ett_lg8979_ts, NULL, |
655 | 0 | "Time-Sync Value: %02d/%02d %02d:%02d:%02d.%03d", |
656 | 0 | ts_mon, ts_day, ts_hr, ts_min, ts_sec, ts_ms); |
657 | |
|
658 | 0 | proto_tree_add_item(lg8979_ts_tree, hf_lg8979_timesync_mon, tvb, offset, 1, ENC_LITTLE_ENDIAN); |
659 | 0 | proto_tree_add_item(lg8979_ts_tree, hf_lg8979_timesync_day, tvb, offset+1, 1, ENC_LITTLE_ENDIAN); |
660 | 0 | proto_tree_add_item(lg8979_ts_tree, hf_lg8979_timesync_hour, tvb, offset+2, 1, ENC_LITTLE_ENDIAN); |
661 | 0 | proto_tree_add_item(lg8979_ts_tree, hf_lg8979_timesync_min, tvb, offset+3, 1, ENC_LITTLE_ENDIAN); |
662 | 0 | proto_tree_add_item(lg8979_ts_tree, hf_lg8979_timesync_sec, tvb, offset+4, 1, ENC_LITTLE_ENDIAN); |
663 | 0 | proto_tree_add_item(lg8979_ts_tree, hf_lg8979_timesync_msec, tvb, offset+5, 2, ENC_LITTLE_ENDIAN); |
664 | 0 | offset += 7; |
665 | 0 | break; |
666 | | |
667 | | /* Function Code 33 Time Bias */ |
668 | 0 | case LG8979_FC_TIME_BIAS: |
669 | 0 | proto_tree_add_item(lg8979_tree, hf_lg8979_timebias_value, tvb, offset, 2, ENC_LITTLE_ENDIAN); |
670 | 0 | offset += 2; |
671 | 0 | break; |
672 | | |
673 | | /* Function Code 34 Analog Deadband Write */ |
674 | 0 | case LG8979_FC_ANG_DEADBAND: |
675 | | |
676 | | /* Get analog point number base and add to tree */ |
677 | 0 | ptnum = tvb_get_letohs(tvb, offset); |
678 | 0 | proto_tree_add_item(lg8979_tree, hf_lg8979_start_ptnum16, tvb, offset, 2, ENC_LITTLE_ENDIAN); |
679 | 0 | offset += 2; |
680 | |
|
681 | 0 | num_points = (data_len-2); |
682 | |
|
683 | 0 | for (cnt=0; cnt<num_points; cnt++) { |
684 | |
|
685 | 0 | ptval = tvb_get_uint8(tvb, offset); |
686 | 0 | proto_tree_add_uint_format(lg8979_tree, hf_lg8979_ang_deadband, tvb, offset, 1, |
687 | 0 | ptnum, "Point Number %u: New Deadband: %u", ptnum, ptval); |
688 | 0 | ptnum += 1; |
689 | 0 | offset += 1; |
690 | 0 | } |
691 | |
|
692 | 0 | break; |
693 | | |
694 | | /* Function Code 35 Analog Group Define */ |
695 | 0 | case LG8979_FC_ANGGRP_DEFINE: |
696 | |
|
697 | 0 | proto_tree_add_item(lg8979_tree, hf_lg8979_ang_group, tvb, offset, 1, ENC_LITTLE_ENDIAN); |
698 | 0 | proto_tree_add_item(lg8979_tree, hf_lg8979_start_ptnum16, tvb, offset+1, 2, ENC_LITTLE_ENDIAN); |
699 | 0 | offset += 3; |
700 | |
|
701 | 0 | num_points = (data_len-3); |
702 | |
|
703 | 0 | for (cnt=0; cnt<num_points; cnt++) { |
704 | 0 | lg8979_ang_group_pts_item = proto_tree_add_item(lg8979_tree, hf_lg8979_ang_group_pts, tvb, offset, 1, ENC_LITTLE_ENDIAN); |
705 | 0 | proto_item_append_text(lg8979_ang_group_pts_item, " (%d - %d), ", (cnt*8), ((cnt*8)+7)); |
706 | 0 | offset += 1; |
707 | 0 | } |
708 | |
|
709 | 0 | break; |
710 | | |
711 | | /* Function Code 36 Accumulator Preset */ |
712 | 0 | case LG8979_FC_ACC_PRESET: |
713 | | |
714 | | /* Each qty to follow has a 8-bit point number followed by a 16-bit value */ |
715 | 0 | num_points = ((data_len)/3); |
716 | |
|
717 | 0 | for (cnt=0; cnt<num_points; cnt++) { |
718 | |
|
719 | 0 | ptnum8 = tvb_get_uint8(tvb, offset); |
720 | 0 | ptval = tvb_get_letohs(tvb, offset+1); |
721 | 0 | proto_tree_add_uint_format(lg8979_tree, hf_lg8979_acc_preset, tvb, offset, 3, |
722 | 0 | ptnum8, "Acc Point Number %u: Preset: %u", ptnum8, ptval); |
723 | 0 | offset += 3; |
724 | 0 | } |
725 | |
|
726 | 0 | break; |
727 | | |
728 | 0 | default: |
729 | 0 | break; |
730 | 0 | } /* func */ |
731 | |
|
732 | 0 | } /* !shr */ |
733 | | |
734 | | /* Add CRC-16 */ |
735 | 0 | proto_tree_add_item(lg8979_tree, hf_lg8979_crc16, tvb, offset, 2, ENC_BIG_ENDIAN); |
736 | |
|
737 | 0 | } |
738 | | /* This packet type is classified as a "Response" and is deemed in the direction of "RTU -> master" */ |
739 | 0 | else if (packet_type == LG8979_DIR_RTU_TO_MASTER) { |
740 | |
|
741 | 0 | static int * const response_flags[] = { |
742 | 0 | &hf_lg8979_shr, |
743 | 0 | &hf_lg8979_con, |
744 | 0 | &hf_lg8979_frz, |
745 | 0 | &hf_lg8979_ind, |
746 | 0 | &hf_lg8979_sch, |
747 | 0 | &hf_lg8979_slg, |
748 | 0 | NULL |
749 | 0 | }; |
750 | |
|
751 | 0 | col_set_str(pinfo->cinfo, COL_INFO, "RTU -> Master"); |
752 | | |
753 | | /* Retrieve and add Flags to Protocol Tree */ |
754 | 0 | shr = tvb_get_uint8(tvb, offset) & 0x80; |
755 | |
|
756 | 0 | proto_tree_add_bitmask(lg8979_tree, tvb, offset, hf_lg8979_flags, ett_lg8979_flags, response_flags, ENC_LITTLE_ENDIAN); |
757 | 0 | offset += 1; |
758 | | |
759 | | /* Add RTU Address to Protocol Tree */ |
760 | 0 | rtu_addr = tvb_get_uint8(tvb, offset); |
761 | 0 | col_append_sep_fstr(pinfo->cinfo, COL_INFO, NULL, "Address: %d", rtu_addr); |
762 | |
|
763 | 0 | proto_tree_add_item(lg8979_tree, hf_lg8979_address, tvb, offset, 1, ENC_BIG_ENDIAN); |
764 | 0 | offset += 1; |
765 | | |
766 | | /* If this is not a short response, and there are at least 2 bytes remaining continue to process function codes */ |
767 | 0 | while ((!shr) && (tvb_reported_length_remaining(tvb, offset) > 2)){ |
768 | | |
769 | | /* Add Function Code & last Mark Block to Protocol Tree */ |
770 | | /* Function code is 7 lower bits of byte , LMB is 8th bit*/ |
771 | 0 | func = tvb_get_uint8(tvb, offset) & 0x7f; |
772 | 0 | col_append_sep_str(pinfo->cinfo, COL_INFO, NULL, |
773 | 0 | val_to_str_const(func, lg8979_funccode_vals, "Unknown Function Code")); |
774 | |
|
775 | 0 | lg8979_fc_tree = proto_tree_add_subtree_format( |
776 | 0 | lg8979_tree, tvb, offset, 1, ett_lg8979_funccode, NULL, |
777 | 0 | "Function Code: %s (%d)", val_to_str_const(func, lg8979_funccode_vals, "Unknown Function Code"), func); |
778 | |
|
779 | 0 | proto_tree_add_item(lg8979_fc_tree, hf_lg8979_lastblock, tvb, offset, 1, ENC_BIG_ENDIAN); |
780 | 0 | proto_tree_add_item(lg8979_fc_tree, hf_lg8979_funccode, tvb, offset, 1, ENC_BIG_ENDIAN); |
781 | 0 | offset += 1; |
782 | |
|
783 | 0 | data_len = tvb_get_uint8(tvb, offset); |
784 | 0 | proto_tree_add_item(lg8979_tree, hf_lg8979_length, tvb, offset, 1, ENC_BIG_ENDIAN); |
785 | 0 | offset += 1; |
786 | |
|
787 | 0 | switch (func) { |
788 | | /* Function Code 0 Analog Change Report */ |
789 | | /* Function Code 2 Analog Group Change Report */ |
790 | 0 | case LG8979_FC_ANG_CHGRPT: |
791 | 0 | case LG8979_FC_ANGGRP_CHGRPT: |
792 | |
|
793 | 0 | num_points = (data_len / 3); |
794 | |
|
795 | 0 | for (cnt=0; cnt<num_points; cnt++) { |
796 | |
|
797 | 0 | ptnum = ( tvb_get_uint8(tvb, offset) | ((tvb_get_uint8(tvb, offset+1) & 0x0F) << 8) ); |
798 | 0 | ptval = ( ((tvb_get_uint8(tvb, offset+1) & 0xF0) >> 4) | (tvb_get_uint8(tvb, offset+2) << 4) ); |
799 | 0 | proto_tree_add_uint_format(lg8979_tree, hf_lg8979_ang_point, tvb, offset, 3, ptnum, |
800 | 0 | "Point Number %u: %u", ptnum, ptval); |
801 | 0 | offset += 3; |
802 | 0 | } |
803 | 0 | break; |
804 | | |
805 | | /* Function Code 1 Analog Force Report */ |
806 | 0 | case LG8979_FC_ANG_FRCRPT: |
807 | |
|
808 | 0 | ptnum = tvb_get_letohs(tvb, offset); |
809 | 0 | proto_tree_add_item(lg8979_tree, hf_lg8979_start_ptnum16, tvb, offset, 2, ENC_LITTLE_ENDIAN); |
810 | 0 | offset += 2; |
811 | | |
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. |
818 | | */ |
819 | | |
820 | | /* even number of data bytes */ |
821 | 0 | if (((data_len-2) % 3) == 0) { |
822 | 0 | num_points = (((data_len-2) / 3) * 2); |
823 | 0 | } |
824 | | /* odd number of data bytes */ |
825 | 0 | else { |
826 | 0 | num_points = ((((data_len-2) / 3) * 2) + 1); |
827 | 0 | } |
828 | | |
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 | 0 | for (cnt=0; cnt < num_points; cnt++) { |
832 | 0 | if (cnt%2 == 0) { |
833 | |
|
834 | 0 | ana12_val = ( tvb_get_uint8(tvb, offset) | ((tvb_get_uint8(tvb, offset+1) & 0x0F) << 8) ); |
835 | 0 | proto_tree_add_uint_format(lg8979_tree, hf_lg8979_ang_point, tvb, offset, 2, ptnum, |
836 | 0 | "Point Number %u: %u", ptnum, ana12_val); |
837 | 0 | offset += 1; |
838 | | |
839 | | /* If we are in the last run through the for loop, increment the offset by 1 more byte than normal */ |
840 | 0 | if (cnt == (num_points - 1)) { |
841 | 0 | offset += 1; |
842 | 0 | } |
843 | 0 | } |
844 | 0 | else { |
845 | |
|
846 | 0 | ana12_val = ( ((tvb_get_uint8(tvb, offset) & 0xF0) >> 4) | (tvb_get_uint8(tvb, offset+1) << 4) ); |
847 | 0 | proto_tree_add_uint_format(lg8979_tree, hf_lg8979_ang_point, tvb, offset, 2, ptnum, |
848 | 0 | "Point Number %u: %u", ptnum, ana12_val); |
849 | 0 | offset += 2; |
850 | 0 | } |
851 | 0 | ptnum += 1; |
852 | 0 | } |
853 | |
|
854 | 0 | break; |
855 | | |
856 | | /* Function Code 5 ADC Reference Force Report */ |
857 | | /* Same byte pattern as 3 sequential analogs in a Force Report would follow */ |
858 | 0 | case LG8979_FC_ADC_FRCRPT: |
859 | |
|
860 | 0 | proto_tree_add_item(lg8979_tree, hf_lg8979_start_ptnum16, tvb, offset, 2, ENC_LITTLE_ENDIAN); |
861 | 0 | offset += 2; |
862 | | |
863 | | /* Retrieve the 0 and -90% references */ |
864 | 0 | ana12_val = ( tvb_get_uint8(tvb, offset) | ((tvb_get_uint8(tvb, offset+1) & 0x0F) << 8) ); |
865 | 0 | proto_tree_add_uint(lg8979_tree, hf_lg8979_adc_ref_zero, tvb, offset, 2, ana12_val); |
866 | |
|
867 | 0 | ana12_val = ( ((tvb_get_uint8(tvb, offset+1) & 0xF0) >> 4) | (tvb_get_uint8(tvb, offset+2) << 4) ); |
868 | 0 | proto_tree_add_uint(lg8979_tree, hf_lg8979_adc_ref_neg90, tvb, offset+1, 2, ana12_val); |
869 | |
|
870 | 0 | offset += 3; |
871 | | |
872 | | /* Retrieve the +90% reference */ |
873 | 0 | ana12_val = ( tvb_get_uint8(tvb, offset) | ((tvb_get_uint8(tvb, offset+1) & 0x0F) << 8) ); |
874 | 0 | proto_tree_add_uint(lg8979_tree, hf_lg8979_adc_ref_pos90, tvb, offset, 2, ana12_val); |
875 | 0 | offset += 2; |
876 | |
|
877 | 0 | break; |
878 | | |
879 | | /* Function Code 6 Indication Change Report */ |
880 | 0 | case LG8979_FC_IND_CHGRPT: |
881 | |
|
882 | 0 | num_points = (data_len / 2); |
883 | |
|
884 | 0 | for (cnt=0; cnt<num_points; cnt++) { |
885 | | /* Get 12-bit point number and new status / change bits */ |
886 | 0 | ptnum = tvb_get_letohs(tvb, offset) & 0xFFF; |
887 | 0 | new_status = (tvb_get_uint8(tvb, offset+1) & 0x80) >> 7; |
888 | 0 | change = (tvb_get_uint8(tvb, offset+1) & 0x40) >> 6; |
889 | |
|
890 | 0 | lg8979_point_tree = proto_tree_add_subtree_format(lg8979_tree, tvb, offset, 2, ett_lg8979_point, NULL, |
891 | 0 | "Indication Change Report, Point Number: %u, Status: %u, Change %u", ptnum, new_status, change); |
892 | |
|
893 | 0 | proto_tree_add_item(lg8979_point_tree, hf_lg8979_ind_chgrpt_ptnum, tvb, offset, 2, ENC_LITTLE_ENDIAN); |
894 | 0 | proto_tree_add_item(lg8979_point_tree, hf_lg8979_ind_chgrpt_status, tvb, offset, 2, ENC_LITTLE_ENDIAN); |
895 | 0 | proto_tree_add_item(lg8979_point_tree, hf_lg8979_ind_chgrpt_change, tvb, offset, 2, ENC_LITTLE_ENDIAN); |
896 | |
|
897 | 0 | offset += 2; |
898 | 0 | } |
899 | |
|
900 | 0 | break; |
901 | | |
902 | | /* Function Code 7 Indication Force Report */ |
903 | 0 | case LG8979_FC_IND_FRCRPT: |
904 | |
|
905 | 0 | ptnum = tvb_get_letohs(tvb, offset); |
906 | 0 | proto_tree_add_item(lg8979_tree, hf_lg8979_start_ptnum16, tvb, offset, 2, ENC_LITTLE_ENDIAN); |
907 | 0 | offset += 2; |
908 | |
|
909 | 0 | num_points = ((data_len - 2) / 2); |
910 | |
|
911 | 0 | for (cnt=0; cnt<num_points; cnt++) { |
912 | 0 | lg8979_point_tree = proto_tree_add_subtree_format(lg8979_tree, tvb, offset, 1, |
913 | 0 | ett_lg8979_point, NULL, "Indication Status, Base Point Num %d", ptnum); |
914 | |
|
915 | 0 | proto_tree_add_item(lg8979_point_tree, hf_lg8979_ind_frcrpt_status_b0, tvb, offset, 1, ENC_LITTLE_ENDIAN); |
916 | 0 | proto_tree_add_item(lg8979_point_tree, hf_lg8979_ind_frcrpt_status_b1, tvb, offset, 1, ENC_LITTLE_ENDIAN); |
917 | 0 | proto_tree_add_item(lg8979_point_tree, hf_lg8979_ind_frcrpt_status_b2, tvb, offset, 1, ENC_LITTLE_ENDIAN); |
918 | 0 | proto_tree_add_item(lg8979_point_tree, hf_lg8979_ind_frcrpt_status_b3, tvb, offset, 1, ENC_LITTLE_ENDIAN); |
919 | 0 | proto_tree_add_item(lg8979_point_tree, hf_lg8979_ind_frcrpt_status_b4, tvb, offset, 1, ENC_LITTLE_ENDIAN); |
920 | 0 | proto_tree_add_item(lg8979_point_tree, hf_lg8979_ind_frcrpt_status_b5, tvb, offset, 1, ENC_LITTLE_ENDIAN); |
921 | 0 | proto_tree_add_item(lg8979_point_tree, hf_lg8979_ind_frcrpt_status_b6, tvb, offset, 1, ENC_LITTLE_ENDIAN); |
922 | 0 | proto_tree_add_item(lg8979_point_tree, hf_lg8979_ind_frcrpt_status_b7, tvb, offset, 1, ENC_LITTLE_ENDIAN); |
923 | 0 | offset += 1; |
924 | |
|
925 | 0 | lg8979_point_tree = proto_tree_add_subtree_format(lg8979_tree, tvb, offset, 1, |
926 | 0 | ett_lg8979_point, NULL, "Indication Change, Base Point Num %d", ptnum); |
927 | |
|
928 | 0 | proto_tree_add_item(lg8979_point_tree, hf_lg8979_ind_frcrpt_change_b0, tvb, offset, 1, ENC_LITTLE_ENDIAN); |
929 | 0 | proto_tree_add_item(lg8979_point_tree, hf_lg8979_ind_frcrpt_change_b1, tvb, offset, 1, ENC_LITTLE_ENDIAN); |
930 | 0 | proto_tree_add_item(lg8979_point_tree, hf_lg8979_ind_frcrpt_change_b2, tvb, offset, 1, ENC_LITTLE_ENDIAN); |
931 | 0 | proto_tree_add_item(lg8979_point_tree, hf_lg8979_ind_frcrpt_change_b3, tvb, offset, 1, ENC_LITTLE_ENDIAN); |
932 | 0 | proto_tree_add_item(lg8979_point_tree, hf_lg8979_ind_frcrpt_change_b4, tvb, offset, 1, ENC_LITTLE_ENDIAN); |
933 | 0 | proto_tree_add_item(lg8979_point_tree, hf_lg8979_ind_frcrpt_change_b5, tvb, offset, 1, ENC_LITTLE_ENDIAN); |
934 | 0 | proto_tree_add_item(lg8979_point_tree, hf_lg8979_ind_frcrpt_change_b6, tvb, offset, 1, ENC_LITTLE_ENDIAN); |
935 | 0 | proto_tree_add_item(lg8979_point_tree, hf_lg8979_ind_frcrpt_change_b7, tvb, offset, 1, ENC_LITTLE_ENDIAN); |
936 | 0 | offset += 1; |
937 | |
|
938 | 0 | ptnum += 8; |
939 | 0 | } |
940 | |
|
941 | 0 | break; |
942 | | |
943 | | /* Function Code 8 SOE Change Report */ |
944 | 0 | case LG8979_FC_SOE_CHGRPT: |
945 | |
|
946 | 0 | num_points = (data_len / 2); |
947 | |
|
948 | 0 | for (cnt=0; cnt<num_points; cnt++) { |
949 | | /* Get 12-bit point number and new status / change bits */ |
950 | 0 | ptnum = tvb_get_letohs(tvb, offset) & 0xFFF; |
951 | 0 | new_status = (tvb_get_uint8(tvb, offset+1) & 0x80) >> 7; |
952 | 0 | change = (tvb_get_uint8(tvb, offset+1) & 0x40) >> 6; |
953 | |
|
954 | 0 | lg8979_point_tree = proto_tree_add_subtree_format(lg8979_tree, tvb, offset, 2, ett_lg8979_point, NULL, |
955 | 0 | "SOE Change Report, Point Number: %u, Status: %u, Change %u", ptnum, new_status, change); |
956 | |
|
957 | 0 | proto_tree_add_item(lg8979_point_tree, hf_lg8979_soe_chgrpt_ptnum, tvb, offset, 2, ENC_LITTLE_ENDIAN); |
958 | 0 | proto_tree_add_item(lg8979_point_tree, hf_lg8979_soe_chgrpt_status, tvb, offset, 2, ENC_LITTLE_ENDIAN); |
959 | 0 | proto_tree_add_item(lg8979_point_tree, hf_lg8979_soe_chgrpt_change, tvb, offset, 2, ENC_LITTLE_ENDIAN); |
960 | |
|
961 | 0 | offset += 2; |
962 | 0 | } |
963 | |
|
964 | 0 | break; |
965 | | |
966 | | /* Function Code 9 SOE Force Report */ |
967 | 0 | case LG8979_FC_SOE_FRCRPT: |
968 | |
|
969 | 0 | ptnum = tvb_get_letohs(tvb, offset); |
970 | 0 | proto_tree_add_item(lg8979_tree, hf_lg8979_start_ptnum16, tvb, offset, 2, ENC_LITTLE_ENDIAN); |
971 | 0 | offset += 2; |
972 | |
|
973 | 0 | num_points = ((data_len - 2) / 2); |
974 | |
|
975 | 0 | for (cnt=0; cnt<num_points; cnt++) { |
976 | 0 | lg8979_point_tree = proto_tree_add_subtree_format(lg8979_tree, tvb, offset, 1, |
977 | 0 | ett_lg8979_point, NULL, "SOE Status, Base Point Num %d", ptnum); |
978 | |
|
979 | 0 | proto_tree_add_item(lg8979_point_tree, hf_lg8979_soe_frcrpt_status_b0, tvb, offset, 1, ENC_LITTLE_ENDIAN); |
980 | 0 | proto_tree_add_item(lg8979_point_tree, hf_lg8979_soe_frcrpt_status_b1, tvb, offset, 1, ENC_LITTLE_ENDIAN); |
981 | 0 | proto_tree_add_item(lg8979_point_tree, hf_lg8979_soe_frcrpt_status_b2, tvb, offset, 1, ENC_LITTLE_ENDIAN); |
982 | 0 | proto_tree_add_item(lg8979_point_tree, hf_lg8979_soe_frcrpt_status_b3, tvb, offset, 1, ENC_LITTLE_ENDIAN); |
983 | 0 | proto_tree_add_item(lg8979_point_tree, hf_lg8979_soe_frcrpt_status_b4, tvb, offset, 1, ENC_LITTLE_ENDIAN); |
984 | 0 | proto_tree_add_item(lg8979_point_tree, hf_lg8979_soe_frcrpt_status_b5, tvb, offset, 1, ENC_LITTLE_ENDIAN); |
985 | 0 | proto_tree_add_item(lg8979_point_tree, hf_lg8979_soe_frcrpt_status_b6, tvb, offset, 1, ENC_LITTLE_ENDIAN); |
986 | 0 | proto_tree_add_item(lg8979_point_tree, hf_lg8979_soe_frcrpt_status_b7, tvb, offset, 1, ENC_LITTLE_ENDIAN); |
987 | 0 | offset += 1; |
988 | |
|
989 | 0 | lg8979_point_tree = proto_tree_add_subtree_format(lg8979_tree, tvb, offset, 1, |
990 | 0 | ett_lg8979_point, NULL, "SOE Change, Base Point Num %d", ptnum); |
991 | |
|
992 | 0 | proto_tree_add_item(lg8979_point_tree, hf_lg8979_soe_frcrpt_change_b0, tvb, offset, 1, ENC_LITTLE_ENDIAN); |
993 | 0 | proto_tree_add_item(lg8979_point_tree, hf_lg8979_soe_frcrpt_change_b1, tvb, offset, 1, ENC_LITTLE_ENDIAN); |
994 | 0 | proto_tree_add_item(lg8979_point_tree, hf_lg8979_soe_frcrpt_change_b2, tvb, offset, 1, ENC_LITTLE_ENDIAN); |
995 | 0 | proto_tree_add_item(lg8979_point_tree, hf_lg8979_soe_frcrpt_change_b3, tvb, offset, 1, ENC_LITTLE_ENDIAN); |
996 | 0 | proto_tree_add_item(lg8979_point_tree, hf_lg8979_soe_frcrpt_change_b4, tvb, offset, 1, ENC_LITTLE_ENDIAN); |
997 | 0 | proto_tree_add_item(lg8979_point_tree, hf_lg8979_soe_frcrpt_change_b5, tvb, offset, 1, ENC_LITTLE_ENDIAN); |
998 | 0 | proto_tree_add_item(lg8979_point_tree, hf_lg8979_soe_frcrpt_change_b6, tvb, offset, 1, ENC_LITTLE_ENDIAN); |
999 | 0 | proto_tree_add_item(lg8979_point_tree, hf_lg8979_soe_frcrpt_change_b7, tvb, offset, 1, ENC_LITTLE_ENDIAN); |
1000 | 0 | offset += 1; |
1001 | |
|
1002 | 0 | ptnum += 8; |
1003 | 0 | } |
1004 | |
|
1005 | 0 | break; |
1006 | | |
1007 | | /* Function Code 11 Digital Input Force Report */ |
1008 | 0 | case LG8979_FC_DIG_FRCRPT: |
1009 | |
|
1010 | 0 | proto_tree_add_item_ret_uint8(lg8979_tree, hf_lg8979_start_ptnum8, tvb, offset, 1, ENC_LITTLE_ENDIAN, &ptnum8); |
1011 | 0 | offset += 1; |
1012 | | |
1013 | | /* 1 byte per start block and 2 bytes per 16-bit block to follow */ |
1014 | 0 | num_points = ((data_len-1)/2); |
1015 | |
|
1016 | 0 | for (cnt=0; cnt<num_points; cnt++) { |
1017 | |
|
1018 | 0 | lg8979_point_tree = proto_tree_add_subtree_format(lg8979_tree, tvb, offset, 2, |
1019 | 0 | ett_lg8979_point, NULL, "Digital Input Block %d", ptnum8); |
1020 | |
|
1021 | 0 | proto_tree_add_item(lg8979_point_tree, hf_lg8979_digin_b0, tvb, offset, 2, ENC_LITTLE_ENDIAN); |
1022 | 0 | proto_tree_add_item(lg8979_point_tree, hf_lg8979_digin_b1, tvb, offset, 2, ENC_LITTLE_ENDIAN); |
1023 | 0 | proto_tree_add_item(lg8979_point_tree, hf_lg8979_digin_b2, tvb, offset, 2, ENC_LITTLE_ENDIAN); |
1024 | 0 | proto_tree_add_item(lg8979_point_tree, hf_lg8979_digin_b3, tvb, offset, 2, ENC_LITTLE_ENDIAN); |
1025 | 0 | proto_tree_add_item(lg8979_point_tree, hf_lg8979_digin_b4, tvb, offset, 2, ENC_LITTLE_ENDIAN); |
1026 | 0 | proto_tree_add_item(lg8979_point_tree, hf_lg8979_digin_b5, tvb, offset, 2, ENC_LITTLE_ENDIAN); |
1027 | 0 | proto_tree_add_item(lg8979_point_tree, hf_lg8979_digin_b6, tvb, offset, 2, ENC_LITTLE_ENDIAN); |
1028 | 0 | proto_tree_add_item(lg8979_point_tree, hf_lg8979_digin_b7, tvb, offset, 2, ENC_LITTLE_ENDIAN); |
1029 | 0 | proto_tree_add_item(lg8979_point_tree, hf_lg8979_digin_b8, tvb, offset, 2, ENC_LITTLE_ENDIAN); |
1030 | 0 | proto_tree_add_item(lg8979_point_tree, hf_lg8979_digin_b9, tvb, offset, 2, ENC_LITTLE_ENDIAN); |
1031 | 0 | proto_tree_add_item(lg8979_point_tree, hf_lg8979_digin_b10, tvb, offset, 2, ENC_LITTLE_ENDIAN); |
1032 | 0 | proto_tree_add_item(lg8979_point_tree, hf_lg8979_digin_b11, tvb, offset, 2, ENC_LITTLE_ENDIAN); |
1033 | 0 | proto_tree_add_item(lg8979_point_tree, hf_lg8979_digin_b12, tvb, offset, 2, ENC_LITTLE_ENDIAN); |
1034 | 0 | proto_tree_add_item(lg8979_point_tree, hf_lg8979_digin_b13, tvb, offset, 2, ENC_LITTLE_ENDIAN); |
1035 | 0 | proto_tree_add_item(lg8979_point_tree, hf_lg8979_digin_b14, tvb, offset, 2, ENC_LITTLE_ENDIAN); |
1036 | 0 | proto_tree_add_item(lg8979_point_tree, hf_lg8979_digin_b15, tvb, offset, 2, ENC_LITTLE_ENDIAN); |
1037 | |
|
1038 | 0 | ptnum8 += 1; |
1039 | 0 | offset += 2; |
1040 | 0 | } |
1041 | |
|
1042 | 0 | break; |
1043 | | |
1044 | | |
1045 | | /* Function Code 12 Accumulator Change Report */ |
1046 | | /* Function Code 13 Accumulator Force Report */ |
1047 | 0 | case LG8979_FC_ACC_CHGRPT: |
1048 | 0 | case LG8979_FC_ACC_FRCRPT: |
1049 | |
|
1050 | 0 | proto_tree_add_item_ret_uint8(lg8979_tree, hf_lg8979_start_ptnum8, tvb, offset, 1, ENC_LITTLE_ENDIAN, &ptnum8); |
1051 | 0 | offset += 1; |
1052 | | |
1053 | | /* 1 byte for start point number and 2 bytes for each 16-bit accumulator value */ |
1054 | 0 | num_points = ((data_len-1) / 2); |
1055 | |
|
1056 | 0 | for (cnt=0; cnt<num_points; cnt++) { |
1057 | |
|
1058 | 0 | lg8979_point_item = proto_tree_add_item(lg8979_tree, hf_lg8979_acc_point, tvb, offset, 2, ENC_LITTLE_ENDIAN); |
1059 | 0 | proto_item_prepend_text(lg8979_point_item, "Point Number %u, ", ptnum8); |
1060 | |
|
1061 | 0 | offset += 2; |
1062 | 0 | ptnum8 += 1; |
1063 | |
|
1064 | 0 | } |
1065 | |
|
1066 | 0 | break; |
1067 | | |
1068 | | /* Function Code 14 SOE Log Change Report */ |
1069 | 0 | case LG8979_FC_SOELOG_CHGRPT: |
1070 | | |
1071 | | /* 9 bytes for each SOE Record */ |
1072 | 0 | num_points = (data_len / 9); |
1073 | |
|
1074 | 0 | for (cnt=0; cnt<num_points; cnt++) { |
1075 | | |
1076 | | /* Get 12-bit point number and new status bit */ |
1077 | 0 | ptnum = tvb_get_letohs(tvb, offset) & 0xFFF; |
1078 | 0 | new_status = (tvb_get_uint8(tvb, offset+1) & 0x80) >> 7; |
1079 | |
|
1080 | 0 | lg8979_point_tree = proto_tree_add_subtree_format(lg8979_tree, tvb, offset, 9, ett_lg8979_point, NULL, |
1081 | 0 | "SOE Log Change Report, Point Number: %u, New Status: %u", ptnum, new_status); |
1082 | | |
1083 | | /* Add 12-bit point number and "new status" bit to tree */ |
1084 | 0 | proto_tree_add_item(lg8979_point_tree, hf_lg8979_soe_logchg_ptnum, tvb, offset, 2, ENC_LITTLE_ENDIAN); |
1085 | 0 | proto_tree_add_item(lg8979_point_tree, hf_lg8979_soe_logchg_newstat, tvb, offset, 2, ENC_LITTLE_ENDIAN); |
1086 | 0 | offset += 2; |
1087 | | |
1088 | | /* Add 7-byte time-stamp to tree */ |
1089 | 0 | ts_mon = tvb_get_uint8(tvb, offset); |
1090 | 0 | ts_day = tvb_get_uint8(tvb, offset+1); |
1091 | 0 | ts_hr = tvb_get_uint8(tvb, offset+2); |
1092 | 0 | ts_min = tvb_get_uint8(tvb, offset+3); |
1093 | 0 | ts_sec = tvb_get_uint8(tvb, offset+4); |
1094 | 0 | ts_ms = tvb_get_letohs(tvb, offset+5); |
1095 | |
|
1096 | 0 | lg8979_ts_tree = proto_tree_add_subtree_format(lg8979_point_tree, tvb, offset, 7, ett_lg8979_ts, NULL, |
1097 | 0 | "SOE Time Stamp: [%02d/%02d %02d:%02d:%02d.%03d]", ts_mon, ts_day, ts_hr, ts_min, ts_sec, ts_ms); |
1098 | |
|
1099 | 0 | proto_tree_add_item(lg8979_ts_tree, hf_lg8979_soe_logchg_mon, tvb, offset, 1, ENC_LITTLE_ENDIAN); |
1100 | 0 | proto_tree_add_item(lg8979_ts_tree, hf_lg8979_soe_logchg_day, tvb, offset+1, 1, ENC_LITTLE_ENDIAN); |
1101 | 0 | proto_tree_add_item(lg8979_ts_tree, hf_lg8979_soe_logchg_hour, tvb, offset+2, 1, ENC_LITTLE_ENDIAN); |
1102 | 0 | proto_tree_add_item(lg8979_ts_tree, hf_lg8979_soe_logchg_min, tvb, offset+3, 1, ENC_LITTLE_ENDIAN); |
1103 | 0 | proto_tree_add_item(lg8979_ts_tree, hf_lg8979_soe_logchg_sec, tvb, offset+4, 1, ENC_LITTLE_ENDIAN); |
1104 | 0 | proto_tree_add_item(lg8979_ts_tree, hf_lg8979_soe_logchg_msec, tvb, offset+5, 2, ENC_LITTLE_ENDIAN); |
1105 | 0 | offset += 7; |
1106 | 0 | } |
1107 | |
|
1108 | 0 | break; |
1109 | | |
1110 | | /* Function Code 21 SBO Select - Echo of Master->RTU Message */ |
1111 | 0 | case LG8979_FC_SBO_SELECT: |
1112 | | |
1113 | | /* Get 8-bit point number and trip/close command-code */ |
1114 | 0 | ptnum = tvb_get_uint8(tvb, offset); |
1115 | 0 | tripclose = (tvb_get_uint8(tvb, offset+1) & 0x80) >> 7; |
1116 | |
|
1117 | 0 | lg8979_point_tree = proto_tree_add_subtree_format( |
1118 | 0 | lg8979_tree, tvb, offset, 2, |
1119 | 0 | ett_lg8979_point, NULL, |
1120 | 0 | "SBO Command, Pt.Num: %u, Code: %s", |
1121 | 0 | ptnum, |
1122 | 0 | val_to_str_const(tripclose, lg8979_sbo_tripclose_vals, "Unknown Control Code")); |
1123 | | |
1124 | | /* Update the Information Column with Command Details */ |
1125 | 0 | col_append_sep_fstr(pinfo->cinfo, COL_INFO, NULL, "Output: %u, Code: %s", |
1126 | 0 | ptnum, val_to_str_const(tripclose, lg8979_sbo_tripclose_vals, "Unknown Control Code")); |
1127 | | |
1128 | | /* Add SBO Select Details to tree */ |
1129 | 0 | proto_tree_add_item(lg8979_point_tree, hf_lg8979_start_ptnum8, tvb, offset, 1, ENC_LITTLE_ENDIAN); |
1130 | 0 | proto_tree_add_item(lg8979_point_tree, hf_lg8979_sbo_tripclose, tvb, offset+1, 1, ENC_LITTLE_ENDIAN); |
1131 | 0 | proto_tree_add_item(lg8979_point_tree, hf_lg8979_sbo_timercnt, tvb, offset+1, 1, ENC_LITTLE_ENDIAN); |
1132 | 0 | offset += 2; |
1133 | 0 | break; |
1134 | | |
1135 | | /* Function Code 22 SBO Operate - Echo of Master->RTU Message */ |
1136 | 0 | case LG8979_FC_SBO_OPERATE: |
1137 | | |
1138 | | /* Get 8-bit point number */ |
1139 | 0 | ptnum = tvb_get_uint8(tvb, offset); |
1140 | | |
1141 | | /* Update the Information Column with Command Details */ |
1142 | 0 | col_append_sep_fstr(pinfo->cinfo, COL_INFO, NULL, "Output: %u", ptnum); |
1143 | | |
1144 | | /* Add 8-bit point number to tree */ |
1145 | 0 | proto_tree_add_item(lg8979_tree, hf_lg8979_start_ptnum8, tvb, offset, 1, ENC_LITTLE_ENDIAN); |
1146 | 0 | offset += 1; |
1147 | 0 | break; |
1148 | | |
1149 | | /* Function Code 31 RTU Configuration */ |
1150 | 0 | case LG8979_FC_RTU_CONFIG: |
1151 | | |
1152 | | /* Number of IO Chassis */ |
1153 | 0 | proto_tree_add_item_ret_uint8(lg8979_tree, hf_lg8979_rtucfg_num_chassis, tvb, offset, 1, ENC_LITTLE_ENDIAN, &num_chassis); |
1154 | 0 | offset += 1; |
1155 | |
|
1156 | 0 | for (cnt=0; cnt<num_chassis; cnt++) { |
1157 | | /* Chassis Number */ |
1158 | 0 | proto_tree_add_item(lg8979_tree, hf_lg8979_rtucfg_chassis_num, tvb, offset, 1, ENC_LITTLE_ENDIAN); |
1159 | 0 | offset += 1; |
1160 | | |
1161 | | /* Card Codes For Each Slot (0-15) */ |
1162 | 0 | for (cnt1=0; cnt1<16; cnt1++) { |
1163 | 0 | lg8979_slot_item = proto_tree_add_item(lg8979_tree, hf_lg8979_rtucfg_card_slot, tvb, offset, 1, ENC_LITTLE_ENDIAN); |
1164 | 0 | proto_item_prepend_text(lg8979_slot_item, "Slot %d, ", cnt1); |
1165 | 0 | offset += 1; |
1166 | 0 | } |
1167 | 0 | } |
1168 | |
|
1169 | 0 | break; |
1170 | | |
1171 | | /* Function Code 33 Time Bias */ |
1172 | 0 | case LG8979_FC_TIME_BIAS: |
1173 | | /* Add Time Bias "Processing Time" to tree */ |
1174 | 0 | proto_tree_add_item(lg8979_tree, hf_lg8979_timebias_proctime, tvb, offset, 1, ENC_LITTLE_ENDIAN); |
1175 | 0 | offset += 1; |
1176 | 0 | break; |
1177 | | |
1178 | | /* Function Code 39 Firmware Configuration */ |
1179 | 0 | case LG8979_FC_FIRMWARE_CFG: |
1180 | 0 | proto_tree_add_item(lg8979_tree, hf_lg8979_firmware_ver, tvb, offset, 2, ENC_LITTLE_ENDIAN); |
1181 | 0 | offset += 2; |
1182 | 0 | break; |
1183 | | |
1184 | | /* Function Code 63 Exception Report */ |
1185 | | /* Parameter byte is context-sensitive to the Code byte used */ |
1186 | | /* For example, if the Code byte is 0x01 (Cold Start) the parameter byte is always 0 */ |
1187 | | /* If the code byte is 0x09 (Function Code), the parameter byte is the value of the disallowed function code */ |
1188 | 0 | case LG8979_FC_EXP_RPT: |
1189 | |
|
1190 | 0 | exp_code = tvb_get_uint8(tvb, offset); |
1191 | |
|
1192 | 0 | proto_tree_add_item(lg8979_tree, hf_lg8979_exprpt_code, tvb, offset, 1, ENC_LITTLE_ENDIAN); |
1193 | 0 | proto_tree_add_item(lg8979_tree, hf_lg8979_exprpt_parm, tvb, offset+1, 1, ENC_LITTLE_ENDIAN); |
1194 | | /* Function code lookup, if required */ |
1195 | 0 | if (exp_code == 14) { |
1196 | 0 | proto_item *lg8979_dfc_item; |
1197 | 0 | lg8979_dfc_item = proto_tree_add_item(lg8979_tree, hf_lg8979_disallowed_func, tvb, offset+1, 1, ENC_NA); |
1198 | 0 | proto_item_set_generated(lg8979_dfc_item); |
1199 | 0 | } |
1200 | |
|
1201 | 0 | offset += 2; |
1202 | 0 | break; |
1203 | | |
1204 | 0 | default: |
1205 | 0 | break; |
1206 | 0 | } |
1207 | |
|
1208 | 0 | } /* !shr */ |
1209 | | |
1210 | 0 | if (shr) { |
1211 | 0 | col_append_sep_str(pinfo->cinfo, COL_INFO, NULL, "Short Response"); |
1212 | 0 | } |
1213 | | |
1214 | | /* Add CRC-16 */ |
1215 | 0 | proto_tree_add_item(lg8979_tree, hf_lg8979_crc16, tvb, offset, 2, ENC_BIG_ENDIAN); |
1216 | |
|
1217 | 0 | } /* packet type */ |
1218 | | |
1219 | 0 | return tvb_reported_length(tvb); |
1220 | |
|
1221 | 0 | } |
1222 | | |
1223 | | /******************************************************************************************************/ |
1224 | | /* Return length of L&G 8979 Protocol over TCP message (used for re-assembly) */ |
1225 | | /******************************************************************************************************/ |
1226 | | static unsigned |
1227 | | get_lg8979_len(packet_info *pinfo _U_, tvbuff_t *tvb, int offset _U_, void *data _U_) |
1228 | 0 | { |
1229 | |
|
1230 | 0 | unsigned len; |
1231 | 0 | len = tvb_reported_length(tvb); /* XXX: should really be some minimum length ?? */ |
1232 | |
|
1233 | 0 | return len; |
1234 | 0 | } |
1235 | | |
1236 | | /******************************************************************************************************/ |
1237 | | /* Dissect (and possibly Re-assemble) L&G 8979 protocol payload data */ |
1238 | | /******************************************************************************************************/ |
1239 | | static int |
1240 | | dissect_lg8979_tcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_) |
1241 | 0 | { |
1242 | |
|
1243 | 0 | int length = tvb_reported_length(tvb); |
1244 | | |
1245 | | /* Check for a L&G8979 packet. It should begin with 0xFF */ |
1246 | 0 | if(length < 2 || tvb_get_uint8(tvb, 0) != 0xFF) { |
1247 | | /* Not a L&G 8979 Protocol packet, just happened to use the same port */ |
1248 | 0 | return 0; |
1249 | 0 | } |
1250 | | |
1251 | 0 | tcp_dissect_pdus(tvb, pinfo, tree, lg8979_desegment, 1, |
1252 | 0 | get_lg8979_len, dissect_lg8979, data); |
1253 | |
|
1254 | 0 | return length; |
1255 | 0 | } |
1256 | | |
1257 | | |
1258 | | /******************************************************************************************************/ |
1259 | | /* Dissect "simple" L&G 8979 protocol payload (no TCP re-assembly) */ |
1260 | | /******************************************************************************************************/ |
1261 | | static int |
1262 | | dissect_lg8979_simple(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_) |
1263 | 0 | { |
1264 | 0 | int length = tvb_reported_length(tvb); |
1265 | | |
1266 | | /* Check for a L&G8979 packet. It should begin with 0xFF */ |
1267 | 0 | if(length < 2 || tvb_get_uint8(tvb, 0) != 0xFF) { |
1268 | | /* Not a L&G 8979 Protocol packet ... */ |
1269 | 0 | return 0; |
1270 | 0 | } |
1271 | | |
1272 | 0 | dissect_lg8979(tvb, pinfo, tree, data); |
1273 | |
|
1274 | 0 | return length; |
1275 | 0 | } |
1276 | | |
1277 | | /******************************************************************************************************/ |
1278 | | /* Register the protocol with Wireshark */ |
1279 | | /******************************************************************************************************/ |
1280 | | void proto_reg_handoff_lg8979(void); |
1281 | | |
1282 | | void |
1283 | | proto_register_lg8979(void) |
1284 | 15 | { |
1285 | | /* L&G 8979 Protocol header fields */ |
1286 | 15 | static hf_register_info lg8979_hf[] = { |
1287 | 15 | { &hf_lg8979_header, |
1288 | 15 | { "Header", "lg8979.header", FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL }}, |
1289 | 15 | { &hf_lg8979_flags, |
1290 | 15 | { "Flags", "lg8979.flags", FT_UINT8, BASE_HEX, NULL, 0x00, NULL, HFILL }}, |
1291 | 15 | { &hf_lg8979_shr, |
1292 | 15 | { "SHR", "lg8979.shr", FT_UINT8, BASE_DEC, NULL, 0x80, "Short Response Flag", HFILL }}, |
1293 | 15 | { &hf_lg8979_mfc, |
1294 | 15 | { "MFC", "lg8979.mfc", FT_UINT8, BASE_DEC, NULL, 0x78, "Multi Function Code", HFILL }}, |
1295 | 15 | { &hf_lg8979_ack, |
1296 | 15 | { "ACK", "lg8979.ack", FT_UINT8, BASE_DEC, NULL, 0x04, "Acknowledge Flag", HFILL }}, |
1297 | 15 | { &hf_lg8979_con, |
1298 | 15 | { "CON", "lg8979.con", FT_UINT8, BASE_DEC, NULL, 0x40, "Continuation Flag", HFILL }}, |
1299 | 15 | { &hf_lg8979_frz, |
1300 | 15 | { "FRZ", "lg8979.frz", FT_UINT8, BASE_DEC, NULL, 0x20, "Accumulator Freeze Flag", HFILL }}, |
1301 | 15 | { &hf_lg8979_ind, |
1302 | 15 | { "IND", "lg8979.ind", FT_UINT8, BASE_DEC, NULL, 0x10, "Indication Change Flag", HFILL }}, |
1303 | 15 | { &hf_lg8979_sch, |
1304 | 15 | { "SCH", "lg8979.sch", FT_UINT8, BASE_DEC, NULL, 0x08, "SOE Change Flag", HFILL }}, |
1305 | 15 | { &hf_lg8979_slg, |
1306 | 15 | { "SLG", "lg8979.slg", FT_UINT8, BASE_DEC, NULL, 0x04, "SOE Log Flag", HFILL }}, |
1307 | 15 | { &hf_lg8979_address, |
1308 | 15 | { "RTU Address", "lg8979.address", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }}, |
1309 | 15 | { &hf_lg8979_lastblock, |
1310 | 15 | { "Last Block Mark", "lg8979.lastblock", FT_UINT8, BASE_DEC, NULL, 0x80, NULL, HFILL }}, |
1311 | 15 | { &hf_lg8979_funccode, |
1312 | 15 | { "Function Code", "lg8979.funccode", FT_UINT8, BASE_DEC|BASE_EXT_STRING, &lg8979_funccode_vals_ext, 0x7F, NULL, HFILL }}, |
1313 | 15 | { &hf_lg8979_length, |
1314 | 15 | { "Data Length", "lg8979.length", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }}, |
1315 | 15 | { &hf_lg8979_start_ptnum16, |
1316 | 15 | { "Start Point Number (16-bit)", "lg8979.start_ptnum16", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }}, |
1317 | 15 | { &hf_lg8979_start_ptnum8, |
1318 | 15 | { "Start Point Number (8-bit)", "lg8979.start_ptnum8", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }}, |
1319 | 15 | { &hf_lg8979_stop_ptnum16, |
1320 | 15 | { "Stop Point Number (16-bit)", "lg8979.stop_ptnum16", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }}, |
1321 | 15 | { &hf_lg8979_stop_ptnum8, |
1322 | 15 | { "Stop Point Number (8-bit)", "lg8979.stop_ptnum8", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }}, |
1323 | 15 | { &hf_lg8979_ang_point, |
1324 | 15 | { "Analog Point", "lg8979.ang_point", FT_UINT24, BASE_DEC, NULL, 0x0, NULL, HFILL }}, |
1325 | 15 | { &hf_lg8979_adc_ref_zero, |
1326 | 15 | { "ADC Reference (0%)", "lg8979.adc_ref_zero", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }}, |
1327 | 15 | { &hf_lg8979_adc_ref_neg90, |
1328 | 15 | { "ADC Reference (-90%)", "lg8979.adc_ref_neg90", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }}, |
1329 | 15 | { &hf_lg8979_adc_ref_pos90, |
1330 | 15 | { "ADC Reference (+90%)", "lg8979.adc_ref_pos90", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }}, |
1331 | 15 | { &hf_lg8979_ind_chgrpt_ptnum, |
1332 | 15 | { "Point Number (12-bit)", "lg8979.ind_chgrpt_ptnum", FT_UINT16, BASE_DEC, NULL, 0x0FFF, NULL, HFILL }}, |
1333 | 15 | { &hf_lg8979_ind_chgrpt_status, |
1334 | 15 | { "Status Bit", "lg8979.ind_chgrpt_status", FT_UINT16, BASE_DEC, NULL, 0x8000, NULL, HFILL }}, |
1335 | 15 | { &hf_lg8979_ind_chgrpt_change, |
1336 | 15 | { "Change Bit", "lg8979.ind_chgrpt_change", FT_UINT16, BASE_DEC, NULL, 0x4000, NULL, HFILL }}, |
1337 | 15 | { &hf_lg8979_ind_frcrpt_status_b0, |
1338 | 15 | { "Status Bit 0", "lg8979.ind.frcrpt.status_b0", FT_BOOLEAN, 8, NULL, 0x01, NULL, HFILL }}, |
1339 | 15 | { &hf_lg8979_ind_frcrpt_status_b1, |
1340 | 15 | { "Status Bit 1", "lg8979.ind.frcrpt.status_b1", FT_BOOLEAN, 8, NULL, 0x02, NULL, HFILL }}, |
1341 | 15 | { &hf_lg8979_ind_frcrpt_status_b2, |
1342 | 15 | { "Status Bit 2", "lg8979.ind.frcrpt.status_b2", FT_BOOLEAN, 8, NULL, 0x04, NULL, HFILL }}, |
1343 | 15 | { &hf_lg8979_ind_frcrpt_status_b3, |
1344 | 15 | { "Status Bit 3", "lg8979.ind.frcrpt.status_b3", FT_BOOLEAN, 8, NULL, 0x08, NULL, HFILL }}, |
1345 | 15 | { &hf_lg8979_ind_frcrpt_status_b4, |
1346 | 15 | { "Status Bit 4", "lg8979.ind.frcrpt.status_b4", FT_BOOLEAN, 8, NULL, 0x10, NULL, HFILL }}, |
1347 | 15 | { &hf_lg8979_ind_frcrpt_status_b5, |
1348 | 15 | { "Status Bit 5", "lg8979.ind.frcrpt.status_b5", FT_BOOLEAN, 8, NULL, 0x20, NULL, HFILL }}, |
1349 | 15 | { &hf_lg8979_ind_frcrpt_status_b6, |
1350 | 15 | { "Status Bit 6", "lg8979.ind.frcrpt.status_b6", FT_BOOLEAN, 8, NULL, 0x40, NULL, HFILL }}, |
1351 | 15 | { &hf_lg8979_ind_frcrpt_status_b7, |
1352 | 15 | { "Status Bit 7", "lg8979.ind.frcrpt.status_b7", FT_BOOLEAN, 8, NULL, 0x80, NULL, HFILL }}, |
1353 | 15 | { &hf_lg8979_ind_frcrpt_change_b0, |
1354 | 15 | { "Change Bit 0", "lg8979.ind.frcrpt.change_b0", FT_BOOLEAN, 8, NULL, 0x01, NULL, HFILL }}, |
1355 | 15 | { &hf_lg8979_ind_frcrpt_change_b1, |
1356 | 15 | { "Change Bit 1", "lg8979.ind.frcrpt.change_b1", FT_BOOLEAN, 8, NULL, 0x02, NULL, HFILL }}, |
1357 | 15 | { &hf_lg8979_ind_frcrpt_change_b2, |
1358 | 15 | { "Change Bit 2", "lg8979.ind.frcrpt.change_b2", FT_BOOLEAN, 8, NULL, 0x04, NULL, HFILL }}, |
1359 | 15 | { &hf_lg8979_ind_frcrpt_change_b3, |
1360 | 15 | { "Change Bit 3", "lg8979.ind.frcrpt.change_b3", FT_BOOLEAN, 8, NULL, 0x08, NULL, HFILL }}, |
1361 | 15 | { &hf_lg8979_ind_frcrpt_change_b4, |
1362 | 15 | { "Change Bit 4", "lg8979.ind.frcrpt.change_b4", FT_BOOLEAN, 8, NULL, 0x10, NULL, HFILL }}, |
1363 | 15 | { &hf_lg8979_ind_frcrpt_change_b5, |
1364 | 15 | { "Change Bit 5", "lg8979.ind.frcrpt.change_b5", FT_BOOLEAN, 8, NULL, 0x20, NULL, HFILL }}, |
1365 | 15 | { &hf_lg8979_ind_frcrpt_change_b6, |
1366 | 15 | { "Change Bit 6", "lg8979.ind.frcrpt.change_b6", FT_BOOLEAN, 8, NULL, 0x40, NULL, HFILL }}, |
1367 | 15 | { &hf_lg8979_ind_frcrpt_change_b7, |
1368 | 15 | { "Change Bit 7", "lg8979.ind.frcrpt.change_b7", FT_BOOLEAN, 8, NULL, 0x80, NULL, HFILL }}, |
1369 | 15 | { &hf_lg8979_soe_chgrpt_ptnum, |
1370 | 15 | { "Point Number (12-bit)", "lg8979.soe_chgrpt_ptnum", FT_UINT16, BASE_DEC, NULL, 0x0FFF, NULL, HFILL }}, |
1371 | 15 | { &hf_lg8979_soe_chgrpt_status, |
1372 | 15 | { "Status Bit", "lg8979.soe_chgrpt_status", FT_UINT16, BASE_DEC, NULL, 0x8000, NULL, HFILL }}, |
1373 | 15 | { &hf_lg8979_soe_chgrpt_change, |
1374 | 15 | { "Change Bit", "lg8979.soe_chgrpt_change", FT_UINT16, BASE_DEC, NULL, 0x4000, NULL, HFILL }}, |
1375 | 15 | { &hf_lg8979_soe_frcrpt_status_b0, |
1376 | 15 | { "Status Bit 0", "lg8979.soe.frcrpt.status_b0", FT_BOOLEAN, 8, NULL, 0x01, NULL, HFILL }}, |
1377 | 15 | { &hf_lg8979_soe_frcrpt_status_b1, |
1378 | 15 | { "Status Bit 1", "lg8979.soe.frcrpt.status_b1", FT_BOOLEAN, 8, NULL, 0x02, NULL, HFILL }}, |
1379 | 15 | { &hf_lg8979_soe_frcrpt_status_b2, |
1380 | 15 | { "Status Bit 2", "lg8979.soe.frcrpt.status_b2", FT_BOOLEAN, 8, NULL, 0x04, NULL, HFILL }}, |
1381 | 15 | { &hf_lg8979_soe_frcrpt_status_b3, |
1382 | 15 | { "Status Bit 3", "lg8979.soe.frcrpt.status_b3", FT_BOOLEAN, 8, NULL, 0x08, NULL, HFILL }}, |
1383 | 15 | { &hf_lg8979_soe_frcrpt_status_b4, |
1384 | 15 | { "Status Bit 4", "lg8979.soe.frcrpt.status_b4", FT_BOOLEAN, 8, NULL, 0x10, NULL, HFILL }}, |
1385 | 15 | { &hf_lg8979_soe_frcrpt_status_b5, |
1386 | 15 | { "Status Bit 5", "lg8979.soe.frcrpt.status_b5", FT_BOOLEAN, 8, NULL, 0x20, NULL, HFILL }}, |
1387 | 15 | { &hf_lg8979_soe_frcrpt_status_b6, |
1388 | 15 | { "Status Bit 6", "lg8979.soe.frcrpt.status_b6", FT_BOOLEAN, 8, NULL, 0x40, NULL, HFILL }}, |
1389 | 15 | { &hf_lg8979_soe_frcrpt_status_b7, |
1390 | 15 | { "Status Bit 7", "lg8979.soe.frcrpt.status_b7", FT_BOOLEAN, 8, NULL, 0x80, NULL, HFILL }}, |
1391 | 15 | { &hf_lg8979_soe_frcrpt_change_b0, |
1392 | 15 | { "Change Bit 0", "lg8979.soe.frcrpt.change_b0", FT_BOOLEAN, 8, NULL, 0x01, NULL, HFILL }}, |
1393 | 15 | { &hf_lg8979_soe_frcrpt_change_b1, |
1394 | 15 | { "Change Bit 1", "lg8979.soe.frcrpt.change_b1", FT_BOOLEAN, 8, NULL, 0x02, NULL, HFILL }}, |
1395 | 15 | { &hf_lg8979_soe_frcrpt_change_b2, |
1396 | 15 | { "Change Bit 2", "lg8979.soe.frcrpt.change_b2", FT_BOOLEAN, 8, NULL, 0x04, NULL, HFILL }}, |
1397 | 15 | { &hf_lg8979_soe_frcrpt_change_b3, |
1398 | 15 | { "Change Bit 3", "lg8979.soe.frcrpt.change_b3", FT_BOOLEAN, 8, NULL, 0x08, NULL, HFILL }}, |
1399 | 15 | { &hf_lg8979_soe_frcrpt_change_b4, |
1400 | 15 | { "Change Bit 4", "lg8979.soe.frcrpt.change_b4", FT_BOOLEAN, 8, NULL, 0x10, NULL, HFILL }}, |
1401 | 15 | { &hf_lg8979_soe_frcrpt_change_b5, |
1402 | 15 | { "Change Bit 5", "lg8979.soe.frcrpt.change_b5", FT_BOOLEAN, 8, NULL, 0x20, NULL, HFILL }}, |
1403 | 15 | { &hf_lg8979_soe_frcrpt_change_b6, |
1404 | 15 | { "Change Bit 6", "lg8979.soe.frcrpt.change_b6", FT_BOOLEAN, 8, NULL, 0x40, NULL, HFILL }}, |
1405 | 15 | { &hf_lg8979_soe_frcrpt_change_b7, |
1406 | 15 | { "Change Bit 7", "lg8979.soe.frcrpt.change_b7", FT_BOOLEAN, 8, NULL, 0x80, NULL, HFILL }}, |
1407 | 15 | { &hf_lg8979_digin_b0, |
1408 | 15 | { "Digital Input Bit 0", "lg8979.digin_b0", FT_BOOLEAN, 16, NULL, 0x0001, NULL, HFILL }}, |
1409 | 15 | { &hf_lg8979_digin_b1, |
1410 | 15 | { "Digital Input Bit 1", "lg8979.digin_b1", FT_BOOLEAN, 16, NULL, 0x0002, NULL, HFILL }}, |
1411 | 15 | { &hf_lg8979_digin_b2, |
1412 | 15 | { "Digital Input Bit 2", "lg8979.digin_b2", FT_BOOLEAN, 16, NULL, 0x0004, NULL, HFILL }}, |
1413 | 15 | { &hf_lg8979_digin_b3, |
1414 | 15 | { "Digital Input Bit 3", "lg8979.digin_b3", FT_BOOLEAN, 16, NULL, 0x0008, NULL, HFILL }}, |
1415 | 15 | { &hf_lg8979_digin_b4, |
1416 | 15 | { "Digital Input Bit 4", "lg8979.digin_b4", FT_BOOLEAN, 16, NULL, 0x0010, NULL, HFILL }}, |
1417 | 15 | { &hf_lg8979_digin_b5, |
1418 | 15 | { "Digital Input Bit 5", "lg8979.digin_b5", FT_BOOLEAN, 16, NULL, 0x0020, NULL, HFILL }}, |
1419 | 15 | { &hf_lg8979_digin_b6, |
1420 | 15 | { "Digital Input Bit 6", "lg8979.digin_b6", FT_BOOLEAN, 16, NULL, 0x0040, NULL, HFILL }}, |
1421 | 15 | { &hf_lg8979_digin_b7, |
1422 | 15 | { "Digital Input Bit 7", "lg8979.digin_b7", FT_BOOLEAN, 16, NULL, 0x0080, NULL, HFILL }}, |
1423 | 15 | { &hf_lg8979_digin_b8, |
1424 | 15 | { "Digital Input Bit 8", "lg8979.digin_b8", FT_BOOLEAN, 16, NULL, 0x0100, NULL, HFILL }}, |
1425 | 15 | { &hf_lg8979_digin_b9, |
1426 | 15 | { "Digital Input Bit 9", "lg8979.digin_b9", FT_BOOLEAN, 16, NULL, 0x0200, NULL, HFILL }}, |
1427 | 15 | { &hf_lg8979_digin_b10, |
1428 | 15 | { "Digital Input Bit 10", "lg8979.digin_b10", FT_BOOLEAN, 16, NULL, 0x0400, NULL, HFILL }}, |
1429 | 15 | { &hf_lg8979_digin_b11, |
1430 | 15 | { "Digital Input Bit 11", "lg8979.digin_b11", FT_BOOLEAN, 16, NULL, 0x0800, NULL, HFILL }}, |
1431 | 15 | { &hf_lg8979_digin_b12, |
1432 | 15 | { "Digital Input Bit 12", "lg8979.digin_b12", FT_BOOLEAN, 16, NULL, 0x1000, NULL, HFILL }}, |
1433 | 15 | { &hf_lg8979_digin_b13, |
1434 | 15 | { "Digital Input Bit 13", "lg8979.digin_b13", FT_BOOLEAN, 16, NULL, 0x2000, NULL, HFILL }}, |
1435 | 15 | { &hf_lg8979_digin_b14, |
1436 | 15 | { "Digital Input Bit 14", "lg8979.digin_b14", FT_BOOLEAN, 16, NULL, 0x4000, NULL, HFILL }}, |
1437 | 15 | { &hf_lg8979_digin_b15, |
1438 | 15 | { "Digital Input Bit 15", "lg8979.digin_b15", FT_BOOLEAN, 16, NULL, 0x8000, NULL, HFILL }}, |
1439 | 15 | { &hf_lg8979_acc_point, |
1440 | 15 | { "Value", "lg8979.acc_point", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }}, |
1441 | 15 | { &hf_lg8979_soe_logchg_ptnum, |
1442 | 15 | { "Point Number", "lg8979.soe_logchg_ptnum", FT_UINT16, BASE_DEC, NULL, 0x0FFF, NULL, HFILL }}, |
1443 | 15 | { &hf_lg8979_soe_logchg_newstat, |
1444 | 15 | { "New Status", "lg8979.soe_logchg_newstat", FT_UINT16, BASE_DEC, NULL, 0x8000, NULL, HFILL }}, |
1445 | 15 | { &hf_lg8979_soe_logchg_mon, |
1446 | 15 | { "Month", "lg8979.soe_logchg_mon", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }}, |
1447 | 15 | { &hf_lg8979_soe_logchg_day, |
1448 | 15 | { "Day", "lg8979.soe_logchg_day", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }}, |
1449 | 15 | { &hf_lg8979_soe_logchg_hour, |
1450 | 15 | { "Hours", "lg8979.soe_logchg_hour", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }}, |
1451 | 15 | { &hf_lg8979_soe_logchg_min, |
1452 | 15 | { "Minute", "lg8979.soe_logchg_min", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }}, |
1453 | 15 | { &hf_lg8979_soe_logchg_sec, |
1454 | 15 | { "Second", "lg8979.soe_logchg_sec", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }}, |
1455 | 15 | { &hf_lg8979_soe_logchg_msec, |
1456 | 15 | { "Milli-Second", "lg8979.soe_logchg_msec", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }}, |
1457 | 15 | { &hf_lg8979_ang_output_val, |
1458 | 15 | { "Point Value", "lg8979.ang_output_val", FT_UINT16, BASE_DEC, NULL, 0x0FFF, NULL, HFILL }}, |
1459 | 15 | { &hf_lg8979_sbo_tripclose, |
1460 | 15 | { "Trip/Close Control Code", "lg8979.sbo_tripclose", FT_UINT8, BASE_DEC, VALS(lg8979_sbo_tripclose_vals), 0x80, NULL, HFILL }}, |
1461 | 15 | { &hf_lg8979_sbo_timercnt, |
1462 | 15 | { "Timer Count", "lg8979.sbo_timercnt", FT_UINT8, BASE_DEC, NULL, 0x7F, NULL, HFILL }}, |
1463 | 15 | { &hf_lg8979_digout_data, |
1464 | 15 | { "Data", "lg8979.digout_data", FT_UINT24, BASE_HEX, NULL, 0x0, NULL, HFILL }}, |
1465 | 15 | { &hf_lg8979_pul_output_base, |
1466 | 15 | { "Base Time", "lg8979.pul_output_base", FT_UINT8, BASE_HEX, VALS(lg8979_pul_output_base_vals), 0x03, NULL, HFILL }}, |
1467 | 15 | { &hf_lg8979_pul_output_dur, |
1468 | 15 | { "Duration", "lg8979.pul_output_dur", FT_UINT8, BASE_HEX, NULL, 0x7C, NULL, HFILL }}, |
1469 | 15 | { &hf_lg8979_pul_output_rl, |
1470 | 15 | { "Raise/Lower", "lg8979.pul_output_rl", FT_UINT8, BASE_HEX, VALS(lg8979_pul_output_rl_vals), 0x80, NULL, HFILL }}, |
1471 | 15 | { &hf_lg8979_ang_deadband, |
1472 | 15 | { "Deadband", "lg8979.ang_deadband", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }}, |
1473 | 15 | { &hf_lg8979_ang_group, |
1474 | 15 | { "Analog Group", "lg8979.ang_group", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }}, |
1475 | 15 | { &hf_lg8979_ang_group_pts, |
1476 | 15 | { "Analog Group Points Mask", "lg8979.ang_group_pts", FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL }}, |
1477 | 15 | { &hf_lg8979_acc_preset, |
1478 | 15 | { "Preset Value", "lg8979.acc_preset", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }}, |
1479 | 15 | { &hf_lg8979_rtucfg_num_chassis, |
1480 | 15 | { "Number of I/O Chassis in RTU", "lg8979.rtucfg_num_chassis", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }}, |
1481 | 15 | { &hf_lg8979_rtucfg_chassis_num, |
1482 | 15 | { "Chassis Number", "lg8979.rtucfg_chassis_num", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }}, |
1483 | 15 | { &hf_lg8979_rtucfg_card_slot, |
1484 | 15 | { "Card Code", "lg8979.rtucfg_card_slot", FT_UINT8, BASE_DEC, VALS(lg8979_cardcode_vals), 0x0, NULL, HFILL }}, |
1485 | 15 | { &hf_lg8979_timesync_mon, |
1486 | 15 | { "Month", "lg8979.timesync_mon", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }}, |
1487 | 15 | { &hf_lg8979_timesync_day, |
1488 | 15 | { "Day", "lg8979.timesync_day", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }}, |
1489 | 15 | { &hf_lg8979_timesync_hour, |
1490 | 15 | { "Hours", "lg8979.timesync_hour", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }}, |
1491 | 15 | { &hf_lg8979_timesync_min, |
1492 | 15 | { "Minute", "lg8979.timesync_min", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }}, |
1493 | 15 | { &hf_lg8979_timesync_sec, |
1494 | 15 | { "Second", "lg8979.timesync_sec", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }}, |
1495 | 15 | { &hf_lg8979_timesync_msec, |
1496 | 15 | { "Milli-Second", "lg8979.timesync_msec", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }}, |
1497 | 15 | { &hf_lg8979_timebias_value, |
1498 | 15 | { "Time Bias Value", "lg8979.timebias_value", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }}, |
1499 | 15 | { &hf_lg8979_firmware_ver, |
1500 | 15 | { "Firmware Version", "lg8979.firmware_ver", FT_UINT16, BASE_HEX, NULL, 0x0, NULL, HFILL }}, |
1501 | 15 | { &hf_lg8979_timebias_proctime, |
1502 | 15 | { "Time Bias Processing Time (ms)", "lg8979.timebias_proctime", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }}, |
1503 | 15 | { &hf_lg8979_exprpt_code, |
1504 | 15 | { "Exception Report Code", "lg8979.exprpt_code", FT_UINT8, BASE_DEC, VALS(lg8979_exprpt_code_vals), 0x0, NULL, HFILL }}, |
1505 | 15 | { &hf_lg8979_exprpt_parm, |
1506 | 15 | { "Value", "lg8979.exprpt_parm", FT_UINT8, BASE_DEC, VALS(lg8979_exprpt_parm_vals), 0x0, NULL, HFILL }}, |
1507 | 15 | { &hf_lg8979_disallowed_func, |
1508 | 15 | { "Disallowed Function Code", "lg8979.disallowed_func", FT_UINT8, BASE_DEC|BASE_EXT_STRING, &lg8979_funccode_vals_ext, 0x0, NULL, HFILL }}, |
1509 | 15 | { &hf_lg8979_crc16, |
1510 | 15 | { "CRC-16", "lg8979.crc16", FT_UINT16, BASE_HEX, NULL, 0x0, NULL, HFILL }}, |
1511 | | |
1512 | 15 | }; |
1513 | | |
1514 | | /* Setup protocol subtree array */ |
1515 | 15 | static int *ett[] = { |
1516 | 15 | &ett_lg8979, |
1517 | 15 | &ett_lg8979_flags, |
1518 | 15 | &ett_lg8979_funccode, |
1519 | 15 | &ett_lg8979_point, |
1520 | 15 | &ett_lg8979_ts, |
1521 | 15 | }; |
1522 | | |
1523 | 15 | module_t *lg8979_module; |
1524 | | |
1525 | | /* Register the protocol name and description */ |
1526 | 15 | proto_lg8979 = proto_register_protocol("Landis & Gyr Telegyr 8979", "L&G 8979", "lg8979"); |
1527 | | |
1528 | | /* Registering protocol to be called by another dissector */ |
1529 | 15 | register_dissector("lg8979", dissect_lg8979_simple, proto_lg8979); |
1530 | | |
1531 | | /* Required function calls to register the header fields and subtrees used */ |
1532 | 15 | proto_register_field_array(proto_lg8979, lg8979_hf, array_length(lg8979_hf)); |
1533 | 15 | proto_register_subtree_array(ett, array_length(ett)); |
1534 | | |
1535 | | |
1536 | | /* Register required preferences for L&G 8979 register decoding */ |
1537 | 15 | lg8979_module = prefs_register_protocol(proto_lg8979, NULL); |
1538 | | |
1539 | | /* L&G 8979 - Desegmentmentation; defaults to true for TCP desegmentation*/ |
1540 | 15 | prefs_register_bool_preference(lg8979_module, "desegment", |
1541 | 15 | "Desegment all L&G 8979 Protocol packets spanning multiple TCP segments", |
1542 | 15 | "Whether the L&G 8979 dissector should desegment all messages spanning multiple TCP segments", |
1543 | 15 | &lg8979_desegment); |
1544 | 15 | } |
1545 | | |
1546 | | /******************************************************************************************************/ |
1547 | | void |
1548 | | proto_reg_handoff_lg8979(void) |
1549 | 15 | { |
1550 | 15 | dissector_handle_t lg8979_handle; |
1551 | | |
1552 | | /* Make sure to use L&G 8979 Protocol Preferences field to determine default TCP port */ |
1553 | 15 | lg8979_handle = create_dissector_handle(dissect_lg8979_tcp, proto_lg8979); |
1554 | | |
1555 | 15 | dissector_add_for_decode_as_with_preference("tcp.port", lg8979_handle); |
1556 | 15 | dissector_add_for_decode_as("rtacser.data", lg8979_handle); |
1557 | 15 | } |
1558 | | |
1559 | | /* |
1560 | | * Editor modelines - https://www.wireshark.org/tools/modelines.html |
1561 | | * |
1562 | | * Local variables: |
1563 | | * c-basic-offset: 4 |
1564 | | * tab-width: 8 |
1565 | | * indent-tabs-mode: nil |
1566 | | * End: |
1567 | | * |
1568 | | * vi: set shiftwidth=4 tabstop=8 expandtab: |
1569 | | * :indentSize=4:tabSize=8:noTabs=true: |
1570 | | */ |