PROFINET IO Controller Stack 1.0.0
Modern C++ implementation of a PROFINET IO Controller stack
Loading...
Searching...
No Matches
profinet::AlarmListener Class Reference

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.
 

Detailed Description

Background listener for PROFINET alarm notifications.

Example:

AlarmEndpoint ep{ifname, controller_ref, device_ref, device_mac};
AlarmListener listener(ep, my_mac);
listener.AddCallback([](const AlarmNotification& n) {
std::cout << n.AlarmTypeName() << " at " << n.Location() << "\n";
});
listener.Start();
// ...
listener.Stop();
Background listener for PROFINET alarm notifications.
Alarm endpoint configuration.
Complete parsed AlarmNotification PDU: header fields + parsed items.
Definition alarms.h:356
std::string Location() const
Location string identifying where the alarm originated.
Definition alarms.cpp:240
std::string AlarmTypeName() const
Human-readable name for AlarmType.
Definition alarms.h:418

Definition at line 78 of file alarmListener.h.

Constructor & Destructor Documentation

◆ AlarmListener() [1/2]

profinet::AlarmListener::AlarmListener ( asio::io_context &  ioContext,
AlarmEndpoint  endpoint,
std::optional< MacAddress >  controllerMac = std::nullopt 
)
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.

Parameters
ioContextAsio execution context.
endpointAlarm endpoint configuration.
controllerMacThis host's MAC address (required for the Layer 2 transport).

Definition at line 17 of file alarmListener.cpp.

◆ ~AlarmListener()

profinet::AlarmListener::~AlarmListener ( )
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:

◆ AlarmListener() [2/2]

profinet::AlarmListener::AlarmListener ( const AlarmListener &  )
delete

Not copyable (owns a socket and background thread).

Member Function Documentation

◆ AddAlarmNotificationCallback()

void profinet::AlarmListener::AddAlarmNotificationCallback ( std::function< void(const AlarmNotification &)>  callback)
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.

Parameters
callbackInvoked from the listener thread for each successfully parsed alarm.

Implements profinet::IAlarmListener.

Definition at line 29 of file alarmListener.cpp.

References alarmNotificationCallbacks, and callbacksMutex.

◆ AddRtaAlarmCallback()

void profinet::AlarmListener::AddRtaAlarmCallback ( std::function< void(const RtaError &)>  callback)
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.

Parameters
callbackInvoked from the listener thread for each successfully parsed alarm.

Implements profinet::IAlarmListener.

Definition at line 64 of file alarmListener.cpp.

References callbacksMutex, and rtaAlarmCallbacks.

◆ HandleLayer2Frame()

void profinet::AlarmListener::HandleLayer2Frame ( )
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:

◆ HandleUdpFrame()

void profinet::AlarmListener::HandleUdpFrame ( )
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:

◆ IsRunning()

bool profinet::AlarmListener::IsRunning ( ) const
inlineoverridevirtual

Whether the listener thread is currently running.

Returns
True if Start() has been called and Stop() has not.

Implements profinet::IAlarmListener.

Definition at line 160 of file alarmListener.h.

References running.

◆ ListenLoop()

void profinet::AlarmListener::ListenLoop ( )
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:

◆ operator=()

AlarmListener & profinet::AlarmListener::operator= ( const AlarmListener &  )
delete

Not copyable (owns a socket and background thread).

◆ ProcessAlarm()

void profinet::AlarmListener::ProcessAlarm ( const Bytes &  payload,
std::optional< bool >  highPriority,
std::optional< MacAddress >  srcMac,
std::optional< UdpEndpoint >  udpSource 
)
private

Parse an alarm payload and dispatch it to registered callbacks.

Parameters
payloadRaw alarm notification payload.
highPriorityWhether this arrived on the high-priority path, if known.
srcMacSender's MAC address, for the Layer 2 transport.
udpSourceSource 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:

◆ RemoveAlarmNotificationCallback()

void profinet::AlarmListener::RemoveAlarmNotificationCallback ( std::function< void(const AlarmNotification &)>  callback)
overridevirtual

Remove a registered (alarm notification) callback.

Parameters
callbackPreviously registered callback to remove.

Implements profinet::IAlarmListener.

Definition at line 40 of file alarmListener.cpp.

References alarmNotificationCallbacks, and callbacksMutex.

◆ RemoveRtaAlarmCallback()

void profinet::AlarmListener::RemoveRtaAlarmCallback ( std::function< void(const RtaError &)>  callback)
overridevirtual

Remove a registered (rta alarm) callback.

Parameters
callbackPreviously registered callback to remove.

Implements profinet::IAlarmListener.

Definition at line 74 of file alarmListener.cpp.

References callbacksMutex, and rtaAlarmCallbacks.

◆ SendAck()

void profinet::AlarmListener::SendAck ( const AlarmNotification &  alarm,
std::optional< MacAddress >  srcMac,
std::optional< UdpEndpoint >  udpSource 
)
private

Build and send an AlarmAck-PDU for a received notification.

Parameters
alarmThe notification being acknowledged.
srcMacSender's MAC address, for the Layer 2 transport.
updSourceSource 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:

◆ SendLayer2Ack()

void profinet::AlarmListener::SendLayer2Ack ( const Bytes &  ackData,
const MacAddress &  dstMac,
bool  highPriority 
)
private

Send an AlarmAck-PDU over the Layer 2 transport.

Parameters
ackDataSerialized AlarmAck-PDU.
dstMacDestination MAC address.
highPriorityWhether 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:

◆ SendNack()

