ua_pubsub_ns0.c 54 KB

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