ua_history_data_gathering_default.c 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230
  1. /* This Source Code Form is subject to the terms of the Mozilla Public
  2. * License, v. 2.0. If a copy of the MPL was not distributed with this
  3. * file, You can obtain one at http://mozilla.org/MPL/2.0/.
  4. *
  5. * Copyright 2018 (c) basysKom GmbH <opensource@basyskom.com> (Author: Peter Rustler)
  6. */
  7. #include <open62541/client_subscriptions.h>
  8. #include <open62541/plugin/historydata/history_data_gathering_default.h>
  9. #include <open62541/plugin/historydata/history_database_default.h>
  10. #include <string.h>
  11. typedef struct {
  12. UA_NodeId nodeId;
  13. UA_HistorizingNodeIdSettings setting;
  14. UA_MonitoredItemCreateResult monitoredResult;
  15. } UA_NodeIdStoreContextItem_gathering_default;
  16. typedef struct {
  17. UA_NodeIdStoreContextItem_gathering_default *dataStore;
  18. size_t storeEnd;
  19. size_t storeSize;
  20. } UA_NodeIdStoreContext;
  21. static void
  22. dataChangeCallback_gathering_default(UA_Server *server,
  23. UA_UInt32 monitoredItemId,
  24. void *monitoredItemContext,
  25. const UA_NodeId *nodeId,
  26. void *nodeContext,
  27. UA_UInt32 attributeId,
  28. const UA_DataValue *value)
  29. {
  30. UA_NodeIdStoreContextItem_gathering_default *context = (UA_NodeIdStoreContextItem_gathering_default*)monitoredItemContext;
  31. context->setting.historizingBackend.serverSetHistoryData(server,
  32. context->setting.historizingBackend.context,
  33. NULL,
  34. NULL,
  35. nodeId,
  36. UA_TRUE,
  37. value);
  38. }
  39. static UA_NodeIdStoreContextItem_gathering_default*
  40. getNodeIdStoreContextItem_gathering_default(UA_NodeIdStoreContext *context,
  41. const UA_NodeId *nodeId)
  42. {
  43. for (size_t i = 0; i < context->storeEnd; ++i) {
  44. if (UA_NodeId_equal(&context->dataStore[i].nodeId, nodeId)) {
  45. return &context->dataStore[i];
  46. }
  47. }
  48. return NULL;
  49. }
  50. static UA_StatusCode
  51. startPoll(UA_Server *server, UA_NodeIdStoreContextItem_gathering_default *item)
  52. {
  53. UA_MonitoredItemCreateRequest monitorRequest =
  54. UA_MonitoredItemCreateRequest_default(item->nodeId);
  55. monitorRequest.requestedParameters.samplingInterval = (double)item->setting.pollingInterval;
  56. monitorRequest.monitoringMode = UA_MONITORINGMODE_REPORTING;
  57. item->monitoredResult =
  58. UA_Server_createDataChangeMonitoredItem(server,
  59. UA_TIMESTAMPSTORETURN_BOTH,
  60. monitorRequest,
  61. item,
  62. &dataChangeCallback_gathering_default);
  63. return item->monitoredResult.statusCode;
  64. }
  65. static UA_StatusCode
  66. stopPoll(UA_Server *server, UA_NodeIdStoreContextItem_gathering_default *item)
  67. {
  68. UA_StatusCode retval = UA_Server_deleteMonitoredItem(server, item->monitoredResult.monitoredItemId);
  69. UA_MonitoredItemCreateResult_init(&item->monitoredResult);
  70. return retval;
  71. }
  72. static UA_StatusCode
  73. stopPoll_gathering_default(UA_Server *server,
  74. void *context,
  75. const UA_NodeId *nodeId)
  76. {
  77. UA_NodeIdStoreContext *ctx = (UA_NodeIdStoreContext *)context;
  78. UA_NodeIdStoreContextItem_gathering_default *item = getNodeIdStoreContextItem_gathering_default(ctx, nodeId);
  79. if (!item) {
  80. return UA_STATUSCODE_BADNODEIDUNKNOWN;
  81. }
  82. if (item->setting.historizingUpdateStrategy != UA_HISTORIZINGUPDATESTRATEGY_POLL)
  83. return UA_STATUSCODE_BADNODEIDINVALID;
  84. if (item->monitoredResult.monitoredItemId == 0)
  85. return UA_STATUSCODE_BADMONITOREDITEMIDINVALID;
  86. return stopPoll(server, item);
  87. }
  88. static UA_StatusCode
  89. startPoll_gathering_default(UA_Server *server,
  90. void *context,
  91. const UA_NodeId *nodeId)
  92. {
  93. UA_NodeIdStoreContext *ctx = (UA_NodeIdStoreContext *)context;
  94. UA_NodeIdStoreContextItem_gathering_default *item = getNodeIdStoreContextItem_gathering_default(ctx, nodeId);
  95. if (!item) {
  96. return UA_STATUSCODE_BADNODEIDUNKNOWN;
  97. }
  98. if (item->setting.historizingUpdateStrategy != UA_HISTORIZINGUPDATESTRATEGY_POLL)
  99. return UA_STATUSCODE_BADNODEIDINVALID;
  100. if (item->monitoredResult.monitoredItemId > 0)
  101. return UA_STATUSCODE_BADMONITOREDITEMIDINVALID;
  102. return startPoll(server, item);
  103. }
  104. static UA_StatusCode
  105. registerNodeId_gathering_default(UA_Server *server,
  106. void *context,
  107. const UA_NodeId *nodeId,
  108. const UA_HistorizingNodeIdSettings setting)
  109. {
  110. UA_NodeIdStoreContext *ctx = (UA_NodeIdStoreContext*)context;
  111. if (getNodeIdStoreContextItem_gathering_default(ctx, nodeId)) {
  112. return UA_STATUSCODE_BADNODEIDEXISTS;
  113. }
  114. if (ctx->storeEnd >= ctx->storeSize) {
  115. size_t newStoreSize = ctx->storeSize * 2;
  116. ctx->dataStore = (UA_NodeIdStoreContextItem_gathering_default*)UA_realloc(ctx->dataStore, (newStoreSize * sizeof(UA_NodeIdStoreContextItem_gathering_default)));
  117. if (!ctx->dataStore) {
  118. ctx->storeSize = 0;
  119. return UA_STATUSCODE_BADOUTOFMEMORY;
  120. }
  121. ctx->storeSize = newStoreSize;
  122. }
  123. UA_NodeId_copy(nodeId, &ctx->dataStore[ctx->storeEnd].nodeId);
  124. size_t current = ctx->storeEnd;
  125. ctx->dataStore[current].setting = setting;
  126. ++ctx->storeEnd;
  127. return UA_STATUSCODE_GOOD;
  128. }
  129. static const UA_HistorizingNodeIdSettings*
  130. getHistorizingSetting_gathering_default(UA_Server *server,
  131. void *context,
  132. const UA_NodeId *nodeId)
  133. {
  134. UA_NodeIdStoreContext *ctx = (UA_NodeIdStoreContext*)context;
  135. UA_NodeIdStoreContextItem_gathering_default *item = getNodeIdStoreContextItem_gathering_default(ctx, nodeId);
  136. if (item) {
  137. return &item->setting;
  138. }
  139. return NULL;
  140. }
  141. static void
  142. deleteMembers_gathering_default(UA_HistoryDataGathering *gathering)
  143. {
  144. if (gathering == NULL || gathering->context == NULL)
  145. return;
  146. UA_NodeIdStoreContext *ctx = (UA_NodeIdStoreContext*)gathering->context;
  147. for (size_t i = 0; i < ctx->storeEnd; ++i) {
  148. UA_NodeId_deleteMembers(&ctx->dataStore[i].nodeId);
  149. // There is still a monitored item present for this gathering
  150. // You need to remove it with UA_Server_deleteMonitoredItem
  151. UA_assert(ctx->dataStore[i].monitoredResult.monitoredItemId == 0);
  152. }
  153. UA_free(ctx->dataStore);
  154. UA_free(gathering->context);
  155. }
  156. static UA_Boolean
  157. updateNodeIdSetting_gathering_default(UA_Server *server,
  158. void *context,
  159. const UA_NodeId *nodeId,
  160. const UA_HistorizingNodeIdSettings setting)
  161. {
  162. UA_NodeIdStoreContext *ctx = (UA_NodeIdStoreContext*)context;
  163. UA_NodeIdStoreContextItem_gathering_default *item = getNodeIdStoreContextItem_gathering_default(ctx, nodeId);
  164. if (!item) {
  165. return false;
  166. }
  167. stopPoll_gathering_default(server, context, nodeId);
  168. item->setting = setting;
  169. return true;
  170. }
  171. static void
  172. setValue_gathering_default(UA_Server *server,
  173. void *context,
  174. const UA_NodeId *sessionId,
  175. void *sessionContext,
  176. const UA_NodeId *nodeId,
  177. UA_Boolean historizing,
  178. const UA_DataValue *value)
  179. {
  180. UA_NodeIdStoreContext *ctx = (UA_NodeIdStoreContext*)context;
  181. UA_NodeIdStoreContextItem_gathering_default *item = getNodeIdStoreContextItem_gathering_default(ctx, nodeId);
  182. if (!item) {
  183. return;
  184. }
  185. if (item->setting.historizingUpdateStrategy == UA_HISTORIZINGUPDATESTRATEGY_VALUESET) {
  186. item->setting.historizingBackend.serverSetHistoryData(server,
  187. item->setting.historizingBackend.context,
  188. sessionId,
  189. sessionContext,
  190. nodeId,
  191. historizing,
  192. value);
  193. }
  194. }
  195. UA_HistoryDataGathering
  196. UA_HistoryDataGathering_Default(size_t initialNodeIdStoreSize)
  197. {
  198. UA_HistoryDataGathering gathering;
  199. memset(&gathering, 0, sizeof(UA_HistoryDataGathering));
  200. gathering.setValue = &setValue_gathering_default;
  201. gathering.getHistorizingSetting = &getHistorizingSetting_gathering_default;
  202. gathering.registerNodeId = &registerNodeId_gathering_default;
  203. gathering.startPoll = &startPoll_gathering_default;
  204. gathering.stopPoll = &stopPoll_gathering_default;
  205. gathering.deleteMembers = &deleteMembers_gathering_default;
  206. gathering.updateNodeIdSetting = &updateNodeIdSetting_gathering_default;
  207. UA_NodeIdStoreContext *context = (UA_NodeIdStoreContext*)UA_calloc(1, sizeof(UA_NodeIdStoreContext));
  208. context->storeEnd = 0;
  209. context->storeSize = initialNodeIdStoreSize;
  210. context->dataStore = (UA_NodeIdStoreContextItem_gathering_default*)UA_calloc(initialNodeIdStoreSize, sizeof(UA_NodeIdStoreContextItem_gathering_default));
  211. gathering.context = context;
  212. return gathering;
  213. }