optimize OPCUA demo and PLC demo and added PLC channel instead of bus
This commit is contained in:
@@ -1,3 +1,3 @@
|
||||
SRC_FILES := ua_data.c open62541.c ua_client.c ua_server.c ua_api.c
|
||||
SRC_FILES := ua_data.c open62541.c ua_client.c ua_server.c ua_api.c ua_test.c
|
||||
|
||||
include $(KERNEL_ROOT)/compiler.mk
|
||||
|
||||
@@ -44256,7 +44256,7 @@ UA_Client_run_iterate(UA_Client *client, UA_UInt32 timeout) {
|
||||
client->sessionState < UA_SESSIONSTATE_ACTIVATED) {
|
||||
retval = connectIterate(client, timeout);
|
||||
notifyClientState(client);
|
||||
lw_print("lw: [%s] ret %d timeout %d state %d ch %d\n", __func__, retval, timeout,
|
||||
ua_print("lw: [%s] ret %d timeout %d state %d ch %d\n", __func__, retval, timeout,
|
||||
client->sessionState, client->channel.state);
|
||||
return retval;
|
||||
}
|
||||
@@ -45299,7 +45299,7 @@ connectIterate(UA_Client *client, UA_UInt32 timeout) {
|
||||
break;
|
||||
}
|
||||
|
||||
lw_print("lw: [%s] sess %d conn %d\n", __func__, client->sessionState, client->connectStatus);
|
||||
ua_print("ua: [%s] sess %d conn %d\n", __func__, client->sessionState, client->connectStatus);
|
||||
return client->connectStatus;
|
||||
}
|
||||
|
||||
|
||||
@@ -10,33 +10,39 @@
|
||||
* See the Mulan PSL v2 for more details.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file ua_api.c
|
||||
* @brief Demo for OpcUa function
|
||||
* @version 1.0
|
||||
* @author AIIT XUOS Lab
|
||||
* @date 2021.11.11
|
||||
*/
|
||||
|
||||
#include "open62541.h"
|
||||
#include <stdlib.h>
|
||||
#include "ua_api.h"
|
||||
|
||||
|
||||
int ua_open(void *dev)
|
||||
{
|
||||
ua_dev_t *pdev = (ua_dev_t *)dev;
|
||||
UaParamType *param = (UaParamType *)dev;
|
||||
|
||||
pdev->client = UA_Client_new();
|
||||
param->client = UA_Client_new();
|
||||
|
||||
ua_pr_info("ua: [%s] start ...\n", __func__);
|
||||
|
||||
if (pdev->client == NULL)
|
||||
if (param->client == NULL)
|
||||
{
|
||||
ua_print("ua: [%s] tcp client null\n", __func__);
|
||||
return EEMPTY;
|
||||
}
|
||||
|
||||
UA_ClientConfig *config = UA_Client_getConfig(pdev->client);
|
||||
UA_ClientConfig *config = UA_Client_getConfig(param->client);
|
||||
UA_ClientConfig_setDefault(config);
|
||||
|
||||
ua_pr_info("ua: [%s] %d %s\n", __func__, strlen(pdev->ua_remote_ip), pdev->ua_remote_ip);
|
||||
ua_pr_info("ua: [%s] %d %s\n", __func__, strlen(param->ua_remote_ip), param->ua_remote_ip);
|
||||
|
||||
UA_StatusCode retval = UA_Client_connect(pdev->client, pdev->ua_remote_ip);
|
||||
UA_StatusCode retval = UA_Client_connect(param->client, param->ua_remote_ip);
|
||||
if(retval != UA_STATUSCODE_GOOD) {
|
||||
// UA_Client_delete(pdev->client);
|
||||
ua_pr_info("ua: [%s] deleted ret %x!\n", __func__, retval);
|
||||
return (int)retval;
|
||||
}
|
||||
@@ -45,28 +51,48 @@ int ua_open(void *dev)
|
||||
|
||||
void ua_close(void *dev)
|
||||
{
|
||||
ua_dev_t *pdev = (ua_dev_t *)dev;
|
||||
UA_Client_disconnect(pdev->client);
|
||||
UA_Client_delete(pdev->client); /* Disconnects the client internally */
|
||||
UaParamType *param = (UaParamType *)dev;
|
||||
UA_Client_disconnect(param->client);
|
||||
UA_Client_delete(param->client); /* Disconnects the client internally */
|
||||
}
|
||||
|
||||
int ua_read(void* dev, void *buf, size_t len)
|
||||
int ua_read(void *dev, void *buf, size_t len)
|
||||
{
|
||||
ua_dev_t *pdev = (ua_dev_t *)dev;
|
||||
ua_get_server_info(pdev->client);
|
||||
UaParamType *param = (UaParamType *)dev;
|
||||
switch(param->act)
|
||||
{
|
||||
case UA_ACT_ATTR:
|
||||
ua_read_nodeid_value(param->client, param->ua_id, buf);
|
||||
break;
|
||||
case UA_ACT_OBJ:
|
||||
ua_test_browser_objects(param->client);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return EOK;
|
||||
}
|
||||
|
||||
int ua_write(void* dev, const void *buf, size_t len)
|
||||
int ua_write(void *dev, const void *buf, size_t len)
|
||||
{
|
||||
ua_dev_t *pdev = (ua_dev_t *)dev;
|
||||
UaParamType *param = (UaParamType *)dev;
|
||||
|
||||
switch(param->act)
|
||||
{
|
||||
case UA_ACT_ATTR:
|
||||
ua_write_nodeid_value(param->client, param->ua_id, (char *)buf);
|
||||
break;
|
||||
case UA_ACT_OBJ:
|
||||
ua_test_browser_objects(param->client);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return EOK;
|
||||
}
|
||||
|
||||
int ua_ioctl(void* dev, int cmd, void *arg)
|
||||
int ua_ioctl(void *dev, int cmd, void *arg)
|
||||
{
|
||||
return EOK;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -9,35 +9,50 @@
|
||||
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
||||
* See the Mulan PSL v2 for more details.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file ua_api.h
|
||||
* @brief API for OpcUa function
|
||||
* @version 1.0
|
||||
* @author AIIT XUOS Lab
|
||||
* @date 2021.11.11
|
||||
*/
|
||||
|
||||
#ifndef __UA_API_H__
|
||||
#define __UA_API_H__
|
||||
|
||||
#include "open62541.h"
|
||||
|
||||
#define UA_DEV_IP_LEN 128
|
||||
#define UA_NODE_LEN 50
|
||||
#define UA_DEV_IP_LEN 48
|
||||
#define UA_NODE_LEN 32
|
||||
|
||||
typedef struct _ua_dev_t
|
||||
enum UaAction_e
|
||||
{
|
||||
UA_ACT_ATTR,
|
||||
UA_ACT_OBJ,
|
||||
};
|
||||
|
||||
typedef struct UaParam
|
||||
{
|
||||
enum UaAction_e act;
|
||||
UA_NodeId ua_id;
|
||||
char ua_remote_ip[UA_DEV_IP_LEN];
|
||||
char ua_node[UA_NODE_LEN];
|
||||
UA_Client *client;
|
||||
}ua_dev_t;
|
||||
}UaParamType;
|
||||
|
||||
#define OPC_SERVER "opc.tcp://192.168.250.5:4840"
|
||||
#define OPC_SERVER "opc.tcp://192.168.250.2:4840"
|
||||
|
||||
#define ua_print //KPrintf
|
||||
#define ua_trace() //KPrintf("ua: [%s] line %d checked!\n", __func__, __LINE__)
|
||||
#define ua_pr_info KPrintf
|
||||
#define ua_debug
|
||||
#define ua_debug //KPrintf
|
||||
|
||||
int ua_server_connect(void);
|
||||
int ua_get_server_info(UA_Client *client);
|
||||
void ua_browser_objects(UA_Client *client);
|
||||
void ua_browser_nodes(UA_Client *client);
|
||||
void ua_browser_id(UA_Client *client, UA_NodeId id);
|
||||
void ua_read_time(UA_Client *client);
|
||||
int16 ua_test(void);
|
||||
|
||||
void ua_add_nodes(UA_Client *client);
|
||||
|
||||
int ua_open(void *dev); // open and connect PLC device
|
||||
void ua_close(void* dev); // close and disconnect PLC device
|
||||
@@ -45,4 +60,12 @@ int ua_read(void* dev, void *buf, size_t len); // read data from PLC
|
||||
int ua_write(void* dev, const void *buf, size_t len); // write data from PLC
|
||||
int ua_ioctl(void* dev, int cmd, void *arg); // send control command to PLC
|
||||
|
||||
char *ua_get_nodeid_str(UA_NodeId *node_id);
|
||||
void ua_read_nodeid_value(UA_Client *client, UA_NodeId id, UA_Int32 *value);
|
||||
void ua_write_nodeid_value(UA_Client *client, UA_NodeId id, char* value);
|
||||
void ua_test_attr(UA_Client *client);
|
||||
UA_StatusCode ua_read_array_value(UA_Client *client, int array_size, UA_ReadValueId *array);
|
||||
void ua_test_browser_objects(UA_Client *client);
|
||||
int ua_test_interact_server(UA_Client *client);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -10,185 +10,365 @@
|
||||
* See the Mulan PSL v2 for more details.
|
||||
*/
|
||||
|
||||
#include "open62541.h"
|
||||
/**
|
||||
* @file ua_client.c
|
||||
* @brief Client for OpcUa function
|
||||
* @version 1.0
|
||||
* @author AIIT XUOS Lab
|
||||
* @date 2021.11.11
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include "open62541.h"
|
||||
#include "ua_api.h"
|
||||
|
||||
#define UA_RESPONSE_TIMEOUT 10000
|
||||
|
||||
#ifdef UA_ENABLE_SUBSCRIPTIONS
|
||||
static void handler_TheAnswerChanged(UA_Client *client, UA_UInt32 subId, void *subContext,
|
||||
UA_UInt32 monId, void *monContext, UA_DataValue *value)
|
||||
static void handler_TheAnswerChanged(UA_Client* client, UA_UInt32 subId, void* subContext,
|
||||
UA_UInt32 monId, void* monContext, UA_DataValue* value)
|
||||
{
|
||||
ua_print("The Answer has changed!\n");
|
||||
}
|
||||
#endif
|
||||
|
||||
static UA_StatusCode nodeIter(UA_NodeId childId, UA_Boolean isInverse, UA_NodeId referenceTypeId, void *handle)
|
||||
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;
|
||||
UA_NodeId* parent = (UA_NodeId*)handle;
|
||||
ua_pr_info("%d, %d --- %d ---> NodeId %d, %d\n",
|
||||
parent->namespaceIndex, parent->identifier.numeric,
|
||||
referenceTypeId.identifier.numeric, childId.namespaceIndex,
|
||||
childId.identifier.numeric);
|
||||
|
||||
parent->namespaceIndex, parent->identifier.numeric,
|
||||
referenceTypeId.identifier.numeric, childId.namespaceIndex,
|
||||
childId.identifier.numeric);
|
||||
return UA_STATUSCODE_GOOD;
|
||||
}
|
||||
|
||||
int ua_get_points(UA_Client *client)
|
||||
int ua_get_points(UA_Client* client)
|
||||
{
|
||||
/* Listing endpoints */
|
||||
UA_EndpointDescription* endpointArray = NULL;
|
||||
size_t endpointArraySize = 0;
|
||||
UA_StatusCode retval = UA_Client_getEndpoints(client, OPC_SERVER,
|
||||
UA_StatusCode ret = UA_Client_getEndpoints(client, OPC_SERVER,
|
||||
&endpointArraySize, &endpointArray);
|
||||
if(retval != UA_STATUSCODE_GOOD)
|
||||
|
||||
if(ret != UA_STATUSCODE_GOOD)
|
||||
{
|
||||
UA_Array_delete(endpointArray, endpointArraySize, &UA_TYPES[UA_TYPES_ENDPOINTDESCRIPTION]);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
ua_print("%i endpoints found\n", (int)endpointArraySize);
|
||||
for(size_t i=0;i<endpointArraySize;i++)
|
||||
|
||||
for(size_t i=0; i<endpointArraySize; i++)
|
||||
{
|
||||
ua_print("URL of endpoint %i is %.*s\n", (int)i,
|
||||
(int)endpointArray[i].endpointUrl.length,
|
||||
endpointArray[i].endpointUrl.data);
|
||||
(int)endpointArray[i].endpointUrl.length,
|
||||
endpointArray[i].endpointUrl.data);
|
||||
}
|
||||
|
||||
UA_Array_delete(endpointArray,endpointArraySize, &UA_TYPES[UA_TYPES_ENDPOINTDESCRIPTION]);
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
void ua_browser_objects(UA_Client *client)
|
||||
void ua_print_value(UA_Variant* val)
|
||||
{
|
||||
/* Browse some objects */
|
||||
ua_pr_info("Browsing nodes in objects folder:\n");
|
||||
if(val->type == &UA_TYPES[UA_TYPES_LOCALIZEDTEXT])
|
||||
{
|
||||
UA_LocalizedText* ptr = (UA_LocalizedText*)val->data;
|
||||
ua_pr_info("%.*s (Text)\n", ptr->text.length, ptr->text.data);
|
||||
}
|
||||
else if(val->type == &UA_TYPES[UA_TYPES_UINT32])
|
||||
{
|
||||
UA_UInt32* ptr = (UA_UInt32*)val->data;
|
||||
ua_pr_info("%d (UInt32)\n", *ptr);
|
||||
}
|
||||
else if(val->type == &UA_TYPES[UA_TYPES_BOOLEAN])
|
||||
{
|
||||
UA_Boolean* ptr = (UA_Boolean*)val->data;
|
||||
ua_pr_info("%i (BOOL)\n", *ptr);
|
||||
}
|
||||
else if(val->type == &UA_TYPES[UA_TYPES_INT32])
|
||||
{
|
||||
UA_Int32* ptr = (UA_Int32*)val->data;
|
||||
ua_pr_info("%d (Int32)\n", *ptr);
|
||||
}
|
||||
else if(val->type == &UA_TYPES[UA_TYPES_INT16])
|
||||
{
|
||||
UA_Int16* ptr = (UA_Int16*)val->data;
|
||||
ua_pr_info("%d (Int16)\n", *ptr);
|
||||
}
|
||||
else if(val->type == &UA_TYPES[UA_TYPES_STRING])
|
||||
{
|
||||
UA_String* ptr = (UA_String*)val->data;
|
||||
ua_pr_info("%*.s (String)\n", ptr->length, ptr->data);
|
||||
}
|
||||
else if(val->type == &UA_TYPES[UA_TYPES_DATETIME])
|
||||
{
|
||||
UA_DateTime* ptr = (UA_DateTime*)val->data;
|
||||
UA_DateTimeStruct dts = UA_DateTime_toStruct(*ptr);
|
||||
ua_pr_info("%d-%d-%d %d:%d:%d.%03d (Time)\n",
|
||||
dts.day, dts.month, dts.year, dts.hour, dts.min, dts.sec, dts.milliSec);
|
||||
}
|
||||
}
|
||||
|
||||
UA_BrowseRequest bReq;
|
||||
UA_BrowseRequest_init(&bReq);
|
||||
char *ua_get_nodeid_str(UA_NodeId *node_id)
|
||||
{
|
||||
static char nodeid_str[UA_NODE_LEN] = {0};
|
||||
|
||||
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 */
|
||||
switch(node_id->identifierType)
|
||||
{
|
||||
case UA_NODEIDTYPE_NUMERIC:
|
||||
snprintf(nodeid_str, UA_NODE_LEN, "n%d,%d", node_id->namespaceIndex, node_id->identifier.numeric);
|
||||
break;
|
||||
case UA_NODEIDTYPE_STRING:
|
||||
snprintf(nodeid_str, UA_NODE_LEN, "n%d,%.*s", node_id->namespaceIndex, node_id->identifier.string.length,
|
||||
node_id->identifier.string.data);
|
||||
break;
|
||||
case UA_NODEIDTYPE_BYTESTRING:
|
||||
snprintf(nodeid_str, UA_NODE_LEN, "n%d,%s", node_id->namespaceIndex, node_id->identifier.byteString.data);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return nodeid_str;
|
||||
}
|
||||
|
||||
UA_BrowseResponse bResp = UA_Client_Service_browse(client, bReq);
|
||||
void ua_print_nodeid(UA_NodeId *node_id)
|
||||
{
|
||||
switch(node_id->identifierType)
|
||||
{
|
||||
case UA_NODEIDTYPE_NUMERIC:
|
||||
ua_pr_info(" NodeID n%d,%d ", node_id->namespaceIndex, node_id->identifier.numeric);
|
||||
break;
|
||||
case UA_NODEIDTYPE_STRING:
|
||||
ua_pr_info(" NodeID n%d,%.*s ", node_id->namespaceIndex, node_id->identifier.string.length,
|
||||
node_id->identifier.string.data);
|
||||
break;
|
||||
case UA_NODEIDTYPE_BYTESTRING:
|
||||
ua_pr_info(" NodeID n%d,%s ", node_id->namespaceIndex, node_id->identifier.byteString.data);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void ua_print_object(UA_BrowseResponse* res)
|
||||
{
|
||||
ua_pr_info("%-9s %-16s %-16s %-16s\n", "NAMESPACE", "NODEID", "BROWSE NAME", "DISPLAY NAME");
|
||||
|
||||
for(size_t i = 0; i < bResp.resultsSize; ++i)
|
||||
for(size_t i = 0; i < res->resultsSize; ++i)
|
||||
{
|
||||
for(size_t j = 0; j < bResp.results[i].referencesSize; ++j)
|
||||
for(size_t j = 0; j < res->results[i].referencesSize; ++j)
|
||||
{
|
||||
UA_ReferenceDescription *ref = &(bResp.results[i].references[j]);
|
||||
UA_ReferenceDescription* ref = &(res->results[i].references[j]);
|
||||
|
||||
if(ref->nodeId.nodeId.identifierType == UA_NODEIDTYPE_NUMERIC)
|
||||
{
|
||||
ua_pr_info("%-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);
|
||||
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)
|
||||
{
|
||||
ua_pr_info("%-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);
|
||||
(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_pr_info("\n");
|
||||
UA_BrowseRequest_clear(&bReq);
|
||||
UA_BrowseResponse_clear(&bResp);
|
||||
}
|
||||
|
||||
void ua_browser_nodes(UA_Client *client)
|
||||
UA_StatusCode ua_read_array_value(UA_Client* client, int array_size, UA_ReadValueId* array)
|
||||
{
|
||||
/* Same thing, this time using the node iterator... */
|
||||
UA_NodeId *parent = UA_NodeId_new();
|
||||
UA_ReadRequest request;
|
||||
UA_ReadRequest_init(&request);
|
||||
request.nodesToRead = array;
|
||||
request.nodesToReadSize = array_size;
|
||||
UA_ReadResponse response = UA_Client_Service_read(client, request);
|
||||
|
||||
if((response.responseHeader.serviceResult != UA_STATUSCODE_GOOD)
|
||||
|| (response.resultsSize != array_size))
|
||||
{
|
||||
UA_ReadResponse_clear(&response);
|
||||
ua_pr_info("ua: [%s] read failed 0x%x\n", __func__,
|
||||
response.responseHeader.serviceResult);
|
||||
return UA_STATUSCODE_BADUNEXPECTEDERROR;
|
||||
}
|
||||
|
||||
UA_StatusCode* arr_ret = malloc(array_size * sizeof(UA_StatusCode));
|
||||
|
||||
for(int i = 0; i < array_size; ++i)
|
||||
{
|
||||
if((response.results[i].status == UA_STATUSCODE_GOOD)
|
||||
&& (response.results[i].hasValue))
|
||||
{
|
||||
ua_pr_info("node %s: ", ua_get_nodeid_str(&array[i].nodeId));
|
||||
ua_print_value(&response.results[i].value);
|
||||
}
|
||||
}
|
||||
ua_pr_info("\n");
|
||||
|
||||
free(arr_ret);
|
||||
UA_ReadResponse_clear(&response);
|
||||
return UA_STATUSCODE_GOOD;
|
||||
}
|
||||
|
||||
void ua_browser_id(UA_Client* client, UA_NodeId id)
|
||||
{
|
||||
/* Browse some objects */
|
||||
ua_pr_info("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 = id; /* browse objects folder */
|
||||
bReq.nodesToBrowse[0].resultMask = UA_BROWSERESULTMASK_ALL; /* return everything */
|
||||
UA_BrowseResponse res = UA_Client_Service_browse(client, bReq);
|
||||
ua_print_object(&res);
|
||||
UA_BrowseResponse_clear(&res);
|
||||
// UA_BrowseRequest_clear(&bReq);
|
||||
}
|
||||
|
||||
void ua_browser_nodes(UA_Client* client)
|
||||
{
|
||||
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_Client_forEachChildNodeCall(client, UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER), nodeIter, (void*) parent);
|
||||
UA_NodeId_delete(parent);
|
||||
}
|
||||
|
||||
UA_UInt32 ua_start_sub(UA_Client *client)
|
||||
UA_UInt32 ua_start_sub(UA_Client* client, UA_NodeId node_id)
|
||||
{
|
||||
/* 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)
|
||||
{
|
||||
ua_print("Create subscription succeeded, id %u\n", subId);
|
||||
}
|
||||
else
|
||||
{
|
||||
ua_print("Create subscription failed, id %u\n", response.responseHeader.serviceResult);
|
||||
return response.responseHeader.serviceResult;
|
||||
}
|
||||
|
||||
UA_MonitoredItemCreateRequest monRequest =
|
||||
UA_MonitoredItemCreateRequest_default(UA_NODEID_STRING(1, "the.answer"));
|
||||
|
||||
UA_MonitoredItemCreateRequest_default(node_id);
|
||||
UA_MonitoredItemCreateResult monResponse =
|
||||
UA_Client_MonitoredItems_createDataChange(client, response.subscriptionId,
|
||||
UA_TIMESTAMPSTORETURN_BOTH,
|
||||
monRequest, NULL, handler_TheAnswerChanged, NULL);
|
||||
if(monResponse.statusCode == UA_STATUSCODE_GOOD)
|
||||
ua_print("Monitoring 'the.answer', id %u\n", monResponse.monitoredItemId);
|
||||
UA_Client_MonitoredItems_createDataChange(client, response.subscriptionId,
|
||||
UA_TIMESTAMPSTORETURN_BOTH,
|
||||
monRequest, NULL, handler_TheAnswerChanged, NULL);
|
||||
|
||||
if(monResponse.statusCode == UA_STATUSCODE_GOOD)
|
||||
{
|
||||
ua_print("Monitoring 'the.answer', id %u\n", monResponse.monitoredItemId);
|
||||
}
|
||||
else
|
||||
{
|
||||
ua_print("%s return 0x%x\n", __func__, monResponse.statusCode);
|
||||
}
|
||||
|
||||
/* The first publish request should return the initial value of the variable */
|
||||
UA_Client_run_iterate(client, 1000);
|
||||
UA_Client_run_iterate(client, UA_RESPONSE_TIMEOUT);
|
||||
return subId;
|
||||
}
|
||||
|
||||
void ua_read_attr(UA_Client *client)
|
||||
void ua_write_nodeid_value(UA_Client* client, UA_NodeId id, char* value)
|
||||
{
|
||||
/* Read attribute */
|
||||
UA_Int32 value = 0;
|
||||
ua_pr_info("\nReading the value of node (1, \"the.answer\"):\n");
|
||||
UA_Variant *val = UA_Variant_new();
|
||||
UA_StatusCode 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;
|
||||
ua_pr_info("the value is: %i\n", value);
|
||||
}
|
||||
UA_Variant_delete(val);
|
||||
|
||||
/* Write node attribute */
|
||||
value++;
|
||||
ua_pr_info("\nWriting a value of node (1, \"the.answer\"):\n");
|
||||
UA_Boolean bool_val;
|
||||
uint32_t integer_val;
|
||||
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");
|
||||
|
||||
if(strncmp(value, "1b", 2) == 0)
|
||||
{
|
||||
wReq.nodesToWrite[0].value.value.type = &UA_TYPES[UA_TYPES_BOOLEAN];
|
||||
bool_val = 1;
|
||||
wReq.nodesToWrite[0].value.value.data = &bool_val;
|
||||
}
|
||||
else if(strncmp(value, "0b", 2) == 0)
|
||||
{
|
||||
wReq.nodesToWrite[0].value.value.type = &UA_TYPES[UA_TYPES_BOOLEAN];
|
||||
bool_val = 0;
|
||||
wReq.nodesToWrite[0].value.value.data = &bool_val;
|
||||
}
|
||||
else
|
||||
{
|
||||
wReq.nodesToWrite[0].value.value.type = &UA_TYPES[UA_TYPES_INT16];
|
||||
sscanf(value, "%d", &integer_val);
|
||||
wReq.nodesToWrite[0].value.value.data = &integer_val;
|
||||
}
|
||||
|
||||
wReq.nodesToWrite[0].nodeId = id;
|
||||
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)
|
||||
ua_pr_info("the new value is: %i\n", value);
|
||||
{
|
||||
ua_pr_info("write new value is: %s\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);
|
||||
|
||||
// /* 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, UA_NODE_STR), myVariant);
|
||||
// UA_Variant_delete(myVariant);
|
||||
}
|
||||
|
||||
void ua_call_remote(UA_Client *client)
|
||||
/* Read attribute */
|
||||
void ua_read_nodeid_value(UA_Client* client, UA_NodeId id, UA_Int32 *value)
|
||||
{
|
||||
UA_Variant* val = UA_Variant_new();
|
||||
UA_StatusCode ret = UA_Client_readValueAttribute(client, id, val);
|
||||
|
||||
if(ret == UA_STATUSCODE_GOOD)
|
||||
{
|
||||
ua_print_value(val);
|
||||
if(UA_Variant_isScalar(val))
|
||||
{
|
||||
if(val->type == &UA_TYPES[UA_TYPES_BOOLEAN])
|
||||
{
|
||||
*value = *(UA_Boolean *)val->data;
|
||||
}
|
||||
else if(val->type == &UA_TYPES[UA_TYPES_INT32])
|
||||
{
|
||||
*value = *(UA_Int32 *)val->data;
|
||||
}
|
||||
else if(val->type == &UA_TYPES[UA_TYPES_INT16])
|
||||
{
|
||||
*value = *(UA_Int16 *)val->data;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
UA_Variant_delete(val);
|
||||
}
|
||||
|
||||
void ua_call_remote(UA_Client* client)
|
||||
{
|
||||
/* Call a remote method */
|
||||
UA_Variant input;
|
||||
@@ -196,24 +376,26 @@ void ua_call_remote(UA_Client *client)
|
||||
UA_Variant_init(&input);
|
||||
UA_Variant_setScalarCopy(&input, &argString, &UA_TYPES[UA_TYPES_STRING]);
|
||||
size_t outputSize;
|
||||
UA_Variant *output;
|
||||
UA_StatusCode 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)
|
||||
UA_Variant* output;
|
||||
UA_StatusCode ret = UA_Client_call(client, UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER),
|
||||
UA_NODEID_NUMERIC(1, 62541), 1, &input, &outputSize, &output);
|
||||
|
||||
if(ret == UA_STATUSCODE_GOOD)
|
||||
{
|
||||
ua_print("Method call was successful, and %lu returned values available.\n",
|
||||
(unsigned long)outputSize);
|
||||
(unsigned long)outputSize);
|
||||
UA_Array_delete(output, outputSize, &UA_TYPES[UA_TYPES_VARIANT]);
|
||||
}
|
||||
else
|
||||
{
|
||||
ua_print("Method call was unsuccessful, and %x returned values available.\n", retval);
|
||||
ua_print("Method call was unsuccessful, and %x returned values available.\n", ret);
|
||||
}
|
||||
|
||||
UA_Variant_clear(&input);
|
||||
}
|
||||
|
||||
|
||||
void ua_add_nodes(UA_Client *client)
|
||||
void ua_add_nodes(UA_Client* client)
|
||||
{
|
||||
/* Add new nodes*/
|
||||
/* New ReferenceType */
|
||||
@@ -222,43 +404,52 @@ void ua_add_nodes(UA_Client *client)
|
||||
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");
|
||||
UA_StatusCode 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 )
|
||||
UA_StatusCode ret = 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(ret == UA_STATUSCODE_GOOD)
|
||||
{
|
||||
ua_print("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,
|
||||
ret = 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)
|
||||
|
||||
if(ret == UA_STATUSCODE_GOOD)
|
||||
{
|
||||
ua_print("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,
|
||||
ret = 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 )
|
||||
|
||||
if(ret == UA_STATUSCODE_GOOD)
|
||||
{
|
||||
ua_print("Created 'NewObject' with numeric NodeID %u\n", obj_id.identifier.numeric);
|
||||
}
|
||||
|
||||
/* New Integer Variable */
|
||||
UA_NodeId var_id;
|
||||
@@ -270,68 +461,36 @@ void ua_add_nodes(UA_Client *client)
|
||||
/* 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,
|
||||
ret = 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 )
|
||||
|
||||
if(ret == UA_STATUSCODE_GOOD)
|
||||
{
|
||||
ua_print("Created 'NewVariable' with numeric NodeID %u\n", var_id.identifier.numeric);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
int ua_get_server_info(UA_Client *client)
|
||||
void ua_read_time(UA_Client* client)
|
||||
{
|
||||
ua_browser_objects(client);
|
||||
|
||||
/* Same thing, this time using the node iterator... */
|
||||
ua_browser_nodes(client);
|
||||
|
||||
#ifdef UA_ENABLE_SUBSCRIPTIONS
|
||||
UA_Int32 subId = ua_start_sub(client);
|
||||
#endif
|
||||
|
||||
ua_read_attr(client);
|
||||
|
||||
#ifdef UA_ENABLE_SUBSCRIPTIONS
|
||||
/* Take another look at the.answer */
|
||||
UA_Client_run_iterate(client, 10000);
|
||||
/* Delete the subscription */
|
||||
if(UA_Client_Subscriptions_deleteSingle(client, subId) == UA_STATUSCODE_GOOD)
|
||||
ua_print("Subscription removed\n");
|
||||
#endif
|
||||
|
||||
#ifdef UA_ENABLE_METHODCALLS
|
||||
ua_call_remote(client);
|
||||
#endif
|
||||
|
||||
#ifdef UA_ENABLE_NODEMANAGEMENT
|
||||
ua_add_nodes(client);
|
||||
#endif
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
void ua_read_time(UA_Client *client)
|
||||
{
|
||||
/* 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 value;
|
||||
UA_Variant_init(&value);
|
||||
|
||||
/* NodeId of the variable holding the current time */
|
||||
const UA_NodeId nodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_CURRENTTIME);
|
||||
UA_StatusCode retval = UA_Client_readValueAttribute(client, nodeId, &value);
|
||||
UA_StatusCode ret = UA_Client_readValueAttribute(client, nodeId, &value);
|
||||
|
||||
if(retval == UA_STATUSCODE_GOOD && UA_Variant_hasScalarType(&value, &UA_TYPES[UA_TYPES_DATETIME]))
|
||||
if(ret == UA_STATUSCODE_GOOD && UA_Variant_hasScalarType(&value, &UA_TYPES[UA_TYPES_DATETIME]))
|
||||
{
|
||||
UA_DateTime raw_date = *(UA_DateTime *) value.data;
|
||||
UA_DateTime raw_date = *(UA_DateTime*) value.data;
|
||||
UA_DateTimeStruct dts = UA_DateTime_toStruct(raw_date);
|
||||
UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, "date is: %u-%u-%u %u:%u:%u.%03u\n",
|
||||
dts.day, dts.month, dts.year, dts.hour, dts.min, dts.sec, dts.milliSec);
|
||||
ua_pr_info("date is: %d-%d-%d %d:%d:%d.%03d\n",
|
||||
dts.day, dts.month, dts.year, dts.hour, dts.min, dts.sec, dts.milliSec);
|
||||
}
|
||||
|
||||
/* Clean up */
|
||||
UA_Variant_clear(&value);
|
||||
}
|
||||
|
||||
@@ -10,6 +10,75 @@
|
||||
* See the Mulan PSL v2 for more details.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file ua_test.c
|
||||
* @brief Test for OpcUa function
|
||||
* @version 1.0
|
||||
* @author AIIT XUOS Lab
|
||||
* @date 2021.11.11
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include "open62541.h"
|
||||
#include "ua_api.h"
|
||||
|
||||
//for target NODEID
|
||||
#define UA_TEST_BROWSER_NODEID UA_NODEID_STRING(3, "ServerInterfaces")
|
||||
#define UA_TEST_BROWSER_NODEID1 UA_NODEID_NUMERIC(4, 1)
|
||||
#define UA_TEST_WRITE_NODEID UA_NODEID_NUMERIC(4, 5)
|
||||
|
||||
|
||||
static UA_StatusCode ua_test_read_array(UA_Client *client)
|
||||
{
|
||||
const int item_size = 4;
|
||||
UA_ReadValueId test_item[item_size];
|
||||
|
||||
for (int i = 0; i < item_size; i++)
|
||||
{
|
||||
UA_ReadValueId_init(&test_item[i]);
|
||||
test_item[i].attributeId = UA_ATTRIBUTEID_VALUE;
|
||||
}
|
||||
|
||||
test_item[0].nodeId = UA_NODEID_NUMERIC(4, 2);
|
||||
test_item[1].nodeId = UA_NODEID_NUMERIC(4, 3);
|
||||
test_item[2].nodeId = UA_NODEID_NUMERIC(4, 4);
|
||||
test_item[3].nodeId = UA_NODEID_NUMERIC(4, 5);
|
||||
|
||||
return ua_read_array_value(client, item_size, test_item);
|
||||
}
|
||||
|
||||
void ua_test_browser_objects(UA_Client *client)
|
||||
{
|
||||
UA_NodeId test_id;
|
||||
ua_browser_id(client, UA_TEST_BROWSER_NODEID);
|
||||
ua_browser_id(client, UA_TEST_BROWSER_NODEID1);
|
||||
test_id = UA_TEST_BROWSER_NODEID1;
|
||||
ua_pr_info("Show values in %s:\n", ua_get_nodeid_str(&test_id));
|
||||
ua_test_read_array(client);
|
||||
return;
|
||||
}
|
||||
|
||||
void ua_test_write_attr(UA_Client *client)
|
||||
{
|
||||
UA_Int32 value;
|
||||
char val_str[UA_NODE_LEN];
|
||||
UA_NodeId id = UA_TEST_WRITE_NODEID;
|
||||
|
||||
ua_pr_info("--- Test write %s ---\n", ua_get_nodeid_str(&id));
|
||||
ua_read_nodeid_value(client, id, &value);
|
||||
ua_write_nodeid_value(client, id, itoa(value + 1, val_str, 10));
|
||||
ua_read_nodeid_value(client, id, &value);
|
||||
ua_pr_info("\n");
|
||||
}
|
||||
|
||||
int ua_test_interact_server(UA_Client *client)
|
||||
{
|
||||
ua_read_time(client);
|
||||
ua_test_browser_objects(client);
|
||||
ua_test_write_attr(client);
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
int16 ua_test(void)
|
||||
{
|
||||
UA_Client *client = UA_Client_new();
|
||||
@@ -20,7 +89,6 @@ int16 ua_test(void)
|
||||
}
|
||||
|
||||
ua_read_time(client);
|
||||
ua_run_test(client);
|
||||
|
||||
/* Clean up */
|
||||
UA_Client_disconnect(client);
|
||||
|
||||
Reference in New Issue
Block a user