/src/wireshark/epan/dissectors/packet-selfm.c
Line | Count | Source |
1 | | /* packet-selfm.c |
2 | | * Routines for Schweitzer Engineering Laboratories (SEL) Protocols Dissection |
3 | | * By Chris Bontje (cbontje[AT]gmail.com |
4 | | * Copyright 2012-2021, |
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 | | * Schweitzer Engineering Labs ("SEL") manufactures and sells digital protective relay equipment |
15 | | * for use in industrial high-voltage installations. SEL Protocol evolved over time as a |
16 | | * (semi)proprietary method for auto-configuration of connected SEL devices for retrieval of |
17 | | * analog and digital status data. The protocol itself supports embedded binary messages |
18 | | * (which are what this dissector looks for) slip-streamed in the data stream with normal |
19 | | * ASCII text data. A combination of both are used for full auto-configuration of devices, |
20 | | * but a wealth of information can be extracted from the binary messages alone. |
21 | | * |
22 | | * 'SEL Protocol' encompasses several message types, including |
23 | | * - Fast Meter |
24 | | * - Fast Operate |
25 | | * - Fast SER |
26 | | * - Fast Message |
27 | | * |
28 | | * Documentation on Fast Meter and Fast Message standards available from www.selinc.com in |
29 | | * SEL Application Guides AG95-10_20091109.pdf and AG_200214.pdf |
30 | | ************************************************************************************************ |
31 | | * Dissector Notes: |
32 | | * |
33 | | * 1) All SEL Protocol messages over TCP are normally tunneled via a Telnet connection. As Telnet |
34 | | * has special handling for the 0xFF character ("IAC"), normally a pair of 0xFF's are inserted |
35 | | * to represent an actual payload byte of 0xFF. A function from the packet-telnet.c dissector has |
36 | | * been borrowed to automatically pre-process any Ethernet-based packet and remove these 'extra' |
37 | | * 0xFF bytes. Wireshark Notes on Telnet 0xFF doubling are discussed here: |
38 | | * https://lists.wireshark.org/archives/wireshark-bugs/201204/msg00198.html |
39 | | * |
40 | | * 2) The auto-configuration process for Fast Meter will exchange several "configuration" messages |
41 | | * that describe various data regions (METER, DEMAND, PEAK, etc) that will later have corresponding |
42 | | * "data" messages. This dissector code will currently save and accurately retrieve the 3 sets |
43 | | * of these exchanges: |
44 | | * 0xA5C1, 0xA5D1, "METER" region |
45 | | * 0xA5C2, 0xA5D2, "DEMAND" region |
46 | | * 0xA5C3, 0xA5D3, "PEAK" region |
47 | | * The configuration messages are stored in structs that are managed using the wmem library and |
48 | | * the Wireshark conversation functionality. |
49 | | */ |
50 | | |
51 | | #include "config.h" |
52 | 0 | #define WS_LOG_DOMAIN "packet-selfm" |
53 | | #include <wireshark.h> |
54 | | |
55 | | #include <epan/packet.h> |
56 | | #include "packet-tcp.h" |
57 | | #include <epan/prefs.h> |
58 | | #include <epan/to_str.h> |
59 | | #include <epan/strutil.h> |
60 | | #include <epan/reassemble.h> |
61 | | #include <epan/expert.h> |
62 | | #include <epan/crc16-tvb.h> |
63 | | #include <epan/proto_data.h> |
64 | | |
65 | | void proto_register_selfm(void); |
66 | | |
67 | | /* Initialize the protocol and registered fields */ |
68 | | static int proto_selfm; |
69 | | static int hf_selfm_msgtype; |
70 | | static int hf_selfm_padbyte; |
71 | | static int hf_selfm_checksum; |
72 | | static int hf_selfm_relaydef_len; |
73 | | static int hf_selfm_relaydef_numproto; |
74 | | static int hf_selfm_relaydef_numfm; |
75 | | static int hf_selfm_relaydef_numflags; |
76 | | static int hf_selfm_relaydef_fmcfg_cmd; |
77 | | static int hf_selfm_relaydef_fmdata_cmd; |
78 | | static int hf_selfm_relaydef_statbit; |
79 | | static int hf_selfm_relaydef_statbit_cmd; |
80 | | static int hf_selfm_relaydef_proto; |
81 | | static int hf_selfm_fmconfig_len; |
82 | | static int hf_selfm_fmconfig_numflags; |
83 | | static int hf_selfm_fmconfig_loc_sf; |
84 | | static int hf_selfm_fmconfig_num_sf; |
85 | | static int hf_selfm_fmconfig_num_ai; |
86 | | static int hf_selfm_fmconfig_num_samp; |
87 | | static int hf_selfm_fmconfig_num_dig; |
88 | | static int hf_selfm_fmconfig_num_calc; |
89 | | static int hf_selfm_fmconfig_ofs_ai; |
90 | | static int hf_selfm_fmconfig_ofs_ts; |
91 | | static int hf_selfm_fmconfig_ofs_dig; |
92 | | static int hf_selfm_fmconfig_ai_type; |
93 | | static int hf_selfm_fmconfig_ai_sf_type; |
94 | | static int hf_selfm_fmconfig_ai_sf_ofs; |
95 | | static int hf_selfm_fmconfig_cblk_rot; |
96 | | static int hf_selfm_fmconfig_cblk_vconn; |
97 | | static int hf_selfm_fmconfig_cblk_iconn; |
98 | | static int hf_selfm_fmconfig_cblk_ctype; |
99 | | static int hf_selfm_fmconfig_cblk_deskew_ofs; |
100 | | static int hf_selfm_fmconfig_cblk_rs_ofs; |
101 | | static int hf_selfm_fmconfig_cblk_xs_ofs; |
102 | | static int hf_selfm_fmconfig_cblk_ia_idx; |
103 | | static int hf_selfm_fmconfig_cblk_ib_idx; |
104 | | static int hf_selfm_fmconfig_cblk_ic_idx; |
105 | | static int hf_selfm_fmconfig_cblk_va_idx; |
106 | | static int hf_selfm_fmconfig_cblk_vb_idx; |
107 | | static int hf_selfm_fmconfig_cblk_vc_idx; |
108 | | static int hf_selfm_fmconfig_ai_sf_float; |
109 | | static int hf_selfm_fmdata_len; |
110 | | static int hf_selfm_fmdata_flagbyte; |
111 | | static int hf_selfm_fmdata_dig_b0; |
112 | | static int hf_selfm_fmdata_dig_b1; |
113 | | static int hf_selfm_fmdata_dig_b2; |
114 | | static int hf_selfm_fmdata_dig_b3; |
115 | | static int hf_selfm_fmdata_dig_b4; |
116 | | static int hf_selfm_fmdata_dig_b5; |
117 | | static int hf_selfm_fmdata_dig_b6; |
118 | | static int hf_selfm_fmdata_dig_b7; |
119 | | static int hf_selfm_fmdata_ai_sf_fp; |
120 | | static int hf_selfm_foconfig_len; |
121 | | static int hf_selfm_foconfig_num_brkr; |
122 | | static int hf_selfm_foconfig_num_rb; |
123 | | static int hf_selfm_foconfig_prb_supp; |
124 | | static int hf_selfm_foconfig_reserved; |
125 | | static int hf_selfm_foconfig_brkr_open; |
126 | | static int hf_selfm_foconfig_brkr_close; |
127 | | static int hf_selfm_foconfig_rb_cmd; |
128 | | static int hf_selfm_fastop_len; |
129 | | static int hf_selfm_fastop_rb_code; |
130 | | static int hf_selfm_fastop_br_code; |
131 | | static int hf_selfm_fastop_valid; |
132 | | static int hf_selfm_alt_foconfig_len; |
133 | | static int hf_selfm_alt_foconfig_num_ports; |
134 | | static int hf_selfm_alt_foconfig_num_brkr; |
135 | | static int hf_selfm_alt_foconfig_num_rb; |
136 | | static int hf_selfm_alt_foconfig_funccode; |
137 | | static int hf_selfm_alt_fastop_len; |
138 | | static int hf_selfm_alt_fastop_code; |
139 | | static int hf_selfm_alt_fastop_valid; |
140 | | |
141 | | static int hf_selfm_fastmsg_len; |
142 | | static int hf_selfm_fastmsg_routing_addr; |
143 | | static int hf_selfm_fastmsg_status; |
144 | | static int hf_selfm_fastmsg_funccode; |
145 | | static int hf_selfm_fastmsg_response_code; |
146 | | static int hf_selfm_fastmsg_seq; |
147 | | static int hf_selfm_fastmsg_seq_fir; |
148 | | static int hf_selfm_fastmsg_seq_fin; |
149 | | static int hf_selfm_fastmsg_seq_cnt; |
150 | | static int hf_selfm_fastmsg_resp_num; |
151 | | static int hf_selfm_fastmsg_crc16; |
152 | | static int hf_selfm_fastmsg_def_route_sup; |
153 | | static int hf_selfm_fastmsg_def_rx_stat; |
154 | | static int hf_selfm_fastmsg_def_tx_stat; |
155 | | static int hf_selfm_fastmsg_def_rx_maxfr; |
156 | | static int hf_selfm_fastmsg_def_tx_maxfr; |
157 | | static int hf_selfm_fastmsg_def_rx_num_fc; |
158 | | static int hf_selfm_fastmsg_def_rx_fc; |
159 | | static int hf_selfm_fastmsg_def_tx_num_fc; |
160 | | static int hf_selfm_fastmsg_def_tx_fc; |
161 | | static int hf_selfm_fastmsg_uns_en_fc; |
162 | | static int hf_selfm_fastmsg_uns_en_fc_data; |
163 | | static int hf_selfm_fastmsg_uns_dis_fc; |
164 | | static int hf_selfm_fastmsg_uns_dis_fc_data; |
165 | | static int hf_selfm_fastmsg_baseaddr; |
166 | | static int hf_selfm_fastmsg_numwords; |
167 | | static int hf_selfm_fastmsg_flags; |
168 | | static int hf_selfm_fastmsg_datafmt_resp_numitem; |
169 | | static int hf_selfm_fastmsg_dataitem_qty; |
170 | | static int hf_selfm_fastmsg_dataitem_type; |
171 | | static int hf_selfm_fastmsg_dataitem_uint16; |
172 | | static int hf_selfm_fastmsg_dataitem_int16; |
173 | | static int hf_selfm_fastmsg_dataitem_uint32; |
174 | | static int hf_selfm_fastmsg_dataitem_int32; |
175 | | static int hf_selfm_fastmsg_dataitem_float; |
176 | | static int hf_selfm_fastmsg_devdesc_num_region; |
177 | | static int hf_selfm_fastmsg_devdesc_num_ctrl; |
178 | | static int hf_selfm_fastmsg_unsresp_orig; |
179 | | static int hf_selfm_fastmsg_unsresp_doy; |
180 | | static int hf_selfm_fastmsg_unsresp_year; |
181 | | static int hf_selfm_fastmsg_unsresp_todms; |
182 | | static int hf_selfm_fastmsg_unsresp_num_elmt; |
183 | | static int hf_selfm_fastmsg_unsresp_elmt_idx; |
184 | | static int hf_selfm_fastmsg_unsresp_elmt_ts_ofs; |
185 | | static int hf_selfm_fastmsg_unsresp_elmt_status; |
186 | | static int hf_selfm_fastmsg_unsresp_eor; |
187 | | static int hf_selfm_fastmsg_unsresp_elmt_statword; |
188 | | static int hf_selfm_fastmsg_unswrite_addr1; |
189 | | static int hf_selfm_fastmsg_unswrite_addr2; |
190 | | static int hf_selfm_fastmsg_unswrite_num_reg; |
191 | | static int hf_selfm_fastmsg_unswrite_reg_val; |
192 | | static int hf_selfm_fastmsg_soe_req_orig; |
193 | | static int hf_selfm_fastmsg_soe_resp_numblks; |
194 | | static int hf_selfm_fastmsg_soe_resp_orig; |
195 | | static int hf_selfm_fastmsg_soe_resp_numbits; |
196 | | static int hf_selfm_fastmsg_soe_resp_pad; |
197 | | static int hf_selfm_fastmsg_soe_resp_doy; |
198 | | static int hf_selfm_fastmsg_soe_resp_year; |
199 | | static int hf_selfm_fastmsg_soe_resp_tod; |
200 | | static int hf_selfm_fastmsg_soe_resp_data; |
201 | | /* Generated from convert_proto_tree_add_text.pl */ |
202 | | static int hf_selfm_fmconfig_ai_channel; |
203 | | static int hf_selfm_fmdata_ai_value16; |
204 | | static int hf_selfm_fmdata_ai_scale_factor; |
205 | | static int hf_selfm_fmdata_ai_value_float; |
206 | | static int hf_selfm_fmdata_ai_value_double; |
207 | | static int hf_selfm_fmdata_data_type; |
208 | | static int hf_selfm_fmdata_quantity; |
209 | | static int hf_selfm_fmdata_ai_value_string; |
210 | | static int hf_selfm_fastmsg_unsresp_elmt_ts_ofs_decoded; |
211 | | static int hf_selfm_fid; |
212 | | static int hf_selfm_rid; |
213 | | static int hf_selfm_fastmsg_data_region_name; |
214 | | static int hf_selfm_fmdata_timestamp; |
215 | | static int hf_selfm_fmdata_frame_data_format_reference; |
216 | | static int hf_selfm_fastmsg_bit_label_name; |
217 | | |
218 | | /* Initialize the subtree pointers */ |
219 | | static int ett_selfm; |
220 | | static int ett_selfm_relaydef; |
221 | | static int ett_selfm_relaydef_fm; |
222 | | static int ett_selfm_relaydef_proto; |
223 | | static int ett_selfm_relaydef_flags; |
224 | | static int ett_selfm_fmconfig; |
225 | | static int ett_selfm_fmconfig_ai; |
226 | | static int ett_selfm_fmconfig_calc; |
227 | | static int ett_selfm_foconfig; |
228 | | static int ett_selfm_foconfig_brkr; |
229 | | static int ett_selfm_foconfig_rb; |
230 | | static int ett_selfm_fastop; |
231 | | static int ett_selfm_fmdata; |
232 | | static int ett_selfm_fmdata_ai; |
233 | | static int ett_selfm_fmdata_dig; |
234 | | static int ett_selfm_fmdata_ai_ch; |
235 | | static int ett_selfm_fmdata_dig_ch; |
236 | | static int ett_selfm_fastmsg; |
237 | | static int ett_selfm_fastmsg_seq; |
238 | | static int ett_selfm_fastmsg_def_fc; |
239 | | static int ett_selfm_fastmsg_datareg; |
240 | | static int ett_selfm_fastmsg_soeblk; |
241 | | static int ett_selfm_fastmsg_tag; |
242 | | static int ett_selfm_fastmsg_element_list; |
243 | | static int ett_selfm_fastmsg_element; |
244 | | |
245 | | /* Expert fields */ |
246 | | static expert_field ei_selfm_crc16_incorrect; |
247 | | |
248 | | static dissector_handle_t selfm_handle; |
249 | | |
250 | 0 | #define CMD_FAST_MSG 0xA546 |
251 | | #define CMD_CLEAR_STATBIT 0xA5B9 |
252 | 0 | #define CMD_RELAY_DEF 0xA5C0 |
253 | 0 | #define CMD_FM_CONFIG 0xA5C1 |
254 | 0 | #define CMD_DFM_CONFIG 0xA5C2 |
255 | 0 | #define CMD_PDFM_CONFIG 0xA5C3 |
256 | | #define CMD_FASTOP_RESETDEF 0xA5CD |
257 | 0 | #define CMD_FASTOP_CONFIG 0xA5CE |
258 | 0 | #define CMD_ALT_FASTOP_CONFIG 0xA5CF |
259 | 0 | #define CMD_FM_DATA 0xA5D1 |
260 | 0 | #define CMD_DFM_DATA 0xA5D2 |
261 | 0 | #define CMD_PDFM_DATA 0xA5D3 |
262 | 0 | #define CMD_FASTOP_RB_CTRL 0xA5E0 |
263 | 0 | #define CMD_FASTOP_BR_CTRL 0xA5E3 |
264 | 0 | #define CMD_ALT_FASTOP_OPEN 0xA5E5 |
265 | 0 | #define CMD_ALT_FASTOP_CLOSE 0xA5E6 |
266 | 0 | #define CMD_ALT_FASTOP_SET 0xA5E7 |
267 | 0 | #define CMD_ALT_FASTOP_CLEAR 0xA5E8 |
268 | 0 | #define CMD_ALT_FASTOP_PULSE 0xA5E9 |
269 | | #define CMD_FASTOP_RESET 0xA5ED |
270 | | |
271 | 0 | #define FM_CONFIG_SF_LOC_FM 0 |
272 | 0 | #define FM_CONFIG_SF_LOC_CFG 1 |
273 | | |
274 | 0 | #define FM_CONFIG_ANA_CHNAME_LEN 6 |
275 | 0 | #define FM_CONFIG_ANA_CHTYPE_INT16 0x00 |
276 | 0 | #define FM_CONFIG_ANA_CHTYPE_FP 0x01 |
277 | 0 | #define FM_CONFIG_ANA_CHTYPE_FPD 0x02 |
278 | | #define FM_CONFIG_ANA_CHTYPE_TS 0x03 |
279 | | #define FM_CONFIG_ANA_CHTYPE_TS_LEN 8 |
280 | | |
281 | | #define FM_CONFIG_ANA_SFTYPE_INT16 0x00 |
282 | 0 | #define FM_CONFIG_ANA_SFTYPE_FP 0x01 |
283 | | #define FM_CONFIG_ANA_SFTYPE_FPD 0x02 |
284 | | #define FM_CONFIG_ANA_SFTYPE_TS 0x03 |
285 | | #define FM_CONFIG_ANA_SFTYPE_NONE 0xFF |
286 | | |
287 | | |
288 | | /* Fast Message Function Codes, "response" or "ACK" messages are the same as the request, but have the MSB set */ |
289 | | #define FAST_MSG_CFG_BLOCK 0x00 |
290 | 0 | #define FAST_MSG_EN_UNS_DATA 0x01 |
291 | 0 | #define FAST_MSG_DIS_UNS_DATA 0x02 |
292 | | #define FAST_MSG_PING 0x05 |
293 | 0 | #define FAST_MSG_READ_REQ 0x10 |
294 | 0 | #define FAST_MSG_GEN_UNS_DATA 0x12 |
295 | 0 | #define FAST_MSG_SOE_STATE_REQ 0x16 |
296 | 0 | #define FAST_MSG_UNS_RESP 0x18 |
297 | 0 | #define FAST_MSG_UNS_WRITE 0x20 |
298 | | #define FAST_MSG_UNS_WRITE_REQ 0x21 |
299 | | #define FAST_MSG_DEVDESC_REQ 0x30 |
300 | 0 | #define FAST_MSG_DATAFMT_REQ 0x31 |
301 | | #define FAST_MSG_UNS_DATAFMT_RESP 0x32 |
302 | 0 | #define FAST_MSG_BITLABEL_REQ 0x33 |
303 | | #define FAST_MSG_MGMT_REQ 0x40 |
304 | 0 | #define FAST_MSG_CFG_BLOCK_RESP 0x80 |
305 | 0 | #define FAST_MSG_EN_UNS_DATA_ACK 0x81 |
306 | 0 | #define FAST_MSG_DIS_UNS_DATA_ACK 0x82 |
307 | | #define FAST_MSG_PING_ACK 0x85 |
308 | 0 | #define FAST_MSG_READ_RESP 0x90 |
309 | 0 | #define FAST_MSG_SOE_STATE_RESP 0x96 |
310 | 0 | #define FAST_MSG_UNS_RESP_ACK 0x98 |
311 | 0 | #define FAST_MSG_DEVDESC_RESP 0xB0 |
312 | 0 | #define FAST_MSG_DATAFMT_RESP 0xB1 |
313 | 0 | #define FAST_MSG_BITLABEL_RESP 0xB3 |
314 | | |
315 | | |
316 | | /* Fast Message Sequence Byte Masks */ |
317 | 16 | #define FAST_MSG_SEQ_FIR 0x80 |
318 | 16 | #define FAST_MSG_SEQ_FIN 0x40 |
319 | 16 | #define FAST_MSG_SEQ_CNT 0x3f |
320 | | |
321 | | /* Fast Message Tag Data Types */ |
322 | 0 | #define FAST_MSG_TAGTYPE_CHAR8 0x0011 /* 1 x 8-bit character per item */ |
323 | 0 | #define FAST_MSG_TAGTYPE_CHAR16 0x0012 /* 2 x 8-bit characters per item */ |
324 | 0 | #define FAST_MSG_TAGTYPE_DIGWORD8_BL 0x0021 /* 8-bit binary item, with labels */ |
325 | 0 | #define FAST_MSG_TAGTYPE_DIGWORD8 0x0022 /* 8-bit binary item, without labels */ |
326 | 0 | #define FAST_MSG_TAGTYPE_DIGWORD16_BL 0x0023 /* 16-bit binary item, with labels */ |
327 | 0 | #define FAST_MSG_TAGTYPE_DIGWORD16 0x0024 /* 16-bit binary item, without labels */ |
328 | 0 | #define FAST_MSG_TAGTYPE_INT16 0x0031 /* 16-bit signed integer */ |
329 | 0 | #define FAST_MSG_TAGTYPE_UINT16 0x0032 /* 16-bit unsigned integer */ |
330 | 0 | #define FAST_MSG_TAGTYPE_INT32 0x0033 /* 32-bit signed integer */ |
331 | 0 | #define FAST_MSG_TAGTYPE_UINT32 0x0034 /* 32-bit unsigned integer */ |
332 | 0 | #define FAST_MSG_TAGTYPE_FLOAT 0x0041 /* 32-bit floating point */ |
333 | | |
334 | | |
335 | | /* Globals for SEL Protocol Preferences */ |
336 | | static bool selfm_desegment = true; |
337 | | static bool selfm_telnet_clean = true; |
338 | | static bool selfm_crc16; /* Default CRC16 validation to false */ |
339 | | static const char *selfm_ser_list; |
340 | | |
341 | | /***************************************************************************************/ |
342 | | /* Fast Meter Message structs */ |
343 | | /***************************************************************************************/ |
344 | | /* Holds Configuration Information required to decode a Fast Meter analog value */ |
345 | | typedef struct { |
346 | | char name[FM_CONFIG_ANA_CHNAME_LEN+1]; /* Name of Analog Channel, 6 char + a null */ |
347 | | uint8_t type; /* Analog Channel Type, Int, FP, etc */ |
348 | | uint8_t sf_type; /* Analog Scale Factor Type, none, etc */ |
349 | | uint16_t sf_offset; /* Analog Scale Factor Offset */ |
350 | | float sf_fp; /* Scale factor, if present in Cfg message */ |
351 | | } fm_analog_info; |
352 | | |
353 | | |
354 | | /* Holds Information from a single "Fast Meter Configuration" frame. Required to dissect subsequent "Data" frames. */ |
355 | | typedef struct { |
356 | | uint32_t fnum; /* frame number */ |
357 | | uint16_t cfg_cmd; /* holds ID of config command, ie: 0xa5c1 */ |
358 | | uint8_t num_flags; /* Number of Flag Bytes */ |
359 | | uint8_t sf_loc; /* Scale Factor Location */ |
360 | | uint8_t sf_num; /* Number of Scale Factors */ |
361 | | uint8_t num_ai; /* Number of Analog Inputs */ |
362 | | uint8_t num_ai_samples; /* Number samples per Analog Input */ |
363 | | uint16_t offset_ai; /* Start Offset of Analog Inputs */ |
364 | | uint8_t num_dig; /* Number of Digital Input Blocks */ |
365 | | uint16_t offset_dig; /* Start Offset of Digital Inputs */ |
366 | | uint16_t offset_ts; /* Start Offset of Time Stamp */ |
367 | | uint8_t num_calc; /* Number of Calculations */ |
368 | | fm_analog_info *analogs; /* Array of fm_analog_infos */ |
369 | | } fm_config_frame; |
370 | | |
371 | | /**************************************************************************************/ |
372 | | /* Fast Message Data Item struct */ |
373 | | /**************************************************************************************/ |
374 | | /* Holds Configuration Information required to decode a Fast Message Data Item */ |
375 | | /* Each data region format is returned as a sequential list of tags, w/o reference to */ |
376 | | /* an absolute address. The format information will consist of a name, a data type */ |
377 | | /* and a quantity of values contained within the data item. We will retrieve this */ |
378 | | /* format information later while attempting to dissect Read Response frames */ |
379 | | typedef struct { |
380 | | uint32_t fnum; /* frame number */ |
381 | | uint32_t base_address; /* Base address of Data Item Region */ |
382 | | uint8_t index_pos; /* Index Offset Position within data format message (1-16) */ |
383 | | char name[10+1]; /* Name of Data Item, 10 chars, null-terminated */ |
384 | | uint16_t quantity; /* Quantity of values within Data Item */ |
385 | | uint16_t data_type; /* Data Item Type, Char, Int, FP, etc */ |
386 | | } fastmsg_dataitem; |
387 | | |
388 | | /**************************************************************************************/ |
389 | | /* Fast Message Data Region struct */ |
390 | | /**************************************************************************************/ |
391 | | /* Holds Configuration Information required to decode a Fast Message Data Region */ |
392 | | /* Each data region format is returned as a sequential list of tags, w/o reference to */ |
393 | | typedef struct { |
394 | | char name[10+1]; /* Name of Data Region, 10 chars, null-terminated */ |
395 | | } fastmsg_dataregion; |
396 | | |
397 | | /**************************************************************************************/ |
398 | | /* Fast Unsolicited SER Index Lookup */ |
399 | | /**************************************************************************************/ |
400 | | /* Holds user-configurable naming information for Unsolicited Fast SER word bits */ |
401 | | /* that will later be present in an 0xA546 msg with only an index position reference */ |
402 | | typedef struct { |
403 | | char *name; /* Name of Word Bit, 8 chars, null-terminated */ |
404 | | } fastser_uns_wordbit; |
405 | | |
406 | | |
407 | | /**************************************************************************************/ |
408 | | /* Fast Message Conversation struct */ |
409 | | /**************************************************************************************/ |
410 | | typedef struct { |
411 | | wmem_list_t *fm_config_frames; /* List contains a fm_config_data struct for each Fast Meter configuration frame */ |
412 | | wmem_list_t *fastmsg_dataitems; /* List contains a fastmsg_dataitem struct for each Fast Message Data Item */ |
413 | | wmem_tree_t *fastmsg_dataregions; /* Tree contains a fastmsg_dataregion struct for each Fast Message Data Region */ |
414 | | wmem_tree_t *fastser_uns_wordbits; /* Tree contains a fastser_uns_wordbit struct for each comma-separated entry in the 'SER List' User Preference */ |
415 | | } fm_conversation; |
416 | | |
417 | | |
418 | | static const value_string selfm_msgtype_vals[] = { |
419 | | { CMD_FAST_MSG, "Fast Message Block" }, /* 0xA546 */ |
420 | | { CMD_CLEAR_STATBIT, "Clear Status Bits Command" }, /* 0xA5B9 */ |
421 | | { CMD_RELAY_DEF, "Relay Definition Block" }, /* 0xA5C0 */ |
422 | | { CMD_FM_CONFIG, "Fast Meter Configuration Block" }, /* 0xA5C1 */ |
423 | | { CMD_DFM_CONFIG, "Demand Fast Meter Configuration Block" }, /* 0xA5C2 */ |
424 | | { CMD_PDFM_CONFIG, "Peak Demand Fast Meter Configuration Block" }, /* 0xA5C3 */ |
425 | | { CMD_FASTOP_RESETDEF, "Fast Operate Reset Definition" }, /* 0xA5CD */ |
426 | | { CMD_FASTOP_CONFIG, "Fast Operate Configuration" }, /* 0xA5CE */ |
427 | | { CMD_ALT_FASTOP_CONFIG, "Alternate Fast Operate Configuration" }, /* 0xA5CF */ |
428 | | { CMD_FM_DATA, "Fast Meter Data Block" }, /* 0xA5D1 */ |
429 | | { CMD_DFM_DATA, "Demand Fast Meter Data Block" }, /* 0xA5D2 */ |
430 | | { CMD_PDFM_DATA, "Peak Demand Fast Meter Data Block" }, /* 0xA5D3 */ |
431 | | { CMD_FASTOP_RB_CTRL, "Fast Operate Remote Bit Control" }, /* 0xA5E0 */ |
432 | | { CMD_FASTOP_BR_CTRL, "Fast Operate Breaker Bit Control" }, /* 0xA5E3 */ |
433 | | { CMD_ALT_FASTOP_OPEN, "Alternate Fast Operate Open Breaker Control" }, /* 0xA5E5 */ |
434 | | { CMD_ALT_FASTOP_CLOSE, "Alternate Fast Operate Close Breaker Control" }, /* 0xA5E6 */ |
435 | | { CMD_ALT_FASTOP_SET, "Alternate Fast Operate Set Remote Bit Control" }, /* 0xA5E7 */ |
436 | | { CMD_ALT_FASTOP_CLEAR, "Alternate Fast Operate Clear Remote Bit Control" }, /* 0xA5E8 */ |
437 | | { CMD_ALT_FASTOP_PULSE, "Alternate Fast Operate Pulse Remote Bit Control" }, /* 0xA5E9 */ |
438 | | { CMD_FASTOP_RESET, "Fast Operate Reset" }, /* 0xA5ED */ |
439 | | { 0, NULL } |
440 | | }; |
441 | | static value_string_ext selfm_msgtype_vals_ext = VALUE_STRING_EXT_INIT(selfm_msgtype_vals); |
442 | | |
443 | | static const value_string selfm_relaydef_proto_vals[] = { |
444 | | { 0x0000, "SEL Fast Meter" }, |
445 | | { 0x0001, "SEL Limited Multidrop (LMD)" }, |
446 | | { 0x0002, "Modbus" }, |
447 | | { 0x0003, "SY/MAX" }, |
448 | | { 0x0004, "SEL Relay-to-Relay" }, |
449 | | { 0x0005, "DNP 3.0" }, |
450 | | { 0x0006, "SEL Mirrored Bits" }, |
451 | | { 0x0007, "IEEE 37.118 Synchrophasors" }, |
452 | | { 0x0008, "IEC 61850" }, |
453 | | { 0x0100, "SEL Fast Meter w/ Fast Operate" }, |
454 | | { 0x0101, "SEL Limited Multidrop (LMD) w/ Fast Operate" }, |
455 | | { 0x0200, "SEL Fast Meter w/ Fast Message" }, |
456 | | { 0x0300, "SEL Fast Meter w/ Fast Operate and Fast Message" }, |
457 | | { 0x0301, "SEL Limited Multidrop (LMD) w/ Fast Operate and Fast Message" }, |
458 | | { 0, NULL } |
459 | | }; |
460 | | static value_string_ext selfm_relaydef_proto_vals_ext = VALUE_STRING_EXT_INIT(selfm_relaydef_proto_vals); |
461 | | |
462 | | static const value_string selfm_fmconfig_ai_chtype_vals[] = { |
463 | | { FM_CONFIG_ANA_CHTYPE_INT16, "16-Bit Integer" }, |
464 | | { FM_CONFIG_ANA_CHTYPE_FP, "IEEE Floating Point" }, |
465 | | { FM_CONFIG_ANA_CHTYPE_FPD, "IEEE Floating Point (Double)" }, |
466 | | { FM_CONFIG_ANA_CHTYPE_TS, "8-byte Time Stamp" }, |
467 | | { 0, NULL } |
468 | | }; |
469 | | |
470 | | static const value_string selfm_fmconfig_ai_sftype_vals[] = { |
471 | | { FM_CONFIG_ANA_SFTYPE_INT16, "16-Bit Integer" }, |
472 | | { FM_CONFIG_ANA_SFTYPE_FP, "IEEE Floating Point" }, |
473 | | { FM_CONFIG_ANA_SFTYPE_FPD, "IEEE Floating Point (Double)" }, |
474 | | { FM_CONFIG_ANA_SFTYPE_TS, "8-byte Time Stamp" }, |
475 | | { FM_CONFIG_ANA_SFTYPE_NONE, "None" }, |
476 | | { 0, NULL } |
477 | | }; |
478 | | |
479 | | static const value_string selfm_fmconfig_sfloc_vals[] = { |
480 | | { FM_CONFIG_SF_LOC_FM, "In Fast Meter Message" }, |
481 | | { FM_CONFIG_SF_LOC_CFG, "In Configuration Message" }, |
482 | | { 0, NULL } |
483 | | }; |
484 | | |
485 | | /* Depending on number of analog samples present in Fast Meter Messages, identification of data will change */ |
486 | | static const value_string selfm_fmconfig_numsamples1_vals[] = { |
487 | | { 1, "Magnitudes Only" }, |
488 | | { 0, NULL } |
489 | | }; |
490 | | |
491 | | static const value_string selfm_fmconfig_numsamples2_vals[] = { |
492 | | { 1, "Imaginary Components" }, |
493 | | { 2, "Real Components" }, |
494 | | { 0, NULL } |
495 | | }; |
496 | | |
497 | | static const value_string selfm_fmconfig_numsamples4_vals[] = { |
498 | | { 1, "1st Quarter Cycle Data" }, |
499 | | { 2, "2nd Quarter Cycle Data" }, |
500 | | { 3, "5th Quarter-Cycle Data" }, |
501 | | { 4, "6th Quarter-Cycle Data" }, |
502 | | { 0, NULL } |
503 | | }; |
504 | | |
505 | | /* Calculation Block lookup values */ |
506 | | static const value_string selfm_fmconfig_cblk_rot_vals[] = { |
507 | | { 0x00, "ABC Rotation" }, |
508 | | { 0x01, "ACB Rotation" }, |
509 | | { 0, NULL } |
510 | | }; |
511 | | |
512 | | static const value_string selfm_fmconfig_cblk_vconn_vals[] = { |
513 | | { 0x00, "Y-Connected" }, |
514 | | { 0x01, "Delta-Connected (in seq. Vab, Vbc, Vca)" }, |
515 | | { 0x02, "Delta-Connected (in seq. Vac, Vba, Vcb)" }, |
516 | | { 0, NULL } |
517 | | }; |
518 | | |
519 | | static const value_string selfm_fmconfig_cblk_iconn_vals[] = { |
520 | | { 0x00, "Y-Connected" }, |
521 | | { 0x01, "Delta-Connected (in seq. Iab, Ibc, Ica)" }, |
522 | | { 0x02, "Delta-Connected (in seq. Iac, Iba, Icb)" }, |
523 | | { 0, NULL } |
524 | | }; |
525 | | |
526 | | static const value_string selfm_fmconfig_cblk_ctype_vals[] = { |
527 | | { 0, "Standard Power Calculations" }, |
528 | | { 1, "2-1/2 Element Delta Power Calculation" }, |
529 | | { 2, "Voltages-Only" }, |
530 | | { 3, "Currents-Only" }, |
531 | | { 4, "Single-Phase Ia and Va Only" }, |
532 | | { 5, "Standard Power Calcs with 2 sets of Currents" }, |
533 | | { 6, "2-1/2 Element Delta Power Calcs with 2 sets of Currents" }, |
534 | | { 0, NULL } |
535 | | }; |
536 | | |
537 | | /* Fast Operate Remote Bit 'Pulse Supported' Lookup */ |
538 | | static const value_string selfm_foconfig_prb_supp_vals[] = { |
539 | | { 0x00, "No" }, |
540 | | { 0x01, "Yes" }, |
541 | | { 0, NULL } |
542 | | }; |
543 | | |
544 | | /* SER Status Value Lookup */ |
545 | | static const value_string selfm_ser_status_vals[] = { |
546 | | { 0x00, "Deasserted" }, |
547 | | { 0x01, "Asserted" }, |
548 | | { 0, NULL } |
549 | | }; |
550 | | |
551 | | /* Fast Operate Remote Bit Lookup */ |
552 | | static const value_string selfm_fo_rb_vals[] = { |
553 | | { 0x00, "RB01 Clear" }, |
554 | | { 0x01, "RB02 Clear" }, |
555 | | { 0x02, "RB03 Clear" }, |
556 | | { 0x03, "RB04 Clear" }, |
557 | | { 0x04, "RB05 Clear" }, |
558 | | { 0x05, "RB06 Clear" }, |
559 | | { 0x06, "RB07 Clear" }, |
560 | | { 0x07, "RB08 Clear" }, |
561 | | { 0x08, "RB09 Clear" }, |
562 | | { 0x09, "RB10 Clear" }, |
563 | | { 0x0A, "RB11 Clear" }, |
564 | | { 0x0B, "RB12 Clear" }, |
565 | | { 0x0C, "RB13 Clear" }, |
566 | | { 0x0D, "RB14 Clear" }, |
567 | | { 0x0E, "RB15 Clear" }, |
568 | | { 0x0F, "RB16 Clear" }, |
569 | | { 0x10, "RB17 Clear" }, |
570 | | { 0x11, "RB18 Clear" }, |
571 | | { 0x12, "RB19 Clear" }, |
572 | | { 0x13, "RB20 Clear" }, |
573 | | { 0x14, "RB21 Clear" }, |
574 | | { 0x15, "RB22 Clear" }, |
575 | | { 0x16, "RB23 Clear" }, |
576 | | { 0x17, "RB24 Clear" }, |
577 | | { 0x18, "RB25 Clear" }, |
578 | | { 0x19, "RB26 Clear" }, |
579 | | { 0x1A, "RB27 Clear" }, |
580 | | { 0x1B, "RB28 Clear" }, |
581 | | { 0x1C, "RB29 Clear" }, |
582 | | { 0x1D, "RB30 Clear" }, |
583 | | { 0x1E, "RB31 Clear" }, |
584 | | { 0x1F, "RB32 Clear" }, |
585 | | { 0x20, "RB01 Set" }, |
586 | | { 0x21, "RB02 Set" }, |
587 | | { 0x22, "RB03 Set" }, |
588 | | { 0x23, "RB04 Set" }, |
589 | | { 0x24, "RB05 Set" }, |
590 | | { 0x25, "RB06 Set" }, |
591 | | { 0x26, "RB07 Set" }, |
592 | | { 0x27, "RB08 Set" }, |
593 | | { 0x28, "RB09 Set" }, |
594 | | { 0x29, "RB10 Set" }, |
595 | | { 0x2A, "RB11 Set" }, |
596 | | { 0x2B, "RB12 Set" }, |
597 | | { 0x2C, "RB13 Set" }, |
598 | | { 0x2D, "RB14 Set" }, |
599 | | { 0x2E, "RB15 Set" }, |
600 | | { 0x2F, "RB16 Set" }, |
601 | | { 0x30, "RB17 Set" }, |
602 | | { 0x31, "RB18 Set" }, |
603 | | { 0x32, "RB19 Set" }, |
604 | | { 0x33, "RB20 Set" }, |
605 | | { 0x34, "RB21 Set" }, |
606 | | { 0x35, "RB22 Set" }, |
607 | | { 0x36, "RB23 Set" }, |
608 | | { 0x37, "RB24 Set" }, |
609 | | { 0x38, "RB25 Set" }, |
610 | | { 0x39, "RB26 Set" }, |
611 | | { 0x3A, "RB27 Set" }, |
612 | | { 0x3B, "RB28 Set" }, |
613 | | { 0x3C, "RB29 Set" }, |
614 | | { 0x3D, "RB30 Set" }, |
615 | | { 0x3E, "RB31 Set" }, |
616 | | { 0x3F, "RB32 Set" }, |
617 | | { 0x40, "RB01 Pulse" }, |
618 | | { 0x41, "RB02 Pulse" }, |
619 | | { 0x42, "RB03 Pulse" }, |
620 | | { 0x43, "RB04 Pulse" }, |
621 | | { 0x44, "RB05 Pulse" }, |
622 | | { 0x45, "RB06 Pulse" }, |
623 | | { 0x46, "RB07 Pulse" }, |
624 | | { 0x47, "RB08 Pulse" }, |
625 | | { 0x48, "RB09 Pulse" }, |
626 | | { 0x49, "RB10 Pulse" }, |
627 | | { 0x4A, "RB11 Pulse" }, |
628 | | { 0x4B, "RB12 Pulse" }, |
629 | | { 0x4C, "RB13 Pulse" }, |
630 | | { 0x4D, "RB14 Pulse" }, |
631 | | { 0x4E, "RB15 Pulse" }, |
632 | | { 0x4F, "RB16 Pulse" }, |
633 | | { 0x50, "RB17 Pulse" }, |
634 | | { 0x51, "RB18 Pulse" }, |
635 | | { 0x52, "RB19 Pulse" }, |
636 | | { 0x53, "RB20 Pulse" }, |
637 | | { 0x54, "RB21 Pulse" }, |
638 | | { 0x55, "RB22 Pulse" }, |
639 | | { 0x56, "RB23 Pulse" }, |
640 | | { 0x57, "RB24 Pulse" }, |
641 | | { 0x58, "RB25 Pulse" }, |
642 | | { 0x59, "RB26 Pulse" }, |
643 | | { 0x5A, "RB27 Pulse" }, |
644 | | { 0x5B, "RB28 Pulse" }, |
645 | | { 0x5C, "RB29 Pulse" }, |
646 | | { 0x5D, "RB30 Pulse" }, |
647 | | { 0x5E, "RB31 Pulse" }, |
648 | | { 0x5F, "RB32 Pulse" }, |
649 | | { 0, NULL } |
650 | | }; |
651 | | static value_string_ext selfm_fo_rb_vals_ext = VALUE_STRING_EXT_INIT(selfm_fo_rb_vals); |
652 | | |
653 | | /* Fast Operate Breaker Bit Lookup */ |
654 | | static const value_string selfm_fo_br_vals[] = { |
655 | | { 0x11, "Breaker Bit 1 Close (CC/CC1)" }, |
656 | | { 0x12, "Breaker Bit 2 Close (CC2)" }, |
657 | | { 0x13, "Breaker Bit 3 Close (CC3)" }, |
658 | | { 0x14, "Breaker Bit 4 Close (CC4)" }, |
659 | | { 0x15, "Breaker Bit 5 Close (CC5)" }, |
660 | | { 0x16, "Breaker Bit 6 Close (CC6)" }, |
661 | | { 0x17, "Breaker Bit 7 Close (CC7)" }, |
662 | | { 0x18, "Breaker Bit 8 Close (CC8)" }, |
663 | | { 0x19, "Breaker Bit 9 Close (CC9)" }, |
664 | | { 0x1A, "Breaker Bit 10 Close (CC10)" }, |
665 | | { 0x1B, "Breaker Bit 11 Close (CC11)" }, |
666 | | { 0x1C, "Breaker Bit 12 Close (CC12)" }, |
667 | | { 0x1D, "Breaker Bit 13 Close (CC13)" }, |
668 | | { 0x1E, "Breaker Bit 14 Close (CC14)" }, |
669 | | { 0x1F, "Breaker Bit 15 Close (CC15)" }, |
670 | | { 0x20, "Breaker Bit 16 Close (CC16)" }, |
671 | | { 0x21, "Breaker Bit 17 Close (CC17)" }, |
672 | | { 0x22, "Breaker Bit 18 Close (CC18)" }, |
673 | | { 0x31, "Breaker Bit 1 Open (OC/OC1)" }, |
674 | | { 0x32, "Breaker Bit 2 Open (OC2)" }, |
675 | | { 0x33, "Breaker Bit 3 Open (OC3)" }, |
676 | | { 0x34, "Breaker Bit 4 Open (OC4)" }, |
677 | | { 0x35, "Breaker Bit 5 Open (OC5)" }, |
678 | | { 0x36, "Breaker Bit 6 Open (OC6)" }, |
679 | | { 0x37, "Breaker Bit 7 Open (OC7)" }, |
680 | | { 0x38, "Breaker Bit 8 Open (OC8)" }, |
681 | | { 0x39, "Breaker Bit 9 Open (OC9)" }, |
682 | | { 0x3A, "Breaker Bit 10 Open (OC10)" }, |
683 | | { 0x3B, "Breaker Bit 11 Open (OC11)" }, |
684 | | { 0x3C, "Breaker Bit 12 Open (OC12)" }, |
685 | | { 0x3D, "Breaker Bit 13 Open (OC13)" }, |
686 | | { 0x3E, "Breaker Bit 14 Open (OC14)" }, |
687 | | { 0x3F, "Breaker Bit 15 Open (OC15)" }, |
688 | | { 0x40, "Breaker Bit 16 Open (OC16)" }, |
689 | | { 0x41, "Breaker Bit 17 Open (OC17)" }, |
690 | | { 0x42, "Breaker Bit 18 Open (OC18)" }, |
691 | | { 0, NULL } |
692 | | }; |
693 | | static value_string_ext selfm_fo_br_vals_ext = VALUE_STRING_EXT_INIT(selfm_fo_br_vals); |
694 | | |
695 | | /* Alternate Fast Operate Function Code Lookup */ |
696 | | static const value_string selfm_foconfig_alt_funccode_vals[] = { |
697 | | { 0xE5, "Open Breaker Bit" }, |
698 | | { 0xE6, "Close Breaker Bit" }, |
699 | | { 0xE7, "Set Remote Bit" }, |
700 | | { 0xE8, "Clear Remote Bit" }, |
701 | | { 0xE9, "Pulse Remote Bit" }, |
702 | | { 0x00, "Unsupported" }, |
703 | | { 0, NULL } |
704 | | }; |
705 | | |
706 | | /* Fast Message Function Codes */ |
707 | | static const value_string selfm_fastmsg_func_code_vals[] = { |
708 | | { FAST_MSG_CFG_BLOCK, "Fast Message Configuration Block Request" }, |
709 | | { FAST_MSG_EN_UNS_DATA, "Enable Unsolicited Data" }, |
710 | | { FAST_MSG_DIS_UNS_DATA, "Disable Unsolicited Data" }, |
711 | | { FAST_MSG_PING, "Ping Message" }, |
712 | | { FAST_MSG_READ_REQ, "Read Request" }, |
713 | | { FAST_MSG_GEN_UNS_DATA, "Generic Unsolicited Data" }, |
714 | | { FAST_MSG_SOE_STATE_REQ, "SOE Present State Request" }, |
715 | | { FAST_MSG_UNS_RESP, "Unsolicited Fast SER Data Response" }, |
716 | | { FAST_MSG_UNS_WRITE, "Unsolicited Write" }, |
717 | | { FAST_MSG_UNS_WRITE_REQ, "Unsolicited Write Request" }, |
718 | | { FAST_MSG_DEVDESC_REQ, "Device Description Request" }, |
719 | | { FAST_MSG_DATAFMT_REQ, "Data Format Request" }, |
720 | | { FAST_MSG_UNS_DATAFMT_RESP, "Unsolicited Data Format Response" }, |
721 | | { FAST_MSG_BITLABEL_REQ, "Bit Label Request" }, |
722 | | { FAST_MSG_MGMT_REQ, "Management Request" }, |
723 | | { FAST_MSG_CFG_BLOCK_RESP, "Fast Message Configuration Block Response" }, |
724 | | { FAST_MSG_EN_UNS_DATA_ACK, "Enable Unsolicited Data ACK" }, |
725 | | { FAST_MSG_DIS_UNS_DATA_ACK, "Disable Unsolicited Data ACK" }, |
726 | | { FAST_MSG_PING_ACK, "Ping Message ACK" }, |
727 | | { FAST_MSG_READ_RESP, "Read Response" }, |
728 | | { FAST_MSG_SOE_STATE_RESP, "SOE Present State Response" }, |
729 | | { FAST_MSG_UNS_RESP_ACK, "Unsolicited Fast SER Data Response ACK" }, |
730 | | { FAST_MSG_DEVDESC_RESP, "Device Description Response" }, |
731 | | { FAST_MSG_DATAFMT_RESP, "Data Format Response" }, |
732 | | { FAST_MSG_BITLABEL_RESP, "Bit Label Response" }, |
733 | | { 0, NULL } |
734 | | }; |
735 | | static value_string_ext selfm_fastmsg_func_code_vals_ext = |
736 | | VALUE_STRING_EXT_INIT(selfm_fastmsg_func_code_vals); |
737 | | |
738 | | static const value_string selfm_fastmsg_tagtype_vals[] = { |
739 | | { FAST_MSG_TAGTYPE_CHAR8, "1 x 8-bit character per item" }, |
740 | | { FAST_MSG_TAGTYPE_CHAR16, "2 x 8-bit characters per item" }, |
741 | | { FAST_MSG_TAGTYPE_DIGWORD8_BL, "8-bit binary item, with labels" }, |
742 | | { FAST_MSG_TAGTYPE_DIGWORD8, "8-bit binary item, without labels" }, |
743 | | { FAST_MSG_TAGTYPE_DIGWORD16_BL, "16-bit binary item, with labels" }, |
744 | | { FAST_MSG_TAGTYPE_DIGWORD16, "16-bit binary item, without labels" }, |
745 | | { FAST_MSG_TAGTYPE_INT16, "16-bit Signed Integer" }, |
746 | | { FAST_MSG_TAGTYPE_UINT16, "16-bit Unsigned Integer" }, |
747 | | { FAST_MSG_TAGTYPE_INT32, "32-bit Signed Integer" }, |
748 | | { FAST_MSG_TAGTYPE_UINT32, "32-bit Unsigned Integer" }, |
749 | | { FAST_MSG_TAGTYPE_FLOAT, "IEEE Floating Point" }, |
750 | | { 0, NULL } |
751 | | }; |
752 | | |
753 | | /* Fast Message ACK Response Codes */ |
754 | | static const value_string selfm_fastmsg_ack_responsecode_vals[] = { |
755 | | { 0x0, "Success" }, |
756 | | { 0x1, "Function code not recognized" }, |
757 | | { 0x2, "Function code supported but disabled" }, |
758 | | { 0x3, "Invalid Data Address" }, |
759 | | { 0x4, "Bad Data" }, |
760 | | { 0x5, "Insufficient Memory" }, |
761 | | { 0x6, "Busy" }, |
762 | | { 0, NULL } |
763 | | }; |
764 | | |
765 | | static value_string_ext selfm_fastmsg_ack_responsecode_vals_ext = |
766 | | VALUE_STRING_EXT_INIT(selfm_fastmsg_ack_responsecode_vals); |
767 | | |
768 | | /* Fast Message Unsolicited Write COM Port Codes */ |
769 | | static const value_string selfm_fastmsg_unswrite_com_vals[] = { |
770 | | { 0x0100, "COM01" }, |
771 | | { 0x0200, "COM02" }, |
772 | | { 0x0300, "COM03" }, |
773 | | { 0x0400, "COM04" }, |
774 | | { 0x0500, "COM05" }, |
775 | | { 0x0600, "COM06" }, |
776 | | { 0x0700, "COM07" }, |
777 | | { 0x0800, "COM08" }, |
778 | | { 0x0900, "COM09" }, |
779 | | { 0x0A00, "COM10" }, |
780 | | { 0x0B00, "COM11" }, |
781 | | { 0x0C00, "COM12" }, |
782 | | { 0x0D00, "COM13" }, |
783 | | { 0x0E00, "COM14" }, |
784 | | { 0x0F00, "COM15" }, |
785 | | { 0, NULL } |
786 | | }; |
787 | | static value_string_ext selfm_fastmsg_unswrite_com_vals_ext = |
788 | | VALUE_STRING_EXT_INIT(selfm_fastmsg_unswrite_com_vals); |
789 | | |
790 | | /* Tables for reassembly of fragments. */ |
791 | | static reassembly_table selfm_reassembly_table; |
792 | | |
793 | | /* ************************************************************************* */ |
794 | | /* Header values for reassembly */ |
795 | | /* ************************************************************************* */ |
796 | | static int hf_selfm_fragment; |
797 | | static int hf_selfm_fragments; |
798 | | static int hf_selfm_fragment_overlap; |
799 | | static int hf_selfm_fragment_overlap_conflict; |
800 | | static int hf_selfm_fragment_multiple_tails; |
801 | | static int hf_selfm_fragment_too_long_fragment; |
802 | | static int hf_selfm_fragment_error; |
803 | | static int hf_selfm_fragment_count; |
804 | | static int hf_selfm_fragment_reassembled_in; |
805 | | static int hf_selfm_fragment_reassembled_length; |
806 | | static int ett_selfm_fragment; |
807 | | static int ett_selfm_fragments; |
808 | | |
809 | | static const fragment_items selfm_frag_items = { |
810 | | &ett_selfm_fragment, |
811 | | &ett_selfm_fragments, |
812 | | &hf_selfm_fragments, |
813 | | &hf_selfm_fragment, |
814 | | &hf_selfm_fragment_overlap, |
815 | | &hf_selfm_fragment_overlap_conflict, |
816 | | &hf_selfm_fragment_multiple_tails, |
817 | | &hf_selfm_fragment_too_long_fragment, |
818 | | &hf_selfm_fragment_error, |
819 | | &hf_selfm_fragment_count, |
820 | | &hf_selfm_fragment_reassembled_in, |
821 | | &hf_selfm_fragment_reassembled_length, |
822 | | /* Reassembled data field */ |
823 | | NULL, |
824 | | "SEL Fast Message fragments" |
825 | | }; |
826 | | |
827 | | /**********************************************************************************************************/ |
828 | | /* Clean all instances of 0xFFFF from Telnet payload to compensate for IAC control code (replace w/ 0xFF) */ |
829 | | /* Function Duplicated from packet-telnet.c (unescape_and_tvbuffify_telnet_option) */ |
830 | | /**********************************************************************************************************/ |
831 | | static tvbuff_t * |
832 | | clean_telnet_iac(packet_info *pinfo, tvbuff_t *tvb, int offset, int len, int *num_skip_byte) |
833 | 0 | { |
834 | 0 | tvbuff_t *telnet_tvb; |
835 | 0 | uint8_t *buf; |
836 | 0 | const uint8_t *spos; |
837 | 0 | uint8_t *dpos; |
838 | 0 | int len_remaining, skip_byte = 0; |
839 | |
|
840 | 0 | spos=tvb_get_ptr(tvb, offset, len); |
841 | 0 | buf=(uint8_t *)wmem_alloc(pinfo->pool, len); |
842 | 0 | dpos=buf; |
843 | 0 | len_remaining = len; |
844 | 0 | while(len_remaining > 0){ |
845 | | |
846 | | /* Only analyze two sequential bytes of source tvb if we have at least two bytes left */ |
847 | 0 | if (len_remaining > 1) { |
848 | | /* If two sequential 0xFF's exist, increment skip_byte counter, decrement */ |
849 | | /* len_remaining by 2 and copy a single 0xFF to dest tvb. */ |
850 | 0 | if((spos[0]==0xff) && (spos[1]==0xff)){ |
851 | 0 | skip_byte++; |
852 | 0 | len_remaining -= 2; |
853 | 0 | *(dpos++)=0xff; |
854 | 0 | spos+=2; |
855 | 0 | continue; |
856 | 0 | } |
857 | 0 | } |
858 | | /* If we only have a single byte left, or there were no sequential 0xFF's, copy byte from src tvb to dest tvb */ |
859 | 0 | *(dpos++)=*(spos++); |
860 | 0 | len_remaining--; |
861 | 0 | } |
862 | 0 | telnet_tvb = tvb_new_child_real_data(tvb, buf, len-skip_byte, len-skip_byte); |
863 | 0 | add_new_data_source(pinfo, telnet_tvb, "Processed Telnet Data"); |
864 | |
|
865 | 0 | *num_skip_byte = skip_byte; |
866 | |
|
867 | 0 | return telnet_tvb; |
868 | 0 | } |
869 | | |
870 | | /* Names are copied from the packet into fixed buffers and shown in item |
871 | | * labels, which must be valid UTF-8: replace any octet that is not ASCII. */ |
872 | | static void |
873 | | selfm_ascii_name(char *name) |
874 | 0 | { |
875 | 0 | for (; *name != '\0'; name++) { |
876 | 0 | if ((unsigned char)*name >= 0x80) { |
877 | 0 | *name = '?'; |
878 | 0 | } |
879 | 0 | } |
880 | 0 | } |
881 | | |
882 | | /******************************************************************************************************/ |
883 | | /* Execute dissection of Fast Meter configuration frames independent of any GUI access of said frames */ |
884 | | /* Load configuration information into fm_config_frame struct */ |
885 | | /******************************************************************************************************/ |
886 | | static fm_config_frame* fmconfig_frame_fast(tvbuff_t *tvb) |
887 | 0 | { |
888 | | /* Set up structures needed to add the protocol subtree and manage it */ |
889 | 0 | unsigned count, offset = 0; |
890 | 0 | fm_config_frame *frame; |
891 | | |
892 | | /* get a new frame and initialize it */ |
893 | 0 | frame = wmem_new(wmem_file_scope(), fm_config_frame); |
894 | | |
895 | | /* Get data packet setup information from config message and copy into ai_info (if required) */ |
896 | 0 | frame->cfg_cmd = tvb_get_ntohs(tvb, offset); |
897 | | /* skip length byte, position offset+2 */ |
898 | 0 | frame->num_flags = tvb_get_uint8(tvb, offset+3); |
899 | 0 | frame->sf_loc = tvb_get_uint8(tvb, offset+4); |
900 | 0 | frame->sf_num = tvb_get_uint8(tvb, offset+5); |
901 | 0 | frame->num_ai = tvb_get_uint8(tvb, offset+6); |
902 | 0 | frame->num_ai_samples = tvb_get_uint8(tvb, offset+7); |
903 | 0 | frame->num_dig = tvb_get_uint8(tvb, offset+8); |
904 | 0 | frame->num_calc = tvb_get_uint8(tvb, offset+9); |
905 | | |
906 | | /* Update offset pointer */ |
907 | 0 | offset += 10; |
908 | | |
909 | | /* Get data packet analog/timestamp/digital offsets and copy into ai_info */ |
910 | 0 | frame->offset_ai = tvb_get_ntohs(tvb, offset); |
911 | 0 | frame->offset_ts = tvb_get_ntohs(tvb, offset+2); |
912 | 0 | frame->offset_dig = tvb_get_ntohs(tvb, offset+4); |
913 | | |
914 | | /* Update offset pointer */ |
915 | 0 | offset += 6; |
916 | |
|
917 | 0 | frame->analogs = (fm_analog_info *)wmem_alloc(wmem_file_scope(), frame->num_ai * sizeof(fm_analog_info)); |
918 | | |
919 | | /* Get AI Channel Details and copy into ai_info */ |
920 | 0 | for (count = 0; count < frame->num_ai; count++) { |
921 | 0 | fm_analog_info *analog = &(frame->analogs[count]); |
922 | 0 | tvb_memcpy(tvb, analog->name, offset, FM_CONFIG_ANA_CHNAME_LEN); |
923 | 0 | analog->name[FM_CONFIG_ANA_CHNAME_LEN] = '\0'; /* Put a terminating null onto the end of the AI Channel name */ |
924 | 0 | selfm_ascii_name(analog->name); |
925 | 0 | analog->type = tvb_get_uint8(tvb, offset+6); |
926 | 0 | analog->sf_type = tvb_get_uint8(tvb, offset+7); |
927 | 0 | analog->sf_offset = tvb_get_ntohs(tvb, offset+8); |
928 | | |
929 | | /* If Scale Factors are present in the cfg message, retrieve and store them per analog */ |
930 | | /* Otherwise, default to Scale Factor of 1 for now */ |
931 | 0 | if (frame->sf_loc == FM_CONFIG_SF_LOC_CFG) { |
932 | 0 | analog->sf_fp = tvb_get_ntohieee_float(tvb, analog->sf_offset); |
933 | 0 | } |
934 | 0 | else { |
935 | 0 | analog->sf_fp = 1; |
936 | 0 | } |
937 | |
|
938 | 0 | offset += 10; |
939 | 0 | } |
940 | |
|
941 | 0 | return frame; |
942 | |
|
943 | 0 | } |
944 | | |
945 | | /******************************************************************************************************/ |
946 | | /* Execute dissection of Data Item definition info before loading GUI tree */ |
947 | | /* Load configuration information into fastmsg_dataitem struct */ |
948 | | /******************************************************************************************************/ |
949 | | static fastmsg_dataitem* fastmsg_dataitem_save(tvbuff_t *tvb, int offset) |
950 | 0 | { |
951 | 0 | fastmsg_dataitem *dataitem; |
952 | | |
953 | | /* get a new dataitem and initialize it */ |
954 | 0 | dataitem = wmem_new(wmem_file_scope(), fastmsg_dataitem); |
955 | | |
956 | | /* retrieve data item name and terminate with a null */ |
957 | 0 | tvb_memcpy(tvb, dataitem->name, offset, 10); |
958 | 0 | dataitem->name[10] = '\0'; /* Put a terminating null onto the end of the string */ |
959 | 0 | selfm_ascii_name(dataitem->name); |
960 | | |
961 | | /* retrieve data item quantity and type */ |
962 | 0 | dataitem->quantity = tvb_get_ntohs(tvb, offset+10); |
963 | 0 | dataitem->data_type = tvb_get_ntohs(tvb, offset+12); |
964 | |
|
965 | 0 | return dataitem; |
966 | |
|
967 | 0 | } |
968 | | |
969 | | /******************************************************************************************************/ |
970 | | /* Execute dissection of Data Region definition info before loading GUI tree */ |
971 | | /* Load configuration information into fastmsg_dataregion struct */ |
972 | | /******************************************************************************************************/ |
973 | | static fastmsg_dataregion* fastmsg_dataregion_save(tvbuff_t *tvb, int offset) |
974 | 0 | { |
975 | 0 | fastmsg_dataregion *dataregion; |
976 | | |
977 | | /* get a new dataregion and initialize it */ |
978 | 0 | dataregion = wmem_new(wmem_file_scope(), fastmsg_dataregion); |
979 | | |
980 | | /* retrieve data region name and terminate with a null */ |
981 | 0 | tvb_memcpy(tvb, dataregion->name, offset, 10); |
982 | 0 | dataregion->name[10] = '\0'; /* Put a terminating null onto the end of the string */ |
983 | 0 | selfm_ascii_name(dataregion->name); |
984 | |
|
985 | 0 | return dataregion; |
986 | |
|
987 | 0 | } |
988 | | |
989 | | /********************************************************************************************************/ |
990 | | /* Lookup region name using current base address & saved conversation data. Return ptr to char string */ |
991 | | /********************************************************************************************************/ |
992 | | static const char* |
993 | | region_lookup(packet_info *pinfo, uint32_t base_addr) |
994 | 0 | { |
995 | 0 | fm_conversation *conv; |
996 | 0 | fastmsg_dataregion *dataregion = NULL; |
997 | |
|
998 | 0 | conv = (fm_conversation *)p_get_proto_data(wmem_file_scope(), pinfo, proto_selfm, 0); |
999 | 0 | if (conv) { |
1000 | 0 | dataregion = (fastmsg_dataregion*)wmem_tree_lookup32(conv->fastmsg_dataregions, base_addr); |
1001 | 0 | } |
1002 | |
|
1003 | 0 | if (dataregion) { |
1004 | 0 | return dataregion->name; |
1005 | 0 | } |
1006 | | |
1007 | | /* If we couldn't identify the region using the current base address, return a default string */ |
1008 | 0 | return "Unknown Region"; |
1009 | 0 | } |
1010 | | |
1011 | | /***********************************************************************************************************/ |
1012 | | /* Create Fast SER Unsolicited Word Bit item. Return item to calling function. 'index' parameter */ |
1013 | | /* will be used to store 'name' parameter in lookup tree. Index 254 and 255 are special (hardcoded) cases */ |
1014 | | /***********************************************************************************************************/ |
1015 | | static fastser_uns_wordbit* fastser_uns_wordbit_save(uint8_t idx, const char *name) |
1016 | 0 | { |
1017 | 0 | fastser_uns_wordbit *wordbit_item; |
1018 | | |
1019 | | /* get a new wordbit_item and initialize it */ |
1020 | 0 | wordbit_item = wmem_new(wmem_file_scope(), fastser_uns_wordbit); |
1021 | |
|
1022 | 0 | if (idx <= 253) { |
1023 | 0 | wordbit_item->name = wmem_strdup(wmem_file_scope(), name); |
1024 | 0 | } |
1025 | |
|
1026 | 0 | if (idx == 254) { |
1027 | 0 | wordbit_item->name = wmem_strdup(wmem_file_scope(), "POWER_UP"); |
1028 | 0 | } |
1029 | |
|
1030 | 0 | if (idx == 255) { |
1031 | 0 | wordbit_item->name = wmem_strdup(wmem_file_scope(), "SET_CHNG"); |
1032 | 0 | } |
1033 | |
|
1034 | 0 | return wordbit_item; |
1035 | |
|
1036 | 0 | } |
1037 | | |
1038 | | /***************************************************************************************************************/ |
1039 | | /* Lookup uns wordbit name using current index position & saved conversation data. Return ptr to char string */ |
1040 | | /***************************************************************************************************************/ |
1041 | | static const char* |
1042 | | fastser_uns_wordbit_lookup(packet_info *pinfo, uint8_t idx) |
1043 | 0 | { |
1044 | 0 | fm_conversation *conv; |
1045 | 0 | fastser_uns_wordbit *wordbit = NULL; |
1046 | |
|
1047 | 0 | conv = (fm_conversation *)p_get_proto_data(wmem_file_scope(), pinfo, proto_selfm, 0); |
1048 | |
|
1049 | 0 | if (conv) { |
1050 | 0 | wordbit = (fastser_uns_wordbit*)wmem_tree_lookup32(conv->fastser_uns_wordbits, idx); |
1051 | 0 | } |
1052 | |
|
1053 | 0 | if (wordbit) { |
1054 | 0 | return wordbit->name; |
1055 | 0 | } |
1056 | | |
1057 | | /* If we couldn't identify the bit using the index, return a default string */ |
1058 | 0 | return "Unknown"; |
1059 | |
|
1060 | 0 | } |
1061 | | |
1062 | | /******************************************************************************************************/ |
1063 | | /* Code to Dissect Relay Definition Frames */ |
1064 | | /******************************************************************************************************/ |
1065 | | static int |
1066 | | dissect_relaydef_frame(tvbuff_t *tvb, proto_tree *tree, int offset) |
1067 | 0 | { |
1068 | | /* Set up structures needed to add the protocol subtree and manage it */ |
1069 | 0 | proto_item *relaydef_fm_item, *relaydef_flags_item, *relaydef_proto_item; |
1070 | 0 | proto_tree *relaydef_tree, *relaydef_fm_tree, *relaydef_flags_tree, *relaydef_proto_tree; |
1071 | 0 | uint8_t len, num_proto, num_fm, num_flags; |
1072 | 0 | int count; |
1073 | |
|
1074 | 0 | len = tvb_get_uint8(tvb, offset); |
1075 | 0 | num_proto = tvb_get_uint8(tvb, offset+1); |
1076 | 0 | num_fm = tvb_get_uint8(tvb, offset+2); |
1077 | 0 | num_flags = tvb_get_uint8(tvb, offset+3); |
1078 | | |
1079 | | /* Add items to protocol tree specific to Relay Definition Block */ |
1080 | 0 | relaydef_tree = proto_tree_add_subtree(tree, tvb, offset, len-2, ett_selfm_relaydef, NULL, "Relay Definition Block Details"); |
1081 | | |
1082 | | /* Reported length */ |
1083 | 0 | proto_tree_add_item(relaydef_tree, hf_selfm_relaydef_len, tvb, offset, 1, ENC_BIG_ENDIAN); |
1084 | | |
1085 | | /* Reported Number of Protocols Supported */ |
1086 | 0 | relaydef_proto_item = proto_tree_add_item(relaydef_tree, hf_selfm_relaydef_numproto, tvb, offset+1, 1, ENC_BIG_ENDIAN); |
1087 | 0 | relaydef_proto_tree = proto_item_add_subtree(relaydef_proto_item, ett_selfm_relaydef_proto); |
1088 | | |
1089 | | /* Reported Number of Fast Meter Commands Supported */ |
1090 | 0 | relaydef_fm_item = proto_tree_add_item(relaydef_tree, hf_selfm_relaydef_numfm, tvb, offset+2, 1, ENC_BIG_ENDIAN); |
1091 | 0 | relaydef_fm_tree = proto_item_add_subtree(relaydef_fm_item, ett_selfm_relaydef_fm); |
1092 | | |
1093 | | /* Reported Number of Status Bit Flags Supported */ |
1094 | 0 | relaydef_flags_item = proto_tree_add_item(relaydef_tree, hf_selfm_relaydef_numflags, tvb, offset+3, 1, ENC_BIG_ENDIAN); |
1095 | 0 | relaydef_flags_tree = proto_item_add_subtree(relaydef_flags_item, ett_selfm_relaydef_flags); |
1096 | | |
1097 | | /* Get our offset up-to-date */ |
1098 | 0 | offset += 4; |
1099 | | |
1100 | | /* Add each reported Fast Meter cfg/data message */ |
1101 | 0 | for (count = 1; count <= num_fm; count++) { |
1102 | 0 | proto_tree_add_item(relaydef_fm_tree, hf_selfm_relaydef_fmcfg_cmd, tvb, offset, 2, ENC_BIG_ENDIAN); |
1103 | 0 | proto_tree_add_item(relaydef_fm_tree, hf_selfm_relaydef_fmdata_cmd, tvb, offset+2, 2, ENC_BIG_ENDIAN); |
1104 | 0 | offset += 4; |
1105 | 0 | } |
1106 | | |
1107 | | /* Add each reported status bit flag, along with corresponding response command */ |
1108 | 0 | for (count = 1; count <= num_flags; count++) { |
1109 | 0 | proto_tree_add_item(relaydef_flags_tree, hf_selfm_relaydef_statbit, tvb, offset, 2, ENC_BIG_ENDIAN); |
1110 | 0 | proto_tree_add_item(relaydef_flags_tree, hf_selfm_relaydef_statbit_cmd, tvb, offset+2, 6, ENC_NA); |
1111 | 0 | offset += 8; |
1112 | 0 | } |
1113 | | |
1114 | | /* Add each supported protocol */ |
1115 | 0 | for (count = 1; count <= num_proto; count++) { |
1116 | 0 | proto_tree_add_item(relaydef_proto_tree, hf_selfm_relaydef_proto, tvb, offset, 2, ENC_BIG_ENDIAN); |
1117 | 0 | offset += 2; |
1118 | 0 | } |
1119 | | |
1120 | | /* Add Pad byte (if present) and checksum */ |
1121 | 0 | if (tvb_reported_length_remaining(tvb, offset) > 1) { |
1122 | 0 | proto_tree_add_item(relaydef_tree, hf_selfm_padbyte, tvb, offset, 1, ENC_BIG_ENDIAN); |
1123 | 0 | offset += 1; |
1124 | 0 | } |
1125 | |
|
1126 | 0 | proto_tree_add_checksum(relaydef_tree, tvb, offset, hf_selfm_checksum, -1, NULL, NULL, 0, ENC_BIG_ENDIAN, PROTO_CHECKSUM_NO_FLAGS); |
1127 | 0 | offset += 1; |
1128 | |
|
1129 | 0 | return offset; |
1130 | 0 | } |
1131 | | |
1132 | | /******************************************************************************************************/ |
1133 | | /* Code to dissect Fast Meter Configuration Frames */ |
1134 | | /******************************************************************************************************/ |
1135 | | static int |
1136 | | dissect_fmconfig_frame(tvbuff_t *tvb, proto_tree *tree, packet_info *pinfo, int offset) |
1137 | 0 | { |
1138 | | /* Set up structures needed to add the protocol subtree and manage it */ |
1139 | 0 | proto_tree *fmconfig_tree, *fmconfig_ai_tree=NULL, *fmconfig_calc_tree=NULL; |
1140 | 0 | unsigned count; |
1141 | 0 | uint8_t len, sf_loc, num_sf, num_ai, num_calc; |
1142 | 0 | char* ai_name; |
1143 | |
|
1144 | 0 | len = tvb_get_uint8(tvb, offset); |
1145 | | /* skip num_flags, position offset+1 */ |
1146 | 0 | sf_loc = tvb_get_uint8(tvb, offset+2); |
1147 | 0 | num_sf = tvb_get_uint8(tvb, offset+3); |
1148 | 0 | num_ai = tvb_get_uint8(tvb, offset+4); |
1149 | | /* skip num_samp, position offset+5 */ |
1150 | | /* skip num_dig, position offset+6 */ |
1151 | 0 | num_calc = tvb_get_uint8(tvb, offset+7); |
1152 | |
|
1153 | 0 | fmconfig_tree = proto_tree_add_subtree(tree, tvb, offset, len-2, ett_selfm_fmconfig, NULL, "Fast Meter Configuration Details"); |
1154 | | |
1155 | | /* Add items to protocol tree specific to Fast Meter Configuration Block */ |
1156 | | |
1157 | | /* Get Setup Information for FM Config Block */ |
1158 | 0 | proto_tree_add_item(fmconfig_tree, hf_selfm_fmconfig_len, tvb, offset, 1, ENC_BIG_ENDIAN); |
1159 | 0 | proto_tree_add_item(fmconfig_tree, hf_selfm_fmconfig_numflags, tvb, offset+1, 1, ENC_BIG_ENDIAN); |
1160 | 0 | proto_tree_add_item(fmconfig_tree, hf_selfm_fmconfig_loc_sf, tvb, offset+2, 1, ENC_BIG_ENDIAN); |
1161 | 0 | proto_tree_add_item(fmconfig_tree, hf_selfm_fmconfig_num_sf, tvb, offset+3, 1, ENC_BIG_ENDIAN); |
1162 | 0 | proto_tree_add_item(fmconfig_tree, hf_selfm_fmconfig_num_ai, tvb, offset+4, 1, ENC_BIG_ENDIAN); |
1163 | 0 | proto_tree_add_item(fmconfig_tree, hf_selfm_fmconfig_num_samp, tvb, offset+5, 1, ENC_BIG_ENDIAN); |
1164 | 0 | proto_tree_add_item(fmconfig_tree, hf_selfm_fmconfig_num_dig, tvb, offset+6, 1, ENC_BIG_ENDIAN); |
1165 | 0 | proto_tree_add_item(fmconfig_tree, hf_selfm_fmconfig_num_calc, tvb, offset+7, 1, ENC_BIG_ENDIAN); |
1166 | | |
1167 | | /* Update offset pointer */ |
1168 | 0 | offset += 8; |
1169 | | |
1170 | | /* Add data packet offsets to tree and update offset pointer */ |
1171 | 0 | proto_tree_add_item(fmconfig_tree, hf_selfm_fmconfig_ofs_ai, tvb, offset, 2, ENC_BIG_ENDIAN); |
1172 | 0 | proto_tree_add_item(fmconfig_tree, hf_selfm_fmconfig_ofs_ts, tvb, offset+2, 2, ENC_BIG_ENDIAN); |
1173 | 0 | proto_tree_add_item(fmconfig_tree, hf_selfm_fmconfig_ofs_dig, tvb, offset+4, 2, ENC_BIG_ENDIAN); |
1174 | 0 | offset += 6; |
1175 | | |
1176 | | /* Get AI Channel Details */ |
1177 | 0 | for (count = 0; count < num_ai; count++) { |
1178 | 0 | ai_name = (char*)tvb_get_string_enc(pinfo->pool, tvb, offset, 6, ENC_ASCII); |
1179 | |
|
1180 | 0 | fmconfig_ai_tree = proto_tree_add_subtree_format(fmconfig_tree, tvb, offset, 10, |
1181 | 0 | ett_selfm_fmconfig_ai, NULL, "Analog Channel: %s", ai_name); |
1182 | | |
1183 | | /* Add Channel Name, Channel Data Type, Scale Factor Type and Scale Factor Offset to tree */ |
1184 | 0 | proto_tree_add_item(fmconfig_ai_tree, hf_selfm_fmconfig_ai_channel, tvb, offset, 6, ENC_ASCII); |
1185 | 0 | proto_tree_add_item(fmconfig_ai_tree, hf_selfm_fmconfig_ai_type, tvb, offset+6, 1, ENC_BIG_ENDIAN); |
1186 | 0 | proto_tree_add_item(fmconfig_ai_tree, hf_selfm_fmconfig_ai_sf_type, tvb, offset+7, 1, ENC_BIG_ENDIAN); |
1187 | 0 | proto_tree_add_item(fmconfig_ai_tree, hf_selfm_fmconfig_ai_sf_ofs, tvb, offset+8, 2, ENC_BIG_ENDIAN); |
1188 | | |
1189 | | /* Update Offset Pointer */ |
1190 | 0 | offset += 10; |
1191 | 0 | } |
1192 | | |
1193 | | /* 14-byte Calculation block instances based on num_calc */ |
1194 | 0 | for (count = 0; count < num_calc; count++) { |
1195 | 0 | fmconfig_calc_tree = proto_tree_add_subtree_format(fmconfig_tree, tvb, offset, 14, |
1196 | 0 | ett_selfm_fmconfig_calc, NULL, "Calculation Block: %d", count+1); |
1197 | | |
1198 | | /* Rotation, Voltage Connection and Current Connection are all bit-masked on the same byte */ |
1199 | 0 | proto_tree_add_item(fmconfig_calc_tree, hf_selfm_fmconfig_cblk_rot, tvb, offset, 1, ENC_BIG_ENDIAN); |
1200 | 0 | proto_tree_add_item(fmconfig_calc_tree, hf_selfm_fmconfig_cblk_vconn, tvb, offset, 1, ENC_BIG_ENDIAN); |
1201 | 0 | proto_tree_add_item(fmconfig_calc_tree, hf_selfm_fmconfig_cblk_iconn, tvb, offset, 1, ENC_BIG_ENDIAN); |
1202 | |
|
1203 | 0 | proto_tree_add_item(fmconfig_calc_tree, hf_selfm_fmconfig_cblk_ctype, tvb, offset+1, 1, ENC_BIG_ENDIAN); |
1204 | 0 | proto_tree_add_item(fmconfig_calc_tree, hf_selfm_fmconfig_cblk_deskew_ofs, tvb, offset+2, 2, ENC_BIG_ENDIAN); |
1205 | 0 | proto_tree_add_item(fmconfig_calc_tree, hf_selfm_fmconfig_cblk_rs_ofs, tvb, offset+4, 2, ENC_BIG_ENDIAN); |
1206 | 0 | proto_tree_add_item(fmconfig_calc_tree, hf_selfm_fmconfig_cblk_xs_ofs, tvb, offset+6, 2, ENC_BIG_ENDIAN); |
1207 | 0 | proto_tree_add_item(fmconfig_calc_tree, hf_selfm_fmconfig_cblk_ia_idx, tvb, offset+8, 1, ENC_BIG_ENDIAN); |
1208 | 0 | proto_tree_add_item(fmconfig_calc_tree, hf_selfm_fmconfig_cblk_ib_idx, tvb, offset+9, 1, ENC_BIG_ENDIAN); |
1209 | 0 | proto_tree_add_item(fmconfig_calc_tree, hf_selfm_fmconfig_cblk_ic_idx, tvb, offset+10, 1, ENC_BIG_ENDIAN); |
1210 | 0 | proto_tree_add_item(fmconfig_calc_tree, hf_selfm_fmconfig_cblk_va_idx, tvb, offset+11, 1, ENC_BIG_ENDIAN); |
1211 | 0 | proto_tree_add_item(fmconfig_calc_tree, hf_selfm_fmconfig_cblk_vb_idx, tvb, offset+12, 1, ENC_BIG_ENDIAN); |
1212 | 0 | proto_tree_add_item(fmconfig_calc_tree, hf_selfm_fmconfig_cblk_vc_idx, tvb, offset+13, 1, ENC_BIG_ENDIAN); |
1213 | |
|
1214 | 0 | offset += 14; |
1215 | 0 | } |
1216 | | |
1217 | | /* Add Config Message Scale Factor(s) (if present) */ |
1218 | 0 | if ((num_sf != 0) && (sf_loc == FM_CONFIG_SF_LOC_CFG)) { |
1219 | 0 | for (count = 0; count < num_sf; count++) { |
1220 | 0 | proto_tree_add_item(fmconfig_tree, hf_selfm_fmconfig_ai_sf_float, tvb, offset, 4, ENC_BIG_ENDIAN); |
1221 | 0 | offset += 4; |
1222 | 0 | } |
1223 | 0 | } |
1224 | | |
1225 | | /* Add Pad byte (if present) and checksum */ |
1226 | 0 | if (tvb_reported_length_remaining(tvb, offset) > 1) { |
1227 | 0 | proto_tree_add_item(fmconfig_tree, hf_selfm_padbyte, tvb, offset, 1, ENC_BIG_ENDIAN); |
1228 | 0 | offset += 1; |
1229 | 0 | } |
1230 | |
|
1231 | 0 | proto_tree_add_checksum(fmconfig_tree, tvb, offset, hf_selfm_checksum, -1, NULL, NULL, 0, ENC_BIG_ENDIAN, PROTO_CHECKSUM_NO_FLAGS); |
1232 | 0 | offset += 1; |
1233 | |
|
1234 | 0 | return offset; |
1235 | |
|
1236 | 0 | } |
1237 | | |
1238 | | /******************************************************************************************************/ |
1239 | | /* Code to dissect Fast Meter Data Frames */ |
1240 | | /* Formatting depends heavily on previously-encountered Configuration Frames so search array instances for them */ |
1241 | | /******************************************************************************************************/ |
1242 | | static int |
1243 | | dissect_fmdata_frame(tvbuff_t *tvb, proto_tree *tree, packet_info *pinfo, int offset, uint16_t config_cmd_match) |
1244 | 0 | { |
1245 | | /* Set up structures needed to add the protocol subtree and manage it */ |
1246 | 0 | proto_item *fmdata_item, *fmdata_dig_ch_item; |
1247 | 0 | proto_item *fmdata_ai_sf_item; |
1248 | 0 | proto_tree *fmdata_tree, *fmdata_ai_tree=NULL, *fmdata_dig_tree=NULL, *fmdata_ai_ch_tree=NULL, *fmdata_dig_ch_tree=NULL; |
1249 | 0 | uint8_t len, j=0; |
1250 | 0 | uint16_t config_cmd; |
1251 | 0 | int16_t ai_int16val; |
1252 | 0 | int cnt = 0, ch_size=0; |
1253 | 0 | float ai_sf_fp; |
1254 | 0 | bool config_found = false; |
1255 | 0 | fm_conversation *conv; |
1256 | 0 | fm_config_frame *cfg_data = NULL; |
1257 | 0 | nstime_t datetime; |
1258 | 0 | struct tm tm; |
1259 | |
|
1260 | 0 | len = tvb_get_uint8(tvb, offset); |
1261 | |
|
1262 | 0 | fmdata_tree = proto_tree_add_subtree_format(tree, tvb, offset, len-2, ett_selfm_fmdata, &fmdata_item, "Fast Meter Data Details"); |
1263 | | |
1264 | | /* Reported length */ |
1265 | 0 | proto_tree_add_item(fmdata_tree, hf_selfm_fmdata_len, tvb, offset, 1, ENC_BIG_ENDIAN); |
1266 | 0 | offset += 1; |
1267 | | |
1268 | | /* Search for previously-encountered Configuration information to dissect the frame */ |
1269 | 0 | { |
1270 | 0 | conv = (fm_conversation *)p_get_proto_data(wmem_file_scope(), pinfo, proto_selfm, 0); |
1271 | |
|
1272 | 0 | if (conv) { |
1273 | 0 | wmem_list_frame_t *frame = wmem_list_head(conv->fm_config_frames); |
1274 | | /* Cycle through possible instances of multiple fm_config_data_blocks, looking for match */ |
1275 | 0 | while (frame && !config_found) { |
1276 | 0 | cfg_data = (fm_config_frame *)wmem_list_frame_data(frame); |
1277 | 0 | config_cmd = cfg_data->cfg_cmd; |
1278 | | |
1279 | | /* If the stored config_cmd matches the expected one we are looking for, mark that the config data was found */ |
1280 | 0 | if (config_cmd == config_cmd_match) { |
1281 | 0 | proto_item_append_text(fmdata_item, ", using frame number %"PRIu32" as Configuration Frame", |
1282 | 0 | cfg_data->fnum); |
1283 | 0 | config_found = true; |
1284 | 0 | } |
1285 | |
|
1286 | 0 | frame = wmem_list_frame_next(frame); |
1287 | 0 | } |
1288 | |
|
1289 | 0 | if (config_found) { |
1290 | | |
1291 | | /* Retrieve number of Status Flag bytes and setup tree */ |
1292 | 0 | if (cfg_data->num_flags == 1){ |
1293 | 0 | proto_tree_add_item(fmdata_tree, hf_selfm_fmdata_flagbyte, tvb, offset, 1, ENC_BIG_ENDIAN); |
1294 | | /*offset += 1;*/ |
1295 | 0 | } |
1296 | |
|
1297 | 0 | cnt = cfg_data->num_ai; /* actual number of analog values to available to dissect */ |
1298 | | |
1299 | | /* Update our current tvb offset to the actual AI offset saved from the Configuration message */ |
1300 | 0 | offset = cfg_data->offset_ai; |
1301 | | |
1302 | | /* Check that we actually have analog data to dissect */ |
1303 | 0 | if (cnt > 0) { |
1304 | | |
1305 | | /* Include decoding for each Sample provided for the Analog Channels */ |
1306 | 0 | for (j=0; j < cfg_data->num_ai_samples; j++) { |
1307 | | |
1308 | | /* Use different lookup strings, depending on how many samples are available per Analog Channel */ |
1309 | 0 | if (cfg_data->num_ai_samples == 1) { |
1310 | 0 | fmdata_ai_tree = proto_tree_add_subtree_format(fmdata_tree, tvb, offset, ((cfg_data->offset_ts - cfg_data->offset_ai)/cfg_data->num_ai_samples), |
1311 | 0 | ett_selfm_fmdata_ai, NULL, "Analog Channels (%d), Sample: %d (%s)", |
1312 | 0 | cfg_data->num_ai, j+1, val_to_str_const(j+1, selfm_fmconfig_numsamples1_vals, "Unknown")); |
1313 | 0 | } |
1314 | 0 | else if (cfg_data->num_ai_samples == 2) { |
1315 | 0 | fmdata_ai_tree = proto_tree_add_subtree_format(fmdata_tree, tvb, offset, ((cfg_data->offset_ts - cfg_data->offset_ai)/cfg_data->num_ai_samples), |
1316 | 0 | ett_selfm_fmdata_ai, NULL, "Analog Channels (%d), Sample: %d (%s)", |
1317 | 0 | cfg_data->num_ai, j+1, val_to_str_const(j+1, selfm_fmconfig_numsamples2_vals, "Unknown")); |
1318 | 0 | } |
1319 | 0 | else if (cfg_data->num_ai_samples == 4) { |
1320 | 0 | fmdata_ai_tree = proto_tree_add_subtree_format(fmdata_tree, tvb, offset, ((cfg_data->offset_ts - cfg_data->offset_ai)/cfg_data->num_ai_samples), |
1321 | 0 | ett_selfm_fmdata_ai, NULL, "Analog Channels (%d), Sample: %d (%s)", |
1322 | 0 | cfg_data->num_ai, j+1, val_to_str_const(j+1, selfm_fmconfig_numsamples4_vals, "Unknown")); |
1323 | 0 | } |
1324 | | |
1325 | | /* For each analog channel we encounter... */ |
1326 | 0 | for (int idx = 0; idx < cnt; idx++) { |
1327 | |
|
1328 | 0 | fm_analog_info *ai = &(cfg_data->analogs[idx]); |
1329 | | |
1330 | | /* Channel size (in bytes) determined by data type */ |
1331 | 0 | switch (ai->type) { |
1332 | 0 | case FM_CONFIG_ANA_CHTYPE_INT16: |
1333 | 0 | ch_size = 2; /* 2 bytes */ |
1334 | 0 | break; |
1335 | 0 | case FM_CONFIG_ANA_CHTYPE_FP: |
1336 | 0 | ch_size = 4; /* 4 bytes */ |
1337 | 0 | break; |
1338 | 0 | case FM_CONFIG_ANA_CHTYPE_FPD: |
1339 | 0 | ch_size = 8; /* 8 bytes */ |
1340 | 0 | break; |
1341 | 0 | default: |
1342 | 0 | break; |
1343 | 0 | } |
1344 | | |
1345 | | /* Build sub-tree for each Analog Channel */ |
1346 | 0 | fmdata_ai_ch_tree = proto_tree_add_subtree_format(fmdata_ai_tree, tvb, offset, ch_size, |
1347 | 0 | ett_selfm_fmdata_ai_ch, NULL, "Analog Channel %d: %s", idx+1, ai->name); |
1348 | | |
1349 | | /* XXX - Need more decoding options here for different data types, but I need packet capture examples first */ |
1350 | | /* Decode analog value appropriately, according to data type */ |
1351 | 0 | switch (ai->type) { |
1352 | | /* Channel type is 16-bit Integer */ |
1353 | 0 | case FM_CONFIG_ANA_CHTYPE_INT16: |
1354 | 0 | ai_int16val = tvb_get_ntohs(tvb, offset); |
1355 | | |
1356 | | /* If we've got a scale factor, apply it before printing the analog */ |
1357 | | /* For scale factors present in the Fast Meter Data message... */ |
1358 | 0 | if ((ai->sf_offset != 0) && (ai->sf_type == FM_CONFIG_ANA_SFTYPE_FP) && (cfg_data->sf_loc == FM_CONFIG_SF_LOC_FM)) { |
1359 | 0 | ai_sf_fp = tvb_get_ntohieee_float(tvb, ai->sf_offset); |
1360 | 0 | proto_tree_add_float(fmdata_ai_ch_tree, hf_selfm_fmdata_ai_sf_fp, tvb, ai->sf_offset, 4, ai_sf_fp); |
1361 | 0 | } |
1362 | | /* For scale factors present in the Fast Meter Configuration Message... */ |
1363 | 0 | else if (cfg_data->sf_loc == FM_CONFIG_SF_LOC_CFG) { |
1364 | 0 | ai_sf_fp = ai->sf_fp; |
1365 | 0 | fmdata_ai_sf_item = proto_tree_add_float(fmdata_ai_ch_tree, hf_selfm_fmdata_ai_sf_fp, tvb, offset, ch_size, ai_sf_fp); |
1366 | 0 | proto_item_set_generated(fmdata_ai_sf_item); |
1367 | 0 | } |
1368 | | /* If there was no scale factor, default value to 1 */ |
1369 | 0 | else { |
1370 | 0 | ai_sf_fp = 1; |
1371 | 0 | } |
1372 | |
|
1373 | 0 | proto_tree_add_int(fmdata_ai_ch_tree, hf_selfm_fmdata_ai_value16, tvb, offset, ch_size, ai_int16val); |
1374 | 0 | proto_tree_add_float(fmdata_ai_ch_tree, hf_selfm_fmdata_ai_scale_factor, tvb, offset, ch_size, ((float)ai_int16val*ai_sf_fp)); |
1375 | 0 | offset += ch_size; |
1376 | 0 | break; |
1377 | | /* Channel type is IEEE Floating point */ |
1378 | 0 | case FM_CONFIG_ANA_CHTYPE_FP: |
1379 | 0 | proto_tree_add_item(fmdata_ai_ch_tree, hf_selfm_fmdata_ai_value_float, tvb, offset, ch_size, ENC_BIG_ENDIAN); |
1380 | 0 | offset += ch_size; |
1381 | 0 | break; |
1382 | | /* Channel type is Double IEEE Floating point */ |
1383 | 0 | case FM_CONFIG_ANA_CHTYPE_FPD: |
1384 | 0 | proto_tree_add_item(fmdata_ai_ch_tree, hf_selfm_fmdata_ai_value_double, tvb, offset, ch_size, ENC_BIG_ENDIAN); |
1385 | 0 | offset += ch_size; |
1386 | 0 | break; |
1387 | |
|
1388 | 0 | } /* channel type */ |
1389 | |
|
1390 | 0 | } /* number of analog channels */ |
1391 | |
|
1392 | 0 | } /* number of samples */ |
1393 | |
|
1394 | 0 | } /* there were analogs */ |
1395 | | |
1396 | | /* Check if we have a time-stamp in this message */ |
1397 | 0 | if (cfg_data->offset_ts != 0xFFFF) { |
1398 | | /* Retrieve timestamp from 8-byte format */ |
1399 | | /* Stored as: month, day, year (xx), hr, min, sec, msec (16-bit) */ |
1400 | 0 | tm.tm_mon = tvb_get_uint8(tvb, offset) - 1; |
1401 | 0 | tm.tm_mday = tvb_get_uint8(tvb, offset+1); |
1402 | 0 | tm.tm_year = tvb_get_uint8(tvb, offset+2) + 100; |
1403 | 0 | tm.tm_hour = tvb_get_uint8(tvb, offset+3); |
1404 | 0 | tm.tm_min = tvb_get_uint8(tvb, offset+4); |
1405 | 0 | tm.tm_sec = tvb_get_uint8(tvb, offset+5); |
1406 | 0 | tm.tm_isdst = 0; |
1407 | |
|
1408 | 0 | datetime.nsecs = (tvb_get_ntohs(tvb, offset+6) % 1000) * 1000000; |
1409 | 0 | datetime.secs = mktime(&tm); |
1410 | |
|
1411 | 0 | proto_tree_add_time(fmdata_tree, hf_selfm_fmdata_timestamp, tvb, offset, 8, &datetime); |
1412 | |
|
1413 | 0 | offset += 8; |
1414 | 0 | } |
1415 | | |
1416 | | /* Check that we actually have digital data */ |
1417 | 0 | if (cfg_data->num_dig > 0) { |
1418 | |
|
1419 | 0 | fmdata_dig_tree = proto_tree_add_subtree_format(fmdata_tree, tvb, offset, cfg_data->num_dig, |
1420 | 0 | ett_selfm_fmdata_dig, NULL, "Digital Channels (%d)", cfg_data->num_dig); |
1421 | |
|
1422 | 0 | for (unsigned idx=0; idx < cfg_data->num_dig; idx++) { |
1423 | |
|
1424 | 0 | fmdata_dig_ch_tree = proto_tree_add_subtree_format(fmdata_dig_tree, tvb, offset, 1, ett_selfm_fmdata_dig_ch, &fmdata_dig_ch_item, "Digital Word Bit Row: %2u", idx+1); |
1425 | | |
1426 | | /* Display the bit pattern on the digital channel proto_item */ |
1427 | 0 | proto_item_append_text(fmdata_dig_ch_item, " [ %d %d %d %d %d %d %d %d ]", |
1428 | 0 | ((tvb_get_uint8(tvb, offset) & 0x80) >> 7), ((tvb_get_uint8(tvb, offset) & 0x40) >> 6), |
1429 | 0 | ((tvb_get_uint8(tvb, offset) & 0x20) >> 5), ((tvb_get_uint8(tvb, offset) & 0x10) >> 4), |
1430 | 0 | ((tvb_get_uint8(tvb, offset) & 0x08) >> 3), ((tvb_get_uint8(tvb, offset) & 0x04) >> 2), |
1431 | 0 | ((tvb_get_uint8(tvb, offset) & 0x02) >> 1), (tvb_get_uint8(tvb, offset) & 0x01)); |
1432 | |
|
1433 | 0 | proto_tree_add_item(fmdata_dig_ch_tree, hf_selfm_fmdata_dig_b0, tvb, offset, 1, ENC_BIG_ENDIAN); |
1434 | 0 | proto_tree_add_item(fmdata_dig_ch_tree, hf_selfm_fmdata_dig_b1, tvb, offset, 1, ENC_BIG_ENDIAN); |
1435 | 0 | proto_tree_add_item(fmdata_dig_ch_tree, hf_selfm_fmdata_dig_b2, tvb, offset, 1, ENC_BIG_ENDIAN); |
1436 | 0 | proto_tree_add_item(fmdata_dig_ch_tree, hf_selfm_fmdata_dig_b3, tvb, offset, 1, ENC_BIG_ENDIAN); |
1437 | 0 | proto_tree_add_item(fmdata_dig_ch_tree, hf_selfm_fmdata_dig_b4, tvb, offset, 1, ENC_BIG_ENDIAN); |
1438 | 0 | proto_tree_add_item(fmdata_dig_ch_tree, hf_selfm_fmdata_dig_b5, tvb, offset, 1, ENC_BIG_ENDIAN); |
1439 | 0 | proto_tree_add_item(fmdata_dig_ch_tree, hf_selfm_fmdata_dig_b6, tvb, offset, 1, ENC_BIG_ENDIAN); |
1440 | 0 | proto_tree_add_item(fmdata_dig_ch_tree, hf_selfm_fmdata_dig_b7, tvb, offset, 1, ENC_BIG_ENDIAN); |
1441 | |
|
1442 | 0 | offset += 1; |
1443 | 0 | } |
1444 | |
|
1445 | 0 | } /* digital data was available */ |
1446 | | |
1447 | | /* Add Pad byte (if present) and checksum */ |
1448 | 0 | if (tvb_reported_length_remaining(tvb, offset) > 1) { |
1449 | 0 | proto_tree_add_item(fmdata_tree, hf_selfm_padbyte, tvb, offset, 1, ENC_BIG_ENDIAN); |
1450 | 0 | offset += 1; |
1451 | 0 | } |
1452 | |
|
1453 | 0 | proto_tree_add_checksum(fmdata_tree, tvb, offset, hf_selfm_checksum, -1, NULL, pinfo, 0, ENC_BIG_ENDIAN, PROTO_CHECKSUM_NO_FLAGS); |
1454 | 0 | offset += 1; |
1455 | |
|
1456 | 0 | } /* matching config frame message was found */ |
1457 | |
|
1458 | 0 | } /* config data found */ |
1459 | | |
1460 | 0 | if (!config_found) { |
1461 | 0 | proto_item_append_text(fmdata_item, ", No Fast Meter Configuration frame found"); |
1462 | 0 | offset += (len-3); /* Don't include the 2 header bytes or 1 length byte, those are already in the offset */ |
1463 | 0 | return offset; |
1464 | 0 | } |
1465 | 0 | } |
1466 | | |
1467 | 0 | return offset; |
1468 | |
|
1469 | 0 | } |
1470 | | |
1471 | | /******************************************************************************************************/ |
1472 | | /* Code to Dissect Fast Operate Configuration Frames */ |
1473 | | /******************************************************************************************************/ |
1474 | | static int |
1475 | | dissect_foconfig_frame(tvbuff_t *tvb, proto_tree *tree, int offset) |
1476 | 0 | { |
1477 | | /* Set up structures needed to add the protocol subtree and manage it */ |
1478 | 0 | proto_item *foconfig_brkr_item, *foconfig_rb_item; |
1479 | 0 | proto_tree *foconfig_tree, *foconfig_brkr_tree=NULL, *foconfig_rb_tree=NULL; |
1480 | 0 | unsigned count; |
1481 | 0 | uint8_t len, num_brkr, prb_supp; |
1482 | 0 | uint16_t num_rb; |
1483 | |
|
1484 | 0 | len = tvb_get_uint8(tvb, offset); |
1485 | 0 | num_brkr = tvb_get_uint8(tvb, offset+1); |
1486 | 0 | num_rb = tvb_get_ntohs(tvb, offset+2); |
1487 | 0 | prb_supp = tvb_get_uint8(tvb, offset+4); |
1488 | |
|
1489 | 0 | foconfig_tree = proto_tree_add_subtree(tree, tvb, offset, len-2, ett_selfm_foconfig, NULL, "Fast Operate Configuration Details"); |
1490 | | |
1491 | | /* Add items to protocol tree specific to Fast Operate Configuration Block */ |
1492 | | |
1493 | | /* Reported length */ |
1494 | 0 | proto_tree_add_item(foconfig_tree, hf_selfm_foconfig_len, tvb, offset, 1, ENC_BIG_ENDIAN); |
1495 | | |
1496 | | /* Supported Breaker Bits */ |
1497 | 0 | foconfig_brkr_item = proto_tree_add_item(foconfig_tree, hf_selfm_foconfig_num_brkr, tvb, offset+1, 1, ENC_BIG_ENDIAN); |
1498 | | |
1499 | | /* Supported Remote Bits */ |
1500 | 0 | foconfig_rb_item = proto_tree_add_item(foconfig_tree, hf_selfm_foconfig_num_rb, tvb, offset+2, 2, ENC_BIG_ENDIAN); |
1501 | | |
1502 | | /* Add "Remote Bit Pulse Supported?" and "Reserved Bit" to Tree */ |
1503 | 0 | proto_tree_add_item(foconfig_tree, hf_selfm_foconfig_prb_supp, tvb, offset+4, 1, ENC_BIG_ENDIAN); |
1504 | 0 | proto_tree_add_item(foconfig_tree, hf_selfm_foconfig_reserved, tvb, offset+5, 1, ENC_BIG_ENDIAN); |
1505 | | |
1506 | | /* Update offset pointer */ |
1507 | 0 | offset += 6; |
1508 | | |
1509 | | /* Get Breaker Bit Command Details */ |
1510 | 0 | for (count = 1; count <= num_brkr; count++) { |
1511 | |
|
1512 | 0 | foconfig_brkr_tree = proto_item_add_subtree(foconfig_brkr_item, ett_selfm_foconfig_brkr); |
1513 | | |
1514 | | /* Add Breaker Open/Close commands to tree */ |
1515 | 0 | proto_tree_add_item(foconfig_brkr_tree, hf_selfm_foconfig_brkr_open, tvb, offset, 1, ENC_BIG_ENDIAN); |
1516 | 0 | proto_tree_add_item(foconfig_brkr_tree, hf_selfm_foconfig_brkr_close, tvb, offset+1, 1, ENC_BIG_ENDIAN); |
1517 | |
|
1518 | 0 | offset += 2; |
1519 | 0 | } |
1520 | | |
1521 | | /* Get Remote Bit Command Details */ |
1522 | 0 | for (count = 1; count <= num_rb; count++) { |
1523 | |
|
1524 | 0 | foconfig_rb_tree = proto_item_add_subtree(foconfig_rb_item, ett_selfm_foconfig_rb); |
1525 | | |
1526 | | /* Add "Remote Bit Set" command to tree */ |
1527 | 0 | proto_tree_add_item(foconfig_rb_tree, hf_selfm_foconfig_rb_cmd, tvb, offset, 1, ENC_BIG_ENDIAN); |
1528 | | |
1529 | | /* Print "Remote Bit Clear" command to tree */ |
1530 | 0 | proto_tree_add_item(foconfig_rb_tree, hf_selfm_foconfig_rb_cmd, tvb, offset+1, 1, ENC_BIG_ENDIAN); |
1531 | | |
1532 | | /* If Remote Bit "pulse" is supported, retrieve that command as well */ |
1533 | 0 | if (prb_supp) { |
1534 | 0 | proto_tree_add_item(foconfig_rb_tree, hf_selfm_foconfig_rb_cmd, tvb, offset+2, 1, ENC_BIG_ENDIAN); |
1535 | 0 | offset += 3; |
1536 | 0 | } |
1537 | 0 | else{ |
1538 | 0 | offset += 2; |
1539 | 0 | } |
1540 | 0 | } |
1541 | | |
1542 | | /* Add Pad byte (if present) and checksum */ |
1543 | 0 | if (tvb_reported_length_remaining(tvb, offset) > 1) { |
1544 | 0 | proto_tree_add_item(foconfig_tree, hf_selfm_padbyte, tvb, offset, 1, ENC_BIG_ENDIAN); |
1545 | 0 | offset += 1; |
1546 | 0 | } |
1547 | |
|
1548 | 0 | proto_tree_add_checksum(foconfig_tree, tvb, offset, hf_selfm_checksum, -1, NULL, NULL, 0, ENC_BIG_ENDIAN, PROTO_CHECKSUM_NO_FLAGS); |
1549 | 0 | offset += 1; |
1550 | |
|
1551 | 0 | return offset; |
1552 | |
|
1553 | 0 | } |
1554 | | |
1555 | | /******************************************************************************************************/ |
1556 | | /* Code to Dissect Alternate Fast Operate (AFO) Configuration Frames */ |
1557 | | /******************************************************************************************************/ |
1558 | | static int |
1559 | | dissect_alt_fastop_config_frame(tvbuff_t *tvb, proto_tree *tree, int offset) |
1560 | 0 | { |
1561 | | /* Set up structures needed to add the protocol subtree and manage it */ |
1562 | 0 | proto_tree *foconfig_tree; |
1563 | 0 | uint8_t len; |
1564 | |
|
1565 | 0 | len = tvb_get_uint8(tvb, offset); |
1566 | |
|
1567 | 0 | foconfig_tree = proto_tree_add_subtree(tree, tvb, offset, len-2, |
1568 | 0 | ett_selfm_foconfig, NULL, "Alternate Fast Operate Configuration Details"); |
1569 | | |
1570 | | /* Add items to protocol tree specific to Fast Operate Configuration Block */ |
1571 | | |
1572 | | /* Reported length */ |
1573 | 0 | proto_tree_add_item(foconfig_tree, hf_selfm_alt_foconfig_len, tvb, offset, 1, ENC_BIG_ENDIAN); |
1574 | | |
1575 | | /* Number of Ports */ |
1576 | 0 | proto_tree_add_item(foconfig_tree, hf_selfm_alt_foconfig_num_ports, tvb, offset+1, 1, ENC_BIG_ENDIAN); |
1577 | | |
1578 | | /* Number of Breaker Bits */ |
1579 | 0 | proto_tree_add_item(foconfig_tree, hf_selfm_alt_foconfig_num_brkr, tvb, offset+2, 1, ENC_BIG_ENDIAN); |
1580 | | |
1581 | | /* Number of Remote Bits */ |
1582 | 0 | proto_tree_add_item(foconfig_tree, hf_selfm_alt_foconfig_num_rb, tvb, offset+3, 1, ENC_BIG_ENDIAN); |
1583 | | |
1584 | | /* Function Code(s) Supported */ |
1585 | 0 | proto_tree_add_item(foconfig_tree, hf_selfm_alt_foconfig_funccode, tvb, offset+4, 1, ENC_BIG_ENDIAN); |
1586 | 0 | proto_tree_add_item(foconfig_tree, hf_selfm_alt_foconfig_funccode, tvb, offset+5, 1, ENC_BIG_ENDIAN); |
1587 | 0 | proto_tree_add_item(foconfig_tree, hf_selfm_alt_foconfig_funccode, tvb, offset+6, 1, ENC_BIG_ENDIAN); |
1588 | 0 | proto_tree_add_item(foconfig_tree, hf_selfm_alt_foconfig_funccode, tvb, offset+7, 1, ENC_BIG_ENDIAN); |
1589 | 0 | proto_tree_add_item(foconfig_tree, hf_selfm_alt_foconfig_funccode, tvb, offset+8, 1, ENC_BIG_ENDIAN); |
1590 | |
|
1591 | 0 | offset += (len - 2); |
1592 | |
|
1593 | 0 | return offset; |
1594 | |
|
1595 | 0 | } |
1596 | | |
1597 | | /******************************************************************************************************/ |
1598 | | /* Code to Dissect Fast Operate (Remote Bit or Breaker Bit) Frames */ |
1599 | | /******************************************************************************************************/ |
1600 | | static int |
1601 | | dissect_fastop_frame(tvbuff_t *tvb, proto_tree *tree, packet_info *pinfo, int offset) |
1602 | 0 | { |
1603 | | /* Set up structures needed to add the protocol subtree and manage it */ |
1604 | 0 | proto_tree *fastop_tree; |
1605 | 0 | uint8_t len, opcode; |
1606 | 0 | uint16_t msg_type; |
1607 | |
|
1608 | 0 | msg_type = tvb_get_ntohs(tvb, offset-2); |
1609 | 0 | len = tvb_get_uint8(tvb, offset); |
1610 | |
|
1611 | 0 | fastop_tree = proto_tree_add_subtree(tree, tvb, offset, len-2, ett_selfm_fastop, NULL, "Fast Operate Details"); |
1612 | | |
1613 | | /* Add Reported length to tree*/ |
1614 | 0 | proto_tree_add_item(fastop_tree, hf_selfm_fastop_len, tvb, offset, 1, ENC_BIG_ENDIAN); |
1615 | 0 | offset += 1; |
1616 | | |
1617 | | /* Operate Code */ |
1618 | 0 | opcode = tvb_get_uint8(tvb, offset); |
1619 | | |
1620 | | /* Use different lookup table for different msg_type */ |
1621 | 0 | if (msg_type == CMD_FASTOP_RB_CTRL) { |
1622 | 0 | proto_tree_add_item(fastop_tree, hf_selfm_fastop_rb_code, tvb, offset, 1, ENC_BIG_ENDIAN); |
1623 | | |
1624 | | /* Append Column Info w/ Control Code Code */ |
1625 | 0 | col_append_sep_str(pinfo->cinfo, COL_INFO, NULL, val_to_str_ext_const(opcode, &selfm_fo_rb_vals_ext, "Unknown Control Code")); |
1626 | 0 | } |
1627 | 0 | else if (msg_type == CMD_FASTOP_BR_CTRL) { |
1628 | 0 | proto_tree_add_item(fastop_tree, hf_selfm_fastop_br_code, tvb, offset, 1, ENC_BIG_ENDIAN); |
1629 | | |
1630 | | /* Append Column Info w/ Control Code Code */ |
1631 | 0 | col_append_sep_str(pinfo->cinfo, COL_INFO, NULL, val_to_str_ext_const(opcode, &selfm_fo_br_vals_ext, "Unknown Control Code")); |
1632 | 0 | } |
1633 | 0 | offset += 1; |
1634 | | |
1635 | | /* Operate Code Validation */ |
1636 | 0 | proto_tree_add_item(fastop_tree, hf_selfm_fastop_valid, tvb, offset, 1, ENC_BIG_ENDIAN); |
1637 | 0 | offset += 1; |
1638 | | |
1639 | | /* Add checksum */ |
1640 | 0 | proto_tree_add_checksum(fastop_tree, tvb, offset, hf_selfm_checksum, -1, NULL, pinfo, 0, ENC_BIG_ENDIAN, PROTO_CHECKSUM_NO_FLAGS); |
1641 | 0 | offset += 1; |
1642 | |
|
1643 | 0 | return offset; |
1644 | |
|
1645 | 0 | } |
1646 | | |
1647 | | /******************************************************************************************************/ |
1648 | | /* Code to Dissect Alternate Fast Operate (AFO) Command Frames */ |
1649 | | /******************************************************************************************************/ |
1650 | | static int |
1651 | | dissect_alt_fastop_frame(tvbuff_t *tvb, proto_tree *tree, packet_info *pinfo, int offset) |
1652 | 0 | { |
1653 | | /* Set up structures needed to add the protocol subtree and manage it */ |
1654 | 0 | proto_tree *fastop_tree; |
1655 | 0 | uint8_t len; |
1656 | 0 | uint16_t opcode; |
1657 | |
|
1658 | 0 | len = tvb_get_uint8(tvb, offset); |
1659 | |
|
1660 | 0 | fastop_tree = proto_tree_add_subtree(tree, tvb, offset, len-2, ett_selfm_fastop, NULL, "Alternate Fast Operate Details"); |
1661 | | |
1662 | | /* Add Reported length to tree */ |
1663 | 0 | proto_tree_add_item(fastop_tree, hf_selfm_alt_fastop_len, tvb, offset, 1, ENC_BIG_ENDIAN); |
1664 | 0 | offset += 1; |
1665 | | |
1666 | | /* Operate Code */ |
1667 | 0 | opcode = tvb_get_ntohs(tvb, offset); |
1668 | | |
1669 | | /* Append Column Info w/ Control Code Code */ |
1670 | 0 | col_append_sep_fstr(pinfo->cinfo, COL_INFO, NULL, "%#x", opcode); |
1671 | |
|
1672 | 0 | proto_tree_add_item(fastop_tree, hf_selfm_alt_fastop_code, tvb, offset, 2, ENC_BIG_ENDIAN); |
1673 | |
|
1674 | 0 | offset += 2; |
1675 | | |
1676 | | /* Operate Code Validation */ |
1677 | 0 | proto_tree_add_item(fastop_tree, hf_selfm_alt_fastop_valid, tvb, offset, 2, ENC_BIG_ENDIAN); |
1678 | 0 | offset += 2; |
1679 | |
|
1680 | 0 | return offset; |
1681 | |
|
1682 | 0 | } |
1683 | | |
1684 | | /************************************************************************************************************************/ |
1685 | | /* Code to dissect Fast Message Read Response Messages */ |
1686 | | /************************************************************************************************************************/ |
1687 | | /* Each Read Response frame can have a maximum data size of 117 x 16-bit words (or 234 bytes) - this is due to the 20 */ |
1688 | | /* bytes of overhead and 254 max frame size. In the event of a larger data payload than 234 bytes, the FIR and FIN */ |
1689 | | /* bits will be used to indicate either the first frame, last frame, or a neither/middle frame. */ |
1690 | | /* We can use the FIN bit to attempt a reassembly of the data payload since all messages will arrive sequentially. */ |
1691 | | /************************************************************************************************************************/ |
1692 | | |
1693 | | static int |
1694 | | dissect_fastmsg_readresp_frame(tvbuff_t *tvb, proto_tree *fastmsg_tree, packet_info *pinfo, int offset, uint8_t seq_byte) |
1695 | 0 | { |
1696 | 0 | proto_item *fastmsg_tag_value_item=NULL, *fmdata_dig_item=NULL; |
1697 | 0 | proto_item *pi_baseaddr=NULL, *pi_fnum=NULL, *pi_type=NULL, *pi_qty=NULL; |
1698 | 0 | proto_tree *fastmsg_tag_tree=NULL, *fmdata_dig_tree=NULL; |
1699 | 0 | uint32_t base_addr; |
1700 | 0 | uint32_t data_size, cnt; |
1701 | 0 | uint16_t num_addr; |
1702 | 0 | uint8_t seq_cnt; |
1703 | 0 | bool seq_fir, seq_fin, save_fragmented; |
1704 | 0 | int payload_offset=0; |
1705 | 0 | fm_conversation *conv; |
1706 | 0 | fastmsg_dataitem *dataitem; |
1707 | 0 | tvbuff_t *data_tvb, *payload_tvb; |
1708 | | |
1709 | | /* Decode sequence byte components */ |
1710 | 0 | seq_cnt = seq_byte & FAST_MSG_SEQ_CNT; |
1711 | 0 | seq_fir = ((seq_byte & FAST_MSG_SEQ_FIR) >> 7); |
1712 | 0 | seq_fin = ((seq_byte & FAST_MSG_SEQ_FIN) >> 6); |
1713 | |
|
1714 | 0 | base_addr = tvb_get_ntohl(tvb, offset); /* 32-bit field with base address to read */ |
1715 | 0 | num_addr = tvb_get_ntohs(tvb, offset+4); /* 16-bit field with number of 16-bit addresses to read */ |
1716 | | |
1717 | | /* Append Column Info w/ Base Address */ |
1718 | 0 | col_append_sep_fstr(pinfo->cinfo, COL_INFO, NULL, "%#x [%s]", base_addr, region_lookup(pinfo, base_addr)); |
1719 | |
|
1720 | 0 | pi_baseaddr = proto_tree_add_item(fastmsg_tree, hf_selfm_fastmsg_baseaddr, tvb, offset, 4, ENC_BIG_ENDIAN); |
1721 | 0 | proto_item_append_text(pi_baseaddr, " [%s]", region_lookup(pinfo, base_addr)); |
1722 | |
|
1723 | 0 | proto_tree_add_item(fastmsg_tree, hf_selfm_fastmsg_numwords, tvb, offset+4, 2, ENC_BIG_ENDIAN); |
1724 | 0 | offset += 6; |
1725 | | |
1726 | | /* Setup a new tvb representing just the data payload of this particular message */ |
1727 | 0 | data_tvb = tvb_new_subset_length(tvb, offset, (tvb_reported_length_remaining(tvb, offset)-2)); |
1728 | |
|
1729 | 0 | save_fragmented = pinfo->fragmented; |
1730 | | |
1731 | | /* Check for fragmented packet by looking at the FIR and FIN bits */ |
1732 | 0 | if (! (seq_fir && seq_fin)) { |
1733 | 0 | fragment_head *frag_msg; |
1734 | | |
1735 | | /* This is a fragmented packet, mark it as such */ |
1736 | 0 | pinfo->fragmented = true; |
1737 | |
|
1738 | 0 | frag_msg = fragment_add_seq_next(&selfm_reassembly_table, |
1739 | 0 | data_tvb, 0, pinfo, 0, NULL, |
1740 | 0 | tvb_reported_length(data_tvb), |
1741 | 0 | !seq_fin); |
1742 | |
|
1743 | 0 | payload_tvb = process_reassembled_data(data_tvb, 0, pinfo, |
1744 | 0 | "Reassembled Data Response Payload", frag_msg, &selfm_frag_items, |
1745 | 0 | NULL, fastmsg_tree); |
1746 | |
|
1747 | 0 | if (payload_tvb) { /* Reassembled */ |
1748 | | /* We have the complete payload */ |
1749 | 0 | col_append_sep_str(pinfo->cinfo, COL_INFO, NULL, "Reassembled Data Response"); |
1750 | 0 | } |
1751 | 0 | else |
1752 | 0 | { |
1753 | | /* We don't have the complete reassembled payload. */ |
1754 | 0 | col_append_sep_fstr(pinfo->cinfo, COL_INFO, NULL, "Response Data Fragment %u" , seq_cnt); |
1755 | 0 | } |
1756 | |
|
1757 | 0 | } |
1758 | | |
1759 | | /* No re-assembly required, setup the payload_tvb based on the single-frame data payload tvb */ |
1760 | 0 | else { |
1761 | 0 | payload_tvb = data_tvb; |
1762 | 0 | add_new_data_source(pinfo, payload_tvb, "Data Response Payload"); |
1763 | 0 | } |
1764 | |
|
1765 | 0 | pinfo->fragmented = save_fragmented; |
1766 | | |
1767 | | /* If we had no need to re-assemble or this is the final packet of a reassembly, let's attempt to dissect the */ |
1768 | | /* data payload using any previously-captured data format information */ |
1769 | 0 | if (payload_tvb) { |
1770 | | |
1771 | | /* Search for previously-encountered data format reference information to dissect the frame */ |
1772 | 0 | conv = (fm_conversation *)p_get_proto_data(wmem_file_scope(), pinfo, proto_selfm, 0); |
1773 | |
|
1774 | 0 | if (conv) { |
1775 | | /* Start at front of list and cycle through possible instances of multiple fastmsg_dataitem frames, looking for match */ |
1776 | 0 | wmem_list_frame_t *frame = wmem_list_head(conv->fastmsg_dataitems); |
1777 | |
|
1778 | 0 | while (frame && (tvb_reported_length_remaining(payload_tvb, payload_offset) > 0)) { |
1779 | 0 | dataitem = (fastmsg_dataitem *)wmem_list_frame_data(frame); |
1780 | | |
1781 | | /* If the stored base address of the current data item matches the current base address of this response frame */ |
1782 | | /* mark that the config data was found and attempt further dissection */ |
1783 | 0 | if (dataitem->base_address == base_addr) { |
1784 | | |
1785 | | /* Data Item size (in bytes) determined by data type and quantity within item */ |
1786 | 0 | switch (dataitem->data_type) { |
1787 | 0 | case FAST_MSG_TAGTYPE_CHAR8: |
1788 | 0 | case FAST_MSG_TAGTYPE_DIGWORD8_BL: |
1789 | 0 | case FAST_MSG_TAGTYPE_DIGWORD8: |
1790 | 0 | data_size = 1 * dataitem->quantity; /* 1 byte per qty */ |
1791 | 0 | break; |
1792 | 0 | case FAST_MSG_TAGTYPE_CHAR16: |
1793 | 0 | case FAST_MSG_TAGTYPE_DIGWORD16_BL: |
1794 | 0 | case FAST_MSG_TAGTYPE_DIGWORD16: |
1795 | 0 | case FAST_MSG_TAGTYPE_INT16: |
1796 | 0 | case FAST_MSG_TAGTYPE_UINT16: |
1797 | 0 | data_size = 2 * dataitem->quantity; /* 2 bytes per qty */ |
1798 | 0 | break; |
1799 | 0 | case FAST_MSG_TAGTYPE_INT32: |
1800 | 0 | case FAST_MSG_TAGTYPE_UINT32: |
1801 | 0 | case FAST_MSG_TAGTYPE_FLOAT: |
1802 | 0 | data_size = 4 * dataitem->quantity; /* 4 bytes per qty */ |
1803 | 0 | break; |
1804 | | |
1805 | 0 | default: |
1806 | 0 | data_size = 0; |
1807 | 0 | break; |
1808 | 0 | } |
1809 | | |
1810 | 0 | fastmsg_tag_tree = proto_tree_add_subtree_format(fastmsg_tree, payload_tvb, payload_offset, data_size, |
1811 | 0 | ett_selfm_fastmsg_tag, NULL, "Data Item Name: %s", dataitem->name); |
1812 | | |
1813 | | /* Load some information from the stored Data Format Response message into the tree for reference */ |
1814 | 0 | pi_fnum = proto_tree_add_uint_format(fastmsg_tag_tree, hf_selfm_fmdata_frame_data_format_reference, payload_tvb, payload_offset, data_size, |
1815 | 0 | dataitem->fnum, "Using frame number %d (Index Pos: %d) as Data Format Reference",dataitem->fnum, dataitem->index_pos ); |
1816 | 0 | pi_type = proto_tree_add_uint(fastmsg_tag_tree, hf_selfm_fmdata_data_type, payload_tvb, payload_offset, 0, dataitem->data_type); |
1817 | 0 | pi_qty = proto_tree_add_uint(fastmsg_tag_tree, hf_selfm_fmdata_quantity, payload_tvb, payload_offset, 0, dataitem->quantity ); |
1818 | |
|
1819 | 0 | proto_item_set_generated(pi_fnum); |
1820 | 0 | proto_item_set_generated(pi_type); |
1821 | 0 | proto_item_set_len(pi_type, data_size); |
1822 | 0 | proto_item_set_generated(pi_qty); |
1823 | 0 | proto_item_set_len(pi_qty, data_size); |
1824 | | |
1825 | | /* Data Item Type determines how to decode */ |
1826 | 0 | switch (dataitem->data_type) { |
1827 | | |
1828 | 0 | case FAST_MSG_TAGTYPE_DIGWORD8_BL: |
1829 | 0 | case FAST_MSG_TAGTYPE_DIGWORD8: |
1830 | |
|
1831 | 0 | for (cnt=1; cnt <= dataitem->quantity; cnt++) { |
1832 | |
|
1833 | 0 | fmdata_dig_tree = proto_tree_add_subtree_format(fastmsg_tag_tree, payload_tvb, payload_offset, 1, |
1834 | 0 | ett_selfm_fmdata_dig, &fmdata_dig_item, "8-bit Binary Items (Row: %2d)", cnt); |
1835 | | |
1836 | | /* Display the bit pattern on the digital channel proto_item */ |
1837 | 0 | proto_item_append_text(fmdata_dig_item, " [ %d %d %d %d %d %d %d %d ]", |
1838 | 0 | ((tvb_get_uint8(payload_tvb, payload_offset) & 0x80) >> 7), ((tvb_get_uint8(payload_tvb, payload_offset) & 0x40) >> 6), |
1839 | 0 | ((tvb_get_uint8(payload_tvb, payload_offset) & 0x20) >> 5), ((tvb_get_uint8(payload_tvb, payload_offset) & 0x10) >> 4), |
1840 | 0 | ((tvb_get_uint8(payload_tvb, payload_offset) & 0x08) >> 3), ((tvb_get_uint8(payload_tvb, payload_offset) & 0x04) >> 2), |
1841 | 0 | ((tvb_get_uint8(payload_tvb, payload_offset) & 0x02) >> 1), (tvb_get_uint8(payload_tvb, payload_offset) & 0x01)); |
1842 | |
|
1843 | 0 | proto_tree_add_item(fmdata_dig_tree, hf_selfm_fmdata_dig_b0, payload_tvb, payload_offset, 1, ENC_BIG_ENDIAN); |
1844 | 0 | proto_tree_add_item(fmdata_dig_tree, hf_selfm_fmdata_dig_b1, payload_tvb, payload_offset, 1, ENC_BIG_ENDIAN); |
1845 | 0 | proto_tree_add_item(fmdata_dig_tree, hf_selfm_fmdata_dig_b2, payload_tvb, payload_offset, 1, ENC_BIG_ENDIAN); |
1846 | 0 | proto_tree_add_item(fmdata_dig_tree, hf_selfm_fmdata_dig_b3, payload_tvb, payload_offset, 1, ENC_BIG_ENDIAN); |
1847 | 0 | proto_tree_add_item(fmdata_dig_tree, hf_selfm_fmdata_dig_b4, payload_tvb, payload_offset, 1, ENC_BIG_ENDIAN); |
1848 | 0 | proto_tree_add_item(fmdata_dig_tree, hf_selfm_fmdata_dig_b5, payload_tvb, payload_offset, 1, ENC_BIG_ENDIAN); |
1849 | 0 | proto_tree_add_item(fmdata_dig_tree, hf_selfm_fmdata_dig_b6, payload_tvb, payload_offset, 1, ENC_BIG_ENDIAN); |
1850 | 0 | proto_tree_add_item(fmdata_dig_tree, hf_selfm_fmdata_dig_b7, payload_tvb, payload_offset, 1, ENC_BIG_ENDIAN); |
1851 | |
|
1852 | 0 | payload_offset += 1; |
1853 | |
|
1854 | 0 | } |
1855 | |
|
1856 | 0 | break; |
1857 | | |
1858 | 0 | case FAST_MSG_TAGTYPE_CHAR8: |
1859 | 0 | case FAST_MSG_TAGTYPE_CHAR16: |
1860 | 0 | proto_tree_add_item(fastmsg_tag_tree, hf_selfm_fmdata_ai_value_string, payload_tvb, payload_offset, data_size, ENC_ASCII); |
1861 | 0 | payload_offset += data_size; |
1862 | 0 | break; |
1863 | | |
1864 | 0 | case FAST_MSG_TAGTYPE_INT16: |
1865 | 0 | for (cnt=1; cnt <= dataitem->quantity; cnt++) { |
1866 | 0 | fastmsg_tag_value_item = proto_tree_add_item(fastmsg_tag_tree, hf_selfm_fastmsg_dataitem_int16, payload_tvb, payload_offset, data_size/dataitem->quantity, ENC_BIG_ENDIAN); |
1867 | 0 | proto_item_prepend_text(fastmsg_tag_value_item, "Value %d ", cnt); |
1868 | 0 | payload_offset += data_size/dataitem->quantity; |
1869 | 0 | } |
1870 | 0 | break; |
1871 | | |
1872 | 0 | case FAST_MSG_TAGTYPE_UINT16: |
1873 | 0 | for (cnt=1; cnt <= dataitem->quantity; cnt++) { |
1874 | 0 | fastmsg_tag_value_item = proto_tree_add_item(fastmsg_tag_tree, hf_selfm_fastmsg_dataitem_uint16, payload_tvb, payload_offset, data_size/dataitem->quantity, ENC_BIG_ENDIAN); |
1875 | 0 | proto_item_prepend_text(fastmsg_tag_value_item, "Value %d ", cnt); |
1876 | 0 | payload_offset += data_size/dataitem->quantity; |
1877 | 0 | } |
1878 | 0 | break; |
1879 | | |
1880 | 0 | case FAST_MSG_TAGTYPE_INT32: |
1881 | 0 | for (cnt=1; cnt <= dataitem->quantity; cnt++) { |
1882 | 0 | fastmsg_tag_value_item = proto_tree_add_item(fastmsg_tag_tree, hf_selfm_fastmsg_dataitem_int32, payload_tvb, payload_offset, data_size/dataitem->quantity, ENC_BIG_ENDIAN); |
1883 | 0 | proto_item_prepend_text(fastmsg_tag_value_item, "Value %d ", cnt); |
1884 | 0 | payload_offset += data_size/dataitem->quantity; |
1885 | 0 | } |
1886 | 0 | break; |
1887 | | |
1888 | 0 | case FAST_MSG_TAGTYPE_UINT32: |
1889 | 0 | for (cnt=1; cnt <= dataitem->quantity; cnt++) { |
1890 | 0 | fastmsg_tag_value_item = proto_tree_add_item(fastmsg_tag_tree, hf_selfm_fastmsg_dataitem_uint32, payload_tvb, payload_offset, data_size/dataitem->quantity, ENC_BIG_ENDIAN); |
1891 | 0 | proto_item_prepend_text(fastmsg_tag_value_item, "Value %d ", cnt); |
1892 | 0 | payload_offset += data_size/dataitem->quantity; |
1893 | 0 | } |
1894 | 0 | break; |
1895 | | |
1896 | 0 | case FAST_MSG_TAGTYPE_FLOAT: |
1897 | 0 | for (cnt=1; cnt <= dataitem->quantity; cnt++) { |
1898 | 0 | fastmsg_tag_value_item = proto_tree_add_item(fastmsg_tag_tree, hf_selfm_fastmsg_dataitem_float, payload_tvb, payload_offset, data_size/dataitem->quantity, ENC_BIG_ENDIAN); |
1899 | 0 | proto_item_prepend_text(fastmsg_tag_value_item, "Value %d ", cnt); |
1900 | 0 | payload_offset += data_size/dataitem->quantity; |
1901 | 0 | } |
1902 | 0 | break; |
1903 | | |
1904 | 0 | default: |
1905 | 0 | break; |
1906 | 0 | } /* data item type switch */ |
1907 | |
|
1908 | 0 | } /* base address is correct */ |
1909 | | |
1910 | | /* After processing this frame/data item, proceed to the next */ |
1911 | 0 | frame = wmem_list_frame_next(frame); |
1912 | |
|
1913 | 0 | } /* while (frame) */ |
1914 | |
|
1915 | 0 | } /* if (conv) found */ |
1916 | |
|
1917 | 0 | } /* if payload_tvb */ |
1918 | | |
1919 | | /* Update the offset field before we leave this frame */ |
1920 | 0 | offset += num_addr*2; |
1921 | |
|
1922 | 0 | return offset; |
1923 | |
|
1924 | 0 | } |
1925 | | |
1926 | | |
1927 | | /******************************************************************************************************/ |
1928 | | /* Code to dissect Fast Message Frames */ |
1929 | | /******************************************************************************************************/ |
1930 | | static int |
1931 | | dissect_fastmsg_frame(tvbuff_t *tvb, proto_tree *tree, packet_info *pinfo, int offset) |
1932 | 0 | { |
1933 | | /* Set up structures needed to add the protocol subtree and manage it */ |
1934 | 0 | proto_item *fastmsg_def_fc_item, *fastmsg_elementlist_item; |
1935 | 0 | proto_item *pi_baseaddr, *fastmsg_crc16_item; |
1936 | 0 | proto_tree *fastmsg_tree, *fastmsg_def_fc_tree=NULL, *fastmsg_elementlist_tree=NULL; |
1937 | 0 | proto_tree *fastmsg_element_tree=NULL, *fastmsg_datareg_tree=NULL, *fastmsg_tag_tree=NULL, *fastmsg_soeblk_tree=NULL; |
1938 | 0 | int cnt, cnt1, num_elements, elmt_status32_ofs=0, elmt_status, null_offset; |
1939 | 0 | uint8_t len, funccode, seq=0, rx_num_fc, tx_num_fc; |
1940 | 0 | uint8_t seq_cnt=0, elmt_idx, fc_enable, soe_num_reg; |
1941 | 0 | uint8_t *tag_name_ptr; |
1942 | 0 | uint16_t base_addr, num_addr, num_reg, addr1, addr2, crc16, crc16_calc, soe_num_blks; |
1943 | 0 | uint32_t tod_ms, elmt_status32, elmt_ts_offset; |
1944 | 0 | static int * const seq_fields[] = { |
1945 | 0 | &hf_selfm_fastmsg_seq_fir, |
1946 | 0 | &hf_selfm_fastmsg_seq_fin, |
1947 | 0 | &hf_selfm_fastmsg_seq_cnt, |
1948 | 0 | NULL |
1949 | 0 | }; |
1950 | |
|
1951 | 0 | len = tvb_get_uint8(tvb, offset); |
1952 | |
|
1953 | 0 | fastmsg_tree = proto_tree_add_subtree(tree, tvb, offset, len-2, ett_selfm_fastmsg, NULL, "Fast Message Details"); |
1954 | | |
1955 | | /* Reported length */ |
1956 | 0 | proto_tree_add_item(fastmsg_tree, hf_selfm_fastmsg_len, tvb, offset, 1, ENC_BIG_ENDIAN); |
1957 | | |
1958 | | /* 5-byte Future Routing Address */ |
1959 | 0 | proto_tree_add_item(fastmsg_tree, hf_selfm_fastmsg_routing_addr, tvb, offset+1, 5, ENC_NA); |
1960 | 0 | offset += 6; |
1961 | | |
1962 | | /* Add Status Byte to tree */ |
1963 | 0 | proto_tree_add_item(fastmsg_tree, hf_selfm_fastmsg_status, tvb, offset, 1, ENC_BIG_ENDIAN); |
1964 | 0 | offset += 1; |
1965 | | |
1966 | | /* Get Function Code, add to tree */ |
1967 | 0 | proto_tree_add_item_ret_uint8(fastmsg_tree, hf_selfm_fastmsg_funccode, tvb, offset, 1, ENC_BIG_ENDIAN, &funccode); |
1968 | | |
1969 | | /* Append Column Info w/ Function Code */ |
1970 | 0 | col_append_sep_str(pinfo->cinfo, COL_INFO, NULL, val_to_str_ext_const(funccode, &selfm_fastmsg_func_code_vals_ext, "Unknown Function Code")); |
1971 | |
|
1972 | 0 | offset += 1; |
1973 | | |
1974 | | /* If this is an ACK message, process this byte as a Response Code. */ |
1975 | 0 | if ((funccode == FAST_MSG_EN_UNS_DATA_ACK) || |
1976 | 0 | (funccode == FAST_MSG_DIS_UNS_DATA_ACK) || |
1977 | 0 | (funccode == FAST_MSG_UNS_RESP_ACK)) { |
1978 | 0 | proto_tree_add_item(fastmsg_tree, hf_selfm_fastmsg_response_code, tvb, offset, 1, ENC_BIG_ENDIAN); |
1979 | 0 | } |
1980 | | |
1981 | 0 | else { |
1982 | | /* Otherwise, it is the sequence byte, add to Tree */ |
1983 | 0 | seq = tvb_get_uint8(tvb, offset); |
1984 | 0 | seq_cnt = seq & FAST_MSG_SEQ_CNT; |
1985 | 0 | proto_tree_add_bitmask_with_flags(fastmsg_tree, tvb, offset, hf_selfm_fastmsg_seq, ett_selfm_fastmsg_seq, |
1986 | 0 | seq_fields, ENC_NA, BMT_NO_APPEND); |
1987 | 0 | } |
1988 | |
|
1989 | 0 | offset += 1; |
1990 | | |
1991 | | /* Add Response Number to tree */ |
1992 | 0 | proto_tree_add_item(fastmsg_tree, hf_selfm_fastmsg_resp_num, tvb, offset, 1, ENC_BIG_ENDIAN); |
1993 | 0 | offset += 1; |
1994 | | |
1995 | | /* Depending on Function Code used, remaining section of packet will be handled differently. */ |
1996 | 0 | switch (funccode) { |
1997 | | |
1998 | 0 | case FAST_MSG_EN_UNS_DATA: /* 0x01 - Enabled Unsolicited Data Transfers */ |
1999 | | |
2000 | | /* Function code to enable */ |
2001 | 0 | fc_enable = tvb_get_uint8(tvb, offset); |
2002 | 0 | proto_tree_add_item(fastmsg_tree, hf_selfm_fastmsg_uns_en_fc, tvb, offset, 1, ENC_BIG_ENDIAN); |
2003 | | |
2004 | | /* Append Column Info w/ "Enable" Function Code */ |
2005 | 0 | col_append_sep_fstr(pinfo->cinfo, COL_INFO, NULL, "Function to Enable (%#x)", fc_enable); |
2006 | | |
2007 | | /* 3-byte Function Code data */ |
2008 | 0 | proto_tree_add_item(fastmsg_tree, hf_selfm_fastmsg_uns_en_fc_data, tvb, offset+1, 3, ENC_NA); |
2009 | |
|
2010 | 0 | offset += 4; |
2011 | |
|
2012 | 0 | break; |
2013 | | |
2014 | 0 | case FAST_MSG_DIS_UNS_DATA: /* 0x02 - Disable Unsolicited Data Transfers */ |
2015 | | |
2016 | | /* Function code to disable */ |
2017 | 0 | fc_enable = tvb_get_uint8(tvb, offset); |
2018 | 0 | proto_tree_add_item(fastmsg_tree, hf_selfm_fastmsg_uns_dis_fc, tvb, offset, 1, ENC_BIG_ENDIAN); |
2019 | | |
2020 | | /* Append Column Info w/ "Disable" Function Code */ |
2021 | 0 | col_append_sep_fstr(pinfo->cinfo, COL_INFO, NULL, "Function to Disable (%#x)", fc_enable); |
2022 | | |
2023 | | /* 1-byte Function Code data */ |
2024 | 0 | proto_tree_add_item(fastmsg_tree, hf_selfm_fastmsg_uns_dis_fc_data, tvb, offset+1, 1, ENC_NA); |
2025 | |
|
2026 | 0 | offset += 2; |
2027 | |
|
2028 | 0 | break; |
2029 | | |
2030 | | |
2031 | 0 | case FAST_MSG_READ_REQ: /* 0x10 - Read Request */ |
2032 | |
|
2033 | 0 | base_addr = tvb_get_ntohl(tvb, offset); /* 32-bit field with base address to read */ |
2034 | | |
2035 | | /* Append Column Info w/ Base Address */ |
2036 | 0 | col_append_sep_fstr(pinfo->cinfo, COL_INFO, NULL, "%#x [%s]", base_addr, region_lookup(pinfo, base_addr)); |
2037 | |
|
2038 | 0 | pi_baseaddr = proto_tree_add_item(fastmsg_tree, hf_selfm_fastmsg_baseaddr, tvb, offset, 4, ENC_BIG_ENDIAN); |
2039 | 0 | proto_item_append_text(pi_baseaddr, " [%s]", region_lookup(pinfo, base_addr)); |
2040 | |
|
2041 | 0 | proto_tree_add_item(fastmsg_tree, hf_selfm_fastmsg_numwords, tvb, offset+4, 2, ENC_BIG_ENDIAN); |
2042 | 0 | offset += 6; |
2043 | 0 | break; |
2044 | | |
2045 | 0 | case FAST_MSG_GEN_UNS_DATA: /* 0x12 - Generic Unsolicited Data */ |
2046 | |
|
2047 | 0 | num_addr = len - 14; /* 12 header bytes + 2-byte CRC, whatever is left is the data portion of this message */ |
2048 | 0 | num_reg = num_addr / 2; |
2049 | | |
2050 | | /* For the number of registers, step through and retrieve/print each 16-bit component */ |
2051 | 0 | for (cnt=0; cnt < num_reg; cnt++) { |
2052 | 0 | proto_tree_add_item(fastmsg_tree, hf_selfm_fastmsg_unswrite_reg_val, tvb, offset, 2, ENC_BIG_ENDIAN); |
2053 | 0 | offset += 2; |
2054 | 0 | } |
2055 | |
|
2056 | 0 | break; |
2057 | | |
2058 | 0 | case FAST_MSG_SOE_STATE_REQ: /* 0x16 - SOE Present State Request */ |
2059 | | |
2060 | | /* 4 bytes - "Origination Path" */ |
2061 | 0 | proto_tree_add_item(fastmsg_tree, hf_selfm_fastmsg_soe_req_orig, tvb, offset, 4, ENC_NA); |
2062 | 0 | offset += 4; |
2063 | |
|
2064 | 0 | break; |
2065 | | |
2066 | 0 | case FAST_MSG_UNS_RESP: /* 0x18 - Unsolicited Fast SER Data Response */ |
2067 | | |
2068 | | /* 4 bytes - "Origination Path" */ |
2069 | 0 | proto_tree_add_item(fastmsg_tree, hf_selfm_fastmsg_unsresp_orig, tvb, offset, 4, ENC_NA); |
2070 | 0 | offset += 4; |
2071 | | |
2072 | | /* Timestamp: 2-byte day-of-year, 2-byte year, 4-byte time-of-day in milliseconds */ |
2073 | | /* XXX - We can use a built-in function to convert the tod_ms to a readable time format, is there anything for day_of_year? */ |
2074 | 0 | tod_ms = tvb_get_ntohl(tvb, offset+4); |
2075 | |
|
2076 | 0 | proto_tree_add_item(fastmsg_tree, hf_selfm_fastmsg_unsresp_doy, tvb, offset, 2, ENC_BIG_ENDIAN); |
2077 | 0 | proto_tree_add_item(fastmsg_tree, hf_selfm_fastmsg_unsresp_year, tvb, offset+2, 2, ENC_BIG_ENDIAN); |
2078 | 0 | proto_tree_add_uint_format_value(fastmsg_tree, hf_selfm_fastmsg_unsresp_todms, tvb, offset+4, 4, |
2079 | 0 | tod_ms, "%s", signed_time_msecs_to_str(pinfo->pool, tod_ms)); |
2080 | 0 | offset += 8; |
2081 | | |
2082 | | /* Build element tree */ |
2083 | | /* Determine the number of elements returned in this unsolicited message */ |
2084 | | /* The general formula is: (Length - 34) / 4 */ |
2085 | 0 | num_elements = (len-34) / 4; |
2086 | |
|
2087 | 0 | fastmsg_elementlist_item = proto_tree_add_uint(fastmsg_tree, hf_selfm_fastmsg_unsresp_num_elmt, tvb, offset, (4*num_elements), num_elements); |
2088 | 0 | fastmsg_elementlist_tree = proto_item_add_subtree(fastmsg_elementlist_item, ett_selfm_fastmsg_element_list); |
2089 | | |
2090 | | /* "Reported New Status" word for up to 32 index elements is following the upcoming 0xFFFFFFFE End-of-record indicator |
2091 | | Search for that indicator and use the detected tvb offset+4 to retrieve the proper 32-bit status word. |
2092 | | Save this word for use in the element index printing but don't print the word itself until the end of the tree dissection */ |
2093 | 0 | for (cnt = offset; cnt < len; cnt++) { |
2094 | |
|
2095 | 0 | if (tvb_memeql(tvb, cnt, (const uint8_t*)"\xFF\xFF\xFF\xFE", 4) == 0) { |
2096 | 0 | elmt_status32_ofs = cnt+4; |
2097 | 0 | } |
2098 | 0 | } |
2099 | 0 | elmt_status32 = tvb_get_ntohl(tvb, elmt_status32_ofs ); |
2100 | | |
2101 | | /* Cycle through each element we have detected that exists in the SER record */ |
2102 | 0 | for (cnt=0; cnt<num_elements; cnt++) { |
2103 | | |
2104 | | /* Get Element Index and Timestamp Offset (in uSec) */ |
2105 | 0 | elmt_idx = tvb_get_uint8(tvb, offset); |
2106 | 0 | elmt_ts_offset = (uint32_t)((tvb_get_uint8(tvb, offset+1) << 16) | (tvb_get_uint8(tvb, offset+2) << 8) | (tvb_get_uint8(tvb, offset+3))); |
2107 | | |
2108 | | /* Bit shift the appropriate element from the 32-bit elmt_status word to position 0 and get the bit state for use in the tree */ |
2109 | 0 | elmt_status = (cnt < 32) ? ((elmt_status32 >> cnt) & 0x01) : 0; |
2110 | | |
2111 | | /* Build the tree */ |
2112 | 0 | fastmsg_element_tree = proto_tree_add_subtree_format(fastmsg_elementlist_tree, tvb, offset, 4, ett_selfm_fastmsg_element, NULL, |
2113 | 0 | "Reported Event %d (Index: %d [%s], New State: %s)", cnt+1, elmt_idx, fastser_uns_wordbit_lookup(pinfo, elmt_idx), |
2114 | 0 | val_to_str_const(elmt_status, selfm_ser_status_vals, "Unknown")); |
2115 | | |
2116 | | /* Add Index Number and Timestamp offset to tree */ |
2117 | 0 | proto_tree_add_item(fastmsg_element_tree, hf_selfm_fastmsg_unsresp_elmt_idx, tvb, offset, 1, ENC_BIG_ENDIAN); |
2118 | 0 | proto_tree_add_item(fastmsg_element_tree, hf_selfm_fastmsg_unsresp_elmt_ts_ofs, tvb, offset+1, 3, ENC_BIG_ENDIAN); |
2119 | 0 | proto_tree_add_uint_format_value(fastmsg_element_tree, hf_selfm_fastmsg_unsresp_elmt_ts_ofs_decoded, tvb, offset+1, 3, |
2120 | 0 | tod_ms + (elmt_ts_offset/1000), "%s", signed_time_msecs_to_str(pinfo->pool, tod_ms + (elmt_ts_offset/1000))); |
2121 | 0 | proto_tree_add_uint(fastmsg_element_tree, hf_selfm_fastmsg_unsresp_elmt_status, tvb, elmt_status32_ofs, 4, elmt_status); |
2122 | |
|
2123 | 0 | offset += 4; |
2124 | |
|
2125 | 0 | } |
2126 | | |
2127 | | /* 4-byte End-of-Record Terminator 0xFFFFFFFE */ |
2128 | 0 | proto_tree_add_item(fastmsg_tree, hf_selfm_fastmsg_unsresp_eor, tvb, offset, 4, ENC_NA); |
2129 | 0 | offset += 4; |
2130 | | |
2131 | | /* 4-byte Element Status word */ |
2132 | 0 | proto_tree_add_item(fastmsg_tree, hf_selfm_fastmsg_unsresp_elmt_statword, tvb, offset, 4, ENC_BIG_ENDIAN); |
2133 | 0 | offset += 4; |
2134 | |
|
2135 | 0 | break; |
2136 | | |
2137 | | |
2138 | 0 | case FAST_MSG_UNS_WRITE: /* 0x20 - Unsolicited Write */ |
2139 | | |
2140 | | /* Write Address Region #1 and #2, along with number of 16-bit registers */ |
2141 | 0 | addr1 = tvb_get_ntohs(tvb, offset); |
2142 | 0 | addr2 = tvb_get_ntohs(tvb, offset+2); |
2143 | 0 | num_reg = tvb_get_ntohs(tvb, offset+4); |
2144 | | |
2145 | | /* Append Column Info w/ Address Information */ |
2146 | 0 | col_append_sep_fstr(pinfo->cinfo, COL_INFO, NULL, "%#x, %#x", addr1, addr2); |
2147 | |
|
2148 | 0 | proto_tree_add_item(fastmsg_tree, hf_selfm_fastmsg_unswrite_addr1, tvb, offset, 2, ENC_BIG_ENDIAN); |
2149 | 0 | proto_tree_add_item(fastmsg_tree, hf_selfm_fastmsg_unswrite_addr2, tvb, offset+2, 2, ENC_BIG_ENDIAN); |
2150 | 0 | proto_tree_add_item(fastmsg_tree, hf_selfm_fastmsg_unswrite_num_reg, tvb, offset+4, 2, ENC_BIG_ENDIAN); |
2151 | |
|
2152 | 0 | offset += 6; |
2153 | | |
2154 | | /* For the number of registers, step through and retrieve/print each 16-bit component */ |
2155 | 0 | for (cnt=0; cnt < num_reg; cnt++) { |
2156 | 0 | proto_tree_add_item(fastmsg_tree, hf_selfm_fastmsg_unswrite_reg_val, tvb, offset, 2, ENC_BIG_ENDIAN); |
2157 | 0 | offset += 2; |
2158 | 0 | } |
2159 | |
|
2160 | 0 | break; |
2161 | | |
2162 | 0 | case FAST_MSG_DATAFMT_REQ: /* 0x31 - Data Format Request */ |
2163 | |
|
2164 | 0 | base_addr = tvb_get_ntohl(tvb, offset); /* 32-bit field with base address to read */ |
2165 | | |
2166 | | /* Append Column Info w/ Base Address */ |
2167 | 0 | col_append_sep_fstr(pinfo->cinfo, COL_INFO, NULL, "%#x [%s]", base_addr, region_lookup(pinfo, base_addr)); |
2168 | | |
2169 | | /* Add Base Address to Tree */ |
2170 | 0 | pi_baseaddr = proto_tree_add_item(fastmsg_tree, hf_selfm_fastmsg_baseaddr, tvb, offset, 4, ENC_BIG_ENDIAN); |
2171 | 0 | proto_item_append_text(pi_baseaddr, " [%s]", region_lookup(pinfo, base_addr)); |
2172 | |
|
2173 | 0 | offset += 4; |
2174 | |
|
2175 | 0 | break; |
2176 | | |
2177 | 0 | case FAST_MSG_BITLABEL_REQ: /* 0x33 - Bit Label Request */ |
2178 | |
|
2179 | 0 | base_addr = tvb_get_ntohl(tvb, offset); /* 32-bit field with base address to read */ |
2180 | 0 | proto_tree_add_item(fastmsg_tree, hf_selfm_fastmsg_baseaddr, tvb, offset, 4, ENC_BIG_ENDIAN); |
2181 | 0 | offset += 4; |
2182 | | |
2183 | | /* Append Column Info w/ Base Address */ |
2184 | 0 | col_append_sep_fstr(pinfo->cinfo, COL_INFO, NULL, "%#x", base_addr); |
2185 | |
|
2186 | 0 | break; |
2187 | | |
2188 | | |
2189 | 0 | case FAST_MSG_CFG_BLOCK_RESP: /* 0x80 (resp to 0x00) - Fast Message Configuration Block Response */ |
2190 | | |
2191 | | /* Routing Support */ |
2192 | 0 | proto_tree_add_item(fastmsg_tree, hf_selfm_fastmsg_def_route_sup, tvb, offset, 1, ENC_BIG_ENDIAN); |
2193 | 0 | offset += 1; |
2194 | | |
2195 | | /* RX / TX Status */ |
2196 | 0 | proto_tree_add_item(fastmsg_tree, hf_selfm_fastmsg_def_rx_stat, tvb, offset, 1, ENC_BIG_ENDIAN); |
2197 | 0 | proto_tree_add_item(fastmsg_tree, hf_selfm_fastmsg_def_tx_stat, tvb, offset+1, 1, ENC_BIG_ENDIAN); |
2198 | 0 | offset += 2; |
2199 | | |
2200 | | /* Max Frames RX/TX */ |
2201 | 0 | proto_tree_add_item(fastmsg_tree, hf_selfm_fastmsg_def_rx_maxfr, tvb, offset, 1, ENC_BIG_ENDIAN); |
2202 | 0 | proto_tree_add_item(fastmsg_tree, hf_selfm_fastmsg_def_tx_maxfr, tvb, offset+1, 1, ENC_BIG_ENDIAN); |
2203 | 0 | offset += 2; |
2204 | | |
2205 | | /* 6 bytes of reserved space */ |
2206 | 0 | offset += 6; |
2207 | | |
2208 | | /* Number of Supported RX Function Codes */ |
2209 | 0 | fastmsg_def_fc_item = proto_tree_add_item_ret_uint8(fastmsg_tree, hf_selfm_fastmsg_def_rx_num_fc, tvb, offset, 1, ENC_BIG_ENDIAN, &rx_num_fc); |
2210 | 0 | fastmsg_def_fc_tree = proto_item_add_subtree(fastmsg_def_fc_item, ett_selfm_fastmsg_def_fc); |
2211 | 0 | offset += 1; |
2212 | | |
2213 | | /* Add Supported RX Function Codes to tree */ |
2214 | 0 | for (cnt=0; cnt<rx_num_fc; cnt++) { |
2215 | 0 | proto_tree_add_item(fastmsg_def_fc_tree, hf_selfm_fastmsg_def_rx_fc, tvb, offset, 1, ENC_BIG_ENDIAN); |
2216 | 0 | offset += 2; |
2217 | 0 | } |
2218 | | |
2219 | | /* Number of Supported TX Function Codes */ |
2220 | 0 | fastmsg_def_fc_item = proto_tree_add_item_ret_uint8(fastmsg_tree, hf_selfm_fastmsg_def_tx_num_fc, tvb, offset, 1, ENC_BIG_ENDIAN, &tx_num_fc); |
2221 | 0 | fastmsg_def_fc_tree = proto_item_add_subtree(fastmsg_def_fc_item, ett_selfm_fastmsg_def_fc); |
2222 | 0 | offset += 1; |
2223 | | |
2224 | | /* Add Supported TX Function Codes to tree */ |
2225 | 0 | for (cnt=0; cnt<tx_num_fc; cnt++) { |
2226 | 0 | proto_tree_add_item(fastmsg_def_fc_tree, hf_selfm_fastmsg_def_tx_fc, tvb, offset, 1, ENC_BIG_ENDIAN); |
2227 | 0 | offset += 2; |
2228 | 0 | } |
2229 | |
|
2230 | 0 | break; |
2231 | | |
2232 | 0 | case FAST_MSG_READ_RESP: /* 0x90 (resp to 0x10) - Read Response */ |
2233 | |
|
2234 | 0 | offset = dissect_fastmsg_readresp_frame( tvb, fastmsg_tree, pinfo, offset, seq); |
2235 | |
|
2236 | 0 | break; |
2237 | | |
2238 | 0 | case FAST_MSG_SOE_STATE_RESP: /* 0x96 - (resp to 0x16) SOE Present State Response */ |
2239 | | |
2240 | | /* 16-bit field with number of blocks of present state data */ |
2241 | 0 | proto_tree_add_item(fastmsg_tree, hf_selfm_fastmsg_soe_resp_numblks, tvb, offset, 2, ENC_BIG_ENDIAN); |
2242 | 0 | soe_num_blks = tvb_get_ntohs(tvb, offset); |
2243 | 0 | offset += 2; |
2244 | | |
2245 | | /* Loop through each one of these block based on the num_blocks */ |
2246 | 0 | for (cnt=0; cnt<soe_num_blks; cnt++) { |
2247 | | |
2248 | | /* Blocks of 16 bits are packed into 16-bit registers, with any remainder into a final 16-bit register */ |
2249 | 0 | if ((tvb_get_uint8(tvb, offset+4) % 16) == 0) { |
2250 | 0 | soe_num_reg = (tvb_get_uint8(tvb, offset+4) / 16); |
2251 | 0 | } |
2252 | 0 | else { |
2253 | 0 | soe_num_reg = (tvb_get_uint8(tvb, offset+4) / 16) + 1; |
2254 | 0 | } |
2255 | |
|
2256 | 0 | fastmsg_soeblk_tree = proto_tree_add_subtree_format(fastmsg_tree, tvb, offset, 14 + soe_num_reg*2, |
2257 | 0 | ett_selfm_fastmsg_soeblk, NULL, "Data Block #%d", cnt+1); |
2258 | |
|
2259 | 0 | proto_tree_add_item(fastmsg_soeblk_tree, hf_selfm_fastmsg_soe_resp_orig, tvb, offset, 4, ENC_NA); |
2260 | 0 | proto_tree_add_item(fastmsg_soeblk_tree, hf_selfm_fastmsg_soe_resp_numbits, tvb, offset+4, 1, ENC_BIG_ENDIAN); |
2261 | 0 | proto_tree_add_item(fastmsg_soeblk_tree, hf_selfm_fastmsg_soe_resp_pad, tvb, offset+5, 1, ENC_BIG_ENDIAN); |
2262 | 0 | proto_tree_add_item(fastmsg_soeblk_tree, hf_selfm_fastmsg_soe_resp_doy, tvb, offset+6, 2, ENC_BIG_ENDIAN); |
2263 | 0 | proto_tree_add_item(fastmsg_soeblk_tree, hf_selfm_fastmsg_soe_resp_year, tvb, offset+8, 2, ENC_BIG_ENDIAN); |
2264 | 0 | proto_tree_add_item(fastmsg_soeblk_tree, hf_selfm_fastmsg_soe_resp_tod, tvb, offset+10, 4, ENC_BIG_ENDIAN); |
2265 | 0 | offset += 14; |
2266 | |
|
2267 | 0 | for (cnt1=0; cnt1<soe_num_reg; cnt1++) { |
2268 | 0 | proto_tree_add_item(fastmsg_soeblk_tree, hf_selfm_fastmsg_soe_resp_data, tvb, offset, 2, ENC_BIG_ENDIAN); |
2269 | 0 | offset += 2; |
2270 | 0 | } |
2271 | 0 | } |
2272 | |
|
2273 | 0 | break; |
2274 | | |
2275 | 0 | case FAST_MSG_DEVDESC_RESP: /* 0xB0 (resp to 0x30) - Device Description Response */ |
2276 | | |
2277 | | /* Add FID / RID ASCII data to tree */ |
2278 | 0 | proto_tree_add_item(fastmsg_tree, hf_selfm_fid, tvb, offset, 50, ENC_ASCII); |
2279 | 0 | proto_tree_add_item(fastmsg_tree, hf_selfm_rid, tvb, offset+50, 40, ENC_ASCII); |
2280 | 0 | offset += 90; |
2281 | | |
2282 | | /* 16-bit field with number of data areas */ |
2283 | 0 | proto_tree_add_item_ret_uint16(fastmsg_tree, hf_selfm_fastmsg_devdesc_num_region, tvb, offset, 2, ENC_BIG_ENDIAN, &num_reg); |
2284 | 0 | offset += 2; |
2285 | | |
2286 | | /* Maximum size of 7 regions per message, check the seq_cnt to determine if we have stepped into |
2287 | | the next sequential message where the remaining regions would be described */ |
2288 | 0 | if ((num_reg >= 8) && (seq_cnt == 0)) { |
2289 | 0 | num_reg = 7; |
2290 | 0 | } |
2291 | 0 | else{ |
2292 | 0 | num_reg = num_reg - (seq_cnt * 7); |
2293 | 0 | } |
2294 | | |
2295 | | /* 16-bit field with number of control areas */ |
2296 | 0 | proto_tree_add_item(fastmsg_tree, hf_selfm_fastmsg_devdesc_num_ctrl, tvb, offset, 2, ENC_BIG_ENDIAN); |
2297 | 0 | offset += 2; |
2298 | | |
2299 | | /* Each 18-byte data area description has a 10 byte region name, followed by 32-bit base, */ |
2300 | | /* 16-bit message word count and 16-bit flag field */ |
2301 | 0 | for (cnt=0; cnt<num_reg; cnt++) { |
2302 | |
|
2303 | 0 | fastmsg_datareg_tree = proto_tree_add_subtree_format(fastmsg_tree, tvb, offset, 18, |
2304 | 0 | ett_selfm_fastmsg_datareg, NULL, "Fast Message Data Region #%d", cnt+1); |
2305 | | |
2306 | | /* 10-Byte Region description */ |
2307 | 0 | proto_tree_add_item(fastmsg_datareg_tree, hf_selfm_fastmsg_data_region_name, tvb, offset, 10, ENC_ASCII); |
2308 | 0 | offset += 10; |
2309 | | |
2310 | | /* 32-bit field with base address of data region */ |
2311 | 0 | proto_tree_add_item(fastmsg_datareg_tree, hf_selfm_fastmsg_baseaddr, tvb, offset, 4, ENC_BIG_ENDIAN); |
2312 | 0 | offset += 4; |
2313 | | |
2314 | | /* 16-bit field with number of 16-bit words in region */ |
2315 | 0 | proto_tree_add_item(fastmsg_datareg_tree, hf_selfm_fastmsg_numwords, tvb, offset, 2, ENC_BIG_ENDIAN); |
2316 | 0 | offset += 2; |
2317 | | |
2318 | | /* 16-bit flag field */ |
2319 | 0 | proto_tree_add_item(fastmsg_datareg_tree, hf_selfm_fastmsg_flags, tvb, offset, 2, ENC_BIG_ENDIAN); |
2320 | 0 | offset += 2; |
2321 | |
|
2322 | 0 | } |
2323 | | |
2324 | | /* Some relays (4xx) don't follow the standard here and include an 8-byte sequence of all 0x00's to represent */ |
2325 | | /* 'reserved' space for the control regions. Detect these and skip if they are present */ |
2326 | 0 | if (tvb_reported_length_remaining(tvb, offset) > 2) { |
2327 | |
|
2328 | 0 | if (tvb_memeql(tvb, offset, (const uint8_t*)"\x00\x00\x00\x00\x00\x00\x00\x00", 8) == 0) { |
2329 | 0 | offset += 8; |
2330 | 0 | } |
2331 | 0 | } |
2332 | |
|
2333 | 0 | break; |
2334 | | |
2335 | 0 | case FAST_MSG_DATAFMT_RESP: /* 0xB1 (resp to 0x31) - Data Format Response */ |
2336 | |
|
2337 | 0 | base_addr = tvb_get_ntohl(tvb, offset); /* 32-bit field with base address to read */ |
2338 | | |
2339 | | /* Add Base Address to Tree */ |
2340 | 0 | pi_baseaddr = proto_tree_add_item(fastmsg_tree, hf_selfm_fastmsg_baseaddr, tvb, offset, 4, ENC_BIG_ENDIAN); |
2341 | 0 | proto_item_append_text(pi_baseaddr, " [%s]", region_lookup(pinfo, base_addr)); |
2342 | |
|
2343 | 0 | offset += 4; |
2344 | | |
2345 | | /* Append Column Info w/ Base Address */ |
2346 | 0 | col_append_sep_fstr(pinfo->cinfo, COL_INFO, NULL, "%#x [%s]", base_addr, region_lookup(pinfo, base_addr)); |
2347 | | |
2348 | | /* 16-bit field with number of data items to follow */ |
2349 | 0 | proto_tree_add_item(fastmsg_tree, hf_selfm_fastmsg_datafmt_resp_numitem, tvb, offset, 2, ENC_BIG_ENDIAN); |
2350 | 0 | offset += 2; |
2351 | |
|
2352 | 0 | while ((tvb_reported_length_remaining(tvb, offset)) > 2) { |
2353 | | /* Data Item record name 10 bytes */ |
2354 | 0 | tag_name_ptr = tvb_get_string_enc(pinfo->pool, tvb, offset, 10, ENC_ASCII); |
2355 | 0 | fastmsg_tag_tree = proto_tree_add_subtree_format(fastmsg_tree, tvb, offset, 14, ett_selfm_fastmsg_tag, NULL, "Data Item Record Name: %s", tag_name_ptr); |
2356 | | |
2357 | | /* Data item qty and type */ |
2358 | 0 | proto_tree_add_item(fastmsg_tag_tree, hf_selfm_fastmsg_dataitem_qty, tvb, offset+10, 2, ENC_BIG_ENDIAN); |
2359 | 0 | proto_tree_add_item(fastmsg_tag_tree, hf_selfm_fastmsg_dataitem_type, tvb, offset+12, 2, ENC_BIG_ENDIAN); |
2360 | |
|
2361 | 0 | offset += 14; |
2362 | 0 | } |
2363 | 0 | break; |
2364 | | |
2365 | 0 | case FAST_MSG_BITLABEL_RESP: /* 0xB3 (resp to 0x33) - Bit Label Response */ |
2366 | | |
2367 | | /* The data in this response is a variable length string containing the names of 8 digital bits. */ |
2368 | | /* Each name is max 8 chars and each is null-separated */ |
2369 | 0 | cnt=1; |
2370 | | |
2371 | | /* find the null separators and add the bit label text strings to the tree */ |
2372 | 0 | for (null_offset = offset; null_offset < len; null_offset++) { |
2373 | 0 | if ((tvb_memeql(tvb, null_offset, (const uint8_t*)"\x00", 1) == 0) && (tvb_reported_length_remaining(tvb, offset) > 2)) { |
2374 | 0 | char* str = tvb_format_text(pinfo->pool, tvb, offset, (null_offset-offset)); |
2375 | 0 | proto_tree_add_string_format(fastmsg_tree, hf_selfm_fastmsg_bit_label_name, tvb, offset, (null_offset-offset), str, |
2376 | 0 | "Bit Label #%d Name: %s", cnt, str); |
2377 | 0 | offset = null_offset+1; /* skip the null */ |
2378 | 0 | cnt++; |
2379 | 0 | } |
2380 | 0 | } |
2381 | |
|
2382 | 0 | break; |
2383 | | |
2384 | 0 | default: |
2385 | 0 | break; |
2386 | 0 | } /* func_code */ |
2387 | | |
2388 | | /* Add CRC16 to Tree */ |
2389 | 0 | fastmsg_crc16_item = proto_tree_add_item(fastmsg_tree, hf_selfm_fastmsg_crc16, tvb, offset, 2, ENC_BIG_ENDIAN); |
2390 | 0 | crc16 = tvb_get_ntohs(tvb, offset); |
2391 | 0 | offset += 2; |
2392 | | |
2393 | | /* If option is enabled, validate the CRC16 */ |
2394 | 0 | if (selfm_crc16) { |
2395 | 0 | crc16_calc = crc16_plain_tvb_offset_seed(tvb, 0, len-2, 0xFFFF); |
2396 | 0 | if (crc16_calc != crc16) { |
2397 | 0 | expert_add_info_format(pinfo, fastmsg_crc16_item, &ei_selfm_crc16_incorrect, "Incorrect CRC - should be 0x%04x", crc16_calc); |
2398 | 0 | } |
2399 | 0 | else { |
2400 | 0 | proto_item_append_text(fastmsg_crc16_item, " [OK]"); |
2401 | 0 | } |
2402 | |
|
2403 | 0 | } |
2404 | |
|
2405 | 0 | return offset; |
2406 | |
|
2407 | 0 | } |
2408 | | |
2409 | | |
2410 | | /******************************************************************************************************/ |
2411 | | /* Code to dissect SEL Fast Message Protocol packets */ |
2412 | | /* Will call other sub-dissectors, as needed */ |
2413 | | /******************************************************************************************************/ |
2414 | | static int |
2415 | | dissect_selfm(tvbuff_t *selfm_tvb, packet_info *pinfo, proto_tree *tree, void* data _U_) |
2416 | 0 | { |
2417 | | /* Set up structures needed to add the protocol subtree and manage it */ |
2418 | 0 | proto_item *selfm_item=NULL; |
2419 | 0 | proto_tree *selfm_tree=NULL; |
2420 | 0 | int offset=0, cnt=0, consumed_bytes=0; |
2421 | 0 | int fm_offset; |
2422 | 0 | uint32_t base_addr; |
2423 | 0 | uint16_t msg_type, len, num_items; |
2424 | 0 | uint8_t seq, seq_cnt; |
2425 | 0 | char **uns_ser_split_str; |
2426 | | |
2427 | | /* Make entries in Protocol column on summary display */ |
2428 | 0 | col_set_str(pinfo->cinfo, COL_PROTOCOL, "SEL Protocol"); |
2429 | 0 | col_clear(pinfo->cinfo, COL_INFO); |
2430 | |
|
2431 | 0 | len = tvb_reported_length(selfm_tvb); |
2432 | |
|
2433 | 0 | msg_type = tvb_get_ntohs(selfm_tvb, offset); |
2434 | | |
2435 | | /* On first pass through the packets we have 4 tasks to complete - they are each noted below */ |
2436 | 0 | if (!pinfo->fd->visited) { |
2437 | 0 | conversation_t *conversation; |
2438 | 0 | fm_conversation *fm_conv_data; |
2439 | | |
2440 | | /* Find a conversation, create a new if no one exists */ |
2441 | 0 | conversation = find_or_create_conversation(pinfo); |
2442 | |
|
2443 | 0 | fm_conv_data = (fm_conversation *)conversation_get_proto_data(conversation, proto_selfm); |
2444 | |
|
2445 | 0 | if (fm_conv_data == NULL) { |
2446 | 0 | fm_conv_data = wmem_new(wmem_file_scope(), fm_conversation); |
2447 | 0 | fm_conv_data->fm_config_frames = wmem_list_new(wmem_file_scope()); |
2448 | 0 | fm_conv_data->fastmsg_dataitems = wmem_list_new(wmem_file_scope()); |
2449 | 0 | fm_conv_data->fastmsg_dataregions = wmem_tree_new(wmem_file_scope()); |
2450 | 0 | fm_conv_data->fastser_uns_wordbits = wmem_tree_new(wmem_file_scope()); |
2451 | 0 | conversation_add_proto_data(conversation, proto_selfm, (void *)fm_conv_data); |
2452 | |
|
2453 | 0 | uns_ser_split_str = wmem_strsplit(pinfo->pool, selfm_ser_list, ",", -1); |
2454 | |
|
2455 | 0 | for (cnt = 0; (uns_ser_split_str[cnt] != NULL); cnt++) { |
2456 | 0 | fastser_uns_wordbit *wordbit_ptr = fastser_uns_wordbit_save(cnt, uns_ser_split_str[cnt]); |
2457 | 0 | wmem_tree_insert32(fm_conv_data->fastser_uns_wordbits, cnt, wordbit_ptr); |
2458 | 0 | } |
2459 | | |
2460 | | /* Power Up (254) and Settings Changed (255) Indexes */ |
2461 | 0 | for (cnt = 254; (cnt <= 255); cnt++) { |
2462 | 0 | fastser_uns_wordbit *wordbit_ptr = fastser_uns_wordbit_save(cnt, "unused"); |
2463 | 0 | wmem_tree_insert32(fm_conv_data->fastser_uns_wordbits, cnt, wordbit_ptr); |
2464 | 0 | } |
2465 | 0 | } |
2466 | |
|
2467 | 0 | p_add_proto_data(wmem_file_scope(), pinfo, proto_selfm, 0, fm_conv_data); |
2468 | | |
2469 | | /* 1. Configuration frames (0xA5C1, 0xA5C2, 0xA5C3) need special treatment during the first run */ |
2470 | | /* For each Fast Meter Configuration frame (0xA5Cx), a 'fm_config_frame' struct is created to hold the */ |
2471 | | /* information necessary to decode subsequent matching Fast Meter Data frames (0xA5Dx). A pointer to */ |
2472 | | /* this struct is saved in the conversation and is copied to the per-packet information if a */ |
2473 | | /* Fast Meter Data frame is dissected. */ |
2474 | 0 | if ((CMD_FM_CONFIG == msg_type) || (CMD_DFM_CONFIG == msg_type) || (CMD_PDFM_CONFIG == msg_type)) { |
2475 | | /* Fill the fm_config_frame */ |
2476 | 0 | fm_config_frame *frame_ptr = fmconfig_frame_fast(selfm_tvb); |
2477 | 0 | frame_ptr->fnum = pinfo->num; |
2478 | 0 | wmem_list_prepend(fm_conv_data->fm_config_frames, frame_ptr); |
2479 | 0 | } |
2480 | | |
2481 | | /* 2. Fill conversation data array with Fast Msg Data Item info from Data Format Response Messages. */ |
2482 | | /* These format definitions will later be retrieved to decode Read Response messages. */ |
2483 | 0 | if ((CMD_FAST_MSG == msg_type) && (tvb_get_uint8(selfm_tvb, offset+9) == FAST_MSG_DATAFMT_RESP)) { |
2484 | |
|
2485 | 0 | seq = tvb_get_uint8(selfm_tvb, offset+10); |
2486 | 0 | seq_cnt = seq & FAST_MSG_SEQ_CNT; |
2487 | |
|
2488 | 0 | base_addr = tvb_get_ntohl(selfm_tvb, offset+12); /* 32-bit field with base address to read */ |
2489 | 0 | num_items = tvb_get_ntohs(selfm_tvb, offset+16); |
2490 | | |
2491 | | /* When dealing with Data Format Response messages, there are a maximum of 16 items per frame */ |
2492 | | /* Use the sequence count if we have more 16 items to determine how many to expect in each frame */ |
2493 | 0 | if ((num_items > 16) && (seq_cnt == 0)) { |
2494 | 0 | num_items = 16; |
2495 | 0 | } |
2496 | 0 | else { |
2497 | 0 | num_items = num_items - (seq_cnt * 16); |
2498 | 0 | } |
2499 | | |
2500 | | /* Set offset to start of data items */ |
2501 | 0 | fm_offset = 18; |
2502 | | |
2503 | | /* Enter the single frame multiple times, retrieving a single dataitem per entry */ |
2504 | 0 | for (cnt = 1; (cnt <= num_items); cnt++) { |
2505 | 0 | fastmsg_dataitem *dataitem_ptr = fastmsg_dataitem_save(selfm_tvb, fm_offset); |
2506 | 0 | dataitem_ptr->fnum = pinfo->num; |
2507 | 0 | dataitem_ptr->base_address = base_addr; |
2508 | 0 | dataitem_ptr->index_pos = cnt; |
2509 | | |
2510 | | /* Store the data item configuration info in the fastmsg_dataitems list */ |
2511 | 0 | wmem_list_append(fm_conv_data->fastmsg_dataitems, dataitem_ptr); |
2512 | 0 | fm_offset += 14; |
2513 | 0 | } |
2514 | 0 | } |
2515 | | |
2516 | | /* 4. Fill conversation data array with Fast Message Data Region info from Device Desc Response Messages. This */ |
2517 | | /* will retrieve a data region name (associated to an address) that can later be displayed in the tree. */ |
2518 | 0 | if ((CMD_FAST_MSG == msg_type) && (tvb_get_uint8(selfm_tvb, offset+9) == FAST_MSG_DEVDESC_RESP)) { |
2519 | |
|
2520 | 0 | seq = tvb_get_uint8(selfm_tvb, offset+10); |
2521 | 0 | seq_cnt = seq & FAST_MSG_SEQ_CNT; |
2522 | |
|
2523 | 0 | num_items = tvb_get_ntohs(selfm_tvb, offset+102); |
2524 | | |
2525 | | /* When dealing with Device Description Response messages, there are a maximum of 7 regions per frame */ |
2526 | | /* Use the sequence count if we have more 7 items to determine how many to expect in each frame */ |
2527 | 0 | if ((num_items >= 8) && (seq_cnt == 0)) { |
2528 | 0 | num_items = 7; |
2529 | 0 | } |
2530 | 0 | else{ |
2531 | 0 | num_items = num_items - (seq_cnt * 7); |
2532 | 0 | } |
2533 | | |
2534 | | /* Set offset to start of data regions */ |
2535 | 0 | fm_offset = 106; |
2536 | | |
2537 | | /* Enter the single frame multiple times, retrieving a single data region per entry */ |
2538 | 0 | for (cnt = 1; (cnt <= num_items); cnt++) { |
2539 | 0 | uint32_t base_address = tvb_get_ntohl(selfm_tvb, fm_offset+10); |
2540 | 0 | fastmsg_dataregion *dataregion_ptr = fastmsg_dataregion_save(selfm_tvb, fm_offset); |
2541 | | |
2542 | | /* Store the data region info in the fastmsg_dataregions tree */ |
2543 | 0 | wmem_tree_insert32(fm_conv_data->fastmsg_dataregions, base_address, dataregion_ptr); |
2544 | 0 | fm_offset += 18; |
2545 | 0 | } |
2546 | 0 | } |
2547 | 0 | } /* if (!visited) */ |
2548 | |
|
2549 | 0 | { |
2550 | |
|
2551 | 0 | selfm_item = proto_tree_add_protocol_format(tree, proto_selfm, selfm_tvb, 0, len, "SEL Protocol"); |
2552 | 0 | selfm_tree = proto_item_add_subtree(selfm_item, ett_selfm); |
2553 | | |
2554 | | /* Set INFO column with SEL Protocol Message Type */ |
2555 | 0 | col_set_str(pinfo->cinfo, COL_INFO, val_to_str_ext_const(msg_type, &selfm_msgtype_vals_ext, "Unknown Message Type")); |
2556 | | |
2557 | | /* Add Message Type to Protocol Tree */ |
2558 | 0 | proto_tree_add_item(selfm_tree, hf_selfm_msgtype, selfm_tvb, offset, 2, ENC_BIG_ENDIAN); |
2559 | 0 | offset += 2; |
2560 | 0 | consumed_bytes += 2; |
2561 | | |
2562 | | /* Determine correct message type and call appropriate dissector */ |
2563 | 0 | if (tvb_reported_length_remaining(selfm_tvb, offset) > 0) { |
2564 | 0 | switch (msg_type) { |
2565 | 0 | case CMD_RELAY_DEF: |
2566 | 0 | consumed_bytes = dissect_relaydef_frame(selfm_tvb, selfm_tree, offset); |
2567 | 0 | break; |
2568 | 0 | case CMD_FM_CONFIG: |
2569 | 0 | case CMD_DFM_CONFIG: |
2570 | 0 | case CMD_PDFM_CONFIG: |
2571 | 0 | consumed_bytes = dissect_fmconfig_frame(selfm_tvb, selfm_tree, pinfo, offset); |
2572 | 0 | break; |
2573 | 0 | case CMD_FM_DATA: |
2574 | 0 | consumed_bytes = dissect_fmdata_frame(selfm_tvb, selfm_tree, pinfo, offset, CMD_FM_CONFIG); |
2575 | 0 | break; |
2576 | 0 | case CMD_DFM_DATA: |
2577 | 0 | consumed_bytes = dissect_fmdata_frame(selfm_tvb, selfm_tree, pinfo, offset, CMD_DFM_CONFIG); |
2578 | 0 | break; |
2579 | 0 | case CMD_PDFM_DATA: |
2580 | 0 | consumed_bytes = dissect_fmdata_frame(selfm_tvb, selfm_tree, pinfo, offset, CMD_PDFM_CONFIG); |
2581 | 0 | break; |
2582 | 0 | case CMD_FASTOP_CONFIG: |
2583 | 0 | consumed_bytes = dissect_foconfig_frame(selfm_tvb, selfm_tree, offset); |
2584 | 0 | break; |
2585 | 0 | case CMD_FAST_MSG: |
2586 | 0 | consumed_bytes = dissect_fastmsg_frame(selfm_tvb, selfm_tree, pinfo, offset); |
2587 | 0 | break; |
2588 | 0 | case CMD_FASTOP_RB_CTRL: |
2589 | 0 | case CMD_FASTOP_BR_CTRL: |
2590 | 0 | consumed_bytes = dissect_fastop_frame(selfm_tvb, selfm_tree, pinfo, offset); |
2591 | 0 | break; |
2592 | 0 | case CMD_ALT_FASTOP_CONFIG: |
2593 | 0 | consumed_bytes = dissect_alt_fastop_config_frame(selfm_tvb, selfm_tree, offset); |
2594 | 0 | break; |
2595 | 0 | case CMD_ALT_FASTOP_OPEN: |
2596 | 0 | case CMD_ALT_FASTOP_CLOSE: |
2597 | 0 | case CMD_ALT_FASTOP_SET: |
2598 | 0 | case CMD_ALT_FASTOP_CLEAR: |
2599 | 0 | case CMD_ALT_FASTOP_PULSE: |
2600 | 0 | consumed_bytes = dissect_alt_fastop_frame(selfm_tvb, selfm_tree, pinfo, offset); |
2601 | 0 | break; |
2602 | 0 | default: |
2603 | 0 | break; |
2604 | 0 | } /* msg_type */ |
2605 | 0 | } /* remaining length > 0 */ |
2606 | 0 | } |
2607 | | |
2608 | 0 | return consumed_bytes; |
2609 | 0 | } |
2610 | | |
2611 | | /******************************************************************************************************/ |
2612 | | /* Dissect (and possibly re-assemble) SEL protocol payload data */ |
2613 | | /******************************************************************************************************/ |
2614 | | /* Since we are dealing with (usually) Telnet-encapsulated data with possible extra IAC bytes present,*/ |
2615 | | /* we cannot know the 'true' length of re-assembled TCP messages by just looking at the protocol PDU */ |
2616 | | /* header and it's included length byte. This precludes the use of tcp_dissect_pdus() and requires */ |
2617 | | /* us to do the reassembly efforts here. */ |
2618 | | /* The tvb structure is as follows: */ |
2619 | | /* tvb = original data tvb from TCP dissector */ |
2620 | | /* selfm_tvb = 'IAC-sanitized' (0xFF) version of tvb */ |
2621 | | /* selfm_pdu_tvb = with multiple PDUs in a single selfm_tvb, split them out for separate dissection */ |
2622 | | /* */ |
2623 | | /* tvb -> selfm_tvb -> selfm_pdu_tvb */ |
2624 | | /* -> selfm_pdu_tvb */ |
2625 | | /******************************************************************************************************/ |
2626 | | static int |
2627 | | dissect_selfm_tcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data) |
2628 | 0 | { |
2629 | |
|
2630 | 0 | tvbuff_t *selfm_tvb, *selfm_pdu_tvb; |
2631 | 0 | int skip_byte = 0, selfm_tvb_len, offset = 0; |
2632 | 0 | uint8_t selfm_PDU_len=0, new_selfm_PDU_len=0; |
2633 | 0 | int length = tvb_reported_length(tvb); |
2634 | | |
2635 | | /* Check for a SEL Protocol packet. It should begin with 0xA5 */ |
2636 | 0 | if(length < 2 || tvb_get_uint8(tvb, 0) != 0xA5) { |
2637 | | /* Not a SEL Protocol packet, just happened to use the same port */ |
2638 | 0 | return 0; |
2639 | 0 | } |
2640 | | |
2641 | | /* If the length of this packet is only 2 bytes, it's a scan message so just do a simple dissection */ |
2642 | 0 | if (length == 2) { |
2643 | 0 | return dissect_selfm(tvb, pinfo, tree, data); |
2644 | 0 | } |
2645 | | |
2646 | 0 | selfm_PDU_len = tvb_get_uint8(tvb,2); |
2647 | | |
2648 | | /* If the reported selfm PDU length is greater than the present tvb length, request more data */ |
2649 | 0 | if (length < selfm_PDU_len) { |
2650 | 0 | pinfo->desegment_offset = 0; |
2651 | 0 | pinfo->desegment_len = DESEGMENT_ONE_MORE_SEGMENT; |
2652 | 0 | return tvb_captured_length(tvb); |
2653 | 0 | } |
2654 | | |
2655 | | /* If this is a Telnet-encapsulated Ethernet packet, let's clean out the IAC 0xFF instances */ |
2656 | | /* before we attempt any kind of re-assembly of the message */ |
2657 | 0 | if ((pinfo->srcport) && selfm_telnet_clean) { |
2658 | 0 | selfm_tvb = clean_telnet_iac(pinfo, tvb, 0, length, &skip_byte); |
2659 | 0 | } |
2660 | 0 | else { |
2661 | 0 | selfm_tvb = tvb_new_subset_length( tvb, 0, length); |
2662 | 0 | } |
2663 | |
|
2664 | 0 | selfm_tvb_len = tvb_reported_length(selfm_tvb); |
2665 | | |
2666 | | /* If sanitized selfm_tvb length is still less than the reported selfm PDU length, there is more segment data to follow */ |
2667 | 0 | if (selfm_tvb_len < selfm_PDU_len) { |
2668 | 0 | pinfo->desegment_offset = 0; |
2669 | 0 | pinfo->desegment_len = DESEGMENT_ONE_MORE_SEGMENT; |
2670 | 0 | return tvb_captured_length(tvb); |
2671 | 0 | } |
2672 | | |
2673 | | /* If the available selfm_tvb length is greater than the reported selfm PDU length, */ |
2674 | | /* there is possibly a second PDU to follow so let's dig deeper... */ |
2675 | 0 | if (selfm_tvb_len > selfm_PDU_len) { |
2676 | | /* Check if additional data is actually selfm PDU data */ |
2677 | 0 | if (tvb_get_uint8(selfm_tvb, selfm_PDU_len) == 0xA5) { |
2678 | 0 | new_selfm_PDU_len = tvb_get_uint8(selfm_tvb, selfm_PDU_len+2); |
2679 | | /* If we still don't have enough data to accommodate the 2 PDUs... */ |
2680 | 0 | if (selfm_tvb_len < (selfm_PDU_len + new_selfm_PDU_len)) { |
2681 | 0 | ws_debug("On Packet: %d, continuing to desegment. PDU: %d NewPDU: %d Still need %d bytes..", pinfo->fd->num, selfm_PDU_len, new_selfm_PDU_len, (selfm_PDU_len + new_selfm_PDU_len) - selfm_tvb_len); |
2682 | | |
2683 | | /* If the current selfm_tvb length is less than the combined reported selfm length of the 2 PDUs, continue TCP desegmentation */ |
2684 | | /* The desegment_len field will be used to report how many additional bytes remain to be reassembled */ |
2685 | 0 | pinfo->desegment_offset = 0; |
2686 | 0 | pinfo->desegment_len = (selfm_PDU_len + new_selfm_PDU_len) - selfm_tvb_len; |
2687 | 0 | return tvb_captured_length(tvb); |
2688 | 0 | } |
2689 | 0 | } |
2690 | 0 | } |
2691 | | |
2692 | | /* If multiple SEL protocol PDUs exist within a single tvb, dissect each of them sequentially */ |
2693 | 0 | while (offset < selfm_tvb_len) { |
2694 | | /* If random ASCII data makes its way onto the end of an SEL protocol PDU, ignore it */ |
2695 | 0 | if (tvb_get_uint8(selfm_tvb, offset) != 0xA5) { |
2696 | 0 | ws_debug("On Packet: %d, extraneous data (starts with: %x)..", pinfo->fd->num, tvb_get_uint8(selfm_tvb, offset)); |
2697 | 0 | break; |
2698 | 0 | } |
2699 | | /* Create new selfm_pdu_tvb that contains only a single PDU worth of data */ |
2700 | 0 | selfm_pdu_tvb = tvb_new_subset_length( selfm_tvb, offset, tvb_get_uint8(selfm_tvb, offset+2)); |
2701 | 0 | offset += dissect_selfm(selfm_pdu_tvb, pinfo, tree, data); |
2702 | 0 | } |
2703 | | |
2704 | | /* Return the completed selfm_tvb dissected length + the count of any IAC skip bytes that were removed from the tvb payload */ |
2705 | 0 | return selfm_tvb_len + skip_byte; |
2706 | 0 | } |
2707 | | |
2708 | | /******************************************************************************************************/ |
2709 | | /* Register the protocol with Wireshark */ |
2710 | | /******************************************************************************************************/ |
2711 | | void proto_reg_handoff_selfm(void); |
2712 | | |
2713 | | void |
2714 | | proto_register_selfm(void) |
2715 | 16 | { |
2716 | | /* SEL Protocol header fields */ |
2717 | 16 | static hf_register_info selfm_hf[] = { |
2718 | 16 | { &hf_selfm_msgtype, |
2719 | 16 | { "Message Type", "selfm.msgtype", FT_UINT16, BASE_HEX|BASE_EXT_STRING, &selfm_msgtype_vals_ext, 0x0, NULL, HFILL }}, |
2720 | 16 | { &hf_selfm_padbyte, |
2721 | 16 | { "Pad Byte", "selfm.padbyte", FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL }}, |
2722 | 16 | { &hf_selfm_checksum, |
2723 | 16 | { "Checksum", "selfm.checksum", FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL }}, |
2724 | | /* "Relay Definition" specific fields */ |
2725 | 16 | { &hf_selfm_relaydef_len, |
2726 | 16 | { "Length", "selfm.relaydef.len", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }}, |
2727 | 16 | { &hf_selfm_relaydef_numproto, |
2728 | 16 | { "Number of Protocols", "selfm.relaydef.numproto", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }}, |
2729 | 16 | { &hf_selfm_relaydef_numfm, |
2730 | 16 | { "Number of Fast Meter Messages", "selfm.relaydef.numfm", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }}, |
2731 | 16 | { &hf_selfm_relaydef_numflags, |
2732 | 16 | { "Number of Status Flags", "selfm.relaydef.numflags", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }}, |
2733 | 16 | { &hf_selfm_relaydef_fmcfg_cmd, |
2734 | 16 | { "Fast Meter Config Command", "selfm.relaydef.fmcfg_cmd", FT_UINT16, BASE_HEX, NULL, 0x0, NULL, HFILL }}, |
2735 | 16 | { &hf_selfm_relaydef_fmdata_cmd, |
2736 | 16 | { "Fast Meter Data Command", "selfm.relaydef.fmdata_cmd", FT_UINT16, BASE_HEX, NULL, 0x0, NULL, HFILL }}, |
2737 | 16 | { &hf_selfm_relaydef_statbit, |
2738 | 16 | { "Status Flag Bit", "selfm.relaydef.status_bit", FT_UINT16, BASE_HEX, NULL, 0x0, NULL, HFILL }}, |
2739 | 16 | { &hf_selfm_relaydef_statbit_cmd, |
2740 | 16 | { "Status Flag Bit Response Command", "selfm.relaydef.status_bit_cmd", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }}, |
2741 | 16 | { &hf_selfm_relaydef_proto, |
2742 | 16 | { "Supported Protocol", "selfm.relaydef.proto", FT_UINT16, BASE_HEX|BASE_EXT_STRING, &selfm_relaydef_proto_vals_ext, 0x0, NULL, HFILL }}, |
2743 | | /* "Fast Meter Configuration" specific fields */ |
2744 | 16 | { &hf_selfm_fmconfig_len, |
2745 | 16 | { "Length", "selfm.fmconfig.len", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }}, |
2746 | 16 | { &hf_selfm_fmconfig_numflags, |
2747 | 16 | { "Number of Status Flags", "selfm.fmconfig.numflags", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }}, |
2748 | 16 | { &hf_selfm_fmconfig_loc_sf, |
2749 | 16 | { "Location of Scale Factor", "selfm.fmconfig.loc_sf", FT_UINT8, BASE_DEC, VALS(selfm_fmconfig_sfloc_vals), 0x0, NULL, HFILL }}, |
2750 | 16 | { &hf_selfm_fmconfig_num_sf, |
2751 | 16 | { "Number of Scale Factors", "selfm.fmconfig.num_sf", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }}, |
2752 | 16 | { &hf_selfm_fmconfig_num_ai, |
2753 | 16 | { "Number of Analog Input Channels", "selfm.fmconfig.num_ai", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }}, |
2754 | 16 | { &hf_selfm_fmconfig_num_samp, |
2755 | 16 | { "Number of Samples per AI Channel", "selfm.fmconfig.num_samp", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }}, |
2756 | 16 | { &hf_selfm_fmconfig_num_dig, |
2757 | 16 | { "Number of Digital Banks", "selfm.fmconfig.num_dig", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }}, |
2758 | 16 | { &hf_selfm_fmconfig_num_calc, |
2759 | 16 | { "Number of Calculation Blocks", "selfm.fmconfig.num_calc", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }}, |
2760 | 16 | { &hf_selfm_fmconfig_ofs_ai, |
2761 | 16 | { "First Analog Channel Offset", "selfm.fmconfig.ofs_ai", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }}, |
2762 | 16 | { &hf_selfm_fmconfig_ofs_ts, |
2763 | 16 | { "Timestamp Offset", "selfm.fmconfig.ofs_ts", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }}, |
2764 | 16 | { &hf_selfm_fmconfig_ofs_dig, |
2765 | 16 | { "First Digital Bank Offset", "selfm.fmconfig.ofs_dig", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }}, |
2766 | 16 | { &hf_selfm_fmconfig_ai_type, |
2767 | 16 | { "Analog Channel Type", "selfm.fmconfig.ai_type", FT_UINT8, BASE_DEC, VALS(selfm_fmconfig_ai_chtype_vals), 0x0, NULL, HFILL }}, |
2768 | 16 | { &hf_selfm_fmconfig_ai_sf_type, |
2769 | 16 | { "Analog Channel Scale Factor Type", "selfm.fmconfig.ai_sf_type", FT_UINT8, BASE_DEC, VALS(selfm_fmconfig_ai_sftype_vals), 0x0, NULL, HFILL }}, |
2770 | 16 | { &hf_selfm_fmconfig_ai_sf_ofs, |
2771 | 16 | { "Analog Channel Scale Factor Offset", "selfm.fmconfig.ai_sf_ofs", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }}, |
2772 | 16 | { &hf_selfm_fmconfig_cblk_rot, |
2773 | 16 | { "Rotation", "selfm.fmconfig.cblk_rot", FT_UINT8, BASE_HEX, VALS(selfm_fmconfig_cblk_rot_vals), 0x01, NULL, HFILL }}, |
2774 | 16 | { &hf_selfm_fmconfig_cblk_vconn, |
2775 | 16 | { "Voltage Connection", "selfm.fmconfig.cblk_vconn", FT_UINT8, BASE_HEX, VALS(selfm_fmconfig_cblk_vconn_vals), 0x06, NULL, HFILL }}, |
2776 | 16 | { &hf_selfm_fmconfig_cblk_iconn, |
2777 | 16 | { "Current Connection", "selfm.fmconfig.cblk_iconn", FT_UINT8, BASE_HEX, VALS(selfm_fmconfig_cblk_iconn_vals), 0x18, NULL, HFILL }}, |
2778 | 16 | { &hf_selfm_fmconfig_cblk_ctype, |
2779 | 16 | { "Calculation Type", "selfm.fmconfig.cblk_ctype", FT_UINT8, BASE_DEC, VALS(selfm_fmconfig_cblk_ctype_vals), 0x0, NULL, HFILL }}, |
2780 | 16 | { &hf_selfm_fmconfig_cblk_deskew_ofs, |
2781 | 16 | { "Skew Correction Offset", "selfm.fmconfig.cblk_deskew_ofs", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }}, |
2782 | 16 | { &hf_selfm_fmconfig_cblk_rs_ofs, |
2783 | 16 | { "Rs Offset", "selfm.fmconfig.cblk_rs_ofs", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }}, |
2784 | 16 | { &hf_selfm_fmconfig_cblk_xs_ofs, |
2785 | 16 | { "Xs Offset", "selfm.fmconfig.cblk_xs_ofs", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }}, |
2786 | 16 | { &hf_selfm_fmconfig_cblk_ia_idx, |
2787 | 16 | { "Analog Record Ia Index Position", "selfm.fmconfig.cblk_ia_idx", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }}, |
2788 | 16 | { &hf_selfm_fmconfig_cblk_ib_idx, |
2789 | 16 | { "Analog Record Ib Index Position", "selfm.fmconfig.cblk_ib_idx", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }}, |
2790 | 16 | { &hf_selfm_fmconfig_cblk_ic_idx, |
2791 | 16 | { "Analog Record Ic Index Position", "selfm.fmconfig.cblk_ic_idx", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }}, |
2792 | 16 | { &hf_selfm_fmconfig_cblk_va_idx, |
2793 | 16 | { "Analog Record Va/Vab Index Position", "selfm.fmconfig.cblk_va_idx", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }}, |
2794 | 16 | { &hf_selfm_fmconfig_cblk_vb_idx, |
2795 | 16 | { "Analog Record Vb/Vbc Index Position", "selfm.fmconfig.cblk_vb_idx", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }}, |
2796 | 16 | { &hf_selfm_fmconfig_cblk_vc_idx, |
2797 | 16 | { "Analog Record Vc/Vca Index Position", "selfm.fmconfig.cblk_vc_idx", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }}, |
2798 | 16 | { &hf_selfm_fmconfig_ai_sf_float, |
2799 | 16 | { "AI Scale Factor (float)", "selfm.fmconfig.ai_sf_float", FT_FLOAT, BASE_NONE, NULL, 0x0, NULL, HFILL }}, |
2800 | | /* "Fast Meter Data" specific fields */ |
2801 | 16 | { &hf_selfm_fmdata_len, |
2802 | 16 | { "Length", "selfm.fmdata.len", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }}, |
2803 | 16 | { &hf_selfm_fmdata_flagbyte, |
2804 | 16 | { "Status Flags Byte", "selfm.fmdata.flagbyte", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }}, |
2805 | 16 | { &hf_selfm_fmdata_ai_sf_fp, |
2806 | 16 | { "Using IEEE FP Format Scale Factor", "selfm.fmdata.ai.sf_fp",FT_FLOAT, BASE_NONE, NULL, 0x0, NULL, HFILL }}, |
2807 | 16 | { &hf_selfm_fmdata_dig_b0, |
2808 | 16 | { "Bit 0", "selfm.fmdata.dig_b0", FT_BOOLEAN, 8, NULL, 0x01, NULL, HFILL }}, |
2809 | 16 | { &hf_selfm_fmdata_dig_b1, |
2810 | 16 | { "Bit 1", "selfm.fmdata.dig_b1", FT_BOOLEAN, 8, NULL, 0x02, NULL, HFILL }}, |
2811 | 16 | { &hf_selfm_fmdata_dig_b2, |
2812 | 16 | { "Bit 2", "selfm.fmdata.dig_b2", FT_BOOLEAN, 8, NULL, 0x04, NULL, HFILL }}, |
2813 | 16 | { &hf_selfm_fmdata_dig_b3, |
2814 | 16 | { "Bit 3", "selfm.fmdata.dig_b3", FT_BOOLEAN, 8, NULL, 0x08, NULL, HFILL }}, |
2815 | 16 | { &hf_selfm_fmdata_dig_b4, |
2816 | 16 | { "Bit 4", "selfm.fmdata.dig_b4", FT_BOOLEAN, 8, NULL, 0x10, NULL, HFILL }}, |
2817 | 16 | { &hf_selfm_fmdata_dig_b5, |
2818 | 16 | { "Bit 5", "selfm.fmdata.dig_b5", FT_BOOLEAN, 8, NULL, 0x20, NULL, HFILL }}, |
2819 | 16 | { &hf_selfm_fmdata_dig_b6, |
2820 | 16 | { "Bit 6", "selfm.fmdata.dig_b6", FT_BOOLEAN, 8, NULL, 0x40, NULL, HFILL }}, |
2821 | 16 | { &hf_selfm_fmdata_dig_b7, |
2822 | 16 | { "Bit 7", "selfm.fmdata.dig_b7", FT_BOOLEAN, 8, NULL, 0x80, NULL, HFILL }}, |
2823 | | /* "Fast Operate Configuration" specific fields */ |
2824 | 16 | { &hf_selfm_foconfig_len, |
2825 | 16 | { "Length", "selfm.foconfig.len", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }}, |
2826 | 16 | { &hf_selfm_foconfig_num_brkr, |
2827 | 16 | { "Number of Breaker Bits", "selfm.foconfig.num_brkr", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }}, |
2828 | 16 | { &hf_selfm_foconfig_num_rb, |
2829 | 16 | { "Number of Remote Bits", "selfm.foconfig.num_rb", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }}, |
2830 | 16 | { &hf_selfm_foconfig_prb_supp, |
2831 | 16 | { "Remote Bit Pulse Supported", "selfm.foconfig.prb_supp", FT_UINT8, BASE_DEC, VALS(selfm_foconfig_prb_supp_vals), 0x0, NULL, HFILL }}, |
2832 | 16 | { &hf_selfm_foconfig_reserved, |
2833 | 16 | { "Reserved Bit (Future)", "selfm.foconfig.reserved", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }}, |
2834 | 16 | { &hf_selfm_foconfig_brkr_open, |
2835 | 16 | { "Breaker Bit Open Command", "selfm.foconfig.brkr_open", FT_UINT8, BASE_HEX | BASE_EXT_STRING, &selfm_fo_br_vals_ext, 0x0, NULL, HFILL }}, |
2836 | 16 | { &hf_selfm_foconfig_brkr_close, |
2837 | 16 | { "Breaker Bit Close Command", "selfm.foconfig.brkr_close", FT_UINT8, BASE_HEX | BASE_EXT_STRING, &selfm_fo_br_vals_ext, 0x0, NULL, HFILL }}, |
2838 | 16 | { &hf_selfm_foconfig_rb_cmd, |
2839 | 16 | { "Remote Bit Command", "selfm.foconfig.rb_cmd", FT_UINT8, BASE_HEX | BASE_EXT_STRING, &selfm_fo_rb_vals_ext, 0x0, NULL, HFILL }}, |
2840 | | /* "Alternate Fast Operate Configuration" specific fields */ |
2841 | 16 | { &hf_selfm_alt_foconfig_len, |
2842 | 16 | { "Length", "selfm.alt_foconfig.len", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }}, |
2843 | 16 | { &hf_selfm_alt_foconfig_num_ports, |
2844 | 16 | { "Number of Ports Available", "selfm.alt_foconfig.num_ports", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }}, |
2845 | 16 | { &hf_selfm_alt_foconfig_num_brkr, |
2846 | 16 | { "Number of Breaker Bits per Port", "selfm.alt_foconfig.num_brkr", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }}, |
2847 | 16 | { &hf_selfm_alt_foconfig_num_rb, |
2848 | 16 | { "Number of Remote Bits per Port", "selfm.alt_foconfig.num_rb", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }}, |
2849 | 16 | { &hf_selfm_alt_foconfig_funccode, |
2850 | 16 | { "Supported Function Code", "selfm.alt_foconfig.funccode", FT_UINT8, BASE_HEX, VALS(selfm_foconfig_alt_funccode_vals), 0x0, NULL, HFILL }}, |
2851 | | /* "Fast Operate Command" specific fields */ |
2852 | 16 | { &hf_selfm_fastop_len, |
2853 | 16 | { "Length", "selfm.fastop.len", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }}, |
2854 | 16 | { &hf_selfm_fastop_rb_code, |
2855 | 16 | { "Remote Bit Operate Code", "selfm.fastop.rb_code", FT_UINT8, BASE_HEX | BASE_EXT_STRING, &selfm_fo_rb_vals_ext, 0x0, NULL, HFILL }}, |
2856 | 16 | { &hf_selfm_fastop_br_code, |
2857 | 16 | { "Breaker Bit Operate Code", "selfm.fastop.br_code", FT_UINT8, BASE_HEX | BASE_EXT_STRING, &selfm_fo_br_vals_ext, 0x0, NULL, HFILL }}, |
2858 | 16 | { &hf_selfm_fastop_valid, |
2859 | 16 | { "Operate Code Validation", "selfm.fastop.valid", FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL }}, |
2860 | | /* "Alternate Fast Operate Command" specific fields */ |
2861 | 16 | { &hf_selfm_alt_fastop_len, |
2862 | 16 | { "Length", "selfm.alt_fastop.len", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }}, |
2863 | 16 | { &hf_selfm_alt_fastop_code, |
2864 | 16 | { "Operate Code", "selfm.alt_fastop.code", FT_UINT16, BASE_HEX, NULL, 0x0, NULL, HFILL }}, |
2865 | 16 | { &hf_selfm_alt_fastop_valid, |
2866 | 16 | { "Operate Code Validation", "selfm.alt_fastop.valid", FT_UINT16, BASE_HEX, NULL, 0x0, NULL, HFILL }}, |
2867 | | /* "Fast Message" specific fields */ |
2868 | 16 | { &hf_selfm_fastmsg_len, |
2869 | 16 | { "Length", "selfm.fastmsg.len", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }}, |
2870 | 16 | { &hf_selfm_fastmsg_routing_addr, |
2871 | 16 | { "Routing Address (future)", "selfm.fastmsg.routing_addr", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }}, |
2872 | 16 | { &hf_selfm_fastmsg_status, |
2873 | 16 | { "Status Byte", "selfm.fastmsg.status", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }}, |
2874 | 16 | { &hf_selfm_fastmsg_funccode, |
2875 | 16 | { "Function Code", "selfm.fastmsg.funccode", FT_UINT8, BASE_HEX | BASE_EXT_STRING, &selfm_fastmsg_func_code_vals_ext, 0x0, NULL, HFILL }}, |
2876 | 16 | { &hf_selfm_fastmsg_response_code, |
2877 | 16 | { "Response Code", "selfm.fastmsg.responsecode", FT_UINT8, BASE_HEX | BASE_EXT_STRING, &selfm_fastmsg_ack_responsecode_vals_ext, 0x0, NULL, HFILL }}, |
2878 | 16 | { &hf_selfm_fastmsg_seq, |
2879 | 16 | { "Sequence Byte", "selfm.fastmsg.seq", FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL }}, |
2880 | 16 | { &hf_selfm_fastmsg_seq_fir, |
2881 | 16 | { "FIR", "selfm.fastmsg.seq_fir", FT_BOOLEAN, 8, NULL, FAST_MSG_SEQ_FIR, NULL, HFILL }}, |
2882 | 16 | { &hf_selfm_fastmsg_seq_fin, |
2883 | 16 | { "FIN", "selfm.fastmsg.seq_fin", FT_BOOLEAN, 8, NULL, FAST_MSG_SEQ_FIN, NULL, HFILL }}, |
2884 | 16 | { &hf_selfm_fastmsg_seq_cnt, |
2885 | 16 | { "Count", "selfm.fastmsg.seq_cnt", FT_UINT8, BASE_DEC, NULL, FAST_MSG_SEQ_CNT, "Frame Count Number", HFILL }}, |
2886 | 16 | { &hf_selfm_fastmsg_resp_num, |
2887 | 16 | { "Response Number", "selfm.fastmsg.resp_num", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }}, |
2888 | 16 | { &hf_selfm_fastmsg_crc16, |
2889 | 16 | { "CRC-16", "selfm.fastmsg.crc16", FT_UINT16, BASE_HEX, NULL, 0x0, NULL, HFILL }}, |
2890 | 16 | { &hf_selfm_fastmsg_def_route_sup, |
2891 | 16 | { "Routing Support", "selfm.fastmsg.def_route_sup", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }}, |
2892 | 16 | { &hf_selfm_fastmsg_def_rx_stat, |
2893 | 16 | { "Status RX", "selfm.fastmsg.def_rx_stat", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }}, |
2894 | 16 | { &hf_selfm_fastmsg_def_tx_stat, |
2895 | 16 | { "Status TX", "selfm.fastmsg.def_tx_stat", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }}, |
2896 | 16 | { &hf_selfm_fastmsg_def_rx_maxfr, |
2897 | 16 | { "Max Frames RX", "selfm.fastmsg.def_rx_maxfr", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }}, |
2898 | 16 | { &hf_selfm_fastmsg_def_tx_maxfr, |
2899 | 16 | { "Max Frames TX", "selfm.fastmsg.def_tx_maxfr", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }}, |
2900 | 16 | { &hf_selfm_fastmsg_def_rx_num_fc, |
2901 | 16 | { "Number of Supported RX Function Codes", "selfm.fastmsg.def_rx_num_fc", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }}, |
2902 | 16 | { &hf_selfm_fastmsg_def_rx_fc, |
2903 | 16 | { "Receive Function Code", "selfm.fastmsg.def_rx_fc", FT_UINT8, BASE_HEX | BASE_EXT_STRING, &selfm_fastmsg_func_code_vals_ext, 0x0, NULL, HFILL }}, |
2904 | 16 | { &hf_selfm_fastmsg_def_tx_num_fc, |
2905 | 16 | { "Number of Supported TX Function Codes", "selfm.fastmsg.def_tx_num_fc", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }}, |
2906 | 16 | { &hf_selfm_fastmsg_def_tx_fc, |
2907 | 16 | { "Transmit Function Code", "selfm.fastmsg.def_tx_fc", FT_UINT8, BASE_HEX | BASE_EXT_STRING, &selfm_fastmsg_func_code_vals_ext, 0x0, NULL, HFILL }}, |
2908 | 16 | { &hf_selfm_fastmsg_uns_en_fc, |
2909 | 16 | { "Function Code to Enable", "selfm.fastmsg.uns_en_fc", FT_UINT8, BASE_HEX | BASE_EXT_STRING, &selfm_fastmsg_func_code_vals_ext, 0x0, NULL, HFILL }}, |
2910 | 16 | { &hf_selfm_fastmsg_uns_en_fc_data, |
2911 | 16 | { "Function Code Data", "selfm.fastmsg.uns_en_fc_data", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }}, |
2912 | 16 | { &hf_selfm_fastmsg_uns_dis_fc, |
2913 | 16 | { "Function Code to Disable", "selfm.fastmsg.uns_dis_fc", FT_UINT8, BASE_HEX | BASE_EXT_STRING, &selfm_fastmsg_func_code_vals_ext, 0x0, NULL, HFILL }}, |
2914 | 16 | { &hf_selfm_fastmsg_uns_dis_fc_data, |
2915 | 16 | { "Function Code Data", "selfm.fastmsg.uns_dis_fc_data", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }}, |
2916 | 16 | { &hf_selfm_fastmsg_unsresp_orig, |
2917 | 16 | { "Origination path", "selfm.fastmsg.unsresp_orig", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }}, |
2918 | 16 | { &hf_selfm_fastmsg_unsresp_doy, |
2919 | 16 | { "Day of Year", "selfm.fastmsg.unsresp_doy", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }}, |
2920 | 16 | { &hf_selfm_fastmsg_unsresp_year, |
2921 | 16 | { "Year", "selfm.fastmsg.unsresp_year", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }}, |
2922 | 16 | { &hf_selfm_fastmsg_unsresp_todms, |
2923 | 16 | { "Time of Day (in ms)", "selfm.fastmsg.unsresp_todms", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }}, |
2924 | 16 | { &hf_selfm_fastmsg_unsresp_num_elmt, |
2925 | 16 | { "Number of SER Elements", "selfm.fastmsg.unsresp_num_elmt", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }}, |
2926 | 16 | { &hf_selfm_fastmsg_unsresp_elmt_idx, |
2927 | 16 | { "SER Element Index", "selfm.fastmsg.unsresp_elmt_idx", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }}, |
2928 | 16 | { &hf_selfm_fastmsg_unsresp_elmt_ts_ofs, |
2929 | 16 | { "SER Element Timestamp Offset (us)", "selfm.fastmsg.unsresp_elmt_ts_ofs", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }}, |
2930 | 16 | { &hf_selfm_fastmsg_unsresp_elmt_status, |
2931 | 16 | { "SER Element Status", "selfm.fastmsg.unsresp_elmt_status", FT_UINT8, BASE_DEC, VALS(selfm_ser_status_vals), 0x0, NULL, HFILL }}, |
2932 | 16 | { &hf_selfm_fastmsg_unsresp_eor, |
2933 | 16 | { "End of Record Indicator", "selfm.fastmsg.unsresp_eor", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }}, |
2934 | 16 | { &hf_selfm_fastmsg_unsresp_elmt_statword, |
2935 | 16 | { "SER Element Status Word", "selfm.fastmsg.unsresp_elmt_statword", FT_UINT32, BASE_HEX, NULL, 0x0, NULL, HFILL }}, |
2936 | 16 | { &hf_selfm_fastmsg_unswrite_addr1, |
2937 | 16 | { "Write Address Region #1", "selfm.fastmsg.unswrite_addr1", FT_UINT16, BASE_HEX | BASE_EXT_STRING, &selfm_fastmsg_unswrite_com_vals_ext, 0x0, NULL, HFILL }}, |
2938 | 16 | { &hf_selfm_fastmsg_unswrite_addr2, |
2939 | 16 | { "Write Address Region #2", "selfm.fastmsg.unswrite_addr2", FT_UINT16, BASE_HEX, NULL, 0x0, NULL, HFILL }}, |
2940 | 16 | { &hf_selfm_fastmsg_unswrite_num_reg, |
2941 | 16 | { "Number of Registers", "selfm.fastmsg.unswrite_num_reg", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }}, |
2942 | 16 | { &hf_selfm_fastmsg_unswrite_reg_val, |
2943 | 16 | { "Register Value", "selfm.fastmsg.unswrite_reg_val", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }}, |
2944 | 16 | { &hf_selfm_fastmsg_baseaddr, |
2945 | 16 | { "Base Address", "selfm.fastmsg.baseaddr", FT_UINT32, BASE_HEX, NULL, 0x0, NULL, HFILL }}, |
2946 | 16 | { &hf_selfm_fastmsg_numwords, |
2947 | 16 | { "Number of 16-bit Words", "selfm.fastmsg.numwords", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }}, |
2948 | 16 | { &hf_selfm_fastmsg_flags, |
2949 | 16 | { "Flag Word", "selfm.fastmsg.flags", FT_UINT16, BASE_HEX, NULL, 0x0, NULL, HFILL }}, |
2950 | 16 | { &hf_selfm_fastmsg_datafmt_resp_numitem, |
2951 | 16 | { "Number of Data Items Records", "selfm.fastmsg.datafmt_resp_numitem", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }}, |
2952 | 16 | { &hf_selfm_fastmsg_dataitem_qty, |
2953 | 16 | { "Data Item Quantity", "selfm.fastmsg.dataitem_qty", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }}, |
2954 | 16 | { &hf_selfm_fastmsg_dataitem_type, |
2955 | 16 | { "Data Item Type", "selfm.fastmsg.dataitem_type", FT_UINT16, BASE_HEX, VALS(selfm_fastmsg_tagtype_vals), 0x0, NULL, HFILL }}, |
2956 | 16 | { &hf_selfm_fastmsg_dataitem_uint16, |
2957 | 16 | { "(uint16)", "selfm.fastmsg.dataitem_uint16", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }}, |
2958 | 16 | { &hf_selfm_fastmsg_dataitem_int16, |
2959 | 16 | { "(int16)", "selfm.fastmsg.dataitem_int16", FT_INT16, BASE_DEC, NULL, 0x0, NULL, HFILL }}, |
2960 | 16 | { &hf_selfm_fastmsg_dataitem_uint32, |
2961 | 16 | { "(uint32)", "selfm.fastmsg.dataitem_uint32", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }}, |
2962 | 16 | { &hf_selfm_fastmsg_dataitem_int32, |
2963 | 16 | { "(int32)", "selfm.fastmsg.dataitem_int32", FT_INT32, BASE_DEC, NULL, 0x0, NULL, HFILL }}, |
2964 | 16 | { &hf_selfm_fastmsg_dataitem_float, |
2965 | 16 | { "(float)", "selfm.fastmsg.dataitem_float", FT_FLOAT, BASE_NONE, NULL, 0x0, NULL, HFILL }}, |
2966 | 16 | { &hf_selfm_fastmsg_devdesc_num_region, |
2967 | 16 | { "Number of Data Regions", "selfm.fastmsg.devdesc_num_region", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }}, |
2968 | 16 | { &hf_selfm_fastmsg_devdesc_num_ctrl, |
2969 | 16 | { "Number of Control Regions", "selfm.fastmsg.devdesc_num_ctrl", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }}, |
2970 | 16 | { &hf_selfm_fastmsg_soe_req_orig, |
2971 | 16 | { "Origination path", "selfm.fastmsg.soe_req_orig", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }}, |
2972 | 16 | { &hf_selfm_fastmsg_soe_resp_numblks, |
2973 | 16 | { "Number of Blocks", "selfm.fastmsg.soe_resp_numblks", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }}, |
2974 | 16 | { &hf_selfm_fastmsg_soe_resp_orig, |
2975 | 16 | { "Origination path", "selfm.fastmsg.soe_resp_orig", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }}, |
2976 | 16 | { &hf_selfm_fastmsg_soe_resp_numbits, |
2977 | 16 | { "Number of Bits", "selfm.fastmsg.soe_resp_numbits", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }}, |
2978 | 16 | { &hf_selfm_fastmsg_soe_resp_pad, |
2979 | 16 | { "Pad Byte", "selfm.fastmsg.soe_resp_pad", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }}, |
2980 | 16 | { &hf_selfm_fastmsg_soe_resp_doy, |
2981 | 16 | { "Day of Year", "selfm.fastmsg.soe_resp_doy", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }}, |
2982 | 16 | { &hf_selfm_fastmsg_soe_resp_year, |
2983 | 16 | { "Year", "selfm.fastmsg.soe_resp_year", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }}, |
2984 | 16 | { &hf_selfm_fastmsg_soe_resp_tod, |
2985 | 16 | { "Time of Day (ms)", "selfm.fastmsg.soe_resp_tod", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }}, |
2986 | 16 | { &hf_selfm_fastmsg_soe_resp_data, |
2987 | 16 | { "Packed Binary State Data", "selfm.fastmsg.soe_resp_data", FT_UINT16, BASE_HEX, NULL, 0x0, NULL, HFILL }}, |
2988 | | |
2989 | | /* "Fast Message" Re-assembly header fields */ |
2990 | 16 | { &hf_selfm_fragment, |
2991 | 16 | { "SEL Fast Msg Response Data Fragment", "selfm.respdata.fragment", FT_FRAMENUM, BASE_NONE, NULL, 0x0, "SEL Fast Message Response Data Fragment", HFILL }}, |
2992 | 16 | { &hf_selfm_fragments, |
2993 | 16 | { "SEL Fast Msg Response Data Fragments", "selfm.respdata.fragments", FT_NONE, BASE_NONE, NULL, 0x0, "SEL Fast Message Response Data Fragments", HFILL }}, |
2994 | 16 | { &hf_selfm_fragment_overlap, |
2995 | 16 | { "Fragment overlap", "selfm.respdata.fragment.overlap", FT_BOOLEAN, BASE_NONE, NULL, 0x0, "Fragment overlaps with other fragments", HFILL }}, |
2996 | 16 | { &hf_selfm_fragment_overlap_conflict, |
2997 | 16 | { "Conflicting data in fragment overlap", "selfm.respdata.fragment.overlap.conflict", FT_BOOLEAN, BASE_NONE, NULL, 0x0, "Overlapping fragments contained conflicting data", HFILL }}, |
2998 | 16 | { &hf_selfm_fragment_multiple_tails, |
2999 | 16 | { "Multiple tail fragments found", "selfm.respdata.fragment.multipletails", FT_BOOLEAN, BASE_NONE, NULL, 0x0, "Several tails were found when defragmenting the packet", HFILL }}, |
3000 | 16 | { &hf_selfm_fragment_too_long_fragment, |
3001 | 16 | { "Fragment too long", "selfm.respdata.fragment.toolongfragment", FT_BOOLEAN, BASE_NONE, NULL, 0x0, "Fragment contained data past end of packet", HFILL }}, |
3002 | 16 | { &hf_selfm_fragment_error, |
3003 | 16 | { "Defragmentation error", "selfm.respdata.fragment.error", FT_FRAMENUM, BASE_NONE, NULL, 0x0, "Defragmentation error due to illegal fragments", HFILL }}, |
3004 | 16 | { &hf_selfm_fragment_count, |
3005 | 16 | { "Fragment count", "selfm.respdata.fragment.count", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }}, |
3006 | 16 | { &hf_selfm_fragment_reassembled_in, |
3007 | 16 | { "Reassembled PDU In Frame", "selfm.respdata.fragment.reassembled_in", FT_FRAMENUM, BASE_NONE, NULL, 0x0, "This PDU is reassembled in this frame", HFILL }}, |
3008 | 16 | { &hf_selfm_fragment_reassembled_length, |
3009 | 16 | { "Reassembled SEL Fast Msg length", "selfm.respdata.fragment.reassembled.length", FT_UINT32, BASE_DEC, NULL, 0x0, "The total length of the reassembled payload", HFILL }}, |
3010 | | /* Generated from convert_proto_tree_add_text.pl */ |
3011 | 16 | { &hf_selfm_fmconfig_ai_channel, { "Analog Channel Name", "selfm.fmconfig.ai_channel", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }}, |
3012 | 16 | { &hf_selfm_fmdata_ai_value16, { "Value (Raw)", "selfm.fmdata.ai.value16", FT_INT16, BASE_DEC, NULL, 0x0, NULL, HFILL }}, |
3013 | 16 | { &hf_selfm_fmdata_ai_scale_factor, { "Value (w/ Scale Factor)", "selfm.fmdata.ai.value_scale_factor", FT_FLOAT, BASE_NONE, NULL, 0x0, NULL, HFILL }}, |
3014 | 16 | { &hf_selfm_fmdata_ai_value_float, { "Value", "selfm.fmdata.ai.value_float", FT_FLOAT, BASE_NONE, NULL, 0x0, NULL, HFILL }}, |
3015 | 16 | { &hf_selfm_fmdata_ai_value_double, { "Value", "selfm.fmdata.ai.value_double", FT_DOUBLE, BASE_NONE, NULL, 0x0, NULL, HFILL }}, |
3016 | 16 | { &hf_selfm_fmdata_data_type, { "Data_Type", "selfm.fmdata.data_type", FT_UINT32, BASE_DEC, VALS(selfm_fastmsg_tagtype_vals), 0x0, NULL, HFILL }}, |
3017 | 16 | { &hf_selfm_fmdata_quantity, { "Quantity", "selfm.fmdata.quantity", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }}, |
3018 | 16 | { &hf_selfm_fmdata_ai_value_string, { "Value", "selfm.fmdata.ai.value_string", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }}, |
3019 | 16 | { &hf_selfm_fastmsg_unsresp_elmt_ts_ofs_decoded, { "SER Element Timestamp Offset (decoded)", "selfm.fastmsg.unsresp_elmt_ts_ofs.decoded", FT_UINT24, BASE_DEC, NULL, 0x0, NULL, HFILL }}, |
3020 | 16 | { &hf_selfm_fid, { "FID", "selfm.fid", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }}, |
3021 | 16 | { &hf_selfm_rid, { "RID", "selfm.rid", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }}, |
3022 | 16 | { &hf_selfm_fastmsg_data_region_name, { "Data Region Name", "selfm.fastmsg.data_region_name", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }}, |
3023 | 16 | { &hf_selfm_fmdata_timestamp, { "Timestamp", "selfm.fmdata.timestamp", FT_ABSOLUTE_TIME, ABSOLUTE_TIME_LOCAL, NULL, 0x0, NULL, HFILL }}, |
3024 | 16 | { &hf_selfm_fmdata_frame_data_format_reference, { "Frame Data Format Reference", "selfm.fmdata.frame_data_format_reference", FT_FRAMENUM, BASE_NONE, NULL, 0x0, NULL, HFILL }}, |
3025 | 16 | { &hf_selfm_fastmsg_bit_label_name, { "Bit Label Name", "selfm.fastmsg.bit_label_name", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }}, |
3026 | 16 | }; |
3027 | | |
3028 | | /* Register expert fields */ |
3029 | 16 | static ei_register_info selfm_ei[] = { |
3030 | 16 | { &ei_selfm_crc16_incorrect, { "selfm.crc16.incorrect", PI_CHECKSUM, PI_WARN, "Incorrect CRC", EXPFILL }} |
3031 | 16 | }; |
3032 | | |
3033 | | /* Setup protocol subtree array */ |
3034 | 16 | static int *ett[] = { |
3035 | 16 | &ett_selfm, |
3036 | 16 | &ett_selfm_relaydef, |
3037 | 16 | &ett_selfm_relaydef_fm, |
3038 | 16 | &ett_selfm_relaydef_proto, |
3039 | 16 | &ett_selfm_relaydef_flags, |
3040 | 16 | &ett_selfm_fmconfig, |
3041 | 16 | &ett_selfm_fmconfig_ai, |
3042 | 16 | &ett_selfm_fmconfig_calc, |
3043 | 16 | &ett_selfm_foconfig, |
3044 | 16 | &ett_selfm_foconfig_brkr, |
3045 | 16 | &ett_selfm_foconfig_rb, |
3046 | 16 | &ett_selfm_fastop, |
3047 | 16 | &ett_selfm_fmdata, |
3048 | 16 | &ett_selfm_fmdata_ai, |
3049 | 16 | &ett_selfm_fmdata_dig, |
3050 | 16 | &ett_selfm_fmdata_ai_ch, |
3051 | 16 | &ett_selfm_fmdata_dig_ch, |
3052 | 16 | &ett_selfm_fastmsg, |
3053 | 16 | &ett_selfm_fastmsg_seq, |
3054 | 16 | &ett_selfm_fastmsg_def_fc, |
3055 | 16 | &ett_selfm_fastmsg_tag, |
3056 | 16 | &ett_selfm_fastmsg_element_list, |
3057 | 16 | &ett_selfm_fastmsg_element, |
3058 | 16 | &ett_selfm_fastmsg_datareg, |
3059 | 16 | &ett_selfm_fastmsg_soeblk, |
3060 | 16 | &ett_selfm_fragment, |
3061 | 16 | &ett_selfm_fragments |
3062 | | |
3063 | 16 | }; |
3064 | | |
3065 | 16 | module_t *selfm_module; |
3066 | 16 | expert_module_t* expert_selfm; |
3067 | | |
3068 | 16 | reassembly_table_register(&selfm_reassembly_table, |
3069 | 16 | &addresses_reassembly_table_functions); |
3070 | | |
3071 | | /* Register the protocol name and description */ |
3072 | 16 | proto_selfm = proto_register_protocol("SEL Protocol", "SEL Protocol", "selfm"); |
3073 | | |
3074 | | /* Registering protocol to be called by another dissector */ |
3075 | 16 | selfm_handle = register_dissector("selfm", dissect_selfm_tcp, proto_selfm); |
3076 | | |
3077 | | /* Required function calls to register the header fields and subtrees used */ |
3078 | 16 | proto_register_field_array(proto_selfm, selfm_hf, array_length(selfm_hf)); |
3079 | 16 | proto_register_subtree_array(ett, array_length(ett)); |
3080 | 16 | expert_selfm = expert_register_protocol(proto_selfm); |
3081 | 16 | expert_register_field_array(expert_selfm, selfm_ei, array_length(selfm_ei)); |
3082 | | |
3083 | | |
3084 | | /* Register required preferences for SEL Protocol register decoding */ |
3085 | 16 | selfm_module = prefs_register_protocol(proto_selfm, NULL); |
3086 | | |
3087 | | /* SEL Protocol - Desegmentmentation; defaults to true for TCP desegmentation*/ |
3088 | 16 | prefs_register_bool_preference(selfm_module, "desegment", |
3089 | 16 | "Desegment packets spanning multiple TCP segments", |
3090 | 16 | "Whether the SEL Protocol dissector should desegment all messages spanning multiple TCP segments", |
3091 | 16 | &selfm_desegment); |
3092 | | |
3093 | | /* SEL Protocol - Telnet protocol IAC (0xFF) processing; defaults to true to allow Telnet Encapsulated Data */ |
3094 | 16 | prefs_register_bool_preference(selfm_module, "telnetclean", |
3095 | 16 | "Remove extra 0xFF (Telnet IAC) bytes", |
3096 | 16 | "Whether the SEL Protocol dissector should automatically pre-process Telnet data to remove duplicate 0xFF IAC bytes", |
3097 | 16 | &selfm_telnet_clean); |
3098 | | |
3099 | | /* SEL Protocol Preference - Disable/Enable CRC verification, */ |
3100 | 16 | prefs_register_bool_preference(selfm_module, "crc_verification", "Validate Fast Message CRC16", |
3101 | 16 | "Perform CRC16 validation on Fast Messages", |
3102 | 16 | &selfm_crc16); |
3103 | | |
3104 | 16 | prefs_register_string_preference(selfm_module, "ser_list", |
3105 | 16 | "SER Index List", "List of word bits contained in SER equations (Comma-separated, no Quotes or Checksums)", &selfm_ser_list); |
3106 | | |
3107 | | |
3108 | 16 | } |
3109 | | |
3110 | | /******************************************************************************************************/ |
3111 | | /* If this dissector uses sub-dissector registration add a registration routine. |
3112 | | This format is required because a script is used to find these routines and |
3113 | | create the code that calls these routines. |
3114 | | */ |
3115 | | /******************************************************************************************************/ |
3116 | | void |
3117 | | proto_reg_handoff_selfm(void) |
3118 | 16 | { |
3119 | 16 | dissector_add_for_decode_as_with_preference("tcp.port", selfm_handle); |
3120 | 16 | dissector_add_for_decode_as("rtacser.data", selfm_handle); |
3121 | 16 | } |
3122 | | |
3123 | | /* |
3124 | | * Editor modelines - https://www.wireshark.org/tools/modelines.html |
3125 | | * |
3126 | | * Local variables: |
3127 | | * c-basic-offset: 4 |
3128 | | * tab-width: 8 |
3129 | | * indent-tabs-mode: nil |
3130 | | * End: |
3131 | | * |
3132 | | * vi: set shiftwidth=4 tabstop=8 expandtab: |
3133 | | * :indentSize=4:tabSize=8:noTabs=true: |
3134 | | */ |