15db4bd3dfe65028e58eb613303d47607e965804
[apps/native/st-things-blind.git] / src / smart-blind.c
1 /*
2  * Copyright (c) 2018 Samsung Electronics Co., Ltd.
3  *
4  * Contact: Jin Yoon <jinny.yoon@samsung.com>
5  *
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  * http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an AS IS BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  */
18
19 #include <tizen.h>
20 #include <service_app.h>
21 #include <stdio.h>
22 #include <string.h>
23 #include <stdlib.h>
24 #include <pthread.h>
25 #include <unistd.h>
26 #include <Ecore.h>
27
28 #include "st_things.h"
29 #include "log.h"
30 #include "sensor-data.h"
31 #include "resource.h"
32
33 #define JSON_PATH "device_def.json"
34
35 #define SENSOR_URI_ILLUMINANCE "/capability/illuminanceMeasurement/main/0"
36 #define SENSOR_KEY_ILLUMINANCE "illuminance"
37 #define SENSOR_KEY_RANGE "range"
38
39 #define SENSOR_URI_POWER "/capability/switch/main/0"
40 #define SENSOR_KEY_POWER "power"
41 #define SENSOR_POWER_INITIALIZING "off"
42
43 #define I2C_BUS_NUMBER (1)
44
45 // QUIZ
46 #define SENSOR_GATHER_INTERVAL (1.0f)
47
48 // QUIZ
49 //#define USE_ST_SDK
50
51 typedef struct app_data_s {
52         Ecore_Timer *getter_illuminance;
53         sensor_data *illuminance_data;
54         sensor_data *power_data;
55 } app_data;
56
57 static app_data *g_ad = NULL;
58
59 #define ILLUMINATION_CRITERIA 1000
60
61 // HS-53 Servo Motor Duty Cycle : 0.54ms ~ 2.1ms
62 // Spec Duty Cycle : 0.553ms ~ 2.227ms(https://www.servocity.com/hitec-hs-53-servo)
63 #define SERVO_MOTOR_DUTY_CYCLE_COUNTER_CLOCKWISE 1.0
64 #define SERVO_MOTOR_DUTY_CYCLE_CLOCKWISE 2.0
65
66 #define BLIND_UP "on"
67 #define BLIND_DOWN "off"
68
69 static inline int __get_illuminance(void *data, unsigned int *illuminance_value)
70 {
71         int ret = 0;
72         app_data *ad = data;
73
74         retv_if(!ad, -1);
75         retv_if(!ad->illuminance_data, -1);
76
77         // QUIZ
78         ret = resource_read_illuminance_sensor(1, illuminance_value);
79         retv_if(ret != 0, -1);
80
81         sensor_data_set_uint(ad->illuminance_data, *illuminance_value);
82         _D("Illuminance value : %u", *illuminance_value);
83
84 #ifdef USE_ST_SDK
85         st_things_notify_observers(SENSOR_URI_ILLUMINANCE);
86 #endif
87
88         return 0;
89 }
90
91 static int __set_servo_motor(void *data, int on)
92 {
93         double duty_cycle = 0;
94         int ret = 0;
95         const char *power_value = NULL;
96         app_data *ad = data;
97
98         retv_if(!ad, -1);
99         retv_if(!ad->illuminance_data, -1);
100
101         if (on) {
102                 duty_cycle = SERVO_MOTOR_DUTY_CYCLE_CLOCKWISE;
103                 power_value = BLIND_UP;
104         } else {
105                 duty_cycle = SERVO_MOTOR_DUTY_CYCLE_COUNTER_CLOCKWISE;
106                 power_value = BLIND_DOWN;
107         }
108
109 #if 0 // QUIZ
110         ret = resource_set_servo_motor_value(/* duty_cycle */);
111         retv_if(ret != 0, -1);
112 #endif
113
114         sensor_data_set_string(ad->power_data, power_value, strlen(power_value));
115
116         return 0;
117 }
118
119 static Eina_Bool __illuminance_to_servo_motor(void *data)
120 {
121         int ret = 0;
122         unsigned int illuminance_value = 0;
123
124         app_data *ad = data;
125
126         if (!ad) {
127                 _E("failed to get app_data");
128                 service_app_exit();
129         }
130
131         if (!ad->illuminance_data) {
132                 _E("failed to get illuminance_data");
133                 service_app_exit();
134         }
135
136         ret = __get_illuminance(ad, &illuminance_value);
137         retv_if(ret != 0, ECORE_CALLBACK_RENEW);
138
139 #if 1 // # Senario : Illuminance sensor
140         int on = 0;
141
142         if (illuminance_value < ILLUMINATION_CRITERIA) {
143                 on = 0;
144         } else {
145                 on = 1;
146         }
147
148         ret = __set_servo_motor(ad, on);
149         retv_if(ret != 0, ECORE_CALLBACK_RENEW);
150 #endif
151
152         return ECORE_CALLBACK_RENEW;
153 }
154
155 void gathering_stop(void *data)
156 {
157         app_data *ad = data;
158
159         ret_if(!ad);
160
161         if (ad->getter_illuminance)
162                 ecore_timer_del(ad->getter_illuminance);
163 }
164
165 void gathering_start(void *data)
166 {
167         app_data *ad = data;
168
169         ret_if(!ad);
170
171         gathering_stop(ad);
172
173         ad->getter_illuminance = ecore_timer_add(SENSOR_GATHER_INTERVAL, __illuminance_to_servo_motor, ad);
174         if (!ad->getter_illuminance)
175                 _E("Failed to add getter_illuminance");
176 }
177
178 #ifdef USE_ST_SDK
179 static bool handle_reset_request(void)
180 {
181         _D("Received a request for RESET.");
182         return false;
183 }
184
185 static void handle_reset_result(bool result)
186 {
187         _D("Reset %s.\n", result ? "succeeded" : "failed");
188 }
189
190 static bool handle_ownership_transfer_request(void)
191 {
192         _D("Received a request for Ownership-transfer.");
193         return true;
194 }
195
196 static void handle_things_status_change(st_things_status_e things_status)
197 {
198         _D("Things status is changed: %d", things_status);
199
200         if (things_status == ST_THINGS_STATUS_REGISTERED_TO_CLOUD) {
201                 ecore_main_loop_thread_safe_call_async(gathering_start, g_ad);
202         }
203 }
204
205 static bool handle_get_request(st_things_get_request_message_s* req_msg, st_things_representation_s* resp_rep)
206 {
207         _D("resource_uri [%s]", req_msg->resource_uri);
208         retv_if(!g_ad, false);
209
210         if (0 == strcmp(req_msg->resource_uri, SENSOR_URI_ILLUMINANCE)) {
211                 if (req_msg->has_property_key(req_msg, SENSOR_KEY_ILLUMINANCE)) {
212                         unsigned int value = 0;
213                         sensor_data_get_uint(g_ad->illuminance_data, &value);
214                         resp_rep->set_int_value(resp_rep, SENSOR_KEY_ILLUMINANCE, value);
215                 }
216                 return true;
217         } else if (0 == strcmp(req_msg->resource_uri, SENSOR_URI_POWER)) {
218                 if (req_msg->has_property_key(req_msg, SENSOR_KEY_POWER)) {
219                         const char *str = NULL;
220                         sensor_data_get_string(g_ad->power_data, &str);
221                         if (!str) {
222                                 str = SENSOR_POWER_INITIALIZING;
223                         }
224                         resp_rep->set_str_value(resp_rep, SENSOR_KEY_POWER, str);
225                         _D("Power : %s", str);
226                 }
227                 return true;
228         }
229         _E("not supported uri");
230         return false;
231 }
232
233 static bool handle_set_request(st_things_set_request_message_s* req_msg, st_things_representation_s* resp_rep)
234 {
235         _D("resource_uri [%s]", req_msg->resource_uri);
236         retv_if(!g_ad, false);
237
238         if (0 == strcmp(req_msg->resource_uri, SENSOR_URI_POWER)) {
239                 int ret = 0;
240                 char *str = NULL;
241
242                 if (req_msg->rep->get_str_value(req_msg->rep, SENSOR_KEY_POWER, &str)) {
243                         retv_if(!str, false);
244                         _D("set [%s:%s] == %s", SENSOR_URI_POWER, SENSOR_KEY_POWER, str);
245
246                         sensor_data_set_string(g_ad->power_data, str, strlen(str));
247                         resp_rep->set_str_value(resp_rep, SENSOR_KEY_POWER, str);
248
249                         if (0 == strcmp(str, "on")) {
250                                 ret = __set_servo_motor(g_ad, 1);
251                         } else {
252                                 ret = __set_servo_motor(g_ad, 0);
253                         }
254                         free(str);
255                         retv_if(ret != 0, false);
256                 } else {
257                         _E("cannot get a string value");
258                 }
259
260                 return true;
261         }
262         return false;
263 }
264
265 static int __st_things_init(void)
266 {
267         bool easysetup_complete = false;
268         char app_json_path[128] = {'\0', };
269         char *app_res_path = NULL;
270         char *app_data_path = NULL;
271
272         app_res_path = app_get_resource_path();
273         if (!app_res_path) {
274                 _E("app_res_path is NULL!!");
275                 return -1;
276         }
277
278         app_data_path = app_get_data_path();
279         if (!app_data_path) {
280                 _E("app_data_path is NULL!!");
281                 free(app_res_path);
282                 return -1;
283         }
284
285         snprintf(app_json_path, sizeof(app_json_path), "%s%s", app_res_path, JSON_PATH);
286
287         if (0 != st_things_set_configuration_prefix_path(app_res_path, app_data_path)) {
288                 _E("st_things_set_configuration_prefix_path() failed!!");
289                 free(app_res_path);
290                 free(app_data_path);
291                 return -1;
292         }
293
294         free(app_res_path);
295         free(app_data_path);
296
297         if (0 != st_things_initialize(app_json_path, &easysetup_complete)) {
298                 _E("st_things_initialize() failed!!");
299                 return -1;
300         }
301
302         _D("easysetup_complete:[%d] ", easysetup_complete);
303
304         st_things_register_request_cb(handle_get_request, handle_set_request);
305         st_things_register_reset_cb(handle_reset_request, handle_reset_result);
306         st_things_register_user_confirm_cb(handle_ownership_transfer_request);
307         st_things_register_things_status_change_cb(handle_things_status_change);
308
309         return 0;
310 }
311
312 static int __st_things_deinit(void)
313 {
314         st_things_deinitialize();
315         return 0;
316 }
317
318 static int __st_things_start(void)
319 {
320         st_things_start();
321         return 0;
322 }
323
324 static int __st_things_stop(void)
325 {
326         st_things_stop();
327         return 0;
328 }
329 #endif /* USE_ST_SDK */
330
331 static bool service_app_create(void *user_data)
332 {
333         app_data *ad = (app_data *)user_data;
334
335         ad->illuminance_data = sensor_data_new(SENSOR_DATA_TYPE_UINT);
336         if (!ad->illuminance_data)
337                 return false;
338
339         ad->power_data = sensor_data_new(SENSOR_DATA_TYPE_STR);
340         if (!ad->power_data)
341                 return false;
342         sensor_data_set_string(g_ad->power_data, SENSOR_POWER_INITIALIZING, strlen(SENSOR_POWER_INITIALIZING));
343
344 #ifdef USE_ST_SDK
345         if (__st_things_init())
346                 return false;
347 #endif
348
349         return true;
350 }
351
352 static void service_app_control(app_control_h app_control, void *user_data)
353 {
354 #ifdef USE_ST_SDK
355         __st_things_start();
356 #else
357         gathering_start(user_data);
358 #endif
359 }
360
361 static void service_app_terminate(void *user_data)
362 {
363         app_data *ad = (app_data *)user_data;
364
365         resource_close_illuminance_sensor();
366         resource_close_servo_motor();
367
368 #ifdef USE_ST_SDK
369         __st_things_stop();
370         __st_things_deinit();
371 #else
372         gathering_stop(ad);
373 #endif
374
375         sensor_data_free(ad->illuminance_data);
376         free(ad);
377 }
378
379 int main(int argc, char *argv[])
380 {
381         app_data *ad = NULL;
382         service_app_lifecycle_callback_s event_callback;
383
384         ad = calloc(1, sizeof(app_data));
385         retv_if(!ad, -1);
386
387         g_ad = ad;
388
389         event_callback.create = service_app_create;
390         event_callback.terminate = service_app_terminate;
391         event_callback.app_control = service_app_control;
392
393         return service_app_main(argc, argv, &event_callback, ad);
394 }
395