18#include <gtest/gtest.h>
35 frame.cycleCounter = 1024;
38 frame.transferStatus = 0;
39 frame.payload = {0xDE, 0xAD, 0xBE, 0xEF};
43 EXPECT_EQ(encoded.size(),
static_cast<std::size_t
>(2 + 4 + 4));
54 EXPECT_FALSE(decoded.
IsOk());
72 frame.cycleCounter = 5;
74 frame.payload = {0x01, 0x02, 0x03};
80 ASSERT_TRUE(parsed.has_value());
82 EXPECT_EQ(parsed->frameId,
frame.frameId);
84 EXPECT_EQ(parsed->payload,
frame.payload);
97 EXPECT_FALSE(parsed.has_value());
105 config.
objects = {{.slot = 1, .subslot = 1, .frameOffset = 0, .dataLength = 4, .offsetIOPS = 4, .offsetIOCS = 0}};
109 builder.
SetData(1, 1, {0x11, 0x22, 0x33, 0x44});
115 EXPECT_EQ(beforeSwap[0],
static_cast<std::uint8_t
>(0));
121 EXPECT_EQ(afterSwap[0],
static_cast<std::uint8_t
>(0x11));
127 EXPECT_EQ(readback,
Bytes({0x11, 0x22, 0x33, 0x44}));
138 EXPECT_THROW(builder.
SetData(9, 9, {0x01}), std::exception);
145 config.
objects = {{.slot = 1, .subslot = 1, .frameOffset = 0, .dataLength = 4, .offsetIOPS = 4, .offsetIOCS = 0}};
147 builder.
SetData(1, 1, {0x80, 0x01});
149 const auto first = builder.
Build();
151 builder.
SetData(1, 1, {0x80, 0x02});
152 EXPECT_EQ(builder.
Build(), first);
155 EXPECT_NE(builder.
Build(), first);
162 config.
objects = {{.slot = 1, .subslot = 1, .frameOffset = 0, .dataLength = 4, .offsetIOPS = 4, .offsetIOCS = 0}};
165 std::atomic_bool stop{
false};
166 std::jthread writer([&]
170 builder.SetData(1, 1, {0x80, 0x01});
174 auto expectedFrameSize = 10U;
175 for (
int i = 0; i < 10000; ++i)
177 const auto frame = builder.Build();
178 ASSERT_LE(
frame.size(), expectedFrameSize);
186 const std::vector<rpc::IOSlot> slots = {{.slot = 0, .subslot = 1, .inputLength = 4, .outputLength = 0, .moduleIdent = 0, .submoduleIdent = 0}, {.slot = 1, .subslot = 1, .inputLength = 0, .outputLength = 2, .moduleIdent = 0, .submoduleIdent = 0}};
194 ASSERT_EQ(input_iocr.objects.size(),
static_cast<std::size_t
>(1));
196 EXPECT_EQ(input_iocr.objects[0].frameOffset, 0);
197 EXPECT_EQ(input_iocr.objects[0].dataLength, 4);
199 EXPECT_EQ(input_iocr.objects[0].offsetIOPS, 4);
201 EXPECT_EQ(input_iocr.dataLength, 40);
203 EXPECT_EQ(input_iocr.frameId,
static_cast<std::uint16_t
>(0xC001));
208 ASSERT_EQ(output_iocr.objects.size(),
static_cast<std::size_t
>(2));
210 EXPECT_EQ(output_iocr.objects[0].slot, 1);
212 EXPECT_EQ(output_iocr.objects[0].dataLength, 2);
214 EXPECT_EQ(output_iocr.objects[1].slot, 0);
216 EXPECT_EQ(output_iocr.objects[1].dataLength, 0);
218 EXPECT_GT(output_iocr.objects[1].offsetIOCS, 0);
220 EXPECT_EQ(output_iocr.frameId,
static_cast<std::uint16_t
>(0x8001));
Builds C_SDU payload from IO data objects with double-buffering.
Bytes GetData(int slot, int subslot) const
Read one object's data from the write buffer.
void SetData(int slot, int subslot, const Bytes &data)
Write one object's data into the write buffer.
void SetIops(int slot, int subslot, std::uint8_t status=IOXS_GOOD)
Set one object's IOPS (provider status) byte.
void Swap()
Promote the write buffer to the send buffer.
Bytes Build() const
Get the current send buffer contents.
std::optional< RTFrame > ParseEthernetFrame(const Bytes &data)
Parse a complete Ethernet frame and extract its RT frame.
constexpr std::uint8_t DATA_STATUS_PROVIDER_RUN
DataStatus bit: provider run state, 0=Stop, 1=Run.
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=40)
Bytes BuildEthernetFrame(const MacAddress &dstMac, const MacAddress &srcMac, const RTFrame &rtFrame)
Build a complete Ethernet frame carrying an RT frame.
constexpr std::uint8_t DATA_STATUS_VALID
DataStatus bit: data validity, 0=Invalid, 1=Valid.
constexpr std::uint8_t IOXS_GOOD
IOxS value: good, subslot level.
TEST_F(AlarmListenerTests, InitializesWithEndpoint)
std::array< std::uint8_t, macAddressLength > MacAddress
A 6-byte Ethernet MAC address.
MacAddress String2Mac(const std::string &macStr)
Parse a colon-separated MAC address string.
std::vector< std::uint8_t > Bytes
Generic byte buffer alias used throughout the library for raw wire data.
PROFINET DCE/RPC protocol structures and IO-Device connection API.
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.
std::uint16_t dataLength
Total cyclic data length in bytes.
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).
static RTFrame FromBytes(const Bytes &data)
Parse an RT frame from raw bytes (after the Ethernet header).
std::uint16_t frameId
Frame ID identifying which IOCR this frame belongs to.
std::uint16_t cycleCounter
Cycle counter, incremented each transmission.
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.