|
PROFINET IO Controller Stack 1.0.0
Modern C++ implementation of a PROFINET IO Controller stack
|
Background listener for PROFINET alarm notifications. More...
#include <alarmListener.h>
Inheritance diagram for profinet::AlarmListener:
Collaboration diagram for profinet::AlarmListener:Public Member Functions | |
| AlarmListener (asio::io_context &ioContext, AlarmEndpoint endpoint, std::optional< MacAddress > controllerMac=std::nullopt) | |
| Construct a listener for the given endpoint. | |
| ~AlarmListener () override | |
| Stop (if running) and release resources. | |
| AlarmListener (const AlarmListener &)=delete | |
| Not copyable (owns a socket and background thread). | |
| AlarmListener & | operator= (const AlarmListener &)=delete |
| Not copyable (owns a socket and background thread). | |
| void | AddAlarmNotificationCallback (std::function< void(const AlarmNotification &)> callback) override |
| Register a callback for received alarms. | |
| void | RemoveAlarmNotificationCallback (std::function< void(const AlarmNotification &)> callback) override |
| Remove a registered (alarm notification) callback. | |
| void | AddRtaAlarmCallback (std::function< void(const RtaError &)> callback) override |
| Register a callback for received alarms. | |
| void | RemoveRtaAlarmCallback (std::function< void(const RtaError &)> callback) override |
| Remove a registered (rta alarm) callback. | |
| void | Start (std::unique_ptr< IRawEthernetSocket > eSocket=nullptr, std::unique_ptr< IUdpSocket > uSocket=nullptr) override |
| Start the background listener (socket + thread). | |
| void | Stop () override |
| Stop the listener. | |
| bool | IsRunning () const override |
| Whether the listener thread is currently running. | |
Public Member Functions inherited from profinet::IAlarmListener | |
| virtual | ~IAlarmListener ()=default |
| Virtual destructor. | |
Private Member Functions | |
| void | ListenLoop () |
| Listener thread body: dispatches to the Layer 2 or UDP handler. | |
| void | HandleLayer2Frame () |
| Receive and process one Layer 2 (RTA-PDU) frame. | |
| void | HandleUdpFrame () |
| Receive and process one UDP frame. | |
| void | ProcessAlarm (const Bytes &payload, std::optional< bool > highPriority, std::optional< MacAddress > srcMac, std::optional< UdpEndpoint > udpSource) |
| Parse an alarm payload and dispatch it to registered callbacks. | |
| void | SendRtaFrame (std::uint8_t pduType, std::uint8_t addFlags, const Bytes &ackData, const MacAddress &dstMac, bool highPriority) |
| Build and send an RTA PDU (Layer 2); returns the frame bytes. | |
| void | SendAck (const AlarmNotification &alarm, std::optional< MacAddress > srcMac, std::optional< UdpEndpoint > udpSource) |
| Build and send an AlarmAck-PDU for a received notification. | |
| void | SendTransportAck (std::optional< MacAddress > srcMac, bool highPriority) |
| Send a pure RTA-ACK (TACK) with empty var part. | |
| void | SendNack (std::optional< MacAddress > srcMac, bool highPriority) |
| Send an RTA-NACK for an out-of-sequence DATA PDU. | |
| void | SendLayer2Ack (const Bytes &ackData, const MacAddress &dstMac, bool highPriority) |
| Send an AlarmAck-PDU over the Layer 2 transport. | |
| void | SendUdpAck (const Bytes &ackData, const UdpEndpoint &dstAddr) |
| Send an AlarmAck-PDU over the UDP transport. | |
Private Attributes | |
| asio::io_context & | ioContext |
| Asio execution context used by the Layer-2 socket. | |
| AlarmEndpoint | endpoint |
| Alarm endpoint configuration. | |
| MacAddress | controllerMac {} |
| This host's MAC address. | |
| std::atomic< bool > | running {false} |
| Whether the listener thread should keep running. | |
| std::jthread | thread |
| Background thread receiving and processing alarms. | |
| std::mutex | callbacksMutex |
| Protects concurrent access to callbacks. | |
| std::vector< std::function< void(const AlarmNotification &)> > | alarmNotificationCallbacks |
| Registered callbacks invoked for successfully parsed alarmsnotifications. | |
| std::vector< std::function< void(const RtaError &)> > | rtaAlarmCallbacks |
| Registered callbacks invoked for successfully parsed rta alarms. | |
| std::uint16_t | sendSeqNum = 0 |
| Sequence number for outgoing AlarmAck-PDUs. | |
| std::uint16_t | recvSeqNum = 0 |
| Last received sequence number, for duplicate detection. | |
| std::unique_ptr< IRawEthernetSocket > | l2Sock |
| Raw Ethernet transport used for Layer 2 alarm reception. | |
| std::unique_ptr< IUdpSocket > | udpSock |
| UDP transport used for UDP alarm reception and acknowledgement. | |
| std::mutex | lifecycleMutex |
| Guards lifecycle steps of listener against concurrent access. | |
Friends | |
| class | AlarmListenerTestAccess |
| Test fixture for AlarmListener private access in unit tests. | |
Background listener for PROFINET alarm notifications.
Example:
Definition at line 78 of file alarmListener.h.
|
explicit |
Construct a listener for the given endpoint.
Creates a listener for the supplied AlarmCR endpoint. When a Layer 2 transport is configured, an optional Ethernet socket may be supplied. This dependency-injection mechanism allows alarm processing to be tested without accessing a physical network interface.
| ioContext | Asio execution context. |
| endpoint | Alarm endpoint configuration. |
| controllerMac | This host's MAC address (required for the Layer 2 transport). |
Definition at line 17 of file alarmListener.cpp.
|
override |
Stop (if running) and release resources.
Definition at line 24 of file alarmListener.cpp.
References Stop().
Here is the call graph for this function:
|
delete |
Not copyable (owns a socket and background thread).
|
overridevirtual |
Register a callback for received alarms.
The callback is invoked from the listener thread for each successfully parsed alarm notification.
Multiple callbacks may be registered. Registration is thread-safe and may be performed while the listener is running.
| callback | Invoked from the listener thread for each successfully parsed alarm. |
Implements profinet::IAlarmListener.
Definition at line 29 of file alarmListener.cpp.
References alarmNotificationCallbacks, and callbacksMutex.
|
overridevirtual |
Register a callback for received alarms.
The callback is invoked from the listener thread for each successfully parsed RTA alarm.
Multiple callbacks may be registered. Registration is thread-safe and may be performed while the listener is running.
| callback | Invoked from the listener thread for each successfully parsed alarm. |
Implements profinet::IAlarmListener.
Definition at line 64 of file alarmListener.cpp.
References callbacksMutex, and rtaAlarmCallbacks.
|
private |
Receive and process one Layer 2 (RTA-PDU) frame.
Definition at line 197 of file alarmListener.cpp.
References profinet::AlarmEndpoint::deviceMac, endpoint, profinet::ETHERTYPE_PROFINET, profinet::FRAME_ID_ALARM_HIGH, profinet::FRAME_ID_ALARM_LOW, frameId, l2Sock, profinet::macAddressLength, ProcessAlarm(), profinet::wire::Reader::SkipTo(), profinet::SkipVlanTags(), and profinet::wire::Reader::U16().
Referenced by profinet::AlarmListenerTestAccess::HandleLayer2Frame(), and ListenLoop().
Here is the call graph for this function:
Here is the caller graph for this function:
|
private |
Receive and process one UDP frame.
Definition at line 259 of file alarmListener.cpp.
References profinet::UdpDatagram::data, ProcessAlarm(), profinet::RECEIVE_BUFFER_LENGTH, profinet::UdpDatagram::source, and udpSock.
Referenced by ListenLoop().
Here is the call graph for this function:
Here is the caller graph for this function:
|
inlineoverridevirtual |
Whether the listener thread is currently running.
Implements profinet::IAlarmListener.
Definition at line 160 of file alarmListener.h.
References running.
|
private |
Listener thread body: dispatches to the Layer 2 or UDP handler.
Definition at line 164 of file alarmListener.cpp.
References endpoint, HandleLayer2Frame(), HandleUdpFrame(), running, and profinet::AlarmEndpoint::transport.
Referenced by Start().
Here is the call graph for this function:
Here is the caller graph for this function:
|
delete |
Not copyable (owns a socket and background thread).
|
private |
Parse an alarm payload and dispatch it to registered callbacks.
| payload | Raw alarm notification payload. |
| highPriority | Whether this arrived on the high-priority path, if known. |
| srcMac | Sender's MAC address, for the Layer 2 transport. |
| udpSource | Source UDP endpoint. |
Definition at line 275 of file alarmListener.cpp.
References profinet::PNRTAHeader::ADD_FLAGS_TACK, profinet::PNRTAHeader::addFlags, profinet::PNRTAHeader::alarmDstEndpoint, alarmNotificationCallbacks, callbacksMutex, profinet::AlarmEndpoint::controllerRef, endpoint, error, profinet::PNRTAHeader::Parse(), profinet::ParseAlarmNotification(), profinet::ParseRtaError(), payload, profinet::PNRTAHeader::pduType, recvSeqNum, rtaAlarmCallbacks, SendAck(), profinet::PNRTAHeader::sendSeqNum, SendTransportAck(), profinet::AlarmEndpoint::transport, and profinet::PNRTAHeader::VERSION_1.
Referenced by HandleLayer2Frame(), and HandleUdpFrame().
Here is the call graph for this function:
Here is the caller graph for this function:
|
overridevirtual |
Remove a registered (alarm notification) callback.
| callback | Previously registered callback to remove. |
Implements profinet::IAlarmListener.
Definition at line 40 of file alarmListener.cpp.
References alarmNotificationCallbacks, and callbacksMutex.
|
overridevirtual |
Remove a registered (rta alarm) callback.
| callback | Previously registered callback to remove. |
Implements profinet::IAlarmListener.
Definition at line 74 of file alarmListener.cpp.
References callbacksMutex, and rtaAlarmCallbacks.
|
private |
Build and send an AlarmAck-PDU for a received notification.
| alarm | The notification being acknowledged. |
| srcMac | Sender's MAC address, for the Layer 2 transport. |
| updSource | Source UDP endpoint. |
Definition at line 399 of file alarmListener.cpp.
References profinet::AlarmAcknowledgementHigh, profinet::AlarmAcknowledgementLow, profinet::AlarmNotification::alarmSequenceNumber, profinet::AlarmSequenceNumber, profinet::PNAlarmAckPDU::alarmSpecifier, profinet::AlarmNotification::alarmType, profinet::PNAlarmAckPDU::alarmType, profinet::AlarmNotification::api, profinet::PNAlarmAckPDU::api, profinet::AlarmNotification::arDiagnosisState, profinet::ArDiagnosisState, profinet::PNAlarmAckPDU::blockHeader, profinet::blockHeaderLength, profinet::PNBlockHeader::blockLength, profinet::PNBlockHeader::blockType, profinet::PNBlockHeader::blockVersionHigh, profinet::PNBlockHeader::blockVersionLow, profinet::AlarmNotification::channelDiagnosis, profinet::ChannelDiagnosis, profinet::AlarmEndpoint::deviceMac, endpoint, profinet::AlarmNotification::IsHighPriority(), profinet::PNAlarmAckPDU::kSize, profinet::AlarmNotification::manufacturerSpecific, profinet::ManufacturerSpecific, profinet::None, SendLayer2Ack(), SendUdpAck(), profinet::AlarmNotification::slotNumber, profinet::PNAlarmAckPDU::slotNumber, profinet::PNAlarmAckPDU::statusPNIO, profinet::AlarmNotification::submoduleDiagnosisState, profinet::SubmoduleDiagnosisState, profinet::AlarmNotification::subslotNumber, profinet::PNAlarmAckPDU::subslotNumber, profinet::PNBlockHeader::ToBytes(), profinet::PNAlarmAckPDU::ToBytes(), and profinet::AlarmEndpoint::transport.
Referenced by ProcessAlarm().
Here is the call graph for this function:
Here is the caller graph for this function:
|
private |
Send an AlarmAck-PDU over the Layer 2 transport.
| ackData | Serialized AlarmAck-PDU. |
| dstMac | Destination MAC address. |
| highPriority | Whether to use the high-priority frame ID. |
Definition at line 442 of file alarmListener.cpp.
References profinet::PNRTAHeader::ADD_FLAGS_TACK, profinet::PNRTAHeader::ADD_FLAGS_WINDOW_1, profinet::PNRTAHeader::RTA_TYPE_DATA, and SendRtaFrame().
Referenced by SendAck().
Here is the call graph for this function:
Here is the caller graph for this function:
|
private |
Send an RTA-NACK for an out-of-sequence DATA PDU.
| srcMac | Sender's MAC address, for the Layer 2 transport. |
| highPriority | Whether to use the high-priority frame ID. |
Definition at line 392 of file alarmListener.cpp.
References profinet::PNRTAHeader::ADD_FLAGS_WINDOW_1, profinet::AlarmEndpoint::deviceMac, endpoint, profinet::PNRTAHeader::RTA_TYPE_NACK, and SendRtaFrame().
Here is the call graph for this function:
|
private |
Build and send an RTA PDU (Layer 2); returns the frame bytes.
| pduType | PDU type. |
| addFlags | Additional flags (window size, TACK flag). |
| ackData | Serialized AlarmAck-PDU. |
| dstMac | Destination MAC address. |
| highPriority | Whether to use the high-priority frame ID. |
Definition at line 449 of file alarmListener.cpp.
References profinet::PNRTAHeader::ackSeqNum, profinet::PNRTAHeader::addFlags, addFlags, profinet::PNRTAHeader::alarmDstEndpoint, profinet::PNRTAHeader::alarmSrcEndpoint, controllerMac, profinet::AlarmEndpoint::controllerRef, profinet::AlarmEndpoint::deviceRef, endpoint, profinet::ETHERTYPE_PROFINET, frame, profinet::FRAME_ID_ALARM_HIGH, profinet::FRAME_ID_ALARM_LOW, frameId, l2Sock, profinet::PNRTAHeader::pduType, profinet::wire::PutBigEndian(), recvSeqNum, sendSeqNum, profinet::PNRTAHeader::sendSeqNum, profinet::PNRTAHeader::ToBytes(), profinet::PNRTAHeader::variablePartLenght, and profinet::PNRTAHeader::VERSION_1.
Referenced by SendLayer2Ack(), SendNack(), and SendTransportAck().
Here is the call graph for this function:
Here is the caller graph for this function:
|
private |
Send a pure RTA-ACK (TACK) with empty var part.
| srcMac | Sender's MAC address, for the Layer 2 transport. |
| highPriority | Whether to use the high-priority frame ID. |
Definition at line 385 of file alarmListener.cpp.
References profinet::PNRTAHeader::ADD_FLAGS_WINDOW_1, profinet::AlarmEndpoint::deviceMac, endpoint, profinet::PNRTAHeader::RTA_TYPE_ACK, and SendRtaFrame().
Referenced by ProcessAlarm().
Here is the call graph for this function:
Here is the caller graph for this function:
|
private |
Send an AlarmAck-PDU over the UDP transport.
| ackData | Serialized AlarmAck-PDU. |
| dstAddr | Destination UDP endpoint. |
Definition at line 497 of file alarmListener.cpp.
References udpSock.
Referenced by SendAck().
Here is the caller graph for this function:
|
overridevirtual |
Start the background listener (socket + thread).
No-op if already running. Throws PermissionDeniedError if a raw socket needs elevated privilege.
| eSocket | Optional Layer 2 Ethernet transport for l2Sock. When omitted, Start() creates the production EthernetSocket for l2Sock. |
| uSocket | Optional UDP transport. |
| PermissionDeniedError | When the selected production transport cannot be created because of insufficient operating-system permissions. |
| SocketError | When the selected transport cannot be initialized. |
Implements profinet::IAlarmListener.
Definition at line 98 of file alarmListener.cpp.
References profinet::ALARM_UDP_PORT, endpoint, profinet::ETHERTYPE_PROFINET, profinet::AlarmEndpoint::interface, ioContext, l2Sock, lifecycleMutex, ListenLoop(), running, thread, profinet::AlarmEndpoint::transport, and udpSock.
Here is the call graph for this function:
|
overridevirtual |
Stop the listener.
Closes the socket (to unblock recv) and joins the thread.
Implements profinet::IAlarmListener.
Definition at line 144 of file alarmListener.cpp.
References l2Sock, lifecycleMutex, running, thread, and udpSock.
Referenced by ~AlarmListener().
Here is the caller graph for this function:
|
friend |
Test fixture for AlarmListener private access in unit tests.
Definition at line 82 of file alarmListener.h.
|
private |
Registered callbacks invoked for successfully parsed alarmsnotifications.
Access to this collection is protected by callbacksMutex. Callbacks are copied before invocation so application callback code executes without holding the mutex.
Definition at line 244 of file alarmListener.h.
Referenced by AddAlarmNotificationCallback(), profinet::AlarmListenerTestAccess::CallbackCount(), ProcessAlarm(), and RemoveAlarmNotificationCallback().
|
mutableprivate |
Protects concurrent access to callbacks.
Definition at line 236 of file alarmListener.h.
Referenced by AddAlarmNotificationCallback(), AddRtaAlarmCallback(), ProcessAlarm(), RemoveAlarmNotificationCallback(), and RemoveRtaAlarmCallback().
|
private |
This host's MAC address.
Definition at line 227 of file alarmListener.h.
Referenced by profinet::AlarmListenerTestAccess::ControllerMac(), and SendRtaFrame().
|
private |
Alarm endpoint configuration.
Definition at line 224 of file alarmListener.h.
Referenced by HandleLayer2Frame(), ListenLoop(), ProcessAlarm(), SendAck(), SendNack(), SendRtaFrame(), SendTransportAck(), and Start().
|
private |
Asio execution context used by the Layer-2 socket.
Definition at line 221 of file alarmListener.h.
Referenced by Start().
|
private |
Raw Ethernet transport used for Layer 2 alarm reception.
When null, Start() creates the production EthernetSocket. Unit tests can provide a MockRawEthernetSocket through the constructor.
Layer 2 path uses EthernetSocket; UDP path manages its own fd directly (needs bind-to-wildcard + recvfrom, which EthernetSocket / UdpSocket don't support – same rationale as RPCCon's CControl listener).
Definition at line 270 of file alarmListener.h.
Referenced by HandleLayer2Frame(), SendRtaFrame(), profinet::AlarmListenerTestAccess::SetSock(), Start(), and Stop().
|
mutableprivate |
Guards lifecycle steps of listener against concurrent access.
Definition at line 280 of file alarmListener.h.
|
private |
Last received sequence number, for duplicate detection.
Definition at line 258 of file alarmListener.h.
Referenced by ProcessAlarm(), and SendRtaFrame().
|
private |
Registered callbacks invoked for successfully parsed rta alarms.
Access to this collection is protected by callbacksMutex. Callbacks are copied before invocation so application callback code executes without holding the mutex.
Definition at line 252 of file alarmListener.h.
Referenced by AddRtaAlarmCallback(), ProcessAlarm(), and RemoveRtaAlarmCallback().
|
private |
Whether the listener thread should keep running.
Definition at line 230 of file alarmListener.h.
Referenced by IsRunning(), ListenLoop(), Start(), and Stop().
|
private |
Sequence number for outgoing AlarmAck-PDUs.
Definition at line 255 of file alarmListener.h.
Referenced by SendRtaFrame().
|
private |
Background thread receiving and processing alarms.
Definition at line 233 of file alarmListener.h.
|
private |
UDP transport used for UDP alarm reception and acknowledgement.
When null, Start() creates a production UdpSocket bound to ALARM_UDP_PORT. Tests can provide a mock implementation.
Definition at line 277 of file alarmListener.h.
Referenced by HandleUdpFrame(), SendUdpAck(), Start(), and Stop().