/* 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 #include #include #include #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 (int)retval; } printf("%i endpoints found\n", (int)endpointArraySize); for(size_t i=0;inodeId.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 (int) UA_STATUSCODE_GOOD; }