2 * DMX packet disassembly.
4 * This dissector is written by
6 * Erwin Rol <erwin@erwinrol.com>
7 * Copyright 2012 Erwin Rol
9 * Wireshark - Network traffic analyzer
10 * Gerald Combs <gerald@wireshark.org>
11 * Copyright 1999 Gerald Combs
13 * SPDX-License-Identifier: GPL-2.0-or-later
17 * This dissector is based on;
18 * American National Standard E1.11 - 2004
19 * Entertainment Technology USITT DMX512-A
20 * Asynchronous Serial Digital Data Transmission Standard
21 * for Controlling Lighting Equipment and Accessories
27 #include <epan/packet.h>
28 #include <epan/prefs.h>
29 #include <epan/expert.h>
31 #define DMX_SC_DMX 0x00
32 #define DMX_SC_TEXT 0x17
33 #define DMX_SC_TEST 0x55
34 #define DMX_SC_RDM 0xCC
35 #define DMX_SC_SIP 0xCF
37 #define DMX_TEST_PACKET_SIZE 512
38 #define DMX_TEST_VALUE 0x55
40 static const value_string dmx_sc_vals
[] = {
41 { DMX_SC_DMX
, "DMX" },
42 { DMX_SC_TEXT
, "Text" },
43 { DMX_SC_TEST
, "Test" },
44 { DMX_SC_RDM
, "RDM" },
45 { DMX_SC_SIP
, "SIP" },
49 void proto_register_dmx(void);
50 void proto_register_dmx_chan(void);
51 void proto_register_dmx_sip(void);
52 void proto_register_dmx_test(void);
53 void proto_register_dmx_text(void);
54 void proto_reg_handoff_dmx(void);
57 static int proto_dmx_chan
;
58 static int proto_dmx_sip
;
59 static int proto_dmx_test
;
60 static int proto_dmx_text
;
62 static int hf_dmx_start_code
;
64 static int hf_dmx_chan_output_dmx_data
;
65 static int hf_dmx_chan_output_data_filter
;
67 static int hf_dmx_sip_byte_count
;
68 static int hf_dmx_sip_control_bit_field
;
69 static int hf_dmx_sip_prev_packet_checksum
;
70 static int hf_dmx_sip_seq_nr
;
71 static int hf_dmx_sip_dmx_universe_nr
;
72 static int hf_dmx_sip_dmx_proc_level
;
73 static int hf_dmx_sip_dmx_software_version
;
74 static int hf_dmx_sip_dmx_packet_len
;
75 static int hf_dmx_sip_dmx_nr_packets
;
76 static int hf_dmx_sip_orig_dev_id
;
77 static int hf_dmx_sip_sec_dev_id
;
78 static int hf_dmx_sip_third_dev_id
;
79 static int hf_dmx_sip_fourth_dev_id
;
80 static int hf_dmx_sip_fifth_dev_id
;
81 static int hf_dmx_sip_reserved
;
82 static int hf_dmx_sip_checksum
;
83 static int hf_dmx_sip_checksum_status
;
84 static int hf_dmx_sip_trailer
;
86 static int hf_dmx_test_data
;
87 static int hf_dmx_test_data_good
;
88 static int hf_dmx_test_data_bad
;
90 static int hf_dmx_text_page_nr
;
91 static int hf_dmx_text_line_len
;
92 static int hf_dmx_text_string
;
94 static int ett_dmx_chan
;
95 static int ett_dmx_sip
;
96 static int ett_dmx_test
;
97 static int ett_dmx_text
;
99 static expert_field ei_dmx_sip_checksum
;
101 static dissector_table_t dmx_dissector_table
;
103 static dissector_handle_t dmx_text_handle
;
106 * Here are the global variables associated with the preferences for DMX
108 static int global_disp_chan_val_type
;
109 static int global_disp_col_count
= 16;
110 static int global_disp_chan_nr_type
;
113 dissect_dmx_chan(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void* data _U_
)
115 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, "DMX Channels");
116 col_clear(pinfo
->cinfo
, COL_INFO
);
119 static const char *chan_format
[] = {
124 static const char *string_format
[] = {
128 wmem_strbuf_t
*chan_str
= wmem_strbuf_create(pinfo
->pool
);
130 uint16_t length
,r
,c
,row_count
;
134 proto_tree
*ti
= proto_tree_add_item(tree
, proto_dmx_chan
, tvb
, offset
, -1, ENC_NA
);
135 proto_tree
*dmx_chan_tree
= proto_item_add_subtree(ti
, ett_dmx_chan
);
137 length
= tvb_reported_length_remaining(tvb
, offset
);
139 row_count
= (length
/ global_disp_col_count
) + ((length
% global_disp_col_count
) == 0 ? 0 : 1);
140 for (r
= 0; r
< row_count
;r
++) {
141 wmem_strbuf_truncate(chan_str
, 0);
142 for (c
= 0;(c
< global_disp_col_count
) && (((r
* global_disp_col_count
) + c
) < length
);c
++) {
143 if ((global_disp_col_count
>= 2) && ((c
% (global_disp_col_count
/ 2)) == 0)) {
144 wmem_strbuf_append(chan_str
, " ");
147 v
= tvb_get_uint8(tvb
, (offset
+ (r
* global_disp_col_count
) + c
));
148 if (global_disp_chan_val_type
== 0) {
151 wmem_strbuf_append(chan_str
, "FL ");
153 wmem_strbuf_append_printf(chan_str
, chan_format
[global_disp_chan_val_type
], v
);
156 wmem_strbuf_append_printf(chan_str
, chan_format
[global_disp_chan_val_type
], v
);
160 proto_tree_add_none_format(dmx_chan_tree
, hf_dmx_chan_output_dmx_data
, tvb
,
161 offset
+(r
* global_disp_col_count
), c
,
162 string_format
[global_disp_chan_nr_type
],
163 (r
* global_disp_col_count
) + 1, wmem_strbuf_get_str(chan_str
));
166 /* Add the real type hidden */
167 item
= proto_tree_add_item(dmx_chan_tree
, hf_dmx_chan_output_data_filter
, tvb
,
168 offset
, length
, ENC_NA
);
169 proto_item_set_hidden(item
);
171 return tvb_captured_length(tvb
);
175 dmx_sip_checksum(tvbuff_t
*tvb
, unsigned length
)
177 uint8_t sum
= DMX_SC_SIP
;
179 for (i
= 0; i
< length
; i
++)
180 sum
+= tvb_get_uint8(tvb
, i
);
185 dissect_dmx_sip(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void* data _U_
)
187 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, "DMX SIP");
188 col_clear(pinfo
->cinfo
, COL_INFO
);
194 proto_tree
*ti
= proto_tree_add_item(tree
, proto_dmx_sip
, tvb
,
196 proto_tree
*dmx_sip_tree
= proto_item_add_subtree(ti
, ett_dmx_sip
);
199 byte_count
= tvb_get_uint8(tvb
, offset
);
200 proto_tree_add_item(dmx_sip_tree
, hf_dmx_sip_byte_count
, tvb
,
201 offset
, 1, ENC_BIG_ENDIAN
);
204 proto_tree_add_item(dmx_sip_tree
, hf_dmx_sip_control_bit_field
, tvb
,
205 offset
, 1, ENC_BIG_ENDIAN
);
208 proto_tree_add_item(dmx_sip_tree
, hf_dmx_sip_prev_packet_checksum
, tvb
,
209 offset
, 2, ENC_BIG_ENDIAN
);
212 proto_tree_add_item(dmx_sip_tree
, hf_dmx_sip_seq_nr
, tvb
,
213 offset
, 1, ENC_BIG_ENDIAN
);
216 proto_tree_add_item(dmx_sip_tree
, hf_dmx_sip_dmx_universe_nr
, tvb
,
217 offset
, 1, ENC_BIG_ENDIAN
);
220 proto_tree_add_item(dmx_sip_tree
, hf_dmx_sip_dmx_proc_level
, tvb
,
221 offset
, 1, ENC_BIG_ENDIAN
);
224 proto_tree_add_item(dmx_sip_tree
, hf_dmx_sip_dmx_software_version
, tvb
,
225 offset
, 1, ENC_BIG_ENDIAN
);
228 proto_tree_add_item(dmx_sip_tree
, hf_dmx_sip_dmx_packet_len
, tvb
,
229 offset
, 2, ENC_BIG_ENDIAN
);
232 proto_tree_add_item(dmx_sip_tree
, hf_dmx_sip_dmx_nr_packets
, tvb
,
233 offset
, 2, ENC_BIG_ENDIAN
);
236 proto_tree_add_item(dmx_sip_tree
, hf_dmx_sip_orig_dev_id
, tvb
,
237 offset
, 2, ENC_BIG_ENDIAN
);
240 proto_tree_add_item(dmx_sip_tree
, hf_dmx_sip_sec_dev_id
, tvb
,
241 offset
, 2, ENC_BIG_ENDIAN
);
244 proto_tree_add_item(dmx_sip_tree
, hf_dmx_sip_third_dev_id
, tvb
,
245 offset
, 2, ENC_BIG_ENDIAN
);
248 proto_tree_add_item(dmx_sip_tree
, hf_dmx_sip_fourth_dev_id
, tvb
,
249 offset
, 2, ENC_BIG_ENDIAN
);
252 proto_tree_add_item(dmx_sip_tree
, hf_dmx_sip_fifth_dev_id
, tvb
,
253 offset
, 2, ENC_BIG_ENDIAN
);
256 if (offset
< byte_count
) {
257 proto_tree_add_item(dmx_sip_tree
, hf_dmx_sip_reserved
, tvb
,
258 offset
, byte_count
- offset
, ENC_NA
);
259 offset
+= (byte_count
- offset
);
262 proto_tree_add_checksum(dmx_sip_tree
, tvb
, offset
, hf_dmx_sip_checksum
, hf_dmx_sip_checksum_status
, &ei_dmx_sip_checksum
, pinfo
, dmx_sip_checksum(tvb
, offset
), ENC_NA
, PROTO_CHECKSUM_VERIFY
);
265 if (offset
< tvb_reported_length(tvb
))
266 proto_tree_add_item(dmx_sip_tree
, hf_dmx_sip_trailer
, tvb
,
269 return tvb_captured_length(tvb
);
273 dissect_dmx_test(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void* data _U_
)
275 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, "DMX Test Frame");
276 col_clear(pinfo
->cinfo
, COL_INFO
);
280 unsigned size
, i
, test_data_is_ok
;
281 proto_tree
*test_data_tree
;
284 proto_tree
*ti
= proto_tree_add_item(tree
, proto_dmx_test
, tvb
,
286 proto_tree
*dmx_test_tree
= proto_item_add_subtree(ti
, ett_dmx_test
);
288 size
= tvb_reported_length_remaining(tvb
, offset
);
290 item
= proto_tree_add_item(dmx_test_tree
, hf_dmx_test_data
, tvb
,
291 offset
, size
, ENC_NA
);
294 if (size
== DMX_TEST_PACKET_SIZE
) {
295 test_data_is_ok
= true;
296 for (i
= 0; i
< DMX_TEST_PACKET_SIZE
; i
++) {
297 if (tvb_get_uint8(tvb
, i
) != DMX_TEST_VALUE
) {
298 test_data_is_ok
= false;
303 test_data_is_ok
= false;
306 if (test_data_is_ok
) {
307 proto_item_append_text(ti
, ", Data correct");
308 proto_item_append_text(item
, " [correct]");
310 test_data_tree
= proto_item_add_subtree(item
, ett_dmx_test
);
311 item
= proto_tree_add_boolean(test_data_tree
, hf_dmx_test_data_good
, tvb
,
313 proto_item_set_generated(item
);
314 item
= proto_tree_add_boolean(test_data_tree
, hf_dmx_test_data_bad
, tvb
,
315 offset
, size
, false);
316 proto_item_set_generated(item
);
318 proto_item_append_text(ti
, ", Data incorrect");
319 proto_item_append_text(item
, " [incorrect]");
321 test_data_tree
= proto_item_add_subtree(item
, ett_dmx_test
);
322 item
= proto_tree_add_boolean(test_data_tree
, hf_dmx_test_data_good
, tvb
,
323 offset
, size
, false);
324 proto_item_set_generated(item
);
325 item
= proto_tree_add_boolean(test_data_tree
, hf_dmx_test_data_bad
, tvb
,
327 proto_item_set_generated(item
);
330 return tvb_captured_length(tvb
);
334 dissect_dmx_text(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void* data _U_
)
336 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, "DMX Text");
337 col_clear(pinfo
->cinfo
, COL_INFO
);
343 proto_tree
*ti
= proto_tree_add_item(tree
, proto_dmx_text
, tvb
,
345 proto_tree
*dmx_text_tree
= proto_item_add_subtree(ti
, ett_dmx_text
);
347 proto_tree_add_item(dmx_text_tree
, hf_dmx_text_page_nr
, tvb
,
348 offset
, 1, ENC_BIG_ENDIAN
);
351 proto_tree_add_item(dmx_text_tree
, hf_dmx_text_line_len
, tvb
,
352 offset
, 1, ENC_BIG_ENDIAN
);
355 size
= tvb_reported_length_remaining(tvb
, offset
);
357 proto_tree_add_item(dmx_text_tree
, hf_dmx_text_string
, tvb
,
358 offset
, size
, ENC_ASCII
);
360 return tvb_captured_length(tvb
);
364 dissect_dmx(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void* data _U_
)
370 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, "DMX");
371 col_clear(pinfo
->cinfo
, COL_INFO
);
373 start_code
= tvb_get_uint8(tvb
, offset
);
374 proto_tree_add_item(tree
, hf_dmx_start_code
, tvb
,
375 offset
, 1, ENC_BIG_ENDIAN
);
378 next_tvb
= tvb_new_subset_remaining(tvb
, offset
);
380 if (!dissector_try_uint_with_data(dmx_dissector_table
, start_code
, tvb
, pinfo
,
382 call_data_dissector(next_tvb
, pinfo
, tree
);
385 return tvb_captured_length(tvb
);
389 proto_register_dmx(void)
391 static hf_register_info hf
[] = {
392 { &hf_dmx_start_code
,
393 { "Start Code", "dmx.start_code",
394 FT_UINT8
, BASE_HEX
, VALS(dmx_sc_vals
), 0x0,
398 proto_dmx
= proto_register_protocol("DMX", "DMX", "dmx");
399 proto_register_field_array(proto_dmx
, hf
, array_length(hf
));
400 register_dissector("dmx", dissect_dmx
, proto_dmx
);
402 dmx_dissector_table
= register_dissector_table("dmx", "DMX Start Code", proto_dmx
,
408 proto_register_dmx_chan(void)
410 static hf_register_info hf
[] = {
411 { &hf_dmx_chan_output_data_filter
,
413 "dmx_chan.data_filter",
414 FT_BYTES
, BASE_NONE
, NULL
, 0x0,
417 { &hf_dmx_chan_output_dmx_data
,
420 FT_NONE
, BASE_NONE
, NULL
, 0x0,
424 static int *ett
[] = {
428 module_t
*dmx_chan_module
;
430 static const enum_val_t disp_chan_val_types
[] = {
431 { "pro", "Percent", 0 },
432 { "hex", "Hexadecimal", 1 },
433 { "dec", "Decimal", 2 },
437 static const enum_val_t disp_chan_nr_types
[] = {
438 { "hex", "Hexadecimal", 0 },
439 { "dec", "Decimal", 1 },
443 static const enum_val_t col_count
[] = {
452 proto_dmx_chan
= proto_register_protocol("DMX Channels","DMX Channels", "dmx_chan");
453 proto_register_field_array(proto_dmx_chan
, hf
, array_length(hf
));
454 proto_register_subtree_array(ett
, array_length(ett
));
455 register_dissector("dmx-chan", dissect_dmx_chan
, proto_dmx_chan
);
457 dmx_chan_module
= prefs_register_protocol(proto_dmx_chan
, NULL
);
459 prefs_register_enum_preference(dmx_chan_module
, "dmx_disp_chan_val_type",
460 "DMX Display channel value type",
461 "The way DMX values are displayed",
462 &global_disp_chan_val_type
,
463 disp_chan_val_types
, false);
465 prefs_register_enum_preference(dmx_chan_module
, "dmx_disp_chan_nr_type",
466 "DMX Display channel nr. type",
467 "The way DMX channel numbers are displayed",
468 &global_disp_chan_nr_type
,
469 disp_chan_nr_types
, false);
471 prefs_register_enum_preference(dmx_chan_module
, "dmx_disp_col_count",
472 "DMX Display Column Count",
473 "The number of columns for the DMX display",
474 &global_disp_col_count
,
479 proto_register_dmx_sip(void)
481 static hf_register_info hf
[] = {
482 { &hf_dmx_sip_byte_count
,
483 { "Byte Count", "dmx_sip.byte_count",
484 FT_UINT8
, BASE_DEC
, NULL
, 0x0,
487 { &hf_dmx_sip_control_bit_field
,
488 { "Control Bit Field", "dmx_sip.control_bit_field",
489 FT_UINT8
, BASE_HEX
, NULL
, 0x0,
492 { &hf_dmx_sip_prev_packet_checksum
,
493 { "Checksum of prev. packet", "dmx_sip.prev_packet_checksum",
494 FT_UINT16
, BASE_HEX
, NULL
, 0x0,
497 { &hf_dmx_sip_seq_nr
,
498 { "SIP sequence nr.", "dmx_sip.seq_nr",
499 FT_UINT8
, BASE_DEC
, NULL
, 0x0,
502 { &hf_dmx_sip_dmx_universe_nr
,
503 { "DMX512 universe nr.", "dmx_sip.dmx_universe_nr",
504 FT_UINT8
, BASE_DEC
, NULL
, 0x0,
507 { &hf_dmx_sip_dmx_proc_level
,
508 { "DMX512 processing level", "dmx_sip.dmx_proc_level",
509 FT_UINT8
, BASE_DEC
, NULL
, 0x0,
512 { &hf_dmx_sip_dmx_software_version
,
513 { "Software Version", "dmx_sip.dmx_software_version",
514 FT_UINT8
, BASE_HEX
, NULL
, 0x0,
517 { &hf_dmx_sip_dmx_packet_len
,
518 { "Standard Packet Len", "dmx_sip.dmx_packet_len",
519 FT_UINT16
, BASE_HEX
, NULL
, 0x0,
522 { &hf_dmx_sip_dmx_nr_packets
,
523 { "Number of Packets", "dmx_sip.dmx_nr_packets",
524 FT_UINT16
, BASE_DEC
, NULL
, 0x0,
527 { &hf_dmx_sip_orig_dev_id
,
528 { "1st Device's ID", "dmx_sip.orig_dev_id",
529 FT_UINT16
, BASE_HEX
, NULL
, 0x0,
532 { &hf_dmx_sip_sec_dev_id
,
533 { "2nd Device's ID", "dmx_sip.sec_dev_id",
534 FT_UINT16
, BASE_HEX
, NULL
, 0x0,
537 { &hf_dmx_sip_third_dev_id
,
538 { "3rd Device's ID", "dmx_sip.third_dev_id",
539 FT_UINT16
, BASE_HEX
, NULL
, 0x0,
542 { &hf_dmx_sip_fourth_dev_id
,
543 { "4th Device's ID", "dmx_sip.fourth_dev_id",
544 FT_UINT16
, BASE_HEX
, NULL
, 0x0,
547 { &hf_dmx_sip_fifth_dev_id
,
548 { "5th Device's ID", "dmx_sip.fifth_dev_id",
549 FT_UINT16
, BASE_HEX
, NULL
, 0x0,
552 { &hf_dmx_sip_reserved
,
553 { "Reserved", "dmx_sip.reserved",
554 FT_BYTES
, BASE_NONE
, NULL
, 0x0,
557 { &hf_dmx_sip_checksum
,
558 { "Checksum", "dmx_sip.checksum",
559 FT_UINT8
, BASE_HEX
, NULL
, 0x0,
562 { &hf_dmx_sip_checksum_status
,
563 { "Checksum Status", "dmx_sip.checksum.status",
564 FT_UINT8
, BASE_NONE
, VALS(proto_checksum_vals
), 0x0,
567 { &hf_dmx_sip_trailer
,
568 { "Trailer", "dmx_sip.trailer",
569 FT_BYTES
, BASE_NONE
, NULL
, 0x0,
573 static int *ett
[] = {
577 static ei_register_info ei
[] = {
578 { &ei_dmx_sip_checksum
, { "dmx_sip.bad_checksum", PI_CHECKSUM
, PI_ERROR
, "Bad checksum", EXPFILL
}},
581 expert_module_t
* expert_dmx_sip
;
583 proto_dmx_sip
= proto_register_protocol("DMX SIP", "DMX SIP", "dmx_sip");
584 proto_register_field_array(proto_dmx_sip
, hf
, array_length(hf
));
585 proto_register_subtree_array(ett
, array_length(ett
));
586 expert_dmx_sip
= expert_register_protocol(proto_dmx_sip
);
587 expert_register_field_array(expert_dmx_sip
, ei
, array_length(ei
));
591 proto_register_dmx_test(void)
593 static hf_register_info hf
[] = {
595 { "Test Data", "dmx_test.data",
596 FT_BYTES
, BASE_NONE
, NULL
, 0x0,
599 { &hf_dmx_test_data_good
,
600 { "Data Good", "dmx_test.data_good",
601 FT_BOOLEAN
, BASE_NONE
, NULL
, 0x0,
602 "True: test data is correct; False: test data is incorrect", HFILL
}},
604 { &hf_dmx_test_data_bad
,
605 { "Data Bad", "dmx_test.data_bad",
606 FT_BOOLEAN
, BASE_NONE
, NULL
, 0x0,
607 "True: test data is incorrect; False: test data is correct", HFILL
}},
610 static int *ett
[] = {
614 proto_dmx_test
= proto_register_protocol("DMX Test Frame", "DMX Test Frame", "dmx_test");
615 proto_register_field_array(proto_dmx_test
, hf
, array_length(hf
));
616 proto_register_subtree_array(ett
, array_length(ett
));
620 proto_register_dmx_text(void)
622 static hf_register_info hf
[] = {
623 { &hf_dmx_text_page_nr
,
626 FT_UINT8
, BASE_DEC
, NULL
, 0x0,
628 { &hf_dmx_text_line_len
,
630 "dmx_text.line_length",
631 FT_UINT8
, BASE_DEC
, NULL
, 0x0,
633 { &hf_dmx_text_string
,
636 FT_STRING
, BASE_NONE
, NULL
, 0x0,
640 static int *ett
[] = {
644 proto_dmx_text
= proto_register_protocol("DMX Text Frame", "DMX Text Frame", "dmx_text");
645 proto_register_field_array(proto_dmx_text
, hf
, array_length(hf
));
646 proto_register_subtree_array(ett
, array_length(ett
));
650 proto_reg_handoff_dmx(void)
652 dmx_text_handle
= find_dissector("dmx-text");
654 dissector_add_uint("dmx", DMX_SC_DMX
, create_dissector_handle(dissect_dmx_chan
, proto_dmx_chan
));
655 dissector_add_uint("dmx", DMX_SC_SIP
, create_dissector_handle(dissect_dmx_sip
, proto_dmx_sip
));
656 dissector_add_uint("dmx", DMX_SC_TEST
, create_dissector_handle(dissect_dmx_test
, proto_dmx_test
));
657 dissector_add_uint("dmx", DMX_SC_TEXT
, create_dissector_handle(dissect_dmx_text
, proto_dmx_text
));
661 * Editor modelines - https://www.wireshark.org/tools/modelines.html
666 * indent-tabs-mode: t
669 * vi: set shiftwidth=8 tabstop=8 noexpandtab:
670 * :indentSize=8:tabSize=8:noTabs=false: