16 static constexpr int minimumRtFrameSize = 6;
17 if (data.size() < minimumRtFrameSize)
19 throw std::runtime_error(
"RT frame too short: " + std::to_string(data.size()) +
" bytes");
24 const std::size_t n = data.size();
47 std::vector<std::string> flags;
50 flags.emplace_back(
"VALID");
54 flags.emplace_back(
"RUN");
58 flags.emplace_back(
"OK");
62 flags.emplace_back(
"PRIMARY");
65 for (std::size_t i = 0; i < flags.size(); ++i)
68 if (i + 1 < flags.size())
78 return std::format(
"RTFrame(id=0x{:04X}, cycle={}, status={}, payload={}B)",
83 : config(std::move(config)),
84 writeBuffer(static_cast<std::size_t>(this->config.dataLength), 0),
85 sendBuffer(static_cast<std::size_t>(this->config.dataLength), 0)
93 if (
obj.slot == slot &&
obj.subslot == subslot)
95 const std::size_t copyLen = std::min<std::size_t>(data.size(),
static_cast<std::size_t
>(
obj.dataLength));
96 const std::lock_guard<std::mutex> lock(
writeLock);
98 data | std::views::take(copyLen),
104 throw std::invalid_argument(
"Unknown slot/subslot: " + std::to_string(slot) +
"/" + std::to_string(subslot));
111 if (
obj.slot == slot &&
obj.subslot == subslot)
113 const std::lock_guard<std::mutex> lock(
writeLock);
119 throw std::invalid_argument(
"Unknown slot/subslot: " + std::to_string(slot) +
"/" + std::to_string(subslot));
126 if (
obj.slot == slot &&
obj.subslot == subslot)
128 if (
obj.dataLength > 0)
130 const std::lock_guard<std::mutex> lock(
writeLock);
131 writeBuffer.at(
static_cast<std::size_t
>(
obj.offsetIOPS)) = status;
143 if (
obj.slot == slot &&
obj.subslot == subslot)
145 if (
obj.offsetIOCS > 0)
147 const std::lock_guard<std::mutex> lock(
writeLock);
148 writeBuffer.at(
static_cast<std::size_t
>(
obj.offsetIOCS)) = status;
158 const std::lock_guard<std::mutex> lock(
writeLock);
161 if (
obj.dataLength > 0)
163 writeBuffer.at(
static_cast<std::size_t
>(
obj.offsetIOPS)) = status;
171 const std::lock_guard<std::mutex> lock(
writeLock);
174 if (
obj.offsetIOCS > 0)
176 writeBuffer.at(
static_cast<std::size_t
>(
obj.offsetIOCS)) = status;
184 const std::lock_guard<std::mutex> lock(
writeLock);
193 const std::lock_guard<std::mutex> lock(
writeLock);
207 const std::lock_guard<std::mutex> lock(
writeLock);
215 out.insert(out.end(), dstMac.begin(), dstMac.end());
216 out.insert(out.end(), srcMac.begin(), srcMac.end());
225 out.insert(out.end(), frameBytes.begin(), frameBytes.end());
231 if (data.size() < 18)
236 const auto ethertype =
static_cast<std::uint16_t
>((data[12] <<
OneOctetShift) | data[13]);
246 catch (
const std::exception&)
std::mutex writeLock
Guards writeBuffer against concurrent access.
Bytes GetData(int slot, int subslot) const
Read one object's data from the write buffer.
Bytes writeBuffer
Buffer the application thread writes into.
CyclicDataBuilder(IOCRConfig config)
Construct a builder for the given IOCR configuration.
void Clear()
Zero the entire write buffer.
IOCRConfig config
IOCR configuration describing the objects this builder manages.
void Load(const Bytes &payload)
Load received payload data into the write buffer.
void SetAllIocs(std::uint8_t status=IOXS_GOOD)
Set every object's IOCS byte to the same value.
void SetData(int slot, int subslot, const Bytes &data)
Write one object's data into the write buffer.
void SetIocs(int slot, int subslot, std::uint8_t status=IOXS_GOOD)
Set one object's IOCS (consumer status) byte, if it has one.
bool dirty
Whether writeBuffer has changed since the last Swap().
void SetIops(int slot, int subslot, std::uint8_t status=IOXS_GOOD)
Set one object's IOPS (provider status) byte.
Bytes sendBuffer
Buffer the TX thread reads from (updated only by Swap()).
void Swap()
Promote the write buffer to the send buffer.
Bytes Build() const
Get the current send buffer contents.
void SetAllIops(std::uint8_t status=IOXS_GOOD)
Set every object's IOPS byte to the same value.
std::optional< RTFrame > ParseEthernetFrame(const Bytes &data)
Parse a complete Ethernet frame and extract its RT frame.
Bytes BuildEthernetFrame(const MacAddress &dstMac, const MacAddress &srcMac, const RTFrame &rtFrame)
Build a complete Ethernet frame carrying an RT frame.
constexpr std::uint16_t ETHERTYPE_PROFINET
EtherType used by PROFINET RT frames (0x8892).
std::array< std::uint8_t, macAddressLength > MacAddress
A 6-byte Ethernet MAC address.
static constexpr int OneOctetShift
The bit-shift distance required to move data across a single octet.
static constexpr std::uint8_t LowByteMask
Bitmask used to isolate the lowest significant byte (8 bits) of a larger integer.
std::vector< std::uint8_t > Bytes
Generic byte buffer alias used throughout the library for raw wire data.
Declares PROFINET RT_CLASS_1 cyclic frame and IOCR data structures.
IOCR configuration derived from AR setup: timing parameters and IO object mappings needed for cyclic ...
std::vector< IODataObject > objects
IO data objects carried in this IOCR's cyclic frame.
A single PROFINET Real-Time cyclic frame: Frame ID + C_SDU payload + cycle counter/status trailer.
std::uint8_t dataStatus
Data status bitmask (see DATA_STATUS_* constants).
std::uint8_t transferStatus
Transfer status (0 = OK).
static RTFrame FromBytes(const Bytes &data)
Parse an RT frame from raw bytes (after the Ethernet header).
Bytes ToBytes() const
Serialize this frame back to raw bytes.
std::uint16_t frameId
Frame ID identifying which IOCR this frame belongs to.
std::uint16_t cycleCounter
Cycle counter, incremented each transmission.
bool IsPrimary() const
Whether the DataStatus state bit indicates Primary.
bool IsOk() const
Whether the DataStatus station-OK bit is set.
Bytes payload
C_SDU payload: process data plus IOPS/IOCS trailers.
bool IsValid() const
Whether the DataStatus valid bit is set.
bool IsRunning() const
Whether the DataStatus provider-run bit is set.
std::string ToString() const
Human-readable summary of this frame, for logging/debugging.