608ad0a34512114d5c05a67793db9bb296174a8f
[apps/native/gear-racing-car.git] / src / app.c
1 /*
2  * Copyright (c) 2017 Samsung Electronics Co., Ltd.
3  *
4  * Contact: Jeonghoon Park <jh1979.park@samsung.com>
5  *
6  * Licensed under the Flora License, Version 1.1 (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://floralicense.org/license/
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 <stdio.h>
20 #include <stdlib.h>
21 #include <unistd.h>
22 #include <math.h>
23 #include <glib.h>
24 #include <service_app.h>
25 #include "log.h"
26 #include "resource.h"
27 #include "receiver.h"
28 #include "message.h"
29 #include "connection_manager.h"
30 #include "net-util.h"
31 #include "config.h"
32 #include "cloud/cloud_communication.h"
33
34 #define ENABLE_MOTOR 1
35
36 #define CONFIG_GRP_CAR "Car"
37 #define CONFIG_KEY_ID "Id"
38 #define CONFIG_KEY_NAME "Name"
39 #define CLOUD_REQUESTS_FREQUENCY 15
40
41 enum {
42         DIR_STATE_S,
43         DIR_STATE_F,
44         DIR_STATE_B,
45 };
46
47 typedef struct app_data_s {
48         unsigned int f_value;
49         unsigned int r_value;
50         unsigned int dir_state;
51         guint idle_h;
52 } app_data;
53
54 static void _initialize_components(app_data *ad);
55 static void _initialize_config();
56
57 static void service_app_lang_changed(app_event_info_h event_info, void *user_data)
58 {
59         return;
60 }
61
62 static void service_app_region_changed(app_event_info_h event_info, void *user_data)
63 {
64         return;
65 }
66
67 static void service_app_low_battery(app_event_info_h event_info, void *user_data)
68 {
69         _E("low battery! exit app");
70         service_app_exit();
71
72         return;
73 }
74
75 static void service_app_low_memory(app_event_info_h event_info, void *user_data)
76 {
77         return;
78 }
79
80 static inline double __map_round(double val)
81 {
82         return floor(val + 0.5);
83 }
84
85 static int __map_range_val(int d_max, int d_min, int v_max, int v_min, int val)
86 {
87         int rval = 0;
88         double slope = 0;
89         slope = 1.0 * (d_max - d_min) / (v_max - v_min);
90
91         rval = d_min + __map_round(slope * (val - v_min));
92
93         return rval;
94 }
95
96 static int ___map_speed_val(int speed)
97 {
98         static const int motor_max = 4095;
99         static const int motor_min = -4095;
100         static const int speed_max = 1000;
101         static const int speed_min = -1000;
102
103         return __map_range_val(motor_max, motor_min,
104                 speed_max, speed_min, speed);
105 }
106
107 static int ___map_servo_val(int servo)
108 {
109         static const int motor_max = 500;
110         static const int motor_min = 400;
111         static const int servo_max = 1000;
112         static const int servo_min = -1000;
113
114         return __map_range_val(motor_max, motor_min,
115                 servo_max, servo_min, servo);
116 }
117
118
119 static int __driving_motors(int servo, int speed)
120 {
121         int val_speed;
122         int val_servo;
123
124         val_servo = ___map_servo_val(servo);
125         val_speed = ___map_speed_val(speed);
126
127         _D("control motor - servo[%4d : %4d], speed[%4d : %4d]",
128                 servo, val_servo, speed, val_speed);
129 #if ENABLE_MOTOR
130         resource_set_servo_motor_value(0, val_servo);
131         resource_set_motor_driver_L298N_speed(MOTOR_ID_1, val_speed);
132         resource_set_motor_driver_L298N_speed(MOTOR_ID_2, val_speed);
133 #endif
134
135         return 0;
136 }
137
138 static gboolean __message_dispatcher(gpointer user_data)
139 {
140         message_s *msg = NULL;
141
142         do {
143                 msg = message_pop_from_inqueue();
144                 if (msg) {
145                         switch (msg->cmd) {
146                         case MESSAGE_CMD_HELLO:
147                                 /* TODO : say hello to sender */
148                                 break;
149                         case MESSAGE_CMD_CALIBRATION:
150                                 /* TODO : set calibration mode */
151                                 break;
152                         case MESSAGE_CMD_DRIVE:
153                                 /* TODO : driving car */
154                                 __driving_motors(msg->servo, msg->speed);
155                                 break;
156                         case MESSAGE_CMD_BYE:
157                                 __driving_motors(0, 0);
158                                 break;
159                         }
160                 }
161                 free(msg);
162         } while (msg);
163
164         return TRUE;
165 }
166
167 static void __recv_state_change(receiver_type_e type,
168         receiver_state_e state, void* user_data)
169 {
170         app_data *ad = user_data;
171         ret_if(!ad);
172
173         _D("receiver type[%d] state changed[%d]", type, state);
174
175         if (state == RECEIVER_STATE_CONNECTED) {
176                 if (!ad->idle_h)
177                         ad->idle_h = g_idle_add(__message_dispatcher, ad);
178         } else {
179                 if (ad->idle_h) {
180                         g_source_remove(ad->idle_h);
181                         ad->idle_h = 0;
182                 }
183                 __driving_motors(0, 0);
184         }
185
186         return;
187 }
188
189 static void __conn_state_changed_cb(connection_state_e state,
190         const char *ip, void* user_data)
191 {
192         app_data *ad = user_data;
193
194         _D("connection state changed : %d", state);
195
196         if (state == CONNECTION_STATE_CONNECTED) {
197                 receiver_start(RECEIVER_TYPE_UDP);
198
199         } else {
200                 receiver_stop(RECEIVER_TYPE_UDP);
201
202                 if (ad->idle_h) {
203                         g_source_remove(ad->idle_h);
204                         ad->idle_h = 0;
205                 }
206
207                 __driving_motors(0, 0);
208         }
209         return;
210 }
211
212 static void _initialize_config()
213 {
214         config_init();
215         char *id = NULL;
216         char *name = NULL;
217         gboolean modified = false;
218         if (config_get_string(CONFIG_GRP_CAR, CONFIG_KEY_ID, &id) != 0) {
219                 char *uuid = g_uuid_string_random();
220                 config_set_string(CONFIG_GRP_CAR, CONFIG_KEY_ID, uuid);
221                 g_free(uuid);
222                 modified = true;
223         }
224         if (config_get_string(CONFIG_GRP_CAR, CONFIG_KEY_NAME, &id) != 0) {
225                 config_set_string(CONFIG_GRP_CAR, CONFIG_KEY_NAME, "Passerati");
226                 modified = true;
227         }
228         if (modified == true) {
229                 config_save();
230         }
231         free(id);
232         free(name);
233 }
234
235 static void _initialize_components(app_data *ad)
236 {
237         receiver_init(RECEIVER_TYPE_UDP);
238         receiver_set_state_changed_cb(RECEIVER_TYPE_UDP, __recv_state_change, ad);
239
240         connection_manager_init();
241         connection_manager_set_state_changed_cb(__conn_state_changed_cb, ad);
242         net_util_init();
243         _initialize_config();
244         cloud_communication_init();
245 }
246
247 static bool service_app_create(void *data)
248 {
249         int ret = 0;
250         app_data *ad = data;
251
252         /*
253          * if you want to use default configuration,
254          * Do not need to call resource_set_motor_driver_L298N_configuration(),
255          *
256         */
257 #if ENABLE_MOTOR
258         ret = resource_set_motor_driver_L298N_configuration(MOTOR_ID_1, 19, 16, 5);
259         if (ret) {
260                 _E("resource_set_motor_driver_L298N_configuration()");
261                 service_app_exit();
262         }
263         ret = resource_set_motor_driver_L298N_configuration(MOTOR_ID_2, 26, 20, 4);
264         if (ret) {
265                 _E("resource_set_motor_driver_L298N_configuration()");
266                 service_app_exit();
267         }
268 #endif
269
270         _initialize_components(ad);
271         cloud_communication_start(CLOUD_REQUESTS_FREQUENCY);
272
273         message_queue_new();
274
275         return true;
276 }
277
278 static void service_app_control(app_control_h app_control, void *data)
279 {
280
281 #if ENABLE_MOTOR
282         /* set speed 0, to reduce delay of initializing motor driver */
283         resource_set_motor_driver_L298N_speed(MOTOR_ID_1, 0);
284         resource_set_motor_driver_L298N_speed(MOTOR_ID_2, 0);
285         resource_set_servo_motor_value(0, 450);
286 #endif
287
288         return;
289 }
290
291 static void service_app_terminate(void *data)
292 {
293         app_data *ad = data;
294
295         if (ad->idle_h)
296                 g_source_remove(ad->idle_h);
297
298
299         connection_manager_fini();
300         receiver_fini(RECEIVER_TYPE_UDP);
301
302         cloud_communication_stop();
303         cloud_communication_fini();
304         config_shutdown();
305         net_util_fini();
306
307         resource_close_all();
308         log_file_close();
309
310         _D("Bye ~");
311
312         return;
313 }
314
315 int main(int argc, char* argv[])
316 {
317         app_data *ad = NULL;
318         int ret = 0;
319         service_app_lifecycle_callback_s event_callback;
320         app_event_handler_h handlers[5] = {NULL, };
321
322         log_type_set(LOG_TYPE_DLOG);
323
324         ad = calloc(1, sizeof(app_data));
325         retv_if(!ad, -1);
326
327         event_callback.create = service_app_create;
328         event_callback.terminate = service_app_terminate;
329         event_callback.app_control = service_app_control;
330
331         service_app_add_event_handler(&handlers[APP_EVENT_LOW_BATTERY],
332                 APP_EVENT_LOW_BATTERY, service_app_low_battery, &ad);
333         service_app_add_event_handler(&handlers[APP_EVENT_LOW_MEMORY],
334                 APP_EVENT_LOW_MEMORY, service_app_low_memory, &ad);
335         service_app_add_event_handler(&handlers[APP_EVENT_LANGUAGE_CHANGED],
336                 APP_EVENT_LANGUAGE_CHANGED, service_app_lang_changed, &ad);
337         service_app_add_event_handler(&handlers[APP_EVENT_REGION_FORMAT_CHANGED],
338                 APP_EVENT_REGION_FORMAT_CHANGED, service_app_region_changed, &ad);
339
340         ret = service_app_main(argc, argv, &event_callback, ad);
341         if (ret)
342                 _E("failed to start app");
343
344         return 0;
345 }