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_errorhandling.h>
#include <opcua_memory.h>
#include <opcua_string.h>
#include <uaclient_module.h>
#include <uaclient_session.h>
#include <uabase_utilities.h>
#include "samplesubscription.h"
/*============================================================================
* Includes End
*===========================================================================*/
#define UACLIENT_APPLICATION_NAME "UaSdkC - Client - Lesson06"
#define UACLIENT_APPLICATION_URI "urn:UnifiedAutomation:UaSdkC:Client:Lesson06"
#define UACLIENT_PRODUCT_URI "urn:UnifiedAutomation:UaSdkC:Client:Lesson06"
/* Server configuration used by this client */
#define SERVER_ENDPOINT_URL "opc.tcp://localhost:48020"
typedef enum _SampleStateMachine
{
State_Idle,
State_Connect,
State_Connected,
State_Subscription,
State_MethodCall,
State_MethodCallDone,
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 */
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;
}
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_Subscription)
{
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)
{
const char *pServiceType = "INVALID";
OpcUa_Boolean bRet = OpcUa_False;
OpcUa_ReferenceParameter(a_pSession);
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");
if (a_overridable)
{
bRet = OpcUa_True;
}
return bRet;
}
/* The UaClient_Session Method Call callback. */
OpcUa_Void Sample_MethodCall_CB(const UaClient_Session *a_pSession,
OpcUa_ResponseHeader *a_pResponseHeader,
OpcUa_DiagnosticInfo *a_pDiagnosticInfo,
OpcUa_Void *a_pUserData)
{
SampleClientContext *pClientContext = a_pSession->pUserData;
OpcUa_ReferenceParameter(a_pResult);
OpcUa_ReferenceParameter(a_pDiagnosticInfo);
OpcUa_ReferenceParameter(a_pUserData);
if (OpcUa_IsGood(a_pResponseHeader->ServiceResult))
{
OpcUa_Trace(OPCUA_TRACE_LEVEL_WARNING, "Sample_MethodCall_CB succeeded\n");
if (pClientContext->State == State_MethodCall)
{
pClientContext->State = State_MethodCallDone;
}
else
{
pClientContext->State = State_Error;
}
}
else
{
OpcUa_Trace(OPCUA_TRACE_LEVEL_WARNING, "Sample_MethodCall_CB failed (0x%08x)\n", a_pResponseHeader->ServiceResult);
pClientContext->State = State_Error;
}
}
OpcUa_StatusCode Sample_MethodCall(UaClient_Session *a_pSession)
{
OpcUa_CallMethodRequest callMethodRequest;
OpcUa_InitializeStatus(OpcUa_Module_Client, "Sample_MethodCall");
OpcUa_CallMethodRequest_Initialize(&callMethodRequest);
/* Fill in details of SetSwitchState Method of MyCustomMachine Object included in lesson05 server*/
UaBase_CreateNumericNodeIdEx(&callMethodRequest.ObjectId, 15, 4);
UaBase_CreateNumericNodeIdEx(&callMethodRequest.MethodId, 19, 4);
callMethodRequest.InputArguments = (OpcUa_Variant*)OpcUa_Alloc(sizeof(OpcUa_Variant));
OpcUa_GotoErrorIfAllocFailed(callMethodRequest.InputArguments);
callMethodRequest.NoOfInputArguments = 1;
OpcUa_Variant_Initialize(&callMethodRequest.InputArguments[0]);
callMethodRequest.InputArguments[0].ArrayType = OpcUa_VariantArrayType_Scalar;
callMethodRequest.InputArguments[0].Datatype = OpcUaType_Boolean;
callMethodRequest.InputArguments[0].Value.Boolean = OpcUa_True;
uStatus = UaClient_Session_BeginCall(a_pSession,
OpcUa_Null,
&callMethodRequest,
Sample_MethodCall_CB,
OpcUa_Null);
OpcUa_GotoErrorIfBad(uStatus);
OpcUa_CallMethodRequest_Clear(&callMethodRequest);
OpcUa_ReturnStatusCode;
OpcUa_BeginErrorHandling;
OpcUa_CallMethodRequest_Clear(&callMethodRequest);
OpcUa_FinishErrorHandling;
}
/* Main OPC UA Client Loop. */
OpcUa_StatusCode ClientMain(void)
{
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;
SampleSubscription *pSampleSubscription = OpcUa_Null;
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);
/* Enable automatic reconnect */
pSession->AutomaticReconnect = OpcUa_True;
/* 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:
/* create the sample subscription context */
pSampleSubscription = SampleSubscription_Create(pSession);
OpcUa_GotoErrorIfArgumentNull(pSampleSubscription);
/* create the server-side subscription */
uStatus = SampleSubscription_CreateSubscription(pSampleSubscription);
OpcUa_GotoErrorIfBad(uStatus);
clientContext.State = State_Subscription;
break;
case State_Subscription:
switch (pSampleSubscription->State)
{
case State_SampleSubscription_SubscriptionCreateDone:
/* create monitored item */
uStatus = SampleSubscription_CreateMonitoredItem(pSampleSubscription);
OpcUa_GotoErrorIfBad(uStatus);
break;
case State_SampleSubscription_MonitoredItemCreateDone:
/* call method */
uStatus = Sample_MethodCall(pSession);
OpcUa_GotoErrorIfBad(uStatus);
pSampleSubscription->State = State_SampleSubscription_WaitForNewEvent;
clientContext.State = State_MethodCall;
break;
case State_SampleSubscription_NewEventReceived:
/* delete the monitored item */
uStatus = SampleSubscription_DeleteMonitoredItem(pSampleSubscription);
OpcUa_GotoErrorIfBad(uStatus);
break;
case State_SampleSubscription_MonitoredItemDeleteDone:
/* delete the subscription */
uStatus = SampleSubscription_DeleteSubscription(pSampleSubscription);
OpcUa_GotoErrorIfBad(uStatus);
break;
case State_SampleSubscription_SubscriptionDeleteDone:
/* delete the sample subscription structure */
SampleSubscription_Delete(&pSampleSubscription);
pSampleSubscription = OpcUa_Null;
/* disconnect from the server */
uStatus = UaClient_Session_BeginDisconnect(pSession, OpcUa_False);
OpcUa_GotoErrorIfBad(uStatus);
/* exit the subscription state */
clientContext.State = State_Disconnect;
break;
case State_SampleSubscription_Error:
OpcUa_Trace(OPCUA_TRACE_LEVEL_WARNING, "An error occured. Terminating now.\n");
bComplete = OpcUa_True;
break;
default:
break;
}
break;
case State_MethodCallDone:
clientContext.State = State_Subscription;
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;
}
}
/******************************************************************************/
SampleSubscription_Delete(&pSampleSubscription);
/* 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(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;
}