CDPConnector Class

The CDPConnector handles communication with a CDPComponent or CDPObject. More...

Header: #include <CDPSystem/Base/CDPConnector.h>
Inherits: CDP::StudioAPI::CDPNode

Public Functions

CDPConnector()
CDPConnector(const char *remoteName)
~CDPConnector() override
virtual void Configure(XMLElementEx *pEx)
void ConnectTo(const char *remoteName)
bool Connected() const
virtual void Create(const char *connectorName, CDPComponent *pOwnerComponent)
std::string GetProperty(const char *propertyName, bool &bSuccess)
CDPComponent *OwnerComponent() const
void Preserve()
bool Preserved() const
void Release()
unsigned int RemoteHandle() const
std::string RemoteName() const
std::string RemoteShortName() const
const char *RemoteState() const
bool RemoteState(const char *stateToCheck) const
unsigned int RemoteStatus() const
unsigned int SendMessage(Message *msg, bool retryEnabled = true)
unsigned int SendMessage(const char *command, unsigned int origin = 0)
unsigned int SendMessage(const char *command, const char *parameter, unsigned int origin = 0)
unsigned int SendMessage(unsigned int command, unsigned int origin = 0)
void SendMessageNoRetry(Message *msg)
void SetConnectionChangeCallback(const std::function<void( bool connected ) > &callback)
void SetProperty(const char *propertyName, const char *propertyValue, int saveOnChange = -1)
virtual bool SubscribeToEventNotifications(IEventReceiver *pReceiver, unsigned int eventFilter = 0xffffffff)
virtual bool UnsubscribeFromEventNotifications(IEventReceiver *pReceiver, unsigned int eventFilter = 0xffffffff)

Reimplemented Public Functions

virtual void FillNodeChildren(CDP::StudioAPI::NodeStream &serializer) const override
virtual const std::string GetNodeName() const override
virtual std::string GetNodeTypeName() const override

Additional Inherited Members

Detailed Description

The CDPConnector handles communication with a CDPComponent or CDPObject.

CDPConnector Features

  • Creates a communication channel to a remote CDPObject or CDPComponent.
  • Simplifies sending of messages to remote object
  • Simplifies retrieval of information about the remote object
  • The connector automatically connects when the remote object name is set.
  • Automatically handles connection state; Disconnects if remote object goes away, connects when it comes back up.

Normal Usage

By adding a CDPConnector in CDP Studio Code mode or in Configure mode, code is automatically generated into your model so that the to CDPConnector is instantiated and created correctly. From there it is easy to use:

Example: By adding 'myConnector' to 'MyComponent':

CDPConnector myConnector;                 // autogenerated in MyComponent header file
...
myConnector.Create("myConnector",this);   // auto-generated in MyComponent::Create() method
...

void MyComponent::ProcessStart()
{
  if (myConnector.Connected() && startWanted && !started)
    myConnector.SendMessage("Start");
}

Connection Status and State

  • Use Connected() to determine if the remote object is connected.
  • Connected means the communication link is valid and that state and handle information is updated (see Periodic Updates below).
  • Not Connected means communication link is not valid; i.e. the specified object is not available on the network.

The CDPConnector retrieves an object (alarm) Status through the call to RemoteStatus(). Component State can be requested/tested by calling RemoteState(), or by checking RemoteState(wantedState).

Example:

void MyComponent::ProcessNull()
{
  if(myConnector.Connected() && myConnector.RemoteState("Online"))
    requestedState = "Online";
}

Sending Messages to Objects

The SendMessage() API is used to send messages. Connectors can send message content (limited to 996 bytes per message) to the connected object.

The simplest way to send a message, is to just send a text-command. Example:

if (pumpConnector.Connected())
  pumpConnector.SendMessage("Start");

The above code assumes a pump connector is connected to a pump CDPComponent. It is also assumed that the pump CDPComponent has a Message handler (as added, for instance in Code mode; CDP Add Message ) that handles this "Start" message. When the pump CDPComponent receives the "Start" message, the MessageStart function is invoked.

To send additional information in the message:

if (pumpConnector.Connected() && pumpConnector.RemoteState("Stopped"))
  pumpConnector.SendMessage("Start","AdditionalInformation");

The MessageHandler can decode the message:

int MyComponent::MessageStart(void* message)
{
  MessageTextCommandWithParameterReceive* msg = static_cast<MessageTextCommandWithParameterReceive*>(message);
  std::string strParameter(msg->parameters);
  CDPMessage("%s: Received Start Message with parameter %s\n",Name(),strParameter.c_str());
  return 1;
}

Message Acknowledgement

When the Retry parameter to SendMessage is non-zero, an acknowledge message (ACK / success) or not acknowledge (NACK / failure) is returned to the sender, dependant on success or failure to transmit a message.

The object that sends the Message can verify message reception or failure in either the MessageConfirm() (ACK) or the MessageTimeout() (NACK) functions. Example:

void MyComponent::ProcessNull()
{
  static bool sent = false;
  if(pump.Connected())
  {
    pump.SendMessage("Start");
    sent = true;
  }
}

int MyComponent::MessageTimedOut(void* messageAck)
{
  MessageACK* pMack = static_cast<MessageACK*>(messageAck);
  unsigned int handle = pMack->originalMessage.Destination();
  CDPMessage("%s: Got Timeout for message to Handle : 0x%08x, sendStatus=%i\n",Name(),handle,pMack->sendStatus);
  return 1;
}

int MyComponent::MessageConfirm(void* messageAck)
{
  MessageACK* pMack = static_cast<MessageACK*>(messageAck);
  unsigned int handle = pMack->originalMessage.Destination();
  CDPMessage("%s: Got Confirmation for message to Handle : 0x%08x, sendStatus=%i\n",Name(),handle,pMack->sendStatus);
  return 1;
}

The MessageAck message contains either the original message sent, or it could be a message in response to the message sent, depending on what the receiver implements. The message data that is passed in to the receiving component is also returned in the acknowledgement message. Since the Receiver can choose to modify this message, it is possible to implement a simple RPC mechanism using the SendMessage protocol.

Retrieving Properties

Properties can be requested from the connected object, even if it is on a different application. The GetProperty() call in CDPConnector will retrieve the property from the local property store if it can be found there. If it can not be found, a subscription will be set up to request the property (and future property changes) from the source object, and failure is returned to the caller. The CDP framework will propagate the property from the source object to the local store, so when GetProperty() is called some time in the future, the value will be present in the local store and returned together with the 'success' argument set to true.

It is also possible to get a callback when the property value arrives. The caller must then inherit the class from IEventReceiver and implement the pure virtual functions it provides. For all CDPObject based objects, a rudimentary (do-nothing) implementation has already been implemented. To get callbacks, the user must call CDPConnector::SubscribeToEventNotifications(this) and override RemotePropertyChanged() to handle reception of the property when that callback is called.

Note: Be aware that the RemotePropertyChanged() callback is not invoked if GetProperty() returns success (i.e if the property is found locally), even if a Subscription has been set up.

Example: Assuming, in your Component 'PumpController', you have a connector 'pump' and you want to know which Model it has:

void PumpController::ProcessNull()
{
  if (pump.Connected() && !modelRequested)
  {
    pump.SubscribeToEventNotifications(this); // Set up subscription so RemotePropertyChanged is called when property is received

    bool success = false;
    std::string model = pump.GetProperty("Model",success);
    if(success)
      RemotePropertyChanged(pump.RemoteHandle(),"Model",model); // locally found property will not cause callback to be called, so we invoke it manually.

    modelRequested = true;
  }
}

The IEventReceiver::RemotePropertyChanged() will be invoked when the property has been retrieved:

void PumpController::RemotePropertyChanged(unsigned int remoteHandle, std::string propertyName, std::string propertyValue)
{
  if(remoteHandle==pump.RemoteHandle() && propertyName=="Model")
  {
    // Print out the model:
    CDPMessage("%s: pump has model %s\n", Name(), propertyValue.c_str());
    // Tell the connector we are no longer interested in eventNotifications:
    RunInComponentThread([=]{pump.UnsubscribeFromEventNotifications(this);});
  }
}

Data Direction

When a connector is mainly used to send messages to its target and this needs to be indicated in block diagrams, the connector instance in a component should set two properties in the connector instance in the component model: Set the TypeHint="RoutingType" and RoutingType="Push" attributes inside the connector instance of the component model. To be able to set this the 'Hide Base Model Items' filter must be disabled. The connector will now appear on the output side of the component in block diagram.

Periodic Updates

