Tizen 2.1 base
[platform/core/location/location-module.git] / modules / geoclue-gpsd.c
1 /*
2  * location-geoclue-gpsd
3  *
4  * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd. All rights reserved.
5  *
6  * Contact: Youngae Kang <youngae.kang@samsung.com>, Yunhan Kim <yhan.kim@samsung.com>,
7  *          Genie Kim <daejins.kim@samsung.com>, Minjune Kim <sena06.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 <glib.h>
23
24 #include <location-module.h>
25
26 #include <geoclue/geoclue-position.h>
27 #include <geoclue/geoclue-velocity.h>
28 #include <geoclue/geoclue-provider.h>
29 #include <dlfcn.h>
30
31 #ifdef HAVE_CONFIG_H
32 #include "config.h"
33 #endif
34 #include "log.h"
35
36 typedef struct{
37         char devname[256];
38         GeocluePosition *pos;
39         GeoclueVelocity *vel;
40         LocModStatusCB status_cb;
41         LocModPositionCB pos_cb;
42         LocModVelocityCB vel_cb;
43         gpointer userdata;
44         gboolean is_started;
45 } GeoclueGpsdData;
46
47 static void
48 status_callback (GeoclueProvider *provider,
49                                         gint             status,
50                                         gpointer                 userdata)
51 {
52         GeoclueGpsdData* gpsd = (GeoclueGpsdData*)userdata;
53         g_return_if_fail(gpsd->status_cb);
54
55         switch(status){
56                 case GEOCLUE_STATUS_ERROR:
57                 case GEOCLUE_STATUS_UNAVAILABLE:
58                 case GEOCLUE_STATUS_ACQUIRING:
59                         MOD_LOGD("Status callback>> GEOCLUE_STATUS_ACQUIRING/ERROR/UNAVAILABLE");
60                         gpsd->status_cb(FALSE, LOCATION_STATUS_NO_FIX, gpsd->userdata);
61                         break;
62                 case GEOCLUE_STATUS_AVAILABLE:
63                         MOD_LOGD("Status callback>> GEOCLUE_STATUS_AVAILABLE");
64                         gpsd->status_cb(TRUE, LOCATION_STATUS_3D_FIX, gpsd->userdata);
65                         break;
66                 default:
67                         break;
68                 }
69 }
70
71 static void
72 position_callback (GeocluePosition      *position,
73                    GeocluePositionFields fields,
74                    int                   timestamp,
75                    double                latitude,
76                    double                longitude,
77                    double                altitude,
78                    GeoclueAccuracy      *accuracy,
79                    gpointer              userdata)
80 {
81         GeoclueGpsdData* gpsd = (GeoclueGpsdData*)userdata;
82         g_return_if_fail(gpsd->pos_cb);
83
84         GeoclueAccuracyLevel level;
85         double horiz_acc;
86         double vert_acc;
87         geoclue_accuracy_get_details (accuracy, &level, &horiz_acc, &vert_acc);
88
89         LocationPosition *pos = NULL;
90         LocationAccuracy *acc = NULL;
91
92         if (fields & GEOCLUE_POSITION_FIELDS_LATITUDE &&
93                 fields & GEOCLUE_POSITION_FIELDS_LONGITUDE) {
94                 if(fields & GEOCLUE_POSITION_FIELDS_ALTITUDE)
95                         pos = location_position_new (timestamp, latitude, longitude, altitude, LOCATION_STATUS_3D_FIX);
96                 else pos = location_position_new (timestamp, latitude, longitude, 0, LOCATION_STATUS_2D_FIX);
97         } else pos = location_position_new (0, 0, 0, 0, LOCATION_STATUS_NO_FIX);
98
99         if (accuracy) {
100                 GeoclueAccuracyLevel level;
101                 double horiz_acc;
102                 double vert_acc;
103                 geoclue_accuracy_get_details (accuracy, &level, &horiz_acc, &vert_acc);
104                 acc = location_accuracy_new (LOCATION_ACCURACY_LEVEL_DETAILED, horiz_acc, vert_acc);
105         } else acc = location_accuracy_new (LOCATION_ACCURACY_LEVEL_NONE, horiz_acc, vert_acc);
106
107         MOD_LOGD("Position callback>> time(%d) lat(%f) long(%f) alt(%f) status(%d) acc_level(%d) hoz_acc(%f) vert_acc(%f)",
108                 pos->timestamp, pos->latitude, pos->longitude, pos->altitude,  pos->status,
109                 acc->level, acc->horizontal_accuracy, acc->vertical_accuracy);
110         gpsd->pos_cb(TRUE, pos, acc, gpsd->userdata);
111         location_position_free (pos);
112         location_accuracy_free (acc);
113 }
114
115 static void
116 velocity_callback (GeoclueVelocity *velocity,
117                    GeoclueVelocityFields fields,
118                    int                   timestamp,
119                    double                speed,
120                    double                direction,
121                    double                climb,
122                    gpointer              userdata)
123 {
124         GeoclueGpsdData* gpsd = (GeoclueGpsdData*)userdata;
125         g_return_if_fail(gpsd->vel_cb);
126
127         LocationVelocity *vel = NULL;
128         LocationAccuracy *acc = NULL;
129
130         if (fields & GEOCLUE_VELOCITY_FIELDS_SPEED &&
131                 fields & GEOCLUE_VELOCITY_FIELDS_DIRECTION) {
132                 if (fields & GEOCLUE_VELOCITY_FIELDS_CLIMB) vel = location_velocity_new (timestamp, speed, direction, climb);
133                 else vel = location_velocity_new (timestamp, speed, direction, 0);
134                 acc = location_accuracy_new (LOCATION_ACCURACY_LEVEL_DETAILED, 0, 0);
135         } else {
136                 vel = location_velocity_new (0, 0, 0, 0);
137                 acc = location_accuracy_new (LOCATION_ACCURACY_LEVEL_NONE, 0, 0);
138         }
139         MOD_LOGD("Velocity callback>> timestamp(%d) speed(%f) direction(%f) climb(%f) acc_level(%d) hoz_acc(%f) vert_acc(%f)",
140                 vel->timestamp, vel->speed, vel->direction, vel->climb,
141                 acc->level, acc->horizontal_accuracy, acc->vertical_accuracy);
142
143         gpsd->vel_cb(TRUE, vel, acc, gpsd->userdata);
144         location_velocity_free (vel);
145         location_accuracy_free (acc);
146 }
147
148 static void
149 _unref_geoclue(GeoclueGpsdData* gpsd)
150 {
151         if(gpsd->pos) {
152                 g_signal_handlers_disconnect_by_func(G_OBJECT (GEOCLUE_PROVIDER(gpsd->pos)), G_CALLBACK (status_callback), gpsd);
153                 g_signal_handlers_disconnect_by_func(G_OBJECT (GEOCLUE_PROVIDER(gpsd->pos)), G_CALLBACK (position_callback), gpsd);
154                 g_object_unref (gpsd->pos);
155                 gpsd->pos = NULL;
156         }
157
158         if( gpsd->vel != NULL){
159                 g_signal_handlers_disconnect_by_func(G_OBJECT (GEOCLUE_PROVIDER(gpsd->vel)), G_CALLBACK (velocity_callback), gpsd);
160                 g_object_unref (gpsd->vel);
161                 gpsd->vel = NULL;
162         }
163         gpsd->is_started = FALSE;
164 }
165
166 static gboolean
167 _ref_geoclue(GeoclueGpsdData* gpsd)
168 {
169         if(gpsd->is_started == TRUE){
170                 MOD_LOGW ("geoclue-gpsd is alredy started");
171                 return TRUE;
172         }
173
174         gchar *service, *path;
175         service = g_strdup_printf ("org.freedesktop.Geoclue.Providers.Gpsd");
176         path = g_strdup_printf ("/org/freedesktop/Geoclue/Providers/Gpsd");
177
178         if(!gpsd->pos){
179                 gpsd->pos = geoclue_position_new (service, path);
180         }
181         if(!gpsd->vel){
182                 gpsd->vel = geoclue_velocity_new (service, path);
183         }
184         g_free (service);
185         g_free (path);
186         if(!gpsd->pos || !gpsd->vel){
187                 MOD_LOGW ("Error while creating Geoclue object.");
188                 _unref_geoclue(gpsd);
189                 return FALSE;
190         }
191
192         gpsd->is_started = TRUE;
193         g_signal_connect (G_OBJECT (GEOCLUE_PROVIDER(gpsd->pos)), "status-changed", G_CALLBACK (status_callback), gpsd);
194         g_signal_connect (G_OBJECT (GEOCLUE_PROVIDER(gpsd->pos)), "position-changed", G_CALLBACK (position_callback), gpsd);
195         g_signal_connect (G_OBJECT (GEOCLUE_PROVIDER(gpsd->vel)), "velocity-changed", G_CALLBACK (velocity_callback), gpsd);
196
197         return TRUE;
198 }
199
200 static int
201 start(gpointer handle, LocModStatusCB status_cb, LocModPositionCB pos_cb, LocModVelocityCB vel_cb, gpointer userdata)
202 {
203         MOD_LOGD("start");
204         GeoclueGpsdData* gpsd = (GeoclueGpsdData*)handle;
205         g_return_val_if_fail(gpsd, LOCATION_ERROR_NOT_AVAILABLE);
206         g_return_val_if_fail(status_cb, LOCATION_ERROR_NOT_AVAILABLE);
207         g_return_val_if_fail(pos_cb, LOCATION_ERROR_NOT_AVAILABLE);
208         g_return_val_if_fail(vel_cb, LOCATION_ERROR_NOT_AVAILABLE);
209
210         gpsd->status_cb = status_cb;
211         gpsd->pos_cb = pos_cb;
212         gpsd->vel_cb = vel_cb;
213         gpsd->userdata = userdata;
214         if (!_ref_geoclue(gpsd)) return LOCATION_ERROR_NOT_AVAILABLE;
215         return LOCATION_ERROR_NONE;
216 }
217
218 static int
219 stop(gpointer handle)
220 {
221         MOD_LOGD("stop");
222         GeoclueGpsdData* gpsd = (GeoclueGpsdData*)handle;
223         g_return_val_if_fail(gpsd, LOCATION_ERROR_NOT_AVAILABLE);
224         g_return_val_if_fail(gpsd->status_cb, LOCATION_ERROR_NOT_AVAILABLE);
225         _unref_geoclue(gpsd);
226         gpsd->status_cb(FALSE, LOCATION_STATUS_NO_FIX, gpsd->userdata);
227         return LOCATION_ERROR_NONE;
228 }
229
230 static int
231 get_position(
232         gpointer         handle,
233         LocationPosition **position,
234         LocationAccuracy **accuracy)
235 {
236         GeoclueGpsdData* gpsd = (GeoclueGpsdData*)handle;
237         g_return_val_if_fail(gpsd, LOCATION_ERROR_NOT_AVAILABLE);
238         g_return_val_if_fail(gpsd->pos, LOCATION_ERROR_NOT_AVAILABLE);
239         g_return_val_if_fail(position, LOCATION_ERROR_PARAMETER);
240         g_return_val_if_fail(accuracy, LOCATION_ERROR_PARAMETER);
241
242         GeocluePositionFields fields;
243         int timestamp;
244         double lat, lon, alt;
245         GeoclueAccuracy *_accuracy = NULL;
246         GError *error = NULL;
247
248         fields = geoclue_position_get_position (gpsd->pos, &timestamp,
249                                                 &lat, &lon, &alt,
250                                                 &_accuracy, &error);
251         if (error) {
252                 MOD_LOGD ("Error getting position: %s", error->message);
253                 g_error_free (error);
254                 return LOCATION_ERROR_NOT_AVAILABLE;
255         }
256
257         if (fields & GEOCLUE_POSITION_FIELDS_LATITUDE &&
258                 fields & GEOCLUE_POSITION_FIELDS_LONGITUDE) {
259                 if(fields & GEOCLUE_POSITION_FIELDS_ALTITUDE) *position = location_position_new (timestamp, lat, lon, alt, LOCATION_STATUS_3D_FIX);
260                 else *position = location_position_new (timestamp, lat, lon, 0, LOCATION_STATUS_2D_FIX);
261         } else *position = location_position_new (0, 0, 0, 0, LOCATION_STATUS_NO_FIX);
262
263         if (_accuracy) {
264                 GeoclueAccuracyLevel level;
265                 double horiz_acc;
266                 double vert_acc;
267                 geoclue_accuracy_get_details (_accuracy, &level, &horiz_acc, &vert_acc);
268                 *accuracy = location_accuracy_new (LOCATION_ACCURACY_LEVEL_DETAILED, horiz_acc, vert_acc);
269                 geoclue_accuracy_free (_accuracy);
270         } else *accuracy = location_accuracy_new (LOCATION_ACCURACY_LEVEL_NONE, 0, 0);
271
272         return LOCATION_ERROR_NONE;
273 }
274
275 static int
276 get_velocity(
277         gpointer         handle,
278         LocationVelocity **velocity,
279         LocationAccuracy **accuracy)
280 {
281         GeoclueGpsdData* gpsd = (GeoclueGpsdData*)handle;
282         g_return_val_if_fail(gpsd, LOCATION_ERROR_NOT_AVAILABLE);
283         g_return_val_if_fail(gpsd->vel, LOCATION_ERROR_NOT_AVAILABLE);
284         g_return_val_if_fail(velocity, LOCATION_ERROR_PARAMETER);
285         g_return_val_if_fail(accuracy, LOCATION_ERROR_PARAMETER);
286
287         GeoclueVelocityFields fields;
288         int timestamp;
289         double spd, dir, climb;
290         GError *error = NULL;
291
292         fields = geoclue_velocity_get_velocity (gpsd->vel, &timestamp,
293                                                 &spd, &dir, &climb,
294                                                 &error);
295         if (error) {
296                 MOD_LOGD ("Error getting velocity: %s", error->message);
297                 g_error_free (error);
298                 return LOCATION_ERROR_NOT_AVAILABLE;
299         }
300
301         if (fields & GEOCLUE_VELOCITY_FIELDS_SPEED &&
302                 fields & GEOCLUE_VELOCITY_FIELDS_DIRECTION) {
303                 if (fields & GEOCLUE_VELOCITY_FIELDS_CLIMB) *velocity = location_velocity_new (timestamp, spd, dir, climb);
304                 else *velocity = location_velocity_new (timestamp, spd, dir, 0);
305                 *accuracy = location_accuracy_new (LOCATION_ACCURACY_LEVEL_DETAILED, 0, 0);
306         } else {
307                 *velocity = location_velocity_new (0, 0, 0, 0);
308                 *accuracy = location_accuracy_new (LOCATION_ACCURACY_LEVEL_NONE, 0, 0);
309         }
310         return LOCATION_ERROR_NONE;
311 }
312
313 static int
314 get_nmea(gpointer handle,
315         char **nmea_data)
316 {
317         MOD_LOGD("get_nmea: not available");
318         return LOCATION_ERROR_NOT_AVAILABLE;
319 }
320
321 static int
322 get_satellite(gpointer handle,
323         LocationSatellite **satellite)
324 {
325         MOD_LOGD("get_satellite: not available");
326         return LOCATION_ERROR_NOT_AVAILABLE;
327 }
328
329 static int
330 set_devname(gpointer handle,
331         const char *devname)
332 {
333         GeoclueGpsdData* gpsd = (GeoclueGpsdData*)handle;
334         g_return_val_if_fail(gpsd, LOCATION_ERROR_NOT_AVAILABLE);
335         g_return_val_if_fail(gpsd->devname, LOCATION_ERROR_NOT_AVAILABLE);
336         g_return_val_if_fail(devname, LOCATION_ERROR_PARAMETER);
337         MOD_LOGD("set_devname: %s --> %s", gpsd->devname, devname);
338         g_stpcpy(gpsd->devname, devname);
339
340         return LOCATION_ERROR_NONE;
341 }
342
343
344 static int
345 get_devname(gpointer handle,
346         char **devname)
347 {
348         GeoclueGpsdData* gpsd = (GeoclueGpsdData*)handle;
349         g_return_val_if_fail(gpsd, LOCATION_ERROR_NOT_AVAILABLE);
350         g_return_val_if_fail(gpsd->devname, LOCATION_ERROR_NOT_AVAILABLE);
351         g_return_val_if_fail(devname, LOCATION_ERROR_PARAMETER);
352
353         *devname = g_strdup(gpsd->devname);
354         MOD_LOGD("get_devname: %s", *devname);
355
356         return LOCATION_ERROR_NONE;
357 }
358
359 LOCATION_MODULE_API gpointer
360 init(LocModGpsOps* ops)
361 {
362         MOD_LOGD("init");
363         g_return_val_if_fail(ops, NULL);
364         ops->start = start;
365         ops->stop = stop ;
366         ops->get_position = get_position;
367         ops->get_velocity = get_velocity;
368         Dl_info info;
369         if (dladdr(&get_position, &info) == 0) {
370                 MOD_LOGD("failed to get module name");
371         } else if (g_str_has_prefix(info.dli_fname, "gps")) {
372                 ops->get_nmea = get_nmea;
373                 ops->get_satellite = get_satellite;
374                 ops->set_devname = set_devname;
375                 ops->get_devname = get_devname;
376         }
377
378         GeoclueGpsdData* gpsd = g_new0(GeoclueGpsdData, 1);
379         g_return_val_if_fail(gpsd, NULL);
380
381         g_stpcpy(gpsd->devname, "/dev/rfcomm0");
382         gpsd->pos = NULL;
383         gpsd->vel = NULL;
384         gpsd->status_cb= NULL;
385         gpsd->pos_cb = NULL;
386         gpsd->vel_cb = NULL;
387         gpsd->userdata = NULL;
388         gpsd->is_started = FALSE;
389
390         return (gpointer)gpsd;
391 }
392
393 LOCATION_MODULE_API void
394 shutdown(gpointer handle)
395 {
396         MOD_LOGD("shutdown");
397         GeoclueGpsdData* gpsd = (GeoclueGpsdData*)handle;
398         g_return_if_fail(gpsd);
399         _unref_geoclue(gpsd);
400         if(gpsd->status_cb) gpsd->status_cb(FALSE, LOCATION_STATUS_NO_FIX, gpsd->userdata);
401         g_free(gpsd);
402 }