关于opcua的介绍这里就不多说了,相信大家大都有了一些了解,open62541是一个开源C(C99)的opc-ua实现,开源代码可在官网或github上下载。

话不多说,首先搭建一个opcua服务器实例

 #include <signal.h>
#include "open62541.h"
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_ServerConfig *config = UA_ServerConfig_new_default();
UA_Server *server = UA_Server_new(config);
UA_StatusCode retval = UA_Server_run(server, &running);
UA_Server_delete(server);
UA_ServerConfig_delete(config);
return (int)retval;
}

以下代码演示如何使用数据类型以及如何向服务器添加变量节点。首先,我们向服务器添加一个新变量。查看UA变量属性结构的定义,以查看为变量节点定义的所有属性的列表。请注意,默认设置将变量值的访问级别设置为只读。有关使变量可写的信息,请参见下文。

 #include <signal.h>
#include <stdio.h>
#include "open62541.h"
static void
addVariable(UA_Server *server) {
/* Define the attribute of the myInteger variable node */
UA_VariableAttributes attr = UA_VariableAttributes_default;
UA_Int32 myInteger = ;
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(, "the.answer");
UA_QualifiedName myIntegerName = UA_QUALIFIEDNAME(, "the answer");
UA_NodeId parentNodeId = UA_NODEID_NUMERIC(, UA_NS0ID_OBJECTSFOLDER);
UA_NodeId parentReferenceNodeId = UA_NODEID_NUMERIC(, UA_NS0ID_ORGANIZES);
UA_Server_addVariableNode(server, myIntegerNodeId, parentNodeId,
parentReferenceNodeId, myIntegerName,
UA_NODEID_NUMERIC(, UA_NS0ID_BASEDATAVARIABLETYPE),attr, NULL, NULL);
}

现在我们用 写服务 更改节点值。也可以通过网络由OPC UA的客户端访问来修改值 。

 static void
writeVariable(UA_Server *server) {
UA_NodeId myIntegerNodeId =
UA_NODEID_STRING(,"the.answer"); /* Write a different integer value */
UA_Int32 myInteger = ;
UA_Variant myVar;
UA_Variant_init(&myVar);
UA_Variant_setScalar(&myVar, &myInteger,
&UA_TYPES[UA_TYPES_INT32]);
UA_Server_writeValue(server, myIntegerNodeId, myVar); /* Set the status code of the value to an error code. The
function
* UA_Server_write provides access to the raw service. The
above
* UA_Server_writeValue is syntactic sugar for writing a specific
node
* attribute with the write service. */
UA_WriteValue wv;
UA_WriteValue_init(&wv);
wv.nodeId = myIntegerNodeId;
wv.attributeId = UA_ATTRIBUTEID_VALUE;
wv.value.status = UA_STATUSCODE_BADNOTCONNECTED;
wv.value.hasStatus = true;
UA_Server_write(server, &wv); /* Reset the variable to a good statuscode with a value */
wv.value.hasStatus = false;
wv.value.value = myVar;
wv.value.hasValue = true;
UA_Server_write(server, &wv);
}

注意我们最初如何将变量节点的data type属性设置为int32数据类型的nodeid。这禁止写入非Int32的值。下面的代码显示了如何对每次写入执行一致性检查。

 static void
writeWrongVariable(UA_Server *server) {
UA_NodeId myIntegerNodeId = UA_NODEID_STRING(, "the.answer"); /* Write a string */
UA_String myString = UA_STRING("test");
UA_Variant myVar;
UA_Variant_init(&myVar);
UA_Variant_setScalar(&myVar, &myString,
&UA_TYPES[UA_TYPES_STRING]);
UA_StatusCode retval = UA_Server_writeValue(server,
myIntegerNodeId, myVar);
printf("Writing a string returned statuscode %s\n",
UA_StatusCode_name(retval));
}

它遵循主服务器代码,使用上述定义。

 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_ServerConfig *config = UA_ServerConfig_new_default();