Status and state are retrieved periodically from remote components only ifRemoteState or RemoteStatus is requested. The very first time the RemoteState or RemoteStatus is read, the information will not be available, as this will be the signal to the update process that status and state information should be retrieved as well. RemoteStatus and RemoteState information are updated at the frequency (fs) of the Application, default is 100ms (for fs of 10Hz).

Member Function Documentation

CDPConnector::CDPConnector()

Constructs a CDPConnector

CDPConnector::CDPConnector(const char *remoteName)

Constructs a CDPConnector and connects to remoteName.

CDPConnector::~CDPConnector()

Releases connection and destroys the instance.

[virtual] void CDPConnector::Configure(XMLElementEx *pEx)

Runs Configure() for m_object and m_description. pEx must point to a xml Connector-line.

void CDPConnector::ConnectTo(const char *remoteName)

Connects to an object identified by remoteName, which is the full name of the object (local or remote) to connect to. Connection is not instant, so the user must call Connected() before attempting any operations on the connector.

bool CDPConnector::Connected() const

Gets connection status

Use Connected() to check if remote object is connected.

Note: Status/state is retrieved periodically from remote components only after RemoteStatus/RemoteState is requested. The very first time the RemoteState() or RemoteStatus() is read, the information will not be available, as this will be the signal to the update process that status and state information periodic updating should start.

Returns true if communication link is valid and state and handle information is updated (see note). Returns false if communication link is not valid; i.e. the specified object is not available on the network.

[virtual] void CDPConnector::Create(const char *connectorName, CDPComponent *pOwnerComponent)

Initializes the instance. Creates CDPProperties and saves pOwnerComponent for later use.

[override virtual] void CDPConnector::FillNodeChildren(CDP::StudioAPI::NodeStream &serializer) const

Reimplemented from CDPNode::FillNodeChildren().

Writes m_object (routing to object), m_connected and m_description to serializer stream.

[override virtual] const std::string CDPConnector::GetNodeName() const

Reimplemented from ICDPNode::GetNodeName().

Returns the local name given to the connector.

[override virtual] std::string CDPConnector::GetNodeTypeName() const

Reimplemented from ICDPNode::GetNodeTypeName().

Returns a "CDPConnector".

std::string CDPConnector::GetProperty(const char *propertyName, bool &bSuccess)

Reads property from remote object.

If the property value is not available locally yet, the value will be requested, and (if SubscribeToEventNotifications has been called) then the owner component RemotePropertyChanged() will be called when the value arrives.

Callback-registration is done by calling SubscribeToEventNotifications( objectToReceiveNotify ) , and the callback will invoke the RemotePropertyChanged() function in objectToReceiveNotify when the property is retrieved.

Example code:

if(connector->Connected())
{
  connector->SubscribeToEventNotifications(this);

  bool success = false;
  std::string name = connector->GetProperty("Name",success);
  if(success)
    RemotePropertyChanged(connector->RemoteHandle(),"Name",name);
}

CDPComponent *CDPConnector::OwnerComponent() const

Returns raw pointer to owner component.

void CDPConnector::Preserve()

Tells the underlying CDPConnection to keep the connection even if this CDPConnector is destroyed or released.

bool CDPConnector::Preserved() const

Gets the preserved state of this connection

void CDPConnector::Release()

Releases connection without deleting connector.

unsigned int CDPConnector::RemoteHandle() const

Gets handle of remote component.

std::string CDPConnector::RemoteName() const

Returns full remote object name.

std::string CDPConnector::RemoteShortName() const

Returns connected component name. If not connected then returns empty string.

const char *CDPConnector::RemoteState() const

Gets state of remote component.

bool CDPConnector::RemoteState(const char *stateToCheck) const

Returns true if the component is in the specified state

unsigned int CDPConnector::RemoteStatus() const

Gets the most recently updated status of the remote object.

The status equals the or'ed statuses of the alarms and subcomponents. The Status bits are defined in CDPAlarm.

unsigned int CDPConnector::SendMessage(Message *msg, bool retryEnabled = true)

Sends custom message with or without retries.

This function is used to send messages already filled out by user code. Messages which is larger than the Message struct may be sent. Also remember that all values in the Message must be on network format. Use macros MESSAGE_FILL and similar to help filling the message correctly.

Note: Set the parameterSize member correctly. This must be set to the number of bytes following after the parameterSize member.

