1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145
|
/* This work is licensed under a Creative Commons CCZero 1.0 Universal License.
* See http://creativecommons.org/publicdomain/zero/1.0/ for more information. */
/**
* Client disconnect handling
* --------------------------
* This example shows you how to handle a client disconnect, e.g., if the server
* is shut down while the client is connected. You just need to call connect
* again and the client will automatically reconnect.
*
* This example is very similar to the tutorial_client_firststeps.c. */
#include <open62541/client_config_default.h>
#include <open62541/client_subscriptions.h>
#include <open62541/plugin/log_stdout.h>
#include "common.h"
#include <signal.h>
#include <stdlib.h>
UA_Boolean running = true;
static void stopHandler(int sign) {
UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, "Received Ctrl-C");
running = 0;
}
static void
handler_currentTimeChanged(UA_Client *client, UA_UInt32 subId, void *subContext,
UA_UInt32 monId, void *monContext, UA_DataValue *value) {
UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, "currentTime has changed!");
if(UA_Variant_hasScalarType(&value->value, &UA_TYPES[UA_TYPES_DATETIME])) {
UA_DateTime raw_date = *(UA_DateTime *) value->value.data;
UA_DateTimeStruct dts = UA_DateTime_toStruct(raw_date);
UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND,
"date is: %02u-%02u-%04u %02u:%02u:%02u.%03u",
dts.day, dts.month, dts.year, dts.hour, dts.min, dts.sec, dts.milliSec);
}
}
static void
deleteSubscriptionCallback(UA_Client *client, UA_UInt32 subscriptionId, void *subscriptionContext) {
UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND,
"Subscription Id %u was deleted", subscriptionId);
}
static void
subscriptionInactivityCallback (UA_Client *client, UA_UInt32 subId, void *subContext) {
UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, "Inactivity for subscription %u", subId);
}
static void
stateCallback(UA_Client *client, UA_SecureChannelState channelState,
UA_SessionState sessionState, UA_StatusCode recoveryStatus) {
switch(channelState) {
case UA_SECURECHANNELSTATE_CLOSED:
UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, "The client is disconnected");
break;
case UA_SECURECHANNELSTATE_HEL_SENT:
UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, "Waiting for ack");
break;
case UA_SECURECHANNELSTATE_OPN_SENT:
UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, "Waiting for OPN Response");
break;
case UA_SECURECHANNELSTATE_OPEN:
UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, "A SecureChannel to the server is open");
break;
default:
break;
}
switch(sessionState) {
case UA_SESSIONSTATE_ACTIVATED: {
UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, "A session with the server is activated");
/* A new session was created. We need to create the subscription. */
/* Create a subscription */
UA_CreateSubscriptionRequest request = UA_CreateSubscriptionRequest_default();
UA_CreateSubscriptionResponse response =
UA_Client_Subscriptions_create(client, request, NULL, NULL, deleteSubscriptionCallback);
if(response.responseHeader.serviceResult == UA_STATUSCODE_GOOD)
UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND,
"Create subscription succeeded, id %u",
response.subscriptionId);
else
return;
/* Add a MonitoredItem */
UA_NodeId currentTimeNode =
UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_CURRENTTIME);
UA_MonitoredItemCreateRequest monRequest =
UA_MonitoredItemCreateRequest_default(currentTimeNode);
UA_MonitoredItemCreateResult monResponse =
UA_Client_MonitoredItems_createDataChange(client, response.subscriptionId,
UA_TIMESTAMPSTORETURN_BOTH, monRequest,
NULL, handler_currentTimeChanged, NULL);
if(monResponse.statusCode == UA_STATUSCODE_GOOD)
UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND,
"Monitoring UA_NS0ID_SERVER_SERVERSTATUS_CURRENTTIME', id %u",
monResponse.monitoredItemId);
}
break;
case UA_SESSIONSTATE_CLOSED:
UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, "Session disconnected");
break;
default:
break;
}
}
int
main(void) {
signal(SIGINT, stopHandler); /* catches ctrl-c */
UA_Client *client = UA_Client_new();
UA_ClientConfig *cc = UA_Client_getConfig(client);
UA_ClientConfig_setDefault(cc);
/* Set stateCallback */
cc->stateCallback = stateCallback;
cc->subscriptionInactivityCallback = subscriptionInactivityCallback;
/* Endless loop runAsync */
while(running) {
/* if already connected, this will return GOOD and do nothing */
/* if the connection is closed/errored, the connection will be reset and then reconnected */
/* Alternatively you can also use UA_Client_getState to get the current state */
UA_StatusCode retval = UA_Client_connect(client, "opc.tcp://localhost:4840");
if(retval != UA_STATUSCODE_GOOD) {
UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND,
"Not connected. Retrying to connect in 1 second");
/* The connect may timeout after 1 second (see above) or it may fail immediately on network errors */
/* E.g. name resolution errors or unreachable network. Thus there should be a small sleep here */
sleep_ms(1000);
continue;
}
UA_Client_run_iterate(client, 1000);
};
/* Clean up */
UA_Client_delete(client); /* Disconnects the client internally */
return EXIT_SUCCESS;
}
|