Advanced: CDP Port
Overview
The CDPPort is used to gather related data into a single data object similar to a structure in programming languages. Connecting two CDPPorts via a single routing creates a data bus, propagating the data in directions defined by the CDPPort Connections.
CDPPort should be thought of as an interface that defines values that belong together for interacting with other objects with the same API. For example, a valve might need to know the current Pressure and use this information to control Flow.
CDPPorts can contain the data members as CDPProperties, contain ValuedConnection objects with values or refer to local data values near the port use location via LocalName attribute. In this case, the Connection objects in the port define the data member directions from the perspective of the one having the Routing attribute set. Ports with data member properties accessible from code are created in a user library via the CDPPort wizard and can then be used in CDPComponent code or during configuration. These ports are called code-ports. The API of such ports is composed of the CDPProperty names referred by the LocalName attributes in the Connection objects.
Note: To override the API names of the code-port, one can set the connections RemoteName property. RemoteName changes what data members must exist in the remote API and where the data referred by the LocalName is connected.
Ports that reference nearby values via PullConnection, PushConnection or ValuedConnection objects are called proxy-ports. ValuedConnection objects also contain a local copy of the value.
Proxy-ports are created in configuration by adding and connecting Connection objects in the default CDPPort model. The API of such ports is composed of the Connection object names.
Note: To override the API names of the proxy-port, one can set the connections RemoteName property. RemoteName changes what data members must exist in the remote API and where the data referred by the Connection name is connected.
CDPPorts can connect to other CDPPorts with a matching API or to CDPObject based nodes containing values that match the expected API names.
Proxy-ports that contain no Connections forward the incoming port requests to the port it routes in its Routing attribute, allowing to create chains of ports.
Usage
When creating CDPComponents code-ports are a great tool to simplify the component API and reduce the need to connect a large number of separate signals between components.
The code can become even easier to read and use if you implement data related functions in the wizard created CDPPort derivate. If you need to control multiple data objects of this type then the benefit of using CDPPort is clear, as you can make an array of CDPPort derivatives and iterate them to do processing, instead of having a lot of seemingly unrelated signals and a lot of duplicate code.
Configuration Only Port
CDPPorts defined in the configuration, known as proxy-ports, can be used to bring separate but related values in a component into a single API. The following attributes can be filled in such a port:
Description | |
---|---|
Routing | Path to remote CDPPort or CDPNode based object matching the mapping of values by port Connections. |
DataConsistency | When enabled, values connected by this port are sent within the same data packet, meaning that a group of remote values always appear consistent. Otherwise, when multiple values change, they may appear for a remote application in the wrong order or one change might be delayed a little. This option can be enabled when the port only connects values with periodic routing (not event-based, see CDPPropertyBase::RouteMethod_e). For example, CDPSignals use periodic routing, CDPParameters use event-based and for CDPProperties it is configurable. |
Connections | List of routable value nodes (e.g. CDPSignal, CDPProperty, etc) that will be connected. Connection objects Name defines the expected API name. |
PushConnection and PullConnection have the following properties:
Property | Description |
---|---|
Name | Unique identifier to this connection defining the API member. |
Input | Inputs subscribe to the remote data values and outputs are subscribed by the remote object. |
LocalName | Routing to a local value near the port. |
RemoteName | Optionally override the remote value name if it differs from the API set by Connection name. For example: ".MyValue". |
Connected | Displays the current state of the connection. |
Connect | Internal property that controls allowed connection directions. By default, both Upstream and Downstream are allowed. Upstream - is the direction of the first subscribing port in the chain. Downstream - is the direction of the end of the chain (last port without set routing) |
Mandatory | Internal property that indicates if this connection is Mandatory to be connected for the Port to report overall successful Connected status. |
Note that when modifying LocalName or RemoteName during runtime, a reconnect sequence will be triggered if the port was connected. For bulk modifications first, disconnect the port by sending CM_SUSPEND message, then do modifications and finally send CM_ACTIVATE message to reconnect.
ValuedConnection has the following properties:
Property | Description |
---|---|
Name | Unique identifier to this connection defining the API member. |
Input | Inputs subscribe to the remote data values and outputs are subscribed by the remote object. |
Type | Type of the Value the Connection stores locally. |
Value | Local copy of the routed value |
Routing | Routing to a local value near the port. |
Connected | Displays the current state of the connection. |
Connect | Internal property that controls allowed connection directions. By default, both Upstream and Downstream are allowed. Upstream - is the direction of the first subscribing port in the chain. Downstream - is the direction of the end of the chain (last port without set routing) |
Mandatory | Internal property that indicates if this connection is Mandatory to be connected for the Port to report overall successful Connected status. |
Simple Example
This simple example shows how to retrieve the values of Amplitude and Frequency from a remote component Sine, and update local signals.
- Create an application, named e.g. "MyApp", containing a Sine component.
- Create another application, named e.g. "MyPortApp", containing a CDPComponent named e.g. "MyComp".
- Click on "MyComp", add 2 CDPSignal<double> and name them "Amp" and "Freq".
- Still on "MyComp", add a CDPPort and set Routing to "MyApp.Sine".
- Click into CDPPort and add 2 PushConnections to update local signals. Notice that selecting PushConnection/PullConnection models is the same as switching Input true/false. Name the first PushConnection "Amplitude" and set LocalName to "..Amp". This will make the CDPPort route the MyApp.Sine.Amplitude value into the MyPortApp.MyComp.Amp signal. Name the second PushConnection "Frequency" and set LocalName to "..Freq" to make the CDPPort route the MyApp.Sine.Frequency into the MyPortApp.MyComp.Freq signal.
- Run your system, and click into MyPortApp.MyComp. The CDPPort should be Connected, and the signals Amp and Freq should be updated with the values from MyApp.Sine.Amplitude and MyApp.Sine.Frequency.
If you are adding 2 PullConnections instead of PushConnections in the CDPPort, you would be able to change the values of MyApp.Sine.Amplitude and MyApp.Sine.Frequency by setting values in MyPortApp.MyComp.Amp and MyPortApp.MyComp.
Inheriting from CDPPort
Code-based CDPPorts are known as code-ports.
class MyPort : public CDPPort { public: void Create(const char* shortName, CDPComponent* parent) override; CDPProperty<double> Flow; CDPProperty<double> Pressure; }; void MyPort::Create(const char* shortName, CDPComponent* parent) { CDPPort::Create(shortName, parent); // Always call base class. Flow.Create("Flow", this); Pressure.Create("Pressure", this); }
The upside of inheriting from CDPPort is that it is easy to use such a variable in the code of your custom component.
class MyComponent : public CDPComponent { ... MyPort Port; }; void MyComponent::Create(const char* fullName) { CDPComponent::Create(fullName); // Always call base class. Port.Create("Port", this); } void MyComponent::ProcessNull() { if (Port.IsConnected()) { Port.Flow = CalculateFlow(); if (Port.Pressure > 200) SetAlarms(); } }
Using the Same CDPPort on Both Sides
It may be beneficial to use the same port object on both sides of the connection. In the previous example, MyPort contained Pressure and Flow. If one component measures Pressure and uses Flow, but another needs Pressure information to regulate Flow, then both could add MyPort as a member. To connect them, only one side must set the port Routing property and set the appropriate Input attribute in the connections table. The side that set the Routing property is the master (dominant), and the other port becomes the slave concerning input and output of the different signals/properties. If you always define ports from the user's/subscriber's perspective no further configuration is needed when using the ports. This makes it possible to set the DisplayHint to Internal for the Connection object in code-port to hide implementation details.
To make connecting ports easier in the Block Diagram view, it is recommended to use either the RoutingType hint or Input property to define if the port is considered a block input or output.
RoutingType Hint
When using the Input property as a hint, the component containing the master port will be on the right side of the block diagram view. If one desires to keep the master port on the left side, a RoutingType hint "Push" should be set on the port when it is added to a component.
For the port instance in a component model that should have the routing set (master side), one must set two properties:
- TypeHint="RoutingType"
- RoutingType="Push"
Note: The Hide Base Model Items filter needs to be disabled to make the RoutingType property visible.
Now the component containing the master port will be on the left side. A special icon on the master port will hint that RoutingType hint "Push" is used:
Note: In Configure mode there are two alternative models of CDPPort available in Resource tree. For push ports, select model CDPPushPort and normal ports should use model CDPPort. Similarly, two alternatives of CDPPortConnection are available - for push connections select model PushConnection and for pull connections select model named PullConnection.
Behavior
When attempting to connect to a remote node, the CDPPort behaves in the following way:
- CDPPort can only connect value nodes that either has a child property named Routing and RoutingStatus or are of type CDPProperty.
- CDPPort looks for values specified by its API in the remote object. The Connected property is
false
until the connection succeeds. - CDPPort will refuse to connect to value nodes that have a read-only Routing child and hence can't subscribe to port data.
- After the connection is done, all routings set by CDPPort are marked read-only, so nothing else can modify them. On disconnect, the read-only flag is removed.
For detailed CDPPort usage see How to Use Multivariable Interfaces
Get started with CDP Studio today
Let us help you take your great ideas and turn them into the products your customer will love.