本文主要讲述在Windows下如何使用Visual Studio来编译open62541,以及基于open62541去开发OPCUA程序。
一 Visual Studio版本选择
必须使用VS2015或者之后的版本,官方教程使用的是VS2015,如下,
安装后,保证创建工程时有Win32 控制台程序选项,如果没有可以百度一下,容易解决。
二 编译open62541
可以使用上节图片中的命令行方式调用cmake.exe去生成VS2015的工程。本人使用的是cmake-gui,更加方便一点,另外,需要提前安装好Python3
首先在open62541源码目录下创建一个build文件夹,然后打开cmake-gui,
第一行输入open62541源码目录,第二行输入刚刚创建的build目录,VS工程最后会生成在这个目录里,然后点击左下角的Configure,在弹出的界面里选择Visual Studio 14 2015,如下,
然后点击Finish开始进行配置,配置完成后如下,
红色一片是open62541自带的CMakeLists里提供的配置选择,这里以gui的方式显示出来了。这里勾选上UA_ENABLE_AMALGAMATION,其它暂时默认就行了。然后点击Generate进行生成,
OK之后点击Generate右边的Open Project按钮,打开VS工程,或者进入open62541下的build目录,找到open62541.sln,打开之,
如下,
在生成下点击生成解决方案就行了,然后等待生成,
最后生成成功,如下显示,
这时回到之前的build目录下,可以看到open62541.h,open62541.c以及bin/Debug/open62541.lib都生成出来了。
三 编写OPC UA Server
首先使用VS2015建立一个Win32控制台工程,建立过程中选择空项目,
建好后,把open62541.h和open62541.c拷贝到工程目录里,然后添加到工程里,最后添加一个main.cpp到工程里(main.c也是可以的),其内容如下,
// server.c
/* 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 "open62541.h"
#include <signal.h>
#include <stdlib.h>
UA_Boolean running = true;
static void stopHandler(int sign) {
UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_SERVER, "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;
}
整体工程目录如下,
此时,点击生成->生成解决方案,但是会报错,如下,
看上去是open62541自身依赖的库没有添加,看名字和网络相关,于是网上搜了下,原因是:open62541使用socket,而windows下的socket要依赖WS2_32.lib。
有2个解决办法:
1. 修改工程配置(推荐)
依次打开项目->属性->链接器->输入->附加依赖项,然后打开并写入WS2_32.lib,然后点击确定就可以了
2. 工程添加WS2_32.lib
网上找的这个库,然后添加到工程里,也可以点击这里下载(本人下载好后传到百度云,提取码9d92)
使用以上任意方法后,再次生成解决方案,成功!
运行,控制台打印如下(只截取一部分),Server运行成功
有些读者运行时会遇到错误:应用程序没有调用 WSAStartup,或者 WSAStartup 失败。可以在main()开头处添加以下2行代码解决,
WSADATA wsaData;
WSAStartup(MAKEWORD(2,2), &wsaData); // 使用Winsock 2.2版本
这2行是用于设置程序中用到的Winsock版本,并初始化相应版本的库。
四 编写OPC UA Client
按照相同操作我们再建一个工程来编写OPC UA Client代码,过程不再赘述,Client的main.cpp代码如下,
// client.c,功能主要是从server那里获取时间
#include <stdlib.h>
#include "open62541.h"
int main(void)
{
UA_Client *client = UA_Client_new();
UA_ClientConfig_setDefault(UA_Client_getConfig(client));
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; /* Variants can hold scalar values and arrays of any type */
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);
retval = UA_Client_readValueAttribute(client, nodeId, &value);
if (retval == UA_STATUSCODE_GOOD && UA_Variant_hasScalarType(&value, &UA_TYPES[UA_TYPES_DATETIME]))
{
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);
}
/* Clean up */
UA_Variant_clear(&value);
UA_Client_delete(client); /* Disconnects the client internally */
system("pause"); // 防止控制台一闪而过
return EXIT_SUCCESS;
}
client的功能是从server那边获取系统时间,然后打印出来,工程结构如下,
编译成功后,运行(要先运行Server),成功获取时间并打印,
五 使用UaExpert连接Server
UaExpert的使用可以参照这篇文章,连接成功后如下,
如果看过前面的系列文章,都知道这是熟悉的界面。
六 总结
本文主要讲述如何在Win下使用VS编译及使用open62541,本系列的第一篇文章是讲述如何在Linux下编译及使用open62541。
能在2个平台下使用,且体验一样,这正体现了OPC UA里的UA,即Unified Architecture,这也符合未来万物互联发展趋势。
如果有写的不对的地方,希望能留言指正,谢谢阅读。