Merge branch 'upstream' into tizen
[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     if (strRet < 0 || (size_t)strRet >= sizeValue)
203     {
204         OIC_LOG_V(ERROR, TAG, "Failed to parse string due to errno: %d", errno);
205         exit(1);
206     }
207     OCRepPayloadSetPropString(payload, "colourspacevalue", value);
208     return (OCPayload*) payload;
209 }
210
211 OCPayload* getChangeDimLevelPayload(uint32_t level)
212 {
213     OCRepPayload* payload = OCRepPayloadCreate();
214     if (!payload)
215     {
216         OIC_LOG(ERROR, TAG, "Failed to create payload object");
217         exit(1);
218     }
219
220     OIC_LOG_V(INFO, TAG, "Setting level to : %u", level);
221     OCRepPayloadSetPropInt(payload, "dimmingSetting", level);
222     return (OCPayload*) payload;
223 }
224
225 OCStackApplicationResult discoveryReqCB(void* ctx, OCDoHandle handle,
226                             OCClientResponse * clientResponse)
227 {
228     (void)handle;
229     (void) ctx;
230     if (!clientResponse)
231     {
232         OIC_LOG(INFO, TAG, "Discovery response is NULL");
233         return OC_STACK_KEEP_TRANSACTION;
234     }
235
236     OIC_LOG_PAYLOAD(INFO, clientResponse->payload);
237     OIC_LOG_V(INFO, TAG, "Discovered @ %s:%d", clientResponse->devAddr.addr,
238                                 clientResponse->devAddr.port);
239
240     destinationAddress = clientResponse->devAddr;
241
242     rememberDiscoveredResources(clientResponse);
243
244     promptUser = true;
245
246     return OC_STACK_KEEP_TRANSACTION;
247 }
248
249 OCPayload* getCustomPutPayload()
250 {
251     OCRepPayload* payload = OCRepPayloadCreate();
252     if (!payload)
253     {
254         OIC_LOG(ERROR, TAG, "Failed to create payload object");
255         exit(1);
256     }
257
258     char key[MAX_USER_INPUT] = {0};
259     char input[MAX_USER_INPUT] = {0};
260     char valueString[MAX_USER_INPUT] = {0};
261     int value = 0;
262     double valueDouble = 0.0;
263     int type = -1;
264
265     printf("\nEnter key value pairs as:\t<type(int)> <key> <value>\n");
266     printf("\nType: 0:bool \t 1:int \t 2:double\n");
267     while (true)
268     {
269         printf("Blank line / press ENTER to finish :");
270         char *ret = fgets(input, sizeof(input), stdin);
271         (void) ret;
272         int inCount = sscanf(input, "%d %s %s", &type, key, valueString);
273
274         if (inCount <= 0)
275         {
276             break;
277         }
278         if (inCount != 3)
279         {
280             printf("Invalid input\n");
281             OCRepPayloadDestroy(payload);
282             promptUser = true;
283             return NULL;
284         }
285
286         if (type == 0)  //bool
287         {
288             if (sscanf(valueString, "%d", &value) == 1)
289             {
290                 OCRepPayloadSetPropBool(payload, key, value);
291             }
292         }
293         else if (type == 1)  //int
294         {
295             if (sscanf(valueString, "%d", &value) == 1)
296             {
297                 OCRepPayloadSetPropInt(payload, key, value);
298             }
299         }
300         else if (type == 2)  //double
301         {
302             if (sscanf(valueString, "%lf", &valueDouble) == 1)
303             {
304                 OCRepPayloadSetPropDouble(payload, key, valueDouble);
305             }
306         }
307         else
308         {
309             OIC_LOG(ERROR, TAG, "Invalid entry. Stopping accepting key-values");
310             OCRepPayloadDestroy(payload);
311             promptUser = true;
312             return NULL;
313         }
314         memset(input, 0, sizeof (input));
315         memset(key, 0, sizeof (key));
316         memset(valueString, 0, sizeof (valueString));
317     }
318
319     if (payload->values)
320     {
321         return (OCPayload *) payload;
322     }
323     else
324     {
325         OCRepPayloadDestroy(payload);
326         return NULL;
327     }
328 }
329
330 void processUserInput(int resourceNo, int testCase)
331 {
332     int level = 0;
333     if (!resourceNo && !testCase)
334     {
335         testCase = TEST_QUIT;
336     }
337     switch (testCase)
338     {
339         case TEST_GET:
340             InitGetRequest(g_discoveredResources[resourceNo].uri);
341             break;
342
343         case TEST_CUSTOM_PUT:
344         {
345             OCPayload *payload = getCustomPutPayload();
346             if (payload)
347             {
348                 InitPutRequest(g_discoveredResources[resourceNo].uri, payload);
349             }
350             else
351             {
352                 OIC_LOG(ERROR, TAG, "Error creating payload. Not sending PUT request");
353                 promptUser = true;
354             }
355             break;
356         }
357
358         case TEST_OBSERVE:
359             InitObserveRequest(g_discoveredResources[resourceNo].uri);
360             break;
361
362         case TEST_TURN_SWITCH_ON:
363             InitPutRequest(g_discoveredResources[resourceNo].uri, getSwitchStatePayload (true));
364             break;
365
366         case TEST_TURN_SWITCH_OFF:
367             InitPutRequest(g_discoveredResources[resourceNo].uri, getSwitchStatePayload (false));
368             break;
369
370         case TEST_SET_LIGHT_BRIGHTNESS:
371             printf("Change bulb level [0-100] to ? :");
372             if (scanf("%d", &level) > 0)
373             {
374                 InitPutRequest(g_discoveredResources[resourceNo].uri,
375                     getChangeDimLevelPayload (level));
376             }
377             else
378             {
379                 printf("Invalid value\n");
380                 promptUser = true;
381             }
382             break;
383
384         case TEST_SET_LIGHT_TEMPERATURE:
385             printf("Change bulb temp level [0-100] to ? :");
386             if (scanf("%d", &level) > 0)
387             {
388                 InitPutRequest(g_discoveredResources[resourceNo].uri,
389                     getChangeBulbTempLevelPayload(level));
390             }
391             else
392             {
393                 printf("Invalid value\n");
394                 promptUser = true;
395             }
396             break;
397
398         case TEST_CYCLE:
399             OCProcess();
400             promptUser = true;
401             break;
402
403         case TEST_QUIT:
404             raise(SIGINT);
405             break;
406
407         default:
408             promptUser = true;
409             OIC_LOG(INFO, TAG, "Invalid test case");
410     }
411 }
412
413 void getTestCaseFromUser()
414 {
415     PrintResources();
416     PrintTestCases();
417     printf("\nUsage:<resource number> <test case> :");
418
419     char input[10] = {0};
420     uint32_t resourceNo = 0;
421     int testCase = 0;
422
423     char * ret = fgets(input, sizeof(input), stdin);
424     (void) ret;
425     int inCount = sscanf(input, "%d %d", &resourceNo, &testCase);
426
427     if (inCount != 2)
428     {
429         printf("Invalid input\n");
430         promptUser = true;
431         return;
432     }
433     if (resourceNo >= countDiscoveredResources)
434     {
435         printf("Invalid resource\n");
436         promptUser = true;
437         return;
438     }
439     processUserInput(resourceNo, testCase);
440 }
441
442 OCStackResult DiscoverResources()
443 {
444     OCCallbackData cbData = {
445                                 .context = (void*)DEFAULT_CONTEXT_VALUE,
446                                 .cb = discoveryReqCB
447                             };
448
449     OCStackResult ret = OCDoResource(NULL, OC_REST_DISCOVER, OC_RSRVD_WELL_KNOWN_URI,
450                         0, 0, CT_ADAPTER_IP,OC_LOW_QOS, &cbData, NULL, 0);
451
452     if (ret != OC_STACK_OK)
453     {
454         OIC_LOG(ERROR, TAG, "OCDoResource error");
455     }
456     return ret;
457 }
458
459 bool processSignal(bool set)
460 {
461     static sig_atomic_t signal = 0;
462     if (set)
463     {
464         signal = 1;
465     }
466     return signal == 1;
467 }
468
469 void processCancel(int signal)
470 {
471     if (signal == SIGINT)
472     {
473         processSignal(true);
474     }
475 }
476
477 int main(int argc, char* argv[])
478 {
479     (void) argc;
480     (void) argv;
481     OCStackResult result;
482     OIC_LOG(INFO, TAG, "Initializing IoTivity...");
483
484     result = OCInit(NULL, 0, OC_CLIENT);
485     if (result != OC_STACK_OK)
486     {
487         OIC_LOG_V(ERROR, TAG, "OCInit Failed %d", result);
488         return -1;
489     }
490
491     DiscoverResources();
492
493     if (signal(SIGINT, processCancel) == SIG_ERR)
494     {
495         OIC_LOG(ERROR, TAG, "Unable to catch SIGINT, terminating...");
496     }
497     else
498     {
499         OIC_LOG(INFO, TAG, "Press Ctrl-C to terminate");
500         // Loop until sigint
501         while (!processSignal(false) && result == OC_STACK_OK)
502         {
503             result = OCProcess();
504             if (result != OC_STACK_OK)
505             {
506                 OIC_LOG_V(ERROR, TAG, "OCProcess Failed: %d", result);
507                 break;
508             }
509
510             if (promptUser)
511             {
512                 promptUser = false;
513                 getTestCaseFromUser();
514             }
515         }
516     }
517
518     OIC_LOG(INFO, TAG, "Stopping IoTivity...");
519     result = OCStop();
520     if (result != OC_STACK_OK)
521     {
522         OIC_LOG_V(ERROR, TAG, "OCStop Failed: %d", result);
523     }
524
525     return 0;
526 }
527