Revert "TODO epan/dissectors/asn1/kerberos/packet-kerberos-template.c new GSS flags"
[wireshark-sm.git] / epan / dissectors / packet-locamation-im.c
blob7ccc3c6c5adac5e7d418104f8ff7e8f6e9241542
1 /* packet-locamation-im.c
2 * Routines for Locamation Interface Modules packet disassembly.
4 * Copyright (c) 2022 Locamation BV.
6 * Wireshark - Network traffic analyzer
7 * By Gerald Combs <gerald@wireshark.org>
8 * Copyright 1998 Gerald Combs
10 * SPDX-License-Identifier: GPL-2.0-or-later
14 * Locamation Interface Modules
16 * The modules send SNAP packets.
18 * Several types of IMs are supported:
19 * - Current Interface Module (CIM), version 1
20 * - Current Interface Module (CIM), version 2, revision 0
21 * - Voltage Interface Module (VIM), version 1
22 * - Voltage Interface Module (VIM), version 2, revision 0
25 /* clang-format off */
26 #include "config.h"
27 #include <epan/packet.h>
28 /* clang-format on */
30 #include <epan/expert.h>
31 #include <epan/tfs.h>
32 #include <wsutil/array.h>
34 #include "packet-llc.h"
36 #ifndef ETH_FRAME_LEN
37 #define ETH_FRAME_LEN 1514 /* Max. octets in frame sans FCS */
38 #endif
41 * ########################################################################
42 * #
43 * # Forward Declarations
44 * #
45 * ########################################################################
48 void proto_register_locamation_im(void);
49 void proto_reg_handoff_locamation_im(void);
52 * ########################################################################
53 * #
54 * # Defines
55 * #
56 * ########################################################################
59 #define COMPANY_NAME "Locamation"
60 #define COMPANY_OUI 0x0040d6
62 #define COMPANY_IM_TEXT "Interface Module"
64 #define COMPANY_PID_CALIBRATION 0x0000
65 #define COMPANY_PID_IDENT 0xffff
66 #define COMPANY_PID_SAMPLES_IM1 0x0002
67 #define COMPANY_PID_SAMPLES_IM2R0 0x000e
69 #define PROTOCOL_NAME_IM_CALIBRATION "CALIBRATION"
70 #define PROTOCOL_NAME_IM_IDENT "IDENT"
71 #define PROTOCOL_NAME_IM_SAMPLES_IM1 "SAMPLES - IM1"
72 #define PROTOCOL_NAME_IM_SAMPLES_IM2R0 "SAMPLES - IM2R0"
74 #define PROTOCOL_NAME_CALIBRATION (COMPANY_NAME " " COMPANY_IM_TEXT " " PROTOCOL_NAME_IM_CALIBRATION)
75 #define PROTOCOL_NAME_IDENT (COMPANY_NAME " " COMPANY_IM_TEXT " " PROTOCOL_NAME_IM_IDENT)
76 #define PROTOCOL_NAME_SAMPLES_IM1 (COMPANY_NAME " " COMPANY_IM_TEXT " " PROTOCOL_NAME_IM_SAMPLES_IM1)
77 #define PROTOCOL_NAME_SAMPLES_IM2R0 (COMPANY_NAME " " COMPANY_IM_TEXT " " PROTOCOL_NAME_IM_SAMPLES_IM2R0)
79 #define PROTOCOL_SHORTNAME_CALIBRATION PROTOCOL_NAME_IM_CALIBRATION
80 #define PROTOCOL_SHORTNAME_IDENT PROTOCOL_NAME_IM_IDENT
81 #define PROTOCOL_SHORTNAME_SAMPLES_IM1 PROTOCOL_NAME_IM_SAMPLES_IM1
82 #define PROTOCOL_SHORTNAME_SAMPLES_IM2R0 PROTOCOL_NAME_IM_SAMPLES_IM2R0
84 #define MASK_SAMPLES_CONTROL_TYPE 0x80
85 #define MASK_SAMPLES_CONTROL_SIMULATED 0x40
86 #define MASK_SAMPLES_CONTROL_VERSION 0x30
87 #define MASK_SAMPLES_CONTROL_SEQUENCE_NUMBER 0x0f
89 #define MASK_RANGES_SAMPLE_8 0xc000
90 #define MASK_RANGES_SAMPLE_7 0x3000
91 #define MASK_RANGES_SAMPLE_6 0x0c00
92 #define MASK_RANGES_SAMPLE_5 0x0300
93 #define MASK_RANGES_SAMPLE_4 0x00c0
94 #define MASK_RANGES_SAMPLE_3 0x0030
95 #define MASK_RANGES_SAMPLE_2 0x000c
96 #define MASK_RANGES_SAMPLE_1 0x0003
98 #define MASK_TIMESTAMP_ADDITIONAL_STATUS_HOLDOVER_STATE 0x01
99 #define MASK_TIMESTAMP_ADDITIONAL_STATUS_MASTER_CLOCK_SWITCH 0x02
102 * ########################################################################
104 * # PID Table
106 * ########################################################################
109 static const value_string company_pid_vals[] = {
110 {COMPANY_PID_CALIBRATION, PROTOCOL_NAME_IM_CALIBRATION},
111 {COMPANY_PID_IDENT, PROTOCOL_NAME_IM_IDENT},
112 {COMPANY_PID_SAMPLES_IM1, PROTOCOL_NAME_IM_SAMPLES_IM1},
113 {COMPANY_PID_SAMPLES_IM2R0, PROTOCOL_NAME_IM_SAMPLES_IM2R0},
114 {0, NULL}};
117 * ########################################################################
119 * # Types
121 * ########################################################################
125 * struct _sample_set_t {
126 * uint16_t ranges;
127 * int32_t sample_1;
128 * int32_t sample_2;
129 * int32_t sample_3;
130 * int32_t sample_4;
131 * int32_t sample_5;
132 * int32_t sample_6;
133 * int32_t sample_7;
134 * int32_t sample_8;
135 * };
137 #define SAMPLE_SET_SIZE 34
140 * struct _timestamp_t {
141 * uint8_t sync_status;
142 * uint8_t additional_status;
143 * uint32_t sec;
144 * uint32_t nsec;
145 * };
147 #define TIMESTAMP_SIZE 10
150 * struct _timestamps_t {
151 * uint8_t version;
152 * uint24_t reserved;
153 * struct _timestamp_t timestamps[8];
154 * };
156 #define TIMESTAMPS_SIZE 84
159 * ########################################################################
161 * # Helpers
163 * ########################################################################
166 static void add_split_lines(packet_info *pinfo, tvbuff_t *tvb, int tvb_offset, proto_tree *tree, int hf) {
167 int offset = tvb_offset;
168 int next_offset;
169 while (tvb_offset_exists(tvb, offset)) {
170 int len = tvb_find_line_end(tvb, offset, -1, &next_offset, false);
171 if (len == -1) {
172 break;
175 char *line = tvb_get_string_enc(pinfo->pool, tvb, offset, len, ENC_UTF_8);
176 proto_tree_add_string_format_value(tree, hf, tvb, offset, (next_offset - offset), line, "%s", line);
177 offset = next_offset;
182 * ########################################################################
184 * # CALIBRATION
186 * ########################################################################
188 * Calibration Packets
190 * Calibration Packets are sent by IM1 sensors.
192 * The calibration packets are sent in a burst, with a header packet
193 * followed by a number of chunk packets. Both packet types start with a
194 * Sequence Number.
196 * The calibration file can be reconstructed by appending all chunk packets
197 * in the Sequence Number order.
199 * Sequence Number: 2 bytes, unsigned
200 * == 0: Header Packet
201 * != 0: Chunk Packet
203 * Header Packet
204 * =============
205 * Sequence Number : 2 bytes, unsigned (fixed value 0)
206 * First Sequence Number: 2 bytes, unsigned (fixed value 1)
207 * Last Sequence Number : 2 bytes, unsigned (N)
208 * Name : string
210 * Chunk Packet
211 * ============
212 * Sequence Number : 2 bytes, unsigned (1 <= Sequence Number <= N)
213 * Calibration Chunk: string
216 static int hf_calibration_sequence_number;
217 static int hf_calibration_first_sequence_number;
218 static int hf_calibration_last_sequence_number;
219 static int hf_calibration_name;
220 static int hf_calibration_name_line;
221 static int hf_calibration_chunk;
222 static int hf_calibration_chunk_line;
224 static hf_register_info protocol_registration_calibration[] = {
225 {&hf_calibration_sequence_number, {"Sequence Number", "locamation-im.calibration.sequence_number", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL}},
226 {&hf_calibration_first_sequence_number, {"First Sequence Number", "locamation-im.calibration.first_sequence_number", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL}},
227 {&hf_calibration_last_sequence_number, {"Last Sequence Number", "locamation-im.calibration.last_sequence_number", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL}},
228 {&hf_calibration_name, {"Name", "locamation-im.calibration.name", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL}},
229 {&hf_calibration_name_line, {"Name Line", "locamation-im.calibration.name.line", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL}},
230 {&hf_calibration_chunk, {"Chunk", "locamation-im.calibration.chunk", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL}},
231 {&hf_calibration_chunk_line, {"Chunk Line", "locamation-im.calibration.chunk.line", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL}}};
233 static expert_field ei_calibration_header;
235 static ei_register_info ei_calibration[] = {
236 {&ei_calibration_header, {"locamation-im.calibration.header", PI_SEQUENCE, PI_NOTE, "Header Packet", EXPFILL}}};
238 static int h_protocol_calibration = -1;
240 static int ett_protocol_calibration;
241 static int ett_calibration_lines;
243 static int dissect_calibration(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_) {
244 col_set_str(pinfo->cinfo, COL_PROTOCOL, PROTOCOL_SHORTNAME_CALIBRATION);
245 col_set_str(pinfo->cinfo, COL_INFO, PROTOCOL_NAME_CALIBRATION);
247 proto_item *calibration_item = proto_tree_add_item(tree, h_protocol_calibration, tvb, 0, -1, ENC_NA);
248 proto_tree *calibration_item_subtree = proto_item_add_subtree(calibration_item, ett_protocol_calibration);
250 int tvb_offset = 0;
252 /* Sequence Number */
253 int item_size = 2;
254 tvb_ensure_bytes_exist(tvb, tvb_offset, item_size);
255 uint16_t sequence_number = tvb_get_uint16(tvb, 0, ENC_BIG_ENDIAN);
256 if (sequence_number == 0) {
257 expert_add_info(pinfo, calibration_item, &ei_calibration_header);
259 proto_tree_add_item(calibration_item_subtree, hf_calibration_sequence_number, tvb, tvb_offset, item_size, ENC_BIG_ENDIAN);
260 tvb_offset += item_size;
262 if (sequence_number == 0) {
263 /* Header Packet */
265 /* First Sequence Number */
266 item_size = 2;
267 tvb_ensure_bytes_exist(tvb, tvb_offset, item_size);
268 proto_tree_add_item(calibration_item_subtree, hf_calibration_first_sequence_number, tvb, tvb_offset, item_size, ENC_BIG_ENDIAN);
269 tvb_offset += item_size;
271 /* Last Sequence Number */
272 item_size = 2;
273 tvb_ensure_bytes_exist(tvb, tvb_offset, item_size);
274 proto_tree_add_item(calibration_item_subtree, hf_calibration_last_sequence_number, tvb, tvb_offset, item_size, ENC_BIG_ENDIAN);
275 tvb_offset += item_size;
277 /* Name */
278 int name_length = tvb_reported_length_remaining(tvb, tvb_offset);
279 proto_item *name_item = proto_tree_add_item(calibration_item_subtree, hf_calibration_name, tvb, tvb_offset, name_length, ENC_UTF_8);
281 /* Name - Lines */
282 proto_tree *name_item_subtree = proto_item_add_subtree(name_item, ett_calibration_lines);
283 add_split_lines(pinfo, tvb, tvb_offset, name_item_subtree, hf_calibration_name_line);
284 } else {
285 /* Chunk Packet */
287 /* Chunk */
288 int chunk_length = tvb_reported_length_remaining(tvb, tvb_offset);
289 proto_item *chunk_item = proto_tree_add_item(calibration_item_subtree, hf_calibration_chunk, tvb, tvb_offset, chunk_length, ENC_UTF_8);
291 /* Chunk - Lines */
292 proto_tree *chunk_item_subtree = proto_item_add_subtree(chunk_item, ett_calibration_lines);
293 add_split_lines(pinfo, tvb, tvb_offset, chunk_item_subtree, hf_calibration_chunk_line);
296 return tvb_captured_length(tvb);
300 * ########################################################################
302 * # IDENT
304 * ########################################################################
306 * Ident Packets
308 * Ident Packets are sent by IM1 and IM2R0 sensors.
310 * Ident Packet
311 * ============
312 * Content: string
315 static int hf_ident_contents;
316 static int hf_ident_contents_line;
318 static hf_register_info protocol_registration_ident[] = {
319 {&hf_ident_contents, {"Contents", "locamation-im.ident.contents", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL}},
320 {&hf_ident_contents_line, {"Contents Line", "locamation-im.ident.contents.line", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL}}};
322 static int h_protocol_ident = -1;
324 static int ett_protocol_ident;
325 static int ett_ident_lines;
327 static int dissect_ident(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_) {
328 col_set_str(pinfo->cinfo, COL_PROTOCOL, PROTOCOL_SHORTNAME_IDENT);
329 col_set_str(pinfo->cinfo, COL_INFO, PROTOCOL_NAME_IDENT);
331 proto_item *ident_item = proto_tree_add_item(tree, h_protocol_ident, tvb, 0, -1, ENC_NA);
332 proto_tree *ident_item_subtree = proto_item_add_subtree(ident_item, ett_protocol_ident);
334 /* Contents */
335 int contents_length = tvb_reported_length_remaining(tvb, 0);
336 proto_item *contents_item = proto_tree_add_item(ident_item_subtree, hf_ident_contents, tvb, 0, contents_length, ENC_UTF_8);
338 /* Contents - Lines */
339 proto_tree *contents_item_subtree = proto_item_add_subtree(contents_item, ett_ident_lines);
340 add_split_lines(pinfo, tvb, 0, contents_item_subtree, hf_ident_contents_line);
342 return tvb_captured_length(tvb);
346 * ########################################################################
348 * # SAMPLES - Common
350 * ########################################################################
353 static expert_field ei_samples_ranges_sample_1_invalid;
354 static expert_field ei_samples_ranges_sample_2_invalid;
355 static expert_field ei_samples_ranges_sample_3_invalid;
356 static expert_field ei_samples_ranges_sample_4_invalid;
357 static expert_field ei_samples_ranges_sample_5_invalid;
358 static expert_field ei_samples_ranges_sample_6_invalid;
359 static expert_field ei_samples_ranges_sample_7_invalid;
360 static expert_field ei_samples_ranges_sample_8_invalid;
362 static void check_ranges(tvbuff_t *tvb, packet_info *pinfo, int tvb_offset, proto_item *item) {
363 uint16_t ranges = tvb_get_uint16(tvb, tvb_offset, ENC_BIG_ENDIAN);
365 if ((ranges & MASK_RANGES_SAMPLE_8) == MASK_RANGES_SAMPLE_8) {
366 expert_add_info(pinfo, item, &ei_samples_ranges_sample_8_invalid);
368 if ((ranges & MASK_RANGES_SAMPLE_7) == MASK_RANGES_SAMPLE_7) {
369 expert_add_info(pinfo, item, &ei_samples_ranges_sample_7_invalid);
371 if ((ranges & MASK_RANGES_SAMPLE_6) == MASK_RANGES_SAMPLE_6) {
372 expert_add_info(pinfo, item, &ei_samples_ranges_sample_6_invalid);
374 if ((ranges & MASK_RANGES_SAMPLE_5) == MASK_RANGES_SAMPLE_5) {
375 expert_add_info(pinfo, item, &ei_samples_ranges_sample_5_invalid);
377 if ((ranges & MASK_RANGES_SAMPLE_4) == MASK_RANGES_SAMPLE_4) {
378 expert_add_info(pinfo, item, &ei_samples_ranges_sample_4_invalid);
380 if ((ranges & MASK_RANGES_SAMPLE_3) == MASK_RANGES_SAMPLE_3) {
381 expert_add_info(pinfo, item, &ei_samples_ranges_sample_3_invalid);
383 if ((ranges & MASK_RANGES_SAMPLE_2) == MASK_RANGES_SAMPLE_2) {
384 expert_add_info(pinfo, item, &ei_samples_ranges_sample_2_invalid);
386 if ((ranges & MASK_RANGES_SAMPLE_1) == MASK_RANGES_SAMPLE_1) {
387 expert_add_info(pinfo, item, &ei_samples_ranges_sample_1_invalid);
391 static int ett_samples_sample_set_ranges;
393 static int hf_samples_sample_set_ranges;
395 static int hf_samples_sample_set_ranges_sample_1;
396 static int hf_samples_sample_set_ranges_sample_2;
397 static int hf_samples_sample_set_ranges_sample_3;
398 static int hf_samples_sample_set_ranges_sample_4;
399 static int hf_samples_sample_set_ranges_sample_5;
400 static int hf_samples_sample_set_ranges_sample_6;
401 static int hf_samples_sample_set_ranges_sample_7;
402 static int hf_samples_sample_set_ranges_sample_8;
404 static int *const rangesBits[] = {
405 &hf_samples_sample_set_ranges_sample_8,
406 &hf_samples_sample_set_ranges_sample_7,
407 &hf_samples_sample_set_ranges_sample_6,
408 &hf_samples_sample_set_ranges_sample_5,
409 &hf_samples_sample_set_ranges_sample_4,
410 &hf_samples_sample_set_ranges_sample_3,
411 &hf_samples_sample_set_ranges_sample_2,
412 &hf_samples_sample_set_ranges_sample_1,
413 NULL};
415 static int hf_samples_sample_set_sample_1;
416 static int hf_samples_sample_set_sample_2;
417 static int hf_samples_sample_set_sample_3;
418 static int hf_samples_sample_set_sample_4;
419 static int hf_samples_sample_set_sample_5;
420 static int hf_samples_sample_set_sample_6;
421 static int hf_samples_sample_set_sample_7;
422 static int hf_samples_sample_set_sample_8;
424 static void add_sample_set(tvbuff_t *tvb, packet_info *pinfo, int *tvb_offset, int hf, proto_tree *tree) {
425 int item_size = SAMPLE_SET_SIZE;
426 tvb_ensure_bytes_exist(tvb, *tvb_offset, item_size);
427 proto_item *sample_set_item = proto_tree_add_item(tree, hf, tvb, *tvb_offset, item_size, ENC_BIG_ENDIAN);
429 proto_tree *sample_set_item_subtree = proto_item_add_subtree(sample_set_item, ett_samples_sample_set_ranges);
431 /* Ranges */
432 item_size = 2;
433 tvb_ensure_bytes_exist(tvb, *tvb_offset, item_size);
434 proto_item *ranges_item = proto_tree_add_bitmask(sample_set_item_subtree, tvb, *tvb_offset, hf_samples_sample_set_ranges, ett_samples_sample_set_ranges, rangesBits, ENC_BIG_ENDIAN);
435 check_ranges(tvb, pinfo, *tvb_offset, ranges_item);
436 *tvb_offset += item_size;
438 /* Samples */
439 int const hfs[] = {
440 hf_samples_sample_set_sample_1,
441 hf_samples_sample_set_sample_2,
442 hf_samples_sample_set_sample_3,
443 hf_samples_sample_set_sample_4,
444 hf_samples_sample_set_sample_5,
445 hf_samples_sample_set_sample_6,
446 hf_samples_sample_set_sample_7,
447 hf_samples_sample_set_sample_8};
449 item_size = 4;
450 for (unsigned index_sample = 0; index_sample < array_length(hfs); index_sample++) {
451 tvb_ensure_bytes_exist(tvb, *tvb_offset, item_size);
452 proto_tree_add_item(sample_set_item_subtree, hfs[index_sample], tvb, *tvb_offset, item_size, ENC_BIG_ENDIAN);
453 *tvb_offset += item_size;
457 static void add_sample_sets(tvbuff_t *tvb, packet_info *pinfo, int *tvb_offset, int *hfs, unsigned hfs_size, proto_tree *tree) {
458 for (unsigned index_sample_set = 0; index_sample_set < hfs_size; index_sample_set++) {
459 add_sample_set(tvb, pinfo, tvb_offset, hfs[index_sample_set], tree);
463 static void add_rms_values(tvbuff_t *tvb, int *tvb_offset, int *hfs, unsigned hfs_size, proto_tree *tree) {
464 int item_size = 4;
465 for (unsigned index_rms_value = 0; index_rms_value < hfs_size; index_rms_value++) {
466 tvb_ensure_bytes_exist(tvb, *tvb_offset, item_size);
467 proto_tree_add_item(tree, hfs[index_rms_value], tvb, *tvb_offset, item_size, ENC_BIG_ENDIAN);
468 *tvb_offset += item_size;
472 static int ett_samples_timestamps_sample;
473 static int ett_samples_timestamps_sample_reserved;
474 static int ett_samples_timestamps_sample_timestamp;
476 static int hf_samples_timestamps_sample_sync_status;
477 static int hf_samples_timestamps_sample_additional_status;
478 static int hf_samples_timestamps_sample_additional_status_holdover_state;
479 static int hf_samples_timestamps_sample_additional_status_master_clock_switch;
480 static int hf_samples_timestamps_sample_timestamp;
481 static int hf_samples_timestamps_sample_timestamp_seconds;
482 static int hf_samples_timestamps_sample_timestamp_nanoseconds;
484 static const value_string samples_timestamps_sample_sync_status[] = {
485 {0, "None"},
486 {1, "Local"},
487 {2, "Global"},
488 {0, NULL}};
490 static int *const timestamp_additional_status_bits[] = {
491 &hf_samples_timestamps_sample_additional_status_holdover_state,
492 &hf_samples_timestamps_sample_additional_status_master_clock_switch,
493 NULL};
495 static expert_field ei_samples_timestamp_sync_status_invalid;
497 static void add_timestamp_sample(tvbuff_t *tvb, packet_info *pinfo, int *tvb_offset_previous, int *tvb_offset, int hf, proto_tree *tree) {
498 int item_size = TIMESTAMP_SIZE;
499 tvb_ensure_bytes_exist(tvb, *tvb_offset, item_size);
501 /* Get the timestamp components */
502 uint8_t sync_status = tvb_get_uint8(tvb, *tvb_offset);
503 uint32_t seconds = tvb_get_uint32(tvb, *tvb_offset + 2, ENC_BIG_ENDIAN);
504 uint32_t nanoseconds = tvb_get_uint32(tvb, *tvb_offset + 6, ENC_BIG_ENDIAN);
506 /* Convert the timestamp seconds to a split time type */
507 time_t sample_time = (time_t)seconds;
508 struct tm *sample_time_split = gmtime(&sample_time);
510 /* Construct the readable sync status */
511 const char *sync_status_buf = val_to_str(sync_status, samples_timestamps_sample_sync_status, "Unknown (%u)");
513 /* Construct the readable timestamp */
514 char timestamp_buf[ITEM_LABEL_LENGTH];
515 size_t timestamp_length = 0;
516 if (sample_time_split != NULL) {
517 timestamp_length += strftime(&timestamp_buf[timestamp_length], ITEM_LABEL_LENGTH - timestamp_length, "%Y-%m-%d %H:%M:%S.", sample_time_split);
518 } else {
519 timestamp_length += snprintf(&timestamp_buf[timestamp_length], ITEM_LABEL_LENGTH - timestamp_length, "\?\?\?\?-\?\?-\?\? \?\?:\?\?:\?\?.");
521 snprintf(&timestamp_buf[timestamp_length], ITEM_LABEL_LENGTH - timestamp_length, "%09u TAI", nanoseconds);
523 /* Construct the readable sample text */
524 char title_buf[ITEM_LABEL_LENGTH];
525 size_t title_length = 0;
526 title_length += snprintf(&title_buf[title_length], ITEM_LABEL_LENGTH - title_length, "%s (Sync: %s", timestamp_buf, sync_status_buf);
527 if (tvb_offset_previous != NULL) {
528 /* Get the previous timestamp components and calculate the time difference */
529 uint32_t seconds_previous = tvb_get_uint32(tvb, *tvb_offset_previous + 2, ENC_BIG_ENDIAN);
530 uint32_t nanoseconds_previous = tvb_get_uint32(tvb, *tvb_offset_previous + 6, ENC_BIG_ENDIAN);
531 uint64_t time_previous = ((uint64_t)seconds_previous * 1000000000) + nanoseconds_previous;
532 uint64_t time_now = ((uint64_t)seconds * 1000000000) + nanoseconds;
533 uint64_t time_diff = 0;
534 char time_difference_sign[2] = {'\0', '\0'};
535 if (time_now > time_previous) {
536 time_diff = time_now - time_previous;
537 time_difference_sign[0] = '\0';
538 } else if (time_now < time_previous) {
539 time_diff = time_previous - time_now;
540 time_difference_sign[0] = '-';
542 double frequency = 0.0;
543 if (time_diff != 0) {
544 frequency = 1.0 / ((double)time_diff * 1.0E-09);
546 title_length += snprintf(&title_buf[title_length], ITEM_LABEL_LENGTH - title_length, ", Time Difference: %s%" PRIu64 " nsec", time_difference_sign, time_diff);
547 if (frequency != 0.0) {
548 title_length += snprintf(&title_buf[title_length], ITEM_LABEL_LENGTH - title_length, " = %f Hz", frequency);
551 snprintf(&title_buf[title_length], ITEM_LABEL_LENGTH - title_length, ")");
553 proto_item *sample_timestamp_item = proto_tree_add_string(tree, hf, tvb, *tvb_offset, item_size, title_buf);
555 proto_tree *sample_timestamp_item_subtree = proto_item_add_subtree(sample_timestamp_item, ett_samples_timestamps_sample);
557 /* Sync Status */
558 item_size = 1;
559 tvb_ensure_bytes_exist(tvb, *tvb_offset, item_size);
560 proto_item *sync_status_item = proto_tree_add_item(sample_timestamp_item_subtree, hf_samples_timestamps_sample_sync_status, tvb, *tvb_offset, item_size, ENC_BIG_ENDIAN);
561 *tvb_offset += item_size;
563 if (sync_status > 2) {
564 expert_add_info(pinfo, sync_status_item, &ei_samples_timestamp_sync_status_invalid);
567 /* Additional Status */
568 item_size = 1;
569 tvb_ensure_bytes_exist(tvb, *tvb_offset, item_size);
570 proto_tree_add_bitmask(sample_timestamp_item_subtree, tvb, *tvb_offset, hf_samples_timestamps_sample_additional_status, ett_samples_timestamps_sample_reserved, timestamp_additional_status_bits, ENC_BIG_ENDIAN);
571 *tvb_offset += item_size;
573 /* Timestamp */
574 item_size = 8;
575 tvb_ensure_bytes_exist(tvb, *tvb_offset, item_size);
576 proto_item *sample_timestamp_timestamp_item = proto_tree_add_string(sample_timestamp_item_subtree, hf_samples_timestamps_sample_timestamp, tvb, *tvb_offset, item_size, timestamp_buf);
578 proto_tree *sample_timestamp_timestamp_item_subtree = proto_item_add_subtree(sample_timestamp_timestamp_item, ett_samples_timestamps_sample_timestamp);
580 /* Seconds */
581 item_size = 4;
582 tvb_ensure_bytes_exist(tvb, *tvb_offset, item_size);
583 proto_tree_add_item(sample_timestamp_timestamp_item_subtree, hf_samples_timestamps_sample_timestamp_seconds, tvb, *tvb_offset, item_size, ENC_BIG_ENDIAN);
584 *tvb_offset += item_size;
586 /* Nanoseconds */
587 item_size = 4;
588 tvb_ensure_bytes_exist(tvb, *tvb_offset, item_size);
589 proto_tree_add_item(sample_timestamp_timestamp_item_subtree, hf_samples_timestamps_sample_timestamp_nanoseconds, tvb, *tvb_offset, item_size, ENC_BIG_ENDIAN);
590 *tvb_offset += item_size;
593 static void add_timestamps_set(tvbuff_t *tvb, packet_info *pinfo, int *tvb_offset, int *hfs, unsigned hfs_size, proto_tree *tree) {
594 int tvb_offset_previous = 0;
595 for (unsigned index_timestamp = 0; index_timestamp < hfs_size; index_timestamp++) {
596 int tvb_offset_saved = *tvb_offset;
597 add_timestamp_sample(tvb, pinfo, (index_timestamp == 0) ? NULL : &tvb_offset_previous, tvb_offset, hfs[index_timestamp], tree);
598 tvb_offset_previous = tvb_offset_saved;
603 * Samples Packets
605 * Samples Packets are sent by IM1 and IM2R0 sensors.
606 * However, details of the packets differ between the sensors.
608 * Samples Packet
609 * ==============
610 * Transport Delay: 2 bytes, unsigned (resolution = 10ns)
611 * Hop Count: 1 byte, unsigned
612 * Control data: 1 byte, bitmap
613 * bit [7] : type : 0 = CIM, 1 = VIM
614 * bit [6] : simulated: 0 = Real Samples, 1 = Simulated Samples
615 * bits [5..4]: version : 00 = IM1, 11 = IM2R0
616 * bits [3..0]: seqnr : Sequence Number, in the range [0,15], monotonically
617 * increasing and wrapping
618 * Temperature: 2 bytes, signed (resolution = 0.25C)
619 * Padding: 1 byte
620 * ADC Status: 1 byte, unsigned
621 * Sample Data
622 * * Sample data is stored in sample data sets.
623 * Each sample data set contains ranges and the data of 8 samples, and
624 * samples are equi-distant in time.
626 * Sample Data Set
627 * ===============
628 * Range: 2 bytes, bitmap
629 * - bits [15,14]: Range of sample 8 (newest sample)
630 * - bits [13,12]: Range of sample 7
631 * - bits [11,10]: Range of sample 6
632 * - bits [ 9, 8]: Range of sample 5
633 * - bits [ 7, 6]: Range of sample 4
634 * - bits [ 5, 4]: Range of sample 3
635 * - bits [ 3, 2]: Range of sample 2
636 * - bits [ 1, 0]: Range of sample 1 (oldest sample)
637 * Range values:
638 * 00 = measurement ADC channel
639 * 01 = protection ADC channel, range low
640 * 10 = protection ADC channel, range high
641 * 11 = unused
642 * Sample 1: 4 bytes, signed (oldest sample)
643 * Sample 2: 4 bytes, signed
644 * Sample 3: 4 bytes, signed
645 * Sample 4: 4 bytes, signed
646 * Sample 5: 4 bytes, signed
647 * Sample 6: 4 bytes, signed
648 * Sample 7: 4 bytes, signed
649 * Sample 8: 4 bytes, signed (newest sample)
651 * * IM1
652 * 6 sample data sets, one set per ADC channel:
654 * Sample Data
655 * ===========
656 * CIM VIM
657 * set 1 channel 1, measurement channel 1
658 * set 2 channel 2, measurement channel 2
659 * set 3 channel 3, measurement channel 3
660 * set 4 channel 1, protection 0
661 * set 5 channel 2, protection 0
662 * set 6 channel 3, protection 0
664 * * IM2R0
665 * 8 sample data sets, one set per ADC channel:
667 * Sample Data
668 * ===========
669 * CIM VIM
670 * set 1 channel 1, measurement channel 1
671 * set 2 channel 2, measurement channel 2
672 * set 3 channel 3, measurement channel 3
673 * set 4 channel 1, protection neutral channel
674 * set 5 channel 2, protection 0
675 * set 6 channel 3, protection 0
676 * set 7 neutral channel, measurement 0
677 * set 8 neutral channel, protection 0
678 * RMS values
679 * * RMS values are stored as 4 byte signed values.
681 * * IM1
682 * 6 values, one per ADC-channel:
684 * RMS values
685 * ==========
686 * CIM VIM
687 * value 1 channel 1, measurement channel 1
688 * value 2 channel 2, measurement channel 2
689 * value 3 channel 3, measurement channel 3
690 * value 4 channel 1, protection 0
691 * value 5 channel 2, protection 0
692 * value 6 channel 3, protection 0
694 * * IM2R0
695 * 8 values, one per ADC-channel:
697 * RMS values
698 * ==========
699 * CIM VIM
700 * value 1 0 0
701 * value 2 0 0
702 * value 3 0 0
703 * value 4 0 0
704 * value 5 0 0
705 * value 6 0 0
706 * value 7 0 0
707 * value 8 0 0
708 * Timestamps
709 * * Timestamps are PTP driven and are stored in a versioned block.
710 * Each timestamp also has status information.
712 * * IM1
713 * Timestamps are not applicable for IM1.
715 * * IM2R0
716 * Timestamps are optional.
718 * Timestamps Block
719 * ================
720 * Version 1 byte, unsigned
721 * Reserved 3 bytes, unsigned
722 * Sample 1 Timestamp (oldest sample)
723 * Sample 2 Timestamp
724 * Sample 3 Timestamp
725 * Sample 4 Timestamp
726 * Sample 5 Timestamp
727 * Sample 6 Timestamp
728 * Sample 7 Timestamp
729 * Sample 8 Timestamp (newest sample)
731 * Timestamp
732 * =========
733 * Sync Status 1 byte, unsigned
734 * 0 = Not synchronized (during start-up or synchronization lost)
735 * 1 = Synchronized but not to a Grand Master Clock
736 * 2 = Synchronized to a Grand Master Clock
737 * 3-255 = Invalid
738 * Additional Status 1 byte, bitmap
739 * bits [7, 2]: Reserved
740 * bits [1] : Master clock switch
741 * 1 = The device switched to a different master clock or
742 * became synchronized to a master clock for the first time.
743 * 0 = The device did not switch to a different master clock nor
744 * became synchronized to a master clock for the first time.
745 * bits [0] : Holdover state
746 * 1 = The device is in its holdover state.
747 * 0 = The device is not in its holdover state.
748 * Seconds 4 bytes, unsigned
749 * Nanoseconds 4 bytes, unsigned
752 static int ett_protocol_samples;
753 static int ett_samples_control;
754 static int ett_samples_sets;
755 static int ett_samples_sets_set;
756 static int ett_samples_rms;
757 static int ett_samples_rms_values;
758 static int ett_samples_timestamps;
759 static int ett_samples_timestamps_set;
761 static expert_field ei_samples_im_version_invalid;
763 static int hf_samples_transport_delay;
764 static int hf_samples_hop_count;
765 static int hf_samples_control;
766 static int hf_samples_control_type;
767 static int hf_samples_control_simulated;
768 static int hf_samples_control_version;
769 static int hf_samples_control_sequence_number;
770 static int hf_samples_temperature;
771 static int hf_samples_padding;
772 static int hf_samples_adc_status;
773 static int hf_samples_sample_set;
774 static int hf_samples_rms_values;
775 static int hf_samples_timestamps;
777 static int *const controlBits[] = {
778 &hf_samples_control_type,
779 &hf_samples_control_simulated,
780 &hf_samples_control_version,
781 &hf_samples_control_sequence_number,
782 NULL};
784 static int hf_samples_sample_set_measurement_channel_1;
785 static int hf_samples_sample_set_measurement_channel_2;
786 static int hf_samples_sample_set_measurement_channel_3;
787 static int hf_samples_sample_set_measurement_channel_n;
788 static int hf_samples_sample_set_protection_channel_1;
789 static int hf_samples_sample_set_protection_channel_2;
790 static int hf_samples_sample_set_protection_channel_3;
791 static int hf_samples_sample_set_protection_channel_n;
792 static int hf_samples_sample_set_channel_unused;
794 static int hf_samples_rms_values_measurement_channel_1;
795 static int hf_samples_rms_values_measurement_channel_2;
796 static int hf_samples_rms_values_measurement_channel_3;
797 static int hf_samples_rms_values_protection_channel_1;
798 static int hf_samples_rms_values_protection_channel_2;
799 static int hf_samples_rms_values_protection_channel_3;
800 static int hf_samples_rms_values_channel_unused;
802 static int hf_samples_timestamps_version;
803 static int hf_samples_timestamps_reserved;
804 static int hf_samples_timestamps_sample_1;
805 static int hf_samples_timestamps_sample_2;
806 static int hf_samples_timestamps_sample_3;
807 static int hf_samples_timestamps_sample_4;
808 static int hf_samples_timestamps_sample_5;
809 static int hf_samples_timestamps_sample_6;
810 static int hf_samples_timestamps_sample_7;
811 static int hf_samples_timestamps_sample_8;
813 static int dissect_samples_im(bool im1, tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_, int h_protocol_samples) {
814 col_set_str(pinfo->cinfo, COL_PROTOCOL, im1 ? PROTOCOL_SHORTNAME_SAMPLES_IM1 : PROTOCOL_SHORTNAME_SAMPLES_IM2R0);
815 col_set_str(pinfo->cinfo, COL_INFO, im1 ? PROTOCOL_NAME_SAMPLES_IM1 : PROTOCOL_NAME_SAMPLES_IM2R0);
817 proto_item *samples_item = proto_tree_add_item(tree, h_protocol_samples, tvb, 0, -1, ENC_NA);
818 proto_tree *samples_item_subtree = proto_item_add_subtree(samples_item, ett_protocol_samples);
820 int tvb_offset = 0;
822 /* Transport Delay */
823 int item_size = 2;
824 tvb_ensure_bytes_exist(tvb, tvb_offset, item_size);
825 proto_tree_add_item(samples_item_subtree, hf_samples_transport_delay, tvb, tvb_offset, item_size, ENC_BIG_ENDIAN);
826 tvb_offset += item_size;
828 /* Hop Count */
829 item_size = 1;
830 tvb_ensure_bytes_exist(tvb, tvb_offset, item_size);
831 proto_tree_add_item(samples_item_subtree, hf_samples_hop_count, tvb, tvb_offset, item_size, ENC_BIG_ENDIAN);
832 tvb_offset += item_size;
834 /* Get Control */
835 uint8_t control = tvb_get_uint8(tvb, tvb_offset);
836 bool isIM1 = ((control & MASK_SAMPLES_CONTROL_VERSION) == 0);
837 bool isIM2R0 = ((control & MASK_SAMPLES_CONTROL_VERSION) == MASK_SAMPLES_CONTROL_VERSION);
838 bool isCIM = ((control & MASK_SAMPLES_CONTROL_TYPE) == 0);
840 /* Control */
841 item_size = 1;
842 tvb_ensure_bytes_exist(tvb, tvb_offset, item_size);
843 proto_item *control_item = proto_tree_add_bitmask(samples_item_subtree, tvb, tvb_offset, hf_samples_control, ett_samples_control, controlBits, ENC_BIG_ENDIAN);
844 tvb_offset += item_size;
845 if (!isIM1 && !isIM2R0) {
846 expert_add_info(pinfo, control_item, &ei_samples_im_version_invalid);
849 /* Temperature */
850 item_size = 2;
851 tvb_ensure_bytes_exist(tvb, tvb_offset, item_size);
852 proto_tree_add_item(samples_item_subtree, hf_samples_temperature, tvb, tvb_offset, item_size, ENC_BIG_ENDIAN);
853 tvb_offset += item_size;
855 /* Padding */
856 item_size = 1;
857 tvb_ensure_bytes_exist(tvb, tvb_offset, item_size);
858 proto_tree_add_item(samples_item_subtree, hf_samples_padding, tvb, tvb_offset, item_size, ENC_BIG_ENDIAN);
859 tvb_offset += item_size;
861 /* ADC status */
862 item_size = 1;
863 tvb_ensure_bytes_exist(tvb, tvb_offset, item_size);
864 proto_tree_add_item(samples_item_subtree, hf_samples_adc_status, tvb, tvb_offset, item_size, ENC_BIG_ENDIAN);
865 tvb_offset += item_size;
867 /* Sample Sets */
869 proto_tree *sample_sets_subtree = proto_item_add_subtree(samples_item, ett_samples_sets);
871 if (im1) {
872 item_size = SAMPLE_SET_SIZE * 6;
873 } else {
874 item_size = SAMPLE_SET_SIZE * 8;
876 tvb_ensure_bytes_exist(tvb, tvb_offset, item_size);
877 proto_item *sample_sets_subtree_item = proto_tree_add_item(sample_sets_subtree, hf_samples_sample_set, tvb, tvb_offset, item_size, ENC_NA);
879 proto_tree *sample_sets_subtree_item_subtree = proto_item_add_subtree(sample_sets_subtree_item, ett_samples_sets_set);
881 if (isIM1) {
882 if (isCIM) {
883 /* IM1 CIM */
885 int hfs[] = {
886 hf_samples_sample_set_measurement_channel_1,
887 hf_samples_sample_set_measurement_channel_2,
888 hf_samples_sample_set_measurement_channel_3,
889 hf_samples_sample_set_protection_channel_1,
890 hf_samples_sample_set_protection_channel_2,
891 hf_samples_sample_set_protection_channel_3};
893 add_sample_sets(tvb, pinfo, &tvb_offset, hfs, array_length(hfs), sample_sets_subtree_item_subtree);
894 } else {
895 /* IM1 VIM */
897 int hfs[] = {
898 hf_samples_sample_set_measurement_channel_1,
899 hf_samples_sample_set_measurement_channel_2,
900 hf_samples_sample_set_measurement_channel_3,
901 hf_samples_sample_set_channel_unused,
902 hf_samples_sample_set_channel_unused,
903 hf_samples_sample_set_channel_unused};
905 add_sample_sets(tvb, pinfo, &tvb_offset, hfs, array_length(hfs), sample_sets_subtree_item_subtree);
907 } else if (isIM2R0) {
908 if (isCIM) {
909 /* IM2R0 CIM */
911 int hfs[] = {
912 hf_samples_sample_set_measurement_channel_1,
913 hf_samples_sample_set_measurement_channel_2,
914 hf_samples_sample_set_measurement_channel_3,
915 hf_samples_sample_set_protection_channel_1,
916 hf_samples_sample_set_protection_channel_2,
917 hf_samples_sample_set_protection_channel_3,
918 hf_samples_sample_set_measurement_channel_n,
919 hf_samples_sample_set_protection_channel_n};
921 add_sample_sets(tvb, pinfo, &tvb_offset, hfs, array_length(hfs), sample_sets_subtree_item_subtree);
922 } else {
923 /* IM2R0 VIM */
925 int hfs[] = {
926 hf_samples_sample_set_measurement_channel_1,
927 hf_samples_sample_set_measurement_channel_2,
928 hf_samples_sample_set_measurement_channel_3,
929 hf_samples_sample_set_measurement_channel_n,
930 hf_samples_sample_set_channel_unused,
931 hf_samples_sample_set_channel_unused,
932 hf_samples_sample_set_channel_unused,
933 hf_samples_sample_set_channel_unused};
935 add_sample_sets(tvb, pinfo, &tvb_offset, hfs, array_length(hfs), sample_sets_subtree_item_subtree);
940 /* RMS Values */
942 proto_tree *rms_values_subtree = proto_item_add_subtree(samples_item, ett_samples_rms);
944 if (im1) {
945 item_size = 4 * 6;
946 } else {
947 item_size = 4 * 8;
949 tvb_ensure_bytes_exist(tvb, tvb_offset, item_size);
950 proto_item *rms_values_item = proto_tree_add_item(rms_values_subtree, hf_samples_rms_values, tvb, tvb_offset, item_size, ENC_NA);
952 proto_tree *rms_values_item_subtree = proto_item_add_subtree(rms_values_item, ett_samples_rms_values);
954 if (isIM1) {
955 if (isCIM) {
956 /* IM1 CIM */
958 int hfs[] = {
959 hf_samples_rms_values_measurement_channel_1,
960 hf_samples_rms_values_measurement_channel_2,
961 hf_samples_rms_values_measurement_channel_3,
962 hf_samples_rms_values_protection_channel_1,
963 hf_samples_rms_values_protection_channel_2,
964 hf_samples_rms_values_protection_channel_3};
966 add_rms_values(tvb, &tvb_offset, hfs, array_length(hfs), rms_values_item_subtree);
967 } else {
968 /* IM1 VIM */
970 int hfs[] = {
971 hf_samples_rms_values_measurement_channel_1,
972 hf_samples_rms_values_measurement_channel_2,
973 hf_samples_rms_values_measurement_channel_3,
974 hf_samples_rms_values_channel_unused,
975 hf_samples_rms_values_channel_unused,
976 hf_samples_rms_values_channel_unused};
978 add_rms_values(tvb, &tvb_offset, hfs, array_length(hfs), rms_values_item_subtree);
980 } else if (isIM2R0) {
981 int hfs[] = {
982 hf_samples_rms_values_channel_unused,
983 hf_samples_rms_values_channel_unused,
984 hf_samples_rms_values_channel_unused,
985 hf_samples_rms_values_channel_unused,
986 hf_samples_rms_values_channel_unused,
987 hf_samples_rms_values_channel_unused,
988 hf_samples_rms_values_channel_unused,
989 hf_samples_rms_values_channel_unused};
991 add_rms_values(tvb, &tvb_offset, hfs, array_length(hfs), rms_values_item_subtree);
995 /* Timestamps */
996 if (isIM2R0 && tvb_bytes_exist(tvb, tvb_offset, TIMESTAMPS_SIZE)) {
997 proto_tree *samples_timestamps_subtree = proto_item_add_subtree(samples_item, ett_samples_timestamps);
999 item_size = TIMESTAMPS_SIZE;
1000 tvb_ensure_bytes_exist(tvb, tvb_offset, item_size);
1001 proto_item *samples_timestamps_subtree_item = proto_tree_add_item(samples_timestamps_subtree, hf_samples_timestamps, tvb, tvb_offset, item_size, ENC_NA);
1003 proto_tree *samples_timestamps_subtree_item_subtree = proto_item_add_subtree(samples_timestamps_subtree_item, ett_samples_timestamps_set);
1005 /* Version */
1006 item_size = 1;
1007 tvb_ensure_bytes_exist(tvb, tvb_offset, item_size);
1008 proto_tree_add_item(samples_timestamps_subtree_item_subtree, hf_samples_timestamps_version, tvb, tvb_offset, item_size, ENC_BIG_ENDIAN);
1009 tvb_offset += item_size;
1011 /* Reserved */
1012 item_size = 3;
1013 tvb_ensure_bytes_exist(tvb, tvb_offset, item_size);
1014 proto_tree_add_item(samples_timestamps_subtree_item_subtree, hf_samples_timestamps_reserved, tvb, tvb_offset, item_size, ENC_BIG_ENDIAN);
1015 tvb_offset += item_size;
1017 /* Sample Timestamps */
1019 int hfs[] = {
1020 hf_samples_timestamps_sample_1,
1021 hf_samples_timestamps_sample_2,
1022 hf_samples_timestamps_sample_3,
1023 hf_samples_timestamps_sample_4,
1024 hf_samples_timestamps_sample_5,
1025 hf_samples_timestamps_sample_6,
1026 hf_samples_timestamps_sample_7,
1027 hf_samples_timestamps_sample_8};
1029 add_timestamps_set(tvb, pinfo, &tvb_offset, hfs, array_length(hfs), samples_timestamps_subtree_item_subtree);
1032 return tvb_captured_length(tvb);
1036 * ########################################################################
1038 * # Samples - IM1
1040 * ########################################################################
1043 static void samples_transport_delay(char *result, uint16_t transport_delay) {
1044 snprintf(result, ITEM_LABEL_LENGTH, "%u ns", transport_delay * 10);
1047 static const value_string samples_control_type_vals[] = {
1048 {0, "Current Interface Module"},
1049 {1, "Voltage Interface Module"},
1050 {0, NULL}};
1052 static const value_string samples_control_simulated_vals[] = {
1053 {0, "Sampled"},
1054 {1, "Simulated"},
1055 {0, NULL}};
1057 static const value_string samples_control_version_vals[] = {
1058 {0, "IM1"},
1059 {1, "Unused"},
1060 {2, "Unused"},
1061 {3, "IM2R0"},
1062 {0, NULL}};
1064 static void samples_sequence_number(char *result, uint8_t sequence_number) {
1065 snprintf(result, ITEM_LABEL_LENGTH, "%u", sequence_number);
1068 static void samples_temperature(char *result, int16_t temperature) {
1069 snprintf(result, ITEM_LABEL_LENGTH, "%.2f C", (0.25f * temperature));
1072 static const value_string ranges_vals[] = {
1073 {0, "Measurement ADC Channel"},
1074 {1, "Protection ADC Channel, Range Low"},
1075 {2, "Protection ADC Channel, Range High"},
1076 {3, "Unused"},
1077 {0, NULL}};
1079 static hf_register_info protocol_registration_samples[] = {
1080 {&hf_samples_transport_delay, {"Transport Delay", "locamation-im.samples.transport_delay", FT_UINT16, BASE_CUSTOM, CF_FUNC(samples_transport_delay), 0x0, NULL, HFILL}},
1081 {&hf_samples_hop_count, {"Hop Count", "locamation-im.samples.hop_count", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL}},
1082 {&hf_samples_control, {"Control", "locamation-im.samples.control", FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL}},
1083 {&hf_samples_control_type, {"Type", "locamation-im.samples.control.type", FT_UINT8, BASE_DEC, VALS(samples_control_type_vals), MASK_SAMPLES_CONTROL_TYPE, NULL, HFILL}},
1084 {&hf_samples_control_simulated, {"Simulated", "locamation-im.samples.control.simulated", FT_UINT8, BASE_DEC, VALS(samples_control_simulated_vals), MASK_SAMPLES_CONTROL_SIMULATED, NULL, HFILL}},
1085 {&hf_samples_control_version, {"Version", "locamation-im.samples.control.version", FT_UINT8, BASE_DEC, VALS(samples_control_version_vals), MASK_SAMPLES_CONTROL_VERSION, NULL, HFILL}},
1086 {&hf_samples_control_sequence_number, {"Sequence Number", "locamation-im.samples.control.sequence_number", FT_UINT8, BASE_CUSTOM, CF_FUNC(samples_sequence_number), MASK_SAMPLES_CONTROL_SEQUENCE_NUMBER, NULL, HFILL}},
1087 {&hf_samples_temperature, {"Temperature", "locamation-im.samples.temperature", FT_INT16, BASE_CUSTOM, CF_FUNC(samples_temperature), 0x0, NULL, HFILL}},
1088 {&hf_samples_padding, {"Padding", "locamation-im.samples.padding", FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL}},
1089 {&hf_samples_adc_status, {"ADC Status", "locamation-im.samples.adc_status", FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL}},
1090 {&hf_samples_sample_set, {"Sample Sets", "locamation-im.samples.sets", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL}},
1091 {&hf_samples_rms_values, {"RMS Values", "locamation-im.samples.rms_values", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL}},
1092 {&hf_samples_sample_set_measurement_channel_1, {"Measurement Channel 1", "locamation-im.samples.sets.measurement.channel.1", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL}},
1093 {&hf_samples_sample_set_measurement_channel_2, {"Measurement Channel 2", "locamation-im.samples.sets.measurement.channel.2", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL}},
1094 {&hf_samples_sample_set_measurement_channel_3, {"Measurement Channel 3", "locamation-im.samples.sets.measurement.channel.3", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL}},
1095 {&hf_samples_sample_set_measurement_channel_n, {"Measurement Channel N", "locamation-im.samples.sets.measurement.channel.n", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL}},
1096 {&hf_samples_sample_set_protection_channel_1, {"Protection Channel 1", "locamation-im.samples.sets.protection.channel.1", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL}},
1097 {&hf_samples_sample_set_protection_channel_2, {"Protection Channel 2", "locamation-im.samples.sets.protection.channel.2", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL}},
1098 {&hf_samples_sample_set_protection_channel_3, {"Protection Channel 3", "locamation-im.samples.sets.protection.channel.3", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL}},
1099 {&hf_samples_sample_set_protection_channel_n, {"Protection Channel N", "locamation-im.samples.sets.protection.channel.n", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL}},
1100 {&hf_samples_sample_set_channel_unused, {"Unused Channel", "locamation-im.samples.sets.channel.unused", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL}},
1101 {&hf_samples_sample_set_ranges, {"Ranges", "locamation-im.samples.sets.measurement.ranges", FT_UINT16, BASE_HEX, NULL, 0x0, NULL, HFILL}},
1102 {&hf_samples_sample_set_ranges_sample_1, {"Sample 1", "locamation-im.samples.sets.measurement.ranges.sample.1", FT_UINT16, BASE_DEC, VALS(ranges_vals), MASK_RANGES_SAMPLE_1, NULL, HFILL}},
1103 {&hf_samples_sample_set_ranges_sample_2, {"Sample 2", "locamation-im.samples.sets.measurement.ranges.sample.2", FT_UINT16, BASE_DEC, VALS(ranges_vals), MASK_RANGES_SAMPLE_2, NULL, HFILL}},
1104 {&hf_samples_sample_set_ranges_sample_3, {"Sample 3", "locamation-im.samples.sets.measurement.ranges.sample.3", FT_UINT16, BASE_DEC, VALS(ranges_vals), MASK_RANGES_SAMPLE_3, NULL, HFILL}},
1105 {&hf_samples_sample_set_ranges_sample_4, {"Sample 4", "locamation-im.samples.sets.measurement.ranges.sample.4", FT_UINT16, BASE_DEC, VALS(ranges_vals), MASK_RANGES_SAMPLE_4, NULL, HFILL}},
1106 {&hf_samples_sample_set_ranges_sample_5, {"Sample 5", "locamation-im.samples.sets.measurement.ranges.sample.5", FT_UINT16, BASE_DEC, VALS(ranges_vals), MASK_RANGES_SAMPLE_5, NULL, HFILL}},
1107 {&hf_samples_sample_set_ranges_sample_6, {"Sample 6", "locamation-im.samples.sets.measurement.ranges.sample.6", FT_UINT16, BASE_DEC, VALS(ranges_vals), MASK_RANGES_SAMPLE_6, NULL, HFILL}},
1108 {&hf_samples_sample_set_ranges_sample_7, {"Sample 7", "locamation-im.samples.sets.measurement.ranges.sample.7", FT_UINT16, BASE_DEC, VALS(ranges_vals), MASK_RANGES_SAMPLE_7, NULL, HFILL}},
1109 {&hf_samples_sample_set_ranges_sample_8, {"Sample 8", "locamation-im.samples.sets.measurement.ranges.sample.8", FT_UINT16, BASE_DEC, VALS(ranges_vals), MASK_RANGES_SAMPLE_8, NULL, HFILL}},
1110 {&hf_samples_sample_set_sample_1, {"Sample 1", "locamation-im.samples.sets.sample.1", FT_INT32, BASE_DEC, NULL, 0x0, NULL, HFILL}},
1111 {&hf_samples_sample_set_sample_2, {"Sample 2", "locamation-im.samples.sets.sample.2", FT_INT32, BASE_DEC, NULL, 0x0, NULL, HFILL}},
1112 {&hf_samples_sample_set_sample_3, {"Sample 3", "locamation-im.samples.sets.sample.3", FT_INT32, BASE_DEC, NULL, 0x0, NULL, HFILL}},
1113 {&hf_samples_sample_set_sample_4, {"Sample 4", "locamation-im.samples.sets.sample.4", FT_INT32, BASE_DEC, NULL, 0x0, NULL, HFILL}},
1114 {&hf_samples_sample_set_sample_5, {"Sample 5", "locamation-im.samples.sets.sample.5", FT_INT32, BASE_DEC, NULL, 0x0, NULL, HFILL}},
1115 {&hf_samples_sample_set_sample_6, {"Sample 6", "locamation-im.samples.sets.sample.6", FT_INT32, BASE_DEC, NULL, 0x0, NULL, HFILL}},
1116 {&hf_samples_sample_set_sample_7, {"Sample 7", "locamation-im.samples.sets.sample.7", FT_INT32, BASE_DEC, NULL, 0x0, NULL, HFILL}},
1117 {&hf_samples_sample_set_sample_8, {"Sample 8", "locamation-im.samples.sets.sample.8", FT_INT32, BASE_DEC, NULL, 0x0, NULL, HFILL}},
1118 {&hf_samples_rms_values_measurement_channel_1, {"Measurement Channel 1", "locamation-im.samples.rms.measurement.channel.1", FT_INT32, BASE_DEC, NULL, 0x0, NULL, HFILL}},
1119 {&hf_samples_rms_values_measurement_channel_2, {"Measurement Channel 2", "locamation-im.samples.rms.measurement.channel.2", FT_INT32, BASE_DEC, NULL, 0x0, NULL, HFILL}},
1120 {&hf_samples_rms_values_measurement_channel_3, {"Measurement Channel 3", "locamation-im.samples.rms.measurement.channel.3", FT_INT32, BASE_DEC, NULL, 0x0, NULL, HFILL}},
1121 {&hf_samples_rms_values_protection_channel_1, {"Protection Channel 1", "locamation-im.samples.rms.protection.channel.1", FT_INT32, BASE_DEC, NULL, 0x0, NULL, HFILL}},
1122 {&hf_samples_rms_values_protection_channel_2, {"Protection Channel 2", "locamation-im.samples.rms.protection.channel.2", FT_INT32, BASE_DEC, NULL, 0x0, NULL, HFILL}},
1123 {&hf_samples_rms_values_protection_channel_3, {"Protection Channel 3", "locamation-im.samples.rms.protection.channel.3", FT_INT32, BASE_DEC, NULL, 0x0, NULL, HFILL}},
1124 {&hf_samples_rms_values_channel_unused, {"Unused Channel", "locamation-im.samples.rms.channel.unused", FT_INT32, BASE_DEC, NULL, 0x0, NULL, HFILL}}};
1126 static ei_register_info ei_samples_im1[] = {
1127 {&ei_samples_ranges_sample_1_invalid, {"locamation-im.samples.sets.measurement.ranges.sample.1.invalid", PI_MALFORMED, PI_ERROR, "Invalid Range for sample 1", EXPFILL}},
1128 {&ei_samples_ranges_sample_2_invalid, {"locamation-im.samples.sets.measurement.ranges.sample.2.invalid", PI_MALFORMED, PI_ERROR, "Invalid Range for sample 2", EXPFILL}},
1129 {&ei_samples_ranges_sample_3_invalid, {"locamation-im.samples.sets.measurement.ranges.sample.3.invalid", PI_MALFORMED, PI_ERROR, "Invalid Range for sample 3", EXPFILL}},
1130 {&ei_samples_ranges_sample_4_invalid, {"locamation-im.samples.sets.measurement.ranges.sample.4.invalid", PI_MALFORMED, PI_ERROR, "Invalid Range for sample 4", EXPFILL}},
1131 {&ei_samples_ranges_sample_5_invalid, {"locamation-im.samples.sets.measurement.ranges.sample.5.invalid", PI_MALFORMED, PI_ERROR, "Invalid Range for sample 5", EXPFILL}},
1132 {&ei_samples_ranges_sample_6_invalid, {"locamation-im.samples.sets.measurement.ranges.sample.6.invalid", PI_MALFORMED, PI_ERROR, "Invalid Range for sample 6", EXPFILL}},
1133 {&ei_samples_ranges_sample_7_invalid, {"locamation-im.samples.sets.measurement.ranges.sample.7.invalid", PI_MALFORMED, PI_ERROR, "Invalid Range for sample 7", EXPFILL}},
1134 {&ei_samples_ranges_sample_8_invalid, {"locamation-im.samples.sets.measurement.ranges.sample.8.invalid", PI_MALFORMED, PI_ERROR, "Invalid Range for sample 8", EXPFILL}}};
1136 static int h_protocol_samples_im1 = -1;
1138 static int dissect_samples_im1(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data) {
1139 return dissect_samples_im(true, tvb, pinfo, tree, data, h_protocol_samples_im1);
1143 * ########################################################################
1145 * # Samples - IM2R0
1147 * ########################################################################
1150 static hf_register_info protocol_registration_samples_im2[] = {
1151 {&hf_samples_timestamps, {"Timestamps", "locamation-im.samples.timestamps", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL}},
1152 {&hf_samples_timestamps_version, {"Version", "locamation-im.samples.timestamps.version", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL}},
1153 {&hf_samples_timestamps_reserved, {"Reserved", "locamation-im.samples.timestamps.reserved", FT_UINT24, BASE_DEC, NULL, 0x0, NULL, HFILL}},
1154 {&hf_samples_timestamps_sample_1, {"Sample 1", "locamation-im.samples.timestamps.sample.1", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL}},
1155 {&hf_samples_timestamps_sample_2, {"Sample 2", "locamation-im.samples.timestamps.sample.2", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL}},
1156 {&hf_samples_timestamps_sample_3, {"Sample 3", "locamation-im.samples.timestamps.sample.3", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL}},
1157 {&hf_samples_timestamps_sample_4, {"Sample 4", "locamation-im.samples.timestamps.sample.4", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL}},
1158 {&hf_samples_timestamps_sample_5, {"Sample 5", "locamation-im.samples.timestamps.sample.5", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL}},
1159 {&hf_samples_timestamps_sample_6, {"Sample 6", "locamation-im.samples.timestamps.sample.6", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL}},
1160 {&hf_samples_timestamps_sample_7, {"Sample 7", "locamation-im.samples.timestamps.sample.7", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL}},
1161 {&hf_samples_timestamps_sample_8, {"Sample 8", "locamation-im.samples.timestamps.sample.8", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL}},
1162 {&hf_samples_timestamps_sample_sync_status, {"Sync Status", "locamation-im.samples.timestamps.sample.sync.status", FT_UINT8, BASE_DEC, VALS(samples_timestamps_sample_sync_status), 0x0, NULL, HFILL}},
1163 {&hf_samples_timestamps_sample_additional_status, {"Additional Status", "locamation-im.samples.timestamps.sample.additional.status", FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL}},
1164 {&hf_samples_timestamps_sample_additional_status_holdover_state, {"Holdover", "locamation-im.samples.timestamps.sample.additional.status.holdover.state", FT_BOOLEAN, 8, TFS(&tfs_active_inactive), MASK_TIMESTAMP_ADDITIONAL_STATUS_HOLDOVER_STATE, NULL, HFILL}},
1165 {&hf_samples_timestamps_sample_additional_status_master_clock_switch, {"Master Clock Switch", "locamation-im.samples.timestamps.sample.additional.status.master.clock.switch", FT_BOOLEAN, 8, TFS(&tfs_yes_no), MASK_TIMESTAMP_ADDITIONAL_STATUS_MASTER_CLOCK_SWITCH, NULL, HFILL}},
1166 {&hf_samples_timestamps_sample_timestamp, {"Timestamp", "locamation-im.samples.timestamps.sample.timestamp", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL}},
1167 {&hf_samples_timestamps_sample_timestamp_seconds, {"Seconds", "locamation-im.samples.timestamps.sample.timestamp.seconds", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL}},
1168 {&hf_samples_timestamps_sample_timestamp_nanoseconds, {"Nanoseconds", "locamation-im.samples.timestamps.sample.timestamp.nanoseconds", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL}}};
1170 static ei_register_info ei_samples_im2r0[] = {
1171 {&ei_samples_im_version_invalid, {"locamation-im.samples.control.version.invalid", PI_MALFORMED, PI_ERROR, "Invalid Version", EXPFILL}},
1172 {&ei_samples_timestamp_sync_status_invalid, {"locamation-im.samples.timestamps.sample.sync.status.invalid", PI_MALFORMED, PI_ERROR, "Invalid Status", EXPFILL}}};
1174 static int h_protocol_samples_im2r0 = -1;
1176 static int dissect_samples_im2r0(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data) {
1177 return dissect_samples_im(false, tvb, pinfo, tree, data, h_protocol_samples_im2r0);
1181 * ########################################################################
1183 * # LLC
1185 * ########################################################################
1188 static int hf_llc_company_pid;
1190 static hf_register_info llc_registration[] = {
1191 {&hf_llc_company_pid, {"PID", "locamation-im.llc.pid", FT_UINT16, BASE_HEX, VALS(company_pid_vals), 0x0, "Protocol ID", HFILL}}};
1194 * ########################################################################
1196 * # Registration
1198 * ########################################################################
1201 static int *ett[] = {
1202 &ett_protocol_calibration,
1203 &ett_calibration_lines,
1205 &ett_protocol_ident,
1206 &ett_ident_lines,
1208 &ett_samples_sample_set_ranges,
1209 &ett_protocol_samples,
1210 &ett_samples_control,
1211 &ett_samples_sets,
1212 &ett_samples_sets_set,
1213 &ett_samples_rms,
1214 &ett_samples_rms_values,
1215 &ett_samples_timestamps,
1216 &ett_samples_timestamps_set,
1217 &ett_samples_timestamps_sample,
1218 &ett_samples_timestamps_sample_timestamp,
1219 &ett_samples_timestamps_sample_reserved
1222 static dissector_handle_t h_calibration;
1223 static dissector_handle_t h_ident;
1224 static dissector_handle_t h_samples_im1;
1225 static dissector_handle_t h_samples_im2r0;
1227 void proto_register_locamation_im(void) {
1228 /* Setup subtrees */
1229 proto_register_subtree_array(ett, array_length(ett));
1231 /* Register Protocols */
1233 /* Calibration */
1234 h_protocol_calibration = proto_register_protocol(PROTOCOL_NAME_CALIBRATION, PROTOCOL_SHORTNAME_CALIBRATION, "locamation-im.calibration");
1235 proto_register_field_array(h_protocol_calibration, protocol_registration_calibration, array_length(protocol_registration_calibration));
1236 expert_module_t *expert_calibration = expert_register_protocol(h_protocol_calibration);
1237 expert_register_field_array(expert_calibration, ei_calibration, array_length(ei_calibration));
1239 /* Ident */
1240 h_protocol_ident = proto_register_protocol(PROTOCOL_NAME_IDENT, PROTOCOL_SHORTNAME_IDENT, "locamation-im.ident");
1241 proto_register_field_array(h_protocol_ident, protocol_registration_ident, array_length(protocol_registration_ident));
1243 /* Samples - IM1 */
1244 h_protocol_samples_im1 = proto_register_protocol(PROTOCOL_NAME_SAMPLES_IM1, PROTOCOL_SHORTNAME_SAMPLES_IM1, "locamation-im.samples.im1");
1245 proto_register_field_array(h_protocol_samples_im1, protocol_registration_samples, array_length(protocol_registration_samples));
1246 expert_module_t *expert_samples_im1 = expert_register_protocol(h_protocol_samples_im1);
1247 expert_register_field_array(expert_samples_im1, ei_samples_im1, array_length(ei_samples_im1));
1249 /* Samples - IM2R0 */
1250 h_protocol_samples_im2r0 = proto_register_protocol(PROTOCOL_NAME_SAMPLES_IM2R0, PROTOCOL_SHORTNAME_SAMPLES_IM2R0, "locamation-im.samples.im2r0");
1251 proto_register_field_array(h_protocol_samples_im2r0, protocol_registration_samples_im2, array_length(protocol_registration_samples_im2));
1252 expert_module_t *expert_samples_im2r0 = expert_register_protocol(h_protocol_samples_im2r0);
1253 expert_register_field_array(expert_samples_im2r0, ei_samples_im2r0, array_length(ei_samples_im2r0));
1255 /* LLC Handler Registration */
1256 llc_add_oui(COMPANY_OUI, "locamation-im.llc.pid", "LLC " COMPANY_NAME " OUI PID", llc_registration, -1);
1259 void proto_reg_handoff_locamation_im(void) {
1260 /* Calibration */
1261 h_calibration = create_dissector_handle(dissect_calibration, h_protocol_calibration);
1262 dissector_add_uint("locamation-im.llc.pid", COMPANY_PID_CALIBRATION, h_calibration);
1264 /* Ident */
1265 h_ident = create_dissector_handle(dissect_ident, h_protocol_ident);
1266 dissector_add_uint("locamation-im.llc.pid", COMPANY_PID_IDENT, h_ident);
1268 /* Samples - IM1 */
1269 h_samples_im1 = create_dissector_handle(dissect_samples_im1, h_protocol_samples_im1);
1270 dissector_add_uint("locamation-im.llc.pid", COMPANY_PID_SAMPLES_IM1, h_samples_im1);
1272 /* Samples - IM2R0 */
1273 h_samples_im2r0 = create_dissector_handle(dissect_samples_im2r0, h_protocol_samples_im2r0);
1274 dissector_add_uint("locamation-im.llc.pid", COMPANY_PID_SAMPLES_IM2R0, h_samples_im2r0);
1278 * Editor modelines - https://www.wireshark.org/tools/modelines.html
1280 * Local variables:
1281 * c-basic-offset: 8
1282 * tab-width: 8
1283 * indent-tabs-mode: t
1284 * End:
1286 * vi: set shiftwidth=8 tabstop=8 noexpandtab:
1287 * :indentSize=8:tabSize=8:noTabs=false: