summaryrefslogtreecommitdiffstats
path: root/chrome/browser/geolocation/libgps_wrapper_linux.cc
diff options
context:
space:
mode:
authorjoth@chromium.org <joth@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-05-27 15:26:18 +0000
committerjoth@chromium.org <joth@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-05-27 15:26:18 +0000
commita2fd492a14c619f899623a0e0e05f5dd61751b6b (patch)
treea9bd46a7fe51f04ae6de7b53114ab892a064883e /chrome/browser/geolocation/libgps_wrapper_linux.cc
parent300e4ea2cb2bfdb316cc0670cc1de8bffffe9d85 (diff)
downloadchromium_src-a2fd492a14c619f899623a0e0e05f5dd61751b6b.zip
chromium_src-a2fd492a14c619f899623a0e0e05f5dd61751b6b.tar.gz
chromium_src-a2fd492a14c619f899623a0e0e05f5dd61751b6b.tar.bz2
First cut at GPS support in chrome linux
Uses libgps / gpsd to get gps fixes. Modified the location arbitrator to use GPS instead of network location provider. Current version requires manual code edit to enable (ENABLE_LIBGPS_LOCATION_PROVIDER) See http://docs.google.com/View?id=dfbnm49n_1g8ktswhr for demo instructions (work in progress) BUG=43868 TEST=Built with ENABLE_LIBGPS_LOCATION_PROVIDER and used gpsd's gpsfake script (see linked doc above) Review URL: http://codereview.chromium.org/2032010 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@48393 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser/geolocation/libgps_wrapper_linux.cc')
-rw-r--r--chrome/browser/geolocation/libgps_wrapper_linux.cc202
1 files changed, 202 insertions, 0 deletions
diff --git a/chrome/browser/geolocation/libgps_wrapper_linux.cc b/chrome/browser/geolocation/libgps_wrapper_linux.cc
new file mode 100644
index 0000000..0dc743c
--- /dev/null
+++ b/chrome/browser/geolocation/libgps_wrapper_linux.cc
@@ -0,0 +1,202 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/geolocation/libgps_wrapper_linux.h"
+
+#include <dlfcn.h>
+
+#include "chrome/common/geoposition.h"
+#include "base/logging.h"
+#include "base/string_util.h"
+
+namespace {
+LibGpsLibraryLoader* TryToOpen(const char* lib,
+ LibGpsLibraryLoader::InitMode mode) {
+ void* dl_handle = dlopen(lib, RTLD_LAZY);
+ if (dl_handle) {
+ LOG(INFO) << "Loaded " << lib;
+ scoped_ptr<LibGpsLibraryLoader> wrapper(new LibGpsLibraryLoader(dl_handle));
+ if (wrapper->Init(mode))
+ return wrapper.release();
+ } else {
+ DLOG(INFO) << "Could not open " << lib << ": " << dlerror();
+ }
+ return NULL;
+}
+} // namespace
+
+LibGps::LibGps(LibGpsLibraryLoader* dl_wrapper)
+ : library_(dl_wrapper) {
+ DCHECK(dl_wrapper != NULL);
+}
+
+LibGps::~LibGps() {
+}
+
+LibGps* LibGps::New() {
+ LibGpsLibraryLoader* wrapper;
+ wrapper = TryToOpen("libgps.so.19", LibGpsLibraryLoader::INITMODE_STREAM);
+ if (wrapper)
+ return NewV294(wrapper);
+ wrapper = TryToOpen("libgps.so.17", LibGpsLibraryLoader::INITMODE_QUERY);
+ if (wrapper)
+ return NewV238(wrapper);
+ wrapper = TryToOpen("libgps.so", LibGpsLibraryLoader::INITMODE_STREAM);
+ if (wrapper)
+ return NewV294(wrapper);
+ return NULL;
+}
+
+bool LibGps::Start(std::string* error_out) {
+ if (!library().open(NULL, NULL, error_out))
+ return false;
+ if (!StartStreaming()) {
+ library().close();
+ return false;
+ }
+ return true;
+}
+
+void LibGps::Stop() {
+ library().close();
+}
+
+bool LibGps::Poll() {
+ bool ret = true;
+ while (DataWaiting(&ret)) {
+ int error = library().poll();
+ if (error) {
+ last_error_ = StringPrintf("poll() returned %d", error);
+ return false;
+ }
+ }
+ if (!ret)
+ last_error_ = "DataWaiting failed";
+ return ret;
+}
+
+bool LibGps::GetPosition(Geoposition* position) {
+ DCHECK(position);
+ position->error_code = Geoposition::ERROR_CODE_POSITION_UNAVAILABLE;
+ if (!library().is_open()) {
+ position->error_message = L"No gpsd connection";
+ return false;
+ }
+ if (!GetPositionIfFixed(position)) {
+ position->error_message = ASCIIToWide(last_error_);
+ return false;
+ }
+ position->error_code = Geoposition::ERROR_CODE_NONE;
+ if (!position->IsValidFix()) {
+ // GetPositionIfFixed returned true, yet we've not got a valid fix.
+ // This shouldn't happen; something went wrong in the conversion.
+ NOTREACHED() << "Invalid position from GetPositionIfFixed: lat,long "
+ << position->latitude << "," << position->longitude
+ << " accuracy " << position->accuracy << " time "
+ << position->timestamp.ToDoubleT();
+ position->error_code = Geoposition::ERROR_CODE_POSITION_UNAVAILABLE;
+ position->error_message = L"Bad fix from gps";
+ return false;
+ }
+ return true;
+}
+
+LibGpsLibraryLoader::LibGpsLibraryLoader(void* dl_handle)
+ : dl_handle_(dl_handle),
+ gps_open_(NULL),
+ gps_close_(NULL),
+ gps_poll_(NULL),
+ gps_query_(NULL),
+ gps_stream_(NULL),
+ gps_waiting_(NULL),
+ gps_data_(NULL) {
+ DCHECK(dl_handle_);
+}
+
+// |mode| could be turned into a bit mask if required, but for now the
+// two options are mutually exclusive.
+bool LibGpsLibraryLoader::Init(InitMode mode) {
+ DCHECK(dl_handle_);
+ DCHECK(!gps_open_) << "Already initialized";
+ #define SET_FN_POINTER(function, required) \
+ function##_ = (function##_fn)dlsym(dl_handle_, #function); \
+ if ((required) && !function##_) { \
+ LOG(INFO) << "libgps " << #function << " error: " << dlerror(); \
+ close(); \
+ return false; \
+ }
+ SET_FN_POINTER(gps_open, true);
+ SET_FN_POINTER(gps_close, true);
+ SET_FN_POINTER(gps_poll, true);
+ SET_FN_POINTER(gps_query, mode == INITMODE_QUERY);
+ SET_FN_POINTER(gps_stream, mode == INITMODE_STREAM);
+ SET_FN_POINTER(gps_waiting, mode == INITMODE_STREAM);
+ #undef SET_FN_POINTER
+ return true;
+}
+
+LibGpsLibraryLoader::~LibGpsLibraryLoader() {
+ close();
+ if (dlclose(dl_handle_) != 0) {
+ NOTREACHED() << "Error closing dl handle";
+ }
+}
+
+bool LibGpsLibraryLoader::open(const char* host, const char* port,
+ std::string* error_out) {
+ DCHECK(!gps_data_) << "libgps handle already opened";
+ DCHECK(gps_open_) << "Must call Init() first";
+ std::string dummy;
+ if (!error_out) error_out = &dummy;
+
+ gps_data_ = gps_open_(host, port);
+ if (!gps_data_) { // GPS session was not created.
+ *error_out = "gps_open failed";
+ close();
+ }
+ return gps_data_;
+}
+
+void LibGpsLibraryLoader::close() {
+ if (gps_data_) {
+ DCHECK(gps_close_);
+ gps_close_(gps_data_);
+ gps_data_ = NULL;
+ }
+}
+
+int LibGpsLibraryLoader::poll() {
+ DCHECK(is_open());
+ DCHECK(gps_poll_);
+ return gps_poll_(gps_data_);
+}
+
+// This is intentionally ignoring the va_arg extension to query(): the caller
+// can use base::StringPrintf to achieve the same effect.
+int LibGpsLibraryLoader::query(const char* fmt) {
+ DCHECK(is_open());
+ DCHECK(gps_query_);
+ return gps_query_(gps_data_, fmt);
+}
+
+int LibGpsLibraryLoader::stream(int flags) {
+ DCHECK(is_open());
+ DCHECK(gps_stream_);
+ return gps_stream_(gps_data_, flags, NULL);
+}
+
+bool LibGpsLibraryLoader::waiting() {
+ DCHECK(is_open());
+ DCHECK(gps_waiting_);
+ return gps_waiting_(gps_data_);
+}
+
+const gps_data_t& LibGpsLibraryLoader::data() const {
+ DCHECK(is_open());
+ return *gps_data_;
+}
+
+bool LibGpsLibraryLoader::is_open() const {
+ return gps_data_ != NULL;
+}