24 const auto ct =
static_cast<std::uint8_t
>(value & 0x03);
27 const auto acc =
static_cast<std::uint8_t
>((value >> 2) & 0x07);
30 static constexpr uint8_t maintenanceRequiredBitIdx = 5;
33 static constexpr uint8_t maintenanceDemandedBitIdx = 6;
37 const auto spec =
static_cast<std::uint8_t
>(
ByteAt(value, 1U) & 0x07);
40 const auto dir =
static_cast<std::uint8_t
>((value >> 11) & 0x03);
67 return "All Disappears";
73 return "Disappears Other";
83 return "Manufacturer";
89 return "Bidirectional";
101const std::map<std::uint16_t, std::string>& ChannelErrorTypes()
104 static const std::map<std::uint16_t, std::string> table = {
105 {0x0000,
"Reserved"},
106 {0x0001,
"Short circuit"},
107 {0x0002,
"Undervoltage"},
108 {0x0003,
"Overvoltage"},
109 {0x0004,
"Overload"},
110 {0x0005,
"Overtemperature"},
111 {0x0006,
"Line break"},
112 {0x0007,
"Upper limit value exceeded"},
113 {0x0008,
"Lower limit value exceeded"},
115 {0x000A,
"Simulation active"},
116 {0x000F,
"Parameter missing"},
117 {0x0010,
"Parameterization fault"},
118 {0x0011,
"Power supply fault"},
119 {0x0012,
"Fuse blown / open"},
120 {0x0013,
"Communication fault"},
121 {0x0014,
"Ground fault"},
122 {0x0015,
"Reference point lost"},
123 {0x0016,
"Process event lost"},
124 {0x0017,
"Threshold warning"},
125 {0x0018,
"Output disabled"},
126 {0x0019,
"Functional safety event"},
127 {0x001A,
"External fault"},
128 {0x001B,
"Sensor has incorrect configuration"},
129 {0x001F,
"Temporary fault"},
130 {0x8000,
"Data transmission impossible"},
131 {0x8001,
"Remote mismatch"},
132 {0x8002,
"Media redundancy mismatch"},
133 {0x8003,
"Sync mismatch"},
134 {0x8004,
"Isochronous mode mismatch"},
135 {0x8005,
"Multicast CR mismatch"},
136 {0x8007,
"Fiber optic mismatch"},
137 {0x8008,
"Network component function mismatch"},
138 {0x8009,
"Time mismatch"},
139 {0x800A,
"Dynamic frame packing function mismatch"},
140 {0x800B,
"Media redundancy with planned duplication mismatch"},
141 {0x800C,
"System redundancy mismatch"},
142 {0x800D,
"Multiple interface mismatch"},
143 {0x9500,
"IO-Link device event"},
144 {0x9501,
"IO-Link device event (MSB cleared)"},
145 {0x9502,
"IO-Link port event"},
151const std::map<std::uint16_t, std::string>& ExtFor(std::uint16_t channelErrorType)
153 static const std::map<std::uint16_t, std::string> general = {
154 {0x0000,
"Reserved"},
155 {0x8000,
"Accumulative info"},
157 static const std::map<std::uint16_t, std::map<std::uint16_t, std::string>> specific = {
158 {0x8000, {{0x0000,
"Reserved"}, {0x8000,
"Link state mismatch - Loss of link"}, {0x8001,
"MAUType mismatch"}, {0x8002,
"Line delay mismatch"}}},
159 {0x8001, {{0x0000,
"Reserved"}, {0x8000,
"Peer name of station mismatch"}, {0x8001,
"Peer name of port mismatch"}, {0x8002,
"Peer RT_CLASS_3 mismatch"}, {0x8003,
"Peer MAUType mismatch"}, {0x8004,
"Peer MRP domain mismatch"}, {0x8005,
"No peer detected"}, {0x8006,
"Peer line delay mismatch"}, {0x8007,
"Peer PTCP mismatch"}, {0x8008,
"Peer Preamble length mismatch"}, {0x8009,
"Peer Fragmentation mismatch"}}},
160 {0x8002, {{0x0000,
"Reserved"}, {0x8000,
"Manager role fail"}, {0x8001,
"MRP-Loss of redundancy"}, {0x8003,
"MRP ring open"}, {0x8004,
"MRP multiple manager"}}},
161 {0x8003, {{0x0000,
"Reserved"}, {0x8000,
"No sync message received"}, {0x8001,
"Jitter out of boundary"}, {0x8002,
"Sync message send failure"}, {0x8003,
"PTCP timeout"}}},
162 {0x8007, {{0x0000,
"Reserved"}, {0x8000,
"Power budget exceeded"}}},
163 {0x8008, {{0x0000,
"Reserved"}, {0x8000,
"Frame dropped - no resource"}, {0x8001,
"Frame dropped - wrong destination address"}, {0x8002,
"Frame dropped - no gateway"}}},
164 {0x8009, {{0x0000,
"Reserved"}, {0x8000,
"No master detected"}, {0x8001,
"Drift exceeded"}, {0x8002,
"Time sync failure"}}},
165 {0x800B, {{0x0000,
"Reserved"}, {0x8000,
"MRPD loss of redundancy"}}},
167 auto it = specific.find(channelErrorType);
168 if (it != specific.end())
176bool IsDiagnosisBlockType(std::uint16_t t)
178 return t == 0x0010 || t == 0x0011 || t == 0x8010 || t == 0x8011 || t == 0x8012;
185 auto it = ChannelErrorTypes().find(errorType);
186 if (it != ChannelErrorTypes().end())
190 if (errorType >= 0x000B && errorType <= 0x000E)
192 return "Reserved (" +
Hex4(errorType) +
")";
194 if (errorType >= 0x0020 && errorType <= 0x00FF)
196 return "Reserved (" +
Hex4(errorType) +
")";
198 if (errorType >= 0x0100 && errorType <= 0x7FFF)
200 return "Manufacturer-specific (" +
Hex4(errorType) +
")";
202 if (errorType >= 0x800E && errorType <= 0x8FFF)
204 return "Reserved (" +
Hex4(errorType) +
")";
206 if (errorType >= 0x9000 && errorType <= 0x9FFF)
208 return "Profile-specific (" +
Hex4(errorType) +
")";
210 if (errorType >= 0xA000)
212 return "Reserved (" +
Hex4(errorType) +
")";
214 return "Unknown (" +
Hex4(errorType) +
")";
219 const auto& lookup = ExtFor(channelErrorType);
220 auto it = lookup.find(extErrorType);
221 if (it != lookup.end())
225 if (extErrorType == 0x8000)
227 return "Accumulative info";
229 if (extErrorType >= 0x0001 && extErrorType <= 0x7FFF)
231 return "Manufacturer-specific (" +
Hex4(extErrorType) +
")";
233 if (extErrorType >= 0x8001 && extErrorType <= 0x8FFF)
235 return "Reserved (" +
Hex4(extErrorType) +
")";
237 if (extErrorType >= 0x9000 && extErrorType <= 0x9FFF)
239 return "Profile-specific (" +
Hex4(extErrorType) +
")";
241 return "Unknown (" +
Hex4(extErrorType) +
")";
256 if (data.size() < (3 *
sizeof(std::uint16_t)))
261 std::size_t offset = 0;
265 if (data.size() >= 4)
267 const auto possibleType = r.
U16();
268 if (IsDiagnosisBlockType(possibleType))
270 offset = (3 *
sizeof(std::uint16_t));
274 while (data.size() >= offset + (3 *
sizeof(std::uint16_t)))
279 if (data.size() >= offset +
sizeof(std::uint32_t) + (2 *
sizeof(std::uint16_t)))
282 locationReader.
SkipTo(offset);
284 const auto maybeApi = locationReader.
U32();
285 const auto maybeSlot = locationReader.
U16();
286 const auto maybeSubslot = locationReader.
U16();
288 if (maybeApi < 0x10000 && maybeSlot < 0x8000)
292 subslot = maybeSubslot;
297 if (data.size() < offset + (3 *
sizeof(std::uint16_t)))
314 const auto channelNum = r.
U16();
315 offset +=
sizeof(std::uint16_t);
317 const auto chPropsRaw = r.
U16();
318 offset +=
sizeof(std::uint16_t);
320 const auto usi =
static_cast<Usi>(r.
U16());
321 offset +=
sizeof(std::uint16_t);
336 if (offset + 2 > data.size())
340 const auto errorType = r.
U16();
341 offset +=
sizeof(std::uint16_t);
349 if (offset + (2 *
sizeof(std::uint16_t)) +
sizeof(std::uint32_t) > data.size())
353 const auto errorType = r.
U16();
354 offset +=
sizeof(std::uint16_t);
356 const auto extType = r.
U16();
357 offset +=
sizeof(std::uint16_t);
359 const std::uint32_t extAdd = r.
U32();
360 offset +=
sizeof(std::uint32_t);
374 if (offset + (2 *
sizeof(std::uint16_t)) + (2 *
sizeof(std::uint32_t)) > data.size())
378 const auto errorType = r.
U16();
379 offset +=
sizeof(std::uint16_t);
381 const auto extType = r.
U16();
382 offset +=
sizeof(std::uint16_t);
384 const std::uint32_t extAdd = r.
U32();
385 offset +=
sizeof(std::uint32_t);
387 const std::uint32_t qualifier = r.
U32();
388 offset +=
sizeof(std::uint32_t);
404 if (offset + 2 > data.size())
408 const auto errorType = r.
U16();
409 offset +=
sizeof(std::uint16_t);
414 result.
entries.push_back(entry);
421 std::uint16_t subslot)
438 while (data.size() >= offset + (3 *
sizeof(std::uint16_t)))
440 const auto channelNum = r.
U16();
441 offset +=
sizeof(std::uint16_t);
443 const auto chPropsRaw = r.
U16();
444 offset +=
sizeof(std::uint16_t);
446 const auto errorType = r.
U16();
447 offset +=
sizeof(std::uint16_t);
450 if (channelNum == 0 && chPropsRaw == 0 && errorType == 0)
464 result.
entries.push_back(entry);
Lightweight cursor for parsing a big-endian byte buffer without copies.
std::size_t Position() const
Current read offset from the start of the buffer.
std::uint32_t U32()
Read and consume a big-endian 32-bit value.
void SkipTo(std::size_t offset)
Move the read position to an absolute byte offset.
std::uint16_t U16()
Read and consume a big-endian 16-bit value.
PROFINET diagnosis data structures, error decoding, and parsers.
std::string DecodeChannelErrorType(std::uint16_t errorType)
Decode a ChannelErrorType to a human-readable string.
@ Output
Output direction.
@ Bidirectional
Bidirectional.
@ Manufacturer
Manufacturer-specific direction.
DiagnosisData ParseDiagnosisSimple(const Bytes &data, std::uint32_t api=0, std::uint16_t slot=0, std::uint16_t subslot=0)
Parse a simple, fixed-format diagnosis block.
DiagnosisData ParseDiagnosisBlock(const Bytes &data, std::uint32_t api=0, std::uint16_t slot=0, std::uint16_t subslot=0)
Parse a full DiagnosisData block from raw bytes.
@ Reserved
Reserved value.
@ All
All channels of the submodule.
@ Submodule
The whole submodule.
@ Specific
A specific, individually addressed channel.
@ Appears
Diagnosis appears.
@ Disappears
Diagnosis disappears.
@ AllDisappears
All diagnosis of the submodule disappears.
@ DisappearsOther
Diagnosis disappears but others remain.
std::string DecodeExtChannelErrorType(std::uint16_t channelErrorType, std::uint16_t extErrorType)
Decode an ExtChannelErrorType given its ChannelErrorType context.
constexpr int blockHeaderLength
Constant lenght of a blockHeader.
std::string Hex4(std::uint16_t value)
Format a 16-bit unsigned integer as a 4-digit hexadecimal string.
Usi
PROFINET User Structure Identifiers (USI).
@ NoIdentifier
No identifier.
@ ExtendedChannelDiagnosis
Extended channel diagnosis.
@ ChannelDiagnosis
Channel diagnosis.
@ QualifiedChannelDiagnosis
Qualified channel diagnosis.
std::vector< std::uint8_t > Bytes
Generic byte buffer alias used throughout the library for raw wire data.
constexpr std::uint8_t ByteAt(T value, std::size_t index)
Return one byte from an integral value.
Any diagnosis entry (USI 0x8000, 0x8002, or 0x8003).
Usi usi
The USI that determined which entry type was parsed.
ChannelDiagnosis base
Common fields, always populated.
std::optional< QualifiedChannelDiagnosis > qualified
Qualified fields, populated only for USI 0x8003.
std::optional< ExtChannelDiagnosis > ext
Extended fields, populated only for USI 0x8002/0x8003.
ChannelDiagnosis entry (USI 0x8000).
std::uint16_t subslot
Subslot number.
std::uint16_t channelNumber
Channel number, with the accumulative bit packed into bit 15.
std::string errorTypeName
Human-readable name for ErrorType.
std::uint16_t slot
Slot number.
std::uint16_t errorType
Channel error type code.
ChannelProperties properties
Decoded channel properties.
std::uint32_t api
API number.
Parsed ChannelProperties word (16 bits).
std::string SpecifierName() const
Human-readable name for Specifier.
std::string DirectionName() const
Human-readable name for Direction.
bool maintenanceRequired
Maintenance required flag (bit 5).
bool naintenanceDemanded
Maintenance demanded flag (bit 6).
std::string ChannelTypeName() const
Human-readable name for ChannelTypeValue.
ChannelAccumulative accumulative
Accumulative info (bits 2-4).
ChannelType channelTypeValue
Channel type (bits 0-1).
ChannelDirection direction
Data direction (bits 11-12).
ChannelSpecifier specifier
Diagnosis specifier (bits 8-10).
static ChannelProperties FromUint16(std::uint16_t value)
Decode a raw 16-bit ChannelProperties value.
std::uint16_t raw
Raw 16-bit ChannelProperties value.
Complete diagnosis data for one slot/subslot.
std::vector< AnyChannelDiagnosis > entries
Parsed diagnosis entries.
Bytes rawData
Raw, undecoded source data.
std::uint32_t api
API number.
std::uint16_t subslot
Subslot number.
std::uint16_t slot
Slot number.
ExtChannelDiagnosis entry (USI 0x8002).
std::uint32_t extAddValue
Extended channel additional value.
std::string extErrorTypeName
Human-readable name for ExtErrorType.
std::uint16_t extErrorType
Extended channel error type code.
QualifiedChannelDiagnosis entry (USI 0x8003).
std::uint32_t qualifier
Qualifier bitmask providing additional severity/context info.
Generic helpers for reading and writing integer and byte data in big- and little-endian wire formats.