C++ Based OPC UA Client/Server SDK  1.5.5.355
Lesson 1: Connect and Read

Step 1: Create New Project

Set up a console application.

Windows:
Create a new project. Use the following settings:

  • Win32 Console Application
  • No precompiled headers
  • Empty project.

Add Files to the Project

Add the following new source files to your project:

sampleclient.h
sampleclient.cpp
The class SampleClient encapsulates OPC UA functionality and it is used to call OPC UA services.
client_cpp_sdk_tutorial.cpp
Instantiates the class SampleClient and initiates actions on it, like connect, disconnect etc.

Add Include Directories

Add the following include paths to your application:

[SDK Installation Directory]\include\uastack
[SDK Installation Directory]\include\uabase
[SDK Installation Directory]\include\uaclient
[SDK Installation Directory]\include\uapki
[SDK Installation Directory]\include\xmlparser
[SDK Installation Directory]\third-party\win32\[VisualStudioVersion]\openssl\inc32
[SDK Installation Directory]\third-party\win32\[VisualStudioVersion]\libxml2\include
[SDK Installation Directory]\examples\utilities

Linux:
[SDK Installation Directory]/examples/utilities/linux

For more information see LibraryOverview.

Add Linker Settings

Windows:
For Additional Library Directories enter the following values:
[SDK Installation Directory]\lib
[SDK Installation Directory]\third-party\win32\[VisualStudioVersion]\libxml2\out32dll.dbg (Debug)
[SDK Installation Directory]\third-party\win32\[VisualStudioVersion]\libxml2\out32dll (Release)
[SDK Installation Directory]\third-party\win32\[VisualStudioVersion]\openssl\out32dll.dbg (Debug)
[SDK Installation Directory]\third-party\win32\[VisualStudioVersion]\openssl\out32dll (Release)

For Additional Dependencies (Debug) enter:
uastackd.lib
uabased.lib
uapkid.lib
uaclientd.lib
crypt32.lib
libeay32d.lib
ws2_32.lib
rpcrt4.lib
xmlparserd.lib
libxml2d.lib

For Additional Dependencies (Release) enter:
uastack.lib
uabase.lib
uapki.lib
uaclient.lib
crypt32.lib
libeay32.lib
ws2_32.lib
rpcrt4.lib
xmlparser.lib
libxml2.lib

Linux:
For Additional Library Directories enter the following values:
-L[SDK Installation Directory]/lib

For Additional Dependencies (Debug) enter:
-luastackd -luaclientd -luabased -luapkid -lpthread -lrt -lssl

For Additional Dependencies (Release) enter:
-luastack -luaclient -luabase -luapki -lpthread -lrt -lssl

Add Preprocessor Defines

Add:

_UA_STACK_USE_DLL

Additional defines for Windows:

UNICODE
_UNICODE
_CRT_SECURE_NO_WARNINGS
_CRT_SECURE_NO_DEPRECATE

Set Output Path

Set output path to bin where the config file resides.

Windows:

Enter these values:

Output Directory
[SDK Installation Directory]\bin
Intermediate Directory
obj\$(Configuration)

Step 2: Introducing UaSession and UaSessionCallback

Add the following code to the file sampleclient.h:

#ifndef SAMPLECLIENT_H
#define SAMPLECLIENT_H
#include "uabase.h"
#include "uaclientsdk.h"
using namespace UaClientSdk;
class SampleClient : public UaSessionCallback
{
UA_DISABLE_COPY(SampleClient);
public:
SampleClient();
virtual ~SampleClient();
// UaSessionCallback implementation ----------------------------------------------------
virtual void connectionStatusChanged(OpcUa_UInt32 clientConnectionId, UaClient::ServerStatus serverStatus);
// UaSessionCallback implementation ------------------------------------------------------
private:
UaSession* m_pSession;
};
#endif // SAMPLECLIENT_H

The code snippet above declares a pointer to UaSession. This class manages a UA client side application session. It is the main class for connecting to any OPC UA server. It provides all non-Subscription related Services. In addition, the class manages the connection to an OPC UA server and the application session established with the server.

UaSessionCallback defines the callback interface for UaSession. This interface must be implemented by the user of UaSession to receive connection status change callbacks from the Client SDK.

Add the following code to sampleclient.cpp

#include "sampleclient.h"
#include "uasession.h"
SampleClient::SampleClient()
{
m_pSession = new UaSession();
}
SampleClient::~SampleClient()
{
if (m_pSession)
{
delete m_pSession;
m_pSession = NULL;
}
}

We implement the method connectionStatusChanged to monitor the connection state using UaSessionCallback.

