| /* This work is licensed under a Creative Commons CCZero 1.0 Universal License. |
| * See http://creativecommons.org/publicdomain/zero/1.0/ for more information. */ |
| |
| #include <open62541/client_config_default.h> |
| #include <open62541/client_highlevel.h> |
| #include <open62541/client_subscriptions.h> |
| #include <open62541/plugin/log_stdout.h> |
| |
| #include <stdlib.h> |
| |
| #ifdef UA_ENABLE_SUBSCRIPTIONS |
| static void |
| handler_TheAnswerChanged(UA_Client *client, UA_UInt32 subId, void *subContext, |
| UA_UInt32 monId, void *monContext, UA_DataValue *value) { |
| printf("The Answer has changed!\n"); |
| } |
| #endif |
| |
| static UA_StatusCode |
| nodeIter(UA_NodeId childId, UA_Boolean isInverse, UA_NodeId referenceTypeId, void *handle) { |
| if(isInverse) |
| return UA_STATUSCODE_GOOD; |
| UA_NodeId *parent = (UA_NodeId *)handle; |
| printf("%d, %d --- %d ---> NodeId %d, %d\n", |
| parent->namespaceIndex, parent->identifier.numeric, |
| referenceTypeId.identifier.numeric, childId.namespaceIndex, |
| childId.identifier.numeric); |
| return UA_STATUSCODE_GOOD; |
| } |
| |
| int main(int argc, char *argv[]) { |
| UA_Client *client = UA_Client_new(); |
| UA_ClientConfig_setDefault(UA_Client_getConfig(client)); |
| |
| /* Listing endpoints */ |
| UA_EndpointDescription* endpointArray = NULL; |
| size_t endpointArraySize = 0; |
| UA_StatusCode retval = UA_Client_getEndpoints(client, "opc.tcp://localhost:4840", |
| &endpointArraySize, &endpointArray); |
| if(retval != UA_STATUSCODE_GOOD) { |
| UA_Array_delete(endpointArray, endpointArraySize, &UA_TYPES[UA_TYPES_ENDPOINTDESCRIPTION]); |
| UA_Client_delete(client); |
| return EXIT_FAILURE; |
| } |
| 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); |
| } |
| UA_Array_delete(endpointArray,endpointArraySize, &UA_TYPES[UA_TYPES_ENDPOINTDESCRIPTION]); |
| |
| /* Connect to a server */ |
| /* anonymous connect would be: retval = UA_Client_connect(client, "opc.tcp://localhost:4840"); */ |
| retval = UA_Client_connect_username(client, "opc.tcp://localhost:4840", "user1", "password"); |
| if(retval != UA_STATUSCODE_GOOD) { |
| UA_Client_delete(client); |
| return EXIT_FAILURE; |
| } |
| |
| /* 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->nodeId.nodeId.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->nodeId.nodeId.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_clear(&bReq); |
| UA_BrowseResponse_clear(&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 */ |
| UA_CreateSubscriptionRequest request = UA_CreateSubscriptionRequest_default(); |
| UA_CreateSubscriptionResponse response = UA_Client_Subscriptions_create(client, request, |
| NULL, NULL, NULL); |
| |
| UA_UInt32 subId = response.subscriptionId; |
| if(response.responseHeader.serviceResult == UA_STATUSCODE_GOOD) |
| printf("Create subscription succeeded, id %u\n", subId); |
| |
| UA_MonitoredItemCreateRequest monRequest = |
| UA_MonitoredItemCreateRequest_default(UA_NODEID_STRING(1, "the.answer")); |
| |
| UA_MonitoredItemCreateResult monResponse = |
| UA_Client_MonitoredItems_createDataChange(client, response.subscriptionId, |
| UA_TIMESTAMPSTORETURN_BOTH, |
| monRequest, NULL, handler_TheAnswerChanged, NULL); |
| if(monResponse.statusCode == UA_STATUSCODE_GOOD) |
| printf("Monitoring 'the.answer', id %u\n", monResponse.monitoredItemId); |
| |
| |
| /* The first publish request should return the initial value of the variable */ |
| UA_Client_run_iterate(client, 1000); |
| #endif |
| |
| /* Read attribute */ |
| UA_Int32 value = 0; |
| printf("\nReading the value of node (1, \"the.answer\"):\n"); |
| UA_Variant *val = UA_Variant_new(); |
| retval = UA_Client_readValueAttribute(client, UA_NODEID_STRING(1, "the.answer"), val); |
| if(retval == UA_STATUSCODE_GOOD && UA_Variant_isScalar(val) && |
| val->type == &UA_TYPES[UA_TYPES_INT32]) { |
| value = *(UA_Int32*)val->data; |
| printf("the value is: %i\n", value); |
| } |
| UA_Variant_delete(val); |
| |
| /* Write node attribute */ |
| 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"); |
| 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_clear(&wReq); |
| UA_WriteResponse_clear(&wResp); |
| |
| /* Write node attribute (using the highlevel 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 */ |
| UA_Client_run_iterate(client, 100); |
| /* Delete the subscription */ |
| if(UA_Client_Subscriptions_deleteSingle(client, subId) == UA_STATUSCODE_GOOD) |
| printf("Subscription removed\n"); |
| #endif |
| |
| #ifdef UA_ENABLE_METHODCALLS |
| /* Call a remote method */ |
| 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 successful, and %lu returned values available.\n", |
| (unsigned long)outputSize); |
| UA_Array_delete(output, outputSize, &UA_TYPES[UA_TYPES_VARIANT]); |
| } else { |
| printf("Method call was unsuccessful, and %x returned values available.\n", retval); |
| } |
| UA_Variant_clear(&input); |
| #endif |
| |
| #ifdef UA_ENABLE_NODEMANAGEMENT |
| /* Add new nodes*/ |
| /* New ReferenceType */ |
| UA_NodeId ref_id; |
| UA_ReferenceTypeAttributes ref_attr = UA_ReferenceTypeAttributes_default; |
| 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_default; |
| 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_HASSUBTYPE), |
| 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_default; |
| 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_default; |
| 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 EXIT_SUCCESS; |
| } |