[content shell] implement testRunner.overridePreference
[chromium-blink-merge.git] / content / browser / geolocation / libgps_wrapper_linux.cc
bloba1eb9d1034968573bf33d94d8887a556a3da5624
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"
7 #include <math.h>
8 #include <dlfcn.h>
9 #include <errno.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);
18 namespace content {
19 namespace {
20 const char kLibGpsName[] = "libgps.so.20";
21 } // namespace
23 LibGps::LibGps(void* dl_handle,
24 gps_open_fn gps_open,
25 gps_close_fn gps_close,
26 gps_read_fn gps_read)
27 : dl_handle_(dl_handle),
28 gps_open_(gps_open),
29 gps_close_(gps_close),
30 gps_read_(gps_read),
31 gps_data_(new gps_data_t),
32 is_open_(false) {
33 DCHECK(gps_open_);
34 DCHECK(gps_close_);
35 DCHECK(gps_read_);
38 LibGps::~LibGps() {
39 Stop();
40 if (dl_handle_) {
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);
48 if (!dl_handle) {
49 DLOG(WARNING) << "Could not open " << kLibGpsName << ": " << dlerror();
50 return NULL;
53 DLOG(INFO) << "Loaded " << kLibGpsName;
55 #define DECLARE_FN_POINTER(function) \
56 function##_fn function = reinterpret_cast<function##_fn>( \
57 dlsym(dl_handle, #function)); \
58 if (!function) { \
59 DLOG(WARNING) << "libgps " << #function << " error: " << dlerror(); \
60 dlclose(dl_handle); \
61 return NULL; \
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() {
76 if (is_open_)
77 return true;
79 #if defined(OS_CHROMEOS)
80 errno = 0;
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;
84 return false;
85 } else {
86 is_open_ = true;
87 return true;
89 #else // drop the support for desktop linux for now
90 DLOG(WARNING) << "LibGps is only supported on ChromeOS";
91 return false;
92 #endif
94 void LibGps::Stop() {
95 if (is_open_)
96 gps_close_(gps_data_.get());
97 is_open_ = false;
100 bool LibGps::Read(Geoposition* position) {
101 DCHECK(position);
102 position->error_code = Geoposition::ERROR_CODE_POSITION_UNAVAILABLE;
103 if (!is_open_) {
104 DLOG(WARNING) << "No gpsd connection";
105 position->error_message = "No gpsd connection";
106 return false;
109 if (gps_read_(gps_data_.get()) < 0) {
110 DLOG(WARNING) << "gps_read() fails";
111 position->error_message = "gps_read() fails";
112 return false;
115 if (!GetPositionIfFixed(position)) {
116 DLOG(WARNING) << "No fixed position";
117 position->error_message = "No fixed position";
118 return false;
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";
132 return false;
134 return true;
137 bool LibGps::GetPositionIfFixed(Geoposition* position) {
138 DCHECK(position);
139 if (gps_data_->status == STATUS_NO_FIX) {
140 DVLOG(2) << "Status_NO_FIX";
141 return false;
144 if (isnan(gps_data_->fix.latitude) || isnan(gps_data_->fix.longitude)) {
145 DVLOG(2) << "No valid lat/lon value";
146 return false;
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;
158 } else {
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;
174 return true;
177 } // namespace content