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