void profinet::AlarmListener::SendNack ( std::optional< MacAddress >  srcMac,
bool  highPriority 
)
private

Send an RTA-NACK for an out-of-sequence DATA PDU.

Parameters
srcMacSender's MAC address, for the Layer 2 transport.
highPriorityWhether 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:

◆ SendRtaFrame()

void profinet::AlarmListener::SendRtaFrame ( std::uint8_t  pduType,
std::uint8_t  addFlags,
const Bytes &  ackData,
const MacAddress &  dstMac,
bool  highPriority 
)
private

Build and send an RTA PDU (Layer 2); returns the frame bytes.

Parameters
pduTypePDU type.
addFlagsAdditional flags (window size, TACK flag).
ackDataSerialized AlarmAck-PDU.
dstMacDestination MAC address.
highPriorityWhether 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:

◆ SendTransportAck()

void profinet::AlarmListener::SendTransportAck ( std::optional< MacAddress >  srcMac,
bool  highPriority 
)
private

Send a pure RTA-ACK (TACK) with empty var part.

Parameters
srcMacSender's MAC address, for the Layer 2 transport.
highPriorityWhether 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:

◆ SendUdpAck()

void profinet::AlarmListener::SendUdpAck ( const Bytes &  ackData,
const UdpEndpoint &  dstAddr 
)
private

Send an AlarmAck-PDU over the UDP transport.

Parameters
ackDataSerialized AlarmAck-PDU.
dstAddrDestination UDP endpoint.

Definition at line 497 of file alarmListener.cpp.

References udpSock.

Referenced by SendAck().

+ Here is the caller graph for this function:

◆ Start()

void profinet::AlarmListener::Start ( std::unique_ptr< IRawEthernetSocket >  eSocket = nullptr,
std::unique_ptr< IUdpSocket >  uSocket = nullptr 
)
overridevirtual

Start the background listener (socket + thread).

No-op if already running. Throws PermissionDeniedError if a raw socket needs elevated privilege.

Parameters
eSocketOptional Layer 2 Ethernet transport for l2Sock. When omitted, Start() creates the production EthernetSocket for l2Sock.
uSocketOptional UDP transport.
Exceptions
PermissionDeniedErrorWhen the selected production transport cannot be created because of insufficient operating-system permissions.
SocketErrorWhen 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:

◆ Stop()

void profinet::AlarmListener::Stop ( )
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:

Friends And Related Symbol Documentation

◆ AlarmListenerTestAccess

friend class AlarmListenerTestAccess
friend

Test fixture for AlarmListener private access in unit tests.

Definition at line 82 of file alarmListener.h.

Member Data Documentation

◆ alarmNotificationCallbacks

std::vector<std::function<void(const AlarmNotification&)> > profinet::AlarmListener::alarmNotificationCallbacks
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().

◆ callbacksMutex

std::mutex profinet::AlarmListener::callbacksMutex
mutableprivate

Protects concurrent access to callbacks.

Definition at line 236 of file alarmListener.h.

Referenced by AddAlarmNotificationCallback(), AddRtaAlarmCallback(), ProcessAlarm(), RemoveAlarmNotificationCallback(), and RemoveRtaAlarmCallback().

◆ controllerMac

MacAddress profinet::AlarmListener::controllerMac {}
private

This host's MAC address.

Definition at line 227 of file alarmListener.h.

Referenced by profinet::AlarmListenerTestAccess::ControllerMac(), and SendRtaFrame().

◆ endpoint

AlarmEndpoint profinet::AlarmListener::endpoint
private

Alarm endpoint configuration.

Definition at line 224 of file alarmListener.h.

Referenced by HandleLayer2Frame(), ListenLoop(), ProcessAlarm(), SendAck(), SendNack(), SendRtaFrame(), SendTransportAck(), and Start().

◆ ioContext

asio::io_context& profinet::AlarmListener::ioContext
private

Asio execution context used by the Layer-2 socket.

Definition at line 221 of file alarmListener.h.

Referenced by Start().

◆ l2Sock

std::unique_ptr<IRawEthernetSocket> profinet::AlarmListener::l2Sock
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().

◆ lifecycleMutex

std::mutex profinet::AlarmListener::lifecycleMutex
mutableprivate

Guards lifecycle steps of listener against concurrent access.

Definition at line 280 of file alarmListener.h.

Referenced by Start(), and Stop().

◆ recvSeqNum

std::uint16_t profinet::AlarmListener::recvSeqNum = 0
private

Last received sequence number, for duplicate detection.

Definition at line 258 of file alarmListener.h.

Referenced by ProcessAlarm(), and SendRtaFrame().

◆ rtaAlarmCallbacks

std::vector<std::function<void(const RtaError&)> > profinet::AlarmListener::rtaAlarmCallbacks
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().

◆ running

std::atomic<bool> profinet::AlarmListener::running {false}
private

Whether the listener thread should keep running.

Definition at line 230 of file alarmListener.h.

Referenced by IsRunning(), ListenLoop(), Start(), and Stop().

◆ sendSeqNum

std::uint16_t profinet::AlarmListener::sendSeqNum = 0
private

Sequence number for outgoing AlarmAck-PDUs.

Definition at line 255 of file alarmListener.h.

Referenced by SendRtaFrame().

◆ thread

std::jthread profinet::AlarmListener::thread
private

Background thread receiving and processing alarms.

Definition at line 233 of file alarmListener.h.

Referenced by Start(), and Stop().

◆ udpSock

std::unique_ptr<IUdpSocket> profinet::AlarmListener::udpSock
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().


The documentation for this class was generated from the following files: