801582cee0404b9c5985114775313318db557392
[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_DOOR "/capability/doorControl/main/0"
40 #define SENSOR_KEY_DOOR "doorState"
41 #define SENSOR_POWER_INITIALIZING BLIND_DOWN
42
43 #define I2C_BUS_NUMBER (1)
44 #define SENSOR_GATHER_INTERVAL (5.0f)
45
46 // QUIZ
47 //#define USE_ST_SDK
48
49 typedef struct app_data_s {
50         Ecore_Timer *getter_illuminance;
51         sensor_data *illuminance_data;
52         sensor_data *power_data;
53 } app_data;
54
55 static app_data *g_ad = NULL;
56
57 #define ILLUMINATION_CRITERIA 1000
58
59 // HS-53 Servo Motor Duty Cycle : 0.54ms ~ 2.1ms
60 // Spec Duty Cycle : 0.553ms ~ 2.227ms(https://www.servocity.com/hitec-hs-53-servo)
61 #define SERVO_MOTOR_DUTY_CYCLE_COUNTER_CLOCKWISE 1.0
62 #define SERVO_MOTOR_DUTY_CYCLE_CLOCKWISE 2.0
63
64 #define BLIND_UP "opening"
65 #define BLIND_DOWN "closing"
66
67 static inline int __get_illuminance(void *data, unsigned int *illuminance_value)
68 {
69         int ret = 0;
70         app_data *ad = data;
71
72         retv_if(!ad, -1);
73         retv_if(!ad->illuminance_data, -1);
74
75         // QUIZ
76 #if 0
77         ret = resource_read_illuminance_sensor(/*** BUS ***/, illuminance_value);
78         retv_if(ret != 0, -1);
79 #endif
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         st_things_notify_observers(SENSOR_URI_DOOR);
116
117         return 0;
118 }
119
120 static Eina_Bool __illuminance_to_servo_motor(void *data)
121 {
122         int ret = 0;
123         unsigned int illuminance_value = 0;
124
125         app_data *ad = data;
126
127         if (!ad) {
128                 _E("failed to get app_data");
129                 service_app_exit();
130         }
131
132         if (!ad->illuminance_data) {
133                 _E("failed to get illuminance_data");
134                 service_app_exit();
135         }
136
137         ret = __get_illuminance(ad, &illuminance_value);
138         retv_if(ret != 0, ECORE_CALLBACK_RENEW);
139
140 #if 0 // # Senario : Illuminance sensor
141         int on = 0;
142
143         if (illuminance_value < ILLUMINATION_CRITERIA) {
144                 on = 0;
145         } else {
146                 on = 1;
147         }
148
149         ret = __set_servo_motor(ad, on);
150         retv_if(ret != 0, ECORE_CALLBACK_RENEW);
151 #endif
152
153         return ECORE_CALLBACK_RENEW;
154 }
155
156 void gathering_stop(void *data)
157 {
158         app_data *ad = data;
159
160         ret_if(!ad);
161
162         if (ad->getter_illuminance)
163                 ecore_timer_del(ad->getter_illuminance);
164 }
165
166 void gathering_start(void *data)
167 {
168         app_data *ad = data;
169
170         ret_if(!ad);
171
172         gathering_stop(ad);
173
174         ad->getter_illuminance = ecore_timer_add(SENSOR_GATHER_INTERVAL, __illuminance_to_servo_motor, ad);
175         if (!ad->getter_illuminance)
176                 _E("Failed to add getter_illuminance");
177 }
178
179 #ifdef USE_ST_SDK
180 static bool handle_reset_request(void)
181 {
182         _D("Received a request for RESET.");
183         return false;
184 }
185
186 static void handle_reset_result(bool result)
187 {
188         _D("Reset %s.\n", result ? "succeeded" : "failed");
189 }
190
191 static bool handle_ownership_transfer_request(void)
192 {
193         _D("Received a request for Ownership-transfer.");
194         return true;
195 }
196
197 static void handle_things_status_change(st_things_status_e things_status)
198 {
199         _D("Things status is changed: %d", things_status);
200
201         if (things_status == ST_THINGS_STATUS_REGISTERED_TO_CLOUD) {
202                 ecore_main_loop_thread_safe_call_async(gathering_start, g_ad);
203         }
204 }
205
206 static bool handle_get_request(st_things_get_request_message_s* req_msg, st_things_representation_s* resp_rep)
207 {
208         _D("resource_uri [%s]", req_msg->resource_uri);
209         retv_if(!g_ad, false);
210
211         // QUIZ
212         if (0 == strcmp(req_msg->resource_uri, /*** URI ILLUMINANCE ***/)) {
213                 if (req_msg->has_property_key(req_msg, SENSOR_KEY_ILLUMINANCE)) {
214                         unsigned int value = 0;
215                         sensor_data_get_uint(g_ad->illuminance_data, &value);
216                         resp_rep->set_int_value(resp_rep, SENSOR_KEY_ILLUMINANCE, value);
217                 }
218                 return true;
219         // QUIZ
220         } else if (0 == strcmp(req_msg->resource_uri, /*** URI_DOOR ***/)) {
221                 if (req_msg->has_property_key(req_msg, SENSOR_KEY_DOOR)) {
222                         const char *str = NULL;
223                         sensor_data_get_string(g_ad->power_data, &str);
224                         if (!str) {
225                                 str = SENSOR_POWER_INITIALIZING;
226                         }
227                         resp_rep->set_str_value(resp_rep, SENSOR_KEY_DOOR, str);
228                         _D("Power : %s", str);
229                 }
230                 return true;
231         }
232         _E("not supported uri");
233         return false;
234 }
235
236 static bool handle_set_request(st_things_set_request_message_s* req_msg, st_things_representation_s* resp_rep)
237 {
238         _D("resource_uri [%s]", req_msg->resource_uri);
239         retv_if(!g_ad, false);
240
241                 // QUIZ
242                 if (0 == strcmp(req_msg->resource_uri, /*** URI DOOR ***/)) {
243                 int ret = 0;
244                 char *str = NULL;
245
246                 if (req_msg->rep->get_str_value(req_msg->rep, SENSOR_KEY_DOOR, &str)) {
247                         retv_if(!str, false);
248                         _D("set [%s:%s] == %s", SENSOR_URI_DOOR, SENSOR_KEY_DOOR, str);
249
250                         sensor_data_set_string(g_ad->power_data, str, strlen(str));
251                         resp_rep->set_str_value(resp_rep, SENSOR_KEY_DOOR, str);
252
253                         if (0 == strcmp(str, "opening")) {
254                                 ret = __set_servo_motor(g_ad, 1);
255                         } else {
256                                 ret = __set_servo_motor(g_ad, 0);
257                         }
258                         free(str);
259                         retv_if(ret != 0, false);
260                 } else {
261                         _E("cannot get a string value");
262                 }
263
264                 return true;
265         }
266         return false;
267 }
268
269 static int __st_things_init(void)
270 {
271         bool easysetup_complete = false;
272         char app_json_path[128] = {'\0', };
273         char *app_res_path = NULL;
274         char *app_data_path = NULL;
275
276         app_res_path = app_get_resource_path();
277         if (!app_res_path) {
278                 _E("app_res_path is NULL!!");
279                 return -1;
280         }
281
282         app_data_path = app_get_data_path();
283         if (!app_data_path) {
284                 _E("app_data_path is NULL!!");
285                 free(app_res_path);
286                 return -1;
287         }
288
289         snprintf(app_json_path, sizeof(app_json_path), "%s%s", app_res_path, JSON_PATH);
290
291         if (0 != st_things_set_configuration_prefix_path(app_res_path, app_data_path)) {
292                 _E("st_things_set_configuration_prefix_path() failed!!");
293                 free(app_res_path);
294                 free(app_data_path);
295                 return -1;
296         }
297
298         free(app_res_path);
299         free(app_data_path);
300
301         if (0 != st_things_initialize(app_json_path, &easysetup_complete)) {
302                 _E("st_things_initialize() failed!!");
303                 return -1;
304         }
305
306         _D("easysetup_complete:[%d] ", easysetup_complete);
307
308         st_things_register_request_cb(handle_get_request, handle_set_request);
309         st_things_register_reset_cb(handle_reset_request, handle_reset_result);
310         st_things_register_user_confirm_cb(handle_ownership_transfer_request);
311         st_things_register_things_status_change_cb(handle_things_status_change);
312
313         return 0;
314 }
315
316 static int __st_things_deinit(void)
317 {
318         st_things_deinitialize();
319         return 0;
320 }
321
322 static int __st_things_start(void)
323 {
324         st_things_start();
325         return 0;
326 }
327
328 static int __st_things_stop(void)
329 {
330         st_things_stop();
331         return 0;
332 }
333 #endif /* USE_ST_SDK */
334
335 static bool service_app_create(void *user_data)
336 {
337         app_data *ad = (app_data *)user_data;
338
339         ad->illuminance_data = sensor_data_new(SENSOR_DATA_TYPE_UINT);
340         if (!ad->illuminance_data)
341                 return false;
342
343         ad->power_data = sensor_data_new(SENSOR_DATA_TYPE_STR);
344         if (!ad->power_data)
345                 return false;
346         sensor_data_set_string(g_ad->power_data, SENSOR_POWER_INITIALIZING, strlen(SENSOR_POWER_INITIALIZING));
347
348 #ifdef USE_ST_SDK
349         if (__st_things_init())
350                 return false;
351 #endif
352
353         return true;
354 }
355
356 static void service_app_control(app_control_h app_control, void *user_data)
357 {
358 #ifdef USE_ST_SDK
359         __st_things_start();
360 #else
361         gathering_start(user_data);
362 #endif
363 }
364
365 static void service_app_terminate(void *user_data)
366 {
367         app_data *ad = (app_data *)user_data;
368
369         resource_close_illuminance_sensor();
370         resource_close_servo_motor();
371
372 #ifdef USE_ST_SDK
373         __st_things_stop();
374         __st_things_deinit();
375 #else
376         gathering_stop(ad);
377 #endif
378
379         sensor_data_free(ad->illuminance_data);
380         free(ad);
381 }
382
383 int main(int argc, char *argv[])
384 {
385         app_data *ad = NULL;
386         service_app_lifecycle_callback_s event_callback;
387
388         ad = calloc(1, sizeof(app_data));
389         retv_if(!ad, -1);
390
391         g_ad = ad;
392
393         event_callback.create = service_app_create;
394         event_callback.terminate = service_app_terminate;
395         event_callback.app_control = service_app_control;
396
397         return service_app_main(argc, argv, &event_callback, ad);
398 }
399