UA_Server *server = UA_Server_new(config); addVariable(server);
writeVariable(server);
writeWrongVariable(server); UA_StatusCode retval = UA_Server_run(server, &running);
UA_Server_delete(server);
UA_ServerConfig_delete(config);
return (int)retval;
}

在基于OPC UA的体系结构中,服务器通常位于信息源附近。在工业环境中,这意味着服务器接近物理过程,客户机在运行时使用数据。在前面的教程中,我们看到了如何向OPC UA信息模型添加变量。本实例演示如何将变量连接到运行时信息,例如从物理过程的测量中连接。为简单起见,我们以系统时钟为基础的“过程”。以下代码段分别与运行时更新变量值的不同方式有关。总之,代码片段定义了一个可编译的源文件。

作为起点,假设已在服务器中为datetime类型的值创建了一个标识符为“ns=1,s=current time”的变量。假设当一个新的值从底层进程到达时,我们的应用程序被触发,我们可以直接写入变量。

 #include <signal.h>
#include "open62541.h"
#pragma comment(lib, "WS2_32")
static void
updateCurrentTime(UA_Server *server) {
UA_DateTime now = UA_DateTime_now();
UA_Variant value;
UA_Variant_setScalar(&value, &now, &UA_TYPES[UA_TYPES_DATETIME]);
UA_NodeId currentNodeId = UA_NODEID_STRING(, "current-time");
UA_Server_writeValue(server, currentNodeId, value);
}
static void
addCurrentTimeVariable(UA_Server *server) {
UA_DateTime now = ;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("en-US", "Current time");
attr.accessLevel = UA_ACCESSLEVELMASK_READ | UA_ACCESSLEVELMASK_WRITE;
UA_Variant_setScalar(&attr.value, &now, &UA_TYPES[UA_TYPES_DATETIME]);
UA_NodeId currentNodeId = UA_NODEID_STRING(, "current-time");
UA_QualifiedName currentName = UA_QUALIFIEDNAME(, "current-time");
UA_NodeId parentNodeId = UA_NODEID_NUMERIC(, UA_NS0ID_OBJECTSFOLDER);
UA_NodeId parentReferenceNodeId = UA_NODEID_NUMERIC(, UA_NS0ID_ORGANIZES);
UA_NodeId variableTypeNodeId = UA_NODEID_NUMERIC(, UA_NS0ID_BASEDATAVARIABLETYPE);
UA_Server_addVariableNode(server, currentNodeId, parentNodeId,
parentReferenceNodeId, currentName,
variableTypeNodeId, attr, NULL, NULL);
updateCurrentTime(server);
}

2.值回调

当一个值不断变化时,例如系统时间,在一个紧密的循环中更新该值将占用大量的资源。值回调允许将变量值与外部表示同步。它们将回调附加到每次读操作之前和每次写操作之后执行的变量。

 static void
beforeReadTime(UA_Server *server,
const UA_NodeId *sessionId, void *sessionContext,
const UA_NodeId *nodeid, void *nodeContext,
const UA_NumericRange *range, const UA_DataValue *data) {
UA_DateTime now = UA_DateTime_now();
UA_Variant value;
UA_Variant_setScalar(&value, &now, &UA_TYPES[UA_TYPES_DATETIME]);
UA_NodeId currentNodeId = UA_NODEID_STRING(, "current-time");
UA_Server_writeValue(server, currentNodeId, value);
}
static void
afterWriteTime(UA_Server *server,
const UA_NodeId *sessionId, void *sessionContext,
const UA_NodeId *nodeId, void *nodeContext,
const UA_NumericRange *range, const UA_DataValue *data) {
UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND,
"The variable was updated");
}
static void
addValueCallbackToCurrentTimeVariable(UA_Server *server) {
UA_NodeId currentNodeId = UA_NODEID_STRING(, "current-time");
UA_ValueCallback callback;
callback.onRead = beforeReadTime;
callback.onWrite = afterWriteTime;
UA_Server_setVariableNode_valueCallback(server, currentNodeId, callback);
}