void SampleClient::connectionStatusChanged(
OpcUa_UInt32 clientConnectionId,
UaClient::ServerStatus serverStatus)
{
OpcUa_ReferenceParameter(clientConnectionId);
printf("-------------------------------------------------------------\n");
switch (serverStatus)
{
case UaClient::Disconnected:
printf("Connection status changed to Disconnected\n");
break;
case UaClient::Connected:
printf("Connection status changed to Connected\n");
break;
case UaClient::ConnectionWarningWatchdogTimeout:
printf("Connection status changed to ConnectionWarningWatchdogTimeout\n");
break;
case UaClient::ConnectionErrorApiReconnect:
printf("Connection status changed to ConnectionErrorApiReconnect\n");
break;
case UaClient::ServerShutdown:
printf("Connection status changed to ServerShutdown\n");
break;
case UaClient::NewSessionCreated:
printf("Connection status changed to NewSessionCreated\n");
break;
}
printf("-------------------------------------------------------------\n");
}

Step 3: Initializing UA Stack and Create Instance of SampleClient

The UA Stack platform layer has to be initialized before calling any Stack or SDK function.

After creating an instance of SampleClient we are prepared to connect to the server.

Add the following code to client_cpp_sdk_tutorial.cpp:

#include "uaplatformlayer.h"
#include "sampleclient.h"
/*============================================================================
* main
*===========================================================================*/
#ifdef _WIN32_WCE
int WINAPI WinMain( HINSTANCE, HINSTANCE, LPWSTR, int)
#else
int main(int, char*[])
#endif
{
UaStatus status;
// Initialize the UA Stack platform layer
// Create instance of SampleClient
SampleClient* pMyClient = new SampleClient();
// Close application
printf("\nPress Enter to close\n");
// Wait for user command.
getchar();
delete pMyClient;
pMyClient = NULL;
// Cleanup the UA Stack platform layer
return 0;
}

Step 4: Connect and Disconnect

Add connect()

Add connect() to the header file:

class SampleClient : public UaSessionCallback
{
...
// UaSessionCallback implementation ----------------------------------------------------
virtual void connectionStatusChanged(OpcUa_UInt32 clientConnectionId, UaClient::ServerStatus serverStatus);
// UaSessionCallback implementation ------------------------------------------------------
// New code begins
// OPC UA service calls
UaStatus connect();
// New code ends
...
};

and the source file:

See SessionConnectInfo for a parameter description.

UaStatus SampleClient::connect()
{
UaStatus result;
// For now we use a hardcoded URL to connect to the local DemoServer
UaString sURL("opc.tcp://localhost:48010");
// 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;
}

Add disconnect()

Now we add disconnect() to header file:

...
// OPC UA service calls
UaStatus connect();
UaStatus disconnect(); // Add this line

and the source file:

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;
}

We complete the destructor of SampleClient:

SampleClient::~SampleClient()
{
if (m_pSession)
{
// New code begins
// disconnect if we're still connected
if (m_pSession->isConnected() != OpcUa_False)
{
ServiceSettings serviceSettings;
m_pSession->disconnect(serviceSettings, OpcUa_True);
}
// New code ends
delete m_pSession;
m_pSession = NULL;
}
}

Now we are able to connect to a server and disconnect. Add the following code to main:

...
// Create instance of SampleClient
SampleClient* pMyClient = new SampleClient();
// New code begins
// Connect to OPC UA Server
status = pMyClient->connect();
// Connect succeeded
if (status.isGood())
{
// Wait for user command.
printf("\nPress Enter to disconnect\n");
getchar();
// Disconnect from OPC UA Server
status = pMyClient->disconnect();
}
//New code ends
// Close application
printf("\nPress Enter to close\n");
// Wait for user command.
getchar();
...

Step 5: Read

In the last step of this lesson the client is enabled to read the value attribute of a variable using UaSession::read.

Add read() to the header

UaStatus connect();
UaStatus disconnect();
UaStatus read();

and the source file:

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);
nodeToRead[0].AttributeId = OpcUa_Attributes_Value;
nodeToRead[0].NodeId.Identifier.Numeric = OpcUaId_Server_ServerStatus_CurrentTime;
printf("\nReading ...\n");
result = m_pSession->read(
serviceSettings,
0,
nodeToRead,
values,
diagnosticInfos);
if (result.isGood())
{
// Read service succeded - check status of read value
if (OpcUa_IsGood(values[0].StatusCode))
{
printf("ServerStatusCurrentTime: %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;
}

Now we are able to call read from main. Add the following code to client_cpp_sdk_tutorial.cpp:

...
// Connect succeeded
if (status.isGood())
{
// New code begins
// Read values
status = pMyClient->read();
// New code ends
// Wait for user command.
printf("\nPress Enter to disconnect\n");
getchar();
...