/* UA_Node */ static void UA_Node_init(UA_Node *p) { UA_NodeId_init(&p->nodeId); UA_NodeClass_init(&p->nodeClass); UA_QualifiedName_init(&p->browseName); UA_LocalizedText_init(&p->displayName); UA_LocalizedText_init(&p->description); UA_UInt32_init(&p->writeMask); UA_UInt32_init(&p->userWriteMask); p->referencesSize = -1; p->references = UA_NULL; }
/* UA_ReferenceTypeNode */ void UA_ReferenceTypeNode_init(UA_ReferenceTypeNode *p) { UA_Node_init((UA_Node*)p); p->nodeClass = UA_NODECLASS_REFERENCETYPE; p->isAbstract = UA_FALSE; p->symmetric = UA_FALSE; UA_LocalizedText_init(&p->inverseName); }
} END_TEST START_TEST(AddAndRemoveWriterGroups){ UA_StatusCode retVal; UA_Client *client = UA_Client_new(); UA_ClientConfig_setDefault(UA_Client_getConfig(client)); retVal = UA_Client_connect(client, "opc.tcp://localhost:4840"); if(retVal != UA_STATUSCODE_GOOD) { UA_Client_delete(client); } ck_assert_int_eq(retVal, UA_STATUSCODE_GOOD); UA_NodeId createdConnection = addPubSubConnection(); UA_Variant *inputArgument = (UA_Variant *) UA_calloc(1, (sizeof(UA_Variant))); UA_WriterGroupDataType writerGroupDataType; UA_WriterGroupDataType_init(&writerGroupDataType); writerGroupDataType.name = UA_STRING("TestWriterGroup"); writerGroupDataType.enabled = UA_TRUE; writerGroupDataType.publishingInterval = 500; writerGroupDataType.writerGroupId = 1234; UA_Variant_setScalar(inputArgument, &writerGroupDataType, &UA_TYPES[UA_TYPES_WRITERGROUPDATATYPE]); UA_CallMethodRequest callMethodRequest; UA_CallMethodRequest_init(&callMethodRequest); callMethodRequest.inputArgumentsSize = 1; callMethodRequest.inputArguments = inputArgument; callMethodRequest.objectId = createdConnection; callMethodRequest.methodId = UA_NODEID_NUMERIC(0, UA_NS0ID_PUBSUBCONNECTIONTYPE_ADDWRITERGROUP); UA_CallMethodResult result; UA_CallMethodResult_init(&result); result = UA_Server_call(server, &callMethodRequest); ck_assert_int_eq(result.statusCode, UA_STATUSCODE_GOOD); ck_assert_int_eq(1, result.outputArgumentsSize); UA_NodeId createdWriterGroup = UA_NODEID_NULL; if(result.outputArguments->type == &UA_TYPES[UA_TYPES_NODEID]) createdWriterGroup = *((UA_NodeId *) result.outputArguments->data); UA_LocalizedText writerGroupDisplayName; UA_LocalizedText_init(&writerGroupDisplayName); retVal = UA_Server_readDisplayName(server, createdWriterGroup, &writerGroupDisplayName); ck_assert_int_eq(retVal, UA_STATUSCODE_GOOD); UA_String compareText = UA_STRING("TestWriterGroup"); ck_assert(UA_String_equal(&writerGroupDisplayName.text, &compareText) == UA_TRUE); UA_free(inputArgument); UA_CallMethodResult_deleteMembers(&result); UA_Client_disconnect(client); UA_Client_delete(client); UA_LocalizedText_deleteMembers(&writerGroupDisplayName); } END_TEST
OV_DLLFNCEXPORT UA_StatusCode servicesOPCUAInterface_interface_ovServiceOutputArgumentsNodeToOPCUA( void *handle, const UA_NodeId *nodeId, UA_Node** opcuaNode) { UA_Node *newNode = NULL; UA_StatusCode result = UA_STATUSCODE_GOOD; OV_PATH path; OV_INSTPTR_ov_object pobj = NULL; OV_TICKET *pTicket = NULL; OV_VTBLPTR_ov_object pVtblObj = NULL; OV_ACCESS access; UA_NodeClass nodeClass; OV_ELEMENT element; OV_STRING tmpString = NULL; OV_UINT len = 0; OV_STRING *plist = NULL; copyOPCUAStringToOV(nodeId->identifier.string, &tmpString); plist = ov_string_split(tmpString, "||", &len); ov_string_setvalue(&tmpString, NULL); UA_NodeId tmpNodeId; UA_NodeId_init(&tmpNodeId); tmpNodeId.namespaceIndex = nodeId->namespaceIndex; tmpNodeId.identifierType = nodeId->identifierType; tmpNodeId.identifier.string = UA_String_fromChars(plist[0]); ov_string_freelist(plist); ov_memstack_lock(); result = opcua_nodeStoreFunctions_resolveNodeIdToPath(tmpNodeId, &path); UA_NodeId_deleteMembers(&tmpNodeId); if(result != UA_STATUSCODE_GOOD){ ov_memstack_unlock(); return result; } element = path.elements[path.size-1]; ov_memstack_unlock(); result = opcua_nodeStoreFunctions_getVtblPointerAndCheckAccess(&(element), pTicket, &pobj, &pVtblObj, &access); if(result != UA_STATUSCODE_GOOD){ return result; } nodeClass = UA_NODECLASS_VARIABLE; newNode = (UA_Node*)UA_calloc(1, sizeof(UA_VariableNode)); // Basic Attribute // BrowseName UA_QualifiedName qName; qName.name = UA_String_fromChars("OutputArguments"); qName.namespaceIndex = 0; //pinterface->v_interfacenamespace.index; newNode->browseName = qName; // Description OV_STRING tempString = pVtblObj->m_getcomment(pobj, &element); UA_LocalizedText lText; UA_LocalizedText_init(&lText); lText.locale = UA_String_fromChars("en"); if(tempString){ lText.text = UA_String_fromChars(tempString); } else { lText.text = UA_String_fromChars(""); } UA_LocalizedText_copy(&lText,&newNode->description); UA_LocalizedText_deleteMembers(&lText); // DisplayName UA_LocalizedText displayName; UA_LocalizedText_init(&displayName); displayName.locale = UA_String_fromChars("en"); displayName.text = UA_String_fromChars("OutputArguments"); UA_LocalizedText_copy(&displayName, &newNode->displayName); UA_LocalizedText_deleteMembers(&displayName); // NodeId UA_NodeId_copy(nodeId, &newNode->nodeId); // NodeClass newNode->nodeClass = nodeClass; // WriteMask UA_UInt32 writeMask = 0; if(element.elemtype != OV_ET_VARIABLE){ if(access & OV_AC_WRITE){ writeMask |= (1<<2); // BrowseName writeMask |= (1<<6); // DisplayName } if(access & OV_AC_RENAMEABLE){ writeMask |= (1<<14); // NodeId } } newNode->writeMask = writeMask; // Variable specific attributes // value OV_ELEMENT tmpPart; tmpPart.elemtype = OV_ET_NONE; tmpPart.pobj = NULL; OV_ELEMENT tmpParrent; tmpParrent.pobj = pobj; tmpParrent.elemtype = OV_ET_OBJECT; OV_UINT sizeOutput = 0; do { ov_element_getnextpart(&tmpParrent, &tmpPart, OV_ET_VARIABLE); if (tmpPart.elemtype == OV_ET_NONE) break; if (tmpPart.elemunion.pvar->v_flags == 16384){ // OutputFlag is set sizeOutput++; continue; } } while(TRUE); // arrayDemensions if (sizeOutput > 1){ ((UA_VariableNode*)newNode)->arrayDimensionsSize = 1; UA_UInt32 *pOutputDimension = UA_UInt32_new(); *pOutputDimension = sizeOutput; ((UA_VariableNode*)newNode)->arrayDimensions = pOutputDimension; //UA_Array_new(((UA_VariableNode*)newNode)->arrayDimensionsSize, &UA_TYPES[UA_TYPES_INT32]); /* scalar or one dimension */ // valuerank ((UA_VariableNode*)newNode)->valueRank = 1; /* one dimension */ }else{ ((UA_VariableNode*)newNode)->arrayDimensionsSize = 0; ((UA_VariableNode*)newNode)->arrayDimensions = NULL; //UA_Array_new(((UA_VariableNode*)newNode)->arrayDimensionsSize, &UA_TYPES[UA_TYPES_INT32]); /* scalar or one dimension */ // valuerank ((UA_VariableNode*)newNode)->valueRank = -1; /* one dimension */ } // value ((UA_Variant*)&((UA_VariableNode*)newNode)->value.data.value.value)->type = &UA_TYPES[UA_TYPES_ARGUMENT]; ((UA_Variant*)&((UA_VariableNode*)newNode)->value.data.value.value)->arrayLength = sizeOutput; if (sizeOutput > 1){ ((UA_Variant*)&((UA_VariableNode*)newNode)->value.data.value.value)->data = UA_Array_new(sizeOutput, &UA_TYPES[UA_TYPES_ARGUMENT]); }else{ ((UA_Variant*)&((UA_VariableNode*)newNode)->value.data.value.value)->data = UA_Argument_new(); } if (!((UA_Variant*)&((UA_VariableNode*)newNode)->value.data.value.value)->data){ result = UA_STATUSCODE_BADOUTOFMEMORY; return result; } ((UA_VariableNode*)newNode)->value.data.value.hasValue = TRUE; ((UA_VariableNode*)newNode)->valueSource = UA_VALUESOURCE_DATA; tmpPart.elemtype = OV_ET_NONE; tmpPart.pobj = NULL; OV_UINT count = 0; do { ov_element_getnextpart(&tmpParrent, &tmpPart, OV_ET_VARIABLE); if (tmpPart.elemtype == OV_ET_NONE) break; if (tmpPart.elemunion.pvar->v_flags == 16384){ // OutputFlag is set UA_Argument_init(&((UA_Argument*)((UA_Variant*)&((UA_VariableNode*)newNode)->value.data.value.value)->data)[count]); ((UA_Argument*)((UA_Variant*)&((UA_VariableNode*)newNode)->value.data.value.value)->data)[count].description = UA_LOCALIZEDTEXT_ALLOC("en_US",""); ((UA_Argument*)((UA_Variant*)&((UA_VariableNode*)newNode)->value.data.value.value)->data)[count].name = UA_STRING_ALLOC(tmpPart.elemunion.pvar->v_identifier); ((UA_Argument*)((UA_Variant*)&((UA_VariableNode*)newNode)->value.data.value.value)->data)[count].valueRank = -1; switch(tmpPart.elemunion.pvar->v_vartype){ case OV_VT_BOOL: ((UA_Argument*)((UA_Variant*)&((UA_VariableNode*)newNode)->value.data.value.value)->data)[count].dataType = UA_TYPES[UA_TYPES_BOOLEAN].typeId; ((UA_Argument*)((UA_Variant*)&((UA_VariableNode*)newNode)->value.data.value.value)->data)[count].valueRank = -1; break; case OV_VT_INT: ((UA_Argument*)((UA_Variant*)&((UA_VariableNode*)newNode)->value.data.value.value)->data)[count].dataType = UA_TYPES[UA_TYPES_INT32].typeId; ((UA_Argument*)((UA_Variant*)&((UA_VariableNode*)newNode)->value.data.value.value)->data)[count].valueRank = -1; break; case OV_VT_UINT: ((UA_Argument*)((UA_Variant*)&((UA_VariableNode*)newNode)->value.data.value.value)->data)[count].dataType = UA_TYPES[UA_TYPES_UINT32].typeId; ((UA_Argument*)((UA_Variant*)&((UA_VariableNode*)newNode)->value.data.value.value)->data)[count].valueRank = -1; break; case OV_VT_SINGLE: ((UA_Argument*)((UA_Variant*)&((UA_VariableNode*)newNode)->value.data.value.value)->data)[count].dataType = UA_TYPES[UA_TYPES_FLOAT].typeId; ((UA_Argument*)((UA_Variant*)&((UA_VariableNode*)newNode)->value.data.value.value)->data)[count].valueRank = -1; break; case OV_VT_DOUBLE: ((UA_Argument*)((UA_Variant*)&((UA_VariableNode*)newNode)->value.data.value.value)->data)[count].dataType = UA_TYPES[UA_TYPES_DOUBLE].typeId; ((UA_Argument*)((UA_Variant*)&((UA_VariableNode*)newNode)->value.data.value.value)->data)[count].valueRank = -1; break; case OV_VT_ANY: ((UA_Argument*)((UA_Variant*)&((UA_VariableNode*)newNode)->value.data.value.value)->data)[count].dataType = UA_TYPES[UA_TYPES_VARIANT].typeId; ((UA_Argument*)((UA_Variant*)&((UA_VariableNode*)newNode)->value.data.value.value)->data)[count].valueRank = 1; break; case OV_VT_STRING: ((UA_Argument*)((UA_Variant*)&((UA_VariableNode*)newNode)->value.data.value.value)->data)[count].dataType = UA_TYPES[UA_TYPES_STRING].typeId; ((UA_Argument*)((UA_Variant*)&((UA_VariableNode*)newNode)->value.data.value.value)->data)[count].valueRank = -1; break; case OV_VT_BOOL_VEC: ((UA_Argument*)((UA_Variant*)&((UA_VariableNode*)newNode)->value.data.value.value)->data)[count].dataType = UA_TYPES[UA_TYPES_BOOLEAN].typeId; ((UA_Argument*)((UA_Variant*)&((UA_VariableNode*)newNode)->value.data.value.value)->data)[count].valueRank = 1; break; case OV_VT_INT_VEC: ((UA_Argument*)((UA_Variant*)&((UA_VariableNode*)newNode)->value.data.value.value)->data)[count].dataType = UA_TYPES[UA_TYPES_INT32].typeId; ((UA_Argument*)((UA_Variant*)&((UA_VariableNode*)newNode)->value.data.value.value)->data)[count].valueRank = 1; break; case OV_VT_UINT_VEC: ((UA_Argument*)((UA_Variant*)&((UA_VariableNode*)newNode)->value.data.value.value)->data)[count].dataType = UA_TYPES[UA_TYPES_UINT32].typeId; ((UA_Argument*)((UA_Variant*)&((UA_VariableNode*)newNode)->value.data.value.value)->data)[count].valueRank = 1; break; case OV_VT_SINGLE_VEC: ((UA_Argument*)((UA_Variant*)&((UA_VariableNode*)newNode)->value.data.value.value)->data)[count].dataType = UA_TYPES[UA_TYPES_FLOAT].typeId; ((UA_Argument*)((UA_Variant*)&((UA_VariableNode*)newNode)->value.data.value.value)->data)[count].valueRank = 1; break; case OV_VT_DOUBLE_VEC: ((UA_Argument*)((UA_Variant*)&((UA_VariableNode*)newNode)->value.data.value.value)->data)[count].dataType = UA_TYPES[UA_TYPES_DOUBLE].typeId; ((UA_Argument*)((UA_Variant*)&((UA_VariableNode*)newNode)->value.data.value.value)->data)[count].valueRank = 1; break; case OV_VT_STRING_VEC: ((UA_Argument*)((UA_Variant*)&((UA_VariableNode*)newNode)->value.data.value.value)->data)[count].dataType = UA_TYPES[UA_TYPES_STRING].typeId; ((UA_Argument*)((UA_Variant*)&((UA_VariableNode*)newNode)->value.data.value.value)->data)[count].valueRank = 1; break; default: break; } count++; if (count == sizeOutput){ break; }else{ continue; } } } while(TRUE); ov_string_setvalue(&tmpString, NULL); // accessLevel UA_Byte accessLevel = 0; if(access & OV_AC_READ){ accessLevel |= (1<<0); } if(access & OV_AC_WRITE){ accessLevel |= (1<<1); } ((UA_VariableNode*)newNode)->accessLevel = accessLevel; // minimumSamplingInterval ((UA_VariableNode*)newNode)->minimumSamplingInterval = -1; // historizing ((UA_VariableNode*)newNode)->historizing = UA_FALSE; // dataType ((UA_VariableNode*)newNode)->dataType = UA_NODEID_NUMERIC(0, 0); // References have to do manual because it is an virtual node size_t size_references = 0; size_references = size_references + 2;// For Parent&TypeNode newNode->references = UA_calloc(size_references, sizeof(UA_ReferenceNode)); if (!newNode->references){ result = ov_resultToUaStatusCode(OV_ERR_HEAPOUTOFMEMORY); UA_free(newNode); return result; } newNode->referencesSize = size_references; // ParentNode newNode->references[0].referenceTypeId = UA_NODEID_NUMERIC(0, UA_NS0ID_HASPROPERTY); newNode->references[0].isInverse = UA_TRUE; len = 0; plist = NULL; tmpString = NULL; copyOPCUAStringToOV(nodeId->identifier.string, &tmpString); plist = ov_string_split(tmpString, "||", &len); newNode->references[0].targetId = UA_EXPANDEDNODEID_STRING_ALLOC(pinterface->v_interfacenamespace.index, plist[0]); ov_string_freelist(plist); ov_string_setvalue(&tmpString, NULL); // TypeNode newNode->references[1].referenceTypeId = UA_NODEID_NUMERIC(0, UA_NS0ID_HASTYPEDEFINITION); newNode->references[1].isInverse = UA_FALSE; newNode->references[1].targetId = UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_PROPERTYTYPE); *opcuaNode = newNode; return UA_STATUSCODE_GOOD; }
} END_TEST START_TEST(AddAndRemovePublishedDataSetFolders){ UA_StatusCode retVal; UA_Client *client = UA_Client_new(); UA_ClientConfig_setDefault(UA_Client_getConfig(client)); retVal = UA_Client_connect(client, "opc.tcp://localhost:4840"); if(retVal != UA_STATUSCODE_GOOD) { UA_Client_delete(client); } ck_assert_int_eq(retVal, UA_STATUSCODE_GOOD); UA_String folderName = UA_STRING("TestFolder"); UA_Variant inputArguments; UA_Variant_init(&inputArguments); UA_Variant_setScalar(&inputArguments, &folderName, &UA_TYPES[UA_TYPES_STRING]); UA_CallMethodRequest callMethodRequest; UA_CallMethodRequest_init(&callMethodRequest); callMethodRequest.inputArgumentsSize = 1; callMethodRequest.inputArguments = &inputArguments; callMethodRequest.objectId = UA_NODEID_NUMERIC(0, UA_NS0ID_PUBLISHSUBSCRIBE_PUBLISHEDDATASETS); callMethodRequest.methodId = UA_NODEID_NUMERIC(0, UA_NS0ID_DATASETFOLDERTYPE_ADDDATASETFOLDER); UA_CallMethodResult result; UA_CallMethodResult_init(&result); result = UA_Server_call(server, &callMethodRequest); ck_assert_int_eq(1, result.outputArgumentsSize); ck_assert_int_eq(result.statusCode, UA_STATUSCODE_GOOD); UA_NodeId createdFolder = UA_NODEID_NULL; if(result.outputArguments->type == &UA_TYPES[UA_TYPES_NODEID]) createdFolder = *((UA_NodeId *) result.outputArguments->data); UA_LocalizedText connectionDisplayName; UA_LocalizedText_init(&connectionDisplayName); retVal = UA_Server_readDisplayName(server, createdFolder, &connectionDisplayName); ck_assert_int_eq(retVal, UA_STATUSCODE_GOOD); UA_String compareText = UA_STRING("TestFolder"); ck_assert(UA_String_equal(&connectionDisplayName.text, &compareText) == UA_TRUE); retVal = UA_Server_readNodeId(server, createdFolder, &createdFolder); ck_assert_int_eq(retVal, UA_STATUSCODE_GOOD); UA_CallMethodResult_deleteMembers(&result); UA_LocalizedText_deleteMembers(&connectionDisplayName); //create folder inside the new folder folderName = UA_STRING("TestFolder2"); UA_Variant_init(&inputArguments); UA_Variant_setScalar(&inputArguments, &folderName, &UA_TYPES[UA_TYPES_STRING]); UA_CallMethodRequest_init(&callMethodRequest); callMethodRequest.inputArgumentsSize = 1; callMethodRequest.inputArguments = &inputArguments; callMethodRequest.objectId = createdFolder; callMethodRequest.methodId = UA_NODEID_NUMERIC(0, UA_NS0ID_DATASETFOLDERTYPE_ADDDATASETFOLDER); UA_CallMethodResult_init(&result); result = UA_Server_call(server, &callMethodRequest); ck_assert_int_eq(1, result.outputArgumentsSize); ck_assert_int_eq(result.statusCode, UA_STATUSCODE_GOOD); UA_NodeId createdFolder2 = UA_NODEID_NULL; if(result.outputArguments->type == &UA_TYPES[UA_TYPES_NODEID]) createdFolder2 = *((UA_NodeId *) result.outputArguments->data); UA_LocalizedText_init(&connectionDisplayName); retVal = UA_Server_readDisplayName(server, createdFolder2, &connectionDisplayName); ck_assert_int_eq(retVal, UA_STATUSCODE_GOOD); compareText = UA_STRING("TestFolder2"); ck_assert(UA_String_equal(&connectionDisplayName.text, &compareText) == UA_TRUE); retVal = UA_Server_readNodeId(server, createdFolder2, &createdFolder2); ck_assert_int_eq(retVal, UA_STATUSCODE_GOOD); UA_CallMethodResult_deleteMembers(&result); //delete the folder UA_Variant_init(&inputArguments); UA_Variant_setScalar(&inputArguments, &createdFolder, &UA_TYPES[UA_TYPES_NODEID]); UA_CallMethodRequest_init(&callMethodRequest); callMethodRequest.inputArgumentsSize = 1; callMethodRequest.inputArguments = &inputArguments; callMethodRequest.objectId = UA_NODEID_NUMERIC(0, UA_NS0ID_PUBLISHSUBSCRIBE_PUBLISHEDDATASETS); callMethodRequest.methodId = UA_NODEID_NUMERIC(0, UA_NS0ID_DATASETFOLDERTYPE_REMOVEDATASETFOLDER); result = UA_Server_call(server, &callMethodRequest); ck_assert_int_eq(0, result.outputArgumentsSize); ck_assert_int_eq(result.statusCode, UA_STATUSCODE_GOOD); //check if the node is deleted retVal = UA_Server_readNodeId(server, createdFolder, NULL); ck_assert_int_eq(retVal, UA_STATUSCODE_BADNODEIDUNKNOWN); UA_CallMethodResult_deleteMembers(&result); UA_Client_disconnect(client); UA_Client_delete(client); UA_LocalizedText_deleteMembers(&connectionDisplayName); } END_TEST
OV_DLLFNCEXPORT UA_StatusCode propertyValueStatementOPCUAInterface_interface_ovExpressionSemanticNodeToOPCUA( void *handle, const UA_NodeId *nodeId, UA_Node** opcuaNode) { UA_Node *newNode = NULL; UA_StatusCode result = UA_STATUSCODE_GOOD; OV_PATH path; OV_INSTPTR_ov_object pobj = NULL; OV_TICKET *pTicket = NULL; OV_VTBLPTR_ov_object pVtblObj = NULL; OV_ACCESS access; UA_NodeClass nodeClass; OV_ELEMENT element; ov_memstack_lock(); result = opcua_nodeStoreFunctions_resolveNodeIdToPath(*nodeId, &path); if(result != UA_STATUSCODE_GOOD){ ov_memstack_unlock(); return result; } element = path.elements[path.size-1]; ov_memstack_unlock(); result = opcua_nodeStoreFunctions_getVtblPointerAndCheckAccess(&(element), pTicket, &pobj, &pVtblObj, &access); if(result != UA_STATUSCODE_GOOD){ return result; } nodeClass = UA_NODECLASS_VARIABLE; newNode = (UA_Node*)UA_calloc(1, sizeof(UA_VariableNode)); // Basic Attribute // BrowseName UA_QualifiedName qName; qName.name = UA_String_fromChars(pobj->v_identifier); qName.namespaceIndex = nodeId->namespaceIndex; newNode->browseName = qName; // Description // Description OV_STRING tempString = pVtblObj->m_getcomment(pobj, &element); UA_LocalizedText lText; UA_LocalizedText_init(&lText); lText.locale = UA_String_fromChars("en"); if(tempString){ lText.text = UA_String_fromChars(tempString); } else { lText.text = UA_String_fromChars(""); } UA_LocalizedText_copy(&lText,&newNode->description); UA_LocalizedText_deleteMembers(&lText); // DisplayName UA_LocalizedText displayName; UA_LocalizedText_init(&displayName); displayName.locale = UA_String_fromChars("en"); displayName.text = UA_String_fromChars(pobj->v_identifier); UA_LocalizedText_copy(&displayName, &newNode->displayName); UA_LocalizedText_deleteMembers(&displayName); // NodeId UA_NodeId_copy(nodeId, &newNode->nodeId); // NodeClass newNode->nodeClass = nodeClass; // WriteMask UA_UInt32 writeMask = 0; if(element.elemtype != OV_ET_VARIABLE){ if(access & OV_AC_WRITE){ writeMask |= (1<<2); // BrowseName writeMask |= (1<<6); // DisplayName } if(access & OV_AC_RENAMEABLE){ writeMask |= (1<<14); // NodeId } } newNode->writeMask = writeMask; // Variable specific attributes // arrayDemensions ((UA_VariableNode*)newNode)->arrayDimensionsSize = 0; ((UA_VariableNode*)newNode)->arrayDimensions = NULL; // UA_Array_new(((UA_VariableNode*)newNode)->arrayDimensionsSize, &UA_TYPES[UA_TYPES_INT32]); /* scalar or one dimension */ // valuerank ((UA_VariableNode*)newNode)->valueRank = 1; /* one dimension */ // value OV_ELEMENT tmpPart; tmpPart.elemtype = OV_ET_NONE; OV_ELEMENT tmpParrent; tmpParrent.pobj = pobj; tmpParrent.elemtype = OV_ET_OBJECT; UA_ExpressionSemanticEnum tmpExpressionSemantic = 0; do { ov_element_getnextpart(&tmpParrent, &tmpPart, OV_ET_VARIABLE); if (tmpPart.elemtype == OV_ET_NONE) break; if (ov_string_compare(tmpPart.elemunion.pvar->v_identifier, "ExpressionSemanticEnum") == OV_STRCMP_EQUAL){ tmpExpressionSemantic = *(UA_UInt32*)tmpPart.pvalue; break; } } while(TRUE); ((UA_Variant*)&((UA_VariableNode*)newNode)->value.data.value.value)->type = &UA_PROPERTYVALUESTATEMENT[UA_PROPERTYVALUESTATEMENT_EXPRESSIONSEMANTICENUM]; ((UA_Variant*)&((UA_VariableNode*)newNode)->value.data.value.value)->data = UA_ExpressionSemanticEnum_new(); if (!((UA_Variant*)&((UA_VariableNode*)newNode)->value.data.value.value)->data){ result = UA_STATUSCODE_BADOUTOFMEMORY; return result; } ((UA_VariableNode*)newNode)->value.data.value.hasValue = TRUE; ((UA_VariableNode*)newNode)->valueSource = UA_VALUESOURCE_DATA; UA_ExpressionSemanticEnum_copy(&tmpExpressionSemantic, ((UA_Variant*)&((UA_VariableNode*)newNode)->value.data.value.value)->data); UA_ExpressionSemanticEnum_deleteMembers(&tmpExpressionSemantic); // accessLevel UA_Byte accessLevel = 0; if(access & OV_AC_READ){ accessLevel |= (1<<0); } if(access & OV_AC_WRITE){ accessLevel |= (1<<1); } ((UA_VariableNode*)newNode)->accessLevel = accessLevel; // minimumSamplingInterval ((UA_VariableNode*)newNode)->minimumSamplingInterval = -1; // historizing ((UA_VariableNode*)newNode)->historizing = UA_FALSE; // dataType ((UA_VariableNode*)newNode)->dataType = UA_NODEID_NUMERIC(pinterface->v_modelnamespace.index, UA_NSPROPERTYVALUESTATEMENTID_EXPRESSIONSEMANTICENUM); // References addReference(newNode); OV_UINT len = 0; OV_STRING *plist = NULL; OV_STRING tmpString = NULL; copyOPCUAStringToOV(nodeId->identifier.string, &tmpString); plist = ov_string_split(tmpString, "/", &len); ov_string_setvalue(&tmpString, plist[0]); for (OV_UINT i = 1; i < len-1; i++){ ov_string_append(&tmpString, "/"); ov_string_append(&tmpString, plist[i]); } ov_string_freelist(plist); UA_NodeId tmpNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_HASTYPEDEFINITION); for (size_t i = 0; i < newNode->referencesSize; i++){ if (UA_NodeId_equal(&newNode->references[i].referenceTypeId, &tmpNodeId)){ newNode->references[i].targetId = UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_PROPERTYTYPE); continue; } OV_STRING tmpString2 = NULL; copyOPCUAStringToOV(newNode->references[i].targetId.nodeId.identifier.string, &tmpString2); if (ov_string_compare(tmpString, tmpString2) == OV_STRCMP_EQUAL && newNode->references[i].isInverse == UA_TRUE){ newNode->references[i].referenceTypeId = UA_NODEID_NUMERIC(0, UA_NS0ID_HASPROPERTY); } ov_string_setvalue(&tmpString2, NULL); } ov_string_setvalue(&tmpString, NULL); UA_NodeId_deleteMembers(&tmpNodeId); *opcuaNode = newNode; return UA_STATUSCODE_GOOD; }