forked from open62541/open62541
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathclient_subscription_loop.c
More file actions
158 lines (143 loc) · 6.53 KB
/
Copy pathclient_subscription_loop.c
File metadata and controls
158 lines (143 loc) · 6.53 KB
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
146
147
148
149
150
151
152
153
154
155
156
157
158
/* 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>
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_APPLICATION, "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_APPLICATION,
"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_APPLICATION,
"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_APPLICATION,
"Inactivity for subscription %u", subId);
}
static void
monCallback(UA_Client *client, void *userdata,
UA_UInt32 requestId, UA_CreateMonitoredItemsResponse *r) {
if(0 < r->resultsSize && r->results[0].statusCode == UA_STATUSCODE_GOOD) {
UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_APPLICATION,
"Monitoring UA_NS0ID_SERVER_SERVERSTATUS_CURRENTTIME', id %u",
r->results[0].monitoredItemId);
}
}
static void
createSubscriptionCallback(UA_Client *client, void *userdata,
UA_UInt32 requestId, UA_CreateSubscriptionResponse *r) {
if (r->subscriptionId == 0) {
UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_APPLICATION,
"response->subscriptionId == 0, %u", r->subscriptionId);
} else if (r->responseHeader.serviceResult != UA_STATUSCODE_GOOD) {
UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_APPLICATION,
"Create subscription failed, serviceResult %u",
r->responseHeader.serviceResult);
} else {
UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_APPLICATION,
"Create subscription succeeded, id %u", r->subscriptionId);
/* Add a MonitoredItem */
UA_NodeId currentTime =
UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_CURRENTTIME);
UA_CreateMonitoredItemsRequest req;
UA_CreateMonitoredItemsRequest_init(&req);
UA_MonitoredItemCreateRequest monRequest =
UA_MonitoredItemCreateRequest_default(currentTime);
req.itemsToCreate = &monRequest;
req.itemsToCreateSize = 1;
req.subscriptionId = r->subscriptionId;
UA_Client_DataChangeNotificationCallback dataChangeNotificationCallback[1] =
{ handler_currentTimeChanged };
UA_StatusCode retval =
UA_Client_MonitoredItems_createDataChanges_async(client, req, NULL,
dataChangeNotificationCallback, NULL,
monCallback, NULL, NULL);
if (retval != UA_STATUSCODE_GOOD)
UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_APPLICATION,
"UA_Client_MonitoredItems_createDataChanges_async ",
UA_StatusCode_name(retval));
}
}
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_APPLICATION,
"The client is disconnected");
break;
case UA_SECURECHANNELSTATE_HEL_SENT:
UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_APPLICATION,
"Waiting for ack");
break;
case UA_SECURECHANNELSTATE_OPN_SENT:
UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_APPLICATION,
"Waiting for OPN Response");
break;
case UA_SECURECHANNELSTATE_OPEN:
UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_APPLICATION,
"A SecureChannel to the server is open");
break;
default:
break;
}
switch(sessionState) {
case UA_SESSIONSTATE_ACTIVATED: {
UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_APPLICATION,
"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_StatusCode retval =
UA_Client_Subscriptions_create_async(client, request, NULL, NULL,
deleteSubscriptionCallback,
createSubscriptionCallback,
NULL, NULL);
if (retval != UA_STATUSCODE_GOOD)
UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_APPLICATION,
"UA_Client_Subscriptions_create_async ",
UA_StatusCode_name(retval));
}
break;
case UA_SESSIONSTATE_CLOSED:
UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_APPLICATION,
"Session disconnected");
break;
default:
break;
}
}
int main(void) {
UA_Client *client = UA_Client_new();
UA_ClientConfig *cc = UA_Client_getConfig(client);
/* Set callbacks */
cc->stateCallback = stateCallback;
cc->subscriptionInactivityCallback = subscriptionInactivityCallback;
/* Run the client until ctrl-c */
UA_Client_runUntilInterrupt(client);
/* Clean up */
UA_Client_delete(client); /* Disconnects the client internally */
return EXIT_SUCCESS;
}