1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "content/browser/geolocation/libgps_wrapper_linux.h"
11 #include "base/logging.h"
12 #include "base/stringprintf.h"
13 #include "content/public/common/geoposition.h"
14 #include "third_party/gpsd/release-3.1/gps.h"
16 COMPILE_ASSERT(GPSD_API_MAJOR_VERSION
== 5, GPSD_API_version_is_not_5
);
20 const char kLibGpsName
[] = "libgps.so.20";
23 LibGps::LibGps(void* dl_handle
,
25 gps_close_fn gps_close
,
27 : dl_handle_(dl_handle
),
29 gps_close_(gps_close
),
31 gps_data_(new gps_data_t
),
41 const int err
= dlclose(dl_handle_
);
42 DCHECK_EQ(0, err
) << "Error closing dl handle: " << err
;
46 LibGps
* LibGps::New() {
47 void* dl_handle
= dlopen(kLibGpsName
, RTLD_LAZY
);
49 DLOG(WARNING
) << "Could not open " << kLibGpsName
<< ": " << dlerror();
53 DLOG(INFO
) << "Loaded " << kLibGpsName
;
55 #define DECLARE_FN_POINTER(function) \
56 function##_fn function = reinterpret_cast<function##_fn>( \
57 dlsym(dl_handle, #function)); \
59 DLOG(WARNING) << "libgps " << #function << " error: " << dlerror(); \
63 DECLARE_FN_POINTER(gps_open
);
64 DECLARE_FN_POINTER(gps_close
);
65 DECLARE_FN_POINTER(gps_read
);
66 // We don't use gps_shm_read() directly, just to make sure that libgps has
67 // the shared memory support.
68 typedef int (*gps_shm_read_fn
)(struct gps_data_t
*);
69 DECLARE_FN_POINTER(gps_shm_read
);
70 #undef DECLARE_FN_POINTER
72 return new LibGps(dl_handle
, gps_open
, gps_close
, gps_read
);
75 bool LibGps::Start() {
79 #if defined(OS_CHROMEOS)
81 if (gps_open_(GPSD_SHARED_MEMORY
, 0, gps_data_
.get()) != 0) {
82 // See gps.h NL_NOxxx for definition of gps_open() error numbers.
83 DLOG(WARNING
) << "gps_open() failed " << errno
;
89 #else // drop the support for desktop linux for now
90 DLOG(WARNING
) << "LibGps is only supported on ChromeOS";
96 gps_close_(gps_data_
.get());
100 bool LibGps::Read(Geoposition
* position
) {
102 position
->error_code
= Geoposition::ERROR_CODE_POSITION_UNAVAILABLE
;
104 DLOG(WARNING
) << "No gpsd connection";
105 position
->error_message
= "No gpsd connection";
109 if (gps_read_(gps_data_
.get()) < 0) {
110 DLOG(WARNING
) << "gps_read() fails";
111 position
->error_message
= "gps_read() fails";
115 if (!GetPositionIfFixed(position
)) {
116 DLOG(WARNING
) << "No fixed position";
117 position
->error_message
= "No fixed position";
121 position
->error_code
= Geoposition::ERROR_CODE_NONE
;
122 position
->timestamp
= base::Time::Now();
123 if (!position
->Validate()) {
124 // GetPositionIfFixed returned true, yet we've not got a valid fix.
125 // This shouldn't happen; something went wrong in the conversion.
126 NOTREACHED() << "Invalid position from GetPositionIfFixed: lat,long "
127 << position
->latitude
<< "," << position
->longitude
128 << " accuracy " << position
->accuracy
<< " time "
129 << position
->timestamp
.ToDoubleT();
130 position
->error_code
= Geoposition::ERROR_CODE_POSITION_UNAVAILABLE
;
131 position
->error_message
= "Bad fix from gps";
137 bool LibGps::GetPositionIfFixed(Geoposition
* position
) {
139 if (gps_data_
->status
== STATUS_NO_FIX
) {
140 DVLOG(2) << "Status_NO_FIX";
144 if (isnan(gps_data_
->fix
.latitude
) || isnan(gps_data_
->fix
.longitude
)) {
145 DVLOG(2) << "No valid lat/lon value";
149 position
->latitude
= gps_data_
->fix
.latitude
;
150 position
->longitude
= gps_data_
->fix
.longitude
;
152 if (!isnan(gps_data_
->fix
.epx
) && !isnan(gps_data_
->fix
.epy
)) {
153 position
->accuracy
= std::max(gps_data_
->fix
.epx
, gps_data_
->fix
.epy
);
154 } else if (isnan(gps_data_
->fix
.epx
) && !isnan(gps_data_
->fix
.epy
)) {
155 position
->accuracy
= gps_data_
->fix
.epy
;
156 } else if (!isnan(gps_data_
->fix
.epx
) && isnan(gps_data_
->fix
.epy
)) {
157 position
->accuracy
= gps_data_
->fix
.epx
;
159 // TODO(joth): Fixme. This is a workaround for http://crbug.com/99326
160 DVLOG(2) << "libgps reported accuracy NaN, forcing to zero";
161 position
->accuracy
= 0;
164 if (gps_data_
->fix
.mode
== MODE_3D
&& !isnan(gps_data_
->fix
.altitude
)) {
165 position
->altitude
= gps_data_
->fix
.altitude
;
166 if (!isnan(gps_data_
->fix
.epv
))
167 position
->altitude_accuracy
= gps_data_
->fix
.epv
;
170 if (!isnan(gps_data_
->fix
.track
))
171 position
->heading
= gps_data_
->fix
.track
;
172 if (!isnan(gps_data_
->fix
.speed
))
173 position
->speed
= gps_data_
->fix
.speed
;
177 } // namespace content