Coverage Report

Created: 2026-05-14 06:28

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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
 */