server_datasource.c 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137
  1. /*
  2. * This work is licensed under a Creative Commons CCZero 1.0 Universal License.
  3. * See http://creativecommons.org/publicdomain/zero/1.0/ for more information.
  4. */
  5. #include <time.h>
  6. #include "ua_types.h"
  7. #include <stdio.h>
  8. #include <stdlib.h>
  9. #include <signal.h>
  10. #define __USE_XOPEN2K
  11. #include <pthread.h>
  12. // provided by the open62541 lib
  13. #include "ua_server.h"
  14. // provided by the user, implementations available in the /examples folder
  15. #include "logger_stdout.h"
  16. #include "networklayer_tcp.h"
  17. /*************************/
  18. /* Read-only data source */
  19. /*************************/
  20. static UA_StatusCode readTimeData(const void *handle, UA_VariantData *data) {
  21. UA_DateTime *currentTime = UA_DateTime_new();
  22. if(!currentTime)
  23. return UA_STATUSCODE_BADOUTOFMEMORY;
  24. *currentTime = UA_DateTime_now();
  25. data->arrayLength = 1;
  26. data->dataPtr = currentTime;
  27. data->arrayDimensionsSize = -1;
  28. data->arrayDimensions = UA_NULL;
  29. return UA_STATUSCODE_GOOD;
  30. }
  31. static void releaseTimeData(const void *handle, UA_VariantData *data) {
  32. UA_DateTime_delete((UA_DateTime*)data->dataPtr);
  33. }
  34. static UA_StatusCode writeTimeData(const void *handle, const UA_VariantData *data) {
  35. return UA_STATUSCODE_BADINTERNALERROR;
  36. }
  37. /**************************/
  38. /* Read/write data source */
  39. /**************************/
  40. UA_Int32 deviceStatus = 0;
  41. pthread_rwlock_t deviceStatusLock;
  42. static void printDeviceStatus(UA_Server *server, void *data) {
  43. printf("Device Status: %i\n", deviceStatus);
  44. }
  45. static UA_StatusCode readDeviceStatus(const void *handle, UA_VariantData *data) {
  46. /* In order to reduce blocking time, we could alloc memory for every read
  47. and return a copy of the data. */
  48. pthread_rwlock_rdlock(&deviceStatusLock);
  49. data->arrayLength = 1;
  50. data->dataPtr = &deviceStatus;
  51. data->arrayDimensionsSize = -1;
  52. data->arrayDimensions = UA_NULL;
  53. return UA_STATUSCODE_GOOD;
  54. }
  55. static void releaseDeviceStatus(const void *handle, UA_VariantData *data) {
  56. /* If we allocated memory for a specific read, free the content of the
  57. variantdata. */
  58. data->dataPtr = UA_NULL;
  59. data->arrayLength = -1;
  60. pthread_rwlock_unlock(&deviceStatusLock);
  61. }
  62. static UA_StatusCode writeDeviceStatus(const void *handle, const UA_VariantData *data) {
  63. pthread_rwlock_wrlock(&deviceStatusLock);
  64. if(data->dataPtr != UA_NULL)
  65. deviceStatus = *(UA_Int32*)data->dataPtr;
  66. pthread_rwlock_unlock(&deviceStatusLock);
  67. return UA_STATUSCODE_GOOD;
  68. }
  69. UA_Boolean running = 1;
  70. static void stopHandler(int sign) {
  71. printf("Received Ctrl-C\n");
  72. running = 0;
  73. }
  74. int main(int argc, char** argv) {
  75. signal(SIGINT, stopHandler); /* catches ctrl-c */
  76. pthread_rwlock_init(&deviceStatusLock, 0);
  77. UA_Server *server = UA_Server_new();
  78. UA_Server_addNetworkLayer(server, ServerNetworkLayerTCP_new(UA_ConnectionConfig_standard, 16664));
  79. // add node with the datetime data source
  80. UA_Variant *dateVariant = UA_Variant_new();
  81. dateVariant->storageType = UA_VARIANT_DATASOURCE;
  82. dateVariant->storage.datasource = (UA_VariantDataSource)
  83. {.handle = UA_NULL,
  84. .read = readTimeData,
  85. .release = releaseTimeData,
  86. .write = writeTimeData};
  87. dateVariant->type = &UA_TYPES[UA_TYPES_DATETIME];
  88. dateVariant->typeId = UA_NODEID_STATIC(UA_TYPES_IDS[UA_TYPES_DATETIME],0);
  89. UA_QualifiedName dateName;
  90. UA_QUALIFIEDNAME_ASSIGN(dateName, "the time");
  91. UA_Server_addVariableNode(server, dateVariant, &UA_NODEID_NULL, &dateName,
  92. &UA_NODEID_STATIC(UA_NS0ID_OBJECTSFOLDER,0),
  93. &UA_NODEID_STATIC(UA_NS0ID_ORGANIZES,0));
  94. // print the status every 2 sec
  95. UA_WorkItem work = {.type = UA_WORKITEMTYPE_METHODCALL, .work.methodCall = {.method = printDeviceStatus, .data = UA_NULL} };
  96. UA_Server_addRepeatedWorkItem(server, &work, 20000000, UA_NULL);
  97. // add node with the device status data source
  98. UA_Variant *statusVariant = UA_Variant_new();
  99. statusVariant->storageType = UA_VARIANT_DATASOURCE;
  100. statusVariant->storage.datasource = (UA_VariantDataSource)
  101. {.handle = UA_NULL,
  102. .read = readDeviceStatus,
  103. .release = releaseDeviceStatus,
  104. .write = writeDeviceStatus};
  105. statusVariant->type = &UA_TYPES[UA_TYPES_INT32];
  106. statusVariant->typeId = UA_NODEID_STATIC(UA_TYPES_IDS[UA_TYPES_INT32],0);
  107. UA_QualifiedName statusName;
  108. UA_QUALIFIEDNAME_ASSIGN(statusName, "device status");
  109. UA_Server_addVariableNode(server, statusVariant, &UA_NODEID_NULL, &statusName,
  110. &UA_NODEID_STATIC(UA_NS0ID_OBJECTSFOLDER,0),
  111. &UA_NODEID_STATIC(UA_NS0ID_ORGANIZES,0));
  112. UA_StatusCode retval = UA_Server_run(server, 1, &running);
  113. UA_Server_delete(server);
  114. pthread_rwlock_destroy(&deviceStatusLock);
  115. return retval;
  116. }