Merge branch '1.1-rel'
[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 <errno.h>
35 #include "ocstack.h"
36 #include "logger.h"
37 #include "ocpayload.h"
38 #include "payload_logging.h"
39 #include "oic_string.h"
40
41 #define DEFAULT_CONTEXT_VALUE       (0x99)
42 #define MAX_QUERY_SIZE              (1024)
43 #define MAX_URI_SIZE                (256)
44 #define MAX_RESOURCE_TYPE_SIZE      (32)
45 #define MAX_RESOURCE_TYPE_LENGTH    (MAX_RESOURCE_TYPE_SIZE - 1)
46 #define MAX_RESOURCES_REMEMBERED    (100)
47
48 #define MAX_USER_INPUT              (100)
49
50 #define TAG "oc_zb_client"
51
52 static uint32_t countDiscoveredResources = 0;
53 static bool promptUser = false;
54
55 static OCDevAddr destinationAddress = {
56     .adapter = OC_ADAPTER_IP
57 };
58
59 typedef struct
60 {
61     char uri[MAX_URI_SIZE];
62     char resourceType[MAX_RESOURCE_TYPE_SIZE];
63
64 } DiscoveredResourceInfo;
65
66 static DiscoveredResourceInfo g_discoveredResources[MAX_RESOURCES_REMEMBERED];
67
68 static void PrintTestCases()
69 {
70     printf("\nTest Cases:\n");
71     printf("\n\t%d : Quit    %d: GET    %d: Build PUT payload %d: OBSERVE\n\n",
72             TEST_QUIT, TEST_GET, TEST_CUSTOM_PUT, TEST_OBSERVE);
73     printf("\t%d : Turn binary switch for light ON\n", TEST_TURN_SWITCH_ON);
74     printf("\t%d : Turn binary switch for light OFF\n", TEST_TURN_SWITCH_OFF);
75     printf("\t%d : Change light brightness\n", TEST_SET_LIGHT_BRIGHTNESS);
76     printf("\t%d : Change light temperature\n", TEST_SET_LIGHT_TEMPERATURE);
77     printf("\n\t%d : Check for observation updates.\n", TEST_CYCLE);
78 }
79
80 static void PrintResources()
81 {
82     printf("\nResources: \n");
83     for(uint32_t i = 0; i < countDiscoveredResources; ++i)
84     {
85         printf("\t# : %u \t URI: %s \t Type:%s\n", i, g_discoveredResources[i].uri,
86             g_discoveredResources[i].resourceType);
87     }
88 }
89
90 void rememberDiscoveredResources(OCClientResponse *clientResponse)
91 {
92     OCResourcePayload* itr = NULL;
93     if (!(OCDiscoveryPayload*)clientResponse->payload)
94     {
95         OIC_LOG(INFO, TAG, "No resources discovered.");
96         return;
97     }
98
99     itr = ((OCDiscoveryPayload*)(clientResponse->payload))->resources;
100
101     while (itr && itr != itr->next)
102     {
103         if (countDiscoveredResources == MAX_RESOURCES_REMEMBERED)
104         {
105             OIC_LOG_V(INFO, TAG, "Only remembering %u resources. Ignoring rest.",
106                 MAX_RESOURCES_REMEMBERED);
107             break;
108         }
109         strncpy(g_discoveredResources[countDiscoveredResources].uri,
110             itr->uri, MAX_URI_SIZE - 1);
111         strncpy(g_discoveredResources[countDiscoveredResources].resourceType,
112             itr->types->value, MAX_RESOURCE_TYPE_SIZE - 1);
113         ++countDiscoveredResources;
114         itr = itr->next;
115     }
116 }
117
118 OCStackResult InvokeOCDoResource(const char *query,
119                                  OCPayload *payload,
120                                  OCMethod method,
121                                  OCClientResponseHandler cb)
122 {
123     OCCallbackData cbData = {
124                                 .context = (void*)DEFAULT_CONTEXT_VALUE,
125                                 .cb = cb
126                             };
127
128     OCDoHandle handle = NULL;
129
130     OCStackResult ret = OCDoResource(&handle, method, query, &destinationAddress,
131                     payload, CT_ADAPTER_IP, OC_LOW_QOS, &cbData, NULL, 0);
132
133     if (ret != OC_STACK_OK)
134     {
135         promptUser = true;
136         OIC_LOG_V(ERROR, TAG, "OCDoResource returns error %d with method %d", ret, method);
137     }
138     return ret;
139 }
140
141 OCStackApplicationResult responseCallbacks(void* ctx,
142                 OCDoHandle handle,
143                 OCClientResponse * clientResponse)
144 {
145     (void)handle;
146     (void) ctx;
147     if (clientResponse == NULL)
148     {
149         OIC_LOG(INFO, TAG, "responseCallbacks received NULL clientResponse");
150         return   OC_STACK_DELETE_TRANSACTION;
151     }
152
153     OIC_LOG_PAYLOAD(INFO, clientResponse->payload);
154     promptUser = true;
155     return OC_STACK_KEEP_TRANSACTION;
156 }
157
158 int InitGetRequest(const char *resourceUri)
159 {
160     OIC_LOG_V(INFO, TAG, "Executing %s for resource: %s", __func__, resourceUri);
161     return (InvokeOCDoResource(resourceUri, NULL, OC_REST_GET, responseCallbacks));
162 }
163
164 int InitPutRequest(const char *resourceUri, OCPayload* payload)
165 {
166     OIC_LOG_V(INFO, TAG, "Executing %s for resource: %s", __func__, resourceUri);
167     return (InvokeOCDoResource(resourceUri, payload, OC_REST_PUT, responseCallbacks));
168 }
169
170 int InitObserveRequest(const char *resourceUri)
171 {
172     OIC_LOG_V(INFO, TAG, "Executing %s for resource: %s", __func__, resourceUri);
173     return (InvokeOCDoResource(resourceUri, NULL, OC_REST_OBSERVE, responseCallbacks));
174 }
175
176 OCPayload * getSwitchStatePayload(bool state)
177 {
178     OCRepPayload* payload = OCRepPayloadCreate();
179     if (!payload)
180     {
181        OIC_LOG(ERROR, TAG, "Failed to create payload object");
182        exit(1);
183     }
184     OCRepPayloadSetPropBool(payload, "value", state);
185     return (OCPayload*) payload;
186 }
187
188 OCPayload* getChangeBulbTempLevelPayload(uint32_t level)
189 {
190     OCRepPayload* payload = OCRepPayloadCreate();
191     if (!payload)
192     {
193         OIC_LOG(ERROR, TAG, "Failed to create payload object");
194         exit(1);
195     }
196
197     OIC_LOG_V(INFO, TAG, "Setting level to : %u", level);
198     char value[4] = "";
199     errno = 0;
200     size_t sizeValue = sizeof(value);
201     int strRet = snprintf(value, sizeValue, "%d", level);
202
203     if (strRet < 0 || strRet >= (int)sizeValue)
204     {
205         OIC_LOG_V(ERROR, TAG, "Failed to parse string due to errno: %d", errno);
206         exit(1);
207     }
208     OCRepPayloadSetPropString(payload, "colourspacevalue", value);
209     return (OCPayload*) payload;
210 }
211
212 OCPayload* getChangeDimLevelPayload(uint32_t level)
213 {
214     OCRepPayload* payload = OCRepPayloadCreate();
215     if (!payload)
216     {
217         OIC_LOG(ERROR, TAG, "Failed to create payload object");
218         exit(1);
219     }
220
221     OIC_LOG_V(INFO, TAG, "Setting level to : %u", level);
222     OCRepPayloadSetPropInt(payload, "dimmingSetting", level);
223     return (OCPayload*) payload;
224 }
225
226 OCStackApplicationResult discoveryReqCB(void* ctx, OCDoHandle handle,
227                             OCClientResponse * clientResponse)
228 {
229     (void)handle;
230     (void) ctx;
231     if (!clientResponse)
232     {
233         OIC_LOG(INFO, TAG, "Discovery response is NULL");
234         return OC_STACK_KEEP_TRANSACTION;
235     }
236
237     OIC_LOG_PAYLOAD(INFO, clientResponse->payload);
238     OIC_LOG_V(INFO, TAG, "Discovered @ %s:%d", clientResponse->devAddr.addr,
239                                 clientResponse->devAddr.port);
240
241     destinationAddress = clientResponse->devAddr;
242
243     rememberDiscoveredResources(clientResponse);
244
245     promptUser = true;
246
247     return OC_STACK_KEEP_TRANSACTION;
248 }
249
250 OCPayload* getCustomPutPayload()
251 {
252     OCRepPayload* payload = OCRepPayloadCreate();
253     if (!payload)
254     {
255         OIC_LOG(ERROR, TAG, "Failed to create payload object");
256         exit(1);
257     }
258
259     char key[MAX_USER_INPUT] = {0};
260     char input[MAX_USER_INPUT] = {0};
261     char valueString[MAX_USER_INPUT] = {0};
262     int value = 0;
263     double valueDouble = 0.0;
264     int type = -1;
265
266     printf("\nEnter key value pairs as:\t<type(int)> <key> <value>\n");
267     printf("\nType: 0:bool \t 1:int \t 2:double\n");
268     while (true)
269     {
270         printf("Blank line / press ENTER to finish :");
271         char *ret = fgets(input, sizeof(input), stdin);
272         (void) ret;
273         int inCount = sscanf(input, "%d %s %s", &type, key, valueString);
274
275         if (inCount <= 0)
276         {
277             break;
278         }
279         if (inCount != 3)
280         {
281             printf("Invalid input\n");
282             OCRepPayloadDestroy(payload);
283             promptUser = true;
284             return NULL;
285         }
286
287         if (type == 0)  //bool
288         {
289             if (sscanf(valueString, "%d", &value) == 1)
290             {
291                 OCRepPayloadSetPropBool(payload, key, value);
292             }
293         }
294         else if (type == 1)  //int
295         {
296             if (sscanf(valueString, "%d", &value) == 1)
297             {
298                 OCRepPayloadSetPropInt(payload, key, value);
299             }
300         }
301         else if (type == 2)  //double
302         {
303             if (sscanf(valueString, "%lf", &valueDouble) == 1)
304             {
305                 OCRepPayloadSetPropDouble(payload, key, valueDouble);
306             }
307         }
308         else
309         {
310             OIC_LOG(ERROR, TAG, "Invalid entry. Stopping accepting key-values");
311             OCRepPayloadDestroy(payload);
312             promptUser = true;
313             return NULL;
314         }
315         memset(input, 0, sizeof (input));
316         memset(key, 0, sizeof (key));
317         memset(valueString, 0, sizeof (valueString));
318     }
319
320     if (payload->values)
321     {
322         return (OCPayload *) payload;
323     }
324     else
325     {
326         OCRepPayloadDestroy(payload);
327         return NULL;
328     }
329 }
330
331 void processUserInput(int resourceNo, int testCase)
332 {
333     int level = 0;
334     if (!resourceNo && !testCase)
335     {
336         testCase = TEST_QUIT;
337     }
338     switch (testCase)
339     {
340         case TEST_GET:
341             InitGetRequest(g_discoveredResources[resourceNo].uri);
342             break;
343
344         case TEST_CUSTOM_PUT:
345         {
346             OCPayload *payload = getCustomPutPayload();
347             if (payload)
348             {
349                 InitPutRequest(g_discoveredResources[resourceNo].uri, payload);
350             }
351             else
352             {
353                 OIC_LOG(ERROR, TAG, "Error creating payload. Not sending PUT request");
354                 promptUser = true;
355             }
356             break;
357         }
358
359         case TEST_OBSERVE:
360             InitObserveRequest(g_discoveredResources[resourceNo].uri);
361             break;
362
363         case TEST_TURN_SWITCH_ON:
364             InitPutRequest(g_discoveredResources[resourceNo].uri, getSwitchStatePayload (true));
365             break;
366
367         case TEST_TURN_SWITCH_OFF:
368             InitPutRequest(g_discoveredResources[resourceNo].uri, getSwitchStatePayload (false));
369             break;
370
371         case TEST_SET_LIGHT_BRIGHTNESS:
372             printf("Change bulb level [0-100] to ? :");
373             if (scanf("%d", &level) > 0)
374             {
375                 InitPutRequest(g_discoveredResources[resourceNo].uri,
376                     getChangeDimLevelPayload (level));
377             }
378             else
379             {
380                 printf("Invalid value\n");
381                 promptUser = true;
382             }
383             break;
384
385         case TEST_SET_LIGHT_TEMPERATURE:
386             printf("Change bulb temp level [0-100] to ? :");
387             if (scanf("%d", &level) > 0)
388             {
389                 InitPutRequest(g_discoveredResources[resourceNo].uri,
390                     getChangeBulbTempLevelPayload(level));
391             }
392             else
393             {
394                 printf("Invalid value\n");
395                 promptUser = true;
396             }
397             break;
398
399         case TEST_CYCLE:
400             OCProcess();
401             promptUser = true;
402             break;
403
404         case TEST_QUIT:
405             raise(SIGINT);
406             break;
407
408         default:
409             promptUser = true;
410             OIC_LOG(INFO, TAG, "Invalid test case");
411     }
412 }
413
414 void getTestCaseFromUser()
415 {
416     PrintResources();
417     PrintTestCases();
418     printf("\nUsage:<resource number> <test case> :");
419
420     char input[10] = {0};
421     uint32_t resourceNo = 0;
422     int testCase = 0;
423
424     char * ret = fgets(input, sizeof(input), stdin);
425     (void) ret;
426     int inCount = sscanf(input, "%d %d", &resourceNo, &testCase);
427
428     if (inCount != 2)
429     {
430         printf("Invalid input\n");
431         promptUser = true;
432         return;
433     }
434     if (resourceNo >= countDiscoveredResources)
435     {
436         printf("Invalid resource\n");
437         promptUser = true;
438         return;
439     }
440     processUserInput(resourceNo, testCase);
441 }
442
443 OCStackResult DiscoverResources()
444 {
445     OCCallbackData cbData = {
446                                 .context = (void*)DEFAULT_CONTEXT_VALUE,
447                                 .cb = discoveryReqCB
448                             };
449
450     OCStackResult ret = OCDoResource(NULL, OC_REST_DISCOVER, OC_RSRVD_WELL_KNOWN_URI,
451                         0, 0, CT_ADAPTER_IP,OC_LOW_QOS, &cbData, NULL, 0);
452
453     if (ret != OC_STACK_OK)
454     {
455         OIC_LOG(ERROR, TAG, "OCDoResource error");
456     }
457     return ret;
458 }
459
460 bool processSignal(bool set)
461 {
462     static sig_atomic_t signal = 0;
463     if (set)
464     {
465         signal = 1;
466     }
467     return signal == 1;
468 }
469
470 void processCancel(int signal)
471 {
472     if (signal == SIGINT)
473     {
474         processSignal(true);
475     }
476 }
477
478 int main(int argc, char* argv[])
479 {
480     (void) argc;
481     (void) argv;
482     OCStackResult result;
483     OIC_LOG(INFO, TAG, "Initializing IoTivity...");
484
485     result = OCInit(NULL, 0, OC_CLIENT);
486     if (result != OC_STACK_OK)
487     {
488         OIC_LOG_V(ERROR, TAG, "OCInit Failed %d", result);
489         return -1;
490     }
491
492     DiscoverResources();
493
494     if (signal(SIGINT, processCancel) == SIG_ERR)
495     {
496         OIC_LOG(ERROR, TAG, "Unable to catch SIGINT, terminating...");
497     }
498     else
499     {
500         OIC_LOG(INFO, TAG, "Press Ctrl-C to terminate");
501         // Loop until sigint
502         while (!processSignal(false) && result == OC_STACK_OK)
503         {
504             result = OCProcess();
505             if (result != OC_STACK_OK)
506             {
507                 OIC_LOG_V(ERROR, TAG, "OCProcess Failed: %d", result);
508                 break;
509             }
510
511             if (promptUser)
512             {
513                 promptUser = false;
514                 getTestCaseFromUser();
515             }
516         }
517     }
518
519     OIC_LOG(INFO, TAG, "Stopping IoTivity...");
520     result = OCStop();
521     if (result != OC_STACK_OK)
522     {
523         OIC_LOG_V(ERROR, TAG, "OCStop Failed: %d", result);
524     }
525
526     return 0;
527 }
528