Remove explicit functions for start/stop gathering and include codes in service_app_c...
[apps/native/st-things-light.git] / src / controller.c
1 /*
2  * Copyright (c) 2018 Samsung Electronics Co., Ltd.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an AS IS BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #include <tizen.h>
18 #include <service_app.h>
19 #include <string.h>
20 #include <stdlib.h>
21 #include <stdint.h>
22 #include <Ecore.h>
23
24 #include "log.h"
25 #include "resource/resource_infrared_motion_sensor.h"
26 #include "resource/resource_led.h"
27
28 // Timer duration
29 #define TIMER_GATHER_INTERVAL (5.0f)
30
31 // Motion sensor information
32 #define SENSOR_MOTION_GPIO_NUMBER (46)
33
34 // LED sensor information
35 #define SENSOR_LED_GPIO_NUMBER (130)
36 #define SENSOR_LED_ON "on"
37 #define SENSOR_LED_OFF "off"
38
39 // For using SmartThings SDK
40 #define USE_ST_SDK
41 #ifdef USE_ST_SDK
42 #include "smartthings.h"
43 #include "smartthings_resource.h"
44 #include "smartthings_payload.h"
45
46 // Certification file and private key file stored in the resource directory
47 #define CERT_FILE "certificate.pem"
48 #define PRIV_FILE "privatekey.der"
49
50 // URI and key information
51 #define SENSOR_MOTION_URI "/capability/motionSensor/main/0"
52 #define SENSOR_MOTION_KEY "value"
53 #define SENSOR_LED_URI "/capability/switch/main/0"
54 #define SENSOR_LED_KEY "power"
55 #endif /* USE_ST_SDK */
56
57 typedef struct app_data_s {
58         Ecore_Timer *getter_timer;
59         uint32_t motion_data;
60         int led_data;
61 #ifdef USE_ST_SDK
62         smartthings_h st_master_h;
63         smartthings_resource_h st_res_h;
64         smartthings_status_e status;
65 #endif /* USE_ST_SDK */
66 } app_data;
67
68 static app_data *g_ad = NULL;
69
70 #ifdef USE_ST_SDK
71 static const char * _resource_error_to_str(smartthings_resource_error_e error)
72 {
73         const char *err_str = NULL;
74
75         switch (error) {
76         case SMARTTHINGS_RESOURCE_ERROR_NONE:
77                 err_str = "SMARTTHINGS_RESOURCE_ERROR_NONE";
78                 break;
79         case SMARTTHINGS_RESOURCE_ERROR_INVALID_PARAMETER:
80                 err_str = "SMARTTHINGS_RESOURCE_ERROR_INVALID_PARAMETER";
81                 break;
82         case SMARTTHINGS_RESOURCE_ERROR_OUT_OF_MEMORY:
83                 err_str = "SMARTTHINGS_RESOURCE_ERROR_OUT_OF_MEMORY";
84                 break;
85         case SMARTTHINGS_RESOURCE_ERROR_PERMISSION_DENIED:
86                 err_str = "SMARTTHINGS_RESOURCE_ERROR_PERMISSION_DENIED";
87                 break;
88         case SMARTTHINGS_RESOURCE_ERROR_NO_DATA:
89                 err_str = "SMARTTHINGS_RESOURCE_ERROR_NO_DATA";
90                 break;
91         case SMARTTHINGS_RESOURCE_ERROR_NOT_SUPPORTED:
92                 err_str = "SMARTTHINGS_RESOURCE_ERROR_NOT_SUPPORTED";
93                 break;
94         case SMARTTHINGS_RESOURCE_ERROR_OPERATION_FAILED:
95                 err_str = "SMARTTHINGS_RESOURCE_ERROR_NOT_SUPPORTED";
96                 break;
97         case SMARTTHINGS_RESOURCE_ERROR_SERVICE_UNAVAILABLE:
98                 err_str = "SMARTTHINGS_RESOURCE_ERROR_SERVICE_UNAVAILABLE";
99                 break;
100         default:
101                 err_str = "Unknown error";
102                 break;
103         }
104
105         return err_str;
106 }
107 #endif
108
109 static Eina_Bool _get_motion_sensor_data(void *user_data)
110 {
111         int ret = 0;
112         uint32_t value = 0;
113         app_data *ad = user_data;
114
115         if (!ad) {
116                 _E("failed to get app_data");
117                 return ECORE_CALLBACK_CANCEL;
118         }
119
120         ret = resource_read_infrared_motion_sensor(SENSOR_MOTION_GPIO_NUMBER, &value);
121         if (ret != 0) {
122                 _E("cannot read data from the infrared motion sensor");
123                 return ECORE_CALLBACK_CANCEL;
124         }
125         ad->motion_data = value;
126
127         _D("Detected motion value is: %u", value);
128
129 #ifdef USE_ST_SDK
130         int error = SMARTTHINGS_RESOURCE_ERROR_NONE;
131         smartthings_payload_h resp_payload = NULL;
132
133         if (ad->status != SMARTTHINGS_STATUS_REGISTERED_TO_CLOUD)
134                 return ECORE_CALLBACK_RENEW;
135
136         error = smartthings_payload_create(&resp_payload);
137         if (error != SMARTTHINGS_RESOURCE_ERROR_NONE || !resp_payload) {
138                 _E("smartthings_payload_create() failed, [%s]",
139                         _resource_error_to_str(error));
140                 return ECORE_CALLBACK_CANCEL;
141         }
142
143         error = smartthings_payload_set_bool(resp_payload, SENSOR_MOTION_KEY, (bool)ad->motion_data);
144         if (error != SMARTTHINGS_RESOURCE_ERROR_NONE)
145                 _E("smartthings_payload_set_bool() failed, [%s]",
146                         _resource_error_to_str(error));
147
148         error = smartthings_resource_notify(ad->st_res_h, SENSOR_MOTION_URI, resp_payload);
149         if (error != SMARTTHINGS_RESOURCE_ERROR_NONE)
150                 _E("smartthings_resource_notify() failed, [%s]",
151                         _resource_error_to_str(error));
152
153         if (smartthings_payload_destroy(resp_payload))
154                 _E("smartthings_payload_destroy() failed");
155 #endif
156
157         return ECORE_CALLBACK_RENEW;
158 }
159
160 static int _set_led_data(app_data *ad, int state) {
161         int ret = 0;
162
163         ad->led_data = state;
164         ret = resource_write_led(SENSOR_LED_GPIO_NUMBER, state);
165         if (ret != 0) {
166                 _E("cannot write led data");
167                 return -1;
168         }
169         _I("LED : %d",state);
170
171         return 0;
172 }
173
174 #ifdef USE_ST_SDK
175 /* SmartThings resource functions */
176 static bool _handle_get_motion(smartthings_payload_h resp_payload, void *user_data)
177 {
178         int error = SMARTTHINGS_RESOURCE_ERROR_NONE;
179         app_data *ad = user_data;
180
181         retv_if(!ad, false);
182
183         _D("Received a GET request for MOTION");
184
185         error = smartthings_payload_set_bool(resp_payload, SENSOR_MOTION_KEY, (bool)ad->motion_data);
186         if (error != SMARTTHINGS_RESOURCE_ERROR_NONE)
187                 _E("smartthings_payload_set_bool() failed, [%s]",
188                         _resource_error_to_str(error));
189
190         return true;
191 }
192
193 static bool _handle_get_led(smartthings_payload_h resp_payload, void *user_data)
194 {
195         app_data *ad = user_data;
196         int error = SMARTTHINGS_RESOURCE_ERROR_NONE;
197         char *str = NULL;
198
199         retv_if(!ad, false);
200
201         _D("Received a GET request for LED");
202
203         if (ad->led_data)
204                 str = SENSOR_LED_ON;
205         else
206                 str = SENSOR_LED_OFF;
207
208         error = smartthings_payload_set_string(resp_payload, SENSOR_LED_KEY, str);
209         if (error != SMARTTHINGS_RESOURCE_ERROR_NONE)
210                 _E("smartthings_payload_set_string() failed, [%s]",
211                         _resource_error_to_str(error));
212
213         _D("Power : %s", str);
214
215         return true;
216 }
217
218 static bool _handle_set_led(smartthings_payload_h payload, smartthings_payload_h resp_payload, void *user_data)
219 {
220         app_data *ad = user_data;
221         char *str = NULL;
222         char *res_str = NULL;
223         int ret = 0;
224         int error = SMARTTHINGS_RESOURCE_ERROR_NONE;
225
226         retv_if(!ad, false);
227
228     _D("Received a SET request");
229
230     error = smartthings_payload_get_string(payload, SENSOR_LED_KEY, &str);
231         if (error != SMARTTHINGS_RESOURCE_ERROR_NONE)
232                 _E("smartthings_payload_get_string() failed, [%s]",
233                         _resource_error_to_str(error));
234
235         if (strncmp(str, SENSOR_LED_ON, strlen(SENSOR_LED_ON))) {
236                 ret = _set_led_data(ad, 0);
237                 res_str = SENSOR_LED_OFF;
238         } else {
239                 ret = _set_led_data(ad, 1);
240                 res_str = SENSOR_LED_ON;
241         }
242
243         free(str);
244         if (ret != 0) {
245                 _E("cannot set LED");
246                 return false;
247         }
248
249         error = smartthings_payload_set_string(resp_payload, SENSOR_LED_KEY, res_str);
250         if (error != SMARTTHINGS_RESOURCE_ERROR_NONE)
251                 _E("smartthings_payload_set_string() failed, [%s]",
252                         _resource_error_to_str(error));
253
254     return true;
255 }
256
257 static void _request_cb(smartthings_resource_h handle, int req_id,
258         const char *uri, smartthings_resource_req_type_e req_type,
259         smartthings_payload_h payload, void *user_data)
260 {
261         smartthings_payload_h resp_payload = NULL;
262         bool result = false;
263         int error = SMARTTHINGS_RESOURCE_ERROR_NONE;
264
265         _D("request on %s, type[%d], id[%d]", uri, req_type, req_id);
266
267         error = smartthings_payload_create(&resp_payload);
268         if (error != SMARTTHINGS_RESOURCE_ERROR_NONE || ! resp_payload)
269                 _E("smartthings_payload_create() failed, [%s]",
270                         _resource_error_to_str(error));
271
272         if (req_type == SMARTTHINGS_RESOURCE_REQUEST_GET) {
273                 if (!strncmp(uri, SENSOR_MOTION_URI, strlen(SENSOR_MOTION_URI)))
274                         result = _handle_get_motion(resp_payload, user_data);
275                 else if (!strncmp(uri, SENSOR_LED_URI, strlen(SENSOR_LED_URI)))
276                         result = _handle_get_led(resp_payload, user_data);
277                 else
278                         _E("No matching Resource uri to get");
279         } else if (req_type == SMARTTHINGS_RESOURCE_REQUEST_SET) {
280                 if (!strncmp(uri, SENSOR_LED_URI, strlen(SENSOR_LED_URI)))
281                         result = _handle_set_led(payload, resp_payload, user_data);
282                 else
283                         _E("No matching Resource uri to get");
284         } else {
285                 _E("Invalid request type - %d", req_type);
286                 smartthings_payload_destroy(resp_payload);
287                 return;
288         }
289
290         error = smartthings_resource_send_response(handle, req_id, uri, resp_payload, result);
291         if (error != SMARTTHINGS_RESOURCE_ERROR_NONE) {
292                         _E("smartthings_resource_send_response() failed, [%s]",
293                                 _resource_error_to_str(error));
294                         smartthings_payload_destroy(resp_payload);
295                         return;
296         }
297
298         if (req_type == SMARTTHINGS_RESOURCE_REQUEST_SET) {
299                         error = smartthings_resource_notify(handle, uri, resp_payload);
300                         if (error != SMARTTHINGS_RESOURCE_ERROR_NONE)
301                                 _E("smartthings_resource_notify() failed, [%s]",
302                                                 _resource_error_to_str(error));
303         }
304
305         if (smartthings_payload_destroy(resp_payload))
306                 _E("smartthings_payload_destroy() failed");
307
308         return;
309 }
310
311 static void _resource_connection_status_cb(
312         smartthings_resource_h handle,
313         smartthings_resource_connection_status_e status, void *user_data)
314 {
315         app_data *ad = user_data;
316
317         _D("status=[%d]", status);
318
319         ret_if(!ad);
320
321         if (status == SMARTTHINGS_RESOURCE_CONNECTION_STATUS_CONNECTED) {
322                 int error = SMARTTHINGS_RESOURCE_ERROR_NONE;
323                 error = smartthings_resource_set_request_cb(handle, _request_cb, ad);
324                 if (error != SMARTTHINGS_RESOURCE_ERROR_NONE) {
325                         _E("smartthings_resource_set_request_cb() is failed");
326                         return;
327                 }
328         } else {
329                 _E("connection failed");
330         }
331 }
332
333 static int _init_resource(app_data *ad)
334 {
335         smartthings_resource_h st_res_h = NULL;
336         int error = 0;
337
338         retv_if(!ad, -1);
339         if (ad->st_res_h) {
340                 _I("Already initialized!");
341                 return 0;
342         }
343
344         error = smartthings_resource_initialize(&st_res_h,
345                                 _resource_connection_status_cb, ad);
346         if (error) {
347                 _E("smartthings_resource_initialize() is failed, [%s]",
348                         _resource_error_to_str(error));
349                 return -1;
350         }
351
352         ad->st_res_h = st_res_h;
353
354         return 0;
355 }
356
357 static int _fini_resource(app_data *ad)
358 {
359         retv_if(!ad, -1);
360
361         if (!ad->st_res_h)
362                 return 0;
363
364         smartthings_resource_unset_request_cb(ad->st_res_h);
365         smartthings_resource_deinitialize(ad->st_res_h);
366
367         ad->st_res_h = NULL;
368
369         return 0;
370 }
371
372 /* SmartThings master functions */
373 static const char *__master_error_to_str(smartthings_error_e error)
374 {
375         const char *err_str = NULL;
376
377         switch (error) {
378         case SMARTTHINGS_ERROR_NONE:
379                 err_str = "SMARTTHINGS_ERROR_NONE";
380                 break;
381         case SMARTTHINGS_ERROR_INVALID_PARAMETER:
382                 err_str = "SMARTTHINGS_ERROR_INVALID_PARAMETER";
383                 break;
384         case SMARTTHINGS_ERROR_OUT_OF_MEMORY:
385                 err_str = "SMARTTHINGS_ERROR_OUT_OF_MEMORY";
386                 break;
387         case SMARTTHINGS_ERROR_PERMISSION_DENIED:
388                 err_str = "SMARTTHINGS_ERROR_PERMISSION_DENIED";
389                 break;
390         case SMARTTHINGS_ERROR_NO_DATA:
391                 err_str = "SMARTTHINGS_ERROR_NO_DATA";
392                 break;
393         case SMARTTHINGS_ERROR_NOT_SUPPORTED:
394                 err_str = "SMARTTHINGS_ERROR_NOT_SUPPORTED";
395                 break;
396         case SMARTTHINGS_ERROR_OPERATION_FAILED:
397                 err_str = "SMARTTHINGS_ERROR_OPERATION_FAILED";
398                 break;
399         case SMARTTHINGS_ERROR_SERVICE_UNAVAILABLE:
400                 err_str = "SMARTTHINGS_ERROR_SERVICE_UNAVAILABLE";
401                 break;
402         default:
403                 err_str = "Unknown error";
404                 break;
405         }
406
407         return err_str;
408 }
409
410 static void _user_confirm_cb(smartthings_h handle, void *user_data)
411 {
412         if (smartthings_send_user_confirm(handle, true) != 0)
413                 _E("smartthings_send_user_confirm() is failed");
414 }
415
416 static void _reset_confirm_cb(smartthings_h handle, void *user_data)
417 {
418         if (smartthings_send_reset_confirm(handle, true) != 0)
419                 _E("smartthings_send_reset_confirm() is failed");
420 }
421
422 static void _reset_result_cb(smartthings_h handle, bool result, void *user_data)
423 {
424         _I("reset result = [%d]", result);
425 }
426
427 static void _thing_status_cb(
428                 smartthings_h handle, smartthings_status_e status, void *user_data)
429 {
430         app_data *ad = user_data;
431         _D("status: [%d]", status);
432         ad->status = status;
433 }
434
435 static void _things_connection_status_cb(
436                 smartthings_h handle, smartthings_connection_status_e status,
437                 void *user_data)
438 {
439         _D("status = [%d]", status);
440
441         if (status == SMARTTHINGS_CONNECTION_STATUS_CONNECTED) {
442                 int err = 0;
443                 bool is_es_completed = false;
444                 const char* dev_name = "motion-light-app";
445                 int wifi_mode = SMARTTHINGS_WIFI_MODE_11B
446                         | SMARTTHINGS_WIFI_MODE_11G
447                         | SMARTTHINGS_WIFI_MODE_11N;
448
449                 int wifi_freq = SMARTTHINGS_WIFI_FREQ_24G | SMARTTHINGS_WIFI_FREQ_5G;
450
451                 err = smartthings_set_device_property(
452                                         handle, dev_name, wifi_mode, wifi_freq);
453                 if (err) {
454                         _E("smartthings_set_device_property() is failed, [%s]",
455                                 __master_error_to_str(err));
456                         return;
457                 }
458
459                 err = smartthings_set_certificate_file(handle, CERT_FILE, PRIV_FILE);
460                 if (err) {
461                         _E("smartthings_set_certificate_file() is failed, [%s]",
462                                 __master_error_to_str(err));
463                         return;
464                 }
465
466                 err = smartthings_set_user_confirm_cb(handle, _user_confirm_cb, NULL);
467                 if (err) {
468                         _E("smartthings_set_user_confirm_cb() is failed, [%s]",
469                                 __master_error_to_str(err));
470                         return;
471                 }
472
473                 err = smartthings_set_reset_confirm_cb(handle, _reset_confirm_cb, NULL);
474                 if (err) {
475                         _E("smartthings_set_reset_confirm_cb() is failed, [%s]",
476                                 __master_error_to_str(err));
477                         return;
478                 }
479
480                 err = smartthings_set_reset_result_cb(handle, _reset_result_cb, NULL);
481                 if (err) {
482                         _E("smartthings_set_reset_result_cb() is failed, [%s]",
483                                 __master_error_to_str(err));
484                         return;
485                 }
486
487                 err = smartthings_set_status_changed_cb(handle, _thing_status_cb, user_data);
488                 if (err) {
489                         _E("smartthings_set_status_changed_callback() is failed, [%s]",
490                                 __master_error_to_str(err));
491                         return;
492                 }
493
494                 err = smartthings_start(handle);
495                 if (err) {
496                         _E("smartthings_start() is failed, [%s]",
497                                 __master_error_to_str(err));
498                         return;
499                 }
500
501                 err = smartthings_get_easysetup_status(handle, &is_es_completed);
502                 if (err) {
503                         _E("smartthings_get_easysetup_status() is failed, [%s]",
504                                 __master_error_to_str(err));
505                         return;
506                 }
507
508                 if (is_es_completed == true) {
509                         _I("Easysetup is already done");
510                         return;
511                 }
512
513                 _I("Easysetup is starting now");
514                 err = smartthings_start_easysetup(handle);
515                 if (err) {
516                         _E("smartthings_start_easysetup() is failed, [%s]",
517                                 __master_error_to_str(err));
518                         smartthings_stop(handle);
519                         return;
520                 }
521         } else {
522                         _E("connection failed");
523         }
524 }
525
526 static int _init_master(app_data *ad)
527 {
528         int err = 0;
529         smartthings_h st_handle = NULL;
530
531         retv_if(!ad, -1);
532
533         if (ad->st_master_h) {
534                 _I("Already initialized!");
535                 return 0;
536         }
537
538         err = smartthings_initialize(&st_handle, _things_connection_status_cb, ad);
539         if (err) {
540                 _E("smartthings_initialize() is failed, [%s]",
541                         __master_error_to_str(err));
542                 return -1;
543         }
544
545         ad->st_master_h = st_handle;
546
547         return 0;
548 }
549
550 int _fini_master(app_data *ad)
551 {
552         retv_if(!ad, -1);
553
554         if (!ad->st_master_h) {
555                 _I("handle is already NULL");
556                 return 0;
557         }
558
559         smartthings_unset_user_confirm_cb(ad->st_master_h);
560         smartthings_unset_reset_confirm_cb(ad->st_master_h);
561         smartthings_unset_reset_result_cb(ad->st_master_h);
562         smartthings_unset_status_changed_cb(ad->st_master_h);
563
564         smartthings_stop_easysetup(ad->st_master_h);
565         smartthings_stop(ad->st_master_h);
566
567         if (smartthings_deinitialize(ad->st_master_h) != 0)  {
568                 _E("smartthings_deinitialize() is failed");
569                 return -1;
570         }
571         ad->st_master_h = NULL;
572
573         return 0;
574 }
575 #endif /* USE_ST_SDK */
576
577 static bool service_app_create(void *user_data)
578 {
579 #ifdef USE_ST_SDK
580         app_data *ad = user_data;
581
582         if (_init_master(ad))
583                 return false;
584
585         if (_init_resource(ad)) {
586                 _fini_master(ad);
587                 return false;
588         }
589 #endif
590
591         return true;
592 }
593
594 static void service_app_control(app_control_h app_control, void *user_data)
595 {
596         app_data *ad = user_data;
597
598         if (ad->getter_timer)
599                 ecore_timer_del(ad->getter_timer);
600
601         ad->getter_timer = ecore_timer_add(TIMER_GATHER_INTERVAL, _get_motion_sensor_data, ad);
602         if (!ad->getter_timer) {
603                 _E("Failed to add getter timer");
604                 return;
605         }
606 }
607
608 static void service_app_terminate(void *user_data)
609 {
610         app_data *ad = user_data;
611
612 #ifdef USE_ST_SDK
613         _fini_resource(ad);
614         _fini_master(ad);
615 #endif
616
617         // Turn off LED light with __set_led()
618         _set_led_data(ad, 0);
619
620         // Close Motion and LED resources
621         resource_close_infrared_motion_sensor();
622         resource_close_led();
623
624         // Free app data
625         free(ad);
626
627         FN_END;
628 }
629
630 int main(int argc, char *argv[])
631 {
632         app_data *ad = NULL;
633         service_app_lifecycle_callback_s event_callback;
634
635         ad = calloc(1, sizeof(app_data));
636         retv_if(!ad, -1);
637
638         g_ad = ad;
639
640         event_callback.create = service_app_create;
641         event_callback.terminate = service_app_terminate;
642         event_callback.app_control = service_app_control;
643
644         return service_app_main(argc, argv, &event_callback, ad);
645 }