10#include <gtest/gtest.h>
33constexpr char kAumaGsdml[] =
"GSDML-V2.42-AUMA-SGX-20220920.xml";
34constexpr char kPhoenixGsdml[] =
"GSDML-V2.45-Phoenix Contact-AXC F 1252-20250813.xml";
37std::string GetGsdmlLocation(
const std::string& fileName)
39 const std::array<std::filesystem::path, 4> candidates{
42 std::filesystem::current_path() /
"tests" /
"gsdml" / fileName,
43 std::filesystem::current_path() /
"gsdml" / fileName};
45 for (
const auto& candidate : candidates)
47 if (std::filesystem::exists(candidate))
49 return candidate.string();
53 ADD_FAILURE() <<
"GSDML fixture not found: " << fileName;
58std::string AumaGsdmlPath()
60 return GetGsdmlLocation(kAumaGsdml);
65std::string PhoenixGsdmlPath()
67 return GetGsdmlLocation(kPhoenixGsdml);
74bool WaitUntil(
const std::function<
bool()>& predicate,
75 const std::chrono::milliseconds timeout = std::chrono::milliseconds(1000))
77 const auto deadline = std::chrono::steady_clock::now() + timeout;
78 while (std::chrono::steady_clock::now() < deadline)
84 std::this_thread::sleep_for(std::chrono::milliseconds(5));
92TEST(VirtualRealGsdmlIntegrationTests, ParsesRealAumaGsdmlAndBuildsSignalCatalog)
94 const std::string path = AumaGsdmlPath();
97 GTEST_SKIP() <<
"Set PROFINET_AUMA_GSDML to run the real AUMA integration test";
101 EXPECT_EQ(device.vendorId, 0x013FU);
102 EXPECT_EQ(device.deviceId, 0x0002U);
105 EXPECT_NE(std::find_if(catalog.Sensors().begin(), catalog.Sensors().end(),
106 [](
const auto& signal)
107 { return signal.textId ==
"T_ID_ACTPOS_E2"; }),
108 catalog.Sensors().end());
109 EXPECT_NE(std::find_if(catalog.Actuators().begin(), catalog.Actuators().end(),
110 [](
const auto& signal)
111 { return signal.textId ==
"T_ID_CMD_0"; }),
112 catalog.Actuators().end());
116TEST(VirtualRealGsdmlIntegrationTests, ParsesRealPhoenixGsdmlAndBuildsSignalCatalog)
118 const std::string path = PhoenixGsdmlPath();
121 GTEST_SKIP() <<
"Set PROFINET_PHOENIX_GSDML to run the real Phoenix integration test";
125 EXPECT_EQ(device.vendorId, 0x00B0U);
126 EXPECT_EQ(device.deviceId, 0x0193U);
129 EXPECT_FALSE(catalog.Sensors().empty());
130 EXPECT_FALSE(catalog.Actuators().empty());
134TEST(VirtualRealGsdmlIntegrationTests, RunsRealAumaAndPhoenixThroughCyclicController)
136 const std::string aumaPath = AumaGsdmlPath();
137 const std::string phoenixPath = PhoenixGsdmlPath();
138 if (aumaPath.empty() || phoenixPath.empty())
140 GTEST_SKIP() <<
"Set both PROFINET_AUMA_GSDML and PROFINET_PHOENIX_GSDML";
149 iocrs.input, iocrs.output);
153 auto controllerIocrs = iocrs;
160 controllerIocrs.input,
161 controllerIocrs.output,
164 ASSERT_TRUE(WaitUntil([&plc]
167 return stats.has_value() && stats->framesReceived >= 3U;
170 plc.
SetOutput(
"auma-real",
"T_ID_CMD_0", 1.0);
172 ASSERT_TRUE(WaitUntil([&valve]
177 const auto actualPosition = plc.
ReadInput(
"auma-real",
"T_ID_ACTPOS_E2");
178 ASSERT_TRUE(actualPosition.has_value());
179 EXPECT_GT(*actualPosition, 0.0);
Declares PROFINET alarm, diagnosis, maintenance, and USI payload types and parsers.
Keeps an Asio I/O context running on a dedicated worker thread.
static IoSignalCatalog FromGsdml(const gsdml::GSDMLDevice &device)
Build a signal catalogue from a parsed GSDML device.
Small virtual Ethernet switch suitable for deterministic tests and demos.
AUMA SGx application model that behaves as a real RTC1 peer in memory.
void Stop()
Stop cyclic simulation.
void Start(InMemoryEthernetBus &bus)
Attach the device to a shared virtual Ethernet bus and start cyclic processing.
std::uint16_t Position() const noexcept
Return the current simulated position.
Virtual Phoenix Contact AXC F 1252 controller hosting real CyclicController instances.
std::optional< double > ReadInput(const std::string &valveName, std::string_view signalTextId) const
Read a typed AUMA input signal using the production controller API.
void SetOutput(const std::string &valveName, std::string_view signalTextId, double value)
Set a typed AUMA actuator signal.
void Stop()
Stop all active connections.
void Connect(asio::io_context &ioContext, InMemoryEthernetBus &bus, VirtualAumaValve &valve, rt::IOCRConfig inputIocr, rt::IOCRConfig outputIocr, int maxConsecutiveTimeouts=cyclic::DEFAULT_MAX_CONSECUTIVE_TIMEOUTS)
Connect the PLC to one virtual AUMA device.
std::optional< cyclic::CyclicStatsSnapshot > ConnectionStats(const std::string &valveName) const
Return one connection statistics snapshot.
Declares the GSDML parser and PROFINET device-description data model.
GSDMLDevice ParseGsdml(const std::string &path)
Parse a GSDML file into a GSDMLDevice.
constexpr MacAddress kControllerMac
constexpr MacAddress kValveMac
bool WaitUntil(const std::function< bool()> &predicate, std::chrono::milliseconds timeout=std::chrono::milliseconds(500))
Wait until a predicate becomes true or the timeout expires.
TEST(InMemoryEthernetRoutingTests, UnicastReachesOnlyMatchingEndpoint)
VirtualAumaIocrConfiguration MakeVirtualAumaIocrConfiguration(const gsdml::GSDMLDevice &device, std::uint16_t inputFrameId=0x9000, std::uint16_t outputFrameId=0x8001, std::uint16_t sendClockFactor=32, std::uint16_t reductionRatio=8, std::uint16_t watchdogFactor=3, std::uint16_t dataHoldFactor=3)
Build the standard two-module AUMA SGx process-data layout from its GSDML.
std::filesystem::path GetExecutableDirectory()
Retrieves the absolute directory path of the currently running executable.
std::unique_ptr< asio::io_context > ioContext
Shared ASIO context.
Helpers for constructing a GSDML-derived AUMA SGx RTC1 test configuration.
Stateful in-memory AUMA SGx PROFINET IO device simulator.
In-memory Phoenix Contact AXC F 1252 PLC/controller simulator.
Shared synthetic GSDML and timing helpers for virtual PROFINET tests.