msg - Pointer to message to send. retryEnabled - Set to true to make the messenger ask for acknowledge and resend the message if not aknowledge has been received.

See also Messenger and MESSAGE_FILL.

unsigned int CDPConnector::SendMessage(const char *command, unsigned int origin = 0)

Sends CM_TEXTCOMMAND message with specified text command (no parameters).

command - Text command to send origin - Origin handle to put in message to send. If 0 or not specified, handle of CDPConnector's owner or Messenger will be used.

unsigned int CDPConnector::SendMessage(const char *command, const char *parameter, unsigned int origin = 0)

Sends CM_TEXTCOMMAND message with specified text command and string parameter. Both command and parameter must be zero terminated strings.

command - Text command to send, must be zero terminated. parameter - Zero-terminated string parameter. origin - Origin handle to put in message to send. If 0 or not specified, handle of CDPConnector's owner or Messenger will be used.

unsigned int CDPConnector::SendMessage(unsigned int command, unsigned int origin = 0)

Sends binary message (without parameters).

command - Binary command to send, typically CM_ACTIVATE or similar. origin - Origin handle to put in message to send. If 0 or not specified, handle of CDPConnector's owner or Messenger will be used.

void CDPConnector::SendMessageNoRetry(Message *msg)

Sends message without retries (no acknowledgement requested from recipient). Same as SendMessage(Message*, false)

See also CDPConnector::SendMessage().

void CDPConnector::SetConnectionChangeCallback(const std::function<void( bool connected ) > &callback)

void CDPConnector::SetProperty(const char *propertyName, const char *propertyValue, int saveOnChange = -1)

Sends a message that sets destination object's CDPProperty named propertyName to propertyValue.

If an owner component is set, it will receive callbacks on message acks.

If optional argument saveOnChange is set to 1, changed CDPProperty value is saved to XML. If 0 then value is changed but change is not saved to XML. Therefore it is lost after restarting the application. Default is -1, then property's SaveOnChange setting is used to determine whether to save the value. Note that this argument will not update SaveOnChange setting, it just overrides it.

[virtual] bool CDPConnector::SubscribeToEventNotifications(IEventReceiver *pReceiver, unsigned int eventFilter = 0xffffffff)

Adds pReceiver to the list of objects that will receive updates when events from object with handle handleEventSource are received ( typically after a call to CDPConnector::GetProperty() )

The pReceiver will then receive a message describing the event. If handleEventSource==0xffffffff, all events will be sent to pReceiver. Use eventFilter to mask out which events to subscribe to.

The eventFilter bits are defined like this:

#define EVENT_ALARMSET                  0x00000001    // The alarm's Set flag/state was set. The alarm changed state to "Unack-Set" (The Unack flag was set if not already set)
#define EVENT_ALARMCLEAR                0x00000002    // The alarm's Set flag was cleared. The Unack state is unchanged.
#define EVENT_ALARMACK                  0x00000004    // The alarm changed state from "Unacknowledged" to "Acknowledged". The Set state is unchanged.
#define EVENT_PROPERTY_CHANGE           0x00000008    // Some property was changed.
#define EVENT_REPRISE                   0x00000040    // A repetition/update of an event that has been reported before. Courtesy of late subscribers.
#define EVENT_SOURCE_OBJECT_UNAVAILABLE 0x00000100    // The provider of the event has become unavailable (disconnected or similar)
#define EVENT_NODE_BOOT                 0x40000000    // The provider reports that the CDPEventNode just have booted.
#define EVENT_EXTENDED_INFO_AVAILABLE   0x80000000    // Indicates that this event also have sent extended event, and that the extended event info is available as extended event.

#define EVENT_MASK_ALL                  0xffffffff
#define EVENT_MASK_ALARM_EVENT          (EVENT_ALARMSET | EVENT_ALARMCLEAR | EVENT_ALARMACK)

See also UnsubscribeFromEventNotifications.

[virtual] bool CDPConnector::UnsubscribeFromEventNotifications(IEventReceiver *pReceiver, unsigned int eventFilter = 0xffffffff)

Removes pReceiver from list of objects that will receive updates when events from object with handle handleEventSource are received.

The pReceiver will then receive a message describing the event. Use eventFilter to mask out which events to unsubscribe to.

See also SubscribeToEventNotifications.

© CDP Technologies AS - All rights reserved