HACK: 2nd try to match RowsetProperties
[wireshark-wip.git] / epan / dissectors / packet-enttec.c
blob270a388e2c3310458e2d4bdd8fe2bd9f6ee4a69b
1 /* packet-enttec.c
2 * Routines for ENTTEC packet disassembly
4 * $Id$
6 * Copyright (c) 2003,2004 by Erwin Rol <erwin@erwinrol.com>
8 * Wireshark - Network traffic analyzer
9 * By Gerald Combs <gerald@wireshark.org>
10 * Copyright 1999 Gerald Combs
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
27 /* Include files */
29 #include "config.h"
31 #include <glib.h>
33 #include <epan/packet.h>
34 #include <epan/addr_resolv.h>
35 #include <epan/prefs.h>
36 #include <epan/wmem/wmem.h>
39 * See
41 * http://www.enttec.com/docs/enttec_protocol.pdf
44 /* Define UDP/TCP ports for ENTTEC */
46 #define UDP_PORT_ENTTEC 0x0D05
47 #define TCP_PORT_ENTTEC 0x0D05
50 #define ENTTEC_HEAD_ESPR 0x45535052
51 #define ENTTEC_HEAD_ESPP 0x45535050
52 #define ENTTEC_HEAD_ESAP 0x45534150
53 #define ENTTEC_HEAD_ESDD 0x45534444
54 #define ENTTEC_HEAD_ESNC 0x45534E43
55 #define ENTTEC_HEAD_ESZZ 0x45535A5A
57 static const value_string enttec_head_vals[] = {
58 { ENTTEC_HEAD_ESPR, "Poll Reply" },
59 { ENTTEC_HEAD_ESPP, "Poll" },
60 { ENTTEC_HEAD_ESAP, "Ack/nAck" },
61 { ENTTEC_HEAD_ESDD, "DMX Data" },
62 { ENTTEC_HEAD_ESNC, "Config" },
63 { ENTTEC_HEAD_ESZZ, "Reset" },
64 { 0, NULL }
67 #define ENTTEC_DATA_TYPE_DMX 0x01
68 #define ENTTEC_DATA_TYPE_CHAN_VAL 0x02
69 #define ENTTEC_DATA_TYPE_RLE 0x04
71 static const value_string enttec_data_type_vals[] = {
72 { ENTTEC_DATA_TYPE_DMX, "Uncompressed DMX" },
73 { ENTTEC_DATA_TYPE_CHAN_VAL, "Channel+Value" },
74 { ENTTEC_DATA_TYPE_RLE, "RLE Compressed DMX" },
75 { 0, NULL }
78 void proto_register_enttec(void);
79 void proto_reg_handoff_enttec(void);
81 /* Define the enttec proto */
82 static int proto_enttec = -1;
84 /* general */
85 static int hf_enttec_head = -1;
87 /* poll */
88 static int hf_enttec_poll_type = -1;
90 /* poll reply */
91 static int hf_enttec_poll_reply_mac = -1;
92 static int hf_enttec_poll_reply_node_type = -1;
93 static int hf_enttec_poll_reply_version = -1;
94 static int hf_enttec_poll_reply_switch = -1;
95 static int hf_enttec_poll_reply_name = -1;
96 static int hf_enttec_poll_reply_option = -1;
97 static int hf_enttec_poll_reply_tos = -1;
98 static int hf_enttec_poll_reply_ttl = -1;
100 /* dmx data */
101 static int hf_enttec_dmx_data_universe = -1;
102 static int hf_enttec_dmx_data_start_code = -1;
103 static int hf_enttec_dmx_data_type = -1;
104 static int hf_enttec_dmx_data_size = -1;
105 static int hf_enttec_dmx_data_data = -1;
106 static int hf_enttec_dmx_data_data_filter = -1;
107 static int hf_enttec_dmx_data_dmx_data = -1;
109 /* Define the tree for enttec */
110 static int ett_enttec = -1;
113 * Here are the global variables associated with the preferences
114 * for enttec
117 static guint global_udp_port_enttec = UDP_PORT_ENTTEC;
118 static guint global_tcp_port_enttec = TCP_PORT_ENTTEC;
120 static gint global_disp_chan_val_type = 0;
121 static gint global_disp_col_count = 16;
122 static gint global_disp_chan_nr_type = 0;
124 static gint
125 dissect_enttec_poll_reply(tvbuff_t *tvb, guint offset, proto_tree *tree)
127 proto_tree_add_item(tree, hf_enttec_poll_reply_mac, tvb,
128 offset, 6, ENC_NA);
129 offset += 6;
131 proto_tree_add_item(tree, hf_enttec_poll_reply_node_type, tvb,
132 offset, 2, ENC_BIG_ENDIAN);
133 offset += 2;
135 proto_tree_add_item(tree, hf_enttec_poll_reply_version, tvb,
136 offset, 1, ENC_BIG_ENDIAN);
137 offset += 1;
139 proto_tree_add_item(tree, hf_enttec_poll_reply_switch, tvb,
140 offset, 1, ENC_BIG_ENDIAN);
141 offset += 1;
143 proto_tree_add_item(tree, hf_enttec_poll_reply_name, tvb,
144 offset, 10, ENC_ASCII|ENC_NA);
145 offset += 10;
147 proto_tree_add_item(tree, hf_enttec_poll_reply_option, tvb,
148 offset, 1, ENC_BIG_ENDIAN);
149 offset += 1;
151 proto_tree_add_item(tree, hf_enttec_poll_reply_tos, tvb,
152 offset, 1, ENC_BIG_ENDIAN);
153 offset += 1;
155 proto_tree_add_item(tree, hf_enttec_poll_reply_ttl, tvb,
156 offset, 1, ENC_BIG_ENDIAN);
157 offset += 1;
159 /* data */
161 return offset;
164 static gint
165 dissect_enttec_poll(tvbuff_t *tvb, guint offset, proto_tree *tree)
167 proto_tree_add_item(tree, hf_enttec_poll_type, tvb,
168 offset, 1, ENC_BIG_ENDIAN);
169 offset += 1;
171 return offset;
174 static gint
175 dissect_enttec_ack(tvbuff_t *tvb _U_, guint offset, proto_tree *tree _U_)
178 return offset;
181 static gint
182 dissect_enttec_dmx_data(tvbuff_t *tvb, guint offset, proto_tree *tree)
184 static const char* chan_format[] = {
185 "%2u ",
186 "%02x ",
187 "%3u "
189 static const char* string_format[] = {
190 "%03x: %s",
191 "%3u: %s"
194 guint8 *dmx_data = (guint8 *)wmem_alloc(wmem_packet_scope(), 512 * sizeof(guint8));
195 guint16 *dmx_data_offset = (guint16 *)wmem_alloc(wmem_packet_scope(), 513 * sizeof(guint16)); /* 1 extra for last offset */
196 wmem_strbuf_t *dmx_epstr;
198 proto_tree *hi,*si;
199 proto_item *item;
200 guint16 length,r,c,row_count;
201 guint8 v,type,count;
202 guint16 ci,ui,i,start_offset,end_offset;
204 proto_tree_add_item(tree, hf_enttec_dmx_data_universe, tvb,
205 offset, 1, ENC_BIG_ENDIAN);
206 offset += 1;
208 proto_tree_add_item(tree, hf_enttec_dmx_data_start_code, tvb,
209 offset, 1, ENC_BIG_ENDIAN);
210 offset += 1;
212 type = tvb_get_guint8(tvb, offset);
213 proto_tree_add_item(tree, hf_enttec_dmx_data_type, tvb,
214 offset, 1, ENC_BIG_ENDIAN);
215 offset += 1;
217 length = tvb_get_ntohs(tvb, offset);
218 proto_tree_add_item(tree, hf_enttec_dmx_data_size, tvb,
219 offset, 2, ENC_BIG_ENDIAN);
220 offset += 2;
223 * XXX - we should handle a too-long length better.
225 if (length > 512)
226 length = 512;
228 if (type == ENTTEC_DATA_TYPE_RLE) {
229 /* uncompress the DMX data */
230 ui = 0;
231 ci = 0;
232 while (ci < length && ui < 512) {
233 v = tvb_get_guint8(tvb, offset+ci);
234 if (v == 0xFE) {
235 ci++;
236 count = tvb_get_guint8(tvb, offset+ci);
237 ci++;
238 v = tvb_get_guint8(tvb, offset+ci);
239 ci++;
240 for (i=0;i < count && ui < 512;i++) {
241 dmx_data[ui] = v;
242 dmx_data_offset[ui] = ci-3;
243 ui++;
245 } else if (v == 0xFD) {
246 ci++;
247 v = tvb_get_guint8(tvb, offset+ci);
248 dmx_data[ui] = v;
249 dmx_data_offset[ui] = ci;
250 ci++;
251 ui++;
252 } else {
253 dmx_data[ui] = v;
254 dmx_data_offset[ui] = ci;
255 ui++;
256 ci++;
259 dmx_data_offset[ui] = ci;
260 } else {
261 for (ui=0; ui < length;ui++) {
262 dmx_data[ui] = tvb_get_guint8(tvb, offset+ui);
263 dmx_data_offset[ui] = ui;
265 dmx_data_offset[ui] = ui;
269 if ((type == ENTTEC_DATA_TYPE_DMX || type == ENTTEC_DATA_TYPE_RLE) && global_disp_col_count > 0) {
270 hi = proto_tree_add_item(tree,
271 hf_enttec_dmx_data_data,
272 tvb,
273 offset,
274 length,
275 ENC_NA);
277 si = proto_item_add_subtree(hi, ett_enttec);
279 row_count = (ui/global_disp_col_count) + ((ui%global_disp_col_count) == 0 ? 0 : 1);
280 dmx_epstr = wmem_strbuf_new_label(wmem_packet_scope());
281 for (r=0; r < row_count;r++) {
282 for (c=0;(c < global_disp_col_count) && (((r*global_disp_col_count)+c) < ui);c++) {
283 if ((global_disp_col_count > 1) && (c % (global_disp_col_count/2)) == 0) {
284 wmem_strbuf_append_c(dmx_epstr, ' ');
286 v = dmx_data[(r*global_disp_col_count)+c];
287 if (global_disp_chan_val_type == 0) {
288 v = (v * 100) / 255;
289 if (v == 100) {
290 wmem_strbuf_append(dmx_epstr, "FL ");
291 } else {
292 wmem_strbuf_append_printf(dmx_epstr, chan_format[global_disp_chan_val_type], v);
294 } else {
295 wmem_strbuf_append_printf(dmx_epstr, chan_format[global_disp_chan_val_type], v);
299 start_offset = dmx_data_offset[(r*global_disp_col_count)];
300 end_offset = dmx_data_offset[(r*global_disp_col_count)+c];
302 proto_tree_add_none_format(si,hf_enttec_dmx_data_dmx_data, tvb,
303 offset+start_offset,
304 end_offset-start_offset,
305 string_format[global_disp_chan_nr_type], (r*global_disp_col_count)+1,
306 wmem_strbuf_get_str(dmx_epstr));
307 wmem_strbuf_truncate(dmx_epstr, 0);
310 item = proto_tree_add_item(si, hf_enttec_dmx_data_data_filter, tvb,
311 offset, length, ENC_NA );
312 PROTO_ITEM_SET_HIDDEN(item);
314 offset += length;
315 } else if (type == ENTTEC_DATA_TYPE_CHAN_VAL) {
316 proto_tree_add_item(tree, hf_enttec_dmx_data_data_filter, tvb,
317 offset, length, ENC_NA);
318 offset += length;
319 } else {
320 proto_tree_add_item(tree, hf_enttec_dmx_data_data_filter, tvb,
321 offset, length, ENC_NA);
322 offset += length;
327 return offset;
330 static gint
331 dissect_enttec_config(tvbuff_t *tvb _U_, guint offset, proto_tree *tree _U_)
334 return offset;
337 static gint
338 dissect_enttec_reset(tvbuff_t *tvb _U_, guint offset, proto_tree *tree _U_)
341 return offset;
344 static int
345 dissect_enttec(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
347 gint offset = 0;
348 guint32 head = 0;
349 proto_tree *ti,*enttec_tree=NULL;
351 /* Set the protocol column */
352 col_set_str(pinfo->cinfo, COL_PROTOCOL, "ENTTEC");
354 head = tvb_get_ntohl(tvb, offset);
356 /* Clear out stuff in the info column */
357 col_add_fstr(pinfo->cinfo, COL_INFO, "%s",
358 val_to_str(head, enttec_head_vals, "Unknown (0x%08x)"));
360 if (tree) {
361 ti = proto_tree_add_item(tree, proto_enttec, tvb, offset, -1, ENC_NA);
362 enttec_tree = proto_item_add_subtree(ti, ett_enttec);
365 if (enttec_tree) {
366 proto_tree_add_item(enttec_tree, hf_enttec_head, tvb,
367 offset, 4, ENC_BIG_ENDIAN );
368 offset += 4;
370 switch (head) {
371 case ENTTEC_HEAD_ESPR:
372 offset = dissect_enttec_poll_reply( tvb, offset, enttec_tree);
373 break;
375 case ENTTEC_HEAD_ESPP:
376 offset = dissect_enttec_poll( tvb, offset, enttec_tree);
377 break;
379 case ENTTEC_HEAD_ESAP:
380 offset = dissect_enttec_ack( tvb, offset, enttec_tree);
381 break;
383 case ENTTEC_HEAD_ESDD:
384 offset = dissect_enttec_dmx_data( tvb, offset, enttec_tree);
385 break;
387 case ENTTEC_HEAD_ESNC:
388 offset = dissect_enttec_config( tvb, offset, enttec_tree);
389 break;
391 case ENTTEC_HEAD_ESZZ:
392 offset = dissect_enttec_reset( tvb, offset, enttec_tree);
393 break;
397 return offset;
400 void
401 proto_register_enttec(void)
403 static hf_register_info hf[] = {
404 /* General */
405 { &hf_enttec_head,
406 { "Head", "enttec.head",
407 FT_UINT32, BASE_HEX, VALS(enttec_head_vals), 0x0,
408 NULL, HFILL } },
409 { &hf_enttec_poll_reply_mac,
410 { "MAC", "enttec.poll_reply.mac",
411 FT_ETHER, BASE_NONE, NULL, 0x0,
412 NULL, HFILL } },
413 { &hf_enttec_poll_reply_node_type,
414 { "Node Type", "enttec.poll_reply.node_type",
415 FT_UINT16, BASE_HEX, NULL, 0x0,
416 NULL, HFILL } },
417 { &hf_enttec_poll_reply_version,
418 { "Version", "enttec.poll_reply.version",
419 FT_UINT8, BASE_DEC, NULL, 0x0,
420 NULL, HFILL } },
421 { &hf_enttec_poll_reply_switch,
422 { "Switch settings", "enttec.poll_reply.switch_settings",
423 FT_UINT8, BASE_HEX, NULL, 0x0,
424 NULL, HFILL } },
425 { &hf_enttec_poll_reply_name,
426 { "Name", "enttec.poll_reply.name",
427 FT_STRING, BASE_NONE, NULL, 0x0,
428 NULL, HFILL } },
429 { &hf_enttec_poll_reply_option,
430 { "Option Field", "enttec.poll_reply.option_field",
431 FT_UINT8, BASE_HEX, NULL, 0x0,
432 NULL, HFILL } },
433 { &hf_enttec_poll_reply_tos,
434 { "TOS", "enttec.poll_reply.tos",
435 FT_UINT8, BASE_HEX, NULL, 0x0,
436 NULL, HFILL } },
437 { &hf_enttec_poll_reply_ttl,
438 { "TTL", "enttec.poll_reply.ttl",
439 FT_UINT8, BASE_DEC, NULL, 0x0,
440 NULL, HFILL } },
441 { &hf_enttec_dmx_data_universe,
442 { "Universe", "enttec.dmx_data.universe",
443 FT_UINT8, BASE_DEC, NULL, 0x0,
444 NULL, HFILL } },
445 { &hf_enttec_dmx_data_start_code,
446 { "Start Code", "enttec.dmx_data.start_code",
447 FT_UINT8, BASE_DEC, NULL, 0x0,
448 NULL, HFILL } },
449 { &hf_enttec_dmx_data_type,
450 { "Data Type", "enttec.dmx_data.type",
451 FT_UINT8, BASE_HEX, VALS(enttec_data_type_vals), 0x0,
452 NULL, HFILL } },
453 { &hf_enttec_dmx_data_size,
454 { "Data Size", "enttec.dmx_data.size",
455 FT_UINT16, BASE_DEC, NULL, 0x0,
456 NULL, HFILL } },
457 { &hf_enttec_dmx_data_data,
458 { "DMX Data", "enttec.dmx_data.data",
459 FT_NONE, BASE_NONE, NULL, 0x0,
460 NULL, HFILL } },
461 { &hf_enttec_dmx_data_data_filter,
462 { "DMX Data", "enttec.dmx_data.data_filter",
463 FT_BYTES, BASE_NONE, NULL, 0x0,
464 NULL, HFILL } },
465 { &hf_enttec_dmx_data_dmx_data,
466 { "DMX Data", "enttec.dmx_data.dmx_data",
467 FT_NONE, BASE_NONE, NULL, 0x0,
468 NULL, HFILL } },
469 { &hf_enttec_poll_type,
470 { "Reply Type", "enttec.poll.reply_type",
471 FT_UINT8, BASE_DEC, NULL, 0x0,
472 NULL, HFILL } }
475 static gint *ett[] = {
476 &ett_enttec,
479 module_t *enttec_module;
481 static const enum_val_t disp_chan_val_types[] = {
482 { "pro", "Percent", 0 },
483 { "hex", "Hexadecimal", 1 },
484 { "dec", "Decimal", 2 },
485 { NULL, NULL, 0 }
488 static const enum_val_t disp_chan_nr_types[] = {
489 { "hex", "Hexadecimal", 0 },
490 { "dec", "Decimal", 1 },
491 { NULL, NULL, 0 }
494 static const enum_val_t col_count[] = {
495 { "6", "6", 6 },
496 { "10", "10", 10 },
497 { "12", "12", 12 },
498 { "16", "16", 16 },
499 { "24", "24", 24 },
500 { NULL, NULL, 0 }
503 proto_enttec = proto_register_protocol("ENTTEC", "ENTTEC","enttec");
504 proto_register_field_array(proto_enttec,hf,array_length(hf));
505 proto_register_subtree_array(ett,array_length(ett));
507 enttec_module = prefs_register_protocol(proto_enttec,
508 proto_reg_handoff_enttec);
509 prefs_register_uint_preference(enttec_module, "udp_port",
510 "ENTTEC UDP Port",
511 "The UDP port on which ENTTEC packets will be sent",
512 10,&global_udp_port_enttec);
514 prefs_register_uint_preference(enttec_module, "tcp_port",
515 "ENTTEC TCP Port",
516 "The TCP port on which ENTTEC packets will be sent",
517 10,&global_tcp_port_enttec);
519 prefs_register_enum_preference(enttec_module, "dmx_disp_chan_val_type",
520 "DMX Display channel value type",
521 "The way DMX values are displayed",
522 &global_disp_chan_val_type,
523 disp_chan_val_types, FALSE);
525 prefs_register_enum_preference(enttec_module, "dmx_disp_chan_nr_type",
526 "DMX Display channel nr. type",
527 "The way DMX channel numbers are displayed",
528 &global_disp_chan_nr_type,
529 disp_chan_nr_types, FALSE);
531 prefs_register_enum_preference(enttec_module, "dmx_disp_col_count",
532 "DMX Display Column Count",
533 "The number of columns for the DMX display",
534 &global_disp_col_count,
535 col_count, FALSE);
538 /* The registration hand-off routing */
539 void
540 proto_reg_handoff_enttec(void) {
541 static gboolean enttec_initialized = FALSE;
542 static dissector_handle_t enttec_handle;
543 static guint udp_port_enttec;
544 static guint tcp_port_enttec;
546 if(!enttec_initialized) {
547 enttec_handle = new_create_dissector_handle(dissect_enttec,proto_enttec);
548 enttec_initialized = TRUE;
549 } else {
550 dissector_delete_uint("udp.port",udp_port_enttec,enttec_handle);
551 dissector_delete_uint("tcp.port",tcp_port_enttec,enttec_handle);
554 udp_port_enttec = global_udp_port_enttec;
555 tcp_port_enttec = global_tcp_port_enttec;
557 dissector_add_uint("udp.port",global_udp_port_enttec,enttec_handle);
558 dissector_add_uint("tcp.port",global_tcp_port_enttec,enttec_handle);