ua_pubsub_ns0.c 61 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155
  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 (c) 2017-2018 Fraunhofer IOSB (Author: Andreas Ebner)
  6. * Copyright (c) 2019 Kalycito Infotech Private Limited
  7. */
  8. #include <open62541/types.h>
  9. #include "ua_pubsub_ns0.h"
  10. #ifdef UA_ENABLE_PUBSUB_INFORMATIONMODEL /* conditional compilation */
  11. typedef struct{
  12. UA_NodeId parentNodeId;
  13. UA_UInt32 parentClassifier;
  14. UA_UInt32 elementClassiefier;
  15. } UA_NodePropertyContext;
  16. //Prototypes
  17. #ifdef UA_ENABLE_PUBSUB_INFORMATIONMODEL_METHODS
  18. static UA_StatusCode addWriterGroupAction(UA_Server *server,
  19. const UA_NodeId *sessionId, void *sessionHandle,
  20. const UA_NodeId *methodId, void *methodContext,
  21. const UA_NodeId *objectId, void *objectContext,
  22. size_t inputSize, const UA_Variant *input,
  23. size_t outputSize, UA_Variant *output);
  24. static UA_StatusCode removeGroupAction(UA_Server *server,
  25. const UA_NodeId *sessionId, void *sessionHandle,
  26. const UA_NodeId *methodId, void *methodContext,
  27. const UA_NodeId *objectId, void *objectContext,
  28. size_t inputSize, const UA_Variant *input,
  29. size_t outputSize, UA_Variant *output);
  30. static UA_StatusCode addDataSetWriterAction(UA_Server *server,
  31. const UA_NodeId *sessionId, void *sessionHandle,
  32. const UA_NodeId *methodId, void *methodContext,
  33. const UA_NodeId *objectId, void *objectContext,
  34. size_t inputSize, const UA_Variant *input,
  35. size_t outputSize, UA_Variant *output);
  36. #endif
  37. static UA_StatusCode
  38. addPubSubObjectNode(UA_Server *server, char* name, UA_UInt32 objectid,
  39. UA_UInt32 parentid, UA_UInt32 referenceid, UA_UInt32 type_id) {
  40. UA_ObjectAttributes object_attr = UA_ObjectAttributes_default;
  41. object_attr.displayName = UA_LOCALIZEDTEXT("", name);
  42. return UA_Server_addObjectNode(server, UA_NODEID_NUMERIC(0, objectid),
  43. UA_NODEID_NUMERIC(0, parentid),
  44. UA_NODEID_NUMERIC(0, referenceid),
  45. UA_QUALIFIEDNAME(0, name),
  46. UA_NODEID_NUMERIC(0, type_id),
  47. object_attr, NULL, NULL);
  48. }
  49. static UA_StatusCode
  50. writePubSubNs0VariableArray(UA_Server *server, UA_UInt32 id, void *v,
  51. size_t length, const UA_DataType *type) {
  52. UA_Variant var;
  53. UA_Variant_init(&var);
  54. UA_Variant_setArray(&var, v, length, type);
  55. return UA_Server_writeValue(server, UA_NODEID_NUMERIC(0, id), var);
  56. }
  57. static UA_NodeId
  58. findSingleChildNode(UA_Server *server, UA_QualifiedName targetName,
  59. UA_NodeId referenceTypeId, UA_NodeId startingNode){
  60. UA_NodeId resultNodeId;
  61. UA_RelativePathElement rpe;
  62. UA_RelativePathElement_init(&rpe);
  63. rpe.referenceTypeId = referenceTypeId;
  64. rpe.isInverse = false;
  65. rpe.includeSubtypes = false;
  66. rpe.targetName = targetName;
  67. UA_BrowsePath bp;
  68. UA_BrowsePath_init(&bp);
  69. bp.startingNode = startingNode;
  70. bp.relativePath.elementsSize = 1;
  71. bp.relativePath.elements = &rpe;
  72. UA_BrowsePathResult bpr =
  73. UA_Server_translateBrowsePathToNodeIds(server, &bp);
  74. if(bpr.statusCode != UA_STATUSCODE_GOOD ||
  75. bpr.targetsSize < 1)
  76. return UA_NODEID_NULL;
  77. if(UA_NodeId_copy(&bpr.targets[0].targetId.nodeId, &resultNodeId) != UA_STATUSCODE_GOOD){
  78. UA_BrowsePathResult_deleteMembers(&bpr);
  79. return UA_NODEID_NULL;
  80. }
  81. UA_BrowsePathResult_deleteMembers(&bpr);
  82. return resultNodeId;
  83. }
  84. static void
  85. onRead(UA_Server *server, const UA_NodeId *sessionId, void *sessionContext,
  86. const UA_NodeId *nodeid, void *context,
  87. const UA_NumericRange *range, const UA_DataValue *data) {
  88. UA_Variant value;
  89. UA_Variant_init(&value);
  90. const UA_NodePropertyContext *nodeContext = (const UA_NodePropertyContext*)context;
  91. const UA_NodeId *myNodeId = &nodeContext->parentNodeId;
  92. switch(nodeContext->parentClassifier){
  93. case UA_NS0ID_PUBSUBCONNECTIONTYPE: {
  94. UA_PubSubConnection *pubSubConnection =
  95. UA_PubSubConnection_findConnectionbyId(server, *myNodeId);
  96. switch(nodeContext->elementClassiefier) {
  97. case UA_NS0ID_PUBSUBCONNECTIONTYPE_PUBLISHERID:
  98. if(pubSubConnection->config->publisherIdType == UA_PUBSUB_PUBLISHERID_STRING) {
  99. UA_Variant_setScalar(&value, &pubSubConnection->config->publisherId.numeric,
  100. &UA_TYPES[UA_TYPES_STRING]);
  101. } else {
  102. UA_Variant_setScalar(&value, &pubSubConnection->config->publisherId.numeric,
  103. &UA_TYPES[UA_TYPES_UINT32]);
  104. }
  105. break;
  106. default:
  107. UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER,
  108. "Read error! Unknown property.");
  109. }
  110. break;
  111. }
  112. case UA_NS0ID_WRITERGROUPTYPE: {
  113. UA_WriterGroup *writerGroup = UA_WriterGroup_findWGbyId(server, *myNodeId);
  114. if(!writerGroup)
  115. return;
  116. switch(nodeContext->elementClassiefier){
  117. case UA_NS0ID_WRITERGROUPTYPE_PUBLISHINGINTERVAL:
  118. UA_Variant_setScalar(&value, &writerGroup->config.publishingInterval,
  119. &UA_TYPES[UA_TYPES_DURATION]);
  120. break;
  121. default:
  122. UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER,
  123. "Read error! Unknown property.");
  124. }
  125. break;
  126. }
  127. case UA_NS0ID_PUBLISHEDDATAITEMSTYPE: {
  128. UA_PublishedDataSet *publishedDataSet = UA_PublishedDataSet_findPDSbyId(server, *myNodeId);
  129. if(!publishedDataSet)
  130. return;
  131. switch(nodeContext->elementClassiefier) {
  132. case UA_NS0ID_PUBLISHEDDATAITEMSTYPE_PUBLISHEDDATA: {
  133. UA_PublishedVariableDataType *pvd = (UA_PublishedVariableDataType *)
  134. UA_calloc(publishedDataSet->fieldSize, sizeof(UA_PublishedVariableDataType));
  135. size_t counter = 0;
  136. UA_DataSetField *field;
  137. TAILQ_FOREACH(field, &publishedDataSet->fields, listEntry) {
  138. pvd[counter].attributeId = UA_ATTRIBUTEID_VALUE;
  139. pvd[counter].publishedVariable = field->config.field.variable.publishParameters.publishedVariable;
  140. //UA_NodeId_copy(&field->config.field.variable.publishParameters.publishedVariable, &pvd[counter].publishedVariable);
  141. counter++;
  142. }
  143. UA_Variant_setArray(&value, pvd, publishedDataSet->fieldSize,
  144. &UA_TYPES[UA_TYPES_PUBLISHEDVARIABLEDATATYPE]);
  145. break;
  146. }
  147. case UA_NS0ID_PUBLISHEDDATAITEMSTYPE_DATASETMETADATA: {
  148. UA_Variant_setScalarCopy(&value, &publishedDataSet->dataSetMetaData, &UA_TYPES[UA_TYPES_DATASETMETADATATYPE]);
  149. break;
  150. }
  151. case UA_NS0ID_PUBLISHEDDATAITEMSTYPE_CONFIGURATIONVERSION: {
  152. UA_Variant_setScalarCopy(&value, &publishedDataSet->dataSetMetaData.configurationVersion,
  153. &UA_TYPES[UA_TYPES_CONFIGURATIONVERSIONDATATYPE]);
  154. break;
  155. }
  156. default:
  157. UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER,
  158. "Read error! Unknown property.");
  159. }
  160. break;
  161. }
  162. default:
  163. UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER,
  164. "Read error! Unknown parent element.");
  165. }
  166. UA_Server_writeValue(server, *nodeid, value);
  167. }
  168. static void
  169. onWrite(UA_Server *server, const UA_NodeId *sessionId, void *sessionContext,
  170. const UA_NodeId *nodeId, void *nodeContext,
  171. const UA_NumericRange *range, const UA_DataValue *data){
  172. UA_Variant value;
  173. UA_NodeId myNodeId;
  174. UA_WriterGroup *writerGroup = NULL;
  175. switch(((UA_NodePropertyContext *) nodeContext)->parentClassifier){
  176. case UA_NS0ID_PUBSUBCONNECTIONTYPE:
  177. //no runtime writable attributes
  178. break;
  179. case UA_NS0ID_WRITERGROUPTYPE:
  180. myNodeId = ((UA_NodePropertyContext *) nodeContext)->parentNodeId;
  181. writerGroup = UA_WriterGroup_findWGbyId(server, myNodeId);
  182. UA_WriterGroupConfig writerGroupConfig;
  183. memset(&writerGroupConfig, 0, sizeof(writerGroupConfig));
  184. if(!writerGroup)
  185. return;
  186. switch(((UA_NodePropertyContext *) nodeContext)->elementClassiefier){
  187. case UA_NS0ID_WRITERGROUPTYPE_PUBLISHINGINTERVAL:
  188. UA_Server_getWriterGroupConfig(server, writerGroup->identifier, &writerGroupConfig);
  189. writerGroupConfig.publishingInterval = *((UA_Duration *) data->value.data);
  190. UA_Server_updateWriterGroupConfig(server, writerGroup->identifier, &writerGroupConfig);
  191. UA_Variant_setScalar(&value, data->value.data, &UA_TYPES[UA_TYPES_DURATION]);
  192. UA_WriterGroupConfig_clear(&writerGroupConfig);
  193. break;
  194. default:
  195. UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER,
  196. "Write error! Unknown property element.");
  197. }
  198. break;
  199. default:
  200. UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER,
  201. "Read error! Unknown parent element.");
  202. }
  203. }
  204. static UA_StatusCode
  205. addVariableValueSource(UA_Server *server, UA_ValueCallback valueCallback,
  206. UA_NodeId node, UA_NodePropertyContext *context){
  207. UA_Server_setNodeContext(server, node, context);
  208. return UA_Server_setVariableNode_valueCallback(server, node, valueCallback);
  209. }
  210. /*************************************************/
  211. /* PubSubConnection */
  212. /*************************************************/
  213. UA_StatusCode
  214. addPubSubConnectionRepresentation(UA_Server *server, UA_PubSubConnection *connection){
  215. UA_StatusCode retVal = UA_STATUSCODE_GOOD;
  216. if(connection->config->name.length > 512)
  217. return UA_STATUSCODE_BADOUTOFMEMORY;
  218. UA_STACKARRAY(char, connectionName, sizeof(char) * connection->config->name.length +1);
  219. memcpy(connectionName, connection->config->name.data, connection->config->name.length);
  220. connectionName[connection->config->name.length] = '\0';
  221. //This code block must use a lock
  222. UA_NODESTORE_REMOVE(server, &connection->identifier);
  223. UA_NodeId pubSubConnectionNodeId;
  224. UA_ObjectAttributes attr = UA_ObjectAttributes_default;
  225. attr.displayName = UA_LOCALIZEDTEXT("de-DE", connectionName);
  226. retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_OBJECT,
  227. UA_NODEID_NUMERIC(0, connection->identifier.identifier.numeric),
  228. UA_NODEID_NUMERIC(0, UA_NS0ID_PUBLISHSUBSCRIBE),
  229. UA_NODEID_NUMERIC(0, UA_NS0ID_HASPUBSUBCONNECTION),
  230. UA_QUALIFIEDNAME(0, connectionName),
  231. UA_NODEID_NUMERIC(0, UA_NS0ID_PUBSUBCONNECTIONTYPE),
  232. (const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_OBJECTATTRIBUTES],
  233. NULL, &pubSubConnectionNodeId);
  234. addPubSubObjectNode(server, "Address", connection->identifier.identifier.numeric+1,
  235. pubSubConnectionNodeId.identifier.numeric, UA_NS0ID_HASCOMPONENT,
  236. UA_NS0ID_NETWORKADDRESSURLTYPE);
  237. UA_Server_addNode_finish(server, pubSubConnectionNodeId);
  238. //End lock zone
  239. UA_NodeId addressNode, urlNode, interfaceNode, publisherIdNode, connectionPropertieNode, transportProfileUri;
  240. addressNode = findSingleChildNode(server, UA_QUALIFIEDNAME(0, "Address"),
  241. UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
  242. UA_NODEID_NUMERIC(0, connection->identifier.identifier.numeric));
  243. urlNode = findSingleChildNode(server, UA_QUALIFIEDNAME(0, "Url"),
  244. UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT), addressNode);
  245. interfaceNode = findSingleChildNode(server, UA_QUALIFIEDNAME(0, "NetworkInterface"),
  246. UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT), addressNode);
  247. publisherIdNode = findSingleChildNode(server, UA_QUALIFIEDNAME(0, "PublisherId"),
  248. UA_NODEID_NUMERIC(0, UA_NS0ID_HASPROPERTY),
  249. UA_NODEID_NUMERIC(0, connection->identifier.identifier.numeric));
  250. connectionPropertieNode = findSingleChildNode(server, UA_QUALIFIEDNAME(0, "ConnectionProperties"),
  251. UA_NODEID_NUMERIC(0, UA_NS0ID_HASPROPERTY),
  252. UA_NODEID_NUMERIC(0, connection->identifier.identifier.numeric));
  253. transportProfileUri = findSingleChildNode(server, UA_QUALIFIEDNAME(0, "TransportProfileUri"),
  254. UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
  255. UA_NODEID_NUMERIC(0, connection->identifier.identifier.numeric));
  256. if(UA_NodeId_equal(&addressNode, &UA_NODEID_NULL) ||
  257. UA_NodeId_equal(&urlNode, &UA_NODEID_NULL) ||
  258. UA_NodeId_equal(&interfaceNode, &UA_NODEID_NULL) ||
  259. UA_NodeId_equal(&publisherIdNode, &UA_NODEID_NULL) ||
  260. UA_NodeId_equal(&connectionPropertieNode, &UA_NODEID_NULL) ||
  261. UA_NodeId_equal(&transportProfileUri, &UA_NODEID_NULL)) {
  262. return UA_STATUSCODE_BADNOTFOUND;
  263. }
  264. retVal |= writePubSubNs0VariableArray(server, connectionPropertieNode.identifier.numeric,
  265. connection->config->connectionProperties,
  266. connection->config->connectionPropertiesSize,
  267. &UA_TYPES[UA_TYPES_KEYVALUEPAIR]);
  268. UA_NetworkAddressUrlDataType *networkAddressUrlDataType = ((UA_NetworkAddressUrlDataType *) connection->config->address.data);
  269. UA_Variant value;
  270. UA_Variant_init(&value);
  271. UA_Variant_setScalar(&value, &networkAddressUrlDataType->url, &UA_TYPES[UA_TYPES_STRING]);
  272. UA_Server_writeValue(server, urlNode, value);
  273. UA_Variant_setScalar(&value, &networkAddressUrlDataType->networkInterface, &UA_TYPES[UA_TYPES_STRING]);
  274. UA_Server_writeValue(server, interfaceNode, value);
  275. UA_Variant_setScalar(&value, &connection->config->transportProfileUri, &UA_TYPES[UA_TYPES_STRING]);
  276. UA_Server_writeValue(server, transportProfileUri, value);
  277. UA_NodePropertyContext *connectionPublisherIdContext = (UA_NodePropertyContext *) UA_malloc(sizeof(UA_NodePropertyContext));
  278. connectionPublisherIdContext->parentNodeId = connection->identifier;
  279. connectionPublisherIdContext->parentClassifier = UA_NS0ID_PUBSUBCONNECTIONTYPE;
  280. connectionPublisherIdContext->elementClassiefier = UA_NS0ID_PUBSUBCONNECTIONTYPE_PUBLISHERID;
  281. UA_ValueCallback valueCallback;
  282. valueCallback.onRead = onRead;
  283. valueCallback.onWrite = NULL;
  284. retVal |= addVariableValueSource(server, valueCallback, publisherIdNode, connectionPublisherIdContext);
  285. #ifdef UA_ENABLE_PUBSUB_INFORMATIONMODEL_METHODS
  286. retVal |= UA_Server_addReference(server, connection->identifier,
  287. UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
  288. UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_PUBSUBCONNECTIONTYPE_ADDWRITERGROUP), true);
  289. retVal |= UA_Server_addReference(server, connection->identifier,
  290. UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
  291. UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_PUBSUBCONNECTIONTYPE_ADDREADERGROUP), true);
  292. retVal |= UA_Server_addReference(server, connection->identifier,
  293. UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
  294. UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_PUBSUBCONNECTIONTYPE_REMOVEGROUP), true);
  295. #endif
  296. return retVal;
  297. }
  298. #ifdef UA_ENABLE_PUBSUB_INFORMATIONMODEL_METHODS
  299. static UA_StatusCode
  300. addPubSubConnectionAction(UA_Server *server,
  301. const UA_NodeId *sessionId, void *sessionHandle,
  302. const UA_NodeId *methodId, void *methodContext,
  303. const UA_NodeId *objectId, void *objectContext,
  304. size_t inputSize, const UA_Variant *input,
  305. size_t outputSize, UA_Variant *output){
  306. UA_StatusCode retVal = UA_STATUSCODE_GOOD;
  307. UA_PubSubConnectionDataType pubSubConnectionDataType = *((UA_PubSubConnectionDataType *) input[0].data);
  308. UA_NetworkAddressUrlDataType networkAddressUrlDataType;
  309. memset(&networkAddressUrlDataType, 0, sizeof(networkAddressUrlDataType));
  310. UA_ExtensionObject eo = pubSubConnectionDataType.address;
  311. if(eo.encoding == UA_EXTENSIONOBJECT_DECODED){
  312. if(eo.content.decoded.type == &UA_TYPES[UA_TYPES_NETWORKADDRESSURLDATATYPE]){
  313. if(UA_NetworkAddressUrlDataType_copy((UA_NetworkAddressUrlDataType *) eo.content.decoded.data,
  314. &networkAddressUrlDataType) != UA_STATUSCODE_GOOD){
  315. return UA_STATUSCODE_BADOUTOFMEMORY;
  316. }
  317. }
  318. }
  319. UA_PubSubConnectionConfig connectionConfig;
  320. memset(&connectionConfig, 0, sizeof(UA_PubSubConnectionConfig));
  321. connectionConfig.transportProfileUri = pubSubConnectionDataType.transportProfileUri;
  322. connectionConfig.name = pubSubConnectionDataType.name;
  323. //TODO set real connection state
  324. connectionConfig.enabled = pubSubConnectionDataType.enabled;
  325. //connectionConfig.enabled = pubSubConnectionDataType.enabled;
  326. UA_Variant_setScalar(&connectionConfig.address, &networkAddressUrlDataType,
  327. &UA_TYPES[UA_TYPES_NETWORKADDRESSURLDATATYPE]);
  328. if(pubSubConnectionDataType.publisherId.type == &UA_TYPES[UA_TYPES_UINT32]){
  329. connectionConfig.publisherId.numeric = * ((UA_UInt32 *) pubSubConnectionDataType.publisherId.data);
  330. } else if(pubSubConnectionDataType.publisherId.type == &UA_TYPES[UA_TYPES_STRING]){
  331. connectionConfig.publisherIdType = UA_PUBSUB_PUBLISHERID_STRING;
  332. UA_String_copy((UA_String *) pubSubConnectionDataType.publisherId.data, &connectionConfig.publisherId.string);
  333. } else {
  334. UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER, "Unsupported PublisherId Type used.");
  335. //TODO what's the best default behaviour here?
  336. connectionConfig.publisherId.numeric = 0;
  337. }
  338. //call API function and create the connection
  339. UA_NodeId connectionId;
  340. retVal |= UA_Server_addPubSubConnection(server, &connectionConfig, &connectionId);
  341. if(retVal != UA_STATUSCODE_GOOD){
  342. return retVal;
  343. }
  344. for(size_t i = 0; i < pubSubConnectionDataType.writerGroupsSize; i++){
  345. //UA_PubSubConnection_addWriterGroup(server, UA_NODEID_NULL, NULL, NULL);
  346. }
  347. for(size_t i = 0; i < pubSubConnectionDataType.readerGroupsSize; i++){
  348. //UA_Server_addReaderGroup(server, NULL, NULL, NULL);
  349. }
  350. UA_NetworkAddressUrlDataType_deleteMembers(&networkAddressUrlDataType);
  351. //set ouput value
  352. UA_Variant_setScalarCopy(output, &connectionId, &UA_TYPES[UA_TYPES_NODEID]);
  353. return UA_STATUSCODE_GOOD;
  354. }
  355. #endif
  356. UA_StatusCode
  357. removePubSubConnectionRepresentation(UA_Server *server, UA_PubSubConnection *connection){
  358. UA_StatusCode retVal = UA_STATUSCODE_GOOD;
  359. #ifdef UA_ENABLE_PUBSUB_INFORMATIONMODEL_METHODS
  360. retVal |= UA_Server_deleteReference(server, connection->identifier, UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT), true,
  361. UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_PUBSUBCONNECTIONTYPE_ADDWRITERGROUP),
  362. false);
  363. retVal |= UA_Server_deleteReference(server, connection->identifier, UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT), true,
  364. UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_PUBSUBCONNECTIONTYPE_ADDREADERGROUP),
  365. false);
  366. retVal |= UA_Server_deleteReference(server, connection->identifier, UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT), true,
  367. UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_PUBSUBCONNECTIONTYPE_REMOVEGROUP),
  368. false);
  369. #endif
  370. retVal |= UA_Server_deleteNode(server, connection->identifier, true);
  371. return retVal;
  372. }
  373. #ifdef UA_ENABLE_PUBSUB_INFORMATIONMODEL_METHODS
  374. static UA_StatusCode
  375. removeConnectionAction(UA_Server *server,
  376. const UA_NodeId *sessionId, void *sessionHandle,
  377. const UA_NodeId *methodId, void *methodContext,
  378. const UA_NodeId *objectId, void *objectContext,
  379. size_t inputSize, const UA_Variant *input,
  380. size_t outputSize, UA_Variant *output){
  381. UA_StatusCode retVal = UA_STATUSCODE_GOOD;
  382. UA_NodeId nodeToRemove = *((UA_NodeId *) input[0].data);
  383. retVal |= UA_Server_removePubSubConnection(server, nodeToRemove);
  384. if(retVal == UA_STATUSCODE_BADNOTFOUND)
  385. retVal = UA_STATUSCODE_BADNODEIDUNKNOWN;
  386. return retVal;
  387. }
  388. #endif
  389. /**********************************************/
  390. /* DataSetReader */
  391. /**********************************************/
  392. UA_StatusCode
  393. addDataSetReaderRepresentation(UA_Server *server, UA_DataSetReader *dataSetReader){
  394. //TODO implement reader part
  395. return UA_STATUSCODE_BADNOTIMPLEMENTED;
  396. }
  397. #ifdef UA_ENABLE_PUBSUB_INFORMATIONMODEL_METHODS
  398. static UA_StatusCode
  399. addDataSetReaderAction(UA_Server *server,
  400. const UA_NodeId *sessionId, void *sessionHandle,
  401. const UA_NodeId *methodId, void *methodContext,
  402. const UA_NodeId *objectId, void *objectContext,
  403. size_t inputSize, const UA_Variant *input,
  404. size_t outputSize, UA_Variant *output){
  405. UA_StatusCode retVal = UA_STATUSCODE_BADNOTIMPLEMENTED;
  406. //TODO implement reader part
  407. return retVal;
  408. }
  409. #endif
  410. UA_StatusCode
  411. removeDataSetReaderRepresentation(UA_Server *server, UA_DataSetReader* dataSetReader){
  412. //TODO implement reader part
  413. return UA_STATUSCODE_BADNOTIMPLEMENTED;
  414. }
  415. #ifdef UA_ENABLE_PUBSUB_INFORMATIONMODEL_METHODS
  416. static UA_StatusCode
  417. removeDataSetReaderAction(UA_Server *server,
  418. const UA_NodeId *sessionId, void *sessionHandle,
  419. const UA_NodeId *methodId, void *methodContext,
  420. const UA_NodeId *objectId, void *objectContext,
  421. size_t inputSize, const UA_Variant *input,
  422. size_t outputSize, UA_Variant *output){
  423. UA_StatusCode retVal = UA_STATUSCODE_BADNOTIMPLEMENTED;
  424. //TODO implement reader part
  425. return retVal;
  426. }
  427. #endif
  428. /*************************************************/
  429. /* PublishedDataSet */
  430. /*************************************************/
  431. #ifdef UA_ENABLE_PUBSUB_INFORMATIONMODEL_METHODS
  432. static UA_StatusCode
  433. addDataSetFolderAction(UA_Server *server,
  434. const UA_NodeId *sessionId, void *sessionHandle,
  435. const UA_NodeId *methodId, void *methodContext,
  436. const UA_NodeId *objectId, void *objectContext,
  437. size_t inputSize, const UA_Variant *input,
  438. size_t outputSize, UA_Variant *output){
  439. /* defined in R 1.04 9.1.4.5.7 */
  440. UA_StatusCode retVal = UA_STATUSCODE_GOOD;
  441. UA_String newFolderName = *((UA_String *) input[0].data);
  442. UA_NodeId generatedId;
  443. UA_ObjectAttributes objectAttributes = UA_ObjectAttributes_default;
  444. UA_LocalizedText name = {UA_STRING("en-US"), newFolderName};
  445. objectAttributes.displayName = name;
  446. retVal |= UA_Server_addObjectNode(server, UA_NODEID_NULL, *objectId, UA_NODEID_NUMERIC(0,UA_NS0ID_ORGANIZES),
  447. UA_QUALIFIEDNAME(0, "DataSetFolder"), UA_NODEID_NUMERIC(0, UA_NS0ID_DATASETFOLDERTYPE),
  448. objectAttributes, NULL, &generatedId);
  449. UA_Variant_setScalarCopy(output, &generatedId, &UA_TYPES[UA_TYPES_NODEID]);
  450. #ifdef UA_ENABLE_PUBSUB_INFORMATIONMODEL_METHODS
  451. retVal |= UA_Server_addReference(server, generatedId,
  452. UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
  453. UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_DATASETFOLDERTYPE_ADDPUBLISHEDDATAITEMS), true);
  454. retVal |= UA_Server_addReference(server, generatedId,
  455. UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
  456. UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_DATASETFOLDERTYPE_REMOVEPUBLISHEDDATASET), true);
  457. retVal |= UA_Server_addReference(server, generatedId,
  458. UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
  459. UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_DATASETFOLDERTYPE_ADDDATASETFOLDER), true);
  460. retVal |= UA_Server_addReference(server, generatedId,
  461. UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
  462. UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_DATASETFOLDERTYPE_REMOVEDATASETFOLDER), true);
  463. #endif
  464. return retVal;
  465. }
  466. #endif
  467. #ifdef UA_ENABLE_PUBSUB_INFORMATIONMODEL_METHODS
  468. static UA_StatusCode
  469. removeDataSetFolderAction(UA_Server *server,
  470. const UA_NodeId *sessionId, void *sessionHandle,
  471. const UA_NodeId *methodId, void *methodContext,
  472. const UA_NodeId *objectId, void *objectContext,
  473. size_t inputSize, const UA_Variant *input,
  474. size_t outputSize, UA_Variant *output){
  475. UA_StatusCode retVal = UA_STATUSCODE_GOOD;
  476. UA_NodeId nodeToRemove = *((UA_NodeId *) input[0].data);
  477. #ifdef UA_ENABLE_PUBSUB_INFORMATIONMODEL_METHODS
  478. retVal |= UA_Server_deleteReference(server, nodeToRemove, UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT), true,
  479. UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_DATASETFOLDERTYPE_ADDPUBLISHEDDATAITEMS),
  480. false);
  481. retVal |= UA_Server_deleteReference(server, nodeToRemove, UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT), true,
  482. UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_DATASETFOLDERTYPE_REMOVEPUBLISHEDDATASET),
  483. false);
  484. retVal |= UA_Server_deleteReference(server, nodeToRemove, UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT), true,
  485. UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_DATASETFOLDERTYPE_ADDDATASETFOLDER),
  486. false);
  487. retVal |= UA_Server_deleteReference(server, nodeToRemove, UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT), true,
  488. UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_DATASETFOLDERTYPE_REMOVEDATASETFOLDER),
  489. false);
  490. #endif
  491. retVal |= UA_Server_deleteNode(server, nodeToRemove, false);
  492. return retVal;
  493. }
  494. #endif
  495. UA_StatusCode
  496. addPublishedDataItemsRepresentation(UA_Server *server, UA_PublishedDataSet *publishedDataSet) {
  497. UA_StatusCode retVal = UA_STATUSCODE_GOOD;
  498. if(publishedDataSet->config.name.length > 512)
  499. return UA_STATUSCODE_BADOUTOFMEMORY;
  500. UA_STACKARRAY(char, pdsName, sizeof(char) * publishedDataSet->config.name.length +1);
  501. memcpy(pdsName, publishedDataSet->config.name.data, publishedDataSet->config.name.length);
  502. pdsName[publishedDataSet->config.name.length] = '\0';
  503. //This code block must use a lock
  504. UA_NODESTORE_REMOVE(server, &publishedDataSet->identifier);
  505. retVal |= addPubSubObjectNode(server, pdsName, publishedDataSet->identifier.identifier.numeric,
  506. UA_NS0ID_PUBLISHSUBSCRIBE_PUBLISHEDDATASETS,
  507. UA_NS0ID_HASPROPERTY, UA_NS0ID_PUBLISHEDDATAITEMSTYPE);
  508. //End lock zone
  509. UA_ValueCallback valueCallback;
  510. valueCallback.onRead = onRead;
  511. valueCallback.onWrite = NULL;
  512. UA_NodeId configurationVersionNode =
  513. findSingleChildNode(server, UA_QUALIFIEDNAME(0, "ConfigurationVersion"),
  514. UA_NODEID_NUMERIC(0, UA_NS0ID_HASPROPERTY),
  515. UA_NODEID_NUMERIC(0, publishedDataSet->identifier.identifier.numeric));
  516. if(UA_NodeId_equal(&configurationVersionNode, &UA_NODEID_NULL))
  517. return UA_STATUSCODE_BADNOTFOUND;
  518. UA_NodePropertyContext * configurationVersionContext = (UA_NodePropertyContext *)
  519. UA_malloc(sizeof(UA_NodePropertyContext));
  520. configurationVersionContext->parentNodeId = publishedDataSet->identifier;
  521. configurationVersionContext->parentClassifier = UA_NS0ID_PUBLISHEDDATAITEMSTYPE;
  522. configurationVersionContext->elementClassiefier =
  523. UA_NS0ID_PUBLISHEDDATAITEMSTYPE_CONFIGURATIONVERSION;
  524. retVal |= addVariableValueSource(server, valueCallback, configurationVersionNode,
  525. configurationVersionContext);
  526. UA_NodeId publishedDataNode =
  527. findSingleChildNode(server, UA_QUALIFIEDNAME(0, "PublishedData"),
  528. UA_NODEID_NUMERIC(0, UA_NS0ID_HASPROPERTY),
  529. UA_NODEID_NUMERIC(0, publishedDataSet->identifier.identifier.numeric));
  530. if(UA_NodeId_equal(&publishedDataNode, &UA_NODEID_NULL))
  531. return UA_STATUSCODE_BADNOTFOUND;
  532. UA_NodePropertyContext * publishingIntervalContext = (UA_NodePropertyContext *)
  533. UA_malloc(sizeof(UA_NodePropertyContext));
  534. publishingIntervalContext->parentNodeId = publishedDataSet->identifier;
  535. publishingIntervalContext->parentClassifier = UA_NS0ID_PUBLISHEDDATAITEMSTYPE;
  536. publishingIntervalContext->elementClassiefier = UA_NS0ID_PUBLISHEDDATAITEMSTYPE_PUBLISHEDDATA;
  537. retVal |= addVariableValueSource(server, valueCallback, publishedDataNode,
  538. publishingIntervalContext);
  539. UA_NodeId dataSetMetaDataNode =
  540. findSingleChildNode(server, UA_QUALIFIEDNAME(0, "DataSetMetaData"),
  541. UA_NODEID_NUMERIC(0, UA_NS0ID_HASPROPERTY),
  542. UA_NODEID_NUMERIC(0, publishedDataSet->identifier.identifier.numeric));
  543. if(UA_NodeId_equal(&dataSetMetaDataNode, &UA_NODEID_NULL))
  544. return UA_STATUSCODE_BADNOTFOUND;
  545. UA_NodePropertyContext *metaDataContext = (UA_NodePropertyContext *)
  546. UA_malloc(sizeof(UA_NodePropertyContext));
  547. metaDataContext->parentNodeId = publishedDataSet->identifier;
  548. metaDataContext->parentClassifier = UA_NS0ID_PUBLISHEDDATAITEMSTYPE;
  549. metaDataContext->elementClassiefier = UA_NS0ID_PUBLISHEDDATAITEMSTYPE_DATASETMETADATA;
  550. retVal |= addVariableValueSource(server, valueCallback, dataSetMetaDataNode, metaDataContext);
  551. #ifdef UA_ENABLE_PUBSUB_INFORMATIONMODEL_METHODS
  552. retVal |= UA_Server_addReference(server, publishedDataSet->identifier,
  553. UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
  554. UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_PUBLISHEDDATAITEMSTYPE_ADDVARIABLES), true);
  555. retVal |= UA_Server_addReference(server, publishedDataSet->identifier,
  556. UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
  557. UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_PUBLISHEDDATAITEMSTYPE_REMOVEVARIABLES), true);
  558. #endif
  559. return retVal;
  560. }
  561. #ifdef UA_ENABLE_PUBSUB_INFORMATIONMODEL_METHODS
  562. static UA_StatusCode
  563. addPublishedDataItemsAction(UA_Server *server,
  564. const UA_NodeId *sessionId, void *sessionHandle,
  565. const UA_NodeId *methodId, void *methodContext,
  566. const UA_NodeId *objectId, void *objectContext,
  567. size_t inputSize, const UA_Variant *input,
  568. size_t outputSize, UA_Variant *output){
  569. UA_StatusCode retVal = UA_STATUSCODE_GOOD;
  570. size_t fieldNameAliasesSize = input[1].arrayLength;
  571. UA_String * fieldNameAliases = (UA_String *) input[1].data;
  572. size_t fieldFlagsSize = input[2].arrayLength;
  573. UA_DataSetFieldFlags * fieldFlags = (UA_DataSetFieldFlags *) input[2].data;
  574. size_t variablesToAddSize = input[3].arrayLength;
  575. UA_PublishedVariableDataType *variablesToAddField = (UA_PublishedVariableDataType *) input[3].data;
  576. if(!(fieldNameAliasesSize == fieldFlagsSize || fieldFlagsSize == variablesToAddSize))
  577. return UA_STATUSCODE_BADINVALIDARGUMENT;
  578. UA_PublishedDataSetConfig publishedDataSetConfig;
  579. memset(&publishedDataSetConfig, 0, sizeof(publishedDataSetConfig));
  580. publishedDataSetConfig.name = *((UA_String *) input[0].data);
  581. publishedDataSetConfig.publishedDataSetType = UA_PUBSUB_DATASET_PUBLISHEDITEMS;
  582. UA_NodeId dataSetItemsNodeId;
  583. retVal |= UA_Server_addPublishedDataSet(server, &publishedDataSetConfig, &dataSetItemsNodeId).addResult;
  584. UA_DataSetFieldConfig dataSetFieldConfig;
  585. for(size_t j = 0; j < variablesToAddSize; ++j) {
  586. memset(&dataSetFieldConfig, 0, sizeof(dataSetFieldConfig));
  587. dataSetFieldConfig.dataSetFieldType = UA_PUBSUB_DATASETFIELD_VARIABLE;
  588. dataSetFieldConfig.field.variable.fieldNameAlias = fieldNameAliases[j];
  589. if(fieldFlags[j] == UA_DATASETFIELDFLAGS_PROMOTEDFIELD){
  590. dataSetFieldConfig.field.variable.promotedField = UA_TRUE;
  591. }
  592. dataSetFieldConfig.field.variable.publishParameters = variablesToAddField[j];
  593. UA_Server_addDataSetField(server, dataSetItemsNodeId, &dataSetFieldConfig, NULL);
  594. }
  595. UA_PublishedVariableDataType_clear(variablesToAddField);
  596. return retVal;
  597. }
  598. #endif
  599. #ifdef UA_ENABLE_PUBSUB_INFORMATIONMODEL_METHODS
  600. static UA_StatusCode
  601. addVariablesAction(UA_Server *server,
  602. const UA_NodeId *sessionId, void *sessionHandle,
  603. const UA_NodeId *methodId, void *methodContext,
  604. const UA_NodeId *objectId, void *objectContext,
  605. size_t inputSize, const UA_Variant *input,
  606. size_t outputSize, UA_Variant *output){
  607. UA_StatusCode retVal = UA_STATUSCODE_GOOD;
  608. return retVal;
  609. }
  610. static UA_StatusCode
  611. removeVariablesAction(UA_Server *server,
  612. const UA_NodeId *sessionId, void *sessionHandle,
  613. const UA_NodeId *methodId, void *methodContext,
  614. const UA_NodeId *objectId, void *objectContext,
  615. size_t inputSize, const UA_Variant *input,
  616. size_t outputSize, UA_Variant *output){
  617. UA_StatusCode retVal = UA_STATUSCODE_GOOD;
  618. return retVal;
  619. }
  620. #endif
  621. UA_StatusCode
  622. removePublishedDataSetRepresentation(UA_Server *server, UA_PublishedDataSet *publishedDataSet){
  623. UA_StatusCode retVal = UA_STATUSCODE_GOOD;
  624. retVal |= UA_Server_deleteNode(server, publishedDataSet->identifier, false);
  625. return retVal;
  626. }
  627. #ifdef UA_ENABLE_PUBSUB_INFORMATIONMODEL_METHODS
  628. static UA_StatusCode
  629. removePublishedDataSetAction(UA_Server *server,
  630. const UA_NodeId *sessionId, void *sessionHandle,
  631. const UA_NodeId *methodId, void *methodContext,
  632. const UA_NodeId *objectId, void *objectContext,
  633. size_t inputSize, const UA_Variant *input,
  634. size_t outputSize, UA_Variant *output){
  635. UA_StatusCode retVal = UA_STATUSCODE_GOOD;
  636. UA_NodeId nodeToRemove = *((UA_NodeId *) input[0].data);
  637. retVal |= UA_Server_removePublishedDataSet(server, nodeToRemove);
  638. return retVal;
  639. }
  640. #endif
  641. /**********************************************/
  642. /* WriterGroup */
  643. /**********************************************/
  644. static UA_StatusCode
  645. readContentMask(UA_Server *server, const UA_NodeId *sessionId,
  646. void *sessionContext, const UA_NodeId *nodeId,
  647. void *nodeContext, UA_Boolean includeSourceTimeStamp,
  648. const UA_NumericRange *range, UA_DataValue *value) {
  649. UA_WriterGroup *writerGroup = (UA_WriterGroup*)nodeContext;
  650. if((writerGroup->config.messageSettings.encoding != UA_EXTENSIONOBJECT_DECODED &&
  651. writerGroup->config.messageSettings.encoding != UA_EXTENSIONOBJECT_DECODED_NODELETE) ||
  652. writerGroup->config.messageSettings.content.decoded.type !=
  653. &UA_TYPES[UA_TYPES_UADPWRITERGROUPMESSAGEDATATYPE])
  654. return UA_STATUSCODE_BADINTERNALERROR;
  655. UA_UadpWriterGroupMessageDataType *wgm = (UA_UadpWriterGroupMessageDataType*)
  656. writerGroup->config.messageSettings.content.decoded.data;
  657. UA_Variant_setScalarCopy(&value->value, &wgm->networkMessageContentMask,
  658. &UA_TYPES[UA_TYPES_UADPNETWORKMESSAGECONTENTMASK]);
  659. value->hasValue = true;
  660. return UA_STATUSCODE_GOOD;
  661. }
  662. static UA_StatusCode
  663. writeContentMask(UA_Server *server, const UA_NodeId *sessionId,
  664. void *sessionContext, const UA_NodeId *nodeId,
  665. void *nodeContext, const UA_NumericRange *range,
  666. const UA_DataValue *value) {
  667. UA_WriterGroup *writerGroup = (UA_WriterGroup*)nodeContext;
  668. if((writerGroup->config.messageSettings.encoding != UA_EXTENSIONOBJECT_DECODED &&
  669. writerGroup->config.messageSettings.encoding != UA_EXTENSIONOBJECT_DECODED_NODELETE) ||
  670. writerGroup->config.messageSettings.content.decoded.type !=
  671. &UA_TYPES[UA_TYPES_UADPWRITERGROUPMESSAGEDATATYPE])
  672. return UA_STATUSCODE_BADINTERNALERROR;
  673. UA_UadpWriterGroupMessageDataType *wgm = (UA_UadpWriterGroupMessageDataType*)
  674. writerGroup->config.messageSettings.content.decoded.data;
  675. if(!value->value.type)
  676. return UA_STATUSCODE_BADTYPEMISMATCH;
  677. if(value->value.type->typeKind != UA_DATATYPEKIND_ENUM &&
  678. value->value.type->typeKind != UA_DATATYPEKIND_INT32)
  679. return UA_STATUSCODE_BADTYPEMISMATCH;
  680. wgm->networkMessageContentMask = *(UA_UadpNetworkMessageContentMask*)value->value.data;
  681. return UA_STATUSCODE_GOOD;
  682. }
  683. UA_StatusCode
  684. addWriterGroupRepresentation(UA_Server *server, UA_WriterGroup *writerGroup){
  685. UA_StatusCode retVal = UA_STATUSCODE_GOOD;
  686. if(writerGroup->config.name.length > 512)
  687. return UA_STATUSCODE_BADOUTOFMEMORY;
  688. UA_STACKARRAY(char, wgName, sizeof(char) * writerGroup->config.name.length + 1);
  689. memcpy(wgName, writerGroup->config.name.data, writerGroup->config.name.length);
  690. wgName[writerGroup->config.name.length] = '\0';
  691. //This code block must use a lock
  692. UA_NODESTORE_REMOVE(server, &writerGroup->identifier);
  693. retVal |= addPubSubObjectNode(server, wgName, writerGroup->identifier.identifier.numeric,
  694. writerGroup->linkedConnection->identifier.identifier.numeric,
  695. UA_NS0ID_HASCOMPONENT, UA_NS0ID_WRITERGROUPTYPE);
  696. //End lock zone
  697. UA_NodeId keepAliveNode =
  698. findSingleChildNode(server, UA_QUALIFIEDNAME(0, "KeepAliveTime"),
  699. UA_NODEID_NUMERIC(0, UA_NS0ID_HASPROPERTY),
  700. UA_NODEID_NUMERIC(0, writerGroup->identifier.identifier.numeric));
  701. UA_NodeId publishingIntervalNode =
  702. findSingleChildNode(server, UA_QUALIFIEDNAME(0, "PublishingInterval"),
  703. UA_NODEID_NUMERIC(0, UA_NS0ID_HASPROPERTY),
  704. UA_NODEID_NUMERIC(0, writerGroup->identifier.identifier.numeric));
  705. if(UA_NodeId_equal(&keepAliveNode, &UA_NODEID_NULL) ||
  706. UA_NodeId_equal(&publishingIntervalNode, &UA_NODEID_NULL))
  707. return UA_STATUSCODE_BADNOTFOUND;
  708. UA_NodePropertyContext * publishingIntervalContext = (UA_NodePropertyContext *)
  709. UA_malloc(sizeof(UA_NodePropertyContext));
  710. publishingIntervalContext->parentNodeId = writerGroup->identifier;
  711. publishingIntervalContext->parentClassifier = UA_NS0ID_WRITERGROUPTYPE;
  712. publishingIntervalContext->elementClassiefier = UA_NS0ID_WRITERGROUPTYPE_PUBLISHINGINTERVAL;
  713. UA_ValueCallback valueCallback;
  714. valueCallback.onRead = onRead;
  715. valueCallback.onWrite = onWrite;
  716. retVal |= addVariableValueSource(server, valueCallback,
  717. publishingIntervalNode, publishingIntervalContext);
  718. UA_Server_writeAccessLevel(server, publishingIntervalNode,
  719. UA_ACCESSLEVELMASK_READ ^ UA_ACCESSLEVELMASK_WRITE);
  720. UA_NodeId priorityNode =
  721. findSingleChildNode(server, UA_QUALIFIEDNAME(0, "Priority"),
  722. UA_NODEID_NUMERIC(0, UA_NS0ID_HASPROPERTY),
  723. UA_NODEID_NUMERIC(0, writerGroup->identifier.identifier.numeric));
  724. UA_NodeId writerGroupIdNode =
  725. findSingleChildNode(server, UA_QUALIFIEDNAME(0, "WriterGroupId"),
  726. UA_NODEID_NUMERIC(0, UA_NS0ID_HASPROPERTY),
  727. UA_NODEID_NUMERIC(0, writerGroup->identifier.identifier.numeric));
  728. UA_Variant value;
  729. UA_Variant_init(&value);
  730. UA_Variant_setScalar(&value, &writerGroup->config.publishingInterval, &UA_TYPES[UA_TYPES_DURATION]);
  731. UA_Server_writeValue(server, publishingIntervalNode, value);
  732. UA_Variant_setScalar(&value, &writerGroup->config.keepAliveTime, &UA_TYPES[UA_TYPES_DURATION]);
  733. UA_Server_writeValue(server, keepAliveNode, value);
  734. UA_Variant_setScalar(&value, &writerGroup->config.priority, &UA_TYPES[UA_TYPES_BYTE]);
  735. UA_Server_writeValue(server, priorityNode, value);
  736. UA_Variant_setScalar(&value, &writerGroup->config.writerGroupId, &UA_TYPES[UA_TYPES_UINT16]);
  737. UA_Server_writeValue(server, writerGroupIdNode, value);
  738. retVal |= addPubSubObjectNode(server, "MessageSettings", 0,
  739. writerGroup->identifier.identifier.numeric,
  740. UA_NS0ID_HASCOMPONENT, UA_NS0ID_UADPWRITERGROUPMESSAGETYPE);
  741. /* Find the variable with the content mask */
  742. UA_NodeId messageSettingsId =
  743. findSingleChildNode(server, UA_QUALIFIEDNAME(0, "MessageSettings"),
  744. UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
  745. UA_NODEID_NUMERIC(0, writerGroup->identifier.identifier.numeric));
  746. UA_NodeId contentMaskId =
  747. findSingleChildNode(server, UA_QUALIFIEDNAME(0, "NetworkMessageContentMask"),
  748. UA_NODEID_NUMERIC(0, UA_NS0ID_HASPROPERTY), messageSettingsId);
  749. if(UA_NodeId_equal(&messageSettingsId, &UA_NODEID_NULL) ||
  750. UA_NodeId_equal(&contentMaskId, &UA_NODEID_NULL)) {
  751. return UA_STATUSCODE_BADNOTFOUND;
  752. }
  753. /* Set the callback */
  754. UA_DataSource ds;
  755. ds.read = readContentMask;
  756. ds.write = writeContentMask;
  757. UA_Server_setVariableNode_dataSource(server, contentMaskId, ds);
  758. UA_Server_setNodeContext(server, contentMaskId, writerGroup);
  759. /* Make writable */
  760. UA_Server_writeAccessLevel(server, contentMaskId,
  761. UA_ACCESSLEVELMASK_WRITE | UA_ACCESSLEVELMASK_READ);
  762. return retVal;
  763. }
  764. #ifdef UA_ENABLE_PUBSUB_INFORMATIONMODEL_METHODS
  765. static UA_StatusCode
  766. addWriterGroupAction(UA_Server *server,
  767. const UA_NodeId *sessionId, void *sessionHandle,
  768. const UA_NodeId *methodId, void *methodContext,
  769. const UA_NodeId *objectId, void *objectContext,
  770. size_t inputSize, const UA_Variant *input,
  771. size_t outputSize, UA_Variant *output){
  772. UA_StatusCode retVal = UA_STATUSCODE_GOOD;
  773. UA_WriterGroupDataType *writerGroupDataType = ((UA_WriterGroupDataType *) input[0].data);
  774. UA_NodeId generatedId;
  775. UA_WriterGroupConfig writerGroupConfig;
  776. memset(&writerGroupConfig, 0, sizeof(UA_WriterGroupConfig));
  777. writerGroupConfig.name = writerGroupDataType->name;
  778. writerGroupConfig.publishingInterval = writerGroupDataType->publishingInterval;
  779. writerGroupConfig.writerGroupId = writerGroupDataType->writerGroupId;
  780. writerGroupConfig.enabled = writerGroupDataType->enabled;
  781. writerGroupConfig.priority = writerGroupDataType->priority;
  782. //TODO remove hard coded UADP
  783. writerGroupConfig.encodingMimeType = UA_PUBSUB_ENCODING_UADP;
  784. //ToDo transfer all arguments to internal WGConfiguration
  785. retVal |= UA_Server_addWriterGroup(server, *objectId, &writerGroupConfig, &generatedId);
  786. UA_Variant_setScalarCopy(output, &generatedId, &UA_TYPES[UA_TYPES_NODEID]);
  787. return retVal;
  788. }
  789. #endif
  790. UA_StatusCode
  791. removeGroupRepresentation(UA_Server *server, UA_WriterGroup *writerGroup) {
  792. UA_StatusCode retVal = UA_STATUSCODE_GOOD;
  793. retVal |= UA_Server_deleteNode(server, writerGroup->identifier, false);
  794. return retVal;
  795. }
  796. #ifdef UA_ENABLE_PUBSUB_INFORMATIONMODEL_METHODS
  797. static UA_StatusCode
  798. removeGroupAction(UA_Server *server,
  799. const UA_NodeId *sessionId, void *sessionHandle,
  800. const UA_NodeId *methodId, void *methodContext,
  801. const UA_NodeId *objectId, void *objectContext,
  802. size_t inputSize, const UA_Variant *input,
  803. size_t outputSize, UA_Variant *output){
  804. UA_StatusCode retVal = UA_STATUSCODE_GOOD;
  805. UA_NodeId nodeToRemove = *((UA_NodeId *) input[0].data);
  806. if(UA_WriterGroup_findWGbyId(server, nodeToRemove) != NULL)
  807. retVal |= UA_Server_removeWriterGroup(server, nodeToRemove);
  808. //else
  809. //retVal |= UA_Server_removeReaderGroup(server, nodeToRemve);
  810. return retVal;
  811. }
  812. #endif
  813. /**********************************************/
  814. /* ReaderGroup */
  815. /**********************************************/
  816. UA_StatusCode
  817. addReaderGroupRepresentation(UA_Server *server, UA_ReaderGroup *readerGroup){
  818. //TODO implement reader part
  819. return UA_STATUSCODE_BADNOTIMPLEMENTED;
  820. }
  821. #ifdef UA_ENABLE_PUBSUB_INFORMATIONMODEL_METHODS
  822. static UA_StatusCode
  823. addReaderGroupAction(UA_Server *server,
  824. const UA_NodeId *sessionId, void *sessionHandle,
  825. const UA_NodeId *methodId, void *methodContext,
  826. const UA_NodeId *objectId, void *objectContext,
  827. size_t inputSize, const UA_Variant *input,
  828. size_t outputSize, UA_Variant *output){
  829. UA_StatusCode retVal = UA_STATUSCODE_GOOD;
  830. //TODO implement reader part
  831. return retVal;
  832. }
  833. #endif
  834. /**********************************************/
  835. /* DataSetWriter */
  836. /**********************************************/
  837. UA_StatusCode
  838. addDataSetWriterRepresentation(UA_Server *server, UA_DataSetWriter *dataSetWriter){
  839. UA_StatusCode retVal = UA_STATUSCODE_GOOD;
  840. if(dataSetWriter->config.name.length > 512)
  841. return UA_STATUSCODE_BADOUTOFMEMORY;
  842. UA_STACKARRAY(char, dswName, sizeof(char) * dataSetWriter->config.name.length + 1);
  843. memcpy(dswName, dataSetWriter->config.name.data, dataSetWriter->config.name.length);
  844. dswName[dataSetWriter->config.name.length] = '\0';
  845. //This code block must use a lock
  846. UA_NODESTORE_REMOVE(server, &dataSetWriter->identifier);
  847. retVal |= addPubSubObjectNode(server, dswName, dataSetWriter->identifier.identifier.numeric,
  848. dataSetWriter->linkedWriterGroup.identifier.numeric,
  849. UA_NS0ID_HASDATASETWRITER, UA_NS0ID_DATASETWRITERTYPE);
  850. //End lock zone
  851. retVal |= UA_Server_addReference(server, dataSetWriter->connectedDataSet,
  852. UA_NODEID_NUMERIC(0, UA_NS0ID_DATASETTOWRITER),
  853. UA_EXPANDEDNODEID_NUMERIC(0, dataSetWriter->identifier.identifier.numeric), true);
  854. retVal |= addPubSubObjectNode(server, "MessageSettings", 0,
  855. dataSetWriter->identifier.identifier.numeric,
  856. UA_NS0ID_HASCOMPONENT, UA_NS0ID_UADPDATASETWRITERMESSAGETYPE);
  857. return retVal;
  858. }
  859. #ifdef UA_ENABLE_PUBSUB_INFORMATIONMODEL_METHODS
  860. static UA_StatusCode
  861. addDataSetWriterAction(UA_Server *server,
  862. const UA_NodeId *sessionId, void *sessionHandle,
  863. const UA_NodeId *methodId, void *methodContext,
  864. const UA_NodeId *objectId, void *objectContext,
  865. size_t inputSize, const UA_Variant *input,
  866. size_t outputSize, UA_Variant *output){
  867. UA_DataSetWriterDataType *dataSetWriterDataType = (UA_DataSetWriterDataType *) input[0].data;
  868. UA_NodeId targetPDS = UA_NODEID_NULL;
  869. for(size_t i = 0; i < server->pubSubManager.publishedDataSetsSize; ++i) {
  870. if(UA_String_equal(&dataSetWriterDataType->dataSetName,
  871. &server->pubSubManager.publishedDataSets[i].config.name)){
  872. targetPDS = server->pubSubManager.publishedDataSets[i].identifier;
  873. }
  874. }
  875. if(UA_NodeId_isNull(&targetPDS))
  876. return UA_STATUSCODE_BADPARENTNODEIDINVALID;
  877. UA_NodeId generatedId;
  878. UA_DataSetWriterConfig dataSetWriterConfig;
  879. memset(&dataSetWriterConfig, 0, sizeof(UA_DataSetWriterConfig));
  880. dataSetWriterConfig.name = dataSetWriterDataType->name;
  881. dataSetWriterConfig.dataSetName = dataSetWriterDataType->dataSetName;
  882. dataSetWriterConfig.keyFrameCount = dataSetWriterDataType->keyFrameCount;
  883. dataSetWriterConfig.dataSetWriterId = dataSetWriterDataType->dataSetWriterId;
  884. UA_Server_addDataSetWriter(server, *objectId, targetPDS, &dataSetWriterConfig, &generatedId);
  885. UA_Variant_setScalarCopy(output, &generatedId, &UA_TYPES[UA_TYPES_NODEID]);
  886. return UA_STATUSCODE_GOOD;
  887. }
  888. #endif
  889. UA_StatusCode
  890. removeDataSetWriterRepresentation(UA_Server *server, UA_DataSetWriter *dataSetWriter) {
  891. UA_StatusCode retVal = UA_STATUSCODE_GOOD;
  892. retVal |= UA_Server_deleteNode(server, dataSetWriter->identifier, false);
  893. return retVal;
  894. }
  895. #ifdef UA_ENABLE_PUBSUB_INFORMATIONMODEL_METHODS
  896. static UA_StatusCode
  897. removeDataSetWriterAction(UA_Server *server,
  898. const UA_NodeId *sessionId, void *sessionHandle,
  899. const UA_NodeId *methodId, void *methodContext,
  900. const UA_NodeId *objectId, void *objectContext,
  901. size_t inputSize, const UA_Variant *input,
  902. size_t outputSize, UA_Variant *output){
  903. UA_StatusCode retVal = UA_STATUSCODE_GOOD;
  904. UA_NodeId nodeToRemove = *((UA_NodeId *) input[0].data);
  905. retVal |= UA_Server_removeDataSetWriter(server, nodeToRemove);
  906. return retVal;
  907. }
  908. #endif
  909. /**********************************************/
  910. /* Destructors */
  911. /**********************************************/
  912. static void
  913. connectionTypeDestructor(UA_Server *server,
  914. const UA_NodeId *sessionId, void *sessionContext,
  915. const UA_NodeId *typeId, void *typeContext,
  916. const UA_NodeId *nodeId, void **nodeContext) {
  917. UA_LOG_INFO(&server->config.logger, UA_LOGCATEGORY_USERLAND, "Connection destructor called!");
  918. UA_NodeId publisherIdNode;
  919. publisherIdNode = findSingleChildNode(server, UA_QUALIFIEDNAME(0, "PublisherId"),
  920. UA_NODEID_NUMERIC(0, UA_NS0ID_HASPROPERTY), *nodeId);
  921. UA_NodePropertyContext *internalConnectionContext;
  922. UA_Server_getNodeContext(server, publisherIdNode, (void **) &internalConnectionContext);
  923. if(!UA_NodeId_equal(&UA_NODEID_NULL , &publisherIdNode)){
  924. UA_free(internalConnectionContext);
  925. }
  926. }
  927. static void
  928. writerGroupTypeDestructor(UA_Server *server,
  929. const UA_NodeId *sessionId, void *sessionContext,
  930. const UA_NodeId *typeId, void *typeContext,
  931. const UA_NodeId *nodeId, void **nodeContext) {
  932. UA_LOG_INFO(&server->config.logger, UA_LOGCATEGORY_USERLAND, "WriterGroup destructor called!");
  933. UA_NodeId intervalNode;
  934. intervalNode = findSingleChildNode(server, UA_QUALIFIEDNAME(0, "PublishingInterval"),
  935. UA_NODEID_NUMERIC(0, UA_NS0ID_HASPROPERTY), *nodeId);
  936. UA_NodePropertyContext *internalConnectionContext;
  937. UA_Server_getNodeContext(server, intervalNode, (void **) &internalConnectionContext);
  938. if(!UA_NodeId_equal(&UA_NODEID_NULL , &intervalNode)){
  939. UA_free(internalConnectionContext);
  940. }
  941. }
  942. static void
  943. readerGroupTypeDestructor(UA_Server *server,
  944. const UA_NodeId *sessionId, void *sessionContext,
  945. const UA_NodeId *typeId, void *typeContext,
  946. const UA_NodeId *nodeId, void **nodeContext) {
  947. UA_LOG_INFO(&server->config.logger, UA_LOGCATEGORY_USERLAND, "ReaderGroup destructor called!");
  948. }
  949. static void
  950. dataSetWriterTypeDestructor(UA_Server *server,
  951. const UA_NodeId *sessionId, void *sessionContext,
  952. const UA_NodeId *typeId, void *typeContext,
  953. const UA_NodeId *nodeId, void **nodeContext) {
  954. UA_LOG_INFO(&server->config.logger, UA_LOGCATEGORY_USERLAND, "DataSetWriter destructor called!");
  955. }
  956. static void
  957. dataSetReaderTypeDestructor(UA_Server *server,
  958. const UA_NodeId *sessionId, void *sessionContext,
  959. const UA_NodeId *typeId, void *typeContext,
  960. const UA_NodeId *nodeId, void **nodeContext) {
  961. UA_LOG_INFO(&server->config.logger, UA_LOGCATEGORY_USERLAND, "DataSetReader destructor called!");
  962. }
  963. static void
  964. publishedDataItemsTypeDestructor(UA_Server *server,
  965. const UA_NodeId *sessionId, void *sessionContext,
  966. const UA_NodeId *typeId, void *typeContext,
  967. const UA_NodeId *nodeId, void **nodeContext) {
  968. UA_LOG_INFO(&server->config.logger, UA_LOGCATEGORY_USERLAND,
  969. "PublishedDataItems destructor called!");
  970. void *childContext;
  971. UA_NodeId node = findSingleChildNode(server, UA_QUALIFIEDNAME(0, "PublishedData"),
  972. UA_NODEID_NUMERIC(0, UA_NS0ID_HASPROPERTY), *nodeId);
  973. UA_Server_getNodeContext(server, node, (void**)&childContext);
  974. if(!UA_NodeId_equal(&UA_NODEID_NULL , &node))
  975. UA_free(childContext);
  976. node = findSingleChildNode(server, UA_QUALIFIEDNAME(0, "ConfigurationVersion"),
  977. UA_NODEID_NUMERIC(0, UA_NS0ID_HASPROPERTY),
  978. *nodeId);
  979. UA_Server_getNodeContext(server, node, (void**)&childContext);
  980. if(!UA_NodeId_equal(&UA_NODEID_NULL , &node))
  981. UA_free(childContext);
  982. node = findSingleChildNode(server, UA_QUALIFIEDNAME(0, "DataSetMetaData"),
  983. UA_NODEID_NUMERIC(0, UA_NS0ID_HASPROPERTY), *nodeId);
  984. UA_Server_getNodeContext(server, node, (void**)&childContext);
  985. if(!UA_NodeId_equal(&node, &UA_NODEID_NULL))
  986. UA_free(childContext);
  987. }
  988. UA_StatusCode
  989. UA_Server_initPubSubNS0(UA_Server *server) {
  990. UA_StatusCode retVal = UA_STATUSCODE_GOOD;
  991. UA_String profileArray[1];
  992. profileArray[0] = UA_STRING("http://opcfoundation.org/UA-Profile/Transport/pubsub-udp-uadp");
  993. retVal |= writePubSubNs0VariableArray(server, UA_NS0ID_PUBLISHSUBSCRIBE_SUPPORTEDTRANSPORTPROFILES,
  994. profileArray,
  995. 1, &UA_TYPES[UA_TYPES_STRING]);
  996. #ifdef UA_ENABLE_PUBSUB_INFORMATIONMODEL_METHODS
  997. retVal |= UA_Server_setMethodNode_callback(server,
  998. UA_NODEID_NUMERIC(0, UA_NS0ID_PUBLISHSUBSCRIBE_ADDCONNECTION), addPubSubConnectionAction);
  999. retVal |= UA_Server_setMethodNode_callback(server,
  1000. UA_NODEID_NUMERIC(0, UA_NS0ID_PUBLISHSUBSCRIBE_REMOVECONNECTION), removeConnectionAction);
  1001. retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(0, UA_NS0ID_PUBLISHSUBSCRIBE_PUBLISHEDDATASETS),
  1002. UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
  1003. UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_DATASETFOLDERTYPE_ADDDATASETFOLDER), true);
  1004. retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(0, UA_NS0ID_PUBLISHSUBSCRIBE_PUBLISHEDDATASETS),
  1005. UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
  1006. UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_DATASETFOLDERTYPE_ADDPUBLISHEDDATAITEMS), true);
  1007. retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(0, UA_NS0ID_PUBLISHSUBSCRIBE_PUBLISHEDDATASETS),
  1008. UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
  1009. UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_DATASETFOLDERTYPE_REMOVEPUBLISHEDDATASET), true);
  1010. retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(0, UA_NS0ID_PUBLISHSUBSCRIBE_PUBLISHEDDATASETS),
  1011. UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
  1012. UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_DATASETFOLDERTYPE_REMOVEDATASETFOLDER), true);
  1013. retVal |= UA_Server_setMethodNode_callback(server,
  1014. UA_NODEID_NUMERIC(0, UA_NS0ID_DATASETFOLDERTYPE_ADDDATASETFOLDER), addDataSetFolderAction);
  1015. retVal |= UA_Server_setMethodNode_callback(server,
  1016. UA_NODEID_NUMERIC(0, UA_NS0ID_DATASETFOLDERTYPE_REMOVEDATASETFOLDER), removeDataSetFolderAction);
  1017. retVal |= UA_Server_setMethodNode_callback(server,
  1018. UA_NODEID_NUMERIC(0, UA_NS0ID_DATASETFOLDERTYPE_ADDPUBLISHEDDATAITEMS), addPublishedDataItemsAction);
  1019. retVal |= UA_Server_setMethodNode_callback(server,
  1020. UA_NODEID_NUMERIC(0, UA_NS0ID_DATASETFOLDERTYPE_REMOVEPUBLISHEDDATASET), removePublishedDataSetAction);
  1021. retVal |= UA_Server_setMethodNode_callback(server,
  1022. UA_NODEID_NUMERIC(0, UA_NS0ID_PUBLISHEDDATAITEMSTYPE_ADDVARIABLES), addVariablesAction);
  1023. retVal |= UA_Server_setMethodNode_callback(server,
  1024. UA_NODEID_NUMERIC(0, UA_NS0ID_PUBLISHEDDATAITEMSTYPE_REMOVEVARIABLES), removeVariablesAction);
  1025. retVal |= UA_Server_setMethodNode_callback(server, UA_NODEID_NUMERIC(0, UA_NS0ID_PUBSUBCONNECTIONTYPE_ADDWRITERGROUP), addWriterGroupAction);
  1026. retVal |= UA_Server_setMethodNode_callback(server, UA_NODEID_NUMERIC(0, UA_NS0ID_PUBSUBCONNECTIONTYPE_ADDREADERGROUP), addReaderGroupAction);
  1027. retVal |= UA_Server_setMethodNode_callback(server, UA_NODEID_NUMERIC(0, UA_NS0ID_PUBSUBCONNECTIONTYPE_REMOVEGROUP), removeGroupAction);
  1028. retVal |= UA_Server_setMethodNode_callback(server, UA_NODEID_NUMERIC(0, UA_NS0ID_WRITERGROUPTYPE_ADDDATASETWRITER), addDataSetWriterAction);
  1029. retVal |= UA_Server_setMethodNode_callback(server, UA_NODEID_NUMERIC(0, UA_NS0ID_WRITERGROUPTYPE_REMOVEDATASETWRITER), removeDataSetWriterAction);
  1030. retVal |= UA_Server_setMethodNode_callback(server, UA_NODEID_NUMERIC(0, UA_NS0ID_READERGROUPTYPE_ADDDATASETREADER), addDataSetReaderAction);
  1031. retVal |= UA_Server_setMethodNode_callback(server, UA_NODEID_NUMERIC(0, UA_NS0ID_READERGROUPTYPE_REMOVEDATASETREADER), removeDataSetReaderAction);
  1032. #else
  1033. retVal |= UA_Server_deleteReference(server, UA_NODEID_NUMERIC(0, UA_NS0ID_PUBLISHSUBSCRIBE), UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT), true,
  1034. UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_PUBLISHSUBSCRIBE_ADDCONNECTION),
  1035. false);
  1036. retVal |= UA_Server_deleteReference(server, UA_NODEID_NUMERIC(0, UA_NS0ID_PUBLISHSUBSCRIBE), UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT), true,
  1037. UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_PUBLISHSUBSCRIBE_REMOVECONNECTION),
  1038. false);
  1039. #endif
  1040. UA_NodeTypeLifecycle liveCycle;
  1041. liveCycle.constructor = NULL;
  1042. liveCycle.destructor = connectionTypeDestructor;
  1043. UA_Server_setNodeTypeLifecycle(server, UA_NODEID_NUMERIC(0, UA_NS0ID_PUBSUBCONNECTIONTYPE), liveCycle);
  1044. liveCycle.destructor = writerGroupTypeDestructor;
  1045. UA_Server_setNodeTypeLifecycle(server, UA_NODEID_NUMERIC(0, UA_NS0ID_WRITERGROUPTYPE), liveCycle);
  1046. liveCycle.destructor = readerGroupTypeDestructor;
  1047. UA_Server_setNodeTypeLifecycle(server, UA_NODEID_NUMERIC(0, UA_NS0ID_READERGROUPTYPE), liveCycle);
  1048. liveCycle.destructor = dataSetWriterTypeDestructor;
  1049. UA_Server_setNodeTypeLifecycle(server, UA_NODEID_NUMERIC(0, UA_NS0ID_DATASETWRITERDATATYPE), liveCycle);
  1050. liveCycle.destructor = publishedDataItemsTypeDestructor;
  1051. UA_Server_setNodeTypeLifecycle(server, UA_NODEID_NUMERIC(0, UA_NS0ID_PUBLISHEDDATAITEMSTYPE), liveCycle);
  1052. liveCycle.destructor = dataSetReaderTypeDestructor;
  1053. UA_Server_setNodeTypeLifecycle(server, UA_NODEID_NUMERIC(0, UA_NS0ID_DATASETREADERDATATYPE), liveCycle);
  1054. return retVal;
  1055. }
  1056. #endif /* UA_ENABLE_PUBSUB_INFORMATIONMODEL */