ua_client_highlevel.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325
  1. #include "ua_client.h"
  2. #include "ua_nodeids.h"
  3. #include "ua_client_highlevel.h"
  4. #include "ua_types_encoding_binary.h"
  5. #include "ua_util.h"
  6. #include "ua_types.h"
  7. UA_StatusCode
  8. UA_Client_NamespaceGetIndex(UA_Client *client, UA_String *namespaceUri, UA_UInt16 *namespaceIndex) {
  9. UA_ReadRequest request;
  10. UA_ReadRequest_init(&request);
  11. UA_ReadValueId id;
  12. id.attributeId = UA_ATTRIBUTEID_VALUE;
  13. id.nodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_NAMESPACEARRAY);
  14. request.nodesToRead = &id;
  15. request.nodesToReadSize = 1;
  16. UA_ReadResponse response = UA_Client_Service_read(client, request);
  17. UA_StatusCode retval = UA_STATUSCODE_GOOD;
  18. if(response.responseHeader.serviceResult != UA_STATUSCODE_GOOD)
  19. retval = response.responseHeader.serviceResult;
  20. else if(response.resultsSize != 1 || !response.results[0].hasValue)
  21. retval = UA_STATUSCODE_BADNODEATTRIBUTESINVALID;
  22. else if(response.results[0].value.type != &UA_TYPES[UA_TYPES_STRING])
  23. retval = UA_STATUSCODE_BADTYPEMISMATCH;
  24. if(retval != UA_STATUSCODE_GOOD) {
  25. UA_ReadResponse_deleteMembers(&response);
  26. return retval;
  27. }
  28. retval = UA_STATUSCODE_BADNOTFOUND;
  29. UA_String *ns = response.results[0].value.data;
  30. for(size_t i = 0; i < response.results[0].value.arrayLength; i++){
  31. if(UA_String_equal(namespaceUri, &ns[i])) {
  32. *namespaceIndex = (UA_UInt16)i;
  33. retval = UA_STATUSCODE_GOOD;
  34. break;
  35. }
  36. }
  37. UA_ReadResponse_deleteMembers(&response);
  38. return retval;
  39. }
  40. UA_StatusCode
  41. UA_Client_forEachChildNodeCall(UA_Client *client, UA_NodeId parentNodeId, UA_NodeIteratorCallback callback, void *handle) {
  42. UA_StatusCode retval = UA_STATUSCODE_GOOD;
  43. UA_BrowseRequest bReq;
  44. UA_BrowseRequest_init(&bReq);
  45. bReq.requestedMaxReferencesPerNode = 0;
  46. bReq.nodesToBrowse = UA_BrowseDescription_new();
  47. bReq.nodesToBrowseSize = 1;
  48. UA_NodeId_copy(&parentNodeId, &bReq.nodesToBrowse[0].nodeId);
  49. bReq.nodesToBrowse[0].resultMask = UA_BROWSERESULTMASK_ALL; //return everything
  50. bReq.nodesToBrowse[0].browseDirection = UA_BROWSEDIRECTION_BOTH;
  51. UA_BrowseResponse bResp = UA_Client_Service_browse(client, bReq);
  52. if(bResp.responseHeader.serviceResult == UA_STATUSCODE_GOOD) {
  53. for (size_t i = 0; i < bResp.resultsSize; ++i) {
  54. for (size_t j = 0; j < bResp.results[i].referencesSize; ++j) {
  55. UA_ReferenceDescription *ref = &(bResp.results[i].references[j]);
  56. retval |= callback(ref->nodeId.nodeId, ! ref->isForward, ref->referenceTypeId, handle);
  57. }
  58. }
  59. }
  60. else
  61. retval = bResp.responseHeader.serviceResult;
  62. UA_BrowseRequest_deleteMembers(&bReq);
  63. UA_BrowseResponse_deleteMembers(&bResp);
  64. return retval;
  65. }
  66. /*******************/
  67. /* Node Management */
  68. /*******************/
  69. UA_StatusCode UA_EXPORT
  70. UA_Client_addReference(UA_Client *client, const UA_NodeId sourceNodeId, const UA_NodeId referenceTypeId,
  71. UA_Boolean isForward, const UA_String targetServerUri,
  72. const UA_ExpandedNodeId targetNodeId, UA_NodeClass targetNodeClass) {
  73. UA_AddReferencesItem item;
  74. UA_AddReferencesItem_init(&item);
  75. item.sourceNodeId = sourceNodeId;
  76. item.referenceTypeId = referenceTypeId;
  77. item.isForward = isForward;
  78. item.targetServerUri = targetServerUri;
  79. item.targetNodeId = targetNodeId;
  80. item.targetNodeClass = targetNodeClass;
  81. UA_AddReferencesRequest request;
  82. UA_AddReferencesRequest_init(&request);
  83. request.referencesToAdd = &item;
  84. request.referencesToAddSize = 1;
  85. UA_AddReferencesResponse response = UA_Client_Service_addReferences(client, request);
  86. UA_StatusCode retval = response.responseHeader.serviceResult;
  87. if(retval != UA_STATUSCODE_GOOD) {
  88. UA_AddReferencesResponse_deleteMembers(&response);
  89. return retval;
  90. }
  91. if(response.resultsSize != 1) {
  92. UA_AddReferencesResponse_deleteMembers(&response);
  93. return UA_STATUSCODE_BADUNEXPECTEDERROR;
  94. }
  95. retval = response.results[0];
  96. UA_AddReferencesResponse_deleteMembers(&response);
  97. return retval;
  98. }
  99. UA_StatusCode UA_EXPORT
  100. UA_Client_deleteReference(UA_Client *client, const UA_NodeId sourceNodeId, const UA_NodeId referenceTypeId,
  101. UA_Boolean isForward, const UA_ExpandedNodeId targetNodeId,
  102. UA_Boolean deleteBidirectional) {
  103. UA_DeleteReferencesItem item;
  104. UA_DeleteReferencesItem_init(&item);
  105. item.sourceNodeId = sourceNodeId;
  106. item.referenceTypeId = referenceTypeId;
  107. item.isForward = isForward;
  108. item.targetNodeId = targetNodeId;
  109. item.deleteBidirectional = deleteBidirectional;
  110. UA_DeleteReferencesRequest request;
  111. UA_DeleteReferencesRequest_init(&request);
  112. request.referencesToDelete = &item;
  113. request.referencesToDeleteSize = 1;
  114. UA_DeleteReferencesResponse response = UA_Client_Service_deleteReferences(client, request);
  115. UA_StatusCode retval = response.responseHeader.serviceResult;
  116. if(retval != UA_STATUSCODE_GOOD) {
  117. UA_DeleteReferencesResponse_deleteMembers(&response);
  118. return retval;
  119. }
  120. if(response.resultsSize != 1) {
  121. UA_DeleteReferencesResponse_deleteMembers(&response);
  122. return UA_STATUSCODE_BADUNEXPECTEDERROR;
  123. }
  124. retval = response.results[0];
  125. UA_DeleteReferencesResponse_deleteMembers(&response);
  126. return retval;
  127. }
  128. UA_StatusCode
  129. UA_Client_deleteNode(UA_Client *client, const UA_NodeId nodeId, UA_Boolean deleteTargetReferences) {
  130. UA_DeleteNodesItem item;
  131. UA_DeleteNodesItem_init(&item);
  132. item.nodeId = nodeId;
  133. item.deleteTargetReferences = deleteTargetReferences;
  134. UA_DeleteNodesRequest request;
  135. UA_DeleteNodesRequest_init(&request);
  136. request.nodesToDelete = &item;
  137. request.nodesToDeleteSize = 1;
  138. UA_DeleteNodesResponse response = UA_Client_Service_deleteNodes(client, request);
  139. UA_StatusCode retval = response.responseHeader.serviceResult;
  140. if(retval != UA_STATUSCODE_GOOD) {
  141. UA_DeleteNodesResponse_deleteMembers(&response);
  142. return retval;
  143. }
  144. if(response.resultsSize != 1) {
  145. UA_DeleteNodesResponse_deleteMembers(&response);
  146. return UA_STATUSCODE_BADUNEXPECTEDERROR;
  147. }
  148. retval = response.results[0];
  149. UA_DeleteNodesResponse_deleteMembers(&response);
  150. return retval;
  151. }
  152. UA_StatusCode
  153. __UA_Client_addNode(UA_Client *client, const UA_NodeClass nodeClass, const UA_NodeId requestedNewNodeId,
  154. const UA_NodeId parentNodeId, const UA_NodeId referenceTypeId,
  155. const UA_QualifiedName browseName, const UA_NodeId typeDefinition,
  156. const UA_NodeAttributes *attr, const UA_DataType *attributeType, UA_NodeId *outNewNodeId) {
  157. UA_StatusCode retval = UA_STATUSCODE_GOOD;
  158. UA_AddNodesRequest request;
  159. UA_AddNodesRequest_init(&request);
  160. UA_AddNodesItem item;
  161. UA_AddNodesItem_init(&item);
  162. item.parentNodeId.nodeId = parentNodeId;
  163. item.referenceTypeId = referenceTypeId;
  164. item.requestedNewNodeId.nodeId = requestedNewNodeId;
  165. item.browseName = browseName;
  166. item.nodeClass = nodeClass;
  167. item.typeDefinition.nodeId = typeDefinition;
  168. item.nodeAttributes.encoding = UA_EXTENSIONOBJECT_DECODED_NODELETE;
  169. item.nodeAttributes.content.decoded.type = attributeType;
  170. item.nodeAttributes.content.decoded.data = (void*)(uintptr_t)attr; // hack. is not written into.
  171. request.nodesToAdd = &item;
  172. request.nodesToAddSize = 1;
  173. UA_AddNodesResponse response = UA_Client_Service_addNodes(client, request);
  174. if(response.responseHeader.serviceResult != UA_STATUSCODE_GOOD) {
  175. retval = response.responseHeader.serviceResult;
  176. UA_AddNodesResponse_deleteMembers(&response);
  177. return retval;
  178. }
  179. if(response.resultsSize != 1) {
  180. UA_AddNodesResponse_deleteMembers(&response);
  181. return UA_STATUSCODE_BADUNEXPECTEDERROR;
  182. }
  183. if(outNewNodeId && response.results[0].statusCode == UA_STATUSCODE_GOOD) {
  184. *outNewNodeId = response.results[0].addedNodeId;
  185. UA_NodeId_init(&response.results[0].addedNodeId);
  186. }
  187. retval = response.results[0].statusCode;
  188. UA_AddNodesResponse_deleteMembers(&response);
  189. return retval;
  190. }
  191. /********/
  192. /* Call */
  193. /********/
  194. UA_StatusCode
  195. UA_Client_call(UA_Client *client, const UA_NodeId objectId, const UA_NodeId methodId, size_t inputSize,
  196. const UA_Variant *input, size_t *outputSize, UA_Variant **output) {
  197. UA_CallRequest request;
  198. UA_CallRequest_init(&request);
  199. UA_CallMethodRequest item;
  200. UA_CallMethodRequest_init(&item);
  201. item.methodId = methodId;
  202. item.objectId = objectId;
  203. item.inputArguments = (void*)(uintptr_t)input; // cast const...
  204. item.inputArgumentsSize = inputSize;
  205. request.methodsToCall = &item;
  206. request.methodsToCallSize = 1;
  207. UA_CallResponse response = UA_Client_Service_call(client, request);
  208. UA_StatusCode retval = response.responseHeader.serviceResult;
  209. if(retval != UA_STATUSCODE_GOOD) {
  210. UA_CallResponse_deleteMembers(&response);
  211. return retval;
  212. }
  213. if(response.resultsSize != 1) {
  214. UA_CallResponse_deleteMembers(&response);
  215. return UA_STATUSCODE_BADUNEXPECTEDERROR;
  216. }
  217. retval = response.results[0].statusCode;
  218. if(retval == UA_STATUSCODE_GOOD && response.resultsSize > 0) {
  219. if (output != NULL && outputSize != NULL) {
  220. *output = response.results[0].outputArguments;
  221. *outputSize = response.results[0].outputArgumentsSize;
  222. }
  223. response.results[0].outputArguments = NULL;
  224. response.results[0].outputArgumentsSize = 0;
  225. }
  226. UA_CallResponse_deleteMembers(&response);
  227. return retval;
  228. }
  229. /**************/
  230. /* Attributes */
  231. /**************/
  232. UA_StatusCode
  233. __UA_Client_writeAttribute(UA_Client *client, UA_NodeId nodeId, UA_AttributeId attributeId,
  234. const void *in, const UA_DataType *inDataType) {
  235. if(!in)
  236. return UA_STATUSCODE_BADTYPEMISMATCH;
  237. UA_WriteRequest *wReq = UA_WriteRequest_new();
  238. wReq->nodesToWrite = UA_WriteValue_new();
  239. wReq->nodesToWriteSize = 1;
  240. UA_NodeId_copy(&nodeId, &wReq->nodesToWrite[0].nodeId);
  241. wReq->nodesToWrite[0].attributeId = attributeId;
  242. if(attributeId == UA_ATTRIBUTEID_VALUE) {
  243. UA_Variant_copy((const UA_Variant*)in, &wReq->nodesToWrite[0].value.value);
  244. wReq->nodesToWrite[0].value.hasValue = true;
  245. } else {
  246. UA_Variant_setScalarCopy(&wReq->nodesToWrite[0].value.value, in, inDataType);
  247. wReq->nodesToWrite[0].value.hasValue = true;
  248. }
  249. UA_WriteResponse wResp = UA_Client_Service_write(client, *wReq);
  250. UA_StatusCode retval = wResp.responseHeader.serviceResult;
  251. UA_WriteRequest_delete(wReq);
  252. UA_WriteResponse_deleteMembers(&wResp);
  253. return retval;
  254. }
  255. UA_StatusCode
  256. __UA_Client_readAttribute(UA_Client *client, UA_NodeId nodeId, UA_AttributeId attributeId,
  257. void *out, const UA_DataType *outDataType) {
  258. UA_ReadValueId item;
  259. UA_ReadValueId_init(&item);
  260. item.nodeId = nodeId;
  261. item.attributeId = attributeId;
  262. UA_ReadRequest request;
  263. UA_ReadRequest_init(&request);
  264. request.nodesToRead = &item;
  265. request.nodesToReadSize = 1;
  266. UA_ReadResponse response = UA_Client_Service_read(client, request);
  267. UA_StatusCode retval = response.responseHeader.serviceResult;
  268. if(retval == UA_STATUSCODE_GOOD && response.resultsSize != 1)
  269. retval = UA_STATUSCODE_BADUNEXPECTEDERROR;
  270. if(retval != UA_STATUSCODE_GOOD) {
  271. UA_ReadResponse_deleteMembers(&response);
  272. return retval;
  273. }
  274. UA_DataValue *res = response.results;
  275. if(res->hasStatus != UA_STATUSCODE_GOOD)
  276. retval = res->hasStatus;
  277. else if(!res->hasValue || !UA_Variant_isScalar(&res->value))
  278. retval = UA_STATUSCODE_BADUNEXPECTEDERROR;
  279. if(retval != UA_STATUSCODE_GOOD) {
  280. UA_ReadResponse_deleteMembers(&response);
  281. return retval;
  282. }
  283. if(attributeId == UA_ATTRIBUTEID_VALUE) {
  284. memcpy(out, &res->value, sizeof(UA_Variant));
  285. UA_Variant_init(&res->value);
  286. } else if(res->value.type != outDataType) {
  287. retval = UA_STATUSCODE_BADUNEXPECTEDERROR;
  288. } else {
  289. memcpy(out, res->value.data, res->value.type->memSize);
  290. UA_free(res->value.data);
  291. res->value.data = NULL;
  292. }
  293. UA_ReadResponse_deleteMembers(&response);
  294. return retval;
  295. }