Using notifications with C++

Use Case

The PLCnext Runtime System contains several services that notify of their own status. These notifications can be received by other services and are available for diagnose purposes, e. g. using the PLCnext Engineer

For developers of C++ applications, this provides versatile opportunities:

  • let your app react to changes in the PLC's status
  • make your app detect a new PROFINET connection
  • spot a wire that's connected to the wrong port
  • ...and many, many more!

Of course, you can create and use your own notifications as well and use them throughout your applications.

Concept

For registering, sending and receiving notifications between components of a controller, the Notification Manager is used. The header files required for using the Notification Manager are provided via the PLCnext Technology SDK (see PLCnext CLI).

The SDK contains classes for the Notification Manager, classes for user-defined user data (payload) as well as the payload classes of the PLCnext Runtime System itself.

How to

If you want to use a class, integrate it into your program via an #include command (e.g. #include <Arp/System/Nm/NotificationManager.hpp>). Further information on the classes and their applications is available directly in the code commentary.

Defining the structure of user data

To enable correct interpretation of the user data of a notification, the structure of the user data has to be defined. Use Arp/System/Nm/SpecializedPayload.hpp for this. User data with up to 50 fields can be used as a character string.

Hide exampleClick to see a code example with two fields

// Example payload with two payload fields
#include "Arp/System/Nm/SpecializedPayload.hpp"
// Use the class name as template parameter for SpecializedPayload
class UserLoggedInPayload
   : public Arp::System::Nm::SpecializedPayload<userloggedinpayload>
{
public:
   // Inherit base class constructors
   using SpecializedPayload::SpecializedPayload;
   // Define a convenient constructor to create the payload
   // This constructor will be called by a variadic template and perfect forwarding when
   // a notification is sent. Therefore this constructor defines the signature of the
   // function to send a notification.
   // Pass a format string for a user visible representation of the payload to the base
   // class' constructor. This format string will be used by the NotificationLogger to
   // serialize the payload.
UserLoggedInPayload(const String& username, const String& permissions)
   : SpecializedPayload("User logged in: {0} (permissions={1})")
   {
      // Store the values of the parameters in the underlying payload data structure
      this->SetFieldvalue(this->fieldIndexUsername, username);
      this->SetFieldvalue(this->fieldIndexPermissions, permissions);
   }
   // Add getters for a type-safe access to the payload fields
   String GetUsername() const
   {
      return this->GetFieldValueAs<string>(this->fieldIndexUsername);
   }
   String GetPermissions() const
   {
   return this->GetFieldValueAs<string>(this->fieldIndexPermissions);
   }
private:
   // Define the fields of the payload type. Each field is accessed by an index.
   // The type infomation is used to ensure only valid information is set to the
   // payload fields.
   // Use direct member initialization here to ensure these members are also initialized
   // when the inherited constructors are used.
   // The order of these declarations matters, so don't change them.
   const size_t fieldIndexUsername = this->AddField<string>();
   const size_t fieldIndexPermissions = this->AddField<string>();
};

Registering and sending notifications

Before a notification can be sent, it must be registered with the Notification Manager. If a component that registered a notification is no longer available, it has to unregister the notification first. Both operations are implemented using the NotificationRegistration proxy object.

Hide exampleClick to see a code example

// in UserManager
NotificationManager& nm= NotificationManager::GetInstance();
auto UserLoggedInRegistration = nm.CreateNotificationRegistration<userloggedinpayload>("Arp.System.Um.Login",
    "UserManager", Severity::Info);
UserLoggedInRegistration.SendNotification("hans", "admin");
// notification is deregistered automatically in destructor of UserLoggedInRegistration

Receiving notifications

To receive notifications, the recipient must subscribe to the notification name with the Notification Manager. ANotificationSubscriber object is used for receiving notifications. If a recipient is no longer to receive notifications, it has to unsubscribe. To make sure this is done at the end of the recipient's life cycle, it is recommended to use a proxy object as it is described for registering of notifications.

Hide exampleClick to see a code example

// in eHMI
void HandleUserLogins(const Notification& notification)
{
   auto payload = notification.GetPayloadAs<userloggedinpayload>();
   // do something with payload.GetUsername() and payload.GetPermissions()
}
// in some long living object of eHMI
NotificationManager& nm = NotificationManager::GetInstance();
auto UserLoggedIn = nm.CreateNotificationSubscriber("Arp.System.Um.Login");
UserLoggedIn.OnNotification += make_delegate(HandleUserLogins);
// notification is unsubscribed automatically in destructor of UserLoggedIn

Querying information

The INotificationManagerInfo interface is the interface for querying information from the Notification Manager. The following options are available:

  • GetNotificationName()
    This method returns the notification name.
  • GetNotificationNameId()
    This method returns the ID of a notification name.
  • GetNotificationRegistration()
    This method returns the information about a notification provided during registration (see Metadata of a notification.)
  • GetAllKnownNotificationNameIds()
    This method returns a list of NotificationNameIds of all known notifications, independent of their status.
  • GetNotificationsNameIdsByStatus()
    This method returns a list of NotificationNameIds of notifications with a certain status.

Reference

Structure of a notification

Metadata of a notification

To register a notification, the sender must specify metadata information:

  • notificationName
    The notification name defines under which name the notification is published. The parts of a name are separated by "." and, to the level of the component, should correspond to the name of the user component to be sent.
    Users may define their own notifications in any namespace except those that are predefined by the PLCnext Runtime System which all derive from the Arp branch.
    Note: Even if you're creating additional notifications for core components of the PLCnext Runtime, keep them in your own namespace. In further firmware releases there will be additional notifications implemented, so to avoid conflicts strictly do not use theArp or theSecurity.Arp  namespace with your own notifications. 
  • senderName
    Name of the component sending the notification.
  • Severity
    Information on the severity of the notification. Processing is not affected by the severity.
    • Default
      Information sent between devices
    • Info
      General information
    • Warning
      Warning for the user
    • Error
      Error without serious impacts
    • Critical
      Error with medium impact
    • Fatal
      Error with serious impact
  • PayloadTypeId
    Unique identification for the user data type.
  • NotificationNameId is returned:
    The ID is used for identifying the instance of a notification. It is required for sending and unregistering a notification.

The status of a notification registration can have the following states:

  • Subscribed: A recipient subscribed but has not yet been registered by a component. Subscribing to a notification that has not yet been registered or already been unregistered is only permitted during startup of the firmware and the controller. Otherwise, an exception will be triggered.
  • Registered: Registered by a component
  • Unregistered: Unregistered by a component

TheGetNotificationRegistration() method returns the above meta information about a notification.

 

 


• Published/reviewed: 2024-09-24   ☀  Revision 073 •