ANSI C Based OPC UA Client/Server/PubSub SDK  1.9.1.442
clientmain.c
/*****************************************************************************
* *
* Copyright (c) 2006-2019 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>
#include <uabase_utilities.h>
/*============================================================================
* Defines
*===========================================================================*/
#define UACLIENT_APPLICATION_NAME "UaSdkC - Client - Lesson05"
#define UACLIENT_APPLICATION_URI "urn:UnifiedAutomation:UaSdkC:Client:Lesson05"
#define UACLIENT_PRODUCT_URI "urn:UnifiedAutomation:UaSdkC:Client:Lesson05"
/* Server configuration used by this client */
#define SERVER_ENDPOINT_URL "opc.tcp://localhost:48020"
/*============================================================================
* Client structures
*===========================================================================*/
typedef enum _SampleStateMachine
{
State_Idle,
State_Connect,
State_Connected,
State_Register,
State_RegisterDone,
State_Unregister,
State_UnregisterDone,
State_Write,
State_WriteDone,
State_Disconnect,
State_Disconnected,
State_Error
} SampleStateMachine;
/* A context for each client that is passed to the callback functions
* as user data. This eliminates the need for global variables.
*/
typedef struct _SampleClientContext
{
SampleStateMachine State;
OpcUa_Int32 noOfRegisteredNodeIds;
OpcUa_NodeId registeredNodeId[5];
} 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 */
printf("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_WARNING;
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;
}
/* The UaClient_Session_Callback UaClient_Session ConnectionStatusChanged callback. */
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);
}
/* The UaClient_Session ConnectError callback. */
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;
}
OpcUa_Void Sample_Register_CB(const UaClient_Session *a_pSession,
OpcUa_ResponseHeader *a_pResponseHeader,
OpcUa_Int32 a_NoOfRegisteredNodeIds,
OpcUa_NodeId *a_pRegisteredNodeIds,
OpcUa_Void *a_pUserData)
{
SampleClientContext *pClientContext = a_pSession->pUserData;
OpcUa_ReferenceParameter(a_pUserData);
if (OpcUa_IsGood(a_pResponseHeader->ServiceResult))
{
OpcUa_Int32 i;
OpcUa_Trace(OPCUA_TRACE_LEVEL_WARNING, "Sample_Register_CB:\n");
if (pClientContext->State == State_Register)
{
pClientContext->State = State_RegisterDone;
pClientContext->noOfRegisteredNodeIds = a_NoOfRegisteredNodeIds;
for (i = 0; i < a_NoOfRegisteredNodeIds; i++)
{
OpcUa_Trace(OPCUA_TRACE_LEVEL_WARNING, " [%i]:\n", i);
OpcUa_Trace(OPCUA_TRACE_LEVEL_WARNING, " IdentifierType: 0x%08x\n", a_pRegisteredNodeIds[i].IdentifierType);
OpcUa_Trace(OPCUA_TRACE_LEVEL_WARNING, " NamespaceIndex: 0x%08x\n", a_pRegisteredNodeIds[i].NamespaceIndex);
pClientContext->registeredNodeId[i].IdentifierType = a_pRegisteredNodeIds[i].IdentifierType;
pClientContext->registeredNodeId[i].NamespaceIndex = a_pRegisteredNodeIds[i].NamespaceIndex;
switch (a_pRegisteredNodeIds[i].IdentifierType)
{
pClientContext->registeredNodeId[i].Identifier.Numeric = a_pRegisteredNodeIds[i].Identifier.Numeric;
OpcUa_Trace(OPCUA_TRACE_LEVEL_WARNING, " Identifier: 0x%08x\n", a_pRegisteredNodeIds[i].Identifier.Numeric);
break;
OpcUa_String_StrnCpy(&pClientContext->registeredNodeId[i].Identifier.String, &a_pRegisteredNodeIds[i].Identifier.String, OPCUA_STRING_LENDONTCARE);
OpcUa_Trace(OPCUA_TRACE_LEVEL_WARNING, " Identifier: %s\n", OpcUa_String_GetRawString(&a_pRegisteredNodeIds[i].Identifier.String));
break;
default:
OpcUa_Trace(OPCUA_TRACE_LEVEL_WARNING, "Sample_Write: Unsupported IdentifierType\n");
break;
}
}
}
else
{
pClientContext->State = State_Error;
}
}
else
{
OpcUa_Trace(OPCUA_TRACE_LEVEL_WARNING, "Sample_Register_CB failed (0x%08x)\n", a_pResponseHeader->ServiceResult);
pClientContext->State = State_Error;
}
}
OpcUa_StatusCode Sample_Register(UaClient_Session* a_pSession)
{
OpcUa_Int32 numNodesToRegister = 1;
OpcUa_NodeId nodesToRegister[1];
OpcUa_InitializeStatus(OpcUa_Module_Client, "Sample_Register");
OpcUa_NodeId_Initialize(&nodesToRegister[0]);
nodesToRegister[0].NamespaceIndex = 4;
OpcUa_String_StrnCpy(&nodesToRegister[0].Identifier.String, OpcUa_String_FromCString("Demo.Static.Scalar.Int32"), OPCUA_STRING_LENDONTCARE);
uStatus = UaClient_Session_BeginRegisterNodes(a_pSession, /* Session */
OpcUa_Null, /* ServiceSettings */
numNodesToRegister, /* NoOfNodesToRegister */
nodesToRegister, /* NodesToRegister */
Sample_Register_CB, /* Callback Function */
OpcUa_Null); /* Callback UserData */
OpcUa_GotoErrorIfBad(uStatus);
OpcUa_NodeId_Clear(&nodesToRegister[0]);
OpcUa_ReturnStatusCode;
OpcUa_BeginErrorHandling;
OpcUa_NodeId_Clear(&nodesToRegister[0]);
OpcUa_FinishErrorHandling;
}
OpcUa_Void Sample_Unregister_CB(const UaClient_Session *a_pSession,
OpcUa_ResponseHeader *a_pResponseHeader,
OpcUa_Void *a_pUserData)
{
SampleClientContext *pClientContext = a_pSession->pUserData;
OpcUa_ReferenceParameter(a_pUserData);
if (OpcUa_IsGood(a_pResponseHeader->ServiceResult))
{
OpcUa_Trace(OPCUA_TRACE_LEVEL_WARNING, "Sample_Unregister_CB: succeeded\n");
if (pClientContext->State == State_Unregister)
{
pClientContext->State = State_UnregisterDone;
}
else
{
pClientContext->State = State_Error;
}
}
else
{
OpcUa_Trace(OPCUA_TRACE_LEVEL_WARNING, "Sample_Unregister_CB failed (0x%08x)\n", a_pResponseHeader->ServiceResult);
pClientContext->State = State_Error;
}
}
OpcUa_StatusCode Sample_Unregister(UaClient_Session* a_pSession)
{
OpcUa_Int32 numNodesToUnregister = 1;
OpcUa_NodeId nodesToUnregister[1];
OpcUa_InitializeStatus(OpcUa_Module_Client, "Sample_Unregister");
OpcUa_NodeId_Initialize(&nodesToUnregister[0]);
nodesToUnregister[0].NamespaceIndex = 4;
OpcUa_String_StrnCpy(&nodesToUnregister[0].Identifier.String, OpcUa_String_FromCString("Demo.Static.Scalar.Int32"), OPCUA_STRING_LENDONTCARE);
uStatus = UaClient_Session_BeginUnregisterNodes(a_pSession, /* Session */
OpcUa_Null, /* ServiceSettings */
numNodesToUnregister, /* NoOfNodesToUnregister */
nodesToUnregister, /* NodesToUnregister */
Sample_Unregister_CB, /* Callback Function */
OpcUa_Null); /* Callback UserData */
OpcUa_GotoErrorIfBad(uStatus);
OpcUa_NodeId_Clear(&nodesToUnregister[0]);
OpcUa_ReturnStatusCode;
OpcUa_BeginErrorHandling;
OpcUa_NodeId_Clear(&nodesToUnregister[0]);
OpcUa_FinishErrorHandling;
}
/* The UaClient_Session BeginWrite callback. */
OpcUa_Void Sample_Write_CB(const UaClient_Session *a_pSession,
OpcUa_ResponseHeader *a_pResponseHeader,
OpcUa_Int32 a_NoOfResults,
OpcUa_StatusCode *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_Write_CB:\n");
for (i = 0; i < a_NoOfResults; i++)
{
OpcUa_Trace(OPCUA_TRACE_LEVEL_WARNING, " [%i]:\n", i);
OpcUa_Trace(OPCUA_TRACE_LEVEL_WARNING, " Status: 0x%08x\n", a_pResults[i]);
}
if (pClientContext->State == State_Write)
pClientContext->State = State_WriteDone;
else
pClientContext->State = State_Error;
}
else
{
OpcUa_Trace(OPCUA_TRACE_LEVEL_WARNING, "Sample_Write_CB failed (0x%08x)\n", a_pResponseHeader->ServiceResult);
pClientContext->State = State_Error;
}
}
OpcUa_StatusCode Sample_Write(UaClient_Session* a_pSession)
{
OpcUa_Int32 numNodesToWrite = 1;
OpcUa_WriteValue nodesToWrite[1];
SampleClientContext *pClientContext = a_pSession->pUserData;
OpcUa_InitializeStatus(OpcUa_Module_Client, "Sample_Write");
OpcUa_WriteValue_Initialize(&nodesToWrite[0]);
nodesToWrite[0].AttributeId = OpcUa_Attributes_Value;
nodesToWrite[0].NodeId.NamespaceIndex = pClientContext->registeredNodeId[0].NamespaceIndex;
nodesToWrite[0].NodeId.IdentifierType = pClientContext->registeredNodeId[0].IdentifierType;
switch (nodesToWrite[0].NodeId.IdentifierType)
{
nodesToWrite[0].NodeId.Identifier.Numeric = pClientContext->registeredNodeId[0].Identifier.Numeric;
break;
OpcUa_String_StrnCpy(&nodesToWrite[0].NodeId.Identifier.String, &pClientContext->registeredNodeId[0].Identifier.String, OPCUA_STRING_LENDONTCARE);
break;
default:
OpcUa_Trace(OPCUA_TRACE_LEVEL_WARNING, "Sample_Write: Unsupported IdentifierType\n");
break;
}
nodesToWrite[0].Value.Value.Datatype = OpcUaType_Int32;
nodesToWrite[0].Value.Value.ArrayType = OpcUa_VariantArrayType_Scalar;
nodesToWrite[0].Value.Value.Value.Int32 = 6789;
uStatus = UaClient_Session_BeginWrite(a_pSession, /* Session */
OpcUa_Null, /* ServiceSettings */
numNodesToWrite, /* NoOfNodesToWrite */
nodesToWrite, /* NodesToWrite */
Sample_Write_CB, /* Callback Function */
OpcUa_Null); /* Callback UserData */
OpcUa_GotoErrorIfBad(uStatus);
OpcUa_WriteValue_Clear(&nodesToWrite[0]);
OpcUa_ReturnStatusCode;
OpcUa_BeginErrorHandling;
OpcUa_WriteValue_Clear(&nodesToWrite[0]);
OpcUa_FinishErrorHandling;
}
/* Main OPC UA Client Loop. */
OpcUa_StatusCode ClientMain(void)
{
OpcUa_Int32 i;
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 = {0};
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);
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_Register(pSession);
OpcUa_GotoErrorIfBad(uStatus);
clientContext.State = State_Register;
break;
case State_RegisterDone:
uStatus = Sample_Write(pSession);
OpcUa_GotoErrorIfBad(uStatus);
clientContext.State = State_Write;
break;
case State_WriteDone:
uStatus = Sample_Unregister(pSession);
OpcUa_GotoErrorIfBad(uStatus);
clientContext.State = State_Unregister;
break;
case State_UnregisterDone:
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;
}
}
for (i = 0; i < clientContext.noOfRegisteredNodeIds; i++)
{
OpcUa_NodeId_Clear(&clientContext.registeredNodeId[i]);
}
pSession->pUserData = OpcUa_Null;
/* 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 (pSession)
pSession->pUserData = OpcUa_Null;
if (bClientInitialized != OpcUa_False)
{
for (i = 0; i < clientContext.noOfRegisteredNodeIds; i++)
{
OpcUa_NodeId_Clear(&clientContext.registeredNodeId[i]);
}
/* 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(void)
{
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;
}