27 throw std::invalid_argument(
"AUMA simulator MAC address is already in use: " +
31 { return entry.name == name; }))
33 throw std::invalid_argument(
"AUMA simulator name already exists: " + name);
35 auto valve = std::make_unique<VirtualAumaValve>(
40 std::move(outputIocr),
43 valves.push_back({std::move(name), std::move(valve)});
44 return *
valves.back().valve;
53 throw std::invalid_argument(
"Phoenix simulator MAC address is already in use: " +
57 { return entry.name == name; }))
59 throw std::invalid_argument(
"Phoenix simulator name already exists: " + name);
61 auto plc = std::make_unique<VirtualPhoenixPlc>(name, gsdml, controllerMac);
62 plcs.push_back({std::move(name), std::move(plc)});
63 return *
plcs.back().plc;
67 const std::string& plcName,
68 const std::string& valveName,
71 const int maxConsecutiveTimeouts)
77 std::move(outputIocr),
78 maxConsecutiveTimeouts);
95 { return entry.name == name; });
98 throw std::invalid_argument(
"Unknown AUMA simulator: " + name);
105 const auto it = std::find_if(
plcs.begin(),
plcs.end(), [&name](
const PlcEntry& entry)
106 { return entry.name == name; });
107 if (it ==
plcs.end())
109 throw std::invalid_argument(
"Unknown Phoenix simulator: " + name);
117 { return entry.name == name; });
120 throw std::invalid_argument(
"Unknown AUMA simulator: " + name);
127 const auto it = std::find_if(
plcs.begin(),
plcs.end(), [&name](
const PlcEntry& entry)
128 { return entry.name == name; });
129 if (it ==
plcs.end())
131 throw std::invalid_argument(
"Unknown Phoenix simulator: " + name);
138 std::vector<std::string> result;
139 result.reserve(
valves.size());
140 for (
const auto& valve :
valves)
142 result.push_back(valve.name);
149 std::vector<std::string> result;
150 result.reserve(
plcs.size());
151 for (
const auto& plc :
plcs)
153 result.push_back(plc.name);
160 std::ostringstream out;
161 out <<
"============================================================\n";
162 out <<
" VIRTUAL PROFINET LAB\n";
163 out <<
"============================================================\n";
165 out <<
"Virtual AUMA valves: " <<
valves.size() <<
'\n';
166 for (
const auto& valve :
valves)
168 out <<
" AUMA " << valve.name
169 <<
" MAC=" <<
Mac2String(valve.valve->DeviceMac())
170 <<
" scenario=" <<
ToString(valve.valve->Scenario())
171 <<
" pos=" << valve.valve->Position()
172 <<
" target=" << valve.valve->TargetPosition()
173 <<
" moving=" << (valve.valve->Moving() ?
"yes" :
"no")
176 out <<
"Virtual Phoenix PLCs: " <<
plcs.size() <<
'\n';
177 for (
const auto& plc :
plcs)
179 out << plc.plc->StatusReport();
181 out <<
"============================================================\n";
187 for (
const auto& entry : valves)
189 if (entry.valve !=
nullptr && entry.valve->DeviceMac() == mac)
194 for (
const auto& entry : plcs)
196 if (entry.plc !=
nullptr && entry.plc->ControllerMac() == mac)
206 for (
auto& plc :
plcs)
208 if (plc.plc !=
nullptr)
213 for (
auto& valve :
valves)
215 if (valve.valve !=
nullptr)
Small virtual Ethernet switch suitable for deterministic tests and demos.
std::size_t EndpointCount() const
Return the number of currently connected socket endpoints.
AUMA SGx application model that behaves as a real RTC1 peer in memory.
void SetScenario(VirtualAumaScenario scenario)
Set the current simulator scenario.
Virtual Phoenix Contact AXC F 1252 controller hosting real CyclicController instances.
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.
void SetAumaScenario(const std::string &valveName, VirtualAumaScenario scenario)
Set one valve scenario.
std::vector< AumaEntry > valves
std::vector< PlcEntry > plcs
std::vector< std::string > PlcNames() const
Return all PLC names.
VirtualPhoenixPlc & AddPhoenixPlc(std::string name, const gsdml::GSDMLDevice &gsdml, MacAddress controllerMac)
Add one Phoenix AXC F 1252 controller instance.
std::string StatusReport() const
Render a compact multi-device status dashboard.
InMemoryEthernetBus & Bus() noexcept
Return the shared virtual bus.
VirtualPhoenixPlc & Plc(const std::string &name)
Find a PLC by name.
void Stop()
Stop all devices and controllers.
bool IsMacInUse(const MacAddress &mac) const noexcept
Determine whether a node MAC is already used by this lab.
VirtualAumaValve & Valve(const std::string &name)
Find a valve by name.
void Connect(asio::io_context &ioContext, const std::string &plcName, const std::string &valveName, rt::IOCRConfig inputIocr, rt::IOCRConfig outputIocr, int maxConsecutiveTimeouts=cyclic::DEFAULT_MAX_CONSECUTIVE_TIMEOUTS)
Connect a PLC to an AUMA valve.
VirtualAumaValve & AddAumaValve(std::string name, const gsdml::GSDMLDevice &gsdml, MacAddress deviceMac, rt::IOCRConfig inputIocr, rt::IOCRConfig outputIocr, VirtualAumaValveConfiguration config={})
Add one AUMA valve instance.
std::vector< std::string > ValveNames() const
Return all valve names.
VirtualAumaScenario
Deterministic operating and communication scenarios for a virtual AUMA valve.
const char * ToString(VirtualAumaScenario scenario) noexcept
Convert a virtual AUMA scenario into its stable CLI spelling.
std::array< std::uint8_t, macAddressLength > MacAddress
A 6-byte Ethernet MAC address.
std::string Mac2String(const MacAddress &mac)
Format a MAC address as a colon-separated string.
Complete parsed GSDML device profile.
IOCR configuration derived from AR setup: timing parameters and IO object mappings needed for cyclic ...
Application-level signal mapping and motion settings for a virtual AUMA SGx.
std::unique_ptr< asio::io_context > ioContext
Shared ASIO context.
Multi-instance in-memory PROFINET laboratory.