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