PROFINET IO Controller Stack 1.0.0
Modern C++ implementation of a PROFINET IO Controller stack
Loading...
Searching...
No Matches
alarms.cpp
Go to the documentation of this file.
1
3
4#include "profinet/alarms.h"
5
6#include <cstdio>
7
8#include "profinet/wire.h"
9
10namespace profinet
11{
12
14{
15 return std::visit([](const auto& i)
16 { return i.userStructureId; }, item);
17}
18
19std::string UsiNameOf(const AlarmItemVariant& item)
20{
21 return std::visit([](const auto& i)
22 { return i.UsiName(); }, item);
23}
24
25namespace
26{
27
28std::pair<DiagnosisItem, std::size_t> ParseDiagnosisItem(const Bytes& data, std::size_t offset, Usi usi)
29{
30 if (data.size() < offset + 6)
31 {
32 throw std::invalid_argument("Truncated DiagnosisItem");
33 }
34 wire::Reader r(data);
35 r.SkipTo(offset);
36
37 DiagnosisItem item;
38 item.userStructureId = usi;
39 item.channelNumber = r.U16();
40 offset += sizeof(std::uint16_t);
41 item.channelProperties = r.U16();
42 offset += sizeof(std::uint16_t);
43 item.channelErrorType = r.U16();
44 offset += sizeof(std::uint16_t);
45
47 {
48 if (data.size() < offset + sizeof(std::uint16_t) + sizeof(std::uint32_t))
49 {
50 throw std::invalid_argument("Truncated ExtChannelDiagnosis");
51 }
52 item.extChannelErrorType = r.U16();
53 offset += sizeof(std::uint16_t);
54 item.extChannelAddValue = r.U32();
55 offset += sizeof(std::uint32_t);
56 }
57
59 {
60 if (data.size() < offset + sizeof(std::uint32_t))
61 {
62 throw std::invalid_argument("Truncated QualifiedChannelDiagnosis");
63 }
64 item.qualifiedChannelQualifier = r.U32();
65 offset += sizeof(std::uint32_t);
66 }
67
68 return {item, offset};
69}
70
71std::pair<MaintenanceItem, std::size_t> ParseMaintenanceItem(const Bytes& data, std::size_t offset)
72{
73 if (data.size() < offset + blockHeaderLength + (2 * sizeof(std::uint8_t)) + sizeof(std::uint32_t))
74 {
75 throw std::invalid_argument("Truncated MaintenanceItem");
76 }
77 const PNBlockHeader hdr = PNBlockHeader::Parse(Bytes(data.begin() + offset, data.begin() + offset + blockHeaderLength));
78
79 offset += blockHeaderLength + (2 * sizeof(std::uint8_t)); // + 2-byte padding
80 wire::Reader r(data);
81 r.SkipTo(offset);
82 const std::uint32_t status = r.U32();
83 offset += sizeof(std::uint32_t);
84
85 MaintenanceItem item;
86 item.userStructureId = Usi::Maintenance;
87 item.blockType = hdr.blockType;
88 item.blockLength = hdr.blockLength;
89 item.blockVersion = hdr.blockVersion;
90 item.maintenanceStatus = status;
91 return {item, offset};
92}
93
94std::pair<UploadRetrievalItem, std::size_t> ParseUploadRetrievalItem(const Bytes& data, std::size_t offset, Usi usi)
95{
96 if (data.size() < offset + blockHeaderLength + sizeof(std::uint16_t) + (2 * sizeof(std::uint32_t)))
97 {
98 throw std::invalid_argument("Truncated UploadRetrievalItem");
99 }
100 const PNBlockHeader hdr = PNBlockHeader::Parse(Bytes(data.begin() + offset, data.begin() + offset + 6));
101 offset += blockHeaderLength + (2 * sizeof(std::uint8_t)); // + 2-byte padding
102 wire::Reader r(data);
103 r.SkipTo(offset);
104
105 const std::uint32_t index = r.U32();
106 offset += sizeof(std::uint32_t);
107 const std::uint32_t length = r.U32();
108 offset += sizeof(std::uint32_t);
109
110 UploadRetrievalItem item;
111 item.userStructureId = usi;
112 item.blockType = hdr.blockType;
113 item.blockLength = hdr.blockLength;
114 item.blockVersion = hdr.blockVersion;
115 item.urRecordIndex = index;
116 item.urRecordLength = length;
117 return {item, offset};
118}
119
120std::pair<PEAlarmItem, std::size_t> ParsePeAlarmItem(const Bytes& data, std::size_t offset)
121{
122 if (data.size() < offset + blockHeaderLength + sizeof(std::uint8_t))
123 {
124 throw std::invalid_argument("Truncated PE_AlarmItem");
125 }
126 const PNBlockHeader hdr = PNBlockHeader::Parse(Bytes(data.begin() + offset, data.begin() + offset + blockHeaderLength));
127 offset += blockHeaderLength;
128 const std::uint8_t mode = data[offset];
129 offset += sizeof(std::uint8_t);
130
131 PEAlarmItem item;
132 item.userStructureId = Usi::PeAlarm;
133 item.blockType = hdr.blockType;
134 item.blockLength = hdr.blockLength;
135 item.blockVersion = hdr.blockVersion;
136 item.peOperationalMode = mode;
137 return {item, offset};
138}
139
140std::pair<RSAlarmItem, std::size_t> ParseRsAlarmItem(const Bytes& data, std::size_t offset, Usi usi)
141{
142 if (data.size() < offset + sizeof(std::uint16_t))
143 {
144 throw std::invalid_argument("Truncated RS_AlarmItem");
145 }
146 wire::Reader r(data);
147 r.SkipTo(offset);
148
149 const auto info = r.U16();
150 offset += sizeof(std::uint32_t);
151
152 RSAlarmItem item;
153 item.userStructureId = usi;
154 item.rsAlarmInfo = info;
155 return {item, offset};
156}
157
158std::pair<PRALAlarmItem, std::size_t> ParsePralAlarmItem(const Bytes& data, std::size_t offset)
159{
160 if (data.size() < offset + (4 * sizeof(std::uint16_t)))
161 {
162 throw std::invalid_argument("Truncated PRAL_AlarmItem");
163 }
164 wire::Reader r(data);
165 r.SkipTo(offset);
166
167 const auto channelNum = r.U16();
168 offset += sizeof(std::uint16_t);
169
170 const auto channelProps = r.U16();
171 offset += sizeof(std::uint16_t);
172
173 const auto reason = r.U16();
174 offset += sizeof(std::uint16_t);
175
176 const auto extReason = r.U16();
177 offset += sizeof(std::uint16_t);
178
179 PRALAlarmItem item;
180 item.userStructureId = Usi::PralAlarm;
181 item.channelNumber = channelNum;
182 item.propAlChannelProperties = channelProps;
183 item.prAlReason = reason;
184 item.prAlExtReason = extReason;
185 item.prAlReasonAddValue = Bytes(data.begin() + offset, data.end());
186 return {item, data.size()};
187}
188
189} // namespace
190
191std::pair<AlarmItemVariant, std::size_t> ParseAlarmItem(const Bytes& data, std::size_t offset)
192{
193 if (data.size() < offset + sizeof(std::uint16_t))
194 {
195 throw std::invalid_argument("Insufficient data for USI");
196 }
197 wire::Reader r(data);
198 r.SkipTo(offset);
199
200 const auto usi = static_cast<Usi>(r.U16());
201 offset += sizeof(std::uint16_t);
202
204 {
205 auto [item, new_offset] = ParseDiagnosisItem(data, offset, usi);
206 return {item, new_offset};
207 }
208 if (usi == Usi::Maintenance)
209 {
210 auto [item, new_offset] = ParseMaintenanceItem(data, offset);
211 return {item, new_offset};
212 }
213 if (usi == Usi::Upload || usi == Usi::IParameter)
214 {
215 auto [item, new_offset] = ParseUploadRetrievalItem(data, offset, usi);
216 return {item, new_offset};
217 }
218 if (usi == Usi::RsAlarmLow || usi == Usi::RsAlarmHigh || usi == Usi::RsAlarmSubmodule)
219 {
220 auto [item, new_offset] = ParseRsAlarmItem(data, offset, usi);
221 return {item, new_offset};
222 }
223 if (usi == Usi::PeAlarm)
224 {
225 auto [item, new_offset] = ParsePeAlarmItem(data, offset);
226 return {item, new_offset};
227 }
228 if (usi == Usi::PralAlarm)
229 {
230 auto [item, new_offset] = ParsePralAlarmItem(data, offset);
231 return {item, new_offset};
232 }
233
234 AlarmItem generic;
235 generic.userStructureId = usi;
236 generic.rawData = Bytes(data.begin() + offset, data.end());
237 return {generic, data.size()};
238}
239
241{
242 return std::format("{}:{}:0x{:04X}", api, slotNumber, subslotNumber);
243}
244
246{
247 // Minimum: BlockHeader(6) + Body(20). The body struct it actually parses
248 // (alarm_type+api+slot+subslot+module_ident+submodule_ident+alarm_specifier = 2+4+2+2+4+4+2)
249 // is only 20 bytes — a real off-by-2 bug that misaligns every item after the
250 // first. Fixed here to the structurally correct 26 total / 20 body, per
251 // IEC 61158-6-10's AlarmNotification-PDU layout (also confirmed against
252 // protocol.h's PNAlarmNotificationPDU::kFixedSize == 26).
253
254 // ralph update:
255 // AlarmNotification body size in bytes (IEC 61158-6-10): AlarmType(2) + API(4) +
256 // SlotNumber(2) + SubslotNumber(2) + ModuleIdent(4) + SubmoduleIdent(4) +
257 // AlarmSpecifier(2). The block header (6) precedes it, so the item-less PDU is
258 // 26 bytes and BlockLength reads 22(bytes following the BlockLength field).
259 if (data.size() < 26)
260 {
261 throw std::invalid_argument("AlarmNotification too short");
262 }
263
264 std::size_t offset = 0;
265 const PNBlockHeader hdr = PNBlockHeader::Parse(Bytes(data.begin(), data.begin() + blockHeaderLength));
266 offset += blockHeaderLength;
267
268 wire::Reader r(data.data() + offset, data.size() - offset);
269
270 const auto alarmType = static_cast<AlarmType>(r.U16());
271 offset += sizeof(std::uint16_t);
272
273 const std::uint32_t api = r.U32();
274 offset += sizeof(std::uint32_t);
275
276 const std::uint16_t slotNumber = r.U16();
277 offset += sizeof(std::uint16_t);
278
279 const std::uint16_t subslotNumber = r.U16();
280 offset += sizeof(std::uint16_t);
281
282 const std::uint32_t moduleIdent = r.U32();
283 offset += sizeof(std::uint32_t);
284
285 const std::uint32_t submoduleIdent = r.U32();
286 offset += sizeof(std::uint32_t);
287
288 const std::uint16_t alarmSpecifier = r.U16();
289 offset += sizeof(std::uint16_t);
290
291 AlarmNotification notification;
292 notification.blockType = hdr.blockType;
293 notification.blockVersion = {hdr.blockVersionHigh, hdr.blockVersionLow};
294 notification.alarmType = alarmType;
295 notification.api = api;
296 notification.slotNumber = slotNumber;
297 notification.subslotNumber = subslotNumber;
298 notification.moduleIdentNumber = moduleIdent;
299 notification.submoduleIdentNumber = submoduleIdent;
301 notification.channelDiagnosis = (alarmSpecifier & AlarmNotificationBitmask::ChannelDiagnosis) != 0;
302 notification.manufacturerSpecific = (alarmSpecifier & AlarmNotificationBitmask::ManufacturerSpecific) != 0;
304 notification.arDiagnosisState = (alarmSpecifier & AlarmNotificationBitmask::ArDiagnosisState) != 0; // dit zou ook 0x8000
305 // (bit 15, maar die lijkt ook voor Channel diagnosis te zijn)
306 // kunnen zijn, bit 14 is gereserveerd.
307
308 const std::size_t blockBodyLength = hdr.blockLength;
309 constexpr std::size_t blockVersionSize = 2;
310 constexpr std::size_t alarmBodySize = 20;
311
312 if (blockBodyLength < blockVersionSize + alarmBodySize)
313 {
314 throw std::invalid_argument("Invalid AlarmNotification BlockLength");
315 }
316
317 const std::size_t blockEnd = 4U + blockBodyLength;
318
319 if (data.size() < blockEnd)
320 {
321 throw std::invalid_argument("Truncated AlarmNotification block");
322 }
323
324 notification.rawPayload = Bytes(data.begin() + offset, data.begin() + blockEnd);
325
326 // notification.rawPayload = Bytes(data.begin() + offset, data.end());
327
328 std::size_t itemOffset = 0;
329 const Bytes& payload = notification.rawPayload;
330 while (itemOffset < payload.size())
331 {
332 try
333 {
334 auto [item, new_offset] = ParseAlarmItem(payload, itemOffset);
335 notification.items.push_back(std::move(item));
336 itemOffset = new_offset;
337 }
338 catch (const std::invalid_argument&)
339 {
340 break;
341 }
342 }
343
344 return notification;
345}
346
348{
349 switch (errorCode2)
350 {
351 case 0x00:
353
354 case 0x01:
356
357 case 0x02:
359
360 case 0x03:
362
363 case 0x04:
365
366 case 0x05:
368
369 case 0x06:
371
372 case 0x07:
374
375 case 0x08:
377
378 case 0x09:
380
381 case 0x0A:
383
384 case 0x0B:
386
387 case 0x0C:
389
390 case 0x0D:
392
393 case 0x0E:
395
396 case 0x0F:
398
399 case 0x10:
401
402 case 0x11:
404
405 case 0x12:
407
408 case 0x13:
410
411 case 0x14:
413
414 case 0x15:
416
417 case 0x16:
419
420 case 0x17:
422
423 case 0x18:
425
426 case 0x19:
428
429 case 0x1A:
431
432 case 0x1B:
434
435 case 0x1C:
437
438 case 0x1D:
440
441 case 0x1E:
443
444 case 0x1F:
446
447 case 0x20:
449
450 case 0x21:
452
453 case 0x22:
455
456 case 0x23:
458
459 case 0x24:
461
462 case 0x25:
464
465 case 0x26:
467
468 case 0x27:
470
471 case 0x28:
473
474 case 0x29:
476
477 case 0x2A:
479
480 case 0x2B:
482
483 case 0x2C:
485
486 case 0x2D:
488
489 case 0xFF:
491
492 default:
494 }
495}
497{
498 switch (errorCode2)
499 {
500 case 0x00:
502
503 case 0x01:
505
506 case 0x02:
507 case 0x03:
508 case 0x04:
509 case 0x05:
510 case 0x06:
511 case 0x07:
512 case 0x08:
513 case 0x09:
514 case 0x0A:
515 case 0x0B:
516 case 0x0C:
517 case 0x0D:
518 case 0x0E:
519 case 0x0F:
520 case 0x10:
521 case 0x11:
522 case 0x12:
523 case 0x13:
524 case 0x14:
525 case 0x15:
526 case 0x16:
527 case 0x17:
528 case 0x18:
529 case 0x19:
530 case 0x1A:
531 case 0x1B:
532 case 0x1C:
533 case 0x1D:
534 case 0x1E:
535 case 0x1F:
536 case 0x20:
537 case 0x21:
538 case 0x22:
539 case 0x23:
540 case 0x24:
541 case 0x25:
543
544 case 0x26:
545 case 0x27:
546 case 0x28:
547 case 0x29:
548 case 0x2A:
549 case 0x2B:
550 case 0x2C:
552
553 case 0x2D:
555
556 case 0xFF:
558
559 default:
561 }
562}
563std::string RtaError::ReasonName() const
564{
565 switch (reason)
566 {
568 return "Reserved";
569
571 return "Error within the coordination of sequence numbers";
572
574 return "Instance closed";
575
577 return "AR out of memory";
578
580 return "AR add provider or consumer failed";
581
583 return "AR consumer DHT/WDT expired";
584
586 return "AR CMI timeout";
587
589 return "AR alarm-open failed";
590
592 return "AR alarm-send.cnf(-)";
593
595 return "AR alarm-ack-send.cnf(-)";
596
598 return "AR alarm data too long";
599
601 return "AR alarm.ind(err)";
602
604 return "AR RPC-client call.cnf(-)";
605
607 return "AR abort.req";
608
610 return "AR re-run aborts existing";
611
613 return "AR release.ind received";
614
616 return "AR device deactivated";
617
619 return "AR removed";
620
622 return "AR protocol violation";
623
625 return "AR name resolution error";
626
628 return "AR RPC-Bind error";
629
631 return "AR RPC-Connect error";
632
634 return "AR RPC-Read error";
635
637 return "AR RPC-Write error";
638
640 return "AR RPC-Control error";
641
643 return "AR forbidden pull or plug after check.rsp and before in-data.ind";
644
646 return "AR AP removed";
647
649 return "AR link down";
650
652 return "AR could not register multicast-mac address";
653
655 return "Not synchronized (cannot start companion-AR)";
656
658 return "Wrong topology (cannot start companion-AR)";
659
661 return "DCP station-name changed";
662
664 return "DCP reset to factory-settings";
665
667 return "Cannot start companion-AR because of 0x8ipp submodule in first AR";
668
670 return "No irdata record yet";
671
673 return "PDEV";
674
676 return "PDEV: no port offers required speed/duplexity";
677
679 return "IP-Suite changed by DCP_Set(IPParameter) or local engineering";
680
682 return "IOCARSR: RDHT expired";
683
685 return "IOCARSR: PDEV parameterization impossible";
686
688 return "Remote application ready timeout expired";
689
691 return "IOCARSR: redundant interface lost or peripheral access impossible";
692
694 return "IOCARSR: MTOT expired";
695
697 return "IOCARSR: AR protocol violation";
698
700 return "PDEV: plug port without CombinedObjectContainer";
701
703 return "(Obsoleted) NME: no or wrong configuration";
704
706 return "User abort";
707 }
708
709 return "Unknown RTA error";
710}
712{
713 const auto value = static_cast<std::uint8_t>(reason);
714
715 if (value == 0x00U)
716 {
718 }
719
720 if (value == 0x01U)
721 {
723 }
724
725 if (value >= 0x02U && value <= 0x25U)
726 {
728 }
729
730 if (value >= 0x26U && value <= 0x2CU)
731 {
733 }
734
735 if (value == 0x2DU)
736 {
738 }
739
741}
742} // namespace profinet
Declares PROFINET alarm, diagnosis, maintenance, and USI payload types and parsers.
Lightweight cursor for parsing a big-endian byte buffer without copies.
Definition wire.h:192
std::uint32_t U32()
Read and consume a big-endian 32-bit value.
Definition wire.h:268
void SkipTo(std::size_t offset)
Move the read position to an absolute byte offset.
Definition wire.h:343
std::uint16_t U16()
Read and consume a big-endian 16-bit value.
Definition wire.h:258
constexpr int blockHeaderLength
Constant lenght of a blockHeader.
Definition protocol.h:58
@ ManufacturerSpecific
Bit 12: Indicates manufacturer-specific alarm details are present.
@ AlarmSequenceNumber
Bit mask extracting the alarm sequence number (bits 0–10, range 0–2047).
@ SubmoduleDiagnosisState
Bit 13: Indicates submodule diagnosis state is present.
@ ArDiagnosisState
Bit 14: Indicates Application Relation (AR) diagnosis state is present.
@ ChannelDiagnosis
Bit 15: Indicates channel diagnosis details are present.
std::pair< AlarmItemVariant, std::size_t > ParseAlarmItem(const Bytes &data, std::size_t offset=0)
Parse a single alarm item starting at an offset.
Definition alarms.cpp:191
AlarmNotification ParseAlarmNotification(const Bytes &data)
Parse a complete AlarmNotification PDU (BlockHeader + body + items).
Definition alarms.cpp:245
AlarmType
PROFINET Alarm Types used in AlarmNotification blocks.
Definition indices.h:382
RtaErrorReason
Exact current PROFINET RTA ErrorCode2 values.
Definition protocol.h:2507
RtaErrorClass ClassifyRtaError(RtaErrorReason reason)
Definition alarms.cpp:711
std::string UsiNameOf(const AlarmItemVariant &item)
Get the human-readable USI name for any AlarmItemVariant alternative.
Definition alarms.cpp:19
Usi
PROFINET User Structure Identifiers (USI).
Definition indices.h:526
@ Maintenance
Maintenance item.
@ IParameter
iParameter item.
@ PralAlarm
PRAL alarm item.
@ Upload
Upload record.
@ ExtendedChannelDiagnosis
Extended channel diagnosis.
@ PeAlarm
PE alarm item.
@ ChannelDiagnosis
Channel diagnosis.
@ RsAlarmHigh
RS alarm item for high alarm.
@ RsAlarmSubmodule
RS alarm item for submodule.
@ RsAlarmLow
RS alarm item for low alarm.
@ QualifiedChannelDiagnosis
Qualified channel diagnosis.
RtaErrorClass
Classification of an RTA protocol error reason.
Definition protocol.h:2485
@ UserSpecific
User-specific RTA abort.
@ SequenceNumber
Error coordinating RTA sequence numbers.
@ Abort
RTA error that aborts the application relation.
@ Reserved
No error / reserved reason.
@ Obsoleted
Obsoleted reason code.
@ Extended
Additional AR/IOCARSR/PDEV RTA reason defined by PROFINET.
std::vector< std::uint8_t > Bytes
Generic byte buffer alias used throughout the library for raw wire data.
Definition protocol.h:55
Usi UsiOf(const AlarmItemVariant &item)
Get the USI shared by every AlarmItemVariant alternative.
Definition alarms.cpp:13
std::variant< AlarmItem, DiagnosisItem, MaintenanceItem, UploadRetrievalItem, PEAlarmItem, RSAlarmItem, PRALAlarmItem > AlarmItemVariant
A parsed alarm payload item; the held alternative is selected by USI.
Definition alarms.h:334
Generic/unknown alarm item.
Definition alarms.h:29
Usi userStructureId
User Structure Identifier for this item.
Definition alarms.h:31
Complete parsed AlarmNotification PDU: header fields + parsed items.
Definition alarms.h:356
bool manufacturerSpecific
Whether the alarm specifier indicates a manufacturer-specific diagnosis.
Definition alarms.h:388
std::vector< AlarmItemVariant > items
Parsed alarm items carried by this notification.
Definition alarms.h:397
std::uint16_t slotNumber
Slot number where the alarm originated.
Definition alarms.h:370
std::uint16_t alarmSequenceNumber
Sequence number extracted from the alarm specifier.
Definition alarms.h:382
BlockType blockType
Block type (high or low priority notification).
Definition alarms.h:358
std::uint32_t api
API number.
Definition alarms.h:367
Bytes rawPayload
Raw, undecoded payload the items were parsed from.
Definition alarms.h:400
std::string Location() const
Location string identifying where the alarm originated.
Definition alarms.cpp:240
AlarmType alarmType
Alarm type (Diagnosis/Process/Pull/Plug/...).
Definition alarms.h:364
std::pair< std::uint8_t, std::uint8_t > blockVersion
Block format version.
Definition alarms.h:361
std::uint32_t submoduleIdentNumber
Submodule ident number of the affected submodule.
Definition alarms.h:379
std::uint16_t subslotNumber
Subslot number where the alarm originated.
Definition alarms.h:373
bool channelDiagnosis
Whether the alarm specifier indicates channel diagnosis is present.
Definition alarms.h:385
std::uint32_t moduleIdentNumber
Module ident number of the affected module.
Definition alarms.h:376
bool arDiagnosisState
Whether the alarm specifier indicates AR diagnosis state.
Definition alarms.h:394
bool submoduleDiagnosisState
Whether the alarm specifier indicates submodule diagnosis state.
Definition alarms.h:391
BlockType blockType
Block type identifier.
Definition protocol.h:1308
static PNBlockHeader Parse(const Bytes &data)
Parse a block header from raw bytes.
Definition protocol.h:1328
std::uint8_t blockVersionHigh
Block format major version.
Definition protocol.h:1317
std::uint8_t blockVersionLow
Block format minor version.
Definition protocol.h:1320
std::uint16_t blockLength
Length in bytes of the block body (excludes Type/Length fields).
Definition protocol.h:1311
static RtaErrorReason ClassifyRtaErrorReason(std::uint8_t errorCode2)
Return the decoded RTA reason.
Definition alarms.cpp:347
static RtaErrorClass ClassifyRtaError(std::uint8_t errorCode2)
Return the decoded RTA reason.
Definition alarms.cpp:496
RtaErrorReason reason
Decoded RTA reason.
Definition protocol.h:2591
std::string ReasonName() const
Return the decoded RTA reason name.
Definition alarms.cpp:563
std::uint8_t errorCode2
PNIO ErrorCode2 byte.
Definition protocol.h:2588
Bytes payload
Definition test_dcp.cpp:392
std::uint16_t length
Definition test_dcp.cpp:391
Generic helpers for reading and writing integer and byte data in big- and little-endian wire formats.