3.变量数据源

对于值回调,该值仍存储在变量节点中。所谓的数据源更进一步。服务器将每个读写请求重定向到回调函数。在读取时,回调提供当前值的副本。在内部,数据源需要实现自己的内存管理。

 static UA_StatusCode
readCurrentTime(UA_Server *server,
const UA_NodeId *sessionId, void *sessionContext,
const UA_NodeId *nodeId, void *nodeContext,
UA_Boolean sourceTimeStamp, const UA_NumericRange *range,
UA_DataValue *dataValue) {
UA_DateTime now = UA_DateTime_now();
UA_Variant_setScalarCopy(&dataValue->value, &now,
&UA_TYPES[UA_TYPES_DATETIME]);
dataValue->hasValue = true;
return UA_STATUSCODE_GOOD;
} static UA_StatusCode
writeCurrentTime(UA_Server *server,
const UA_NodeId *sessionId, void *sessionContext,
const UA_NodeId *nodeId, void *nodeContext,
const UA_NumericRange *range, const UA_DataValue *data) {
UA_LOG_INFO(UA_Log_out, UA_LOGCATEGORY_USERLAND,
"Changing the system time is not implemented");
return UA_STATUSCODE_GOOD;
} static void
addCurrentTimeDataSourceVariable(UA_Server *server) {
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("en-US", "Current time - data source");
attr.accessLevel = UA_ACCESSLEVELMASK_READ | UA_ACCESSLEVELMASK_WRITE;
UA_NodeId currentNodeId = UA_NODEID_STRING(, "current-time-datasource");
UA_QualifiedName currentName = UA_QUALIFIEDNAME(, "current-time-datasource");
UA_NodeId parentNodeId = UA_NODEID_NUMERIC(, UA_NS0ID_OBJECTSFOLDER);
UA_NodeId parentReferenceNodeId = UA_NODEID_NUMERIC(, UA_NS0ID_ORGANIZES);
UA_NodeId variableTypeNodeId = UA_NODEID_NUMERIC(, UA_NS0ID_BASEDATAVARIABLETYPE);
UA_DataSource timeDataSource;
timeDataSource.read = readCurrentTime;
timeDataSource.write = writeCurrentTime;
UA_Server_addDataSourceVariableNode(server, currentNodeId, parentNodeId,
parentReferenceNodeId, currentName,
variableTypeNodeId, attr,
timeDataSource, NULL, NULL);
}

以下代码遵循主服务器代码,使用上述定义。

 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_ServerConfig *config = UA_ServerConfig_new_default();
UA_Server *server = UA_Server_new(config);
addCurrentTimeVariable(server);
addValueCallbackToCurrentTimeVariable(server);
addCurrentTimeDataSourceVariable(server);
UA_StatusCode retval = UA_Server_run(server, &running);
UA_Server_delete(server);
UA_ServerConfig_delete(config);
return (int)retval;
}
 

