开发环境:
Linux ubuntu16 4.15.0-117
gcc (Ubuntu 5.4.0-6ubuntu1~16.04.12) 5.4.0 20160609(编译源代码)
ccmake version 3.5.1(生成open62541.c/.h)
vscode version 1.49.1(开发工具)
UaExpert version 1.4.4.257(测试工具)
参照open62541文档,生成 open62541.c/.h 文件。
并没有实质性的内容,只是熟悉一下环境
创建基础服务
代码
#include <open62541.h>
#include <signal.h>
#include <stdlib.h>
static volatile UA_Boolean running = true;
static void stopHandler(int sig) {
UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, "received ctrl-c");
running = false;
}
int main(void) {
signal(SIGINT, stopHandler);
signal(SIGTERM, stopHandler);
UA_Server *server = UA_Server_new();
UA_ServerConfig_setDefault(UA_Server_getConfig(server));
UA_StatusCode retval = UA_Server_run(server, &running);
UA_Server_delete(server);
return retval == UA_STATUSCODE_GOOD ? EXIT_SUCCESS : EXIT_FAILURE;
}
编译、运行
参数 -I…/opcua_c 指定 open62541.h 文件所在目录,我这编译的时候,就算是复制到当前目录也提示找不到这个文件,所以添加了 -I 参数
gcc DemoServer.c open62541.c -o ds01 -I../opcua_c
运行效果如下图
使用UaExpert连接(地址:opc.tcp://<服务IP>:4840/)成功
添加自定义节点
代码
#include <open62541.h>
#include <signal.h>
#include <stdlib.h>
static void addVariable(UA_Server *server);
static void addMatrixVariable(UA_Server *server);
static volatile UA_Boolean running = true;
static void stopHandler(int sig) {
UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, "received ctrl-c");
running = false;
}
int main(void) {
signal(SIGINT, stopHandler);
signal(SIGTERM, stopHandler);
UA_Server *server = UA_Server_new();
UA_ServerConfig_setDefault(UA_Server_getConfig(server));
// 添加节点
addVariable(server);
addMatrixVariable(server);
UA_StatusCode retval = UA_Server_run(server, &running);
UA_Server_delete(server);
return retval == UA_STATUSCODE_GOOD ? EXIT_SUCCESS : EXIT_FAILURE;
}
static void addVariable(UA_Server *server) {
/* 定义整数变量节点的属性 */
UA_VariableAttributes attr = UA_VariableAttributes_default;
UA_Int32 myInteger = 42;
UA_Variant_setScalar(&attr.value, &myInteger, &UA_TYPES[UA_TYPES_INT32]);
attr.description = UA_LOCALIZEDTEXT("zh-CN","整数类型节点");
attr.displayName = UA_LOCALIZEDTEXT("zh-CN","整数类型节点");
attr.dataType = UA_TYPES[UA_TYPES_INT32].typeId;
attr.accessLevel = UA_ACCESSLEVELMASK_READ | UA_ACCESSLEVELMASK_WRITE;
/* 将变量节点添加到信息模型中 */
UA_NodeId myIntegerNodeId = UA_NODEID_STRING(1, "整数类型节点");
UA_QualifiedName myIntegerName = UA_QUALIFIEDNAME(1, "整数类型节点");
UA_NodeId parentNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER);
UA_NodeId parentReferenceNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES);
UA_Server_addVariableNode(
server,
myIntegerNodeId,
parentNodeId,
parentReferenceNodeId,
myIntegerName,
UA_NODEID_NUMERIC(0, UA_NS0ID_BASEDATAVARIABLETYPE),
attr,
NULL,
NULL);
}
static void addMatrixVariable(UA_Server *server) {
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("zh-CN", "双精度数组");
attr.accessLevel = UA_ACCESSLEVELMASK_READ | UA_ACCESSLEVELMASK_WRITE;
/* 设置变量值约束 */
attr.dataType = UA_TYPES[UA_TYPES_DOUBLE].typeId;
attr.valueRank = UA_VALUERANK_TWO_DIMENSIONS;
UA_UInt32 arrayDims[2] = {2,2};
attr.arrayDimensions = arrayDims;
attr.arrayDimensionsSize = 2;
/* 设置值。值的数组维度必须相同。 */
UA_Double zero[4] = {0.0, 0.0, 0.0, 0.0};
UA_Variant_setArray(&attr.value, zero, 4, &UA_TYPES[UA_TYPES_DOUBLE]);
attr.value.arrayDimensions = arrayDims;
attr.value.arrayDimensionsSize = 2;
UA_NodeId myArrayNodeId = UA_NODEID_STRING(1, "双精度数组");
UA_QualifiedName myArrayName = UA_QUALIFIEDNAME(1, "双精度数组");
UA_NodeId parentNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER);
UA_NodeId parentReferenceNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES);
UA_Server_addVariableNode(
server,
myArrayNodeId,
parentNodeId,
parentReferenceNodeId,
myArrayName,
UA_NODEID_NUMERIC(0, UA_NS0ID_BASEDATAVARIABLETYPE),
attr,
NULL,
NULL);
}
UaExpert查看(添加节点时使用的是中文,不知道有没有问题。尽量不要使用中文。)
修改节点的值
代码
#include <open62541.h>
#include <signal.h>
#include <stdlib.h>
#include <pthread.h>
void *consoleThread(UA_Server *server);
static UA_NodeId addVariable(UA_Server *server,const UA_Int32 nsIndex, char *identifier,const UA_Int32 data);
static void writeVariable(UA_Server *server,const UA_NodeId nodeId,const UA_Int32 value);
void *consoleThread(UA_Server *server);
static volatile UA_Boolean running = true;
static void stopHandler(int sig) {
UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, "received ctrl-c");
running = false;
}
int main(void) {
signal(SIGINT, stopHandler);
signal(SIGTERM, stopHandler);
UA_Server *server = UA_Server_new();
UA_ServerConfig_setDefault(UA_Server_getConfig(server));
int ret = 0;
pthread_t id1;//声明线程ID
ret = pthread_create(&id1 , NULL , (void *)consoleThread, (void *)server); //创建并执行线程id1
if(ret == -1){
printf("Create console thread error!\n");
return 1;
}
UA_StatusCode retval = UA_Server_run(server, &running);
UA_Server_delete(server);
return retval == UA_STATUSCODE_GOOD ? EXIT_SUCCESS : EXIT_FAILURE;
}
void showMenu(void){
printf("\n");
printf("*********(0)菜单**********************************\n");
printf("*********(1)添加整数节点,默认值:0 **************\n");
printf("*********(2)修改整数节点的值 *********************\n");
printf("*********(3)退出 *********************************\n");
printf("\n");
}
void *consoleThread(UA_Server *server)
{
showMenu();
while(running){
int nsIndex,data;
char identifier[128] = {0};
int input =0;
printf("输入你的选择:");
scanf("%d",&input);
switch(input){
case 0:
showMenu();
break;
case 1:
printf("输入新增节点信息(如:1 No.1_Value_Opening 31):");
scanf("%d%s%d",&nsIndex,identifier,&data);
addVariable(server,nsIndex,identifier,data);
break;
case 2:
printf("输入修改节点信息(如:1 No.1_Value_Opening 31):");
scanf("%d%s%d",&nsIndex,identifier,&data);
UA_NodeId nodeId = UA_NODEID_STRING(nsIndex,identifier);
writeVariable(server,nodeId,data);
break;
case 3:
running = false ;
break;
}
}
}
static UA_NodeId addVariable(UA_Server *server,const UA_Int32 nsIndex, char *identifier,UA_Int32 data) {
/* 定义整数变量节点的属性 */
UA_VariableAttributes attr = UA_VariableAttributes_default;
UA_Variant_setScalar(&attr.value, &data, &UA_TYPES[UA_TYPES_INT32]);
attr.description = UA_LOCALIZEDTEXT("zh-CN",identifier);
attr.displayName = UA_LOCALIZEDTEXT("zh-CN",identifier);
attr.dataType = UA_TYPES[UA_TYPES_INT32].typeId;
attr.accessLevel = UA_ACCESSLEVELMASK_READ | UA_ACCESSLEVELMASK_WRITE;
/* 将变量节点添加到信息模型中 */
UA_NodeId myIntegerNodeId = UA_NODEID_STRING(nsIndex, identifier);
UA_QualifiedName myIntegerName = UA_QUALIFIEDNAME(nsIndex, identifier);
UA_NodeId parentNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER);
UA_NodeId parentReferenceNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES);
UA_StatusCode code = UA_Server_addVariableNode(
server,
myIntegerNodeId,
parentNodeId,
parentReferenceNodeId,
myIntegerName,
UA_NODEID_NUMERIC(0, UA_NS0ID_BASEDATAVARIABLETYPE),
attr,
NULL,
NULL);
printf("添加节点完成!%d\n",code);
return myIntegerNodeId;
}
static void writeVariable(UA_Server *server,const UA_NodeId nodeId,UA_Int32 value) {
UA_Variant myVar;
UA_Variant_init(&myVar);
UA_Variant_setScalar(&myVar, &value, &UA_TYPES[UA_TYPES_INT32]);
UA_StatusCode code = UA_Server_writeValue(server, nodeId, myVar);
printf("已修改节点的值,code = %d ,value = %d\n",code,value);
}
编译选项 -lpthread :因为使用线程,引用了 pthread.h,指定库文件位置。
下面截图中的修改节点值的提示信息是错误的,代码已更改,截图未更改。
gcc DemoServer.c open62541.c -o ds01 -I../opcua_c -lpthread
Ua_Expert 显示内容
暂时写到这吧