tutorial_pubsub_subscribe.c 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116
  1. /* This work is licensed under a Creative Commons CCZero 1.0 Universal License.
  2. * See http://creativecommons.org/publicdomain/zero/1.0/ for more information.
  3. */
  4. /**
  5. * IMPORTANT ANNOUNCEMENT
  6. * The PubSub subscriber API is currently not finished. This examples can be used to receive
  7. * and print the values, which are published by the tutorial_pubsub_publish example.
  8. * The following code uses internal API which will be later replaced by the higher-level
  9. * PubSub subscriber API.
  10. */
  11. #include <signal.h>
  12. #include <stdio.h>
  13. #include "ua_pubsub_networkmessage.h"
  14. #include "ua_log_stdout.h"
  15. #include "ua_server.h"
  16. #include "ua_config_default.h"
  17. #include "ua_pubsub.h"
  18. #include "ua_network_pubsub_udp.h"
  19. #include "src_generated/ua_types_generated.h"
  20. UA_Boolean running = true;
  21. static void stopHandler(int sign) {
  22. UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_SERVER, "received ctrl-c");
  23. running = false;
  24. }
  25. static void
  26. subscriptionPollingCallback(UA_Server *server, UA_PubSubConnection *connection) {
  27. UA_ByteString buffer;
  28. if (UA_ByteString_allocBuffer(&buffer, 512) != UA_STATUSCODE_GOOD) {
  29. UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_SERVER, "Message buffer allocation failed!");
  30. return;
  31. }
  32. connection->channel->receive(connection->channel, &buffer, NULL, 300000);
  33. if (buffer.length > 0) {
  34. UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, "Message received:");
  35. UA_NetworkMessage *actualNetworkMessage = (UA_NetworkMessage *) UA_calloc(1, sizeof(UA_NetworkMessage));
  36. size_t currentPosition = 0;
  37. if (!actualNetworkMessage) {
  38. UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_SERVER, "Networkmessage allocation failed!");
  39. UA_ByteString_deleteMembers(&buffer);
  40. return;
  41. }
  42. UA_NetworkMessage_decodeBinary(&buffer, &currentPosition, actualNetworkMessage);
  43. printf("Message length: %zu\n", buffer.length);
  44. if (actualNetworkMessage->networkMessageType == UA_NETWORKMESSAGE_DATASET) {
  45. if ((actualNetworkMessage->payloadHeaderEnabled && (actualNetworkMessage->payloadHeader.dataSetPayloadHeader.count >= 1)) ||
  46. (!actualNetworkMessage->payloadHeaderEnabled)) {
  47. if (actualNetworkMessage->payload.dataSetPayload.dataSetMessages[0].header.dataSetMessageType ==
  48. UA_DATASETMESSAGE_DATAKEYFRAME) {
  49. for (int i = 0; i < actualNetworkMessage->payload.dataSetPayload.dataSetMessages[0].data.keyFrameData.fieldCount; i++) {
  50. const UA_DataType *currentType = actualNetworkMessage->payload.dataSetPayload.dataSetMessages[0].data.keyFrameData.dataSetFields[i].value.type;
  51. if (currentType == &UA_TYPES[UA_TYPES_BYTE]) {
  52. printf("Message content: [Byte] \n\tReceived data: %i\n",
  53. *((UA_Byte *) actualNetworkMessage->payload.dataSetPayload.dataSetMessages[0].data.keyFrameData.dataSetFields[i].value.data));
  54. } else if (currentType == &UA_TYPES[UA_TYPES_DATETIME]) {
  55. UA_DateTimeStruct receivedTime = UA_DateTime_toStruct(
  56. *((UA_DateTime *) actualNetworkMessage->payload.dataSetPayload.dataSetMessages[0].data.keyFrameData.dataSetFields[i].value.data));
  57. printf("Message content: [DateTime] \n\tReceived date: %02i-%02i-%02i Received time: %02i:%02i:%02i\n", receivedTime.year, receivedTime.month,
  58. receivedTime.day, receivedTime.hour, receivedTime.min, receivedTime.sec);
  59. }
  60. }
  61. }
  62. }
  63. }
  64. }
  65. }
  66. int main(void) {
  67. signal(SIGINT, stopHandler);
  68. signal(SIGTERM, stopHandler);
  69. UA_ServerConfig *config = UA_ServerConfig_new_minimal(4801, NULL);
  70. /* Details about the PubSubTransportLayer can be found inside the tutorial_pubsub_connection */
  71. config->pubsubTransportLayers = (UA_PubSubTransportLayer *) UA_malloc(sizeof(UA_PubSubTransportLayer));
  72. if (!config->pubsubTransportLayers) {
  73. UA_ServerConfig_delete(config);
  74. return -1;
  75. }
  76. config->pubsubTransportLayers[0] = UA_PubSubTransportLayerUDPMP();
  77. config->pubsubTransportLayersSize++;
  78. UA_Server *server = UA_Server_new(config);
  79. UA_PubSubConnectionConfig connectionConfig;
  80. memset(&connectionConfig, 0, sizeof(connectionConfig));
  81. connectionConfig.name = UA_STRING("UDP-UADP Connection 1");
  82. connectionConfig.transportProfileUri = UA_STRING("http://opcfoundation.org/UA-Profile/Transport/pubsub-udp-uadp");
  83. connectionConfig.enabled = UA_TRUE;
  84. UA_NetworkAddressUrlDataType networkAddressUrl = {UA_STRING_NULL , UA_STRING("opc.udp://224.0.0.22:4840/")};
  85. UA_Variant_setScalar(&connectionConfig.address, &networkAddressUrl, &UA_TYPES[UA_TYPES_NETWORKADDRESSURLDATATYPE]);
  86. UA_NodeId connectionIdent;
  87. UA_StatusCode retval = UA_Server_addPubSubConnection(server, &connectionConfig, &connectionIdent);
  88. if(retval == UA_STATUSCODE_GOOD){
  89. UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_SERVER, "The PubSub Connection was created successfully!");
  90. }
  91. /* The following lines register the listening on the configured multicast address and configure
  92. * a repeated job, which is used to handle received messages. */
  93. UA_PubSubConnection *connection = UA_PubSubConnection_findConnectionbyId(server, connectionIdent);
  94. if (connection != NULL) {
  95. UA_StatusCode rv = connection->channel->regist(connection->channel, NULL);
  96. if (rv == UA_STATUSCODE_GOOD) {
  97. UA_UInt64 subscriptionCallbackId;
  98. UA_Server_addRepeatedCallback(server, (UA_ServerCallback)subscriptionPollingCallback, connection, 5, &subscriptionCallbackId);
  99. } else {
  100. UA_LOG_WARNING(UA_Log_Stdout, UA_LOGCATEGORY_SERVER, "register channel failed: 0x%x!", rv);
  101. }
  102. }
  103. retval |= UA_Server_run(server, &running);
  104. UA_Server_delete(server);
  105. UA_ServerConfig_delete(config);
  106. return (int)retval;
  107. }