forked from open62541/open62541
-
Notifications
You must be signed in to change notification settings - Fork 0
/
client_subscription_loop.c
141 lines (123 loc) · 6.18 KB
/
client_subscription_loop.c
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
/* 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 <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_ClientState clientState) {
switch(clientState) {
case UA_CLIENTSTATE_DISCONNECTED:
UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, "The client is disconnected");
break;
case UA_CLIENTSTATE_WAITING_FOR_ACK:
UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, "Waiting for ack");
break;
case UA_CLIENTSTATE_CONNECTED:
UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND,
"A TCP connection to the server is open");
break;
case UA_CLIENTSTATE_SECURECHANNEL:
UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND,
"A SecureChannel to the server is open");
break;
case UA_CLIENTSTATE_SESSION:{
UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, "A session with the server is open");
/* 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_MonitoredItemCreateRequest monRequest =
UA_MonitoredItemCreateRequest_default(UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_CURRENTTIME));
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_CLIENTSTATE_SESSION_RENEWED:
UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND,
"A session with the server is open (renewed)");
/* The session was renewed. We don't need to recreate the subscription. */
break;
case UA_CLIENTSTATE_SESSION_DISCONNECTED:
UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, "Session disconnected");
break;
}
return;
}
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 */
UA_sleep_ms(1000);
continue;
}
UA_Client_run_iterate(client, 1000);
};
/* Clean up */
UA_Client_delete(client); /* Disconnects the client internally */
return EXIT_SUCCESS;
}