使用OPCUA的目标是:将linux端的共享内存的一些信息实时反馈集成到window端去,并从window给到linux的共享内存赋值。最后是成功的,可以看我专栏。
这里使用的是一个免费的开源项目https://github.com/open62541/open62541。
仔细查看,上面有足够详细的文档与例子,感觉已经是一个成熟的协议,开始学习吧。
首先在https://open62541.org/下载一份linux32的包,我这里使用的是链接:https://pan.baidu.com/s/16nUPH7drmoNDKSCz51YQPg
提取码:y3b6
Git-Revision: v0.3-rc4,当时是最新的。
,这里的包是把github的源码处理成.a加接口文件open62541.c与open62541.h。在bin文件夹中有已经编好了的.a静态库,如下(不详细截图了。):
Server
最简单的案例:在linux中搭建服务器与客户端,传输一个int值。服务器myServer.c文件内容如下:
- 创建结束ctrl-c的处理函数
- 定义一个int变量的节点,并添加到信息模型
- 运行并等待ctrl-c
#include <signal.h>
#include <stdio.h>
#include "open62541.h"
UA_Boolean runing = true;
static void stopHandler(int sig)
{
UA_LOG_INFO(UA_Log_Stdout,UA_LOGCATEGORY_USERLAND,"received ctrl c");
runing = false;
}
static void addVariable(UA_Server *server)
{
/*Define the attribute of the myInteger variable node*/
UA_VariableAttributes attr = UA_VariableAttributes_default;
UA_Int32 myInteger = 43;
UA_Variant_setScalar(&attr.value,&myInteger,&UA_TYPES[UA_TYPES_INT32]);
attr.description = UA_LOCALIZEDTEXT("en-US","the answer");
attr.displayName = UA_LOCALIZEDTEXT("en-US","the answer");
attr.dataType = UA_TYPES[UA_TYPES_INT32].typeId;
attr.accessLevel = UA_ACCESSLEVELMASK_READ | UA_ACCESSLEVELMASK_WRITE;
/*Add the variable node to the information model*/
UA_NodeId myIntegerNodeId = UA_NODEID_STRING(1,"the.answer");
UA_QualifiedName myIntegerName = UA_QUALIFIEDNAME(1,"the answer");
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);
}
int main(void)
{
signal(SIGINT,stopHandler);
signal(SIGTERM,stopHandler);
UA_ServerConfig *config = UA_ServerConfig_new_default();
UA_Server *server = UA_Server_new(config);
addVariable(server);
UA_StatusCode retval = UA_Server_run(server,&runing);
UA_Server_delete(server);
UA_ServerConfig_delete(config);
return (int)retval;
}
Client
然后就是客户端的读取了。
- 连接到默认的端口
- 根据UA_NodeId将server中的值读取
- 打印输出,结束
#include <stdio.h>
#include "open62541.h"
int main(void)
{
UA_Client *client = UA_Client_new(UA_ClientConfig_default);
UA_StatusCode retval = UA_Client_connect(client,"opc.tcp://localhost:4840");
if(retval != UA_STATUSCODE_GOOD)
{
UA_Client_delete(client);
return (int)retval;
}
/*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;
UA_Variant_init(&value);
UA_NodeId testvar = UA_NODEID_STRING(1,"the.answer");
retval = UA_Client_readValueAttribute(client, testvar, &value);
if(retval == UA_STATUSCODE_GOOD) {
UA_Int32 *p = (UA_Int32 *)value.data;
printf("Var = %d \n",*p);
}
/*Clean up */
UA_Variant_deleteMembers(&value);
UA_Client_delete(client);
return UA_STATUSCODE_GOOD;
}
编译:
gcc -std=c99 open62541.c myClient.c -o myClient
gcc -std=c99 open62541.c myServer.c -o myServer
运行:
./myServer
打开一个终端
./myClient
反馈正确,Var = 43 .over
拓展
若是想在Arm上使用该例子,则需要下载其中的raspiberry树莓派的版本的发布包,里面是一个动态库。使用时有可能会出以下错误:
undefined reference to `clock_gettime'
请使用在最后添加 -lrt库:
gcc -std=c99 open62541.c myClient.c -o myClient -lrt
gcc -std=c99 open62541.c myServer.c -o myServer -lrt
拷贝到arm板子上执行即可!
这里提供一个简单的客户端,是从别人那下来的:
链接:https://pan.baidu.com/s/1KqcguYOpXKNB42CWdOJUDA 密码:1t0r
可以从linux连接网线到window,使用opc.tcp://192.168.XXX.XXX:4840连接:
如下,43也是打印出来的: