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 */
27 #include <epan/packet.h>
30 #include <epan/expert.h>
32 #include <wsutil/array.h>
34 #include "packet-llc.h"
37 #define ETH_FRAME_LEN 1514 /* Max. octets in frame sans FCS */
41 * ########################################################################
43 * # Forward Declarations
45 * ########################################################################
48 void proto_register_locamation_im(void);
49 void proto_reg_handoff_locamation_im(void);
52 * ########################################################################
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 * ########################################################################
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
},
117 * ########################################################################
121 * ########################################################################
125 * struct _sample_set_t {
137 #define SAMPLE_SET_SIZE 34
140 * struct _timestamp_t {
141 * uint8_t sync_status;
142 * uint8_t additional_status;
147 #define TIMESTAMP_SIZE 10
150 * struct _timestamps_t {
153 * struct _timestamp_t timestamps[8];
156 #define TIMESTAMPS_SIZE 84
159 * ########################################################################
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
;
169 while (tvb_offset_exists(tvb
, offset
)) {
170 int len
= tvb_find_line_end(tvb
, offset
, -1, &next_offset
, false);
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 * ########################################################################
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
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
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)
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
);
252 /* Sequence Number */
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) {
265 /* First Sequence Number */
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 */
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
;
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
);
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
);
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
);
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 * ########################################################################
304 * ########################################################################
308 * Ident Packets are sent by IM1 and IM2R0 sensors.
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
);
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 * ########################################################################
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
,
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
);
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
;
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
};
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
) {
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
[] = {
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
,
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(×tamp_buf
[timestamp_length
], ITEM_LABEL_LENGTH
- timestamp_length
, "%Y-%m-%d %H:%M:%S.", sample_time_split
);
519 timestamp_length
+= snprintf(×tamp_buf
[timestamp_length
], ITEM_LABEL_LENGTH
- timestamp_length
, "\?\?\?\?-\?\?-\?\? \?\?:\?\?:\?\?.");
521 snprintf(×tamp_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
);
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 */
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
;
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
);
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
;
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
;
605 * Samples Packets are sent by IM1 and IM2R0 sensors.
606 * However, details of the packets differ between the sensors.
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)
620 * ADC Status: 1 byte, unsigned
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.
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)
638 * 00 = measurement ADC channel
639 * 01 = protection ADC channel, range low
640 * 10 = protection ADC channel, range high
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)
652 * 6 sample data sets, one set per ADC channel:
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
665 * 8 sample data sets, one set per ADC channel:
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
679 * * RMS values are stored as 4 byte signed values.
682 * 6 values, one per ADC-channel:
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
695 * 8 values, one per ADC-channel:
709 * * Timestamps are PTP driven and are stored in a versioned block.
710 * Each timestamp also has status information.
713 * Timestamps are not applicable for IM1.
716 * Timestamps are optional.
720 * Version 1 byte, unsigned
721 * Reserved 3 bytes, unsigned
722 * Sample 1 Timestamp (oldest sample)
729 * Sample 8 Timestamp (newest sample)
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
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
,
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
);
822 /* Transport Delay */
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
;
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
;
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);
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
);
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
;
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
;
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
;
869 proto_tree
*sample_sets_subtree
= proto_item_add_subtree(samples_item
, ett_samples_sets
);
872 item_size
= SAMPLE_SET_SIZE
* 6;
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
);
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
);
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
) {
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
);
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
);
942 proto_tree
*rms_values_subtree
= proto_item_add_subtree(samples_item
, ett_samples_rms
);
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
);
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
);
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
) {
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
);
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
);
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
;
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 */
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 * ########################################################################
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"},
1052 static const value_string samples_control_simulated_vals
[] = {
1057 static const value_string samples_control_version_vals
[] = {
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"},
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 * ########################################################################
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 * ########################################################################
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 * ########################################################################
1198 * ########################################################################
1201 static int *ett
[] = {
1202 &ett_protocol_calibration
,
1203 &ett_calibration_lines
,
1205 &ett_protocol_ident
,
1208 &ett_samples_sample_set_ranges
,
1209 &ett_protocol_samples
,
1210 &ett_samples_control
,
1212 &ett_samples_sets_set
,
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 */
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
));
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
));
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) {
1261 h_calibration
= create_dissector_handle(dissect_calibration
, h_protocol_calibration
);
1262 dissector_add_uint("locamation-im.llc.pid", COMPANY_PID_CALIBRATION
, h_calibration
);
1265 h_ident
= create_dissector_handle(dissect_ident
, h_protocol_ident
);
1266 dissector_add_uint("locamation-im.llc.pid", COMPANY_PID_IDENT
, h_ident
);
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
1283 * indent-tabs-mode: t
1286 * vi: set shiftwidth=8 tabstop=8 noexpandtab:
1287 * :indentSize=8:tabSize=8:noTabs=false: