int main(int argc, char **argv) { signal(SIGINT, stopHandler); signal(SIGTERM, stopHandler); UA_Server *server = UA_Server_new(); UA_ServerConfig *config = UA_Server_getConfig(server); UA_ServerConfig_setDefault(config); config->customDataTypes = &customTypesArray; UA_StatusCode retval; /* create nodes from nodeset */ if(namespace_testnodeset_generated(server) != UA_STATUSCODE_GOOD) { UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_SERVER, "Could not add the example nodeset. " "Check previous output for any error."); retval = UA_STATUSCODE_BADUNEXPECTEDERROR; } else { UA_Variant out; UA_Variant_init(&out); UA_Server_readValue(server, UA_NODEID_NUMERIC(2, 10002), &out); UA_Point *p = (UA_Point *)out.data; printf("point 2d x: %f y: %f \n", p->x, p->y); retval = UA_Server_run(server, &running); } UA_Server_delete(server); return retval == UA_STATUSCODE_GOOD ? EXIT_SUCCESS : EXIT_FAILURE; }
static UA_NodeId addPubSubConnection(void){ UA_Variant publisherId; UA_Variant_init(&publisherId); UA_UInt32 publisherIdValue = 13245; UA_Variant_setScalar(&publisherId, &publisherIdValue , &UA_TYPES[UA_TYPES_UINT32]); UA_PubSubConnectionDataType pubSubConnection; UA_PubSubConnectionDataType_init(&pubSubConnection); pubSubConnection.name = UA_STRING("Model Connection 1"); pubSubConnection.enabled = UA_TRUE; pubSubConnection.publisherId = publisherId; pubSubConnection.transportProfileUri = UA_STRING("http://opcfoundation.org/UA-Profile/Transport/pubsub-udp-uadp"); UA_ExtensionObject eo; UA_NetworkAddressUrlDataType networkAddressDataType = {UA_STRING("eth0"), UA_STRING("opc.udp://224.0.0.22:4840/")}; UA_NetworkAddressUrlDataType* identityToken = UA_NetworkAddressUrlDataType_new(); UA_NetworkAddressUrlDataType_init(identityToken); UA_NetworkAddressUrlDataType_copy(&networkAddressDataType, identityToken); eo.encoding = UA_EXTENSIONOBJECT_DECODED; eo.content.decoded.type = &UA_TYPES[UA_TYPES_NETWORKADDRESSURLDATATYPE]; eo.content.decoded.data = identityToken; pubSubConnection.address = eo; pubSubConnection.connectionPropertiesSize = 2; UA_KeyValuePair connectionOptions[2]; memset(connectionOptions, 0, sizeof(UA_KeyValuePair)* 2); connectionOptions[0].key = UA_QUALIFIEDNAME(0, "ttl"); UA_UInt32 ttl = 10; UA_Variant_setScalar(&connectionOptions[0].value, &ttl, &UA_TYPES[UA_TYPES_UINT32]); connectionOptions[1].key = UA_QUALIFIEDNAME(0, "loopback"); UA_Boolean loopback = UA_FALSE; UA_Variant_setScalar(&connectionOptions[1].value, &loopback, &UA_TYPES[UA_TYPES_UINT32]); pubSubConnection.connectionProperties = connectionOptions; UA_Variant inputArguments; UA_Variant_init(&inputArguments); UA_Variant_setScalar(&inputArguments, &pubSubConnection, &UA_TYPES[UA_TYPES_PUBSUBCONNECTIONDATATYPE]); UA_CallMethodRequest callMethodRequest; UA_CallMethodRequest_init(&callMethodRequest); callMethodRequest.inputArgumentsSize = 1; callMethodRequest.inputArguments = &inputArguments; callMethodRequest.objectId = UA_NODEID_NUMERIC(0, UA_NS0ID_PUBLISHSUBSCRIBE); callMethodRequest.methodId = UA_NODEID_NUMERIC(0, UA_NS0ID_PUBLISHSUBSCRIBE_ADDCONNECTION); UA_NodeId connectionId = UA_NODEID_NULL; 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); if(result.outputArguments->type == &UA_TYPES[UA_TYPES_NODEID]) connectionId = *((UA_NodeId *) result.outputArguments->data); UA_ExtensionObject_deleteMembers(&eo); callMethodRequest.inputArguments = NULL; callMethodRequest.inputArgumentsSize = 0; UA_CallMethodRequest_deleteMembers(&callMethodRequest); UA_CallMethodResult_deleteMembers(&result); return connectionId; }
END_TEST START_TEST(SecureChannel_cableunplugged) { UA_Client *client = UA_Client_new(); UA_ClientConfig_setDefault(UA_Client_getConfig(client)); UA_StatusCode retval = UA_Client_connect(client, "opc.tcp://localhost:4840"); ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD); UA_Variant val; UA_Variant_init(&val); UA_NodeId nodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_STATE); retval = UA_Client_readValueAttribute(client, nodeId, &val); ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD); UA_Variant_deleteMembers(&val); UA_Client_recv = client->connection.recv; client->connection.recv = UA_Client_recvTesting; /* Simulate network cable unplugged (no response from server) */ UA_Client_recvTesting_result = UA_STATUSCODE_GOODNONCRITICALTIMEOUT; UA_Variant_init(&val); retval = UA_Client_readValueAttribute(client, nodeId, &val); ck_assert_uint_eq(retval, UA_STATUSCODE_BADCONNECTIONCLOSED); ck_assert_msg(UA_Client_getState(client) == UA_CLIENTSTATE_DISCONNECTED); UA_Client_recvTesting_result = UA_STATUSCODE_GOOD; UA_Client_delete(client); }
END_TEST START_TEST(Client_methodcall) { UA_Client *client = UA_Client_new(UA_ClientConfig_default); UA_StatusCode retval = UA_Client_connect(client, "opc.tcp://localhost:4840"); ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD); UA_UInt32 subId; retval = UA_Client_Subscriptions_new(client, UA_SubscriptionSettings_default, &subId); ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD); /* monitor the server state */ UA_UInt32 monId; retval = UA_Client_Subscriptions_addMonitoredItem(client, subId, UA_NODEID_NUMERIC(0, 2259), UA_ATTRIBUTEID_VALUE, NULL, NULL, &monId); ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD); /* call a method to get monitored item id */ UA_Variant input; UA_Variant_init(&input); UA_Variant_setScalarCopy(&input, &subId, &UA_TYPES[UA_TYPES_UINT32]); size_t outputSize; UA_Variant *output; retval = UA_Client_call(client, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER), UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_GETMONITOREDITEMS), 1, &input, &outputSize, &output); ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD); ck_assert_uint_eq(outputSize, 2); ck_assert_uint_eq(output[0].arrayLength, 1); ck_assert_uint_eq(*((UA_UInt32*)output[0].data), monId); UA_Array_delete(output, outputSize, &UA_TYPES[UA_TYPES_VARIANT]); UA_Variant_deleteMembers(&input); /* call with invalid subscription id */ UA_Variant_init(&input); subId = 0; UA_Variant_setScalarCopy(&input, &subId, &UA_TYPES[UA_TYPES_UINT32]); retval = UA_Client_call(client, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER), UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_GETMONITOREDITEMS), 1, &input, &outputSize, &output); ck_assert_uint_eq(retval, UA_STATUSCODE_BADSUBSCRIPTIONIDINVALID); UA_Variant_deleteMembers(&input); UA_Client_disconnect(client); UA_Client_delete(client); }
END_TEST /* Send an async message and receive the response when the securechannel timed out */ START_TEST(SecureChannel_networkfail) { UA_Client *client = UA_Client_new(); UA_ClientConfig_setDefault(UA_Client_getConfig(client)); UA_StatusCode retval = UA_Client_connect(client, "opc.tcp://localhost:4840"); ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD); UA_ReadRequest rq; UA_ReadRequest_init(&rq); UA_ReadValueId rvi; UA_ReadValueId_init(&rvi); rvi.attributeId = UA_ATTRIBUTEID_VALUE; rvi.nodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_STATE); rq.nodesToRead = &rvi; rq.nodesToReadSize = 1; /* Forward the clock after recv in the client */ UA_ClientConfig *cconfig = UA_Client_getConfig(client); UA_Client_recv = client->connection.recv; client->connection.recv = UA_Client_recvTesting; UA_Client_recvSleepDuration = cconfig->secureChannelLifeTime + 1; UA_Variant val; UA_Variant_init(&val); UA_NodeId nodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_STATE); retval = UA_Client_readValueAttribute(client, nodeId, &val); ck_assert_msg(retval == UA_STATUSCODE_BADSECURECHANNELCLOSED); UA_Client_disconnect(client); UA_Client_delete(client); }
END_TEST /* Send the next message after the securechannel timed out */ START_TEST(SecureChannel_timeout_fail) { UA_Client *client = UA_Client_new(); UA_ClientConfig_setDefault(UA_Client_getConfig(client)); UA_StatusCode retval = UA_Client_connect(client, "opc.tcp://localhost:4840"); ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD); UA_ClientConfig *cconfig = UA_Client_getConfig(client); UA_fakeSleep(cconfig->secureChannelLifeTime + 1); UA_realSleep(50 + 1); // UA_MAXTIMEOUT+1 wait to be sure UA_Server_run_iterate can be completely executed UA_Variant val; UA_Variant_init(&val); UA_NodeId nodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_STATE); retval = UA_Client_readValueAttribute(client, nodeId, &val); ck_assert(retval != UA_STATUSCODE_GOOD); UA_Variant_deleteMembers(&val); UA_Client_disconnect(client); UA_Client_delete(client); }
/* UA_VariableTypeNode */ void UA_VariableTypeNode_init(UA_VariableTypeNode *p) { UA_Node_init((UA_Node*)p); p->nodeClass = UA_NODECLASS_VARIABLETYPE; p->valueSource = UA_VALUESOURCE_VARIANT; UA_Variant_init(&p->value.variant); p->valueRank = -2; // scalar or array of any dimension p->isAbstract = UA_FALSE; }
static UA_StatusCode parseVariableNode(UA_ExtensionObject *attributes, UA_Node **new_node) { if(attributes->typeId.identifier.numeric != UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES].typeId.identifier.numeric + UA_ENCODINGOFFSET_BINARY) return UA_STATUSCODE_BADNODEATTRIBUTESINVALID; UA_VariableAttributes attr; size_t pos = 0; // todo return more informative error codes from decodeBinary if(UA_VariableAttributes_decodeBinary(&attributes->body, &pos, &attr) != UA_STATUSCODE_GOOD) return UA_STATUSCODE_BADNODEATTRIBUTESINVALID; UA_VariableNode *vnode = UA_VariableNode_new(); if(!vnode) { UA_VariableAttributes_deleteMembers(&attr); return UA_STATUSCODE_BADOUTOFMEMORY; } // now copy all the attributes. This potentially removes them from the decoded attributes. COPY_STANDARDATTRIBUTES; if(attr.specifiedAttributes & UA_NODEATTRIBUTESMASK_ACCESSLEVEL) vnode->accessLevel = attr.accessLevel; if(attr.specifiedAttributes & UA_NODEATTRIBUTESMASK_USERACCESSLEVEL) vnode->userAccessLevel = attr.userAccessLevel; if(attr.specifiedAttributes & UA_NODEATTRIBUTESMASK_HISTORIZING) vnode->historizing = attr.historizing; if(attr.specifiedAttributes & UA_NODEATTRIBUTESMASK_MINIMUMSAMPLINGINTERVAL) vnode->minimumSamplingInterval = attr.minimumSamplingInterval; if(attr.specifiedAttributes & UA_NODEATTRIBUTESMASK_VALUERANK) vnode->valueRank = attr.valueRank; // don't use extra dimension spec. This comes from the value. /* if(attr.specifiedAttributes & UA_NODEATTRIBUTESMASK_ARRAYDIMENSIONS) { */ /* vnode->arrayDimensionsSize = attr.arrayDimensionsSize; */ /* vnode->arrayDimensions = attr.arrayDimensions; */ /* attr.arrayDimensionsSize = -1; */ /* attr.arrayDimensions = UA_NULL; */ /* } */ // don't use the extra type id. This comes from the value. /* if(attr.specifiedAttributes & UA_NODEATTRIBUTESMASK_DATATYPE || */ /* attr.specifiedAttributes & UA_NODEATTRIBUTESMASK_OBJECTTYPEORDATATYPE) { */ /* vnode->dataType = attr.dataType; */ /* UA_NodeId_init(&attr.dataType); */ /* } */ if(attr.specifiedAttributes & UA_NODEATTRIBUTESMASK_VALUE) { vnode->value.variant = attr.value; UA_Variant_init(&attr.value); } UA_VariableAttributes_deleteMembers(&attr); *new_node = (UA_Node*)vnode; return UA_STATUSCODE_GOOD; }
/* UA_VariableNode */ void UA_VariableNode_init(UA_VariableNode *p) { UA_Node_init((UA_Node*)p); p->nodeClass = UA_NODECLASS_VARIABLE; p->valueSource = UA_VALUESOURCE_VARIANT; UA_Variant_init(&p->value.variant); p->valueRank = -2; // scalar or array of any dimension p->accessLevel = 0; p->userAccessLevel = 0; p->minimumSamplingInterval = 0.0; p->historizing = UA_FALSE; }
END_TEST START_TEST(Nodes_createCustomObjectType) { // Create a custom object type "CustomDemoType" which has a "CustomStateType" component UA_StatusCode retval = UA_STATUSCODE_GOOD; /* create new object type node which has a subcomponent of the type StateType */ UA_ObjectTypeAttributes otAttr = UA_ObjectTypeAttributes_default; otAttr.displayName = UA_LOCALIZEDTEXT("", "CustomDemoType"); otAttr.description = UA_LOCALIZEDTEXT("", ""); retval = UA_Server_addObjectTypeNode(server, UA_NODEID_NUMERIC(1, 6010), UA_NODEID_NUMERIC(0, UA_NS0ID_BASEOBJECTTYPE), UA_NODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE), UA_QUALIFIEDNAME(1, "CustomDemoType"), otAttr, NULL, NULL); ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD); UA_ObjectAttributes oAttr = UA_ObjectAttributes_default; oAttr.displayName = UA_LOCALIZEDTEXT("", "State"); oAttr.description = UA_LOCALIZEDTEXT("", ""); retval = UA_Server_addObjectNode(server, UA_NODEID_NUMERIC(1, 6011), UA_NODEID_NUMERIC(1, 6010), UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT), UA_QUALIFIEDNAME(1, "State"), UA_NODEID_NUMERIC(1, 6000), oAttr, NULL, NULL); ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD); /* modelling rule is mandatory so it will be inherited for the object created from CustomDemoType */ retval = UA_Server_addReference(server, UA_NODEID_NUMERIC(1, 6011), UA_NODEID_NUMERIC(0, UA_NS0ID_HASMODELLINGRULE), UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_MODELLINGRULE_MANDATORY), true); ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD); /* assign a default value to the attribute "StateNumber" inside the state attribute (part of the MyDemoType) */ UA_Variant stateNum; UA_Variant_init(&stateNum); UA_Variant_setScalar(&stateNum, &valueToBeInherited, &UA_TYPES[UA_TYPES_UINT32]); UA_NodeId childID; findChildId(UA_NODEID_NUMERIC(1, 6011), UA_NODEID_NUMERIC(0, UA_NS0ID_HASPROPERTY), UA_QUALIFIEDNAME(1, "CustomStateNumber"), &childID); ck_assert(!UA_NodeId_isNull(&childID)); retval = UA_Server_writeValue(server, childID, stateNum); ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD); }
int main(void) { signal(SIGINT, stopHandler); /* catches ctrl-c */ UA_ClientConfig config = UA_ClientConfig_default; /* default timeout is 5 seconds. Set it to 1 second here for demo */ config.timeout = 1000; UA_Client *client = UA_Client_new(config); /* Read the value attribute of the node. UA_Client_readValueAttribute is a * wrapper for the raw read service available as UA_Client_Service_read. */ UA_Variant value; /* Variants can hold scalar values and arrays of any type */ UA_Variant_init(&value); /* Endless loop reading the server time */ while (running) { /* if already connected, this will return GOOD and do nothing */ /* if the connection is closed/errored, the connection will be reset and then reconnected */ /* Alternatively you can also use UA_Client_getState to get the current state */ UA_StatusCode retval = UA_Client_connect(client, "opc.tcp://localhost:4840"); if (retval != UA_STATUSCODE_GOOD) { UA_LOG_ERROR(logger, UA_LOGCATEGORY_CLIENT, "Not connected. Retrying to connect in 1 second"); /* The connect may timeout after 1 second (see above) or it may fail immediately on network errors */ /* E.g. name resolution errors or unreachable network. Thus there should be a small sleep here */ UA_sleep_ms(1000); continue; } /* NodeId of the variable holding the current time */ const UA_NodeId nodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_CURRENTTIME); retval = UA_Client_readValueAttribute(client, nodeId, &value); if (retval == UA_STATUSCODE_BADCONNECTIONCLOSED) { UA_LOG_ERROR(logger, UA_LOGCATEGORY_CLIENT, "Connection was closed. Reconnecting ..."); continue; } if (retval == UA_STATUSCODE_GOOD && UA_Variant_hasScalarType(&value, &UA_TYPES[UA_TYPES_DATETIME])) { UA_DateTime raw_date = *(UA_DateTime *) value.data; UA_String string_date = UA_DateTime_toString(raw_date); UA_LOG_INFO(logger, UA_LOGCATEGORY_CLIENT, "string date is: %.*s", (int) string_date.length, string_date.data); UA_String_deleteMembers(&string_date); } UA_sleep_ms(1000); }; /* Clean up */ UA_Variant_deleteMembers(&value); UA_Client_delete(client); /* Disconnects the client internally */ return UA_STATUSCODE_GOOD; }
UA_StatusCode __UA_Client_readAttribute(UA_Client *client, const UA_NodeId *nodeId, UA_AttributeId attributeId, void *out, const UA_DataType *outDataType) { UA_ReadValueId item; UA_ReadValueId_init(&item); item.nodeId = *nodeId; item.attributeId = attributeId; UA_ReadRequest request; UA_ReadRequest_init(&request); request.nodesToRead = &item; request.nodesToReadSize = 1; UA_ReadResponse response = UA_Client_Service_read(client, request); UA_StatusCode retval = response.responseHeader.serviceResult; if(retval == UA_STATUSCODE_GOOD && response.resultsSize != 1) retval = UA_STATUSCODE_BADUNEXPECTEDERROR; if(retval != UA_STATUSCODE_GOOD) { UA_ReadResponse_deleteMembers(&response); return retval; } UA_DataValue *res = response.results; if(res->hasStatus != UA_STATUSCODE_GOOD) retval = res->hasStatus; else if(!res->hasValue || !UA_Variant_isScalar(&res->value)) retval = UA_STATUSCODE_BADUNEXPECTEDERROR; if(retval != UA_STATUSCODE_GOOD) { UA_ReadResponse_deleteMembers(&response); return retval; } if(attributeId == UA_ATTRIBUTEID_VALUE) { memcpy(out, &res->value, sizeof(UA_Variant)); UA_Variant_init(&res->value); } else if(UA_Variant_isScalar(&res->value) && res->value.type == outDataType) { memcpy(out, res->value.data, res->value.type->memSize); UA_free(res->value.data); res->value.data = NULL; } else { retval = UA_STATUSCODE_BADUNEXPECTEDERROR; } UA_ReadResponse_deleteMembers(&response); return retval; }
END_TEST START_TEST(Nodes_checkInheritedValue) { UA_NodeId childState; findChildId(UA_NODEID_NUMERIC(1, 6020), UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT), UA_QUALIFIEDNAME(1, "State"), &childState); ck_assert(!UA_NodeId_isNull(&childState)); UA_NodeId childNumber; findChildId(childState, UA_NODEID_NUMERIC(0, UA_NS0ID_HASPROPERTY), UA_QUALIFIEDNAME(1, "CustomStateNumber"), &childNumber); ck_assert(!UA_NodeId_isNull(&childNumber)); UA_Variant inheritedValue; UA_Variant_init(&inheritedValue); UA_Server_readValue(server, childNumber, &inheritedValue); ck_assert(inheritedValue.type == &UA_TYPES[UA_TYPES_UINT32]); UA_UInt32 *value = (UA_UInt32 *) inheritedValue.data; ck_assert_int_eq(*value, valueToBeInherited); UA_Variant_deleteMembers(&inheritedValue); }
UA_StatusCode UA_Server_addVariableNode(UA_Server *server, UA_Variant *value, const UA_QualifiedName browseName, UA_NodeId nodeId, const UA_NodeId parentNodeId, const UA_NodeId referenceTypeId) { UA_VariableNode *node = UA_VariableNode_new(); node->value.variant = *value; // copy content UA_NodeId_copy(&nodeId, &node->nodeId); UA_QualifiedName_copy(&browseName, &node->browseName); UA_String_copy(&browseName.name, &node->displayName.text); UA_ExpandedNodeId parentId; // we need an expandednodeid UA_ExpandedNodeId_init(&parentId); UA_NodeId_copy(&parentNodeId, &parentId.nodeId); UA_AddNodesResult res = UA_Server_addNodeWithSession(server, &adminSession, (UA_Node*)node, parentId, referenceTypeId); ADDREFERENCE(res.addedNodeId, UA_NODEID_NUMERIC(0, UA_NS0ID_HASTYPEDEFINITION), UA_EXPANDEDNODEID_NUMERIC(0, value->type->typeId.identifier.numeric)); if(res.statusCode != UA_STATUSCODE_GOOD) { UA_Variant_init(&node->value.variant); UA_VariableNode_delete(node); } else UA_free(value); UA_AddNodesResult_deleteMembers(&res); return res.statusCode; }
/* force cast for zero-copy reading. ensure that the variant is never written into. */ static void forceVariantSetScalar(UA_Variant *v, const void *p, const UA_DataType *type) { UA_Variant_init(v); v->type = type; v->data = (void*)(uintptr_t)p; v->storageType = UA_VARIANT_DATA_NODELETE; }
void Service_Read(UA_Server *server, UA_Session *session, const UA_ReadRequest *request, UA_ReadResponse *response) { if(request->nodesToReadSize <= 0) { response->responseHeader.serviceResult = UA_STATUSCODE_BADNOTHINGTODO; return; } if(request->timestampsToReturn > 3){ response->responseHeader.serviceResult = UA_STATUSCODE_BADTIMESTAMPSTORETURNINVALID; return; } size_t size = request->nodesToReadSize; response->results = UA_Array_new(&UA_TYPES[UA_TYPES_DATAVALUE], size); if(!response->results) { response->responseHeader.serviceResult = UA_STATUSCODE_BADOUTOFMEMORY; return; } response->resultsSize = size; if(request->maxAge < 0) { response->responseHeader.serviceResult = UA_STATUSCODE_BADMAXAGEINVALID; return; } /* ### Begin External Namespaces */ UA_Boolean *isExternal = UA_alloca(sizeof(UA_Boolean) * size); UA_memset(isExternal, UA_FALSE, sizeof(UA_Boolean) * size); UA_UInt32 *indices = UA_alloca(sizeof(UA_UInt32) * size); for(UA_Int32 j = 0;j<server->externalNamespacesSize;j++) { size_t indexSize = 0; for(size_t i = 0;i < size;i++) { if(request->nodesToRead[i].nodeId.namespaceIndex != server->externalNamespaces[j].index) continue; isExternal[i] = UA_TRUE; indices[indexSize] = i; indexSize++; } if(indexSize == 0) continue; UA_ExternalNodeStore *ens = &server->externalNamespaces[j].externalNodeStore; ens->readNodes(ens->ensHandle, &request->requestHeader, request->nodesToRead, indices, indexSize, response->results, UA_FALSE, response->diagnosticInfos); } /* ### End External Namespaces */ for(size_t i = 0;i < size;i++) { if(!isExternal[i]) readValue(server, request->timestampsToReturn, &request->nodesToRead[i], &response->results[i]); } #ifdef EXTENSION_STATELESS if(session==&anonymousSession){ /* expiry header */ UA_ExtensionObject additionalHeader; UA_ExtensionObject_init(&additionalHeader); additionalHeader.encoding = UA_EXTENSIONOBJECT_ENCODINGMASK_BODYISBYTESTRING; UA_Variant variant; UA_Variant_init(&variant); variant.type = &UA_TYPES[UA_TYPES_DATETIME]; variant.arrayLength = request->nodesToReadSize; UA_DateTime* expireArray = UA_NULL; expireArray = UA_Array_new(&UA_TYPES[UA_TYPES_DATETIME], request->nodesToReadSize); variant.data = expireArray; UA_ByteString str; UA_ByteString_init(&str); /*expires in 20 seconds*/ for(UA_Int32 i = 0;i < response->resultsSize;i++) { expireArray[i] = UA_DateTime_now() + 20 * 100 * 1000 * 1000; } size_t offset = 0; str.data = UA_malloc(UA_Variant_calcSizeBinary(&variant)); str.length = UA_Variant_calcSizeBinary(&variant); UA_Variant_encodeBinary(&variant, &str, &offset); additionalHeader.body = str; response->responseHeader.additionalHeader = additionalHeader; } #endif }
} 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
void Service_Read(UA_Server *server, UA_Session *session, const UA_ReadRequest *request, UA_ReadResponse *response) { UA_LOG_DEBUG(server->config.logger, UA_LOGCATEGORY_SESSION, "Processing ReadRequest for Session (ns=%i,i=%i)", session->sessionId.namespaceIndex, session->sessionId.identifier.numeric); if(request->nodesToReadSize <= 0) { response->responseHeader.serviceResult = UA_STATUSCODE_BADNOTHINGTODO; return; } if(request->timestampsToReturn > 3){ response->responseHeader.serviceResult = UA_STATUSCODE_BADTIMESTAMPSTORETURNINVALID; return; } size_t size = request->nodesToReadSize; response->results = UA_Array_new(size, &UA_TYPES[UA_TYPES_DATAVALUE]); if(!response->results) { response->responseHeader.serviceResult = UA_STATUSCODE_BADOUTOFMEMORY; return; } response->resultsSize = size; if(request->maxAge < 0) { response->responseHeader.serviceResult = UA_STATUSCODE_BADMAXAGEINVALID; return; } #ifdef UA_ENABLE_EXTERNAL_NAMESPACES UA_Boolean isExternal[size]; UA_UInt32 indices[size]; memset(isExternal, UA_FALSE, sizeof(UA_Boolean) * size); for(size_t j = 0;j<server->externalNamespacesSize;j++) { size_t indexSize = 0; for(size_t i = 0;i < size;i++) { if(request->nodesToRead[i].nodeId.namespaceIndex != server->externalNamespaces[j].index) continue; isExternal[i] = UA_TRUE; indices[indexSize] = i; indexSize++; } if(indexSize == 0) continue; UA_ExternalNodeStore *ens = &server->externalNamespaces[j].externalNodeStore; ens->readNodes(ens->ensHandle, &request->requestHeader, request->nodesToRead, indices, indexSize, response->results, UA_FALSE, response->diagnosticInfos); } #endif for(size_t i = 0;i < size;i++) { #ifdef UA_ENABLE_EXTERNAL_NAMESPACES if(!isExternal[i]) #endif Service_Read_single(server, session, request->timestampsToReturn, &request->nodesToRead[i], &response->results[i]); } #ifdef UA_ENABLE_NONSTANDARD_STATELESS /* Add an expiry header for caching */ if(session==&anonymousSession){ UA_ExtensionObject additionalHeader; UA_ExtensionObject_init(&additionalHeader); additionalHeader.typeId = UA_TYPES[UA_TYPES_VARIANT].typeId; additionalHeader.encoding = UA_EXTENSIONOBJECT_ENCODINGMASK_BODYISBYTESTRING; UA_Variant variant; UA_Variant_init(&variant); UA_DateTime* expireArray = NULL; expireArray = UA_Array_new(&UA_TYPES[UA_TYPES_DATETIME], request->nodesToReadSize); variant.data = expireArray; /*expires in 20 seconds*/ for(UA_Int32 i = 0;i < response->resultsSize;i++) { expireArray[i] = UA_DateTime_now() + 20 * 100 * 1000 * 1000; } UA_Variant_setArray(&variant, expireArray, request->nodesToReadSize, &UA_TYPES[UA_TYPES_DATETIME]); size_t offset = 0; UA_ByteString str; UA_ByteString_newMembers(&str, 65536); UA_Variant_encodeBinary(&variant, &str, &offset); UA_Array_delete(expireArray, &UA_TYPES[UA_TYPES_DATETIME], request->nodesToReadSize); additionalHeader.body = str; additionalHeader.body.length = offset; response->responseHeader.additionalHeader = additionalHeader; } #endif }
int main(int argc, char *argv[]) { UA_Client *client = UA_Client_new(UA_ClientConfig_standard, Logger_Stdout_new()); UA_StatusCode retval = UA_Client_connect(client, ClientNetworkLayerTCP_connect, "opc.tcp://localhost:16664"); if(retval != UA_STATUSCODE_GOOD) { UA_Client_delete(client); return retval; } // Browse some objects printf("Browsing nodes in objects folder:\n"); UA_BrowseRequest bReq; UA_BrowseRequest_init(&bReq); bReq.requestedMaxReferencesPerNode = 0; bReq.nodesToBrowse = UA_BrowseDescription_new(); bReq.nodesToBrowseSize = 1; bReq.nodesToBrowse[0].nodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER); //browse objects folder bReq.nodesToBrowse[0].resultMask = UA_BROWSERESULTMASK_ALL; //return everything UA_BrowseResponse bResp = UA_Client_browse(client, &bReq); printf("%-9s %-16s %-16s %-16s\n", "NAMESPACE", "NODEID", "BROWSE NAME", "DISPLAY NAME"); for (int i = 0; i < bResp.resultsSize; ++i) { for (int j = 0; j < bResp.results[i].referencesSize; ++j) { UA_ReferenceDescription *ref = &(bResp.results[i].references[j]); if(ref->nodeId.nodeId.identifierType == UA_NODEIDTYPE_NUMERIC) { printf("%-9d %-16d %-16.*s %-16.*s\n", ref->browseName.namespaceIndex, ref->nodeId.nodeId.identifier.numeric, ref->browseName.name.length, ref->browseName.name.data, ref->displayName.text.length, ref->displayName.text.data); } else if(ref->nodeId.nodeId.identifierType == UA_NODEIDTYPE_STRING) { printf("%-9d %-16.*s %-16.*s %-16.*s\n", ref->browseName.namespaceIndex, ref->nodeId.nodeId.identifier.string.length, ref->nodeId.nodeId.identifier.string.data, ref->browseName.name.length, ref->browseName.name.data, ref->displayName.text.length, ref->displayName.text.data); } //TODO: distinguish further types } } UA_BrowseRequest_deleteMembers(&bReq); UA_BrowseResponse_deleteMembers(&bResp); #ifdef ENABLE_SUBSCRIPTIONS // Create a subscription with interval 0 (immediate)... UA_Int32 subId = UA_Client_newSubscription(client, 0); if (subId) printf("Create subscription succeeded, id %u\n", subId); // .. and monitor TheAnswer UA_NodeId monitorThis; monitorThis = UA_NODEID_STRING_ALLOC(1, "the.answer"); UA_UInt32 monId = UA_Client_monitorItemChanges(client, subId, monitorThis, UA_ATTRIBUTEID_VALUE, &handler_TheAnswerChanged ); if (monId) printf("Monitoring 'the.answer', id %u\n", subId); UA_NodeId_deleteMembers(&monitorThis); // First Publish always generates data (current value) and call out handler. UA_Client_doPublish(client); // This should not generate anything UA_Client_doPublish(client); #endif UA_Int32 value = 0; // Read node's value printf("\nReading the value of node (1, \"the.answer\"):\n"); UA_ReadRequest rReq; UA_ReadRequest_init(&rReq); rReq.nodesToRead = UA_ReadValueId_new(); rReq.nodesToReadSize = 1; rReq.nodesToRead[0].nodeId = UA_NODEID_STRING_ALLOC(1, "the.answer"); /* assume this node exists */ rReq.nodesToRead[0].attributeId = UA_ATTRIBUTEID_VALUE; UA_ReadResponse rResp = UA_Client_read(client, &rReq); if(rResp.responseHeader.serviceResult == UA_STATUSCODE_GOOD && rResp.resultsSize > 0 && rResp.results[0].hasValue && UA_Variant_isScalar(&rResp.results[0].value) && rResp.results[0].value.type == &UA_TYPES[UA_TYPES_INT32]) { value = *(UA_Int32*)rResp.results[0].value.data; printf("the value is: %i\n", value); } UA_ReadRequest_deleteMembers(&rReq); UA_ReadResponse_deleteMembers(&rResp); value++; // Write node's value printf("\nWriting a value of node (1, \"the.answer\"):\n"); UA_WriteRequest wReq; UA_WriteRequest_init(&wReq); wReq.nodesToWrite = UA_WriteValue_new(); wReq.nodesToWriteSize = 1; wReq.nodesToWrite[0].nodeId = UA_NODEID_STRING_ALLOC(1, "the.answer"); /* assume this node exists */ wReq.nodesToWrite[0].attributeId = UA_ATTRIBUTEID_VALUE; wReq.nodesToWrite[0].value.hasValue = UA_TRUE; wReq.nodesToWrite[0].value.value.type = &UA_TYPES[UA_TYPES_INT32]; wReq.nodesToWrite[0].value.value.storageType = UA_VARIANT_DATA_NODELETE; //do not free the integer on deletion wReq.nodesToWrite[0].value.value.data = &value; UA_WriteResponse wResp = UA_Client_write(client, &wReq); if(wResp.responseHeader.serviceResult == UA_STATUSCODE_GOOD) printf("the new value is: %i\n", value); UA_WriteRequest_deleteMembers(&wReq); UA_WriteResponse_deleteMembers(&wResp); #ifdef ENABLE_SUBSCRIPTIONS // Take another look at the.answer... this should call the handler. UA_Client_doPublish(client); // Delete our subscription (which also unmonitors all items) if(!UA_Client_removeSubscription(client, subId)) printf("Subscription removed\n"); #endif #ifdef ENABLE_METHODCALLS /* Note: This example requires Namespace 0 Node 11489 (ServerType -> GetMonitoredItems) FIXME: Provide a namespace 0 independant example on the server side */ UA_Variant input; UA_String argString = UA_STRING("Hello Server"); UA_Variant_init(&input); UA_Variant_setScalarCopy(&input, &argString, &UA_TYPES[UA_TYPES_STRING]); UA_Int32 outputSize; UA_Variant *output; retval = UA_Client_CallServerMethod(client, UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER), UA_NODEID_NUMERIC(1, 62541), 1, &input, &outputSize, &output); if(retval == UA_STATUSCODE_GOOD) { printf("Method call was successfull, and %i returned values available.\n", outputSize); UA_Array_delete(output, &UA_TYPES[UA_TYPES_VARIANT], outputSize); } else { printf("Method call was unsuccessfull, and %x returned values available.\n", retval); } UA_Variant_deleteMembers(&input); #endif #ifdef ENABLE_ADDNODES /* Create a new object type node */ // New ReferenceType UA_AddNodesResponse *adResp = UA_Client_createReferenceTypeNode(client, UA_EXPANDEDNODEID_NUMERIC(1, 12133), // Assign this NodeId (will fail if client is called multiple times) UA_QUALIFIEDNAME(0, "NewReference"), UA_LOCALIZEDTEXT("en_US", "TheNewReference"), UA_LOCALIZEDTEXT("en_US", "References something that might or might not exist."), UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER), UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES), (UA_UInt32) 0, (UA_UInt32) 0, UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER), UA_LOCALIZEDTEXT("en_US", "IsNewlyReferencedBy")); if (adResp->resultsSize > 0 && adResp->results[0].statusCode == UA_STATUSCODE_GOOD ) { printf("Created 'NewReference' with numeric NodeID %u\n", adResp->results[0].addedNodeId.identifier.numeric ); } UA_AddNodesResponse_deleteMembers(adResp); free(adResp); // New ObjectType adResp = UA_Client_createObjectTypeNode(client, UA_EXPANDEDNODEID_NUMERIC(1, 12134), // Assign this NodeId (will fail if client is called multiple times) UA_QUALIFIEDNAME(0, "NewObjectType"), UA_LOCALIZEDTEXT("en_US", "TheNewObjectType"), UA_LOCALIZEDTEXT("en_US", "Put innovative description here."), UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER), UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES), (UA_UInt32) 0, (UA_UInt32) 0, UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER)); if (adResp->resultsSize > 0 && adResp->results[0].statusCode == UA_STATUSCODE_GOOD ) { printf("Created 'NewObjectType' with numeric NodeID %u\n", adResp->results[0].addedNodeId.identifier.numeric ); } // New Object adResp = UA_Client_createObjectNode(client, UA_EXPANDEDNODEID_NUMERIC(1, 0), // Assign new/random NodeID UA_QUALIFIEDNAME(0, "TheNewGreatNodeBrowseName"), UA_LOCALIZEDTEXT("en_US", "TheNewGreatNode"), UA_LOCALIZEDTEXT("de_DE", "Hier koennte Ihre Webung stehen!"), UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER), UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES), (UA_UInt32) 0, (UA_UInt32) 0, UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER)); if (adResp->resultsSize > 0 && adResp->results[0].statusCode == UA_STATUSCODE_GOOD ) { printf("Created 'NewObject' with numeric NodeID %u\n", adResp->results[0].addedNodeId.identifier.numeric ); } UA_AddNodesResponse_deleteMembers(adResp); free(adResp); // New Integer Variable UA_Variant *theValue = UA_Variant_new(); UA_Int32 *theValueDate = UA_Int32_new(); *theValueDate = 1234; theValue->type = &UA_TYPES[UA_TYPES_INT32]; theValue->data = theValueDate; adResp = UA_Client_createVariableNode(client, UA_EXPANDEDNODEID_NUMERIC(1, 0), // Assign new/random NodeID UA_QUALIFIEDNAME(0, "VariableNode"), UA_LOCALIZEDTEXT("en_US", "TheNewVariableNode"), UA_LOCALIZEDTEXT("en_US", "This integer is just amazing - it has digits and everything."), UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER), UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES), (UA_UInt32) 0, (UA_UInt32) 0, UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER), UA_NODEID_NUMERIC(0, UA_NS0ID_INT32), theValue); if (adResp->resultsSize > 0 && adResp->results[0].statusCode == UA_STATUSCODE_GOOD ) { printf("Created 'NewVariable' with numeric NodeID %u\n", adResp->results[0].addedNodeId.identifier.numeric ); } UA_AddNodesResponse_deleteMembers(adResp); free(adResp); free(theValue); /* Done creating a new node*/ #endif UA_Client_disconnect(client); UA_Client_delete(client); return UA_STATUSCODE_GOOD; }
int main(int argc, char *argv[]) { UA_Client *client = UA_Client_new(UA_ClientConfig_standard); //listing endpoints UA_EndpointDescription* endpointArray = NULL; size_t endpointArraySize = 0; UA_StatusCode retval = UA_Client_getEndpoints(client, "opc.tcp://localhost:16664", &endpointArraySize, &endpointArray); //freeing the endpointArray if(retval != UA_STATUSCODE_GOOD) { //cleanup array UA_Array_delete(endpointArray,endpointArraySize, &UA_TYPES[UA_TYPES_ENDPOINTDESCRIPTION]); UA_Client_delete(client); return (int)retval; } printf("%i endpoints found\n", (int)endpointArraySize); for(size_t i=0;i<endpointArraySize;i++){ printf("URL of endpoint %i is %.*s\n", (int)i, (int)endpointArray[i].endpointUrl.length, endpointArray[i].endpointUrl.data); } //cleanup array of enpoints UA_Array_delete(endpointArray,endpointArraySize, &UA_TYPES[UA_TYPES_ENDPOINTDESCRIPTION]); //connect to a server //anonymous connect would be: retval = UA_Client_connect_username(client, UA_ClientConnectionTCP, "opc.tcp://localhost:16664"); retval = UA_Client_connect_username(client, "opc.tcp://localhost:16664", "user1", "password"); if(retval != UA_STATUSCODE_GOOD) { UA_Client_delete(client); return (int)retval; } // Browse some objects printf("Browsing nodes in objects folder:\n"); UA_BrowseRequest bReq; UA_BrowseRequest_init(&bReq); bReq.requestedMaxReferencesPerNode = 0; bReq.nodesToBrowse = UA_BrowseDescription_new(); bReq.nodesToBrowseSize = 1; bReq.nodesToBrowse[0].nodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER); //browse objects folder bReq.nodesToBrowse[0].resultMask = UA_BROWSERESULTMASK_ALL; //return everything UA_BrowseResponse bResp = UA_Client_Service_browse(client, bReq); printf("%-9s %-16s %-16s %-16s\n", "NAMESPACE", "NODEID", "BROWSE NAME", "DISPLAY NAME"); for (size_t i = 0; i < bResp.resultsSize; ++i) { for (size_t j = 0; j < bResp.results[i].referencesSize; ++j) { UA_ReferenceDescription *ref = &(bResp.results[i].references[j]); if(ref->nodeId.nodeId.identifierType == UA_NODEIDTYPE_NUMERIC) { printf("%-9d %-16d %-16.*s %-16.*s\n", ref->browseName.namespaceIndex, ref->nodeId.nodeId.identifier.numeric, (int)ref->browseName.name.length, ref->browseName.name.data, (int)ref->displayName.text.length, ref->displayName.text.data); } else if(ref->nodeId.nodeId.identifierType == UA_NODEIDTYPE_STRING) { printf("%-9d %-16.*s %-16.*s %-16.*s\n", ref->browseName.namespaceIndex, (int)ref->nodeId.nodeId.identifier.string.length, ref->nodeId.nodeId.identifier.string.data, (int)ref->browseName.name.length, ref->browseName.name.data, (int)ref->displayName.text.length, ref->displayName.text.data); } //TODO: distinguish further types } } UA_BrowseRequest_deleteMembers(&bReq); UA_BrowseResponse_deleteMembers(&bResp); // Same thing, this time using the node iterator... UA_NodeId *parent = UA_NodeId_new(); *parent = UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER); UA_Client_forEachChildNodeCall(client, UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER), nodeIter, (void *) parent); UA_NodeId_delete(parent); #ifdef UA_ENABLE_SUBSCRIPTIONS // Create a subscription with interval 0 (immediate)... UA_UInt32 subId=0; UA_Client_Subscriptions_new(client, UA_SubscriptionSettings_standard, &subId); if(subId) printf("Create subscription succeeded, id %u\n", subId); // .. and monitor TheAnswer UA_NodeId monitorThis = UA_NODEID_STRING(1, "the.answer"); UA_UInt32 monId=0; UA_Client_Subscriptions_addMonitoredItem(client, subId, monitorThis, UA_ATTRIBUTEID_VALUE, &handler_TheAnswerChanged, NULL, &monId); if (monId) printf("Monitoring 'the.answer', id %u\n", subId); // First Publish always generates data (current value) and call out handler. UA_Client_Subscriptions_manuallySendPublishRequest(client); // This should not generate anything UA_Client_Subscriptions_manuallySendPublishRequest(client); #endif UA_Int32 value = 0; // Read node's value printf("\nReading the value of node (1, \"the.answer\"):\n"); UA_ReadRequest rReq; UA_ReadRequest_init(&rReq); rReq.nodesToRead = UA_Array_new(1, &UA_TYPES[UA_TYPES_READVALUEID]); rReq.nodesToReadSize = 1; rReq.nodesToRead[0].nodeId = UA_NODEID_STRING_ALLOC(1, "the.answer"); /* assume this node exists */ rReq.nodesToRead[0].attributeId = UA_ATTRIBUTEID_VALUE; UA_ReadResponse rResp = UA_Client_Service_read(client, rReq); if(rResp.responseHeader.serviceResult == UA_STATUSCODE_GOOD && rResp.resultsSize > 0 && rResp.results[0].hasValue && UA_Variant_isScalar(&rResp.results[0].value) && rResp.results[0].value.type == &UA_TYPES[UA_TYPES_INT32]) { value = *(UA_Int32*)rResp.results[0].value.data; printf("the value is: %i\n", value); } UA_ReadRequest_deleteMembers(&rReq); UA_ReadResponse_deleteMembers(&rResp); value++; // Write node's value printf("\nWriting a value of node (1, \"the.answer\"):\n"); UA_WriteRequest wReq; UA_WriteRequest_init(&wReq); wReq.nodesToWrite = UA_WriteValue_new(); wReq.nodesToWriteSize = 1; wReq.nodesToWrite[0].nodeId = UA_NODEID_STRING_ALLOC(1, "the.answer"); /* assume this node exists */ wReq.nodesToWrite[0].attributeId = UA_ATTRIBUTEID_VALUE; wReq.nodesToWrite[0].value.hasValue = true; wReq.nodesToWrite[0].value.value.type = &UA_TYPES[UA_TYPES_INT32]; wReq.nodesToWrite[0].value.value.storageType = UA_VARIANT_DATA_NODELETE; //do not free the integer on deletion wReq.nodesToWrite[0].value.value.data = &value; UA_WriteResponse wResp = UA_Client_Service_write(client, wReq); if(wResp.responseHeader.serviceResult == UA_STATUSCODE_GOOD) printf("the new value is: %i\n", value); UA_WriteRequest_deleteMembers(&wReq); UA_WriteResponse_deleteMembers(&wResp); // Alternate Form, this time using the hl API value++; UA_Variant *myVariant = UA_Variant_new(); UA_Variant_setScalarCopy(myVariant, &value, &UA_TYPES[UA_TYPES_INT32]); UA_Client_writeValueAttribute(client, UA_NODEID_STRING(1, "the.answer"), myVariant); UA_Variant_delete(myVariant); #ifdef UA_ENABLE_SUBSCRIPTIONS // Take another look at the.answer... this should call the handler. UA_Client_Subscriptions_manuallySendPublishRequest(client); // Delete our subscription (which also unmonitors all items) if(!UA_Client_Subscriptions_remove(client, subId)) printf("Subscription removed\n"); #endif #ifdef UA_ENABLE_METHODCALLS /* Note: This example requires Namespace 0 Node 11489 (ServerType -> GetMonitoredItems) FIXME: Provide a namespace 0 independant example on the server side */ UA_Variant input; UA_String argString = UA_STRING("Hello Server"); UA_Variant_init(&input); UA_Variant_setScalarCopy(&input, &argString, &UA_TYPES[UA_TYPES_STRING]); size_t outputSize; UA_Variant *output; retval = UA_Client_call(client, UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER), UA_NODEID_NUMERIC(1, 62541), 1, &input, &outputSize, &output); if(retval == UA_STATUSCODE_GOOD) { printf("Method call was successfull, and %lu returned values available.\n", (unsigned long)outputSize); UA_Array_delete(output, outputSize, &UA_TYPES[UA_TYPES_VARIANT]); } else { printf("Method call was unsuccessfull, and %x returned values available.\n", retval); } UA_Variant_deleteMembers(&input); #endif #ifdef UA_ENABLE_NODEMANAGEMENT /* New ReferenceType */ UA_NodeId ref_id; UA_ReferenceTypeAttributes ref_attr; UA_ReferenceTypeAttributes_init(&ref_attr); ref_attr.displayName = UA_LOCALIZEDTEXT("en_US", "NewReference"); ref_attr.description = UA_LOCALIZEDTEXT("en_US", "References something that might or might not exist"); ref_attr.inverseName = UA_LOCALIZEDTEXT("en_US", "IsNewlyReferencedBy"); retval = UA_Client_addReferenceTypeNode(client, UA_NODEID_NUMERIC(1, 12133), UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES), UA_NODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE), UA_QUALIFIEDNAME(1, "NewReference"), ref_attr, &ref_id); if(retval == UA_STATUSCODE_GOOD ) printf("Created 'NewReference' with numeric NodeID %u\n", ref_id.identifier.numeric); /* New ObjectType */ UA_NodeId objt_id; UA_ObjectTypeAttributes objt_attr; UA_ObjectTypeAttributes_init(&objt_attr); objt_attr.displayName = UA_LOCALIZEDTEXT("en_US", "TheNewObjectType"); objt_attr.description = UA_LOCALIZEDTEXT("en_US", "Put innovative description here"); retval = UA_Client_addObjectTypeNode(client, UA_NODEID_NUMERIC(1, 12134), UA_NODEID_NUMERIC(0, UA_NS0ID_BASEOBJECTTYPE), UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES), UA_QUALIFIEDNAME(1, "NewObjectType"), objt_attr, &objt_id); if(retval == UA_STATUSCODE_GOOD) printf("Created 'NewObjectType' with numeric NodeID %u\n", objt_id.identifier.numeric); /* New Object */ UA_NodeId obj_id; UA_ObjectAttributes obj_attr; UA_ObjectAttributes_init(&obj_attr); obj_attr.displayName = UA_LOCALIZEDTEXT("en_US", "TheNewGreatNode"); obj_attr.description = UA_LOCALIZEDTEXT("de_DE", "Hier koennte Ihre Webung stehen!"); retval = UA_Client_addObjectNode(client, UA_NODEID_NUMERIC(1, 0), UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER), UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES), UA_QUALIFIEDNAME(1, "TheGreatNode"), UA_NODEID_NUMERIC(1, 12134), obj_attr, &obj_id); if(retval == UA_STATUSCODE_GOOD ) printf("Created 'NewObject' with numeric NodeID %u\n", obj_id.identifier.numeric); /* New Integer Variable */ UA_NodeId var_id; UA_VariableAttributes var_attr; UA_VariableAttributes_init(&var_attr); var_attr.displayName = UA_LOCALIZEDTEXT("en_US", "TheNewVariableNode"); var_attr.description = UA_LOCALIZEDTEXT("en_US", "This integer is just amazing - it has digits and everything."); UA_Int32 int_value = 1234; /* This does not copy the value */ UA_Variant_setScalar(&var_attr.value, &int_value, &UA_TYPES[UA_TYPES_INT32]); var_attr.dataType = UA_TYPES[UA_TYPES_INT32].typeId; retval = UA_Client_addVariableNode(client, UA_NODEID_NUMERIC(1, 0), // Assign new/random NodeID UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER), UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES), UA_QUALIFIEDNAME(0, "VariableNode"), UA_NODEID_NULL, // no variable type var_attr, &var_id); if(retval == UA_STATUSCODE_GOOD ) printf("Created 'NewVariable' with numeric NodeID %u\n", var_id.identifier.numeric); #endif UA_Client_disconnect(client); UA_Client_delete(client); return (int) UA_STATUSCODE_GOOD; }