sync
[framework/location/libslp-lbs-plugin-replay.git] / gps-plugin / src / gps_plugin_replay.c
1 /*
2  * gps-manager replay plugin
3  *
4  * Copyright (c) 2011-2013 Samsung Electronics Co., Ltd. All rights reserved.
5  *
6  * Contact: Youngae Kang <youngae.kang@samsung.com>, Minjune Kim <sena06.kim@samsung.com>
7  *          Genie Kim <daejins.kim@samsung.com>
8  *
9  * Licensed under the Apache License, Version 2.0 (the "License");
10  * you may not use this file except in compliance with the License.
11  * You may obtain a copy of the License at
12  *
13  * http://www.apache.org/licenses/LICENSE-2.0
14  *
15  * Unless required by applicable law or agreed to in writing, software
16  * distributed under the License is distributed on an "AS IS" BASIS,
17  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18  * See the License for the specific language governing permissions and
19  * limitations under the License.
20  */
21
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <glib.h>
26 #include <errno.h>
27 #include <sys/time.h>
28
29 #include <gps_manager_plugin_intf.h>
30
31 #include "gps_plugin_debug.h"
32 #include "nmea_parser.h"
33 #include "setting.h"
34
35 #define REPLAY_NMEA_SET_SIZE            4096
36 #define REPLAY_NMEA_SENTENCE_SIZE       128
37
38 gps_event_cb g_gps_event_cb = NULL;
39
40 typedef struct {
41         FILE *fd;
42         int interval;
43         int replay_mode;
44
45         pos_data_t *pos_data;
46         sv_data_t *sv_data;
47         nmea_data_t *nmea_data;
48
49         GSource *timeout_src;
50         GMainContext *default_context;
51 } replay_timeout;
52
53 replay_timeout *g_replay_timer = NULL;
54
55 int gps_plugin_replay_gps_init(gps_event_cb gps_event_cb, gps_server_param_t * gps_params);
56 int gps_plugin_replay_gps_deinit(gps_failure_reason_t * reason_code);
57 int gps_plugin_replay_gps_request(gps_action_t gps_action, void *data, gps_failure_reason_t * reason_code);
58
59 static const gps_plugin_interface g_gps_plugin_replay_interface = {
60         gps_plugin_replay_gps_init,
61         gps_plugin_replay_gps_deinit,
62         gps_plugin_replay_gps_request
63 };
64
65 void gps_plugin_replay_pos_event(pos_data_t * data)
66 {
67         gps_event_info_t gps_event;
68         time_t timestamp;
69
70         memset(&gps_event, 0, sizeof(gps_event_info_t));
71         time(&timestamp);
72
73         gps_event.event_id = GPS_EVENT_REPORT_POSITION;
74
75         if (data == NULL) {
76                 LOG_PLUGIN(DBG_ERR, "NULL POS data.");
77                 gps_event.event_data.pos_ind.error = GPS_ERR_COMMUNICATION;
78         } else {
79                 gps_event.event_data.pos_ind.error = GPS_ERR_NONE;
80                 gps_event.event_data.pos_ind.pos.timestamp = timestamp;
81                 gps_event.event_data.pos_ind.pos.latitude = data->latitude;
82                 gps_event.event_data.pos_ind.pos.longitude = data->longitude;
83                 gps_event.event_data.pos_ind.pos.altitude = data->altitude;
84                 gps_event.event_data.pos_ind.pos.speed = data->speed;
85                 gps_event.event_data.pos_ind.pos.bearing = data->bearing;
86                 gps_event.event_data.pos_ind.pos.hor_accuracy = data->hor_accuracy;
87                 gps_event.event_data.pos_ind.pos.ver_accuracy = data->ver_accuracy;
88         }
89
90         //LOG_PLUGIN(DBG_LOW, "%d / %f / %f / %f", gps_event.event_data.pos_ind.pos.timestamp, gps_event.event_data.pos_ind.pos.latitude, gps_event.event_data.pos_ind.pos.longitude, gps_event.event_data.pos_ind.pos.altitude);
91
92         if (g_gps_event_cb != NULL) {
93                 g_gps_event_cb(&gps_event);
94         }
95 }
96
97 void gps_plugin_replay_sv_event(sv_data_t * data)
98 {
99         int i;
100         gps_event_info_t gps_event;
101         time_t timestamp;
102
103         memset(&gps_event, 0, sizeof(gps_event_info_t));
104         time(&timestamp);
105         gps_event.event_id = GPS_EVENT_REPORT_SATELLITE;
106
107         if (data == NULL) {
108                 LOG_PLUGIN(DBG_ERR, "NULL SV data.");
109                 gps_event.event_data.sv_ind.error = GPS_ERR_COMMUNICATION;
110         } else {
111                 gps_event.event_data.sv_ind.error = GPS_ERR_NONE;
112                 gps_event.event_data.sv_ind.sv.timestamp = timestamp;
113                 gps_event.event_data.sv_ind.sv.pos_valid = data->pos_valid;
114                 gps_event.event_data.sv_ind.sv.num_of_sat = data->num_of_sat;
115                 for (i = 0; i < data->num_of_sat; i++) {
116                         gps_event.event_data.sv_ind.sv.sat[i].used = data->sat[i].used;
117                         gps_event.event_data.sv_ind.sv.sat[i].prn = data->sat[i].prn;
118                         gps_event.event_data.sv_ind.sv.sat[i].snr = data->sat[i].snr;
119                         gps_event.event_data.sv_ind.sv.sat[i].elevation = data->sat[i].elevation;
120                         gps_event.event_data.sv_ind.sv.sat[i].azimuth = data->sat[i].azimuth;
121                 }
122         }
123
124         if (g_gps_event_cb != NULL) {
125                 g_gps_event_cb(&gps_event);
126         }
127 }
128
129 void gps_plugin_replay_nmea_event(nmea_data_t * data)
130 {
131         gps_event_info_t gps_event;
132         time_t timestamp;
133
134         memset(&gps_event, 0, sizeof(gps_event_info_t));
135         time(&timestamp);
136
137         gps_event.event_id = GPS_EVENT_REPORT_NMEA;
138
139         if (data == NULL) {
140                 LOG_PLUGIN(DBG_ERR, "NULL NMEA data.");
141                 gps_event.event_data.nmea_ind.error = GPS_ERR_COMMUNICATION;
142         } else {
143                 if (data->len > REPLAY_NMEA_SENTENCE_SIZE) {
144                         LOG_PLUGIN(DBG_WARN, "The Size of NMEA[ %d ] is larger then max ", data->len);
145                         data->len = REPLAY_NMEA_SENTENCE_SIZE;
146                         gps_event.event_data.nmea_ind.error = GPS_ERR_COMMUNICATION;
147                 } else {
148                         gps_event.event_data.nmea_ind.error = GPS_ERR_NONE;
149                 }
150                 gps_event.event_data.nmea_ind.nmea.timestamp = timestamp;
151                 gps_event.event_data.nmea_ind.nmea.len = data->len;
152                 gps_event.event_data.nmea_ind.nmea.data = (char *)malloc(data->len);
153                 memset(gps_event.event_data.nmea_ind.nmea.data, 0x00, data->len);
154                 memcpy(gps_event.event_data.nmea_ind.nmea.data, data->data, data->len);
155                 //LOG_PLUGIN(DBG_LOW, "NMEA[%d] : %s", gps_event.event_data.nmea_ind.nmea.len, gps_event.event_data.nmea_ind.nmea.data);
156         }
157
158         if (g_gps_event_cb != NULL) {
159                 g_gps_event_cb(&gps_event);
160         }
161
162         if (gps_event.event_data.nmea_ind.nmea.data != NULL) {
163                 free(gps_event.event_data.nmea_ind.nmea.data);
164                 gps_event.event_data.nmea_ind.nmea.data = NULL;
165         }
166 }
167
168 void gps_plugin_respond_start_session(gboolean ret)
169 {
170         gps_event_info_t gps_event;
171         gps_event.event_id = GPS_EVENT_START_SESSION;
172
173         if (ret == TRUE) {
174                 gps_event.event_data.start_session_rsp.error = GPS_ERR_NONE;
175         } else {
176                 gps_event.event_data.start_session_rsp.error = GPS_ERR_COMMUNICATION;
177         }
178
179         if (g_gps_event_cb != NULL) {
180                 g_gps_event_cb(&gps_event);
181         }
182 }
183
184 void gps_plugin_respond_stop_session(void)
185 {
186         gps_event_info_t gps_event;
187
188         gps_event.event_id = GPS_EVENT_STOP_SESSION;
189         gps_event.event_data.stop_session_rsp.error = GPS_ERR_NONE;
190
191         if (g_gps_event_cb != NULL) {
192                 g_gps_event_cb(&gps_event);
193         }
194 }
195
196 gboolean gps_plugin_replay_read_nmea(replay_timeout * timer, char *nmea_data)
197 {
198         gboolean ret = FALSE;
199         int ref = 0;
200         char buf[REPLAY_NMEA_SENTENCE_SIZE] = { 0, };
201
202         if (timer->fd == NULL) {
203                 LOG_PLUGIN(DBG_ERR, "nmea fd is NULL");
204                 return FALSE;
205         }
206
207         if (nmea_data == NULL) {
208                 LOG_PLUGIN(DBG_ERR, "nmea_data is NULL");
209                 fclose(timer->fd);
210                 timer->fd = NULL;
211                 return FALSE;
212         }
213
214         while (fgets(buf, REPLAY_NMEA_SENTENCE_SIZE, timer->fd) != NULL) {
215                 if (strncmp(buf, "$GPGGA", 6) == 0) {
216                         ref++;
217                         if (ref > 1) {
218                                 fseek(timer->fd, -strlen(buf), SEEK_CUR);
219                                 LOG_PLUGIN(DBG_LOW, "2nd GPGGA : stop to read nmea data");
220                                 ret = TRUE;
221                                 break;
222                         } else if (ref == 1) {
223                                 LOG_PLUGIN(DBG_LOW, "1st GPGGA : start to read nmea data");
224                                 strncpy(nmea_data, buf, strlen(buf));
225                         }
226                 } else {
227                         if (strlen(nmea_data) + strlen(buf) > REPLAY_NMEA_SET_SIZE) {
228                                 LOG_PLUGIN(DBG_ERR, "read nmea data size is too long");
229                                 break;
230                         } else {
231                                 strncat(nmea_data, buf, strlen(buf));
232                         }
233                 }
234                 timer->nmea_data->len = strlen(buf);
235                 timer->nmea_data->data = buf;
236                 gps_plugin_replay_nmea_event(timer->nmea_data);
237         }
238
239         if (feof(timer->fd)) {
240                 LOG_PLUGIN(DBG_ERR, "end of file");
241                 rewind(timer->fd);
242                 ret = TRUE;
243         } else {
244                 LOG_PLUGIN(DBG_LOW, "read nmea data [%s]", nmea_data);
245         }
246         return ret;
247 }
248
249 gboolean gps_plugin_replay_read_manual(pos_data_t * pos_data)
250 {
251         gboolean ret = TRUE;
252
253         if (setting_get_double(VCONFKEY_LOCATION_MANUAL_LATITUDE, &pos_data->latitude) == FALSE) {
254                 LOG_PLUGIN(DBG_ERR, "Fail to get latitude");
255                 ret = FALSE;
256         }
257         if (setting_get_double(VCONFKEY_LOCATION_MANUAL_LONGITUDE, &pos_data->longitude) == FALSE) {
258                 LOG_PLUGIN(DBG_ERR, "Fail to get longitude");
259                 ret = FALSE;
260         }
261         if (setting_get_double(VCONFKEY_LOCATION_MANUAL_ALTITUDE, &pos_data->altitude) == FALSE) {
262                 LOG_PLUGIN(DBG_ERR, "Fail to get altitude");
263                 ret = FALSE;
264         }
265
266         return ret;
267 }
268
269 gboolean gps_plugin_replay_timeout_cb(gpointer data)
270 {
271         gboolean ret = FALSE;
272         read_error_t err = READ_SUCCESS;
273         char nmea_data[REPLAY_NMEA_SET_SIZE] = { 0, };
274         replay_timeout *timer = (replay_timeout *) data;
275
276         if (timer == NULL) {
277                 LOG_PLUGIN(DBG_ERR, "replay handel[timer] is NULL");
278                 return FALSE;
279         }
280
281         memset(timer->pos_data, 0, sizeof(pos_data_t));
282         memset(timer->sv_data, 0, sizeof(sv_data_t));
283
284         if (timer->replay_mode == REPLAY_NMEA) {
285                 if (gps_plugin_replay_read_nmea(timer, nmea_data) == FALSE) {
286                         LOG_PLUGIN(DBG_ERR, "Fail to read nmea data from file");
287                         return FALSE;
288                 } else {
289                         err = nmea_parser(nmea_data, timer->pos_data, timer->sv_data);
290                         if (err == READ_ERROR) {
291                                 LOG_PLUGIN(DBG_ERR, "Fail to parser nmea data from file");
292                                 return FALSE;
293                         } else if (err == READ_NOT_FIXED) {
294                                 LOG_PLUGIN(DBG_LOW, "GPS position is not fixed");
295                                 timer->sv_data->pos_valid = FALSE;
296                         }
297                 }
298         } else if (timer->replay_mode == REPLAY_MANUAL) {
299                 if (gps_plugin_replay_read_manual(timer->pos_data) == FALSE) {
300                         LOG_PLUGIN(DBG_ERR, "Fail to read manual data");
301                         err = READ_ERROR;
302                         return FALSE;
303                 } else {
304                         timer->sv_data->pos_valid = TRUE;
305                         err = READ_SUCCESS;
306                 }
307         } else if (timer->replay_mode == REPLAY_OFF) {
308                 LOG_PLUGIN(DBG_WARN, "replay_mode is OFF");
309                 err = READ_NOT_FIXED;
310                 timer->sv_data->pos_valid = FALSE;
311         }
312
313         if (g_gps_event_cb != NULL) {
314                 if (err != READ_NOT_FIXED) {
315                         gps_plugin_replay_pos_event(timer->pos_data);
316                 }
317                 gps_plugin_replay_sv_event(timer->sv_data);
318         }
319         ret = TRUE;
320         return ret;
321 }
322
323 void gps_plugin_stop_replay_mode(replay_timeout * timer)
324 {
325         if (timer->replay_mode == REPLAY_NMEA && fclose(timer->fd) != 0) {
326                 LOG_PLUGIN(DBG_ERR, "fclose failed");
327         }
328         timer->fd = NULL;
329
330         if (timer->timeout_src != NULL && timer->default_context != NULL && !g_source_is_destroyed(timer->timeout_src)) {
331                 if (timer->default_context == g_source_get_context(timer->timeout_src)) {
332                         g_source_destroy(timer->timeout_src);
333                         LOG_PLUGIN(DBG_LOW, "g_source_destroy timeout_src");
334                 } else {
335                         LOG_PLUGIN(DBG_WARN, "timer->timeout_src is attatched to 0x%x (actual 0x%x)",
336                                    g_source_get_context(timer->timeout_src), timer->default_context);
337                 }
338                 timer->timeout_src = NULL;
339                 timer->default_context = NULL;
340         } else {
341                 LOG_PLUGIN(DBG_WARN, "timeout_src or default_context is NULL or timeout_src is already destroyed");
342         }
343         gps_plugin_respond_stop_session();
344 }
345
346 gboolean gps_plugin_get_nmea_fd(replay_timeout * timer)
347 {
348         char replay_file_path[256];
349
350         snprintf(replay_file_path, sizeof(replay_file_path), NMEA_FILE_PATH"%s", setting_get_string(VCONFKEY_LOCATION_NMEA_FILE_NAME));
351         LOG_PLUGIN(DBG_ERR, "replay file name : %s", replay_file_path);
352
353         timer->fd = fopen(replay_file_path, "r");
354         if (timer->fd == NULL) {
355                 LOG_PLUGIN(DBG_ERR, "fopen(%s) failed", replay_file_path);
356                 timer->fd = fopen(DEFAULT_NMEA_LOG, "r");
357                 if (timer->fd == NULL) {
358                         LOG_PLUGIN(DBG_ERR, "fopen(%s) failed", DEFAULT_NMEA_LOG);
359                         return FALSE;
360                 }
361         }
362         return TRUE;
363 }
364
365 gboolean gps_plugin_start_replay_mode(replay_timeout * timer)
366 {
367         gboolean ret = FALSE;
368
369         if (timer->replay_mode == REPLAY_NMEA) {
370                 if (gps_plugin_get_nmea_fd(timer) == FALSE) {
371                         return FALSE;
372                 }
373         }
374
375         if (timer->default_context == NULL) {
376                 timer->default_context = g_main_context_default();
377                 if (timer->default_context == NULL) {
378                         return ret;
379                 }
380         }
381
382         if (timer->timeout_src != NULL) {
383                 LOG_PLUGIN(DBG_ERR, "timeout_src is already existed");
384                 ret = FALSE;
385         } else {
386                 timer->timeout_src = g_timeout_source_new_seconds(timer->interval);
387                 if (timer->timeout_src != NULL) {
388                         g_source_set_callback(timer->timeout_src, &gps_plugin_replay_timeout_cb, timer, NULL);
389                         if (g_source_attach(timer->timeout_src, timer->default_context) > 0) {
390                                 LOG_PLUGIN(DBG_LOW, "timeout_src(0x%x) is created & attatched to 0x%x", timer->timeout_src,
391                                            timer->default_context);
392                                 ret = TRUE;
393                         } else {
394                                 gps_plugin_stop_replay_mode(timer);
395                                 ret = FALSE;
396                         }
397                 }
398         }
399         gps_plugin_respond_start_session(ret);
400
401         return ret;
402 }
403
404 static void replay_mode_changed_cb(keynode_t * key, void *data)
405 {
406         if (setting_get_int(VCONFKEY_LOCATION_REPLAY_MODE, &g_replay_timer->replay_mode) == FALSE) {
407                 g_replay_timer->replay_mode = REPLAY_OFF;
408         }
409
410         if (g_replay_timer->replay_mode == REPLAY_NMEA) {
411                 if (gps_plugin_get_nmea_fd(g_replay_timer) == FALSE) {
412                         LOG_PLUGIN(DBG_ERR, "Fail to get nmea fd.");
413                 }
414         } else {
415                 if (g_replay_timer->fd != NULL) {
416                         fclose(g_replay_timer->fd);
417                         g_replay_timer->fd = NULL;
418                 }
419         }
420         return;
421 }
422
423 replay_timeout *gps_plugin_replay_timer_init()
424 {
425         replay_timeout *timer = NULL;
426
427         timer = (replay_timeout *) malloc(sizeof(replay_timeout));
428         if (timer == NULL) {
429                 LOG_PLUGIN(DBG_ERR, "replay_timeout allocation is failed.");
430                 return NULL;
431         }
432
433         timer->fd = NULL;
434         timer->interval = 1;
435         if (setting_get_int(VCONFKEY_LOCATION_REPLAY_MODE, &timer->replay_mode) == FALSE) {
436                 timer->replay_mode = REPLAY_OFF;
437         }
438         setting_notify_key_changed(VCONFKEY_LOCATION_REPLAY_MODE, replay_mode_changed_cb);
439
440         timer->pos_data = (pos_data_t *) malloc(sizeof(pos_data_t));
441         if (timer->pos_data == NULL) {
442                 LOG_PLUGIN(DBG_ERR, "pos_data allocation is failed.");
443                 free(timer);
444                 return NULL;
445         }
446
447         timer->sv_data = (sv_data_t *) malloc(sizeof(sv_data_t));
448         if (timer->sv_data == NULL) {
449                 LOG_PLUGIN(DBG_ERR, "sv_data allocation is failed.");
450                 free(timer->pos_data);
451                 free(timer);
452                 return NULL;
453         }
454
455         timer->nmea_data = (nmea_data_t *) malloc(sizeof(nmea_data_t));
456         if (timer->nmea_data == NULL) {
457                 LOG_PLUGIN(DBG_ERR, "nmea_data allocation is failed.");
458                 free(timer->pos_data);
459                 free(timer->sv_data);
460                 free(timer);
461                 return NULL;
462         }
463
464         timer->timeout_src = NULL;
465         timer->default_context = NULL;
466
467         return timer;
468 }
469
470 void gps_plugin_replay_timer_deinit(replay_timeout * timer)
471 {
472         if (timer == NULL) {
473                 return;
474         }
475
476         if (timer->pos_data != NULL) {
477                 free(timer->pos_data);
478                 timer->pos_data = NULL;
479         }
480         if (timer->sv_data != NULL) {
481                 free(timer->sv_data);
482                 timer->sv_data = NULL;
483         }
484         if (timer->nmea_data != NULL) {
485                 free(timer->nmea_data);
486                 timer->nmea_data = NULL;
487         }
488
489         setting_ignore_key_changed(VCONFKEY_LOCATION_REPLAY_MODE, replay_mode_changed_cb);
490
491         free(timer);
492         timer = NULL;
493 }
494
495 int gps_plugin_replay_gps_init(gps_event_cb gps_event_cb, gps_server_param_t * gps_params)
496 {
497         g_gps_event_cb = gps_event_cb;
498         g_replay_timer = gps_plugin_replay_timer_init();
499
500         return TRUE;
501 }
502
503 int gps_plugin_replay_gps_deinit(gps_failure_reason_t * reason_code)
504 {
505         gps_plugin_replay_timer_deinit(g_replay_timer);
506
507         return TRUE;
508 }
509
510 int gps_plugin_replay_gps_request(gps_action_t gps_action, void *data, gps_failure_reason_t * reason_code)
511 {
512         switch (gps_action) {
513         case GPS_ACTION_SEND_PARAMS:
514                 break;
515         case GPS_ACTION_START_SESSION:
516                 gps_plugin_start_replay_mode(g_replay_timer);
517                 break;
518         case GPS_ACTION_STOP_SESSION:
519                 gps_plugin_stop_replay_mode(g_replay_timer);
520                 break;
521         case GPS_INDI_SUPL_VERIFICATION:
522         case GPS_INDI_SUPL_DNSQUERY:
523         case GPS_ACTION_START_FACTTEST:
524         case GPS_ACTION_STOP_FACTTEST:
525         case GPS_ACTION_REQUEST_SUPL_NI:
526                 LOG_PLUGIN(DBG_LOW, "Don't use action type : [ %d ]", gps_action);
527                 break;
528         default:
529                 break;
530         }
531
532         return TRUE;
533 }
534
535 EXPORT_API const gps_plugin_interface *get_gps_plugin_interface()
536 {
537         return &g_gps_plugin_replay_interface;
538 }