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
>((value >>
OneOctetShift) & 0x07);
40 const auto dir =
static_cast<std::uint8_t
>((value >> 11) & 0x03);
67 return "AllDisappears";
73 return "DisappearsOther";
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) +
")";
261 std::size_t offset = 0;
264 if (data.size() >= 4)
266 const auto possibleType =
static_cast<std::uint16_t
>((data[0] <<
OneOctetShift) | data[1]);
267 if (IsDiagnosisBlockType(possibleType))
273 while (offset + 6 <= data.size())
278 if (offset + 8 <= data.size())
280 const std::uint32_t maybeApi =
static_cast<std::uint32_t
>(data[offset]) <<
ThreeOctetsShift |
282 static_cast<std::uint32_t
>(data[offset + 2]) <<
OneOctetShift | data[offset + 3];
283 const auto maybeSlot =
static_cast<std::uint16_t
>((data[offset + 4] <<
OneOctetShift) | data[offset + 5]);
284 const auto maybeSubslot =
static_cast<std::uint16_t
>((data[offset + 6] <<
OneOctetShift) | data[offset + 7]);
285 if (maybeApi < 0x10000 && maybeSlot < 0x8000)
289 subslot = maybeSubslot;
291 if (offset + 6 > data.size())
299 const auto channelNum =
static_cast<std::uint16_t
>((data[offset] <<
OneOctetShift) | data[offset + 1]);
300 const auto chPropsRaw =
static_cast<std::uint16_t
>((data[offset + 2] <<
OneOctetShift) | data[offset + 3]);
301 const auto usi =
static_cast<std::uint16_t
>((data[offset + 4] <<
OneOctetShift) | data[offset + 5]);
317 if (offset + 2 > data.size())
321 const auto errorType =
static_cast<std::uint16_t
>((data[offset] <<
OneOctetShift) | data[offset + 1]);
326 else if (usi == 0x8002)
329 if (offset + 8 > data.size())
333 const auto errorType =
static_cast<std::uint16_t
>((data[offset] <<
OneOctetShift) | data[offset + 1]);
334 const auto extType =
static_cast<std::uint16_t
>((data[offset + 2] <<
OneOctetShift) | data[offset + 3]);
335 const std::uint32_t extAdd =
static_cast<std::uint32_t
>(data[offset + 4]) <<
ThreeOctetsShift |
337 static_cast<std::uint32_t
>(data[offset + 6]) <<
OneOctetShift | data[offset + 7];
349 else if (usi == 0x8003)
352 if (offset + 12 > data.size())
356 const auto errorType =
static_cast<std::uint16_t
>((data[offset] <<
OneOctetShift) | data[offset + 1]);
357 const auto extType =
static_cast<std::uint16_t
>((data[offset + 2] <<
OneOctetShift) | data[offset + 3]);
358 const std::uint32_t extAdd =
static_cast<std::uint32_t
>(data[offset + 4]) <<
ThreeOctetsShift |
360 static_cast<std::uint32_t
>(data[offset + 6]) <<
OneOctetShift | data[offset + 7];
361 const std::uint32_t qualifier =
static_cast<std::uint32_t
>(data[offset + 8]) <<
ThreeOctetsShift |
363 static_cast<std::uint32_t
>(data[offset + 10]) <<
OneOctetShift | data[offset + 11];
380 if (offset + 2 > data.size())
384 const auto errorType =
static_cast<std::uint16_t
>((data[offset] <<
OneOctetShift) | data[offset + 1]);
390 result.
entries.push_back(entry);
397 std::uint16_t subslot)
410 std::size_t offset = 6;
412 while (offset + 6 <= data.size())
414 const auto channelNum =
static_cast<std::uint16_t
>((data[offset] <<
OneOctetShift) | data[offset + 1]);
415 const auto chPropsRaw =
static_cast<std::uint16_t
>((data[offset + 2] <<
OneOctetShift) | data[offset + 3]);
416 const auto errorType =
static_cast<std::uint16_t
>((data[offset + 4] <<
OneOctetShift) | data[offset + 5]);
420 if (channelNum == 0 && chPropsRaw == 0 && errorType == 0)
434 result.
entries.push_back(entry);
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.
static constexpr int OneOctetShift
The bit-shift distance required to move data across a single octet.
static constexpr int ThreeOctetsShift
The bit-shift distance required to move data across three octets.
static constexpr int TwoOctetsShift
The bit-shift distance required to move data across two octets.
std::string Hex4(std::uint16_t value)
Format a 16-bit unsigned integer as a 4-digit hexadecimal string.
std::vector< std::uint8_t > Bytes
Generic byte buffer alias used throughout the library for raw wire data.
Any diagnosis entry (USI 0x8000, 0x8002, or 0x8003).
std::uint16_t 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.
Small helpers for reading/writing big-endian ("network order") integers to/from byte buffers....