31#include <condition_variable>
149 void Stop() noexcept;
155 [[nodiscard]] std::
size_t ConnectCount() const noexcept;
161 [[nodiscard]] std::
size_t PrmEndCount() const noexcept;
170 [[nodiscard]] std::
size_t ReleaseCount() const noexcept;
182 [[nodiscard]]
bool SawAlarmCr() const noexcept;
185 [[nodiscard]] std::
string LastError() const;
193 std::chrono::milliseconds timeout) const;
196 [[nodiscard]] std::uint16_t
RpcPort() const noexcept;
206 const asio::ip::udp::endpoint& sender);
210 const asio::ip::udp::endpoint& sender);
214 const asio::ip::udp::endpoint& sender);
226 const
Bytes& nrdPayload,
227 const asio::ip::udp::endpoint& sender);
237 const
Bytes& nrdPayload);
252 const
Bytes& connectPayload,
271 std::unique_ptr<asio::ip::udp::socket>
socket;
287 std::array<std::uint8_t, uuidLenght>
arUuid{};
Stateful UDP PROFINET IO-Device protocol simulator.
static bool ContainsBlock(const Bytes &data, BlockType blockType)
Find a block type in a serialized CONNECT payload.
void WakeWorker() noexcept
Wake the synchronous receive so the worker can observe shutdown.
std::size_t PrmEndCount() const noexcept
Return the number of PrmEnd requests accepted.
std::array< std::uint8_t, uuidLenght > arUuid
std::size_t PrmBeginCount() const noexcept
Return the number of PrmBegin requests accepted.
void ScheduleApplicationReady()
Start a cancellable ApplicationReady delay.
void SendApplicationReady()
Send a device-originated ApplicationReady request.
std::uint16_t RpcPort() const noexcept
Return the configured device RPC port.
std::size_t prmBeginCount
std::unique_ptr< asio::ip::udp::socket > socket
std::size_t ApplicationReadyResponseCount() const noexcept
Return the number of ApplicationReady responses accepted.
std::optional< asio::ip::udp::endpoint > controllerEndpoint
void Stop() noexcept
Stop listening and join the worker thread.
void Start()
Start listening for controller RPC packets.
std::atomic< bool > running
VirtualProfinetRpcDevice & operator=(const VirtualProfinetRpcDevice &)=delete
static Bytes MakeAlarmCrResponse(std::uint16_t deviceAlarmReference)
Build a minimal successful AlarmCRBlockRes.
std::condition_variable stateCondition
void Run()
Worker loop receiving controller datagrams.
std::thread applicationReadyWorker
Delayed ApplicationReady worker.
std::optional< PNRPCHeader > lastApplicationReadyRequest
std::unique_ptr< asio::io_context > ioContext
std::size_t applicationReadyRequestCount
bool SawInputIocr() const noexcept
Return whether the controller supplied an Input IOCR.
void HandleApplicationReadyResponse(const PNRPCHeader &response)
Handle the response to the device-originated ApplicationReady.
bool sawExpectedSubmodules
void HandleControl(const PNRPCHeader &request, const asio::ip::udp::endpoint &sender)
Handle a CONTROL request such as PrmBegin or PrmEnd.
VirtualProfinetRpcDevice(const VirtualProfinetRpcDevice &)=delete
std::size_t applicationReadyResponseCount
std::size_t ConnectCount() const noexcept
Return the number of CONNECT requests accepted.
~VirtualProfinetRpcDevice()
Stop the simulator.
std::size_t ApplicationReadyRequestCount() const noexcept
Return the number of ApplicationReady requests sent.
static void ParseArIdentity(const Bytes &connectPayload, std::array< std::uint8_t, uuidLenght > &arUuid, std::uint16_t &sessionKey)
Parse the AR UUID and session key from a CONNECT request.
VirtualProfinetDeviceState State() const noexcept
Return the current protocol state.
static Bytes MakeIocrResponse(const PNIOCRBlockReqHeader &request, std::uint16_t frameId)
Build one IOCRBlockRes from a controller IOCR request.
std::string LastError() const
Return the last diagnostic/rejection text.
VirtualProfinetDeviceConfiguration config
bool ValidateConnect(const Bytes &nrdPayload)
Validate and extract the CONNECT blocks.
void HandlePacket(const PNRPCHeader &request, const asio::ip::udp::endpoint &sender)
Dispatch one complete RPC packet.
VirtualProfinetDeviceState state
void SendResponse(const PNRPCHeader &request, const Bytes &nrdPayload, const asio::ip::udp::endpoint &sender)
Send a successful RPC response.
std::size_t ReleaseCount() const noexcept
Return the number of Release requests observed.
bool SawExpectedSubmodules() const noexcept
Return whether the controller supplied ExpectedSubmodule blocks.
static Bytes MakeNrd(const Bytes &payload)
Build an NRD wrapper with successful status.
void HandleConnect(const PNRPCHeader &request, const asio::ip::udp::endpoint &sender)
Handle a CONNECT request.
static PNRPCHeader MakeResponse(const PNRPCHeader &request, const Bytes &nrdPayload)
Build an RPC response preserving correlation fields.
bool SawAlarmCr() const noexcept
Return whether the controller supplied an AlarmCR.
bool SawOutputIocr() const noexcept
Return whether the controller supplied an Output IOCR.
bool WaitForState(VirtualProfinetDeviceState expected, std::chrono::milliseconds timeout) const
Wait until the simulator reaches a state.
constexpr std::uint16_t RPC_PORT
PROFINET IO RPC port (34964).
@ Fault
Application fault: movement stops, IOPS becomes BAD and alarms are emitted.
VirtualProfinetDeviceState
Observable Application Relation state of the virtual device.
@ ApplicationReady
The controller confirmed the device's ApplicationReady request.
@ Connected
A CONNECT was accepted and the AR is being configured.
@ Parameterizing
PrmBegin was accepted.
@ Parameterized
PrmEnd was accepted and the device can issue ApplicationReady.
@ Idle
No Application Relation exists.
@ Released
The controller released the AR.
const char * ToString(VirtualAumaScenario scenario) noexcept
Convert a virtual AUMA scenario into its stable CLI spelling.
BlockType
PROFINET block types.
constexpr int uuidLenght
Constant lenght of a UUID.
std::array< std::uint8_t, macAddressLength > MacAddress
A 6-byte Ethernet MAC address.
std::vector< std::uint8_t > Bytes
Generic byte buffer alias used throughout the library for raw wire data.
PROFINET protocol wire-format structures and serialization helpers.
PROFINET DCE/RPC protocol structures and IO-Device connection API.
Configuration for a controller-facing virtual PROFINET device.
bool requireExpectedSubmodules
Require ExpectedSubmoduleBlockReq in cyclic CONNECT requests.
std::chrono::milliseconds applicationReadyDelay
Delay between accepting PrmEnd and sending ApplicationReady.
std::uint16_t deviceId
PROFINET device identifier.
bool automaticApplicationReady
Automatically send ApplicationReady after PrmEnd.
std::uint16_t vendorId
PROFINET vendor identifier.
bool requireBothIocrs
Require an Input and Output IOCR when CONNECT contains cyclic data.
std::string stationName
Station name reported by the virtual device.
std::string controllerAddress
Controller loopback address used for ApplicationReady.
std::uint16_t outputFrameId
Frame ID returned for the output IOCR.
std::uint16_t inputFrameId
Frame ID returned for the input IOCR.
bool requireAlarmCr
Require AlarmCR when cyclic CONNECT is requested.
std::uint16_t controllerCcontrolPort
Controller CControl listener port used for ApplicationReady.
std::uint16_t rpcPort
UDP port on which the virtual device accepts controller RPC.
MacAddress deviceMac
Device MAC address used by the virtual device model.
std::uint16_t deviceAlarmReference
Alarm reference returned by the device when AlarmCR is supported.
std::uint16_t frameId
Ethernet FrameID.