|
@@ -7,19 +7,21 @@
|
|
|
* Working with Publish/Subscribe
|
|
|
* ------------------------------
|
|
|
*
|
|
|
- * Work in progress:
|
|
|
- * This Tutorial will be continuously extended during the next PubSub batches. More details about
|
|
|
- * the PubSub extension and corresponding open62541 API are located here: :ref:`pubsub`.
|
|
|
+ * Work in progress: This Tutorial will be continuously extended during the next
|
|
|
+ * PubSub batches. More details about the PubSub extension and corresponding
|
|
|
+ * open62541 API are located here: :ref:`pubsub`.
|
|
|
*
|
|
|
* Publishing Fields
|
|
|
* ^^^^^^^^^^^^^^^^^
|
|
|
* The PubSub publish example demonstrate the simplest way to publish
|
|
|
- * informations from the information model over UDP multicast using
|
|
|
- * the UADP encoding.
|
|
|
+ * informations from the information model over UDP multicast using the UADP
|
|
|
+ * encoding.
|
|
|
*
|
|
|
* **Connection handling**
|
|
|
- * PubSubConnections can be created and deleted on runtime. More details about the system preconfiguration and
|
|
|
- * connection can be found in ``tutorial_pubsub_connection.c``.
|
|
|
+ *
|
|
|
+ * PubSubConnections can be created and deleted on runtime. More details about
|
|
|
+ * the system preconfiguration and connection can be found in
|
|
|
+ * ``tutorial_pubsub_connection.c``.
|
|
|
*/
|
|
|
|
|
|
#include "open62541.h"
|
|
@@ -29,7 +31,8 @@
|
|
|
UA_NodeId connectionIdent, publishedDataSetIdent, writerGroupIdent;
|
|
|
|
|
|
static void
|
|
|
-addPubSubConnection(UA_Server *server, UA_String *transportProfile, UA_NetworkAddressUrlDataType *networkAddressUrl){
|
|
|
+addPubSubConnection(UA_Server *server, UA_String *transportProfile,
|
|
|
+ UA_NetworkAddressUrlDataType *networkAddressUrl){
|
|
|
/* Details about the connection configuration and handling are located
|
|
|
* in the pubsub connection tutorial */
|
|
|
UA_PubSubConnectionConfig connectionConfig;
|
|
@@ -37,17 +40,19 @@ addPubSubConnection(UA_Server *server, UA_String *transportProfile, UA_NetworkAd
|
|
|
connectionConfig.name = UA_STRING("UADP Connection 1");
|
|
|
connectionConfig.transportProfileUri = *transportProfile;
|
|
|
connectionConfig.enabled = UA_TRUE;
|
|
|
- UA_Variant_setScalar(&connectionConfig.address, networkAddressUrl, &UA_TYPES[UA_TYPES_NETWORKADDRESSURLDATATYPE]);
|
|
|
+ UA_Variant_setScalar(&connectionConfig.address, networkAddressUrl,
|
|
|
+ &UA_TYPES[UA_TYPES_NETWORKADDRESSURLDATATYPE]);
|
|
|
connectionConfig.publisherId.numeric = UA_UInt32_random();
|
|
|
UA_Server_addPubSubConnection(server, &connectionConfig, &connectionIdent);
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* **PublishedDataSet handling**
|
|
|
- * The PublishedDataSet (PDS) and PubSubConnection are the toplevel entities and can exist alone. The PDS contains
|
|
|
- * the collection of the published fields.
|
|
|
- * All other PubSub elements are directly or indirectly linked with the PDS or connection.
|
|
|
- */
|
|
|
+ *
|
|
|
+ * The PublishedDataSet (PDS) and PubSubConnection are the toplevel entities and
|
|
|
+ * can exist alone. The PDS contains the collection of the published fields. All
|
|
|
+ * other PubSub elements are directly or indirectly linked with the PDS or
|
|
|
+ * connection. */
|
|
|
static void
|
|
|
addPublishedDataSet(UA_Server *server) {
|
|
|
/* The PublishedDataSetConfig contains all necessary public
|
|
@@ -62,8 +67,9 @@ addPublishedDataSet(UA_Server *server) {
|
|
|
|
|
|
/**
|
|
|
* **DataSetField handling**
|
|
|
- * The DataSetField (DSF) is part of the PDS and describes exactly one published field.
|
|
|
- */
|
|
|
+ *
|
|
|
+ * The DataSetField (DSF) is part of the PDS and describes exactly one published
|
|
|
+ * field. */
|
|
|
static void
|
|
|
addDataSetField(UA_Server *server) {
|
|
|
/* Add a field to the previous created PublishedDataSet */
|
|
@@ -76,17 +82,19 @@ addDataSetField(UA_Server *server) {
|
|
|
dataSetFieldConfig.field.variable.publishParameters.publishedVariable =
|
|
|
UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_CURRENTTIME);
|
|
|
dataSetFieldConfig.field.variable.publishParameters.attributeId = UA_ATTRIBUTEID_VALUE;
|
|
|
- UA_Server_addDataSetField(server, publishedDataSetIdent, &dataSetFieldConfig, &dataSetFieldIdent);
|
|
|
+ UA_Server_addDataSetField(server, publishedDataSetIdent,
|
|
|
+ &dataSetFieldConfig, &dataSetFieldIdent);
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* **WriterGroup handling**
|
|
|
- * The WriterGroup (WG) is part of the connection and contains the primary configuration
|
|
|
- * parameters for the message creation.
|
|
|
- */
|
|
|
+ *
|
|
|
+ * The WriterGroup (WG) is part of the connection and contains the primary
|
|
|
+ * configuration parameters for the message creation. */
|
|
|
static void
|
|
|
addWriterGroup(UA_Server *server) {
|
|
|
- /* Now we create a new WriterGroupConfig and add the group to the existing PubSubConnection. */
|
|
|
+ /* Now we create a new WriterGroupConfig and add the group to the existing
|
|
|
+ * PubSubConnection. */
|
|
|
UA_WriterGroupConfig writerGroupConfig;
|
|
|
memset(&writerGroupConfig, 0, sizeof(UA_WriterGroupConfig));
|
|
|
writerGroupConfig.name = UA_STRING("Demo WriterGroup");
|
|
@@ -95,16 +103,18 @@ addWriterGroup(UA_Server *server) {
|
|
|
writerGroupConfig.writerGroupId = 100;
|
|
|
writerGroupConfig.encodingMimeType = UA_PUBSUB_ENCODING_UADP;
|
|
|
/* The configuration flags for the messages are encapsulated inside the
|
|
|
- * message- and transport settings extension objects. These extension objects
|
|
|
- * are defined by the standard. e.g. UadpWriterGroupMessageDataType */
|
|
|
+ * message- and transport settings extension objects. These extension
|
|
|
+ * objects are defined by the standard. e.g.
|
|
|
+ * UadpWriterGroupMessageDataType */
|
|
|
UA_Server_addWriterGroup(server, connectionIdent, &writerGroupConfig, &writerGroupIdent);
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* **DataSetWriter handling**
|
|
|
- * A DataSetWriter (DSW) is the glue between the WG and the PDS. The DSW is linked to exactly one
|
|
|
- * PDS and contains additional informations for the message generation.
|
|
|
- */
|
|
|
+ *
|
|
|
+ * A DataSetWriter (DSW) is the glue between the WG and the PDS. The DSW is
|
|
|
+ * linked to exactly one PDS and contains additional informations for the
|
|
|
+ * message generation. */
|
|
|
static void
|
|
|
addDataSetWriter(UA_Server *server) {
|
|
|
/* We need now a DataSetWriter within the WriterGroup. This means we must
|
|
@@ -120,16 +130,18 @@ addDataSetWriter(UA_Server *server) {
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * That's it! You're now publishing the selected fields.
|
|
|
- * Open a packet inspection tool of trust e.g. wireshark and take a look on the outgoing packages.
|
|
|
- * The following graphic figures out the packages created by this tutorial.
|
|
|
+ * That's it! You're now publishing the selected fields. Open a packet
|
|
|
+ * inspection tool of trust e.g. wireshark and take a look on the outgoing
|
|
|
+ * packages. The following graphic figures out the packages created by this
|
|
|
+ * tutorial.
|
|
|
*
|
|
|
* .. figure:: ua-wireshark-pubsub.png
|
|
|
* :figwidth: 100 %
|
|
|
* :alt: OPC UA PubSub communication in wireshark
|
|
|
*
|
|
|
- * The open62541 subscriber API will be released later. If you want to process the the datagrams,
|
|
|
- * take a look on the ua_network_pubsub_networkmessage.c which already contains the decoding code for UADP messages.
|
|
|
+ * The open62541 subscriber API will be released later. If you want to process
|
|
|
+ * the the datagrams, take a look on the ua_network_pubsub_networkmessage.c
|
|
|
+ * which already contains the decoding code for UADP messages.
|
|
|
*
|
|
|
* It follows the main server code, making use of the above definitions. */
|
|
|
UA_Boolean running = true;
|
|
@@ -138,14 +150,17 @@ static void stopHandler(int sign) {
|
|
|
running = false;
|
|
|
}
|
|
|
|
|
|
-static int run(UA_String *transportProfile, UA_NetworkAddressUrlDataType *networkAddressUrl) {
|
|
|
+static int run(UA_String *transportProfile,
|
|
|
+ UA_NetworkAddressUrlDataType *networkAddressUrl) {
|
|
|
signal(SIGINT, stopHandler);
|
|
|
signal(SIGTERM, stopHandler);
|
|
|
|
|
|
UA_StatusCode retval = UA_STATUSCODE_GOOD;
|
|
|
UA_ServerConfig *config = UA_ServerConfig_new_default();
|
|
|
- /* Details about the connection configuration and handling are located in the pubsub connection tutorial */
|
|
|
- config->pubsubTransportLayers = (UA_PubSubTransportLayer *) UA_calloc(2, sizeof(UA_PubSubTransportLayer));
|
|
|
+ /* Details about the connection configuration and handling are located in
|
|
|
+ * the pubsub connection tutorial */
|
|
|
+ config->pubsubTransportLayers =
|
|
|
+ (UA_PubSubTransportLayer *) UA_calloc(2, sizeof(UA_PubSubTransportLayer));
|
|
|
if(!config->pubsubTransportLayers) {
|
|
|
UA_ServerConfig_delete(config);
|
|
|
return -1;
|
|
@@ -176,8 +191,10 @@ usage(char *progname) {
|
|
|
}
|
|
|
|
|
|
int main(int argc, char **argv) {
|
|
|
- UA_String transportProfile = UA_STRING("http://opcfoundation.org/UA-Profile/Transport/pubsub-udp-uadp");
|
|
|
- UA_NetworkAddressUrlDataType networkAddressUrl = {UA_STRING_NULL , UA_STRING("opc.udp://224.0.0.22:4840/")};
|
|
|
+ UA_String transportProfile =
|
|
|
+ UA_STRING("http://opcfoundation.org/UA-Profile/Transport/pubsub-udp-uadp");
|
|
|
+ UA_NetworkAddressUrlDataType networkAddressUrl =
|
|
|
+ {UA_STRING_NULL , UA_STRING("opc.udp://224.0.0.22:4840/")};
|
|
|
|
|
|
if (argc > 1) {
|
|
|
if (strcmp(argv[1], "-h") == 0) {
|
|
@@ -186,7 +203,8 @@ int main(int argc, char **argv) {
|
|
|
} else if (strncmp(argv[1], "opc.udp://", 10) == 0) {
|
|
|
networkAddressUrl.url = UA_STRING(argv[1]);
|
|
|
} else if (strncmp(argv[1], "opc.eth://", 10) == 0) {
|
|
|
- transportProfile = UA_STRING("http://opcfoundation.org/UA-Profile/Transport/pubsub-eth-uadp");
|
|
|
+ transportProfile =
|
|
|
+ UA_STRING("http://opcfoundation.org/UA-Profile/Transport/pubsub-eth-uadp");
|
|
|
if (argc < 3) {
|
|
|
printf("Error: UADP/ETH needs an interface name\n");
|
|
|
return 1;
|