硬件软件版本
雷赛MC508CS MC508CS
VS2022 Visual Studio 2022
Win64 OpenSSL v3.5.1 OpenSSL
UaExpert v1.7.2 UaExpert
C++ based OPC UA Client/Server + Pub/Sub SDK - Windows 64Bit C++ SDK
配置
VS运行库选用多线程 DLL (/MD),配置Release x64。
Add Include Directories
Add the following include paths to your application
将Win64 OpenSSL v3.5.1的安装路径D:\Program Files\OpenSSL-Win64\include复制到…\third-party\win64\vs2022
$(SolutionDir)\include\uastack
$(SolutionDir)\include\uabasecpp
$(SolutionDir)\include\uaclientcpp
$(SolutionDir)\include\uapkicpp
$(SolutionDir)\include\xmlparsercpp
$(SolutionDir)\third-party\win64\vs2022
$(SolutionDir)\third-party\win64\vs2022\libxml2\include\libxml
$(SolutionDir)\utilities
Add Linker Settings
For Additional Library Directories enter the following values:选择Debug或Release。
将安装路径的D:\Program Files\OpenSSL-Win64\lib\VC\x86\MD中的文件复制到…\third-party\win64\vs2022\openssl
$(SolutionDir)\lib
$(SolutionDir)\third-party\win64\vs2022\libxml2\out32dll
$(SolutionDir)\third-party\win64\vs2022\openssl
For Additional Dependencies (Debug) enter:根据配置选择。
uastackd.lib
uabasecppd.lib
uapkicppd.lib
uaclientcppd.lib
crypt32.lib
libcryptod.lib
ws2_32.lib
rpcrt4.lib
xmlparsercppd.lib
libxml2d.lib
For Additional Dependencies (Release) enter:根据配置选择。
uastack.lib
uabasecpp.lib
uapkicpp.lib
uaclientcpp.lib
crypt32.lib
libcrypto.lib
ws2_32.lib
rpcrt4.lib
xmlparsercpp.lib
libxml2.lib
Add Preprocessor Defines,Add:
_UA_STACK_USE_DLL
UNICODE
_UNICODE
_CRT_SECURE_NO_WARNINGS
_CRT_SECURE_NO_DEPRECATE
将…\uasdkcppbundlepubsub-bin-EVAL-windows-vs2015_x64-v1.8.7-644\bin\uastack.dll和…\uasdkcppbundlepubsub-bin-EVAL-windows-vs2015_x64-v1.8.7-644\third-party\win64\vs2022\libxml2\out32dll\libxml2.dll复制到exe路径…\Release
代码
连接
UaStatus SampleClient::connect()
{
UaStatus result;
// For now we use a hardcoded URL to connect to the local DemoServer
UaString sURL("opc.tcp://192.168.1.3:4840");
// Provide information about the client
SessionConnectInfo sessionConnectInfo;
UaString sNodeName("unknown_host");
char szHostName[256];
if (0 == UA_GetHostname(szHostName, 256))
{
sNodeName = szHostName;
}
sessionConnectInfo.sApplicationName = "Unified Automation Getting Started Client";
// Use the host name to generate a unique application URI
sessionConnectInfo.sApplicationUri = UaString("urn:%1:UnifiedAutomation:GettingStartedClient").arg(sNodeName);
sessionConnectInfo.sProductUri = "urn:UnifiedAutomation:GettingStartedClient";
sessionConnectInfo.sSessionName = sessionConnectInfo.sApplicationUri;
// Security settings are not initialized - we connect without security for now
SessionSecurityInfo sessionSecurityInfo;
printf("\nConnecting to %s\n", sURL.toUtf8());
result = m_pSession->connect(
sURL,
sessionConnectInfo,
sessionSecurityInfo,
this);
if (result.isGood())
{
printf("Connect succeeded\n");
}
else
{
printf("Connect failed with status %s\n", result.toString().toUtf8());
}
return result;
}
断开
UaStatus SampleClient::disconnect()
{
UaStatus result;
// Default settings like timeout
ServiceSettings serviceSettings;
printf("\nDisconnecting ...\n");
result = m_pSession->disconnect(
serviceSettings,
OpcUa_True);
if (result.isGood())
{
printf("Disconnect succeeded\n");
}
else
{
printf("Disconnect failed with status %s\n", result.toString().toUtf8());
}
return result;
}
读取变量
UaStatus SampleClient::read()
{
UaStatus result;
ServiceSettings serviceSettings;
UaReadValueIds nodeToRead;
UaDataValues values;
UaDiagnosticInfos diagnosticInfos;
// Configure one node to read
// We read the value of the ServerStatus -> CurrentTime
nodeToRead.create(1);
UaNodeId volt(UaString("|var|Leadshine-ARM-Linux-SM-CNC.Application.PLC_PRG.test"), 4);
OpcUa_NodeId_CopyTo(volt, &nodeToRead[0].NodeId);
nodeToRead[0].AttributeId = OpcUa_Attributes_Value;
printf("\nReading ...\n");
result = m_pSession->read(
serviceSettings,
0,
OpcUa_TimestampsToReturn_Both,
nodeToRead,
values,
diagnosticInfos);
if (result.isGood())
{
// Read service succeeded - check status of read value
if (OpcUa_IsGood(values[0].StatusCode))
{
printf("ServerStatusCurrentValue: %s\n", UaVariant(values[0].Value).toString().toUtf8());
}
else
{
printf("Read failed for item[0] with status %s\n", UaStatus(values[0].StatusCode).toString().toUtf8());
}
}
else
{
// Service call failed
printf("Read failed with status %s\n", result.toString().toUtf8());
}
return result;
}
创建订阅
UaStatus SampleSubscription::createSubscription(UaSession* pSession)
{
if ( m_pSubscription )
{
printf("\nError: Subscription already created\n");
return OpcUa_BadInvalidState;
}
m_pSession = pSession;
UaStatus result;
ServiceSettings serviceSettings;
SubscriptionSettings subscriptionSettings;
subscriptionSettings.publishingInterval = 100;
printf("\nCreating subscription ...\n");
result = pSession->createSubscription(
serviceSettings,
this,
1,
subscriptionSettings,
OpcUa_True,
&m_pSubscription);
if (result.isGood())
{
printf("CreateSubscription succeeded\n");
}
else
{
m_pSubscription = NULL;
printf("CreateSubscription failed with status %s\n", result.toString().toUtf8());
}
return result;
}
创建数据监测
UaStatus SampleSubscription::createMonitoredItems()
{
if ( m_pSubscription == NULL )
{
printf("\nError: No Subscription created\n");
return OpcUa_BadInvalidState;
}
UaStatus result;
OpcUa_UInt32 i;
ServiceSettings serviceSettings;
UaMonitoredItemCreateRequests itemsToCreate;
UaMonitoredItemCreateResults createResults;
// Configure one item to add to subscription
// We monitor the value of the ServerStatus -> CurrentTime
itemsToCreate.create(1);
UaNodeId myVar(UaString("|var|Leadshine-ARM-Linux-SM-CNC.Application.PLC_PRG.test"),4);
myVar.copyTo(&itemsToCreate[0].ItemToMonitor.NodeId);
itemsToCreate[0].ItemToMonitor.AttributeId = OpcUa_Attributes_Value;
itemsToCreate[0].RequestedParameters.ClientHandle = 1;
itemsToCreate[0].RequestedParameters.SamplingInterval = 100;
itemsToCreate[0].RequestedParameters.QueueSize = 1;
itemsToCreate[0].RequestedParameters.DiscardOldest = OpcUa_True;
itemsToCreate[0].MonitoringMode = OpcUa_MonitoringMode_Reporting;
printf("\nAdding monitored items to subscription ...\n");
result = m_pSubscription->createMonitoredItems(
serviceSettings,
OpcUa_TimestampsToReturn_Both,
itemsToCreate,
createResults);
if (result.isGood())
{
// check individual results
for (i = 0; i < createResults.length(); i++)
{
if (OpcUa_IsGood(createResults[i].StatusCode))
{
printf("CreateMonitoredItems succeeded for item: %s\n",
UaNodeId(itemsToCreate[i].ItemToMonitor.NodeId).toXmlString().toUtf8());
}
else
{
printf("CreateMonitoredItems failed for item: %s - Status %s\n",
UaNodeId(itemsToCreate[i].ItemToMonitor.NodeId).toXmlString().toUtf8(),
UaStatus(createResults[i].StatusCode).toString().toUtf8());
}
}
}
// service call failed
else
{
printf("CreateMonitoredItems failed with status %s\n", result.toString().toUtf8());
}
return result;
}
写入变量
UaStatus SampleClient::write()
{
UaStatus result;
ServiceSettings serviceSettings;
UaWriteValues nodesToWrite;
UaStatusCodeArray results;
UaDiagnosticInfos diagnosticInfos;
nodesToWrite.create(1);
UaNodeId targetId("|var|Leadshine-ARM-Linux-SM-CNC.Application.PLC_PRG.test", 4);
targetId.copyTo(&nodesToWrite[0].NodeId);
nodesToWrite[0].AttributeId = OpcUa_Attributes_Value;
UaVariant value; // 例如变量在 PLC 为 REAL,则 setDouble / setFloat
value.setBoolean(OpcUa_False);
OpcUa_Variant_CopyTo(value, &nodesToWrite[0].Value.Value);
printf("\nWriting...\n");
result = m_pSession->write(serviceSettings,
nodesToWrite,
results,
diagnosticInfos);
if (result.isGood() && results[0] == OpcUa_Good)
{
printf("Write succeeded.\n");
}
else
{
printf("Write failed for item with status %s\n", UaStatus(results[0]).toString().toUtf8());
}
return result;
}
参考
C++ Based OPC UA Client/Server/PubSub SDK
Read Custom Node from OPCUA with C++ SDK - String as Node identifier