基于open62541的opc ua 服务器开发实现(1)的更多相关文章

  1. SharpNodeSettings项目,可配置的数据采集,统一的工业数据网关,OPC UA服务器开发,PLC数据发布到自身内存,redis,opc ua,以及数据可视化开发

    本项目隶属于 HslCommunication 项目的SDK套件,如果不清楚HslCommunication组件的话,可以先了解那个项目,源代码地址:https://github.com/dathli ...

  2. C# 读写opc ua服务器,浏览所有节点,读写节点,读历史数据,调用方法,订阅,批量订阅操作

    OPC UA简介 OPC是应用于工业通信的,在windows环境的下一种通讯技术,原有的通信技术难以满足日益复杂的环境,在可扩展性,安全性,跨平台性方面的不足日益明显,所以OPC基金会在几年前提出了面 ...

  3. C# 实现opc ua服务器的远程连接(转)

    原文转自:https://www.cnblogs.com/dathlin/p/7724834.html OPC UA简介 OPC是应用于工业通信的,在windows环境的下一种通讯技术,原有的通信技术 ...

  4. 分享一款免费OPC UA服务器

    OPC UA基于OPC基金会提供的新一代技术,提供安全,可靠和独立于厂商的,实现原始数据和预处理的信息从制造层级到生产计划或ERP层级的传输.通过OPC UA,所有需要的信息在任何时间,任何地点对每个 ...

  5. C#实现访问OPC UA服务器

    OPC UA服务器支持三种认证方式,分别是匿名认证.用户认证和证书认证.其中匿名认证安全等级最低,访问不做任何校验.用户认证访问时,OPC UA客户端需要提供用户名及密码认证,只有用户名和密码正确才允 ...

  6. C# OPC UA服务器 OPC UA网关 三菱 西门子 欧姆龙 Modbus转OPC UA 服务器 可配置的OPC UA服务器网关 HslSharp软件文档

    前言 本文将使用一个基于开源项目HslCommunication创建的OPC UA网关,方便通过配置创建一个OPC UA的网关中心.具体的操作及支持的设备信息项目参照下面: 开源项目HslCommun ...

  7. OPC协议解析-OPC UA OPC统一架构

    1    什么是OPC UA 为了应对标准化和跨平台的趋势,为了更好的推广OPC,OPC基金会近些年在之前OPC成功应用的基础上推出了一个新的OPC标准-OPC UA.OPC UA接口协议包含了之前的 ...

  8. OPC UA (统一架构)的优势

    OPC UA OPC统一架构(OPC Unified Architecture)是OPC基金会(OPC Foundation)创建的新技术,更加安全.可靠.中性(与供应商无关),为制造现场到生产计划或 ...

  9. 转:OPC协议解析-OPC UA OPC统一架构

    1    什么是OPC UA 为了应对标准化和跨平台的趋势,为了更好的推广OPC,OPC基金会近些年在之前OPC成功应用的基础上推出了一个新的OPC标准-OPC UA.OPC UA接口协议包含了之前的 ...

随机推荐

  1. scrapy 教程

    pip install Scrapy 结果报错,那就一个一个安装吧 一.安装  1.pip install wheel 后面的都一样 pip install lxml pip install pyop ...

  2. java中的反射整理

    1,什么是反射 反射机制是java语言提供的一种基础功能,它能够赋予成语在运行时进行自省的能力.通过反射我们可以直接操作类或者对象,例如:可以通过反射去获取某个对象的类的定义,属性,方法,还可以修改类 ...

  3. 第k小的元素

    利用快排思想,如果标志位大于k,则第k小的数字在左边,否则在右边.(程序是第k大的元素) #include <iostream> #include <vector> using ...

  4. go 结构体

    结构体声明 type Employee struct { ID int Name string Address string DoB time.Time Position string Salary ...

  5. ctf密码学习题总结

    1.变异凯撒 加密密文:afZ_r9VYfScOeO_UL^RWUc格式:flag{ }   一看题中说的是凯撒加密,我就赶快使用工具列出了所有的组合,然而发现没有一个是我想要的. 于是乎,又重新审题 ...

  6. 微信小程序统计分析

    在微信公众平台社区看到一个不错的东西,小博统计:https://www.wxappdev.com/:用于微信小程序统计分析.

  7. 转 c#性能优化秘密

    原文:http://www.dotnetperls.com/optimization Generally, using the simplest features of the language pr ...

  8. LeetCode 字符串专题(一)

    目录 LeetCode 字符串专题 <c++> \([5]\) Longest Palindromic Substring \([28]\) Implement strStr() [\(4 ...

  9. 19南昌网络赛L

    校赛打杂没施展开. 题意:一开始给你一颗 (0,0)到(0,l)的树. 这棵树每一年会长出来三个幼芽(雾),长度均为l/4,方向分别是左转60,右转60,和不变. 年份<=14 考虑3^14直接 ...

  10. Java 设计模式(概述)

    设计模式的三个分类                                                                                   创建型模式:对象 ...