ua_pubsub_ns0.c 54 KB

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