Enable ZigBee eventing in Plugin Interface through to IoTivity.
[platform/upstream/iotivity.git] / plugins / samples / linux / IotivityandZigbeeClient.c
1 //******************************************************************
2 //
3 // Copyright 2015 Intel Mobile Communications GmbH All Rights Reserved.
4 //
5 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
6 //
7 // Licensed under the Apache License, Version 2.0 (the "License");
8 // you may not use this file except in compliance with the License.
9 // You may obtain a copy of the License at
10 //
11 //      http://www.apache.org/licenses/LICENSE-2.0
12 //
13 // Unless required by applicable law or agreed to in writing, software
14 // distributed under the License is distributed on an "AS IS" BASIS,
15 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 // See the License for the specific language governing permissions and
17 // limitations under the License.
18 //
19 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
20
21 // The source file for sample application "IotivityandZigbee".
22
23 // This application will utilize our interface (ie. zpluginz.h).
24 // The application may still be responsible for making any IoTivity API calls,
25 // except for resource-specific IoTivity APIs (ie. OCCreateResource(),
26 // OCDeleteResource(), EntityHandler()..etc.)
27
28 #include "IotivityandZigbeeClient.h"
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <string.h>
32 #include <signal.h>
33 #include <unistd.h>
34 #include "ocstack.h"
35 #include "logger.h"
36 #include "ocpayload.h"
37 #include "payload_logging.h"
38 #include "oic_string.h"
39
40 #define DEFAULT_CONTEXT_VALUE       (0x99)
41 #define MAX_QUERY_SIZE              (1024)
42 #define MAX_URI_SIZE                (256)
43 #define MAX_RESOURCE_TYPE_SIZE      (32)
44 #define MAX_RESOURCE_TYPE_LENGTH    (MAX_RESOURCE_TYPE_SIZE - 1)
45 #define MAX_RESOURCES_REMEMBERED    (10)
46
47 #define TAG "oc_zb_client"
48
49 static uint32_t countDiscoveredResources = 0;
50 static bool promptUser = false;
51
52 static OCDevAddr destinationAddress = {
53     .adapter = OC_ADAPTER_IP
54 };
55
56 typedef struct
57 {
58     char uri[MAX_URI_SIZE];
59     char resourceType[MAX_RESOURCE_TYPE_SIZE];
60
61 } DiscoveredResourceInfo;
62
63 static DiscoveredResourceInfo g_discoveredResources[MAX_RESOURCES_REMEMBERED];
64
65 static void PrintTestCases()
66 {
67     printf("\nTest Cases:\n");
68     printf ("\n\t%d : Quit    %d: GET    %d: Build PUT payload %d: OBSERVE\n\n",
69             TEST_QUIT, TEST_GET, TEST_CUSTOM_PUT, TEST_OBSERVE);
70     printf ("\t%d : Turn binary switch for light ON\n", TEST_TURN_SWITCH_ON);
71     printf ("\t%d : Turn binary switch for light OFF\n", TEST_TURN_SWITCH_OFF);
72     printf ("\t%d : Change light brightness\n", TEST_SET_LIGHT_BRIGHTNESS);
73     printf ("\n\t%d : Check for observation updates.\n", TEST_CYCLE);
74 }
75
76 static void PrintResources ()
77 {
78     printf("\nResources: \n");
79     for (uint32_t i = 0; i < countDiscoveredResources; ++i)
80     {
81         printf("\t# : %u \t URI: %s \t Type:%s\n", i, g_discoveredResources[i].uri,
82             g_discoveredResources[i].resourceType);
83     }
84 }
85
86 void rememberDiscoveredResources (OCClientResponse *clientResponse)
87 {
88     OCResourcePayload* itr = NULL;
89     if(!(OCDiscoveryPayload*)clientResponse->payload)
90     {
91         OC_LOG (INFO, TAG, "No resources discovered.");
92         return;
93     }
94
95     itr = ((OCDiscoveryPayload*)(clientResponse->payload))->resources;
96
97     while(itr && itr != itr->next)
98     {
99         if (countDiscoveredResources == MAX_RESOURCES_REMEMBERED)
100         {
101             OC_LOG_V (INFO, TAG, "Only remembering %u resources. Ignoring rest.",
102                 MAX_RESOURCES_REMEMBERED);
103             break;
104         }
105         strncpy (g_discoveredResources[countDiscoveredResources].uri,
106             itr->uri, MAX_URI_SIZE - 1);
107         strncpy (g_discoveredResources[countDiscoveredResources].resourceType,
108             itr->types->value, MAX_RESOURCE_TYPE_SIZE - 1);
109         ++countDiscoveredResources;
110         itr = itr->next;
111     }
112 }
113
114 OCStackResult InvokeOCDoResource (const char *query,
115                                  OCPayload *payload,
116                                  OCMethod method,
117                                  OCClientResponseHandler cb)
118 {
119     OCCallbackData cbData = {
120                                 .context = (void*)DEFAULT_CONTEXT_VALUE,
121                                 .cb = cb
122                             };
123
124     OCDoHandle handle = NULL;
125
126     OCStackResult ret = OCDoResource(&handle, method, query, &destinationAddress,
127                     payload, CT_ADAPTER_IP, OC_LOW_QOS, &cbData, NULL, 0);
128
129     if (ret != OC_STACK_OK)
130     {
131         promptUser = true;
132         OC_LOG_V(ERROR, TAG, "OCDoResource returns error %d with method %d", ret, method);
133     }
134     return ret;
135 }
136
137 OCStackApplicationResult responseCallbacks(void* ctx,
138                 OCDoHandle handle,
139                 OCClientResponse * clientResponse)
140 {
141     (void)handle;
142     (void) ctx;
143     if(clientResponse == NULL)
144     {
145         OC_LOG(INFO, TAG, "responseCallbacks received NULL clientResponse");
146         return   OC_STACK_DELETE_TRANSACTION;
147     }
148
149     OC_LOG_PAYLOAD(INFO, clientResponse->payload);
150     promptUser = true;
151     return OC_STACK_KEEP_TRANSACTION;
152 }
153
154 int InitGetRequest (const char *resourceUri)
155 {
156     OC_LOG_V(INFO, TAG, "Executing %s for resource: %s", __func__, resourceUri);
157     return (InvokeOCDoResource(resourceUri, NULL, OC_REST_GET, responseCallbacks));
158 }
159
160 int InitPutRequest (const char *resourceUri, OCPayload* payload)
161 {
162     OC_LOG_V(INFO, TAG, "Executing %s for resource: %s", __func__, resourceUri);
163     return (InvokeOCDoResource(resourceUri, payload, OC_REST_PUT, responseCallbacks));
164 }
165
166 int InitObserveRequest(const char *resourceUri)
167 {
168     OC_LOG_V(INFO, TAG, "Executing %s for resource: %s", __func__, resourceUri);
169     return (InvokeOCDoResource(resourceUri, NULL, OC_REST_OBSERVE, responseCallbacks));
170 }
171
172 OCPayload * getSwitchStatePayload (bool state)
173 {
174     OCRepPayload* payload = OCRepPayloadCreate();
175     if(!payload)
176     {
177        OC_LOG (ERROR, TAG, "Failed to create payload object");
178        exit(1);
179     }
180     OCRepPayloadSetPropBool(payload, "value", state);
181     return (OCPayload*) payload;
182 }
183
184 OCPayload* getChangeLevelPayload(uint32_t level)
185 {
186     OCRepPayload* payload = OCRepPayloadCreate();
187     if(!payload)
188     {
189         OC_LOG (ERROR, TAG, "Failed to create payload object");
190         exit(1);
191     }
192
193     OC_LOG_V(INFO, TAG, "Setting level to : %u", level);
194     OCRepPayloadSetPropInt(payload, "dimmingSetting", level);
195     return (OCPayload*) payload;
196 }
197
198 OCStackApplicationResult discoveryReqCB(void* ctx, OCDoHandle handle,
199                             OCClientResponse * clientResponse)
200 {
201     (void)handle;
202     (void) ctx;
203     if (!clientResponse)
204     {
205         OC_LOG(INFO, TAG, "Discovery response is NULL");
206         return OC_STACK_KEEP_TRANSACTION;
207     }
208
209     OC_LOG_PAYLOAD(INFO, clientResponse->payload);
210     OC_LOG_V(INFO, TAG, "Discovered @ %s:%d", clientResponse->devAddr.addr,
211                                 clientResponse->devAddr.port);
212
213     destinationAddress = clientResponse->devAddr;
214
215     rememberDiscoveredResources (clientResponse);
216
217     promptUser = true;
218
219     return OC_STACK_KEEP_TRANSACTION;
220 }
221
222 OCPayload* getCustomPutPayload ()
223 {
224     OCRepPayload* payload = OCRepPayloadCreate();
225     if(!payload)
226     {
227         OC_LOG (ERROR, TAG, "Failed to create payload object");
228         exit(1);
229     }
230
231     char key[100] = {0};
232     char input[100] = {0};
233     char valueString[100] = {0};
234     int value = 0;
235     double valueDouble = 0.0;
236     int type = -1;
237
238     printf("\nEnter key value pairs as:\t<type(int)> <key> <value>\n");
239     printf("\nType: 0:bool \t 1:int \t 2:double\n");
240     while (true)
241     {
242         printf ("Blank line / press ENTER to finish :");
243         char *ret = fgets (input, sizeof(input), stdin);
244         (void) ret;
245         int inCount = sscanf (input, "%d %s %s", &type, key, valueString);
246
247         if (inCount <= 0)
248         {
249             break;
250         }
251         if (inCount != 3)
252         {
253             printf("Invalid input\n");
254             OCRepPayloadDestroy (payload);
255             promptUser = true;
256             return NULL;
257         }
258
259         if (type == 0)  //bool
260         {
261             if (sscanf(valueString, "%d", &value) == 1)
262             {
263                 OCRepPayloadSetPropBool(payload, key, value);
264             }
265         }
266         else if (type == 1)  //int
267         {
268             if (sscanf(valueString, "%d", &value) == 1)
269             {
270                 OCRepPayloadSetPropInt(payload, key, value);
271             }
272         }
273         else if (type == 2)  //double
274         {
275             if (sscanf(valueString, "%lf", &valueDouble) == 1)
276             {
277                 OCRepPayloadSetPropDouble(payload, key, valueDouble);
278             }
279         }
280         else
281         {
282             OC_LOG(ERROR, TAG, "Invalid entry. Stopping accepting key-values");
283             OCRepPayloadDestroy (payload);
284             promptUser = true;
285             return NULL;
286         }
287         memset (input, 0, sizeof (input));
288         memset (key, 0, sizeof (key));
289         memset (valueString, 0, sizeof (valueString));
290     }
291
292     if (payload->values)
293     {
294         return (OCPayload *) payload;
295     }
296     else
297     {
298         OCRepPayloadDestroy (payload);
299         return NULL;
300     }
301 }
302
303 void processUserInput (int resourceNo, int testCase)
304 {
305     switch (testCase)
306     {
307         case TEST_GET:
308             InitGetRequest (g_discoveredResources[resourceNo].uri);
309             break;
310
311         case TEST_CUSTOM_PUT:
312         {
313             OCPayload *payload = getCustomPutPayload ();
314             if (payload)
315             {
316                 InitPutRequest (g_discoveredResources[resourceNo].uri, payload);
317             }
318             else
319             {
320                 OC_LOG(ERROR, TAG, "Error creating payload. Not sending PUT request");
321                 promptUser = true;
322             }
323             break;
324         }
325
326         case TEST_OBSERVE:
327             InitObserveRequest (g_discoveredResources[resourceNo].uri);
328             break;
329
330         case TEST_TURN_SWITCH_ON:
331             InitPutRequest (g_discoveredResources[resourceNo].uri, getSwitchStatePayload (true));
332             break;
333
334         case TEST_TURN_SWITCH_OFF:
335             InitPutRequest (g_discoveredResources[resourceNo].uri, getSwitchStatePayload (false));
336             break;
337
338         case TEST_SET_LIGHT_BRIGHTNESS:
339             printf ("Change bulb level [0-100] to ? :");
340             int level = 0;
341             if (scanf ("%d", &level) > 0)
342             {
343                 InitPutRequest (g_discoveredResources[resourceNo].uri,
344                     getChangeLevelPayload (level));
345             }
346             else
347             {
348                 printf("Invalid value\n");
349                 promptUser = true;
350             }
351             break;
352
353         case TEST_CYCLE:
354             OCProcess();
355             promptUser = true;
356             break;
357
358         case TEST_QUIT:
359             raise (SIGINT);
360             break;
361
362         default:
363             promptUser = true;
364             OC_LOG(INFO, TAG, "Invalid test case");
365     }
366 }
367
368 void getTestCaseFromUser ()
369 {
370     PrintResources ();
371     PrintTestCases ();
372     printf("\nUsage:<resource number> <test case> :");
373
374     char input[10] = {0};
375     uint32_t resourceNo = 0;
376     int testCase = 0;
377
378     char * ret = fgets (input, sizeof(input), stdin);
379     (void) ret;
380     int inCount = sscanf (input, "%d %d", &resourceNo, &testCase);
381
382     if (inCount != 2)
383     {
384         printf("Invalid input\n");
385         promptUser = true;
386         return;
387     }
388     if (resourceNo >= countDiscoveredResources)
389     {
390         printf("Invalid resource\n");
391         promptUser = true;
392         return;
393     }
394     processUserInput (resourceNo, testCase);
395 }
396
397 OCStackResult DiscoverResources ()
398 {
399     OCCallbackData cbData = {
400                                 .context = (void*)DEFAULT_CONTEXT_VALUE,
401                                 .cb = discoveryReqCB
402                             };
403
404     OCStackResult ret = OCDoResource(NULL, OC_REST_DISCOVER, OC_RSRVD_WELL_KNOWN_URI,
405                         0, 0, CT_ADAPTER_IP,OC_LOW_QOS, &cbData, NULL, 0);
406
407     if (ret != OC_STACK_OK)
408     {
409         OC_LOG(ERROR, TAG, "OCDoResource error");
410     }
411     return ret;
412 }
413
414 bool processSignal(bool set)
415 {
416     static sig_atomic_t signal = 0;
417     if (set)
418     {
419         signal = 1;
420     }
421     return signal == 1;
422 }
423
424 void processCancel(int signal)
425 {
426     if(signal == SIGINT)
427     {
428         processSignal(true);
429     }
430 }
431
432 int main(int argc, char* argv[])
433 {
434     (void) argc;
435     (void) argv;
436     OCStackResult result;
437     OC_LOG(INFO, TAG, "Initializing IoTivity...");
438
439     result = OCInit(NULL, 0, OC_CLIENT);
440     if (result != OC_STACK_OK)
441     {
442         OC_LOG_V(ERROR, TAG, "OCInit Failed %d", result);
443         return -1;
444     }
445
446     DiscoverResources ();
447
448     if (signal(SIGINT, processCancel) == SIG_ERR)
449     {
450         OC_LOG(ERROR, TAG, "Unable to catch SIGINT, terminating...");
451     }
452     else
453     {
454         OC_LOG(INFO, TAG, "Press Ctrl-C to terminate");
455         // Loop until sigint
456         while (!processSignal(false) && result == OC_STACK_OK)
457         {
458             result = OCProcess();
459             if (result != OC_STACK_OK)
460             {
461                 OC_LOG_V(ERROR, TAG, "OCProcess Failed: %d", result);
462                 break;
463             }
464
465             if (promptUser)
466             {
467                 promptUser = false;
468                 getTestCaseFromUser ();
469             }
470         }
471     }
472
473     OC_LOG(INFO, TAG, "Stopping IoTivity...");
474     result = OCStop();
475     if (result != OC_STACK_OK)
476     {
477         OC_LOG_V(ERROR, TAG, "OCStop Failed: %d", result);
478     }
479
480     return 0;
481 }
482