Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "content/browser/geolocation/libgps_wrapper_linux.h" | 5 #include "content/browser/geolocation/libgps_wrapper_linux.h" |
| 6 | 6 |
| 7 #include <math.h> | |
| 7 #include <dlfcn.h> | 8 #include <dlfcn.h> |
| 8 #include <errno.h> | 9 #include <errno.h> |
| 9 | 10 |
| 10 #include "base/logging.h" | 11 #include "base/logging.h" |
| 11 #include "base/stringprintf.h" | 12 #include "base/stringprintf.h" |
| 12 #include "content/common/geoposition.h" | 13 #include "content/common/geoposition.h" |
| 13 | 14 |
| 14 namespace { | 15 LibGps::LibGps(void* dl_handle, |
| 15 // Attempts to load dynamic library named |lib| and initialize the required | 16 gps_open_fn gps_open, |
| 16 // function pointers according to |mode|. Returns ownership a new instance | 17 gps_close_fn gps_close, |
| 17 // of the library loader class, or NULL on failure. | 18 gps_read_fn gps_read) |
| 18 // TODO(joth): This is a hang-over from when we dynamically two different | 19 : dl_handle_(dl_handle), |
| 19 // versions of libgps and chose between them. Now we could remove at least one | 20 gps_open_(gps_open), |
| 20 // layer of wrapper class and directly #include gps.h in this cc file. | 21 gps_close_(gps_close), |
| 21 // See http://crbug.com/98132 and http://crbug.com/99177 | 22 gps_read_(gps_read), |
| 22 LibGpsLibraryWrapper* TryToOpen(const char* lib) { | 23 is_open_(false) { |
| 23 void* dl_handle = dlopen(lib, RTLD_LAZY); | 24 DCHECK(gps_open_); |
| 25 DCHECK(gps_close_); | |
| 26 DCHECK(gps_read_); | |
| 27 } | |
| 28 | |
| 29 LibGps::~LibGps() { | |
| 30 Stop(); | |
| 31 if (dl_handle_) { | |
| 32 const int err = dlclose(dl_handle_); | |
| 33 CHECK_EQ(0, err) << "Error closing dl handle: " << err; | |
|
joth
2011/11/11 18:40:40
nit: use DCHECK_EQ
Yufeng Shen (Slow to review)
2011/11/11 21:11:35
Done.
| |
| 34 } | |
| 35 } | |
| 36 | |
| 37 LibGps* LibGps::New() { | |
| 38 void* dl_handle = dlopen(LIBGPS_VERSION, RTLD_LAZY); | |
| 24 if (!dl_handle) { | 39 if (!dl_handle) { |
| 25 VLOG(1) << "Could not open " << lib << ": " << dlerror(); | 40 LOG(WARNING) << "Could not open " << LIBGPS_VERSION << ": " << dlerror(); |
|
joth
2011/11/11 18:40:40
this is only log warning for Chrome OS.
DLOG(WARN
Yufeng Shen (Slow to review)
2011/11/11 21:11:35
Done.
| |
| 26 return NULL; | 41 return NULL; |
| 27 } | 42 } |
| 28 VLOG(1) << "Loaded " << lib; | 43 |
| 44 LOG(INFO) << "Loaded " << LIBGPS_VERSION; | |
|
joth
2011/11/11 18:40:40
again DLOG (or DVLOG).
chrome is trying to discou
Yufeng Shen (Slow to review)
2011/11/11 21:11:35
Done.
| |
| 29 | 45 |
| 30 #define DECLARE_FN_POINTER(function) \ | 46 #define DECLARE_FN_POINTER(function) \ |
| 31 LibGpsLibraryWrapper::function##_fn function; \ | 47 function##_fn function = reinterpret_cast<function##_fn>( \ |
| 32 function = reinterpret_cast<LibGpsLibraryWrapper::function##_fn>( \ | |
| 33 dlsym(dl_handle, #function)); \ | 48 dlsym(dl_handle, #function)); \ |
| 34 if (!function) { \ | 49 if (!function) { \ |
| 35 LOG(WARNING) << "libgps " << #function << " error: " << dlerror(); \ | 50 LOG(WARNING) << "libgps " << #function << " error: " << dlerror(); \ |
|
joth
2011/11/11 18:40:40
ditto, and throughout the file
Yufeng Shen (Slow to review)
2011/11/11 21:11:35
Done.
| |
| 36 dlclose(dl_handle); \ | 51 dlclose(dl_handle); \ |
| 37 return NULL; \ | 52 return NULL; \ |
| 38 } | 53 } |
| 39 DECLARE_FN_POINTER(gps_open); | 54 DECLARE_FN_POINTER(gps_open); |
| 40 DECLARE_FN_POINTER(gps_close); | 55 DECLARE_FN_POINTER(gps_close); |
| 41 DECLARE_FN_POINTER(gps_poll); | 56 DECLARE_FN_POINTER(gps_read); |
| 42 DECLARE_FN_POINTER(gps_stream); | 57 // We don't use gps_shm_read() directly, just to make sure that libgps has |
| 43 DECLARE_FN_POINTER(gps_waiting); | 58 // the shared memory support. |
| 59 typedef int (*gps_shm_read_fn)(struct gps_data_t*); | |
| 60 DECLARE_FN_POINTER(gps_shm_read); | |
| 44 #undef DECLARE_FN_POINTER | 61 #undef DECLARE_FN_POINTER |
| 45 | 62 |
| 46 return new LibGpsLibraryWrapper(dl_handle, | 63 return new LibGps(dl_handle, gps_open, gps_close, gps_read); |
| 47 gps_open, | |
| 48 gps_close, | |
| 49 gps_poll, | |
| 50 gps_stream, | |
| 51 gps_waiting); | |
| 52 } | |
| 53 } // namespace | |
| 54 | |
| 55 LibGps::LibGps(LibGpsLibraryWrapper* dl_wrapper) | |
| 56 : library_(dl_wrapper) { | |
| 57 DCHECK(dl_wrapper != NULL); | |
| 58 } | |
| 59 | |
| 60 LibGps::~LibGps() { | |
| 61 } | |
| 62 | |
| 63 LibGps* LibGps::New() { | |
| 64 LibGpsLibraryWrapper* wrapper; | |
| 65 wrapper = TryToOpen("libgps.so.19"); | |
| 66 if (wrapper) | |
| 67 return NewV294(wrapper); | |
| 68 wrapper = TryToOpen("libgps.so"); | |
| 69 if (wrapper) | |
| 70 return NewV294(wrapper); | |
| 71 return NULL; | |
| 72 } | 64 } |
| 73 | 65 |
| 74 bool LibGps::Start() { | 66 bool LibGps::Start() { |
| 75 if (library().is_open()) | 67 if (is_open_) |
| 76 return true; | 68 return true; |
| 69 | |
| 77 errno = 0; | 70 errno = 0; |
| 78 static int fail_count = 0; | 71 if (gps_open_(GPSD_SHARED_MEMORY, 0, &gps_data_) != 0) { |
|
joth
2011/11/11 18:40:40
this is still applied for desktop linux?
I'm stil
Yufeng Shen (Slow to review)
2011/11/11 21:11:35
Drop the desktop linux for now
On 2011/11/11 18:4
| |
| 79 if (!library().open(NULL, NULL)) { | |
| 80 // See gps.h NL_NOxxx for definition of gps_open() error numbers. | 72 // See gps.h NL_NOxxx for definition of gps_open() error numbers. |
| 81 LOG_IF(WARNING, 0 == fail_count++) << "gps_open() failed: " << errno; | 73 LOG(WARNING) << "gps_open() failed " << errno; |
| 82 return false; | 74 return false; |
| 83 } | 75 } |
| 84 fail_count = 0; | 76 |
| 85 if (!StartStreaming()) { | 77 is_open_ = true; |
| 86 VLOG(1) << "StartStreaming failed"; | |
| 87 library().close(); | |
| 88 return false; | |
| 89 } | |
| 90 return true; | 78 return true; |
| 91 } | 79 } |
| 92 | |
| 93 void LibGps::Stop() { | 80 void LibGps::Stop() { |
| 94 library().close(); | 81 if (is_open_) |
| 82 gps_close_(&gps_data_); | |
| 83 is_open_ = false; | |
| 95 } | 84 } |
| 96 | 85 |
| 97 bool LibGps::Poll() { | 86 bool LibGps::Read(Geoposition* position) { |
| 98 last_error_ = "no data received from gpsd"; | |
| 99 while (DataWaiting()) { | |
| 100 int error = library().poll(); | |
| 101 if (error) { | |
| 102 last_error_ = base::StringPrintf("poll() returned %d", error); | |
| 103 Stop(); | |
| 104 return false; | |
| 105 } | |
| 106 last_error_.clear(); | |
| 107 } | |
| 108 return last_error_.empty(); | |
| 109 } | |
| 110 | |
| 111 bool LibGps::GetPosition(Geoposition* position) { | |
| 112 DCHECK(position); | 87 DCHECK(position); |
| 113 position->error_code = Geoposition::ERROR_CODE_POSITION_UNAVAILABLE; | 88 position->error_code = Geoposition::ERROR_CODE_POSITION_UNAVAILABLE; |
| 114 if (!library().is_open()) { | 89 if (!is_open_) { |
| 115 position->error_message = "No gpsd connection"; | 90 LOG(WARNING) << "No gpsd connection"; |
| 116 return false; | 91 position->error_message = "No gpsd connection"; |
| 92 return false; | |
| 117 } | 93 } |
| 94 | |
| 95 if (gps_read_(&gps_data_) < 0) { | |
| 96 LOG(WARNING) << "gps_read() fails"; | |
| 97 position->error_message = "gps_read() fails"; | |
| 98 return false; | |
| 99 } | |
| 100 | |
| 118 if (!GetPositionIfFixed(position)) { | 101 if (!GetPositionIfFixed(position)) { |
| 119 position->error_message = last_error_; | 102 LOG(WARNING) << "No fixed position"; |
| 120 return false; | 103 position->error_message = "No fixed position"; |
| 104 return false; | |
| 121 } | 105 } |
| 106 | |
| 122 position->error_code = Geoposition::ERROR_CODE_NONE; | 107 position->error_code = Geoposition::ERROR_CODE_NONE; |
| 123 position->timestamp = base::Time::Now(); | 108 position->timestamp = base::Time::Now(); |
| 124 if (!position->IsValidFix()) { | 109 if (!position->IsValidFix()) { |
| 125 // GetPositionIfFixed returned true, yet we've not got a valid fix. | 110 // GetPositionIfFixed returned true, yet we've not got a valid fix. |
| 126 // This shouldn't happen; something went wrong in the conversion. | 111 // This shouldn't happen; something went wrong in the conversion. |
| 127 NOTREACHED() << "Invalid position from GetPositionIfFixed: lat,long " | 112 NOTREACHED() << "Invalid position from GetPositionIfFixed: lat,long " |
| 128 << position->latitude << "," << position->longitude | 113 << position->latitude << "," << position->longitude |
| 129 << " accuracy " << position->accuracy << " time " | 114 << " accuracy " << position->accuracy << " time " |
| 130 << position->timestamp.ToDoubleT(); | 115 << position->timestamp.ToDoubleT(); |
| 131 position->error_code = Geoposition::ERROR_CODE_POSITION_UNAVAILABLE; | 116 position->error_code = Geoposition::ERROR_CODE_POSITION_UNAVAILABLE; |
| 132 position->error_message = "Bad fix from gps"; | 117 position->error_message = "Bad fix from gps"; |
| 133 return false; | 118 return false; |
| 134 } | 119 } |
| 135 return true; | 120 return true; |
| 136 } | 121 } |
| 137 | 122 |
| 138 LibGpsLibraryWrapper::LibGpsLibraryWrapper(void* dl_handle, | 123 bool LibGps::GetPositionIfFixed(Geoposition* position) { |
| 139 gps_open_fn gps_open, | 124 DCHECK(position); |
| 140 gps_close_fn gps_close, | 125 if (gps_data_.status == STATUS_NO_FIX) { |
| 141 gps_poll_fn gps_poll, | 126 DLOG(WARNING) << "Status_NO_FIX"; |
|
joth
2011/11/11 18:40:40
this looks like it will be very noisy. DVLOG(1) or
Yufeng Shen (Slow to review)
2011/11/11 21:11:35
done
trying to get myself familiar with that
On
| |
| 142 gps_stream_fn gps_stream, | 127 return false; |
| 143 gps_waiting_fn gps_waiting) | 128 } |
| 144 : dl_handle_(dl_handle), | 129 |
| 145 gps_open_(gps_open), | 130 if (isnan(gps_data_.fix.latitude) || isnan(gps_data_.fix.longitude)) { |
| 146 gps_close_(gps_close), | 131 DLOG(WARNING) << "No valid lat/lon value"; |
| 147 gps_poll_(gps_poll), | 132 return false; |
| 148 gps_stream_(gps_stream), | 133 } |
| 149 gps_waiting_(gps_waiting), | 134 |
| 150 gps_data_(NULL) { | 135 position->latitude = gps_data_.fix.latitude; |
| 136 position->longitude = gps_data_.fix.longitude; | |
| 137 | |
| 138 if (!isnan(gps_data_.fix.epx) && !isnan(gps_data_.fix.epy)) { | |
|
joth
2011/11/11 18:40:40
nit: i guess either epx or epy would probably do i
Yufeng Shen (Slow to review)
2011/11/11 21:11:35
Done.
| |
| 139 position->accuracy = std::max(gps_data_.fix.epx, gps_data_.fix.epy); | |
| 140 } else { | |
| 141 // TODO(joth): Fixme. This is a workaround for http://crbug.com/99326 | |
| 142 // (miletus) : With NMEA protocol, only sentences GPGBS (in NMEA 3.0) and | |
| 143 // PGRME (Garmin specific) send out accuracy data fix.epx and fix.epy. | |
| 144 // So expecting that accuracy is not valid most of the time. | |
|
joth
2011/11/11 18:40:40
maybe this comment should go onto the bug report.
Yufeng Shen (Slow to review)
2011/11/11 21:11:35
It means with most devices we won't get fix.epx an
| |
| 145 DLOG(WARNING) << "libgps reported accuracy NaN, forcing to zero"; | |
| 146 position->accuracy = 0; | |
| 147 } | |
| 148 | |
| 149 if (gps_data_.fix.mode == MODE_3D && !isnan(gps_data_.fix.altitude)) { | |
| 150 position->altitude = gps_data_.fix.altitude; | |
| 151 if (!isnan(gps_data_.fix.epv)) | |
| 152 position->altitude_accuracy = gps_data_.fix.epv; | |
| 153 } | |
| 154 | |
| 155 if (!isnan(gps_data_.fix.track)) | |
| 156 position->heading = gps_data_.fix.track; | |
| 157 if (!isnan(gps_data_.fix.speed)) | |
| 158 position->speed = gps_data_.fix.speed; | |
| 159 return true; | |
| 151 } | 160 } |
| 152 | |
| 153 LibGpsLibraryWrapper::~LibGpsLibraryWrapper() { | |
| 154 close(); | |
| 155 if (dl_handle_) { | |
| 156 const int err = dlclose(dl_handle_); | |
| 157 CHECK_EQ(0, err) << "Error closing dl handle: " << err; | |
| 158 } | |
| 159 } | |
| 160 | |
| 161 bool LibGpsLibraryWrapper::open(const char* host, const char* port) { | |
| 162 DCHECK(!gps_data_) << "libgps already opened"; | |
| 163 DCHECK(gps_open_); | |
| 164 gps_data_ = gps_open_(host, port); | |
| 165 return is_open(); | |
| 166 } | |
| 167 | |
| 168 void LibGpsLibraryWrapper::close() { | |
| 169 if (is_open()) { | |
| 170 DCHECK(gps_close_); | |
| 171 gps_close_(gps_data_); | |
| 172 gps_data_ = NULL; | |
| 173 } | |
| 174 } | |
| 175 | |
| 176 int LibGpsLibraryWrapper::poll() { | |
| 177 DCHECK(is_open()); | |
| 178 DCHECK(gps_poll_); | |
| 179 return gps_poll_(gps_data_); | |
| 180 } | |
| 181 | |
| 182 int LibGpsLibraryWrapper::stream(int flags) { | |
| 183 DCHECK(is_open()); | |
| 184 DCHECK(gps_stream_); | |
| 185 return gps_stream_(gps_data_, flags, NULL); | |
| 186 } | |
| 187 | |
| 188 bool LibGpsLibraryWrapper::waiting() { | |
| 189 DCHECK(is_open()); | |
| 190 DCHECK(gps_waiting_); | |
| 191 return gps_waiting_(gps_data_); | |
| 192 } | |
| 193 | |
| 194 const gps_data_t& LibGpsLibraryWrapper::data() const { | |
| 195 DCHECK(is_open()); | |
| 196 return *gps_data_; | |
| 197 } | |
| 198 | |
| 199 bool LibGpsLibraryWrapper::is_open() const { | |
| 200 return gps_data_ != NULL; | |
| 201 } | |
| OLD | NEW |