| OLD | NEW |
| (Empty) |
| 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. | |
| 4 | |
| 5 #include "content/browser/geolocation/libgps_wrapper_linux.h" | |
| 6 | |
| 7 #include <math.h> | |
| 8 #include <dlfcn.h> | |
| 9 #include <errno.h> | |
| 10 | |
| 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" | |
| 15 | |
| 16 COMPILE_ASSERT(GPSD_API_MAJOR_VERSION == 5, GPSD_API_version_is_not_5); | |
| 17 | |
| 18 namespace content { | |
| 19 namespace { | |
| 20 const char kLibGpsName[] = "libgps.so.20"; | |
| 21 } // namespace | |
| 22 | |
| 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_); | |
| 36 } | |
| 37 | |
| 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; | |
| 43 } | |
| 44 } | |
| 45 | |
| 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; | |
| 51 } | |
| 52 | |
| 53 DLOG(INFO) << "Loaded " << kLibGpsName; | |
| 54 | |
| 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; \ | |
| 62 } | |
| 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 | |
| 71 | |
| 72 return new LibGps(dl_handle, gps_open, gps_close, gps_read); | |
| 73 } | |
| 74 | |
| 75 bool LibGps::Start() { | |
| 76 if (is_open_) | |
| 77 return true; | |
| 78 | |
| 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; | |
| 88 } | |
| 89 #else // drop the support for desktop linux for now | |
| 90 DLOG(WARNING) << "LibGps is only supported on ChromeOS"; | |
| 91 return false; | |
| 92 #endif | |
| 93 } | |
| 94 void LibGps::Stop() { | |
| 95 if (is_open_) | |
| 96 gps_close_(gps_data_.get()); | |
| 97 is_open_ = false; | |
| 98 } | |
| 99 | |
| 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; | |
| 107 } | |
| 108 | |
| 109 if (gps_read_(gps_data_.get()) < 0) { | |
| 110 DLOG(WARNING) << "gps_read() fails"; | |
| 111 position->error_message = "gps_read() fails"; | |
| 112 return false; | |
| 113 } | |
| 114 | |
| 115 if (!GetPositionIfFixed(position)) { | |
| 116 DLOG(WARNING) << "No fixed position"; | |
| 117 position->error_message = "No fixed position"; | |
| 118 return false; | |
| 119 } | |
| 120 | |
| 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; | |
| 133 } | |
| 134 return true; | |
| 135 } | |
| 136 | |
| 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; | |
| 142 } | |
| 143 | |
| 144 if (isnan(gps_data_->fix.latitude) || isnan(gps_data_->fix.longitude)) { | |
| 145 DVLOG(2) << "No valid lat/lon value"; | |
| 146 return false; | |
| 147 } | |
| 148 | |
| 149 position->latitude = gps_data_->fix.latitude; | |
| 150 position->longitude = gps_data_->fix.longitude; | |
| 151 | |
| 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; | |
| 162 } | |
| 163 | |
| 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; | |
| 168 } | |
| 169 | |
| 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; | |
| 175 } | |
| 176 | |
| 177 } // namespace content | |
| OLD | NEW |