Changing the spec file to add license changes and addition of comments
[framework/location/libslp-lbs-plugin-replay.git] / replay-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 /* 
60 This is the interface that will be given to the gps-manager to call the API's of this plug-in module.
61 Init is called immediately after loading the plugin.
62 Deinit is called during the shut-down.
63 Request is called with specific parameter for the required operations.
64 */
65 static const gps_plugin_interface g_gps_plugin_replay_interface = {
66         gps_plugin_replay_gps_init,
67         gps_plugin_replay_gps_deinit,
68         gps_plugin_replay_gps_request
69 };
70
71 void gps_plugin_replay_pos_event(pos_data_t * data)
72 {
73         gps_event_info_t gps_event;
74         time_t timestamp;
75
76         memset(&gps_event, 0, sizeof(gps_event_info_t));
77         time(&timestamp);
78
79         gps_event.event_id = GPS_EVENT_REPORT_POSITION;
80
81         if (data == NULL) {
82                 LOG_PLUGIN(DBG_ERR, "NULL POS data.");
83                 gps_event.event_data.pos_ind.error = GPS_ERR_COMMUNICATION;
84         } else {
85                 gps_event.event_data.pos_ind.error = GPS_ERR_NONE;
86                 gps_event.event_data.pos_ind.pos.timestamp = timestamp;
87                 gps_event.event_data.pos_ind.pos.latitude = data->latitude;
88                 gps_event.event_data.pos_ind.pos.longitude = data->longitude;
89                 gps_event.event_data.pos_ind.pos.altitude = data->altitude;
90                 gps_event.event_data.pos_ind.pos.speed = data->speed;
91                 gps_event.event_data.pos_ind.pos.bearing = data->bearing;
92                 gps_event.event_data.pos_ind.pos.hor_accuracy = data->hor_accuracy;
93                 gps_event.event_data.pos_ind.pos.ver_accuracy = data->ver_accuracy;
94         }
95
96         //LOG_PLUGIN(DBG_LOW, "%d", gps_event.event_data.pos_ind.pos.timestamp);
97
98         if (g_gps_event_cb != NULL) {
99                 g_gps_event_cb(&gps_event);
100         }
101 }
102
103 void gps_plugin_replay_sv_event(sv_data_t * data)
104 {
105         int i;
106         gps_event_info_t gps_event;
107         time_t timestamp;
108
109         memset(&gps_event, 0, sizeof(gps_event_info_t));
110         time(&timestamp);
111         gps_event.event_id = GPS_EVENT_REPORT_SATELLITE;
112
113         if (data == NULL) {
114                 LOG_PLUGIN(DBG_ERR, "NULL SV data.");
115                 gps_event.event_data.sv_ind.error = GPS_ERR_COMMUNICATION;
116         } else {
117                 gps_event.event_data.sv_ind.error = GPS_ERR_NONE;
118                 gps_event.event_data.sv_ind.sv.timestamp = timestamp;
119                 gps_event.event_data.sv_ind.sv.pos_valid = data->pos_valid;
120                 gps_event.event_data.sv_ind.sv.num_of_sat = data->num_of_sat;
121                 for (i = 0; i < data->num_of_sat; i++) {
122                         gps_event.event_data.sv_ind.sv.sat[i].used = data->sat[i].used;
123                         gps_event.event_data.sv_ind.sv.sat[i].prn = data->sat[i].prn;
124                         gps_event.event_data.sv_ind.sv.sat[i].snr = data->sat[i].snr;
125                         gps_event.event_data.sv_ind.sv.sat[i].elevation = data->sat[i].elevation;
126                         gps_event.event_data.sv_ind.sv.sat[i].azimuth = data->sat[i].azimuth;
127                 }
128         }
129
130         if (g_gps_event_cb != NULL) {
131                 g_gps_event_cb(&gps_event);
132         }
133 }
134
135 void gps_plugin_replay_nmea_event(nmea_data_t * data)
136 {
137         gps_event_info_t gps_event;
138         time_t timestamp;
139
140         memset(&gps_event, 0, sizeof(gps_event_info_t));
141         time(&timestamp);
142
143         gps_event.event_id = GPS_EVENT_REPORT_NMEA;
144
145         if (data == NULL) {
146                 LOG_PLUGIN(DBG_ERR, "NULL NMEA data.");
147                 gps_event.event_data.nmea_ind.error = GPS_ERR_COMMUNICATION;
148         } else {
149                 if (data->len > REPLAY_NMEA_SENTENCE_SIZE) {
150                         LOG_PLUGIN(DBG_WARN, "The Size of NMEA[ %d ] is larger then max ", data->len);
151                         data->len = REPLAY_NMEA_SENTENCE_SIZE;
152                         gps_event.event_data.nmea_ind.error = GPS_ERR_COMMUNICATION;
153                 } else {
154                         gps_event.event_data.nmea_ind.error = GPS_ERR_NONE;
155                 }
156                 gps_event.event_data.nmea_ind.nmea.timestamp = timestamp;
157                 gps_event.event_data.nmea_ind.nmea.len = data->len;
158                 gps_event.event_data.nmea_ind.nmea.data = (char *)malloc(data->len);
159                 memset(gps_event.event_data.nmea_ind.nmea.data, 0x00, data->len);
160                 memcpy(gps_event.event_data.nmea_ind.nmea.data, data->data, data->len);
161                 //LOG_PLUGIN(DBG_LOW, "NMEA[%d] : %s", gps_event.event_data.nmea_ind.nmea.len, gps_event.event_data.nmea_ind.nmea.data);
162         }
163
164         if (g_gps_event_cb != NULL) {
165                 g_gps_event_cb(&gps_event);
166         }
167
168         if (gps_event.event_data.nmea_ind.nmea.data != NULL) {
169                 free(gps_event.event_data.nmea_ind.nmea.data);
170                 gps_event.event_data.nmea_ind.nmea.data = NULL;
171         }
172 }
173
174 void gps_plugin_respond_start_session(gboolean ret)
175 {
176         gps_event_info_t gps_event;
177         gps_event.event_id = GPS_EVENT_START_SESSION;
178
179         if (ret == TRUE) {
180                 gps_event.event_data.start_session_rsp.error = GPS_ERR_NONE;
181         } else {
182                 gps_event.event_data.start_session_rsp.error = GPS_ERR_COMMUNICATION;
183         }
184
185         if (g_gps_event_cb != NULL) {
186                 g_gps_event_cb(&gps_event);
187         }
188 }
189
190 void gps_plugin_respond_stop_session(void)
191 {
192         gps_event_info_t gps_event;
193
194         gps_event.event_id = GPS_EVENT_STOP_SESSION;
195         gps_event.event_data.stop_session_rsp.error = GPS_ERR_NONE;
196
197         if (g_gps_event_cb != NULL) {
198                 g_gps_event_cb(&gps_event);
199         }
200 }
201
202 gboolean gps_plugin_replay_read_nmea(replay_timeout * timer, char *nmea_data)
203 {
204         gboolean ret = FALSE;
205         int ref = 0;
206         char buf[REPLAY_NMEA_SENTENCE_SIZE] = { 0, };
207
208         if (timer->fd == NULL) {
209                 LOG_PLUGIN(DBG_ERR, "nmea fd is NULL");
210                 return FALSE;
211         }
212
213         if (nmea_data == NULL) {
214                 LOG_PLUGIN(DBG_ERR, "nmea_data is NULL");
215                 fclose(timer->fd);
216                 timer->fd = NULL;
217                 return FALSE;
218         }
219
220         while (fgets(buf, REPLAY_NMEA_SENTENCE_SIZE, timer->fd) != NULL) {
221                 if (strncmp(buf, "$GPGGA", 6) == 0) {
222                         ref++;
223                         if (ref > 1) {
224                                 fseek(timer->fd, -strlen(buf), SEEK_CUR);
225                                 LOG_PLUGIN(DBG_LOW, "2nd GPGGA : stop to read nmea data");
226                                 ret = TRUE;
227                                 break;
228                         } else if (ref == 1) {
229                                 LOG_PLUGIN(DBG_LOW, "1st GPGGA : start to read nmea data");
230                                 strncpy(nmea_data, buf, strlen(buf));
231                         }
232                 } else {
233                         if (strlen(nmea_data) + strlen(buf) > REPLAY_NMEA_SET_SIZE) {
234                                 LOG_PLUGIN(DBG_ERR, "read nmea data size is too long");
235                                 break;
236                         } else {
237                                 strncat(nmea_data, buf, strlen(buf));
238                         }
239                 }
240                 timer->nmea_data->len = strlen(buf);
241                 timer->nmea_data->data = buf;
242                 gps_plugin_replay_nmea_event(timer->nmea_data);
243         }
244
245         if (feof(timer->fd)) {
246                 LOG_PLUGIN(DBG_ERR, "end of file");
247                 rewind(timer->fd);
248                 ret = TRUE;
249         } else {
250                 LOG_PLUGIN(DBG_LOW, "read nmea data [%s]", nmea_data);
251         }
252         return ret;
253 }
254
255 gboolean gps_plugin_replay_read_manual(pos_data_t * pos_data)
256 {
257         gboolean ret = TRUE;
258
259         if (setting_get_double(VCONFKEY_LOCATION_MANUAL_LATITUDE, &pos_data->latitude) == FALSE) {
260                 LOG_PLUGIN(DBG_ERR, "Fail to get latitude");
261                 ret = FALSE;
262         }
263         if (setting_get_double(VCONFKEY_LOCATION_MANUAL_LONGITUDE, &pos_data->longitude) == FALSE) {
264                 LOG_PLUGIN(DBG_ERR, "Fail to get longitude");
265                 ret = FALSE;
266         }
267         if (setting_get_double(VCONFKEY_LOCATION_MANUAL_ALTITUDE, &pos_data->altitude) == FALSE) {
268                 LOG_PLUGIN(DBG_ERR, "Fail to get altitude");
269                 ret = FALSE;
270         }
271
272         return ret;
273 }
274
275 gboolean gps_plugin_replay_timeout_cb(gpointer data)
276 {
277         gboolean ret = FALSE;
278         read_error_t err = READ_SUCCESS;
279         char nmea_data[REPLAY_NMEA_SET_SIZE] = { 0, };
280         replay_timeout *timer = (replay_timeout *) data;
281
282         if (timer == NULL) {
283                 LOG_PLUGIN(DBG_ERR, "replay handel[timer] is NULL");
284                 return FALSE;
285         }
286
287         memset(timer->pos_data, 0, sizeof(pos_data_t));
288         memset(timer->sv_data, 0, sizeof(sv_data_t));
289
290         if (timer->replay_mode == REPLAY_NMEA) {
291                 if (gps_plugin_replay_read_nmea(timer, nmea_data) == FALSE) {
292                         LOG_PLUGIN(DBG_ERR, "Fail to read nmea data from file");
293                         return FALSE;
294                 } else {
295                         err = nmea_parser(nmea_data, timer->pos_data, timer->sv_data);
296                         if (err == READ_ERROR) {
297                                 LOG_PLUGIN(DBG_ERR, "Fail to parser nmea data from file");
298                                 return FALSE;
299                         } else if (err == READ_NOT_FIXED) {
300                                 LOG_PLUGIN(DBG_LOW, "GPS position is not fixed");
301                                 timer->sv_data->pos_valid = FALSE;
302                         }
303                 }
304         } else if (timer->replay_mode == REPLAY_MANUAL) {
305                 if (gps_plugin_replay_read_manual(timer->pos_data) == FALSE) {
306                         LOG_PLUGIN(DBG_ERR, "Fail to read manual data");
307                         err = READ_ERROR;
308                         return FALSE;
309                 } else {
310                         timer->sv_data->pos_valid = TRUE;
311                         err = READ_SUCCESS;
312                 }
313         } else if (timer->replay_mode == REPLAY_OFF) {
314                 LOG_PLUGIN(DBG_WARN, "replay_mode is OFF");
315                 err = READ_NOT_FIXED;
316                 timer->sv_data->pos_valid = FALSE;
317         }
318
319         if (g_gps_event_cb != NULL) {
320                 if (err != READ_NOT_FIXED) {
321                         gps_plugin_replay_pos_event(timer->pos_data);
322                 }
323                 gps_plugin_replay_sv_event(timer->sv_data);
324         }
325         ret = TRUE;
326         return ret;
327 }
328
329 void gps_plugin_stop_replay_mode(replay_timeout * timer)
330 {
331         if (timer->replay_mode == REPLAY_NMEA && fclose(timer->fd) != 0) {
332                 LOG_PLUGIN(DBG_ERR, "fclose failed");
333         }
334         timer->fd = NULL;
335
336         if (timer->timeout_src != NULL && timer->default_context != NULL && !g_source_is_destroyed(timer->timeout_src)) {
337                 if (timer->default_context == g_source_get_context(timer->timeout_src)) {
338                         g_source_destroy(timer->timeout_src);
339                         LOG_PLUGIN(DBG_LOW, "g_source_destroy timeout_src");
340                 } else {
341                         LOG_PLUGIN(DBG_WARN, "timer->timeout_src is attatched to 0x%x (actual 0x%x)",
342                                    g_source_get_context(timer->timeout_src), timer->default_context);
343                 }
344                 timer->timeout_src = NULL;
345                 timer->default_context = NULL;
346         } else {
347                 LOG_PLUGIN(DBG_WARN, "timeout_src or default_context is NULL or timeout_src is already destroyed");
348         }
349         gps_plugin_respond_stop_session();
350 }
351
352 gboolean gps_plugin_get_nmea_fd(replay_timeout * timer)
353 {
354         char replay_file_path[256];
355
356         snprintf(replay_file_path, sizeof(replay_file_path), NMEA_FILE_PATH"%s", setting_get_string(VCONFKEY_LOCATION_NMEA_FILE_NAME));
357         LOG_PLUGIN(DBG_ERR, "replay file name : %s", replay_file_path);
358
359         timer->fd = fopen(replay_file_path, "r");
360         if (timer->fd == NULL) {
361                 LOG_PLUGIN(DBG_ERR, "fopen(%s) failed", replay_file_path);
362                 timer->fd = fopen(DEFAULT_NMEA_LOG, "r");
363                 if (timer->fd == NULL) {
364                         LOG_PLUGIN(DBG_ERR, "fopen(%s) failed", DEFAULT_NMEA_LOG);
365                         return FALSE;
366                 }
367         }
368         return TRUE;
369 }
370
371 gboolean gps_plugin_start_replay_mode(replay_timeout * timer)
372 {
373         gboolean ret = FALSE;
374
375         if (timer->replay_mode == REPLAY_NMEA) {
376                 if (gps_plugin_get_nmea_fd(timer) == FALSE) {
377                         return FALSE;
378                 }
379         }
380
381         if (timer->default_context == NULL) {
382                 timer->default_context = g_main_context_default();
383                 if (timer->default_context == NULL) {
384                         return ret;
385                 }
386         }
387
388         if (timer->timeout_src != NULL) {
389                 LOG_PLUGIN(DBG_ERR, "timeout_src is already existed");
390                 ret = FALSE;
391         } else {
392                 timer->timeout_src = g_timeout_source_new_seconds(timer->interval);
393                 if (timer->timeout_src != NULL) {
394                         g_source_set_callback(timer->timeout_src, &gps_plugin_replay_timeout_cb, timer, NULL);
395                         if (g_source_attach(timer->timeout_src, timer->default_context) > 0) {
396                                 LOG_PLUGIN(DBG_LOW, "timeout_src(0x%x) is created & attatched to 0x%x", timer->timeout_src,
397                                            timer->default_context);
398                                 ret = TRUE;
399                         } else {
400                                 gps_plugin_stop_replay_mode(timer);
401                                 ret = FALSE;
402                         }
403                 }
404         }
405         gps_plugin_respond_start_session(ret);
406
407         return ret;
408 }
409
410 static void replay_mode_changed_cb(keynode_t * key, void *data)
411 {
412         if (setting_get_int(VCONFKEY_LOCATION_REPLAY_MODE, &g_replay_timer->replay_mode) == FALSE) {
413                 g_replay_timer->replay_mode = REPLAY_OFF;
414         }
415
416         if (g_replay_timer->replay_mode == REPLAY_NMEA) {
417                 if (gps_plugin_get_nmea_fd(g_replay_timer) == FALSE) {
418                         LOG_PLUGIN(DBG_ERR, "Fail to get nmea fd.");
419                 }
420         } else {
421                 if (g_replay_timer->fd != NULL) {
422                         fclose(g_replay_timer->fd);
423                         g_replay_timer->fd = NULL;
424                 }
425         }
426         return;
427 }
428
429 replay_timeout *gps_plugin_replay_timer_init()
430 {
431         replay_timeout *timer = NULL;
432
433         timer = (replay_timeout *) malloc(sizeof(replay_timeout));
434         if (timer == NULL) {
435                 LOG_PLUGIN(DBG_ERR, "replay_timeout allocation is failed.");
436                 return NULL;
437         }
438
439         timer->fd = NULL;
440         timer->interval = 1;
441         if (setting_get_int(VCONFKEY_LOCATION_REPLAY_MODE, &timer->replay_mode) == FALSE) {
442                 timer->replay_mode = REPLAY_OFF;
443         }
444         setting_notify_key_changed(VCONFKEY_LOCATION_REPLAY_MODE, replay_mode_changed_cb);
445
446         timer->pos_data = (pos_data_t *) malloc(sizeof(pos_data_t));
447         if (timer->pos_data == NULL) {
448                 LOG_PLUGIN(DBG_ERR, "pos_data allocation is failed.");
449                 free(timer);
450                 return NULL;
451         }
452
453         timer->sv_data = (sv_data_t *) malloc(sizeof(sv_data_t));
454         if (timer->sv_data == NULL) {
455                 LOG_PLUGIN(DBG_ERR, "sv_data allocation is failed.");
456                 free(timer->pos_data);
457                 free(timer);
458                 return NULL;
459         }
460
461         timer->nmea_data = (nmea_data_t *) malloc(sizeof(nmea_data_t));
462         if (timer->nmea_data == NULL) {
463                 LOG_PLUGIN(DBG_ERR, "nmea_data allocation is failed.");
464                 free(timer->pos_data);
465                 free(timer->sv_data);
466                 free(timer);
467                 return NULL;
468         }
469
470         timer->timeout_src = NULL;
471         timer->default_context = NULL;
472
473         return timer;
474 }
475
476 void gps_plugin_replay_timer_deinit(replay_timeout * timer)
477 {
478         if (timer == NULL) {
479                 return;
480         }
481
482         if (timer->pos_data != NULL) {
483                 free(timer->pos_data);
484                 timer->pos_data = NULL;
485         }
486         if (timer->sv_data != NULL) {
487                 free(timer->sv_data);
488                 timer->sv_data = NULL;
489         }
490         if (timer->nmea_data != NULL) {
491                 free(timer->nmea_data);
492                 timer->nmea_data = NULL;
493         }
494
495         setting_ignore_key_changed(VCONFKEY_LOCATION_REPLAY_MODE, replay_mode_changed_cb);
496
497         free(timer);
498         timer = NULL;
499 }
500
501 int gps_plugin_replay_gps_init(gps_event_cb gps_event_cb, gps_server_param_t * gps_params)
502 {
503         g_gps_event_cb = gps_event_cb;
504         g_replay_timer = gps_plugin_replay_timer_init();
505
506         return TRUE;
507 }
508
509 int gps_plugin_replay_gps_deinit(gps_failure_reason_t * reason_code)
510 {
511         gps_plugin_replay_timer_deinit(g_replay_timer);
512
513         return TRUE;
514 }
515
516 int gps_plugin_replay_gps_request(gps_action_t gps_action, void *data, gps_failure_reason_t * reason_code)
517 {
518         switch (gps_action) {
519         case GPS_ACTION_SEND_PARAMS:
520                 break;
521         case GPS_ACTION_START_SESSION:
522                 gps_plugin_start_replay_mode(g_replay_timer);
523                 break;
524         case GPS_ACTION_STOP_SESSION:
525                 gps_plugin_stop_replay_mode(g_replay_timer);
526                 break;
527         case GPS_INDI_SUPL_VERIFICATION:
528         case GPS_INDI_SUPL_DNSQUERY:
529         case GPS_ACTION_START_FACTTEST:
530         case GPS_ACTION_STOP_FACTTEST:
531         case GPS_ACTION_REQUEST_SUPL_NI:
532                 LOG_PLUGIN(DBG_LOW, "Don't use action type : [ %d ]", gps_action);
533                 break;
534         default:
535                 break;
536         }
537
538         return TRUE;
539 }
540
541 EXPORT_API const gps_plugin_interface *get_gps_plugin_interface()
542 {
543         return &g_gps_plugin_replay_interface;
544 }