| 202 | } |
| 203 | |
| 204 | NodeData Client::getNodeData(const UA_ReferenceDescription *ref, const std::string& basePath) { |
| 205 | if(ref->nodeClass == UA_NODECLASS_VARIABLE) { |
| 206 | opc::NodeData nodedata; |
| 207 | std::string browsename(reinterpret_cast<const char*>(ref->browseName.name.data), ref->browseName.name.length); |
| 208 | |
| 209 | if(ref->nodeId.nodeId.identifierType == UA_NODEIDTYPE_STRING) { |
| 210 | std::string nodeidstr(reinterpret_cast<const char*>(ref->nodeId.nodeId.identifier.string.data), |
| 211 | ref->nodeId.nodeId.identifier.string.length); |
| 212 | nodedata.attributes["NodeID"] = nodeidstr; |
| 213 | nodedata.attributes["NodeID type"] = "string"; |
| 214 | } else if(ref->nodeId.nodeId.identifierType == UA_NODEIDTYPE_BYTESTRING) { |
| 215 | std::string nodeidstr(reinterpret_cast<const char*>(ref->nodeId.nodeId.identifier.byteString.data), ref->nodeId.nodeId.identifier.byteString.length); |
| 216 | nodedata.attributes["NodeID"] = nodeidstr; |
| 217 | nodedata.attributes["NodeID type"] = "bytestring"; |
| 218 | } else if (ref->nodeId.nodeId.identifierType == UA_NODEIDTYPE_NUMERIC) { |
| 219 | nodedata.attributes["NodeID"] = std::to_string(ref->nodeId.nodeId.identifier.numeric); |
| 220 | nodedata.attributes["NodeID type"] = "numeric"; |
| 221 | } |
| 222 | nodedata.attributes["Browsename"] = browsename; |
| 223 | nodedata.attributes["Full path"] = basePath + "/" + browsename; |
| 224 | nodedata.dataTypeID = UA_TYPES_COUNT; |
| 225 | UA_Variant* var = UA_Variant_new(); |
| 226 | if(UA_Client_readValueAttribute(client_, ref->nodeId.nodeId, var) == UA_STATUSCODE_GOOD && var->type != NULL && var->data != NULL) { |
| 227 | // Because the timestamps are eliminated in readValueAttribute for simplification |
| 228 | // We need to call the inner function UA_Client_Service_read. |
| 229 | UA_ReadValueId item; |
| 230 | UA_ReadValueId_init(&item); |
| 231 | item.nodeId = ref->nodeId.nodeId; |
| 232 | item.attributeId = UA_ATTRIBUTEID_VALUE; |
| 233 | UA_ReadRequest request; |
| 234 | UA_ReadRequest_init(&request); |
| 235 | request.nodesToRead = &item; |
| 236 | request.nodesToReadSize = 1; |
| 237 | // Differ from ua_client_highlevel.c src |
| 238 | request.timestampsToReturn = UA_TIMESTAMPSTORETURN_BOTH; |
| 239 | UA_ReadResponse response = UA_Client_Service_read(client_, request); |
| 240 | UA_DataValue *dv = response.results; |
| 241 | auto server_timestamp = OPCDateTime2String(dv->serverTimestamp); |
| 242 | auto source_timestamp = OPCDateTime2String(dv->sourceTimestamp); |
| 243 | nodedata.attributes["Sourcetimestamp"] = source_timestamp; |
| 244 | UA_ReadResponse_deleteMembers(&response); |
| 245 | |
| 246 | nodedata.dataTypeID = var->type->typeIndex; |
| 247 | nodedata.addVariant(var); |
| 248 | if(var->type->typeName) { |
| 249 | nodedata.attributes["Typename"] = std::string(var->type->typeName); |
| 250 | } |
| 251 | if(var->type->memSize) { |
| 252 | nodedata.attributes["Datasize"] = std::to_string(var->type->memSize); |
| 253 | nodedata.data = std::vector<uint8_t>(var->type->memSize); |
| 254 | memcpy(nodedata.data.data(), var->data, var->type->memSize); |
| 255 | } |
| 256 | return nodedata; |
| 257 | } |
| 258 | UA_Variant_delete(var); |
| 259 | throw OPCException(GENERAL_EXCEPTION, "Failed to read value of node: " + browsename); |
| 260 | } else { |
| 261 | throw OPCException(GENERAL_EXCEPTION, "Only variable nodes are supported!"); |
no test coverage detected