Files
softbus_OPC/third_party/open62541/tools/ua-tool/ua.c
2026-06-09 17:27:24 +08:00

290 lines
8.1 KiB
C

/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* Copyright 2021 (c) Fraunhofer IOSB (Author: Julius Pfrommer)
*/
/* Enable POSIX features */
#if !defined(_XOPEN_SOURCE)
# define _XOPEN_SOURCE 600
#endif
#ifndef _DEFAULT_SOURCE
# define _DEFAULT_SOURCE
#endif
/* On older systems we need to define _BSD_SOURCE.
* _DEFAULT_SOURCE is an alias for that. */
#ifndef _BSD_SOURCE
# define _BSD_SOURCE
#endif
#include <stdio.h>
#include <ctype.h>
#include <open62541/client.h>
#include <open62541/client_config_default.h>
static UA_Client *client = NULL;
static UA_NodeId nodeidval = {0};
static char *url = NULL;
static char *service = NULL;
static char *nodeid = NULL;
static char *value = NULL;
#ifdef UA_ENABLE_JSON_ENCODING
static UA_Boolean json = false;
#endif
static void
usage(void) {
printf("Usage: ua <server-url> <service> [--json] [--help]\n"
" <server-url>: opc.tcp://domain[:port]\n"
" <service> -> getendpoints: Log the endpoint descriptions of the server\n"
" <service> -> read <nodeid>: Read an attribute of the node\n"
" --attr <attribute-id | attribute-name>: Attribute to read from the node. "
"[default: value]\n"
//" <service> -> browse <nodeid>: Browse the Node\n"
//" <service> -> call <method-id> <object-id> <arguments>: Call the method \n"
//" <service> -> write <nodeid> <value>: Write an attribute of the node\n"
#ifdef UA_ENABLE_JSON_ENCODING
" --json: Format output as JSON\n"
#endif
" --help: Print this message\n");
}
static void
printType(void *p, const UA_DataType *type) {
UA_ByteString out = UA_BYTESTRING_NULL;
#ifdef UA_ENABLE_JSON_ENCODING
if(!json) {
UA_print(p, type, &out);
} else {
UA_StatusCode res = UA_encodeJson(p, type, &out, NULL);
(void)res;
}
#else
UA_print(p, type, &out);
#endif
printf("%.*s\n", (int)out.length, out.data);
UA_ByteString_clear(&out);
}
static void
abortWithStatus(UA_StatusCode res) {
printf("Aborting with status code %s\n", UA_StatusCode_name(res));
}
static int
getEndpoints(int argc, char **argv) {
client = UA_Client_new();
if(!client)
return -1;
UA_ClientConfig_setDefault(UA_Client_getConfig(client));
/* Get endpoints */
size_t endpointDescriptionsSize = 0;
UA_EndpointDescription* endpointDescriptions = NULL;
UA_StatusCode res = UA_Client_getEndpoints(client, url,
&endpointDescriptionsSize,
&endpointDescriptions);
UA_Client_delete(client);
if(res != UA_STATUSCODE_GOOD) {
abortWithStatus(res);
return -1;
}
/* Print the results */
UA_Variant var;
UA_Variant_setArray(&var, endpointDescriptions, endpointDescriptionsSize,
&UA_TYPES[UA_TYPES_ENDPOINTDESCRIPTION]);
printType(&var, &UA_TYPES[UA_TYPES_VARIANT]);
UA_Variant_clear(&var); /* deletes the original array */
return 0;
}
static int
parseNodeId(void) {
UA_StatusCode res = UA_NodeId_parse(&nodeidval, UA_STRING(nodeid));
if(res != UA_STATUSCODE_GOOD) {
printf("Could not parse the NodeId\n");
return -1;
}
return 0;
}
static int
connectClient(void) {
client = UA_Client_new();
if(!client)
return -1;
UA_ClientConfig_setDefault(UA_Client_getConfig(client));
UA_StatusCode res = UA_Client_connect(client, url);
if(res != UA_STATUSCODE_GOOD) {
abortWithStatus(res);
return -1;
}
return 0;
}
static const char *attributeIds[27] = {
"nodeid", "nodeclass", "browsename", "displayname", "description",
"writemask", "userwritemask", "isabstract", "symmetric", "inversename",
"containsnoloops", "eventnotifier", "value", "datatype", "valuerank",
"arraydimensions", "accesslevel", "useraccesslevel",
"minimumsamplinginterval", "historizing", "executable", "userexecutable",
"datatypedefinition", "rolepermissions", "userrolepermissions",
"accessrestrictions", "accesslevelex"
};
static int
readAttr(int argc, char **argv) {
/* Get the attr attribute (default: value) */
UA_UInt32 attr = UA_ATTRIBUTEID_VALUE;
for(int argpos = 1; argpos < argc; argpos++) {
if(argv[argpos] == NULL)
continue;
if(strcmp(argv[argpos], "--attr") == 0) {
argpos++;
if(argpos == argc) {
usage();
return -1;
}
/* Try to parse integer attr argument */
attr = (UA_UInt32)atoi(argv[argpos]);
if(attr != 0)
continue;
/* Convert to lower case and try to find in table */
for(char *w = argv[argpos]; *w; w++)
*w = (char)tolower(*w);
for(UA_UInt32 i = 0; i < 26; i++) {
if(strcmp(argv[argpos], attributeIds[i]) == 0) {
attr = i+1;
break;
}
}
if(attr != 0)
continue;
usage();
return -1;
}
/* Unknown option */
usage();
return -1;
}
int ret = parseNodeId();
if(ret != 0)
return ret;
ret = connectClient();
if(ret != 0) {
UA_NodeId_clear(&nodeidval);
return ret;
}
/* Read */
UA_ReadValueId rvid;
UA_ReadValueId_init(&rvid);
rvid.nodeId = nodeidval;
rvid.attributeId = attr;
UA_ReadRequest req;
UA_ReadRequest_init(&req);
req.timestampsToReturn = UA_TIMESTAMPSTORETURN_BOTH;
req.nodesToReadSize = 1;
req.nodesToRead = &rvid;
UA_ReadResponse resp = UA_Client_Service_read(client, req);
UA_Client_delete(client);
/* Print the result */
if(resp.responseHeader.serviceResult == UA_STATUSCODE_GOOD &&
resp.resultsSize != 1)
resp.responseHeader.serviceResult = UA_STATUSCODE_BADUNEXPECTEDERROR;
if(resp.responseHeader.serviceResult == UA_STATUSCODE_GOOD)
printType(&resp.results[0], &UA_TYPES[UA_TYPES_DATAVALUE]);
else
abortWithStatus(resp.responseHeader.serviceResult);
UA_ReadResponse_clear(&resp);
UA_NodeId_clear(&nodeidval);
return 0;
}
int
main(int argc, char **argv) {
/* Read the command line options. Set used options to NULL.
* Service-specific options are parsed later. */
if(argc < 3) {
usage();
return 0;
}
/* Get the url. Must not be a -- option string */
if(strstr(argv[1], "--") == argv[1]) {
usage();
return -1;
}
url = argv[1];
argv[1] = NULL;
/* Get the service */
service = argv[2];
argv[2] = NULL;
/* If not a -- option string, then this is the NodeId */
int argpos = 3;
if(argc > argpos && strstr(argv[argpos], "--") != argv[argpos]) {
nodeid = argv[argpos];
argv[argpos] = NULL;
argpos++;
/* If not a -- option string, then this is the value */
if(argc > argpos && strstr(argv[argpos], "--") != argv[argpos]) {
value = argv[argpos];
argv[argpos] = NULL;
argpos++;
}
}
/* Process the options */
for(; argpos < argc; argpos++) {
if(strcmp(argv[argpos], "--help") == 0) {
usage();
return 0;
}
#ifdef UA_ENABLE_JSON_ENCODING
if(strcmp(argv[argpos], "--json") == 0) {
json = true;
argv[argpos] = NULL;
continue;
}
#endif
}
/* Execute the service */
if(strcmp(service, "getendpoints") == 0) {
if(!nodeid && !value)
return getEndpoints(argc, argv);
} else if(strcmp(service, "read") == 0) {
if(nodeid && !value)
return readAttr(argc, argv);
}
//else if(strcmp(service, "browse") == 0) {
// if(nodeid && !value)
// return browse(argc, argv);
//}
//else if(strcmp(argv[1], "write") == 0) {
// if(nodeid && value)
// return writeAttr(argc-argpos, &argv[argpos]);
//}
/* Unknown service */
usage();
return -1;
}