1 /* packet-pn-rtc-one.c
2 * Routines for PROFINET IO - RTC1 dissection.
3 *
4 * Wireshark - Network traffic analyzer
5 * By Gerald Combs <gerald@wireshark.org>
6 * Copyright 1999 Gerald Combs
7 *
8 * SPDX-License-Identifier: GPL-2.0-or-later
9 */
10
11 /*
12 * The PN-IO protocol is a field bus protocol related to decentralized
13 * periphery and is developed by the PROFIBUS Nutzerorganisation e.V. (PNO),
14 * see: www.profibus.com
15 *
16 *
17 * PN-IO is based on the common DCE-RPC and the "lightweight" PN-RT
18 * (ethernet type 0x8892) protocols.
19 *
20 * The context manager (CM) part is handling context information
21 * (like establishing, ...) and is using DCE-RPC as its underlying
22 * protocol.
23 *
24 * The actual cyclic data transfer and acyclic notification uses the
25 * "lightweight" PN-RT protocol.
26 *
27 * There are some other related PROFINET protocols (e.g. PN-DCP, which is
28 * handling addressing topics).
29 *
30 * Please note: the PROFINET CBA protocol is independent of the PN-IO protocol!
31 */
32
33 /*
34 * Cyclic PNIO RTC1 Data Dissection:
35 *
36 * To dissect cyclic PNIO RTC1 frames, this plug-in has to collect important module
37 * information out of "Ident OK", "Connect Request" and "Write Response"
38 * frames first.
39 *
40 * The data of Stationname-, -type and -id will be gained out of
41 * packet-pn-dcp.c. The header packet-pn.h will transfer those data between
42 * those two files.
43 *
44 * This file is used as a "addon" for packet-dcerpc-pn-io.c. Within "packet-dcerpc-pn-io.c"
45 * the defined structures in "packet-pn.h" will be filled with all necessary information.
46 * Those informations will be used in thise file to dissect cyclic PNIO RTC1 and PROFIsafe
47 * frames. Furthermore since RTC1 is a special frame type of PNIO, this dissection uses the
48 * already defined protocol PNIO.
49 *
50 * Overview for cyclic PNIO RTC1 data dissection functions:
51 * -> dissect_PNIO_C_SDU_RTC1 (general dissection of RTC1)
52 */
53
54 #include "config.h"
55
56 #include <stdio.h>
57 #include <string.h>
58 #include <glib.h>
59 #include <epan/packet.h>
60 #include <epan/dissectors/packet-dcerpc.h>
61 #include <epan/proto.h>
62 #include <epan/expert.h>
63
64 #include "packet-pn.h"
65
66
67 #define F_MESSAGE_TRAILER_4BYTE 4 /* PROFIsafe: Defines the Amount of Bytes for CRC and Status-/Controlbyte */
68 #define PN_INPUT_CR 1 /* PROFINET Input Connect Request value */
69 #define PN_INPUT_DATADESCRITPION 1 /* PROFINET Input Data Description value */
70
71
72 static int proto_pn_io_rtc1 = -1;
73
74 /* General module information */
75 static int hf_pn_io_frame_info_type = -1;
76 static int hf_pn_io_frame_info_vendor = -1;
77 static int hf_pn_io_frame_info_nameofstation = -1;
78 static int hf_pn_io_frame_info_gsd_found = -1;
79 static int hf_pn_io_frame_info_gsd_error = -1;
80 static int hf_pn_io_frame_info_gsd_path = -1;
81 static int hf_pn_io_io_data_object = -1;
82 static int hf_pn_io_io_data_object_info_module_diff = -1;
83 static int hf_pn_io_io_data_object_info_moduleidentnumber = -1;
84 static int hf_pn_io_io_data_object_info_submoduleidentnumber = -1;
85
86 static int hf_pn_io_iocs = -1;
87 static int hf_pn_io_iops = -1;
88 static int hf_pn_io_ioxs_extension = -1;
89 static int hf_pn_io_ioxs_res14 = -1;
90 static int hf_pn_io_ioxs_instance = -1;
91 static int hf_pn_io_ioxs_datastate = -1;
92
93 /* PROFIsafe statusbyte and controlbyte */
94 static int hf_pn_io_ps_sb = -1;
95 static int hf_pn_io_ps_sb_iparOK = -1;
96 static int hf_pn_io_ps_sb_DeviceFault = -1;
97 static int hf_pn_io_ps_sb_CECRC = -1;
98 static int hf_pn_io_ps_sb_WDtimeout = -1;
99 static int hf_pn_io_ps_sb_FVactivated = -1;
100 static int hf_pn_io_ps_sb_Toggle_d = -1;
101 static int hf_pn_io_ps_sb_ConsNr_reset = -1;
102 static int hf_pn_io_ps_sb_res = -1;
103 static int hf_pn_io_ps_sb_toggelBitChanged = -1;
104 static int hf_pn_io_ps_sb_toggelBitChange_slot_nr = -1;
105 static int hf_pn_io_ps_sb_toggelBitChange_subslot_nr = -1;
106
107 static int hf_pn_io_ps_cb = -1;
108 static int hf_pn_io_ps_cb_iparEN = -1;
109 static int hf_pn_io_ps_cb_OAReq = -1;
110 static int hf_pn_io_ps_cb_resetConsNr = -1;
111 static int hf_pn_io_ps_cb_useTO2 = -1;
112 static int hf_pn_io_ps_cb_activateFV = -1;
113 static int hf_pn_io_ps_cb_Toggle_h = -1;
114 static int hf_pn_io_ps_cb_Chf_ACK = -1;
115 static int hf_pn_io_ps_cb_loopcheck = -1;
116 static int hf_pn_io_ps_cb_toggelBitChanged = -1;
117 static int hf_pn_io_ps_cb_toggelBitChange_slot_nr = -1;
118 static int hf_pn_io_ps_cb_toggelBitChange_subslot_nr = -1;
119
120 /* PROFIsafe */
121 static int hf_pn_io_ps_f_dest_adr = -1;
122 static int hf_pn_io_ps_f_data = -1;
123
124 static gint ett_pn_io_rtc = -1;
125 static gint ett_pn_io_ioxs = -1;
126 static gint ett_pn_io_io_data_object = -1;
127
128 static expert_field ei_pn_io_too_many_data_objects = EI_INIT;
129
130 static const value_string pn_io_ioxs_extension[] = {
131 { 0x00 /* 0*/, "No IOxS octet follows" },
132 { 0x01 /* 1*/, "One more IOxS octet follows" },
133 { 0, NULL }
134 };
135
136 static const value_string pn_io_ioxs_instance[] = {
137 { 0x00 /* 0*/, "Detected by subslot" },
138 { 0x01 /* 1*/, "Detected by slot" },
139 { 0x02 /* 2*/, "Detected by IO device" },
140 { 0x03 /* 3*/, "Detected by IO controller" },
141 { 0, NULL }
142 };
143
144 static const value_string pn_io_ioxs_datastate[] = {
145 { 0x00 /* 0*/, "Bad" },
146 { 0x01 /* 1*/, "Good" },
147 { 0, NULL }
148 };
149
150
151 static int * const ps_sb_fields[] = {
152 &hf_pn_io_ps_sb_res,
153 &hf_pn_io_ps_sb_ConsNr_reset,
154 &hf_pn_io_ps_sb_Toggle_d,
155 &hf_pn_io_ps_sb_FVactivated,
156 &hf_pn_io_ps_sb_WDtimeout,
157 &hf_pn_io_ps_sb_CECRC,
158 &hf_pn_io_ps_sb_DeviceFault,
159 &hf_pn_io_ps_sb_iparOK,
160 NULL
161 };
162
163 static int * const ps_cb_fields[] = {
164 &hf_pn_io_ps_cb_loopcheck,
165 &hf_pn_io_ps_cb_Chf_ACK,
166 &hf_pn_io_ps_cb_Toggle_h,
167 &hf_pn_io_ps_cb_activateFV,
168 &hf_pn_io_ps_cb_useTO2,
169 &hf_pn_io_ps_cb_resetConsNr,
170 &hf_pn_io_ps_cb_OAReq,
171 &hf_pn_io_ps_cb_iparEN,
172 NULL
173 };
174
175 static int * const ioxs_fields[] = {
176 &hf_pn_io_ioxs_datastate,
177 &hf_pn_io_ioxs_instance,
178 &hf_pn_io_ioxs_res14,
179 &hf_pn_io_ioxs_extension,
180 NULL
181 };
182
183
184 /* Dissector for PROFIsafe Status Byte */
185 static int
dissect_pn_io_ps_SB(tvbuff_t * tvb,int offset,packet_info * pinfo _U_,proto_tree * tree,guint8 * drep _U_,int hfindex,int * const * fields)186 dissect_pn_io_ps_SB(tvbuff_t *tvb, int offset,
187 packet_info *pinfo _U_, proto_tree *tree, guint8 *drep _U_, int hfindex, int * const *fields)
188 {
189
190 if (tree) {
191 guint8 u8StatusByte;
192 proto_item *sb_item;
193
194 u8StatusByte = tvb_get_guint8(tvb, offset);
195
196 /* Add Status Byte subtree */
197 sb_item = proto_tree_add_bitmask_with_flags(tree, tvb, offset, hfindex, ett_pn_io_ioxs, fields,
198 ENC_LITTLE_ENDIAN, BMT_NO_APPEND);
199 proto_item_append_text(sb_item, " (%s)", ((u8StatusByte == 0x20) || (u8StatusByte == 0x00)) ? "normal" : "unnormal");
200 }
201
202 return offset + 1;
203 }
204
205
206 /* Dissector for PROFIsafe Control Byte */
207 static int
dissect_pn_io_ps_CB(tvbuff_t * tvb,int offset,packet_info * pinfo _U_,proto_tree * tree,guint8 * drep _U_,int hfindex,int * const * fields)208 dissect_pn_io_ps_CB(tvbuff_t *tvb, int offset,
209 packet_info *pinfo _U_, proto_tree *tree, guint8 *drep _U_, int hfindex, int * const *fields)
210 {
211
212 if (tree) {
213 guint8 u8ControlByte;
214 proto_item *cb_item;
215
216 u8ControlByte = tvb_get_guint8(tvb, offset);
217
218 /* Add Status Byte subtree */
219 cb_item = proto_tree_add_bitmask_with_flags(tree, tvb, offset, hfindex, ett_pn_io_ioxs, fields,
220 ENC_LITTLE_ENDIAN, BMT_NO_APPEND);
221 proto_item_append_text(cb_item, " (%s)", ((u8ControlByte == 0x20) || (u8ControlByte == 0x00) ||
222 (u8ControlByte == 0xa0) || (u8ControlByte == 0x80)) ? "normal" : "unnormal");
223 }
224
225 return offset + 1;
226 }
227
228
229 /* Dissector for IOCS (As each IOCS stands for a specific Slot & Subslot) */
230 static int
dissect_PNIO_IOCS(tvbuff_t * tvb,int offset,packet_info * pinfo _U_,proto_tree * tree,guint8 * drep _U_,int hfindex,guint16 slotNr,guint16 subSlotNr,int * const * fields)231 dissect_PNIO_IOCS(tvbuff_t *tvb, int offset, packet_info *pinfo _U_, proto_tree *tree,
232 guint8 *drep _U_, int hfindex, guint16 slotNr, guint16 subSlotNr, int * const *fields)
233 {
234
235 if (tree) {
236 guint8 u8IOxS;
237 proto_item *ioxs_item;
238
239 u8IOxS = tvb_get_guint8(tvb, offset);
240
241 /* Add ioxs subtree */
242 ioxs_item = proto_tree_add_bitmask_with_flags(tree, tvb, offset, hfindex,
243 ett_pn_io_ioxs, fields, ENC_LITTLE_ENDIAN, BMT_NO_APPEND);
244 proto_item_append_text(ioxs_item,
245 " (%s%s), Slot: 0x%x, Subslot: 0x%x",
246 (u8IOxS & 0x01) ? "another IOxS follows " : "",
247 (u8IOxS & 0x80) ? "good" : "bad",
248 slotNr,
249 subSlotNr);
250 }
251
252 return offset + 1;
253 }
254
255
256 /* dissect the IOxS (IOCS, IOPS) field */
257 static int
dissect_PNIO_IOxS(tvbuff_t * tvb,int offset,packet_info * pinfo _U_,proto_tree * tree,guint8 * drep _U_,int hfindex,int * const * fields)258 dissect_PNIO_IOxS(tvbuff_t *tvb, int offset,
259 packet_info *pinfo _U_, proto_tree *tree, guint8 *drep _U_, int hfindex, int * const *fields)
260 {
261
262 if (tree) {
263 guint8 u8IOxS;
264 proto_item *ioxs_item;
265
266 u8IOxS = tvb_get_guint8(tvb, offset);
267
268 /* Add ioxs subtree */
269 ioxs_item = proto_tree_add_bitmask_with_flags(tree, tvb, offset, hfindex,
270 ett_pn_io_ioxs, fields, ENC_LITTLE_ENDIAN, BMT_NO_APPEND);
271 proto_item_append_text(ioxs_item,
272 " (%s%s)",
273 (u8IOxS & 0x01) ? "another IOxS follows " : "",
274 (u8IOxS & 0x80) ? "good" : "bad");
275 }
276
277 return offset + 1;
278 }
279
280
281 /* Universel dissector for flexibel PROFIsafe Data 8 to 64 Bits */
282 static int
dissect_pn_io_ps_uint(tvbuff_t * tvb,gint offset,packet_info * pinfo _U_,proto_tree * tree,guint8 * drep,int hfindex,guint8 bytelength,guint64 * pdata)283 dissect_pn_io_ps_uint(tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
284 proto_tree *tree, guint8 *drep,
285 int hfindex, guint8 bytelength, guint64 *pdata)
286 {
287 guint64 data;
288 gboolean generalDissection;
289
290 generalDissection = FALSE;
291
292 switch (bytelength) {
293 case 1: /* 8 Bit Safety IO Data */
294 data = tvb_get_guint8(tvb, offset);
295 if (pdata)
296 *pdata = data;
297 break;
298
299 case 2: /* 16 Bit Safety IO Data */
300 data = tvb_get_letohs(tvb, offset);
301 if (pdata)
302 *pdata = data;
303 break;
304
305 case 3: /* 24 Bit Safety IO Data */
306 data = tvb_get_letoh24(tvb, offset);
307 if (pdata)
308 *pdata = data;
309 break;
310
311 case 4: /* 32 Bit Safety IO Data */
312 data = tvb_get_letohl(tvb, offset);
313 if (pdata)
314 *pdata = data;
315 break;
316
317 case 5: /* 40 Bit Safety IO Data */
318 data = tvb_get_letoh40(tvb, offset);
319 if (pdata)
320 *pdata = data;
321 break;
322
323 case 6: /* 48 Bit Safety IO Data */
324 data = tvb_get_letoh48(tvb, offset);
325 if (pdata)
326 *pdata = data;
327 break;
328
329 case 7: /* 56 Bit Safety IO Data */
330 data = tvb_get_letoh56(tvb, offset);
331 if (pdata)
332 *pdata = data;
333 break;
334
335 case 8: /* 64 Bit Safety IO Data */
336 data = tvb_get_letoh64(tvb, offset);
337 if (pdata)
338 *pdata = data;
339 break;
340
341 default: /* Safety IO Data is too big to save it into one variable */
342 dissect_pn_user_data(tvb, offset, pinfo, tree, bytelength, "Safety IO Data");
343 generalDissection = TRUE;
344 break;
345 }
346
347 if (tree && generalDissection == FALSE) {
348 proto_tree_add_item(tree, hfindex, tvb, offset, bytelength, DREP_ENC_INTEGER(drep));
349 }
350
351 return offset + bytelength;
352 }
353
354
355 /* dissect a PN-IO RTC1 Cyclic Service Data Unit */
356 int
dissect_PNIO_C_SDU_RTC1(tvbuff_t * tvb,int offset,packet_info * pinfo,proto_tree * tree,guint8 * drep _U_,guint16 frameid)357 dissect_PNIO_C_SDU_RTC1(tvbuff_t *tvb, int offset,
358 packet_info *pinfo, proto_tree *tree, guint8 *drep _U_, guint16 frameid)
359 {
360 proto_tree *data_tree = NULL;
361
362 /* Count & offset for comparation of the arrays */
363 guint16 frameOffset;
364 guint32 objectCounter;
365 gboolean inputFlag;
366 gboolean outputFlag;
367 gboolean psInfoText; /* Used to display only once per frame the info text "PROFIsafe Device" */
368
369 proto_item *data_item;
370 proto_item *IODataObject_item;
371 proto_item *IODataObject_item_info;
372 proto_tree *IODataObject_tree;
373 proto_item *ModuleID_item;
374 proto_item *ModuleDiff_item;
375
376 wmem_strbuf_t *moduleName;
377
378 guint8 toggleBitSb;
379 guint8 toggleBitCb;
380 guint64 f_data;
381
382 guint8 statusbyte;
383 guint8 controlbyte;
384
385 guint16 number_io_data_objects_input_cr;
386 guint16 number_iocs_input_cr;
387 guint16 number_io_data_objects_output_cr;
388 guint16 number_iocs_output_cr;
389
390 conversation_t *conversation;
391 stationInfo *station_info = NULL;
392 iocsObject *iocs_object;
393 ioDataObject *io_data_object;
394 moduleDiffInfo *module_diff_info;
395 wmem_list_frame_t *frame;
396 wmem_list_frame_t *frame_diff;
397
398 /* Initial */
399 frameOffset = 0;
400 f_data = 0;
401 inputFlag = FALSE;
402 outputFlag = FALSE;
403 psInfoText = FALSE;
404 number_io_data_objects_input_cr = 0;
405 number_iocs_input_cr = 0;
406 number_io_data_objects_output_cr = 0;
407 number_iocs_output_cr = 0;
408
409 wmem_list_frame_t *aruuid_frame;
410 ARUUIDFrame *current_aruuid_frame = NULL;
411 guint32 current_aruuid = 0;
412
413 col_set_str(pinfo->cinfo, COL_PROTOCOL, "PNIO"); /* set protocol name */
414
415 data_item = proto_tree_add_protocol_format(tree, proto_pn_io_rtc1, tvb, offset, tvb_captured_length(tvb),
416 "PROFINET IO Cyclic Service Data Unit: %u bytes", tvb_captured_length(tvb));
417 data_tree = proto_item_add_subtree(data_item, ett_pn_io_rtc);
418
419 /* dissect_dcerpc_uint16(tvb, offset, pinfo, data_tree, drep, hf_pn_io_packedframe_SFCRC, &u16SFCRC); */
420 if (!(dissect_CSF_SDU_heur(tvb, pinfo, data_tree, NULL) == FALSE))
421 return(tvb_captured_length(tvb));
422
423 /* Only dissect cyclic RTC1 frames, if PN Connect Request has been read */
424 conversation = find_conversation(pinfo->num, &pinfo->dl_src, &pinfo->dl_dst, ENDPOINT_NONE, 0, 0, 0);
425
426 /* Detect input data package and output data package */
427 if (conversation != NULL) {
428 if (aruuid_frame_setup_list != NULL) {
429 for (aruuid_frame = wmem_list_tail(aruuid_frame_setup_list); aruuid_frame != NULL; aruuid_frame = wmem_list_frame_prev(aruuid_frame)) {
430 current_aruuid_frame = (ARUUIDFrame*)wmem_list_frame_data(aruuid_frame);
431 /* There are prerequisites to dissect RTC frame data */
432 /* Current station info must be found before RTC frame dissection starts */
433 /* if RTC frame has setup frame and setup frame number is less than RTC frame number AND if RTC frame has release frame and release frame number is greater than RTC frame number */
434 /* if RTC frame has setup frame and setup frame number is less than RTC frame number AND RTC frame does not have release frame yet! */
435 /* then, get AR UUID of current station info */
436 if ((current_aruuid_frame->setupframe && current_aruuid_frame->setupframe < pinfo->num) &&
437 ((current_aruuid_frame->releaseframe && current_aruuid_frame->releaseframe > pinfo->num) ||
438 !current_aruuid_frame->releaseframe)) {
439 if (current_aruuid_frame->inputframe == frameid) {
440 current_aruuid = current_aruuid_frame->aruuid.data1;
441 break;
442 }
443 else if (current_aruuid_frame->outputframe == frameid) {
444 current_aruuid = current_aruuid_frame->aruuid.data1;
445 break;
446 }
447 }
448 }
449 }
450
451 station_info = (stationInfo*)conversation_get_proto_data(conversation, current_aruuid);
452
453 if (station_info != NULL) {
454 pn_find_dcp_station_info(station_info, conversation);
455
456 if (pnio_ps_selection == TRUE) {
457 col_set_str(pinfo->cinfo, COL_PROTOCOL, "PNIO_PS"); /* set PROFISsafe protocol name */
458 }
459
460 if (addresses_equal(&(pinfo->src), conversation_key_addr1(conversation->key_ptr)) && addresses_equal(&(pinfo->dst), conversation_key_addr2(conversation->key_ptr))) {
461 inputFlag = TRUE;
462 outputFlag = FALSE;
463 number_io_data_objects_input_cr = station_info->ioDataObjectNr;
464 number_iocs_input_cr = station_info->iocsNr;
465 }
466
467 if (addresses_equal(&(pinfo->dst), conversation_key_addr1(conversation->key_ptr)) && addresses_equal(&(pinfo->src), conversation_key_addr2(conversation->key_ptr))) {
468 outputFlag = TRUE;
469 inputFlag = FALSE;
470 number_io_data_objects_output_cr = station_info->ioDataObjectNr;
471 number_iocs_output_cr = station_info->iocsNr;
472 }
473 }
474 }
475
476 /* ------- Input (PNIO) / Response (PNIO_PS) Frame Handling ------- */
477 if (inputFlag) {
478 if (pnio_ps_selection == TRUE) {
479 proto_tree_add_string_format_value(data_tree, hf_pn_io_frame_info_type, tvb,
480 offset, 0, "Response", "Response Frame (IO_Device -> IO_Controller)");
481 }
482 else {
483 proto_tree_add_string_format_value(data_tree, hf_pn_io_frame_info_type, tvb,
484 offset, 0, "Input", "Input Frame (IO_Device -> IO_Controller)");
485 }
486
487 if (station_info != NULL) {
488 if (station_info->typeofstation != NULL) {
489 proto_tree_add_string_format_value(data_tree, hf_pn_io_frame_info_vendor, tvb, 0,
490 0, station_info->typeofstation, "\"%s\"", station_info->typeofstation);
491 }
492 if (station_info->nameofstation != NULL) {
493 proto_tree_add_string_format_value(data_tree, hf_pn_io_frame_info_nameofstation, tvb, 0,
494 0, station_info->nameofstation, "\"%s\"", station_info->nameofstation);
495 }
496
497 if (station_info->gsdPathLength == TRUE) { /* given path isn't too long for the array */
498 if (station_info->gsdFound == TRUE) { /* found a GSD-file */
499 if (station_info->gsdLocation != NULL) {
500 IODataObject_item_info = proto_tree_add_item(data_tree, hf_pn_io_frame_info_gsd_found, tvb, offset, 0, ENC_NA);
501 proto_item_append_text(IODataObject_item_info, ": \"%s\"", station_info->gsdLocation);
502 }
503 }
504 else {
505 if (station_info->gsdLocation != NULL) {
506 IODataObject_item_info = proto_tree_add_item(data_tree, hf_pn_io_frame_info_gsd_error, tvb, offset, 0, ENC_NA);
507 proto_item_append_text(IODataObject_item_info, " Please place relevant GSD-file under \"%s\"", station_info->gsdLocation);
508 }
509 }
510 }
511 else {
512 IODataObject_item_info = proto_tree_add_item(data_tree, hf_pn_io_frame_info_gsd_path, tvb, offset, 0, ENC_NA);
513 proto_item_append_text(IODataObject_item_info, " Please check your GSD-file networkpath. (No Path configured)");
514 }
515 }
516
517 /* ---- Input IOData-/IOCS-Object Handling ---- */
518 objectCounter = number_io_data_objects_input_cr + number_iocs_input_cr;
519 if (objectCounter > (guint)tvb_reported_length_remaining(tvb, offset)) {
520 expert_add_info_format(pinfo, data_item, &ei_pn_io_too_many_data_objects, "Too many data objects: %d", objectCounter);
521 return(tvb_captured_length(tvb));
522 }
523
524 while (objectCounter--) {
525 /* ---- Input IO Data Object Handling ---- */
526 if (station_info != NULL) {
527 for (frame = wmem_list_head(station_info->ioobject_data_in); frame != NULL; frame = wmem_list_frame_next(frame)) {
528 io_data_object = (ioDataObject*)wmem_list_frame_data(frame);
529 if (io_data_object->frameOffset == frameOffset) {
530 /* Found following object */
531
532 IODataObject_item = proto_tree_add_item(data_tree, hf_pn_io_io_data_object, tvb, offset, 0, ENC_NA);
533 IODataObject_tree = proto_item_add_subtree(IODataObject_item, ett_pn_io_io_data_object);
534
535 /* Control: the Device still uses the correct ModuleIdentNumber? */
536 for (frame_diff = wmem_list_head(station_info->diff_module); frame_diff != NULL; frame_diff = wmem_list_frame_next(frame_diff)) {
537 module_diff_info = (moduleDiffInfo*)wmem_list_frame_data(frame_diff);
538 if (io_data_object->moduleIdentNr != module_diff_info->modulID) {
539 ModuleDiff_item = proto_tree_add_item(IODataObject_tree, hf_pn_io_io_data_object_info_module_diff, tvb, 0, 0, ENC_NA);
540 proto_item_append_text(ModuleDiff_item, ": Device using ModuleIdentNumber 0x%08x instead of 0x%08x", module_diff_info->modulID, io_data_object->moduleIdentNr);
541 break;
542 }
543 }
544
545 proto_tree_add_uint(IODataObject_tree, hf_pn_io_io_data_object_info_moduleidentnumber, tvb, 0, 0, io_data_object->moduleIdentNr);
546 proto_tree_add_uint(IODataObject_tree, hf_pn_io_io_data_object_info_submoduleidentnumber, tvb, 0, 0, io_data_object->subModuleIdentNr);
547
548 /* PROFIsafe Supported Inputmodule handling */
549 if (io_data_object->profisafeSupported == TRUE && pnio_ps_selection == TRUE) {
550 if (io_data_object->profisafeSupported == TRUE && psInfoText == FALSE) {
551 /* Only add one information string per device to the infotext */
552 col_append_str(pinfo->cinfo, COL_INFO, ", PROFIsafe Device"); /* Add string to wireshark infotext */
553 psInfoText = TRUE;
554 }
555
556 proto_tree_add_uint(IODataObject_tree, hf_pn_io_ps_f_dest_adr, tvb, 0, 0, io_data_object->f_dest_adr);
557
558 /* Get Safety IO Data */
559 if ((io_data_object->length - F_MESSAGE_TRAILER_4BYTE) > 0) {
560 offset = dissect_pn_io_ps_uint(tvb, offset, pinfo, IODataObject_tree, drep, hf_pn_io_ps_f_data,
561 (io_data_object->length - F_MESSAGE_TRAILER_4BYTE), &f_data);
562 }
563
564 /* ---- Check for new PNIO data using togglebit ---- */
565 statusbyte = tvb_get_guint8(tvb, offset);
566 toggleBitSb = statusbyte & 0x20; /* get ToggleBit of StatusByte */
567
568 if (io_data_object->lastToggleBit != toggleBitSb) { /* ToggleBit has changed --> new Data incoming */
569 /* Special Filter for ToggleBit within Statusbyte */
570 ModuleID_item = proto_tree_add_uint(IODataObject_tree, hf_pn_io_ps_sb_toggelBitChanged, tvb, offset, 0, toggleBitSb);
571 proto_item_set_hidden(ModuleID_item);
572
573 ModuleID_item = proto_tree_add_uint(IODataObject_tree, hf_pn_io_ps_sb_toggelBitChange_slot_nr, tvb, offset, 0, io_data_object->slotNr);
574 proto_item_set_hidden(ModuleID_item);
575
576 ModuleID_item = proto_tree_add_uint(IODataObject_tree, hf_pn_io_ps_sb_toggelBitChange_subslot_nr, tvb, offset, 0, io_data_object->subSlotNr);
577 proto_item_set_hidden(ModuleID_item);
578 }
579
580 offset = dissect_pn_io_ps_SB(tvb, offset, pinfo, IODataObject_tree, drep, hf_pn_io_ps_sb, ps_sb_fields);
581 offset = dissect_pn_user_data(tvb, offset, pinfo, IODataObject_tree, io_data_object->f_crc_len, "CRC");
582
583 io_data_object->last_sb_cb = statusbyte; /* save the value of current statusbyte */
584 io_data_object->lastToggleBit = toggleBitSb; /* save the value of current togglebit within statusbyte */
585 } /* END of PROFIsafe Module Handling */
586
587 else {
588 /* Module is not PROFIsafe supported */
589 offset = dissect_pn_user_data(tvb, offset, pinfo, IODataObject_tree, io_data_object->length, "IO Data");
590 }
591
592 if (io_data_object->discardIOXS == FALSE) {
593 offset = dissect_PNIO_IOxS(tvb, offset, pinfo, IODataObject_tree, drep, hf_pn_io_iops, ioxs_fields);
594 proto_item_set_len(IODataObject_item, io_data_object->length + 1); /* Length = Databytes + IOXS Byte */
595 }
596 else {
597 proto_item_set_len(IODataObject_item, io_data_object->length); /* Length = Databytes */
598 }
599
600 proto_item_append_text(IODataObject_item, ": Slot: 0x%x Subslot: 0x%x",
601 io_data_object->slotNr, io_data_object->subSlotNr);
602
603
604 /* ModuleIdentNr appears not only once in GSD-file -> set module name more generally */
605 if (io_data_object->amountInGSDML > 1) { /* if ModuleIdentNr only appears once in GSD-file, use the found GSD-file-ModuleName, else ... */
606 if (io_data_object->slotNr == 0) {
607 moduleName = wmem_strbuf_new(pinfo->pool, "Headstation");
608 }
609 else {
610 moduleName = wmem_strbuf_new(pinfo->pool, "Module");
611 }
612
613 if (io_data_object->profisafeSupported == TRUE) {
614 /* PROFIsafe */
615 if (io_data_object->length >= 5) { /* 5 due to 3 CRC bytes & 1 status byte & (at least) 1 data byte */
616 wmem_strbuf_append(moduleName, ", DI");
617 }
618 else {
619 wmem_strbuf_append(moduleName, ", DO");
620 }
621 }
622 else {
623 /* PROFINET */
624 if (io_data_object->length > 0) {
625 wmem_strbuf_append(moduleName, ", DI");
626 }
627 else {
628 wmem_strbuf_append(moduleName, ", DO");
629 }
630 }
631
632 io_data_object->moduleNameStr = wmem_strdup(wmem_file_scope(), wmem_strbuf_get_str(moduleName));
633 }
634
635 proto_item_append_text(IODataObject_item, " ModuleName: \"%s\"", io_data_object->moduleNameStr);
636
637 /* emphasize the PROFIsafe supported Modul */
638 if (io_data_object->profisafeSupported == TRUE && pnio_ps_selection == TRUE) {
639 (proto_item_append_text(IODataObject_item, " (PROFIsafe Module)"));
640 }
641
642
643 /* Set frameOffset to its new value, to find the next object */
644 frameOffset = frameOffset + io_data_object->length; /* frameOffset = current value + data bytes */
645 if (io_data_object->discardIOXS == FALSE) {
646 frameOffset = frameOffset + 1; /* frameOffset = current value + iops byte */
647 }
648 }
649 }
650 }
651
652 /* ---- Input IOCS Object Handling ---- */
653 if (station_info != NULL) {
654 for (frame = wmem_list_head(station_info->iocs_data_in); frame != NULL; frame = wmem_list_frame_next(frame)) {
655 iocs_object = (iocsObject*)wmem_list_frame_data(frame);
656 if (iocs_object->frameOffset == frameOffset) {
657 offset = dissect_PNIO_IOCS(tvb, offset, pinfo, data_tree, drep, hf_pn_io_iocs, iocs_object->slotNr,
658 iocs_object->subSlotNr, ioxs_fields);
659
660 /* Set frameOffset to its new value, to find the next object */
661 frameOffset = frameOffset + 1; /* frameOffset = current value + iops byte */
662
663 break;
664 }
665 }
666 }
667 }
668
669 /* Dissect padding */
670 offset = dissect_pn_user_data(tvb, offset, pinfo, tree, tvb_captured_length_remaining(tvb, offset), "GAP and RTCPadding");
671 } /* END of Input Frame Handling */
672
673 /* ----- Output (PNIO) / Request (PNIO_PS) Frame Handling ------ */
674 else if (outputFlag) {
675 if (pnio_ps_selection == TRUE) {
676 proto_tree_add_string_format_value(data_tree, hf_pn_io_frame_info_type, tvb,
677 offset, 0, "Request", "Request Frame (IO_Controller -> IO_Device)");
678 }
679 else {
680 proto_tree_add_string_format_value(data_tree, hf_pn_io_frame_info_type, tvb,
681 offset, 0, "Output", "Output Frame (IO_Controller -> IO_Device)");
682 }
683
684 if (station_info != NULL) {
685 if (station_info->typeofstation != NULL) {
686 proto_tree_add_string_format_value(data_tree, hf_pn_io_frame_info_vendor, tvb, 0,
687 0, station_info->typeofstation, "\"%s\"", station_info->typeofstation);
688 }
689 if (station_info->nameofstation != NULL) {
690 proto_tree_add_string_format_value(data_tree, hf_pn_io_frame_info_nameofstation, tvb, 0,
691 0, station_info->nameofstation, "\"%s\"", station_info->nameofstation);
692 }
693
694 if (station_info->gsdPathLength == TRUE) { /* given path isn't too long for the array */
695 if (station_info->gsdFound == TRUE) { /* found a GSD-file */
696 if (station_info->gsdLocation != NULL) {
697 IODataObject_item_info = proto_tree_add_item(data_tree, hf_pn_io_frame_info_gsd_found, tvb, offset, 0, ENC_NA);
698 proto_item_append_text(IODataObject_item_info, ": \"%s\"", station_info->gsdLocation);
699 }
700 }
701 else {
702 if (station_info->gsdLocation != NULL) {
703 IODataObject_item_info = proto_tree_add_item(data_tree, hf_pn_io_frame_info_gsd_error, tvb, offset, 0, ENC_NA);
704 proto_item_append_text(IODataObject_item_info, " Please place relevant GSD-file under \"%s\"", station_info->gsdLocation);
705 }
706 }
707 }
708 else {
709 IODataObject_item_info = proto_tree_add_item(data_tree, hf_pn_io_frame_info_gsd_path, tvb, offset, 0, ENC_NA);
710 proto_item_append_text(IODataObject_item_info, " Please check your GSD-file networkpath. (No Path configured)");
711 }
712 }
713
714 /* ---- Output IOData-/IOCS-Object Handling ---- */
715 objectCounter = number_io_data_objects_output_cr + number_iocs_output_cr;
716 if (objectCounter > (guint)tvb_reported_length_remaining(tvb, offset)) {
717 expert_add_info_format(pinfo, data_item, &ei_pn_io_too_many_data_objects, "Too many data objects: %d", objectCounter);
718 return(tvb_captured_length(tvb));
719 }
720 while (objectCounter--) {
721 /* ---- Output IO Data Object Handling ---- */
722 if (station_info != NULL) {
723 for (frame = wmem_list_head(station_info->ioobject_data_out); frame != NULL; frame = wmem_list_frame_next(frame)) {
724 io_data_object = (ioDataObject*)wmem_list_frame_data(frame);
725 if (io_data_object != NULL && io_data_object->frameOffset == frameOffset) {
726 /* Found following object */
727
728 IODataObject_item = proto_tree_add_item(data_tree, hf_pn_io_io_data_object, tvb, offset, 0, ENC_NA);
729 IODataObject_tree = proto_item_add_subtree(IODataObject_item, ett_pn_io_io_data_object);
730
731 /* Control: the Device still uses the correct ModuleIdentNumber? */
732 for (frame_diff = wmem_list_head(station_info->diff_module); frame_diff != NULL; frame_diff = wmem_list_frame_next(frame_diff)) {
733 module_diff_info = (moduleDiffInfo*)wmem_list_frame_data(frame_diff);
734 if (io_data_object->moduleIdentNr != module_diff_info->modulID) {
735 ModuleDiff_item = proto_tree_add_item(IODataObject_tree, hf_pn_io_io_data_object_info_module_diff, tvb, 0, 0, ENC_NA);
736 proto_item_append_text(ModuleDiff_item, ": Device using ModuleIdentNumber 0x%08x instead of 0x%08x", module_diff_info->modulID, io_data_object->moduleIdentNr);
737 break;
738 }
739 }
740
741 proto_tree_add_uint(IODataObject_tree, hf_pn_io_io_data_object_info_moduleidentnumber, tvb, 0, 0, io_data_object->moduleIdentNr);
742 proto_tree_add_uint(IODataObject_tree, hf_pn_io_io_data_object_info_submoduleidentnumber, tvb, 0, 0, io_data_object->subModuleIdentNr);
743
744 if (io_data_object->profisafeSupported == TRUE && pnio_ps_selection == TRUE) {
745 if (io_data_object->profisafeSupported == TRUE && psInfoText == FALSE) {
746 /* Only add one information string per device to the infotext */
747 col_append_str(pinfo->cinfo, COL_INFO, ", PROFIsafe Device"); /* Add string to wireshark infotext */
748 psInfoText = TRUE;
749 }
750
751 proto_tree_add_uint(IODataObject_tree, hf_pn_io_ps_f_dest_adr, tvb, 0, 0, io_data_object->f_dest_adr);
752
753 /* Get Safety IO Data */
754 if ((io_data_object->length - F_MESSAGE_TRAILER_4BYTE) > 0) {
755 offset = dissect_pn_io_ps_uint(tvb, offset, pinfo, IODataObject_tree, drep, hf_pn_io_ps_f_data,
756 (io_data_object->length - F_MESSAGE_TRAILER_4BYTE), &f_data);
757 }
758
759 /* ---- Check for new PNIO data using togglebit ---- */
760 controlbyte = tvb_get_guint8(tvb, offset);
761 toggleBitCb = controlbyte & 0x20; /* get ToggleBit of Controlbyte */
762
763 if (io_data_object->lastToggleBit != toggleBitCb) { /* ToggleBit has changed --> new Data incoming */
764 /* Special Filter for ToggleBit within Controlbyte */
765 ModuleID_item = proto_tree_add_uint(IODataObject_tree, hf_pn_io_ps_cb_toggelBitChanged, tvb, offset, 0, toggleBitCb);
766 proto_item_set_hidden(ModuleID_item);
767
768 ModuleID_item = proto_tree_add_uint(IODataObject_tree, hf_pn_io_ps_cb_toggelBitChange_slot_nr, tvb, offset, 0, io_data_object->slotNr);
769 proto_item_set_hidden(ModuleID_item);
770
771 ModuleID_item = proto_tree_add_uint(IODataObject_tree, hf_pn_io_ps_cb_toggelBitChange_subslot_nr, tvb, offset, 0, io_data_object->subSlotNr);
772 proto_item_set_hidden(ModuleID_item);
773 }
774
775 offset = dissect_pn_io_ps_CB(tvb, offset, pinfo, IODataObject_tree, drep, hf_pn_io_ps_cb, ps_cb_fields);
776 offset = dissect_pn_user_data(tvb, offset, pinfo, IODataObject_tree, io_data_object->f_crc_len, "CRC");
777
778 io_data_object->last_sb_cb = controlbyte; /* save the value of current controlbyte */
779 io_data_object->lastToggleBit = toggleBitCb; /* save the value of current togglebit within controlbyte */
780 } /* End of PROFIsafe Module Handling */
781 else {
782 /* Module is not PROFIsafe supported */
783 offset = dissect_pn_user_data(tvb, offset, pinfo, IODataObject_tree, io_data_object->length, "IO Data");
784 }
785
786 if (io_data_object->discardIOXS == FALSE) {
787 offset = dissect_PNIO_IOxS(tvb, offset, pinfo, IODataObject_tree, drep, hf_pn_io_iops, ioxs_fields);
788 proto_item_set_len(IODataObject_item, io_data_object->length + 1); /* Length = Databytes + IOXS Byte */
789 }
790 else {
791 proto_item_set_len(IODataObject_item, io_data_object->length); /* Length = Databytes */
792 }
793
794 proto_item_append_text(IODataObject_item, ": Slot: 0x%x Subslot: 0x%x",
795 io_data_object->slotNr, io_data_object->subSlotNr);
796
797
798 /* ModuleIdentNr appears not only once in GSD-file -> set module name more generally */
799 if (io_data_object->amountInGSDML > 1) { /* if ModuleIdentNr only appears once in GSD-file, use the found GSD-file-ModuleName, else ... */
800 if (io_data_object->slotNr == 0) {
801 moduleName = wmem_strbuf_new(pinfo->pool, "Headstation");
802 }
803 else {
804 moduleName = wmem_strbuf_new(pinfo->pool, "Module");
805 }
806
807 if (io_data_object->profisafeSupported == TRUE) {
808 /* PROFIsafe */
809 if (io_data_object->length >= 5) { /* 5 due to 3 CRC bytes & 1 status byte & (at least) 1 data byte */
810 wmem_strbuf_append(moduleName, ", DO");
811 }
812 else {
813 wmem_strbuf_append(moduleName, ", DI");
814 }
815 }
816 else {
817 /* PROFINET */
818 if (io_data_object->length > 0) {
819 wmem_strbuf_append(moduleName, ", DO");
820 }
821 else {
822 wmem_strbuf_append(moduleName, ", DI");
823 }
824 }
825
826 io_data_object->moduleNameStr = wmem_strdup(wmem_file_scope(), wmem_strbuf_get_str(moduleName));
827 }
828
829 proto_item_append_text(IODataObject_item, " ModuleName: \"%s\"", io_data_object->moduleNameStr);
830
831 /* emphasize the PROFIsafe supported Modul */
832 if (io_data_object->profisafeSupported == TRUE && pnio_ps_selection == TRUE) {
833 proto_item_append_text(IODataObject_item, " (PROFIsafe Module)");
834 }
835
836 /* Set frameOffset to its new value, to find the next object */
837 frameOffset = frameOffset + io_data_object->length; /* frameOffset = current value + data bytes */
838 if (io_data_object->discardIOXS == FALSE) {
839 frameOffset = frameOffset + 1; /* frameOffset = current value + iops byte */
840 }
841 }
842 }
843 }
844
845 /* ---- Output IOCS Object Handling ---- */
846 if (station_info != NULL) {
847 for (frame = wmem_list_head(station_info->iocs_data_out); frame != NULL; frame = wmem_list_frame_next(frame)) {
848 iocs_object = (iocsObject*)wmem_list_frame_data(frame);
849 if (iocs_object->frameOffset == frameOffset) {
850 offset = dissect_PNIO_IOCS(tvb, offset, pinfo, data_tree, drep, hf_pn_io_iocs, iocs_object->slotNr,
851 iocs_object->subSlotNr, ioxs_fields);
852
853 /* Set frameOffset to its new value, to find the next object */
854 frameOffset = frameOffset + 1; /* frameOffset = current value + iops byte */
855
856 break;
857 }
858 }
859 }
860 }
861
862 /* Dissect padding */
863 offset = dissect_pn_user_data(tvb, offset, pinfo, tree, tvb_captured_length_remaining(tvb, offset), "GAP and RTCPadding");
864 } /* END of Output Frame Handling */
865
866 return offset;
867 }
868
869
870 void
init_pn_io_rtc1(int proto)871 init_pn_io_rtc1(int proto)
872 {
873 static hf_register_info hf[] = {
874 { &hf_pn_io_io_data_object,
875 { "IODataObject", "pn_io.io_data_object",
876 FT_NONE, BASE_NONE, NULL, 0x0,
877 NULL, HFILL }
878 },
879 { &hf_pn_io_io_data_object_info_module_diff,
880 { "Difference", "pn_io.io_data_object.diff_module",
881 FT_NONE, BASE_NONE, NULL, 0x0,
882 NULL, HFILL }
883 },
884 { &hf_pn_io_io_data_object_info_moduleidentnumber,
885 { "ModuleIdentNumber", "pn_io.io_data_object.module_nr",
886 FT_UINT32, BASE_HEX, NULL, 0x0,
887 NULL, HFILL }
888 },
889 { &hf_pn_io_io_data_object_info_submoduleidentnumber,
890 { "SubmoduleIdentNumber", "pn_io.io_data_object.submodule_nr",
891 FT_UINT32, BASE_HEX, NULL, 0x0,
892 NULL, HFILL }
893 },
894 { &hf_pn_io_frame_info_type,
895 { "PN Frame Type", "pn_io.frame_info.type",
896 FT_STRING, BASE_NONE, NULL, 0x0,
897 NULL, HFILL }
898 },
899 { &hf_pn_io_frame_info_vendor,
900 { "DeviceVendorValue", "pn_io.frame_info.vendor",
901 FT_STRING, BASE_NONE, NULL, 0x0,
902 NULL, HFILL }
903 },
904 { &hf_pn_io_frame_info_nameofstation,
905 { "NameOfStation", "pn_io.frame_info.nameofstation",
906 FT_STRING, BASE_NONE, NULL, 0x0,
907 NULL, HFILL }
908 },
909 { &hf_pn_io_frame_info_gsd_found,
910 { "GSD-file found", "pn_io.frame_info.gsd_found",
911 FT_NONE, BASE_NONE, NULL, 0x0,
912 NULL, HFILL }
913 },
914 { &hf_pn_io_frame_info_gsd_error,
915 { "GSD-file not found.", "pn_io.frame_info.gsd_error",
916 FT_NONE, BASE_NONE, NULL, 0x0,
917 NULL, HFILL }
918 },
919 { &hf_pn_io_frame_info_gsd_path,
920 { "GSD-file networkpath failure!", "pn_io.frame_info.gsd_path",
921 FT_NONE, BASE_NONE, NULL, 0x0,
922 NULL, HFILL }
923 },
924 { &hf_pn_io_iocs,
925 { "IOCS", "pn_io.ioxs",
926 FT_UINT8, BASE_HEX, NULL, 0x0,
927 NULL, HFILL }
928 },
929 { &hf_pn_io_iops,
930 { "IOPS", "pn_io.ioxs",
931 FT_UINT8, BASE_HEX, NULL, 0x0,
932 NULL, HFILL }
933 },
934 { &hf_pn_io_ioxs_extension,
935 { "Extension", "pn_io.ioxs.extension",
936 FT_UINT8, BASE_HEX, VALS(pn_io_ioxs_extension), 0x01,
937 NULL, HFILL }
938 },
939 { &hf_pn_io_ioxs_res14,
940 { "Reserved", "pn_io.ioxs.res14",
941 FT_UINT8, BASE_HEX, NULL, 0x1E,
942 NULL, HFILL }
943 },
944 { &hf_pn_io_ioxs_instance,
945 { "Instance", "pn_io.ioxs.instance",
946 FT_UINT8, BASE_HEX, VALS(pn_io_ioxs_instance), 0x60,
947 NULL, HFILL }
948 },
949 { &hf_pn_io_ioxs_datastate,
950 { "DataState", "pn_io.ioxs.datastate",
951 FT_UINT8, BASE_HEX, VALS(pn_io_ioxs_datastate), 0x80,
952 NULL, HFILL }
953 },
954 /* PROFIsafe parameter */
955 /* Status Byte & Control Byte for PROFIsafe --- dissector handle */
956 { &hf_pn_io_ps_sb,
957 { "Status Byte", "pn_io.ps.sb",
958 FT_UINT8, BASE_HEX, NULL, 0x0,
959 NULL, HFILL }
960 },
961 { &hf_pn_io_ps_sb_toggelBitChanged,
962 { "Status Byte", "pn_io.ps.sb.toggle_d_changed",
963 FT_UINT8, BASE_DEC, NULL, 0x00,
964 NULL, HFILL }
965 },
966 { &hf_pn_io_ps_sb_toggelBitChange_slot_nr,
967 { "Slot_Number", "pn_io.ps.sb.toggle_d_changed.slot",
968 FT_UINT16, BASE_DEC, NULL, 0x0,
969 NULL, HFILL }
970 },
971 { &hf_pn_io_ps_sb_toggelBitChange_subslot_nr,
972 { "Sub_Slot_Number", "pn_io.ps.sb.toggle_d_changed.subslot",
973 FT_UINT16, BASE_DEC, NULL, 0x0,
974 NULL, HFILL }
975 },
976 { &hf_pn_io_ps_cb,
977 { "Control Byte", "pn_io.ps.cb",
978 FT_UINT8, BASE_HEX, NULL, 0x0,
979 NULL, HFILL }
980 },
981 { &hf_pn_io_ps_cb_toggelBitChanged,
982 { "Control Byte", "pn_io.ps.cb.toggle_h_changed",
983 FT_UINT8, BASE_DEC, NULL, 0x00,
984 NULL, HFILL }
985 },
986 { &hf_pn_io_ps_cb_toggelBitChange_slot_nr,
987 { "Slot_Number", "pn_io.ps.cb.toggle_h_changed.slot",
988 FT_UINT16, BASE_DEC, NULL, 0x0,
989 NULL, HFILL }
990 },
991 { &hf_pn_io_ps_cb_toggelBitChange_subslot_nr,
992 { "Sub_Slot_Number", "pn_io.ps.cb.toggle_h_changed.subslot",
993 FT_UINT16, BASE_DEC, NULL, 0x0,
994 NULL, HFILL }
995 },
996 /* Structures for dissecting Status Byte & Control Byte PROFIsafe ---dissector details */
997 { &hf_pn_io_ps_sb_iparOK,
998 { "iPar_OK - F-Device has new iParameter values assigned", "pn_io.ps.sb.iPar_OK",
999 FT_UINT8, BASE_HEX, NULL, 0x01,
1000 NULL, HFILL }
1001 },
1002 { &hf_pn_io_ps_sb_DeviceFault,
1003 { "Device_Fault - Failure exists in F-Device or F-Module", "pn_io.ps.sb.DeviceFault",
1004 FT_UINT8, BASE_HEX, NULL, 0x02,
1005 NULL, HFILL }
1006 },
1007 { &hf_pn_io_ps_sb_CECRC,
1008 { "CE_CRC - CRC Communication fault", "pn_io.ps.sb.CE_CRC",
1009 FT_UINT8, BASE_HEX, NULL, 0x04,
1010 NULL, HFILL }
1011 },
1012 { &hf_pn_io_ps_sb_WDtimeout,
1013 { "WD_timeout - WatchDog timeout Communication fault", "pn_io.ps.sb.WD_timeout",
1014 FT_UINT8, BASE_HEX, NULL, 0x08,
1015 NULL, HFILL }
1016 },
1017 { &hf_pn_io_ps_sb_FVactivated,
1018 { "FV_activated - Fail-safe values (FV) activated", "pn_io.ps.sb.FV_activated",
1019 FT_UINT8, BASE_HEX, NULL, 0x10,
1020 NULL, HFILL }
1021 },
1022 { &hf_pn_io_ps_sb_Toggle_d,
1023 { "Toggle_d - Device-based Toggle Bit", "pn_io.ps.sb.Toggle_d",
1024 FT_UINT8, BASE_HEX, NULL, 0x20,
1025 NULL, HFILL }
1026 },
1027 { &hf_pn_io_ps_sb_ConsNr_reset,
1028 { "cons_nr_R - F-Device has reset its consecutive number counter", "pn_io.ps.sb.cons_nr_R",
1029 FT_UINT8, BASE_HEX, NULL, 0x40,
1030 NULL, HFILL }
1031 },
1032 { &hf_pn_io_ps_sb_res,
1033 { "Bit7 - reserved for future releases", "pn_io.ps.sb.bit7",
1034 FT_UINT8, BASE_HEX, NULL, 0x80,
1035 NULL, HFILL }
1036 },
1037 { &hf_pn_io_ps_cb_iparEN,
1038 { "iPar_EN - iParameter assignment deblocked", "pn_io.ps.cb.iparEN",
1039 FT_UINT8, BASE_HEX, NULL, 0x01,
1040 NULL, HFILL }
1041 },
1042 { &hf_pn_io_ps_cb_OAReq,
1043 { "OA_Req - Operator acknowledge requested", "pn_io.ps.cb.OA_Req",
1044 FT_UINT8, BASE_HEX, NULL, 0x02,
1045 NULL, HFILL }
1046 },
1047 { &hf_pn_io_ps_cb_resetConsNr,
1048 { "R_cons_nr - Set the Virtual Consecutive Number within the F-Device to be \"0\"", "pn_io.ps.cb.R_cons_nr",
1049 FT_UINT8, BASE_HEX, NULL, 0x04,
1050 NULL, HFILL }
1051 },
1052 { &hf_pn_io_ps_cb_useTO2,
1053 { "Bit3 - Reserved or Use the secondary watchdog (Use_TO2)", "pn_io.ps.cb.bit3",
1054 FT_UINT8, BASE_HEX, NULL, 0x08,
1055 NULL, HFILL }
1056 },
1057 { &hf_pn_io_ps_cb_activateFV,
1058 { "activate_FV - Fail-safe values (FV) to be activated", "pn_io.ps.cb.activate_FV",
1059 FT_UINT8, BASE_HEX, NULL, 0x10,
1060 NULL, HFILL }
1061 },
1062 { &hf_pn_io_ps_cb_Toggle_h,
1063 { "Toggle_h - Host-based Toggle Bit", "pn_io.ps.cb.Toggle_h",
1064 FT_UINT8, BASE_HEX, NULL, 0x20,
1065 NULL, HFILL }
1066 },
1067 { &hf_pn_io_ps_cb_Chf_ACK,
1068 { "Bit6 - Reserved or Operator acknowledge after cleared channel fault (ChF_Ack)", "pn_io.ps.cb.bit6",
1069 FT_UINT8, BASE_HEX, NULL, 0x40,
1070 NULL, HFILL }
1071 },
1072 { &hf_pn_io_ps_cb_loopcheck,
1073 { "Bit7 - Reserved or Loop-back check (Loopcheck, shall be set to 1)", "pn_io.ps.cb.bit7",
1074 FT_UINT8, BASE_HEX, NULL, 0x80,
1075 NULL, HFILL }
1076 },
1077 /* PROFIsafe */
1078 { &hf_pn_io_ps_f_dest_adr,
1079 { "F_Dest_Add", "pn_io.ps.f_dest_add",
1080 FT_UINT16, BASE_DEC, NULL, 0x0,
1081 NULL, HFILL }
1082 },
1083 { &hf_pn_io_ps_f_data,
1084 { "SafetyIO Data", "pn_io.ps.f_data",
1085 FT_UINT64, BASE_HEX, NULL, 0x0,
1086 NULL, HFILL }
1087 },
1088 };
1089
1090 static gint *ett[] = {
1091 &ett_pn_io_rtc,
1092 &ett_pn_io_ioxs,
1093 &ett_pn_io_io_data_object
1094 };
1095
1096 static ei_register_info ei[] = {
1097 { &ei_pn_io_too_many_data_objects, { "pn_io.too_many_data_objects", PI_MALFORMED, PI_ERROR, "Too many data objects", EXPFILL }},
1098 };
1099
1100 expert_module_t* expert_pn_io;
1101
1102 proto_pn_io_rtc1 = proto;
1103 proto_register_field_array(proto, hf, array_length(hf));
1104 proto_register_subtree_array(ett, array_length(ett));
1105 expert_pn_io = expert_register_protocol(proto_pn_io_rtc1);
1106 expert_register_field_array(expert_pn_io, ei, array_length(ei));
1107 }
1108
1109
1110 /*
1111 * Editor modelines - https://www.wireshark.org/tools/modelines.html
1112 *
1113 * Local variables:
1114 * c-basic-offset: 4
1115 * tab-width: 8
1116 * indent-tabs-mode: nil
1117 * End:
1118 *
1119 * vi: set shiftwidth=4 tabstop=8 expandtab:
1120 * :indentSize=4:tabSize=8:noTabs=true:
1121 */
1122