PROFINET IO Controller Stack 1.0.0
Modern C++ implementation of a PROFINET IO Controller stack
Loading...
Searching...
No Matches
rt.h
Go to the documentation of this file.
1
17
18#pragma once
19
20#include <cstdint>
21#include <mutex>
22#include <optional>
23#include <string>
24#include <vector>
25
26#include "profinet/protocol.h"
27#include "profinet/util.h"
28
29namespace profinet::rt
30{
31
32// NOLINTBEGIN(readability-identifier-naming)
34inline constexpr std::uint16_t ETHERTYPE_PROFINET = 0x8892;
35/* Dit is oud en niet complient met std... denk ik
37inline constexpr std::uint16_t FRAME_ID_RT_CLASS_1_MIN = 0x8000;
39inline constexpr std::uint16_t FRAME_ID_RT_CLASS_1_MAX = 0xFBFF;
40*/
41// RTC1 (legacy RT_CLASS_1) cyclic frame ID range per IEC 61158-6-10;
42// 0x8000-0xBFFF is a separate range (RT_CLASS_2 in pre-V2.3 spec naming)
44inline constexpr std::uint16_t FRAME_ID_RT_CLASS_1_MIN = 0xC000;
46inline constexpr std::uint16_t FRAME_ID_RT_CLASS_1_MAX = 0xF7FF;
47
52inline constexpr std::uint16_t VLAN_TAG_RT = 0x8100C000;
53
55inline constexpr std::uint16_t FRAME_ID_ALARM_HIGH = 0xFC01;
57inline constexpr std::uint16_t FRAME_ID_ALARM_LOW = 0xFE01;
58
60inline constexpr std::uint16_t IOCR_TYPE_INPUT = 1;
62inline constexpr std::uint16_t IOCR_TYPE_OUTPUT = 2;
63
65inline constexpr std::uint8_t RT_CLASS_1 = 0x01;
67inline constexpr std::uint8_t RT_CLASS_2 = 0x02;
69inline constexpr std::uint8_t RT_CLASS_3 = 0x03;
70
71// DataStatus bit definitions
73inline constexpr std::uint8_t DATA_STATUS_STATE = 0x01;
75inline constexpr std::uint8_t DATA_STATUS_REDUNDANCY = 0x02;
77inline constexpr std::uint8_t DATA_STATUS_VALID = 0x04;
79inline constexpr std::uint8_t DATA_STATUS_RESERVED = 0x08;
81inline constexpr std::uint8_t DATA_STATUS_PROVIDER_RUN = 0x10;
83inline constexpr std::uint8_t DATA_STATUS_STATION_OK = 0x20;
85inline constexpr std::uint8_t DATA_STATUS_IGNORE = 0x80;
86
87// IOxS (Provider/Consumer Status) values
89inline constexpr std::uint8_t IOXS_GOOD = 0x80;
90
93inline constexpr std::uint8_t IOXS_DATA_STATE_GOOD = 0x80;
95inline constexpr std::uint8_t IOXS_BAD = 0x00;
97inline constexpr std::uint8_t IOXS_EXTENSION = 0x01;
98// NOLINTEND(readability-identifier-naming)
99
103{
105 std::uint16_t slot = 0;
106
108 std::uint16_t subslot = 0;
109
111 std::uint16_t frameOffset = 0;
112
114 std::uint16_t dataLength = 0;
115
117 std::uint16_t offsetIOPS = 0;
118
120 std::uint16_t offsetIOCS = 0;
121};
122
126{
128 std::uint16_t typeIOCR = 0;
129
131 std::uint16_t referenceIOCR = 0;
132
134 std::uint16_t frameId = 0;
135
137 std::uint16_t sendClockFactor = 32;
138
140 std::uint16_t reductionRatio = 32;
141
143 std::uint16_t phase = 0;
144
146 std::uint16_t watchdogFactor = 3;
147
149 std::uint16_t dataLength = 40;
150
152 std::vector<IODataObject> objects;
153
160 [[nodiscard]] std::uint32_t CycleTimeUs() const
161 {
162 return static_cast<std::uint32_t>(reductionRatio) * sendClockFactor * 125 / 4;
163 }
164
167 [[nodiscard]] double CycleTimeMs() const
168 {
169 return CycleTimeUs() / 1000.0;
170 }
171
174 [[nodiscard]] std::uint32_t WatchdogTimeUs() const
175 {
176 return static_cast<std::uint32_t>(watchdogFactor) * CycleTimeUs();
177 }
178
181 [[nodiscard]] bool IsInput() const
182 {
183 return typeIOCR == IOCR_TYPE_INPUT;
184 }
185
188 [[nodiscard]] bool IsOutput() const
189 {
190 return typeIOCR == IOCR_TYPE_OUTPUT;
191 }
192};
193
197{
199 std::uint16_t frameId = 0;
200
202 std::uint16_t cycleCounter = 0;
203
205 std::uint8_t dataStatus = 0;
206
208 std::uint8_t transferStatus = 0;
209
212
213 // NOLINTBEGIN(readability-identifier-naming)
215 static constexpr std::uint8_t DATA_VALID = DATA_STATUS_VALID;
216
218 static constexpr std::uint8_t DATA_PRIMARY = DATA_STATUS_STATE;
219
221 static constexpr std::uint8_t DATA_RUN = DATA_STATUS_PROVIDER_RUN;
222
224 static constexpr std::uint8_t DATA_OK = DATA_STATUS_STATION_OK;
225 // NOLINTEND(readability-identifier-naming)
226
231 static RTFrame FromBytes(const Bytes& data);
232
235 [[nodiscard]] Bytes ToBytes() const;
236
239 [[nodiscard]] bool IsValid() const
240 {
241 return (dataStatus & DATA_STATUS_VALID) != 0;
242 }
243
246 [[nodiscard]] bool IsRunning() const
247 {
248 return (dataStatus & DATA_STATUS_PROVIDER_RUN) != 0;
249 }
250
253 [[nodiscard]] bool IsOk() const
254 {
255 return (dataStatus & DATA_STATUS_STATION_OK) != 0;
256 }
257
260 [[nodiscard]] bool IsPrimary() const
261 {
262 return (dataStatus & DATA_STATUS_STATE) != 0;
263 }
264
267 [[nodiscard]] std::string ToString() const;
268};
269
277{
278 public:
282
288 void SetData(int slot, int subslot, const Bytes& data);
289
294 Bytes GetData(int slot, int subslot) const;
295
301 void SetIops(int slot, int subslot, std::uint8_t status = IOXS_GOOD);
302
307 void SetIocs(int slot, int subslot, std::uint8_t status = IOXS_GOOD);
308
311 void SetAllIops(std::uint8_t status = IOXS_GOOD);
312
315 void SetAllIocs(std::uint8_t status = IOXS_GOOD);
316
318 void Clear();
319
323 void Swap();
324
328 Bytes Build() const;
329
332 void Load(const Bytes& payload);
333
336 const IOCRConfig& Config() const
337 {
338 return config;
339 }
340
341 private:
344
347
350
352 mutable std::mutex writeLock;
353
355 bool dirty = false;
356};
357/*
371template <typename SlotT>
372std::pair<IOCRConfig, IOCRConfig> BuildIocrConfigs(const std::vector<SlotT>& slots, std::uint16_t inputFrameId,
373 std::uint16_t outputFrameId,
374 std::uint16_t sendClockFactor = 32,
375 std::uint16_t reductionRatio = 32,
376 int watchdogFactor = 3)
377{
378 std::vector<IODataObject> inputObjects;
379 int frameOffset = 0;
380 for (const auto& s : slots)
381 {
382 if (s.inputLength > 0)
383 {
384 inputObjects.push_back(
385 {s.slot, s.subslot, frameOffset, s.inputLength, frameOffset + s.inputLength, 0});
386 frameOffset += s.inputLength + 1;
387 }
388 }
389 for (const auto& s : slots)
390 {
391 if (s.inputLength == 0)
392 {
393 frameOffset += 1;
394 }
395 }
396
397 IOCRConfig inputIocr;
398 inputIocr.typeIOCR = IOCR_TYPE_INPUT;
399 inputIocr.referenceIOCR = 1;
400 inputIocr.frameId = inputFrameId;
401 inputIocr.sendClockFactor = sendClockFactor;
402 inputIocr.reductionRatio = reductionRatio;
403 inputIocr.watchdogFactor = watchdogFactor;
404 inputIocr.dataLength = std::max(40, frameOffset);
405 inputIocr.objects = inputObjects;
406
407 std::vector<IODataObject> outputObjects;
408 frameOffset = 0;
409 for (const auto& s : slots)
410 {
411 if (s.outputLength > 0)
412 {
413 outputObjects.push_back(
414 {s.slot, s.subslot, frameOffset, s.outputLength, frameOffset + s.outputLength, 0});
415 frameOffset += s.outputLength + 1;
416 }
417 }
418 // IOCS entries for slots with no output data: submodules with input
419 // but no output (e.g. DAP submodules) still need their IOCS
420 // acknowledged in the output frame.
421 for (const auto& s : slots)
422 {
423 if (s.outputLength == 0)
424 {
425 outputObjects.push_back({s.slot, s.subslot, frameOffset, 0, 0, frameOffset});
426 frameOffset += 1;
427 }
428 }
429
430 IOCRConfig outputIocr;
431 outputIocr.typeIOCR = IOCR_TYPE_OUTPUT;
432 outputIocr.referenceIOCR = 2;
433 outputIocr.frameId = outputFrameId;
434 outputIocr.sendClockFactor = sendClockFactor;
435 outputIocr.reductionRatio = reductionRatio;
436 outputIocr.watchdogFactor = watchdogFactor;
437 outputIocr.dataLength = std::max(40, frameOffset);
438 outputIocr.objects = outputObjects;
439
440 return {inputIocr, outputIocr};
441}
442*/
443template <typename SlotT>
444std::pair<IOCRConfig, IOCRConfig> BuildIocrConfigs(
445 const std::vector<SlotT>& slots,
446 std::uint16_t inputFrameId,
447 std::uint16_t outputFrameId,
448 std::uint16_t sendClockFactor = 32,
449 std::uint16_t reductionRatio = 32,
450 int watchdogFactor = 3,
451 std::uint16_t cSduLength = 43)
452{
453 // =========================================================================
454 // INPUT IOCR
455 //
456 // Device -> Controller
457 //
458 // C_SDU layout:
459 //
460 // 1. IOCS for every configured submodule without input data
461 // 2. Input process data
462 // 3. IOPS for every configured submodule with input data
463 //
464 // For the AUMA GSDML:
465 //
466 // 8 IOCS bytes
467 // 34 input bytes
468 // 1 IOPS byte
469 // ----------------
470 // 43 bytes total
471 // =========================================================================
472
473 std::vector<IODataObject> inputObjects;
474 std::uint16_t inputFrameOffset = 0;
475
476 // -------------------------------------------------------------------------
477 // First: IOCS section.
478 //
479 // Every configured submodule that does not provide input process data
480 // occupies one IOCS byte in the input IOCR.
481 // -------------------------------------------------------------------------
482 for (const auto& s : slots)
483 {
484 if (s.inputLength == 0)
485 {
486 inputObjects.push_back(
487 {
488 s.slot,
489 s.subslot,
490 inputFrameOffset, // No process-data bytes.
491 0, // No input data.
492 0, // No IOPS.
493 inputFrameOffset // IOCS position.
494 });
495
496 ++inputFrameOffset;
497 }
498 }
499
500 // -------------------------------------------------------------------------
501 // Second: input process data followed by IOPS.
502 // -------------------------------------------------------------------------
503 for (const auto& s : slots)
504 {
505 if (s.inputLength > 0)
506 {
507 const std::uint16_t dataOffset = inputFrameOffset;
508
509 inputFrameOffset += s.inputLength;
510
511 const std::uint16_t iopsOffset = inputFrameOffset;
512
513 ++inputFrameOffset;
514
515 inputObjects.push_back(
516 {
517 s.slot,
518 s.subslot,
519 dataOffset,
520 s.inputLength,
521 iopsOffset, // IOPS immediately after process data.
522 0 // No IOCS for this input-data object.
523 });
524 }
525 }
526
527 IOCRConfig inputIocr;
528 inputIocr.typeIOCR = IOCR_TYPE_INPUT;
529 inputIocr.referenceIOCR = 1;
530 inputIocr.frameId = inputFrameId;
531 inputIocr.sendClockFactor = sendClockFactor;
532 inputIocr.reductionRatio = reductionRatio;
533 inputIocr.phase = 0;
534 inputIocr.watchdogFactor = watchdogFactor;
535 inputIocr.dataLength = std::max(inputFrameOffset, cSduLength);
536 inputIocr.objects = std::move(inputObjects);
537
538 // =========================================================================
539 // OUTPUT IOCR
540 //
541 // Controller -> Device
542 //
543 // C_SDU layout:
544 //
545 // 1. IOCS for every configured submodule without output data
546 // 2. Output process data
547 // 3. IOPS for every configured submodule with output data
548 //
549 // For the AUMA GSDML:
550 //
551 // 8 IOCS bytes
552 // 16 output bytes
553 // 1 IOPS byte
554 // ----------------
555 // 25 bytes total
556 // =========================================================================
557
558 std::vector<IODataObject> outputObjects;
559 std::uint16_t outputFrameOffset = 0;
560
561 // -------------------------------------------------------------------------
562 // First: IOCS section.
563 //
564 // Every configured submodule that does not provide output process data
565 // occupies one IOCS byte in the output IOCR.
566 // -------------------------------------------------------------------------
567 for (const auto& s : slots)
568 {
569 if (s.outputLength == 0)
570 {
571 outputObjects.push_back(
572 {
573 s.slot,
574 s.subslot,
575 outputFrameOffset, // No process-data bytes.
576 0, // No output data.
577 0, // No IOPS.
578 outputFrameOffset // IOCS position.
579 });
580
581 ++outputFrameOffset;
582 }
583 }
584
585 // -------------------------------------------------------------------------
586 // Second: output process data followed by IOPS.
587 // -------------------------------------------------------------------------
588 for (const auto& s : slots)
589 {
590 if (s.outputLength > 0)
591 {
592 const std::uint16_t dataOffset = outputFrameOffset;
593
594 outputFrameOffset += s.outputLength;
595
596 const std::uint16_t iopsOffset = outputFrameOffset;
597
598 ++outputFrameOffset;
599
600 outputObjects.push_back(
601 {
602 s.slot,
603 s.subslot,
604 dataOffset,
605 s.outputLength,
606 // 42, // iopsOffset, // IOPS immediately after process data.
607 iopsOffset,
608 0 // No IOCS for this output-data object (was -1).
609 });
610 }
611 }
612
613 IOCRConfig outputIocr;
614 outputIocr.typeIOCR = IOCR_TYPE_OUTPUT;
615 outputIocr.referenceIOCR = 2;
616 outputIocr.frameId = outputFrameId;
617 outputIocr.sendClockFactor = sendClockFactor;
618 outputIocr.reductionRatio = reductionRatio;
619 outputIocr.phase = 0;
620 outputIocr.watchdogFactor = watchdogFactor;
621 outputIocr.dataLength = std::max(outputFrameOffset, cSduLength);
622 outputIocr.objects = std::move(outputObjects);
623
624 return {std::move(inputIocr), std::move(outputIocr)};
625}
626
632Bytes BuildEthernetFrame(const MacAddress& dstMac, const MacAddress& srcMac, const RTFrame& rtFrame);
633
638std::optional<RTFrame> ParseEthernetFrame(const Bytes& data);
639
640} // namespace profinet::rt
Builds C_SDU payload from IO data objects with double-buffering.
Definition rt.h:277
const IOCRConfig & Config() const
The IOCR configuration this builder was constructed with.
Definition rt.h:336
std::mutex writeLock
Guards writeBuffer against concurrent access.
Definition rt.h:352
Bytes GetData(int slot, int subslot) const
Read one object's data from the write buffer.
Definition rt.cpp:107
Bytes writeBuffer
Buffer the application thread writes into.
Definition rt.h:346
void Clear()
Zero the entire write buffer.
Definition rt.cpp:182
IOCRConfig config
IOCR configuration describing the objects this builder manages.
Definition rt.h:343
void Load(const Bytes &payload)
Load received payload data into the write buffer.
Definition rt.cpp:204
void SetAllIocs(std::uint8_t status=IOXS_GOOD)
Set every object's IOCS byte to the same value.
Definition rt.cpp:169
void SetData(int slot, int subslot, const Bytes &data)
Write one object's data into the write buffer.
Definition rt.cpp:89
void SetIocs(int slot, int subslot, std::uint8_t status=IOXS_GOOD)
Set one object's IOCS (consumer status) byte, if it has one.
Definition rt.cpp:139
bool dirty
Whether writeBuffer has changed since the last Swap().
Definition rt.h:355
void SetIops(int slot, int subslot, std::uint8_t status=IOXS_GOOD)
Set one object's IOPS (provider status) byte.
Definition rt.cpp:122
Bytes sendBuffer
Buffer the TX thread reads from (updated only by Swap()).
Definition rt.h:349
void Swap()
Promote the write buffer to the send buffer.
Definition rt.cpp:189
Bytes Build() const
Get the current send buffer contents.
Definition rt.cpp:199
void SetAllIops(std::uint8_t status=IOXS_GOOD)
Set every object's IOPS byte to the same value.
Definition rt.cpp:156
constexpr std::uint16_t FRAME_ID_RT_CLASS_1_MIN
Minimum frame ID in the RT_CLASS_1 range.
Definition rt.h:44
std::optional< RTFrame > ParseEthernetFrame(const Bytes &data)
Parse a complete Ethernet frame and extract its RT frame.
Definition rt.cpp:229
constexpr std::uint8_t IOXS_BAD
IOxS value: bad.
Definition rt.h:95
std::pair< IOCRConfig, IOCRConfig > BuildIocrConfigs(const std::vector< SlotT > &slots, std::uint16_t inputFrameId, std::uint16_t outputFrameId, std::uint16_t sendClockFactor=32, std::uint16_t reductionRatio=32, int watchdogFactor=3, std::uint16_t cSduLength=43)
Definition rt.h:444
constexpr std::uint16_t IOCR_TYPE_INPUT
IOCR direction: Device -> Controller.
Definition rt.h:60
constexpr std::uint8_t DATA_STATUS_STATION_OK
DataStatus bit: station health, 0=Problem, 1=OK.
Definition rt.h:83
constexpr std::uint8_t RT_CLASS_2
Real-time class: hardware scheduled (reserved).
Definition rt.h:67
constexpr std::uint8_t DATA_STATUS_IGNORE
DataStatus bit: 1=Ignore this frame.
Definition rt.h:85
constexpr std::uint16_t VLAN_TAG_RT
802.1Q priority tag for cyclic RT frames per IEC 61158-6-10: TPID 0x8100, PCP 6, VID 0 (TCI 0xC000,...
Definition rt.h:52
constexpr std::uint8_t DATA_STATUS_PROVIDER_RUN
DataStatus bit: provider run state, 0=Stop, 1=Run.
Definition rt.h:81
Bytes BuildEthernetFrame(const MacAddress &dstMac, const MacAddress &srcMac, const RTFrame &rtFrame)
Build a complete Ethernet frame carrying an RT frame.
Definition rt.cpp:212
constexpr std::uint8_t DATA_STATUS_STATE
DataStatus bit: provider state, 0=Backup, 1=Primary.
Definition rt.h:73
constexpr std::uint16_t FRAME_ID_ALARM_LOW
Frame ID used for low-priority alarms.
Definition rt.h:57
constexpr std::uint16_t ETHERTYPE_PROFINET
EtherType used by PROFINET RT frames (0x8892).
Definition rt.h:34
constexpr std::uint8_t RT_CLASS_1
Real-time class: software scheduled (250us-512ms).
Definition rt.h:65
constexpr std::uint16_t FRAME_ID_ALARM_HIGH
Frame ID used for high-priority alarms.
Definition rt.h:55
constexpr std::uint8_t DATA_STATUS_REDUNDANCY
DataStatus bit: redundancy state.
Definition rt.h:75
constexpr std::uint8_t IOXS_EXTENSION
IOxS value: extension bit set (another IOxS byte follows).
Definition rt.h:97
constexpr std::uint8_t DATA_STATUS_RESERVED
DataStatus bit: reserved.
Definition rt.h:79
constexpr std::uint8_t RT_CLASS_3
Real-time class: isochronous (IRT, hardware only).
Definition rt.h:69
constexpr std::uint8_t DATA_STATUS_VALID
DataStatus bit: data validity, 0=Invalid, 1=Valid.
Definition rt.h:77
constexpr std::uint8_t IOXS_DATA_STATE_GOOD
IOxS value: DataState is bit 7 of an IOxS byte; the lower bits carry Instance and Extension,...
Definition rt.h:93
constexpr std::uint16_t IOCR_TYPE_OUTPUT
IOCR direction: Controller -> Device.
Definition rt.h:62
constexpr std::uint8_t IOXS_GOOD
IOxS value: good, subslot level.
Definition rt.h:89
constexpr std::uint16_t FRAME_ID_RT_CLASS_1_MAX
Maximum frame ID in the RT_CLASS_1 range.
Definition rt.h:46
std::array< std::uint8_t, macAddressLength > MacAddress
A 6-byte Ethernet MAC address.
Definition util.h:67
std::vector< std::uint8_t > Bytes
Generic byte buffer alias used throughout the library for raw wire data.
Definition protocol.h:52
PROFINET protocol wire-format structures and serialization helpers.
Bytes payload
Definition rpc.cpp:3254
IOCR configuration derived from AR setup: timing parameters and IO object mappings needed for cyclic ...
Definition rt.h:126
std::uint32_t CycleTimeUs() const
Compute the cycle time in microseconds.
Definition rt.h:160
std::vector< IODataObject > objects
IO data objects carried in this IOCR's cyclic frame.
Definition rt.h:152
std::uint16_t dataLength
Total cyclic data length in bytes.
Definition rt.h:149
std::uint16_t typeIOCR
IOCR direction: 1=Input, 2=Output.
Definition rt.h:128
std::uint16_t referenceIOCR
IOCR reference assigned during AR establishment.
Definition rt.h:131
std::uint16_t sendClockFactor
Send clock base factor (31.25us units).
Definition rt.h:137
bool IsInput() const
Whether this is an input (device -> controller) IOCR.
Definition rt.h:181
double CycleTimeMs() const
Compute the cycle time in milliseconds.
Definition rt.h:167
std::uint16_t frameId
Frame ID assigned to this IOCR.
Definition rt.h:134
std::uint16_t reductionRatio
Reduction ratio relative to the send clock.
Definition rt.h:140
std::uint16_t watchdogFactor
Watchdog factor (missed-frame tolerance before a timeout fault).
Definition rt.h:146
bool IsOutput() const
Whether this is an output (controller -> device) IOCR.
Definition rt.h:188
std::uint32_t WatchdogTimeUs() const
Compute the watchdog timeout in microseconds.
Definition rt.h:174
std::uint16_t phase
Phase offset within the reduction ratio.
Definition rt.h:143
Single IO data object within the C_SDU: one piece of process data mapped to a slot/subslot,...
Definition rt.h:103
std::uint16_t frameOffset
Byte offset of this object's data within the cyclic frame.
Definition rt.h:111
std::uint16_t dataLength
Length in bytes of this object's data.
Definition rt.h:114
std::uint16_t offsetIOCS
Byte offset of this object's IOCS (consumer status) byte, or 0 if not applicable.
Definition rt.h:120
std::uint16_t offsetIOPS
Byte offset of this object's IOPS (provider status) byte.
Definition rt.h:117
std::uint16_t slot
Slot number.
Definition rt.h:105
std::uint16_t subslot
Subslot number.
Definition rt.h:108
A single PROFINET Real-Time cyclic frame: Frame ID + C_SDU payload + cycle counter/status trailer.
Definition rt.h:197
static constexpr std::uint8_t DATA_PRIMARY
Alias for DATA_STATUS_STATE, for readability at call sites.
Definition rt.h:218
std::uint8_t dataStatus
Data status bitmask (see DATA_STATUS_* constants).
Definition rt.h:205
std::uint8_t transferStatus
Transfer status (0 = OK).
Definition rt.h:208
static constexpr std::uint8_t DATA_OK
Alias for DATA_STATUS_STATION_OK, for readability at call sites.
Definition rt.h:224
static RTFrame FromBytes(const Bytes &data)
Parse an RT frame from raw bytes (after the Ethernet header).
Definition rt.cpp:14
Bytes ToBytes() const
Serialize this frame back to raw bytes.
Definition rt.cpp:32
std::uint16_t frameId
Frame ID identifying which IOCR this frame belongs to.
Definition rt.h:199
std::uint16_t cycleCounter
Cycle counter, incremented each transmission.
Definition rt.h:202
static constexpr std::uint8_t DATA_RUN
Alias for DATA_STATUS_PROVIDER_RUN, for readability at call sites.
Definition rt.h:221
bool IsPrimary() const
Whether the DataStatus state bit indicates Primary.
Definition rt.h:260
static constexpr std::uint8_t DATA_VALID
Alias for DATA_STATUS_VALID, for readability at call sites.
Definition rt.h:215
bool IsOk() const
Whether the DataStatus station-OK bit is set.
Definition rt.h:253
Bytes payload
C_SDU payload: process data plus IOPS/IOCS trailers.
Definition rt.h:211
bool IsValid() const
Whether the DataStatus valid bit is set.
Definition rt.h:239
bool IsRunning() const
Whether the DataStatus provider-run bit is set.
Definition rt.h:246
std::string ToString() const
Human-readable summary of this frame, for logging/debugging.
Definition rt.cpp:45
Declares Linux Ethernet, addressing, timing, and utility helpers used by the PROFINET stack.