PROFINET IO Controller Stack 1.0.0
Modern C++ implementation of a PROFINET IO Controller stack
Loading...
Searching...
No Matches
test_blocks.cpp
Go to the documentation of this file.
1
20
21#include <gtest/gtest.h>
22
23#include "profinet/blocks.h"
24#include "profinet/indices.h"
25#include "profinet/wire.h"
26
27using namespace profinet;
28using namespace profinet::blocks;
29
30// =============================================================================
31// Helpers to build raw wire bytes for test fixtures
32// =============================================================================
33
34namespace
35{
36
37Bytes MakeBlockHeader(BlockType blockType,
38 std::uint16_t blockLength,
39 std::uint8_t verHi = 1,
40 std::uint8_t verLo = 0)
41{
42 Bytes out;
43 wire::PutU16(out, static_cast<std::uint16_t>(blockType));
44 wire::PutU16(out, blockLength);
45 wire::PutU8(out, verHi);
46 wire::PutU8(out, verLo);
47 return out;
48}
49
50Bytes MakeModuleDiffBlock(std::uint16_t slot,
51 std::uint16_t subslot,
52 std::uint16_t moduleState,
53 std::uint16_t submoduleState)
54{
55 Bytes body;
56
57 wire::PutU16(body, 1); // NumberOfAPIs
58 wire::PutU32(body, 0); // API
59 wire::PutU16(body, 1); // NumberOfModules
60 wire::PutU16(body, slot); // SlotNumber
61 wire::PutU32(body, 0x0001); // ModuleIdentNumber
62 wire::PutU16(body, moduleState);
63 wire::PutU16(body, 1); // NumberOfSubmodules
64 wire::PutU16(body, subslot);
65 wire::PutU32(body, 0x0001); // SubmoduleIdentNumber
66 wire::PutU16(body, submoduleState);
67
68 const Bytes hdr = MakeBlockHeader(BlockType::ModuleDifference, body.size() + 2);
69
70 Bytes out = hdr;
71 out.insert(out.end(), body.begin(), body.end());
72
73 return out;
74}
75
76Bytes MakeRealIdDataV10(const std::vector<std::pair<std::uint16_t, std::uint16_t>>& slots)
77{
78 // No outer block header for v1.0.
79 Bytes body;
80
81 wire::PutU16(body, slots.size());
82
83 for (auto [Slot, Subslot] : slots)
84 {
85 wire::PutU16(body, Slot);
86 wire::PutU32(body, 0x42); // ModuleIdentNumber
87 wire::PutU16(body, 1); // NumberOfSubslots
88 wire::PutU16(body, Subslot);
89 wire::PutU32(body, 0x99); // SubmoduleIdentNumber
90 }
91
92 return body;
93}
94
95Bytes MakeExpectedSubmoduleDD(std::uint16_t dataDescription,
96 std::uint16_t dataLen)
97{
98 Bytes out;
99
100 wire::PutU16(out, dataDescription);
101 wire::PutU16(out, dataLen);
102 wire::PutU8(out, 1); // length_iocs
103 wire::PutU8(out, 1); // length_iops
104
105 return out;
106}
107
108} // namespace
109
110// =============================================================================
111// Test fixture
112// =============================================================================
113namespace
114{
115class BlocksTest : public ::testing::Test
116{
117};
118} // namespace
119 //
120// =============================================================================
121// parse_block_header
122// =============================================================================
123
126{
127 const Bytes data = MakeBlockHeader(BlockType::ApplicationRelationRequest, 58);
128
129 auto [hdr, newOffset] = ParseBlockHeader(data);
130
131 EXPECT_EQ(hdr.blockType, BlockType::ApplicationRelationRequest);
132 EXPECT_EQ(hdr.blockLength, 58);
133 EXPECT_EQ(hdr.versionHigh, 1);
134 EXPECT_EQ(hdr.versionLow, 0);
135 EXPECT_EQ(newOffset, 6U);
136 EXPECT_EQ(hdr.BodyLength(), 56);
137 EXPECT_EQ(hdr.TypeName(), "Application Relation Request");
138}
139
141TEST_F(BlocksTest, ParseBlockHeaderRejectsTooShortData)
142{
143 const Bytes data = {0x01, 0x01, 0x00};
144
145 EXPECT_THROW(ParseBlockHeader(data), std::exception);
146}
147
149TEST_F(BlocksTest, Align4)
150{
151 EXPECT_EQ(Align4(0), 0);
152 EXPECT_EQ(Align4(1), 4);
153 EXPECT_EQ(Align4(4), 4);
154 EXPECT_EQ(Align4(5), 8);
155 EXPECT_EQ(Align4(7), 8);
156 EXPECT_EQ(Align4(8), 8);
157}
158
159// =============================================================================
160// ModuleDiffBlock
161// =============================================================================
162
164TEST_F(BlocksTest, ParseModuleDiffBlockAllOk)
165{
166 const Bytes data = MakeModuleDiffBlock(
167 1,
168 1,
171
172 auto mdb = ParseModuleDiffBlock(data);
173
174 ASSERT_EQ(mdb.modules.size(), 1);
175
176 ASSERT_FALSE(mdb.modules[0].submodules.empty());
177
178 EXPECT_TRUE(mdb.modules[0].IsProper());
179 EXPECT_TRUE(mdb.modules[0].submodules[0].IsOk());
180 EXPECT_TRUE(mdb.AllOk());
181 EXPECT_TRUE(mdb.GetMismatches().empty());
182}
183
185TEST_F(BlocksTest, ParseModuleDiffBlockWrongSubmodule)
186{
187 const Bytes data = MakeModuleDiffBlock(
188 1,
189 2,
192
193 auto mdb = ParseModuleDiffBlock(data);
194
195 EXPECT_FALSE(mdb.AllOk());
196
197 auto mismatches = mdb.GetMismatches();
198
199 ASSERT_EQ(mismatches.size(), 1);
200
201 EXPECT_EQ(std::get<0>(mismatches[0]), 1);
202
203 EXPECT_EQ(std::get<1>(mismatches[0]), 2);
204
205 EXPECT_EQ(std::get<2>(mismatches[0]), "WrongSubmodule");
206}
207
209TEST_F(BlocksTest, ParseModuleDiffBlockRejectsWrongBlockType)
210{
211 Bytes data = MakeBlockHeader(BlockType::ExpectedSubmoduleRequest, 10);
212
213 data.insert(data.end(), 10, 0);
214
215 EXPECT_THROW(ParseModuleDiffBlock(data), std::exception);
216}
217
219TEST_F(BlocksTest, ParseModuleDiffBlockTooShortReturnsEmpty)
220{
221 const Bytes data = {0x01, 0x02};
222
223 auto mdb = ParseModuleDiffBlock(data);
224
225 EXPECT_TRUE(mdb.modules.empty());
226}
227
228// =============================================================================
229// RealIdentificationData
230// =============================================================================
231
233TEST_F(BlocksTest, ParseRealIdentificationDataV10)
234{
235 const Bytes data = MakeRealIdDataV10({{0, 1},
236 {1, 1}});
237
238 auto result = ParseRealIdentificationData(data);
239
240 // v1.0 has no outer block header; version defaults to 1.0.
241 ASSERT_EQ(result.slots.size(), 2);
242
243 EXPECT_EQ(result.slots[0].slot, 0);
244 EXPECT_EQ(result.slots[1].slot, 1);
245 EXPECT_EQ(result.slots[0].moduleIdent, 0x42);
246 EXPECT_EQ(result.slots[0].submoduleIdent, 0x99);
247}
248
250TEST_F(BlocksTest, ParseRealIdentificationDataTooShortReturnsEmpty)
251{
252 const Bytes data = {0x01};
253
254 auto result = ParseRealIdentificationData(data);
255
256 EXPECT_TRUE(result.slots.empty());
257}
258
259// =============================================================================
260// IODWriteMultipleBuilder + parse_write_multiple_response
261// =============================================================================
262
264TEST_F(BlocksTest, IODWriteMultipleBuilderBuildsValidPacket)
265{
266 std::array<std::uint8_t, uuidLenght> arUuid{};
267
268 arUuid[0] = 0xAA;
269
270 IODWriteMultipleBuilder builder(arUuid, 0);
271
272 builder.AddWrite(
273 1,
274 1,
275 0xAFF1,
276 {0x11, 0x22, 0x33, 0x44});
277
278 builder.AddWrite(
279 1,
280 1,
281 0xAFF2,
282 {0x55, 0x66});
283
284 Bytes packet = builder.Build();
285
286 // Outer header:
287 // 6 (block header)
288 // + 2 (seq)
289 // + 16 (ar_uuid)
290 // + 4 (api)
291 // + 2 (slot)
292 // + 2 (subslot)
293 // + 2 (pad)
294 // + 2 (idx)
295 // + 4 (len)
296 // + 24 (padding)
297 // = 64
298 ASSERT_GE(packet.size(), 64);
299
300 // INDEX field is at bytes 34-35.
301 ASSERT_GE(packet.size(), 36);
302
303 wire::Reader r(packet);
304 r.SkipTo(34);
305 const auto outerIdx = r.U16();
306
307 EXPECT_EQ(outerIdx, WRITE_MULTIPLE);
308}
309
310// =============================================================================
311// ExpectedSubmoduleBlockReq
312// =============================================================================
313
315TEST_F(BlocksTest, ExpectedSubmoduleBlockReqBuildsInputBlock)
316{
318
319 req.AddSubmodule(
320 0,
321 1,
322 1,
323 0x0001,
324 0x0001,
325 1, // INPUT
326 4,
327 0);
328
329 Bytes out = req.ToBytes();
330 wire::Reader r(out);
331
332 ASSERT_GE(out.size(), 6U);
333
334 const auto blockType = r.U16();
335
336 EXPECT_EQ(blockType, BlockType::ExpectedSubmoduleRequest);
337
338 // Body starts at offset 6:
339 r.SkipTo(6);
340 // NumberOfAPIs
341 const auto numApis = r.U16();
342
343 EXPECT_EQ(numApis, 1U);
344}
345
347TEST_F(BlocksTest, ExpectedSubmoduleBlockReqInputOutputIncludesTwoDataDescriptions)
348{
350
351 req.AddSubmodule(
352 0,
353 1,
354 1,
355 0x0001,
356 0x0001,
357 3, // INPUT_OUTPUT
358 4,
359 2);
360
361 const Bytes out = req.ToBytes();
362
363 // Body:
364 // NumAPIs(2)
365 // + API entry(14)
366 // + submodule header(8)
367 // + 2 DDs(12)
368 // = 36 bytes
369 //
370 // Total with header = 6 + 36 = 42 bytes.
371 EXPECT_EQ(out.size(), 42);
372}
373
375TEST_F(BlocksTest, ExpectedSubmoduleBlockReqNoIoProducesOneDataDescription)
376{
378
379 req.AddSubmodule(
380 0,
381 0,
382 1,
383 0x0001,
384 0x0001,
385 0, // NO_IO
386 0,
387 0);
388
389 const Bytes out = req.ToBytes();
390
391 // Body:
392 // NumAPIs(2)
393 // + API entry(14)
394 // + submodule header(8)
395 // + 1 DD(6)
396 // = 30 bytes
397 //
398 // Total with header = 6 + 30 = 36 bytes.
399 EXPECT_EQ(out.size(), 36);
400}
401
402// =============================================================================
403// parse_port_statistics
404// =============================================================================
405
408{
409 Bytes data;
410
411 wire::PutU16(data, 0x0003); // counter_status
412 wire::PutU32(data, 100000); // in_octets
413 wire::PutU32(data, 200000); // out_octets
414 wire::PutU32(data, 10); // in_discards
415 wire::PutU32(data, 20); // out_discards
416 wire::PutU32(data, 5); // in_errors
417 wire::PutU32(data, 7); // out_errors
418
419 auto stats = ParsePortStatistics(data);
420
421 ASSERT_TRUE(stats.has_value());
422
423 EXPECT_EQ(stats->counterStatus, 0x0003);
424 EXPECT_EQ(stats->inOctets, 100000);
425 EXPECT_EQ(stats->outOctets, 200000);
426 EXPECT_EQ(stats->inErrors, 5);
427}
428
430TEST_F(BlocksTest, ParsePortStatisticsTooShortReturnsNullopt)
431{
432 const Bytes data = {0x00, 0x03, 0x00};
433
434 auto stats = ParsePortStatistics(data);
435
436 EXPECT_FALSE(stats.has_value());
437}
438
439namespace
440{
441
443constexpr std::size_t TestAlign4(const std::size_t offset)
444{
445 return (offset + 3U) & ~3U;
446}
447
449void AlignBuffer4(Bytes& data)
450{
451 data.resize(TestAlign4(data.size()), 0);
452}
453
474Bytes BuildPdPortData(
475 const std::uint16_t slot,
476 const std::uint16_t subslot,
477 const std::string& portId,
478 const std::vector<PeerInfo>& peers,
479 const std::uint16_t mauType = 0,
480 const std::uint32_t domainBoundary = 0,
481 const std::uint32_t multicastBoundary = 0,
482 const std::uint8_t linkStatePort = 0,
483 const std::uint8_t linkStateLink = 0,
484 const std::uint32_t mediaType = 0)
485{
486 Bytes data;
487
488 // Slot / subslot.
489 wire::PutU16(data, slot);
490 wire::PutU16(data, subslot);
491
492 // Port ID.
493 wire::PutU8(data, portId.size());
494 wire::PutFixed(data, portId);
495
496 // Number of peers.
497 wire::PutU8(data, peers.size());
498
499 // Peer records start on a 4-byte boundary.
500 AlignBuffer4(data);
501
502 for (const auto& peer : peers)
503 {
504 wire::PutU8(data, peer.portId.size());
505 wire::PutFixed(data, peer.portId);
506
507 wire::PutU8(data, peer.chassisId.size());
508 wire::PutFixed(data, peer.chassisId);
509
510 // Parser aligns before reading the MAC address.
511 AlignBuffer4(data);
512
513 wire::PutFixed(data, peer.macAddress);
514 // Parser aligns before the next peer / MAU type.
515 AlignBuffer4(data);
516 }
517
518 // MAU type.
519 wire::PutU16(data, mauType);
520
521 // Parser aligns before boundaries.
522 AlignBuffer4(data);
523
524 // Domain boundary.
525 wire::PutU32(data, domainBoundary);
526
527 // Multicast boundary.
528 wire::PutU32(data, multicastBoundary);
529
530 // Link state.
531 wire::PutU8(data, linkStatePort);
532 wire::PutU8(data, linkStateLink);
533
534 // Parser aligns before media type.
535 AlignBuffer4(data);
536
537 // Media type.
538 wire::PutU32(data, mediaType);
539
540 return data;
541}
542
543} // namespace
544
546TEST_F(BlocksTest, ParsePdPortDataRealParsesSlotAndSubslot)
547{
548 const Bytes data = BuildPdPortData(
549 1,
550 0x8001,
551 "",
552 {});
553
554 const auto result = ParsePdPortDataReal(data, 0, 99, 99);
555
556 EXPECT_EQ(result.slot, 1);
557 EXPECT_EQ(result.subslot, 0x8001);
558}
559
561TEST_F(BlocksTest, ParsePdPortDataRealDecodesAsciiPortId)
562{
563 const Bytes data = BuildPdPortData(
564 1,
565 0x8001,
566 "Port",
567 {});
568
569 const auto result = ParsePdPortDataReal(data, 0, 99, 99);
570
571 EXPECT_EQ(result.slot, 1);
572 EXPECT_EQ(result.subslot, 0x8001);
573 EXPECT_EQ(result.portId, "Port");
574}
575
577TEST_F(BlocksTest, ParsePdPortDataRealDecodesExtendedLatin1PortId)
578{
579 const std::string latin1PortId{
580 'P',
581 static_cast<char>(0xE9), // é
582 static_cast<char>(0xF6) // ö
583 };
584
585 const Bytes data = BuildPdPortData(
586 1,
587 0x8001,
588 latin1PortId,
589 {});
590
591 const auto result = ParsePdPortDataReal(data, 0, 99, 99);
592
593 EXPECT_EQ(
594 result.portId,
595 "P\xC3\xA9\xC3\xB6");
596}
597
599TEST_F(BlocksTest, ParsePdPortDataRealParsesPeer)
600{
601 const PeerInfo peer{
602 .portId = "Peer1",
603 .chassisId = "Chass1",
604 .macAddress = {
605 0x00, 0x11, 0x22,
606 0x33, 0x44, 0x55}};
607
608 const Bytes data = BuildPdPortData(
609 1,
610 0x8001,
611 "Port",
612 {peer});
613
614 const auto result = ParsePdPortDataReal(data, 0, 99, 99);
615
616 ASSERT_EQ(result.peers.size(), 1U);
617
618 EXPECT_EQ(result.peers[0].portId, "Peer1");
619 EXPECT_EQ(result.peers[0].chassisId, "Chass1");
620
621 const std::array<std::uint8_t, 6> expectedMac{
622 0x00, 0x11, 0x22,
623 0x33, 0x44, 0x55};
624
625 EXPECT_EQ(result.peers[0].macAddress, expectedMac);
626}
627
629TEST_F(BlocksTest, ParsePdPortDataRealDecodesExtendedLatin1PeerIds)
630{
631 const PeerInfo peer{
632 .portId = std::string{
633 static_cast<char>(0xE9) // é
634 },
635 .chassisId = std::string{
636 static_cast<char>(0xF6) // ö
637 },
638 .macAddress = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55}};
639
640 const Bytes data = BuildPdPortData(
641 1,
642 0x8001,
643 "Port",
644 {peer});
645
646 const auto result = ParsePdPortDataReal(data, 0, 99, 99);
647
648 ASSERT_EQ(result.peers.size(), 1U);
649
650 EXPECT_EQ(result.peers[0].portId, "\xC3\xA9");
651 EXPECT_EQ(result.peers[0].chassisId, "\xC3\xB6");
652}
653
655TEST_F(BlocksTest, ParsePdPortDataRealParsesMauType)
656{
657 const Bytes data = BuildPdPortData(
658 1,
659 0x8001,
660 "Port",
661 {},
662 30);
663
664 const auto result = ParsePdPortDataReal(data, 0, 99, 99);
665
666 EXPECT_EQ(result.mauType, 30);
667}
668
670TEST_F(BlocksTest, ParsePdPortDataRealParsesPortProperties)
671{
672 const Bytes data = BuildPdPortData(
673 1,
674 0x8001,
675 "Port",
676 {},
677 30,
678 0x12345678,
679 0x9ABCDEF0,
680 0x01,
681 0x02,
682 0x11223344);
683
684 const auto result = ParsePdPortDataReal(data, 0, 99, 99);
685
686 EXPECT_EQ(result.mauType, 30);
687 EXPECT_EQ(result.domainBoundary, 0x12345678U);
688 EXPECT_EQ(result.multicastBoundary, 0x9ABCDEF0U);
689 EXPECT_EQ(result.linkStatePort, 0x01);
690 EXPECT_EQ(result.linkStateLink, 0x02);
691 EXPECT_EQ(result.mediaType, 0x11223344U);
692}
693
695TEST_F(BlocksTest, ParsePdPortDataRealParsesCompletePortData)
696{
697 const PeerInfo peer{
698 .portId = "Peer1",
699 .chassisId = "Chass1",
700 .macAddress = {
701 0xAA, 0xBB, 0xCC,
702 0xDD, 0xEE, 0xFF}};
703
704 const Bytes data = BuildPdPortData(
705 1,
706 0x8001,
707 "Port",
708 {peer},
709 30,
710 0x12345678,
711 0x9ABCDEF0,
712 0x01,
713 0x02,
714 0x11223344);
715
716 const auto result = ParsePdPortDataReal(data, 0, 0, 0);
717
718 EXPECT_EQ(result.slot, 1);
719 EXPECT_EQ(result.subslot, 0x8001);
720 EXPECT_EQ(result.portId, "Port");
721
722 EXPECT_EQ(result.mauType, 30);
723 EXPECT_EQ(result.domainBoundary, 0x12345678U);
724 EXPECT_EQ(result.multicastBoundary, 0x9ABCDEF0U);
725 EXPECT_EQ(result.linkStatePort, 0x01);
726 EXPECT_EQ(result.linkStateLink, 0x02);
727 EXPECT_EQ(result.mediaType, 0x11223344U);
728
729 ASSERT_EQ(result.peers.size(), 1U);
730
731 EXPECT_EQ(result.peers[0].portId, "Peer1");
732 EXPECT_EQ(result.peers[0].chassisId, "Chass1");
733
734 const std::array<std::uint8_t, 6> expectedMac{
735 0xAA, 0xBB, 0xCC,
736 0xDD, 0xEE, 0xFF};
737
738 EXPECT_EQ(result.peers[0].macAddress, expectedMac);
739}
740
742TEST_F(BlocksTest, ParsePdPortDataRealHandlesEmptyData)
743{
744 const Bytes data;
745
746 const auto result = ParsePdPortDataReal(data, 0, 7, 0x8001);
747
748 EXPECT_EQ(result.slot, 7);
749 EXPECT_EQ(result.subslot, 0x8001);
750 EXPECT_TRUE(result.portId.empty());
751 EXPECT_EQ(result.mauType, 0);
752 EXPECT_EQ(result.linkStatePort, 0);
753 EXPECT_EQ(result.linkStateLink, 0);
754 EXPECT_EQ(result.mediaType, 0);
755 EXPECT_TRUE(result.peers.empty());
756 EXPECT_EQ(result.domainBoundary, 0U);
757 EXPECT_EQ(result.multicastBoundary, 0U);
758}
759
761TEST_F(BlocksTest, ParsePdPortDataRealHandlesMissingPortIdLength)
762{
763 const Bytes data{
764 0x00, 0x01,
765 0x80, 0x01};
766
767 const auto result = ParsePdPortDataReal(data, 0, 7, 0x8001);
768
769 EXPECT_EQ(result.slot, 1);
770 EXPECT_EQ(result.subslot, 0x8001);
771 EXPECT_TRUE(result.portId.empty());
772 EXPECT_TRUE(result.peers.empty());
773}
774
776TEST_F(BlocksTest, ParsePdPortDataRealHandlesTruncatedPortId)
777{
778 const Bytes data{
779 0x00, 0x01,
780 0x80, 0x01,
781
782 // Port ID length = 5, but only 2 bytes follow.
783 0x05,
784 'P',
785 'o'};
786
787 const auto result = ParsePdPortDataReal(data, 0, 7, 0x8001);
788
789 EXPECT_TRUE(result.portId.empty());
790 EXPECT_TRUE(result.peers.empty());
791}
792
794TEST_F(BlocksTest, ParsePdPortDataRealHandlesMissingPeerCount)
795{
796 const Bytes data{
797 0x00, 0x01,
798 0x80, 0x01,
799
800 0x01,
801 'P'};
802
803 const auto result = ParsePdPortDataReal(data, 0, 7, 0x8001);
804
805 EXPECT_EQ(result.portId, "P");
806 EXPECT_TRUE(result.peers.empty());
807}
808
810TEST_F(BlocksTest, DISABLED_ParsePdPortDataRealHandlesTruncatedPeerPortId)
811{
812 const Bytes data{
813 // Slot/subslot.
814 0x00, 0x01,
815 0x80, 0x01,
816
817 // Port ID: "P".
818 0x01,
819 'P',
820
821 // One peer.
822 0x01,
823
824 // Padding to relative offset 8.
825 0x00,
826
827 // Peer port ID length = 5, but only "Pe" is present.
828 0x05,
829 'P',
830 'e'};
831
832 ASSERT_EQ(data.size(), 11U);
833
834 const auto result = ParsePdPortDataReal(data, 0, 7, 0x8001);
835
836 EXPECT_EQ(result.slot, 1);
837 EXPECT_EQ(result.subslot, 0x8001);
838 EXPECT_EQ(result.portId, "P");
839 EXPECT_TRUE(result.peers.empty());
840}
Declares PROFINET IO connection-management block structures and wire serialization.
ExpectedSubmoduleBlockReq (0x0104) builder.
Definition blocks.h:673
Bytes ToBytes() const
Serialize the complete block to raw bytes.
Definition blocks.cpp:958
ExpectedSubmoduleBlockReq & AddSubmodule(std::uint32_t api, std::uint16_t slot, std::uint16_t subslot, std::uint32_t moduleIdent, std::uint32_t submoduleIdent, std::uint16_t submoduleType=0, std::uint16_t inputLength=0, std::uint16_t outputLength=0)
Add a single submodule.
Definition blocks.cpp:878
Builder for IODWriteMultipleReq packets (index 0xE040).
Definition blocks.h:487
Bytes Build() const
Build the complete IODWriteMultipleReq packet.
Definition blocks.cpp:733
IODWriteMultipleBuilder & AddWrite(std::uint16_t slot, std::uint16_t subslot, std::uint16_t index, Bytes data, std::uint32_t api=0)
Add a write operation.
Definition blocks.cpp:683
Lightweight cursor for parsing a big-endian byte buffer without copies.
Definition wire.h:192
void SkipTo(std::size_t offset)
Move the read position to an absolute byte offset.
Definition wire.h:343
std::uint16_t U16()
Read and consume a big-endian 16-bit value.
Definition wire.h:258
PROFINET record-data indices, block types, and protocol enumerations.
ModuleDiffBlock ParseModuleDiffBlock(const Bytes &data)
Parse a ModuleDiffBlock (0x8104) from raw bytes.
Definition blocks.cpp:609
PortInfo ParsePdPortDataReal(const Bytes &data, std::size_t offset=0, std::uint16_t slot=0, std::uint16_t subslot=0)
Parse a PDPortDataReal (0x020F) block body.
Definition blocks.cpp:199
std::size_t Align4(std::size_t offset)
Round an offset up to the next 4-byte boundary.
Definition blocks.h:266
RealIdentificationData ParseRealIdentificationData(const Bytes &data)
Parse a RealIdentificationData (0xF000 or 0x0013) response.
Definition blocks.cpp:422
std::pair< BlockHeader, std::size_t > ParseBlockHeader(const Bytes &data, std::size_t offset=0)
Parse a 6-byte PROFINET block header at an offset.
Definition blocks.cpp:114
std::optional< PortStatistics > ParsePortStatistics(const Bytes &data, std::size_t offset=0)
Parse a PDPortStatistic (0x0251) block body.
Definition blocks.cpp:529
void PutFixed(std::vector< std::uint8_t > &out, const std::array< std::uint8_t, N > &data)
Append a fixed-size byte array to a buffer.
Definition wire.h:124
void PutU8(std::vector< std::uint8_t > &out, std::uint8_t value)
Append a single byte to a buffer.
Definition wire.h:89
void PutU16(std::vector< std::uint8_t > &out, std::uint16_t value)
Append a 16-bit value to a buffer in big-endian order.
Definition wire.h:97
void PutU32(std::vector< std::uint8_t > &out, std::uint32_t value)
Append a 32-bit value to a buffer in big-endian order.
Definition wire.h:105
BlockType
PROFINET block types.
Definition indices.h:89
TEST_F(AlarmListenerTests, InitializesWithEndpoint)
constexpr std::uint16_t SUBMODULE_STATE_WRONG_SUBMODULE
Submodule State Wrong Submodule.
Definition indices.h:652
constexpr std::uint16_t MODULE_STATE_PROPER_MODULE
Module State Proper Module.
Definition indices.h:645
constexpr std::uint16_t WRITE_MULTIPLE
Write Multiple.
Definition indices.h:976
constexpr std::uint16_t SUBMODULE_STATE_OK
Submodule State Ok.
Definition indices.h:658
std::vector< std::uint8_t > Bytes
Generic byte buffer alias used throughout the library for raw wire data.
Definition protocol.h:55
LLDP peer information from PDPortDataReal.
Definition blocks.h:93
std::string portId
Peer's LLDP port ID.
Definition blocks.h:95
Generic helpers for reading and writing integer and byte data in big- and little-endian wire formats.