123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195 |
- /* This work is licensed under a Creative Commons CCZero 1.0 Universal License.
- * See http://creativecommons.org/publicdomain/zero/1.0/ for more information.
- */
- /**
- * IMPORTANT ANNOUNCEMENT
- * The PubSub subscriber API is currently not finished. This examples can be used to receive
- * and print the values, which are published by the tutorial_pubsub_publish example.
- * The following code uses internal API which will be later replaced by the higher-level
- * PubSub subscriber API.
- */
- #include "ua_pubsub_networkmessage.h"
- #include "ua_log_stdout.h"
- #include "ua_server.h"
- #include "ua_config_default.h"
- #include "ua_pubsub.h"
- #include "ua_network_pubsub_udp.h"
- #ifdef UA_ENABLE_PUBSUB_ETH_UADP
- #include "ua_network_pubsub_ethernet.h"
- #endif
- #include "src_generated/ua_types_generated.h"
- #include <stdio.h>
- #include <signal.h>
- #include <stdlib.h>
- UA_Boolean running = true;
- static void stopHandler(int sign) {
- UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_SERVER, "received ctrl-c");
- running = false;
- }
- static void
- subscriptionPollingCallback(UA_Server *server, UA_PubSubConnection *connection) {
- UA_ByteString buffer;
- if (UA_ByteString_allocBuffer(&buffer, 512) != UA_STATUSCODE_GOOD) {
- UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_SERVER,
- "Message buffer allocation failed!");
- return;
- }
- /* Receive the message. Blocks for 5ms */
- UA_StatusCode retval =
- connection->channel->receive(connection->channel, &buffer, NULL, 5);
- if(retval != UA_STATUSCODE_GOOD || buffer.length == 0) {
- /* Workaround!! Reset buffer length. Receive can set the length to zero.
- * Then the buffer is not deleted because no memory allocation is
- * assumed.
- * TODO: Return an error code in 'receive' instead of setting the buf
- * length to zero. */
- buffer.length = 512;
- UA_ByteString_clear(&buffer);
- return;
- }
- /* Decode the message */
- UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND,
- "Message length: %lu", (unsigned long) buffer.length);
- UA_NetworkMessage networkMessage;
- memset(&networkMessage, 0, sizeof(UA_NetworkMessage));
- size_t currentPosition = 0;
- UA_NetworkMessage_decodeBinary(&buffer, ¤tPosition, &networkMessage);
- UA_ByteString_clear(&buffer);
- /* Is this the correct message type? */
- if(networkMessage.networkMessageType != UA_NETWORKMESSAGE_DATASET)
- goto cleanup;
- /* At least one DataSetMessage in the NetworkMessage? */
- if(networkMessage.payloadHeaderEnabled &&
- networkMessage.payloadHeader.dataSetPayloadHeader.count < 1)
- goto cleanup;
- /* Is this a KeyFrame-DataSetMessage? */
- UA_DataSetMessage *dsm = &networkMessage.payload.dataSetPayload.dataSetMessages[0];
- if(dsm->header.dataSetMessageType != UA_DATASETMESSAGE_DATAKEYFRAME)
- goto cleanup;
- /* Loop over the fields and print well-known content types */
- for(int i = 0; i < dsm->data.keyFrameData.fieldCount; i++) {
- const UA_DataType *currentType = dsm->data.keyFrameData.dataSetFields[i].value.type;
- if(currentType == &UA_TYPES[UA_TYPES_BYTE]) {
- UA_Byte value = *(UA_Byte *)dsm->data.keyFrameData.dataSetFields[i].value.data;
- UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND,
- "Message content: [Byte] \tReceived data: %i", value);
- } else if (currentType == &UA_TYPES[UA_TYPES_DATETIME]) {
- UA_DateTime value = *(UA_DateTime *)dsm->data.keyFrameData.dataSetFields[i].value.data;
- UA_DateTimeStruct receivedTime = UA_DateTime_toStruct(value);
- UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND,
- "Message content: [DateTime] \t"
- "Received date: %02i-%02i-%02i Received time: %02i:%02i:%02i",
- receivedTime.year, receivedTime.month, receivedTime.day,
- receivedTime.hour, receivedTime.min, receivedTime.sec);
- }
- }
- cleanup:
- UA_NetworkMessage_clear(&networkMessage);
- }
- static int
- run(UA_String *transportProfile, UA_NetworkAddressUrlDataType *networkAddressUrl) {
- signal(SIGINT, stopHandler);
- signal(SIGTERM, stopHandler);
- UA_ServerConfig *config = UA_ServerConfig_new_minimal(4801, NULL);
- /* Details about the PubSubTransportLayer can be found inside the
- * tutorial_pubsub_connection */
- config->pubsubTransportLayers = (UA_PubSubTransportLayer *)
- UA_calloc(2, sizeof(UA_PubSubTransportLayer));
- if (!config->pubsubTransportLayers) {
- UA_ServerConfig_delete(config);
- return EXIT_FAILURE;
- }
- config->pubsubTransportLayers[0] = UA_PubSubTransportLayerUDPMP();
- config->pubsubTransportLayersSize++;
- #ifdef UA_ENABLE_PUBSUB_ETH_UADP
- config->pubsubTransportLayers[1] = UA_PubSubTransportLayerEthernet();
- config->pubsubTransportLayersSize++;
- #endif
- UA_Server *server = UA_Server_new(config);
- UA_PubSubConnectionConfig connectionConfig;
- memset(&connectionConfig, 0, sizeof(connectionConfig));
- 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_NodeId connectionIdent;
- UA_StatusCode retval =
- UA_Server_addPubSubConnection(server, &connectionConfig, &connectionIdent);
- if(retval == UA_STATUSCODE_GOOD)
- UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_SERVER,
- "The PubSub Connection was created successfully!");
- /* The following lines register the listening on the configured multicast
- * address and configure a repeated job, which is used to handle received
- * messages. */
- UA_PubSubConnection *connection =
- UA_PubSubConnection_findConnectionbyId(server, connectionIdent);
- if(connection != NULL) {
- UA_StatusCode rv = connection->channel->regist(connection->channel, NULL, NULL);
- if (rv == UA_STATUSCODE_GOOD) {
- UA_UInt64 subscriptionCallbackId;
- UA_Server_addRepeatedCallback(server, (UA_ServerCallback)subscriptionPollingCallback,
- connection, 100, &subscriptionCallbackId);
- } else {
- UA_LOG_WARNING(UA_Log_Stdout, UA_LOGCATEGORY_SERVER, "register channel failed: %s!",
- UA_StatusCode_name(rv));
- }
- }
- retval |= UA_Server_run(server, &running);
- UA_Server_delete(server);
- UA_ServerConfig_delete(config);
- return retval == UA_STATUSCODE_GOOD ? EXIT_SUCCESS : EXIT_FAILURE;;
- }
- static void
- usage(char *progname) {
- printf("usage: %s <uri> [device]\n", 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/")};
- if (argc > 1) {
- if (strcmp(argv[1], "-h") == 0) {
- usage(argv[0]);
- return EXIT_SUCCESS;
- } 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");
- if (argc < 3) {
- printf("Error: UADP/ETH needs an interface name\n");
- return EXIT_FAILURE;
- }
- networkAddressUrl.networkInterface = UA_STRING(argv[2]);
- networkAddressUrl.url = UA_STRING(argv[1]);
- } else {
- printf("Error: unknown URI\n");
- return EXIT_FAILURE;
- }
- }
- return run(&transportProfile, &networkAddressUrl);
- }
|