diff options
author | Dante Russo <drusso@codeaurora.org> | 2017-02-28 16:45:47 -0800 |
---|---|---|
committer | Dante Russo <drusso@codeaurora.org> | 2017-02-28 16:47:50 -0800 |
commit | c85c8ff673e4347cea911b353de120f639b39b83 (patch) | |
tree | 5fe203230801cf76dc1823b6d05a44ea94663883 /location | |
parent | 4bb940c0679ab23c9b8954bcb9ad8da5ede093cd (diff) | |
download | gps-c85c8ff673e4347cea911b353de120f639b39b83.tar.gz |
LocationAPI implementation
Implementation of LocationAPI into gps hal
to be a common API that is called into by platform
specific APIs.
Change-Id: Ie5a7bd217d4ae2175ad49e6aca2fb6ecd4702f3b
CRs-fixed: 1112712
Diffstat (limited to 'location')
-rw-r--r-- | location/Android.mk | 41 | ||||
-rw-r--r-- | location/LocationAPI.cpp | 675 | ||||
-rw-r--r-- | location/LocationAPI.h | 866 | ||||
-rw-r--r-- | location/LocationAPIClientBase.cpp | 769 | ||||
-rw-r--r-- | location/LocationAPIClientBase.h | 457 | ||||
-rw-r--r-- | location/location_interface.h | 86 |
6 files changed, 2894 insertions, 0 deletions
diff --git a/location/Android.mk b/location/Android.mk new file mode 100644 index 0000000..49a60d7 --- /dev/null +++ b/location/Android.mk @@ -0,0 +1,41 @@ +ifneq ($(BOARD_VENDOR_QCOM_GPS_LOC_API_HARDWARE),) +ifneq ($(BUILD_TINY_ANDROID),true) + +LOCAL_PATH := $(call my-dir) + +include $(CLEAR_VARS) + +LOCAL_MODULE := liblocation_api +LOCAL_MODULE_OWNER := qti + +LOCAL_MODULE_TAGS := optional + +LOCAL_SHARED_LIBRARIES := \ + libutils \ + libcutils \ + libgps.utils \ + libdl \ + liblog + +LOCAL_SRC_FILES += \ + LocationAPI.cpp \ + LocationAPIClientBase.cpp + +LOCAL_CFLAGS += \ + -fno-short-enums + +LOCAL_C_INCLUDES:= \ + $(TARGET_OUT_HEADERS)/gps.utils + +LOCAL_COPY_HEADERS_TO:= liblocation_api/ +LOCAL_COPY_HEADERS:= \ + LocationAPI.h \ + LocationAPIClientBase.h \ + location_interface.h + +LOCAL_PRELINK_MODULE := false + +include $(BUILD_SHARED_LIBRARY) + +endif # not BUILD_TINY_ANDROID +endif # BOARD_VENDOR_QCOM_GPS_LOC_API_HARDWARE diff --git a/location/LocationAPI.cpp b/location/LocationAPI.cpp new file mode 100644 index 0000000..c800851 --- /dev/null +++ b/location/LocationAPI.cpp @@ -0,0 +1,675 @@ +/* Copyright (c) 2017 The Linux Foundation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * * Neither the name of The Linux Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#define LOG_TAG "LocSvc_LocationAPI" + +#include <location_interface.h> +#include <dlfcn.h> +#include <log_util.h> +#include <pthread.h> +#include <map> + +typedef void* (getLocationInterface)(); +typedef std::map<LocationAPI*, LocationCallbacks> LocationClientMap; +typedef struct { + LocationClientMap clientData; + LocationControlAPI* controlAPI; + LocationControlCallbacks controlCallbacks; + GnssInterface* gnssInterface; + GeofenceInterface* geofenceInterface; + FlpInterface* flpInterface; +} LocationAPIData; +static LocationAPIData gData = {}; +static pthread_mutex_t gDataMutex = PTHREAD_MUTEX_INITIALIZER; +static bool gGnssLoadFailed = false; +static bool gFlpLoadFailed = false; +static bool gGeofenceLoadFailed = false; + +static bool needsGnssTrackingInfo(LocationCallbacks& locationCallbacks) +{ + return (locationCallbacks.gnssLocationInfoCb != nullptr || + locationCallbacks.gnssSvCb != nullptr || + locationCallbacks.gnssNmeaCb != nullptr || + locationCallbacks.gnssMeasurementsCb != nullptr); +} + +static bool isGnssClient(LocationCallbacks& locationCallbacks) +{ + return (locationCallbacks.gnssNiCb != nullptr || + locationCallbacks.trackingCb != nullptr || + locationCallbacks.gnssMeasurementsCb != nullptr); +} + +static bool isFlpClient(LocationCallbacks& locationCallbacks) +{ + return (locationCallbacks.trackingCb != nullptr || + locationCallbacks.batchingCb != nullptr); +} + +static bool isGeofenceClient(LocationCallbacks& locationCallbacks) +{ + return (locationCallbacks.geofenceBreachCb != nullptr || + locationCallbacks.geofenceStatusCb != nullptr); +} + +static void* loadLocationInterface(const char* library, const char* name) { + LOC_LOGD("%s]: loading %s::%s ...", __func__, library, name); + if (NULL == library || NULL == name) { + return NULL; + } + getLocationInterface* getter = NULL; + const char *error; + dlerror(); + void *handle = dlopen(library, RTLD_NOW); + if (NULL == handle || (error = dlerror()) != NULL) { + LOC_LOGW("dlopen for %s failed, error = %s", library, error); + } else { + getter = (getLocationInterface*)dlsym(handle, name); + if ((error = dlerror()) != NULL) { + LOC_LOGW("dlsym for %s::%s failed, error = %s", library, name, error); + getter = NULL; + } + } + + if (NULL == getter) { + return (void*)getter; + } else { + return (*getter)(); + } +} + +LocationAPI* +LocationAPI::createInstance(LocationCallbacks& locationCallbacks) +{ + if (nullptr == locationCallbacks.capabilitiesCb || + nullptr == locationCallbacks.responseCb || + nullptr == locationCallbacks.collectiveResponseCb) { + return NULL; + } + + LocationAPI* newLocationAPI = new LocationAPI(); + bool requestedCapabilities = false; + + pthread_mutex_lock(&gDataMutex); + + if (isGnssClient(locationCallbacks)) { + if (NULL == gData.gnssInterface && !gGnssLoadFailed) { + gData.gnssInterface = + (GnssInterface*)loadLocationInterface("libgnss.so", "getGnssInterface"); + if (NULL == gData.gnssInterface) { + gGnssLoadFailed = true; + LOC_LOGW("%s:%d]: No gnss interface available", __func__, __LINE__); + } else { + gData.gnssInterface->initialize(); + } + } + if (NULL != gData.gnssInterface) { + gData.gnssInterface->addClient(newLocationAPI, locationCallbacks); + if (!requestedCapabilities) { + gData.gnssInterface->requestCapabilities(newLocationAPI); + requestedCapabilities = true; + } + } + } + + if (isFlpClient(locationCallbacks)) { + if (NULL == gData.flpInterface && !gFlpLoadFailed) { + gData.flpInterface = + (FlpInterface*)loadLocationInterface("libflp.so", "getFlpInterface"); + if (NULL == gData.flpInterface) { + gFlpLoadFailed = true; + LOC_LOGW("%s:%d]: No flp interface available", __func__, __LINE__); + } else { + gData.flpInterface->initialize(); + } + } + if (NULL != gData.flpInterface) { + gData.flpInterface->addClient(newLocationAPI, locationCallbacks); + if (!requestedCapabilities) { + gData.flpInterface->requestCapabilities(newLocationAPI); + requestedCapabilities = true; + } + } + } + + if (isGeofenceClient(locationCallbacks)) { + if (NULL == gData.geofenceInterface && !gGeofenceLoadFailed) { + gData.geofenceInterface = + (GeofenceInterface*)loadLocationInterface("libgeofence.so", "getGeofenceInterface"); + if (NULL == gData.geofenceInterface) { + gGeofenceLoadFailed = true; + LOC_LOGW("%s:%d]: No geofence interface available", __func__, __LINE__); + } else { + gData.geofenceInterface->initialize(); + } + } + if (NULL != gData.geofenceInterface) { + gData.geofenceInterface->addClient(newLocationAPI, locationCallbacks); + if (!requestedCapabilities) { + gData.geofenceInterface->requestCapabilities(newLocationAPI); + requestedCapabilities = true; + } + } + } + + gData.clientData[newLocationAPI] = locationCallbacks; + + pthread_mutex_unlock(&gDataMutex); + + return newLocationAPI; +} + +void +LocationAPI::destroy() +{ + delete this; +} + +LocationAPI::LocationAPI() +{ + LOC_LOGD("LOCATION API CONSTRUCTOR"); +} + +LocationAPI::~LocationAPI() +{ + LOC_LOGD("LOCATION API DESTRUCTOR"); + pthread_mutex_lock(&gDataMutex); + + auto it = gData.clientData.find(this); + if (it != gData.clientData.end()) { + size_t gnssClientCount = 0; + size_t flpClientCount = 0; + size_t geofenceClientCount = 0; + for (auto it2=gData.clientData.begin(); it2 != gData.clientData.end(); ++it2) { + if (isGnssClient(it2->second)) { + gnssClientCount++; + } + if (isFlpClient(it2->second)) { + flpClientCount++; + } + if (isGeofenceClient(it2->second)) { + geofenceClientCount++; + } + } + if (isGnssClient(it->second) && NULL != gData.gnssInterface) { + gData.gnssInterface->removeClient(it->first); + if (1 == gnssClientCount && NULL == gData.controlAPI) { + gData.gnssInterface->deinitialize(); + } + } + if (isFlpClient(it->second) && NULL != gData.flpInterface) { + gData.flpInterface->removeClient(it->first); + if (1 == flpClientCount) { + gData.flpInterface->deinitialize(); + } + } + if (isGeofenceClient(it->second) && NULL != gData.geofenceInterface) { + gData.geofenceInterface->removeClient(it->first); + if (1 == geofenceClientCount) { + gData.geofenceInterface->deinitialize(); + } + } + gData.clientData.erase(it); + } else { + LOC_LOGE("%s:%d]: Location API client %p not found in client data", + __func__, __LINE__, this); + } + + pthread_mutex_unlock(&gDataMutex); +} + +void +LocationAPI::updateCallbacks(LocationCallbacks& locationCallbacks) +{ + if (nullptr == locationCallbacks.capabilitiesCb || + nullptr == locationCallbacks.responseCb || + nullptr == locationCallbacks.collectiveResponseCb) { + return; + } + + pthread_mutex_lock(&gDataMutex); + + if (isGnssClient(locationCallbacks)) { + if (NULL == gData.gnssInterface && !gGnssLoadFailed) { + gData.gnssInterface = + (GnssInterface*)loadLocationInterface("libgnss.so", "getGnssInterface"); + if (NULL == gData.gnssInterface) { + gGnssLoadFailed = true; + LOC_LOGW("%s:%d]: No gnss interface available", __func__, __LINE__); + } else { + gData.gnssInterface->initialize(); + } + } + if (NULL != gData.gnssInterface) { + // either adds new Client or updates existing Client + gData.gnssInterface->addClient(this, locationCallbacks); + } + } + + if (isFlpClient(locationCallbacks)) { + if (NULL == gData.flpInterface && !gFlpLoadFailed) { + gData.flpInterface = + (FlpInterface*)loadLocationInterface("libflp.so", "getFlpInterface"); + if (NULL == gData.flpInterface) { + gFlpLoadFailed = true; + LOC_LOGW("%s:%d]: No flp interface available", __func__, __LINE__); + } else { + gData.flpInterface->initialize(); + } + } + if (NULL != gData.flpInterface) { + // either adds new Client or updates existing Client + gData.flpInterface->addClient(this, locationCallbacks); + } + } + + if (isGeofenceClient(locationCallbacks)) { + if (NULL == gData.geofenceInterface && !gGeofenceLoadFailed) { + gData.geofenceInterface = + (GeofenceInterface*)loadLocationInterface("libgeofence.so", "getGeofenceInterface"); + if (NULL == gData.geofenceInterface) { + gGeofenceLoadFailed = true; + LOC_LOGW("%s:%d]: No geofence interface available", __func__, __LINE__); + } else { + gData.geofenceInterface->initialize(); + } + } + if (NULL != gData.geofenceInterface) { + // either adds new Client or updates existing Client + gData.geofenceInterface->addClient(this, locationCallbacks); + } + } + + gData.clientData[this] = locationCallbacks; + + pthread_mutex_unlock(&gDataMutex); +} + +uint32_t +LocationAPI::startTracking(LocationOptions& locationOptions) +{ + uint32_t id = 0; + pthread_mutex_lock(&gDataMutex); + + auto it = gData.clientData.find(this); + if (it != gData.clientData.end()) { + if (gData.flpInterface != NULL && locationOptions.minDistance > 0) { + id = gData.flpInterface->startTracking(this, locationOptions); + } else if (gData.gnssInterface != NULL && needsGnssTrackingInfo(it->second)) { + id = gData.gnssInterface->startTracking(this, locationOptions); + } else if (gData.flpInterface != NULL) { + id = gData.flpInterface->startTracking(this, locationOptions); + } else if (gData.gnssInterface != NULL) { + id = gData.gnssInterface->startTracking(this, locationOptions); + } else { + LOC_LOGE("%s:%d]: No gnss/flp interface available for Location API client %p ", + __func__, __LINE__, this); + } + } else { + LOC_LOGE("%s:%d]: Location API client %p not found in client data", + __func__, __LINE__, this); + } + + pthread_mutex_unlock(&gDataMutex); + return id; +} + +void +LocationAPI::stopTracking(uint32_t id) +{ + pthread_mutex_lock(&gDataMutex); + + auto it = gData.clientData.find(this); + if (it != gData.clientData.end()) { + // we don't know if tracking was started on flp or gnss, so we call stop on both, where + // stopTracking call to the incorrect interface will fail without response back to client + if (gData.gnssInterface != NULL) { + gData.gnssInterface->stopTracking(this, id); + } + if (gData.flpInterface != NULL) { + gData.flpInterface->stopTracking(this, id); + } + if (gData.flpInterface != NULL && gData.gnssInterface != NULL) { + LOC_LOGE("%s:%d]: No gnss/flp interface available for Location API client %p ", + __func__, __LINE__, this); + } + } else { + LOC_LOGE("%s:%d]: Location API client %p not found in client data", + __func__, __LINE__, this); + } + + pthread_mutex_unlock(&gDataMutex); +} + +void +LocationAPI::updateTrackingOptions(uint32_t id, LocationOptions& locationOptions) +{ + pthread_mutex_lock(&gDataMutex); + + auto it = gData.clientData.find(this); + if (it != gData.clientData.end()) { + // we don't know if tracking was started on flp or gnss, so we call update on both, where + // updateTracking call to the incorrect interface will fail without response back to client + if (gData.gnssInterface != NULL) { + gData.gnssInterface->updateTrackingOptions(this, id, locationOptions); + } + if (gData.flpInterface != NULL) { + gData.flpInterface->updateTrackingOptions(this, id, locationOptions); + } + if (gData.flpInterface != NULL && gData.gnssInterface != NULL) { + LOC_LOGE("%s:%d]: No gnss/flp interface available for Location API client %p ", + __func__, __LINE__, this); + } + } else { + LOC_LOGE("%s:%d]: Location API client %p not found in client data", + __func__, __LINE__, this); + } + + pthread_mutex_unlock(&gDataMutex); +} + +uint32_t +LocationAPI::startBatching(LocationOptions& locationOptions) +{ + uint32_t id = 0; + pthread_mutex_lock(&gDataMutex); + + if (gData.flpInterface != NULL) { + id = gData.flpInterface->startBatching(this, locationOptions); + } else { + LOC_LOGE("%s:%d]: No flp interface available for Location API client %p ", + __func__, __LINE__, this); + } + + pthread_mutex_unlock(&gDataMutex); + return id; +} + +void +LocationAPI::stopBatching(uint32_t id) +{ + pthread_mutex_lock(&gDataMutex); + + if (gData.flpInterface != NULL) { + gData.flpInterface->stopBatching(this, id); + } else { + LOC_LOGE("%s:%d]: No flp interface available for Location API client %p ", + __func__, __LINE__, this); + } + + pthread_mutex_unlock(&gDataMutex); +} + +void +LocationAPI::updateBatchingOptions(uint32_t id, LocationOptions& locationOptions) +{ + pthread_mutex_lock(&gDataMutex); + + if (gData.flpInterface != NULL) { + gData.flpInterface->updateBatchingOptions(this, + id, + locationOptions); + } else { + LOC_LOGE("%s:%d]: No flp interface available for Location API client %p ", + __func__, __LINE__, this); + } + + pthread_mutex_unlock(&gDataMutex); +} + +void +LocationAPI::getBatchedLocations(uint32_t id, size_t count) +{ + pthread_mutex_lock(&gDataMutex); + + if (gData.flpInterface != NULL) { + gData.flpInterface->getBatchedLocations(this, id, count); + } else { + LOC_LOGE("%s:%d]: No flp interface available for Location API client %p ", + __func__, __LINE__, this); + } + + pthread_mutex_unlock(&gDataMutex); +} + +uint32_t* +LocationAPI::addGeofences(size_t count, GeofenceOption* options, GeofenceInfo* info) +{ + uint32_t* ids = NULL; + pthread_mutex_lock(&gDataMutex); + + if (gData.geofenceInterface != NULL) { + ids = gData.geofenceInterface->addGeofences(this, count, options, info); + } else { + LOC_LOGE("%s:%d]: No geofence interface available for Location API client %p ", + __func__, __LINE__, this); + } + + pthread_mutex_unlock(&gDataMutex); + return ids; +} + +void +LocationAPI::removeGeofences(size_t count, uint32_t* ids) +{ + pthread_mutex_lock(&gDataMutex); + + if (gData.geofenceInterface != NULL) { + gData.geofenceInterface->removeGeofences(this, count, ids); + } else { + LOC_LOGE("%s:%d]: No geofence interface available for Location API client %p ", + __func__, __LINE__, this); + } + + pthread_mutex_unlock(&gDataMutex); +} + +void +LocationAPI::modifyGeofences(size_t count, uint32_t* ids, GeofenceOption* options) +{ + pthread_mutex_lock(&gDataMutex); + + if (gData.geofenceInterface != NULL) { + gData.geofenceInterface->modifyGeofences(this, count, ids, options); + } else { + LOC_LOGE("%s:%d]: No geofence interface available for Location API client %p ", + __func__, __LINE__, this); + } + + pthread_mutex_unlock(&gDataMutex); +} + +void +LocationAPI::pauseGeofences(size_t count, uint32_t* ids) +{ + pthread_mutex_lock(&gDataMutex); + + if (gData.geofenceInterface != NULL) { + gData.geofenceInterface->pauseGeofences(this, count, ids); + } else { + LOC_LOGE("%s:%d]: No geofence interface available for Location API client %p ", + __func__, __LINE__, this); + } + + pthread_mutex_unlock(&gDataMutex); +} + +void +LocationAPI::resumeGeofences(size_t count, uint32_t* ids) +{ + pthread_mutex_lock(&gDataMutex); + + if (gData.geofenceInterface != NULL) { + gData.geofenceInterface->resumeGeofences(this, count, ids); + } else { + LOC_LOGE("%s:%d]: No geofence interface available for Location API client %p ", + __func__, __LINE__, this); + } + + pthread_mutex_unlock(&gDataMutex); +} + +void +LocationAPI::gnssNiResponse(uint32_t id, GnssNiResponse response) +{ + pthread_mutex_lock(&gDataMutex); + + if (gData.gnssInterface != NULL) { + gData.gnssInterface->gnssNiResponse(this, id, response); + } else { + LOC_LOGE("%s:%d]: No gnss interface available for Location API client %p ", + __func__, __LINE__, this); + } + + pthread_mutex_unlock(&gDataMutex); +} + +LocationControlAPI* +LocationControlAPI::createInstance(LocationControlCallbacks& locationControlCallbacks) +{ + LocationControlAPI* controlAPI = NULL; + pthread_mutex_lock(&gDataMutex); + + if (nullptr != locationControlCallbacks.responseCb && NULL == gData.controlAPI) { + if (NULL == gData.gnssInterface && !gGnssLoadFailed) { + gData.gnssInterface = + (GnssInterface*)loadLocationInterface("libgnss.so", "getGnssInterface"); + if (NULL == gData.gnssInterface) { + gGnssLoadFailed = true; + LOC_LOGW("%s:%d]: No gnss interface available", __func__, __LINE__); + } else { + gData.gnssInterface->initialize(); + } + } + if (NULL != gData.gnssInterface) { + gData.controlAPI = new LocationControlAPI(); + gData.controlCallbacks = locationControlCallbacks; + gData.gnssInterface->setControlCallbacks(locationControlCallbacks); + controlAPI = gData.controlAPI; + } + } + + pthread_mutex_unlock(&gDataMutex); + return controlAPI; +} + +void +LocationControlAPI::destroy() +{ + delete this; +} + +LocationControlAPI::LocationControlAPI() +{ + LOC_LOGD("LOCATION CONTROL API CONSTRUCTOR"); +} + +LocationControlAPI::~LocationControlAPI() +{ + LOC_LOGD("LOCATION CONTROL API DESTRUCTOR"); + pthread_mutex_lock(&gDataMutex); + + size_t gnssClientCount = 0; + for (auto it=gData.clientData.begin(); it != gData.clientData.end(); ++it) { + if (isGnssClient(it->second)) { + gnssClientCount++; + } + } + if (gData.gnssInterface != NULL && 0 == gnssClientCount) { + //@todo: we might want to call gData.gnssInterface.disable before deinitialize? + gData.gnssInterface->deinitialize(); + } + gData.controlAPI = NULL; + + pthread_mutex_unlock(&gDataMutex); +} + +uint32_t +LocationControlAPI::enable(LocationTechnologyType techType) +{ + uint32_t id = 0; + pthread_mutex_lock(&gDataMutex); + + if (gData.gnssInterface != NULL) { + id = gData.gnssInterface->enable(techType); + } else { + LOC_LOGE("%s:%d]: No gnss interface available for Location Control API client %p ", + __func__, __LINE__, this); + } + + pthread_mutex_unlock(&gDataMutex); + return id; +} + +void +LocationControlAPI::disable(uint32_t id) +{ + pthread_mutex_lock(&gDataMutex); + + if (gData.gnssInterface != NULL) { + gData.gnssInterface->disable(id); + } else { + LOC_LOGE("%s:%d]: No gnss interface available for Location Control API client %p ", + __func__, __LINE__, this); + } + + pthread_mutex_unlock(&gDataMutex); +} + +uint32_t* +LocationControlAPI::gnssUpdateConfig(GnssConfig config) +{ + uint32_t* ids = NULL; + pthread_mutex_lock(&gDataMutex); + + if (gData.gnssInterface != NULL) { + ids = gData.gnssInterface->gnssUpdateConfig(config); + } else { + LOC_LOGE("%s:%d]: No gnss interface available for Location Control API client %p ", + __func__, __LINE__, this); + } + + pthread_mutex_unlock(&gDataMutex); + return ids; +} + +uint32_t +LocationControlAPI::gnssDeleteAidingData(GnssAidingData& data) +{ + uint32_t id = 0; + pthread_mutex_lock(&gDataMutex); + + if (gData.gnssInterface != NULL) { + id = gData.gnssInterface->gnssDeleteAidingData(data); + } else { + LOC_LOGE("%s:%d]: No gnss interface available for Location Control API client %p ", + __func__, __LINE__, this); + } + + pthread_mutex_unlock(&gDataMutex); + return id; +} diff --git a/location/LocationAPI.h b/location/LocationAPI.h new file mode 100644 index 0000000..cc15ddd --- /dev/null +++ b/location/LocationAPI.h @@ -0,0 +1,866 @@ +/* Copyright (c) 2017 The Linux Foundation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * * Neither the name of The Linux Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef LOCATION_H +#define LOCATION_H + +#include <stdint.h> +#include <functional> + +#define GNSS_NI_REQUESTOR_MAX 256 +#define GNSS_NI_MESSAGE_ID_MAX 2048 +#define GNSS_SV_MAX 64 +#define GNSS_MEASUREMENTS_MAX 64 + +typedef enum { + LOCATION_ERROR_SUCCESS = 0, + LOCATION_ERROR_GENERAL_FAILURE, + LOCATION_ERROR_CALLBACK_MISSING, + LOCATION_ERROR_INVALID_PARAMETER, + LOCATION_ERROR_ID_EXISTS, + LOCATION_ERROR_ID_UNKNOWN, + LOCATION_ERROR_ALREADY_STARTED, + LOCATION_ERROR_GEOFENCES_AT_MAX, + LOCATION_ERROR_NOT_SUPPORTED +} LocationError; + +// Flags to indicate which values are valid in a Location +typedef uint16_t LocationFlagsMask; +typedef enum { + LOCATION_HAS_LAT_LONG_BIT = (1<<0), // location has valid latitude and longitude + LOCATION_HAS_ALTITUDE_BIT = (1<<1), // location has valid altitude + LOCATION_HAS_SPEED_BIT = (1<<2), // location has valid speed + LOCATION_HAS_BEARING_BIT = (1<<3), // location has valid bearing + LOCATION_HAS_ACCURACY_BIT = (1<<4), // location has valid accuracy +} LocationFlagsBits; + +typedef uint16_t LocationTechnologyMask; +typedef enum { + LOCATION_TECHNOLOGY_GNSS_BIT = (1<<0), // location was calculated using GNSS + LOCATION_TECHNOLOGY_CELL_BIT = (1<<1), // location was calculated using Cell + LOCATION_TECHNOLOGY_WIFI_BIT = (1<<2), // location was calculated using WiFi + LOCATION_TECHNOLOGY_SENSORS_BIT = (1<<3), // location was calculated using Sensors +} LocationTechnologyBits; + +typedef enum { + LOCATION_RELIABILITY_NOT_SET = 0, + LOCATION_RELIABILITY_VERY_LOW, + LOCATION_RELIABILITY_LOW, + LOCATION_RELIABILITY_MEDIUM, + LOCATION_RELIABILITY_HIGH, +} LocationReliability; + +typedef uint32_t GnssLocationInfoFlagMask; +typedef enum { + GNSS_LOCATION_INFO_ALTITUDE_MEAN_SEA_LEVEL_BIT = (1<<0), // valid altitude mean sea level + GNSS_LOCATION_INFO_DOP_BIT = (1<<1), // valid pdop, hdop, and vdop + GNSS_LOCATION_INFO_MAGNETIC_DEVIATION_BIT = (1<<2), // valid magnetic deviation + GNSS_LOCATION_INFO_VER_ACCURACY_BIT = (1<<3), // valid vertical accuracy + GNSS_LOCATION_INFO_SPEED_ACCURACY_BIT = (1<<4), // valid speed accuracy + GNSS_LOCATION_INFO_BEARING_ACCURACY_BIT = (1<<5), // valid bearing accuracy + GNSS_LOCATION_INFO_HOR_RELIABILITY_BIT = (1<<6), // valid horizontal reliability + GNSS_LOCATION_INFO_VER_RELIABILITY_BIT = (1<<7), // valid vertical reliability + GNSS_LOCATION_INFO_HOR_ACCURACY_ELIP_SEMI_MAJOR_BIT = (1<<8), // valid elipsode semi major + GNSS_LOCATION_INFO_HOR_ACCURACY_ELIP_SEMI_MINOR_BIT = (1<<9), // valid elipsode semi minor + GNSS_LOCATION_INFO_HOR_ACCURACY_ELIP_AZIMUTH_BIT = (1<<10),// valid accuracy elipsode azimuth +} GnssLocationInfoFlagBits; + +typedef enum { + GEOFENCE_BREACH_ENTER = 0, + GEOFENCE_BREACH_EXIT, + GEOFENCE_BREACH_DWELL_IN, + GEOFENCE_BREACH_DWELL_OUT, + GEOFENCE_BREACH_UNKNOWN, +} GeofenceBreachType; + +typedef uint16_t GeofenceBreachTypeMask; +typedef enum { + GEOFENCE_BREACH_ENTER_BIT = (1<<0), + GEOFENCE_BREACH_EXIT_BIT = (1<<1), + GEOFENCE_BREACH_DWELL_IN_BIT = (1<<2), + GEOFENCE_BREACH_DWELL_OUT_BIT = (1<<3), +} GeofenceBreachTypeBits; + +typedef enum { + GEOFENCE_STATUS_AVAILABILE_NO = 0, + GEOFENCE_STATUS_AVAILABILE_YES, +} GeofenceStatusAvailable; + +typedef uint32_t LocationCapabilitiesMask; +typedef enum { + // supports startTracking API with minInterval param + LOCATION_CAPABILITIES_TIME_BASED_TRACKING_BIT = (1<<0), + // supports startBatching API with minInterval param + LOCATION_CAPABILITIES_TIME_BASED_BATCHING_BIT = (1<<1), + // supports startTracking API with minDistance param + LOCATION_CAPABILITIES_DISTANCE_BASED_TRACKING_BIT = (1<<2), + // supports startBatching API with minDistance param + LOCATION_CAPABILITIES_DISTANCE_BASED_BATCHING_BIT = (1<<3), + // supports addGeofences API + LOCATION_CAPABILITIES_GEOFENCE_BIT = (1<<4), + // supports GnssMeasurementsCallback + LOCATION_CAPABILITIES_GNSS_MEASUREMENTS_BIT = (1<<5), + // supports startTracking/startBatching API with LocationOptions.mode of MSB (Ms Based) + LOCATION_CAPABILITIES_GNSS_MSB_BIT = (1<<6), + // supports startTracking/startBatching API with LocationOptions.mode of MSA (MS Assisted) + LOCATION_CAPABILITIES_GNSS_MSA_BIT = (1<<7), +} LocationCapabilitiesBits; + +typedef enum { + LOCATION_TECHNOLOGY_TYPE_GNSS = 0, +} LocationTechnologyType; + +// Configures how GPS is locked when GPS is disabled (through GnssDisable) +typedef enum { + GNSS_CONFIG_GPS_LOCK_NONE = 0, // gps is not locked when GPS is disabled (GnssDisable) + GNSS_CONFIG_GPS_LOCK_MO, // gps mobile originated (MO) is locked when GPS is disabled + GNSS_CONFIG_GPS_LOCK_NI, // gps network initiated (NI) is locked when GPS is disabled + GNSS_CONFIG_GPS_LOCK_MO_AND_NI,// gps MO and NI is locked when GPS is disabled +} GnssConfigGpsLock; + +// SUPL version +typedef enum { + GNSS_CONFIG_SUPL_VERSION_1_0_0 = 1, + GNSS_CONFIG_SUPL_VERSION_2_0_0, + GNSS_CONFIG_SUPL_VERSION_2_0_2, +} GnssConfigSuplVersion; + +// LTE Positioning Profile +typedef enum { + GNSS_CONFIG_LPP_PROFILE_RRLP_ON_LTE = 0, // RRLP on LTE (Default) + GNSS_CONFIG_LPP_PROFILE_USER_PLANE, // LPP User Plane (UP) on LTE + GNSS_CONFIG_LPP_PROFILE_CONTROL_PLANE, // LPP_Control_Plane (CP) + GNSS_CONFIG_LPP_PROFILE_USER_PLANE_AND_CONTROL_PLANE, // Both LPP UP and CP +} GnssConfigLppProfile; + +// Technology for LPPe Control Plane +typedef uint16_t GnssConfigLppeControlPlaneMask; +typedef enum { + GNSS_CONFIG_LPPE_CONTROL_PLANE_DBH_BIT = (1<<0), // DBH + GNSS_CONFIG_LPPE_CONTROL_PLANE_WLAN_AP_MEASUREMENTS_BIT = (1<<1), // WLAN_AP_MEASUREMENTS +} GnssConfigLppeControlPlaneBits; + +// Technology for LPPe User Plane +typedef uint16_t GnssConfigLppeUserPlaneMask; +typedef enum { + GNSS_CONFIG_LPPE_USER_PLANE_DBH_BIT = (1<<0), // DBH + GNSS_CONFIG_LPPE_USER_PLANE_WLAN_AP_MEASUREMENTS_BIT = (1<<1), // WLAN_AP_MEASUREMENTS +} GnssConfigLppeUserPlaneBits; + +// Positioning Protocol on A-GLONASS system +typedef uint16_t GnssConfigAGlonassPositionProtocolMask; +typedef enum { + GNSS_CONFIG_RRC_CONTROL_PLANE_BIT = (1<<0), // RRC Control Plane + GNSS_CONFIG_RRLP_USER_PLANE_BIT = (1<<1), // RRLP User Plane + GNSS_CONFIG_LLP_USER_PLANE_BIT = (1<<2), // LPP User Plane + GNSS_CONFIG_LLP_CONTROL_PLANE_BIT = (1<<3), // LPP Control Plane +} GnssConfigAGlonassPositionProtocolBits; + +typedef enum { + GNSS_CONFIG_EMERGENCY_PDN_FOR_EMERGENCY_SUPL_NO = 0, + GNSS_CONFIG_EMERGENCY_PDN_FOR_EMERGENCY_SUPL_YES, +} GnssConfigEmergencyPdnForEmergencySupl; + +typedef enum { + GNSS_CONFIG_SUPL_EMERGENCY_SERVICES_NO = 0, + GNSS_CONFIG_SUPL_EMERGENCY_SERVICES_YES, +} GnssConfigSuplEmergencyServices; + +typedef uint16_t GnssConfigSuplModeMask; +typedef enum { + GNSS_CONFIG_SUPL_MODE_MSB = (1<<0), + GNSS_CONFIG_SUPL_MODE_MSA = (1<<1), +} GnssConfigSuplModeBits; + +typedef uint32_t GnssConfigFlagsMask; +typedef enum { + GNSS_CONFIG_FLAGS_GPS_LOCK_VALID_BIT = (1<<0), + GNSS_CONFIG_FLAGS_SUPL_VERSION_VALID_BIT = (1<<1), + GNSS_CONFIG_FLAGS_SET_ASSISTANCE_DATA_VALID_BIT = (1<<2), + GNSS_CONFIG_FLAGS_LPP_PROFILE_VALID_BIT = (1<<3), + GNSS_CONFIG_FLAGS_LPPE_CONTROL_PLANE_VALID_BIT = (1<<4), + GNSS_CONFIG_FLAGS_LPPE_USER_PLANE_VALID_BIT = (1<<5), + GNSS_CONFIG_FLAGS_AGLONASS_POSITION_PROTOCOL_VALID_BIT = (1<<6), + GNSS_CONFIG_FLAGS_EM_PDN_FOR_EM_SUPL_VALID_BIT = (1<<7), + GNSS_CONFIG_FLAGS_SUPL_EM_SERVICES_BIT = (1<<8), + GNSS_CONFIG_FLAGS_SUPL_MODE_BIT = (1<<9), +} GnssConfigFlagsBits; + +typedef enum { + GNSS_NI_ENCODING_TYPE_NONE = 0, + GNSS_NI_ENCODING_TYPE_GSM_DEFAULT, + GNSS_NI_ENCODING_TYPE_UTF8, + GNSS_NI_ENCODING_TYPE_UCS2, +} GnssNiEncodingType; + +typedef enum { + GNSS_NI_TYPE_VOICE = 0, + GNSS_NI_TYPE_SUPL, + GNSS_NI_TYPE_CONTROL_PLANE, + GNSS_NI_TYPE_EMERGENCY_SUPL +} GnssNiType; + +typedef uint16_t GnssNiOptionsMask; +typedef enum { + GNSS_NI_OPTIONS_NOTIFICATION = (1<<0), + GNSS_NI_OPTIONS_VERIFICATION = (1<<1), + GNSS_NI_OPTIONS_PRIVACY_OVERRIDE = (1<<2), +} GnssNiOptionsBits; + +typedef enum { + GNSS_NI_RESPONSE_ACCEPT = 1, + GNSS_NI_RESPONSE_DENY, + GNSS_NI_RESPONSE_NO_RESPONSE, + GNSS_NI_RESPONSE_IGNORE, +} GnssNiResponse; + +typedef enum { + GNSS_SV_TYPE_UNKNOWN = 0, + GNSS_SV_TYPE_GPS, + GNSS_SV_TYPE_SBAS, + GNSS_SV_TYPE_GLONASS, + GNSS_SV_TYPE_QZSS, + GNSS_SV_TYPE_BEIDOU, + GNSS_SV_TYPE_GALILEO, +} GnssSvType; + +typedef uint16_t GnssSvOptionsMask; +typedef enum { + GNSS_SV_OPTIONS_HAS_EPHEMER_BIT = (1<<0), + GNSS_SV_OPTIONS_HAS_ALMANAC_BIT = (1<<1), + GNSS_SV_OPTIONS_USED_IN_FIX_BIT = (1<<2), +} GnssSvOptionsBits; + +typedef enum { + GNSS_ASSISTANCE_TYPE_SUPL = 0, + GNSS_ASSISTANCE_TYPE_C2K, +} GnssAssistanceType; + +typedef enum { + GNSS_SUPL_MODE_STANDALONE = 0, + GNSS_SUPL_MODE_MSB, + GNSS_SUPL_MODE_MSA, +} GnssSuplMode; + +typedef uint16_t GnssMeasurementsAdrStateMask; +typedef enum { + GNSS_MEASUREMENTS_ACCUMULATED_DELTA_RANGE_STATE_UNKNOWN = 0, + GNSS_MEASUREMENTS_ACCUMULATED_DELTA_RANGE_STATE_VALID_BIT = (1<<0), + GNSS_MEASUREMENTS_ACCUMULATED_DELTA_RANGE_STATE_RESET_BIT = (1<<1), + GNSS_MEASUREMENTS_ACCUMULATED_DELTA_RANGE_STATE_CYCLE_SLIP_BIT = (1<<2), +} GnssMeasurementsAdrStateBits; + +typedef uint32_t GnssMeasurementsDataFlagsMask; +typedef enum { + GNSS_MEASUREMENTS_DATA_SV_ID_BIT = (1<<0), + GNSS_MEASUREMENTS_DATA_SV_TYPE_BIT = (1<<1), + GNSS_MEASUREMENTS_DATA_STATE_BIT = (1<<2), + GNSS_MEASUREMENTS_DATA_RECEIVED_SV_TIME_BIT = (1<<3), + GNSS_MEASUREMENTS_DATA_RECEIVED_SV_TIME_UNCERTAINTY_BIT = (1<<4), + GNSS_MEASUREMENTS_DATA_CARRIER_TO_NOISE_BIT = (1<<5), + GNSS_MEASUREMENTS_DATA_PSEUDORANGE_RATE_BIT = (1<<6), + GNSS_MEASUREMENTS_DATA_PSEUDORANGE_RATE_UNCERTAINTY_BIT = (1<<7), + GNSS_MEASUREMENTS_DATA_ADR_STATE_BIT = (1<<8), + GNSS_MEASUREMENTS_DATA_ADR_BIT = (1<<9), + GNSS_MEASUREMENTS_DATA_ADR_UNCERTAINTY_BIT = (1<<10), + GNSS_MEASUREMENTS_DATA_CARRIER_FREQUENCY_BIT = (1<<11), + GNSS_MEASUREMENTS_DATA_CARRIER_CYCLES_BIT = (1<<12), + GNSS_MEASUREMENTS_DATA_CARRIER_PHASE_BIT = (1<<13), + GNSS_MEASUREMENTS_DATA_CARRIER_PHASE_UNCERTAINTY_BIT = (1<<14), + GNSS_MEASUREMENTS_DATA_MULTIPATH_INDICATOR_BIT = (1<<15), + GNSS_MEASUREMENTS_DATA_SIGNAL_TO_NOISE_RATIO_BIT = (1<<16), +} GnssMeasurementsDataFlagsBits; + +typedef uint32_t GnssMeasurementsStateMask; +typedef enum { + GNSS_MEASUREMENTS_STATE_UNKNOWN_BIT = 0, + GNSS_MEASUREMENTS_STATE_CODE_LOCK_BIT = (1<<0), + GNSS_MEASUREMENTS_STATE_BIT_SYNC_BIT = (1<<1), + GNSS_MEASUREMENTS_STATE_SUBFRAME_SYNC_BIT = (1<<2), + GNSS_MEASUREMENTS_STATE_TOW_DECODED_BIT = (1<<3), + GNSS_MEASUREMENTS_STATE_MSEC_AMBIGUOUS_BIT = (1<<4), + GNSS_MEASUREMENTS_STATE_SYMBOL_SYNC_BIT = (1<<5), + GNSS_MEASUREMENTS_STATE_GLO_STRING_SYNC_BIT = (1<<6), + GNSS_MEASUREMENTS_STATE_GLO_TOD_DECODED_BIT = (1<<7), + GNSS_MEASUREMENTS_STATE_BDS_D2_BIT_SYNC_BIT = (1<<8), + GNSS_MEASUREMENTS_STATE_BDS_D2_SUBFRAME_SYNC_BIT = (1<<9), + GNSS_MEASUREMENTS_STATE_GAL_E1BC_CODE_LOCK_BIT = (1<<10), + GNSS_MEASUREMENTS_STATE_GAL_E1C_2ND_CODE_LOCK_BIT = (1<<11), + GNSS_MEASUREMENTS_STATE_GAL_E1B_PAGE_SYNC_BIT = (1<<12), + GNSS_MEASUREMENTS_STATE_SBAS_SYNC_BIT = (1<<13), +} GnssMeasurementsStateBits; + +typedef enum { + GNSS_MEASUREMENTS_MULTIPATH_INDICATOR_UNKNOWN = 0, + GNSS_MEASUREMENTS_MULTIPATH_INDICATOR_PRESENT, + GNSS_MEASUREMENTS_MULTIPATH_INDICATOR_NOT_PRESENT, +} GnssMeasurementsMultipathIndicator; + +typedef uint32_t GnssMeasurementsClockFlagsMask; +typedef enum { + GNSS_MEASUREMENTS_CLOCK_FLAGS_LEAP_SECOND_BIT = (1<<0), + GNSS_MEASUREMENTS_CLOCK_FLAGS_TIME_BIT = (1<<1), + GNSS_MEASUREMENTS_CLOCK_FLAGS_TIME_UNCERTAINTY_BIT = (1<<2), + GNSS_MEASUREMENTS_CLOCK_FLAGS_FULL_BIAS_BIT = (1<<3), + GNSS_MEASUREMENTS_CLOCK_FLAGS_BIAS_BIT = (1<<4), + GNSS_MEASUREMENTS_CLOCK_FLAGS_BIAS_UNCERTAINTY_BIT = (1<<5), + GNSS_MEASUREMENTS_CLOCK_FLAGS_DRIFT_BIT = (1<<6), + GNSS_MEASUREMENTS_CLOCK_FLAGS_DRIFT_UNCERTAINTY_BIT = (1<<7), + GNSS_MEASUREMENTS_CLOCK_FLAGS_HW_CLOCK_DISCONTINUITY_COUNT_BIT = (1<<8), +} GnssMeasurementsClockFlagsBits; + +typedef uint32_t GnssAidingDataSvMask; +typedef enum { + GNSS_AIDING_DATA_SV_EPHEMERIS = (1<<0), // ephemeris + GNSS_AIDING_DATA_SV_ALMANAC = (1<<1), // almanac + GNSS_AIDING_DATA_SV_HEALTH = (1<<2), // health + GNSS_AIDING_DATA_SV_DIRECTION = (1<<3), // direction + GNSS_AIDING_DATA_SV_STEER = (1<<4), // steer + GNSS_AIDING_DATA_SV_ALMANAC_CORR = (1<<5), // almanac correction + GNSS_AIDING_DATA_SV_BLACKLIST = (1<<6), // blacklist SVs + GNSS_AIDING_DATA_SV_SA_DATA = (1<<7), // sensitivity assistance data + GNSS_AIDING_DATA_SV_NO_EXIST = (1<<8), // SV does not exist + GNSS_AIDING_DATA_SV_IONOSPHERE = (1<<9), // ionosphere correction + GNSS_AIDING_DATA_SV_TIME = (1<<10),// reset satellite time +} GnssAidingDataSvBits; + +typedef uint32_t GnssAidingDataSvTypeMask; +typedef enum { + GNSS_AIDING_DATA_SV_TYPE_GPS = (1<<0), + GNSS_AIDING_DATA_SV_TYPE_GLONASS = (1<<1), + GNSS_AIDING_DATA_SV_TYPE_QZSS = (1<<2), + GNSS_AIDING_DATA_SV_TYPE_BEIDOU = (1<<3), + GNSS_AIDING_DATA_SV_TYPE_GALILEO = (1<<4), +} GnssAidingDataSvTypeBits; + +typedef struct { + GnssAidingDataSvMask svMask; // bitwise OR of GnssAidingDataSvBits + GnssAidingDataSvTypeMask svTypeMask; // bitwise OR of GnssAidingDataSvTypeBits +} GnssAidingDataSv; + +typedef uint32_t GnssAidingDataCommonMask; +typedef enum { + GNSS_AIDING_DATA_COMMON_POSITION = (1<<0), // position estimate + GNSS_AIDING_DATA_COMMON_TIME = (1<<1), // reset all clock values + GNSS_AIDING_DATA_COMMON_UTC = (1<<2), // UTC estimate + GNSS_AIDING_DATA_COMMON_RTI = (1<<3), // RTI + GNSS_AIDING_DATA_COMMON_FREQ_BIAS_EST = (1<<4), // frequency bias estimate + GNSS_AIDING_DATA_COMMON_CELLDB = (1<<5), // all celldb info +} GnssAidingDataCommonBits; + +typedef struct { + GnssAidingDataCommonMask mask; // bitwise OR of GnssAidingDataCommonBits +} GnssAidingDataCommon; + +typedef struct { + bool deleteAll; // if true, delete all aiding data and ignore other params + GnssAidingDataSv sv; // SV specific aiding data + GnssAidingDataCommon common; // common aiding data +} GnssAidingData; + +typedef struct { + size_t size; // set to sizeof(Location) + LocationFlagsMask flags; // bitwise OR of LocationFlagsBits to mark which params are valid + uint64_t timestamp; // UTC timestamp for location fix, milliseconds since January 1, 1970 + double latitude; // in degrees + double longitude; // in degrees + double altitude; // in meters above the WGS 84 reference ellipsoid + float speed; // in meters per second + float bearing; // in degrees; range [0, 360) + float accuracy; // in meters + LocationTechnologyMask techMask; +} Location; + +typedef struct { + size_t size; // set to sizeof(LocationOptions) + uint32_t minInterval; // in milliseconds + uint32_t minDistance; // in meters. if minDistance > 0, gnssSvCallback/gnssNmeaCallback/ + // gnssMeasurementsCallback may not be called + GnssSuplMode mode; // Standalone/MS-Based/MS-Assisted +} LocationOptions; + +typedef struct { + size_t size; // set to sizeof(GeofenceOption) + GeofenceBreachTypeMask breachTypeMask; // bitwise OR of GeofenceBreachTypeBits + uint32_t responsiveness; // in milliseconds + uint32_t dwellTime; // in seconds +} GeofenceOption; + +typedef struct { + size_t size; // set to sizeof(GeofenceInfo) + double latitude; // in degrees + double longitude; // in degrees + double radius; // in meters +} GeofenceInfo; + +typedef struct { + size_t size; // set to sizeof(GeofenceBreachNotification) + size_t count; // number of ids in array + uint32_t* ids; // array of ids that have breached + Location location; // location associated with breach + GeofenceBreachType type; // type of breach + uint64_t timestamp; // timestamp of breach +} GeofenceBreachNotification; + +typedef struct { + size_t size; // set to sizeof(GeofenceBreachNotification) + GeofenceStatusAvailable available; // GEOFENCE_STATUS_AVAILABILE_NO/_YES + LocationTechnologyType techType; // GNSS +} GeofenceStatusNotification; + +typedef struct { + size_t size; // set to sizeof(GnssLocationInfo) + GnssLocationInfoFlagMask flags; // bitwise OR of GnssLocationInfoBits for param validity + float altitudeMeanSeaLevel; // altitude wrt mean sea level + float pdop; // position dilusion of precision + float hdop; // horizontal dilusion of precision + float vdop; // vertical dilusion of precision + float magneticDeviation; // magnetic deviation + float verAccuracy; // vertical accuracy in meters + float speedAccuracy; // speed accuracy in meters/second + float bearingAccuracy; // bearing accuracy in degrees (0 to 359.999) + LocationReliability horReliability; // horizontal reliability + LocationReliability verReliability; // vertical reliability + float horUncEllipseSemiMajor; // horizontal elliptical accuracy semi-major axis + float horUncEllipseSemiMinor; // horizontal elliptical accuracy semi-minor axis + float horUncEllipseOrientAzimuth; // horizontal elliptical accuracy azimuth +} GnssLocationInfoNotification; + +typedef struct { + size_t size; // set to sizeof(GnssNiNotification) + GnssNiType type; // type of NI (Voice, SUPL, Control Plane) + GnssNiOptionsMask options; // bitwise OR of GnssNiOptionsBits + uint32_t timeout; // time (seconds) to wait for user input + GnssNiResponse timeoutResponse; // the response that should be sent when timeout expires + char requestor[GNSS_NI_REQUESTOR_MAX]; // the requestor that is making the request + GnssNiEncodingType requestorEncoding; // the encoding type for requestor + char message[GNSS_NI_MESSAGE_ID_MAX]; // the message to show user + GnssNiEncodingType messageEncoding; // the encoding type for message + char extras[GNSS_NI_MESSAGE_ID_MAX]; +} GnssNiNotification; + +typedef struct { + size_t size; // set to sizeof(GnssSv) + uint16_t svId; // Unique Identifier + GnssSvType type; // type of SV (GPS, SBAS, GLONASS, QZSS, BEIDOU, GALILEO) + float cN0Dbhz; // signal strength + float elevation; // elevation of SV (in degrees) + float azimuth; // azimuth of SV (in degrees) + GnssSvOptionsMask gnssSvOptionsMask; // Bitwise OR of GnssSvOptionsBits +} GnssSv; + +typedef struct { + size_t size; // set to sizeof(GnssConfigSetAssistanceServer) + GnssAssistanceType type; // SUPL or C2K + const char* hostName; // null terminated string + uint32_t port; // port of server +} GnssConfigSetAssistanceServer; + +typedef struct { + size_t size; // set to sizeof(GnssMeasurementsData) + GnssMeasurementsDataFlagsMask flags; // bitwise OR of GnssMeasurementsDataFlagsBits + int16_t svId; + GnssSvType svType; + double timeOffsetNs; + GnssMeasurementsStateMask stateMask; // bitwise OR of GnssMeasurementsStateBits + int64_t receivedSvTimeNs; + int64_t receivedSvTimeUncertaintyNs; + double carrierToNoiseDbHz; + double pseudorangeRateMps; + double pseudorangeRateUncertaintyMps; + GnssMeasurementsAdrStateMask adrStateMask; // bitwise OR of GnssMeasurementsAdrStateBits + double adrMeters; + double adrUncertaintyMeters; + float carrierFrequencyHz; + int64_t carrierCycles; + double carrierPhase; + double carrierPhaseUncertainty; + GnssMeasurementsMultipathIndicator multipathIndicator; + double signalToNoiseRatioDb; +} GnssMeasurementsData; + +typedef struct { + size_t size; // set to sizeof(GnssMeasurementsClock) + GnssMeasurementsClockFlagsMask flags; // bitwise OR of GnssMeasurementsClockFlagsBits + int16_t leapSecond; + int64_t timeNs; + double timeUncertaintyNs; + int64_t fullBiasNs; + double biasNs; + double biasUncertaintyNs; + double driftNsps; + double driftUncertaintyNsps; + uint32_t hwClockDiscontinuityCount; +} GnssMeasurementsClock; + +typedef struct { + size_t size; // set to sizeof(GnssSvNotification) + size_t count; // number of SVs in the GnssSv array + GnssSv gnssSvs[GNSS_SV_MAX]; // information on a number of SVs +} GnssSvNotification; + +typedef struct { + size_t size; // set to sizeof(GnssNmeaNotification) + uint64_t timestamp; // timestamp + const char* nmea; // nmea text + size_t length; // length of the nmea text +} GnssNmeaNotification; + +typedef struct { + size_t size; // set to sizeof(GnssMeasurementsNotification) + size_t count; // number of items in GnssMeasurements array + GnssMeasurementsData measurements[GNSS_MEASUREMENTS_MAX]; + GnssMeasurementsClock clock; // clock +} GnssMeasurementsNotification; + +typedef struct { + size_t size; // set to sizeof(GnssConfig) + GnssConfigFlagsMask flags; // bitwise OR of GnssConfigFlagsBits to mark which params are valid + GnssConfigGpsLock gpsLock; + GnssConfigSuplVersion suplVersion; + GnssConfigSetAssistanceServer assistanceServer; + GnssConfigLppProfile lppProfile; + GnssConfigLppeControlPlaneMask lppeControlPlaneMask; + GnssConfigLppeUserPlaneMask lppeUserPlaneMask; + GnssConfigAGlonassPositionProtocolMask aGlonassPositionProtocolMask; + GnssConfigEmergencyPdnForEmergencySupl emergencyPdnForEmergencySupl; + GnssConfigSuplEmergencyServices suplEmergencyServices; + GnssConfigSuplModeMask suplModeMask; //bitwise OR of GnssConfigSuplModeBits +} GnssConfig; + +/* Provides the capabilities of the system + capabilities callback is called once soon after createInstance is called */ +typedef std::function<void( + LocationCapabilitiesMask capabilitiesMask // bitwise OR of LocationCapabilitiesBits +)> capabilitiesCallback; + +/* Used by tracking, batching, and miscellanous APIs + responseCallback is called for every Tracking, Batching API, and Miscellanous API */ +typedef std::function<void( + LocationError err, // if not SUCCESS, then id is not valid + uint32_t id // id to be associated to the request +)> responseCallback; + +/* Used by APIs that gets more than one LocationError in it's response + collectiveResponseCallback is called for every geofence API call. + ids array and LocationError array are only valid until collectiveResponseCallback returns. */ +typedef std::function<void( + size_t count, // number of locations in arrays + LocationError* errs, // array of LocationError associated to the request + uint32_t* ids // array of ids to be associated to the request +)> collectiveResponseCallback; + +/* Used for startTracking API, optional can be NULL + trackingCallback is called when delivering a location in a tracking session + broadcasted to all clients, no matter if a session has started by client */ +typedef std::function<void( + Location location +)> trackingCallback; + +/* Used for startBatching API, optional can be NULL + batchingCallback is called when delivering locations in a batching session. + broadcasted to all clients, no matter if a session has started by client */ +typedef std::function<void( + size_t count, // number of locations in array + Location* location // array of locations +)> batchingCallback; + +/* Gives GNSS Location information, optional can be NULL + gnssLocationInfoCallback is called only during a tracking session + broadcasted to all clients, no matter if a session has started by client */ +typedef std::function<void( + GnssLocationInfoNotification gnssLocationInfoNotification +)> gnssLocationInfoCallback; + +/* Used for addGeofences API, optional can be NULL + geofenceBreachCallback is called when any number of geofences have a state change */ +typedef std::function<void( + GeofenceBreachNotification geofenceBreachNotification +)> geofenceBreachCallback; + +/* Used for addGeofences API, optional can be NULL + geofenceStatusCallback is called when any number of geofences have a status change */ +typedef std::function<void( + GeofenceStatusNotification geofenceStatusNotification +)> geofenceStatusCallback; + +/* Network Initiated request, optional can be NULL + This callback should be responded to by calling gnssNiResponse */ +typedef std::function<void( + uint32_t id, // id that should be used to respond by calling gnssNiResponse + GnssNiNotification gnssNiNotification +)> gnssNiCallback; + +/* Gives GNSS SV information, optional can be NULL + gnssSvCallback is called only during a tracking session + broadcasted to all clients, no matter if a session has started by client */ +typedef std::function<void( + GnssSvNotification gnssSvNotification +)> gnssSvCallback; + +/* Gives GNSS NMEA data, optional can be NULL + gnssNmeaCallback is called only during a tracking session + broadcasted to all clients, no matter if a session has started by client */ +typedef std::function<void( + GnssNmeaNotification gnssNmeaNotification +)> gnssNmeaCallback; + +/* Gives GNSS Measurements information, optional can be NULL + gnssMeasurementsCallback is called only during a tracking session + broadcasted to all clients, no matter if a session has started by client */ +typedef std::function<void( + GnssMeasurementsNotification gnssMeasurementsNotification +)> gnssMeasurementsCallback; + +typedef struct { + size_t size; // set to sizeof(LocationCallbacks) + capabilitiesCallback capabilitiesCb; // mandatory + responseCallback responseCb; // mandatory + collectiveResponseCallback collectiveResponseCb; // mandatory + trackingCallback trackingCb; // optional + batchingCallback batchingCb; // optional + geofenceBreachCallback geofenceBreachCb; // optional + geofenceStatusCallback geofenceStatusCb; // optional + gnssLocationInfoCallback gnssLocationInfoCb; // optional + gnssNiCallback gnssNiCb; // optional + gnssSvCallback gnssSvCb; // optional + gnssNmeaCallback gnssNmeaCb; // optional + gnssMeasurementsCallback gnssMeasurementsCb; // optional +} LocationCallbacks; + +class LocationAPI +{ +private: + LocationAPI(); + ~LocationAPI(); + +public: + /* creates an instance to LocationAPI object. + Will return NULL if mandatory parameters are invalid or if the maximum number + of instances have been reached */ + static LocationAPI* createInstance(LocationCallbacks&); + + /* destroy/cleans up the instance, which should be called when LocationAPI object is + no longer needed. LocationAPI* returned from createInstance will no longer valid + after destroy is called */ + void destroy(); + + /* updates/changes the callbacks that will be called. + mandatory callbacks must be present for callbacks to be successfully updated + no return value */ + void updateCallbacks(LocationCallbacks&); + + /* ================================== TRACKING ================================== */ + + /* startTracking starts a tracking session, which returns a session id that will be + used by the other tracking APIs and also in the responseCallback to match command + with response. locations are reported on the trackingCallback passed in createInstance + periodically according to LocationOptions. + responseCallback returns: + LOCATION_ERROR_SUCCESS if session was successfully started + LOCATION_ERROR_ALREADY_STARTED if a startTracking session is already in progress + LOCATION_ERROR_CALLBACK_MISSING if no trackingCallback was passed in createInstance + LOCATION_ERROR_INVALID_PARAMETER if LocationOptions parameter is invalid */ + uint32_t startTracking(LocationOptions&); // returns session id + + /* stopTracking stops a tracking session associated with id parameter. + responseCallback returns: + LOCATION_ERROR_SUCCESS if successful + LOCATION_ERROR_ID_UNKNOWN if id is not associated with a tracking session */ + void stopTracking(uint32_t id); + + /* updateTrackingOptions changes the LocationOptions of a tracking session associated with id + responseCallback returns: + LOCATION_ERROR_SUCCESS if successful + LOCATION_ERROR_INVALID_PARAMETER if LocationOptions parameters are invalid + LOCATION_ERROR_ID_UNKNOWN if id is not associated with a tracking session */ + void updateTrackingOptions(uint32_t id, LocationOptions&); + + /* ================================== BATCHING ================================== */ + + /* startBatching starts a batching session, which returns a session id that will be + used by the other batching APIs and also in the responseCallback to match command + with response. locations are reported on the batchingCallback passed in createInstance + periodically according to LocationOptions. A batching session starts tracking on + the low power processor and delivers them in batches by the batchingCallback when + the batch is full or when getBatchedLocations is called. This allows for the processor + that calls this API to sleep when the low power processor can batch locations in the + backgroup and wake up the processor calling the API only when the batch is full, thus + saving power + responseCallback returns: + LOCATION_ERROR_SUCCESS if session was successful + LOCATION_ERROR_ALREADY_STARTED if a startBatching session is already in progress + LOCATION_ERROR_CALLBACK_MISSING if no batchingCallback was passed in createInstance + LOCATION_ERROR_INVALID_PARAMETER if a parameter is invalid + LOCATION_ERROR_NOT_SUPPORTED if batching is not supported */ + uint32_t startBatching(LocationOptions&); // returns session id + + /* stopBatching stops a batching session associated with id parameter. + responseCallback returns: + LOCATION_ERROR_SUCCESS if successful + LOCATION_ERROR_ID_UNKNOWN if id is not associated with batching session */ + void stopBatching(uint32_t id); + + /* updateBatchingOptions changes the LocationOptions of a batching session associated with id + responseCallback returns: + LOCATION_ERROR_SUCCESS if successful + LOCATION_ERROR_INVALID_PARAMETER if LocationOptions parameters are invalid + LOCATION_ERROR_ID_UNKNOWN if id is not associated with a batching session */ + void updateBatchingOptions(uint32_t id, LocationOptions&); + + /* getBatchedLocations gets a number of locations that are currently stored/batched + on the low power processor, delivered by the batchingCallback passed in createInstance. + Location are then deleted from the batch stored on the low power processor. + responseCallback returns: + LOCATION_ERROR_SUCCESS if successful, will be followed by batchingCallback call + LOCATION_ERROR_CALLBACK_MISSING if no batchingCallback was passed in createInstance + LOCATION_ERROR_ID_UNKNOWN if id is not associated with a batching session */ + void getBatchedLocations(uint32_t id, size_t count); + + /* ================================== GEOFENCE ================================== */ + + /* addGeofences adds any number of geofences and returns an array of geofence ids that + will be used by the other geofence APIs and also in the collectiveResponseCallback to + match command with response. The geofenceBreachCallback will deliver the status of each + geofence according to the GeofenceOption for each. The geofence id array returned will + be valid until the collectiveResponseCallback is called and has returned. + collectiveResponseCallback returns: + LOCATION_ERROR_SUCCESS if session was successful + LOCATION_ERROR_CALLBACK_MISSING if no geofenceBreachCallback + LOCATION_ERROR_INVALID_PARAMETER if any parameters are invalid + LOCATION_ERROR_NOT_SUPPORTED if geofence is not supported */ + uint32_t* addGeofences(size_t count, GeofenceOption*, GeofenceInfo*); // returns id array + + /* removeGeofences removes any number of geofences. Caller should delete ids array after + removeGeofences returneds. + collectiveResponseCallback returns: + LOCATION_ERROR_SUCCESS if successful + LOCATION_ERROR_ID_UNKNOWN if id is not associated with a geofence session */ + void removeGeofences(size_t count, uint32_t* ids); + + /* modifyGeofences modifies any number of geofences. Caller should delete ids array after + modifyGeofences returns. + collectiveResponseCallback returns: + LOCATION_ERROR_SUCCESS if successful + LOCATION_ERROR_ID_UNKNOWN if id is not associated with a geofence session + LOCATION_ERROR_INVALID_PARAMETER if any parameters are invalid */ + void modifyGeofences(size_t count, uint32_t* ids, GeofenceOption* options); + + /* pauseGeofences pauses any number of geofences, which is similar to removeGeofences, + only that they can be resumed at any time. Caller should delete ids array after + pauseGeofences returns. + collectiveResponseCallback returns: + LOCATION_ERROR_SUCCESS if successful + LOCATION_ERROR_ID_UNKNOWN if id is not associated with a geofence session */ + void pauseGeofences(size_t count, uint32_t* ids); + + /* resumeGeofences resumes any number of geofences that are currently paused. Caller should + delete ids array after resumeGeofences returns. + collectiveResponseCallback returns: + LOCATION_ERROR_SUCCESS if successful + LOCATION_ERROR_ID_UNKNOWN if id is not associated with a geofence session */ + void resumeGeofences(size_t count, uint32_t* ids); + + /* ================================== GNSS ====================================== */ + + /* gnssNiResponse is called in response to a gnssNiCallback. + responseCallback returns: + LOCATION_ERROR_SUCCESS if session was successful + LOCATION_ERROR_INVALID_PARAMETER if any parameters in GnssNiResponse are invalid + LOCATION_ERROR_ID_UNKNOWN if id does not match a gnssNiCallback */ + void gnssNiResponse(uint32_t id, GnssNiResponse response); +}; + +typedef struct { + size_t size; // set to sizeof(LocationControlCallbacks) + responseCallback responseCb; // mandatory + collectiveResponseCallback collectiveResponseCb; // mandatory +} LocationControlCallbacks; + +class LocationControlAPI +{ +private: + LocationControlAPI(); + ~LocationControlAPI(); + +public: + /* creates an instance to LocationControlAPI object. + Will return NULL if mandatory parameters are invalid or if the maximum number + of instances have been reached. Only once instance allowed */ + static LocationControlAPI* createInstance(LocationControlCallbacks&); + + /* destroy/cleans up the instance, which should be called when LocationControlAPI object is + no longer needed. LocationControlAPI* returned from createInstance will no longer valid + after destroy is called */ + void destroy(); + + /* enable will enable specific location technology to be used for calculation locations and + will effectively start a control session if call is successful, which returns a session id + that will be returned in responseCallback to match command with response. The session id is + also needed to call the disable command. + This effect is global for all clients of LocationAPI + responseCallback returns: + LOCATION_ERROR_SUCCESS if successful + LOCATION_ERROR_ALREADY_STARTED if an enable was already called for this techType + LOCATION_ERROR_INVALID_PARAMETER if any parameters are invalid + LOCATION_ERROR_GENERAL_FAILURE if failure for any other reason */ + uint32_t enable(LocationTechnologyType techType); + + /* disable will disable specific location technology to be used for calculation locations and + effectively ends the control session if call is successful. + id parameter is the session id that was returned in enable responseCallback for techType. + The session id is no longer valid after disable's responseCallback returns success. + This effect is global for all clients of LocationAPI + responseCallback returns: + LOCATION_ERROR_SUCCESS if successful + LOCATION_ERROR_ID_UNKNOWN if id was not returned from responseCallback from enable + LOCATION_ERROR_GENERAL_FAILURE if failure for any other reason */ + void disable(uint32_t id); + + /* gnssUpdateConfig updates the gnss specific configuration, which returns a session id array + with an id for each of the bits set in GnssConfig.flags, order from low bits to high bits. + The response for each config that is set will be returned in collectiveResponseCallback. + The session id array returned will be valid until the collectiveResponseCallback is called + and has returned. This effect is global for all clients of LocationAPI + collectiveResponseCallback returns: + LOCATION_ERROR_SUCCESS if session was successful + LOCATION_ERROR_INVALID_PARAMETER if any other parameters are invalid + LOCATION_ERROR_GENERAL_FAILURE if failure for any other reason */ + uint32_t* gnssUpdateConfig(GnssConfig config); + + /* delete specific gnss aiding data for testing, which returns a session id + that will be returned in responseCallback to match command with response. + Only allowed in userdebug builds. This effect is global for all clients of LocationAPI + responseCallback returns: + LOCATION_ERROR_SUCCESS if successful + LOCATION_ERROR_INVALID_PARAMETER if any parameters are invalid + LOCATION_ERROR_NOT_SUPPORTED if build is not userdebug */ + uint32_t gnssDeleteAidingData(GnssAidingData& data); +}; + +#endif /* LOCATION_H */ diff --git a/location/LocationAPIClientBase.cpp b/location/LocationAPIClientBase.cpp new file mode 100644 index 0000000..3413d3e --- /dev/null +++ b/location/LocationAPIClientBase.cpp @@ -0,0 +1,769 @@ +/* Copyright (c) 2017 The Linux Foundation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * * Neither the name of The Linux Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#define LOG_NDDEBUG 0 +#define LOG_TAG "LocSvc_APIClientBase" + +#include <log_util.h> +#include <loc_cfg.h> +#include "LocationAPIClientBase.h" + +#define FLP_CONF_FILE "/etc/flp.conf" + +LocationAPIClientBase::LocationAPIClientBase() : + mTrackingCallback(nullptr), + mBatchingCallback(nullptr), + mGeofenceBreachCallback(nullptr), + mLocationAPI(nullptr), + mLocationControlAPI(nullptr), + mBatchSize(-1) +{ + + // use recursive mutex, in case callback come from the same thread + pthread_mutexattr_t attr; + pthread_mutexattr_init(&attr); + pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); + pthread_mutex_init(&mMutex, &attr); + + for (int i = 0; i < REQUEST_MAX; i++) { + mRequestQueues[i] = nullptr; + } + + memset(&mConfig, 0, sizeof(GnssConfig)); +} + +void LocationAPIClientBase::locAPISetCallbacks(LocationCallbacks& locationCallbacks) +{ + if (locationCallbacks.geofenceBreachCb != nullptr) { + mGeofenceBreachCallback = locationCallbacks.geofenceBreachCb; + locationCallbacks.geofenceBreachCb = + [this](GeofenceBreachNotification geofenceBreachNotification) { + beforeGeofenceBreachCb(geofenceBreachNotification); + }; + } + + locationCallbacks.capabilitiesCb = + [this](LocationCapabilitiesMask capabilitiesMask) { + onCapabilitiesCb(capabilitiesMask); + }; + locationCallbacks.responseCb = [this](LocationError error, uint32_t id) { + onResponseCb(error, id); + }; + locationCallbacks.collectiveResponseCb = + [this](size_t count, LocationError* errors, uint32_t* ids) { + onCollectiveResponseCb(count, errors, ids); + }; + + if (mLocationAPI == nullptr ) { + mLocationAPI = LocationAPI::createInstance(locationCallbacks); + } else { + mLocationAPI->updateCallbacks(locationCallbacks); + } + + if (mLocationControlAPI == nullptr) { + LocationControlCallbacks locationControlCallbacks; + locationControlCallbacks.size = sizeof(LocationControlCallbacks); + + locationControlCallbacks.responseCb = + [this](LocationError error, uint32_t id) { + onCtrlResponseCb(error, id); + }; + locationControlCallbacks.collectiveResponseCb = + [this](size_t count, LocationError* errors, uint32_t* ids) { + onCtrlCollectiveResponseCb(count, errors, ids); + }; + + mLocationControlAPI = LocationControlAPI::createInstance(locationControlCallbacks); + } +} + +LocationAPIClientBase::~LocationAPIClientBase() +{ + if (mLocationAPI) { + mLocationAPI->destroy(); + mLocationAPI = nullptr; + } + if (mLocationControlAPI) { + mLocationControlAPI->destroy(); + mLocationControlAPI = nullptr; + } + + pthread_mutex_lock(&mMutex); + for (int i = 0; i < REQUEST_MAX; i++) { + if (mRequestQueues[i]) { + delete mRequestQueues[i]; + mRequestQueues[i] = nullptr; + } + } + pthread_mutex_unlock(&mMutex); + + pthread_mutex_destroy(&mMutex); +} + +uint32_t LocationAPIClientBase::locAPIStartTracking(LocationOptions& options) +{ + uint32_t retVal = LOCATION_ERROR_GENERAL_FAILURE; + if (mLocationAPI) { + pthread_mutex_lock(&mMutex); + RequestQueue* requests = mRequestQueues[REQUEST_TRACKING]; + if (requests) { + delete requests; + } + uint32_t session = mLocationAPI->startTracking(options); + LOC_LOGI("%s:%d] start new session: %d", __FUNCTION__, __LINE__, session); + // onResponseCb might be called from other thread immediately after + // startTracking returns, so we are not going to unlock mutex + // until StartTrackingRequest is pushed into mRequestQueues[REQUEST_TRACKING] + requests = new RequestQueue(session); + requests->push(new StartTrackingRequest(*this)); + mRequestQueues[REQUEST_TRACKING] = requests; + pthread_mutex_unlock(&mMutex); + + retVal = LOCATION_ERROR_SUCCESS; + } + + return retVal; +} + +void LocationAPIClientBase::locAPIStopTracking() +{ + if (mLocationAPI) { + pthread_mutex_lock(&mMutex); + uint32_t session = -1; + RequestQueue* requests = mRequestQueues[REQUEST_TRACKING]; + if (requests) { + session = requests->getSession(); + requests->push(new StopTrackingRequest(*this)); + mLocationAPI->stopTracking(session); + } + pthread_mutex_unlock(&mMutex); + } +} + +void LocationAPIClientBase::locAPIUpdateTrackingOptions(LocationOptions& options) +{ + if (mLocationAPI) { + pthread_mutex_lock(&mMutex); + uint32_t session = -1; + RequestQueue* requests = mRequestQueues[REQUEST_TRACKING]; + if (requests) { + session = requests->getSession(); + requests->push(new UpdateTrackingOptionsRequest(*this)); + mLocationAPI->updateTrackingOptions(session, options); + } + pthread_mutex_unlock(&mMutex); + } +} + +int32_t LocationAPIClientBase::locAPIGetBatchSize() +{ + if (mBatchSize == -1) { + const loc_param_s_type flp_conf_param_table[] = + { + {"BATCH_SIZE", &mBatchSize, nullptr, 'n'}, + }; + UTIL_READ_CONF(FLP_CONF_FILE, flp_conf_param_table); + if (mBatchSize < 0) { + // set mBatchSize to 0 if we got an illegal value from config file + mBatchSize = 0; + } + } + return mBatchSize; +} + + +uint32_t LocationAPIClientBase::locAPIStartSession(uint32_t id, uint32_t sessionMode, + LocationOptions& options) +{ + uint32_t retVal = LOCATION_ERROR_GENERAL_FAILURE; + if (mLocationAPI) { + pthread_mutex_lock(&mMutex); + + if (mSessionMap.find(id) != mSessionMap.end()) { + LOC_LOGE("%s:%d] session %d has already started.", __FUNCTION__, __LINE__, id); + retVal = LOCATION_ERROR_ALREADY_STARTED; + } else { + uint32_t trackingSession = 0; + uint32_t batchingSession = 0; + + if (sessionMode == SESSION_MODE_ON_FIX) { + RequestQueue* requests = mRequestQueues[REQUEST_TRACKING]; + if (requests) { + delete requests; + } + trackingSession = mLocationAPI->startTracking(options); + LOC_LOGI("%s:%d] start new session: %d", __FUNCTION__, __LINE__, trackingSession); + requests = new RequestQueue(trackingSession); + requests->push(new StartTrackingRequest(*this)); + mRequestQueues[REQUEST_TRACKING] = requests; + } else if (sessionMode == SESSION_MODE_ON_FULL) { + RequestQueue* requests = mRequestQueues[REQUEST_BATCHING]; + if (requests) { + delete requests; + } + batchingSession = mLocationAPI->startBatching(options); + LOC_LOGI("%s:%d] start new session: %d", __FUNCTION__, __LINE__, batchingSession); + requests = new RequestQueue(batchingSession); + requests->push(new StartBatchingRequest(*this)); + mRequestQueues[REQUEST_BATCHING] = requests; + } + + SessionEntity entity; + entity.id = id; + entity.trackingSession = trackingSession; + entity.batchingSession = batchingSession; + entity.sessionMode = sessionMode; + mSessionMap[id] = entity; + + retVal = LOCATION_ERROR_SUCCESS; + } + + pthread_mutex_unlock(&mMutex); + } + + return retVal; +} + +uint32_t LocationAPIClientBase::locAPIStopSession(uint32_t id) +{ + uint32_t retVal = LOCATION_ERROR_GENERAL_FAILURE; + if (mLocationAPI) { + pthread_mutex_lock(&mMutex); + + if (mSessionMap.find(id) != mSessionMap.end()) { + SessionEntity entity = mSessionMap[id]; + + uint32_t trackingSession = entity.trackingSession; + uint32_t batchingSession = entity.batchingSession; + uint32_t sMode = entity.sessionMode; + + mSessionMap.erase(id); + + if (sMode == SESSION_MODE_ON_FIX) { + RequestQueue* requests = mRequestQueues[REQUEST_TRACKING]; + if (requests) { + requests->push(new StopTrackingRequest(*this)); + mLocationAPI->stopTracking(trackingSession); + } + } else if (sMode == SESSION_MODE_ON_FULL) { + RequestQueue* requests = mRequestQueues[REQUEST_BATCHING]; + if (requests) { + requests->push(new StopBatchingRequest(*this)); + mLocationAPI->stopBatching(batchingSession); + } + } + + retVal = LOCATION_ERROR_SUCCESS; + } else { + retVal = LOCATION_ERROR_ID_UNKNOWN; + LOC_LOGE("%s:%d] session %d is not exist.", __FUNCTION__, __LINE__, id); + } + + pthread_mutex_unlock(&mMutex); + } + return retVal; +} + +uint32_t LocationAPIClientBase::locAPIUpdateSessionOptions(uint32_t id, uint32_t sessionMode, + LocationOptions& options) +{ + uint32_t retVal = LOCATION_ERROR_GENERAL_FAILURE; + if (mLocationAPI) { + pthread_mutex_lock(&mMutex); + + if (mSessionMap.find(id) != mSessionMap.end()) { + SessionEntity& entity = mSessionMap[id]; + + uint32_t trackingSession = entity.trackingSession; + uint32_t batchingSession = entity.batchingSession; + uint32_t sMode = entity.sessionMode; + + if (sessionMode == SESSION_MODE_ON_FIX) { + if (sMode == SESSION_MODE_ON_FIX) { + RequestQueue* requests = mRequestQueues[REQUEST_TRACKING]; + if (requests) { + requests->push(new UpdateTrackingOptionsRequest(*this)); + mLocationAPI->updateTrackingOptions(trackingSession, options); + } + } else if (sMode == SESSION_MODE_ON_FULL) { + // stop batching + { + RequestQueue* requests = mRequestQueues[REQUEST_BATCHING]; + if (requests) { + requests->push(new StopBatchingRequest(*this)); + mLocationAPI->stopBatching(batchingSession); + batchingSession = 0; + } + } + // start tracking + { + RequestQueue* requests = mRequestQueues[REQUEST_TRACKING]; + if (requests) { + delete requests; + } + trackingSession = mLocationAPI->startTracking(options); + LOC_LOGI("%s:%d] start new session: %d", + __FUNCTION__, __LINE__, trackingSession); + requests = new RequestQueue(trackingSession); + requests->push(new StartTrackingRequest(*this)); + mRequestQueues[REQUEST_TRACKING] = requests; + } + } + } else if (sessionMode == SESSION_MODE_ON_FULL) { + if (sMode == SESSION_MODE_ON_FIX) { + // stop tracking + { + RequestQueue* requests = mRequestQueues[REQUEST_TRACKING]; + if (requests) { + requests->push(new StopTrackingRequest(*this)); + mLocationAPI->stopTracking(trackingSession); + trackingSession = 0; + } + } + // start batching + { + RequestQueue* requests = mRequestQueues[REQUEST_BATCHING]; + if (requests) { + delete requests; + } + batchingSession = mLocationAPI->startBatching(options); + LOC_LOGI("%s:%d] start new session: %d", + __FUNCTION__, __LINE__, batchingSession); + requests = new RequestQueue(batchingSession); + requests->push(new StartBatchingRequest(*this)); + mRequestQueues[REQUEST_BATCHING] = requests; + } + } else if (sMode == SESSION_MODE_ON_FULL) { + RequestQueue* requests = mRequestQueues[REQUEST_BATCHING]; + requests = mRequestQueues[REQUEST_BATCHING]; + if (requests) { + requests->push(new UpdateBatchingOptionsRequest(*this)); + mLocationAPI->updateBatchingOptions(batchingSession, options); + } + } + } + + entity.trackingSession = trackingSession; + entity.batchingSession = batchingSession; + entity.sessionMode = sessionMode; + + retVal = LOCATION_ERROR_SUCCESS; + } else { + retVal = LOCATION_ERROR_ID_UNKNOWN; + LOC_LOGE("%s:%d] session %d is not exist.", __FUNCTION__, __LINE__, id); + } + + pthread_mutex_unlock(&mMutex); + } + return retVal; +} + +void LocationAPIClientBase::locAPIGetBatchedLocations(size_t count) +{ + if (mLocationAPI) { + pthread_mutex_lock(&mMutex); + uint32_t session = -1; + RequestQueue* requests = mRequestQueues[REQUEST_BATCHING]; + if (requests) { + session = requests->getSession(); + requests->push(new GetBatchedLocationsRequest(*this)); + mLocationAPI->getBatchedLocations(session, count); + } + pthread_mutex_unlock(&mMutex); + } +} + +uint32_t LocationAPIClientBase::locAPIAddGeofences( + size_t count, uint32_t* ids, GeofenceOption* options, GeofenceInfo* data) +{ + uint32_t retVal = LOCATION_ERROR_GENERAL_FAILURE; + if (mLocationAPI) { + pthread_mutex_lock(&mMutex); + RequestQueue* requests = mRequestQueues[REQUEST_GEOFENCE]; + if (requests) { + delete requests; + } + uint32_t* sessions = mLocationAPI->addGeofences(count, options, data); + LOC_LOGI("%s:%d] start new sessions: %p", __FUNCTION__, __LINE__, sessions); + requests = new RequestQueue(-1); + requests->push(new AddGeofencesRequest(*this)); + mRequestQueues[REQUEST_GEOFENCE] = requests; + + for (size_t i = 0; i < count; i++) { + mGeofenceBiDict.set(ids[i], sessions[i], options[i].breachTypeMask); + } + pthread_mutex_unlock(&mMutex); + + retVal = LOCATION_ERROR_SUCCESS; + } + + return retVal; +} + +void LocationAPIClientBase::locAPIRemoveGeofences(size_t count, uint32_t* ids) +{ + if (mLocationAPI) { + uint32_t* sessions = (uint32_t*)malloc(sizeof(uint32_t) * count); + + pthread_mutex_lock(&mMutex); + RequestQueue* requests = mRequestQueues[REQUEST_GEOFENCE]; + if (requests) { + for (size_t i = 0; i < count; i++) { + sessions[i] = mGeofenceBiDict.getSession(ids[i]); + } + requests->push(new RemoveGeofencesRequest(*this)); + mLocationAPI->removeGeofences(count, sessions); + } + pthread_mutex_unlock(&mMutex); + + free(sessions); + } +} + +void LocationAPIClientBase::locAPIModifyGeofences( + size_t count, uint32_t* ids, GeofenceOption* options) +{ + if (mLocationAPI) { + uint32_t* sessions = (uint32_t*)malloc(sizeof(uint32_t) * count); + + pthread_mutex_lock(&mMutex); + RequestQueue* requests = mRequestQueues[REQUEST_GEOFENCE]; + if (requests) { + for (size_t i = 0; i < count; i++) { + sessions[i] = mGeofenceBiDict.getSession(ids[i]); + mGeofenceBiDict.set(ids[i], sessions[i], options[i].breachTypeMask); + } + requests->push(new ModifyGeofencesRequest(*this)); + mLocationAPI->modifyGeofences(count, sessions, options); + } + pthread_mutex_unlock(&mMutex); + + free(sessions); + } +} + +void LocationAPIClientBase::locAPIPauseGeofences(size_t count, uint32_t* ids) +{ + if (mLocationAPI) { + uint32_t* sessions = (uint32_t*)malloc(sizeof(uint32_t) * count); + + pthread_mutex_lock(&mMutex); + RequestQueue* requests = mRequestQueues[REQUEST_GEOFENCE]; + if (requests) { + for (size_t i = 0; i < count; i++) { + sessions[i] = mGeofenceBiDict.getSession(ids[i]); + } + requests->push(new PauseGeofencesRequest(*this)); + mLocationAPI->pauseGeofences(count, sessions); + } + pthread_mutex_unlock(&mMutex); + + free(sessions); + } +} + +void LocationAPIClientBase::locAPIResumeGeofences( + size_t count, uint32_t* ids, GeofenceBreachTypeMask* mask) +{ + if (mLocationAPI) { + uint32_t* sessions = (uint32_t*)malloc(sizeof(uint32_t) * count); + + pthread_mutex_lock(&mMutex); + RequestQueue* requests = mRequestQueues[REQUEST_GEOFENCE]; + if (requests) { + for (size_t i = 0; i < count; i++) { + sessions[i] = mGeofenceBiDict.getSession(ids[i]); + if (mask) { + mGeofenceBiDict.set(ids[i], sessions[i], mask[i]); + } + } + requests->push(new ResumeGeofencesRequest(*this)); + mLocationAPI->resumeGeofences(count, sessions); + } + pthread_mutex_unlock(&mMutex); + + free(sessions); + } +} + +void LocationAPIClientBase::locAPIRemoveAllGeofences() +{ + if (mLocationAPI) { + std::vector<uint32_t> sessionsVec = mGeofenceBiDict.getAllSessions(); + size_t count = sessionsVec.size(); + uint32_t* sessions = (uint32_t*)malloc(sizeof(uint32_t) * count); + + pthread_mutex_lock(&mMutex); + RequestQueue* requests = mRequestQueues[REQUEST_GEOFENCE]; + if (requests) { + for (size_t i = 0; i < count; i++) { + sessions[i] = sessionsVec[i]; + } + requests->push(new RemoveGeofencesRequest(*this)); + mLocationAPI->removeGeofences(count, sessions); + } + pthread_mutex_unlock(&mMutex); + + free(sessions); + } +} + +void LocationAPIClientBase::locAPIGnssNiResponse(uint32_t id, GnssNiResponse response) +{ + uint32_t session = 0; + if (mLocationAPI) { + pthread_mutex_lock(&mMutex); + RequestQueue* requests = mRequestQueues[REQUEST_NIRESPONSE]; + if (requests) { + delete requests; + } + uint32_t session = id; + mLocationAPI->gnssNiResponse(id, response); + LOC_LOGI("%s:%d] start new session: %d", __FUNCTION__, __LINE__, session); + requests = new RequestQueue(session); + requests->push(new GnssNiResponseRequest(*this)); + mRequestQueues[REQUEST_NIRESPONSE] = requests; + pthread_mutex_unlock(&mMutex); + } +} + +uint32_t LocationAPIClientBase::locAPIGnssDeleteAidingData(GnssAidingData& data) +{ + uint32_t retVal = LOCATION_ERROR_GENERAL_FAILURE; + if (mLocationControlAPI) { + pthread_mutex_lock(&mMutex); + RequestQueue* requests = mRequestQueues[REQUEST_DELETEAIDINGDATA]; + if (requests) { + delete requests; + } + uint32_t session = mLocationControlAPI->gnssDeleteAidingData(data); + LOC_LOGI("%s:%d] start new session: %d", __FUNCTION__, __LINE__, session); + requests = new RequestQueue(session); + requests->push(new GnssDeleteAidingDataRequest(*this)); + mRequestQueues[REQUEST_DELETEAIDINGDATA] = requests; + pthread_mutex_unlock(&mMutex); + + retVal = LOCATION_ERROR_SUCCESS; + } + + return retVal; +} + +uint32_t LocationAPIClientBase::locAPIEnable(LocationTechnologyType techType) +{ + uint32_t retVal = LOCATION_ERROR_GENERAL_FAILURE; + if (mLocationControlAPI) { + pthread_mutex_lock(&mMutex); + RequestQueue* requests = mRequestQueues[REQUEST_CONTROL]; + if (requests) { + delete requests; + } + uint32_t session = mLocationControlAPI->enable(techType); + LOC_LOGI("%s:%d] start new session: %d", __FUNCTION__, __LINE__, session); + requests = new RequestQueue(session); + requests->push(new EnableRequest(*this)); + mRequestQueues[REQUEST_CONTROL] = requests; + pthread_mutex_unlock(&mMutex); + + retVal = LOCATION_ERROR_SUCCESS; + } + + return retVal; +} + +void LocationAPIClientBase::locAPIDisable() +{ + if (mLocationControlAPI) { + pthread_mutex_lock(&mMutex); + uint32_t session = -1; + RequestQueue* requests = mRequestQueues[REQUEST_CONTROL]; + if (requests) { + session = requests->getSession(); + requests->push(new DisableRequest(*this)); + mLocationControlAPI->disable(session); + } + pthread_mutex_unlock(&mMutex); + } +} + +uint32_t LocationAPIClientBase::locAPIGnssUpdateConfig(GnssConfig config) +{ + uint32_t retVal = LOCATION_ERROR_GENERAL_FAILURE; + if (memcmp(&mConfig, &config, sizeof(GnssConfig)) == 0) { + LOC_LOGE("%s:%d] GnssConfig is identical to previous call", __FUNCTION__, __LINE__); + return retVal; + } + + if (mLocationControlAPI) { + pthread_mutex_lock(&mMutex); + + memcpy(&mConfig, &config, sizeof(GnssConfig)); + + uint32_t session = -1; + RequestQueue* requests = mRequestQueues[REQUEST_CONTROL]; + if (requests) { + session = requests->getSession(); + requests->push(new GnssUpdateConfigRequest(*this)); + uint32_t* idArray = mLocationControlAPI->gnssUpdateConfig(config); + LOC_LOGV("%s:%d] gnssUpdateConfig return array: %p", __FUNCTION__, __LINE__, idArray); + } + pthread_mutex_unlock(&mMutex); + + retVal = LOCATION_ERROR_SUCCESS; + } + return retVal; +} + +void LocationAPIClientBase::beforeGeofenceBreachCb( + GeofenceBreachNotification geofenceBreachNotification) +{ + if (mGeofenceBreachCallback == nullptr) + return; + uint32_t* ids = (uint32_t*)malloc(sizeof(uint32_t) * geofenceBreachNotification.count); + uint32_t* backup = geofenceBreachNotification.ids; + size_t n = geofenceBreachNotification.count; + + size_t count = 0; + for (size_t i = 0; i < n; i++) { + uint32_t id = mGeofenceBiDict.getId(geofenceBreachNotification.ids[i]); + GeofenceBreachTypeMask type = mGeofenceBiDict.getType(geofenceBreachNotification.ids[i]); + if ((geofenceBreachNotification.type == GEOFENCE_BREACH_ENTER && + (type & GEOFENCE_BREACH_ENTER_BIT)) || + (geofenceBreachNotification.type == GEOFENCE_BREACH_EXIT && + (type & GEOFENCE_BREACH_EXIT_BIT)) + ) { + ids[count] = id; + count++; + } + } + geofenceBreachNotification.count = count; + geofenceBreachNotification.ids = ids; + mGeofenceBreachCallback(geofenceBreachNotification); + + // restore ids + geofenceBreachNotification.ids = backup; + geofenceBreachNotification.count = n; + free(ids); +} + +void LocationAPIClientBase::onResponseCb(LocationError error, uint32_t id) +{ + if (error != LOCATION_ERROR_SUCCESS) { + LOC_LOGE("%s:%d] ERROR: %d ID: %d", __FUNCTION__, __LINE__, error, id); + } else { + LOC_LOGV("%s:%d] error: %d id: %d", __FUNCTION__, __LINE__, error, id); + } + LocationAPIRequest* request = getRequestBySession(id); + if (request) { + request->onResponse(error); + delete request; + } +} + +void LocationAPIClientBase::onCollectiveResponseCb( + size_t count, LocationError* errors, uint32_t* ids) +{ + for (size_t i = 0; i < count; i++) { + if (errors[i] != LOCATION_ERROR_SUCCESS) { + LOC_LOGE("%s:%d] ERROR: %d ID: %d", __FUNCTION__, __LINE__, errors[i], ids[i]); + } else { + LOC_LOGV("%s:%d] error: %d id: %d", __FUNCTION__, __LINE__, errors[i], ids[i]); + } + } + LocationAPIRequest* request = nullptr; + if (count > 0 && ids) + request = getRequestBySession(ids[0]); + if (!request) + request = getGeofencesRequest(); + if (request) { + request->onCollectiveResponse(count, errors, ids); + delete request; + } +} + +void LocationAPIClientBase::onCtrlResponseCb(LocationError error, uint32_t id) +{ + if (error != LOCATION_ERROR_SUCCESS) { + LOC_LOGE("%s:%d] ERROR: %d ID: %d", __FUNCTION__, __LINE__, error, id); + } else { + LOC_LOGV("%s:%d] error: %d id: %d", __FUNCTION__, __LINE__, error, id); + } + LocationAPIRequest* request = getRequestBySession(id); + if (request) { + request->onResponse(error); + delete request; + } +} + +void LocationAPIClientBase::onCtrlCollectiveResponseCb( + size_t count, LocationError* errors, uint32_t* ids) +{ + for (size_t i = 0; i < count; i++) { + if (errors[i] != LOCATION_ERROR_SUCCESS) { + LOC_LOGE("%s:%d] ERROR: %d ID: %d", __FUNCTION__, __LINE__, errors[i], ids[i]); + } else { + LOC_LOGV("%s:%d] error: %d id: %d", __FUNCTION__, __LINE__, errors[i], ids[i]); + } + } + LocationAPIRequest* request = nullptr; + if (count > 0 && ids) + request = getRequestBySession(ids[0]); + if (request) { + request->onCollectiveResponse(count, errors, ids); + delete request; + } +} + +LocationAPIClientBase::LocationAPIRequest* +LocationAPIClientBase::getRequestBySession(uint32_t session) +{ + pthread_mutex_lock(&mMutex); + LocationAPIRequest* request = nullptr; + for (int i = 0; i < REQUEST_MAX; i++) { + if (i != REQUEST_GEOFENCE && + mRequestQueues[i] && + mRequestQueues[i]->getSession() == session) { + request = mRequestQueues[i]->pop(); + break; + } + } + pthread_mutex_unlock(&mMutex); + return request; +} + +LocationAPIClientBase::LocationAPIRequest* +LocationAPIClientBase::getGeofencesRequest() +{ + pthread_mutex_lock(&mMutex); + LocationAPIRequest* request = nullptr; + if (mRequestQueues[REQUEST_GEOFENCE]) { + request = mRequestQueues[REQUEST_GEOFENCE]->pop(); + } + pthread_mutex_unlock(&mMutex); + return request; +} diff --git a/location/LocationAPIClientBase.h b/location/LocationAPIClientBase.h new file mode 100644 index 0000000..8bbaa3d --- /dev/null +++ b/location/LocationAPIClientBase.h @@ -0,0 +1,457 @@ +/* Copyright (c) 2017 The Linux Foundation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * * Neither the name of The Linux Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef LOCATION_API_CLINET_BASE_H +#define LOCATION_API_CLINET_BASE_H + +#include <stdint.h> +#include <stdlib.h> +#include <pthread.h> +#include <queue> +#include <map> + +#include "LocationAPI.h" + +enum SESSION_MODE { + SESSION_MODE_NONE = 0, + SESSION_MODE_ON_FULL, + SESSION_MODE_ON_FIX, +}; + +enum REQUEST_TYPE { + REQUEST_TRACKING = 0, + REQUEST_BATCHING, + REQUEST_GEOFENCE, + REQUEST_NIRESPONSE, + REQUEST_DELETEAIDINGDATA, + REQUEST_CONTROL, + REQUEST_MAX, +}; + +class LocationAPIClientBase +{ +public: + LocationAPIClientBase(); + virtual ~LocationAPIClientBase(); + LocationAPIClientBase(const LocationAPIClientBase&) = delete; + LocationAPIClientBase& operator=(const LocationAPIClientBase&) = delete; + + void locAPISetCallbacks(LocationCallbacks& locationCallbacks); + + // LocationAPI + uint32_t locAPIStartTracking(LocationOptions& options); + void locAPIStopTracking(); + void locAPIUpdateTrackingOptions(LocationOptions& options); + + int32_t locAPIGetBatchSize(); + uint32_t locAPIStartSession(uint32_t id, uint32_t sessionMode, + LocationOptions& options); + uint32_t locAPIStopSession(uint32_t id); + uint32_t locAPIUpdateSessionOptions(uint32_t id, uint32_t sessionMode, + LocationOptions& options); + void locAPIGetBatchedLocations(size_t count); + + uint32_t locAPIAddGeofences(size_t count, uint32_t* ids, + GeofenceOption* options, GeofenceInfo* data); + void locAPIRemoveGeofences(size_t count, uint32_t* ids); + void locAPIModifyGeofences(size_t count, uint32_t* ids, GeofenceOption* options); + void locAPIPauseGeofences(size_t count, uint32_t* ids); + void locAPIResumeGeofences(size_t count, uint32_t* ids, GeofenceBreachTypeMask* mask); + void locAPIRemoveAllGeofences(); + + void locAPIGnssNiResponse(uint32_t id, GnssNiResponse response); + uint32_t locAPIGnssDeleteAidingData(GnssAidingData& data); + + uint32_t locAPIEnable(LocationTechnologyType techType); + void locAPIDisable(); + uint32_t locAPIGnssUpdateConfig(GnssConfig config); + + // callbacks + void onResponseCb(LocationError error, uint32_t id); + void onCollectiveResponseCb(size_t count, LocationError* errors, uint32_t* ids); + + void onCtrlResponseCb(LocationError error, uint32_t id); + void onCtrlCollectiveResponseCb(size_t count, LocationError* errors, uint32_t* ids); + + void beforeGeofenceBreachCb(GeofenceBreachNotification geofenceBreachNotification); + + inline virtual void onCapabilitiesCb(LocationCapabilitiesMask /*capabilitiesMask*/) {} + inline virtual void onGnssNmeaCb(GnssNmeaNotification /*gnssNmeaNotification*/) {} + inline virtual void onGnssMeasurementsCb( + GnssMeasurementsNotification /*gnssMeasurementsNotification*/) {} + + inline virtual void onTrackingCb(Location /*location*/) {} + inline virtual void onGnssSvCb(GnssSvNotification /*gnssSvNotification*/) {} + inline virtual void onStartTrackingCb(LocationError /*error*/) {} + inline virtual void onStopTrackingCb(LocationError /*error*/) {} + inline virtual void onUpdateTrackingOptionsCb(LocationError /*error*/) {} + + inline virtual void onGnssLocationInfoCb( + GnssLocationInfoNotification /*gnssLocationInfoNotification*/) {} + + inline virtual void onBatchingCb(size_t /*count*/, Location* /*location*/) {} + inline virtual void onStartBatchingCb(LocationError /*error*/) {} + inline virtual void onStopBatchingCb(LocationError /*error*/) {} + inline virtual void onUpdateBatchingOptionsCb(LocationError /*error*/) {} + inline virtual void onGetBatchedLocationsCb(LocationError /*error*/) {} + + inline virtual void onGeofenceBreachCb( + GeofenceBreachNotification /*geofenceBreachNotification*/) {} + inline virtual void onGeofenceStatusCb( + GeofenceStatusNotification /*geofenceStatusNotification*/) {} + inline virtual void onAddGeofencesCb( + size_t /*count*/, LocationError* /*errors*/, uint32_t* /*ids*/) {} + inline virtual void onRemoveGeofencesCb( + size_t /*count*/, LocationError* /*errors*/, uint32_t* /*ids*/) {} + inline virtual void onModifyGeofencesCb( + size_t /*count*/, LocationError* /*errors*/, uint32_t* /*ids*/) {} + inline virtual void onPauseGeofencesCb( + size_t /*count*/, LocationError* /*errors*/, uint32_t* /*ids*/) {} + inline virtual void onResumeGeofencesCb( + size_t /*count*/, LocationError* /*errors*/, uint32_t* /*ids*/) {} + + inline virtual void onGnssNiCb(uint32_t /*id*/, GnssNiNotification /*gnssNiNotification*/) {} + inline virtual void onGnssNiResponseCb(LocationError /*error*/) {} + inline virtual void onGnssDeleteAidingDataCb(LocationError /*error*/) {} + + inline virtual void onEnableCb(LocationError /*error*/) {} + inline virtual void onDisableCb(LocationError /*error*/) {} + inline virtual void onGnssUpdateConfigCb( + size_t /*count*/, LocationError* /*errors*/, uint32_t* /*ids*/) {} + +private: + // private inner classes + typedef struct { + uint32_t id; + uint32_t trackingSession; + uint32_t batchingSession; + uint32_t sessionMode; + } SessionEntity; + + class BiDict { + public: + BiDict() { + pthread_mutex_init(&mBiDictMutex, nullptr); + } + ~BiDict() { + pthread_mutex_destroy(&mBiDictMutex); + } + bool hasId(uint32_t id) { + pthread_mutex_lock(&mBiDictMutex); + bool ret = (mForwardMap.find(id) != mForwardMap.end()); + pthread_mutex_unlock(&mBiDictMutex); + return ret; + } + void set(uint32_t id, uint32_t session, uint32_t type) { + pthread_mutex_lock(&mBiDictMutex); + mForwardMap[id] = session; + mBackwardMap[session] = id; + mTypeMap[session] = type; + pthread_mutex_unlock(&mBiDictMutex); + } + void clear() { + pthread_mutex_lock(&mBiDictMutex); + mForwardMap.clear(); + mBackwardMap.clear(); + mTypeMap.clear(); + pthread_mutex_unlock(&mBiDictMutex); + } + void rmById(uint32_t id) { + pthread_mutex_lock(&mBiDictMutex); + mBackwardMap.erase(mForwardMap[id]); + mTypeMap.erase(mForwardMap[id]); + mForwardMap.erase(id); + pthread_mutex_unlock(&mBiDictMutex); + } + void rmBySession(uint32_t session) { + pthread_mutex_lock(&mBiDictMutex); + mForwardMap.erase(mBackwardMap[session]); + mBackwardMap.erase(session); + mTypeMap.erase(session); + pthread_mutex_unlock(&mBiDictMutex); + } + uint32_t getId(uint32_t session) { + pthread_mutex_lock(&mBiDictMutex); + uint32_t ret = mBackwardMap[session]; + pthread_mutex_unlock(&mBiDictMutex); + return ret; + } + uint32_t getSession(uint32_t id) { + pthread_mutex_lock(&mBiDictMutex); + uint32_t ret = mForwardMap[id]; + pthread_mutex_unlock(&mBiDictMutex); + return ret; + } + uint32_t getType(uint32_t session) { + pthread_mutex_lock(&mBiDictMutex); + uint32_t ret = mTypeMap[session]; + pthread_mutex_unlock(&mBiDictMutex); + return ret; + } + std::vector<uint32_t> getAllSessions() { + std::vector<uint32_t> ret; + pthread_mutex_lock(&mBiDictMutex); + for (auto it = mBackwardMap.begin(); it != mBackwardMap.end(); it++) { + ret.push_back(it->first); + } + pthread_mutex_unlock(&mBiDictMutex); + return ret; + } + private: + pthread_mutex_t mBiDictMutex; + // mForwarMap mapping id->session + std::map<uint32_t, uint32_t> mForwardMap; + // mBackwardMap mapping session->id + std::map<uint32_t, uint32_t> mBackwardMap; + // mTypeMap mapping session->type + std::map<uint32_t, uint32_t> mTypeMap; + }; + + class LocationAPIRequest { + public: + LocationAPIRequest(LocationAPIClientBase& API) : mAPI(API) {} + virtual ~LocationAPIRequest() {} + virtual void onResponse(LocationError /*error*/) {}; + virtual void onCollectiveResponse( + size_t /*count*/, LocationError* /*errors*/, uint32_t* /*ids*/) {}; + LocationAPIClientBase& mAPI; + }; + + class StartTrackingRequest : public LocationAPIRequest { + public: + StartTrackingRequest(LocationAPIClientBase& API) : LocationAPIRequest(API) {} + inline void onResponse(LocationError error) { + mAPI.onStartTrackingCb(error); + } + }; + + class StopTrackingRequest : public LocationAPIRequest { + public: + StopTrackingRequest(LocationAPIClientBase& API) : LocationAPIRequest(API) {} + inline void onResponse(LocationError error) { + mAPI.onStopTrackingCb(error); + } + }; + + class UpdateTrackingOptionsRequest : public LocationAPIRequest { + public: + UpdateTrackingOptionsRequest(LocationAPIClientBase& API) : LocationAPIRequest(API) {} + inline void onResponse(LocationError error) { + mAPI.onUpdateTrackingOptionsCb(error); + } + }; + + class StartBatchingRequest : public LocationAPIRequest { + public: + StartBatchingRequest(LocationAPIClientBase& API) : LocationAPIRequest(API) {} + inline void onResponse(LocationError error) { + mAPI.onStartBatchingCb(error); + } + }; + + class StopBatchingRequest : public LocationAPIRequest { + public: + StopBatchingRequest(LocationAPIClientBase& API) : LocationAPIRequest(API) {} + inline void onResponse(LocationError error) { + mAPI.onStopBatchingCb(error); + } + }; + + class UpdateBatchingOptionsRequest : public LocationAPIRequest { + public: + UpdateBatchingOptionsRequest(LocationAPIClientBase& API) : LocationAPIRequest(API) {} + inline void onResponse(LocationError error) { + mAPI.onUpdateBatchingOptionsCb(error); + } + }; + + class GetBatchedLocationsRequest : public LocationAPIRequest { + public: + GetBatchedLocationsRequest(LocationAPIClientBase& API) : LocationAPIRequest(API) {} + inline void onResponse(LocationError error) { + mAPI.onGetBatchedLocationsCb(error); + } + }; + + class AddGeofencesRequest : public LocationAPIRequest { + public: + AddGeofencesRequest(LocationAPIClientBase& API) : LocationAPIRequest(API) {} + inline void onCollectiveResponse(size_t count, LocationError* errors, uint32_t* sessions) { + uint32_t *ids = (uint32_t*)malloc(sizeof(uint32_t) * count); + for (size_t i = 0; i < count; i++) { + ids[i] = mAPI.mGeofenceBiDict.getId(sessions[i]); + } + mAPI.onAddGeofencesCb(count, errors, ids); + free(ids); + } + }; + + class RemoveGeofencesRequest : public LocationAPIRequest { + public: + RemoveGeofencesRequest(LocationAPIClientBase& API) : LocationAPIRequest(API) {} + inline void onCollectiveResponse(size_t count, LocationError* errors, uint32_t* sessions) { + uint32_t *ids = (uint32_t*)malloc(sizeof(uint32_t) * count); + for (size_t i = 0; i < count; i++) { + ids[i] = mAPI.mGeofenceBiDict.getId(sessions[i]); + mAPI.mGeofenceBiDict.rmBySession(sessions[i]); + } + mAPI.onRemoveGeofencesCb(count, errors, ids); + free(ids); + } + }; + + class ModifyGeofencesRequest : public LocationAPIRequest { + public: + ModifyGeofencesRequest(LocationAPIClientBase& API) : LocationAPIRequest(API) {} + inline void onCollectiveResponse(size_t count, LocationError* errors, uint32_t* sessions) { + uint32_t *ids = (uint32_t*)malloc(sizeof(uint32_t) * count); + for (size_t i = 0; i < count; i++) { + ids[i] = mAPI.mGeofenceBiDict.getId(sessions[i]); + } + mAPI.onModifyGeofencesCb(count, errors, ids); + free(ids); + } + }; + + class PauseGeofencesRequest : public LocationAPIRequest { + public: + PauseGeofencesRequest(LocationAPIClientBase& API) : LocationAPIRequest(API) {} + inline void onCollectiveResponse(size_t count, LocationError* errors, uint32_t* sessions) { + uint32_t *ids = (uint32_t*)malloc(sizeof(uint32_t) * count); + for (size_t i = 0; i < count; i++) { + ids[i] = mAPI.mGeofenceBiDict.getId(sessions[i]); + } + mAPI.onPauseGeofencesCb(count, errors, ids); + free(ids); + } + }; + + class ResumeGeofencesRequest : public LocationAPIRequest { + public: + ResumeGeofencesRequest(LocationAPIClientBase& API) : LocationAPIRequest(API) {} + inline void onCollectiveResponse(size_t count, LocationError* errors, uint32_t* sessions) { + uint32_t *ids = (uint32_t*)malloc(sizeof(uint32_t) * count); + for (size_t i = 0; i < count; i++) { + ids[i] = mAPI.mGeofenceBiDict.getId(sessions[i]); + } + mAPI.onResumeGeofencesCb(count, errors, ids); + free(ids); + } + }; + + class GnssNiResponseRequest : public LocationAPIRequest { + public: + GnssNiResponseRequest(LocationAPIClientBase& API) : LocationAPIRequest(API) {} + inline void onResponse(LocationError error) { + mAPI.onGnssNiResponseCb(error); + } + }; + + class GnssDeleteAidingDataRequest : public LocationAPIRequest { + public: + GnssDeleteAidingDataRequest(LocationAPIClientBase& API) : LocationAPIRequest(API) {} + inline void onResponse(LocationError error) { + mAPI.onGnssDeleteAidingDataCb(error); + } + }; + + class EnableRequest : public LocationAPIRequest { + public: + EnableRequest(LocationAPIClientBase& API) : LocationAPIRequest(API) {} + inline void onResponse(LocationError error) { + mAPI.onEnableCb(error); + } + }; + + class DisableRequest : public LocationAPIRequest { + public: + DisableRequest(LocationAPIClientBase& API) : LocationAPIRequest(API) {} + inline void onResponse(LocationError error) { + mAPI.onDisableCb(error); + } + }; + + class GnssUpdateConfigRequest : public LocationAPIRequest { + public: + GnssUpdateConfigRequest(LocationAPIClientBase& API) : LocationAPIRequest(API) {} + inline void onCollectiveResponse(size_t count, LocationError* errors, uint32_t* ids) { + mAPI.onGnssUpdateConfigCb(count, errors, ids); + } + }; + + class RequestQueue { + public: + RequestQueue(uint32_t session): mSession(session) { + } + ~RequestQueue() { + LocationAPIRequest* request = nullptr; + while (!mQueue.empty()) { + request = mQueue.front(); + mQueue.pop(); + delete request; + } + } + void push(LocationAPIRequest* request) { + mQueue.push(request); + } + LocationAPIRequest* pop() { + LocationAPIRequest* request = nullptr; + if (!mQueue.empty()) { + request = mQueue.front(); + mQueue.pop(); + } + return request; + } + uint32_t getSession() { return mSession; } + private: + uint32_t mSession; + std::queue<LocationAPIRequest*> mQueue; + }; + + LocationAPIRequest* getRequestBySession(uint32_t session); + LocationAPIRequest* getGeofencesRequest(); + +private: + pthread_mutex_t mMutex; + + trackingCallback mTrackingCallback; + batchingCallback mBatchingCallback; + geofenceBreachCallback mGeofenceBreachCallback; + + LocationAPI* mLocationAPI; + LocationControlAPI* mLocationControlAPI; + + BiDict mGeofenceBiDict; + RequestQueue* mRequestQueues[REQUEST_MAX]; + std::map<uint32_t, SessionEntity> mSessionMap; + int32_t mBatchSize; + + GnssConfig mConfig; +}; + +#endif /* LOCATION_API_CLINET_BASE_H */ diff --git a/location/location_interface.h b/location/location_interface.h new file mode 100644 index 0000000..b726931 --- /dev/null +++ b/location/location_interface.h @@ -0,0 +1,86 @@ +/* Copyright (c) 2017 The Linux Foundation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * * Neither the name of The Linux Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef LOCATION_INTERFACE_H +#define LOCATION_INTERFACE_H + +#include <LocationAPI.h> + +struct GnssInterface { + size_t size; + void (*initialize)(void); + void (*deinitialize)(void); + void (*addClient)(LocationAPI* client, const LocationCallbacks& callbacks); + void (*removeClient)(LocationAPI* client); + void (*requestCapabilities)(LocationAPI* client); + uint32_t (*startTracking)(LocationAPI* client, LocationOptions& options); + void (*updateTrackingOptions)(LocationAPI* client, uint32_t id, LocationOptions& options); + void (*stopTracking)(LocationAPI* client, uint32_t id); + void (*gnssNiResponse)(LocationAPI* client, uint32_t id, GnssNiResponse response); + void (*setControlCallbacks)(LocationControlCallbacks& controlCallbacks); + uint32_t (*enable)(LocationTechnologyType techType); + void (*disable)(uint32_t id); + uint32_t* (*gnssUpdateConfig)(GnssConfig config); + uint32_t (*gnssDeleteAidingData)(GnssAidingData& data); + void (*injectLocation)(double latitude, double longitude, float accuracy); + void (*injectTime)(int64_t time, int64_t timeReference, int32_t uncertainty); +}; + +struct FlpInterface { + size_t size; + void (*initialize)(void); + void (*deinitialize)(void); + void (*addClient)(LocationAPI* client, const LocationCallbacks& callbacks); + void (*removeClient)(LocationAPI* client); + void (*requestCapabilities)(LocationAPI* client); + uint32_t (*startTracking)(LocationAPI* client, LocationOptions& options); + void (*updateTrackingOptions)(LocationAPI* client, uint32_t id, LocationOptions& options); + void (*stopTracking)(LocationAPI* client, uint32_t id); + uint32_t (*startBatching)(LocationAPI* client, LocationOptions&); + void (*stopBatching)(LocationAPI* client, uint32_t id); + void (*updateBatchingOptions)(LocationAPI* client, uint32_t id, LocationOptions&); + void (*getBatchedLocations)(LocationAPI* client, uint32_t id, size_t count); + void (*getPowerStateChanges)(void* powerStateCb); +}; + +struct GeofenceInterface { + size_t size; + void (*initialize)(void); + void (*deinitialize)(void); + void (*addClient)(LocationAPI* client, const LocationCallbacks& callbacks); + void (*removeClient)(LocationAPI* client); + void (*requestCapabilities)(LocationAPI* client); + uint32_t* (*addGeofences)(LocationAPI* client, size_t count, GeofenceOption*, GeofenceInfo*); + void (*removeGeofences)(LocationAPI* client, size_t count, uint32_t* ids); + void (*modifyGeofences)(LocationAPI* client, size_t count, uint32_t* ids, + GeofenceOption* options); + void (*pauseGeofences)(LocationAPI* client, size_t count, uint32_t* ids); + void (*resumeGeofences)(LocationAPI* client, size_t count, uint32_t* ids); +}; + +#endif /* LOCATION_INTERFACE_H */ |