ANSI C Based OPC UA Client/Server SDK  1.8.3.398
clientmain.c
/*****************************************************************************
* *
* Copyright (c) 2006-2018 Unified Automation GmbH. All rights reserved. *
* *
* Software License Agreement ("SLA") Version 2.7 *
* *
* Unless explicitly acquired and licensed from Licensor under another *
* license, the contents of this file are subject to the Software License *
* Agreement ("SLA") Version 2.7, or subsequent versions as allowed by the *
* SLA, and You may not copy or use this file in either source code or *
* executable form, except in compliance with the terms and conditions of *
* the SLA. *
* *
* All software distributed under the SLA is provided strictly on an "AS *
* IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED, *
* AND LICENSOR HEREBY DISCLAIMS ALL SUCH WARRANTIES, INCLUDING WITHOUT *
* LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR *
* PURPOSE, QUIET ENJOYMENT, OR NON-INFRINGEMENT. See the SLA for specific *
* language governing rights and limitations under the SLA. *
* *
* The complete license agreement can be found here: *
* http://unifiedautomation.com/License/SLA/2.7/ *
* *
* Project: Unified Automation ANSI C based OPC UA Server SDK *
* *
*****************************************************************************/
/*============================================================================
* Includes
*===========================================================================*/
#include <uaclient_config.h>
#include <stdlib.h>
#include <opcua_datetime.h>
#include <opcua_trace.h>
#include <opcua_string.h>
#include <uaclient_module.h>
#include <uaclient_session.h>
/*============================================================================
* Includes End
*===========================================================================*/
#define UACLIENT_APPLICATION_NAME "UaSdkC - Client - Lesson01"
#define UACLIENT_APPLICATION_URI "urn:UnifiedAutomation:UaSdkC:Client:Lesson01"
#define UACLIENT_PRODUCT_URI "urn:UnifiedAutomation:UaSdkC:Client:Lesson01"
/* Server configuration used by this client */
#define SERVER_ENDPOINT_URL "opc.tcp://localhost:48020"
typedef enum _SampleStateMachine
{
State_Idle,
State_Connect,
State_Connected,
State_Read,
State_ReadDone,
State_Disconnect,
State_Disconnected,
State_Error
} SampleStateMachine;
typedef struct _SampleClientContext
{
SampleStateMachine State;
} SampleClientContext;
/*============================================================================
* Main helper functions
*===========================================================================*/
/* Initializes OPC UA Stack.
* Here you can configure trace settings and other stack configuration options.
*/
OpcUa_StatusCode InitializeOpcUaStack(OpcUa_Handle *a_phProxyStubPlatformLayer,
OpcUa_ProxyStubConfiguration *a_pProxyStubConfiguration)
{
OpcUa_InitializeStatus(OpcUa_Module_Client, "InitializeOpcUaStack");
/* Initialize Stack */
OpcUa_Trace(OPCUA_TRACE_LEVEL_WARNING, "UA Client: Initializing Stack...\n");
/* Default values can be changed here */
a_pProxyStubConfiguration->bProxyStub_Trace_Enabled = OpcUa_True;
a_pProxyStubConfiguration->uProxyStub_Trace_Level = OPCUA_TRACE_OUTPUT_LEVEL_ERROR;
uStatus = UaBase_Module_InitializeUaStack(a_phProxyStubPlatformLayer, a_pProxyStubConfiguration);
OpcUa_ReturnStatusCode;
OpcUa_BeginErrorHandling;
OpcUa_FinishErrorHandling;
}
/* Cleanup counterpart to InitializeOpcUaStack. */
OpcUa_StatusCode CleanupOpcUaStack(OpcUa_Handle *a_phProxyStubPlatformLayer)
{
OpcUa_InitializeStatus(OpcUa_Module_Client, "CleanupOpcUaStack");
/* Clean Up UA Stack */
uStatus = UaBase_Module_ClearUaStack(a_phProxyStubPlatformLayer);
OpcUa_ReturnStatusCode;
OpcUa_BeginErrorHandling;
OpcUa_FinishErrorHandling;
}
OpcUa_Void Sample_ConnectionStatusChanged_CB(UaClient_Session *a_pSession,
{
SampleClientContext *pClientContext = a_pSession->pUserData;
const char *pStatus = "INVALID";
switch (a_status)
{
pStatus = "Disconnected";
if (pClientContext->State == State_Connect)
{
OpcUa_Trace(OPCUA_TRACE_LEVEL_WARNING, "UA Client: failed to connect to server!\n");
}
if (pClientContext->State == State_Disconnect)
{
pClientContext->State = State_Disconnected;
}
else
{
pClientContext->State = State_Error;
}
break;
pStatus = "Connected";
if (pClientContext->State == State_Connect)
{
pClientContext->State = State_Connected;
}
else
{
pClientContext->State = State_Error;
}
break;
pStatus = "Connecting";
break;
pStatus = "ConnectionWarningWatchdogTimeout";
break;
pStatus = "ConnectionErrorClientReconnect";
break;
pStatus = "SessionAutomaticallyRecreated";
break;
default: break;
}
OpcUa_Trace(OPCUA_TRACE_LEVEL_WARNING, "\n--> Sample_ConnectionStatusChanged_CB: %s\n\n", pStatus);
}
OpcUa_Boolean Sample_ConnectError_CB(UaClient_Session *a_pSession,
OpcUa_Boolean a_overridable)
{
SampleClientContext *pClientContext = a_pSession->pUserData;
const char *pServiceType = "INVALID";
switch (a_serviceType)
{
case UaClient_ConnectServiceType_CertificateValidation: pServiceType = "CertificateValidation"; break;
case UaClient_ConnectServiceType_OpenSecureChannel: pServiceType = "OpenSecureChannel"; break;
case UaClient_ConnectServiceType_CreateSession: pServiceType = "CreateSession"; break;
case UaClient_ConnectServiceType_UserIdentityToken: pServiceType = "UserIdentityToken"; break;
case UaClient_ConnectServiceType_ActivateSession: pServiceType = "ActivateSession"; break;
default: break;
}
OpcUa_Trace(OPCUA_TRACE_LEVEL_WARNING, "Sample_ConnectError_CB:\n");
OpcUa_Trace(OPCUA_TRACE_LEVEL_WARNING, " ServiceType: %s\n", pServiceType);
OpcUa_Trace(OPCUA_TRACE_LEVEL_WARNING, " Error: 0x%08x\n", a_error);
OpcUa_Trace(OPCUA_TRACE_LEVEL_WARNING, " Overridable: %s\n", a_overridable == OpcUa_False ? "false" : "true");
pClientContext->State = State_Error;
return OpcUa_False;
}
static void Variant_ToString(const OpcUa_Variant *pValue, char *text, int len)
{
if (pValue->ArrayType == OpcUa_VariantArrayType_Scalar)
{
switch (pValue->Datatype)
{
case OpcUaType_Null:
OpcUa_SnPrintfA(text, len, "Null");
break;
case OpcUaType_Int32:
OpcUa_SnPrintfA(text, len, "%i", pValue->Value.Int32);
break;
case OpcUaType_UInt32:
OpcUa_SnPrintfA(text, len, "%u", pValue->Value.UInt32);
break;
case OpcUaType_Float:
OpcUa_SnPrintfA(text, len, "%f", pValue->Value.Float);
break;
case OpcUaType_Double:
OpcUa_SnPrintfA(text, len, "%f", pValue->Value.Double);
break;
case OpcUaType_DateTime:
OpcUa_DateTime_GetStringFromDateTime(pValue->Value.DateTime, text, len);
break;
default:
OpcUa_SnPrintfA(text, len, "Unsupported type");
break;
}
}
else
{
OpcUa_SnPrintfA(text, len, "Unsupported type");
}
}
OpcUa_Void Sample_Read_CB(const UaClient_Session *a_pSession,
OpcUa_ResponseHeader *a_pResponseHeader,
OpcUa_Int32 a_NoOfResults,
OpcUa_DataValue *a_pResults,
OpcUa_Int32 a_NoOfDiagnosticInfos,
OpcUa_DiagnosticInfo *a_pDiagnosticInfos,
OpcUa_Void *a_pUserData)
{
SampleClientContext *pClientContext = a_pSession->pUserData;
OpcUa_ReferenceParameter(a_NoOfDiagnosticInfos);
OpcUa_ReferenceParameter(a_pDiagnosticInfos);
OpcUa_ReferenceParameter(a_pUserData);
if (OpcUa_IsGood(a_pResponseHeader->ServiceResult))
{
OpcUa_Int32 i;
OpcUa_Trace(OPCUA_TRACE_LEVEL_WARNING, "Sample_Read_CB:\n");
for (i = 0; i < a_NoOfResults; i++)
{
char szSourceTimestamp[64] = {0};
char szServerTimestamp[64] = {0};
char szValue[64] = {0};
OpcUa_DateTime_GetStringFromDateTime(a_pResults[i].SourceTimestamp, szSourceTimestamp, sizeof(szSourceTimestamp));
OpcUa_DateTime_GetStringFromDateTime(a_pResults[i].ServerTimestamp, szServerTimestamp, sizeof(szServerTimestamp));
Variant_ToString(&a_pResults[i].Value, szValue, sizeof(szValue));
OpcUa_Trace(OPCUA_TRACE_LEVEL_WARNING, " [%i]:\n", i);
OpcUa_Trace(OPCUA_TRACE_LEVEL_WARNING, " Status: 0x%08x\n", a_pResults[i].StatusCode);
OpcUa_Trace(OPCUA_TRACE_LEVEL_WARNING, " SourceTimestamp: %s\n", szSourceTimestamp);
OpcUa_Trace(OPCUA_TRACE_LEVEL_WARNING, " ServerTimestamp: %s\n", szServerTimestamp);
OpcUa_Trace(OPCUA_TRACE_LEVEL_WARNING, " Value: %s\n", szValue);
}
if (pClientContext->State == State_Read)
pClientContext->State = State_ReadDone;
else
pClientContext->State = State_Error;
}
else
{
OpcUa_Trace(OPCUA_TRACE_LEVEL_WARNING, "Sample_Read_CB failed (0x%08x)\n", a_pResponseHeader->ServiceResult);
pClientContext->State = State_Error;
}
}
OpcUa_StatusCode Sample_Read(UaClient_Session *pSession)
{
OpcUa_Int32 numNodesToRead = 2;
OpcUa_ReadValueId nodesToRead[2];
OpcUa_ReadValueId_Initialize(&nodesToRead[0]);
nodesToRead[0].AttributeId = OpcUa_Attributes_Value;
nodesToRead[0].NodeId.NamespaceIndex = 0;
nodesToRead[0].NodeId.Identifier.Numeric = OpcUaId_Server_ServerStatus_State;
OpcUa_ReadValueId_Initialize(&nodesToRead[1]);
nodesToRead[1].AttributeId = OpcUa_Attributes_Value;
nodesToRead[1].NodeId.NamespaceIndex = 0;
nodesToRead[1].NodeId.Identifier.Numeric = OpcUaId_Server_ServerStatus_CurrentTime;
return UaClient_Session_BeginRead(pSession, /* Session */
OpcUa_Null, /* ServiceSettings */
0, /* MaxAge */
OpcUa_TimestampsToReturn_Both, /* TimestampsToReturn */
numNodesToRead, /* NoOfNodesToRead */
nodesToRead, /* NodesToRead */
Sample_Read_CB, /* Callback Function */
OpcUa_Null); /* Callback UserData */
}
/* Main OPC UA Client Loop. */
OpcUa_StatusCode ClientMain()
{
UaClient uaClient;
OpcUa_Boolean bClientInitialized = OpcUa_False;
UaClient_Configuration *pClientConfiguration = OpcUa_Null;
UaClient_Session *pSession = OpcUa_Null;
UaClient_Session_Callback sessionCallback;
OpcUa_Boolean bComplete = OpcUa_False;
SampleClientContext clientContext;
OpcUa_InitializeStatus(OpcUa_Module_Client, "ClientMain");
OpcUa_DeclareErrorTraceModule(OpcUa_Module_Client);
clientContext.State = State_Idle;
/* Initialize the Client SDK */
uStatus = UaClient_Initialize(&uaClient);
OpcUa_GotoErrorIfBad(uStatus);
bClientInitialized = OpcUa_True;
pClientConfiguration = UaClient_GetConfiguration();
/* ApplicationDescription and BuildInfo are not set by UaClient_Settings_GetConfigurationFromSettings,
the application has to set those manually */
/* ApplicationDescription */
OpcUa_String_AttachReadOnly(&pClientConfiguration->ApplicationDescription.ApplicationUri, UACLIENT_APPLICATION_URI);
OpcUa_String_AttachReadOnly(&pClientConfiguration->ApplicationDescription.ProductUri, UACLIENT_PRODUCT_URI);
OpcUa_String_AttachReadOnly(&pClientConfiguration->ApplicationDescription.ApplicationName.Text, UACLIENT_APPLICATION_NAME);
/* This example does not use security, disable PKI */
pClientConfiguration->PkiConfig.strPkiType = (char*)OPCUA_PKI_TYPE_NONE;
/* Create an OPC UA Session which handles the connection */
OpcUa_MemSet(&sessionCallback, 0, sizeof(sessionCallback));
sessionCallback.pfConnectionStatusChanged_CB = Sample_ConnectionStatusChanged_CB;
sessionCallback.pfConnectError_CB = Sample_ConnectError_CB;
uStatus = UaClient_Session_Create(&sessionCallback, &pSession);
OpcUa_GotoErrorIfBad(uStatus);
/* Set EndpointUrl */
OpcUa_String_AttachReadOnly(&pSession->EndpointDescription.EndpointUrl, SERVER_ENDPOINT_URL);
/* Disable automatic reconnect */
pSession->AutomaticReconnect = OpcUa_False;
/* Set user data */
pSession->pUserData = &clientContext;
/* StartUp Client */
uStatus = UaClient_StartUp(&uaClient);
OpcUa_GotoErrorIfBad(uStatus);
/* Main loop */
while (!(bComplete && pSession->ConnectionStatus == UaClient_ConnectionStatus_Disconnected))
{
/* process sample state machine */
switch (clientContext.State)
{
case State_Idle:
OpcUa_Trace(OPCUA_TRACE_LEVEL_WARNING, "UA Client: Connecting to %s ...\n", SERVER_ENDPOINT_URL);
uStatus = UaClient_Session_BeginConnect(pSession);
OpcUa_GotoErrorIfBad(uStatus);
clientContext.State = State_Connect;
break;
case State_Connected:
uStatus = Sample_Read(pSession);
OpcUa_GotoErrorIfBad(uStatus);
clientContext.State = State_Read;
break;
case State_ReadDone:
uStatus = UaClient_Session_BeginDisconnect(pSession, OpcUa_False);
OpcUa_GotoErrorIfBad(uStatus);
clientContext.State = State_Disconnect;
break;
case State_Disconnected:
OpcUa_Trace(OPCUA_TRACE_LEVEL_WARNING, "Sample successfully completed. Terminating now.\n");
bComplete = OpcUa_True;
break;
case State_Error:
uStatus = UaClient_Session_BeginDisconnect(pSession, OpcUa_True);
if (OpcUa_IsBad(uStatus) && uStatus != OpcUa_BadInvalidState) {OpcUa_GotoError;}
OpcUa_Trace(OPCUA_TRACE_LEVEL_WARNING, "An error occured. Terminating now.\n");
bComplete = OpcUa_True;
break;
default:
break;
}
/* Process Ua Client events */
uStatus = UaBase_DoCom();
if (OpcUa_IsBad(uStatus))
{
OpcUa_Trace(OPCUA_TRACE_LEVEL_WARNING, "UaBase_DoCom failed (0x%08x)\n", uStatus);
bComplete = OpcUa_True;
}
}
/******************************************************************************/
/* UaClient_Clear clears the PkiConfig of the client and attempts to free the strings
set there. As we have set literal string constants, we don't want those to be freed, so
we set them to NULL by initializing the structure. */
OpcUa_CertificateStoreConfiguration_Initialize(&pClientConfiguration->PkiConfig);
/* Clean Up Client */
OpcUa_Trace(OPCUA_TRACE_LEVEL_WARNING, "UA Client: Main stopped\n");
OpcUa_ReturnStatusCode;
OpcUa_BeginErrorHandling;
if (bClientInitialized != OpcUa_False)
{
/* Clean up Base */
}
OpcUa_Trace(OPCUA_TRACE_LEVEL_WARNING, "UA Client: Main stopped due ERROR! (0x%08x)\n", uStatus);
OpcUa_FinishErrorHandling;
}
/*============================================================================
* Main entry point for the application
*===========================================================================*/
int main()
{
int ret = EXIT_SUCCESS;
OpcUa_StatusCode uStatus = OpcUa_Good;
OpcUa_Handle hProxyStubPlatformLayer = OpcUa_Null;
OpcUa_ProxyStubConfiguration proxyStubConfiguration;
/* Set up OPC UA */
uStatus = InitializeOpcUaStack(&hProxyStubPlatformLayer, &proxyStubConfiguration);
if ( OpcUa_IsNotGood(uStatus) )
{
return EXIT_FAILURE;
}
/* Start the main client loop */
uStatus = ClientMain();
if ( OpcUa_IsNotGood(uStatus) )
{
ret = EXIT_FAILURE;
}
/* Clean up OPC UA */
uStatus = CleanupOpcUaStack(&hProxyStubPlatformLayer);
if ( OpcUa_IsNotGood(uStatus) )
{
ret = EXIT_FAILURE;
}
return ret;
}
#ifdef _WIN32_WCE
int WINAPI WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPWSTR lpCmdLine,
int nShowCmd)
{
OpcUa_ReferenceParameter(hInstance);
OpcUa_ReferenceParameter(hPrevInstance);
OpcUa_ReferenceParameter(lpCmdLine);
OpcUa_ReferenceParameter(nShowCmd);
return main(0, OpcUa_Null);
}
#endif