summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Bestas <mkbestas@gmail.com>2020-04-18 17:12:06 +0300
committerMichael Bestas <mkbestas@gmail.com>2020-04-18 17:12:06 +0300
commitea8aefcf657335910a97e158e1c4752db9b0a880 (patch)
tree0b9f185d6b013c9402446ad1d41ae560fa137288
Squashed 'gps/' content from commit 8582827c8
git-subtree-dir: gps git-subtree-split: 8582827c8f8cb19c2eff71f0737e17f3068ba41a
-rw-r--r--Android.mk5
-rw-r--r--CleanSpec.mk50
-rw-r--r--Makefile.am10
-rw-r--r--android/1.0/AGnss.cpp203
-rw-r--r--android/1.0/AGnss.h79
-rw-r--r--android/1.0/AGnssRil.cpp114
-rw-r--r--android/1.0/AGnssRil.h83
-rw-r--r--android/1.0/Android.mk97
-rw-r--r--android/1.0/Gnss.cpp360
-rw-r--r--android/1.0/Gnss.h143
-rw-r--r--android/1.0/GnssBatching.cpp130
-rw-r--r--android/1.0/GnssBatching.h80
-rw-r--r--android/1.0/GnssConfiguration.cpp230
-rw-r--r--android/1.0/GnssConfiguration.h71
-rw-r--r--android/1.0/GnssDebug.cpp173
-rw-r--r--android/1.0/GnssDebug.h59
-rw-r--r--android/1.0/GnssGeofencing.cpp141
-rw-r--r--android/1.0/GnssGeofencing.h91
-rw-r--r--android/1.0/GnssMeasurement.cpp101
-rw-r--r--android/1.0/GnssMeasurement.h77
-rw-r--r--android/1.0/GnssNi.cpp85
-rw-r--r--android/1.0/GnssNi.h75
-rw-r--r--android/1.0/android.hardware.gnss@1.0-service-qti.rc4
-rw-r--r--android/1.0/android.hardware.gnss@1.0-service-qti.xml35
-rw-r--r--android/1.0/location_api/BatchingAPIClient.cpp196
-rw-r--r--android/1.0/location_api/BatchingAPIClient.h74
-rw-r--r--android/1.0/location_api/GeofenceAPIClient.cpp275
-rw-r--r--android/1.0/location_api/GeofenceAPIClient.h76
-rw-r--r--android/1.0/location_api/GnssAPIClient.cpp566
-rw-r--r--android/1.0/location_api/GnssAPIClient.h109
-rw-r--r--android/1.0/location_api/LocationUtil.cpp206
-rw-r--r--android/1.0/location_api/LocationUtil.h55
-rw-r--r--android/1.0/location_api/MeasurementAPIClient.cpp276
-rw-r--r--android/1.0/location_api/MeasurementAPIClient.h77
-rw-r--r--android/1.0/service.cpp85
-rw-r--r--android/1.1/AGnss.cpp203
-rw-r--r--android/1.1/AGnss.h79
-rw-r--r--android/1.1/AGnssRil.cpp114
-rw-r--r--android/1.1/AGnssRil.h83
-rw-r--r--android/1.1/Android.mk99
-rw-r--r--android/1.1/Gnss.cpp477
-rw-r--r--android/1.1/Gnss.h154
-rw-r--r--android/1.1/GnssBatching.cpp130
-rw-r--r--android/1.1/GnssBatching.h80
-rw-r--r--android/1.1/GnssConfiguration.cpp313
-rw-r--r--android/1.1/GnssConfiguration.h78
-rw-r--r--android/1.1/GnssDebug.cpp175
-rw-r--r--android/1.1/GnssDebug.h59
-rw-r--r--android/1.1/GnssGeofencing.cpp141
-rw-r--r--android/1.1/GnssGeofencing.h91
-rw-r--r--android/1.1/GnssMeasurement.cpp134
-rw-r--r--android/1.1/GnssMeasurement.h83
-rw-r--r--android/1.1/GnssNi.cpp85
-rw-r--r--android/1.1/GnssNi.h75
-rw-r--r--android/1.1/android.hardware.gnss@1.1-service-qti.rc4
-rw-r--r--android/1.1/android.hardware.gnss@1.1-service-qti.xml35
-rw-r--r--android/1.1/location_api/BatchingAPIClient.cpp196
-rw-r--r--android/1.1/location_api/BatchingAPIClient.h74
-rw-r--r--android/1.1/location_api/GeofenceAPIClient.cpp275
-rw-r--r--android/1.1/location_api/GeofenceAPIClient.h76
-rw-r--r--android/1.1/location_api/GnssAPIClient.cpp566
-rw-r--r--android/1.1/location_api/GnssAPIClient.h109
-rw-r--r--android/1.1/location_api/LocationUtil.cpp206
-rw-r--r--android/1.1/location_api/LocationUtil.h55
-rw-r--r--android/1.1/location_api/MeasurementAPIClient.cpp332
-rw-r--r--android/1.1/location_api/MeasurementAPIClient.h84
-rw-r--r--android/1.1/service.cpp85
-rw-r--r--android/2.0/AGnss.cpp209
-rw-r--r--android/2.0/AGnss.h77
-rw-r--r--android/2.0/AGnssRil.cpp133
-rw-r--r--android/2.0/AGnssRil.h84
-rw-r--r--android/2.0/Android.mk110
-rw-r--r--android/2.0/Gnss.cpp671
-rw-r--r--android/2.0/Gnss.h187
-rw-r--r--android/2.0/GnssBatching.cpp163
-rw-r--r--android/2.0/GnssBatching.h84
-rw-r--r--android/2.0/GnssConfiguration.cpp321
-rw-r--r--android/2.0/GnssConfiguration.h80
-rw-r--r--android/2.0/GnssDebug.cpp299
-rw-r--r--android/2.0/GnssDebug.h62
-rw-r--r--android/2.0/GnssGeofencing.cpp141
-rw-r--r--android/2.0/GnssGeofencing.h91
-rw-r--r--android/2.0/GnssMeasurement.cpp165
-rw-r--r--android/2.0/GnssMeasurement.h86
-rw-r--r--android/2.0/GnssNi.cpp85
-rw-r--r--android/2.0/GnssNi.h75
-rw-r--r--android/2.0/android.hardware.gnss@2.0-service-qti.rc4
-rw-r--r--android/2.0/android.hardware.gnss@2.0-service-qti.xml36
-rw-r--r--android/2.0/location_api/BatchingAPIClient.cpp250
-rw-r--r--android/2.0/location_api/BatchingAPIClient.h81
-rw-r--r--android/2.0/location_api/GeofenceAPIClient.cpp275
-rw-r--r--android/2.0/location_api/GeofenceAPIClient.h76
-rw-r--r--android/2.0/location_api/GnssAPIClient.cpp726
-rw-r--r--android/2.0/location_api/GnssAPIClient.h114
-rw-r--r--android/2.0/location_api/LocationUtil.cpp278
-rw-r--r--android/2.0/location_api/LocationUtil.h58
-rw-r--r--android/2.0/location_api/MeasurementAPIClient.cpp474
-rw-r--r--android/2.0/location_api/MeasurementAPIClient.h89
-rw-r--r--android/2.0/service.cpp85
-rw-r--r--android/Android.mk15
-rw-r--r--android/measurement_corrections/1.0/MeasurementCorrections.cpp71
-rw-r--r--android/measurement_corrections/1.0/MeasurementCorrections.h76
-rw-r--r--android/utils/Android.mk37
-rw-r--r--android/utils/battery_listener.cpp266
-rw-r--r--android/utils/battery_listener.h32
-rw-r--r--android/visibility_control/1.0/GnssVisibilityControl.cpp169
-rw-r--r--android/visibility_control/1.0/GnssVisibilityControl.h90
-rw-r--r--batching/Android.mk37
-rw-r--r--batching/BatchingAdapter.cpp1050
-rw-r--r--batching/BatchingAdapter.h152
-rw-r--r--batching/Makefile.am45
-rw-r--r--batching/configure.ac78
-rw-r--r--batching/location-batching.pc.in10
-rw-r--r--batching/location_batching.cpp134
-rw-r--r--build/target_specific_features.mk69
-rw-r--r--configure.ac87
-rw-r--r--core/Android.mk59
-rw-r--r--core/ContextBase.cpp331
-rw-r--r--core/ContextBase.h260
-rw-r--r--core/EngineHubProxyBase.h127
-rw-r--r--core/LBSProxyBase.h70
-rw-r--r--core/LocAdapterBase.cpp411
-rw-r--r--core/LocAdapterBase.h222
-rw-r--r--core/LocAdapterProxyBase.h77
-rw-r--r--core/LocApiBase.cpp877
-rw-r--r--core/LocApiBase.h322
-rw-r--r--core/LocContext.cpp98
-rw-r--r--core/LocContext.h66
-rw-r--r--core/Makefile.am66
-rw-r--r--core/SystemStatus.cpp1748
-rw-r--r--core/SystemStatus.h916
-rw-r--r--core/SystemStatusOsObserver.cpp575
-rw-r--r--core/SystemStatusOsObserver.h176
-rw-r--r--core/configure.ac82
-rw-r--r--core/data-items/DataItemConcreteTypesBase.h554
-rw-r--r--core/data-items/DataItemId.h79
-rw-r--r--core/data-items/DataItemsFactoryProxy.cpp100
-rw-r--r--core/data-items/DataItemsFactoryProxy.h55
-rw-r--r--core/data-items/IDataItemCore.h82
-rw-r--r--core/loc-core.pc.in10
-rw-r--r--core/loc_core_log.cpp227
-rw-r--r--core/loc_core_log.h58
-rw-r--r--core/observer/IDataItemObserver.h76
-rw-r--r--core/observer/IDataItemSubscription.h129
-rw-r--r--core/observer/IFrameworkActionReq.h101
-rw-r--r--core/observer/IOsObserver.h107
-rw-r--r--etc/Android.mk21
-rw-r--r--etc/flp.conf60
-rw-r--r--etc/gps.conf299
-rw-r--r--geofence/Android.mk36
-rw-r--r--geofence/GeofenceAdapter.cpp870
-rw-r--r--geofence/GeofenceAdapter.h136
-rw-r--r--geofence/Makefile.am50
-rw-r--r--geofence/configure.ac72
-rw-r--r--geofence/location-geofence.pc.in10
-rw-r--r--geofence/location_geofence.cpp145
-rw-r--r--gnss/Agps.cpp675
-rw-r--r--gnss/Agps.h316
-rw-r--r--gnss/Android.mk46
-rw-r--r--gnss/GnssAdapter.cpp5046
-rw-r--r--gnss/GnssAdapter.h469
-rw-r--r--gnss/Makefile.am31
-rw-r--r--gnss/XtraSystemStatusObserver.cpp329
-rw-r--r--gnss/XtraSystemStatusObserver.h90
-rw-r--r--gnss/location_gnss.cpp392
-rw-r--r--gps_vendor_board.mk7
-rw-r--r--gps_vendor_product.mk14
-rw-r--r--loc-hal.pc.in10
-rw-r--r--location/Android.mk41
-rw-r--r--location/ILocationAPI.h194
-rw-r--r--location/LocationAPI.cpp725
-rw-r--r--location/LocationAPI.h266
-rw-r--r--location/LocationAPIClientBase.cpp954
-rw-r--r--location/LocationAPIClientBase.h587
-rw-r--r--location/LocationDataTypes.h1465
-rw-r--r--location/Makefile.am40
-rw-r--r--location/configure.ac82
-rw-r--r--location/location-api.pc.in10
-rw-r--r--location/location_interface.h121
-rw-r--r--pla/Android.mk29
-rw-r--r--pla/android/loc_pla.h66
-rw-r--r--pla/oe/loc_pla.h100
-rw-r--r--utils/Android.mk65
-rw-r--r--utils/LocHeap.cpp354
-rw-r--r--utils/LocHeap.h96
-rw-r--r--utils/LocIpc.cpp414
-rw-r--r--utils/LocIpc.h206
-rw-r--r--utils/LocSharedLock.h77
-rw-r--r--utils/LocThread.cpp266
-rw-r--r--utils/LocThread.h92
-rw-r--r--utils/LocTimer.cpp753
-rw-r--r--utils/LocTimer.h74
-rw-r--r--utils/LocUnorderedSetMap.h192
-rw-r--r--utils/Makefile.am72
-rw-r--r--utils/MsgTask.cpp108
-rw-r--r--utils/MsgTask.h67
-rw-r--r--utils/configure.ac92
-rw-r--r--utils/gps-utils.pc.in10
-rw-r--r--utils/gps_extended.h114
-rw-r--r--utils/gps_extended_c.h2290
-rw-r--r--utils/linked_list.c325
-rw-r--r--utils/linked_list.h219
-rw-r--r--utils/loc_cfg.cpp1067
-rw-r--r--utils/loc_cfg.h143
-rw-r--r--utils/loc_gps.h2229
-rw-r--r--utils/loc_log.cpp238
-rw-r--r--utils/loc_log.h71
-rw-r--r--utils/loc_misc_utils.cpp145
-rw-r--r--utils/loc_misc_utils.h127
-rw-r--r--utils/loc_nmea.cpp2088
-rw-r--r--utils/loc_nmea.h92
-rw-r--r--utils/loc_target.cpp210
-rw-r--r--utils/loc_target.h78
-rw-r--r--utils/loc_timer.h74
-rw-r--r--utils/log_util.h203
-rw-r--r--utils/msg_q.c378
-rw-r--r--utils/msg_q.h230
217 files changed, 52452 insertions, 0 deletions
diff --git a/Android.mk b/Android.mk
new file mode 100644
index 0000000..f1088a4
--- /dev/null
+++ b/Android.mk
@@ -0,0 +1,5 @@
+ifneq ($(BOARD_VENDOR_QCOM_GPS_LOC_API_HARDWARE),)
+LOCAL_PATH := $(call my-dir)
+include $(LOCAL_PATH)/build/target_specific_features.mk
+include $(call all-makefiles-under,$(LOCAL_PATH))
+endif
diff --git a/CleanSpec.mk b/CleanSpec.mk
new file mode 100644
index 0000000..dd1849d
--- /dev/null
+++ b/CleanSpec.mk
@@ -0,0 +1,50 @@
+# Copyright (C) 2007 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+# If you don't need to do a full clean build but would like to touch
+# a file or delete some intermediate files, add a clean step to the end
+# of the list. These steps will only be run once, if they haven't been
+# run before.
+#
+# E.g.:
+# $(call add-clean-step, touch -c external/sqlite/sqlite3.h)
+# $(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/STATIC_LIBRARIES/libz_intermediates)
+#
+# Always use "touch -c" and "rm -f" or "rm -rf" to gracefully deal with
+# files that are missing or have been moved.
+#
+# Use $(PRODUCT_OUT) to get to the "out/target/product/blah/" directory.
+# Use $(OUT_DIR) to refer to the "out" directory.
+#
+# If you need to re-do something that's already mentioned, just copy
+# the command and add it to the bottom of the list. E.g., if a change
+# that you made last week required touching a file and a change you
+# made today requires touching the same file, just copy the old
+# touch step and add it to the end of the list.
+#
+# ************************************************
+# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST
+# ************************************************
+
+# For example:
+#$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/APPS/AndroidTests_intermediates)
+#$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/core_intermediates)
+#$(call add-clean-step, find $(OUT_DIR) -type f -name "IGTalkSession*" -print0 | xargs -0 rm -f)
+#$(call add-clean-step, rm -rf $(PRODUCT_OUT)/data/*)
+
+# ************************************************
+# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST
+# ************************************************
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/SHARED_LIBRARIES/libloc_api*)
diff --git a/Makefile.am b/Makefile.am
new file mode 100644
index 0000000..cd4a731
--- /dev/null
+++ b/Makefile.am
@@ -0,0 +1,10 @@
+# Makefile.am - Automake script for gps loc_api
+#
+
+ACLOCAL_AMFLAGS = -I m4
+
+SUBDIRS = gnss
+
+pkgconfigdir = $(libdir)/pkgconfig
+pkgconfig_DATA = loc-hal.pc
+EXTRA_DIST = $(pkgconfig_DATA)
diff --git a/android/1.0/AGnss.cpp b/android/1.0/AGnss.cpp
new file mode 100644
index 0000000..79f665c
--- /dev/null
+++ b/android/1.0/AGnss.cpp
@@ -0,0 +1,203 @@
+/*
+ * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
+ * Not a Contribution
+ */
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "LocSvc_AGnssInterface"
+
+#include <log_util.h>
+#include "Gnss.h"
+#include "AGnss.h"
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace V1_0 {
+namespace implementation {
+
+static AGnss* spAGnss = nullptr;
+
+AGnss::AGnss(Gnss* gnss) : mGnss(gnss) {
+ spAGnss = this;
+}
+
+AGnss::~AGnss() {
+ spAGnss = nullptr;
+}
+
+void AGnss::agnssStatusIpV4Cb(AGnssExtStatusIpV4 status){
+ if (nullptr != spAGnss) {
+ spAGnss->statusIpV4Cb(status);
+ }
+}
+
+void AGnss::statusIpV4Cb(AGnssExtStatusIpV4 status) {
+ IAGnssCallback::AGnssStatusIpV4 st = {};
+
+ switch (status.type) {
+ case LOC_AGPS_TYPE_SUPL:
+ st.type = IAGnssCallback::AGnssType::TYPE_SUPL;
+ break;
+ case LOC_AGPS_TYPE_C2K:
+ st.type = IAGnssCallback::AGnssType::TYPE_C2K;
+ break;
+ default:
+ LOC_LOGE("invalid type: %d", status.type);
+ return;
+ }
+
+ switch (status.status) {
+ case LOC_GPS_REQUEST_AGPS_DATA_CONN:
+ st.status = IAGnssCallback::AGnssStatusValue::REQUEST_AGNSS_DATA_CONN;
+ break;
+ case LOC_GPS_RELEASE_AGPS_DATA_CONN:
+ st.status = IAGnssCallback::AGnssStatusValue::RELEASE_AGNSS_DATA_CONN;
+ break;
+ case LOC_GPS_AGPS_DATA_CONNECTED:
+ st.status = IAGnssCallback::AGnssStatusValue::AGNSS_DATA_CONNECTED;
+ break;
+ case LOC_GPS_AGPS_DATA_CONN_DONE:
+ st.status = IAGnssCallback::AGnssStatusValue::AGNSS_DATA_CONN_DONE;
+ break;
+ case LOC_GPS_AGPS_DATA_CONN_FAILED:
+ st.status = IAGnssCallback::AGnssStatusValue::AGNSS_DATA_CONN_FAILED;
+ break;
+ default:
+ LOC_LOGE("invalid status: %d", status.status);
+ return;
+ }
+ st.ipV4Addr = status.ipV4Addr;
+
+ if (mAGnssCbIface != nullptr) {
+ auto r = mAGnssCbIface->agnssStatusIpV4Cb(st);
+ if (!r.isOk()) {
+ LOC_LOGw("Error invoking AGNSS status cb %s", r.description().c_str());
+ }
+ } else {
+ LOC_LOGw("setCallback has not been called yet");
+ }
+}
+
+Return<void> AGnss::setCallback(const sp<IAGnssCallback>& callback) {
+
+ if(mGnss == nullptr || mGnss->getGnssInterface() == nullptr){
+ LOC_LOGE("Null GNSS interface");
+ return Void();
+ }
+
+ // Save the interface
+ mAGnssCbIface = callback;
+
+ AgpsCbInfo cbInfo = {};
+ cbInfo.statusV4Cb = (void*)agnssStatusIpV4Cb;
+ cbInfo.atlType = AGPS_ATL_TYPE_SUPL | AGPS_ATL_TYPE_SUPL_ES;
+
+ mGnss->getGnssInterface()->agpsInit(cbInfo);
+ return Void();
+}
+
+Return<bool> AGnss::dataConnClosed() {
+
+ if(mGnss == nullptr || mGnss->getGnssInterface() == nullptr){
+ LOC_LOGE("Null GNSS interface");
+ return false;
+ }
+
+ mGnss->getGnssInterface()->agpsDataConnClosed(LOC_AGPS_TYPE_SUPL);
+ return true;
+}
+
+Return<bool> AGnss::dataConnFailed() {
+
+ if(mGnss == nullptr || mGnss->getGnssInterface() == nullptr){
+ LOC_LOGE("Null GNSS interface");
+ return false;
+ }
+
+ mGnss->getGnssInterface()->agpsDataConnFailed(LOC_AGPS_TYPE_SUPL);
+ return true;
+}
+
+Return<bool> AGnss::dataConnOpen(const hidl_string& apn,
+ IAGnss::ApnIpType apnIpType) {
+
+ if(mGnss == nullptr || mGnss->getGnssInterface() == nullptr){
+ LOC_LOGE("Null GNSS interface");
+ return false;
+ }
+
+ /* Validate */
+ if(apn.empty()){
+ LOC_LOGE("Invalid APN");
+ return false;
+ }
+
+ LOC_LOGD("dataConnOpen APN name = [%s]", apn.c_str());
+
+ AGpsBearerType bearerType;
+ switch (apnIpType) {
+ case IAGnss::ApnIpType::IPV4:
+ bearerType = AGPS_APN_BEARER_IPV4;
+ break;
+ case IAGnss::ApnIpType::IPV6:
+ bearerType = AGPS_APN_BEARER_IPV6;
+ break;
+ case IAGnss::ApnIpType::IPV4V6:
+ bearerType = AGPS_APN_BEARER_IPV4V6;
+ break;
+ default:
+ bearerType = AGPS_APN_BEARER_IPV4;
+ break;
+ }
+
+ mGnss->getGnssInterface()->agpsDataConnOpen(
+ LOC_AGPS_TYPE_SUPL, apn.c_str(), apn.size(), (int)bearerType);
+ return true;
+}
+
+Return<bool> AGnss::setServer(IAGnssCallback::AGnssType type,
+ const hidl_string& hostname,
+ int32_t port) {
+ if (mGnss == nullptr) {
+ LOC_LOGE("%s]: mGnss is nullptr", __FUNCTION__);
+ return false;
+ }
+
+ GnssConfig config;
+ memset(&config, 0, sizeof(GnssConfig));
+ config.size = sizeof(GnssConfig);
+ config.flags = GNSS_CONFIG_FLAGS_SET_ASSISTANCE_DATA_VALID_BIT;
+ config.assistanceServer.size = sizeof(GnssConfigSetAssistanceServer);
+ if (type == IAGnssCallback::AGnssType::TYPE_SUPL) {
+ config.assistanceServer.type = GNSS_ASSISTANCE_TYPE_SUPL;
+ } else if (type == IAGnssCallback::AGnssType::TYPE_C2K) {
+ config.assistanceServer.type = GNSS_ASSISTANCE_TYPE_C2K;
+ } else {
+ LOC_LOGE("%s]: invalid AGnssType: %d", __FUNCTION__, static_cast<int>(type));
+ return false;
+ }
+ config.assistanceServer.hostName = strdup(hostname.c_str());
+ config.assistanceServer.port = port;
+ return mGnss->updateConfiguration(config);
+}
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace gnss
+} // namespace hardware
+} // namespace android
diff --git a/android/1.0/AGnss.h b/android/1.0/AGnss.h
new file mode 100644
index 0000000..cdd5931
--- /dev/null
+++ b/android/1.0/AGnss.h
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
+ * Not a Contribution
+ */
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HARDWARE_GNSS_V1_0_AGNSS_H
+#define ANDROID_HARDWARE_GNSS_V1_0_AGNSS_H
+
+#include <android/hardware/gnss/1.0/IAGnss.h>
+#include <hidl/Status.h>
+#include <gps_extended_c.h>
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace V1_0 {
+namespace implementation {
+
+using ::android::hardware::gnss::V1_0::IAGnss;
+using ::android::hardware::gnss::V1_0::IAGnssCallback;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::hidl_string;
+using ::android::sp;
+
+struct Gnss;
+struct AGnss : public IAGnss {
+
+ AGnss(Gnss* gnss);
+ ~AGnss();
+ /*
+ * Methods from ::android::hardware::gnss::V1_0::IAGnss interface follow.
+ * These declarations were generated from IAGnss.hal.
+ */
+ Return<void> setCallback(const sp<IAGnssCallback>& callback) override;
+
+ Return<bool> dataConnClosed() override;
+
+ Return<bool> dataConnFailed() override;
+
+ Return<bool> dataConnOpen(const hidl_string& apn,
+ IAGnss::ApnIpType apnIpType) override;
+
+ Return<bool> setServer(IAGnssCallback::AGnssType type,
+ const hidl_string& hostname, int32_t port) override;
+
+ void statusIpV4Cb(AGnssExtStatusIpV4 status);
+
+ /* Data call setup callback passed down to GNSS HAL implementation */
+ static void agnssStatusIpV4Cb(AGnssExtStatusIpV4 status);
+
+ private:
+ Gnss* mGnss = nullptr;
+ sp<IAGnssCallback> mAGnssCbIface = nullptr;
+};
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace gnss
+} // namespace hardware
+} // namespace android
+
+#endif // ANDROID_HARDWARE_GNSS_V1_0_AGNSS_H
diff --git a/android/1.0/AGnssRil.cpp b/android/1.0/AGnssRil.cpp
new file mode 100644
index 0000000..0437cf1
--- /dev/null
+++ b/android/1.0/AGnssRil.cpp
@@ -0,0 +1,114 @@
+/*
+ * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
+ * Not a Contribution
+ */
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "LocSvc__AGnssRilInterface"
+
+#include <log_util.h>
+#include <dlfcn.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <sstream>
+#include <string>
+#include "Gnss.h"
+#include "AGnssRil.h"
+#include <DataItemConcreteTypesBase.h>
+
+typedef void* (getLocationInterface)();
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace V1_0 {
+namespace implementation {
+
+
+AGnssRil::AGnssRil(Gnss* gnss) : mGnss(gnss) {
+ ENTRY_LOG_CALLFLOW();
+}
+
+AGnssRil::~AGnssRil() {
+ ENTRY_LOG_CALLFLOW();
+}
+
+Return<bool> AGnssRil::updateNetworkState(bool connected, NetworkType type, bool /*roaming*/) {
+ ENTRY_LOG_CALLFLOW();
+ // Extra NetworkTypes not available in IAgnssRil enums
+ const int NetworkType_BLUETOOTH = 7;
+ const int NetworkType_ETHERNET = 9;
+ const int NetworkType_PROXY = 16;
+
+ // for XTRA
+ if (nullptr != mGnss && ( nullptr != mGnss->getGnssInterface() )) {
+ int8_t typeout = loc_core::NetworkInfoDataItemBase::TYPE_UNKNOWN;
+ switch(type)
+ {
+ case IAGnssRil::NetworkType::MOBILE:
+ typeout = loc_core::NetworkInfoDataItemBase::TYPE_MOBILE;
+ break;
+ case IAGnssRil::NetworkType::WIFI:
+ typeout = loc_core::NetworkInfoDataItemBase::TYPE_WIFI;
+ break;
+ case IAGnssRil::NetworkType::MMS:
+ typeout = loc_core::NetworkInfoDataItemBase::TYPE_MMS;
+ break;
+ case IAGnssRil::NetworkType::SUPL:
+ typeout = loc_core::NetworkInfoDataItemBase::TYPE_SUPL;
+ break;
+ case IAGnssRil::NetworkType::DUN:
+ typeout = loc_core::NetworkInfoDataItemBase::TYPE_DUN;
+ break;
+ case IAGnssRil::NetworkType::HIPRI:
+ typeout = loc_core::NetworkInfoDataItemBase::TYPE_HIPRI;
+ break;
+ case IAGnssRil::NetworkType::WIMAX:
+ typeout = loc_core::NetworkInfoDataItemBase::TYPE_WIMAX;
+ break;
+ default:
+ {
+ int networkType = (int) type;
+ // Handling network types not available in IAgnssRil
+ switch(networkType)
+ {
+ case NetworkType_BLUETOOTH:
+ typeout = loc_core::NetworkInfoDataItemBase::TYPE_BLUETOOTH;
+ break;
+ case NetworkType_ETHERNET:
+ typeout = loc_core::NetworkInfoDataItemBase::TYPE_ETHERNET;
+ break;
+ case NetworkType_PROXY:
+ typeout = loc_core::NetworkInfoDataItemBase::TYPE_PROXY;
+ break;
+ default:
+ typeout = loc_core::NetworkInfoDataItemBase::TYPE_UNKNOWN;
+ }
+ }
+ break;
+ }
+ mGnss->getGnssInterface()->updateConnectionStatus(connected, false, typeout, 0);
+ }
+ return true;
+}
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace gnss
+} // namespace hardware
+} // namespace android
diff --git a/android/1.0/AGnssRil.h b/android/1.0/AGnssRil.h
new file mode 100644
index 0000000..7f18c57
--- /dev/null
+++ b/android/1.0/AGnssRil.h
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
+ * Not a Contribution
+ */
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HARDWARE_GNSS_V1_0_AGNSSRIL_H_
+#define ANDROID_HARDWARE_GNSS_V1_0_AGNSSRIL_H_
+
+#include <android/hardware/gnss/1.0/IAGnssRil.h>
+#include <hidl/Status.h>
+#include <location_interface.h>
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace V1_0 {
+namespace implementation {
+
+using ::android::hardware::gnss::V1_0::IAGnssRil;
+using ::android::hardware::gnss::V1_0::IAGnssRilCallback;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::hidl_string;
+using ::android::sp;
+
+struct Gnss;
+/*
+ * Extended interface for AGNSS RIL support. An Assisted GNSS Radio Interface Layer interface
+ * allows the GNSS chipset to request radio interface layer information from Android platform.
+ * Examples of such information are reference location, unique subscriber ID, phone number string
+ * and network availability changes. Also contains wrapper methods to allow methods from
+ * IAGnssiRilCallback interface to be passed into the conventional implementation of the GNSS HAL.
+ */
+struct AGnssRil : public IAGnssRil {
+ AGnssRil(Gnss* gnss);
+ ~AGnssRil();
+
+ /*
+ * Methods from ::android::hardware::gnss::V1_0::IAGnssRil follow.
+ * These declarations were generated from IAGnssRil.hal.
+ */
+ Return<void> setCallback(const sp<IAGnssRilCallback>& /*callback*/) override {
+ return Void();
+ }
+ Return<void> setRefLocation(const IAGnssRil::AGnssRefLocation& /*agnssReflocation*/) override {
+ return Void();
+ }
+ Return<bool> setSetId(IAGnssRil::SetIDType /*type*/, const hidl_string& /*setid*/) override {
+ return false;
+ }
+ Return<bool> updateNetworkAvailability(bool /*available*/,
+ const hidl_string& /*apn*/) override {
+ return false;
+ }
+ Return<bool> updateNetworkState(bool connected, NetworkType type, bool roaming) override;
+
+ private:
+ Gnss* mGnss = nullptr;
+};
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace gnss
+} // namespace hardware
+} // namespace android
+
+#endif // ANDROID_HARDWARE_GNSS_V1_0_AGNSSRIL_H_
diff --git a/android/1.0/Android.mk b/android/1.0/Android.mk
new file mode 100644
index 0000000..9337325
--- /dev/null
+++ b/android/1.0/Android.mk
@@ -0,0 +1,97 @@
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := android.hardware.gnss@1.0-impl-qti
+LOCAL_VENDOR_MODULE := true
+LOCAL_MODULE_RELATIVE_PATH := hw
+LOCAL_SRC_FILES := \
+ AGnss.cpp \
+ Gnss.cpp \
+ GnssBatching.cpp \
+ GnssGeofencing.cpp \
+ GnssMeasurement.cpp \
+ GnssNi.cpp \
+ GnssConfiguration.cpp \
+ GnssDebug.cpp \
+ AGnssRil.cpp
+
+LOCAL_SRC_FILES += \
+ location_api/LocationUtil.cpp \
+ location_api/GnssAPIClient.cpp \
+ location_api/GeofenceAPIClient.cpp \
+ location_api/BatchingAPIClient.cpp \
+ location_api/MeasurementAPIClient.cpp \
+
+LOCAL_C_INCLUDES:= \
+ $(LOCAL_PATH)/location_api
+LOCAL_HEADER_LIBRARIES := \
+ libgps.utils_headers \
+ libloc_core_headers \
+ libloc_pla_headers \
+ liblocation_api_headers \
+ liblocbatterylistener_headers
+
+LOCAL_SHARED_LIBRARIES := \
+ liblog \
+ libhidlbase \
+ libhidltransport \
+ libhwbinder \
+ libcutils \
+ libutils \
+ android.hardware.gnss@1.0 \
+ android.hardware.health@1.0 \
+ android.hardware.health@2.0 \
+ android.hardware.power@1.2 \
+ libbase
+
+LOCAL_SHARED_LIBRARIES += \
+ libloc_core \
+ libgps.utils \
+ libdl \
+ liblocation_api \
+
+LOCAL_CFLAGS += $(GNSS_CFLAGS)
+LOCAL_STATIC_LIBRARIES := liblocbatterylistener
+LOCAL_STATIC_LIBRARIES += libhealthhalutils
+include $(BUILD_SHARED_LIBRARY)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := android.hardware.gnss@1.0-service-qti
+LOCAL_VINTF_FRAGMENTS := android.hardware.gnss@1.0-service-qti.xml
+LOCAL_VENDOR_MODULE := true
+LOCAL_MODULE_RELATIVE_PATH := hw
+LOCAL_INIT_RC := android.hardware.gnss@1.0-service-qti.rc
+LOCAL_SRC_FILES := \
+ service.cpp \
+
+LOCAL_C_INCLUDES:= \
+ $(LOCAL_PATH)/location_api
+LOCAL_HEADER_LIBRARIES := \
+ libgps.utils_headers \
+ libloc_core_headers \
+ libloc_pla_headers \
+ liblocation_api_headers
+
+
+LOCAL_SHARED_LIBRARIES := \
+ liblog \
+ libcutils \
+ libdl \
+ libbase \
+ libutils \
+ libgps.utils \
+ libqti_vndfwk_detect \
+
+LOCAL_SHARED_LIBRARIES += \
+ libhwbinder \
+ libhidlbase \
+ libhidltransport \
+ android.hardware.gnss@1.0 \
+
+LOCAL_CFLAGS += $(GNSS_CFLAGS)
+
+ifneq ($(LOC_HIDL_VERSION),)
+LOCAL_CFLAGS += -DLOC_HIDL_VERSION='"$(LOC_HIDL_VERSION)"'
+endif
+
+include $(BUILD_EXECUTABLE)
diff --git a/android/1.0/Gnss.cpp b/android/1.0/Gnss.cpp
new file mode 100644
index 0000000..d85e0a4
--- /dev/null
+++ b/android/1.0/Gnss.cpp
@@ -0,0 +1,360 @@
+/*
+ * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
+ * Not a Contribution
+ */
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "LocSvc_GnssInterface"
+#define LOG_NDEBUG 0
+
+#include <fstream>
+#include <log_util.h>
+#include <dlfcn.h>
+#include <cutils/properties.h>
+#include "Gnss.h"
+#include <LocationUtil.h>
+#include "battery_listener.h"
+
+typedef const GnssInterface* (getLocationInterface)();
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace V1_0 {
+namespace implementation {
+
+static sp<Gnss> sGnss;
+void Gnss::GnssDeathRecipient::serviceDied(uint64_t cookie, const wp<IBase>& who) {
+ LOC_LOGE("%s] service died. cookie: %llu, who: %p",
+ __FUNCTION__, static_cast<unsigned long long>(cookie), &who);
+ if (mGnss != nullptr) {
+ mGnss->stop();
+ mGnss->cleanup();
+ }
+}
+
+void location_on_battery_status_changed(bool charging) {
+ LOC_LOGd("battery status changed to %s charging", charging ? "" : "not ");
+ if (sGnss != nullptr) {
+ sGnss->getGnssInterface()->updateBatteryStatus(charging);
+ }
+}
+Gnss::Gnss() {
+ ENTRY_LOG_CALLFLOW();
+ sGnss = this;
+ // register health client to listen on battery change
+ loc_extn_battery_properties_listener_init(location_on_battery_status_changed);
+ // clear pending GnssConfig
+ memset(&mPendingConfig, 0, sizeof(GnssConfig));
+
+ mGnssDeathRecipient = new GnssDeathRecipient(this);
+}
+
+Gnss::~Gnss() {
+ ENTRY_LOG_CALLFLOW();
+ if (mApi != nullptr) {
+ delete mApi;
+ mApi = nullptr;
+ }
+ sGnss = nullptr;
+}
+
+GnssAPIClient* Gnss::getApi() {
+ if (mApi == nullptr && (mGnssCbIface != nullptr || mGnssNiCbIface != nullptr)) {
+ mApi = new GnssAPIClient(mGnssCbIface, mGnssNiCbIface);
+ if (mApi == nullptr) {
+ LOC_LOGE("%s] faild to create GnssAPIClient", __FUNCTION__);
+ return mApi;
+ }
+
+ if (mPendingConfig.size == sizeof(GnssConfig)) {
+ // we have pending GnssConfig
+ mApi->gnssConfigurationUpdate(mPendingConfig);
+ // clear size to invalid mPendingConfig
+ mPendingConfig.size = 0;
+ if (mPendingConfig.assistanceServer.hostName != nullptr) {
+ free((void*)mPendingConfig.assistanceServer.hostName);
+ }
+ }
+ }
+ if (mApi == nullptr) {
+ LOC_LOGW("%s] GnssAPIClient is not ready", __FUNCTION__);
+ }
+ return mApi;
+}
+
+const GnssInterface* Gnss::getGnssInterface() {
+ static bool getGnssInterfaceFailed = false;
+ if (nullptr == mGnssInterface && !getGnssInterfaceFailed) {
+ LOC_LOGD("%s]: loading libgnss.so::getGnssInterface ...", __func__);
+ getLocationInterface* getter = NULL;
+ const char *error = NULL;
+ dlerror();
+ void *handle = dlopen("libgnss.so", RTLD_NOW);
+ if (NULL == handle || (error = dlerror()) != NULL) {
+ LOC_LOGW("dlopen for libgnss.so failed, error = %s", error);
+ } else {
+ getter = (getLocationInterface*)dlsym(handle, "getGnssInterface");
+ if ((error = dlerror()) != NULL) {
+ LOC_LOGW("dlsym for libgnss.so::getGnssInterface failed, error = %s", error);
+ getter = NULL;
+ }
+ }
+
+ if (NULL == getter) {
+ getGnssInterfaceFailed = true;
+ } else {
+ mGnssInterface = (const GnssInterface*)(*getter)();
+ }
+ }
+ return mGnssInterface;
+}
+
+Return<bool> Gnss::setCallback(const sp<V1_0::IGnssCallback>& callback) {
+ ENTRY_LOG_CALLFLOW();
+ if (mGnssCbIface != nullptr) {
+ mGnssCbIface->unlinkToDeath(mGnssDeathRecipient);
+ }
+ mGnssCbIface = callback;
+ if (mGnssCbIface != nullptr) {
+ mGnssCbIface->linkToDeath(mGnssDeathRecipient, 0 /*cookie*/);
+ }
+
+ GnssAPIClient* api = getApi();
+ if (api != nullptr) {
+ api->gnssUpdateCallbacks(mGnssCbIface, mGnssNiCbIface);
+ api->gnssEnable(LOCATION_TECHNOLOGY_TYPE_GNSS);
+ api->requestCapabilities();
+ }
+ return true;
+}
+
+Return<bool> Gnss::setGnssNiCb(const sp<IGnssNiCallback>& callback) {
+ ENTRY_LOG_CALLFLOW();
+ mGnssNiCbIface = callback;
+ GnssAPIClient* api = getApi();
+ if (api != nullptr) {
+ api->gnssUpdateCallbacks(mGnssCbIface, mGnssNiCbIface);
+ }
+ return true;
+}
+
+Return<bool> Gnss::updateConfiguration(GnssConfig& gnssConfig) {
+ ENTRY_LOG_CALLFLOW();
+ GnssAPIClient* api = getApi();
+ if (api) {
+ api->gnssConfigurationUpdate(gnssConfig);
+ } else if (gnssConfig.flags != 0) {
+ // api is not ready yet, update mPendingConfig with gnssConfig
+ mPendingConfig.size = sizeof(GnssConfig);
+
+ if (gnssConfig.flags & GNSS_CONFIG_FLAGS_GPS_LOCK_VALID_BIT) {
+ mPendingConfig.flags |= GNSS_CONFIG_FLAGS_GPS_LOCK_VALID_BIT;
+ mPendingConfig.gpsLock = gnssConfig.gpsLock;
+ }
+ if (gnssConfig.flags & GNSS_CONFIG_FLAGS_SUPL_VERSION_VALID_BIT) {
+ mPendingConfig.flags |= GNSS_CONFIG_FLAGS_SUPL_VERSION_VALID_BIT;
+ mPendingConfig.suplVersion = gnssConfig.suplVersion;
+ }
+ if (gnssConfig.flags & GNSS_CONFIG_FLAGS_SET_ASSISTANCE_DATA_VALID_BIT) {
+ mPendingConfig.flags |= GNSS_CONFIG_FLAGS_SET_ASSISTANCE_DATA_VALID_BIT;
+ mPendingConfig.assistanceServer.size = sizeof(GnssConfigSetAssistanceServer);
+ mPendingConfig.assistanceServer.type = gnssConfig.assistanceServer.type;
+ if (mPendingConfig.assistanceServer.hostName != nullptr) {
+ free((void*)mPendingConfig.assistanceServer.hostName);
+ mPendingConfig.assistanceServer.hostName =
+ strdup(gnssConfig.assistanceServer.hostName);
+ }
+ mPendingConfig.assistanceServer.port = gnssConfig.assistanceServer.port;
+ }
+ if (gnssConfig.flags & GNSS_CONFIG_FLAGS_LPP_PROFILE_VALID_BIT) {
+ mPendingConfig.flags |= GNSS_CONFIG_FLAGS_LPP_PROFILE_VALID_BIT;
+ mPendingConfig.lppProfile = gnssConfig.lppProfile;
+ }
+ if (gnssConfig.flags & GNSS_CONFIG_FLAGS_LPPE_CONTROL_PLANE_VALID_BIT) {
+ mPendingConfig.flags |= GNSS_CONFIG_FLAGS_LPPE_CONTROL_PLANE_VALID_BIT;
+ mPendingConfig.lppeControlPlaneMask = gnssConfig.lppeControlPlaneMask;
+ }
+ if (gnssConfig.flags & GNSS_CONFIG_FLAGS_LPPE_USER_PLANE_VALID_BIT) {
+ mPendingConfig.flags |= GNSS_CONFIG_FLAGS_LPPE_USER_PLANE_VALID_BIT;
+ mPendingConfig.lppeUserPlaneMask = gnssConfig.lppeUserPlaneMask;
+ }
+ if (gnssConfig.flags & GNSS_CONFIG_FLAGS_AGLONASS_POSITION_PROTOCOL_VALID_BIT) {
+ mPendingConfig.flags |= GNSS_CONFIG_FLAGS_AGLONASS_POSITION_PROTOCOL_VALID_BIT;
+ mPendingConfig.aGlonassPositionProtocolMask = gnssConfig.aGlonassPositionProtocolMask;
+ }
+ if (gnssConfig.flags & GNSS_CONFIG_FLAGS_EM_PDN_FOR_EM_SUPL_VALID_BIT) {
+ mPendingConfig.flags |= GNSS_CONFIG_FLAGS_EM_PDN_FOR_EM_SUPL_VALID_BIT;
+ mPendingConfig.emergencyPdnForEmergencySupl = gnssConfig.emergencyPdnForEmergencySupl;
+ }
+ if (gnssConfig.flags & GNSS_CONFIG_FLAGS_SUPL_EM_SERVICES_BIT) {
+ mPendingConfig.flags |= GNSS_CONFIG_FLAGS_SUPL_EM_SERVICES_BIT;
+ mPendingConfig.suplEmergencyServices = gnssConfig.suplEmergencyServices;
+ }
+ if (gnssConfig.flags & GNSS_CONFIG_FLAGS_SUPL_MODE_BIT) {
+ mPendingConfig.flags |= GNSS_CONFIG_FLAGS_SUPL_MODE_BIT;
+ mPendingConfig.suplModeMask = gnssConfig.suplModeMask;
+ }
+ if (gnssConfig.flags & GNSS_CONFIG_FLAGS_BLACKLISTED_SV_IDS_BIT) {
+ mPendingConfig.flags |= GNSS_CONFIG_FLAGS_BLACKLISTED_SV_IDS_BIT;
+ mPendingConfig.blacklistedSvIds = gnssConfig.blacklistedSvIds;
+ }
+ }
+ return true;
+}
+
+Return<bool> Gnss::start() {
+ ENTRY_LOG_CALLFLOW();
+ bool retVal = false;
+ GnssAPIClient* api = getApi();
+ if (api) {
+ retVal = api->gnssStart();
+ }
+ return retVal;
+}
+
+Return<bool> Gnss::stop() {
+ ENTRY_LOG_CALLFLOW();
+ bool retVal = false;
+ GnssAPIClient* api = getApi();
+ if (api) {
+ retVal = api->gnssStop();
+ }
+ return retVal;
+}
+
+Return<void> Gnss::cleanup() {
+ ENTRY_LOG_CALLFLOW();
+
+ if (mApi != nullptr) {
+ mApi->gnssDisable();
+ }
+
+ return Void();
+}
+
+Return<bool> Gnss::injectLocation(double latitudeDegrees,
+ double longitudeDegrees,
+ float accuracyMeters) {
+ ENTRY_LOG_CALLFLOW();
+ const GnssInterface* gnssInterface = getGnssInterface();
+ if (nullptr != gnssInterface) {
+ gnssInterface->injectLocation(latitudeDegrees, longitudeDegrees, accuracyMeters);
+ return true;
+ } else {
+ return false;
+ }
+}
+
+Return<bool> Gnss::injectTime(int64_t timeMs, int64_t timeReferenceMs,
+ int32_t uncertaintyMs) {
+ ENTRY_LOG_CALLFLOW();
+ const GnssInterface* gnssInterface = getGnssInterface();
+ if (nullptr != gnssInterface) {
+ gnssInterface->injectTime(timeMs, timeReferenceMs, uncertaintyMs);
+ return true;
+ } else {
+ return false;
+ }
+}
+
+Return<void> Gnss::deleteAidingData(V1_0::IGnss::GnssAidingData aidingDataFlags) {
+ ENTRY_LOG_CALLFLOW();
+ GnssAPIClient* api = getApi();
+ if (api) {
+ api->gnssDeleteAidingData(aidingDataFlags);
+ }
+ return Void();
+}
+
+Return<bool> Gnss::setPositionMode(V1_0::IGnss::GnssPositionMode mode,
+ V1_0::IGnss::GnssPositionRecurrence recurrence,
+ uint32_t minIntervalMs,
+ uint32_t preferredAccuracyMeters,
+ uint32_t preferredTimeMs) {
+ ENTRY_LOG_CALLFLOW();
+ bool retVal = false;
+ GnssAPIClient* api = getApi();
+ if (api) {
+ retVal = api->gnssSetPositionMode(mode, recurrence, minIntervalMs,
+ preferredAccuracyMeters, preferredTimeMs);
+ }
+ return retVal;
+}
+
+Return<sp<V1_0::IAGnss>> Gnss::getExtensionAGnss() {
+ ENTRY_LOG_CALLFLOW();
+ mAGnssIface = new AGnss(this);
+ return mAGnssIface;
+}
+
+Return<sp<V1_0::IGnssNi>> Gnss::getExtensionGnssNi() {
+ ENTRY_LOG_CALLFLOW();
+ mGnssNi = new GnssNi(this);
+ return mGnssNi;
+}
+
+Return<sp<V1_0::IGnssMeasurement>> Gnss::getExtensionGnssMeasurement() {
+ ENTRY_LOG_CALLFLOW();
+ if (mGnssMeasurement == nullptr)
+ mGnssMeasurement = new GnssMeasurement();
+ return mGnssMeasurement;
+}
+
+Return<sp<V1_0::IGnssConfiguration>> Gnss::getExtensionGnssConfiguration() {
+ ENTRY_LOG_CALLFLOW();
+ mGnssConfig = new GnssConfiguration(this);
+ return mGnssConfig;
+}
+
+Return<sp<V1_0::IGnssGeofencing>> Gnss::getExtensionGnssGeofencing() {
+ ENTRY_LOG_CALLFLOW();
+ mGnssGeofencingIface = new GnssGeofencing();
+ return mGnssGeofencingIface;
+}
+
+Return<sp<V1_0::IGnssBatching>> Gnss::getExtensionGnssBatching() {
+ mGnssBatching = new GnssBatching();
+ return mGnssBatching;
+}
+
+Return<sp<V1_0::IGnssDebug>> Gnss::getExtensionGnssDebug() {
+ ENTRY_LOG_CALLFLOW();
+ mGnssDebug = new GnssDebug(this);
+ return mGnssDebug;
+}
+
+Return<sp<V1_0::IAGnssRil>> Gnss::getExtensionAGnssRil() {
+ mGnssRil = new AGnssRil(this);
+ return mGnssRil;
+}
+
+IGnss* HIDL_FETCH_IGnss(const char* hal) {
+ ENTRY_LOG_CALLFLOW();
+ IGnss* iface = nullptr;
+ iface = new Gnss();
+ if (iface == nullptr) {
+ LOC_LOGE("%s]: failed to get %s", __FUNCTION__, hal);
+ }
+ return iface;
+}
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace gnss
+} // namespace hardware
+} // namespace android
diff --git a/android/1.0/Gnss.h b/android/1.0/Gnss.h
new file mode 100644
index 0000000..900a510
--- /dev/null
+++ b/android/1.0/Gnss.h
@@ -0,0 +1,143 @@
+/*
+ * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
+ * Not a Contribution
+ */
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HARDWARE_GNSS_V1_0_GNSS_H
+#define ANDROID_HARDWARE_GNSS_V1_0_GNSS_H
+
+#include <AGnss.h>
+#include <AGnssRil.h>
+#include <GnssBatching.h>
+#include <GnssConfiguration.h>
+#include <GnssGeofencing.h>
+#include <GnssMeasurement.h>
+#include <GnssNi.h>
+#include <GnssDebug.h>
+
+#include <android/hardware/gnss/1.0/IGnss.h>
+#include <hidl/MQDescriptor.h>
+#include <hidl/Status.h>
+
+#include <GnssAPIClient.h>
+#include <location_interface.h>
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace V1_0 {
+namespace implementation {
+
+using ::android::hardware::hidl_array;
+using ::android::hardware::hidl_memory;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::sp;
+using ::android::hardware::gnss::V1_0::GnssLocation;
+
+struct Gnss : public IGnss {
+ Gnss();
+ ~Gnss();
+
+ /*
+ * Methods from ::android::hardware::gnss::V1_0::IGnss follow.
+ * These declarations were generated from Gnss.hal.
+ */
+ Return<bool> setCallback(const sp<V1_0::IGnssCallback>& callback) override;
+ Return<bool> start() override;
+ Return<bool> stop() override;
+ Return<void> cleanup() override;
+ Return<bool> injectLocation(double latitudeDegrees,
+ double longitudeDegrees,
+ float accuracyMeters) override;
+ Return<bool> injectTime(int64_t timeMs,
+ int64_t timeReferenceMs,
+ int32_t uncertaintyMs) override;
+ Return<void> deleteAidingData(V1_0::IGnss::GnssAidingData aidingDataFlags) override;
+ Return<bool> setPositionMode(V1_0::IGnss::GnssPositionMode mode,
+ V1_0::IGnss::GnssPositionRecurrence recurrence,
+ uint32_t minIntervalMs,
+ uint32_t preferredAccuracyMeters,
+ uint32_t preferredTimeMs) override;
+ Return<sp<V1_0::IAGnss>> getExtensionAGnss() override;
+ Return<sp<V1_0::IGnssNi>> getExtensionGnssNi() override;
+ Return<sp<V1_0::IGnssMeasurement>> getExtensionGnssMeasurement() override;
+ Return<sp<V1_0::IGnssConfiguration>> getExtensionGnssConfiguration() override;
+ Return<sp<V1_0::IGnssGeofencing>> getExtensionGnssGeofencing() override;
+ Return<sp<V1_0::IGnssBatching>> getExtensionGnssBatching() override;
+
+ Return<sp<V1_0::IAGnssRil>> getExtensionAGnssRil() override;
+
+ inline Return<sp<V1_0::IGnssNavigationMessage>> getExtensionGnssNavigationMessage() override {
+ return nullptr;
+ }
+
+ inline Return<sp<V1_0::IGnssXtra>> getExtensionXtra() override {
+ return nullptr;
+ }
+
+ Return<sp<V1_0::IGnssDebug>> getExtensionGnssDebug() override;
+
+ // These methods are not part of the IGnss base class.
+ GnssAPIClient* getApi();
+ Return<bool> setGnssNiCb(const sp<IGnssNiCallback>& niCb);
+ Return<bool> updateConfiguration(GnssConfig& gnssConfig);
+ const GnssInterface* getGnssInterface();
+
+ // Callback for ODCPI request
+ void odcpiRequestCb(const OdcpiRequestInfo& request);
+
+ private:
+ struct GnssDeathRecipient : hidl_death_recipient {
+ GnssDeathRecipient(sp<Gnss> gnss) : mGnss(gnss) {
+ }
+ ~GnssDeathRecipient() = default;
+ virtual void serviceDied(uint64_t cookie, const wp<IBase>& who) override;
+ sp<Gnss> mGnss;
+ };
+
+ private:
+ sp<GnssDeathRecipient> mGnssDeathRecipient = nullptr;
+
+ sp<AGnss> mAGnssIface = nullptr;
+ sp<GnssNi> mGnssNi = nullptr;
+ sp<GnssMeasurement> mGnssMeasurement = nullptr;
+ sp<GnssConfiguration> mGnssConfig = nullptr;
+ sp<GnssGeofencing> mGnssGeofencingIface = nullptr;
+ sp<GnssBatching> mGnssBatching = nullptr;
+ sp<IGnssDebug> mGnssDebug = nullptr;
+ sp<AGnssRil> mGnssRil = nullptr;
+
+ GnssAPIClient* mApi = nullptr;
+ sp<V1_0::IGnssCallback> mGnssCbIface = nullptr;
+ sp<V1_0::IGnssNiCallback> mGnssNiCbIface = nullptr;
+ GnssConfig mPendingConfig;
+ const GnssInterface* mGnssInterface = nullptr;
+};
+
+extern "C" IGnss* HIDL_FETCH_IGnss(const char* name);
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace gnss
+} // namespace hardware
+} // namespace android
+
+#endif // ANDROID_HARDWARE_GNSS_V1_0_GNSS_H
diff --git a/android/1.0/GnssBatching.cpp b/android/1.0/GnssBatching.cpp
new file mode 100644
index 0000000..3e5a9f4
--- /dev/null
+++ b/android/1.0/GnssBatching.cpp
@@ -0,0 +1,130 @@
+/*
+ * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
+ * Not a Contribution
+ */
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "LocSvc_GnssBatchingInterface"
+
+#include <log_util.h>
+#include <BatchingAPIClient.h>
+#include "GnssBatching.h"
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace V1_0 {
+namespace implementation {
+
+void GnssBatching::GnssBatchingDeathRecipient::serviceDied(
+ uint64_t cookie, const wp<IBase>& who) {
+ LOC_LOGE("%s] service died. cookie: %llu, who: %p",
+ __FUNCTION__, static_cast<unsigned long long>(cookie), &who);
+ if (mGnssBatching != nullptr) {
+ mGnssBatching->stop();
+ mGnssBatching->cleanup();
+ }
+}
+
+GnssBatching::GnssBatching() : mApi(nullptr) {
+ mGnssBatchingDeathRecipient = new GnssBatchingDeathRecipient(this);
+}
+
+GnssBatching::~GnssBatching() {
+ if (mApi != nullptr) {
+ delete mApi;
+ mApi = nullptr;
+ }
+}
+
+
+// Methods from ::android::hardware::gnss::V1_0::IGnssBatching follow.
+Return<bool> GnssBatching::init(const sp<IGnssBatchingCallback>& callback) {
+ if (mApi != nullptr) {
+ LOC_LOGD("%s]: mApi is NOT nullptr, delete it first", __FUNCTION__);
+ delete mApi;
+ mApi = nullptr;
+ }
+
+ mApi = new BatchingAPIClient(callback);
+ if (mApi == nullptr) {
+ LOC_LOGE("%s]: failed to create mApi", __FUNCTION__);
+ return false;
+ }
+
+ if (mGnssBatchingCbIface != nullptr) {
+ mGnssBatchingCbIface->unlinkToDeath(mGnssBatchingDeathRecipient);
+ }
+ mGnssBatchingCbIface = callback;
+ if (mGnssBatchingCbIface != nullptr) {
+ mGnssBatchingCbIface->linkToDeath(mGnssBatchingDeathRecipient, 0 /*cookie*/);
+ }
+
+ return true;
+}
+
+Return<uint16_t> GnssBatching::getBatchSize() {
+ uint16_t ret = 0;
+ if (mApi == nullptr) {
+ LOC_LOGE("%s]: mApi is nullptr", __FUNCTION__);
+ } else {
+ ret = mApi->getBatchSize();
+ }
+ return ret;
+}
+
+Return<bool> GnssBatching::start(const IGnssBatching::Options& options) {
+ bool ret = false;
+ if (mApi == nullptr) {
+ LOC_LOGE("%s]: mApi is nullptr", __FUNCTION__);
+ } else {
+ ret = mApi->startSession(options);
+ }
+ return ret;
+}
+
+Return<void> GnssBatching::flush() {
+ if (mApi == nullptr) {
+ LOC_LOGE("%s]: mApi is nullptr", __FUNCTION__);
+ } else {
+ mApi->flushBatchedLocations();
+ }
+ return Void();
+}
+
+Return<bool> GnssBatching::stop() {
+ bool ret = false;
+ if (mApi == nullptr) {
+ LOC_LOGE("%s]: mApi is nullptr", __FUNCTION__);
+ } else {
+ ret = mApi->stopSession();
+ }
+ return ret;
+}
+
+Return<void> GnssBatching::cleanup() {
+ if (mGnssBatchingCbIface != nullptr) {
+ mGnssBatchingCbIface->unlinkToDeath(mGnssBatchingDeathRecipient);
+ }
+ return Void();
+}
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace gnss
+} // namespace hardware
+} // namespace android
diff --git a/android/1.0/GnssBatching.h b/android/1.0/GnssBatching.h
new file mode 100644
index 0000000..8fab857
--- /dev/null
+++ b/android/1.0/GnssBatching.h
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
+ * Not a Contribution
+ */
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HARDWARE_GNSS_V1_0_GNSSBATCHING_H
+#define ANDROID_HARDWARE_GNSS_V1_0_GNSSBATCHING_H
+
+#include <android/hardware/gnss/1.0/IGnssBatching.h>
+#include <hidl/Status.h>
+
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace V1_0 {
+namespace implementation {
+
+using ::android::hardware::gnss::V1_0::IGnssBatching;
+using ::android::hardware::gnss::V1_0::IGnssBatchingCallback;
+using ::android::hidl::base::V1_0::IBase;
+using ::android::hardware::hidl_array;
+using ::android::hardware::hidl_memory;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::sp;
+
+class BatchingAPIClient;
+struct GnssBatching : public IGnssBatching {
+ GnssBatching();
+ ~GnssBatching();
+
+ // Methods from ::android::hardware::gnss::V1_0::IGnssBatching follow.
+ Return<bool> init(const sp<IGnssBatchingCallback>& callback) override;
+ Return<uint16_t> getBatchSize() override;
+ Return<bool> start(const IGnssBatching::Options& options ) override;
+ Return<void> flush() override;
+ Return<bool> stop() override;
+ Return<void> cleanup() override;
+
+ private:
+ struct GnssBatchingDeathRecipient : hidl_death_recipient {
+ GnssBatchingDeathRecipient(sp<GnssBatching> gnssBatching) :
+ mGnssBatching(gnssBatching) {
+ }
+ ~GnssBatchingDeathRecipient() = default;
+ virtual void serviceDied(uint64_t cookie, const wp<IBase>& who) override;
+ sp<GnssBatching> mGnssBatching;
+ };
+
+ private:
+ sp<GnssBatchingDeathRecipient> mGnssBatchingDeathRecipient = nullptr;
+ sp<IGnssBatchingCallback> mGnssBatchingCbIface = nullptr;
+ BatchingAPIClient* mApi = nullptr;
+};
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace gnss
+} // namespace hardware
+} // namespace android
+
+#endif // ANDROID_HARDWARE_GNSS_V1_0_GNSSBATCHING_H
diff --git a/android/1.0/GnssConfiguration.cpp b/android/1.0/GnssConfiguration.cpp
new file mode 100644
index 0000000..0b62249
--- /dev/null
+++ b/android/1.0/GnssConfiguration.cpp
@@ -0,0 +1,230 @@
+/*
+ * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
+ * Not a Contribution
+ */
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "LocSvc_GnssConfigurationInterface"
+
+#include <log_util.h>
+#include "Gnss.h"
+#include "GnssConfiguration.h"
+#include <android/hardware/gnss/1.0/types.h>
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace V1_0 {
+namespace implementation {
+
+using ::android::hardware::gnss::V1_0::GnssConstellationType;
+
+GnssConfiguration::GnssConfiguration(Gnss* gnss) : mGnss(gnss) {
+}
+
+// Methods from ::android::hardware::gps::V1_0::IGnssConfiguration follow.
+Return<bool> GnssConfiguration::setSuplEs(bool enabled) {
+ if (mGnss == nullptr) {
+ LOC_LOGE("%s]: mGnss is nullptr", __FUNCTION__);
+ return false;
+ }
+
+ GnssConfig config;
+ memset(&config, 0, sizeof(GnssConfig));
+ config.size = sizeof(GnssConfig);
+ config.flags = GNSS_CONFIG_FLAGS_SUPL_EM_SERVICES_BIT;
+ config.suplEmergencyServices = (enabled ?
+ GNSS_CONFIG_SUPL_EMERGENCY_SERVICES_YES :
+ GNSS_CONFIG_SUPL_EMERGENCY_SERVICES_NO);
+
+ return mGnss->updateConfiguration(config);
+}
+
+Return<bool> GnssConfiguration::setSuplVersion(uint32_t version) {
+ if (mGnss == nullptr) {
+ LOC_LOGE("%s]: mGnss is nullptr", __FUNCTION__);
+ return false;
+ }
+
+ GnssConfig config;
+ memset(&config, 0, sizeof(GnssConfig));
+ config.size = sizeof(GnssConfig);
+ config.flags = GNSS_CONFIG_FLAGS_SUPL_VERSION_VALID_BIT;
+ switch (version) {
+ case 0x00020002:
+ config.suplVersion = GNSS_CONFIG_SUPL_VERSION_2_0_2;
+ break;
+ case 0x00020000:
+ config.suplVersion = GNSS_CONFIG_SUPL_VERSION_2_0_0;
+ break;
+ case 0x00010000:
+ config.suplVersion = GNSS_CONFIG_SUPL_VERSION_1_0_0;
+ break;
+ default:
+ LOC_LOGE("%s]: invalid version: 0x%x.", __FUNCTION__, version);
+ return false;
+ break;
+ }
+
+ return mGnss->updateConfiguration(config);
+}
+
+Return<bool> GnssConfiguration::setSuplMode(uint8_t mode) {
+ if (mGnss == nullptr) {
+ LOC_LOGE("%s]: mGnss is nullptr", __FUNCTION__);
+ return false;
+ }
+
+ GnssConfig config;
+ memset(&config, 0, sizeof(GnssConfig));
+ config.size = sizeof(GnssConfig);
+ config.flags = GNSS_CONFIG_FLAGS_SUPL_MODE_BIT;
+ switch (mode) {
+ case 0:
+ config.suplModeMask = 0; // STANDALONE ONLY
+ break;
+ case 1:
+ config.suplModeMask = GNSS_CONFIG_SUPL_MODE_MSB_BIT;
+ break;
+ case 2:
+ config.suplModeMask = GNSS_CONFIG_SUPL_MODE_MSA_BIT;
+ break;
+ case 3:
+ config.suplModeMask = GNSS_CONFIG_SUPL_MODE_MSB_BIT | GNSS_CONFIG_SUPL_MODE_MSA_BIT;
+ break;
+ default:
+ LOC_LOGE("%s]: invalid mode: %d.", __FUNCTION__, mode);
+ return false;
+ break;
+ }
+
+ return mGnss->updateConfiguration(config);
+}
+
+Return<bool> GnssConfiguration::setLppProfile(uint8_t lppProfile) {
+ if (mGnss == nullptr) {
+ LOC_LOGE("%s]: mGnss is nullptr", __FUNCTION__);
+ return false;
+ }
+
+ GnssConfig config;
+ memset(&config, 0, sizeof(GnssConfig));
+ config.size = sizeof(GnssConfig);
+ config.flags = GNSS_CONFIG_FLAGS_LPP_PROFILE_VALID_BIT;
+ switch (lppProfile) {
+ case 0:
+ config.lppProfile = GNSS_CONFIG_LPP_PROFILE_RRLP_ON_LTE;
+ break;
+ case 1:
+ config.lppProfile = GNSS_CONFIG_LPP_PROFILE_USER_PLANE;
+ break;
+ case 2:
+ config.lppProfile = GNSS_CONFIG_LPP_PROFILE_CONTROL_PLANE;
+ break;
+ case 3:
+ config.lppProfile = GNSS_CONFIG_LPP_PROFILE_USER_PLANE_AND_CONTROL_PLANE;
+ break;
+ default:
+ LOC_LOGE("%s]: invalid lppProfile: %d.", __FUNCTION__, lppProfile);
+ return false;
+ break;
+ }
+
+ return mGnss->updateConfiguration(config);
+}
+
+Return<bool> GnssConfiguration::setGlonassPositioningProtocol(uint8_t protocol) {
+ if (mGnss == nullptr) {
+ LOC_LOGE("%s]: mGnss is nullptr", __FUNCTION__);
+ return false;
+ }
+
+ GnssConfig config;
+ memset(&config, 0, sizeof(GnssConfig));
+ config.size = sizeof(GnssConfig);
+
+ config.flags = GNSS_CONFIG_FLAGS_AGLONASS_POSITION_PROTOCOL_VALID_BIT;
+ if (protocol & (1<<0)) {
+ config.aGlonassPositionProtocolMask |= GNSS_CONFIG_RRC_CONTROL_PLANE_BIT;
+ }
+ if (protocol & (1<<1)) {
+ config.aGlonassPositionProtocolMask |= GNSS_CONFIG_RRLP_USER_PLANE_BIT;
+ }
+ if (protocol & (1<<2)) {
+ config.aGlonassPositionProtocolMask |= GNSS_CONFIG_LLP_USER_PLANE_BIT;
+ }
+ if (protocol & (1<<3)) {
+ config.aGlonassPositionProtocolMask |= GNSS_CONFIG_LLP_CONTROL_PLANE_BIT;
+ }
+
+ return mGnss->updateConfiguration(config);
+}
+
+Return<bool> GnssConfiguration::setGpsLock(uint8_t lock) {
+ if (mGnss == nullptr) {
+ LOC_LOGE("%s]: mGnss is nullptr", __FUNCTION__);
+ return false;
+ }
+
+ GnssConfig config;
+ memset(&config, 0, sizeof(GnssConfig));
+ config.size = sizeof(GnssConfig);
+ config.flags = GNSS_CONFIG_FLAGS_GPS_LOCK_VALID_BIT;
+ switch (lock) {
+ case 0:
+ config.gpsLock = GNSS_CONFIG_GPS_LOCK_NONE;
+ break;
+ case 1:
+ config.gpsLock = GNSS_CONFIG_GPS_LOCK_MO;
+ break;
+ case 2:
+ config.gpsLock = GNSS_CONFIG_GPS_LOCK_NI;
+ break;
+ case 3:
+ config.gpsLock = GNSS_CONFIG_GPS_LOCK_MO_AND_NI;
+ break;
+ default:
+ LOC_LOGE("%s]: invalid lock: %d.", __FUNCTION__, lock);
+ return false;
+ break;
+ }
+
+ return mGnss->updateConfiguration(config);
+}
+
+Return<bool> GnssConfiguration::setEmergencySuplPdn(bool enabled) {
+ if (mGnss == nullptr) {
+ LOC_LOGE("%s]: mGnss is nullptr", __FUNCTION__);
+ return false;
+ }
+
+ GnssConfig config;
+ memset(&config, 0, sizeof(GnssConfig));
+ config.size = sizeof(GnssConfig);
+ config.flags = GNSS_CONFIG_FLAGS_EM_PDN_FOR_EM_SUPL_VALID_BIT;
+ config.emergencyPdnForEmergencySupl = (enabled ?
+ GNSS_CONFIG_EMERGENCY_PDN_FOR_EMERGENCY_SUPL_YES :
+ GNSS_CONFIG_EMERGENCY_PDN_FOR_EMERGENCY_SUPL_NO);
+
+ return mGnss->updateConfiguration(config);
+}
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace gnss
+} // namespace hardware
+} // namespace android
diff --git a/android/1.0/GnssConfiguration.h b/android/1.0/GnssConfiguration.h
new file mode 100644
index 0000000..1629e06
--- /dev/null
+++ b/android/1.0/GnssConfiguration.h
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
+ * Not a Contribution
+ */
+
+ /* Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+#ifndef ANDROID_HARDWARE_GNSS_V1_0_GNSSCONFIGURATION_H
+#define ANDROID_HARDWARE_GNSS_V1_0_GNSSCONFIGURATION_H
+
+#include <android/hardware/gnss/1.0/IGnssConfiguration.h>
+#include <hidl/Status.h>
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace V1_0 {
+namespace implementation {
+
+using ::android::hardware::gnss::V1_0::IGnssConfiguration;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::hidl_string;
+using ::android::sp;
+
+/*
+ * Interface for passing GNSS configuration info from platform to HAL.
+ */
+struct Gnss;
+struct GnssConfiguration : public IGnssConfiguration {
+ GnssConfiguration(Gnss* gnss);
+ ~GnssConfiguration() = default;
+
+ /*
+ * Methods from ::android::hardware::gnss::V1_0::IGnssConfiguration follow.
+ * These declarations were generated from IGnssConfiguration.hal.
+ */
+ Return<bool> setSuplVersion(uint32_t version) override;
+ Return<bool> setSuplMode(uint8_t mode) override;
+ Return<bool> setSuplEs(bool enabled) override;
+ Return<bool> setLppProfile(uint8_t lppProfile) override;
+ Return<bool> setGlonassPositioningProtocol(uint8_t protocol) override;
+ Return<bool> setEmergencySuplPdn(bool enable) override;
+ Return<bool> setGpsLock(uint8_t lock) override;
+
+ private:
+ Gnss* mGnss = nullptr;
+};
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace gnss
+} // namespace hardware
+} // namespace android
+
+#endif // ANDROID_HARDWARE_GNSS_V1_0_GNSSCONFIGURATION_H
diff --git a/android/1.0/GnssDebug.cpp b/android/1.0/GnssDebug.cpp
new file mode 100644
index 0000000..ead72e1
--- /dev/null
+++ b/android/1.0/GnssDebug.cpp
@@ -0,0 +1,173 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "LocSvc_GnssDebugInterface"
+
+#include <log/log.h>
+#include <log_util.h>
+#include "Gnss.h"
+#include "GnssDebug.h"
+#include "LocationUtil.h"
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace V1_0 {
+namespace implementation {
+
+using ::android::hardware::hidl_vec;
+
+#define GNSS_DEBUG_UNKNOWN_HORIZONTAL_ACCURACY_METERS (20000000)
+#define GNSS_DEBUG_UNKNOWN_VERTICAL_ACCURACY_METERS (20000)
+#define GNSS_DEBUG_UNKNOWN_SPEED_ACCURACY_PER_SEC (500)
+#define GNSS_DEBUG_UNKNOWN_BEARING_ACCURACY_DEG (180)
+
+#define GNSS_DEBUG_UNKNOWN_UTC_TIME (1483228800000LL) // 1/1/2017 00:00 GMT
+#define GNSS_DEBUG_UNKNOWN_UTC_TIME_UNC (1.57783680E17) // 5 years in ns
+#define GNSS_DEBUG_UNKNOWN_FREQ_UNC_NS_PER_SEC (2.0e5) // ppm
+
+GnssDebug::GnssDebug(Gnss* gnss) : mGnss(gnss)
+{
+}
+
+/*
+ * This methods requests position, time and satellite ephemeris debug information
+ * from the HAL.
+ *
+ * @return void
+*/
+Return<void> GnssDebug::getDebugData(getDebugData_cb _hidl_cb)
+{
+ LOC_LOGD("%s]: ", __func__);
+
+ DebugData data = { };
+
+ if((nullptr == mGnss) || (nullptr == mGnss->getGnssInterface())){
+ LOC_LOGE("GnssDebug - Null GNSS interface");
+ _hidl_cb(data);
+ return Void();
+ }
+
+ // get debug report snapshot via hal interface
+ GnssDebugReport reports = { };
+ mGnss->getGnssInterface()->getDebugReport(reports);
+
+ // location block
+ if (reports.mLocation.mValid) {
+ data.position.valid = true;
+ data.position.latitudeDegrees = reports.mLocation.mLocation.latitude;
+ data.position.longitudeDegrees = reports.mLocation.mLocation.longitude;
+ data.position.altitudeMeters = reports.mLocation.mLocation.altitude;
+
+ data.position.speedMetersPerSec =
+ (double)(reports.mLocation.mLocation.speed);
+ data.position.bearingDegrees =
+ (double)(reports.mLocation.mLocation.bearing);
+ data.position.horizontalAccuracyMeters =
+ (double)(reports.mLocation.mLocation.accuracy);
+ data.position.verticalAccuracyMeters =
+ reports.mLocation.verticalAccuracyMeters;
+ data.position.speedAccuracyMetersPerSecond =
+ reports.mLocation.speedAccuracyMetersPerSecond;
+ data.position.bearingAccuracyDegrees =
+ reports.mLocation.bearingAccuracyDegrees;
+
+ timeval tv_now, tv_report;
+ tv_report.tv_sec = reports.mLocation.mUtcReported.tv_sec;
+ tv_report.tv_usec = reports.mLocation.mUtcReported.tv_nsec / 1000ULL;
+ gettimeofday(&tv_now, NULL);
+ data.position.ageSeconds =
+ (tv_now.tv_sec - tv_report.tv_sec) +
+ (float)((tv_now.tv_usec - tv_report.tv_usec)) / 1000000;
+ }
+ else {
+ data.position.valid = false;
+ }
+
+ if (data.position.horizontalAccuracyMeters <= 0 ||
+ data.position.horizontalAccuracyMeters > GNSS_DEBUG_UNKNOWN_HORIZONTAL_ACCURACY_METERS) {
+ data.position.horizontalAccuracyMeters = GNSS_DEBUG_UNKNOWN_HORIZONTAL_ACCURACY_METERS;
+ }
+ if (data.position.verticalAccuracyMeters <= 0 ||
+ data.position.verticalAccuracyMeters > GNSS_DEBUG_UNKNOWN_VERTICAL_ACCURACY_METERS) {
+ data.position.verticalAccuracyMeters = GNSS_DEBUG_UNKNOWN_VERTICAL_ACCURACY_METERS;
+ }
+ if (data.position.speedAccuracyMetersPerSecond <= 0 ||
+ data.position.speedAccuracyMetersPerSecond > GNSS_DEBUG_UNKNOWN_SPEED_ACCURACY_PER_SEC) {
+ data.position.speedAccuracyMetersPerSecond = GNSS_DEBUG_UNKNOWN_SPEED_ACCURACY_PER_SEC;
+ }
+ if (data.position.bearingAccuracyDegrees <= 0 ||
+ data.position.bearingAccuracyDegrees > GNSS_DEBUG_UNKNOWN_BEARING_ACCURACY_DEG) {
+ data.position.bearingAccuracyDegrees = GNSS_DEBUG_UNKNOWN_BEARING_ACCURACY_DEG;
+ }
+
+ // time block
+ if (reports.mTime.mValid) {
+ data.time.timeEstimate = reports.mTime.timeEstimate;
+ data.time.timeUncertaintyNs = reports.mTime.timeUncertaintyNs;
+ data.time.frequencyUncertaintyNsPerSec =
+ reports.mTime.frequencyUncertaintyNsPerSec;
+ }
+
+ if (data.time.timeEstimate < GNSS_DEBUG_UNKNOWN_UTC_TIME) {
+ data.time.timeEstimate = GNSS_DEBUG_UNKNOWN_UTC_TIME;
+ }
+ if (data.time.timeUncertaintyNs <= 0 ||
+ data.time.timeUncertaintyNs > (float)GNSS_DEBUG_UNKNOWN_UTC_TIME_UNC) {
+ data.time.timeUncertaintyNs = (float)GNSS_DEBUG_UNKNOWN_UTC_TIME_UNC;
+ }
+ if (data.time.frequencyUncertaintyNsPerSec <= 0 ||
+ data.time.frequencyUncertaintyNsPerSec > (float)GNSS_DEBUG_UNKNOWN_FREQ_UNC_NS_PER_SEC) {
+ data.time.frequencyUncertaintyNsPerSec = (float)GNSS_DEBUG_UNKNOWN_FREQ_UNC_NS_PER_SEC;
+ }
+
+ // satellite data block
+ SatelliteData s = { };
+ std::vector<SatelliteData> s_array = { };
+
+ for (uint32_t i=0; i<reports.mSatelliteInfo.size(); i++) {
+ memset(&s, 0, sizeof(s));
+ s.svid = reports.mSatelliteInfo[i].svid;
+ convertGnssConstellationType(
+ reports.mSatelliteInfo[i].constellation, s.constellation);
+ convertGnssEphemerisType(
+ reports.mSatelliteInfo[i].mEphemerisType, s.ephemerisType);
+ convertGnssEphemerisSource(
+ reports.mSatelliteInfo[i].mEphemerisSource, s.ephemerisSource);
+ convertGnssEphemerisHealth(
+ reports.mSatelliteInfo[i].mEphemerisHealth, s.ephemerisHealth);
+
+ s.ephemerisAgeSeconds =
+ reports.mSatelliteInfo[i].ephemerisAgeSeconds;
+ s.serverPredictionIsAvailable =
+ reports.mSatelliteInfo[i].serverPredictionIsAvailable;
+ s.serverPredictionAgeSeconds =
+ reports.mSatelliteInfo[i].serverPredictionAgeSeconds;
+
+ s_array.push_back(s);
+ }
+ data.satelliteDataArray = s_array;
+
+ // callback HIDL with collected debug data
+ _hidl_cb(data);
+ return Void();
+}
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace gnss
+} // namespace hardware
+} // namespace android
diff --git a/android/1.0/GnssDebug.h b/android/1.0/GnssDebug.h
new file mode 100644
index 0000000..a7116cb
--- /dev/null
+++ b/android/1.0/GnssDebug.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HARDWARE_GNSS_V1_0_GNSSDEBUG_H
+#define ANDROID_HARDWARE_GNSS_V1_0_GNSSDEBUG_H
+
+
+#include <android/hardware/gnss/1.0/IGnssDebug.h>
+#include <hidl/Status.h>
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace V1_0 {
+namespace implementation {
+
+using ::android::hardware::gnss::V1_0::IGnssDebug;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::hidl_string;
+using ::android::sp;
+
+/* Interface for GNSS Debug support. */
+struct Gnss;
+struct GnssDebug : public IGnssDebug {
+ GnssDebug(Gnss* gnss);
+ ~GnssDebug() {};
+
+ /*
+ * Methods from ::android::hardware::gnss::V1_0::IGnssDebug follow.
+ * These declarations were generated from IGnssDebug.hal.
+ */
+ Return<void> getDebugData(getDebugData_cb _hidl_cb) override;
+
+private:
+ Gnss* mGnss = nullptr;
+};
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace gnss
+} // namespace hardware
+} // namespace android
+
+#endif // ANDROID_HARDWARE_GNSS_V1_0_GNSSDEBUG_H
diff --git a/android/1.0/GnssGeofencing.cpp b/android/1.0/GnssGeofencing.cpp
new file mode 100644
index 0000000..2a8ff88
--- /dev/null
+++ b/android/1.0/GnssGeofencing.cpp
@@ -0,0 +1,141 @@
+/*
+ * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
+ * Not a Contribution
+ */
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "GnssHal_GnssGeofencing"
+
+#include <log_util.h>
+#include <GeofenceAPIClient.h>
+#include "GnssGeofencing.h"
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace V1_0 {
+namespace implementation {
+
+void GnssGeofencing::GnssGeofencingDeathRecipient::serviceDied(
+ uint64_t cookie, const wp<IBase>& who) {
+ LOC_LOGE("%s] service died. cookie: %llu, who: %p",
+ __FUNCTION__, static_cast<unsigned long long>(cookie), &who);
+ if (mGnssGeofencing != nullptr) {
+ mGnssGeofencing->removeAllGeofences();
+ }
+}
+
+GnssGeofencing::GnssGeofencing() : mApi(nullptr) {
+ mGnssGeofencingDeathRecipient = new GnssGeofencingDeathRecipient(this);
+}
+
+GnssGeofencing::~GnssGeofencing() {
+ if (mApi != nullptr) {
+ delete mApi;
+ mApi = nullptr;
+ }
+}
+
+// Methods from ::android::hardware::gnss::V1_0::IGnssGeofencing follow.
+Return<void> GnssGeofencing::setCallback(const sp<IGnssGeofenceCallback>& callback) {
+ if (mApi != nullptr) {
+ LOC_LOGE("%s]: mApi is NOT nullptr", __FUNCTION__);
+ return Void();
+ }
+
+ mApi = new GeofenceAPIClient(callback);
+ if (mApi == nullptr) {
+ LOC_LOGE("%s]: failed to create mApi", __FUNCTION__);
+ }
+
+ if (mGnssGeofencingCbIface != nullptr) {
+ mGnssGeofencingCbIface->unlinkToDeath(mGnssGeofencingDeathRecipient);
+ }
+ mGnssGeofencingCbIface = callback;
+ if (mGnssGeofencingCbIface != nullptr) {
+ mGnssGeofencingCbIface->linkToDeath(mGnssGeofencingDeathRecipient, 0 /*cookie*/);
+ }
+
+ return Void();
+}
+
+Return<void> GnssGeofencing::addGeofence(
+ int32_t geofenceId,
+ double latitudeDegrees,
+ double longitudeDegrees,
+ double radiusMeters,
+ IGnssGeofenceCallback::GeofenceTransition lastTransition,
+ int32_t monitorTransitions,
+ uint32_t notificationResponsivenessMs,
+ uint32_t unknownTimerMs) {
+ if (mApi == nullptr) {
+ LOC_LOGE("%s]: mApi is nullptr", __FUNCTION__);
+ } else {
+ mApi->geofenceAdd(
+ geofenceId,
+ latitudeDegrees,
+ longitudeDegrees,
+ radiusMeters,
+ static_cast<int32_t>(lastTransition),
+ monitorTransitions,
+ notificationResponsivenessMs,
+ unknownTimerMs);
+ }
+ return Void();
+}
+
+Return<void> GnssGeofencing::pauseGeofence(int32_t geofenceId) {
+ if (mApi == nullptr) {
+ LOC_LOGE("%s]: mApi is nullptr", __FUNCTION__);
+ } else {
+ mApi->geofencePause(geofenceId);
+ }
+ return Void();
+}
+
+Return<void> GnssGeofencing::resumeGeofence(int32_t geofenceId, int32_t monitorTransitions) {
+ if (mApi == nullptr) {
+ LOC_LOGE("%s]: mApi is nullptr", __FUNCTION__);
+ } else {
+ mApi->geofenceResume(geofenceId, monitorTransitions);
+ }
+ return Void();
+}
+
+Return<void> GnssGeofencing::removeGeofence(int32_t geofenceId) {
+ if (mApi == nullptr) {
+ LOC_LOGE("%s]: mApi is nullptr", __FUNCTION__);
+ } else {
+ mApi->geofenceRemove(geofenceId);
+ }
+ return Void();
+}
+
+Return<void> GnssGeofencing::removeAllGeofences() {
+ if (mApi == nullptr) {
+ LOC_LOGD("%s]: mApi is nullptr, do nothing", __FUNCTION__);
+ } else {
+ mApi->geofenceRemoveAll();
+ }
+ return Void();
+}
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace gnss
+} // namespace hardware
+} // namespace android
diff --git a/android/1.0/GnssGeofencing.h b/android/1.0/GnssGeofencing.h
new file mode 100644
index 0000000..db5f9d2
--- /dev/null
+++ b/android/1.0/GnssGeofencing.h
@@ -0,0 +1,91 @@
+/*
+ * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
+ * Not a Contribution
+ */
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HARDWARE_GNSS_V1_0_GNSSGEOFENCING_H
+#define ANDROID_HARDWARE_GNSS_V1_0_GNSSGEOFENCING_H
+
+#include <android/hardware/gnss/1.0/IGnssGeofencing.h>
+#include <hidl/Status.h>
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace V1_0 {
+namespace implementation {
+
+using ::android::hardware::gnss::V1_0::IGnssGeofenceCallback;
+using ::android::hardware::gnss::V1_0::IGnssGeofencing;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::hidl_string;
+using ::android::sp;
+
+class GeofenceAPIClient;
+struct GnssGeofencing : public IGnssGeofencing {
+ GnssGeofencing();
+ ~GnssGeofencing();
+
+ /*
+ * Methods from ::android::hardware::gnss::V1_0::IGnssGeofencing follow.
+ * These declarations were generated from IGnssGeofencing.hal.
+ */
+ Return<void> setCallback(const sp<IGnssGeofenceCallback>& callback) override;
+ Return<void> addGeofence(int32_t geofenceId,
+ double latitudeDegrees,
+ double longitudeDegrees,
+ double radiusMeters,
+ IGnssGeofenceCallback::GeofenceTransition lastTransition,
+ int32_t monitorTransitions,
+ uint32_t notificationResponsivenessMs,
+ uint32_t unknownTimerMs) override;
+
+ Return<void> pauseGeofence(int32_t geofenceId) override;
+ Return<void> resumeGeofence(int32_t geofenceId, int32_t monitorTransitions) override;
+ Return<void> removeGeofence(int32_t geofenceId) override;
+
+ private:
+ // This method is not part of the IGnss base class.
+ // It is called by GnssGeofencingDeathRecipient to remove all geofences added so far.
+ Return<void> removeAllGeofences();
+
+ private:
+ struct GnssGeofencingDeathRecipient : hidl_death_recipient {
+ GnssGeofencingDeathRecipient(sp<GnssGeofencing> gnssGeofencing) :
+ mGnssGeofencing(gnssGeofencing) {
+ }
+ ~GnssGeofencingDeathRecipient() = default;
+ virtual void serviceDied(uint64_t cookie, const wp<IBase>& who) override;
+ sp<GnssGeofencing> mGnssGeofencing;
+ };
+
+ private:
+ sp<GnssGeofencingDeathRecipient> mGnssGeofencingDeathRecipient = nullptr;
+ sp<IGnssGeofenceCallback> mGnssGeofencingCbIface = nullptr;
+ GeofenceAPIClient* mApi = nullptr;
+};
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace gnss
+} // namespace hardware
+} // namespace android
+
+#endif // ANDROID_HARDWARE_GNSS_V1_0_GNSSGEOFENCING_H
diff --git a/android/1.0/GnssMeasurement.cpp b/android/1.0/GnssMeasurement.cpp
new file mode 100644
index 0000000..1c65bd6
--- /dev/null
+++ b/android/1.0/GnssMeasurement.cpp
@@ -0,0 +1,101 @@
+/*
+ * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
+ * Not a Contribution
+ */
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "LocSvc_GnssMeasurementInterface"
+
+#include <log_util.h>
+#include <MeasurementAPIClient.h>
+#include "GnssMeasurement.h"
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace V1_0 {
+namespace implementation {
+
+void GnssMeasurement::GnssMeasurementDeathRecipient::serviceDied(
+ uint64_t cookie, const wp<IBase>& who) {
+ LOC_LOGE("%s] service died. cookie: %llu, who: %p",
+ __FUNCTION__, static_cast<unsigned long long>(cookie), &who);
+ if (mGnssMeasurement != nullptr) {
+ mGnssMeasurement->close();
+ }
+}
+
+GnssMeasurement::GnssMeasurement() {
+ mGnssMeasurementDeathRecipient = new GnssMeasurementDeathRecipient(this);
+ mApi = new MeasurementAPIClient();
+}
+
+GnssMeasurement::~GnssMeasurement() {
+ if (mApi) {
+ delete mApi;
+ mApi = nullptr;
+ }
+}
+
+// Methods from ::android::hardware::gnss::V1_0::IGnssMeasurement follow.
+
+Return<IGnssMeasurement::GnssMeasurementStatus> GnssMeasurement::setCallback(
+ const sp<V1_0::IGnssMeasurementCallback>& callback) {
+
+ Return<IGnssMeasurement::GnssMeasurementStatus> ret =
+ IGnssMeasurement::GnssMeasurementStatus::ERROR_GENERIC;
+ if (mGnssMeasurementCbIface != nullptr) {
+ LOC_LOGE("%s]: GnssMeasurementCallback is already set", __FUNCTION__);
+ return IGnssMeasurement::GnssMeasurementStatus::ERROR_ALREADY_INIT;
+ }
+
+ if (callback == nullptr) {
+ LOC_LOGE("%s]: callback is nullptr", __FUNCTION__);
+ return ret;
+ }
+ if (mApi == nullptr) {
+ LOC_LOGE("%s]: mApi is nullptr", __FUNCTION__);
+ return ret;
+ }
+
+ mGnssMeasurementCbIface = callback;
+ mGnssMeasurementCbIface->linkToDeath(mGnssMeasurementDeathRecipient, 0);
+
+ return mApi->measurementSetCallback(callback);
+
+}
+
+Return<void> GnssMeasurement::close() {
+ if (mApi == nullptr) {
+ LOC_LOGE("%s]: mApi is nullptr", __FUNCTION__);
+ return Void();
+ }
+
+ if (mGnssMeasurementCbIface != nullptr) {
+ mGnssMeasurementCbIface->unlinkToDeath(mGnssMeasurementDeathRecipient);
+ mGnssMeasurementCbIface = nullptr;
+ }
+ mApi->measurementClose();
+
+ return Void();
+}
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace gnss
+} // namespace hardware
+} // namespace android
diff --git a/android/1.0/GnssMeasurement.h b/android/1.0/GnssMeasurement.h
new file mode 100644
index 0000000..4247dbf
--- /dev/null
+++ b/android/1.0/GnssMeasurement.h
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
+ * Not a Contribution
+ */
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HARDWARE_GNSS_V1_0_GNSSMEASUREMENT_H
+#define ANDROID_HARDWARE_GNSS_V1_0_GNSSMEASUREMENT_H
+
+#include <android/hardware/gnss/1.0/IGnssMeasurement.h>
+#include <hidl/MQDescriptor.h>
+#include <hidl/Status.h>
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace V1_0 {
+namespace implementation {
+
+using ::android::hardware::gnss::V1_0::IGnssMeasurement;
+using ::android::hardware::gnss::V1_0::IGnssMeasurementCallback;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::hidl_string;
+using ::android::sp;
+
+class MeasurementAPIClient;
+struct GnssMeasurement : public IGnssMeasurement {
+ GnssMeasurement();
+ ~GnssMeasurement();
+
+ /*
+ * Methods from ::android::hardware::gnss::V1_0::IGnssMeasurement follow.
+ * These declarations were generated from IGnssMeasurement.hal.
+ */
+ Return<GnssMeasurement::GnssMeasurementStatus> setCallback(
+ const sp<V1_0::IGnssMeasurementCallback>& callback) override;
+ Return<void> close() override;
+
+ private:
+ struct GnssMeasurementDeathRecipient : hidl_death_recipient {
+ GnssMeasurementDeathRecipient(sp<GnssMeasurement> gnssMeasurement) :
+ mGnssMeasurement(gnssMeasurement) {
+ }
+ ~GnssMeasurementDeathRecipient() = default;
+ virtual void serviceDied(uint64_t cookie, const wp<IBase>& who) override;
+ sp<GnssMeasurement> mGnssMeasurement;
+ };
+
+ private:
+ sp<GnssMeasurementDeathRecipient> mGnssMeasurementDeathRecipient = nullptr;
+ sp<V1_0::IGnssMeasurementCallback> mGnssMeasurementCbIface = nullptr;
+ MeasurementAPIClient* mApi;
+};
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace gnss
+} // namespace hardware
+} // namespace android
+
+#endif // ANDROID_HARDWARE_GNSS_V1_0_GNSSMEASUREMENT_H
diff --git a/android/1.0/GnssNi.cpp b/android/1.0/GnssNi.cpp
new file mode 100644
index 0000000..d06cc20
--- /dev/null
+++ b/android/1.0/GnssNi.cpp
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
+ * Not a Contribution
+ */
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "LocSvc_GnssNiInterface"
+
+#include <log_util.h>
+#include "Gnss.h"
+#include "GnssNi.h"
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace V1_0 {
+namespace implementation {
+
+void GnssNi::GnssNiDeathRecipient::serviceDied(uint64_t cookie, const wp<IBase>& who) {
+ LOC_LOGE("%s] service died. cookie: %llu, who: %p",
+ __FUNCTION__, static_cast<unsigned long long>(cookie), &who);
+ // we do nothing here
+ // Gnss::GnssDeathRecipient will stop the session
+}
+
+GnssNi::GnssNi(Gnss* gnss) : mGnss(gnss) {
+ mGnssNiDeathRecipient = new GnssNiDeathRecipient(this);
+}
+
+// Methods from ::android::hardware::gnss::V1_0::IGnssNi follow.
+Return<void> GnssNi::setCallback(const sp<IGnssNiCallback>& callback) {
+ if (mGnss == nullptr) {
+ LOC_LOGE("%s]: mGnss is nullptr", __FUNCTION__);
+ return Void();
+ }
+
+ mGnss->setGnssNiCb(callback);
+
+ if (mGnssNiCbIface != nullptr) {
+ mGnssNiCbIface->unlinkToDeath(mGnssNiDeathRecipient);
+ }
+ mGnssNiCbIface = callback;
+ if (mGnssNiCbIface != nullptr) {
+ mGnssNiCbIface->linkToDeath(mGnssNiDeathRecipient, 0 /*cookie*/);
+ }
+
+ return Void();
+}
+
+Return<void> GnssNi::respond(int32_t notifId, IGnssNiCallback::GnssUserResponseType userResponse) {
+ if (mGnss == nullptr) {
+ LOC_LOGE("%s]: mGnss is nullptr", __FUNCTION__);
+ return Void();
+ }
+
+ GnssAPIClient* api = mGnss->getApi();
+ if (api == nullptr) {
+ LOC_LOGE("%s]: api is nullptr", __FUNCTION__);
+ return Void();
+ }
+
+ api->gnssNiRespond(notifId, userResponse);
+
+ return Void();
+}
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace gnss
+} // namespace hardware
+} // namespace android
diff --git a/android/1.0/GnssNi.h b/android/1.0/GnssNi.h
new file mode 100644
index 0000000..90f62d5
--- /dev/null
+++ b/android/1.0/GnssNi.h
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
+ * Not a Contribution
+ */
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HARDWARE_GNSS_V1_0_GNSSNI_H
+#define ANDROID_HARDWARE_GNSS_V1_0_GNSSNI_H
+
+#include <android/hardware/gnss/1.0/IGnssNi.h>
+#include <hidl/Status.h>
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace V1_0 {
+namespace implementation {
+
+using ::android::hardware::gnss::V1_0::IGnssNi;
+using ::android::hardware::gnss::V1_0::IGnssNiCallback;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::hidl_string;
+using ::android::sp;
+
+struct Gnss;
+struct GnssNi : public IGnssNi {
+ GnssNi(Gnss* gnss);
+ ~GnssNi() = default;
+
+ /*
+ * Methods from ::android::hardware::gnss::V1_0::IGnssNi follow.
+ * These declarations were generated from IGnssNi.hal.
+ */
+ Return<void> setCallback(const sp<IGnssNiCallback>& callback) override;
+ Return<void> respond(int32_t notifId,
+ IGnssNiCallback::GnssUserResponseType userResponse) override;
+
+ private:
+ struct GnssNiDeathRecipient : hidl_death_recipient {
+ GnssNiDeathRecipient(sp<GnssNi> gnssNi) : mGnssNi(gnssNi) {
+ }
+ ~GnssNiDeathRecipient() = default;
+ virtual void serviceDied(uint64_t cookie, const wp<IBase>& who) override;
+ sp<GnssNi> mGnssNi;
+ };
+
+ private:
+ sp<GnssNiDeathRecipient> mGnssNiDeathRecipient = nullptr;
+ sp<IGnssNiCallback> mGnssNiCbIface = nullptr;
+ Gnss* mGnss = nullptr;
+};
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace gnss
+} // namespace hardware
+} // namespace android
+
+#endif // ANDROID_HARDWARE_GNSS_V1_0_GNSSNI_H
diff --git a/android/1.0/android.hardware.gnss@1.0-service-qti.rc b/android/1.0/android.hardware.gnss@1.0-service-qti.rc
new file mode 100644
index 0000000..1fbd893
--- /dev/null
+++ b/android/1.0/android.hardware.gnss@1.0-service-qti.rc
@@ -0,0 +1,4 @@
+service gnss_service /vendor/bin/hw/android.hardware.gnss@1.0-service-qti
+ class hal
+ user gps
+ group system gps radio vendor_qti_diag
diff --git a/android/1.0/android.hardware.gnss@1.0-service-qti.xml b/android/1.0/android.hardware.gnss@1.0-service-qti.xml
new file mode 100644
index 0000000..46bcffb
--- /dev/null
+++ b/android/1.0/android.hardware.gnss@1.0-service-qti.xml
@@ -0,0 +1,35 @@
+<!-- Copyright (c) 2019, 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.
+-->
+<manifest version="1.0" type="device">
+ <hal format="hidl">
+ <name>android.hardware.gnss</name>
+ <transport>hwbinder</transport>
+ <fqname>@1.0::IGnss/default</fqname>
+ </hal>
+</manifest>
+
diff --git a/android/1.0/location_api/BatchingAPIClient.cpp b/android/1.0/location_api/BatchingAPIClient.cpp
new file mode 100644
index 0000000..264ab83
--- /dev/null
+++ b/android/1.0/location_api/BatchingAPIClient.cpp
@@ -0,0 +1,196 @@
+/* Copyright (c) 2017-2018, 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_NDEBUG 0
+#define LOG_TAG "LocSvc_BatchingAPIClient"
+
+#include <log_util.h>
+#include <loc_cfg.h>
+
+#include "LocationUtil.h"
+#include "BatchingAPIClient.h"
+
+#include "limits.h"
+
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace V1_0 {
+namespace implementation {
+
+using ::android::hardware::gnss::V1_0::IGnssBatching;
+using ::android::hardware::gnss::V1_0::IGnssBatchingCallback;
+using ::android::hardware::gnss::V1_0::GnssLocation;
+
+static void convertBatchOption(const IGnssBatching::Options& in, LocationOptions& out,
+ LocationCapabilitiesMask mask);
+
+BatchingAPIClient::BatchingAPIClient(const sp<IGnssBatchingCallback>& callback) :
+ LocationAPIClientBase(),
+ mGnssBatchingCbIface(callback),
+ mDefaultId(UINT_MAX),
+ mLocationCapabilitiesMask(0)
+{
+ LOC_LOGD("%s]: (%p)", __FUNCTION__, &callback);
+
+ LocationCallbacks locationCallbacks;
+ memset(&locationCallbacks, 0, sizeof(LocationCallbacks));
+ locationCallbacks.size = sizeof(LocationCallbacks);
+
+ locationCallbacks.trackingCb = nullptr;
+ locationCallbacks.batchingCb = nullptr;
+ if (mGnssBatchingCbIface != nullptr) {
+ locationCallbacks.batchingCb = [this](size_t count, Location* location,
+ BatchingOptions batchOptions) {
+ onBatchingCb(count, location, batchOptions);
+ };
+ }
+ locationCallbacks.geofenceBreachCb = nullptr;
+ locationCallbacks.geofenceStatusCb = nullptr;
+ locationCallbacks.gnssLocationInfoCb = nullptr;
+ locationCallbacks.gnssNiCb = nullptr;
+ locationCallbacks.gnssSvCb = nullptr;
+ locationCallbacks.gnssNmeaCb = nullptr;
+ locationCallbacks.gnssMeasurementsCb = nullptr;
+
+ locAPISetCallbacks(locationCallbacks);
+}
+
+BatchingAPIClient::~BatchingAPIClient()
+{
+ LOC_LOGD("%s]: ()", __FUNCTION__);
+}
+
+int BatchingAPIClient::getBatchSize()
+{
+ LOC_LOGD("%s]: ()", __FUNCTION__);
+ return locAPIGetBatchSize();
+}
+
+int BatchingAPIClient::startSession(const IGnssBatching::Options& opts)
+{
+ LOC_LOGD("%s]: (%lld %d)", __FUNCTION__,
+ static_cast<long long>(opts.periodNanos), static_cast<uint8_t>(opts.flags));
+ int retVal = -1;
+ LocationOptions options;
+ convertBatchOption(opts, options, mLocationCapabilitiesMask);
+ uint32_t mode = 0;
+ if (opts.flags == static_cast<uint8_t>(IGnssBatching::Flag::WAKEUP_ON_FIFO_FULL)) {
+ mode = SESSION_MODE_ON_FULL;
+ }
+ if (locAPIStartSession(mDefaultId, mode, options) == LOCATION_ERROR_SUCCESS) {
+ retVal = 1;
+ }
+ return retVal;
+}
+
+int BatchingAPIClient::updateSessionOptions(const IGnssBatching::Options& opts)
+{
+ LOC_LOGD("%s]: (%lld %d)", __FUNCTION__,
+ static_cast<long long>(opts.periodNanos), static_cast<uint8_t>(opts.flags));
+ int retVal = -1;
+ LocationOptions options;
+ convertBatchOption(opts, options, mLocationCapabilitiesMask);
+
+ uint32_t mode = 0;
+ if (opts.flags == static_cast<uint8_t>(IGnssBatching::Flag::WAKEUP_ON_FIFO_FULL)) {
+ mode = SESSION_MODE_ON_FULL;
+ }
+ if (locAPIUpdateSessionOptions(mDefaultId, mode, options) == LOCATION_ERROR_SUCCESS) {
+ retVal = 1;
+ }
+ return retVal;
+}
+
+int BatchingAPIClient::stopSession()
+{
+ LOC_LOGD("%s]: ", __FUNCTION__);
+ int retVal = -1;
+ if (locAPIStopSession(mDefaultId) == LOCATION_ERROR_SUCCESS) {
+ retVal = 1;
+ }
+ return retVal;
+}
+
+void BatchingAPIClient::getBatchedLocation(int last_n_locations)
+{
+ LOC_LOGD("%s]: (%d)", __FUNCTION__, last_n_locations);
+ locAPIGetBatchedLocations(mDefaultId, last_n_locations);
+}
+
+void BatchingAPIClient::flushBatchedLocations()
+{
+ LOC_LOGD("%s]: ()", __FUNCTION__);
+ locAPIGetBatchedLocations(mDefaultId, SIZE_MAX);
+}
+
+void BatchingAPIClient::onCapabilitiesCb(LocationCapabilitiesMask capabilitiesMask)
+{
+ LOC_LOGD("%s]: (%02x)", __FUNCTION__, capabilitiesMask);
+ mLocationCapabilitiesMask = capabilitiesMask;
+}
+
+void BatchingAPIClient::onBatchingCb(size_t count, Location* location,
+ BatchingOptions /*batchOptions*/)
+{
+ LOC_LOGD("%s]: (count: %zu)", __FUNCTION__, count);
+ if (mGnssBatchingCbIface != nullptr && count > 0) {
+ hidl_vec<GnssLocation> locationVec;
+ locationVec.resize(count);
+ for (size_t i = 0; i < count; i++) {
+ convertGnssLocation(location[i], locationVec[i]);
+ }
+ auto r = mGnssBatchingCbIface->gnssLocationBatchCb(locationVec);
+ if (!r.isOk()) {
+ LOC_LOGE("%s] Error from gnssLocationBatchCb description=%s",
+ __func__, r.description().c_str());
+ }
+ }
+}
+
+static void convertBatchOption(const IGnssBatching::Options& in, LocationOptions& out,
+ LocationCapabilitiesMask mask)
+{
+ memset(&out, 0, sizeof(LocationOptions));
+ out.size = sizeof(LocationOptions);
+ out.minInterval = (uint32_t)(in.periodNanos / 1000000L);
+ out.minDistance = 0;
+ out.mode = GNSS_SUPL_MODE_STANDALONE;
+ if (mask & LOCATION_CAPABILITIES_GNSS_MSA_BIT)
+ out.mode = GNSS_SUPL_MODE_MSA;
+ if (mask & LOCATION_CAPABILITIES_GNSS_MSB_BIT)
+ out.mode = GNSS_SUPL_MODE_MSB;
+}
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace gnss
+} // namespace hardware
+} // namespace android
diff --git a/android/1.0/location_api/BatchingAPIClient.h b/android/1.0/location_api/BatchingAPIClient.h
new file mode 100644
index 0000000..5d64df3
--- /dev/null
+++ b/android/1.0/location_api/BatchingAPIClient.h
@@ -0,0 +1,74 @@
+/* Copyright (c) 2017-2018, 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 BATCHING_API_CLINET_H
+#define BATCHING_API_CLINET_H
+
+#include <android/hardware/gnss/1.0/IGnssBatching.h>
+#include <android/hardware/gnss/1.0/IGnssBatchingCallback.h>
+#include <pthread.h>
+
+#include <LocationAPIClientBase.h>
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace V1_0 {
+namespace implementation {
+
+class BatchingAPIClient : public LocationAPIClientBase
+{
+public:
+ BatchingAPIClient(const sp<V1_0::IGnssBatchingCallback>& callback);
+ ~BatchingAPIClient();
+ int getBatchSize();
+ int startSession(const V1_0::IGnssBatching::Options& options);
+ int updateSessionOptions(const V1_0::IGnssBatching::Options& options);
+ int stopSession();
+ void getBatchedLocation(int last_n_locations);
+ void flushBatchedLocations();
+
+ inline LocationCapabilitiesMask getCapabilities() { return mLocationCapabilitiesMask; }
+
+ // callbacks
+ void onCapabilitiesCb(LocationCapabilitiesMask capabilitiesMask) final;
+ void onBatchingCb(size_t count, Location* location, BatchingOptions batchOptions) final;
+
+private:
+ sp<V1_0::IGnssBatchingCallback> mGnssBatchingCbIface;
+ uint32_t mDefaultId;
+ LocationCapabilitiesMask mLocationCapabilitiesMask;
+};
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace gnss
+} // namespace hardware
+} // namespace android
+#endif // BATCHING_API_CLINET_H
diff --git a/android/1.0/location_api/GeofenceAPIClient.cpp b/android/1.0/location_api/GeofenceAPIClient.cpp
new file mode 100644
index 0000000..774a049
--- /dev/null
+++ b/android/1.0/location_api/GeofenceAPIClient.cpp
@@ -0,0 +1,275 @@
+/* Copyright (c) 2017-2018, 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_NDEBUG 0
+#define LOG_TAG "LocSvc_GeofenceApiClient"
+
+#include <log_util.h>
+#include <loc_cfg.h>
+
+#include "LocationUtil.h"
+#include "GeofenceAPIClient.h"
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace V1_0 {
+namespace implementation {
+
+using ::android::hardware::gnss::V1_0::IGnssGeofenceCallback;
+using ::android::hardware::gnss::V1_0::GnssLocation;
+
+GeofenceAPIClient::GeofenceAPIClient(const sp<IGnssGeofenceCallback>& callback) :
+ LocationAPIClientBase(),
+ mGnssGeofencingCbIface(callback)
+{
+ LOC_LOGD("%s]: (%p)", __FUNCTION__, &callback);
+
+ LocationCallbacks locationCallbacks;
+ memset(&locationCallbacks, 0, sizeof(LocationCallbacks));
+ locationCallbacks.size = sizeof(LocationCallbacks);
+
+ locationCallbacks.trackingCb = nullptr;
+ locationCallbacks.batchingCb = nullptr;
+
+ locationCallbacks.geofenceBreachCb = nullptr;
+ if (mGnssGeofencingCbIface != nullptr) {
+ locationCallbacks.geofenceBreachCb =
+ [this](GeofenceBreachNotification geofenceBreachNotification) {
+ onGeofenceBreachCb(geofenceBreachNotification);
+ };
+
+ locationCallbacks.geofenceStatusCb =
+ [this](GeofenceStatusNotification geofenceStatusNotification) {
+ onGeofenceStatusCb(geofenceStatusNotification);
+ };
+ }
+
+ locationCallbacks.gnssLocationInfoCb = nullptr;
+ locationCallbacks.gnssNiCb = nullptr;
+ locationCallbacks.gnssSvCb = nullptr;
+ locationCallbacks.gnssNmeaCb = nullptr;
+ locationCallbacks.gnssMeasurementsCb = nullptr;
+
+ locAPISetCallbacks(locationCallbacks);
+}
+
+void GeofenceAPIClient::geofenceAdd(uint32_t geofence_id, double latitude, double longitude,
+ double radius_meters, int32_t last_transition, int32_t monitor_transitions,
+ uint32_t notification_responsiveness_ms, uint32_t unknown_timer_ms)
+{
+ LOC_LOGD("%s]: (%d %f %f %f %d %d %d %d)", __FUNCTION__,
+ geofence_id, latitude, longitude, radius_meters,
+ last_transition, monitor_transitions, notification_responsiveness_ms, unknown_timer_ms);
+
+ GeofenceOption options;
+ memset(&options, 0, sizeof(GeofenceOption));
+ options.size = sizeof(GeofenceOption);
+ if (monitor_transitions & IGnssGeofenceCallback::GeofenceTransition::ENTERED)
+ options.breachTypeMask |= GEOFENCE_BREACH_ENTER_BIT;
+ if (monitor_transitions & IGnssGeofenceCallback::GeofenceTransition::EXITED)
+ options.breachTypeMask |= GEOFENCE_BREACH_EXIT_BIT;
+ options.responsiveness = notification_responsiveness_ms;
+
+ GeofenceInfo data;
+ data.size = sizeof(GeofenceInfo);
+ data.latitude = latitude;
+ data.longitude = longitude;
+ data.radius = radius_meters;
+
+ LocationError err = (LocationError)locAPIAddGeofences(1, &geofence_id, &options, &data);
+ if (LOCATION_ERROR_SUCCESS != err) {
+ onAddGeofencesCb(1, &err, &geofence_id);
+ }
+}
+
+void GeofenceAPIClient::geofencePause(uint32_t geofence_id)
+{
+ LOC_LOGD("%s]: (%d)", __FUNCTION__, geofence_id);
+ locAPIPauseGeofences(1, &geofence_id);
+}
+
+void GeofenceAPIClient::geofenceResume(uint32_t geofence_id, int32_t monitor_transitions)
+{
+ LOC_LOGD("%s]: (%d %d)", __FUNCTION__, geofence_id, monitor_transitions);
+ GeofenceBreachTypeMask mask = 0;
+ if (monitor_transitions & IGnssGeofenceCallback::GeofenceTransition::ENTERED)
+ mask |= GEOFENCE_BREACH_ENTER_BIT;
+ if (monitor_transitions & IGnssGeofenceCallback::GeofenceTransition::EXITED)
+ mask |= GEOFENCE_BREACH_EXIT_BIT;
+ locAPIResumeGeofences(1, &geofence_id, &mask);
+}
+
+void GeofenceAPIClient::geofenceRemove(uint32_t geofence_id)
+{
+ LOC_LOGD("%s]: (%d)", __FUNCTION__, geofence_id);
+ locAPIRemoveGeofences(1, &geofence_id);
+}
+
+void GeofenceAPIClient::geofenceRemoveAll()
+{
+ LOC_LOGD("%s]", __FUNCTION__);
+ // TODO locAPIRemoveAllGeofences();
+}
+
+// callbacks
+void GeofenceAPIClient::onGeofenceBreachCb(GeofenceBreachNotification geofenceBreachNotification)
+{
+ LOC_LOGD("%s]: (%zu)", __FUNCTION__, geofenceBreachNotification.count);
+ if (mGnssGeofencingCbIface != nullptr) {
+ for (size_t i = 0; i < geofenceBreachNotification.count; i++) {
+ GnssLocation gnssLocation;
+ convertGnssLocation(geofenceBreachNotification.location, gnssLocation);
+
+ IGnssGeofenceCallback::GeofenceTransition transition;
+ if (geofenceBreachNotification.type == GEOFENCE_BREACH_ENTER)
+ transition = IGnssGeofenceCallback::GeofenceTransition::ENTERED;
+ else if (geofenceBreachNotification.type == GEOFENCE_BREACH_EXIT)
+ transition = IGnssGeofenceCallback::GeofenceTransition::EXITED;
+ else {
+ // continue with other breach if transition is
+ // nether GPS_GEOFENCE_ENTERED nor GPS_GEOFENCE_EXITED
+ continue;
+ }
+
+ auto r = mGnssGeofencingCbIface->gnssGeofenceTransitionCb(
+ geofenceBreachNotification.ids[i], gnssLocation, transition,
+ static_cast<V1_0::GnssUtcTime>(geofenceBreachNotification.timestamp));
+ if (!r.isOk()) {
+ LOC_LOGE("%s] Error from gnssGeofenceTransitionCb description=%s",
+ __func__, r.description().c_str());
+ }
+ }
+ }
+}
+
+void GeofenceAPIClient::onGeofenceStatusCb(GeofenceStatusNotification geofenceStatusNotification)
+{
+ LOC_LOGD("%s]: (%d)", __FUNCTION__, geofenceStatusNotification.available);
+ if (mGnssGeofencingCbIface != nullptr) {
+ IGnssGeofenceCallback::GeofenceAvailability status =
+ IGnssGeofenceCallback::GeofenceAvailability::UNAVAILABLE;
+ if (geofenceStatusNotification.available == GEOFENCE_STATUS_AVAILABILE_YES) {
+ status = IGnssGeofenceCallback::GeofenceAvailability::AVAILABLE;
+ }
+ GnssLocation gnssLocation;
+ memset(&gnssLocation, 0, sizeof(GnssLocation));
+ auto r = mGnssGeofencingCbIface->gnssGeofenceStatusCb(status, gnssLocation);
+ if (!r.isOk()) {
+ LOC_LOGE("%s] Error from gnssGeofenceStatusCb description=%s",
+ __func__, r.description().c_str());
+ }
+ }
+}
+
+void GeofenceAPIClient::onAddGeofencesCb(size_t count, LocationError* errors, uint32_t* ids)
+{
+ LOC_LOGD("%s]: (%zu)", __FUNCTION__, count);
+ if (mGnssGeofencingCbIface != nullptr) {
+ for (size_t i = 0; i < count; i++) {
+ IGnssGeofenceCallback::GeofenceStatus status =
+ IGnssGeofenceCallback::GeofenceStatus::ERROR_GENERIC;
+ if (errors[i] == LOCATION_ERROR_SUCCESS)
+ status = IGnssGeofenceCallback::GeofenceStatus::OPERATION_SUCCESS;
+ else if (errors[i] == LOCATION_ERROR_ID_EXISTS)
+ status = IGnssGeofenceCallback::GeofenceStatus::ERROR_ID_EXISTS;
+ auto r = mGnssGeofencingCbIface->gnssGeofenceAddCb(ids[i], status);
+ if (!r.isOk()) {
+ LOC_LOGE("%s] Error from gnssGeofenceAddCb description=%s",
+ __func__, r.description().c_str());
+ }
+ }
+ }
+}
+
+void GeofenceAPIClient::onRemoveGeofencesCb(size_t count, LocationError* errors, uint32_t* ids)
+{
+ LOC_LOGD("%s]: (%zu)", __FUNCTION__, count);
+ if (mGnssGeofencingCbIface != nullptr) {
+ for (size_t i = 0; i < count; i++) {
+ IGnssGeofenceCallback::GeofenceStatus status =
+ IGnssGeofenceCallback::GeofenceStatus::ERROR_GENERIC;
+ if (errors[i] == LOCATION_ERROR_SUCCESS)
+ status = IGnssGeofenceCallback::GeofenceStatus::OPERATION_SUCCESS;
+ else if (errors[i] == LOCATION_ERROR_ID_UNKNOWN)
+ status = IGnssGeofenceCallback::GeofenceStatus::ERROR_ID_UNKNOWN;
+ auto r = mGnssGeofencingCbIface->gnssGeofenceRemoveCb(ids[i], status);
+ if (!r.isOk()) {
+ LOC_LOGE("%s] Error from gnssGeofenceRemoveCb description=%s",
+ __func__, r.description().c_str());
+ }
+ }
+ }
+}
+
+void GeofenceAPIClient::onPauseGeofencesCb(size_t count, LocationError* errors, uint32_t* ids)
+{
+ LOC_LOGD("%s]: (%zu)", __FUNCTION__, count);
+ if (mGnssGeofencingCbIface != nullptr) {
+ for (size_t i = 0; i < count; i++) {
+ IGnssGeofenceCallback::GeofenceStatus status =
+ IGnssGeofenceCallback::GeofenceStatus::ERROR_GENERIC;
+ if (errors[i] == LOCATION_ERROR_SUCCESS)
+ status = IGnssGeofenceCallback::GeofenceStatus::OPERATION_SUCCESS;
+ else if (errors[i] == LOCATION_ERROR_ID_UNKNOWN)
+ status = IGnssGeofenceCallback::GeofenceStatus::ERROR_ID_UNKNOWN;
+ auto r = mGnssGeofencingCbIface->gnssGeofencePauseCb(ids[i], status);
+ if (!r.isOk()) {
+ LOC_LOGE("%s] Error from gnssGeofencePauseCb description=%s",
+ __func__, r.description().c_str());
+ }
+ }
+ }
+}
+
+void GeofenceAPIClient::onResumeGeofencesCb(size_t count, LocationError* errors, uint32_t* ids)
+{
+ LOC_LOGD("%s]: (%zu)", __FUNCTION__, count);
+ if (mGnssGeofencingCbIface != nullptr) {
+ for (size_t i = 0; i < count; i++) {
+ IGnssGeofenceCallback::GeofenceStatus status =
+ IGnssGeofenceCallback::GeofenceStatus::ERROR_GENERIC;
+ if (errors[i] == LOCATION_ERROR_SUCCESS)
+ status = IGnssGeofenceCallback::GeofenceStatus::OPERATION_SUCCESS;
+ else if (errors[i] == LOCATION_ERROR_ID_UNKNOWN)
+ status = IGnssGeofenceCallback::GeofenceStatus::ERROR_ID_UNKNOWN;
+ auto r = mGnssGeofencingCbIface->gnssGeofenceResumeCb(ids[i], status);
+ if (!r.isOk()) {
+ LOC_LOGE("%s] Error from gnssGeofenceResumeCb description=%s",
+ __func__, r.description().c_str());
+ }
+ }
+ }
+}
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace gnss
+} // namespace hardware
+} // namespace android
diff --git a/android/1.0/location_api/GeofenceAPIClient.h b/android/1.0/location_api/GeofenceAPIClient.h
new file mode 100644
index 0000000..dc99ddd
--- /dev/null
+++ b/android/1.0/location_api/GeofenceAPIClient.h
@@ -0,0 +1,76 @@
+/* Copyright (c) 2017-2018, 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 GEOFENCE_API_CLINET_H
+#define GEOFENCE_API_CLINET_H
+
+
+#include <android/hardware/gnss/1.0/IGnssGeofenceCallback.h>
+#include <LocationAPIClientBase.h>
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace V1_0 {
+namespace implementation {
+
+using ::android::sp;
+
+class GeofenceAPIClient : public LocationAPIClientBase
+{
+public:
+ GeofenceAPIClient(const sp<V1_0::IGnssGeofenceCallback>& callback);
+ virtual ~GeofenceAPIClient() = default;
+
+ void geofenceAdd(uint32_t geofence_id, double latitude, double longitude,
+ double radius_meters, int32_t last_transition, int32_t monitor_transitions,
+ uint32_t notification_responsiveness_ms, uint32_t unknown_timer_ms);
+ void geofencePause(uint32_t geofence_id);
+ void geofenceResume(uint32_t geofence_id, int32_t monitor_transitions);
+ void geofenceRemove(uint32_t geofence_id);
+ void geofenceRemoveAll();
+
+ // callbacks
+ void onGeofenceBreachCb(GeofenceBreachNotification geofenceBreachNotification) final;
+ void onGeofenceStatusCb(GeofenceStatusNotification geofenceStatusNotification) final;
+ void onAddGeofencesCb(size_t count, LocationError* errors, uint32_t* ids) final;
+ void onRemoveGeofencesCb(size_t count, LocationError* errors, uint32_t* ids) final;
+ void onPauseGeofencesCb(size_t count, LocationError* errors, uint32_t* ids) final;
+ void onResumeGeofencesCb(size_t count, LocationError* errors, uint32_t* ids) final;
+
+private:
+ sp<V1_0::IGnssGeofenceCallback> mGnssGeofencingCbIface;
+};
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace gnss
+} // namespace hardware
+} // namespace android
+#endif // GEOFENCE_API_CLINET_H
diff --git a/android/1.0/location_api/GnssAPIClient.cpp b/android/1.0/location_api/GnssAPIClient.cpp
new file mode 100644
index 0000000..b9fe2b2
--- /dev/null
+++ b/android/1.0/location_api/GnssAPIClient.cpp
@@ -0,0 +1,566 @@
+/* Copyright (c) 2017-2019, 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_NDEBUG 0
+#define LOG_TAG "LocSvc_GnssAPIClient"
+#define SINGLE_SHOT_MIN_TRACKING_INTERVAL_MSEC (590 * 60 * 60 * 1000) // 590 hours
+
+#include <log_util.h>
+#include <loc_cfg.h>
+
+#include "LocationUtil.h"
+#include "GnssAPIClient.h"
+#include <LocContext.h>
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace V1_0 {
+namespace implementation {
+
+using ::android::hardware::gnss::V1_0::IGnss;
+using ::android::hardware::gnss::V1_0::IGnssCallback;
+using ::android::hardware::gnss::V1_0::IGnssNiCallback;
+using ::android::hardware::gnss::V1_0::GnssLocation;
+
+static void convertGnssSvStatus(GnssSvNotification& in, IGnssCallback::GnssSvStatus& out);
+
+GnssAPIClient::GnssAPIClient(const sp<IGnssCallback>& gpsCb,
+ const sp<IGnssNiCallback>& niCb) :
+ LocationAPIClientBase(),
+ mGnssCbIface(nullptr),
+ mGnssNiCbIface(nullptr),
+ mControlClient(new LocationAPIControlClient()),
+ mLocationCapabilitiesMask(0),
+ mLocationCapabilitiesCached(false)
+{
+ LOC_LOGD("%s]: (%p %p)", __FUNCTION__, &gpsCb, &niCb);
+
+ // set default LocationOptions.
+ memset(&mTrackingOptions, 0, sizeof(TrackingOptions));
+ mTrackingOptions.size = sizeof(TrackingOptions);
+ mTrackingOptions.minInterval = 1000;
+ mTrackingOptions.minDistance = 0;
+ mTrackingOptions.mode = GNSS_SUPL_MODE_STANDALONE;
+
+ gnssUpdateCallbacks(gpsCb, niCb);
+}
+
+GnssAPIClient::~GnssAPIClient()
+{
+ LOC_LOGD("%s]: ()", __FUNCTION__);
+ if (mControlClient) {
+ delete mControlClient;
+ mControlClient = nullptr;
+ }
+}
+
+// for GpsInterface
+void GnssAPIClient::gnssUpdateCallbacks(const sp<IGnssCallback>& gpsCb,
+ const sp<IGnssNiCallback>& niCb)
+{
+ LOC_LOGD("%s]: (%p %p)", __FUNCTION__, &gpsCb, &niCb);
+
+ mMutex.lock();
+ mGnssCbIface = gpsCb;
+ mGnssNiCbIface = niCb;
+ mMutex.unlock();
+
+ LocationCallbacks locationCallbacks;
+ memset(&locationCallbacks, 0, sizeof(LocationCallbacks));
+ locationCallbacks.size = sizeof(LocationCallbacks);
+
+ locationCallbacks.trackingCb = nullptr;
+ if (mGnssCbIface != nullptr) {
+ locationCallbacks.trackingCb = [this](Location location) {
+ onTrackingCb(location);
+ };
+ }
+
+ locationCallbacks.batchingCb = nullptr;
+ locationCallbacks.geofenceBreachCb = nullptr;
+ locationCallbacks.geofenceStatusCb = nullptr;
+ locationCallbacks.gnssLocationInfoCb = nullptr;
+
+ locationCallbacks.gnssNiCb = nullptr;
+ loc_core::ContextBase* context =
+ loc_core::LocContext::getLocContext(
+ NULL, NULL,
+ loc_core::LocContext::mLocationHalName, false);
+ if (mGnssNiCbIface != nullptr && !context->hasAgpsExtendedCapabilities()) {
+ LOC_LOGD("Registering NI CB");
+ locationCallbacks.gnssNiCb = [this](uint32_t id, GnssNiNotification gnssNiNotification) {
+ onGnssNiCb(id, gnssNiNotification);
+ };
+ }
+
+ locationCallbacks.gnssSvCb = nullptr;
+ if (mGnssCbIface != nullptr) {
+ locationCallbacks.gnssSvCb = [this](GnssSvNotification gnssSvNotification) {
+ onGnssSvCb(gnssSvNotification);
+ };
+ }
+
+ locationCallbacks.gnssNmeaCb = nullptr;
+ if (mGnssCbIface != nullptr) {
+ locationCallbacks.gnssNmeaCb = [this](GnssNmeaNotification gnssNmeaNotification) {
+ onGnssNmeaCb(gnssNmeaNotification);
+ };
+ }
+
+ locationCallbacks.gnssMeasurementsCb = nullptr;
+
+ locAPISetCallbacks(locationCallbacks);
+}
+
+bool GnssAPIClient::gnssStart()
+{
+ LOC_LOGD("%s]: ()", __FUNCTION__);
+ bool retVal = true;
+ locAPIStartTracking(mTrackingOptions);
+ return retVal;
+}
+
+bool GnssAPIClient::gnssStop()
+{
+ LOC_LOGD("%s]: ()", __FUNCTION__);
+ bool retVal = true;
+ locAPIStopTracking();
+ return retVal;
+}
+
+bool GnssAPIClient::gnssSetPositionMode(IGnss::GnssPositionMode mode,
+ IGnss::GnssPositionRecurrence recurrence, uint32_t minIntervalMs,
+ uint32_t preferredAccuracyMeters, uint32_t preferredTimeMs,
+ GnssPowerMode powerMode, uint32_t timeBetweenMeasurement)
+{
+ LOC_LOGD("%s]: (%d %d %d %d %d %d %d)", __FUNCTION__,
+ (int)mode, recurrence, minIntervalMs, preferredAccuracyMeters,
+ preferredTimeMs, (int)powerMode, timeBetweenMeasurement);
+ bool retVal = true;
+ memset(&mTrackingOptions, 0, sizeof(TrackingOptions));
+ mTrackingOptions.size = sizeof(TrackingOptions);
+ mTrackingOptions.minInterval = minIntervalMs;
+ if (IGnss::GnssPositionMode::MS_ASSISTED == mode ||
+ IGnss::GnssPositionRecurrence::RECURRENCE_SINGLE == recurrence) {
+ // We set a very large interval to simulate SINGLE mode. Once we report a fix,
+ // the caller should take the responsibility to stop the session.
+ // For MSA, we always treat it as SINGLE mode.
+ mTrackingOptions.minInterval = SINGLE_SHOT_MIN_TRACKING_INTERVAL_MSEC;
+ }
+ mTrackingOptions.minDistance = preferredAccuracyMeters;
+ if (mode == IGnss::GnssPositionMode::STANDALONE)
+ mTrackingOptions.mode = GNSS_SUPL_MODE_STANDALONE;
+ else if (mode == IGnss::GnssPositionMode::MS_BASED)
+ mTrackingOptions.mode = GNSS_SUPL_MODE_MSB;
+ else if (mode == IGnss::GnssPositionMode::MS_ASSISTED)
+ mTrackingOptions.mode = GNSS_SUPL_MODE_MSA;
+ else {
+ LOC_LOGD("%s]: invalid GnssPositionMode: %d", __FUNCTION__, (int)mode);
+ retVal = false;
+ }
+ if (GNSS_POWER_MODE_INVALID != powerMode) {
+ mTrackingOptions.powerMode = powerMode;
+ mTrackingOptions.tbm = timeBetweenMeasurement;
+ }
+ locAPIUpdateTrackingOptions(mTrackingOptions);
+ return retVal;
+}
+
+// for GpsNiInterface
+void GnssAPIClient::gnssNiRespond(int32_t notifId,
+ IGnssNiCallback::GnssUserResponseType userResponse)
+{
+ LOC_LOGD("%s]: (%d %d)", __FUNCTION__, notifId, static_cast<int>(userResponse));
+ GnssNiResponse data;
+ switch (userResponse) {
+ case IGnssNiCallback::GnssUserResponseType::RESPONSE_ACCEPT:
+ data = GNSS_NI_RESPONSE_ACCEPT;
+ break;
+ case IGnssNiCallback::GnssUserResponseType::RESPONSE_DENY:
+ data = GNSS_NI_RESPONSE_DENY;
+ break;
+ case IGnssNiCallback::GnssUserResponseType::RESPONSE_NORESP:
+ data = GNSS_NI_RESPONSE_NO_RESPONSE;
+ break;
+ default:
+ data = GNSS_NI_RESPONSE_IGNORE;
+ break;
+ }
+
+ locAPIGnssNiResponse(notifId, data);
+}
+
+// these apis using LocationAPIControlClient
+void GnssAPIClient::gnssDeleteAidingData(IGnss::GnssAidingData aidingDataFlags)
+{
+ LOC_LOGD("%s]: (%02hx)", __FUNCTION__, aidingDataFlags);
+ if (mControlClient == nullptr) {
+ return;
+ }
+ GnssAidingData data;
+ memset(&data, 0, sizeof (GnssAidingData));
+ data.sv.svTypeMask = GNSS_AIDING_DATA_SV_TYPE_GPS_BIT |
+ GNSS_AIDING_DATA_SV_TYPE_GLONASS_BIT |
+ GNSS_AIDING_DATA_SV_TYPE_QZSS_BIT |
+ GNSS_AIDING_DATA_SV_TYPE_BEIDOU_BIT |
+ GNSS_AIDING_DATA_SV_TYPE_GALILEO_BIT;
+ data.posEngineMask = STANDARD_POSITIONING_ENGINE;
+
+ if (aidingDataFlags == IGnss::GnssAidingData::DELETE_ALL)
+ data.deleteAll = true;
+ else {
+ if (aidingDataFlags & IGnss::GnssAidingData::DELETE_EPHEMERIS)
+ data.sv.svMask |= GNSS_AIDING_DATA_SV_EPHEMERIS_BIT;
+ if (aidingDataFlags & IGnss::GnssAidingData::DELETE_ALMANAC)
+ data.sv.svMask |= GNSS_AIDING_DATA_SV_ALMANAC_BIT;
+ if (aidingDataFlags & IGnss::GnssAidingData::DELETE_POSITION)
+ data.common.mask |= GNSS_AIDING_DATA_COMMON_POSITION_BIT;
+ if (aidingDataFlags & IGnss::GnssAidingData::DELETE_TIME)
+ data.common.mask |= GNSS_AIDING_DATA_COMMON_TIME_BIT;
+ if (aidingDataFlags & IGnss::GnssAidingData::DELETE_IONO)
+ data.sv.svMask |= GNSS_AIDING_DATA_SV_IONOSPHERE_BIT;
+ if (aidingDataFlags & IGnss::GnssAidingData::DELETE_UTC)
+ data.common.mask |= GNSS_AIDING_DATA_COMMON_UTC_BIT;
+ if (aidingDataFlags & IGnss::GnssAidingData::DELETE_HEALTH)
+ data.sv.svMask |= GNSS_AIDING_DATA_SV_HEALTH_BIT;
+ if (aidingDataFlags & IGnss::GnssAidingData::DELETE_SVDIR)
+ data.sv.svMask |= GNSS_AIDING_DATA_SV_DIRECTION_BIT;
+ if (aidingDataFlags & IGnss::GnssAidingData::DELETE_SVSTEER)
+ data.sv.svMask |= GNSS_AIDING_DATA_SV_STEER_BIT;
+ if (aidingDataFlags & IGnss::GnssAidingData::DELETE_SADATA)
+ data.sv.svMask |= GNSS_AIDING_DATA_SV_SA_DATA_BIT;
+ if (aidingDataFlags & IGnss::GnssAidingData::DELETE_RTI)
+ data.common.mask |= GNSS_AIDING_DATA_COMMON_RTI_BIT;
+ if (aidingDataFlags & IGnss::GnssAidingData::DELETE_CELLDB_INFO)
+ data.common.mask |= GNSS_AIDING_DATA_COMMON_CELLDB_BIT;
+ }
+ mControlClient->locAPIGnssDeleteAidingData(data);
+}
+
+void GnssAPIClient::gnssEnable(LocationTechnologyType techType)
+{
+ LOC_LOGD("%s]: (%0d)", __FUNCTION__, techType);
+ if (mControlClient == nullptr) {
+ return;
+ }
+ mControlClient->locAPIEnable(techType);
+}
+
+void GnssAPIClient::gnssDisable()
+{
+ LOC_LOGD("%s]: ()", __FUNCTION__);
+ if (mControlClient == nullptr) {
+ return;
+ }
+ mControlClient->locAPIDisable();
+}
+
+void GnssAPIClient::gnssConfigurationUpdate(const GnssConfig& gnssConfig)
+{
+ LOC_LOGD("%s]: (%02x)", __FUNCTION__, gnssConfig.flags);
+ if (mControlClient == nullptr) {
+ return;
+ }
+ mControlClient->locAPIGnssUpdateConfig(gnssConfig);
+}
+
+void GnssAPIClient::requestCapabilities() {
+ // only send capablities if it's already cached, otherwise the first time LocationAPI
+ // is initialized, capabilities will be sent by LocationAPI
+ if (mLocationCapabilitiesCached) {
+ onCapabilitiesCb(mLocationCapabilitiesMask);
+ }
+}
+
+// callbacks
+void GnssAPIClient::onCapabilitiesCb(LocationCapabilitiesMask capabilitiesMask)
+{
+ LOC_LOGD("%s]: (%02x)", __FUNCTION__, capabilitiesMask);
+ mLocationCapabilitiesMask = capabilitiesMask;
+ mLocationCapabilitiesCached = true;
+
+ mMutex.lock();
+ auto gnssCbIface(mGnssCbIface);
+ mMutex.unlock();
+
+ if (gnssCbIface != nullptr) {
+ uint32_t data = 0;
+ if ((capabilitiesMask & LOCATION_CAPABILITIES_TIME_BASED_TRACKING_BIT) ||
+ (capabilitiesMask & LOCATION_CAPABILITIES_TIME_BASED_BATCHING_BIT) ||
+ (capabilitiesMask & LOCATION_CAPABILITIES_DISTANCE_BASED_TRACKING_BIT) ||
+ (capabilitiesMask & LOCATION_CAPABILITIES_DISTANCE_BASED_BATCHING_BIT))
+ data |= IGnssCallback::Capabilities::SCHEDULING;
+ if (capabilitiesMask & LOCATION_CAPABILITIES_GEOFENCE_BIT)
+ data |= IGnssCallback::Capabilities::GEOFENCING;
+ if (capabilitiesMask & LOCATION_CAPABILITIES_GNSS_MEASUREMENTS_BIT)
+ data |= IGnssCallback::Capabilities::MEASUREMENTS;
+ if (capabilitiesMask & LOCATION_CAPABILITIES_GNSS_MSB_BIT)
+ data |= IGnssCallback::Capabilities::MSB;
+ if (capabilitiesMask & LOCATION_CAPABILITIES_GNSS_MSA_BIT)
+ data |= IGnssCallback::Capabilities::MSA;
+ auto r = gnssCbIface->gnssSetCapabilitesCb(data);
+ if (!r.isOk()) {
+ LOC_LOGE("%s] Error from gnssSetCapabilitesCb description=%s",
+ __func__, r.description().c_str());
+ }
+ }
+ if (gnssCbIface != nullptr) {
+ IGnssCallback::GnssSystemInfo gnssInfo;
+ if (capabilitiesMask & LOCATION_CAPABILITIES_CONSTELLATION_ENABLEMENT_BIT ||
+ capabilitiesMask & LOCATION_CAPABILITIES_AGPM_BIT) {
+ gnssInfo.yearOfHw = 2018;
+ } else if (capabilitiesMask & LOCATION_CAPABILITIES_DEBUG_NMEA_BIT) {
+ gnssInfo.yearOfHw = 2017;
+ } else if (capabilitiesMask & LOCATION_CAPABILITIES_GNSS_MEASUREMENTS_BIT) {
+ gnssInfo.yearOfHw = 2016;
+ } else {
+ gnssInfo.yearOfHw = 2015;
+ }
+ LOC_LOGV("%s:%d] set_system_info_cb (%d)", __FUNCTION__, __LINE__, gnssInfo.yearOfHw);
+ auto r = gnssCbIface->gnssSetSystemInfoCb(gnssInfo);
+ if (!r.isOk()) {
+ LOC_LOGE("%s] Error from gnssSetSystemInfoCb description=%s",
+ __func__, r.description().c_str());
+ }
+ }
+}
+
+void GnssAPIClient::onTrackingCb(Location location)
+{
+ LOC_LOGD("%s]: (flags: %02x)", __FUNCTION__, location.flags);
+ mMutex.lock();
+ auto gnssCbIface(mGnssCbIface);
+ mMutex.unlock();
+
+ if (gnssCbIface != nullptr) {
+ GnssLocation gnssLocation;
+ convertGnssLocation(location, gnssLocation);
+ auto r = gnssCbIface->gnssLocationCb(gnssLocation);
+ if (!r.isOk()) {
+ LOC_LOGE("%s] Error from gnssLocationCb description=%s",
+ __func__, r.description().c_str());
+ }
+ }
+}
+
+void GnssAPIClient::onGnssNiCb(uint32_t id, GnssNiNotification gnssNiNotification)
+{
+ LOC_LOGD("%s]: (id: %d)", __FUNCTION__, id);
+ mMutex.lock();
+ auto gnssNiCbIface(mGnssNiCbIface);
+ mMutex.unlock();
+
+ if (gnssNiCbIface == nullptr) {
+ LOC_LOGE("%s]: mGnssNiCbIface is nullptr", __FUNCTION__);
+ return;
+ }
+
+ IGnssNiCallback::GnssNiNotification notificationGnss = {};
+
+ notificationGnss.notificationId = id;
+
+ if (gnssNiNotification.type == GNSS_NI_TYPE_VOICE)
+ notificationGnss.niType = IGnssNiCallback::GnssNiType::VOICE;
+ else if (gnssNiNotification.type == GNSS_NI_TYPE_SUPL)
+ notificationGnss.niType = IGnssNiCallback::GnssNiType::UMTS_SUPL;
+ else if (gnssNiNotification.type == GNSS_NI_TYPE_CONTROL_PLANE)
+ notificationGnss.niType = IGnssNiCallback::GnssNiType::UMTS_CTRL_PLANE;
+ else if (gnssNiNotification.type == GNSS_NI_TYPE_EMERGENCY_SUPL)
+ notificationGnss.niType = IGnssNiCallback::GnssNiType::EMERGENCY_SUPL;
+
+ if (gnssNiNotification.options & GNSS_NI_OPTIONS_NOTIFICATION_BIT)
+ notificationGnss.notifyFlags |= IGnssNiCallback::GnssNiNotifyFlags::NEED_NOTIFY;
+ if (gnssNiNotification.options & GNSS_NI_OPTIONS_VERIFICATION_BIT)
+ notificationGnss.notifyFlags |= IGnssNiCallback::GnssNiNotifyFlags::NEED_VERIFY;
+ if (gnssNiNotification.options & GNSS_NI_OPTIONS_PRIVACY_OVERRIDE_BIT)
+ notificationGnss.notifyFlags |= IGnssNiCallback::GnssNiNotifyFlags::PRIVACY_OVERRIDE;
+
+ notificationGnss.timeoutSec = gnssNiNotification.timeout;
+
+ if (gnssNiNotification.timeoutResponse == GNSS_NI_RESPONSE_ACCEPT)
+ notificationGnss.defaultResponse = IGnssNiCallback::GnssUserResponseType::RESPONSE_ACCEPT;
+ else if (gnssNiNotification.timeoutResponse == GNSS_NI_RESPONSE_DENY)
+ notificationGnss.defaultResponse = IGnssNiCallback::GnssUserResponseType::RESPONSE_DENY;
+ else if (gnssNiNotification.timeoutResponse == GNSS_NI_RESPONSE_NO_RESPONSE ||
+ gnssNiNotification.timeoutResponse == GNSS_NI_RESPONSE_IGNORE)
+ notificationGnss.defaultResponse = IGnssNiCallback::GnssUserResponseType::RESPONSE_NORESP;
+
+ notificationGnss.requestorId = gnssNiNotification.requestor;
+
+ notificationGnss.notificationMessage = gnssNiNotification.message;
+
+ if (gnssNiNotification.requestorEncoding == GNSS_NI_ENCODING_TYPE_NONE)
+ notificationGnss.requestorIdEncoding =
+ IGnssNiCallback::GnssNiEncodingType::ENC_NONE;
+ else if (gnssNiNotification.requestorEncoding == GNSS_NI_ENCODING_TYPE_GSM_DEFAULT)
+ notificationGnss.requestorIdEncoding =
+ IGnssNiCallback::GnssNiEncodingType::ENC_SUPL_GSM_DEFAULT;
+ else if (gnssNiNotification.requestorEncoding == GNSS_NI_ENCODING_TYPE_UTF8)
+ notificationGnss.requestorIdEncoding =
+ IGnssNiCallback::GnssNiEncodingType::ENC_SUPL_UTF8;
+ else if (gnssNiNotification.requestorEncoding == GNSS_NI_ENCODING_TYPE_UCS2)
+ notificationGnss.requestorIdEncoding =
+ IGnssNiCallback::GnssNiEncodingType::ENC_SUPL_UCS2;
+
+ if (gnssNiNotification.messageEncoding == GNSS_NI_ENCODING_TYPE_NONE)
+ notificationGnss.notificationIdEncoding =
+ IGnssNiCallback::GnssNiEncodingType::ENC_NONE;
+ else if (gnssNiNotification.messageEncoding == GNSS_NI_ENCODING_TYPE_GSM_DEFAULT)
+ notificationGnss.notificationIdEncoding =
+ IGnssNiCallback::GnssNiEncodingType::ENC_SUPL_GSM_DEFAULT;
+ else if (gnssNiNotification.messageEncoding == GNSS_NI_ENCODING_TYPE_UTF8)
+ notificationGnss.notificationIdEncoding =
+ IGnssNiCallback::GnssNiEncodingType::ENC_SUPL_UTF8;
+ else if (gnssNiNotification.messageEncoding == GNSS_NI_ENCODING_TYPE_UCS2)
+ notificationGnss.notificationIdEncoding =
+ IGnssNiCallback::GnssNiEncodingType::ENC_SUPL_UCS2;
+
+ gnssNiCbIface->niNotifyCb(notificationGnss);
+}
+
+void GnssAPIClient::onGnssSvCb(GnssSvNotification gnssSvNotification)
+{
+ LOC_LOGD("%s]: (count: %zu)", __FUNCTION__, gnssSvNotification.count);
+ mMutex.lock();
+ auto gnssCbIface(mGnssCbIface);
+ mMutex.unlock();
+
+ if (gnssCbIface != nullptr) {
+ IGnssCallback::GnssSvStatus svStatus;
+ convertGnssSvStatus(gnssSvNotification, svStatus);
+ auto r = gnssCbIface->gnssSvStatusCb(svStatus);
+ if (!r.isOk()) {
+ LOC_LOGE("%s] Error from gnssSvStatusCb description=%s",
+ __func__, r.description().c_str());
+ }
+ }
+}
+
+void GnssAPIClient::onGnssNmeaCb(GnssNmeaNotification gnssNmeaNotification)
+{
+ mMutex.lock();
+ auto gnssCbIface(mGnssCbIface);
+ mMutex.unlock();
+
+ if (gnssCbIface != nullptr) {
+ const std::string s(gnssNmeaNotification.nmea);
+ std::stringstream ss(s);
+ std::string each;
+ while(std::getline(ss, each, '\n')) {
+ each += '\n';
+ android::hardware::hidl_string nmeaString;
+ nmeaString.setToExternal(each.c_str(), each.length());
+ auto r = gnssCbIface->gnssNmeaCb(
+ static_cast<V1_0::GnssUtcTime>(gnssNmeaNotification.timestamp), nmeaString);
+ if (!r.isOk()) {
+ LOC_LOGE("%s] Error from gnssNmeaCb nmea=%s length=%zu description=%s", __func__,
+ gnssNmeaNotification.nmea, gnssNmeaNotification.length,
+ r.description().c_str());
+ }
+ }
+ }
+}
+
+void GnssAPIClient::onStartTrackingCb(LocationError error)
+{
+ LOC_LOGD("%s]: (%d)", __FUNCTION__, error);
+ mMutex.lock();
+ auto gnssCbIface(mGnssCbIface);
+ mMutex.unlock();
+
+ if (error == LOCATION_ERROR_SUCCESS && gnssCbIface != nullptr) {
+ auto r = gnssCbIface->gnssStatusCb(IGnssCallback::GnssStatusValue::ENGINE_ON);
+ if (!r.isOk()) {
+ LOC_LOGE("%s] Error from gnssStatusCb ENGINE_ON description=%s",
+ __func__, r.description().c_str());
+ }
+ r = gnssCbIface->gnssStatusCb(IGnssCallback::GnssStatusValue::SESSION_BEGIN);
+ if (!r.isOk()) {
+ LOC_LOGE("%s] Error from gnssStatusCb SESSION_BEGIN description=%s",
+ __func__, r.description().c_str());
+ }
+ }
+}
+
+void GnssAPIClient::onStopTrackingCb(LocationError error)
+{
+ LOC_LOGD("%s]: (%d)", __FUNCTION__, error);
+ mMutex.lock();
+ auto gnssCbIface(mGnssCbIface);
+ mMutex.unlock();
+
+ if (error == LOCATION_ERROR_SUCCESS && gnssCbIface != nullptr) {
+ auto r = gnssCbIface->gnssStatusCb(IGnssCallback::GnssStatusValue::SESSION_END);
+ if (!r.isOk()) {
+ LOC_LOGE("%s] Error from gnssStatusCb SESSION_END description=%s",
+ __func__, r.description().c_str());
+ }
+ r = gnssCbIface->gnssStatusCb(IGnssCallback::GnssStatusValue::ENGINE_OFF);
+ if (!r.isOk()) {
+ LOC_LOGE("%s] Error from gnssStatusCb ENGINE_OFF description=%s",
+ __func__, r.description().c_str());
+ }
+ }
+}
+
+static void convertGnssSvStatus(GnssSvNotification& in, IGnssCallback::GnssSvStatus& out)
+{
+ memset(&out, 0, sizeof(IGnssCallback::GnssSvStatus));
+ out.numSvs = in.count;
+ if (out.numSvs > static_cast<uint32_t>(V1_0::GnssMax::SVS_COUNT)) {
+ LOC_LOGW("%s]: Too many satellites %u. Clamps to %d.",
+ __FUNCTION__, out.numSvs, V1_0::GnssMax::SVS_COUNT);
+ out.numSvs = static_cast<uint32_t>(V1_0::GnssMax::SVS_COUNT);
+ }
+ for (size_t i = 0; i < out.numSvs; i++) {
+ IGnssCallback::GnssSvInfo& info = out.gnssSvList[i];
+ info.svid = in.gnssSvs[i].svId;
+ convertGnssConstellationType(in.gnssSvs[i].type, info.constellation);
+ info.cN0Dbhz = in.gnssSvs[i].cN0Dbhz;
+ info.elevationDegrees = in.gnssSvs[i].elevation;
+ info.azimuthDegrees = in.gnssSvs[i].azimuth;
+ info.carrierFrequencyHz = in.gnssSvs[i].carrierFrequencyHz;
+ info.svFlag = static_cast<uint8_t>(IGnssCallback::GnssSvFlags::NONE);
+ if (in.gnssSvs[i].gnssSvOptionsMask & GNSS_SV_OPTIONS_HAS_EPHEMER_BIT)
+ info.svFlag |= IGnssCallback::GnssSvFlags::HAS_EPHEMERIS_DATA;
+ if (in.gnssSvs[i].gnssSvOptionsMask & GNSS_SV_OPTIONS_HAS_ALMANAC_BIT)
+ info.svFlag |= IGnssCallback::GnssSvFlags::HAS_ALMANAC_DATA;
+ if (in.gnssSvs[i].gnssSvOptionsMask & GNSS_SV_OPTIONS_USED_IN_FIX_BIT)
+ info.svFlag |= IGnssCallback::GnssSvFlags::USED_IN_FIX;
+ if (in.gnssSvs[i].gnssSvOptionsMask & GNSS_SV_OPTIONS_HAS_CARRIER_FREQUENCY_BIT)
+ info.svFlag |= IGnssCallback::GnssSvFlags::HAS_CARRIER_FREQUENCY;
+ }
+}
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace gnss
+} // namespace hardware
+} // namespace android
diff --git a/android/1.0/location_api/GnssAPIClient.h b/android/1.0/location_api/GnssAPIClient.h
new file mode 100644
index 0000000..4e4b4a9
--- /dev/null
+++ b/android/1.0/location_api/GnssAPIClient.h
@@ -0,0 +1,109 @@
+/* Copyright (c) 2017-2018, 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 GNSS_API_CLINET_H
+#define GNSS_API_CLINET_H
+
+
+#include <mutex>
+#include <android/hardware/gnss/1.0/IGnss.h>
+#include <android/hardware/gnss/1.0/IGnssCallback.h>
+#include <android/hardware/gnss/1.0/IGnssNiCallback.h>
+#include <LocationAPIClientBase.h>
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace V1_0 {
+namespace implementation {
+
+using ::android::sp;
+
+class GnssAPIClient : public LocationAPIClientBase
+{
+public:
+ GnssAPIClient(const sp<V1_0::IGnssCallback>& gpsCb,
+ const sp<V1_0::IGnssNiCallback>& niCb);
+ virtual ~GnssAPIClient();
+ GnssAPIClient(const GnssAPIClient&) = delete;
+ GnssAPIClient& operator=(const GnssAPIClient&) = delete;
+
+ // for GpsInterface
+ void gnssUpdateCallbacks(const sp<V1_0::IGnssCallback>& gpsCb,
+ const sp<V1_0::IGnssNiCallback>& niCb);
+ bool gnssStart();
+ bool gnssStop();
+ bool gnssSetPositionMode(V1_0::IGnss::GnssPositionMode mode,
+ V1_0::IGnss::GnssPositionRecurrence recurrence,
+ uint32_t minIntervalMs,
+ uint32_t preferredAccuracyMeters,
+ uint32_t preferredTimeMs,
+ GnssPowerMode powerMode = GNSS_POWER_MODE_INVALID,
+ uint32_t timeBetweenMeasurement = 0);
+
+ // for GpsNiInterface
+ void gnssNiRespond(int32_t notifId, V1_0::IGnssNiCallback::GnssUserResponseType userResponse);
+
+ // these apis using LocationAPIControlClient
+ void gnssDeleteAidingData(V1_0::IGnss::GnssAidingData aidingDataFlags);
+ void gnssEnable(LocationTechnologyType techType);
+ void gnssDisable();
+ void gnssConfigurationUpdate(const GnssConfig& gnssConfig);
+
+ inline LocationCapabilitiesMask gnssGetCapabilities() const {
+ return mLocationCapabilitiesMask;
+ }
+ void requestCapabilities();
+
+ // callbacks we are interested in
+ void onCapabilitiesCb(LocationCapabilitiesMask capabilitiesMask) final;
+ void onTrackingCb(Location location) final;
+ void onGnssNiCb(uint32_t id, GnssNiNotification gnssNiNotification) final;
+ void onGnssSvCb(GnssSvNotification gnssSvNotification) final;
+ void onGnssNmeaCb(GnssNmeaNotification gnssNmeaNotification) final;
+
+ void onStartTrackingCb(LocationError error) final;
+ void onStopTrackingCb(LocationError error) final;
+
+private:
+ sp<V1_0::IGnssCallback> mGnssCbIface;
+ sp<V1_0::IGnssNiCallback> mGnssNiCbIface;
+ std::mutex mMutex;
+ LocationAPIControlClient* mControlClient;
+ LocationCapabilitiesMask mLocationCapabilitiesMask;
+ bool mLocationCapabilitiesCached;
+ TrackingOptions mTrackingOptions;
+};
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace gnss
+} // namespace hardware
+} // namespace android
+#endif // GNSS_API_CLINET_H
diff --git a/android/1.0/location_api/LocationUtil.cpp b/android/1.0/location_api/LocationUtil.cpp
new file mode 100644
index 0000000..102593b
--- /dev/null
+++ b/android/1.0/location_api/LocationUtil.cpp
@@ -0,0 +1,206 @@
+/* Copyright (c) 2017-2018, 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.
+ *
+ */
+
+#include <LocationUtil.h>
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace V1_0 {
+namespace implementation {
+
+using ::android::hardware::gnss::V1_0::GnssLocation;
+using ::android::hardware::gnss::V1_0::GnssConstellationType;
+using ::android::hardware::gnss::V1_0::GnssLocationFlags;
+
+void convertGnssLocation(Location& in, GnssLocation& out)
+{
+ memset(&out, 0, sizeof(GnssLocation));
+ if (in.flags & LOCATION_HAS_LAT_LONG_BIT) {
+ out.gnssLocationFlags |= GnssLocationFlags::HAS_LAT_LONG;
+ out.latitudeDegrees = in.latitude;
+ out.longitudeDegrees = in.longitude;
+ }
+ if (in.flags & LOCATION_HAS_ALTITUDE_BIT) {
+ out.gnssLocationFlags |= GnssLocationFlags::HAS_ALTITUDE;
+ out.altitudeMeters = in.altitude;
+ }
+ if (in.flags & LOCATION_HAS_SPEED_BIT) {
+ out.gnssLocationFlags |= GnssLocationFlags::HAS_SPEED;
+ out.speedMetersPerSec = in.speed;
+ }
+ if (in.flags & LOCATION_HAS_BEARING_BIT) {
+ out.gnssLocationFlags |= GnssLocationFlags::HAS_BEARING;
+ out.bearingDegrees = in.bearing;
+ }
+ if (in.flags & LOCATION_HAS_ACCURACY_BIT) {
+ out.gnssLocationFlags |= GnssLocationFlags::HAS_HORIZONTAL_ACCURACY;
+ out.horizontalAccuracyMeters = in.accuracy;
+ }
+ if (in.flags & LOCATION_HAS_VERTICAL_ACCURACY_BIT) {
+ out.gnssLocationFlags |= GnssLocationFlags::HAS_VERTICAL_ACCURACY;
+ out.verticalAccuracyMeters = in.verticalAccuracy;
+ }
+ if (in.flags & LOCATION_HAS_SPEED_ACCURACY_BIT) {
+ out.gnssLocationFlags |= GnssLocationFlags::HAS_SPEED_ACCURACY;
+ out.speedAccuracyMetersPerSecond = in.speedAccuracy;
+ }
+ if (in.flags & LOCATION_HAS_BEARING_ACCURACY_BIT) {
+ out.gnssLocationFlags |= GnssLocationFlags::HAS_BEARING_ACCURACY;
+ out.bearingAccuracyDegrees = in.bearingAccuracy;
+ }
+
+ out.timestamp = static_cast<V1_0::GnssUtcTime>(in.timestamp);
+}
+
+void convertGnssLocation(const GnssLocation& in, Location& out)
+{
+ memset(&out, 0, sizeof(out));
+ if (in.gnssLocationFlags & GnssLocationFlags::HAS_LAT_LONG) {
+ out.flags |= LOCATION_HAS_LAT_LONG_BIT;
+ out.latitude = in.latitudeDegrees;
+ out.longitude = in.longitudeDegrees;
+ }
+ if (in.gnssLocationFlags & GnssLocationFlags::HAS_ALTITUDE) {
+ out.flags |= LOCATION_HAS_ALTITUDE_BIT;
+ out.altitude = in.altitudeMeters;
+ }
+ if (in.gnssLocationFlags & GnssLocationFlags::HAS_SPEED) {
+ out.flags |= LOCATION_HAS_SPEED_BIT;
+ out.speed = in.speedMetersPerSec;
+ }
+ if (in.gnssLocationFlags & GnssLocationFlags::HAS_BEARING) {
+ out.flags |= LOCATION_HAS_BEARING_BIT;
+ out.bearing = in.bearingDegrees;
+ }
+ if (in.gnssLocationFlags & GnssLocationFlags::HAS_HORIZONTAL_ACCURACY) {
+ out.flags |= LOCATION_HAS_ACCURACY_BIT;
+ out.accuracy = in.horizontalAccuracyMeters;
+ }
+ if (in.gnssLocationFlags & GnssLocationFlags::HAS_VERTICAL_ACCURACY) {
+ out.flags |= LOCATION_HAS_VERTICAL_ACCURACY_BIT;
+ out.verticalAccuracy = in.verticalAccuracyMeters;
+ }
+ if (in.gnssLocationFlags & GnssLocationFlags::HAS_SPEED_ACCURACY) {
+ out.flags |= LOCATION_HAS_SPEED_ACCURACY_BIT;
+ out.speedAccuracy = in.speedAccuracyMetersPerSecond;
+ }
+ if (in.gnssLocationFlags & GnssLocationFlags::HAS_BEARING_ACCURACY) {
+ out.flags |= LOCATION_HAS_BEARING_ACCURACY_BIT;
+ out.bearingAccuracy = in.bearingAccuracyDegrees;
+ }
+
+ out.timestamp = static_cast<uint64_t>(in.timestamp);
+}
+
+void convertGnssConstellationType(GnssSvType& in, GnssConstellationType& out)
+{
+ switch(in) {
+ case GNSS_SV_TYPE_GPS:
+ out = GnssConstellationType::GPS;
+ break;
+ case GNSS_SV_TYPE_SBAS:
+ out = GnssConstellationType::SBAS;
+ break;
+ case GNSS_SV_TYPE_GLONASS:
+ out = GnssConstellationType::GLONASS;
+ break;
+ case GNSS_SV_TYPE_QZSS:
+ out = GnssConstellationType::QZSS;
+ break;
+ case GNSS_SV_TYPE_BEIDOU:
+ out = GnssConstellationType::BEIDOU;
+ break;
+ case GNSS_SV_TYPE_GALILEO:
+ out = GnssConstellationType::GALILEO;
+ break;
+ case GNSS_SV_TYPE_UNKNOWN:
+ default:
+ out = GnssConstellationType::UNKNOWN;
+ break;
+ }
+}
+
+void convertGnssEphemerisType(GnssEphemerisType& in, GnssDebug::SatelliteEphemerisType& out)
+{
+ switch(in) {
+ case GNSS_EPH_TYPE_EPHEMERIS:
+ out = GnssDebug::SatelliteEphemerisType::EPHEMERIS;
+ break;
+ case GNSS_EPH_TYPE_ALMANAC:
+ out = GnssDebug::SatelliteEphemerisType::ALMANAC_ONLY;
+ break;
+ case GNSS_EPH_TYPE_UNKNOWN:
+ default:
+ out = GnssDebug::SatelliteEphemerisType::NOT_AVAILABLE;
+ break;
+ }
+}
+
+void convertGnssEphemerisSource(GnssEphemerisSource& in, GnssDebug::SatelliteEphemerisSource& out)
+{
+ switch(in) {
+ case GNSS_EPH_SOURCE_DEMODULATED:
+ out = GnssDebug::SatelliteEphemerisSource::DEMODULATED;
+ break;
+ case GNSS_EPH_SOURCE_SUPL_PROVIDED:
+ out = GnssDebug::SatelliteEphemerisSource::SUPL_PROVIDED;
+ break;
+ case GNSS_EPH_SOURCE_OTHER_SERVER_PROVIDED:
+ out = GnssDebug::SatelliteEphemerisSource::OTHER_SERVER_PROVIDED;
+ break;
+ case GNSS_EPH_SOURCE_LOCAL:
+ case GNSS_EPH_SOURCE_UNKNOWN:
+ default:
+ out = GnssDebug::SatelliteEphemerisSource::OTHER;
+ break;
+ }
+}
+
+void convertGnssEphemerisHealth(GnssEphemerisHealth& in, GnssDebug::SatelliteEphemerisHealth& out)
+{
+ switch(in) {
+ case GNSS_EPH_HEALTH_GOOD:
+ out = GnssDebug::SatelliteEphemerisHealth::GOOD;
+ break;
+ case GNSS_EPH_HEALTH_BAD:
+ out = GnssDebug::SatelliteEphemerisHealth::BAD;
+ break;
+ case GNSS_EPH_HEALTH_UNKNOWN:
+ default:
+ out = GnssDebug::SatelliteEphemerisHealth::UNKNOWN;
+ break;
+ }
+}
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace gnss
+} // namespace hardware
+} // namespace android
diff --git a/android/1.0/location_api/LocationUtil.h b/android/1.0/location_api/LocationUtil.h
new file mode 100644
index 0000000..9e0cd36
--- /dev/null
+++ b/android/1.0/location_api/LocationUtil.h
@@ -0,0 +1,55 @@
+/* Copyright (c) 2017-2018, 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_UTIL_H
+#define LOCATION_UTIL_H
+
+#include <android/hardware/gnss/1.0/types.h>
+#include <LocationAPI.h>
+#include <GnssDebug.h>
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace V1_0 {
+namespace implementation {
+
+void convertGnssLocation(Location& in, V1_0::GnssLocation& out);
+void convertGnssLocation(const V1_0::GnssLocation& in, Location& out);
+void convertGnssConstellationType(GnssSvType& in, V1_0::GnssConstellationType& out);
+void convertGnssEphemerisType(GnssEphemerisType& in, GnssDebug::SatelliteEphemerisType& out);
+void convertGnssEphemerisSource(GnssEphemerisSource& in, GnssDebug::SatelliteEphemerisSource& out);
+void convertGnssEphemerisHealth(GnssEphemerisHealth& in, GnssDebug::SatelliteEphemerisHealth& out);
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace gnss
+} // namespace hardware
+} // namespace android
+#endif // LOCATION_UTIL_H
diff --git a/android/1.0/location_api/MeasurementAPIClient.cpp b/android/1.0/location_api/MeasurementAPIClient.cpp
new file mode 100644
index 0000000..73709e3
--- /dev/null
+++ b/android/1.0/location_api/MeasurementAPIClient.cpp
@@ -0,0 +1,276 @@
+/* Copyright (c) 2017-2018, 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_NDEBUG 0
+#define LOG_TAG "LocSvc_MeasurementAPIClient"
+
+#include <log_util.h>
+#include <loc_cfg.h>
+
+#include "LocationUtil.h"
+#include "MeasurementAPIClient.h"
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace V1_0 {
+namespace implementation {
+
+using ::android::hardware::gnss::V1_0::IGnssMeasurement;
+using ::android::hardware::gnss::V1_0::IGnssMeasurementCallback;
+
+static void convertGnssData(GnssMeasurementsNotification& in,
+ V1_0::IGnssMeasurementCallback::GnssData& out);
+static void convertGnssMeasurement(GnssMeasurementsData& in,
+ V1_0::IGnssMeasurementCallback::GnssMeasurement& out);
+static void convertGnssClock(GnssMeasurementsClock& in, IGnssMeasurementCallback::GnssClock& out);
+
+MeasurementAPIClient::MeasurementAPIClient() :
+ mGnssMeasurementCbIface(nullptr),
+ mTracking(false)
+{
+ LOC_LOGD("%s]: ()", __FUNCTION__);
+}
+
+MeasurementAPIClient::~MeasurementAPIClient()
+{
+ LOC_LOGD("%s]: ()", __FUNCTION__);
+}
+
+// for GpsInterface
+Return<IGnssMeasurement::GnssMeasurementStatus>
+MeasurementAPIClient::measurementSetCallback(const sp<V1_0::IGnssMeasurementCallback>& callback)
+{
+ LOC_LOGD("%s]: (%p)", __FUNCTION__, &callback);
+
+ mMutex.lock();
+ mGnssMeasurementCbIface = callback;
+ mMutex.unlock();
+
+ return startTracking();
+}
+
+Return<IGnssMeasurement::GnssMeasurementStatus>
+MeasurementAPIClient::startTracking()
+{
+ LocationCallbacks locationCallbacks;
+ memset(&locationCallbacks, 0, sizeof(LocationCallbacks));
+ locationCallbacks.size = sizeof(LocationCallbacks);
+
+ locationCallbacks.trackingCb = nullptr;
+ locationCallbacks.batchingCb = nullptr;
+ locationCallbacks.geofenceBreachCb = nullptr;
+ locationCallbacks.geofenceStatusCb = nullptr;
+ locationCallbacks.gnssLocationInfoCb = nullptr;
+ locationCallbacks.gnssNiCb = nullptr;
+ locationCallbacks.gnssSvCb = nullptr;
+ locationCallbacks.gnssNmeaCb = nullptr;
+
+ locationCallbacks.gnssMeasurementsCb = nullptr;
+ if (mGnssMeasurementCbIface != nullptr) {
+ locationCallbacks.gnssMeasurementsCb =
+ [this](GnssMeasurementsNotification gnssMeasurementsNotification) {
+ onGnssMeasurementsCb(gnssMeasurementsNotification);
+ };
+ }
+
+ locAPISetCallbacks(locationCallbacks);
+
+ TrackingOptions options = {};
+ memset(&options, 0, sizeof(TrackingOptions));
+ options.size = sizeof(TrackingOptions);
+ options.minInterval = 1000;
+ options.mode = GNSS_SUPL_MODE_STANDALONE;
+
+ mTracking = true;
+ LOC_LOGD("%s]: start tracking session", __FUNCTION__);
+ locAPIStartTracking(options);
+ return IGnssMeasurement::GnssMeasurementStatus::SUCCESS;
+}
+
+// for GpsMeasurementInterface
+void MeasurementAPIClient::measurementClose() {
+ LOC_LOGD("%s]: ()", __FUNCTION__);
+ mTracking = false;
+ locAPIStopTracking();
+}
+
+// callbacks
+void MeasurementAPIClient::onGnssMeasurementsCb(
+ GnssMeasurementsNotification gnssMeasurementsNotification)
+{
+ LOC_LOGD("%s]: (count: %zu active: %d)",
+ __FUNCTION__, gnssMeasurementsNotification.count, mTracking);
+ if (mTracking) {
+ mMutex.lock();
+ sp<V1_0::IGnssMeasurementCallback> gnssMeasurementCbIface = nullptr;
+ if (mGnssMeasurementCbIface != nullptr) {
+ gnssMeasurementCbIface = mGnssMeasurementCbIface;
+ }
+ mMutex.unlock();
+
+ if (gnssMeasurementCbIface != nullptr) {
+ V1_0::IGnssMeasurementCallback::GnssData gnssData;
+ convertGnssData(gnssMeasurementsNotification, gnssData);
+ auto r = gnssMeasurementCbIface->GnssMeasurementCb(gnssData);
+ if (!r.isOk()) {
+ LOC_LOGE("%s] Error from GnssMeasurementCb description=%s",
+ __func__, r.description().c_str());
+ }
+ }
+ }
+}
+
+static void convertGnssMeasurement(GnssMeasurementsData& in,
+ V1_0::IGnssMeasurementCallback::GnssMeasurement& out)
+{
+ memset(&out, 0, sizeof(IGnssMeasurementCallback::GnssMeasurement));
+ if (in.flags & GNSS_MEASUREMENTS_DATA_SIGNAL_TO_NOISE_RATIO_BIT)
+ out.flags |= IGnssMeasurementCallback::GnssMeasurementFlags::HAS_SNR;
+ if (in.flags & GNSS_MEASUREMENTS_DATA_CARRIER_FREQUENCY_BIT)
+ out.flags |= IGnssMeasurementCallback::GnssMeasurementFlags::HAS_CARRIER_FREQUENCY;
+ if (in.flags & GNSS_MEASUREMENTS_DATA_CARRIER_CYCLES_BIT)
+ out.flags |= IGnssMeasurementCallback::GnssMeasurementFlags::HAS_CARRIER_CYCLES;
+ if (in.flags & GNSS_MEASUREMENTS_DATA_CARRIER_PHASE_BIT)
+ out.flags |= IGnssMeasurementCallback::GnssMeasurementFlags::HAS_CARRIER_PHASE;
+ if (in.flags & GNSS_MEASUREMENTS_DATA_CARRIER_PHASE_UNCERTAINTY_BIT)
+ out.flags |= IGnssMeasurementCallback::GnssMeasurementFlags::HAS_CARRIER_PHASE_UNCERTAINTY;
+ if (in.flags & GNSS_MEASUREMENTS_DATA_AUTOMATIC_GAIN_CONTROL_BIT)
+ out.flags |= IGnssMeasurementCallback::GnssMeasurementFlags::HAS_AUTOMATIC_GAIN_CONTROL;
+ out.svid = in.svId;
+ convertGnssConstellationType(in.svType, out.constellation);
+ out.timeOffsetNs = in.timeOffsetNs;
+ if (in.stateMask & GNSS_MEASUREMENTS_STATE_CODE_LOCK_BIT)
+ out.state |= IGnssMeasurementCallback::GnssMeasurementState::STATE_CODE_LOCK;
+ if (in.stateMask & GNSS_MEASUREMENTS_STATE_BIT_SYNC_BIT)
+ out.state |= IGnssMeasurementCallback::GnssMeasurementState::STATE_BIT_SYNC;
+ if (in.stateMask & GNSS_MEASUREMENTS_STATE_SUBFRAME_SYNC_BIT)
+ out.state |= IGnssMeasurementCallback::GnssMeasurementState::STATE_SUBFRAME_SYNC;
+ if (in.stateMask & GNSS_MEASUREMENTS_STATE_TOW_DECODED_BIT)
+ out.state |= IGnssMeasurementCallback::GnssMeasurementState::STATE_TOW_DECODED;
+ if (in.stateMask & GNSS_MEASUREMENTS_STATE_MSEC_AMBIGUOUS_BIT)
+ out.state |= IGnssMeasurementCallback::GnssMeasurementState::STATE_MSEC_AMBIGUOUS;
+ if (in.stateMask & GNSS_MEASUREMENTS_STATE_SYMBOL_SYNC_BIT)
+ out.state |= IGnssMeasurementCallback::GnssMeasurementState::STATE_SYMBOL_SYNC;
+ if (in.stateMask & GNSS_MEASUREMENTS_STATE_GLO_STRING_SYNC_BIT)
+ out.state |= IGnssMeasurementCallback::GnssMeasurementState::STATE_GLO_STRING_SYNC;
+ if (in.stateMask & GNSS_MEASUREMENTS_STATE_GLO_TOD_DECODED_BIT)
+ out.state |= IGnssMeasurementCallback::GnssMeasurementState::STATE_GLO_TOD_DECODED;
+ if (in.stateMask & GNSS_MEASUREMENTS_STATE_BDS_D2_BIT_SYNC_BIT)
+ out.state |= IGnssMeasurementCallback::GnssMeasurementState::STATE_BDS_D2_BIT_SYNC;
+ if (in.stateMask & GNSS_MEASUREMENTS_STATE_BDS_D2_SUBFRAME_SYNC_BIT)
+ out.state |= IGnssMeasurementCallback::GnssMeasurementState::STATE_BDS_D2_SUBFRAME_SYNC;
+ if (in.stateMask & GNSS_MEASUREMENTS_STATE_GAL_E1BC_CODE_LOCK_BIT)
+ out.state |= IGnssMeasurementCallback::GnssMeasurementState::STATE_GAL_E1BC_CODE_LOCK;
+ if (in.stateMask & GNSS_MEASUREMENTS_STATE_GAL_E1C_2ND_CODE_LOCK_BIT)
+ out.state |= IGnssMeasurementCallback::GnssMeasurementState::STATE_GAL_E1C_2ND_CODE_LOCK;
+ if (in.stateMask & GNSS_MEASUREMENTS_STATE_GAL_E1B_PAGE_SYNC_BIT)
+ out.state |= IGnssMeasurementCallback::GnssMeasurementState::STATE_GAL_E1B_PAGE_SYNC;
+ if (in.stateMask & GNSS_MEASUREMENTS_STATE_SBAS_SYNC_BIT)
+ out.state |= IGnssMeasurementCallback::GnssMeasurementState::STATE_SBAS_SYNC;
+ out.receivedSvTimeInNs = in.receivedSvTimeNs;
+ out.receivedSvTimeUncertaintyInNs = in.receivedSvTimeUncertaintyNs;
+ out.cN0DbHz = in.carrierToNoiseDbHz;
+ out.pseudorangeRateMps = in.pseudorangeRateMps;
+ out.pseudorangeRateUncertaintyMps = in.pseudorangeRateUncertaintyMps;
+ if (in.adrStateMask & GNSS_MEASUREMENTS_ACCUMULATED_DELTA_RANGE_STATE_VALID_BIT)
+ out.accumulatedDeltaRangeState |=
+ IGnssMeasurementCallback::GnssAccumulatedDeltaRangeState::ADR_STATE_VALID;
+ if (in.adrStateMask & GNSS_MEASUREMENTS_ACCUMULATED_DELTA_RANGE_STATE_RESET_BIT)
+ out.accumulatedDeltaRangeState |=
+ IGnssMeasurementCallback::GnssAccumulatedDeltaRangeState::ADR_STATE_RESET;
+ if (in.adrStateMask & GNSS_MEASUREMENTS_ACCUMULATED_DELTA_RANGE_STATE_CYCLE_SLIP_BIT)
+ out.accumulatedDeltaRangeState |=
+ IGnssMeasurementCallback::GnssAccumulatedDeltaRangeState::ADR_STATE_CYCLE_SLIP;
+ out.accumulatedDeltaRangeM = in.adrMeters;
+ out.accumulatedDeltaRangeUncertaintyM = in.adrUncertaintyMeters;
+ out.carrierFrequencyHz = in.carrierFrequencyHz;
+ out.carrierCycles = in.carrierCycles;
+ out.carrierPhase = in.carrierPhase;
+ out.carrierPhaseUncertainty = in.carrierPhaseUncertainty;
+ uint8_t indicator =
+ static_cast<uint8_t>(IGnssMeasurementCallback::GnssMultipathIndicator::INDICATOR_UNKNOWN);
+ if (in.multipathIndicator & GNSS_MEASUREMENTS_MULTIPATH_INDICATOR_PRESENT)
+ indicator |= IGnssMeasurementCallback::GnssMultipathIndicator::INDICATOR_PRESENT;
+ if (in.multipathIndicator & GNSS_MEASUREMENTS_MULTIPATH_INDICATOR_NOT_PRESENT)
+ indicator |= IGnssMeasurementCallback::GnssMultipathIndicator::INDICATIOR_NOT_PRESENT;
+ out.multipathIndicator =
+ static_cast<IGnssMeasurementCallback::GnssMultipathIndicator>(indicator);
+ out.snrDb = in.signalToNoiseRatioDb;
+ out.agcLevelDb = in.agcLevelDb;
+}
+
+static void convertGnssClock(GnssMeasurementsClock& in, IGnssMeasurementCallback::GnssClock& out)
+{
+ memset(&out, 0, sizeof(IGnssMeasurementCallback::GnssClock));
+ if (in.flags & GNSS_MEASUREMENTS_CLOCK_FLAGS_LEAP_SECOND_BIT)
+ out.gnssClockFlags |= IGnssMeasurementCallback::GnssClockFlags::HAS_LEAP_SECOND;
+ if (in.flags & GNSS_MEASUREMENTS_CLOCK_FLAGS_TIME_UNCERTAINTY_BIT)
+ out.gnssClockFlags |= IGnssMeasurementCallback::GnssClockFlags::HAS_TIME_UNCERTAINTY;
+ if (in.flags & GNSS_MEASUREMENTS_CLOCK_FLAGS_FULL_BIAS_BIT)
+ out.gnssClockFlags |= IGnssMeasurementCallback::GnssClockFlags::HAS_FULL_BIAS;
+ if (in.flags & GNSS_MEASUREMENTS_CLOCK_FLAGS_BIAS_BIT)
+ out.gnssClockFlags |= IGnssMeasurementCallback::GnssClockFlags::HAS_BIAS;
+ if (in.flags & GNSS_MEASUREMENTS_CLOCK_FLAGS_BIAS_UNCERTAINTY_BIT)
+ out.gnssClockFlags |= IGnssMeasurementCallback::GnssClockFlags::HAS_BIAS_UNCERTAINTY;
+ if (in.flags & GNSS_MEASUREMENTS_CLOCK_FLAGS_DRIFT_BIT)
+ out.gnssClockFlags |= IGnssMeasurementCallback::GnssClockFlags::HAS_DRIFT;
+ if (in.flags & GNSS_MEASUREMENTS_CLOCK_FLAGS_DRIFT_UNCERTAINTY_BIT)
+ out.gnssClockFlags |= IGnssMeasurementCallback::GnssClockFlags::HAS_DRIFT_UNCERTAINTY;
+ out.leapSecond = in.leapSecond;
+ out.timeNs = in.timeNs;
+ out.timeUncertaintyNs = in.timeUncertaintyNs;
+ out.fullBiasNs = in.fullBiasNs;
+ out.biasNs = in.biasNs;
+ out.biasUncertaintyNs = in.biasUncertaintyNs;
+ out.driftNsps = in.driftNsps;
+ out.driftUncertaintyNsps = in.driftUncertaintyNsps;
+ out.hwClockDiscontinuityCount = in.hwClockDiscontinuityCount;
+}
+
+static void convertGnssData(GnssMeasurementsNotification& in,
+ V1_0::IGnssMeasurementCallback::GnssData& out)
+{
+ out.measurementCount = in.count;
+ if (out.measurementCount > static_cast<uint32_t>(V1_0::GnssMax::SVS_COUNT)) {
+ LOC_LOGW("%s]: Too many measurement %u. Clamps to %d.",
+ __FUNCTION__, out.measurementCount, V1_0::GnssMax::SVS_COUNT);
+ out.measurementCount = static_cast<uint32_t>(V1_0::GnssMax::SVS_COUNT);
+ }
+ for (size_t i = 0; i < out.measurementCount; i++) {
+ convertGnssMeasurement(in.measurements[i], out.measurements[i]);
+ }
+ convertGnssClock(in.clock, out.clock);
+}
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace gnss
+} // namespace hardware
+} // namespace android
diff --git a/android/1.0/location_api/MeasurementAPIClient.h b/android/1.0/location_api/MeasurementAPIClient.h
new file mode 100644
index 0000000..c357313
--- /dev/null
+++ b/android/1.0/location_api/MeasurementAPIClient.h
@@ -0,0 +1,77 @@
+/* Copyright (c) 2017-2018, 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 MEASUREMENT_API_CLINET_H
+#define MEASUREMENT_API_CLINET_H
+
+#include <mutex>
+#include <android/hardware/gnss/1.0/IGnssMeasurement.h>
+#include <android/hardware/gnss/1.0/IGnssMeasurementCallback.h>
+#include <LocationAPIClientBase.h>
+#include <hidl/Status.h>
+#include <gps_extended_c.h>
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace V1_0 {
+namespace implementation {
+
+using ::android::sp;
+
+class MeasurementAPIClient : public LocationAPIClientBase
+{
+public:
+ MeasurementAPIClient();
+ virtual ~MeasurementAPIClient();
+ MeasurementAPIClient(const MeasurementAPIClient&) = delete;
+ MeasurementAPIClient& operator=(const MeasurementAPIClient&) = delete;
+
+ // for GpsMeasurementInterface
+ Return<V1_0::IGnssMeasurement::GnssMeasurementStatus> measurementSetCallback(
+ const sp<V1_0::IGnssMeasurementCallback>& callback);
+ void measurementClose();
+ Return<IGnssMeasurement::GnssMeasurementStatus> startTracking();
+
+ // callbacks we are interested in
+ void onGnssMeasurementsCb(GnssMeasurementsNotification gnssMeasurementsNotification) final;
+
+private:
+ std::mutex mMutex;
+ sp<V1_0::IGnssMeasurementCallback> mGnssMeasurementCbIface;
+
+ bool mTracking;
+};
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace gnss
+} // namespace hardware
+} // namespace android
+#endif // MEASUREMENT_API_CLINET_H
diff --git a/android/1.0/service.cpp b/android/1.0/service.cpp
new file mode 100644
index 0000000..2a6f60f
--- /dev/null
+++ b/android/1.0/service.cpp
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
+ * Not a Contribution
+ */
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "android.hardware.gnss@1.0-service-qti"
+
+#include <android/hardware/gnss/1.0/IGnss.h>
+#include <hidl/LegacySupport.h>
+#include "loc_cfg.h"
+#include "loc_misc_utils.h"
+
+extern "C" {
+#include "vndfwk-detect.h"
+}
+
+#ifdef ARCH_ARM_32
+#define DEFAULT_HW_BINDER_MEM_SIZE 65536
+#endif
+
+using android::hardware::gnss::V1_0::IGnss;
+
+using android::hardware::configureRpcThreadpool;
+using android::hardware::registerPassthroughServiceImplementation;
+using android::hardware::joinRpcThreadpool;
+
+using android::status_t;
+using android::OK;
+
+typedef int vendorEnhancedServiceMain(int /* argc */, char* /* argv */ []);
+
+int main() {
+
+ ALOGI("%s", __FUNCTION__);
+
+ int vendorInfo = getVendorEnhancedInfo();
+ bool vendorEnhanced = ( 1 == vendorInfo || 3 == vendorInfo );
+ setVendorEnhanced(vendorEnhanced);
+
+#ifdef ARCH_ARM_32
+ android::hardware::ProcessState::initWithMmapSize((size_t)(DEFAULT_HW_BINDER_MEM_SIZE));
+#endif
+ configureRpcThreadpool(1, true);
+ status_t status;
+
+ status = registerPassthroughServiceImplementation<IGnss>();
+ if (status == OK) {
+ if (vendorEnhanced) {
+ #ifdef LOC_HIDL_VERSION
+ #define VENDOR_ENHANCED_LIB "vendor.qti.gnss@" LOC_HIDL_VERSION "-service.so"
+
+ void* libHandle = NULL;
+ vendorEnhancedServiceMain* vendorEnhancedMainMethod = (vendorEnhancedServiceMain*)
+ dlGetSymFromLib(libHandle, VENDOR_ENHANCED_LIB, "main");
+ if (NULL != vendorEnhancedMainMethod) {
+ (*vendorEnhancedMainMethod)(0, NULL);
+ }
+ #else
+ ALOGE("LOC_HIDL_VERSION not defined.");
+ #endif
+ }
+
+ joinRpcThreadpool();
+
+ } else {
+ ALOGE("Error while registering IGnss 1.0 service: %d", status);
+ }
+
+ return 0;
+}
diff --git a/android/1.1/AGnss.cpp b/android/1.1/AGnss.cpp
new file mode 100644
index 0000000..d8f9706
--- /dev/null
+++ b/android/1.1/AGnss.cpp
@@ -0,0 +1,203 @@
+/*
+ * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
+ * Not a Contribution
+ */
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "LocSvc_AGnssInterface"
+
+#include <log_util.h>
+#include "Gnss.h"
+#include "AGnss.h"
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace V1_1 {
+namespace implementation {
+
+static AGnss* spAGnss = nullptr;
+
+AGnss::AGnss(Gnss* gnss) : mGnss(gnss) {
+ spAGnss = this;
+}
+
+AGnss::~AGnss() {
+ spAGnss = nullptr;
+}
+
+void AGnss::agnssStatusIpV4Cb(AGnssExtStatusIpV4 status){
+ if (nullptr != spAGnss) {
+ spAGnss->statusIpV4Cb(status);
+ }
+}
+
+void AGnss::statusIpV4Cb(AGnssExtStatusIpV4 status) {
+ IAGnssCallback::AGnssStatusIpV4 st = {};
+
+ switch (status.type) {
+ case LOC_AGPS_TYPE_SUPL:
+ st.type = IAGnssCallback::AGnssType::TYPE_SUPL;
+ break;
+ case LOC_AGPS_TYPE_C2K:
+ st.type = IAGnssCallback::AGnssType::TYPE_C2K;
+ break;
+ default:
+ LOC_LOGE("invalid type: %d", status.type);
+ return;
+ }
+
+ switch (status.status) {
+ case LOC_GPS_REQUEST_AGPS_DATA_CONN:
+ st.status = IAGnssCallback::AGnssStatusValue::REQUEST_AGNSS_DATA_CONN;
+ break;
+ case LOC_GPS_RELEASE_AGPS_DATA_CONN:
+ st.status = IAGnssCallback::AGnssStatusValue::RELEASE_AGNSS_DATA_CONN;
+ break;
+ case LOC_GPS_AGPS_DATA_CONNECTED:
+ st.status = IAGnssCallback::AGnssStatusValue::AGNSS_DATA_CONNECTED;
+ break;
+ case LOC_GPS_AGPS_DATA_CONN_DONE:
+ st.status = IAGnssCallback::AGnssStatusValue::AGNSS_DATA_CONN_DONE;
+ break;
+ case LOC_GPS_AGPS_DATA_CONN_FAILED:
+ st.status = IAGnssCallback::AGnssStatusValue::AGNSS_DATA_CONN_FAILED;
+ break;
+ default:
+ LOC_LOGE("invalid status: %d", status.status);
+ return;
+ }
+ st.ipV4Addr = status.ipV4Addr;
+
+ if (mAGnssCbIface != nullptr) {
+ auto r = mAGnssCbIface->agnssStatusIpV4Cb(st);
+ if (!r.isOk()) {
+ LOC_LOGw("Error invoking AGNSS status cb %s", r.description().c_str());
+ }
+ } else {
+ LOC_LOGw("setCallback has not been called yet");
+ }
+}
+
+Return<void> AGnss::setCallback(const sp<IAGnssCallback>& callback) {
+
+ if(mGnss == nullptr || mGnss->getGnssInterface() == nullptr){
+ LOC_LOGE("Null GNSS interface");
+ return Void();
+ }
+
+ // Save the interface
+ mAGnssCbIface = callback;
+
+ AgpsCbInfo cbInfo = {};
+ cbInfo.statusV4Cb = (void*)agnssStatusIpV4Cb;
+ cbInfo.atlType = AGPS_ATL_TYPE_SUPL | AGPS_ATL_TYPE_SUPL_ES;
+
+ mGnss->getGnssInterface()->agpsInit(cbInfo);
+ return Void();
+}
+
+Return<bool> AGnss::dataConnClosed() {
+
+ if(mGnss == nullptr || mGnss->getGnssInterface() == nullptr){
+ LOC_LOGE("Null GNSS interface");
+ return false;
+ }
+
+ mGnss->getGnssInterface()->agpsDataConnClosed(LOC_AGPS_TYPE_SUPL);
+ return true;
+}
+
+Return<bool> AGnss::dataConnFailed() {
+
+ if(mGnss == nullptr || mGnss->getGnssInterface() == nullptr){
+ LOC_LOGE("Null GNSS interface");
+ return false;
+ }
+
+ mGnss->getGnssInterface()->agpsDataConnFailed(LOC_AGPS_TYPE_SUPL);
+ return true;
+}
+
+Return<bool> AGnss::dataConnOpen(const hidl_string& apn,
+ IAGnss::ApnIpType apnIpType) {
+
+ if(mGnss == nullptr || mGnss->getGnssInterface() == nullptr){
+ LOC_LOGE("Null GNSS interface");
+ return false;
+ }
+
+ /* Validate */
+ if(apn.empty()){
+ LOC_LOGE("Invalid APN");
+ return false;
+ }
+
+ LOC_LOGD("dataConnOpen APN name = [%s]", apn.c_str());
+
+ AGpsBearerType bearerType;
+ switch (apnIpType) {
+ case IAGnss::ApnIpType::IPV4:
+ bearerType = AGPS_APN_BEARER_IPV4;
+ break;
+ case IAGnss::ApnIpType::IPV6:
+ bearerType = AGPS_APN_BEARER_IPV6;
+ break;
+ case IAGnss::ApnIpType::IPV4V6:
+ bearerType = AGPS_APN_BEARER_IPV4V6;
+ break;
+ default:
+ bearerType = AGPS_APN_BEARER_IPV4;
+ break;
+ }
+
+ mGnss->getGnssInterface()->agpsDataConnOpen(
+ LOC_AGPS_TYPE_SUPL, apn.c_str(), apn.size(), (int)bearerType);
+ return true;
+}
+
+Return<bool> AGnss::setServer(IAGnssCallback::AGnssType type,
+ const hidl_string& hostname,
+ int32_t port) {
+ if (mGnss == nullptr) {
+ LOC_LOGE("%s]: mGnss is nullptr", __FUNCTION__);
+ return false;
+ }
+
+ GnssConfig config;
+ memset(&config, 0, sizeof(GnssConfig));
+ config.size = sizeof(GnssConfig);
+ config.flags = GNSS_CONFIG_FLAGS_SET_ASSISTANCE_DATA_VALID_BIT;
+ config.assistanceServer.size = sizeof(GnssConfigSetAssistanceServer);
+ if (type == IAGnssCallback::AGnssType::TYPE_SUPL) {
+ config.assistanceServer.type = GNSS_ASSISTANCE_TYPE_SUPL;
+ } else if (type == IAGnssCallback::AGnssType::TYPE_C2K) {
+ config.assistanceServer.type = GNSS_ASSISTANCE_TYPE_C2K;
+ } else {
+ LOC_LOGE("%s]: invalid AGnssType: %d", __FUNCTION__, static_cast<int>(type));
+ return false;
+ }
+ config.assistanceServer.hostName = strdup(hostname.c_str());
+ config.assistanceServer.port = port;
+ return mGnss->updateConfiguration(config);
+}
+
+} // namespace implementation
+} // namespace V1_1
+} // namespace gnss
+} // namespace hardware
+} // namespace android
diff --git a/android/1.1/AGnss.h b/android/1.1/AGnss.h
new file mode 100644
index 0000000..4b599b9
--- /dev/null
+++ b/android/1.1/AGnss.h
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
+ * Not a Contribution
+ */
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HARDWARE_GNSS_V1_1_AGNSS_H
+#define ANDROID_HARDWARE_GNSS_V1_1_AGNSS_H
+
+#include <android/hardware/gnss/1.0/IAGnss.h>
+#include <hidl/Status.h>
+#include <gps_extended_c.h>
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace V1_1 {
+namespace implementation {
+
+using ::android::hardware::gnss::V1_0::IAGnss;
+using ::android::hardware::gnss::V1_0::IAGnssCallback;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::hidl_string;
+using ::android::sp;
+
+struct Gnss;
+struct AGnss : public IAGnss {
+
+ AGnss(Gnss* gnss);
+ ~AGnss();
+ /*
+ * Methods from ::android::hardware::gnss::V1_0::IAGnss interface follow.
+ * These declarations were generated from IAGnss.hal.
+ */
+ Return<void> setCallback(const sp<IAGnssCallback>& callback) override;
+
+ Return<bool> dataConnClosed() override;
+
+ Return<bool> dataConnFailed() override;
+
+ Return<bool> dataConnOpen(const hidl_string& apn,
+ IAGnss::ApnIpType apnIpType) override;
+
+ Return<bool> setServer(IAGnssCallback::AGnssType type,
+ const hidl_string& hostname, int32_t port) override;
+
+ void statusIpV4Cb(AGnssExtStatusIpV4 status);
+
+ /* Data call setup callback passed down to GNSS HAL implementation */
+ static void agnssStatusIpV4Cb(AGnssExtStatusIpV4 status);
+
+ private:
+ Gnss* mGnss = nullptr;
+ sp<IAGnssCallback> mAGnssCbIface = nullptr;
+};
+
+} // namespace implementation
+} // namespace V1_1
+} // namespace gnss
+} // namespace hardware
+} // namespace android
+
+#endif // ANDROID_HARDWARE_GNSS_V1_1_AGNSS_H
diff --git a/android/1.1/AGnssRil.cpp b/android/1.1/AGnssRil.cpp
new file mode 100644
index 0000000..1e774f1
--- /dev/null
+++ b/android/1.1/AGnssRil.cpp
@@ -0,0 +1,114 @@
+/*
+ * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
+ * Not a Contribution
+ */
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "LocSvc__AGnssRilInterface"
+
+#include <log_util.h>
+#include <dlfcn.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <sstream>
+#include <string>
+#include "Gnss.h"
+#include "AGnssRil.h"
+#include <DataItemConcreteTypesBase.h>
+
+typedef void* (getLocationInterface)();
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace V1_1 {
+namespace implementation {
+
+
+AGnssRil::AGnssRil(Gnss* gnss) : mGnss(gnss) {
+ ENTRY_LOG_CALLFLOW();
+}
+
+AGnssRil::~AGnssRil() {
+ ENTRY_LOG_CALLFLOW();
+}
+
+Return<bool> AGnssRil::updateNetworkState(bool connected, NetworkType type, bool /*roaming*/) {
+ ENTRY_LOG_CALLFLOW();
+ // Extra NetworkTypes not available in IAgnssRil enums
+ const int NetworkType_BLUETOOTH = 7;
+ const int NetworkType_ETHERNET = 9;
+ const int NetworkType_PROXY = 16;
+
+ // for XTRA
+ if (nullptr != mGnss && ( nullptr != mGnss->getGnssInterface() )) {
+ int8_t typeout = loc_core::NetworkInfoDataItemBase::TYPE_UNKNOWN;
+ switch(type)
+ {
+ case IAGnssRil::NetworkType::MOBILE:
+ typeout = loc_core::NetworkInfoDataItemBase::TYPE_MOBILE;
+ break;
+ case IAGnssRil::NetworkType::WIFI:
+ typeout = loc_core::NetworkInfoDataItemBase::TYPE_WIFI;
+ break;
+ case IAGnssRil::NetworkType::MMS:
+ typeout = loc_core::NetworkInfoDataItemBase::TYPE_MMS;
+ break;
+ case IAGnssRil::NetworkType::SUPL:
+ typeout = loc_core::NetworkInfoDataItemBase::TYPE_SUPL;
+ break;
+ case IAGnssRil::NetworkType::DUN:
+ typeout = loc_core::NetworkInfoDataItemBase::TYPE_DUN;
+ break;
+ case IAGnssRil::NetworkType::HIPRI:
+ typeout = loc_core::NetworkInfoDataItemBase::TYPE_HIPRI;
+ break;
+ case IAGnssRil::NetworkType::WIMAX:
+ typeout = loc_core::NetworkInfoDataItemBase::TYPE_WIMAX;
+ break;
+ default:
+ {
+ int networkType = (int) type;
+ // Handling network types not available in IAgnssRil
+ switch(networkType)
+ {
+ case NetworkType_BLUETOOTH:
+ typeout = loc_core::NetworkInfoDataItemBase::TYPE_BLUETOOTH;
+ break;
+ case NetworkType_ETHERNET:
+ typeout = loc_core::NetworkInfoDataItemBase::TYPE_ETHERNET;
+ break;
+ case NetworkType_PROXY:
+ typeout = loc_core::NetworkInfoDataItemBase::TYPE_PROXY;
+ break;
+ default:
+ typeout = loc_core::NetworkInfoDataItemBase::TYPE_UNKNOWN;
+ }
+ }
+ break;
+ }
+ mGnss->getGnssInterface()->updateConnectionStatus(connected, false, typeout, 0);
+ }
+ return true;
+}
+
+} // namespace implementation
+} // namespace V1_1
+} // namespace gnss
+} // namespace hardware
+} // namespace android
diff --git a/android/1.1/AGnssRil.h b/android/1.1/AGnssRil.h
new file mode 100644
index 0000000..5c9298a
--- /dev/null
+++ b/android/1.1/AGnssRil.h
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
+ * Not a Contribution
+ */
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HARDWARE_GNSS_V1_0_AGNSSRIL_H_
+#define ANDROID_HARDWARE_GNSS_V1_0_AGNSSRIL_H_
+
+#include <android/hardware/gnss/1.0/IAGnssRil.h>
+#include <hidl/Status.h>
+#include <location_interface.h>
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace V1_1 {
+namespace implementation {
+
+using ::android::hardware::gnss::V1_0::IAGnssRil;
+using ::android::hardware::gnss::V1_0::IAGnssRilCallback;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::hidl_string;
+using ::android::sp;
+
+struct Gnss;
+/*
+ * Extended interface for AGNSS RIL support. An Assisted GNSS Radio Interface Layer interface
+ * allows the GNSS chipset to request radio interface layer information from Android platform.
+ * Examples of such information are reference location, unique subscriber ID, phone number string
+ * and network availability changes. Also contains wrapper methods to allow methods from
+ * IAGnssiRilCallback interface to be passed into the conventional implementation of the GNSS HAL.
+ */
+struct AGnssRil : public IAGnssRil {
+ AGnssRil(Gnss* gnss);
+ ~AGnssRil();
+
+ /*
+ * Methods from ::android::hardware::gnss::V1_0::IAGnssRil follow.
+ * These declarations were generated from IAGnssRil.hal.
+ */
+ Return<void> setCallback(const sp<IAGnssRilCallback>& /*callback*/) override {
+ return Void();
+ }
+ Return<void> setRefLocation(const IAGnssRil::AGnssRefLocation& /*agnssReflocation*/) override {
+ return Void();
+ }
+ Return<bool> setSetId(IAGnssRil::SetIDType /*type*/, const hidl_string& /*setid*/) override {
+ return false;
+ }
+ Return<bool> updateNetworkAvailability(bool /*available*/,
+ const hidl_string& /*apn*/) override {
+ return false;
+ }
+ Return<bool> updateNetworkState(bool connected, NetworkType type, bool roaming) override;
+
+ private:
+ Gnss* mGnss = nullptr;
+};
+
+} // namespace implementation
+} // namespace V1_1
+} // namespace gnss
+} // namespace hardware
+} // namespace android
+
+#endif // ANDROID_HARDWARE_GNSS_V1_0_AGNSSRIL_H_
diff --git a/android/1.1/Android.mk b/android/1.1/Android.mk
new file mode 100644
index 0000000..fb72de1
--- /dev/null
+++ b/android/1.1/Android.mk
@@ -0,0 +1,99 @@
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := android.hardware.gnss@1.1-impl-qti
+LOCAL_VENDOR_MODULE := true
+LOCAL_MODULE_RELATIVE_PATH := hw
+LOCAL_SRC_FILES := \
+ AGnss.cpp \
+ Gnss.cpp \
+ GnssBatching.cpp \
+ GnssGeofencing.cpp \
+ GnssMeasurement.cpp \
+ GnssNi.cpp \
+ GnssConfiguration.cpp \
+ GnssDebug.cpp \
+ AGnssRil.cpp
+
+LOCAL_SRC_FILES += \
+ location_api/LocationUtil.cpp \
+ location_api/GnssAPIClient.cpp \
+ location_api/GeofenceAPIClient.cpp \
+ location_api/BatchingAPIClient.cpp \
+ location_api/MeasurementAPIClient.cpp \
+
+LOCAL_C_INCLUDES:= \
+ $(LOCAL_PATH)/location_api
+LOCAL_HEADER_LIBRARIES := \
+ libgps.utils_headers \
+ libloc_core_headers \
+ libloc_pla_headers \
+ liblocation_api_headers \
+ liblocbatterylistener_headers
+
+LOCAL_SHARED_LIBRARIES := \
+ liblog \
+ libhidlbase \
+ libhidltransport \
+ libhwbinder \
+ libcutils \
+ libutils \
+ android.hardware.gnss@1.0 \
+ android.hardware.gnss@1.1 \
+ android.hardware.health@1.0 \
+ android.hardware.health@2.0 \
+ android.hardware.power@1.2 \
+ libbase
+
+LOCAL_SHARED_LIBRARIES += \
+ libloc_core \
+ libgps.utils \
+ libdl \
+ liblocation_api \
+
+LOCAL_CFLAGS += $(GNSS_CFLAGS)
+LOCAL_STATIC_LIBRARIES := liblocbatterylistener
+LOCAL_STATIC_LIBRARIES += libhealthhalutils
+include $(BUILD_SHARED_LIBRARY)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := android.hardware.gnss@1.1-service-qti
+LOCAL_VINTF_FRAGMENTS := android.hardware.gnss@1.1-service-qti.xml
+LOCAL_VENDOR_MODULE := true
+LOCAL_MODULE_RELATIVE_PATH := hw
+LOCAL_INIT_RC := android.hardware.gnss@1.1-service-qti.rc
+LOCAL_SRC_FILES := \
+ service.cpp \
+
+LOCAL_C_INCLUDES:= \
+ $(LOCAL_PATH)/location_api
+LOCAL_HEADER_LIBRARIES := \
+ libgps.utils_headers \
+ libloc_core_headers \
+ libloc_pla_headers \
+ liblocation_api_headers
+
+
+LOCAL_SHARED_LIBRARIES := \
+ liblog \
+ libcutils \
+ libdl \
+ libbase \
+ libutils \
+ libgps.utils \
+ libqti_vndfwk_detect \
+
+LOCAL_SHARED_LIBRARIES += \
+ libhwbinder \
+ libhidlbase \
+ libhidltransport \
+ android.hardware.gnss@1.0 \
+ android.hardware.gnss@1.1 \
+
+LOCAL_CFLAGS += $(GNSS_CFLAGS)
+
+ifneq ($(LOC_HIDL_VERSION),)
+LOCAL_CFLAGS += -DLOC_HIDL_VERSION='"$(LOC_HIDL_VERSION)"'
+endif
+
+include $(BUILD_EXECUTABLE)
diff --git a/android/1.1/Gnss.cpp b/android/1.1/Gnss.cpp
new file mode 100644
index 0000000..bea556f
--- /dev/null
+++ b/android/1.1/Gnss.cpp
@@ -0,0 +1,477 @@
+/*
+ * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
+ * Not a Contribution
+ */
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "LocSvc_GnssInterface"
+#define LOG_NDEBUG 0
+
+#include <fstream>
+#include <log_util.h>
+#include <dlfcn.h>
+#include <cutils/properties.h>
+#include "Gnss.h"
+#include <LocationUtil.h>
+
+#include "battery_listener.h"
+
+typedef const GnssInterface* (getLocationInterface)();
+
+#define IMAGES_INFO_FILE "/sys/devices/soc0/images"
+#define DELIMITER ";"
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace V1_1 {
+namespace implementation {
+
+static sp<Gnss> sGnss;
+static std::string getVersionString() {
+ static std::string version;
+ if (!version.empty())
+ return version;
+
+ char value[PROPERTY_VALUE_MAX] = {0};
+ property_get("ro.hardware", value, "unknown");
+ version.append(value).append(DELIMITER);
+
+ std::ifstream in(IMAGES_INFO_FILE);
+ std::string s;
+ while(getline(in, s)) {
+ std::size_t found = s.find("CRM:");
+ if (std::string::npos == found) {
+ continue;
+ }
+
+ // skip over space characters after "CRM:"
+ const char* substr = s.c_str();
+ found += 4;
+ while (0 != substr[found] && isspace(substr[found])) {
+ found++;
+ }
+ if (s.find("11:") != found) {
+ continue;
+ }
+ s.erase(0, found + 3);
+
+ found = s.find_first_of("\r\n");
+ if (std::string::npos != found) {
+ s.erase(s.begin() + found, s.end());
+ }
+ version.append(s).append(DELIMITER);
+ }
+ return version;
+}
+
+void Gnss::GnssDeathRecipient::serviceDied(uint64_t cookie, const wp<IBase>& who) {
+ LOC_LOGE("%s] service died. cookie: %llu, who: %p",
+ __FUNCTION__, static_cast<unsigned long long>(cookie), &who);
+ if (mGnss != nullptr) {
+ mGnss->stop();
+ mGnss->cleanup();
+ }
+}
+
+void location_on_battery_status_changed(bool charging) {
+ LOC_LOGd("battery status changed to %s charging", charging ? "" : "not");
+ if (sGnss != nullptr) {
+ sGnss->getGnssInterface()->updateBatteryStatus(charging);
+ }
+}
+Gnss::Gnss() {
+ ENTRY_LOG_CALLFLOW();
+ sGnss = this;
+ // register health client to listen on battery change
+ loc_extn_battery_properties_listener_init(location_on_battery_status_changed);
+ // clear pending GnssConfig
+ memset(&mPendingConfig, 0, sizeof(GnssConfig));
+
+ mGnssDeathRecipient = new GnssDeathRecipient(this);
+}
+
+Gnss::~Gnss() {
+ ENTRY_LOG_CALLFLOW();
+ if (mApi != nullptr) {
+ delete mApi;
+ mApi = nullptr;
+ }
+ sGnss = nullptr;
+}
+
+GnssAPIClient* Gnss::getApi() {
+ if (mApi == nullptr && (mGnssCbIface != nullptr || mGnssNiCbIface != nullptr)) {
+ mApi = new GnssAPIClient(mGnssCbIface, mGnssNiCbIface);
+ if (mApi == nullptr) {
+ LOC_LOGE("%s] faild to create GnssAPIClient", __FUNCTION__);
+ return mApi;
+ }
+
+ if (mPendingConfig.size == sizeof(GnssConfig)) {
+ // we have pending GnssConfig
+ mApi->gnssConfigurationUpdate(mPendingConfig);
+ // clear size to invalid mPendingConfig
+ mPendingConfig.size = 0;
+ if (mPendingConfig.assistanceServer.hostName != nullptr) {
+ free((void*)mPendingConfig.assistanceServer.hostName);
+ }
+ }
+ }
+ if (mApi == nullptr) {
+ LOC_LOGW("%s] GnssAPIClient is not ready", __FUNCTION__);
+ }
+ return mApi;
+}
+
+const GnssInterface* Gnss::getGnssInterface() {
+ static bool getGnssInterfaceFailed = false;
+ if (nullptr == mGnssInterface && !getGnssInterfaceFailed) {
+ LOC_LOGD("%s]: loading libgnss.so::getGnssInterface ...", __func__);
+ getLocationInterface* getter = NULL;
+ const char *error = NULL;
+ dlerror();
+ void *handle = dlopen("libgnss.so", RTLD_NOW);
+ if (NULL == handle || (error = dlerror()) != NULL) {
+ LOC_LOGW("dlopen for libgnss.so failed, error = %s", error);
+ } else {
+ getter = (getLocationInterface*)dlsym(handle, "getGnssInterface");
+ if ((error = dlerror()) != NULL) {
+ LOC_LOGW("dlsym for libgnss.so::getGnssInterface failed, error = %s", error);
+ getter = NULL;
+ }
+ }
+
+ if (NULL == getter) {
+ getGnssInterfaceFailed = true;
+ } else {
+ mGnssInterface = (const GnssInterface*)(*getter)();
+ }
+ }
+ return mGnssInterface;
+}
+
+Return<bool> Gnss::setCallback(const sp<V1_0::IGnssCallback>& callback) {
+ ENTRY_LOG_CALLFLOW();
+ if (mGnssCbIface != nullptr) {
+ mGnssCbIface->unlinkToDeath(mGnssDeathRecipient);
+ }
+ mGnssCbIface = callback;
+ if (mGnssCbIface != nullptr) {
+ mGnssCbIface->linkToDeath(mGnssDeathRecipient, 0 /*cookie*/);
+ }
+
+ GnssAPIClient* api = getApi();
+ if (api != nullptr) {
+ api->gnssUpdateCallbacks(mGnssCbIface, mGnssNiCbIface);
+ api->gnssEnable(LOCATION_TECHNOLOGY_TYPE_GNSS);
+ api->requestCapabilities();
+ }
+ return true;
+}
+
+Return<bool> Gnss::setGnssNiCb(const sp<IGnssNiCallback>& callback) {
+ ENTRY_LOG_CALLFLOW();
+ mGnssNiCbIface = callback;
+ GnssAPIClient* api = getApi();
+ if (api != nullptr) {
+ api->gnssUpdateCallbacks(mGnssCbIface, mGnssNiCbIface);
+ }
+ return true;
+}
+
+Return<bool> Gnss::updateConfiguration(GnssConfig& gnssConfig) {
+ ENTRY_LOG_CALLFLOW();
+ GnssAPIClient* api = getApi();
+ if (api) {
+ api->gnssConfigurationUpdate(gnssConfig);
+ } else if (gnssConfig.flags != 0) {
+ // api is not ready yet, update mPendingConfig with gnssConfig
+ mPendingConfig.size = sizeof(GnssConfig);
+
+ if (gnssConfig.flags & GNSS_CONFIG_FLAGS_GPS_LOCK_VALID_BIT) {
+ mPendingConfig.flags |= GNSS_CONFIG_FLAGS_GPS_LOCK_VALID_BIT;
+ mPendingConfig.gpsLock = gnssConfig.gpsLock;
+ }
+ if (gnssConfig.flags & GNSS_CONFIG_FLAGS_SUPL_VERSION_VALID_BIT) {
+ mPendingConfig.flags |= GNSS_CONFIG_FLAGS_SUPL_VERSION_VALID_BIT;
+ mPendingConfig.suplVersion = gnssConfig.suplVersion;
+ }
+ if (gnssConfig.flags & GNSS_CONFIG_FLAGS_SET_ASSISTANCE_DATA_VALID_BIT) {
+ mPendingConfig.flags |= GNSS_CONFIG_FLAGS_SET_ASSISTANCE_DATA_VALID_BIT;
+ mPendingConfig.assistanceServer.size = sizeof(GnssConfigSetAssistanceServer);
+ mPendingConfig.assistanceServer.type = gnssConfig.assistanceServer.type;
+ if (mPendingConfig.assistanceServer.hostName != nullptr) {
+ free((void*)mPendingConfig.assistanceServer.hostName);
+ mPendingConfig.assistanceServer.hostName =
+ strdup(gnssConfig.assistanceServer.hostName);
+ }
+ mPendingConfig.assistanceServer.port = gnssConfig.assistanceServer.port;
+ }
+ if (gnssConfig.flags & GNSS_CONFIG_FLAGS_LPP_PROFILE_VALID_BIT) {
+ mPendingConfig.flags |= GNSS_CONFIG_FLAGS_LPP_PROFILE_VALID_BIT;
+ mPendingConfig.lppProfile = gnssConfig.lppProfile;
+ }
+ if (gnssConfig.flags & GNSS_CONFIG_FLAGS_LPPE_CONTROL_PLANE_VALID_BIT) {
+ mPendingConfig.flags |= GNSS_CONFIG_FLAGS_LPPE_CONTROL_PLANE_VALID_BIT;
+ mPendingConfig.lppeControlPlaneMask = gnssConfig.lppeControlPlaneMask;
+ }
+ if (gnssConfig.flags & GNSS_CONFIG_FLAGS_LPPE_USER_PLANE_VALID_BIT) {
+ mPendingConfig.flags |= GNSS_CONFIG_FLAGS_LPPE_USER_PLANE_VALID_BIT;
+ mPendingConfig.lppeUserPlaneMask = gnssConfig.lppeUserPlaneMask;
+ }
+ if (gnssConfig.flags & GNSS_CONFIG_FLAGS_AGLONASS_POSITION_PROTOCOL_VALID_BIT) {
+ mPendingConfig.flags |= GNSS_CONFIG_FLAGS_AGLONASS_POSITION_PROTOCOL_VALID_BIT;
+ mPendingConfig.aGlonassPositionProtocolMask = gnssConfig.aGlonassPositionProtocolMask;
+ }
+ if (gnssConfig.flags & GNSS_CONFIG_FLAGS_EM_PDN_FOR_EM_SUPL_VALID_BIT) {
+ mPendingConfig.flags |= GNSS_CONFIG_FLAGS_EM_PDN_FOR_EM_SUPL_VALID_BIT;
+ mPendingConfig.emergencyPdnForEmergencySupl = gnssConfig.emergencyPdnForEmergencySupl;
+ }
+ if (gnssConfig.flags & GNSS_CONFIG_FLAGS_SUPL_EM_SERVICES_BIT) {
+ mPendingConfig.flags |= GNSS_CONFIG_FLAGS_SUPL_EM_SERVICES_BIT;
+ mPendingConfig.suplEmergencyServices = gnssConfig.suplEmergencyServices;
+ }
+ if (gnssConfig.flags & GNSS_CONFIG_FLAGS_SUPL_MODE_BIT) {
+ mPendingConfig.flags |= GNSS_CONFIG_FLAGS_SUPL_MODE_BIT;
+ mPendingConfig.suplModeMask = gnssConfig.suplModeMask;
+ }
+ if (gnssConfig.flags & GNSS_CONFIG_FLAGS_BLACKLISTED_SV_IDS_BIT) {
+ mPendingConfig.flags |= GNSS_CONFIG_FLAGS_BLACKLISTED_SV_IDS_BIT;
+ mPendingConfig.blacklistedSvIds = gnssConfig.blacklistedSvIds;
+ }
+ }
+ return true;
+}
+
+Return<bool> Gnss::start() {
+ ENTRY_LOG_CALLFLOW();
+ bool retVal = false;
+ GnssAPIClient* api = getApi();
+ if (api) {
+ retVal = api->gnssStart();
+ }
+ return retVal;
+}
+
+Return<bool> Gnss::stop() {
+ ENTRY_LOG_CALLFLOW();
+ bool retVal = false;
+ GnssAPIClient* api = getApi();
+ if (api) {
+ retVal = api->gnssStop();
+ }
+ return retVal;
+}
+
+Return<void> Gnss::cleanup() {
+ ENTRY_LOG_CALLFLOW();
+
+ if (mApi != nullptr) {
+ mApi->gnssDisable();
+ }
+
+ return Void();
+}
+
+Return<bool> Gnss::injectLocation(double latitudeDegrees,
+ double longitudeDegrees,
+ float accuracyMeters) {
+ ENTRY_LOG_CALLFLOW();
+ const GnssInterface* gnssInterface = getGnssInterface();
+ if (nullptr != gnssInterface) {
+ gnssInterface->injectLocation(latitudeDegrees, longitudeDegrees, accuracyMeters);
+ return true;
+ } else {
+ return false;
+ }
+}
+
+Return<bool> Gnss::injectTime(int64_t timeMs, int64_t timeReferenceMs,
+ int32_t uncertaintyMs) {
+ ENTRY_LOG_CALLFLOW();
+ const GnssInterface* gnssInterface = getGnssInterface();
+ if (nullptr != gnssInterface) {
+ gnssInterface->injectTime(timeMs, timeReferenceMs, uncertaintyMs);
+ return true;
+ } else {
+ return false;
+ }
+}
+
+Return<void> Gnss::deleteAidingData(V1_0::IGnss::GnssAidingData aidingDataFlags) {
+ ENTRY_LOG_CALLFLOW();
+ GnssAPIClient* api = getApi();
+ if (api) {
+ api->gnssDeleteAidingData(aidingDataFlags);
+ }
+ return Void();
+}
+
+Return<bool> Gnss::setPositionMode(V1_0::IGnss::GnssPositionMode mode,
+ V1_0::IGnss::GnssPositionRecurrence recurrence,
+ uint32_t minIntervalMs,
+ uint32_t preferredAccuracyMeters,
+ uint32_t preferredTimeMs) {
+ ENTRY_LOG_CALLFLOW();
+ bool retVal = false;
+ GnssAPIClient* api = getApi();
+ if (api) {
+ retVal = api->gnssSetPositionMode(mode, recurrence, minIntervalMs,
+ preferredAccuracyMeters, preferredTimeMs);
+ }
+ return retVal;
+}
+
+Return<sp<V1_0::IAGnss>> Gnss::getExtensionAGnss() {
+ ENTRY_LOG_CALLFLOW();
+ mAGnssIface = new AGnss(this);
+ return mAGnssIface;
+}
+
+Return<sp<V1_0::IGnssNi>> Gnss::getExtensionGnssNi() {
+ ENTRY_LOG_CALLFLOW();
+ mGnssNi = new GnssNi(this);
+ return mGnssNi;
+}
+
+Return<sp<V1_0::IGnssMeasurement>> Gnss::getExtensionGnssMeasurement() {
+ ENTRY_LOG_CALLFLOW();
+ if (mGnssMeasurement == nullptr)
+ mGnssMeasurement = new GnssMeasurement();
+ return mGnssMeasurement;
+}
+
+Return<sp<V1_0::IGnssConfiguration>> Gnss::getExtensionGnssConfiguration() {
+ ENTRY_LOG_CALLFLOW();
+ mGnssConfig = new GnssConfiguration(this);
+ return mGnssConfig;
+}
+
+Return<sp<V1_0::IGnssGeofencing>> Gnss::getExtensionGnssGeofencing() {
+ ENTRY_LOG_CALLFLOW();
+ mGnssGeofencingIface = new GnssGeofencing();
+ return mGnssGeofencingIface;
+}
+
+Return<sp<V1_0::IGnssBatching>> Gnss::getExtensionGnssBatching() {
+ mGnssBatching = new GnssBatching();
+ return mGnssBatching;
+}
+
+Return<sp<V1_0::IGnssDebug>> Gnss::getExtensionGnssDebug() {
+ ENTRY_LOG_CALLFLOW();
+ mGnssDebug = new GnssDebug(this);
+ return mGnssDebug;
+}
+
+Return<sp<V1_0::IAGnssRil>> Gnss::getExtensionAGnssRil() {
+ mGnssRil = new AGnssRil(this);
+ return mGnssRil;
+}
+
+// Methods from ::android::hardware::gnss::V1_1::IGnss follow.
+Return<bool> Gnss::setCallback_1_1(const sp<V1_1::IGnssCallback>& callback) {
+ ENTRY_LOG_CALLFLOW();
+ callback->gnssNameCb(getVersionString());
+ mGnssCbIface_1_1 = callback;
+ const GnssInterface* gnssInterface = getGnssInterface();
+ if (nullptr != gnssInterface) {
+ OdcpiRequestCallback cb = [this](const OdcpiRequestInfo& odcpiRequest) {
+ odcpiRequestCb(odcpiRequest);
+ };
+ gnssInterface->odcpiInit(cb);
+ }
+ return setCallback(callback);
+}
+
+Return<bool> Gnss::setPositionMode_1_1(V1_0::IGnss::GnssPositionMode mode,
+ V1_0::IGnss::GnssPositionRecurrence recurrence,
+ uint32_t minIntervalMs,
+ uint32_t preferredAccuracyMeters,
+ uint32_t preferredTimeMs,
+ bool lowPowerMode) {
+ ENTRY_LOG_CALLFLOW();
+ bool retVal = false;
+ GnssAPIClient* api = getApi();
+ if (api) {
+ GnssPowerMode powerMode = lowPowerMode?
+ GNSS_POWER_MODE_M4 : GNSS_POWER_MODE_M2;
+ retVal = api->gnssSetPositionMode(mode, recurrence, minIntervalMs,
+ preferredAccuracyMeters, preferredTimeMs, powerMode, minIntervalMs);
+ }
+ return retVal;
+}
+
+Return<sp<V1_1::IGnssMeasurement>> Gnss::getExtensionGnssMeasurement_1_1() {
+ ENTRY_LOG_CALLFLOW();
+ if (mGnssMeasurement == nullptr)
+ mGnssMeasurement = new GnssMeasurement();
+ return mGnssMeasurement;
+}
+
+Return<sp<V1_1::IGnssConfiguration>> Gnss::getExtensionGnssConfiguration_1_1() {
+ ENTRY_LOG_CALLFLOW();
+ if (mGnssConfig == nullptr)
+ mGnssConfig = new GnssConfiguration(this);
+ return mGnssConfig;
+}
+
+Return<bool> Gnss::injectBestLocation(const GnssLocation& gnssLocation) {
+ ENTRY_LOG_CALLFLOW();
+ const GnssInterface* gnssInterface = getGnssInterface();
+ if (nullptr != gnssInterface) {
+ Location location = {};
+ convertGnssLocation(gnssLocation, location);
+ gnssInterface->odcpiInject(location);
+ }
+ return true;
+}
+
+void Gnss::odcpiRequestCb(const OdcpiRequestInfo& request) {
+ ENTRY_LOG_CALLFLOW();
+ if (mGnssCbIface_1_1 != nullptr) {
+ // For emergency mode, request DBH (Device based hybrid) location
+ // Mark Independent from GNSS flag to false.
+ if (ODCPI_REQUEST_TYPE_START == request.type) {
+ auto r = mGnssCbIface_1_1->gnssRequestLocationCb(!request.isEmergencyMode);
+ if (!r.isOk()) {
+ LOC_LOGe("Error invoking gnssRequestLocationCb %s", r.description().c_str());
+ }
+ } else {
+ LOC_LOGv("Unsupported ODCPI request type: %d", request.type);
+ }
+ } else {
+ LOC_LOGe("ODCPI request not supported.");
+ }
+}
+
+V1_0::IGnss* HIDL_FETCH_IGnss(const char* hal) {
+ ENTRY_LOG_CALLFLOW();
+ V1_0::IGnss* iface = nullptr;
+ iface = new Gnss();
+ if (iface == nullptr) {
+ LOC_LOGE("%s]: failed to get %s", __FUNCTION__, hal);
+ }
+ return iface;
+}
+
+} // namespace implementation
+} // namespace V1_1
+} // namespace gnss
+} // namespace hardware
+} // namespace android
diff --git a/android/1.1/Gnss.h b/android/1.1/Gnss.h
new file mode 100644
index 0000000..15645eb
--- /dev/null
+++ b/android/1.1/Gnss.h
@@ -0,0 +1,154 @@
+/*
+ * Copyright (c) 2017-2018-2018-2018, The Linux Foundation. All rights reserved.
+ * Not a Contribution
+ */
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HARDWARE_GNSS_V1_1_GNSS_H
+#define ANDROID_HARDWARE_GNSS_V1_1_GNSS_H
+
+#include <AGnss.h>
+#include <AGnssRil.h>
+#include <GnssBatching.h>
+#include <GnssConfiguration.h>
+#include <GnssGeofencing.h>
+#include <GnssMeasurement.h>
+#include <GnssNi.h>
+#include <GnssDebug.h>
+
+#include <android/hardware/gnss/1.1/IGnss.h>
+#include <hidl/MQDescriptor.h>
+#include <hidl/Status.h>
+
+#include <GnssAPIClient.h>
+#include <location_interface.h>
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace V1_1 {
+namespace implementation {
+
+using ::android::hardware::hidl_array;
+using ::android::hardware::hidl_memory;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::sp;
+using ::android::hardware::gnss::V1_0::GnssLocation;
+
+struct Gnss : public IGnss {
+ Gnss();
+ ~Gnss();
+
+ /*
+ * Methods from ::android::hardware::gnss::V1_0::IGnss follow.
+ * These declarations were generated from Gnss.hal.
+ */
+ Return<bool> setCallback(const sp<V1_0::IGnssCallback>& callback) override;
+ Return<bool> start() override;
+ Return<bool> stop() override;
+ Return<void> cleanup() override;
+ Return<bool> injectLocation(double latitudeDegrees,
+ double longitudeDegrees,
+ float accuracyMeters) override;
+ Return<bool> injectTime(int64_t timeMs,
+ int64_t timeReferenceMs,
+ int32_t uncertaintyMs) override;
+ Return<void> deleteAidingData(V1_0::IGnss::GnssAidingData aidingDataFlags) override;
+ Return<bool> setPositionMode(V1_0::IGnss::GnssPositionMode mode,
+ V1_0::IGnss::GnssPositionRecurrence recurrence,
+ uint32_t minIntervalMs,
+ uint32_t preferredAccuracyMeters,
+ uint32_t preferredTimeMs) override;
+ Return<sp<V1_0::IAGnss>> getExtensionAGnss() override;
+ Return<sp<V1_0::IGnssNi>> getExtensionGnssNi() override;
+ Return<sp<V1_0::IGnssMeasurement>> getExtensionGnssMeasurement() override;
+ Return<sp<V1_0::IGnssConfiguration>> getExtensionGnssConfiguration() override;
+ Return<sp<V1_0::IGnssGeofencing>> getExtensionGnssGeofencing() override;
+ Return<sp<V1_0::IGnssBatching>> getExtensionGnssBatching() override;
+
+ Return<sp<V1_0::IAGnssRil>> getExtensionAGnssRil() override;
+
+ inline Return<sp<V1_0::IGnssNavigationMessage>> getExtensionGnssNavigationMessage() override {
+ return nullptr;
+ }
+
+ inline Return<sp<V1_0::IGnssXtra>> getExtensionXtra() override {
+ return nullptr;
+ }
+
+ Return<sp<V1_0::IGnssDebug>> getExtensionGnssDebug() override;
+
+ // Methods from ::android::hardware::gnss::V1_1::IGnss follow.
+ Return<bool> setCallback_1_1(const sp<V1_1::IGnssCallback>& callback) override;
+ Return<bool> setPositionMode_1_1(V1_0::IGnss::GnssPositionMode mode,
+ V1_0::IGnss::GnssPositionRecurrence recurrence,
+ uint32_t minIntervalMs, uint32_t preferredAccuracyMeters,
+ uint32_t preferredTimeMs, bool lowPowerMode) override;
+ Return<sp<V1_1::IGnssMeasurement>> getExtensionGnssMeasurement_1_1() override;
+ Return<sp<V1_1::IGnssConfiguration>> getExtensionGnssConfiguration_1_1() override;
+ Return<bool> injectBestLocation(const GnssLocation& location) override;
+
+ // These methods are not part of the IGnss base class.
+ GnssAPIClient* getApi();
+ Return<bool> setGnssNiCb(const sp<IGnssNiCallback>& niCb);
+ Return<bool> updateConfiguration(GnssConfig& gnssConfig);
+ const GnssInterface* getGnssInterface();
+
+ // Callback for ODCPI request
+ void odcpiRequestCb(const OdcpiRequestInfo& request);
+
+ private:
+ struct GnssDeathRecipient : hidl_death_recipient {
+ GnssDeathRecipient(sp<Gnss> gnss) : mGnss(gnss) {
+ }
+ ~GnssDeathRecipient() = default;
+ virtual void serviceDied(uint64_t cookie, const wp<IBase>& who) override;
+ sp<Gnss> mGnss;
+ };
+
+ private:
+ sp<GnssDeathRecipient> mGnssDeathRecipient = nullptr;
+
+ sp<AGnss> mAGnssIface = nullptr;
+ sp<GnssNi> mGnssNi = nullptr;
+ sp<GnssMeasurement> mGnssMeasurement = nullptr;
+ sp<GnssConfiguration> mGnssConfig = nullptr;
+ sp<GnssGeofencing> mGnssGeofencingIface = nullptr;
+ sp<GnssBatching> mGnssBatching = nullptr;
+ sp<IGnssDebug> mGnssDebug = nullptr;
+ sp<AGnssRil> mGnssRil = nullptr;
+
+ GnssAPIClient* mApi = nullptr;
+ sp<V1_0::IGnssCallback> mGnssCbIface = nullptr;
+ sp<V1_1::IGnssCallback> mGnssCbIface_1_1 = nullptr;
+ sp<V1_0::IGnssNiCallback> mGnssNiCbIface = nullptr;
+ GnssConfig mPendingConfig;
+ const GnssInterface* mGnssInterface = nullptr;
+};
+
+extern "C" V1_0::IGnss* HIDL_FETCH_IGnss(const char* name);
+
+} // namespace implementation
+} // namespace V1_1
+} // namespace gnss
+} // namespace hardware
+} // namespace android
+
+#endif // ANDROID_HARDWARE_GNSS_V1_1_GNSS_H
diff --git a/android/1.1/GnssBatching.cpp b/android/1.1/GnssBatching.cpp
new file mode 100644
index 0000000..9701aff
--- /dev/null
+++ b/android/1.1/GnssBatching.cpp
@@ -0,0 +1,130 @@
+/*
+ * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
+ * Not a Contribution
+ */
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "LocSvc_GnssBatchingInterface"
+
+#include <log_util.h>
+#include <BatchingAPIClient.h>
+#include "GnssBatching.h"
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace V1_1 {
+namespace implementation {
+
+void GnssBatching::GnssBatchingDeathRecipient::serviceDied(
+ uint64_t cookie, const wp<IBase>& who) {
+ LOC_LOGE("%s] service died. cookie: %llu, who: %p",
+ __FUNCTION__, static_cast<unsigned long long>(cookie), &who);
+ if (mGnssBatching != nullptr) {
+ mGnssBatching->stop();
+ mGnssBatching->cleanup();
+ }
+}
+
+GnssBatching::GnssBatching() : mApi(nullptr) {
+ mGnssBatchingDeathRecipient = new GnssBatchingDeathRecipient(this);
+}
+
+GnssBatching::~GnssBatching() {
+ if (mApi != nullptr) {
+ delete mApi;
+ mApi = nullptr;
+ }
+}
+
+
+// Methods from ::android::hardware::gnss::V1_0::IGnssBatching follow.
+Return<bool> GnssBatching::init(const sp<IGnssBatchingCallback>& callback) {
+ if (mApi != nullptr) {
+ LOC_LOGD("%s]: mApi is NOT nullptr, delete it first", __FUNCTION__);
+ delete mApi;
+ mApi = nullptr;
+ }
+
+ mApi = new BatchingAPIClient(callback);
+ if (mApi == nullptr) {
+ LOC_LOGE("%s]: failed to create mApi", __FUNCTION__);
+ return false;
+ }
+
+ if (mGnssBatchingCbIface != nullptr) {
+ mGnssBatchingCbIface->unlinkToDeath(mGnssBatchingDeathRecipient);
+ }
+ mGnssBatchingCbIface = callback;
+ if (mGnssBatchingCbIface != nullptr) {
+ mGnssBatchingCbIface->linkToDeath(mGnssBatchingDeathRecipient, 0 /*cookie*/);
+ }
+
+ return true;
+}
+
+Return<uint16_t> GnssBatching::getBatchSize() {
+ uint16_t ret = 0;
+ if (mApi == nullptr) {
+ LOC_LOGE("%s]: mApi is nullptr", __FUNCTION__);
+ } else {
+ ret = mApi->getBatchSize();
+ }
+ return ret;
+}
+
+Return<bool> GnssBatching::start(const IGnssBatching::Options& options) {
+ bool ret = false;
+ if (mApi == nullptr) {
+ LOC_LOGE("%s]: mApi is nullptr", __FUNCTION__);
+ } else {
+ ret = mApi->startSession(options);
+ }
+ return ret;
+}
+
+Return<void> GnssBatching::flush() {
+ if (mApi == nullptr) {
+ LOC_LOGE("%s]: mApi is nullptr", __FUNCTION__);
+ } else {
+ mApi->flushBatchedLocations();
+ }
+ return Void();
+}
+
+Return<bool> GnssBatching::stop() {
+ bool ret = false;
+ if (mApi == nullptr) {
+ LOC_LOGE("%s]: mApi is nullptr", __FUNCTION__);
+ } else {
+ ret = mApi->stopSession();
+ }
+ return ret;
+}
+
+Return<void> GnssBatching::cleanup() {
+ if (mGnssBatchingCbIface != nullptr) {
+ mGnssBatchingCbIface->unlinkToDeath(mGnssBatchingDeathRecipient);
+ }
+ return Void();
+}
+
+} // namespace implementation
+} // namespace V1_1
+} // namespace gnss
+} // namespace hardware
+} // namespace android
diff --git a/android/1.1/GnssBatching.h b/android/1.1/GnssBatching.h
new file mode 100644
index 0000000..8e235d8
--- /dev/null
+++ b/android/1.1/GnssBatching.h
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
+ * Not a Contribution
+ */
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HARDWARE_GNSS_V1_1_GNSSBATCHING_H
+#define ANDROID_HARDWARE_GNSS_V1_1_GNSSBATCHING_H
+
+#include <android/hardware/gnss/1.0/IGnssBatching.h>
+#include <hidl/Status.h>
+
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace V1_1 {
+namespace implementation {
+
+using ::android::hardware::gnss::V1_0::IGnssBatching;
+using ::android::hardware::gnss::V1_0::IGnssBatchingCallback;
+using ::android::hidl::base::V1_0::IBase;
+using ::android::hardware::hidl_array;
+using ::android::hardware::hidl_memory;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::sp;
+
+class BatchingAPIClient;
+struct GnssBatching : public IGnssBatching {
+ GnssBatching();
+ ~GnssBatching();
+
+ // Methods from ::android::hardware::gnss::V1_0::IGnssBatching follow.
+ Return<bool> init(const sp<IGnssBatchingCallback>& callback) override;
+ Return<uint16_t> getBatchSize() override;
+ Return<bool> start(const IGnssBatching::Options& options ) override;
+ Return<void> flush() override;
+ Return<bool> stop() override;
+ Return<void> cleanup() override;
+
+ private:
+ struct GnssBatchingDeathRecipient : hidl_death_recipient {
+ GnssBatchingDeathRecipient(sp<GnssBatching> gnssBatching) :
+ mGnssBatching(gnssBatching) {
+ }
+ ~GnssBatchingDeathRecipient() = default;
+ virtual void serviceDied(uint64_t cookie, const wp<IBase>& who) override;
+ sp<GnssBatching> mGnssBatching;
+ };
+
+ private:
+ sp<GnssBatchingDeathRecipient> mGnssBatchingDeathRecipient = nullptr;
+ sp<IGnssBatchingCallback> mGnssBatchingCbIface = nullptr;
+ BatchingAPIClient* mApi = nullptr;
+};
+
+} // namespace implementation
+} // namespace V1_1
+} // namespace gnss
+} // namespace hardware
+} // namespace android
+
+#endif // ANDROID_HARDWARE_GNSS_V1_1_GNSSBATCHING_H
diff --git a/android/1.1/GnssConfiguration.cpp b/android/1.1/GnssConfiguration.cpp
new file mode 100644
index 0000000..93f9645
--- /dev/null
+++ b/android/1.1/GnssConfiguration.cpp
@@ -0,0 +1,313 @@
+/*
+ * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
+ * Not a Contribution
+ */
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "LocSvc_GnssConfigurationInterface"
+
+#include <log_util.h>
+#include "Gnss.h"
+#include "GnssConfiguration.h"
+#include <android/hardware/gnss/1.0/types.h>
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace V1_1 {
+namespace implementation {
+
+using ::android::hardware::gnss::V1_0::GnssConstellationType;
+
+GnssConfiguration::GnssConfiguration(Gnss* gnss) : mGnss(gnss) {
+}
+
+// Methods from ::android::hardware::gps::V1_0::IGnssConfiguration follow.
+Return<bool> GnssConfiguration::setSuplEs(bool enabled) {
+ if (mGnss == nullptr) {
+ LOC_LOGE("%s]: mGnss is nullptr", __FUNCTION__);
+ return false;
+ }
+
+ GnssConfig config;
+ memset(&config, 0, sizeof(GnssConfig));
+ config.size = sizeof(GnssConfig);
+ config.flags = GNSS_CONFIG_FLAGS_SUPL_EM_SERVICES_BIT;
+ config.suplEmergencyServices = (enabled ?
+ GNSS_CONFIG_SUPL_EMERGENCY_SERVICES_YES :
+ GNSS_CONFIG_SUPL_EMERGENCY_SERVICES_NO);
+
+ return mGnss->updateConfiguration(config);
+}
+
+Return<bool> GnssConfiguration::setSuplVersion(uint32_t version) {
+ if (mGnss == nullptr) {
+ LOC_LOGE("%s]: mGnss is nullptr", __FUNCTION__);
+ return false;
+ }
+
+ GnssConfig config;
+ memset(&config, 0, sizeof(GnssConfig));
+ config.size = sizeof(GnssConfig);
+ config.flags = GNSS_CONFIG_FLAGS_SUPL_VERSION_VALID_BIT;
+ switch (version) {
+ case 0x00020002:
+ config.suplVersion = GNSS_CONFIG_SUPL_VERSION_2_0_2;
+ break;
+ case 0x00020000:
+ config.suplVersion = GNSS_CONFIG_SUPL_VERSION_2_0_0;
+ break;
+ case 0x00010000:
+ config.suplVersion = GNSS_CONFIG_SUPL_VERSION_1_0_0;
+ break;
+ default:
+ LOC_LOGE("%s]: invalid version: 0x%x.", __FUNCTION__, version);
+ return false;
+ break;
+ }
+
+ return mGnss->updateConfiguration(config);
+}
+
+Return<bool> GnssConfiguration::setSuplMode(uint8_t mode) {
+ if (mGnss == nullptr) {
+ LOC_LOGE("%s]: mGnss is nullptr", __FUNCTION__);
+ return false;
+ }
+
+ GnssConfig config;
+ memset(&config, 0, sizeof(GnssConfig));
+ config.size = sizeof(GnssConfig);
+ config.flags = GNSS_CONFIG_FLAGS_SUPL_MODE_BIT;
+ switch (mode) {
+ case 0:
+ config.suplModeMask = 0; // STANDALONE ONLY
+ break;
+ case 1:
+ config.suplModeMask = GNSS_CONFIG_SUPL_MODE_MSB_BIT;
+ break;
+ case 2:
+ config.suplModeMask = GNSS_CONFIG_SUPL_MODE_MSA_BIT;
+ break;
+ case 3:
+ config.suplModeMask = GNSS_CONFIG_SUPL_MODE_MSB_BIT | GNSS_CONFIG_SUPL_MODE_MSA_BIT;
+ break;
+ default:
+ LOC_LOGE("%s]: invalid mode: %d.", __FUNCTION__, mode);
+ return false;
+ break;
+ }
+
+ return mGnss->updateConfiguration(config);
+}
+
+Return<bool> GnssConfiguration::setLppProfile(uint8_t lppProfile) {
+ if (mGnss == nullptr) {
+ LOC_LOGE("%s]: mGnss is nullptr", __FUNCTION__);
+ return false;
+ }
+
+ GnssConfig config;
+ memset(&config, 0, sizeof(GnssConfig));
+ config.size = sizeof(GnssConfig);
+ config.flags = GNSS_CONFIG_FLAGS_LPP_PROFILE_VALID_BIT;
+ switch (lppProfile) {
+ case 0:
+ config.lppProfile = GNSS_CONFIG_LPP_PROFILE_RRLP_ON_LTE;
+ break;
+ case 1:
+ config.lppProfile = GNSS_CONFIG_LPP_PROFILE_USER_PLANE;
+ break;
+ case 2:
+ config.lppProfile = GNSS_CONFIG_LPP_PROFILE_CONTROL_PLANE;
+ break;
+ case 3:
+ config.lppProfile = GNSS_CONFIG_LPP_PROFILE_USER_PLANE_AND_CONTROL_PLANE;
+ break;
+ default:
+ LOC_LOGE("%s]: invalid lppProfile: %d.", __FUNCTION__, lppProfile);
+ return false;
+ break;
+ }
+
+ return mGnss->updateConfiguration(config);
+}
+
+Return<bool> GnssConfiguration::setGlonassPositioningProtocol(uint8_t protocol) {
+ if (mGnss == nullptr) {
+ LOC_LOGE("%s]: mGnss is nullptr", __FUNCTION__);
+ return false;
+ }
+
+ GnssConfig config;
+ memset(&config, 0, sizeof(GnssConfig));
+ config.size = sizeof(GnssConfig);
+
+ config.flags = GNSS_CONFIG_FLAGS_AGLONASS_POSITION_PROTOCOL_VALID_BIT;
+ if (protocol & (1<<0)) {
+ config.aGlonassPositionProtocolMask |= GNSS_CONFIG_RRC_CONTROL_PLANE_BIT;
+ }
+ if (protocol & (1<<1)) {
+ config.aGlonassPositionProtocolMask |= GNSS_CONFIG_RRLP_USER_PLANE_BIT;
+ }
+ if (protocol & (1<<2)) {
+ config.aGlonassPositionProtocolMask |= GNSS_CONFIG_LLP_USER_PLANE_BIT;
+ }
+ if (protocol & (1<<3)) {
+ config.aGlonassPositionProtocolMask |= GNSS_CONFIG_LLP_CONTROL_PLANE_BIT;
+ }
+
+ return mGnss->updateConfiguration(config);
+}
+
+Return<bool> GnssConfiguration::setGpsLock(uint8_t lock) {
+ if (mGnss == nullptr) {
+ LOC_LOGE("%s]: mGnss is nullptr", __FUNCTION__);
+ return false;
+ }
+
+ GnssConfig config;
+ memset(&config, 0, sizeof(GnssConfig));
+ config.size = sizeof(GnssConfig);
+ config.flags = GNSS_CONFIG_FLAGS_GPS_LOCK_VALID_BIT;
+ switch (lock) {
+ case 0:
+ config.gpsLock = GNSS_CONFIG_GPS_LOCK_NONE;
+ break;
+ case 1:
+ config.gpsLock = GNSS_CONFIG_GPS_LOCK_MO;
+ break;
+ case 2:
+ config.gpsLock = GNSS_CONFIG_GPS_LOCK_NI;
+ break;
+ case 3:
+ config.gpsLock = GNSS_CONFIG_GPS_LOCK_MO_AND_NI;
+ break;
+ default:
+ LOC_LOGE("%s]: invalid lock: %d.", __FUNCTION__, lock);
+ return false;
+ break;
+ }
+
+ return mGnss->updateConfiguration(config);
+}
+
+Return<bool> GnssConfiguration::setEmergencySuplPdn(bool enabled) {
+ if (mGnss == nullptr) {
+ LOC_LOGE("%s]: mGnss is nullptr", __FUNCTION__);
+ return false;
+ }
+
+ GnssConfig config;
+ memset(&config, 0, sizeof(GnssConfig));
+ config.size = sizeof(GnssConfig);
+ config.flags = GNSS_CONFIG_FLAGS_EM_PDN_FOR_EM_SUPL_VALID_BIT;
+ config.emergencyPdnForEmergencySupl = (enabled ?
+ GNSS_CONFIG_EMERGENCY_PDN_FOR_EMERGENCY_SUPL_YES :
+ GNSS_CONFIG_EMERGENCY_PDN_FOR_EMERGENCY_SUPL_NO);
+
+ return mGnss->updateConfiguration(config);
+}
+
+// Methods from ::android::hardware::gnss::V1_1::IGnssConfiguration follow.
+Return<bool> GnssConfiguration::setBlacklist(
+ const hidl_vec<GnssConfiguration::BlacklistedSource>& blacklist) {
+
+ ENTRY_LOG_CALLFLOW();
+ if (nullptr == mGnss) {
+ LOC_LOGe("mGnss is null");
+ return false;
+ }
+
+ // blValid is true if blacklist is empty, i.e. clearing the BL;
+ // if blacklist is not empty, blValid is initialied to false, and later
+ // updated in the for loop to become true only if there is at least
+ // one {constellation, svid} in the list that is valid.
+ bool blValid = (0 == blacklist.size());
+ GnssConfig config;
+ memset(&config, 0, sizeof(GnssConfig));
+ config.size = sizeof(GnssConfig);
+ config.flags = GNSS_CONFIG_FLAGS_BLACKLISTED_SV_IDS_BIT;
+ config.blacklistedSvIds.clear();
+
+ GnssSvIdSource source = {};
+ for (int idx = 0; idx < (int)blacklist.size(); idx++) {
+ // Set blValid true if any one source is valid
+ blValid = setBlacklistedSource(source, blacklist[idx]) || blValid;
+ config.blacklistedSvIds.push_back(source);
+ }
+
+ // Update configuration only if blValid is true
+ // i.e. only if atleast one source is valid for blacklisting
+ return (blValid && mGnss->updateConfiguration(config));
+}
+
+bool GnssConfiguration::setBlacklistedSource(
+ GnssSvIdSource& copyToSource,
+ const GnssConfiguration::BlacklistedSource& copyFromSource) {
+
+ bool retVal = true;
+ uint16_t svIdOffset = 0;
+ copyToSource.size = sizeof(GnssSvIdSource);
+ copyToSource.svId = copyFromSource.svid;
+
+ switch(copyFromSource.constellation) {
+ case GnssConstellationType::GPS:
+ copyToSource.constellation = GNSS_SV_TYPE_GPS;
+ LOC_LOGe("GPS SVs can't be blacklisted.");
+ retVal = false;
+ break;
+ case GnssConstellationType::SBAS:
+ copyToSource.constellation = GNSS_SV_TYPE_SBAS;
+ LOC_LOGe("SBAS SVs can't be blacklisted.");
+ retVal = false;
+ break;
+ case GnssConstellationType::GLONASS:
+ copyToSource.constellation = GNSS_SV_TYPE_GLONASS;
+ svIdOffset = GNSS_SV_CONFIG_GLO_INITIAL_SV_ID - 1;
+ break;
+ case GnssConstellationType::QZSS:
+ copyToSource.constellation = GNSS_SV_TYPE_QZSS;
+ svIdOffset = 0;
+ break;
+ case GnssConstellationType::BEIDOU:
+ copyToSource.constellation = GNSS_SV_TYPE_BEIDOU;
+ svIdOffset = GNSS_SV_CONFIG_BDS_INITIAL_SV_ID - 1;
+ break;
+ case GnssConstellationType::GALILEO:
+ copyToSource.constellation = GNSS_SV_TYPE_GALILEO;
+ svIdOffset = GNSS_SV_CONFIG_GAL_INITIAL_SV_ID - 1;
+ break;
+ default:
+ copyToSource.constellation = GNSS_SV_TYPE_UNKNOWN;
+ LOC_LOGe("Invalid constellation %d", copyFromSource.constellation);
+ retVal = false;
+ break;
+ }
+
+ if (copyToSource.svId > 0 && svIdOffset > 0) {
+ copyToSource.svId += svIdOffset;
+ }
+
+ return retVal;
+}
+
+} // namespace implementation
+} // namespace V1_1
+} // namespace gnss
+} // namespace hardware
+} // namespace android
diff --git a/android/1.1/GnssConfiguration.h b/android/1.1/GnssConfiguration.h
new file mode 100644
index 0000000..96681b6
--- /dev/null
+++ b/android/1.1/GnssConfiguration.h
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
+ * Not a Contribution
+ */
+
+ /* Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+#ifndef ANDROID_HARDWARE_GNSS_V1_1_GNSSCONFIGURATION_H
+#define ANDROID_HARDWARE_GNSS_V1_1_GNSSCONFIGURATION_H
+
+#include <android/hardware/gnss/1.1/IGnssConfiguration.h>
+#include <hidl/Status.h>
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace V1_1 {
+namespace implementation {
+
+using ::android::hardware::gnss::V1_1::IGnssConfiguration;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::hidl_string;
+using ::android::sp;
+
+/*
+ * Interface for passing GNSS configuration info from platform to HAL.
+ */
+struct Gnss;
+struct GnssConfiguration : public IGnssConfiguration {
+ GnssConfiguration(Gnss* gnss);
+ ~GnssConfiguration() = default;
+
+ /*
+ * Methods from ::android::hardware::gnss::V1_0::IGnssConfiguration follow.
+ * These declarations were generated from IGnssConfiguration.hal.
+ */
+ Return<bool> setSuplVersion(uint32_t version) override;
+ Return<bool> setSuplMode(uint8_t mode) override;
+ Return<bool> setSuplEs(bool enabled) override;
+ Return<bool> setLppProfile(uint8_t lppProfile) override;
+ Return<bool> setGlonassPositioningProtocol(uint8_t protocol) override;
+ Return<bool> setEmergencySuplPdn(bool enable) override;
+ Return<bool> setGpsLock(uint8_t lock) override;
+
+ // Methods from ::android::hardware::gnss::V1_1::IGnssConfiguration follow.
+ Return<bool> setBlacklist(
+ const hidl_vec<GnssConfiguration::BlacklistedSource>& blacklist) override;
+
+ private:
+ Gnss* mGnss = nullptr;
+ bool setBlacklistedSource(
+ GnssSvIdSource& copyToSource,
+ const GnssConfiguration::BlacklistedSource& copyFromSource);
+};
+
+} // namespace implementation
+} // namespace V1_1
+} // namespace gnss
+} // namespace hardware
+} // namespace android
+
+#endif // ANDROID_HARDWARE_GNSS_V1_1_GNSSCONFIGURATION_H
diff --git a/android/1.1/GnssDebug.cpp b/android/1.1/GnssDebug.cpp
new file mode 100644
index 0000000..f164c54
--- /dev/null
+++ b/android/1.1/GnssDebug.cpp
@@ -0,0 +1,175 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "LocSvc_GnssDebugInterface"
+
+#include <log/log.h>
+#include <log_util.h>
+#include "Gnss.h"
+#include "GnssDebug.h"
+#include "LocationUtil.h"
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace V1_1 {
+namespace implementation {
+
+using ::android::hardware::hidl_vec;
+
+#define GNSS_DEBUG_UNKNOWN_HORIZONTAL_ACCURACY_METERS (20000000)
+#define GNSS_DEBUG_UNKNOWN_VERTICAL_ACCURACY_METERS (20000)
+#define GNSS_DEBUG_UNKNOWN_SPEED_ACCURACY_PER_SEC (500)
+#define GNSS_DEBUG_UNKNOWN_BEARING_ACCURACY_DEG (180)
+
+#define GNSS_DEBUG_UNKNOWN_UTC_TIME (1483228800000LL) // 1/1/2017 00:00 GMT
+#define GNSS_DEBUG_UNKNOWN_UTC_TIME_UNC_MIN (999) // 999 ns
+#define GNSS_DEBUG_UNKNOWN_UTC_TIME_UNC_MAX (1.57783680E17) // 5 years in ns
+#define GNSS_DEBUG_UNKNOWN_FREQ_UNC_NS_PER_SEC (2.0e5) // ppm
+
+GnssDebug::GnssDebug(Gnss* gnss) : mGnss(gnss)
+{
+}
+
+/*
+ * This methods requests position, time and satellite ephemeris debug information
+ * from the HAL.
+ *
+ * @return void
+*/
+Return<void> GnssDebug::getDebugData(getDebugData_cb _hidl_cb)
+{
+ LOC_LOGD("%s]: ", __func__);
+
+ DebugData data = { };
+
+ if((nullptr == mGnss) || (nullptr == mGnss->getGnssInterface())){
+ LOC_LOGE("GnssDebug - Null GNSS interface");
+ _hidl_cb(data);
+ return Void();
+ }
+
+ // get debug report snapshot via hal interface
+ GnssDebugReport reports = { };
+ mGnss->getGnssInterface()->getDebugReport(reports);
+
+ // location block
+ if (reports.mLocation.mValid) {
+ data.position.valid = true;
+ data.position.latitudeDegrees = reports.mLocation.mLocation.latitude;
+ data.position.longitudeDegrees = reports.mLocation.mLocation.longitude;
+ data.position.altitudeMeters = reports.mLocation.mLocation.altitude;
+
+ data.position.speedMetersPerSec =
+ (double)(reports.mLocation.mLocation.speed);
+ data.position.bearingDegrees =
+ (double)(reports.mLocation.mLocation.bearing);
+ data.position.horizontalAccuracyMeters =
+ (double)(reports.mLocation.mLocation.accuracy);
+ data.position.verticalAccuracyMeters =
+ reports.mLocation.verticalAccuracyMeters;
+ data.position.speedAccuracyMetersPerSecond =
+ reports.mLocation.speedAccuracyMetersPerSecond;
+ data.position.bearingAccuracyDegrees =
+ reports.mLocation.bearingAccuracyDegrees;
+
+ timeval tv_now, tv_report;
+ tv_report.tv_sec = reports.mLocation.mUtcReported.tv_sec;
+ tv_report.tv_usec = reports.mLocation.mUtcReported.tv_nsec / 1000ULL;
+ gettimeofday(&tv_now, NULL);
+ data.position.ageSeconds =
+ (tv_now.tv_sec - tv_report.tv_sec) +
+ (float)((tv_now.tv_usec - tv_report.tv_usec)) / 1000000;
+ }
+ else {
+ data.position.valid = false;
+ }
+
+ if (data.position.horizontalAccuracyMeters <= 0 ||
+ data.position.horizontalAccuracyMeters > GNSS_DEBUG_UNKNOWN_HORIZONTAL_ACCURACY_METERS) {
+ data.position.horizontalAccuracyMeters = GNSS_DEBUG_UNKNOWN_HORIZONTAL_ACCURACY_METERS;
+ }
+ if (data.position.verticalAccuracyMeters <= 0 ||
+ data.position.verticalAccuracyMeters > GNSS_DEBUG_UNKNOWN_VERTICAL_ACCURACY_METERS) {
+ data.position.verticalAccuracyMeters = GNSS_DEBUG_UNKNOWN_VERTICAL_ACCURACY_METERS;
+ }
+ if (data.position.speedAccuracyMetersPerSecond <= 0 ||
+ data.position.speedAccuracyMetersPerSecond > GNSS_DEBUG_UNKNOWN_SPEED_ACCURACY_PER_SEC) {
+ data.position.speedAccuracyMetersPerSecond = GNSS_DEBUG_UNKNOWN_SPEED_ACCURACY_PER_SEC;
+ }
+ if (data.position.bearingAccuracyDegrees <= 0 ||
+ data.position.bearingAccuracyDegrees > GNSS_DEBUG_UNKNOWN_BEARING_ACCURACY_DEG) {
+ data.position.bearingAccuracyDegrees = GNSS_DEBUG_UNKNOWN_BEARING_ACCURACY_DEG;
+ }
+
+ // time block
+ if (reports.mTime.mValid) {
+ data.time.timeEstimate = reports.mTime.timeEstimate;
+ data.time.timeUncertaintyNs = reports.mTime.timeUncertaintyNs;
+ data.time.frequencyUncertaintyNsPerSec =
+ reports.mTime.frequencyUncertaintyNsPerSec;
+ }
+
+ if (data.time.timeEstimate < GNSS_DEBUG_UNKNOWN_UTC_TIME) {
+ data.time.timeEstimate = GNSS_DEBUG_UNKNOWN_UTC_TIME;
+ }
+ if (data.time.timeUncertaintyNs <= 0) {
+ data.time.timeUncertaintyNs = (float)GNSS_DEBUG_UNKNOWN_UTC_TIME_UNC_MIN;
+ } else if (data.time.timeUncertaintyNs > GNSS_DEBUG_UNKNOWN_UTC_TIME_UNC_MAX) {
+ data.time.timeUncertaintyNs = (float)GNSS_DEBUG_UNKNOWN_UTC_TIME_UNC_MAX;
+ }
+ if (data.time.frequencyUncertaintyNsPerSec <= 0 ||
+ data.time.frequencyUncertaintyNsPerSec > (float)GNSS_DEBUG_UNKNOWN_FREQ_UNC_NS_PER_SEC) {
+ data.time.frequencyUncertaintyNsPerSec = (float)GNSS_DEBUG_UNKNOWN_FREQ_UNC_NS_PER_SEC;
+ }
+
+ // satellite data block
+ SatelliteData s = { };
+ std::vector<SatelliteData> s_array = { };
+
+ for (uint32_t i=0; i<reports.mSatelliteInfo.size(); i++) {
+ memset(&s, 0, sizeof(s));
+ s.svid = reports.mSatelliteInfo[i].svid;
+ convertGnssConstellationType(
+ reports.mSatelliteInfo[i].constellation, s.constellation);
+ convertGnssEphemerisType(
+ reports.mSatelliteInfo[i].mEphemerisType, s.ephemerisType);
+ convertGnssEphemerisSource(
+ reports.mSatelliteInfo[i].mEphemerisSource, s.ephemerisSource);
+ convertGnssEphemerisHealth(
+ reports.mSatelliteInfo[i].mEphemerisHealth, s.ephemerisHealth);
+
+ s.ephemerisAgeSeconds =
+ reports.mSatelliteInfo[i].ephemerisAgeSeconds;
+ s.serverPredictionIsAvailable =
+ reports.mSatelliteInfo[i].serverPredictionIsAvailable;
+ s.serverPredictionAgeSeconds =
+ reports.mSatelliteInfo[i].serverPredictionAgeSeconds;
+
+ s_array.push_back(s);
+ }
+ data.satelliteDataArray = s_array;
+
+ // callback HIDL with collected debug data
+ _hidl_cb(data);
+ return Void();
+}
+
+} // namespace implementation
+} // namespace V1_1
+} // namespace gnss
+} // namespace hardware
+} // namespace android
diff --git a/android/1.1/GnssDebug.h b/android/1.1/GnssDebug.h
new file mode 100644
index 0000000..cb818ac
--- /dev/null
+++ b/android/1.1/GnssDebug.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HARDWARE_GNSS_V1_1_GNSSDEBUG_H
+#define ANDROID_HARDWARE_GNSS_V1_1_GNSSDEBUG_H
+
+
+#include <android/hardware/gnss/1.0/IGnssDebug.h>
+#include <hidl/Status.h>
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace V1_1 {
+namespace implementation {
+
+using ::android::hardware::gnss::V1_0::IGnssDebug;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::hidl_string;
+using ::android::sp;
+
+/* Interface for GNSS Debug support. */
+struct Gnss;
+struct GnssDebug : public IGnssDebug {
+ GnssDebug(Gnss* gnss);
+ ~GnssDebug() {};
+
+ /*
+ * Methods from ::android::hardware::gnss::V1_0::IGnssDebug follow.
+ * These declarations were generated from IGnssDebug.hal.
+ */
+ Return<void> getDebugData(getDebugData_cb _hidl_cb) override;
+
+private:
+ Gnss* mGnss = nullptr;
+};
+
+} // namespace implementation
+} // namespace V1_1
+} // namespace gnss
+} // namespace hardware
+} // namespace android
+
+#endif // ANDROID_HARDWARE_GNSS_V1_1_GNSSDEBUG_H
diff --git a/android/1.1/GnssGeofencing.cpp b/android/1.1/GnssGeofencing.cpp
new file mode 100644
index 0000000..d57a666
--- /dev/null
+++ b/android/1.1/GnssGeofencing.cpp
@@ -0,0 +1,141 @@
+/*
+ * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
+ * Not a Contribution
+ */
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "GnssHal_GnssGeofencing"
+
+#include <log_util.h>
+#include <GeofenceAPIClient.h>
+#include "GnssGeofencing.h"
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace V1_1 {
+namespace implementation {
+
+void GnssGeofencing::GnssGeofencingDeathRecipient::serviceDied(
+ uint64_t cookie, const wp<IBase>& who) {
+ LOC_LOGE("%s] service died. cookie: %llu, who: %p",
+ __FUNCTION__, static_cast<unsigned long long>(cookie), &who);
+ if (mGnssGeofencing != nullptr) {
+ mGnssGeofencing->removeAllGeofences();
+ }
+}
+
+GnssGeofencing::GnssGeofencing() : mApi(nullptr) {
+ mGnssGeofencingDeathRecipient = new GnssGeofencingDeathRecipient(this);
+}
+
+GnssGeofencing::~GnssGeofencing() {
+ if (mApi != nullptr) {
+ delete mApi;
+ mApi = nullptr;
+ }
+}
+
+// Methods from ::android::hardware::gnss::V1_0::IGnssGeofencing follow.
+Return<void> GnssGeofencing::setCallback(const sp<IGnssGeofenceCallback>& callback) {
+ if (mApi != nullptr) {
+ LOC_LOGd("mApi is NOT nullptr");
+ return Void();
+ }
+
+ mApi = new GeofenceAPIClient(callback);
+ if (mApi == nullptr) {
+ LOC_LOGE("%s]: failed to create mApi", __FUNCTION__);
+ }
+
+ if (mGnssGeofencingCbIface != nullptr) {
+ mGnssGeofencingCbIface->unlinkToDeath(mGnssGeofencingDeathRecipient);
+ }
+ mGnssGeofencingCbIface = callback;
+ if (mGnssGeofencingCbIface != nullptr) {
+ mGnssGeofencingCbIface->linkToDeath(mGnssGeofencingDeathRecipient, 0 /*cookie*/);
+ }
+
+ return Void();
+}
+
+Return<void> GnssGeofencing::addGeofence(
+ int32_t geofenceId,
+ double latitudeDegrees,
+ double longitudeDegrees,
+ double radiusMeters,
+ IGnssGeofenceCallback::GeofenceTransition lastTransition,
+ int32_t monitorTransitions,
+ uint32_t notificationResponsivenessMs,
+ uint32_t unknownTimerMs) {
+ if (mApi == nullptr) {
+ LOC_LOGE("%s]: mApi is nullptr", __FUNCTION__);
+ } else {
+ mApi->geofenceAdd(
+ geofenceId,
+ latitudeDegrees,
+ longitudeDegrees,
+ radiusMeters,
+ static_cast<int32_t>(lastTransition),
+ monitorTransitions,
+ notificationResponsivenessMs,
+ unknownTimerMs);
+ }
+ return Void();
+}
+
+Return<void> GnssGeofencing::pauseGeofence(int32_t geofenceId) {
+ if (mApi == nullptr) {
+ LOC_LOGE("%s]: mApi is nullptr", __FUNCTION__);
+ } else {
+ mApi->geofencePause(geofenceId);
+ }
+ return Void();
+}
+
+Return<void> GnssGeofencing::resumeGeofence(int32_t geofenceId, int32_t monitorTransitions) {
+ if (mApi == nullptr) {
+ LOC_LOGE("%s]: mApi is nullptr", __FUNCTION__);
+ } else {
+ mApi->geofenceResume(geofenceId, monitorTransitions);
+ }
+ return Void();
+}
+
+Return<void> GnssGeofencing::removeGeofence(int32_t geofenceId) {
+ if (mApi == nullptr) {
+ LOC_LOGE("%s]: mApi is nullptr", __FUNCTION__);
+ } else {
+ mApi->geofenceRemove(geofenceId);
+ }
+ return Void();
+}
+
+Return<void> GnssGeofencing::removeAllGeofences() {
+ if (mApi == nullptr) {
+ LOC_LOGD("%s]: mApi is nullptr, do nothing", __FUNCTION__);
+ } else {
+ mApi->geofenceRemoveAll();
+ }
+ return Void();
+}
+
+} // namespace implementation
+} // namespace V1_1
+} // namespace gnss
+} // namespace hardware
+} // namespace android
diff --git a/android/1.1/GnssGeofencing.h b/android/1.1/GnssGeofencing.h
new file mode 100644
index 0000000..94a73de
--- /dev/null
+++ b/android/1.1/GnssGeofencing.h
@@ -0,0 +1,91 @@
+/*
+ * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
+ * Not a Contribution
+ */
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HARDWARE_GNSS_V1_1_GNSSGEOFENCING_H
+#define ANDROID_HARDWARE_GNSS_V1_1_GNSSGEOFENCING_H
+
+#include <android/hardware/gnss/1.0/IGnssGeofencing.h>
+#include <hidl/Status.h>
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace V1_1 {
+namespace implementation {
+
+using ::android::hardware::gnss::V1_0::IGnssGeofenceCallback;
+using ::android::hardware::gnss::V1_0::IGnssGeofencing;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::hidl_string;
+using ::android::sp;
+
+class GeofenceAPIClient;
+struct GnssGeofencing : public IGnssGeofencing {
+ GnssGeofencing();
+ ~GnssGeofencing();
+
+ /*
+ * Methods from ::android::hardware::gnss::V1_0::IGnssGeofencing follow.
+ * These declarations were generated from IGnssGeofencing.hal.
+ */
+ Return<void> setCallback(const sp<IGnssGeofenceCallback>& callback) override;
+ Return<void> addGeofence(int32_t geofenceId,
+ double latitudeDegrees,
+ double longitudeDegrees,
+ double radiusMeters,
+ IGnssGeofenceCallback::GeofenceTransition lastTransition,
+ int32_t monitorTransitions,
+ uint32_t notificationResponsivenessMs,
+ uint32_t unknownTimerMs) override;
+
+ Return<void> pauseGeofence(int32_t geofenceId) override;
+ Return<void> resumeGeofence(int32_t geofenceId, int32_t monitorTransitions) override;
+ Return<void> removeGeofence(int32_t geofenceId) override;
+
+ private:
+ // This method is not part of the IGnss base class.
+ // It is called by GnssGeofencingDeathRecipient to remove all geofences added so far.
+ Return<void> removeAllGeofences();
+
+ private:
+ struct GnssGeofencingDeathRecipient : hidl_death_recipient {
+ GnssGeofencingDeathRecipient(sp<GnssGeofencing> gnssGeofencing) :
+ mGnssGeofencing(gnssGeofencing) {
+ }
+ ~GnssGeofencingDeathRecipient() = default;
+ virtual void serviceDied(uint64_t cookie, const wp<IBase>& who) override;
+ sp<GnssGeofencing> mGnssGeofencing;
+ };
+
+ private:
+ sp<GnssGeofencingDeathRecipient> mGnssGeofencingDeathRecipient = nullptr;
+ sp<IGnssGeofenceCallback> mGnssGeofencingCbIface = nullptr;
+ GeofenceAPIClient* mApi = nullptr;
+};
+
+} // namespace implementation
+} // namespace V1_1
+} // namespace gnss
+} // namespace hardware
+} // namespace android
+
+#endif // ANDROID_HARDWARE_GNSS_V1_1_GNSSGEOFENCING_H
diff --git a/android/1.1/GnssMeasurement.cpp b/android/1.1/GnssMeasurement.cpp
new file mode 100644
index 0000000..ffe5c52
--- /dev/null
+++ b/android/1.1/GnssMeasurement.cpp
@@ -0,0 +1,134 @@
+/*
+ * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
+ * Not a Contribution
+ */
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "LocSvc_GnssMeasurementInterface"
+
+#include <log_util.h>
+#include <MeasurementAPIClient.h>
+#include "GnssMeasurement.h"
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace V1_1 {
+namespace implementation {
+
+void GnssMeasurement::GnssMeasurementDeathRecipient::serviceDied(
+ uint64_t cookie, const wp<IBase>& who) {
+ LOC_LOGE("%s] service died. cookie: %llu, who: %p",
+ __FUNCTION__, static_cast<unsigned long long>(cookie), &who);
+ if (mGnssMeasurement != nullptr) {
+ mGnssMeasurement->close();
+ }
+}
+
+GnssMeasurement::GnssMeasurement() {
+ mGnssMeasurementDeathRecipient = new GnssMeasurementDeathRecipient(this);
+ mApi = new MeasurementAPIClient();
+}
+
+GnssMeasurement::~GnssMeasurement() {
+ if (mApi) {
+ delete mApi;
+ mApi = nullptr;
+ }
+}
+
+// Methods from ::android::hardware::gnss::V1_0::IGnssMeasurement follow.
+
+Return<IGnssMeasurement::GnssMeasurementStatus> GnssMeasurement::setCallback(
+ const sp<V1_0::IGnssMeasurementCallback>& callback) {
+
+ Return<IGnssMeasurement::GnssMeasurementStatus> ret =
+ IGnssMeasurement::GnssMeasurementStatus::ERROR_GENERIC;
+ if (mGnssMeasurementCbIface != nullptr) {
+ LOC_LOGE("%s]: GnssMeasurementCallback is already set", __FUNCTION__);
+ return IGnssMeasurement::GnssMeasurementStatus::ERROR_ALREADY_INIT;
+ }
+
+ if (callback == nullptr) {
+ LOC_LOGE("%s]: callback is nullptr", __FUNCTION__);
+ return ret;
+ }
+ if (mApi == nullptr) {
+ LOC_LOGE("%s]: mApi is nullptr", __FUNCTION__);
+ return ret;
+ }
+
+ mGnssMeasurementCbIface = callback;
+ mGnssMeasurementCbIface->linkToDeath(mGnssMeasurementDeathRecipient, 0);
+
+ return mApi->measurementSetCallback(callback);
+
+}
+
+Return<void> GnssMeasurement::close() {
+ if (mApi == nullptr) {
+ LOC_LOGE("%s]: mApi is nullptr", __FUNCTION__);
+ return Void();
+ }
+
+ if (mGnssMeasurementCbIface != nullptr) {
+ mGnssMeasurementCbIface->unlinkToDeath(mGnssMeasurementDeathRecipient);
+ mGnssMeasurementCbIface = nullptr;
+ }
+ if (mGnssMeasurementCbIface_1_1 != nullptr) {
+ mGnssMeasurementCbIface_1_1->unlinkToDeath(mGnssMeasurementDeathRecipient);
+ mGnssMeasurementCbIface_1_1 = nullptr;
+ }
+ mApi->measurementClose();
+
+ return Void();
+}
+
+// Methods from ::android::hardware::gnss::V1_1::IGnssMeasurement follow.
+Return<GnssMeasurement::GnssMeasurementStatus> GnssMeasurement::setCallback_1_1(
+ const sp<IGnssMeasurementCallback>& callback, bool enableFullTracking) {
+
+ Return<IGnssMeasurement::GnssMeasurementStatus> ret =
+ IGnssMeasurement::GnssMeasurementStatus::ERROR_GENERIC;
+ if (mGnssMeasurementCbIface_1_1 != nullptr) {
+ LOC_LOGE("%s]: GnssMeasurementCallback is already set", __FUNCTION__);
+ return IGnssMeasurement::GnssMeasurementStatus::ERROR_ALREADY_INIT;
+ }
+
+ if (callback == nullptr) {
+ LOC_LOGE("%s]: callback is nullptr", __FUNCTION__);
+ return ret;
+ }
+ if (nullptr == mApi) {
+ LOC_LOGE("%s]: mApi is nullptr", __FUNCTION__);
+ return ret;
+ }
+
+ mGnssMeasurementCbIface_1_1 = callback;
+ mGnssMeasurementCbIface_1_1->linkToDeath(mGnssMeasurementDeathRecipient, 0);
+
+ GnssPowerMode powerMode = enableFullTracking?
+ GNSS_POWER_MODE_M1 : GNSS_POWER_MODE_M2;
+
+ return mApi->measurementSetCallback_1_1(callback, powerMode);
+}
+
+} // namespace implementation
+} // namespace V1_1
+} // namespace gnss
+} // namespace hardware
+} // namespace android
diff --git a/android/1.1/GnssMeasurement.h b/android/1.1/GnssMeasurement.h
new file mode 100644
index 0000000..373f0d0
--- /dev/null
+++ b/android/1.1/GnssMeasurement.h
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
+ * Not a Contribution
+ */
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HARDWARE_GNSS_V1_1_GNSSMEASUREMENT_H
+#define ANDROID_HARDWARE_GNSS_V1_1_GNSSMEASUREMENT_H
+
+#include <android/hardware/gnss/1.1/IGnssMeasurement.h>
+#include <hidl/MQDescriptor.h>
+#include <hidl/Status.h>
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace V1_1 {
+namespace implementation {
+
+using ::android::hardware::gnss::V1_1::IGnssMeasurement;
+using ::android::hardware::gnss::V1_1::IGnssMeasurementCallback;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::hidl_string;
+using ::android::sp;
+
+class MeasurementAPIClient;
+struct GnssMeasurement : public IGnssMeasurement {
+ GnssMeasurement();
+ ~GnssMeasurement();
+
+ /*
+ * Methods from ::android::hardware::gnss::V1_0::IGnssMeasurement follow.
+ * These declarations were generated from IGnssMeasurement.hal.
+ */
+ Return<GnssMeasurement::GnssMeasurementStatus> setCallback(
+ const sp<V1_0::IGnssMeasurementCallback>& callback) override;
+ Return<void> close() override;
+
+ // Methods from ::android::hardware::gnss::V1_1::IGnssMeasurement follow.
+ Return<GnssMeasurement::GnssMeasurementStatus> setCallback_1_1(
+ const sp<IGnssMeasurementCallback>& callback,
+ bool enableFullTracking) override;
+
+ private:
+ struct GnssMeasurementDeathRecipient : hidl_death_recipient {
+ GnssMeasurementDeathRecipient(sp<GnssMeasurement> gnssMeasurement) :
+ mGnssMeasurement(gnssMeasurement) {
+ }
+ ~GnssMeasurementDeathRecipient() = default;
+ virtual void serviceDied(uint64_t cookie, const wp<IBase>& who) override;
+ sp<GnssMeasurement> mGnssMeasurement;
+ };
+
+ private:
+ sp<GnssMeasurementDeathRecipient> mGnssMeasurementDeathRecipient = nullptr;
+ sp<V1_0::IGnssMeasurementCallback> mGnssMeasurementCbIface = nullptr;
+ sp<IGnssMeasurementCallback> mGnssMeasurementCbIface_1_1 = nullptr;
+ MeasurementAPIClient* mApi;
+};
+
+} // namespace implementation
+} // namespace V1_1
+} // namespace gnss
+} // namespace hardware
+} // namespace android
+
+#endif // ANDROID_HARDWARE_GNSS_V1_1_GNSSMEASUREMENT_H
diff --git a/android/1.1/GnssNi.cpp b/android/1.1/GnssNi.cpp
new file mode 100644
index 0000000..5ce9569
--- /dev/null
+++ b/android/1.1/GnssNi.cpp
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
+ * Not a Contribution
+ */
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "LocSvc_GnssNiInterface"
+
+#include <log_util.h>
+#include "Gnss.h"
+#include "GnssNi.h"
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace V1_1 {
+namespace implementation {
+
+void GnssNi::GnssNiDeathRecipient::serviceDied(uint64_t cookie, const wp<IBase>& who) {
+ LOC_LOGE("%s] service died. cookie: %llu, who: %p",
+ __FUNCTION__, static_cast<unsigned long long>(cookie), &who);
+ // we do nothing here
+ // Gnss::GnssDeathRecipient will stop the session
+}
+
+GnssNi::GnssNi(Gnss* gnss) : mGnss(gnss) {
+ mGnssNiDeathRecipient = new GnssNiDeathRecipient(this);
+}
+
+// Methods from ::android::hardware::gnss::V1_0::IGnssNi follow.
+Return<void> GnssNi::setCallback(const sp<IGnssNiCallback>& callback) {
+ if (mGnss == nullptr) {
+ LOC_LOGE("%s]: mGnss is nullptr", __FUNCTION__);
+ return Void();
+ }
+
+ mGnss->setGnssNiCb(callback);
+
+ if (mGnssNiCbIface != nullptr) {
+ mGnssNiCbIface->unlinkToDeath(mGnssNiDeathRecipient);
+ }
+ mGnssNiCbIface = callback;
+ if (mGnssNiCbIface != nullptr) {
+ mGnssNiCbIface->linkToDeath(mGnssNiDeathRecipient, 0 /*cookie*/);
+ }
+
+ return Void();
+}
+
+Return<void> GnssNi::respond(int32_t notifId, IGnssNiCallback::GnssUserResponseType userResponse) {
+ if (mGnss == nullptr) {
+ LOC_LOGE("%s]: mGnss is nullptr", __FUNCTION__);
+ return Void();
+ }
+
+ GnssAPIClient* api = mGnss->getApi();
+ if (api == nullptr) {
+ LOC_LOGE("%s]: api is nullptr", __FUNCTION__);
+ return Void();
+ }
+
+ api->gnssNiRespond(notifId, userResponse);
+
+ return Void();
+}
+
+} // namespace implementation
+} // namespace V1_1
+} // namespace gnss
+} // namespace hardware
+} // namespace android
diff --git a/android/1.1/GnssNi.h b/android/1.1/GnssNi.h
new file mode 100644
index 0000000..6733e5b
--- /dev/null
+++ b/android/1.1/GnssNi.h
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
+ * Not a Contribution
+ */
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HARDWARE_GNSS_V1_1_GNSSNI_H
+#define ANDROID_HARDWARE_GNSS_V1_1_GNSSNI_H
+
+#include <android/hardware/gnss/1.0/IGnssNi.h>
+#include <hidl/Status.h>
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace V1_1 {
+namespace implementation {
+
+using ::android::hardware::gnss::V1_0::IGnssNi;
+using ::android::hardware::gnss::V1_0::IGnssNiCallback;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::hidl_string;
+using ::android::sp;
+
+struct Gnss;
+struct GnssNi : public IGnssNi {
+ GnssNi(Gnss* gnss);
+ ~GnssNi() = default;
+
+ /*
+ * Methods from ::android::hardware::gnss::V1_0::IGnssNi follow.
+ * These declarations were generated from IGnssNi.hal.
+ */
+ Return<void> setCallback(const sp<IGnssNiCallback>& callback) override;
+ Return<void> respond(int32_t notifId,
+ IGnssNiCallback::GnssUserResponseType userResponse) override;
+
+ private:
+ struct GnssNiDeathRecipient : hidl_death_recipient {
+ GnssNiDeathRecipient(sp<GnssNi> gnssNi) : mGnssNi(gnssNi) {
+ }
+ ~GnssNiDeathRecipient() = default;
+ virtual void serviceDied(uint64_t cookie, const wp<IBase>& who) override;
+ sp<GnssNi> mGnssNi;
+ };
+
+ private:
+ sp<GnssNiDeathRecipient> mGnssNiDeathRecipient = nullptr;
+ sp<IGnssNiCallback> mGnssNiCbIface = nullptr;
+ Gnss* mGnss = nullptr;
+};
+
+} // namespace implementation
+} // namespace V1_1
+} // namespace gnss
+} // namespace hardware
+} // namespace android
+
+#endif // ANDROID_HARDWARE_GNSS_V1_1_GNSSNI_H
diff --git a/android/1.1/android.hardware.gnss@1.1-service-qti.rc b/android/1.1/android.hardware.gnss@1.1-service-qti.rc
new file mode 100644
index 0000000..bd65584
--- /dev/null
+++ b/android/1.1/android.hardware.gnss@1.1-service-qti.rc
@@ -0,0 +1,4 @@
+service gnss_service /vendor/bin/hw/android.hardware.gnss@1.1-service-qti
+ class hal
+ user gps
+ group system gps radio vendor_qti_diag
diff --git a/android/1.1/android.hardware.gnss@1.1-service-qti.xml b/android/1.1/android.hardware.gnss@1.1-service-qti.xml
new file mode 100644
index 0000000..c9c83fb
--- /dev/null
+++ b/android/1.1/android.hardware.gnss@1.1-service-qti.xml
@@ -0,0 +1,35 @@
+<!-- Copyright (c) 2019, 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.
+-->
+<manifest version="1.0" type="device">
+ <hal format="hidl">
+ <name>android.hardware.gnss</name>
+ <transport>hwbinder</transport>
+ <fqname>@1.1::IGnss/default</fqname>
+ </hal>
+</manifest>
+
diff --git a/android/1.1/location_api/BatchingAPIClient.cpp b/android/1.1/location_api/BatchingAPIClient.cpp
new file mode 100644
index 0000000..82a803f
--- /dev/null
+++ b/android/1.1/location_api/BatchingAPIClient.cpp
@@ -0,0 +1,196 @@
+/* Copyright (c) 2017-2018, 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_NDEBUG 0
+#define LOG_TAG "LocSvc_BatchingAPIClient"
+
+#include <log_util.h>
+#include <loc_cfg.h>
+
+#include "LocationUtil.h"
+#include "BatchingAPIClient.h"
+
+#include "limits.h"
+
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace V1_1 {
+namespace implementation {
+
+using ::android::hardware::gnss::V1_0::IGnssBatching;
+using ::android::hardware::gnss::V1_0::IGnssBatchingCallback;
+using ::android::hardware::gnss::V1_0::GnssLocation;
+
+static void convertBatchOption(const IGnssBatching::Options& in, LocationOptions& out,
+ LocationCapabilitiesMask mask);
+
+BatchingAPIClient::BatchingAPIClient(const sp<IGnssBatchingCallback>& callback) :
+ LocationAPIClientBase(),
+ mGnssBatchingCbIface(callback),
+ mDefaultId(UINT_MAX),
+ mLocationCapabilitiesMask(0)
+{
+ LOC_LOGD("%s]: (%p)", __FUNCTION__, &callback);
+
+ LocationCallbacks locationCallbacks;
+ memset(&locationCallbacks, 0, sizeof(LocationCallbacks));
+ locationCallbacks.size = sizeof(LocationCallbacks);
+
+ locationCallbacks.trackingCb = nullptr;
+ locationCallbacks.batchingCb = nullptr;
+ if (mGnssBatchingCbIface != nullptr) {
+ locationCallbacks.batchingCb = [this](size_t count, Location* location,
+ BatchingOptions batchOptions) {
+ onBatchingCb(count, location, batchOptions);
+ };
+ }
+ locationCallbacks.geofenceBreachCb = nullptr;
+ locationCallbacks.geofenceStatusCb = nullptr;
+ locationCallbacks.gnssLocationInfoCb = nullptr;
+ locationCallbacks.gnssNiCb = nullptr;
+ locationCallbacks.gnssSvCb = nullptr;
+ locationCallbacks.gnssNmeaCb = nullptr;
+ locationCallbacks.gnssMeasurementsCb = nullptr;
+
+ locAPISetCallbacks(locationCallbacks);
+}
+
+BatchingAPIClient::~BatchingAPIClient()
+{
+ LOC_LOGD("%s]: ()", __FUNCTION__);
+}
+
+int BatchingAPIClient::getBatchSize()
+{
+ LOC_LOGD("%s]: ()", __FUNCTION__);
+ return locAPIGetBatchSize();
+}
+
+int BatchingAPIClient::startSession(const IGnssBatching::Options& opts)
+{
+ LOC_LOGD("%s]: (%lld %d)", __FUNCTION__,
+ static_cast<long long>(opts.periodNanos), static_cast<uint8_t>(opts.flags));
+ int retVal = -1;
+ LocationOptions options;
+ convertBatchOption(opts, options, mLocationCapabilitiesMask);
+ uint32_t mode = 0;
+ if (opts.flags == static_cast<uint8_t>(IGnssBatching::Flag::WAKEUP_ON_FIFO_FULL)) {
+ mode = SESSION_MODE_ON_FULL;
+ }
+ if (locAPIStartSession(mDefaultId, mode, options) == LOCATION_ERROR_SUCCESS) {
+ retVal = 1;
+ }
+ return retVal;
+}
+
+int BatchingAPIClient::updateSessionOptions(const IGnssBatching::Options& opts)
+{
+ LOC_LOGD("%s]: (%lld %d)", __FUNCTION__,
+ static_cast<long long>(opts.periodNanos), static_cast<uint8_t>(opts.flags));
+ int retVal = -1;
+ LocationOptions options;
+ convertBatchOption(opts, options, mLocationCapabilitiesMask);
+
+ uint32_t mode = 0;
+ if (opts.flags == static_cast<uint8_t>(IGnssBatching::Flag::WAKEUP_ON_FIFO_FULL)) {
+ mode = SESSION_MODE_ON_FULL;
+ }
+ if (locAPIUpdateSessionOptions(mDefaultId, mode, options) == LOCATION_ERROR_SUCCESS) {
+ retVal = 1;
+ }
+ return retVal;
+}
+
+int BatchingAPIClient::stopSession()
+{
+ LOC_LOGD("%s]: ", __FUNCTION__);
+ int retVal = -1;
+ if (locAPIStopSession(mDefaultId) == LOCATION_ERROR_SUCCESS) {
+ retVal = 1;
+ }
+ return retVal;
+}
+
+void BatchingAPIClient::getBatchedLocation(int last_n_locations)
+{
+ LOC_LOGD("%s]: (%d)", __FUNCTION__, last_n_locations);
+ locAPIGetBatchedLocations(mDefaultId, last_n_locations);
+}
+
+void BatchingAPIClient::flushBatchedLocations()
+{
+ LOC_LOGD("%s]: ()", __FUNCTION__);
+ locAPIGetBatchedLocations(mDefaultId, SIZE_MAX);
+}
+
+void BatchingAPIClient::onCapabilitiesCb(LocationCapabilitiesMask capabilitiesMask)
+{
+ LOC_LOGD("%s]: (%02x)", __FUNCTION__, capabilitiesMask);
+ mLocationCapabilitiesMask = capabilitiesMask;
+}
+
+void BatchingAPIClient::onBatchingCb(size_t count, Location* location,
+ BatchingOptions /*batchOptions*/)
+{
+ LOC_LOGD("%s]: (count: %zu)", __FUNCTION__, count);
+ if (mGnssBatchingCbIface != nullptr && count > 0) {
+ hidl_vec<GnssLocation> locationVec;
+ locationVec.resize(count);
+ for (size_t i = 0; i < count; i++) {
+ convertGnssLocation(location[i], locationVec[i]);
+ }
+ auto r = mGnssBatchingCbIface->gnssLocationBatchCb(locationVec);
+ if (!r.isOk()) {
+ LOC_LOGE("%s] Error from gnssLocationBatchCb description=%s",
+ __func__, r.description().c_str());
+ }
+ }
+}
+
+static void convertBatchOption(const IGnssBatching::Options& in, LocationOptions& out,
+ LocationCapabilitiesMask mask)
+{
+ memset(&out, 0, sizeof(LocationOptions));
+ out.size = sizeof(LocationOptions);
+ out.minInterval = (uint32_t)(in.periodNanos / 1000000L);
+ out.minDistance = 0;
+ out.mode = GNSS_SUPL_MODE_STANDALONE;
+ if (mask & LOCATION_CAPABILITIES_GNSS_MSA_BIT)
+ out.mode = GNSS_SUPL_MODE_MSA;
+ if (mask & LOCATION_CAPABILITIES_GNSS_MSB_BIT)
+ out.mode = GNSS_SUPL_MODE_MSB;
+}
+
+} // namespace implementation
+} // namespace V1_1
+} // namespace gnss
+} // namespace hardware
+} // namespace android
diff --git a/android/1.1/location_api/BatchingAPIClient.h b/android/1.1/location_api/BatchingAPIClient.h
new file mode 100644
index 0000000..64d47a0
--- /dev/null
+++ b/android/1.1/location_api/BatchingAPIClient.h
@@ -0,0 +1,74 @@
+/* Copyright (c) 2017-2018, 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 BATCHING_API_CLINET_H
+#define BATCHING_API_CLINET_H
+
+#include <android/hardware/gnss/1.0/IGnssBatching.h>
+#include <android/hardware/gnss/1.0/IGnssBatchingCallback.h>
+#include <pthread.h>
+
+#include <LocationAPIClientBase.h>
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace V1_1 {
+namespace implementation {
+
+class BatchingAPIClient : public LocationAPIClientBase
+{
+public:
+ BatchingAPIClient(const sp<V1_0::IGnssBatchingCallback>& callback);
+ ~BatchingAPIClient();
+ int getBatchSize();
+ int startSession(const V1_0::IGnssBatching::Options& options);
+ int updateSessionOptions(const V1_0::IGnssBatching::Options& options);
+ int stopSession();
+ void getBatchedLocation(int last_n_locations);
+ void flushBatchedLocations();
+
+ inline LocationCapabilitiesMask getCapabilities() { return mLocationCapabilitiesMask; }
+
+ // callbacks
+ void onCapabilitiesCb(LocationCapabilitiesMask capabilitiesMask) final;
+ void onBatchingCb(size_t count, Location* location, BatchingOptions batchOptions) final;
+
+private:
+ sp<V1_0::IGnssBatchingCallback> mGnssBatchingCbIface;
+ uint32_t mDefaultId;
+ LocationCapabilitiesMask mLocationCapabilitiesMask;
+};
+
+} // namespace implementation
+} // namespace V1_1
+} // namespace gnss
+} // namespace hardware
+} // namespace android
+#endif // BATCHING_API_CLINET_H
diff --git a/android/1.1/location_api/GeofenceAPIClient.cpp b/android/1.1/location_api/GeofenceAPIClient.cpp
new file mode 100644
index 0000000..93d175e
--- /dev/null
+++ b/android/1.1/location_api/GeofenceAPIClient.cpp
@@ -0,0 +1,275 @@
+/* Copyright (c) 2017-2018, 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_NDEBUG 0
+#define LOG_TAG "LocSvc_GeofenceApiClient"
+
+#include <log_util.h>
+#include <loc_cfg.h>
+
+#include "LocationUtil.h"
+#include "GeofenceAPIClient.h"
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace V1_1 {
+namespace implementation {
+
+using ::android::hardware::gnss::V1_0::IGnssGeofenceCallback;
+using ::android::hardware::gnss::V1_0::GnssLocation;
+
+GeofenceAPIClient::GeofenceAPIClient(const sp<IGnssGeofenceCallback>& callback) :
+ LocationAPIClientBase(),
+ mGnssGeofencingCbIface(callback)
+{
+ LOC_LOGD("%s]: (%p)", __FUNCTION__, &callback);
+
+ LocationCallbacks locationCallbacks;
+ memset(&locationCallbacks, 0, sizeof(LocationCallbacks));
+ locationCallbacks.size = sizeof(LocationCallbacks);
+
+ locationCallbacks.trackingCb = nullptr;
+ locationCallbacks.batchingCb = nullptr;
+
+ locationCallbacks.geofenceBreachCb = nullptr;
+ if (mGnssGeofencingCbIface != nullptr) {
+ locationCallbacks.geofenceBreachCb =
+ [this](GeofenceBreachNotification geofenceBreachNotification) {
+ onGeofenceBreachCb(geofenceBreachNotification);
+ };
+
+ locationCallbacks.geofenceStatusCb =
+ [this](GeofenceStatusNotification geofenceStatusNotification) {
+ onGeofenceStatusCb(geofenceStatusNotification);
+ };
+ }
+
+ locationCallbacks.gnssLocationInfoCb = nullptr;
+ locationCallbacks.gnssNiCb = nullptr;
+ locationCallbacks.gnssSvCb = nullptr;
+ locationCallbacks.gnssNmeaCb = nullptr;
+ locationCallbacks.gnssMeasurementsCb = nullptr;
+
+ locAPISetCallbacks(locationCallbacks);
+}
+
+void GeofenceAPIClient::geofenceAdd(uint32_t geofence_id, double latitude, double longitude,
+ double radius_meters, int32_t last_transition, int32_t monitor_transitions,
+ uint32_t notification_responsiveness_ms, uint32_t unknown_timer_ms)
+{
+ LOC_LOGD("%s]: (%d %f %f %f %d %d %d %d)", __FUNCTION__,
+ geofence_id, latitude, longitude, radius_meters,
+ last_transition, monitor_transitions, notification_responsiveness_ms, unknown_timer_ms);
+
+ GeofenceOption options;
+ memset(&options, 0, sizeof(GeofenceOption));
+ options.size = sizeof(GeofenceOption);
+ if (monitor_transitions & IGnssGeofenceCallback::GeofenceTransition::ENTERED)
+ options.breachTypeMask |= GEOFENCE_BREACH_ENTER_BIT;
+ if (monitor_transitions & IGnssGeofenceCallback::GeofenceTransition::EXITED)
+ options.breachTypeMask |= GEOFENCE_BREACH_EXIT_BIT;
+ options.responsiveness = notification_responsiveness_ms;
+
+ GeofenceInfo data;
+ data.size = sizeof(GeofenceInfo);
+ data.latitude = latitude;
+ data.longitude = longitude;
+ data.radius = radius_meters;
+
+ LocationError err = (LocationError)locAPIAddGeofences(1, &geofence_id, &options, &data);
+ if (LOCATION_ERROR_SUCCESS != err) {
+ onAddGeofencesCb(1, &err, &geofence_id);
+ }
+}
+
+void GeofenceAPIClient::geofencePause(uint32_t geofence_id)
+{
+ LOC_LOGD("%s]: (%d)", __FUNCTION__, geofence_id);
+ locAPIPauseGeofences(1, &geofence_id);
+}
+
+void GeofenceAPIClient::geofenceResume(uint32_t geofence_id, int32_t monitor_transitions)
+{
+ LOC_LOGD("%s]: (%d %d)", __FUNCTION__, geofence_id, monitor_transitions);
+ GeofenceBreachTypeMask mask = 0;
+ if (monitor_transitions & IGnssGeofenceCallback::GeofenceTransition::ENTERED)
+ mask |= GEOFENCE_BREACH_ENTER_BIT;
+ if (monitor_transitions & IGnssGeofenceCallback::GeofenceTransition::EXITED)
+ mask |= GEOFENCE_BREACH_EXIT_BIT;
+ locAPIResumeGeofences(1, &geofence_id, &mask);
+}
+
+void GeofenceAPIClient::geofenceRemove(uint32_t geofence_id)
+{
+ LOC_LOGD("%s]: (%d)", __FUNCTION__, geofence_id);
+ locAPIRemoveGeofences(1, &geofence_id);
+}
+
+void GeofenceAPIClient::geofenceRemoveAll()
+{
+ LOC_LOGD("%s]", __FUNCTION__);
+ // TODO locAPIRemoveAllGeofences();
+}
+
+// callbacks
+void GeofenceAPIClient::onGeofenceBreachCb(GeofenceBreachNotification geofenceBreachNotification)
+{
+ LOC_LOGD("%s]: (%zu)", __FUNCTION__, geofenceBreachNotification.count);
+ if (mGnssGeofencingCbIface != nullptr) {
+ for (size_t i = 0; i < geofenceBreachNotification.count; i++) {
+ GnssLocation gnssLocation;
+ convertGnssLocation(geofenceBreachNotification.location, gnssLocation);
+
+ IGnssGeofenceCallback::GeofenceTransition transition;
+ if (geofenceBreachNotification.type == GEOFENCE_BREACH_ENTER)
+ transition = IGnssGeofenceCallback::GeofenceTransition::ENTERED;
+ else if (geofenceBreachNotification.type == GEOFENCE_BREACH_EXIT)
+ transition = IGnssGeofenceCallback::GeofenceTransition::EXITED;
+ else {
+ // continue with other breach if transition is
+ // nether GPS_GEOFENCE_ENTERED nor GPS_GEOFENCE_EXITED
+ continue;
+ }
+
+ auto r = mGnssGeofencingCbIface->gnssGeofenceTransitionCb(
+ geofenceBreachNotification.ids[i], gnssLocation, transition,
+ static_cast<V1_0::GnssUtcTime>(geofenceBreachNotification.timestamp));
+ if (!r.isOk()) {
+ LOC_LOGE("%s] Error from gnssGeofenceTransitionCb description=%s",
+ __func__, r.description().c_str());
+ }
+ }
+ }
+}
+
+void GeofenceAPIClient::onGeofenceStatusCb(GeofenceStatusNotification geofenceStatusNotification)
+{
+ LOC_LOGD("%s]: (%d)", __FUNCTION__, geofenceStatusNotification.available);
+ if (mGnssGeofencingCbIface != nullptr) {
+ IGnssGeofenceCallback::GeofenceAvailability status =
+ IGnssGeofenceCallback::GeofenceAvailability::UNAVAILABLE;
+ if (geofenceStatusNotification.available == GEOFENCE_STATUS_AVAILABILE_YES) {
+ status = IGnssGeofenceCallback::GeofenceAvailability::AVAILABLE;
+ }
+ GnssLocation gnssLocation;
+ memset(&gnssLocation, 0, sizeof(GnssLocation));
+ auto r = mGnssGeofencingCbIface->gnssGeofenceStatusCb(status, gnssLocation);
+ if (!r.isOk()) {
+ LOC_LOGE("%s] Error from gnssGeofenceStatusCb description=%s",
+ __func__, r.description().c_str());
+ }
+ }
+}
+
+void GeofenceAPIClient::onAddGeofencesCb(size_t count, LocationError* errors, uint32_t* ids)
+{
+ LOC_LOGD("%s]: (%zu)", __FUNCTION__, count);
+ if (mGnssGeofencingCbIface != nullptr) {
+ for (size_t i = 0; i < count; i++) {
+ IGnssGeofenceCallback::GeofenceStatus status =
+ IGnssGeofenceCallback::GeofenceStatus::ERROR_GENERIC;
+ if (errors[i] == LOCATION_ERROR_SUCCESS)
+ status = IGnssGeofenceCallback::GeofenceStatus::OPERATION_SUCCESS;
+ else if (errors[i] == LOCATION_ERROR_ID_EXISTS)
+ status = IGnssGeofenceCallback::GeofenceStatus::ERROR_ID_EXISTS;
+ auto r = mGnssGeofencingCbIface->gnssGeofenceAddCb(ids[i], status);
+ if (!r.isOk()) {
+ LOC_LOGE("%s] Error from gnssGeofenceAddCb description=%s",
+ __func__, r.description().c_str());
+ }
+ }
+ }
+}
+
+void GeofenceAPIClient::onRemoveGeofencesCb(size_t count, LocationError* errors, uint32_t* ids)
+{
+ LOC_LOGD("%s]: (%zu)", __FUNCTION__, count);
+ if (mGnssGeofencingCbIface != nullptr) {
+ for (size_t i = 0; i < count; i++) {
+ IGnssGeofenceCallback::GeofenceStatus status =
+ IGnssGeofenceCallback::GeofenceStatus::ERROR_GENERIC;
+ if (errors[i] == LOCATION_ERROR_SUCCESS)
+ status = IGnssGeofenceCallback::GeofenceStatus::OPERATION_SUCCESS;
+ else if (errors[i] == LOCATION_ERROR_ID_UNKNOWN)
+ status = IGnssGeofenceCallback::GeofenceStatus::ERROR_ID_UNKNOWN;
+ auto r = mGnssGeofencingCbIface->gnssGeofenceRemoveCb(ids[i], status);
+ if (!r.isOk()) {
+ LOC_LOGE("%s] Error from gnssGeofenceRemoveCb description=%s",
+ __func__, r.description().c_str());
+ }
+ }
+ }
+}
+
+void GeofenceAPIClient::onPauseGeofencesCb(size_t count, LocationError* errors, uint32_t* ids)
+{
+ LOC_LOGD("%s]: (%zu)", __FUNCTION__, count);
+ if (mGnssGeofencingCbIface != nullptr) {
+ for (size_t i = 0; i < count; i++) {
+ IGnssGeofenceCallback::GeofenceStatus status =
+ IGnssGeofenceCallback::GeofenceStatus::ERROR_GENERIC;
+ if (errors[i] == LOCATION_ERROR_SUCCESS)
+ status = IGnssGeofenceCallback::GeofenceStatus::OPERATION_SUCCESS;
+ else if (errors[i] == LOCATION_ERROR_ID_UNKNOWN)
+ status = IGnssGeofenceCallback::GeofenceStatus::ERROR_ID_UNKNOWN;
+ auto r = mGnssGeofencingCbIface->gnssGeofencePauseCb(ids[i], status);
+ if (!r.isOk()) {
+ LOC_LOGE("%s] Error from gnssGeofencePauseCb description=%s",
+ __func__, r.description().c_str());
+ }
+ }
+ }
+}
+
+void GeofenceAPIClient::onResumeGeofencesCb(size_t count, LocationError* errors, uint32_t* ids)
+{
+ LOC_LOGD("%s]: (%zu)", __FUNCTION__, count);
+ if (mGnssGeofencingCbIface != nullptr) {
+ for (size_t i = 0; i < count; i++) {
+ IGnssGeofenceCallback::GeofenceStatus status =
+ IGnssGeofenceCallback::GeofenceStatus::ERROR_GENERIC;
+ if (errors[i] == LOCATION_ERROR_SUCCESS)
+ status = IGnssGeofenceCallback::GeofenceStatus::OPERATION_SUCCESS;
+ else if (errors[i] == LOCATION_ERROR_ID_UNKNOWN)
+ status = IGnssGeofenceCallback::GeofenceStatus::ERROR_ID_UNKNOWN;
+ auto r = mGnssGeofencingCbIface->gnssGeofenceResumeCb(ids[i], status);
+ if (!r.isOk()) {
+ LOC_LOGE("%s] Error from gnssGeofenceResumeCb description=%s",
+ __func__, r.description().c_str());
+ }
+ }
+ }
+}
+
+} // namespace implementation
+} // namespace V1_1
+} // namespace gnss
+} // namespace hardware
+} // namespace android
diff --git a/android/1.1/location_api/GeofenceAPIClient.h b/android/1.1/location_api/GeofenceAPIClient.h
new file mode 100644
index 0000000..c74a59a
--- /dev/null
+++ b/android/1.1/location_api/GeofenceAPIClient.h
@@ -0,0 +1,76 @@
+/* Copyright (c) 2017-2018, 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 GEOFENCE_API_CLINET_H
+#define GEOFENCE_API_CLINET_H
+
+
+#include <android/hardware/gnss/1.0/IGnssGeofenceCallback.h>
+#include <LocationAPIClientBase.h>
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace V1_1 {
+namespace implementation {
+
+using ::android::sp;
+
+class GeofenceAPIClient : public LocationAPIClientBase
+{
+public:
+ GeofenceAPIClient(const sp<V1_0::IGnssGeofenceCallback>& callback);
+ virtual ~GeofenceAPIClient() = default;
+
+ void geofenceAdd(uint32_t geofence_id, double latitude, double longitude,
+ double radius_meters, int32_t last_transition, int32_t monitor_transitions,
+ uint32_t notification_responsiveness_ms, uint32_t unknown_timer_ms);
+ void geofencePause(uint32_t geofence_id);
+ void geofenceResume(uint32_t geofence_id, int32_t monitor_transitions);
+ void geofenceRemove(uint32_t geofence_id);
+ void geofenceRemoveAll();
+
+ // callbacks
+ void onGeofenceBreachCb(GeofenceBreachNotification geofenceBreachNotification) final;
+ void onGeofenceStatusCb(GeofenceStatusNotification geofenceStatusNotification) final;
+ void onAddGeofencesCb(size_t count, LocationError* errors, uint32_t* ids) final;
+ void onRemoveGeofencesCb(size_t count, LocationError* errors, uint32_t* ids) final;
+ void onPauseGeofencesCb(size_t count, LocationError* errors, uint32_t* ids) final;
+ void onResumeGeofencesCb(size_t count, LocationError* errors, uint32_t* ids) final;
+
+private:
+ sp<V1_0::IGnssGeofenceCallback> mGnssGeofencingCbIface;
+};
+
+} // namespace implementation
+} // namespace V1_1
+} // namespace gnss
+} // namespace hardware
+} // namespace android
+#endif // GEOFENCE_API_CLINET_H
diff --git a/android/1.1/location_api/GnssAPIClient.cpp b/android/1.1/location_api/GnssAPIClient.cpp
new file mode 100644
index 0000000..9a95fdf
--- /dev/null
+++ b/android/1.1/location_api/GnssAPIClient.cpp
@@ -0,0 +1,566 @@
+/* Copyright (c) 2017-2019, 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_NDEBUG 0
+#define LOG_TAG "LocSvc_GnssAPIClient"
+#define SINGLE_SHOT_MIN_TRACKING_INTERVAL_MSEC (590 * 60 * 60 * 1000) // 590 hours
+
+#include <log_util.h>
+#include <loc_cfg.h>
+
+#include "LocationUtil.h"
+#include "GnssAPIClient.h"
+#include <LocContext.h>
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace V1_1 {
+namespace implementation {
+
+using ::android::hardware::gnss::V1_0::IGnss;
+using ::android::hardware::gnss::V1_0::IGnssCallback;
+using ::android::hardware::gnss::V1_0::IGnssNiCallback;
+using ::android::hardware::gnss::V1_0::GnssLocation;
+
+static void convertGnssSvStatus(GnssSvNotification& in, IGnssCallback::GnssSvStatus& out);
+
+GnssAPIClient::GnssAPIClient(const sp<IGnssCallback>& gpsCb,
+ const sp<IGnssNiCallback>& niCb) :
+ LocationAPIClientBase(),
+ mGnssCbIface(nullptr),
+ mGnssNiCbIface(nullptr),
+ mControlClient(new LocationAPIControlClient()),
+ mLocationCapabilitiesMask(0),
+ mLocationCapabilitiesCached(false)
+{
+ LOC_LOGD("%s]: (%p %p)", __FUNCTION__, &gpsCb, &niCb);
+
+ // set default LocationOptions.
+ memset(&mTrackingOptions, 0, sizeof(TrackingOptions));
+ mTrackingOptions.size = sizeof(TrackingOptions);
+ mTrackingOptions.minInterval = 1000;
+ mTrackingOptions.minDistance = 0;
+ mTrackingOptions.mode = GNSS_SUPL_MODE_STANDALONE;
+
+ gnssUpdateCallbacks(gpsCb, niCb);
+}
+
+GnssAPIClient::~GnssAPIClient()
+{
+ LOC_LOGD("%s]: ()", __FUNCTION__);
+ if (mControlClient) {
+ delete mControlClient;
+ mControlClient = nullptr;
+ }
+}
+
+// for GpsInterface
+void GnssAPIClient::gnssUpdateCallbacks(const sp<IGnssCallback>& gpsCb,
+ const sp<IGnssNiCallback>& niCb)
+{
+ LOC_LOGD("%s]: (%p %p)", __FUNCTION__, &gpsCb, &niCb);
+
+ mMutex.lock();
+ mGnssCbIface = gpsCb;
+ mGnssNiCbIface = niCb;
+ mMutex.unlock();
+
+ LocationCallbacks locationCallbacks;
+ memset(&locationCallbacks, 0, sizeof(LocationCallbacks));
+ locationCallbacks.size = sizeof(LocationCallbacks);
+
+ locationCallbacks.trackingCb = nullptr;
+ if (mGnssCbIface != nullptr) {
+ locationCallbacks.trackingCb = [this](Location location) {
+ onTrackingCb(location);
+ };
+ }
+
+ locationCallbacks.batchingCb = nullptr;
+ locationCallbacks.geofenceBreachCb = nullptr;
+ locationCallbacks.geofenceStatusCb = nullptr;
+ locationCallbacks.gnssLocationInfoCb = nullptr;
+
+ locationCallbacks.gnssNiCb = nullptr;
+ loc_core::ContextBase* context =
+ loc_core::LocContext::getLocContext(
+ NULL, NULL,
+ loc_core::LocContext::mLocationHalName, false);
+ if (mGnssNiCbIface != nullptr && !context->hasAgpsExtendedCapabilities()) {
+ LOC_LOGD("Registering NI CB");
+ locationCallbacks.gnssNiCb = [this](uint32_t id, GnssNiNotification gnssNiNotification) {
+ onGnssNiCb(id, gnssNiNotification);
+ };
+ }
+
+ locationCallbacks.gnssSvCb = nullptr;
+ if (mGnssCbIface != nullptr) {
+ locationCallbacks.gnssSvCb = [this](GnssSvNotification gnssSvNotification) {
+ onGnssSvCb(gnssSvNotification);
+ };
+ }
+
+ locationCallbacks.gnssNmeaCb = nullptr;
+ if (mGnssCbIface != nullptr) {
+ locationCallbacks.gnssNmeaCb = [this](GnssNmeaNotification gnssNmeaNotification) {
+ onGnssNmeaCb(gnssNmeaNotification);
+ };
+ }
+
+ locationCallbacks.gnssMeasurementsCb = nullptr;
+
+ locAPISetCallbacks(locationCallbacks);
+}
+
+bool GnssAPIClient::gnssStart()
+{
+ LOC_LOGD("%s]: ()", __FUNCTION__);
+ bool retVal = true;
+ locAPIStartTracking(mTrackingOptions);
+ return retVal;
+}
+
+bool GnssAPIClient::gnssStop()
+{
+ LOC_LOGD("%s]: ()", __FUNCTION__);
+ bool retVal = true;
+ locAPIStopTracking();
+ return retVal;
+}
+
+bool GnssAPIClient::gnssSetPositionMode(IGnss::GnssPositionMode mode,
+ IGnss::GnssPositionRecurrence recurrence, uint32_t minIntervalMs,
+ uint32_t preferredAccuracyMeters, uint32_t preferredTimeMs,
+ GnssPowerMode powerMode, uint32_t timeBetweenMeasurement)
+{
+ LOC_LOGD("%s]: (%d %d %d %d %d %d %d)", __FUNCTION__,
+ (int)mode, recurrence, minIntervalMs, preferredAccuracyMeters,
+ preferredTimeMs, (int)powerMode, timeBetweenMeasurement);
+ bool retVal = true;
+ memset(&mTrackingOptions, 0, sizeof(TrackingOptions));
+ mTrackingOptions.size = sizeof(TrackingOptions);
+ mTrackingOptions.minInterval = minIntervalMs;
+ if (IGnss::GnssPositionMode::MS_ASSISTED == mode ||
+ IGnss::GnssPositionRecurrence::RECURRENCE_SINGLE == recurrence) {
+ // We set a very large interval to simulate SINGLE mode. Once we report a fix,
+ // the caller should take the responsibility to stop the session.
+ // For MSA, we always treat it as SINGLE mode.
+ mTrackingOptions.minInterval = SINGLE_SHOT_MIN_TRACKING_INTERVAL_MSEC;
+ }
+ mTrackingOptions.minDistance = preferredAccuracyMeters;
+ if (mode == IGnss::GnssPositionMode::STANDALONE)
+ mTrackingOptions.mode = GNSS_SUPL_MODE_STANDALONE;
+ else if (mode == IGnss::GnssPositionMode::MS_BASED)
+ mTrackingOptions.mode = GNSS_SUPL_MODE_MSB;
+ else if (mode == IGnss::GnssPositionMode::MS_ASSISTED)
+ mTrackingOptions.mode = GNSS_SUPL_MODE_MSA;
+ else {
+ LOC_LOGD("%s]: invalid GnssPositionMode: %d", __FUNCTION__, (int)mode);
+ retVal = false;
+ }
+ if (GNSS_POWER_MODE_INVALID != powerMode) {
+ mTrackingOptions.powerMode = powerMode;
+ mTrackingOptions.tbm = timeBetweenMeasurement;
+ }
+ locAPIUpdateTrackingOptions(mTrackingOptions);
+ return retVal;
+}
+
+// for GpsNiInterface
+void GnssAPIClient::gnssNiRespond(int32_t notifId,
+ IGnssNiCallback::GnssUserResponseType userResponse)
+{
+ LOC_LOGD("%s]: (%d %d)", __FUNCTION__, notifId, static_cast<int>(userResponse));
+ GnssNiResponse data;
+ switch (userResponse) {
+ case IGnssNiCallback::GnssUserResponseType::RESPONSE_ACCEPT:
+ data = GNSS_NI_RESPONSE_ACCEPT;
+ break;
+ case IGnssNiCallback::GnssUserResponseType::RESPONSE_DENY:
+ data = GNSS_NI_RESPONSE_DENY;
+ break;
+ case IGnssNiCallback::GnssUserResponseType::RESPONSE_NORESP:
+ data = GNSS_NI_RESPONSE_NO_RESPONSE;
+ break;
+ default:
+ data = GNSS_NI_RESPONSE_IGNORE;
+ break;
+ }
+
+ locAPIGnssNiResponse(notifId, data);
+}
+
+// these apis using LocationAPIControlClient
+void GnssAPIClient::gnssDeleteAidingData(IGnss::GnssAidingData aidingDataFlags)
+{
+ LOC_LOGD("%s]: (%02hx)", __FUNCTION__, aidingDataFlags);
+ if (mControlClient == nullptr) {
+ return;
+ }
+ GnssAidingData data;
+ memset(&data, 0, sizeof (GnssAidingData));
+ data.sv.svTypeMask = GNSS_AIDING_DATA_SV_TYPE_GPS_BIT |
+ GNSS_AIDING_DATA_SV_TYPE_GLONASS_BIT |
+ GNSS_AIDING_DATA_SV_TYPE_QZSS_BIT |
+ GNSS_AIDING_DATA_SV_TYPE_BEIDOU_BIT |
+ GNSS_AIDING_DATA_SV_TYPE_GALILEO_BIT;
+ data.posEngineMask = STANDARD_POSITIONING_ENGINE;
+
+ if (aidingDataFlags == IGnss::GnssAidingData::DELETE_ALL)
+ data.deleteAll = true;
+ else {
+ if (aidingDataFlags & IGnss::GnssAidingData::DELETE_EPHEMERIS)
+ data.sv.svMask |= GNSS_AIDING_DATA_SV_EPHEMERIS_BIT;
+ if (aidingDataFlags & IGnss::GnssAidingData::DELETE_ALMANAC)
+ data.sv.svMask |= GNSS_AIDING_DATA_SV_ALMANAC_BIT;
+ if (aidingDataFlags & IGnss::GnssAidingData::DELETE_POSITION)
+ data.common.mask |= GNSS_AIDING_DATA_COMMON_POSITION_BIT;
+ if (aidingDataFlags & IGnss::GnssAidingData::DELETE_TIME)
+ data.common.mask |= GNSS_AIDING_DATA_COMMON_TIME_BIT;
+ if (aidingDataFlags & IGnss::GnssAidingData::DELETE_IONO)
+ data.sv.svMask |= GNSS_AIDING_DATA_SV_IONOSPHERE_BIT;
+ if (aidingDataFlags & IGnss::GnssAidingData::DELETE_UTC)
+ data.common.mask |= GNSS_AIDING_DATA_COMMON_UTC_BIT;
+ if (aidingDataFlags & IGnss::GnssAidingData::DELETE_HEALTH)
+ data.sv.svMask |= GNSS_AIDING_DATA_SV_HEALTH_BIT;
+ if (aidingDataFlags & IGnss::GnssAidingData::DELETE_SVDIR)
+ data.sv.svMask |= GNSS_AIDING_DATA_SV_DIRECTION_BIT;
+ if (aidingDataFlags & IGnss::GnssAidingData::DELETE_SVSTEER)
+ data.sv.svMask |= GNSS_AIDING_DATA_SV_STEER_BIT;
+ if (aidingDataFlags & IGnss::GnssAidingData::DELETE_SADATA)
+ data.sv.svMask |= GNSS_AIDING_DATA_SV_SA_DATA_BIT;
+ if (aidingDataFlags & IGnss::GnssAidingData::DELETE_RTI)
+ data.common.mask |= GNSS_AIDING_DATA_COMMON_RTI_BIT;
+ if (aidingDataFlags & IGnss::GnssAidingData::DELETE_CELLDB_INFO)
+ data.common.mask |= GNSS_AIDING_DATA_COMMON_CELLDB_BIT;
+ }
+ mControlClient->locAPIGnssDeleteAidingData(data);
+}
+
+void GnssAPIClient::gnssEnable(LocationTechnologyType techType)
+{
+ LOC_LOGD("%s]: (%0d)", __FUNCTION__, techType);
+ if (mControlClient == nullptr) {
+ return;
+ }
+ mControlClient->locAPIEnable(techType);
+}
+
+void GnssAPIClient::gnssDisable()
+{
+ LOC_LOGD("%s]: ()", __FUNCTION__);
+ if (mControlClient == nullptr) {
+ return;
+ }
+ mControlClient->locAPIDisable();
+}
+
+void GnssAPIClient::gnssConfigurationUpdate(const GnssConfig& gnssConfig)
+{
+ LOC_LOGD("%s]: (%02x)", __FUNCTION__, gnssConfig.flags);
+ if (mControlClient == nullptr) {
+ return;
+ }
+ mControlClient->locAPIGnssUpdateConfig(gnssConfig);
+}
+
+void GnssAPIClient::requestCapabilities() {
+ // only send capablities if it's already cached, otherwise the first time LocationAPI
+ // is initialized, capabilities will be sent by LocationAPI
+ if (mLocationCapabilitiesCached) {
+ onCapabilitiesCb(mLocationCapabilitiesMask);
+ }
+}
+
+// callbacks
+void GnssAPIClient::onCapabilitiesCb(LocationCapabilitiesMask capabilitiesMask)
+{
+ LOC_LOGD("%s]: (%02x)", __FUNCTION__, capabilitiesMask);
+ mLocationCapabilitiesMask = capabilitiesMask;
+ mLocationCapabilitiesCached = true;
+
+ mMutex.lock();
+ auto gnssCbIface(mGnssCbIface);
+ mMutex.unlock();
+
+ if (gnssCbIface != nullptr) {
+ uint32_t data = 0;
+ if ((capabilitiesMask & LOCATION_CAPABILITIES_TIME_BASED_TRACKING_BIT) ||
+ (capabilitiesMask & LOCATION_CAPABILITIES_TIME_BASED_BATCHING_BIT) ||
+ (capabilitiesMask & LOCATION_CAPABILITIES_DISTANCE_BASED_TRACKING_BIT) ||
+ (capabilitiesMask & LOCATION_CAPABILITIES_DISTANCE_BASED_BATCHING_BIT))
+ data |= IGnssCallback::Capabilities::SCHEDULING;
+ if (capabilitiesMask & LOCATION_CAPABILITIES_GEOFENCE_BIT)
+ data |= IGnssCallback::Capabilities::GEOFENCING;
+ if (capabilitiesMask & LOCATION_CAPABILITIES_GNSS_MEASUREMENTS_BIT)
+ data |= IGnssCallback::Capabilities::MEASUREMENTS;
+ if (capabilitiesMask & LOCATION_CAPABILITIES_GNSS_MSB_BIT)
+ data |= IGnssCallback::Capabilities::MSB;
+ if (capabilitiesMask & LOCATION_CAPABILITIES_GNSS_MSA_BIT)
+ data |= IGnssCallback::Capabilities::MSA;
+ auto r = gnssCbIface->gnssSetCapabilitesCb(data);
+ if (!r.isOk()) {
+ LOC_LOGE("%s] Error from gnssSetCapabilitesCb description=%s",
+ __func__, r.description().c_str());
+ }
+ }
+ if (gnssCbIface != nullptr) {
+ IGnssCallback::GnssSystemInfo gnssInfo;
+ if (capabilitiesMask & LOCATION_CAPABILITIES_CONSTELLATION_ENABLEMENT_BIT ||
+ capabilitiesMask & LOCATION_CAPABILITIES_AGPM_BIT) {
+ gnssInfo.yearOfHw = 2018;
+ } else if (capabilitiesMask & LOCATION_CAPABILITIES_DEBUG_NMEA_BIT) {
+ gnssInfo.yearOfHw = 2017;
+ } else if (capabilitiesMask & LOCATION_CAPABILITIES_GNSS_MEASUREMENTS_BIT) {
+ gnssInfo.yearOfHw = 2016;
+ } else {
+ gnssInfo.yearOfHw = 2015;
+ }
+ LOC_LOGV("%s:%d] set_system_info_cb (%d)", __FUNCTION__, __LINE__, gnssInfo.yearOfHw);
+ auto r = gnssCbIface->gnssSetSystemInfoCb(gnssInfo);
+ if (!r.isOk()) {
+ LOC_LOGE("%s] Error from gnssSetSystemInfoCb description=%s",
+ __func__, r.description().c_str());
+ }
+ }
+}
+
+void GnssAPIClient::onTrackingCb(Location location)
+{
+ LOC_LOGD("%s]: (flags: %02x)", __FUNCTION__, location.flags);
+ mMutex.lock();
+ auto gnssCbIface(mGnssCbIface);
+ mMutex.unlock();
+
+ if (gnssCbIface != nullptr) {
+ GnssLocation gnssLocation;
+ convertGnssLocation(location, gnssLocation);
+ auto r = gnssCbIface->gnssLocationCb(gnssLocation);
+ if (!r.isOk()) {
+ LOC_LOGE("%s] Error from gnssLocationCb description=%s",
+ __func__, r.description().c_str());
+ }
+ }
+}
+
+void GnssAPIClient::onGnssNiCb(uint32_t id, GnssNiNotification gnssNiNotification)
+{
+ LOC_LOGD("%s]: (id: %d)", __FUNCTION__, id);
+ mMutex.lock();
+ auto gnssNiCbIface(mGnssNiCbIface);
+ mMutex.unlock();
+
+ if (gnssNiCbIface == nullptr) {
+ LOC_LOGE("%s]: mGnssNiCbIface is nullptr", __FUNCTION__);
+ return;
+ }
+
+ IGnssNiCallback::GnssNiNotification notificationGnss = {};
+
+ notificationGnss.notificationId = id;
+
+ if (gnssNiNotification.type == GNSS_NI_TYPE_VOICE)
+ notificationGnss.niType = IGnssNiCallback::GnssNiType::VOICE;
+ else if (gnssNiNotification.type == GNSS_NI_TYPE_SUPL)
+ notificationGnss.niType = IGnssNiCallback::GnssNiType::UMTS_SUPL;
+ else if (gnssNiNotification.type == GNSS_NI_TYPE_CONTROL_PLANE)
+ notificationGnss.niType = IGnssNiCallback::GnssNiType::UMTS_CTRL_PLANE;
+ else if (gnssNiNotification.type == GNSS_NI_TYPE_EMERGENCY_SUPL)
+ notificationGnss.niType = IGnssNiCallback::GnssNiType::EMERGENCY_SUPL;
+
+ if (gnssNiNotification.options & GNSS_NI_OPTIONS_NOTIFICATION_BIT)
+ notificationGnss.notifyFlags |= IGnssNiCallback::GnssNiNotifyFlags::NEED_NOTIFY;
+ if (gnssNiNotification.options & GNSS_NI_OPTIONS_VERIFICATION_BIT)
+ notificationGnss.notifyFlags |= IGnssNiCallback::GnssNiNotifyFlags::NEED_VERIFY;
+ if (gnssNiNotification.options & GNSS_NI_OPTIONS_PRIVACY_OVERRIDE_BIT)
+ notificationGnss.notifyFlags |= IGnssNiCallback::GnssNiNotifyFlags::PRIVACY_OVERRIDE;
+
+ notificationGnss.timeoutSec = gnssNiNotification.timeout;
+
+ if (gnssNiNotification.timeoutResponse == GNSS_NI_RESPONSE_ACCEPT)
+ notificationGnss.defaultResponse = IGnssNiCallback::GnssUserResponseType::RESPONSE_ACCEPT;
+ else if (gnssNiNotification.timeoutResponse == GNSS_NI_RESPONSE_DENY)
+ notificationGnss.defaultResponse = IGnssNiCallback::GnssUserResponseType::RESPONSE_DENY;
+ else if (gnssNiNotification.timeoutResponse == GNSS_NI_RESPONSE_NO_RESPONSE ||
+ gnssNiNotification.timeoutResponse == GNSS_NI_RESPONSE_IGNORE)
+ notificationGnss.defaultResponse = IGnssNiCallback::GnssUserResponseType::RESPONSE_NORESP;
+
+ notificationGnss.requestorId = gnssNiNotification.requestor;
+
+ notificationGnss.notificationMessage = gnssNiNotification.message;
+
+ if (gnssNiNotification.requestorEncoding == GNSS_NI_ENCODING_TYPE_NONE)
+ notificationGnss.requestorIdEncoding =
+ IGnssNiCallback::GnssNiEncodingType::ENC_NONE;
+ else if (gnssNiNotification.requestorEncoding == GNSS_NI_ENCODING_TYPE_GSM_DEFAULT)
+ notificationGnss.requestorIdEncoding =
+ IGnssNiCallback::GnssNiEncodingType::ENC_SUPL_GSM_DEFAULT;
+ else if (gnssNiNotification.requestorEncoding == GNSS_NI_ENCODING_TYPE_UTF8)
+ notificationGnss.requestorIdEncoding =
+ IGnssNiCallback::GnssNiEncodingType::ENC_SUPL_UTF8;
+ else if (gnssNiNotification.requestorEncoding == GNSS_NI_ENCODING_TYPE_UCS2)
+ notificationGnss.requestorIdEncoding =
+ IGnssNiCallback::GnssNiEncodingType::ENC_SUPL_UCS2;
+
+ if (gnssNiNotification.messageEncoding == GNSS_NI_ENCODING_TYPE_NONE)
+ notificationGnss.notificationIdEncoding =
+ IGnssNiCallback::GnssNiEncodingType::ENC_NONE;
+ else if (gnssNiNotification.messageEncoding == GNSS_NI_ENCODING_TYPE_GSM_DEFAULT)
+ notificationGnss.notificationIdEncoding =
+ IGnssNiCallback::GnssNiEncodingType::ENC_SUPL_GSM_DEFAULT;
+ else if (gnssNiNotification.messageEncoding == GNSS_NI_ENCODING_TYPE_UTF8)
+ notificationGnss.notificationIdEncoding =
+ IGnssNiCallback::GnssNiEncodingType::ENC_SUPL_UTF8;
+ else if (gnssNiNotification.messageEncoding == GNSS_NI_ENCODING_TYPE_UCS2)
+ notificationGnss.notificationIdEncoding =
+ IGnssNiCallback::GnssNiEncodingType::ENC_SUPL_UCS2;
+
+ gnssNiCbIface->niNotifyCb(notificationGnss);
+}
+
+void GnssAPIClient::onGnssSvCb(GnssSvNotification gnssSvNotification)
+{
+ LOC_LOGD("%s]: (count: %zu)", __FUNCTION__, gnssSvNotification.count);
+ mMutex.lock();
+ auto gnssCbIface(mGnssCbIface);
+ mMutex.unlock();
+
+ if (gnssCbIface != nullptr) {
+ IGnssCallback::GnssSvStatus svStatus;
+ convertGnssSvStatus(gnssSvNotification, svStatus);
+ auto r = gnssCbIface->gnssSvStatusCb(svStatus);
+ if (!r.isOk()) {
+ LOC_LOGE("%s] Error from gnssSvStatusCb description=%s",
+ __func__, r.description().c_str());
+ }
+ }
+}
+
+void GnssAPIClient::onGnssNmeaCb(GnssNmeaNotification gnssNmeaNotification)
+{
+ mMutex.lock();
+ auto gnssCbIface(mGnssCbIface);
+ mMutex.unlock();
+
+ if (gnssCbIface != nullptr) {
+ const std::string s(gnssNmeaNotification.nmea);
+ std::stringstream ss(s);
+ std::string each;
+ while(std::getline(ss, each, '\n')) {
+ each += '\n';
+ android::hardware::hidl_string nmeaString;
+ nmeaString.setToExternal(each.c_str(), each.length());
+ auto r = gnssCbIface->gnssNmeaCb(
+ static_cast<V1_0::GnssUtcTime>(gnssNmeaNotification.timestamp), nmeaString);
+ if (!r.isOk()) {
+ LOC_LOGE("%s] Error from gnssNmeaCb nmea=%s length=%zu description=%s", __func__,
+ gnssNmeaNotification.nmea, gnssNmeaNotification.length,
+ r.description().c_str());
+ }
+ }
+ }
+}
+
+void GnssAPIClient::onStartTrackingCb(LocationError error)
+{
+ LOC_LOGD("%s]: (%d)", __FUNCTION__, error);
+ mMutex.lock();
+ auto gnssCbIface(mGnssCbIface);
+ mMutex.unlock();
+
+ if (error == LOCATION_ERROR_SUCCESS && gnssCbIface != nullptr) {
+ auto r = gnssCbIface->gnssStatusCb(IGnssCallback::GnssStatusValue::ENGINE_ON);
+ if (!r.isOk()) {
+ LOC_LOGE("%s] Error from gnssStatusCb ENGINE_ON description=%s",
+ __func__, r.description().c_str());
+ }
+ r = gnssCbIface->gnssStatusCb(IGnssCallback::GnssStatusValue::SESSION_BEGIN);
+ if (!r.isOk()) {
+ LOC_LOGE("%s] Error from gnssStatusCb SESSION_BEGIN description=%s",
+ __func__, r.description().c_str());
+ }
+ }
+}
+
+void GnssAPIClient::onStopTrackingCb(LocationError error)
+{
+ LOC_LOGD("%s]: (%d)", __FUNCTION__, error);
+ mMutex.lock();
+ auto gnssCbIface(mGnssCbIface);
+ mMutex.unlock();
+
+ if (error == LOCATION_ERROR_SUCCESS && gnssCbIface != nullptr) {
+ auto r = gnssCbIface->gnssStatusCb(IGnssCallback::GnssStatusValue::SESSION_END);
+ if (!r.isOk()) {
+ LOC_LOGE("%s] Error from gnssStatusCb SESSION_END description=%s",
+ __func__, r.description().c_str());
+ }
+ r = gnssCbIface->gnssStatusCb(IGnssCallback::GnssStatusValue::ENGINE_OFF);
+ if (!r.isOk()) {
+ LOC_LOGE("%s] Error from gnssStatusCb ENGINE_OFF description=%s",
+ __func__, r.description().c_str());
+ }
+ }
+}
+
+static void convertGnssSvStatus(GnssSvNotification& in, IGnssCallback::GnssSvStatus& out)
+{
+ memset(&out, 0, sizeof(IGnssCallback::GnssSvStatus));
+ out.numSvs = in.count;
+ if (out.numSvs > static_cast<uint32_t>(V1_0::GnssMax::SVS_COUNT)) {
+ LOC_LOGW("%s]: Too many satellites %u. Clamps to %d.",
+ __FUNCTION__, out.numSvs, V1_0::GnssMax::SVS_COUNT);
+ out.numSvs = static_cast<uint32_t>(V1_0::GnssMax::SVS_COUNT);
+ }
+ for (size_t i = 0; i < out.numSvs; i++) {
+ IGnssCallback::GnssSvInfo& info = out.gnssSvList[i];
+ info.svid = in.gnssSvs[i].svId;
+ convertGnssConstellationType(in.gnssSvs[i].type, info.constellation);
+ info.cN0Dbhz = in.gnssSvs[i].cN0Dbhz;
+ info.elevationDegrees = in.gnssSvs[i].elevation;
+ info.azimuthDegrees = in.gnssSvs[i].azimuth;
+ info.carrierFrequencyHz = in.gnssSvs[i].carrierFrequencyHz;
+ info.svFlag = static_cast<uint8_t>(IGnssCallback::GnssSvFlags::NONE);
+ if (in.gnssSvs[i].gnssSvOptionsMask & GNSS_SV_OPTIONS_HAS_EPHEMER_BIT)
+ info.svFlag |= IGnssCallback::GnssSvFlags::HAS_EPHEMERIS_DATA;
+ if (in.gnssSvs[i].gnssSvOptionsMask & GNSS_SV_OPTIONS_HAS_ALMANAC_BIT)
+ info.svFlag |= IGnssCallback::GnssSvFlags::HAS_ALMANAC_DATA;
+ if (in.gnssSvs[i].gnssSvOptionsMask & GNSS_SV_OPTIONS_USED_IN_FIX_BIT)
+ info.svFlag |= IGnssCallback::GnssSvFlags::USED_IN_FIX;
+ if (in.gnssSvs[i].gnssSvOptionsMask & GNSS_SV_OPTIONS_HAS_CARRIER_FREQUENCY_BIT)
+ info.svFlag |= IGnssCallback::GnssSvFlags::HAS_CARRIER_FREQUENCY;
+ }
+}
+
+} // namespace implementation
+} // namespace V1_1
+} // namespace gnss
+} // namespace hardware
+} // namespace android
diff --git a/android/1.1/location_api/GnssAPIClient.h b/android/1.1/location_api/GnssAPIClient.h
new file mode 100644
index 0000000..82f8fbf
--- /dev/null
+++ b/android/1.1/location_api/GnssAPIClient.h
@@ -0,0 +1,109 @@
+/* Copyright (c) 2017-2018, 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 GNSS_API_CLINET_H
+#define GNSS_API_CLINET_H
+
+
+#include <mutex>
+#include <android/hardware/gnss/1.1/IGnss.h>
+#include <android/hardware/gnss/1.1/IGnssCallback.h>
+#include <android/hardware/gnss/1.0/IGnssNiCallback.h>
+#include <LocationAPIClientBase.h>
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace V1_1 {
+namespace implementation {
+
+using ::android::sp;
+
+class GnssAPIClient : public LocationAPIClientBase
+{
+public:
+ GnssAPIClient(const sp<V1_0::IGnssCallback>& gpsCb,
+ const sp<V1_0::IGnssNiCallback>& niCb);
+ virtual ~GnssAPIClient();
+ GnssAPIClient(const GnssAPIClient&) = delete;
+ GnssAPIClient& operator=(const GnssAPIClient&) = delete;
+
+ // for GpsInterface
+ void gnssUpdateCallbacks(const sp<V1_0::IGnssCallback>& gpsCb,
+ const sp<V1_0::IGnssNiCallback>& niCb);
+ bool gnssStart();
+ bool gnssStop();
+ bool gnssSetPositionMode(V1_0::IGnss::GnssPositionMode mode,
+ V1_0::IGnss::GnssPositionRecurrence recurrence,
+ uint32_t minIntervalMs,
+ uint32_t preferredAccuracyMeters,
+ uint32_t preferredTimeMs,
+ GnssPowerMode powerMode = GNSS_POWER_MODE_INVALID,
+ uint32_t timeBetweenMeasurement = 0);
+
+ // for GpsNiInterface
+ void gnssNiRespond(int32_t notifId, V1_0::IGnssNiCallback::GnssUserResponseType userResponse);
+
+ // these apis using LocationAPIControlClient
+ void gnssDeleteAidingData(V1_0::IGnss::GnssAidingData aidingDataFlags);
+ void gnssEnable(LocationTechnologyType techType);
+ void gnssDisable();
+ void gnssConfigurationUpdate(const GnssConfig& gnssConfig);
+
+ inline LocationCapabilitiesMask gnssGetCapabilities() const {
+ return mLocationCapabilitiesMask;
+ }
+ void requestCapabilities();
+
+ // callbacks we are interested in
+ void onCapabilitiesCb(LocationCapabilitiesMask capabilitiesMask) final;
+ void onTrackingCb(Location location) final;
+ void onGnssNiCb(uint32_t id, GnssNiNotification gnssNiNotification) final;
+ void onGnssSvCb(GnssSvNotification gnssSvNotification) final;
+ void onGnssNmeaCb(GnssNmeaNotification gnssNmeaNotification) final;
+
+ void onStartTrackingCb(LocationError error) final;
+ void onStopTrackingCb(LocationError error) final;
+
+private:
+ sp<V1_0::IGnssCallback> mGnssCbIface;
+ sp<V1_0::IGnssNiCallback> mGnssNiCbIface;
+ std::mutex mMutex;
+ LocationAPIControlClient* mControlClient;
+ LocationCapabilitiesMask mLocationCapabilitiesMask;
+ bool mLocationCapabilitiesCached;
+ TrackingOptions mTrackingOptions;
+};
+
+} // namespace implementation
+} // namespace V1_1
+} // namespace gnss
+} // namespace hardware
+} // namespace android
+#endif // GNSS_API_CLINET_H
diff --git a/android/1.1/location_api/LocationUtil.cpp b/android/1.1/location_api/LocationUtil.cpp
new file mode 100644
index 0000000..f1d051c
--- /dev/null
+++ b/android/1.1/location_api/LocationUtil.cpp
@@ -0,0 +1,206 @@
+/* Copyright (c) 2017-2018, 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.
+ *
+ */
+
+#include <LocationUtil.h>
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace V1_1 {
+namespace implementation {
+
+using ::android::hardware::gnss::V1_0::GnssLocation;
+using ::android::hardware::gnss::V1_0::GnssConstellationType;
+using ::android::hardware::gnss::V1_0::GnssLocationFlags;
+
+void convertGnssLocation(Location& in, GnssLocation& out)
+{
+ memset(&out, 0, sizeof(GnssLocation));
+ if (in.flags & LOCATION_HAS_LAT_LONG_BIT) {
+ out.gnssLocationFlags |= GnssLocationFlags::HAS_LAT_LONG;
+ out.latitudeDegrees = in.latitude;
+ out.longitudeDegrees = in.longitude;
+ }
+ if (in.flags & LOCATION_HAS_ALTITUDE_BIT) {
+ out.gnssLocationFlags |= GnssLocationFlags::HAS_ALTITUDE;
+ out.altitudeMeters = in.altitude;
+ }
+ if (in.flags & LOCATION_HAS_SPEED_BIT) {
+ out.gnssLocationFlags |= GnssLocationFlags::HAS_SPEED;
+ out.speedMetersPerSec = in.speed;
+ }
+ if (in.flags & LOCATION_HAS_BEARING_BIT) {
+ out.gnssLocationFlags |= GnssLocationFlags::HAS_BEARING;
+ out.bearingDegrees = in.bearing;
+ }
+ if (in.flags & LOCATION_HAS_ACCURACY_BIT) {
+ out.gnssLocationFlags |= GnssLocationFlags::HAS_HORIZONTAL_ACCURACY;
+ out.horizontalAccuracyMeters = in.accuracy;
+ }
+ if (in.flags & LOCATION_HAS_VERTICAL_ACCURACY_BIT) {
+ out.gnssLocationFlags |= GnssLocationFlags::HAS_VERTICAL_ACCURACY;
+ out.verticalAccuracyMeters = in.verticalAccuracy;
+ }
+ if (in.flags & LOCATION_HAS_SPEED_ACCURACY_BIT) {
+ out.gnssLocationFlags |= GnssLocationFlags::HAS_SPEED_ACCURACY;
+ out.speedAccuracyMetersPerSecond = in.speedAccuracy;
+ }
+ if (in.flags & LOCATION_HAS_BEARING_ACCURACY_BIT) {
+ out.gnssLocationFlags |= GnssLocationFlags::HAS_BEARING_ACCURACY;
+ out.bearingAccuracyDegrees = in.bearingAccuracy;
+ }
+
+ out.timestamp = static_cast<V1_0::GnssUtcTime>(in.timestamp);
+}
+
+void convertGnssLocation(const GnssLocation& in, Location& out)
+{
+ memset(&out, 0, sizeof(out));
+ if (in.gnssLocationFlags & GnssLocationFlags::HAS_LAT_LONG) {
+ out.flags |= LOCATION_HAS_LAT_LONG_BIT;
+ out.latitude = in.latitudeDegrees;
+ out.longitude = in.longitudeDegrees;
+ }
+ if (in.gnssLocationFlags & GnssLocationFlags::HAS_ALTITUDE) {
+ out.flags |= LOCATION_HAS_ALTITUDE_BIT;
+ out.altitude = in.altitudeMeters;
+ }
+ if (in.gnssLocationFlags & GnssLocationFlags::HAS_SPEED) {
+ out.flags |= LOCATION_HAS_SPEED_BIT;
+ out.speed = in.speedMetersPerSec;
+ }
+ if (in.gnssLocationFlags & GnssLocationFlags::HAS_BEARING) {
+ out.flags |= LOCATION_HAS_BEARING_BIT;
+ out.bearing = in.bearingDegrees;
+ }
+ if (in.gnssLocationFlags & GnssLocationFlags::HAS_HORIZONTAL_ACCURACY) {
+ out.flags |= LOCATION_HAS_ACCURACY_BIT;
+ out.accuracy = in.horizontalAccuracyMeters;
+ }
+ if (in.gnssLocationFlags & GnssLocationFlags::HAS_VERTICAL_ACCURACY) {
+ out.flags |= LOCATION_HAS_VERTICAL_ACCURACY_BIT;
+ out.verticalAccuracy = in.verticalAccuracyMeters;
+ }
+ if (in.gnssLocationFlags & GnssLocationFlags::HAS_SPEED_ACCURACY) {
+ out.flags |= LOCATION_HAS_SPEED_ACCURACY_BIT;
+ out.speedAccuracy = in.speedAccuracyMetersPerSecond;
+ }
+ if (in.gnssLocationFlags & GnssLocationFlags::HAS_BEARING_ACCURACY) {
+ out.flags |= LOCATION_HAS_BEARING_ACCURACY_BIT;
+ out.bearingAccuracy = in.bearingAccuracyDegrees;
+ }
+
+ out.timestamp = static_cast<uint64_t>(in.timestamp);
+}
+
+void convertGnssConstellationType(GnssSvType& in, GnssConstellationType& out)
+{
+ switch(in) {
+ case GNSS_SV_TYPE_GPS:
+ out = GnssConstellationType::GPS;
+ break;
+ case GNSS_SV_TYPE_SBAS:
+ out = GnssConstellationType::SBAS;
+ break;
+ case GNSS_SV_TYPE_GLONASS:
+ out = GnssConstellationType::GLONASS;
+ break;
+ case GNSS_SV_TYPE_QZSS:
+ out = GnssConstellationType::QZSS;
+ break;
+ case GNSS_SV_TYPE_BEIDOU:
+ out = GnssConstellationType::BEIDOU;
+ break;
+ case GNSS_SV_TYPE_GALILEO:
+ out = GnssConstellationType::GALILEO;
+ break;
+ case GNSS_SV_TYPE_UNKNOWN:
+ default:
+ out = GnssConstellationType::UNKNOWN;
+ break;
+ }
+}
+
+void convertGnssEphemerisType(GnssEphemerisType& in, GnssDebug::SatelliteEphemerisType& out)
+{
+ switch(in) {
+ case GNSS_EPH_TYPE_EPHEMERIS:
+ out = GnssDebug::SatelliteEphemerisType::EPHEMERIS;
+ break;
+ case GNSS_EPH_TYPE_ALMANAC:
+ out = GnssDebug::SatelliteEphemerisType::ALMANAC_ONLY;
+ break;
+ case GNSS_EPH_TYPE_UNKNOWN:
+ default:
+ out = GnssDebug::SatelliteEphemerisType::NOT_AVAILABLE;
+ break;
+ }
+}
+
+void convertGnssEphemerisSource(GnssEphemerisSource& in, GnssDebug::SatelliteEphemerisSource& out)
+{
+ switch(in) {
+ case GNSS_EPH_SOURCE_DEMODULATED:
+ out = GnssDebug::SatelliteEphemerisSource::DEMODULATED;
+ break;
+ case GNSS_EPH_SOURCE_SUPL_PROVIDED:
+ out = GnssDebug::SatelliteEphemerisSource::SUPL_PROVIDED;
+ break;
+ case GNSS_EPH_SOURCE_OTHER_SERVER_PROVIDED:
+ out = GnssDebug::SatelliteEphemerisSource::OTHER_SERVER_PROVIDED;
+ break;
+ case GNSS_EPH_SOURCE_LOCAL:
+ case GNSS_EPH_SOURCE_UNKNOWN:
+ default:
+ out = GnssDebug::SatelliteEphemerisSource::OTHER;
+ break;
+ }
+}
+
+void convertGnssEphemerisHealth(GnssEphemerisHealth& in, GnssDebug::SatelliteEphemerisHealth& out)
+{
+ switch(in) {
+ case GNSS_EPH_HEALTH_GOOD:
+ out = GnssDebug::SatelliteEphemerisHealth::GOOD;
+ break;
+ case GNSS_EPH_HEALTH_BAD:
+ out = GnssDebug::SatelliteEphemerisHealth::BAD;
+ break;
+ case GNSS_EPH_HEALTH_UNKNOWN:
+ default:
+ out = GnssDebug::SatelliteEphemerisHealth::UNKNOWN;
+ break;
+ }
+}
+
+} // namespace implementation
+} // namespace V1_1
+} // namespace gnss
+} // namespace hardware
+} // namespace android
diff --git a/android/1.1/location_api/LocationUtil.h b/android/1.1/location_api/LocationUtil.h
new file mode 100644
index 0000000..63f4f6f
--- /dev/null
+++ b/android/1.1/location_api/LocationUtil.h
@@ -0,0 +1,55 @@
+/* Copyright (c) 2017-2018, 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_UTIL_H
+#define LOCATION_UTIL_H
+
+#include <android/hardware/gnss/1.0/types.h>
+#include <LocationAPI.h>
+#include <GnssDebug.h>
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace V1_1 {
+namespace implementation {
+
+void convertGnssLocation(Location& in, V1_0::GnssLocation& out);
+void convertGnssLocation(const V1_0::GnssLocation& in, Location& out);
+void convertGnssConstellationType(GnssSvType& in, V1_0::GnssConstellationType& out);
+void convertGnssEphemerisType(GnssEphemerisType& in, GnssDebug::SatelliteEphemerisType& out);
+void convertGnssEphemerisSource(GnssEphemerisSource& in, GnssDebug::SatelliteEphemerisSource& out);
+void convertGnssEphemerisHealth(GnssEphemerisHealth& in, GnssDebug::SatelliteEphemerisHealth& out);
+
+} // namespace implementation
+} // namespace V1_1
+} // namespace gnss
+} // namespace hardware
+} // namespace android
+#endif // LOCATION_UTIL_H
diff --git a/android/1.1/location_api/MeasurementAPIClient.cpp b/android/1.1/location_api/MeasurementAPIClient.cpp
new file mode 100644
index 0000000..6f25067
--- /dev/null
+++ b/android/1.1/location_api/MeasurementAPIClient.cpp
@@ -0,0 +1,332 @@
+/* Copyright (c) 2017-2018, 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_NDEBUG 0
+#define LOG_TAG "LocSvc_MeasurementAPIClient"
+
+#include <log_util.h>
+#include <loc_cfg.h>
+
+#include "LocationUtil.h"
+#include "MeasurementAPIClient.h"
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace V1_1 {
+namespace implementation {
+
+using ::android::hardware::gnss::V1_0::IGnssMeasurement;
+using ::android::hardware::gnss::V1_1::IGnssMeasurementCallback;
+
+static void convertGnssData(GnssMeasurementsNotification& in,
+ V1_0::IGnssMeasurementCallback::GnssData& out);
+static void convertGnssData_1_1(GnssMeasurementsNotification& in,
+ IGnssMeasurementCallback::GnssData& out);
+static void convertGnssMeasurement(GnssMeasurementsData& in,
+ V1_0::IGnssMeasurementCallback::GnssMeasurement& out);
+static void convertGnssClock(GnssMeasurementsClock& in, IGnssMeasurementCallback::GnssClock& out);
+
+MeasurementAPIClient::MeasurementAPIClient() :
+ mGnssMeasurementCbIface(nullptr),
+ mGnssMeasurementCbIface_1_1(nullptr),
+ mTracking(false)
+{
+ LOC_LOGD("%s]: ()", __FUNCTION__);
+}
+
+MeasurementAPIClient::~MeasurementAPIClient()
+{
+ LOC_LOGD("%s]: ()", __FUNCTION__);
+}
+
+// for GpsInterface
+Return<IGnssMeasurement::GnssMeasurementStatus>
+MeasurementAPIClient::measurementSetCallback(const sp<V1_0::IGnssMeasurementCallback>& callback)
+{
+ LOC_LOGD("%s]: (%p)", __FUNCTION__, &callback);
+
+ mMutex.lock();
+ mGnssMeasurementCbIface = callback;
+ mMutex.unlock();
+
+ return startTracking();
+}
+
+Return<IGnssMeasurement::GnssMeasurementStatus>
+MeasurementAPIClient::measurementSetCallback_1_1(
+ const sp<IGnssMeasurementCallback>& callback,
+ GnssPowerMode powerMode, uint32_t timeBetweenMeasurement)
+{
+ LOC_LOGD("%s]: (%p) (powermode: %d) (tbm: %d)",
+ __FUNCTION__, &callback, (int)powerMode, timeBetweenMeasurement);
+
+ mMutex.lock();
+ mGnssMeasurementCbIface_1_1 = callback;
+ mMutex.unlock();
+
+ return startTracking(powerMode, timeBetweenMeasurement);
+}
+
+Return<IGnssMeasurement::GnssMeasurementStatus>
+MeasurementAPIClient::startTracking(
+ GnssPowerMode powerMode, uint32_t timeBetweenMeasurement)
+{
+ LocationCallbacks locationCallbacks;
+ memset(&locationCallbacks, 0, sizeof(LocationCallbacks));
+ locationCallbacks.size = sizeof(LocationCallbacks);
+
+ locationCallbacks.trackingCb = nullptr;
+ locationCallbacks.batchingCb = nullptr;
+ locationCallbacks.geofenceBreachCb = nullptr;
+ locationCallbacks.geofenceStatusCb = nullptr;
+ locationCallbacks.gnssLocationInfoCb = nullptr;
+ locationCallbacks.gnssNiCb = nullptr;
+ locationCallbacks.gnssSvCb = nullptr;
+ locationCallbacks.gnssNmeaCb = nullptr;
+
+ locationCallbacks.gnssMeasurementsCb = nullptr;
+ if (mGnssMeasurementCbIface_1_1 != nullptr || mGnssMeasurementCbIface != nullptr) {
+ locationCallbacks.gnssMeasurementsCb =
+ [this](GnssMeasurementsNotification gnssMeasurementsNotification) {
+ onGnssMeasurementsCb(gnssMeasurementsNotification);
+ };
+ }
+
+ locAPISetCallbacks(locationCallbacks);
+
+ TrackingOptions options = {};
+ memset(&options, 0, sizeof(TrackingOptions));
+ options.size = sizeof(TrackingOptions);
+ options.minInterval = 1000;
+ options.mode = GNSS_SUPL_MODE_STANDALONE;
+ if (GNSS_POWER_MODE_INVALID != powerMode) {
+ options.powerMode = powerMode;
+ options.tbm = timeBetweenMeasurement;
+ }
+
+ mTracking = true;
+ LOC_LOGD("%s]: start tracking session", __FUNCTION__);
+ locAPIStartTracking(options);
+ return IGnssMeasurement::GnssMeasurementStatus::SUCCESS;
+}
+
+// for GpsMeasurementInterface
+void MeasurementAPIClient::measurementClose() {
+ LOC_LOGD("%s]: ()", __FUNCTION__);
+ mTracking = false;
+ locAPIStopTracking();
+}
+
+// callbacks
+void MeasurementAPIClient::onGnssMeasurementsCb(
+ GnssMeasurementsNotification gnssMeasurementsNotification)
+{
+ LOC_LOGD("%s]: (count: %zu active: %d)",
+ __FUNCTION__, gnssMeasurementsNotification.count, mTracking);
+ if (mTracking) {
+ mMutex.lock();
+ sp<V1_0::IGnssMeasurementCallback> gnssMeasurementCbIface = nullptr;
+ sp<IGnssMeasurementCallback> gnssMeasurementCbIface_1_1 = nullptr;
+ if (mGnssMeasurementCbIface_1_1 != nullptr) {
+ gnssMeasurementCbIface_1_1 = mGnssMeasurementCbIface_1_1;
+ } else if (mGnssMeasurementCbIface != nullptr) {
+ gnssMeasurementCbIface = mGnssMeasurementCbIface;
+ }
+ mMutex.unlock();
+
+ if (gnssMeasurementCbIface_1_1 != nullptr) {
+ IGnssMeasurementCallback::GnssData gnssData;
+ convertGnssData_1_1(gnssMeasurementsNotification, gnssData);
+ auto r = gnssMeasurementCbIface_1_1->gnssMeasurementCb(gnssData);
+ if (!r.isOk()) {
+ LOC_LOGE("%s] Error from gnssMeasurementCb description=%s",
+ __func__, r.description().c_str());
+ }
+ } else if (gnssMeasurementCbIface != nullptr) {
+ V1_0::IGnssMeasurementCallback::GnssData gnssData;
+ convertGnssData(gnssMeasurementsNotification, gnssData);
+ auto r = gnssMeasurementCbIface->GnssMeasurementCb(gnssData);
+ if (!r.isOk()) {
+ LOC_LOGE("%s] Error from GnssMeasurementCb description=%s",
+ __func__, r.description().c_str());
+ }
+ }
+ }
+}
+
+static void convertGnssMeasurement(GnssMeasurementsData& in,
+ V1_0::IGnssMeasurementCallback::GnssMeasurement& out)
+{
+ memset(&out, 0, sizeof(IGnssMeasurementCallback::GnssMeasurement));
+ if (in.flags & GNSS_MEASUREMENTS_DATA_SIGNAL_TO_NOISE_RATIO_BIT)
+ out.flags |= IGnssMeasurementCallback::GnssMeasurementFlags::HAS_SNR;
+ if (in.flags & GNSS_MEASUREMENTS_DATA_CARRIER_FREQUENCY_BIT)
+ out.flags |= IGnssMeasurementCallback::GnssMeasurementFlags::HAS_CARRIER_FREQUENCY;
+ if (in.flags & GNSS_MEASUREMENTS_DATA_CARRIER_CYCLES_BIT)
+ out.flags |= IGnssMeasurementCallback::GnssMeasurementFlags::HAS_CARRIER_CYCLES;
+ if (in.flags & GNSS_MEASUREMENTS_DATA_CARRIER_PHASE_BIT)
+ out.flags |= IGnssMeasurementCallback::GnssMeasurementFlags::HAS_CARRIER_PHASE;
+ if (in.flags & GNSS_MEASUREMENTS_DATA_CARRIER_PHASE_UNCERTAINTY_BIT)
+ out.flags |= IGnssMeasurementCallback::GnssMeasurementFlags::HAS_CARRIER_PHASE_UNCERTAINTY;
+ if (in.flags & GNSS_MEASUREMENTS_DATA_AUTOMATIC_GAIN_CONTROL_BIT)
+ out.flags |= IGnssMeasurementCallback::GnssMeasurementFlags::HAS_AUTOMATIC_GAIN_CONTROL;
+ out.svid = in.svId;
+ convertGnssConstellationType(in.svType, out.constellation);
+ out.timeOffsetNs = in.timeOffsetNs;
+ if (in.stateMask & GNSS_MEASUREMENTS_STATE_CODE_LOCK_BIT)
+ out.state |= IGnssMeasurementCallback::GnssMeasurementState::STATE_CODE_LOCK;
+ if (in.stateMask & GNSS_MEASUREMENTS_STATE_BIT_SYNC_BIT)
+ out.state |= IGnssMeasurementCallback::GnssMeasurementState::STATE_BIT_SYNC;
+ if (in.stateMask & GNSS_MEASUREMENTS_STATE_SUBFRAME_SYNC_BIT)
+ out.state |= IGnssMeasurementCallback::GnssMeasurementState::STATE_SUBFRAME_SYNC;
+ if (in.stateMask & GNSS_MEASUREMENTS_STATE_TOW_DECODED_BIT)
+ out.state |= IGnssMeasurementCallback::GnssMeasurementState::STATE_TOW_DECODED;
+ if (in.stateMask & GNSS_MEASUREMENTS_STATE_MSEC_AMBIGUOUS_BIT)
+ out.state |= IGnssMeasurementCallback::GnssMeasurementState::STATE_MSEC_AMBIGUOUS;
+ if (in.stateMask & GNSS_MEASUREMENTS_STATE_SYMBOL_SYNC_BIT)
+ out.state |= IGnssMeasurementCallback::GnssMeasurementState::STATE_SYMBOL_SYNC;
+ if (in.stateMask & GNSS_MEASUREMENTS_STATE_GLO_STRING_SYNC_BIT)
+ out.state |= IGnssMeasurementCallback::GnssMeasurementState::STATE_GLO_STRING_SYNC;
+ if (in.stateMask & GNSS_MEASUREMENTS_STATE_GLO_TOD_DECODED_BIT)
+ out.state |= IGnssMeasurementCallback::GnssMeasurementState::STATE_GLO_TOD_DECODED;
+ if (in.stateMask & GNSS_MEASUREMENTS_STATE_BDS_D2_BIT_SYNC_BIT)
+ out.state |= IGnssMeasurementCallback::GnssMeasurementState::STATE_BDS_D2_BIT_SYNC;
+ if (in.stateMask & GNSS_MEASUREMENTS_STATE_BDS_D2_SUBFRAME_SYNC_BIT)
+ out.state |= IGnssMeasurementCallback::GnssMeasurementState::STATE_BDS_D2_SUBFRAME_SYNC;
+ if (in.stateMask & GNSS_MEASUREMENTS_STATE_GAL_E1BC_CODE_LOCK_BIT)
+ out.state |= IGnssMeasurementCallback::GnssMeasurementState::STATE_GAL_E1BC_CODE_LOCK;
+ if (in.stateMask & GNSS_MEASUREMENTS_STATE_GAL_E1C_2ND_CODE_LOCK_BIT)
+ out.state |= IGnssMeasurementCallback::GnssMeasurementState::STATE_GAL_E1C_2ND_CODE_LOCK;
+ if (in.stateMask & GNSS_MEASUREMENTS_STATE_GAL_E1B_PAGE_SYNC_BIT)
+ out.state |= IGnssMeasurementCallback::GnssMeasurementState::STATE_GAL_E1B_PAGE_SYNC;
+ if (in.stateMask & GNSS_MEASUREMENTS_STATE_SBAS_SYNC_BIT)
+ out.state |= IGnssMeasurementCallback::GnssMeasurementState::STATE_SBAS_SYNC;
+ out.receivedSvTimeInNs = in.receivedSvTimeNs;
+ out.receivedSvTimeUncertaintyInNs = in.receivedSvTimeUncertaintyNs;
+ out.cN0DbHz = in.carrierToNoiseDbHz;
+ out.pseudorangeRateMps = in.pseudorangeRateMps;
+ out.pseudorangeRateUncertaintyMps = in.pseudorangeRateUncertaintyMps;
+ if (in.adrStateMask & GNSS_MEASUREMENTS_ACCUMULATED_DELTA_RANGE_STATE_VALID_BIT)
+ out.accumulatedDeltaRangeState |=
+ IGnssMeasurementCallback::GnssAccumulatedDeltaRangeState::ADR_STATE_VALID;
+ if (in.adrStateMask & GNSS_MEASUREMENTS_ACCUMULATED_DELTA_RANGE_STATE_RESET_BIT)
+ out.accumulatedDeltaRangeState |=
+ IGnssMeasurementCallback::GnssAccumulatedDeltaRangeState::ADR_STATE_RESET;
+ if (in.adrStateMask & GNSS_MEASUREMENTS_ACCUMULATED_DELTA_RANGE_STATE_CYCLE_SLIP_BIT)
+ out.accumulatedDeltaRangeState |=
+ IGnssMeasurementCallback::GnssAccumulatedDeltaRangeState::ADR_STATE_CYCLE_SLIP;
+ out.accumulatedDeltaRangeM = in.adrMeters;
+ out.accumulatedDeltaRangeUncertaintyM = in.adrUncertaintyMeters;
+ out.carrierFrequencyHz = in.carrierFrequencyHz;
+ out.carrierCycles = in.carrierCycles;
+ out.carrierPhase = in.carrierPhase;
+ out.carrierPhaseUncertainty = in.carrierPhaseUncertainty;
+ uint8_t indicator =
+ static_cast<uint8_t>(IGnssMeasurementCallback::GnssMultipathIndicator::INDICATOR_UNKNOWN);
+ if (in.multipathIndicator & GNSS_MEASUREMENTS_MULTIPATH_INDICATOR_PRESENT)
+ indicator |= IGnssMeasurementCallback::GnssMultipathIndicator::INDICATOR_PRESENT;
+ if (in.multipathIndicator & GNSS_MEASUREMENTS_MULTIPATH_INDICATOR_NOT_PRESENT)
+ indicator |= IGnssMeasurementCallback::GnssMultipathIndicator::INDICATIOR_NOT_PRESENT;
+ out.multipathIndicator =
+ static_cast<IGnssMeasurementCallback::GnssMultipathIndicator>(indicator);
+ out.snrDb = in.signalToNoiseRatioDb;
+ out.agcLevelDb = in.agcLevelDb;
+}
+
+static void convertGnssClock(GnssMeasurementsClock& in, IGnssMeasurementCallback::GnssClock& out)
+{
+ memset(&out, 0, sizeof(IGnssMeasurementCallback::GnssClock));
+ if (in.flags & GNSS_MEASUREMENTS_CLOCK_FLAGS_LEAP_SECOND_BIT)
+ out.gnssClockFlags |= IGnssMeasurementCallback::GnssClockFlags::HAS_LEAP_SECOND;
+ if (in.flags & GNSS_MEASUREMENTS_CLOCK_FLAGS_TIME_UNCERTAINTY_BIT)
+ out.gnssClockFlags |= IGnssMeasurementCallback::GnssClockFlags::HAS_TIME_UNCERTAINTY;
+ if (in.flags & GNSS_MEASUREMENTS_CLOCK_FLAGS_FULL_BIAS_BIT)
+ out.gnssClockFlags |= IGnssMeasurementCallback::GnssClockFlags::HAS_FULL_BIAS;
+ if (in.flags & GNSS_MEASUREMENTS_CLOCK_FLAGS_BIAS_BIT)
+ out.gnssClockFlags |= IGnssMeasurementCallback::GnssClockFlags::HAS_BIAS;
+ if (in.flags & GNSS_MEASUREMENTS_CLOCK_FLAGS_BIAS_UNCERTAINTY_BIT)
+ out.gnssClockFlags |= IGnssMeasurementCallback::GnssClockFlags::HAS_BIAS_UNCERTAINTY;
+ if (in.flags & GNSS_MEASUREMENTS_CLOCK_FLAGS_DRIFT_BIT)
+ out.gnssClockFlags |= IGnssMeasurementCallback::GnssClockFlags::HAS_DRIFT;
+ if (in.flags & GNSS_MEASUREMENTS_CLOCK_FLAGS_DRIFT_UNCERTAINTY_BIT)
+ out.gnssClockFlags |= IGnssMeasurementCallback::GnssClockFlags::HAS_DRIFT_UNCERTAINTY;
+ out.leapSecond = in.leapSecond;
+ out.timeNs = in.timeNs;
+ out.timeUncertaintyNs = in.timeUncertaintyNs;
+ out.fullBiasNs = in.fullBiasNs;
+ out.biasNs = in.biasNs;
+ out.biasUncertaintyNs = in.biasUncertaintyNs;
+ out.driftNsps = in.driftNsps;
+ out.driftUncertaintyNsps = in.driftUncertaintyNsps;
+ out.hwClockDiscontinuityCount = in.hwClockDiscontinuityCount;
+}
+
+static void convertGnssData(GnssMeasurementsNotification& in,
+ V1_0::IGnssMeasurementCallback::GnssData& out)
+{
+ out.measurementCount = in.count;
+ if (out.measurementCount > static_cast<uint32_t>(V1_0::GnssMax::SVS_COUNT)) {
+ LOC_LOGW("%s]: Too many measurement %u. Clamps to %d.",
+ __FUNCTION__, out.measurementCount, V1_0::GnssMax::SVS_COUNT);
+ out.measurementCount = static_cast<uint32_t>(V1_0::GnssMax::SVS_COUNT);
+ }
+ for (size_t i = 0; i < out.measurementCount; i++) {
+ convertGnssMeasurement(in.measurements[i], out.measurements[i]);
+ }
+ convertGnssClock(in.clock, out.clock);
+}
+
+static void convertGnssData_1_1(GnssMeasurementsNotification& in,
+ IGnssMeasurementCallback::GnssData& out)
+{
+ out.measurements.resize(in.count);
+ for (size_t i = 0; i < in.count; i++) {
+ convertGnssMeasurement(in.measurements[i], out.measurements[i].v1_0);
+ if (in.measurements[i].adrStateMask & GNSS_MEASUREMENTS_ACCUMULATED_DELTA_RANGE_STATE_VALID_BIT)
+ out.measurements[i].accumulatedDeltaRangeState |=
+ IGnssMeasurementCallback::GnssAccumulatedDeltaRangeState::ADR_STATE_VALID;
+ if (in.measurements[i].adrStateMask & GNSS_MEASUREMENTS_ACCUMULATED_DELTA_RANGE_STATE_RESET_BIT)
+ out.measurements[i].accumulatedDeltaRangeState |=
+ IGnssMeasurementCallback::GnssAccumulatedDeltaRangeState::ADR_STATE_RESET;
+ if (in.measurements[i].adrStateMask & GNSS_MEASUREMENTS_ACCUMULATED_DELTA_RANGE_STATE_CYCLE_SLIP_BIT)
+ out.measurements[i].accumulatedDeltaRangeState |=
+ IGnssMeasurementCallback::GnssAccumulatedDeltaRangeState::ADR_STATE_CYCLE_SLIP;
+ if (in.measurements[i].adrStateMask & GNSS_MEASUREMENTS_ACCUMULATED_DELTA_RANGE_STATE_HALF_CYCLE_RESOLVED_BIT)
+ out.measurements[i].accumulatedDeltaRangeState |=
+ IGnssMeasurementCallback::GnssAccumulatedDeltaRangeState::ADR_STATE_HALF_CYCLE_RESOLVED;
+ }
+ convertGnssClock(in.clock, out.clock);
+}
+
+} // namespace implementation
+} // namespace V1_1
+} // namespace gnss
+} // namespace hardware
+} // namespace android
diff --git a/android/1.1/location_api/MeasurementAPIClient.h b/android/1.1/location_api/MeasurementAPIClient.h
new file mode 100644
index 0000000..38811c5
--- /dev/null
+++ b/android/1.1/location_api/MeasurementAPIClient.h
@@ -0,0 +1,84 @@
+/* Copyright (c) 2017-2018, 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 MEASUREMENT_API_CLINET_H
+#define MEASUREMENT_API_CLINET_H
+
+#include <mutex>
+#include <android/hardware/gnss/1.1/IGnssMeasurement.h>
+#include <android/hardware/gnss/1.1/IGnssMeasurementCallback.h>
+#include <LocationAPIClientBase.h>
+#include <hidl/Status.h>
+#include <gps_extended_c.h>
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace V1_1 {
+namespace implementation {
+
+using ::android::sp;
+
+class MeasurementAPIClient : public LocationAPIClientBase
+{
+public:
+ MeasurementAPIClient();
+ virtual ~MeasurementAPIClient();
+ MeasurementAPIClient(const MeasurementAPIClient&) = delete;
+ MeasurementAPIClient& operator=(const MeasurementAPIClient&) = delete;
+
+ // for GpsMeasurementInterface
+ Return<V1_0::IGnssMeasurement::GnssMeasurementStatus> measurementSetCallback(
+ const sp<V1_0::IGnssMeasurementCallback>& callback);
+ Return<V1_0::IGnssMeasurement::GnssMeasurementStatus> measurementSetCallback_1_1(
+ const sp<IGnssMeasurementCallback>& callback,
+ GnssPowerMode powerMode = GNSS_POWER_MODE_INVALID,
+ uint32_t timeBetweenMeasurement = GPS_DEFAULT_FIX_INTERVAL_MS);
+ void measurementClose();
+ Return<IGnssMeasurement::GnssMeasurementStatus> startTracking(
+ GnssPowerMode powerMode = GNSS_POWER_MODE_INVALID,
+ uint32_t timeBetweenMeasurement = GPS_DEFAULT_FIX_INTERVAL_MS);
+
+ // callbacks we are interested in
+ void onGnssMeasurementsCb(GnssMeasurementsNotification gnssMeasurementsNotification) final;
+
+private:
+ std::mutex mMutex;
+ sp<V1_0::IGnssMeasurementCallback> mGnssMeasurementCbIface;
+ sp<IGnssMeasurementCallback> mGnssMeasurementCbIface_1_1;
+
+ bool mTracking;
+};
+
+} // namespace implementation
+} // namespace V1_1
+} // namespace gnss
+} // namespace hardware
+} // namespace android
+#endif // MEASUREMENT_API_CLINET_H
diff --git a/android/1.1/service.cpp b/android/1.1/service.cpp
new file mode 100644
index 0000000..0cb91f7
--- /dev/null
+++ b/android/1.1/service.cpp
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
+ * Not a Contribution
+ */
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "android.hardware.gnss@1.1-service-qti"
+
+#include <android/hardware/gnss/1.1/IGnss.h>
+#include <hidl/LegacySupport.h>
+#include "loc_cfg.h"
+#include "loc_misc_utils.h"
+
+extern "C" {
+#include "vndfwk-detect.h"
+}
+
+#ifdef ARCH_ARM_32
+#define DEFAULT_HW_BINDER_MEM_SIZE 65536
+#endif
+
+using android::hardware::gnss::V1_1::IGnss;
+
+using android::hardware::configureRpcThreadpool;
+using android::hardware::registerPassthroughServiceImplementation;
+using android::hardware::joinRpcThreadpool;
+
+using android::status_t;
+using android::OK;
+
+typedef int vendorEnhancedServiceMain(int /* argc */, char* /* argv */ []);
+
+int main() {
+
+ ALOGI("%s", __FUNCTION__);
+
+ int vendorInfo = getVendorEnhancedInfo();
+ bool vendorEnhanced = ( 1 == vendorInfo || 3 == vendorInfo );
+ setVendorEnhanced(vendorEnhanced);
+
+#ifdef ARCH_ARM_32
+ android::hardware::ProcessState::initWithMmapSize((size_t)(DEFAULT_HW_BINDER_MEM_SIZE));
+#endif
+ configureRpcThreadpool(1, true);
+ status_t status;
+
+ status = registerPassthroughServiceImplementation<IGnss>();
+ if (status == OK) {
+ if (vendorEnhanced) {
+ #ifdef LOC_HIDL_VERSION
+ #define VENDOR_ENHANCED_LIB "vendor.qti.gnss@" LOC_HIDL_VERSION "-service.so"
+
+ void* libHandle = NULL;
+ vendorEnhancedServiceMain* vendorEnhancedMainMethod = (vendorEnhancedServiceMain*)
+ dlGetSymFromLib(libHandle, VENDOR_ENHANCED_LIB, "main");
+ if (NULL != vendorEnhancedMainMethod) {
+ (*vendorEnhancedMainMethod)(0, NULL);
+ }
+ #else
+ ALOGE("LOC_HIDL_VERSION not defined.");
+ #endif
+ }
+
+ joinRpcThreadpool();
+
+ } else {
+ ALOGE("Error while registering IGnss 1.1 service: %d", status);
+ }
+
+ return 0;
+}
diff --git a/android/2.0/AGnss.cpp b/android/2.0/AGnss.cpp
new file mode 100644
index 0000000..a48f1a0
--- /dev/null
+++ b/android/2.0/AGnss.cpp
@@ -0,0 +1,209 @@
+/*
+ * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved.
+ * Not a Contribution
+ */
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "LocSvc_AGnssInterface"
+
+#include <log_util.h>
+#include "Gnss.h"
+#include "AGnss.h"
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace V2_0 {
+namespace implementation {
+
+static AGnss* spAGnss = nullptr;
+
+AGnss::AGnss(Gnss* gnss) : mGnss(gnss) {
+ spAGnss = this;
+}
+
+AGnss::~AGnss() {
+ spAGnss = nullptr;
+}
+
+void AGnss::agnssStatusIpV4Cb(AGnssExtStatusIpV4 status) {
+ if (nullptr != spAGnss) {
+ spAGnss->statusCb(status.type, status.status);
+ }
+}
+
+void AGnss::statusCb(AGpsExtType type, LocAGpsStatusValue status) {
+
+ V2_0::IAGnssCallback::AGnssType aType;
+ IAGnssCallback::AGnssStatusValue aStatus;
+
+ switch (type) {
+ case LOC_AGPS_TYPE_SUPL:
+ aType = IAGnssCallback::AGnssType::SUPL;
+ break;
+ case LOC_AGPS_TYPE_SUPL_ES:
+ aType = IAGnssCallback::AGnssType::SUPL_EIMS;
+ break;
+ default:
+ LOC_LOGE("invalid type: %d", type);
+ return;
+ }
+
+ switch (status) {
+ case LOC_GPS_REQUEST_AGPS_DATA_CONN:
+ aStatus = IAGnssCallback::AGnssStatusValue::REQUEST_AGNSS_DATA_CONN;
+ break;
+ case LOC_GPS_RELEASE_AGPS_DATA_CONN:
+ aStatus = IAGnssCallback::AGnssStatusValue::RELEASE_AGNSS_DATA_CONN;
+ break;
+ case LOC_GPS_AGPS_DATA_CONNECTED:
+ aStatus = IAGnssCallback::AGnssStatusValue::AGNSS_DATA_CONNECTED;
+ break;
+ case LOC_GPS_AGPS_DATA_CONN_DONE:
+ aStatus = IAGnssCallback::AGnssStatusValue::AGNSS_DATA_CONN_DONE;
+ break;
+ case LOC_GPS_AGPS_DATA_CONN_FAILED:
+ aStatus = IAGnssCallback::AGnssStatusValue::AGNSS_DATA_CONN_FAILED;
+ break;
+ default:
+ LOC_LOGE("invalid status: %d", status);
+ return;
+ }
+
+ if (mAGnssCbIface != nullptr) {
+ auto r = mAGnssCbIface->agnssStatusCb(aType, aStatus);
+ if (!r.isOk()) {
+ LOC_LOGw("Error invoking AGNSS status cb %s", r.description().c_str());
+ }
+ }
+ else {
+ LOC_LOGw("setCallback has not been called yet");
+ }
+}
+
+Return<void> AGnss::setCallback(const sp<V2_0::IAGnssCallback>& callback) {
+
+ if(mGnss == nullptr || mGnss->getGnssInterface() == nullptr){
+ LOC_LOGE("Null GNSS interface");
+ return Void();
+ }
+
+ // Save the interface
+ mAGnssCbIface = callback;
+
+ AgpsCbInfo cbInfo = {};
+ cbInfo.statusV4Cb = (void*)agnssStatusIpV4Cb;
+ cbInfo.atlType = AGPS_ATL_TYPE_SUPL | AGPS_ATL_TYPE_SUPL_ES;
+
+ mGnss->getGnssInterface()->agpsInit(cbInfo);
+ return Void();
+}
+
+Return<bool> AGnss::dataConnClosed() {
+
+ if(mGnss == nullptr || mGnss->getGnssInterface() == nullptr){
+ LOC_LOGE("Null GNSS interface");
+ return false;
+ }
+
+ mGnss->getGnssInterface()->agpsDataConnClosed(LOC_AGPS_TYPE_SUPL);
+ return true;
+}
+
+Return<bool> AGnss::dataConnFailed() {
+
+ if(mGnss == nullptr || mGnss->getGnssInterface() == nullptr){
+ LOC_LOGE("Null GNSS interface");
+ return false;
+ }
+
+ mGnss->getGnssInterface()->agpsDataConnFailed(LOC_AGPS_TYPE_SUPL);
+ return true;
+}
+
+Return<bool> AGnss::dataConnOpen(uint64_t /*networkHandle*/, const hidl_string& apn,
+ V2_0::IAGnss::ApnIpType apnIpType) {
+
+ if(mGnss == nullptr || mGnss->getGnssInterface() == nullptr){
+ LOC_LOGE("Null GNSS interface");
+ return false;
+ }
+
+ /* Validate */
+ if(apn.empty()){
+ LOC_LOGE("Invalid APN");
+ return false;
+ }
+
+ LOC_LOGD("dataConnOpen APN name = [%s]", apn.c_str());
+
+ AGpsBearerType bearerType;
+ switch (apnIpType) {
+ case IAGnss::ApnIpType::IPV4:
+ bearerType = AGPS_APN_BEARER_IPV4;
+ break;
+ case IAGnss::ApnIpType::IPV6:
+ bearerType = AGPS_APN_BEARER_IPV6;
+ break;
+ case IAGnss::ApnIpType::IPV4V6:
+ bearerType = AGPS_APN_BEARER_IPV4V6;
+ break;
+ default:
+ bearerType = AGPS_APN_BEARER_IPV4;
+ break;
+ }
+
+ mGnss->getGnssInterface()->agpsDataConnOpen(
+ LOC_AGPS_TYPE_SUPL, apn.c_str(), apn.size(), (int)bearerType);
+ return true;
+}
+
+Return<bool> AGnss::setServer(V2_0::IAGnssCallback::AGnssType type,
+ const hidl_string& hostname,
+ int32_t port) {
+ if (mGnss == nullptr) {
+ LOC_LOGE("%s]: mGnss is nullptr", __FUNCTION__);
+ return false;
+ }
+
+ GnssConfig config;
+ memset(&config, 0, sizeof(GnssConfig));
+ config.size = sizeof(GnssConfig);
+ config.flags = GNSS_CONFIG_FLAGS_SET_ASSISTANCE_DATA_VALID_BIT;
+ config.assistanceServer.size = sizeof(GnssConfigSetAssistanceServer);
+ if (type == IAGnssCallback::AGnssType::SUPL) {
+ config.assistanceServer.type = GNSS_ASSISTANCE_TYPE_SUPL;
+ } else if (type == IAGnssCallback::AGnssType::C2K) {
+ config.assistanceServer.type = GNSS_ASSISTANCE_TYPE_C2K;
+ } else if (type == IAGnssCallback::AGnssType::SUPL_EIMS) {
+ config.assistanceServer.type = GNSS_ASSISTANCE_TYPE_SUPL_EIMS;
+ } else if (type == IAGnssCallback::AGnssType::SUPL_IMS) {
+ config.assistanceServer.type = GNSS_ASSISTANCE_TYPE_SUPL_IMS;
+ } else {
+ LOC_LOGE("%s]: invalid AGnssType: %d", __FUNCTION__, static_cast<uint8_t>(type));
+ return false;
+ }
+ config.assistanceServer.hostName = strdup(hostname.c_str());
+ config.assistanceServer.port = port;
+ return mGnss->updateConfiguration(config);
+}
+
+} // namespace implementation
+} // namespace V2_0
+} // namespace gnss
+} // namespace hardware
+} // namespace android
diff --git a/android/2.0/AGnss.h b/android/2.0/AGnss.h
new file mode 100644
index 0000000..c442327
--- /dev/null
+++ b/android/2.0/AGnss.h
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved.
+ * Not a Contribution
+ */
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HARDWARE_GNSS_V2_0_AGNSS_H
+#define ANDROID_HARDWARE_GNSS_V2_0_AGNSS_H
+
+#include <android/hardware/gnss/2.0/IAGnss.h>
+#include <hidl/Status.h>
+#include <gps_extended_c.h>
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace V2_0 {
+namespace implementation {
+
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::hidl_string;
+using ::android::sp;
+
+struct Gnss;
+struct AGnss : public V2_0::IAGnss {
+
+ AGnss(Gnss* gnss);
+ ~AGnss();
+ /*
+ * Methods from ::android::hardware::gnss::V2_0::IAGnss interface follow.
+ * These declarations were generated from IAGnss.hal.
+ */
+ Return<void> setCallback(const sp<V2_0::IAGnssCallback>& callback) override;
+
+ Return<bool> dataConnClosed() override;
+
+ Return<bool> dataConnFailed() override;
+
+ Return<bool> dataConnOpen(uint64_t networkHandle, const hidl_string& apn,
+ V2_0::IAGnss::ApnIpType apnIpType) override;
+
+ Return<bool> setServer(V2_0::IAGnssCallback::AGnssType type,
+ const hidl_string& hostname, int32_t port) override;
+
+ void statusCb(AGpsExtType type, LocAGpsStatusValue status);
+
+ /* Data call setup callback passed down to GNSS HAL implementation */
+ static void agnssStatusIpV4Cb(AGnssExtStatusIpV4 status);
+
+ private:
+ Gnss* mGnss = nullptr;
+ sp<IAGnssCallback> mAGnssCbIface = nullptr;
+};
+
+} // namespace implementation
+} // namespace V2_0
+} // namespace gnss
+} // namespace hardware
+} // namespace android
+
+#endif // ANDROID_HARDWARE_GNSS_V2_0_AGNSS_H
diff --git a/android/2.0/AGnssRil.cpp b/android/2.0/AGnssRil.cpp
new file mode 100644
index 0000000..a477fc2
--- /dev/null
+++ b/android/2.0/AGnssRil.cpp
@@ -0,0 +1,133 @@
+/*
+ * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved.
+ * Not a Contribution
+ */
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "LocSvc__AGnssRilInterface"
+
+#include <log_util.h>
+#include <dlfcn.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <sstream>
+#include <string>
+#include "Gnss.h"
+#include "AGnssRil.h"
+#include <DataItemConcreteTypesBase.h>
+
+typedef void* (getLocationInterface)();
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace V2_0 {
+namespace implementation {
+
+
+AGnssRil::AGnssRil(Gnss* gnss) : mGnss(gnss) {
+ ENTRY_LOG_CALLFLOW();
+}
+
+AGnssRil::~AGnssRil() {
+ ENTRY_LOG_CALLFLOW();
+}
+
+Return<bool> AGnssRil::updateNetworkState(bool connected, NetworkType type, bool /*roaming*/) {
+ ENTRY_LOG_CALLFLOW();
+ // Extra NetworkTypes not available in IAgnssRil enums
+ const int NetworkType_BLUETOOTH = 7;
+ const int NetworkType_ETHERNET = 9;
+ const int NetworkType_PROXY = 16;
+
+ // for XTRA
+ if (nullptr != mGnss && ( nullptr != mGnss->getGnssInterface() )) {
+ int8_t typeout = loc_core::TYPE_UNKNOWN;
+ switch(type)
+ {
+ case IAGnssRil::NetworkType::MOBILE:
+ typeout = loc_core::TYPE_MOBILE;
+ break;
+ case IAGnssRil::NetworkType::WIFI:
+ typeout = loc_core::TYPE_WIFI;
+ break;
+ case IAGnssRil::NetworkType::MMS:
+ typeout = loc_core::TYPE_MMS;
+ break;
+ case IAGnssRil::NetworkType::SUPL:
+ typeout = loc_core::TYPE_SUPL;
+ break;
+ case IAGnssRil::NetworkType::DUN:
+ typeout = loc_core::TYPE_DUN;
+ break;
+ case IAGnssRil::NetworkType::HIPRI:
+ typeout = loc_core::TYPE_HIPRI;
+ break;
+ case IAGnssRil::NetworkType::WIMAX:
+ typeout = loc_core::TYPE_WIMAX;
+ break;
+ default:
+ {
+ int networkType = (int) type;
+ // Handling network types not available in IAgnssRil
+ switch(networkType)
+ {
+ case NetworkType_BLUETOOTH:
+ typeout = loc_core::TYPE_BLUETOOTH;
+ break;
+ case NetworkType_ETHERNET:
+ typeout = loc_core::TYPE_ETHERNET;
+ break;
+ case NetworkType_PROXY:
+ typeout = loc_core::TYPE_PROXY;
+ break;
+ default:
+ typeout = loc_core::TYPE_UNKNOWN;
+ }
+ }
+ break;
+ }
+ mGnss->getGnssInterface()->updateConnectionStatus(connected, false, typeout, 0);
+ }
+ return true;
+}
+Return<bool> AGnssRil::updateNetworkState_2_0(const V2_0::IAGnssRil::NetworkAttributes& attributes) {
+ ENTRY_LOG_CALLFLOW();
+
+ if (nullptr != mGnss && (nullptr != mGnss->getGnssInterface())) {
+ int8_t typeout = loc_core::TYPE_UNKNOWN;
+ bool roaming = false;
+ if (attributes.capabilities & IAGnssRil::NetworkCapability::NOT_METERED) {
+ typeout = loc_core::TYPE_WIFI;
+ } else {
+ typeout = loc_core::TYPE_MOBILE;
+ }
+ if (attributes.capabilities & IAGnssRil::NetworkCapability::NOT_ROAMING) {
+ roaming = false;
+ }
+ mGnss->getGnssInterface()->updateConnectionStatus(attributes.isConnected,
+ typeout, roaming, (NetworkHandle) attributes.networkHandle);
+ }
+ return true;
+}
+
+} // namespace implementation
+} // namespace V2_0
+} // namespace gnss
+} // namespace hardware
+} // namespace android
diff --git a/android/2.0/AGnssRil.h b/android/2.0/AGnssRil.h
new file mode 100644
index 0000000..a04d8aa
--- /dev/null
+++ b/android/2.0/AGnssRil.h
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved.
+ * Not a Contribution
+ */
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HARDWARE_GNSS_V2_0_AGNSSRIL_H_
+#define ANDROID_HARDWARE_GNSS_V2_0_AGNSSRIL_H_
+
+#include <android/hardware/gnss/2.0/IAGnssRil.h>
+#include <hidl/Status.h>
+#include <location_interface.h>
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace V2_0 {
+namespace implementation {
+
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::hidl_string;
+using ::android::sp;
+
+struct Gnss;
+/*
+ * Extended interface for AGNSS RIL support. An Assisted GNSS Radio Interface Layer interface
+ * allows the GNSS chipset to request radio interface layer information from Android platform.
+ * Examples of such information are reference location, unique subscriber ID, phone number string
+ * and network availability changes. Also contains wrapper methods to allow methods from
+ * IAGnssiRilCallback interface to be passed into the conventional implementation of the GNSS HAL.
+ */
+struct AGnssRil : public V2_0::IAGnssRil {
+ AGnssRil(Gnss* gnss);
+ ~AGnssRil();
+
+ /*
+ * Methods from ::android::hardware::gnss::V1_0::IAGnssRil follow.
+ * These declarations were generated from IAGnssRil.hal.
+ */
+ Return<void> setCallback(const sp<V1_0::IAGnssRilCallback>& /*callback*/) override {
+ return Void();
+ }
+ Return<void> setRefLocation(const V1_0::IAGnssRil::AGnssRefLocation& /*agnssReflocation*/) override {
+ return Void();
+ }
+ Return<bool> setSetId(V1_0::IAGnssRil::SetIDType /*type*/, const hidl_string& /*setid*/) override {
+ return false;
+ }
+ Return<bool> updateNetworkAvailability(bool /*available*/,
+ const hidl_string& /*apn*/) override {
+ return false;
+ }
+ Return<bool> updateNetworkState(bool connected, V1_0::IAGnssRil::NetworkType type, bool roaming) override;
+
+ // Methods from ::android::hardware::gnss::V2_0::IAGnssRil follow
+ Return<bool> updateNetworkState_2_0(const V2_0::IAGnssRil::NetworkAttributes& attributes) override;
+
+ private:
+ Gnss* mGnss = nullptr;
+};
+
+} // namespace implementation
+} // namespace V2_0
+} // namespace gnss
+} // namespace hardware
+} // namespace android
+
+#endif // ANDROID_HARDWARE_GNSS_V2_0_AGNSSRIL_H_
diff --git a/android/2.0/Android.mk b/android/2.0/Android.mk
new file mode 100644
index 0000000..7c55504
--- /dev/null
+++ b/android/2.0/Android.mk
@@ -0,0 +1,110 @@
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := android.hardware.gnss@2.0-impl-qti
+LOCAL_VENDOR_MODULE := true
+LOCAL_MODULE_RELATIVE_PATH := hw
+LOCAL_SRC_FILES := \
+ AGnss.cpp \
+ Gnss.cpp \
+ AGnssRil.cpp \
+ GnssMeasurement.cpp \
+ GnssConfiguration.cpp \
+ GnssBatching.cpp \
+ GnssGeofencing.cpp \
+ GnssNi.cpp \
+ GnssDebug.cpp \
+ ../measurement_corrections/1.0/MeasurementCorrections.cpp \
+ ../visibility_control/1.0/GnssVisibilityControl.cpp
+
+LOCAL_SRC_FILES += \
+ location_api/GnssAPIClient.cpp \
+ location_api/MeasurementAPIClient.cpp \
+ location_api/GeofenceAPIClient.cpp \
+ location_api/BatchingAPIClient.cpp \
+ location_api/LocationUtil.cpp \
+
+ifeq ($(GNSS_HIDL_LEGACY_MEASURMENTS),true)
+LOCAL_CFLAGS += \
+ -DGNSS_HIDL_LEGACY_MEASURMENTS
+endif
+
+LOCAL_C_INCLUDES:= \
+ $(LOCAL_PATH)/location_api \
+ $(LOCAL_PATH)/../measurement_corrections/1.0 \
+ $(LOCAL_PATH)/../visibility_control/1.0
+LOCAL_HEADER_LIBRARIES := \
+ libgps.utils_headers \
+ libloc_core_headers \
+ libloc_pla_headers \
+ liblocation_api_headers \
+ liblocbatterylistener_headers
+
+LOCAL_SHARED_LIBRARIES := \
+ liblog \
+ libhidlbase \
+ libhidltransport \
+ libhwbinder \
+ libcutils \
+ libutils \
+ android.hardware.gnss@1.0 \
+ android.hardware.gnss@1.1 \
+ android.hardware.gnss@2.0 \
+ android.hardware.gnss.measurement_corrections@1.0 \
+ android.hardware.gnss.visibility_control@1.0 \
+ android.hardware.health@1.0 \
+ android.hardware.health@2.0 \
+ android.hardware.power@1.2 \
+ libbase
+
+LOCAL_SHARED_LIBRARIES += \
+ libloc_core \
+ libgps.utils \
+ libdl \
+ liblocation_api \
+
+LOCAL_CFLAGS += $(GNSS_CFLAGS)
+LOCAL_STATIC_LIBRARIES := liblocbatterylistener
+LOCAL_STATIC_LIBRARIES += libhealthhalutils
+include $(BUILD_SHARED_LIBRARY)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := android.hardware.gnss@2.0-service-qti
+LOCAL_VINTF_FRAGMENTS := android.hardware.gnss@2.0-service-qti.xml
+LOCAL_VENDOR_MODULE := true
+LOCAL_MODULE_RELATIVE_PATH := hw
+LOCAL_INIT_RC := android.hardware.gnss@2.0-service-qti.rc
+LOCAL_SRC_FILES := \
+ service.cpp \
+
+LOCAL_HEADER_LIBRARIES := \
+ libgps.utils_headers \
+ libloc_core_headers \
+ libloc_pla_headers \
+ liblocation_api_headers
+
+
+LOCAL_SHARED_LIBRARIES := \
+ liblog \
+ libcutils \
+ libdl \
+ libbase \
+ libutils \
+ libgps.utils \
+ libqti_vndfwk_detect \
+
+LOCAL_SHARED_LIBRARIES += \
+ libhwbinder \
+ libhidlbase \
+ libhidltransport \
+ android.hardware.gnss@1.0 \
+ android.hardware.gnss@1.1 \
+ android.hardware.gnss@2.0 \
+
+LOCAL_CFLAGS += $(GNSS_CFLAGS)
+
+ifneq ($(LOC_HIDL_VERSION),)
+LOCAL_CFLAGS += -DLOC_HIDL_VERSION='"$(LOC_HIDL_VERSION)"'
+endif
+
+include $(BUILD_EXECUTABLE)
diff --git a/android/2.0/Gnss.cpp b/android/2.0/Gnss.cpp
new file mode 100644
index 0000000..af76b72
--- /dev/null
+++ b/android/2.0/Gnss.cpp
@@ -0,0 +1,671 @@
+/*
+ * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved.
+ * Not a Contribution
+ */
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "LocSvc_GnssInterface"
+#define LOG_NDEBUG 0
+
+#include <fstream>
+#include <log_util.h>
+#include <dlfcn.h>
+#include <cutils/properties.h>
+#include "Gnss.h"
+#include "LocationUtil.h"
+#include "battery_listener.h"
+
+typedef const GnssInterface* (getLocationInterface)();
+
+#define IMAGES_INFO_FILE "/sys/devices/soc0/images"
+#define DELIMITER ";"
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace V2_0 {
+namespace implementation {
+
+using ::android::hardware::gnss::visibility_control::V1_0::implementation::GnssVisibilityControl;
+static sp<Gnss> sGnss;
+static std::string getVersionString() {
+ static std::string version;
+ if (!version.empty())
+ return version;
+
+ char value[PROPERTY_VALUE_MAX] = {0};
+ property_get("ro.hardware", value, "unknown");
+ version.append(value).append(DELIMITER);
+
+ std::ifstream in(IMAGES_INFO_FILE);
+ std::string s;
+ while(getline(in, s)) {
+ std::size_t found = s.find("CRM:");
+ if (std::string::npos == found) {
+ continue;
+ }
+
+ // skip over space characters after "CRM:"
+ const char* substr = s.c_str();
+ found += 4;
+ while (0 != substr[found] && isspace(substr[found])) {
+ found++;
+ }
+ if (s.find("11:") != found) {
+ continue;
+ }
+ s.erase(0, found + 3);
+
+ found = s.find_first_of("\r\n");
+ if (std::string::npos != found) {
+ s.erase(s.begin() + found, s.end());
+ }
+ version.append(s).append(DELIMITER);
+ }
+ return version;
+}
+
+void Gnss::GnssDeathRecipient::serviceDied(uint64_t cookie, const wp<IBase>& who) {
+ LOC_LOGE("%s] service died. cookie: %llu, who: %p",
+ __FUNCTION__, static_cast<unsigned long long>(cookie), &who);
+ if (mGnss != nullptr) {
+ mGnss->cleanup();
+ }
+}
+
+void location_on_battery_status_changed(bool charging) {
+ LOC_LOGd("battery status changed to %s charging", charging ? "" : "not");
+ if (sGnss != nullptr) {
+ sGnss->getGnssInterface()->updateBatteryStatus(charging);
+ }
+}
+Gnss::Gnss() {
+ ENTRY_LOG_CALLFLOW();
+ sGnss = this;
+ // register health client to listen on battery change
+ loc_extn_battery_properties_listener_init(location_on_battery_status_changed);
+ // clear pending GnssConfig
+ memset(&mPendingConfig, 0, sizeof(GnssConfig));
+ mGnssDeathRecipient = new GnssDeathRecipient(this);
+}
+
+Gnss::~Gnss() {
+ ENTRY_LOG_CALLFLOW();
+ if (mApi != nullptr) {
+ delete mApi;
+ mApi = nullptr;
+ }
+ sGnss = nullptr;
+}
+
+GnssAPIClient* Gnss::getApi() {
+ if (mApi != nullptr) {
+ return mApi;
+ }
+
+ if (mGnssCbIface_2_0 != nullptr) {
+ mApi = new GnssAPIClient(mGnssCbIface_2_0);
+ } else if (mGnssCbIface_1_1 != nullptr) {
+ mApi = new GnssAPIClient(mGnssCbIface_1_1, mGnssNiCbIface);
+ } else if (mGnssCbIface != nullptr) {
+ mApi = new GnssAPIClient(mGnssCbIface, mGnssNiCbIface);
+ } else {
+ LOC_LOGW("%s] GnssAPIClient is not ready", __FUNCTION__);
+ return mApi;
+ }
+
+ if (mPendingConfig.size == sizeof(GnssConfig)) {
+ // we have pending GnssConfig
+ mApi->gnssConfigurationUpdate(mPendingConfig);
+ // clear size to invalid mPendingConfig
+ mPendingConfig.size = 0;
+ if (mPendingConfig.assistanceServer.hostName != nullptr) {
+ free((void*)mPendingConfig.assistanceServer.hostName);
+ }
+ }
+
+ return mApi;
+}
+
+const GnssInterface* Gnss::getGnssInterface() {
+ static bool getGnssInterfaceFailed = false;
+ if (nullptr == mGnssInterface && !getGnssInterfaceFailed) {
+ LOC_LOGD("%s]: loading libgnss.so::getGnssInterface ...", __func__);
+ getLocationInterface* getter = NULL;
+ const char *error = NULL;
+ dlerror();
+ void *handle = dlopen("libgnss.so", RTLD_NOW);
+ if (NULL == handle || (error = dlerror()) != NULL) {
+ LOC_LOGW("dlopen for libgnss.so failed, error = %s", error);
+ } else {
+ getter = (getLocationInterface*)dlsym(handle, "getGnssInterface");
+ if ((error = dlerror()) != NULL) {
+ LOC_LOGW("dlsym for libgnss.so::getGnssInterface failed, error = %s", error);
+ getter = NULL;
+ }
+ }
+
+ if (NULL == getter) {
+ getGnssInterfaceFailed = true;
+ } else {
+ mGnssInterface = (const GnssInterface*)(*getter)();
+ }
+ }
+ return mGnssInterface;
+}
+
+Return<bool> Gnss::setCallback(const sp<V1_0::IGnssCallback>& callback) {
+ ENTRY_LOG_CALLFLOW();
+
+ // In case where previous call to setCallback_1_1 or setCallback_2_0, then
+ // we need to cleanup these interfaces/callbacks here since we no longer
+ // do so in cleanup() function to keep callbacks around after cleanup()
+ if (mApi != nullptr) {
+ mApi->gnssUpdateCallbacks_2_0(nullptr);
+ }
+ if (mGnssCbIface_1_1 != nullptr) {
+ mGnssCbIface_1_1->unlinkToDeath(mGnssDeathRecipient);
+ mGnssCbIface_1_1 = nullptr;
+ }
+ if (mGnssCbIface_2_0 != nullptr) {
+ mGnssCbIface_2_0->unlinkToDeath(mGnssDeathRecipient);
+ mGnssCbIface_2_0 = nullptr;
+ }
+
+
+ if (mGnssCbIface != nullptr) {
+ mGnssCbIface->unlinkToDeath(mGnssDeathRecipient);
+ }
+ mGnssCbIface = callback;
+ if (mGnssCbIface != nullptr) {
+ mGnssCbIface->linkToDeath(mGnssDeathRecipient, 0 /*cookie*/);
+ }
+
+ GnssAPIClient* api = getApi();
+ if (api != nullptr) {
+ api->gnssUpdateCallbacks(mGnssCbIface, mGnssNiCbIface);
+ api->gnssEnable(LOCATION_TECHNOLOGY_TYPE_GNSS);
+ api->requestCapabilities();
+ }
+ return true;
+}
+
+Return<bool> Gnss::setGnssNiCb(const sp<IGnssNiCallback>& callback) {
+ ENTRY_LOG_CALLFLOW();
+ mGnssNiCbIface = callback;
+ GnssAPIClient* api = getApi();
+ if (api != nullptr) {
+ api->gnssUpdateCallbacks(mGnssCbIface, mGnssNiCbIface);
+ }
+ return true;
+}
+
+Return<bool> Gnss::updateConfiguration(GnssConfig& gnssConfig) {
+ ENTRY_LOG_CALLFLOW();
+ GnssAPIClient* api = getApi();
+ if (api) {
+ api->gnssConfigurationUpdate(gnssConfig);
+ } else if (gnssConfig.flags != 0) {
+ // api is not ready yet, update mPendingConfig with gnssConfig
+ mPendingConfig.size = sizeof(GnssConfig);
+
+ if (gnssConfig.flags & GNSS_CONFIG_FLAGS_GPS_LOCK_VALID_BIT) {
+ mPendingConfig.flags |= GNSS_CONFIG_FLAGS_GPS_LOCK_VALID_BIT;
+ mPendingConfig.gpsLock = gnssConfig.gpsLock;
+ }
+ if (gnssConfig.flags & GNSS_CONFIG_FLAGS_SUPL_VERSION_VALID_BIT) {
+ mPendingConfig.flags |= GNSS_CONFIG_FLAGS_SUPL_VERSION_VALID_BIT;
+ mPendingConfig.suplVersion = gnssConfig.suplVersion;
+ }
+ if (gnssConfig.flags & GNSS_CONFIG_FLAGS_SET_ASSISTANCE_DATA_VALID_BIT) {
+ mPendingConfig.flags |= GNSS_CONFIG_FLAGS_SET_ASSISTANCE_DATA_VALID_BIT;
+ mPendingConfig.assistanceServer.size = sizeof(GnssConfigSetAssistanceServer);
+ mPendingConfig.assistanceServer.type = gnssConfig.assistanceServer.type;
+ if (mPendingConfig.assistanceServer.hostName != nullptr) {
+ free((void*)mPendingConfig.assistanceServer.hostName);
+ mPendingConfig.assistanceServer.hostName =
+ strdup(gnssConfig.assistanceServer.hostName);
+ }
+ mPendingConfig.assistanceServer.port = gnssConfig.assistanceServer.port;
+ }
+ if (gnssConfig.flags & GNSS_CONFIG_FLAGS_LPP_PROFILE_VALID_BIT) {
+ mPendingConfig.flags |= GNSS_CONFIG_FLAGS_LPP_PROFILE_VALID_BIT;
+ mPendingConfig.lppProfile = gnssConfig.lppProfile;
+ }
+ if (gnssConfig.flags & GNSS_CONFIG_FLAGS_LPPE_CONTROL_PLANE_VALID_BIT) {
+ mPendingConfig.flags |= GNSS_CONFIG_FLAGS_LPPE_CONTROL_PLANE_VALID_BIT;
+ mPendingConfig.lppeControlPlaneMask = gnssConfig.lppeControlPlaneMask;
+ }
+ if (gnssConfig.flags & GNSS_CONFIG_FLAGS_LPPE_USER_PLANE_VALID_BIT) {
+ mPendingConfig.flags |= GNSS_CONFIG_FLAGS_LPPE_USER_PLANE_VALID_BIT;
+ mPendingConfig.lppeUserPlaneMask = gnssConfig.lppeUserPlaneMask;
+ }
+ if (gnssConfig.flags & GNSS_CONFIG_FLAGS_AGLONASS_POSITION_PROTOCOL_VALID_BIT) {
+ mPendingConfig.flags |= GNSS_CONFIG_FLAGS_AGLONASS_POSITION_PROTOCOL_VALID_BIT;
+ mPendingConfig.aGlonassPositionProtocolMask = gnssConfig.aGlonassPositionProtocolMask;
+ }
+ if (gnssConfig.flags & GNSS_CONFIG_FLAGS_EM_PDN_FOR_EM_SUPL_VALID_BIT) {
+ mPendingConfig.flags |= GNSS_CONFIG_FLAGS_EM_PDN_FOR_EM_SUPL_VALID_BIT;
+ mPendingConfig.emergencyPdnForEmergencySupl = gnssConfig.emergencyPdnForEmergencySupl;
+ }
+ if (gnssConfig.flags & GNSS_CONFIG_FLAGS_SUPL_EM_SERVICES_BIT) {
+ mPendingConfig.flags |= GNSS_CONFIG_FLAGS_SUPL_EM_SERVICES_BIT;
+ mPendingConfig.suplEmergencyServices = gnssConfig.suplEmergencyServices;
+ }
+ if (gnssConfig.flags & GNSS_CONFIG_FLAGS_SUPL_MODE_BIT) {
+ mPendingConfig.flags |= GNSS_CONFIG_FLAGS_SUPL_MODE_BIT;
+ mPendingConfig.suplModeMask = gnssConfig.suplModeMask;
+ }
+ if (gnssConfig.flags & GNSS_CONFIG_FLAGS_BLACKLISTED_SV_IDS_BIT) {
+ mPendingConfig.flags |= GNSS_CONFIG_FLAGS_BLACKLISTED_SV_IDS_BIT;
+ mPendingConfig.blacklistedSvIds = gnssConfig.blacklistedSvIds;
+ }
+ if (gnssConfig.flags & GNSS_CONFIG_FLAGS_EMERGENCY_EXTENSION_SECONDS_BIT) {
+ mPendingConfig.flags |= GNSS_CONFIG_FLAGS_EMERGENCY_EXTENSION_SECONDS_BIT;
+ mPendingConfig.emergencyExtensionSeconds = gnssConfig.emergencyExtensionSeconds;
+ }
+ }
+ return true;
+}
+
+Return<bool> Gnss::start() {
+ ENTRY_LOG_CALLFLOW();
+ bool retVal = false;
+ GnssAPIClient* api = getApi();
+ if (api) {
+ retVal = api->gnssStart();
+ }
+ return retVal;
+}
+
+Return<bool> Gnss::stop() {
+ ENTRY_LOG_CALLFLOW();
+ bool retVal = false;
+ GnssAPIClient* api = getApi();
+ if (api) {
+ retVal = api->gnssStop();
+ }
+ return retVal;
+}
+
+Return<void> Gnss::cleanup() {
+ ENTRY_LOG_CALLFLOW();
+
+ if (mApi != nullptr) {
+ mApi->gnssStop();
+ mApi->gnssDisable();
+ }
+
+ return Void();
+}
+
+Return<bool> Gnss::injectLocation(double latitudeDegrees,
+ double longitudeDegrees,
+ float accuracyMeters) {
+ ENTRY_LOG_CALLFLOW();
+ const GnssInterface* gnssInterface = getGnssInterface();
+ if (nullptr != gnssInterface) {
+ gnssInterface->injectLocation(latitudeDegrees, longitudeDegrees, accuracyMeters);
+ return true;
+ } else {
+ return false;
+ }
+}
+
+Return<bool> Gnss::injectTime(int64_t timeMs, int64_t timeReferenceMs,
+ int32_t uncertaintyMs) {
+ ENTRY_LOG_CALLFLOW();
+ const GnssInterface* gnssInterface = getGnssInterface();
+ if (nullptr != gnssInterface) {
+ gnssInterface->injectTime(timeMs, timeReferenceMs, uncertaintyMs);
+ return true;
+ } else {
+ return false;
+ }
+}
+
+Return<void> Gnss::deleteAidingData(V1_0::IGnss::GnssAidingData aidingDataFlags) {
+ ENTRY_LOG_CALLFLOW();
+ GnssAPIClient* api = getApi();
+ if (api) {
+ api->gnssDeleteAidingData(aidingDataFlags);
+ }
+ return Void();
+}
+
+Return<bool> Gnss::setPositionMode(V1_0::IGnss::GnssPositionMode mode,
+ V1_0::IGnss::GnssPositionRecurrence recurrence,
+ uint32_t minIntervalMs,
+ uint32_t preferredAccuracyMeters,
+ uint32_t preferredTimeMs) {
+ ENTRY_LOG_CALLFLOW();
+ bool retVal = false;
+ GnssAPIClient* api = getApi();
+ if (api) {
+ retVal = api->gnssSetPositionMode(mode, recurrence, minIntervalMs,
+ preferredAccuracyMeters, preferredTimeMs);
+ }
+ return retVal;
+}
+
+Return<sp<V1_0::IAGnss>> Gnss::getExtensionAGnss() {
+ ENTRY_LOG_CALLFLOW();
+ // deprecated function. Must return nullptr to pass VTS
+ return nullptr;
+}
+
+Return<sp<V1_0::IGnssNi>> Gnss::getExtensionGnssNi() {
+ ENTRY_LOG_CALLFLOW();
+ // deprecated function. Must return nullptr to pass VTS
+ return nullptr;
+}
+
+Return<sp<V1_0::IGnssMeasurement>> Gnss::getExtensionGnssMeasurement() {
+ ENTRY_LOG_CALLFLOW();
+ if (mGnssMeasurement == nullptr)
+ mGnssMeasurement = new GnssMeasurement();
+ return mGnssMeasurement;
+}
+
+Return<sp<V1_0::IGnssConfiguration>> Gnss::getExtensionGnssConfiguration() {
+ ENTRY_LOG_CALLFLOW();
+ mGnssConfig = new GnssConfiguration(this);
+ return mGnssConfig;
+}
+
+Return<sp<V1_0::IGnssGeofencing>> Gnss::getExtensionGnssGeofencing() {
+ ENTRY_LOG_CALLFLOW();
+ mGnssGeofencingIface = new GnssGeofencing();
+ return mGnssGeofencingIface;
+}
+
+Return<sp<V1_0::IGnssBatching>> Gnss::getExtensionGnssBatching() {
+ ENTRY_LOG_CALLFLOW();
+ mGnssBatching = new GnssBatching();
+ return mGnssBatching;
+}
+
+Return<sp<V1_0::IGnssDebug>> Gnss::getExtensionGnssDebug() {
+ ENTRY_LOG_CALLFLOW();
+ mGnssDebug = new GnssDebug(this);
+ return mGnssDebug;
+}
+
+Return<sp<V1_0::IAGnssRil>> Gnss::getExtensionAGnssRil() {
+ ENTRY_LOG_CALLFLOW();
+ mGnssRil = new AGnssRil(this);
+ return mGnssRil;
+}
+
+// Methods from ::android::hardware::gnss::V1_1::IGnss follow.
+Return<bool> Gnss::setCallback_1_1(const sp<V1_1::IGnssCallback>& callback) {
+ ENTRY_LOG_CALLFLOW();
+ auto r = callback->gnssNameCb(getVersionString());
+ if (!r.isOk()) {
+ LOC_LOGE("%s] Error from gnssNameCb description=%s",
+ __func__, r.description().c_str());
+ }
+
+ // In case where previous call to setCallback or setCallback_2_1, then
+ // we need to cleanup these interfaces/callbacks here since we no longer
+ // do so in cleanup() function to keep callbacks around after cleanup()
+ if (mApi != nullptr) {
+ mApi->gnssUpdateCallbacks_2_0(nullptr);
+ }
+ if (mGnssCbIface != nullptr) {
+ mGnssCbIface->unlinkToDeath(mGnssDeathRecipient);
+ mGnssCbIface = nullptr;
+ }
+ if (mGnssCbIface_2_0 != nullptr) {
+ mGnssCbIface_2_0->unlinkToDeath(mGnssDeathRecipient);
+ mGnssCbIface_2_0 = nullptr;
+ }
+
+
+ if (mGnssCbIface_1_1 != nullptr) {
+ mGnssCbIface_1_1->unlinkToDeath(mGnssDeathRecipient);
+ }
+ mGnssCbIface_1_1 = callback;
+ if (mGnssCbIface_1_1 != nullptr) {
+ mGnssCbIface_1_1->linkToDeath(mGnssDeathRecipient, 0 /*cookie*/);
+ }
+
+ const GnssInterface* gnssInterface = getGnssInterface();
+ if (nullptr != gnssInterface) {
+ OdcpiRequestCallback cb = [this](const OdcpiRequestInfo& odcpiRequest) {
+ odcpiRequestCb(odcpiRequest);
+ };
+ gnssInterface->odcpiInit(cb);
+ }
+
+ GnssAPIClient* api = getApi();
+ if (api != nullptr) {
+ api->gnssUpdateCallbacks(mGnssCbIface_1_1, mGnssNiCbIface);
+ api->gnssEnable(LOCATION_TECHNOLOGY_TYPE_GNSS);
+ api->requestCapabilities();
+ }
+
+ return true;
+}
+
+Return<bool> Gnss::setPositionMode_1_1(V1_0::IGnss::GnssPositionMode mode,
+ V1_0::IGnss::GnssPositionRecurrence recurrence,
+ uint32_t minIntervalMs,
+ uint32_t preferredAccuracyMeters,
+ uint32_t preferredTimeMs,
+ bool lowPowerMode) {
+ ENTRY_LOG_CALLFLOW();
+ bool retVal = false;
+ GnssAPIClient* api = getApi();
+ if (api) {
+ GnssPowerMode powerMode = lowPowerMode?
+ GNSS_POWER_MODE_M4 : GNSS_POWER_MODE_M2;
+ retVal = api->gnssSetPositionMode(mode, recurrence, minIntervalMs,
+ preferredAccuracyMeters, preferredTimeMs, powerMode, minIntervalMs);
+ }
+ return retVal;
+}
+
+Return<sp<V1_1::IGnssMeasurement>> Gnss::getExtensionGnssMeasurement_1_1() {
+ ENTRY_LOG_CALLFLOW();
+#ifdef GNSS_HIDL_LEGACY_MEASURMENTS
+ return nullptr;
+#else
+ if (mGnssMeasurement == nullptr)
+ mGnssMeasurement = new GnssMeasurement();
+ return mGnssMeasurement;
+#endif
+}
+
+Return<sp<V1_1::IGnssConfiguration>> Gnss::getExtensionGnssConfiguration_1_1() {
+ ENTRY_LOG_CALLFLOW();
+ if (mGnssConfig == nullptr)
+ mGnssConfig = new GnssConfiguration(this);
+ return mGnssConfig;
+}
+
+Return<bool> Gnss::injectBestLocation(const GnssLocation& gnssLocation) {
+ ENTRY_LOG_CALLFLOW();
+ const GnssInterface* gnssInterface = getGnssInterface();
+ if (nullptr != gnssInterface) {
+ Location location = {};
+ convertGnssLocation(gnssLocation, location);
+ gnssInterface->odcpiInject(location);
+ }
+ return true;
+}
+
+void Gnss::odcpiRequestCb(const OdcpiRequestInfo& request) {
+ ENTRY_LOG_CALLFLOW();
+
+ if (mGnssCbIface_2_0 != nullptr) {
+ // For emergency mode, request DBH (Device based hybrid) location
+ // Mark Independent from GNSS flag to false.
+ if (ODCPI_REQUEST_TYPE_START == request.type) {
+ LOC_LOGd("gnssRequestLocationCb_2_0 isUserEmergency = %d", request.isEmergencyMode);
+ auto r = mGnssCbIface_2_0->gnssRequestLocationCb_2_0(!request.isEmergencyMode,
+ request.isEmergencyMode);
+ if (!r.isOk()) {
+ LOC_LOGe("Error invoking gnssRequestLocationCb_2_0 %s", r.description().c_str());
+ }
+ } else {
+ LOC_LOGv("Unsupported ODCPI request type: %d", request.type);
+ }
+ } else if (mGnssCbIface_1_1 != nullptr) {
+ // For emergency mode, request DBH (Device based hybrid) location
+ // Mark Independent from GNSS flag to false.
+ if (ODCPI_REQUEST_TYPE_START == request.type) {
+ auto r = mGnssCbIface_1_1->gnssRequestLocationCb(!request.isEmergencyMode);
+ if (!r.isOk()) {
+ LOC_LOGe("Error invoking gnssRequestLocationCb %s", r.description().c_str());
+ }
+ } else {
+ LOC_LOGv("Unsupported ODCPI request type: %d", request.type);
+ }
+ } else {
+ LOC_LOGe("ODCPI request not supported.");
+ }
+}
+
+// Methods from ::android::hardware::gnss::V2_0::IGnss follow.
+Return<bool> Gnss::setCallback_2_0(const sp<V2_0::IGnssCallback>& callback) {
+ ENTRY_LOG_CALLFLOW();
+ auto r = callback->gnssNameCb(getVersionString());
+ if (!r.isOk()) {
+ LOC_LOGE("%s] Error from gnssNameCb description=%s",
+ __func__, r.description().c_str());
+ }
+
+ // In case where previous call to setCallback or setCallback_1_1, then
+ // we need to cleanup these interfaces/callbacks here since we no longer
+ // do so in cleanup() function to keep callbacks around after cleanup()
+ if (mApi != nullptr) {
+ mApi->gnssUpdateCallbacks(nullptr, nullptr);
+ }
+ mGnssNiCbIface = nullptr;
+ if (mGnssCbIface != nullptr) {
+ mGnssCbIface->unlinkToDeath(mGnssDeathRecipient);
+ mGnssCbIface = nullptr;
+ }
+ if (mGnssCbIface_1_1 != nullptr) {
+ mGnssCbIface_1_1->unlinkToDeath(mGnssDeathRecipient);
+ mGnssCbIface_1_1 = nullptr;
+ }
+
+ if (mGnssCbIface_2_0 != nullptr) {
+ mGnssCbIface_2_0->unlinkToDeath(mGnssDeathRecipient);
+ }
+ mGnssCbIface_2_0 = callback;
+ if (mGnssCbIface_2_0 != nullptr) {
+ mGnssCbIface_2_0->linkToDeath(mGnssDeathRecipient, 0 /*cookie*/);
+ }
+
+ const GnssInterface* gnssInterface = getGnssInterface();
+ if (nullptr != gnssInterface) {
+ OdcpiRequestCallback cb = [this](const OdcpiRequestInfo& odcpiRequest) {
+ odcpiRequestCb(odcpiRequest);
+ };
+ gnssInterface->odcpiInit(cb);
+ }
+
+ GnssAPIClient* api = getApi();
+ if (api != nullptr) {
+ api->gnssUpdateCallbacks_2_0(mGnssCbIface_2_0);
+ api->gnssEnable(LOCATION_TECHNOLOGY_TYPE_GNSS);
+ api->requestCapabilities();
+ }
+
+ return true;
+}
+
+Return<sp<V2_0::IAGnss>> Gnss::getExtensionAGnss_2_0() {
+ ENTRY_LOG_CALLFLOW();
+ mAGnssIface_2_0 = new AGnss(this);
+ return mAGnssIface_2_0;
+}
+Return<sp<V2_0::IAGnssRil>> Gnss::getExtensionAGnssRil_2_0() {
+ mGnssRil = new AGnssRil(this);
+ return mGnssRil;
+}
+
+Return<sp<V2_0::IGnssConfiguration>> Gnss::getExtensionGnssConfiguration_2_0() {
+ ENTRY_LOG_CALLFLOW();
+ mGnssConfig = new GnssConfiguration(this);
+ return mGnssConfig;
+}
+Return<sp<V2_0::IGnssMeasurement>> Gnss::getExtensionGnssMeasurement_2_0() {
+ ENTRY_LOG_CALLFLOW();
+#ifdef GNSS_HIDL_LEGACY_MEASURMENTS
+ return nullptr;
+#else
+ if (mGnssMeasurement == nullptr)
+ mGnssMeasurement = new GnssMeasurement();
+ return mGnssMeasurement;
+#endif
+}
+Return<sp<::android::hardware::gnss::measurement_corrections::V1_0::IMeasurementCorrections>>
+ Gnss::getExtensionMeasurementCorrections() {
+ // We do not support, so return nullptr to pass VTS
+ return nullptr;
+}
+Return<sp<::android::hardware::gnss::visibility_control::V1_0::IGnssVisibilityControl>>
+ Gnss::getExtensionVisibilityControl() {
+ ENTRY_LOG_CALLFLOW();
+ if (mVisibCtrl == nullptr) {
+ mVisibCtrl = new GnssVisibilityControl(this);
+ }
+ return mVisibCtrl;
+}
+
+Return<bool> Gnss::injectBestLocation_2_0(const V2_0::GnssLocation& gnssLocation) {
+ ENTRY_LOG_CALLFLOW();
+ const GnssInterface* gnssInterface = getGnssInterface();
+ if (nullptr != gnssInterface) {
+ Location location = {};
+ convertGnssLocation(gnssLocation, location);
+ gnssInterface->odcpiInject(location);
+ }
+ return true;
+}
+
+Return<sp<V2_0::IGnssDebug>> Gnss::getExtensionGnssDebug_2_0() {
+ ENTRY_LOG_CALLFLOW();
+ mGnssDebug = new GnssDebug(this);
+ return mGnssDebug;
+}
+
+Return<sp<V2_0::IGnssBatching>> Gnss::getExtensionGnssBatching_2_0() {
+ ENTRY_LOG_CALLFLOW();
+ mGnssBatching = new GnssBatching();
+ return mGnssBatching;
+}
+
+V1_0::IGnss* HIDL_FETCH_IGnss(const char* hal) {
+ ENTRY_LOG_CALLFLOW();
+ V1_0::IGnss* iface = nullptr;
+ iface = new Gnss();
+ if (iface == nullptr) {
+ LOC_LOGE("%s]: failed to get %s", __FUNCTION__, hal);
+ }
+ return iface;
+}
+
+} // namespace implementation
+} // namespace V2_0
+} // namespace gnss
+} // namespace hardware
+} // namespace android
diff --git a/android/2.0/Gnss.h b/android/2.0/Gnss.h
new file mode 100644
index 0000000..a403d61
--- /dev/null
+++ b/android/2.0/Gnss.h
@@ -0,0 +1,187 @@
+/*
+ * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved.
+ * Not a Contribution
+ */
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HARDWARE_GNSS_V2_0_GNSS_H
+#define ANDROID_HARDWARE_GNSS_V2_0_GNSS_H
+
+#include <AGnss.h>
+#include <AGnssRil.h>
+#include <GnssConfiguration.h>
+#include <GnssMeasurement.h>
+#include <GnssBatching.h>
+#include <GnssGeofencing.h>
+#include <GnssNi.h>
+#include <GnssDebug.h>
+
+#include <android/hardware/gnss/2.0/IGnss.h>
+#include <MeasurementCorrections.h>
+#include <GnssVisibilityControl.h>
+#include <hidl/MQDescriptor.h>
+#include <hidl/Status.h>
+
+#include "GnssAPIClient.h"
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace V2_0 {
+namespace implementation {
+
+using ::android::hardware::hidl_array;
+using ::android::hardware::hidl_memory;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::sp;
+using ::android::hardware::gnss::V1_0::GnssLocation;
+using ::android::hardware::gnss::measurement_corrections::V1_0::IMeasurementCorrections;
+using ::android::hardware::gnss::measurement_corrections::V1_0::implementation::MeasurementCorrections;
+using ::android::hardware::gnss::visibility_control::V1_0::IGnssVisibilityControl;
+
+struct Gnss : public IGnss {
+ Gnss();
+ ~Gnss();
+
+ /*
+ * Methods from ::android::hardware::gnss::V1_0::IGnss follow.
+ * These declarations were generated from Gnss.hal.
+ */
+ Return<bool> setCallback(const sp<V1_0::IGnssCallback>& callback) override;
+ Return<bool> start() override;
+ Return<bool> stop() override;
+ Return<void> cleanup() override;
+ Return<bool> injectLocation(double latitudeDegrees,
+ double longitudeDegrees,
+ float accuracyMeters) override;
+ Return<bool> injectTime(int64_t timeMs,
+ int64_t timeReferenceMs,
+ int32_t uncertaintyMs) override;
+ Return<void> deleteAidingData(V1_0::IGnss::GnssAidingData aidingDataFlags) override;
+ Return<bool> setPositionMode(V1_0::IGnss::GnssPositionMode mode,
+ V1_0::IGnss::GnssPositionRecurrence recurrence,
+ uint32_t minIntervalMs,
+ uint32_t preferredAccuracyMeters,
+ uint32_t preferredTimeMs) override;
+ Return<sp<V1_0::IAGnss>> getExtensionAGnss() override;
+ Return<sp<V1_0::IGnssNi>> getExtensionGnssNi() override;
+ Return<sp<V1_0::IGnssMeasurement>> getExtensionGnssMeasurement() override;
+ Return<sp<V1_0::IGnssConfiguration>> getExtensionGnssConfiguration() override;
+ Return<sp<V1_0::IGnssGeofencing>> getExtensionGnssGeofencing() override;
+ Return<sp<V1_0::IGnssBatching>> getExtensionGnssBatching() override;
+
+ Return<sp<V1_0::IAGnssRil>> getExtensionAGnssRil() override;
+
+ inline Return<sp<V1_0::IGnssNavigationMessage>> getExtensionGnssNavigationMessage() override {
+ return nullptr;
+ }
+
+ inline Return<sp<V1_0::IGnssXtra>> getExtensionXtra() override {
+ return nullptr;
+ }
+
+ Return<sp<V1_0::IGnssDebug>> getExtensionGnssDebug() override;
+
+ // Methods from ::android::hardware::gnss::V1_1::IGnss follow.
+ Return<bool> setCallback_1_1(const sp<V1_1::IGnssCallback>& callback) override;
+ Return<bool> setPositionMode_1_1(V1_0::IGnss::GnssPositionMode mode,
+ V1_0::IGnss::GnssPositionRecurrence recurrence,
+ uint32_t minIntervalMs, uint32_t preferredAccuracyMeters,
+ uint32_t preferredTimeMs, bool lowPowerMode) override;
+ Return<sp<V1_1::IGnssMeasurement>> getExtensionGnssMeasurement_1_1() override;
+ Return<sp<V1_1::IGnssConfiguration>> getExtensionGnssConfiguration_1_1() override;
+ Return<bool> injectBestLocation(const GnssLocation& location) override;
+
+ // Methods from ::android::hardware::gnss::V2_0::IGnss follow.
+ Return<bool> setCallback_2_0(const sp<V2_0::IGnssCallback>& callback) override;
+ Return<sp<V2_0::IAGnss>> getExtensionAGnss_2_0() override;
+ Return<sp<V2_0::IAGnssRil>> getExtensionAGnssRil_2_0() override;
+
+ Return<sp<V2_0::IGnssConfiguration>> getExtensionGnssConfiguration_2_0() override;
+ Return<sp<::android::hardware::gnss::measurement_corrections::V1_0::IMeasurementCorrections>>
+ getExtensionMeasurementCorrections() override;
+ Return<sp<V2_0::IGnssMeasurement>> getExtensionGnssMeasurement_2_0() override;
+
+ Return<bool> injectBestLocation_2_0(const ::android::hardware::gnss::V2_0::GnssLocation& location) override;
+
+ Return<sp<V2_0::IGnssBatching>> getExtensionGnssBatching_2_0() override;
+ Return<sp<V2_0::IGnssDebug>> getExtensionGnssDebug_2_0() override;
+
+
+ /**
+ * This method returns the IGnssVisibilityControl interface.
+ *
+ * @return visibilityControlIface Handle to the IGnssVisibilityControl interface.
+ */
+ Return<sp<::android::hardware::gnss::visibility_control::V1_0::IGnssVisibilityControl>>
+ getExtensionVisibilityControl() override;
+
+
+ // These methods are not part of the IGnss base class.
+ GnssAPIClient* getApi();
+ Return<bool> setGnssNiCb(const sp<IGnssNiCallback>& niCb);
+ Return<bool> updateConfiguration(GnssConfig& gnssConfig);
+ const GnssInterface* getGnssInterface();
+
+ // Callback for ODCPI request
+ void odcpiRequestCb(const OdcpiRequestInfo& request);
+
+ private:
+ struct GnssDeathRecipient : hidl_death_recipient {
+ GnssDeathRecipient(sp<Gnss> gnss) : mGnss(gnss) {
+ }
+ ~GnssDeathRecipient() = default;
+ virtual void serviceDied(uint64_t cookie, const wp<IBase>& who) override;
+ sp<Gnss> mGnss;
+ };
+
+ private:
+ sp<GnssDeathRecipient> mGnssDeathRecipient = nullptr;
+
+ sp<V1_0::IGnssNi> mGnssNi = nullptr;
+ sp<V1_0::IGnssGeofencing> mGnssGeofencingIface = nullptr;
+ sp<V1_0::IAGnss> mAGnssIface = nullptr;
+ sp<V1_0::IGnssCallback> mGnssCbIface = nullptr;
+ sp<V1_0::IGnssNiCallback> mGnssNiCbIface = nullptr;
+ sp<V1_1::IGnssCallback> mGnssCbIface_1_1 = nullptr;
+ sp<V2_0::IAGnss> mAGnssIface_2_0 = nullptr;
+ sp<V2_0::IAGnssRil> mGnssRil = nullptr;
+ sp<V2_0::IGnssMeasurement> mGnssMeasurement = nullptr;
+ sp<V2_0::IGnssConfiguration> mGnssConfig = nullptr;
+ sp<V2_0::IGnssBatching> mGnssBatching = nullptr;
+ sp<V2_0::IGnssDebug> mGnssDebug = nullptr;
+ sp<V2_0::IGnssCallback> mGnssCbIface_2_0 = nullptr;
+ sp<IMeasurementCorrections> mGnssMeasCorr = nullptr;
+ sp<IGnssVisibilityControl> mVisibCtrl = nullptr;
+
+ GnssAPIClient* mApi = nullptr;
+ GnssConfig mPendingConfig;
+ const GnssInterface* mGnssInterface = nullptr;
+};
+
+extern "C" V1_0::IGnss* HIDL_FETCH_IGnss(const char* name);
+
+} // namespace implementation
+} // namespace V2_0
+} // namespace gnss
+} // namespace hardware
+} // namespace android
+
+#endif // ANDROID_HARDWARE_GNSS_V2_0_GNSS_H
diff --git a/android/2.0/GnssBatching.cpp b/android/2.0/GnssBatching.cpp
new file mode 100644
index 0000000..7a937fc
--- /dev/null
+++ b/android/2.0/GnssBatching.cpp
@@ -0,0 +1,163 @@
+/*
+ * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved.
+ * Not a Contribution
+ */
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "LocSvc_GnssBatchingInterface"
+
+#include <log_util.h>
+#include <BatchingAPIClient.h>
+#include "GnssBatching.h"
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace V2_0 {
+namespace implementation {
+
+void GnssBatching::GnssBatchingDeathRecipient::serviceDied(
+ uint64_t cookie, const wp<IBase>& who) {
+ LOC_LOGE("%s] service died. cookie: %llu, who: %p",
+ __FUNCTION__, static_cast<unsigned long long>(cookie), &who);
+ if (mGnssBatching != nullptr) {
+ mGnssBatching->stop();
+ mGnssBatching->cleanup();
+ }
+}
+
+GnssBatching::GnssBatching() : mApi(nullptr) {
+ mGnssBatchingDeathRecipient = new GnssBatchingDeathRecipient(this);
+}
+
+GnssBatching::~GnssBatching() {
+ if (mApi != nullptr) {
+ delete mApi;
+ mApi = nullptr;
+ }
+}
+
+
+// Methods from ::android::hardware::gnss::V1_0::IGnssBatching follow.
+Return<bool> GnssBatching::init(const sp<V1_0::IGnssBatchingCallback>& callback) {
+ if (mApi != nullptr) {
+ LOC_LOGD("%s]: mApi is NOT nullptr, delete it first", __FUNCTION__);
+ delete mApi;
+ mApi = nullptr;
+ }
+
+ mApi = new BatchingAPIClient(callback);
+ if (mApi == nullptr) {
+ LOC_LOGE("%s]: failed to create mApi", __FUNCTION__);
+ return false;
+ }
+
+ if (mGnssBatchingCbIface != nullptr) {
+ mGnssBatchingCbIface->unlinkToDeath(mGnssBatchingDeathRecipient);
+ }
+ mGnssBatchingCbIface = callback;
+ if (mGnssBatchingCbIface != nullptr) {
+ mGnssBatchingCbIface->linkToDeath(mGnssBatchingDeathRecipient, 0 /*cookie*/);
+ }
+
+ return true;
+}
+
+Return<uint16_t> GnssBatching::getBatchSize() {
+ uint16_t ret = 0;
+ if (mApi == nullptr) {
+ LOC_LOGE("%s]: mApi is nullptr", __FUNCTION__);
+ } else {
+ ret = mApi->getBatchSize();
+ }
+ return ret;
+}
+
+Return<bool> GnssBatching::start(const IGnssBatching::Options& options) {
+ bool ret = false;
+ if (mApi == nullptr) {
+ LOC_LOGE("%s]: mApi is nullptr", __FUNCTION__);
+ } else {
+ ret = mApi->startSession(options);
+ }
+ return ret;
+}
+
+Return<void> GnssBatching::flush() {
+ if (mApi == nullptr) {
+ LOC_LOGE("%s]: mApi is nullptr", __FUNCTION__);
+ } else {
+ mApi->flushBatchedLocations();
+ }
+ return Void();
+}
+
+Return<bool> GnssBatching::stop() {
+ bool ret = false;
+ if (mApi == nullptr) {
+ LOC_LOGE("%s]: mApi is nullptr", __FUNCTION__);
+ } else {
+ ret = mApi->stopSession();
+ }
+ return ret;
+}
+
+Return<void> GnssBatching::cleanup() {
+ if (mApi != nullptr) {
+ mApi->stopSession();
+ }
+ if (mGnssBatchingCbIface != nullptr) {
+ mGnssBatchingCbIface->unlinkToDeath(mGnssBatchingDeathRecipient);
+ mGnssBatchingCbIface = nullptr;
+ }
+ if (mGnssBatchingCbIface_2_0 != nullptr) {
+ mGnssBatchingCbIface_2_0->unlinkToDeath(mGnssBatchingDeathRecipient);
+ mGnssBatchingCbIface_2_0 = nullptr;
+ }
+ return Void();
+}
+
+// Methods from ::android::hardware::gnss::V2_0::IGnssBatching follow.
+Return<bool> GnssBatching::init_2_0(const sp<V2_0::IGnssBatchingCallback>& callback) {
+ if (mApi != nullptr) {
+ LOC_LOGD("%s]: mApi is NOT nullptr, delete it first", __FUNCTION__);
+ delete mApi;
+ mApi = nullptr;
+ }
+
+ mApi = new BatchingAPIClient(callback);
+ if (mApi == nullptr) {
+ LOC_LOGE("%s]: failed to create mApi", __FUNCTION__);
+ return false;
+ }
+
+ if (mGnssBatchingCbIface_2_0 != nullptr) {
+ mGnssBatchingCbIface_2_0->unlinkToDeath(mGnssBatchingDeathRecipient);
+ }
+ mGnssBatchingCbIface_2_0 = callback;
+ if (mGnssBatchingCbIface_2_0 != nullptr) {
+ mGnssBatchingCbIface_2_0->linkToDeath(mGnssBatchingDeathRecipient, 0 /*cookie*/);
+ }
+
+ return true;
+}
+
+} // namespace implementation
+} // namespace V2_0
+} // namespace gnss
+} // namespace hardware
+} // namespace android
diff --git a/android/2.0/GnssBatching.h b/android/2.0/GnssBatching.h
new file mode 100644
index 0000000..4c8d1db
--- /dev/null
+++ b/android/2.0/GnssBatching.h
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved.
+ * Not a Contribution
+ */
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HARDWARE_GNSS_V2_0_GNSSBATCHING_H
+#define ANDROID_HARDWARE_GNSS_V2_0_GNSSBATCHING_H
+
+#include <android/hardware/gnss/2.0/IGnssBatching.h>
+#include <hidl/Status.h>
+
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace V2_0 {
+namespace implementation {
+
+using ::android::hardware::gnss::V2_0::IGnssBatching;
+using ::android::hardware::gnss::V2_0::IGnssBatchingCallback;
+using ::android::hidl::base::V1_0::IBase;
+using ::android::hardware::hidl_array;
+using ::android::hardware::hidl_memory;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::sp;
+
+class BatchingAPIClient;
+struct GnssBatching : public IGnssBatching {
+ GnssBatching();
+ ~GnssBatching();
+
+ // Methods from ::android::hardware::gnss::V1_0::IGnssBatching follow.
+ Return<bool> init(const sp<V1_0::IGnssBatchingCallback>& callback) override;
+ Return<uint16_t> getBatchSize() override;
+ Return<bool> start(const IGnssBatching::Options& options ) override;
+ Return<void> flush() override;
+ Return<bool> stop() override;
+ Return<void> cleanup() override;
+
+ // Methods from ::android::hardware::gnss::V2_0::IGnssBatching follow.
+ Return<bool> init_2_0(const sp<V2_0::IGnssBatchingCallback>& callback) override;
+
+ private:
+ struct GnssBatchingDeathRecipient : hidl_death_recipient {
+ GnssBatchingDeathRecipient(sp<GnssBatching> gnssBatching) :
+ mGnssBatching(gnssBatching) {
+ }
+ ~GnssBatchingDeathRecipient() = default;
+ virtual void serviceDied(uint64_t cookie, const wp<IBase>& who) override;
+ sp<GnssBatching> mGnssBatching;
+ };
+
+ private:
+ sp<GnssBatchingDeathRecipient> mGnssBatchingDeathRecipient = nullptr;
+ sp<V1_0::IGnssBatchingCallback> mGnssBatchingCbIface = nullptr;
+ BatchingAPIClient* mApi = nullptr;
+ sp<V2_0::IGnssBatchingCallback> mGnssBatchingCbIface_2_0 = nullptr;
+};
+
+} // namespace implementation
+} // namespace V2_0
+} // namespace gnss
+} // namespace hardware
+} // namespace android
+
+#endif // ANDROID_HARDWARE_GNSS_V2_0_GNSSBATCHING_H
diff --git a/android/2.0/GnssConfiguration.cpp b/android/2.0/GnssConfiguration.cpp
new file mode 100644
index 0000000..363d2b1
--- /dev/null
+++ b/android/2.0/GnssConfiguration.cpp
@@ -0,0 +1,321 @@
+/*
+ * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved.
+ * Not a Contribution
+ */
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "LocSvc_GnssConfigurationInterface"
+
+#include <log_util.h>
+#include "Gnss.h"
+#include "GnssConfiguration.h"
+#include "ContextBase.h"
+#include <android/hardware/gnss/1.0/types.h>
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace V2_0 {
+namespace implementation {
+
+using ::android::hardware::gnss::V1_0::GnssConstellationType;
+using namespace loc_core;
+
+GnssConfiguration::GnssConfiguration(Gnss* gnss) : mGnss(gnss) {
+}
+
+// Methods from ::android::hardware::gps::V1_0::IGnssConfiguration follow.
+Return<bool> GnssConfiguration::setSuplEs(bool enabled) {
+ // deprecated function. Must return false to pass VTS
+ return false;
+}
+
+Return<bool> GnssConfiguration::setSuplVersion(uint32_t version) {
+ if (mGnss == nullptr) {
+ LOC_LOGE("%s]: mGnss is nullptr", __FUNCTION__);
+ return false;
+ }
+
+ GnssConfig config;
+ memset(&config, 0, sizeof(GnssConfig));
+ config.size = sizeof(GnssConfig);
+ config.flags = GNSS_CONFIG_FLAGS_SUPL_VERSION_VALID_BIT;
+ switch (version) {
+ case 0x00020002:
+ config.suplVersion = GNSS_CONFIG_SUPL_VERSION_2_0_2;
+ break;
+ case 0x00020000:
+ config.suplVersion = GNSS_CONFIG_SUPL_VERSION_2_0_0;
+ break;
+ case 0x00010000:
+ config.suplVersion = GNSS_CONFIG_SUPL_VERSION_1_0_0;
+ break;
+ default:
+ LOC_LOGE("%s]: invalid version: 0x%x.", __FUNCTION__, version);
+ return false;
+ break;
+ }
+
+ return mGnss->updateConfiguration(config);
+}
+
+Return<bool> GnssConfiguration::setSuplMode(uint8_t mode) {
+ if (mGnss == nullptr) {
+ LOC_LOGE("%s]: mGnss is nullptr", __FUNCTION__);
+ return false;
+ }
+
+ GnssConfig config;
+ memset(&config, 0, sizeof(GnssConfig));
+ config.size = sizeof(GnssConfig);
+ config.flags = GNSS_CONFIG_FLAGS_SUPL_MODE_BIT;
+ switch (mode) {
+ case 0:
+ config.suplModeMask = 0; // STANDALONE ONLY
+ break;
+ case 1:
+ config.suplModeMask = GNSS_CONFIG_SUPL_MODE_MSB_BIT;
+ break;
+ case 2:
+ config.suplModeMask = GNSS_CONFIG_SUPL_MODE_MSA_BIT;
+ break;
+ case 3:
+ config.suplModeMask = GNSS_CONFIG_SUPL_MODE_MSB_BIT | GNSS_CONFIG_SUPL_MODE_MSA_BIT;
+ break;
+ default:
+ LOC_LOGE("%s]: invalid mode: %d.", __FUNCTION__, mode);
+ return false;
+ break;
+ }
+
+ return mGnss->updateConfiguration(config);
+}
+
+Return<bool> GnssConfiguration::setLppProfile(uint8_t lppProfile) {
+ if (mGnss == nullptr) {
+ LOC_LOGE("%s]: mGnss is nullptr", __FUNCTION__);
+ return false;
+ }
+
+ GnssConfig config = {};
+ config.size = sizeof(GnssConfig);
+ config.flags = GNSS_CONFIG_FLAGS_LPP_PROFILE_VALID_BIT;
+ switch (lppProfile) {
+ case 0:
+ config.lppProfile = GNSS_CONFIG_LPP_PROFILE_RRLP_ON_LTE;
+ break;
+ case 1:
+ config.lppProfile = GNSS_CONFIG_LPP_PROFILE_USER_PLANE;
+ break;
+ case 2:
+ config.lppProfile = GNSS_CONFIG_LPP_PROFILE_CONTROL_PLANE;
+ break;
+ case 3:
+ config.lppProfile = GNSS_CONFIG_LPP_PROFILE_USER_PLANE_AND_CONTROL_PLANE;
+ break;
+ default:
+ LOC_LOGE("%s]: invalid lppProfile: %d.", __FUNCTION__, lppProfile);
+ return false;
+ break;
+ }
+
+ return mGnss->updateConfiguration(config);
+}
+
+Return<bool> GnssConfiguration::setGlonassPositioningProtocol(uint8_t protocol) {
+ if (mGnss == nullptr) {
+ LOC_LOGE("%s]: mGnss is nullptr", __FUNCTION__);
+ return false;
+ }
+
+ GnssConfig config;
+ memset(&config, 0, sizeof(GnssConfig));
+ config.size = sizeof(GnssConfig);
+
+ config.flags = GNSS_CONFIG_FLAGS_AGLONASS_POSITION_PROTOCOL_VALID_BIT;
+ if (protocol & (1<<0)) {
+ config.aGlonassPositionProtocolMask |= GNSS_CONFIG_RRC_CONTROL_PLANE_BIT;
+ }
+ if (protocol & (1<<1)) {
+ config.aGlonassPositionProtocolMask |= GNSS_CONFIG_RRLP_USER_PLANE_BIT;
+ }
+ if (protocol & (1<<2)) {
+ config.aGlonassPositionProtocolMask |= GNSS_CONFIG_LLP_USER_PLANE_BIT;
+ }
+ if (protocol & (1<<3)) {
+ config.aGlonassPositionProtocolMask |= GNSS_CONFIG_LLP_CONTROL_PLANE_BIT;
+ }
+
+ return mGnss->updateConfiguration(config);
+}
+
+Return<bool> GnssConfiguration::setGpsLock(uint8_t lock) {
+
+ if (mGnss == nullptr) {
+ LOC_LOGE("%s]: mGnss is nullptr", __FUNCTION__);
+ return false;
+ }
+
+ GnssConfig config = {};
+ config.size = sizeof(GnssConfig);
+ config.flags = GNSS_CONFIG_FLAGS_GPS_LOCK_VALID_BIT;
+ switch (lock) {
+ case 0:
+ config.gpsLock = GNSS_CONFIG_GPS_LOCK_NONE;
+ break;
+ case 1:
+ config.gpsLock = GNSS_CONFIG_GPS_LOCK_MO;
+ break;
+ case 2:
+ config.gpsLock = GNSS_CONFIG_GPS_LOCK_NI;
+ break;
+ case 3:
+ config.gpsLock = GNSS_CONFIG_GPS_LOCK_MO_AND_NI;
+ break;
+ default:
+ LOC_LOGE("%s]: invalid lock: %d.", __FUNCTION__, lock);
+ return false;
+ break;
+ }
+
+ mGnss->updateConfiguration(config);
+ // Must return false to pass VTS
+ return false;
+}
+
+Return<bool> GnssConfiguration::setEmergencySuplPdn(bool enabled) {
+ if (mGnss == nullptr) {
+ LOC_LOGE("%s]: mGnss is nullptr", __FUNCTION__);
+ return false;
+ }
+
+ GnssConfig config;
+ memset(&config, 0, sizeof(GnssConfig));
+ config.size = sizeof(GnssConfig);
+ config.flags = GNSS_CONFIG_FLAGS_EM_PDN_FOR_EM_SUPL_VALID_BIT;
+ config.emergencyPdnForEmergencySupl = (enabled ?
+ GNSS_CONFIG_EMERGENCY_PDN_FOR_EMERGENCY_SUPL_YES :
+ GNSS_CONFIG_EMERGENCY_PDN_FOR_EMERGENCY_SUPL_NO);
+
+ return mGnss->updateConfiguration(config);
+}
+
+// Methods from ::android::hardware::gnss::V1_1::IGnssConfiguration follow.
+Return<bool> GnssConfiguration::setBlacklist(
+ const hidl_vec<GnssConfiguration::BlacklistedSource>& blacklist) {
+
+ ENTRY_LOG_CALLFLOW();
+ if (nullptr == mGnss) {
+ LOC_LOGe("mGnss is null");
+ return false;
+ }
+
+ // blValid is true if blacklist is empty, i.e. clearing the BL;
+ // if blacklist is not empty, blValid is initialied to false, and later
+ // updated in the for loop to become true only if there is at least
+ // one {constellation, svid} in the list that is valid.
+ bool blValid = (0 == blacklist.size());
+ GnssConfig config;
+ memset(&config, 0, sizeof(GnssConfig));
+ config.size = sizeof(GnssConfig);
+ config.flags = GNSS_CONFIG_FLAGS_BLACKLISTED_SV_IDS_BIT;
+ config.blacklistedSvIds.clear();
+
+ GnssSvIdSource source = {};
+ for (int idx = 0; idx < (int)blacklist.size(); idx++) {
+ // Set blValid true if any one source is valid
+ blValid = setBlacklistedSource(source, blacklist[idx]) || blValid;
+ config.blacklistedSvIds.push_back(source);
+ }
+
+ // Update configuration only if blValid is true
+ // i.e. only if atleast one source is valid for blacklisting
+ return (blValid && mGnss->updateConfiguration(config));
+}
+
+bool GnssConfiguration::setBlacklistedSource(
+ GnssSvIdSource& copyToSource,
+ const GnssConfiguration::BlacklistedSource& copyFromSource) {
+
+ bool retVal = true;
+ uint16_t svIdOffset = 0;
+ copyToSource.size = sizeof(GnssSvIdSource);
+ copyToSource.svId = copyFromSource.svid;
+
+ switch(copyFromSource.constellation) {
+ case GnssConstellationType::GPS:
+ copyToSource.constellation = GNSS_SV_TYPE_GPS;
+ LOC_LOGe("GPS SVs can't be blacklisted.");
+ retVal = false;
+ break;
+ case GnssConstellationType::SBAS:
+ copyToSource.constellation = GNSS_SV_TYPE_SBAS;
+ LOC_LOGe("SBAS SVs can't be blacklisted.");
+ retVal = false;
+ break;
+ case GnssConstellationType::GLONASS:
+ copyToSource.constellation = GNSS_SV_TYPE_GLONASS;
+ svIdOffset = GNSS_SV_CONFIG_GLO_INITIAL_SV_ID - 1;
+ break;
+ case GnssConstellationType::QZSS:
+ copyToSource.constellation = GNSS_SV_TYPE_QZSS;
+ svIdOffset = 0;
+ break;
+ case GnssConstellationType::BEIDOU:
+ copyToSource.constellation = GNSS_SV_TYPE_BEIDOU;
+ svIdOffset = GNSS_SV_CONFIG_BDS_INITIAL_SV_ID - 1;
+ break;
+ case GnssConstellationType::GALILEO:
+ copyToSource.constellation = GNSS_SV_TYPE_GALILEO;
+ svIdOffset = GNSS_SV_CONFIG_GAL_INITIAL_SV_ID - 1;
+ break;
+ default:
+ copyToSource.constellation = GNSS_SV_TYPE_UNKNOWN;
+ LOC_LOGe("Invalid constellation %hhu", copyFromSource.constellation);
+ retVal = false;
+ break;
+ }
+
+ if (copyToSource.svId > 0 && svIdOffset > 0) {
+ copyToSource.svId += svIdOffset;
+ }
+
+ return retVal;
+}
+
+// Methods from ::android::hardware::gnss::V2_0::IGnssConfiguration follow.
+Return<bool> GnssConfiguration::setEsExtensionSec(uint32_t emergencyExtensionSeconds) {
+ ENTRY_LOG_CALLFLOW();
+ if (mGnss == nullptr) {
+ LOC_LOGe("mGnss is nullptr");
+ return false;
+ }
+
+ GnssConfig config;
+ memset(&config, 0, sizeof(GnssConfig));
+ config.size = sizeof(GnssConfig);
+ config.flags = GNSS_CONFIG_FLAGS_EMERGENCY_EXTENSION_SECONDS_BIT;
+ config.emergencyExtensionSeconds = emergencyExtensionSeconds;
+
+ return mGnss->updateConfiguration(config);
+}
+
+} // namespace implementation
+} // namespace V2_0
+} // namespace gnss
+} // namespace hardware
+} // namespace android
diff --git a/android/2.0/GnssConfiguration.h b/android/2.0/GnssConfiguration.h
new file mode 100644
index 0000000..202a9fd
--- /dev/null
+++ b/android/2.0/GnssConfiguration.h
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved.
+ * Not a Contribution
+ */
+
+ /* Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+#ifndef ANDROID_HARDWARE_GNSS_V2_0_GNSSCONFIGURATION_H
+#define ANDROID_HARDWARE_GNSS_V2_0_GNSSCONFIGURATION_H
+
+#include <android/hardware/gnss/2.0/IGnssConfiguration.h>
+#include <hidl/Status.h>
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace V2_0 {
+namespace implementation {
+
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::hidl_string;
+using ::android::sp;
+
+/*
+ * Interface for passing GNSS configuration info from platform to HAL.
+ */
+struct Gnss;
+struct GnssConfiguration : public V2_0::IGnssConfiguration {
+ GnssConfiguration(Gnss* gnss);
+ ~GnssConfiguration() = default;
+
+ /*
+ * Methods from ::android::hardware::gnss::V1_0::IGnssConfiguration follow.
+ * These declarations were generated from IGnssConfiguration.hal.
+ */
+ Return<bool> setSuplVersion(uint32_t version) override;
+ Return<bool> setSuplMode(uint8_t mode) override;
+ Return<bool> setSuplEs(bool enabled) override;
+ Return<bool> setLppProfile(uint8_t lppProfile) override;
+ Return<bool> setGlonassPositioningProtocol(uint8_t protocol) override;
+ Return<bool> setEmergencySuplPdn(bool enable) override;
+ Return<bool> setGpsLock(uint8_t lock) override;
+
+ // Methods from ::android::hardware::gnss::V1_1::IGnssConfiguration follow.
+ Return<bool> setBlacklist(
+ const hidl_vec<GnssConfiguration::BlacklistedSource>& blacklist) override;
+
+ // Methods from ::android::hardware::gnss::V2_0::IGnssConfiguration follow.
+ Return<bool> setEsExtensionSec(uint32_t emergencyExtensionSeconds) override;
+
+ private:
+ Gnss* mGnss = nullptr;
+ bool setBlacklistedSource(
+ GnssSvIdSource& copyToSource,
+ const GnssConfiguration::BlacklistedSource& copyFromSource);
+};
+
+} // namespace implementation
+} // namespace V2_0
+} // namespace gnss
+} // namespace hardware
+} // namespace android
+
+#endif // ANDROID_HARDWARE_GNSS_V2_0_GNSSCONFIGURATION_H
diff --git a/android/2.0/GnssDebug.cpp b/android/2.0/GnssDebug.cpp
new file mode 100644
index 0000000..dc0d9f4
--- /dev/null
+++ b/android/2.0/GnssDebug.cpp
@@ -0,0 +1,299 @@
+/*
+ * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved.
+ * Not a Contribution
+ */
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "LocSvc_GnssDebugInterface"
+
+#include <log/log.h>
+#include <log_util.h>
+#include "Gnss.h"
+#include "GnssDebug.h"
+#include "LocationUtil.h"
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace V2_0 {
+namespace implementation {
+
+using ::android::hardware::hidl_vec;
+using ::android::hardware::gnss::V2_0::IGnssDebug;
+
+#define GNSS_DEBUG_UNKNOWN_HORIZONTAL_ACCURACY_METERS (20000000)
+#define GNSS_DEBUG_UNKNOWN_VERTICAL_ACCURACY_METERS (20000)
+#define GNSS_DEBUG_UNKNOWN_SPEED_ACCURACY_PER_SEC (500)
+#define GNSS_DEBUG_UNKNOWN_BEARING_ACCURACY_DEG (180)
+
+#define GNSS_DEBUG_UNKNOWN_UTC_TIME (1483228800000LL) // 1/1/2017 00:00 GMT
+#define GNSS_DEBUG_UNKNOWN_UTC_TIME_UNC_MIN (999) // 999 ns
+#define GNSS_DEBUG_UNKNOWN_UTC_TIME_UNC_MAX (1.57783680E17) // 5 years in ns
+#define GNSS_DEBUG_UNKNOWN_FREQ_UNC_NS_PER_SEC (2.0e5) // ppm
+
+GnssDebug::GnssDebug(Gnss* gnss) : mGnss(gnss)
+{
+}
+
+/*
+ * This methods requests position, time and satellite ephemeris debug information
+ * from the HAL.
+ *
+ * @return void
+*/
+Return<void> GnssDebug::getDebugData(getDebugData_cb _hidl_cb)
+{
+ LOC_LOGD("%s]: ", __func__);
+
+ V1_0::IGnssDebug::DebugData data = { };
+
+ if((nullptr == mGnss) || (nullptr == mGnss->getGnssInterface())){
+ LOC_LOGE("GnssDebug - Null GNSS interface");
+ _hidl_cb(data);
+ return Void();
+ }
+
+ // get debug report snapshot via hal interface
+ GnssDebugReport reports = { };
+ mGnss->getGnssInterface()->getDebugReport(reports);
+
+ // location block
+ if (reports.mLocation.mValid) {
+ data.position.valid = true;
+ data.position.latitudeDegrees = reports.mLocation.mLocation.latitude;
+ data.position.longitudeDegrees = reports.mLocation.mLocation.longitude;
+ data.position.altitudeMeters = reports.mLocation.mLocation.altitude;
+
+ data.position.speedMetersPerSec =
+ (double)(reports.mLocation.mLocation.speed);
+ data.position.bearingDegrees =
+ (double)(reports.mLocation.mLocation.bearing);
+ data.position.horizontalAccuracyMeters =
+ (double)(reports.mLocation.mLocation.accuracy);
+ data.position.verticalAccuracyMeters =
+ reports.mLocation.verticalAccuracyMeters;
+ data.position.speedAccuracyMetersPerSecond =
+ reports.mLocation.speedAccuracyMetersPerSecond;
+ data.position.bearingAccuracyDegrees =
+ reports.mLocation.bearingAccuracyDegrees;
+
+ timeval tv_now, tv_report;
+ tv_report.tv_sec = reports.mLocation.mUtcReported.tv_sec;
+ tv_report.tv_usec = reports.mLocation.mUtcReported.tv_nsec / 1000ULL;
+ gettimeofday(&tv_now, NULL);
+ data.position.ageSeconds =
+ (tv_now.tv_sec - tv_report.tv_sec) +
+ (float)((tv_now.tv_usec - tv_report.tv_usec)) / 1000000;
+ }
+ else {
+ data.position.valid = false;
+ }
+
+ if (data.position.horizontalAccuracyMeters <= 0 ||
+ data.position.horizontalAccuracyMeters > GNSS_DEBUG_UNKNOWN_HORIZONTAL_ACCURACY_METERS) {
+ data.position.horizontalAccuracyMeters = GNSS_DEBUG_UNKNOWN_HORIZONTAL_ACCURACY_METERS;
+ }
+ if (data.position.verticalAccuracyMeters <= 0 ||
+ data.position.verticalAccuracyMeters > GNSS_DEBUG_UNKNOWN_VERTICAL_ACCURACY_METERS) {
+ data.position.verticalAccuracyMeters = GNSS_DEBUG_UNKNOWN_VERTICAL_ACCURACY_METERS;
+ }
+ if (data.position.speedAccuracyMetersPerSecond <= 0 ||
+ data.position.speedAccuracyMetersPerSecond > GNSS_DEBUG_UNKNOWN_SPEED_ACCURACY_PER_SEC) {
+ data.position.speedAccuracyMetersPerSecond = GNSS_DEBUG_UNKNOWN_SPEED_ACCURACY_PER_SEC;
+ }
+ if (data.position.bearingAccuracyDegrees <= 0 ||
+ data.position.bearingAccuracyDegrees > GNSS_DEBUG_UNKNOWN_BEARING_ACCURACY_DEG) {
+ data.position.bearingAccuracyDegrees = GNSS_DEBUG_UNKNOWN_BEARING_ACCURACY_DEG;
+ }
+
+ // time block
+ if (reports.mTime.mValid) {
+ data.time.timeEstimate = reports.mTime.timeEstimate;
+ data.time.timeUncertaintyNs = reports.mTime.timeUncertaintyNs;
+ data.time.frequencyUncertaintyNsPerSec =
+ reports.mTime.frequencyUncertaintyNsPerSec;
+ }
+
+ if (data.time.timeEstimate < GNSS_DEBUG_UNKNOWN_UTC_TIME) {
+ data.time.timeEstimate = GNSS_DEBUG_UNKNOWN_UTC_TIME;
+ }
+ if (data.time.timeUncertaintyNs <= 0) {
+ data.time.timeUncertaintyNs = (float)GNSS_DEBUG_UNKNOWN_UTC_TIME_UNC_MIN;
+ } else if (data.time.timeUncertaintyNs > GNSS_DEBUG_UNKNOWN_UTC_TIME_UNC_MAX) {
+ data.time.timeUncertaintyNs = (float)GNSS_DEBUG_UNKNOWN_UTC_TIME_UNC_MAX;
+ }
+ if (data.time.frequencyUncertaintyNsPerSec <= 0 ||
+ data.time.frequencyUncertaintyNsPerSec > (float)GNSS_DEBUG_UNKNOWN_FREQ_UNC_NS_PER_SEC) {
+ data.time.frequencyUncertaintyNsPerSec = (float)GNSS_DEBUG_UNKNOWN_FREQ_UNC_NS_PER_SEC;
+ }
+
+ // satellite data block
+ V1_0::IGnssDebug::SatelliteData s = { };
+ std::vector<V1_0::IGnssDebug::SatelliteData> s_array;
+
+ for (uint32_t i=0; i<reports.mSatelliteInfo.size(); i++) {
+ memset(&s, 0, sizeof(s));
+ s.svid = reports.mSatelliteInfo[i].svid;
+ convertGnssConstellationType(
+ reports.mSatelliteInfo[i].constellation, s.constellation);
+ convertGnssEphemerisType(
+ reports.mSatelliteInfo[i].mEphemerisType, s.ephemerisType);
+ convertGnssEphemerisSource(
+ reports.mSatelliteInfo[i].mEphemerisSource, s.ephemerisSource);
+ convertGnssEphemerisHealth(
+ reports.mSatelliteInfo[i].mEphemerisHealth, s.ephemerisHealth);
+
+ s.ephemerisAgeSeconds =
+ reports.mSatelliteInfo[i].ephemerisAgeSeconds;
+ s.serverPredictionIsAvailable =
+ reports.mSatelliteInfo[i].serverPredictionIsAvailable;
+ s.serverPredictionAgeSeconds =
+ reports.mSatelliteInfo[i].serverPredictionAgeSeconds;
+
+ s_array.push_back(s);
+ }
+ data.satelliteDataArray = s_array;
+
+ // callback HIDL with collected debug data
+ _hidl_cb(data);
+ return Void();
+}
+
+Return<void> GnssDebug::getDebugData_2_0(getDebugData_2_0_cb _hidl_cb)
+{
+ LOC_LOGD("%s]: ", __func__);
+
+ V2_0::IGnssDebug::DebugData data = { };
+
+ if((nullptr == mGnss) || (nullptr == mGnss->getGnssInterface())){
+ LOC_LOGE("GnssDebug - Null GNSS interface");
+ _hidl_cb(data);
+ return Void();
+ }
+
+ // get debug report snapshot via hal interface
+ GnssDebugReport reports = { };
+ mGnss->getGnssInterface()->getDebugReport(reports);
+
+ // location block
+ if (reports.mLocation.mValid) {
+ data.position.valid = true;
+ data.position.latitudeDegrees = reports.mLocation.mLocation.latitude;
+ data.position.longitudeDegrees = reports.mLocation.mLocation.longitude;
+ data.position.altitudeMeters = reports.mLocation.mLocation.altitude;
+
+ data.position.speedMetersPerSec =
+ (double)(reports.mLocation.mLocation.speed);
+ data.position.bearingDegrees =
+ (double)(reports.mLocation.mLocation.bearing);
+ data.position.horizontalAccuracyMeters =
+ (double)(reports.mLocation.mLocation.accuracy);
+ data.position.verticalAccuracyMeters =
+ reports.mLocation.verticalAccuracyMeters;
+ data.position.speedAccuracyMetersPerSecond =
+ reports.mLocation.speedAccuracyMetersPerSecond;
+ data.position.bearingAccuracyDegrees =
+ reports.mLocation.bearingAccuracyDegrees;
+
+ timeval tv_now, tv_report;
+ tv_report.tv_sec = reports.mLocation.mUtcReported.tv_sec;
+ tv_report.tv_usec = reports.mLocation.mUtcReported.tv_nsec / 1000ULL;
+ gettimeofday(&tv_now, NULL);
+ data.position.ageSeconds =
+ (tv_now.tv_sec - tv_report.tv_sec) +
+ (float)((tv_now.tv_usec - tv_report.tv_usec)) / 1000000;
+ }
+ else {
+ data.position.valid = false;
+ }
+
+ if (data.position.horizontalAccuracyMeters <= 0 ||
+ data.position.horizontalAccuracyMeters > GNSS_DEBUG_UNKNOWN_HORIZONTAL_ACCURACY_METERS) {
+ data.position.horizontalAccuracyMeters = GNSS_DEBUG_UNKNOWN_HORIZONTAL_ACCURACY_METERS;
+ }
+ if (data.position.verticalAccuracyMeters <= 0 ||
+ data.position.verticalAccuracyMeters > GNSS_DEBUG_UNKNOWN_VERTICAL_ACCURACY_METERS) {
+ data.position.verticalAccuracyMeters = GNSS_DEBUG_UNKNOWN_VERTICAL_ACCURACY_METERS;
+ }
+ if (data.position.speedAccuracyMetersPerSecond <= 0 ||
+ data.position.speedAccuracyMetersPerSecond > GNSS_DEBUG_UNKNOWN_SPEED_ACCURACY_PER_SEC) {
+ data.position.speedAccuracyMetersPerSecond = GNSS_DEBUG_UNKNOWN_SPEED_ACCURACY_PER_SEC;
+ }
+ if (data.position.bearingAccuracyDegrees <= 0 ||
+ data.position.bearingAccuracyDegrees > GNSS_DEBUG_UNKNOWN_BEARING_ACCURACY_DEG) {
+ data.position.bearingAccuracyDegrees = GNSS_DEBUG_UNKNOWN_BEARING_ACCURACY_DEG;
+ }
+
+ // time block
+ if (reports.mTime.mValid) {
+ data.time.timeEstimate = reports.mTime.timeEstimate;
+ data.time.timeUncertaintyNs = reports.mTime.timeUncertaintyNs;
+ data.time.frequencyUncertaintyNsPerSec =
+ reports.mTime.frequencyUncertaintyNsPerSec;
+ }
+
+ if (data.time.timeEstimate < GNSS_DEBUG_UNKNOWN_UTC_TIME) {
+ data.time.timeEstimate = GNSS_DEBUG_UNKNOWN_UTC_TIME;
+ }
+ if (data.time.timeUncertaintyNs <= 0) {
+ data.time.timeUncertaintyNs = (float)GNSS_DEBUG_UNKNOWN_UTC_TIME_UNC_MIN;
+ }
+ else if (data.time.timeUncertaintyNs > GNSS_DEBUG_UNKNOWN_UTC_TIME_UNC_MAX) {
+ data.time.timeUncertaintyNs = (float)GNSS_DEBUG_UNKNOWN_UTC_TIME_UNC_MAX;
+ }
+ if (data.time.frequencyUncertaintyNsPerSec <= 0 ||
+ data.time.frequencyUncertaintyNsPerSec > (float)GNSS_DEBUG_UNKNOWN_FREQ_UNC_NS_PER_SEC) {
+ data.time.frequencyUncertaintyNsPerSec = (float)GNSS_DEBUG_UNKNOWN_FREQ_UNC_NS_PER_SEC;
+ }
+
+ // satellite data block
+ V2_0::IGnssDebug::SatelliteData s = { };
+ std::vector<V2_0::IGnssDebug::SatelliteData> s_array;
+
+ for (uint32_t i=0; i<reports.mSatelliteInfo.size(); i++) {
+ memset(&s, 0, sizeof(s));
+ s.v1_0.svid = reports.mSatelliteInfo[i].svid;
+ convertGnssConstellationType(
+ reports.mSatelliteInfo[i].constellation, s.constellation);
+ convertGnssEphemerisType(
+ reports.mSatelliteInfo[i].mEphemerisType, s.v1_0.ephemerisType);
+ convertGnssEphemerisSource(
+ reports.mSatelliteInfo[i].mEphemerisSource, s.v1_0.ephemerisSource);
+ convertGnssEphemerisHealth(
+ reports.mSatelliteInfo[i].mEphemerisHealth, s.v1_0.ephemerisHealth);
+
+ s.v1_0.ephemerisAgeSeconds =
+ reports.mSatelliteInfo[i].ephemerisAgeSeconds;
+ s.v1_0.serverPredictionIsAvailable =
+ reports.mSatelliteInfo[i].serverPredictionIsAvailable;
+ s.v1_0.serverPredictionAgeSeconds =
+ reports.mSatelliteInfo[i].serverPredictionAgeSeconds;
+
+ s_array.push_back(s);
+ }
+ data.satelliteDataArray = s_array;
+
+ // callback HIDL with collected debug data
+ _hidl_cb(data);
+ return Void();
+}
+
+} // namespace implementation
+} // namespace V2_0
+} // namespace gnss
+} // namespace hardware
+} // namespace android
diff --git a/android/2.0/GnssDebug.h b/android/2.0/GnssDebug.h
new file mode 100644
index 0000000..8d75bea
--- /dev/null
+++ b/android/2.0/GnssDebug.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved.
+ * Not a Contribution
+ */
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HARDWARE_GNSS_V2_0_GNSSDEBUG_H
+#define ANDROID_HARDWARE_GNSS_V2_0_GNSSDEBUG_H
+
+
+#include <android/hardware/gnss/2.0/IGnssDebug.h>
+#include <hidl/Status.h>
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace V2_0 {
+namespace implementation {
+
+using ::android::hardware::gnss::V2_0::IGnssDebug;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::hidl_string;
+using ::android::sp;
+
+/* Interface for GNSS Debug support. */
+struct Gnss;
+struct GnssDebug : public IGnssDebug {
+ GnssDebug(Gnss* gnss);
+ ~GnssDebug() {};
+
+ // Methods from ::android::hardware::gnss::V1_0::IGnssDebug follow
+ Return<void> getDebugData(getDebugData_cb _hidl_cb) override;
+ // Methods from ::android::hardware::gnss::V2_0::IGnssDebug follow.
+ Return<void> getDebugData_2_0(getDebugData_2_0_cb _hidl_cb) override;
+
+private:
+ Gnss* mGnss = nullptr;
+};
+
+} // namespace implementation
+} // namespace V2_0
+} // namespace gnss
+} // namespace hardware
+} // namespace android
+
+#endif // ANDROID_HARDWARE_GNSS_V2_0_GNSSDEBUG_H
diff --git a/android/2.0/GnssGeofencing.cpp b/android/2.0/GnssGeofencing.cpp
new file mode 100644
index 0000000..b72d835
--- /dev/null
+++ b/android/2.0/GnssGeofencing.cpp
@@ -0,0 +1,141 @@
+/*
+ * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved.
+ * Not a Contribution
+ */
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "GnssHal_GnssGeofencing"
+
+#include <log_util.h>
+#include <GeofenceAPIClient.h>
+#include "GnssGeofencing.h"
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace V2_0 {
+namespace implementation {
+
+void GnssGeofencing::GnssGeofencingDeathRecipient::serviceDied(
+ uint64_t cookie, const wp<IBase>& who) {
+ LOC_LOGE("%s] service died. cookie: %llu, who: %p",
+ __FUNCTION__, static_cast<unsigned long long>(cookie), &who);
+ if (mGnssGeofencing != nullptr) {
+ mGnssGeofencing->removeAllGeofences();
+ }
+}
+
+GnssGeofencing::GnssGeofencing() : mApi(nullptr) {
+ mGnssGeofencingDeathRecipient = new GnssGeofencingDeathRecipient(this);
+}
+
+GnssGeofencing::~GnssGeofencing() {
+ if (mApi != nullptr) {
+ delete mApi;
+ mApi = nullptr;
+ }
+}
+
+// Methods from ::android::hardware::gnss::V1_0::IGnssGeofencing follow.
+Return<void> GnssGeofencing::setCallback(const sp<IGnssGeofenceCallback>& callback) {
+ if (mApi != nullptr) {
+ LOC_LOGd("mApi is NOT nullptr");
+ return Void();
+ }
+
+ mApi = new GeofenceAPIClient(callback);
+ if (mApi == nullptr) {
+ LOC_LOGE("%s]: failed to create mApi", __FUNCTION__);
+ }
+
+ if (mGnssGeofencingCbIface != nullptr) {
+ mGnssGeofencingCbIface->unlinkToDeath(mGnssGeofencingDeathRecipient);
+ }
+ mGnssGeofencingCbIface = callback;
+ if (mGnssGeofencingCbIface != nullptr) {
+ mGnssGeofencingCbIface->linkToDeath(mGnssGeofencingDeathRecipient, 0 /*cookie*/);
+ }
+
+ return Void();
+}
+
+Return<void> GnssGeofencing::addGeofence(
+ int32_t geofenceId,
+ double latitudeDegrees,
+ double longitudeDegrees,
+ double radiusMeters,
+ IGnssGeofenceCallback::GeofenceTransition lastTransition,
+ int32_t monitorTransitions,
+ uint32_t notificationResponsivenessMs,
+ uint32_t unknownTimerMs) {
+ if (mApi == nullptr) {
+ LOC_LOGE("%s]: mApi is nullptr", __FUNCTION__);
+ } else {
+ mApi->geofenceAdd(
+ geofenceId,
+ latitudeDegrees,
+ longitudeDegrees,
+ radiusMeters,
+ static_cast<int32_t>(lastTransition),
+ monitorTransitions,
+ notificationResponsivenessMs,
+ unknownTimerMs);
+ }
+ return Void();
+}
+
+Return<void> GnssGeofencing::pauseGeofence(int32_t geofenceId) {
+ if (mApi == nullptr) {
+ LOC_LOGE("%s]: mApi is nullptr", __FUNCTION__);
+ } else {
+ mApi->geofencePause(geofenceId);
+ }
+ return Void();
+}
+
+Return<void> GnssGeofencing::resumeGeofence(int32_t geofenceId, int32_t monitorTransitions) {
+ if (mApi == nullptr) {
+ LOC_LOGE("%s]: mApi is nullptr", __FUNCTION__);
+ } else {
+ mApi->geofenceResume(geofenceId, monitorTransitions);
+ }
+ return Void();
+}
+
+Return<void> GnssGeofencing::removeGeofence(int32_t geofenceId) {
+ if (mApi == nullptr) {
+ LOC_LOGE("%s]: mApi is nullptr", __FUNCTION__);
+ } else {
+ mApi->geofenceRemove(geofenceId);
+ }
+ return Void();
+}
+
+Return<void> GnssGeofencing::removeAllGeofences() {
+ if (mApi == nullptr) {
+ LOC_LOGD("%s]: mApi is nullptr, do nothing", __FUNCTION__);
+ } else {
+ mApi->geofenceRemoveAll();
+ }
+ return Void();
+}
+
+} // namespace implementation
+} // namespace V2_0
+} // namespace gnss
+} // namespace hardware
+} // namespace android
diff --git a/android/2.0/GnssGeofencing.h b/android/2.0/GnssGeofencing.h
new file mode 100644
index 0000000..caa56d0
--- /dev/null
+++ b/android/2.0/GnssGeofencing.h
@@ -0,0 +1,91 @@
+/*
+ * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved.
+ * Not a Contribution
+ */
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HARDWARE_GNSS_V2_0_GNSSGEOFENCING_H
+#define ANDROID_HARDWARE_GNSS_V2_0_GNSSGEOFENCING_H
+
+#include <android/hardware/gnss/1.0/IGnssGeofencing.h>
+#include <hidl/Status.h>
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace V2_0 {
+namespace implementation {
+
+using ::android::hardware::gnss::V1_0::IGnssGeofenceCallback;
+using ::android::hardware::gnss::V1_0::IGnssGeofencing;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::hidl_string;
+using ::android::sp;
+
+class GeofenceAPIClient;
+struct GnssGeofencing : public IGnssGeofencing {
+ GnssGeofencing();
+ ~GnssGeofencing();
+
+ /*
+ * Methods from ::android::hardware::gnss::V1_0::IGnssGeofencing follow.
+ * These declarations were generated from IGnssGeofencing.hal.
+ */
+ Return<void> setCallback(const sp<IGnssGeofenceCallback>& callback) override;
+ Return<void> addGeofence(int32_t geofenceId,
+ double latitudeDegrees,
+ double longitudeDegrees,
+ double radiusMeters,
+ IGnssGeofenceCallback::GeofenceTransition lastTransition,
+ int32_t monitorTransitions,
+ uint32_t notificationResponsivenessMs,
+ uint32_t unknownTimerMs) override;
+
+ Return<void> pauseGeofence(int32_t geofenceId) override;
+ Return<void> resumeGeofence(int32_t geofenceId, int32_t monitorTransitions) override;
+ Return<void> removeGeofence(int32_t geofenceId) override;
+
+ private:
+ // This method is not part of the IGnss base class.
+ // It is called by GnssGeofencingDeathRecipient to remove all geofences added so far.
+ Return<void> removeAllGeofences();
+
+ private:
+ struct GnssGeofencingDeathRecipient : hidl_death_recipient {
+ GnssGeofencingDeathRecipient(sp<GnssGeofencing> gnssGeofencing) :
+ mGnssGeofencing(gnssGeofencing) {
+ }
+ ~GnssGeofencingDeathRecipient() = default;
+ virtual void serviceDied(uint64_t cookie, const wp<IBase>& who) override;
+ sp<GnssGeofencing> mGnssGeofencing;
+ };
+
+ private:
+ sp<GnssGeofencingDeathRecipient> mGnssGeofencingDeathRecipient = nullptr;
+ sp<IGnssGeofenceCallback> mGnssGeofencingCbIface = nullptr;
+ GeofenceAPIClient* mApi = nullptr;
+};
+
+} // namespace implementation
+} // namespace V2_0
+} // namespace gnss
+} // namespace hardware
+} // namespace android
+
+#endif // ANDROID_HARDWARE_GNSS_V2_0_GNSSGEOFENCING_H
diff --git a/android/2.0/GnssMeasurement.cpp b/android/2.0/GnssMeasurement.cpp
new file mode 100644
index 0000000..721a48c
--- /dev/null
+++ b/android/2.0/GnssMeasurement.cpp
@@ -0,0 +1,165 @@
+/*
+ * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved.
+ * Not a Contribution
+ */
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "LocSvc_GnssMeasurementInterface"
+
+#include <log_util.h>
+#include "GnssMeasurement.h"
+#include "MeasurementAPIClient.h"
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace V2_0 {
+namespace implementation {
+
+void GnssMeasurement::GnssMeasurementDeathRecipient::serviceDied(
+ uint64_t cookie, const wp<IBase>& who) {
+ LOC_LOGE("%s] service died. cookie: %llu, who: %p",
+ __FUNCTION__, static_cast<unsigned long long>(cookie), &who);
+ if (mGnssMeasurement != nullptr) {
+ mGnssMeasurement->close();
+ }
+}
+
+GnssMeasurement::GnssMeasurement() {
+ mGnssMeasurementDeathRecipient = new GnssMeasurementDeathRecipient(this);
+ mApi = new MeasurementAPIClient();
+}
+
+GnssMeasurement::~GnssMeasurement() {
+ if (mApi) {
+ delete mApi;
+ mApi = nullptr;
+ }
+}
+
+// Methods from ::android::hardware::gnss::V1_0::IGnssMeasurement follow.
+Return<GnssMeasurement::GnssMeasurementStatus> GnssMeasurement::setCallback(
+ const sp<V1_0::IGnssMeasurementCallback>& callback) {
+
+ Return<GnssMeasurement::GnssMeasurementStatus> ret =
+ IGnssMeasurement::GnssMeasurementStatus::ERROR_GENERIC;
+ if (mGnssMeasurementCbIface != nullptr) {
+ LOC_LOGE("%s]: GnssMeasurementCallback is already set", __FUNCTION__);
+ return IGnssMeasurement::GnssMeasurementStatus::ERROR_ALREADY_INIT;
+ }
+
+ if (callback == nullptr) {
+ LOC_LOGE("%s]: callback is nullptr", __FUNCTION__);
+ return ret;
+ }
+ if (mApi == nullptr) {
+ LOC_LOGE("%s]: mApi is nullptr", __FUNCTION__);
+ return ret;
+ }
+
+ mGnssMeasurementCbIface = callback;
+ mGnssMeasurementCbIface->linkToDeath(mGnssMeasurementDeathRecipient, 0);
+
+ return mApi->measurementSetCallback(callback);
+}
+
+Return<void> GnssMeasurement::close() {
+ if (mApi == nullptr) {
+ LOC_LOGE("%s]: mApi is nullptr", __FUNCTION__);
+ return Void();
+ }
+
+ if (mGnssMeasurementCbIface != nullptr) {
+ mGnssMeasurementCbIface->unlinkToDeath(mGnssMeasurementDeathRecipient);
+ mGnssMeasurementCbIface = nullptr;
+ }
+ if (mGnssMeasurementCbIface_1_1 != nullptr) {
+ mGnssMeasurementCbIface_1_1->unlinkToDeath(mGnssMeasurementDeathRecipient);
+ mGnssMeasurementCbIface_1_1 = nullptr;
+ }
+ if (mGnssMeasurementCbIface_2_0 != nullptr) {
+ mGnssMeasurementCbIface_2_0->unlinkToDeath(mGnssMeasurementDeathRecipient);
+ mGnssMeasurementCbIface_2_0 = nullptr;
+ }
+ mApi->measurementClose();
+
+ return Void();
+}
+
+// Methods from ::android::hardware::gnss::V1_1::IGnssMeasurement follow.
+Return<GnssMeasurement::GnssMeasurementStatus> GnssMeasurement::setCallback_1_1(
+ const sp<V1_1::IGnssMeasurementCallback>& callback, bool enableFullTracking) {
+
+ Return<GnssMeasurement::GnssMeasurementStatus> ret =
+ IGnssMeasurement::GnssMeasurementStatus::ERROR_GENERIC;
+ if (mGnssMeasurementCbIface_1_1 != nullptr) {
+ LOC_LOGE("%s]: GnssMeasurementCallback is already set", __FUNCTION__);
+ return IGnssMeasurement::GnssMeasurementStatus::ERROR_ALREADY_INIT;
+ }
+
+ if (callback == nullptr) {
+ LOC_LOGE("%s]: callback is nullptr", __FUNCTION__);
+ return ret;
+ }
+ if (nullptr == mApi) {
+ LOC_LOGE("%s]: mApi is nullptr", __FUNCTION__);
+ return ret;
+ }
+
+ mGnssMeasurementCbIface_1_1 = callback;
+ mGnssMeasurementCbIface_1_1->linkToDeath(mGnssMeasurementDeathRecipient, 0);
+
+ GnssPowerMode powerMode = enableFullTracking?
+ GNSS_POWER_MODE_M1 : GNSS_POWER_MODE_M2;
+
+ return mApi->measurementSetCallback_1_1(callback, powerMode);
+}
+// Methods from ::android::hardware::gnss::V2_0::IGnssMeasurement follow.
+Return<V1_0::IGnssMeasurement::GnssMeasurementStatus> GnssMeasurement::setCallback_2_0(
+ const sp<V2_0::IGnssMeasurementCallback>& callback,
+ bool enableFullTracking) {
+
+ Return<GnssMeasurement::GnssMeasurementStatus> ret =
+ IGnssMeasurement::GnssMeasurementStatus::ERROR_GENERIC;
+ if (mGnssMeasurementCbIface_2_0 != nullptr) {
+ LOC_LOGE("%s]: GnssMeasurementCallback is already set", __FUNCTION__);
+ return IGnssMeasurement::GnssMeasurementStatus::ERROR_ALREADY_INIT;
+ }
+
+ if (callback == nullptr) {
+ LOC_LOGE("%s]: callback is nullptr", __FUNCTION__);
+ return ret;
+ }
+ if (nullptr == mApi) {
+ LOC_LOGE("%s]: mApi is nullptr", __FUNCTION__);
+ return ret;
+ }
+
+ mGnssMeasurementCbIface_2_0 = callback;
+ mGnssMeasurementCbIface_2_0->linkToDeath(mGnssMeasurementDeathRecipient, 0);
+
+ GnssPowerMode powerMode = enableFullTracking ?
+ GNSS_POWER_MODE_M1 : GNSS_POWER_MODE_M2;
+
+ return mApi->measurementSetCallback_2_0(callback, powerMode);
+}
+
+} // namespace implementation
+} // namespace V2_0
+} // namespace gnss
+} // namespace hardware
+} // namespace android
diff --git a/android/2.0/GnssMeasurement.h b/android/2.0/GnssMeasurement.h
new file mode 100644
index 0000000..000b00f
--- /dev/null
+++ b/android/2.0/GnssMeasurement.h
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved.
+ * Not a Contribution
+ */
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HARDWARE_GNSS_V2_0_GNSSMEASUREMENT_H
+#define ANDROID_HARDWARE_GNSS_V2_0_GNSSMEASUREMENT_H
+
+#include <android/hardware/gnss/2.0/IGnssMeasurement.h>
+#include <hidl/MQDescriptor.h>
+#include <hidl/Status.h>
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace V2_0 {
+namespace implementation {
+
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::hidl_string;
+using ::android::sp;
+
+class MeasurementAPIClient;
+struct GnssMeasurement : public V2_0::IGnssMeasurement {
+ GnssMeasurement();
+ ~GnssMeasurement();
+
+ /*
+ * Methods from ::android::hardware::gnss::V1_0::IGnssMeasurement follow.
+ * These declarations were generated from IGnssMeasurement.hal.
+ */
+ Return<GnssMeasurement::GnssMeasurementStatus> setCallback(
+ const sp<V1_0::IGnssMeasurementCallback>& callback) override;
+ Return<void> close() override;
+
+ // Methods from ::android::hardware::gnss::V1_1::IGnssMeasurement follow.
+ Return<GnssMeasurement::GnssMeasurementStatus> setCallback_1_1(
+ const sp<V1_1::IGnssMeasurementCallback>& callback,
+ bool enableFullTracking) override;
+
+ // Methods from ::android::hardware::gnss::V2_0::IGnssMeasurement follow.
+ Return<GnssMeasurement::GnssMeasurementStatus> setCallback_2_0(
+ const sp<V2_0::IGnssMeasurementCallback>& callback,
+ bool enableFullTracking) override;
+ private:
+ struct GnssMeasurementDeathRecipient : hidl_death_recipient {
+ GnssMeasurementDeathRecipient(sp<GnssMeasurement> gnssMeasurement) :
+ mGnssMeasurement(gnssMeasurement) {
+ }
+ ~GnssMeasurementDeathRecipient() = default;
+ virtual void serviceDied(uint64_t cookie, const wp<IBase>& who) override;
+ sp<GnssMeasurement> mGnssMeasurement;
+ };
+
+ private:
+ sp<GnssMeasurementDeathRecipient> mGnssMeasurementDeathRecipient = nullptr;
+ sp<V1_0::IGnssMeasurementCallback> mGnssMeasurementCbIface = nullptr;
+ sp<V1_1::IGnssMeasurementCallback> mGnssMeasurementCbIface_1_1 = nullptr;
+ sp<V2_0::IGnssMeasurementCallback> mGnssMeasurementCbIface_2_0 = nullptr;
+ MeasurementAPIClient* mApi;
+};
+
+} // namespace implementation
+} // namespace V2_0
+} // namespace gnss
+} // namespace hardware
+} // namespace android
+
+#endif // ANDROID_HARDWARE_GNSS_V2_0_GNSSMEASUREMENT_H
diff --git a/android/2.0/GnssNi.cpp b/android/2.0/GnssNi.cpp
new file mode 100644
index 0000000..d65a488
--- /dev/null
+++ b/android/2.0/GnssNi.cpp
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved.
+ * Not a Contribution
+ */
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "LocSvc_GnssNiInterface"
+
+#include <log_util.h>
+#include "Gnss.h"
+#include "GnssNi.h"
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace V2_0 {
+namespace implementation {
+
+void GnssNi::GnssNiDeathRecipient::serviceDied(uint64_t cookie, const wp<IBase>& who) {
+ LOC_LOGE("%s] service died. cookie: %llu, who: %p",
+ __FUNCTION__, static_cast<unsigned long long>(cookie), &who);
+ // we do nothing here
+ // Gnss::GnssDeathRecipient will stop the session
+}
+
+GnssNi::GnssNi(Gnss* gnss) : mGnss(gnss) {
+ mGnssNiDeathRecipient = new GnssNiDeathRecipient(this);
+}
+
+// Methods from ::android::hardware::gnss::V1_0::IGnssNi follow.
+Return<void> GnssNi::setCallback(const sp<IGnssNiCallback>& callback) {
+ if (mGnss == nullptr) {
+ LOC_LOGE("%s]: mGnss is nullptr", __FUNCTION__);
+ return Void();
+ }
+
+ mGnss->setGnssNiCb(callback);
+
+ if (mGnssNiCbIface != nullptr) {
+ mGnssNiCbIface->unlinkToDeath(mGnssNiDeathRecipient);
+ }
+ mGnssNiCbIface = callback;
+ if (mGnssNiCbIface != nullptr) {
+ mGnssNiCbIface->linkToDeath(mGnssNiDeathRecipient, 0 /*cookie*/);
+ }
+
+ return Void();
+}
+
+Return<void> GnssNi::respond(int32_t notifId, IGnssNiCallback::GnssUserResponseType userResponse) {
+ if (mGnss == nullptr) {
+ LOC_LOGE("%s]: mGnss is nullptr", __FUNCTION__);
+ return Void();
+ }
+
+ GnssAPIClient* api = mGnss->getApi();
+ if (api == nullptr) {
+ LOC_LOGE("%s]: api is nullptr", __FUNCTION__);
+ return Void();
+ }
+
+ api->gnssNiRespond(notifId, userResponse);
+
+ return Void();
+}
+
+} // namespace implementation
+} // namespace V2_0
+} // namespace gnss
+} // namespace hardware
+} // namespace android
diff --git a/android/2.0/GnssNi.h b/android/2.0/GnssNi.h
new file mode 100644
index 0000000..26e281f
--- /dev/null
+++ b/android/2.0/GnssNi.h
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved.
+ * Not a Contribution
+ */
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HARDWARE_GNSS_V2_0_GNSSNI_H
+#define ANDROID_HARDWARE_GNSS_V2_0_GNSSNI_H
+
+#include <android/hardware/gnss/1.0/IGnssNi.h>
+#include <hidl/Status.h>
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace V2_0 {
+namespace implementation {
+
+using ::android::hardware::gnss::V1_0::IGnssNi;
+using ::android::hardware::gnss::V1_0::IGnssNiCallback;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::hidl_string;
+using ::android::sp;
+
+struct Gnss;
+struct GnssNi : public IGnssNi {
+ GnssNi(Gnss* gnss);
+ ~GnssNi() = default;
+
+ /*
+ * Methods from ::android::hardware::gnss::V1_0::IGnssNi follow.
+ * These declarations were generated from IGnssNi.hal.
+ */
+ Return<void> setCallback(const sp<IGnssNiCallback>& callback) override;
+ Return<void> respond(int32_t notifId,
+ IGnssNiCallback::GnssUserResponseType userResponse) override;
+
+ private:
+ struct GnssNiDeathRecipient : hidl_death_recipient {
+ GnssNiDeathRecipient(sp<GnssNi> gnssNi) : mGnssNi(gnssNi) {
+ }
+ ~GnssNiDeathRecipient() = default;
+ virtual void serviceDied(uint64_t cookie, const wp<IBase>& who) override;
+ sp<GnssNi> mGnssNi;
+ };
+
+ private:
+ sp<GnssNiDeathRecipient> mGnssNiDeathRecipient = nullptr;
+ sp<IGnssNiCallback> mGnssNiCbIface = nullptr;
+ Gnss* mGnss = nullptr;
+};
+
+} // namespace implementation
+} // namespace V2_0
+} // namespace gnss
+} // namespace hardware
+} // namespace android
+
+#endif // ANDROID_HARDWARE_GNSS_V2_0_GNSSNI_H
diff --git a/android/2.0/android.hardware.gnss@2.0-service-qti.rc b/android/2.0/android.hardware.gnss@2.0-service-qti.rc
new file mode 100644
index 0000000..36ee47c
--- /dev/null
+++ b/android/2.0/android.hardware.gnss@2.0-service-qti.rc
@@ -0,0 +1,4 @@
+service gnss_service /vendor/bin/hw/android.hardware.gnss@2.0-service-qti
+ class hal
+ user gps
+ group system gps radio
diff --git a/android/2.0/android.hardware.gnss@2.0-service-qti.xml b/android/2.0/android.hardware.gnss@2.0-service-qti.xml
new file mode 100644
index 0000000..ff9fb2c
--- /dev/null
+++ b/android/2.0/android.hardware.gnss@2.0-service-qti.xml
@@ -0,0 +1,36 @@
+<!-- Copyright (c) 2019, 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.
+-->
+<manifest version="1.0" type="device">
+ <hal format="hidl">
+ <name>android.hardware.gnss</name>
+ <transport>hwbinder</transport>
+ <fqname>@1.1::IGnss/default</fqname>
+ <fqname>@2.0::IGnss/default</fqname>
+ </hal>
+</manifest>
+
diff --git a/android/2.0/location_api/BatchingAPIClient.cpp b/android/2.0/location_api/BatchingAPIClient.cpp
new file mode 100644
index 0000000..49cd18a
--- /dev/null
+++ b/android/2.0/location_api/BatchingAPIClient.cpp
@@ -0,0 +1,250 @@
+/* Copyright (c) 2017-2019, 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_NDEBUG 0
+#define LOG_TAG "LocSvc_BatchingAPIClient"
+
+#include <log_util.h>
+#include <loc_cfg.h>
+
+#include "LocationUtil.h"
+#include "BatchingAPIClient.h"
+
+#include "limits.h"
+
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace V2_0 {
+namespace implementation {
+
+using ::android::hardware::gnss::V2_0::IGnssBatching;
+using ::android::hardware::gnss::V2_0::IGnssBatchingCallback;
+using ::android::hardware::gnss::V2_0::GnssLocation;
+
+static void convertBatchOption(const IGnssBatching::Options& in, LocationOptions& out,
+ LocationCapabilitiesMask mask);
+
+BatchingAPIClient::BatchingAPIClient(const sp<V1_0::IGnssBatchingCallback>& callback) :
+ LocationAPIClientBase(),
+ mGnssBatchingCbIface(nullptr),
+ mDefaultId(UINT_MAX),
+ mLocationCapabilitiesMask(0),
+ mGnssBatchingCbIface_2_0(nullptr)
+{
+ LOC_LOGD("%s]: (%p)", __FUNCTION__, &callback);
+
+ gnssUpdateCallbacks(callback);
+}
+
+BatchingAPIClient::BatchingAPIClient(const sp<V2_0::IGnssBatchingCallback>& callback) :
+ LocationAPIClientBase(),
+ mGnssBatchingCbIface(nullptr),
+ mDefaultId(UINT_MAX),
+ mLocationCapabilitiesMask(0),
+ mGnssBatchingCbIface_2_0(nullptr)
+{
+ LOC_LOGD("%s]: (%p)", __FUNCTION__, &callback);
+
+ gnssUpdateCallbacks_2_0(callback);
+}
+
+BatchingAPIClient::~BatchingAPIClient()
+{
+ LOC_LOGD("%s]: ()", __FUNCTION__);
+}
+
+int BatchingAPIClient::getBatchSize()
+{
+ LOC_LOGD("%s]: ()", __FUNCTION__);
+ return locAPIGetBatchSize();
+}
+
+void BatchingAPIClient::setCallbacks()
+{
+ LocationCallbacks locationCallbacks;
+ memset(&locationCallbacks, 0, sizeof(LocationCallbacks));
+ locationCallbacks.size = sizeof(LocationCallbacks);
+
+ locationCallbacks.trackingCb = nullptr;
+ locationCallbacks.batchingCb = nullptr;
+ locationCallbacks.batchingCb = [this](size_t count, Location* location,
+ BatchingOptions batchOptions) {
+ onBatchingCb(count, location, batchOptions);
+ };
+ locationCallbacks.geofenceBreachCb = nullptr;
+ locationCallbacks.geofenceStatusCb = nullptr;
+ locationCallbacks.gnssLocationInfoCb = nullptr;
+ locationCallbacks.gnssNiCb = nullptr;
+ locationCallbacks.gnssSvCb = nullptr;
+ locationCallbacks.gnssNmeaCb = nullptr;
+ locationCallbacks.gnssMeasurementsCb = nullptr;
+
+ locAPISetCallbacks(locationCallbacks);
+}
+
+void BatchingAPIClient::gnssUpdateCallbacks(const sp<V1_0::IGnssBatchingCallback>& callback)
+{
+ mMutex.lock();
+ mGnssBatchingCbIface = callback;
+ mMutex.unlock();
+
+ if (mGnssBatchingCbIface != nullptr) {
+ setCallbacks();
+ }
+}
+
+void BatchingAPIClient::gnssUpdateCallbacks_2_0(const sp<V2_0::IGnssBatchingCallback>& callback)
+{
+ mMutex.lock();
+ mGnssBatchingCbIface_2_0 = callback;
+ mMutex.unlock();
+
+ if (mGnssBatchingCbIface_2_0 != nullptr) {
+ setCallbacks();
+ }
+}
+
+int BatchingAPIClient::startSession(const IGnssBatching::Options& opts)
+{
+ LOC_LOGD("%s]: (%lld %d)", __FUNCTION__,
+ static_cast<long long>(opts.periodNanos), static_cast<uint8_t>(opts.flags));
+ int retVal = -1;
+ LocationOptions options;
+ convertBatchOption(opts, options, mLocationCapabilitiesMask);
+ uint32_t mode = 0;
+ if (opts.flags == static_cast<uint8_t>(IGnssBatching::Flag::WAKEUP_ON_FIFO_FULL)) {
+ mode = SESSION_MODE_ON_FULL;
+ }
+ if (locAPIStartSession(mDefaultId, mode, options) == LOCATION_ERROR_SUCCESS) {
+ retVal = 1;
+ }
+ return retVal;
+}
+
+int BatchingAPIClient::updateSessionOptions(const IGnssBatching::Options& opts)
+{
+ LOC_LOGD("%s]: (%lld %d)", __FUNCTION__,
+ static_cast<long long>(opts.periodNanos), static_cast<uint8_t>(opts.flags));
+ int retVal = -1;
+ LocationOptions options;
+ convertBatchOption(opts, options, mLocationCapabilitiesMask);
+
+ uint32_t mode = 0;
+ if (opts.flags == static_cast<uint8_t>(IGnssBatching::Flag::WAKEUP_ON_FIFO_FULL)) {
+ mode = SESSION_MODE_ON_FULL;
+ }
+ if (locAPIUpdateSessionOptions(mDefaultId, mode, options) == LOCATION_ERROR_SUCCESS) {
+ retVal = 1;
+ }
+ return retVal;
+}
+
+int BatchingAPIClient::stopSession()
+{
+ LOC_LOGD("%s]: ", __FUNCTION__);
+ int retVal = -1;
+ if (locAPIStopSession(mDefaultId) == LOCATION_ERROR_SUCCESS) {
+ retVal = 1;
+ }
+ return retVal;
+}
+
+void BatchingAPIClient::getBatchedLocation(int last_n_locations)
+{
+ LOC_LOGD("%s]: (%d)", __FUNCTION__, last_n_locations);
+ locAPIGetBatchedLocations(mDefaultId, last_n_locations);
+}
+
+void BatchingAPIClient::flushBatchedLocations()
+{
+ LOC_LOGD("%s]: ()", __FUNCTION__);
+ locAPIGetBatchedLocations(mDefaultId, SIZE_MAX);
+}
+
+void BatchingAPIClient::onCapabilitiesCb(LocationCapabilitiesMask capabilitiesMask)
+{
+ LOC_LOGD("%s]: (%02x)", __FUNCTION__, capabilitiesMask);
+ mLocationCapabilitiesMask = capabilitiesMask;
+}
+
+void BatchingAPIClient::onBatchingCb(size_t count, Location* location,
+ BatchingOptions /*batchOptions*/)
+{
+ mMutex.lock();
+ auto gnssBatchingCbIface(mGnssBatchingCbIface);
+ auto gnssBatchingCbIface_2_0(mGnssBatchingCbIface_2_0);
+ mMutex.unlock();
+
+ LOC_LOGD("%s]: (count: %zu)", __FUNCTION__, count);
+ if (gnssBatchingCbIface_2_0 != nullptr && count > 0) {
+ hidl_vec<V2_0::GnssLocation> locationVec;
+ locationVec.resize(count);
+ for (size_t i = 0; i < count; i++) {
+ convertGnssLocation(location[i], locationVec[i]);
+ }
+ auto r = gnssBatchingCbIface_2_0->gnssLocationBatchCb(locationVec);
+ if (!r.isOk()) {
+ LOC_LOGE("%s] Error from gnssLocationBatchCb 2.0 description=%s",
+ __func__, r.description().c_str());
+ }
+ } else if (gnssBatchingCbIface != nullptr && count > 0) {
+ hidl_vec<V1_0::GnssLocation> locationVec;
+ locationVec.resize(count);
+ for (size_t i = 0; i < count; i++) {
+ convertGnssLocation(location[i], locationVec[i]);
+ }
+ auto r = gnssBatchingCbIface->gnssLocationBatchCb(locationVec);
+ if (!r.isOk()) {
+ LOC_LOGE("%s] Error from gnssLocationBatchCb 1.0 description=%s",
+ __func__, r.description().c_str());
+ }
+ }
+}
+
+static void convertBatchOption(const IGnssBatching::Options& in, LocationOptions& out,
+ LocationCapabilitiesMask mask)
+{
+ memset(&out, 0, sizeof(LocationOptions));
+ out.size = sizeof(LocationOptions);
+ out.minInterval = (uint32_t)(in.periodNanos / 1000000L);
+ out.minDistance = 0;
+ out.mode = GNSS_SUPL_MODE_STANDALONE;
+ if (mask & LOCATION_CAPABILITIES_GNSS_MSA_BIT)
+ out.mode = GNSS_SUPL_MODE_MSA;
+ if (mask & LOCATION_CAPABILITIES_GNSS_MSB_BIT)
+ out.mode = GNSS_SUPL_MODE_MSB;
+}
+
+} // namespace implementation
+} // namespace V2_0
+} // namespace gnss
+} // namespace hardware
+} // namespace android
diff --git a/android/2.0/location_api/BatchingAPIClient.h b/android/2.0/location_api/BatchingAPIClient.h
new file mode 100644
index 0000000..7198341
--- /dev/null
+++ b/android/2.0/location_api/BatchingAPIClient.h
@@ -0,0 +1,81 @@
+/* Copyright (c) 2017-2019, 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 BATCHING_API_CLINET_H
+#define BATCHING_API_CLINET_H
+
+#include <mutex>
+#include <android/hardware/gnss/2.0/IGnssBatching.h>
+#include <android/hardware/gnss/2.0/IGnssBatchingCallback.h>
+#include <pthread.h>
+
+#include <LocationAPIClientBase.h>
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace V2_0 {
+namespace implementation {
+
+class BatchingAPIClient : public LocationAPIClientBase
+{
+public:
+ BatchingAPIClient(const sp<V1_0::IGnssBatchingCallback>& callback);
+ BatchingAPIClient(const sp<V2_0::IGnssBatchingCallback>& callback);
+ void gnssUpdateCallbacks(const sp<V1_0::IGnssBatchingCallback>& callback);
+ void gnssUpdateCallbacks_2_0(const sp<V2_0::IGnssBatchingCallback>& callback);
+ ~BatchingAPIClient();
+ int getBatchSize();
+ int startSession(const V1_0::IGnssBatching::Options& options);
+ int updateSessionOptions(const V1_0::IGnssBatching::Options& options);
+ int stopSession();
+ void getBatchedLocation(int last_n_locations);
+ void flushBatchedLocations();
+
+ inline LocationCapabilitiesMask getCapabilities() { return mLocationCapabilitiesMask; }
+
+ // callbacks
+ void onCapabilitiesCb(LocationCapabilitiesMask capabilitiesMask) final;
+ void onBatchingCb(size_t count, Location* location, BatchingOptions batchOptions) final;
+
+private:
+ void setCallbacks();
+ std::mutex mMutex;
+ sp<V1_0::IGnssBatchingCallback> mGnssBatchingCbIface;
+ uint32_t mDefaultId;
+ LocationCapabilitiesMask mLocationCapabilitiesMask;
+ sp<V2_0::IGnssBatchingCallback> mGnssBatchingCbIface_2_0;
+};
+
+} // namespace implementation
+} // namespace V2_0
+} // namespace gnss
+} // namespace hardware
+} // namespace android
+#endif // BATCHING_API_CLINET_H
diff --git a/android/2.0/location_api/GeofenceAPIClient.cpp b/android/2.0/location_api/GeofenceAPIClient.cpp
new file mode 100644
index 0000000..a93c988
--- /dev/null
+++ b/android/2.0/location_api/GeofenceAPIClient.cpp
@@ -0,0 +1,275 @@
+/* Copyright (c) 2017-2019, 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_NDEBUG 0
+#define LOG_TAG "LocSvc_GeofenceApiClient"
+
+#include <log_util.h>
+#include <loc_cfg.h>
+
+#include "LocationUtil.h"
+#include "GeofenceAPIClient.h"
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace V2_0 {
+namespace implementation {
+
+using ::android::hardware::gnss::V1_0::IGnssGeofenceCallback;
+using ::android::hardware::gnss::V1_0::GnssLocation;
+
+GeofenceAPIClient::GeofenceAPIClient(const sp<IGnssGeofenceCallback>& callback) :
+ LocationAPIClientBase(),
+ mGnssGeofencingCbIface(callback)
+{
+ LOC_LOGD("%s]: (%p)", __FUNCTION__, &callback);
+
+ LocationCallbacks locationCallbacks;
+ memset(&locationCallbacks, 0, sizeof(LocationCallbacks));
+ locationCallbacks.size = sizeof(LocationCallbacks);
+
+ locationCallbacks.trackingCb = nullptr;
+ locationCallbacks.batchingCb = nullptr;
+
+ locationCallbacks.geofenceBreachCb = nullptr;
+ if (mGnssGeofencingCbIface != nullptr) {
+ locationCallbacks.geofenceBreachCb =
+ [this](GeofenceBreachNotification geofenceBreachNotification) {
+ onGeofenceBreachCb(geofenceBreachNotification);
+ };
+
+ locationCallbacks.geofenceStatusCb =
+ [this](GeofenceStatusNotification geofenceStatusNotification) {
+ onGeofenceStatusCb(geofenceStatusNotification);
+ };
+ }
+
+ locationCallbacks.gnssLocationInfoCb = nullptr;
+ locationCallbacks.gnssNiCb = nullptr;
+ locationCallbacks.gnssSvCb = nullptr;
+ locationCallbacks.gnssNmeaCb = nullptr;
+ locationCallbacks.gnssMeasurementsCb = nullptr;
+
+ locAPISetCallbacks(locationCallbacks);
+}
+
+void GeofenceAPIClient::geofenceAdd(uint32_t geofence_id, double latitude, double longitude,
+ double radius_meters, int32_t last_transition, int32_t monitor_transitions,
+ uint32_t notification_responsiveness_ms, uint32_t unknown_timer_ms)
+{
+ LOC_LOGD("%s]: (%d %f %f %f %d %d %d %d)", __FUNCTION__,
+ geofence_id, latitude, longitude, radius_meters,
+ last_transition, monitor_transitions, notification_responsiveness_ms, unknown_timer_ms);
+
+ GeofenceOption options;
+ memset(&options, 0, sizeof(GeofenceOption));
+ options.size = sizeof(GeofenceOption);
+ if (monitor_transitions & IGnssGeofenceCallback::GeofenceTransition::ENTERED)
+ options.breachTypeMask |= GEOFENCE_BREACH_ENTER_BIT;
+ if (monitor_transitions & IGnssGeofenceCallback::GeofenceTransition::EXITED)
+ options.breachTypeMask |= GEOFENCE_BREACH_EXIT_BIT;
+ options.responsiveness = notification_responsiveness_ms;
+
+ GeofenceInfo data;
+ data.size = sizeof(GeofenceInfo);
+ data.latitude = latitude;
+ data.longitude = longitude;
+ data.radius = radius_meters;
+
+ LocationError err = (LocationError)locAPIAddGeofences(1, &geofence_id, &options, &data);
+ if (LOCATION_ERROR_SUCCESS != err) {
+ onAddGeofencesCb(1, &err, &geofence_id);
+ }
+}
+
+void GeofenceAPIClient::geofencePause(uint32_t geofence_id)
+{
+ LOC_LOGD("%s]: (%d)", __FUNCTION__, geofence_id);
+ locAPIPauseGeofences(1, &geofence_id);
+}
+
+void GeofenceAPIClient::geofenceResume(uint32_t geofence_id, int32_t monitor_transitions)
+{
+ LOC_LOGD("%s]: (%d %d)", __FUNCTION__, geofence_id, monitor_transitions);
+ GeofenceBreachTypeMask mask = 0;
+ if (monitor_transitions & IGnssGeofenceCallback::GeofenceTransition::ENTERED)
+ mask |= GEOFENCE_BREACH_ENTER_BIT;
+ if (monitor_transitions & IGnssGeofenceCallback::GeofenceTransition::EXITED)
+ mask |= GEOFENCE_BREACH_EXIT_BIT;
+ locAPIResumeGeofences(1, &geofence_id, &mask);
+}
+
+void GeofenceAPIClient::geofenceRemove(uint32_t geofence_id)
+{
+ LOC_LOGD("%s]: (%d)", __FUNCTION__, geofence_id);
+ locAPIRemoveGeofences(1, &geofence_id);
+}
+
+void GeofenceAPIClient::geofenceRemoveAll()
+{
+ LOC_LOGD("%s]", __FUNCTION__);
+ // TODO locAPIRemoveAllGeofences();
+}
+
+// callbacks
+void GeofenceAPIClient::onGeofenceBreachCb(GeofenceBreachNotification geofenceBreachNotification)
+{
+ LOC_LOGD("%s]: (%d)", __FUNCTION__, geofenceBreachNotification.count);
+ if (mGnssGeofencingCbIface != nullptr) {
+ for (size_t i = 0; i < geofenceBreachNotification.count; i++) {
+ GnssLocation gnssLocation;
+ convertGnssLocation(geofenceBreachNotification.location, gnssLocation);
+
+ IGnssGeofenceCallback::GeofenceTransition transition;
+ if (geofenceBreachNotification.type == GEOFENCE_BREACH_ENTER)
+ transition = IGnssGeofenceCallback::GeofenceTransition::ENTERED;
+ else if (geofenceBreachNotification.type == GEOFENCE_BREACH_EXIT)
+ transition = IGnssGeofenceCallback::GeofenceTransition::EXITED;
+ else {
+ // continue with other breach if transition is
+ // nether GPS_GEOFENCE_ENTERED nor GPS_GEOFENCE_EXITED
+ continue;
+ }
+
+ auto r = mGnssGeofencingCbIface->gnssGeofenceTransitionCb(
+ geofenceBreachNotification.ids[i], gnssLocation, transition,
+ static_cast<V1_0::GnssUtcTime>(geofenceBreachNotification.timestamp));
+ if (!r.isOk()) {
+ LOC_LOGE("%s] Error from gnssGeofenceTransitionCb description=%s",
+ __func__, r.description().c_str());
+ }
+ }
+ }
+}
+
+void GeofenceAPIClient::onGeofenceStatusCb(GeofenceStatusNotification geofenceStatusNotification)
+{
+ LOC_LOGD("%s]: (%d)", __FUNCTION__, geofenceStatusNotification.available);
+ if (mGnssGeofencingCbIface != nullptr) {
+ IGnssGeofenceCallback::GeofenceAvailability status =
+ IGnssGeofenceCallback::GeofenceAvailability::UNAVAILABLE;
+ if (geofenceStatusNotification.available == GEOFENCE_STATUS_AVAILABILE_YES) {
+ status = IGnssGeofenceCallback::GeofenceAvailability::AVAILABLE;
+ }
+ GnssLocation gnssLocation;
+ memset(&gnssLocation, 0, sizeof(GnssLocation));
+ auto r = mGnssGeofencingCbIface->gnssGeofenceStatusCb(status, gnssLocation);
+ if (!r.isOk()) {
+ LOC_LOGE("%s] Error from gnssGeofenceStatusCb description=%s",
+ __func__, r.description().c_str());
+ }
+ }
+}
+
+void GeofenceAPIClient::onAddGeofencesCb(size_t count, LocationError* errors, uint32_t* ids)
+{
+ LOC_LOGD("%s]: (%zu)", __FUNCTION__, count);
+ if (mGnssGeofencingCbIface != nullptr) {
+ for (size_t i = 0; i < count; i++) {
+ IGnssGeofenceCallback::GeofenceStatus status =
+ IGnssGeofenceCallback::GeofenceStatus::ERROR_GENERIC;
+ if (errors[i] == LOCATION_ERROR_SUCCESS)
+ status = IGnssGeofenceCallback::GeofenceStatus::OPERATION_SUCCESS;
+ else if (errors[i] == LOCATION_ERROR_ID_EXISTS)
+ status = IGnssGeofenceCallback::GeofenceStatus::ERROR_ID_EXISTS;
+ auto r = mGnssGeofencingCbIface->gnssGeofenceAddCb(ids[i], status);
+ if (!r.isOk()) {
+ LOC_LOGE("%s] Error from gnssGeofenceAddCb description=%s",
+ __func__, r.description().c_str());
+ }
+ }
+ }
+}
+
+void GeofenceAPIClient::onRemoveGeofencesCb(size_t count, LocationError* errors, uint32_t* ids)
+{
+ LOC_LOGD("%s]: (%zu)", __FUNCTION__, count);
+ if (mGnssGeofencingCbIface != nullptr) {
+ for (size_t i = 0; i < count; i++) {
+ IGnssGeofenceCallback::GeofenceStatus status =
+ IGnssGeofenceCallback::GeofenceStatus::ERROR_GENERIC;
+ if (errors[i] == LOCATION_ERROR_SUCCESS)
+ status = IGnssGeofenceCallback::GeofenceStatus::OPERATION_SUCCESS;
+ else if (errors[i] == LOCATION_ERROR_ID_UNKNOWN)
+ status = IGnssGeofenceCallback::GeofenceStatus::ERROR_ID_UNKNOWN;
+ auto r = mGnssGeofencingCbIface->gnssGeofenceRemoveCb(ids[i], status);
+ if (!r.isOk()) {
+ LOC_LOGE("%s] Error from gnssGeofenceRemoveCb description=%s",
+ __func__, r.description().c_str());
+ }
+ }
+ }
+}
+
+void GeofenceAPIClient::onPauseGeofencesCb(size_t count, LocationError* errors, uint32_t* ids)
+{
+ LOC_LOGD("%s]: (%zu)", __FUNCTION__, count);
+ if (mGnssGeofencingCbIface != nullptr) {
+ for (size_t i = 0; i < count; i++) {
+ IGnssGeofenceCallback::GeofenceStatus status =
+ IGnssGeofenceCallback::GeofenceStatus::ERROR_GENERIC;
+ if (errors[i] == LOCATION_ERROR_SUCCESS)
+ status = IGnssGeofenceCallback::GeofenceStatus::OPERATION_SUCCESS;
+ else if (errors[i] == LOCATION_ERROR_ID_UNKNOWN)
+ status = IGnssGeofenceCallback::GeofenceStatus::ERROR_ID_UNKNOWN;
+ auto r = mGnssGeofencingCbIface->gnssGeofencePauseCb(ids[i], status);
+ if (!r.isOk()) {
+ LOC_LOGE("%s] Error from gnssGeofencePauseCb description=%s",
+ __func__, r.description().c_str());
+ }
+ }
+ }
+}
+
+void GeofenceAPIClient::onResumeGeofencesCb(size_t count, LocationError* errors, uint32_t* ids)
+{
+ LOC_LOGD("%s]: (%zu)", __FUNCTION__, count);
+ if (mGnssGeofencingCbIface != nullptr) {
+ for (size_t i = 0; i < count; i++) {
+ IGnssGeofenceCallback::GeofenceStatus status =
+ IGnssGeofenceCallback::GeofenceStatus::ERROR_GENERIC;
+ if (errors[i] == LOCATION_ERROR_SUCCESS)
+ status = IGnssGeofenceCallback::GeofenceStatus::OPERATION_SUCCESS;
+ else if (errors[i] == LOCATION_ERROR_ID_UNKNOWN)
+ status = IGnssGeofenceCallback::GeofenceStatus::ERROR_ID_UNKNOWN;
+ auto r = mGnssGeofencingCbIface->gnssGeofenceResumeCb(ids[i], status);
+ if (!r.isOk()) {
+ LOC_LOGE("%s] Error from gnssGeofenceResumeCb description=%s",
+ __func__, r.description().c_str());
+ }
+ }
+ }
+}
+
+} // namespace implementation
+} // namespace V2_0
+} // namespace gnss
+} // namespace hardware
+} // namespace android
diff --git a/android/2.0/location_api/GeofenceAPIClient.h b/android/2.0/location_api/GeofenceAPIClient.h
new file mode 100644
index 0000000..71049de
--- /dev/null
+++ b/android/2.0/location_api/GeofenceAPIClient.h
@@ -0,0 +1,76 @@
+/* Copyright (c) 2017-2019, 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 GEOFENCE_API_CLINET_H
+#define GEOFENCE_API_CLINET_H
+
+
+#include <android/hardware/gnss/1.0/IGnssGeofenceCallback.h>
+#include <LocationAPIClientBase.h>
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace V2_0 {
+namespace implementation {
+
+using ::android::sp;
+
+class GeofenceAPIClient : public LocationAPIClientBase
+{
+public:
+ GeofenceAPIClient(const sp<V1_0::IGnssGeofenceCallback>& callback);
+ virtual ~GeofenceAPIClient() = default;
+
+ void geofenceAdd(uint32_t geofence_id, double latitude, double longitude,
+ double radius_meters, int32_t last_transition, int32_t monitor_transitions,
+ uint32_t notification_responsiveness_ms, uint32_t unknown_timer_ms);
+ void geofencePause(uint32_t geofence_id);
+ void geofenceResume(uint32_t geofence_id, int32_t monitor_transitions);
+ void geofenceRemove(uint32_t geofence_id);
+ void geofenceRemoveAll();
+
+ // callbacks
+ void onGeofenceBreachCb(GeofenceBreachNotification geofenceBreachNotification) final;
+ void onGeofenceStatusCb(GeofenceStatusNotification geofenceStatusNotification) final;
+ void onAddGeofencesCb(size_t count, LocationError* errors, uint32_t* ids) final;
+ void onRemoveGeofencesCb(size_t count, LocationError* errors, uint32_t* ids) final;
+ void onPauseGeofencesCb(size_t count, LocationError* errors, uint32_t* ids) final;
+ void onResumeGeofencesCb(size_t count, LocationError* errors, uint32_t* ids) final;
+
+private:
+ sp<V1_0::IGnssGeofenceCallback> mGnssGeofencingCbIface;
+};
+
+} // namespace implementation
+} // namespace V2_0
+} // namespace gnss
+} // namespace hardware
+} // namespace android
+#endif // GEOFENCE_API_CLINET_H
diff --git a/android/2.0/location_api/GnssAPIClient.cpp b/android/2.0/location_api/GnssAPIClient.cpp
new file mode 100644
index 0000000..ffe9075
--- /dev/null
+++ b/android/2.0/location_api/GnssAPIClient.cpp
@@ -0,0 +1,726 @@
+/* Copyright (c) 2017-2019, 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_NDEBUG 0
+#define LOG_TAG "LocSvc_GnssAPIClient"
+#define SINGLE_SHOT_MIN_TRACKING_INTERVAL_MSEC (590 * 60 * 60 * 1000) // 590 hours
+
+#include <log_util.h>
+#include <loc_cfg.h>
+
+#include "LocationUtil.h"
+#include "GnssAPIClient.h"
+#include <LocContext.h>
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace V2_0 {
+namespace implementation {
+
+using ::android::hardware::gnss::V2_0::IGnss;
+using ::android::hardware::gnss::V2_0::IGnssCallback;
+using ::android::hardware::gnss::V1_0::IGnssNiCallback;
+using ::android::hardware::gnss::V2_0::GnssLocation;
+
+static void convertGnssSvStatus(GnssSvNotification& in, V1_0::IGnssCallback::GnssSvStatus& out);
+static void convertGnssSvStatus(GnssSvNotification& in,
+ hidl_vec<V2_0::IGnssCallback::GnssSvInfo>& out);
+
+GnssAPIClient::GnssAPIClient(const sp<V1_0::IGnssCallback>& gpsCb,
+ const sp<V1_0::IGnssNiCallback>& niCb) :
+ LocationAPIClientBase(),
+ mGnssCbIface(nullptr),
+ mGnssNiCbIface(nullptr),
+ mControlClient(new LocationAPIControlClient()),
+ mLocationCapabilitiesMask(0),
+ mLocationCapabilitiesCached(false),
+ mTracking(false),
+ mGnssCbIface_2_0(nullptr)
+{
+ LOC_LOGD("%s]: (%p %p)", __FUNCTION__, &gpsCb, &niCb);
+
+ initLocationOptions();
+ gnssUpdateCallbacks(gpsCb, niCb);
+}
+
+GnssAPIClient::GnssAPIClient(const sp<V2_0::IGnssCallback>& gpsCb) :
+ LocationAPIClientBase(),
+ mGnssCbIface(nullptr),
+ mGnssNiCbIface(nullptr),
+ mControlClient(new LocationAPIControlClient()),
+ mLocationCapabilitiesMask(0),
+ mLocationCapabilitiesCached(false),
+ mTracking(false),
+ mGnssCbIface_2_0(nullptr)
+{
+ LOC_LOGD("%s]: (%p)", __FUNCTION__, &gpsCb);
+
+ initLocationOptions();
+ gnssUpdateCallbacks_2_0(gpsCb);
+}
+
+GnssAPIClient::~GnssAPIClient()
+{
+ LOC_LOGD("%s]: ()", __FUNCTION__);
+ if (mControlClient) {
+ delete mControlClient;
+ mControlClient = nullptr;
+ }
+}
+
+void GnssAPIClient::initLocationOptions()
+{
+ // set default LocationOptions.
+ memset(&mTrackingOptions, 0, sizeof(TrackingOptions));
+ mTrackingOptions.size = sizeof(TrackingOptions);
+ mTrackingOptions.minInterval = 1000;
+ mTrackingOptions.minDistance = 0;
+ mTrackingOptions.mode = GNSS_SUPL_MODE_STANDALONE;
+}
+
+void GnssAPIClient::setCallbacks()
+{
+ LocationCallbacks locationCallbacks;
+ memset(&locationCallbacks, 0, sizeof(LocationCallbacks));
+ locationCallbacks.size = sizeof(LocationCallbacks);
+
+ locationCallbacks.trackingCb = nullptr;
+ locationCallbacks.trackingCb = [this](Location location) {
+ onTrackingCb(location);
+ };
+
+ locationCallbacks.batchingCb = nullptr;
+ locationCallbacks.geofenceBreachCb = nullptr;
+ locationCallbacks.geofenceStatusCb = nullptr;
+ locationCallbacks.gnssLocationInfoCb = nullptr;
+ locationCallbacks.gnssNiCb = nullptr;
+ if (mGnssNiCbIface != nullptr) {
+ loc_core::ContextBase* context =
+ loc_core::LocContext::getLocContext(
+ NULL, NULL,
+ loc_core::LocContext::mLocationHalName, false);
+ if (!context->hasAgpsExtendedCapabilities()) {
+ LOC_LOGD("Registering NI CB");
+ locationCallbacks.gnssNiCb = [this](uint32_t id, GnssNiNotification gnssNiNotify) {
+ onGnssNiCb(id, gnssNiNotify);
+ };
+ }
+ }
+
+ locationCallbacks.gnssSvCb = nullptr;
+ locationCallbacks.gnssSvCb = [this](GnssSvNotification gnssSvNotification) {
+ onGnssSvCb(gnssSvNotification);
+ };
+
+ locationCallbacks.gnssNmeaCb = nullptr;
+ locationCallbacks.gnssNmeaCb = [this](GnssNmeaNotification gnssNmeaNotification) {
+ onGnssNmeaCb(gnssNmeaNotification);
+ };
+
+ locationCallbacks.gnssMeasurementsCb = nullptr;
+
+ locAPISetCallbacks(locationCallbacks);
+}
+
+// for GpsInterface
+void GnssAPIClient::gnssUpdateCallbacks(const sp<V1_0::IGnssCallback>& gpsCb,
+ const sp<IGnssNiCallback>& niCb)
+{
+ LOC_LOGD("%s]: (%p %p)", __FUNCTION__, &gpsCb, &niCb);
+
+ mMutex.lock();
+ mGnssCbIface = gpsCb;
+ mGnssNiCbIface = niCb;
+ mMutex.unlock();
+
+ if (mGnssCbIface != nullptr || mGnssNiCbIface != nullptr) {
+ setCallbacks();
+ }
+}
+
+void GnssAPIClient::gnssUpdateCallbacks_2_0(const sp<V2_0::IGnssCallback>& gpsCb)
+{
+ LOC_LOGD("%s]: (%p)", __FUNCTION__, &gpsCb);
+
+ mMutex.lock();
+ mGnssCbIface_2_0 = gpsCb;
+ mMutex.unlock();
+
+ if (mGnssCbIface_2_0 != nullptr) {
+ setCallbacks();
+ }
+}
+
+bool GnssAPIClient::gnssStart()
+{
+ LOC_LOGD("%s]: ()", __FUNCTION__);
+
+ mMutex.lock();
+ mTracking = true;
+ mMutex.unlock();
+
+ bool retVal = true;
+ locAPIStartTracking(mTrackingOptions);
+ return retVal;
+}
+
+bool GnssAPIClient::gnssStop()
+{
+ LOC_LOGD("%s]: ()", __FUNCTION__);
+
+ mMutex.lock();
+ mTracking = false;
+ mMutex.unlock();
+
+ bool retVal = true;
+ locAPIStopTracking();
+ return retVal;
+}
+
+bool GnssAPIClient::gnssSetPositionMode(IGnss::GnssPositionMode mode,
+ IGnss::GnssPositionRecurrence recurrence, uint32_t minIntervalMs,
+ uint32_t preferredAccuracyMeters, uint32_t preferredTimeMs,
+ GnssPowerMode powerMode, uint32_t timeBetweenMeasurement)
+{
+ LOC_LOGD("%s]: (%d %d %d %d %d %d %d)", __FUNCTION__,
+ (int)mode, recurrence, minIntervalMs, preferredAccuracyMeters,
+ preferredTimeMs, (int)powerMode, timeBetweenMeasurement);
+ bool retVal = true;
+ memset(&mTrackingOptions, 0, sizeof(TrackingOptions));
+ mTrackingOptions.size = sizeof(TrackingOptions);
+ mTrackingOptions.minInterval = minIntervalMs;
+ if (IGnss::GnssPositionMode::MS_ASSISTED == mode ||
+ IGnss::GnssPositionRecurrence::RECURRENCE_SINGLE == recurrence) {
+ // We set a very large interval to simulate SINGLE mode. Once we report a fix,
+ // the caller should take the responsibility to stop the session.
+ // For MSA, we always treat it as SINGLE mode.
+ mTrackingOptions.minInterval = SINGLE_SHOT_MIN_TRACKING_INTERVAL_MSEC;
+ }
+ mTrackingOptions.minDistance = preferredAccuracyMeters;
+ if (mode == IGnss::GnssPositionMode::STANDALONE)
+ mTrackingOptions.mode = GNSS_SUPL_MODE_STANDALONE;
+ else if (mode == IGnss::GnssPositionMode::MS_BASED)
+ mTrackingOptions.mode = GNSS_SUPL_MODE_MSB;
+ else if (mode == IGnss::GnssPositionMode::MS_ASSISTED)
+ mTrackingOptions.mode = GNSS_SUPL_MODE_MSA;
+ else {
+ LOC_LOGD("%s]: invalid GnssPositionMode: %d", __FUNCTION__, (int)mode);
+ retVal = false;
+ }
+ if (GNSS_POWER_MODE_INVALID != powerMode) {
+ mTrackingOptions.powerMode = powerMode;
+ mTrackingOptions.tbm = timeBetweenMeasurement;
+ }
+ locAPIUpdateTrackingOptions(mTrackingOptions);
+ return retVal;
+}
+
+// for GpsNiInterface
+void GnssAPIClient::gnssNiRespond(int32_t notifId,
+ IGnssNiCallback::GnssUserResponseType userResponse)
+{
+ LOC_LOGD("%s]: (%d %d)", __FUNCTION__, notifId, static_cast<int>(userResponse));
+ GnssNiResponse data;
+ switch (userResponse) {
+ case IGnssNiCallback::GnssUserResponseType::RESPONSE_ACCEPT:
+ data = GNSS_NI_RESPONSE_ACCEPT;
+ break;
+ case IGnssNiCallback::GnssUserResponseType::RESPONSE_DENY:
+ data = GNSS_NI_RESPONSE_DENY;
+ break;
+ case IGnssNiCallback::GnssUserResponseType::RESPONSE_NORESP:
+ data = GNSS_NI_RESPONSE_NO_RESPONSE;
+ break;
+ default:
+ data = GNSS_NI_RESPONSE_IGNORE;
+ break;
+ }
+
+ locAPIGnssNiResponse(notifId, data);
+}
+
+// these apis using LocationAPIControlClient
+void GnssAPIClient::gnssDeleteAidingData(IGnss::GnssAidingData aidingDataFlags)
+{
+ LOC_LOGD("%s]: (%02hx)", __FUNCTION__, aidingDataFlags);
+ if (mControlClient == nullptr) {
+ return;
+ }
+ GnssAidingData data;
+ memset(&data, 0, sizeof (GnssAidingData));
+ data.sv.svTypeMask = GNSS_AIDING_DATA_SV_TYPE_GPS_BIT |
+ GNSS_AIDING_DATA_SV_TYPE_GLONASS_BIT |
+ GNSS_AIDING_DATA_SV_TYPE_QZSS_BIT |
+ GNSS_AIDING_DATA_SV_TYPE_BEIDOU_BIT |
+ GNSS_AIDING_DATA_SV_TYPE_GALILEO_BIT;
+
+ if (aidingDataFlags == IGnss::GnssAidingData::DELETE_ALL)
+ data.deleteAll = true;
+ else {
+ if (aidingDataFlags & IGnss::GnssAidingData::DELETE_EPHEMERIS)
+ data.sv.svMask |= GNSS_AIDING_DATA_SV_EPHEMERIS_BIT;
+ if (aidingDataFlags & IGnss::GnssAidingData::DELETE_ALMANAC)
+ data.sv.svMask |= GNSS_AIDING_DATA_SV_ALMANAC_BIT;
+ if (aidingDataFlags & IGnss::GnssAidingData::DELETE_POSITION)
+ data.common.mask |= GNSS_AIDING_DATA_COMMON_POSITION_BIT;
+ if (aidingDataFlags & IGnss::GnssAidingData::DELETE_TIME)
+ data.common.mask |= GNSS_AIDING_DATA_COMMON_TIME_BIT;
+ if (aidingDataFlags & IGnss::GnssAidingData::DELETE_IONO)
+ data.sv.svMask |= GNSS_AIDING_DATA_SV_IONOSPHERE_BIT;
+ if (aidingDataFlags & IGnss::GnssAidingData::DELETE_UTC)
+ data.common.mask |= GNSS_AIDING_DATA_COMMON_UTC_BIT;
+ if (aidingDataFlags & IGnss::GnssAidingData::DELETE_HEALTH)
+ data.sv.svMask |= GNSS_AIDING_DATA_SV_HEALTH_BIT;
+ if (aidingDataFlags & IGnss::GnssAidingData::DELETE_SVDIR)
+ data.sv.svMask |= GNSS_AIDING_DATA_SV_DIRECTION_BIT;
+ if (aidingDataFlags & IGnss::GnssAidingData::DELETE_SVSTEER)
+ data.sv.svMask |= GNSS_AIDING_DATA_SV_STEER_BIT;
+ if (aidingDataFlags & IGnss::GnssAidingData::DELETE_SADATA)
+ data.sv.svMask |= GNSS_AIDING_DATA_SV_SA_DATA_BIT;
+ if (aidingDataFlags & IGnss::GnssAidingData::DELETE_RTI)
+ data.common.mask |= GNSS_AIDING_DATA_COMMON_RTI_BIT;
+ if (aidingDataFlags & IGnss::GnssAidingData::DELETE_CELLDB_INFO)
+ data.common.mask |= GNSS_AIDING_DATA_COMMON_CELLDB_BIT;
+ }
+ mControlClient->locAPIGnssDeleteAidingData(data);
+}
+
+void GnssAPIClient::gnssEnable(LocationTechnologyType techType)
+{
+ LOC_LOGD("%s]: (%0d)", __FUNCTION__, techType);
+ if (mControlClient == nullptr) {
+ return;
+ }
+ mControlClient->locAPIEnable(techType);
+}
+
+void GnssAPIClient::gnssDisable()
+{
+ LOC_LOGD("%s]: ()", __FUNCTION__);
+ if (mControlClient == nullptr) {
+ return;
+ }
+ mControlClient->locAPIDisable();
+}
+
+void GnssAPIClient::gnssConfigurationUpdate(const GnssConfig& gnssConfig)
+{
+ LOC_LOGD("%s]: (%02x)", __FUNCTION__, gnssConfig.flags);
+ if (mControlClient == nullptr) {
+ return;
+ }
+ mControlClient->locAPIGnssUpdateConfig(gnssConfig);
+}
+
+void GnssAPIClient::requestCapabilities() {
+ // only send capablities if it's already cached, otherwise the first time LocationAPI
+ // is initialized, capabilities will be sent by LocationAPI
+ if (mLocationCapabilitiesCached) {
+ onCapabilitiesCb(mLocationCapabilitiesMask);
+ }
+}
+
+// callbacks
+void GnssAPIClient::onCapabilitiesCb(LocationCapabilitiesMask capabilitiesMask)
+{
+ LOC_LOGD("%s]: (%02x)", __FUNCTION__, capabilitiesMask);
+ mLocationCapabilitiesMask = capabilitiesMask;
+ mLocationCapabilitiesCached = true;
+
+ mMutex.lock();
+ auto gnssCbIface(mGnssCbIface);
+ auto gnssCbIface_2_0(mGnssCbIface_2_0);
+ mMutex.unlock();
+
+ if (gnssCbIface_2_0 != nullptr || gnssCbIface != nullptr) {
+ uint32_t data = 0;
+ if ((capabilitiesMask & LOCATION_CAPABILITIES_TIME_BASED_TRACKING_BIT) ||
+ (capabilitiesMask & LOCATION_CAPABILITIES_TIME_BASED_BATCHING_BIT) ||
+ (capabilitiesMask & LOCATION_CAPABILITIES_DISTANCE_BASED_TRACKING_BIT) ||
+ (capabilitiesMask & LOCATION_CAPABILITIES_DISTANCE_BASED_BATCHING_BIT))
+ data |= IGnssCallback::Capabilities::SCHEDULING;
+ if (capabilitiesMask & LOCATION_CAPABILITIES_GEOFENCE_BIT)
+ data |= V1_0::IGnssCallback::Capabilities::GEOFENCING;
+ if (capabilitiesMask & LOCATION_CAPABILITIES_GNSS_MEASUREMENTS_BIT)
+ data |= V1_0::IGnssCallback::Capabilities::MEASUREMENTS;
+ if (capabilitiesMask & LOCATION_CAPABILITIES_GNSS_MSB_BIT)
+ data |= IGnssCallback::Capabilities::MSB;
+ if (capabilitiesMask & LOCATION_CAPABILITIES_GNSS_MSA_BIT)
+ data |= IGnssCallback::Capabilities::MSA;
+ if (capabilitiesMask & LOCATION_CAPABILITIES_AGPM_BIT)
+ data |= IGnssCallback::Capabilities::LOW_POWER_MODE;
+ if (capabilitiesMask & LOCATION_CAPABILITIES_CONSTELLATION_ENABLEMENT_BIT)
+ data |= IGnssCallback::Capabilities::SATELLITE_BLACKLIST;
+
+ IGnssCallback::GnssSystemInfo gnssInfo;
+ if (capabilitiesMask & LOCATION_CAPABILITIES_PRIVACY_BIT) {
+ gnssInfo.yearOfHw = 2019;
+ } else if (capabilitiesMask & LOCATION_CAPABILITIES_CONSTELLATION_ENABLEMENT_BIT ||
+ capabilitiesMask & LOCATION_CAPABILITIES_AGPM_BIT) {
+ gnssInfo.yearOfHw = 2018;
+ } else if (capabilitiesMask & LOCATION_CAPABILITIES_DEBUG_NMEA_BIT) {
+ gnssInfo.yearOfHw = 2017;
+ } else if (capabilitiesMask & LOCATION_CAPABILITIES_GNSS_MEASUREMENTS_BIT) {
+ gnssInfo.yearOfHw = 2016;
+ } else {
+ gnssInfo.yearOfHw = 2015;
+ }
+ LOC_LOGV("%s:%d] set_system_info_cb (%d)", __FUNCTION__, __LINE__, gnssInfo.yearOfHw);
+
+ if (gnssCbIface_2_0 != nullptr) {
+ auto r = gnssCbIface_2_0->gnssSetCapabilitiesCb_2_0(data);
+ if (!r.isOk()) {
+ LOC_LOGE("%s] Error from gnssSetCapabilitiesCb_2_0 description=%s",
+ __func__, r.description().c_str());
+ }
+ r = gnssCbIface_2_0->gnssSetSystemInfoCb(gnssInfo);
+ if (!r.isOk()) {
+ LOC_LOGE("%s] Error from gnssSetSystemInfoCb description=%s",
+ __func__, r.description().c_str());
+ }
+ } else if (gnssCbIface != nullptr) {
+ auto r = gnssCbIface->gnssSetCapabilitesCb(data);
+ if (!r.isOk()) {
+ LOC_LOGE("%s] Error from gnssSetCapabilitesCb description=%s",
+ __func__, r.description().c_str());
+ }
+ r = gnssCbIface->gnssSetSystemInfoCb(gnssInfo);
+ if (!r.isOk()) {
+ LOC_LOGE("%s] Error from gnssSetSystemInfoCb description=%s",
+ __func__, r.description().c_str());
+ }
+ }
+
+ }
+
+}
+
+void GnssAPIClient::onTrackingCb(Location location)
+{
+ mMutex.lock();
+ auto gnssCbIface(mGnssCbIface);
+ auto gnssCbIface_2_0(mGnssCbIface_2_0);
+ bool isTracking = mTracking;
+ mMutex.unlock();
+
+ LOC_LOGD("%s]: (flags: %02x isTracking: %d)", __FUNCTION__, location.flags, isTracking);
+
+ if (!isTracking) {
+ return;
+ }
+
+ if (gnssCbIface_2_0 != nullptr) {
+ V2_0::GnssLocation gnssLocation;
+ convertGnssLocation(location, gnssLocation);
+ auto r = gnssCbIface_2_0->gnssLocationCb_2_0(gnssLocation);
+ if (!r.isOk()) {
+ LOC_LOGE("%s] Error from gnssLocationCb_2_0 description=%s",
+ __func__, r.description().c_str());
+ }
+ } else if (gnssCbIface != nullptr) {
+ V1_0::GnssLocation gnssLocation;
+ convertGnssLocation(location, gnssLocation);
+ auto r = gnssCbIface->gnssLocationCb(gnssLocation);
+ if (!r.isOk()) {
+ LOC_LOGE("%s] Error from gnssLocationCb description=%s",
+ __func__, r.description().c_str());
+ }
+ } else {
+ LOC_LOGW("%s] No GNSS Interface ready for gnssLocationCb ", __FUNCTION__);
+ }
+
+}
+
+void GnssAPIClient::onGnssNiCb(uint32_t id, GnssNiNotification gnssNiNotification)
+{
+ LOC_LOGD("%s]: (id: %d)", __FUNCTION__, id);
+ mMutex.lock();
+ auto gnssNiCbIface(mGnssNiCbIface);
+ mMutex.unlock();
+
+ if (gnssNiCbIface == nullptr) {
+ LOC_LOGE("%s]: mGnssNiCbIface is nullptr", __FUNCTION__);
+ return;
+ }
+
+ IGnssNiCallback::GnssNiNotification notificationGnss = {};
+
+ notificationGnss.notificationId = id;
+
+ if (gnssNiNotification.type == GNSS_NI_TYPE_VOICE)
+ notificationGnss.niType = IGnssNiCallback::GnssNiType::VOICE;
+ else if (gnssNiNotification.type == GNSS_NI_TYPE_SUPL)
+ notificationGnss.niType = IGnssNiCallback::GnssNiType::UMTS_SUPL;
+ else if (gnssNiNotification.type == GNSS_NI_TYPE_CONTROL_PLANE)
+ notificationGnss.niType = IGnssNiCallback::GnssNiType::UMTS_CTRL_PLANE;
+ else if (gnssNiNotification.type == GNSS_NI_TYPE_EMERGENCY_SUPL)
+ notificationGnss.niType = IGnssNiCallback::GnssNiType::EMERGENCY_SUPL;
+
+ if (gnssNiNotification.options & GNSS_NI_OPTIONS_NOTIFICATION_BIT)
+ notificationGnss.notifyFlags |= IGnssNiCallback::GnssNiNotifyFlags::NEED_NOTIFY;
+ if (gnssNiNotification.options & GNSS_NI_OPTIONS_VERIFICATION_BIT)
+ notificationGnss.notifyFlags |= IGnssNiCallback::GnssNiNotifyFlags::NEED_VERIFY;
+ if (gnssNiNotification.options & GNSS_NI_OPTIONS_PRIVACY_OVERRIDE_BIT)
+ notificationGnss.notifyFlags |= IGnssNiCallback::GnssNiNotifyFlags::PRIVACY_OVERRIDE;
+
+ notificationGnss.timeoutSec = gnssNiNotification.timeout;
+
+ if (gnssNiNotification.timeoutResponse == GNSS_NI_RESPONSE_ACCEPT)
+ notificationGnss.defaultResponse = IGnssNiCallback::GnssUserResponseType::RESPONSE_ACCEPT;
+ else if (gnssNiNotification.timeoutResponse == GNSS_NI_RESPONSE_DENY)
+ notificationGnss.defaultResponse = IGnssNiCallback::GnssUserResponseType::RESPONSE_DENY;
+ else if (gnssNiNotification.timeoutResponse == GNSS_NI_RESPONSE_NO_RESPONSE ||
+ gnssNiNotification.timeoutResponse == GNSS_NI_RESPONSE_IGNORE)
+ notificationGnss.defaultResponse = IGnssNiCallback::GnssUserResponseType::RESPONSE_NORESP;
+
+ notificationGnss.requestorId = gnssNiNotification.requestor;
+
+ notificationGnss.notificationMessage = gnssNiNotification.message;
+
+ if (gnssNiNotification.requestorEncoding == GNSS_NI_ENCODING_TYPE_NONE)
+ notificationGnss.requestorIdEncoding =
+ IGnssNiCallback::GnssNiEncodingType::ENC_NONE;
+ else if (gnssNiNotification.requestorEncoding == GNSS_NI_ENCODING_TYPE_GSM_DEFAULT)
+ notificationGnss.requestorIdEncoding =
+ IGnssNiCallback::GnssNiEncodingType::ENC_SUPL_GSM_DEFAULT;
+ else if (gnssNiNotification.requestorEncoding == GNSS_NI_ENCODING_TYPE_UTF8)
+ notificationGnss.requestorIdEncoding =
+ IGnssNiCallback::GnssNiEncodingType::ENC_SUPL_UTF8;
+ else if (gnssNiNotification.requestorEncoding == GNSS_NI_ENCODING_TYPE_UCS2)
+ notificationGnss.requestorIdEncoding =
+ IGnssNiCallback::GnssNiEncodingType::ENC_SUPL_UCS2;
+
+ if (gnssNiNotification.messageEncoding == GNSS_NI_ENCODING_TYPE_NONE)
+ notificationGnss.notificationIdEncoding =
+ IGnssNiCallback::GnssNiEncodingType::ENC_NONE;
+ else if (gnssNiNotification.messageEncoding == GNSS_NI_ENCODING_TYPE_GSM_DEFAULT)
+ notificationGnss.notificationIdEncoding =
+ IGnssNiCallback::GnssNiEncodingType::ENC_SUPL_GSM_DEFAULT;
+ else if (gnssNiNotification.messageEncoding == GNSS_NI_ENCODING_TYPE_UTF8)
+ notificationGnss.notificationIdEncoding =
+ IGnssNiCallback::GnssNiEncodingType::ENC_SUPL_UTF8;
+ else if (gnssNiNotification.messageEncoding == GNSS_NI_ENCODING_TYPE_UCS2)
+ notificationGnss.notificationIdEncoding =
+ IGnssNiCallback::GnssNiEncodingType::ENC_SUPL_UCS2;
+
+ gnssNiCbIface->niNotifyCb(notificationGnss);
+}
+
+void GnssAPIClient::onGnssSvCb(GnssSvNotification gnssSvNotification)
+{
+ LOC_LOGD("%s]: (count: %u)", __FUNCTION__, gnssSvNotification.count);
+ mMutex.lock();
+ auto gnssCbIface(mGnssCbIface);
+ auto gnssCbIface_2_0(mGnssCbIface_2_0);
+ mMutex.unlock();
+
+ if (gnssCbIface_2_0 != nullptr) {
+ hidl_vec<V2_0::IGnssCallback::GnssSvInfo> svInfoList;
+ convertGnssSvStatus(gnssSvNotification, svInfoList);
+ auto r = gnssCbIface_2_0->gnssSvStatusCb_2_0(svInfoList);
+ if (!r.isOk()) {
+ LOC_LOGE("%s] Error from gnssSvStatusCb_2_0 description=%s",
+ __func__, r.description().c_str());
+ }
+ } else if (gnssCbIface != nullptr) {
+ V1_0::IGnssCallback::GnssSvStatus svStatus;
+ convertGnssSvStatus(gnssSvNotification, svStatus);
+ auto r = gnssCbIface->gnssSvStatusCb(svStatus);
+ if (!r.isOk()) {
+ LOC_LOGE("%s] Error from gnssSvStatusCb description=%s",
+ __func__, r.description().c_str());
+ }
+ }
+}
+
+void GnssAPIClient::onGnssNmeaCb(GnssNmeaNotification gnssNmeaNotification)
+{
+ mMutex.lock();
+ auto gnssCbIface(mGnssCbIface);
+ auto gnssCbIface_2_0(mGnssCbIface_2_0);
+ mMutex.unlock();
+
+ if (gnssCbIface != nullptr || gnssCbIface_2_0 != nullptr) {
+ const std::string s(gnssNmeaNotification.nmea);
+ std::stringstream ss(s);
+ std::string each;
+ while(std::getline(ss, each, '\n')) {
+ each += '\n';
+ android::hardware::hidl_string nmeaString;
+ nmeaString.setToExternal(each.c_str(), each.length());
+ if (gnssCbIface_2_0 != nullptr) {
+ auto r = gnssCbIface_2_0->gnssNmeaCb(
+ static_cast<V1_0::GnssUtcTime>(gnssNmeaNotification.timestamp), nmeaString);
+ if (!r.isOk()) {
+ LOC_LOGE("%s] Error from gnssCbIface_2_0 nmea=%s length=%u description=%s",
+ __func__, gnssNmeaNotification.nmea, gnssNmeaNotification.length,
+ r.description().c_str());
+ }
+ } else if (gnssCbIface != nullptr) {
+ auto r = gnssCbIface->gnssNmeaCb(
+ static_cast<V1_0::GnssUtcTime>(gnssNmeaNotification.timestamp), nmeaString);
+ if (!r.isOk()) {
+ LOC_LOGE("%s] Error from gnssNmeaCb nmea=%s length=%u description=%s",
+ __func__, gnssNmeaNotification.nmea, gnssNmeaNotification.length,
+ r.description().c_str());
+ }
+ }
+ }
+ }
+}
+
+void GnssAPIClient::onStartTrackingCb(LocationError error)
+{
+ LOC_LOGD("%s]: (%d)", __FUNCTION__, error);
+ mMutex.lock();
+ auto gnssCbIface(mGnssCbIface);
+ auto gnssCbIface_2_0(mGnssCbIface_2_0);
+ mMutex.unlock();
+
+ if (error == LOCATION_ERROR_SUCCESS) {
+ if (gnssCbIface_2_0 != nullptr) {
+ auto r = gnssCbIface_2_0->gnssStatusCb(IGnssCallback::GnssStatusValue::ENGINE_ON);
+ if (!r.isOk()) {
+ LOC_LOGE("%s] Error from gnssStatusCb 2.0 ENGINE_ON description=%s",
+ __func__, r.description().c_str());
+ }
+ r = gnssCbIface_2_0->gnssStatusCb(IGnssCallback::GnssStatusValue::SESSION_BEGIN);
+ if (!r.isOk()) {
+ LOC_LOGE("%s] Error from gnssStatusCb 2.0 SESSION_BEGIN description=%s",
+ __func__, r.description().c_str());
+ }
+ } else if (gnssCbIface != nullptr) {
+ auto r = gnssCbIface->gnssStatusCb(IGnssCallback::GnssStatusValue::ENGINE_ON);
+ if (!r.isOk()) {
+ LOC_LOGE("%s] Error from gnssStatusCb ENGINE_ON description=%s",
+ __func__, r.description().c_str());
+ }
+ r = gnssCbIface->gnssStatusCb(IGnssCallback::GnssStatusValue::SESSION_BEGIN);
+ if (!r.isOk()) {
+ LOC_LOGE("%s] Error from gnssStatusCb SESSION_BEGIN description=%s",
+ __func__, r.description().c_str());
+ }
+ }
+ }
+}
+
+void GnssAPIClient::onStopTrackingCb(LocationError error)
+{
+ LOC_LOGD("%s]: (%d)", __FUNCTION__, error);
+ mMutex.lock();
+ auto gnssCbIface(mGnssCbIface);
+ auto gnssCbIface_2_0(mGnssCbIface_2_0);
+ mMutex.unlock();
+
+ if (error == LOCATION_ERROR_SUCCESS) {
+ if (gnssCbIface_2_0 != nullptr) {
+ auto r = gnssCbIface_2_0->gnssStatusCb(IGnssCallback::GnssStatusValue::SESSION_END);
+ if (!r.isOk()) {
+ LOC_LOGE("%s] Error from gnssStatusCb 2.0 SESSION_END description=%s",
+ __func__, r.description().c_str());
+ }
+ r = gnssCbIface_2_0->gnssStatusCb(IGnssCallback::GnssStatusValue::ENGINE_OFF);
+ if (!r.isOk()) {
+ LOC_LOGE("%s] Error from gnssStatusCb 2.0 ENGINE_OFF description=%s",
+ __func__, r.description().c_str());
+ }
+
+ } else if (gnssCbIface != nullptr) {
+ auto r = gnssCbIface->gnssStatusCb(IGnssCallback::GnssStatusValue::SESSION_END);
+ if (!r.isOk()) {
+ LOC_LOGE("%s] Error from gnssStatusCb SESSION_END description=%s",
+ __func__, r.description().c_str());
+ }
+ r = gnssCbIface->gnssStatusCb(IGnssCallback::GnssStatusValue::ENGINE_OFF);
+ if (!r.isOk()) {
+ LOC_LOGE("%s] Error from gnssStatusCb ENGINE_OFF description=%s",
+ __func__, r.description().c_str());
+ }
+ }
+ }
+}
+
+static void convertGnssSvStatus(GnssSvNotification& in, V1_0::IGnssCallback::GnssSvStatus& out)
+{
+ memset(&out, 0, sizeof(IGnssCallback::GnssSvStatus));
+ out.numSvs = in.count;
+ if (out.numSvs > static_cast<uint32_t>(V1_0::GnssMax::SVS_COUNT)) {
+ LOC_LOGW("%s]: Too many satellites %u. Clamps to %d.",
+ __FUNCTION__, out.numSvs, V1_0::GnssMax::SVS_COUNT);
+ out.numSvs = static_cast<uint32_t>(V1_0::GnssMax::SVS_COUNT);
+ }
+ for (size_t i = 0; i < out.numSvs; i++) {
+ out.gnssSvList[i].svid = in.gnssSvs[i].svId;
+ convertGnssConstellationType(in.gnssSvs[i].type, out.gnssSvList[i].constellation);
+ out.gnssSvList[i].cN0Dbhz = in.gnssSvs[i].cN0Dbhz;
+ out.gnssSvList[i].elevationDegrees = in.gnssSvs[i].elevation;
+ out.gnssSvList[i].azimuthDegrees = in.gnssSvs[i].azimuth;
+ out.gnssSvList[i].carrierFrequencyHz = in.gnssSvs[i].carrierFrequencyHz;
+ out.gnssSvList[i].svFlag = static_cast<uint8_t>(IGnssCallback::GnssSvFlags::NONE);
+ if (in.gnssSvs[i].gnssSvOptionsMask & GNSS_SV_OPTIONS_HAS_EPHEMER_BIT)
+ out.gnssSvList[i].svFlag |= IGnssCallback::GnssSvFlags::HAS_EPHEMERIS_DATA;
+ if (in.gnssSvs[i].gnssSvOptionsMask & GNSS_SV_OPTIONS_HAS_ALMANAC_BIT)
+ out.gnssSvList[i].svFlag |= IGnssCallback::GnssSvFlags::HAS_ALMANAC_DATA;
+ if (in.gnssSvs[i].gnssSvOptionsMask & GNSS_SV_OPTIONS_USED_IN_FIX_BIT)
+ out.gnssSvList[i].svFlag |= IGnssCallback::GnssSvFlags::USED_IN_FIX;
+ if (in.gnssSvs[i].gnssSvOptionsMask & GNSS_SV_OPTIONS_HAS_CARRIER_FREQUENCY_BIT)
+ out.gnssSvList[i].svFlag |= IGnssCallback::GnssSvFlags::HAS_CARRIER_FREQUENCY;
+ }
+}
+
+static void convertGnssSvStatus(GnssSvNotification& in,
+ hidl_vec<V2_0::IGnssCallback::GnssSvInfo>& out)
+{
+ out.resize(in.count);
+ for (size_t i = 0; i < in.count; i++) {
+ out[i].v1_0.svid = in.gnssSvs[i].svId;
+ out[i].v1_0.cN0Dbhz = in.gnssSvs[i].cN0Dbhz;
+ out[i].v1_0.elevationDegrees = in.gnssSvs[i].elevation;
+ out[i].v1_0.azimuthDegrees = in.gnssSvs[i].azimuth;
+ out[i].v1_0.carrierFrequencyHz = in.gnssSvs[i].carrierFrequencyHz;
+ out[i].v1_0.svFlag = static_cast<uint8_t>(IGnssCallback::GnssSvFlags::NONE);
+ if (in.gnssSvs[i].gnssSvOptionsMask & GNSS_SV_OPTIONS_HAS_EPHEMER_BIT)
+ out[i].v1_0.svFlag |= IGnssCallback::GnssSvFlags::HAS_EPHEMERIS_DATA;
+ if (in.gnssSvs[i].gnssSvOptionsMask & GNSS_SV_OPTIONS_HAS_ALMANAC_BIT)
+ out[i].v1_0.svFlag |= IGnssCallback::GnssSvFlags::HAS_ALMANAC_DATA;
+ if (in.gnssSvs[i].gnssSvOptionsMask & GNSS_SV_OPTIONS_USED_IN_FIX_BIT)
+ out[i].v1_0.svFlag |= IGnssCallback::GnssSvFlags::USED_IN_FIX;
+ if (in.gnssSvs[i].gnssSvOptionsMask & GNSS_SV_OPTIONS_HAS_CARRIER_FREQUENCY_BIT)
+ out[i].v1_0.svFlag |= IGnssCallback::GnssSvFlags::HAS_CARRIER_FREQUENCY;
+
+ convertGnssConstellationType(in.gnssSvs[i].type, out[i].constellation);
+ }
+}
+
+} // namespace implementation
+} // namespace V2_0
+} // namespace gnss
+} // namespace hardware
+} // namespace android
diff --git a/android/2.0/location_api/GnssAPIClient.h b/android/2.0/location_api/GnssAPIClient.h
new file mode 100644
index 0000000..63b4561
--- /dev/null
+++ b/android/2.0/location_api/GnssAPIClient.h
@@ -0,0 +1,114 @@
+/* Copyright (c) 2017-2019, 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 GNSS_API_CLINET_H
+#define GNSS_API_CLINET_H
+
+
+#include <mutex>
+#include <android/hardware/gnss/2.0/IGnss.h>
+#include <android/hardware/gnss/2.0/IGnssCallback.h>
+#include <LocationAPIClientBase.h>
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace V2_0 {
+namespace implementation {
+
+using ::android::sp;
+
+class GnssAPIClient : public LocationAPIClientBase
+{
+public:
+ GnssAPIClient(const sp<V1_0::IGnssCallback>& gpsCb,
+ const sp<V1_0::IGnssNiCallback>& niCb);
+ GnssAPIClient(const sp<V2_0::IGnssCallback>& gpsCb);
+ virtual ~GnssAPIClient();
+ GnssAPIClient(const GnssAPIClient&) = delete;
+ GnssAPIClient& operator=(const GnssAPIClient&) = delete;
+
+ // for GpsInterface
+ void gnssUpdateCallbacks(const sp<V1_0::IGnssCallback>& gpsCb,
+ const sp<V1_0::IGnssNiCallback>& niCb);
+ void gnssUpdateCallbacks_2_0(const sp<V2_0::IGnssCallback>& gpsCb);
+ bool gnssStart();
+ bool gnssStop();
+ bool gnssSetPositionMode(V1_0::IGnss::GnssPositionMode mode,
+ V1_0::IGnss::GnssPositionRecurrence recurrence,
+ uint32_t minIntervalMs,
+ uint32_t preferredAccuracyMeters,
+ uint32_t preferredTimeMs,
+ GnssPowerMode powerMode = GNSS_POWER_MODE_INVALID,
+ uint32_t timeBetweenMeasurement = 0);
+
+ // for GpsNiInterface
+ void gnssNiRespond(int32_t notifId, V1_0::IGnssNiCallback::GnssUserResponseType userResponse);
+
+ // these apis using LocationAPIControlClient
+ void gnssDeleteAidingData(V1_0::IGnss::GnssAidingData aidingDataFlags);
+ void gnssEnable(LocationTechnologyType techType);
+ void gnssDisable();
+ void gnssConfigurationUpdate(const GnssConfig& gnssConfig);
+
+ inline LocationCapabilitiesMask gnssGetCapabilities() const {
+ return mLocationCapabilitiesMask;
+ }
+ void requestCapabilities();
+
+ // callbacks we are interested in
+ void onCapabilitiesCb(LocationCapabilitiesMask capabilitiesMask) final;
+ void onTrackingCb(Location location) final;
+ void onGnssNiCb(uint32_t id, GnssNiNotification gnssNiNotification) final;
+ void onGnssSvCb(GnssSvNotification gnssSvNotification) final;
+ void onGnssNmeaCb(GnssNmeaNotification gnssNmeaNotification) final;
+
+ void onStartTrackingCb(LocationError error) final;
+ void onStopTrackingCb(LocationError error) final;
+
+private:
+ void setCallbacks();
+ void initLocationOptions();
+ sp<V1_0::IGnssCallback> mGnssCbIface;
+ sp<V1_0::IGnssNiCallback> mGnssNiCbIface;
+ std::mutex mMutex;
+ LocationAPIControlClient* mControlClient;
+ LocationCapabilitiesMask mLocationCapabilitiesMask;
+ bool mLocationCapabilitiesCached;
+ TrackingOptions mTrackingOptions;
+ bool mTracking;
+ sp<V2_0::IGnssCallback> mGnssCbIface_2_0;
+};
+
+} // namespace implementation
+} // namespace V2_0
+} // namespace gnss
+} // namespace hardware
+} // namespace android
+#endif // GNSS_API_CLINET_H
diff --git a/android/2.0/location_api/LocationUtil.cpp b/android/2.0/location_api/LocationUtil.cpp
new file mode 100644
index 0000000..38a083a
--- /dev/null
+++ b/android/2.0/location_api/LocationUtil.cpp
@@ -0,0 +1,278 @@
+/* Copyright (c) 2017-2019, 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.
+ *
+ */
+
+#include <LocationUtil.h>
+#include <log_util.h>
+#include <inttypes.h>
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace V2_0 {
+namespace implementation {
+
+using ::android::hardware::gnss::V2_0::GnssLocation;
+using ::android::hardware::gnss::V2_0::GnssConstellationType;
+using ::android::hardware::gnss::V1_0::GnssLocationFlags;
+
+void convertGnssLocation(Location& in, V1_0::GnssLocation& out)
+{
+ memset(&out, 0, sizeof(V1_0::GnssLocation));
+ if (in.flags & LOCATION_HAS_LAT_LONG_BIT) {
+ out.gnssLocationFlags |= GnssLocationFlags::HAS_LAT_LONG;
+ out.latitudeDegrees = in.latitude;
+ out.longitudeDegrees = in.longitude;
+ }
+ if (in.flags & LOCATION_HAS_ALTITUDE_BIT) {
+ out.gnssLocationFlags |= GnssLocationFlags::HAS_ALTITUDE;
+ out.altitudeMeters = in.altitude;
+ }
+ if (in.flags & LOCATION_HAS_SPEED_BIT) {
+ out.gnssLocationFlags |= GnssLocationFlags::HAS_SPEED;
+ out.speedMetersPerSec = in.speed;
+ }
+ if (in.flags & LOCATION_HAS_BEARING_BIT) {
+ out.gnssLocationFlags |= GnssLocationFlags::HAS_BEARING;
+ out.bearingDegrees = in.bearing;
+ }
+ if (in.flags & LOCATION_HAS_ACCURACY_BIT) {
+ out.gnssLocationFlags |= GnssLocationFlags::HAS_HORIZONTAL_ACCURACY;
+ out.horizontalAccuracyMeters = in.accuracy;
+ }
+ if (in.flags & LOCATION_HAS_VERTICAL_ACCURACY_BIT) {
+ out.gnssLocationFlags |= GnssLocationFlags::HAS_VERTICAL_ACCURACY;
+ out.verticalAccuracyMeters = in.verticalAccuracy;
+ }
+ if (in.flags & LOCATION_HAS_SPEED_ACCURACY_BIT) {
+ out.gnssLocationFlags |= GnssLocationFlags::HAS_SPEED_ACCURACY;
+ out.speedAccuracyMetersPerSecond = in.speedAccuracy;
+ }
+ if (in.flags & LOCATION_HAS_BEARING_ACCURACY_BIT) {
+ out.gnssLocationFlags |= GnssLocationFlags::HAS_BEARING_ACCURACY;
+ out.bearingAccuracyDegrees = in.bearingAccuracy;
+ }
+
+ out.timestamp = static_cast<V1_0::GnssUtcTime>(in.timestamp);
+}
+
+void convertGnssLocation(Location& in, V2_0::GnssLocation& out)
+{
+ memset(&out, 0, sizeof(V2_0::GnssLocation));
+ convertGnssLocation(in, out.v1_0);
+
+ struct timespec sinceBootTime;
+ struct timespec currentTime;
+ if (0 == clock_gettime(CLOCK_BOOTTIME,&sinceBootTime) &&
+ 0 == clock_gettime(CLOCK_REALTIME,&currentTime)) {
+
+ int64_t sinceBootTimeNanos = sinceBootTime.tv_sec*1000000000 + sinceBootTime.tv_nsec;
+ int64_t currentTimeNanos = currentTime.tv_sec*1000000000 + currentTime.tv_nsec;
+ int64_t locationTimeNanos = in.timestamp*1000000;
+ LOC_LOGD("%s]: sinceBootTimeNanos:%" PRIi64 " currentTimeNanos:%" PRIi64 ""
+ " locationTimeNanos:%" PRIi64 "",
+ __FUNCTION__, sinceBootTimeNanos, currentTimeNanos, locationTimeNanos);
+ if (currentTimeNanos >= locationTimeNanos) {
+ int64_t ageTimeNanos = currentTimeNanos - locationTimeNanos;
+ LOC_LOGD("%s]: ageTimeNanos:%" PRIi64 ")", __FUNCTION__, ageTimeNanos);
+ if (ageTimeNanos >= 0 && ageTimeNanos <= sinceBootTimeNanos) {
+ out.elapsedRealtime.flags |= ElapsedRealtimeFlags::HAS_TIMESTAMP_NS;
+ out.elapsedRealtime.timestampNs = sinceBootTimeNanos - ageTimeNanos;
+ out.elapsedRealtime.flags |= ElapsedRealtimeFlags::HAS_TIME_UNCERTAINTY_NS;
+ // time uncertainty is 1 ms since it is calculated from utc time that is in ms
+ out.elapsedRealtime.timeUncertaintyNs = 1000000;
+ LOC_LOGD("%s]: timestampNs:%" PRIi64 ")",
+ __FUNCTION__, out.elapsedRealtime.timestampNs);
+ }
+ }
+ }
+
+}
+
+void convertGnssLocation(const V1_0::GnssLocation& in, Location& out)
+{
+ memset(&out, 0, sizeof(out));
+ if (in.gnssLocationFlags & GnssLocationFlags::HAS_LAT_LONG) {
+ out.flags |= LOCATION_HAS_LAT_LONG_BIT;
+ out.latitude = in.latitudeDegrees;
+ out.longitude = in.longitudeDegrees;
+ }
+ if (in.gnssLocationFlags & GnssLocationFlags::HAS_ALTITUDE) {
+ out.flags |= LOCATION_HAS_ALTITUDE_BIT;
+ out.altitude = in.altitudeMeters;
+ }
+ if (in.gnssLocationFlags & GnssLocationFlags::HAS_SPEED) {
+ out.flags |= LOCATION_HAS_SPEED_BIT;
+ out.speed = in.speedMetersPerSec;
+ }
+ if (in.gnssLocationFlags & GnssLocationFlags::HAS_BEARING) {
+ out.flags |= LOCATION_HAS_BEARING_BIT;
+ out.bearing = in.bearingDegrees;
+ }
+ if (in.gnssLocationFlags & GnssLocationFlags::HAS_HORIZONTAL_ACCURACY) {
+ out.flags |= LOCATION_HAS_ACCURACY_BIT;
+ out.accuracy = in.horizontalAccuracyMeters;
+ }
+ if (in.gnssLocationFlags & GnssLocationFlags::HAS_VERTICAL_ACCURACY) {
+ out.flags |= LOCATION_HAS_VERTICAL_ACCURACY_BIT;
+ out.verticalAccuracy = in.verticalAccuracyMeters;
+ }
+ if (in.gnssLocationFlags & GnssLocationFlags::HAS_SPEED_ACCURACY) {
+ out.flags |= LOCATION_HAS_SPEED_ACCURACY_BIT;
+ out.speedAccuracy = in.speedAccuracyMetersPerSecond;
+ }
+ if (in.gnssLocationFlags & GnssLocationFlags::HAS_BEARING_ACCURACY) {
+ out.flags |= LOCATION_HAS_BEARING_ACCURACY_BIT;
+ out.bearingAccuracy = in.bearingAccuracyDegrees;
+ }
+
+ out.timestamp = static_cast<uint64_t>(in.timestamp);
+}
+
+void convertGnssLocation(const V2_0::GnssLocation& in, Location& out)
+{
+ memset(&out, 0, sizeof(out));
+ convertGnssLocation(in.v1_0, out);
+}
+
+void convertGnssConstellationType(GnssSvType& in, V1_0::GnssConstellationType& out)
+{
+ switch(in) {
+ case GNSS_SV_TYPE_GPS:
+ out = V1_0::GnssConstellationType::GPS;
+ break;
+ case GNSS_SV_TYPE_SBAS:
+ out = V1_0::GnssConstellationType::SBAS;
+ break;
+ case GNSS_SV_TYPE_GLONASS:
+ out = V1_0::GnssConstellationType::GLONASS;
+ break;
+ case GNSS_SV_TYPE_QZSS:
+ out = V1_0::GnssConstellationType::QZSS;
+ break;
+ case GNSS_SV_TYPE_BEIDOU:
+ out = V1_0::GnssConstellationType::BEIDOU;
+ break;
+ case GNSS_SV_TYPE_GALILEO:
+ out = V1_0::GnssConstellationType::GALILEO;
+ break;
+ case GNSS_SV_TYPE_UNKNOWN:
+ default:
+ out = V1_0::GnssConstellationType::UNKNOWN;
+ break;
+ }
+}
+
+void convertGnssConstellationType(GnssSvType& in, V2_0::GnssConstellationType& out)
+{
+ switch(in) {
+ case GNSS_SV_TYPE_GPS:
+ out = V2_0::GnssConstellationType::GPS;
+ break;
+ case GNSS_SV_TYPE_SBAS:
+ out = V2_0::GnssConstellationType::SBAS;
+ break;
+ case GNSS_SV_TYPE_GLONASS:
+ out = V2_0::GnssConstellationType::GLONASS;
+ break;
+ case GNSS_SV_TYPE_QZSS:
+ out = V2_0::GnssConstellationType::QZSS;
+ break;
+ case GNSS_SV_TYPE_BEIDOU:
+ out = V2_0::GnssConstellationType::BEIDOU;
+ break;
+ case GNSS_SV_TYPE_GALILEO:
+ out = V2_0::GnssConstellationType::GALILEO;
+ break;
+ case GNSS_SV_TYPE_NAVIC:
+ out = V2_0::GnssConstellationType::IRNSS;
+ break;
+ case GNSS_SV_TYPE_UNKNOWN:
+ default:
+ out = V2_0::GnssConstellationType::UNKNOWN;
+ break;
+ }
+}
+
+void convertGnssEphemerisType(GnssEphemerisType& in, GnssDebug::SatelliteEphemerisType& out)
+{
+ switch(in) {
+ case GNSS_EPH_TYPE_EPHEMERIS:
+ out = GnssDebug::SatelliteEphemerisType::EPHEMERIS;
+ break;
+ case GNSS_EPH_TYPE_ALMANAC:
+ out = GnssDebug::SatelliteEphemerisType::ALMANAC_ONLY;
+ break;
+ case GNSS_EPH_TYPE_UNKNOWN:
+ default:
+ out = GnssDebug::SatelliteEphemerisType::NOT_AVAILABLE;
+ break;
+ }
+}
+
+void convertGnssEphemerisSource(GnssEphemerisSource& in, GnssDebug::SatelliteEphemerisSource& out)
+{
+ switch(in) {
+ case GNSS_EPH_SOURCE_DEMODULATED:
+ out = GnssDebug::SatelliteEphemerisSource::DEMODULATED;
+ break;
+ case GNSS_EPH_SOURCE_SUPL_PROVIDED:
+ out = GnssDebug::SatelliteEphemerisSource::SUPL_PROVIDED;
+ break;
+ case GNSS_EPH_SOURCE_OTHER_SERVER_PROVIDED:
+ out = GnssDebug::SatelliteEphemerisSource::OTHER_SERVER_PROVIDED;
+ break;
+ case GNSS_EPH_SOURCE_LOCAL:
+ case GNSS_EPH_SOURCE_UNKNOWN:
+ default:
+ out = GnssDebug::SatelliteEphemerisSource::OTHER;
+ break;
+ }
+}
+
+void convertGnssEphemerisHealth(GnssEphemerisHealth& in, GnssDebug::SatelliteEphemerisHealth& out)
+{
+ switch(in) {
+ case GNSS_EPH_HEALTH_GOOD:
+ out = GnssDebug::SatelliteEphemerisHealth::GOOD;
+ break;
+ case GNSS_EPH_HEALTH_BAD:
+ out = GnssDebug::SatelliteEphemerisHealth::BAD;
+ break;
+ case GNSS_EPH_HEALTH_UNKNOWN:
+ default:
+ out = GnssDebug::SatelliteEphemerisHealth::UNKNOWN;
+ break;
+ }
+}
+
+} // namespace implementation
+} // namespace V2_0
+} // namespace gnss
+} // namespace hardware
+} // namespace android
diff --git a/android/2.0/location_api/LocationUtil.h b/android/2.0/location_api/LocationUtil.h
new file mode 100644
index 0000000..8426de7
--- /dev/null
+++ b/android/2.0/location_api/LocationUtil.h
@@ -0,0 +1,58 @@
+/* Copyright (c) 2017-2019, 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_UTIL_H
+#define LOCATION_UTIL_H
+
+#include <android/hardware/gnss/2.0/types.h>
+#include <LocationAPI.h>
+#include <GnssDebug.h>
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace V2_0 {
+namespace implementation {
+
+void convertGnssLocation(Location& in, V1_0::GnssLocation& out);
+void convertGnssLocation(Location& in, V2_0::GnssLocation& out);
+void convertGnssLocation(const V1_0::GnssLocation& in, Location& out);
+void convertGnssLocation(const V2_0::GnssLocation& in, Location& out);
+void convertGnssConstellationType(GnssSvType& in, V1_0::GnssConstellationType& out);
+void convertGnssConstellationType(GnssSvType& in, V2_0::GnssConstellationType& out);
+void convertGnssEphemerisType(GnssEphemerisType& in, GnssDebug::SatelliteEphemerisType& out);
+void convertGnssEphemerisSource(GnssEphemerisSource& in, GnssDebug::SatelliteEphemerisSource& out);
+void convertGnssEphemerisHealth(GnssEphemerisHealth& in, GnssDebug::SatelliteEphemerisHealth& out);
+
+} // namespace implementation
+} // namespace V2_0
+} // namespace gnss
+} // namespace hardware
+} // namespace android
+#endif // LOCATION_UTIL_H
diff --git a/android/2.0/location_api/MeasurementAPIClient.cpp b/android/2.0/location_api/MeasurementAPIClient.cpp
new file mode 100644
index 0000000..dc972ec
--- /dev/null
+++ b/android/2.0/location_api/MeasurementAPIClient.cpp
@@ -0,0 +1,474 @@
+/* Copyright (c) 2017-2019, 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_NDEBUG 0
+#define LOG_TAG "LocSvc_MeasurementAPIClient"
+
+#include <log_util.h>
+#include <loc_cfg.h>
+
+#include "LocationUtil.h"
+#include "MeasurementAPIClient.h"
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace V2_0 {
+namespace implementation {
+
+using ::android::hardware::gnss::V1_0::IGnssMeasurement;
+using ::android::hardware::gnss::V2_0::IGnssMeasurementCallback;
+
+static void convertGnssData(GnssMeasurementsNotification& in,
+ V1_0::IGnssMeasurementCallback::GnssData& out);
+static void convertGnssData_1_1(GnssMeasurementsNotification& in,
+ V1_1::IGnssMeasurementCallback::GnssData& out);
+static void convertGnssData_2_0(GnssMeasurementsNotification& in,
+ V2_0::IGnssMeasurementCallback::GnssData& out);
+static void convertGnssMeasurement(GnssMeasurementsData& in,
+ V1_0::IGnssMeasurementCallback::GnssMeasurement& out);
+static void convertGnssClock(GnssMeasurementsClock& in, IGnssMeasurementCallback::GnssClock& out);
+static void convertGnssMeasurementsCodeType(GnssMeasurementsCodeType& in,
+ ::android::hardware::hidl_string& out);
+
+MeasurementAPIClient::MeasurementAPIClient() :
+ mGnssMeasurementCbIface(nullptr),
+ mGnssMeasurementCbIface_1_1(nullptr),
+ mGnssMeasurementCbIface_2_0(nullptr),
+ mTracking(false)
+{
+ LOC_LOGD("%s]: ()", __FUNCTION__);
+}
+
+MeasurementAPIClient::~MeasurementAPIClient()
+{
+ LOC_LOGD("%s]: ()", __FUNCTION__);
+}
+
+// for GpsInterface
+Return<IGnssMeasurement::GnssMeasurementStatus>
+MeasurementAPIClient::measurementSetCallback(const sp<V1_0::IGnssMeasurementCallback>& callback)
+{
+ LOC_LOGD("%s]: (%p)", __FUNCTION__, &callback);
+
+ mMutex.lock();
+ mGnssMeasurementCbIface = callback;
+ mMutex.unlock();
+
+ return startTracking();
+}
+
+Return<IGnssMeasurement::GnssMeasurementStatus>
+MeasurementAPIClient::measurementSetCallback_1_1(
+ const sp<V1_1::IGnssMeasurementCallback>& callback,
+ GnssPowerMode powerMode, uint32_t timeBetweenMeasurement)
+{
+ LOC_LOGD("%s]: (%p) (powermode: %d) (tbm: %d)",
+ __FUNCTION__, &callback, (int)powerMode, timeBetweenMeasurement);
+
+ mMutex.lock();
+ mGnssMeasurementCbIface_1_1 = callback;
+ mMutex.unlock();
+
+ return startTracking(powerMode, timeBetweenMeasurement);
+}
+
+Return<IGnssMeasurement::GnssMeasurementStatus>
+MeasurementAPIClient::measurementSetCallback_2_0(
+ const sp<V2_0::IGnssMeasurementCallback>& callback,
+ GnssPowerMode powerMode, uint32_t timeBetweenMeasurement)
+{
+ LOC_LOGD("%s]: (%p) (powermode: %d) (tbm: %d)",
+ __FUNCTION__, &callback, (int)powerMode, timeBetweenMeasurement);
+
+ mMutex.lock();
+ mGnssMeasurementCbIface_2_0 = callback;
+ mMutex.unlock();
+
+ return startTracking(powerMode, timeBetweenMeasurement);
+}
+
+Return<IGnssMeasurement::GnssMeasurementStatus>
+MeasurementAPIClient::startTracking(
+ GnssPowerMode powerMode, uint32_t timeBetweenMeasurement)
+{
+ LocationCallbacks locationCallbacks;
+ memset(&locationCallbacks, 0, sizeof(LocationCallbacks));
+ locationCallbacks.size = sizeof(LocationCallbacks);
+
+ locationCallbacks.trackingCb = nullptr;
+ locationCallbacks.batchingCb = nullptr;
+ locationCallbacks.geofenceBreachCb = nullptr;
+ locationCallbacks.geofenceStatusCb = nullptr;
+ locationCallbacks.gnssLocationInfoCb = nullptr;
+ locationCallbacks.gnssNiCb = nullptr;
+ locationCallbacks.gnssSvCb = nullptr;
+ locationCallbacks.gnssNmeaCb = nullptr;
+
+ locationCallbacks.gnssMeasurementsCb = nullptr;
+ if (mGnssMeasurementCbIface_2_0 != nullptr ||
+ mGnssMeasurementCbIface_1_1 != nullptr ||
+ mGnssMeasurementCbIface != nullptr) {
+ locationCallbacks.gnssMeasurementsCb =
+ [this](GnssMeasurementsNotification gnssMeasurementsNotification) {
+ onGnssMeasurementsCb(gnssMeasurementsNotification);
+ };
+ }
+
+ locAPISetCallbacks(locationCallbacks);
+
+ TrackingOptions options = {};
+ memset(&options, 0, sizeof(TrackingOptions));
+ options.size = sizeof(TrackingOptions);
+ options.minInterval = 1000;
+ options.mode = GNSS_SUPL_MODE_STANDALONE;
+ if (GNSS_POWER_MODE_INVALID != powerMode) {
+ options.powerMode = powerMode;
+ options.tbm = timeBetweenMeasurement;
+ }
+
+ mTracking = true;
+ LOC_LOGD("%s]: start tracking session", __FUNCTION__);
+ locAPIStartTracking(options);
+ return IGnssMeasurement::GnssMeasurementStatus::SUCCESS;
+}
+
+// for GpsMeasurementInterface
+void MeasurementAPIClient::measurementClose() {
+ LOC_LOGD("%s]: ()", __FUNCTION__);
+ mTracking = false;
+ locAPIStopTracking();
+}
+
+// callbacks
+void MeasurementAPIClient::onGnssMeasurementsCb(
+ GnssMeasurementsNotification gnssMeasurementsNotification)
+{
+ LOC_LOGD("%s]: (count: %u active: %d)",
+ __FUNCTION__, gnssMeasurementsNotification.count, mTracking);
+ if (mTracking) {
+ mMutex.lock();
+ sp<V1_0::IGnssMeasurementCallback> gnssMeasurementCbIface = nullptr;
+ sp<V1_1::IGnssMeasurementCallback> gnssMeasurementCbIface_1_1 = nullptr;
+ sp<V2_0::IGnssMeasurementCallback> gnssMeasurementCbIface_2_0 = nullptr;
+ if (mGnssMeasurementCbIface_2_0 != nullptr) {
+ gnssMeasurementCbIface_2_0 = mGnssMeasurementCbIface_2_0;
+ } else if (mGnssMeasurementCbIface_1_1 != nullptr) {
+ gnssMeasurementCbIface_1_1 = mGnssMeasurementCbIface_1_1;
+ } else if (mGnssMeasurementCbIface != nullptr) {
+ gnssMeasurementCbIface = mGnssMeasurementCbIface;
+ }
+ mMutex.unlock();
+
+ if (gnssMeasurementCbIface_2_0 != nullptr) {
+ V2_0::IGnssMeasurementCallback::GnssData gnssData;
+ convertGnssData_2_0(gnssMeasurementsNotification, gnssData);
+ auto r = gnssMeasurementCbIface_2_0->gnssMeasurementCb_2_0(gnssData);
+ if (!r.isOk()) {
+ LOC_LOGE("%s] Error from gnssMeasurementCb description=%s",
+ __func__, r.description().c_str());
+ }
+ } else if (gnssMeasurementCbIface_1_1 != nullptr) {
+ V1_1::IGnssMeasurementCallback::GnssData gnssData;
+ convertGnssData_1_1(gnssMeasurementsNotification, gnssData);
+ auto r = gnssMeasurementCbIface_1_1->gnssMeasurementCb(gnssData);
+ if (!r.isOk()) {
+ LOC_LOGE("%s] Error from gnssMeasurementCb description=%s",
+ __func__, r.description().c_str());
+ }
+ } else if (gnssMeasurementCbIface != nullptr) {
+ V1_0::IGnssMeasurementCallback::GnssData gnssData;
+ convertGnssData(gnssMeasurementsNotification, gnssData);
+ auto r = gnssMeasurementCbIface->GnssMeasurementCb(gnssData);
+ if (!r.isOk()) {
+ LOC_LOGE("%s] Error from GnssMeasurementCb description=%s",
+ __func__, r.description().c_str());
+ }
+ }
+ }
+}
+
+static void convertGnssMeasurement(GnssMeasurementsData& in,
+ V1_0::IGnssMeasurementCallback::GnssMeasurement& out)
+{
+ memset(&out, 0, sizeof(out));
+ if (in.flags & GNSS_MEASUREMENTS_DATA_SIGNAL_TO_NOISE_RATIO_BIT)
+ out.flags |= IGnssMeasurementCallback::GnssMeasurementFlags::HAS_SNR;
+ if (in.flags & GNSS_MEASUREMENTS_DATA_CARRIER_FREQUENCY_BIT)
+ out.flags |= IGnssMeasurementCallback::GnssMeasurementFlags::HAS_CARRIER_FREQUENCY;
+ if (in.flags & GNSS_MEASUREMENTS_DATA_CARRIER_CYCLES_BIT)
+ out.flags |= IGnssMeasurementCallback::GnssMeasurementFlags::HAS_CARRIER_CYCLES;
+ if (in.flags & GNSS_MEASUREMENTS_DATA_CARRIER_PHASE_BIT)
+ out.flags |= IGnssMeasurementCallback::GnssMeasurementFlags::HAS_CARRIER_PHASE;
+ if (in.flags & GNSS_MEASUREMENTS_DATA_CARRIER_PHASE_UNCERTAINTY_BIT)
+ out.flags |= IGnssMeasurementCallback::GnssMeasurementFlags::HAS_CARRIER_PHASE_UNCERTAINTY;
+ if (in.flags & GNSS_MEASUREMENTS_DATA_AUTOMATIC_GAIN_CONTROL_BIT)
+ out.flags |= IGnssMeasurementCallback::GnssMeasurementFlags::HAS_AUTOMATIC_GAIN_CONTROL;
+ out.svid = in.svId;
+ convertGnssConstellationType(in.svType, out.constellation);
+ out.timeOffsetNs = in.timeOffsetNs;
+ if (in.stateMask & GNSS_MEASUREMENTS_STATE_CODE_LOCK_BIT)
+ out.state |= IGnssMeasurementCallback::GnssMeasurementState::STATE_CODE_LOCK;
+ if (in.stateMask & GNSS_MEASUREMENTS_STATE_BIT_SYNC_BIT)
+ out.state |= IGnssMeasurementCallback::GnssMeasurementState::STATE_BIT_SYNC;
+ if (in.stateMask & GNSS_MEASUREMENTS_STATE_SUBFRAME_SYNC_BIT)
+ out.state |= IGnssMeasurementCallback::GnssMeasurementState::STATE_SUBFRAME_SYNC;
+ if (in.stateMask & GNSS_MEASUREMENTS_STATE_TOW_DECODED_BIT)
+ out.state |= IGnssMeasurementCallback::GnssMeasurementState::STATE_TOW_DECODED;
+ if (in.stateMask & GNSS_MEASUREMENTS_STATE_MSEC_AMBIGUOUS_BIT)
+ out.state |= IGnssMeasurementCallback::GnssMeasurementState::STATE_MSEC_AMBIGUOUS;
+ if (in.stateMask & GNSS_MEASUREMENTS_STATE_SYMBOL_SYNC_BIT)
+ out.state |= IGnssMeasurementCallback::GnssMeasurementState::STATE_SYMBOL_SYNC;
+ if (in.stateMask & GNSS_MEASUREMENTS_STATE_GLO_STRING_SYNC_BIT)
+ out.state |= IGnssMeasurementCallback::GnssMeasurementState::STATE_GLO_STRING_SYNC;
+ if (in.stateMask & GNSS_MEASUREMENTS_STATE_GLO_TOD_DECODED_BIT)
+ out.state |= IGnssMeasurementCallback::GnssMeasurementState::STATE_GLO_TOD_DECODED;
+ if (in.stateMask & GNSS_MEASUREMENTS_STATE_BDS_D2_BIT_SYNC_BIT)
+ out.state |= IGnssMeasurementCallback::GnssMeasurementState::STATE_BDS_D2_BIT_SYNC;
+ if (in.stateMask & GNSS_MEASUREMENTS_STATE_BDS_D2_SUBFRAME_SYNC_BIT)
+ out.state |= IGnssMeasurementCallback::GnssMeasurementState::STATE_BDS_D2_SUBFRAME_SYNC;
+ if (in.stateMask & GNSS_MEASUREMENTS_STATE_GAL_E1BC_CODE_LOCK_BIT)
+ out.state |= IGnssMeasurementCallback::GnssMeasurementState::STATE_GAL_E1BC_CODE_LOCK;
+ if (in.stateMask & GNSS_MEASUREMENTS_STATE_GAL_E1C_2ND_CODE_LOCK_BIT)
+ out.state |= IGnssMeasurementCallback::GnssMeasurementState::STATE_GAL_E1C_2ND_CODE_LOCK;
+ if (in.stateMask & GNSS_MEASUREMENTS_STATE_GAL_E1B_PAGE_SYNC_BIT)
+ out.state |= IGnssMeasurementCallback::GnssMeasurementState::STATE_GAL_E1B_PAGE_SYNC;
+ if (in.stateMask & GNSS_MEASUREMENTS_STATE_SBAS_SYNC_BIT)
+ out.state |= IGnssMeasurementCallback::GnssMeasurementState::STATE_SBAS_SYNC;
+ out.receivedSvTimeInNs = in.receivedSvTimeNs;
+ out.receivedSvTimeUncertaintyInNs = in.receivedSvTimeUncertaintyNs;
+ out.cN0DbHz = in.carrierToNoiseDbHz;
+ out.pseudorangeRateMps = in.pseudorangeRateMps;
+ out.pseudorangeRateUncertaintyMps = in.pseudorangeRateUncertaintyMps;
+ if (in.adrStateMask & GNSS_MEASUREMENTS_ACCUMULATED_DELTA_RANGE_STATE_VALID_BIT)
+ out.accumulatedDeltaRangeState |=
+ IGnssMeasurementCallback::GnssAccumulatedDeltaRangeState::ADR_STATE_VALID;
+ if (in.adrStateMask & GNSS_MEASUREMENTS_ACCUMULATED_DELTA_RANGE_STATE_RESET_BIT)
+ out.accumulatedDeltaRangeState |=
+ IGnssMeasurementCallback::GnssAccumulatedDeltaRangeState::ADR_STATE_RESET;
+ if (in.adrStateMask & GNSS_MEASUREMENTS_ACCUMULATED_DELTA_RANGE_STATE_CYCLE_SLIP_BIT)
+ out.accumulatedDeltaRangeState |=
+ IGnssMeasurementCallback::GnssAccumulatedDeltaRangeState::ADR_STATE_CYCLE_SLIP;
+ out.accumulatedDeltaRangeM = in.adrMeters;
+ out.accumulatedDeltaRangeUncertaintyM = in.adrUncertaintyMeters;
+ out.carrierFrequencyHz = in.carrierFrequencyHz;
+ out.carrierCycles = in.carrierCycles;
+ out.carrierPhase = in.carrierPhase;
+ out.carrierPhaseUncertainty = in.carrierPhaseUncertainty;
+ uint8_t indicator =
+ static_cast<uint8_t>(IGnssMeasurementCallback::GnssMultipathIndicator::INDICATOR_UNKNOWN);
+ if (in.multipathIndicator & GNSS_MEASUREMENTS_MULTIPATH_INDICATOR_PRESENT)
+ indicator |= IGnssMeasurementCallback::GnssMultipathIndicator::INDICATOR_PRESENT;
+ if (in.multipathIndicator & GNSS_MEASUREMENTS_MULTIPATH_INDICATOR_NOT_PRESENT)
+ indicator |= IGnssMeasurementCallback::GnssMultipathIndicator::INDICATIOR_NOT_PRESENT;
+ out.multipathIndicator =
+ static_cast<IGnssMeasurementCallback::GnssMultipathIndicator>(indicator);
+ out.snrDb = in.signalToNoiseRatioDb;
+ out.agcLevelDb = in.agcLevelDb;
+}
+
+static void convertGnssClock(GnssMeasurementsClock& in, IGnssMeasurementCallback::GnssClock& out)
+{
+ memset(&out, 0, sizeof(IGnssMeasurementCallback::GnssClock));
+ if (in.flags & GNSS_MEASUREMENTS_CLOCK_FLAGS_LEAP_SECOND_BIT)
+ out.gnssClockFlags |= IGnssMeasurementCallback::GnssClockFlags::HAS_LEAP_SECOND;
+ if (in.flags & GNSS_MEASUREMENTS_CLOCK_FLAGS_TIME_UNCERTAINTY_BIT)
+ out.gnssClockFlags |= IGnssMeasurementCallback::GnssClockFlags::HAS_TIME_UNCERTAINTY;
+ if (in.flags & GNSS_MEASUREMENTS_CLOCK_FLAGS_FULL_BIAS_BIT)
+ out.gnssClockFlags |= IGnssMeasurementCallback::GnssClockFlags::HAS_FULL_BIAS;
+ if (in.flags & GNSS_MEASUREMENTS_CLOCK_FLAGS_BIAS_BIT)
+ out.gnssClockFlags |= IGnssMeasurementCallback::GnssClockFlags::HAS_BIAS;
+ if (in.flags & GNSS_MEASUREMENTS_CLOCK_FLAGS_BIAS_UNCERTAINTY_BIT)
+ out.gnssClockFlags |= IGnssMeasurementCallback::GnssClockFlags::HAS_BIAS_UNCERTAINTY;
+ if (in.flags & GNSS_MEASUREMENTS_CLOCK_FLAGS_DRIFT_BIT)
+ out.gnssClockFlags |= IGnssMeasurementCallback::GnssClockFlags::HAS_DRIFT;
+ if (in.flags & GNSS_MEASUREMENTS_CLOCK_FLAGS_DRIFT_UNCERTAINTY_BIT)
+ out.gnssClockFlags |= IGnssMeasurementCallback::GnssClockFlags::HAS_DRIFT_UNCERTAINTY;
+ out.leapSecond = in.leapSecond;
+ out.timeNs = in.timeNs;
+ out.timeUncertaintyNs = in.timeUncertaintyNs;
+ out.fullBiasNs = in.fullBiasNs;
+ out.biasNs = in.biasNs;
+ out.biasUncertaintyNs = in.biasUncertaintyNs;
+ out.driftNsps = in.driftNsps;
+ out.driftUncertaintyNsps = in.driftUncertaintyNsps;
+ out.hwClockDiscontinuityCount = in.hwClockDiscontinuityCount;
+}
+
+static void convertGnssData(GnssMeasurementsNotification& in,
+ V1_0::IGnssMeasurementCallback::GnssData& out)
+{
+ out.measurementCount = in.count;
+ if (out.measurementCount > static_cast<uint32_t>(V1_0::GnssMax::SVS_COUNT)) {
+ LOC_LOGW("%s]: Too many measurement %u. Clamps to %d.",
+ __FUNCTION__, out.measurementCount, V1_0::GnssMax::SVS_COUNT);
+ out.measurementCount = static_cast<uint32_t>(V1_0::GnssMax::SVS_COUNT);
+ }
+ for (size_t i = 0; i < out.measurementCount; i++) {
+ convertGnssMeasurement(in.measurements[i], out.measurements[i]);
+ }
+ convertGnssClock(in.clock, out.clock);
+}
+
+static void convertGnssData_1_1(GnssMeasurementsNotification& in,
+ V1_1::IGnssMeasurementCallback::GnssData& out)
+{
+ out.measurements.resize(in.count);
+ for (size_t i = 0; i < in.count; i++) {
+ convertGnssMeasurement(in.measurements[i], out.measurements[i].v1_0);
+ if (in.measurements[i].adrStateMask & GNSS_MEASUREMENTS_ACCUMULATED_DELTA_RANGE_STATE_VALID_BIT)
+ out.measurements[i].accumulatedDeltaRangeState |=
+ IGnssMeasurementCallback::GnssAccumulatedDeltaRangeState::ADR_STATE_VALID;
+ if (in.measurements[i].adrStateMask & GNSS_MEASUREMENTS_ACCUMULATED_DELTA_RANGE_STATE_RESET_BIT)
+ out.measurements[i].accumulatedDeltaRangeState |=
+ IGnssMeasurementCallback::GnssAccumulatedDeltaRangeState::ADR_STATE_RESET;
+ if (in.measurements[i].adrStateMask & GNSS_MEASUREMENTS_ACCUMULATED_DELTA_RANGE_STATE_CYCLE_SLIP_BIT)
+ out.measurements[i].accumulatedDeltaRangeState |=
+ IGnssMeasurementCallback::GnssAccumulatedDeltaRangeState::ADR_STATE_CYCLE_SLIP;
+ if (in.measurements[i].adrStateMask & GNSS_MEASUREMENTS_ACCUMULATED_DELTA_RANGE_STATE_HALF_CYCLE_RESOLVED_BIT)
+ out.measurements[i].accumulatedDeltaRangeState |=
+ IGnssMeasurementCallback::GnssAccumulatedDeltaRangeState::ADR_STATE_HALF_CYCLE_RESOLVED;
+ }
+ convertGnssClock(in.clock, out.clock);
+}
+
+static void convertGnssData_2_0(GnssMeasurementsNotification& in,
+ V2_0::IGnssMeasurementCallback::GnssData& out)
+{
+ out.measurements.resize(in.count);
+ for (size_t i = 0; i < in.count; i++) {
+ convertGnssMeasurement(in.measurements[i], out.measurements[i].v1_1.v1_0);
+ convertGnssConstellationType(in.measurements[i].svType, out.measurements[i].constellation);
+ convertGnssMeasurementsCodeType(in.measurements[i].codeType, out.measurements[i].codeType);
+ if (in.measurements[i].adrStateMask & GNSS_MEASUREMENTS_ACCUMULATED_DELTA_RANGE_STATE_VALID_BIT)
+ out.measurements[i].v1_1.accumulatedDeltaRangeState |=
+ IGnssMeasurementCallback::GnssAccumulatedDeltaRangeState::ADR_STATE_VALID;
+ if (in.measurements[i].adrStateMask & GNSS_MEASUREMENTS_ACCUMULATED_DELTA_RANGE_STATE_RESET_BIT)
+ out.measurements[i].v1_1.accumulatedDeltaRangeState |=
+ IGnssMeasurementCallback::GnssAccumulatedDeltaRangeState::ADR_STATE_RESET;
+ if (in.measurements[i].adrStateMask & GNSS_MEASUREMENTS_ACCUMULATED_DELTA_RANGE_STATE_CYCLE_SLIP_BIT)
+ out.measurements[i].v1_1.accumulatedDeltaRangeState |=
+ IGnssMeasurementCallback::GnssAccumulatedDeltaRangeState::ADR_STATE_CYCLE_SLIP;
+ if (in.measurements[i].adrStateMask & GNSS_MEASUREMENTS_ACCUMULATED_DELTA_RANGE_STATE_HALF_CYCLE_RESOLVED_BIT)
+ out.measurements[i].v1_1.accumulatedDeltaRangeState |=
+ IGnssMeasurementCallback::GnssAccumulatedDeltaRangeState::ADR_STATE_HALF_CYCLE_RESOLVED;
+ if (in.measurements[i].stateMask & GNSS_MEASUREMENTS_STATE_CODE_LOCK_BIT)
+ out.measurements[i].state |= IGnssMeasurementCallback::GnssMeasurementState::STATE_CODE_LOCK;
+ if (in.measurements[i].stateMask & GNSS_MEASUREMENTS_STATE_BIT_SYNC_BIT)
+ out.measurements[i].state |= IGnssMeasurementCallback::GnssMeasurementState::STATE_BIT_SYNC;
+ if (in.measurements[i].stateMask & GNSS_MEASUREMENTS_STATE_SUBFRAME_SYNC_BIT)
+ out.measurements[i].state |= IGnssMeasurementCallback::GnssMeasurementState::STATE_SUBFRAME_SYNC;
+ if (in.measurements[i].stateMask & GNSS_MEASUREMENTS_STATE_TOW_DECODED_BIT)
+ out.measurements[i].state |= IGnssMeasurementCallback::GnssMeasurementState::STATE_TOW_DECODED;
+ if (in.measurements[i].stateMask & GNSS_MEASUREMENTS_STATE_MSEC_AMBIGUOUS_BIT)
+ out.measurements[i].state |= IGnssMeasurementCallback::GnssMeasurementState::STATE_MSEC_AMBIGUOUS;
+ if (in.measurements[i].stateMask & GNSS_MEASUREMENTS_STATE_SYMBOL_SYNC_BIT)
+ out.measurements[i].state |= IGnssMeasurementCallback::GnssMeasurementState::STATE_SYMBOL_SYNC;
+ if (in.measurements[i].stateMask & GNSS_MEASUREMENTS_STATE_GLO_STRING_SYNC_BIT)
+ out.measurements[i].state |= IGnssMeasurementCallback::GnssMeasurementState::STATE_GLO_STRING_SYNC;
+ if (in.measurements[i].stateMask & GNSS_MEASUREMENTS_STATE_GLO_TOD_DECODED_BIT)
+ out.measurements[i].state |= IGnssMeasurementCallback::GnssMeasurementState::STATE_GLO_TOD_DECODED;
+ if (in.measurements[i].stateMask & GNSS_MEASUREMENTS_STATE_BDS_D2_BIT_SYNC_BIT)
+ out.measurements[i].state |= IGnssMeasurementCallback::GnssMeasurementState::STATE_BDS_D2_BIT_SYNC;
+ if (in.measurements[i].stateMask & GNSS_MEASUREMENTS_STATE_BDS_D2_SUBFRAME_SYNC_BIT)
+ out.measurements[i].state |= IGnssMeasurementCallback::GnssMeasurementState::STATE_BDS_D2_SUBFRAME_SYNC;
+ if (in.measurements[i].stateMask & GNSS_MEASUREMENTS_STATE_GAL_E1BC_CODE_LOCK_BIT)
+ out.measurements[i].state |= IGnssMeasurementCallback::GnssMeasurementState::STATE_GAL_E1BC_CODE_LOCK;
+ if (in.measurements[i].stateMask & GNSS_MEASUREMENTS_STATE_GAL_E1C_2ND_CODE_LOCK_BIT)
+ out.measurements[i].state |= IGnssMeasurementCallback::GnssMeasurementState::STATE_GAL_E1C_2ND_CODE_LOCK;
+ if (in.measurements[i].stateMask & GNSS_MEASUREMENTS_STATE_GAL_E1B_PAGE_SYNC_BIT)
+ out.measurements[i].state |= IGnssMeasurementCallback::GnssMeasurementState::STATE_GAL_E1B_PAGE_SYNC;
+ if (in.measurements[i].stateMask & GNSS_MEASUREMENTS_STATE_SBAS_SYNC_BIT)
+ out.measurements[i].state |= IGnssMeasurementCallback::GnssMeasurementState::STATE_SBAS_SYNC;
+ if (in.measurements[i].stateMask & GNSS_MEASUREMENTS_STATE_TOW_KNOWN_BIT)
+ out.measurements[i].state |= IGnssMeasurementCallback::GnssMeasurementState::STATE_TOW_KNOWN;
+ if (in.measurements[i].stateMask & GNSS_MEASUREMENTS_STATE_GLO_TOD_KNOWN_BIT)
+ out.measurements[i].state |= IGnssMeasurementCallback::GnssMeasurementState::STATE_GLO_TOD_KNOWN;
+ if (in.measurements[i].stateMask & GNSS_MEASUREMENTS_STATE_2ND_CODE_LOCK_BIT)
+ out.measurements[i].state |= IGnssMeasurementCallback::GnssMeasurementState::STATE_2ND_CODE_LOCK;
+ }
+ convertGnssClock(in.clock, out.clock);
+}
+
+static void convertGnssMeasurementsCodeType(GnssMeasurementsCodeType& in,
+ ::android::hardware::hidl_string& out)
+{
+ switch(in) {
+ case GNSS_MEASUREMENTS_CODE_TYPE_A:
+ out = "A";
+ break;
+ case GNSS_MEASUREMENTS_CODE_TYPE_B:
+ out = "B";
+ break;
+ case GNSS_MEASUREMENTS_CODE_TYPE_C:
+ out = "C";
+ break;
+ case GNSS_MEASUREMENTS_CODE_TYPE_I:
+ out = "I";
+ break;
+ case GNSS_MEASUREMENTS_CODE_TYPE_L:
+ out = "L";
+ break;
+ case GNSS_MEASUREMENTS_CODE_TYPE_M:
+ out = "M";
+ break;
+ case GNSS_MEASUREMENTS_CODE_TYPE_P:
+ out = "P";
+ break;
+ case GNSS_MEASUREMENTS_CODE_TYPE_Q:
+ out = "Q";
+ break;
+ case GNSS_MEASUREMENTS_CODE_TYPE_S:
+ out = "S";
+ break;
+ case GNSS_MEASUREMENTS_CODE_TYPE_W:
+ out = "W";
+ break;
+ case GNSS_MEASUREMENTS_CODE_TYPE_X:
+ out = "X";
+ break;
+ case GNSS_MEASUREMENTS_CODE_TYPE_Y:
+ out = "Y";
+ break;
+ case GNSS_MEASUREMENTS_CODE_TYPE_Z:
+ out = "Z";
+ break;
+ case GNSS_MEASUREMENTS_CODE_TYPE_N:
+ out = "N";
+ break;
+ default:
+ out = "UNKNOWN";
+ }
+}
+
+} // namespace implementation
+} // namespace V2_0
+} // namespace gnss
+} // namespace hardware
+} // namespace android
diff --git a/android/2.0/location_api/MeasurementAPIClient.h b/android/2.0/location_api/MeasurementAPIClient.h
new file mode 100644
index 0000000..4146a13
--- /dev/null
+++ b/android/2.0/location_api/MeasurementAPIClient.h
@@ -0,0 +1,89 @@
+/* Copyright (c) 2017-2019, 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 MEASUREMENT_API_CLINET_H
+#define MEASUREMENT_API_CLINET_H
+
+#include <mutex>
+#include <android/hardware/gnss/2.0/IGnssMeasurement.h>
+//#include <android/hardware/gnss/1.1/IGnssMeasurementCallback.h>
+#include <LocationAPIClientBase.h>
+#include <hidl/Status.h>
+#include <gps_extended_c.h>
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace V2_0 {
+namespace implementation {
+
+using ::android::sp;
+
+class MeasurementAPIClient : public LocationAPIClientBase
+{
+public:
+ MeasurementAPIClient();
+ virtual ~MeasurementAPIClient();
+ MeasurementAPIClient(const MeasurementAPIClient&) = delete;
+ MeasurementAPIClient& operator=(const MeasurementAPIClient&) = delete;
+
+ // for GpsMeasurementInterface
+ Return<V1_0::IGnssMeasurement::GnssMeasurementStatus> measurementSetCallback(
+ const sp<V1_0::IGnssMeasurementCallback>& callback);
+ Return<V1_0::IGnssMeasurement::GnssMeasurementStatus> measurementSetCallback_1_1(
+ const sp<V1_1::IGnssMeasurementCallback>& callback,
+ GnssPowerMode powerMode = GNSS_POWER_MODE_INVALID,
+ uint32_t timeBetweenMeasurement = GPS_DEFAULT_FIX_INTERVAL_MS);
+ Return<V1_0::IGnssMeasurement::GnssMeasurementStatus> measurementSetCallback_2_0(
+ const sp<V2_0::IGnssMeasurementCallback>& callback,
+ GnssPowerMode powerMode = GNSS_POWER_MODE_INVALID,
+ uint32_t timeBetweenMeasurement = GPS_DEFAULT_FIX_INTERVAL_MS);
+ void measurementClose();
+ Return<IGnssMeasurement::GnssMeasurementStatus> startTracking(
+ GnssPowerMode powerMode = GNSS_POWER_MODE_INVALID,
+ uint32_t timeBetweenMeasurement = GPS_DEFAULT_FIX_INTERVAL_MS);
+
+ // callbacks we are interested in
+ void onGnssMeasurementsCb(GnssMeasurementsNotification gnssMeasurementsNotification) final;
+
+private:
+ std::mutex mMutex;
+ sp<V1_0::IGnssMeasurementCallback> mGnssMeasurementCbIface;
+ sp<V1_1::IGnssMeasurementCallback> mGnssMeasurementCbIface_1_1;
+ sp<V2_0::IGnssMeasurementCallback> mGnssMeasurementCbIface_2_0;
+
+ bool mTracking;
+};
+
+} // namespace implementation
+} // namespace V2_0
+} // namespace gnss
+} // namespace hardware
+} // namespace android
+#endif // MEASUREMENT_API_CLINET_H
diff --git a/android/2.0/service.cpp b/android/2.0/service.cpp
new file mode 100644
index 0000000..664c661
--- /dev/null
+++ b/android/2.0/service.cpp
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved.
+ * Not a Contribution
+ */
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "android.hardware.gnss@2.0-service-qti"
+
+#include <android/hardware/gnss/2.0/IGnss.h>
+#include <hidl/LegacySupport.h>
+#include "loc_cfg.h"
+#include "loc_misc_utils.h"
+
+extern "C" {
+#include "vndfwk-detect.h"
+}
+
+#ifdef ARCH_ARM_32
+#define DEFAULT_HW_BINDER_MEM_SIZE 65536
+#endif
+
+using android::hardware::gnss::V2_0::IGnss;
+
+using android::hardware::configureRpcThreadpool;
+using android::hardware::registerPassthroughServiceImplementation;
+using android::hardware::joinRpcThreadpool;
+
+using android::status_t;
+using android::OK;
+
+typedef int vendorEnhancedServiceMain(int /* argc */, char* /* argv */ []);
+
+int main() {
+
+ ALOGI("%s", __FUNCTION__);
+
+ int vendorInfo = getVendorEnhancedInfo();
+ bool vendorEnhanced = ( 1 == vendorInfo || 3 == vendorInfo );
+ setVendorEnhanced(vendorEnhanced);
+
+#ifdef ARCH_ARM_32
+ android::hardware::ProcessState::initWithMmapSize((size_t)(DEFAULT_HW_BINDER_MEM_SIZE));
+#endif
+ configureRpcThreadpool(1, true);
+ status_t status;
+
+ status = registerPassthroughServiceImplementation<IGnss>();
+ if (status == OK) {
+ if (vendorEnhanced) {
+ #ifdef LOC_HIDL_VERSION
+ #define VENDOR_ENHANCED_LIB "vendor.qti.gnss@" LOC_HIDL_VERSION "-service.so"
+
+ void* libHandle = NULL;
+ vendorEnhancedServiceMain* vendorEnhancedMainMethod = (vendorEnhancedServiceMain*)
+ dlGetSymFromLib(libHandle, VENDOR_ENHANCED_LIB, "main");
+ if (NULL != vendorEnhancedMainMethod) {
+ (*vendorEnhancedMainMethod)(0, NULL);
+ }
+ #else
+ ALOGE("LOC_HIDL_VERSION not defined.");
+ #endif
+ }
+
+ joinRpcThreadpool();
+
+ } else {
+ ALOGE("Error while registering IGnss 2.0 service: %d", status);
+ }
+
+ return 0;
+}
diff --git a/android/Android.mk b/android/Android.mk
new file mode 100644
index 0000000..3b5c01f
--- /dev/null
+++ b/android/Android.mk
@@ -0,0 +1,15 @@
+LOCAL_PATH := $(call my-dir)
+ifneq ($(BOARD_VENDOR_QCOM_GPS_LOC_API_HARDWARE),)
+include $(CLEAR_VARS)
+DIR_LIST := $(LOCAL_PATH)
+include $(DIR_LIST)/utils/Android.mk
+ifeq ($(GNSS_HIDL_VERSION),2.0)
+include $(DIR_LIST)/2.0/Android.mk
+else
+ifeq ($(GNSS_HIDL_VERSION),1.1)
+include $(DIR_LIST)/1.1/Android.mk
+else
+include $(DIR_LIST)/1.0/Android.mk
+endif #GNSS HIDL 1.1
+endif #GNSS HIDL 2.0
+endif #BOARD_VENDOR_QCOM_GPS_LOC_API_HARDWARE
diff --git a/android/measurement_corrections/1.0/MeasurementCorrections.cpp b/android/measurement_corrections/1.0/MeasurementCorrections.cpp
new file mode 100644
index 0000000..2c93cb3
--- /dev/null
+++ b/android/measurement_corrections/1.0/MeasurementCorrections.cpp
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2019, 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_MeasurementCorrectionsInterface"
+
+#include <log_util.h>
+#include "MeasurementCorrections.h"
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace measurement_corrections {
+namespace V1_0 {
+namespace implementation {
+
+using ::android::hardware::hidl_array;
+using ::android::hardware::hidl_memory;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::sp;
+using ::android::hardware::gnss::V1_0::GnssLocation;
+
+MeasurementCorrections::MeasurementCorrections() {
+}
+
+MeasurementCorrections::~MeasurementCorrections() {
+}
+
+Return<bool> MeasurementCorrections::setCorrections(const ::android::hardware::gnss::measurement_corrections::V1_0::MeasurementCorrections& /*corrections*/) {
+ return true;
+}
+
+Return<bool> MeasurementCorrections::setCallback(
+ const sp<V1_0::IMeasurementCorrectionsCallback>& /*callback*/) {
+ return true;
+}
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace measurement_corrections
+} // namespace gnss
+} // namespace hardware
+} // namespace android
diff --git a/android/measurement_corrections/1.0/MeasurementCorrections.h b/android/measurement_corrections/1.0/MeasurementCorrections.h
new file mode 100644
index 0000000..ad534dc
--- /dev/null
+++ b/android/measurement_corrections/1.0/MeasurementCorrections.h
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2019, 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 ANDROID_HARDWARE_GNSS_V1_0_MeasurementCorrections_H
+#define ANDROID_HARDWARE_GNSS_V1_0_MeasurementCorrections_H
+
+#include <android/hardware/gnss/measurement_corrections/1.0/IMeasurementCorrections.h>
+#include <android/hardware/gnss/measurement_corrections/1.0/IMeasurementCorrectionsCallback.h>
+#include <hidl/MQDescriptor.h>
+#include <hidl/Status.h>
+
+#include <location_interface.h>
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace measurement_corrections {
+namespace V1_0 {
+namespace implementation {
+
+using ::android::hardware::hidl_array;
+using ::android::hardware::hidl_memory;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::sp;
+using ::android::hardware::gnss::V1_0::GnssLocation;
+using ::android::hardware::gnss::measurement_corrections::V1_0::IMeasurementCorrectionsCallback;
+
+struct MeasurementCorrections : public IMeasurementCorrections {
+ MeasurementCorrections();
+ ~MeasurementCorrections();
+
+// Methods from ::android::hardware::gnss::measurement_corrections::V1_0::IMeasurementCorrections follow.
+Return<bool> setCorrections(const ::android::hardware::gnss::measurement_corrections::V1_0::MeasurementCorrections& corrections) override;
+
+Return<bool> setCallback(const sp<IMeasurementCorrectionsCallback>& callback) override;
+
+};
+
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace measurement_corrections
+} // namespace gnss
+} // namespace hardware
+} // namespace android
+
+#endif // ANDROID_HARDWARE_GNSS_V1_0_MeasurementCorrections_H
diff --git a/android/utils/Android.mk b/android/utils/Android.mk
new file mode 100644
index 0000000..47b4081
--- /dev/null
+++ b/android/utils/Android.mk
@@ -0,0 +1,37 @@
+LOCAL_PATH := $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := liblocbatterylistener
+LOCAL_VENDOR_MODULE := true
+
+LOCAL_CFLAGS += $(GNSS_CFLAGS)
+
+LOCAL_C_INCLUDES += \
+ $(LOCAL_PATH) \
+
+LOCAL_SRC_FILES:= \
+ battery_listener.cpp
+LOCAL_SHARED_LIBRARIES := \
+ liblog \
+ libhidlbase \
+ libhidltransport \
+ libhwbinder \
+ libcutils \
+ libutils \
+ android.hardware.health@1.0 \
+ android.hardware.health@2.0 \
+ android.hardware.power@1.2 \
+ libbase
+
+LOCAL_STATIC_LIBRARIES := libhealthhalutils
+LOCAL_CFLAGS += -DBATTERY_LISTENER_ENABLED
+
+include $(BUILD_STATIC_LIBRARY)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := liblocbatterylistener_headers
+LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)
+
+include $(BUILD_HEADER_LIBRARY)
+
+
diff --git a/android/utils/battery_listener.cpp b/android/utils/battery_listener.cpp
new file mode 100644
index 0000000..a790702
--- /dev/null
+++ b/android/utils/battery_listener.cpp
@@ -0,0 +1,266 @@
+/*
+* Copyright (c) 2019, 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.
+*/
+#include "battery_listener.h"
+#ifdef LOG_TAG
+#undef LOG_TAG
+#endif
+#define LOG_TAG "LocSvc_BatteryListener"
+
+#include <android/hidl/manager/1.0/IServiceManager.h>
+#include <android/hardware/health/2.0/IHealth.h>
+#include <healthhalutils/HealthHalUtils.h>
+#include <hidl/HidlTransportSupport.h>
+#include <thread>
+using android::hardware::interfacesEqual;
+using android::hardware::Return;
+using android::hardware::Void;
+using android::hardware::health::V1_0::BatteryStatus;
+using android::hardware::health::V1_0::toString;
+using android::hardware::health::V2_0::get_health_service;
+using android::hardware::health::V2_0::HealthInfo;
+using android::hardware::health::V2_0::IHealth;
+using android::hardware::health::V2_0::Result;
+using android::hidl::manager::V1_0::IServiceManager;
+using namespace std::literals::chrono_literals;
+
+static bool sIsBatteryListened = false;
+namespace android {
+
+#define GET_HEALTH_SVC_RETRY_CNT 5
+#define GET_HEALTH_SVC_WAIT_TIME_MS 500
+
+struct BatteryListenerImpl : public hardware::health::V2_0::IHealthInfoCallback,
+ public hardware::hidl_death_recipient {
+ typedef std::function<void(bool)> cb_fn_t;
+ BatteryListenerImpl(cb_fn_t cb);
+ virtual ~BatteryListenerImpl ();
+ virtual hardware::Return<void> healthInfoChanged(
+ const hardware::health::V2_0::HealthInfo& info);
+ virtual void serviceDied(uint64_t cookie,
+ const wp<hidl::base::V1_0::IBase>& who);
+ bool isCharging() {
+ std::lock_guard<std::mutex> _l(mLock);
+ return statusToBool(mStatus);
+ }
+ private:
+ sp<hardware::health::V2_0::IHealth> mHealth;
+ status_t init();
+ BatteryStatus mStatus;
+ cb_fn_t mCb;
+ std::mutex mLock;
+ std::condition_variable mCond;
+ std::unique_ptr<std::thread> mThread;
+ bool mDone;
+ bool statusToBool(const BatteryStatus &s) const {
+ return (s == BatteryStatus::CHARGING) ||
+ (s == BatteryStatus::FULL);
+ }
+};
+
+status_t BatteryListenerImpl::init()
+{
+ int tries = 0;
+
+ if (mHealth != NULL)
+ return INVALID_OPERATION;
+
+ do {
+ mHealth = hardware::health::V2_0::get_health_service();
+ if (mHealth != NULL)
+ break;
+ usleep(GET_HEALTH_SVC_WAIT_TIME_MS * 1000);
+ tries++;
+ } while(tries < GET_HEALTH_SVC_RETRY_CNT);
+
+ if (mHealth == NULL) {
+ ALOGE("no health service found, retries %d", tries);
+ return NO_INIT;
+ } else {
+ ALOGI("Get health service in %d tries", tries);
+ }
+ mStatus = BatteryStatus::UNKNOWN;
+ auto ret = mHealth->getChargeStatus([&](Result r, BatteryStatus status) {
+ if (r != Result::SUCCESS) {
+ ALOGE("batterylistener: cannot get battery status");
+ return;
+ }
+ mStatus = status;
+ });
+ if (!ret.isOk())
+ ALOGE("batterylistener: get charge status transaction error");
+
+ if (mStatus == BatteryStatus::UNKNOWN)
+ ALOGW("batterylistener: init: invalid battery status");
+ mDone = false;
+ mThread = std::make_unique<std::thread>([this]() {
+ std::unique_lock<std::mutex> l(mLock);
+ BatteryStatus local_status = mStatus;
+ while (!mDone) {
+ if (local_status == mStatus) {
+ mCond.wait(l);
+ continue;
+ }
+ local_status = mStatus;
+ switch (local_status) {
+ // NOT_CHARGING is a special event that indicates, a battery is connected,
+ // but not charging. This is seen for approx a second
+ // after charger is plugged in. A charging event is eventually received.
+ // We must try to avoid an unnecessary cb to HAL
+ // only to call it again shortly.
+ // An option to deal with this transient event would be to ignore this.
+ // Or process this event with a slight delay (i.e cancel this event
+ // if a different event comes in within a timeout
+ case BatteryStatus::NOT_CHARGING : {
+ auto mStatusnot_ncharging =
+ [this, local_status]() { return mStatus != local_status; };
+ mCond.wait_for(l, 3s, mStatusnot_ncharging);
+ if (mStatusnot_ncharging()) // i.e event changed
+ break;
+ [[clang::fallthrough]]; //explicit fall-through between switch labels
+ }
+ default:
+ bool c = statusToBool(local_status);
+ ALOGI("healthInfo cb thread: cb %s", c ? "CHARGING" : "NOT CHARGING");
+ l.unlock();
+ mCb(c);
+ l.lock();
+ break;
+ }
+ }
+ });
+ auto reg = mHealth->registerCallback(this);
+ if (!reg.isOk()) {
+ ALOGE("Transaction error in registeringCb to HealthHAL death: %s",
+ reg.description().c_str());
+ }
+
+ auto linked = mHealth->linkToDeath(this, 0 /* cookie */);
+ if (!linked.isOk() || linked == false) {
+ ALOGE("Transaction error in linking to HealthHAL death: %s", linked.description().c_str());
+ }
+ return NO_ERROR;
+}
+
+BatteryListenerImpl::BatteryListenerImpl(cb_fn_t cb) :
+ mCb(cb)
+{
+ init();
+}
+
+BatteryListenerImpl::~BatteryListenerImpl()
+{
+ {
+ std::lock_guard<std::mutex> _l(mLock);
+ if (mHealth != NULL)
+ mHealth->unlinkToDeath(this);
+ auto r = mHealth->unlinkToDeath(this);
+ if (!r.isOk() || r == false) {
+ ALOGE("Transaction error in unregister to HealthHAL death: %s",
+ r.description().c_str());
+ }
+ }
+ mDone = true;
+ mThread->join();
+}
+
+void BatteryListenerImpl::serviceDied(uint64_t cookie __unused,
+ const wp<hidl::base::V1_0::IBase>& who)
+{
+ {
+ std::lock_guard<std::mutex> _l(mLock);
+ if (mHealth == NULL || !interfacesEqual(mHealth, who.promote())) {
+ ALOGE("health not initialized or unknown interface died");
+ return;
+ }
+ ALOGI("health service died, reinit");
+ mDone = true;
+ }
+ mThread->join();
+ std::lock_guard<std::mutex> _l(mLock);
+ init();
+}
+
+// this callback seems to be a SYNC callback and so
+// waits for return before next event is issued.
+// therefore we need not have a queue to process
+// NOT_CHARGING and CHARGING concurrencies.
+// Replace single var by a list if this assumption is broken
+Return<void> BatteryListenerImpl::healthInfoChanged(
+ const hardware::health::V2_0::HealthInfo& info)
+{
+ ALOGV("healthInfoChanged: %d", info.legacy.batteryStatus);
+ std::unique_lock<std::mutex> l(mLock);
+ if (info.legacy.batteryStatus != mStatus) {
+ mStatus = info.legacy.batteryStatus;
+ mCond.notify_one();
+ }
+ return Void();
+}
+
+static sp<BatteryListenerImpl> batteryListener;
+status_t batteryPropertiesListenerInit(BatteryListenerImpl::cb_fn_t cb)
+{
+ ALOGV("batteryPropertiesListenerInit entry");
+ batteryListener = new BatteryListenerImpl(cb);
+ return NO_ERROR;
+}
+
+status_t batteryPropertiesListenerDeinit()
+{
+ batteryListener.clear();
+ return OK;
+}
+
+bool batteryPropertiesListenerIsCharging()
+{
+ return batteryListener->isCharging();
+}
+
+} // namespace android
+
+void loc_extn_battery_properties_listener_init(battery_status_change_fn_t fn)
+{
+ ALOGV("loc_extn_battery_properties_listener_init entry");
+ if (!sIsBatteryListened) {
+ std::thread t1(android::batteryPropertiesListenerInit,
+ [=](bool charging) { fn(charging); });
+ t1.detach();
+ sIsBatteryListened = true;
+ }
+}
+
+void loc_extn_battery_properties_listener_deinit()
+{
+ android::batteryPropertiesListenerDeinit();
+}
+
+bool loc_extn_battery_properties_is_charging()
+{
+ return android::batteryPropertiesListenerIsCharging();
+}
diff --git a/android/utils/battery_listener.h b/android/utils/battery_listener.h
new file mode 100644
index 0000000..bb6b715
--- /dev/null
+++ b/android/utils/battery_listener.h
@@ -0,0 +1,32 @@
+/*
+* Copyright (c) 2019, 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.
+*/
+typedef void (* battery_status_change_fn_t)(bool);
+void loc_extn_battery_properties_listener_init(battery_status_change_fn_t fn);
+void loc_extn_battery_properties_listener_deinit();
+bool loc_extn_battery_properties_is_charging();
diff --git a/android/visibility_control/1.0/GnssVisibilityControl.cpp b/android/visibility_control/1.0/GnssVisibilityControl.cpp
new file mode 100644
index 0000000..5a8c697
--- /dev/null
+++ b/android/visibility_control/1.0/GnssVisibilityControl.cpp
@@ -0,0 +1,169 @@
+/*
+ * Copyright (c) 2019, 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.
+ */
+
+#include <android/hardware/gnss/visibility_control/1.0/IGnssVisibilityControl.h>
+#include <hidl/MQDescriptor.h>
+#include <hidl/Status.h>
+#include "GnssVisibilityControl.h"
+#include <location_interface.h>
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace visibility_control {
+namespace V1_0 {
+namespace implementation {
+
+using ::android::hardware::hidl_array;
+using ::android::hardware::hidl_memory;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::sp;
+
+static GnssVisibilityControl* spGnssVisibilityControl = nullptr;
+
+static void convertGnssNfwNotification(GnssNfwNotification& in,
+ IGnssVisibilityControlCallback::NfwNotification& out);
+
+GnssVisibilityControl::GnssVisibilityControl(Gnss* gnss) : mGnss(gnss) {
+ spGnssVisibilityControl = this;
+}
+GnssVisibilityControl::~GnssVisibilityControl() {
+ spGnssVisibilityControl = nullptr;
+}
+
+void GnssVisibilityControl::nfwStatusCb(GnssNfwNotification notification) {
+ if (nullptr != spGnssVisibilityControl) {
+ spGnssVisibilityControl->statusCb(notification);
+ }
+}
+
+bool GnssVisibilityControl::isInEmergencySession() {
+ if (nullptr != spGnssVisibilityControl) {
+ return spGnssVisibilityControl->isE911Session();
+ }
+ return false;
+}
+
+static void convertGnssNfwNotification(GnssNfwNotification& in,
+ IGnssVisibilityControlCallback::NfwNotification& out)
+{
+ memset(&out, 0, sizeof(IGnssVisibilityControlCallback::NfwNotification));
+ out.proxyAppPackageName = in.proxyAppPackageName;
+ out.protocolStack = (IGnssVisibilityControlCallback::NfwProtocolStack)in.protocolStack;
+ out.otherProtocolStackName = in.otherProtocolStackName;
+ out.requestor = (IGnssVisibilityControlCallback::NfwRequestor)in.requestor;
+ out.requestorId = in.requestorId;
+ out.responseType = (IGnssVisibilityControlCallback::NfwResponseType)in.responseType;
+ out.inEmergencyMode = in.inEmergencyMode;
+ out.isCachedLocation = in.isCachedLocation;
+}
+
+void GnssVisibilityControl::statusCb(GnssNfwNotification notification) {
+
+ if (mGnssVisibilityControlCbIface != nullptr) {
+ IGnssVisibilityControlCallback::NfwNotification nfwNotification;
+
+ // Convert from one structure to another
+ convertGnssNfwNotification(notification, nfwNotification);
+
+ auto r = mGnssVisibilityControlCbIface->nfwNotifyCb(nfwNotification);
+ if (!r.isOk()) {
+ LOC_LOGw("Error invoking NFW status cb %s", r.description().c_str());
+ }
+ } else {
+ LOC_LOGw("setCallback has not been called yet");
+ }
+}
+
+bool GnssVisibilityControl::isE911Session() {
+
+ if (mGnssVisibilityControlCbIface != nullptr) {
+ auto r = mGnssVisibilityControlCbIface->isInEmergencySession();
+ if (!r.isOk()) {
+ LOC_LOGw("Error invoking NFW status cb %s", r.description().c_str());
+ return false;
+ } else {
+ return (r);
+ }
+ } else {
+ LOC_LOGw("setCallback has not been called yet");
+ return false;
+ }
+}
+
+// Methods from ::android::hardware::gnss::visibility_control::V1_0::IGnssVisibilityControl follow.
+Return<bool> GnssVisibilityControl::enableNfwLocationAccess(const hidl_vec<::android::hardware::hidl_string>& proxyApps) {
+
+ if (nullptr == mGnss || nullptr == mGnss->getGnssInterface()) {
+ LOC_LOGe("Null GNSS interface");
+ return false;
+ }
+
+ /* If the vector is empty we need to disable all NFW clients
+ If there is at least one app in the vector we need to enable
+ all NFW clients */
+ if (0 == proxyApps.size()) {
+ mGnss->getGnssInterface()->enableNfwLocationAccess(false);
+ } else {
+ mGnss->getGnssInterface()->enableNfwLocationAccess(true);
+ }
+
+ return true;
+}
+/**
+ * Registers the callback for HAL implementation to use.
+ *
+ * @param callback Handle to IGnssVisibilityControlCallback interface.
+ */
+Return<bool> GnssVisibilityControl::setCallback(const ::android::sp<::android::hardware::gnss::visibility_control::V1_0::IGnssVisibilityControlCallback>& callback) {
+
+ if (nullptr == mGnss || nullptr == mGnss->getGnssInterface()) {
+ LOC_LOGe("Null GNSS interface");
+ return false;
+ }
+ mGnssVisibilityControlCbIface = callback;
+
+ NfwCbInfo cbInfo = {};
+ cbInfo.visibilityControlCb = (void*)nfwStatusCb;
+ cbInfo.isInEmergencySession = (void*)isInEmergencySession;
+
+ mGnss->getGnssInterface()->nfwInit(cbInfo);
+
+ return true;
+}
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace visibility_control
+} // namespace gnss
+} // namespace hardware
+} // namespace android
diff --git a/android/visibility_control/1.0/GnssVisibilityControl.h b/android/visibility_control/1.0/GnssVisibilityControl.h
new file mode 100644
index 0000000..9c26e38
--- /dev/null
+++ b/android/visibility_control/1.0/GnssVisibilityControl.h
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 2019, 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 ANDROID_HARDWARE_GNSS_V1_0_GnssVisibilityControl_H
+#define ANDROID_HARDWARE_GNSS_V1_0_GnssVisibilityControl_H
+
+#include <android/hardware/gnss/visibility_control/1.0/IGnssVisibilityControl.h>
+#include <hidl/MQDescriptor.h>
+#include <hidl/Status.h>
+
+#include <gps_extended_c.h>
+#include <location_interface.h>
+#include "Gnss.h"
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace visibility_control {
+namespace V1_0 {
+namespace implementation {
+
+using ::android::hardware::hidl_array;
+using ::android::hardware::hidl_memory;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::sp;
+using ::android::hardware::gnss::V2_0::implementation::Gnss;
+
+struct GnssVisibilityControl : public IGnssVisibilityControl {
+ GnssVisibilityControl(Gnss* gnss);
+ ~GnssVisibilityControl();
+
+ // Methods from ::android::hardware::gnss::visibility_control::V1_0::IGnssVisibilityControl follow.
+ Return<bool> enableNfwLocationAccess(const hidl_vec<::android::hardware::hidl_string>& proxyApps) override;
+ /**
+ * Registers the callback for HAL implementation to use.
+ *
+ * @param callback Handle to IGnssVisibilityControlCallback interface.
+ */
+ Return<bool> setCallback(const ::android::sp<::android::hardware::gnss::visibility_control::V1_0::IGnssVisibilityControlCallback>& callback) override;
+
+ void statusCb(GnssNfwNotification notification);
+ bool isE911Session();
+
+ /* Data call setup callback passed down to GNSS HAL implementation */
+ static void nfwStatusCb(GnssNfwNotification notification);
+ static bool isInEmergencySession();
+
+private:
+ Gnss* mGnss = nullptr;
+ sp<IGnssVisibilityControlCallback> mGnssVisibilityControlCbIface = nullptr;
+};
+
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace visibility_control
+} // namespace gnss
+} // namespace hardware
+} // namespace android
+
+#endif // ANDROID_HARDWARE_GNSS_V1_0_GnssVisibilityControl_H
diff --git a/batching/Android.mk b/batching/Android.mk
new file mode 100644
index 0000000..b08d155
--- /dev/null
+++ b/batching/Android.mk
@@ -0,0 +1,37 @@
+ifneq ($(BOARD_VENDOR_QCOM_GPS_LOC_API_HARDWARE),)
+ifneq ($(BUILD_TINY_ANDROID),true)
+
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := libbatching
+LOCAL_VENDOR_MODULE := true
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_SHARED_LIBRARIES := \
+ libutils \
+ libcutils \
+ liblog \
+ libloc_core \
+ libgps.utils \
+ libdl \
+ liblbs_core
+
+LOCAL_SRC_FILES += \
+ location_batching.cpp \
+ BatchingAdapter.cpp
+
+LOCAL_HEADER_LIBRARIES := \
+ libgps.utils_headers \
+ libloc_core_headers \
+ libloc_pla_headers \
+ liblocation_api_headers
+
+LOCAL_PRELINK_MODULE := false
+
+LOCAL_CFLAGS += $(GNSS_CFLAGS)
+include $(BUILD_SHARED_LIBRARY)
+
+endif # not BUILD_TINY_ANDROID
+endif # BOARD_VENDOR_QCOM_GPS_LOC_API_HARDWARE
diff --git a/batching/BatchingAdapter.cpp b/batching/BatchingAdapter.cpp
new file mode 100644
index 0000000..135f0ed
--- /dev/null
+++ b/batching/BatchingAdapter.cpp
@@ -0,0 +1,1050 @@
+/* Copyright (c) 2017-2019, 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_NDEBUG 0
+#define LOG_TAG "LocSvc_BatchingAdapter"
+
+#include <loc_pla.h>
+#include <log_util.h>
+#include <LocContext.h>
+#include <BatchingAdapter.h>
+
+using namespace loc_core;
+
+BatchingAdapter::BatchingAdapter() :
+ LocAdapterBase(0,
+ LocContext::getLocContext(
+ NULL,
+ NULL,
+ LocContext::mLocationHalName,
+ false)),
+ mOngoingTripDistance(0),
+ mOngoingTripTBFInterval(0),
+ mTripWithOngoingTBFDropped(false),
+ mTripWithOngoingTripDistanceDropped(false),
+ mBatchingTimeout(0),
+ mBatchingAccuracy(1),
+ mBatchSize(0),
+ mTripBatchSize(0)
+{
+ LOC_LOGD("%s]: Constructor", __func__);
+ readConfigCommand();
+ setConfigCommand();
+}
+
+void
+BatchingAdapter::readConfigCommand()
+{
+ LOC_LOGD("%s]: ", __func__);
+
+ struct MsgReadConfig : public LocMsg {
+ BatchingAdapter& mAdapter;
+ inline MsgReadConfig(BatchingAdapter& adapter) :
+ LocMsg(),
+ mAdapter(adapter) {}
+ inline virtual void proc() const {
+ uint32_t batchingTimeout = 0;
+ uint32_t batchingAccuracy = 0;
+ uint32_t batchSize = 0;
+ uint32_t tripBatchSize = 0;
+ static const loc_param_s_type flp_conf_param_table[] =
+ {
+ {"BATCH_SIZE", &batchSize, NULL, 'n'},
+ {"OUTDOOR_TRIP_BATCH_SIZE", &tripBatchSize, NULL, 'n'},
+ {"BATCH_SESSION_TIMEOUT", &batchingTimeout, NULL, 'n'},
+ {"ACCURACY", &batchingAccuracy, NULL, 'n'},
+ };
+ UTIL_READ_CONF(LOC_PATH_FLP_CONF, flp_conf_param_table);
+
+ LOC_LOGD("%s]: batchSize %u tripBatchSize %u batchingAccuracy %u batchingTimeout %u ",
+ __func__, batchSize, tripBatchSize, batchingAccuracy, batchingTimeout);
+
+ mAdapter.setBatchSize(batchSize);
+ mAdapter.setTripBatchSize(tripBatchSize);
+ mAdapter.setBatchingTimeout(batchingTimeout);
+ mAdapter.setBatchingAccuracy(batchingAccuracy);
+ }
+ };
+
+ sendMsg(new MsgReadConfig(*this));
+
+}
+
+void
+BatchingAdapter::setConfigCommand()
+{
+ LOC_LOGD("%s]: ", __func__);
+
+ struct MsgSetConfig : public LocMsg {
+ BatchingAdapter& mAdapter;
+ LocApiBase& mApi;
+ inline MsgSetConfig(BatchingAdapter& adapter,
+ LocApiBase& api) :
+ LocMsg(),
+ mAdapter(adapter),
+ mApi(api) {}
+ inline virtual void proc() const {
+ mApi.setBatchSize(mAdapter.getBatchSize());
+ mApi.setTripBatchSize(mAdapter.getTripBatchSize());
+ }
+ };
+
+ sendMsg(new MsgSetConfig(*this, *mLocApi));
+}
+
+void
+BatchingAdapter::stopClientSessions(LocationAPI* client)
+{
+ LOC_LOGD("%s]: client %p", __func__, client);
+
+ typedef struct pairKeyBatchMode {
+ LocationAPI* client;
+ uint32_t id;
+ BatchingMode batchingMode;
+ inline pairKeyBatchMode(LocationAPI* _client, uint32_t _id, BatchingMode _bMode) :
+ client(_client), id(_id), batchingMode(_bMode) {}
+ } pairKeyBatchMode;
+ std::vector<pairKeyBatchMode> vBatchingClient;
+ for (auto it : mBatchingSessions) {
+ if (client == it.first.client) {
+ vBatchingClient.emplace_back(it.first.client, it.first.id, it.second.batchingMode);
+ }
+ }
+ for (auto keyBatchingMode : vBatchingClient) {
+ if (keyBatchingMode.batchingMode != BATCHING_MODE_TRIP) {
+ stopBatching(keyBatchingMode.client, keyBatchingMode.id);
+ } else {
+ stopTripBatchingMultiplex(keyBatchingMode.client, keyBatchingMode.id);
+ }
+ }
+}
+
+void
+BatchingAdapter::updateClientsEventMask()
+{
+ LOC_API_ADAPTER_EVENT_MASK_T mask = 0;
+ for (auto it=mClientData.begin(); it != mClientData.end(); ++it) {
+ // we don't register LOC_API_ADAPTER_BIT_BATCH_FULL until we
+ // start batching with ROUTINE or TRIP option
+ if (it->second.batchingCb != nullptr) {
+ mask |= LOC_API_ADAPTER_BIT_BATCH_STATUS;
+ }
+ }
+ if (autoReportBatchingSessionsCount() > 0) {
+ mask |= LOC_API_ADAPTER_BIT_BATCH_FULL;
+ }
+ updateEvtMask(mask, LOC_REGISTRATION_MASK_SET);
+}
+
+void
+BatchingAdapter::handleEngineUpEvent()
+{
+ struct MsgSSREvent : public LocMsg {
+ BatchingAdapter& mAdapter;
+ LocApiBase& mApi;
+ inline MsgSSREvent(BatchingAdapter& adapter,
+ LocApiBase& api) :
+ LocMsg(),
+ mAdapter(adapter),
+ mApi(api) {}
+ virtual void proc() const {
+ mAdapter.setEngineCapabilitiesKnown(true);
+ mAdapter.broadcastCapabilities(mAdapter.getCapabilities());
+ mApi.setBatchSize(mAdapter.getBatchSize());
+ mApi.setTripBatchSize(mAdapter.getTripBatchSize());
+ mAdapter.restartSessions();
+ for (auto msg: mAdapter.mPendingMsgs) {
+ mAdapter.sendMsg(msg);
+ }
+ mAdapter.mPendingMsgs.clear();
+ }
+ };
+
+ sendMsg(new MsgSSREvent(*this, *mLocApi));
+}
+
+void
+BatchingAdapter::restartSessions()
+{
+ LOC_LOGD("%s]: ", __func__);
+
+ if (autoReportBatchingSessionsCount() > 0) {
+ updateEvtMask(LOC_API_ADAPTER_BIT_BATCH_FULL,
+ LOC_REGISTRATION_MASK_ENABLED);
+ }
+ for (auto it = mBatchingSessions.begin();
+ it != mBatchingSessions.end(); ++it) {
+ if (it->second.batchingMode != BATCHING_MODE_TRIP) {
+ mLocApi->startBatching(it->first.id, it->second,
+ getBatchingAccuracy(), getBatchingTimeout(),
+ new LocApiResponse(*getContext(),
+ [] (LocationError /*err*/) {}));
+ }
+ }
+
+ if (mTripSessions.size() > 0) {
+ // restart outdoor trip batching session if any.
+ mOngoingTripDistance = 0;
+ mOngoingTripTBFInterval = 0;
+
+ // record the min trip distance and min tbf interval of all ongoing sessions
+ for (auto tripSession : mTripSessions) {
+
+ TripSessionStatus &tripSessStatus = tripSession.second;
+
+ if ((0 == mOngoingTripDistance) ||
+ (mOngoingTripDistance >
+ (tripSessStatus.tripDistance - tripSessStatus.accumulatedDistanceThisTrip))) {
+ mOngoingTripDistance = tripSessStatus.tripDistance -
+ tripSessStatus.accumulatedDistanceThisTrip;
+ }
+
+ if ((0 == mOngoingTripTBFInterval) ||
+ (mOngoingTripTBFInterval > tripSessStatus.tripTBFInterval)) {
+ mOngoingTripTBFInterval = tripSessStatus.tripTBFInterval;
+ }
+
+ // reset the accumulatedDistanceOngoingBatch for each session
+ tripSessStatus.accumulatedDistanceOngoingBatch = 0;
+
+ }
+
+ mLocApi->startOutdoorTripBatching(mOngoingTripDistance, mOngoingTripTBFInterval,
+ getBatchingTimeout(), new LocApiResponse(*getContext(), [this] (LocationError err) {
+ if (LOCATION_ERROR_SUCCESS != err) {
+ mOngoingTripDistance = 0;
+ mOngoingTripTBFInterval = 0;
+ }
+ printTripReport();
+ }));
+ }
+}
+
+bool
+BatchingAdapter::hasBatchingCallback(LocationAPI* client)
+{
+ auto it = mClientData.find(client);
+ return (it != mClientData.end() && it->second.batchingCb);
+}
+
+bool
+BatchingAdapter::isBatchingSession(LocationAPI* client, uint32_t sessionId)
+{
+ LocationSessionKey key(client, sessionId);
+ return (mBatchingSessions.find(key) != mBatchingSessions.end());
+}
+
+bool
+BatchingAdapter::isTripSession(uint32_t sessionId) {
+ return (mTripSessions.find(sessionId) != mTripSessions.end());
+}
+
+void
+BatchingAdapter::saveBatchingSession(LocationAPI* client, uint32_t sessionId,
+ const BatchingOptions& batchingOptions)
+{
+ LocationSessionKey key(client, sessionId);
+ mBatchingSessions[key] = batchingOptions;
+}
+
+void
+BatchingAdapter::eraseBatchingSession(LocationAPI* client, uint32_t sessionId)
+{
+ LocationSessionKey key(client, sessionId);
+ auto it = mBatchingSessions.find(key);
+ if (it != mBatchingSessions.end()) {
+ mBatchingSessions.erase(it);
+ }
+}
+
+void
+BatchingAdapter::reportResponse(LocationAPI* client, LocationError err, uint32_t sessionId)
+{
+ LOC_LOGD("%s]: client %p id %u err %u", __func__, client, sessionId, err);
+
+ auto it = mClientData.find(client);
+ if (it != mClientData.end() &&
+ it->second.responseCb != nullptr) {
+ it->second.responseCb(err, sessionId);
+ } else {
+ LOC_LOGE("%s]: client %p id %u not found in data", __func__, client, sessionId);
+ }
+}
+
+uint32_t
+BatchingAdapter::autoReportBatchingSessionsCount()
+{
+ uint32_t count = 0;
+ for (auto batchingSession: mBatchingSessions) {
+ if (batchingSession.second.batchingMode != BATCHING_MODE_NO_AUTO_REPORT) {
+ count++;
+ }
+ }
+ count += mTripSessions.size();
+ return count;
+}
+
+uint32_t
+BatchingAdapter::startBatchingCommand(
+ LocationAPI* client, BatchingOptions& batchOptions)
+{
+ uint32_t sessionId = generateSessionId();
+ LOC_LOGD("%s]: client %p id %u minInterval %u minDistance %u mode %u Batching Mode %d",
+ __func__, client, sessionId, batchOptions.minInterval, batchOptions.minDistance,
+ batchOptions.mode,batchOptions.batchingMode);
+
+ struct MsgStartBatching : public LocMsg {
+ BatchingAdapter& mAdapter;
+ LocApiBase& mApi;
+ LocationAPI* mClient;
+ uint32_t mSessionId;
+ BatchingOptions mBatchingOptions;
+ inline MsgStartBatching(BatchingAdapter& adapter,
+ LocApiBase& api,
+ LocationAPI* client,
+ uint32_t sessionId,
+ BatchingOptions batchOptions) :
+ LocMsg(),
+ mAdapter(adapter),
+ mApi(api),
+ mClient(client),
+ mSessionId(sessionId),
+ mBatchingOptions(batchOptions) {}
+ inline virtual void proc() const {
+ if (!mAdapter.isEngineCapabilitiesKnown()) {
+ mAdapter.mPendingMsgs.push_back(new MsgStartBatching(*this));
+ return;
+ }
+ LocationError err = LOCATION_ERROR_SUCCESS;
+
+ if (!mAdapter.hasBatchingCallback(mClient)) {
+ err = LOCATION_ERROR_CALLBACK_MISSING;
+ } else if (0 == mBatchingOptions.size) {
+ err = LOCATION_ERROR_INVALID_PARAMETER;
+ } else if (!ContextBase::isMessageSupported(
+ LOC_API_ADAPTER_MESSAGE_DISTANCE_BASE_LOCATION_BATCHING)) {
+ err = LOCATION_ERROR_NOT_SUPPORTED;
+ }
+ if (LOCATION_ERROR_SUCCESS == err) {
+ if (mBatchingOptions.batchingMode == BATCHING_MODE_ROUTINE ||
+ mBatchingOptions.batchingMode == BATCHING_MODE_NO_AUTO_REPORT) {
+ mAdapter.startBatching(mClient, mSessionId, mBatchingOptions);
+ } else if (mBatchingOptions.batchingMode == BATCHING_MODE_TRIP) {
+ mAdapter.startTripBatchingMultiplex(mClient, mSessionId, mBatchingOptions);
+ } else {
+ mAdapter.reportResponse(mClient, LOCATION_ERROR_INVALID_PARAMETER, mSessionId);
+ }
+ }
+ }
+ };
+
+ sendMsg(new MsgStartBatching(*this, *mLocApi, client, sessionId, batchOptions));
+
+ return sessionId;
+}
+
+void
+BatchingAdapter::startBatching(LocationAPI* client, uint32_t sessionId,
+ const BatchingOptions& batchingOptions)
+{
+ if (batchingOptions.batchingMode != BATCHING_MODE_NO_AUTO_REPORT &&
+ 0 == autoReportBatchingSessionsCount()) {
+ // if there is currenty no batching sessions interested in batch full event, then this
+ // new session will need to register for batch full event
+ updateEvtMask(LOC_API_ADAPTER_BIT_BATCH_FULL,
+ LOC_REGISTRATION_MASK_ENABLED);
+ }
+
+ // Assume start will be OK, remove session if not
+ saveBatchingSession(client, sessionId, batchingOptions);
+ mLocApi->startBatching(sessionId, batchingOptions, getBatchingAccuracy(), getBatchingTimeout(),
+ new LocApiResponse(*getContext(),
+ [this, client, sessionId, batchingOptions] (LocationError err) {
+ if (LOCATION_ERROR_SUCCESS != err) {
+ eraseBatchingSession(client, sessionId);
+ }
+
+ if (LOCATION_ERROR_SUCCESS != err &&
+ batchingOptions.batchingMode != BATCHING_MODE_NO_AUTO_REPORT &&
+ 0 == autoReportBatchingSessionsCount()) {
+ // if we fail to start batching and we have already registered batch full event
+ // we need to undo that since no sessions are now interested in batch full event
+ updateEvtMask(LOC_API_ADAPTER_BIT_BATCH_FULL,
+ LOC_REGISTRATION_MASK_DISABLED);
+ }
+
+ reportResponse(client, err, sessionId);
+ }));
+}
+
+void
+BatchingAdapter::updateBatchingOptionsCommand(LocationAPI* client, uint32_t id,
+ BatchingOptions& batchOptions)
+{
+ LOC_LOGD("%s]: client %p id %u minInterval %u minDistance %u mode %u batchMode %u",
+ __func__, client, id, batchOptions.minInterval,
+ batchOptions.minDistance, batchOptions.mode,
+ batchOptions.batchingMode);
+
+ struct MsgUpdateBatching : public LocMsg {
+ BatchingAdapter& mAdapter;
+ LocApiBase& mApi;
+ LocationAPI* mClient;
+ uint32_t mSessionId;
+ BatchingOptions mBatchOptions;
+ inline MsgUpdateBatching(BatchingAdapter& adapter,
+ LocApiBase& api,
+ LocationAPI* client,
+ uint32_t sessionId,
+ BatchingOptions batchOptions) :
+ LocMsg(),
+ mAdapter(adapter),
+ mApi(api),
+ mClient(client),
+ mSessionId(sessionId),
+ mBatchOptions(batchOptions) {}
+ inline virtual void proc() const {
+ if (!mAdapter.isEngineCapabilitiesKnown()) {
+ mAdapter.mPendingMsgs.push_back(new MsgUpdateBatching(*this));
+ return;
+ }
+ LocationError err = LOCATION_ERROR_SUCCESS;
+ if (!mAdapter.isBatchingSession(mClient, mSessionId)) {
+ err = LOCATION_ERROR_ID_UNKNOWN;
+ } else if ((0 == mBatchOptions.size) ||
+ (mBatchOptions.batchingMode > BATCHING_MODE_NO_AUTO_REPORT)) {
+ err = LOCATION_ERROR_INVALID_PARAMETER;
+ }
+ if (LOCATION_ERROR_SUCCESS == err) {
+ if (!mAdapter.isTripSession(mSessionId)) {
+ mAdapter.stopBatching(mClient, mSessionId, true, mBatchOptions);
+ } else {
+ mAdapter.stopTripBatchingMultiplex(mClient, mSessionId, true, mBatchOptions);
+ }
+ }
+ }
+ };
+
+ sendMsg(new MsgUpdateBatching(*this, *mLocApi, client, id, batchOptions));
+}
+
+void
+BatchingAdapter::stopBatchingCommand(LocationAPI* client, uint32_t id)
+{
+ LOC_LOGD("%s]: client %p id %u", __func__, client, id);
+
+ struct MsgStopBatching : public LocMsg {
+ BatchingAdapter& mAdapter;
+ LocApiBase& mApi;
+ LocationAPI* mClient;
+ uint32_t mSessionId;
+ inline MsgStopBatching(BatchingAdapter& adapter,
+ LocApiBase& api,
+ LocationAPI* client,
+ uint32_t sessionId) :
+ LocMsg(),
+ mAdapter(adapter),
+ mApi(api),
+ mClient(client),
+ mSessionId(sessionId) {}
+ inline virtual void proc() const {
+ if (!mAdapter.isEngineCapabilitiesKnown()) {
+ mAdapter.mPendingMsgs.push_back(new MsgStopBatching(*this));
+ return;
+ }
+ LocationError err = LOCATION_ERROR_SUCCESS;
+ if (!mAdapter.isBatchingSession(mClient, mSessionId)) {
+ err = LOCATION_ERROR_ID_UNKNOWN;
+ }
+ if (LOCATION_ERROR_SUCCESS == err) {
+ if (mAdapter.isTripSession(mSessionId)) {
+ mAdapter.stopTripBatchingMultiplex(mClient, mSessionId);
+ } else {
+ mAdapter.stopBatching(mClient, mSessionId);
+ }
+ }
+ }
+ };
+
+ sendMsg(new MsgStopBatching(*this, *mLocApi, client, id));
+}
+
+void
+BatchingAdapter::stopBatching(LocationAPI* client, uint32_t sessionId, bool restartNeeded,
+ const BatchingOptions& batchOptions)
+{
+ LocationSessionKey key(client, sessionId);
+ auto it = mBatchingSessions.find(key);
+ if (it != mBatchingSessions.end()) {
+ auto flpOptions = it->second;
+ // Assume stop will be OK, restore session if not
+ eraseBatchingSession(client, sessionId);
+ mLocApi->stopBatching(sessionId,
+ new LocApiResponse(*getContext(),
+ [this, client, sessionId, flpOptions, restartNeeded, batchOptions]
+ (LocationError err) {
+ if (LOCATION_ERROR_SUCCESS != err) {
+ saveBatchingSession(client, sessionId, batchOptions);
+ } else {
+ // if stopBatching is success, unregister for batch full event if this was the last
+ // batching session that is interested in batch full event
+ if (0 == autoReportBatchingSessionsCount() &&
+ flpOptions.batchingMode != BATCHING_MODE_NO_AUTO_REPORT) {
+ updateEvtMask(LOC_API_ADAPTER_BIT_BATCH_FULL,
+ LOC_REGISTRATION_MASK_DISABLED);
+ }
+
+ if (restartNeeded) {
+ if (batchOptions.batchingMode == BATCHING_MODE_ROUTINE ||
+ batchOptions.batchingMode == BATCHING_MODE_NO_AUTO_REPORT) {
+ startBatching(client, sessionId, batchOptions);
+ } else if (batchOptions.batchingMode == BATCHING_MODE_TRIP) {
+ startTripBatchingMultiplex(client, sessionId, batchOptions);
+ }
+ }
+ }
+ reportResponse(client, err, sessionId);
+ }));
+ }
+}
+
+void
+BatchingAdapter::getBatchedLocationsCommand(LocationAPI* client, uint32_t id, size_t count)
+{
+ LOC_LOGD("%s]: client %p id %u count %zu", __func__, client, id, count);
+
+ struct MsgGetBatchedLocations : public LocMsg {
+ BatchingAdapter& mAdapter;
+ LocApiBase& mApi;
+ LocationAPI* mClient;
+ uint32_t mSessionId;
+ size_t mCount;
+ inline MsgGetBatchedLocations(BatchingAdapter& adapter,
+ LocApiBase& api,
+ LocationAPI* client,
+ uint32_t sessionId,
+ size_t count) :
+ LocMsg(),
+ mAdapter(adapter),
+ mApi(api),
+ mClient(client),
+ mSessionId(sessionId),
+ mCount(count) {}
+ inline virtual void proc() const {
+ if (!mAdapter.isEngineCapabilitiesKnown()) {
+ mAdapter.mPendingMsgs.push_back(new MsgGetBatchedLocations(*this));
+ return;
+ }
+ LocationError err = LOCATION_ERROR_SUCCESS;
+ if (!mAdapter.hasBatchingCallback(mClient)) {
+ err = LOCATION_ERROR_CALLBACK_MISSING;
+ } else if (!mAdapter.isBatchingSession(mClient, mSessionId)) {
+ err = LOCATION_ERROR_ID_UNKNOWN;
+ }
+ if (LOCATION_ERROR_SUCCESS == err) {
+ if (mAdapter.isTripSession(mSessionId)) {
+ mApi.getBatchedTripLocations(mCount, 0,
+ new LocApiResponse(*mAdapter.getContext(),
+ [&mAdapter = mAdapter, mSessionId = mSessionId,
+ mClient = mClient] (LocationError err) {
+ mAdapter.reportResponse(mClient, err, mSessionId);
+ }));
+ } else {
+ mApi.getBatchedLocations(mCount, new LocApiResponse(*mAdapter.getContext(),
+ [&mAdapter = mAdapter, mSessionId = mSessionId,
+ mClient = mClient] (LocationError err) {
+ mAdapter.reportResponse(mClient, err, mSessionId);
+ }));
+ }
+ } else {
+ mAdapter.reportResponse(mClient, err, mSessionId);
+ }
+ }
+ };
+
+ sendMsg(new MsgGetBatchedLocations(*this, *mLocApi, client, id, count));
+}
+
+void
+BatchingAdapter::reportLocationsEvent(const Location* locations, size_t count,
+ BatchingMode batchingMode)
+{
+ LOC_LOGD("%s]: count %zu batchMode %d", __func__, count, batchingMode);
+
+ struct MsgReportLocations : public LocMsg {
+ BatchingAdapter& mAdapter;
+ Location* mLocations;
+ size_t mCount;
+ BatchingMode mBatchingMode;
+ inline MsgReportLocations(BatchingAdapter& adapter,
+ const Location* locations,
+ size_t count,
+ BatchingMode batchingMode) :
+ LocMsg(),
+ mAdapter(adapter),
+ mLocations(new Location[count]),
+ mCount(count),
+ mBatchingMode(batchingMode)
+ {
+ if (nullptr == mLocations) {
+ LOC_LOGE("%s]: new failed to allocate mLocations", __func__);
+ return;
+ }
+ for (size_t i=0; i < mCount; ++i) {
+ mLocations[i] = locations[i];
+ }
+ }
+ inline virtual ~MsgReportLocations() {
+ if (nullptr != mLocations)
+ delete[] mLocations;
+ }
+ inline virtual void proc() const {
+ mAdapter.reportLocations(mLocations, mCount, mBatchingMode);
+ }
+ };
+
+ sendMsg(new MsgReportLocations(*this, locations, count, batchingMode));
+}
+
+void
+BatchingAdapter::reportLocations(Location* locations, size_t count, BatchingMode batchingMode)
+{
+ BatchingOptions batchOptions = {sizeof(BatchingOptions), batchingMode};
+
+ for (auto it=mClientData.begin(); it != mClientData.end(); ++it) {
+ if (nullptr != it->second.batchingCb) {
+ it->second.batchingCb(count, locations, batchOptions);
+ }
+ }
+}
+
+void
+BatchingAdapter::reportCompletedTripsEvent(uint32_t accumulated_distance)
+{
+ struct MsgReportCompletedTrips : public LocMsg {
+ BatchingAdapter& mAdapter;
+ uint32_t mAccumulatedDistance;
+ inline MsgReportCompletedTrips(BatchingAdapter& adapter,
+ uint32_t accumulated_distance) :
+ LocMsg(),
+ mAdapter(adapter),
+ mAccumulatedDistance(accumulated_distance)
+ {
+ }
+ inline virtual ~MsgReportCompletedTrips() {
+ }
+ inline virtual void proc() const {
+
+ // Check if any trips are completed
+ std::list<uint32_t> completedTripsList;
+ completedTripsList.clear();
+
+ for(auto itt = mAdapter.mTripSessions.begin(); itt != mAdapter.mTripSessions.end();)
+ {
+ TripSessionStatus &tripSession = itt->second;
+
+ tripSession.accumulatedDistanceThisTrip =
+ tripSession.accumulatedDistanceOnTripRestart
+ + (mAccumulatedDistance - tripSession.accumulatedDistanceOngoingBatch);
+ if (tripSession.tripDistance <= tripSession.accumulatedDistanceThisTrip) {
+ // trip is completed
+ completedTripsList.push_back(itt->first);
+ itt = mAdapter.mTripSessions.erase(itt);
+
+ if (tripSession.tripTBFInterval == mAdapter.mOngoingTripTBFInterval) {
+ // trip with ongoing TBF interval is completed
+ mAdapter.mTripWithOngoingTBFDropped = true;
+ }
+
+ if (tripSession.tripDistance == mAdapter.mOngoingTripDistance) {
+ // trip with ongoing trip distance is completed
+ mAdapter.mTripWithOngoingTripDistanceDropped = true;
+ }
+ } else {
+ itt++;
+ }
+ }
+
+ if (completedTripsList.size() > 0) {
+ mAdapter.reportBatchStatusChange(BATCHING_STATUS_TRIP_COMPLETED,
+ completedTripsList);
+ mAdapter.restartTripBatching(false, mAccumulatedDistance, 0);
+ } else {
+ mAdapter.printTripReport();
+ }
+ }
+ };
+
+ LOC_LOGD("%s]: Accumulated Distance so far: %u",
+ __func__, accumulated_distance);
+
+ sendMsg(new MsgReportCompletedTrips(*this, accumulated_distance));
+}
+
+void
+BatchingAdapter::reportBatchStatusChange(BatchingStatus batchStatus,
+ std::list<uint32_t> & completedTripsList)
+{
+ BatchingStatusInfo batchStatusInfo =
+ {sizeof(BatchingStatusInfo), batchStatus};
+
+ for (auto it=mClientData.begin(); it != mClientData.end(); ++it) {
+ if (nullptr != it->second.batchingStatusCb) {
+ it->second.batchingStatusCb(batchStatusInfo, completedTripsList);
+ }
+ }
+}
+
+void
+BatchingAdapter::reportBatchStatusChangeEvent(BatchingStatus batchStatus)
+{
+ struct MsgReportBatchStatus : public LocMsg {
+ BatchingAdapter& mAdapter;
+ BatchingStatus mBatchStatus;
+ inline MsgReportBatchStatus(BatchingAdapter& adapter,
+ BatchingStatus batchStatus) :
+ LocMsg(),
+ mAdapter(adapter),
+ mBatchStatus(batchStatus)
+ {
+ }
+ inline virtual ~MsgReportBatchStatus() {
+ }
+ inline virtual void proc() const {
+ std::list<uint32_t> tempList;
+ tempList.clear();
+ mAdapter.reportBatchStatusChange(mBatchStatus, tempList);
+ }
+ };
+
+ sendMsg(new MsgReportBatchStatus(*this, batchStatus));
+}
+
+void
+BatchingAdapter::startTripBatchingMultiplex(LocationAPI* client, uint32_t sessionId,
+ const BatchingOptions& batchingOptions)
+{
+ if (mTripSessions.size() == 0) {
+ // if there is currenty no batching sessions interested in batch full event, then this
+ // new session will need to register for batch full event
+ if (0 == autoReportBatchingSessionsCount()) {
+ updateEvtMask(LOC_API_ADAPTER_BIT_BATCH_FULL,
+ LOC_REGISTRATION_MASK_ENABLED);
+ }
+
+ // Assume start will be OK, remove session if not
+ saveBatchingSession(client, sessionId, batchingOptions);
+
+ mTripSessions[sessionId] = { 0, 0, 0, batchingOptions.minDistance,
+ batchingOptions.minInterval};
+ mLocApi->startOutdoorTripBatching(batchingOptions.minDistance,
+ batchingOptions.minInterval, getBatchingTimeout(), new LocApiResponse(*getContext(),
+ [this, client, sessionId, batchingOptions] (LocationError err) {
+ if (err == LOCATION_ERROR_SUCCESS) {
+ mOngoingTripDistance = batchingOptions.minDistance;
+ mOngoingTripTBFInterval = batchingOptions.minInterval;
+ LOC_LOGD("%s] New Trip started ...", __func__);
+ printTripReport();
+ } else {
+ eraseBatchingSession(client, sessionId);
+ mTripSessions.erase(sessionId);
+ // if we fail to start batching and we have already registered batch full event
+ // we need to undo that since no sessions are now interested in batch full event
+ if (0 == autoReportBatchingSessionsCount()) {
+ updateEvtMask(LOC_API_ADAPTER_BIT_BATCH_FULL,
+ LOC_REGISTRATION_MASK_DISABLED);
+ }
+ }
+ reportResponse(client, err, sessionId);
+ }));
+ } else {
+ // query accumulated distance
+ mLocApi->queryAccumulatedTripDistance(
+ new LocApiResponseData<LocApiBatchData>(*getContext(),
+ [this, batchingOptions, sessionId, client]
+ (LocationError err, LocApiBatchData data) {
+ uint32_t accumulatedDistanceOngoingBatch = 0;
+ uint32_t numOfBatchedPositions = 0;
+ uint32_t ongoingTripDistance = mOngoingTripDistance;
+ uint32_t ongoingTripInterval = mOngoingTripTBFInterval;
+ bool needsRestart = false;
+
+ // check if TBF of new session is lesser than ongoing TBF interval
+ if (ongoingTripInterval > batchingOptions.minInterval) {
+ ongoingTripInterval = batchingOptions.minInterval;
+ needsRestart = true;
+ }
+ accumulatedDistanceOngoingBatch = data.accumulatedDistance;
+ numOfBatchedPositions = data.numOfBatchedPositions;
+ TripSessionStatus newTripSession = { accumulatedDistanceOngoingBatch, 0, 0,
+ batchingOptions.minDistance,
+ batchingOptions.minInterval};
+ if (err != LOCATION_ERROR_SUCCESS) {
+ // unable to query accumulated distance, assume remaining distance in
+ // ongoing batch is mongoingTripDistance.
+ if (batchingOptions.minDistance < ongoingTripDistance) {
+ ongoingTripDistance = batchingOptions.minDistance;
+ needsRestart = true;
+ }
+ } else {
+ // compute the remaining distance
+ uint32_t ongoing_trip_remaining_distance = ongoingTripDistance -
+ accumulatedDistanceOngoingBatch;
+
+ // check if new trip distance is lesser than the ongoing batch remaining distance
+ if (batchingOptions.minDistance < ongoing_trip_remaining_distance) {
+ ongoingTripDistance = batchingOptions.minDistance;
+ needsRestart = true;
+ } else if (needsRestart == true) {
+ // needsRestart is anyways true , may be because of lesser TBF of new session.
+ ongoingTripDistance = ongoing_trip_remaining_distance;
+ }
+ mTripSessions[sessionId] = newTripSession;
+ LOC_LOGD("%s] New Trip started ...", __func__);
+ printTripReport();
+ }
+
+ if (needsRestart) {
+ mOngoingTripDistance = ongoingTripDistance;
+ mOngoingTripTBFInterval = ongoingTripInterval;
+
+ // reset the accumulatedDistanceOngoingBatch for each session,
+ // and record the total accumulated distance so far for the session.
+ for (auto itt = mTripSessions.begin(); itt != mTripSessions.end(); itt++) {
+ TripSessionStatus &tripSessStatus = itt->second;
+ tripSessStatus.accumulatedDistanceOngoingBatch = 0;
+ tripSessStatus.accumulatedDistanceOnTripRestart =
+ tripSessStatus.accumulatedDistanceThisTrip;
+ }
+ mLocApi->reStartOutdoorTripBatching(ongoingTripDistance, ongoingTripInterval,
+ getBatchingTimeout(), new LocApiResponse(*getContext(),
+ [this, client, sessionId] (LocationError err) {
+ if (err != LOCATION_ERROR_SUCCESS) {
+ LOC_LOGE("%s] New Trip restart failed!", __func__);
+ }
+ reportResponse(client, err, sessionId);
+ }));
+ } else {
+ reportResponse(client, LOCATION_ERROR_SUCCESS, sessionId);
+ }
+ }));
+ }
+}
+
+void
+BatchingAdapter::stopTripBatchingMultiplex(LocationAPI* client, uint32_t sessionId,
+ bool restartNeeded, const BatchingOptions& batchOptions)
+{
+ LocationError err = LOCATION_ERROR_SUCCESS;
+
+ if (mTripSessions.size() == 1) {
+ mLocApi->stopOutdoorTripBatching(true, new LocApiResponse(*getContext(),
+ [this, restartNeeded, client, sessionId, batchOptions]
+ (LocationError err) {
+ if (LOCATION_ERROR_SUCCESS == err) {
+ // if stopOutdoorTripBatching is success, unregister for batch full event if this
+ // was the last batching session that is interested in batch full event
+ if (1 == autoReportBatchingSessionsCount()) {
+ updateEvtMask(LOC_API_ADAPTER_BIT_BATCH_FULL,
+ LOC_REGISTRATION_MASK_DISABLED);
+ }
+ }
+ stopTripBatchingMultiplexCommon(err, client, sessionId, restartNeeded, batchOptions);
+ }));
+ return;
+ }
+
+ stopTripBatchingMultiplexCommon(err, client, sessionId, restartNeeded, batchOptions);
+}
+
+void
+BatchingAdapter::stopTripBatchingMultiplexCommon(LocationError err, LocationAPI* client,
+ uint32_t sessionId, bool restartNeeded, const BatchingOptions& batchOptions)
+{
+ auto itt = mTripSessions.find(sessionId);
+ TripSessionStatus tripSess = itt->second;
+ if (tripSess.tripTBFInterval == mOngoingTripTBFInterval) {
+ // trip with ongoing trip interval is stopped
+ mTripWithOngoingTBFDropped = true;
+ }
+
+ if (tripSess.tripDistance == mOngoingTripDistance) {
+ // trip with ongoing trip distance is stopped
+ mTripWithOngoingTripDistanceDropped = true;
+ }
+
+ mTripSessions.erase(sessionId);
+
+ if (mTripSessions.size() == 0) {
+ mOngoingTripDistance = 0;
+ mOngoingTripTBFInterval = 0;
+ } else {
+ restartTripBatching(true);
+ }
+
+ if (restartNeeded) {
+ eraseBatchingSession(client, sessionId);
+ if (batchOptions.batchingMode == BATCHING_MODE_ROUTINE ||
+ batchOptions.batchingMode == BATCHING_MODE_NO_AUTO_REPORT) {
+ startBatching(client, sessionId, batchOptions);
+ } else if (batchOptions.batchingMode == BATCHING_MODE_TRIP) {
+ startTripBatchingMultiplex(client, sessionId, batchOptions);
+ }
+ }
+ reportResponse(client, err, sessionId);
+}
+
+
+void
+BatchingAdapter::restartTripBatching(bool queryAccumulatedDistance, uint32_t accDist,
+ uint32_t numbatchedPos)
+{
+ // does batch need restart with new trip distance / TBF interval
+ uint32_t minRemainingDistance = 0;
+ uint32_t minTBFInterval = 0;
+
+ // if no more trips left, stop the ongoing trip
+ if (mTripSessions.size() == 0) {
+ mLocApi->stopOutdoorTripBatching(true, new LocApiResponse(*getContext(),
+ [] (LocationError /*err*/) {}));
+ mOngoingTripDistance = 0;
+ mOngoingTripTBFInterval = 0;
+ // unregister for batch full event if there are no more
+ // batching session that is interested in batch full event
+ if (0 == autoReportBatchingSessionsCount()) {
+ updateEvtMask(LOC_API_ADAPTER_BIT_BATCH_FULL,
+ LOC_REGISTRATION_MASK_DISABLED);
+ }
+ return;
+ }
+
+ // record the min trip distance and min tbf interval of all ongoing sessions
+ for (auto itt = mTripSessions.begin(); itt != mTripSessions.end(); itt++) {
+
+ TripSessionStatus tripSessStatus = itt->second;
+
+ if ((minRemainingDistance == 0) ||
+ (minRemainingDistance > (tripSessStatus.tripDistance
+ - tripSessStatus.accumulatedDistanceThisTrip))) {
+ minRemainingDistance = tripSessStatus.tripDistance -
+ tripSessStatus.accumulatedDistanceThisTrip;
+ }
+
+ if ((minTBFInterval == 0) ||
+ (minTBFInterval > tripSessStatus.tripTBFInterval)) {
+ minTBFInterval = tripSessStatus.tripTBFInterval;
+ }
+ }
+
+ mLocApi->queryAccumulatedTripDistance(
+ new LocApiResponseData<LocApiBatchData>(*getContext(),
+ [this, queryAccumulatedDistance, minRemainingDistance, minTBFInterval, accDist,
+ numbatchedPos] (LocationError /*err*/, LocApiBatchData data) {
+ bool needsRestart = false;
+
+ uint32_t ongoingTripDistance = mOngoingTripDistance;
+ uint32_t ongoingTripInterval = mOngoingTripTBFInterval;
+ uint32_t accumulatedDistance = accDist;
+ uint32_t numOfBatchedPositions = numbatchedPos;
+
+ if (queryAccumulatedDistance) {
+ accumulatedDistance = data.accumulatedDistance;
+ numOfBatchedPositions = data.numOfBatchedPositions;
+ }
+
+ if ((!mTripWithOngoingTripDistanceDropped) &&
+ (ongoingTripDistance - accumulatedDistance != 0)) {
+ // if ongoing trip is already not completed still,
+ // check the min distance against the remaining distance
+ if (minRemainingDistance <
+ (ongoingTripDistance - accumulatedDistance)) {
+ ongoingTripDistance = minRemainingDistance;
+ needsRestart = true;
+ }
+ } else if (minRemainingDistance != 0) {
+ // else if ongoing trip is already completed / dropped,
+ // use the minRemainingDistance of ongoing sessions
+ ongoingTripDistance = minRemainingDistance;
+ needsRestart = true;
+ }
+
+ if ((minTBFInterval < ongoingTripInterval) ||
+ ((minTBFInterval != ongoingTripInterval) &&
+ (mTripWithOngoingTBFDropped))) {
+ ongoingTripInterval = minTBFInterval;
+ needsRestart = true;
+ }
+
+ if (needsRestart) {
+ mLocApi->reStartOutdoorTripBatching(ongoingTripDistance, ongoingTripInterval,
+ getBatchingTimeout(), new LocApiResponse(*getContext(),
+ [this, accumulatedDistance, ongoingTripDistance, ongoingTripInterval]
+ (LocationError err) {
+
+ if (err == LOCATION_ERROR_SUCCESS) {
+ for(auto itt = mTripSessions.begin(); itt != mTripSessions.end(); itt++) {
+ TripSessionStatus &tripSessStatus = itt->second;
+ tripSessStatus.accumulatedDistanceThisTrip =
+ tripSessStatus.accumulatedDistanceOnTripRestart +
+ (accumulatedDistance -
+ tripSessStatus.accumulatedDistanceOngoingBatch);
+
+ tripSessStatus.accumulatedDistanceOngoingBatch = 0;
+ tripSessStatus.accumulatedDistanceOnTripRestart =
+ tripSessStatus.accumulatedDistanceThisTrip;
+ }
+
+ mOngoingTripDistance = ongoingTripDistance;
+ mOngoingTripTBFInterval = ongoingTripInterval;
+ }
+ }));
+ }
+ }));
+}
+
+void
+BatchingAdapter::printTripReport()
+{
+ IF_LOC_LOGD {
+ LOC_LOGD("Ongoing Trip Distance = %u, Ongoing Trip TBF Interval = %u",
+ mOngoingTripDistance, mOngoingTripTBFInterval);
+
+ for (auto itt = mTripSessions.begin(); itt != mTripSessions.end(); itt++) {
+ TripSessionStatus tripSessStatus = itt->second;
+
+ LOC_LOGD("tripDistance:%u tripTBFInterval:%u"
+ " trip accumulated Distance:%u"
+ " trip accumualted distance ongoing batch:%u"
+ " trip accumulated distance on trip restart %u \r\n",
+ tripSessStatus.tripDistance, tripSessStatus.tripTBFInterval,
+ tripSessStatus.accumulatedDistanceThisTrip,
+ tripSessStatus.accumulatedDistanceOngoingBatch,
+ tripSessStatus.accumulatedDistanceOnTripRestart);
+ }
+ }
+}
diff --git a/batching/BatchingAdapter.h b/batching/BatchingAdapter.h
new file mode 100644
index 0000000..66f7c5f
--- /dev/null
+++ b/batching/BatchingAdapter.h
@@ -0,0 +1,152 @@
+/* Copyright (c) 2017-2019, 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 BATCHING_ADAPTER_H
+#define BATCHING_ADAPTER_H
+
+#include <LocAdapterBase.h>
+#include <LocContext.h>
+#include <LocationAPI.h>
+#include <map>
+
+using namespace loc_core;
+
+class BatchingAdapter : public LocAdapterBase {
+
+ /* ==== BATCHING ======================================================================= */
+ typedef struct {
+ uint32_t accumulatedDistanceOngoingBatch;
+ uint32_t accumulatedDistanceThisTrip;
+ uint32_t accumulatedDistanceOnTripRestart;
+ uint32_t tripDistance;
+ uint32_t tripTBFInterval;
+ } TripSessionStatus;
+ typedef std::map<uint32_t, TripSessionStatus> TripSessionStatusMap;
+ typedef std::map<LocationSessionKey, BatchingOptions> BatchingSessionMap;
+
+ BatchingSessionMap mBatchingSessions;
+ TripSessionStatusMap mTripSessions;
+ uint32_t mOngoingTripDistance;
+ uint32_t mOngoingTripTBFInterval;
+ bool mTripWithOngoingTBFDropped;
+ bool mTripWithOngoingTripDistanceDropped;
+
+ void startTripBatchingMultiplex(LocationAPI* client, uint32_t sessionId,
+ const BatchingOptions& batchingOptions);
+ void stopTripBatchingMultiplex(LocationAPI* client, uint32_t sessionId,
+ bool restartNeeded,
+ const BatchingOptions& batchOptions);
+ inline void stopTripBatchingMultiplex(LocationAPI* client, uint32_t id) {
+ BatchingOptions batchOptions;
+ stopTripBatchingMultiplex(client, id, false, batchOptions);
+ };
+ void stopTripBatchingMultiplexCommon(LocationError err,
+ LocationAPI* client,
+ uint32_t sessionId,
+ bool restartNeeded,
+ const BatchingOptions& batchOptions);
+ void restartTripBatching(bool queryAccumulatedDistance, uint32_t accDist = 0,
+ uint32_t numbatchedPos = 0);
+ void printTripReport();
+
+ /* ==== CONFIGURATION ================================================================== */
+ uint32_t mBatchingTimeout;
+ uint32_t mBatchingAccuracy;
+ size_t mBatchSize;
+ size_t mTripBatchSize;
+
+protected:
+
+ /* ==== CLIENT ========================================================================= */
+ virtual void updateClientsEventMask();
+ virtual void stopClientSessions(LocationAPI* client);
+
+public:
+ BatchingAdapter();
+ virtual ~BatchingAdapter() {}
+
+ /* ==== SSR ============================================================================ */
+ /* ======== EVENTS ====(Called from QMI Thread)========================================= */
+ virtual void handleEngineUpEvent();
+ /* ======== UTILITIES ================================================================== */
+ void restartSessions();
+
+ /* ==== BATCHING ======================================================================= */
+ /* ======== COMMANDS ====(Called from Client Thread)==================================== */
+ uint32_t startBatchingCommand(LocationAPI* client, BatchingOptions &batchOptions);
+ void updateBatchingOptionsCommand(
+ LocationAPI* client, uint32_t id, BatchingOptions& batchOptions);
+ void stopBatchingCommand(LocationAPI* client, uint32_t id);
+ void getBatchedLocationsCommand(LocationAPI* client, uint32_t id, size_t count);
+ /* ======== RESPONSES ================================================================== */
+ void reportResponse(LocationAPI* client, LocationError err, uint32_t sessionId);
+ /* ======== UTILITIES ================================================================== */
+ bool hasBatchingCallback(LocationAPI* client);
+ bool isBatchingSession(LocationAPI* client, uint32_t sessionId);
+ bool isTripSession(uint32_t sessionId);
+ void saveBatchingSession(LocationAPI* client, uint32_t sessionId,
+ const BatchingOptions& batchingOptions);
+ void eraseBatchingSession(LocationAPI* client, uint32_t sessionId);
+ uint32_t autoReportBatchingSessionsCount();
+ void startBatching(LocationAPI* client, uint32_t sessionId,
+ const BatchingOptions& batchingOptions);
+ void stopBatching(LocationAPI* client, uint32_t sessionId, bool restartNeeded,
+ const BatchingOptions& batchOptions);
+ void stopBatching(LocationAPI* client, uint32_t sessionId) {
+ BatchingOptions batchOptions;
+ stopBatching(client, sessionId, false, batchOptions);
+ };
+
+ /* ==== REPORTS ======================================================================== */
+ /* ======== EVENTS ====(Called from QMI Thread)========================================= */
+ void reportLocationsEvent(const Location* locations, size_t count,
+ BatchingMode batchingMode);
+ void reportCompletedTripsEvent(uint32_t accumulatedDistance);
+ void reportBatchStatusChangeEvent(BatchingStatus batchStatus);
+ /* ======== UTILITIES ================================================================== */
+ void reportLocations(Location* locations, size_t count, BatchingMode batchingMode);
+ void reportBatchStatusChange(BatchingStatus batchStatus,
+ std::list<uint32_t> & completedTripsList);
+
+ /* ==== CONFIGURATION ================================================================== */
+ /* ======== COMMANDS ====(Called from Client Thread)==================================== */
+ void readConfigCommand();
+ void setConfigCommand();
+ /* ======== UTILITIES ================================================================== */
+ void setBatchSize(size_t batchSize) { mBatchSize = batchSize; }
+ size_t getBatchSize() { return mBatchSize; }
+ void setTripBatchSize(size_t batchSize) { mTripBatchSize = batchSize; }
+ size_t getTripBatchSize() { return mTripBatchSize; }
+ void setBatchingTimeout(uint32_t batchingTimeout) { mBatchingTimeout = batchingTimeout; }
+ uint32_t getBatchingTimeout() { return mBatchingTimeout; }
+ void setBatchingAccuracy(uint32_t accuracy) { mBatchingAccuracy = accuracy; }
+ uint32_t getBatchingAccuracy() { return mBatchingAccuracy; }
+
+};
+
+#endif /* BATCHING_ADAPTER_H */
diff --git a/batching/Makefile.am b/batching/Makefile.am
new file mode 100644
index 0000000..ef8011e
--- /dev/null
+++ b/batching/Makefile.am
@@ -0,0 +1,45 @@
+AM_CFLAGS = \
+ $(GPSUTILS_CFLAGS) \
+ $(LOCCORE_CFLAGS) \
+ -I./ \
+ -std=c++1y \
+ -D__func__=__PRETTY_FUNCTION__ \
+ -fno-short-enums
+
+ACLOCAL_AMFLAGS = -I m4
+
+requiredlibs = \
+ $(GPSUTILS_LIBS) \
+ $(LOCCORE_LIBS) \
+ -llog
+
+h_sources = \
+ BatchingAdapter.h
+
+libbatching_la_SOURCES = \
+ location_batching.cpp \
+ BatchingAdapter.cpp
+
+if USE_GLIB
+libbatching_la_CFLAGS = -DUSE_GLIB $(AM_CFLAGS) @GLIB_CFLAGS@
+#libbatching_la_LDFLAGS = -lstdc++ -g -Wl,-z,defs -lpthread $(requiredlibs) @GLIB_LIBS@ -shared -avoid-version
+libbatching_la_LDFLAGS = -lstdc++ -g -Wl,-z,defs -lpthread $(requiredlibs) @GLIB_LIBS@ -avoid-version
+libbatching_la_CPPFLAGS = -DUSE_GLIB $(AM_CFLAGS) $(AM_CPPFLAGS) @GLIB_CFLAGS@
+else
+libbatching_la_CFLAGS = $(AM_CFLAGS)
+libbatching_la_LDFLAGS = -Wl,-z,defs -lpthread $(requiredlibs) -shared -version-info 1:0:0
+libbatching_la_CPPFLAGS = $(AM_CFLAGS) $(AM_CPPFLAGS)
+endif
+
+library_include_HEADERS = $(h_sources)
+
+library_includedir = $(pkgincludedir)
+
+#Create and Install libraries
+lib_LTLIBRARIES = libbatching.la
+
+pkgconfigdir = $(libdir)/pkgconfig
+pkgconfig_DATA = location-batching.pc
+sysconf_DATA = $(WORKSPACE)/hardware/qcom/gps/etc/flp.conf
+EXTRA_DIST = $(pkgconfig_DATA)
+
diff --git a/batching/configure.ac b/batching/configure.ac
new file mode 100644
index 0000000..27435c6
--- /dev/null
+++ b/batching/configure.ac
@@ -0,0 +1,78 @@
+# configure.ac -- Autoconf script for gps location-batching
+#
+# Process this file with autoconf to produce a configure script
+
+# Requires autoconf tool later than 2.61
+AC_PREREQ(2.61)
+# Initialize the gps location-batching package version 1.0.0
+AC_INIT([location-batching],1.0.0)
+# Does not strictly follow GNU Coding standards
+AM_INIT_AUTOMAKE([foreign])
+# Disables auto rebuilding of configure, Makefile.ins
+AM_MAINTAINER_MODE
+# Verifies the --srcdir is correct by checking for the path
+AC_CONFIG_SRCDIR([Makefile.am])
+# defines some macros variable to be included by source
+AC_CONFIG_HEADERS([config.h])
+AC_CONFIG_MACRO_DIR([m4])
+
+# Checks for programs.
+AC_PROG_LIBTOOL
+AC_PROG_CXX
+AC_PROG_CC
+AM_PROG_CC_C_O
+AC_PROG_AWK
+AC_PROG_CPP
+AC_PROG_INSTALL
+AC_PROG_LN_S
+AC_PROG_MAKE_SET
+PKG_PROG_PKG_CONFIG
+
+# Checks for libraries.
+PKG_CHECK_MODULES([GPSUTILS], [gps-utils])
+AC_SUBST([GPSUTILS_CFLAGS])
+AC_SUBST([GPSUTILS_LIBS])
+
+PKG_CHECK_MODULES([LOCCORE], [loc-core])
+AC_SUBST([LOCCORE_CFLAGS])
+AC_SUBST([LOCCORE_LIBS])
+
+PKG_CHECK_MODULES([GEOFENCE], [location-geofence])
+AC_SUBST([GEOFENCE_CFLAGS])
+AC_SUBST([GEOFENCE_LIBS])
+
+AC_ARG_WITH([locpla_includes],
+ AC_HELP_STRING([--with-locpla-includes=@<:@dir@:>@],
+ [specify the path to locpla-includes in loc-pla_git.bb]),
+ [locpla_incdir=$withval],
+ with_locpla_includes=no)
+
+if test "x$with_locpla_includes" != "xno"; then
+ AC_SUBST(LOCPLA_CFLAGS, "-I${locpla_incdir}")
+fi
+
+AC_ARG_WITH([glib],
+ AC_HELP_STRING([--with-glib],
+ [enable glib, building HLOS systems which use glib]))
+
+if (test "x${with_glib}" = "xyes"); then
+ AC_DEFINE(ENABLE_USEGLIB, 1, [Define if HLOS systems uses glib])
+ PKG_CHECK_MODULES(GTHREAD, gthread-2.0 >= 2.16, dummy=yes,
+ AC_MSG_ERROR(GThread >= 2.16 is required))
+ PKG_CHECK_MODULES(GLIB, glib-2.0 >= 2.16, dummy=yes,
+ AC_MSG_ERROR(GLib >= 2.16 is required))
+ GLIB_CFLAGS="$GLIB_CFLAGS $GTHREAD_CFLAGS"
+ GLIB_LIBS="$GLIB_LIBS $GTHREAD_LIBS"
+
+ AC_SUBST(GLIB_CFLAGS)
+ AC_SUBST(GLIB_LIBS)
+fi
+
+AM_CONDITIONAL(USE_GLIB, test "x${with_glib}" = "xyes")
+
+AC_CONFIG_FILES([ \
+ Makefile \
+ location-batching.pc
+ ])
+
+AC_OUTPUT
diff --git a/batching/location-batching.pc.in b/batching/location-batching.pc.in
new file mode 100644
index 0000000..da1fbf4
--- /dev/null
+++ b/batching/location-batching.pc.in
@@ -0,0 +1,10 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+
+Name: location-batching
+Description: QTI GPS Batching
+Version: @VERSION
+Libs: -L${libdir} -lbatching
+Cflags: -I${includedir}/location-batching
diff --git a/batching/location_batching.cpp b/batching/location_batching.cpp
new file mode 100644
index 0000000..571da72
--- /dev/null
+++ b/batching/location_batching.cpp
@@ -0,0 +1,134 @@
+/* Copyright (c) 2017-2019, 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.
+ *
+ */
+#include "BatchingAdapter.h"
+#include "location_interface.h"
+
+static BatchingAdapter* gBatchingAdapter = NULL;
+
+static void initialize();
+static void deinitialize();
+
+static void addClient(LocationAPI* client, const LocationCallbacks& callbacks);
+static void removeClient(LocationAPI* client, removeClientCompleteCallback rmClientCb);
+static void requestCapabilities(LocationAPI* client);
+
+static uint32_t startBatching(LocationAPI* client, BatchingOptions&);
+static void stopBatching(LocationAPI* client, uint32_t id);
+static void updateBatchingOptions(LocationAPI* client, uint32_t id, BatchingOptions&);
+static void getBatchedLocations(LocationAPI* client, uint32_t id, size_t count);
+
+static const BatchingInterface gBatchingInterface = {
+ sizeof(BatchingInterface),
+ initialize,
+ deinitialize,
+ addClient,
+ removeClient,
+ requestCapabilities,
+ startBatching,
+ stopBatching,
+ updateBatchingOptions,
+ getBatchedLocations
+};
+
+#ifndef DEBUG_X86
+extern "C" const BatchingInterface* getBatchingInterface()
+#else
+const BatchingInterface* getBatchingInterface()
+#endif // DEBUG_X86
+{
+ return &gBatchingInterface;
+}
+
+static void initialize()
+{
+ if (NULL == gBatchingAdapter) {
+ gBatchingAdapter = new BatchingAdapter();
+ }
+}
+
+static void deinitialize()
+{
+ if (NULL != gBatchingAdapter) {
+ delete gBatchingAdapter;
+ gBatchingAdapter = NULL;
+ }
+}
+
+static void addClient(LocationAPI* client, const LocationCallbacks& callbacks)
+{
+ if (NULL != gBatchingAdapter) {
+ gBatchingAdapter->addClientCommand(client, callbacks);
+ }
+}
+
+static void removeClient(LocationAPI* client, removeClientCompleteCallback rmClientCb)
+{
+ if (NULL != gBatchingAdapter) {
+ gBatchingAdapter->removeClientCommand(client, rmClientCb);
+ }
+}
+
+static void requestCapabilities(LocationAPI* client)
+{
+ if (NULL != gBatchingAdapter) {
+ gBatchingAdapter->requestCapabilitiesCommand(client);
+ }
+}
+
+static uint32_t startBatching(LocationAPI* client, BatchingOptions &batchOptions)
+{
+ if (NULL != gBatchingAdapter) {
+ return gBatchingAdapter->startBatchingCommand(client, batchOptions);
+ } else {
+ return 0;
+ }
+}
+
+static void stopBatching(LocationAPI* client, uint32_t id)
+{
+ if (NULL != gBatchingAdapter) {
+ gBatchingAdapter->stopBatchingCommand(client, id);
+ }
+}
+
+static void updateBatchingOptions(
+ LocationAPI* client, uint32_t id, BatchingOptions& batchOptions)
+{
+ if (NULL != gBatchingAdapter) {
+ gBatchingAdapter->updateBatchingOptionsCommand(client, id, batchOptions);
+ }
+}
+
+static void getBatchedLocations(LocationAPI* client, uint32_t id, size_t count)
+{
+ if (NULL != gBatchingAdapter) {
+ gBatchingAdapter->getBatchedLocationsCommand(client, id, count);
+ }
+}
+
diff --git a/build/target_specific_features.mk b/build/target_specific_features.mk
new file mode 100644
index 0000000..766402a
--- /dev/null
+++ b/build/target_specific_features.mk
@@ -0,0 +1,69 @@
+GNSS_CFLAGS := \
+ -Werror \
+ -Wno-error=unused-parameter \
+ -Wno-error=macro-redefined \
+ -Wno-error=reorder \
+ -Wno-error=missing-braces \
+ -Wno-error=self-assign \
+ -Wno-error=enum-conversion \
+ -Wno-error=logical-op-parentheses \
+ -Wno-error=null-arithmetic \
+ -Wno-error=null-conversion \
+ -Wno-error=parentheses-equality \
+ -Wno-error=undefined-bool-conversion \
+ -Wno-error=tautological-compare \
+ -Wno-error=switch \
+ -Wno-error=date-time
+
+LOCAL_SANITIZE := signed-integer-overflow, unsigned-integer-overflow
+
+# GPS-HIDL
+GNSS_HIDL_1_0_TARGET_LIST := msm8960
+GNSS_HIDL_1_0_TARGET_LIST += msm8974
+GNSS_HIDL_1_0_TARGET_LIST += msm8226
+GNSS_HIDL_1_0_TARGET_LIST += msm8610
+GNSS_HIDL_1_0_TARGET_LIST += apq8084
+GNSS_HIDL_1_0_TARGET_LIST += msm8916
+GNSS_HIDL_1_0_TARGET_LIST += msm8994
+GNSS_HIDL_1_0_TARGET_LIST += msm8909
+GNSS_HIDL_1_0_TARGET_LIST += msm8952
+GNSS_HIDL_1_0_TARGET_LIST += msm8992
+GNSS_HIDL_1_0_TARGET_LIST += msm8996
+GNSS_HIDL_2_0_TARGET_LIST := msm8937
+GNSS_HIDL_2_0_TARGET_LIST += msm8953
+GNSS_HIDL_2_0_TARGET_LIST += msm8998
+GNSS_HIDL_2_0_TARGET_LIST += apq8098_latv
+GNSS_HIDL_2_0_TARGET_LIST += sdm710
+GNSS_HIDL_2_0_TARGET_LIST += qcs605
+GNSS_HIDL_2_0_TARGET_LIST += sdm845
+GNSS_HIDL_2_0_TARGET_LIST += sdm660
+GNSS_HIDL_2_0_TARGET_LIST += msmnile
+GNSS_HIDL_2_0_TARGET_LIST += $(MSMSTEPPE)
+GNSS_HIDL_2_0_TARGET_LIST += $(TRINKET)
+GNSS_HIDL_2_0_TARGET_LIST += kona
+GNSS_HIDL_2_0_TARGET_LIST += atoll
+GNSS_HIDL_2_0_TARGET_LIST += lito
+GNSS_HIDL_2_0_TARGET_LIST += bengal
+
+ifneq (,$(filter $(GNSS_HIDL_2_0_TARGET_LIST),$(TARGET_BOARD_PLATFORM)))
+GNSS_HIDL_VERSION = 2.0
+endif
+ifneq (,$(filter $(GNSS_HIDL_1_0_TARGET_LIST),$(TARGET_BOARD_PLATFORM)))
+GNSS_HIDL_VERSION = 1.0
+endif
+ifneq (,$(filter $(GNSS_HIDL_1_1_TARGET_LIST),$(TARGET_BOARD_PLATFORM)))
+GNSS_HIDL_VERSION = 1.1
+endif
+
+GNSS_HIDL_LEGACY_MEASURMENTS_TARGET_LIST := msm8937
+GNSS_HIDL_LEGACY_MEASURMENTS_TARGET_LIST += msm8953
+GNSS_HIDL_LEGACY_MEASURMENTS_TARGET_LIST += msm8998
+GNSS_HIDL_LEGACY_MEASURMENTS_TARGET_LIST += apq8098_latv
+GNSS_HIDL_LEGACY_MEASURMENTS_TARGET_LIST += sdm710
+GNSS_HIDL_LEGACY_MEASURMENTS_TARGET_LIST += qcs605
+GNSS_HIDL_LEGACY_MEASURMENTS_TARGET_LIST += sdm845
+GNSS_HIDL_LEGACY_MEASURMENTS_TARGET_LIST += sdm660
+
+ifneq (,$(filter $(GNSS_HIDL_LEGACY_MEASURMENTS_TARGET_LIST),$(TARGET_BOARD_PLATFORM)))
+GNSS_HIDL_LEGACY_MEASURMENTS = true
+endif
diff --git a/configure.ac b/configure.ac
new file mode 100644
index 0000000..0ab8e68
--- /dev/null
+++ b/configure.ac
@@ -0,0 +1,87 @@
+# configure.ac -- Autoconf script for gps loc_hal
+#
+# Process this file with autoconf to produce a configure script
+
+# Requires autoconf tool later than 2.61
+AC_PREREQ(2.61)
+# Initialize the gps loc-hal package version 1.0.0
+AC_INIT([loc-hal],1.0.0)
+# Does not strictly follow GNU Coding standards
+AM_INIT_AUTOMAKE([foreign])
+# Disables auto rebuilding of configure, Makefile.ins
+AM_MAINTAINER_MODE
+# Verifies the --srcdir is correct by checking for the path
+AC_CONFIG_SRCDIR([Makefile.am])
+# defines some macros variable to be included by source
+AC_CONFIG_HEADERS([config.h])
+AC_CONFIG_MACRO_DIR([m4])
+
+# Checks for programs.
+AC_PROG_LIBTOOL
+AC_PROG_CXX
+AC_PROG_CC
+AM_PROG_CC_C_O
+AC_PROG_AWK
+AC_PROG_CPP
+AC_PROG_INSTALL
+AC_PROG_LN_S
+AC_PROG_MAKE_SET
+PKG_PROG_PKG_CONFIG
+
+# Checks for libraries.
+PKG_CHECK_MODULES([GPSUTILS], [gps-utils])
+AC_SUBST([GPSUTILS_CFLAGS])
+AC_SUBST([GPSUTILS_LIBS])
+
+PKG_CHECK_MODULES([LOCCORE], [loc-core])
+AC_SUBST([LOCCORE_CFLAGS])
+AC_SUBST([LOCCORE_LIBS])
+
+AC_ARG_WITH([core_includes],
+ AC_HELP_STRING([--with-core-includes=@<:@dir@:>@],
+ [Specify the location of the core headers]),
+ [core_incdir=$withval],
+ with_core_includes=no)
+
+if test "x$with_core_includes" != "xno"; then
+ CPPFLAGS="${CPPFLAGS} -I${core_incdir}"
+fi
+
+AC_ARG_WITH([locpla_includes],
+ AC_HELP_STRING([--with-locpla-includes=@<:@dir@:>@],
+ [specify the path to locpla-includes in loc-pla_git.bb]),
+ [locpla_incdir=$withval],
+ with_locpla_includes=no)
+
+if test "x$with_locpla_includes" != "xno"; then
+ AC_SUBST(LOCPLA_CFLAGS, "-I${locpla_incdir}")
+fi
+
+AC_SUBST([CPPFLAGS])
+
+AC_ARG_WITH([glib],
+ AC_HELP_STRING([--with-glib],
+ [enable glib, building HLOS systems which use glib]))
+
+if (test "x${with_glib}" = "xyes"); then
+ AC_DEFINE(ENABLE_USEGLIB, 1, [Define if HLOS systems uses glib])
+ PKG_CHECK_MODULES(GTHREAD, gthread-2.0 >= 2.16, dummy=yes,
+ AC_MSG_ERROR(GThread >= 2.16 is required))
+ PKG_CHECK_MODULES(GLIB, glib-2.0 >= 2.16, dummy=yes,
+ AC_MSG_ERROR(GLib >= 2.16 is required))
+ GLIB_CFLAGS="$GLIB_CFLAGS $GTHREAD_CFLAGS"
+ GLIB_LIBS="$GLIB_LIBS $GTHREAD_LIBS"
+
+ AC_SUBST(GLIB_CFLAGS)
+ AC_SUBST(GLIB_LIBS)
+fi
+
+AM_CONDITIONAL(USE_GLIB, test "x${with_glib}" = "xyes")
+
+AC_CONFIG_FILES([ \
+ Makefile \
+ gnss/Makefile \
+ loc-hal.pc \
+ ])
+
+AC_OUTPUT
diff --git a/core/Android.mk b/core/Android.mk
new file mode 100644
index 0000000..bd955c1
--- /dev/null
+++ b/core/Android.mk
@@ -0,0 +1,59 @@
+ifneq ($(BOARD_VENDOR_QCOM_GPS_LOC_API_HARDWARE),)
+ifneq ($(BUILD_TINY_ANDROID),true)
+
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := libloc_core
+LOCAL_VENDOR_MODULE := true
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_SHARED_LIBRARIES := \
+ liblog \
+ libutils \
+ libcutils \
+ libgps.utils \
+ libdl \
+ liblog
+
+LOCAL_SRC_FILES += \
+ LocApiBase.cpp \
+ LocAdapterBase.cpp \
+ ContextBase.cpp \
+ LocContext.cpp \
+ loc_core_log.cpp \
+ data-items/DataItemsFactoryProxy.cpp \
+ SystemStatusOsObserver.cpp \
+ SystemStatus.cpp
+
+LOCAL_CFLAGS += \
+ -fno-short-enums \
+ -D_ANDROID_
+
+LOCAL_C_INCLUDES:= \
+ $(LOCAL_PATH)/data-items \
+ $(LOCAL_PATH)/data-items/common \
+ $(LOCAL_PATH)/observer \
+
+LOCAL_HEADER_LIBRARIES := \
+ libutils_headers \
+ libgps.utils_headers \
+ libloc_pla_headers \
+ liblocation_api_headers
+
+LOCAL_CFLAGS += $(GNSS_CFLAGS)
+
+include $(BUILD_SHARED_LIBRARY)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := libloc_core_headers
+LOCAL_EXPORT_C_INCLUDE_DIRS := \
+ $(LOCAL_PATH) \
+ $(LOCAL_PATH)/data-items \
+ $(LOCAL_PATH)/data-items/common \
+ $(LOCAL_PATH)/observer
+include $(BUILD_HEADER_LIBRARY)
+
+endif # not BUILD_TINY_ANDROID
+endif # BOARD_VENDOR_QCOM_GPS_LOC_API_HARDWARE
diff --git a/core/ContextBase.cpp b/core/ContextBase.cpp
new file mode 100644
index 0000000..d5c3108
--- /dev/null
+++ b/core/ContextBase.cpp
@@ -0,0 +1,331 @@
+/* Copyright (c) 2011-2014,2016-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_NDEBUG 0
+#define LOG_TAG "LocSvc_CtxBase"
+
+#include <dlfcn.h>
+#include <cutils/sched_policy.h>
+#include <unistd.h>
+#include <ContextBase.h>
+#include <msg_q.h>
+#include <loc_target.h>
+#include <loc_pla.h>
+#include <loc_log.h>
+
+namespace loc_core {
+
+#define SLL_LOC_API_LIB_NAME "libsynergy_loc_api.so"
+#define LOC_APIV2_0_LIB_NAME "libloc_api_v02.so"
+#define IS_SS5_HW_ENABLED 1
+
+loc_gps_cfg_s_type ContextBase::mGps_conf {};
+loc_sap_cfg_s_type ContextBase::mSap_conf {};
+bool ContextBase::sIsEngineCapabilitiesKnown = false;
+uint64_t ContextBase::sSupportedMsgMask = 0;
+bool ContextBase::sGnssMeasurementSupported = false;
+uint8_t ContextBase::sFeaturesSupported[MAX_FEATURE_LENGTH];
+
+const loc_param_s_type ContextBase::mGps_conf_table[] =
+{
+ {"GPS_LOCK", &mGps_conf.GPS_LOCK, NULL, 'n'},
+ {"SUPL_VER", &mGps_conf.SUPL_VER, NULL, 'n'},
+ {"LPP_PROFILE", &mGps_conf.LPP_PROFILE, NULL, 'n'},
+ {"A_GLONASS_POS_PROTOCOL_SELECT", &mGps_conf.A_GLONASS_POS_PROTOCOL_SELECT, NULL, 'n'},
+ {"LPPE_CP_TECHNOLOGY", &mGps_conf.LPPE_CP_TECHNOLOGY, NULL, 'n'},
+ {"LPPE_UP_TECHNOLOGY", &mGps_conf.LPPE_UP_TECHNOLOGY, NULL, 'n'},
+ {"AGPS_CERT_WRITABLE_MASK", &mGps_conf.AGPS_CERT_WRITABLE_MASK, NULL, 'n'},
+ {"SUPL_MODE", &mGps_conf.SUPL_MODE, NULL, 'n'},
+ {"SUPL_ES", &mGps_conf.SUPL_ES, NULL, 'n'},
+ {"INTERMEDIATE_POS", &mGps_conf.INTERMEDIATE_POS, NULL, 'n'},
+ {"ACCURACY_THRES", &mGps_conf.ACCURACY_THRES, NULL, 'n'},
+ {"NMEA_PROVIDER", &mGps_conf.NMEA_PROVIDER, NULL, 'n'},
+ {"CAPABILITIES", &mGps_conf.CAPABILITIES, NULL, 'n'},
+ {"XTRA_VERSION_CHECK", &mGps_conf.XTRA_VERSION_CHECK, NULL, 'n'},
+ {"XTRA_SERVER_1", &mGps_conf.XTRA_SERVER_1, NULL, 's'},
+ {"XTRA_SERVER_2", &mGps_conf.XTRA_SERVER_2, NULL, 's'},
+ {"XTRA_SERVER_3", &mGps_conf.XTRA_SERVER_3, NULL, 's'},
+ {"USE_EMERGENCY_PDN_FOR_EMERGENCY_SUPL", &mGps_conf.USE_EMERGENCY_PDN_FOR_EMERGENCY_SUPL, NULL, 'n'},
+ {"AGPS_CONFIG_INJECT", &mGps_conf.AGPS_CONFIG_INJECT, NULL, 'n'},
+ {"EXTERNAL_DR_ENABLED", &mGps_conf.EXTERNAL_DR_ENABLED, NULL, 'n'},
+ {"SUPL_HOST", &mGps_conf.SUPL_HOST, NULL, 's'},
+ {"SUPL_PORT", &mGps_conf.SUPL_PORT, NULL, 'n'},
+ {"MODEM_TYPE", &mGps_conf.MODEM_TYPE, NULL, 'n' },
+ {"MO_SUPL_HOST", &mGps_conf.MO_SUPL_HOST, NULL, 's' },
+ {"MO_SUPL_PORT", &mGps_conf.MO_SUPL_PORT, NULL, 'n' },
+ {"CONSTRAINED_TIME_UNCERTAINTY_ENABLED", &mGps_conf.CONSTRAINED_TIME_UNCERTAINTY_ENABLED, NULL, 'n'},
+ {"CONSTRAINED_TIME_UNCERTAINTY_THRESHOLD", &mGps_conf.CONSTRAINED_TIME_UNCERTAINTY_THRESHOLD, NULL, 'f'},
+ {"CONSTRAINED_TIME_UNCERTAINTY_ENERGY_BUDGET", &mGps_conf.CONSTRAINED_TIME_UNCERTAINTY_ENERGY_BUDGET, NULL, 'n'},
+ {"POSITION_ASSISTED_CLOCK_ESTIMATOR_ENABLED", &mGps_conf.POSITION_ASSISTED_CLOCK_ESTIMATOR_ENABLED, NULL, 'n'},
+ {"PROXY_APP_PACKAGE_NAME", &mGps_conf.PROXY_APP_PACKAGE_NAME, NULL, 's' },
+ {"CP_MTLR_ES", &mGps_conf.CP_MTLR_ES, NULL, 'n' },
+ {"GNSS_DEPLOYMENT", &mGps_conf.GNSS_DEPLOYMENT, NULL, 'n'},
+};
+
+const loc_param_s_type ContextBase::mSap_conf_table[] =
+{
+ {"GYRO_BIAS_RANDOM_WALK", &mSap_conf.GYRO_BIAS_RANDOM_WALK, &mSap_conf.GYRO_BIAS_RANDOM_WALK_VALID, 'f'},
+ {"ACCEL_RANDOM_WALK_SPECTRAL_DENSITY", &mSap_conf.ACCEL_RANDOM_WALK_SPECTRAL_DENSITY, &mSap_conf.ACCEL_RANDOM_WALK_SPECTRAL_DENSITY_VALID, 'f'},
+ {"ANGLE_RANDOM_WALK_SPECTRAL_DENSITY", &mSap_conf.ANGLE_RANDOM_WALK_SPECTRAL_DENSITY, &mSap_conf.ANGLE_RANDOM_WALK_SPECTRAL_DENSITY_VALID, 'f'},
+ {"RATE_RANDOM_WALK_SPECTRAL_DENSITY", &mSap_conf.RATE_RANDOM_WALK_SPECTRAL_DENSITY, &mSap_conf.RATE_RANDOM_WALK_SPECTRAL_DENSITY_VALID, 'f'},
+ {"VELOCITY_RANDOM_WALK_SPECTRAL_DENSITY", &mSap_conf.VELOCITY_RANDOM_WALK_SPECTRAL_DENSITY, &mSap_conf.VELOCITY_RANDOM_WALK_SPECTRAL_DENSITY_VALID, 'f'},
+ {"SENSOR_ACCEL_BATCHES_PER_SEC", &mSap_conf.SENSOR_ACCEL_BATCHES_PER_SEC, NULL, 'n'},
+ {"SENSOR_ACCEL_SAMPLES_PER_BATCH", &mSap_conf.SENSOR_ACCEL_SAMPLES_PER_BATCH, NULL, 'n'},
+ {"SENSOR_GYRO_BATCHES_PER_SEC", &mSap_conf.SENSOR_GYRO_BATCHES_PER_SEC, NULL, 'n'},
+ {"SENSOR_GYRO_SAMPLES_PER_BATCH", &mSap_conf.SENSOR_GYRO_SAMPLES_PER_BATCH, NULL, 'n'},
+ {"SENSOR_ACCEL_BATCHES_PER_SEC_HIGH", &mSap_conf.SENSOR_ACCEL_BATCHES_PER_SEC_HIGH, NULL, 'n'},
+ {"SENSOR_ACCEL_SAMPLES_PER_BATCH_HIGH", &mSap_conf.SENSOR_ACCEL_SAMPLES_PER_BATCH_HIGH, NULL, 'n'},
+ {"SENSOR_GYRO_BATCHES_PER_SEC_HIGH", &mSap_conf.SENSOR_GYRO_BATCHES_PER_SEC_HIGH, NULL, 'n'},
+ {"SENSOR_GYRO_SAMPLES_PER_BATCH_HIGH", &mSap_conf.SENSOR_GYRO_SAMPLES_PER_BATCH_HIGH, NULL, 'n'},
+ {"SENSOR_CONTROL_MODE", &mSap_conf.SENSOR_CONTROL_MODE, NULL, 'n'},
+ {"SENSOR_ALGORITHM_CONFIG_MASK", &mSap_conf.SENSOR_ALGORITHM_CONFIG_MASK, NULL, 'n'}
+};
+
+void ContextBase::readConfig()
+{
+ static bool confReadDone = false;
+ if (!confReadDone) {
+ confReadDone = true;
+ /*Defaults for gps.conf*/
+ mGps_conf.INTERMEDIATE_POS = 0;
+ mGps_conf.ACCURACY_THRES = 0;
+ mGps_conf.NMEA_PROVIDER = 0;
+ mGps_conf.GPS_LOCK = GNSS_CONFIG_GPS_LOCK_MO_AND_NI;
+ mGps_conf.SUPL_VER = 0x10000;
+ mGps_conf.SUPL_MODE = 0x1;
+ mGps_conf.SUPL_ES = 0;
+ mGps_conf.CP_MTLR_ES = 0;
+ mGps_conf.SUPL_HOST[0] = 0;
+ mGps_conf.SUPL_PORT = 0;
+ mGps_conf.CAPABILITIES = 0x7;
+ /* LTE Positioning Profile configuration is disable by default*/
+ mGps_conf.LPP_PROFILE = 0;
+ /*By default no positioning protocol is selected on A-GLONASS system*/
+ mGps_conf.A_GLONASS_POS_PROTOCOL_SELECT = 0;
+ /*XTRA version check is disabled by default*/
+ mGps_conf.XTRA_VERSION_CHECK=0;
+ /*Use emergency PDN by default*/
+ mGps_conf.USE_EMERGENCY_PDN_FOR_EMERGENCY_SUPL = 1;
+ /* By default no LPPe CP technology is enabled*/
+ mGps_conf.LPPE_CP_TECHNOLOGY = 0;
+ /* By default no LPPe UP technology is enabled*/
+ mGps_conf.LPPE_UP_TECHNOLOGY = 0;
+ /* By default we use unknown modem type*/
+ mGps_conf.MODEM_TYPE = 2;
+
+ /*Defaults for sap.conf*/
+ mSap_conf.GYRO_BIAS_RANDOM_WALK = 0;
+ mSap_conf.SENSOR_ACCEL_BATCHES_PER_SEC = 2;
+ mSap_conf.SENSOR_ACCEL_SAMPLES_PER_BATCH = 5;
+ mSap_conf.SENSOR_GYRO_BATCHES_PER_SEC = 2;
+ mSap_conf.SENSOR_GYRO_SAMPLES_PER_BATCH = 5;
+ mSap_conf.SENSOR_ACCEL_BATCHES_PER_SEC_HIGH = 4;
+ mSap_conf.SENSOR_ACCEL_SAMPLES_PER_BATCH_HIGH = 25;
+ mSap_conf.SENSOR_GYRO_BATCHES_PER_SEC_HIGH = 4;
+ mSap_conf.SENSOR_GYRO_SAMPLES_PER_BATCH_HIGH = 25;
+ mSap_conf.SENSOR_CONTROL_MODE = 0; /* AUTO */
+ mSap_conf.SENSOR_ALGORITHM_CONFIG_MASK = 0; /* INS Disabled = FALSE*/
+ /* Values MUST be set by OEMs in configuration for sensor-assisted
+ navigation to work. There are NO default values */
+ mSap_conf.ACCEL_RANDOM_WALK_SPECTRAL_DENSITY = 0;
+ mSap_conf.ANGLE_RANDOM_WALK_SPECTRAL_DENSITY = 0;
+ mSap_conf.RATE_RANDOM_WALK_SPECTRAL_DENSITY = 0;
+ mSap_conf.VELOCITY_RANDOM_WALK_SPECTRAL_DENSITY = 0;
+ mSap_conf.GYRO_BIAS_RANDOM_WALK_VALID = 0;
+ mSap_conf.ACCEL_RANDOM_WALK_SPECTRAL_DENSITY_VALID = 0;
+ mSap_conf.ANGLE_RANDOM_WALK_SPECTRAL_DENSITY_VALID = 0;
+ mSap_conf.RATE_RANDOM_WALK_SPECTRAL_DENSITY_VALID = 0;
+ mSap_conf.VELOCITY_RANDOM_WALK_SPECTRAL_DENSITY_VALID = 0;
+
+ /* None of the 10 slots for agps certificates are writable by default */
+ mGps_conf.AGPS_CERT_WRITABLE_MASK = 0;
+
+ /* inject supl config to modem with config values from config.xml or gps.conf, default 1 */
+ mGps_conf.AGPS_CONFIG_INJECT = 1;
+
+ /* default configuration value of constrained time uncertainty mode:
+ feature disabled, time uncertainty threshold defined by modem,
+ and unlimited power budget */
+ mGps_conf.CONSTRAINED_TIME_UNCERTAINTY_ENABLED = 0;
+ mGps_conf.CONSTRAINED_TIME_UNCERTAINTY_THRESHOLD = 0.0;
+ mGps_conf.CONSTRAINED_TIME_UNCERTAINTY_ENERGY_BUDGET = 0;
+ /* default configuration value of position assisted clock estimator mode */
+ mGps_conf.POSITION_ASSISTED_CLOCK_ESTIMATOR_ENABLED = 0;
+ /* default configuration QTI GNSS H/W */
+ mGps_conf.GNSS_DEPLOYMENT = 0;
+
+ UTIL_READ_CONF(LOC_PATH_GPS_CONF, mGps_conf_table);
+ UTIL_READ_CONF(LOC_PATH_SAP_CONF, mSap_conf_table);
+
+ LOC_LOGI("%s] GNSS Deployment: %s", __FUNCTION__,
+ ((mGps_conf.GNSS_DEPLOYMENT == 1) ? "SS5" :
+ ((mGps_conf.GNSS_DEPLOYMENT == 2) ? "QFUSION" : "QGNSS")));
+
+ switch (getTargetGnssType(loc_get_target())) {
+ case GNSS_GSS:
+ case GNSS_AUTO:
+ // For APQ targets, MSA/MSB capabilities should be reset
+ mGps_conf.CAPABILITIES &= ~(LOC_GPS_CAPABILITY_MSA | LOC_GPS_CAPABILITY_MSB);
+ break;
+ default:
+ break;
+ }
+ }
+}
+
+uint32_t ContextBase::getCarrierCapabilities() {
+ #define carrierMSA (uint32_t)0x2
+ #define carrierMSB (uint32_t)0x1
+ #define gpsConfMSA (uint32_t)0x4
+ #define gpsConfMSB (uint32_t)0x2
+ uint32_t capabilities = mGps_conf.CAPABILITIES;
+ if ((mGps_conf.SUPL_MODE & carrierMSA) != carrierMSA) {
+ capabilities &= ~gpsConfMSA;
+ }
+ if ((mGps_conf.SUPL_MODE & carrierMSB) != carrierMSB) {
+ capabilities &= ~gpsConfMSB;
+ }
+
+ LOC_LOGV("getCarrierCapabilities: CAPABILITIES %x, SUPL_MODE %x, carrier capabilities %x",
+ mGps_conf.CAPABILITIES, mGps_conf.SUPL_MODE, capabilities);
+ return capabilities;
+}
+
+LBSProxyBase* ContextBase::getLBSProxy(const char* libName)
+{
+ LBSProxyBase* proxy = NULL;
+ LOC_LOGD("%s:%d]: getLBSProxy libname: %s\n", __func__, __LINE__, libName);
+ void* lib = dlopen(libName, RTLD_NOW);
+
+ if ((void*)NULL != lib) {
+ getLBSProxy_t* getter = (getLBSProxy_t*)dlsym(lib, "getLBSProxy");
+ if (NULL != getter) {
+ proxy = (*getter)();
+ }
+ }
+ else
+ {
+ LOC_LOGW("%s:%d]: FAILED TO LOAD libname: %s\n", __func__, __LINE__, libName);
+ }
+ if (NULL == proxy) {
+ proxy = new LBSProxyBase();
+ }
+ LOC_LOGD("%s:%d]: Exiting\n", __func__, __LINE__);
+ return proxy;
+}
+
+LocApiBase* ContextBase::createLocApi(LOC_API_ADAPTER_EVENT_MASK_T exMask)
+{
+ LocApiBase* locApi = NULL;
+ const char* libname = LOC_APIV2_0_LIB_NAME;
+
+ // Check the target
+ if (TARGET_NO_GNSS != loc_get_target()){
+
+ if (NULL == (locApi = mLBSProxy->getLocApi(exMask, this))) {
+ void *handle = NULL;
+
+ if (IS_SS5_HW_ENABLED == mGps_conf.GNSS_DEPLOYMENT) {
+ libname = SLL_LOC_API_LIB_NAME;
+ }
+
+ if ((handle = dlopen(libname, RTLD_NOW)) != NULL) {
+ LOC_LOGD("%s:%d]: %s is present", __func__, __LINE__, libname);
+ getLocApi_t* getter = (getLocApi_t*) dlsym(handle, "getLocApi");
+ if (getter != NULL) {
+ LOC_LOGD("%s:%d]: getter is not NULL of %s", __func__,
+ __LINE__, libname);
+ locApi = (*getter)(exMask, this);
+ }
+ }
+ // only RPC is the option now
+ else {
+ LOC_LOGD("%s:%d]: libloc_api_v02.so is NOT present. Trying RPC",
+ __func__, __LINE__);
+ handle = dlopen("libloc_api-rpc-qc.so", RTLD_NOW);
+ if (NULL != handle) {
+ getLocApi_t* getter = (getLocApi_t*) dlsym(handle, "getLocApi");
+ if (NULL != getter) {
+ LOC_LOGD("%s:%d]: getter is not NULL in RPC", __func__,
+ __LINE__);
+ locApi = (*getter)(exMask, this);
+ }
+ }
+ }
+ }
+ }
+
+ // locApi could still be NULL at this time
+ // we would then create a dummy one
+ if (NULL == locApi) {
+ locApi = new LocApiBase(exMask, this);
+ }
+
+ return locApi;
+}
+
+ContextBase::ContextBase(const MsgTask* msgTask,
+ LOC_API_ADAPTER_EVENT_MASK_T exMask,
+ const char* libName) :
+ mLBSProxy(getLBSProxy(libName)),
+ mMsgTask(msgTask),
+ mLocApi(createLocApi(exMask)),
+ mLocApiProxy(mLocApi->getLocApiProxy())
+{
+}
+
+void ContextBase::setEngineCapabilities(uint64_t supportedMsgMask,
+ uint8_t *featureList, bool gnssMeasurementSupported) {
+
+ if (ContextBase::sIsEngineCapabilitiesKnown == false) {
+ ContextBase::sSupportedMsgMask = supportedMsgMask;
+ ContextBase::sGnssMeasurementSupported = gnssMeasurementSupported;
+ if (featureList != NULL) {
+ memcpy((void *)ContextBase::sFeaturesSupported,
+ (void *)featureList, sizeof(ContextBase::sFeaturesSupported));
+ }
+
+ ContextBase::sIsEngineCapabilitiesKnown = true;
+ }
+}
+
+
+bool ContextBase::isFeatureSupported(uint8_t featureVal)
+{
+ uint8_t arrayIndex = featureVal >> 3;
+ uint8_t bitPos = featureVal & 7;
+
+ if (arrayIndex >= MAX_FEATURE_LENGTH) return false;
+ return ((ContextBase::sFeaturesSupported[arrayIndex] >> bitPos ) & 0x1);
+}
+
+bool ContextBase::gnssConstellationConfig() {
+ return sGnssMeasurementSupported;
+}
+
+}
diff --git a/core/ContextBase.h b/core/ContextBase.h
new file mode 100644
index 0000000..5da76e2
--- /dev/null
+++ b/core/ContextBase.h
@@ -0,0 +1,260 @@
+/* Copyright (c) 2011-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 __LOC_CONTEXT_BASE__
+#define __LOC_CONTEXT_BASE__
+
+#include <stdbool.h>
+#include <ctype.h>
+#include <MsgTask.h>
+#include <LocApiBase.h>
+#include <LBSProxyBase.h>
+#include <loc_cfg.h>
+
+/* GPS.conf support */
+/* NOTE: the implementaiton of the parser casts number
+ fields to 32 bit. To ensure all 'n' fields working,
+ they must all be 32 bit fields. */
+typedef struct loc_gps_cfg_s
+{
+ uint32_t INTERMEDIATE_POS;
+ uint32_t ACCURACY_THRES;
+ uint32_t SUPL_VER;
+ uint32_t SUPL_MODE;
+ uint32_t SUPL_ES;
+ uint32_t CAPABILITIES;
+ uint32_t LPP_PROFILE;
+ uint32_t XTRA_VERSION_CHECK;
+ char XTRA_SERVER_1[LOC_MAX_PARAM_STRING];
+ char XTRA_SERVER_2[LOC_MAX_PARAM_STRING];
+ char XTRA_SERVER_3[LOC_MAX_PARAM_STRING];
+ uint32_t USE_EMERGENCY_PDN_FOR_EMERGENCY_SUPL;
+ uint32_t NMEA_PROVIDER;
+ GnssConfigGpsLock GPS_LOCK;
+ uint32_t A_GLONASS_POS_PROTOCOL_SELECT;
+ uint32_t AGPS_CERT_WRITABLE_MASK;
+ uint32_t AGPS_CONFIG_INJECT;
+ uint32_t LPPE_CP_TECHNOLOGY;
+ uint32_t LPPE_UP_TECHNOLOGY;
+ uint32_t EXTERNAL_DR_ENABLED;
+ char SUPL_HOST[LOC_MAX_PARAM_STRING];
+ uint32_t SUPL_PORT;
+ uint32_t MODEM_TYPE;
+ char MO_SUPL_HOST[LOC_MAX_PARAM_STRING];
+ uint32_t MO_SUPL_PORT;
+ uint32_t CONSTRAINED_TIME_UNCERTAINTY_ENABLED;
+ double CONSTRAINED_TIME_UNCERTAINTY_THRESHOLD;
+ uint32_t CONSTRAINED_TIME_UNCERTAINTY_ENERGY_BUDGET;
+ uint32_t POSITION_ASSISTED_CLOCK_ESTIMATOR_ENABLED;
+ char PROXY_APP_PACKAGE_NAME[LOC_MAX_PARAM_STRING];
+ uint32_t CP_MTLR_ES;
+ uint32_t GNSS_DEPLOYMENT;
+} loc_gps_cfg_s_type;
+
+/* NOTE: the implementaiton of the parser casts number
+ fields to 32 bit. To ensure all 'n' fields working,
+ they must all be 32 bit fields. */
+/* Meanwhile, *_valid fields are 8 bit fields, and 'f'
+ fields are double. Rigid as they are, it is the
+ the status quo, until the parsing mechanism is
+ change, that is. */
+typedef struct
+{
+ uint8_t GYRO_BIAS_RANDOM_WALK_VALID;
+ double GYRO_BIAS_RANDOM_WALK;
+ uint32_t SENSOR_ACCEL_BATCHES_PER_SEC;
+ uint32_t SENSOR_ACCEL_SAMPLES_PER_BATCH;
+ uint32_t SENSOR_GYRO_BATCHES_PER_SEC;
+ uint32_t SENSOR_GYRO_SAMPLES_PER_BATCH;
+ uint32_t SENSOR_ACCEL_BATCHES_PER_SEC_HIGH;
+ uint32_t SENSOR_ACCEL_SAMPLES_PER_BATCH_HIGH;
+ uint32_t SENSOR_GYRO_BATCHES_PER_SEC_HIGH;
+ uint32_t SENSOR_GYRO_SAMPLES_PER_BATCH_HIGH;
+ uint32_t SENSOR_CONTROL_MODE;
+ uint32_t SENSOR_ALGORITHM_CONFIG_MASK;
+ uint8_t ACCEL_RANDOM_WALK_SPECTRAL_DENSITY_VALID;
+ double ACCEL_RANDOM_WALK_SPECTRAL_DENSITY;
+ uint8_t ANGLE_RANDOM_WALK_SPECTRAL_DENSITY_VALID;
+ double ANGLE_RANDOM_WALK_SPECTRAL_DENSITY;
+ uint8_t RATE_RANDOM_WALK_SPECTRAL_DENSITY_VALID;
+ double RATE_RANDOM_WALK_SPECTRAL_DENSITY;
+ uint8_t VELOCITY_RANDOM_WALK_SPECTRAL_DENSITY_VALID;
+ double VELOCITY_RANDOM_WALK_SPECTRAL_DENSITY;
+} loc_sap_cfg_s_type;
+
+namespace loc_core {
+
+class LocAdapterBase;
+
+class ContextBase {
+ static LBSProxyBase* getLBSProxy(const char* libName);
+ LocApiBase* createLocApi(LOC_API_ADAPTER_EVENT_MASK_T excludedMask);
+ static const loc_param_s_type mGps_conf_table[];
+ static const loc_param_s_type mSap_conf_table[];
+protected:
+ const LBSProxyBase* mLBSProxy;
+ const MsgTask* mMsgTask;
+ LocApiBase* mLocApi;
+ LocApiProxyBase *mLocApiProxy;
+
+public:
+ ContextBase(const MsgTask* msgTask,
+ LOC_API_ADAPTER_EVENT_MASK_T exMask,
+ const char* libName);
+ inline virtual ~ContextBase() {
+ if (nullptr != mLocApi) {
+ mLocApi->destroy();
+ mLocApi = nullptr;
+ }
+ if (nullptr != mLBSProxy) {
+ delete mLBSProxy;
+ mLBSProxy = nullptr;
+ }
+ }
+
+ inline const MsgTask* getMsgTask() { return mMsgTask; }
+ inline LocApiBase* getLocApi() { return mLocApi; }
+ inline LocApiProxyBase* getLocApiProxy() { return mLocApiProxy; }
+ inline bool hasAgpsExtendedCapabilities() { return mLBSProxy->hasAgpsExtendedCapabilities(); }
+ inline bool hasNativeXtraClient() { return mLBSProxy->hasNativeXtraClient(); }
+ inline void modemPowerVote(bool power) const { return mLBSProxy->modemPowerVote(power); }
+ inline IzatDevId_t getIzatDevId() const {
+ return mLBSProxy->getIzatDevId();
+ }
+ inline void sendMsg(const LocMsg *msg) { getMsgTask()->sendMsg(msg); }
+
+ static loc_gps_cfg_s_type mGps_conf;
+ static loc_sap_cfg_s_type mSap_conf;
+ static bool sIsEngineCapabilitiesKnown;
+ static uint64_t sSupportedMsgMask;
+ static uint8_t sFeaturesSupported[MAX_FEATURE_LENGTH];
+ static bool sGnssMeasurementSupported;
+
+ void readConfig();
+ static uint32_t getCarrierCapabilities();
+ void setEngineCapabilities(uint64_t supportedMsgMask,
+ uint8_t *featureList, bool gnssMeasurementSupported);
+
+ static inline bool isEngineCapabilitiesKnown() {
+ return sIsEngineCapabilitiesKnown;
+ }
+
+ static inline bool isMessageSupported(LocCheckingMessagesID msgID) {
+
+ // confirm if msgID is not larger than the number of bits in
+ // mSupportedMsg
+ if ((uint64_t)msgID > (sizeof(sSupportedMsgMask) << 3)) {
+ return false;
+ } else {
+ uint32_t messageChecker = 1 << msgID;
+ return (messageChecker & sSupportedMsgMask) == messageChecker;
+ }
+ }
+
+ /*
+ Check if a feature is supported
+ */
+ static bool isFeatureSupported(uint8_t featureVal);
+
+ /*
+ Check if gnss measurement is supported
+ */
+ static bool gnssConstellationConfig();
+
+};
+
+struct LocApiResponse: LocMsg {
+ private:
+ ContextBase& mContext;
+ std::function<void (LocationError err)> mProcImpl;
+ inline virtual void proc() const {
+ mProcImpl(mLocationError);
+ }
+ protected:
+ LocationError mLocationError;
+ public:
+ inline LocApiResponse(ContextBase& context,
+ std::function<void (LocationError err)> procImpl ) :
+ mContext(context), mProcImpl(procImpl) {}
+
+ void returnToSender(const LocationError err) {
+ mLocationError = err;
+ mContext.sendMsg(this);
+ }
+};
+
+struct LocApiCollectiveResponse: LocMsg {
+ private:
+ ContextBase& mContext;
+ std::function<void (std::vector<LocationError> errs)> mProcImpl;
+ inline virtual void proc() const {
+ mProcImpl(mLocationErrors);
+ }
+ protected:
+ std::vector<LocationError> mLocationErrors;
+ public:
+ inline LocApiCollectiveResponse(ContextBase& context,
+ std::function<void (std::vector<LocationError> errs)> procImpl ) :
+ mContext(context), mProcImpl(procImpl) {}
+ inline virtual ~LocApiCollectiveResponse() {
+ }
+
+ void returnToSender(std::vector<LocationError>& errs) {
+ mLocationErrors = errs;
+ mContext.sendMsg(this);
+ }
+};
+
+
+template <typename DATA>
+struct LocApiResponseData: LocMsg {
+ private:
+ ContextBase& mContext;
+ std::function<void (LocationError err, DATA data)> mProcImpl;
+ inline virtual void proc() const {
+ mProcImpl(mLocationError, mData);
+ }
+ protected:
+ LocationError mLocationError;
+ DATA mData;
+ public:
+ inline LocApiResponseData(ContextBase& context,
+ std::function<void (LocationError err, DATA data)> procImpl ) :
+ mContext(context), mProcImpl(procImpl) {}
+
+ void returnToSender(const LocationError err, const DATA data) {
+ mLocationError = err;
+ mData = data;
+ mContext.sendMsg(this);
+ }
+};
+
+
+} // namespace loc_core
+
+#endif //__LOC_CONTEXT_BASE__
diff --git a/core/EngineHubProxyBase.h b/core/EngineHubProxyBase.h
new file mode 100644
index 0000000..ec881f6
--- /dev/null
+++ b/core/EngineHubProxyBase.h
@@ -0,0 +1,127 @@
+/* Copyright (c) 2018, 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 ENGINE_HUB_PROXY_BASE_H
+#define ENGINE_HUB_PROXY_BASE_H
+
+namespace loc_core {
+
+class EngineHubProxyBase {
+public:
+ inline EngineHubProxyBase() {
+ }
+ inline virtual ~EngineHubProxyBase() {}
+
+ // gnss session related functions
+ inline virtual bool gnssStartFix() {
+ return false;
+ }
+
+ inline virtual bool gnssStopFix() {
+ return false;
+ }
+
+ inline virtual bool gnssSetFixMode(const LocPosMode &params) {
+ (void) params;
+ return false;
+ }
+
+ inline virtual bool gnssDeleteAidingData(const GnssAidingData &aidingData) {
+ (void) aidingData;
+ return false;
+ }
+
+ // GNSS reports
+ inline virtual bool gnssReportPosition(const UlpLocation &location,
+ const GpsLocationExtended &locationExtended,
+ enum loc_sess_status status) {
+ (void) location;
+ (void) locationExtended;
+ (void) status;
+ return false;
+ }
+
+ inline virtual bool gnssReportSv(const GnssSvNotification& svNotify) {
+ (void) svNotify;
+ return false;
+ }
+
+ inline virtual bool gnssReportSvMeasurement(const GnssSvMeasurementSet& svMeasurementSet) {
+ (void) svMeasurementSet;
+ return false;
+ }
+
+ inline virtual bool gnssReportSvPolynomial(const GnssSvPolynomial& svPolynomial) {
+ (void) svPolynomial;
+ return false;
+ }
+
+ inline virtual bool gnssReportSvEphemeris(const GnssSvEphemerisReport& svEphemeris) {
+ (void) svEphemeris;
+ return false;
+ }
+
+ inline virtual bool gnssReportSystemInfo(const LocationSystemInfo& systemInfo) {
+ (void) systemInfo;
+ return false;
+ }
+
+ inline virtual bool gnssReportKlobucharIonoModel(const GnssKlobucharIonoModel& ionoModel) {
+ (void) ionoModel;
+ return false;
+ }
+
+ inline virtual bool gnssReportAdditionalSystemInfo(
+ const GnssAdditionalSystemInfo& additionalSystemInfo) {
+ (void) additionalSystemInfo;
+ return false;
+ }
+};
+
+typedef std::function<void(int count, EngineLocationInfo* locationArr)>
+ GnssAdapterReportEnginePositionsEventCb;
+
+typedef std::function<void(const GnssSvNotification& svNotify,
+ bool fromEngineHub)>
+ GnssAdapterReportSvEventCb;
+
+typedef std::function<void(const GnssAidingDataSvMask& svDataMask)>
+ GnssAdapterReqAidingDataCb;
+
+// potential parameters: message queue: MsgTask * msgTask;
+// callback function to report back dr and ppe position and sv report
+typedef EngineHubProxyBase* (getEngHubProxyFn)(
+ const MsgTask * msgTask,
+ IOsObserver* osObserver,
+ GnssAdapterReportEnginePositionsEventCb positionEventCb,
+ GnssAdapterReportSvEventCb svEventCb,
+ GnssAdapterReqAidingDataCb reqAidingDataCb);
+
+} // namespace loc_core
+
+#endif // ENGINE_HUB_PROXY_BASE_H
diff --git a/core/LBSProxyBase.h b/core/LBSProxyBase.h
new file mode 100644
index 0000000..564c60b
--- /dev/null
+++ b/core/LBSProxyBase.h
@@ -0,0 +1,70 @@
+/* Copyright (c) 2013-2015, 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 IZAT_PROXY_BASE_H
+#define IZAT_PROXY_BASE_H
+#include <gps_extended.h>
+
+namespace loc_core {
+
+class LocApiBase;
+class LocAdapterBase;
+class ContextBase;
+
+class LBSProxyBase {
+ friend class ContextBase;
+ inline virtual LocApiBase*
+ getLocApi(LOC_API_ADAPTER_EVENT_MASK_T exMask,
+ ContextBase* context) const {
+
+ (void)exMask;
+ (void)context;
+ return NULL;
+ }
+protected:
+ inline LBSProxyBase() {}
+public:
+ inline virtual ~LBSProxyBase() {}
+ inline virtual bool hasAgpsExtendedCapabilities() const { return false; }
+ inline virtual void modemPowerVote(bool power) const {
+
+ (void)power;
+ }
+ virtual void injectFeatureConfig(ContextBase* context) const {
+
+ (void)context;
+ }
+ inline virtual bool hasNativeXtraClient() const { return false; }
+ inline virtual IzatDevId_t getIzatDevId() const { return 0; }
+};
+
+typedef LBSProxyBase* (getLBSProxy_t)();
+
+} // namespace loc_core
+
+#endif // IZAT_PROXY_BASE_H
diff --git a/core/LocAdapterBase.cpp b/core/LocAdapterBase.cpp
new file mode 100644
index 0000000..1b844e5
--- /dev/null
+++ b/core/LocAdapterBase.cpp
@@ -0,0 +1,411 @@
+/* Copyright (c) 2011-2014, 2016-2019 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_NDEBUG 0
+#define LOG_TAG "LocSvc_LocAdapterBase"
+
+#include <dlfcn.h>
+#include <LocAdapterBase.h>
+#include <loc_target.h>
+#include <log_util.h>
+#include <LocAdapterProxyBase.h>
+
+namespace loc_core {
+
+// This is the top level class, so the constructor will
+// always gets called. Here we prepare for the default.
+// But if getLocApi(targetEnumType target) is overriden,
+// the right locApi should get created.
+LocAdapterBase::LocAdapterBase(const LOC_API_ADAPTER_EVENT_MASK_T mask,
+ ContextBase* context, bool isMaster,
+ LocAdapterProxyBase *adapterProxyBase) :
+ mIsMaster(isMaster), mEvtMask(mask), mContext(context),
+ mLocApi(context->getLocApi()), mLocAdapterProxyBase(adapterProxyBase),
+ mMsgTask(context->getMsgTask()),
+ mIsEngineCapabilitiesKnown(ContextBase::sIsEngineCapabilitiesKnown)
+{
+ mLocApi->addAdapter(this);
+}
+
+uint32_t LocAdapterBase::mSessionIdCounter(1);
+
+uint32_t LocAdapterBase::generateSessionId()
+{
+ if (++mSessionIdCounter == 0xFFFFFFFF)
+ mSessionIdCounter = 1;
+
+ return mSessionIdCounter;
+}
+
+void LocAdapterBase::handleEngineUpEvent()
+{
+ if (mLocAdapterProxyBase) {
+ mLocAdapterProxyBase->handleEngineUpEvent();
+ }
+}
+
+void LocAdapterBase::handleEngineDownEvent()
+{
+ if (mLocAdapterProxyBase) {
+ mLocAdapterProxyBase->handleEngineDownEvent();
+ }
+}
+
+void LocAdapterBase::
+ reportPositionEvent(const UlpLocation& location,
+ const GpsLocationExtended& locationExtended,
+ enum loc_sess_status status,
+ LocPosTechMask loc_technology_mask,
+ GnssDataNotification* pDataNotify,
+ int msInWeek)
+{
+ if (mLocAdapterProxyBase != NULL) {
+ mLocAdapterProxyBase->reportPositionEvent((UlpLocation&)location,
+ (GpsLocationExtended&)locationExtended,
+ status,
+ loc_technology_mask);
+ } else {
+ DEFAULT_IMPL()
+ }
+}
+
+void LocAdapterBase::
+ reportSvEvent(const GnssSvNotification& /*svNotify*/,
+ bool /*fromEngineHub*/)
+DEFAULT_IMPL()
+
+void LocAdapterBase::
+ reportSvPolynomialEvent(GnssSvPolynomial &/*svPolynomial*/)
+DEFAULT_IMPL()
+
+void LocAdapterBase::
+ reportSvEphemerisEvent(GnssSvEphemerisReport &/*svEphemeris*/)
+DEFAULT_IMPL()
+
+
+void LocAdapterBase::
+ reportStatus(LocGpsStatusValue /*status*/)
+DEFAULT_IMPL()
+
+
+void LocAdapterBase::
+ reportNmeaEvent(const char* /*nmea*/, size_t /*length*/)
+DEFAULT_IMPL()
+
+void LocAdapterBase::
+ reportDataEvent(const GnssDataNotification& /*dataNotify*/,
+ int /*msInWeek*/)
+DEFAULT_IMPL()
+
+bool LocAdapterBase::
+ reportXtraServer(const char* /*url1*/, const char* /*url2*/,
+ const char* /*url3*/, const int /*maxlength*/)
+DEFAULT_IMPL(false)
+
+void LocAdapterBase::
+ reportLocationSystemInfoEvent(const LocationSystemInfo& /*locationSystemInfo*/)
+DEFAULT_IMPL()
+
+bool LocAdapterBase::
+ requestXtraData()
+DEFAULT_IMPL(false)
+
+bool LocAdapterBase::
+ requestTime()
+DEFAULT_IMPL(false)
+
+bool LocAdapterBase::
+ requestLocation()
+DEFAULT_IMPL(false)
+
+bool LocAdapterBase::
+ requestATL(int /*connHandle*/, LocAGpsType /*agps_type*/,
+ LocApnTypeMask /*apn_type_mask*/)
+DEFAULT_IMPL(false)
+
+bool LocAdapterBase::
+ releaseATL(int /*connHandle*/)
+DEFAULT_IMPL(false)
+
+bool LocAdapterBase::
+ requestNiNotifyEvent(const GnssNiNotification &/*notify*/,
+ const void* /*data*/,
+ const LocInEmergency emergencyState)
+DEFAULT_IMPL(false)
+
+void LocAdapterBase::
+reportGnssMeasurementsEvent(const GnssMeasurements& /*gnssMeasurements*/,
+ int /*msInWeek*/)
+DEFAULT_IMPL()
+
+bool LocAdapterBase::
+ reportWwanZppFix(LocGpsLocation &/*zppLoc*/)
+DEFAULT_IMPL(false)
+
+bool LocAdapterBase::
+ reportZppBestAvailableFix(LocGpsLocation& /*zppLoc*/,
+ GpsLocationExtended& /*location_extended*/, LocPosTechMask /*tech_mask*/)
+DEFAULT_IMPL(false)
+
+void LocAdapterBase::reportGnssSvIdConfigEvent(const GnssSvIdConfig& /*config*/)
+DEFAULT_IMPL()
+
+void LocAdapterBase::reportGnssSvTypeConfigEvent(const GnssSvTypeConfig& /*config*/)
+DEFAULT_IMPL()
+
+bool LocAdapterBase::
+ requestOdcpiEvent(OdcpiRequestInfo& /*request*/)
+DEFAULT_IMPL(false)
+
+bool LocAdapterBase::
+ reportGnssEngEnergyConsumedEvent(uint64_t /*energyConsumedSinceFirstBoot*/)
+DEFAULT_IMPL(false)
+
+bool LocAdapterBase::
+ reportDeleteAidingDataEvent(GnssAidingData & /*aidingData*/)
+DEFAULT_IMPL(false)
+
+bool LocAdapterBase::
+ reportKlobucharIonoModelEvent(GnssKlobucharIonoModel& /*ionoModel*/)
+DEFAULT_IMPL(false)
+
+bool LocAdapterBase::
+ reportGnssAdditionalSystemInfoEvent(GnssAdditionalSystemInfo& /*additionalSystemInfo*/)
+DEFAULT_IMPL(false)
+
+void LocAdapterBase::
+ reportNfwNotificationEvent(GnssNfwNotification& /*notification*/)
+DEFAULT_IMPL()
+
+void
+LocAdapterBase::geofenceBreachEvent(size_t /*count*/, uint32_t* /*hwIds*/, Location& /*location*/,
+ GeofenceBreachType /*breachType*/, uint64_t /*timestamp*/)
+DEFAULT_IMPL()
+
+void
+LocAdapterBase::geofenceStatusEvent(GeofenceStatusAvailable /*available*/)
+DEFAULT_IMPL()
+
+void
+LocAdapterBase::reportLocationsEvent(const Location* /*locations*/, size_t /*count*/,
+ BatchingMode /*batchingMode*/)
+DEFAULT_IMPL()
+
+void
+LocAdapterBase::reportCompletedTripsEvent(uint32_t /*accumulated_distance*/)
+DEFAULT_IMPL()
+
+void
+LocAdapterBase::reportBatchStatusChangeEvent(BatchingStatus /*batchStatus*/)
+DEFAULT_IMPL()
+
+void
+LocAdapterBase::reportPositionEvent(UlpLocation& /*location*/,
+ GpsLocationExtended& /*locationExtended*/,
+ enum loc_sess_status /*status*/,
+ LocPosTechMask /*loc_technology_mask*/)
+DEFAULT_IMPL()
+
+void
+LocAdapterBase::saveClient(LocationAPI* client, const LocationCallbacks& callbacks)
+{
+ mClientData[client] = callbacks;
+ updateClientsEventMask();
+}
+
+void
+LocAdapterBase::eraseClient(LocationAPI* client)
+{
+ auto it = mClientData.find(client);
+ if (it != mClientData.end()) {
+ mClientData.erase(it);
+ }
+ updateClientsEventMask();
+}
+
+LocationCallbacks
+LocAdapterBase::getClientCallbacks(LocationAPI* client)
+{
+ LocationCallbacks callbacks = {};
+ auto it = mClientData.find(client);
+ if (it != mClientData.end()) {
+ callbacks = it->second;
+ }
+ return callbacks;
+}
+
+LocationCapabilitiesMask
+LocAdapterBase::getCapabilities()
+{
+ LocationCapabilitiesMask mask = 0;
+
+ if (isEngineCapabilitiesKnown()) {
+ // time based tracking always supported
+ mask |= LOCATION_CAPABILITIES_TIME_BASED_TRACKING_BIT;
+ if (ContextBase::isMessageSupported(
+ LOC_API_ADAPTER_MESSAGE_DISTANCE_BASE_LOCATION_BATCHING)){
+ mask |= LOCATION_CAPABILITIES_TIME_BASED_BATCHING_BIT |
+ LOCATION_CAPABILITIES_DISTANCE_BASED_BATCHING_BIT;
+ }
+ if (ContextBase::isMessageSupported(LOC_API_ADAPTER_MESSAGE_DISTANCE_BASE_TRACKING)) {
+ mask |= LOCATION_CAPABILITIES_DISTANCE_BASED_TRACKING_BIT;
+ }
+ if (ContextBase::isMessageSupported(LOC_API_ADAPTER_MESSAGE_OUTDOOR_TRIP_BATCHING)) {
+ mask |= LOCATION_CAPABILITIES_OUTDOOR_TRIP_BATCHING_BIT;
+ }
+ // geofence always supported
+ mask |= LOCATION_CAPABILITIES_GEOFENCE_BIT;
+ if (ContextBase::gnssConstellationConfig()) {
+ mask |= LOCATION_CAPABILITIES_GNSS_MEASUREMENTS_BIT;
+ }
+ uint32_t carrierCapabilities = ContextBase::getCarrierCapabilities();
+ if (carrierCapabilities & LOC_GPS_CAPABILITY_MSB) {
+ mask |= LOCATION_CAPABILITIES_GNSS_MSB_BIT;
+ }
+ if (LOC_GPS_CAPABILITY_MSA & carrierCapabilities) {
+ mask |= LOCATION_CAPABILITIES_GNSS_MSA_BIT;
+ }
+ if (ContextBase::isFeatureSupported(LOC_SUPPORTED_FEATURE_DEBUG_NMEA_V02)) {
+ mask |= LOCATION_CAPABILITIES_DEBUG_NMEA_BIT;
+ }
+ if (ContextBase::isFeatureSupported(LOC_SUPPORTED_FEATURE_CONSTELLATION_ENABLEMENT_V02)) {
+ mask |= LOCATION_CAPABILITIES_CONSTELLATION_ENABLEMENT_BIT;
+ }
+ if (ContextBase::isFeatureSupported(LOC_SUPPORTED_FEATURE_AGPM_V02)) {
+ mask |= LOCATION_CAPABILITIES_AGPM_BIT;
+ }
+ if (ContextBase::isFeatureSupported(LOC_SUPPORTED_FEATURE_LOCATION_PRIVACY)) {
+ mask |= LOCATION_CAPABILITIES_PRIVACY_BIT;
+ }
+ } else {
+ LOC_LOGE("%s]: attempt to get capabilities before they are known.", __func__);
+ }
+
+ return mask;
+}
+
+void
+LocAdapterBase::broadcastCapabilities(LocationCapabilitiesMask mask)
+{
+ for (auto clientData : mClientData) {
+ if (nullptr != clientData.second.capabilitiesCb) {
+ clientData.second.capabilitiesCb(mask);
+ }
+ }
+}
+
+void
+LocAdapterBase::updateClientsEventMask()
+DEFAULT_IMPL()
+
+void
+LocAdapterBase::stopClientSessions(LocationAPI* client)
+DEFAULT_IMPL()
+
+void
+LocAdapterBase::addClientCommand(LocationAPI* client, const LocationCallbacks& callbacks)
+{
+ LOC_LOGD("%s]: client %p", __func__, client);
+
+ struct MsgAddClient : public LocMsg {
+ LocAdapterBase& mAdapter;
+ LocationAPI* mClient;
+ const LocationCallbacks mCallbacks;
+ inline MsgAddClient(LocAdapterBase& adapter,
+ LocationAPI* client,
+ const LocationCallbacks& callbacks) :
+ LocMsg(),
+ mAdapter(adapter),
+ mClient(client),
+ mCallbacks(callbacks) {}
+ inline virtual void proc() const {
+ mAdapter.saveClient(mClient, mCallbacks);
+ }
+ };
+
+ sendMsg(new MsgAddClient(*this, client, callbacks));
+}
+
+void
+LocAdapterBase::removeClientCommand(LocationAPI* client,
+ removeClientCompleteCallback rmClientCb)
+{
+ LOC_LOGD("%s]: client %p", __func__, client);
+
+ struct MsgRemoveClient : public LocMsg {
+ LocAdapterBase& mAdapter;
+ LocationAPI* mClient;
+ removeClientCompleteCallback mRmClientCb;
+ inline MsgRemoveClient(LocAdapterBase& adapter,
+ LocationAPI* client,
+ removeClientCompleteCallback rmCb) :
+ LocMsg(),
+ mAdapter(adapter),
+ mClient(client),
+ mRmClientCb(rmCb){}
+ inline virtual void proc() const {
+ mAdapter.stopClientSessions(mClient);
+ mAdapter.eraseClient(mClient);
+ if (nullptr != mRmClientCb) {
+ (mRmClientCb)(mClient);
+ }
+ }
+ };
+
+ sendMsg(new MsgRemoveClient(*this, client, rmClientCb));
+}
+
+void
+LocAdapterBase::requestCapabilitiesCommand(LocationAPI* client)
+{
+ LOC_LOGD("%s]: ", __func__);
+
+ struct MsgRequestCapabilities : public LocMsg {
+ LocAdapterBase& mAdapter;
+ LocationAPI* mClient;
+ inline MsgRequestCapabilities(LocAdapterBase& adapter,
+ LocationAPI* client) :
+ LocMsg(),
+ mAdapter(adapter),
+ mClient(client) {}
+ inline virtual void proc() const {
+ if (!mAdapter.isEngineCapabilitiesKnown()) {
+ mAdapter.mPendingMsgs.push_back(new MsgRequestCapabilities(*this));
+ return;
+ }
+ LocationCallbacks callbacks = mAdapter.getClientCallbacks(mClient);
+ if (callbacks.capabilitiesCb != nullptr) {
+ callbacks.capabilitiesCb(mAdapter.getCapabilities());
+ }
+ }
+ };
+
+ sendMsg(new MsgRequestCapabilities(*this, client));
+}
+
+} // namespace loc_core
diff --git a/core/LocAdapterBase.h b/core/LocAdapterBase.h
new file mode 100644
index 0000000..909b6fe
--- /dev/null
+++ b/core/LocAdapterBase.h
@@ -0,0 +1,222 @@
+/* Copyright (c) 2011-2014, 2016-2019 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 LOC_API_ADAPTER_BASE_H
+#define LOC_API_ADAPTER_BASE_H
+
+#include <gps_extended.h>
+#include <ContextBase.h>
+#include <LocationAPI.h>
+#include <map>
+
+#define MIN_TRACKING_INTERVAL (100) // 100 msec
+
+typedef struct LocationSessionKey {
+ LocationAPI* client;
+ uint32_t id;
+ inline LocationSessionKey(LocationAPI* _client, uint32_t _id) :
+ client(_client), id(_id) {}
+} LocationSessionKey;
+inline bool operator <(LocationSessionKey const& left, LocationSessionKey const& right) {
+ return left.id < right.id || (left.id == right.id && left.client < right.client);
+}
+inline bool operator ==(LocationSessionKey const& left, LocationSessionKey const& right) {
+ return left.id == right.id && left.client == right.client;
+}
+inline bool operator !=(LocationSessionKey const& left, LocationSessionKey const& right) {
+ return left.id != right.id || left.client != right.client;
+}
+
+typedef void (*removeClientCompleteCallback)(LocationAPI* client);
+
+namespace loc_core {
+
+class LocAdapterProxyBase;
+
+class LocAdapterBase {
+private:
+ static uint32_t mSessionIdCounter;
+ const bool mIsMaster;
+ bool mIsEngineCapabilitiesKnown = false;
+
+protected:
+ LOC_API_ADAPTER_EVENT_MASK_T mEvtMask;
+ ContextBase* mContext;
+ LocApiBase* mLocApi;
+ LocAdapterProxyBase* mLocAdapterProxyBase;
+ const MsgTask* mMsgTask;
+ inline LocAdapterBase(const MsgTask* msgTask) :
+ mIsMaster(false), mEvtMask(0), mContext(NULL), mLocApi(NULL),
+ mLocAdapterProxyBase(NULL), mMsgTask(msgTask) {}
+
+ /* ==== CLIENT ========================================================================= */
+ typedef std::map<LocationAPI*, LocationCallbacks> ClientDataMap;
+ ClientDataMap mClientData;
+ std::vector<LocMsg*> mPendingMsgs; // For temporal storage of msgs before Open is completed
+ /* ======== UTILITIES ================================================================== */
+ void saveClient(LocationAPI* client, const LocationCallbacks& callbacks);
+ void eraseClient(LocationAPI* client);
+ LocationCallbacks getClientCallbacks(LocationAPI* client);
+ LocationCapabilitiesMask getCapabilities();
+ void broadcastCapabilities(LocationCapabilitiesMask mask);
+ virtual void updateClientsEventMask();
+ virtual void stopClientSessions(LocationAPI* client);
+
+public:
+ inline virtual ~LocAdapterBase() { mLocApi->removeAdapter(this); }
+ LocAdapterBase(const LOC_API_ADAPTER_EVENT_MASK_T mask,
+ ContextBase* context, bool isMaster = false,
+ LocAdapterProxyBase *adapterProxyBase = NULL);
+
+ inline LOC_API_ADAPTER_EVENT_MASK_T
+ checkMask(LOC_API_ADAPTER_EVENT_MASK_T mask) const {
+ return mEvtMask & mask;
+ }
+
+ inline LOC_API_ADAPTER_EVENT_MASK_T getEvtMask() const {
+ return mEvtMask;
+ }
+
+ inline void sendMsg(const LocMsg* msg) const {
+ mMsgTask->sendMsg(msg);
+ }
+
+ inline void sendMsg(const LocMsg* msg) {
+ mMsgTask->sendMsg(msg);
+ }
+
+ inline void updateEvtMask(LOC_API_ADAPTER_EVENT_MASK_T event,
+ loc_registration_mask_status status)
+ {
+ switch(status) {
+ case (LOC_REGISTRATION_MASK_ENABLED):
+ mEvtMask = mEvtMask | event;
+ break;
+ case (LOC_REGISTRATION_MASK_DISABLED):
+ mEvtMask = mEvtMask &~ event;
+ break;
+ case (LOC_REGISTRATION_MASK_SET):
+ mEvtMask = event;
+ break;
+ }
+ mLocApi->updateEvtMask();
+ }
+
+ inline void updateNmeaMask(uint32_t mask)
+ {
+ mLocApi->updateNmeaMask(mask);
+ }
+
+ inline bool isFeatureSupported(uint8_t featureVal) {
+ return ContextBase::isFeatureSupported(featureVal);
+ }
+
+ uint32_t generateSessionId();
+
+ inline bool isAdapterMaster() {
+ return mIsMaster;
+ }
+
+ inline bool isEngineCapabilitiesKnown() { return mIsEngineCapabilitiesKnown;}
+ inline void setEngineCapabilitiesKnown(bool value) { mIsEngineCapabilitiesKnown = value;}
+
+ virtual void handleEngineUpEvent();
+ virtual void handleEngineDownEvent();
+ virtual void reportPositionEvent(const UlpLocation& location,
+ const GpsLocationExtended& locationExtended,
+ enum loc_sess_status status,
+ LocPosTechMask loc_technology_mask,
+ GnssDataNotification* pDataNotify = nullptr,
+ int msInWeek = -1);
+ virtual void reportEnginePositionsEvent(unsigned int count,
+ EngineLocationInfo* locationArr) {
+ (void)count;
+ (void)locationArr;
+ }
+ virtual void reportSvEvent(const GnssSvNotification& svNotify,
+ bool fromEngineHub=false);
+ virtual void reportDataEvent(const GnssDataNotification& dataNotify, int msInWeek);
+ virtual void reportNmeaEvent(const char* nmea, size_t length);
+ virtual void reportSvPolynomialEvent(GnssSvPolynomial &svPolynomial);
+ virtual void reportSvEphemerisEvent(GnssSvEphemerisReport &svEphemeris);
+ virtual void reportStatus(LocGpsStatusValue status);
+ virtual bool reportXtraServer(const char* url1, const char* url2,
+ const char* url3, const int maxlength);
+ virtual void reportLocationSystemInfoEvent(const LocationSystemInfo& locationSystemInfo);
+
+ virtual bool requestXtraData();
+ virtual bool requestTime();
+ virtual bool requestLocation();
+ virtual bool requestATL(int connHandle, LocAGpsType agps_type,
+ LocApnTypeMask apn_type_mask);
+ virtual bool releaseATL(int connHandle);
+ virtual bool requestNiNotifyEvent(const GnssNiNotification &notify, const void* data,
+ const LocInEmergency emergencyState);
+ inline virtual bool isInSession() { return false; }
+ ContextBase* getContext() const { return mContext; }
+ virtual void reportGnssMeasurementsEvent(const GnssMeasurements& gnssMeasurements,
+ int msInWeek);
+ virtual bool reportWwanZppFix(LocGpsLocation &zppLoc);
+ virtual bool reportZppBestAvailableFix(LocGpsLocation &zppLoc,
+ GpsLocationExtended &location_extended, LocPosTechMask tech_mask);
+ virtual void reportGnssSvIdConfigEvent(const GnssSvIdConfig& config);
+ virtual void reportGnssSvTypeConfigEvent(const GnssSvTypeConfig& config);
+ virtual bool requestOdcpiEvent(OdcpiRequestInfo& request);
+ virtual bool reportGnssEngEnergyConsumedEvent(uint64_t energyConsumedSinceFirstBoot);
+ virtual bool reportDeleteAidingDataEvent(GnssAidingData &aidingData);
+ virtual bool reportKlobucharIonoModelEvent(GnssKlobucharIonoModel& ionoModel);
+ virtual bool reportGnssAdditionalSystemInfoEvent(
+ GnssAdditionalSystemInfo& additionalSystemInfo);
+ virtual void reportNfwNotificationEvent(GnssNfwNotification& notification);
+
+ virtual void geofenceBreachEvent(size_t count, uint32_t* hwIds, Location& location,
+ GeofenceBreachType breachType, uint64_t timestamp);
+ virtual void geofenceStatusEvent(GeofenceStatusAvailable available);
+
+ virtual void reportPositionEvent(UlpLocation &location,
+ GpsLocationExtended &locationExtended,
+ enum loc_sess_status status,
+ LocPosTechMask loc_technology_mask);
+
+ virtual void reportLocationsEvent(const Location* locations, size_t count,
+ BatchingMode batchingMode);
+ virtual void reportCompletedTripsEvent(uint32_t accumulated_distance);
+ virtual void reportBatchStatusChangeEvent(BatchingStatus batchStatus);
+
+ /* ==== CLIENT ========================================================================= */
+ /* ======== COMMANDS ====(Called from Client Thread)==================================== */
+ void addClientCommand(LocationAPI* client, const LocationCallbacks& callbacks);
+ void removeClientCommand(LocationAPI* client,
+ removeClientCompleteCallback rmClientCb);
+ void requestCapabilitiesCommand(LocationAPI* client);
+
+};
+
+} // namespace loc_core
+
+#endif //LOC_API_ADAPTER_BASE_H
diff --git a/core/LocAdapterProxyBase.h b/core/LocAdapterProxyBase.h
new file mode 100644
index 0000000..727d424
--- /dev/null
+++ b/core/LocAdapterProxyBase.h
@@ -0,0 +1,77 @@
+/* Copyright (c) 2014, 2016-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 LOC_ADAPTER_PROXY_BASE_H
+#define LOC_ADAPTER_PROXY_BASE_H
+
+#include <ContextBase.h>
+#include <gps_extended.h>
+
+namespace loc_core {
+
+class LocAdapterProxyBase {
+private:
+ LocAdapterBase *mLocAdapterBase;
+protected:
+ inline LocAdapterProxyBase(const LOC_API_ADAPTER_EVENT_MASK_T mask,
+ ContextBase* context, bool isMaster = false):
+ mLocAdapterBase(new LocAdapterBase(mask, context, isMaster, this)) {
+ }
+ inline virtual ~LocAdapterProxyBase() {
+ delete mLocAdapterBase;
+ }
+ inline void updateEvtMask(LOC_API_ADAPTER_EVENT_MASK_T event,
+ loc_registration_mask_status isEnabled) {
+ mLocAdapterBase->updateEvtMask(event,isEnabled);
+ }
+
+ inline uint32_t generateSessionId() {
+ return mLocAdapterBase->generateSessionId();
+ }
+public:
+ inline ContextBase* getContext() const {
+ return mLocAdapterBase->getContext();
+ }
+
+ inline virtual void handleEngineUpEvent() {};
+ inline virtual void handleEngineDownEvent() {};
+ inline virtual void reportPositionEvent(UlpLocation &location,
+ GpsLocationExtended &locationExtended,
+ enum loc_sess_status status,
+ LocPosTechMask loc_technology_mask) {
+ (void)location;
+ (void)locationExtended;
+ (void)status;
+ (void)loc_technology_mask;
+ }
+};
+
+} // namespace loc_core
+
+#endif //LOC_ADAPTER_PROXY_BASE_H
diff --git a/core/LocApiBase.cpp b/core/LocApiBase.cpp
new file mode 100644
index 0000000..8c79cf7
--- /dev/null
+++ b/core/LocApiBase.cpp
@@ -0,0 +1,877 @@
+/* Copyright (c) 2011-2014, 2016-2019 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_NDEBUG 0 //Define to enable LOGV
+#define LOG_TAG "LocSvc_LocApiBase"
+
+#include <dlfcn.h>
+#include <inttypes.h>
+#include <gps_extended_c.h>
+#include <LocApiBase.h>
+#include <LocAdapterBase.h>
+#include <log_util.h>
+#include <LocContext.h>
+
+namespace loc_core {
+
+#define TO_ALL_LOCADAPTERS(call) TO_ALL_ADAPTERS(mLocAdapters, (call))
+#define TO_1ST_HANDLING_LOCADAPTERS(call) TO_1ST_HANDLING_ADAPTER(mLocAdapters, (call))
+
+int hexcode(char *hexstring, int string_size,
+ const char *data, int data_size)
+{
+ int i;
+ for (i = 0; i < data_size; i++)
+ {
+ char ch = data[i];
+ if (i*2 + 3 <= string_size)
+ {
+ snprintf(&hexstring[i*2], 3, "%02X", ch);
+ }
+ else {
+ break;
+ }
+ }
+ return i;
+}
+
+int decodeAddress(char *addr_string, int string_size,
+ const char *data, int data_size)
+{
+ const char addr_prefix = 0x91;
+ int i, idxOutput = 0;
+
+ if (!data || !addr_string) { return 0; }
+
+ if (data[0] != addr_prefix)
+ {
+ LOC_LOGW("decodeAddress: address prefix is not 0x%x but 0x%x", addr_prefix, data[0]);
+ addr_string[0] = '\0';
+ return 0; // prefix not correct
+ }
+
+ for (i = 1; i < data_size; i++)
+ {
+ unsigned char ch = data[i], low = ch & 0x0F, hi = ch >> 4;
+ if (low <= 9 && idxOutput < string_size - 1) { addr_string[idxOutput++] = low + '0'; }
+ if (hi <= 9 && idxOutput < string_size - 1) { addr_string[idxOutput++] = hi + '0'; }
+ }
+
+ addr_string[idxOutput] = '\0'; // Terminates the string
+
+ return idxOutput;
+}
+
+struct LocSsrMsg : public LocMsg {
+ LocApiBase* mLocApi;
+ inline LocSsrMsg(LocApiBase* locApi) :
+ LocMsg(), mLocApi(locApi)
+ {
+ locallog();
+ }
+ inline virtual void proc() const {
+ mLocApi->close();
+ if (LOC_API_ADAPTER_ERR_SUCCESS == mLocApi->open(mLocApi->getEvtMask())) {
+ // Notify adapters that engine up after SSR
+ mLocApi->handleEngineUpEvent();
+ }
+ }
+ inline void locallog() const {
+ LOC_LOGV("LocSsrMsg");
+ }
+ inline virtual void log() const {
+ locallog();
+ }
+};
+
+struct LocOpenMsg : public LocMsg {
+ LocApiBase* mLocApi;
+ LocAdapterBase* mAdapter;
+ inline LocOpenMsg(LocApiBase* locApi, LocAdapterBase* adapter = nullptr) :
+ LocMsg(), mLocApi(locApi), mAdapter(adapter)
+ {
+ locallog();
+ }
+ inline virtual void proc() const {
+ if (LOC_API_ADAPTER_ERR_SUCCESS == mLocApi->open(mLocApi->getEvtMask()) &&
+ nullptr != mAdapter) {
+ mAdapter->handleEngineUpEvent();
+ }
+ }
+ inline void locallog() const {
+ LOC_LOGv("LocOpen Mask: %" PRIx64 "\n", mLocApi->getEvtMask());
+ }
+ inline virtual void log() const {
+ locallog();
+ }
+};
+
+struct LocCloseMsg : public LocMsg {
+ LocApiBase* mLocApi;
+ inline LocCloseMsg(LocApiBase* locApi) :
+ LocMsg(), mLocApi(locApi)
+ {
+ locallog();
+ }
+ inline virtual void proc() const {
+ mLocApi->close();
+ }
+ inline void locallog() const {
+ }
+ inline virtual void log() const {
+ locallog();
+ }
+};
+
+MsgTask* LocApiBase::mMsgTask = nullptr;
+volatile int32_t LocApiBase::mMsgTaskRefCount = 0;
+
+LocApiBase::LocApiBase(LOC_API_ADAPTER_EVENT_MASK_T excludedMask,
+ ContextBase* context) :
+ mContext(context),
+ mMask(0), mExcludedMask(excludedMask)
+{
+ memset(mLocAdapters, 0, sizeof(mLocAdapters));
+
+ android_atomic_inc(&mMsgTaskRefCount);
+ if (nullptr == mMsgTask) {
+ mMsgTask = new MsgTask("LocApiMsgTask", false);
+ }
+}
+
+LOC_API_ADAPTER_EVENT_MASK_T LocApiBase::getEvtMask()
+{
+ LOC_API_ADAPTER_EVENT_MASK_T mask = 0;
+
+ TO_ALL_LOCADAPTERS(mask |= mLocAdapters[i]->getEvtMask());
+
+ return mask & ~mExcludedMask;
+}
+
+bool LocApiBase::isMaster()
+{
+ bool isMaster = false;
+
+ for (int i = 0;
+ !isMaster && i < MAX_ADAPTERS && NULL != mLocAdapters[i];
+ i++) {
+ isMaster |= mLocAdapters[i]->isAdapterMaster();
+ }
+ return isMaster;
+}
+
+bool LocApiBase::isInSession()
+{
+ bool inSession = false;
+
+ for (int i = 0;
+ !inSession && i < MAX_ADAPTERS && NULL != mLocAdapters[i];
+ i++) {
+ inSession = mLocAdapters[i]->isInSession();
+ }
+
+ return inSession;
+}
+
+bool LocApiBase::needReport(const UlpLocation& ulpLocation,
+ enum loc_sess_status status,
+ LocPosTechMask techMask)
+{
+ bool reported = false;
+
+ if (LOC_SESS_SUCCESS == status) {
+ // this is a final fix
+ LocPosTechMask mask =
+ LOC_POS_TECH_MASK_SATELLITE | LOC_POS_TECH_MASK_SENSORS | LOC_POS_TECH_MASK_HYBRID;
+ // it is a Satellite fix or a sensor fix
+ reported = (mask & techMask);
+ }
+ else if (LOC_SESS_INTERMEDIATE == status &&
+ LOC_SESS_INTERMEDIATE == ContextBase::mGps_conf.INTERMEDIATE_POS) {
+ // this is a intermediate fix and we accept intermediate
+
+ // it is NOT the case that
+ // there is inaccuracy; and
+ // we care about inaccuracy; and
+ // the inaccuracy exceeds our tolerance
+ reported = !((ulpLocation.gpsLocation.flags & LOC_GPS_LOCATION_HAS_ACCURACY) &&
+ (ContextBase::mGps_conf.ACCURACY_THRES != 0) &&
+ (ulpLocation.gpsLocation.accuracy > ContextBase::mGps_conf.ACCURACY_THRES));
+ }
+
+ return reported;
+}
+
+void LocApiBase::addAdapter(LocAdapterBase* adapter)
+{
+ for (int i = 0; i < MAX_ADAPTERS && mLocAdapters[i] != adapter; i++) {
+ if (mLocAdapters[i] == NULL) {
+ mLocAdapters[i] = adapter;
+ sendMsg(new LocOpenMsg(this, adapter));
+ break;
+ }
+ }
+}
+
+void LocApiBase::removeAdapter(LocAdapterBase* adapter)
+{
+ for (int i = 0;
+ i < MAX_ADAPTERS && NULL != mLocAdapters[i];
+ i++) {
+ if (mLocAdapters[i] == adapter) {
+ mLocAdapters[i] = NULL;
+
+ // shift the rest of the adapters up so that the pointers
+ // in the array do not have holes. This should be more
+ // performant, because the array maintenance is much much
+ // less frequent than event handlings, which need to linear
+ // search all the adapters
+ int j = i;
+ while (++i < MAX_ADAPTERS && mLocAdapters[i] != NULL);
+
+ // i would be MAX_ADAPTERS or point to a NULL
+ i--;
+ // i now should point to a none NULL adapter within valid
+ // range although i could be equal to j, but it won't hurt.
+ // No need to check it, as it gains nothing.
+ mLocAdapters[j] = mLocAdapters[i];
+ // this makes sure that we exit the for loop
+ mLocAdapters[i] = NULL;
+
+ // if we have an empty list of adapters
+ if (0 == i) {
+ sendMsg(new LocCloseMsg(this));
+ } else {
+ // else we need to remove the bit
+ sendMsg(new LocOpenMsg(this));
+ }
+ }
+ }
+}
+
+void LocApiBase::updateEvtMask()
+{
+ sendMsg(new LocOpenMsg(this));
+}
+
+void LocApiBase::updateNmeaMask(uint32_t mask)
+{
+ struct LocSetNmeaMsg : public LocMsg {
+ LocApiBase* mLocApi;
+ uint32_t mMask;
+ inline LocSetNmeaMsg(LocApiBase* locApi, uint32_t mask) :
+ LocMsg(), mLocApi(locApi), mMask(mask)
+ {
+ locallog();
+ }
+ inline virtual void proc() const {
+ mLocApi->setNMEATypesSync(mMask);
+ }
+ inline void locallog() const {
+ LOC_LOGv("LocSyncNmea NmeaMask: %" PRIx32 "\n", mMask);
+ }
+ inline virtual void log() const {
+ locallog();
+ }
+ };
+
+ sendMsg(new LocSetNmeaMsg(this, mask));
+}
+
+void LocApiBase::handleEngineUpEvent()
+{
+ // loop through adapters, and deliver to all adapters.
+ TO_ALL_LOCADAPTERS(mLocAdapters[i]->handleEngineUpEvent());
+}
+
+void LocApiBase::handleEngineDownEvent()
+{ // This will take care of renegotiating the loc handle
+ sendMsg(new LocSsrMsg(this));
+
+ // loop through adapters, and deliver to all adapters.
+ TO_ALL_LOCADAPTERS(mLocAdapters[i]->handleEngineDownEvent());
+}
+
+void LocApiBase::reportPosition(UlpLocation& location,
+ GpsLocationExtended& locationExtended,
+ enum loc_sess_status status,
+ LocPosTechMask loc_technology_mask,
+ GnssDataNotification* pDataNotify,
+ int msInWeek)
+{
+ // print the location info before delivering
+ LOC_LOGD("flags: %d\n source: %d\n latitude: %f\n longitude: %f\n "
+ "altitude: %f\n speed: %f\n bearing: %f\n accuracy: %f\n "
+ "timestamp: %" PRId64 "\n"
+ "Session status: %d\n Technology mask: %u\n "
+ "SV used in fix (gps/glo/bds/gal/qzss) : \
+ (0x%" PRIx64 "/0x%" PRIx64 "/0x%" PRIx64 "/0x%" PRIx64 "/0x%" PRIx64 ")",
+ location.gpsLocation.flags, location.position_source,
+ location.gpsLocation.latitude, location.gpsLocation.longitude,
+ location.gpsLocation.altitude, location.gpsLocation.speed,
+ location.gpsLocation.bearing, location.gpsLocation.accuracy,
+ location.gpsLocation.timestamp, status, loc_technology_mask,
+ locationExtended.gnss_sv_used_ids.gps_sv_used_ids_mask,
+ locationExtended.gnss_sv_used_ids.glo_sv_used_ids_mask,
+ locationExtended.gnss_sv_used_ids.bds_sv_used_ids_mask,
+ locationExtended.gnss_sv_used_ids.gal_sv_used_ids_mask,
+ locationExtended.gnss_sv_used_ids.qzss_sv_used_ids_mask);
+ // loop through adapters, and deliver to all adapters.
+ TO_ALL_LOCADAPTERS(
+ mLocAdapters[i]->reportPositionEvent(location, locationExtended,
+ status, loc_technology_mask,
+ pDataNotify, msInWeek)
+ );
+}
+
+void LocApiBase::reportWwanZppFix(LocGpsLocation &zppLoc)
+{
+ // loop through adapters, and deliver to the first handling adapter.
+ TO_1ST_HANDLING_LOCADAPTERS(mLocAdapters[i]->reportWwanZppFix(zppLoc));
+}
+
+void LocApiBase::reportZppBestAvailableFix(LocGpsLocation &zppLoc,
+ GpsLocationExtended &location_extended, LocPosTechMask tech_mask)
+{
+ // loop through adapters, and deliver to the first handling adapter.
+ TO_1ST_HANDLING_LOCADAPTERS(mLocAdapters[i]->reportZppBestAvailableFix(zppLoc,
+ location_extended, tech_mask));
+}
+
+void LocApiBase::requestOdcpi(OdcpiRequestInfo& request)
+{
+ // loop through adapters, and deliver to the first handling adapter.
+ TO_1ST_HANDLING_LOCADAPTERS(mLocAdapters[i]->requestOdcpiEvent(request));
+}
+
+void LocApiBase::reportGnssEngEnergyConsumedEvent(uint64_t energyConsumedSinceFirstBoot)
+{
+ // loop through adapters, and deliver to the first handling adapter.
+ TO_ALL_LOCADAPTERS(mLocAdapters[i]->reportGnssEngEnergyConsumedEvent(
+ energyConsumedSinceFirstBoot));
+}
+
+void LocApiBase::reportDeleteAidingDataEvent(GnssAidingData& aidingData) {
+ // loop through adapters, and deliver to the first handling adapter.
+ TO_1ST_HANDLING_LOCADAPTERS(mLocAdapters[i]->reportDeleteAidingDataEvent(aidingData));
+}
+
+void LocApiBase::reportKlobucharIonoModel(GnssKlobucharIonoModel & ionoModel) {
+ // loop through adapters, and deliver to the first handling adapter.
+ TO_1ST_HANDLING_LOCADAPTERS(mLocAdapters[i]->reportKlobucharIonoModelEvent(ionoModel));
+}
+
+void LocApiBase::reportGnssAdditionalSystemInfo(GnssAdditionalSystemInfo& additionalSystemInfo) {
+ // loop through adapters, and deliver to the first handling adapter.
+ TO_1ST_HANDLING_LOCADAPTERS(mLocAdapters[i]->reportGnssAdditionalSystemInfoEvent(
+ additionalSystemInfo));
+}
+
+void LocApiBase::sendNfwNotification(GnssNfwNotification& notification)
+{
+ // loop through adapters, and deliver to the first handling adapter.
+ TO_ALL_LOCADAPTERS(mLocAdapters[i]->reportNfwNotificationEvent(notification));
+
+}
+
+void LocApiBase::reportSv(GnssSvNotification& svNotify)
+{
+ const char* constellationString[] = { "Unknown", "GPS", "SBAS", "GLONASS",
+ "QZSS", "BEIDOU", "GALILEO", "NAVIC" };
+
+ // print the SV info before delivering
+ LOC_LOGV("num sv: %u\n"
+ " sv: constellation svid cN0"
+ " elevation azimuth flags",
+ svNotify.count);
+ for (size_t i = 0; i < svNotify.count && i < LOC_GNSS_MAX_SVS; i++) {
+ if (svNotify.gnssSvs[i].type >
+ sizeof(constellationString) / sizeof(constellationString[0]) - 1) {
+ svNotify.gnssSvs[i].type = GNSS_SV_TYPE_UNKNOWN;
+ }
+ // Display what we report to clients
+ uint16_t displaySvId = GNSS_SV_TYPE_QZSS == svNotify.gnssSvs[i].type ?
+ svNotify.gnssSvs[i].svId + QZSS_SV_PRN_MIN - 1 :
+ svNotify.gnssSvs[i].svId;
+ LOC_LOGV(" %03zu: %*s %02d %f %f %f %f 0x%02X",
+ i,
+ 13,
+ constellationString[svNotify.gnssSvs[i].type],
+ displaySvId,
+ svNotify.gnssSvs[i].cN0Dbhz,
+ svNotify.gnssSvs[i].elevation,
+ svNotify.gnssSvs[i].azimuth,
+ svNotify.gnssSvs[i].carrierFrequencyHz,
+ svNotify.gnssSvs[i].gnssSvOptionsMask);
+ }
+ // loop through adapters, and deliver to all adapters.
+ TO_ALL_LOCADAPTERS(
+ mLocAdapters[i]->reportSvEvent(svNotify)
+ );
+}
+
+void LocApiBase::reportSvPolynomial(GnssSvPolynomial &svPolynomial)
+{
+ // loop through adapters, and deliver to all adapters.
+ TO_ALL_LOCADAPTERS(
+ mLocAdapters[i]->reportSvPolynomialEvent(svPolynomial)
+ );
+}
+
+void LocApiBase::reportSvEphemeris(GnssSvEphemerisReport & svEphemeris)
+{
+ // loop through adapters, and deliver to all adapters.
+ TO_ALL_LOCADAPTERS(
+ mLocAdapters[i]->reportSvEphemerisEvent(svEphemeris)
+ );
+}
+
+void LocApiBase::reportStatus(LocGpsStatusValue status)
+{
+ // loop through adapters, and deliver to all adapters.
+ TO_ALL_LOCADAPTERS(mLocAdapters[i]->reportStatus(status));
+}
+
+void LocApiBase::reportData(GnssDataNotification& dataNotify, int msInWeek)
+{
+ // loop through adapters, and deliver to all adapters.
+ TO_ALL_LOCADAPTERS(mLocAdapters[i]->reportDataEvent(dataNotify, msInWeek));
+}
+
+void LocApiBase::reportNmea(const char* nmea, int length)
+{
+ // loop through adapters, and deliver to all adapters.
+ TO_ALL_LOCADAPTERS(mLocAdapters[i]->reportNmeaEvent(nmea, length));
+}
+
+void LocApiBase::reportXtraServer(const char* url1, const char* url2,
+ const char* url3, const int maxlength)
+{
+ // loop through adapters, and deliver to the first handling adapter.
+ TO_1ST_HANDLING_LOCADAPTERS(mLocAdapters[i]->reportXtraServer(url1, url2, url3, maxlength));
+
+}
+
+void LocApiBase::reportLocationSystemInfo(const LocationSystemInfo& locationSystemInfo)
+{
+ // loop through adapters, and deliver to all adapters.
+ TO_ALL_LOCADAPTERS(mLocAdapters[i]->reportLocationSystemInfoEvent(locationSystemInfo));
+}
+
+void LocApiBase::requestXtraData()
+{
+ // loop through adapters, and deliver to the first handling adapter.
+ TO_1ST_HANDLING_LOCADAPTERS(mLocAdapters[i]->requestXtraData());
+}
+
+void LocApiBase::requestTime()
+{
+ // loop through adapters, and deliver to the first handling adapter.
+ TO_1ST_HANDLING_LOCADAPTERS(mLocAdapters[i]->requestTime());
+}
+
+void LocApiBase::requestLocation()
+{
+ // loop through adapters, and deliver to the first handling adapter.
+ TO_1ST_HANDLING_LOCADAPTERS(mLocAdapters[i]->requestLocation());
+}
+
+void LocApiBase::requestATL(int connHandle, LocAGpsType agps_type,
+ LocApnTypeMask apn_type_mask)
+{
+ // loop through adapters, and deliver to the first handling adapter.
+ TO_1ST_HANDLING_LOCADAPTERS(
+ mLocAdapters[i]->requestATL(connHandle, agps_type, apn_type_mask));
+}
+
+void LocApiBase::releaseATL(int connHandle)
+{
+ // loop through adapters, and deliver to the first handling adapter.
+ TO_1ST_HANDLING_LOCADAPTERS(mLocAdapters[i]->releaseATL(connHandle));
+}
+
+void LocApiBase::requestNiNotify(GnssNiNotification &notify, const void* data,
+ const LocInEmergency emergencyState)
+{
+ // loop through adapters, and deliver to the first handling adapter.
+ TO_1ST_HANDLING_LOCADAPTERS(
+ mLocAdapters[i]->requestNiNotifyEvent(notify,
+ data,
+ emergencyState));
+}
+
+void* LocApiBase :: getSibling()
+ DEFAULT_IMPL(NULL)
+
+LocApiProxyBase* LocApiBase :: getLocApiProxy()
+ DEFAULT_IMPL(NULL)
+
+void LocApiBase::reportGnssMeasurements(GnssMeasurements& gnssMeasurements, int msInWeek)
+{
+ // loop through adapters, and deliver to all adapters.
+ TO_ALL_LOCADAPTERS(mLocAdapters[i]->reportGnssMeasurementsEvent(gnssMeasurements, msInWeek));
+}
+
+void LocApiBase::reportGnssSvIdConfig(const GnssSvIdConfig& config)
+{
+ // Print the config
+ LOC_LOGv("gloBlacklistSvMask: %" PRIu64 ", bdsBlacklistSvMask: %" PRIu64 ",\n"
+ "qzssBlacklistSvMask: %" PRIu64 ", galBlacklistSvMask: %" PRIu64,
+ config.gloBlacklistSvMask, config.bdsBlacklistSvMask,
+ config.qzssBlacklistSvMask, config.galBlacklistSvMask);
+
+ // Loop through adapters, and deliver to all adapters.
+ TO_ALL_LOCADAPTERS(mLocAdapters[i]->reportGnssSvIdConfigEvent(config));
+}
+
+void LocApiBase::reportGnssSvTypeConfig(const GnssSvTypeConfig& config)
+{
+ // Print the config
+ LOC_LOGv("blacklistedMask: %" PRIu64 ", enabledMask: %" PRIu64,
+ config.blacklistedSvTypesMask, config.enabledSvTypesMask);
+
+ // Loop through adapters, and deliver to all adapters.
+ TO_ALL_LOCADAPTERS(mLocAdapters[i]->reportGnssSvTypeConfigEvent(config));
+}
+
+void LocApiBase::geofenceBreach(size_t count, uint32_t* hwIds, Location& location,
+ GeofenceBreachType breachType, uint64_t timestamp)
+{
+ TO_ALL_LOCADAPTERS(mLocAdapters[i]->geofenceBreachEvent(count, hwIds, location, breachType,
+ timestamp));
+}
+
+void LocApiBase::geofenceStatus(GeofenceStatusAvailable available)
+{
+ TO_ALL_LOCADAPTERS(mLocAdapters[i]->geofenceStatusEvent(available));
+}
+
+void LocApiBase::reportDBTPosition(UlpLocation &location, GpsLocationExtended &locationExtended,
+ enum loc_sess_status status, LocPosTechMask loc_technology_mask)
+{
+ TO_ALL_LOCADAPTERS(mLocAdapters[i]->reportPositionEvent(location, locationExtended, status,
+ loc_technology_mask));
+}
+
+void LocApiBase::reportLocations(Location* locations, size_t count, BatchingMode batchingMode)
+{
+ TO_ALL_LOCADAPTERS(mLocAdapters[i]->reportLocationsEvent(locations, count, batchingMode));
+}
+
+void LocApiBase::reportCompletedTrips(uint32_t accumulated_distance)
+{
+ TO_ALL_LOCADAPTERS(mLocAdapters[i]->reportCompletedTripsEvent(accumulated_distance));
+}
+
+void LocApiBase::handleBatchStatusEvent(BatchingStatus batchStatus)
+{
+ TO_ALL_LOCADAPTERS(mLocAdapters[i]->reportBatchStatusChangeEvent(batchStatus));
+}
+
+
+enum loc_api_adapter_err LocApiBase::
+ open(LOC_API_ADAPTER_EVENT_MASK_T /*mask*/)
+DEFAULT_IMPL(LOC_API_ADAPTER_ERR_SUCCESS)
+
+enum loc_api_adapter_err LocApiBase::
+ close()
+DEFAULT_IMPL(LOC_API_ADAPTER_ERR_SUCCESS)
+
+void LocApiBase::startFix(const LocPosMode& /*posMode*/, LocApiResponse* /*adapterResponse*/)
+DEFAULT_IMPL()
+
+void LocApiBase::stopFix(LocApiResponse* /*adapterResponse*/)
+DEFAULT_IMPL()
+
+void LocApiBase::
+ deleteAidingData(const GnssAidingData& /*data*/, LocApiResponse* /*adapterResponse*/)
+DEFAULT_IMPL()
+
+void LocApiBase::
+ injectPosition(double /*latitude*/, double /*longitude*/, float /*accuracy*/)
+DEFAULT_IMPL()
+
+void LocApiBase::
+ injectPosition(const Location& /*location*/, bool /*onDemandCpi*/)
+DEFAULT_IMPL()
+
+void LocApiBase::
+ injectPosition(const GnssLocationInfoNotification & /*locationInfo*/, bool /*onDemandCpi*/)
+DEFAULT_IMPL()
+
+void LocApiBase::
+ setTime(LocGpsUtcTime /*time*/, int64_t /*timeReference*/, int /*uncertainty*/)
+DEFAULT_IMPL()
+
+enum loc_api_adapter_err LocApiBase::
+ setXtraData(char* /*data*/, int /*length*/)
+DEFAULT_IMPL(LOC_API_ADAPTER_ERR_SUCCESS)
+
+void LocApiBase::
+ atlOpenStatus(int /*handle*/, int /*is_succ*/, char* /*apn*/, uint32_t /*apnLen*/,
+ AGpsBearerType /*bear*/, LocAGpsType /*agpsType*/,
+ LocApnTypeMask /*mask*/)
+DEFAULT_IMPL()
+
+void LocApiBase::
+ atlCloseStatus(int /*handle*/, int /*is_succ*/)
+DEFAULT_IMPL()
+
+LocationError LocApiBase::
+ setServerSync(const char* /*url*/, int /*len*/, LocServerType /*type*/)
+DEFAULT_IMPL(LOCATION_ERROR_SUCCESS)
+
+LocationError LocApiBase::
+ setServerSync(unsigned int /*ip*/, int /*port*/, LocServerType /*type*/)
+DEFAULT_IMPL(LOCATION_ERROR_SUCCESS)
+
+void LocApiBase::
+ informNiResponse(GnssNiResponse /*userResponse*/, const void* /*passThroughData*/)
+DEFAULT_IMPL()
+
+LocationError LocApiBase::
+ setSUPLVersionSync(GnssConfigSuplVersion /*version*/)
+DEFAULT_IMPL(LOCATION_ERROR_SUCCESS)
+
+enum loc_api_adapter_err LocApiBase::
+ setNMEATypesSync (uint32_t /*typesMask*/)
+DEFAULT_IMPL(LOC_API_ADAPTER_ERR_SUCCESS)
+
+LocationError LocApiBase::
+ setLPPConfigSync(GnssConfigLppProfile /*profile*/)
+DEFAULT_IMPL(LOCATION_ERROR_SUCCESS)
+
+
+enum loc_api_adapter_err LocApiBase::
+ setSensorPropertiesSync(bool /*gyroBiasVarianceRandomWalk_valid*/,
+ float /*gyroBiasVarianceRandomWalk*/,
+ bool /*accelBiasVarianceRandomWalk_valid*/,
+ float /*accelBiasVarianceRandomWalk*/,
+ bool /*angleBiasVarianceRandomWalk_valid*/,
+ float /*angleBiasVarianceRandomWalk*/,
+ bool /*rateBiasVarianceRandomWalk_valid*/,
+ float /*rateBiasVarianceRandomWalk*/,
+ bool /*velocityBiasVarianceRandomWalk_valid*/,
+ float /*velocityBiasVarianceRandomWalk*/)
+DEFAULT_IMPL(LOC_API_ADAPTER_ERR_SUCCESS)
+
+enum loc_api_adapter_err LocApiBase::
+ setSensorPerfControlConfigSync(int /*controlMode*/,
+ int /*accelSamplesPerBatch*/,
+ int /*accelBatchesPerSec*/,
+ int /*gyroSamplesPerBatch*/,
+ int /*gyroBatchesPerSec*/,
+ int /*accelSamplesPerBatchHigh*/,
+ int /*accelBatchesPerSecHigh*/,
+ int /*gyroSamplesPerBatchHigh*/,
+ int /*gyroBatchesPerSecHigh*/,
+ int /*algorithmConfig*/)
+DEFAULT_IMPL(LOC_API_ADAPTER_ERR_SUCCESS)
+
+LocationError LocApiBase::
+ setAGLONASSProtocolSync(GnssConfigAGlonassPositionProtocolMask /*aGlonassProtocol*/)
+DEFAULT_IMPL(LOCATION_ERROR_SUCCESS)
+
+LocationError LocApiBase::
+ setLPPeProtocolCpSync(GnssConfigLppeControlPlaneMask /*lppeCP*/)
+DEFAULT_IMPL(LOCATION_ERROR_SUCCESS)
+
+LocationError LocApiBase::
+ setLPPeProtocolUpSync(GnssConfigLppeUserPlaneMask /*lppeUP*/)
+DEFAULT_IMPL(LOCATION_ERROR_SUCCESS)
+
+GnssConfigSuplVersion LocApiBase::convertSuplVersion(const uint32_t /*suplVersion*/)
+DEFAULT_IMPL(GNSS_CONFIG_SUPL_VERSION_1_0_0)
+
+GnssConfigLppProfile LocApiBase::convertLppProfile(const uint32_t /*lppProfile*/)
+DEFAULT_IMPL(GNSS_CONFIG_LPP_PROFILE_RRLP_ON_LTE)
+
+GnssConfigLppeControlPlaneMask LocApiBase::convertLppeCp(const uint32_t /*lppeControlPlaneMask*/)
+DEFAULT_IMPL(0)
+
+GnssConfigLppeUserPlaneMask LocApiBase::convertLppeUp(const uint32_t /*lppeUserPlaneMask*/)
+DEFAULT_IMPL(0)
+
+LocationError LocApiBase::setEmergencyExtensionWindowSync(
+ const uint32_t /*emergencyExtensionSeconds*/)
+DEFAULT_IMPL(LOCATION_ERROR_SUCCESS)
+
+void LocApiBase::
+ getWwanZppFix()
+DEFAULT_IMPL()
+
+void LocApiBase::
+ getBestAvailableZppFix()
+DEFAULT_IMPL()
+
+LocationError LocApiBase::
+ setGpsLockSync(GnssConfigGpsLock /*lock*/)
+DEFAULT_IMPL(LOCATION_ERROR_SUCCESS)
+
+void LocApiBase::
+ requestForAidingData(GnssAidingDataSvMask /*svDataMask*/)
+DEFAULT_IMPL()
+
+void LocApiBase::
+ installAGpsCert(const LocDerEncodedCertificate* /*pData*/,
+ size_t /*length*/,
+ uint32_t /*slotBitMask*/)
+DEFAULT_IMPL()
+
+LocationError LocApiBase::
+ setXtraVersionCheckSync(uint32_t /*check*/)
+DEFAULT_IMPL(LOCATION_ERROR_SUCCESS)
+
+LocationError LocApiBase::setBlacklistSvSync(const GnssSvIdConfig& /*config*/)
+DEFAULT_IMPL(LOCATION_ERROR_SUCCESS)
+
+void LocApiBase::setBlacklistSv(const GnssSvIdConfig& /*config*/)
+DEFAULT_IMPL()
+
+void LocApiBase::getBlacklistSv()
+DEFAULT_IMPL()
+
+void LocApiBase::setConstellationControl(const GnssSvTypeConfig& /*config*/)
+DEFAULT_IMPL()
+
+void LocApiBase::getConstellationControl()
+DEFAULT_IMPL()
+
+void LocApiBase::resetConstellationControl()
+DEFAULT_IMPL()
+
+LocationError LocApiBase::
+ setConstrainedTuncMode(bool /*enabled*/,
+ float /*tuncConstraint*/,
+ uint32_t /*energyBudget*/)
+DEFAULT_IMPL(LOCATION_ERROR_SUCCESS)
+
+LocationError LocApiBase::
+ setPositionAssistedClockEstimatorMode(bool /*enabled*/)
+DEFAULT_IMPL(LOCATION_ERROR_SUCCESS)
+
+LocationError LocApiBase::getGnssEnergyConsumed()
+DEFAULT_IMPL(LOCATION_ERROR_SUCCESS)
+
+
+void LocApiBase::addGeofence(uint32_t /*clientId*/, const GeofenceOption& /*options*/,
+ const GeofenceInfo& /*info*/,
+ LocApiResponseData<LocApiGeofenceData>* /*adapterResponseData*/)
+DEFAULT_IMPL()
+
+void LocApiBase::removeGeofence(uint32_t /*hwId*/, uint32_t /*clientId*/,
+ LocApiResponse* /*adapterResponse*/)
+DEFAULT_IMPL()
+
+void LocApiBase::pauseGeofence(uint32_t /*hwId*/, uint32_t /*clientId*/,
+ LocApiResponse* /*adapterResponse*/)
+DEFAULT_IMPL()
+
+void LocApiBase::resumeGeofence(uint32_t /*hwId*/, uint32_t /*clientId*/,
+ LocApiResponse* /*adapterResponse*/)
+DEFAULT_IMPL()
+
+void LocApiBase::modifyGeofence(uint32_t /*hwId*/, uint32_t /*clientId*/,
+ const GeofenceOption& /*options*/, LocApiResponse* /*adapterResponse*/)
+DEFAULT_IMPL()
+
+void LocApiBase::startTimeBasedTracking(const TrackingOptions& /*options*/,
+ LocApiResponse* /*adapterResponse*/)
+DEFAULT_IMPL()
+
+void LocApiBase::stopTimeBasedTracking(LocApiResponse* /*adapterResponse*/)
+DEFAULT_IMPL()
+
+void LocApiBase::startDistanceBasedTracking(uint32_t /*sessionId*/,
+ const LocationOptions& /*options*/, LocApiResponse* /*adapterResponse*/)
+DEFAULT_IMPL()
+
+void LocApiBase::stopDistanceBasedTracking(uint32_t /*sessionId*/,
+ LocApiResponse* /*adapterResponse*/)
+DEFAULT_IMPL()
+
+void LocApiBase::startBatching(uint32_t /*sessionId*/, const LocationOptions& /*options*/,
+ uint32_t /*accuracy*/, uint32_t /*timeout*/, LocApiResponse* /*adapterResponse*/)
+DEFAULT_IMPL()
+
+void LocApiBase::stopBatching(uint32_t /*sessionId*/, LocApiResponse* /*adapterResponse*/)
+DEFAULT_IMPL()
+
+LocationError LocApiBase::startOutdoorTripBatchingSync(uint32_t /*tripDistance*/,
+ uint32_t /*tripTbf*/, uint32_t /*timeout*/)
+DEFAULT_IMPL(LOCATION_ERROR_SUCCESS)
+
+void LocApiBase::startOutdoorTripBatching(uint32_t /*tripDistance*/, uint32_t /*tripTbf*/,
+ uint32_t /*timeout*/, LocApiResponse* /*adapterResponse*/)
+DEFAULT_IMPL()
+
+void LocApiBase::reStartOutdoorTripBatching(uint32_t /*ongoingTripDistance*/,
+ uint32_t /*ongoingTripInterval*/, uint32_t /*batchingTimeout,*/,
+ LocApiResponse* /*adapterResponse*/)
+DEFAULT_IMPL()
+
+LocationError LocApiBase::stopOutdoorTripBatchingSync(bool /*deallocBatchBuffer*/)
+DEFAULT_IMPL(LOCATION_ERROR_SUCCESS)
+
+void LocApiBase::stopOutdoorTripBatching(bool /*deallocBatchBuffer*/,
+ LocApiResponse* /*adapterResponse*/)
+DEFAULT_IMPL()
+
+LocationError LocApiBase::getBatchedLocationsSync(size_t /*count*/)
+DEFAULT_IMPL(LOCATION_ERROR_SUCCESS)
+
+void LocApiBase::getBatchedLocations(size_t /*count*/, LocApiResponse* /*adapterResponse*/)
+DEFAULT_IMPL()
+
+LocationError LocApiBase::getBatchedTripLocationsSync(size_t /*count*/,
+ uint32_t /*accumulatedDistance*/)
+DEFAULT_IMPL(LOCATION_ERROR_SUCCESS)
+
+void LocApiBase::getBatchedTripLocations(size_t /*count*/, uint32_t /*accumulatedDistance*/,
+ LocApiResponse* /*adapterResponse*/)
+DEFAULT_IMPL()
+
+LocationError LocApiBase::queryAccumulatedTripDistanceSync(uint32_t& /*accumulated_trip_distance*/,
+ uint32_t& /*numOfBatchedPositions*/)
+DEFAULT_IMPL(LOCATION_ERROR_SUCCESS)
+
+void LocApiBase::queryAccumulatedTripDistance(
+ LocApiResponseData<LocApiBatchData>* /*adapterResponseData*/)
+DEFAULT_IMPL()
+
+void LocApiBase::setBatchSize(size_t /*size*/)
+DEFAULT_IMPL()
+
+void LocApiBase::setTripBatchSize(size_t /*size*/)
+DEFAULT_IMPL()
+
+void LocApiBase::addToCallQueue(LocApiResponse* /*adapterResponse*/)
+DEFAULT_IMPL()
+
+
+} // namespace loc_core
diff --git a/core/LocApiBase.h b/core/LocApiBase.h
new file mode 100644
index 0000000..6dac585
--- /dev/null
+++ b/core/LocApiBase.h
@@ -0,0 +1,322 @@
+/* Copyright (c) 2011-2014, 2016-2019 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 LOC_API_BASE_H
+#define LOC_API_BASE_H
+
+#include <stddef.h>
+#include <ctype.h>
+#include <gps_extended.h>
+#include <LocationAPI.h>
+#include <MsgTask.h>
+#include <LocSharedLock.h>
+#include <log_util.h>
+
+namespace loc_core {
+
+class ContextBase;
+struct LocApiResponse;
+template <typename> struct LocApiResponseData;
+
+int hexcode(char *hexstring, int string_size,
+ const char *data, int data_size);
+int decodeAddress(char *addr_string, int string_size,
+ const char *data, int data_size);
+
+#define MAX_ADAPTERS 10
+#define MAX_FEATURE_LENGTH 100
+
+#define TO_ALL_ADAPTERS(adapters, call) \
+ for (int i = 0; i < MAX_ADAPTERS && NULL != (adapters)[i]; i++) { \
+ call; \
+ }
+
+#define TO_1ST_HANDLING_ADAPTER(adapters, call) \
+ for (int i = 0; i <MAX_ADAPTERS && NULL != (adapters)[i] && !(call); i++);
+
+enum xtra_version_check {
+ DISABLED,
+ AUTO,
+ XTRA2,
+ XTRA3
+};
+
+class LocAdapterBase;
+struct LocSsrMsg;
+struct LocOpenMsg;
+
+typedef struct
+{
+ uint32_t accumulatedDistance;
+ uint32_t numOfBatchedPositions;
+} LocApiBatchData;
+
+typedef struct
+{
+ uint32_t hwId;
+} LocApiGeofenceData;
+
+struct LocApiMsg: LocMsg {
+ private:
+ std::function<void ()> mProcImpl;
+ inline virtual void proc() const {
+ mProcImpl();
+ }
+ public:
+ inline LocApiMsg(std::function<void ()> procImpl ) :
+ mProcImpl(procImpl) {}
+};
+
+class LocApiProxyBase {
+public:
+ inline LocApiProxyBase() {}
+ inline virtual ~LocApiProxyBase() {}
+ inline virtual void* getSibling2() { return NULL; }
+};
+
+class LocApiBase {
+ friend struct LocSsrMsg;
+ //LocOpenMsg calls open() which makes it necessary to declare
+ //it as a friend
+ friend struct LocOpenMsg;
+ friend struct LocCloseMsg;
+ friend struct LocKillMsg;
+ friend class ContextBase;
+ static MsgTask* mMsgTask;
+ static volatile int32_t mMsgTaskRefCount;
+ LocAdapterBase* mLocAdapters[MAX_ADAPTERS];
+
+protected:
+ ContextBase *mContext;
+ virtual enum loc_api_adapter_err
+ open(LOC_API_ADAPTER_EVENT_MASK_T mask);
+ virtual enum loc_api_adapter_err
+ close();
+ LOC_API_ADAPTER_EVENT_MASK_T getEvtMask();
+ LOC_API_ADAPTER_EVENT_MASK_T mMask;
+ uint32_t mNmeaMask;
+ LocApiBase(LOC_API_ADAPTER_EVENT_MASK_T excludedMask,
+ ContextBase* context = NULL);
+ inline virtual ~LocApiBase() {
+ android_atomic_dec(&mMsgTaskRefCount);
+ if (nullptr != mMsgTask && 0 == mMsgTaskRefCount) {
+ mMsgTask->destroy();
+ mMsgTask = nullptr;
+ }
+ }
+ bool isInSession();
+ const LOC_API_ADAPTER_EVENT_MASK_T mExcludedMask;
+ bool isMaster();
+
+public:
+ inline void sendMsg(const LocMsg* msg) const {
+ if (nullptr != mMsgTask) {
+ mMsgTask->sendMsg(msg);
+ }
+ }
+ inline void destroy() {
+ close();
+ struct LocKillMsg : public LocMsg {
+ LocApiBase* mLocApi;
+ inline LocKillMsg(LocApiBase* locApi) : LocMsg(), mLocApi(locApi) {}
+ inline virtual void proc() const {
+ delete mLocApi;
+ }
+ };
+ sendMsg(new LocKillMsg(this));
+ }
+
+ static bool needReport(const UlpLocation& ulpLocation,
+ enum loc_sess_status status,
+ LocPosTechMask techMask);
+
+ void addAdapter(LocAdapterBase* adapter);
+ void removeAdapter(LocAdapterBase* adapter);
+
+ // upward calls
+ void handleEngineUpEvent();
+ void handleEngineDownEvent();
+ void reportPosition(UlpLocation& location,
+ GpsLocationExtended& locationExtended,
+ enum loc_sess_status status,
+ LocPosTechMask loc_technology_mask =
+ LOC_POS_TECH_MASK_DEFAULT,
+ GnssDataNotification* pDataNotify = nullptr,
+ int msInWeek = -1);
+ void reportSv(GnssSvNotification& svNotify);
+ void reportSvPolynomial(GnssSvPolynomial &svPolynomial);
+ void reportSvEphemeris(GnssSvEphemerisReport &svEphemeris);
+ void reportStatus(LocGpsStatusValue status);
+ void reportNmea(const char* nmea, int length);
+ void reportData(GnssDataNotification& dataNotify, int msInWeek);
+ void reportXtraServer(const char* url1, const char* url2,
+ const char* url3, const int maxlength);
+ void reportLocationSystemInfo(const LocationSystemInfo& locationSystemInfo);
+ void requestXtraData();
+ void requestTime();
+ void requestLocation();
+ void requestATL(int connHandle, LocAGpsType agps_type, LocApnTypeMask apn_type_mask);
+ void releaseATL(int connHandle);
+ void requestNiNotify(GnssNiNotification &notify, const void* data,
+ const LocInEmergency emergencyState);
+ void reportGnssMeasurements(GnssMeasurements& gnssMeasurements, int msInWeek);
+ void reportWwanZppFix(LocGpsLocation &zppLoc);
+ void reportZppBestAvailableFix(LocGpsLocation &zppLoc, GpsLocationExtended &location_extended,
+ LocPosTechMask tech_mask);
+ void reportGnssSvIdConfig(const GnssSvIdConfig& config);
+ void reportGnssSvTypeConfig(const GnssSvTypeConfig& config);
+ void requestOdcpi(OdcpiRequestInfo& request);
+ void reportGnssEngEnergyConsumedEvent(uint64_t energyConsumedSinceFirstBoot);
+ void reportDeleteAidingDataEvent(GnssAidingData& aidingData);
+ void reportKlobucharIonoModel(GnssKlobucharIonoModel& ionoModel);
+ void reportGnssAdditionalSystemInfo(GnssAdditionalSystemInfo& additionalSystemInfo);
+ void sendNfwNotification(GnssNfwNotification& notification);
+
+ void geofenceBreach(size_t count, uint32_t* hwIds, Location& location,
+ GeofenceBreachType breachType, uint64_t timestamp);
+ void geofenceStatus(GeofenceStatusAvailable available);
+ void reportDBTPosition(UlpLocation &location,
+ GpsLocationExtended &locationExtended,
+ enum loc_sess_status status,
+ LocPosTechMask loc_technology_mask);
+ void reportLocations(Location* locations, size_t count, BatchingMode batchingMode);
+ void reportCompletedTrips(uint32_t accumulated_distance);
+ void handleBatchStatusEvent(BatchingStatus batchStatus);
+
+ // downward calls
+ virtual void* getSibling();
+ virtual LocApiProxyBase* getLocApiProxy();
+ virtual void startFix(const LocPosMode& fixCriteria, LocApiResponse* adapterResponse);
+ virtual void stopFix(LocApiResponse* adapterResponse);
+ virtual void deleteAidingData(const GnssAidingData& data, LocApiResponse* adapterResponse);
+ virtual void injectPosition(double latitude, double longitude, float accuracy);
+ virtual void injectPosition(const GnssLocationInfoNotification &locationInfo,
+ bool onDemandCpi=false);
+ virtual void injectPosition(const Location& location, bool onDemandCpi);
+ virtual void setTime(LocGpsUtcTime time, int64_t timeReference, int uncertainty);
+ virtual enum loc_api_adapter_err setXtraData(char* data, int length);
+ virtual void atlOpenStatus(int handle, int is_succ, char* apn, uint32_t apnLen,
+ AGpsBearerType bear, LocAGpsType agpsType, LocApnTypeMask mask);
+ virtual void atlCloseStatus(int handle, int is_succ);
+ virtual LocationError setServerSync(const char* url, int len, LocServerType type);
+ virtual LocationError setServerSync(unsigned int ip, int port, LocServerType type);
+ virtual void informNiResponse(GnssNiResponse userResponse, const void* passThroughData);
+ virtual LocationError setSUPLVersionSync(GnssConfigSuplVersion version);
+ virtual enum loc_api_adapter_err setNMEATypesSync(uint32_t typesMask);
+ virtual LocationError setLPPConfigSync(GnssConfigLppProfile profile);
+ virtual enum loc_api_adapter_err setSensorPropertiesSync(
+ bool gyroBiasVarianceRandomWalk_valid, float gyroBiasVarianceRandomWalk,
+ bool accelBiasVarianceRandomWalk_valid, float accelBiasVarianceRandomWalk,
+ bool angleBiasVarianceRandomWalk_valid, float angleBiasVarianceRandomWalk,
+ bool rateBiasVarianceRandomWalk_valid, float rateBiasVarianceRandomWalk,
+ bool velocityBiasVarianceRandomWalk_valid, float velocityBiasVarianceRandomWalk);
+ virtual enum loc_api_adapter_err setSensorPerfControlConfigSync(int controlMode,
+ int accelSamplesPerBatch, int accelBatchesPerSec, int gyroSamplesPerBatch,
+ int gyroBatchesPerSec, int accelSamplesPerBatchHigh, int accelBatchesPerSecHigh,
+ int gyroSamplesPerBatchHigh, int gyroBatchesPerSecHigh, int algorithmConfig);
+ virtual LocationError
+ setAGLONASSProtocolSync(GnssConfigAGlonassPositionProtocolMask aGlonassProtocol);
+ virtual LocationError setLPPeProtocolCpSync(GnssConfigLppeControlPlaneMask lppeCP);
+ virtual LocationError setLPPeProtocolUpSync(GnssConfigLppeUserPlaneMask lppeUP);
+ virtual GnssConfigSuplVersion convertSuplVersion(const uint32_t suplVersion);
+ virtual GnssConfigLppProfile convertLppProfile(const uint32_t lppProfile);
+ virtual GnssConfigLppeControlPlaneMask convertLppeCp(const uint32_t lppeControlPlaneMask);
+ virtual GnssConfigLppeUserPlaneMask convertLppeUp(const uint32_t lppeUserPlaneMask);
+ virtual LocationError setEmergencyExtensionWindowSync(const uint32_t emergencyExtensionSeconds);
+
+ virtual void getWwanZppFix();
+ virtual void getBestAvailableZppFix();
+ virtual void installAGpsCert(const LocDerEncodedCertificate* pData, size_t length,
+ uint32_t slotBitMask);
+ virtual LocationError setGpsLockSync(GnssConfigGpsLock lock);
+ virtual void requestForAidingData(GnssAidingDataSvMask svDataMask);
+ virtual LocationError setXtraVersionCheckSync(uint32_t check);
+ /* Requests for SV/Constellation Control */
+ virtual LocationError setBlacklistSvSync(const GnssSvIdConfig& config);
+ virtual void setBlacklistSv(const GnssSvIdConfig& config);
+ virtual void getBlacklistSv();
+ virtual void setConstellationControl(const GnssSvTypeConfig& config);
+ virtual void getConstellationControl();
+ virtual void resetConstellationControl();
+ virtual LocationError setConstrainedTuncMode(bool enabled, float tuncConstraint,
+ uint32_t energyBudget);
+ virtual LocationError setPositionAssistedClockEstimatorMode(bool enabled);
+ virtual LocationError getGnssEnergyConsumed();
+
+ virtual void addGeofence(uint32_t clientId, const GeofenceOption& options,
+ const GeofenceInfo& info, LocApiResponseData<LocApiGeofenceData>* adapterResponseData);
+ virtual void removeGeofence(uint32_t hwId, uint32_t clientId, LocApiResponse* adapterResponse);
+ virtual void pauseGeofence(uint32_t hwId, uint32_t clientId, LocApiResponse* adapterResponse);
+ virtual void resumeGeofence(uint32_t hwId, uint32_t clientId, LocApiResponse* adapterResponse);
+ virtual void modifyGeofence(uint32_t hwId, uint32_t clientId, const GeofenceOption& options,
+ LocApiResponse* adapterResponse);
+
+ virtual void startTimeBasedTracking(const TrackingOptions& options,
+ LocApiResponse* adapterResponse);
+ virtual void stopTimeBasedTracking(LocApiResponse* adapterResponse);
+ virtual void startDistanceBasedTracking(uint32_t sessionId, const LocationOptions& options,
+ LocApiResponse* adapterResponse);
+ virtual void stopDistanceBasedTracking(uint32_t sessionId,
+ LocApiResponse* adapterResponse = nullptr);
+ virtual void startBatching(uint32_t sessionId, const LocationOptions& options,
+ uint32_t accuracy, uint32_t timeout, LocApiResponse* adapterResponse);
+ virtual void stopBatching(uint32_t sessionId, LocApiResponse* adapterResponse);
+ virtual LocationError startOutdoorTripBatchingSync(uint32_t tripDistance,
+ uint32_t tripTbf, uint32_t timeout);
+ virtual void startOutdoorTripBatching(uint32_t tripDistance,
+ uint32_t tripTbf, uint32_t timeout, LocApiResponse* adapterResponse);
+ virtual void reStartOutdoorTripBatching(uint32_t ongoingTripDistance,
+ uint32_t ongoingTripInterval, uint32_t batchingTimeout,
+ LocApiResponse* adapterResponse);
+ virtual LocationError stopOutdoorTripBatchingSync(bool deallocBatchBuffer = true);
+ virtual void stopOutdoorTripBatching(bool deallocBatchBuffer = true,
+ LocApiResponse* adapterResponse = nullptr);
+ virtual LocationError getBatchedLocationsSync(size_t count);
+ virtual void getBatchedLocations(size_t count, LocApiResponse* adapterResponse);
+ virtual LocationError getBatchedTripLocationsSync(size_t count, uint32_t accumulatedDistance);
+ virtual void getBatchedTripLocations(size_t count, uint32_t accumulatedDistance,
+ LocApiResponse* adapterResponse);
+ virtual LocationError queryAccumulatedTripDistanceSync(uint32_t &accumulated_trip_distance,
+ uint32_t &numOfBatchedPositions);
+ virtual void queryAccumulatedTripDistance(
+ LocApiResponseData<LocApiBatchData>* adapterResponseData);
+ virtual void setBatchSize(size_t size);
+ virtual void setTripBatchSize(size_t size);
+ virtual void addToCallQueue(LocApiResponse* adapterResponse);
+
+ void updateEvtMask();
+ void updateNmeaMask(uint32_t mask);
+
+};
+
+typedef LocApiBase* (getLocApi_t)(LOC_API_ADAPTER_EVENT_MASK_T exMask,
+ ContextBase *context);
+
+} // namespace loc_core
+
+#endif //LOC_API_BASE_H
diff --git a/core/LocContext.cpp b/core/LocContext.cpp
new file mode 100644
index 0000000..18d3f2d
--- /dev/null
+++ b/core/LocContext.cpp
@@ -0,0 +1,98 @@
+/* Copyright (c) 2011-2014, 2016-2019 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_NDEBUG 0
+#define LOG_TAG "LocSvc_Ctx"
+
+#include <cutils/sched_policy.h>
+#include <unistd.h>
+#include <LocContext.h>
+#include <msg_q.h>
+#include <log_util.h>
+#include <loc_log.h>
+
+namespace loc_core {
+
+const MsgTask* LocContext::mMsgTask = NULL;
+ContextBase* LocContext::mContext = NULL;
+// the name must be shorter than 15 chars
+const char* LocContext::mLocationHalName = "Loc_hal_worker";
+#ifndef USE_GLIB
+const char* LocContext::mLBSLibName = "liblbs_core.so";
+#else
+const char* LocContext::mLBSLibName = "liblbs_core.so.1";
+#endif
+
+pthread_mutex_t LocContext::mGetLocContextMutex = PTHREAD_MUTEX_INITIALIZER;
+
+const MsgTask* LocContext::getMsgTask(LocThread::tCreate tCreator,
+ const char* name, bool joinable)
+{
+ if (NULL == mMsgTask) {
+ mMsgTask = new MsgTask(tCreator, name, joinable);
+ }
+ return mMsgTask;
+}
+
+inline
+const MsgTask* LocContext::getMsgTask(const char* name, bool joinable) {
+ return getMsgTask((LocThread::tCreate)NULL, name, joinable);
+}
+
+ContextBase* LocContext::getLocContext(LocThread::tCreate tCreator,
+ LocMsg* firstMsg, const char* name, bool joinable)
+{
+ pthread_mutex_lock(&LocContext::mGetLocContextMutex);
+ LOC_LOGD("%s:%d]: querying ContextBase with tCreator", __func__, __LINE__);
+ if (NULL == mContext) {
+ LOC_LOGD("%s:%d]: creating msgTask with tCreator", __func__, __LINE__);
+ const MsgTask* msgTask = getMsgTask(tCreator, name, joinable);
+ mContext = new LocContext(msgTask);
+ }
+ pthread_mutex_unlock(&LocContext::mGetLocContextMutex);
+
+ if (firstMsg) {
+ mContext->sendMsg(firstMsg);
+ }
+
+ return mContext;
+}
+
+void LocContext :: injectFeatureConfig(ContextBase *curContext)
+{
+ LOC_LOGD("%s:%d]: Calling LBSProxy (%p) to inject feature config",
+ __func__, __LINE__, ((LocContext *)curContext)->mLBSProxy);
+ ((LocContext *)curContext)->mLBSProxy->injectFeatureConfig(curContext);
+}
+
+LocContext::LocContext(const MsgTask* msgTask) :
+ ContextBase(msgTask, 0, mLBSLibName)
+{
+}
+
+}
diff --git a/core/LocContext.h b/core/LocContext.h
new file mode 100644
index 0000000..fb7d009
--- /dev/null
+++ b/core/LocContext.h
@@ -0,0 +1,66 @@
+/* Copyright (c) 2011-2014, 2017-2019 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 __LOC_CONTEXT__
+#define __LOC_CONTEXT__
+
+#include <stdbool.h>
+#include <ctype.h>
+#include <dlfcn.h>
+#include <ContextBase.h>
+
+namespace loc_core {
+
+class LocContext : public ContextBase {
+ static const MsgTask* mMsgTask;
+ static ContextBase* mContext;
+ static const MsgTask* getMsgTask(LocThread::tCreate tCreator,
+ const char* name, bool joinable = true);
+ static const MsgTask* getMsgTask(const char* name, bool joinable = true);
+ static pthread_mutex_t mGetLocContextMutex;
+
+protected:
+ LocContext(const MsgTask* msgTask);
+ inline virtual ~LocContext() {}
+
+public:
+ static const char* mLBSLibName;
+ static const char* mLocationHalName;
+
+ static ContextBase* getLocContext(LocThread::tCreate tCreator, LocMsg* firstMsg,
+ const char* name, bool joinable = true);
+ inline static ContextBase* getLocContext(const char* name, bool joinable = true) {
+ return getLocContext(NULL, NULL, name, joinable);
+ }
+
+ static void injectFeatureConfig(ContextBase *context);
+};
+
+}
+
+#endif //__LOC_CONTEXT__
diff --git a/core/Makefile.am b/core/Makefile.am
new file mode 100644
index 0000000..ffd9357
--- /dev/null
+++ b/core/Makefile.am
@@ -0,0 +1,66 @@
+ACLOCAL_AMFLAGS = -I m4
+
+AM_CFLAGS = -I./ \
+ $(LOCPLA_CFLAGS) \
+ $(GPSUTILS_CFLAGS) \
+ -I./data-items/ \
+ -I./data-items/common \
+ -I./observer \
+ -I$(WORKSPACE)/gps-noship/flp \
+ -D__func__=__PRETTY_FUNCTION__ \
+ -fno-short-enums \
+ -std=c++11
+
+libloc_core_la_h_sources = \
+ LocApiBase.h \
+ LocAdapterBase.h \
+ ContextBase.h \
+ LocContext.h \
+ LBSProxyBase.h \
+ loc_core_log.h \
+ LocAdapterProxyBase.h \
+ EngineHubProxyBase.h \
+ data-items/DataItemId.h \
+ data-items/IDataItemCore.h \
+ data-items/DataItemConcreteTypesBase.h \
+ observer/IDataItemObserver.h \
+ observer/IDataItemSubscription.h \
+ observer/IFrameworkActionReq.h \
+ observer/IOsObserver.h \
+ SystemStatusOsObserver.h \
+ SystemStatus.h
+
+libloc_core_la_c_sources = \
+ LocApiBase.cpp \
+ LocAdapterBase.cpp \
+ ContextBase.cpp \
+ LocContext.cpp \
+ loc_core_log.cpp \
+ data-items/DataItemsFactoryProxy.cpp \
+ SystemStatusOsObserver.cpp \
+ SystemStatus.cpp
+
+library_includedir = $(pkgincludedir)
+
+library_include_HEADERS = $(libloc_core_la_h_sources)
+
+libloc_core_la_SOURCES = $(libloc_core_la_c_sources)
+
+if USE_GLIB
+libloc_core_la_CFLAGS = -DUSE_GLIB $(AM_CFLAGS) @GLIB_CFLAGS@
+libloc_core_la_LDFLAGS = -lstdc++ -Wl,-z,defs -lpthread @GLIB_LIBS@ -shared -version-info 1:0:0
+libloc_core_la_CPPFLAGS = -DUSE_GLIB $(AM_CFLAGS) $(AM_CPPFLAGS) @GLIB_CFLAGS@
+else
+libloc_core_la_CFLAGS = $(AM_CFLAGS)
+libloc_core_la_LDFLAGS = -Wl,-z,defs -lpthread -shared -version-info 1:0:0
+libloc_core_la_CPPFLAGS = $(AM_CFLAGS) $(AM_CPPFLAGS)
+endif
+
+libloc_core_la_LIBADD = -ldl $(GPSUTILS_LIBS)
+
+#Create and Install libraries
+lib_LTLIBRARIES = libloc_core.la
+
+pkgconfigdir = $(libdir)/pkgconfig
+pkgconfig_DATA = loc-core.pc
+EXTRA_DIST = $(pkgconfig_DATA)
diff --git a/core/SystemStatus.cpp b/core/SystemStatus.cpp
new file mode 100644
index 0000000..7d76651
--- /dev/null
+++ b/core/SystemStatus.cpp
@@ -0,0 +1,1748 @@
+/* Copyright (c) 2017, 2019, 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_SystemStatus"
+
+#include <inttypes.h>
+#include <string>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/time.h>
+#include <pthread.h>
+#include <loc_pla.h>
+#include <log_util.h>
+#include <loc_nmea.h>
+#include <DataItemsFactoryProxy.h>
+#include <SystemStatus.h>
+#include <SystemStatusOsObserver.h>
+#include <DataItemConcreteTypesBase.h>
+
+namespace loc_core
+{
+
+/******************************************************************************
+ SystemStatusNmeaBase - base class for all NMEA parsers
+******************************************************************************/
+class SystemStatusNmeaBase
+{
+protected:
+ std::vector<std::string> mField;
+
+ SystemStatusNmeaBase(const char *str_in, uint32_t len_in)
+ {
+ // check size and talker
+ if (!loc_nmea_is_debug(str_in, len_in)) {
+ return;
+ }
+
+ std::string parser(str_in);
+ std::string::size_type index = 0;
+
+ // verify checksum field
+ index = parser.find("*");
+ if (index == std::string::npos) {
+ return;
+ }
+ parser[index] = ',';
+
+ // tokenize parser
+ while (1) {
+ std::string str;
+ index = parser.find(",");
+ if (index == std::string::npos) {
+ break;
+ }
+ str = parser.substr(0, index);
+ parser = parser.substr(index + 1);
+ mField.push_back(str);
+ }
+ }
+
+ virtual ~SystemStatusNmeaBase() { }
+
+public:
+ static const uint32_t NMEA_MINSIZE = DEBUG_NMEA_MINSIZE;
+ static const uint32_t NMEA_MAXSIZE = DEBUG_NMEA_MAXSIZE;
+};
+
+/******************************************************************************
+ SystemStatusPQWM1
+******************************************************************************/
+class SystemStatusPQWM1
+{
+public:
+ uint16_t mGpsWeek; // x1
+ uint32_t mGpsTowMs; // x2
+ uint8_t mTimeValid; // x3
+ uint8_t mTimeSource; // x4
+ int32_t mTimeUnc; // x5
+ int32_t mClockFreqBias; // x6
+ int32_t mClockFreqBiasUnc; // x7
+ uint8_t mXoState; // x8
+ int32_t mPgaGain; // x9
+ uint32_t mGpsBpAmpI; // xA
+ uint32_t mGpsBpAmpQ; // xB
+ uint32_t mAdcI; // xC
+ uint32_t mAdcQ; // xD
+ uint32_t mJammerGps; // xE
+ uint32_t mJammerGlo; // xF
+ uint32_t mJammerBds; // x10
+ uint32_t mJammerGal; // x11
+ uint32_t mRecErrorRecovery; // x12
+ double mAgcGps; // x13
+ double mAgcGlo; // x14
+ double mAgcBds; // x15
+ double mAgcGal; // x16
+ int32_t mLeapSeconds;// x17
+ int32_t mLeapSecUnc; // x18
+ uint32_t mGloBpAmpI; // x19
+ uint32_t mGloBpAmpQ; // x1A
+ uint32_t mBdsBpAmpI; // x1B
+ uint32_t mBdsBpAmpQ; // x1C
+ uint32_t mGalBpAmpI; // x1D
+ uint32_t mGalBpAmpQ; // x1E
+ uint64_t mTimeUncNs; // x1F
+};
+
+// parser
+class SystemStatusPQWM1parser : public SystemStatusNmeaBase
+{
+private:
+ enum
+ {
+ eTalker = 0,
+ eGpsWeek = 1,
+ eGpsTowMs = 2,
+ eTimeValid = 3,
+ eTimeSource = 4,
+ eTimeUnc = 5,
+ eClockFreqBias = 6,
+ eClockFreqBiasUnc = 7,
+ eXoState = 8,
+ ePgaGain = 9,
+ eGpsBpAmpI = 10,
+ eGpsBpAmpQ = 11,
+ eAdcI = 12,
+ eAdcQ = 13,
+ eJammerGps = 14,
+ eJammerGlo = 15,
+ eJammerBds = 16,
+ eJammerGal = 17,
+ eRecErrorRecovery = 18,
+ eAgcGps = 19,
+ eAgcGlo = 20,
+ eAgcBds = 21,
+ eAgcGal = 22,
+ eLeapSeconds = 23,
+ eLeapSecUnc = 24,
+ eGloBpAmpI = 25,
+ eGloBpAmpQ = 26,
+ eBdsBpAmpI = 27,
+ eBdsBpAmpQ = 28,
+ eGalBpAmpI = 29,
+ eGalBpAmpQ = 30,
+ eMax0 = eGalBpAmpQ,
+ eTimeUncNs = 31,
+ eMax
+ };
+ SystemStatusPQWM1 mM1;
+
+public:
+ inline uint16_t getGpsWeek() { return mM1.mGpsWeek; }
+ inline uint32_t getGpsTowMs() { return mM1.mGpsTowMs; }
+ inline uint8_t getTimeValid() { return mM1.mTimeValid; }
+ inline uint8_t getTimeSource() { return mM1.mTimeSource; }
+ inline int32_t getTimeUnc() { return mM1.mTimeUnc; }
+ inline int32_t getClockFreqBias() { return mM1.mClockFreqBias; }
+ inline int32_t getClockFreqBiasUnc() { return mM1.mClockFreqBiasUnc; }
+ inline uint8_t getXoState() { return mM1.mXoState;}
+ inline int32_t getPgaGain() { return mM1.mPgaGain; }
+ inline uint32_t getGpsBpAmpI() { return mM1.mGpsBpAmpI; }
+ inline uint32_t getGpsBpAmpQ() { return mM1.mGpsBpAmpQ; }
+ inline uint32_t getAdcI() { return mM1.mAdcI; }
+ inline uint32_t getAdcQ() { return mM1.mAdcQ; }
+ inline uint32_t getJammerGps() { return mM1.mJammerGps; }
+ inline uint32_t getJammerGlo() { return mM1.mJammerGlo; }
+ inline uint32_t getJammerBds() { return mM1.mJammerBds; }
+ inline uint32_t getJammerGal() { return mM1.mJammerGal; }
+ inline uint32_t getAgcGps() { return mM1.mAgcGps; }
+ inline uint32_t getAgcGlo() { return mM1.mAgcGlo; }
+ inline uint32_t getAgcBds() { return mM1.mAgcBds; }
+ inline uint32_t getAgcGal() { return mM1.mAgcGal; }
+ inline uint32_t getRecErrorRecovery() { return mM1.mRecErrorRecovery; }
+ inline int32_t getLeapSeconds(){ return mM1.mLeapSeconds; }
+ inline int32_t getLeapSecUnc() { return mM1.mLeapSecUnc; }
+ inline uint32_t getGloBpAmpI() { return mM1.mGloBpAmpI; }
+ inline uint32_t getGloBpAmpQ() { return mM1.mGloBpAmpQ; }
+ inline uint32_t getBdsBpAmpI() { return mM1.mBdsBpAmpI; }
+ inline uint32_t getBdsBpAmpQ() { return mM1.mBdsBpAmpQ; }
+ inline uint32_t getGalBpAmpI() { return mM1.mGalBpAmpI; }
+ inline uint32_t getGalBpAmpQ() { return mM1.mGalBpAmpQ; }
+ inline uint64_t getTimeUncNs() { return mM1.mTimeUncNs; }
+
+ SystemStatusPQWM1parser(const char *str_in, uint32_t len_in)
+ : SystemStatusNmeaBase(str_in, len_in)
+ {
+ memset(&mM1, 0, sizeof(mM1));
+ if (mField.size() <= eMax0) {
+ LOC_LOGE("PQWM1parser - invalid size=%zu", mField.size());
+ mM1.mTimeValid = 0;
+ return;
+ }
+ mM1.mGpsWeek = atoi(mField[eGpsWeek].c_str());
+ mM1.mGpsTowMs = atoi(mField[eGpsTowMs].c_str());
+ mM1.mTimeValid = atoi(mField[eTimeValid].c_str());
+ mM1.mTimeSource = atoi(mField[eTimeSource].c_str());
+ mM1.mTimeUnc = atoi(mField[eTimeUnc].c_str());
+ mM1.mClockFreqBias = atoi(mField[eClockFreqBias].c_str());
+ mM1.mClockFreqBiasUnc = atoi(mField[eClockFreqBiasUnc].c_str());
+ mM1.mXoState = atoi(mField[eXoState].c_str());
+ mM1.mPgaGain = atoi(mField[ePgaGain].c_str());
+ mM1.mGpsBpAmpI = atoi(mField[eGpsBpAmpI].c_str());
+ mM1.mGpsBpAmpQ = atoi(mField[eGpsBpAmpQ].c_str());
+ mM1.mAdcI = atoi(mField[eAdcI].c_str());
+ mM1.mAdcQ = atoi(mField[eAdcQ].c_str());
+ mM1.mJammerGps = atoi(mField[eJammerGps].c_str());
+ mM1.mJammerGlo = atoi(mField[eJammerGlo].c_str());
+ mM1.mJammerBds = atoi(mField[eJammerBds].c_str());
+ mM1.mJammerGal = atoi(mField[eJammerGal].c_str());
+ mM1.mRecErrorRecovery = atoi(mField[eRecErrorRecovery].c_str());
+ mM1.mAgcGps = atof(mField[eAgcGps].c_str());
+ mM1.mAgcGlo = atof(mField[eAgcGlo].c_str());
+ mM1.mAgcBds = atof(mField[eAgcBds].c_str());
+ mM1.mAgcGal = atof(mField[eAgcGal].c_str());
+ if (mField.size() > eLeapSecUnc) {
+ mM1.mLeapSeconds = atoi(mField[eLeapSeconds].c_str());
+ mM1.mLeapSecUnc = atoi(mField[eLeapSecUnc].c_str());
+ }
+ if (mField.size() > eGalBpAmpQ) {
+ mM1.mGloBpAmpI = atoi(mField[eGloBpAmpI].c_str());
+ mM1.mGloBpAmpQ = atoi(mField[eGloBpAmpQ].c_str());
+ mM1.mBdsBpAmpI = atoi(mField[eBdsBpAmpI].c_str());
+ mM1.mBdsBpAmpQ = atoi(mField[eBdsBpAmpQ].c_str());
+ mM1.mGalBpAmpI = atoi(mField[eGalBpAmpI].c_str());
+ mM1.mGalBpAmpQ = atoi(mField[eGalBpAmpQ].c_str());
+ }
+ if (mField.size() > eTimeUncNs) {
+ mM1.mTimeUncNs = strtoull(mField[eTimeUncNs].c_str(), nullptr, 10);
+ }
+ }
+
+ inline SystemStatusPQWM1& get() { return mM1;} //getparser
+};
+
+/******************************************************************************
+ SystemStatusPQWP1
+******************************************************************************/
+class SystemStatusPQWP1
+{
+public:
+ uint8_t mEpiValidity; // x4
+ float mEpiLat; // x5
+ float mEpiLon; // x6
+ float mEpiAlt; // x7
+ float mEpiHepe; // x8
+ float mEpiAltUnc; // x9
+ uint8_t mEpiSrc; // x10
+};
+
+class SystemStatusPQWP1parser : public SystemStatusNmeaBase
+{
+private:
+ enum
+ {
+ eTalker = 0,
+ eUtcTime = 1,
+ eEpiValidity = 2,
+ eEpiLat = 3,
+ eEpiLon = 4,
+ eEpiAlt = 5,
+ eEpiHepe = 6,
+ eEpiAltUnc = 7,
+ eEpiSrc = 8,
+ eMax
+ };
+ SystemStatusPQWP1 mP1;
+
+public:
+ inline uint8_t getEpiValidity() { return mP1.mEpiValidity; }
+ inline float getEpiLat() { return mP1.mEpiLat; }
+ inline float getEpiLon() { return mP1.mEpiLon; }
+ inline float getEpiAlt() { return mP1.mEpiAlt; }
+ inline float getEpiHepe() { return mP1.mEpiHepe; }
+ inline float getEpiAltUnc() { return mP1.mEpiAltUnc; }
+ inline uint8_t getEpiSrc() { return mP1.mEpiSrc; }
+
+ SystemStatusPQWP1parser(const char *str_in, uint32_t len_in)
+ : SystemStatusNmeaBase(str_in, len_in)
+ {
+ if (mField.size() < eMax) {
+ return;
+ }
+ memset(&mP1, 0, sizeof(mP1));
+ mP1.mEpiValidity = strtol(mField[eEpiValidity].c_str(), NULL, 16);
+ mP1.mEpiLat = atof(mField[eEpiLat].c_str());
+ mP1.mEpiLon = atof(mField[eEpiLon].c_str());
+ mP1.mEpiAlt = atof(mField[eEpiAlt].c_str());
+ mP1.mEpiHepe = atoi(mField[eEpiHepe].c_str());
+ mP1.mEpiAltUnc = atof(mField[eEpiAltUnc].c_str());
+ mP1.mEpiSrc = atoi(mField[eEpiSrc].c_str());
+ }
+
+ inline SystemStatusPQWP1& get() { return mP1;}
+};
+
+/******************************************************************************
+ SystemStatusPQWP2
+******************************************************************************/
+class SystemStatusPQWP2
+{
+public:
+ float mBestLat; // x4
+ float mBestLon; // x5
+ float mBestAlt; // x6
+ float mBestHepe; // x7
+ float mBestAltUnc; // x8
+};
+
+class SystemStatusPQWP2parser : public SystemStatusNmeaBase
+{
+private:
+ enum
+ {
+ eTalker = 0,
+ eUtcTime = 1,
+ eBestLat = 2,
+ eBestLon = 3,
+ eBestAlt = 4,
+ eBestHepe = 5,
+ eBestAltUnc = 6,
+ eMax
+ };
+ SystemStatusPQWP2 mP2;
+
+public:
+ inline float getBestLat() { return mP2.mBestLat; }
+ inline float getBestLon() { return mP2.mBestLon; }
+ inline float getBestAlt() { return mP2.mBestAlt; }
+ inline float getBestHepe() { return mP2.mBestHepe; }
+ inline float getBestAltUnc() { return mP2.mBestAltUnc; }
+
+ SystemStatusPQWP2parser(const char *str_in, uint32_t len_in)
+ : SystemStatusNmeaBase(str_in, len_in)
+ {
+ if (mField.size() < eMax) {
+ return;
+ }
+ memset(&mP2, 0, sizeof(mP2));
+ mP2.mBestLat = atof(mField[eBestLat].c_str());
+ mP2.mBestLon = atof(mField[eBestLon].c_str());
+ mP2.mBestAlt = atof(mField[eBestAlt].c_str());
+ mP2.mBestHepe = atof(mField[eBestHepe].c_str());
+ mP2.mBestAltUnc = atof(mField[eBestAltUnc].c_str());
+ }
+
+ inline SystemStatusPQWP2& get() { return mP2;}
+};
+
+/******************************************************************************
+ SystemStatusPQWP3
+******************************************************************************/
+class SystemStatusPQWP3
+{
+public:
+ uint8_t mXtraValidMask;
+ uint32_t mGpsXtraAge;
+ uint32_t mGloXtraAge;
+ uint32_t mBdsXtraAge;
+ uint32_t mGalXtraAge;
+ uint32_t mQzssXtraAge;
+ uint32_t mNavicXtraAge;
+ uint32_t mGpsXtraValid;
+ uint32_t mGloXtraValid;
+ uint64_t mBdsXtraValid;
+ uint64_t mGalXtraValid;
+ uint8_t mQzssXtraValid;
+ uint32_t mNavicXtraValid;
+};
+
+class SystemStatusPQWP3parser : public SystemStatusNmeaBase
+{
+private:
+ // todo: update for navic once available
+ enum
+ {
+ eTalker = 0,
+ eUtcTime = 1,
+ eXtraValidMask = 2,
+ eGpsXtraAge = 3,
+ eGloXtraAge = 4,
+ eBdsXtraAge = 5,
+ eGalXtraAge = 6,
+ eQzssXtraAge = 7,
+ eGpsXtraValid = 8,
+ eGloXtraValid = 9,
+ eBdsXtraValid = 10,
+ eGalXtraValid = 11,
+ eQzssXtraValid = 12,
+ eMax
+ };
+ SystemStatusPQWP3 mP3;
+
+public:
+ inline uint8_t getXtraValid() { return mP3.mXtraValidMask; }
+ inline uint32_t getGpsXtraAge() { return mP3.mGpsXtraAge; }
+ inline uint32_t getGloXtraAge() { return mP3.mGloXtraAge; }
+ inline uint32_t getBdsXtraAge() { return mP3.mBdsXtraAge; }
+ inline uint32_t getGalXtraAge() { return mP3.mGalXtraAge; }
+ inline uint32_t getQzssXtraAge() { return mP3.mQzssXtraAge; }
+ inline uint32_t getNavicXtraAge() { return mP3.mNavicXtraAge; }
+ inline uint32_t getGpsXtraValid() { return mP3.mGpsXtraValid; }
+ inline uint32_t getGloXtraValid() { return mP3.mGloXtraValid; }
+ inline uint64_t getBdsXtraValid() { return mP3.mBdsXtraValid; }
+ inline uint64_t getGalXtraValid() { return mP3.mGalXtraValid; }
+ inline uint8_t getQzssXtraValid() { return mP3.mQzssXtraValid; }
+ inline uint32_t getNavicXtraValid() { return mP3.mNavicXtraValid; }
+
+ SystemStatusPQWP3parser(const char *str_in, uint32_t len_in)
+ : SystemStatusNmeaBase(str_in, len_in)
+ {
+ if (mField.size() < eMax) {
+ return;
+ }
+ memset(&mP3, 0, sizeof(mP3));
+ // todo: update for navic once available
+ mP3.mXtraValidMask = strtol(mField[eXtraValidMask].c_str(), NULL, 16);
+ mP3.mGpsXtraAge = atoi(mField[eGpsXtraAge].c_str());
+ mP3.mGloXtraAge = atoi(mField[eGloXtraAge].c_str());
+ mP3.mBdsXtraAge = atoi(mField[eBdsXtraAge].c_str());
+ mP3.mGalXtraAge = atoi(mField[eGalXtraAge].c_str());
+ mP3.mQzssXtraAge = atoi(mField[eQzssXtraAge].c_str());
+ mP3.mGpsXtraValid = strtol(mField[eGpsXtraValid].c_str(), NULL, 16);
+ mP3.mGloXtraValid = strtol(mField[eGloXtraValid].c_str(), NULL, 16);
+ mP3.mBdsXtraValid = strtol(mField[eBdsXtraValid].c_str(), NULL, 16);
+ mP3.mGalXtraValid = strtol(mField[eGalXtraValid].c_str(), NULL, 16);
+ mP3.mQzssXtraValid = strtol(mField[eQzssXtraValid].c_str(), NULL, 16);
+ }
+
+ inline SystemStatusPQWP3& get() { return mP3;}
+};
+
+/******************************************************************************
+ SystemStatusPQWP4
+******************************************************************************/
+class SystemStatusPQWP4
+{
+public:
+ uint32_t mGpsEpheValid;
+ uint32_t mGloEpheValid;
+ uint64_t mBdsEpheValid;
+ uint64_t mGalEpheValid;
+ uint8_t mQzssEpheValid;
+};
+
+class SystemStatusPQWP4parser : public SystemStatusNmeaBase
+{
+private:
+ enum
+ {
+ eTalker = 0,
+ eUtcTime = 1,
+ eGpsEpheValid = 2,
+ eGloEpheValid = 3,
+ eBdsEpheValid = 4,
+ eGalEpheValid = 5,
+ eQzssEpheValid = 6,
+ eMax
+ };
+ SystemStatusPQWP4 mP4;
+
+public:
+ inline uint32_t getGpsEpheValid() { return mP4.mGpsEpheValid; }
+ inline uint32_t getGloEpheValid() { return mP4.mGloEpheValid; }
+ inline uint64_t getBdsEpheValid() { return mP4.mBdsEpheValid; }
+ inline uint64_t getGalEpheValid() { return mP4.mGalEpheValid; }
+ inline uint8_t getQzssEpheValid() { return mP4.mQzssEpheValid; }
+
+ SystemStatusPQWP4parser(const char *str_in, uint32_t len_in)
+ : SystemStatusNmeaBase(str_in, len_in)
+ {
+ if (mField.size() < eMax) {
+ return;
+ }
+ memset(&mP4, 0, sizeof(mP4));
+ mP4.mGpsEpheValid = strtol(mField[eGpsEpheValid].c_str(), NULL, 16);
+ mP4.mGloEpheValid = strtol(mField[eGloEpheValid].c_str(), NULL, 16);
+ mP4.mBdsEpheValid = strtol(mField[eBdsEpheValid].c_str(), NULL, 16);
+ mP4.mGalEpheValid = strtol(mField[eGalEpheValid].c_str(), NULL, 16);
+ mP4.mQzssEpheValid = strtol(mField[eQzssEpheValid].c_str(), NULL, 16);
+ }
+
+ inline SystemStatusPQWP4& get() { return mP4;}
+};
+
+/******************************************************************************
+ SystemStatusPQWP5
+******************************************************************************/
+class SystemStatusPQWP5
+{
+public:
+ uint32_t mGpsUnknownMask;
+ uint32_t mGloUnknownMask;
+ uint64_t mBdsUnknownMask;
+ uint64_t mGalUnknownMask;
+ uint8_t mQzssUnknownMask;
+ uint32_t mNavicUnknownMask;
+ uint32_t mGpsGoodMask;
+ uint32_t mGloGoodMask;
+ uint64_t mBdsGoodMask;
+ uint64_t mGalGoodMask;
+ uint8_t mQzssGoodMask;
+ uint32_t mNavicGoodMask;
+ uint32_t mGpsBadMask;
+ uint32_t mGloBadMask;
+ uint64_t mBdsBadMask;
+ uint64_t mGalBadMask;
+ uint8_t mQzssBadMask;
+ uint32_t mNavicBadMask;
+};
+
+class SystemStatusPQWP5parser : public SystemStatusNmeaBase
+{
+private:
+ // todo: update for navic once available
+ enum
+ {
+ eTalker = 0,
+ eUtcTime = 1,
+ eGpsUnknownMask = 2,
+ eGloUnknownMask = 3,
+ eBdsUnknownMask = 4,
+ eGalUnknownMask = 5,
+ eQzssUnknownMask = 6,
+ eGpsGoodMask = 7,
+ eGloGoodMask = 8,
+ eBdsGoodMask = 9,
+ eGalGoodMask = 10,
+ eQzssGoodMask = 11,
+ eGpsBadMask = 12,
+ eGloBadMask = 13,
+ eBdsBadMask = 14,
+ eGalBadMask = 15,
+ eQzssBadMask = 16,
+ eMax
+ };
+ SystemStatusPQWP5 mP5;
+
+public:
+ inline uint32_t getGpsUnknownMask() { return mP5.mGpsUnknownMask; }
+ inline uint32_t getGloUnknownMask() { return mP5.mGloUnknownMask; }
+ inline uint64_t getBdsUnknownMask() { return mP5.mBdsUnknownMask; }
+ inline uint64_t getGalUnknownMask() { return mP5.mGalUnknownMask; }
+ inline uint8_t getQzssUnknownMask() { return mP5.mQzssUnknownMask; }
+ inline uint32_t getNavicUnknownMask() { return mP5.mNavicUnknownMask; }
+ inline uint32_t getGpsGoodMask() { return mP5.mGpsGoodMask; }
+ inline uint32_t getGloGoodMask() { return mP5.mGloGoodMask; }
+ inline uint64_t getBdsGoodMask() { return mP5.mBdsGoodMask; }
+ inline uint64_t getGalGoodMask() { return mP5.mGalGoodMask; }
+ inline uint8_t getQzssGoodMask() { return mP5.mQzssGoodMask; }
+ inline uint32_t getNavicGoodMask() { return mP5.mNavicGoodMask; }
+ inline uint32_t getGpsBadMask() { return mP5.mGpsBadMask; }
+ inline uint32_t getGloBadMask() { return mP5.mGloBadMask; }
+ inline uint64_t getBdsBadMask() { return mP5.mBdsBadMask; }
+ inline uint64_t getGalBadMask() { return mP5.mGalBadMask; }
+ inline uint8_t getQzssBadMask() { return mP5.mQzssBadMask; }
+ inline uint32_t getNavicBadMask() { return mP5.mNavicBadMask; }
+
+ SystemStatusPQWP5parser(const char *str_in, uint32_t len_in)
+ : SystemStatusNmeaBase(str_in, len_in)
+ {
+ if (mField.size() < eMax) {
+ return;
+ }
+ memset(&mP5, 0, sizeof(mP5));
+ // todo: update for navic once available
+ mP5.mGpsUnknownMask = strtol(mField[eGpsUnknownMask].c_str(), NULL, 16);
+ mP5.mGloUnknownMask = strtol(mField[eGloUnknownMask].c_str(), NULL, 16);
+ mP5.mBdsUnknownMask = strtol(mField[eBdsUnknownMask].c_str(), NULL, 16);
+ mP5.mGalUnknownMask = strtol(mField[eGalUnknownMask].c_str(), NULL, 16);
+ mP5.mQzssUnknownMask = strtol(mField[eQzssUnknownMask].c_str(), NULL, 16);
+ mP5.mGpsGoodMask = strtol(mField[eGpsGoodMask].c_str(), NULL, 16);
+ mP5.mGloGoodMask = strtol(mField[eGloGoodMask].c_str(), NULL, 16);
+ mP5.mBdsGoodMask = strtol(mField[eBdsGoodMask].c_str(), NULL, 16);
+ mP5.mGalGoodMask = strtol(mField[eGalGoodMask].c_str(), NULL, 16);
+ mP5.mQzssGoodMask = strtol(mField[eQzssGoodMask].c_str(), NULL, 16);
+ mP5.mGpsBadMask = strtol(mField[eGpsBadMask].c_str(), NULL, 16);
+ mP5.mGloBadMask = strtol(mField[eGloBadMask].c_str(), NULL, 16);
+ mP5.mBdsBadMask = strtol(mField[eBdsBadMask].c_str(), NULL, 16);
+ mP5.mGalBadMask = strtol(mField[eGalBadMask].c_str(), NULL, 16);
+ mP5.mQzssBadMask = strtol(mField[eQzssBadMask].c_str(), NULL, 16);
+ }
+
+ inline SystemStatusPQWP5& get() { return mP5;}
+};
+
+/******************************************************************************
+ SystemStatusPQWP6parser
+******************************************************************************/
+class SystemStatusPQWP6
+{
+public:
+ uint32_t mFixInfoMask;
+};
+
+class SystemStatusPQWP6parser : public SystemStatusNmeaBase
+{
+private:
+ enum
+ {
+ eTalker = 0,
+ eUtcTime = 1,
+ eFixInfoMask = 2,
+ eMax
+ };
+ SystemStatusPQWP6 mP6;
+
+public:
+ inline uint32_t getFixInfoMask() { return mP6.mFixInfoMask; }
+
+ SystemStatusPQWP6parser(const char *str_in, uint32_t len_in)
+ : SystemStatusNmeaBase(str_in, len_in)
+ {
+ if (mField.size() < eMax) {
+ return;
+ }
+ memset(&mP6, 0, sizeof(mP6));
+ mP6.mFixInfoMask = strtol(mField[eFixInfoMask].c_str(), NULL, 16);
+ }
+
+ inline SystemStatusPQWP6& get() { return mP6;}
+};
+
+/******************************************************************************
+ SystemStatusPQWP7parser
+******************************************************************************/
+class SystemStatusPQWP7
+{
+public:
+ SystemStatusNav mNav[SV_ALL_NUM];
+};
+
+class SystemStatusPQWP7parser : public SystemStatusNmeaBase
+{
+private:
+ enum
+ {
+ eTalker = 0,
+ eUtcTime = 1,
+ eMin = 2 + SV_ALL_NUM_MIN*3,
+ eMax = 2 + SV_ALL_NUM*3
+ };
+ SystemStatusPQWP7 mP7;
+
+public:
+ SystemStatusPQWP7parser(const char *str_in, uint32_t len_in)
+ : SystemStatusNmeaBase(str_in, len_in)
+ {
+ uint32_t svLimit = SV_ALL_NUM;
+ if (mField.size() < eMin) {
+ LOC_LOGE("PQWP7parser - invalid size=%zu", mField.size());
+ return;
+ }
+ if (mField.size() < eMax) {
+ // Try reducing limit, accounting for possibly missing NAVIC support
+ svLimit = SV_ALL_NUM_MIN;
+ }
+
+ memset(mP7.mNav, 0, sizeof(mP7.mNav));
+ for (uint32_t i=0; i<svLimit; i++) {
+ mP7.mNav[i].mType = GnssEphemerisType(atoi(mField[i*3+2].c_str()));
+ mP7.mNav[i].mSource = GnssEphemerisSource(atoi(mField[i*3+3].c_str()));
+ mP7.mNav[i].mAgeSec = atoi(mField[i*3+4].c_str());
+ }
+ }
+
+ inline SystemStatusPQWP7& get() { return mP7;}
+};
+
+/******************************************************************************
+ SystemStatusPQWS1parser
+******************************************************************************/
+class SystemStatusPQWS1
+{
+public:
+ uint32_t mFixInfoMask;
+ uint32_t mHepeLimit;
+};
+
+class SystemStatusPQWS1parser : public SystemStatusNmeaBase
+{
+private:
+ enum
+ {
+ eTalker = 0,
+ eUtcTime = 1,
+ eFixInfoMask = 2,
+ eHepeLimit = 3,
+ eMax
+ };
+ SystemStatusPQWS1 mS1;
+
+public:
+ inline uint16_t getFixInfoMask() { return mS1.mFixInfoMask; }
+ inline uint32_t getHepeLimit() { return mS1.mHepeLimit; }
+
+ SystemStatusPQWS1parser(const char *str_in, uint32_t len_in)
+ : SystemStatusNmeaBase(str_in, len_in)
+ {
+ if (mField.size() < eMax) {
+ return;
+ }
+ memset(&mS1, 0, sizeof(mS1));
+ mS1.mFixInfoMask = atoi(mField[eFixInfoMask].c_str());
+ mS1.mHepeLimit = atoi(mField[eHepeLimit].c_str());
+ }
+
+ inline SystemStatusPQWS1& get() { return mS1;}
+};
+
+/******************************************************************************
+ SystemStatusTimeAndClock
+******************************************************************************/
+SystemStatusTimeAndClock::SystemStatusTimeAndClock(const SystemStatusPQWM1& nmea) :
+ mGpsWeek(nmea.mGpsWeek),
+ mGpsTowMs(nmea.mGpsTowMs),
+ mTimeValid(nmea.mTimeValid),
+ mTimeSource(nmea.mTimeSource),
+ mTimeUnc(nmea.mTimeUnc),
+ mClockFreqBias(nmea.mClockFreqBias),
+ mClockFreqBiasUnc(nmea.mClockFreqBiasUnc),
+ mLeapSeconds(nmea.mLeapSeconds),
+ mLeapSecUnc(nmea.mLeapSecUnc),
+ mTimeUncNs(nmea.mTimeUncNs)
+{
+}
+
+bool SystemStatusTimeAndClock::equals(const SystemStatusTimeAndClock& peer)
+{
+ if ((mGpsWeek != peer.mGpsWeek) ||
+ (mGpsTowMs != peer.mGpsTowMs) ||
+ (mTimeValid != peer.mTimeValid) ||
+ (mTimeSource != peer.mTimeSource) ||
+ (mTimeUnc != peer.mTimeUnc) ||
+ (mClockFreqBias != peer.mClockFreqBias) ||
+ (mClockFreqBiasUnc != peer.mClockFreqBiasUnc) ||
+ (mLeapSeconds != peer.mLeapSeconds) ||
+ (mLeapSecUnc != peer.mLeapSecUnc) ||
+ (mTimeUncNs != peer.mTimeUncNs)) {
+ return false;
+ }
+ return true;
+}
+
+void SystemStatusTimeAndClock::dump()
+{
+ LOC_LOGV("TimeAndClock: u=%ld:%ld g=%d:%d v=%d ts=%d tu=%d b=%d bu=%d ls=%d lu=%d un=%" PRIu64,
+ mUtcTime.tv_sec, mUtcTime.tv_nsec,
+ mGpsWeek,
+ mGpsTowMs,
+ mTimeValid,
+ mTimeSource,
+ mTimeUnc,
+ mClockFreqBias,
+ mClockFreqBiasUnc,
+ mLeapSeconds,
+ mLeapSecUnc,
+ mTimeUncNs);
+ return;
+}
+
+/******************************************************************************
+ SystemStatusXoState
+******************************************************************************/
+SystemStatusXoState::SystemStatusXoState(const SystemStatusPQWM1& nmea) :
+ mXoState(nmea.mXoState)
+{
+}
+
+bool SystemStatusXoState::equals(const SystemStatusXoState& peer)
+{
+ if (mXoState != peer.mXoState) {
+ return false;
+ }
+ return true;
+}
+
+void SystemStatusXoState::dump()
+{
+ LOC_LOGV("XoState: u=%ld:%ld x=%d",
+ mUtcTime.tv_sec, mUtcTime.tv_nsec,
+ mXoState);
+ return;
+}
+
+/******************************************************************************
+ SystemStatusRfAndParams
+******************************************************************************/
+SystemStatusRfAndParams::SystemStatusRfAndParams(const SystemStatusPQWM1& nmea) :
+ mPgaGain(nmea.mPgaGain),
+ mGpsBpAmpI(nmea.mGpsBpAmpI),
+ mGpsBpAmpQ(nmea.mGpsBpAmpQ),
+ mAdcI(nmea.mAdcI),
+ mAdcQ(nmea.mAdcQ),
+ mJammerGps(nmea.mJammerGps),
+ mJammerGlo(nmea.mJammerGlo),
+ mJammerBds(nmea.mJammerBds),
+ mJammerGal(nmea.mJammerGal),
+ mAgcGps(nmea.mAgcGps),
+ mAgcGlo(nmea.mAgcGlo),
+ mAgcBds(nmea.mAgcBds),
+ mAgcGal(nmea.mAgcGal),
+ mGloBpAmpI(nmea.mGloBpAmpI),
+ mGloBpAmpQ(nmea.mGloBpAmpQ),
+ mBdsBpAmpI(nmea.mBdsBpAmpI),
+ mBdsBpAmpQ(nmea.mBdsBpAmpQ),
+ mGalBpAmpI(nmea.mGalBpAmpI),
+ mGalBpAmpQ(nmea.mGalBpAmpQ)
+{
+}
+
+bool SystemStatusRfAndParams::equals(const SystemStatusRfAndParams& peer)
+{
+ if ((mPgaGain != peer.mPgaGain) ||
+ (mGpsBpAmpI != peer.mGpsBpAmpI) ||
+ (mGpsBpAmpQ != peer.mGpsBpAmpQ) ||
+ (mAdcI != peer.mAdcI) ||
+ (mAdcQ != peer.mAdcQ) ||
+ (mJammerGps != peer.mJammerGps) ||
+ (mJammerGlo != peer.mJammerGlo) ||
+ (mJammerBds != peer.mJammerBds) ||
+ (mJammerGal != peer.mJammerGal) ||
+ (mAgcGps != peer.mAgcGps) ||
+ (mAgcGlo != peer.mAgcGlo) ||
+ (mAgcBds != peer.mAgcBds) ||
+ (mAgcGal != peer.mAgcGal) ||
+ (mGloBpAmpI != peer.mGloBpAmpI) ||
+ (mGloBpAmpQ != peer.mGloBpAmpQ) ||
+ (mBdsBpAmpI != peer.mBdsBpAmpI) ||
+ (mBdsBpAmpQ != peer.mBdsBpAmpQ) ||
+ (mGalBpAmpI != peer.mGalBpAmpI) ||
+ (mGalBpAmpQ != peer.mGalBpAmpQ)) {
+ return false;
+ }
+ return true;
+}
+
+void SystemStatusRfAndParams::dump()
+{
+ LOC_LOGV("RfAndParams: u=%ld:%ld p=%d bi=%d bq=%d ai=%d aq=%d "
+ "jgp=%d jgl=%d jbd=%d jga=%d "
+ "agp=%lf agl=%lf abd=%lf aga=%lf",
+ mUtcTime.tv_sec, mUtcTime.tv_nsec,
+ mPgaGain,
+ mGpsBpAmpI,
+ mGpsBpAmpQ,
+ mAdcI,
+ mAdcQ,
+ mJammerGps,
+ mJammerGlo,
+ mJammerBds,
+ mJammerGal,
+ mAgcGps,
+ mAgcGlo,
+ mAgcBds,
+ mAgcGal);
+ return;
+}
+
+/******************************************************************************
+ SystemStatusErrRecovery
+******************************************************************************/
+SystemStatusErrRecovery::SystemStatusErrRecovery(const SystemStatusPQWM1& nmea) :
+ mRecErrorRecovery(nmea.mRecErrorRecovery)
+{
+}
+
+bool SystemStatusErrRecovery::equals(const SystemStatusErrRecovery& peer)
+{
+ if (mRecErrorRecovery != peer.mRecErrorRecovery) {
+ return false;
+ }
+ return true;
+}
+
+void SystemStatusErrRecovery::dump()
+{
+ LOC_LOGV("ErrRecovery: u=%ld:%ld e=%d",
+ mUtcTime.tv_sec, mUtcTime.tv_nsec,
+ mRecErrorRecovery);
+ return;
+}
+
+/******************************************************************************
+ SystemStatusInjectedPosition
+******************************************************************************/
+SystemStatusInjectedPosition::SystemStatusInjectedPosition(const SystemStatusPQWP1& nmea) :
+ mEpiValidity(nmea.mEpiValidity),
+ mEpiLat(nmea.mEpiLat),
+ mEpiLon(nmea.mEpiLon),
+ mEpiAlt(nmea.mEpiAlt),
+ mEpiHepe(nmea.mEpiHepe),
+ mEpiAltUnc(nmea.mEpiAltUnc),
+ mEpiSrc(nmea.mEpiSrc)
+{
+}
+
+bool SystemStatusInjectedPosition::equals(const SystemStatusInjectedPosition& peer)
+{
+ if ((mEpiValidity != peer.mEpiValidity) ||
+ (mEpiLat != peer.mEpiLat) ||
+ (mEpiLon != peer.mEpiLon) ||
+ (mEpiAlt != peer.mEpiAlt) ||
+ (mEpiHepe != peer.mEpiHepe) ||
+ (mEpiAltUnc != peer.mEpiAltUnc) ||
+ (mEpiSrc != peer.mEpiSrc)) {
+ return false;
+ }
+ return true;
+}
+
+void SystemStatusInjectedPosition::dump()
+{
+ LOC_LOGV("InjectedPosition: u=%ld:%ld v=%x la=%f lo=%f al=%f he=%f au=%f es=%d",
+ mUtcTime.tv_sec, mUtcTime.tv_nsec,
+ mEpiValidity,
+ mEpiLat,
+ mEpiLon,
+ mEpiAlt,
+ mEpiHepe,
+ mEpiAltUnc,
+ mEpiSrc);
+ return;
+}
+
+/******************************************************************************
+ SystemStatusBestPosition
+******************************************************************************/
+SystemStatusBestPosition::SystemStatusBestPosition(const SystemStatusPQWP2& nmea) :
+ mValid(true),
+ mBestLat(nmea.mBestLat),
+ mBestLon(nmea.mBestLon),
+ mBestAlt(nmea.mBestAlt),
+ mBestHepe(nmea.mBestHepe),
+ mBestAltUnc(nmea.mBestAltUnc)
+{
+}
+
+bool SystemStatusBestPosition::equals(const SystemStatusBestPosition& peer)
+{
+ if ((mBestLat != peer.mBestLat) ||
+ (mBestLon != peer.mBestLon) ||
+ (mBestAlt != peer.mBestAlt) ||
+ (mBestHepe != peer.mBestHepe) ||
+ (mBestAltUnc != peer.mBestAltUnc)) {
+ return false;
+ }
+ return true;
+}
+
+void SystemStatusBestPosition::dump()
+{
+ LOC_LOGV("BestPosition: u=%ld:%ld la=%f lo=%f al=%f he=%f au=%f",
+ mUtcTime.tv_sec, mUtcTime.tv_nsec,
+ mBestLat,
+ mBestLon,
+ mBestAlt,
+ mBestHepe,
+ mBestAltUnc);
+ return;
+}
+
+/******************************************************************************
+ SystemStatusXtra
+******************************************************************************/
+SystemStatusXtra::SystemStatusXtra(const SystemStatusPQWP3& nmea) :
+ mXtraValidMask(nmea.mXtraValidMask),
+ mGpsXtraAge(nmea.mGpsXtraAge),
+ mGloXtraAge(nmea.mGloXtraAge),
+ mBdsXtraAge(nmea.mBdsXtraAge),
+ mGalXtraAge(nmea.mGalXtraAge),
+ mQzssXtraAge(nmea.mQzssXtraAge),
+ mNavicXtraAge(nmea.mNavicXtraAge),
+ mGpsXtraValid(nmea.mGpsXtraValid),
+ mGloXtraValid(nmea.mGloXtraValid),
+ mBdsXtraValid(nmea.mBdsXtraValid),
+ mGalXtraValid(nmea.mGalXtraValid),
+ mQzssXtraValid(nmea.mQzssXtraValid),
+ mNavicXtraValid(nmea.mNavicXtraValid)
+{
+}
+
+bool SystemStatusXtra::equals(const SystemStatusXtra& peer)
+{
+ if ((mXtraValidMask != peer.mXtraValidMask) ||
+ (mGpsXtraAge != peer.mGpsXtraAge) ||
+ (mGloXtraAge != peer.mGloXtraAge) ||
+ (mBdsXtraAge != peer.mBdsXtraAge) ||
+ (mGalXtraAge != peer.mGalXtraAge) ||
+ (mQzssXtraAge != peer.mQzssXtraAge) ||
+ (mNavicXtraAge != peer.mNavicXtraAge) ||
+ (mGpsXtraValid != peer.mGpsXtraValid) ||
+ (mGloXtraValid != peer.mGloXtraValid) ||
+ (mBdsXtraValid != peer.mBdsXtraValid) ||
+ (mGalXtraValid != peer.mGalXtraValid) ||
+ (mQzssXtraValid != peer.mQzssXtraValid) ||
+ (mNavicXtraValid != peer.mNavicXtraValid)) {
+ return false;
+ }
+ return true;
+}
+
+void SystemStatusXtra::dump()
+{
+ LOC_LOGV("SystemStatusXtra: u=%ld:%ld m=%x a=%d:%d:%d:%d:%d v=%x:%x:%" PRIx64 ":%" PRIx64":%x",
+ mUtcTime.tv_sec, mUtcTime.tv_nsec,
+ mXtraValidMask,
+ mGpsXtraAge,
+ mGloXtraAge,
+ mBdsXtraAge,
+ mGalXtraAge,
+ mQzssXtraAge,
+ mGpsXtraValid,
+ mGloXtraValid,
+ mBdsXtraValid,
+ mGalXtraValid,
+ mQzssXtraValid);
+ return;
+}
+
+/******************************************************************************
+ SystemStatusEphemeris
+******************************************************************************/
+SystemStatusEphemeris::SystemStatusEphemeris(const SystemStatusPQWP4& nmea) :
+ mGpsEpheValid(nmea.mGpsEpheValid),
+ mGloEpheValid(nmea.mGloEpheValid),
+ mBdsEpheValid(nmea.mBdsEpheValid),
+ mGalEpheValid(nmea.mGalEpheValid),
+ mQzssEpheValid(nmea.mQzssEpheValid)
+{
+}
+
+bool SystemStatusEphemeris::equals(const SystemStatusEphemeris& peer)
+{
+ if ((mGpsEpheValid != peer.mGpsEpheValid) ||
+ (mGloEpheValid != peer.mGloEpheValid) ||
+ (mBdsEpheValid != peer.mBdsEpheValid) ||
+ (mGalEpheValid != peer.mGalEpheValid) ||
+ (mQzssEpheValid != peer.mQzssEpheValid)) {
+ return false;
+ }
+ return true;
+}
+
+void SystemStatusEphemeris::dump()
+{
+ LOC_LOGV("Ephemeris: u=%ld:%ld ev=%x:%x:%" PRIx64 ":%" PRIx64 ":%x",
+ mUtcTime.tv_sec, mUtcTime.tv_nsec,
+ mGpsEpheValid,
+ mGloEpheValid,
+ mBdsEpheValid,
+ mGalEpheValid,
+ mQzssEpheValid);
+ return;
+}
+
+/******************************************************************************
+ SystemStatusSvHealth
+******************************************************************************/
+SystemStatusSvHealth::SystemStatusSvHealth(const SystemStatusPQWP5& nmea) :
+ mGpsUnknownMask(nmea.mGpsUnknownMask),
+ mGloUnknownMask(nmea.mGloUnknownMask),
+ mBdsUnknownMask(nmea.mBdsUnknownMask),
+ mGalUnknownMask(nmea.mGalUnknownMask),
+ mQzssUnknownMask(nmea.mQzssUnknownMask),
+ mNavicUnknownMask(nmea.mNavicUnknownMask),
+ mGpsGoodMask(nmea.mGpsGoodMask),
+ mGloGoodMask(nmea.mGloGoodMask),
+ mBdsGoodMask(nmea.mBdsGoodMask),
+ mGalGoodMask(nmea.mGalGoodMask),
+ mQzssGoodMask(nmea.mQzssGoodMask),
+ mNavicGoodMask(nmea.mNavicGoodMask),
+ mGpsBadMask(nmea.mGpsBadMask),
+ mGloBadMask(nmea.mGloBadMask),
+ mBdsBadMask(nmea.mBdsBadMask),
+ mGalBadMask(nmea.mGalBadMask),
+ mQzssBadMask(nmea.mQzssBadMask),
+ mNavicBadMask(nmea.mNavicBadMask)
+{
+}
+
+bool SystemStatusSvHealth::equals(const SystemStatusSvHealth& peer)
+{
+ if ((mGpsUnknownMask != peer.mGpsUnknownMask) ||
+ (mGloUnknownMask != peer.mGloUnknownMask) ||
+ (mBdsUnknownMask != peer.mBdsUnknownMask) ||
+ (mGalUnknownMask != peer.mGalUnknownMask) ||
+ (mQzssUnknownMask != peer.mQzssUnknownMask) ||
+ (mGpsGoodMask != peer.mGpsGoodMask) ||
+ (mGloGoodMask != peer.mGloGoodMask) ||
+ (mBdsGoodMask != peer.mBdsGoodMask) ||
+ (mGalGoodMask != peer.mGalGoodMask) ||
+ (mQzssGoodMask != peer.mQzssGoodMask) ||
+ (mGpsBadMask != peer.mGpsBadMask) ||
+ (mGloBadMask != peer.mGloBadMask) ||
+ (mBdsBadMask != peer.mBdsBadMask) ||
+ (mGalBadMask != peer.mGalBadMask) ||
+ (mQzssBadMask != peer.mQzssBadMask)) {
+ return false;
+ }
+ return true;
+}
+
+void SystemStatusSvHealth::dump()
+{
+ LOC_LOGV("SvHealth: u=%ld:%ld \
+ u=%x:%x:%" PRIx64 ":%" PRIx64 ":%x \
+ g=%x:%x:%" PRIx64 ":%" PRIx64 ":%x \
+ b=%x:%x:%" PRIx64 ":%" PRIx64 ":%x",
+ mUtcTime.tv_sec, mUtcTime.tv_nsec,
+ mGpsUnknownMask,
+ mGloUnknownMask,
+ mBdsUnknownMask,
+ mGalUnknownMask,
+ mQzssUnknownMask,
+ mGpsGoodMask,
+ mGloGoodMask,
+ mBdsGoodMask,
+ mGalGoodMask,
+ mQzssGoodMask,
+ mGpsBadMask,
+ mGloBadMask,
+ mBdsBadMask,
+ mGalBadMask,
+ mQzssBadMask);
+ return;
+}
+
+/******************************************************************************
+ SystemStatusPdr
+******************************************************************************/
+SystemStatusPdr::SystemStatusPdr(const SystemStatusPQWP6& nmea) :
+ mFixInfoMask(nmea.mFixInfoMask)
+{
+}
+
+bool SystemStatusPdr::equals(const SystemStatusPdr& peer)
+{
+ if (mFixInfoMask != peer.mFixInfoMask) {
+ return false;
+ }
+ return true;
+}
+
+void SystemStatusPdr::dump()
+{
+ LOC_LOGV("Pdr: u=%ld:%ld m=%x",
+ mUtcTime.tv_sec, mUtcTime.tv_nsec,
+ mFixInfoMask);
+ return;
+}
+
+/******************************************************************************
+ SystemStatusNavData
+******************************************************************************/
+SystemStatusNavData::SystemStatusNavData(const SystemStatusPQWP7& nmea)
+{
+ for (uint32_t i=0; i<SV_ALL_NUM; i++) {
+ mNav[i] = nmea.mNav[i];
+ }
+}
+
+bool SystemStatusNavData::equals(const SystemStatusNavData& peer)
+{
+ for (uint32_t i=0; i<SV_ALL_NUM; i++) {
+ if ((mNav[i].mType != peer.mNav[i].mType) ||
+ (mNav[i].mSource != peer.mNav[i].mSource) ||
+ (mNav[i].mAgeSec != peer.mNav[i].mAgeSec)) {
+ return false;
+ }
+ }
+ return true;
+}
+
+void SystemStatusNavData::dump()
+{
+ LOC_LOGV("NavData: u=%ld:%ld",
+ mUtcTime.tv_sec, mUtcTime.tv_nsec);
+ for (uint32_t i=0; i<SV_ALL_NUM; i++) {
+ LOC_LOGV("i=%d type=%d src=%d age=%d",
+ i, mNav[i].mType, mNav[i].mSource, mNav[i].mAgeSec);
+ }
+ return;
+}
+
+/******************************************************************************
+ SystemStatusPositionFailure
+******************************************************************************/
+SystemStatusPositionFailure::SystemStatusPositionFailure(const SystemStatusPQWS1& nmea) :
+ mFixInfoMask(nmea.mFixInfoMask),
+ mHepeLimit(nmea.mHepeLimit)
+{
+}
+
+bool SystemStatusPositionFailure::equals(const SystemStatusPositionFailure& peer)
+{
+ if ((mFixInfoMask != peer.mFixInfoMask) ||
+ (mHepeLimit != peer.mHepeLimit)) {
+ return false;
+ }
+ return true;
+}
+
+void SystemStatusPositionFailure::dump()
+{
+ LOC_LOGV("PositionFailure: u=%ld:%ld m=%d h=%d",
+ mUtcTime.tv_sec, mUtcTime.tv_nsec,
+ mFixInfoMask,
+ mHepeLimit);
+ return;
+}
+
+/******************************************************************************
+ SystemStatusLocation
+******************************************************************************/
+bool SystemStatusLocation::equals(const SystemStatusLocation& peer)
+{
+ if ((mLocation.gpsLocation.latitude != peer.mLocation.gpsLocation.latitude) ||
+ (mLocation.gpsLocation.longitude != peer.mLocation.gpsLocation.longitude) ||
+ (mLocation.gpsLocation.altitude != peer.mLocation.gpsLocation.altitude)) {
+ return false;
+ }
+ return true;
+}
+
+void SystemStatusLocation::dump()
+{
+ LOC_LOGV("Location: lat=%f lon=%f alt=%f spd=%f",
+ mLocation.gpsLocation.latitude,
+ mLocation.gpsLocation.longitude,
+ mLocation.gpsLocation.altitude,
+ mLocation.gpsLocation.speed);
+ return;
+}
+
+/******************************************************************************
+ SystemStatus
+******************************************************************************/
+pthread_mutex_t SystemStatus::mMutexSystemStatus = PTHREAD_MUTEX_INITIALIZER;
+SystemStatus* SystemStatus::mInstance = NULL;
+
+SystemStatus* SystemStatus::getInstance(const MsgTask* msgTask)
+{
+ pthread_mutex_lock(&mMutexSystemStatus);
+
+ if (!mInstance) {
+ // Instantiating for the first time. msgTask should not be NULL
+ if (msgTask == NULL) {
+ LOC_LOGE("SystemStatus: msgTask is NULL!!");
+ pthread_mutex_unlock(&mMutexSystemStatus);
+ return NULL;
+ }
+ mInstance = new (nothrow) SystemStatus(msgTask);
+ LOC_LOGD("SystemStatus::getInstance:%p. Msgtask:%p", mInstance, msgTask);
+ }
+
+ pthread_mutex_unlock(&mMutexSystemStatus);
+ return mInstance;
+}
+
+void SystemStatus::destroyInstance()
+{
+ delete mInstance;
+ mInstance = NULL;
+}
+
+IOsObserver* SystemStatus::getOsObserver()
+{
+ return &mSysStatusObsvr;
+}
+
+SystemStatus::SystemStatus(const MsgTask* msgTask) :
+ mSysStatusObsvr(this, msgTask)
+{
+ int result = 0;
+ ENTRY_LOG ();
+ mCache.mLocation.clear();
+
+ mCache.mTimeAndClock.clear();
+ mCache.mXoState.clear();
+ mCache.mRfAndParams.clear();
+ mCache.mErrRecovery.clear();
+
+ mCache.mInjectedPosition.clear();
+ mCache.mBestPosition.clear();
+ mCache.mXtra.clear();
+ mCache.mEphemeris.clear();
+ mCache.mSvHealth.clear();
+ mCache.mPdr.clear();
+ mCache.mNavData.clear();
+
+ mCache.mPositionFailure.clear();
+
+ mCache.mAirplaneMode.clear();
+ mCache.mENH.clear();
+ mCache.mGPSState.clear();
+ mCache.mNLPStatus.clear();
+ mCache.mWifiHardwareState.clear();
+ mCache.mNetworkInfo.clear();
+ mCache.mRilServiceInfo.clear();
+ mCache.mRilCellInfo.clear();
+ mCache.mServiceStatus.clear();
+ mCache.mModel.clear();
+ mCache.mManufacturer.clear();
+ mCache.mAssistedGps.clear();
+ mCache.mScreenState.clear();
+ mCache.mPowerConnectState.clear();
+ mCache.mTimeZoneChange.clear();
+ mCache.mTimeChange.clear();
+ mCache.mWifiSupplicantStatus.clear();
+ mCache.mShutdownState.clear();
+ mCache.mTac.clear();
+ mCache.mMccMnc.clear();
+ mCache.mBtDeviceScanDetail.clear();
+ mCache.mBtLeDeviceScanDetail.clear();
+
+ EXIT_LOG_WITH_ERROR ("%d",result);
+}
+
+/******************************************************************************
+ SystemStatus - storing dataitems
+******************************************************************************/
+template <typename TYPE_REPORT, typename TYPE_ITEM>
+bool SystemStatus::setIteminReport(TYPE_REPORT& report, TYPE_ITEM&& s)
+{
+ if (!report.empty() && report.back().equals(static_cast<TYPE_ITEM&>(s.collate(report.back())))) {
+ // there is no change - just update reported timestamp
+ report.back().mUtcReported = s.mUtcReported;
+ return false;
+ }
+
+ // first event or updated
+ report.push_back(s);
+ if (report.size() > s.maxItem) {
+ report.erase(report.begin());
+ }
+ return true;
+}
+
+template <typename TYPE_REPORT, typename TYPE_ITEM>
+void SystemStatus::setDefaultIteminReport(TYPE_REPORT& report, const TYPE_ITEM& s)
+{
+ report.push_back(s);
+ if (report.size() > s.maxItem) {
+ report.erase(report.begin());
+ }
+}
+
+template <typename TYPE_REPORT, typename TYPE_ITEM>
+void SystemStatus::getIteminReport(TYPE_REPORT& reportout, const TYPE_ITEM& c) const
+{
+ reportout.clear();
+ if (c.size() >= 1) {
+ reportout.push_back(c.back());
+ reportout.back().dump();
+ }
+}
+
+/******************************************************************************
+@brief API to set report data into internal buffer
+
+@param[In] data pointer to the NMEA string
+@param[In] len length of the NMEA string
+
+@return true when the NMEA is consumed by the method.
+******************************************************************************/
+bool SystemStatus::setNmeaString(const char *data, uint32_t len)
+{
+ if (!loc_nmea_is_debug(data, len)) {
+ return false;
+ }
+
+ char buf[SystemStatusNmeaBase::NMEA_MAXSIZE + 1] = { 0 };
+ strlcpy(buf, data, sizeof(buf));
+
+ pthread_mutex_lock(&mMutexSystemStatus);
+
+ // parse the received nmea strings here
+ if (0 == strncmp(data, "$PQWM1", SystemStatusNmeaBase::NMEA_MINSIZE)) {
+ SystemStatusPQWM1 s = SystemStatusPQWM1parser(buf, len).get();
+ setIteminReport(mCache.mTimeAndClock, SystemStatusTimeAndClock(s));
+ setIteminReport(mCache.mXoState, SystemStatusXoState(s));
+ setIteminReport(mCache.mRfAndParams, SystemStatusRfAndParams(s));
+ setIteminReport(mCache.mErrRecovery, SystemStatusErrRecovery(s));
+ }
+ else if (0 == strncmp(data, "$PQWP1", SystemStatusNmeaBase::NMEA_MINSIZE)) {
+ setIteminReport(mCache.mInjectedPosition,
+ SystemStatusInjectedPosition(SystemStatusPQWP1parser(buf, len).get()));
+ }
+ else if (0 == strncmp(data, "$PQWP2", SystemStatusNmeaBase::NMEA_MINSIZE)) {
+ setIteminReport(mCache.mBestPosition,
+ SystemStatusBestPosition(SystemStatusPQWP2parser(buf, len).get()));
+ }
+ else if (0 == strncmp(data, "$PQWP3", SystemStatusNmeaBase::NMEA_MINSIZE)) {
+ setIteminReport(mCache.mXtra,
+ SystemStatusXtra(SystemStatusPQWP3parser(buf, len).get()));
+ }
+ else if (0 == strncmp(data, "$PQWP4", SystemStatusNmeaBase::NMEA_MINSIZE)) {
+ setIteminReport(mCache.mEphemeris,
+ SystemStatusEphemeris(SystemStatusPQWP4parser(buf, len).get()));
+ }
+ else if (0 == strncmp(data, "$PQWP5", SystemStatusNmeaBase::NMEA_MINSIZE)) {
+ setIteminReport(mCache.mSvHealth,
+ SystemStatusSvHealth(SystemStatusPQWP5parser(buf, len).get()));
+ }
+ else if (0 == strncmp(data, "$PQWP6", SystemStatusNmeaBase::NMEA_MINSIZE)) {
+ setIteminReport(mCache.mPdr,
+ SystemStatusPdr(SystemStatusPQWP6parser(buf, len).get()));
+ }
+ else if (0 == strncmp(data, "$PQWP7", SystemStatusNmeaBase::NMEA_MINSIZE)) {
+ setIteminReport(mCache.mNavData,
+ SystemStatusNavData(SystemStatusPQWP7parser(buf, len).get()));
+ }
+ else if (0 == strncmp(data, "$PQWS1", SystemStatusNmeaBase::NMEA_MINSIZE)) {
+ setIteminReport(mCache.mPositionFailure,
+ SystemStatusPositionFailure(SystemStatusPQWS1parser(buf, len).get()));
+ }
+ else {
+ // do nothing
+ }
+
+ pthread_mutex_unlock(&mMutexSystemStatus);
+ return true;
+}
+
+/******************************************************************************
+@brief API to set report position data into internal buffer
+
+@param[In] UlpLocation
+
+@return true when successfully done
+******************************************************************************/
+bool SystemStatus::eventPosition(const UlpLocation& location,
+ const GpsLocationExtended& locationEx)
+{
+ bool ret = false;
+ pthread_mutex_lock(&mMutexSystemStatus);
+
+ ret = setIteminReport(mCache.mLocation, SystemStatusLocation(location, locationEx));
+ LOC_LOGV("eventPosition - lat=%f lon=%f alt=%f speed=%f",
+ location.gpsLocation.latitude,
+ location.gpsLocation.longitude,
+ location.gpsLocation.altitude,
+ location.gpsLocation.speed);
+
+ pthread_mutex_unlock(&mMutexSystemStatus);
+ return ret;
+}
+
+/******************************************************************************
+@brief API to set report DataItem event into internal buffer
+
+@param[In] DataItem
+
+@return true when info is updatated
+******************************************************************************/
+bool SystemStatus::eventDataItemNotify(IDataItemCore* dataitem)
+{
+ bool ret = false;
+ pthread_mutex_lock(&mMutexSystemStatus);
+ switch(dataitem->getId())
+ {
+ case AIRPLANEMODE_DATA_ITEM_ID:
+ ret = setIteminReport(mCache.mAirplaneMode,
+ SystemStatusAirplaneMode(*(static_cast<AirplaneModeDataItemBase*>(dataitem))));
+ break;
+ case ENH_DATA_ITEM_ID:
+ ret = setIteminReport(mCache.mENH,
+ SystemStatusENH(*(static_cast<ENHDataItemBase*>(dataitem))));
+ break;
+ case GPSSTATE_DATA_ITEM_ID:
+ ret = setIteminReport(mCache.mGPSState,
+ SystemStatusGpsState(*(static_cast<GPSStateDataItemBase*>(dataitem))));
+ break;
+ case NLPSTATUS_DATA_ITEM_ID:
+ ret = setIteminReport(mCache.mNLPStatus,
+ SystemStatusNLPStatus(*(static_cast<NLPStatusDataItemBase*>(dataitem))));
+ break;
+ case WIFIHARDWARESTATE_DATA_ITEM_ID:
+ ret = setIteminReport(mCache.mWifiHardwareState,
+ SystemStatusWifiHardwareState(*(static_cast<WifiHardwareStateDataItemBase*>(dataitem))));
+ break;
+ case NETWORKINFO_DATA_ITEM_ID:
+ ret = setIteminReport(mCache.mNetworkInfo,
+ SystemStatusNetworkInfo(*(static_cast<NetworkInfoDataItemBase*>(dataitem))));
+ break;
+ case RILSERVICEINFO_DATA_ITEM_ID:
+ ret = setIteminReport(mCache.mRilServiceInfo,
+ SystemStatusServiceInfo(*(static_cast<RilServiceInfoDataItemBase*>(dataitem))));
+ break;
+ case RILCELLINFO_DATA_ITEM_ID:
+ ret = setIteminReport(mCache.mRilCellInfo,
+ SystemStatusRilCellInfo(*(static_cast<RilCellInfoDataItemBase*>(dataitem))));
+ break;
+ case SERVICESTATUS_DATA_ITEM_ID:
+ ret = setIteminReport(mCache.mServiceStatus,
+ SystemStatusServiceStatus(*(static_cast<ServiceStatusDataItemBase*>(dataitem))));
+ break;
+ case MODEL_DATA_ITEM_ID:
+ ret = setIteminReport(mCache.mModel,
+ SystemStatusModel(*(static_cast<ModelDataItemBase*>(dataitem))));
+ break;
+ case MANUFACTURER_DATA_ITEM_ID:
+ ret = setIteminReport(mCache.mManufacturer,
+ SystemStatusManufacturer(*(static_cast<ManufacturerDataItemBase*>(dataitem))));
+ break;
+ case ASSISTED_GPS_DATA_ITEM_ID:
+ ret = setIteminReport(mCache.mAssistedGps,
+ SystemStatusAssistedGps(*(static_cast<AssistedGpsDataItemBase*>(dataitem))));
+ break;
+ case SCREEN_STATE_DATA_ITEM_ID:
+ ret = setIteminReport(mCache.mScreenState,
+ SystemStatusScreenState(*(static_cast<ScreenStateDataItemBase*>(dataitem))));
+ break;
+ case POWER_CONNECTED_STATE_DATA_ITEM_ID:
+ ret = setIteminReport(mCache.mPowerConnectState,
+ SystemStatusPowerConnectState(*(static_cast<PowerConnectStateDataItemBase*>(dataitem))));
+ break;
+ case TIMEZONE_CHANGE_DATA_ITEM_ID:
+ ret = setIteminReport(mCache.mTimeZoneChange,
+ SystemStatusTimeZoneChange(*(static_cast<TimeZoneChangeDataItemBase*>(dataitem))));
+ break;
+ case TIME_CHANGE_DATA_ITEM_ID:
+ ret = setIteminReport(mCache.mTimeChange,
+ SystemStatusTimeChange(*(static_cast<TimeChangeDataItemBase*>(dataitem))));
+ break;
+ case WIFI_SUPPLICANT_STATUS_DATA_ITEM_ID:
+ ret = setIteminReport(mCache.mWifiSupplicantStatus,
+ SystemStatusWifiSupplicantStatus(*(static_cast<WifiSupplicantStatusDataItemBase*>(dataitem))));
+ break;
+ case SHUTDOWN_STATE_DATA_ITEM_ID:
+ ret = setIteminReport(mCache.mShutdownState,
+ SystemStatusShutdownState(*(static_cast<ShutdownStateDataItemBase*>(dataitem))));
+ break;
+ case TAC_DATA_ITEM_ID:
+ ret = setIteminReport(mCache.mTac,
+ SystemStatusTac(*(static_cast<TacDataItemBase*>(dataitem))));
+ break;
+ case MCCMNC_DATA_ITEM_ID:
+ ret = setIteminReport(mCache.mMccMnc,
+ SystemStatusMccMnc(*(static_cast<MccmncDataItemBase*>(dataitem))));
+ break;
+ case BTLE_SCAN_DATA_ITEM_ID:
+ ret = setIteminReport(mCache.mBtDeviceScanDetail,
+ SystemStatusBtDeviceScanDetail(*(static_cast<BtDeviceScanDetailsDataItemBase*>(dataitem))));
+ break;
+ case BT_SCAN_DATA_ITEM_ID:
+ ret = setIteminReport(mCache.mBtLeDeviceScanDetail,
+ SystemStatusBtleDeviceScanDetail(*(static_cast<BtLeDeviceScanDetailsDataItemBase*>(dataitem))));
+ break;
+ default:
+ break;
+ }
+ pthread_mutex_unlock(&mMutexSystemStatus);
+ return ret;
+}
+
+/******************************************************************************
+@brief API to get report data into a given buffer
+
+@param[In] reference to report buffer
+@param[In] bool flag to identify latest only or entire buffer
+
+@return true when successfully done
+******************************************************************************/
+bool SystemStatus::getReport(SystemStatusReports& report, bool isLatestOnly) const
+{
+ pthread_mutex_lock(&mMutexSystemStatus);
+
+ if (isLatestOnly) {
+ // push back only the latest report and return it
+ getIteminReport(report.mLocation, mCache.mLocation);
+
+ getIteminReport(report.mTimeAndClock, mCache.mTimeAndClock);
+ getIteminReport(report.mXoState, mCache.mXoState);
+ getIteminReport(report.mRfAndParams, mCache.mRfAndParams);
+ getIteminReport(report.mErrRecovery, mCache.mErrRecovery);
+
+ getIteminReport(report.mInjectedPosition, mCache.mInjectedPosition);
+ getIteminReport(report.mBestPosition, mCache.mBestPosition);
+ getIteminReport(report.mXtra, mCache.mXtra);
+ getIteminReport(report.mEphemeris, mCache.mEphemeris);
+ getIteminReport(report.mSvHealth, mCache.mSvHealth);
+ getIteminReport(report.mPdr, mCache.mPdr);
+ getIteminReport(report.mNavData, mCache.mNavData);
+
+ getIteminReport(report.mPositionFailure, mCache.mPositionFailure);
+
+ getIteminReport(report.mAirplaneMode, mCache.mAirplaneMode);
+ getIteminReport(report.mENH, mCache.mENH);
+ getIteminReport(report.mGPSState, mCache.mGPSState);
+ getIteminReport(report.mNLPStatus, mCache.mNLPStatus);
+ getIteminReport(report.mWifiHardwareState, mCache.mWifiHardwareState);
+ getIteminReport(report.mNetworkInfo, mCache.mNetworkInfo);
+ getIteminReport(report.mRilServiceInfo, mCache.mRilServiceInfo);
+ getIteminReport(report.mRilCellInfo, mCache.mRilCellInfo);
+ getIteminReport(report.mServiceStatus, mCache.mServiceStatus);
+ getIteminReport(report.mModel, mCache.mModel);
+ getIteminReport(report.mManufacturer, mCache.mManufacturer);
+ getIteminReport(report.mAssistedGps, mCache.mAssistedGps);
+ getIteminReport(report.mScreenState, mCache.mScreenState);
+ getIteminReport(report.mPowerConnectState, mCache.mPowerConnectState);
+ getIteminReport(report.mTimeZoneChange, mCache.mTimeZoneChange);
+ getIteminReport(report.mTimeChange, mCache.mTimeChange);
+ getIteminReport(report.mWifiSupplicantStatus, mCache.mWifiSupplicantStatus);
+ getIteminReport(report.mShutdownState, mCache.mShutdownState);
+ getIteminReport(report.mTac, mCache.mTac);
+ getIteminReport(report.mMccMnc, mCache.mMccMnc);
+ getIteminReport(report.mBtDeviceScanDetail, mCache.mBtDeviceScanDetail);
+ getIteminReport(report.mBtLeDeviceScanDetail, mCache.mBtLeDeviceScanDetail);
+ }
+ else {
+ // copy entire reports and return them
+ report.mLocation.clear();
+
+ report.mTimeAndClock.clear();
+ report.mXoState.clear();
+ report.mRfAndParams.clear();
+ report.mErrRecovery.clear();
+
+ report.mInjectedPosition.clear();
+ report.mBestPosition.clear();
+ report.mXtra.clear();
+ report.mEphemeris.clear();
+ report.mSvHealth.clear();
+ report.mPdr.clear();
+ report.mNavData.clear();
+
+ report.mPositionFailure.clear();
+
+ report.mAirplaneMode.clear();
+ report.mENH.clear();
+ report.mGPSState.clear();
+ report.mNLPStatus.clear();
+ report.mWifiHardwareState.clear();
+ report.mNetworkInfo.clear();
+ report.mRilServiceInfo.clear();
+ report.mRilCellInfo.clear();
+ report.mServiceStatus.clear();
+ report.mModel.clear();
+ report.mManufacturer.clear();
+ report.mAssistedGps.clear();
+ report.mScreenState.clear();
+ report.mPowerConnectState.clear();
+ report.mTimeZoneChange.clear();
+ report.mTimeChange.clear();
+ report.mWifiSupplicantStatus.clear();
+ report.mShutdownState.clear();
+ report.mTac.clear();
+ report.mMccMnc.clear();
+ report.mBtDeviceScanDetail.clear();
+ report.mBtLeDeviceScanDetail.clear();
+
+ report = mCache;
+ }
+
+ pthread_mutex_unlock(&mMutexSystemStatus);
+ return true;
+}
+
+/******************************************************************************
+@brief API to set default report data
+
+@param[In] none
+
+@return true when successfully done
+******************************************************************************/
+bool SystemStatus::setDefaultGnssEngineStates(void)
+{
+ pthread_mutex_lock(&mMutexSystemStatus);
+
+ setDefaultIteminReport(mCache.mLocation, SystemStatusLocation());
+
+ setDefaultIteminReport(mCache.mTimeAndClock, SystemStatusTimeAndClock());
+ setDefaultIteminReport(mCache.mXoState, SystemStatusXoState());
+ setDefaultIteminReport(mCache.mRfAndParams, SystemStatusRfAndParams());
+ setDefaultIteminReport(mCache.mErrRecovery, SystemStatusErrRecovery());
+
+ setDefaultIteminReport(mCache.mInjectedPosition, SystemStatusInjectedPosition());
+ setDefaultIteminReport(mCache.mBestPosition, SystemStatusBestPosition());
+ setDefaultIteminReport(mCache.mXtra, SystemStatusXtra());
+ setDefaultIteminReport(mCache.mEphemeris, SystemStatusEphemeris());
+ setDefaultIteminReport(mCache.mSvHealth, SystemStatusSvHealth());
+ setDefaultIteminReport(mCache.mPdr, SystemStatusPdr());
+ setDefaultIteminReport(mCache.mNavData, SystemStatusNavData());
+
+ setDefaultIteminReport(mCache.mPositionFailure, SystemStatusPositionFailure());
+
+ pthread_mutex_unlock(&mMutexSystemStatus);
+ return true;
+}
+
+/******************************************************************************
+@brief API to handle connection status update event from GnssRil
+
+@param[In] Connection status
+
+@return true when successfully done
+******************************************************************************/
+bool SystemStatus::eventConnectionStatus(bool connected, int8_t type,
+ bool roaming, NetworkHandle networkHandle)
+{
+ // send networkinof dataitem to systemstatus observer clients
+ SystemStatusNetworkInfo s(type, "", "", connected, roaming,
+ (uint64_t) networkHandle);
+ mSysStatusObsvr.notify({&s});
+
+ return true;
+}
+
+/******************************************************************************
+@brief API to update power connect state
+
+@param[In] power connect status
+
+@return true when successfully done
+******************************************************************************/
+bool SystemStatus::updatePowerConnectState(bool charging)
+{
+ SystemStatusPowerConnectState s(charging);
+ mSysStatusObsvr.notify({&s});
+ return true;
+}
+} // namespace loc_core
+
diff --git a/core/SystemStatus.h b/core/SystemStatus.h
new file mode 100644
index 0000000..2cfb25d
--- /dev/null
+++ b/core/SystemStatus.h
@@ -0,0 +1,916 @@
+/* Copyright (c) 2017-2019, 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 __SYSTEM_STATUS__
+#define __SYSTEM_STATUS__
+
+#include <stdint.h>
+#include <sys/time.h>
+#include <vector>
+#include <algorithm>
+#include <iterator>
+#include <loc_pla.h>
+#include <log_util.h>
+#include <MsgTask.h>
+#include <IDataItemCore.h>
+#include <IOsObserver.h>
+#include <DataItemConcreteTypesBase.h>
+#include <SystemStatusOsObserver.h>
+
+#include <gps_extended_c.h>
+
+#define GPS_MIN (1) //1-32
+#define SBAS_MIN (33)
+#define GLO_MIN (65) //65-88
+#define QZSS_MIN (193) //193-197
+#define BDS_MIN (201) //201-237
+#define GAL_MIN (301) //301-336
+#define NAVIC_MIN (401) //401-414
+
+#define GPS_NUM (32)
+#define SBAS_NUM (32)
+#define GLO_NUM (24)
+#define QZSS_NUM (5)
+#define BDS_NUM (37)
+#define GAL_NUM (36)
+#define NAVIC_NUM (14)
+#define SV_ALL_NUM_MIN (GPS_NUM + GLO_NUM + QZSS_NUM + BDS_NUM + GAL_NUM) //=134
+#define SV_ALL_NUM (SV_ALL_NUM_MIN + NAVIC_NUM) //=148
+
+namespace loc_core
+{
+
+/******************************************************************************
+ SystemStatus report data structure
+******************************************************************************/
+class SystemStatusItemBase
+{
+public:
+ timespec mUtcTime;
+ timespec mUtcReported;
+ static const uint32_t maxItem = 5;
+
+ SystemStatusItemBase() {
+ timeval tv;
+ gettimeofday(&tv, NULL);
+ mUtcTime.tv_sec = tv.tv_sec;
+ mUtcTime.tv_nsec = tv.tv_usec*1000ULL;
+ mUtcReported = mUtcTime;
+ };
+ virtual ~SystemStatusItemBase() {};
+ inline virtual SystemStatusItemBase& collate(SystemStatusItemBase&) {
+ return *this;
+ }
+ virtual void dump(void) {};
+};
+
+class SystemStatusLocation : public SystemStatusItemBase
+{
+public:
+ bool mValid;
+ UlpLocation mLocation;
+ GpsLocationExtended mLocationEx;
+ inline SystemStatusLocation() :
+ mValid(false) {}
+ inline SystemStatusLocation(const UlpLocation& location,
+ const GpsLocationExtended& locationEx) :
+ mValid(true),
+ mLocation(location),
+ mLocationEx(locationEx) {}
+ bool equals(const SystemStatusLocation& peer);
+ void dump(void);
+};
+
+class SystemStatusPQWM1;
+class SystemStatusTimeAndClock : public SystemStatusItemBase
+{
+public:
+ uint16_t mGpsWeek;
+ uint32_t mGpsTowMs;
+ uint8_t mTimeValid;
+ uint8_t mTimeSource;
+ int32_t mTimeUnc;
+ int32_t mClockFreqBias;
+ int32_t mClockFreqBiasUnc;
+ int32_t mLeapSeconds;
+ int32_t mLeapSecUnc;
+ uint64_t mTimeUncNs;
+ inline SystemStatusTimeAndClock() :
+ mGpsWeek(0),
+ mGpsTowMs(0),
+ mTimeValid(0),
+ mTimeSource(0),
+ mTimeUnc(0),
+ mClockFreqBias(0),
+ mClockFreqBiasUnc(0),
+ mLeapSeconds(0),
+ mLeapSecUnc(0),
+ mTimeUncNs(0ULL) {}
+ inline SystemStatusTimeAndClock(const SystemStatusPQWM1& nmea);
+ bool equals(const SystemStatusTimeAndClock& peer);
+ void dump(void);
+};
+
+class SystemStatusXoState : public SystemStatusItemBase
+{
+public:
+ uint8_t mXoState;
+ inline SystemStatusXoState() :
+ mXoState(0) {}
+ inline SystemStatusXoState(const SystemStatusPQWM1& nmea);
+ bool equals(const SystemStatusXoState& peer);
+ void dump(void);
+};
+
+class SystemStatusRfAndParams : public SystemStatusItemBase
+{
+public:
+ int32_t mPgaGain;
+ uint32_t mGpsBpAmpI;
+ uint32_t mGpsBpAmpQ;
+ uint32_t mAdcI;
+ uint32_t mAdcQ;
+ uint32_t mJammerGps;
+ uint32_t mJammerGlo;
+ uint32_t mJammerBds;
+ uint32_t mJammerGal;
+ double mAgcGps;
+ double mAgcGlo;
+ double mAgcBds;
+ double mAgcGal;
+ uint32_t mGloBpAmpI;
+ uint32_t mGloBpAmpQ;
+ uint32_t mBdsBpAmpI;
+ uint32_t mBdsBpAmpQ;
+ uint32_t mGalBpAmpI;
+ uint32_t mGalBpAmpQ;
+ inline SystemStatusRfAndParams() :
+ mPgaGain(0),
+ mGpsBpAmpI(0),
+ mGpsBpAmpQ(0),
+ mAdcI(0),
+ mAdcQ(0),
+ mJammerGps(0),
+ mJammerGlo(0),
+ mJammerBds(0),
+ mJammerGal(0),
+ mAgcGps(0),
+ mAgcGlo(0),
+ mAgcBds(0),
+ mAgcGal(0),
+ mGloBpAmpI(0),
+ mGloBpAmpQ(0),
+ mBdsBpAmpI(0),
+ mBdsBpAmpQ(0),
+ mGalBpAmpI(0),
+ mGalBpAmpQ(0) {}
+ inline SystemStatusRfAndParams(const SystemStatusPQWM1& nmea);
+ bool equals(const SystemStatusRfAndParams& peer);
+ void dump(void);
+};
+
+class SystemStatusErrRecovery : public SystemStatusItemBase
+{
+public:
+ uint32_t mRecErrorRecovery;
+ inline SystemStatusErrRecovery() :
+ mRecErrorRecovery(0) {};
+ inline SystemStatusErrRecovery(const SystemStatusPQWM1& nmea);
+ bool equals(const SystemStatusErrRecovery& peer);
+ void dump(void);
+};
+
+class SystemStatusPQWP1;
+class SystemStatusInjectedPosition : public SystemStatusItemBase
+{
+public:
+ uint8_t mEpiValidity;
+ float mEpiLat;
+ float mEpiLon;
+ float mEpiAlt;
+ float mEpiHepe;
+ float mEpiAltUnc;
+ uint8_t mEpiSrc;
+ inline SystemStatusInjectedPosition() :
+ mEpiValidity(0),
+ mEpiLat(0),
+ mEpiLon(0),
+ mEpiAlt(0),
+ mEpiHepe(0),
+ mEpiAltUnc(0),
+ mEpiSrc(0) {}
+ inline SystemStatusInjectedPosition(const SystemStatusPQWP1& nmea);
+ bool equals(const SystemStatusInjectedPosition& peer);
+ void dump(void);
+};
+
+class SystemStatusPQWP2;
+class SystemStatusBestPosition : public SystemStatusItemBase
+{
+public:
+ bool mValid;
+ float mBestLat;
+ float mBestLon;
+ float mBestAlt;
+ float mBestHepe;
+ float mBestAltUnc;
+ inline SystemStatusBestPosition() :
+ mValid(false),
+ mBestLat(0),
+ mBestLon(0),
+ mBestAlt(0),
+ mBestHepe(0),
+ mBestAltUnc(0) {}
+ inline SystemStatusBestPosition(const SystemStatusPQWP2& nmea);
+ bool equals(const SystemStatusBestPosition& peer);
+ void dump(void);
+};
+
+class SystemStatusPQWP3;
+class SystemStatusXtra : public SystemStatusItemBase
+{
+public:
+ uint8_t mXtraValidMask;
+ uint32_t mGpsXtraAge;
+ uint32_t mGloXtraAge;
+ uint32_t mBdsXtraAge;
+ uint32_t mGalXtraAge;
+ uint32_t mQzssXtraAge;
+ uint32_t mNavicXtraAge;
+ uint32_t mGpsXtraValid;
+ uint32_t mGloXtraValid;
+ uint64_t mBdsXtraValid;
+ uint64_t mGalXtraValid;
+ uint8_t mQzssXtraValid;
+ uint32_t mNavicXtraValid;
+ inline SystemStatusXtra() :
+ mXtraValidMask(0),
+ mGpsXtraAge(0),
+ mGloXtraAge(0),
+ mBdsXtraAge(0),
+ mGalXtraAge(0),
+ mQzssXtraAge(0),
+ mNavicXtraAge(0),
+ mGpsXtraValid(0),
+ mGloXtraValid(0),
+ mBdsXtraValid(0ULL),
+ mGalXtraValid(0ULL),
+ mQzssXtraValid(0),
+ mNavicXtraValid(0) {}
+ inline SystemStatusXtra(const SystemStatusPQWP3& nmea);
+ bool equals(const SystemStatusXtra& peer);
+ void dump(void);
+};
+
+class SystemStatusPQWP4;
+class SystemStatusEphemeris : public SystemStatusItemBase
+{
+public:
+ uint32_t mGpsEpheValid;
+ uint32_t mGloEpheValid;
+ uint64_t mBdsEpheValid;
+ uint64_t mGalEpheValid;
+ uint8_t mQzssEpheValid;
+ inline SystemStatusEphemeris() :
+ mGpsEpheValid(0),
+ mGloEpheValid(0),
+ mBdsEpheValid(0ULL),
+ mGalEpheValid(0ULL),
+ mQzssEpheValid(0) {}
+ inline SystemStatusEphemeris(const SystemStatusPQWP4& nmea);
+ bool equals(const SystemStatusEphemeris& peer);
+ void dump(void);
+};
+
+class SystemStatusPQWP5;
+class SystemStatusSvHealth : public SystemStatusItemBase
+{
+public:
+ uint32_t mGpsUnknownMask;
+ uint32_t mGloUnknownMask;
+ uint64_t mBdsUnknownMask;
+ uint64_t mGalUnknownMask;
+ uint8_t mQzssUnknownMask;
+ uint32_t mNavicUnknownMask;
+ uint32_t mGpsGoodMask;
+ uint32_t mGloGoodMask;
+ uint64_t mBdsGoodMask;
+ uint64_t mGalGoodMask;
+ uint8_t mQzssGoodMask;
+ uint32_t mNavicGoodMask;
+ uint32_t mGpsBadMask;
+ uint32_t mGloBadMask;
+ uint64_t mBdsBadMask;
+ uint64_t mGalBadMask;
+ uint8_t mQzssBadMask;
+ uint32_t mNavicBadMask;
+ inline SystemStatusSvHealth() :
+ mGpsUnknownMask(0),
+ mGloUnknownMask(0),
+ mBdsUnknownMask(0ULL),
+ mGalUnknownMask(0ULL),
+ mQzssUnknownMask(0),
+ mNavicUnknownMask(0),
+ mGpsGoodMask(0),
+ mGloGoodMask(0),
+ mBdsGoodMask(0ULL),
+ mGalGoodMask(0ULL),
+ mQzssGoodMask(0),
+ mNavicGoodMask(0),
+ mGpsBadMask(0),
+ mGloBadMask(0),
+ mBdsBadMask(0ULL),
+ mGalBadMask(0ULL),
+ mQzssBadMask(0),
+ mNavicBadMask(0) {}
+ inline SystemStatusSvHealth(const SystemStatusPQWP5& nmea);
+ bool equals(const SystemStatusSvHealth& peer);
+ void dump(void);
+};
+
+class SystemStatusPQWP6;
+class SystemStatusPdr : public SystemStatusItemBase
+{
+public:
+ uint32_t mFixInfoMask;
+ inline SystemStatusPdr() :
+ mFixInfoMask(0) {}
+ inline SystemStatusPdr(const SystemStatusPQWP6& nmea);
+ bool equals(const SystemStatusPdr& peer);
+ void dump(void);
+};
+
+class SystemStatusPQWP7;
+struct SystemStatusNav
+{
+ GnssEphemerisType mType;
+ GnssEphemerisSource mSource;
+ int32_t mAgeSec;
+};
+
+class SystemStatusNavData : public SystemStatusItemBase
+{
+public:
+ SystemStatusNav mNav[SV_ALL_NUM];
+ inline SystemStatusNavData() {
+ for (uint32_t i=0; i<SV_ALL_NUM; i++) {
+ mNav[i].mType = GNSS_EPH_TYPE_UNKNOWN;
+ mNav[i].mSource = GNSS_EPH_SOURCE_UNKNOWN;
+ mNav[i].mAgeSec = 0;
+ }
+ }
+ inline SystemStatusNavData(const SystemStatusPQWP7& nmea);
+ bool equals(const SystemStatusNavData& peer);
+ void dump(void);
+};
+
+class SystemStatusPQWS1;
+class SystemStatusPositionFailure : public SystemStatusItemBase
+{
+public:
+ uint32_t mFixInfoMask;
+ uint32_t mHepeLimit;
+ inline SystemStatusPositionFailure() :
+ mFixInfoMask(0),
+ mHepeLimit(0) {}
+ inline SystemStatusPositionFailure(const SystemStatusPQWS1& nmea);
+ bool equals(const SystemStatusPositionFailure& peer);
+ void dump(void);
+};
+
+/******************************************************************************
+ SystemStatus report data structure - from DataItem observer
+******************************************************************************/
+class SystemStatusAirplaneMode : public SystemStatusItemBase,
+ public AirplaneModeDataItemBase
+{
+public:
+ inline SystemStatusAirplaneMode(bool mode=false) :
+ AirplaneModeDataItemBase(mode) {}
+ inline SystemStatusAirplaneMode(const AirplaneModeDataItemBase& itemBase) :
+ AirplaneModeDataItemBase(itemBase) {}
+ inline bool equals(const SystemStatusAirplaneMode& peer) {
+ return (mMode == peer.mMode);
+ }
+};
+
+class SystemStatusENH : public SystemStatusItemBase,
+ public ENHDataItemBase
+{
+public:
+ inline SystemStatusENH(bool enabled=false) :
+ ENHDataItemBase(enabled) {}
+ inline SystemStatusENH(const ENHDataItemBase& itemBase) :
+ ENHDataItemBase(itemBase) {}
+ inline bool equals(const SystemStatusENH& peer) {
+ return (mEnabled == peer.mEnabled);
+ }
+};
+
+class SystemStatusGpsState : public SystemStatusItemBase,
+ public GPSStateDataItemBase
+{
+public:
+ inline SystemStatusGpsState(bool enabled=false) :
+ GPSStateDataItemBase(enabled) {}
+ inline SystemStatusGpsState(const GPSStateDataItemBase& itemBase) :
+ GPSStateDataItemBase(itemBase) {}
+ inline bool equals(const SystemStatusGpsState& peer) {
+ return (mEnabled == peer.mEnabled);
+ }
+ inline void dump(void) override {
+ LOC_LOGD("GpsState: state=%u", mEnabled);
+ }
+};
+
+class SystemStatusNLPStatus : public SystemStatusItemBase,
+ public NLPStatusDataItemBase
+{
+public:
+ inline SystemStatusNLPStatus(bool enabled=false) :
+ NLPStatusDataItemBase(enabled) {}
+ inline SystemStatusNLPStatus(const NLPStatusDataItemBase& itemBase) :
+ NLPStatusDataItemBase(itemBase) {}
+ inline bool equals(const SystemStatusNLPStatus& peer) {
+ return (mEnabled == peer.mEnabled);
+ }
+};
+
+class SystemStatusWifiHardwareState : public SystemStatusItemBase,
+ public WifiHardwareStateDataItemBase
+{
+public:
+ inline SystemStatusWifiHardwareState(bool enabled=false) :
+ WifiHardwareStateDataItemBase(enabled) {}
+ inline SystemStatusWifiHardwareState(const WifiHardwareStateDataItemBase& itemBase) :
+ WifiHardwareStateDataItemBase(itemBase) {}
+ inline bool equals(const SystemStatusWifiHardwareState& peer) {
+ return (mEnabled == peer.mEnabled);
+ }
+};
+
+class SystemStatusNetworkInfo : public SystemStatusItemBase,
+ public NetworkInfoDataItemBase
+{
+ NetworkInfoDataItemBase* mSrcObjPtr;
+public:
+ inline SystemStatusNetworkInfo(
+ int32_t type=0,
+ std::string typeName="",
+ string subTypeName="",
+ bool connected=false,
+ bool roaming=false,
+ uint64_t networkHandle=NETWORK_HANDLE_UNKNOWN) :
+ NetworkInfoDataItemBase(
+ (NetworkType)type,
+ type,
+ typeName,
+ subTypeName,
+ connected && (!roaming),
+ connected,
+ roaming,
+ networkHandle),
+ mSrcObjPtr(nullptr) {}
+ inline SystemStatusNetworkInfo(const NetworkInfoDataItemBase& itemBase) :
+ NetworkInfoDataItemBase(itemBase),
+ mSrcObjPtr((NetworkInfoDataItemBase*)&itemBase) {
+ mType = itemBase.getType();
+ }
+ inline bool equals(const SystemStatusNetworkInfo& peer) {
+ for (uint8_t i = 0; i < MAX_NETWORK_HANDLES; ++i) {
+ if (!(mAllNetworkHandles[i] == peer.mAllNetworkHandles[i])) {
+ return false;
+ }
+ }
+ return true;
+ }
+ inline virtual SystemStatusItemBase& collate(SystemStatusItemBase& curInfo) {
+ uint64_t allTypes = (static_cast<SystemStatusNetworkInfo&>(curInfo)).mAllTypes;
+ uint64_t networkHandle =
+ (static_cast<SystemStatusNetworkInfo&>(curInfo)).mNetworkHandle;
+ int32_t type = (static_cast<SystemStatusNetworkInfo&>(curInfo)).mType;
+ // Replace current with cached table for now and then update
+ memcpy(mAllNetworkHandles,
+ (static_cast<SystemStatusNetworkInfo&>(curInfo)).getNetworkHandle(),
+ sizeof(mAllNetworkHandles));
+ if (mConnected) {
+ mAllTypes |= allTypes;
+ for (uint8_t i = 0; i < MAX_NETWORK_HANDLES; ++i) {
+ if (mNetworkHandle == mAllNetworkHandles[i].networkHandle) {
+ LOC_LOGD("collate duplicate detected, not updating");
+ break;
+ }
+ if (NETWORK_HANDLE_UNKNOWN == mAllNetworkHandles[i].networkHandle) {
+ mAllNetworkHandles[i].networkHandle = mNetworkHandle;
+ mAllNetworkHandles[i].networkType = (loc_core::NetworkType) mType;
+ break;
+ }
+ }
+ } else if (0 != mAllTypes) {
+ uint8_t deletedIndex = MAX_NETWORK_HANDLES;
+ uint8_t lastValidIndex = 0;
+ uint8_t typeCount = 0;
+ for (; lastValidIndex < MAX_NETWORK_HANDLES &&
+ NETWORK_HANDLE_UNKNOWN != mAllNetworkHandles[lastValidIndex].networkHandle;
+ ++lastValidIndex) {
+ // Maintain count for number of network handles still
+ // connected for given type
+ if (mType == mAllNetworkHandles[lastValidIndex].networkType) {
+ typeCount++;
+ }
+
+ if (mNetworkHandle == mAllNetworkHandles[lastValidIndex].networkHandle) {
+ deletedIndex = lastValidIndex;
+ typeCount--;
+ }
+ }
+
+ if (MAX_NETWORK_HANDLES != deletedIndex) {
+ LOC_LOGD("deletedIndex:%u, lastValidIndex:%u, typeCount:%u",
+ deletedIndex, lastValidIndex, typeCount);
+ mAllNetworkHandles[deletedIndex] = mAllNetworkHandles[lastValidIndex];
+ mAllNetworkHandles[lastValidIndex].networkHandle = NETWORK_HANDLE_UNKNOWN;
+ mAllNetworkHandles[lastValidIndex].networkType = TYPE_UNKNOWN;
+ }
+
+ // If no more handles of given type, set bitmask
+ if (0 == typeCount) {
+ mAllTypes = (allTypes & (~mAllTypes));
+ LOC_LOGD("mAllTypes:%" PRIx64, mAllTypes);
+ }
+ } // else (mConnected == false && mAllTypes == 0)
+ // we keep mAllTypes as 0, which means no more connections.
+
+ if (nullptr != mSrcObjPtr) {
+ // this is critical, changing mAllTypes of the original obj
+ mSrcObjPtr->mAllTypes = mAllTypes;
+ memcpy(mSrcObjPtr->mAllNetworkHandles,
+ mAllNetworkHandles,
+ sizeof(mSrcObjPtr->mAllNetworkHandles));
+ }
+ return *this;
+ }
+ inline void dump(void) override {
+ LOC_LOGD("NetworkInfo: mAllTypes=%" PRIx64 " connected=%u mType=%x",
+ mAllTypes, mConnected, mType);
+ }
+};
+
+class SystemStatusServiceInfo : public SystemStatusItemBase,
+ public RilServiceInfoDataItemBase
+{
+public:
+ inline SystemStatusServiceInfo() :
+ RilServiceInfoDataItemBase() {}
+ inline SystemStatusServiceInfo(const RilServiceInfoDataItemBase& itemBase) :
+ RilServiceInfoDataItemBase(itemBase) {}
+ inline bool equals(const SystemStatusServiceInfo& peer) {
+ return static_cast<const RilServiceInfoDataItemBase&>(peer) ==
+ static_cast<const RilServiceInfoDataItemBase&>(*this);
+ }
+};
+
+class SystemStatusRilCellInfo : public SystemStatusItemBase,
+ public RilCellInfoDataItemBase
+{
+public:
+ inline SystemStatusRilCellInfo() :
+ RilCellInfoDataItemBase() {}
+ inline SystemStatusRilCellInfo(const RilCellInfoDataItemBase& itemBase) :
+ RilCellInfoDataItemBase(itemBase) {}
+ inline bool equals(const SystemStatusRilCellInfo& peer) {
+ return static_cast<const RilCellInfoDataItemBase&>(peer) ==
+ static_cast<const RilCellInfoDataItemBase&>(*this);
+ }
+};
+
+class SystemStatusServiceStatus : public SystemStatusItemBase,
+ public ServiceStatusDataItemBase
+{
+public:
+ inline SystemStatusServiceStatus(int32_t mServiceState=0) :
+ ServiceStatusDataItemBase(mServiceState) {}
+ inline SystemStatusServiceStatus(const ServiceStatusDataItemBase& itemBase) :
+ ServiceStatusDataItemBase(itemBase) {}
+ inline bool equals(const SystemStatusServiceStatus& peer) {
+ return (mServiceState == peer.mServiceState);
+ }
+};
+
+class SystemStatusModel : public SystemStatusItemBase,
+ public ModelDataItemBase
+{
+public:
+ inline SystemStatusModel(string name="") :
+ ModelDataItemBase(name) {}
+ inline SystemStatusModel(const ModelDataItemBase& itemBase) :
+ ModelDataItemBase(itemBase) {}
+ inline bool equals(const SystemStatusModel& peer) {
+ return (mModel == peer.mModel);
+ }
+};
+
+class SystemStatusManufacturer : public SystemStatusItemBase,
+ public ManufacturerDataItemBase
+{
+public:
+ inline SystemStatusManufacturer(string name="") :
+ ManufacturerDataItemBase(name) {}
+ inline SystemStatusManufacturer(const ManufacturerDataItemBase& itemBase) :
+ ManufacturerDataItemBase(itemBase) {}
+ inline bool equals(const SystemStatusManufacturer& peer) {
+ return (mManufacturer == peer.mManufacturer);
+ }
+};
+
+class SystemStatusAssistedGps : public SystemStatusItemBase,
+ public AssistedGpsDataItemBase
+{
+public:
+ inline SystemStatusAssistedGps(bool enabled=false) :
+ AssistedGpsDataItemBase(enabled) {}
+ inline SystemStatusAssistedGps(const AssistedGpsDataItemBase& itemBase) :
+ AssistedGpsDataItemBase(itemBase) {}
+ inline bool equals(const SystemStatusAssistedGps& peer) {
+ return (mEnabled == peer.mEnabled);
+ }
+};
+
+class SystemStatusScreenState : public SystemStatusItemBase,
+ public ScreenStateDataItemBase
+{
+public:
+ inline SystemStatusScreenState(bool state=false) :
+ ScreenStateDataItemBase(state) {}
+ inline SystemStatusScreenState(const ScreenStateDataItemBase& itemBase) :
+ ScreenStateDataItemBase(itemBase) {}
+ inline bool equals(const SystemStatusScreenState& peer) {
+ return (mState == peer.mState);
+ }
+};
+
+class SystemStatusPowerConnectState : public SystemStatusItemBase,
+ public PowerConnectStateDataItemBase
+{
+public:
+ inline SystemStatusPowerConnectState(bool state=false) :
+ PowerConnectStateDataItemBase(state) {}
+ inline SystemStatusPowerConnectState(const PowerConnectStateDataItemBase& itemBase) :
+ PowerConnectStateDataItemBase(itemBase) {}
+ inline bool equals(const SystemStatusPowerConnectState& peer) {
+ return (mState == peer.mState);
+ }
+};
+
+class SystemStatusTimeZoneChange : public SystemStatusItemBase,
+ public TimeZoneChangeDataItemBase
+{
+public:
+ inline SystemStatusTimeZoneChange(
+ int64_t currTimeMillis=0ULL, int32_t rawOffset=0, int32_t dstOffset=0) :
+ TimeZoneChangeDataItemBase(currTimeMillis, rawOffset, dstOffset) {}
+ inline SystemStatusTimeZoneChange(const TimeZoneChangeDataItemBase& itemBase) :
+ TimeZoneChangeDataItemBase(itemBase) {}
+ inline bool equals(const SystemStatusTimeZoneChange& peer) {
+ return ((mCurrTimeMillis == peer.mCurrTimeMillis) &&
+ (mRawOffsetTZ == peer.mRawOffsetTZ) &&
+ (mDstOffsetTZ == peer.mDstOffsetTZ));
+ }
+};
+
+class SystemStatusTimeChange : public SystemStatusItemBase,
+ public TimeChangeDataItemBase
+{
+public:
+ inline SystemStatusTimeChange(
+ int64_t currTimeMillis=0ULL, int32_t rawOffset=0, int32_t dstOffset=0) :
+ TimeChangeDataItemBase(currTimeMillis, rawOffset, dstOffset) {}
+ inline SystemStatusTimeChange(const TimeChangeDataItemBase& itemBase) :
+ TimeChangeDataItemBase(itemBase) {}
+ inline bool equals(const SystemStatusTimeChange& peer) {
+ return ((mCurrTimeMillis == peer.mCurrTimeMillis) &&
+ (mRawOffsetTZ == peer.mRawOffsetTZ) &&
+ (mDstOffsetTZ == peer.mDstOffsetTZ));
+ }
+};
+
+class SystemStatusWifiSupplicantStatus : public SystemStatusItemBase,
+ public WifiSupplicantStatusDataItemBase
+{
+public:
+ inline SystemStatusWifiSupplicantStatus() :
+ WifiSupplicantStatusDataItemBase() {}
+ inline SystemStatusWifiSupplicantStatus(const WifiSupplicantStatusDataItemBase& itemBase) :
+ WifiSupplicantStatusDataItemBase(itemBase) {}
+ inline bool equals(const SystemStatusWifiSupplicantStatus& peer) {
+ return ((mState == peer.mState) &&
+ (mApMacAddressValid == peer.mApMacAddressValid) &&
+ (mWifiApSsidValid == peer.mWifiApSsidValid) &&
+ (mWifiApSsid == peer.mWifiApSsid));
+ }
+};
+
+class SystemStatusShutdownState : public SystemStatusItemBase,
+ public ShutdownStateDataItemBase
+{
+public:
+ inline SystemStatusShutdownState(bool state=false) :
+ ShutdownStateDataItemBase(state) {}
+ inline SystemStatusShutdownState(const ShutdownStateDataItemBase& itemBase) :
+ ShutdownStateDataItemBase(itemBase) {}
+ inline bool equals(const SystemStatusShutdownState& peer) {
+ return (mState == peer.mState);
+ }
+};
+
+class SystemStatusTac : public SystemStatusItemBase,
+ public TacDataItemBase
+{
+public:
+ inline SystemStatusTac(std::string value="") :
+ TacDataItemBase(value) {}
+ inline SystemStatusTac(const TacDataItemBase& itemBase) :
+ TacDataItemBase(itemBase) {}
+ inline bool equals(const SystemStatusTac& peer) {
+ return (mValue == peer.mValue);
+ }
+ inline void dump(void) {
+ LOC_LOGD("Tac: value=%s", mValue.c_str());
+ }
+};
+
+class SystemStatusMccMnc : public SystemStatusItemBase,
+ public MccmncDataItemBase
+{
+public:
+ inline SystemStatusMccMnc(std::string value="") :
+ MccmncDataItemBase(value) {}
+ inline SystemStatusMccMnc(const MccmncDataItemBase& itemBase) :
+ MccmncDataItemBase(itemBase) {}
+ inline bool equals(const SystemStatusMccMnc& peer) {
+ return (mValue == peer.mValue);
+ }
+ inline void dump(void) {
+ LOC_LOGD("TacMccMnc value=%s", mValue.c_str());
+ }
+};
+
+class SystemStatusBtDeviceScanDetail : public SystemStatusItemBase,
+ public BtDeviceScanDetailsDataItemBase
+{
+public:
+ inline SystemStatusBtDeviceScanDetail() :
+ BtDeviceScanDetailsDataItemBase() {}
+ inline SystemStatusBtDeviceScanDetail(const BtDeviceScanDetailsDataItemBase& itemBase) :
+ BtDeviceScanDetailsDataItemBase(itemBase) {}
+ inline bool equals(const SystemStatusBtDeviceScanDetail& peer) {
+ return ((mApSrnRssi == peer.mApSrnRssi) &&
+ (0 == memcmp(mApSrnMacAddress, peer.mApSrnMacAddress, sizeof(mApSrnMacAddress))) &&
+ (mApSrnTimestamp == peer.mApSrnTimestamp) &&
+ (mRequestTimestamp == peer.mRequestTimestamp) &&
+ (mReceiveTimestamp == peer.mReceiveTimestamp));
+ }
+};
+
+class SystemStatusBtleDeviceScanDetail : public SystemStatusItemBase,
+ public BtLeDeviceScanDetailsDataItemBase
+{
+public:
+ inline SystemStatusBtleDeviceScanDetail() :
+ BtLeDeviceScanDetailsDataItemBase() {}
+ inline SystemStatusBtleDeviceScanDetail(const BtLeDeviceScanDetailsDataItemBase& itemBase) :
+ BtLeDeviceScanDetailsDataItemBase(itemBase) {}
+ inline bool equals(const SystemStatusBtleDeviceScanDetail& peer) {
+ return ((mApSrnRssi == peer.mApSrnRssi) &&
+ (0 == memcmp(mApSrnMacAddress, peer.mApSrnMacAddress, sizeof(mApSrnMacAddress))) &&
+ (mApSrnTimestamp == peer.mApSrnTimestamp) &&
+ (mRequestTimestamp == peer.mRequestTimestamp) &&
+ (mReceiveTimestamp == peer.mReceiveTimestamp));
+ }
+};
+
+/******************************************************************************
+ SystemStatusReports
+******************************************************************************/
+class SystemStatusReports
+{
+public:
+ // from QMI_LOC indication
+ std::vector<SystemStatusLocation> mLocation;
+
+ // from ME debug NMEA
+ std::vector<SystemStatusTimeAndClock> mTimeAndClock;
+ std::vector<SystemStatusXoState> mXoState;
+ std::vector<SystemStatusRfAndParams> mRfAndParams;
+ std::vector<SystemStatusErrRecovery> mErrRecovery;
+
+ // from PE debug NMEA
+ std::vector<SystemStatusInjectedPosition> mInjectedPosition;
+ std::vector<SystemStatusBestPosition> mBestPosition;
+ std::vector<SystemStatusXtra> mXtra;
+ std::vector<SystemStatusEphemeris> mEphemeris;
+ std::vector<SystemStatusSvHealth> mSvHealth;
+ std::vector<SystemStatusPdr> mPdr;
+ std::vector<SystemStatusNavData> mNavData;
+
+ // from SM debug NMEA
+ std::vector<SystemStatusPositionFailure> mPositionFailure;
+
+ // from dataitems observer
+ std::vector<SystemStatusAirplaneMode> mAirplaneMode;
+ std::vector<SystemStatusENH> mENH;
+ std::vector<SystemStatusGpsState> mGPSState;
+ std::vector<SystemStatusNLPStatus> mNLPStatus;
+ std::vector<SystemStatusWifiHardwareState> mWifiHardwareState;
+ std::vector<SystemStatusNetworkInfo> mNetworkInfo;
+ std::vector<SystemStatusServiceInfo> mRilServiceInfo;
+ std::vector<SystemStatusRilCellInfo> mRilCellInfo;
+ std::vector<SystemStatusServiceStatus> mServiceStatus;
+ std::vector<SystemStatusModel> mModel;
+ std::vector<SystemStatusManufacturer> mManufacturer;
+ std::vector<SystemStatusAssistedGps> mAssistedGps;
+ std::vector<SystemStatusScreenState> mScreenState;
+ std::vector<SystemStatusPowerConnectState> mPowerConnectState;
+ std::vector<SystemStatusTimeZoneChange> mTimeZoneChange;
+ std::vector<SystemStatusTimeChange> mTimeChange;
+ std::vector<SystemStatusWifiSupplicantStatus> mWifiSupplicantStatus;
+ std::vector<SystemStatusShutdownState> mShutdownState;
+ std::vector<SystemStatusTac> mTac;
+ std::vector<SystemStatusMccMnc> mMccMnc;
+ std::vector<SystemStatusBtDeviceScanDetail> mBtDeviceScanDetail;
+ std::vector<SystemStatusBtleDeviceScanDetail> mBtLeDeviceScanDetail;
+};
+
+/******************************************************************************
+ SystemStatus
+******************************************************************************/
+class SystemStatus
+{
+private:
+ static SystemStatus *mInstance;
+ SystemStatusOsObserver mSysStatusObsvr;
+ // ctor
+ SystemStatus(const MsgTask* msgTask);
+ // dtor
+ inline ~SystemStatus() {}
+
+ // Data members
+ static pthread_mutex_t mMutexSystemStatus;
+ SystemStatusReports mCache;
+
+ template <typename TYPE_REPORT, typename TYPE_ITEM>
+ bool setIteminReport(TYPE_REPORT& report, TYPE_ITEM&& s);
+
+ // set default dataitem derived item in report cache
+ template <typename TYPE_REPORT, typename TYPE_ITEM>
+ void setDefaultIteminReport(TYPE_REPORT& report, const TYPE_ITEM& s);
+
+ template <typename TYPE_REPORT, typename TYPE_ITEM>
+ void getIteminReport(TYPE_REPORT& reportout, const TYPE_ITEM& c) const;
+
+public:
+ // Static methods
+ static SystemStatus* getInstance(const MsgTask* msgTask);
+ static void destroyInstance();
+ IOsObserver* getOsObserver();
+
+ // Helpers
+ bool eventPosition(const UlpLocation& location,const GpsLocationExtended& locationEx);
+ bool eventDataItemNotify(IDataItemCore* dataitem);
+ bool setNmeaString(const char *data, uint32_t len);
+ bool getReport(SystemStatusReports& reports, bool isLatestonly = false) const;
+ bool setDefaultGnssEngineStates(void);
+ bool eventConnectionStatus(bool connected, int8_t type,
+ bool roaming, NetworkHandle networkHandle);
+ bool updatePowerConnectState(bool charging);
+};
+
+} // namespace loc_core
+
+#endif //__SYSTEM_STATUS__
+
diff --git a/core/SystemStatusOsObserver.cpp b/core/SystemStatusOsObserver.cpp
new file mode 100644
index 0000000..0427380
--- /dev/null
+++ b/core/SystemStatusOsObserver.cpp
@@ -0,0 +1,575 @@
+/* Copyright (c) 2015-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_SystemStatusOsObserver"
+
+#include <algorithm>
+#include <SystemStatus.h>
+#include <SystemStatusOsObserver.h>
+#include <IDataItemCore.h>
+#include <DataItemsFactoryProxy.h>
+
+namespace loc_core
+{
+template <typename CINT, typename COUT>
+COUT SystemStatusOsObserver::containerTransfer(CINT& inContainer) {
+ COUT outContainer(0);
+ for (auto item : inContainer) {
+ outContainer.insert(outContainer.begin(), item);
+ }
+ return outContainer;
+}
+
+SystemStatusOsObserver::~SystemStatusOsObserver() {
+ // Close data-item library handle
+ DataItemsFactoryProxy::closeDataItemLibraryHandle();
+
+ // Destroy cache
+ for (auto each : mDataItemCache) {
+ if (nullptr != each.second) {
+ delete each.second;
+ }
+ }
+
+ mDataItemCache.clear();
+}
+
+void SystemStatusOsObserver::setSubscriptionObj(IDataItemSubscription* subscriptionObj)
+{
+ struct SetSubsObj : public LocMsg {
+ ObserverContext& mContext;
+ IDataItemSubscription* mSubsObj;
+ inline SetSubsObj(ObserverContext& context, IDataItemSubscription* subscriptionObj) :
+ mContext(context), mSubsObj(subscriptionObj) {}
+ void proc() const {
+ mContext.mSubscriptionObj = mSubsObj;
+
+ if (!mContext.mSSObserver->mDataItemToClients.empty()) {
+ list<DataItemId> dis(
+ containerTransfer<unordered_set<DataItemId>, list<DataItemId>>(
+ mContext.mSSObserver->mDataItemToClients.getKeys()));
+ mContext.mSubscriptionObj->subscribe(dis, mContext.mSSObserver);
+ mContext.mSubscriptionObj->requestData(dis, mContext.mSSObserver);
+ }
+ }
+ };
+
+ if (nullptr == subscriptionObj) {
+ LOC_LOGw("subscriptionObj is NULL");
+ } else {
+ mContext.mMsgTask->sendMsg(new SetSubsObj(mContext, subscriptionObj));
+ }
+}
+
+/******************************************************************************
+ IDataItemSubscription Overrides
+******************************************************************************/
+void SystemStatusOsObserver::subscribe(const list<DataItemId>& l, IDataItemObserver* client,
+ bool toRequestData)
+{
+ struct HandleSubscribeReq : public LocMsg {
+ inline HandleSubscribeReq(SystemStatusOsObserver* parent,
+ list<DataItemId>& l, IDataItemObserver* client, bool requestData) :
+ mParent(parent), mClient(client),
+ mDataItemSet(containerTransfer<list<DataItemId>, unordered_set<DataItemId>>(l)),
+ diItemlist(l),
+ mToRequestData(requestData) {}
+
+ void proc() const {
+ unordered_set<DataItemId> dataItemsToSubscribe(0);
+ mParent->mDataItemToClients.add(mDataItemSet, {mClient}, &dataItemsToSubscribe);
+ mParent->mClientToDataItems.add(mClient, mDataItemSet);
+
+ mParent->sendCachedDataItems(mDataItemSet, mClient);
+
+ // Send subscription set to framework
+ if (nullptr != mParent->mContext.mSubscriptionObj) {
+ if (mToRequestData) {
+ LOC_LOGD("Request Data sent to framework for the following");
+ mParent->mContext.mSubscriptionObj->requestData(diItemlist, mParent);
+ } else if (!dataItemsToSubscribe.empty()) {
+ LOC_LOGD("Subscribe Request sent to framework for the following");
+ mParent->logMe(dataItemsToSubscribe);
+ mParent->mContext.mSubscriptionObj->subscribe(
+ containerTransfer<unordered_set<DataItemId>, list<DataItemId>>(
+ std::move(dataItemsToSubscribe)),
+ mParent);
+ }
+ }
+ }
+ mutable SystemStatusOsObserver* mParent;
+ IDataItemObserver* mClient;
+ const unordered_set<DataItemId> mDataItemSet;
+ const list<DataItemId> diItemlist;
+ bool mToRequestData;
+ };
+
+ if (l.empty() || nullptr == client) {
+ LOC_LOGw("Data item set is empty or client is nullptr");
+ } else {
+ mContext.mMsgTask->sendMsg(
+ new HandleSubscribeReq(this, (list<DataItemId>&)l, client, toRequestData));
+ }
+}
+
+void SystemStatusOsObserver::updateSubscription(
+ const list<DataItemId>& l, IDataItemObserver* client)
+{
+ struct HandleUpdateSubscriptionReq : public LocMsg {
+ HandleUpdateSubscriptionReq(SystemStatusOsObserver* parent,
+ list<DataItemId>& l, IDataItemObserver* client) :
+ mParent(parent), mClient(client),
+ mDataItemSet(containerTransfer<list<DataItemId>, unordered_set<DataItemId>>(l)) {}
+
+ void proc() const {
+ unordered_set<DataItemId> dataItemsToSubscribe(0);
+ unordered_set<DataItemId> dataItemsToUnsubscribe(0);
+ unordered_set<IDataItemObserver*> clients({mClient});
+ // below removes clients from all entries keyed with the return of the
+ // mClientToDataItems.update() call. If leaving an empty set of clients as the
+ // result, the entire entry will be removed. dataItemsToUnsubscribe will be
+ // populated to keep the keys of the removed entries.
+ mParent->mDataItemToClients.trimOrRemove(
+ // this call updates <IDataItemObserver*, DataItemId> map; removes
+ // the DataItemId's that are not new to the clietn from mDataItemSet;
+ // and returns a set of mDataItemSet's that are no longer used by client.
+ // This unused set of mDataItemSet's is passed to trimOrRemove method of
+ // <DataItemId, IDataItemObserver*> map to remove the client from the
+ // corresponding entries, and gets a set of the entries that are
+ // removed from the <DataItemId, IDataItemObserver*> map as a result.
+ mParent->mClientToDataItems.update(mClient,
+ (unordered_set<DataItemId>&)mDataItemSet),
+ clients, &dataItemsToUnsubscribe, nullptr);
+ // below adds mClient to <DataItemId, IDataItemObserver*> map, and populates
+ // new keys added to that map, which are DataItemIds to be subscribed.
+ mParent->mDataItemToClients.add(mDataItemSet, clients, &dataItemsToSubscribe);
+
+ // Send First Response
+ mParent->sendCachedDataItems(mDataItemSet, mClient);
+
+ if (nullptr != mParent->mContext.mSubscriptionObj) {
+ // Send subscription set to framework
+ if (!dataItemsToSubscribe.empty()) {
+ LOC_LOGD("Subscribe Request sent to framework for the following");
+ mParent->logMe(dataItemsToSubscribe);
+
+ mParent->mContext.mSubscriptionObj->subscribe(
+ containerTransfer<unordered_set<DataItemId>, list<DataItemId>>(
+ std::move(dataItemsToSubscribe)),
+ mParent);
+ }
+
+ // Send unsubscribe to framework
+ if (!dataItemsToUnsubscribe.empty()) {
+ LOC_LOGD("Unsubscribe Request sent to framework for the following");
+ mParent->logMe(dataItemsToUnsubscribe);
+
+ mParent->mContext.mSubscriptionObj->unsubscribe(
+ containerTransfer<unordered_set<DataItemId>, list<DataItemId>>(
+ std::move(dataItemsToUnsubscribe)),
+ mParent);
+ }
+ }
+ }
+ SystemStatusOsObserver* mParent;
+ IDataItemObserver* mClient;
+ unordered_set<DataItemId> mDataItemSet;
+ };
+
+ if (l.empty() || nullptr == client) {
+ LOC_LOGw("Data item set is empty or client is nullptr");
+ } else {
+ mContext.mMsgTask->sendMsg(
+ new HandleUpdateSubscriptionReq(this, (list<DataItemId>&)l, client));
+ }
+}
+
+void SystemStatusOsObserver::unsubscribe(
+ const list<DataItemId>& l, IDataItemObserver* client)
+{
+ struct HandleUnsubscribeReq : public LocMsg {
+ HandleUnsubscribeReq(SystemStatusOsObserver* parent,
+ list<DataItemId>& l, IDataItemObserver* client) :
+ mParent(parent), mClient(client),
+ mDataItemSet(containerTransfer<list<DataItemId>, unordered_set<DataItemId>>(l)) {}
+
+ void proc() const {
+ unordered_set<DataItemId> dataItemsUnusedByClient(0);
+ unordered_set<IDataItemObserver*> clientToRemove(0);
+ mParent->mClientToDataItems.trimOrRemove({mClient}, mDataItemSet, &clientToRemove,
+ &dataItemsUnusedByClient);
+ unordered_set<DataItemId> dataItemsToUnsubscribe(0);
+ mParent->mDataItemToClients.trimOrRemove(dataItemsUnusedByClient, {mClient},
+ &dataItemsToUnsubscribe, nullptr);
+
+ if (nullptr != mParent->mContext.mSubscriptionObj && !dataItemsToUnsubscribe.empty()) {
+ LOC_LOGD("Unsubscribe Request sent to framework for the following data items");
+ mParent->logMe(dataItemsToUnsubscribe);
+
+ // Send unsubscribe to framework
+ mParent->mContext.mSubscriptionObj->unsubscribe(
+ containerTransfer<unordered_set<DataItemId>, list<DataItemId>>(
+ std::move(dataItemsToUnsubscribe)),
+ mParent);
+ }
+ }
+ SystemStatusOsObserver* mParent;
+ IDataItemObserver* mClient;
+ unordered_set<DataItemId> mDataItemSet;
+ };
+
+ if (l.empty() || nullptr == client) {
+ LOC_LOGw("Data item set is empty or client is nullptr");
+ } else {
+ mContext.mMsgTask->sendMsg(new HandleUnsubscribeReq(this, (list<DataItemId>&)l, client));
+ }
+}
+
+void SystemStatusOsObserver::unsubscribeAll(IDataItemObserver* client)
+{
+ struct HandleUnsubscribeAllReq : public LocMsg {
+ HandleUnsubscribeAllReq(SystemStatusOsObserver* parent,
+ IDataItemObserver* client) :
+ mParent(parent), mClient(client) {}
+
+ void proc() const {
+ unordered_set<DataItemId> diByClient = mParent->mClientToDataItems.getValSet(mClient);
+ if (!diByClient.empty()) {
+ unordered_set<DataItemId> dataItemsToUnsubscribe;
+ mParent->mClientToDataItems.remove(mClient);
+ mParent->mDataItemToClients.trimOrRemove(diByClient, {mClient},
+ &dataItemsToUnsubscribe, nullptr);
+
+ if (!dataItemsToUnsubscribe.empty() &&
+ nullptr != mParent->mContext.mSubscriptionObj) {
+
+ LOC_LOGD("Unsubscribe Request sent to framework for the following data items");
+ mParent->logMe(dataItemsToUnsubscribe);
+
+ // Send unsubscribe to framework
+ mParent->mContext.mSubscriptionObj->unsubscribe(
+ containerTransfer<unordered_set<DataItemId>, list<DataItemId>>(
+ std::move(dataItemsToUnsubscribe)),
+ mParent);
+ }
+ }
+ }
+ SystemStatusOsObserver* mParent;
+ IDataItemObserver* mClient;
+ };
+
+ if (nullptr == client) {
+ LOC_LOGw("Data item set is empty or client is nullptr");
+ } else {
+ mContext.mMsgTask->sendMsg(new HandleUnsubscribeAllReq(this, client));
+ }
+}
+
+/******************************************************************************
+ IDataItemObserver Overrides
+******************************************************************************/
+void SystemStatusOsObserver::notify(const list<IDataItemCore*>& dlist)
+{
+ struct HandleNotify : public LocMsg {
+ HandleNotify(SystemStatusOsObserver* parent, vector<IDataItemCore*>& v) :
+ mParent(parent), mDiVec(std::move(v)) {}
+
+ inline virtual ~HandleNotify() {
+ for (auto item : mDiVec) {
+ delete item;
+ }
+ }
+
+ void proc() const {
+ // Update Cache with received data items and prepare
+ // list of data items to be sent.
+ unordered_set<DataItemId> dataItemIdsToBeSent(0);
+ for (auto item : mDiVec) {
+ if (mParent->updateCache(item)) {
+ dataItemIdsToBeSent.insert(item->getId());
+ }
+ }
+
+ // Send data item to all subscribed clients
+ unordered_set<IDataItemObserver*> clientSet(0);
+ for (auto each : dataItemIdsToBeSent) {
+ auto clients = mParent->mDataItemToClients.getValSetPtr(each);
+ if (nullptr != clients) {
+ clientSet.insert(clients->begin(), clients->end());
+ }
+ }
+
+ for (auto client : clientSet) {
+ unordered_set<DataItemId> dataItemIdsForThisClient(
+ mParent->mClientToDataItems.getValSet(client));
+ for (auto itr = dataItemIdsForThisClient.begin();
+ itr != dataItemIdsForThisClient.end(); ) {
+ if (dataItemIdsToBeSent.find(*itr) == dataItemIdsToBeSent.end()) {
+ itr = dataItemIdsForThisClient.erase(itr);
+ } else {
+ itr++;
+ }
+ }
+
+ mParent->sendCachedDataItems(dataItemIdsForThisClient, client);
+ }
+ }
+ SystemStatusOsObserver* mParent;
+ const vector<IDataItemCore*> mDiVec;
+ };
+
+ if (!dlist.empty()) {
+ vector<IDataItemCore*> dataItemVec(dlist.size());
+
+ for (auto each : dlist) {
+ IF_LOC_LOGD {
+ string dv;
+ each->stringify(dv);
+ LOC_LOGD("notify: DataItem In Value:%s", dv.c_str());
+ }
+
+ IDataItemCore* di = DataItemsFactoryProxy::createNewDataItem(each->getId());
+ if (nullptr == di) {
+ LOC_LOGw("Unable to create dataitem:%d", each->getId());
+ continue;
+ }
+
+ // Copy contents into the newly created data item
+ di->copy(each);
+
+ // add this dataitem if updated from last one
+ dataItemVec.push_back(di);
+ }
+
+ if (!dataItemVec.empty()) {
+ mContext.mMsgTask->sendMsg(new HandleNotify(this, dataItemVec));
+ }
+ }
+}
+
+/******************************************************************************
+ IFrameworkActionReq Overrides
+******************************************************************************/
+void SystemStatusOsObserver::turnOn(DataItemId dit, int timeOut)
+{
+ if (nullptr == mContext.mFrameworkActionReqObj) {
+ LOC_LOGE("%s:%d]: Framework action request object is NULL", __func__, __LINE__);
+ return;
+ }
+
+ // Check if data item exists in mActiveRequestCount
+ DataItemIdToInt::iterator citer = mActiveRequestCount.find(dit);
+ if (citer == mActiveRequestCount.end()) {
+ // Data item not found in map
+ // Add reference count as 1 and add dataitem to map
+ pair<DataItemId, int> cpair(dit, 1);
+ mActiveRequestCount.insert(cpair);
+ LOC_LOGD("Sending turnOn request");
+
+ // Send action turn on to framework
+ struct HandleTurnOnMsg : public LocMsg {
+ HandleTurnOnMsg(IFrameworkActionReq* framework,
+ DataItemId dit, int timeOut) :
+ mFrameworkActionReqObj(framework), mDataItemId(dit), mTimeOut(timeOut) {}
+ virtual ~HandleTurnOnMsg() {}
+ void proc() const {
+ mFrameworkActionReqObj->turnOn(mDataItemId, mTimeOut);
+ }
+ IFrameworkActionReq* mFrameworkActionReqObj;
+ DataItemId mDataItemId;
+ int mTimeOut;
+ };
+ mContext.mMsgTask->sendMsg(
+ new (nothrow) HandleTurnOnMsg(mContext.mFrameworkActionReqObj, dit, timeOut));
+ }
+ else {
+ // Found in map, update reference count
+ citer->second++;
+ LOC_LOGD("turnOn - Data item:%d Num_refs:%d", dit, citer->second);
+ }
+}
+
+void SystemStatusOsObserver::turnOff(DataItemId dit)
+{
+ if (nullptr == mContext.mFrameworkActionReqObj) {
+ LOC_LOGE("%s:%d]: Framework action request object is NULL", __func__, __LINE__);
+ return;
+ }
+
+ // Check if data item exists in mActiveRequestCount
+ DataItemIdToInt::iterator citer = mActiveRequestCount.find(dit);
+ if (citer != mActiveRequestCount.end()) {
+ // found
+ citer->second--;
+ LOC_LOGD("turnOff - Data item:%d Remaining:%d", dit, citer->second);
+ if(citer->second == 0) {
+ // if this was last reference, remove item from map and turn off module
+ mActiveRequestCount.erase(citer);
+
+ // Send action turn off to framework
+ struct HandleTurnOffMsg : public LocMsg {
+ HandleTurnOffMsg(IFrameworkActionReq* framework, DataItemId dit) :
+ mFrameworkActionReqObj(framework), mDataItemId(dit) {}
+ virtual ~HandleTurnOffMsg() {}
+ void proc() const {
+ mFrameworkActionReqObj->turnOff(mDataItemId);
+ }
+ IFrameworkActionReq* mFrameworkActionReqObj;
+ DataItemId mDataItemId;
+ };
+ mContext.mMsgTask->sendMsg(
+ new (nothrow) HandleTurnOffMsg(mContext.mFrameworkActionReqObj, dit));
+ }
+ }
+}
+
+#ifdef USE_GLIB
+bool SystemStatusOsObserver::connectBackhaul()
+{
+ bool result = false;
+
+ if (mContext.mFrameworkActionReqObj != NULL) {
+ struct HandleConnectBackhaul : public LocMsg {
+ HandleConnectBackhaul(IFrameworkActionReq* fwkActReq) :
+ mFwkActionReqObj(fwkActReq) {}
+ virtual ~HandleConnectBackhaul() {}
+ void proc() const {
+ LOC_LOGD("HandleConnectBackhaul");
+ mFwkActionReqObj->connectBackhaul();
+ }
+ IFrameworkActionReq* mFwkActionReqObj;
+ };
+ mContext.mMsgTask->sendMsg(
+ new (nothrow) HandleConnectBackhaul(mContext.mFrameworkActionReqObj));
+ result = true;
+ }
+ else {
+ ++mBackHaulConnectReqCount;
+ LOC_LOGE("Framework action request object is NULL.Caching connect request: %d",
+ mBackHaulConnectReqCount);
+ result = false;
+ }
+ return result;
+
+}
+
+bool SystemStatusOsObserver::disconnectBackhaul()
+{
+ bool result = false;
+
+ if (mContext.mFrameworkActionReqObj != NULL) {
+ struct HandleDisconnectBackhaul : public LocMsg {
+ HandleDisconnectBackhaul(IFrameworkActionReq* fwkActReq) :
+ mFwkActionReqObj(fwkActReq) {}
+ virtual ~HandleDisconnectBackhaul() {}
+ void proc() const {
+ LOC_LOGD("HandleDisconnectBackhaul");
+ mFwkActionReqObj->disconnectBackhaul();
+ }
+ IFrameworkActionReq* mFwkActionReqObj;
+ };
+ mContext.mMsgTask->sendMsg(
+ new (nothrow) HandleDisconnectBackhaul(mContext.mFrameworkActionReqObj));
+ }
+ else {
+ if (mBackHaulConnectReqCount > 0) {
+ --mBackHaulConnectReqCount;
+ }
+ LOC_LOGE("Framework action request object is NULL.Caching disconnect request: %d",
+ mBackHaulConnectReqCount);
+ result = false;
+ }
+ return result;
+}
+#endif
+/******************************************************************************
+ Helpers
+******************************************************************************/
+void SystemStatusOsObserver::sendCachedDataItems(
+ const unordered_set<DataItemId>& s, IDataItemObserver* to)
+{
+ if (nullptr == to) {
+ LOC_LOGv("client pointer is NULL.");
+ } else {
+ string clientName;
+ to->getName(clientName);
+ list<IDataItemCore*> dataItems(0);
+
+ for (auto each : s) {
+ auto citer = mDataItemCache.find(each);
+ if (citer != mDataItemCache.end()) {
+ string dv;
+ citer->second->stringify(dv);
+ LOC_LOGI("DataItem: %s >> %s", dv.c_str(), clientName.c_str());
+ dataItems.push_front(citer->second);
+ }
+ }
+
+ if (dataItems.empty()) {
+ LOC_LOGv("No items to notify.");
+ } else {
+ to->notify(dataItems);
+ }
+ }
+}
+
+bool SystemStatusOsObserver::updateCache(IDataItemCore* d)
+{
+ bool dataItemUpdated = false;
+
+ // Request systemstatus to record this dataitem in its cache
+ // if the return is false, it means that SystemStatus is not
+ // handling it, so SystemStatusOsObserver also doesn't.
+ // So it has to be true to proceed.
+ if (nullptr != d && mSystemStatus->eventDataItemNotify(d)) {
+ auto citer = mDataItemCache.find(d->getId());
+ if (citer == mDataItemCache.end()) {
+ // New data item; not found in cache
+ IDataItemCore* dataitem = DataItemsFactoryProxy::createNewDataItem(d->getId());
+ if (nullptr != dataitem) {
+ // Copy the contents of the data item
+ dataitem->copy(d);
+ // Insert in mDataItemCache
+ mDataItemCache.insert(std::make_pair(d->getId(), dataitem));
+ dataItemUpdated = true;
+ }
+ } else {
+ // Found in cache; Update cache if necessary
+ citer->second->copy(d, &dataItemUpdated);
+ }
+
+ if (dataItemUpdated) {
+ LOC_LOGV("DataItem:%d updated:%d", d->getId(), dataItemUpdated);
+ }
+ }
+
+ return dataItemUpdated;
+}
+
+} // namespace loc_core
+
diff --git a/core/SystemStatusOsObserver.h b/core/SystemStatusOsObserver.h
new file mode 100644
index 0000000..fd60606
--- /dev/null
+++ b/core/SystemStatusOsObserver.h
@@ -0,0 +1,176 @@
+/* Copyright (c) 2015-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 __SYSTEM_STATUS_OSOBSERVER__
+#define __SYSTEM_STATUS_OSOBSERVER__
+
+#include <cinttypes>
+#include <string>
+#include <list>
+#include <map>
+#include <new>
+#include <vector>
+
+#include <MsgTask.h>
+#include <DataItemId.h>
+#include <IOsObserver.h>
+#include <loc_pla.h>
+#include <log_util.h>
+#include <LocUnorderedSetMap.h>
+
+namespace loc_core
+{
+/******************************************************************************
+ SystemStatusOsObserver
+******************************************************************************/
+using namespace std;
+using namespace loc_util;
+
+// Forward Declarations
+class IDataItemCore;
+class SystemStatus;
+class SystemStatusOsObserver;
+typedef map<IDataItemObserver*, list<DataItemId>> ObserverReqCache;
+typedef LocUnorderedSetMap<IDataItemObserver*, DataItemId> ClientToDataItems;
+typedef LocUnorderedSetMap<DataItemId, IDataItemObserver*> DataItemToClients;
+typedef unordered_map<DataItemId, IDataItemCore*> DataItemIdToCore;
+typedef unordered_map<DataItemId, int> DataItemIdToInt;
+
+struct ObserverContext {
+ IDataItemSubscription* mSubscriptionObj;
+ IFrameworkActionReq* mFrameworkActionReqObj;
+ const MsgTask* mMsgTask;
+ SystemStatusOsObserver* mSSObserver;
+
+ inline ObserverContext(const MsgTask* msgTask, SystemStatusOsObserver* observer) :
+ mSubscriptionObj(NULL), mFrameworkActionReqObj(NULL),
+ mMsgTask(msgTask), mSSObserver(observer) {}
+};
+
+// Clients wanting to get data from OS/Framework would need to
+// subscribe with OSObserver using IDataItemSubscription interface.
+// Such clients would need to implement IDataItemObserver interface
+// to receive data when it becomes available.
+class SystemStatusOsObserver : public IOsObserver {
+
+public:
+ // ctor
+ inline SystemStatusOsObserver(SystemStatus* systemstatus, const MsgTask* msgTask) :
+ mSystemStatus(systemstatus), mContext(msgTask, this),
+ mAddress("SystemStatusOsObserver"),
+ mClientToDataItems(MAX_DATA_ITEM_ID), mDataItemToClients(MAX_DATA_ITEM_ID)
+#ifdef USE_GLIB
+ , mBackHaulConnectReqCount(0)
+#endif
+ {
+ }
+
+ // dtor
+ ~SystemStatusOsObserver();
+
+ template <typename CINT, typename COUT>
+ static COUT containerTransfer(CINT& s);
+ template <typename CINT, typename COUT>
+ inline static COUT containerTransfer(CINT&& s) {
+ return containerTransfer<CINT, COUT>(s);
+ }
+
+ // To set the subscription object
+ virtual void setSubscriptionObj(IDataItemSubscription* subscriptionObj);
+
+ // To set the framework action request object
+ inline void setFrameworkActionReqObj(IFrameworkActionReq* frameworkActionReqObj) {
+ mContext.mFrameworkActionReqObj = frameworkActionReqObj;
+#ifdef USE_GLIB
+ if (mBackHaulConnectReqCount > 0) {
+ connectBackhaul();
+ mBackHaulConnectReqCount = 0;
+ }
+#endif
+ }
+
+ // IDataItemSubscription Overrides
+ inline virtual void subscribe(const list<DataItemId>& l, IDataItemObserver* client) override {
+ subscribe(l, client, false);
+ }
+ virtual void updateSubscription(const list<DataItemId>& l, IDataItemObserver* client) override;
+ inline virtual void requestData(const list<DataItemId>& l, IDataItemObserver* client) override {
+ subscribe(l, client, true);
+ }
+ virtual void unsubscribe(const list<DataItemId>& l, IDataItemObserver* client) override;
+ virtual void unsubscribeAll(IDataItemObserver* client) override;
+
+ // IDataItemObserver Overrides
+ virtual void notify(const list<IDataItemCore*>& dlist) override;
+ inline virtual void getName(string& name) override {
+ name = mAddress;
+ }
+
+ // IFrameworkActionReq Overrides
+ virtual void turnOn(DataItemId dit, int timeOut = 0) override;
+ virtual void turnOff(DataItemId dit) override;
+#ifdef USE_GLIB
+ virtual bool connectBackhaul() override;
+ virtual bool disconnectBackhaul();
+#endif
+
+private:
+ SystemStatus* mSystemStatus;
+ ObserverContext mContext;
+ const string mAddress;
+ ClientToDataItems mClientToDataItems;
+ DataItemToClients mDataItemToClients;
+ DataItemIdToCore mDataItemCache;
+ DataItemIdToInt mActiveRequestCount;
+
+ // Cache the subscribe and requestData till subscription obj is obtained
+ void cacheObserverRequest(ObserverReqCache& reqCache,
+ const list<DataItemId>& l, IDataItemObserver* client);
+#ifdef USE_GLIB
+ // Cache the framework action request for connect/disconnect
+ int mBackHaulConnectReqCount;
+#endif
+
+ void subscribe(const list<DataItemId>& l, IDataItemObserver* client, bool toRequestData);
+
+ // Helpers
+ void sendCachedDataItems(const unordered_set<DataItemId>& s, IDataItemObserver* to);
+ bool updateCache(IDataItemCore* d);
+ inline void logMe(const unordered_set<DataItemId>& l) {
+ IF_LOC_LOGD {
+ for (auto id : l) {
+ LOC_LOGD("DataItem %d", id);
+ }
+ }
+ }
+};
+
+} // namespace loc_core
+
+#endif //__SYSTEM_STATUS__
+
diff --git a/core/configure.ac b/core/configure.ac
new file mode 100644
index 0000000..ea0a128
--- /dev/null
+++ b/core/configure.ac
@@ -0,0 +1,82 @@
+# configure.ac -- Autoconf script for gps loc-core
+#
+# Process this file with autoconf to produce a configure script
+
+# Requires autoconf tool later than 2.61
+AC_PREREQ(2.61)
+# Initialize the gps loc-hal package version 1.0.0
+AC_INIT([loc-core],1.0.0)
+# Does not strictly follow GNU Coding standards
+AM_INIT_AUTOMAKE([foreign])
+# Disables auto rebuilding of configure, Makefile.ins
+AM_MAINTAINER_MODE
+# Verifies the --srcdir is correct by checking for the path
+AC_CONFIG_SRCDIR([loc-core.pc.in])
+# defines some macros variable to be included by source
+AC_CONFIG_HEADERS([config.h])
+AC_CONFIG_MACRO_DIR([m4])
+
+# Checks for programs.
+AC_PROG_LIBTOOL
+AC_PROG_CXX
+AC_PROG_CC
+AM_PROG_CC_C_O
+AC_PROG_AWK
+AC_PROG_CPP
+AC_PROG_INSTALL
+AC_PROG_LN_S
+AC_PROG_MAKE_SET
+PKG_PROG_PKG_CONFIG
+
+# Checks for libraries.
+PKG_CHECK_MODULES([GPSUTILS], [gps-utils])
+AC_SUBST([GPSUTILS_CFLAGS])
+AC_SUBST([GPSUTILS_LIBS])
+
+AC_ARG_WITH([core_includes],
+ AC_HELP_STRING([--with-core-includes=@<:@dir@:>@],
+ [Specify the location of the core headers]),
+ [core_incdir=$withval],
+ with_core_includes=no)
+
+if test "x$with_core_includes" != "xno"; then
+ CPPFLAGS="${CPPFLAGS} -I${core_incdir}"
+fi
+
+AC_ARG_WITH([locpla_includes],
+ AC_HELP_STRING([--with-locpla-includes=@<:@dir@:>@],
+ [specify the path to locpla-includes in loc-pla_git.bb]),
+ [locpla_incdir=$withval],
+ with_locpla_includes=no)
+
+if test "x$with_locpla_includes" != "xno"; then
+ AC_SUBST(LOCPLA_CFLAGS, "-I${locpla_incdir}")
+fi
+
+AC_SUBST([CPPFLAGS])
+
+AC_ARG_WITH([glib],
+ AC_HELP_STRING([--with-glib],
+ [enable glib, building HLOS systems which use glib]))
+
+if (test "x${with_glib}" = "xyes"); then
+ AC_DEFINE(ENABLE_USEGLIB, 1, [Define if HLOS systems uses glib])
+ PKG_CHECK_MODULES(GTHREAD, gthread-2.0 >= 2.16, dummy=yes,
+ AC_MSG_ERROR(GThread >= 2.16 is required))
+ PKG_CHECK_MODULES(GLIB, glib-2.0 >= 2.16, dummy=yes,
+ AC_MSG_ERROR(GLib >= 2.16 is required))
+ GLIB_CFLAGS="$GLIB_CFLAGS $GTHREAD_CFLAGS"
+ GLIB_LIBS="$GLIB_LIBS $GTHREAD_LIBS"
+
+ AC_SUBST(GLIB_CFLAGS)
+ AC_SUBST(GLIB_LIBS)
+fi
+
+AM_CONDITIONAL(USE_GLIB, test "x${with_glib}" = "xyes")
+
+AC_CONFIG_FILES([ \
+ Makefile \
+ loc-core.pc \
+ ])
+
+AC_OUTPUT
diff --git a/core/data-items/DataItemConcreteTypesBase.h b/core/data-items/DataItemConcreteTypesBase.h
new file mode 100644
index 0000000..c32d65d
--- /dev/null
+++ b/core/data-items/DataItemConcreteTypesBase.h
@@ -0,0 +1,554 @@
+/* Copyright (c) 2015-2017, 2019, 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 __DATAITEMCONCRETEBASETYPES__
+#define __DATAITEMCONCRETEBASETYPES__
+
+#include <string>
+#include <cstring>
+#include <sstream>
+#include <DataItemId.h>
+#include <IDataItemCore.h>
+#include <gps_extended_c.h>
+#include <inttypes.h>
+
+#define MAC_ADDRESS_LENGTH 6
+// MAC address length in bytes
+// QMI_LOC_SRN_MAC_ADDR_LENGTH_V02
+#define SRN_MAC_ADDRESS_LENGTH 6
+#define WIFI_SUPPLICANT_DEFAULT_STATE 0
+
+static constexpr char sDelimit = ':';
+
+namespace loc_core
+{
+using namespace std;
+
+enum NetworkType {
+ TYPE_MOBILE = 0,
+ TYPE_WIFI,
+ TYPE_ETHERNET,
+ TYPE_BLUETOOTH,
+ TYPE_MMS,
+ TYPE_SUPL,
+ TYPE_DUN,
+ TYPE_HIPRI,
+ TYPE_WIMAX,
+ TYPE_PROXY,
+ TYPE_UNKNOWN,
+};
+
+typedef struct NetworkInfoType
+{
+ // Unique network handle ID
+ uint64_t networkHandle;
+ // Type of network for corresponding network handle
+ NetworkType networkType;
+ NetworkInfoType() : networkHandle(NETWORK_HANDLE_UNKNOWN), networkType(TYPE_UNKNOWN) {}
+ NetworkInfoType(string strObj) {
+ size_t posDelimit = strObj.find(sDelimit);
+
+ if ( posDelimit != string::npos) {
+ int32_t type = TYPE_UNKNOWN;
+ string handleStr = strObj.substr(0, posDelimit);
+ string typeStr = strObj.substr(posDelimit + 1, strObj.length() - posDelimit - 1);
+ stringstream(handleStr) >> networkHandle;
+ stringstream(typeStr) >> type;
+ networkType = (NetworkType) type;
+ } else {
+ networkHandle = NETWORK_HANDLE_UNKNOWN;
+ networkType = TYPE_UNKNOWN;
+ }
+ }
+ bool operator== (const NetworkInfoType& other) {
+ return ((networkHandle == other.networkHandle) && (networkType == other.networkType));
+ }
+ string toString() {
+ string valueStr;
+ valueStr.clear ();
+ char nethandle [32];
+ memset (nethandle, 0, 32);
+ snprintf(nethandle, sizeof(nethandle), "%" PRIu64, networkHandle);
+ valueStr += string(nethandle);
+ valueStr += sDelimit;
+ char type [12];
+ memset (type, 0, 12);
+ snprintf (type, 12, "%u", networkType);
+ valueStr += string (type);
+ return valueStr;
+ }
+} NetworkInfoType;
+
+
+class AirplaneModeDataItemBase : public IDataItemCore {
+public:
+ AirplaneModeDataItemBase(bool mode):
+ mMode(mode),
+ mId(AIRPLANEMODE_DATA_ITEM_ID) {}
+ virtual ~AirplaneModeDataItemBase() {}
+ inline virtual DataItemId getId() { return mId; }
+ virtual void stringify(string& /*valueStr*/) {}
+ virtual int32_t copy(IDataItemCore* /*src*/, bool* /*dataItemCopied = NULL*/) {return 1;}
+// Data members
+ bool mMode;
+
+protected:
+ DataItemId mId;
+};
+
+class ENHDataItemBase : public IDataItemCore {
+public:
+ ENHDataItemBase(bool enabled) :
+ mEnabled(enabled),
+ mId(ENH_DATA_ITEM_ID) {}
+ virtual ~ENHDataItemBase() {}
+ inline virtual DataItemId getId() { return mId; }
+ virtual void stringify(string& /*valueStr*/) {}
+ virtual int32_t copy(IDataItemCore* /*src*/, bool* /*dataItemCopied = NULL*/) {return 1;}
+// Data members
+ bool mEnabled;
+protected:
+ DataItemId mId;
+};
+
+class GPSStateDataItemBase : public IDataItemCore {
+public:
+ GPSStateDataItemBase(bool enabled) :
+ mEnabled(enabled),
+ mId(GPSSTATE_DATA_ITEM_ID) {}
+ virtual ~GPSStateDataItemBase() {}
+ inline virtual DataItemId getId() { return mId; }
+ virtual void stringify(string& /*valueStr*/) {}
+ virtual int32_t copy(IDataItemCore* /*src*/, bool* /*dataItemCopied = NULL*/) {return 1;}
+// Data members
+ bool mEnabled;
+protected:
+ DataItemId mId;
+};
+
+class NLPStatusDataItemBase : public IDataItemCore {
+public:
+ NLPStatusDataItemBase(bool enabled) :
+ mEnabled(enabled),
+ mId(NLPSTATUS_DATA_ITEM_ID) {}
+ virtual ~NLPStatusDataItemBase() {}
+ inline virtual DataItemId getId() { return mId; }
+ virtual void stringify(string& /*valueStr*/) {}
+ virtual int32_t copy(IDataItemCore* /*src*/, bool* /*dataItemCopied = NULL*/) {return 1;}
+// Data members
+ bool mEnabled;
+protected:
+ DataItemId mId;
+};
+
+class WifiHardwareStateDataItemBase : public IDataItemCore {
+public:
+ WifiHardwareStateDataItemBase(bool enabled) :
+ mEnabled(enabled),
+ mId(WIFIHARDWARESTATE_DATA_ITEM_ID) {}
+ virtual ~WifiHardwareStateDataItemBase() {}
+ inline virtual DataItemId getId() { return mId; }
+ virtual void stringify(string& /*valueStr*/) {}
+ virtual int32_t copy(IDataItemCore* /*src*/, bool* /*dataItemCopied = NULL*/) {return 1;}
+// Data members
+ bool mEnabled;
+protected:
+ DataItemId mId;
+};
+
+class ScreenStateDataItemBase : public IDataItemCore {
+public:
+ ScreenStateDataItemBase(bool state) :
+ mState(state),
+ mId(SCREEN_STATE_DATA_ITEM_ID) {}
+ virtual ~ScreenStateDataItemBase() {}
+ inline virtual DataItemId getId() { return mId; }
+ virtual void stringify(string& /*valueStr*/) {}
+ virtual int32_t copy(IDataItemCore* /*src*/, bool* /*dataItemCopied = NULL*/) {return 1;}
+// Data members
+ bool mState;
+protected:
+ DataItemId mId;
+};
+
+class PowerConnectStateDataItemBase : public IDataItemCore {
+public:
+ PowerConnectStateDataItemBase(bool state) :
+ mState(state),
+ mId(POWER_CONNECTED_STATE_DATA_ITEM_ID) {}
+ virtual ~PowerConnectStateDataItemBase() {}
+ inline virtual DataItemId getId() { return mId; }
+ virtual void stringify(string& /*valueStr*/) {}
+ virtual int32_t copy(IDataItemCore* /*src*/, bool* /*dataItemCopied = NULL*/) {return 1;}
+// Data members
+ bool mState;
+protected:
+ DataItemId mId;
+};
+
+class TimeZoneChangeDataItemBase : public IDataItemCore {
+public:
+ TimeZoneChangeDataItemBase(int64_t currTimeMillis, int32_t rawOffset, int32_t dstOffset) :
+ mCurrTimeMillis (currTimeMillis),
+ mRawOffsetTZ (rawOffset),
+ mDstOffsetTZ (dstOffset),
+ mId(TIMEZONE_CHANGE_DATA_ITEM_ID) {}
+ virtual ~TimeZoneChangeDataItemBase() {}
+ inline virtual DataItemId getId() { return mId; }
+ virtual void stringify(string& /*valueStr*/) {}
+ virtual int32_t copy(IDataItemCore* /*src*/, bool* /*dataItemCopied = NULL*/) {return 1;}
+// Data members
+ int64_t mCurrTimeMillis;
+ int32_t mRawOffsetTZ;
+ int32_t mDstOffsetTZ;
+protected:
+ DataItemId mId;
+};
+
+class TimeChangeDataItemBase : public IDataItemCore {
+public:
+ TimeChangeDataItemBase(int64_t currTimeMillis, int32_t rawOffset, int32_t dstOffset) :
+ mCurrTimeMillis (currTimeMillis),
+ mRawOffsetTZ (rawOffset),
+ mDstOffsetTZ (dstOffset),
+ mId(TIME_CHANGE_DATA_ITEM_ID) {}
+ virtual ~TimeChangeDataItemBase() {}
+ inline virtual DataItemId getId() { return mId; }
+ virtual void stringify(string& /*valueStr*/) {}
+ virtual int32_t copy(IDataItemCore* /*src*/, bool* /*dataItemCopied = NULL*/) {return 1;}
+// Data members
+ int64_t mCurrTimeMillis;
+ int32_t mRawOffsetTZ;
+ int32_t mDstOffsetTZ;
+protected:
+ DataItemId mId;
+};
+
+class ShutdownStateDataItemBase : public IDataItemCore {
+public:
+ ShutdownStateDataItemBase(bool state) :
+ mState (state),
+ mId(SHUTDOWN_STATE_DATA_ITEM_ID) {}
+ virtual ~ShutdownStateDataItemBase() {}
+ inline virtual DataItemId getId() { return mId; }
+ virtual void stringify(string& /*valueStr*/) {}
+ virtual int32_t copy(IDataItemCore* /*src*/, bool* /*dataItemCopied = NULL*/) {return 1;}
+// Data members
+ bool mState;
+protected:
+ DataItemId mId;
+};
+
+class AssistedGpsDataItemBase : public IDataItemCore {
+public:
+ AssistedGpsDataItemBase(bool enabled) :
+ mEnabled(enabled),
+ mId(ASSISTED_GPS_DATA_ITEM_ID) {}
+ virtual ~AssistedGpsDataItemBase() {}
+ inline virtual DataItemId getId() { return mId; }
+ virtual void stringify(string& /*valueStr*/) {}
+ virtual int32_t copy(IDataItemCore* /*src*/, bool* /*dataItemCopied = NULL*/) {return 1;}
+// Data members
+ bool mEnabled;
+protected:
+ DataItemId mId;
+};
+
+class NetworkInfoDataItemBase : public IDataItemCore {
+public:
+ NetworkInfoDataItemBase(
+ NetworkType initialType, int32_t type, string typeName, string subTypeName,
+ bool available, bool connected, bool roaming, uint64_t networkHandle ):
+ mAllTypes(typeToAllTypes(initialType)),
+ mType(type),
+ mTypeName(typeName),
+ mSubTypeName(subTypeName),
+ mAvailable(available),
+ mConnected(connected),
+ mRoaming(roaming),
+ mNetworkHandle(networkHandle),
+ mId(NETWORKINFO_DATA_ITEM_ID) {
+ mAllNetworkHandles[0].networkHandle = networkHandle;
+ mAllNetworkHandles[0].networkType = initialType;
+ }
+ virtual ~NetworkInfoDataItemBase() {}
+ inline virtual DataItemId getId() { return mId; }
+ virtual void stringify(string& /*valueStr*/) {}
+ virtual int32_t copy(IDataItemCore* /*src*/, bool* /*dataItemCopied = NULL*/) {return 1;}
+ inline virtual NetworkType getType(void) const {
+ return (NetworkType)mType;
+ }
+ inline uint64_t getAllTypes() { return mAllTypes; }
+ inline NetworkInfoType* getNetworkHandle() {
+ return &mAllNetworkHandles[0];
+ }
+ // Data members
+ uint64_t mAllTypes;
+ int32_t mType;
+ string mTypeName;
+ string mSubTypeName;
+ bool mAvailable;
+ bool mConnected;
+ bool mRoaming;
+ NetworkInfoType mAllNetworkHandles[MAX_NETWORK_HANDLES];
+ uint64_t mNetworkHandle;
+protected:
+ DataItemId mId;
+ inline uint64_t typeToAllTypes(NetworkType type) {
+ return (type >= TYPE_UNKNOWN || type < TYPE_MOBILE) ? 0 : (1<<type);
+ }
+};
+
+class ServiceStatusDataItemBase : public IDataItemCore {
+public:
+ ServiceStatusDataItemBase(int32_t serviceState) :
+ mServiceState (serviceState),
+ mId(SERVICESTATUS_DATA_ITEM_ID) {}
+ virtual ~ServiceStatusDataItemBase() {}
+ inline virtual DataItemId getId() { return mId; }
+ virtual void stringify(string& /*valueStr*/) {}
+ virtual int32_t copy(IDataItemCore* /*src*/, bool* /*dataItemCopied = NULL*/) {return 1;}
+// Data members
+ int32_t mServiceState;
+protected:
+ DataItemId mId;
+};
+
+class ModelDataItemBase : public IDataItemCore {
+public:
+ ModelDataItemBase(const string & name) :
+ mModel (name),
+ mId(MODEL_DATA_ITEM_ID) {}
+ virtual ~ModelDataItemBase() {}
+ inline virtual DataItemId getId() { return mId; }
+ virtual void stringify(string& /*valueStr*/) {}
+ virtual int32_t copy(IDataItemCore* /*src*/, bool* /*dataItemCopied = NULL*/) {return 1;}
+// Data members
+ string mModel;
+protected:
+ DataItemId mId;
+};
+
+class ManufacturerDataItemBase : public IDataItemCore {
+public:
+ ManufacturerDataItemBase(const string & name) :
+ mManufacturer (name),
+ mId(MANUFACTURER_DATA_ITEM_ID) {}
+ virtual ~ManufacturerDataItemBase() {}
+ inline virtual DataItemId getId() { return mId; }
+ virtual void stringify(string& /*valueStr*/) {}
+ virtual int32_t copy(IDataItemCore* /*src*/, bool* /*dataItemCopied = NULL*/) {return 1;}
+// Data members
+ string mManufacturer;
+protected:
+ DataItemId mId;
+};
+
+class RilServiceInfoDataItemBase : public IDataItemCore {
+public:
+ inline RilServiceInfoDataItemBase() :
+ mData(nullptr), mId(RILSERVICEINFO_DATA_ITEM_ID) {}
+ inline virtual ~RilServiceInfoDataItemBase() { if (nullptr != mData) free(mData); }
+ inline virtual DataItemId getId() { return mId; }
+ virtual void stringify(string& /*valueStr*/) {}
+ virtual int32_t copy(IDataItemCore* /*src*/, bool* /*dataItemCopied = NULL*/) {return 1;}
+ inline RilServiceInfoDataItemBase(const RilServiceInfoDataItemBase& peer) :
+ RilServiceInfoDataItemBase() {
+ peer.setPeerData(*this);
+ }
+ inline virtual bool operator==(const RilServiceInfoDataItemBase& other) const {
+ return other.mData == mData;
+ }
+ inline virtual void setPeerData(RilServiceInfoDataItemBase& /*peer*/) const {}
+ void* mData;
+protected:
+ DataItemId mId;
+};
+
+class RilCellInfoDataItemBase : public IDataItemCore {
+public:
+ inline RilCellInfoDataItemBase() :
+ mData(nullptr), mId(RILCELLINFO_DATA_ITEM_ID) {}
+ inline virtual ~RilCellInfoDataItemBase() { if (nullptr != mData) free(mData); }
+ inline virtual DataItemId getId() { return mId; }
+ virtual void stringify(string& /*valueStr*/) {}
+ virtual int32_t copy(IDataItemCore* /*src*/, bool* /*dataItemCopied = NULL*/) {return 1;}
+ inline RilCellInfoDataItemBase(const RilCellInfoDataItemBase& peer) :
+ RilCellInfoDataItemBase() {
+ peer.setPeerData(*this);
+ }
+ inline virtual bool operator==(const RilCellInfoDataItemBase& other) const {
+ return other.mData == mData;
+ }
+ inline virtual void setPeerData(RilCellInfoDataItemBase& /*peer*/) const {}
+ void* mData;
+protected:
+ DataItemId mId;
+};
+
+class WifiSupplicantStatusDataItemBase : public IDataItemCore {
+public:
+ WifiSupplicantStatusDataItemBase() :
+ mState((WifiSupplicantState)WIFI_SUPPLICANT_DEFAULT_STATE),
+ mApMacAddressValid(false),
+ mWifiApSsidValid(false),
+ mId(WIFI_SUPPLICANT_STATUS_DATA_ITEM_ID) {
+ memset (&mApMacAddress, 0, sizeof (mApMacAddress));
+ mWifiApSsid.clear();
+ }
+ virtual ~WifiSupplicantStatusDataItemBase() {}
+ inline virtual DataItemId getId() { return mId; }
+ virtual void stringify(string& /*valueStr*/) {}
+ virtual int32_t copy(IDataItemCore* /*src*/, bool* /*dataItemCopied = NULL*/) {return 1;}
+ // Data members
+ typedef enum WifiSupplicantState {
+ DISCONNECTED,
+ INTERFACE_DISABLED,
+ INACTIVE,
+ SCANNING,
+ AUTHENTICATING,
+ ASSOCIATING,
+ ASSOCIATED,
+ FOUR_WAY_HANDSHAKE,
+ GROUP_HANDSHAKE,
+ COMPLETED,
+ DORMANT,
+ UNINITIALIZED,
+ INVALID
+ } WifiSupplicantState;
+ /* Represents whether access point attach state*/
+ WifiSupplicantState mState;
+ /* Represents info on whether ap mac address is valid */
+ bool mApMacAddressValid;
+ /* Represents mac address of the wifi access point*/
+ uint8_t mApMacAddress[MAC_ADDRESS_LENGTH];
+ /* Represents info on whether ap SSID is valid */
+ bool mWifiApSsidValid;
+ /* Represents Wifi SSID string*/
+ string mWifiApSsid;
+protected:
+ DataItemId mId;
+};
+
+class TacDataItemBase : public IDataItemCore {
+public:
+ TacDataItemBase(const string & name) :
+ mValue (name),
+ mId(TAC_DATA_ITEM_ID) {}
+ virtual ~TacDataItemBase() {}
+ inline virtual DataItemId getId() { return mId; }
+ virtual void stringify(string& /*valueStr*/) {}
+ virtual int32_t copy(IDataItemCore* /*src*/, bool* /*dataItemCopied = NULL*/) {return 1;}
+// Data members
+ string mValue;
+protected:
+ DataItemId mId;
+};
+
+class MccmncDataItemBase : public IDataItemCore {
+public:
+ MccmncDataItemBase(const string & name) :
+ mValue(name),
+ mId(MCCMNC_DATA_ITEM_ID) {}
+ virtual ~MccmncDataItemBase() {}
+ inline virtual DataItemId getId() { return mId; }
+ virtual void stringify(string& /*valueStr*/) {}
+ virtual int32_t copy(IDataItemCore* /*src*/, bool* /*dataItemCopied = NULL*/) {return 1;}
+// Data members
+ string mValue;
+protected:
+ DataItemId mId;
+};
+
+class SrnDeviceScanDetailsDataItemBase : public IDataItemCore {
+public:
+ SrnDeviceScanDetailsDataItemBase(DataItemId Id) :
+ mValidSrnData(false),
+ mApSrnRssi(-1),
+ mApSrnTimestamp(0),
+ mRequestTimestamp(0),
+ mReceiveTimestamp(0),
+ mErrorCause(-1),
+ mId(Id) {}
+ virtual ~SrnDeviceScanDetailsDataItemBase() {}
+ inline virtual DataItemId getId() { return mId; }
+ // Data members common to all SRN tech types
+ /* Represents info on whether SRN data is valid (no error)*/
+ bool mValidSrnData;
+ /* SRN device RSSI reported */
+ int32_t mApSrnRssi;
+ /* MAC adress of SRN device */
+ uint8_t mApSrnMacAddress[SRN_MAC_ADDRESS_LENGTH];
+ /* UTC timestamp at which the scan was requested.for this SRN device*/
+ int64_t mApSrnTimestamp;
+ /* UTC timestamp at which the scan was started. */
+ int64_t mRequestTimestamp;
+ /* UTC timestamp at which the scan was received.*/
+ int64_t mReceiveTimestamp;
+ /* Reason for the error/failure if SRN details are not valid */
+ int32_t mErrorCause;
+protected:
+ DataItemId mId;
+};
+
+class BtDeviceScanDetailsDataItemBase : public SrnDeviceScanDetailsDataItemBase {
+
+public:
+ BtDeviceScanDetailsDataItemBase() :
+ SrnDeviceScanDetailsDataItemBase(BT_SCAN_DATA_ITEM_ID) {}
+ virtual ~BtDeviceScanDetailsDataItemBase() {}
+ virtual void stringify(string& /*valueStr*/) {}
+ virtual int32_t copy(IDataItemCore* /*src*/, bool* /*dataItemCopied = NULL*/) {return 1;}
+};
+
+class BtLeDeviceScanDetailsDataItemBase : public SrnDeviceScanDetailsDataItemBase {
+
+public:
+ BtLeDeviceScanDetailsDataItemBase() :
+ SrnDeviceScanDetailsDataItemBase(BTLE_SCAN_DATA_ITEM_ID) {}
+ virtual ~BtLeDeviceScanDetailsDataItemBase() {}
+ virtual void stringify(string& /*valueStr*/) {}
+ virtual int32_t copy(IDataItemCore* /*src*/, bool* /*dataItemCopied = NULL*/) {return 1;}
+};
+
+class BatteryLevelDataItemBase : public IDataItemCore {
+public:
+ inline BatteryLevelDataItemBase(uint8_t batteryPct) :
+ mBatteryPct(batteryPct), mId(BATTERY_LEVEL_DATA_ITEM_ID) {}
+ inline ~BatteryLevelDataItemBase() {}
+ inline virtual DataItemId getId() { return mId; }
+// Data members
+ uint8_t mBatteryPct;
+protected:
+ DataItemId mId;
+};
+
+} // namespace loc_core
+
+#endif //__DATAITEMCONCRETEBASETYPES__
diff --git a/core/data-items/DataItemId.h b/core/data-items/DataItemId.h
new file mode 100644
index 0000000..1661be6
--- /dev/null
+++ b/core/data-items/DataItemId.h
@@ -0,0 +1,79 @@
+/* Copyright (c) 2015-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 __DATAITEMID_H__
+#define __DATAITEMID_H__
+
+/**
+ * Enumeration of Data Item types
+ * When add/remove/update changes are made to Data Items, this file needs to be updated
+ * accordingly
+ */
+typedef enum e_DataItemId {
+ INVALID_DATA_ITEM_ID = -1,
+ // 0 - 4
+ AIRPLANEMODE_DATA_ITEM_ID,
+ ENH_DATA_ITEM_ID,
+ GPSSTATE_DATA_ITEM_ID,
+ NLPSTATUS_DATA_ITEM_ID,
+ WIFIHARDWARESTATE_DATA_ITEM_ID,
+ // 5 - 9
+ NETWORKINFO_DATA_ITEM_ID,
+ RILVERSION_DATA_ITEM_ID,
+ RILSERVICEINFO_DATA_ITEM_ID,
+ RILCELLINFO_DATA_ITEM_ID,
+ SERVICESTATUS_DATA_ITEM_ID,
+ // 10 - 14
+ MODEL_DATA_ITEM_ID,
+ MANUFACTURER_DATA_ITEM_ID,
+ VOICECALL_DATA_ITEM,
+ ASSISTED_GPS_DATA_ITEM_ID,
+ SCREEN_STATE_DATA_ITEM_ID,
+ // 15 - 19
+ POWER_CONNECTED_STATE_DATA_ITEM_ID,
+ TIMEZONE_CHANGE_DATA_ITEM_ID,
+ TIME_CHANGE_DATA_ITEM_ID,
+ WIFI_SUPPLICANT_STATUS_DATA_ITEM_ID,
+ SHUTDOWN_STATE_DATA_ITEM_ID,
+ // 20 - 24
+ TAC_DATA_ITEM_ID,
+ MCCMNC_DATA_ITEM_ID,
+ BTLE_SCAN_DATA_ITEM_ID,
+ BT_SCAN_DATA_ITEM_ID,
+ OEM_GTP_UPLOAD_TRIGGER_READY_ITEM_ID,
+
+ MAX_DATA_ITEM_ID,
+
+ // 26 -
+ BATTERY_LEVEL_DATA_ITEM_ID,
+
+ MAX_DATA_ITEM_ID_1_1,
+} DataItemId;
+
+#endif // #ifndef __DATAITEMID_H__
diff --git a/core/data-items/DataItemsFactoryProxy.cpp b/core/data-items/DataItemsFactoryProxy.cpp
new file mode 100644
index 0000000..f8a5e03
--- /dev/null
+++ b/core/data-items/DataItemsFactoryProxy.cpp
@@ -0,0 +1,100 @@
+/* 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 "DataItemsFactoryProxy"
+
+#include <dlfcn.h>
+#include <DataItemId.h>
+#include <IDataItemCore.h>
+#include <DataItemsFactoryProxy.h>
+#include <loc_pla.h>
+#include <log_util.h>
+
+namespace loc_core
+{
+void* DataItemsFactoryProxy::dataItemLibHandle = NULL;
+get_concrete_data_item_fn* DataItemsFactoryProxy::getConcreteDIFunc = NULL;
+
+IDataItemCore* DataItemsFactoryProxy::createNewDataItem(DataItemId id)
+{
+ IDataItemCore *mydi = nullptr;
+
+ if (NULL != getConcreteDIFunc) {
+ mydi = (*getConcreteDIFunc)(id);
+ }
+ else {
+ // first call to this function, symbol not yet loaded
+ if (NULL == dataItemLibHandle) {
+ LOC_LOGD("Loaded library %s",DATA_ITEMS_LIB_NAME);
+ dataItemLibHandle = dlopen(DATA_ITEMS_LIB_NAME, RTLD_NOW);
+ if (NULL == dataItemLibHandle) {
+ // dlopen failed.
+ const char * err = dlerror();
+ if (NULL == err)
+ {
+ err = "Unknown";
+ }
+ LOC_LOGE("%s:%d]: failed to load library %s; error=%s",
+ __func__, __LINE__, DATA_ITEMS_LIB_NAME, err);
+ }
+ }
+
+ // load sym - if dlopen handle is obtained and symbol is not yet obtained
+ if (NULL != dataItemLibHandle) {
+ getConcreteDIFunc = (get_concrete_data_item_fn * )
+ dlsym(dataItemLibHandle, DATA_ITEMS_GET_CONCRETE_DI);
+ if (NULL != getConcreteDIFunc) {
+ LOC_LOGD("Loaded function %s : %p",DATA_ITEMS_GET_CONCRETE_DI,getConcreteDIFunc);
+ mydi = (*getConcreteDIFunc)(id);
+ }
+ else {
+ // dlysm failed.
+ const char * err = dlerror();
+ if (NULL == err)
+ {
+ err = "Unknown";
+ }
+ LOC_LOGE("%s:%d]: failed to find symbol %s; error=%s",
+ __func__, __LINE__, DATA_ITEMS_GET_CONCRETE_DI, err);
+ }
+ }
+ }
+ return mydi;
+}
+
+void DataItemsFactoryProxy::closeDataItemLibraryHandle()
+{
+ if (NULL != dataItemLibHandle) {
+ dlclose(dataItemLibHandle);
+ dataItemLibHandle = NULL;
+ }
+}
+
+} // namespace loc_core
+
+
diff --git a/core/data-items/DataItemsFactoryProxy.h b/core/data-items/DataItemsFactoryProxy.h
new file mode 100644
index 0000000..cfd447d
--- /dev/null
+++ b/core/data-items/DataItemsFactoryProxy.h
@@ -0,0 +1,55 @@
+/* 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 __DATAITEMFACTORYBASE__
+#define __DATAITEMFACTORYBASE__
+
+#include <DataItemId.h>
+#include <IDataItemCore.h>
+
+namespace loc_core
+{
+
+#define DATA_ITEMS_LIB_NAME "libdataitems.so"
+#define DATA_ITEMS_GET_CONCRETE_DI "getConcreteDataItem"
+
+typedef IDataItemCore * (get_concrete_data_item_fn)(DataItemId);
+
+class DataItemsFactoryProxy {
+public:
+ static IDataItemCore* createNewDataItem(DataItemId id);
+ static void closeDataItemLibraryHandle();
+ static void *dataItemLibHandle;
+ static get_concrete_data_item_fn *getConcreteDIFunc;
+};
+
+} // namespace loc_core
+
+#endif //__DATAITEMFACTORYBASE__
+
diff --git a/core/data-items/IDataItemCore.h b/core/data-items/IDataItemCore.h
new file mode 100644
index 0000000..6084c92
--- /dev/null
+++ b/core/data-items/IDataItemCore.h
@@ -0,0 +1,82 @@
+/* Copyright (c) 2015, 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 __IDATAITEMCORE_H__
+#define __IDATAITEMCORE_H__
+
+#include <string>
+#include <DataItemId.h>
+
+namespace loc_core {
+
+using namespace std;
+
+/**
+ * @brief IDataItemCore interface.
+ * @details IDataItemCore interface.
+ *
+ */
+class IDataItemCore {
+public:
+ /**
+ * @brief Gets Data item id.
+ * @details Gets Data item id.
+ * @return Data item id.
+ */
+ virtual DataItemId getId () = 0;
+
+ /**
+ * @brief Stringify.
+ * @details Stringify.
+ *
+ * @param valueStr Reference to string.
+ */
+ virtual void stringify (string & valueStr) = 0;
+
+ /**
+ * @brief copy.
+ * @details copy.
+ *
+ * @param src Where to copy from.
+ * @param dataItemCopied Boolean flag indicated whether or not copied.
+ *
+ * @return Zero for success or non zero for failure.
+ */
+ virtual int32_t copy (IDataItemCore * src, bool *dataItemCopied = nullptr) = 0;
+
+ /**
+ * @brief Destructor.
+ * @details Destructor.
+ */
+ virtual ~IDataItemCore () {}
+};
+
+} // namespace loc_core
+
+#endif // __IDATAITEMCORE_H__
diff --git a/core/loc-core.pc.in b/core/loc-core.pc.in
new file mode 100644
index 0000000..76b514c
--- /dev/null
+++ b/core/loc-core.pc.in
@@ -0,0 +1,10 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+
+Name: loc-core
+Description: QTI GPS Loc Core
+Version: @VERSION@
+Libs: -L${libdir} -lloc_core
+Cflags: -I${includedir}/loc-core
diff --git a/core/loc_core_log.cpp b/core/loc_core_log.cpp
new file mode 100644
index 0000000..ddf18ec
--- /dev/null
+++ b/core/loc_core_log.cpp
@@ -0,0 +1,227 @@
+/* Copyright (c) 2011-2015, 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_NDEBUG 0
+#define LOG_TAG "LocSvc_core_log"
+
+#include <log_util.h>
+#include <loc_log.h>
+#include <loc_core_log.h>
+#include <loc_pla.h>
+
+void LocPosMode::logv() const
+{
+ LOC_LOGV ("Position mode: %s\n Position recurrence: %s\n "
+ "min interval: %d\n preferred accuracy: %d\n "
+ "preferred time: %d\n credentials: %s provider: %s \n "
+ "power mode: %d\n tbm %d",
+ loc_get_position_mode_name(mode),
+ loc_get_position_recurrence_name(recurrence),
+ min_interval,
+ preferred_accuracy,
+ preferred_time,
+ credentials,
+ provider,
+ powerMode,
+ timeBetweenMeasurements);
+}
+
+/* GPS status names */
+static const loc_name_val_s_type gps_status_name[] =
+{
+ NAME_VAL( LOC_GPS_STATUS_NONE ),
+ NAME_VAL( LOC_GPS_STATUS_SESSION_BEGIN ),
+ NAME_VAL( LOC_GPS_STATUS_SESSION_END ),
+ NAME_VAL( LOC_GPS_STATUS_ENGINE_ON ),
+ NAME_VAL( LOC_GPS_STATUS_ENGINE_OFF ),
+};
+static const int gps_status_num = sizeof(gps_status_name) / sizeof(loc_name_val_s_type);
+
+/* Find Android GPS status name */
+const char* loc_get_gps_status_name(LocGpsStatusValue gps_status)
+{
+ return loc_get_name_from_val(gps_status_name, gps_status_num,
+ (long) gps_status);
+}
+
+
+
+static const loc_name_val_s_type loc_eng_position_modes[] =
+{
+ NAME_VAL( LOC_POSITION_MODE_STANDALONE ),
+ NAME_VAL( LOC_POSITION_MODE_MS_BASED ),
+ NAME_VAL( LOC_POSITION_MODE_MS_ASSISTED ),
+ NAME_VAL( LOC_POSITION_MODE_RESERVED_1 ),
+ NAME_VAL( LOC_POSITION_MODE_RESERVED_2 ),
+ NAME_VAL( LOC_POSITION_MODE_RESERVED_3 ),
+ NAME_VAL( LOC_POSITION_MODE_RESERVED_4 ),
+ NAME_VAL( LOC_POSITION_MODE_RESERVED_5 )
+};
+static const int loc_eng_position_mode_num = sizeof(loc_eng_position_modes) / sizeof(loc_name_val_s_type);
+
+const char* loc_get_position_mode_name(LocGpsPositionMode mode)
+{
+ return loc_get_name_from_val(loc_eng_position_modes, loc_eng_position_mode_num, (long) mode);
+}
+
+
+
+static const loc_name_val_s_type loc_eng_position_recurrences[] =
+{
+ NAME_VAL( LOC_GPS_POSITION_RECURRENCE_PERIODIC ),
+ NAME_VAL( LOC_GPS_POSITION_RECURRENCE_SINGLE )
+};
+static const int loc_eng_position_recurrence_num = sizeof(loc_eng_position_recurrences) / sizeof(loc_name_val_s_type);
+
+const char* loc_get_position_recurrence_name(LocGpsPositionRecurrence recur)
+{
+ return loc_get_name_from_val(loc_eng_position_recurrences, loc_eng_position_recurrence_num, (long) recur);
+}
+
+const char* loc_get_aiding_data_mask_names(LocGpsAidingData /*data*/)
+{
+ return NULL;
+}
+
+
+static const loc_name_val_s_type loc_eng_agps_types[] =
+{
+ NAME_VAL( LOC_AGPS_TYPE_INVALID ),
+ NAME_VAL( LOC_AGPS_TYPE_ANY ),
+ NAME_VAL( LOC_AGPS_TYPE_SUPL ),
+ NAME_VAL( LOC_AGPS_TYPE_C2K ),
+ NAME_VAL( LOC_AGPS_TYPE_WWAN_ANY )
+};
+static const int loc_eng_agps_type_num = sizeof(loc_eng_agps_types) / sizeof(loc_name_val_s_type);
+
+const char* loc_get_agps_type_name(LocAGpsType type)
+{
+ return loc_get_name_from_val(loc_eng_agps_types, loc_eng_agps_type_num, (long) type);
+}
+
+
+static const loc_name_val_s_type loc_eng_ni_types[] =
+{
+ NAME_VAL( LOC_GPS_NI_TYPE_VOICE ),
+ NAME_VAL( LOC_GPS_NI_TYPE_UMTS_SUPL ),
+ NAME_VAL( LOC_GPS_NI_TYPE_UMTS_CTRL_PLANE ),
+ NAME_VAL( LOC_GPS_NI_TYPE_EMERGENCY_SUPL )
+};
+static const int loc_eng_ni_type_num = sizeof(loc_eng_ni_types) / sizeof(loc_name_val_s_type);
+
+const char* loc_get_ni_type_name(LocGpsNiType type)
+{
+ return loc_get_name_from_val(loc_eng_ni_types, loc_eng_ni_type_num, (long) type);
+}
+
+
+static const loc_name_val_s_type loc_eng_ni_responses[] =
+{
+ NAME_VAL( LOC_GPS_NI_RESPONSE_ACCEPT ),
+ NAME_VAL( LOC_GPS_NI_RESPONSE_DENY ),
+ NAME_VAL( LOC_GPS_NI_RESPONSE_DENY )
+};
+static const int loc_eng_ni_reponse_num = sizeof(loc_eng_ni_responses) / sizeof(loc_name_val_s_type);
+
+const char* loc_get_ni_response_name(LocGpsUserResponseType response)
+{
+ return loc_get_name_from_val(loc_eng_ni_responses, loc_eng_ni_reponse_num, (long) response);
+}
+
+
+static const loc_name_val_s_type loc_eng_ni_encodings[] =
+{
+ NAME_VAL( LOC_GPS_ENC_NONE ),
+ NAME_VAL( LOC_GPS_ENC_SUPL_GSM_DEFAULT ),
+ NAME_VAL( LOC_GPS_ENC_SUPL_UTF8 ),
+ NAME_VAL( LOC_GPS_ENC_SUPL_UCS2 ),
+ NAME_VAL( LOC_GPS_ENC_UNKNOWN )
+};
+static const int loc_eng_ni_encoding_num = sizeof(loc_eng_ni_encodings) / sizeof(loc_name_val_s_type);
+
+const char* loc_get_ni_encoding_name(LocGpsNiEncodingType encoding)
+{
+ return loc_get_name_from_val(loc_eng_ni_encodings, loc_eng_ni_encoding_num, (long) encoding);
+}
+
+static const loc_name_val_s_type loc_eng_agps_bears[] =
+{
+ NAME_VAL( AGPS_APN_BEARER_INVALID ),
+ NAME_VAL( AGPS_APN_BEARER_IPV4 ),
+ NAME_VAL( AGPS_APN_BEARER_IPV6 ),
+ NAME_VAL( AGPS_APN_BEARER_IPV4V6 )
+};
+static const int loc_eng_agps_bears_num = sizeof(loc_eng_agps_bears) / sizeof(loc_name_val_s_type);
+
+const char* loc_get_agps_bear_name(AGpsBearerType bearer)
+{
+ return loc_get_name_from_val(loc_eng_agps_bears, loc_eng_agps_bears_num, (long) bearer);
+}
+
+static const loc_name_val_s_type loc_eng_server_types[] =
+{
+ NAME_VAL( LOC_AGPS_CDMA_PDE_SERVER ),
+ NAME_VAL( LOC_AGPS_CUSTOM_PDE_SERVER ),
+ NAME_VAL( LOC_AGPS_MPC_SERVER ),
+ NAME_VAL( LOC_AGPS_SUPL_SERVER )
+};
+static const int loc_eng_server_types_num = sizeof(loc_eng_server_types) / sizeof(loc_name_val_s_type);
+
+const char* loc_get_server_type_name(LocServerType type)
+{
+ return loc_get_name_from_val(loc_eng_server_types, loc_eng_server_types_num, (long) type);
+}
+
+static const loc_name_val_s_type loc_eng_position_sess_status_types[] =
+{
+ NAME_VAL( LOC_SESS_SUCCESS ),
+ NAME_VAL( LOC_SESS_INTERMEDIATE ),
+ NAME_VAL( LOC_SESS_FAILURE )
+};
+static const int loc_eng_position_sess_status_num = sizeof(loc_eng_position_sess_status_types) / sizeof(loc_name_val_s_type);
+
+const char* loc_get_position_sess_status_name(enum loc_sess_status status)
+{
+ return loc_get_name_from_val(loc_eng_position_sess_status_types, loc_eng_position_sess_status_num, (long) status);
+}
+
+static const loc_name_val_s_type loc_eng_agps_status_names[] =
+{
+ NAME_VAL( LOC_GPS_REQUEST_AGPS_DATA_CONN ),
+ NAME_VAL( LOC_GPS_RELEASE_AGPS_DATA_CONN ),
+ NAME_VAL( LOC_GPS_AGPS_DATA_CONNECTED ),
+ NAME_VAL( LOC_GPS_AGPS_DATA_CONN_DONE ),
+ NAME_VAL( LOC_GPS_AGPS_DATA_CONN_FAILED )
+};
+static const int loc_eng_agps_status_num = sizeof(loc_eng_agps_status_names) / sizeof(loc_name_val_s_type);
+
+const char* loc_get_agps_status_name(LocAGpsStatusValue status)
+{
+ return loc_get_name_from_val(loc_eng_agps_status_names, loc_eng_agps_status_num, (long) status);
+}
diff --git a/core/loc_core_log.h b/core/loc_core_log.h
new file mode 100644
index 0000000..2beb687
--- /dev/null
+++ b/core/loc_core_log.h
@@ -0,0 +1,58 @@
+/* Copyright (c) 2011-2013, 2016-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 LOC_CORE_LOG_H
+#define LOC_CORE_LOG_H
+
+#include <ctype.h>
+#include <gps_extended.h>
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+const char* loc_get_gps_status_name(LocGpsStatusValue gps_status);
+const char* loc_get_position_mode_name(LocGpsPositionMode mode);
+const char* loc_get_position_recurrence_name(LocGpsPositionRecurrence recur);
+const char* loc_get_aiding_data_mask_names(LocGpsAidingData data);
+const char* loc_get_agps_type_name(LocAGpsType type);
+const char* loc_get_ni_type_name(LocGpsNiType type);
+const char* loc_get_ni_response_name(LocGpsUserResponseType response);
+const char* loc_get_ni_encoding_name(LocGpsNiEncodingType encoding);
+const char* loc_get_agps_bear_name(AGpsBearerType bear);
+const char* loc_get_server_type_name(LocServerType type);
+const char* loc_get_position_sess_status_name(enum loc_sess_status status);
+const char* loc_get_agps_status_name(LocAGpsStatusValue status);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* LOC_CORE_LOG_H */
diff --git a/core/observer/IDataItemObserver.h b/core/observer/IDataItemObserver.h
new file mode 100644
index 0000000..7954d85
--- /dev/null
+++ b/core/observer/IDataItemObserver.h
@@ -0,0 +1,76 @@
+/* Copyright (c) 2015, 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 __IDATAITEMOBSERVER_H__
+#define __IDATAITEMOBSERVER_H__
+
+#include <list>
+#include <string>
+
+using namespace std;
+
+namespace loc_core
+{
+class IDataItemCore;
+
+/**
+ * @brief IDataItemObserver interface
+ * @details IDataItemObserver interface;
+ * In OS dependent code this type serves as a handle to an OS independent instance of this interface.
+ */
+class IDataItemObserver {
+
+public:
+
+ /**
+ * @brief Gets name of Data Item Observer
+ * @details Gets name of Data Item Observer
+ *
+ * @param name reference to name of Data Item Observer
+ */
+ virtual void getName (string & name) = 0;
+
+ /**
+ * @brief Notify updated values of Data Items
+ * @details Notifys updated values of Data items
+ *
+ * @param dlist List of updated data items
+ */
+ virtual void notify (const std :: list <IDataItemCore *> & dlist) = 0;
+
+ /**
+ * @brief Destructor
+ * @details Destructor
+ */
+ virtual ~IDataItemObserver () {}
+};
+
+} // namespace loc_core
+
+#endif // #ifndef __IDATAITEMOBSERVER_H__
diff --git a/core/observer/IDataItemSubscription.h b/core/observer/IDataItemSubscription.h
new file mode 100644
index 0000000..7e8b8c8
--- /dev/null
+++ b/core/observer/IDataItemSubscription.h
@@ -0,0 +1,129 @@
+/* Copyright (c) 2015, 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 __IDATAITEMSUBSCRIPTION_H__
+#define __IDATAITEMSUBSCRIPTION_H__
+
+#include <list>
+#include <DataItemId.h>
+
+namespace loc_core
+{
+class IDataItemObserver;
+
+/**
+ * @brief IDataItemSubscription interface
+ * @details IDataItemSubscription interface;
+ * Defines an interface for operations such as subscribe,
+ * unsubscribe data items by their IDs.
+ * Must be implemented by OS dependent code.
+ */
+class IDataItemSubscription {
+
+public:
+ /**
+ * @brief Subscribe for data items by their IDs
+ * @details Subscribe for data items by their IDs;
+ * An IDataItemObserver implementer invokes this method to subscribe
+ * for a list of DataItems by passing in their Ids.
+ * A symbolic invocation of this method in the following order
+ * subscribe ( {1,2,3}, &obj), subscribe ( {2,3,4,5}, &obj)
+ * where the numbers enclosed in braces indicate a list of data item Ids
+ * will cause this class implementer to update its subscription list for
+ * &obj to only contain the following Data Item Ids 1,2,3,4,5.
+ *
+ * @param l List of DataItemId
+ * @param o Pointer to an instance of IDataItemObserver
+ */
+ virtual void subscribe (const std :: list <DataItemId> & l, IDataItemObserver * o = NULL) = 0;
+
+ /**
+ * @brief Update subscription for Data items
+ * @details Update subscription for Data items;
+ * An IDataItemObserver implementer invokes this method to update their
+ * subscription for a list of DataItems by passing in their Ids
+ * A symbolic invocation of this method in the following order
+ * updateSubscription ( {1,2,3}, &obj),updateSubscription ( {2,3,4,5}, &obj)
+ * where the numbers enclosed in braces indicate a list of data item Ids
+ * will cause this class implementer to update its subscription list for
+ * &obj to only contain the following Data Item Ids 2,3,4,5.
+ * Note that this method may or may not be called.
+ *
+ * @param l List of DataItemId
+ * @param o Pointer to an instance of IDataItemObserver
+ */
+ virtual void updateSubscription (const std :: list <DataItemId> & l, IDataItemObserver * o = NULL) = 0;
+
+ /**
+ * @brief Request Data
+ * @details Request Data
+ *
+ * @param l List of DataItemId
+ * @param o Pointer to an instance of IDataItemObserver
+ */
+ virtual void requestData (const std :: list <DataItemId> & l, IDataItemObserver * o = NULL) = 0;
+
+ /**
+ * @brief Unsubscribe Data items
+ * @details Unsubscrbe Data items;
+ * An IDataItemObserver implementer invokes this method to unsubscribe their
+ * subscription for a list of DataItems by passing in their Ids
+ * Suppose this class implementor has a currently active subscription list
+ * containing 1,2,3,4,5,6,7 for &obj then a symbolic invocation of this
+ * method in the following order
+ * unsubscribe ( {1,2,3}, &obj), unsubscribe ( {1,2,3,4}, &obj),
+ * unsubscribe ( {7}, &obj)
+ * where the numbers enclosed in braces indicate a list of data item Ids
+ * will cause this class implementer to update its subscription list for
+ * &obj to only contain the following data item id 5,6.
+ *
+ * @param l List of DataItemId
+ * @param o Pointer to an instance of IDataItemObserver
+ */
+ virtual void unsubscribe (const std :: list <DataItemId> & l, IDataItemObserver * o = NULL) = 0;
+
+ /**
+ * @brief Unsubscribe all data items
+ * @details Unsubscribe all data items
+ *
+ * @param o Pointer to an instance of IDataItemObserver
+ */
+ virtual void unsubscribeAll (IDataItemObserver * o = NULL) = 0;
+
+ /**
+ * @brief Destructor
+ * @details Destructor
+ */
+ virtual ~IDataItemSubscription () {}
+};
+
+} // namespace loc_core
+
+#endif // #ifndef __IDATAITEMSUBSCRIPTION_H__
+
diff --git a/core/observer/IFrameworkActionReq.h b/core/observer/IFrameworkActionReq.h
new file mode 100644
index 0000000..4be947f
--- /dev/null
+++ b/core/observer/IFrameworkActionReq.h
@@ -0,0 +1,101 @@
+/* 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 __IFRAMEWORKACTIONREQ_H__
+#define __IFRAMEWORKACTIONREQ_H__
+
+#include <DataItemId.h>
+
+namespace loc_core
+{
+
+/**
+ * @brief IFrameworkActionReq interface
+ * @details IFrameworkActionReq interface;
+ * Defines an interface for operations such as turnOn, turnOff a
+ * framework module described by the data item. Framework module
+ * could be bluetooth, wifi etc.
+ * Must be implemented by OS dependent code.
+ *
+ */
+class IFrameworkActionReq {
+
+public:
+ /**
+ * @brief Turn on the framework module described by the data item.
+ * @details Turn on the framework module described by the data item;
+ * An IFrameworkActionReq implementer invokes this method to
+ * turn on the framework module described by the data item.
+ * Framework module could be bluetooth, wifi etc.
+ *
+ * @param dit DataItemId
+ * @param timeout Timeout after which to turn off the framework module.
+ */
+ virtual void turnOn (DataItemId dit, int timeOut = 0) = 0;
+
+ /**
+ * @brief Turn off the framework module described by the data item.
+ * @details Turn off the framework module described by the data item;
+ * An IFrameworkActionReq implementer invokes this method to
+ * turn off the framework module described by the data item.
+ * Framework module could be bluetooth, wifi etc.
+ *
+ * @param dit DataItemId
+ */
+ virtual void turnOff (DataItemId dit) = 0;
+
+#ifdef USE_GLIB
+ /**
+ * @brief Setup WWAN backhaul
+ * @details Setup WWAN backhaul
+ *
+ * @param None
+ */
+ virtual bool connectBackhaul() = 0;
+
+ /**
+ * @brief Disconnects the WWANbackhaul
+ * @details Disconnects the WWANbackhaul, only if it was setup by us
+ *
+ * @param None
+ */
+ virtual bool disconnectBackhaul() = 0;
+#endif
+
+ /**
+ * @brief Destructor
+ * @details Destructor
+ */
+ virtual ~IFrameworkActionReq () {}
+};
+
+} // namespace loc_core
+
+#endif // #ifndef __IFRAMEWORKACTIONREQ_H__
+
diff --git a/core/observer/IOsObserver.h b/core/observer/IOsObserver.h
new file mode 100644
index 0000000..f661828
--- /dev/null
+++ b/core/observer/IOsObserver.h
@@ -0,0 +1,107 @@
+/* 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 __IOSOBSERVER_H__
+#define __IOSOBSERVER_H__
+
+#include <list>
+#include <string>
+#include <IDataItemObserver.h>
+#include <IDataItemSubscription.h>
+#include <IFrameworkActionReq.h>
+
+using namespace std;
+
+namespace loc_core
+{
+
+/**
+ * @brief IOsObserver interface
+ * @details IOsObserver interface;
+ * In OS dependent code this type serves as a handle to
+ * an OS independent instance of this interface.
+ */
+class IOsObserver :
+ public IDataItemObserver,
+ public IDataItemSubscription,
+ public IFrameworkActionReq {
+
+public:
+
+ // To set the subscription object
+ virtual void setSubscriptionObj(IDataItemSubscription *subscriptionObj) = 0;
+
+ // To set the framework action request object
+ virtual void setFrameworkActionReqObj(IFrameworkActionReq *frameworkActionReqObj) = 0;
+
+ // IDataItemObserver Overrides
+ inline virtual void getName (string & /*name*/) {}
+ inline virtual void notify (const std::list <IDataItemCore *> & /*dlist*/) {}
+
+ // IDataItemSubscription Overrides
+ inline virtual void subscribe
+ (
+ const std :: list <DataItemId> & /*l*/,
+ IDataItemObserver * /*client*/
+ ){}
+ inline virtual void updateSubscription
+ (
+ const std :: list <DataItemId> & /*l*/,
+ IDataItemObserver * /*client*/
+ ){}
+ inline virtual void requestData
+ (
+ const std :: list <DataItemId> & /*l*/,
+ IDataItemObserver * /*client*/
+ ){}
+ inline virtual void unsubscribe
+ (
+ const std :: list <DataItemId> & /*l*/,
+ IDataItemObserver * /*client*/
+ ){}
+ inline virtual void unsubscribeAll (IDataItemObserver * /*client*/){}
+
+ // IFrameworkActionReq Overrides
+ inline virtual void turnOn (DataItemId /*dit*/, int /*timeOut*/){}
+ inline virtual void turnOff (DataItemId /*dit*/) {}
+#ifdef USE_GLIB
+ inline virtual bool connectBackhaul() { return false; }
+ inline virtual bool disconnectBackhaul() { return false; }
+#endif
+
+ /**
+ * @brief Destructor
+ * @details Destructor
+ */
+ virtual ~IOsObserver () {}
+};
+
+} // namespace loc_core
+
+#endif // #ifndef __IOSOBSERVER_H__
diff --git a/etc/Android.mk b/etc/Android.mk
new file mode 100644
index 0000000..22ca2f7
--- /dev/null
+++ b/etc/Android.mk
@@ -0,0 +1,21 @@
+
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := gps.conf
+LOCAL_VENDOR_MODULE := true
+LOCAL_MODULE_TAGS := optional
+LOCAL_MODULE_CLASS := ETC
+LOCAL_SRC_FILES := gps.conf
+LOCAL_MODULE_PATH := $(TARGET_OUT_VENDOR_ETC)
+include $(BUILD_PREBUILT)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := flp.conf
+LOCAL_VENDOR_MODULE := true
+LOCAL_MODULE_TAGS := optional
+LOCAL_MODULE_CLASS := ETC
+LOCAL_SRC_FILES := flp.conf
+LOCAL_MODULE_PATH := $(TARGET_OUT_VENDOR_ETC)
+include $(BUILD_PREBUILT)
+
diff --git a/etc/flp.conf b/etc/flp.conf
new file mode 100644
index 0000000..65d54d3
--- /dev/null
+++ b/etc/flp.conf
@@ -0,0 +1,60 @@
+###################################
+##### FLP settings #####
+###################################
+
+###################################
+# FLP BATCH SIZE
+###################################
+# The number of batched locations
+# requested to modem. The desired number
+# defined below may not be satisfied, as
+# the modem can only return the number
+# of batched locations that can be allocated,
+# which is limited by memory. The default
+# batch size defined as 20 as below.
+BATCH_SIZE=20
+
+###################################
+# FLP OUTDOOR TRIP BATCH SIZE
+###################################
+# The number of batched locations
+# requested to modem for outdoor
+# trip batching. The desired number
+# defined below may not be satisfied, as
+# the modem can only return the number
+# of batched locations that can be allocated,
+# which is limited by memory. The default
+# trip batch size defined as 600 as below.
+OUTDOOR_TRIP_BATCH_SIZE=600
+
+###################################
+# FLP BATCHING SESSION TIMEOUT
+###################################
+# Duration with which batch session timeout
+# happens in milliseconds. If not specified
+# or set to zero, batching session timeout
+# defaults to 20 seconds by the modem.
+# BATCH_SESSION_TIMEOUT=20000
+
+###################################
+# FLP BATCHING ACCURACY
+###################################
+# Set to one of the defined values below
+# to define the accuracy of batching.
+# If not specified, accuracy defaults
+# to LOW.
+# FLP BATCHING ACCURACY values:
+# Low accuracy = 0
+# Medium accuracy = 1
+# High accuracy = 2
+ACCURACY=1
+
+####################################
+# By default if network fixes are not sensor assisted
+# these fixes must be dropped. This parameter adds an exception
+# for targets where there is no PDR and we still want to
+# report out network fixes
+# 0: MUST NOT ALLOW NETWORK FIXES
+# 1: ALLOW NETWORK FIXES
+####################################
+ALLOW_NETWORK_FIXES = 0
diff --git a/etc/gps.conf b/etc/gps.conf
new file mode 100644
index 0000000..fc37653
--- /dev/null
+++ b/etc/gps.conf
@@ -0,0 +1,299 @@
+#Version check for XTRA
+#DISABLE = 0
+#AUTO = 1
+#XTRA2 = 2
+#XTRA3 = 3
+XTRA_VERSION_CHECK=0
+
+# Error Estimate
+# _SET = 1
+# _CLEAR = 0
+ERR_ESTIMATE=0
+
+#NTP server
+NTP_SERVER=time.izatcloud.net
+
+#XTRA CA path
+XTRA_CA_PATH=/usr/lib/ssl/certs
+
+# DEBUG LEVELS: 0 - none, 1 - Error, 2 - Warning, 3 - Info
+# 4 - Debug, 5 - Verbose
+# If DEBUG_LEVEL is commented, Android's logging levels will be used
+DEBUG_LEVEL = 3
+
+# Intermediate position report, 1=enable, 0=disable
+INTERMEDIATE_POS=0
+
+# supl version 1.0
+SUPL_VER=0x10000
+
+# Emergency SUPL, 1=enable, 0=disable
+#SUPL_ES=1
+
+#Choose PDN for Emergency SUPL
+#1 - Use emergency PDN
+#0 - Use regular SUPL PDN for Emergency SUPL
+#USE_EMERGENCY_PDN_FOR_EMERGENCY_SUPL=0
+
+#SUPL_MODE is a bit mask set in config.xml per carrier by default.
+#If it is uncommented here, this value will overwrite the value from
+#config.xml.
+#MSA=0X2
+#MSB=0X1
+#SUPL_MODE=
+
+# GPS Capabilities bit mask
+# SCHEDULING = 0x01
+# MSB = 0x02
+# MSA = 0x04
+# ON_DEMAND_TIME = 0x10
+# default = ON_DEMAND_TIME | MSA | MSB | SCHEDULING
+CAPABILITIES=0x17
+
+# Accuracy threshold for intermediate positions
+# less accurate positions are ignored, 0 for passing all positions
+# ACCURACY_THRES=5000
+
+################################
+##### AGPS server settings #####
+################################
+
+# FOR SUPL SUPPORT, set the following
+# SUPL_HOST=supl.host.com or IP
+# SUPL_PORT=1234
+
+# FOR MO SUPL SUPPORT, set the following
+# MO_SUPL_HOST=supl.host.com or IP
+# MO_SUPL_PORT=1234
+
+# FOR C2K PDE SUPPORT, set the following
+# C2K_HOST=c2k.pde.com or IP
+# C2K_PORT=1234
+
+# Bitmask of slots that are available
+# for write/install to, where 1s indicate writable,
+# and the default value is 0 where no slots
+# are writable. For example, AGPS_CERT_WRITABLE_MASK
+# of b1000001010 makes 3 slots available
+# and the remaining 7 slots unwritable.
+#AGPS_CERT_WRITABLE_MASK=0
+
+####################################
+# LTE Positioning Profile Settings
+####################################
+# 0: Enable RRLP on LTE(Default)
+# 1: Enable LPP_User_Plane on LTE
+# 2: Enable LPP_Control_Plane
+# 3: Enable both LPP_User_Plane and LPP_Control_Plane
+LPP_PROFILE = 2
+
+####################################
+#Datum Type
+####################################
+# 0: WGS-84
+# 1: PZ-90
+DATUM_TYPE = 0
+
+################################
+# EXTRA SETTINGS
+################################
+# NMEA provider (1=Modem Processor, 0=Application Processor)
+NMEA_PROVIDER=0
+# Mark if it is a SGLTE target (1=SGLTE, 0=nonSGLTE)
+SGLTE_TARGET=0
+
+##################################################
+# Select Positioning Protocol on A-GLONASS system
+##################################################
+# 0x1: RRC CPlane
+# 0x2: RRLP UPlane
+# 0x4: LLP Uplane
+A_GLONASS_POS_PROTOCOL_SELECT = 0
+
+##################################################
+# Select technology for LPPe Control Plane
+##################################################
+# 0x1: DBH for LPPe CP
+# 0x2: WLAN AP Measurements for LPPe CP
+# 0x4: SRN AP measurement for CP
+# 0x8: Sensor Barometer Measurement LPPe CP
+#LPPE_CP_TECHNOLOGY = 0
+
+##################################################
+# Select technology for LPPe User Plane
+##################################################
+# 0x1: DBH for LPPe UP
+# 0x2: WLAN AP Measurements for LPPe UP
+# 0x4: SRN AP measurement for UP
+# 0x8: Sensor Barometer Measurement LPPe UP
+#LPPE_UP_TECHNOLOGY = 0
+
+##################################################
+# AGPS_CONFIG_INJECT
+##################################################
+# enable/disable injection of AGPS configurations:
+# SUPL_VER
+# SUPL_HOST
+# SUPL_PORT
+# MO_SUPL_HOST
+# MO_SUPL_PORT
+# C2K_HOST
+# C2K_PORT
+# LPP_PROFILE
+# A_GLONASS_POS_PROTOCOL_SELECT
+# 0: disable
+# 1: enable
+AGPS_CONFIG_INJECT = 1
+
+##################################################
+# GNSS settings for automotive use cases
+# Configurations in following section are
+# specific to automotive use cases, others
+# please do not change, keep the default values
+##################################################
+
+# AP Coarse Timestamp Uncertainty
+##################################################
+# default : 10
+# AP time stamp uncertainty, until GNSS receiver
+# is able to acquire better timing information
+AP_TIMESTAMP_UNCERTAINTY = 10
+
+##################################################
+# QDR engine availability status
+##################################################
+# 0 : NO QDR (default)
+# 1 : QDR enabled
+# This settings enables QDR Configuration for
+# automotive use case, if enabled then
+# DR_AP_Service needs to be enabled in izat.conf
+#EXTERNAL_DR_ENABLED = 0
+
+#####################################
+# DR_SYNC Pulse Availability
+#####################################
+# 0 : DR_SYNC pulse not available (default)
+# 1 : DR_SYNC pulse available
+# This configuration enables the driver to make use
+# of PPS events generated by DR_SYNC pulse
+# Standard Linux PPS driver needs to be enabled
+DR_SYNC_ENABLED = 0
+
+#####################################
+# PPS Device name
+#####################################
+PPS_DEVICENAME = /dev/pps0
+
+#####################################
+# Ignore PPS at Startup and after long outage
+#####################################
+IGNORE_PPS_PULSE_COUNT = 1
+
+#####################################
+# Long GNSS RF outage in seconds
+#####################################
+GNSS_OUTAGE_DURATION = 10
+
+#####################################
+# AP Clock Accuracy
+#####################################
+# Quality of APPS processor clock (in PPM).
+# Value specified is used for calculation of
+# APPS time stamp uncertainty
+AP_CLOCK_PPM = 100
+
+#####################################
+# MAX ms difference to detect missing pulse
+#####################################
+# Specifies time threshold in ms to validate any missing PPS pulses
+MISSING_PULSE_TIME_DELTA = 900
+
+#####################################
+# Propagation time uncertainty
+#####################################
+# This settings enables time uncertainty propagation
+# logic incase of missing PPS pulse
+PROPAGATION_TIME_UNCERTAINTY = 1
+
+#######################################
+# APN / IP Type Configuration
+# APN and IP Type to use for setting
+# up WWAN call.
+# Use below values for IP Type:
+# v4 = 4
+# v6 = 6
+# v4v6 = 10
+#######################################
+# INTERNET_APN = abc.xyz
+# INTERNET_IP_TYPE = 4
+# SUPL_APN = abc.xyz
+# SUPL_IP_TYPE = 4
+
+#####################################
+# Modem type
+#####################################
+# This setting configures modem type
+# (external=0 or internal=1)
+# comment out the next line to vote
+# for the first modem in the list
+MODEM_TYPE = 1
+
+##################################################
+# CONSTRAINED TIME UNCERTAINTY MODE
+##################################################
+# 0 : disabled (default)
+# 1 : enabled
+# This setting enables GPS engine to keep its time
+# uncertainty below the specified constraint
+#CONSTRAINED_TIME_UNCERTAINTY_ENABLED = 0
+
+# If constrained time uncertainty mode is enabled,
+# this setting specifies the time uncertainty
+# threshold that gps engine need to maintain.
+# In unit of milli-seconds.
+# Default is 0.0 meaning that modem default value
+# of time uncertainty threshold will be used.
+#CONSTRAINED_TIME_UNCERTAINTY_THRESHOLD = 0.0
+
+# If constrained time uncertainty mode is enabled,
+# this setting specifies the power budget that
+# gps engine is allowed to spend to maintain the time
+# uncertainty.
+# Default is 0 meaning that GPS engine is not constained
+# by power budget and can spend as much power as needed.
+# In unit of 0.1 milli watt second.
+#CONSTRAINED_TIME_UNCERTAINTY_ENERGY_BUDGET = 0
+
+##################################################
+# POSITION ASSISTED CLOCK ESTIMATOR
+##################################################
+# 0 : disabled (default)
+# 1 : enabled
+# This setting enables GPS engine to estimate clock
+# bias and drift when the signal from at least 1
+# SV is available and the UE’s position is known by
+# other position engines.
+#POSITION_ASSISTED_CLOCK_ESTIMATOR_ENABLED = 0
+
+#####################################
+# proxyAppPackageName
+#####################################
+# This is a string that is sent to the framework
+# in nfwNotifyCb callback
+PROXY_APP_PACKAGE_NAME = com.google.android.carrierlocation
+
+#####################################
+# CP_MTLR_ES
+#####################################
+# CP MTLR ES, 1=enable, 0=disable
+CP_MTLR_ES=0
+
+##################################################
+# GNSS_DEPLOYMENT
+##################################################
+# 0 : Enable QTI GNSS (default)
+# 1 : Enable QCSR SS5
+# This setting use to select between QTI GNSS
+# and QCSR SS5 hardware receiver.
+# By default QTI GNSS receiver is enabled.
+# GNSS_DEPLOYMENT = 0
diff --git a/geofence/Android.mk b/geofence/Android.mk
new file mode 100644
index 0000000..6e9e870
--- /dev/null
+++ b/geofence/Android.mk
@@ -0,0 +1,36 @@
+ifneq ($(BOARD_VENDOR_QCOM_GPS_LOC_API_HARDWARE),)
+ifneq ($(BUILD_TINY_ANDROID),true)
+
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := libgeofencing
+LOCAL_VENDOR_MODULE := true
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_SRC_FILES:= \
+ GeofenceAdapter.cpp \
+ location_geofence.cpp
+
+LOCAL_SHARED_LIBRARIES := \
+ libutils \
+ libcutils \
+ libgps.utils \
+ liblog \
+ libloc_core \
+ liblbs_core
+
+LOCAL_HEADER_LIBRARIES := \
+ libgps.utils_headers \
+ libloc_core_headers \
+ libloc_pla_headers \
+ liblocation_api_headers
+
+LOCAL_PRELINK_MODULE := false
+LOCAL_CFLAGS += $(GNSS_CFLAGS)
+include $(BUILD_SHARED_LIBRARY)
+
+endif # not BUILD_TINY_ANDROID
+endif # BOARD_VENDOR_QCOM_GPS_LOC_API_HARDWARE
+
diff --git a/geofence/GeofenceAdapter.cpp b/geofence/GeofenceAdapter.cpp
new file mode 100644
index 0000000..e299589
--- /dev/null
+++ b/geofence/GeofenceAdapter.cpp
@@ -0,0 +1,870 @@
+/* Copyright (c) 2013-2019, 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_GeofenceAdapter"
+
+#include <GeofenceAdapter.h>
+#include "loc_log.h"
+#include <log_util.h>
+#include <string>
+
+using namespace loc_core;
+
+GeofenceAdapter::GeofenceAdapter() :
+ LocAdapterBase(0,
+ LocContext::getLocContext(
+ NULL,
+ NULL,
+ LocContext::mLocationHalName,
+ false),
+ true /*isMaster*/)
+{
+ LOC_LOGD("%s]: Constructor", __func__);
+}
+
+void
+GeofenceAdapter::stopClientSessions(LocationAPI* client)
+{
+ LOC_LOGD("%s]: client %p", __func__, client);
+
+
+ for (auto it = mGeofenceIds.begin(); it != mGeofenceIds.end();) {
+ uint32_t hwId = it->second;
+ GeofenceKey key(it->first);
+ if (client == key.client) {
+ it = mGeofenceIds.erase(it);
+ mLocApi->removeGeofence(hwId, key.id,
+ new LocApiResponse(*getContext(),
+ [this, hwId] (LocationError err) {
+ if (LOCATION_ERROR_SUCCESS == err) {
+ auto it2 = mGeofences.find(hwId);
+ if (it2 != mGeofences.end()) {
+ mGeofences.erase(it2);
+ } else {
+ LOC_LOGE("%s]:geofence item to erase not found. hwId %u", __func__, hwId);
+ }
+ }
+ }));
+ continue;
+ }
+ ++it; // increment only when not erasing an iterator
+ }
+
+}
+
+void
+GeofenceAdapter::updateClientsEventMask()
+{
+ LOC_API_ADAPTER_EVENT_MASK_T mask = 0;
+ for (auto it=mClientData.begin(); it != mClientData.end(); ++it) {
+ if (it->second.geofenceBreachCb != nullptr) {
+ mask |= LOC_API_ADAPTER_BIT_BATCHED_GENFENCE_BREACH_REPORT;
+ mask |= LOC_API_ADAPTER_BIT_REPORT_GENFENCE_DWELL;
+ }
+ if (it->second.geofenceStatusCb != nullptr) {
+ mask |= LOC_API_ADAPTER_BIT_GEOFENCE_GEN_ALERT;
+ }
+ }
+ updateEvtMask(mask, LOC_REGISTRATION_MASK_SET);
+}
+
+LocationError
+GeofenceAdapter::getHwIdFromClient(LocationAPI* client, uint32_t clientId, uint32_t& hwId)
+{
+ GeofenceKey key(client, clientId);
+ auto it = mGeofenceIds.find(key);
+ if (it != mGeofenceIds.end()) {
+ hwId = it->second;
+ return LOCATION_ERROR_SUCCESS;
+ }
+ return LOCATION_ERROR_ID_UNKNOWN;
+}
+
+LocationError
+GeofenceAdapter::getGeofenceKeyFromHwId(uint32_t hwId, GeofenceKey& key)
+{
+ auto it = mGeofences.find(hwId);
+ if (it != mGeofences.end()) {
+ key = it->second.key;
+ return LOCATION_ERROR_SUCCESS;
+ }
+ return LOCATION_ERROR_ID_UNKNOWN;
+}
+
+void
+GeofenceAdapter::handleEngineUpEvent()
+{
+ struct MsgSSREvent : public LocMsg {
+ GeofenceAdapter& mAdapter;
+ inline MsgSSREvent(GeofenceAdapter& adapter) :
+ LocMsg(),
+ mAdapter(adapter) {}
+ virtual void proc() const {
+ mAdapter.setEngineCapabilitiesKnown(true);
+ mAdapter.broadcastCapabilities(mAdapter.getCapabilities());
+ mAdapter.restartGeofences();
+ for (auto msg: mAdapter.mPendingMsgs) {
+ mAdapter.sendMsg(msg);
+ }
+ mAdapter.mPendingMsgs.clear();
+ }
+ };
+
+ sendMsg(new MsgSSREvent(*this));
+}
+
+void
+GeofenceAdapter::restartGeofences()
+{
+ if (mGeofences.empty()) {
+ return;
+ }
+
+ GeofencesMap oldGeofences(mGeofences);
+ mGeofences.clear();
+ mGeofenceIds.clear();
+
+ for (auto it = oldGeofences.begin(); it != oldGeofences.end(); it++) {
+ GeofenceObject object = it->second;
+ GeofenceOption options = {sizeof(GeofenceOption),
+ object.breachMask,
+ object.responsiveness,
+ object.dwellTime};
+ GeofenceInfo info = {sizeof(GeofenceInfo),
+ object.latitude,
+ object.longitude,
+ object.radius};
+ mLocApi->addGeofence(object.key.id,
+ options,
+ info,
+ new LocApiResponseData<LocApiGeofenceData>(*getContext(),
+ [this, object, options, info] (LocationError err, LocApiGeofenceData data) {
+ if (LOCATION_ERROR_SUCCESS == err) {
+ if (true == object.paused) {
+ mLocApi->pauseGeofence(data.hwId, object.key.id,
+ new LocApiResponse(*getContext(), [] (LocationError err ) {}));
+ }
+ saveGeofenceItem(object.key.client, object.key.id, data.hwId, options, info);
+ }
+ }));
+ }
+}
+
+void
+GeofenceAdapter::reportResponse(LocationAPI* client, size_t count, LocationError* errs,
+ uint32_t* ids)
+{
+ IF_LOC_LOGD {
+ std::string idsString = "[";
+ std::string errsString = "[";
+ if (NULL != ids && NULL != errs) {
+ for (size_t i=0; i < count; ++i) {
+ idsString += std::to_string(ids[i]) + " ";
+ errsString += std::to_string(errs[i]) + " ";
+ }
+ }
+ idsString += "]";
+ errsString += "]";
+
+ LOC_LOGD("%s]: client %p ids %s errs %s",
+ __func__, client, idsString.c_str(), errsString.c_str());
+ }
+
+ auto it = mClientData.find(client);
+ if (it != mClientData.end() && it->second.collectiveResponseCb != nullptr) {
+ it->second.collectiveResponseCb(count, errs, ids);
+ } else {
+ LOC_LOGE("%s]: client %p response not found in info", __func__, client);
+ }
+}
+
+uint32_t*
+GeofenceAdapter::addGeofencesCommand(LocationAPI* client, size_t count, GeofenceOption* options,
+ GeofenceInfo* infos)
+{
+ LOC_LOGD("%s]: client %p count %zu", __func__, client, count);
+
+ struct MsgAddGeofences : public LocMsg {
+ GeofenceAdapter& mAdapter;
+ LocApiBase& mApi;
+ LocationAPI* mClient;
+ size_t mCount;
+ uint32_t* mIds;
+ GeofenceOption* mOptions;
+ GeofenceInfo* mInfos;
+ inline MsgAddGeofences(GeofenceAdapter& adapter,
+ LocApiBase& api,
+ LocationAPI* client,
+ size_t count,
+ uint32_t* ids,
+ GeofenceOption* options,
+ GeofenceInfo* infos) :
+ LocMsg(),
+ mAdapter(adapter),
+ mApi(api),
+ mClient(client),
+ mCount(count),
+ mIds(ids),
+ mOptions(options),
+ mInfos(infos) {}
+ inline virtual void proc() const {
+ LocationError* errs = new LocationError[mCount];
+ if (nullptr == errs) {
+ LOC_LOGE("%s]: new failed to allocate errs", __func__);
+ return;
+ }
+ for (size_t i=0; i < mCount; ++i) {
+ if (NULL == mIds || NULL == mOptions || NULL == mInfos) {
+ errs[i] = LOCATION_ERROR_INVALID_PARAMETER;
+ } else {
+ mApi.addToCallQueue(new LocApiResponse(*mAdapter.getContext(),
+ [&mAdapter = mAdapter, mCount = mCount, mClient = mClient,
+ mOptions = mOptions, mInfos = mInfos, mIds = mIds, &mApi = mApi,
+ errs, i] (LocationError err ) {
+ mApi.addGeofence(mIds[i], mOptions[i], mInfos[i],
+ new LocApiResponseData<LocApiGeofenceData>(*mAdapter.getContext(),
+ [&mAdapter = mAdapter, mOptions = mOptions, mClient = mClient,
+ mCount = mCount, mIds = mIds, mInfos = mInfos, errs, i]
+ (LocationError err, LocApiGeofenceData data) {
+ if (LOCATION_ERROR_SUCCESS == err) {
+ mAdapter.saveGeofenceItem(mClient,
+ mIds[i],
+ data.hwId,
+ mOptions[i],
+ mInfos[i]);
+ }
+ errs[i] = err;
+
+ // Send aggregated response on last item and cleanup
+ if (i == mCount-1) {
+ mAdapter.reportResponse(mClient, mCount, errs, mIds);
+ delete[] errs;
+ delete[] mIds;
+ delete[] mOptions;
+ delete[] mInfos;
+ }
+ }));
+ }));
+ }
+ }
+ }
+ };
+
+ if (0 == count) {
+ return NULL;
+ }
+ uint32_t* ids = new uint32_t[count];
+ if (nullptr == ids) {
+ LOC_LOGE("%s]: new failed to allocate ids", __func__);
+ return NULL;
+ }
+ if (NULL != ids) {
+ for (size_t i=0; i < count; ++i) {
+ ids[i] = generateSessionId();
+ }
+ }
+ GeofenceOption* optionsCopy;
+ if (options == NULL) {
+ optionsCopy = NULL;
+ } else {
+ optionsCopy = new GeofenceOption[count];
+ if (nullptr == optionsCopy) {
+ LOC_LOGE("%s]: new failed to allocate optionsCopy", __func__);
+ return NULL;
+ }
+ COPY_IF_NOT_NULL(optionsCopy, options, count);
+ }
+ GeofenceInfo* infosCopy;
+ if (infos == NULL) {
+ infosCopy = NULL;
+ } else {
+ infosCopy = new GeofenceInfo[count];
+ if (nullptr == infosCopy) {
+ LOC_LOGE("%s]: new failed to allocate infosCopy", __func__);
+ return NULL;
+ }
+ COPY_IF_NOT_NULL(infosCopy, infos, count);
+ }
+
+ sendMsg(new MsgAddGeofences(*this, *mLocApi, client, count, ids, optionsCopy, infosCopy));
+ return ids;
+}
+
+void
+GeofenceAdapter::removeGeofencesCommand(LocationAPI* client, size_t count, uint32_t* ids)
+{
+ LOC_LOGD("%s]: client %p count %zu", __func__, client, count);
+
+ struct MsgRemoveGeofences : public LocMsg {
+ GeofenceAdapter& mAdapter;
+ LocApiBase& mApi;
+ LocationAPI* mClient;
+ size_t mCount;
+ uint32_t* mIds;
+ inline MsgRemoveGeofences(GeofenceAdapter& adapter,
+ LocApiBase& api,
+ LocationAPI* client,
+ size_t count,
+ uint32_t* ids) :
+ LocMsg(),
+ mAdapter(adapter),
+ mApi(api),
+ mClient(client),
+ mCount(count),
+ mIds(ids) {}
+ inline virtual void proc() const {
+ LocationError* errs = new LocationError[mCount];
+ if (nullptr == errs) {
+ LOC_LOGE("%s]: new failed to allocate errs", __func__);
+ return;
+ }
+ for (size_t i=0; i < mCount; ++i) {
+ mApi.addToCallQueue(new LocApiResponse(*mAdapter.getContext(),
+ [&mAdapter = mAdapter, mCount = mCount, mClient = mClient, mIds = mIds,
+ &mApi = mApi, errs, i] (LocationError err ) {
+ uint32_t hwId = 0;
+ errs[i] = mAdapter.getHwIdFromClient(mClient, mIds[i], hwId);
+ if (LOCATION_ERROR_SUCCESS == errs[i]) {
+ mApi.removeGeofence(hwId, mIds[i],
+ new LocApiResponse(*mAdapter.getContext(),
+ [&mAdapter = mAdapter, mCount = mCount, mClient = mClient, mIds = mIds,
+ hwId, errs, i] (LocationError err ) {
+ if (LOCATION_ERROR_SUCCESS == err) {
+ mAdapter.removeGeofenceItem(hwId);
+ }
+ errs[i] = err;
+
+ // Send aggregated response on last item and cleanup
+ if (i == mCount-1) {
+ mAdapter.reportResponse(mClient, mCount, errs, mIds);
+ delete[] errs;
+ delete[] mIds;
+ }
+ }));
+ } else {
+ // Send aggregated response on last item and cleanup
+ if (i == mCount-1) {
+ mAdapter.reportResponse(mClient, mCount, errs, mIds);
+ delete[] errs;
+ delete[] mIds;
+ }
+ }
+ }));
+ }
+ }
+ };
+
+ if (0 == count) {
+ return;
+ }
+ uint32_t* idsCopy = new uint32_t[count];
+ if (nullptr == idsCopy) {
+ LOC_LOGE("%s]: new failed to allocate idsCopy", __func__);
+ return;
+ }
+ COPY_IF_NOT_NULL(idsCopy, ids, count);
+ sendMsg(new MsgRemoveGeofences(*this, *mLocApi, client, count, idsCopy));
+}
+
+void
+GeofenceAdapter::pauseGeofencesCommand(LocationAPI* client, size_t count, uint32_t* ids)
+{
+ LOC_LOGD("%s]: client %p count %zu", __func__, client, count);
+
+ struct MsgPauseGeofences : public LocMsg {
+ GeofenceAdapter& mAdapter;
+ LocApiBase& mApi;
+ LocationAPI* mClient;
+ size_t mCount;
+ uint32_t* mIds;
+ inline MsgPauseGeofences(GeofenceAdapter& adapter,
+ LocApiBase& api,
+ LocationAPI* client,
+ size_t count,
+ uint32_t* ids) :
+ LocMsg(),
+ mAdapter(adapter),
+ mApi(api),
+ mClient(client),
+ mCount(count),
+ mIds(ids) {}
+ inline virtual void proc() const {
+ LocationError* errs = new LocationError[mCount];
+ if (nullptr == errs) {
+ LOC_LOGE("%s]: new failed to allocate errs", __func__);
+ return;
+ }
+ for (size_t i=0; i < mCount; ++i) {
+ mApi.addToCallQueue(new LocApiResponse(*mAdapter.getContext(),
+ [&mAdapter = mAdapter, mCount = mCount, mClient = mClient, mIds = mIds,
+ &mApi = mApi, errs, i] (LocationError err ) {
+ uint32_t hwId = 0;
+ errs[i] = mAdapter.getHwIdFromClient(mClient, mIds[i], hwId);
+ if (LOCATION_ERROR_SUCCESS == errs[i]) {
+ mApi.pauseGeofence(hwId, mIds[i], new LocApiResponse(*mAdapter.getContext(),
+ [&mAdapter = mAdapter, mCount = mCount, mClient = mClient, mIds = mIds,
+ hwId, errs, i] (LocationError err ) {
+ if (LOCATION_ERROR_SUCCESS == err) {
+ mAdapter.pauseGeofenceItem(hwId);
+ }
+ errs[i] = err;
+
+ // Send aggregated response on last item and cleanup
+ if (i == mCount-1) {
+ mAdapter.reportResponse(mClient, mCount, errs, mIds);
+ delete[] errs;
+ delete[] mIds;
+ }
+ }));
+ } else {
+ // Send aggregated response on last item and cleanup
+ if (i == mCount-1) {
+ mAdapter.reportResponse(mClient, mCount, errs, mIds);
+ delete[] errs;
+ delete[] mIds;
+ }
+ }
+ }));
+ }
+ }
+ };
+
+ if (0 == count) {
+ return;
+ }
+ uint32_t* idsCopy = new uint32_t[count];
+ if (nullptr == idsCopy) {
+ LOC_LOGE("%s]: new failed to allocate idsCopy", __func__);
+ return;
+ }
+ COPY_IF_NOT_NULL(idsCopy, ids, count);
+ sendMsg(new MsgPauseGeofences(*this, *mLocApi, client, count, idsCopy));
+}
+
+void
+GeofenceAdapter::resumeGeofencesCommand(LocationAPI* client, size_t count, uint32_t* ids)
+{
+ LOC_LOGD("%s]: client %p count %zu", __func__, client, count);
+
+ struct MsgResumeGeofences : public LocMsg {
+ GeofenceAdapter& mAdapter;
+ LocApiBase& mApi;
+ LocationAPI* mClient;
+ size_t mCount;
+ uint32_t* mIds;
+ inline MsgResumeGeofences(GeofenceAdapter& adapter,
+ LocApiBase& api,
+ LocationAPI* client,
+ size_t count,
+ uint32_t* ids) :
+ LocMsg(),
+ mAdapter(adapter),
+ mApi(api),
+ mClient(client),
+ mCount(count),
+ mIds(ids) {}
+ inline virtual void proc() const {
+ LocationError* errs = new LocationError[mCount];
+ if (nullptr == errs) {
+ LOC_LOGE("%s]: new failed to allocate errs", __func__);
+ return;
+ }
+ for (size_t i=0; i < mCount; ++i) {
+ mApi.addToCallQueue(new LocApiResponse(*mAdapter.getContext(),
+ [&mAdapter = mAdapter, mCount = mCount, mClient = mClient, mIds = mIds,
+ &mApi = mApi, errs, i] (LocationError err ) {
+ uint32_t hwId = 0;
+ errs[i] = mAdapter.getHwIdFromClient(mClient, mIds[i], hwId);
+ if (LOCATION_ERROR_SUCCESS == errs[i]) {
+ mApi.resumeGeofence(hwId, mIds[i],
+ new LocApiResponse(*mAdapter.getContext(),
+ [&mAdapter = mAdapter, mCount = mCount, mClient = mClient, hwId,
+ errs, mIds = mIds, i] (LocationError err ) {
+ if (LOCATION_ERROR_SUCCESS == err) {
+ errs[i] = err;
+
+ mAdapter.resumeGeofenceItem(hwId);
+ // Send aggregated response on last item and cleanup
+ if (i == mCount-1) {
+ mAdapter.reportResponse(mClient, mCount, errs, mIds);
+ delete[] errs;
+ delete[] mIds;
+ }
+ }
+ }));
+ } else {
+ // Send aggregated response on last item and cleanup
+ if (i == mCount-1) {
+ mAdapter.reportResponse(mClient, mCount, errs, mIds);
+ delete[] errs;
+ delete[] mIds;
+ }
+ }
+ }));
+ }
+ }
+ };
+
+ if (0 == count) {
+ return;
+ }
+ uint32_t* idsCopy = new uint32_t[count];
+ if (nullptr == idsCopy) {
+ LOC_LOGE("%s]: new failed to allocate idsCopy", __func__);
+ return;
+ }
+ COPY_IF_NOT_NULL(idsCopy, ids, count);
+ sendMsg(new MsgResumeGeofences(*this, *mLocApi, client, count, idsCopy));
+}
+
+void
+GeofenceAdapter::modifyGeofencesCommand(LocationAPI* client, size_t count, uint32_t* ids,
+ GeofenceOption* options)
+{
+ LOC_LOGD("%s]: client %p count %zu", __func__, client, count);
+
+ struct MsgModifyGeofences : public LocMsg {
+ GeofenceAdapter& mAdapter;
+ LocApiBase& mApi;
+ LocationAPI* mClient;
+ size_t mCount;
+ uint32_t* mIds;
+ GeofenceOption* mOptions;
+ inline MsgModifyGeofences(GeofenceAdapter& adapter,
+ LocApiBase& api,
+ LocationAPI* client,
+ size_t count,
+ uint32_t* ids,
+ GeofenceOption* options) :
+ LocMsg(),
+ mAdapter(adapter),
+ mApi(api),
+ mClient(client),
+ mCount(count),
+ mIds(ids),
+ mOptions(options) {}
+ inline virtual void proc() const {
+ LocationError* errs = new LocationError[mCount];
+ if (nullptr == errs) {
+ LOC_LOGE("%s]: new failed to allocate errs", __func__);
+ return;
+ }
+ for (size_t i=0; i < mCount; ++i) {
+ if (NULL == mIds || NULL == mOptions) {
+ errs[i] = LOCATION_ERROR_INVALID_PARAMETER;
+ } else {
+ mApi.addToCallQueue(new LocApiResponse(*mAdapter.getContext(),
+ [&mAdapter = mAdapter, mCount = mCount, mClient = mClient, mIds = mIds,
+ &mApi = mApi, mOptions = mOptions, errs, i] (LocationError err ) {
+ uint32_t hwId = 0;
+ errs[i] = mAdapter.getHwIdFromClient(mClient, mIds[i], hwId);
+ if (LOCATION_ERROR_SUCCESS == errs[i]) {
+ mApi.modifyGeofence(hwId, mIds[i], mOptions[i],
+ new LocApiResponse(*mAdapter.getContext(),
+ [&mAdapter = mAdapter, mCount = mCount, mClient = mClient,
+ mIds = mIds, mOptions = mOptions, hwId, errs, i]
+ (LocationError err ) {
+ if (LOCATION_ERROR_SUCCESS == err) {
+ errs[i] = err;
+
+ mAdapter.modifyGeofenceItem(hwId, mOptions[i]);
+ }
+ // Send aggregated response on last item and cleanup
+ if (i == mCount-1) {
+ mAdapter.reportResponse(mClient, mCount, errs, mIds);
+ delete[] errs;
+ delete[] mIds;
+ delete[] mOptions;
+ }
+ }));
+ } else {
+ // Send aggregated response on last item and cleanup
+ if (i == mCount-1) {
+ mAdapter.reportResponse(mClient, mCount, errs, mIds);
+ delete[] errs;
+ delete[] mIds;
+ delete[] mOptions;
+ }
+ }
+ }));
+ }
+ }
+ }
+ };
+
+ if (0 == count) {
+ return;
+ }
+ uint32_t* idsCopy = new uint32_t[count];
+ if (nullptr == idsCopy) {
+ LOC_LOGE("%s]: new failed to allocate idsCopy", __func__);
+ return;
+ }
+ COPY_IF_NOT_NULL(idsCopy, ids, count);
+ GeofenceOption* optionsCopy;
+ if (options == NULL) {
+ optionsCopy = NULL;
+ } else {
+ optionsCopy = new GeofenceOption[count];
+ if (nullptr == optionsCopy) {
+ LOC_LOGE("%s]: new failed to allocate optionsCopy", __func__);
+ return;
+ }
+ COPY_IF_NOT_NULL(optionsCopy, options, count);
+ }
+
+ sendMsg(new MsgModifyGeofences(*this, *mLocApi, client, count, idsCopy, optionsCopy));
+}
+
+void
+GeofenceAdapter::saveGeofenceItem(LocationAPI* client, uint32_t clientId, uint32_t hwId,
+ const GeofenceOption& options, const GeofenceInfo& info)
+{
+ LOC_LOGD("%s]: hwId %u client %p clientId %u", __func__, hwId, client, clientId);
+ GeofenceKey key(client, clientId);
+ GeofenceObject object = {key,
+ options.breachTypeMask,
+ options.responsiveness,
+ options.dwellTime,
+ info.latitude,
+ info.longitude,
+ info.radius,
+ false};
+ mGeofences[hwId] = object;
+ mGeofenceIds[key] = hwId;
+ dump();
+}
+
+void
+GeofenceAdapter::removeGeofenceItem(uint32_t hwId)
+{
+ GeofenceKey key;
+ LocationError err = getGeofenceKeyFromHwId(hwId, key);
+ if (LOCATION_ERROR_SUCCESS != err) {
+ LOC_LOGE("%s]: can not find the key for hwId %u", __func__, hwId);
+ } else {
+ auto it1 = mGeofenceIds.find(key);
+ if (it1 != mGeofenceIds.end()) {
+ mGeofenceIds.erase(it1);
+
+ auto it2 = mGeofences.find(hwId);
+ if (it2 != mGeofences.end()) {
+ mGeofences.erase(it2);
+ dump();
+ } else {
+ LOC_LOGE("%s]:geofence item to erase not found. hwId %u", __func__, hwId);
+ }
+ } else {
+ LOC_LOGE("%s]: geofence item to erase not found. hwId %u", __func__, hwId);
+ }
+ }
+}
+
+void
+GeofenceAdapter::pauseGeofenceItem(uint32_t hwId)
+{
+ auto it = mGeofences.find(hwId);
+ if (it != mGeofences.end()) {
+ it->second.paused = true;
+ dump();
+ } else {
+ LOC_LOGE("%s]: geofence item to pause not found. hwId %u", __func__, hwId);
+ }
+}
+
+void
+GeofenceAdapter::resumeGeofenceItem(uint32_t hwId)
+{
+ auto it = mGeofences.find(hwId);
+ if (it != mGeofences.end()) {
+ it->second.paused = false;
+ dump();
+ } else {
+ LOC_LOGE("%s]: geofence item to resume not found. hwId %u", __func__, hwId);
+ }
+}
+
+void
+GeofenceAdapter::modifyGeofenceItem(uint32_t hwId, const GeofenceOption& options)
+{
+ auto it = mGeofences.find(hwId);
+ if (it != mGeofences.end()) {
+ it->second.breachMask = options.breachTypeMask;
+ it->second.responsiveness = options.responsiveness;
+ it->second.dwellTime = options.dwellTime;
+ dump();
+ } else {
+ LOC_LOGE("%s]: geofence item to modify not found. hwId %u", __func__, hwId);
+ }
+}
+
+
+void
+GeofenceAdapter::geofenceBreachEvent(size_t count, uint32_t* hwIds, Location& location,
+ GeofenceBreachType breachType, uint64_t timestamp)
+{
+
+ IF_LOC_LOGD {
+ std::string idsString = "[";
+ if (NULL != hwIds) {
+ for (size_t i=0; i < count; ++i) {
+ idsString += std::to_string(hwIds[i]) + " ";
+ }
+ }
+ idsString += "]";
+ LOC_LOGD("%s]: breachType %u count %zu ids %s",
+ __func__, breachType, count, idsString.c_str());
+ }
+
+ if (0 == count || NULL == hwIds)
+ return;
+
+ struct MsgGeofenceBreach : public LocMsg {
+ GeofenceAdapter& mAdapter;
+ size_t mCount;
+ uint32_t* mHwIds;
+ Location mLocation;
+ GeofenceBreachType mBreachType;
+ uint64_t mTimestamp;
+ inline MsgGeofenceBreach(GeofenceAdapter& adapter,
+ size_t count,
+ uint32_t* hwIds,
+ Location& location,
+ GeofenceBreachType breachType,
+ uint64_t timestamp) :
+ LocMsg(),
+ mAdapter(adapter),
+ mCount(count),
+ mHwIds(new uint32_t[count]),
+ mLocation(location),
+ mBreachType(breachType),
+ mTimestamp(timestamp)
+ {
+ if (nullptr == mHwIds) {
+ LOC_LOGE("%s]: new failed to allocate mHwIds", __func__);
+ return;
+ }
+ COPY_IF_NOT_NULL(mHwIds, hwIds, mCount);
+ }
+ inline virtual ~MsgGeofenceBreach() {
+ delete[] mHwIds;
+ }
+ inline virtual void proc() const {
+ mAdapter.geofenceBreach(mCount, mHwIds, mLocation, mBreachType, mTimestamp);
+ }
+ };
+
+ sendMsg(new MsgGeofenceBreach(*this, count, hwIds, location, breachType, timestamp));
+
+}
+
+void
+GeofenceAdapter::geofenceBreach(size_t count, uint32_t* hwIds, const Location& location,
+ GeofenceBreachType breachType, uint64_t timestamp)
+{
+
+ for (auto it = mClientData.begin(); it != mClientData.end(); ++it) {
+ uint32_t* clientIds = new uint32_t[count];
+ if (nullptr == clientIds) {
+ return;
+ }
+ uint32_t index = 0;
+ for (size_t i=0; i < count; ++i) {
+ GeofenceKey key;
+ LocationError err = getGeofenceKeyFromHwId(hwIds[i], key);
+ if (LOCATION_ERROR_SUCCESS == err) {
+ if (key.client == it->first) {
+ clientIds[index++] = key.id;
+ }
+ }
+ }
+ if (index > 0 && it->second.geofenceBreachCb != nullptr) {
+ GeofenceBreachNotification notify = {sizeof(GeofenceBreachNotification),
+ index,
+ clientIds,
+ location,
+ breachType,
+ timestamp};
+
+ it->second.geofenceBreachCb(notify);
+ }
+ delete[] clientIds;
+ }
+}
+
+void
+GeofenceAdapter::geofenceStatusEvent(GeofenceStatusAvailable available)
+{
+ LOC_LOGD("%s]: available %u ", __func__, available);
+
+ struct MsgGeofenceStatus : public LocMsg {
+ GeofenceAdapter& mAdapter;
+ GeofenceStatusAvailable mAvailable;
+ inline MsgGeofenceStatus(GeofenceAdapter& adapter,
+ GeofenceStatusAvailable available) :
+ LocMsg(),
+ mAdapter(adapter),
+ mAvailable(available) {}
+ inline virtual void proc() const {
+ mAdapter.geofenceStatus(mAvailable);
+ }
+ };
+
+ sendMsg(new MsgGeofenceStatus(*this, available));
+}
+
+void
+GeofenceAdapter::geofenceStatus(GeofenceStatusAvailable available)
+{
+ for (auto it = mClientData.begin(); it != mClientData.end(); ++it) {
+ if (it->second.geofenceStatusCb != nullptr) {
+ GeofenceStatusNotification notify = {sizeof(GeofenceStatusNotification),
+ available,
+ LOCATION_TECHNOLOGY_TYPE_GNSS};
+ it->second.geofenceStatusCb(notify);
+ }
+ }
+}
+
+void
+GeofenceAdapter::dump()
+{
+ IF_LOC_LOGV {
+ LOC_LOGV(
+ "HAL | hwId | mask | respon | latitude | longitude | radius | paused | Id | client");
+ for (auto it = mGeofences.begin(); it != mGeofences.end(); ++it) {
+ uint32_t hwId = it->first;
+ GeofenceObject object = it->second;
+ LOC_LOGV(" | %5u | %4u | %6u | %8.2f | %9.2f | %6.2f | %6u | %04x | %p ",
+ hwId, object.breachMask, object.responsiveness,
+ object.latitude, object.longitude, object.radius,
+ object.paused, object.key.id, object.key.client);
+ }
+ }
+}
+
diff --git a/geofence/GeofenceAdapter.h b/geofence/GeofenceAdapter.h
new file mode 100644
index 0000000..38f4823
--- /dev/null
+++ b/geofence/GeofenceAdapter.h
@@ -0,0 +1,136 @@
+/* Copyright (c) 2013-2019, 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 GEOFENCE_ADAPTER_H
+#define GEOFENCE_ADAPTER_H
+
+#include <LocAdapterBase.h>
+#include <LocContext.h>
+#include <LocationAPI.h>
+#include <map>
+
+using namespace loc_core;
+
+#define COPY_IF_NOT_NULL(dest, src, len) do { \
+ if (NULL!=dest && NULL!=src) { \
+ for (size_t i=0; i<len; ++i) { \
+ dest[i] = src[i]; \
+ } \
+ } \
+} while (0)
+
+typedef struct GeofenceKey {
+ LocationAPI* client;
+ uint32_t id;
+ inline GeofenceKey() :
+ client(NULL), id(0) {}
+ inline GeofenceKey(LocationAPI* _client, uint32_t _id) :
+ client(_client), id(_id) {}
+} GeofenceKey;
+inline bool operator <(GeofenceKey const& left, GeofenceKey const& right) {
+ return left.id < right.id || (left.id == right.id && left.client < right.client);
+}
+inline bool operator ==(GeofenceKey const& left, GeofenceKey const& right) {
+ return left.id == right.id && left.client == right.client;
+}
+inline bool operator !=(GeofenceKey const& left, GeofenceKey const& right) {
+ return left.id != right.id || left.client != right.client;
+}
+typedef struct {
+ GeofenceKey key;
+ GeofenceBreachTypeMask breachMask;
+ uint32_t responsiveness;
+ uint32_t dwellTime;
+ double latitude;
+ double longitude;
+ double radius;
+ bool paused;
+} GeofenceObject;
+typedef std::map<uint32_t, GeofenceObject> GeofencesMap; //map of hwId to GeofenceObject
+typedef std::map<GeofenceKey, uint32_t> GeofenceIdMap; //map of GeofenceKey to hwId
+
+class GeofenceAdapter : public LocAdapterBase {
+
+ /* ==== GEOFENCES ====================================================================== */
+ GeofencesMap mGeofences; //map hwId to GeofenceObject
+ GeofenceIdMap mGeofenceIds; //map of GeofenceKey to hwId
+
+protected:
+
+ /* ==== CLIENT ========================================================================= */
+ virtual void updateClientsEventMask();
+ virtual void stopClientSessions(LocationAPI* client);
+
+public:
+
+ GeofenceAdapter();
+ virtual ~GeofenceAdapter() {}
+
+ /* ==== SSR ============================================================================ */
+ /* ======== EVENTS ====(Called from QMI Thread)========================================= */
+ virtual void handleEngineUpEvent();
+ /* ======== UTILITIES ================================================================== */
+ void restartGeofences();
+
+ /* ==== GEOFENCES ====================================================================== */
+ /* ======== COMMANDS ====(Called from Client Thread)==================================== */
+ uint32_t* addGeofencesCommand(LocationAPI* client, size_t count,
+ GeofenceOption* options, GeofenceInfo* info);
+ void removeGeofencesCommand(LocationAPI* client, size_t count, uint32_t* ids);
+ void pauseGeofencesCommand(LocationAPI* client, size_t count, uint32_t* ids);
+ void resumeGeofencesCommand(LocationAPI* client, size_t count, uint32_t* ids);
+ void modifyGeofencesCommand(LocationAPI* client, size_t count, uint32_t* ids,
+ GeofenceOption* options);
+ /* ======== RESPONSES ================================================================== */
+ void reportResponse(LocationAPI* client, size_t count, LocationError* errs, uint32_t* ids);
+ /* ======== UTILITIES ================================================================== */
+ void saveGeofenceItem(LocationAPI* client,
+ uint32_t clientId,
+ uint32_t hwId,
+ const GeofenceOption& options,
+ const GeofenceInfo& info);
+ void removeGeofenceItem(uint32_t hwId);
+ void pauseGeofenceItem(uint32_t hwId);
+ void resumeGeofenceItem(uint32_t hwId);
+ void modifyGeofenceItem(uint32_t hwId, const GeofenceOption& options);
+ LocationError getHwIdFromClient(LocationAPI* client, uint32_t clientId, uint32_t& hwId);
+ LocationError getGeofenceKeyFromHwId(uint32_t hwId, GeofenceKey& key);
+ void dump();
+
+ /* ==== REPORTS ======================================================================== */
+ /* ======== EVENTS ====(Called from QMI Thread)========================================= */
+ void geofenceBreachEvent(size_t count, uint32_t* hwIds, Location& location,
+ GeofenceBreachType breachType, uint64_t timestamp);
+ void geofenceStatusEvent(GeofenceStatusAvailable available);
+ /* ======== UTILITIES ================================================================== */
+ void geofenceBreach(size_t count, uint32_t* hwIds, const Location& location,
+ GeofenceBreachType breachType, uint64_t timestamp);
+ void geofenceStatus(GeofenceStatusAvailable available);
+};
+
+#endif /* GEOFENCE_ADAPTER_H */
diff --git a/geofence/Makefile.am b/geofence/Makefile.am
new file mode 100644
index 0000000..61883ff
--- /dev/null
+++ b/geofence/Makefile.am
@@ -0,0 +1,50 @@
+AM_CFLAGS = -Wundef \
+ -Wno-trigraphs \
+ -g -O0 \
+ -fno-inline \
+ -fno-short-enums \
+ -fpic \
+ ${GPSUTILS_CFLAGS} \
+ ${LOCCORE_CFLAGS} \
+ $(LOCPLA_CFLAGS) \
+ -D__func__=__PRETTY_FUNCTION__ \
+ -std=c++1y
+
+AM_CPPFLAGS = $(AM_CFLAGS)
+
+ACLOCAL_AMFLAGS = -I m4
+
+requiredlibs = \
+ ${LOCCORE_LIBS} \
+ $(GPSUTILS_LIBS) \
+ -llog
+
+h_sources = \
+ GeofenceAdapter.h
+
+c_sources = \
+ GeofenceAdapter.cpp \
+ location_geofence.cpp
+
+libgeofencing_la_SOURCES = $(c_sources)
+if USE_GLIB
+libgeofencing_la_CFLAGS = -DUSE_GLIB @GLIB_CFLAGS@ $(AM_CFLAGS)
+libgeofencing_la_CPPFLAGS = -DUSE_GLIB @GLIB_CFLAGS@ $(AM_CFLAGS) $(AM_CPPFLAGS)
+libgeofencing_la_LDFLAGS = -lstdc++ -Wl,-z,defs @GLIB_LIBS@ $(requiredlibs) -shared -version-info 1:0:0
+libgeofencing_la_LIBDADD = $(requiredlibs) -lstdc++ @GLIB_LIBS@
+else
+libgeofencing_la_CFLAGS = $(AM_CFLAGS)
+libgeofencing_la_CPPFLAGS = $(AM_CFLAGS) $(AM_CPPFLAGS)
+libgeofencing_la_LDFLAGS = -lstdc++ -Wl,-z,defs $(requiredlibs) -shared -version-info 1:0:0
+libgeofencing_la_LIBDADD = $(requiredlibs) -lstdc++
+endif
+
+library_include_HEADERS = $(h_sources)
+
+library_includedir = $(pkgincludedir)
+
+lib_LTLIBRARIES = libgeofencing.la
+
+pkgconfigdir = $(libdir)/pkgconfig
+pkgconfig_DATA = location-geofence.pc
+EXTRA_DIST = $(pkgconfig_DATA)
diff --git a/geofence/configure.ac b/geofence/configure.ac
new file mode 100644
index 0000000..8e3cd81
--- /dev/null
+++ b/geofence/configure.ac
@@ -0,0 +1,72 @@
+AC_PREREQ(2.61)
+AC_INIT([location-geofence], 1.0.0)
+AM_INIT_AUTOMAKE([foreign])
+AC_CONFIG_SRCDIR([Makefile.am])
+AC_CONFIG_HEADERS([config.h])
+AC_CONFIG_MACRO_DIR([m4])
+
+# Check for programs
+AC_PROG_LIBTOOL
+AC_PROG_CXX
+AC_PROG_CC
+AM_PROG_CC_C_O
+AC_PROG_AWK
+AC_PROG_CPP
+AC_PROG_INSTALL
+AC_PROG_LN_S
+AC_PROG_MAKE_SET
+PKG_PROG_PKG_CONFIG
+
+# Check for libraries
+PKG_CHECK_MODULES([GPSUTILS], [gps-utils])
+AC_SUBST([GPSUTILS_CFLAGS])
+AC_SUBST([GPSUTILS_LIBS])
+
+PKG_CHECK_MODULES([LOCCORE], [loc-core])
+AC_SUBST([LOCCORE_CFLAGS])
+AC_SUBST([LOCCORE_LIBS])
+
+AS_CASE([$host],
+ [arm*], [ARM=yes],
+ [ARM=no]
+)
+
+AC_ARG_WITH([locpla_includes],
+ AC_HELP_STRING([--with-locpla-includes=@<:@dir@:>@],
+ [specify the path to locpla-includes in loc-pla_git.bb]),
+ [locpla_incdir=$withval],
+ with_locpla_includes=no)
+
+if test "x$with_locpla_includes" != "xno"; then
+ AC_SUBST(LOCPLA_CFLAGS, "-I${locpla_incdir}")
+fi
+
+AC_ARG_WITH([glib],
+ AC_HELP_STRING([--with-glib],
+ [enable glib, building HLOS systems which use glib]))
+
+if (test "x${with_glib}" = "xyes"); then
+ AC_DEFINE(ENABLE_USEGLIB, 1, [Define if HLOS systems uses glib])
+ PKG_CHECK_MODULES(GTHREAD, gthread-2.0 >= 2.16, dummy=yes,
+ AC_MSG_ERROR(GThread >= 2.16 is required))
+ PKG_CHECK_MODULES(GLIB, glib-2.0 >= 2.16, dummy=yes,
+ AC_MSG_ERROR(GLib >= 2.16 is required))
+ GLIB_CFLAGS="$GLIB_CFLAGS $GTHREAD_CFLAGS"
+ GLIB_LIBS="$GLIB_LIBS $GTHREAD_LIBS"
+
+ AC_SUBST(GLIB_CFLAGS)
+ AC_SUBST(GLIB_LIBS)
+fi
+
+AM_CONDITIONAL(USE_GLIB, test "x${with_glib}" = "xyes")
+
+AC_SUBST([CFLAGS])
+AC_SUBST([CPPFLAGS])
+AC_SUBST([LIBS])
+
+AC_CONFIG_FILES([ \
+ Makefile \
+ location-geofence.pc
+ ])
+
+AC_OUTPUT
diff --git a/geofence/location-geofence.pc.in b/geofence/location-geofence.pc.in
new file mode 100644
index 0000000..6a0781f
--- /dev/null
+++ b/geofence/location-geofence.pc.in
@@ -0,0 +1,10 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+
+Name: location-geofence
+Description: QTI GPS Geofence
+Version: @VERSION
+Libs: -L${libdir} -lgeofencing
+Cflags: -I${includedir}/location-geofence
diff --git a/geofence/location_geofence.cpp b/geofence/location_geofence.cpp
new file mode 100644
index 0000000..66729f4
--- /dev/null
+++ b/geofence/location_geofence.cpp
@@ -0,0 +1,145 @@
+/* Copyright (c) 2017-2019, 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.
+ *
+ */
+#include "GeofenceAdapter.h"
+#include "location_interface.h"
+
+static GeofenceAdapter* gGeofenceAdapter = NULL;
+
+static void initialize();
+static void deinitialize();
+
+static void addClient(LocationAPI* client, const LocationCallbacks& callbacks);
+static void removeClient(LocationAPI* client, removeClientCompleteCallback rmClientCb);
+static void requestCapabilities(LocationAPI* client);
+
+static uint32_t* addGeofences(LocationAPI* client, size_t count, GeofenceOption*, GeofenceInfo*);
+static void removeGeofences(LocationAPI* client, size_t count, uint32_t* ids);
+static void modifyGeofences(LocationAPI* client, size_t count, uint32_t* ids,
+ GeofenceOption* options);
+static void pauseGeofences(LocationAPI* client, size_t count, uint32_t* ids);
+static void resumeGeofences(LocationAPI* client, size_t count, uint32_t* ids);
+
+static const GeofenceInterface gGeofenceInterface = {
+ sizeof(GeofenceInterface),
+ initialize,
+ deinitialize,
+ addClient,
+ removeClient,
+ requestCapabilities,
+ addGeofences,
+ removeGeofences,
+ modifyGeofences,
+ pauseGeofences,
+ resumeGeofences
+};
+
+#ifndef DEBUG_X86
+extern "C" const GeofenceInterface* getGeofenceInterface()
+#else
+const GeofenceInterface* getGeofenceInterface()
+#endif // DEBUG_X86
+{
+ return &gGeofenceInterface;
+}
+
+static void initialize()
+{
+ if (NULL == gGeofenceAdapter) {
+ gGeofenceAdapter = new GeofenceAdapter();
+ }
+}
+
+static void deinitialize()
+{
+ if (NULL != gGeofenceAdapter) {
+ delete gGeofenceAdapter;
+ gGeofenceAdapter = NULL;
+ }
+}
+
+static void addClient(LocationAPI* client, const LocationCallbacks& callbacks)
+{
+ if (NULL != gGeofenceAdapter) {
+ gGeofenceAdapter->addClientCommand(client, callbacks);
+ }
+}
+
+static void removeClient(LocationAPI* client, removeClientCompleteCallback rmClientCb)
+{
+ if (NULL != gGeofenceAdapter) {
+ gGeofenceAdapter->removeClientCommand(client, rmClientCb);
+ }
+}
+
+static void requestCapabilities(LocationAPI* client)
+{
+ if (NULL != gGeofenceAdapter) {
+ gGeofenceAdapter->requestCapabilitiesCommand(client);
+ }
+}
+
+static uint32_t* addGeofences(LocationAPI* client, size_t count,
+ GeofenceOption* options, GeofenceInfo* info)
+{
+ if (NULL != gGeofenceAdapter) {
+ return gGeofenceAdapter->addGeofencesCommand(client, count, options, info);
+ } else {
+ return NULL;
+ }
+}
+
+static void removeGeofences(LocationAPI* client, size_t count, uint32_t* ids)
+{
+ if (NULL != gGeofenceAdapter) {
+ return gGeofenceAdapter->removeGeofencesCommand(client, count, ids);
+ }
+}
+
+static void modifyGeofences(LocationAPI* client, size_t count, uint32_t* ids,
+ GeofenceOption* options)
+{
+ if (NULL != gGeofenceAdapter) {
+ return gGeofenceAdapter->modifyGeofencesCommand(client, count, ids, options);
+ }
+}
+
+static void pauseGeofences(LocationAPI* client, size_t count, uint32_t* ids)
+{
+ if (NULL != gGeofenceAdapter) {
+ return gGeofenceAdapter->pauseGeofencesCommand(client, count, ids);
+ }
+}
+
+static void resumeGeofences(LocationAPI* client, size_t count, uint32_t* ids)
+{
+ if (NULL != gGeofenceAdapter) {
+ return gGeofenceAdapter->resumeGeofencesCommand(client, count, ids);
+ }
+}
+
diff --git a/gnss/Agps.cpp b/gnss/Agps.cpp
new file mode 100644
index 0000000..9255f88
--- /dev/null
+++ b/gnss/Agps.cpp
@@ -0,0 +1,675 @@
+/* Copyright (c) 2012-2019, 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_NDEBUG 0
+#define LOG_TAG "LocSvc_Agps"
+
+#include <Agps.h>
+#include <loc_pla.h>
+#include <ContextBase.h>
+#include <loc_timer.h>
+#include <inttypes.h>
+
+/* --------------------------------------------------------------------
+ * AGPS State Machine Methods
+ * -------------------------------------------------------------------*/
+void AgpsStateMachine::processAgpsEvent(AgpsEvent event){
+
+ LOC_LOGD("processAgpsEvent(): SM %p, Event %d, State %d",
+ this, event, mState);
+
+ switch (event) {
+
+ case AGPS_EVENT_SUBSCRIBE:
+ processAgpsEventSubscribe();
+ break;
+
+ case AGPS_EVENT_UNSUBSCRIBE:
+ processAgpsEventUnsubscribe();
+ break;
+
+ case AGPS_EVENT_GRANTED:
+ processAgpsEventGranted();
+ break;
+
+ case AGPS_EVENT_RELEASED:
+ processAgpsEventReleased();
+ break;
+
+ case AGPS_EVENT_DENIED:
+ processAgpsEventDenied();
+ break;
+
+ default:
+ LOC_LOGE("Invalid Loc Agps Event");
+ }
+}
+
+void AgpsStateMachine::processAgpsEventSubscribe(){
+
+ switch (mState) {
+
+ case AGPS_STATE_RELEASED:
+ /* Add subscriber to list
+ * No notifications until we get RSRC_GRANTED */
+ addSubscriber(mCurrentSubscriber);
+ requestOrReleaseDataConn(true);
+ transitionState(AGPS_STATE_PENDING);
+ break;
+
+ case AGPS_STATE_PENDING:
+ /* Already requested for data connection,
+ * do nothing until we get RSRC_GRANTED event;
+ * Just add this subscriber to the list, for notifications */
+ addSubscriber(mCurrentSubscriber);
+ break;
+
+ case AGPS_STATE_ACQUIRED:
+ /* We already have the data connection setup,
+ * Notify current subscriber with GRANTED event,
+ * And add it to the subscriber list for further notifications. */
+ notifyEventToSubscriber(AGPS_EVENT_GRANTED, mCurrentSubscriber, false);
+ addSubscriber(mCurrentSubscriber);
+ break;
+
+ case AGPS_STATE_RELEASING:
+ addSubscriber(mCurrentSubscriber);
+ break;
+
+ default:
+ LOC_LOGE("Invalid state: %d", mState);
+ }
+}
+
+void AgpsStateMachine::processAgpsEventUnsubscribe(){
+
+ switch (mState) {
+
+ case AGPS_STATE_RELEASED:
+ notifyEventToSubscriber(
+ AGPS_EVENT_UNSUBSCRIBE, mCurrentSubscriber, false);
+ break;
+
+ case AGPS_STATE_PENDING:
+ case AGPS_STATE_ACQUIRED:
+ /* If the subscriber wishes to wait for connection close,
+ * before being removed from list, move to inactive state
+ * and notify */
+ if (mCurrentSubscriber->mWaitForCloseComplete) {
+ mCurrentSubscriber->mIsInactive = true;
+ }
+ else {
+ /* Notify only current subscriber and then delete it from
+ * subscriberList */
+ notifyEventToSubscriber(
+ AGPS_EVENT_UNSUBSCRIBE, mCurrentSubscriber, true);
+ }
+
+ /* If no subscribers in list, release data connection */
+ if (mSubscriberList.empty()) {
+ transitionState(AGPS_STATE_RELEASED);
+ requestOrReleaseDataConn(false);
+ }
+ /* Some subscribers in list, but all inactive;
+ * Release data connection */
+ else if(!anyActiveSubscribers()) {
+ transitionState(AGPS_STATE_RELEASING);
+ requestOrReleaseDataConn(false);
+ }
+ break;
+
+ case AGPS_STATE_RELEASING:
+ /* If the subscriber wishes to wait for connection close,
+ * before being removed from list, move to inactive state
+ * and notify */
+ if (mCurrentSubscriber->mWaitForCloseComplete) {
+ mCurrentSubscriber->mIsInactive = true;
+ }
+ else {
+ /* Notify only current subscriber and then delete it from
+ * subscriberList */
+ notifyEventToSubscriber(
+ AGPS_EVENT_UNSUBSCRIBE, mCurrentSubscriber, true);
+ }
+
+ /* If no subscribers in list, just move the state.
+ * Request for releasing data connection should already have been
+ * sent */
+ if (mSubscriberList.empty()) {
+ transitionState(AGPS_STATE_RELEASED);
+ }
+ break;
+
+ default:
+ LOC_LOGE("Invalid state: %d", mState);
+ }
+}
+
+void AgpsStateMachine::processAgpsEventGranted(){
+
+ switch (mState) {
+
+ case AGPS_STATE_RELEASED:
+ case AGPS_STATE_ACQUIRED:
+ case AGPS_STATE_RELEASING:
+ LOC_LOGE("Unexpected event GRANTED in state %d", mState);
+ break;
+
+ case AGPS_STATE_PENDING:
+ // Move to acquired state
+ transitionState(AGPS_STATE_ACQUIRED);
+ notifyAllSubscribers(
+ AGPS_EVENT_GRANTED, false,
+ AGPS_NOTIFICATION_TYPE_FOR_ACTIVE_SUBSCRIBERS);
+ break;
+
+ default:
+ LOC_LOGE("Invalid state: %d", mState);
+ }
+}
+
+void AgpsStateMachine::processAgpsEventReleased(){
+
+ switch (mState) {
+
+ case AGPS_STATE_RELEASED:
+ /* Subscriber list should be empty if we are in released state */
+ if (!mSubscriberList.empty()) {
+ LOC_LOGE("Unexpected event RELEASED in RELEASED state");
+ }
+ break;
+
+ case AGPS_STATE_ACQUIRED:
+ /* Force release received */
+ LOC_LOGW("Force RELEASED event in ACQUIRED state");
+ transitionState(AGPS_STATE_RELEASED);
+ notifyAllSubscribers(
+ AGPS_EVENT_RELEASED, true,
+ AGPS_NOTIFICATION_TYPE_FOR_ALL_SUBSCRIBERS);
+ break;
+
+ case AGPS_STATE_RELEASING:
+ /* Notify all inactive subscribers about the event */
+ notifyAllSubscribers(
+ AGPS_EVENT_RELEASED, true,
+ AGPS_NOTIFICATION_TYPE_FOR_INACTIVE_SUBSCRIBERS);
+
+ /* If we have active subscribers now, they must be waiting for
+ * data conn setup */
+ if (anyActiveSubscribers()) {
+ transitionState(AGPS_STATE_PENDING);
+ requestOrReleaseDataConn(true);
+ }
+ /* No active subscribers, move to released state */
+ else {
+ transitionState(AGPS_STATE_RELEASED);
+ }
+ break;
+
+ case AGPS_STATE_PENDING:
+ /* NOOP */
+ break;
+
+ default:
+ LOC_LOGE("Invalid state: %d", mState);
+ }
+}
+
+void AgpsStateMachine::processAgpsEventDenied(){
+
+ switch (mState) {
+
+ case AGPS_STATE_RELEASED:
+ LOC_LOGE("Unexpected event DENIED in state %d", mState);
+ break;
+
+ case AGPS_STATE_ACQUIRED:
+ /* NOOP */
+ break;
+
+ case AGPS_STATE_RELEASING:
+ /* Notify all inactive subscribers about the event */
+ notifyAllSubscribers(
+ AGPS_EVENT_RELEASED, true,
+ AGPS_NOTIFICATION_TYPE_FOR_INACTIVE_SUBSCRIBERS);
+
+ /* If we have active subscribers now, they must be waiting for
+ * data conn setup */
+ if (anyActiveSubscribers()) {
+ transitionState(AGPS_STATE_PENDING);
+ requestOrReleaseDataConn(true);
+ }
+ /* No active subscribers, move to released state */
+ else {
+ transitionState(AGPS_STATE_RELEASED);
+ }
+ break;
+
+ case AGPS_STATE_PENDING:
+ transitionState(AGPS_STATE_RELEASED);
+ notifyAllSubscribers(
+ AGPS_EVENT_DENIED, true,
+ AGPS_NOTIFICATION_TYPE_FOR_ALL_SUBSCRIBERS);
+ break;
+
+ default:
+ LOC_LOGE("Invalid state: %d", mState);
+ }
+}
+
+/* Request or Release data connection
+ * bool request :
+ * true = Request data connection
+ * false = Release data connection */
+void AgpsStateMachine::requestOrReleaseDataConn(bool request){
+
+ AGnssExtStatusIpV4 nifRequest;
+ memset(&nifRequest, 0, sizeof(nifRequest));
+
+ nifRequest.type = mAgpsType;
+ nifRequest.apnTypeMask = mApnTypeMask;
+ if (request) {
+ LOC_LOGD("AGPS Data Conn Request mAgpsType=%d mApnTypeMask=0x%X",
+ mAgpsType, mApnTypeMask);
+ nifRequest.status = LOC_GPS_REQUEST_AGPS_DATA_CONN;
+ }
+ else{
+ LOC_LOGD("AGPS Data Conn Release mAgpsType=%d mApnTypeMask=0x%X",
+ mAgpsType, mApnTypeMask);
+ nifRequest.status = LOC_GPS_RELEASE_AGPS_DATA_CONN;
+ }
+
+ mFrameworkStatusV4Cb(nifRequest);
+}
+
+void AgpsStateMachine::notifyAllSubscribers(
+ AgpsEvent event, bool deleteSubscriberPostNotify,
+ AgpsNotificationType notificationType){
+
+ LOC_LOGD("notifyAllSubscribers(): "
+ "SM %p, Event %d Delete %d Notification Type %d",
+ this, event, deleteSubscriberPostNotify, notificationType);
+
+ std::list<AgpsSubscriber*>::const_iterator it = mSubscriberList.begin();
+ while ( it != mSubscriberList.end() ) {
+
+ AgpsSubscriber* subscriber = *it;
+
+ if (notificationType == AGPS_NOTIFICATION_TYPE_FOR_ALL_SUBSCRIBERS ||
+ (notificationType == AGPS_NOTIFICATION_TYPE_FOR_INACTIVE_SUBSCRIBERS &&
+ subscriber->mIsInactive) ||
+ (notificationType == AGPS_NOTIFICATION_TYPE_FOR_ACTIVE_SUBSCRIBERS &&
+ !subscriber->mIsInactive)) {
+
+ /* Deleting via this call would require another traversal
+ * through subscriber list, inefficient; hence pass in false*/
+ notifyEventToSubscriber(event, subscriber, false);
+
+ if (deleteSubscriberPostNotify) {
+ it = mSubscriberList.erase(it);
+ delete subscriber;
+ } else {
+ it++;
+ }
+ } else {
+ it++;
+ }
+ }
+}
+
+void AgpsStateMachine::notifyEventToSubscriber(
+ AgpsEvent event, AgpsSubscriber* subscriberToNotify,
+ bool deleteSubscriberPostNotify) {
+
+ LOC_LOGD("notifyEventToSubscriber(): "
+ "SM %p, Event %d Subscriber %p Delete %d",
+ this, event, subscriberToNotify, deleteSubscriberPostNotify);
+
+ switch (event) {
+
+ case AGPS_EVENT_GRANTED:
+ mAgpsManager->mAtlOpenStatusCb(
+ subscriberToNotify->mConnHandle, 1, getAPN(), getAPNLen(),
+ getBearer(), mAgpsType, mApnTypeMask);
+ break;
+
+ case AGPS_EVENT_DENIED:
+ mAgpsManager->mAtlOpenStatusCb(
+ subscriberToNotify->mConnHandle, 0, getAPN(), getAPNLen(),
+ getBearer(), mAgpsType, mApnTypeMask);
+ break;
+
+ case AGPS_EVENT_UNSUBSCRIBE:
+ case AGPS_EVENT_RELEASED:
+ mAgpsManager->mAtlCloseStatusCb(subscriberToNotify->mConnHandle, 1);
+ break;
+
+ default:
+ LOC_LOGE("Invalid event %d", event);
+ }
+
+ /* Search this subscriber in list and delete */
+ if (deleteSubscriberPostNotify) {
+ deleteSubscriber(subscriberToNotify);
+ }
+}
+
+void AgpsStateMachine::transitionState(AgpsState newState){
+
+ LOC_LOGD("transitionState(): SM %p, old %d, new %d",
+ this, mState, newState);
+
+ mState = newState;
+
+ // notify state transitions to all subscribers ?
+}
+
+void AgpsStateMachine::addSubscriber(AgpsSubscriber* subscriberToAdd){
+
+ LOC_LOGD("addSubscriber(): SM %p, Subscriber %p",
+ this, subscriberToAdd);
+
+ // Check if subscriber is already present in the current list
+ // If not, then add
+ std::list<AgpsSubscriber*>::const_iterator it = mSubscriberList.begin();
+ for (; it != mSubscriberList.end(); it++) {
+ AgpsSubscriber* subscriber = *it;
+ if (subscriber->equals(subscriberToAdd)) {
+ LOC_LOGE("Subscriber already in list");
+ return;
+ }
+ }
+
+ AgpsSubscriber* cloned = subscriberToAdd->clone();
+ LOC_LOGD("addSubscriber(): cloned subscriber: %p", cloned);
+ mSubscriberList.push_back(cloned);
+}
+
+void AgpsStateMachine::deleteSubscriber(AgpsSubscriber* subscriberToDelete){
+
+ LOC_LOGD("deleteSubscriber(): SM %p, Subscriber %p",
+ this, subscriberToDelete);
+
+ std::list<AgpsSubscriber*>::const_iterator it = mSubscriberList.begin();
+ while ( it != mSubscriberList.end() ) {
+
+ AgpsSubscriber* subscriber = *it;
+ if (subscriber && subscriber->equals(subscriberToDelete)) {
+
+ it = mSubscriberList.erase(it);
+ delete subscriber;
+ } else {
+ it++;
+ }
+ }
+}
+
+bool AgpsStateMachine::anyActiveSubscribers(){
+
+ std::list<AgpsSubscriber*>::const_iterator it = mSubscriberList.begin();
+ for (; it != mSubscriberList.end(); it++) {
+ AgpsSubscriber* subscriber = *it;
+ if (!subscriber->mIsInactive) {
+ return true;
+ }
+ }
+ return false;
+}
+
+void AgpsStateMachine::setAPN(char* apn, unsigned int len){
+
+ if (NULL != mAPN) {
+ delete mAPN;
+ mAPN = NULL;
+ }
+
+ if (NULL == apn || len <= 0 || len > MAX_APN_LEN || strlen(apn) != len) {
+ LOC_LOGD("Invalid apn len (%d) or null apn", len);
+ mAPN = NULL;
+ mAPNLen = 0;
+ } else {
+ mAPN = new char[len+1];
+ if (NULL != mAPN) {
+ memcpy(mAPN, apn, len);
+ mAPN[len] = '\0';
+ mAPNLen = len;
+ }
+ }
+}
+
+AgpsSubscriber* AgpsStateMachine::getSubscriber(int connHandle){
+
+ /* Go over the subscriber list */
+ std::list<AgpsSubscriber*>::const_iterator it = mSubscriberList.begin();
+ for (; it != mSubscriberList.end(); it++) {
+ AgpsSubscriber* subscriber = *it;
+ if (subscriber->mConnHandle == connHandle) {
+ return subscriber;
+ }
+ }
+
+ /* Not found, return NULL */
+ return NULL;
+}
+
+AgpsSubscriber* AgpsStateMachine::getFirstSubscriber(bool isInactive){
+
+ /* Go over the subscriber list */
+ std::list<AgpsSubscriber*>::const_iterator it = mSubscriberList.begin();
+ for (; it != mSubscriberList.end(); it++) {
+ AgpsSubscriber* subscriber = *it;
+ if(subscriber->mIsInactive == isInactive) {
+ return subscriber;
+ }
+ }
+
+ /* Not found, return NULL */
+ return NULL;
+}
+
+void AgpsStateMachine::dropAllSubscribers(){
+
+ LOC_LOGD("dropAllSubscribers(): SM %p", this);
+
+ /* Go over the subscriber list */
+ std::list<AgpsSubscriber*>::const_iterator it = mSubscriberList.begin();
+ while ( it != mSubscriberList.end() ) {
+ AgpsSubscriber* subscriber = *it;
+ it = mSubscriberList.erase(it);
+ delete subscriber;
+ }
+}
+
+/* --------------------------------------------------------------------
+ * Loc AGPS Manager Methods
+ * -------------------------------------------------------------------*/
+
+/* CREATE AGPS STATE MACHINES
+ * Must be invoked in Msg Handler context */
+void AgpsManager::createAgpsStateMachines(const AgpsCbInfo& cbInfo) {
+
+ LOC_LOGD("AgpsManager::createAgpsStateMachines");
+
+ bool agpsCapable =
+ ((loc_core::ContextBase::mGps_conf.CAPABILITIES & LOC_GPS_CAPABILITY_MSA) ||
+ (loc_core::ContextBase::mGps_conf.CAPABILITIES & LOC_GPS_CAPABILITY_MSB));
+
+ if (NULL == mInternetNif && (cbInfo.atlType & AGPS_ATL_TYPE_WWAN)) {
+ mInternetNif = new AgpsStateMachine(this, LOC_AGPS_TYPE_WWAN_ANY);
+ mInternetNif->registerFrameworkStatusCallback((AgnssStatusIpV4Cb)cbInfo.statusV4Cb);
+ LOC_LOGD("Internet NIF: %p", mInternetNif);
+ }
+ if (agpsCapable) {
+ if (NULL == mAgnssNif && (cbInfo.atlType & AGPS_ATL_TYPE_SUPL) &&
+ (cbInfo.atlType & AGPS_ATL_TYPE_SUPL_ES)) {
+ mAgnssNif = new AgpsStateMachine(this, LOC_AGPS_TYPE_SUPL);
+ mAgnssNif->registerFrameworkStatusCallback((AgnssStatusIpV4Cb)cbInfo.statusV4Cb);
+ LOC_LOGD("AGNSS NIF: %p", mAgnssNif);
+ }
+ }
+}
+
+AgpsStateMachine* AgpsManager::getAgpsStateMachine(AGpsExtType agpsType) {
+
+ LOC_LOGD("AgpsManager::getAgpsStateMachine(): agpsType %d", agpsType);
+
+ switch (agpsType) {
+
+ case LOC_AGPS_TYPE_INVALID:
+ case LOC_AGPS_TYPE_SUPL:
+ case LOC_AGPS_TYPE_SUPL_ES:
+ if (mAgnssNif == NULL) {
+ LOC_LOGE("NULL AGNSS NIF !");
+ }
+ return mAgnssNif;
+ case LOC_AGPS_TYPE_WWAN_ANY:
+ if (mInternetNif == NULL) {
+ LOC_LOGE("NULL Internet NIF !");
+ }
+ return mInternetNif;
+ default:
+ return mInternetNif;
+ }
+
+ LOC_LOGE("No SM found !");
+ return NULL;
+}
+
+void AgpsManager::requestATL(int connHandle, AGpsExtType agpsType,
+ LocApnTypeMask apnTypeMask){
+
+ LOC_LOGD("AgpsManager::requestATL(): connHandle %d, agpsType 0x%X apnTypeMask: 0x%X",
+ connHandle, agpsType, apnTypeMask);
+
+ if (0 == loc_core::ContextBase::mGps_conf.USE_EMERGENCY_PDN_FOR_EMERGENCY_SUPL &&
+ LOC_AGPS_TYPE_SUPL_ES == agpsType) {
+ agpsType = LOC_AGPS_TYPE_SUPL;
+ apnTypeMask &= ~LOC_APN_TYPE_MASK_EMERGENCY;
+ apnTypeMask |= LOC_APN_TYPE_MASK_SUPL;
+ LOC_LOGD("Changed agpsType to non-emergency when USE_EMERGENCY... is 0"
+ "and removed LOC_APN_TYPE_MASK_EMERGENCY from apnTypeMask"
+ "agpsType 0x%X apnTypeMask : 0x%X",
+ agpsType, apnTypeMask);
+ }
+ AgpsStateMachine* sm = getAgpsStateMachine(agpsType);
+
+ if (sm == NULL) {
+
+ LOC_LOGE("No AGPS State Machine for agpsType: %d apnTypeMask: 0x%X",
+ agpsType, apnTypeMask);
+ mAtlOpenStatusCb(
+ connHandle, 0, NULL, 0, AGPS_APN_BEARER_INVALID, agpsType, apnTypeMask);
+ return;
+ }
+ sm->setType(agpsType);
+ sm->setApnTypeMask(apnTypeMask);
+
+ /* Invoke AGPS SM processing */
+ AgpsSubscriber subscriber(connHandle, false, false, apnTypeMask);
+ sm->setCurrentSubscriber(&subscriber);
+ /* Send subscriber event */
+ sm->processAgpsEvent(AGPS_EVENT_SUBSCRIBE);
+}
+
+void AgpsManager::releaseATL(int connHandle){
+
+ LOC_LOGD("AgpsManager::releaseATL(): connHandle %d", connHandle);
+
+ /* First find the subscriber with specified handle.
+ * We need to search in all state machines. */
+ AgpsStateMachine* sm = NULL;
+ AgpsSubscriber* subscriber = NULL;
+
+ if (mAgnssNif &&
+ (subscriber = mAgnssNif->getSubscriber(connHandle)) != NULL) {
+ sm = mAgnssNif;
+ }
+ else if (mInternetNif &&
+ (subscriber = mInternetNif->getSubscriber(connHandle)) != NULL) {
+ sm = mInternetNif;
+ }
+ if (sm == NULL) {
+ LOC_LOGE("Subscriber with connHandle %d not found in any SM",
+ connHandle);
+ return;
+ }
+
+ /* Now send unsubscribe event */
+ sm->setCurrentSubscriber(subscriber);
+ sm->processAgpsEvent(AGPS_EVENT_UNSUBSCRIBE);
+}
+
+void AgpsManager::reportAtlOpenSuccess(
+ AGpsExtType agpsType, char* apnName, int apnLen,
+ AGpsBearerType bearerType){
+
+ LOC_LOGD("AgpsManager::reportAtlOpenSuccess(): "
+ "AgpsType %d, APN [%s], Len %d, BearerType %d",
+ agpsType, apnName, apnLen, bearerType);
+
+ /* Find the state machine instance */
+ AgpsStateMachine* sm = getAgpsStateMachine(agpsType);
+
+ /* Set bearer and apn info in state machine instance */
+ sm->setBearer(bearerType);
+ sm->setAPN(apnName, apnLen);
+
+ /* Send GRANTED event to state machine */
+ sm->processAgpsEvent(AGPS_EVENT_GRANTED);
+}
+
+void AgpsManager::reportAtlOpenFailed(AGpsExtType agpsType){
+
+ LOC_LOGD("AgpsManager::reportAtlOpenFailed(): AgpsType %d", agpsType);
+
+ /* Fetch SM and send DENIED event */
+ AgpsStateMachine* sm = getAgpsStateMachine(agpsType);
+ sm->processAgpsEvent(AGPS_EVENT_DENIED);
+}
+
+void AgpsManager::reportAtlClosed(AGpsExtType agpsType){
+
+ LOC_LOGD("AgpsManager::reportAtlClosed(): AgpsType %d", agpsType);
+
+ /* Fetch SM and send RELEASED event */
+ AgpsStateMachine* sm = getAgpsStateMachine(agpsType);
+ sm->processAgpsEvent(AGPS_EVENT_RELEASED);
+}
+
+void AgpsManager::handleModemSSR(){
+
+ LOC_LOGD("AgpsManager::handleModemSSR");
+
+ /* Drop subscribers from all state machines */
+ if (mAgnssNif) {
+ mAgnssNif->dropAllSubscribers();
+ }
+ if (mInternetNif) {
+ mInternetNif->dropAllSubscribers();
+ }
+}
diff --git a/gnss/Agps.h b/gnss/Agps.h
new file mode 100644
index 0000000..d559377
--- /dev/null
+++ b/gnss/Agps.h
@@ -0,0 +1,316 @@
+/* Copyright (c) 2012-2018, 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 AGPS_H
+#define AGPS_H
+
+#include <functional>
+#include <list>
+#include <MsgTask.h>
+#include <gps_extended_c.h>
+#include <loc_pla.h>
+#include <log_util.h>
+
+/* ATL callback function pointers
+ * Passed in by Adapter to AgpsManager */
+typedef std::function<void(
+ int handle, int isSuccess, char* apn, uint32_t apnLen,
+ AGpsBearerType bearerType, AGpsExtType agpsType,
+ LocApnTypeMask mask)> AgpsAtlOpenStatusCb;
+
+typedef std::function<void(int handle, int isSuccess)> AgpsAtlCloseStatusCb;
+
+/* Post message to adapter's message queue */
+typedef std::function<void(LocMsg* msg)> SendMsgToAdapterMsgQueueFn;
+
+/* AGPS States */
+typedef enum {
+ AGPS_STATE_INVALID = 0,
+ AGPS_STATE_RELEASED,
+ AGPS_STATE_PENDING,
+ AGPS_STATE_ACQUIRED,
+ AGPS_STATE_RELEASING
+} AgpsState;
+
+typedef enum {
+ AGPS_EVENT_INVALID = 0,
+ AGPS_EVENT_SUBSCRIBE,
+ AGPS_EVENT_UNSUBSCRIBE,
+ AGPS_EVENT_GRANTED,
+ AGPS_EVENT_RELEASED,
+ AGPS_EVENT_DENIED
+} AgpsEvent;
+
+/* Notification Types sent to subscribers */
+typedef enum {
+ AGPS_NOTIFICATION_TYPE_INVALID = 0,
+
+ /* Meant for all subscribers, either active or inactive */
+ AGPS_NOTIFICATION_TYPE_FOR_ALL_SUBSCRIBERS,
+
+ /* Meant for only inactive subscribers */
+ AGPS_NOTIFICATION_TYPE_FOR_INACTIVE_SUBSCRIBERS,
+
+ /* Meant for only active subscribers */
+ AGPS_NOTIFICATION_TYPE_FOR_ACTIVE_SUBSCRIBERS
+} AgpsNotificationType;
+
+/* Classes in this header */
+class AgpsSubscriber;
+class AgpsManager;
+class AgpsStateMachine;
+
+/* SUBSCRIBER
+ * Each Subscriber instance corresponds to one AGPS request,
+ * received by the AGPS state machine */
+class AgpsSubscriber {
+
+public:
+ int mConnHandle;
+
+ /* Does this subscriber wait for data call close complete,
+ * before being notified ATL close ?
+ * While waiting for data call close, subscriber will be in
+ * inactive state. */
+ bool mWaitForCloseComplete;
+ bool mIsInactive;
+ LocApnTypeMask mApnTypeMask;
+
+ inline AgpsSubscriber(
+ int connHandle, bool waitForCloseComplete, bool isInactive,
+ LocApnTypeMask apnTypeMask) :
+ mConnHandle(connHandle),
+ mWaitForCloseComplete(waitForCloseComplete),
+ mIsInactive(isInactive),
+ mApnTypeMask(apnTypeMask) {}
+ inline virtual ~AgpsSubscriber() {}
+
+ inline virtual bool equals(const AgpsSubscriber *s) const
+ { return (mConnHandle == s->mConnHandle); }
+
+ inline virtual AgpsSubscriber* clone()
+ { return new AgpsSubscriber(
+ mConnHandle, mWaitForCloseComplete, mIsInactive, mApnTypeMask); }
+};
+
+/* AGPS STATE MACHINE */
+class AgpsStateMachine {
+protected:
+ /* AGPS Manager instance, from where this state machine is created */
+ AgpsManager* mAgpsManager;
+
+ /* List of all subscribers for this State Machine.
+ * Once a subscriber is notified for ATL open/close status,
+ * it is deleted */
+ std::list<AgpsSubscriber*> mSubscriberList;
+
+ /* Current subscriber, whose request this State Machine is
+ * currently processing */
+ AgpsSubscriber* mCurrentSubscriber;
+
+ /* Current state for this state machine */
+ AgpsState mState;
+
+ AgnssStatusIpV4Cb mFrameworkStatusV4Cb;
+private:
+ /* AGPS Type for this state machine
+ LOC_AGPS_TYPE_ANY 0
+ LOC_AGPS_TYPE_SUPL 1
+ LOC_AGPS_TYPE_WWAN_ANY 3
+ LOC_AGPS_TYPE_SUPL_ES 5 */
+ AGpsExtType mAgpsType;
+ LocApnTypeMask mApnTypeMask;
+
+ /* APN and IP Type info for AGPS Call */
+ char* mAPN;
+ unsigned int mAPNLen;
+ AGpsBearerType mBearer;
+
+public:
+ /* CONSTRUCTOR */
+ AgpsStateMachine(AgpsManager* agpsManager, AGpsExtType agpsType):
+ mFrameworkStatusV4Cb(NULL),
+ mAgpsManager(agpsManager), mSubscriberList(),
+ mCurrentSubscriber(NULL), mState(AGPS_STATE_RELEASED),
+ mAgpsType(agpsType), mAPN(NULL), mAPNLen(0),
+ mBearer(AGPS_APN_BEARER_INVALID) {};
+
+ virtual ~AgpsStateMachine() { if(NULL != mAPN) delete[] mAPN; };
+
+ /* Getter/Setter methods */
+ void setAPN(char* apn, unsigned int len);
+ inline char* getAPN() const { return (char*)mAPN; }
+ inline uint32_t getAPNLen() const { return mAPNLen; }
+ inline void setBearer(AGpsBearerType bearer) { mBearer = bearer; }
+ inline LocApnTypeMask getApnTypeMask() const { return mApnTypeMask; }
+ inline void setApnTypeMask(LocApnTypeMask apnTypeMask)
+ { mApnTypeMask = apnTypeMask; }
+ inline AGpsBearerType getBearer() const { return mBearer; }
+ inline void setType(AGpsExtType type) { mAgpsType = type; }
+ inline AGpsExtType getType() const { return mAgpsType; }
+ inline void setCurrentSubscriber(AgpsSubscriber* subscriber)
+ { mCurrentSubscriber = subscriber; }
+
+ inline void registerFrameworkStatusCallback(AgnssStatusIpV4Cb frameworkStatusV4Cb) {
+ mFrameworkStatusV4Cb = frameworkStatusV4Cb;
+ }
+
+ /* Fetch subscriber with specified handle */
+ AgpsSubscriber* getSubscriber(int connHandle);
+
+ /* Fetch first active or inactive subscriber in list
+ * isInactive = true : fetch first inactive subscriber
+ * isInactive = false : fetch first active subscriber */
+ AgpsSubscriber* getFirstSubscriber(bool isInactive);
+
+ /* Process LOC AGPS Event being passed in
+ * onRsrcEvent */
+ virtual void processAgpsEvent(AgpsEvent event);
+
+ /* Drop all subscribers, in case of Modem SSR */
+ void dropAllSubscribers();
+
+protected:
+ /* Remove the specified subscriber from list if present.
+ * Also delete the subscriber instance. */
+ void deleteSubscriber(AgpsSubscriber* subscriber);
+
+private:
+ /* Send call setup request to framework
+ * sendRsrcRequest(LOC_GPS_REQUEST_AGPS_DATA_CONN)
+ * sendRsrcRequest(LOC_GPS_RELEASE_AGPS_DATA_CONN) */
+ void requestOrReleaseDataConn(bool request);
+
+ /* Individual event processing methods */
+ void processAgpsEventSubscribe();
+ void processAgpsEventUnsubscribe();
+ void processAgpsEventGranted();
+ void processAgpsEventReleased();
+ void processAgpsEventDenied();
+
+ /* Clone the passed in subscriber and add to the subscriber list
+ * if not already present */
+ void addSubscriber(AgpsSubscriber* subscriber);
+
+ /* Notify subscribers about AGPS events */
+ void notifyAllSubscribers(
+ AgpsEvent event, bool deleteSubscriberPostNotify,
+ AgpsNotificationType notificationType);
+ virtual void notifyEventToSubscriber(
+ AgpsEvent event, AgpsSubscriber* subscriber,
+ bool deleteSubscriberPostNotify);
+
+ /* Do we have any subscribers in active state */
+ bool anyActiveSubscribers();
+
+ /* Transition state */
+ void transitionState(AgpsState newState);
+};
+
+/* LOC AGPS MANAGER */
+class AgpsManager {
+
+ friend class AgpsStateMachine;
+public:
+ /* CONSTRUCTOR */
+ AgpsManager():
+ mAtlOpenStatusCb(), mAtlCloseStatusCb(),
+ mAgnssNif(NULL), mInternetNif(NULL)/*, mDsNif(NULL)*/ {}
+
+ /* Register callbacks */
+ inline void registerATLCallbacks(AgpsAtlOpenStatusCb atlOpenStatusCb,
+ AgpsAtlCloseStatusCb atlCloseStatusCb) {
+
+ mAtlOpenStatusCb = atlOpenStatusCb;
+ mAtlCloseStatusCb = atlCloseStatusCb;
+ }
+
+ /* Check if AGPS client is registered */
+ inline bool isRegistered() { return nullptr != mAgnssNif || nullptr != mInternetNif; }
+
+ /* Create all AGPS state machines */
+ void createAgpsStateMachines(const AgpsCbInfo& cbInfo);
+
+ /* Process incoming ATL requests */
+ void requestATL(int connHandle, AGpsExtType agpsType, LocApnTypeMask apnTypeMask);
+ void releaseATL(int connHandle);
+ /* Process incoming framework data call events */
+ void reportAtlOpenSuccess(AGpsExtType agpsType, char* apnName, int apnLen,
+ AGpsBearerType bearerType);
+ void reportAtlOpenFailed(AGpsExtType agpsType);
+ void reportAtlClosed(AGpsExtType agpsType);
+
+ /* Handle Modem SSR */
+ void handleModemSSR();
+
+protected:
+
+ AgpsAtlOpenStatusCb mAtlOpenStatusCb;
+ AgpsAtlCloseStatusCb mAtlCloseStatusCb;
+ AgpsStateMachine* mAgnssNif;
+ AgpsStateMachine* mInternetNif;
+private:
+ /* Fetch state machine for handling request ATL call */
+ AgpsStateMachine* getAgpsStateMachine(AGpsExtType agpsType);
+};
+
+/* Request SUPL/INTERNET/SUPL_ES ATL
+ * This LocMsg is defined in this header since it has to be used from more
+ * than one place, other Agps LocMsg are restricted to GnssAdapter and
+ * declared inline */
+struct AgpsMsgRequestATL: public LocMsg {
+
+ AgpsManager* mAgpsManager;
+ int mConnHandle;
+ AGpsExtType mAgpsType;
+ LocApnTypeMask mApnTypeMask;
+
+ inline AgpsMsgRequestATL(AgpsManager* agpsManager, int connHandle,
+ AGpsExtType agpsType, LocApnTypeMask apnTypeMask) :
+ LocMsg(), mAgpsManager(agpsManager), mConnHandle(connHandle),
+ mAgpsType(agpsType), mApnTypeMask(apnTypeMask){
+
+ LOC_LOGV("AgpsMsgRequestATL");
+ }
+
+ inline virtual void proc() const {
+
+ LOC_LOGV("AgpsMsgRequestATL::proc()");
+ mAgpsManager->requestATL(mConnHandle, mAgpsType, mApnTypeMask);
+ }
+};
+
+namespace AgpsUtils {
+
+AGpsBearerType ipTypeToBearerType(LocApnIpType ipType);
+LocApnIpType bearerTypeToIpType(AGpsBearerType bearerType);
+
+}
+
+#endif /* AGPS_H */
diff --git a/gnss/Android.mk b/gnss/Android.mk
new file mode 100644
index 0000000..d809bc2
--- /dev/null
+++ b/gnss/Android.mk
@@ -0,0 +1,46 @@
+ifneq ($(BOARD_VENDOR_QCOM_GPS_LOC_API_HARDWARE),)
+ifneq ($(BUILD_TINY_ANDROID),true)
+
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := libgnss
+LOCAL_VENDOR_MODULE := true
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_SHARED_LIBRARIES := \
+ libutils \
+ libcutils \
+ libdl \
+ liblog \
+ libloc_core \
+ libgps.utils
+
+LOCAL_SRC_FILES += \
+ location_gnss.cpp \
+ GnssAdapter.cpp \
+ Agps.cpp \
+ XtraSystemStatusObserver.cpp
+
+LOCAL_CFLAGS += \
+ -fno-short-enums \
+
+ifeq ($(TARGET_BUILD_VARIANT),user)
+ LOCAL_CFLAGS += -DTARGET_BUILD_VARIANT_USER
+endif
+
+LOCAL_HEADER_LIBRARIES := \
+ libgps.utils_headers \
+ libloc_core_headers \
+ libloc_pla_headers \
+ liblocation_api_headers
+
+LOCAL_CFLAGS += $(GNSS_CFLAGS)
+
+LOCAL_PRELINK_MODULE := false
+
+include $(BUILD_SHARED_LIBRARY)
+
+endif # not BUILD_TINY_ANDROID
+endif # BOARD_VENDOR_QCOM_GPS_LOC_API_HARDWARE
diff --git a/gnss/GnssAdapter.cpp b/gnss/GnssAdapter.cpp
new file mode 100644
index 0000000..c2e4a09
--- /dev/null
+++ b/gnss/GnssAdapter.cpp
@@ -0,0 +1,5046 @@
+/* Copyright (c) 2017-2019, 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_NDEBUG 0
+#define LOG_TAG "LocSvc_GnssAdapter"
+
+#include <inttypes.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <ctype.h>
+#include <cutils/properties.h>
+#include <math.h>
+#include <arpa/inet.h>
+#include <netinet/in.h>
+#include <netdb.h>
+#include <GnssAdapter.h>
+#include <string>
+#include <sstream>
+#include <loc_log.h>
+#include <loc_nmea.h>
+#include <Agps.h>
+#include <SystemStatus.h>
+
+#include <vector>
+
+#define RAD2DEG (180.0 / M_PI)
+#define PROCESS_NAME_ENGINE_SERVICE "engine-service"
+#define MIN_TRACKING_INTERVAL (100) // 100 msec
+
+using namespace loc_core;
+
+/* Method to fetch status cb from loc_net_iface library */
+typedef AgpsCbInfo& (*LocAgpsGetAgpsCbInfo)(LocAgpsOpenResultCb openResultCb,
+ LocAgpsCloseResultCb closeResultCb, void* userDataPtr);
+
+static void agpsOpenResultCb (bool isSuccess, AGpsExtType agpsType, const char* apn,
+ AGpsBearerType bearerType, void* userDataPtr);
+static void agpsCloseResultCb (bool isSuccess, AGpsExtType agpsType, void* userDataPtr);
+
+GnssAdapter::GnssAdapter() :
+ LocAdapterBase(0,
+ LocContext::getLocContext(NULL,
+ NULL,
+ LocContext::mLocationHalName,
+ false), true, nullptr),
+ mEngHubProxy(new EngineHubProxyBase()),
+ mLocPositionMode(),
+ mGnssSvIdUsedInPosition(),
+ mGnssSvIdUsedInPosAvail(false),
+ mControlCallbacks(),
+ mAfwControlId(0),
+ mNmeaMask(0),
+ mGnssSvIdConfig(),
+ mGnssSvTypeConfig(),
+ mGnssSvTypeConfigCb(nullptr),
+ mNiData(),
+ mAgpsManager(),
+ mOdcpiRequestCb(nullptr),
+ mOdcpiRequestActive(false),
+ mOdcpiTimer(this),
+ mOdcpiRequest(),
+ mSystemStatus(SystemStatus::getInstance(mMsgTask)),
+ mServerUrl(":"),
+ mXtraObserver(mSystemStatus->getOsObserver(), mMsgTask),
+ mLocSystemInfo{},
+ mBlockCPIInfo{},
+ mNfwCb(NULL),
+ mPowerOn(false),
+ mAllowFlpNetworkFixes(0),
+ mGnssEnergyConsumedCb(nullptr),
+ mPowerStateCb(nullptr),
+ mIsE911Session(NULL),
+ mGnssMbSvIdUsedInPosition{},
+ mGnssMbSvIdUsedInPosAvail(false),
+ mSupportNfwControl(true)
+{
+ LOC_LOGD("%s]: Constructor %p", __func__, this);
+ mLocPositionMode.mode = LOC_POSITION_MODE_INVALID;
+
+ pthread_condattr_t condAttr;
+ pthread_condattr_init(&condAttr);
+ pthread_condattr_setclock(&condAttr, CLOCK_MONOTONIC);
+ pthread_cond_init(&mNiData.session.tCond, &condAttr);
+ pthread_cond_init(&mNiData.sessionEs.tCond, &condAttr);
+ pthread_condattr_destroy(&condAttr);
+
+ /* Set ATL open/close callbacks */
+ AgpsAtlOpenStatusCb atlOpenStatusCb =
+ [this](int handle, int isSuccess, char* apn, uint32_t apnLen,
+ AGpsBearerType bearerType, AGpsExtType agpsType, LocApnTypeMask mask) {
+
+ mLocApi->atlOpenStatus(
+ handle, isSuccess, apn, apnLen, bearerType, agpsType, mask);
+ };
+ AgpsAtlCloseStatusCb atlCloseStatusCb =
+ [this](int handle, int isSuccess) {
+
+ mLocApi->atlCloseStatus(handle, isSuccess);
+ };
+ mAgpsManager.registerATLCallbacks(atlOpenStatusCb, atlCloseStatusCb);
+
+ readConfigCommand();
+ initDefaultAgpsCommand();
+ initEngHubProxyCommand();
+}
+
+void
+GnssAdapter::setControlCallbacksCommand(LocationControlCallbacks& controlCallbacks)
+{
+ struct MsgSetControlCallbacks : public LocMsg {
+ GnssAdapter& mAdapter;
+ const LocationControlCallbacks mControlCallbacks;
+ inline MsgSetControlCallbacks(GnssAdapter& adapter,
+ LocationControlCallbacks& controlCallbacks) :
+ LocMsg(),
+ mAdapter(adapter),
+ mControlCallbacks(controlCallbacks) {}
+ inline virtual void proc() const {
+ mAdapter.setControlCallbacks(mControlCallbacks);
+ }
+ };
+
+ sendMsg(new MsgSetControlCallbacks(*this, controlCallbacks));
+}
+
+void
+GnssAdapter::convertOptions(LocPosMode& out, const TrackingOptions& trackingOptions)
+{
+ switch (trackingOptions.mode) {
+ case GNSS_SUPL_MODE_MSB:
+ out.mode = LOC_POSITION_MODE_MS_BASED;
+ break;
+ case GNSS_SUPL_MODE_MSA:
+ out.mode = LOC_POSITION_MODE_MS_ASSISTED;
+ break;
+ default:
+ out.mode = LOC_POSITION_MODE_STANDALONE;
+ break;
+ }
+ out.share_position = true;
+ out.min_interval = trackingOptions.minInterval;
+ out.powerMode = trackingOptions.powerMode;
+ out.timeBetweenMeasurements = trackingOptions.tbm;
+}
+
+void
+GnssAdapter::convertLocation(Location& out, const UlpLocation& ulpLocation,
+ const GpsLocationExtended& locationExtended,
+ const LocPosTechMask techMask)
+{
+ memset(&out, 0, sizeof(Location));
+ out.size = sizeof(Location);
+ if (LOC_GPS_LOCATION_HAS_LAT_LONG & ulpLocation.gpsLocation.flags) {
+ out.flags |= LOCATION_HAS_LAT_LONG_BIT;
+ out.latitude = ulpLocation.gpsLocation.latitude;
+ out.longitude = ulpLocation.gpsLocation.longitude;
+ }
+ if (LOC_GPS_LOCATION_HAS_ALTITUDE & ulpLocation.gpsLocation.flags) {
+ out.flags |= LOCATION_HAS_ALTITUDE_BIT;
+ out.altitude = ulpLocation.gpsLocation.altitude;
+ }
+ if (LOC_GPS_LOCATION_HAS_SPEED & ulpLocation.gpsLocation.flags) {
+ out.flags |= LOCATION_HAS_SPEED_BIT;
+ out.speed = ulpLocation.gpsLocation.speed;
+ }
+ if (LOC_GPS_LOCATION_HAS_BEARING & ulpLocation.gpsLocation.flags) {
+ out.flags |= LOCATION_HAS_BEARING_BIT;
+ out.bearing = ulpLocation.gpsLocation.bearing;
+ }
+ if (LOC_GPS_LOCATION_HAS_ACCURACY & ulpLocation.gpsLocation.flags) {
+ out.flags |= LOCATION_HAS_ACCURACY_BIT;
+ out.accuracy = ulpLocation.gpsLocation.accuracy;
+ }
+ if (GPS_LOCATION_EXTENDED_HAS_VERT_UNC & locationExtended.flags) {
+ out.flags |= LOCATION_HAS_VERTICAL_ACCURACY_BIT;
+ out.verticalAccuracy = locationExtended.vert_unc;
+ }
+ if (GPS_LOCATION_EXTENDED_HAS_SPEED_UNC & locationExtended.flags) {
+ out.flags |= LOCATION_HAS_SPEED_ACCURACY_BIT;
+ out.speedAccuracy = locationExtended.speed_unc;
+ }
+ if (GPS_LOCATION_EXTENDED_HAS_BEARING_UNC & locationExtended.flags) {
+ out.flags |= LOCATION_HAS_BEARING_ACCURACY_BIT;
+ out.bearingAccuracy = locationExtended.bearing_unc;
+ }
+ out.timestamp = ulpLocation.gpsLocation.timestamp;
+ if (LOC_POS_TECH_MASK_SATELLITE & techMask) {
+ out.techMask |= LOCATION_TECHNOLOGY_GNSS_BIT;
+ }
+ if (LOC_POS_TECH_MASK_CELLID & techMask) {
+ out.techMask |= LOCATION_TECHNOLOGY_CELL_BIT;
+ }
+ if (LOC_POS_TECH_MASK_WIFI & techMask) {
+ out.techMask |= LOCATION_TECHNOLOGY_WIFI_BIT;
+ }
+ if (LOC_POS_TECH_MASK_SENSORS & techMask) {
+ out.techMask |= LOCATION_TECHNOLOGY_SENSORS_BIT;
+ }
+
+ if (LOC_GPS_LOCATION_HAS_SPOOF_MASK & ulpLocation.gpsLocation.flags) {
+ out.flags |= LOCATION_HAS_SPOOF_MASK;
+ out.spoofMask = ulpLocation.gpsLocation.spoof_mask;
+ }
+}
+
+/* This is utility routine that computes number of SV used
+ in the fix from the svUsedIdsMask.
+ */
+#define MAX_SV_CNT_SUPPORTED_IN_ONE_CONSTELLATION 64
+uint16_t GnssAdapter::getNumSvUsed(uint64_t svUsedIdsMask,
+ int totalSvCntInThisConstellation)
+{
+ if (totalSvCntInThisConstellation > MAX_SV_CNT_SUPPORTED_IN_ONE_CONSTELLATION) {
+ LOC_LOGe ("error: total SV count in this constellation %d exceeded limit of %d",
+ totalSvCntInThisConstellation, MAX_SV_CNT_SUPPORTED_IN_ONE_CONSTELLATION);
+ return 0;
+ }
+
+ uint16_t numSvUsed = 0;
+ uint64_t mask = 0x1;
+ for (int i = 0; i < totalSvCntInThisConstellation; i++) {
+ if (svUsedIdsMask & mask) {
+ numSvUsed++;
+ }
+ mask <<= 1;
+ }
+
+ return numSvUsed;
+}
+
+void
+GnssAdapter::convertLocationInfo(GnssLocationInfoNotification& out,
+ const GpsLocationExtended& locationExtended)
+{
+ out.size = sizeof(GnssLocationInfoNotification);
+ if (GPS_LOCATION_EXTENDED_HAS_ALTITUDE_MEAN_SEA_LEVEL & locationExtended.flags) {
+ out.flags |= GNSS_LOCATION_INFO_ALTITUDE_MEAN_SEA_LEVEL_BIT;
+ out.altitudeMeanSeaLevel = locationExtended.altitudeMeanSeaLevel;
+ }
+ if (GPS_LOCATION_EXTENDED_HAS_EXT_DOP & locationExtended.flags) {
+ out.flags |= (GNSS_LOCATION_INFO_DOP_BIT|GNSS_LOCATION_INFO_EXT_DOP_BIT);
+ out.pdop = locationExtended.extDOP.PDOP;
+ out.hdop = locationExtended.extDOP.HDOP;
+ out.vdop = locationExtended.extDOP.VDOP;
+ out.gdop = locationExtended.extDOP.GDOP;
+ out.tdop = locationExtended.extDOP.TDOP;
+ } else if (GPS_LOCATION_EXTENDED_HAS_DOP & locationExtended.flags) {
+ out.flags |= GNSS_LOCATION_INFO_DOP_BIT;
+ out.pdop = locationExtended.pdop;
+ out.hdop = locationExtended.hdop;
+ out.vdop = locationExtended.vdop;
+ }
+ if (GPS_LOCATION_EXTENDED_HAS_MAG_DEV & locationExtended.flags) {
+ out.flags |= GNSS_LOCATION_INFO_MAGNETIC_DEVIATION_BIT;
+ out.magneticDeviation = locationExtended.magneticDeviation;
+ }
+ if (GPS_LOCATION_EXTENDED_HAS_HOR_RELIABILITY & locationExtended.flags) {
+ out.flags |= GNSS_LOCATION_INFO_HOR_RELIABILITY_BIT;
+ switch (locationExtended.horizontal_reliability) {
+ case LOC_RELIABILITY_VERY_LOW:
+ out.horReliability = LOCATION_RELIABILITY_VERY_LOW;
+ break;
+ case LOC_RELIABILITY_LOW:
+ out.horReliability = LOCATION_RELIABILITY_LOW;
+ break;
+ case LOC_RELIABILITY_MEDIUM:
+ out.horReliability = LOCATION_RELIABILITY_MEDIUM;
+ break;
+ case LOC_RELIABILITY_HIGH:
+ out.horReliability = LOCATION_RELIABILITY_HIGH;
+ break;
+ default:
+ out.horReliability = LOCATION_RELIABILITY_NOT_SET;
+ break;
+ }
+ }
+ if (GPS_LOCATION_EXTENDED_HAS_VERT_RELIABILITY & locationExtended.flags) {
+ out.flags |= GNSS_LOCATION_INFO_VER_RELIABILITY_BIT;
+ switch (locationExtended.vertical_reliability) {
+ case LOC_RELIABILITY_VERY_LOW:
+ out.verReliability = LOCATION_RELIABILITY_VERY_LOW;
+ break;
+ case LOC_RELIABILITY_LOW:
+ out.verReliability = LOCATION_RELIABILITY_LOW;
+ break;
+ case LOC_RELIABILITY_MEDIUM:
+ out.verReliability = LOCATION_RELIABILITY_MEDIUM;
+ break;
+ case LOC_RELIABILITY_HIGH:
+ out.verReliability = LOCATION_RELIABILITY_HIGH;
+ break;
+ default:
+ out.verReliability = LOCATION_RELIABILITY_NOT_SET;
+ break;
+ }
+ }
+ if (GPS_LOCATION_EXTENDED_HAS_HOR_ELIP_UNC_MAJOR & locationExtended.flags) {
+ out.flags |= GNSS_LOCATION_INFO_HOR_ACCURACY_ELIP_SEMI_MAJOR_BIT;
+ out.horUncEllipseSemiMajor = locationExtended.horUncEllipseSemiMajor;
+ }
+ if (GPS_LOCATION_EXTENDED_HAS_HOR_ELIP_UNC_MINOR & locationExtended.flags) {
+ out.flags |= GNSS_LOCATION_INFO_HOR_ACCURACY_ELIP_SEMI_MINOR_BIT;
+ out.horUncEllipseSemiMinor = locationExtended.horUncEllipseSemiMinor;
+ }
+ if (GPS_LOCATION_EXTENDED_HAS_HOR_ELIP_UNC_AZIMUTH & locationExtended.flags) {
+ out.flags |= GNSS_LOCATION_INFO_HOR_ACCURACY_ELIP_AZIMUTH_BIT;
+ out.horUncEllipseOrientAzimuth = locationExtended.horUncEllipseOrientAzimuth;
+ }
+ if (GPS_LOCATION_EXTENDED_HAS_NORTH_STD_DEV & locationExtended.flags) {
+ out.flags |= GNSS_LOCATION_INFO_NORTH_STD_DEV_BIT;
+ out.northStdDeviation = locationExtended.northStdDeviation;
+ }
+ if (GPS_LOCATION_EXTENDED_HAS_EAST_STD_DEV & locationExtended.flags) {
+ out.flags |= GNSS_LOCATION_INFO_EAST_STD_DEV_BIT;
+ out.eastStdDeviation = locationExtended.eastStdDeviation;
+ }
+ if (GPS_LOCATION_EXTENDED_HAS_NORTH_VEL & locationExtended.flags) {
+ out.flags |= GNSS_LOCATION_INFO_NORTH_VEL_BIT;
+ out.northVelocity = locationExtended.northVelocity;
+ }
+ if (GPS_LOCATION_EXTENDED_HAS_NORTH_VEL_UNC & locationExtended.flags) {
+ out.flags |= GNSS_LOCATION_INFO_NORTH_VEL_UNC_BIT;
+ out.northVelocityStdDeviation = locationExtended.northVelocityStdDeviation;
+ }
+ if (GPS_LOCATION_EXTENDED_HAS_EAST_VEL & locationExtended.flags) {
+ out.flags |= GNSS_LOCATION_INFO_EAST_VEL_BIT;
+ out.eastVelocity = locationExtended.eastVelocity;
+ }
+ if (GPS_LOCATION_EXTENDED_HAS_EAST_VEL_UNC & locationExtended.flags) {
+ out.flags |= GNSS_LOCATION_INFO_EAST_VEL_UNC_BIT;
+ out.eastVelocityStdDeviation = locationExtended.eastVelocityStdDeviation;
+ }
+ if (GPS_LOCATION_EXTENDED_HAS_UP_VEL & locationExtended.flags) {
+ out.flags |= GNSS_LOCATION_INFO_UP_VEL_BIT;
+ out.upVelocity = locationExtended.upVelocity;
+ }
+ if (GPS_LOCATION_EXTENDED_HAS_UP_VEL_UNC & locationExtended.flags) {
+ out.flags |= GNSS_LOCATION_INFO_UP_VEL_UNC_BIT;
+ out.upVelocityStdDeviation = locationExtended.upVelocityStdDeviation;
+ }
+ if (GPS_LOCATION_EXTENDED_HAS_GNSS_SV_USED_DATA & locationExtended.flags) {
+ out.flags |= GNSS_LOCATION_INFO_GNSS_SV_USED_DATA_BIT;
+ out.svUsedInPosition.gpsSvUsedIdsMask =
+ locationExtended.gnss_sv_used_ids.gps_sv_used_ids_mask;
+ out.svUsedInPosition.gloSvUsedIdsMask =
+ locationExtended.gnss_sv_used_ids.glo_sv_used_ids_mask;
+ out.svUsedInPosition.galSvUsedIdsMask =
+ locationExtended.gnss_sv_used_ids.gal_sv_used_ids_mask;
+ out.svUsedInPosition.bdsSvUsedIdsMask =
+ locationExtended.gnss_sv_used_ids.bds_sv_used_ids_mask;
+ out.svUsedInPosition.qzssSvUsedIdsMask =
+ locationExtended.gnss_sv_used_ids.qzss_sv_used_ids_mask;
+
+ out.flags |= GNSS_LOCATION_INFO_NUM_SV_USED_IN_POSITION_BIT;
+ out.numSvUsedInPosition = getNumSvUsed(out.svUsedInPosition.gpsSvUsedIdsMask,
+ GPS_SV_PRN_MAX - GPS_SV_PRN_MIN + 1);
+ out.numSvUsedInPosition += getNumSvUsed(out.svUsedInPosition.gloSvUsedIdsMask,
+ GLO_SV_PRN_MAX - GLO_SV_PRN_MIN + 1);
+ out.numSvUsedInPosition += getNumSvUsed(out.svUsedInPosition.qzssSvUsedIdsMask,
+ QZSS_SV_PRN_MAX - QZSS_SV_PRN_MIN + 1);
+ out.numSvUsedInPosition += getNumSvUsed(out.svUsedInPosition.bdsSvUsedIdsMask,
+ BDS_SV_PRN_MAX - BDS_SV_PRN_MIN + 1);
+ out.numSvUsedInPosition += getNumSvUsed(out.svUsedInPosition.galSvUsedIdsMask,
+ GAL_SV_PRN_MAX - GAL_SV_PRN_MIN + 1);
+
+ out.numOfMeasReceived = locationExtended.numOfMeasReceived;
+ for (int idx =0; idx < locationExtended.numOfMeasReceived; idx++) {
+ out.measUsageInfo[idx].gnssSignalType =
+ locationExtended.measUsageInfo[idx].gnssSignalType;
+ out.measUsageInfo[idx].gnssSvId =
+ locationExtended.measUsageInfo[idx].gnssSvId;
+ out.measUsageInfo[idx].gnssConstellation =
+ locationExtended.measUsageInfo[idx].gnssConstellation;
+ }
+ }
+ if (GPS_LOCATION_EXTENDED_HAS_NAV_SOLUTION_MASK & locationExtended.flags) {
+ out.flags |= GNSS_LOCATION_INFO_NAV_SOLUTION_MASK_BIT;
+ out.navSolutionMask = locationExtended.navSolutionMask;
+ }
+ if (GPS_LOCATION_EXTENDED_HAS_POS_TECH_MASK & locationExtended.flags) {
+ out.flags |= GNSS_LOCATION_INFO_POS_TECH_MASK_BIT;
+ out.posTechMask = locationExtended.tech_mask;
+ }
+ if (GPS_LOCATION_EXTENDED_HAS_POS_DYNAMICS_DATA & locationExtended.flags) {
+ out.flags |= GPS_LOCATION_EXTENDED_HAS_POS_DYNAMICS_DATA;
+ if (locationExtended.bodyFrameData.bodyFrameDataMask &
+ LOCATION_NAV_DATA_HAS_LONG_ACCEL_BIT) {
+ out.bodyFrameData.bodyFrameDataMask |= LOCATION_NAV_DATA_HAS_LONG_ACCEL_BIT;
+ }
+ if (locationExtended.bodyFrameData.bodyFrameDataMask &
+ LOCATION_NAV_DATA_HAS_LAT_ACCEL_BIT) {
+ out.bodyFrameData.bodyFrameDataMask |= LOCATION_NAV_DATA_HAS_LAT_ACCEL_BIT;
+ }
+ if (locationExtended.bodyFrameData.bodyFrameDataMask &
+ LOCATION_NAV_DATA_HAS_VERT_ACCEL_BIT) {
+ out.bodyFrameData.bodyFrameDataMask |= LOCATION_NAV_DATA_HAS_VERT_ACCEL_BIT;
+ }
+ if (locationExtended.bodyFrameData.bodyFrameDataMask & LOCATION_NAV_DATA_HAS_YAW_RATE_BIT) {
+ out.bodyFrameData.bodyFrameDataMask |= LOCATION_NAV_DATA_HAS_YAW_RATE_BIT;
+ }
+ if (locationExtended.bodyFrameData.bodyFrameDataMask & LOCATION_NAV_DATA_HAS_PITCH_BIT) {
+ out.bodyFrameData.bodyFrameDataMask |= LOCATION_NAV_DATA_HAS_PITCH_BIT;
+ }
+ out.bodyFrameData.longAccel = locationExtended.bodyFrameData.longAccel;
+ out.bodyFrameData.latAccel = locationExtended.bodyFrameData.latAccel;
+ out.bodyFrameData.vertAccel = locationExtended.bodyFrameData.vertAccel;
+ out.bodyFrameData.yawRate = locationExtended.bodyFrameData.yawRate;
+ out.bodyFrameData.pitch = locationExtended.bodyFrameData.pitch;
+ }
+ if (GPS_LOCATION_EXTENDED_HAS_GPS_TIME & locationExtended.flags) {
+ out.flags |= GPS_LOCATION_EXTENDED_HAS_GPS_TIME;
+ out.gnssSystemTime.gnssSystemTimeSrc = locationExtended.gnssSystemTime.gnssSystemTimeSrc;
+ out.gnssSystemTime.u = locationExtended.gnssSystemTime.u;
+ }
+ if (GPS_LOCATION_EXTENDED_HAS_NORTH_VEL & locationExtended.flags) {
+ out.flags |= GPS_LOCATION_EXTENDED_HAS_NORTH_VEL;
+ out.northVelocity = locationExtended.northVelocity;
+ }
+ if (GPS_LOCATION_EXTENDED_HAS_EAST_VEL & locationExtended.flags) {
+ out.flags |= GPS_LOCATION_EXTENDED_HAS_EAST_VEL;
+ out.eastVelocity = locationExtended.eastVelocity;
+ }
+ if (GPS_LOCATION_EXTENDED_HAS_UP_VEL & locationExtended.flags) {
+ out.flags |= GPS_LOCATION_EXTENDED_HAS_UP_VEL;
+ out.upVelocity = locationExtended.upVelocity;
+ }
+ if (GPS_LOCATION_EXTENDED_HAS_NORTH_VEL_UNC & locationExtended.flags) {
+ out.flags |= GPS_LOCATION_EXTENDED_HAS_NORTH_VEL_UNC;
+ out.northVelocityStdDeviation = locationExtended.northVelocityStdDeviation;
+ }
+ if (GPS_LOCATION_EXTENDED_HAS_EAST_VEL_UNC & locationExtended.flags) {
+ out.flags |= GPS_LOCATION_EXTENDED_HAS_EAST_VEL_UNC;
+ out.eastVelocityStdDeviation = locationExtended.eastVelocityStdDeviation;
+ }
+ if (GPS_LOCATION_EXTENDED_HAS_UP_VEL_UNC & locationExtended.flags) {
+ out.flags |= GPS_LOCATION_EXTENDED_HAS_UP_VEL_UNC;
+ out.upVelocityStdDeviation = locationExtended.upVelocityStdDeviation;
+ }
+
+ // Validity of this structure is established from the timeSrc of the GnssSystemTime structure.
+ out.gnssSystemTime = locationExtended.gnssSystemTime;
+
+ if (GPS_LOCATION_EXTENDED_HAS_LEAP_SECONDS & locationExtended.flags) {
+ out.flags |= GNSS_LOCATION_INFO_LEAP_SECONDS_BIT;
+ out.leapSeconds = locationExtended.leapSeconds;
+ }
+
+ if (GPS_LOCATION_EXTENDED_HAS_TIME_UNC & locationExtended.flags) {
+ out.flags |= GNSS_LOCATION_INFO_TIME_UNC_BIT;
+ out.timeUncMs = locationExtended.timeUncMs;
+ }
+
+ if (GPS_LOCATION_EXTENDED_HAS_CALIBRATION_CONFIDENCE & locationExtended.flags) {
+ out.flags |= GNSS_LOCATION_INFO_CALIBRATION_CONFIDENCE_BIT;
+ out.calibrationConfidence = locationExtended.calibrationConfidence;
+ }
+
+ if (GPS_LOCATION_EXTENDED_HAS_CALIBRATION_STATUS & locationExtended.flags) {
+ out.flags |= GNSS_LOCATION_INFO_CALIBRATION_STATUS_BIT;
+ out.calibrationStatus = locationExtended.calibrationStatus;
+ }
+
+ if (GPS_LOCATION_EXTENDED_HAS_OUTPUT_ENG_TYPE & locationExtended.flags) {
+ out.flags |= GNSS_LOCATION_INFO_OUTPUT_ENG_TYPE_BIT;
+ out.locOutputEngType = locationExtended.locOutputEngType;
+ }
+
+ if (GPS_LOCATION_EXTENDED_HAS_OUTPUT_ENG_MASK & locationExtended.flags) {
+ out.flags |= GNSS_LOCATION_INFO_OUTPUT_ENG_MASK_BIT;
+ out.locOutputEngMask = locationExtended.locOutputEngMask;
+ }
+}
+
+
+
+inline uint32_t
+GnssAdapter::convertSuplVersion(const GnssConfigSuplVersion suplVersion)
+{
+ switch (suplVersion) {
+ case GNSS_CONFIG_SUPL_VERSION_2_0_0:
+ return 0x00020000;
+ case GNSS_CONFIG_SUPL_VERSION_2_0_2:
+ return 0x00020002;
+ case GNSS_CONFIG_SUPL_VERSION_1_0_0:
+ default:
+ return 0x00010000;
+ }
+}
+
+inline uint32_t
+GnssAdapter::convertLppProfile(const GnssConfigLppProfile lppProfile)
+{
+ switch (lppProfile) {
+ case GNSS_CONFIG_LPP_PROFILE_USER_PLANE:
+ return 1;
+ case GNSS_CONFIG_LPP_PROFILE_CONTROL_PLANE:
+ return 2;
+ case GNSS_CONFIG_LPP_PROFILE_USER_PLANE_AND_CONTROL_PLANE:
+ return 3;
+ case GNSS_CONFIG_LPP_PROFILE_RRLP_ON_LTE:
+ default:
+ return 0;
+ }
+}
+
+uint32_t
+GnssAdapter::convertLppeCp(const GnssConfigLppeControlPlaneMask lppeControlPlaneMask)
+{
+ uint32_t mask = 0;
+ if (GNSS_CONFIG_LPPE_CONTROL_PLANE_DBH_BIT & lppeControlPlaneMask) {
+ mask |= (1<<0);
+ }
+ if (GNSS_CONFIG_LPPE_CONTROL_PLANE_WLAN_AP_MEASUREMENTS_BIT & lppeControlPlaneMask) {
+ mask |= (1<<1);
+ }
+ if (GNSS_CONFIG_LPPE_CONTROL_PLANE_SRN_AP_MEASUREMENTS_BIT & lppeControlPlaneMask) {
+ mask |= (1<<2);
+ }
+ if (GNSS_CONFIG_LPPE_CONTROL_PLANE_SENSOR_BARO_MEASUREMENTS_BIT & lppeControlPlaneMask) {
+ mask |= (1<<3);
+ }
+ return mask;
+}
+
+uint32_t
+GnssAdapter::convertLppeUp(const GnssConfigLppeUserPlaneMask lppeUserPlaneMask)
+{
+ uint32_t mask = 0;
+ if (GNSS_CONFIG_LPPE_USER_PLANE_DBH_BIT & lppeUserPlaneMask) {
+ mask |= (1<<0);
+ }
+ if (GNSS_CONFIG_LPPE_USER_PLANE_WLAN_AP_MEASUREMENTS_BIT & lppeUserPlaneMask) {
+ mask |= (1<<1);
+ }
+ if (GNSS_CONFIG_LPPE_USER_PLANE_SRN_AP_MEASUREMENTS_BIT & lppeUserPlaneMask) {
+ mask |= (1<<2);
+ }
+ if (GNSS_CONFIG_LPPE_USER_PLANE_SENSOR_BARO_MEASUREMENTS_BIT & lppeUserPlaneMask) {
+ mask |= (1<<3);
+ }
+ return mask;
+}
+
+uint32_t
+GnssAdapter::convertAGloProt(const GnssConfigAGlonassPositionProtocolMask aGloPositionProtocolMask)
+{
+ uint32_t mask = 0;
+ if (GNSS_CONFIG_RRC_CONTROL_PLANE_BIT & aGloPositionProtocolMask) {
+ mask |= (1<<0);
+ }
+ if (GNSS_CONFIG_RRLP_USER_PLANE_BIT & aGloPositionProtocolMask) {
+ mask |= (1<<1);
+ }
+ if (GNSS_CONFIG_LLP_USER_PLANE_BIT & aGloPositionProtocolMask) {
+ mask |= (1<<2);
+ }
+ if (GNSS_CONFIG_LLP_CONTROL_PLANE_BIT & aGloPositionProtocolMask) {
+ mask |= (1<<3);
+ }
+ return mask;
+}
+
+uint32_t
+GnssAdapter::convertEP4ES(const GnssConfigEmergencyPdnForEmergencySupl emergencyPdnForEmergencySupl)
+{
+ switch (emergencyPdnForEmergencySupl) {
+ case GNSS_CONFIG_EMERGENCY_PDN_FOR_EMERGENCY_SUPL_YES:
+ return 1;
+ case GNSS_CONFIG_EMERGENCY_PDN_FOR_EMERGENCY_SUPL_NO:
+ default:
+ return 0;
+ }
+}
+
+uint32_t
+GnssAdapter::convertSuplEs(const GnssConfigSuplEmergencyServices suplEmergencyServices)
+{
+ switch (suplEmergencyServices) {
+ case GNSS_CONFIG_SUPL_EMERGENCY_SERVICES_YES:
+ return 1;
+ case GNSS_CONFIG_SUPL_EMERGENCY_SERVICES_NO:
+ default:
+ return 0;
+ }
+}
+
+uint32_t
+GnssAdapter::convertSuplMode(const GnssConfigSuplModeMask suplModeMask)
+{
+ uint32_t mask = 0;
+ if (GNSS_CONFIG_SUPL_MODE_MSB_BIT & suplModeMask) {
+ mask |= (1<<0);
+ }
+ if (GNSS_CONFIG_SUPL_MODE_MSA_BIT & suplModeMask) {
+ mask |= (1<<1);
+ }
+ return mask;
+}
+
+void
+GnssAdapter::readConfigCommand()
+{
+ LOC_LOGD("%s]: ", __func__);
+
+ struct MsgReadConfig : public LocMsg {
+ GnssAdapter* mAdapter;
+ ContextBase& mContext;
+ inline MsgReadConfig(GnssAdapter* adapter,
+ ContextBase& context) :
+ LocMsg(),
+ mAdapter(adapter),
+ mContext(context) {}
+ inline virtual void proc() const {
+ static bool confReadDone = false;
+ if (!confReadDone) {
+ confReadDone = true;
+ // reads config into mContext->mGps_conf
+ mContext.readConfig();
+
+ uint32_t allowFlpNetworkFixes = 0;
+ static const loc_param_s_type flp_conf_param_table[] =
+ {
+ {"ALLOW_NETWORK_FIXES", &allowFlpNetworkFixes, NULL, 'n'},
+ };
+ UTIL_READ_CONF(LOC_PATH_FLP_CONF, flp_conf_param_table);
+ LOC_LOGd("allowFlpNetworkFixes %u", allowFlpNetworkFixes);
+ mAdapter->setAllowFlpNetworkFixes(allowFlpNetworkFixes);
+ }
+ }
+ };
+
+ if (mContext != NULL) {
+ sendMsg(new MsgReadConfig(this, *mContext));
+ }
+}
+
+void
+GnssAdapter::setSuplHostServer(const char* server, int port, LocServerType type)
+{
+ if (ContextBase::mGps_conf.AGPS_CONFIG_INJECT) {
+ char serverUrl[MAX_URL_LEN] = {};
+ int32_t length = -1;
+ const char noHost[] = "NONE";
+
+ if ((NULL == server) || (server[0] == 0) ||
+ (strncasecmp(noHost, server, sizeof(noHost)) == 0)) {
+ serverUrl[0] = '\0';
+ length = 0;
+ } else if (port > 0) {
+ length = snprintf(serverUrl, sizeof(serverUrl), "%s:%u", server, port);
+ }
+ if (LOC_AGPS_SUPL_SERVER != type && LOC_AGPS_MO_SUPL_SERVER != type) {
+ LOC_LOGe("Invalid type=%d", type);
+ } else if (length >= 0) {
+ if (LOC_AGPS_SUPL_SERVER == type) {
+ getServerUrl().assign(serverUrl);
+ strlcpy(ContextBase::mGps_conf.SUPL_HOST, server, LOC_MAX_PARAM_STRING);
+ ContextBase::mGps_conf.SUPL_PORT = port;
+ } else {
+ if (strncasecmp(getMoServerUrl().c_str(), serverUrl, sizeof(serverUrl)) != 0) {
+ getMoServerUrl().assign(serverUrl);
+ }
+ }
+ }
+ }
+}
+
+void
+GnssAdapter::setConfig()
+{
+ LOC_LOGD("%s]: ", __func__);
+
+ // set nmea mask type
+ uint32_t mask = 0;
+ if (NMEA_PROVIDER_MP == ContextBase::mGps_conf.NMEA_PROVIDER) {
+ mask |= LOC_NMEA_ALL_GENERAL_SUPPORTED_MASK;
+ }
+ if (ContextBase::isFeatureSupported(LOC_SUPPORTED_FEATURE_DEBUG_NMEA_V02)) {
+ mask |= LOC_NMEA_MASK_DEBUG_V02;
+ }
+ if (mNmeaMask != mask) {
+ mNmeaMask = mask;
+ if (mNmeaMask) {
+ for (auto it=mClientData.begin(); it != mClientData.end(); ++it) {
+ if ((it->second.gnssNmeaCb != nullptr)) {
+ updateEvtMask(LOC_API_ADAPTER_BIT_NMEA_1HZ_REPORT,
+ LOC_REGISTRATION_MASK_ENABLED);
+ break;
+ }
+ }
+ }
+ }
+
+ std::string oldMoServerUrl = getMoServerUrl();
+ setSuplHostServer(ContextBase::mGps_conf.SUPL_HOST,
+ ContextBase::mGps_conf.SUPL_PORT,
+ LOC_AGPS_SUPL_SERVER);
+ setSuplHostServer(ContextBase::mGps_conf.MO_SUPL_HOST,
+ ContextBase::mGps_conf.MO_SUPL_PORT,
+ LOC_AGPS_MO_SUPL_SERVER);
+
+ // inject the configurations into modem
+ loc_gps_cfg_s gpsConf = ContextBase::mGps_conf;
+ loc_sap_cfg_s_type sapConf = ContextBase::mSap_conf;
+
+ //cache the injected configuration with GnssConfigRequested struct
+ GnssConfig gnssConfigRequested = {};
+ gnssConfigRequested.flags |= GNSS_CONFIG_FLAGS_GPS_LOCK_VALID_BIT |
+ GNSS_CONFIG_FLAGS_BLACKLISTED_SV_IDS_BIT;
+ /* Here we process an SSR. We need to set the GPS_LOCK to the proper values, as follows:
+ 1. Q behavior. This is identified by mSupportNfwControl being 1. In this case
+ ContextBase::mGps_conf.GPS_LOCK is a "state", meaning it should reflect the
+ NV value. Therefore we will set the NV to ContextBase::mGps_conf.GPS_LOCK
+ 2. P behavior. This is identified by mSupportNfwControl being 0. In this case
+ ContextBase::mGps_conf.GPS_LOCK is a "configuration", meaning it should hold
+ the "mask" for NI. There are two subcases:
+ a. Location enabled in GUI (1 == getAfwControlId()). We need to set
+ the NV to GNSS_CONFIG_GPS_LOCK_NONE (both MO and NI enabled)
+ b. Location disabled in GUI (0 == getAfwControlId()). We need to set
+ the NV to ContextBase::mGps_conf.GPS_LOCK (the "mask", which is SIM-card
+ specific)
+ */
+ if (mSupportNfwControl || (0 == getAfwControlId())) {
+ gnssConfigRequested.gpsLock = gpsConf.GPS_LOCK;
+ } else {
+ gnssConfigRequested.gpsLock = GNSS_CONFIG_GPS_LOCK_NONE;
+ }
+
+ if (gpsConf.AGPS_CONFIG_INJECT) {
+ gnssConfigRequested.flags |= GNSS_CONFIG_FLAGS_SET_ASSISTANCE_DATA_VALID_BIT |
+ GNSS_CONFIG_FLAGS_SUPL_VERSION_VALID_BIT |
+ GNSS_CONFIG_FLAGS_AGLONASS_POSITION_PROTOCOL_VALID_BIT |
+ GNSS_CONFIG_FLAGS_LPP_PROFILE_VALID_BIT;
+ gnssConfigRequested.suplVersion =
+ mLocApi->convertSuplVersion(gpsConf.SUPL_VER);
+ gnssConfigRequested.lppProfile =
+ mLocApi->convertLppProfile(gpsConf.LPP_PROFILE);
+ gnssConfigRequested.aGlonassPositionProtocolMask =
+ gpsConf.A_GLONASS_POS_PROTOCOL_SELECT;
+ }
+ if (gpsConf.LPPE_CP_TECHNOLOGY) {
+ gnssConfigRequested.flags |= GNSS_CONFIG_FLAGS_LPPE_CONTROL_PLANE_VALID_BIT;
+ gnssConfigRequested.lppeControlPlaneMask =
+ mLocApi->convertLppeCp(gpsConf.LPPE_CP_TECHNOLOGY);
+ }
+
+ if (gpsConf.LPPE_UP_TECHNOLOGY) {
+ gnssConfigRequested.flags |= GNSS_CONFIG_FLAGS_LPPE_USER_PLANE_VALID_BIT;
+ gnssConfigRequested.lppeUserPlaneMask =
+ mLocApi->convertLppeUp(gpsConf.LPPE_UP_TECHNOLOGY);
+ }
+ gnssConfigRequested.blacklistedSvIds.assign(mBlacklistedSvIds.begin(),
+ mBlacklistedSvIds.end());
+ mLocApi->sendMsg(new LocApiMsg(
+ [this, gpsConf, sapConf, oldMoServerUrl, gnssConfigRequested] () {
+ gnssUpdateConfig(oldMoServerUrl, gnssConfigRequested, gnssConfigRequested);
+
+ // set nmea mask type
+ uint32_t mask = 0;
+ if (NMEA_PROVIDER_MP == gpsConf.NMEA_PROVIDER) {
+ mask |= LOC_NMEA_ALL_GENERAL_SUPPORTED_MASK;
+ }
+ if (ContextBase::isFeatureSupported(LOC_SUPPORTED_FEATURE_DEBUG_NMEA_V02)) {
+ mask |= LOC_NMEA_MASK_DEBUG_V02;
+ }
+
+ if (mask != 0) {
+ mLocApi->setNMEATypesSync(mask);
+ }
+
+ mLocApi->setXtraVersionCheckSync(gpsConf.XTRA_VERSION_CHECK);
+
+ mLocApi->setConstrainedTuncMode(
+ gpsConf.CONSTRAINED_TIME_UNCERTAINTY_ENABLED == 1,
+ (float)gpsConf.CONSTRAINED_TIME_UNCERTAINTY_THRESHOLD,
+ gpsConf.CONSTRAINED_TIME_UNCERTAINTY_ENERGY_BUDGET);
+ mLocApi->setPositionAssistedClockEstimatorMode(
+ gpsConf.POSITION_ASSISTED_CLOCK_ESTIMATOR_ENABLED == 1);
+
+ if (sapConf.GYRO_BIAS_RANDOM_WALK_VALID ||
+ sapConf.ACCEL_RANDOM_WALK_SPECTRAL_DENSITY_VALID ||
+ sapConf.ANGLE_RANDOM_WALK_SPECTRAL_DENSITY_VALID ||
+ sapConf.RATE_RANDOM_WALK_SPECTRAL_DENSITY_VALID ||
+ sapConf.VELOCITY_RANDOM_WALK_SPECTRAL_DENSITY_VALID ) {
+ mLocApi->setSensorPropertiesSync(
+ sapConf.GYRO_BIAS_RANDOM_WALK_VALID,
+ sapConf.GYRO_BIAS_RANDOM_WALK,
+ sapConf.ACCEL_RANDOM_WALK_SPECTRAL_DENSITY_VALID,
+ sapConf.ACCEL_RANDOM_WALK_SPECTRAL_DENSITY,
+ sapConf.ANGLE_RANDOM_WALK_SPECTRAL_DENSITY_VALID,
+ sapConf.ANGLE_RANDOM_WALK_SPECTRAL_DENSITY,
+ sapConf.RATE_RANDOM_WALK_SPECTRAL_DENSITY_VALID,
+ sapConf.RATE_RANDOM_WALK_SPECTRAL_DENSITY,
+ sapConf.VELOCITY_RANDOM_WALK_SPECTRAL_DENSITY_VALID,
+ sapConf.VELOCITY_RANDOM_WALK_SPECTRAL_DENSITY);
+ }
+ mLocApi->setSensorPerfControlConfigSync(
+ sapConf.SENSOR_CONTROL_MODE,
+ sapConf.SENSOR_ACCEL_SAMPLES_PER_BATCH,
+ sapConf.SENSOR_ACCEL_BATCHES_PER_SEC,
+ sapConf.SENSOR_GYRO_SAMPLES_PER_BATCH,
+ sapConf.SENSOR_GYRO_BATCHES_PER_SEC,
+ sapConf.SENSOR_ACCEL_SAMPLES_PER_BATCH_HIGH,
+ sapConf.SENSOR_ACCEL_BATCHES_PER_SEC_HIGH,
+ sapConf.SENSOR_GYRO_SAMPLES_PER_BATCH_HIGH,
+ sapConf.SENSOR_GYRO_BATCHES_PER_SEC_HIGH,
+ sapConf.SENSOR_ALGORITHM_CONFIG_MASK);
+ } ));
+
+}
+
+std::vector<LocationError> GnssAdapter::gnssUpdateConfig(const std::string& oldMoServerUrl,
+ const GnssConfig& gnssConfigRequested,
+ const GnssConfig& gnssConfigNeedEngineUpdate, size_t count) {
+ loc_gps_cfg_s gpsConf = ContextBase::mGps_conf;
+ size_t index = 0;
+ LocationError err = LOCATION_ERROR_SUCCESS;
+ std::vector<LocationError> errsList = {err};
+ if (count > 0) {
+ errsList.insert(errsList.begin(), count, LOCATION_ERROR_SUCCESS);
+ }
+
+
+ std::string serverUrl = getServerUrl();
+ std::string moServerUrl = getMoServerUrl();
+
+ int serverUrlLen = serverUrl.length();
+ int moServerUrlLen = moServerUrl.length();
+
+ if (gnssConfigRequested.flags & GNSS_CONFIG_FLAGS_GPS_LOCK_VALID_BIT) {
+ if (gnssConfigNeedEngineUpdate.flags & GNSS_CONFIG_FLAGS_GPS_LOCK_VALID_BIT) {
+ err = mLocApi->setGpsLockSync(gnssConfigRequested.gpsLock);
+ if (index < count) {
+ errsList[index] = err;
+ }
+ }
+ index++;
+ }
+
+ if (gnssConfigRequested.flags &
+ GNSS_CONFIG_FLAGS_SET_ASSISTANCE_DATA_VALID_BIT) {
+ if (gnssConfigNeedEngineUpdate.flags &
+ GNSS_CONFIG_FLAGS_SET_ASSISTANCE_DATA_VALID_BIT) {
+ if (gnssConfigNeedEngineUpdate.assistanceServer.type ==
+ GNSS_ASSISTANCE_TYPE_SUPL) {
+ err = mLocApi->setServerSync(
+ serverUrl.c_str(), serverUrlLen, LOC_AGPS_SUPL_SERVER);
+ if (index < count) {
+ errsList[index] = err;
+ }
+ if (0 != oldMoServerUrl.compare(moServerUrl)) {
+ LocationError locErr =
+ mLocApi->setServerSync(moServerUrl.c_str(),
+ moServerUrlLen,
+ LOC_AGPS_MO_SUPL_SERVER);
+ if (locErr != LOCATION_ERROR_SUCCESS) {
+ LOC_LOGe("Error while setting MO SUPL_HOST server:%s",
+ moServerUrl.c_str());
+ }
+ }
+ } else if (gnssConfigNeedEngineUpdate.assistanceServer.type ==
+ GNSS_ASSISTANCE_TYPE_C2K) {
+ struct in_addr addr;
+ struct hostent* hp;
+ bool resolveAddrSuccess = true;
+
+ hp = gethostbyname(
+ gnssConfigNeedEngineUpdate.assistanceServer.hostName);
+ if (hp != NULL) { /* DNS OK */
+ memcpy(&addr, hp->h_addr_list[0], hp->h_length);
+ } else {
+ /* Try IP representation */
+ if (inet_aton(
+ gnssConfigNeedEngineUpdate.assistanceServer.hostName,
+ &addr) == 0) {
+ /* IP not valid */
+ LOC_LOGE("%s]: hostname '%s' cannot be resolved ",
+ __func__,
+ gnssConfigNeedEngineUpdate.assistanceServer.hostName);
+ if (index < count) {
+ errsList[index] = LOCATION_ERROR_INVALID_PARAMETER;
+ }
+ } else {
+ resolveAddrSuccess = false;
+ }
+ }
+
+ if (resolveAddrSuccess) {
+ unsigned int ip = htonl(addr.s_addr);
+ err = mLocApi->setServerSync(ip,
+ gnssConfigNeedEngineUpdate.assistanceServer.port,
+ LOC_AGPS_CDMA_PDE_SERVER);
+ if (index < count) {
+ errsList[index] = err;
+ }
+ }
+ }
+ }
+ index++;
+ }
+
+ if (gnssConfigRequested.flags & GNSS_CONFIG_FLAGS_SUPL_VERSION_VALID_BIT) {
+ if (gnssConfigNeedEngineUpdate.flags &
+ GNSS_CONFIG_FLAGS_SUPL_VERSION_VALID_BIT) {
+ err = mLocApi->setSUPLVersionSync(gnssConfigRequested.suplVersion);
+ if (index < count) {
+ errsList[index] = err;
+ }
+ }
+ index++;
+ }
+
+ if (gnssConfigRequested.flags & GNSS_CONFIG_FLAGS_LPP_PROFILE_VALID_BIT) {
+ if (gnssConfigNeedEngineUpdate.flags &
+ GNSS_CONFIG_FLAGS_LPP_PROFILE_VALID_BIT) {
+ err = mLocApi->setLPPConfigSync(gnssConfigRequested.lppProfile);
+ if (index < count) {
+ errsList[index] = err;
+ }
+ }
+ index++;
+ }
+
+ if (gnssConfigRequested.flags & GNSS_CONFIG_FLAGS_LPPE_CONTROL_PLANE_VALID_BIT) {
+ if (gnssConfigNeedEngineUpdate.flags &
+ GNSS_CONFIG_FLAGS_LPPE_CONTROL_PLANE_VALID_BIT) {
+ err = mLocApi->setLPPeProtocolCpSync(
+ gnssConfigRequested.lppeControlPlaneMask);
+ if (index < count) {
+ errsList[index] = err;
+ }
+ }
+ index++;
+ }
+
+ if (gnssConfigRequested.flags & GNSS_CONFIG_FLAGS_LPPE_USER_PLANE_VALID_BIT) {
+ if (gnssConfigNeedEngineUpdate.flags &
+ GNSS_CONFIG_FLAGS_LPPE_USER_PLANE_VALID_BIT) {
+ err = mLocApi->setLPPeProtocolUpSync(
+ gnssConfigRequested.lppeUserPlaneMask);
+ if (index < count) {
+ errsList[index] = err;
+ }
+ }
+ index++;
+ }
+
+ if (gnssConfigRequested.flags &
+ GNSS_CONFIG_FLAGS_AGLONASS_POSITION_PROTOCOL_VALID_BIT) {
+ if (gnssConfigNeedEngineUpdate.flags &
+ GNSS_CONFIG_FLAGS_AGLONASS_POSITION_PROTOCOL_VALID_BIT) {
+ err = mLocApi->setAGLONASSProtocolSync(
+ gnssConfigRequested.aGlonassPositionProtocolMask);
+ if (index < count) {
+ errsList[index] = err;
+ }
+ }
+ index++;
+ }
+ if (gnssConfigRequested.flags & GNSS_CONFIG_FLAGS_BLACKLISTED_SV_IDS_BIT) {
+ // Check if feature is supported
+ if (!ContextBase::isFeatureSupported(
+ LOC_SUPPORTED_FEATURE_CONSTELLATION_ENABLEMENT_V02)) {
+ LOC_LOGe("Feature constellation enablement not supported.");
+ err = LOCATION_ERROR_NOT_SUPPORTED;
+ } else {
+ // Send the SV ID Config to Modem
+ mBlacklistedSvIds.assign(gnssConfigRequested.blacklistedSvIds.begin(),
+ gnssConfigRequested.blacklistedSvIds.end());
+ err = gnssSvIdConfigUpdateSync(gnssConfigRequested.blacklistedSvIds);
+ if (LOCATION_ERROR_SUCCESS != err) {
+ LOC_LOGe("Failed to send config to modem, err %d", err);
+ }
+ }
+ if (index < count) {
+ errsList[index] = err;
+ }
+ index++;
+ }
+ if (gnssConfigRequested.flags &
+ GNSS_CONFIG_FLAGS_EMERGENCY_EXTENSION_SECONDS_BIT) {
+ if (gnssConfigNeedEngineUpdate.flags &
+ GNSS_CONFIG_FLAGS_EMERGENCY_EXTENSION_SECONDS_BIT) {
+ err = mLocApi->setEmergencyExtensionWindowSync(
+ gnssConfigRequested.emergencyExtensionSeconds);
+ if (index < count) {
+ errsList[index] = err;
+ }
+ }
+ index++;
+ }
+ return errsList;
+}
+
+uint32_t*
+GnssAdapter::gnssUpdateConfigCommand(GnssConfig config)
+{
+ // count the number of bits set
+ GnssConfigFlagsMask flagsCopy = config.flags;
+ size_t count = 0;
+ while (flagsCopy > 0) {
+ if (flagsCopy & 1) {
+ count++;
+ }
+ flagsCopy >>= 1;
+ }
+ std::string idsString = "[";
+ uint32_t* ids = NULL;
+ if (count > 0) {
+ ids = new uint32_t[count];
+ if (ids == nullptr) {
+ LOC_LOGE("%s] new allocation failed, fatal error.", __func__);
+ return nullptr;
+ }
+ for (size_t i=0; i < count; ++i) {
+ ids[i] = generateSessionId();
+ IF_LOC_LOGD {
+ idsString += std::to_string(ids[i]) + " ";
+ }
+ }
+ }
+ idsString += "]";
+
+ LOC_LOGD("%s]: ids %s flags 0x%X", __func__, idsString.c_str(), config.flags);
+
+ struct MsgGnssUpdateConfig : public LocMsg {
+ GnssAdapter& mAdapter;
+ LocApiBase& mApi;
+ GnssConfig mConfig;
+ size_t mCount;
+ uint32_t* mIds;
+ inline MsgGnssUpdateConfig(GnssAdapter& adapter,
+ LocApiBase& api,
+ GnssConfig config,
+ uint32_t* ids,
+ size_t count) :
+ LocMsg(),
+ mAdapter(adapter),
+ mApi(api),
+ mConfig(config),
+ mCount(count),
+ mIds(ids) {}
+ inline MsgGnssUpdateConfig(const MsgGnssUpdateConfig& obj) :
+ MsgGnssUpdateConfig(obj.mAdapter, obj.mApi, obj.mConfig,
+ new uint32_t[obj.mCount], obj.mCount) {
+ if (mIds != nullptr) {
+ for (int i = 0; i < mCount; ++i) {
+ mIds[i] = obj.mIds[i];
+ }
+ }
+ }
+ inline virtual ~MsgGnssUpdateConfig()
+ {
+ delete[] mIds;
+ }
+
+ inline virtual void proc() const {
+ if (!mAdapter.isEngineCapabilitiesKnown()) {
+ mAdapter.mPendingMsgs.push_back(new MsgGnssUpdateConfig(*this));
+ return;
+ }
+ GnssAdapter& adapter = mAdapter;
+ size_t countOfConfigs = mCount;
+ GnssConfig gnssConfigRequested = mConfig;
+ GnssConfig gnssConfigNeedEngineUpdate = mConfig;
+
+ std::vector<uint32_t> sessionIds;
+ sessionIds.assign(mIds, mIds + mCount);
+ std::vector<LocationError> errs(mCount, LOCATION_ERROR_SUCCESS);
+ int index = 0;
+
+ if (gnssConfigRequested.flags & GNSS_CONFIG_FLAGS_GPS_LOCK_VALID_BIT) {
+ GnssConfigGpsLock newGpsLock = gnssConfigRequested.gpsLock;
+
+ newGpsLock |= GNSS_CONFIG_GPS_LOCK_MO;
+ ContextBase::mGps_conf.GPS_LOCK = newGpsLock;
+ /* If we get here it means that the changes in the framework to request for
+ 'P' behavior were made, and therefore we need to "behave" as in 'P'
+ However, we need to determine if enableCommand function has already been
+ called, since it could get called before this function.*/
+ if (0 != mAdapter.getAfwControlId()) {
+ /* enableCommand function has already been called since getAfwControlId
+ returns non zero. Now there are two possible cases:
+ 1. This is the first time this function is called
+ (mSupportNfwControl is true). We need to behave as in 'P', but
+ for the first time, meaning MO was enabled, but NI was not, so
+ we need to unlock NI
+ 2. This is not the first time this function is called, meaning we
+ are already behaving as in 'P'. No need to update the configuration
+ in this case (return to 'P' code) */
+ if (mAdapter.mSupportNfwControl) {
+ // case 1 above
+ newGpsLock = GNSS_CONFIG_GPS_LOCK_NONE;
+ } else {
+ // case 2 above
+ gnssConfigNeedEngineUpdate.flags &= ~(GNSS_CONFIG_FLAGS_GPS_LOCK_VALID_BIT);
+ }
+ }
+ gnssConfigRequested.gpsLock = newGpsLock;
+ mAdapter.mSupportNfwControl = false;
+ index++;
+ }
+ if (gnssConfigRequested.flags & GNSS_CONFIG_FLAGS_SUPL_VERSION_VALID_BIT) {
+ uint32_t newSuplVersion =
+ mAdapter.convertSuplVersion(gnssConfigRequested.suplVersion);
+ ContextBase::mGps_conf.SUPL_VER = newSuplVersion;
+ index++;
+ }
+ if (gnssConfigRequested.flags & GNSS_CONFIG_FLAGS_SET_ASSISTANCE_DATA_VALID_BIT) {
+ if (GNSS_ASSISTANCE_TYPE_SUPL == mConfig.assistanceServer.type) {
+ mAdapter.setSuplHostServer(mConfig.assistanceServer.hostName,
+ mConfig.assistanceServer.port,
+ LOC_AGPS_SUPL_SERVER);
+ } else {
+ LOC_LOGE("%s]: Not a valid gnss assistance type %u",
+ __func__, mConfig.assistanceServer.type);
+ errs.at(index) = LOCATION_ERROR_INVALID_PARAMETER;
+ gnssConfigNeedEngineUpdate.flags &=
+ ~(GNSS_CONFIG_FLAGS_SET_ASSISTANCE_DATA_VALID_BIT);
+ }
+ index++;
+ }
+ if (gnssConfigRequested.flags & GNSS_CONFIG_FLAGS_LPP_PROFILE_VALID_BIT) {
+ uint32_t newLppProfile = mAdapter.convertLppProfile(gnssConfigRequested.lppProfile);
+ ContextBase::mGps_conf.LPP_PROFILE = newLppProfile;
+ index++;
+ }
+ if (gnssConfigRequested.flags & GNSS_CONFIG_FLAGS_LPPE_CONTROL_PLANE_VALID_BIT) {
+ uint32_t newLppeControlPlaneMask =
+ mAdapter.convertLppeCp(gnssConfigRequested.lppeControlPlaneMask);
+ ContextBase::mGps_conf.LPPE_CP_TECHNOLOGY = newLppeControlPlaneMask;
+ index++;
+ }
+ if (gnssConfigRequested.flags & GNSS_CONFIG_FLAGS_LPPE_USER_PLANE_VALID_BIT) {
+ uint32_t newLppeUserPlaneMask =
+ mAdapter.convertLppeUp(gnssConfigRequested.lppeUserPlaneMask);
+ ContextBase::mGps_conf.LPPE_UP_TECHNOLOGY = newLppeUserPlaneMask;
+ index++;
+ }
+ if (gnssConfigRequested.flags &
+ GNSS_CONFIG_FLAGS_AGLONASS_POSITION_PROTOCOL_VALID_BIT) {
+ uint32_t newAGloProtMask =
+ mAdapter.convertAGloProt(gnssConfigRequested.aGlonassPositionProtocolMask);
+ ContextBase::mGps_conf.A_GLONASS_POS_PROTOCOL_SELECT = newAGloProtMask;
+ index++;
+ }
+ if (gnssConfigRequested.flags & GNSS_CONFIG_FLAGS_EM_PDN_FOR_EM_SUPL_VALID_BIT) {
+ uint32_t newEP4ES = mAdapter.convertEP4ES(
+ gnssConfigRequested.emergencyPdnForEmergencySupl);
+ if (newEP4ES != ContextBase::mGps_conf.USE_EMERGENCY_PDN_FOR_EMERGENCY_SUPL) {
+ ContextBase::mGps_conf.USE_EMERGENCY_PDN_FOR_EMERGENCY_SUPL = newEP4ES;
+ }
+ index++;
+ }
+ if (gnssConfigRequested.flags & GNSS_CONFIG_FLAGS_SUPL_EM_SERVICES_BIT) {
+ uint32_t newSuplEs = mAdapter.convertSuplEs(
+ gnssConfigRequested.suplEmergencyServices);
+ if (newSuplEs != ContextBase::mGps_conf.SUPL_ES) {
+ ContextBase::mGps_conf.SUPL_ES = newSuplEs;
+ }
+ index++;
+ }
+ if (gnssConfigRequested.flags & GNSS_CONFIG_FLAGS_SUPL_MODE_BIT) {
+ uint32_t newSuplMode = mAdapter.convertSuplMode(gnssConfigRequested.suplModeMask);
+ ContextBase::mGps_conf.SUPL_MODE = newSuplMode;
+ mAdapter.broadcastCapabilities(mAdapter.getCapabilities());
+ index++;
+ }
+
+ LocApiCollectiveResponse *configCollectiveResponse = new LocApiCollectiveResponse(
+ *adapter.getContext(),
+ [&adapter, sessionIds, countOfConfigs] (std::vector<LocationError> errs) {
+
+ std::vector<uint32_t> ids(sessionIds);
+ adapter.reportResponse(countOfConfigs, errs.data(), ids.data());
+ });
+
+ mApi.sendMsg(new LocApiMsg(
+ [&adapter, gnssConfigRequested, gnssConfigNeedEngineUpdate,
+ countOfConfigs, configCollectiveResponse, errs] () {
+ std::vector<LocationError> errsList = adapter.gnssUpdateConfig("",
+ gnssConfigRequested, gnssConfigNeedEngineUpdate, countOfConfigs);
+
+ configCollectiveResponse->returnToSender(errsList);
+ }));
+ }
+ };
+
+ if (NULL != ids) {
+ sendMsg(new MsgGnssUpdateConfig(*this, *mLocApi, config, ids, count));
+ } else {
+ LOC_LOGE("%s]: No GNSS config items to update", __func__);
+ }
+
+ return ids;
+}
+
+void
+GnssAdapter::gnssSvIdConfigUpdate(const std::vector<GnssSvIdSource>& blacklistedSvIds)
+{
+ // Clear the existing config
+ memset(&mGnssSvIdConfig, 0, sizeof(GnssSvIdConfig));
+
+ // Convert the sv id lists to masks
+ bool convertSuccess = convertToGnssSvIdConfig(blacklistedSvIds, mGnssSvIdConfig);
+
+ // Now send to Modem if conversion successful
+ if (convertSuccess) {
+ gnssSvIdConfigUpdate();
+ } else {
+ LOC_LOGe("convertToGnssSvIdConfig failed");
+ }
+}
+
+void
+GnssAdapter::gnssSvIdConfigUpdate()
+{
+ LOC_LOGd("blacklist bds 0x%" PRIx64 ", glo 0x%" PRIx64
+ ", qzss 0x%" PRIx64 ", gal 0x%" PRIx64,
+ mGnssSvIdConfig.bdsBlacklistSvMask, mGnssSvIdConfig.gloBlacklistSvMask,
+ mGnssSvIdConfig.qzssBlacklistSvMask, mGnssSvIdConfig.galBlacklistSvMask);
+
+ // Now set required blacklisted SVs
+ mLocApi->setBlacklistSv(mGnssSvIdConfig);
+}
+
+LocationError
+GnssAdapter::gnssSvIdConfigUpdateSync(const std::vector<GnssSvIdSource>& blacklistedSvIds)
+{
+ // Clear the existing config
+ memset(&mGnssSvIdConfig, 0, sizeof(GnssSvIdConfig));
+
+ // Convert the sv id lists to masks
+ convertToGnssSvIdConfig(blacklistedSvIds, mGnssSvIdConfig);
+
+ // Now send to Modem
+ return gnssSvIdConfigUpdateSync();
+}
+
+LocationError
+GnssAdapter::gnssSvIdConfigUpdateSync()
+{
+ LOC_LOGd("blacklist bds 0x%" PRIx64 ", glo 0x%" PRIx64
+ ", qzss 0x%" PRIx64 ", gal 0x%" PRIx64,
+ mGnssSvIdConfig.bdsBlacklistSvMask, mGnssSvIdConfig.gloBlacklistSvMask,
+ mGnssSvIdConfig.qzssBlacklistSvMask, mGnssSvIdConfig.galBlacklistSvMask);
+
+ // Now set required blacklisted SVs
+ return mLocApi->setBlacklistSvSync(mGnssSvIdConfig);
+}
+
+uint32_t*
+GnssAdapter::gnssGetConfigCommand(GnssConfigFlagsMask configMask) {
+
+ // count the number of bits set
+ GnssConfigFlagsMask flagsCopy = configMask;
+ size_t count = 0;
+ while (flagsCopy > 0) {
+ if (flagsCopy & 1) {
+ count++;
+ }
+ flagsCopy >>= 1;
+ }
+ std::string idsString = "[";
+ uint32_t* ids = NULL;
+ if (count > 0) {
+ ids = new uint32_t[count];
+ if (nullptr == ids) {
+ LOC_LOGe("new allocation failed, fatal error.");
+ return nullptr;
+ }
+ for (size_t i=0; i < count; ++i) {
+ ids[i] = generateSessionId();
+ IF_LOC_LOGD {
+ idsString += std::to_string(ids[i]) + " ";
+ }
+ }
+ }
+ idsString += "]";
+
+ LOC_LOGd("ids %s flags 0x%X", idsString.c_str(), configMask);
+
+ struct MsgGnssGetConfig : public LocMsg {
+ GnssAdapter& mAdapter;
+ LocApiBase& mApi;
+ GnssConfigFlagsMask mConfigMask;
+ uint32_t* mIds;
+ size_t mCount;
+ inline MsgGnssGetConfig(GnssAdapter& adapter,
+ LocApiBase& api,
+ GnssConfigFlagsMask configMask,
+ uint32_t* ids,
+ size_t count) :
+ LocMsg(),
+ mAdapter(adapter),
+ mApi(api),
+ mConfigMask(configMask),
+ mIds(ids),
+ mCount(count) {}
+
+ inline MsgGnssGetConfig(const MsgGnssGetConfig& obj) :
+ MsgGnssGetConfig(obj.mAdapter, obj.mApi, obj.mConfigMask,
+ new uint32_t[obj.mCount], obj.mCount) {
+ if (mIds != nullptr) {
+ for (int i = 0; i < mCount; ++i) {
+ mIds[i] = obj.mIds[i];
+ }
+ }
+ }
+ inline virtual ~MsgGnssGetConfig()
+ {
+ delete[] mIds;
+ }
+ inline virtual void proc() const {
+ if (!mAdapter.isEngineCapabilitiesKnown()) {
+ mAdapter.mPendingMsgs.push_back(new MsgGnssGetConfig(*this));
+ return;
+ }
+ LocationError* errs = new LocationError[mCount];
+ LocationError err = LOCATION_ERROR_SUCCESS;
+ uint32_t index = 0;
+
+ if (nullptr == errs) {
+ LOC_LOGE("%s] new allocation failed, fatal error.", __func__);
+ return;
+ }
+
+ if (mConfigMask & GNSS_CONFIG_FLAGS_GPS_LOCK_VALID_BIT) {
+ if (index < mCount) {
+ errs[index++] = LOCATION_ERROR_NOT_SUPPORTED;
+ }
+ }
+ if (mConfigMask & GNSS_CONFIG_FLAGS_SUPL_VERSION_VALID_BIT) {
+ if (index < mCount) {
+ errs[index++] = LOCATION_ERROR_NOT_SUPPORTED;
+ }
+ }
+ if (mConfigMask & GNSS_CONFIG_FLAGS_SET_ASSISTANCE_DATA_VALID_BIT) {
+ if (index < mCount) {
+ errs[index++] = LOCATION_ERROR_NOT_SUPPORTED;
+ }
+ }
+ if (mConfigMask & GNSS_CONFIG_FLAGS_LPP_PROFILE_VALID_BIT) {
+ if (index < mCount) {
+ errs[index++] = LOCATION_ERROR_NOT_SUPPORTED;
+ }
+ }
+ if (mConfigMask & GNSS_CONFIG_FLAGS_LPPE_CONTROL_PLANE_VALID_BIT) {
+ if (index < mCount) {
+ errs[index++] = LOCATION_ERROR_NOT_SUPPORTED;
+ }
+ }
+ if (mConfigMask & GNSS_CONFIG_FLAGS_LPPE_USER_PLANE_VALID_BIT) {
+ if (index < mCount) {
+ errs[index++] = LOCATION_ERROR_NOT_SUPPORTED;
+ }
+ }
+ if (mConfigMask & GNSS_CONFIG_FLAGS_AGLONASS_POSITION_PROTOCOL_VALID_BIT) {
+ if (index < mCount) {
+ errs[index++] = LOCATION_ERROR_NOT_SUPPORTED;
+ }
+ }
+ if (mConfigMask & GNSS_CONFIG_FLAGS_EM_PDN_FOR_EM_SUPL_VALID_BIT) {
+ if (index < mCount) {
+ errs[index++] = LOCATION_ERROR_NOT_SUPPORTED;
+ }
+ }
+ if (mConfigMask & GNSS_CONFIG_FLAGS_SUPL_EM_SERVICES_BIT) {
+ if (index < mCount) {
+ errs[index++] = LOCATION_ERROR_NOT_SUPPORTED;
+ }
+ }
+ if (mConfigMask & GNSS_CONFIG_FLAGS_SUPL_MODE_BIT) {
+ err = LOCATION_ERROR_NOT_SUPPORTED;
+ if (index < mCount) {
+ errs[index++] = LOCATION_ERROR_NOT_SUPPORTED;
+ }
+ }
+ if (mConfigMask & GNSS_CONFIG_FLAGS_BLACKLISTED_SV_IDS_BIT) {
+ // Check if feature is supported
+ if (!ContextBase::isFeatureSupported(
+ LOC_SUPPORTED_FEATURE_CONSTELLATION_ENABLEMENT_V02)) {
+ LOC_LOGe("Feature not supported.");
+ err = LOCATION_ERROR_NOT_SUPPORTED;
+ } else {
+ // Send request to Modem to fetch the config
+ mApi.getBlacklistSv();
+ err = LOCATION_ERROR_SUCCESS;
+ }
+ if (index < mCount) {
+ errs[index++] = err;
+ }
+ }
+ if (mConfigMask & GNSS_CONFIG_FLAGS_EMERGENCY_EXTENSION_SECONDS_BIT) {
+ err = LOCATION_ERROR_NOT_SUPPORTED;
+ if (index < mCount) {
+ errs[index++] = LOCATION_ERROR_NOT_SUPPORTED;
+ }
+ }
+
+ mAdapter.reportResponse(index, errs, mIds);
+ delete[] errs;
+
+ }
+ };
+
+ if (NULL != ids) {
+ sendMsg(new MsgGnssGetConfig(*this, *mLocApi, configMask, ids, count));
+ } else {
+ LOC_LOGe("No GNSS config items to Get");
+ }
+
+ return ids;
+}
+
+bool
+GnssAdapter::convertToGnssSvIdConfig(
+ const std::vector<GnssSvIdSource>& blacklistedSvIds, GnssSvIdConfig& config)
+{
+ bool retVal = false;
+ config.size = sizeof(GnssSvIdConfig);
+
+ // Empty vector => Clear any previous blacklisted SVs
+ if (0 == blacklistedSvIds.size()) {
+ config.gloBlacklistSvMask = 0;
+ config.bdsBlacklistSvMask = 0;
+ config.qzssBlacklistSvMask = 0;
+ config.galBlacklistSvMask = 0;
+ retVal = true;
+ } else {
+ // Parse the vector and convert SV IDs to mask values
+ for (GnssSvIdSource source : blacklistedSvIds) {
+ uint64_t* svMaskPtr = NULL;
+ GnssSvId initialSvId = 0;
+ switch(source.constellation) {
+ case GNSS_SV_TYPE_GLONASS:
+ svMaskPtr = &config.gloBlacklistSvMask;
+ initialSvId = GNSS_SV_CONFIG_GLO_INITIAL_SV_ID;
+ break;
+ case GNSS_SV_TYPE_BEIDOU:
+ svMaskPtr = &config.bdsBlacklistSvMask;
+ initialSvId = GNSS_SV_CONFIG_BDS_INITIAL_SV_ID;
+ break;
+ case GNSS_SV_TYPE_QZSS:
+ svMaskPtr = &config.qzssBlacklistSvMask;
+ initialSvId = GNSS_SV_CONFIG_QZSS_INITIAL_SV_ID;
+ break;
+ case GNSS_SV_TYPE_GALILEO:
+ svMaskPtr = &config.galBlacklistSvMask;
+ initialSvId = GNSS_SV_CONFIG_GAL_INITIAL_SV_ID;
+ break;
+ default:
+ break;
+ }
+
+ if (NULL == svMaskPtr) {
+ LOC_LOGe("Invalid constellation %d", source.constellation);
+ } else {
+ // SV ID 0 = All SV IDs
+ if (0 == source.svId) {
+ *svMaskPtr = GNSS_SV_CONFIG_ALL_BITS_ENABLED_MASK;
+ } else if (source.svId < initialSvId || source.svId >= initialSvId + 64) {
+ LOC_LOGe("Invalid sv id %d for sv type %d",
+ source.svId, source.constellation);
+ } else {
+ *svMaskPtr |= (1 << (source.svId - initialSvId));
+ }
+ }
+ }
+
+ // Return true if any one source is valid
+ if (0 != config.gloBlacklistSvMask ||
+ 0 != config.bdsBlacklistSvMask ||
+ 0 != config.galBlacklistSvMask ||
+ 0 != config.qzssBlacklistSvMask) {
+ retVal = true;
+ }
+ }
+
+ return retVal;
+}
+
+void GnssAdapter::convertFromGnssSvIdConfig(
+ const GnssSvIdConfig& svConfig, GnssConfig& config)
+{
+ // Convert blacklisted SV mask values to vectors
+ if (svConfig.bdsBlacklistSvMask) {
+ convertGnssSvIdMaskToList(
+ svConfig.bdsBlacklistSvMask, config.blacklistedSvIds,
+ GNSS_SV_CONFIG_BDS_INITIAL_SV_ID, GNSS_SV_TYPE_BEIDOU);
+ config.flags |= GNSS_CONFIG_FLAGS_BLACKLISTED_SV_IDS_BIT;
+ }
+ if (svConfig.galBlacklistSvMask) {
+ convertGnssSvIdMaskToList(
+ svConfig.galBlacklistSvMask, config.blacklistedSvIds,
+ GNSS_SV_CONFIG_GAL_INITIAL_SV_ID, GNSS_SV_TYPE_GALILEO);
+ config.flags |= GNSS_CONFIG_FLAGS_BLACKLISTED_SV_IDS_BIT;
+ }
+ if (svConfig.gloBlacklistSvMask) {
+ convertGnssSvIdMaskToList(
+ svConfig.gloBlacklistSvMask, config.blacklistedSvIds,
+ GNSS_SV_CONFIG_GLO_INITIAL_SV_ID, GNSS_SV_TYPE_GLONASS);
+ config.flags |= GNSS_CONFIG_FLAGS_BLACKLISTED_SV_IDS_BIT;
+ }
+ if (svConfig.qzssBlacklistSvMask) {
+ convertGnssSvIdMaskToList(
+ svConfig.qzssBlacklistSvMask, config.blacklistedSvIds,
+ GNSS_SV_CONFIG_QZSS_INITIAL_SV_ID, GNSS_SV_TYPE_QZSS);
+ config.flags |= GNSS_CONFIG_FLAGS_BLACKLISTED_SV_IDS_BIT;
+ }
+}
+
+void GnssAdapter::convertGnssSvIdMaskToList(
+ uint64_t svIdMask, std::vector<GnssSvIdSource>& svIds,
+ GnssSvId initialSvId, GnssSvType svType)
+{
+ GnssSvIdSource source = {};
+ source.size = sizeof(GnssSvIdSource);
+ source.constellation = svType;
+
+ // SV ID 0 => All SV IDs in mask
+ if (GNSS_SV_CONFIG_ALL_BITS_ENABLED_MASK == svIdMask) {
+ source.svId = 0;
+ svIds.push_back(source);
+ return;
+ }
+
+ // Convert each bit in svIdMask to vector entry
+ uint32_t bitNumber = 0;
+ while (svIdMask > 0) {
+ if (svIdMask & 0x1) {
+ source.svId = bitNumber + initialSvId;
+ svIds.push_back(source);
+ }
+ bitNumber++;
+ svIdMask >>= 1;
+ }
+}
+
+void GnssAdapter::reportGnssSvIdConfigEvent(const GnssSvIdConfig& config)
+{
+ struct MsgReportGnssSvIdConfig : public LocMsg {
+ GnssAdapter& mAdapter;
+ const GnssSvIdConfig mConfig;
+ inline MsgReportGnssSvIdConfig(GnssAdapter& adapter,
+ const GnssSvIdConfig& config) :
+ LocMsg(),
+ mAdapter(adapter),
+ mConfig(config) {}
+ inline virtual void proc() const {
+ mAdapter.reportGnssSvIdConfig(mConfig);
+ }
+ };
+
+ sendMsg(new MsgReportGnssSvIdConfig(*this, config));
+}
+
+void GnssAdapter::reportGnssSvIdConfig(const GnssSvIdConfig& svIdConfig)
+{
+ GnssConfig config = {};
+ config.size = sizeof(GnssConfig);
+
+ // Invoke control clients config callback
+ if (nullptr != mControlCallbacks.gnssConfigCb &&
+ svIdConfig.size == sizeof(GnssSvIdConfig)) {
+ convertFromGnssSvIdConfig(svIdConfig, config);
+ LOC_LOGd("blacklist bds 0x%" PRIx64 ", glo 0x%" PRIx64
+ ", qzss 0x%" PRIx64 ", gal 0x%" PRIx64,
+ svIdConfig.bdsBlacklistSvMask, svIdConfig.gloBlacklistSvMask,
+ svIdConfig.qzssBlacklistSvMask, svIdConfig.galBlacklistSvMask);
+ mControlCallbacks.gnssConfigCb(config);
+ } else {
+ LOC_LOGe("Failed to report, size %d", (uint32_t)config.size);
+ }
+}
+
+void
+GnssAdapter::gnssUpdateSvTypeConfigCommand(GnssSvTypeConfig config)
+{
+ struct MsgGnssUpdateSvTypeConfig : public LocMsg {
+ GnssAdapter* mAdapter;
+ LocApiBase* mApi;
+ GnssSvTypeConfig mConfig;
+ inline MsgGnssUpdateSvTypeConfig(
+ GnssAdapter* adapter,
+ LocApiBase* api,
+ GnssSvTypeConfig& config) :
+ LocMsg(),
+ mAdapter(adapter),
+ mApi(api),
+ mConfig(config) {}
+ inline virtual void proc() const {
+ if (!mAdapter->isEngineCapabilitiesKnown()) {
+ mAdapter->mPendingMsgs.push_back(new MsgGnssUpdateSvTypeConfig(*this));
+ return;
+ }
+ // Check if feature is supported
+ if (!ContextBase::isFeatureSupported(
+ LOC_SUPPORTED_FEATURE_CONSTELLATION_ENABLEMENT_V02)) {
+ LOC_LOGe("Feature not supported.");
+ } else {
+ // Send update request to modem
+ mAdapter->gnssSvTypeConfigUpdate(mConfig);
+ }
+ }
+ };
+
+ sendMsg(new MsgGnssUpdateSvTypeConfig(this, mLocApi, config));
+}
+
+void
+GnssAdapter::gnssSvTypeConfigUpdate(const GnssSvTypeConfig& config)
+{
+ // Gather bits removed from enabled mask
+ GnssSvTypesMask enabledRemoved = mGnssSvTypeConfig.enabledSvTypesMask &
+ (mGnssSvTypeConfig.enabledSvTypesMask ^ config.enabledSvTypesMask);
+ // Send reset if any constellation is removed from the enabled list
+ bool sendReset = (enabledRemoved != 0);
+ // Save new config and update
+ gnssSetSvTypeConfig(config);
+ gnssSvTypeConfigUpdate(sendReset);
+}
+
+void
+GnssAdapter::gnssSvTypeConfigUpdate(bool sendReset)
+{
+ LOC_LOGd("size %" PRIu32" constellations blacklisted 0x%" PRIx64 ", enabled 0x%" PRIx64
+ ", sendReset %d",
+ mGnssSvTypeConfig.size, mGnssSvTypeConfig.blacklistedSvTypesMask,
+ mGnssSvTypeConfig.enabledSvTypesMask, sendReset);
+
+ if (mGnssSvTypeConfig.size == sizeof(mGnssSvTypeConfig)) {
+
+ if (sendReset) {
+ mLocApi->resetConstellationControl();
+ }
+
+ GnssSvIdConfig blacklistConfig = {};
+ // Revert to previously blacklisted SVs for each enabled constellation
+ blacklistConfig = mGnssSvIdConfig;
+ // Blacklist all SVs for each disabled constellation
+ if (mGnssSvTypeConfig.blacklistedSvTypesMask) {
+ if (mGnssSvTypeConfig.blacklistedSvTypesMask & GNSS_SV_TYPES_MASK_GLO_BIT) {
+ blacklistConfig.gloBlacklistSvMask = GNSS_SV_CONFIG_ALL_BITS_ENABLED_MASK;
+ }
+ if (mGnssSvTypeConfig.blacklistedSvTypesMask & GNSS_SV_TYPES_MASK_BDS_BIT) {
+ blacklistConfig.bdsBlacklistSvMask = GNSS_SV_CONFIG_ALL_BITS_ENABLED_MASK;
+ }
+ if (mGnssSvTypeConfig.blacklistedSvTypesMask & GNSS_SV_TYPES_MASK_QZSS_BIT) {
+ blacklistConfig.qzssBlacklistSvMask = GNSS_SV_CONFIG_ALL_BITS_ENABLED_MASK;
+ }
+ if (mGnssSvTypeConfig.blacklistedSvTypesMask & GNSS_SV_TYPES_MASK_GAL_BIT) {
+ blacklistConfig.galBlacklistSvMask = GNSS_SV_CONFIG_ALL_BITS_ENABLED_MASK;
+ }
+ }
+
+ // Send blacklist info
+ mLocApi->setBlacklistSv(blacklistConfig);
+
+ // Send only enabled constellation config
+ if (mGnssSvTypeConfig.enabledSvTypesMask) {
+ GnssSvTypeConfig svTypeConfig = {sizeof(GnssSvTypeConfig), 0, 0};
+ svTypeConfig.enabledSvTypesMask = mGnssSvTypeConfig.enabledSvTypesMask;
+ mLocApi->setConstellationControl(svTypeConfig);
+ }
+ }
+}
+
+void
+GnssAdapter::gnssGetSvTypeConfigCommand(GnssSvTypeConfigCallback callback)
+{
+ struct MsgGnssGetSvTypeConfig : public LocMsg {
+ GnssAdapter* mAdapter;
+ LocApiBase* mApi;
+ GnssSvTypeConfigCallback mCallback;
+ inline MsgGnssGetSvTypeConfig(
+ GnssAdapter* adapter,
+ LocApiBase* api,
+ GnssSvTypeConfigCallback callback) :
+ LocMsg(),
+ mAdapter(adapter),
+ mApi(api),
+ mCallback(callback) {}
+ inline virtual void proc() const {
+ if (!mAdapter->isEngineCapabilitiesKnown()) {
+ mAdapter->mPendingMsgs.push_back(new MsgGnssGetSvTypeConfig(*this));
+ return;
+ }
+ if (!ContextBase::isFeatureSupported(
+ LOC_SUPPORTED_FEATURE_CONSTELLATION_ENABLEMENT_V02)) {
+ LOC_LOGe("Feature not supported.");
+ } else {
+ // Save the callback
+ mAdapter->gnssSetSvTypeConfigCallback(mCallback);
+ // Send GET request to modem
+ mApi->getConstellationControl();
+ }
+ }
+ };
+
+ sendMsg(new MsgGnssGetSvTypeConfig(this, mLocApi, callback));
+}
+
+void
+GnssAdapter::gnssResetSvTypeConfigCommand()
+{
+ struct MsgGnssResetSvTypeConfig : public LocMsg {
+ GnssAdapter* mAdapter;
+ LocApiBase* mApi;
+ inline MsgGnssResetSvTypeConfig(
+ GnssAdapter* adapter,
+ LocApiBase* api) :
+ LocMsg(),
+ mAdapter(adapter),
+ mApi(api) {}
+ inline virtual void proc() const {
+ if (!mAdapter->isEngineCapabilitiesKnown()) {
+ mAdapter->mPendingMsgs.push_back(new MsgGnssResetSvTypeConfig(*this));
+ return;
+ }
+ if (!ContextBase::isFeatureSupported(
+ LOC_SUPPORTED_FEATURE_CONSTELLATION_ENABLEMENT_V02)) {
+ LOC_LOGe("Feature not supported.");
+ } else {
+ // Reset constellation config
+ mAdapter->gnssSetSvTypeConfig({sizeof(GnssSvTypeConfig), 0, 0});
+ // Re-enforce SV blacklist config
+ mAdapter->gnssSvIdConfigUpdate();
+ // Send reset request to modem
+ mApi->resetConstellationControl();
+ }
+ }
+ };
+
+ sendMsg(new MsgGnssResetSvTypeConfig(this, mLocApi));
+}
+
+void GnssAdapter::reportGnssSvTypeConfigEvent(const GnssSvTypeConfig& config)
+{
+ struct MsgReportGnssSvTypeConfig : public LocMsg {
+ GnssAdapter& mAdapter;
+ const GnssSvTypeConfig mConfig;
+ inline MsgReportGnssSvTypeConfig(GnssAdapter& adapter,
+ const GnssSvTypeConfig& config) :
+ LocMsg(),
+ mAdapter(adapter),
+ mConfig(config) {}
+ inline virtual void proc() const {
+ mAdapter.reportGnssSvTypeConfig(mConfig);
+ }
+ };
+
+ sendMsg(new MsgReportGnssSvTypeConfig(*this, config));
+}
+
+void GnssAdapter::reportGnssSvTypeConfig(const GnssSvTypeConfig& config)
+{
+ // Invoke Get SV Type Callback
+ if (NULL != mGnssSvTypeConfigCb &&
+ config.size == sizeof(GnssSvTypeConfig)) {
+ LOC_LOGd("constellations blacklisted 0x%" PRIx64 ", enabled 0x%" PRIx64,
+ config.blacklistedSvTypesMask, config.enabledSvTypesMask);
+ mGnssSvTypeConfigCb(config);
+ } else {
+ LOC_LOGe("Failed to report, size %d", (uint32_t)config.size);
+ }
+}
+
+void GnssAdapter::deleteAidingData(const GnssAidingData &data, uint32_t sessionId) {
+ mLocApi->deleteAidingData(data, new LocApiResponse(*getContext(),
+ [this, sessionId] (LocationError err) {
+ reportResponse(err, sessionId);
+ }));
+}
+
+uint32_t
+GnssAdapter::gnssDeleteAidingDataCommand(GnssAidingData& data)
+{
+ uint32_t sessionId = generateSessionId();
+ LOC_LOGD("%s]: id %u", __func__, sessionId);
+
+ struct MsgDeleteAidingData : public LocMsg {
+ GnssAdapter& mAdapter;
+ uint32_t mSessionId;
+ GnssAidingData mData;
+ inline MsgDeleteAidingData(GnssAdapter& adapter,
+ uint32_t sessionId,
+ GnssAidingData& data) :
+ LocMsg(),
+ mAdapter(adapter),
+ mSessionId(sessionId),
+ mData(data) {}
+ inline virtual void proc() const {
+ if ((mData.posEngineMask & STANDARD_POSITIONING_ENGINE) != 0) {
+ mAdapter.deleteAidingData(mData, mSessionId);
+
+ SystemStatus* s = mAdapter.getSystemStatus();
+ if ((nullptr != s) && (mData.deleteAll)) {
+ s->setDefaultGnssEngineStates();
+ }
+ }
+
+ mAdapter.mEngHubProxy->gnssDeleteAidingData(mData);
+ }
+ };
+
+ sendMsg(new MsgDeleteAidingData(*this, sessionId, data));
+ return sessionId;
+}
+
+void
+GnssAdapter::gnssUpdateXtraThrottleCommand(const bool enabled)
+{
+ LOC_LOGD("%s] enabled:%d", __func__, enabled);
+
+ struct UpdateXtraThrottleMsg : public LocMsg {
+ GnssAdapter& mAdapter;
+ const bool mEnabled;
+ inline UpdateXtraThrottleMsg(GnssAdapter& adapter, const bool enabled) :
+ LocMsg(),
+ mAdapter(adapter),
+ mEnabled(enabled) {}
+ inline virtual void proc() const {
+ mAdapter.mXtraObserver.updateXtraThrottle(mEnabled);
+ }
+ };
+
+ sendMsg(new UpdateXtraThrottleMsg(*this, enabled));
+}
+
+void
+GnssAdapter::injectLocationCommand(double latitude, double longitude, float accuracy)
+{
+ LOC_LOGD("%s]: latitude %8.4f longitude %8.4f accuracy %8.4f",
+ __func__, latitude, longitude, accuracy);
+
+ struct MsgInjectLocation : public LocMsg {
+ LocApiBase& mApi;
+ ContextBase& mContext;
+ BlockCPIInfo& mBlockCPI;
+ double mLatitude;
+ double mLongitude;
+ float mAccuracy;
+ inline MsgInjectLocation(LocApiBase& api,
+ ContextBase& context,
+ BlockCPIInfo& blockCPIInfo,
+ double latitude,
+ double longitude,
+ float accuracy) :
+ LocMsg(),
+ mApi(api),
+ mContext(context),
+ mBlockCPI(blockCPIInfo),
+ mLatitude(latitude),
+ mLongitude(longitude),
+ mAccuracy(accuracy) {}
+ inline virtual void proc() const {
+ if ((uptimeMillis() <= mBlockCPI.blockedTillTsMs) &&
+ (fabs(mLatitude-mBlockCPI.latitude) <= mBlockCPI.latLonDiffThreshold) &&
+ (fabs(mLongitude-mBlockCPI.longitude) <= mBlockCPI.latLonDiffThreshold)) {
+
+ LOC_LOGD("%s]: positon injeciton blocked: lat: %f, lon: %f, accuracy: %f",
+ __func__, mLatitude, mLongitude, mAccuracy);
+
+ } else {
+ mApi.injectPosition(mLatitude, mLongitude, mAccuracy);
+ }
+ }
+ };
+
+ sendMsg(new MsgInjectLocation(*mLocApi, *mContext, mBlockCPIInfo,
+ latitude, longitude, accuracy));
+}
+
+void
+GnssAdapter::injectLocationExtCommand(const GnssLocationInfoNotification &locationInfo)
+{
+ LOC_LOGd("latitude %8.4f longitude %8.4f accuracy %8.4f, tech mask 0x%x",
+ locationInfo.location.latitude, locationInfo.location.longitude,
+ locationInfo.location.accuracy, locationInfo.location.techMask);
+
+ struct MsgInjectLocationExt : public LocMsg {
+ LocApiBase& mApi;
+ ContextBase& mContext;
+ GnssLocationInfoNotification mLocationInfo;
+ inline MsgInjectLocationExt(LocApiBase& api,
+ ContextBase& context,
+ GnssLocationInfoNotification locationInfo) :
+ LocMsg(),
+ mApi(api),
+ mContext(context),
+ mLocationInfo(locationInfo) {}
+ inline virtual void proc() const {
+ // false to indicate for none-ODCPI
+ mApi.injectPosition(mLocationInfo, false);
+ }
+ };
+
+ sendMsg(new MsgInjectLocationExt(*mLocApi, *mContext, locationInfo));
+}
+
+void
+GnssAdapter::injectTimeCommand(int64_t time, int64_t timeReference, int32_t uncertainty)
+{
+ LOC_LOGD("%s]: time %lld timeReference %lld uncertainty %d",
+ __func__, (long long)time, (long long)timeReference, uncertainty);
+
+ struct MsgInjectTime : public LocMsg {
+ LocApiBase& mApi;
+ ContextBase& mContext;
+ int64_t mTime;
+ int64_t mTimeReference;
+ int32_t mUncertainty;
+ inline MsgInjectTime(LocApiBase& api,
+ ContextBase& context,
+ int64_t time,
+ int64_t timeReference,
+ int32_t uncertainty) :
+ LocMsg(),
+ mApi(api),
+ mContext(context),
+ mTime(time),
+ mTimeReference(timeReference),
+ mUncertainty(uncertainty) {}
+ inline virtual void proc() const {
+ mApi.setTime(mTime, mTimeReference, mUncertainty);
+ }
+ };
+
+ sendMsg(new MsgInjectTime(*mLocApi, *mContext, time, timeReference, uncertainty));
+}
+
+// This command is to called to block the position to be injected to the modem.
+// This can happen for network position that comes from modem.
+void
+GnssAdapter::blockCPICommand(double latitude, double longitude,
+ float accuracy, int blockDurationMsec,
+ double latLonDiffThreshold)
+{
+ struct MsgBlockCPI : public LocMsg {
+ BlockCPIInfo& mDstCPIInfo;
+ BlockCPIInfo mSrcCPIInfo;
+
+ inline MsgBlockCPI(BlockCPIInfo& dstCPIInfo,
+ BlockCPIInfo& srcCPIInfo) :
+ mDstCPIInfo(dstCPIInfo),
+ mSrcCPIInfo(srcCPIInfo) {}
+ inline virtual void proc() const {
+ // in the same hal thread, save the cpi to be blocked
+ // the global variable
+ mDstCPIInfo = mSrcCPIInfo;
+ }
+ };
+
+ // construct the new block CPI info and queue on the same thread
+ // for processing
+ BlockCPIInfo blockCPIInfo;
+ blockCPIInfo.latitude = latitude;
+ blockCPIInfo.longitude = longitude;
+ blockCPIInfo.accuracy = accuracy;
+ blockCPIInfo.blockedTillTsMs = uptimeMillis() + blockDurationMsec;
+ blockCPIInfo.latLonDiffThreshold = latLonDiffThreshold;
+
+ LOC_LOGD("%s]: block CPI lat: %f, lon: %f ", __func__, latitude, longitude);
+ // send a message to record down the coarse position
+ // to be blocked from injection in the master copy (mBlockCPIInfo)
+ sendMsg(new MsgBlockCPI(mBlockCPIInfo, blockCPIInfo));
+}
+
+void
+GnssAdapter::addClientCommand(LocationAPI* client, const LocationCallbacks& callbacks)
+{
+ LOC_LOGD("%s]: client %p", __func__, client);
+
+ struct MsgAddClient : public LocMsg {
+ GnssAdapter& mAdapter;
+ LocationAPI* mClient;
+ const LocationCallbacks mCallbacks;
+ inline MsgAddClient(GnssAdapter& adapter,
+ LocationAPI* client,
+ const LocationCallbacks& callbacks) :
+ LocMsg(),
+ mAdapter(adapter),
+ mClient(client),
+ mCallbacks(callbacks) {}
+ inline virtual void proc() const {
+ // check whether we need to notify client of cached location system info
+ mAdapter.notifyClientOfCachedLocationSystemInfo(mClient, mCallbacks);
+ mAdapter.saveClient(mClient, mCallbacks);
+ }
+ };
+
+ sendMsg(new MsgAddClient(*this, client, callbacks));
+}
+
+void
+GnssAdapter::stopClientSessions(LocationAPI* client)
+{
+ LOC_LOGD("%s]: client %p", __func__, client);
+
+ /* Time-based Tracking */
+ std::vector<LocationSessionKey> vTimeBasedTrackingClient;
+ for (auto it : mTimeBasedTrackingSessions) {
+ if (client == it.first.client) {
+ vTimeBasedTrackingClient.emplace_back(it.first.client, it.first.id);
+ }
+ }
+ for (auto key : vTimeBasedTrackingClient) {
+ stopTimeBasedTrackingMultiplex(key.client, key.id);
+ }
+
+ /* Distance-based Tracking */
+ for (auto it = mDistanceBasedTrackingSessions.begin();
+ it != mDistanceBasedTrackingSessions.end(); /* no increment here*/) {
+ if (client == it->first.client) {
+ mLocApi->stopDistanceBasedTracking(it->first.id, new LocApiResponse(*getContext(),
+ [this, client, id=it->first.id] (LocationError err) {
+ if (LOCATION_ERROR_SUCCESS == err) {
+ eraseTrackingSession(client, id);
+ }
+ }
+ ));
+ }
+ ++it; // increment only when not erasing an iterator
+ }
+
+}
+
+void
+GnssAdapter::updateClientsEventMask()
+{
+ LOC_API_ADAPTER_EVENT_MASK_T mask = 0;
+ for (auto it=mClientData.begin(); it != mClientData.end(); ++it) {
+ if (it->second.trackingCb != nullptr || it->second.gnssLocationInfoCb != nullptr) {
+ mask |= LOC_API_ADAPTER_BIT_PARSED_POSITION_REPORT;
+ }
+ if (it->second.gnssSvCb != nullptr) {
+ mask |= LOC_API_ADAPTER_BIT_SATELLITE_REPORT;
+ }
+ if ((it->second.gnssNmeaCb != nullptr) && (mNmeaMask)) {
+ mask |= LOC_API_ADAPTER_BIT_NMEA_1HZ_REPORT;
+ }
+ if (it->second.gnssMeasurementsCb != nullptr) {
+ mask |= LOC_API_ADAPTER_BIT_GNSS_MEASUREMENT;
+ }
+ if (it->second.gnssDataCb != nullptr) {
+ mask |= LOC_API_ADAPTER_BIT_PARSED_POSITION_REPORT;
+ mask |= LOC_API_ADAPTER_BIT_NMEA_1HZ_REPORT;
+ updateNmeaMask(mNmeaMask | LOC_NMEA_MASK_DEBUG_V02);
+ }
+ }
+
+ /*
+ ** For Automotive use cases we need to enable MEASUREMENT, POLY and EPHEMERIS
+ ** when QDR is enabled (e.g.: either enabled via conf file or
+ ** engine hub is loaded successfully).
+ ** Note: this need to be called from msg queue thread.
+ */
+ if((1 == ContextBase::mGps_conf.EXTERNAL_DR_ENABLED) ||
+ (true == initEngHubProxy())) {
+ mask |= LOC_API_ADAPTER_BIT_GNSS_MEASUREMENT;
+ mask |= LOC_API_ADAPTER_BIT_GNSS_NHZ_MEASUREMENT;
+ mask |= LOC_API_ADAPTER_BIT_GNSS_SV_POLYNOMIAL_REPORT;
+ mask |= LOC_API_ADAPTER_BIT_PARSED_UNPROPAGATED_POSITION_REPORT;
+ mask |= LOC_API_ADAPTER_BIT_GNSS_SV_EPHEMERIS_REPORT;
+ mask |= LOC_API_ADAPTER_BIT_LOC_SYSTEM_INFO;
+ mask |= LOC_API_ADAPTER_BIT_EVENT_REPORT_INFO;
+
+ LOC_LOGd("Auto usecase, Enable MEAS/POLY/EPHEMERIS - mask 0x%" PRIx64 "",
+ mask);
+ }
+
+ if (mAgpsManager.isRegistered()) {
+ mask |= LOC_API_ADAPTER_BIT_LOCATION_SERVER_REQUEST;
+ }
+ // Add ODCPI handling
+ if (nullptr != mOdcpiRequestCb) {
+ mask |= LOC_API_ADAPTER_BIT_REQUEST_WIFI;
+ }
+
+ // need to register for leap second info
+ // for proper nmea generation
+ mask |= LOC_API_ADAPTER_BIT_LOC_SYSTEM_INFO;
+
+ // always register for NI NOTIFY VERIFY to handle internally in HAL
+ mask |= LOC_API_ADAPTER_BIT_NI_NOTIFY_VERIFY_REQUEST;
+
+ updateEvtMask(mask, LOC_REGISTRATION_MASK_SET);
+}
+
+void
+GnssAdapter::handleEngineUpEvent()
+{
+ LOC_LOGD("%s]: ", __func__);
+
+ struct MsgHandleEngineUpEvent : public LocMsg {
+ GnssAdapter& mAdapter;
+ inline MsgHandleEngineUpEvent(GnssAdapter& adapter) :
+ LocMsg(),
+ mAdapter(adapter) {}
+ virtual void proc() const {
+ mAdapter.setEngineCapabilitiesKnown(true);
+ mAdapter.broadcastCapabilities(mAdapter.getCapabilities());
+ // must be called only after capabilities are known
+ mAdapter.setConfig();
+ mAdapter.restartSessions();
+ mAdapter.gnssSvIdConfigUpdate();
+ mAdapter.gnssSvTypeConfigUpdate();
+ for (auto msg: mAdapter.mPendingMsgs) {
+ mAdapter.sendMsg(msg);
+ }
+ mAdapter.mPendingMsgs.clear();
+ }
+ };
+
+ readConfigCommand();
+ sendMsg(new MsgHandleEngineUpEvent(*this));
+}
+
+void
+GnssAdapter::restartSessions()
+{
+ LOC_LOGD("%s]: ", __func__);
+
+ // odcpi session is no longer active after restart
+ mOdcpiRequestActive = false;
+
+ if (!mTimeBasedTrackingSessions.empty()) {
+ // get the LocationOptions that has the smallest interval, which should be the active one
+ TrackingOptions smallestIntervalOptions; // size is zero until set for the first time
+ TrackingOptions highestPowerTrackingOptions;
+ memset(&smallestIntervalOptions, 0, sizeof(smallestIntervalOptions));
+ memset(&highestPowerTrackingOptions, 0, sizeof(highestPowerTrackingOptions));
+ for (auto it = mTimeBasedTrackingSessions.begin(); it != mTimeBasedTrackingSessions.end(); ++it) {
+ // size of zero means we havent set it yet
+ if (0 == smallestIntervalOptions.size ||
+ it->second.minInterval < smallestIntervalOptions.minInterval) {
+ smallestIntervalOptions = it->second;
+ }
+ GnssPowerMode powerMode = it->second.powerMode;
+ // Size of zero means we havent set it yet
+ if (0 == highestPowerTrackingOptions.size ||
+ (GNSS_POWER_MODE_INVALID != powerMode &&
+ powerMode < highestPowerTrackingOptions.powerMode)) {
+ highestPowerTrackingOptions = it->second;
+ }
+ }
+
+ highestPowerTrackingOptions.setLocationOptions(smallestIntervalOptions);
+ mLocApi->startTimeBasedTracking(highestPowerTrackingOptions, nullptr);
+ }
+
+ for (auto it = mDistanceBasedTrackingSessions.begin();
+ it != mDistanceBasedTrackingSessions.end(); ++it) {
+ mLocApi->startDistanceBasedTracking(it->first.id, it->second,
+ new LocApiResponse(*getContext(),
+ [] (LocationError /*err*/) {}));
+ }
+}
+
+void
+GnssAdapter::notifyClientOfCachedLocationSystemInfo(
+ LocationAPI* client, const LocationCallbacks& callbacks) {
+
+ if (mLocSystemInfo.systemInfoMask) {
+ // client need to be notified if client has not yet previously registered
+ // for the info but now register for it.
+ bool notifyClientOfSystemInfo = false;
+ // check whether we need to notify client of cached location system info
+ //
+ // client need to be notified if client has not yet previously registered
+ // for the info but now register for it.
+ if (callbacks.locationSystemInfoCb) {
+ notifyClientOfSystemInfo = true;
+ auto it = mClientData.find(client);
+ if (it != mClientData.end()) {
+ LocationCallbacks oldCallbacks = it->second;
+ if (oldCallbacks.locationSystemInfoCb) {
+ notifyClientOfSystemInfo = false;
+ }
+ }
+ }
+
+ if (notifyClientOfSystemInfo) {
+ callbacks.locationSystemInfoCb(mLocSystemInfo);
+ }
+ }
+}
+
+bool
+GnssAdapter::hasTrackingCallback(LocationAPI* client)
+{
+ auto it = mClientData.find(client);
+ return (it != mClientData.end() && (it->second.trackingCb || it->second.gnssLocationInfoCb));
+}
+
+bool
+GnssAdapter::isTimeBasedTrackingSession(LocationAPI* client, uint32_t sessionId)
+{
+ LocationSessionKey key(client, sessionId);
+ return (mTimeBasedTrackingSessions.find(key) != mTimeBasedTrackingSessions.end());
+}
+
+bool
+GnssAdapter::isDistanceBasedTrackingSession(LocationAPI* client, uint32_t sessionId)
+{
+ LocationSessionKey key(client, sessionId);
+ return (mDistanceBasedTrackingSessions.find(key) != mDistanceBasedTrackingSessions.end());
+}
+
+bool
+GnssAdapter::hasMeasurementsCallback(LocationAPI* client)
+{
+ auto it = mClientData.find(client);
+ return (it != mClientData.end() && it->second.gnssMeasurementsCb);
+}
+
+bool
+GnssAdapter::isTrackingSession(LocationAPI* client, uint32_t sessionId)
+{
+ LocationSessionKey key(client, sessionId);
+ return (mTimeBasedTrackingSessions.find(key) != mTimeBasedTrackingSessions.end());
+}
+
+void
+GnssAdapter::reportPowerStateIfChanged()
+{
+ bool newPowerOn = !mTimeBasedTrackingSessions.empty() ||
+ !mDistanceBasedTrackingSessions.empty();
+ if (newPowerOn != mPowerOn) {
+ mPowerOn = newPowerOn;
+ if (mPowerStateCb != nullptr) {
+ mPowerStateCb(mPowerOn);
+ }
+ }
+}
+
+void
+GnssAdapter::getPowerStateChangesCommand(void* powerStateCb)
+{
+ LOC_LOGD("%s]: ", __func__);
+
+ struct MsgReportLocation : public LocMsg {
+ GnssAdapter& mAdapter;
+ powerStateCallback mPowerStateCb;
+ inline MsgReportLocation(GnssAdapter& adapter,
+ powerStateCallback powerStateCb) :
+ LocMsg(),
+ mAdapter(adapter),
+ mPowerStateCb(powerStateCb) {}
+ inline virtual void proc() const {
+ mAdapter.savePowerStateCallback(mPowerStateCb);
+ mPowerStateCb(mAdapter.getPowerState());
+ }
+ };
+
+ sendMsg(new MsgReportLocation(*this, (powerStateCallback)powerStateCb));
+}
+
+void
+GnssAdapter::saveTrackingSession(LocationAPI* client, uint32_t sessionId,
+ const TrackingOptions& options)
+{
+ LocationSessionKey key(client, sessionId);
+ if ((options.minDistance > 0) &&
+ ContextBase::isMessageSupported(LOC_API_ADAPTER_MESSAGE_DISTANCE_BASE_TRACKING)) {
+ mDistanceBasedTrackingSessions[key] = options;
+ } else {
+ mTimeBasedTrackingSessions[key] = options;
+ }
+ reportPowerStateIfChanged();
+}
+
+void
+GnssAdapter::eraseTrackingSession(LocationAPI* client, uint32_t sessionId)
+{
+ LocationSessionKey key(client, sessionId);
+ auto it = mTimeBasedTrackingSessions.find(key);
+ if (it != mTimeBasedTrackingSessions.end()) {
+ mTimeBasedTrackingSessions.erase(it);
+ } else {
+ auto itr = mDistanceBasedTrackingSessions.find(key);
+ if (itr != mDistanceBasedTrackingSessions.end()) {
+ mDistanceBasedTrackingSessions.erase(itr);
+ }
+ }
+ reportPowerStateIfChanged();
+}
+
+
+bool GnssAdapter::setLocPositionMode(const LocPosMode& mode) {
+ if (!mLocPositionMode.equals(mode)) {
+ mLocPositionMode = mode;
+ return true;
+ } else {
+ return false;
+ }
+}
+
+void
+GnssAdapter::reportResponse(LocationAPI* client, LocationError err, uint32_t sessionId)
+{
+ LOC_LOGD("%s]: client %p id %u err %u", __func__, client, sessionId, err);
+
+ auto it = mClientData.find(client);
+ if (it != mClientData.end() && it->second.responseCb != nullptr) {
+ it->second.responseCb(err, sessionId);
+ } else {
+ LOC_LOGW("%s]: client %p id %u not found in data", __func__, client, sessionId);
+ }
+}
+
+void
+GnssAdapter::reportResponse(LocationError err, uint32_t sessionId)
+{
+ LOC_LOGD("%s]: id %u err %u", __func__, sessionId, err);
+
+ if (mControlCallbacks.size > 0 && mControlCallbacks.responseCb != nullptr) {
+ mControlCallbacks.responseCb(err, sessionId);
+ } else {
+ LOC_LOGW("%s]: control client response callback not found", __func__);
+ }
+}
+
+void
+GnssAdapter::reportResponse(size_t count, LocationError* errs, uint32_t* ids)
+{
+ IF_LOC_LOGD {
+ std::string idsString = "[";
+ std::string errsString = "[";
+ if (NULL != ids && NULL != errs) {
+ for (size_t i=0; i < count; ++i) {
+ idsString += std::to_string(ids[i]) + " ";
+ errsString += std::to_string(errs[i]) + " ";
+ }
+ }
+ idsString += "]";
+ errsString += "]";
+
+ LOC_LOGD("%s]: ids %s errs %s",
+ __func__, idsString.c_str(), errsString.c_str());
+ }
+
+ if (mControlCallbacks.size > 0 && mControlCallbacks.collectiveResponseCb != nullptr) {
+ mControlCallbacks.collectiveResponseCb(count, errs, ids);
+ } else {
+ LOC_LOGW("%s]: control client callback not found", __func__);
+ }
+}
+
+uint32_t
+GnssAdapter::startTrackingCommand(LocationAPI* client, TrackingOptions& options)
+{
+ uint32_t sessionId = generateSessionId();
+ LOC_LOGD("%s]: client %p id %u minInterval %u minDistance %u mode %u powermode %u tbm %u",
+ __func__, client, sessionId, options.minInterval, options.minDistance, options.mode,
+ options.powerMode, options.tbm);
+
+ struct MsgStartTracking : public LocMsg {
+ GnssAdapter& mAdapter;
+ LocApiBase& mApi;
+ LocationAPI* mClient;
+ uint32_t mSessionId;
+ mutable TrackingOptions mOptions;
+ inline MsgStartTracking(GnssAdapter& adapter,
+ LocApiBase& api,
+ LocationAPI* client,
+ uint32_t sessionId,
+ TrackingOptions options) :
+ LocMsg(),
+ mAdapter(adapter),
+ mApi(api),
+ mClient(client),
+ mSessionId(sessionId),
+ mOptions(options) {}
+ inline virtual void proc() const {
+ // distance based tracking will need to know engine capabilities before it can start
+ if (!mAdapter.isEngineCapabilitiesKnown() && mOptions.minDistance > 0) {
+ mAdapter.mPendingMsgs.push_back(new MsgStartTracking(*this));
+ return;
+ }
+ LocationError err = LOCATION_ERROR_SUCCESS;
+ if (!mAdapter.hasTrackingCallback(mClient) &&
+ !mAdapter.hasMeasurementsCallback(mClient)) {
+ err = LOCATION_ERROR_CALLBACK_MISSING;
+ } else if (0 == mOptions.size) {
+ err = LOCATION_ERROR_INVALID_PARAMETER;
+ } else {
+ if (mOptions.minInterval < MIN_TRACKING_INTERVAL) {
+ mOptions.minInterval = MIN_TRACKING_INTERVAL;
+ }
+ if (mOptions.minDistance > 0 &&
+ ContextBase::isMessageSupported(
+ LOC_API_ADAPTER_MESSAGE_DISTANCE_BASE_TRACKING)) {
+ mAdapter.saveTrackingSession(mClient, mSessionId, mOptions);
+ mApi.startDistanceBasedTracking(mSessionId, mOptions,
+ new LocApiResponse(*mAdapter.getContext(),
+ [&mAdapter = mAdapter, mSessionId = mSessionId, mClient = mClient]
+ (LocationError err) {
+ if (LOCATION_ERROR_SUCCESS != err) {
+ mAdapter.eraseTrackingSession(mClient, mSessionId);
+ }
+ mAdapter.reportResponse(mClient, err, mSessionId);
+ }));
+ } else {
+ if (GNSS_POWER_MODE_M4 == mOptions.powerMode &&
+ mOptions.tbm > TRACKING_TBM_THRESHOLD_MILLIS) {
+ LOC_LOGd("TBM (%d) > %d Falling back to M2 power mode",
+ mOptions.tbm, TRACKING_TBM_THRESHOLD_MILLIS);
+ mOptions.powerMode = GNSS_POWER_MODE_M2;
+ }
+ // Api doesn't support multiple clients for time based tracking, so mutiplex
+ bool reportToClientWithNoWait =
+ mAdapter.startTimeBasedTrackingMultiplex(mClient, mSessionId, mOptions);
+ mAdapter.saveTrackingSession(mClient, mSessionId, mOptions);
+
+ if (reportToClientWithNoWait) {
+ mAdapter.reportResponse(mClient, LOCATION_ERROR_SUCCESS, mSessionId);
+ }
+ }
+ }
+ }
+ };
+
+ sendMsg(new MsgStartTracking(*this, *mLocApi, client, sessionId, options));
+ return sessionId;
+
+}
+
+bool
+GnssAdapter::startTimeBasedTrackingMultiplex(LocationAPI* client, uint32_t sessionId,
+ const TrackingOptions& options)
+{
+ bool reportToClientWithNoWait = true;
+
+ if (mTimeBasedTrackingSessions.empty()) {
+ startTimeBasedTracking(client, sessionId, options);
+ // need to wait for QMI callback
+ reportToClientWithNoWait = false;
+ } else {
+ // find the smallest interval and powerMode
+ TrackingOptions multiplexedOptions = {}; // size is 0 until set for the first time
+ GnssPowerMode multiplexedPowerMode = GNSS_POWER_MODE_INVALID;
+ memset(&multiplexedOptions, 0, sizeof(multiplexedOptions));
+ for (auto it = mTimeBasedTrackingSessions.begin(); it != mTimeBasedTrackingSessions.end(); ++it) {
+ // if not set or there is a new smallest interval, then set the new interval
+ if (0 == multiplexedOptions.size ||
+ it->second.minInterval < multiplexedOptions.minInterval) {
+ multiplexedOptions = it->second;
+ }
+ // if session is not the one we are updating and either powerMode
+ // is not set or there is a new smallest powerMode, then set the new powerMode
+ if (GNSS_POWER_MODE_INVALID == multiplexedPowerMode ||
+ it->second.powerMode < multiplexedPowerMode) {
+ multiplexedPowerMode = it->second.powerMode;
+ }
+ }
+ bool updateOptions = false;
+ // if session we are starting has smaller interval then next smallest
+ if (options.minInterval < multiplexedOptions.minInterval) {
+ multiplexedOptions.minInterval = options.minInterval;
+ updateOptions = true;
+ }
+ // if session we are starting has smaller powerMode then next smallest
+ if (options.powerMode < multiplexedPowerMode) {
+ multiplexedOptions.powerMode = options.powerMode;
+ updateOptions = true;
+ }
+ if (updateOptions) {
+ // restart time based tracking with the newly updated options
+
+ startTimeBasedTracking(client, sessionId, multiplexedOptions);
+ // need to wait for QMI callback
+ reportToClientWithNoWait = false;
+ }
+ // else part: no QMI call is made, need to report back to client right away
+ }
+
+ return reportToClientWithNoWait;
+}
+
+void
+GnssAdapter::startTimeBasedTracking(LocationAPI* client, uint32_t sessionId,
+ const TrackingOptions& trackingOptions)
+{
+ LOC_LOGd("minInterval %u minDistance %u mode %u powermode %u tbm %u",
+ trackingOptions.minInterval, trackingOptions.minDistance,
+ trackingOptions.mode, trackingOptions.powerMode, trackingOptions.tbm);
+
+ LocPosMode locPosMode = {};
+ convertOptions(locPosMode, trackingOptions);
+
+ // inform engine hub that GNSS session is about to start
+ mEngHubProxy->gnssSetFixMode(locPosMode);
+ mEngHubProxy->gnssStartFix();
+
+ mLocApi->startTimeBasedTracking(trackingOptions, new LocApiResponse(*getContext(),
+ [this, client, sessionId] (LocationError err) {
+ if (LOCATION_ERROR_SUCCESS != err) {
+ eraseTrackingSession(client, sessionId);
+ }
+
+ reportResponse(client, err, sessionId);
+ }
+ ));
+}
+
+void
+GnssAdapter::updateTracking(LocationAPI* client, uint32_t sessionId,
+ const TrackingOptions& updatedOptions, const TrackingOptions& oldOptions)
+{
+ LocPosMode locPosMode = {};
+ convertOptions(locPosMode, updatedOptions);
+
+ // inform engine hub that GNSS session is about to start
+ mEngHubProxy->gnssSetFixMode(locPosMode);
+ mEngHubProxy->gnssStartFix();
+
+ mLocApi->startTimeBasedTracking(updatedOptions, new LocApiResponse(*getContext(),
+ [this, client, sessionId, oldOptions] (LocationError err) {
+ if (LOCATION_ERROR_SUCCESS != err) {
+ // restore the old LocationOptions
+ saveTrackingSession(client, sessionId, oldOptions);
+ }
+
+ reportResponse(client, err, sessionId);
+ }
+ ));
+}
+
+void
+GnssAdapter::updateTrackingOptionsCommand(LocationAPI* client, uint32_t id,
+ TrackingOptions& options)
+{
+ LOC_LOGD("%s]: client %p id %u minInterval %u mode %u",
+ __func__, client, id, options.minInterval, options.mode);
+
+ struct MsgUpdateTracking : public LocMsg {
+ GnssAdapter& mAdapter;
+ LocApiBase& mApi;
+ LocationAPI* mClient;
+ uint32_t mSessionId;
+ mutable TrackingOptions mOptions;
+ inline MsgUpdateTracking(GnssAdapter& adapter,
+ LocApiBase& api,
+ LocationAPI* client,
+ uint32_t sessionId,
+ TrackingOptions options) :
+ LocMsg(),
+ mAdapter(adapter),
+ mApi(api),
+ mClient(client),
+ mSessionId(sessionId),
+ mOptions(options) {}
+ inline virtual void proc() const {
+ // distance based tracking will need to know engine capabilities before it can start
+ if (!mAdapter.isEngineCapabilitiesKnown() && mOptions.minDistance > 0) {
+ mAdapter.mPendingMsgs.push_back(new MsgUpdateTracking(*this));
+ return;
+ }
+ LocationError err = LOCATION_ERROR_SUCCESS;
+ bool isTimeBased = mAdapter.isTimeBasedTrackingSession(mClient, mSessionId);
+ bool isDistanceBased = mAdapter.isDistanceBasedTrackingSession(mClient, mSessionId);
+ if (!isTimeBased && !isDistanceBased) {
+ err = LOCATION_ERROR_ID_UNKNOWN;
+ } else if (0 == mOptions.size) {
+ err = LOCATION_ERROR_INVALID_PARAMETER;
+ }
+ if (LOCATION_ERROR_SUCCESS != err) {
+ mAdapter.reportResponse(mClient, err, mSessionId);
+ } else {
+ if (GNSS_POWER_MODE_M4 == mOptions.powerMode &&
+ mOptions.tbm > TRACKING_TBM_THRESHOLD_MILLIS) {
+ LOC_LOGd("TBM (%d) > %d Falling back to M2 power mode",
+ mOptions.tbm, TRACKING_TBM_THRESHOLD_MILLIS);
+ mOptions.powerMode = GNSS_POWER_MODE_M2;
+ }
+ if (mOptions.minInterval < MIN_TRACKING_INTERVAL) {
+ mOptions.minInterval = MIN_TRACKING_INTERVAL;
+ }
+ // Now update session as required
+ if (isTimeBased && mOptions.minDistance > 0) {
+ // switch from time based to distance based
+ // Api doesn't support multiple clients for time based tracking, so mutiplex
+ bool reportToClientWithNoWait =
+ mAdapter.stopTimeBasedTrackingMultiplex(mClient, mSessionId);
+ // erases the time based Session
+ mAdapter.eraseTrackingSession(mClient, mSessionId);
+ if (reportToClientWithNoWait) {
+ mAdapter.reportResponse(mClient, LOCATION_ERROR_SUCCESS, mSessionId);
+ }
+ // saves as distance based Session
+ mAdapter.saveTrackingSession(mClient, mSessionId, mOptions);
+ mApi.startDistanceBasedTracking(mSessionId, mOptions,
+ new LocApiResponse(*mAdapter.getContext(),
+ [] (LocationError /*err*/) {}));
+ } else if (isDistanceBased && mOptions.minDistance == 0) {
+ // switch from distance based to time based
+ mAdapter.eraseTrackingSession(mClient, mSessionId);
+ mApi.stopDistanceBasedTracking(mSessionId, new LocApiResponse(
+ *mAdapter.getContext(),
+ [&mAdapter = mAdapter, mSessionId = mSessionId, mOptions = mOptions,
+ mClient = mClient] (LocationError /*err*/) {
+ // Api doesn't support multiple clients for time based tracking,
+ // so mutiplex
+ bool reportToClientWithNoWait =
+ mAdapter.startTimeBasedTrackingMultiplex(mClient, mSessionId,
+ mOptions);
+ mAdapter.saveTrackingSession(mClient, mSessionId, mOptions);
+
+ if (reportToClientWithNoWait) {
+ mAdapter.reportResponse(mClient, LOCATION_ERROR_SUCCESS, mSessionId);
+ }
+ }));
+ } else if (isTimeBased) {
+ // update time based tracking
+ // Api doesn't support multiple clients for time based tracking, so mutiplex
+ bool reportToClientWithNoWait =
+ mAdapter.updateTrackingMultiplex(mClient, mSessionId, mOptions);
+ mAdapter.saveTrackingSession(mClient, mSessionId, mOptions);
+
+ if (reportToClientWithNoWait) {
+ mAdapter.reportResponse(mClient, err, mSessionId);
+ }
+ } else if (isDistanceBased) {
+ // restart distance based tracking
+ mApi.stopDistanceBasedTracking(mSessionId, new LocApiResponse(
+ *mAdapter.getContext(),
+ [&mAdapter = mAdapter, mSessionId = mSessionId, mOptions = mOptions,
+ mClient = mClient, &mApi = mApi] (LocationError err) {
+ if (LOCATION_ERROR_SUCCESS == err) {
+ mApi.startDistanceBasedTracking(mSessionId, mOptions,
+ new LocApiResponse(*mAdapter.getContext(),
+ [&mAdapter, mClient, mSessionId, mOptions]
+ (LocationError err) {
+ if (LOCATION_ERROR_SUCCESS == err) {
+ mAdapter.saveTrackingSession(mClient, mSessionId, mOptions);
+ }
+ mAdapter.reportResponse(mClient, err, mSessionId);
+ }));
+ }
+ }));
+ }
+ }
+ }
+ };
+
+ sendMsg(new MsgUpdateTracking(*this, *mLocApi, client, id, options));
+}
+
+bool
+GnssAdapter::updateTrackingMultiplex(LocationAPI* client, uint32_t id,
+ const TrackingOptions& trackingOptions)
+{
+ bool reportToClientWithNoWait = true;
+
+ LocationSessionKey key(client, id);
+ // get the session we are updating
+ auto it = mTimeBasedTrackingSessions.find(key);
+
+ // cache the clients existing LocationOptions
+ TrackingOptions oldOptions = it->second;
+
+ // if session we are updating exists and the minInterval or powerMode has changed
+ if (it != mTimeBasedTrackingSessions.end() &&
+ (it->second.minInterval != trackingOptions.minInterval ||
+ it->second.powerMode != trackingOptions.powerMode)) {
+ // find the smallest interval and powerMode, other than the session we are updating
+ TrackingOptions multiplexedOptions = {}; // size is 0 until set for the first time
+ GnssPowerMode multiplexedPowerMode = GNSS_POWER_MODE_INVALID;
+ memset(&multiplexedOptions, 0, sizeof(multiplexedOptions));
+ for (auto it2 = mTimeBasedTrackingSessions.begin();
+ it2 != mTimeBasedTrackingSessions.end(); ++it2) {
+ // if session is not the one we are updating and either interval
+ // is not set or there is a new smallest interval, then set the new interval
+ if (it2->first != key && (0 == multiplexedOptions.size ||
+ it2->second.minInterval < multiplexedOptions.minInterval)) {
+ multiplexedOptions = it2->second;
+ }
+ // if session is not the one we are updating and either powerMode
+ // is not set or there is a new smallest powerMode, then set the new powerMode
+ if (it2->first != key && (GNSS_POWER_MODE_INVALID == multiplexedPowerMode ||
+ it2->second.powerMode < multiplexedPowerMode)) {
+ multiplexedPowerMode = it2->second.powerMode;
+ }
+ // else part: no QMI call is made, need to report back to client right away
+ }
+ bool updateOptions = false;
+ // if session we are updating has smaller interval then next smallest
+ if (trackingOptions.minInterval < multiplexedOptions.minInterval) {
+ multiplexedOptions.minInterval = trackingOptions.minInterval;
+ updateOptions = true;
+ }
+ // if session we are updating has smaller powerMode then next smallest
+ if (trackingOptions.powerMode < multiplexedPowerMode) {
+ multiplexedOptions.powerMode = trackingOptions.powerMode;
+ updateOptions = true;
+ }
+ // if only one session exists, then tracking should be updated with it
+ if (1 == mTimeBasedTrackingSessions.size()) {
+ multiplexedOptions = trackingOptions;
+ updateOptions = true;
+ }
+ if (updateOptions) {
+ // restart time based tracking with the newly updated options
+ updateTracking(client, id, multiplexedOptions, oldOptions);
+ // need to wait for QMI callback
+ reportToClientWithNoWait = false;
+ }
+ }
+
+ return reportToClientWithNoWait;
+}
+
+void
+GnssAdapter::stopTrackingCommand(LocationAPI* client, uint32_t id)
+{
+ LOC_LOGD("%s]: client %p id %u", __func__, client, id);
+
+ struct MsgStopTracking : public LocMsg {
+ GnssAdapter& mAdapter;
+ LocApiBase& mApi;
+ LocationAPI* mClient;
+ uint32_t mSessionId;
+ inline MsgStopTracking(GnssAdapter& adapter,
+ LocApiBase& api,
+ LocationAPI* client,
+ uint32_t sessionId) :
+ LocMsg(),
+ mAdapter(adapter),
+ mApi(api),
+ mClient(client),
+ mSessionId(sessionId) {}
+ inline virtual void proc() const {
+ bool isTimeBased = mAdapter.isTimeBasedTrackingSession(mClient, mSessionId);
+ bool isDistanceBased = mAdapter.isDistanceBasedTrackingSession(mClient, mSessionId);
+ if (isTimeBased || isDistanceBased) {
+ if (isTimeBased) {
+ // Api doesn't support multiple clients for time based tracking, so mutiplex
+ bool reportToClientWithNoWait =
+ mAdapter.stopTimeBasedTrackingMultiplex(mClient, mSessionId);
+ mAdapter.eraseTrackingSession(mClient, mSessionId);
+
+ if (reportToClientWithNoWait) {
+ mAdapter.reportResponse(mClient, LOCATION_ERROR_SUCCESS, mSessionId);
+ }
+ } else if (isDistanceBased) {
+ mApi.stopDistanceBasedTracking(mSessionId, new LocApiResponse(
+ *mAdapter.getContext(),
+ [&mAdapter = mAdapter, mSessionId = mSessionId, mClient = mClient]
+ (LocationError err) {
+ if (LOCATION_ERROR_SUCCESS == err) {
+ mAdapter.eraseTrackingSession(mClient, mSessionId);
+ }
+ mAdapter.reportResponse(mClient, err, mSessionId);
+ }));
+ }
+ } else {
+ mAdapter.reportResponse(mClient, LOCATION_ERROR_ID_UNKNOWN, mSessionId);
+ }
+
+ }
+ };
+
+ sendMsg(new MsgStopTracking(*this, *mLocApi, client, id));
+}
+
+bool
+GnssAdapter::stopTimeBasedTrackingMultiplex(LocationAPI* client, uint32_t id)
+{
+ bool reportToClientWithNoWait = true;
+
+ if (1 == mTimeBasedTrackingSessions.size()) {
+ stopTracking(client, id);
+ // need to wait for QMI callback
+ reportToClientWithNoWait = false;
+ } else {
+ LocationSessionKey key(client, id);
+
+ // get the session we are stopping
+ auto it = mTimeBasedTrackingSessions.find(key);
+ if (it != mTimeBasedTrackingSessions.end()) {
+ // find the smallest interval and powerMode, other than the session we are stopping
+ TrackingOptions multiplexedOptions = {}; // size is 0 until set for the first time
+ GnssPowerMode multiplexedPowerMode = GNSS_POWER_MODE_INVALID;
+ memset(&multiplexedOptions, 0, sizeof(multiplexedOptions));
+ for (auto it2 = mTimeBasedTrackingSessions.begin();
+ it2 != mTimeBasedTrackingSessions.end(); ++it2) {
+ // if session is not the one we are stopping and either interval
+ // is not set or there is a new smallest interval, then set the new interval
+ if (it2->first != key && (0 == multiplexedOptions.size ||
+ it2->second.minInterval < multiplexedOptions.minInterval)) {
+ multiplexedOptions = it2->second;
+ }
+ // if session is not the one we are stopping and either powerMode
+ // is not set or there is a new smallest powerMode, then set the new powerMode
+ if (it2->first != key && (GNSS_POWER_MODE_INVALID == multiplexedPowerMode ||
+ it2->second.powerMode < multiplexedPowerMode)) {
+ multiplexedPowerMode = it2->second.powerMode;
+ }
+ }
+ // if session we are stopping has smaller interval then next smallest or
+ // if session we are stopping has smaller powerMode then next smallest
+ if (it->second.minInterval < multiplexedOptions.minInterval ||
+ it->second.powerMode < multiplexedPowerMode) {
+ multiplexedOptions.powerMode = multiplexedPowerMode;
+ // restart time based tracking with the newly updated options
+ startTimeBasedTracking(client, id, multiplexedOptions);
+ // need to wait for QMI callback
+ reportToClientWithNoWait = false;
+ }
+ // else part: no QMI call is made, need to report back to client right away
+ }
+ }
+
+ return reportToClientWithNoWait;
+}
+
+void
+GnssAdapter::stopTracking(LocationAPI* client, uint32_t id)
+{
+ // inform engine hub that GNSS session has stopped
+ mEngHubProxy->gnssStopFix();
+
+ mLocApi->stopFix(new LocApiResponse(*getContext(),
+ [this, client, id] (LocationError err) {
+ reportResponse(client, err, id);
+ }));
+}
+
+bool
+GnssAdapter::hasNiNotifyCallback(LocationAPI* client)
+{
+ auto it = mClientData.find(client);
+ return (it != mClientData.end() && it->second.gnssNiCb);
+}
+
+void
+GnssAdapter::gnssNiResponseCommand(LocationAPI* client,
+ uint32_t id,
+ GnssNiResponse response)
+{
+ LOC_LOGD("%s]: client %p id %u response %u", __func__, client, id, response);
+
+ struct MsgGnssNiResponse : public LocMsg {
+ GnssAdapter& mAdapter;
+ LocationAPI* mClient;
+ uint32_t mSessionId;
+ GnssNiResponse mResponse;
+ inline MsgGnssNiResponse(GnssAdapter& adapter,
+ LocationAPI* client,
+ uint32_t sessionId,
+ GnssNiResponse response) :
+ LocMsg(),
+ mAdapter(adapter),
+ mClient(client),
+ mSessionId(sessionId),
+ mResponse(response) {}
+ inline virtual void proc() const {
+ NiData& niData = mAdapter.getNiData();
+ LocationError err = LOCATION_ERROR_SUCCESS;
+ if (!mAdapter.hasNiNotifyCallback(mClient)) {
+ err = LOCATION_ERROR_ID_UNKNOWN;
+ } else {
+ NiSession* pSession = NULL;
+ if (mSessionId == niData.sessionEs.reqID &&
+ NULL != niData.sessionEs.rawRequest) {
+ pSession = &niData.sessionEs;
+ // ignore any SUPL NI non-Es session if a SUPL NI ES is accepted
+ if (mResponse == GNSS_NI_RESPONSE_ACCEPT &&
+ NULL != niData.session.rawRequest) {
+ pthread_mutex_lock(&niData.session.tLock);
+ niData.session.resp = GNSS_NI_RESPONSE_IGNORE;
+ niData.session.respRecvd = true;
+ pthread_cond_signal(&niData.session.tCond);
+ pthread_mutex_unlock(&niData.session.tLock);
+ }
+ } else if (mSessionId == niData.session.reqID &&
+ NULL != niData.session.rawRequest) {
+ pSession = &niData.session;
+ }
+
+ if (pSession) {
+ LOC_LOGI("%s]: gnssNiResponseCommand: send user mResponse %u for id %u",
+ __func__, mResponse, mSessionId);
+ pthread_mutex_lock(&pSession->tLock);
+ pSession->resp = mResponse;
+ pSession->respRecvd = true;
+ pthread_cond_signal(&pSession->tCond);
+ pthread_mutex_unlock(&pSession->tLock);
+ } else {
+ err = LOCATION_ERROR_ID_UNKNOWN;
+ LOC_LOGE("%s]: gnssNiResponseCommand: id %u not an active session",
+ __func__, mSessionId);
+ }
+ }
+ mAdapter.reportResponse(mClient, err, mSessionId);
+ }
+ };
+
+ sendMsg(new MsgGnssNiResponse(*this, client, id, response));
+
+}
+
+void
+GnssAdapter::gnssNiResponseCommand(GnssNiResponse response, void* rawRequest)
+{
+ LOC_LOGD("%s]: response %u", __func__, response);
+
+ struct MsgGnssNiResponse : public LocMsg {
+ GnssAdapter& mAdapter;
+ LocApiBase& mApi;
+ const GnssNiResponse mResponse;
+ const void* mPayload;
+ inline MsgGnssNiResponse(GnssAdapter& adapter,
+ LocApiBase& api,
+ const GnssNiResponse response,
+ const void* rawRequest) :
+ LocMsg(),
+ mAdapter(adapter),
+ mApi(api),
+ mResponse(response),
+ mPayload(rawRequest) {}
+ inline virtual ~MsgGnssNiResponse() {
+ }
+ inline virtual void proc() const {
+ mApi.informNiResponse(mResponse, mPayload);
+ }
+ };
+
+ sendMsg(new MsgGnssNiResponse(*this, *mLocApi, response, rawRequest));
+
+}
+
+uint32_t
+GnssAdapter::enableCommand(LocationTechnologyType techType)
+{
+ uint32_t sessionId = generateSessionId();
+ LOC_LOGD("%s]: id %u techType %u", __func__, sessionId, techType);
+
+ struct MsgEnableGnss : public LocMsg {
+ GnssAdapter& mAdapter;
+ LocApiBase& mApi;
+ ContextBase& mContext;
+ uint32_t mSessionId;
+ LocationTechnologyType mTechType;
+ inline MsgEnableGnss(GnssAdapter& adapter,
+ LocApiBase& api,
+ ContextBase& context,
+ uint32_t sessionId,
+ LocationTechnologyType techType) :
+ LocMsg(),
+ mAdapter(adapter),
+ mApi(api),
+ mContext(context),
+ mSessionId(sessionId),
+ mTechType(techType) {}
+ inline virtual void proc() const {
+ LocationError err = LOCATION_ERROR_SUCCESS;
+ uint32_t afwControlId = mAdapter.getAfwControlId();
+ if (mTechType != LOCATION_TECHNOLOGY_TYPE_GNSS) {
+ err = LOCATION_ERROR_INVALID_PARAMETER;
+ } else if (afwControlId > 0) {
+ err = LOCATION_ERROR_ALREADY_STARTED;
+ } else {
+ mContext.modemPowerVote(true);
+ mAdapter.setAfwControlId(mSessionId);
+
+ GnssConfigGpsLock gpsLock = GNSS_CONFIG_GPS_LOCK_NONE;
+ if (mAdapter.mSupportNfwControl) {
+ ContextBase::mGps_conf.GPS_LOCK &= GNSS_CONFIG_GPS_LOCK_NI;
+ gpsLock = ContextBase::mGps_conf.GPS_LOCK;
+ }
+ mApi.sendMsg(new LocApiMsg([&mApi = mApi, gpsLock]() {
+ mApi.setGpsLockSync(gpsLock);
+ }));
+ mAdapter.mXtraObserver.updateLockStatus(gpsLock);
+ }
+ mAdapter.reportResponse(err, mSessionId);
+ }
+ };
+
+ if (mContext != NULL) {
+ sendMsg(new MsgEnableGnss(*this, *mLocApi, *mContext, sessionId, techType));
+ } else {
+ LOC_LOGE("%s]: Context is NULL", __func__);
+ }
+
+ return sessionId;
+}
+
+void
+GnssAdapter::disableCommand(uint32_t id)
+{
+ LOC_LOGD("%s]: id %u", __func__, id);
+
+ struct MsgDisableGnss : public LocMsg {
+ GnssAdapter& mAdapter;
+ LocApiBase& mApi;
+ ContextBase& mContext;
+ uint32_t mSessionId;
+ inline MsgDisableGnss(GnssAdapter& adapter,
+ LocApiBase& api,
+ ContextBase& context,
+ uint32_t sessionId) :
+ LocMsg(),
+ mAdapter(adapter),
+ mApi(api),
+ mContext(context),
+ mSessionId(sessionId) {}
+ inline virtual void proc() const {
+ LocationError err = LOCATION_ERROR_SUCCESS;
+ uint32_t afwControlId = mAdapter.getAfwControlId();
+ if (afwControlId != mSessionId) {
+ err = LOCATION_ERROR_ID_UNKNOWN;
+ } else {
+ mContext.modemPowerVote(false);
+ mAdapter.setAfwControlId(0);
+
+ if (mAdapter.mSupportNfwControl) {
+ /* We need to disable MO (AFW) */
+ ContextBase::mGps_conf.GPS_LOCK |= GNSS_CONFIG_GPS_LOCK_MO;
+ }
+ GnssConfigGpsLock gpsLock = ContextBase::mGps_conf.GPS_LOCK;
+ mApi.sendMsg(new LocApiMsg([&mApi = mApi, gpsLock]() {
+ mApi.setGpsLockSync(gpsLock);
+ }));
+ mAdapter.mXtraObserver.updateLockStatus(gpsLock);
+ }
+ mAdapter.reportResponse(err, mSessionId);
+ }
+ };
+
+ if (mContext != NULL) {
+ sendMsg(new MsgDisableGnss(*this, *mLocApi, *mContext, id));
+ }
+
+}
+
+void
+GnssAdapter::reportPositionEvent(const UlpLocation& ulpLocation,
+ const GpsLocationExtended& locationExtended,
+ enum loc_sess_status status,
+ LocPosTechMask techMask,
+ GnssDataNotification* pDataNotify,
+ int msInWeek)
+{
+ // this position is from QMI LOC API, then send report to engine hub
+ // if sending is successful, we return as we will wait for final report from engine hub
+ // if the position is called from engine hub, then send it out directly
+
+ if (true == initEngHubProxy()){
+ mEngHubProxy->gnssReportPosition(ulpLocation, locationExtended, status);
+ return;
+ }
+
+ if (true == ulpLocation.unpropagatedPosition) {
+ return;
+ }
+
+ // Fix is from QMI, and it is not an
+ // unpropagated position and engine hub is not loaded, queue the msg
+ // when message is queued, the position can be dispatched to requesting client
+ struct MsgReportPosition : public LocMsg {
+ GnssAdapter& mAdapter;
+ const UlpLocation mUlpLocation;
+ const GpsLocationExtended mLocationExtended;
+ loc_sess_status mStatus;
+ LocPosTechMask mTechMask;
+ GnssDataNotification mDataNotify;
+ int mMsInWeek;
+ bool mbIsDataValid;
+ inline MsgReportPosition(GnssAdapter& adapter,
+ const UlpLocation& ulpLocation,
+ const GpsLocationExtended& locationExtended,
+ loc_sess_status status,
+ LocPosTechMask techMask,
+ GnssDataNotification* pDataNotify,
+ int msInWeek) :
+ LocMsg(),
+ mAdapter(adapter),
+ mUlpLocation(ulpLocation),
+ mLocationExtended(locationExtended),
+ mStatus(status),
+ mTechMask(techMask),
+ mMsInWeek(msInWeek) {
+ memset(&mDataNotify, 0, sizeof(mDataNotify));
+ if (pDataNotify != nullptr) {
+ mDataNotify = *pDataNotify;
+ mbIsDataValid = true;
+ } else {
+ mbIsDataValid = false;
+ }
+ }
+ inline virtual void proc() const {
+ // extract bug report info - this returns true if consumed by systemstatus
+ SystemStatus* s = mAdapter.getSystemStatus();
+ if ((nullptr != s) &&
+ ((LOC_SESS_SUCCESS == mStatus) || (LOC_SESS_INTERMEDIATE == mStatus))){
+ s->eventPosition(mUlpLocation, mLocationExtended);
+ }
+ mAdapter.reportPosition(mUlpLocation, mLocationExtended, mStatus, mTechMask);
+ if (true == mbIsDataValid) {
+ if (-1 != mMsInWeek) {
+ mAdapter.getDataInformation((GnssDataNotification&)mDataNotify,
+ mMsInWeek);
+ }
+ mAdapter.reportData((GnssDataNotification&)mDataNotify);
+ }
+ }
+ };
+
+ sendMsg(new MsgReportPosition(*this, ulpLocation, locationExtended,
+ status, techMask,
+ pDataNotify, msInWeek));
+}
+
+void
+GnssAdapter::reportEnginePositionsEvent(unsigned int count,
+ EngineLocationInfo* locationArr)
+{
+ struct MsgReportEnginePositions : public LocMsg {
+ GnssAdapter& mAdapter;
+ unsigned int mCount;
+ EngineLocationInfo mEngLocInfo[LOC_OUTPUT_ENGINE_COUNT];
+ inline MsgReportEnginePositions(GnssAdapter& adapter,
+ unsigned int count,
+ EngineLocationInfo* locationArr) :
+ LocMsg(),
+ mAdapter(adapter),
+ mCount(count) {
+ if (mCount > LOC_OUTPUT_ENGINE_COUNT) {
+ mCount = LOC_OUTPUT_ENGINE_COUNT;
+ }
+ if (mCount > 0) {
+ memcpy(mEngLocInfo, locationArr, sizeof(EngineLocationInfo)*mCount);
+ }
+ }
+ inline virtual void proc() const {
+ mAdapter.reportEnginePositions(mCount, mEngLocInfo);
+ }
+ };
+
+ sendMsg(new MsgReportEnginePositions(*this, count, locationArr));
+}
+
+bool
+GnssAdapter::needReportForGnssClient(const UlpLocation& ulpLocation,
+ enum loc_sess_status status,
+ LocPosTechMask techMask) {
+ bool reported = false;
+
+ // if engine hub is enabled, aka, any of the engine services is enabled,
+ // then always output position reported by engine hub to requesting client
+ if (true == initEngHubProxy()) {
+ reported = true;
+ } else {
+ reported = LocApiBase::needReport(ulpLocation, status, techMask);
+ }
+ return reported;
+}
+
+bool
+GnssAdapter::needReportForFlpClient(enum loc_sess_status status,
+ LocPosTechMask techMask) {
+ if ((status == LOC_SESS_INTERMEDIATE) &&
+ !(techMask & LOC_POS_TECH_MASK_SENSORS) &&
+ (!getAllowFlpNetworkFixes())) {
+ return false;
+ } else {
+ return true;
+ }
+}
+
+bool
+GnssAdapter::isFlpClient(LocationCallbacks& locationCallbacks)
+{
+ return (locationCallbacks.gnssLocationInfoCb == nullptr &&
+ locationCallbacks.gnssSvCb == nullptr &&
+ locationCallbacks.gnssNmeaCb == nullptr &&
+ locationCallbacks.gnssDataCb == nullptr &&
+ locationCallbacks.gnssMeasurementsCb == nullptr);
+}
+
+void
+GnssAdapter::reportPosition(const UlpLocation& ulpLocation,
+ const GpsLocationExtended& locationExtended,
+ enum loc_sess_status status,
+ LocPosTechMask techMask)
+{
+ bool reportToGnssClient = needReportForGnssClient(ulpLocation, status, techMask);
+ bool reportToFlpClient = needReportForFlpClient(status, techMask);
+
+ if (reportToGnssClient || reportToFlpClient) {
+ GnssLocationInfoNotification locationInfo = {};
+ convertLocationInfo(locationInfo, locationExtended);
+ convertLocation(locationInfo.location, ulpLocation, locationExtended, techMask);
+
+ for (auto it=mClientData.begin(); it != mClientData.end(); ++it) {
+ if ((reportToFlpClient && isFlpClient(it->second)) ||
+ (reportToGnssClient && !isFlpClient(it->second))) {
+ if (nullptr != it->second.gnssLocationInfoCb) {
+ it->second.gnssLocationInfoCb(locationInfo);
+ } else if ((nullptr != it->second.engineLocationsInfoCb) &&
+ (false == initEngHubProxy())) {
+ // if engine hub is disabled, this is SPE fix from modem
+ // we need to mark one copy marked as fused and one copy marked as PPE
+ // and dispatch it to the engineLocationsInfoCb
+ GnssLocationInfoNotification engLocationsInfo[2];
+ engLocationsInfo[0] = locationInfo;
+ engLocationsInfo[0].locOutputEngType = LOC_OUTPUT_ENGINE_FUSED;
+ engLocationsInfo[0].flags |= GNSS_LOCATION_INFO_OUTPUT_ENG_TYPE_BIT;
+ engLocationsInfo[1] = locationInfo;
+ it->second.engineLocationsInfoCb(2, engLocationsInfo);
+ } else if (nullptr != it->second.trackingCb) {
+ it->second.trackingCb(locationInfo.location);
+ }
+ }
+ }
+
+ mGnssSvIdUsedInPosAvail = false;
+ mGnssMbSvIdUsedInPosAvail = false;
+ if (reportToGnssClient) {
+ if (locationExtended.flags & GPS_LOCATION_EXTENDED_HAS_GNSS_SV_USED_DATA) {
+ mGnssSvIdUsedInPosAvail = true;
+ mGnssSvIdUsedInPosition = locationExtended.gnss_sv_used_ids;
+ if (locationExtended.flags & GPS_LOCATION_EXTENDED_HAS_MULTIBAND) {
+ mGnssMbSvIdUsedInPosAvail = true;
+ mGnssMbSvIdUsedInPosition = locationExtended.gnss_mb_sv_used_ids;
+ }
+ }
+
+ // if engine hub is running and the fix is from sensor, e.g.: DRE,
+ // inject DRE fix to modem
+ if ((1 == ContextBase::mGps_conf.POSITION_ASSISTED_CLOCK_ESTIMATOR_ENABLED) &&
+ (true == initEngHubProxy()) && (LOC_POS_TECH_MASK_SENSORS & techMask)) {
+ mLocApi->injectPosition(locationInfo, false);
+ }
+ }
+ }
+
+ if (NMEA_PROVIDER_AP == ContextBase::mGps_conf.NMEA_PROVIDER &&
+ !mTimeBasedTrackingSessions.empty()) {
+ /*Only BlankNMEA sentence needs to be processed and sent, if both lat, long is 0 &
+ horReliability is not set. */
+ bool blank_fix = ((0 == ulpLocation.gpsLocation.latitude) &&
+ (0 == ulpLocation.gpsLocation.longitude) &&
+ (LOC_RELIABILITY_NOT_SET == locationExtended.horizontal_reliability));
+ uint8_t generate_nmea = (reportToGnssClient && status != LOC_SESS_FAILURE && !blank_fix);
+ std::vector<std::string> nmeaArraystr;
+ loc_nmea_generate_pos(ulpLocation, locationExtended, mLocSystemInfo,
+ generate_nmea, nmeaArraystr);
+ stringstream ss;
+ for (auto itor = nmeaArraystr.begin(); itor != nmeaArraystr.end(); ++itor) {
+ ss << *itor;
+ }
+ string s = ss.str();
+ reportNmea(s.c_str(), s.length());
+ }
+}
+
+void
+GnssAdapter::reportEnginePositions(unsigned int count,
+ const EngineLocationInfo* locationArr)
+{
+ bool needReportEnginePositions = false;
+ for (auto it=mClientData.begin(); it != mClientData.end(); ++it) {
+ if (nullptr != it->second.engineLocationsInfoCb) {
+ needReportEnginePositions = true;
+ break;
+ }
+ }
+
+ GnssLocationInfoNotification locationInfo[LOC_OUTPUT_ENGINE_COUNT] = {};
+ for (unsigned int i = 0; i < count; i++) {
+ const EngineLocationInfo* engLocation = (locationArr+i);
+ // if it is fused/default location, call reportPosition maintain legacy behavior
+ if ((GPS_LOCATION_EXTENDED_HAS_OUTPUT_ENG_TYPE & engLocation->locationExtended.flags) &&
+ (LOC_OUTPUT_ENGINE_FUSED == engLocation->locationExtended.locOutputEngType)) {
+ reportPosition(engLocation->location,
+ engLocation->locationExtended,
+ engLocation->sessionStatus,
+ engLocation->location.tech_mask);
+ }
+
+ if (needReportEnginePositions) {
+ convertLocationInfo(locationInfo[i], engLocation->locationExtended);
+ convertLocation(locationInfo[i].location,
+ engLocation->location,
+ engLocation->locationExtended,
+ engLocation->location.tech_mask);
+ }
+ }
+
+ if (needReportEnginePositions) {
+ for (auto it=mClientData.begin(); it != mClientData.end(); ++it) {
+ if (nullptr != it->second.engineLocationsInfoCb) {
+ it->second.engineLocationsInfoCb(count, locationInfo);
+ }
+ }
+ }
+}
+
+void
+GnssAdapter::reportSvEvent(const GnssSvNotification& svNotify,
+ bool fromEngineHub)
+{
+ if (!fromEngineHub) {
+ mEngHubProxy->gnssReportSv(svNotify);
+ if (true == initEngHubProxy()){
+ return;
+ }
+ }
+
+ struct MsgReportSv : public LocMsg {
+ GnssAdapter& mAdapter;
+ const GnssSvNotification mSvNotify;
+ inline MsgReportSv(GnssAdapter& adapter,
+ const GnssSvNotification& svNotify) :
+ LocMsg(),
+ mAdapter(adapter),
+ mSvNotify(svNotify) {}
+ inline virtual void proc() const {
+ mAdapter.reportSv((GnssSvNotification&)mSvNotify);
+ }
+ };
+
+ sendMsg(new MsgReportSv(*this, svNotify));
+}
+
+void
+GnssAdapter::reportSv(GnssSvNotification& svNotify)
+{
+ int numSv = svNotify.count;
+ int16_t gnssSvId = 0;
+ uint64_t svUsedIdMask = 0;
+ for (int i=0; i < numSv; i++) {
+ svUsedIdMask = 0;
+ gnssSvId = svNotify.gnssSvs[i].svId;
+ GnssSignalTypeMask signalTypeMask = svNotify.gnssSvs[i].gnssSignalTypeMask;
+ switch (svNotify.gnssSvs[i].type) {
+ case GNSS_SV_TYPE_GPS:
+ if (mGnssSvIdUsedInPosAvail) {
+ if (mGnssMbSvIdUsedInPosAvail) {
+ switch (signalTypeMask) {
+ case GNSS_SIGNAL_GPS_L1CA:
+ svUsedIdMask = mGnssMbSvIdUsedInPosition.gps_l1ca_sv_used_ids_mask;
+ break;
+ case GNSS_SIGNAL_GPS_L1C:
+ svUsedIdMask = mGnssMbSvIdUsedInPosition.gps_l1c_sv_used_ids_mask;
+ break;
+ case GNSS_SIGNAL_GPS_L2:
+ svUsedIdMask = mGnssMbSvIdUsedInPosition.gps_l2_sv_used_ids_mask;
+ break;
+ case GNSS_SIGNAL_GPS_L5:
+ svUsedIdMask = mGnssMbSvIdUsedInPosition.gps_l5_sv_used_ids_mask;
+ break;
+ }
+ } else {
+ svUsedIdMask = mGnssSvIdUsedInPosition.gps_sv_used_ids_mask;
+ }
+ }
+ break;
+ case GNSS_SV_TYPE_GLONASS:
+ if (mGnssSvIdUsedInPosAvail) {
+ if (mGnssMbSvIdUsedInPosAvail) {
+ switch (signalTypeMask) {
+ case GNSS_SIGNAL_GLONASS_G1:
+ svUsedIdMask = mGnssMbSvIdUsedInPosition.glo_g1_sv_used_ids_mask;
+ break;
+ case GNSS_SIGNAL_GLONASS_G2:
+ svUsedIdMask = mGnssMbSvIdUsedInPosition.glo_g2_sv_used_ids_mask;
+ break;
+ }
+ } else {
+ svUsedIdMask = mGnssSvIdUsedInPosition.glo_sv_used_ids_mask;
+ }
+ }
+ break;
+ case GNSS_SV_TYPE_BEIDOU:
+ if (mGnssSvIdUsedInPosAvail) {
+ if (mGnssMbSvIdUsedInPosAvail) {
+ switch (signalTypeMask) {
+ case GNSS_SIGNAL_BEIDOU_B1I:
+ svUsedIdMask = mGnssMbSvIdUsedInPosition.bds_b1i_sv_used_ids_mask;
+ break;
+ case GNSS_SIGNAL_BEIDOU_B1C:
+ svUsedIdMask = mGnssMbSvIdUsedInPosition.bds_b1c_sv_used_ids_mask;
+ break;
+ case GNSS_SIGNAL_BEIDOU_B2I:
+ svUsedIdMask = mGnssMbSvIdUsedInPosition.bds_b2i_sv_used_ids_mask;
+ break;
+ case GNSS_SIGNAL_BEIDOU_B2AI:
+ svUsedIdMask = mGnssMbSvIdUsedInPosition.bds_b2ai_sv_used_ids_mask;
+ break;
+ case GNSS_SIGNAL_BEIDOU_B2AQ:
+ svUsedIdMask = mGnssMbSvIdUsedInPosition.bds_b2aq_sv_used_ids_mask;
+ break;
+ }
+ } else {
+ svUsedIdMask = mGnssSvIdUsedInPosition.bds_sv_used_ids_mask;
+ }
+ }
+ break;
+ case GNSS_SV_TYPE_GALILEO:
+ if (mGnssSvIdUsedInPosAvail) {
+ if (mGnssMbSvIdUsedInPosAvail) {
+ switch (signalTypeMask) {
+ case GNSS_SIGNAL_GALILEO_E1:
+ svUsedIdMask = mGnssMbSvIdUsedInPosition.gal_e1_sv_used_ids_mask;
+ break;
+ case GNSS_SIGNAL_GALILEO_E5A:
+ svUsedIdMask = mGnssMbSvIdUsedInPosition.gal_e5a_sv_used_ids_mask;
+ break;
+ case GNSS_SIGNAL_GALILEO_E5B:
+ svUsedIdMask = mGnssMbSvIdUsedInPosition.gal_e5b_sv_used_ids_mask;
+ break;
+ }
+ } else {
+ svUsedIdMask = mGnssSvIdUsedInPosition.gal_sv_used_ids_mask;
+ }
+ }
+ break;
+ case GNSS_SV_TYPE_QZSS:
+ if (mGnssSvIdUsedInPosAvail) {
+ if (mGnssMbSvIdUsedInPosAvail) {
+ switch (signalTypeMask) {
+ case GNSS_SIGNAL_QZSS_L1CA:
+ svUsedIdMask = mGnssMbSvIdUsedInPosition.qzss_l1ca_sv_used_ids_mask;
+ break;
+ case GNSS_SIGNAL_QZSS_L1S:
+ svUsedIdMask = mGnssMbSvIdUsedInPosition.qzss_l1s_sv_used_ids_mask;
+ break;
+ case GNSS_SIGNAL_QZSS_L2:
+ svUsedIdMask = mGnssMbSvIdUsedInPosition.qzss_l2_sv_used_ids_mask;
+ break;
+ case GNSS_SIGNAL_QZSS_L5:
+ svUsedIdMask = mGnssMbSvIdUsedInPosition.qzss_l5_sv_used_ids_mask;
+ break;
+ }
+ } else {
+ svUsedIdMask = mGnssSvIdUsedInPosition.qzss_sv_used_ids_mask;
+ }
+ }
+ // QZSS SV id's need to reported as it is to framework, since
+ // framework expects it as it is. See GnssStatus.java.
+ // SV id passed to here by LocApi is 1-based.
+ svNotify.gnssSvs[i].svId += (QZSS_SV_PRN_MIN - 1);
+ break;
+ case GNSS_SV_TYPE_NAVIC:
+ if (mGnssSvIdUsedInPosAvail) {
+ svUsedIdMask = mGnssSvIdUsedInPosition.navic_sv_used_ids_mask;
+ }
+ break;
+ default:
+ svUsedIdMask = 0;
+ break;
+ }
+
+ // If SV ID was used in previous position fix, then set USED_IN_FIX
+ // flag, else clear the USED_IN_FIX flag.
+ if (svUsedIdMask & (1 << (gnssSvId - 1))) {
+ svNotify.gnssSvs[i].gnssSvOptionsMask |= GNSS_SV_OPTIONS_USED_IN_FIX_BIT;
+ }
+ }
+
+ for (auto it=mClientData.begin(); it != mClientData.end(); ++it) {
+ if (nullptr != it->second.gnssSvCb) {
+ it->second.gnssSvCb(svNotify);
+ }
+ }
+
+ if (NMEA_PROVIDER_AP == ContextBase::mGps_conf.NMEA_PROVIDER &&
+ !mTimeBasedTrackingSessions.empty()) {
+ std::vector<std::string> nmeaArraystr;
+ loc_nmea_generate_sv(svNotify, nmeaArraystr);
+ stringstream ss;
+ for (auto itor = nmeaArraystr.begin(); itor != nmeaArraystr.end(); ++itor) {
+ ss << *itor;
+ }
+ string s = ss.str();
+ reportNmea(s.c_str(), s.length());
+ }
+
+ mGnssSvIdUsedInPosAvail = false;
+}
+
+void
+GnssAdapter::reportNmeaEvent(const char* nmea, size_t length)
+{
+ if (NMEA_PROVIDER_AP == ContextBase::mGps_conf.NMEA_PROVIDER &&
+ !loc_nmea_is_debug(nmea, length)) {
+ return;
+ }
+
+ struct MsgReportNmea : public LocMsg {
+ GnssAdapter& mAdapter;
+ const char* mNmea;
+ size_t mLength;
+ inline MsgReportNmea(GnssAdapter& adapter,
+ const char* nmea,
+ size_t length) :
+ LocMsg(),
+ mAdapter(adapter),
+ mNmea(new char[length+1]),
+ mLength(length) {
+ if (mNmea == nullptr) {
+ LOC_LOGE("%s] new allocation failed, fatal error.", __func__);
+ return;
+ }
+ strlcpy((char*)mNmea, nmea, length+1);
+ }
+ inline virtual ~MsgReportNmea()
+ {
+ delete[] mNmea;
+ }
+ inline virtual void proc() const {
+ // extract bug report info - this returns true if consumed by systemstatus
+ bool ret = false;
+ SystemStatus* s = mAdapter.getSystemStatus();
+ if (nullptr != s) {
+ ret = s->setNmeaString(mNmea, mLength);
+ }
+ if (false == ret) {
+ // forward NMEA message to upper layer
+ mAdapter.reportNmea(mNmea, mLength);
+ }
+ }
+ };
+
+ sendMsg(new MsgReportNmea(*this, nmea, length));
+}
+
+void
+GnssAdapter::reportNmea(const char* nmea, size_t length)
+{
+ GnssNmeaNotification nmeaNotification = {};
+ nmeaNotification.size = sizeof(GnssNmeaNotification);
+
+ struct timeval tv;
+ gettimeofday(&tv, (struct timezone *) NULL);
+ int64_t now = tv.tv_sec * 1000LL + tv.tv_usec / 1000;
+ nmeaNotification.timestamp = now;
+ nmeaNotification.nmea = nmea;
+ nmeaNotification.length = length;
+
+ for (auto it=mClientData.begin(); it != mClientData.end(); ++it) {
+ if (nullptr != it->second.gnssNmeaCb) {
+ it->second.gnssNmeaCb(nmeaNotification);
+ }
+ }
+}
+
+void
+GnssAdapter::reportDataEvent(const GnssDataNotification& dataNotify,
+ int msInWeek)
+{
+ struct MsgReportData : public LocMsg {
+ GnssAdapter& mAdapter;
+ GnssDataNotification mDataNotify;
+ int mMsInWeek;
+ inline MsgReportData(GnssAdapter& adapter,
+ const GnssDataNotification& dataNotify,
+ int msInWeek) :
+ LocMsg(),
+ mAdapter(adapter),
+ mDataNotify(dataNotify),
+ mMsInWeek(msInWeek) {
+ }
+ inline virtual void proc() const {
+ if (-1 != mMsInWeek) {
+ mAdapter.getDataInformation((GnssDataNotification&)mDataNotify,
+ mMsInWeek);
+ }
+ mAdapter.reportData((GnssDataNotification&)mDataNotify);
+ }
+ };
+
+ sendMsg(new MsgReportData(*this, dataNotify, msInWeek));
+}
+
+void
+GnssAdapter::reportData(GnssDataNotification& dataNotify)
+{
+ for (int sig = 0; sig < GNSS_LOC_MAX_NUMBER_OF_SIGNAL_TYPES; sig++) {
+ if (GNSS_LOC_DATA_JAMMER_IND_BIT ==
+ (dataNotify.gnssDataMask[sig] & GNSS_LOC_DATA_JAMMER_IND_BIT)) {
+ LOC_LOGv("jammerInd[%d]=%f", sig, dataNotify.jammerInd[sig]);
+ }
+ if (GNSS_LOC_DATA_AGC_BIT ==
+ (dataNotify.gnssDataMask[sig] & GNSS_LOC_DATA_AGC_BIT)) {
+ LOC_LOGv("agc[%d]=%f", sig, dataNotify.agc[sig]);
+ }
+ }
+ for (auto it = mClientData.begin(); it != mClientData.end(); ++it) {
+ if (nullptr != it->second.gnssDataCb) {
+ it->second.gnssDataCb(dataNotify);
+ }
+ }
+}
+
+bool
+GnssAdapter::requestNiNotifyEvent(const GnssNiNotification &notify, const void* data,
+ const LocInEmergency emergencyState)
+{
+ LOC_LOGI("%s]: notif_type: %d, timeout: %d, default_resp: %d"
+ "requestor_id: %s (encoding: %d) text: %s text (encoding: %d) extras: %s",
+ __func__, notify.type, notify.timeout, notify.timeoutResponse,
+ notify.requestor, notify.requestorEncoding,
+ notify.message, notify.messageEncoding, notify.extras);
+
+ struct MsgReportNiNotify : public LocMsg {
+ GnssAdapter& mAdapter;
+ LocApiBase& mApi;
+ const GnssNiNotification mNotify;
+ const void* mData;
+ const LocInEmergency mEmergencyState;
+ inline MsgReportNiNotify(GnssAdapter& adapter,
+ LocApiBase& api,
+ const GnssNiNotification& notify,
+ const void* data,
+ const LocInEmergency emergencyState) :
+ LocMsg(),
+ mAdapter(adapter),
+ mApi(api),
+ mNotify(notify),
+ mData(data),
+ mEmergencyState(emergencyState) {}
+ inline virtual void proc() const {
+ bool bIsInEmergency = false;
+ bool bInformNiAccept = false;
+
+ bIsInEmergency = ((LOC_IN_EMERGENCY_UNKNOWN == mEmergencyState) &&
+ mAdapter.getE911State()) || // older modems
+ (LOC_IN_EMERGENCY_SET == mEmergencyState); // newer modems
+
+ if (GNSS_NI_TYPE_EMERGENCY_SUPL == mNotify.type) {
+ bInformNiAccept = bIsInEmergency ||
+ (GNSS_CONFIG_SUPL_EMERGENCY_SERVICES_NO == ContextBase::mGps_conf.SUPL_ES);
+
+ if (bInformNiAccept) {
+ mAdapter.requestNiNotify(mNotify, mData, bInformNiAccept);
+ } else {
+ mApi.informNiResponse(GNSS_NI_RESPONSE_DENY, mData);
+ }
+ } else if (GNSS_NI_TYPE_CONTROL_PLANE == mNotify.type) {
+ if (bIsInEmergency && (1 == ContextBase::mGps_conf.CP_MTLR_ES)) {
+ mApi.informNiResponse(GNSS_NI_RESPONSE_ACCEPT, mData);
+ }
+ else {
+ mAdapter.requestNiNotify(mNotify, mData, false);
+ }
+ } else {
+ mAdapter.requestNiNotify(mNotify, mData, false);
+ }
+ }
+ };
+
+ sendMsg(new MsgReportNiNotify(*this, *mLocApi, notify, data, emergencyState));
+
+ return true;
+}
+
+void
+GnssAdapter::reportLocationSystemInfoEvent(const LocationSystemInfo & locationSystemInfo) {
+
+ // send system info to engine hub
+ mEngHubProxy->gnssReportSystemInfo(locationSystemInfo);
+
+ struct MsgLocationSystemInfo : public LocMsg {
+ GnssAdapter& mAdapter;
+ LocationSystemInfo mSystemInfo;
+ inline MsgLocationSystemInfo(GnssAdapter& adapter,
+ const LocationSystemInfo& systemInfo) :
+ LocMsg(),
+ mAdapter(adapter),
+ mSystemInfo(systemInfo) {}
+ inline virtual void proc() const {
+ mAdapter.reportLocationSystemInfo(mSystemInfo);
+ }
+ };
+
+ sendMsg(new MsgLocationSystemInfo(*this, locationSystemInfo));
+}
+
+void
+GnssAdapter::reportLocationSystemInfo(const LocationSystemInfo & locationSystemInfo) {
+ // save the info into the master copy piece by piece, as other system info
+ // may come at different time
+ if (locationSystemInfo.systemInfoMask & LOCATION_SYS_INFO_LEAP_SECOND) {
+ mLocSystemInfo.systemInfoMask |= LOCATION_SYS_INFO_LEAP_SECOND;
+
+ const LeapSecondSystemInfo &srcLeapSecondSysInfo = locationSystemInfo.leapSecondSysInfo;
+ LeapSecondSystemInfo &dstLeapSecondSysInfo = mLocSystemInfo.leapSecondSysInfo;
+ if (srcLeapSecondSysInfo.leapSecondInfoMask &
+ LEAP_SECOND_SYS_INFO_CURRENT_LEAP_SECONDS_BIT) {
+ dstLeapSecondSysInfo.leapSecondInfoMask |=
+ LEAP_SECOND_SYS_INFO_CURRENT_LEAP_SECONDS_BIT;
+ dstLeapSecondSysInfo.leapSecondCurrent = srcLeapSecondSysInfo.leapSecondCurrent;
+ }
+ // once leap second change event is complete, modem may send up event invalidate the leap
+ // second change info while AP is still processing report during leap second transition
+ // so, we choose to keep this info around even though it is old
+ if (srcLeapSecondSysInfo.leapSecondInfoMask & LEAP_SECOND_SYS_INFO_LEAP_SECOND_CHANGE_BIT) {
+ dstLeapSecondSysInfo.leapSecondInfoMask |= LEAP_SECOND_SYS_INFO_LEAP_SECOND_CHANGE_BIT;
+ dstLeapSecondSysInfo.leapSecondChangeInfo = srcLeapSecondSysInfo.leapSecondChangeInfo;
+ }
+ }
+
+ // we received new info, inform client of the newly received info
+ if (locationSystemInfo.systemInfoMask) {
+ for (auto it=mClientData.begin(); it != mClientData.end(); ++it) {
+ if (it->second.locationSystemInfoCb != nullptr) {
+ it->second.locationSystemInfoCb(locationSystemInfo);
+ }
+ }
+ }
+}
+
+static void* niThreadProc(void *args)
+{
+ NiSession* pSession = (NiSession*)args;
+ int rc = 0; /* return code from pthread calls */
+
+ struct timespec present_time;
+ struct timespec expire_time;
+
+ pthread_mutex_lock(&pSession->tLock);
+ /* Calculate absolute expire time */
+ clock_gettime(CLOCK_MONOTONIC, &present_time);
+ expire_time.tv_sec = present_time.tv_sec + pSession->respTimeLeft;
+ expire_time.tv_nsec = present_time.tv_nsec;
+ LOC_LOGD("%s]: time out set for abs time %ld with delay %d sec",
+ __func__, (long)expire_time.tv_sec, pSession->respTimeLeft);
+
+ while (!pSession->respRecvd) {
+ rc = pthread_cond_timedwait(&pSession->tCond,
+ &pSession->tLock,
+ &expire_time);
+ if (rc == ETIMEDOUT) {
+ pSession->resp = GNSS_NI_RESPONSE_NO_RESPONSE;
+ LOC_LOGD("%s]: time out after valting for specified time. Ret Val %d",
+ __func__, rc);
+ break;
+ }
+ }
+ LOC_LOGD("%s]: Java layer has sent us a user response and return value from "
+ "pthread_cond_timedwait = %d pSession->resp is %u", __func__, rc, pSession->resp);
+ pSession->respRecvd = false; /* Reset the user response flag for the next session*/
+
+ // adding this check to support modem restart, in which case, we need the thread
+ // to exit without calling sending data. We made sure that rawRequest is NULL in
+ // loc_eng_ni_reset_on_engine_restart()
+ GnssAdapter* adapter = pSession->adapter;
+ GnssNiResponse resp;
+ void* rawRequest = NULL;
+ bool sendResponse = false;
+
+ if (NULL != pSession->rawRequest) {
+ if (pSession->resp != GNSS_NI_RESPONSE_IGNORE) {
+ resp = pSession->resp;
+ rawRequest = pSession->rawRequest;
+ sendResponse = true;
+ } else {
+ free(pSession->rawRequest);
+ }
+ pSession->rawRequest = NULL;
+ }
+ pthread_mutex_unlock(&pSession->tLock);
+
+ pSession->respTimeLeft = 0;
+ pSession->reqID = 0;
+
+ if (sendResponse) {
+ adapter->gnssNiResponseCommand(resp, rawRequest);
+ }
+
+ return NULL;
+}
+
+bool
+GnssAdapter::requestNiNotify(const GnssNiNotification& notify, const void* data,
+ const bool bInformNiAccept)
+{
+ NiSession* pSession = NULL;
+ gnssNiCallback gnssNiCb = nullptr;
+
+ for (auto it=mClientData.begin(); it != mClientData.end(); ++it) {
+ if (nullptr != it->second.gnssNiCb) {
+ gnssNiCb = it->second.gnssNiCb;
+ break;
+ }
+ }
+ if (nullptr == gnssNiCb) {
+ if (GNSS_NI_TYPE_EMERGENCY_SUPL == notify.type) {
+ if (bInformNiAccept) {
+ mLocApi->informNiResponse(GNSS_NI_RESPONSE_ACCEPT, data);
+ NiData& niData = getNiData();
+ // ignore any SUPL NI non-Es session if a SUPL NI ES is accepted
+ if (NULL != niData.session.rawRequest) {
+ pthread_mutex_lock(&niData.session.tLock);
+ niData.session.resp = GNSS_NI_RESPONSE_IGNORE;
+ niData.session.respRecvd = true;
+ pthread_cond_signal(&niData.session.tCond);
+ pthread_mutex_unlock(&niData.session.tLock);
+ }
+ }
+ }
+ EXIT_LOG(%s, "no clients with gnssNiCb.");
+ return false;
+ }
+
+ if (notify.type == GNSS_NI_TYPE_EMERGENCY_SUPL) {
+ if (NULL != mNiData.sessionEs.rawRequest) {
+ LOC_LOGI("%s]: supl es NI in progress, new supl es NI ignored, type: %d",
+ __func__, notify.type);
+ if (NULL != data) {
+ free((void*)data);
+ }
+ } else {
+ pSession = &mNiData.sessionEs;
+ }
+ } else {
+ if (NULL != mNiData.session.rawRequest ||
+ NULL != mNiData.sessionEs.rawRequest) {
+ LOC_LOGI("%s]: supl NI in progress, new supl NI ignored, type: %d",
+ __func__, notify.type);
+ if (NULL != data) {
+ free((void*)data);
+ }
+ } else {
+ pSession = &mNiData.session;
+ }
+ }
+
+ if (pSession) {
+ /* Save request */
+ pSession->rawRequest = (void*)data;
+ pSession->reqID = ++mNiData.reqIDCounter;
+ pSession->adapter = this;
+
+ int sessionId = pSession->reqID;
+
+ /* For robustness, spawn a thread at this point to timeout to clear up the notification
+ * status, even though the OEM layer in java does not do so.
+ **/
+ pSession->respTimeLeft =
+ 5 + (notify.timeout != 0 ? notify.timeout : LOC_NI_NO_RESPONSE_TIME);
+
+ int rc = 0;
+ rc = pthread_create(&pSession->thread, NULL, niThreadProc, pSession);
+ if (rc) {
+ LOC_LOGE("%s]: Loc NI thread is not created.", __func__);
+ }
+ rc = pthread_detach(pSession->thread);
+ if (rc) {
+ LOC_LOGE("%s]: Loc NI thread is not detached.", __func__);
+ }
+
+ if (nullptr != gnssNiCb) {
+ gnssNiCb(sessionId, notify);
+ }
+ }
+
+ return true;
+}
+
+void
+GnssAdapter::reportGnssMeasurementsEvent(const GnssMeasurements& gnssMeasurements,
+ int msInWeek)
+{
+ LOC_LOGD("%s]: msInWeek=%d", __func__, msInWeek);
+
+ if (0 != gnssMeasurements.gnssMeasNotification.count) {
+ struct MsgReportGnssMeasurementData : public LocMsg {
+ GnssAdapter& mAdapter;
+ GnssMeasurements mGnssMeasurements;
+ GnssMeasurementsNotification mMeasurementsNotify;
+ inline MsgReportGnssMeasurementData(GnssAdapter& adapter,
+ const GnssMeasurements& gnssMeasurements,
+ int msInWeek) :
+ LocMsg(),
+ mAdapter(adapter),
+ mMeasurementsNotify(gnssMeasurements.gnssMeasNotification) {
+ if (-1 != msInWeek) {
+ mAdapter.getAgcInformation(mMeasurementsNotify, msInWeek);
+ }
+ }
+ inline virtual void proc() const {
+ mAdapter.reportGnssMeasurementData(mMeasurementsNotify);
+ }
+ };
+
+ sendMsg(new MsgReportGnssMeasurementData(*this, gnssMeasurements, msInWeek));
+ }
+ mEngHubProxy->gnssReportSvMeasurement(gnssMeasurements.gnssSvMeasurementSet);
+}
+
+void
+GnssAdapter::reportGnssMeasurementData(const GnssMeasurementsNotification& measurements)
+{
+ for (auto it=mClientData.begin(); it != mClientData.end(); ++it) {
+ if (nullptr != it->second.gnssMeasurementsCb) {
+ it->second.gnssMeasurementsCb(measurements);
+ }
+ }
+}
+
+void
+GnssAdapter::reportSvPolynomialEvent(GnssSvPolynomial &svPolynomial)
+{
+ LOC_LOGD("%s]: ", __func__);
+ mEngHubProxy->gnssReportSvPolynomial(svPolynomial);
+}
+
+void
+GnssAdapter::reportSvEphemerisEvent(GnssSvEphemerisReport & svEphemeris)
+{
+ LOC_LOGD("%s]:", __func__);
+ mEngHubProxy->gnssReportSvEphemeris(svEphemeris);
+}
+
+
+bool
+GnssAdapter::requestOdcpiEvent(OdcpiRequestInfo& request)
+{
+ struct MsgRequestOdcpi : public LocMsg {
+ GnssAdapter& mAdapter;
+ OdcpiRequestInfo mOdcpiRequest;
+ inline MsgRequestOdcpi(GnssAdapter& adapter, OdcpiRequestInfo& request) :
+ LocMsg(),
+ mAdapter(adapter),
+ mOdcpiRequest(request) {}
+ inline virtual void proc() const {
+ mAdapter.requestOdcpi(mOdcpiRequest);
+ }
+ };
+
+ sendMsg(new MsgRequestOdcpi(*this, request));
+ return true;
+}
+
+void GnssAdapter::requestOdcpi(const OdcpiRequestInfo& request)
+{
+ if (nullptr != mOdcpiRequestCb) {
+ LOC_LOGd("request: type %d, tbf %d, isEmergency %d"
+ " requestActive: %d timerActive: %d",
+ request.type, request.tbfMillis, request.isEmergencyMode,
+ mOdcpiRequestActive, mOdcpiTimer.isActive());
+ // ODCPI START and ODCPI STOP from modem can come in quick succession
+ // so the mOdcpiTimer helps avoid spamming the framework as well as
+ // extending the odcpi session past 30 seconds if needed
+ if (ODCPI_REQUEST_TYPE_START == request.type) {
+ if (false == mOdcpiRequestActive && false == mOdcpiTimer.isActive()) {
+ mOdcpiRequestCb(request);
+ mOdcpiRequestActive = true;
+ mOdcpiTimer.start();
+ // if the current active odcpi session is non-emergency, and the new
+ // odcpi request is emergency, replace the odcpi request with new request
+ // and restart the timer
+ } else if (false == mOdcpiRequest.isEmergencyMode &&
+ true == request.isEmergencyMode) {
+ mOdcpiRequestCb(request);
+ mOdcpiRequestActive = true;
+ if (true == mOdcpiTimer.isActive()) {
+ mOdcpiTimer.restart();
+ } else {
+ mOdcpiTimer.start();
+ }
+ // if ODCPI request is not active but the timer is active, then
+ // just update the active state and wait for timer to expire
+ // before requesting new ODCPI to avoid spamming ODCPI requests
+ } else if (false == mOdcpiRequestActive && true == mOdcpiTimer.isActive()) {
+ mOdcpiRequestActive = true;
+ }
+ mOdcpiRequest = request;
+ // the request is being stopped, but allow timer to expire first
+ // before stopping the timer just in case more ODCPI requests come
+ // to avoid spamming more odcpi requests to the framework
+ } else {
+ mOdcpiRequestActive = false;
+ }
+ } else {
+ LOC_LOGw("ODCPI request not supported");
+ }
+}
+
+bool GnssAdapter::reportDeleteAidingDataEvent(GnssAidingData& aidingData)
+{
+ LOC_LOGD("%s]:", __func__);
+ mEngHubProxy->gnssDeleteAidingData(aidingData);
+ return true;
+}
+
+bool GnssAdapter::reportKlobucharIonoModelEvent(GnssKlobucharIonoModel & ionoModel)
+{
+ LOC_LOGD("%s]:", __func__);
+ mEngHubProxy->gnssReportKlobucharIonoModel(ionoModel);
+ return true;
+}
+
+bool GnssAdapter::reportGnssAdditionalSystemInfoEvent(
+ GnssAdditionalSystemInfo & additionalSystemInfo)
+{
+ LOC_LOGD("%s]:", __func__);
+ mEngHubProxy->gnssReportAdditionalSystemInfo(additionalSystemInfo);
+ return true;
+}
+
+void GnssAdapter::initOdcpiCommand(const OdcpiRequestCallback& callback)
+{
+ struct MsgInitOdcpi : public LocMsg {
+ GnssAdapter& mAdapter;
+ OdcpiRequestCallback mOdcpiCb;
+ inline MsgInitOdcpi(GnssAdapter& adapter,
+ const OdcpiRequestCallback& callback) :
+ LocMsg(),
+ mAdapter(adapter),
+ mOdcpiCb(callback) {}
+ inline virtual void proc() const {
+ mAdapter.initOdcpi(mOdcpiCb);
+ }
+ };
+
+ sendMsg(new MsgInitOdcpi(*this, callback));
+}
+
+void GnssAdapter::initOdcpi(const OdcpiRequestCallback& callback)
+{
+ mOdcpiRequestCb = callback;
+
+ /* Register for WIFI request */
+ updateEvtMask(LOC_API_ADAPTER_BIT_REQUEST_WIFI,
+ LOC_REGISTRATION_MASK_ENABLED);
+}
+
+void GnssAdapter::injectOdcpiCommand(const Location& location)
+{
+ struct MsgInjectOdcpi : public LocMsg {
+ GnssAdapter& mAdapter;
+ Location mLocation;
+ inline MsgInjectOdcpi(GnssAdapter& adapter, const Location& location) :
+ LocMsg(),
+ mAdapter(adapter),
+ mLocation(location) {}
+ inline virtual void proc() const {
+ mAdapter.injectOdcpi(mLocation);
+ }
+ };
+
+ sendMsg(new MsgInjectOdcpi(*this, location));
+}
+
+void GnssAdapter::injectOdcpi(const Location& location)
+{
+ LOC_LOGd("ODCPI Injection: requestActive: %d timerActive: %d"
+ "lat %.7f long %.7f",
+ mOdcpiRequestActive, mOdcpiTimer.isActive(),
+ location.latitude, location.longitude);
+
+ mLocApi->injectPosition(location, true);
+}
+
+// Called in the context of LocTimer thread
+void OdcpiTimer::timeOutCallback()
+{
+ if (nullptr != mAdapter) {
+ mAdapter->odcpiTimerExpireEvent();
+ }
+}
+
+// Called in the context of LocTimer thread
+void GnssAdapter::odcpiTimerExpireEvent()
+{
+ struct MsgOdcpiTimerExpire : public LocMsg {
+ GnssAdapter& mAdapter;
+ inline MsgOdcpiTimerExpire(GnssAdapter& adapter) :
+ LocMsg(),
+ mAdapter(adapter) {}
+ inline virtual void proc() const {
+ mAdapter.odcpiTimerExpire();
+ }
+ };
+ sendMsg(new MsgOdcpiTimerExpire(*this));
+}
+void GnssAdapter::odcpiTimerExpire()
+{
+ LOC_LOGd("requestActive: %d timerActive: %d",
+ mOdcpiRequestActive, mOdcpiTimer.isActive());
+
+ // if ODCPI request is still active after timer
+ // expires, request again and restart timer
+ if (mOdcpiRequestActive) {
+ mOdcpiRequestCb(mOdcpiRequest);
+ mOdcpiTimer.restart();
+ } else {
+ mOdcpiTimer.stop();
+ }
+}
+
+void
+GnssAdapter::invokeGnssEnergyConsumedCallback(uint64_t energyConsumedSinceFirstBoot) {
+ if (mGnssEnergyConsumedCb) {
+ mGnssEnergyConsumedCb(energyConsumedSinceFirstBoot);
+ mGnssEnergyConsumedCb = nullptr;
+ }
+}
+
+bool
+GnssAdapter::reportGnssEngEnergyConsumedEvent(uint64_t energyConsumedSinceFirstBoot){
+ LOC_LOGD("%s]: %" PRIu64 " ", __func__, energyConsumedSinceFirstBoot);
+
+ struct MsgReportGnssGnssEngEnergyConsumed : public LocMsg {
+ GnssAdapter& mAdapter;
+ uint64_t mGnssEnergyConsumedSinceFirstBoot;
+ inline MsgReportGnssGnssEngEnergyConsumed(GnssAdapter& adapter,
+ uint64_t energyConsumed) :
+ LocMsg(),
+ mAdapter(adapter),
+ mGnssEnergyConsumedSinceFirstBoot(energyConsumed) {}
+ inline virtual void proc() const {
+ mAdapter.invokeGnssEnergyConsumedCallback(mGnssEnergyConsumedSinceFirstBoot);
+ }
+ };
+
+ sendMsg(new MsgReportGnssGnssEngEnergyConsumed(*this, energyConsumedSinceFirstBoot));
+ return true;
+}
+
+void GnssAdapter::initDefaultAgps() {
+ LOC_LOGD("%s]: ", __func__);
+
+ void *handle = nullptr;
+ if ((handle = dlopen("libloc_net_iface.so", RTLD_NOW)) == nullptr) {
+ LOC_LOGD("%s]: libloc_net_iface.so not found !", __func__);
+ return;
+ }
+
+ LocAgpsGetAgpsCbInfo getAgpsCbInfo = (LocAgpsGetAgpsCbInfo)
+ dlsym(handle, "LocNetIfaceAgps_getAgpsCbInfo");
+ if (getAgpsCbInfo == nullptr) {
+ LOC_LOGE("%s]: Failed to get method LocNetIfaceAgps_getStatusCb", __func__);
+ dlclose(handle);
+ return;
+ }
+
+ AgpsCbInfo& cbInfo = getAgpsCbInfo(agpsOpenResultCb, agpsCloseResultCb, this);
+
+ if (cbInfo.statusV4Cb == nullptr) {
+ LOC_LOGE("%s]: statusV4Cb is nullptr!", __func__);
+ dlclose(handle);
+ return;
+ }
+
+ initAgps(cbInfo);
+}
+
+void GnssAdapter::initDefaultAgpsCommand() {
+ LOC_LOGD("%s]: ", __func__);
+
+ struct MsgInitDefaultAgps : public LocMsg {
+ GnssAdapter& mAdapter;
+ inline MsgInitDefaultAgps(GnssAdapter& adapter) :
+ LocMsg(),
+ mAdapter(adapter) {
+ }
+ inline virtual void proc() const {
+ mAdapter.initDefaultAgps();
+ }
+ };
+
+ sendMsg(new MsgInitDefaultAgps(*this));
+}
+
+/* INIT LOC AGPS MANAGER */
+
+void GnssAdapter::initAgps(const AgpsCbInfo& cbInfo) {
+ LOC_LOGD("%s]:cbInfo.atlType - %d", __func__, cbInfo.atlType);
+
+ if (!((ContextBase::mGps_conf.CAPABILITIES & LOC_GPS_CAPABILITY_MSB) ||
+ (ContextBase::mGps_conf.CAPABILITIES & LOC_GPS_CAPABILITY_MSA))) {
+ return;
+ }
+
+ mAgpsManager.createAgpsStateMachines(cbInfo);
+ /* Register for AGPS event mask */
+ updateEvtMask(LOC_API_ADAPTER_BIT_LOCATION_SERVER_REQUEST,
+ LOC_REGISTRATION_MASK_ENABLED);
+}
+
+void GnssAdapter::initAgpsCommand(const AgpsCbInfo& cbInfo){
+ LOC_LOGI("GnssAdapter::initAgpsCommand");
+
+ /* Message to initialize AGPS module */
+ struct AgpsMsgInit: public LocMsg {
+ const AgpsCbInfo mCbInfo;
+ GnssAdapter& mAdapter;
+
+ inline AgpsMsgInit(const AgpsCbInfo& cbInfo,
+ GnssAdapter& adapter) :
+ LocMsg(), mCbInfo(cbInfo), mAdapter(adapter) {
+ LOC_LOGV("AgpsMsgInit");
+ }
+
+ inline virtual void proc() const {
+ LOC_LOGV("AgpsMsgInit::proc()");
+ mAdapter.initAgps(mCbInfo);
+ }
+ };
+
+ /* Send message to initialize AGPS Manager */
+ sendMsg(new AgpsMsgInit(cbInfo, *this));
+}
+
+void GnssAdapter::initNfwCommand(const NfwCbInfo& cbInfo) {
+ LOC_LOGi("GnssAdapter::initNfwCommand");
+
+ /* Message to initialize NFW */
+ struct MsgInitNfw : public LocMsg {
+ const NfwCbInfo mCbInfo;
+ GnssAdapter& mAdapter;
+
+ inline MsgInitNfw(const NfwCbInfo& cbInfo,
+ GnssAdapter& adapter) :
+ LocMsg(), mCbInfo(cbInfo), mAdapter(adapter) {
+ LOC_LOGv("MsgInitNfw");
+ }
+
+ inline virtual void proc() const {
+ LOC_LOGv("MsgInitNfw::proc()");
+ mAdapter.initNfw(mCbInfo);
+ }
+ };
+
+ /* Send message to initialize NFW */
+ sendMsg(new MsgInitNfw(cbInfo, *this));
+}
+
+void GnssAdapter::reportNfwNotificationEvent(GnssNfwNotification& notification) {
+ LOC_LOGi("GnssAdapter::reportNfwNotificationEvent");
+
+ struct MsgReportNfwNotification : public LocMsg {
+ const GnssNfwNotification mNotification;
+ GnssAdapter& mAdapter;
+
+ inline MsgReportNfwNotification(const GnssNfwNotification& notification,
+ GnssAdapter& adapter) :
+ LocMsg(), mNotification(notification), mAdapter(adapter) {
+ LOC_LOGv("MsgReportNfwNotification");
+ }
+
+ inline virtual void proc() const {
+ LOC_LOGv("MsgReportNfwNotification::proc()");
+ mAdapter.reportNfwNotification(mNotification);
+ }
+ };
+
+ sendMsg(new MsgReportNfwNotification(notification, *this));
+}
+
+/* GnssAdapter::requestATL
+ * Method triggered in QMI thread as part of handling below message:
+ * eQMI_LOC_SERVER_REQUEST_OPEN_V02
+ * Triggers the AGPS state machine to setup AGPS call for below WWAN types:
+ * eQMI_LOC_WWAN_TYPE_INTERNET_V02
+ * eQMI_LOC_WWAN_TYPE_AGNSS_V02
+ * eQMI_LOC_WWAN_TYPE_AGNSS_EMERGENCY_V02 */
+bool GnssAdapter::requestATL(int connHandle, LocAGpsType agpsType,
+ LocApnTypeMask apnTypeMask){
+
+ LOC_LOGI("GnssAdapter::requestATL handle=%d agpsType=0x%X apnTypeMask=0x%X",
+ connHandle, agpsType, apnTypeMask);
+
+ sendMsg( new AgpsMsgRequestATL(
+ &mAgpsManager, connHandle, (AGpsExtType)agpsType,
+ apnTypeMask));
+
+ return true;
+}
+
+/* GnssAdapter::releaseATL
+ * Method triggered in QMI thread as part of handling below message:
+ * eQMI_LOC_SERVER_REQUEST_CLOSE_V02
+ * Triggers teardown of an existing AGPS call */
+bool GnssAdapter::releaseATL(int connHandle){
+
+ LOC_LOGI("GnssAdapter::releaseATL");
+
+ /* Release SUPL/INTERNET/SUPL_ES ATL */
+ struct AgpsMsgReleaseATL: public LocMsg {
+
+ AgpsManager* mAgpsManager;
+ int mConnHandle;
+
+ inline AgpsMsgReleaseATL(AgpsManager* agpsManager, int connHandle) :
+ LocMsg(), mAgpsManager(agpsManager), mConnHandle(connHandle) {
+
+ LOC_LOGV("AgpsMsgReleaseATL");
+ }
+
+ inline virtual void proc() const {
+
+ LOC_LOGV("AgpsMsgReleaseATL::proc()");
+ mAgpsManager->releaseATL(mConnHandle);
+ }
+ };
+
+ sendMsg( new AgpsMsgReleaseATL(&mAgpsManager, connHandle));
+
+ return true;
+}
+
+void GnssAdapter::dataConnOpenCommand(
+ AGpsExtType agpsType,
+ const char* apnName, int apnLen, AGpsBearerType bearerType){
+
+ LOC_LOGI("GnssAdapter::frameworkDataConnOpen");
+
+ struct AgpsMsgAtlOpenSuccess: public LocMsg {
+
+ AgpsManager* mAgpsManager;
+ AGpsExtType mAgpsType;
+ char* mApnName;
+ int mApnLen;
+ AGpsBearerType mBearerType;
+
+ inline AgpsMsgAtlOpenSuccess(AgpsManager* agpsManager, AGpsExtType agpsType,
+ const char* apnName, int apnLen, AGpsBearerType bearerType) :
+ LocMsg(), mAgpsManager(agpsManager), mAgpsType(agpsType), mApnName(
+ new char[apnLen + 1]), mApnLen(apnLen), mBearerType(bearerType) {
+
+ LOC_LOGV("AgpsMsgAtlOpenSuccess");
+ if (mApnName == nullptr) {
+ LOC_LOGE("%s] new allocation failed, fatal error.", __func__);
+ // Reporting the failure here
+ mAgpsManager->reportAtlClosed(mAgpsType);
+ return;
+ }
+ memcpy(mApnName, apnName, apnLen);
+ mApnName[apnLen] = 0;
+ }
+
+ inline ~AgpsMsgAtlOpenSuccess() {
+ delete[] mApnName;
+ }
+
+ inline virtual void proc() const {
+
+ LOC_LOGV("AgpsMsgAtlOpenSuccess::proc()");
+ mAgpsManager->reportAtlOpenSuccess(mAgpsType, mApnName, mApnLen, mBearerType);
+ }
+ };
+ // Added inital length checks for apnlen check to avoid security issues
+ // In case of failure reporting the same
+ if (NULL == apnName || apnLen <= 0 || apnLen > MAX_APN_LEN || (strlen(apnName) != apnLen)) {
+ LOC_LOGe("%s]: incorrect apnlen length or incorrect apnName", __func__);
+ mAgpsManager.reportAtlClosed(agpsType);
+ } else {
+ sendMsg( new AgpsMsgAtlOpenSuccess(
+ &mAgpsManager, agpsType, apnName, apnLen, bearerType));
+ }
+}
+
+void GnssAdapter::dataConnClosedCommand(AGpsExtType agpsType){
+
+ LOC_LOGI("GnssAdapter::frameworkDataConnClosed");
+
+ struct AgpsMsgAtlClosed: public LocMsg {
+
+ AgpsManager* mAgpsManager;
+ AGpsExtType mAgpsType;
+
+ inline AgpsMsgAtlClosed(AgpsManager* agpsManager, AGpsExtType agpsType) :
+ LocMsg(), mAgpsManager(agpsManager), mAgpsType(agpsType) {
+
+ LOC_LOGV("AgpsMsgAtlClosed");
+ }
+
+ inline virtual void proc() const {
+
+ LOC_LOGV("AgpsMsgAtlClosed::proc()");
+ mAgpsManager->reportAtlClosed(mAgpsType);
+ }
+ };
+
+ sendMsg( new AgpsMsgAtlClosed(&mAgpsManager, (AGpsExtType)agpsType));
+}
+
+void GnssAdapter::dataConnFailedCommand(AGpsExtType agpsType){
+
+ LOC_LOGI("GnssAdapter::frameworkDataConnFailed");
+
+ struct AgpsMsgAtlOpenFailed: public LocMsg {
+
+ AgpsManager* mAgpsManager;
+ AGpsExtType mAgpsType;
+
+ inline AgpsMsgAtlOpenFailed(AgpsManager* agpsManager, AGpsExtType agpsType) :
+ LocMsg(), mAgpsManager(agpsManager), mAgpsType(agpsType) {
+
+ LOC_LOGV("AgpsMsgAtlOpenFailed");
+ }
+
+ inline virtual void proc() const {
+
+ LOC_LOGV("AgpsMsgAtlOpenFailed::proc()");
+ mAgpsManager->reportAtlOpenFailed(mAgpsType);
+ }
+ };
+
+ sendMsg( new AgpsMsgAtlOpenFailed(&mAgpsManager, (AGpsExtType)agpsType));
+}
+
+void GnssAdapter::convertSatelliteInfo(std::vector<GnssDebugSatelliteInfo>& out,
+ const GnssSvType& in_constellation,
+ const SystemStatusReports& in)
+{
+ uint64_t sv_mask = 0ULL;
+ uint32_t svid_min = 0;
+ uint32_t svid_num = 0;
+ uint32_t svid_idx = 0;
+
+ uint64_t eph_health_good_mask = 0ULL;
+ uint64_t eph_health_bad_mask = 0ULL;
+ uint64_t server_perdiction_available_mask = 0ULL;
+ float server_perdiction_age = 0.0f;
+
+ // set constellationi based parameters
+ switch (in_constellation) {
+ case GNSS_SV_TYPE_GPS:
+ svid_min = GNSS_BUGREPORT_GPS_MIN;
+ svid_num = GPS_NUM;
+ svid_idx = 0;
+ if (!in.mSvHealth.empty()) {
+ eph_health_good_mask = in.mSvHealth.back().mGpsGoodMask;
+ eph_health_bad_mask = in.mSvHealth.back().mGpsBadMask;
+ }
+ if (!in.mXtra.empty()) {
+ server_perdiction_available_mask = in.mXtra.back().mGpsXtraValid;
+ server_perdiction_age = (float)(in.mXtra.back().mGpsXtraAge);
+ }
+ break;
+ case GNSS_SV_TYPE_GLONASS:
+ svid_min = GNSS_BUGREPORT_GLO_MIN;
+ svid_num = GLO_NUM;
+ svid_idx = GPS_NUM;
+ if (!in.mSvHealth.empty()) {
+ eph_health_good_mask = in.mSvHealth.back().mGloGoodMask;
+ eph_health_bad_mask = in.mSvHealth.back().mGloBadMask;
+ }
+ if (!in.mXtra.empty()) {
+ server_perdiction_available_mask = in.mXtra.back().mGloXtraValid;
+ server_perdiction_age = (float)(in.mXtra.back().mGloXtraAge);
+ }
+ break;
+ case GNSS_SV_TYPE_QZSS:
+ svid_min = GNSS_BUGREPORT_QZSS_MIN;
+ svid_num = QZSS_NUM;
+ svid_idx = GPS_NUM+GLO_NUM+BDS_NUM+GAL_NUM;
+ if (!in.mSvHealth.empty()) {
+ eph_health_good_mask = in.mSvHealth.back().mQzssGoodMask;
+ eph_health_bad_mask = in.mSvHealth.back().mQzssBadMask;
+ }
+ if (!in.mXtra.empty()) {
+ server_perdiction_available_mask = in.mXtra.back().mQzssXtraValid;
+ server_perdiction_age = (float)(in.mXtra.back().mQzssXtraAge);
+ }
+ break;
+ case GNSS_SV_TYPE_BEIDOU:
+ svid_min = GNSS_BUGREPORT_BDS_MIN;
+ svid_num = BDS_NUM;
+ svid_idx = GPS_NUM+GLO_NUM;
+ if (!in.mSvHealth.empty()) {
+ eph_health_good_mask = in.mSvHealth.back().mBdsGoodMask;
+ eph_health_bad_mask = in.mSvHealth.back().mBdsBadMask;
+ }
+ if (!in.mXtra.empty()) {
+ server_perdiction_available_mask = in.mXtra.back().mBdsXtraValid;
+ server_perdiction_age = (float)(in.mXtra.back().mBdsXtraAge);
+ }
+ break;
+ case GNSS_SV_TYPE_GALILEO:
+ svid_min = GNSS_BUGREPORT_GAL_MIN;
+ svid_num = GAL_NUM;
+ svid_idx = GPS_NUM+GLO_NUM+BDS_NUM;
+ if (!in.mSvHealth.empty()) {
+ eph_health_good_mask = in.mSvHealth.back().mGalGoodMask;
+ eph_health_bad_mask = in.mSvHealth.back().mGalBadMask;
+ }
+ if (!in.mXtra.empty()) {
+ server_perdiction_available_mask = in.mXtra.back().mGalXtraValid;
+ server_perdiction_age = (float)(in.mXtra.back().mGalXtraAge);
+ }
+ break;
+ case GNSS_SV_TYPE_NAVIC:
+ svid_min = GNSS_BUGREPORT_NAVIC_MIN;
+ svid_num = NAVIC_NUM;
+ svid_idx = GPS_NUM+GLO_NUM+QZSS_NUM+BDS_NUM+GAL_NUM;
+ if (!in.mSvHealth.empty()) {
+ eph_health_good_mask = in.mSvHealth.back().mNavicGoodMask;
+ eph_health_bad_mask = in.mSvHealth.back().mNavicBadMask;
+ }
+ if (!in.mXtra.empty()) {
+ server_perdiction_available_mask = in.mXtra.back().mNavicXtraValid;
+ server_perdiction_age = (float)(in.mXtra.back().mNavicXtraAge);
+ }
+ break;
+ default:
+ return;
+ }
+
+ // extract each sv info from systemstatus report
+ for(uint32_t i=0; i<svid_num && (svid_idx+i)<SV_ALL_NUM; i++) {
+
+ GnssDebugSatelliteInfo s = {};
+ s.size = sizeof(s);
+ s.svid = i + svid_min;
+ s.constellation = in_constellation;
+
+ if (!in.mNavData.empty()) {
+ s.mEphemerisType = in.mNavData.back().mNav[svid_idx+i].mType;
+ s.mEphemerisSource = in.mNavData.back().mNav[svid_idx+i].mSource;
+ }
+ else {
+ s.mEphemerisType = GNSS_EPH_TYPE_UNKNOWN;
+ s.mEphemerisSource = GNSS_EPH_SOURCE_UNKNOWN;
+ }
+
+ sv_mask = 0x1ULL << i;
+ if (eph_health_good_mask & sv_mask) {
+ s.mEphemerisHealth = GNSS_EPH_HEALTH_GOOD;
+ }
+ else if (eph_health_bad_mask & sv_mask) {
+ s.mEphemerisHealth = GNSS_EPH_HEALTH_BAD;
+ }
+ else {
+ s.mEphemerisHealth = GNSS_EPH_HEALTH_UNKNOWN;
+ }
+
+ if (!in.mNavData.empty()) {
+ s.ephemerisAgeSeconds =
+ (float)(in.mNavData.back().mNav[svid_idx+i].mAgeSec);
+ }
+ else {
+ s.ephemerisAgeSeconds = 0.0f;
+ }
+
+ if (server_perdiction_available_mask & sv_mask) {
+ s.serverPredictionIsAvailable = true;
+ }
+ else {
+ s.serverPredictionIsAvailable = false;
+ }
+
+ s.serverPredictionAgeSeconds = server_perdiction_age;
+ out.push_back(s);
+ }
+
+ return;
+}
+
+bool GnssAdapter::getDebugReport(GnssDebugReport& r)
+{
+ LOC_LOGD("%s]: ", __func__);
+
+ SystemStatus* systemstatus = getSystemStatus();
+ if (nullptr == systemstatus) {
+ return false;
+ }
+
+ SystemStatusReports reports = {};
+ systemstatus->getReport(reports, true);
+
+ r.size = sizeof(r);
+
+ // location block
+ r.mLocation.size = sizeof(r.mLocation);
+ if(!reports.mLocation.empty() && reports.mLocation.back().mValid) {
+ r.mLocation.mValid = true;
+ r.mLocation.mLocation.latitude =
+ reports.mLocation.back().mLocation.gpsLocation.latitude;
+ r.mLocation.mLocation.longitude =
+ reports.mLocation.back().mLocation.gpsLocation.longitude;
+ r.mLocation.mLocation.altitude =
+ reports.mLocation.back().mLocation.gpsLocation.altitude;
+ r.mLocation.mLocation.speed =
+ (double)(reports.mLocation.back().mLocation.gpsLocation.speed);
+ r.mLocation.mLocation.bearing =
+ (double)(reports.mLocation.back().mLocation.gpsLocation.bearing);
+ r.mLocation.mLocation.accuracy =
+ (double)(reports.mLocation.back().mLocation.gpsLocation.accuracy);
+
+ r.mLocation.verticalAccuracyMeters =
+ reports.mLocation.back().mLocationEx.vert_unc;
+ r.mLocation.speedAccuracyMetersPerSecond =
+ reports.mLocation.back().mLocationEx.speed_unc;
+ r.mLocation.bearingAccuracyDegrees =
+ reports.mLocation.back().mLocationEx.bearing_unc;
+
+ r.mLocation.mUtcReported =
+ reports.mLocation.back().mUtcReported;
+ }
+ else if(!reports.mBestPosition.empty() && reports.mBestPosition.back().mValid) {
+ r.mLocation.mValid = true;
+ r.mLocation.mLocation.latitude =
+ (double)(reports.mBestPosition.back().mBestLat) * RAD2DEG;
+ r.mLocation.mLocation.longitude =
+ (double)(reports.mBestPosition.back().mBestLon) * RAD2DEG;
+ r.mLocation.mLocation.altitude = reports.mBestPosition.back().mBestAlt;
+ r.mLocation.mLocation.accuracy =
+ (double)(reports.mBestPosition.back().mBestHepe);
+
+ r.mLocation.mUtcReported = reports.mBestPosition.back().mUtcReported;
+ }
+ else {
+ r.mLocation.mValid = false;
+ }
+
+ if (r.mLocation.mValid) {
+ LOC_LOGV("getDebugReport - lat=%f lon=%f alt=%f speed=%f",
+ r.mLocation.mLocation.latitude,
+ r.mLocation.mLocation.longitude,
+ r.mLocation.mLocation.altitude,
+ r.mLocation.mLocation.speed);
+ }
+
+ // time block
+ r.mTime.size = sizeof(r.mTime);
+ if(!reports.mTimeAndClock.empty() && reports.mTimeAndClock.back().mTimeValid) {
+ r.mTime.mValid = true;
+ r.mTime.timeEstimate =
+ (((int64_t)(reports.mTimeAndClock.back().mGpsWeek)*7 +
+ GNSS_UTC_TIME_OFFSET)*24*60*60 -
+ (int64_t)(reports.mTimeAndClock.back().mLeapSeconds))*1000ULL +
+ (int64_t)(reports.mTimeAndClock.back().mGpsTowMs);
+
+ if (reports.mTimeAndClock.back().mTimeUncNs > 0) {
+ // TimeUncNs value is available
+ r.mTime.timeUncertaintyNs =
+ (float)(reports.mTimeAndClock.back().mLeapSecUnc)*1000.0f +
+ (float)(reports.mTimeAndClock.back().mTimeUncNs);
+ } else {
+ // fall back to legacy TimeUnc
+ r.mTime.timeUncertaintyNs =
+ ((float)(reports.mTimeAndClock.back().mTimeUnc) +
+ (float)(reports.mTimeAndClock.back().mLeapSecUnc))*1000.0f;
+ }
+
+ r.mTime.frequencyUncertaintyNsPerSec =
+ (float)(reports.mTimeAndClock.back().mClockFreqBiasUnc);
+ LOC_LOGV("getDebugReport - timeestimate=%" PRIu64 " unc=%f frequnc=%f",
+ r.mTime.timeEstimate,
+ r.mTime.timeUncertaintyNs, r.mTime.frequencyUncertaintyNsPerSec);
+ }
+ else {
+ r.mTime.mValid = false;
+ }
+
+ // satellite info block
+ convertSatelliteInfo(r.mSatelliteInfo, GNSS_SV_TYPE_GPS, reports);
+ convertSatelliteInfo(r.mSatelliteInfo, GNSS_SV_TYPE_GLONASS, reports);
+ convertSatelliteInfo(r.mSatelliteInfo, GNSS_SV_TYPE_QZSS, reports);
+ convertSatelliteInfo(r.mSatelliteInfo, GNSS_SV_TYPE_BEIDOU, reports);
+ convertSatelliteInfo(r.mSatelliteInfo, GNSS_SV_TYPE_GALILEO, reports);
+ convertSatelliteInfo(r.mSatelliteInfo, GNSS_SV_TYPE_NAVIC, reports);
+ LOC_LOGV("getDebugReport - satellite=%zu", r.mSatelliteInfo.size());
+
+ return true;
+}
+
+/* get AGC information from system status and fill it */
+void
+GnssAdapter::getAgcInformation(GnssMeasurementsNotification& measurements, int msInWeek)
+{
+ SystemStatus* systemstatus = getSystemStatus();
+
+ if (nullptr != systemstatus) {
+ SystemStatusReports reports = {};
+ systemstatus->getReport(reports, true);
+
+ if ((!reports.mRfAndParams.empty()) && (!reports.mTimeAndClock.empty()) &&
+ (abs(msInWeek - (int)reports.mTimeAndClock.back().mGpsTowMs) < 2000)) {
+
+ for (size_t i = 0; i < measurements.count; i++) {
+ switch (measurements.measurements[i].svType) {
+ case GNSS_SV_TYPE_GPS:
+ case GNSS_SV_TYPE_QZSS:
+ measurements.measurements[i].agcLevelDb =
+ reports.mRfAndParams.back().mAgcGps;
+ measurements.measurements[i].flags |=
+ GNSS_MEASUREMENTS_DATA_AUTOMATIC_GAIN_CONTROL_BIT;
+ break;
+
+ case GNSS_SV_TYPE_GALILEO:
+ measurements.measurements[i].agcLevelDb =
+ reports.mRfAndParams.back().mAgcGal;
+ measurements.measurements[i].flags |=
+ GNSS_MEASUREMENTS_DATA_AUTOMATIC_GAIN_CONTROL_BIT;
+ break;
+
+ case GNSS_SV_TYPE_GLONASS:
+ measurements.measurements[i].agcLevelDb =
+ reports.mRfAndParams.back().mAgcGlo;
+ measurements.measurements[i].flags |=
+ GNSS_MEASUREMENTS_DATA_AUTOMATIC_GAIN_CONTROL_BIT;
+ break;
+
+ case GNSS_SV_TYPE_BEIDOU:
+ measurements.measurements[i].agcLevelDb =
+ reports.mRfAndParams.back().mAgcBds;
+ measurements.measurements[i].flags |=
+ GNSS_MEASUREMENTS_DATA_AUTOMATIC_GAIN_CONTROL_BIT;
+ break;
+
+ case GNSS_SV_TYPE_SBAS:
+ case GNSS_SV_TYPE_UNKNOWN:
+ default:
+ break;
+ }
+ }
+ }
+ }
+}
+
+/* get Data information from system status and fill it */
+void
+GnssAdapter::getDataInformation(GnssDataNotification& data, int msInWeek)
+{
+ SystemStatus* systemstatus = getSystemStatus();
+
+ LOC_LOGV("%s]: msInWeek=%d", __func__, msInWeek);
+ if (nullptr != systemstatus) {
+ SystemStatusReports reports = {};
+ systemstatus->getReport(reports, true);
+
+ if ((!reports.mRfAndParams.empty()) && (!reports.mTimeAndClock.empty()) &&
+ (abs(msInWeek - (int)reports.mTimeAndClock.back().mGpsTowMs) < 2000)) {
+
+ for (int sig = GNSS_LOC_SIGNAL_TYPE_GPS_L1CA;
+ sig < GNSS_LOC_MAX_NUMBER_OF_SIGNAL_TYPES; sig++) {
+ data.gnssDataMask[sig] = 0;
+ data.jammerInd[sig] = 0.0;
+ data.agc[sig] = 0.0;
+ }
+ if (GNSS_INVALID_JAMMER_IND != reports.mRfAndParams.back().mAgcGps) {
+ data.gnssDataMask[GNSS_LOC_SIGNAL_TYPE_GPS_L1CA] |=
+ GNSS_LOC_DATA_AGC_BIT;
+ data.agc[GNSS_LOC_SIGNAL_TYPE_GPS_L1CA] =
+ reports.mRfAndParams.back().mAgcGps;
+ data.gnssDataMask[GNSS_LOC_SIGNAL_TYPE_QZSS_L1CA] |=
+ GNSS_LOC_DATA_AGC_BIT;
+ data.agc[GNSS_LOC_SIGNAL_TYPE_QZSS_L1CA] =
+ reports.mRfAndParams.back().mAgcGps;
+ data.gnssDataMask[GNSS_LOC_SIGNAL_TYPE_SBAS_L1_CA] |=
+ GNSS_LOC_DATA_AGC_BIT;
+ data.agc[GNSS_LOC_SIGNAL_TYPE_SBAS_L1_CA] =
+ reports.mRfAndParams.back().mAgcGps;
+ }
+ if (GNSS_INVALID_JAMMER_IND != reports.mRfAndParams.back().mJammerGps) {
+ data.gnssDataMask[GNSS_LOC_SIGNAL_TYPE_GPS_L1CA] |=
+ GNSS_LOC_DATA_JAMMER_IND_BIT;
+ data.jammerInd[GNSS_LOC_SIGNAL_TYPE_GPS_L1CA] =
+ (double)reports.mRfAndParams.back().mJammerGps;
+ data.gnssDataMask[GNSS_LOC_SIGNAL_TYPE_QZSS_L1CA] |=
+ GNSS_LOC_DATA_JAMMER_IND_BIT;
+ data.jammerInd[GNSS_LOC_SIGNAL_TYPE_QZSS_L1CA] =
+ (double)reports.mRfAndParams.back().mJammerGps;
+ data.gnssDataMask[GNSS_LOC_SIGNAL_TYPE_SBAS_L1_CA] |=
+ GNSS_LOC_DATA_JAMMER_IND_BIT;
+ data.jammerInd[GNSS_LOC_SIGNAL_TYPE_SBAS_L1_CA] =
+ (double)reports.mRfAndParams.back().mJammerGps;
+ }
+ if (GNSS_INVALID_JAMMER_IND != reports.mRfAndParams.back().mAgcGlo) {
+ data.gnssDataMask[GNSS_LOC_SIGNAL_TYPE_GLONASS_G1] |=
+ GNSS_LOC_DATA_AGC_BIT;
+ data.agc[GNSS_LOC_SIGNAL_TYPE_GLONASS_G1] =
+ reports.mRfAndParams.back().mAgcGlo;
+ }
+ if (GNSS_INVALID_JAMMER_IND != reports.mRfAndParams.back().mJammerGlo) {
+ data.gnssDataMask[GNSS_LOC_SIGNAL_TYPE_GLONASS_G1] |=
+ GNSS_LOC_DATA_JAMMER_IND_BIT;
+ data.jammerInd[GNSS_LOC_SIGNAL_TYPE_GLONASS_G1] =
+ (double)reports.mRfAndParams.back().mJammerGlo;
+ }
+ if (GNSS_INVALID_JAMMER_IND != reports.mRfAndParams.back().mAgcBds) {
+ data.gnssDataMask[GNSS_LOC_SIGNAL_TYPE_BEIDOU_B1_I] |=
+ GNSS_LOC_DATA_AGC_BIT;
+ data.agc[GNSS_LOC_SIGNAL_TYPE_BEIDOU_B1_I] =
+ reports.mRfAndParams.back().mAgcBds;
+ }
+ if (GNSS_INVALID_JAMMER_IND != reports.mRfAndParams.back().mJammerBds) {
+ data.gnssDataMask[GNSS_LOC_SIGNAL_TYPE_BEIDOU_B1_I] |=
+ GNSS_LOC_DATA_JAMMER_IND_BIT;
+ data.jammerInd[GNSS_LOC_SIGNAL_TYPE_BEIDOU_B1_I] =
+ (double)reports.mRfAndParams.back().mJammerBds;
+ }
+ if (GNSS_INVALID_JAMMER_IND != reports.mRfAndParams.back().mAgcGal) {
+ data.gnssDataMask[GNSS_LOC_SIGNAL_TYPE_GALILEO_E1_C] |=
+ GNSS_LOC_DATA_AGC_BIT;
+ data.agc[GNSS_LOC_SIGNAL_TYPE_GALILEO_E1_C] =
+ reports.mRfAndParams.back().mAgcGal;
+ }
+ if (GNSS_INVALID_JAMMER_IND != reports.mRfAndParams.back().mJammerGal) {
+ data.gnssDataMask[GNSS_LOC_SIGNAL_TYPE_GALILEO_E1_C] |=
+ GNSS_LOC_DATA_JAMMER_IND_BIT;
+ data.jammerInd[GNSS_LOC_SIGNAL_TYPE_GALILEO_E1_C] =
+ (double)reports.mRfAndParams.back().mJammerGal;
+ }
+ }
+ }
+}
+
+/* Callbacks registered with loc_net_iface library */
+static void agpsOpenResultCb (bool isSuccess, AGpsExtType agpsType, const char* apn,
+ AGpsBearerType bearerType, void* userDataPtr) {
+ LOC_LOGD("%s]: ", __func__);
+ if (userDataPtr == nullptr) {
+ LOC_LOGE("%s]: userDataPtr is nullptr.", __func__);
+ return;
+ }
+ if (apn == nullptr) {
+ LOC_LOGE("%s]: apn is nullptr.", __func__);
+ return;
+ }
+ GnssAdapter* adapter = (GnssAdapter*)userDataPtr;
+ if (isSuccess) {
+ adapter->dataConnOpenCommand(agpsType, apn, strlen(apn), bearerType);
+ } else {
+ adapter->dataConnFailedCommand(agpsType);
+ }
+}
+
+static void agpsCloseResultCb (bool isSuccess, AGpsExtType agpsType, void* userDataPtr) {
+ LOC_LOGD("%s]: ", __func__);
+ if (userDataPtr == nullptr) {
+ LOC_LOGE("%s]: userDataPtr is nullptr.", __func__);
+ return;
+ }
+ GnssAdapter* adapter = (GnssAdapter*)userDataPtr;
+ if (isSuccess) {
+ adapter->dataConnClosedCommand(agpsType);
+ } else {
+ adapter->dataConnFailedCommand(agpsType);
+ }
+}
+
+void
+GnssAdapter::saveGnssEnergyConsumedCallback(GnssEnergyConsumedCallback energyConsumedCb) {
+ mGnssEnergyConsumedCb = energyConsumedCb;
+}
+
+void
+GnssAdapter::getGnssEnergyConsumedCommand(GnssEnergyConsumedCallback energyConsumedCb) {
+ struct MsgGetGnssEnergyConsumed : public LocMsg {
+ GnssAdapter& mAdapter;
+ LocApiBase& mApi;
+ GnssEnergyConsumedCallback mEnergyConsumedCb;
+ inline MsgGetGnssEnergyConsumed(GnssAdapter& adapter, LocApiBase& api,
+ GnssEnergyConsumedCallback energyConsumedCb) :
+ LocMsg(),
+ mAdapter(adapter),
+ mApi(api),
+ mEnergyConsumedCb(energyConsumedCb){}
+ inline virtual void proc() const {
+ mAdapter.saveGnssEnergyConsumedCallback(mEnergyConsumedCb);
+ mApi.getGnssEnergyConsumed();
+ }
+ };
+
+ sendMsg(new MsgGetGnssEnergyConsumed(*this, *mLocApi, energyConsumedCb));
+}
+
+void
+GnssAdapter::nfwControlCommand(bool enable) {
+ struct MsgControlNfwLocationAccess : public LocMsg {
+ GnssAdapter& mAdapter;
+ LocApiBase& mApi;
+ bool mEnable;
+ inline MsgControlNfwLocationAccess(GnssAdapter& adapter, LocApiBase& api,
+ bool enable) :
+ LocMsg(),
+ mAdapter(adapter),
+ mApi(api),
+ mEnable(enable) {}
+ inline virtual void proc() const {
+ GnssConfigGpsLock gpsLock;
+
+ gpsLock = ContextBase::mGps_conf.GPS_LOCK;
+ if (mEnable) {
+ gpsLock &= ~GNSS_CONFIG_GPS_LOCK_NI;
+ } else {
+ gpsLock |= GNSS_CONFIG_GPS_LOCK_NI;
+ }
+ ContextBase::mGps_conf.GPS_LOCK = gpsLock;
+ mApi.sendMsg(new LocApiMsg([&mApi = mApi, gpsLock]() {
+ mApi.setGpsLockSync((GnssConfigGpsLock)gpsLock);
+ }));
+ }
+ };
+
+ if (mSupportNfwControl) {
+ sendMsg(new MsgControlNfwLocationAccess(*this, *mLocApi, enable));
+ } else {
+ LOC_LOGw("NFW control is not supported, do not use this for NFW");
+ }
+}
+
+/* ==== Eng Hub Proxy ================================================================= */
+/* ======== UTILITIES ================================================================= */
+void
+GnssAdapter::initEngHubProxyCommand() {
+ LOC_LOGD("%s]: ", __func__);
+
+ struct MsgInitEngHubProxy : public LocMsg {
+ GnssAdapter* mAdapter;
+ inline MsgInitEngHubProxy(GnssAdapter* adapter) :
+ LocMsg(),
+ mAdapter(adapter) {}
+ inline virtual void proc() const {
+ mAdapter->initEngHubProxy();
+ }
+ };
+
+ sendMsg(new MsgInitEngHubProxy(this));
+}
+
+bool
+GnssAdapter::initEngHubProxy() {
+ static bool firstTime = true;
+ static bool engHubLoadSuccessful = false;
+
+ const char *error = nullptr;
+ unsigned int processListLength = 0;
+ loc_process_info_s_type* processInfoList = nullptr;
+
+ do {
+ // load eng hub only once
+ if (firstTime == false) {
+ break;
+ }
+
+ int rc = loc_read_process_conf(LOC_PATH_IZAT_CONF, &processListLength,
+ &processInfoList);
+ if (rc != 0) {
+ LOC_LOGE("%s]: failed to parse conf file", __func__);
+ break;
+ }
+
+ bool pluginDaemonEnabled = false;
+ // go over the conf table to see whether any plugin daemon is enabled
+ for (unsigned int i = 0; i < processListLength; i++) {
+ if ((strncmp(processInfoList[i].name[0], PROCESS_NAME_ENGINE_SERVICE,
+ strlen(PROCESS_NAME_ENGINE_SERVICE)) == 0) &&
+ (processInfoList[i].proc_status == ENABLED)) {
+ pluginDaemonEnabled = true;
+ break;
+ }
+ }
+
+ // no plugin daemon is enabled for this platform, no need to load eng hub .so
+ if (pluginDaemonEnabled == false) {
+ break;
+ }
+
+ // load the engine hub .so, if the .so is not present
+ // all EngHubProxyBase calls will turn into no-op.
+ void *handle = nullptr;
+ if ((handle = dlopen("libloc_eng_hub.so", RTLD_NOW)) == nullptr) {
+ if ((error = dlerror()) != nullptr) {
+ LOC_LOGE("%s]: libloc_eng_hub.so not found %s !", __func__, error);
+ }
+ break;
+ }
+
+ // prepare the callback functions
+ // callback function for engine hub to report back position event
+ GnssAdapterReportEnginePositionsEventCb reportPositionEventCb =
+ [this](int count, EngineLocationInfo* locationArr) {
+ // report from engine hub on behalf of PPE will be treated as fromUlp
+ reportEnginePositionsEvent(count, locationArr);
+ };
+
+ // callback function for engine hub to report back sv event
+ GnssAdapterReportSvEventCb reportSvEventCb =
+ [this](const GnssSvNotification& svNotify, bool fromEngineHub) {
+ reportSvEvent(svNotify, fromEngineHub);
+ };
+
+ // callback function for engine hub to request for complete aiding data
+ GnssAdapterReqAidingDataCb reqAidingDataCb =
+ [this] (const GnssAidingDataSvMask& svDataMask) {
+ mLocApi->requestForAidingData(svDataMask);
+ };
+
+ getEngHubProxyFn* getter = (getEngHubProxyFn*) dlsym(handle, "getEngHubProxy");
+ if(getter != nullptr) {
+ EngineHubProxyBase* hubProxy = (*getter) (mMsgTask, mSystemStatus->getOsObserver(),
+ reportPositionEventCb,
+ reportSvEventCb, reqAidingDataCb);
+ if (hubProxy != nullptr) {
+ mEngHubProxy = hubProxy;
+ engHubLoadSuccessful = true;
+ }
+ }
+ else {
+ LOC_LOGD("%s]: entered, did not find function", __func__);
+ }
+
+ LOC_LOGD("%s]: first time initialization %d, returned %d",
+ __func__, firstTime, engHubLoadSuccessful);
+
+ } while (0);
+
+ if (processInfoList != nullptr) {
+ free (processInfoList);
+ processInfoList = nullptr;
+ }
+
+ firstTime = false;
+ return engHubLoadSuccessful;
+}
diff --git a/gnss/GnssAdapter.h b/gnss/GnssAdapter.h
new file mode 100644
index 0000000..3ccdd96
--- /dev/null
+++ b/gnss/GnssAdapter.h
@@ -0,0 +1,469 @@
+/* Copyright (c) 2017-2019, 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 GNSS_ADAPTER_H
+#define GNSS_ADAPTER_H
+
+#include <LocAdapterBase.h>
+#include <LocContext.h>
+#include <IOsObserver.h>
+#include <EngineHubProxyBase.h>
+#include <LocationAPI.h>
+#include <Agps.h>
+#include <SystemStatus.h>
+#include <XtraSystemStatusObserver.h>
+#include <map>
+
+#define MAX_URL_LEN 256
+#define NMEA_SENTENCE_MAX_LENGTH 200
+#define GLONASS_SV_ID_OFFSET 64
+#define MAX_SATELLITES_IN_USE 12
+#define LOC_NI_NO_RESPONSE_TIME 20
+#define LOC_GPS_NI_RESPONSE_IGNORE 4
+#define ODCPI_EXPECTED_INJECTION_TIME_MS 10000
+
+class GnssAdapter;
+
+typedef std::map<LocationSessionKey, LocationOptions> LocationSessionMap;
+typedef std::map<LocationSessionKey, TrackingOptions> TrackingOptionsMap;
+
+class OdcpiTimer : public LocTimer {
+public:
+ OdcpiTimer(GnssAdapter* adapter) :
+ LocTimer(), mAdapter(adapter), mActive(false) {}
+
+ inline void start() {
+ mActive = true;
+ LocTimer::start(ODCPI_EXPECTED_INJECTION_TIME_MS, false);
+ }
+ inline void stop() {
+ mActive = false;
+ LocTimer::stop();
+ }
+ inline void restart() {
+ stop();
+ start();
+ }
+ inline bool isActive() {
+ return mActive;
+ }
+
+private:
+ // Override
+ virtual void timeOutCallback() override;
+
+ GnssAdapter* mAdapter;
+ bool mActive;
+};
+
+typedef struct {
+ pthread_t thread; /* NI thread */
+ uint32_t respTimeLeft; /* examine time for NI response */
+ bool respRecvd; /* NI User reponse received or not from Java layer*/
+ void* rawRequest;
+ uint32_t reqID; /* ID to check against response */
+ GnssNiResponse resp;
+ pthread_cond_t tCond;
+ pthread_mutex_t tLock;
+ GnssAdapter* adapter;
+} NiSession;
+typedef struct {
+ NiSession session; /* SUPL NI Session */
+ NiSession sessionEs; /* Emergency SUPL NI Session */
+ uint32_t reqIDCounter;
+} NiData;
+
+typedef enum {
+ NMEA_PROVIDER_AP = 0, // Application Processor Provider of NMEA
+ NMEA_PROVIDER_MP // Modem Processor Provider of NMEA
+} NmeaProviderType;
+typedef struct {
+ GnssSvType svType;
+ const char* talker;
+ uint64_t mask;
+ uint32_t svIdOffset;
+} NmeaSvMeta;
+
+typedef struct {
+ double latitude;
+ double longitude;
+ float accuracy;
+ // the CPI will be blocked until the boot time
+ // specified in blockedTillTsMs
+ int64_t blockedTillTsMs;
+ // CPIs whose both latitude and longitude differ
+ // no more than latLonThreshold will be blocked
+ // in units of degree
+ double latLonDiffThreshold;
+} BlockCPIInfo;
+
+using namespace loc_core;
+
+namespace loc_core {
+ class SystemStatus;
+}
+
+typedef std::function<void(
+ uint64_t gnssEnergyConsumedFromFirstBoot
+)> GnssEnergyConsumedCallback;
+
+typedef void (*powerStateCallback)(bool on);
+
+class GnssAdapter : public LocAdapterBase {
+
+ /* ==== Engine Hub ===================================================================== */
+ EngineHubProxyBase* mEngHubProxy;
+
+ /* ==== TRACKING ======================================================================= */
+ TrackingOptionsMap mTimeBasedTrackingSessions;
+ LocationSessionMap mDistanceBasedTrackingSessions;
+ LocPosMode mLocPositionMode;
+ GnssSvUsedInPosition mGnssSvIdUsedInPosition;
+ bool mGnssSvIdUsedInPosAvail;
+ GnssSvMbUsedInPosition mGnssMbSvIdUsedInPosition;
+ bool mGnssMbSvIdUsedInPosAvail;
+
+ /* ==== CONTROL ======================================================================== */
+ LocationControlCallbacks mControlCallbacks;
+ uint32_t mAfwControlId;
+ uint32_t mNmeaMask;
+ GnssSvIdConfig mGnssSvIdConfig;
+ GnssSvTypeConfig mGnssSvTypeConfig;
+ GnssSvTypeConfigCallback mGnssSvTypeConfigCb;
+ bool mSupportNfwControl;
+
+ /* ==== NI ============================================================================= */
+ NiData mNiData;
+
+ /* ==== AGPS =========================================================================== */
+ // This must be initialized via initAgps()
+ AgpsManager mAgpsManager;
+ void initAgps(const AgpsCbInfo& cbInfo);
+
+ /* ==== NFW =========================================================================== */
+ NfwStatusCb mNfwCb;
+ IsInEmergencySession mIsE911Session;
+ inline void initNfw(const NfwCbInfo& cbInfo) {
+ mNfwCb = (NfwStatusCb)cbInfo.visibilityControlCb;
+ mIsE911Session = (IsInEmergencySession)cbInfo.isInEmergencySession;
+ }
+
+ /* ==== ODCPI ========================================================================== */
+ OdcpiRequestCallback mOdcpiRequestCb;
+ bool mOdcpiRequestActive;
+ OdcpiTimer mOdcpiTimer;
+ OdcpiRequestInfo mOdcpiRequest;
+ void odcpiTimerExpire();
+
+ /* === SystemStatus ===================================================================== */
+ SystemStatus* mSystemStatus;
+ std::string mServerUrl;
+ std::string mMoServerUrl;
+ XtraSystemStatusObserver mXtraObserver;
+ LocationSystemInfo mLocSystemInfo;
+ std::vector<GnssSvIdSource> mBlacklistedSvIds;
+
+ /* === Misc ===================================================================== */
+ BlockCPIInfo mBlockCPIInfo;
+ bool mPowerOn;
+ uint32_t mAllowFlpNetworkFixes;
+
+ /* === Misc callback from QMI LOC API ============================================== */
+ GnssEnergyConsumedCallback mGnssEnergyConsumedCb;
+ powerStateCallback mPowerStateCb;
+
+ /*==== CONVERSION ===================================================================*/
+ static void convertOptions(LocPosMode& out, const TrackingOptions& trackingOptions);
+ static void convertLocation(Location& out, const UlpLocation& ulpLocation,
+ const GpsLocationExtended& locationExtended,
+ const LocPosTechMask techMask);
+ static void convertLocationInfo(GnssLocationInfoNotification& out,
+ const GpsLocationExtended& locationExtended);
+ static uint16_t getNumSvUsed(uint64_t svUsedIdsMask,
+ int totalSvCntInThisConstellation);
+
+ /* ======== UTILITIES ================================================================== */
+ inline void initOdcpi(const OdcpiRequestCallback& callback);
+ inline void injectOdcpi(const Location& location);
+ static bool isFlpClient(LocationCallbacks& locationCallbacks);
+
+protected:
+
+ /* ==== CLIENT ========================================================================= */
+ virtual void updateClientsEventMask();
+ virtual void stopClientSessions(LocationAPI* client);
+
+public:
+
+ GnssAdapter();
+ virtual inline ~GnssAdapter() { }
+
+ /* ==== SSR ============================================================================ */
+ /* ======== EVENTS ====(Called from QMI Thread)========================================= */
+ virtual void handleEngineUpEvent();
+ /* ======== UTILITIES ================================================================== */
+ void restartSessions();
+
+ /* ==== CLIENT ========================================================================= */
+ /* ======== COMMANDS ====(Called from Client Thread)==================================== */
+ virtual void addClientCommand(LocationAPI* client, const LocationCallbacks& callbacks);
+
+ /* ==== TRACKING ======================================================================= */
+ /* ======== COMMANDS ====(Called from Client Thread)==================================== */
+ uint32_t startTrackingCommand(
+ LocationAPI* client, TrackingOptions& trackingOptions);
+ void updateTrackingOptionsCommand(
+ LocationAPI* client, uint32_t id, TrackingOptions& trackingOptions);
+ void stopTrackingCommand(LocationAPI* client, uint32_t id);
+ /* ======== RESPONSES ================================================================== */
+ void reportResponse(LocationAPI* client, LocationError err, uint32_t sessionId);
+ /* ======== UTILITIES ================================================================== */
+ bool hasTrackingCallback(LocationAPI* client);
+ bool isTimeBasedTrackingSession(LocationAPI* client, uint32_t sessionId);
+ bool isDistanceBasedTrackingSession(LocationAPI* client, uint32_t sessionId);
+ bool hasMeasurementsCallback(LocationAPI* client);
+ bool isTrackingSession(LocationAPI* client, uint32_t sessionId);
+ void saveTrackingSession(LocationAPI* client, uint32_t sessionId,
+ const TrackingOptions& trackingOptions);
+ void eraseTrackingSession(LocationAPI* client, uint32_t sessionId);
+
+ bool setLocPositionMode(const LocPosMode& mode);
+ LocPosMode& getLocPositionMode() { return mLocPositionMode; }
+
+ bool startTimeBasedTrackingMultiplex(LocationAPI* client, uint32_t sessionId,
+ const TrackingOptions& trackingOptions);
+ void startTimeBasedTracking(LocationAPI* client, uint32_t sessionId,
+ const TrackingOptions& trackingOptions);
+ bool stopTimeBasedTrackingMultiplex(LocationAPI* client, uint32_t id);
+ void stopTracking(LocationAPI* client, uint32_t id);
+ bool updateTrackingMultiplex(LocationAPI* client, uint32_t id,
+ const TrackingOptions& trackingOptions);
+ void updateTracking(LocationAPI* client, uint32_t sessionId,
+ const TrackingOptions& updatedOptions, const TrackingOptions& oldOptions);
+
+ /* ==== NI ============================================================================= */
+ /* ======== COMMANDS ====(Called from Client Thread)==================================== */
+ void gnssNiResponseCommand(LocationAPI* client, uint32_t id, GnssNiResponse response);
+ /* ======================(Called from NI Thread)======================================== */
+ void gnssNiResponseCommand(GnssNiResponse response, void* rawRequest);
+ /* ======== UTILITIES ================================================================== */
+ bool hasNiNotifyCallback(LocationAPI* client);
+ NiData& getNiData() { return mNiData; }
+
+ /* ==== CONTROL CLIENT ================================================================= */
+ /* ======== COMMANDS ====(Called from Client Thread)==================================== */
+ uint32_t enableCommand(LocationTechnologyType techType);
+ void disableCommand(uint32_t id);
+ void setControlCallbacksCommand(LocationControlCallbacks& controlCallbacks);
+ void readConfigCommand();
+ void requestUlpCommand();
+ void initEngHubProxyCommand();
+ uint32_t* gnssUpdateConfigCommand(GnssConfig config);
+ uint32_t* gnssGetConfigCommand(GnssConfigFlagsMask mask);
+ uint32_t gnssDeleteAidingDataCommand(GnssAidingData& data);
+ void deleteAidingData(const GnssAidingData &data, uint32_t sessionId);
+ void gnssUpdateXtraThrottleCommand(const bool enabled);
+ std::vector<LocationError> gnssUpdateConfig(const std::string& oldMoServerUrl,
+ const GnssConfig& gnssConfigRequested,
+ const GnssConfig& gnssConfigNeedEngineUpdate, size_t count = 0);
+
+ /* ==== GNSS SV TYPE CONFIG ============================================================ */
+ /* ==== COMMANDS ====(Called from Client Thread)======================================== */
+ /* ==== These commands are received directly from client bypassing Location API ======== */
+ void gnssUpdateSvTypeConfigCommand(GnssSvTypeConfig config);
+ void gnssGetSvTypeConfigCommand(GnssSvTypeConfigCallback callback);
+ void gnssResetSvTypeConfigCommand();
+
+ /* ==== UTILITIES ====================================================================== */
+ LocationError gnssSvIdConfigUpdateSync(const std::vector<GnssSvIdSource>& blacklistedSvIds);
+ LocationError gnssSvIdConfigUpdateSync();
+ void gnssSvIdConfigUpdate(const std::vector<GnssSvIdSource>& blacklistedSvIds);
+ void gnssSvIdConfigUpdate();
+ void gnssSvTypeConfigUpdate(const GnssSvTypeConfig& config);
+ void gnssSvTypeConfigUpdate(bool sendReset = false);
+ inline void gnssSetSvTypeConfig(const GnssSvTypeConfig& config)
+ { mGnssSvTypeConfig = config; }
+ inline void gnssSetSvTypeConfigCallback(GnssSvTypeConfigCallback callback)
+ { mGnssSvTypeConfigCb = callback; }
+ inline GnssSvTypeConfigCallback gnssGetSvTypeConfigCallback()
+ { return mGnssSvTypeConfigCb; }
+ void setConfig();
+
+ /* ========= AGPS ====================================================================== */
+ /* ======== COMMANDS ====(Called from Client Thread)==================================== */
+ void initDefaultAgpsCommand();
+ void initAgpsCommand(const AgpsCbInfo& cbInfo);
+ void initNfwCommand(const NfwCbInfo& cbInfo);
+ void dataConnOpenCommand(AGpsExtType agpsType,
+ const char* apnName, int apnLen, AGpsBearerType bearerType);
+ void dataConnClosedCommand(AGpsExtType agpsType);
+ void dataConnFailedCommand(AGpsExtType agpsType);
+ void getGnssEnergyConsumedCommand(GnssEnergyConsumedCallback energyConsumedCb);
+ void nfwControlCommand(bool enable);
+
+ /* ========= ODCPI ===================================================================== */
+ /* ======== COMMANDS ====(Called from Client Thread)==================================== */
+ void initOdcpiCommand(const OdcpiRequestCallback& callback);
+ void injectOdcpiCommand(const Location& location);
+ /* ======== RESPONSES ================================================================== */
+ void reportResponse(LocationError err, uint32_t sessionId);
+ void reportResponse(size_t count, LocationError* errs, uint32_t* ids);
+ /* ======== UTILITIES ================================================================== */
+ LocationControlCallbacks& getControlCallbacks() { return mControlCallbacks; }
+ void setControlCallbacks(const LocationControlCallbacks& controlCallbacks)
+ { mControlCallbacks = controlCallbacks; }
+ void setAfwControlId(uint32_t id) { mAfwControlId = id; }
+ uint32_t getAfwControlId() { return mAfwControlId; }
+ virtual bool isInSession() { return !mTimeBasedTrackingSessions.empty(); }
+ void initDefaultAgps();
+ bool initEngHubProxy();
+ void odcpiTimerExpireEvent();
+
+ /* ==== REPORTS ======================================================================== */
+ /* ======== EVENTS ====(Called from QMI/EngineHub Thread)===================================== */
+ virtual void reportPositionEvent(const UlpLocation& ulpLocation,
+ const GpsLocationExtended& locationExtended,
+ enum loc_sess_status status,
+ LocPosTechMask techMask,
+ GnssDataNotification* pDataNotify = nullptr,
+ int msInWeek = -1);
+ virtual void reportEnginePositionsEvent(unsigned int count,
+ EngineLocationInfo* locationArr);
+
+ virtual void reportSvEvent(const GnssSvNotification& svNotify,
+ bool fromEngineHub=false);
+ virtual void reportNmeaEvent(const char* nmea, size_t length);
+ virtual void reportDataEvent(const GnssDataNotification& dataNotify, int msInWeek);
+ virtual bool requestNiNotifyEvent(const GnssNiNotification& notify, const void* data,
+ const LocInEmergency emergencyState);
+ virtual void reportGnssMeasurementsEvent(const GnssMeasurements& gnssMeasurements,
+ int msInWeek);
+ virtual void reportSvPolynomialEvent(GnssSvPolynomial &svPolynomial);
+ virtual void reportSvEphemerisEvent(GnssSvEphemerisReport & svEphemeris);
+ virtual void reportGnssSvIdConfigEvent(const GnssSvIdConfig& config);
+ virtual void reportGnssSvTypeConfigEvent(const GnssSvTypeConfig& config);
+ virtual bool reportGnssEngEnergyConsumedEvent(uint64_t energyConsumedSinceFirstBoot);
+ virtual void reportLocationSystemInfoEvent(const LocationSystemInfo& locationSystemInfo);
+
+ virtual bool requestATL(int connHandle, LocAGpsType agps_type, LocApnTypeMask apn_type_mask);
+ virtual bool releaseATL(int connHandle);
+ virtual bool requestOdcpiEvent(OdcpiRequestInfo& request);
+ virtual bool reportDeleteAidingDataEvent(GnssAidingData& aidingData);
+ virtual bool reportKlobucharIonoModelEvent(GnssKlobucharIonoModel& ionoModel);
+ virtual bool reportGnssAdditionalSystemInfoEvent(
+ GnssAdditionalSystemInfo& additionalSystemInfo);
+ virtual void reportNfwNotificationEvent(GnssNfwNotification& notification);
+
+ /* ======== UTILITIES ================================================================= */
+ bool needReportForGnssClient(const UlpLocation& ulpLocation,
+ enum loc_sess_status status, LocPosTechMask techMask);
+ bool needReportForFlpClient(enum loc_sess_status status, LocPosTechMask techMask);
+ void reportPosition(const UlpLocation &ulpLocation,
+ const GpsLocationExtended &locationExtended,
+ enum loc_sess_status status,
+ LocPosTechMask techMask);
+ void reportEnginePositions(unsigned int count,
+ const EngineLocationInfo* locationArr);
+ void reportSv(GnssSvNotification& svNotify);
+ void reportNmea(const char* nmea, size_t length);
+ void reportData(GnssDataNotification& dataNotify);
+ bool requestNiNotify(const GnssNiNotification& notify, const void* data,
+ const bool bInformNiAccept);
+ void reportGnssMeasurementData(const GnssMeasurementsNotification& measurements);
+ void reportGnssSvIdConfig(const GnssSvIdConfig& config);
+ void reportGnssSvTypeConfig(const GnssSvTypeConfig& config);
+ void requestOdcpi(const OdcpiRequestInfo& request);
+ void invokeGnssEnergyConsumedCallback(uint64_t energyConsumedSinceFirstBoot);
+ void saveGnssEnergyConsumedCallback(GnssEnergyConsumedCallback energyConsumedCb);
+ void reportLocationSystemInfo(const LocationSystemInfo & locationSystemInfo);
+ inline void reportNfwNotification(const GnssNfwNotification& notification) {
+ if (NULL != mNfwCb) {
+ mNfwCb(notification);
+ }
+ }
+ inline bool getE911State(void) {
+ if (NULL != mIsE911Session) {
+ return mIsE911Session();
+ }
+ return false;
+ }
+
+ /*======== GNSSDEBUG ================================================================*/
+ bool getDebugReport(GnssDebugReport& report);
+ /* get AGC information from system status and fill it */
+ void getAgcInformation(GnssMeasurementsNotification& measurements, int msInWeek);
+ /* get Data information from system status and fill it */
+ void getDataInformation(GnssDataNotification& data, int msInWeek);
+
+ /*==== SYSTEM STATUS ================================================================*/
+ inline SystemStatus* getSystemStatus(void) { return mSystemStatus; }
+ std::string& getServerUrl(void) { return mServerUrl; }
+ std::string& getMoServerUrl(void) { return mMoServerUrl; }
+
+ /*==== CONVERSION ===================================================================*/
+ static uint32_t convertSuplVersion(const GnssConfigSuplVersion suplVersion);
+ static uint32_t convertLppProfile(const GnssConfigLppProfile lppProfile);
+ static uint32_t convertEP4ES(const GnssConfigEmergencyPdnForEmergencySupl);
+ static uint32_t convertSuplEs(const GnssConfigSuplEmergencyServices suplEmergencyServices);
+ static uint32_t convertLppeCp(const GnssConfigLppeControlPlaneMask lppeControlPlaneMask);
+ static uint32_t convertLppeUp(const GnssConfigLppeUserPlaneMask lppeUserPlaneMask);
+ static uint32_t convertAGloProt(const GnssConfigAGlonassPositionProtocolMask);
+ static uint32_t convertSuplMode(const GnssConfigSuplModeMask suplModeMask);
+ static void convertSatelliteInfo(std::vector<GnssDebugSatelliteInfo>& out,
+ const GnssSvType& in_constellation,
+ const SystemStatusReports& in);
+ static bool convertToGnssSvIdConfig(
+ const std::vector<GnssSvIdSource>& blacklistedSvIds, GnssSvIdConfig& config);
+ static void convertFromGnssSvIdConfig(
+ const GnssSvIdConfig& svConfig, GnssConfig& config);
+ static void convertGnssSvIdMaskToList(
+ uint64_t svIdMask, std::vector<GnssSvIdSource>& svIds,
+ GnssSvId initialSvId, GnssSvType svType);
+
+ void injectLocationCommand(double latitude, double longitude, float accuracy);
+ void injectLocationExtCommand(const GnssLocationInfoNotification &locationInfo);
+
+ void injectTimeCommand(int64_t time, int64_t timeReference, int32_t uncertainty);
+ void blockCPICommand(double latitude, double longitude, float accuracy,
+ int blockDurationMsec, double latLonDiffThreshold);
+
+ /* ==== MISCELLANEOUS ================================================================== */
+ /* ======== COMMANDS ====(Called from Client Thread)==================================== */
+ void getPowerStateChangesCommand(void* powerStateCb);
+ /* ======== UTILITIES ================================================================== */
+ void reportPowerStateIfChanged();
+ void savePowerStateCallback(powerStateCallback powerStateCb){ mPowerStateCb = powerStateCb; }
+ bool getPowerState() { return mPowerOn; }
+ void setAllowFlpNetworkFixes(uint32_t allow) { mAllowFlpNetworkFixes = allow; }
+ uint32_t getAllowFlpNetworkFixes() { return mAllowFlpNetworkFixes; }
+ void setSuplHostServer(const char* server, int port, LocServerType type);
+ void notifyClientOfCachedLocationSystemInfo(LocationAPI* client,
+ const LocationCallbacks& callbacks);
+};
+
+#endif //GNSS_ADAPTER_H
diff --git a/gnss/Makefile.am b/gnss/Makefile.am
new file mode 100644
index 0000000..db20c15
--- /dev/null
+++ b/gnss/Makefile.am
@@ -0,0 +1,31 @@
+AM_CFLAGS = \
+ $(LOCPLA_CFLAGS) \
+ $(LOCHAL_CFLAGS) \
+ $(GPSUTILS_CFLAGS) \
+ $(LOCCORE_CFLAGS) \
+ -I./ \
+ -I../utils \
+ -I$(WORKSPACE)/hardware/qcom/gps/core/data-items \
+ -I../location \
+ -std=c++1y
+
+libgnss_la_SOURCES = \
+ location_gnss.cpp \
+ GnssAdapter.cpp \
+ XtraSystemStatusObserver.cpp \
+ Agps.cpp
+
+if USE_GLIB
+libgnss_la_CFLAGS = -DUSE_GLIB $(AM_CFLAGS) @GLIB_CFLAGS@
+libgnss_la_LDFLAGS = -lstdc++ -Wl,-z,defs -lpthread @GLIB_LIBS@ -shared -avoid-version
+libgnss_la_CPPFLAGS = -DUSE_GLIB $(AM_CFLAGS) $(AM_CPPFLAGS) @GLIB_CFLAGS@
+else
+libgnss_la_CFLAGS = $(AM_CFLAGS)
+libgnss_la_LDFLAGS = -Wl,-z,defs -lpthread -shared -version-info 1:0:0
+libgnss_la_CPPFLAGS = $(AM_CFLAGS) $(AM_CPPFLAGS)
+endif
+
+libgnss_la_LIBADD = -lstdc++ -ldl $(GPSUTILS_LIBS) $(LOCCORE_LIBS)
+
+#Create and Install libraries
+lib_LTLIBRARIES = libgnss.la
diff --git a/gnss/XtraSystemStatusObserver.cpp b/gnss/XtraSystemStatusObserver.cpp
new file mode 100644
index 0000000..a58f735
--- /dev/null
+++ b/gnss/XtraSystemStatusObserver.cpp
@@ -0,0 +1,329 @@
+/* Copyright (c) 2017, 2019, 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_XtraSystemStatusObs"
+
+#include <sys/stat.h>
+#include <sys/un.h>
+#include <errno.h>
+#include <ctype.h>
+#include <cutils/properties.h>
+#include <math.h>
+#include <arpa/inet.h>
+#include <netinet/in.h>
+#include <netdb.h>
+#include <string>
+#include <loc_log.h>
+#include <loc_nmea.h>
+#include <SystemStatus.h>
+#include <vector>
+#include <sstream>
+#include <XtraSystemStatusObserver.h>
+#include <LocAdapterBase.h>
+#include <DataItemId.h>
+#include <DataItemsFactoryProxy.h>
+#include <DataItemConcreteTypesBase.h>
+
+using namespace loc_util;
+using namespace loc_core;
+
+#ifdef LOG_TAG
+#undef LOG_TAG
+#endif
+#define LOG_TAG "LocSvc_XSSO"
+
+class XtraIpcListener : public ILocIpcListener {
+ IOsObserver* mSystemStatusObsrvr;
+ const MsgTask* mMsgTask;
+ XtraSystemStatusObserver& mXSSO;
+public:
+ inline XtraIpcListener(IOsObserver* observer, const MsgTask* msgTask,
+ XtraSystemStatusObserver& xsso) :
+ mSystemStatusObsrvr(observer), mMsgTask(msgTask), mXSSO(xsso) {}
+ virtual void onReceive(const char* data, uint32_t length,
+ const LocIpcRecver* recver) override {
+#define STRNCMP(str, constStr) strncmp(str, constStr, sizeof(constStr)-1)
+ if (!STRNCMP(data, "ping")) {
+ LOC_LOGd("ping received");
+#ifdef USE_GLIB
+ } else if (!STRNCMP(data, "connectBackhaul")) {
+ mSystemStatusObsrvr->connectBackhaul();
+ } else if (!STRNCMP(data, "disconnectBackhaul")) {
+ mSystemStatusObsrvr->disconnectBackhaul();
+#endif
+ } else if (!STRNCMP(data, "requestStatus")) {
+ int32_t xtraStatusUpdated = 0;
+ sscanf(data, "%*s %d", &xtraStatusUpdated);
+
+ struct HandleStatusRequestMsg : public LocMsg {
+ XtraSystemStatusObserver& mXSSO;
+ int32_t mXtraStatusUpdated;
+ inline HandleStatusRequestMsg(XtraSystemStatusObserver& xsso,
+ int32_t xtraStatusUpdated) :
+ mXSSO(xsso), mXtraStatusUpdated(xtraStatusUpdated) {}
+ inline void proc() const override {
+ mXSSO.onStatusRequested(mXtraStatusUpdated);
+ }
+ };
+ mMsgTask->sendMsg(new HandleStatusRequestMsg(mXSSO, xtraStatusUpdated));
+ } else {
+ LOC_LOGw("unknown event: %s", data);
+ }
+ }
+};
+
+XtraSystemStatusObserver::XtraSystemStatusObserver(IOsObserver* sysStatObs,
+ const MsgTask* msgTask) :
+ mSystemStatusObsrvr(sysStatObs), mMsgTask(msgTask),
+ mGpsLock(-1), mConnections(~0), mXtraThrottle(true),
+ mReqStatusReceived(false),
+ mIsConnectivityStatusKnown(false),
+ mSender(LocIpc::getLocIpcLocalSender(LOC_IPC_XTRA)),
+ mDelayLocTimer(*mSender) {
+ subscribe(true);
+ auto recver = LocIpc::getLocIpcLocalRecver(
+ make_shared<XtraIpcListener>(sysStatObs, msgTask, *this),
+ LOC_IPC_HAL);
+ mIpc.startNonBlockingListening(recver);
+ mDelayLocTimer.start(100 /*.1 sec*/, false);
+}
+
+bool XtraSystemStatusObserver::updateLockStatus(GnssConfigGpsLock lock) {
+ // mask NI(NFW bit) since from XTRA's standpoint GPS is enabled if
+ // MO(AFW bit) is enabled and disabled when MO is disabled
+ mGpsLock = lock & ~GNSS_CONFIG_GPS_LOCK_NI;
+
+ if (!mReqStatusReceived) {
+ return true;
+ }
+
+ stringstream ss;
+ ss << "gpslock";
+ ss << " " << mGpsLock;
+ string s = ss.str();
+ return ( LocIpc::send(*mSender, (const uint8_t*)s.data(), s.size()) );
+}
+
+bool XtraSystemStatusObserver::updateConnections(uint64_t allConnections,
+ NetworkInfoType* networkHandleInfo) {
+ mIsConnectivityStatusKnown = true;
+ mConnections = allConnections;
+
+ LOC_LOGd("updateConnections mConnections:%" PRIx64, mConnections);
+ for (uint8_t i = 0; i < MAX_NETWORK_HANDLES; ++i) {
+ mNetworkHandle[i] = networkHandleInfo[i];
+ LOC_LOGd("updateConnections [%d] networkHandle:%" PRIx64 " networkType:%u",
+ i, mNetworkHandle[i].networkHandle, mNetworkHandle[i].networkType);
+ }
+
+ if (!mReqStatusReceived) {
+ return true;
+ }
+
+ stringstream ss;
+ ss << "connection" << endl << mConnections << endl
+ << mNetworkHandle[0].toString() << endl
+ << mNetworkHandle[1].toString() << endl
+ << mNetworkHandle[2].toString() << endl
+ << mNetworkHandle[3].toString() << endl
+ << mNetworkHandle[4].toString() << endl
+ << mNetworkHandle[5].toString() << endl
+ << mNetworkHandle[6].toString() << endl
+ << mNetworkHandle[7].toString() << endl
+ << mNetworkHandle[8].toString() << endl
+ << mNetworkHandle[MAX_NETWORK_HANDLES-1].toString();
+ string s = ss.str();
+ return ( LocIpc::send(*mSender, (const uint8_t*)s.data(), s.size()) );
+}
+
+bool XtraSystemStatusObserver::updateTac(const string& tac) {
+ mTac = tac;
+
+ if (!mReqStatusReceived) {
+ return true;
+ }
+
+ stringstream ss;
+ ss << "tac";
+ ss << " " << tac.c_str();
+ string s = ss.str();
+ return ( LocIpc::send(*mSender, (const uint8_t*)s.data(), s.size()) );
+}
+
+bool XtraSystemStatusObserver::updateMccMnc(const string& mccmnc) {
+ mMccmnc = mccmnc;
+
+ if (!mReqStatusReceived) {
+ return true;
+ }
+
+ stringstream ss;
+ ss << "mncmcc";
+ ss << " " << mccmnc.c_str();
+ string s = ss.str();
+ return ( LocIpc::send(*mSender, (const uint8_t*)s.data(), s.size()) );
+}
+
+bool XtraSystemStatusObserver::updateXtraThrottle(const bool enabled) {
+ mXtraThrottle = enabled;
+
+ if (!mReqStatusReceived) {
+ return true;
+ }
+
+ stringstream ss;
+ ss << "xtrathrottle";
+ ss << " " << (enabled ? 1 : 0);
+ string s = ss.str();
+ return ( LocIpc::send(*mSender, (const uint8_t*)s.data(), s.size()) );
+}
+
+inline bool XtraSystemStatusObserver::onStatusRequested(int32_t xtraStatusUpdated) {
+ mReqStatusReceived = true;
+
+ if (xtraStatusUpdated) {
+ return true;
+ }
+
+ stringstream ss;
+
+ ss << "respondStatus" << endl;
+ (mGpsLock == -1 ? ss : ss << mGpsLock) << endl;
+ (mConnections == (uint64_t)~0 ? ss : ss << mConnections) << endl
+ << mNetworkHandle[0].toString() << endl
+ << mNetworkHandle[1].toString() << endl
+ << mNetworkHandle[2].toString() << endl
+ << mNetworkHandle[3].toString() << endl
+ << mNetworkHandle[4].toString() << endl
+ << mNetworkHandle[5].toString() << endl
+ << mNetworkHandle[6].toString() << endl
+ << mNetworkHandle[7].toString() << endl
+ << mNetworkHandle[8].toString() << endl
+ << mNetworkHandle[MAX_NETWORK_HANDLES-1].toString() << endl
+ << mTac << endl << mMccmnc << endl << mIsConnectivityStatusKnown;
+
+ string s = ss.str();
+ return ( LocIpc::send(*mSender, (const uint8_t*)s.data(), s.size()) );
+}
+
+void XtraSystemStatusObserver::subscribe(bool yes)
+{
+ // Subscription data list
+ list<DataItemId> subItemIdList;
+ subItemIdList.push_back(NETWORKINFO_DATA_ITEM_ID);
+ subItemIdList.push_back(MCCMNC_DATA_ITEM_ID);
+
+ if (yes) {
+ mSystemStatusObsrvr->subscribe(subItemIdList, this);
+
+ list<DataItemId> reqItemIdList;
+ reqItemIdList.push_back(TAC_DATA_ITEM_ID);
+
+ mSystemStatusObsrvr->requestData(reqItemIdList, this);
+
+ } else {
+ mSystemStatusObsrvr->unsubscribe(subItemIdList, this);
+ }
+}
+
+// IDataItemObserver overrides
+void XtraSystemStatusObserver::getName(string& name)
+{
+ name = "XtraSystemStatusObserver";
+}
+
+void XtraSystemStatusObserver::notify(const list<IDataItemCore*>& dlist)
+{
+ struct HandleOsObserverUpdateMsg : public LocMsg {
+ XtraSystemStatusObserver* mXtraSysStatObj;
+ list <IDataItemCore*> mDataItemList;
+
+ inline HandleOsObserverUpdateMsg(XtraSystemStatusObserver* xtraSysStatObs,
+ const list<IDataItemCore*>& dataItemList) :
+ mXtraSysStatObj(xtraSysStatObs) {
+ for (auto eachItem : dataItemList) {
+ IDataItemCore* dataitem = DataItemsFactoryProxy::createNewDataItem(
+ eachItem->getId());
+ if (NULL == dataitem) {
+ break;
+ }
+ // Copy the contents of the data item
+ dataitem->copy(eachItem);
+
+ mDataItemList.push_back(dataitem);
+ }
+ }
+
+ inline ~HandleOsObserverUpdateMsg() {
+ for (auto itor = mDataItemList.begin(); itor != mDataItemList.end(); ++itor) {
+ if (*itor != nullptr) {
+ delete *itor;
+ *itor = nullptr;
+ }
+ }
+ }
+
+ inline void proc() const {
+ for (auto each : mDataItemList) {
+ switch (each->getId())
+ {
+ case NETWORKINFO_DATA_ITEM_ID:
+ {
+ NetworkInfoDataItemBase* networkInfo =
+ static_cast<NetworkInfoDataItemBase*>(each);
+ NetworkInfoType* networkHandleInfo =
+ static_cast<NetworkInfoType*>(networkInfo->getNetworkHandle());
+ mXtraSysStatObj->updateConnections(networkInfo->getAllTypes(),
+ networkHandleInfo);
+ }
+ break;
+
+ case TAC_DATA_ITEM_ID:
+ {
+ TacDataItemBase* tac =
+ static_cast<TacDataItemBase*>(each);
+ mXtraSysStatObj->updateTac(tac->mValue);
+ }
+ break;
+
+ case MCCMNC_DATA_ITEM_ID:
+ {
+ MccmncDataItemBase* mccmnc =
+ static_cast<MccmncDataItemBase*>(each);
+ mXtraSysStatObj->updateMccMnc(mccmnc->mValue);
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+ }
+ };
+ mMsgTask->sendMsg(new (nothrow) HandleOsObserverUpdateMsg(this, dlist));
+}
diff --git a/gnss/XtraSystemStatusObserver.h b/gnss/XtraSystemStatusObserver.h
new file mode 100644
index 0000000..3a5259d
--- /dev/null
+++ b/gnss/XtraSystemStatusObserver.h
@@ -0,0 +1,90 @@
+/* Copyright (c) 2017-2019, 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 XTRA_SYSTEM_STATUS_OBS_H
+#define XTRA_SYSTEM_STATUS_OBS_H
+
+#include <cinttypes>
+#include <MsgTask.h>
+#include <LocIpc.h>
+#include <LocTimer.h>
+
+using namespace std;
+using namespace loc_util;
+using loc_core::IOsObserver;
+using loc_core::IDataItemObserver;
+using loc_core::IDataItemCore;
+
+class XtraSystemStatusObserver : public IDataItemObserver {
+public :
+ // constructor & destructor
+ XtraSystemStatusObserver(IOsObserver* sysStatObs, const MsgTask* msgTask);
+ inline virtual ~XtraSystemStatusObserver() {
+ subscribe(false);
+ mIpc.stopNonBlockingListening();
+ }
+
+ // IDataItemObserver overrides
+ inline virtual void getName(string& name);
+ virtual void notify(const list<IDataItemCore*>& dlist);
+
+ bool updateLockStatus(GnssConfigGpsLock lock);
+ bool updateConnections(uint64_t allConnections,
+ loc_core::NetworkInfoType* networkHandleInfo);
+ bool updateTac(const string& tac);
+ bool updateMccMnc(const string& mccmnc);
+ bool updateXtraThrottle(const bool enabled);
+ inline const MsgTask* getMsgTask() { return mMsgTask; }
+ void subscribe(bool yes);
+ bool onStatusRequested(int32_t xtraStatusUpdated);
+
+private:
+ IOsObserver* mSystemStatusObsrvr;
+ const MsgTask* mMsgTask;
+ GnssConfigGpsLock mGpsLock;
+ LocIpc mIpc;
+ uint64_t mConnections;
+ loc_core::NetworkInfoType mNetworkHandle[MAX_NETWORK_HANDLES];
+ string mTac;
+ string mMccmnc;
+ bool mXtraThrottle;
+ bool mReqStatusReceived;
+ bool mIsConnectivityStatusKnown;
+ shared_ptr<LocIpcSender> mSender;
+
+ class DelayLocTimer : public LocTimer {
+ LocIpcSender& mSender;
+ public:
+ DelayLocTimer(LocIpcSender& sender) : mSender(sender) {}
+ void timeOutCallback() override {
+ LocIpc::send(mSender, (const uint8_t*)"halinit", sizeof("halinit"));
+ }
+ } mDelayLocTimer;
+};
+
+#endif
diff --git a/gnss/location_gnss.cpp b/gnss/location_gnss.cpp
new file mode 100644
index 0000000..76839b6
--- /dev/null
+++ b/gnss/location_gnss.cpp
@@ -0,0 +1,392 @@
+/* Copyright (c) 2017-2019, 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.
+ *
+ */
+
+#include "GnssAdapter.h"
+#include "location_interface.h"
+
+static GnssAdapter* gGnssAdapter = NULL;
+
+static void initialize();
+static void deinitialize();
+
+static void addClient(LocationAPI* client, const LocationCallbacks& callbacks);
+static void removeClient(LocationAPI* client, removeClientCompleteCallback rmClientCb);
+static void requestCapabilities(LocationAPI* client);
+
+static uint32_t startTracking(LocationAPI* client, TrackingOptions&);
+static void updateTrackingOptions(LocationAPI* client, uint32_t id, TrackingOptions&);
+static void stopTracking(LocationAPI* client, uint32_t id);
+
+static void gnssNiResponse(LocationAPI* client, uint32_t id, GnssNiResponse response);
+static uint32_t gnssDeleteAidingData(GnssAidingData& data);
+static void gnssUpdateXtraThrottle(const bool enabled);
+
+static void setControlCallbacks(LocationControlCallbacks& controlCallbacks);
+static uint32_t enable(LocationTechnologyType techType);
+static void disable(uint32_t id);
+static uint32_t* gnssUpdateConfig(GnssConfig config);
+static uint32_t* gnssGetConfig(GnssConfigFlagsMask mask);
+
+static void gnssUpdateSvTypeConfig(GnssSvTypeConfig& config);
+static void gnssGetSvTypeConfig(GnssSvTypeConfigCallback& callback);
+static void gnssResetSvTypeConfig();
+
+static void injectLocation(double latitude, double longitude, float accuracy);
+static void injectLocationExt(const GnssLocationInfoNotification &locationInfo);
+static void injectTime(int64_t time, int64_t timeReference, int32_t uncertainty);
+
+static void agpsInit(const AgpsCbInfo& cbInfo);
+static void agpsDataConnOpen(AGpsExtType agpsType, const char* apnName, int apnLen, int ipType);
+static void agpsDataConnClosed(AGpsExtType agpsType);
+static void agpsDataConnFailed(AGpsExtType agpsType);
+static void getDebugReport(GnssDebugReport& report);
+static void updateConnectionStatus(bool connected, int8_t type, bool roaming = false,
+ NetworkHandle networkHandle = NETWORK_HANDLE_UNKNOWN);
+static void getGnssEnergyConsumed(GnssEnergyConsumedCallback energyConsumedCb);
+static void enableNfwLocationAccess(bool enable);
+static void nfwInit(const NfwCbInfo& cbInfo);
+static void getPowerStateChanges(void* powerStateCb);
+
+static void odcpiInit(const OdcpiRequestCallback& callback);
+static void odcpiInject(const Location& location);
+
+static void blockCPI(double latitude, double longitude, float accuracy,
+ int blockDurationMsec, double latLonDiffThreshold);
+static void updateBatteryStatus(bool charging);
+
+static const GnssInterface gGnssInterface = {
+ sizeof(GnssInterface),
+ initialize,
+ deinitialize,
+ addClient,
+ removeClient,
+ requestCapabilities,
+ startTracking,
+ updateTrackingOptions,
+ stopTracking,
+ gnssNiResponse,
+ setControlCallbacks,
+ enable,
+ disable,
+ gnssUpdateConfig,
+ gnssGetConfig,
+ gnssUpdateSvTypeConfig,
+ gnssGetSvTypeConfig,
+ gnssResetSvTypeConfig,
+ gnssDeleteAidingData,
+ gnssUpdateXtraThrottle,
+ injectLocation,
+ injectTime,
+ agpsInit,
+ agpsDataConnOpen,
+ agpsDataConnClosed,
+ agpsDataConnFailed,
+ getDebugReport,
+ updateConnectionStatus,
+ odcpiInit,
+ odcpiInject,
+ blockCPI,
+ getGnssEnergyConsumed,
+ enableNfwLocationAccess,
+ nfwInit,
+ getPowerStateChanges,
+ injectLocationExt,
+ updateBatteryStatus
+};
+
+#ifndef DEBUG_X86
+extern "C" const GnssInterface* getGnssInterface()
+#else
+const GnssInterface* getGnssInterface()
+#endif // DEBUG_X86
+{
+ return &gGnssInterface;
+}
+
+static void initialize()
+{
+ if (NULL == gGnssAdapter) {
+ gGnssAdapter = new GnssAdapter();
+ }
+}
+
+static void deinitialize()
+{
+ if (NULL != gGnssAdapter) {
+ delete gGnssAdapter;
+ gGnssAdapter = NULL;
+ }
+}
+
+static void addClient(LocationAPI* client, const LocationCallbacks& callbacks)
+{
+ if (NULL != gGnssAdapter) {
+ gGnssAdapter->addClientCommand(client, callbacks);
+ }
+}
+
+static void removeClient(LocationAPI* client, removeClientCompleteCallback rmClientCb)
+{
+ if (NULL != gGnssAdapter) {
+ gGnssAdapter->removeClientCommand(client, rmClientCb);
+ }
+}
+
+static void requestCapabilities(LocationAPI* client)
+{
+ if (NULL != gGnssAdapter) {
+ gGnssAdapter->requestCapabilitiesCommand(client);
+ }
+}
+
+static uint32_t startTracking(
+ LocationAPI* client, TrackingOptions& trackingOptions)
+{
+ if (NULL != gGnssAdapter) {
+ return gGnssAdapter->startTrackingCommand(client, trackingOptions);
+ } else {
+ return 0;
+ }
+}
+
+static void updateTrackingOptions(
+ LocationAPI* client, uint32_t id, TrackingOptions& trackingOptions)
+{
+ if (NULL != gGnssAdapter) {
+ gGnssAdapter->updateTrackingOptionsCommand(
+ client, id, trackingOptions);
+ }
+}
+
+static void stopTracking(LocationAPI* client, uint32_t id)
+{
+ if (NULL != gGnssAdapter) {
+ gGnssAdapter->stopTrackingCommand(client, id);
+ }
+}
+
+static void gnssNiResponse(LocationAPI* client, uint32_t id, GnssNiResponse response)
+{
+ if (NULL != gGnssAdapter) {
+ gGnssAdapter->gnssNiResponseCommand(client, id, response);
+ }
+}
+
+static void setControlCallbacks(LocationControlCallbacks& controlCallbacks)
+{
+ if (NULL != gGnssAdapter) {
+ gGnssAdapter->setControlCallbacksCommand(controlCallbacks);
+ }
+}
+
+static uint32_t enable(LocationTechnologyType techType)
+{
+ if (NULL != gGnssAdapter) {
+ return gGnssAdapter->enableCommand(techType);
+ } else {
+ return 0;
+ }
+}
+
+static void disable(uint32_t id)
+{
+ if (NULL != gGnssAdapter) {
+ gGnssAdapter->disableCommand(id);
+ }
+}
+
+static uint32_t* gnssUpdateConfig(GnssConfig config)
+{
+ if (NULL != gGnssAdapter) {
+ return gGnssAdapter->gnssUpdateConfigCommand(config);
+ } else {
+ return NULL;
+ }
+}
+
+static uint32_t* gnssGetConfig(GnssConfigFlagsMask mask)
+{
+ if (NULL != gGnssAdapter) {
+ return gGnssAdapter->gnssGetConfigCommand(mask);
+ } else {
+ return NULL;
+ }
+}
+
+static void gnssUpdateSvTypeConfig(GnssSvTypeConfig& config)
+{
+ if (NULL != gGnssAdapter) {
+ gGnssAdapter->gnssUpdateSvTypeConfigCommand(config);
+ }
+}
+
+static void gnssGetSvTypeConfig(GnssSvTypeConfigCallback& callback)
+{
+ if (NULL != gGnssAdapter) {
+ gGnssAdapter->gnssGetSvTypeConfigCommand(callback);
+ }
+}
+
+static void gnssResetSvTypeConfig()
+{
+ if (NULL != gGnssAdapter) {
+ gGnssAdapter->gnssResetSvTypeConfigCommand();
+ }
+}
+
+static uint32_t gnssDeleteAidingData(GnssAidingData& data)
+{
+ if (NULL != gGnssAdapter) {
+ return gGnssAdapter->gnssDeleteAidingDataCommand(data);
+ } else {
+ return 0;
+ }
+}
+
+static void gnssUpdateXtraThrottle(const bool enabled)
+{
+ if (NULL != gGnssAdapter) {
+ gGnssAdapter->gnssUpdateXtraThrottleCommand(enabled);
+ }
+}
+
+static void injectLocation(double latitude, double longitude, float accuracy)
+{
+ if (NULL != gGnssAdapter) {
+ gGnssAdapter->injectLocationCommand(latitude, longitude, accuracy);
+ }
+}
+
+static void injectTime(int64_t time, int64_t timeReference, int32_t uncertainty)
+{
+ if (NULL != gGnssAdapter) {
+ gGnssAdapter->injectTimeCommand(time, timeReference, uncertainty);
+ }
+}
+
+static void agpsInit(const AgpsCbInfo& cbInfo) {
+
+ if (NULL != gGnssAdapter) {
+ gGnssAdapter->initAgpsCommand(cbInfo);
+ }
+}
+static void agpsDataConnOpen(
+ AGpsExtType agpsType, const char* apnName, int apnLen, int ipType) {
+
+ if (NULL != gGnssAdapter) {
+ gGnssAdapter->dataConnOpenCommand(
+ agpsType, apnName, apnLen, (AGpsBearerType)ipType);
+ }
+}
+static void agpsDataConnClosed(AGpsExtType agpsType) {
+
+ if (NULL != gGnssAdapter) {
+ gGnssAdapter->dataConnClosedCommand(agpsType);
+ }
+}
+static void agpsDataConnFailed(AGpsExtType agpsType) {
+
+ if (NULL != gGnssAdapter) {
+ gGnssAdapter->dataConnFailedCommand(agpsType);
+ }
+}
+
+static void getDebugReport(GnssDebugReport& report) {
+
+ if (NULL != gGnssAdapter) {
+ gGnssAdapter->getDebugReport(report);
+ }
+}
+
+static void updateConnectionStatus(bool connected, int8_t type,
+ bool roaming, NetworkHandle networkHandle) {
+ if (NULL != gGnssAdapter) {
+ gGnssAdapter->getSystemStatus()->eventConnectionStatus(
+ connected, type, roaming, networkHandle);
+ }
+}
+
+static void odcpiInit(const OdcpiRequestCallback& callback)
+{
+ if (NULL != gGnssAdapter) {
+ gGnssAdapter->initOdcpiCommand(callback);
+ }
+}
+
+static void odcpiInject(const Location& location)
+{
+ if (NULL != gGnssAdapter) {
+ gGnssAdapter->injectOdcpiCommand(location);
+ }
+}
+
+static void blockCPI(double latitude, double longitude, float accuracy,
+ int blockDurationMsec, double latLonDiffThreshold) {
+ if (NULL != gGnssAdapter) {
+ gGnssAdapter->blockCPICommand(latitude, longitude, accuracy,
+ blockDurationMsec, latLonDiffThreshold);
+ }
+}
+
+static void getGnssEnergyConsumed(GnssEnergyConsumedCallback energyConsumedCb) {
+ if (NULL != gGnssAdapter) {
+ gGnssAdapter->getGnssEnergyConsumedCommand(energyConsumedCb);
+ }
+}
+
+static void enableNfwLocationAccess(bool enable) {
+ if (NULL != gGnssAdapter) {
+ gGnssAdapter->nfwControlCommand(enable);
+ }
+}
+
+static void nfwInit(const NfwCbInfo& cbInfo) {
+ if (NULL != gGnssAdapter) {
+ gGnssAdapter->initNfwCommand(cbInfo);
+ }
+}
+static void getPowerStateChanges(void* powerStateCb)
+{
+ if (NULL != gGnssAdapter) {
+ gGnssAdapter->getPowerStateChangesCommand(powerStateCb);
+ }
+}
+
+static void injectLocationExt(const GnssLocationInfoNotification &locationInfo)
+{
+ if (NULL != gGnssAdapter) {
+ gGnssAdapter->injectLocationExtCommand(locationInfo);
+ }
+}
+
+static void updateBatteryStatus(bool charging) {
+ if (NULL != gGnssAdapter) {
+ gGnssAdapter->getSystemStatus()->updatePowerConnectState(charging);
+ }
+}
diff --git a/gps_vendor_board.mk b/gps_vendor_board.mk
new file mode 100644
index 0000000..e1915ea
--- /dev/null
+++ b/gps_vendor_board.mk
@@ -0,0 +1,7 @@
+# Flags from BoardConfigVendor.mk
+ifneq ($(TARGET_USES_QMAA),true)
+BOARD_VENDOR_QCOM_GPS_LOC_API_HARDWARE := default
+else ifneq ($(TARGET_USES_QMAA_OVERRIDE_GPS),false)
+BOARD_VENDOR_QCOM_GPS_LOC_API_HARDWARE := default
+endif
+
diff --git a/gps_vendor_product.mk b/gps_vendor_product.mk
new file mode 100644
index 0000000..6e938b3
--- /dev/null
+++ b/gps_vendor_product.mk
@@ -0,0 +1,14 @@
+# HAL packages
+PRODUCT_PACKAGES += android.hardware.gnss@1.0-impl-qti
+PRODUCT_PACKAGES += android.hardware.gnss@1.0-service-qti
+PRODUCT_PACKAGES += android.hardware.gnss@1.1-impl-qti
+PRODUCT_PACKAGES += android.hardware.gnss@1.1-service-qti
+PRODUCT_PACKAGES += android.hardware.gnss@2.0-impl-qti
+PRODUCT_PACKAGES += android.hardware.gnss@2.0-service-qti
+PRODUCT_PACKAGES += gps.conf
+PRODUCT_PACKAGES += libloc_core
+PRODUCT_PACKAGES += libgnss
+PRODUCT_PACKAGES += liblocation_api
+PRODUCT_PACKAGES += libgps.utils
+PRODUCT_PACKAGES += libbatching
+PRODUCT_PACKAGES += libgeofencing
diff --git a/loc-hal.pc.in b/loc-hal.pc.in
new file mode 100644
index 0000000..22d174b
--- /dev/null
+++ b/loc-hal.pc.in
@@ -0,0 +1,10 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+
+Name: loc-hal
+Description: QTI GPS Loc HAL
+Version: @VERSION
+Libs: -L${libdir} -lgnss
+Cflags: -I${includedir} -I${includedir}/utils -I${includedir}/core -I${includedir}/loc-hal
diff --git a/location/Android.mk b/location/Android.mk
new file mode 100644
index 0000000..bbd6fbd
--- /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_VENDOR_MODULE := true
+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_HEADER_LIBRARIES := \
+ libloc_pla_headers \
+ libgps.utils_headers
+
+LOCAL_PRELINK_MODULE := false
+
+LOCAL_CFLAGS += $(GNSS_CFLAGS)
+include $(BUILD_SHARED_LIBRARY)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := liblocation_api_headers
+LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)
+include $(BUILD_HEADER_LIBRARY)
+
+endif # not BUILD_TINY_ANDROID
+endif # BOARD_VENDOR_QCOM_GPS_LOC_API_HARDWARE
diff --git a/location/ILocationAPI.h b/location/ILocationAPI.h
new file mode 100644
index 0000000..3df6f79
--- /dev/null
+++ b/location/ILocationAPI.h
@@ -0,0 +1,194 @@
+/* Copyright (c) 2018 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 ILOCATIONAPI_H
+#define ILOCATIONAPI_H
+
+#include "LocationDataTypes.h"
+
+class ILocationAPI
+{
+public:
+ virtual ~ILocationAPI(){};
+
+ /** @brief Updates/changes the callbacks that will be called.
+ mandatory callbacks must be present for callbacks to be successfully updated
+ no return value */
+ virtual void updateCallbacks(LocationCallbacks&) = 0;
+
+ /* ================================== TRACKING ================================== */
+
+ /** @brief 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 registered trackingCallback
+ periodically according to LocationOptions.
+ @return session id
+ 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
+ LOCATION_ERROR_INVALID_PARAMETER if LocationOptions parameter is invalid */
+ virtual uint32_t startTracking(TrackingOptions&) = 0;
+
+ /** @brief 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 */
+ virtual void stopTracking(uint32_t id) = 0;
+
+ /** @brief 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 */
+ virtual void updateTrackingOptions(uint32_t id, TrackingOptions&) = 0;
+
+ /* ================================== BATCHING ================================== */
+
+ /** @brief 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.
+ @return session id
+ 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
+ LOCATION_ERROR_INVALID_PARAMETER if a parameter is invalid
+ LOCATION_ERROR_NOT_SUPPORTED if batching is not supported */
+ virtual uint32_t startBatching(BatchingOptions&) = 0;
+
+ /** @brief 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 */
+ virtual void stopBatching(uint32_t id) = 0;
+
+ /** @brief 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 */
+ virtual void updateBatchingOptions(uint32_t id, BatchingOptions&) = 0;
+
+ /** @brief 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
+ LOCATION_ERROR_ID_UNKNOWN if id is not associated with a batching session */
+ virtual void getBatchedLocations(uint32_t id, size_t count) = 0;
+
+ /* ================================== GEOFENCE ================================== */
+
+ /** @brief 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.
+ @return id array
+ 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 */
+ virtual uint32_t* addGeofences(size_t count, GeofenceOption*, GeofenceInfo*) = 0;
+
+ /** @brief 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 */
+ virtual void removeGeofences(size_t count, uint32_t* ids) = 0;
+
+ /** @brief 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 */
+ virtual void modifyGeofences(size_t count, uint32_t* ids, GeofenceOption* options) = 0;
+
+ /** @brief 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 */
+ virtual void pauseGeofences(size_t count, uint32_t* ids) = 0;
+
+ /** @brief 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 */
+ virtual void resumeGeofences(size_t count, uint32_t* ids) = 0;
+
+ /* ================================== GNSS ====================================== */
+
+ /** @brief 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 */
+ virtual void gnssNiResponse(uint32_t id, GnssNiResponse response) = 0;
+};
+
+class ILocationControlAPI
+{
+public:
+ virtual ~ILocationControlAPI(){};
+
+ /** @brief 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 ILocationAPI.
+ 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 */
+ virtual uint32_t* gnssUpdateConfig(GnssConfig config) = 0;
+
+ /** @brief 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 ILocationAPI.
+ 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 */
+ virtual uint32_t gnssDeleteAidingData(GnssAidingData& data) = 0;
+};
+
+#endif /* ILOCATIONAPI_H */
diff --git a/location/LocationAPI.cpp b/location/LocationAPI.cpp
new file mode 100644
index 0000000..4348c27
--- /dev/null
+++ b/location/LocationAPI.cpp
@@ -0,0 +1,725 @@
+/* Copyright (c) 2017-2019 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_NDEBUG 0
+#define LOG_TAG "LocSvc_LocationAPI"
+
+#include <location_interface.h>
+#include <dlfcn.h>
+#include <loc_pla.h>
+#include <log_util.h>
+#include <pthread.h>
+#include <map>
+#include <loc_misc_utils.h>
+
+typedef const GnssInterface* (getGnssInterface)();
+typedef const GeofenceInterface* (getGeofenceInterface)();
+typedef const BatchingInterface* (getBatchingInterface)();
+
+typedef struct {
+ // bit mask of the adpaters that we need to wait for the removeClientCompleteCallback
+ // before we invoke the registered locationApiDestroyCompleteCallback
+ LocationAdapterTypeMask waitAdapterMask;
+ locationApiDestroyCompleteCallback destroyCompleteCb;
+} LocationAPIDestroyCbData;
+
+// This is the map for the client that has requested destroy with
+// destroy callback provided.
+typedef std::map<LocationAPI*, LocationAPIDestroyCbData>
+ LocationClientDestroyCbMap;
+
+typedef std::map<LocationAPI*, LocationCallbacks> LocationClientMap;
+typedef struct {
+ LocationClientMap clientData;
+ LocationClientDestroyCbMap destroyClientData;
+ LocationControlAPI* controlAPI;
+ LocationControlCallbacks controlCallbacks;
+ GnssInterface* gnssInterface;
+ GeofenceInterface* geofenceInterface;
+ BatchingInterface* batchingInterface;
+} LocationAPIData;
+
+static LocationAPIData gData = {};
+static pthread_mutex_t gDataMutex = PTHREAD_MUTEX_INITIALIZER;
+static bool gGnssLoadFailed = false;
+static bool gBatchingLoadFailed = false;
+static bool gGeofenceLoadFailed = false;
+
+template <typename T1, typename T2>
+static const T1* loadLocationInterface(const char* library, const char* name) {
+ void* libhandle = nullptr;
+ T2* getter = (T2*)dlGetSymFromLib(libhandle, library, name);
+ if (nullptr == getter) {
+ return (const T1*) getter;
+ }else {
+ return (*getter)();
+ }
+}
+
+static bool isGnssClient(LocationCallbacks& locationCallbacks)
+{
+ return (locationCallbacks.gnssNiCb != nullptr ||
+ locationCallbacks.trackingCb != nullptr ||
+ locationCallbacks.gnssLocationInfoCb != nullptr ||
+ locationCallbacks.engineLocationsInfoCb != nullptr ||
+ locationCallbacks.gnssMeasurementsCb != nullptr);
+}
+
+static bool isBatchingClient(LocationCallbacks& locationCallbacks)
+{
+ return (locationCallbacks.batchingCb != nullptr);
+}
+
+static bool isGeofenceClient(LocationCallbacks& locationCallbacks)
+{
+ return (locationCallbacks.geofenceBreachCb != nullptr ||
+ locationCallbacks.geofenceStatusCb != nullptr);
+}
+
+
+void LocationAPI::onRemoveClientCompleteCb (LocationAdapterTypeMask adapterType)
+{
+ bool invokeCallback = false;
+ locationApiDestroyCompleteCallback destroyCompleteCb;
+ LOC_LOGd("adatper type %x", adapterType);
+ pthread_mutex_lock(&gDataMutex);
+ auto it = gData.destroyClientData.find(this);
+ if (it != gData.destroyClientData.end()) {
+ it->second.waitAdapterMask &= ~adapterType;
+ if (it->second.waitAdapterMask == 0) {
+ invokeCallback = true;
+ destroyCompleteCb = it->second.destroyCompleteCb;
+ gData.destroyClientData.erase(it);
+ }
+ }
+ pthread_mutex_unlock(&gDataMutex);
+
+ if ((true == invokeCallback) && (nullptr != destroyCompleteCb)) {
+ LOC_LOGd("invoke client destroy cb");
+ (destroyCompleteCb) ();
+ LOC_LOGd("finish invoke client destroy cb");
+
+ delete this;
+ }
+}
+
+void onGnssRemoveClientCompleteCb (LocationAPI* client)
+{
+ client->onRemoveClientCompleteCb (LOCATION_ADAPTER_GNSS_TYPE_BIT);
+}
+
+void onBatchingRemoveClientCompleteCb (LocationAPI* client)
+{
+ client->onRemoveClientCompleteCb (LOCATION_ADAPTER_BATCHING_TYPE_BIT);
+}
+
+void onGeofenceRemoveClientCompleteCb (LocationAPI* client)
+{
+ client->onRemoveClientCompleteCb (LOCATION_ADAPTER_GEOFENCE_TYPE_BIT);
+}
+
+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<GnssInterface,
+ getGnssInterface>("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 (isBatchingClient(locationCallbacks)) {
+ if (NULL == gData.batchingInterface && !gBatchingLoadFailed) {
+ gData.batchingInterface =
+ (BatchingInterface*)loadLocationInterface<BatchingInterface,
+ getBatchingInterface>("libbatching.so", "getBatchingInterface");
+ if (NULL == gData.batchingInterface) {
+ gBatchingLoadFailed = true;
+ LOC_LOGW("%s:%d]: No batching interface available", __func__, __LINE__);
+ } else {
+ gData.batchingInterface->initialize();
+ }
+ }
+ if (NULL != gData.batchingInterface) {
+ gData.batchingInterface->addClient(newLocationAPI, locationCallbacks);
+ if (!requestedCapabilities) {
+ gData.batchingInterface->requestCapabilities(newLocationAPI);
+ requestedCapabilities = true;
+ }
+ }
+ }
+
+ if (isGeofenceClient(locationCallbacks)) {
+ if (NULL == gData.geofenceInterface && !gGeofenceLoadFailed) {
+ gData.geofenceInterface =
+ (GeofenceInterface*)loadLocationInterface<GeofenceInterface,
+ getGeofenceInterface>("libgeofencing.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(locationApiDestroyCompleteCallback destroyCompleteCb)
+{
+ bool invokeDestroyCb = false;
+
+ pthread_mutex_lock(&gDataMutex);
+ auto it = gData.clientData.find(this);
+ if (it != gData.clientData.end()) {
+ bool removeFromGnssInf =
+ (isGnssClient(it->second) && NULL != gData.gnssInterface);
+ bool removeFromBatchingInf =
+ (isBatchingClient(it->second) && NULL != gData.batchingInterface);
+ bool removeFromGeofenceInf =
+ (isGeofenceClient(it->second) && NULL != gData.geofenceInterface);
+ bool needToWait = (removeFromGnssInf || removeFromBatchingInf || removeFromGeofenceInf);
+ LOC_LOGe("removeFromGnssInf: %d, removeFromBatchingInf: %d, removeFromGeofenceInf: %d,"
+ "need %d", removeFromGnssInf, removeFromBatchingInf, removeFromGeofenceInf,
+ needToWait);
+
+ if ((NULL != destroyCompleteCb) && (true == needToWait)) {
+ LocationAPIDestroyCbData destroyCbData = {};
+ destroyCbData.destroyCompleteCb = destroyCompleteCb;
+ // record down from which adapter we need to wait for the destroy complete callback
+ // only when we have received all the needed callbacks from all the associated stacks,
+ // we shall notify the client.
+ destroyCbData.waitAdapterMask =
+ (removeFromGnssInf ? LOCATION_ADAPTER_GNSS_TYPE_BIT : 0);
+ destroyCbData.waitAdapterMask |=
+ (removeFromBatchingInf ? LOCATION_ADAPTER_BATCHING_TYPE_BIT : 0);
+ destroyCbData.waitAdapterMask |=
+ (removeFromGeofenceInf ? LOCATION_ADAPTER_GEOFENCE_TYPE_BIT : 0);
+ gData.destroyClientData[this] = destroyCbData;
+ LOC_LOGe("destroy data stored in the map: 0x%x", destroyCbData.waitAdapterMask);
+ }
+
+ if (removeFromGnssInf) {
+ gData.gnssInterface->removeClient(it->first,
+ onGnssRemoveClientCompleteCb);
+ }
+ if (removeFromBatchingInf) {
+ gData.batchingInterface->removeClient(it->first,
+ onBatchingRemoveClientCompleteCb);
+ }
+ if (removeFromGeofenceInf) {
+ gData.geofenceInterface->removeClient(it->first,
+ onGeofenceRemoveClientCompleteCb);
+ }
+
+ gData.clientData.erase(it);
+
+ if ((NULL != destroyCompleteCb) && (false == needToWait)) {
+ invokeDestroyCb = true;
+ }
+ } else {
+ LOC_LOGE("%s:%d]: Location API client %p not found in client data",
+ __func__, __LINE__, this);
+ }
+
+ pthread_mutex_unlock(&gDataMutex);
+ if (invokeDestroyCb == true) {
+ (destroyCompleteCb) ();
+ delete this;
+ }
+}
+
+LocationAPI::LocationAPI()
+{
+ LOC_LOGD("LOCATION API CONSTRUCTOR");
+}
+
+// private destructor
+LocationAPI::~LocationAPI()
+{
+ LOC_LOGD("LOCATION API DESTRUCTOR");
+}
+
+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<GnssInterface,
+ getGnssInterface>("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 (isBatchingClient(locationCallbacks)) {
+ if (NULL == gData.batchingInterface && !gBatchingLoadFailed) {
+ gData.batchingInterface =
+ (BatchingInterface*)loadLocationInterface<BatchingInterface,
+ getBatchingInterface>("libbatching.so", "getBatchingInterface");
+ if (NULL == gData.batchingInterface) {
+ gBatchingLoadFailed = true;
+ LOC_LOGW("%s:%d]: No batching interface available", __func__, __LINE__);
+ } else {
+ gData.batchingInterface->initialize();
+ }
+ }
+ if (NULL != gData.batchingInterface) {
+ // either adds new Client or updates existing Client
+ gData.batchingInterface->addClient(this, locationCallbacks);
+ }
+ }
+
+ if (isGeofenceClient(locationCallbacks)) {
+ if (NULL == gData.geofenceInterface && !gGeofenceLoadFailed) {
+ gData.geofenceInterface =
+ (GeofenceInterface*)loadLocationInterface<GeofenceInterface,
+ getGeofenceInterface>("libgeofencing.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(TrackingOptions& trackingOptions)
+{
+ uint32_t id = 0;
+ pthread_mutex_lock(&gDataMutex);
+
+ auto it = gData.clientData.find(this);
+ if (it != gData.clientData.end()) {
+ if (NULL != gData.gnssInterface) {
+ id = gData.gnssInterface->startTracking(this, trackingOptions);
+ } else {
+ LOC_LOGE("%s:%d]: No gnss 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()) {
+ if (gData.gnssInterface != NULL) {
+ gData.gnssInterface->stopTracking(this, id);
+ } else {
+ LOC_LOGE("%s:%d]: No gnss 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, TrackingOptions& trackingOptions)
+{
+ pthread_mutex_lock(&gDataMutex);
+
+ auto it = gData.clientData.find(this);
+ if (it != gData.clientData.end()) {
+ if (gData.gnssInterface != NULL) {
+ gData.gnssInterface->updateTrackingOptions(this, id, trackingOptions);
+ } else {
+ LOC_LOGE("%s:%d]: No gnss 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(BatchingOptions &batchingOptions)
+{
+ uint32_t id = 0;
+ pthread_mutex_lock(&gDataMutex);
+
+ if (NULL != gData.batchingInterface) {
+ id = gData.batchingInterface->startBatching(this, batchingOptions);
+ } else {
+ LOC_LOGE("%s:%d]: No batching 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 (NULL != gData.batchingInterface) {
+ gData.batchingInterface->stopBatching(this, id);
+ } else {
+ LOC_LOGE("%s:%d]: No batching interface available for Location API client %p ",
+ __func__, __LINE__, this);
+ }
+
+ pthread_mutex_unlock(&gDataMutex);
+}
+
+void
+LocationAPI::updateBatchingOptions(uint32_t id, BatchingOptions& batchOptions)
+{
+ pthread_mutex_lock(&gDataMutex);
+
+ if (NULL != gData.batchingInterface) {
+ gData.batchingInterface->updateBatchingOptions(this, id, batchOptions);
+ } else {
+ LOC_LOGE("%s:%d]: No batching 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.batchingInterface != NULL) {
+ gData.batchingInterface->getBatchedLocations(this, id, count);
+ } else {
+ LOC_LOGE("%s:%d]: No batching 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<GnssInterface,
+ getGnssInterface>("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);
+
+ 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::gnssGetConfig(GnssConfigFlagsMask mask) {
+
+ uint32_t* ids = NULL;
+ pthread_mutex_lock(&gDataMutex);
+
+ if (NULL != gData.gnssInterface) {
+ ids = gData.gnssInterface->gnssGetConfig(mask);
+ } else {
+ LOC_LOGe("No gnss interface available for Control API client %p", 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..6f5987c
--- /dev/null
+++ b/location/LocationAPI.h
@@ -0,0 +1,266 @@
+/* Copyright (c) 2017-2018 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 LOCATIONAPI_H
+#define LOCATIONAPI_H
+
+#include "ILocationAPI.h"
+
+class LocationAPI : public ILocationAPI
+{
+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 LocationControlAPI object is
+ no longer needed. LocationControlAPI* returned from createInstance will no longer valid
+ after destroy is called.
+ If the caller allocates the memory for LocationControlCallbacks used in
+ LocationControlAPI::createInstance, then the caller must ensure that the memory still remains
+ valid until destroyCompleteCb is invoked.
+ */
+ void destroy(locationApiDestroyCompleteCallback destroyCompleteCb=nullptr);
+
+ void onRemoveClientCompleteCb (LocationAdapterTypeMask adapterType);
+
+ /* updates/changes the callbacks that will be called.
+ mandatory callbacks must be present for callbacks to be successfully updated
+ no return value */
+ virtual void updateCallbacks(LocationCallbacks&) override;
+
+ /* ================================== 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 TrackingOptions parameter is invalid */
+ virtual uint32_t startTracking(TrackingOptions&) override;
+
+ /* 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 */
+ virtual void stopTracking(uint32_t id) override;
+
+ /* updateTrackingOptions changes the TrackingOptions of a tracking session associated with id
+ responseCallback returns:
+ LOCATION_ERROR_SUCCESS if successful
+ LOCATION_ERROR_INVALID_PARAMETER if TrackingOptions parameters are invalid
+ LOCATION_ERROR_ID_UNKNOWN if id is not associated with a tracking session */
+ virtual void updateTrackingOptions(uint32_t id, TrackingOptions&) override;
+
+ /* ================================== 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 */
+ virtual uint32_t startBatching(BatchingOptions&) override;
+
+ /* 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 */
+ virtual void stopBatching(uint32_t id) override;
+
+ /* updateBatchingOptions changes the BatchingOptions of a batching session associated with id
+ responseCallback returns:
+ LOCATION_ERROR_SUCCESS if successful
+ LOCATION_ERROR_INVALID_PARAMETER if BatchingOptions parameters are invalid
+ LOCATION_ERROR_ID_UNKNOWN if id is not associated with a batching session */
+ virtual void updateBatchingOptions(uint32_t id, BatchingOptions&) override;
+
+ /* 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 */
+ virtual void getBatchedLocations(uint32_t id, size_t count) override;
+
+ /* ================================== 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 */
+ virtual uint32_t* addGeofences(size_t count, GeofenceOption*, GeofenceInfo*) override;
+
+ /* 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 */
+ virtual void removeGeofences(size_t count, uint32_t* ids) override;
+
+ /* 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 */
+ virtual void modifyGeofences(size_t count, uint32_t* ids, GeofenceOption* options) override;
+
+ /* 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 */
+ virtual void pauseGeofences(size_t count, uint32_t* ids) override;
+
+ /* 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 */
+ virtual void resumeGeofences(size_t count, uint32_t* ids) override;
+
+ /* ================================== 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 */
+ virtual void gnssNiResponse(uint32_t id, GnssNiResponse response) override;
+};
+
+typedef struct {
+ size_t size; // set to sizeof(LocationControlCallbacks)
+ responseCallback responseCb; // mandatory
+ collectiveResponseCallback collectiveResponseCb; // mandatory
+ gnssConfigCallback gnssConfigCb; // optional
+} LocationControlCallbacks;
+
+class LocationControlAPI : public ILocationControlAPI
+{
+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 */
+ virtual uint32_t* gnssUpdateConfig(GnssConfig config) override;
+
+ /* gnssGetConfig fetches the current constellation and SV configuration
+ on the GNSS engine.
+ Returns a session id array with an id for each of the bits set in
+ the mask parameter, order from low bits to high bits.
+ Response is sent via the registered gnssConfigCallback.
+ This effect is global for all clients of LocationAPI
+ collectiveResponseCallback returns:
+ LOCATION_ERROR_SUCCESS if session was successful
+ LOCATION_ERROR_INVALID_PARAMETER if any parameter is invalid
+ LOCATION_ERROR_CALLBACK_MISSING If no gnssConfigCallback
+ was passed in createInstance
+ LOCATION_ERROR_NOT_SUPPORTED If read of requested configuration
+ is not supported */
+ uint32_t* gnssGetConfig(GnssConfigFlagsMask mask);
+
+ /* 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 */
+ virtual uint32_t gnssDeleteAidingData(GnssAidingData& data) override;
+};
+
+#endif /* LOCATIONAPI_H */
diff --git a/location/LocationAPIClientBase.cpp b/location/LocationAPIClientBase.cpp
new file mode 100644
index 0000000..5a09712
--- /dev/null
+++ b/location/LocationAPIClientBase.cpp
@@ -0,0 +1,954 @@
+/* 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_NDEBUG 0
+#define LOG_TAG "LocSvc_APIClientBase"
+
+#include <loc_pla.h>
+#include <log_util.h>
+#include <inttypes.h>
+#include <loc_cfg.h>
+#include "LocationAPIClientBase.h"
+
+#define GEOFENCE_SESSION_ID 0xFFFFFFFF
+#define CONFIG_SESSION_ID 0xFFFFFFFF
+
+// LocationAPIControlClient
+LocationAPIControlClient::LocationAPIControlClient() :
+ mEnabled(false)
+{
+ pthread_mutex_init(&mMutex, nullptr);
+
+ for (int i = 0; i < CTRL_REQUEST_MAX; i++) {
+ mRequestQueues[i].reset((uint32_t)0);
+ }
+
+ memset(&mConfig, 0, sizeof(GnssConfig));
+
+ 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);
+}
+
+LocationAPIControlClient::~LocationAPIControlClient()
+{
+ pthread_mutex_lock(&mMutex);
+
+ if (mLocationControlAPI) {
+ mLocationControlAPI->destroy();
+ mLocationControlAPI = nullptr;
+ }
+
+ for (int i = 0; i < CTRL_REQUEST_MAX; i++) {
+ mRequestQueues[i].reset((uint32_t)0);
+ }
+
+ pthread_mutex_unlock(&mMutex);
+
+ pthread_mutex_destroy(&mMutex);
+}
+
+uint32_t LocationAPIControlClient::locAPIGnssDeleteAidingData(GnssAidingData& data)
+{
+ uint32_t retVal = LOCATION_ERROR_GENERAL_FAILURE;
+ pthread_mutex_lock(&mMutex);
+ if (mLocationControlAPI) {
+ uint32_t session = mLocationControlAPI->gnssDeleteAidingData(data);
+ LOC_LOGI("%s:%d] start new session: %d", __FUNCTION__, __LINE__, session);
+ mRequestQueues[CTRL_REQUEST_DELETEAIDINGDATA].reset(session);
+ mRequestQueues[CTRL_REQUEST_DELETEAIDINGDATA].push(new GnssDeleteAidingDataRequest(*this));
+
+ retVal = LOCATION_ERROR_SUCCESS;
+ }
+ pthread_mutex_unlock(&mMutex);
+
+ return retVal;
+}
+
+uint32_t LocationAPIControlClient::locAPIEnable(LocationTechnologyType techType)
+{
+ uint32_t retVal = LOCATION_ERROR_GENERAL_FAILURE;
+ pthread_mutex_lock(&mMutex);
+ if (mEnabled) {
+ // just return success if already enabled
+ retVal = LOCATION_ERROR_SUCCESS;
+ } else if (mLocationControlAPI) {
+ uint32_t session = mLocationControlAPI->enable(techType);
+ LOC_LOGI("%s:%d] start new session: %d", __FUNCTION__, __LINE__, session);
+ mRequestQueues[CTRL_REQUEST_CONTROL].reset(session);
+ mRequestQueues[CTRL_REQUEST_CONTROL].push(new EnableRequest(*this));
+ retVal = LOCATION_ERROR_SUCCESS;
+ mEnabled = true;
+ } else {
+ LOC_LOGE("%s:%d] failed.", __FUNCTION__, __LINE__);
+ }
+ pthread_mutex_unlock(&mMutex);
+
+ return retVal;
+}
+
+void LocationAPIControlClient::locAPIDisable()
+{
+ pthread_mutex_lock(&mMutex);
+ if (mEnabled && mLocationControlAPI) {
+ uint32_t session = 0;
+ session = mRequestQueues[CTRL_REQUEST_CONTROL].getSession();
+ if (session > 0) {
+ mRequestQueues[CTRL_REQUEST_CONTROL].push(new DisableRequest(*this));
+ mLocationControlAPI->disable(session);
+ mEnabled = false;
+ } else {
+ LOC_LOGE("%s:%d] invalid session: %d.", __FUNCTION__, __LINE__, session);
+ }
+ }
+ pthread_mutex_unlock(&mMutex);
+}
+
+uint32_t LocationAPIControlClient::locAPIGnssUpdateConfig(GnssConfig config)
+{
+ uint32_t retVal = LOCATION_ERROR_GENERAL_FAILURE;
+
+ pthread_mutex_lock(&mMutex);
+ if (mLocationControlAPI) {
+ if (mConfig.equals(config)) {
+ LOC_LOGv("GnssConfig is identical to previous call");
+ retVal = LOCATION_ERROR_SUCCESS;
+ } else {
+ mConfig = config;
+ uint32_t* idArray = mLocationControlAPI->gnssUpdateConfig(config);
+ LOC_LOGv("gnssUpdateConfig return array: %p", idArray);
+ if (nullptr != idArray) {
+ if (nullptr != mRequestQueues[CTRL_REQUEST_CONFIG_UPDATE].getSessionArrayPtr()) {
+ mRequestQueues[CTRL_REQUEST_CONFIG_UPDATE].reset(idArray);
+ }
+ mRequestQueues[CTRL_REQUEST_CONFIG_UPDATE].push(new GnssUpdateConfigRequest(*this));
+ retVal = LOCATION_ERROR_SUCCESS;
+ }
+ }
+ }
+ pthread_mutex_unlock(&mMutex);
+ return retVal;
+}
+
+uint32_t LocationAPIControlClient::locAPIGnssGetConfig(GnssConfigFlagsMask mask)
+{
+ uint32_t retVal = LOCATION_ERROR_GENERAL_FAILURE;
+
+ pthread_mutex_lock(&mMutex);
+ if (mLocationControlAPI) {
+
+ uint32_t* idArray = mLocationControlAPI->gnssGetConfig(mask);
+ LOC_LOGv("gnssGetConfig return array: %p", idArray);
+ if (nullptr != idArray) {
+ if (nullptr != mRequestQueues[CTRL_REQUEST_CONFIG_GET].getSessionArrayPtr()) {
+ mRequestQueues[CTRL_REQUEST_CONFIG_GET].reset(idArray);
+ }
+ mRequestQueues[CTRL_REQUEST_CONFIG_GET].push(new GnssGetConfigRequest(*this));
+ retVal = LOCATION_ERROR_SUCCESS;
+ }
+ }
+ pthread_mutex_unlock(&mMutex);
+ return retVal;
+}
+
+void LocationAPIControlClient::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] SUCCESS: %d id: %d", __FUNCTION__, __LINE__, error, id);
+ }
+ LocationAPIRequest* request = getRequestBySession(id);
+ if (request) {
+ request->onResponse(error, id);
+ delete request;
+ }
+}
+
+void LocationAPIControlClient::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] SUCCESS: %d id: %d", __FUNCTION__, __LINE__, errors[i], ids[i]);
+ }
+ }
+ LocationAPIRequest* request = getRequestBySessionArrayPtr(ids);
+ if (request) {
+ request->onCollectiveResponse(count, errors, ids);
+ delete request;
+ }
+}
+
+LocationAPIRequest* LocationAPIControlClient::getRequestBySession(uint32_t session)
+{
+ pthread_mutex_lock(&mMutex);
+ LocationAPIRequest* request = nullptr;
+
+ if (mRequestQueues[CTRL_REQUEST_DELETEAIDINGDATA].getSession() == session) {
+ request = mRequestQueues[CTRL_REQUEST_DELETEAIDINGDATA].pop();
+ } else if (mRequestQueues[CTRL_REQUEST_CONTROL].getSession() == session) {
+ request = mRequestQueues[CTRL_REQUEST_CONTROL].pop();
+ }
+
+ pthread_mutex_unlock(&mMutex);
+ return request;
+}
+
+LocationAPIRequest*
+LocationAPIControlClient::getRequestBySessionArrayPtr(
+ uint32_t* sessionArrayPtr)
+{
+ pthread_mutex_lock(&mMutex);
+ LocationAPIRequest* request = nullptr;
+
+ if (mRequestQueues[CTRL_REQUEST_CONFIG_UPDATE].getSessionArrayPtr() == sessionArrayPtr) {
+ request = mRequestQueues[CTRL_REQUEST_CONFIG_UPDATE].pop();
+ } else if (mRequestQueues[CTRL_REQUEST_CONFIG_GET].getSessionArrayPtr() == sessionArrayPtr) {
+ request = mRequestQueues[CTRL_REQUEST_CONFIG_GET].pop();
+ }
+
+ pthread_mutex_unlock(&mMutex);
+ return request;
+}
+
+// LocationAPIClientBase
+LocationAPIClientBase::LocationAPIClientBase() :
+ mGeofenceBreachCallback(nullptr),
+ mBatchingStatusCallback(nullptr),
+ mLocationAPI(nullptr),
+ mBatchSize(-1),
+ mTracking(false)
+{
+
+ // 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].reset((uint32_t)0);
+ }
+}
+
+void LocationAPIClientBase::locAPISetCallbacks(LocationCallbacks& locationCallbacks)
+{
+ pthread_mutex_lock(&mMutex);
+
+ 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 (locationCallbacks.batchingStatusCb != nullptr) {
+ mBatchingStatusCallback = locationCallbacks.batchingStatusCb;
+ locationCallbacks.batchingStatusCb =
+ [this](BatchingStatusInfo batchStatus, std::list<uint32_t> & tripCompletedList) {
+ beforeBatchingStatusCb(batchStatus, tripCompletedList);
+ };
+ }
+
+ if (mLocationAPI == nullptr ) {
+ mLocationAPI = LocationAPI::createInstance(locationCallbacks);
+ } else {
+ mLocationAPI->updateCallbacks(locationCallbacks);
+ }
+
+ pthread_mutex_unlock(&mMutex);
+}
+
+LocationAPIClientBase::~LocationAPIClientBase()
+{
+ pthread_mutex_lock(&mMutex);
+
+ mGeofenceBreachCallback = nullptr;
+
+ if (mLocationAPI) {
+ mLocationAPI->destroy();
+ mLocationAPI = nullptr;
+ }
+
+ for (int i = 0; i < REQUEST_MAX; i++) {
+ mRequestQueues[i].reset((uint32_t)0);
+ }
+
+ pthread_mutex_unlock(&mMutex);
+
+ pthread_mutex_destroy(&mMutex);
+}
+
+uint32_t LocationAPIClientBase::locAPIStartTracking(TrackingOptions& options)
+{
+ uint32_t retVal = LOCATION_ERROR_GENERAL_FAILURE;
+ pthread_mutex_lock(&mMutex);
+ if (mLocationAPI) {
+ if (mTracking) {
+ LOC_LOGW("%s:%d] Existing tracking session present", __FUNCTION__, __LINE__);
+ } else {
+ 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]
+ mRequestQueues[REQUEST_TRACKING].reset(session);
+ mRequestQueues[REQUEST_TRACKING].push(new StartTrackingRequest(*this));
+ mTracking = true;
+ }
+
+ retVal = LOCATION_ERROR_SUCCESS;
+ }
+ pthread_mutex_unlock(&mMutex);
+
+ return retVal;
+}
+
+void LocationAPIClientBase::locAPIStopTracking()
+{
+ pthread_mutex_lock(&mMutex);
+ if (mLocationAPI) {
+ uint32_t session = 0;
+ session = mRequestQueues[REQUEST_TRACKING].getSession();
+ if (session > 0) {
+ mRequestQueues[REQUEST_TRACKING].push(new StopTrackingRequest(*this));
+ mLocationAPI->stopTracking(session);
+ mTracking = false;
+ } else {
+ LOC_LOGD("%s:%d] invalid session: %d.", __FUNCTION__, __LINE__, session);
+ }
+ }
+ pthread_mutex_unlock(&mMutex);
+}
+
+void LocationAPIClientBase::locAPIUpdateTrackingOptions(TrackingOptions& options)
+{
+ pthread_mutex_lock(&mMutex);
+ if (mLocationAPI) {
+ uint32_t session = 0;
+ session = mRequestQueues[REQUEST_TRACKING].getSession();
+ if (session > 0) {
+ mRequestQueues[REQUEST_TRACKING].push(new UpdateTrackingOptionsRequest(*this));
+ mLocationAPI->updateTrackingOptions(session, options);
+ } else {
+ LOC_LOGE("%s:%d] invalid session: %d.", __FUNCTION__, __LINE__, session);
+ }
+ }
+ 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(LOC_PATH_FLP_CONF, 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, TrackingOptions&& options)
+{
+ uint32_t retVal = LOCATION_ERROR_GENERAL_FAILURE;
+ pthread_mutex_lock(&mMutex);
+ if (mLocationAPI) {
+
+ if (mSessionBiDict.hasId(id)) {
+ 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) {
+ trackingSession = mLocationAPI->startTracking(options);
+ LOC_LOGI("%s:%d] start new session: %d", __FUNCTION__, __LINE__, trackingSession);
+ mRequestQueues[REQUEST_SESSION].push(new StartTrackingRequest(*this));
+ } else {
+ // Fill in the batch mode
+ BatchingOptions batchOptions = {};
+ batchOptions.size = sizeof(BatchingOptions);
+ switch (sessionMode) {
+ case SESSION_MODE_ON_FULL:
+ batchOptions.batchingMode = BATCHING_MODE_ROUTINE;
+ break;
+ case SESSION_MODE_ON_TRIP_COMPLETED:
+ batchOptions.batchingMode = BATCHING_MODE_TRIP;
+ break;
+ default:
+ batchOptions.batchingMode = BATCHING_MODE_NO_AUTO_REPORT;
+ break;
+ }
+
+ // Populate location option values
+ batchOptions.minDistance = options.minDistance;
+ batchOptions.minInterval = options.minInterval;
+ batchOptions.mode = options.mode;
+
+ batchingSession = mLocationAPI->startBatching(batchOptions);
+ LOC_LOGI("%s:%d] start new session: %d", __FUNCTION__, __LINE__, batchingSession);
+ mRequestQueues[REQUEST_SESSION].setSession(batchingSession);
+ mRequestQueues[REQUEST_SESSION].push(new StartBatchingRequest(*this));
+ }
+
+ uint32_t session = ((sessionMode != SESSION_MODE_ON_FIX) ?
+ batchingSession : trackingSession);
+
+ SessionEntity entity;
+ entity.id = id;
+ entity.trackingSession = trackingSession;
+ entity.batchingSession = batchingSession;
+ entity.sessionMode = sessionMode;
+ mSessionBiDict.set(id, session, 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;
+ pthread_mutex_lock(&mMutex);
+ if (mLocationAPI) {
+
+ if (mSessionBiDict.hasId(id)) {
+ SessionEntity entity = mSessionBiDict.getExtById(id);
+
+ uint32_t trackingSession = entity.trackingSession;
+ uint32_t batchingSession = entity.batchingSession;
+ uint32_t sMode = entity.sessionMode;
+
+ if (sMode == SESSION_MODE_ON_FIX) {
+ mRequestQueues[REQUEST_SESSION].push(new StopTrackingRequest(*this));
+ mLocationAPI->stopTracking(trackingSession);
+ } else {
+ mRequestQueues[REQUEST_SESSION].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, TrackingOptions&& options)
+{
+ uint32_t retVal = LOCATION_ERROR_GENERAL_FAILURE;
+ pthread_mutex_lock(&mMutex);
+ if (mLocationAPI) {
+
+ if (mSessionBiDict.hasId(id)) {
+ SessionEntity entity = mSessionBiDict.getExtById(id);
+
+ uint32_t trackingSession = entity.trackingSession;
+ uint32_t batchingSession = entity.batchingSession;
+ uint32_t sMode = entity.sessionMode;
+
+ if (sessionMode == SESSION_MODE_ON_FIX) {
+ // we only add an UpdateTrackingOptionsRequest to mRequestQueues[REQUEST_SESSION],
+ // even if this update request will stop batching and then start tracking.
+ mRequestQueues[REQUEST_SESSION].push(new UpdateTrackingOptionsRequest(*this));
+ if (sMode == SESSION_MODE_ON_FIX) {
+ mLocationAPI->updateTrackingOptions(trackingSession, options);
+ } else {
+ // stop batching
+ // batchingSession will be removed from mSessionBiDict soon,
+ // so we don't need to add a new request to mRequestQueues[REQUEST_SESSION].
+ mLocationAPI->stopBatching(batchingSession);
+ batchingSession = 0;
+ mRequestQueues[REQUEST_SESSION].setSession(batchingSession);
+
+ // start tracking
+ trackingSession = mLocationAPI->startTracking(options);
+ LOC_LOGI("%s:%d] start new session: %d",
+ __FUNCTION__, __LINE__, trackingSession);
+ }
+ } else {
+ // we only add an UpdateBatchingOptionsRequest to mRequestQueues[REQUEST_SESSION],
+ // even if this update request will stop tracking and then start batching.
+ mRequestQueues[REQUEST_SESSION].push(new UpdateBatchingOptionsRequest(*this));
+ BatchingOptions batchOptions = {};
+ batchOptions.size = sizeof(BatchingOptions);
+ switch (sessionMode) {
+ case SESSION_MODE_ON_FULL:
+ batchOptions.batchingMode = BATCHING_MODE_ROUTINE;
+ break;
+ case SESSION_MODE_ON_TRIP_COMPLETED:
+ batchOptions.batchingMode = BATCHING_MODE_TRIP;
+ break;
+ default:
+ batchOptions.batchingMode = BATCHING_MODE_NO_AUTO_REPORT;
+ break;
+ }
+
+ if (sMode == SESSION_MODE_ON_FIX) {
+ // stop tracking
+ // trackingSession will be removed from mSessionBiDict soon,
+ // so we don't need to add a new request to mRequestQueues[REQUEST_SESSION].
+ mLocationAPI->stopTracking(trackingSession);
+ trackingSession = 0;
+
+ // Populate location option values
+ batchOptions.minDistance = options.minDistance;
+ batchOptions.minInterval = options.minInterval;
+ batchOptions.mode = options.mode;
+
+ // start batching
+ batchingSession = mLocationAPI->startBatching(batchOptions);
+ LOC_LOGI("%s:%d] start new session: %d",
+ __FUNCTION__, __LINE__, batchingSession);
+ mRequestQueues[REQUEST_SESSION].setSession(batchingSession);
+ } else {
+ mLocationAPI->updateBatchingOptions(batchingSession, batchOptions);
+ }
+
+ }
+
+ uint32_t session = ((sessionMode != SESSION_MODE_ON_FIX) ?
+ batchingSession : trackingSession);
+
+ entity.trackingSession = trackingSession;
+ entity.batchingSession = batchingSession;
+ entity.sessionMode = sessionMode;
+ // remove the old values from mSessionBiDict before we add a new one.
+ mSessionBiDict.rmById(id);
+ mSessionBiDict.set(id, session, entity);
+
+ 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::locAPIGetBatchedLocations(uint32_t id, size_t count)
+{
+ uint32_t retVal = LOCATION_ERROR_GENERAL_FAILURE;
+ pthread_mutex_lock(&mMutex);
+ if (mLocationAPI) {
+ if (mSessionBiDict.hasId(id)) {
+ SessionEntity entity = mSessionBiDict.getExtById(id);
+ if (entity.sessionMode != SESSION_MODE_ON_FIX) {
+ uint32_t batchingSession = entity.batchingSession;
+ mRequestQueues[REQUEST_SESSION].push(new GetBatchedLocationsRequest(*this));
+ mLocationAPI->getBatchedLocations(batchingSession, count);
+ retVal = LOCATION_ERROR_SUCCESS;
+ } else {
+ LOC_LOGE("%s:%d] Unsupported for session id: %d, mode is SESSION_MODE_ON_FIX",
+ __FUNCTION__, __LINE__, id);
+ retVal = LOCATION_ERROR_NOT_SUPPORTED;
+ }
+ } else {
+ retVal = LOCATION_ERROR_ID_UNKNOWN;
+ LOC_LOGE("%s:%d] invalid session: %d.", __FUNCTION__, __LINE__, id);
+ }
+ }
+ pthread_mutex_unlock(&mMutex);
+
+ return retVal;
+}
+
+uint32_t LocationAPIClientBase::locAPIAddGeofences(
+ size_t count, uint32_t* ids, GeofenceOption* options, GeofenceInfo* data)
+{
+ uint32_t retVal = LOCATION_ERROR_GENERAL_FAILURE;
+ pthread_mutex_lock(&mMutex);
+ if (mLocationAPI) {
+ if (mRequestQueues[REQUEST_GEOFENCE].getSession() != GEOFENCE_SESSION_ID) {
+ mRequestQueues[REQUEST_GEOFENCE].reset(GEOFENCE_SESSION_ID);
+ }
+ uint32_t* sessions = mLocationAPI->addGeofences(count, options, data);
+ if (sessions) {
+ LOC_LOGI("%s:%d] start new sessions: %p", __FUNCTION__, __LINE__, sessions);
+ mRequestQueues[REQUEST_GEOFENCE].push(new AddGeofencesRequest(*this));
+
+ for (size_t i = 0; i < count; i++) {
+ mGeofenceBiDict.set(ids[i], sessions[i], options[i].breachTypeMask);
+ }
+ retVal = LOCATION_ERROR_SUCCESS;
+ }
+ }
+ pthread_mutex_unlock(&mMutex);
+
+ return retVal;
+}
+
+void LocationAPIClientBase::locAPIRemoveGeofences(size_t count, uint32_t* ids)
+{
+ pthread_mutex_lock(&mMutex);
+ if (mLocationAPI) {
+ uint32_t* sessions = (uint32_t*)malloc(sizeof(uint32_t) * count);
+ if (sessions == NULL) {
+ LOC_LOGE("%s:%d] Failed to allocate %zu bytes !",
+ __FUNCTION__, __LINE__, sizeof(uint32_t) * count);
+ pthread_mutex_unlock(&mMutex);
+ return;
+ }
+
+ if (mRequestQueues[REQUEST_GEOFENCE].getSession() == GEOFENCE_SESSION_ID) {
+ BiDict<GeofenceBreachTypeMask>* removedGeofenceBiDict =
+ new BiDict<GeofenceBreachTypeMask>();
+ size_t j = 0;
+ for (size_t i = 0; i < count; i++) {
+ sessions[j] = mGeofenceBiDict.getSession(ids[i]);
+ if (sessions[j] > 0) {
+ GeofenceBreachTypeMask type = mGeofenceBiDict.getExtBySession(sessions[j]);
+ mGeofenceBiDict.rmBySession(sessions[j]);
+ removedGeofenceBiDict->set(ids[i], sessions[j], type);
+ j++;
+ }
+ }
+ if (j > 0) {
+ mRequestQueues[REQUEST_GEOFENCE].push(new RemoveGeofencesRequest(*this,
+ removedGeofenceBiDict));
+ mLocationAPI->removeGeofences(j, sessions);
+ } else {
+ delete(removedGeofenceBiDict);
+ }
+ } else {
+ LOC_LOGE("%s:%d] invalid session: %d.", __FUNCTION__, __LINE__,
+ mRequestQueues[REQUEST_GEOFENCE].getSession());
+ }
+
+ free(sessions);
+ }
+ pthread_mutex_unlock(&mMutex);
+}
+
+void LocationAPIClientBase::locAPIModifyGeofences(
+ size_t count, uint32_t* ids, GeofenceOption* options)
+{
+ pthread_mutex_lock(&mMutex);
+ if (mLocationAPI) {
+ uint32_t* sessions = (uint32_t*)malloc(sizeof(uint32_t) * count);
+ if (sessions == NULL) {
+ LOC_LOGE("%s:%d] Failed to allocate %zu bytes !",
+ __FUNCTION__, __LINE__, sizeof(uint32_t) * count);
+ pthread_mutex_unlock(&mMutex);
+ return;
+ }
+
+ if (mRequestQueues[REQUEST_GEOFENCE].getSession() == GEOFENCE_SESSION_ID) {
+ size_t j = 0;
+ for (size_t i = 0; i < count; i++) {
+ sessions[j] = mGeofenceBiDict.getSession(ids[i]);
+ if (sessions[j] > 0) {
+ mGeofenceBiDict.set(ids[i], sessions[j], options[i].breachTypeMask);
+ j++;
+ }
+ }
+ if (j > 0) {
+ mRequestQueues[REQUEST_GEOFENCE].push(new ModifyGeofencesRequest(*this));
+ mLocationAPI->modifyGeofences(j, sessions, options);
+ }
+ } else {
+ LOC_LOGE("%s:%d] invalid session: %d.", __FUNCTION__, __LINE__,
+ mRequestQueues[REQUEST_GEOFENCE].getSession());
+ }
+
+ free(sessions);
+ }
+ pthread_mutex_unlock(&mMutex);
+}
+
+void LocationAPIClientBase::locAPIPauseGeofences(size_t count, uint32_t* ids)
+{
+ pthread_mutex_lock(&mMutex);
+ if (mLocationAPI) {
+ uint32_t* sessions = (uint32_t*)malloc(sizeof(uint32_t) * count);
+ if (sessions == NULL) {
+ LOC_LOGE("%s:%d] Failed to allocate %zu bytes !",
+ __FUNCTION__, __LINE__, sizeof(uint32_t) * count);
+ pthread_mutex_unlock(&mMutex);
+ return;
+ }
+
+ if (mRequestQueues[REQUEST_GEOFENCE].getSession() == GEOFENCE_SESSION_ID) {
+ size_t j = 0;
+ for (size_t i = 0; i < count; i++) {
+ sessions[j] = mGeofenceBiDict.getSession(ids[i]);
+ if (sessions[j] > 0) {
+ j++;
+ }
+ }
+ if (j > 0) {
+ mRequestQueues[REQUEST_GEOFENCE].push(new PauseGeofencesRequest(*this));
+ mLocationAPI->pauseGeofences(j, sessions);
+ }
+ } else {
+ LOC_LOGE("%s:%d] invalid session: %d.", __FUNCTION__, __LINE__,
+ mRequestQueues[REQUEST_GEOFENCE].getSession());
+ }
+
+ free(sessions);
+ }
+ pthread_mutex_unlock(&mMutex);
+}
+
+void LocationAPIClientBase::locAPIResumeGeofences(
+ size_t count, uint32_t* ids, GeofenceBreachTypeMask* mask)
+{
+ pthread_mutex_lock(&mMutex);
+ if (mLocationAPI) {
+ uint32_t* sessions = (uint32_t*)malloc(sizeof(uint32_t) * count);
+ if (sessions == NULL) {
+ LOC_LOGE("%s:%d] Failed to allocate %zu bytes !",
+ __FUNCTION__, __LINE__, sizeof(uint32_t) * count);
+ pthread_mutex_unlock(&mMutex);
+ return;
+ }
+
+ if (mRequestQueues[REQUEST_GEOFENCE].getSession() == GEOFENCE_SESSION_ID) {
+ size_t j = 0;
+ for (size_t i = 0; i < count; i++) {
+ sessions[j] = mGeofenceBiDict.getSession(ids[i]);
+ if (sessions[j] > 0) {
+ if (mask) {
+ mGeofenceBiDict.set(ids[i], sessions[j], mask[i]);
+ }
+ j++;
+ }
+ }
+ if (j > 0) {
+ mRequestQueues[REQUEST_GEOFENCE].push(new ResumeGeofencesRequest(*this));
+ mLocationAPI->resumeGeofences(j, sessions);
+ }
+ } else {
+ LOC_LOGE("%s:%d] invalid session: %d.", __FUNCTION__, __LINE__,
+ mRequestQueues[REQUEST_GEOFENCE].getSession());
+ }
+
+ free(sessions);
+ }
+ pthread_mutex_unlock(&mMutex);
+}
+
+void LocationAPIClientBase::locAPIRemoveAllGeofences()
+{
+ std::vector<uint32_t> sessionsVec = mGeofenceBiDict.getAllSessions();
+ locAPIRemoveGeofences(sessionsVec.size(), &sessionsVec[0]);
+}
+
+void LocationAPIClientBase::locAPIGnssNiResponse(uint32_t id, GnssNiResponse response)
+{
+ pthread_mutex_lock(&mMutex);
+ if (mLocationAPI) {
+ uint32_t session = id;
+ mLocationAPI->gnssNiResponse(id, response);
+ LOC_LOGI("%s:%d] start new session: %d", __FUNCTION__, __LINE__, session);
+ mRequestQueues[REQUEST_NIRESPONSE].reset(session);
+ mRequestQueues[REQUEST_NIRESPONSE].push(new GnssNiResponseRequest(*this));
+ }
+ pthread_mutex_unlock(&mMutex);
+}
+
+void LocationAPIClientBase::beforeGeofenceBreachCb(
+ GeofenceBreachNotification geofenceBreachNotification)
+{
+ uint32_t* ids = (uint32_t*)malloc(sizeof(uint32_t) * geofenceBreachNotification.count);
+ uint32_t* backup = geofenceBreachNotification.ids;
+ size_t n = geofenceBreachNotification.count;
+ geofenceBreachCallback genfenceCallback = nullptr;
+
+ if (ids == NULL) {
+ LOC_LOGE("%s:%d] Failed to alloc %zu bytes",
+ __FUNCTION__, __LINE__,
+ sizeof(uint32_t) * geofenceBreachNotification.count);
+ return;
+ }
+
+ pthread_mutex_lock(&mMutex);
+ if (mGeofenceBreachCallback != nullptr) {
+ size_t count = 0;
+ for (size_t i = 0; i < n; i++) {
+ uint32_t id = mGeofenceBiDict.getId(geofenceBreachNotification.ids[i]);
+ GeofenceBreachTypeMask type =
+ mGeofenceBiDict.getExtBySession(geofenceBreachNotification.ids[i]);
+ // if type == 0, we will not head into the fllowing block anyway.
+ // so we don't need to check id and type
+ 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;
+
+ genfenceCallback = mGeofenceBreachCallback;
+ }
+ pthread_mutex_unlock(&mMutex);
+
+ if (genfenceCallback != nullptr) {
+ genfenceCallback(geofenceBreachNotification);
+ }
+
+ // restore ids
+ geofenceBreachNotification.ids = backup;
+ geofenceBreachNotification.count = n;
+ free(ids);
+}
+
+void LocationAPIClientBase::beforeBatchingStatusCb(BatchingStatusInfo batchStatus,
+ std::list<uint32_t> & tripCompletedList) {
+
+ // map the trip ids to the client ids
+ std::list<uint32_t> tripCompletedClientIdList;
+ tripCompletedClientIdList.clear();
+
+ if (batchStatus.batchingStatus == BATCHING_STATUS_TRIP_COMPLETED) {
+ for (auto itt = tripCompletedList.begin(); itt != tripCompletedList.end(); itt++) {
+ if (mSessionBiDict.hasSession(*itt)) {
+ SessionEntity sessEntity = mSessionBiDict.getExtBySession(*itt);
+
+ if (sessEntity.sessionMode == SESSION_MODE_ON_TRIP_COMPLETED) {
+ tripCompletedClientIdList.push_back(sessEntity.id);
+ mSessionBiDict.rmBySession(*itt);
+ }
+ }
+ }
+ }
+
+ mBatchingStatusCallback(batchStatus, tripCompletedClientIdList);
+}
+
+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] SUCCESS: %d id: %d", __FUNCTION__, __LINE__, error, id);
+ }
+ LocationAPIRequest* request = getRequestBySession(id);
+ if (request) {
+ request->onResponse(error, id);
+ 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] SUCCESS: %d id: %d", __FUNCTION__, __LINE__, errors[i], ids[i]);
+ }
+ }
+ LocationAPIRequest* request = nullptr;
+ pthread_mutex_lock(&mMutex);
+ if (mRequestQueues[REQUEST_GEOFENCE].getSession() == GEOFENCE_SESSION_ID) {
+ request = mRequestQueues[REQUEST_GEOFENCE].pop();
+ }
+ pthread_mutex_unlock(&mMutex);
+ if (request) {
+ request->onCollectiveResponse(count, errors, ids);
+ delete request;
+ }
+}
+
+void LocationAPIClientBase::removeSession(uint32_t session) {
+ if (mSessionBiDict.hasSession(session)) {
+ mSessionBiDict.rmBySession(session);
+ }
+}
+
+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 &&
+ i != REQUEST_SESSION &&
+ mRequestQueues[i].getSession() == session) {
+ request = mRequestQueues[i].pop();
+ break;
+ }
+ }
+ if (request == nullptr) {
+ // Can't find a request with correct session,
+ // try to find it from mSessionBiDict
+ if (mSessionBiDict.hasSession(session)) {
+ request = mRequestQueues[REQUEST_SESSION].pop();
+ }
+ }
+ pthread_mutex_unlock(&mMutex);
+ return request;
+}
diff --git a/location/LocationAPIClientBase.h b/location/LocationAPIClientBase.h
new file mode 100644
index 0000000..098000c
--- /dev/null
+++ b/location/LocationAPIClientBase.h
@@ -0,0 +1,587 @@
+/* Copyright (c) 2017-2019 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"
+#include <loc_pla.h>
+#include <log_util.h>
+
+enum SESSION_MODE {
+ SESSION_MODE_NONE = 0,
+ SESSION_MODE_ON_FULL,
+ SESSION_MODE_ON_FIX,
+ SESSION_MODE_ON_TRIP_COMPLETED
+};
+
+enum REQUEST_TYPE {
+ REQUEST_TRACKING = 0,
+ REQUEST_SESSION,
+ REQUEST_GEOFENCE,
+ REQUEST_NIRESPONSE,
+ REQUEST_MAX,
+};
+
+enum CTRL_REQUEST_TYPE {
+ CTRL_REQUEST_DELETEAIDINGDATA = 0,
+ CTRL_REQUEST_CONTROL,
+ CTRL_REQUEST_CONFIG_UPDATE,
+ CTRL_REQUEST_CONFIG_GET,
+ CTRL_REQUEST_MAX,
+};
+
+class LocationAPIClientBase;
+
+class LocationAPIRequest {
+public:
+ LocationAPIRequest() {}
+ virtual ~LocationAPIRequest() {}
+ virtual void onResponse(LocationError /*error*/, uint32_t /*id*/) {}
+ virtual void onCollectiveResponse(
+ size_t /*count*/, LocationError* /*errors*/, uint32_t* /*ids*/) {}
+};
+
+class RequestQueue {
+public:
+ RequestQueue(): mSession(0), mSessionArrayPtr(nullptr) {
+ }
+ virtual ~RequestQueue() {
+ reset((uint32_t)0);
+ }
+ void inline setSession(uint32_t session) { mSession = session; }
+ void inline setSessionArrayPtr(uint32_t* ptr) { mSessionArrayPtr = ptr; }
+ void reset(uint32_t session) {
+ LocationAPIRequest* request = nullptr;
+ while (!mQueue.empty()) {
+ request = mQueue.front();
+ mQueue.pop();
+ delete request;
+ }
+ mSession = session;
+ }
+ void reset(uint32_t* sessionArrayPtr) {
+ reset((uint32_t)0);
+ mSessionArrayPtr = sessionArrayPtr;
+ }
+ 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; }
+ uint32_t* getSessionArrayPtr() { return mSessionArrayPtr; }
+private:
+ uint32_t mSession;
+ uint32_t* mSessionArrayPtr;
+ std::queue<LocationAPIRequest*> mQueue;
+};
+
+class LocationAPIControlClient {
+public:
+ LocationAPIControlClient();
+ virtual ~LocationAPIControlClient();
+ LocationAPIControlClient(const LocationAPIControlClient&) = delete;
+ LocationAPIControlClient& operator=(const LocationAPIControlClient&) = delete;
+
+ LocationAPIRequest* getRequestBySession(uint32_t session);
+ LocationAPIRequest* getRequestBySessionArrayPtr(uint32_t* sessionArrayPtr);
+
+ // LocationControlAPI
+ uint32_t locAPIGnssDeleteAidingData(GnssAidingData& data);
+ uint32_t locAPIEnable(LocationTechnologyType techType);
+ void locAPIDisable();
+ uint32_t locAPIGnssUpdateConfig(GnssConfig config);
+ uint32_t locAPIGnssGetConfig(GnssConfigFlagsMask config);
+ inline LocationControlAPI* getControlAPI() { return mLocationControlAPI; }
+
+ // callbacks
+ void onCtrlResponseCb(LocationError error, uint32_t id);
+ void onCtrlCollectiveResponseCb(size_t count, LocationError* errors, uint32_t* ids);
+
+ 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*/) {}
+ inline virtual void onGnssGetConfigCb(
+ size_t /*count*/, LocationError* /*errors*/, uint32_t* /*ids*/) {}
+
+ class GnssDeleteAidingDataRequest : public LocationAPIRequest {
+ public:
+ GnssDeleteAidingDataRequest(LocationAPIControlClient& API) : mAPI(API) {}
+ inline void onResponse(LocationError error, uint32_t /*id*/) {
+ mAPI.onGnssDeleteAidingDataCb(error);
+ }
+ LocationAPIControlClient& mAPI;
+ };
+
+ class EnableRequest : public LocationAPIRequest {
+ public:
+ EnableRequest(LocationAPIControlClient& API) : mAPI(API) {}
+ inline void onResponse(LocationError error, uint32_t /*id*/) {
+ mAPI.onEnableCb(error);
+ }
+ LocationAPIControlClient& mAPI;
+ };
+
+ class DisableRequest : public LocationAPIRequest {
+ public:
+ DisableRequest(LocationAPIControlClient& API) : mAPI(API) {}
+ inline void onResponse(LocationError error, uint32_t /*id*/) {
+ mAPI.onDisableCb(error);
+ }
+ LocationAPIControlClient& mAPI;
+ };
+
+ class GnssUpdateConfigRequest : public LocationAPIRequest {
+ public:
+ GnssUpdateConfigRequest(LocationAPIControlClient& API) : mAPI(API) {}
+ inline void onCollectiveResponse(size_t count, LocationError* errors, uint32_t* ids) {
+ mAPI.onGnssUpdateConfigCb(count, errors, ids);
+ }
+ LocationAPIControlClient& mAPI;
+ };
+
+ class GnssGetConfigRequest : public LocationAPIRequest {
+ public:
+ GnssGetConfigRequest(LocationAPIControlClient& API) : mAPI(API) {}
+ inline void onCollectiveResponse(size_t count, LocationError* errors, uint32_t* ids) {
+ mAPI.onGnssGetConfigCb(count, errors, ids);
+ }
+ LocationAPIControlClient& mAPI;
+ };
+
+private:
+ pthread_mutex_t mMutex;
+ LocationControlAPI* mLocationControlAPI;
+ RequestQueue mRequestQueues[CTRL_REQUEST_MAX];
+ bool mEnabled;
+ GnssConfig mConfig;
+};
+
+class LocationAPIClientBase {
+public:
+ LocationAPIClientBase();
+ virtual ~LocationAPIClientBase();
+ LocationAPIClientBase(const LocationAPIClientBase&) = delete;
+ LocationAPIClientBase& operator=(const LocationAPIClientBase&) = delete;
+
+ void locAPISetCallbacks(LocationCallbacks& locationCallbacks);
+ void removeSession(uint32_t session);
+ LocationAPIRequest* getRequestBySession(uint32_t session);
+
+ // LocationAPI
+ uint32_t locAPIStartTracking(TrackingOptions& trackingOptions);
+ void locAPIStopTracking();
+ void locAPIUpdateTrackingOptions(TrackingOptions& trackingOptions);
+
+ int32_t locAPIGetBatchSize();
+ uint32_t locAPIStartSession(
+ uint32_t id, uint32_t sessionMode, TrackingOptions&& trackingOptions);
+ uint32_t locAPIStopSession(uint32_t id);
+ uint32_t locAPIUpdateSessionOptions(
+ uint32_t id, uint32_t sessionMode, TrackingOptions&& trackingOptions);
+ uint32_t locAPIGetBatchedLocations(uint32_t id, 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);
+
+ // callbacks
+ void onResponseCb(LocationError error, uint32_t id);
+ void onCollectiveResponseCb(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 onGnssDataCb(GnssDataNotification /*gnssDataNotification*/) {}
+ 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*/,
+ BatchingOptions /*batchingOptions*/) {}
+ inline virtual void onBatchingStatusCb(BatchingStatusInfo /*batchingStatus*/,
+ std::list<uint32_t> &/*listOfCompletedTrips*/) {}
+ void beforeBatchingStatusCb(BatchingStatusInfo batchStatus,
+ std::list<uint32_t> & tripCompletedList);
+ 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 onLocationSystemInfoCb(LocationSystemInfo /*locationSystemInfo*/) {}
+
+private:
+ // private inner classes
+ typedef struct {
+ uint32_t id;
+ uint32_t trackingSession;
+ uint32_t batchingSession;
+ uint32_t sessionMode;
+ } SessionEntity;
+
+ template<typename T>
+ class BiDict {
+ public:
+ BiDict() {
+ pthread_mutex_init(&mBiDictMutex, nullptr);
+ }
+ virtual ~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;
+ }
+ bool hasSession(uint32_t session) {
+ pthread_mutex_lock(&mBiDictMutex);
+ bool ret = (mBackwardMap.find(session) != mBackwardMap.end());
+ pthread_mutex_unlock(&mBiDictMutex);
+ return ret;
+ }
+ void set(uint32_t id, uint32_t session, T& ext) {
+ pthread_mutex_lock(&mBiDictMutex);
+ mForwardMap[id] = session;
+ mBackwardMap[session] = id;
+ mExtMap[session] = ext;
+ pthread_mutex_unlock(&mBiDictMutex);
+ }
+ void clear() {
+ pthread_mutex_lock(&mBiDictMutex);
+ mForwardMap.clear();
+ mBackwardMap.clear();
+ mExtMap.clear();
+ pthread_mutex_unlock(&mBiDictMutex);
+ }
+ void rmById(uint32_t id) {
+ pthread_mutex_lock(&mBiDictMutex);
+ mBackwardMap.erase(mForwardMap[id]);
+ mExtMap.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);
+ mExtMap.erase(session);
+ pthread_mutex_unlock(&mBiDictMutex);
+ }
+ uint32_t getId(uint32_t session) {
+ pthread_mutex_lock(&mBiDictMutex);
+ uint32_t ret = 0;
+ auto it = mBackwardMap.find(session);
+ if (it != mBackwardMap.end()) {
+ ret = it->second;
+ }
+ pthread_mutex_unlock(&mBiDictMutex);
+ return ret;
+ }
+ uint32_t getSession(uint32_t id) {
+ pthread_mutex_lock(&mBiDictMutex);
+ uint32_t ret = 0;
+ auto it = mForwardMap.find(id);
+ if (it != mForwardMap.end()) {
+ ret = it->second;
+ }
+ pthread_mutex_unlock(&mBiDictMutex);
+ return ret;
+ }
+ T getExtById(uint32_t id) {
+ pthread_mutex_lock(&mBiDictMutex);
+ T ret;
+ memset(&ret, 0, sizeof(T));
+ uint32_t session = mForwardMap[id];
+ if (session > 0) {
+ auto it = mExtMap.find(session);
+ if (it != mExtMap.end()) {
+ ret = it->second;
+ }
+ }
+ pthread_mutex_unlock(&mBiDictMutex);
+ return ret;
+ }
+ T getExtBySession(uint32_t session) {
+ pthread_mutex_lock(&mBiDictMutex);
+ T ret;
+ memset(&ret, 0, sizeof(T));
+ auto it = mExtMap.find(session);
+ if (it != mExtMap.end()) {
+ ret = it->second;
+ }
+ 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;
+ // mExtMap mapping session->ext
+ std::map<uint32_t, T> mExtMap;
+ };
+
+ class StartTrackingRequest : public LocationAPIRequest {
+ public:
+ StartTrackingRequest(LocationAPIClientBase& API) : mAPI(API) {}
+ inline void onResponse(LocationError error, uint32_t id) {
+ if (error != LOCATION_ERROR_SUCCESS) {
+ mAPI.removeSession(id);
+ }
+ mAPI.onStartTrackingCb(error);
+ }
+ LocationAPIClientBase& mAPI;
+ };
+
+ class StopTrackingRequest : public LocationAPIRequest {
+ public:
+ StopTrackingRequest(LocationAPIClientBase& API) : mAPI(API) {}
+ inline void onResponse(LocationError error, uint32_t id) {
+ mAPI.onStopTrackingCb(error);
+ if (error == LOCATION_ERROR_SUCCESS) {
+ mAPI.removeSession(id);
+ }
+ }
+ LocationAPIClientBase& mAPI;
+ };
+
+ class UpdateTrackingOptionsRequest : public LocationAPIRequest {
+ public:
+ UpdateTrackingOptionsRequest(LocationAPIClientBase& API) : mAPI(API) {}
+ inline void onResponse(LocationError error, uint32_t /*id*/) {
+ mAPI.onUpdateTrackingOptionsCb(error);
+ }
+ LocationAPIClientBase& mAPI;
+ };
+
+ class StartBatchingRequest : public LocationAPIRequest {
+ public:
+ StartBatchingRequest(LocationAPIClientBase& API) : mAPI(API) {}
+ inline void onResponse(LocationError error, uint32_t id) {
+ if (error != LOCATION_ERROR_SUCCESS) {
+ mAPI.removeSession(id);
+ }
+ mAPI.onStartBatchingCb(error);
+ }
+ LocationAPIClientBase& mAPI;
+ };
+
+ class StopBatchingRequest : public LocationAPIRequest {
+ public:
+ StopBatchingRequest(LocationAPIClientBase& API) : mAPI(API) {}
+ inline void onResponse(LocationError error, uint32_t id) {
+ mAPI.onStopBatchingCb(error);
+ if (error == LOCATION_ERROR_SUCCESS) {
+ mAPI.removeSession(id);
+ }
+ }
+ LocationAPIClientBase& mAPI;
+ };
+
+ class UpdateBatchingOptionsRequest : public LocationAPIRequest {
+ public:
+ UpdateBatchingOptionsRequest(LocationAPIClientBase& API) : mAPI(API) {}
+ inline void onResponse(LocationError error, uint32_t /*id*/) {
+ mAPI.onUpdateBatchingOptionsCb(error);
+ }
+ LocationAPIClientBase& mAPI;
+ };
+
+ class GetBatchedLocationsRequest : public LocationAPIRequest {
+ public:
+ GetBatchedLocationsRequest(LocationAPIClientBase& API) : mAPI(API) {}
+ inline void onResponse(LocationError error, uint32_t /*id*/) {
+ mAPI.onGetBatchedLocationsCb(error);
+ }
+ LocationAPIClientBase& mAPI;
+ };
+
+ class AddGeofencesRequest : public LocationAPIRequest {
+ public:
+ AddGeofencesRequest(LocationAPIClientBase& API) : mAPI(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]);
+ }
+ LOC_LOGD("%s:]Returned geofence-id: %d in add geofence", __FUNCTION__, *ids);
+ mAPI.onAddGeofencesCb(count, errors, ids);
+ free(ids);
+ }
+ LocationAPIClientBase& mAPI;
+ };
+
+ class RemoveGeofencesRequest : public LocationAPIRequest {
+ public:
+ RemoveGeofencesRequest(LocationAPIClientBase& API,
+ BiDict<GeofenceBreachTypeMask>* removedGeofenceBiDict) :
+ mAPI(API), mRemovedGeofenceBiDict(removedGeofenceBiDict) {}
+ inline void onCollectiveResponse(size_t count, LocationError* errors, uint32_t* sessions) {
+ if (nullptr != mRemovedGeofenceBiDict) {
+ uint32_t *ids = (uint32_t*)malloc(sizeof(uint32_t) * count);
+ for (size_t i = 0; i < count; i++) {
+ ids[i] = mRemovedGeofenceBiDict->getId(sessions[i]);
+ }
+ LOC_LOGD("%s:]Returned geofence-id: %d in remove geofence", __FUNCTION__, *ids);
+ mAPI.onRemoveGeofencesCb(count, errors, ids);
+ free(ids);
+ delete(mRemovedGeofenceBiDict);
+ } else {
+ LOC_LOGE("%s:%d] Unable to access removed geofences data.", __FUNCTION__, __LINE__);
+ }
+ }
+ LocationAPIClientBase& mAPI;
+ BiDict<GeofenceBreachTypeMask>* mRemovedGeofenceBiDict;
+ };
+
+ class ModifyGeofencesRequest : public LocationAPIRequest {
+ public:
+ ModifyGeofencesRequest(LocationAPIClientBase& API) : mAPI(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);
+ }
+ LocationAPIClientBase& mAPI;
+ };
+
+ class PauseGeofencesRequest : public LocationAPIRequest {
+ public:
+ PauseGeofencesRequest(LocationAPIClientBase& API) : mAPI(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);
+ }
+ LocationAPIClientBase& mAPI;
+ };
+
+ class ResumeGeofencesRequest : public LocationAPIRequest {
+ public:
+ ResumeGeofencesRequest(LocationAPIClientBase& API) : mAPI(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);
+ }
+ LocationAPIClientBase& mAPI;
+ };
+
+ class GnssNiResponseRequest : public LocationAPIRequest {
+ public:
+ GnssNiResponseRequest(LocationAPIClientBase& API) : mAPI(API) {}
+ inline void onResponse(LocationError error, uint32_t /*id*/) {
+ mAPI.onGnssNiResponseCb(error);
+ }
+ LocationAPIClientBase& mAPI;
+ };
+
+private:
+ pthread_mutex_t mMutex;
+
+ geofenceBreachCallback mGeofenceBreachCallback;
+ batchingStatusCallback mBatchingStatusCallback;
+
+ LocationAPI* mLocationAPI;
+
+ RequestQueue mRequestQueues[REQUEST_MAX];
+ BiDict<GeofenceBreachTypeMask> mGeofenceBiDict;
+ BiDict<SessionEntity> mSessionBiDict;
+ int32_t mBatchSize;
+ bool mTracking;
+};
+
+#endif /* LOCATION_API_CLINET_BASE_H */
diff --git a/location/LocationDataTypes.h b/location/LocationDataTypes.h
new file mode 100644
index 0000000..17094ab
--- /dev/null
+++ b/location/LocationDataTypes.h
@@ -0,0 +1,1465 @@
+/* Copyright (c) 2018-2019 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 LOCATIONDATATYPES_H
+#define LOCATIONDATATYPES_H
+
+#include <vector>
+#include <stdint.h>
+#include <functional>
+#include <list>
+#include <string.h>
+
+#define GNSS_NI_REQUESTOR_MAX (256)
+#define GNSS_NI_MESSAGE_ID_MAX (2048)
+#define GNSS_SV_MAX (176)
+#define GNSS_MEASUREMENTS_MAX (128)
+#define GNSS_UTC_TIME_OFFSET (3657)
+
+#define GNSS_BUGREPORT_GPS_MIN (1)
+#define GNSS_BUGREPORT_SBAS_MIN (120)
+#define GNSS_BUGREPORT_GLO_MIN (1)
+#define GNSS_BUGREPORT_QZSS_MIN (193)
+#define GNSS_BUGREPORT_BDS_MIN (1)
+#define GNSS_BUGREPORT_GAL_MIN (1)
+#define GNSS_BUGREPORT_NAVIC_MIN (1)
+
+#define GNSS_MAX_NAME_LENGTH (8)
+
+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
+ LOCATION_HAS_VERTICAL_ACCURACY_BIT = (1<<5), // location has valid vertical accuracy
+ LOCATION_HAS_SPEED_ACCURACY_BIT = (1<<6), // location has valid speed accuracy
+ LOCATION_HAS_BEARING_ACCURACY_BIT = (1<<7), // location has valid bearing accuracy
+ LOCATION_HAS_SPOOF_MASK = (1<<8), // location has valid spoof mask
+} 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 uint32_t LocationSpoofMask;
+typedef enum {
+ LOCATION_POSTION_SPOOFED = (1<<0), // location position spoofed
+ LOCATION_TIME_SPOOFED = (1<<1), // location time spoofed
+ LOCATION_NAVIGATION_DATA_SPOOFED = (1<<2), // location navigation data spoofed
+} LocationSpoofBits;
+
+typedef enum {
+ LOCATION_RELIABILITY_NOT_SET = 0,
+ LOCATION_RELIABILITY_VERY_LOW,
+ LOCATION_RELIABILITY_LOW,
+ LOCATION_RELIABILITY_MEDIUM,
+ LOCATION_RELIABILITY_HIGH,
+} LocationReliability;
+
+typedef uint32_t GnssLocationNavSolutionMask;
+typedef enum {
+ LOCATION_SBAS_CORRECTION_IONO_BIT = (1<<0), // SBAS ionospheric correction is used
+ LOCATION_SBAS_CORRECTION_FAST_BIT = (1<<1), // SBAS fast correction is used
+ LOCATION_SBAS_CORRECTION_LONG_BIT = (1<<2), // SBAS long-tem correction is used
+ LOCATION_SBAS_INTEGRITY_BIT = (1<<3), // SBAS integrity information is used
+ LOCATION_NAV_CORRECTION_DGNSS_BIT = (1<<4), // Position Report is DGNSS corrected
+ LOCATION_NAV_CORRECTION_RTK_BIT = (1<<5), // Position Report is RTK corrected
+ LOCATION_NAV_CORRECTION_PPP_BIT = (1<<6) // Position Report is PPP corrected
+} GnssLocationNavSolutionBits;
+
+typedef uint32_t GnssLocationPosTechMask;
+typedef enum {
+ LOCATION_POS_TECH_DEFAULT_BIT = 0,
+ LOCATION_POS_TECH_SATELLITE_BIT = (1<<0),
+ LOCATION_POS_TECH_CELLID_BIT = (1<<1),
+ LOCATION_POS_TECH_WIFI_BIT = (1<<2),
+ LOCATION_POS_TECH_SENSORS_BIT = (1<<3),
+ LOCATION_POS_TECH_REFERENCE_LOCATION_BIT = (1<<4),
+ LOCATION_POS_TECH_INJECTED_COARSE_POSITION_BIT = (1<<5),
+ LOCATION_POS_TECH_AFLT_BIT = (1<<6),
+ LOCATION_POS_TECH_HYBRID_BIT = (1<<7),
+ LOCATION_POS_TECH_PPE_BIT = (1<<8)
+} GnssLocationPosTechBits;
+
+typedef uint32_t GnssLocationPosDataMask;
+typedef enum {
+ LOCATION_NAV_DATA_HAS_LONG_ACCEL_BIT = (1<<0), // Navigation data has Forward Acceleration
+ LOCATION_NAV_DATA_HAS_LAT_ACCEL_BIT = (1<<1), // Navigation data has Sideward Acceleration
+ LOCATION_NAV_DATA_HAS_VERT_ACCEL_BIT = (1<<2), // Navigation data has Vertical Acceleration
+ LOCATION_NAV_DATA_HAS_YAW_RATE_BIT = (1<<3), // Navigation data has Heading Rate
+ LOCATION_NAV_DATA_HAS_PITCH_BIT = (1<<4), // Navigation data has Body pitch
+ // Navigation data has Forward Acceleration uncertainty
+ LOCATION_NAV_DATA_HAS_LONG_ACCEL_UNC_BIT = (1<<5),
+ // Navigation data has Sideward Acceleration uncertainty
+ LOCATION_NAV_DATA_HAS_LAT_ACCEL_UNC_BIT = (1<<6),
+ // Navigation data has Vertical Acceleration uncertainty
+ LOCATION_NAV_DATA_HAS_VERT_ACCEL_UNC_BIT = (1<<7),
+ // Navigation data has Heading Rate uncertainty
+ LOCATION_NAV_DATA_HAS_YAW_RATE_UNC_BIT = (1<<8),
+ // Navigation data has Body pitch uncertainty
+ LOCATION_NAV_DATA_HAS_PITCH_UNC_BIT = (1<<9)
+} GnssLocationPosDataBits;
+
+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_HOR_RELIABILITY_BIT = (1<<3), // valid horizontal reliability
+ GNSS_LOCATION_INFO_VER_RELIABILITY_BIT = (1<<4), // valid vertical reliability
+ GNSS_LOCATION_INFO_HOR_ACCURACY_ELIP_SEMI_MAJOR_BIT = (1<<5), // valid elipsode semi major
+ GNSS_LOCATION_INFO_HOR_ACCURACY_ELIP_SEMI_MINOR_BIT = (1<<6), // valid elipsode semi minor
+ GNSS_LOCATION_INFO_HOR_ACCURACY_ELIP_AZIMUTH_BIT = (1<<7), // valid accuracy elipsode azimuth
+ GNSS_LOCATION_INFO_GNSS_SV_USED_DATA_BIT = (1<<8), // valid svUsedInPosition,
+ // numOfMeasReceived
+ // and measUsageInfo
+ GNSS_LOCATION_INFO_NAV_SOLUTION_MASK_BIT = (1<<9), // valid navSolutionMask
+ GNSS_LOCATION_INFO_POS_TECH_MASK_BIT = (1<<10),// valid LocPosTechMask
+ GNSS_LOCATION_INFO_SV_SOURCE_INFO_BIT = (1<<11),// valid LocSvInfoSource
+ GNSS_LOCATION_INFO_POS_DYNAMICS_DATA_BIT = (1<<12),// valid position dynamics data
+ GNSS_LOCATION_INFO_EXT_DOP_BIT = (1<<13),// valid gdop, tdop
+ GNSS_LOCATION_INFO_NORTH_STD_DEV_BIT = (1<<14),// valid North standard deviation
+ GNSS_LOCATION_INFO_EAST_STD_DEV_BIT = (1<<15),// valid East standard deviation
+ GNSS_LOCATION_INFO_NORTH_VEL_BIT = (1<<16),// valid North Velocity
+ GNSS_LOCATION_INFO_EAST_VEL_BIT = (1<<17),// valid East Velocity
+ GNSS_LOCATION_INFO_UP_VEL_BIT = (1<<18),// valid Up Velocity
+ GNSS_LOCATION_INFO_NORTH_VEL_UNC_BIT = (1<<19),// valid North Velocity Uncertainty
+ GNSS_LOCATION_INFO_EAST_VEL_UNC_BIT = (1<<20),// valid East Velocity Uncertainty
+ GNSS_LOCATION_INFO_UP_VEL_UNC_BIT = (1<<21),// valid Up Velocity Uncertainty
+ GNSS_LOCATION_INFO_LEAP_SECONDS_BIT = (1<<22),// valid leap seconds
+ GNSS_LOCATION_INFO_TIME_UNC_BIT = (1<<23),// valid time uncertainty
+ GNSS_LOCATION_INFO_NUM_SV_USED_IN_POSITION_BIT = (1<<24), // number of SV used in position
+ GNSS_LOCATION_INFO_CALIBRATION_CONFIDENCE_BIT = (1<<25), // valid sensor cal confidence
+ GNSS_LOCATION_INFO_CALIBRATION_STATUS_BIT = (1<<26), // valid sensor cal status
+ GNSS_LOCATION_INFO_OUTPUT_ENG_TYPE_BIT = (1<<27), // valid output engine type
+ GNSS_LOCATION_INFO_OUTPUT_ENG_MASK_BIT = (1<<28), // valid output engine mask
+} 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),
+ // supports debug nmea sentences in the debugNmeaCallback
+ LOCATION_CAPABILITIES_DEBUG_NMEA_BIT = (1<<8),
+ // support outdoor trip batching
+ LOCATION_CAPABILITIES_OUTDOOR_TRIP_BATCHING_BIT = (1<<9),
+ // support constellation enablement
+ LOCATION_CAPABILITIES_CONSTELLATION_ENABLEMENT_BIT = (1<<10),
+ // support agpm
+ LOCATION_CAPABILITIES_AGPM_BIT = (1<<11),
+ // support location privacy
+ LOCATION_CAPABILITIES_PRIVACY_BIT = (1<<12),
+} LocationCapabilitiesBits;
+
+typedef enum {
+ LOCATION_TECHNOLOGY_TYPE_GNSS = 0,
+} LocationTechnologyType;
+
+// Configures how GPS is locked when GPS is disabled (through GnssDisable)
+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
+};
+typedef int32_t 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
+ GNSS_CONFIG_LPPE_CONTROL_PLANE_SRN_AP_MEASUREMENTS_BIT = (1<<2), // SRN_AP_MEASUREMENTS
+ GNSS_CONFIG_LPPE_CONTROL_PLANE_SENSOR_BARO_MEASUREMENTS_BIT = (1<<3),
+ // SENSOR_BARO_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
+ GNSS_CONFIG_LPPE_USER_PLANE_SRN_AP_MEASUREMENTS_BIT = (1<<2), // SRN_AP_MEASUREMENTS
+ GNSS_CONFIG_LPPE_USER_PLANE_SENSOR_BARO_MEASUREMENTS_BIT = (1<<3),
+ // SENSOR_BARO_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_BIT = (1<<0),
+ GNSS_CONFIG_SUPL_MODE_MSA_BIT = (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),
+ GNSS_CONFIG_FLAGS_BLACKLISTED_SV_IDS_BIT = (1<<10),
+ GNSS_CONFIG_FLAGS_EMERGENCY_EXTENSION_SECONDS_BIT = (1<<11),
+} 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_BIT = (1<<0),
+ GNSS_NI_OPTIONS_VERIFICATION_BIT = (1<<1),
+ GNSS_NI_OPTIONS_PRIVACY_OVERRIDE_BIT = (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,
+ GNSS_SV_TYPE_NAVIC,
+} GnssSvType;
+
+typedef enum {
+ GNSS_EPH_TYPE_UNKNOWN = 0,
+ GNSS_EPH_TYPE_EPHEMERIS,
+ GNSS_EPH_TYPE_ALMANAC,
+} GnssEphemerisType;
+
+typedef enum {
+ GNSS_EPH_SOURCE_UNKNOWN = 0,
+ GNSS_EPH_SOURCE_DEMODULATED,
+ GNSS_EPH_SOURCE_SUPL_PROVIDED,
+ GNSS_EPH_SOURCE_OTHER_SERVER_PROVIDED,
+ GNSS_EPH_SOURCE_LOCAL,
+} GnssEphemerisSource;
+
+typedef enum {
+ GNSS_EPH_HEALTH_UNKNOWN = 0,
+ GNSS_EPH_HEALTH_GOOD,
+ GNSS_EPH_HEALTH_BAD,
+} GnssEphemerisHealth;
+
+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),
+ GNSS_SV_OPTIONS_HAS_CARRIER_FREQUENCY_BIT = (1<<3),
+} GnssSvOptionsBits;
+
+typedef enum {
+ GNSS_ASSISTANCE_TYPE_SUPL = 0,
+ GNSS_ASSISTANCE_TYPE_C2K,
+ GNSS_ASSISTANCE_TYPE_SUPL_EIMS,
+ GNSS_ASSISTANCE_TYPE_SUPL_IMS,
+} GnssAssistanceType;
+
+typedef enum {
+ GNSS_SUPL_MODE_STANDALONE = 0,
+ GNSS_SUPL_MODE_MSB,
+ GNSS_SUPL_MODE_MSA,
+} GnssSuplMode;
+
+typedef enum {
+ BATCHING_MODE_ROUTINE = 0, // positions are reported when batched positions memory is full
+ BATCHING_MODE_TRIP, // positions are reported when a certain distance is covered
+ BATCHING_MODE_NO_AUTO_REPORT // no report of positions automatically, instead queried on demand
+} BatchingMode;
+
+typedef enum {
+ BATCHING_STATUS_TRIP_COMPLETED = 0,
+ BATCHING_STATUS_POSITION_AVAILABE,
+ BATCHING_STATUS_POSITION_UNAVAILABLE
+} BatchingStatus;
+
+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),
+ GNSS_MEASUREMENTS_ACCUMULATED_DELTA_RANGE_STATE_HALF_CYCLE_RESOLVED_BIT = (1<<3),
+} GnssMeasurementsAdrStateBits;
+
+typedef enum {
+ GNSS_MEASUREMENTS_CODE_TYPE_A = 0,
+ GNSS_MEASUREMENTS_CODE_TYPE_B = 1,
+ GNSS_MEASUREMENTS_CODE_TYPE_C = 2,
+ GNSS_MEASUREMENTS_CODE_TYPE_I = 3,
+ GNSS_MEASUREMENTS_CODE_TYPE_L = 4,
+ GNSS_MEASUREMENTS_CODE_TYPE_M = 5,
+ GNSS_MEASUREMENTS_CODE_TYPE_P = 6,
+ GNSS_MEASUREMENTS_CODE_TYPE_Q = 7,
+ GNSS_MEASUREMENTS_CODE_TYPE_S = 8,
+ GNSS_MEASUREMENTS_CODE_TYPE_W = 9,
+ GNSS_MEASUREMENTS_CODE_TYPE_X = 10,
+ GNSS_MEASUREMENTS_CODE_TYPE_Y = 11,
+ GNSS_MEASUREMENTS_CODE_TYPE_Z = 12,
+ GNSS_MEASUREMENTS_CODE_TYPE_N = 13,
+ GNSS_MEASUREMENTS_CODE_TYPE_OTHER = 255,
+} GnssMeasurementsCodeType;
+
+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),
+ GNSS_MEASUREMENTS_DATA_AUTOMATIC_GAIN_CONTROL_BIT = (1<<17),
+} 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),
+ GNSS_MEASUREMENTS_STATE_TOW_KNOWN_BIT = (1<<14),
+ GNSS_MEASUREMENTS_STATE_GLO_TOD_KNOWN_BIT = (1<<15),
+ GNSS_MEASUREMENTS_STATE_2ND_CODE_LOCK_BIT = (1<<16),
+} 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_BIT = (1<<0), // ephemeris
+ GNSS_AIDING_DATA_SV_ALMANAC_BIT = (1<<1), // almanac
+ GNSS_AIDING_DATA_SV_HEALTH_BIT = (1<<2), // health
+ GNSS_AIDING_DATA_SV_DIRECTION_BIT = (1<<3), // direction
+ GNSS_AIDING_DATA_SV_STEER_BIT = (1<<4), // steer
+ GNSS_AIDING_DATA_SV_ALMANAC_CORR_BIT = (1<<5), // almanac correction
+ GNSS_AIDING_DATA_SV_BLACKLIST_BIT = (1<<6), // blacklist SVs
+ GNSS_AIDING_DATA_SV_SA_DATA_BIT = (1<<7), // sensitivity assistance data
+ GNSS_AIDING_DATA_SV_NO_EXIST_BIT = (1<<8), // SV does not exist
+ GNSS_AIDING_DATA_SV_IONOSPHERE_BIT = (1<<9), // ionosphere correction
+ GNSS_AIDING_DATA_SV_TIME_BIT = (1<<10),// reset satellite time
+ GNSS_AIDING_DATA_SV_MB_DATA = (1<<11),// delete multiband data
+ GNSS_AIDING_DATA_SV_POLY_BIT = (1<<12),// poly
+} GnssAidingDataSvBits;
+
+typedef uint32_t GnssAidingDataSvTypeMask;
+typedef enum {
+ GNSS_AIDING_DATA_SV_TYPE_GPS_BIT = (1<<0),
+ GNSS_AIDING_DATA_SV_TYPE_GLONASS_BIT = (1<<1),
+ GNSS_AIDING_DATA_SV_TYPE_QZSS_BIT = (1<<2),
+ GNSS_AIDING_DATA_SV_TYPE_BEIDOU_BIT = (1<<3),
+ GNSS_AIDING_DATA_SV_TYPE_GALILEO_BIT = (1<<4),
+ GNSS_AIDING_DATA_SV_TYPE_NAVIC_BIT = (1<<5),
+} GnssAidingDataSvTypeBits;
+
+/* Gnss constellation type mask */
+typedef uint16_t GnssConstellationTypeMask;
+typedef enum {
+ GNSS_CONSTELLATION_TYPE_GPS_BIT = (1<<0),
+ GNSS_CONSTELLATION_TYPE_GLONASS_BIT = (1<<1),
+ GNSS_CONSTELLATION_TYPE_QZSS_BIT = (1<<2),
+ GNSS_CONSTELLATION_TYPE_BEIDOU_BIT = (1<<3),
+ GNSS_CONSTELLATION_TYPE_GALILEO_BIT = (1<<4),
+ GNSS_CONSTELLATION_TYPE_SBAS_BIT = (1<<5),
+ GNSS_CONSTELLATION_TYPE_NAVIC_BIT = (1<<6)
+} GnssConstellationTypeBits;
+
+#define GNSS_CONSTELLATION_TYPE_MASK_ALL\
+ (GNSS_CONSTELLATION_TYPE_GPS_BIT | GNSS_CONSTELLATION_TYPE_GLONASS_BIT |\
+ GNSS_CONSTELLATION_TYPE_QZSS_BIT | GNSS_CONSTELLATION_TYPE_BEIDOU_BIT |\
+ GNSS_CONSTELLATION_TYPE_GALILEO_BIT | GNSS_CONSTELLATION_TYPE_SBAS_BIT |\
+ GNSS_CONSTELLATION_TYPE_NAVIC_BIT)
+
+/** GNSS Signal Type and RF Band */
+typedef uint32_t GnssSignalTypeMask;
+typedef enum {
+ /** GPS L1CA Signal */
+ GNSS_SIGNAL_GPS_L1CA = (1<<0),
+ /** GPS L1C Signal */
+ GNSS_SIGNAL_GPS_L1C = (1<<1),
+ /** GPS L2 RF Band */
+ GNSS_SIGNAL_GPS_L2 = (1<<2),
+ /** GPS L5 RF Band */
+ GNSS_SIGNAL_GPS_L5 = (1<<3),
+ /** GLONASS G1 (L1OF) RF Band */
+ GNSS_SIGNAL_GLONASS_G1 = (1<<4),
+ /** GLONASS G2 (L2OF) RF Band */
+ GNSS_SIGNAL_GLONASS_G2 = (1<<5),
+ /** GALILEO E1 RF Band */
+ GNSS_SIGNAL_GALILEO_E1 = (1<<6),
+ /** GALILEO E5A RF Band */
+ GNSS_SIGNAL_GALILEO_E5A = (1<<7),
+ /** GALILEO E5B RF Band */
+ GNSS_SIGNAL_GALILEO_E5B = (1<<8),
+ /** BEIDOU B1_I RF Band */
+ GNSS_SIGNAL_BEIDOU_B1I = (1<<9),
+ /** BEIDOU B1C RF Band */
+ GNSS_SIGNAL_BEIDOU_B1C = (1<<10),
+ /** BEIDOU B2_I RF Band */
+ GNSS_SIGNAL_BEIDOU_B2I = (1<<11),
+ /** BEIDOU B2A_I RF Band */
+ GNSS_SIGNAL_BEIDOU_B2AI = (1<<12),
+ /** QZSS L1CA RF Band */
+ GNSS_SIGNAL_QZSS_L1CA = (1<<13),
+ /** QZSS L1S RF Band */
+ GNSS_SIGNAL_QZSS_L1S = (1<<14),
+ /** QZSS L2 RF Band */
+ GNSS_SIGNAL_QZSS_L2 = (1<<15),
+ /** QZSS L5 RF Band */
+ GNSS_SIGNAL_QZSS_L5 = (1<<16),
+ /** SBAS L1 RF Band */
+ GNSS_SIGNAL_SBAS_L1 = (1<<17),
+ /** NAVIC L5 RF Band */
+ GNSS_SIGNAL_NAVIC_L5 = (1<<18),
+ /** BEIDOU B2A_Q RF Band */
+ GNSS_SIGNAL_BEIDOU_B2AQ = (1<<19)
+} GnssSignalTypeBits;
+
+#define GNSS_SIGNAL_TYPE_MASK_ALL\
+ (GNSS_SIGNAL_GPS_L1CA | GNSS_SIGNAL_GPS_L1C | GNSS_SIGNAL_GPS_L2 |\
+ GNSS_SIGNAL_GPS_L5| GNSS_SIGNAL_GLONASS_G1 | GNSS_SIGNAL_GLONASS_G2 |\
+ GNSS_SIGNAL_GALILEO_E1 | GNSS_SIGNAL_GALILEO_E5A | GNSS_SIGNAL_GALILEO_E5B |\
+ GNSS_SIGNAL_BEIDOU_B1I | GNSS_SIGNAL_BEIDOU_B1C | GNSS_SIGNAL_BEIDOU_B2I|\
+ GNSS_SIGNAL_BEIDOU_B2AI | GNSS_SIGNAL_QZSS_L1CA | GNSS_SIGNAL_QZSS_L1S |\
+ GNSS_SIGNAL_QZSS_L2| GNSS_SIGNAL_QZSS_L5 | GNSS_SIGNAL_SBAS_L1 |\
+ GNSS_SIGNAL_NAVIC_L5 | GNSS_SIGNAL_BEIDOU_B2AQ)
+
+typedef enum
+{
+ GNSS_LOC_SV_SYSTEM_UNKNOWN = 0,
+ /** unknown sv system. */
+ GNSS_LOC_SV_SYSTEM_MIN = 1,
+ /**< Min enum of valid SV system. */
+ GNSS_LOC_SV_SYSTEM_GPS = 1,
+ /**< GPS satellite. */
+ GNSS_LOC_SV_SYSTEM_GALILEO = 2,
+ /**< GALILEO satellite. */
+ GNSS_LOC_SV_SYSTEM_SBAS = 3,
+ /**< SBAS satellite. */
+ GNSS_LOC_SV_SYSTEM_GLONASS = 4,
+ /**< GLONASS satellite. */
+ GNSS_LOC_SV_SYSTEM_BDS = 5,
+ /**< BDS satellite. */
+ GNSS_LOC_SV_SYSTEM_QZSS = 6,
+ /**< QZSS satellite. */
+ GNSS_LOC_SV_SYSTEM_NAVIC = 7,
+ /**< QZSS satellite. */
+ GNSS_LOC_SV_SYSTEM_MAX = 7,
+ /**< Max enum of valid SV system. */
+} Gnss_LocSvSystemEnumType;
+
+typedef enum {
+ GNSS_LOC_SIGNAL_TYPE_GPS_L1CA = 0, /**< GPS L1CA Signal */
+ GNSS_LOC_SIGNAL_TYPE_GPS_L1C = 1, /**< GPS L1C Signal */
+ GNSS_LOC_SIGNAL_TYPE_GPS_L2C_L = 2, /**< GPS L2C_L RF Band */
+ GNSS_LOC_SIGNAL_TYPE_GPS_L5_Q = 3, /**< GPS L5_Q RF Band */
+ GNSS_LOC_SIGNAL_TYPE_GLONASS_G1 = 4, /**< GLONASS G1 (L1OF) RF Band */
+ GNSS_LOC_SIGNAL_TYPE_GLONASS_G2 = 5, /**< GLONASS G2 (L2OF) RF Band */
+ GNSS_LOC_SIGNAL_TYPE_GALILEO_E1_C = 6, /**< GALILEO E1_C RF Band */
+ GNSS_LOC_SIGNAL_TYPE_GALILEO_E5A_Q = 7, /**< GALILEO E5A_Q RF Band */
+ GNSS_LOC_SIGNAL_TYPE_GALILEO_E5B_Q = 8, /**< GALILEO E5B_Q RF Band */
+ GNSS_LOC_SIGNAL_TYPE_BEIDOU_B1_I = 9, /**< BEIDOU B1_I RF Band */
+ GNSS_LOC_SIGNAL_TYPE_BEIDOU_B1C = 10, /**< BEIDOU B1C RF Band */
+ GNSS_LOC_SIGNAL_TYPE_BEIDOU_B2_I = 11, /**< BEIDOU B2_I RF Band */
+ GNSS_LOC_SIGNAL_TYPE_BEIDOU_B2A_I = 12, /**< BEIDOU B2A_I RF Band */
+ GNSS_LOC_SIGNAL_TYPE_QZSS_L1CA = 13, /**< QZSS L1CA RF Band */
+ GNSS_LOC_SIGNAL_TYPE_QZSS_L1S = 14, /**< QZSS L1S RF Band */
+ GNSS_LOC_SIGNAL_TYPE_QZSS_L2C_L = 15, /**< QZSS L2C_L RF Band */
+ GNSS_LOC_SIGNAL_TYPE_QZSS_L5_Q = 16, /**< QZSS L5_Q RF Band */
+ GNSS_LOC_SIGNAL_TYPE_SBAS_L1_CA = 17, /**< SBAS L1_CA RF Band */
+ GNSS_LOC_SIGNAL_TYPE_NAVIC_L5 = 18, /**< NAVIC L5 RF Band */
+ GNSS_LOC_SIGNAL_TYPE_BEIDOU_B2A_Q = 19, /**< BEIDOU B2A_Q RF Band */
+ GNSS_LOC_MAX_NUMBER_OF_SIGNAL_TYPES = 20 /**< Maximum number of signal types */
+} Gnss_LocSignalEnumType;
+
+typedef uint32_t PositioningEngineMask;
+typedef enum {
+ STANDARD_POSITIONING_ENGINE = (1 << 0),
+ DEAD_RECKONING_ENGINE = (1 << 1),
+ PRECISE_POSITIONING_ENGINE = (1 << 2)
+} PositioningEngineBits;
+
+typedef uint64_t GnssDataMask;
+typedef enum {
+ // Jammer Indicator is available
+ GNSS_LOC_DATA_JAMMER_IND_BIT = (1ULL << 0),
+ // AGC is available
+ GNSS_LOC_DATA_AGC_BIT = (1ULL << 1)
+} GnssDataBits;
+
+typedef uint32_t GnssSystemTimeStructTypeFlags;
+typedef enum {
+ GNSS_SYSTEM_TIME_WEEK_VALID = (1 << 0),
+ GNSS_SYSTEM_TIME_WEEK_MS_VALID = (1 << 1),
+ GNSS_SYSTEM_CLK_TIME_BIAS_VALID = (1 << 2),
+ GNSS_SYSTEM_CLK_TIME_BIAS_UNC_VALID = (1 << 3),
+ GNSS_SYSTEM_REF_FCOUNT_VALID = (1 << 4),
+ GNSS_SYSTEM_NUM_CLOCK_RESETS_VALID = (1 << 5)
+} GnssSystemTimeTypeBits;
+
+typedef uint32_t GnssGloTimeStructTypeFlags;
+typedef enum {
+ GNSS_CLO_DAYS_VALID = (1 << 0),
+ GNSS_GLO_MSEC_VALID = (1 << 1),
+ GNSS_GLO_CLK_TIME_BIAS_VALID = (1 << 2),
+ GNSS_GLO_CLK_TIME_BIAS_UNC_VALID = (1 << 3),
+ GNSS_GLO_REF_FCOUNT_VALID = (1 << 4),
+ GNSS_GLO_NUM_CLOCK_RESETS_VALID = (1 << 5),
+ GNSS_GLO_FOUR_YEAR_VALID = (1 << 6)
+} GnssGloTimeTypeBits;
+
+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_BIT = (1<<0), // position estimate
+ GNSS_AIDING_DATA_COMMON_TIME_BIT = (1<<1), // reset all clock values
+ GNSS_AIDING_DATA_COMMON_UTC_BIT = (1<<2), // UTC estimate
+ GNSS_AIDING_DATA_COMMON_RTI_BIT = (1<<3), // RTI
+ GNSS_AIDING_DATA_COMMON_FREQ_BIAS_EST_BIT = (1<<4), // frequency bias estimate
+ GNSS_AIDING_DATA_COMMON_CELLDB_BIT = (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
+ PositioningEngineMask posEngineMask; // engines to perform the delete operation on.
+} GnssAidingData;
+
+typedef uint16_t DrCalibrationStatusMask;
+typedef enum {
+ // Indicate that roll calibration is needed. Need to take more turns on level ground
+ DR_ROLL_CALIBRATION_NEEDED = (1<<0),
+ // Indicate that pitch calibration is needed. Need to take more turns on level ground
+ DR_PITCH_CALIBRATION_NEEDED = (1<<1),
+ // Indicate that yaw calibration is needed. Need to accelerate in a straight line
+ DR_YAW_CALIBRATION_NEEDED = (1<<2),
+ // Indicate that odo calibration is needed. Need to accelerate in a straight line
+ DR_ODO_CALIBRATION_NEEDED = (1<<3),
+ // Indicate that gyro calibration is needed. Need to take more turns on level ground
+ DR_GYRO_CALIBRATION_NEEDED = (1<<4)
+} DrCalibrationStatusBits;
+
+typedef struct {
+ uint32_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
+ float verticalAccuracy; // in meters
+ float speedAccuracy; // in meters/second
+ float bearingAccuracy; // in degrees (0 to 359.999)
+ LocationTechnologyMask techMask;
+ LocationSpoofMask spoofMask;
+} Location;
+
+typedef enum {
+ LOC_REQ_ENGINE_FUSED_BIT = (1<<0),
+ LOC_REQ_ENGINE_SPE_BIT = (1<<1),
+ LOC_REQ_ENGINE_PPE_BIT = (1<<2),
+} LocReqEngineTypeMask;
+
+typedef enum {
+ LOC_OUTPUT_ENGINE_FUSED = 0,
+ /** This is the GNSS fix from modem */
+ LOC_OUTPUT_ENGINE_SPE = 1,
+ /** This is the GNSS fix with correction PPP/RTK correction */
+ LOC_OUTPUT_ENGINE_PPE = 2,
+ LOC_OUTPUT_ENGINE_COUNT,
+} LocOutputEngineType;
+
+struct LocationOptions {
+ uint32_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
+ // behavior when this field is 0:
+ // if engine hub is running, this will be fused fix,
+ // if engine hub is not running, this will be SPE fix
+ LocReqEngineTypeMask locReqEngTypeMask;
+
+ inline LocationOptions() :
+ size(0), minInterval(0), minDistance(0), mode(GNSS_SUPL_MODE_STANDALONE),
+ locReqEngTypeMask((LocReqEngineTypeMask)0) {}
+};
+
+typedef enum {
+ GNSS_POWER_MODE_INVALID = 0,
+ GNSS_POWER_MODE_M1, /* Improved Accuracy Mode */
+ GNSS_POWER_MODE_M2, /* Normal Mode */
+ GNSS_POWER_MODE_M3, /* Background Mode */
+ GNSS_POWER_MODE_M4, /* Background Mode */
+ GNSS_POWER_MODE_M5 /* Background Mode */
+} GnssPowerMode;
+
+struct TrackingOptions : LocationOptions {
+ GnssPowerMode powerMode; /* Power Mode to be used for time based tracking
+ sessions */
+ uint32_t tbm; /* Time interval between measurements specified in millis.
+ Applicable to background power modes */
+
+ inline TrackingOptions() :
+ LocationOptions(), powerMode(GNSS_POWER_MODE_INVALID), tbm(0) {}
+ inline TrackingOptions(uint32_t s, GnssPowerMode m, uint32_t t) :
+ LocationOptions(), powerMode(m), tbm(t) { LocationOptions::size = s; }
+ inline TrackingOptions(const LocationOptions& options) :
+ LocationOptions(options), powerMode(GNSS_POWER_MODE_INVALID), tbm(0) {}
+ inline void setLocationOptions(const LocationOptions& options) {
+ size = sizeof(TrackingOptions);
+ minInterval = options.minInterval;
+ minDistance = options.minDistance;
+ mode = options.mode;
+ locReqEngTypeMask = options.locReqEngTypeMask;
+ }
+ inline LocationOptions getLocationOptions() {
+ LocationOptions locOption;
+ locOption.size = sizeof(locOption);
+ locOption.minDistance = minDistance;
+ locOption.minInterval = minInterval;
+ locOption.mode = mode;
+ locOption.locReqEngTypeMask = locReqEngTypeMask;
+ return locOption;
+ }
+};
+
+struct BatchingOptions : LocationOptions {
+ BatchingMode batchingMode;
+
+ inline BatchingOptions() :
+ LocationOptions(), batchingMode(BATCHING_MODE_ROUTINE) {}
+ inline BatchingOptions(uint32_t s, BatchingMode m) :
+ LocationOptions(), batchingMode(m) { LocationOptions::size = s; }
+ inline BatchingOptions(const LocationOptions& options) :
+ LocationOptions(options), batchingMode(BATCHING_MODE_ROUTINE) {}
+ inline void setLocationOptions(const LocationOptions& options) {
+ minInterval = options.minInterval;
+ minDistance = options.minDistance;
+ mode = options.mode;
+ }
+};
+
+typedef struct {
+ uint32_t size;
+ BatchingStatus batchingStatus;
+} BatchingStatusInfo;
+
+typedef struct {
+ uint32_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 {
+ uint32_t size; // set to sizeof(GeofenceInfo)
+ double latitude; // in degrees
+ double longitude; // in degrees
+ double radius; // in meters
+} GeofenceInfo;
+
+typedef struct {
+ uint32_t size; // set to sizeof(GeofenceBreachNotification)
+ uint32_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 {
+ uint32_t size; // set to sizeof(GeofenceBreachNotification)
+ GeofenceStatusAvailable available; // GEOFENCE_STATUS_AVAILABILE_NO/_YES
+ LocationTechnologyType techType; // GNSS
+} GeofenceStatusNotification;
+
+typedef struct {
+ uint64_t gpsSvUsedIdsMask;
+ uint64_t gloSvUsedIdsMask;
+ uint64_t galSvUsedIdsMask;
+ uint64_t bdsSvUsedIdsMask;
+ uint64_t qzssSvUsedIdsMask;
+ uint64_t navicSvUsedIdsMask;
+} GnssLocationSvUsedInPosition;
+
+typedef struct {
+ /** GnssSignalType mask */
+ GnssSignalTypeMask gnssSignalType;
+ /** Specifies GNSS Constellation Type */
+ Gnss_LocSvSystemEnumType gnssConstellation;
+ /** GNSS SV ID.
+ For GPS: 1 to 32
+ For GLONASS: 65 to 96. When slot-number to SV ID mapping is unknown, set as 255.
+ For SBAS: 120 to 151
+ For QZSS-L1CA:193 to 197
+ For BDS: 201 to 237
+ For GAL: 301 to 336
+ For NAVIC: 401 to 414 */
+ uint16_t gnssSvId;
+} GnssMeasUsageInfo;
+
+/** @struct
+ Body Frame parameters
+*/
+typedef struct {
+ GnssLocationPosDataMask bodyFrameDataMask; // Contains Body frame LocPosDataMask bits
+ float longAccel; // Forward Acceleration in body frame (m/s2)
+ float latAccel; // Sideward Acceleration in body frame (m/s2)
+ float vertAccel; // Vertical Acceleration in body frame (m/s2)
+ float yawRate; // Heading Rate (Radians/second)
+ float pitch; // Body pitch (Radians)
+ float longAccelUnc; // Uncertainty of Forward Acceleration in body frame
+ float latAccelUnc; // Uncertainty of Side-ward Acceleration in body frame
+ float vertAccelUnc; // Uncertainty of Vertical Acceleration in body frame
+ float yawRateUnc; // Uncertainty of Heading Rate
+ float pitchUnc; // Uncertainty of Body pitch
+} GnssLocationPositionDynamics;
+
+typedef struct {
+ /** Validity mask for below fields */
+ GnssSystemTimeStructTypeFlags validityMask;
+ /** Extended week number at reference tick.
+ Unit: Week.
+ Set to 65535 if week number is unknown.
+ For GPS:
+ Calculated from midnight, Jan. 6, 1980.
+ OTA decoded 10 bit GPS week is extended to map between:
+ [NV6264 to (NV6264 + 1023)].
+ NV6264: Minimum GPS week number configuration.
+ Default value of NV6264: 1738
+ For BDS:
+ Calculated from 00:00:00 on January 1, 2006 of Coordinated Universal Time (UTC).
+ For GAL:
+ Calculated from 00:00 UT on Sunday August 22, 1999 (midnight between August 21 and August 22).
+ */
+ uint16_t systemWeek;
+ /** Time in to the current week at reference tick.
+ Unit: Millisecond. Range: 0 to 604799999.
+ Check for systemClkTimeUncMs before use */
+ uint32_t systemMsec;
+ /** System clock time bias (sub-millisecond)
+ Units: Millisecond
+ Note: System time (TOW Millisecond) = systemMsec - systemClkTimeBias.
+ Check for systemClkTimeUncMs before use. */
+ float systemClkTimeBias;
+ /** Single sided maximum time bias uncertainty
+ Units: Millisecond */
+ float systemClkTimeUncMs;
+ /** FCount (free running HW timer) value. Don't use for relative time purpose
+ due to possible discontinuities.
+ Unit: Millisecond */
+ uint32_t refFCount;
+ /** Number of clock resets/discontinuities detected, affecting the local hardware counter value. */
+ uint32_t numClockResets;
+} GnssSystemTimeStructType;
+
+typedef struct {
+ /** GLONASS day number in four years. Refer to GLONASS ICD.
+ Applicable only for GLONASS and shall be ignored for other constellations.
+ If unknown shall be set to 65535 */
+ uint16_t gloDays;
+ /** Validity mask for below fields */
+ GnssGloTimeStructTypeFlags validityMask;
+ /** GLONASS time of day in Millisecond. Refer to GLONASS ICD.
+ Units: Millisecond
+ Check for gloClkTimeUncMs before use */
+ uint32_t gloMsec;
+ /** GLONASS clock time bias (sub-millisecond)
+ Units: Millisecond
+ Note: GLO time (TOD Millisecond) = gloMsec - gloClkTimeBias.
+ Check for gloClkTimeUncMs before use. */
+ float gloClkTimeBias;
+ /** Single sided maximum time bias uncertainty
+ Units: Millisecond */
+ float gloClkTimeUncMs;
+ /** FCount (free running HW timer) value. Don't use for relative time purpose
+ due to possible discontinuities.
+ Unit: Millisecond */
+ uint32_t refFCount;
+ /** Number of clock resets/discontinuities detected, affecting the local hardware counter value. */
+ uint32_t numClockResets;
+ /** GLONASS four year number from 1996. Refer to GLONASS ICD.
+ Applicable only for GLONASS and shall be ignored for other constellations.
+ If unknown shall be set to 255 */
+ uint8_t gloFourYear;
+} GnssGloTimeStructType;
+
+typedef union {
+ GnssSystemTimeStructType gpsSystemTime;
+ GnssSystemTimeStructType galSystemTime;
+ GnssSystemTimeStructType bdsSystemTime;
+ GnssSystemTimeStructType qzssSystemTime;
+ GnssGloTimeStructType gloSystemTime;
+ GnssSystemTimeStructType navicSystemTime;
+} SystemTimeStructUnion;
+ /** Time applicability of PVT report */
+typedef struct {
+ /** Specifies GNSS system time reported. Mandatory field */
+ Gnss_LocSvSystemEnumType gnssSystemTimeSrc;
+ /** Reporting of GPS system time is recommended.
+ If GPS time is unknown & other satellite system time is known,
+ it should be reported.
+ Mandatory field
+ */
+ SystemTimeStructUnion u;
+} GnssSystemTime;
+
+typedef struct {
+ uint32_t size; // set to sizeof(GnssLocationInfo)
+ Location location; // basic locaiton info, latitude, longitude, and etc
+ 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 gdop; // geometric dilution of precision
+ float tdop; // time dilution of precision
+ float magneticDeviation; // magnetic deviation
+ 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
+ float northStdDeviation; // North standard deviation Unit: Meters
+ float eastStdDeviation; // East standard deviation. Unit: Meters
+ float northVelocity; // North Velocity.Unit: Meters/sec
+ float eastVelocity; // East Velocity Unit Meters/sec
+ float upVelocity; // Up Velocity. Unit Meters/sec
+ float northVelocityStdDeviation;
+ float eastVelocityStdDeviation;
+ float upVelocityStdDeviation;
+ uint16_t numSvUsedInPosition;
+ GnssLocationSvUsedInPosition svUsedInPosition;// Gnss sv used in position data
+ GnssLocationNavSolutionMask navSolutionMask; // Nav solution mask to indicate sbas corrections
+ GnssLocationPosTechMask posTechMask; // Position technology used in computing this fix
+ GnssLocationPositionDynamics bodyFrameData; // Body Frame Dynamics: 4wayAcceleration and
+ // pitch set with validity
+ GnssSystemTime gnssSystemTime; // GNSS System Time
+ uint8_t numOfMeasReceived; // Number of measurements received for use in fix.
+ GnssMeasUsageInfo measUsageInfo[GNSS_SV_MAX]; // GNSS Measurement Usage info
+ uint8_t leapSeconds; // leap second
+ float timeUncMs; // Time uncertainty in milliseconds
+ uint8_t calibrationConfidence; // Sensor calibration confidence percent,
+ // in range of [0, 100]
+ DrCalibrationStatusMask calibrationStatus; // Sensor calibration status
+ // location engine type. When the fix. when the type is set to
+ // LOC_ENGINE_SRC_FUSED, the fix is the propagated/aggregated
+ // reports from all engines running on the system (e.g.:
+ // DR/SPE/PPE). To check which location engine contributes to
+ // the fused output, check for locOutputEngMask.
+ LocOutputEngineType locOutputEngType;
+ // when loc output eng type is set to fused, this field
+ // indicates the set of engines contribute to the fix.
+ PositioningEngineMask locOutputEngMask;
+} GnssLocationInfoNotification;
+
+typedef struct {
+ uint32_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 {
+ uint32_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
+ float carrierFrequencyHz; // carrier frequency of the signal tracked
+ GnssSignalTypeMask gnssSignalTypeMask; // Specifies GNSS signal type
+} GnssSv;
+
+struct GnssConfigSetAssistanceServer {
+ uint32_t size; // set to sizeof(GnssConfigSetAssistanceServer)
+ GnssAssistanceType type; // SUPL or C2K
+ const char* hostName; // null terminated string
+ uint32_t port; // port of server
+
+ inline bool equals(const GnssConfigSetAssistanceServer& config) {
+ if (config.type == type && config.port == port &&
+ ((NULL == config.hostName && NULL == hostName) ||
+ (NULL != config.hostName && NULL != hostName &&
+ 0 == strcmp(config.hostName, hostName)))) {
+ return true;
+ }
+ return false;
+ }
+};
+
+typedef struct {
+ uint32_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;
+ double agcLevelDb;
+ GnssMeasurementsCodeType codeType;
+ char otherCodeTypeName[GNSS_MAX_NAME_LENGTH];
+} GnssMeasurementsData;
+
+typedef struct {
+ uint32_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 {
+ uint32_t size; // set to sizeof(GnssSvNotification)
+ uint32_t count; // number of SVs in the GnssSv array
+ bool gnssSignalTypeMaskValid;
+ GnssSv gnssSvs[GNSS_SV_MAX]; // information on a number of SVs
+} GnssSvNotification;
+
+typedef struct {
+ uint32_t size; // set to sizeof(GnssNmeaNotification)
+ uint64_t timestamp; // timestamp
+ const char* nmea; // nmea text
+ uint32_t length; // length of the nmea text
+} GnssNmeaNotification;
+
+typedef struct {
+ uint32_t size; // set to sizeof(GnssDataNotification)
+ GnssDataMask gnssDataMask[GNSS_LOC_MAX_NUMBER_OF_SIGNAL_TYPES]; // bitwise OR of GnssDataBits
+ double jammerInd[GNSS_LOC_MAX_NUMBER_OF_SIGNAL_TYPES]; // Jammer Indication
+ double agc[GNSS_LOC_MAX_NUMBER_OF_SIGNAL_TYPES]; // Automatic gain control
+} GnssDataNotification;
+
+typedef struct {
+ uint32_t size; // set to sizeof(GnssMeasurementsNotification)
+ uint32_t count; // number of items in GnssMeasurements array
+ GnssMeasurementsData measurements[GNSS_MEASUREMENTS_MAX];
+ GnssMeasurementsClock clock; // clock
+} GnssMeasurementsNotification;
+
+typedef uint32_t GnssSvId;
+
+struct GnssSvIdSource{
+ uint32_t size; // set to sizeof(GnssSvIdSource)
+ GnssSvType constellation; // constellation for the sv to blacklist
+ GnssSvId svId; // sv id to blacklist
+};
+inline bool operator ==(GnssSvIdSource const& left, GnssSvIdSource const& right) {
+ return left.size == right.size &&
+ left.constellation == right.constellation && left.svId == right.svId;
+}
+
+#define GNSS_SV_CONFIG_ALL_BITS_ENABLED_MASK ((uint64_t)0xFFFFFFFFFFFFFFFF)
+typedef struct {
+ uint32_t size; // set to sizeof(GnssSvIdConfig)
+
+ // GLONASS - SV 65 maps to bit 0
+#define GNSS_SV_CONFIG_GLO_INITIAL_SV_ID 65
+ uint64_t gloBlacklistSvMask;
+
+ // BEIDOU - SV 201 maps to bit 0
+#define GNSS_SV_CONFIG_BDS_INITIAL_SV_ID 201
+ uint64_t bdsBlacklistSvMask;
+
+ // QZSS - SV 193 maps to bit 0
+#define GNSS_SV_CONFIG_QZSS_INITIAL_SV_ID 193
+ uint64_t qzssBlacklistSvMask;
+
+ // GAL - SV 301 maps to bit 0
+#define GNSS_SV_CONFIG_GAL_INITIAL_SV_ID 301
+ uint64_t galBlacklistSvMask;
+} GnssSvIdConfig;
+
+struct GnssConfig{
+ uint32_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
+ std::vector<GnssSvIdSource> blacklistedSvIds;
+ uint32_t emergencyExtensionSeconds;
+
+ inline bool equals(const GnssConfig& config) {
+ if (flags == config.flags &&
+ gpsLock == config.gpsLock &&
+ suplVersion == config.suplVersion &&
+ assistanceServer.equals(config.assistanceServer) &&
+ lppProfile == config.lppProfile &&
+ lppeControlPlaneMask == config.lppeControlPlaneMask &&
+ lppeUserPlaneMask == config.lppeUserPlaneMask &&
+ aGlonassPositionProtocolMask == config.aGlonassPositionProtocolMask &&
+ emergencyPdnForEmergencySupl == config.emergencyPdnForEmergencySupl &&
+ suplEmergencyServices == config.suplEmergencyServices &&
+ suplModeMask == config.suplModeMask &&
+ blacklistedSvIds == config.blacklistedSvIds &&
+ emergencyExtensionSeconds == config.emergencyExtensionSeconds) {
+ return true;
+ }
+ return false;
+ }
+};
+
+typedef struct {
+ uint32_t size; // set to sizeof
+ bool mValid;
+ Location mLocation;
+ double verticalAccuracyMeters;
+ double speedAccuracyMetersPerSecond;
+ double bearingAccuracyDegrees;
+ timespec mUtcReported;
+} GnssDebugLocation;
+
+typedef struct {
+ uint32_t size; // set to sizeof
+ bool mValid;
+ int64_t timeEstimate;
+ float timeUncertaintyNs;
+ float frequencyUncertaintyNsPerSec;
+} GnssDebugTime;
+
+typedef struct {
+ uint32_t size; // set to sizeof
+ uint32_t svid;
+ GnssSvType constellation;
+ GnssEphemerisType mEphemerisType;
+ GnssEphemerisSource mEphemerisSource;
+ GnssEphemerisHealth mEphemerisHealth;
+ float ephemerisAgeSeconds;
+ bool serverPredictionIsAvailable;
+ float serverPredictionAgeSeconds;
+} GnssDebugSatelliteInfo;
+
+typedef struct {
+ uint32_t size; // set to sizeof
+ GnssDebugLocation mLocation;
+ GnssDebugTime mTime;
+ std::vector<GnssDebugSatelliteInfo> mSatelliteInfo;
+} GnssDebugReport;
+
+typedef uint32_t LeapSecondSysInfoMask;
+typedef enum {
+ // current leap second info is available. This info will only
+ // be available if the leap second change info is not available.
+ //
+ // If leap second change info is avaiable, to figure out
+ // the current leap second info, compare current gps time with
+ // the gps timestamp of leap second change to know whether to choose
+ // leapSecondBefore or leapSecondAfter as current leap second.
+ LEAP_SECOND_SYS_INFO_CURRENT_LEAP_SECONDS_BIT = (1ULL << 0),
+ // the last known leap change event is available.
+ // The info can be available on two scenario:
+ // 1: this leap second change event has been scheduled and yet to happen
+ // 2: this leap second change event has already happened and next
+ // leap second change event has not yet been scheduled.
+ LEAP_SECOND_SYS_INFO_LEAP_SECOND_CHANGE_BIT = (1ULL << 1),
+} LeapSecondSysInfoDataBits;
+
+struct LeapSecondChangeInfo {
+ // GPS timestamp that corrresponds to the last known
+ // leap second change event.
+ //
+ // The info can be available on two scenario:
+ // 1: this leap second change event has been scheduled and yet to happen
+ // 2: this leap second change event has already happened and next
+ // leap second change event has not yet been scheduled.
+ GnssSystemTimeStructType gpsTimestampLsChange;
+ // Number of leap seconds prior to the leap second change event
+ // that corresponds to the timestamp at gpsTimestampLsChange.
+ uint8_t leapSecondsBeforeChange;
+ // Number of leap seconds after the leap second change event
+ // that corresponds to the timestamp at gpsTimestampLsChange.
+ uint8_t leapSecondsAfterChange;
+};
+
+struct LeapSecondSystemInfo {
+ LeapSecondSysInfoMask leapSecondInfoMask;
+ uint8_t leapSecondCurrent;
+ LeapSecondChangeInfo leapSecondChangeInfo;
+};
+
+typedef uint32_t LocationSystemInfoMask;
+typedef enum {
+ // contains current leap second or leap second change info
+ LOCATION_SYS_INFO_LEAP_SECOND = (1ULL << 0),
+} LocationSystemInfoDataBits;
+
+struct LocationSystemInfo {
+ LocationSystemInfoMask systemInfoMask;
+ LeapSecondSystemInfo leapSecondSysInfo;
+};
+
+/* 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(
+ uint32_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(
+ uint32_t count, // number of locations in array
+ Location* location, // array of locations
+ BatchingOptions batchingOptions // Batching options
+)> batchingCallback;
+
+typedef std::function<void(
+ BatchingStatusInfo batchingStatus, // batch status
+ std::list<uint32_t> & listOfCompletedTrips
+)> batchingStatusCallback;
+
+/* 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;
+
+/* Gives default combined location information from all engines and
+ location information individually from selected engines.
+ This callback is only used when there are multiple engines
+ running in the system.
+
+ optional can be NULL
+
+ engineLocationsInfoCallback is called only during a tracking session
+ broadcasted to all clients, no matter if a session has started by client */
+typedef std::function<void(
+ uint32_t count,
+ GnssLocationInfoNotification* engineLocationInfoNotification
+)> engineLocationsInfoCallback;
+
+/* 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 data, optional can be NULL
+ gnssDataCallback is called only during a tracking session
+ broadcasted to all clients, no matter if a session has started by client */
+typedef std::function<void(
+ GnssDataNotification gnssDataNotification
+)> gnssDataCallback;
+
+/* 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;
+
+/* Provides the current GNSS configuration to the client */
+typedef std::function<void(
+ GnssConfig& config
+)> gnssConfigCallback;
+
+/* LocationSystemInfoCb is for receiving rare occuring location
+ system information update. optional, can be NULL.
+*/
+typedef std::function<void(
+ LocationSystemInfo locationSystemInfo
+)> locationSystemInfoCallback;
+
+typedef std::function<void(
+)> locationApiDestroyCompleteCallback;
+
+typedef uint16_t LocationAdapterTypeMask;
+typedef enum {
+ LOCATION_ADAPTER_GNSS_TYPE_BIT = (1<<0), // adapter type is GNSS
+ LOCATION_ADAPTER_BATCHING_TYPE_BIT = (1<<1), // adapter type is BATCHING
+ LOCATION_ADAPTER_GEOFENCE_TYPE_BIT = (1<<2) // adapter type is geo fence
+} LocationAdapterTypeBits;
+
+typedef struct {
+ uint32_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
+ gnssDataCallback gnssDataCb; // optional
+ gnssMeasurementsCallback gnssMeasurementsCb; // optional
+ batchingStatusCallback batchingStatusCb; // optional
+ locationSystemInfoCallback locationSystemInfoCb; // optional
+ engineLocationsInfoCallback engineLocationsInfoCb; // optional
+} LocationCallbacks;
+
+#endif /* LOCATIONDATATYPES_H */
diff --git a/location/Makefile.am b/location/Makefile.am
new file mode 100644
index 0000000..fccdf94
--- /dev/null
+++ b/location/Makefile.am
@@ -0,0 +1,40 @@
+ACLOCAL_AMFLAGS = -I m4
+
+AM_CFLAGS = \
+ -I./ \
+ -I../utils \
+ $(LOCPLA_CFLAGS) \
+ $(GPSUTILS_CFLAGS) \
+ -std=c++11
+
+liblocation_api_la_SOURCES = \
+ LocationAPI.cpp \
+ LocationAPIClientBase.cpp
+
+if USE_GLIB
+liblocation_api_la_CFLAGS = -DUSE_GLIB $(AM_CFLAGS) @GLIB_CFLAGS@
+liblocation_api_la_LDFLAGS = -lstdc++ -Wl,-z,defs -lpthread @GLIB_LIBS@ -shared -version-info 1:0:0
+liblocation_api_la_CPPFLAGS = -DUSE_GLIB $(AM_CFLAGS) $(AM_CPPFLAGS) @GLIB_CFLAGS@
+else
+liblocation_api_la_CFLAGS = $(AM_CFLAGS)
+liblocation_api_la_LDFLAGS = -Wl,-z,defs -lpthread -shared -version-info 1:0:0
+liblocation_api_la_CPPFLAGS = $(AM_CFLAGS) $(AM_CPPFLAGS)
+endif
+
+liblocation_api_la_LIBADD = -lstdc++ -ldl $(GPSUTILS_LIBS)
+
+library_include_HEADERS = \
+ LocationAPI.h \
+ LocationAPIClientBase.h \
+ location_interface.h \
+ LocationDataTypes.h \
+ ILocationAPI.h
+
+#Create and Install libraries
+lib_LTLIBRARIES = liblocation_api.la
+
+library_includedir = $(pkgincludedir)
+
+pkgconfigdir = $(libdir)/pkgconfig
+pkgconfig_DATA = location-api.pc
+EXTRA_DIST = $(pkgconfig_DATA)
diff --git a/location/configure.ac b/location/configure.ac
new file mode 100644
index 0000000..6391d65
--- /dev/null
+++ b/location/configure.ac
@@ -0,0 +1,82 @@
+# configure.ac -- Autoconf script for gps location-api-iface
+#
+# Process this file with autoconf to produce a configure script
+
+# Requires autoconf tool later than 2.61
+AC_PREREQ(2.61)
+# Initialize the gps location-api-iface package version 1.0.0
+AC_INIT([location-api-iface],1.0.0)
+# Does not strictly follow GNU Coding standards
+AM_INIT_AUTOMAKE([foreign])
+# Disables auto rebuilding of configure, Makefile.ins
+AM_MAINTAINER_MODE
+# Verifies the --srcdir is correct by checking for the path
+AC_CONFIG_SRCDIR([location-api.pc.in])
+# defines some macros variable to be included by source
+AC_CONFIG_HEADERS([config.h])
+AC_CONFIG_MACRO_DIR([m4])
+
+# Checks for programs.
+AC_PROG_LIBTOOL
+AC_PROG_CXX
+AC_PROG_CC
+AM_PROG_CC_C_O
+AC_PROG_AWK
+AC_PROG_CPP
+AC_PROG_INSTALL
+AC_PROG_LN_S
+AC_PROG_MAKE_SET
+PKG_PROG_PKG_CONFIG
+
+# Checks for libraries.
+PKG_CHECK_MODULES([GPSUTILS], [gps-utils])
+AC_SUBST([GPSUTILS_CFLAGS])
+AC_SUBST([GPSUTILS_LIBS])
+
+AC_ARG_WITH([core_includes],
+ AC_HELP_STRING([--with-core-includes=@<:@dir@:>@],
+ [Specify the location of the core headers]),
+ [core_incdir=$withval],
+ with_core_includes=no)
+
+if test "x$with_core_includes" != "xno"; then
+ CPPFLAGS="${CPPFLAGS} -I${core_incdir}"
+fi
+
+AC_ARG_WITH([locpla_includes],
+ AC_HELP_STRING([--with-locpla-includes=@<:@dir@:>@],
+ [Specify the path to locpla-includes in loc-pla_git.bb]),
+ [locpla_incdir=$withval],
+ with_locpla_includes=no)
+
+if test "x${with_locpla_includes}" != "xno"; then
+ AC_SUBST(LOCPLA_CFLAGS, "-I${locpla_incdir}")
+fi
+
+AC_SUBST([CPPFLAGS])
+
+AC_ARG_WITH([glib],
+ AC_HELP_STRING([--with-glib],
+ [enable glib, building HLOS systems which use glib]))
+
+if (test "x${with_glib}" = "xyes"); then
+ AC_DEFINE(ENABLE_USEGLIB, 1, [Define if HLOS systems uses glib])
+ PKG_CHECK_MODULES(GTHREAD, gthread-2.0 >= 2.16, dummy=yes,
+ AC_MSG_ERROR(GThread >= 2.16 is required))
+ PKG_CHECK_MODULES(GLIB, glib-2.0 >= 2.16, dummy=yes,
+ AC_MSG_ERROR(GLib >= 2.16 is required))
+ GLIB_CFLAGS="$GLIB_CFLAGS $GTHREAD_CFLAGS"
+ GLIB_LIBS="$GLIB_LIBS $GTHREAD_LIBS"
+
+ AC_SUBST(GLIB_CFLAGS)
+ AC_SUBST(GLIB_LIBS)
+fi
+
+AM_CONDITIONAL(USE_GLIB, test "x${with_glib}" = "xyes")
+
+AC_CONFIG_FILES([ \
+ Makefile \
+ location-api.pc \
+ ])
+
+AC_OUTPUT
diff --git a/location/location-api.pc.in b/location/location-api.pc.in
new file mode 100644
index 0000000..c7b146a
--- /dev/null
+++ b/location/location-api.pc.in
@@ -0,0 +1,10 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+
+Name: location-api
+Description: Location API
+Version: @VERSION
+Libs: -L${libdir} -llocation_api
+Cflags: -I${includedir}/location-api
diff --git a/location/location_interface.h b/location/location_interface.h
new file mode 100644
index 0000000..fb15bea
--- /dev/null
+++ b/location/location_interface.h
@@ -0,0 +1,121 @@
+/* Copyright (c) 2017-2019 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>
+#include <gps_extended_c.h>
+
+/* Used for callback to deliver GNSS energy consumed */
+/** @fn
+ @brief Used by query API that retrieves energy consumed by
+ modem GNSS engine.
+
+ @param gnssEnergyConsumedFromFirstBoot:
+ Energy consumed by the GNSS engine since the first bootup
+ in units of 0.1 milli watt seconds.
+ A value of 0xffffffffffffffff indicates an invalid reading.
+*/
+typedef std::function<void(
+ uint64_t gnssEnergyConsumedFromFirstBoot
+)> GnssEnergyConsumedCallback;
+
+typedef void (*removeClientCompleteCallback)(LocationAPI* client);
+
+struct GnssInterface {
+ size_t size;
+ void (*initialize)(void);
+ void (*deinitialize)(void);
+ void (*addClient)(LocationAPI* client, const LocationCallbacks& callbacks);
+ void (*removeClient)(LocationAPI* client, removeClientCompleteCallback rmClientCb);
+ void (*requestCapabilities)(LocationAPI* client);
+ uint32_t (*startTracking)(LocationAPI* client, TrackingOptions&);
+ void (*updateTrackingOptions)(LocationAPI* client, uint32_t id, TrackingOptions&);
+ 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* (*gnssGetConfig)(GnssConfigFlagsMask config);
+ void (*gnssUpdateSvTypeConfig)(GnssSvTypeConfig& config);
+ void (*gnssGetSvTypeConfig)(GnssSvTypeConfigCallback& callback);
+ void (*gnssResetSvTypeConfig)();
+ uint32_t (*gnssDeleteAidingData)(GnssAidingData& data);
+ void (*gnssUpdateXtraThrottle)(const bool enabled);
+ void (*injectLocation)(double latitude, double longitude, float accuracy);
+ void (*injectTime)(int64_t time, int64_t timeReference, int32_t uncertainty);
+ void (*agpsInit)(const AgpsCbInfo& cbInfo);
+ void (*agpsDataConnOpen)(AGpsExtType agpsType, const char* apnName, int apnLen, int ipType);
+ void (*agpsDataConnClosed)(AGpsExtType agpsType);
+ void (*agpsDataConnFailed)(AGpsExtType agpsType);
+ void (*getDebugReport)(GnssDebugReport& report);
+ void (*updateConnectionStatus)(bool connected, int8_t type, bool roaming,
+ NetworkHandle networkHandle);
+ void (*odcpiInit)(const OdcpiRequestCallback& callback);
+ void (*odcpiInject)(const Location& location);
+ void (*blockCPI)(double latitude, double longitude, float accuracy,
+ int blockDurationMsec, double latLonDiffThreshold);
+ void (*getGnssEnergyConsumed)(GnssEnergyConsumedCallback energyConsumedCb);
+ void (*enableNfwLocationAccess)(bool enable);
+ void (*nfwInit)(const NfwCbInfo& cbInfo);
+ void (*getPowerStateChanges)(void* powerStateCb);
+ void (*injectLocationExt)(const GnssLocationInfoNotification &locationInfo);
+ void (*updateBatteryStatus)(bool charging);
+};
+
+struct BatchingInterface {
+ size_t size;
+ void (*initialize)(void);
+ void (*deinitialize)(void);
+ void (*addClient)(LocationAPI* client, const LocationCallbacks& callbacks);
+ void (*removeClient)(LocationAPI* client, removeClientCompleteCallback rmClientCb);
+ void (*requestCapabilities)(LocationAPI* client);
+ uint32_t (*startBatching)(LocationAPI* client, BatchingOptions&);
+ void (*stopBatching)(LocationAPI* client, uint32_t id);
+ void (*updateBatchingOptions)(LocationAPI* client, uint32_t id, BatchingOptions&);
+ void (*getBatchedLocations)(LocationAPI* client, uint32_t id, size_t count);
+};
+
+struct GeofenceInterface {
+ size_t size;
+ void (*initialize)(void);
+ void (*deinitialize)(void);
+ void (*addClient)(LocationAPI* client, const LocationCallbacks& callbacks);
+ void (*removeClient)(LocationAPI* client, removeClientCompleteCallback rmClientCb);
+ 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 */
diff --git a/pla/Android.mk b/pla/Android.mk
new file mode 100644
index 0000000..a57861d
--- /dev/null
+++ b/pla/Android.mk
@@ -0,0 +1,29 @@
+GNSS_CFLAGS := \
+ -Werror \
+ -Wno-error=unused-parameter \
+ -Wno-error=macro-redefined \
+ -Wno-error=reorder \
+ -Wno-error=missing-braces \
+ -Wno-error=self-assign \
+ -Wno-error=enum-conversion \
+ -Wno-error=logical-op-parentheses \
+ -Wno-error=null-arithmetic \
+ -Wno-error=null-conversion \
+ -Wno-error=parentheses-equality \
+ -Wno-error=undefined-bool-conversion \
+ -Wno-error=tautological-compare \
+ -Wno-error=switch \
+ -Wno-error=date-time
+
+ifneq ($(BOARD_VENDOR_QCOM_GPS_LOC_API_HARDWARE),)
+ifneq ($(BUILD_TINY_ANDROID),true)
+
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := libloc_pla_headers
+LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/android
+include $(BUILD_HEADER_LIBRARY)
+
+endif # not BUILD_TINY_ANDROID
+endif # BOARD_VENDOR_QCOM_GPS_LOC_API_HARDWARE
diff --git a/pla/android/loc_pla.h b/pla/android/loc_pla.h
new file mode 100644
index 0000000..6104bfb
--- /dev/null
+++ b/pla/android/loc_pla.h
@@ -0,0 +1,66 @@
+/* Copyright (c) 2014, 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 __LOC_PLA__
+#define __LOC_PLA__
+
+#ifdef __cplusplus
+#include <utils/SystemClock.h>
+#define uptimeMillis android::uptimeMillis
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <cutils/properties.h>
+#include <cutils/threads.h>
+#include <cutils/sched_policy.h>
+#include <cutils/android_filesystem_config.h>
+#include <string.h>
+#include <stdlib.h>
+
+#define UID_GPS (AID_GPS)
+#define GID_GPS (AID_GPS)
+#define UID_LOCCLIENT (4021)
+#define GID_LOCCLIENT (4021)
+
+#define LOC_PATH_GPS_CONF_STR "/vendor/etc/gps.conf"
+#define LOC_PATH_IZAT_CONF_STR "/vendor/etc/izat.conf"
+#define LOC_PATH_FLP_CONF_STR "/vendor/etc/flp.conf"
+#define LOC_PATH_LOWI_CONF_STR "/vendor/etc/lowi.conf"
+#define LOC_PATH_SAP_CONF_STR "/vendor/etc/sap.conf"
+#define LOC_PATH_APDR_CONF_STR "/vendor/etc/apdr.conf"
+#define LOC_PATH_XTWIFI_CONF_STR "/vendor/etc/xtwifi.conf"
+#define LOC_PATH_QUIPC_CONF_STR "/vendor/etc/quipc.conf"
+
+#ifdef __cplusplus
+}
+#endif /*__cplusplus */
+
+#endif /* __LOC_PLA__ */
diff --git a/pla/oe/loc_pla.h b/pla/oe/loc_pla.h
new file mode 100644
index 0000000..e795a23
--- /dev/null
+++ b/pla/oe/loc_pla.h
@@ -0,0 +1,100 @@
+/* Copyright (c) 2014, 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 __LOC_PLA__
+#define __LOC_PLA__
+
+#ifdef __cplusplus
+#ifndef FEATURE_EXTERNAL_AP
+#include <utils/SystemClock.h>
+#endif /* FEATURE_EXTERNAL_AP */
+#include <inttypes.h>
+#include <sys/time.h>
+#include <time.h>
+
+inline int64_t uptimeMillis()
+{
+ struct timespec ts;
+ int64_t time_ms = 0;
+ clock_gettime(CLOCK_BOOTTIME, &ts);
+ time_ms += (ts.tv_sec * 1000000000LL);
+ time_ms += ts.tv_nsec + 500000LL;
+ return time_ms / 1000000LL;
+}
+
+extern "C" {
+#endif
+
+#ifndef FEATURE_EXTERNAL_AP
+#include <cutils/properties.h>
+#include <cutils/threads.h>
+#include <cutils/sched_policy.h>
+#endif /* FEATURE_EXTERNAL_AP */
+#include <pthread.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <string.h>
+#include <stdlib.h>
+#ifndef OFF_TARGET
+#include <glib.h>
+#define strlcat g_strlcat
+#define strlcpy g_strlcpy
+#else
+#define strlcat strncat
+#define strlcpy strncpy
+#endif
+
+#define UID_GPS (1021)
+#define GID_GPS (1021)
+#define UID_LOCCLIENT (4021)
+#define GID_LOCCLIENT (4021)
+
+#define LOC_PATH_GPS_CONF_STR "/etc/gps.conf"
+#define LOC_PATH_IZAT_CONF_STR "/etc/izat.conf"
+#define LOC_PATH_FLP_CONF_STR "/etc/flp.conf"
+#define LOC_PATH_LOWI_CONF_STR "/etc/lowi.conf"
+#define LOC_PATH_SAP_CONF_STR "/etc/sap.conf"
+#define LOC_PATH_APDR_CONF_STR "/etc/apdr.conf"
+#define LOC_PATH_XTWIFI_CONF_STR "/etc/xtwifi.conf"
+#define LOC_PATH_QUIPC_CONF_STR "/etc/quipc.conf"
+
+#ifdef FEATURE_EXTERNAL_AP
+#define PROPERTY_VALUE_MAX 92
+
+inline int property_get(const char* key, char* value, const char* default_value)
+{
+ strlcpy(value, default_value, PROPERTY_VALUE_MAX - 1);
+ return strlen(value);
+}
+#endif /* FEATURE_EXTERNAL_AP */
+
+#ifdef __cplusplus
+}
+#endif /*__cplusplus */
+
+#endif /* __LOC_PLA__ */
diff --git a/utils/Android.mk b/utils/Android.mk
new file mode 100644
index 0000000..3887696
--- /dev/null
+++ b/utils/Android.mk
@@ -0,0 +1,65 @@
+ifneq ($(BOARD_VENDOR_QCOM_GPS_LOC_API_HARDWARE),)
+ifneq ($(BUILD_TINY_ANDROID),true)
+#Compile this library only for builds with the latest modem image
+
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+
+
+## Libs
+LOCAL_SHARED_LIBRARIES := \
+ libdl \
+ libutils \
+ libcutils \
+ liblog \
+ libprocessgroup
+
+LOCAL_SRC_FILES += \
+ loc_log.cpp \
+ loc_cfg.cpp \
+ msg_q.c \
+ linked_list.c \
+ loc_target.cpp \
+ LocHeap.cpp \
+ LocTimer.cpp \
+ LocThread.cpp \
+ MsgTask.cpp \
+ loc_misc_utils.cpp \
+ loc_nmea.cpp \
+ LocIpc.cpp
+
+# Flag -std=c++11 is not accepted by compiler when LOCAL_CLANG is set to true
+LOCAL_CFLAGS += \
+ -fno-short-enums \
+ -D_ANDROID_
+
+ifeq ($(TARGET_BUILD_VARIANT),user)
+ LOCAL_CFLAGS += -DTARGET_BUILD_VARIANT_USER
+endif
+
+LOCAL_LDFLAGS += -Wl,--export-dynamic
+
+## Includes
+LOCAL_HEADER_LIBRARIES := \
+ libutils_headers \
+ libloc_pla_headers \
+ liblocation_api_headers
+
+LOCAL_MODULE := libgps.utils
+LOCAL_VENDOR_MODULE := true
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_PRELINK_MODULE := false
+
+LOCAL_CFLAGS += $(GNSS_CFLAGS)
+
+include $(BUILD_SHARED_LIBRARY)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := libgps.utils_headers
+LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)
+include $(BUILD_HEADER_LIBRARY)
+
+endif # not BUILD_TINY_ANDROID
+endif # BOARD_VENDOR_QCOM_GPS_LOC_API_HARDWARE
diff --git a/utils/LocHeap.cpp b/utils/LocHeap.cpp
new file mode 100644
index 0000000..d667f14
--- /dev/null
+++ b/utils/LocHeap.cpp
@@ -0,0 +1,354 @@
+/* Copyright (c) 2015, 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.
+ *
+ */
+#include <LocHeap.h>
+
+class LocHeapNode {
+ friend class LocHeap;
+
+ // size of of the subtree, excluding self, 1 if no subtree
+ int mSize;
+ LocHeapNode* mLeft;
+ LocHeapNode* mRight;
+ LocRankable* mData;
+public:
+ inline LocHeapNode(LocRankable& data) :
+ mSize(1), mLeft(NULL), mRight(NULL), mData(&data) {}
+ ~LocHeapNode();
+
+ // this only swaps the data of the two nodes, so no
+ // detach / re-attached is necessary
+ void swap(LocHeapNode& node);
+
+ LocRankable* detachData();
+
+ // push a node into the tree stucture, keeping sorted by rank
+ void push(LocHeapNode& node);
+
+ // pop the head node out of the tree stucture. keeping sorted by rank
+ static LocHeapNode* pop(LocHeapNode*& top);
+
+ // remove a specific node from the tree
+ // returns the pointer to the node removed, which would be either the
+ // same as input (if successfully removed); or NULL (if failed).
+ static LocHeapNode* remove(LocHeapNode*& top, LocRankable& data);
+
+ // convenience method to compare data ranking
+ inline bool outRanks(LocHeapNode& node) { return mData->outRanks(*node.mData); }
+ inline bool outRanks(LocRankable& data) { return mData->outRanks(data); }
+
+ // checks if mSize is correct, AND this node is the highest ranking
+ // of the entire subtree
+ bool checkNodes();
+
+ inline int getSize() { return mSize; }
+};
+
+inline
+LocHeapNode::~LocHeapNode() {
+ if (mLeft) {
+ delete mLeft;
+ mLeft = NULL;
+ }
+ if (mRight) {
+ delete mRight;
+ mRight = NULL;
+ }
+ if (mData) {
+ mData = NULL;
+ }
+}
+
+inline
+void LocHeapNode::swap(LocHeapNode& node) {
+ LocRankable* tmpData = node.mData;
+ node.mData = mData;
+ mData = tmpData;
+}
+
+inline
+LocRankable* LocHeapNode::detachData() {
+ LocRankable* data = mData;
+ mData = NULL;
+ return data;
+}
+
+// push keeps the tree sorted by rank, it also tries to balance the
+// tree by adding the new node to the smaller of the subtrees.
+// The pointer to the tree and internal links never change. If the
+// mData of tree top ranks lower than that of the incoming node,
+// mData will be swapped with that of the incoming node to ensure
+// ranking, no restructuring the container nodes.
+void LocHeapNode::push(LocHeapNode& node) {
+ // ensure the current node ranks higher than in the incoming one
+ if (node.outRanks(*this)) {
+ swap(node);
+ }
+
+ // now drop the new node (ensured lower than *this) into a subtree
+ if (NULL == mLeft) {
+ mLeft = &node;
+ } else if (NULL == mRight) {
+ mRight = &node;
+ } else if (mLeft->mSize <= mRight->mSize) {
+ mLeft->push(node);
+ } else {
+ mRight->push(node);
+ }
+ mSize++;
+}
+
+// pop keeps the tree sorted by rank, but it does not try to balance
+// the tree. It recursively swaps with the higher ranked top of the
+// subtrees.
+// The return is a popped out node from leaf level, that has the data
+// swapped all the way down from the top. The pinter to the tree and
+// internal links will not be changed or restructured, except for the
+// node that is popped out.
+// If the return pointer == this, this the last node in the tree.
+LocHeapNode* LocHeapNode::pop(LocHeapNode*& top) {
+ // we know the top has the highest ranking at this point, else
+ // the tree is broken. This top will be popped out. But we need
+ // a node from the left or right child, whichever ranks higher,
+ // to replace the current top. This then will need to be done
+ // recursively to the leaf level. So we swap the mData of the
+ // current top node all the way down to the leaf level.
+ LocHeapNode* poppedNode = top;
+ // top is losing a node in its subtree
+ top->mSize--;
+ if (top->mLeft || top->mRight) {
+ // if mLeft is NULL, mRight for sure is NOT NULL, take that;
+ // else if mRight is NULL, mLeft for sure is NOT, take that;
+ // else we take the address of whatever has higher ranking mData
+ LocHeapNode*& subTop = (NULL == top->mLeft) ? top->mRight :
+ ((NULL == top->mRight) ? top->mLeft :
+ (top->mLeft->outRanks(*(top->mRight)) ? top->mLeft : top->mRight));
+ // swap mData, the tree top gets updated with the new data.
+ top->swap(*subTop);
+ // pop out from the subtree
+ poppedNode = pop(subTop);
+ } else {
+ // if the top has only single node
+ // detach the poppedNode from the tree
+ // subTop is the reference of ether mLeft or mRight
+ // NOT a local stack pointer. so it MUST be NULL'ed here.
+ top = NULL;
+ }
+
+ return poppedNode;
+}
+
+// navigating through the tree and find the node that hass the input
+// data. Since this is a heap, we do recursive linear search.
+// returns the pointer to the node removed, which would be either the
+// same as input (if successfully removed); or NULL (if failed).
+LocHeapNode* LocHeapNode::remove(LocHeapNode*& top, LocRankable& data) {
+ LocHeapNode* removedNode = NULL;
+ // this is the node, by address
+ if (&data == (LocRankable*)(top->mData)) {
+ // pop this node out
+ removedNode = pop(top);
+ } else if (!data.outRanks(*top->mData)) {
+ // subtrees might have this node
+ if (top->mLeft) {
+ removedNode = remove(top->mLeft, data);
+ }
+ // if we did not find in mLeft, and mRight is not empty
+ if (!removedNode && top->mRight) {
+ removedNode = remove(top->mRight, data);
+ }
+
+ // top lost a node in its subtree
+ if (removedNode) {
+ top->mSize--;
+ }
+ }
+
+ return removedNode;
+}
+
+// checks if mSize is correct, AND this node is the highest ranking
+// of the entire subtree
+bool LocHeapNode::checkNodes() {
+ // size of the current subtree
+ int totalSize = mSize;
+ if (mLeft) {
+ // check the consistency of left subtree
+ if (mLeft->outRanks(*this) || !mLeft->checkNodes()) {
+ return false;
+ }
+ // subtract the size of left subtree (with subtree head)
+ totalSize -= mLeft->mSize;
+ }
+
+ if (mRight) {
+ // check the consistency of right subtree
+ if (mRight->outRanks(*this) || !mRight->checkNodes()) {
+ return false;
+ }
+ // subtract the size of right subtree (with subtree head)
+ totalSize -= mRight->mSize;
+ }
+
+ // for the tree nodes to consistent, totalSize must be 1 now
+ return totalSize == 1;
+}
+
+LocHeap::~LocHeap() {
+ if (mTree) {
+ delete mTree;
+ }
+}
+
+void LocHeap::push(LocRankable& node) {
+ LocHeapNode* heapNode = new LocHeapNode(node);
+ if (!mTree) {
+ mTree = heapNode;
+ } else {
+ mTree->push(*heapNode);
+ }
+}
+
+LocRankable* LocHeap::peek() {
+ LocRankable* top = NULL;
+ if (mTree) {
+ top = mTree->mData;
+ }
+ return top;
+}
+
+LocRankable* LocHeap::pop() {
+ LocRankable* locNode = NULL;
+ if (mTree) {
+ // mTree may become NULL after this call
+ LocHeapNode* heapNode = LocHeapNode::pop(mTree);
+ locNode = heapNode->detachData();
+ delete heapNode;
+ }
+ return locNode;
+}
+
+LocRankable* LocHeap::remove(LocRankable& rankable) {
+ LocRankable* locNode = NULL;
+ if (mTree) {
+ // mTree may become NULL after this call
+ LocHeapNode* heapNode = LocHeapNode::remove(mTree, rankable);
+ if (heapNode) {
+ locNode = heapNode->detachData();
+ delete heapNode;
+ }
+ }
+ return locNode;
+}
+
+#ifdef __LOC_UNIT_TEST__
+bool LocHeap::checkTree() {
+ return ((NULL == mTree) || mTree->checkNodes());
+}
+uint32_t LocHeap::getTreeSize() {
+ return (NULL == mTree) ? 0 : mTree->getSize();
+}
+#endif
+
+#ifdef __LOC_DEBUG__
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <time.h>
+
+class LocHeapDebug : public LocHeap {
+public:
+ bool checkTree() {
+ return ((NULL == mTree) || mTree->checkNodes());
+ }
+
+ uint32_t getTreeSize() {
+ return (NULL == mTree) ? 0 : (mTree->getSize());
+ }
+};
+
+class LocHeapDebugData : public LocRankable {
+ const int mID;
+public:
+ LocHeapDebugData(int id) : mID(id) {}
+ inline virtual int ranks(LocRankable& rankable) {
+ LocHeapDebugData* testData = dynamic_cast<LocHeapDebugData*>(&rankable);
+ return testData->mID - mID;
+ }
+};
+
+// For Linux command line testing:
+// compilation: g++ -D__LOC_HOST_DEBUG__ -D__LOC_DEBUG__ -g -I. -I../../../../vendor/qcom/proprietary/gps-internal/unit-tests/fakes_for_host -I../../../../system/core/include LocHeap.cpp
+// test: valgrind --leak-check=full ./a.out 100
+int main(int argc, char** argv) {
+ srand(time(NULL));
+ int tries = atoi(argv[1]);
+ int checks = tries >> 3;
+ LocHeapDebug heap;
+ int treeSize = 0;
+
+ for (int i = 0; i < tries; i++) {
+ if (i % checks == 0 && !heap.checkTree()) {
+ printf("tree check failed before %dth op\n", i);
+ }
+ int r = rand();
+
+ if (r & 1) {
+ LocHeapDebugData* data = new LocHeapDebugData(r >> 1);
+ heap.push(dynamic_cast<LocRankable&>(*data));
+ treeSize++;
+ } else {
+ LocRankable* rankable = heap.pop();
+ if (rankable) {
+ delete rankable;
+ }
+ treeSize ? treeSize-- : 0;
+ }
+
+ printf("%s: %d == %d\n", (r&1)?"push":"pop", treeSize, heap.getTreeSize());
+ if (treeSize != heap.getTreeSize()) {
+ printf("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n");
+ tries = i+1;
+ break;
+ }
+ }
+
+ if (!heap.checkTree()) {
+ printf("!!!!!!!!!!tree check failed at the end after %d ops!!!!!!!\n", tries);
+ } else {
+ printf("success!\n");
+ }
+
+ for (LocRankable* data = heap.pop(); NULL != data; data = heap.pop()) {
+ delete data;
+ }
+
+ return 0;
+}
+
+#endif
diff --git a/utils/LocHeap.h b/utils/LocHeap.h
new file mode 100644
index 0000000..b491948
--- /dev/null
+++ b/utils/LocHeap.h
@@ -0,0 +1,96 @@
+/* Copyright (c) 2015, 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 __LOC_HEAP__
+#define __LOC_HEAP__
+
+#include <stddef.h>
+#include <string.h>
+
+// abstract class to be implemented by client to provide a rankable class
+class LocRankable {
+public:
+ virtual inline ~LocRankable() {}
+
+ // method to rank objects of such type for sorting purposes.
+ // The pointer of the input node would be stored in the heap.
+ // >0 if ranks higher than the input;
+ // ==0 if equally ranks with the input;
+ // <0 if ranks lower than the input
+ virtual int ranks(LocRankable& rankable) = 0;
+
+ // convenient method to rank objects of such type for sorting purposes.
+ inline bool outRanks(LocRankable& rankable) { return ranks(rankable) > 0; }
+};
+
+// opaque class to provide service implementation.
+class LocHeapNode;
+
+// a heap whose left and right children are not sorted. It is sorted only vertically,
+// i.e. parent always ranks higher than children, if they exist. Ranking algorithm is
+// implemented in Rankable. The reason that there is no sort between children is to
+// help beter balance the tree with lower cost. When a node is pushed to the tree,
+// it is guaranteed that the subtree that is smaller gets to have the new node.
+class LocHeap {
+protected:
+ LocHeapNode* mTree;
+public:
+ inline LocHeap() : mTree(NULL) {}
+ ~LocHeap();
+
+ // push keeps the tree sorted by rank, it also tries to balance the
+ // tree by adding the new node to the smaller of the subtrees.
+ // node is reference to an obj that is managed by client, that client
+ // creates and destroyes. The destroy should happen after the
+ // node is popped out from the heap.
+ void push(LocRankable& node);
+
+ // Peeks the node data on tree top, which has currently the highest ranking
+ // There is no change the tree structure with this operation
+ // Returns NULL if the tree is empty, otherwise pointer to the node data of
+ // the tree top.
+ LocRankable* peek();
+
+ // pop keeps the tree sorted by rank, but it does not try to balance
+ // the tree.
+ // Return - pointer to the node popped out, or NULL if heap is already empty
+ LocRankable* pop();
+
+ // navigating through the tree and find the node that ranks the same
+ // as the input data, then remove it from the tree. Rank is implemented
+ // by rankable obj.
+ // returns the pointer to the node removed; or NULL (if failed).
+ LocRankable* remove(LocRankable& rankable);
+
+#ifdef __LOC_UNIT_TEST__
+ bool checkTree();
+ uint32_t getTreeSize();
+#endif
+};
+
+#endif //__LOC_HEAP__
diff --git a/utils/LocIpc.cpp b/utils/LocIpc.cpp
new file mode 100644
index 0000000..e9dbe9d
--- /dev/null
+++ b/utils/LocIpc.cpp
@@ -0,0 +1,414 @@
+/* Copyright (c) 2017-2018 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.
+ *
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <netinet/in.h>
+#include <netdb.h>
+#include <loc_misc_utils.h>
+#include <log_util.h>
+#include <LocIpc.h>
+#include <algorithm>
+
+using namespace std;
+
+namespace loc_util {
+
+#ifdef LOG_TAG
+#undef LOG_TAG
+#endif
+#define LOG_TAG "LocSvc_LocIpc"
+
+#define SOCK_OP_AND_LOG(buf, length, opable, rtv, exe) \
+ if (nullptr == (buf) || 0 == (length)) { \
+ LOC_LOGe("Invalid inputs: buf - %p, length - %u", (buf), (length)); \
+ } else if (!(opable)) { \
+ LOC_LOGe("Invalid object: operable - %d", (opable)); \
+ } else { \
+ rtv = (exe); \
+ if (-1 == rtv) { \
+ LOC_LOGw("failed reason: %s", strerror(errno)); \
+ } \
+ }
+
+const char Sock::MSG_ABORT[] = "LocIpc::Sock::ABORT";
+const char Sock::LOC_IPC_HEAD[] = "$MSGLEN$";
+ssize_t Sock::send(const void *buf, uint32_t len, int flags, const struct sockaddr *destAddr,
+ socklen_t addrlen) const {
+ ssize_t rtv = -1;
+ SOCK_OP_AND_LOG(buf, len, isValid(), rtv, sendto(buf, len, flags, destAddr, addrlen));
+ return rtv;
+}
+ssize_t Sock::recv(const LocIpcRecver& recver, const shared_ptr<ILocIpcListener>& dataCb, int flags,
+ struct sockaddr *srcAddr, socklen_t *addrlen, int sid) const {
+ ssize_t rtv = -1;
+ if (-1 == sid) {
+ sid = mSid;
+ } // else it sid would be connection based socket id for recv
+ SOCK_OP_AND_LOG(dataCb.get(), mMaxTxSize, isValid(), rtv,
+ recvfrom(recver, dataCb, sid, flags, srcAddr, addrlen));
+ return rtv;
+}
+ssize_t Sock::sendto(const void *buf, size_t len, int flags, const struct sockaddr *destAddr,
+ socklen_t addrlen) const {
+ ssize_t rtv = -1;
+ if (len <= mMaxTxSize) {
+ rtv = ::sendto(mSid, buf, len, flags, destAddr, addrlen);
+ } else {
+ std::string head(LOC_IPC_HEAD + to_string(len));
+ rtv = ::sendto(mSid, head.c_str(), head.length(), flags, destAddr, addrlen);
+ if (rtv > 0) {
+ for (size_t offset = 0; offset < len && rtv > 0; offset += rtv) {
+ rtv = ::sendto(mSid, (char*)buf + offset, min(len - offset, (size_t)mMaxTxSize),
+ flags, destAddr, addrlen);
+ }
+ rtv = (rtv > 0) ? (head.length() + len) : -1;
+ }
+ }
+ return rtv;
+}
+ssize_t Sock::recvfrom(const LocIpcRecver& recver, const shared_ptr<ILocIpcListener>& dataCb,
+ int sid, int flags, struct sockaddr *srcAddr, socklen_t *addrlen) const {
+ std::string msg(mMaxTxSize, 0);
+ ssize_t nBytes = ::recvfrom(sid, (void*)msg.data(), msg.size(), flags, srcAddr, addrlen);
+ if (nBytes > 0) {
+ if (strncmp(msg.data(), MSG_ABORT, sizeof(MSG_ABORT)) == 0) {
+ LOC_LOGi("recvd abort msg.data %s", msg.data());
+ nBytes = 0;
+ } else if (strncmp(msg.data(), LOC_IPC_HEAD, sizeof(LOC_IPC_HEAD) - 1)) {
+ // short message
+ msg.resize(nBytes);
+ dataCb->onReceive(msg.data(), nBytes, &recver);
+ } else {
+ // long message
+ size_t msgLen = 0;
+ sscanf(msg.data() + sizeof(LOC_IPC_HEAD) - 1, "%zu", &msgLen);
+ msg.resize(msgLen);
+ for (size_t msgLenReceived = 0; (msgLenReceived < msgLen) && (nBytes > 0);
+ msgLenReceived += nBytes) {
+ nBytes = ::recvfrom(sid, &(msg[msgLenReceived]), msg.size() - msgLenReceived,
+ flags, srcAddr, addrlen);
+ }
+ if (nBytes > 0) {
+ nBytes = msgLen;
+ dataCb->onReceive(msg.data(), nBytes, &recver);
+ }
+ }
+ }
+
+ return nBytes;
+}
+ssize_t Sock::sendAbort(int flags, const struct sockaddr *destAddr, socklen_t addrlen) {
+ return send(MSG_ABORT, sizeof(MSG_ABORT), flags, destAddr, addrlen);
+}
+
+class LocIpcLocalSender : public LocIpcSender {
+protected:
+ shared_ptr<Sock> mSock;
+ struct sockaddr_un mAddr;
+ inline virtual bool isOperable() const override { return mSock != nullptr && mSock->isValid(); }
+ inline virtual ssize_t send(const uint8_t data[], uint32_t length, int32_t /* msgId */) const {
+ return mSock->send(data, length, 0, (struct sockaddr*)&mAddr, sizeof(mAddr));
+ }
+public:
+ inline LocIpcLocalSender(const char* name) : LocIpcSender(),
+ mSock(make_shared<Sock>((nullptr == name) ? -1 : (::socket(AF_UNIX, SOCK_DGRAM, 0)))),
+ mAddr({.sun_family = AF_UNIX, {}}) {
+ if (mSock != nullptr && mSock->isValid()) {
+ snprintf(mAddr.sun_path, sizeof(mAddr.sun_path), "%s", name);
+ }
+ }
+};
+
+class LocIpcLocalRecver : public LocIpcLocalSender, public LocIpcRecver {
+protected:
+ inline virtual ssize_t recv() const override {
+ socklen_t size = sizeof(mAddr);
+ return mSock->recv(*this, mDataCb, 0, (struct sockaddr*)&mAddr, &size);
+ }
+public:
+ inline LocIpcLocalRecver(const shared_ptr<ILocIpcListener>& listener, const char* name) :
+ LocIpcLocalSender(name), LocIpcRecver(listener, *this) {
+
+ if ((unlink(mAddr.sun_path) < 0) && (errno != ENOENT)) {
+ LOC_LOGw("unlink socket error. reason:%s", strerror(errno));
+ }
+
+ umask(0157);
+ if (mSock->isValid() && ::bind(mSock->mSid, (struct sockaddr*)&mAddr, sizeof(mAddr)) < 0) {
+ LOC_LOGe("bind socket error. sock fd: %d: %s, reason: %s", mSock->mSid,
+ mAddr.sun_path, strerror(errno));
+ mSock->close();
+ }
+ }
+ inline virtual ~LocIpcLocalRecver() { unlink(mAddr.sun_path); }
+ inline virtual const char* getName() const override { return mAddr.sun_path; };
+ inline virtual void abort() const override {
+ if (isSendable()) {
+ mSock->sendAbort(0, (struct sockaddr*)&mAddr, sizeof(mAddr));
+ }
+ }
+};
+
+class LocIpcInetSender : public LocIpcSender {
+protected:
+ int mSockType;
+ shared_ptr<Sock> mSock;
+ const string mName;
+ sockaddr_in mAddr;
+ inline virtual bool isOperable() const override { return mSock != nullptr && mSock->isValid(); }
+ virtual ssize_t send(const uint8_t data[], uint32_t length, int32_t /* msgId */) const {
+ return mSock->send(data, length, 0, (struct sockaddr*)&mAddr, sizeof(mAddr));
+ }
+public:
+ inline LocIpcInetSender(const LocIpcInetSender& sender) :
+ mSockType(sender.mSockType), mSock(sender.mSock),
+ mName(sender.mName), mAddr(sender.mAddr) {
+ }
+ inline LocIpcInetSender(const char* name, int32_t port, int sockType) : LocIpcSender(),
+ mSockType(sockType),
+ mSock(make_shared<Sock>((nullptr == name) ? -1 : (::socket(AF_INET, mSockType, 0)))),
+ mName((nullptr == name) ? "" : name),
+ mAddr({.sin_family = AF_INET, .sin_port = htons(port),
+ .sin_addr = {htonl(INADDR_ANY)}}) {
+ if (mSock != nullptr && mSock->isValid() && nullptr != name) {
+ struct hostent* hp = gethostbyname(name);
+ if (nullptr != hp) {
+ memcpy((char*)&(mAddr.sin_addr.s_addr), hp->h_addr_list[0], hp->h_length);
+ }
+ }
+ }
+
+ unique_ptr<LocIpcRecver> getRecver(const shared_ptr<ILocIpcListener>& listener) override {
+ return make_unique<SockRecver>(listener, *this, mSock);
+ }
+};
+
+class LocIpcInetTcpSender : public LocIpcInetSender {
+protected:
+ mutable bool mFirstTime;
+
+ virtual ssize_t send(const uint8_t data[], uint32_t length, int32_t /* msgId */) const {
+ if (mFirstTime) {
+ mFirstTime = false;
+ ::connect(mSock->mSid, (const struct sockaddr*)&mAddr, sizeof(mAddr));
+ }
+ return mSock->send(data, length, 0, (struct sockaddr*)&mAddr, sizeof(mAddr));
+ }
+
+public:
+ inline LocIpcInetTcpSender(const char* name, int32_t port) :
+ LocIpcInetSender(name, port, SOCK_STREAM),
+ mFirstTime(true) {}
+};
+
+class LocIpcInetRecver : public LocIpcInetSender, public LocIpcRecver {
+ int32_t mPort;
+protected:
+ virtual ssize_t recv() const = 0;
+public:
+ inline LocIpcInetRecver(const shared_ptr<ILocIpcListener>& listener, const char* name,
+ int32_t port, int sockType) :
+ LocIpcInetSender(name, port, sockType), LocIpcRecver(listener, *this),
+ mPort(port) {
+ if (mSock->isValid() && ::bind(mSock->mSid, (struct sockaddr*)&mAddr, sizeof(mAddr)) < 0) {
+ LOC_LOGe("bind socket error. sock fd: %d, reason: %s", mSock->mSid, strerror(errno));
+ mSock->close();
+ }
+ }
+ inline virtual ~LocIpcInetRecver() {}
+ inline virtual const char* getName() const override { return mName.data(); };
+ inline virtual void abort() const override {
+ if (isSendable()) {
+ sockaddr_in loopBackAddr = {.sin_family = AF_INET, .sin_port = htons(mPort),
+ .sin_addr = {htonl(INADDR_LOOPBACK)}};
+ mSock->sendAbort(0, (struct sockaddr*)&loopBackAddr, sizeof(loopBackAddr));
+ }
+ }
+ inline virtual unique_ptr<LocIpcSender> getLastSender() const override {
+ return make_unique<LocIpcInetSender>(static_cast<const LocIpcInetSender&>(*this));
+ }
+};
+
+class LocIpcInetTcpRecver : public LocIpcInetRecver {
+ mutable int32_t mConnFd;
+protected:
+ inline virtual ssize_t recv() const override {
+ socklen_t size = sizeof(mAddr);
+ if (-1 == mConnFd && mSock->isValid()) {
+ if (::listen(mSock->mSid, 3) < 0 ||
+ (mConnFd = accept(mSock->mSid, (struct sockaddr*)&mAddr, &size)) < 0) {
+ mSock->close();
+ mConnFd = -1;
+ }
+ }
+ return mSock->recv(*this, mDataCb, 0, (struct sockaddr*)&mAddr, &size, mConnFd);
+ }
+public:
+ inline LocIpcInetTcpRecver(const shared_ptr<ILocIpcListener>& listener, const char* name,
+ int32_t port) :
+ LocIpcInetRecver(listener, name, port, SOCK_STREAM), mConnFd(-1) {}
+ inline virtual ~LocIpcInetTcpRecver() { if (-1 != mConnFd) ::close(mConnFd);}
+};
+
+class LocIpcInetUdpRecver : public LocIpcInetRecver {
+protected:
+ inline virtual ssize_t recv() const override {
+ socklen_t size = sizeof(mAddr);
+ return mSock->recv(*this, mDataCb, 0, (struct sockaddr*)&mAddr, &size);
+ }
+public:
+ inline LocIpcInetUdpRecver(const shared_ptr<ILocIpcListener>& listener, const char* name,
+ int32_t port) :
+ LocIpcInetRecver(listener, name, port, SOCK_DGRAM) {}
+
+ inline virtual ~LocIpcInetUdpRecver() {}
+};
+
+class LocIpcRunnable : public LocRunnable {
+ bool mAbortCalled;
+ LocIpc& mLocIpc;
+ unique_ptr<LocIpcRecver> mIpcRecver;
+public:
+ inline LocIpcRunnable(LocIpc& locIpc, unique_ptr<LocIpcRecver>& ipcRecver) :
+ mAbortCalled(false),
+ mLocIpc(locIpc),
+ mIpcRecver(move(ipcRecver)) {}
+ inline bool run() override {
+ if (mIpcRecver != nullptr) {
+ mLocIpc.startBlockingListening(*(mIpcRecver.get()));
+ if (!mAbortCalled) {
+ LOC_LOGw("startListeningBlocking() returned w/o stopBlockingListening() called");
+ }
+ }
+ // return false so the calling thread exits while loop
+ return false;
+ }
+ inline void abort() {
+ mAbortCalled = true;
+ if (mIpcRecver != nullptr) {
+ mIpcRecver->abort();
+ }
+ }
+};
+
+bool LocIpc::startNonBlockingListening(unique_ptr<LocIpcRecver>& ipcRecver) {
+ if (ipcRecver != nullptr && ipcRecver->isRecvable()) {
+ std::string threadName("LocIpc-");
+ threadName.append(ipcRecver->getName());
+ mRunnable = new LocIpcRunnable(*this, ipcRecver);
+ return mThread.start(threadName.c_str(), mRunnable);
+ } else {
+ LOC_LOGe("ipcRecver is null OR ipcRecver->recvable() is fasle");
+ return false;
+ }
+}
+
+bool LocIpc::startBlockingListening(LocIpcRecver& ipcRecver) {
+ if (ipcRecver.isRecvable()) {
+ // inform that the socket is ready to receive message
+ ipcRecver.onListenerReady();
+ while (ipcRecver.recvData());
+ return true;
+ } else {
+ LOC_LOGe("ipcRecver is null OR ipcRecver->recvable() is fasle");
+ return false;
+ }
+}
+
+void LocIpc::stopNonBlockingListening() {
+ if (mRunnable) {
+ mRunnable->abort();
+ mRunnable = nullptr;
+ }
+}
+
+void LocIpc::stopBlockingListening(LocIpcRecver& ipcRecver) {
+ if (ipcRecver.isRecvable()) {
+ ipcRecver.abort();
+ }
+}
+
+bool LocIpc::send(LocIpcSender& sender, const uint8_t data[], uint32_t length, int32_t msgId) {
+ return sender.sendData(data, length, msgId);
+}
+
+shared_ptr<LocIpcSender> LocIpc::getLocIpcLocalSender(const char* localSockName) {
+ return make_shared<LocIpcLocalSender>(localSockName);
+}
+unique_ptr<LocIpcRecver> LocIpc::getLocIpcLocalRecver(const shared_ptr<ILocIpcListener>& listener,
+ const char* localSockName) {
+ return make_unique<LocIpcLocalRecver>(listener, localSockName);
+}
+static void* sLibQrtrHandle = nullptr;
+static const char* sLibQrtrName = "libloc_socket.so";
+shared_ptr<LocIpcSender> LocIpc::getLocIpcQrtrSender(int service, int instance) {
+ typedef shared_ptr<LocIpcSender> (*creator_t) (int, int);
+ static creator_t creator = (creator_t)dlGetSymFromLib(sLibQrtrHandle, sLibQrtrName,
+ "_ZN8loc_util22createLocIpcQrtrSenderEii");
+ return (nullptr == creator) ? nullptr : creator(service, instance);
+}
+unique_ptr<LocIpcRecver> LocIpc::getLocIpcQrtrRecver(const shared_ptr<ILocIpcListener>& listener,
+ int service, int instance) {
+ typedef unique_ptr<LocIpcRecver> (*creator_t)(const shared_ptr<ILocIpcListener>&, int, int);
+ static creator_t creator = (creator_t)dlGetSymFromLib(sLibQrtrHandle, sLibQrtrName,
+#ifdef USE_GLIB
+ "_ZN8loc_util22createLocIpcQrtrRecverERKSt10shared_ptrINS_15ILocIpcListenerEEii");
+#else
+ "_ZN8loc_util22createLocIpcQrtrRecverERKNSt3__110shared_ptrINS_15ILocIpcListenerEEEii");
+#endif
+ return (nullptr == creator) ? nullptr : creator(listener, service, instance);
+}
+shared_ptr<LocIpcSender> LocIpc::getLocIpcInetTcpSender(const char* serverName, int32_t port) {
+ return make_shared<LocIpcInetTcpSender>(serverName, port);
+}
+unique_ptr<LocIpcRecver> LocIpc::getLocIpcInetTcpRecver(const shared_ptr<ILocIpcListener>& listener,
+ const char* serverName, int32_t port) {
+ return make_unique<LocIpcInetTcpRecver>(listener, serverName, port);
+}
+shared_ptr<LocIpcSender> LocIpc::getLocIpcInetUdpSender(const char* serverName, int32_t port) {
+ return make_shared<LocIpcInetSender>(serverName, port, SOCK_DGRAM);
+}
+unique_ptr<LocIpcRecver> LocIpc::getLocIpcInetUdpRecver(const shared_ptr<ILocIpcListener>& listener,
+ const char* serverName, int32_t port) {
+ return make_unique<LocIpcInetUdpRecver>(listener, serverName, port);
+}
+pair<shared_ptr<LocIpcSender>, unique_ptr<LocIpcRecver>>
+ LocIpc::getLocIpcQmiLocServiceSenderRecverPair(const shared_ptr<ILocIpcListener>& listener, int instance) {
+ typedef pair<shared_ptr<LocIpcSender>, unique_ptr<LocIpcRecver>> (*creator_t)(const shared_ptr<ILocIpcListener>&, int);
+ static void* sLibEmuHandle = nullptr;
+ static creator_t creator = (creator_t)dlGetSymFromLib(sLibEmuHandle, "libloc_emu.so",
+ "_ZN13QmiLocService41createLocIpcQmiLocServiceSenderRecverPairERKNSt3__110shared_ptrIN8loc_util15ILocIpcListenerEEEi");
+ return (nullptr == creator) ?
+ make_pair<shared_ptr<LocIpcSender>, unique_ptr<LocIpcRecver>>(nullptr, nullptr) :
+ creator(listener, instance);
+}
+
+}
diff --git a/utils/LocIpc.h b/utils/LocIpc.h
new file mode 100644
index 0000000..d6f8d1d
--- /dev/null
+++ b/utils/LocIpc.h
@@ -0,0 +1,206 @@
+/* Copyright (c) 2017-2018 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 __LOC_IPC__
+#define __LOC_IPC__
+
+#include <string>
+#include <memory>
+#include <unistd.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <LocThread.h>
+
+using namespace std;
+
+namespace loc_util {
+
+
+class LocIpcRecver;
+class LocIpcSender;
+class LocIpcRunnable;
+
+class ILocIpcListener {
+protected:
+ inline virtual ~ILocIpcListener() {}
+public:
+ // LocIpc client can overwrite this function to get notification
+ // when the socket for LocIpc is ready to receive messages.
+ inline virtual void onListenerReady() {}
+ virtual void onReceive(const char* data, uint32_t len, const LocIpcRecver* recver) = 0;
+};
+
+
+class LocIpc {
+public:
+ inline LocIpc() : mRunnable(nullptr) {}
+ inline virtual ~LocIpc() {
+ stopNonBlockingListening();
+ }
+
+ static shared_ptr<LocIpcSender>
+ getLocIpcLocalSender(const char* localSockName);
+ static shared_ptr<LocIpcSender>
+ getLocIpcInetUdpSender(const char* serverName, int32_t port);
+ static shared_ptr<LocIpcSender>
+ getLocIpcInetTcpSender(const char* serverName, int32_t port);
+ static shared_ptr<LocIpcSender>
+ getLocIpcQrtrSender(int service, int instance);
+
+ static unique_ptr<LocIpcRecver>
+ getLocIpcLocalRecver(const shared_ptr<ILocIpcListener>& listener,
+ const char* localSockName);
+ static unique_ptr<LocIpcRecver>
+ getLocIpcInetUdpRecver(const shared_ptr<ILocIpcListener>& listener,
+ const char* serverName, int32_t port);
+ static unique_ptr<LocIpcRecver>
+ getLocIpcInetTcpRecver(const shared_ptr<ILocIpcListener>& listener,
+ const char* serverName, int32_t port);
+ static unique_ptr<LocIpcRecver>
+ getLocIpcQrtrRecver(const shared_ptr<ILocIpcListener>& listener,
+ int service, int instance);
+
+ static pair<shared_ptr<LocIpcSender>, unique_ptr<LocIpcRecver>>
+ getLocIpcQmiLocServiceSenderRecverPair(const shared_ptr<ILocIpcListener>& listener,
+ int instance);
+
+ // Listen for new messages in current thread. Calling this funciton will
+ // block current thread.
+ // The listening can be stopped by calling stopBlockingListening() passing
+ // in the same ipcRecver obj handle.
+ static bool startBlockingListening(LocIpcRecver& ipcRecver);
+ static void stopBlockingListening(LocIpcRecver& ipcRecver);
+
+ // Create a new LocThread and listen for new messages in it.
+ // Calling this function will return immediately and won't block current thread.
+ // The listening can be stopped by calling stopNonBlockingListening().
+ bool startNonBlockingListening(unique_ptr<LocIpcRecver>& ipcRecver);
+ void stopNonBlockingListening();
+
+ // Send out a message.
+ // Call this function to send a message in argument data to socket in argument name.
+ //
+ // Argument name contains the name of the target unix socket. data contains the
+ // message to be sent out. Convert your message to a string before calling this function.
+ // The function will return true on success, and false on failure.
+ static bool send(LocIpcSender& sender, const uint8_t data[],
+ uint32_t length, int32_t msgId = -1);
+
+private:
+ LocThread mThread;
+ LocIpcRunnable *mRunnable;
+};
+
+/* this is only when client needs to implement Sender / Recver that are not already provided by
+ the factor methods prvoided by LocIpc. */
+
+class LocIpcSender {
+protected:
+ LocIpcSender() = default;
+ virtual bool isOperable() const = 0;
+ virtual ssize_t send(const uint8_t data[], uint32_t length, int32_t msgId) const = 0;
+public:
+ virtual ~LocIpcSender() = default;
+ virtual void informRecverRestarted() {}
+ inline bool isSendable() const { return isOperable(); }
+ inline bool sendData(const uint8_t data[], uint32_t length, int32_t msgId) const {
+ return isSendable() && (send(data, length, msgId) > 0);
+ }
+ virtual unique_ptr<LocIpcRecver> getRecver(const shared_ptr<ILocIpcListener>& listener) {
+ return nullptr;
+ }
+};
+
+class LocIpcRecver {
+ LocIpcSender& mIpcSender;
+protected:
+ const shared_ptr<ILocIpcListener> mDataCb;
+ inline LocIpcRecver(const shared_ptr<ILocIpcListener>& listener, LocIpcSender& sender) :
+ mIpcSender(sender), mDataCb(listener) {}
+ LocIpcRecver(LocIpcRecver const& recver) = delete;
+ LocIpcRecver& operator=(LocIpcRecver const& recver) = delete;
+ virtual ssize_t recv() const = 0;
+public:
+ virtual ~LocIpcRecver() = default;
+ inline bool recvData() const { return isRecvable() && (recv() > 0); }
+ inline bool isRecvable() const { return mDataCb != nullptr && mIpcSender.isSendable(); }
+ virtual void onListenerReady() { if (mDataCb != nullptr) mDataCb->onListenerReady(); }
+ inline virtual unique_ptr<LocIpcSender> getLastSender() const {
+ return nullptr;
+ }
+ virtual void abort() const = 0;
+ virtual const char* getName() const = 0;
+};
+
+class Sock {
+ static const char MSG_ABORT[];
+ static const char LOC_IPC_HEAD[];
+ const uint32_t mMaxTxSize;
+ ssize_t sendto(const void *buf, size_t len, int flags, const struct sockaddr *destAddr,
+ socklen_t addrlen) const;
+ ssize_t recvfrom(const LocIpcRecver& recver, const shared_ptr<ILocIpcListener>& dataCb,
+ int sid, int flags, struct sockaddr *srcAddr, socklen_t *addrlen) const;
+public:
+ int mSid;
+ inline Sock(int sid, const uint32_t maxTxSize = 8192) : mMaxTxSize(maxTxSize), mSid(sid) {}
+ inline ~Sock() { close(); }
+ inline bool isValid() const { return -1 != mSid; }
+ ssize_t send(const void *buf, uint32_t len, int flags, const struct sockaddr *destAddr,
+ socklen_t addrlen) const;
+ ssize_t recv(const LocIpcRecver& recver, const shared_ptr<ILocIpcListener>& dataCb, int flags,
+ struct sockaddr *srcAddr, socklen_t *addrlen, int sid = -1) const;
+ ssize_t sendAbort(int flags, const struct sockaddr *destAddr, socklen_t addrlen);
+ inline void close() {
+ if (isValid()) {
+ ::close(mSid);
+ mSid = -1;
+ }
+ }
+};
+
+class SockRecver : public LocIpcRecver {
+ shared_ptr<Sock> mSock;
+protected:
+ inline virtual ssize_t recv() const override {
+ return mSock->recv(*this, mDataCb, 0, nullptr, nullptr);
+ }
+public:
+ inline SockRecver(const shared_ptr<ILocIpcListener>& listener,
+ LocIpcSender& sender, shared_ptr<Sock> sock) :
+ LocIpcRecver(listener, sender), mSock(sock) {
+ }
+ inline virtual const char* getName() const override {
+ return "SockRecver";
+ }
+ inline virtual void abort() const override {}
+};
+
+}
+
+#endif //__LOC_IPC__
diff --git a/utils/LocSharedLock.h b/utils/LocSharedLock.h
new file mode 100644
index 0000000..a7af35e
--- /dev/null
+++ b/utils/LocSharedLock.h
@@ -0,0 +1,77 @@
+/* Copyright (c) 2015, 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 __LOC_SHARED_LOCK__
+#define __LOC_SHARED_LOCK__
+
+#include <stddef.h>
+#ifndef FEATURE_EXTERNAL_AP
+#include <cutils/atomic.h>
+#endif /* FEATURE_EXTERNAL_AP */
+#include <pthread.h>
+
+#ifdef FEATURE_EXTERNAL_AP
+#include <atomic>
+
+inline int32_t android_atomic_inc(volatile int32_t *addr)
+{
+ volatile std::atomic_int_least32_t* a = (volatile std::atomic_int_least32_t*)addr;
+ return std::atomic_fetch_add_explicit(a, 1, std::memory_order_release);
+}
+
+inline int32_t android_atomic_dec(volatile int32_t *addr)
+{
+ volatile std::atomic_int_least32_t* a = (volatile std::atomic_int_least32_t*)addr;
+ return std::atomic_fetch_sub_explicit(a, 1, std::memory_order_release);
+}
+
+#endif /* FEATURE_EXTERNAL_AP */
+ // This is a utility created for use cases such that there are more than
+// one client who need to share the same lock, but it is not predictable
+// which of these clients is to last to go away. This shared lock deletes
+// itself when the last client calls its drop() method. To add a cient,
+// this share lock's share() method has to be called, so that the obj
+// can maintain an accurate client count.
+class LocSharedLock {
+ volatile int32_t mRef;
+ pthread_mutex_t mMutex;
+ inline ~LocSharedLock() { pthread_mutex_destroy(&mMutex); }
+public:
+ // first client to create this LockSharedLock
+ inline LocSharedLock() : mRef(1) { pthread_mutex_init(&mMutex, NULL); }
+ // following client(s) are to *share()* this lock created by the first client
+ inline LocSharedLock* share() { android_atomic_inc(&mRef); return this; }
+ // whe a client no longer needs this shared lock, drop() shall be called.
+ inline void drop() { if (1 == android_atomic_dec(&mRef)) delete this; }
+ // locking the lock to enter critical section
+ inline void lock() { pthread_mutex_lock(&mMutex); }
+ // unlocking the lock to leave the critical section
+ inline void unlock() { pthread_mutex_unlock(&mMutex); }
+};
+
+#endif //__LOC_SHARED_LOCK__
diff --git a/utils/LocThread.cpp b/utils/LocThread.cpp
new file mode 100644
index 0000000..568a6bb
--- /dev/null
+++ b/utils/LocThread.cpp
@@ -0,0 +1,266 @@
+/* Copyright (c) 2015, 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.
+ *
+ */
+#include <LocThread.h>
+#include <string.h>
+#include <pthread.h>
+#include <loc_pla.h>
+
+class LocThreadDelegate {
+ LocRunnable* mRunnable;
+ bool mJoinable;
+ pthread_t mThandle;
+ pthread_mutex_t mMutex;
+ int mRefCount;
+ ~LocThreadDelegate();
+ LocThreadDelegate(LocThread::tCreate creator, const char* threadName,
+ LocRunnable* runnable, bool joinable);
+ void destroy();
+public:
+ static LocThreadDelegate* create(LocThread::tCreate creator,
+ const char* threadName, LocRunnable* runnable, bool joinable);
+ void stop();
+ // bye() is for the parent thread to go away. if joinable,
+ // parent must stop the spawned thread, join, and then
+ // destroy(); if detached, the parent can go straight
+ // ahead to destroy()
+ inline void bye() { mJoinable ? stop() : destroy(); }
+ inline bool isRunning() { return (NULL != mRunnable); }
+ static void* threadMain(void* arg);
+};
+
+// it is important to note that internal members must be
+// initialized to values as if pthread_create succeeds.
+// This is to avoid the race condition between the threads,
+// once the thread is created, some of these values will
+// be check in the spawned thread, and must set correctly
+// then and there.
+// However, upon pthread_create failure, the data members
+// must be set to indicate failure, e.g. mRunnable, and
+// threashold approprietly for destroy(), e.g. mRefCount.
+LocThreadDelegate::LocThreadDelegate(LocThread::tCreate creator,
+ const char* threadName, LocRunnable* runnable, bool joinable) :
+ mRunnable(runnable), mJoinable(joinable), mThandle((pthread_t)NULL),
+ mMutex(PTHREAD_MUTEX_INITIALIZER), mRefCount(2) {
+
+ // set up thread name, if nothing is passed in
+ if (!threadName) {
+ threadName = "LocThread";
+ }
+
+ // create the thread here, then if successful
+ // and a name is given, we set the thread name
+ if (creator) {
+ mThandle = creator(threadName, threadMain, this);
+ } else if (pthread_create(&mThandle, NULL, threadMain, this)) {
+ // pthread_create() failed
+ mThandle = (pthread_t)NULL;
+ }
+
+ if (mThandle) {
+ // set thread name
+ char lname[16];
+ int len = (sizeof(lname) > (strlen(threadName) + 1)) ?
+ (strlen(threadName)):(sizeof(lname) - 1);
+ memcpy(lname, threadName, len);
+ lname[len] = 0;
+ // set the thread name here
+ pthread_setname_np(mThandle, lname);
+
+ // detach, if not joinable
+ if (!joinable) {
+ pthread_detach(mThandle);
+ }
+ } else {
+ // must set these values upon failure
+ mRunnable = NULL;
+ mJoinable = false;
+ mRefCount = 1;
+ }
+}
+
+inline
+LocThreadDelegate::~LocThreadDelegate() {
+ // at this point nothing should need done any more
+}
+
+// factory method so that we could return NULL upon failure
+LocThreadDelegate* LocThreadDelegate::create(LocThread::tCreate creator,
+ const char* threadName, LocRunnable* runnable, bool joinable) {
+ LocThreadDelegate* thread = NULL;
+ if (runnable) {
+ thread = new LocThreadDelegate(creator, threadName, runnable, joinable);
+ if (thread && !thread->isRunning()) {
+ thread->destroy();
+ thread = NULL;
+ }
+ }
+
+ return thread;
+}
+
+// The order is importang
+// NULLing mRunnalbe stops the while loop in threadMain()
+// join() if mJoinble must come before destroy() call, as
+// the obj must remain alive at this time so that mThandle
+// remains valud.
+void LocThreadDelegate::stop() {
+ // mRunnable and mJoinable are reset on different triggers.
+ // mRunnable may get nulled on the spawned thread's way out;
+ // or here.
+ // mJouinable (if ever been true) gets falsed when client
+ // thread triggers stop, with either a stop()
+ // call or the client releases thread obj handle.
+ if (mRunnable) {
+ mRunnable = NULL;
+ }
+ if (mJoinable) {
+ mJoinable = false;
+ pthread_join(mThandle, NULL);
+ }
+ // call destroy() to possibly delete the obj
+ destroy();
+}
+
+// method for clients to call to release the obj
+// when it is a detached thread, the client thread
+// and the spawned thread can both try to destroy()
+// asynchronously. And we delete this obj when
+// mRefCount becomes 0.
+void LocThreadDelegate::destroy() {
+ // else case shouldn't happen, unless there is a
+ // leaking obj. But only our code here has such
+ // obj, so if we test our code well, else case
+ // will never happen
+ if (mRefCount > 0) {
+ // we need a flag on the stack
+ bool callDelete = false;
+
+ // critical section between threads
+ pthread_mutex_lock(&mMutex);
+ // last destroy() call
+ callDelete = (1 == mRefCount--);
+ pthread_mutex_unlock(&mMutex);
+
+ // upon last destroy() call we delete this obj
+ if (callDelete) {
+ delete this;
+ }
+ }
+}
+
+void* LocThreadDelegate::threadMain(void* arg) {
+ LocThreadDelegate* locThread = (LocThreadDelegate*)(arg);
+
+ if (locThread) {
+ LocRunnable* runnable = locThread->mRunnable;
+
+ if (runnable) {
+ if (locThread->isRunning()) {
+ runnable->prerun();
+ }
+
+ while (locThread->isRunning() && runnable->run());
+
+ if (locThread->isRunning()) {
+ runnable->postrun();
+ }
+
+ // at this time, locThread->mRunnable may or may not be NULL
+ // NULL it just to be safe and clean, as we want the field
+ // in the released memory slot to be NULL.
+ locThread->mRunnable = NULL;
+ delete runnable;
+ }
+ locThread->destroy();
+ }
+
+ return NULL;
+}
+
+LocThread::~LocThread() {
+ if (mThread) {
+ mThread->bye();
+ mThread = NULL;
+ }
+}
+
+bool LocThread::start(tCreate creator, const char* threadName, LocRunnable* runnable, bool joinable) {
+ bool success = false;
+ if (!mThread) {
+ mThread = LocThreadDelegate::create(creator, threadName, runnable, joinable);
+ // true only if thread is created successfully
+ success = (NULL != mThread);
+ }
+ return success;
+}
+
+void LocThread::stop() {
+ if (mThread) {
+ mThread->stop();
+ mThread = NULL;
+ }
+}
+
+#ifdef __LOC_DEBUG__
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+class LocRunnableTest1 : public LocRunnable {
+ int mID;
+public:
+ LocRunnableTest1(int id) : LocRunnable(), mID(id) {}
+ virtual bool run() {
+ printf("LocRunnableTest1: %d\n", mID++);
+ sleep(1);
+ return true;
+ }
+};
+
+// on linux command line:
+// compile: g++ -D__LOC_HOST_DEBUG__ -D__LOC_DEBUG__ -g -std=c++0x -I. -I../../../../vendor/qcom/proprietary/gps-internal/unit-tests/fakes_for_host -I../../../../system/core/include -lpthread LocThread.cpp
+// test detached thread: valgrind ./a.out 0
+// test joinable thread: valgrind ./a.out 1
+int main(int argc, char** argv) {
+ LocRunnableTest1 test(10);
+
+ LocThread thread;
+ thread.start("LocThreadTest", test, atoi(argv[1]));
+
+ sleep(10);
+
+ thread.stop();
+
+ sleep(5);
+
+ return 0;
+}
+
+#endif
diff --git a/utils/LocThread.h b/utils/LocThread.h
new file mode 100644
index 0000000..2a65d8f
--- /dev/null
+++ b/utils/LocThread.h
@@ -0,0 +1,92 @@
+/* Copyright (c) 2015, 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 __LOC_THREAD__
+#define __LOC_THREAD__
+
+#include <stddef.h>
+#include <pthread.h>
+
+// abstract class to be implemented by client to provide a runnable class
+// which gets scheduled by LocThread
+class LocRunnable {
+public:
+ inline LocRunnable() {}
+ inline virtual ~LocRunnable() {}
+
+ // The method to be implemented by thread clients
+ // and be scheduled by LocThread
+ // This method will be repeated called until it returns false; or
+ // until thread is stopped.
+ virtual bool run() = 0;
+
+ // The method to be run before thread loop (conditionally repeatedly)
+ // calls run()
+ inline virtual void prerun() {}
+
+ // The method to be run after thread loop (conditionally repeatedly)
+ // calls run()
+ inline virtual void postrun() {}
+};
+
+// opaque class to provide service implementation.
+class LocThreadDelegate;
+
+// A utility class to create a thread and run LocRunnable
+// caller passes in.
+class LocThread {
+ LocThreadDelegate* mThread;
+public:
+ inline LocThread() : mThread(NULL) {}
+ virtual ~LocThread();
+
+ typedef pthread_t (*tCreate)(const char* name, void* (*start)(void*), void* arg);
+ // client starts thread with a runnable, which implements
+ // the logics to fun in the created thread context.
+ // The thread could be either joinable or detached.
+ // runnable is an obj managed by client. Client creates and
+ // frees it (but must be after stop() is called, or
+ // this LocThread obj is deleted).
+ // The obj will be deleted by LocThread if start()
+ // returns true. Else it is client's responsibility
+ // to delete the object
+ // Returns 0 if success; false if failure.
+ bool start(tCreate creator, const char* threadName, LocRunnable* runnable, bool joinable = true);
+ inline bool start(const char* threadName, LocRunnable* runnable, bool joinable = true) {
+ return start(NULL, threadName, runnable, joinable);
+ }
+
+ // NOTE: if this is a joinable thread, this stop may block
+ // for a while until the thread is joined.
+ void stop();
+
+ // thread status check
+ inline bool isRunning() { return NULL != mThread; }
+};
+
+#endif //__LOC_THREAD__
diff --git a/utils/LocTimer.cpp b/utils/LocTimer.cpp
new file mode 100644
index 0000000..93775d0
--- /dev/null
+++ b/utils/LocTimer.cpp
@@ -0,0 +1,753 @@
+/* Copyright (c) 2015, 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.
+ *
+ */
+
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <time.h>
+#include <errno.h>
+#include <sys/timerfd.h>
+#include <sys/epoll.h>
+#include <log_util.h>
+#include <loc_timer.h>
+#include <LocTimer.h>
+#include <LocHeap.h>
+#include <LocThread.h>
+#include <LocSharedLock.h>
+#include <MsgTask.h>
+
+#ifdef __HOST_UNIT_TEST__
+#define EPOLLWAKEUP 0
+#define CLOCK_BOOTTIME CLOCK_MONOTONIC
+#define CLOCK_BOOTTIME_ALARM CLOCK_MONOTONIC
+#endif
+
+/*
+There are implementations of 5 classes in this file:
+LocTimer, LocTimerDelegate, LocTimerContainer, LocTimerPollTask, LocTimerWrapper
+
+LocTimer - client front end, interface for client to start / stop timers, also
+ to provide a callback.
+LocTimerDelegate - an internal timer entity, which also is a LocRankable obj.
+ Its life cycle is different than that of LocTimer. It gets
+ created when LocTimer::start() is called, and gets deleted
+ when it expires or clients calls the hosting LocTimer obj's
+ stop() method. When a LocTimerDelegate obj is ticking, it
+ stays in the corresponding LocTimerContainer. When expired
+ or stopped, the obj is removed from the container. Since it
+ is also a LocRankable obj, and LocTimerContainer also is a
+ heap, its ranks() implementation decides where it is placed
+ in the heap.
+LocTimerContainer - core of the timer service. It is a container (derived from
+ LocHeap) for LocTimerDelegate (implements LocRankable) objs.
+ There are 2 of such containers, one for sw timers (or Linux
+ timers) one for hw timers (or Linux alarms). It adds one of
+ each (those that expire the soonest) to kernel via services
+ provided by LocTimerPollTask. All the heap management on the
+ LocTimerDelegate objs are done in the MsgTask context, such
+ that synchronization is ensured.
+LocTimerPollTask - is a class that wraps timerfd and epoll POXIS APIs. It also
+ both implements LocRunnalbe with epoll_wait() in the run()
+ method. It is also a LocThread client, so as to loop the run
+ method.
+LocTimerWrapper - a LocTimer client itself, to implement the existing C API with
+ APIs, loc_timer_start() and loc_timer_stop().
+
+*/
+
+class LocTimerPollTask;
+
+// This is a multi-functaional class that:
+// * extends the LocHeap class for the detection of head update upon add / remove
+// events. When that happens, soonest time out changes, so timerfd needs update.
+// * contains the timers, and add / remove them into the heap
+// * provides and maps 2 of such containers, one for timers (or mSwTimers), one
+// for alarms (or mHwTimers);
+// * provides a polling thread;
+// * provides a MsgTask thread for synchronized add / remove / timer client callback.
+class LocTimerContainer : public LocHeap {
+ // mutex to synchronize getters of static members
+ static pthread_mutex_t mMutex;
+ // Container of timers
+ static LocTimerContainer* mSwTimers;
+ // Container of alarms
+ static LocTimerContainer* mHwTimers;
+ // Msg task to provider msg Q, sender and reader.
+ static MsgTask* mMsgTask;
+ // Poll task to provide epoll call and threading to poll.
+ static LocTimerPollTask* mPollTask;
+ // timer / alarm fd
+ int mDevFd;
+ // ctor
+ LocTimerContainer(bool wakeOnExpire);
+ // dtor
+ ~LocTimerContainer();
+ static MsgTask* getMsgTaskLocked();
+ static LocTimerPollTask* getPollTaskLocked();
+ // extend LocHeap and pop if the top outRanks input
+ LocTimerDelegate* popIfOutRanks(LocTimerDelegate& timer);
+ // update the timer POSIX calls with updated soonest timer spec
+ void updateSoonestTime(LocTimerDelegate* priorTop);
+
+public:
+ // factory method to control the creation of mSwTimers / mHwTimers
+ static LocTimerContainer* get(bool wakeOnExpire);
+
+ LocTimerDelegate* getSoonestTimer();
+ int getTimerFd();
+ // add a timer / alarm obj into the container
+ void add(LocTimerDelegate& timer);
+ // remove a timer / alarm obj from the container
+ void remove(LocTimerDelegate& timer);
+ // handling of timer / alarm expiration
+ void expire();
+};
+
+// This class implements the polling thread that epolls imer / alarm fds.
+// The LocRunnable::run() contains the actual polling. The other methods
+// will be run in the caller's thread context to add / remove timer / alarm
+// fds the kernel, while the polling is blocked on epoll_wait() call.
+// Since the design is that we have maximally 2 polls, one for all the
+// timers; one for all the alarms, we will poll at most on 2 fds. But it
+// is possile that all we have are only timers or alarms at one time, so we
+// allow dynamically add / remove fds we poll on. The design decision of
+// having 1 fd per container of timer / alarm is such that, we may not need
+// to make a system call each time a timer / alarm is added / removed, unless
+// that changes the "soonest" time out of that of all the timers / alarms.
+class LocTimerPollTask : public LocRunnable {
+ // the epoll fd
+ const int mFd;
+ // the thread that calls run() method
+ LocThread* mThread;
+ friend class LocThreadDelegate;
+ // dtor
+ ~LocTimerPollTask();
+public:
+ // ctor
+ LocTimerPollTask();
+ // this obj will be deleted once thread is deleted
+ void destroy();
+ // add a container of timers. Each contain has a unique device fd, i.e.
+ // either timer or alarm fd, and a heap of timers / alarms. It is expected
+ // that container would have written to the device fd with the soonest
+ // time out value in the heap at the time of calling this method. So all
+ // this method does is to add the fd of the input container to the poll
+ // and also add the pointer of the container to the event data ptr, such
+ // when poll_wait wakes up on events, we know who is the owner of the fd.
+ void addPoll(LocTimerContainer& timerContainer);
+ // remove a fd that is assciated with a container. The expectation is that
+ // the atual timer would have been removed from the container.
+ void removePoll(LocTimerContainer& timerContainer);
+ // The polling thread context will call this method. This is where
+ // epoll_wait() is blocking and waiting for events..
+ virtual bool run();
+};
+
+// Internal class of timer obj. It gets born when client calls LocTimer::start();
+// and gets deleted when client calls LocTimer::stop() or when the it expire()'s.
+// This class implements LocRankable::ranks() so that when an obj is added into
+// the container (of LocHeap), it gets placed in sorted order.
+class LocTimerDelegate : public LocRankable {
+ friend class LocTimerContainer;
+ friend class LocTimer;
+ LocTimer* mClient;
+ LocSharedLock* mLock;
+ struct timespec mFutureTime;
+ LocTimerContainer* mContainer;
+ // not a complete obj, just ctor for LocRankable comparisons
+ inline LocTimerDelegate(struct timespec& delay)
+ : mClient(NULL), mLock(NULL), mFutureTime(delay), mContainer(NULL) {}
+ inline ~LocTimerDelegate() { if (mLock) { mLock->drop(); mLock = NULL; } }
+public:
+ LocTimerDelegate(LocTimer& client, struct timespec& futureTime, LocTimerContainer* container);
+ void destroyLocked();
+ // LocRankable virtual method
+ virtual int ranks(LocRankable& rankable);
+ void expire();
+ inline struct timespec getFutureTime() { return mFutureTime; }
+};
+
+/***************************LocTimerContainer methods***************************/
+
+// Most of these static recources are created on demand. They however are never
+// destoyed. The theory is that there are processes that link to this util lib
+// but never use timer, then these resources would never need to be created.
+// For those processes that do use timer, it will likely also need to every
+// once in a while. It might be cheaper keeping them around.
+pthread_mutex_t LocTimerContainer::mMutex = PTHREAD_MUTEX_INITIALIZER;
+LocTimerContainer* LocTimerContainer::mSwTimers = NULL;
+LocTimerContainer* LocTimerContainer::mHwTimers = NULL;
+MsgTask* LocTimerContainer::mMsgTask = NULL;
+LocTimerPollTask* LocTimerContainer::mPollTask = NULL;
+
+// ctor - initialize timer heaps
+// A container for swTimer (timer) is created, when wakeOnExpire is true; or
+// HwTimer (alarm), when wakeOnExpire is false.
+LocTimerContainer::LocTimerContainer(bool wakeOnExpire) :
+ mDevFd(timerfd_create(wakeOnExpire ? CLOCK_BOOTTIME_ALARM : CLOCK_BOOTTIME, 0)) {
+
+ if ((-1 == mDevFd) && (errno == EINVAL)) {
+ LOC_LOGW("%s: timerfd_create failure, fallback to CLOCK_MONOTONIC - %s",
+ __FUNCTION__, strerror(errno));
+ mDevFd = timerfd_create(CLOCK_MONOTONIC, 0);
+ }
+
+ if (-1 != mDevFd) {
+ // ensure we have the necessary resources created
+ LocTimerContainer::getPollTaskLocked();
+ LocTimerContainer::getMsgTaskLocked();
+ } else {
+ LOC_LOGE("%s: timerfd_create failure - %s", __FUNCTION__, strerror(errno));
+ }
+}
+
+// dtor
+// we do not ever destroy the static resources.
+inline
+LocTimerContainer::~LocTimerContainer() {
+ close(mDevFd);
+}
+
+LocTimerContainer* LocTimerContainer::get(bool wakeOnExpire) {
+ // get the reference of either mHwTimer or mSwTimers per wakeOnExpire
+ LocTimerContainer*& container = wakeOnExpire ? mHwTimers : mSwTimers;
+ // it is cheap to check pointer first than locking mutext unconditionally
+ if (!container) {
+ pthread_mutex_lock(&mMutex);
+ // let's check one more time to be safe
+ if (!container) {
+ container = new LocTimerContainer(wakeOnExpire);
+ // timerfd_create failure
+ if (-1 == container->getTimerFd()) {
+ delete container;
+ container = NULL;
+ }
+ }
+ pthread_mutex_unlock(&mMutex);
+ }
+ return container;
+}
+
+MsgTask* LocTimerContainer::getMsgTaskLocked() {
+ // it is cheap to check pointer first than locking mutext unconditionally
+ if (!mMsgTask) {
+ mMsgTask = new MsgTask("LocTimerMsgTask", false);
+ }
+ return mMsgTask;
+}
+
+LocTimerPollTask* LocTimerContainer::getPollTaskLocked() {
+ // it is cheap to check pointer first than locking mutext unconditionally
+ if (!mPollTask) {
+ mPollTask = new LocTimerPollTask();
+ }
+ return mPollTask;
+}
+
+inline
+LocTimerDelegate* LocTimerContainer::getSoonestTimer() {
+ return (LocTimerDelegate*)(peek());
+}
+
+inline
+int LocTimerContainer::getTimerFd() {
+ return mDevFd;
+}
+
+void LocTimerContainer::updateSoonestTime(LocTimerDelegate* priorTop) {
+ LocTimerDelegate* curTop = getSoonestTimer();
+
+ // check if top has changed
+ if (curTop != priorTop) {
+ struct itimerspec delay;
+ memset(&delay, 0, sizeof(struct itimerspec));
+ bool toSetTime = false;
+ // if tree is empty now, we remove poll and disarm timer
+ if (!curTop) {
+ mPollTask->removePoll(*this);
+ // setting the values to disarm timer
+ delay.it_value.tv_sec = 0;
+ delay.it_value.tv_nsec = 0;
+ toSetTime = true;
+ } else if (!priorTop || curTop->outRanks(*priorTop)) {
+ // do this first to avoid race condition, in case settime is called
+ // with too small an interval
+ mPollTask->addPoll(*this);
+ delay.it_value = curTop->getFutureTime();
+ toSetTime = true;
+ }
+ if (toSetTime) {
+ timerfd_settime(getTimerFd(), TFD_TIMER_ABSTIME, &delay, NULL);
+ }
+ }
+}
+
+// all the heap management is done in the MsgTask context.
+inline
+void LocTimerContainer::add(LocTimerDelegate& timer) {
+ struct MsgTimerPush : public LocMsg {
+ LocTimerContainer* mTimerContainer;
+ LocHeapNode* mTree;
+ LocTimerDelegate* mTimer;
+ inline MsgTimerPush(LocTimerContainer& container, LocTimerDelegate& timer) :
+ LocMsg(), mTimerContainer(&container), mTimer(&timer) {}
+ inline virtual void proc() const {
+ LocTimerDelegate* priorTop = mTimerContainer->getSoonestTimer();
+ mTimerContainer->push((LocRankable&)(*mTimer));
+ mTimerContainer->updateSoonestTime(priorTop);
+ }
+ };
+
+ mMsgTask->sendMsg(new MsgTimerPush(*this, timer));
+}
+
+// all the heap management is done in the MsgTask context.
+void LocTimerContainer::remove(LocTimerDelegate& timer) {
+ struct MsgTimerRemove : public LocMsg {
+ LocTimerContainer* mTimerContainer;
+ LocTimerDelegate* mTimer;
+ inline MsgTimerRemove(LocTimerContainer& container, LocTimerDelegate& timer) :
+ LocMsg(), mTimerContainer(&container), mTimer(&timer) {}
+ inline virtual void proc() const {
+ LocTimerDelegate* priorTop = mTimerContainer->getSoonestTimer();
+
+ // update soonest timer only if mTimer is actually removed from
+ // mTimerContainer AND mTimer is not priorTop.
+ if (priorTop == ((LocHeap*)mTimerContainer)->remove((LocRankable&)*mTimer)) {
+ // if passing in NULL, we tell updateSoonestTime to update
+ // kernel with the current top timer interval.
+ mTimerContainer->updateSoonestTime(NULL);
+ }
+ // all timers are deleted here, and only here.
+ delete mTimer;
+ }
+ };
+
+ mMsgTask->sendMsg(new MsgTimerRemove(*this, timer));
+}
+
+// all the heap management is done in the MsgTask context.
+// Upon expire, we check and continuously pop the heap until
+// the top node's timeout is in the future.
+void LocTimerContainer::expire() {
+ struct MsgTimerExpire : public LocMsg {
+ LocTimerContainer* mTimerContainer;
+ inline MsgTimerExpire(LocTimerContainer& container) :
+ LocMsg(), mTimerContainer(&container) {}
+ inline virtual void proc() const {
+ struct timespec now;
+ // get time spec of now
+ clock_gettime(CLOCK_BOOTTIME, &now);
+ LocTimerDelegate timerOfNow(now);
+ // pop everything in the heap that outRanks now, i.e. has time older than now
+ // and then call expire() on that timer.
+ for (LocTimerDelegate* timer = (LocTimerDelegate*)mTimerContainer->pop();
+ NULL != timer;
+ timer = mTimerContainer->popIfOutRanks(timerOfNow)) {
+ // the timer delegate obj will be deleted before the return of this call
+ timer->expire();
+ }
+ mTimerContainer->updateSoonestTime(NULL);
+ }
+ };
+
+ struct itimerspec delay;
+ memset(&delay, 0, sizeof(struct itimerspec));
+ timerfd_settime(getTimerFd(), TFD_TIMER_ABSTIME, &delay, NULL);
+ mPollTask->removePoll(*this);
+ mMsgTask->sendMsg(new MsgTimerExpire(*this));
+}
+
+LocTimerDelegate* LocTimerContainer::popIfOutRanks(LocTimerDelegate& timer) {
+ LocTimerDelegate* poppedNode = NULL;
+ if (mTree && !timer.outRanks(*peek())) {
+ poppedNode = (LocTimerDelegate*)(pop());
+ }
+
+ return poppedNode;
+}
+
+
+/***************************LocTimerPollTask methods***************************/
+
+inline
+LocTimerPollTask::LocTimerPollTask()
+ : mFd(epoll_create(2)), mThread(new LocThread()) {
+ // before a next call returens, a thread will be created. The run() method
+ // could already be running in parallel. Also, since each of the objs
+ // creates a thread, the container will make sure that there will be only
+ // one of such obj for our timer implementation.
+ if (!mThread->start("LocTimerPollTask", this)) {
+ delete mThread;
+ mThread = NULL;
+ }
+}
+
+inline
+LocTimerPollTask::~LocTimerPollTask() {
+ // when fs is closed, epoll_wait() should fail run() should return false
+ // and the spawned thread should exit.
+ close(mFd);
+}
+
+void LocTimerPollTask::destroy() {
+ if (mThread) {
+ LocThread* thread = mThread;
+ mThread = NULL;
+ delete thread;
+ } else {
+ delete this;
+ }
+}
+
+void LocTimerPollTask::addPoll(LocTimerContainer& timerContainer) {
+ struct epoll_event ev;
+ memset(&ev, 0, sizeof(ev));
+
+ ev.events = EPOLLIN | EPOLLWAKEUP;
+ ev.data.fd = timerContainer.getTimerFd();
+ // it is important that we set this context pointer with the input
+ // timer container this is how we know which container should handle
+ // which expiration.
+ ev.data.ptr = &timerContainer;
+
+ epoll_ctl(mFd, EPOLL_CTL_ADD, timerContainer.getTimerFd(), &ev);
+}
+
+inline
+void LocTimerPollTask::removePoll(LocTimerContainer& timerContainer) {
+ epoll_ctl(mFd, EPOLL_CTL_DEL, timerContainer.getTimerFd(), NULL);
+}
+
+// The polling thread context will call this method. If run() method needs to
+// be repetitvely called, it must return true from the previous call.
+bool LocTimerPollTask::run() {
+ struct epoll_event ev[2];
+
+ // we have max 2 descriptors to poll from
+ int fds = epoll_wait(mFd, ev, 2, -1);
+
+ // we pretty much want to continually poll until the fd is closed
+ bool rerun = (fds > 0) || (errno == EINTR);
+
+ if (fds > 0) {
+ // we may have 2 events
+ for (int i = 0; i < fds; i++) {
+ // each fd has a context pointer associated with the right timer container
+ LocTimerContainer* container = (LocTimerContainer*)(ev[i].data.ptr);
+ if (container) {
+ container->expire();
+ } else {
+ epoll_ctl(mFd, EPOLL_CTL_DEL, ev[i].data.fd, NULL);
+ }
+ }
+ }
+
+ // if rerun is true, we are requesting to be scheduled again
+ return rerun;
+}
+
+/***************************LocTimerDelegate methods***************************/
+
+inline
+LocTimerDelegate::LocTimerDelegate(LocTimer& client,
+ struct timespec& futureTime,
+ LocTimerContainer* container)
+ : mClient(&client),
+ mLock(mClient->mLock->share()),
+ mFutureTime(futureTime),
+ mContainer(container) {
+ // adding the timer into the container
+ mContainer->add(*this);
+}
+
+inline
+void LocTimerDelegate::destroyLocked() {
+ // client handle will likely be deleted soon after this
+ // method returns. Nulling this handle so that expire()
+ // won't call the callback on the dead handle any more.
+ mClient = NULL;
+
+ if (mContainer) {
+ LocTimerContainer* container = mContainer;
+ mContainer = NULL;
+ if (container) {
+ container->remove(*this);
+ }
+ } // else we do not do anything. No such *this* can be
+ // created and reached here with mContainer ever been
+ // a non NULL. So *this* must have reached the if clause
+ // once, and we want it reach there only once.
+}
+
+int LocTimerDelegate::ranks(LocRankable& rankable) {
+ int rank = -1;
+ LocTimerDelegate* timer = (LocTimerDelegate*)(&rankable);
+ if (timer) {
+ // larger time ranks lower!!!
+ // IOW, if input obj has bigger tv_sec/tv_nsec, this obj outRanks higher
+ rank = timer->mFutureTime.tv_sec - mFutureTime.tv_sec;
+ if(0 == rank)
+ {
+ //rank against tv_nsec for msec accuracy
+ rank = (int)(timer->mFutureTime.tv_nsec - mFutureTime.tv_nsec);
+ }
+ }
+ return rank;
+}
+
+inline
+void LocTimerDelegate::expire() {
+ // keeping a copy of client pointer to be safe
+ // when timeOutCallback() is called at the end of this
+ // method, *this* obj may be already deleted.
+ LocTimer* client = mClient;
+ // force a stop, which will lead to delete of this obj
+ if (client && client->stop()) {
+ // calling client callback with a pointer save on the stack
+ // only if stop() returns true, i.e. it hasn't been stopped
+ // already.
+ client->timeOutCallback();
+ }
+}
+
+
+/***************************LocTimer methods***************************/
+LocTimer::LocTimer() : mTimer(NULL), mLock(new LocSharedLock()) {
+}
+
+LocTimer::~LocTimer() {
+ stop();
+ if (mLock) {
+ mLock->drop();
+ mLock = NULL;
+ }
+}
+
+bool LocTimer::start(unsigned int timeOutInMs, bool wakeOnExpire) {
+ bool success = false;
+ mLock->lock();
+ if (!mTimer) {
+ struct timespec futureTime;
+ clock_gettime(CLOCK_BOOTTIME, &futureTime);
+ futureTime.tv_sec += timeOutInMs / 1000;
+ futureTime.tv_nsec += (timeOutInMs % 1000) * 1000000;
+ if (futureTime.tv_nsec >= 1000000000) {
+ futureTime.tv_sec += futureTime.tv_nsec / 1000000000;
+ futureTime.tv_nsec %= 1000000000;
+ }
+
+ LocTimerContainer* container;
+ container = LocTimerContainer::get(wakeOnExpire);
+ if (NULL != container) {
+ mTimer = new LocTimerDelegate(*this, futureTime, container);
+ // if mTimer is non 0, success should be 0; or vice versa
+ }
+ success = (NULL != mTimer);
+ }
+ mLock->unlock();
+ return success;
+}
+
+bool LocTimer::stop() {
+ bool success = false;
+ mLock->lock();
+ if (mTimer) {
+ LocTimerDelegate* timer = mTimer;
+ mTimer = NULL;
+ if (timer) {
+ timer->destroyLocked();
+ success = true;
+ }
+ }
+ mLock->unlock();
+ return success;
+}
+
+/***************************LocTimerWrapper methods***************************/
+//////////////////////////////////////////////////////////////////////////
+// This section below wraps for the C style APIs
+//////////////////////////////////////////////////////////////////////////
+class LocTimerWrapper : public LocTimer {
+ loc_timer_callback mCb;
+ void* mCallerData;
+ LocTimerWrapper* mMe;
+ static pthread_mutex_t mMutex;
+ inline ~LocTimerWrapper() { mCb = NULL; mMe = NULL; }
+public:
+ inline LocTimerWrapper(loc_timer_callback cb, void* callerData) :
+ mCb(cb), mCallerData(callerData), mMe(this) {
+ }
+ void destroy() {
+ pthread_mutex_lock(&mMutex);
+ if (NULL != mCb && this == mMe) {
+ delete this;
+ }
+ pthread_mutex_unlock(&mMutex);
+ }
+ virtual void timeOutCallback() {
+ loc_timer_callback cb = mCb;
+ void* callerData = mCallerData;
+ if (cb) {
+ cb(callerData, 0);
+ }
+ destroy();
+ }
+};
+
+pthread_mutex_t LocTimerWrapper::mMutex = PTHREAD_MUTEX_INITIALIZER;
+
+void* loc_timer_start(uint64_t msec, loc_timer_callback cb_func,
+ void *caller_data, bool wake_on_expire)
+{
+ LocTimerWrapper* locTimerWrapper = NULL;
+
+ if (cb_func) {
+ locTimerWrapper = new LocTimerWrapper(cb_func, caller_data);
+
+ if (locTimerWrapper) {
+ locTimerWrapper->start(msec, wake_on_expire);
+ }
+ }
+
+ return locTimerWrapper;
+}
+
+void loc_timer_stop(void*& handle)
+{
+ if (handle) {
+ LocTimerWrapper* locTimerWrapper = (LocTimerWrapper*)(handle);
+ locTimerWrapper->destroy();
+ handle = NULL;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+// This section above wraps for the C style APIs
+//////////////////////////////////////////////////////////////////////////
+
+#ifdef __LOC_DEBUG__
+
+double getDeltaSeconds(struct timespec from, struct timespec to) {
+ return (double)to.tv_sec + (double)to.tv_nsec / 1000000000
+ - from.tv_sec - (double)from.tv_nsec / 1000000000;
+}
+
+struct timespec getNow() {
+ struct timespec now;
+ clock_gettime(CLOCK_BOOTTIME, &now);
+ return now;
+}
+
+class LocTimerTest : public LocTimer, public LocRankable {
+ int mTimeOut;
+ const struct timespec mTimeOfBirth;
+ inline struct timespec getTimerWrapper(int timeout) {
+ struct timespec now;
+ clock_gettime(CLOCK_BOOTTIME, &now);
+ now.tv_sec += timeout;
+ return now;
+ }
+public:
+ inline LocTimerTest(int timeout) : LocTimer(), LocRankable(),
+ mTimeOut(timeout), mTimeOfBirth(getTimerWrapper(0)) {}
+ inline virtual int ranks(LocRankable& rankable) {
+ LocTimerTest* timer = dynamic_cast<LocTimerTest*>(&rankable);
+ return timer->mTimeOut - mTimeOut;
+ }
+ inline virtual void timeOutCallback() {
+ printf("timeOutCallback() - ");
+ deviation();
+ }
+ double deviation() {
+ struct timespec now = getTimerWrapper(0);
+ double delta = getDeltaSeconds(mTimeOfBirth, now);
+ printf("%lf: %lf\n", delta, delta * 100 / mTimeOut);
+ return delta / mTimeOut;
+ }
+};
+
+// For Linux command line testing:
+// compilation:
+// g++ -D__LOC_HOST_DEBUG__ -D__LOC_DEBUG__ -g -I. -I../../../../system/core/include -o LocHeap.o LocHeap.cpp
+// g++ -D__LOC_HOST_DEBUG__ -D__LOC_DEBUG__ -g -std=c++0x -I. -I../../../../system/core/include -lpthread -o LocThread.o LocThread.cpp
+// g++ -D__LOC_HOST_DEBUG__ -D__LOC_DEBUG__ -g -I. -I../../../../system/core/include -o LocTimer.o LocTimer.cpp
+int main(int argc, char** argv) {
+ struct timespec timeOfStart=getNow();
+ srand(time(NULL));
+ int tries = atoi(argv[1]);
+ int checks = tries >> 3;
+ LocTimerTest** timerArray = new LocTimerTest*[tries];
+ memset(timerArray, NULL, tries);
+
+ for (int i = 0; i < tries; i++) {
+ int r = rand() % tries;
+ LocTimerTest* timer = new LocTimerTest(r);
+ if (timerArray[r]) {
+ if (!timer->stop()) {
+ printf("%lf:\n", getDeltaSeconds(timeOfStart, getNow()));
+ printf("ERRER: %dth timer, id %d, not running when it should be\n", i, r);
+ exit(0);
+ } else {
+ printf("stop() - %d\n", r);
+ delete timer;
+ timerArray[r] = NULL;
+ }
+ } else {
+ if (!timer->start(r, false)) {
+ printf("%lf:\n", getDeltaSeconds(timeOfStart, getNow()));
+ printf("ERRER: %dth timer, id %d, running when it should not be\n", i, r);
+ exit(0);
+ } else {
+ printf("stop() - %d\n", r);
+ timerArray[r] = timer;
+ }
+ }
+ }
+
+ for (int i = 0; i < tries; i++) {
+ if (timerArray[i]) {
+ if (!timerArray[i]->stop()) {
+ printf("%lf:\n", getDeltaSeconds(timeOfStart, getNow()));
+ printf("ERRER: %dth timer, not running when it should be\n", i);
+ exit(0);
+ } else {
+ printf("stop() - %d\n", i);
+ delete timerArray[i];
+ timerArray[i] = NULL;
+ }
+ }
+ }
+
+ delete[] timerArray;
+
+ return 0;
+}
+
+#endif
diff --git a/utils/LocTimer.h b/utils/LocTimer.h
new file mode 100644
index 0000000..abc7f64
--- /dev/null
+++ b/utils/LocTimer.h
@@ -0,0 +1,74 @@
+/* Copyright (c) 2015, 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 __LOC_TIMER_CPP_H__
+#define __LOC_TIMER_CPP_H__
+
+#include <stddef.h>
+#include <loc_pla.h>
+
+// opaque class to provide service implementation.
+class LocTimerDelegate;
+class LocSharedLock;
+
+// LocTimer client must extend this class and implementthe callback.
+// start() / stop() methods are to arm / disarm timer.
+class LocTimer
+{
+ LocTimerDelegate* mTimer;
+ LocSharedLock* mLock;
+ // don't really want mLock to be manipulated by clients, yet LocTimer
+ // has to have a reference to the lock so that the delete of LocTimer
+ // and LocTimerDelegate can work together on their share resources.
+ friend class LocTimerDelegate;
+
+public:
+ LocTimer();
+ virtual ~LocTimer();
+
+ // timeOutInMs: timeout delay in ms
+ // wakeOnExpire: true if to wake up CPU (if sleeping) upon timer
+ // expiration and notify the client.
+ // false if to wait until next time CPU wakes up (if
+ // sleeping) and then notify the client.
+ // return: true on success;
+ // false on failure, e.g. timer is already running.
+ bool start(uint32_t timeOutInMs, bool wakeOnExpire);
+
+ // return: true on success;
+ // false on failure, e.g. timer is not running.
+ bool stop();
+
+ // LocTimer client Should implement this method.
+ // This method is used for timeout calling back to client. This method
+ // should be short enough (eg: send a message to your own thread).
+ virtual void timeOutCallback() = 0;
+};
+
+#endif //__LOC_DELAY_H__
diff --git a/utils/LocUnorderedSetMap.h b/utils/LocUnorderedSetMap.h
new file mode 100644
index 0000000..8748134
--- /dev/null
+++ b/utils/LocUnorderedSetMap.h
@@ -0,0 +1,192 @@
+/* Copyright (c) 2015, 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 __LOC_UNORDERDED_SETMAP_H__
+#define __LOC_UNORDERDED_SETMAP_H__
+
+#include <algorithm>
+#include <unordered_set>
+#include <unordered_map>
+
+using std::unordered_set;
+using std::unordered_map;
+
+namespace loc_util {
+
+// Trim from *fromSet* any elements that also exist in *rVals*.
+// The optional *goneVals*, if not null, will be populated with removed elements.
+template <typename T>
+inline static void trimSet(unordered_set<T>& fromSet, const unordered_set<T>& rVals,
+ unordered_set<T>* goneVals) {
+ for (auto val : rVals) {
+ if (fromSet.erase(val) > 0 && nullptr != goneVals) {
+ goneVals->insert(val);
+ }
+ }
+}
+
+// this method is destructive to the input unordered_sets.
+// the return set is the interset extracted out from the two input sets, *s1* and *s2*.
+// *s1* and *s2* will be left with the intersect removed from them.
+template <typename T>
+static unordered_set<T> removeAndReturnInterset(unordered_set<T>& s1, unordered_set<T>& s2) {
+ unordered_set<T> common(0);
+ for (auto b = s2.begin(); b != s2.end(); b++) {
+ auto a = find(s1.begin(), s1.end(), *b);
+ if (a != s1.end()) {
+ // this is a common item of both l1 and l2, remove from both
+ // but after we add to common
+ common.insert(*a);
+ s1.erase(a);
+ s2.erase(b);
+ }
+ }
+ return common;
+}
+
+template <typename KEY, typename VAL>
+class LocUnorderedSetMap {
+ unordered_map<KEY, unordered_set<VAL>> mMap;
+
+
+ // Trim the VALs pointed to by *iter*, with everything that also exist in *rVals*.
+ // If the set becomes empty, remove the map entry. *goneVals*, if not null, records
+ // the trimmed VALs.
+ bool trimOrRemove(typename unordered_map<KEY, unordered_set<VAL>>::iterator iter,
+ const unordered_set<VAL>& rVals, unordered_set<VAL>* goneVals) {
+ trimSet<VAL>(iter->second, rVals, goneVals);
+ bool removeEntry = (iter->second.empty());
+ if (removeEntry) {
+ mMap.erase(iter);
+ }
+ return removeEntry;
+ }
+
+public:
+ inline LocUnorderedSetMap() {}
+ inline LocUnorderedSetMap(size_t size) : mMap(size) {}
+
+ inline bool empty() { return mMap.empty(); }
+
+ // This gets the raw pointer to the VALs pointed to by *key*
+ // If the entry is not in the map, nullptr will be returned.
+ inline unordered_set<VAL>* getValSetPtr(const KEY& key) {
+ auto entry = mMap.find(key);
+ return (entry != mMap.end()) ? &(entry->second) : nullptr;
+ }
+
+ // This gets a copy of VALs pointed to by *key*
+ // If the entry is not in the map, an empty set will be returned.
+ inline unordered_set<VAL> getValSet(const KEY& key) {
+ auto entry = mMap.find(key);
+ return (entry != mMap.end()) ? entry->second : unordered_set<VAL>(0);
+ }
+
+ // This gets all the KEYs from the map
+ inline unordered_set<KEY> getKeys() {
+ unordered_set<KEY> keys(0);
+ for (auto entry : mMap) {
+ keys.insert(entry.first);
+ }
+ return keys;
+ }
+
+ inline bool remove(const KEY& key) {
+ return mMap.erase(key) > 0;
+ }
+
+ // This looks into all the entries keyed by *keys*. Remove any VALs from the entries
+ // that also exist in *rVals*. If the entry is left with an empty set, the entry will
+ // be removed. The optional parameters *goneKeys* and *goneVals* will record the KEYs
+ // (or entries) and the collapsed VALs removed from the map, respectively.
+ inline void trimOrRemove(unordered_set<KEY>&& keys, const unordered_set<VAL>& rVals,
+ unordered_set<KEY>* goneKeys, unordered_set<VAL>* goneVals) {
+ trimOrRemove(keys, rVals, goneKeys, goneVals);
+ }
+ inline void trimOrRemove(unordered_set<KEY>& keys, const unordered_set<VAL>& rVals,
+ unordered_set<KEY>* goneKeys, unordered_set<VAL>* goneVals) {
+ for (auto key : keys) {
+ auto iter = mMap.find(key);
+ if (iter != mMap.end() && trimOrRemove(iter, rVals, goneVals) && nullptr != goneKeys) {
+ goneKeys->insert(iter->first);
+ }
+ }
+ }
+
+ // This adds all VALs from *newVals* to the map entry keyed by *key*. Or if it
+ // doesn't exist yet, add the set to the map.
+ bool add(const KEY& key, const unordered_set<VAL>& newVals) {
+ bool newEntryAdded = false;
+ if (!newVals.empty()) {
+ auto iter = mMap.find(key);
+ if (iter != mMap.end()) {
+ iter->second.insert(newVals.begin(), newVals.end());
+ } else {
+ mMap[key] = newVals;
+ newEntryAdded = true;
+ }
+ }
+ return newEntryAdded;
+ }
+
+ // This adds to each of entries in the map keyed by *keys* with the VALs in the
+ // *enwVals*. If there new entries added (new key in *keys*), *newKeys*, if not
+ // null, would be populated with those keys.
+ inline void add(const unordered_set<KEY>& keys, const unordered_set<VAL>&& newVals,
+ unordered_set<KEY>* newKeys) {
+ add(keys, newVals, newKeys);
+ }
+ inline void add(const unordered_set<KEY>& keys, const unordered_set<VAL>& newVals,
+ unordered_set<KEY>* newKeys) {
+ for (auto key : keys) {
+ if (add(key, newVals) && nullptr != newKeys) {
+ newKeys->insert(key);
+ }
+ }
+ }
+
+ // This puts *newVals* into the map keyed by *key*, and returns the VALs that are
+ // in effect removed from the keyed VAL set in the map entry.
+ // This call would also remove those same VALs from *newVals*.
+ inline unordered_set<VAL> update(const KEY& key, unordered_set<VAL>& newVals) {
+ unordered_set<VAL> goneVals(0);
+
+ if (newVals.empty()) {
+ mMap.erase(key);
+ } else {
+ auto curVals = mMap[key];
+ mMap[key] = newVals;
+ goneVals = removeAndReturnInterset(curVals, newVals);
+ }
+ return goneVals;
+ }
+};
+
+} // namespace loc_util
+
+#endif // #ifndef __LOC_UNORDERDED_SETMAP_H__
diff --git a/utils/Makefile.am b/utils/Makefile.am
new file mode 100644
index 0000000..9a9c67e
--- /dev/null
+++ b/utils/Makefile.am
@@ -0,0 +1,72 @@
+ACLOCAL_AMFLAGS = -I m4
+
+AM_CFLAGS = -Wundef \
+ -MD \
+ -Wno-trigraphs \
+ -g -O0 \
+ -fno-inline \
+ -fno-short-enums \
+ -fpic \
+ -I./ \
+ -std=c++14 \
+ $(LOCPLA_CFLAGS)
+
+libgps_utils_la_h_sources = \
+ msg_q.h \
+ linked_list.h \
+ loc_cfg.h \
+ loc_log.h \
+ loc_target.h \
+ loc_timer.h \
+ MsgTask.h \
+ LocHeap.h \
+ LocThread.h \
+ LocTimer.h \
+ LocIpc.h \
+ loc_misc_utils.h \
+ loc_nmea.h \
+ gps_extended_c.h \
+ gps_extended.h \
+ loc_gps.h \
+ log_util.h \
+ LocSharedLock.h \
+ LocUnorderedSetMap.h
+
+libgps_utils_la_c_sources = \
+ linked_list.c \
+ msg_q.c \
+ loc_cfg.cpp \
+ loc_log.cpp \
+ loc_target.cpp \
+ LocHeap.cpp \
+ LocTimer.cpp \
+ LocThread.cpp \
+ LocIpc.cpp \
+ MsgTask.cpp \
+ loc_misc_utils.cpp \
+ loc_nmea.cpp
+
+library_includedir = $(pkgincludedir)
+
+library_include_HEADERS = $(libgps_utils_la_h_sources)
+
+libgps_utils_la_SOURCES = $(libgps_utils_la_c_sources)
+
+if USE_GLIB
+libgps_utils_la_CFLAGS = -DUSE_GLIB $(AM_CFLAGS) @GLIB_CFLAGS@
+libgps_utils_la_LDFLAGS = -lstdc++ -Wl,-z,defs -lpthread @GLIB_LIBS@ -shared -version-info 1:0:0
+libgps_utils_la_CPPFLAGS = -DUSE_GLIB $(AM_CFLAGS) $(AM_CPPFLAGS) @GLIB_CFLAGS@
+else
+libgps_utils_la_CFLAGS = $(AM_CFLAGS)
+libgps_utils_la_LDFLAGS = -Wl,-z,defs -lpthread -shared -version-info 1:0:0
+libgps_utils_la_CPPFLAGS = $(AM_CFLAGS) $(AM_CPPFLAGS)
+endif
+
+libgps_utils_la_LIBADD = $(CUTILS_LIBS) -ldl
+
+#Create and Install libraries
+lib_LTLIBRARIES = libgps_utils.la
+
+pkgconfigdir = $(libdir)/pkgconfig
+pkgconfig_DATA = gps-utils.pc
+EXTRA_DIST = $(pkgconfig_DATA)
diff --git a/utils/MsgTask.cpp b/utils/MsgTask.cpp
new file mode 100644
index 0000000..73a77fd
--- /dev/null
+++ b/utils/MsgTask.cpp
@@ -0,0 +1,108 @@
+/* Copyright (c) 2011-2013, 2015, 2017The 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_NDEBUG 0
+#define LOG_TAG "LocSvc_MsgTask"
+
+#include <unistd.h>
+#include <MsgTask.h>
+#include <msg_q.h>
+#include <log_util.h>
+#include <loc_log.h>
+#include <loc_pla.h>
+
+static void LocMsgDestroy(void* msg) {
+ delete (LocMsg*)msg;
+}
+
+MsgTask::MsgTask(LocThread::tCreate tCreator,
+ const char* threadName, bool joinable) :
+ mQ(msg_q_init2()), mThread(new LocThread()) {
+ if (!mThread->start(tCreator, threadName, this, joinable)) {
+ delete mThread;
+ mThread = NULL;
+ }
+}
+
+MsgTask::MsgTask(const char* threadName, bool joinable) :
+ mQ(msg_q_init2()), mThread(new LocThread()) {
+ if (!mThread->start(threadName, this, joinable)) {
+ delete mThread;
+ mThread = NULL;
+ }
+}
+
+MsgTask::~MsgTask() {
+ msg_q_flush((void*)mQ);
+ msg_q_destroy((void**)&mQ);
+}
+
+void MsgTask::destroy() {
+ LocThread* thread = mThread;
+ msg_q_unblock((void*)mQ);
+ if (thread) {
+ mThread = NULL;
+ delete thread;
+ } else {
+ delete this;
+ }
+}
+
+void MsgTask::sendMsg(const LocMsg* msg) const {
+ if (msg && this) {
+ msg_q_snd((void*)mQ, (void*)msg, LocMsgDestroy);
+ } else {
+ LOC_LOGE("%s: msg is %p and this is %p",
+ __func__, msg, this);
+ }
+}
+
+void MsgTask::prerun() {
+#ifndef FEATURE_EXTERNAL_AP
+ // make sure we do not run in background scheduling group
+ set_sched_policy(gettid(), SP_FOREGROUND);
+#endif /* FEATURE_EXTERNAL_AP */
+}
+
+bool MsgTask::run() {
+ LocMsg* msg;
+ msq_q_err_type result = msg_q_rcv((void*)mQ, (void **)&msg);
+ if (eMSG_Q_SUCCESS != result) {
+ LOC_LOGE("%s:%d] fail receiving msg: %s\n", __func__, __LINE__,
+ loc_get_msg_q_status(result));
+ return false;
+ }
+
+ msg->log();
+ // there is where each individual msg handling is invoked
+ msg->proc();
+
+ delete msg;
+
+ return true;
+}
diff --git a/utils/MsgTask.h b/utils/MsgTask.h
new file mode 100644
index 0000000..9eb1f56
--- /dev/null
+++ b/utils/MsgTask.h
@@ -0,0 +1,67 @@
+/* Copyright (c) 2011-2013,2015 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 __MSG_TASK__
+#define __MSG_TASK__
+
+#include <LocThread.h>
+
+struct LocMsg {
+ inline LocMsg() {}
+ inline virtual ~LocMsg() {}
+ virtual void proc() const = 0;
+ inline virtual void log() const {}
+};
+
+class MsgTask : public LocRunnable {
+ const void* mQ;
+ LocThread* mThread;
+ friend class LocThreadDelegate;
+protected:
+ virtual ~MsgTask();
+public:
+ MsgTask(LocThread::tCreate tCreator, const char* threadName = NULL, bool joinable = true);
+ MsgTask(const char* threadName = NULL, bool joinable = true);
+ // this obj will be deleted once thread is deleted
+ void destroy();
+ void sendMsg(const LocMsg* msg) const;
+ // Overrides of LocRunnable methods
+ // This method will be repeated called until it returns false; or
+ // until thread is stopped.
+ virtual bool run();
+
+ // The method to be run before thread loop (conditionally repeatedly)
+ // calls run()
+ virtual void prerun();
+
+ // The method to be run after thread loop (conditionally repeatedly)
+ // calls run()
+ inline virtual void postrun() {}
+};
+
+#endif //__MSG_TASK__
diff --git a/utils/configure.ac b/utils/configure.ac
new file mode 100644
index 0000000..fd16494
--- /dev/null
+++ b/utils/configure.ac
@@ -0,0 +1,92 @@
+# configure.ac -- Autoconf script for gps gps-utils
+#
+# Process this file with autoconf to produce a configure script
+
+# Requires autoconf tool later than 2.61
+AC_PREREQ(2.61)
+# Initialize the gps gps-utils package version 1.0.0
+AC_INIT([gps-utils],1.0.0)
+# Does not strictly follow GNU Coding standards
+AM_INIT_AUTOMAKE([foreign])
+# Disables auto rebuilding of configure, Makefile.ins
+AM_MAINTAINER_MODE
+# Verifies the --srcdir is correct by checking for the path
+AC_CONFIG_SRCDIR([Makefile.am])
+# defines some macros variable to be included by source
+AC_CONFIG_HEADERS([config.h])
+AC_CONFIG_MACRO_DIR([m4])
+
+# Checks for programs.
+AC_PROG_LIBTOOL
+AC_PROG_CXX
+AC_PROG_CC
+AM_PROG_CC_C_O
+AC_PROG_AWK
+AC_PROG_CPP
+AC_PROG_INSTALL
+AC_PROG_LN_S
+AC_PROG_MAKE_SET
+PKG_PROG_PKG_CONFIG
+
+AC_ARG_WITH([external_ap],
+ AC_HELP_STRING([--with-external_ap=@<:@dir@:>@],
+ [Using External Application Processor]),
+ [],
+ with_external_ap=no)
+
+if test "x$with_external_ap" != "xno"; then
+ CPPFLAGS="${CPPFLAGS} -DFEATURE_EXTERNAL_AP"
+else
+ # Checks for libraries.
+ PKG_CHECK_MODULES([CUTILS], [libcutils])
+ AC_SUBST([CUTILS_CFLAGS])
+ AC_SUBST([CUTILS_LIBS])
+fi
+
+AC_ARG_WITH([core_includes],
+ AC_HELP_STRING([--with-core-includes=@<:@dir@:>@],
+ [Specify the location of the core headers]),
+ [core_incdir=$withval],
+ with_core_includes=no)
+
+if test "x$with_core_includes" != "xno"; then
+ CPPFLAGS="${CPPFLAGS} -I${core_incdir}"
+fi
+
+AC_ARG_WITH([locpla_includes],
+ AC_HELP_STRING([--with-locpla-includes=@<:@dir@:>@],
+ [specify the path to locpla-includes in loc-pla_git.bb]),
+ [locpla_incdir=$withval],
+ with_locpla_includes=no)
+
+if test "x$with_locpla_includes" != "xno"; then
+ AC_SUBST(LOCPLA_CFLAGS, "-I${locpla_incdir}")
+fi
+
+AC_SUBST([CPPFLAGS])
+
+AC_ARG_WITH([glib],
+ AC_HELP_STRING([--with-glib],
+ [enable glib, building HLOS systems which use glib]))
+
+if (test "x${with_glib}" = "xyes"); then
+ AC_DEFINE(ENABLE_USEGLIB, 1, [Define if HLOS systems uses glib])
+ PKG_CHECK_MODULES(GTHREAD, gthread-2.0 >= 2.16, dummy=yes,
+ AC_MSG_ERROR(GThread >= 2.16 is required))
+ PKG_CHECK_MODULES(GLIB, glib-2.0 >= 2.16, dummy=yes,
+ AC_MSG_ERROR(GLib >= 2.16 is required))
+ GLIB_CFLAGS="$GLIB_CFLAGS $GTHREAD_CFLAGS"
+ GLIB_LIBS="$GLIB_LIBS $GTHREAD_LIBS"
+
+ AC_SUBST(GLIB_CFLAGS)
+ AC_SUBST(GLIB_LIBS)
+fi
+
+AM_CONDITIONAL(USE_GLIB, test "x${with_glib}" = "xyes")
+
+AC_CONFIG_FILES([ \
+ Makefile \
+ gps-utils.pc
+ ])
+
+AC_OUTPUT
diff --git a/utils/gps-utils.pc.in b/utils/gps-utils.pc.in
new file mode 100644
index 0000000..a988731
--- /dev/null
+++ b/utils/gps-utils.pc.in
@@ -0,0 +1,10 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+
+Name: gps-utils
+Description: QTI GPS Location utils
+Version: @VERSION
+Libs: -L${libdir} -lgps_utils
+Cflags: -I${includedir}/gps-utils
diff --git a/utils/gps_extended.h b/utils/gps_extended.h
new file mode 100644
index 0000000..2455629
--- /dev/null
+++ b/utils/gps_extended.h
@@ -0,0 +1,114 @@
+/* Copyright (c) 2013-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 GPS_EXTENDED_H
+#define GPS_EXTENDED_H
+
+/**
+ * @file
+ * @brief C++ declarations for GPS types
+ */
+
+#include <gps_extended_c.h>
+#if defined(USE_GLIB) || defined(OFF_TARGET)
+#include <string.h>
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+
+
+struct LocPosMode
+{
+ LocPositionMode mode;
+ LocGpsPositionRecurrence recurrence;
+ uint32_t min_interval;
+ uint32_t preferred_accuracy;
+ uint32_t preferred_time;
+ bool share_position;
+ char credentials[14];
+ char provider[8];
+ GnssPowerMode powerMode;
+ uint32_t timeBetweenMeasurements;
+ LocPosMode(LocPositionMode m, LocGpsPositionRecurrence recr,
+ uint32_t gap, uint32_t accu, uint32_t time,
+ bool sp, const char* cred, const char* prov,
+ GnssPowerMode pMode = GNSS_POWER_MODE_INVALID,
+ uint32_t tbm = 0) :
+ mode(m), recurrence(recr),
+ min_interval(gap < GPS_MIN_POSSIBLE_FIX_INTERVAL_MS ?
+ GPS_MIN_POSSIBLE_FIX_INTERVAL_MS : gap),
+ preferred_accuracy(accu), preferred_time(time),
+ share_position(sp), powerMode(pMode),
+ timeBetweenMeasurements(tbm) {
+ memset(credentials, 0, sizeof(credentials));
+ memset(provider, 0, sizeof(provider));
+ if (NULL != cred) {
+ memcpy(credentials, cred, sizeof(credentials)-1);
+ }
+ if (NULL != prov) {
+ memcpy(provider, prov, sizeof(provider)-1);
+ }
+ }
+
+ inline LocPosMode() :
+ mode(LOC_POSITION_MODE_MS_BASED),
+ recurrence(LOC_GPS_POSITION_RECURRENCE_PERIODIC),
+ min_interval(GPS_DEFAULT_FIX_INTERVAL_MS),
+ preferred_accuracy(50), preferred_time(120000),
+ share_position(true), powerMode(GNSS_POWER_MODE_INVALID),
+ timeBetweenMeasurements(GPS_DEFAULT_FIX_INTERVAL_MS) {
+ memset(credentials, 0, sizeof(credentials));
+ memset(provider, 0, sizeof(provider));
+ }
+
+ inline bool equals(const LocPosMode &anotherMode) const
+ {
+ return anotherMode.mode == mode &&
+ anotherMode.recurrence == recurrence &&
+ anotherMode.min_interval == min_interval &&
+ anotherMode.preferred_accuracy == preferred_accuracy &&
+ anotherMode.preferred_time == preferred_time &&
+ anotherMode.powerMode == powerMode &&
+ anotherMode.timeBetweenMeasurements == timeBetweenMeasurements &&
+ !strncmp(anotherMode.credentials, credentials, sizeof(credentials)-1) &&
+ !strncmp(anotherMode.provider, provider, sizeof(provider)-1);
+ }
+
+ void logv() const;
+};
+
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* GPS_EXTENDED_H */
+
diff --git a/utils/gps_extended_c.h b/utils/gps_extended_c.h
new file mode 100644
index 0000000..69a659e
--- /dev/null
+++ b/utils/gps_extended_c.h
@@ -0,0 +1,2290 @@
+/* Copyright (c) 2013-2019 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 GPS_EXTENDED_C_H
+#define GPS_EXTENDED_C_H
+
+#include <ctype.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
+#include <loc_gps.h>
+#include <LocationAPI.h>
+
+struct timespec32_t {
+ uint32_t tv_sec; /* seconds */
+ uint32_t tv_nsec; /* and nanoseconds */
+};
+
+
+/**
+ * @file
+ * @brief C++ declarations for GPS types
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+/** Location has valid source information. */
+#define LOCATION_HAS_SOURCE_INFO 0x0020
+/** LocGpsLocation has valid "is indoor?" flag */
+#define LOC_GPS_LOCATION_HAS_IS_INDOOR 0x0040
+/** LocGpsLocation has valid floor number */
+#define LOC_GPS_LOCATION_HAS_FLOOR_NUMBER 0x0080
+/** LocGpsLocation has valid map URL*/
+#define LOC_GPS_LOCATION_HAS_MAP_URL 0x0100
+/** LocGpsLocation has valid map index */
+#define LOC_GPS_LOCATION_HAS_MAP_INDEX 0x0200
+
+#define GNSS_INVALID_JAMMER_IND 0x7FFFFFFF
+
+/** Sizes for indoor fields */
+#define GPS_LOCATION_MAP_URL_SIZE 400
+#define GPS_LOCATION_MAP_INDEX_SIZE 16
+
+/** Position source is ULP */
+#define ULP_LOCATION_IS_FROM_HYBRID 0x0001
+/** Position source is GNSS only */
+#define ULP_LOCATION_IS_FROM_GNSS 0x0002
+/** Position is from a Geofence Breach Event */
+#define ULP_LOCATION_IS_FROM_GEOFENCE 0X0004
+/** Position is from Hardware FLP */
+#define ULP_LOCATION_IS_FROM_HW_FLP 0x0008
+/** Position is from NLP */
+#define ULP_LOCATION_IS_FROM_NLP 0x0010
+/** Position is from external DR solution*/
+#define ULP_LOCATION_IS_FROM_EXT_DR 0X0020
+/** Raw GNSS position fixes */
+#define ULP_LOCATION_IS_FROM_GNSS_RAW 0X0040
+
+typedef uint32_t LocSvInfoSource;
+/** SVinfo source is GNSS/DR */
+#define ULP_SVINFO_IS_FROM_GNSS ((LocSvInfoSource)0x0001)
+/** Raw SVinfo from GNSS */
+#define ULP_SVINFO_IS_FROM_DR ((LocSvInfoSource)0x0002)
+
+#define ULP_MIN_INTERVAL_INVALID 0xffffffff
+#define ULP_MAX_NMEA_STRING_SIZE 201
+
+/*Emergency SUPL*/
+#define LOC_GPS_NI_TYPE_EMERGENCY_SUPL 4
+
+#define LOC_AGPS_CERTIFICATE_MAX_LENGTH 2000
+#define LOC_AGPS_CERTIFICATE_MAX_SLOTS 10
+
+/* TBM Threshold for tracking in background power mode : in millis */
+#define TRACKING_TBM_THRESHOLD_MILLIS 480000
+
+/** Maximum number of satellites in an ephemeris report. */
+#define GNSS_EPHEMERIS_LIST_MAX_SIZE_V02 32
+
+typedef uint32_t LocPosTechMask;
+#define LOC_POS_TECH_MASK_DEFAULT ((LocPosTechMask)0x00000000)
+#define LOC_POS_TECH_MASK_SATELLITE ((LocPosTechMask)0x00000001)
+#define LOC_POS_TECH_MASK_CELLID ((LocPosTechMask)0x00000002)
+#define LOC_POS_TECH_MASK_WIFI ((LocPosTechMask)0x00000004)
+#define LOC_POS_TECH_MASK_SENSORS ((LocPosTechMask)0x00000008)
+#define LOC_POS_TECH_MASK_REFERENCE_LOCATION ((LocPosTechMask)0x00000010)
+#define LOC_POS_TECH_MASK_INJECTED_COARSE_POSITION ((LocPosTechMask)0x00000020)
+#define LOC_POS_TECH_MASK_AFLT ((LocPosTechMask)0x00000040)
+#define LOC_POS_TECH_MASK_HYBRID ((LocPosTechMask)0x00000080)
+#define LOC_POS_TECH_MASK_PPE ((LocPosTechMask)0x00000100)
+
+enum loc_registration_mask_status {
+ LOC_REGISTRATION_MASK_ENABLED,
+ LOC_REGISTRATION_MASK_DISABLED,
+ LOC_REGISTRATION_MASK_SET
+};
+
+typedef enum {
+ LOC_SUPPORTED_FEATURE_ODCPI_2_V02 = 0, /**< Support ODCPI version 2 feature */
+ LOC_SUPPORTED_FEATURE_WIFI_AP_DATA_INJECT_2_V02, /**< Support Wifi AP data inject version 2 feature */
+ LOC_SUPPORTED_FEATURE_DEBUG_NMEA_V02, /**< Support debug NMEA feature */
+ LOC_SUPPORTED_FEATURE_GNSS_ONLY_POSITION_REPORT, /**< Support GNSS Only position reports */
+ LOC_SUPPORTED_FEATURE_FDCL, /**< Support FDCL */
+ LOC_SUPPORTED_FEATURE_CONSTELLATION_ENABLEMENT_V02, /**< Support constellation enablement */
+ LOC_SUPPORTED_FEATURE_AGPM_V02, /**< Support AGPM feature */
+ LOC_SUPPORTED_FEATURE_XTRA_INTEGRITY, /**< Support XTRA integrity */
+ LOC_SUPPORTED_FEATURE_FDCL_2, /**< Support FDCL V2 */
+ LOC_SUPPORTED_FEATURE_LOCATION_PRIVACY /**< Support location privacy */
+} loc_supported_feature_enum;
+
+typedef struct {
+ /** set to sizeof(UlpLocation) */
+ uint32_t size;
+ LocGpsLocation gpsLocation;
+ /* Provider indicator for HYBRID or GPS */
+ uint16_t position_source;
+ LocPosTechMask tech_mask;
+ bool unpropagatedPosition;
+} UlpLocation;
+
+typedef struct {
+ /** set to sizeof(UlpNmea) */
+ uint32_t size;
+ char nmea_str[ULP_MAX_NMEA_STRING_SIZE];
+ unsigned int len;
+} UlpNmea;
+
+
+/** AGPS type */
+typedef int8_t AGpsExtType;
+#define LOC_AGPS_TYPE_INVALID -1
+#define LOC_AGPS_TYPE_ANY 0
+#define LOC_AGPS_TYPE_SUPL 1
+#define LOC_AGPS_TYPE_C2K 2
+#define LOC_AGPS_TYPE_WWAN_ANY 3
+#define LOC_AGPS_TYPE_WIFI 4
+#define LOC_AGPS_TYPE_SUPL_ES 5
+
+/** SSID length */
+#define SSID_BUF_SIZE (32+1)
+
+typedef int16_t AGpsBearerType;
+#define AGPS_APN_BEARER_INVALID 0
+#define AGPS_APN_BEARER_IPV4 1
+#define AGPS_APN_BEARER_IPV6 2
+#define AGPS_APN_BEARER_IPV4V6 3
+
+typedef uint32_t LocApnTypeMask;
+/**< Denotes APN type for Default/Internet traffic */
+#define LOC_APN_TYPE_MASK_DEFAULT ((LocApnTypeMask)0x00000001)
+/**< Denotes APN type for IP Multimedia Subsystem */
+#define LOC_APN_TYPE_MASK_IMS ((LocApnTypeMask)0x00000002)
+/**< Denotes APN type for Multimedia Messaging Service */
+#define LOC_APN_TYPE_MASK_MMS ((LocApnTypeMask)0x00000004)
+/**< Denotes APN type for Dial Up Network */
+#define LOC_APN_TYPE_MASK_DUN ((LocApnTypeMask)0x00000008)
+/**< Denotes APN type for Secure User Plane Location */
+#define LOC_APN_TYPE_MASK_SUPL ((LocApnTypeMask)0x00000010)
+/**< Denotes APN type for High Priority Mobile Data */
+#define LOC_APN_TYPE_MASK_HIPRI ((LocApnTypeMask)0x00000020)
+/**< Denotes APN type for over the air administration */
+#define LOC_APN_TYPE_MASK_FOTA ((LocApnTypeMask)0x00000040)
+/**< Denotes APN type for Carrier Branded Services */
+#define LOC_APN_TYPE_MASK_CBS ((LocApnTypeMask)0x00000080)
+/**< Denotes APN type for Initial Attach */
+#define LOC_APN_TYPE_MASK_IA ((LocApnTypeMask)0x00000100)
+/**< Denotes APN type for emergency */
+#define LOC_APN_TYPE_MASK_EMERGENCY ((LocApnTypeMask)0x00000200)
+
+typedef uint32_t AGpsTypeMask;
+#define AGPS_ATL_TYPE_SUPL ((AGpsTypeMask)0x00000001)
+#define AGPS_ATL_TYPE_SUPL_ES ((AGpsTypeMask)0x00000002)
+#define AGPS_ATL_TYPE_WWAN ((AGpsTypeMask)0x00000004)
+
+typedef struct {
+ void* statusV4Cb;
+ AGpsTypeMask atlType;
+} AgpsCbInfo;
+
+typedef struct {
+ void* visibilityControlCb;
+ void* isInEmergencySession;
+} NfwCbInfo;
+
+/** GPS extended callback structure. */
+typedef struct {
+ /** set to sizeof(LocGpsCallbacks) */
+ uint32_t size;
+ loc_gps_set_capabilities set_capabilities_cb;
+ loc_gps_acquire_wakelock acquire_wakelock_cb;
+ loc_gps_release_wakelock release_wakelock_cb;
+ loc_gps_create_thread create_thread_cb;
+ loc_gps_request_utc_time request_utc_time_cb;
+} GpsExtCallbacks;
+
+/** Callback to report the xtra server url to the client.
+ * The client should use this url when downloading xtra unless overwritten
+ * in the gps.conf file
+ */
+typedef void (* report_xtra_server)(const char*, const char*, const char*);
+
+/** Callback structure for the XTRA interface. */
+typedef struct {
+ loc_gps_xtra_download_request download_request_cb;
+ loc_gps_create_thread create_thread_cb;
+ report_xtra_server report_xtra_server_cb;
+} GpsXtraExtCallbacks;
+
+/** Represents the status of AGPS. */
+typedef struct {
+ /** set to sizeof(AGpsExtStatus) */
+ uint32_t size;
+
+ AGpsExtType type;
+ LocAGpsStatusValue status;
+ uint32_t ipv4_addr;
+ struct sockaddr_storage addr;
+ char ssid[SSID_BUF_SIZE];
+ char password[SSID_BUF_SIZE];
+} AGpsExtStatus;
+
+/** Callback with AGPS status information.
+ * Can only be called from a thread created by create_thread_cb.
+ */
+typedef void (* agps_status_extended)(AGpsExtStatus* status);
+
+/** Callback structure for the AGPS interface. */
+typedef struct {
+ agps_status_extended status_cb;
+ loc_gps_create_thread create_thread_cb;
+} AGpsExtCallbacks;
+
+
+typedef void (*loc_ni_notify_callback)(LocGpsNiNotification *notification, bool esEnalbed);
+/** GPS NI callback structure. */
+typedef struct
+{
+ /**
+ * Sends the notification request from HAL to GPSLocationProvider.
+ */
+ loc_ni_notify_callback notify_cb;
+} GpsNiExtCallbacks;
+
+typedef enum loc_server_type {
+ LOC_AGPS_CDMA_PDE_SERVER,
+ LOC_AGPS_CUSTOM_PDE_SERVER,
+ LOC_AGPS_MPC_SERVER,
+ LOC_AGPS_SUPL_SERVER,
+ LOC_AGPS_MO_SUPL_SERVER
+} LocServerType;
+
+typedef enum loc_position_mode_type {
+ LOC_POSITION_MODE_INVALID = -1,
+ LOC_POSITION_MODE_STANDALONE = 0,
+ LOC_POSITION_MODE_MS_BASED,
+ LOC_POSITION_MODE_MS_ASSISTED,
+ LOC_POSITION_MODE_RESERVED_1,
+ LOC_POSITION_MODE_RESERVED_2,
+ LOC_POSITION_MODE_RESERVED_3,
+ LOC_POSITION_MODE_RESERVED_4,
+ LOC_POSITION_MODE_RESERVED_5
+
+} LocPositionMode;
+
+/**
+ * @brief Minimum allowed value for fix interval.
+ *
+ * This value is a sanity limit in GPS framework. The hardware has own internal
+ * limits that may not match this value
+ *
+ * @sa GPS_DEFAULT_FIX_INTERVAL_MS
+ */
+
+#define GPS_MIN_POSSIBLE_FIX_INTERVAL_MS 100
+/**
+ * @brief Default value for fix interval.
+ *
+ * This value is used by default whenever appropriate.
+ *
+ * @sa GPS_MIN_POSSIBLE_FIX_INTERVAL_MS
+ */
+#define GPS_DEFAULT_FIX_INTERVAL_MS 1000
+
+/** Flags to indicate which values are valid in a GpsLocationExtended. */
+typedef uint64_t GpsLocationExtendedFlags;
+/** GpsLocationExtended has valid pdop, hdop, vdop. */
+#define GPS_LOCATION_EXTENDED_HAS_DOP 0x0001
+/** GpsLocationExtended has valid altitude mean sea level. */
+#define GPS_LOCATION_EXTENDED_HAS_ALTITUDE_MEAN_SEA_LEVEL 0x0002
+/** UlpLocation has valid magnetic deviation. */
+#define GPS_LOCATION_EXTENDED_HAS_MAG_DEV 0x0004
+/** UlpLocation has valid mode indicator. */
+#define GPS_LOCATION_EXTENDED_HAS_MODE_IND 0x0008
+/** GpsLocationExtended has valid vertical uncertainty */
+#define GPS_LOCATION_EXTENDED_HAS_VERT_UNC 0x0010
+/** GpsLocationExtended has valid speed uncertainty */
+#define GPS_LOCATION_EXTENDED_HAS_SPEED_UNC 0x0020
+/** GpsLocationExtended has valid heading uncertainty */
+#define GPS_LOCATION_EXTENDED_HAS_BEARING_UNC 0x0040
+/** GpsLocationExtended has valid horizontal reliability */
+#define GPS_LOCATION_EXTENDED_HAS_HOR_RELIABILITY 0x0080
+/** GpsLocationExtended has valid vertical reliability */
+#define GPS_LOCATION_EXTENDED_HAS_VERT_RELIABILITY 0x0100
+/** GpsLocationExtended has valid Horizontal Elliptical Uncertainty (Semi-Major Axis) */
+#define GPS_LOCATION_EXTENDED_HAS_HOR_ELIP_UNC_MAJOR 0x0200
+/** GpsLocationExtended has valid Horizontal Elliptical Uncertainty (Semi-Minor Axis) */
+#define GPS_LOCATION_EXTENDED_HAS_HOR_ELIP_UNC_MINOR 0x0400
+/** GpsLocationExtended has valid Elliptical Horizontal Uncertainty Azimuth */
+#define GPS_LOCATION_EXTENDED_HAS_HOR_ELIP_UNC_AZIMUTH 0x0800
+/** GpsLocationExtended has valid gnss sv used in position data */
+#define GPS_LOCATION_EXTENDED_HAS_GNSS_SV_USED_DATA 0x1000
+/** GpsLocationExtended has valid navSolutionMask */
+#define GPS_LOCATION_EXTENDED_HAS_NAV_SOLUTION_MASK 0x2000
+/** GpsLocationExtended has valid LocPosTechMask */
+#define GPS_LOCATION_EXTENDED_HAS_POS_TECH_MASK 0x4000
+/** GpsLocationExtended has valid LocSvInfoSource */
+#define GPS_LOCATION_EXTENDED_HAS_SV_SOURCE_INFO 0x8000
+/** GpsLocationExtended has valid position dynamics data */
+#define GPS_LOCATION_EXTENDED_HAS_POS_DYNAMICS_DATA 0x10000
+/** GpsLocationExtended has GPS Time */
+#define GPS_LOCATION_EXTENDED_HAS_GPS_TIME 0x20000
+/** GpsLocationExtended has Extended Dilution of Precision */
+#define GPS_LOCATION_EXTENDED_HAS_EXT_DOP 0x40000
+/** GpsLocationExtended has North standard deviation */
+#define GPS_LOCATION_EXTENDED_HAS_NORTH_STD_DEV 0x80000
+/** GpsLocationExtended has East standard deviation*/
+#define GPS_LOCATION_EXTENDED_HAS_EAST_STD_DEV 0x100000
+/** GpsLocationExtended has North Velocity */
+#define GPS_LOCATION_EXTENDED_HAS_NORTH_VEL 0x200000
+/** GpsLocationExtended has East Velocity */
+#define GPS_LOCATION_EXTENDED_HAS_EAST_VEL 0x400000
+/** GpsLocationExtended has up Velocity */
+#define GPS_LOCATION_EXTENDED_HAS_UP_VEL 0x800000
+/** GpsLocationExtended has North Velocity Uncertainty */
+#define GPS_LOCATION_EXTENDED_HAS_NORTH_VEL_UNC 0x1000000
+/** GpsLocationExtended has East Velocity Uncertainty */
+#define GPS_LOCATION_EXTENDED_HAS_EAST_VEL_UNC 0x2000000
+/** GpsLocationExtended has up Velocity Uncertainty */
+#define GPS_LOCATION_EXTENDED_HAS_UP_VEL_UNC 0x4000000
+/** GpsLocationExtended has Clock Bias */
+#define GPS_LOCATION_EXTENDED_HAS_CLOCK_BIAS 0x8000000
+/** GpsLocationExtended has Clock Bias std deviation*/
+#define GPS_LOCATION_EXTENDED_HAS_CLOCK_BIAS_STD_DEV 0x10000000
+/** GpsLocationExtended has Clock drift*/
+#define GPS_LOCATION_EXTENDED_HAS_CLOCK_DRIFT 0x20000000
+/** GpsLocationExtended has Clock drift std deviation**/
+#define GPS_LOCATION_EXTENDED_HAS_CLOCK_DRIFT_STD_DEV 0x40000000
+/** GpsLocationExtended has leap seconds **/
+#define GPS_LOCATION_EXTENDED_HAS_LEAP_SECONDS 0x80000000
+/** GpsLocationExtended has time uncertainty **/
+#define GPS_LOCATION_EXTENDED_HAS_TIME_UNC 0x100000000
+/** GpsLocationExtended has heading rate **/
+#define GPS_LOCATION_EXTENDED_HAS_HEADING_RATE 0x200000000
+/** GpsLocationExtended has multiband signals **/
+#define GPS_LOCATION_EXTENDED_HAS_MULTIBAND 0x400000000
+/** GpsLocationExtended has sensor calibration confidence */
+#define GPS_LOCATION_EXTENDED_HAS_CALIBRATION_CONFIDENCE 0x800000000
+/** GpsLocationExtended has sensor calibration status */
+#define GPS_LOCATION_EXTENDED_HAS_CALIBRATION_STATUS 0x1000000000
+/** GpsLocationExtended has the engine type that produced this
+ * position, the bit mask will only be set when there are two
+ * or more position engines running in the system */
+#define GPS_LOCATION_EXTENDED_HAS_OUTPUT_ENG_TYPE 0x2000000000
+ /** GpsLocationExtended has the engine mask that indicates the
+ * set of engines contribute to the fix. */
+#define GPS_LOCATION_EXTENDED_HAS_OUTPUT_ENG_MASK 0x4000000000
+
+typedef uint32_t LocNavSolutionMask;
+/* Bitmask to specify whether SBAS ionospheric correction is used */
+#define LOC_NAV_MASK_SBAS_CORRECTION_IONO ((LocNavSolutionMask)0x0001)
+/* Bitmask to specify whether SBAS fast correction is used */
+#define LOC_NAV_MASK_SBAS_CORRECTION_FAST ((LocNavSolutionMask)0x0002)
+/**< Bitmask to specify whether SBAS long-tem correction is used */
+#define LOC_NAV_MASK_SBAS_CORRECTION_LONG ((LocNavSolutionMask)0x0004)
+/**< Bitmask to specify whether SBAS integrity information is used */
+#define LOC_NAV_MASK_SBAS_INTEGRITY ((LocNavSolutionMask)0x0008)
+/**< Bitmask to specify whether Position Report is DGNSS corrected */
+#define LOC_NAV_MASK_DGNSS_CORRECTION ((LocNavSolutionMask)0x0010)
+/**< Bitmask to specify whether Position Report is RTK corrected */
+#define LOC_NAV_MASK_RTK_CORRECTION ((LocNavSolutionMask)0x0020)
+/**< Bitmask to specify whether Position Report is PPP corrected */
+#define LOC_NAV_MASK_PPP_CORRECTION ((LocNavSolutionMask)0x0040)
+/**< Bitmask to specify whether Position Report is RTK fixed corrected */
+#define LOC_NAV_MASK_RTK_FIXED_CORRECTION ((LocNavSolutionMask)0x0080)
+
+typedef uint32_t LocPosDataMask;
+/* Bitmask to specify whether Navigation data has Forward Acceleration */
+#define LOC_NAV_DATA_HAS_LONG_ACCEL ((LocPosDataMask)0x0001)
+/* Bitmask to specify whether Navigation data has Sideward Acceleration */
+#define LOC_NAV_DATA_HAS_LAT_ACCEL ((LocPosDataMask)0x0002)
+/* Bitmask to specify whether Navigation data has Vertical Acceleration */
+#define LOC_NAV_DATA_HAS_VERT_ACCEL ((LocPosDataMask)0x0004)
+/* Bitmask to specify whether Navigation data has Heading Rate */
+#define LOC_NAV_DATA_HAS_YAW_RATE ((LocPosDataMask)0x0008)
+/* Bitmask to specify whether Navigation data has Body pitch */
+#define LOC_NAV_DATA_HAS_PITCH ((LocPosDataMask)0x0010)
+/* Bitmask to specify whether Navigation data has Forward Acceleration Unc */
+#define LOC_NAV_DATA_HAS_LONG_ACCEL_UNC ((LocPosDataMask)0x0020)
+/* Bitmask to specify whether Navigation data has Sideward Acceleration Unc*/
+#define LOC_NAV_DATA_HAS_LAT_ACCEL_UNC ((LocPosDataMask)0x0040)
+/* Bitmask to specify whether Navigation data has Vertical Acceleration Unc*/
+#define LOC_NAV_DATA_HAS_VERT_ACCEL_UNC ((LocPosDataMask)0x0080)
+/* Bitmask to specify whether Navigation data has Heading Rate Unc*/
+#define LOC_NAV_DATA_HAS_YAW_RATE_UNC ((LocPosDataMask)0x0100)
+/* Bitmask to specify whether Navigation data has Body pitch Unc*/
+#define LOC_NAV_DATA_HAS_PITCH_UNC ((LocPosDataMask)0x0200)
+
+typedef uint32_t GnssAdditionalSystemInfoMask;
+/* Bitmask to specify whether Tauc is valid */
+#define GNSS_ADDITIONAL_SYSTEMINFO_HAS_TAUC ((GnssAdditionalSystemInfoMask)0x0001)
+/* Bitmask to specify whether leapSec is valid */
+#define GNSS_ADDITIONAL_SYSTEMINFO_HAS_LEAP_SEC ((GnssAdditionalSystemInfoMask)0x0002)
+
+
+/** GPS PRN Range */
+#define GPS_SV_PRN_MIN 1
+#define GPS_SV_PRN_MAX 32
+#define SBAS_SV_PRN_MIN 33
+#define SBAS_SV_PRN_MAX 64
+#define GLO_SV_PRN_MIN 65
+#define GLO_SV_PRN_MAX 96
+#define QZSS_SV_PRN_MIN 193
+#define QZSS_SV_PRN_MAX 197
+#define BDS_SV_PRN_MIN 201
+#define BDS_SV_PRN_MAX 235
+#define GAL_SV_PRN_MIN 301
+#define GAL_SV_PRN_MAX 336
+#define NAVIC_SV_PRN_MIN 401
+#define NAVIC_SV_PRN_MAX 414
+
+typedef enum {
+ LOC_RELIABILITY_NOT_SET = 0,
+ LOC_RELIABILITY_VERY_LOW = 1,
+ LOC_RELIABILITY_LOW = 2,
+ LOC_RELIABILITY_MEDIUM = 3,
+ LOC_RELIABILITY_HIGH = 4
+}LocReliability;
+
+typedef enum {
+ LOC_IN_EMERGENCY_UNKNOWN = 0,
+ LOC_IN_EMERGENCY_SET = 1,
+ LOC_IN_EMERGENCY_NOT_SET = 2
+}LocInEmergency;
+
+typedef struct {
+ struct timespec32_t apTimeStamp;
+ /*boottime received from pps-ktimer*/
+ float apTimeStampUncertaintyMs;
+ /* timestamp uncertainty in milli seconds */
+}Gnss_ApTimeStampStructType;
+
+typedef struct {
+ uint64_t gps_sv_used_ids_mask;
+ uint64_t glo_sv_used_ids_mask;
+ uint64_t gal_sv_used_ids_mask;
+ uint64_t bds_sv_used_ids_mask;
+ uint64_t qzss_sv_used_ids_mask;
+ uint64_t navic_sv_used_ids_mask;
+} GnssSvUsedInPosition;
+
+typedef struct {
+ uint64_t gps_l1ca_sv_used_ids_mask; // GPS L1CA
+ uint64_t gps_l1c_sv_used_ids_mask; // GPS L1C
+ uint64_t gps_l2_sv_used_ids_mask; // GPS L2
+ uint64_t gps_l5_sv_used_ids_mask; // GPS L5
+ uint64_t glo_g1_sv_used_ids_mask; // GLO G1
+ uint64_t glo_g2_sv_used_ids_mask; // GLO G2
+ uint64_t gal_e1_sv_used_ids_mask; // GAL E1
+ uint64_t gal_e5a_sv_used_ids_mask; // GAL E5A
+ uint64_t gal_e5b_sv_used_ids_mask; // GAL E5B
+ uint64_t bds_b1i_sv_used_ids_mask; // BDS B1I
+ uint64_t bds_b1c_sv_used_ids_mask; // BDS B1C
+ uint64_t bds_b2i_sv_used_ids_mask; // BDS B2I
+ uint64_t bds_b2ai_sv_used_ids_mask; // BDS B2AI
+ uint64_t qzss_l1ca_sv_used_ids_mask; // QZSS L1CA
+ uint64_t qzss_l1s_sv_used_ids_mask; // QZSS L1S
+ uint64_t qzss_l2_sv_used_ids_mask; // QZSS L2
+ uint64_t qzss_l5_sv_used_ids_mask; // QZSS L5
+ uint64_t sbas_l1_sv_used_ids_mask; // SBAS L1
+ uint64_t bds_b2aq_sv_used_ids_mask; // BDS B2AQ
+} GnssSvMbUsedInPosition;
+
+/* Body Frame parameters */
+typedef struct {
+ /** Contains Body frame LocPosDataMask bits. */
+ uint32_t bodyFrameDatamask;
+ /* Forward Acceleration in body frame (m/s2)*/
+ float longAccel;
+ /** Uncertainty of Forward Acceleration in body frame */
+ float longAccelUnc;
+ /* Sideward Acceleration in body frame (m/s2)*/
+ float latAccel;
+ /** Uncertainty of Side-ward Acceleration in body frame */
+ float latAccelUnc;
+ /* Vertical Acceleration in body frame (m/s2)*/
+ float vertAccel;
+ /** Uncertainty of Vertical Acceleration in body frame */
+ float vertAccelUnc;
+ /* Heading Rate (Radians/second) */
+ float yawRate;
+ /** Uncertainty of Heading Rate */
+ float yawRateUnc;
+ /* Body pitch (Radians) */
+ float pitch;
+ /** Uncertainty of Body pitch */
+ float pitchRadUnc;
+}LocPositionDynamics;
+
+typedef struct {
+
+ /** Position dilution of precision.
+ Range: 1 (highest accuracy) to 50 (lowest accuracy) */
+ float PDOP;
+
+ /** Horizontal dilution of precision.
+ Range: 1 (highest accuracy) to 50 (lowest accuracy) */
+ float HDOP;
+
+ /** Vertical dilution of precision.
+ Range: 1 (highest accuracy) to 50 (lowest accuracy) */
+ float VDOP;
+
+ /** geometric dilution of precision.
+ Range: 1 (highest accuracy) to 50 (lowest accuracy) */
+ float GDOP;
+
+ /** time dilution of precision.
+ Range: 1 (highest accuracy) to 50 (lowest accuracy) */
+ float TDOP;
+}LocExtDOP;
+
+/* GPS Time structure */
+typedef struct {
+
+ /**< Current GPS week as calculated from midnight, Jan. 6, 1980. \n
+ - Units: Weeks */
+ uint16_t gpsWeek;
+
+ /**< Amount of time into the current GPS week. \n
+ - Units: Milliseconds */
+ uint32_t gpsTimeOfWeekMs;
+}GPSTimeStruct;
+
+typedef uint8_t CarrierPhaseAmbiguityType;
+#define CARRIER_PHASE_AMBIGUITY_RESOLUTION_NONE ((CarrierPhaseAmbiguityType)0)
+#define CARRIER_PHASE_AMBIGUITY_RESOLUTION_FLOAT ((CarrierPhaseAmbiguityType)1)
+#define CARRIER_PHASE_AMBIGUITY_RESOLUTION_FIXED ((CarrierPhaseAmbiguityType)2)
+
+/** GNSS Signal Type and RF Band */
+typedef uint32_t GnssSignalTypeMask;
+/** GPS L1CA Signal */
+#define GNSS_SIGNAL_GPS_L1CA ((GnssSignalTypeMask)0x00000001ul)
+/** GPS L1C Signal */
+#define GNSS_SIGNAL_GPS_L1C ((GnssSignalTypeMask)0x00000002ul)
+/** GPS L2 RF Band */
+#define GNSS_SIGNAL_GPS_L2 ((GnssSignalTypeMask)0x00000004ul)
+/** GPS L5 RF Band */
+#define GNSS_SIGNAL_GPS_L5 ((GnssSignalTypeMask)0x00000008ul)
+/** GLONASS G1 (L1OF) RF Band */
+#define GNSS_SIGNAL_GLONASS_G1 ((GnssSignalTypeMask)0x00000010ul)
+/** GLONASS G2 (L2OF) RF Band */
+#define GNSS_SIGNAL_GLONASS_G2 ((GnssSignalTypeMask)0x00000020ul)
+/** GALILEO E1 RF Band */
+#define GNSS_SIGNAL_GALILEO_E1 ((GnssSignalTypeMask)0x00000040ul)
+/** GALILEO E5A RF Band */
+#define GNSS_SIGNAL_GALILEO_E5A ((GnssSignalTypeMask)0x00000080ul)
+/** GALILEO E5B RF Band */
+#define GNSS_SIGNAL_GALILIEO_E5B ((GnssSignalTypeMask)0x00000100ul)
+/** BEIDOU B1_I RF Band */
+#define GNSS_SIGNAL_BEIDOU_B1I ((GnssSignalTypeMask)0x00000200ul)
+/** BEIDOU B1C RF Band */
+#define GNSS_SIGNAL_BEIDOU_B1C ((GnssSignalTypeMask)0x00000400ul)
+/** BEIDOU B2_I RF Band */
+#define GNSS_SIGNAL_BEIDOU_B2I ((GnssSignalTypeMask)0x00000800ul)
+/** BEIDOU B2A_I RF Band */
+#define GNSS_SIGNAL_BEIDOU_B2AI ((GnssSignalTypeMask)0x00001000ul)
+/** QZSS L1CA RF Band */
+#define GNSS_SIGNAL_QZSS_L1CA ((GnssSignalTypeMask)0x00002000ul)
+/** QZSS L1S RF Band */
+#define GNSS_SIGNAL_QZSS_L1S ((GnssSignalTypeMask)0x00004000ul)
+/** QZSS L2 RF Band */
+#define GNSS_SIGNAL_QZSS_L2 ((GnssSignalTypeMask)0x00008000ul)
+/** QZSS L5 RF Band */
+#define GNSS_SIGNAL_QZSS_L5 ((GnssSignalTypeMask)0x00010000ul)
+/** SBAS L1 RF Band */
+#define GNSS_SIGNAL_SBAS_L1 ((GnssSignalTypeMask)0x00020000ul)
+/** NAVIC L5 RF Band */
+#define GNSS_SIGNAL_NAVIC_L5 ((GnssSignalTypeMask)0x00040000ul)
+/** BEIDOU B2A_Q RF Band */
+#define GNSS_SIGNAL_BEIDOU_B2AQ ((GnssSignalTypeMask)0x00080000ul)
+
+typedef uint16_t GnssMeasUsageStatusBitMask;
+/** Used in fix */
+#define GNSS_MEAS_USED_IN_PVT ((GnssMeasUsageStatusBitMask)0x00000001ul)
+/** Measurement is Bad */
+#define GNSS_MEAS_USAGE_STATUS_BAD_MEAS ((GnssMeasUsageStatusBitMask)0x00000002ul)
+/** Measurement has too low C/N */
+#define GNSS_MEAS_USAGE_STATUS_CNO_TOO_LOW ((GnssMeasUsageStatusBitMask)0x00000004ul)
+/** Measurement has too low elevation */
+#define GNSS_MEAS_USAGE_STATUS_ELEVATION_TOO_LOW ((GnssMeasUsageStatusBitMask)0x00000008ul)
+/** No ephemeris available for this measurement */
+#define GNSS_MEAS_USAGE_STATUS_NO_EPHEMERIS ((GnssMeasUsageStatusBitMask)0x00000010ul)
+/** No corrections available for the measurement */
+#define GNSS_MEAS_USAGE_STATUS_NO_CORRECTIONS ((GnssMeasUsageStatusBitMask)0x00000020ul)
+/** Corrections has timed out for the measurement */
+#define GNSS_MEAS_USAGE_STATUS_CORRECTION_TIMEOUT ((GnssMeasUsageStatusBitMask)0x00000040ul)
+/** Measurement is unhealthy */
+#define GNSS_MEAS_USAGE_STATUS_UNHEALTHY ((GnssMeasUsageStatusBitMask)0x00000080ul)
+/** Configuration is disabled for this measurement */
+#define GNSS_MEAS_USAGE_STATUS_CONFIG_DISABLED ((GnssMeasUsageStatusBitMask)0x00000100ul)
+/** Measurement not used for other reasons */
+#define GNSS_MEAS_USAGE_STATUS_OTHER ((GnssMeasUsageStatusBitMask)0x00000200ul)
+
+/** Flags to indicate valid fields in epMeasUsageInfo */
+typedef uint16_t GnssMeasUsageInfoValidityMask;
+#define GNSS_PSEUDO_RANGE_RESIDUAL_VALID ((GnssMeasUsageInfoValidityMask)0x00000001ul)
+#define GNSS_DOPPLER_RESIDUAL_VALID ((GnssMeasUsageInfoValidityMask)0x00000002ul)
+#define GNSS_CARRIER_PHASE_RESIDUAL_VALID ((GnssMeasUsageInfoValidityMask)0x00000004ul)
+#define GNSS_CARRIER_PHASE_AMBIGUITY_TYPE_VALID ((GnssMeasUsageInfoValidityMask)0x00000008ul)
+
+typedef uint16_t GnssSvPolyStatusMask;
+#define GNSS_SV_POLY_SRC_ALM_CORR_V02 ((GnssSvPolyStatusMask)0x01)
+#define GNSS_SV_POLY_GLO_STR4_V02 ((GnssSvPolyStatusMask)0x02)
+#define GNSS_SV_POLY_DELETE_V02 ((GnssSvPolyStatusMask)0x04)
+#define GNSS_SV_POLY_SRC_GAL_FNAV_OR_INAV_V02 ((GnssSvPolyStatusMask)0x08)
+typedef uint16_t GnssSvPolyStatusMaskValidity;
+#define GNSS_SV_POLY_SRC_ALM_CORR_VALID_V02 ((GnssSvPolyStatusMaskValidity)0x01)
+#define GNSS_SV_POLY_GLO_STR4_VALID_V02 ((GnssSvPolyStatusMaskValidity)0x02)
+#define GNSS_SV_POLY_DELETE_VALID_V02 ((GnssSvPolyStatusMaskValidity)0x04)
+#define GNSS_SV_POLY_SRC_GAL_FNAV_OR_INAV_VALID_V02 ((GnssSvPolyStatusMaskValidity)0x08)
+
+
+typedef struct {
+ /** Specifies GNSS signal type
+ Mandatory Field*/
+ GnssSignalTypeMask gnssSignalType;
+ /** Specifies GNSS Constellation Type
+ Mandatory Field*/
+ Gnss_LocSvSystemEnumType gnssConstellation;
+ /** GNSS SV ID.
+ For GPS: 1 to 32
+ For GLONASS: 65 to 96. When slot-number to SV ID mapping is unknown, set as 255.
+ For SBAS: 120 to 151
+ For QZSS-L1CA:193 to 197
+ For BDS: 201 to 237
+ For GAL: 301 to 336 */
+ uint16_t gnssSvId;
+ /** GLONASS frequency number + 7.
+ Valid only for a GLONASS system and
+ is to be ignored for all other systems.
+ Range: 1 to 14 */
+ uint8_t gloFrequency;
+ /** Carrier phase ambiguity type. */
+ CarrierPhaseAmbiguityType carrierPhaseAmbiguityType;
+ /** Validity mask */
+ GnssMeasUsageStatusBitMask measUsageStatusMask;
+ /** Specifies measurement usage status
+ Mandatory Field*/
+ GnssMeasUsageInfoValidityMask validityMask;
+ /** Computed pseudorange residual.
+ Unit: Meters */
+ float pseudorangeResidual;
+ /** Computed doppler residual.
+ Unit: Meters/sec*/
+ float dopplerResidual;
+ /** Computed carrier phase residual.
+ Unit: Cycles*/
+ float carrierPhaseResidual;
+ /** Carrier phase ambiguity value.
+ Unit: Cycles*/
+ float carrierPhasAmbiguity;
+} GpsMeasUsageInfo;
+
+
+/** Represents gps location extended. */
+typedef struct {
+ /** set to sizeof(GpsLocationExtended) */
+ uint32_t size;
+ /** Contains GpsLocationExtendedFlags bits. */
+ uint64_t flags;
+ /** Contains the Altitude wrt mean sea level */
+ float altitudeMeanSeaLevel;
+ /** Contains Position Dilusion of Precision. */
+ float pdop;
+ /** Contains Horizontal Dilusion of Precision. */
+ float hdop;
+ /** Contains Vertical Dilusion of Precision. */
+ float vdop;
+ /** Contains Magnetic Deviation. */
+ float magneticDeviation;
+ /** vertical uncertainty in meters */
+ float vert_unc;
+ /** speed uncertainty in m/s */
+ float speed_unc;
+ /** heading uncertainty in degrees (0 to 359.999) */
+ float bearing_unc;
+ /** horizontal reliability. */
+ LocReliability horizontal_reliability;
+ /** vertical reliability. */
+ LocReliability vertical_reliability;
+ /* Horizontal Elliptical Uncertainty (Semi-Major Axis) */
+ float horUncEllipseSemiMajor;
+ /* Horizontal Elliptical Uncertainty (Semi-Minor Axis) */
+ float horUncEllipseSemiMinor;
+ /* Elliptical Horizontal Uncertainty Azimuth */
+ float horUncEllipseOrientAzimuth;
+
+ Gnss_ApTimeStampStructType timeStamp;
+ /** Gnss sv used in position data */
+ GnssSvUsedInPosition gnss_sv_used_ids;
+ /** Gnss sv used in position data for multiband */
+ GnssSvMbUsedInPosition gnss_mb_sv_used_ids;
+ /** Nav solution mask to indicate sbas corrections */
+ LocNavSolutionMask navSolutionMask;
+ /** Position technology used in computing this fix */
+ LocPosTechMask tech_mask;
+ /** SV Info source used in computing this fix */
+ LocSvInfoSource sv_source;
+ /** Body Frame Dynamics: 4wayAcceleration and pitch set with validity */
+ GnssLocationPositionDynamics bodyFrameData;
+ /** GPS Time */
+ GPSTimeStruct gpsTime;
+ GnssSystemTime gnssSystemTime;
+ /** Dilution of precision associated with this position*/
+ LocExtDOP extDOP;
+ /** North standard deviation.
+ Unit: Meters */
+ float northStdDeviation;
+ /** East standard deviation.
+ Unit: Meters */
+ float eastStdDeviation;
+ /** North Velocity.
+ Unit: Meters/sec */
+ float northVelocity;
+ /** East Velocity.
+ Unit: Meters/sec */
+ float eastVelocity;
+ /** Up Velocity.
+ Unit: Meters/sec */
+ float upVelocity;
+ /** North Velocity standard deviation.
+ Unit: Meters/sec */
+ float northVelocityStdDeviation;
+ /** East Velocity standard deviation.
+ Unit: Meters/sec */
+ float eastVelocityStdDeviation;
+ /** Up Velocity standard deviation
+ Unit: Meters/sec */
+ float upVelocityStdDeviation;
+ /** Estimated clock bias. Unit: Nano seconds */
+ float clockbiasMeter;
+ /** Estimated clock bias std deviation. Unit: Nano seconds */
+ float clockBiasStdDeviationMeter;
+ /** Estimated clock drift. Unit: Meters/sec */
+ float clockDrift;
+ /** Estimated clock drift std deviation. Unit: Meters/sec */
+ float clockDriftStdDeviation;
+ /** Number of valid reference stations. Range:[0-4] */
+ uint8_t numValidRefStations;
+ /** Reference station(s) number */
+ uint16_t referenceStation[4];
+ /** Number of measurements received for use in fix.
+ Shall be used as maximum index in-to svUsageInfo[].
+ Set to 0, if svUsageInfo reporting is not supported.
+ Range: 0-EP_GNSS_MAX_MEAS */
+ uint8_t numOfMeasReceived;
+ /** Measurement Usage Information */
+ GpsMeasUsageInfo measUsageInfo[GNSS_SV_MAX];
+ /** Leap Seconds */
+ uint8_t leapSeconds;
+ /** Time uncertainty in milliseconds */
+ float timeUncMs;
+ /** Heading Rate is in NED frame.
+ Range: 0 to 359.999. 946
+ Unit: Degrees per Seconds */
+ float headingRateDeg;
+ /** Sensor calibration confidence percent. Range: 0 - 100 */
+ uint8_t calibrationConfidence;
+ DrCalibrationStatusMask calibrationStatus;
+ /* location engine type. When the fix. when the type is set to
+ LOC_ENGINE_SRC_FUSED, the fix is the propagated/aggregated
+ reports from all engines running on the system (e.g.:
+ DR/SPE/PPE). To check which location engine contributes to
+ the fused output, check for locOutputEngMask. */
+ LocOutputEngineType locOutputEngType;
+ /* when loc output eng type is set to fused, this field
+ indicates the set of engines contribute to the fix. */
+ PositioningEngineMask locOutputEngMask;
+} GpsLocationExtended;
+
+enum loc_sess_status {
+ LOC_SESS_SUCCESS,
+ LOC_SESS_INTERMEDIATE,
+ LOC_SESS_FAILURE
+};
+
+// struct that contains complete position info from engine
+typedef struct {
+ UlpLocation location;
+ GpsLocationExtended locationExtended;
+ enum loc_sess_status sessionStatus;
+} EngineLocationInfo;
+
+// Nmea sentence types mask
+typedef uint32_t NmeaSentenceTypesMask;
+#define LOC_NMEA_MASK_GGA_V02 ((NmeaSentenceTypesMask)0x00000001) /**< Enable GGA type */
+#define LOC_NMEA_MASK_RMC_V02 ((NmeaSentenceTypesMask)0x00000002) /**< Enable RMC type */
+#define LOC_NMEA_MASK_GSV_V02 ((NmeaSentenceTypesMask)0x00000004) /**< Enable GSV type */
+#define LOC_NMEA_MASK_GSA_V02 ((NmeaSentenceTypesMask)0x00000008) /**< Enable GSA type */
+#define LOC_NMEA_MASK_VTG_V02 ((NmeaSentenceTypesMask)0x00000010) /**< Enable VTG type */
+#define LOC_NMEA_MASK_PQXFI_V02 ((NmeaSentenceTypesMask)0x00000020) /**< Enable PQXFI type */
+#define LOC_NMEA_MASK_PSTIS_V02 ((NmeaSentenceTypesMask)0x00000040) /**< Enable PSTIS type */
+#define LOC_NMEA_MASK_GLGSV_V02 ((NmeaSentenceTypesMask)0x00000080) /**< Enable GLGSV type */
+#define LOC_NMEA_MASK_GNGSA_V02 ((NmeaSentenceTypesMask)0x00000100) /**< Enable GNGSA type */
+#define LOC_NMEA_MASK_GNGNS_V02 ((NmeaSentenceTypesMask)0x00000200) /**< Enable GNGNS type */
+#define LOC_NMEA_MASK_GARMC_V02 ((NmeaSentenceTypesMask)0x00000400) /**< Enable GARMC type */
+#define LOC_NMEA_MASK_GAGSV_V02 ((NmeaSentenceTypesMask)0x00000800) /**< Enable GAGSV type */
+#define LOC_NMEA_MASK_GAGSA_V02 ((NmeaSentenceTypesMask)0x00001000) /**< Enable GAGSA type */
+#define LOC_NMEA_MASK_GAVTG_V02 ((NmeaSentenceTypesMask)0x00002000) /**< Enable GAVTG type */
+#define LOC_NMEA_MASK_GAGGA_V02 ((NmeaSentenceTypesMask)0x00004000) /**< Enable GAGGA type */
+#define LOC_NMEA_MASK_PQGSA_V02 ((NmeaSentenceTypesMask)0x00008000) /**< Enable PQGSA type */
+#define LOC_NMEA_MASK_PQGSV_V02 ((NmeaSentenceTypesMask)0x00010000) /**< Enable PQGSV type */
+#define LOC_NMEA_MASK_DEBUG_V02 ((NmeaSentenceTypesMask)0x00020000) /**< Enable DEBUG type */
+#define LOC_NMEA_MASK_GPDTM_V02 ((NmeaSentenceTypesMask)0x00040000) /**< Enable GPDTM type */
+#define LOC_NMEA_MASK_GNGGA_V02 ((NmeaSentenceTypesMask)0x00080000) /**< Enable GNGGA type */
+#define LOC_NMEA_MASK_GNRMC_V02 ((NmeaSentenceTypesMask)0x00100000) /**< Enable GNRMC type */
+#define LOC_NMEA_MASK_GNVTG_V02 ((NmeaSentenceTypesMask)0x00200000) /**< Enable GNVTG type */
+#define LOC_NMEA_MASK_GAGNS_V02 ((NmeaSentenceTypesMask)0x00400000) /**< Enable GAGNS type */
+#define LOC_NMEA_MASK_GBGGA_V02 ((NmeaSentenceTypesMask)0x00800000) /**< Enable GBGGA type */
+#define LOC_NMEA_MASK_GBGSA_V02 ((NmeaSentenceTypesMask)0x01000000) /**< Enable GBGSA type */
+#define LOC_NMEA_MASK_GBGSV_V02 ((NmeaSentenceTypesMask)0x02000000) /**< Enable GBGSV type */
+#define LOC_NMEA_MASK_GBRMC_V02 ((NmeaSentenceTypesMask)0x04000000) /**< Enable GBRMC type */
+#define LOC_NMEA_MASK_GBVTG_V02 ((NmeaSentenceTypesMask)0x08000000) /**< Enable GBVTG type */
+#define LOC_NMEA_MASK_GQGSV_V02 ((NmeaSentenceTypesMask)0x10000000) /**< Enable GQGSV type */
+#define LOC_NMEA_MASK_GIGSV_V02 ((NmeaSentenceTypesMask)0x20000000) /**< Enable GIGSV type */
+#define LOC_NMEA_MASK_GNDTM_V02 ((NmeaSentenceTypesMask)0x40000000) /**< Enable GNDTM type */
+
+
+// all bitmasks of general supported NMEA sentenses - debug is not part of this
+#define LOC_NMEA_ALL_GENERAL_SUPPORTED_MASK (LOC_NMEA_MASK_GGA_V02 | LOC_NMEA_MASK_RMC_V02 | \
+ LOC_NMEA_MASK_GSV_V02 | LOC_NMEA_MASK_GSA_V02 | LOC_NMEA_MASK_VTG_V02 | \
+ LOC_NMEA_MASK_PQXFI_V02 | LOC_NMEA_MASK_PSTIS_V02 | LOC_NMEA_MASK_GLGSV_V02 | \
+ LOC_NMEA_MASK_GNGSA_V02 | LOC_NMEA_MASK_GNGNS_V02 | LOC_NMEA_MASK_GARMC_V02 | \
+ LOC_NMEA_MASK_GAGSV_V02 | LOC_NMEA_MASK_GAGSA_V02 | LOC_NMEA_MASK_GAVTG_V02 | \
+ LOC_NMEA_MASK_GAGGA_V02 | LOC_NMEA_MASK_PQGSA_V02 | LOC_NMEA_MASK_PQGSV_V02 | \
+ LOC_NMEA_MASK_GPDTM_V02 | LOC_NMEA_MASK_GNGGA_V02 | LOC_NMEA_MASK_GNRMC_V02 | \
+ LOC_NMEA_MASK_GNVTG_V02 | LOC_NMEA_MASK_GAGNS_V02 | LOC_NMEA_MASK_GBGGA_V02 | \
+ LOC_NMEA_MASK_GBGSA_V02 | LOC_NMEA_MASK_GBGSV_V02 | LOC_NMEA_MASK_GBRMC_V02 | \
+ LOC_NMEA_MASK_GBVTG_V02 | LOC_NMEA_MASK_GQGSV_V02 | LOC_NMEA_MASK_GIGSV_V02 | \
+ LOC_NMEA_MASK_GNDTM_V02)
+
+typedef enum {
+ LOC_ENG_IF_REQUEST_SENDER_ID_QUIPC = 0,
+ LOC_ENG_IF_REQUEST_SENDER_ID_MSAPM,
+ LOC_ENG_IF_REQUEST_SENDER_ID_MSAPU,
+ LOC_ENG_IF_REQUEST_SENDER_ID_GPSONE_DAEMON,
+ LOC_ENG_IF_REQUEST_SENDER_ID_MODEM,
+ LOC_ENG_IF_REQUEST_SENDER_ID_UNKNOWN
+} loc_if_req_sender_id_e_type;
+
+
+#define smaller_of(a, b) (((a) > (b)) ? (b) : (a))
+#define MAX_APN_LEN 100
+
+// This will be overridden by the individual adapters
+// if necessary.
+#define DEFAULT_IMPL(rtv) \
+{ \
+ LOC_LOGD("%s: default implementation invoked", __func__); \
+ return rtv; \
+}
+
+enum loc_api_adapter_err {
+ LOC_API_ADAPTER_ERR_SUCCESS = 0,
+ LOC_API_ADAPTER_ERR_GENERAL_FAILURE = 1,
+ LOC_API_ADAPTER_ERR_UNSUPPORTED = 2,
+ LOC_API_ADAPTER_ERR_INVALID_HANDLE = 4,
+ LOC_API_ADAPTER_ERR_INVALID_PARAMETER = 5,
+ LOC_API_ADAPTER_ERR_ENGINE_BUSY = 6,
+ LOC_API_ADAPTER_ERR_PHONE_OFFLINE = 7,
+ LOC_API_ADAPTER_ERR_TIMEOUT = 8,
+ LOC_API_ADAPTER_ERR_SERVICE_NOT_PRESENT = 9,
+ LOC_API_ADAPTER_ERR_INTERNAL = 10,
+
+ /* equating engine down to phone offline, as they are the same errror */
+ LOC_API_ADAPTER_ERR_ENGINE_DOWN = LOC_API_ADAPTER_ERR_PHONE_OFFLINE,
+ LOC_API_ADAPTER_ERR_FAILURE = 101,
+ LOC_API_ADAPTER_ERR_UNKNOWN
+};
+
+enum loc_api_adapter_event_index {
+ LOC_API_ADAPTER_REPORT_POSITION = 0, // Position report comes in loc_parsed_position_s_type
+ LOC_API_ADAPTER_REPORT_SATELLITE, // Satellite in view report
+ LOC_API_ADAPTER_REPORT_NMEA_1HZ, // NMEA report at 1HZ rate
+ LOC_API_ADAPTER_REPORT_NMEA_POSITION, // NMEA report at position report rate
+ LOC_API_ADAPTER_REQUEST_NI_NOTIFY_VERIFY, // NI notification/verification request
+ LOC_API_ADAPTER_REQUEST_ASSISTANCE_DATA, // Assistance data, eg: time, predicted orbits request
+ LOC_API_ADAPTER_REQUEST_LOCATION_SERVER, // Request for location server
+ LOC_API_ADAPTER_REPORT_IOCTL, // Callback report for loc_ioctl
+ LOC_API_ADAPTER_REPORT_STATUS, // Misc status report: eg, engine state
+ LOC_API_ADAPTER_REQUEST_WIFI, //
+ LOC_API_ADAPTER_SENSOR_STATUS, //
+ LOC_API_ADAPTER_REQUEST_TIME_SYNC, //
+ LOC_API_ADAPTER_REPORT_SPI, //
+ LOC_API_ADAPTER_REPORT_NI_GEOFENCE, //
+ LOC_API_ADAPTER_GEOFENCE_GEN_ALERT, //
+ LOC_API_ADAPTER_REPORT_GENFENCE_BREACH, //
+ LOC_API_ADAPTER_PEDOMETER_CTRL, //
+ LOC_API_ADAPTER_MOTION_CTRL, //
+ LOC_API_ADAPTER_REQUEST_WIFI_AP_DATA, // Wifi ap data
+ LOC_API_ADAPTER_BATCH_FULL, // Batching on full
+ LOC_API_ADAPTER_BATCHED_POSITION_REPORT, // Batching on fix
+ LOC_API_ADAPTER_BATCHED_GENFENCE_BREACH_REPORT, //
+ LOC_API_ADAPTER_GNSS_MEASUREMENT_REPORT, // GNSS Measurement Report
+ LOC_API_ADAPTER_GNSS_SV_POLYNOMIAL_REPORT, // GNSS SV Polynomial Report
+ LOC_API_ADAPTER_GDT_UPLOAD_BEGIN_REQ, // GDT upload start request
+ LOC_API_ADAPTER_GDT_UPLOAD_END_REQ, // GDT upload end request
+ LOC_API_ADAPTER_GNSS_MEASUREMENT, // GNSS Measurement report
+ LOC_API_ADAPTER_REQUEST_TIMEZONE, // Timezone injection request
+ LOC_API_ADAPTER_REPORT_GENFENCE_DWELL_REPORT, // Geofence dwell report
+ LOC_API_ADAPTER_REQUEST_SRN_DATA, // request srn data from AP
+ LOC_API_ADAPTER_REQUEST_POSITION_INJECTION, // Position injection request
+ LOC_API_ADAPTER_BATCH_STATUS, // batch status
+ LOC_API_ADAPTER_FDCL_SERVICE_REQ, // FDCL service request
+ LOC_API_ADAPTER_REPORT_UNPROPAGATED_POSITION, // Unpropagated Position report
+ LOC_API_ADAPTER_BS_OBS_DATA_SERVICE_REQ, // BS observation data request
+ LOC_API_ADAPTER_GNSS_SV_EPHEMERIS_REPORT, // GNSS SV Ephemeris Report
+ LOC_API_ADAPTER_LOC_SYSTEM_INFO, // Location system info event
+ LOC_API_ADAPTER_GNSS_NHZ_MEASUREMENT_REPORT, // GNSS SV nHz measurement report
+ LOC_API_ADAPTER_EVENT_REPORT_INFO, // Event report info
+ LOC_API_ADAPTER_EVENT_MAX
+};
+
+#define LOC_API_ADAPTER_BIT_PARSED_POSITION_REPORT (1<<LOC_API_ADAPTER_REPORT_POSITION)
+#define LOC_API_ADAPTER_BIT_SATELLITE_REPORT (1<<LOC_API_ADAPTER_REPORT_SATELLITE)
+#define LOC_API_ADAPTER_BIT_NMEA_1HZ_REPORT (1<<LOC_API_ADAPTER_REPORT_NMEA_1HZ)
+#define LOC_API_ADAPTER_BIT_NMEA_POSITION_REPORT (1<<LOC_API_ADAPTER_REPORT_NMEA_POSITION)
+#define LOC_API_ADAPTER_BIT_NI_NOTIFY_VERIFY_REQUEST (1<<LOC_API_ADAPTER_REQUEST_NI_NOTIFY_VERIFY)
+#define LOC_API_ADAPTER_BIT_ASSISTANCE_DATA_REQUEST (1<<LOC_API_ADAPTER_REQUEST_ASSISTANCE_DATA)
+#define LOC_API_ADAPTER_BIT_LOCATION_SERVER_REQUEST (1<<LOC_API_ADAPTER_REQUEST_LOCATION_SERVER)
+#define LOC_API_ADAPTER_BIT_IOCTL_REPORT (1<<LOC_API_ADAPTER_REPORT_IOCTL)
+#define LOC_API_ADAPTER_BIT_STATUS_REPORT (1<<LOC_API_ADAPTER_REPORT_STATUS)
+#define LOC_API_ADAPTER_BIT_REQUEST_WIFI (1<<LOC_API_ADAPTER_REQUEST_WIFI)
+#define LOC_API_ADAPTER_BIT_SENSOR_STATUS (1<<LOC_API_ADAPTER_SENSOR_STATUS)
+#define LOC_API_ADAPTER_BIT_REQUEST_TIME_SYNC (1<<LOC_API_ADAPTER_REQUEST_TIME_SYNC)
+#define LOC_API_ADAPTER_BIT_REPORT_SPI (1<<LOC_API_ADAPTER_REPORT_SPI)
+#define LOC_API_ADAPTER_BIT_REPORT_NI_GEOFENCE (1<<LOC_API_ADAPTER_REPORT_NI_GEOFENCE)
+#define LOC_API_ADAPTER_BIT_GEOFENCE_GEN_ALERT (1<<LOC_API_ADAPTER_GEOFENCE_GEN_ALERT)
+#define LOC_API_ADAPTER_BIT_REPORT_GENFENCE_BREACH (1<<LOC_API_ADAPTER_REPORT_GENFENCE_BREACH)
+#define LOC_API_ADAPTER_BIT_BATCHED_GENFENCE_BREACH_REPORT (1<<LOC_API_ADAPTER_BATCHED_GENFENCE_BREACH_REPORT)
+#define LOC_API_ADAPTER_BIT_PEDOMETER_CTRL (1<<LOC_API_ADAPTER_PEDOMETER_CTRL)
+#define LOC_API_ADAPTER_BIT_MOTION_CTRL (1<<LOC_API_ADAPTER_MOTION_CTRL)
+#define LOC_API_ADAPTER_BIT_REQUEST_WIFI_AP_DATA (1<<LOC_API_ADAPTER_REQUEST_WIFI_AP_DATA)
+#define LOC_API_ADAPTER_BIT_BATCH_FULL (1<<LOC_API_ADAPTER_BATCH_FULL)
+#define LOC_API_ADAPTER_BIT_BATCHED_POSITION_REPORT (1<<LOC_API_ADAPTER_BATCHED_POSITION_REPORT)
+#define LOC_API_ADAPTER_BIT_GNSS_MEASUREMENT_REPORT (1<<LOC_API_ADAPTER_GNSS_MEASUREMENT_REPORT)
+#define LOC_API_ADAPTER_BIT_GNSS_SV_POLYNOMIAL_REPORT (1<<LOC_API_ADAPTER_GNSS_SV_POLYNOMIAL_REPORT)
+#define LOC_API_ADAPTER_BIT_GDT_UPLOAD_BEGIN_REQ (1<<LOC_API_ADAPTER_GDT_UPLOAD_BEGIN_REQ)
+#define LOC_API_ADAPTER_BIT_GDT_UPLOAD_END_REQ (1<<LOC_API_ADAPTER_GDT_UPLOAD_END_REQ)
+#define LOC_API_ADAPTER_BIT_GNSS_MEASUREMENT (1<<LOC_API_ADAPTER_GNSS_MEASUREMENT)
+#define LOC_API_ADAPTER_BIT_REQUEST_TIMEZONE (1<<LOC_API_ADAPTER_REQUEST_TIMEZONE)
+#define LOC_API_ADAPTER_BIT_REPORT_GENFENCE_DWELL (1<<LOC_API_ADAPTER_REPORT_GENFENCE_DWELL_REPORT)
+#define LOC_API_ADAPTER_BIT_REQUEST_SRN_DATA (1<<LOC_API_ADAPTER_REQUEST_SRN_DATA)
+#define LOC_API_ADAPTER_BIT_POSITION_INJECTION_REQUEST (1<<LOC_API_ADAPTER_REQUEST_POSITION_INJECTION)
+#define LOC_API_ADAPTER_BIT_BATCH_STATUS (1<<LOC_API_ADAPTER_BATCH_STATUS)
+#define LOC_API_ADAPTER_BIT_FDCL_SERVICE_REQ (1ULL<<LOC_API_ADAPTER_FDCL_SERVICE_REQ)
+#define LOC_API_ADAPTER_BIT_PARSED_UNPROPAGATED_POSITION_REPORT (1ULL<<LOC_API_ADAPTER_REPORT_UNPROPAGATED_POSITION)
+#define LOC_API_ADAPTER_BIT_BS_OBS_DATA_SERVICE_REQ (1ULL<<LOC_API_ADAPTER_BS_OBS_DATA_SERVICE_REQ)
+#define LOC_API_ADAPTER_BIT_GNSS_SV_EPHEMERIS_REPORT (1ULL<<LOC_API_ADAPTER_GNSS_SV_EPHEMERIS_REPORT)
+#define LOC_API_ADAPTER_BIT_LOC_SYSTEM_INFO (1ULL<<LOC_API_ADAPTER_LOC_SYSTEM_INFO)
+#define LOC_API_ADAPTER_BIT_GNSS_NHZ_MEASUREMENT (1ULL<<LOC_API_ADAPTER_GNSS_NHZ_MEASUREMENT_REPORT)
+#define LOC_API_ADAPTER_BIT_EVENT_REPORT_INFO (1ULL<<LOC_API_ADAPTER_EVENT_REPORT_INFO)
+
+typedef uint64_t LOC_API_ADAPTER_EVENT_MASK_T;
+
+typedef enum loc_api_adapter_msg_to_check_supported {
+ LOC_API_ADAPTER_MESSAGE_LOCATION_BATCHING, // Batching 1.0
+ LOC_API_ADAPTER_MESSAGE_BATCHED_GENFENCE_BREACH, // Geofence Batched Breach
+ LOC_API_ADAPTER_MESSAGE_DISTANCE_BASE_TRACKING, // DBT 2.0
+ LOC_API_ADAPTER_MESSAGE_ADAPTIVE_LOCATION_BATCHING, // Batching 1.5
+ LOC_API_ADAPTER_MESSAGE_DISTANCE_BASE_LOCATION_BATCHING, // Batching 2.0
+ LOC_API_ADAPTER_MESSAGE_UPDATE_TBF_ON_THE_FLY, // Updating Tracking TBF On The Fly
+ LOC_API_ADAPTER_MESSAGE_OUTDOOR_TRIP_BATCHING, // Outdoor Trip Batching
+
+ LOC_API_ADAPTER_MESSAGE_MAX
+} LocCheckingMessagesID;
+
+typedef int IzatDevId_t;
+
+typedef uint32_t LOC_GPS_LOCK_MASK;
+#define isGpsLockNone(lock) ((lock) == 0)
+#define isGpsLockMO(lock) ((lock) & ((LOC_GPS_LOCK_MASK)1))
+#define isGpsLockMT(lock) ((lock) & ((LOC_GPS_LOCK_MASK)2))
+#define isGpsLockAll(lock) (((lock) & ((LOC_GPS_LOCK_MASK)3)) == 3)
+
+/*++ ***********************************************
+** Satellite Measurement and Satellite Polynomial
+** Structure definitions
+** ***********************************************
+--*/
+#define GNSS_SV_POLY_VELOCITY_COEF_MAX_SIZE 12
+#define GNSS_SV_POLY_XYZ_0_TH_ORDER_COEFF_MAX_SIZE 3
+#define GNSS_SV_POLY_XYZ_N_TH_ORDER_COEFF_MAX_SIZE 9
+#define GNSS_SV_POLY_SV_CLKBIAS_COEFF_MAX_SIZE 4
+/** Max number of GNSS SV measurement */
+#define GNSS_LOC_SV_MEAS_LIST_MAX_SIZE 128
+
+enum ulp_gnss_sv_measurement_valid_flags{
+
+ ULP_GNSS_SV_MEAS_GPS_TIME = 0,
+ ULP_GNSS_SV_MEAS_PSUEDO_RANGE,
+ ULP_GNSS_SV_MEAS_MS_IN_WEEK,
+ ULP_GNSS_SV_MEAS_SUB_MSEC,
+ ULP_GNSS_SV_MEAS_CARRIER_PHASE,
+ ULP_GNSS_SV_MEAS_DOPPLER_SHIFT,
+ ULP_GNSS_SV_MEAS_CNO,
+ ULP_GNSS_SV_MEAS_LOSS_OF_LOCK,
+
+ ULP_GNSS_SV_MEAS_MAX_VALID_FLAGS
+};
+
+#define ULP_GNSS_SV_MEAS_BIT_GPS_TIME (1<<ULP_GNSS_SV_MEAS_GPS_TIME)
+#define ULP_GNSS_SV_MEAS_BIT_PSUEDO_RANGE (1<<ULP_GNSS_SV_MEAS_PSUEDO_RANGE)
+#define ULP_GNSS_SV_MEAS_BIT_MS_IN_WEEK (1<<ULP_GNSS_SV_MEAS_MS_IN_WEEK)
+#define ULP_GNSS_SV_MEAS_BIT_SUB_MSEC (1<<ULP_GNSS_SV_MEAS_SUB_MSEC)
+#define ULP_GNSS_SV_MEAS_BIT_CARRIER_PHASE (1<<ULP_GNSS_SV_MEAS_CARRIER_PHASE)
+#define ULP_GNSS_SV_MEAS_BIT_DOPPLER_SHIFT (1<<ULP_GNSS_SV_MEAS_DOPPLER_SHIFT)
+#define ULP_GNSS_SV_MEAS_BIT_CNO (1<<ULP_GNSS_SV_MEAS_CNO)
+#define ULP_GNSS_SV_MEAS_BIT_LOSS_OF_LOCK (1<<ULP_GNSS_SV_MEAS_LOSS_OF_LOCK)
+
+enum ulp_gnss_sv_poly_valid_flags{
+
+ ULP_GNSS_SV_POLY_GLO_FREQ = 0,
+ ULP_GNSS_SV_POLY_T0,
+ ULP_GNSS_SV_POLY_IODE,
+ ULP_GNSS_SV_POLY_FLAG,
+ ULP_GNSS_SV_POLY_POLYCOEFF_XYZ0,
+ ULP_GNSS_SV_POLY_POLYCOEFF_XYZN,
+ ULP_GNSS_SV_POLY_POLYCOEFF_OTHER,
+ ULP_GNSS_SV_POLY_SV_POSUNC,
+ ULP_GNSS_SV_POLY_IONODELAY,
+ ULP_GNSS_SV_POLY_IONODOT,
+ ULP_GNSS_SV_POLY_SBAS_IONODELAY,
+ ULP_GNSS_SV_POLY_SBAS_IONODOT,
+ ULP_GNSS_SV_POLY_TROPODELAY,
+ ULP_GNSS_SV_POLY_ELEVATION,
+ ULP_GNSS_SV_POLY_ELEVATIONDOT,
+ ULP_GNSS_SV_POLY_ELEVATIONUNC,
+ ULP_GNSS_SV_POLY_VELO_COEFF,
+ ULP_GNSS_SV_POLY_ENHANCED_IOD,
+ ULP_GNSS_SV_POLY_GPS_ISC_L1CA,
+ ULP_GNSS_SV_POLY_GPS_ISC_L2C,
+ ULP_GNSS_SV_POLY_GPS_ISC_L5I5,
+ ULP_GNSS_SV_POLY_GPS_ISC_L5Q5,
+ ULP_GNSS_SV_POLY_GPS_TGD,
+ ULP_GNSS_SV_POLY_GLO_TGD_G1G2,
+ ULP_GNSS_SV_POLY_BDS_TGD_B1,
+ ULP_GNSS_SV_POLY_BDS_TGD_B2,
+ ULP_GNSS_SV_POLY_BDS_TGD_B2A,
+ ULP_GNSS_SV_POLY_BDS_ISC_B2A,
+ ULP_GNSS_SV_POLY_GAL_BGD_E1E5A,
+ ULP_GNSS_SV_POLY_GAL_BGD_E1E5B,
+ ULP_GNSS_SV_POLY_NAVIC_TGD_L5
+};
+
+#define ULP_GNSS_SV_POLY_BIT_GLO_FREQ (1<<ULP_GNSS_SV_POLY_GLO_FREQ)
+#define ULP_GNSS_SV_POLY_BIT_T0 (1<<ULP_GNSS_SV_POLY_T0)
+#define ULP_GNSS_SV_POLY_BIT_IODE (1<<ULP_GNSS_SV_POLY_IODE)
+#define ULP_GNSS_SV_POLY_BIT_FLAG (1<<ULP_GNSS_SV_POLY_FLAG)
+#define ULP_GNSS_SV_POLY_BIT_POLYCOEFF_XYZ0 (1<<ULP_GNSS_SV_POLY_POLYCOEFF_XYZ0)
+#define ULP_GNSS_SV_POLY_BIT_POLYCOEFF_XYZN (1<<ULP_GNSS_SV_POLY_POLYCOEFF_XYZN)
+#define ULP_GNSS_SV_POLY_BIT_POLYCOEFF_OTHER (1<<ULP_GNSS_SV_POLY_POLYCOEFF_OTHER)
+#define ULP_GNSS_SV_POLY_BIT_SV_POSUNC (1<<ULP_GNSS_SV_POLY_SV_POSUNC)
+#define ULP_GNSS_SV_POLY_BIT_IONODELAY (1<<ULP_GNSS_SV_POLY_IONODELAY)
+#define ULP_GNSS_SV_POLY_BIT_IONODOT (1<<ULP_GNSS_SV_POLY_IONODOT)
+#define ULP_GNSS_SV_POLY_BIT_SBAS_IONODELAY (1<<ULP_GNSS_SV_POLY_SBAS_IONODELAY)
+#define ULP_GNSS_SV_POLY_BIT_SBAS_IONODOT (1<<ULP_GNSS_SV_POLY_SBAS_IONODOT)
+#define ULP_GNSS_SV_POLY_BIT_TROPODELAY (1<<ULP_GNSS_SV_POLY_TROPODELAY)
+#define ULP_GNSS_SV_POLY_BIT_ELEVATION (1<<ULP_GNSS_SV_POLY_ELEVATION)
+#define ULP_GNSS_SV_POLY_BIT_ELEVATIONDOT (1<<ULP_GNSS_SV_POLY_ELEVATIONDOT)
+#define ULP_GNSS_SV_POLY_BIT_ELEVATIONUNC (1<<ULP_GNSS_SV_POLY_ELEVATIONUNC)
+#define ULP_GNSS_SV_POLY_BIT_VELO_COEFF (1<<ULP_GNSS_SV_POLY_VELO_COEFF)
+#define ULP_GNSS_SV_POLY_BIT_ENHANCED_IOD (1<<ULP_GNSS_SV_POLY_ENHANCED_IOD)
+#define ULP_GNSS_SV_POLY_BIT_GPS_ISC_L1CA (1<<ULP_GNSS_SV_POLY_GPS_ISC_L1CA)
+#define ULP_GNSS_SV_POLY_BIT_GPS_ISC_L2C (1<<ULP_GNSS_SV_POLY_GPS_ISC_L2C)
+#define ULP_GNSS_SV_POLY_BIT_GPS_ISC_L5I5 (1<<ULP_GNSS_SV_POLY_GPS_ISC_L5I5)
+#define ULP_GNSS_SV_POLY_BIT_GPS_ISC_L5Q5 (1<<ULP_GNSS_SV_POLY_GPS_ISC_L5Q5)
+#define ULP_GNSS_SV_POLY_BIT_GPS_TGD (1<<ULP_GNSS_SV_POLY_GPS_TGD)
+#define ULP_GNSS_SV_POLY_BIT_GLO_TGD_G1G2 (1<<ULP_GNSS_SV_POLY_GLO_TGD_G1G2)
+#define ULP_GNSS_SV_POLY_BIT_BDS_TGD_B1 (1<<ULP_GNSS_SV_POLY_BDS_TGD_B1)
+#define ULP_GNSS_SV_POLY_BIT_BDS_TGD_B2 (1<<ULP_GNSS_SV_POLY_BDS_TGD_B2)
+#define ULP_GNSS_SV_POLY_BIT_BDS_TGD_B2A (1<<ULP_GNSS_SV_POLY_BDS_TGD_B2A)
+#define ULP_GNSS_SV_POLY_BIT_BDS_ISC_B2A (1<<ULP_GNSS_SV_POLY_BDS_ISC_B2A)
+#define ULP_GNSS_SV_POLY_BIT_GAL_BGD_E1E5A (1<<ULP_GNSS_SV_POLY_GAL_BGD_E1E5A)
+#define ULP_GNSS_SV_POLY_BIT_GAL_BGD_E1E5B (1<<ULP_GNSS_SV_POLY_GAL_BGD_E1E5B)
+#define ULP_GNSS_SV_POLY_BIT_NAVIC_TGD_L5 (1<<ULP_GNSS_SV_POLY_NAVIC_TGD_L5)
+
+typedef enum
+{
+ GNSS_LOC_FREQ_SOURCE_INVALID = 0,
+ /**< Source of the frequency is invalid */
+ GNSS_LOC_FREQ_SOURCE_EXTERNAL = 1,
+ /**< Source of the frequency is from external injection */
+ GNSS_LOC_FREQ_SOURCE_PE_CLK_REPORT = 2,
+ /**< Source of the frequency is from Navigation engine */
+ GNSS_LOC_FREQ_SOURCE_UNKNOWN = 3
+ /**< Source of the frequency is unknown */
+} Gnss_LocSourceofFreqEnumType;
+
+typedef struct
+{
+ uint32_t size;
+ float clockDrift;
+ /**< Receiver clock Drift \n
+ - Units: meter per sec \n
+ */
+ float clockDriftUnc;
+ /**< Receiver clock Drift uncertainty \n
+ - Units: meter per sec \n
+ */
+ Gnss_LocSourceofFreqEnumType sourceOfFreq;
+}Gnss_LocRcvrClockFrequencyInfoStructType;
+
+typedef struct
+{
+ uint32_t size;
+ uint8_t leapSec;
+ /**< GPS time leap second delta to UTC time \n
+ - Units: sec \n
+ */
+ uint8_t leapSecUnc;
+ /**< Uncertainty for GPS leap second \n
+ - Units: sec \n
+ */
+}Gnss_LeapSecondInfoStructType;
+
+typedef enum
+{
+ GNSS_LOC_SYS_TIME_BIAS_VALID = 0x01,
+ /**< System time bias valid */
+ GNSS_LOC_SYS_TIME_BIAS_UNC_VALID = 0x02,
+ /**< System time bias uncertainty valid */
+}Gnss_LocInterSystemBiasValidMaskType;
+
+typedef struct
+{
+ uint32_t size;
+ uint32_t validMask;
+ /* Validity mask as per Gnss_LocInterSystemBiasValidMaskType */
+
+ float timeBias;
+ /**< System-1 to System-2 Time Bias \n
+ - Units: msec \n
+ */
+ float timeBiasUnc;
+ /**< System-1 to System-2 Time Bias uncertainty \n
+ - Units: msec \n
+ */
+} Gnss_InterSystemBiasStructType;
+
+
+typedef struct {
+
+ uint32_t size;
+
+ uint8_t systemRtc_valid;
+ /**< Validity indicator for System RTC */
+
+ uint64_t systemRtcMs;
+ /**< Platform system RTC value \n
+ - Units: msec \n
+ */
+
+}Gnss_LocGnssTimeExtStructType;
+
+typedef enum
+{
+ GNSS_LOC_MEAS_STATUS_NULL = 0x00000000,
+ /**< No information state */
+ GNSS_LOC_MEAS_STATUS_SM_VALID = 0x00000001,
+ /**< Code phase is known */
+ GNSS_LOC_MEAS_STATUS_SB_VALID = 0x00000002,
+ /**< Sub-bit time is known */
+ GNSS_LOC_MEAS_STATUS_MS_VALID = 0x00000004,
+ /**< Satellite time is known */
+ GNSS_LOC_MEAS_STATUS_BE_CONFIRM = 0x00000008,
+ /**< Bit edge is confirmed from signal */
+ GNSS_LOC_MEAS_STATUS_VELOCITY_VALID = 0x00000010,
+ /**< Satellite Doppler measured */
+ GNSS_LOC_MEAS_STATUS_VELOCITY_FINE = 0x00000020,
+ /**< TRUE: Fine Doppler measured, FALSE: Coarse Doppler measured */
+ GNSS_LOC_MEAS_STATUS_FROM_RNG_DIFF = 0x00000200,
+ /**< Range update from Satellite differences */
+ GNSS_LOC_MEAS_STATUS_FROM_VE_DIFF = 0x00000400,
+ /**< Doppler update from Satellite differences */
+ GNSS_LOC_MEAS_STATUS_DONT_USE_X = 0x00000800,
+ /**< Don't use measurement if bit is set */
+ GNSS_LOC_MEAS_STATUS_DONT_USE_M = 0x000001000,
+ /**< Don't use measurement if bit is set */
+ GNSS_LOC_MEAS_STATUS_DONT_USE_D = 0x000002000,
+ /**< Don't use measurement if bit is set */
+ GNSS_LOC_MEAS_STATUS_DONT_USE_S = 0x000004000,
+ /**< Don't use measurement if bit is set */
+ GNSS_LOC_MEAS_STATUS_DONT_USE_P = 0x000008000
+ /**< Don't use measurement if bit is set */
+}Gnss_LocSvMeasStatusMaskType;
+
+typedef struct
+{
+ uint32_t size;
+ uint32_t svMs;
+ /**< Satellite time milisecond.\n
+ For GPS, BDS, GAL range of 0 thru (604800000-1) \n
+ For GLONASS range of 0 thru (86400000-1) \n
+ Valid when PD_LOC_MEAS_STATUS_MS_VALID bit is set in measurement status \n
+ Note: All SV times in the current measurement block are alredy propagated to common reference time epoch. \n
+ - Units: msec \n
+ */
+ float svSubMs;
+ /**<Satellite time sub-millisecond. \n
+ Total SV Time = svMs + svSubMs \n
+ - Units: msec \n
+ */
+ float svTimeUncMs;
+ /**< Satellite Time uncertainty \n
+ - Units: msec \n
+ */
+ float dopplerShift;
+ /**< Satellite Doppler \n
+ - Units: meter per sec \n
+ */
+ float dopplerShiftUnc;
+ /**< Satellite Doppler uncertainty\n
+ - Units: meter per sec \n
+ */
+}Gnss_LocSVTimeSpeedStructType;
+
+typedef enum
+{
+ GNSS_SV_STATE_IDLE = 0,
+ GNSS_SV_STATE_SEARCH = 1,
+ GNSS_SV_STATE_SEARCH_VERIFY = 2,
+ GNSS_SV_STATE_BIT_EDGE = 3,
+ GNSS_SV_STATE_VERIFY_TRACK = 4,
+ GNSS_SV_STATE_TRACK = 5,
+ GNSS_SV_STATE_RESTART = 6,
+ GNSS_SV_STATE_DPO_TRACK = 7
+} Gnss_LocSVStateEnumType;
+
+typedef enum
+{
+ GNSS_LOC_SVINFO_MASK_HAS_EPHEMERIS = 0x01,
+ /**< Ephemeris is available for this SV */
+ GNSS_LOC_SVINFO_MASK_HAS_ALMANAC = 0x02
+ /**< Almanac is available for this SV */
+}Gnss_LocSvInfoMaskT;
+
+typedef enum
+{
+ GNSS_LOC_SV_SRCH_STATUS_IDLE = 1,
+ /**< SV is not being actively processed */
+ GNSS_LOC_SV_SRCH_STATUS_SEARCH = 2,
+ /**< The system is searching for this SV */
+ GNSS_LOC_SV_SRCH_STATUS_TRACK = 3
+ /**< SV is being tracked */
+}Gnss_LocSvSearchStatusEnumT;
+
+typedef struct
+{
+ uint32_t size;
+ Gnss_LocSvSystemEnumType gnssSystem;
+ // 0 signal type mask indicates invalid value
+ GnssSignalTypeMask gnssSignalTypeMask;
+ uint16_t gnssSvId;
+ /**< GNSS SV ID.
+ \begin{itemize1}
+ \item Range: \begin{itemize1}
+ \item For GPS: 1 to 32
+ \item For GLONASS: 1 to 32
+ \item For SBAS: 120 to 151
+ \item For BDS: 201 to 237
+ \end{itemize1} \end{itemize1}
+ The GPS and GLONASS SVs can be disambiguated using the system field.
+ */
+ uint8_t gloFrequency;
+ /**< GLONASS frequency number + 7 \n
+ Valid only for GLONASS System \n
+ Shall be ignored for all other systems \n
+ - Range: 1 to 14 \n
+ */
+ Gnss_LocSvSearchStatusEnumT svStatus;
+ /**< Satellite search state \n
+ @ENUM()
+ */
+ bool healthStatus_valid;
+ /**< SV Health Status validity flag\n
+ - 0: Not valid \n
+ - 1: Valid \n
+ */
+ uint8_t healthStatus;
+ /**< Health status.
+ \begin{itemize1}
+ \item Range: 0 to 1; 0 = unhealthy, \n 1 = healthy, 2 = unknown
+ \vspace{-0.18in} \end{itemize1}
+ */
+ Gnss_LocSvInfoMaskT svInfoMask;
+ /**< Indicates whether almanac and ephemeris information is available. \n
+ @MASK()
+ */
+ uint64_t measurementStatus;
+ /**< Bitmask indicating SV measurement status.
+ Valid bitmasks: \n
+ If any MSB bit in 0xFFC0000000000000 DONT_USE is set, the measurement
+ must not be used by the client.
+ @MASK()
+ */
+ uint16_t CNo;
+ /**< Carrier to Noise ratio \n
+ - Units: 0.1 dBHz \n
+ */
+ uint16_t gloRfLoss;
+ /**< GLONASS Rf loss reference to Antenna. \n
+ - Units: dB, Scale: 0.1 \n
+ */
+ bool lossOfLock;
+ /**< Loss of signal lock indicator \n
+ - 0: Signal in continuous track \n
+ - 1: Signal not in track \n
+ */
+ int16_t measLatency;
+ /**< Age of the measurement. Positive value means measurement precedes ref time. \n
+ - Units: msec \n
+ */
+ Gnss_LocSVTimeSpeedStructType svTimeSpeed;
+ /**< Unfiltered SV Time and Speed information
+ */
+ float dopplerAccel;
+ /**< Satellite Doppler Accelertion\n
+ - Units: Hz/s \n
+ */
+ bool multipathEstValid;
+ /**< Multipath estimate validity flag\n
+ - 0: Multipath estimate not valid \n
+ - 1: Multipath estimate valid \n
+ */
+ float multipathEstimate;
+ /**< Estimate of multipath in measurement\n
+ - Units: Meters \n
+ */
+ bool fineSpeedValid;
+ /**< Fine speed validity flag\n
+ - 0: Fine speed not valid \n
+ - 1: Fine speed valid \n
+ */
+ float fineSpeed;
+ /**< Carrier phase derived speed \n
+ - Units: m/s \n
+ */
+ bool fineSpeedUncValid;
+ /**< Fine speed uncertainty validity flag\n
+ - 0: Fine speed uncertainty not valid \n
+ - 1: Fine speed uncertainty valid \n
+ */
+ float fineSpeedUnc;
+ /**< Carrier phase derived speed \n
+ - Units: m/s \n
+ */
+ bool carrierPhaseValid;
+ /**< Carrier Phase measurement validity flag\n
+ - 0: Carrier Phase not valid \n
+ - 1: Carrier Phase valid \n
+ */
+ double carrierPhase;
+ /**< Carrier phase measurement [L1 cycles] \n
+ */
+ bool cycleSlipCountValid;
+ /**< Cycle slup count validity flag\n
+ - 0: Not valid \n
+ - 1: Valid \n
+ */
+ uint8_t cycleSlipCount;
+ /**< Increments when a CSlip is detected */
+
+ bool svDirectionValid;
+ /**< Validity flag for SV direction */
+
+ float svAzimuth;
+ /**< Satellite Azimuth
+ - Units: radians \n
+ */
+ float svElevation;
+ /**< Satellite Elevation
+ - Units: radians \n
+ */
+ uint64_t validMeasStatusMask;
+ /**< Bitmask indicating SV measurement status Validity.
+ Valid bitmasks: \n
+ If any MSB bit in 0xFFC0000000000000 DONT_USE is set, the measurement
+ must not be used by the client.
+ @MASK()
+ */
+ bool carrierPhaseUncValid;
+ /**< Validity flag for SV direction */
+
+ float carrierPhaseUnc;
+
+
+} Gnss_SVMeasurementStructType;
+
+
+typedef uint64_t GpsSvMeasHeaderFlags;
+#define GNSS_SV_MEAS_HEADER_HAS_LEAP_SECOND 0x00000001
+#define GNSS_SV_MEAS_HEADER_HAS_CLOCK_FREQ 0x00000002
+#define GNSS_SV_MEAS_HEADER_HAS_AP_TIMESTAMP 0x00000004
+#define GNSS_SV_MEAS_HEADER_HAS_GPS_GLO_INTER_SYSTEM_BIAS 0x00000008
+#define GNSS_SV_MEAS_HEADER_HAS_GPS_BDS_INTER_SYSTEM_BIAS 0x00000010
+#define GNSS_SV_MEAS_HEADER_HAS_GPS_GAL_INTER_SYSTEM_BIAS 0x00000020
+#define GNSS_SV_MEAS_HEADER_HAS_BDS_GLO_INTER_SYSTEM_BIAS 0x00000040
+#define GNSS_SV_MEAS_HEADER_HAS_GAL_GLO_INTER_SYSTEM_BIAS 0x00000080
+#define GNSS_SV_MEAS_HEADER_HAS_GAL_BDS_INTER_SYSTEM_BIAS 0x00000100
+#define GNSS_SV_MEAS_HEADER_HAS_GPS_SYSTEM_TIME 0x00000200
+#define GNSS_SV_MEAS_HEADER_HAS_GAL_SYSTEM_TIME 0x00000400
+#define GNSS_SV_MEAS_HEADER_HAS_BDS_SYSTEM_TIME 0x00000800
+#define GNSS_SV_MEAS_HEADER_HAS_QZSS_SYSTEM_TIME 0x00001000
+#define GNSS_SV_MEAS_HEADER_HAS_GLO_SYSTEM_TIME 0x00002000
+#define GNSS_SV_MEAS_HEADER_HAS_GPS_SYSTEM_TIME_EXT 0x00004000
+#define GNSS_SV_MEAS_HEADER_HAS_GAL_SYSTEM_TIME_EXT 0x00008000
+#define GNSS_SV_MEAS_HEADER_HAS_BDS_SYSTEM_TIME_EXT 0x00010000
+#define GNSS_SV_MEAS_HEADER_HAS_QZSS_SYSTEM_TIME_EXT 0x00020000
+#define GNSS_SV_MEAS_HEADER_HAS_GLO_SYSTEM_TIME_EXT 0x00040000
+#define GNSS_SV_MEAS_HEADER_HAS_GPSL1L5_TIME_BIAS 0x00080000
+#define GNSS_SV_MEAS_HEADER_HAS_GALE1E5A_TIME_BIAS 0x00100000
+#define GNSS_SV_MEAS_HEADER_HAS_GPS_NAVIC_INTER_SYSTEM_BIAS 0x00200000
+#define GNSS_SV_MEAS_HEADER_HAS_GAL_NAVIC_INTER_SYSTEM_BIAS 0x00400000
+#define GNSS_SV_MEAS_HEADER_HAS_GLO_NAVIC_INTER_SYSTEM_BIAS 0x00800000
+#define GNSS_SV_MEAS_HEADER_HAS_BDS_NAVIC_INTER_SYSTEM_BIAS 0x01000000
+#define GNSS_SV_MEAS_HEADER_HAS_NAVIC_SYSTEM_TIME 0x02000000
+#define GNSS_SV_MEAS_HEADER_HAS_NAVIC_SYSTEM_TIME_EXT 0x04000000
+
+typedef struct
+{
+ uint32_t size;
+ // see defines in GNSS_SV_MEAS_HEADER_HAS_XXX_XXX
+ uint64_t flags;
+
+ Gnss_LeapSecondInfoStructType leapSec;
+
+ Gnss_LocRcvrClockFrequencyInfoStructType clockFreq; /* Freq */
+
+ Gnss_ApTimeStampStructType apBootTimeStamp;
+
+ Gnss_InterSystemBiasStructType gpsGloInterSystemBias;
+ Gnss_InterSystemBiasStructType gpsBdsInterSystemBias;
+ Gnss_InterSystemBiasStructType gpsGalInterSystemBias;
+ Gnss_InterSystemBiasStructType bdsGloInterSystemBias;
+ Gnss_InterSystemBiasStructType galGloInterSystemBias;
+ Gnss_InterSystemBiasStructType galBdsInterSystemBias;
+ Gnss_InterSystemBiasStructType gpsNavicInterSystemBias;
+ Gnss_InterSystemBiasStructType galNavicInterSystemBias;
+ Gnss_InterSystemBiasStructType gloNavicInterSystemBias;
+ Gnss_InterSystemBiasStructType bdsNavicInterSystemBias;
+ Gnss_InterSystemBiasStructType gpsL1L5TimeBias;
+ Gnss_InterSystemBiasStructType galE1E5aTimeBias;
+
+ GnssSystemTimeStructType gpsSystemTime;
+ GnssSystemTimeStructType galSystemTime;
+ GnssSystemTimeStructType bdsSystemTime;
+ GnssSystemTimeStructType qzssSystemTime;
+ GnssSystemTimeStructType navicSystemTime;
+ GnssGloTimeStructType gloSystemTime;
+
+ /** GPS system RTC time information. */
+ Gnss_LocGnssTimeExtStructType gpsSystemTimeExt;
+ /** GAL system RTC time information. */
+ Gnss_LocGnssTimeExtStructType galSystemTimeExt;
+ /** BDS system RTC time information. */
+ Gnss_LocGnssTimeExtStructType bdsSystemTimeExt;
+ /** QZSS system RTC time information. */
+ Gnss_LocGnssTimeExtStructType qzssSystemTimeExt;
+ /** GLONASS system RTC time information. */
+ Gnss_LocGnssTimeExtStructType gloSystemTimeExt;
+ /** NAVIC system RTC time information. */
+ Gnss_LocGnssTimeExtStructType navicSystemTimeExt;
+} GnssSvMeasurementHeader;
+
+typedef struct {
+ uint32_t size;
+ bool isNhz;
+ GnssSvMeasurementHeader svMeasSetHeader;
+ uint32_t svMeasCount;
+ Gnss_SVMeasurementStructType svMeas[GNSS_LOC_SV_MEAS_LIST_MAX_SIZE];
+
+} GnssSvMeasurementSet;
+
+typedef struct {
+ uint32_t size; // set to sizeof(GnssMeasurements)
+ GnssSvMeasurementSet gnssSvMeasurementSet;
+ GnssMeasurementsNotification gnssMeasNotification;
+} GnssMeasurements;
+
+typedef enum
+{
+ GNSS_SV_POLY_COEFF_VALID = 0x01,
+ /**< SV position in orbit coefficients are valid */
+ GNSS_SV_POLY_IONO_VALID = 0x02,
+ /**< Iono estimates are valid */
+
+ GNSS_SV_POLY_TROPO_VALID = 0x04,
+ /**< Tropo estimates are valid */
+
+ GNSS_SV_POLY_ELEV_VALID = 0x08,
+ /**< Elevation, rate, uncertainty are valid */
+
+ GNSS_SV_POLY_SRC_ALM_CORR = 0x10,
+ /**< Polynomials based on XTRA */
+
+ GNSS_SV_POLY_SBAS_IONO_VALID = 0x20,
+ /**< SBAS IONO and rate are valid */
+
+ GNSS_SV_POLY_GLO_STR4 = 0x40
+ /**< GLONASS String 4 has been received */
+}Gnss_SvPolyStatusMaskType;
+
+
+typedef struct
+{
+ uint32_t size;
+ uint16_t gnssSvId;
+ /* GPS: 1-32, GLO: 65-96, 0: Invalid,
+ SBAS: 120-151, BDS:201-237,GAL:301 to 336
+ All others are reserved
+ */
+ int8_t freqNum;
+ /* Freq index, only valid if u_SysInd is GLO */
+
+ GnssSvPolyStatusMaskValidity svPolyStatusMaskValidity;
+ GnssSvPolyStatusMask svPolyStatusMask;
+
+ uint32_t is_valid;
+
+ uint16_t iode;
+ /* Ephemeris reference time
+ GPS:Issue of Data Ephemeris used [unitless].
+ GLO: Tb 7-bit, refer to ICD02
+ */
+ double T0;
+ /* Reference time for polynominal calculations
+ GPS: Secs in week.
+ GLO: Full secs since Jan/01/96
+ */
+ double polyCoeffXYZ0[GNSS_SV_POLY_XYZ_0_TH_ORDER_COEFF_MAX_SIZE];
+ /* C0X, C0Y, C0Z */
+ double polyCoefXYZN[GNSS_SV_POLY_XYZ_N_TH_ORDER_COEFF_MAX_SIZE];
+ /* C1X, C2X ... C2Z, C3Z */
+ float polyCoefOther[GNSS_SV_POLY_SV_CLKBIAS_COEFF_MAX_SIZE];
+ /* C0T, C1T, C2T, C3T */
+ float svPosUnc; /* SV position uncertainty [m]. */
+ float ionoDelay; /* Ionospheric delay at d_T0 [m]. */
+ float ionoDot; /* Iono delay rate [m/s]. */
+ float sbasIonoDelay;/* SBAS Ionospheric delay at d_T0 [m]. */
+ float sbasIonoDot; /* SBAS Iono delay rate [m/s]. */
+ float tropoDelay; /* Tropospheric delay [m]. */
+ float elevation; /* Elevation [rad] at d_T0 */
+ float elevationDot; /* Elevation rate [rad/s] */
+ float elevationUnc; /* SV elevation [rad] uncertainty */
+ double velCoef[GNSS_SV_POLY_VELOCITY_COEF_MAX_SIZE];
+ /* Coefficients of velocity poly */
+ uint32_t enhancedIOD; /* Enhanced Reference Time */
+ float gpsIscL1ca;
+ float gpsIscL2c;
+ float gpsIscL5I5;
+ float gpsIscL5Q5;
+ float gpsTgd;
+ float gloTgdG1G2;
+ float bdsTgdB1;
+ float bdsTgdB2;
+ float bdsTgdB2a;
+ float bdsIscB2a;
+ float galBgdE1E5a;
+ float galBgdE1E5b;
+ float navicTgdL5;
+} GnssSvPolynomial;
+
+typedef enum {
+ GNSS_EPH_ACTION_UPDATE_SRC_UNKNOWN_V02 = 0, /**<Update ephemeris. Source of ephemeris is unknown */
+ GNSS_EPH_ACTION_UPDATE_SRC_OTA_V02 = 1, /**<Update ephemeris. Source of ephemeris is OTA */
+ GNSS_EPH_ACTION_UPDATE_SRC_NETWORK_V02 = 2, /**<Update ephemeris. Source of ephemeris is Network */
+ GNSS_EPH_ACTION_UPDATE_MAX_V02 = 999, /**<Max value for update ephemeris action. DO NOT USE */
+ GNSS_EPH_ACTION_DELETE_SRC_UNKNOWN_V02 = 1000, /**<Delete previous ephemeris from unknown source */
+ GNSS_EPH_ACTION_DELETE_SRC_NETWORK_V02 = 1001, /**<Delete previous ephemeris from network */
+ GNSS_EPH_ACTION_DELETE_SRC_OTA_V02 = 1002, /**<Delete previous ephemeris from OTA */
+ GNSS_EPH_ACTION_DELETE_MAX_V02 = 1999, /**<Max value for delete ephemeris action. DO NOT USE */
+} GnssEphAction;
+
+typedef enum {
+ GAL_EPH_SIGNAL_SRC_UNKNOWN_V02 = 0, /**< GALILEO signal is unknown */
+ GAL_EPH_SIGNAL_SRC_E1B_V02 = 1, /**< GALILEO signal is E1B */
+ GAL_EPH_SIGNAL_SRC_E5A_V02 = 2, /**< GALILEO signal is E5A */
+ GAL_EPH_SIGNAL_SRC_E5B_V02 = 3, /**< GALILEO signal is E5B */
+} GalEphSignalSource;
+
+typedef struct {
+ uint16_t gnssSvId;
+ /**< GNSS SV ID.
+ - Type: uint16
+ \begin{itemize1}
+ \item Range: \begin{itemize1}
+ \item For GPS: 1 to 32
+ \item For QZSS: 193 to 197
+ \item For BDS: 201 to 237
+ \item For GAL: 301 to 336
+ \vspace{-0.18in} \end{itemize1} \end{itemize1} */
+
+ GnssEphAction updateAction;
+ /**< Specifies the action and source of ephemeris. \n
+ - Type: int32 enum */
+
+ uint16_t IODE;
+ /**< Issue of data ephemeris used (unit-less). \n
+ GPS: IODE 8 bits.\n
+ BDS: AODE 5 bits. \n
+ GAL: SIS IOD 10 bits. \n
+ - Type: uint16
+ - Units: Unit-less */
+
+ double aSqrt;
+ /**< Square root of semi-major axis. \n
+ - Type: double
+ - Units: Square Root of Meters */
+
+ double deltaN;
+ /**< Mean motion difference from computed value. \n
+ - Type: double
+ - Units: Radians/Second */
+
+ double m0;
+ /**< Mean anomaly at reference time. \n
+ - Type: double
+ - Units: Radians */
+
+ double eccentricity;
+ /**< Eccentricity . \n
+ - Type: double
+ - Units: Unit-less */
+
+ double omega0;
+ /**< Longitude of ascending node of orbital plane at the weekly epoch. \n
+ - Type: double
+ - Units: Radians */
+
+ double i0;
+ /**< Inclination angle at reference time. \n
+ - Type: double
+ - Units: Radians */
+
+ double omega;
+ /**< Argument of Perigee. \n
+ - Type: double
+ - Units: Radians */
+
+ double omegaDot;
+ /**< Rate of change of right ascension. \n
+ - Type: double
+ - Units: Radians/Second */
+
+ double iDot;
+ /**< Rate of change of inclination angle. \n
+ - Type: double
+ - Units: Radians/Second */
+
+ double cUc;
+ /**< Amplitude of the cosine harmonic correction term to the argument of latitude. \n
+ - Type: double
+ - Units: Radians */
+
+ double cUs;
+ /**< Amplitude of the sine harmonic correction term to the argument of latitude. \n
+ - Type: double
+ - Units: Radians */
+
+ double cRc;
+ /**< Amplitude of the cosine harmonic correction term to the orbit radius. \n
+ - Type: double
+ - Units: Meters */
+
+ double cRs;
+ /**< Amplitude of the sine harmonic correction term to the orbit radius. \n
+ - Type: double
+ - Units: Meters */
+
+ double cIc;
+ /**< Amplitude of the cosine harmonic correction term to the angle of inclination. \n
+ - Type: double
+ - Units: Radians */
+
+ double cIs;
+ /**< Amplitude of the sine harmonic correction term to the angle of inclination. \n
+ - Type: double
+ - Units: Radians */
+
+ uint32_t toe;
+ /**< Reference time of ephemeris. \n
+ - Type: uint32
+ - Units: Seconds */
+
+ uint32_t toc;
+ /**< Clock data reference time of week. \n
+ - Type: uint32
+ - Units: Seconds */
+
+ double af0;
+ /**< Clock bias correction coefficient. \n
+ - Type: double
+ - Units: Seconds */
+
+ double af1;
+ /**< Clock drift coefficient. \n
+ - Type: double
+ - Units: Seconds/Second */
+
+ double af2;
+ /**< Clock drift rate correction coefficient. \n
+ - Type: double
+ - Units: Seconds/Seconds^2 */
+
+} GnssEphCommon;
+
+/* GPS Navigation Model Info */
+typedef struct {
+ GnssEphCommon commonEphemerisData;
+ /**< Common ephemeris data. */
+
+ uint8_t signalHealth;
+ /**< Signal health. \n
+ Bit 0 : L5 Signal Health. \n
+ Bit 1 : L2 Signal Health. \n
+ Bit 2 : L1 Signal Health. \n
+ - Type: uint8
+ - Values: 3 bit mask of signal health, where set bit indicates unhealthy signal */
+
+ uint8_t URAI;
+ /**< User Range Accuracy Index. \n
+ - Type: uint8
+ - Units: Unit-less */
+
+ uint8_t codeL2;
+ /**< Indicates which codes are commanded ON for the L2 channel (2-bits). \n
+ - Type: uint8
+ Valid Values: \n
+ - 00 : Reserved
+ - 01 : P code ON
+ - 10 : C/A code ON */
+
+ uint8_t dataFlagL2P;
+ /**< L2 P-code indication flag. \n
+ - Type: uint8
+ - Value 1 indicates that the Nav data stream was commanded OFF on the P-code of the L2 channel. */
+
+ double tgd;
+ /**< Time of group delay. \n
+ - Type: double
+ - Units: Seconds */
+
+ uint8_t fitInterval;
+ /**< Indicates the curve-fit interval used by the CS. \n
+ - Type: uint8
+ Valid Values:
+ - 0 : Four hours
+ - 1 : Greater than four hours */
+
+ uint16_t IODC;
+ /**< Issue of Data, Clock. \n
+ - Type: uint16
+ - Units: Unit-less */
+} GpsEphemeris;
+
+/* GLONASS Navigation Model Info */
+typedef struct {
+
+ uint16_t gnssSvId;
+ /**< GNSS SV ID.
+ - Type: uint16
+ - Range: 65 to 96 if known. When the slot number to SV ID mapping is unknown, set to 255 */
+
+ GnssEphAction updateAction;
+ /**< Specifies the action and source of ephemeris. \n
+ - Type: int32 enum */
+
+ uint8_t bnHealth;
+ /**< SV health flags. \n
+ - Type: uint8
+ Valid Values: \n
+ - 0 : Healthy
+ - 1 : Unhealthy */
+
+ uint8_t lnHealth;
+ /**< Ln SV health flags. GLONASS-M. \n
+ - Type: uint8
+ Valid Values: \n
+ - 0 : Healthy
+ - 1 : Unhealthy */
+
+ uint8_t tb;
+ /**< Index of a time interval within current day according to UTC(SU) + 03 hours 00 min. \n
+ - Type: uint8
+ - Units: Unit-less */
+
+ uint8_t ft;
+ /**< SV accuracy index. \n
+ - Type: uint8
+ - Units: Unit-less */
+
+ uint8_t gloM;
+ /**< GLONASS-M flag. \n
+ - Type: uint8
+ Valid Values: \n
+ - 0 : GLONASS
+ - 1 : GLONASS-M */
+
+ uint8_t enAge;
+ /**< Characterizes "Age" of current information. \n
+ - Type: uint8
+ - Units: Days */
+
+ uint8_t gloFrequency;
+ /**< GLONASS frequency number + 8. \n
+ - Type: uint8
+ - Range: 1 to 14
+ */
+
+ uint8_t p1;
+ /**< Time interval between two adjacent values of tb parameter. \n
+ - Type: uint8
+ - Units: Minutes */
+
+ uint8_t p2;
+ /**< Flag of oddness ("1") or evenness ("0") of the value of tb \n
+ for intervals 30 or 60 minutes. \n
+ - Type: uint8 */
+
+ float deltaTau;
+ /**< Time difference between navigation RF signal transmitted in L2 sub-band \n
+ and aviation RF signal transmitted in L1 sub-band. \n
+ - Type: floating point
+ - Units: Seconds */
+
+ double position[3];
+ /**< Satellite XYZ position. \n
+ - Type: array of doubles
+ - Units: Meters */
+
+ double velocity[3];
+ /**< Satellite XYZ velocity. \n
+ - Type: array of doubles
+ - Units: Meters/Second */
+
+ double acceleration[3];
+ /**< Satellite XYZ sola-luni acceleration. \n
+ - Type: array of doubles
+ - Units: Meters/Second^2 */
+
+ float tauN;
+ /**< Satellite clock correction relative to GLONASS time. \n
+ - Type: floating point
+ - Units: Seconds */
+
+ float gamma;
+ /**< Relative deviation of predicted carrier frequency value \n
+ from nominal value at the instant tb. \n
+ - Type: floating point
+ - Units: Unit-less */
+
+ double toe;
+ /**< Complete ephemeris time, including N4, NT and Tb. \n
+ [(N4-1)*1461 + (NT-1)]*86400 + tb*900 \n
+ - Type: double
+ - Units: Seconds */
+
+ uint16_t nt;
+ /**< Current date, calendar number of day within four-year interval. \n
+ Starting from the 1-st of January in a leap year. \n
+ - Type: uint16
+ - Units: Days */
+} GlonassEphemeris;
+
+/* BDS Navigation Model Info */
+typedef struct {
+
+ GnssEphCommon commonEphemerisData;
+ /**< Common ephemeris data. */
+
+ uint8_t svHealth;
+ /**< Satellite health information applied to both B1 and B2 (SatH1). \n
+ - Type: uint8
+ Valid Values: \n
+ - 0 : Healthy
+ - 1 : Unhealthy */
+
+ uint8_t AODC;
+ /**< Age of data clock. \n
+ - Type: uint8
+ - Units: Hours */
+
+ double tgd1;
+ /**< Equipment group delay differential on B1 signal. \n
+ - Type: double
+ - Units: Nano-Seconds */
+
+ double tgd2;
+ /**< Equipment group delay differential on B2 signal. \n
+ - Type: double
+ - Units: Nano-Seconds */
+
+ uint8_t URAI;
+ /**< User range accuracy index (4-bits). \n
+ - Type: uint8
+ - Units: Unit-less */
+} BdsEphemeris;
+
+/* GALIELO Navigation Model Info */
+typedef struct {
+
+ GnssEphCommon commonEphemerisData;
+ /**< Common ephemeris data. */
+
+ GalEphSignalSource dataSourceSignal;
+ /**< Galileo Signal Source. \n
+ Valid Values: \n
+ - GAL_EPH_SIGNAL_SRC_UNKNOWN (0) -- GALILEO signal is unknown
+ - GAL_EPH_SIGNAL_SRC_E1B (1) -- GALILEO signal is E1B
+ - GAL_EPH_SIGNAL_SRC_E5A (2) -- GALILEO signal is E5A
+ - GAL_EPH_SIGNAL_SRC_E5B (3) -- GALILEO signal is E5B */
+
+ uint8_t sisIndex;
+ /**< Signal-in-space index for dual frequency E1-E5b/E5a depending on dataSignalSource. \n
+ - Type: uint8
+ - Units: Unit-less */
+
+ double bgdE1E5a;
+ /**< E1-E5a Broadcast group delay from F/Nav (E5A). \n
+ - Type: double
+ - Units: Seconds */
+
+ double bgdE1E5b;
+ /**< E1-E5b Broadcast group delay from I/Nav (E1B or E5B). \n
+ For E1B or E5B signal, both bgdE1E5a and bgdE1E5b are valid. \n
+ For E5A signal, only bgdE1E5a is valid. \n
+ Signal source identified using dataSignalSource. \n
+ - Type: double
+ - Units: Seconds */
+
+ uint8_t svHealth;
+ /**< SV health status of signal identified by dataSourceSignal. \n
+ - Type: uint8
+ Valid Values: \n
+ - 0 : Healthy
+ - 1 : Unhealthy */
+} GalileoEphemeris;
+
+/** GPS Navigation model for each SV */
+typedef struct {
+ uint16_t numOfEphemeris;
+ GpsEphemeris gpsEphemerisData[GNSS_EPHEMERIS_LIST_MAX_SIZE_V02];
+} GpsEphemerisResponse;
+
+/** GLONASS Navigation model for each SV */
+typedef struct {
+ uint16_t numOfEphemeris;
+ GlonassEphemeris gloEphemerisData[GNSS_EPHEMERIS_LIST_MAX_SIZE_V02];
+} GlonassEphemerisResponse;
+
+/** BDS Navigation model for each SV */
+typedef struct {
+ uint16_t numOfEphemeris;
+ BdsEphemeris bdsEphemerisData[GNSS_EPHEMERIS_LIST_MAX_SIZE_V02];
+} BdsEphemerisResponse;
+
+/** GALILEO Navigation model for each SV */
+typedef struct {
+ uint16_t numOfEphemeris;
+ GalileoEphemeris galEphemerisData[GNSS_EPHEMERIS_LIST_MAX_SIZE_V02];
+} GalileoEphemerisResponse;
+
+/** QZSS Navigation model for each SV */
+typedef struct {
+ uint16_t numOfEphemeris;
+ GpsEphemeris qzssEphemerisData[GNSS_EPHEMERIS_LIST_MAX_SIZE_V02];
+} QzssEphemerisResponse;
+
+
+typedef struct {
+ /** Indicates GNSS Constellation Type
+ Mandatory field */
+ Gnss_LocSvSystemEnumType gnssConstellation;
+
+ /** GPS System Time of the ephemeris report */
+ bool isSystemTimeValid;
+ GnssSystemTimeStructType systemTime;
+
+ union {
+ /** GPS Ephemeris */
+ GpsEphemerisResponse gpsEphemeris;
+ /** GLONASS Ephemeris */
+ GlonassEphemerisResponse glonassEphemeris;
+ /** BDS Ephemeris */
+ BdsEphemerisResponse bdsEphemeris;
+ /** GALILEO Ephemeris */
+ GalileoEphemerisResponse galileoEphemeris;
+ /** QZSS Ephemeris */
+ QzssEphemerisResponse qzssEphemeris;
+ } ephInfo;
+} GnssSvEphemerisReport;
+
+typedef struct {
+ /** GPS System Time of the iono model report */
+ bool isSystemTimeValid;
+ GnssSystemTimeStructType systemTime;
+
+ /** Indicates GNSS Constellation Type */
+ Gnss_LocSvSystemEnumType gnssConstellation;
+
+ float alpha0;
+ /**< Klobuchar Model Parameter Alpha 0.
+ - Type: float
+ - Unit: Seconds
+ */
+
+ float alpha1;
+ /**< Klobuchar Model Parameter Alpha 1.
+ - Type: float
+ - Unit: Seconds / Semi-Circle
+ */
+
+ float alpha2;
+ /**< Klobuchar Model Parameter Alpha 2.
+ - Type: float
+ - Unit: Seconds / Semi-Circle^2
+ */
+
+ float alpha3;
+ /**< Klobuchar Model Parameter Alpha 3.
+ - Type: float
+ - Unit: Seconds / Semi-Circle^3
+ */
+
+ float beta0;
+ /**< Klobuchar Model Parameter Beta 0.
+ - Type: float
+ - Unit: Seconds
+ */
+
+ float beta1;
+ /**< Klobuchar Model Parameter Beta 1.
+ - Type: float
+ - Unit: Seconds / Semi-Circle
+ */
+
+ float beta2;
+ /**< Klobuchar Model Parameter Beta 2.
+ - Type: float
+ - Unit: Seconds / Semi-Circle^2
+ */
+
+ float beta3;
+ /**< Klobuchar Model Parameter Beta 3.
+ - Type: float
+ - Unit: Seconds / Semi-Circle^3
+ */
+} GnssKlobucharIonoModel;
+
+typedef struct {
+ /** GPS System Time of the report */
+ bool isSystemTimeValid;
+ GnssSystemTimeStructType systemTime;
+
+ GnssAdditionalSystemInfoMask validityMask;
+ double tauC;
+ int8_t leapSec;
+} GnssAdditionalSystemInfo;
+
+/* Various Short Range Node Technology type*/
+typedef enum {
+ SRN_AP_DATA_TECH_TYPE_NONE,
+ SRN_AP_DATA_TECH_TYPE_BT,
+ SRN_AP_DATA_TECH_TYPE_BTLE,
+ SRN_AP_DATA_TECH_TYPE_NFC,
+ SRN_AP_DATA_TECH_TYPE_MOBILE_CODE,
+ SRN_AP_DATA_TECH_TYPE_OTHER
+} Gnss_SrnTech;
+
+/* Mac Address type requested by modem */
+typedef enum {
+ SRN_AP_DATA_PUBLIC_MAC_ADDR_TYPE_INVALID, /* No valid mac address type send */
+ SRN_AP_DATA_PUBLIC_MAC_ADDR_TYPE_PUBLIC, /* SRN AP MAC Address type PUBLIC */
+ SRN_AP_DATA_PUBLIC_MAC_ADDR_TYPE_PRIVATE, /* SRN AP MAC Address type PRIVATE */
+ SRN_AP_DATA_PUBLIC_MAC_ADDR_TYPE_OTHER, /* SRN AP MAC Address type OTHER */
+}Gnss_Srn_MacAddr_Type;
+
+typedef struct
+{
+ uint32_t size;
+ Gnss_SrnTech srnTechType; /* SRN Technology type in request */
+ bool srnRequest; /* scan - start(true) or stop(false) */
+ bool e911Mode; /* If in E911 emergency */
+ Gnss_Srn_MacAddr_Type macAddrType; /* SRN AP MAC Address type */
+} GnssSrnDataReq;
+
+/* Mask indicating enabled or disabled constellations */
+typedef uint64_t GnssSvTypesMask;
+typedef enum {
+ GNSS_SV_TYPES_MASK_GLO_BIT = (1<<0),
+ GNSS_SV_TYPES_MASK_BDS_BIT = (1<<1),
+ GNSS_SV_TYPES_MASK_QZSS_BIT = (1<<2),
+ GNSS_SV_TYPES_MASK_GAL_BIT = (1<<3),
+ GNSS_SV_TYPES_MASK_NAVIC_BIT = (1<<4),
+} GnssSvTypesMaskBits;
+
+/* This SV Type config is injected directly to GNSS Adapter
+ * bypassing Location API */
+typedef struct {
+ uint32_t size; // set to sizeof(GnssSvTypeConfig)
+ // Enabled Constellations
+ GnssSvTypesMask enabledSvTypesMask;
+ // Disabled Constellations
+ GnssSvTypesMask blacklistedSvTypesMask;
+} GnssSvTypeConfig;
+
+/* Provides the current GNSS SV Type configuration to the client.
+ * This is fetched via direct call to GNSS Adapter bypassing
+ * Location API */
+typedef std::function<void(
+ const GnssSvTypeConfig& config
+)> GnssSvTypeConfigCallback;
+
+/*
+ * Represents the status of AGNSS augmented to support IPv4.
+ */
+struct AGnssExtStatusIpV4 {
+ AGpsExtType type;
+ LocApnTypeMask apnTypeMask;
+ LocAGpsStatusValue status;
+ /*
+ * 32-bit IPv4 address.
+ */
+ uint32_t ipV4Addr;
+};
+
+/*
+ * Represents the status of AGNSS augmented to support IPv6.
+ */
+struct AGnssExtStatusIpV6 {
+ AGpsExtType type;
+ LocApnTypeMask apnTypeMask;
+ LocAGpsStatusValue status;
+ /*
+ * 128-bit IPv6 address.
+ */
+ uint8_t ipV6Addr[16];
+};
+
+/*
+* Represents the the Nfw Notification structure
+*/
+#define GNSS_MAX_NFW_APP_STRING_LEN 64
+#define GNSS_MAX_NFW_STRING_LEN 20
+
+typedef enum {
+ GNSS_NFW_CTRL_PLANE = 0,
+ GNSS_NFW_SUPL = 1,
+ GNSS_NFW_IMS = 10,
+ GNSS_NFW_SIM = 11,
+ GNSS_NFW_OTHER_PROTOCOL_STACK = 100
+} GnssNfwProtocolStack;
+
+typedef enum {
+ GNSS_NFW_CARRIER = 0,
+ GNSS_NFW_OEM = 10,
+ GNSS_NFW_MODEM_CHIPSET_VENDOR = 11,
+ GNSS_NFW_GNSS_CHIPSET_VENDOR = 12,
+ GNSS_NFW_OTHER_CHIPSET_VENDOR = 13,
+ GNSS_NFW_AUTOMOBILE_CLIENT = 20,
+ GNSS_NFW_OTHER_REQUESTOR = 100
+} GnssNfwRequestor;
+
+typedef enum {
+ GNSS_NFW_REJECTED = 0,
+ GNSS_NFW_ACCEPTED_NO_LOCATION_PROVIDED = 1,
+ GNSS_NFW_ACCEPTED_LOCATION_PROVIDED = 2,
+} GnssNfwResponseType;
+
+typedef struct {
+ char proxyAppPackageName[GNSS_MAX_NFW_APP_STRING_LEN];
+ GnssNfwProtocolStack protocolStack;
+ char otherProtocolStackName[GNSS_MAX_NFW_STRING_LEN];
+ GnssNfwRequestor requestor;
+ char requestorId[GNSS_MAX_NFW_STRING_LEN];
+ GnssNfwResponseType responseType;
+ bool inEmergencyMode;
+ bool isCachedLocation;
+} GnssNfwNotification;
+
+/* ODCPI Request Info */
+enum OdcpiRequestType {
+ ODCPI_REQUEST_TYPE_START,
+ ODCPI_REQUEST_TYPE_STOP
+};
+struct OdcpiRequestInfo {
+ uint32_t size;
+ OdcpiRequestType type;
+ uint32_t tbfMillis;
+ bool isEmergencyMode;
+};
+/* Callback to send ODCPI request to framework */
+typedef std::function<void(const OdcpiRequestInfo& request)> OdcpiRequestCallback;
+
+/*
+ * Callback with AGNSS(IpV4) status information.
+ *
+ * @param status Will be of type AGnssExtStatusIpV4.
+ */
+typedef void (*AgnssStatusIpV4Cb)(AGnssExtStatusIpV4 status);
+
+/*
+* Callback with NFW information.
+*/
+typedef void(*NfwStatusCb)(GnssNfwNotification notification);
+typedef bool(*IsInEmergencySession)(void);
+
+/*
+ * Callback with AGNSS(IpV6) status information.
+ *
+ * @param status Will be of type AGnssExtStatusIpV6.
+ */
+typedef void (*AgnssStatusIpV6Cb)(AGnssExtStatusIpV6 status);
+
+/* Constructs for interaction with loc_net_iface library */
+typedef void (*LocAgpsOpenResultCb)(bool isSuccess, AGpsExtType agpsType, const char* apn,
+ AGpsBearerType bearerType, void* userDataPtr);
+
+typedef void (*LocAgpsCloseResultCb)(bool isSuccess, AGpsExtType agpsType, void* userDataPtr);
+
+/* Shared resources of LocIpc */
+#define LOC_IPC_HAL "/dev/socket/location/socket_hal"
+#define LOC_IPC_XTRA "/dev/socket/location/xtra/socket_xtra"
+
+#define SOCKET_DIR_LOCATION "/dev/socket/location/"
+#define SOCKET_DIR_EHUB "/dev/socket/location/ehub/"
+#define SOCKET_TO_LOCATION_HAL_DAEMON "/dev/socket/loc_client/hal_daemon"
+
+#define SOCKET_LOC_CLIENT_DIR "/dev/socket/loc_client/"
+#define EAP_LOC_CLIENT_DIR "/data/vendor/location/extap_locclient/"
+
+#define LOC_CLIENT_NAME_PREFIX "toclient"
+
+typedef uint64_t NetworkHandle;
+#define NETWORK_HANDLE_UNKNOWN ~0
+#define MAX_NETWORK_HANDLES 10
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* GPS_EXTENDED_C_H */
diff --git a/utils/linked_list.c b/utils/linked_list.c
new file mode 100644
index 0000000..02e1463
--- /dev/null
+++ b/utils/linked_list.c
@@ -0,0 +1,325 @@
+/* Copyright (c) 2011, 2014, 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_utils_ll"
+
+#include "linked_list.h"
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <loc_pla.h>
+#include <log_util.h>
+
+typedef struct list_element {
+ struct list_element* next;
+ struct list_element* prev;
+ void* data_ptr;
+ void (*dealloc_func)(void*);
+}list_element;
+
+typedef struct list_state {
+ list_element* p_head;
+ list_element* p_tail;
+} list_state;
+
+/* ----------------------- END INTERNAL FUNCTIONS ---------------------------------------- */
+
+/*===========================================================================
+
+ FUNCTION: linked_list_init
+
+ ===========================================================================*/
+linked_list_err_type linked_list_init(void** list_data)
+{
+ if( list_data == NULL )
+ {
+ LOC_LOGE("%s: Invalid list parameter!\n", __FUNCTION__);
+ return eLINKED_LIST_INVALID_PARAMETER;
+ }
+
+ list_state* tmp_list;
+ tmp_list = (list_state*)calloc(1, sizeof(list_state));
+ if( tmp_list == NULL )
+ {
+ LOC_LOGE("%s: Unable to allocate space for list!\n", __FUNCTION__);
+ return eLINKED_LIST_FAILURE_GENERAL;
+ }
+
+ tmp_list->p_head = NULL;
+ tmp_list->p_tail = NULL;
+
+ *list_data = tmp_list;
+
+ return eLINKED_LIST_SUCCESS;
+}
+
+/*===========================================================================
+
+ FUNCTION: linked_list_destroy
+
+ ===========================================================================*/
+linked_list_err_type linked_list_destroy(void** list_data)
+{
+ if( list_data == NULL )
+ {
+ LOC_LOGE("%s: Invalid list parameter!\n", __FUNCTION__);
+ return eLINKED_LIST_INVALID_HANDLE;
+ }
+
+ list_state* p_list = (list_state*)*list_data;
+
+ linked_list_flush(p_list);
+
+ free(*list_data);
+ *list_data = NULL;
+
+ return eLINKED_LIST_SUCCESS;
+}
+
+/*===========================================================================
+
+ FUNCTION: linked_list_add
+
+ ===========================================================================*/
+linked_list_err_type linked_list_add(void* list_data, void *data_obj, void (*dealloc)(void*))
+{
+ if( list_data == NULL )
+ {
+ LOC_LOGE("%s: Invalid list parameter!\n", __FUNCTION__);
+ return eLINKED_LIST_INVALID_HANDLE;
+ }
+
+ if( data_obj == NULL )
+ {
+ LOC_LOGE("%s: Invalid input parameter!\n", __FUNCTION__);
+ return eLINKED_LIST_INVALID_PARAMETER;
+ }
+
+ list_state* p_list = (list_state*)list_data;
+ list_element* elem = (list_element*)malloc(sizeof(list_element));
+ if( elem == NULL )
+ {
+ LOC_LOGE("%s: Memory allocation failed\n", __FUNCTION__);
+ return eLINKED_LIST_FAILURE_GENERAL;
+ }
+
+ /* Copy data to newly created element */
+ elem->data_ptr = data_obj;
+ elem->next = NULL;
+ elem->prev = NULL;
+ elem->dealloc_func = dealloc;
+
+ /* Replace head element */
+ list_element* tmp = p_list->p_head;
+ p_list->p_head = elem;
+ /* Point next to the previous head element */
+ p_list->p_head->next = tmp;
+
+ if( tmp != NULL )
+ {
+ tmp->prev = p_list->p_head;
+ }
+ else
+ {
+ p_list->p_tail = p_list->p_head;
+ }
+
+ return eLINKED_LIST_SUCCESS;
+}
+
+/*===========================================================================
+
+ FUNCTION: linked_list_remove
+
+ ===========================================================================*/
+linked_list_err_type linked_list_remove(void* list_data, void **data_obj)
+{
+ if( list_data == NULL )
+ {
+ LOC_LOGE("%s: Invalid list parameter!\n", __FUNCTION__);
+ return eLINKED_LIST_INVALID_HANDLE;
+ }
+
+ if( data_obj == NULL )
+ {
+ LOC_LOGE("%s: Invalid input parameter!\n", __FUNCTION__);
+ return eLINKED_LIST_INVALID_PARAMETER;
+ }
+
+ list_state* p_list = (list_state*)list_data;
+ if( p_list->p_tail == NULL )
+ {
+ return eLINKED_LIST_UNAVAILABLE_RESOURCE;
+ }
+
+ list_element* tmp = p_list->p_tail;
+
+ /* Replace tail element */
+ p_list->p_tail = tmp->prev;
+
+ if( p_list->p_tail != NULL )
+ {
+ p_list->p_tail->next = NULL;
+ }
+ else
+ {
+ p_list->p_head = p_list->p_tail;
+ }
+
+ /* Copy data to output param */
+ *data_obj = tmp->data_ptr;
+
+ /* Free allocated list element */
+ free(tmp);
+
+ return eLINKED_LIST_SUCCESS;
+}
+
+/*===========================================================================
+
+ FUNCTION: linked_list_empty
+
+ ===========================================================================*/
+int linked_list_empty(void* list_data)
+{
+ if( list_data == NULL )
+ {
+ LOC_LOGE("%s: Invalid list parameter!\n", __FUNCTION__);
+ return (int)eLINKED_LIST_INVALID_HANDLE;
+ }
+ else
+ {
+ list_state* p_list = (list_state*)list_data;
+ return p_list->p_head == NULL ? 1 : 0;
+ }
+}
+
+/*===========================================================================
+
+ FUNCTION: linked_list_flush
+
+ ===========================================================================*/
+linked_list_err_type linked_list_flush(void* list_data)
+{
+ if( list_data == NULL )
+ {
+ LOC_LOGE("%s: Invalid list parameter!\n", __FUNCTION__);
+ return eLINKED_LIST_INVALID_HANDLE;
+ }
+
+ list_state* p_list = (list_state*)list_data;
+
+ /* Remove all dynamically allocated elements */
+ while( p_list->p_head != NULL )
+ {
+ list_element* tmp = p_list->p_head->next;
+
+ /* Free data pointer if told to do so. */
+ if( p_list->p_head->dealloc_func != NULL )
+ {
+ p_list->p_head->dealloc_func(p_list->p_head->data_ptr);
+ }
+
+ /* Free list element */
+ free(p_list->p_head);
+
+ p_list->p_head = tmp;
+ }
+
+ p_list->p_tail = NULL;
+
+ return eLINKED_LIST_SUCCESS;
+}
+
+/*===========================================================================
+
+ FUNCTION: linked_list_search
+
+ ===========================================================================*/
+linked_list_err_type linked_list_search(void* list_data, void **data_p,
+ bool (*equal)(void* data_0, void* data),
+ void* data_0, bool rm_if_found)
+{
+ if( list_data == NULL || NULL == equal )
+ {
+ LOC_LOGE("%s: Invalid list parameter! list_data %p equal %p\n",
+ __FUNCTION__, list_data, equal);
+ return eLINKED_LIST_INVALID_HANDLE;
+ }
+
+ list_state* p_list = (list_state*)list_data;
+ if( p_list->p_tail == NULL )
+ {
+ return eLINKED_LIST_UNAVAILABLE_RESOURCE;
+ }
+
+ list_element* tmp = p_list->p_head;
+
+ if (NULL != data_p) {
+ *data_p = NULL;
+ }
+
+ while (NULL != tmp) {
+ if ((*equal)(data_0, tmp->data_ptr)) {
+ if (NULL != data_p) {
+ *data_p = tmp->data_ptr;
+ }
+
+ if (rm_if_found) {
+ if (NULL == tmp->prev) {
+ p_list->p_head = tmp->next;
+ } else {
+ tmp->prev->next = tmp->next;
+ }
+
+ if (NULL == tmp->next) {
+ p_list->p_tail = tmp->prev;
+ } else {
+ tmp->next->prev = tmp->prev;
+ }
+
+ tmp->prev = tmp->next = NULL;
+
+ // dealloc data if it is not copied out && caller
+ // has given us a dealloc function pointer.
+ if (NULL == data_p && NULL != tmp->dealloc_func) {
+ tmp->dealloc_func(tmp->data_ptr);
+ }
+ free(tmp);
+ }
+
+ tmp = NULL;
+ } else {
+ tmp = tmp->next;
+ }
+ }
+
+ return eLINKED_LIST_SUCCESS;
+}
+
diff --git a/utils/linked_list.h b/utils/linked_list.h
new file mode 100644
index 0000000..0b33ecb
--- /dev/null
+++ b/utils/linked_list.h
@@ -0,0 +1,219 @@
+/* Copyright (c) 2011, 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 __LINKED_LIST_H__
+#define __LINKED_LIST_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+#include <stdbool.h>
+#include <stdlib.h>
+
+/** Linked List Return Codes */
+typedef enum
+{
+ eLINKED_LIST_SUCCESS = 0,
+ /**< Request was successful. */
+ eLINKED_LIST_FAILURE_GENERAL = -1,
+ /**< Failed because of a general failure. */
+ eLINKED_LIST_INVALID_PARAMETER = -2,
+ /**< Failed because the request contained invalid parameters. */
+ eLINKED_LIST_INVALID_HANDLE = -3,
+ /**< Failed because an invalid handle was specified. */
+ eLINKED_LIST_UNAVAILABLE_RESOURCE = -4,
+ /**< Failed because an there were not enough resources. */
+ eLINKED_LIST_INSUFFICIENT_BUFFER = -5,
+ /**< Failed because an the supplied buffer was too small. */
+ eLINKED_LIST_EMPTY = -6
+ /**< Failed because list is empty. */
+}linked_list_err_type;
+
+/*===========================================================================
+FUNCTION linked_list_init
+
+DESCRIPTION
+ Initializes internal structures for linked list.
+
+ list_data: State of list to be initialized.
+
+DEPENDENCIES
+ N/A
+
+RETURN VALUE
+ Look at error codes above.
+
+SIDE EFFECTS
+ N/A
+
+===========================================================================*/
+linked_list_err_type linked_list_init(void** list_data);
+
+/*===========================================================================
+FUNCTION linked_list_destroy
+
+DESCRIPTION
+ Destroys internal structures for linked list.
+
+ p_list_data: State of list to be destroyed.
+
+DEPENDENCIES
+ N/A
+
+RETURN VALUE
+ Look at error codes above.
+
+SIDE EFFECTS
+ N/A
+
+===========================================================================*/
+linked_list_err_type linked_list_destroy(void** list_data);
+
+/*===========================================================================
+FUNCTION linked_list_add
+
+DESCRIPTION
+ Adds an element to the head of the linked list. The passed in data pointer
+ is not modified or freed. Passed in data_obj is expected to live throughout
+ the use of the linked_list (i.e. data is not allocated internally)
+
+ p_list_data: List to add data to the head of.
+ data_obj: Pointer to data to add into list
+ dealloc: Function used to deallocate memory for this element. Pass NULL
+ if you do not want data deallocated during a flush operation
+
+DEPENDENCIES
+ N/A
+
+RETURN VALUE
+ Look at error codes above.
+
+SIDE EFFECTS
+ N/A
+
+===========================================================================*/
+linked_list_err_type linked_list_add(void* list_data, void *data_obj, void (*dealloc)(void*));
+
+/*===========================================================================
+FUNCTION linked_list_remove
+
+DESCRIPTION
+ Retrieves data from the list tail. data_obj is the tail element from the list
+ passed in by linked_list_add.
+
+ p_list_data: List to remove the tail from.
+ data_obj: Pointer to data removed from list
+
+DEPENDENCIES
+ N/A
+
+RETURN VALUE
+ Look at error codes above.
+
+SIDE EFFECTS
+ N/A
+
+===========================================================================*/
+linked_list_err_type linked_list_remove(void* list_data, void **data_obj);
+
+/*===========================================================================
+FUNCTION linked_list_empty
+
+DESCRIPTION
+ Tells whether the list currently contains any elements
+
+ p_list_data: List to check if empty.
+
+DEPENDENCIES
+ N/A
+
+RETURN VALUE
+ 0/FALSE : List contains elements
+ 1/TRUE : List is Empty
+ Otherwise look at error codes above.
+
+SIDE EFFECTS
+ N/A
+
+===========================================================================*/
+int linked_list_empty(void* list_data);
+
+/*===========================================================================
+FUNCTION linked_list_flush
+
+DESCRIPTION
+ Removes all elements from the list and deallocates them using the provided
+ dealloc function while adding elements.
+
+ p_list_data: List to remove all elements from.
+
+DEPENDENCIES
+ N/A
+
+RETURN VALUE
+ Look at error codes above.
+
+SIDE EFFECTS
+ N/A
+
+===========================================================================*/
+linked_list_err_type linked_list_flush(void* list_data);
+
+/*===========================================================================
+FUNCTION linked_list_search
+
+DESCRIPTION
+ Searches for an element in the linked list.
+
+ p_list_data: List handle.
+ data_p: to be stored with the data found; NUll if no match.
+ if data_p passed in as NULL, then no write to it.
+ equal: Function ptr takes in a list element, and returns
+ indication if this the one looking for.
+ data_0: The data being compared against.
+ rm_if_found: Should data be removed if found?
+
+DEPENDENCIES
+ N/A
+
+RETURN VALUE
+ Look at error codes above.
+
+SIDE EFFECTS
+ N/A
+
+===========================================================================*/
+linked_list_err_type linked_list_search(void* list_data, void **data_p,
+ bool (*equal)(void* data_0, void* data),
+ void* data_0, bool rm_if_found);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* __LINKED_LIST_H__ */
diff --git a/utils/loc_cfg.cpp b/utils/loc_cfg.cpp
new file mode 100644
index 0000000..9c1f0b3
--- /dev/null
+++ b/utils/loc_cfg.cpp
@@ -0,0 +1,1067 @@
+/* Copyright (c) 2011-2015, 2018 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_NDEBUG 0
+#define LOG_TAG "LocSvc_utils_cfg"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <pthread.h>
+#include <string.h>
+#include <ctype.h>
+#include <unistd.h>
+#include <time.h>
+#include <grp.h>
+#include <errno.h>
+#include <loc_cfg.h>
+#include <loc_pla.h>
+#include <loc_target.h>
+#include <loc_misc_utils.h>
+#ifdef USE_GLIB
+#include <glib.h>
+#endif
+#include "log_util.h"
+
+/*=============================================================================
+ *
+ * GLOBAL DATA DECLARATION
+ *
+ *============================================================================*/
+
+/* Parameter data */
+static uint32_t DEBUG_LEVEL = 0xff;
+static uint32_t TIMESTAMP = 0;
+static uint32_t DATUM_TYPE = 0;
+static bool sVendorEnhanced = true;
+
+/* Parameter spec table */
+static const loc_param_s_type loc_param_table[] =
+{
+ {"DEBUG_LEVEL", &DEBUG_LEVEL, NULL, 'n'},
+ {"TIMESTAMP", &TIMESTAMP, NULL, 'n'},
+ {"DATUM_TYPE", &DATUM_TYPE, NULL, 'n'},
+};
+static const int loc_param_num = sizeof(loc_param_table) / sizeof(loc_param_s_type);
+
+typedef struct loc_param_v_type
+{
+ char* param_name;
+ char* param_str_value;
+ int param_int_value;
+ double param_double_value;
+}loc_param_v_type;
+
+// Reference below arrays wherever needed to avoid duplicating
+// same conf path string over and again in location code.
+const char LOC_PATH_GPS_CONF[] = LOC_PATH_GPS_CONF_STR;
+const char LOC_PATH_IZAT_CONF[] = LOC_PATH_IZAT_CONF_STR;
+const char LOC_PATH_FLP_CONF[] = LOC_PATH_FLP_CONF_STR;
+const char LOC_PATH_LOWI_CONF[] = LOC_PATH_LOWI_CONF_STR;
+const char LOC_PATH_SAP_CONF[] = LOC_PATH_SAP_CONF_STR;
+const char LOC_PATH_APDR_CONF[] = LOC_PATH_APDR_CONF_STR;
+const char LOC_PATH_XTWIFI_CONF[] = LOC_PATH_XTWIFI_CONF_STR;
+const char LOC_PATH_QUIPC_CONF[] = LOC_PATH_QUIPC_CONF_STR;
+
+bool isVendorEnhanced() {
+ return sVendorEnhanced;
+}
+void setVendorEnhanced(bool vendorEnhanced) {
+ sVendorEnhanced = vendorEnhanced;
+}
+
+/*===========================================================================
+FUNCTION loc_get_datum_type
+
+DESCRIPTION
+ get datum type
+
+PARAMETERS:
+ N/A
+
+DEPENDENCIES
+ N/A
+
+RETURN VALUE
+ DATUM TYPE
+
+SIDE EFFECTS
+ N/A
+===========================================================================*/
+int loc_get_datum_type()
+{
+ return DATUM_TYPE;
+}
+
+/*===========================================================================
+FUNCTION loc_set_config_entry
+
+DESCRIPTION
+ Potentially sets a given configuration table entry based on the passed in
+ configuration value. This is done by using a string comparison of the
+ parameter names and those found in the configuration file.
+
+PARAMETERS:
+ config_entry: configuration entry in the table to possibly set
+ config_value: value to store in the entry if the parameter names match
+
+DEPENDENCIES
+ N/A
+
+RETURN VALUE
+ None
+
+SIDE EFFECTS
+ N/A
+===========================================================================*/
+int loc_set_config_entry(const loc_param_s_type* config_entry, loc_param_v_type* config_value)
+{
+ int ret=-1;
+ if(NULL == config_entry || NULL == config_value)
+ {
+ LOC_LOGE("%s: INVALID config entry or parameter", __FUNCTION__);
+ return ret;
+ }
+
+ if (strcmp(config_entry->param_name, config_value->param_name) == 0 &&
+ config_entry->param_ptr)
+ {
+ switch (config_entry->param_type)
+ {
+ case 's':
+ if (strcmp(config_value->param_str_value, "NULL") == 0)
+ {
+ *((char*)config_entry->param_ptr) = '\0';
+ }
+ else {
+ strlcpy((char*) config_entry->param_ptr,
+ config_value->param_str_value,
+ LOC_MAX_PARAM_STRING);
+ }
+ /* Log INI values */
+ LOC_LOGD("%s: PARAM %s = %s", __FUNCTION__,
+ config_entry->param_name, (char*)config_entry->param_ptr);
+
+ if(NULL != config_entry->param_set)
+ {
+ *(config_entry->param_set) = 1;
+ }
+ ret = 0;
+ break;
+ case 'n':
+ *((int *)config_entry->param_ptr) = config_value->param_int_value;
+ /* Log INI values */
+ LOC_LOGD("%s: PARAM %s = %d", __FUNCTION__,
+ config_entry->param_name, config_value->param_int_value);
+
+ if(NULL != config_entry->param_set)
+ {
+ *(config_entry->param_set) = 1;
+ }
+ ret = 0;
+ break;
+ case 'f':
+ *((double *)config_entry->param_ptr) = config_value->param_double_value;
+ /* Log INI values */
+ LOC_LOGD("%s: PARAM %s = %f", __FUNCTION__,
+ config_entry->param_name, config_value->param_double_value);
+
+ if(NULL != config_entry->param_set)
+ {
+ *(config_entry->param_set) = 1;
+ }
+ ret = 0;
+ break;
+ default:
+ LOC_LOGE("%s: PARAM %s parameter type must be n, f, or s",
+ __FUNCTION__, config_entry->param_name);
+ }
+ }
+ return ret;
+}
+
+/*===========================================================================
+FUNCTION loc_fill_conf_item
+
+DESCRIPTION
+ Takes a line of configuration item and sets defined values based on
+ the passed in configuration table. This table maps strings to values to
+ set along with the type of each of these values.
+
+PARAMETERS:
+ input_buf : buffer contanis config item
+ config_table: table definition of strings to places to store information
+ table_length: length of the configuration table
+
+DEPENDENCIES
+ N/A
+
+RETURN VALUE
+ 0: Number of records in the config_table filled with input_buf
+
+SIDE EFFECTS
+ N/A
+===========================================================================*/
+int loc_fill_conf_item(char* input_buf,
+ const loc_param_s_type* config_table, uint32_t table_length)
+{
+ int ret = 0;
+
+ if (input_buf && config_table) {
+ char *lasts;
+ loc_param_v_type config_value;
+ memset(&config_value, 0, sizeof(config_value));
+
+ /* Separate variable and value */
+ config_value.param_name = strtok_r(input_buf, "=", &lasts);
+ /* skip lines that do not contain "=" */
+ if (config_value.param_name) {
+ config_value.param_str_value = strtok_r(NULL, "=", &lasts);
+
+ /* skip lines that do not contain two operands */
+ if (config_value.param_str_value) {
+ /* Trim leading and trailing spaces */
+ loc_util_trim_space(config_value.param_name);
+ loc_util_trim_space(config_value.param_str_value);
+
+ /* Parse numerical value */
+ if ((strlen(config_value.param_str_value) >=3) &&
+ (config_value.param_str_value[0] == '0') &&
+ (tolower(config_value.param_str_value[1]) == 'x'))
+ {
+ /* hex */
+ config_value.param_int_value = (int) strtol(&config_value.param_str_value[2],
+ (char**) NULL, 16);
+ }
+ else {
+ config_value.param_double_value = (double) atof(config_value.param_str_value); /* float */
+ config_value.param_int_value = atoi(config_value.param_str_value); /* dec */
+ }
+
+ for(uint32_t i = 0; NULL != config_table && i < table_length; i++)
+ {
+ if(!loc_set_config_entry(&config_table[i], &config_value)) {
+ ret += 1;
+ }
+ }
+ }
+ }
+ }
+
+ return ret;
+}
+
+/*===========================================================================
+FUNCTION loc_read_conf_r (repetitive)
+
+DESCRIPTION
+ Reads the specified configuration file and sets defined values based on
+ the passed in configuration table. This table maps strings to values to
+ set along with the type of each of these values.
+ The difference between this and loc_read_conf is that this function returns
+ the file pointer position at the end of filling a config table. Also, it
+ reads a fixed number of parameters at a time which is equal to the length
+ of the configuration table. This functionality enables the caller to
+ repeatedly call the function to read data from the same file.
+
+PARAMETERS:
+ conf_fp : file pointer
+ config_table: table definition of strings to places to store information
+ table_length: length of the configuration table
+
+DEPENDENCIES
+ N/A
+
+RETURN VALUE
+ 0: Table filled successfully
+ 1: No more parameters to read
+ -1: Error filling table
+
+SIDE EFFECTS
+ N/A
+===========================================================================*/
+int loc_read_conf_r(FILE *conf_fp, const loc_param_s_type* config_table, uint32_t table_length)
+{
+ int ret=0;
+
+ unsigned int num_params=table_length;
+ if(conf_fp == NULL) {
+ LOC_LOGE("%s:%d]: ERROR: File pointer is NULL\n", __func__, __LINE__);
+ ret = -1;
+ goto err;
+ }
+
+ /* Clear all validity bits */
+ for(uint32_t i = 0; NULL != config_table && i < table_length; i++)
+ {
+ if(NULL != config_table[i].param_set)
+ {
+ *(config_table[i].param_set) = 0;
+ }
+ }
+
+ char input_buf[LOC_MAX_PARAM_LINE]; /* declare a char array */
+
+ LOC_LOGD("%s:%d]: num_params: %d\n", __func__, __LINE__, num_params);
+ while(num_params)
+ {
+ if(!fgets(input_buf, LOC_MAX_PARAM_LINE, conf_fp)) {
+ LOC_LOGD("%s:%d]: fgets returned NULL\n", __func__, __LINE__);
+ break;
+ }
+
+ num_params -= loc_fill_conf_item(input_buf, config_table, table_length);
+ }
+
+err:
+ return ret;
+}
+
+/*===========================================================================
+FUNCTION loc_udpate_conf
+
+DESCRIPTION
+ Parses the passed in buffer for configuration items, and update the table
+ that is also passed in.
+
+Reads the specified configuration file and sets defined values based on
+ the passed in configuration table. This table maps strings to values to
+ set along with the type of each of these values.
+
+PARAMETERS:
+ conf_data: configuration items in bufferas a string
+ length: strlen(conf_data)
+ config_table: table definition of strings to places to store information
+ table_length: length of the configuration table
+
+DEPENDENCIES
+ N/A
+
+RETURN VALUE
+ number of the records in the table that is updated at time of return.
+
+SIDE EFFECTS
+ N/A
+===========================================================================*/
+int loc_update_conf(const char* conf_data, int32_t length,
+ const loc_param_s_type* config_table, uint32_t table_length)
+{
+ int ret = -1;
+
+ if (conf_data && length && config_table && table_length) {
+ // make a copy, so we do not tokenize the original data
+ char* conf_copy = (char*)malloc(length+1);
+
+ if (conf_copy != NULL)
+ {
+ memcpy(conf_copy, conf_data, length);
+ // we hard NULL the end of string to be safe
+ conf_copy[length] = 0;
+
+ // start with one record off
+ uint32_t num_params = table_length - 1;
+ char* saveptr = NULL;
+ char* input_buf = strtok_r(conf_copy, "\n", &saveptr);
+ ret = 0;
+
+ LOC_LOGD("%s:%d]: num_params: %d\n", __func__, __LINE__, num_params);
+ while(num_params && input_buf) {
+ ret++;
+ num_params -= loc_fill_conf_item(input_buf, config_table, table_length);
+ input_buf = strtok_r(NULL, "\n", &saveptr);
+ }
+ free(conf_copy);
+ }
+ }
+
+ return ret;
+}
+
+/*===========================================================================
+FUNCTION loc_read_conf
+
+DESCRIPTION
+ Reads the specified configuration file and sets defined values based on
+ the passed in configuration table. This table maps strings to values to
+ set along with the type of each of these values.
+
+PARAMETERS:
+ conf_file_name: configuration file to read
+ config_table: table definition of strings to places to store information
+ table_length: length of the configuration table
+
+DEPENDENCIES
+ N/A
+
+RETURN VALUE
+ None
+
+SIDE EFFECTS
+ N/A
+===========================================================================*/
+void loc_read_conf(const char* conf_file_name, const loc_param_s_type* config_table,
+ uint32_t table_length)
+{
+ FILE *conf_fp = NULL;
+
+ if((conf_fp = fopen(conf_file_name, "r")) != NULL)
+ {
+ LOC_LOGD("%s: using %s", __FUNCTION__, conf_file_name);
+ if(table_length && config_table) {
+ loc_read_conf_r(conf_fp, config_table, table_length);
+ rewind(conf_fp);
+ }
+ loc_read_conf_r(conf_fp, loc_param_table, loc_param_num);
+ fclose(conf_fp);
+ }
+ /* Initialize logging mechanism with parsed data */
+ loc_logger_init(DEBUG_LEVEL, TIMESTAMP);
+}
+
+/*=============================================================================
+ *
+ * Define and Structures for Parsing Location Process Configuration File
+ *
+ *============================================================================*/
+#define MAX_NUM_STRINGS 20
+
+//We can have 8 masks for now
+#define CONFIG_MASK_TARGET_ALL 0X01
+#define CONFIG_MASK_TARGET_FOUND 0X02
+#define CONFIG_MASK_TARGET_CHECK 0X03
+#define CONFIG_MASK_BASEBAND_ALL 0X04
+#define CONFIG_MASK_BASEBAND_FOUND 0X08
+#define CONFIG_MASK_BASEBAND_CHECK 0x0c
+#define CONFIG_MASK_AUTOPLATFORM_ALL 0x10
+#define CONFIG_MASK_AUTOPLATFORM_FOUND 0x20
+#define CONFIG_MASK_AUTOPLATFORM_CHECK 0x30
+
+#define LOC_FEATURE_MASK_GTP_WIFI_BASIC 0x01
+#define LOC_FEATURE_MASK_GTP_WIFI_PREMIUM 0X02
+#define LOC_FEATURE_MASK_GTP_CELL_BASIC 0X04
+#define LOC_FEATURE_MASK_GTP_CELL_PREMIUM 0X08
+#define LOC_FEATURE_MASK_SAP_BASIC 0x40
+#define LOC_FEATURE_MASK_SAP_PREMIUM 0X80
+#define LOC_FEATURE_MASK_GTP_WAA_BASIC 0X100
+#define LOC_FEATURE_MASK_GTP_MODEM_CELL_BASIC 0X400
+#define LOC_FEATURE_MASK_ODCPI 0x1000
+#define LOC_FEATURE_MASK_FREE_WIFI_SCAN_INJECT 0x2000
+#define LOC_FEATURE_MASK_SUPL_WIFI 0x4000
+#define LOC_FEATURE_MASK_WIFI_SUPPLICANT_INFO 0x8000
+
+typedef struct {
+ char proc_name[LOC_MAX_PARAM_STRING];
+ char proc_argument[LOC_MAX_PARAM_STRING];
+ char proc_status[LOC_MAX_PARAM_STRING];
+ char group_list[LOC_MAX_PARAM_STRING];
+ unsigned int premium_feature;
+ unsigned int loc_feature_mask;
+ char platform_list[LOC_MAX_PARAM_STRING];
+ char baseband[LOC_MAX_PARAM_STRING];
+ unsigned int sglte_target;
+ char feature_gtp_mode[LOC_MAX_PARAM_STRING];
+ char feature_gtp_waa[LOC_MAX_PARAM_STRING];
+ char feature_sap[LOC_MAX_PARAM_STRING];
+ char feature_odcpi[LOC_MAX_PARAM_STRING];
+ char feature_free_wifi_scan_inject[LOC_MAX_PARAM_STRING];
+ char feature_supl_wifi[LOC_MAX_PARAM_STRING];
+ char feature_wifi_supplicant_info[LOC_MAX_PARAM_STRING];
+ char auto_platform[LOC_MAX_PARAM_STRING];
+ unsigned int vendor_enhanced_process;
+} loc_launcher_conf;
+
+/* process configuration parameters */
+static loc_launcher_conf conf;
+
+/* gps.conf Parameter spec table */
+static const loc_param_s_type gps_conf_parameter_table[] = {
+ {"SGLTE_TARGET", &conf.sglte_target, NULL, 'n'},
+};
+
+/* location feature conf, e.g.: izat.conf feature mode table*/
+static const loc_param_s_type loc_feature_conf_table[] = {
+ {"GTP_MODE", &conf.feature_gtp_mode, NULL, 's'},
+ {"GTP_WAA", &conf.feature_gtp_waa, NULL, 's'},
+ {"SAP", &conf.feature_sap, NULL, 's'},
+ {"ODCPI", &conf.feature_odcpi, NULL, 's'},
+ {"FREE_WIFI_SCAN_INJECT", &conf.feature_free_wifi_scan_inject, NULL, 's'},
+ {"SUPL_WIFI", &conf.feature_supl_wifi, NULL, 's'},
+ {"WIFI_SUPPLICANT_INFO", &conf.feature_wifi_supplicant_info, NULL, 's'},
+};
+
+/* location process conf, e.g.: izat.conf Parameter spec table */
+static const loc_param_s_type loc_process_conf_parameter_table[] = {
+ {"PROCESS_NAME", &conf.proc_name, NULL, 's'},
+ {"PROCESS_ARGUMENT", &conf.proc_argument, NULL, 's'},
+ {"PROCESS_STATE", &conf.proc_status, NULL, 's'},
+ {"PROCESS_GROUPS", &conf.group_list, NULL, 's'},
+ {"PREMIUM_FEATURE", &conf.premium_feature, NULL, 'n'},
+ {"IZAT_FEATURE_MASK", &conf.loc_feature_mask, NULL, 'n'},
+ {"PLATFORMS", &conf.platform_list, NULL, 's'},
+ {"BASEBAND", &conf.baseband, NULL, 's'},
+ {"HARDWARE_TYPE", &conf.auto_platform, NULL, 's'},
+ {"VENDOR_ENHANCED_PROCESS", &conf.vendor_enhanced_process, NULL, 'n'},
+};
+
+/*===========================================================================
+FUNCTION loc_read_process_conf
+
+DESCRIPTION
+ Parse the specified conf file and return info for the processes defined.
+ The format of the file should conform with izat.conf.
+
+PARAMETERS:
+ conf_file_name: configuration file to read
+ process_count_ptr: pointer to store number of processes defined in the conf file.
+ process_info_table_ptr: pointer to store the process info table.
+
+DEPENDENCIES
+ The file must be in izat.conf format.
+
+RETURN VALUE
+ 0: success
+ none-zero: failure
+
+SIDE EFFECTS
+ N/A
+
+NOTES:
+ On success, memory pointed by (*process_info_table_ptr) must be freed.
+===========================================================================*/
+int loc_read_process_conf(const char* conf_file_name, uint32_t * process_count_ptr,
+ loc_process_info_s_type** process_info_table_ptr) {
+ loc_process_info_s_type *child_proc = nullptr;
+ volatile int i=0;
+ unsigned int j=0;
+ gid_t gid_list[LOC_PROCESS_MAX_NUM_GROUPS];
+ char *split_strings[MAX_NUM_STRINGS];
+ int name_length=0, group_list_length=0, platform_length=0, baseband_length=0, ngroups=0, ret=0;
+ int auto_platform_length = 0;
+ int group_index=0, nstrings=0, status_length=0;
+ FILE* conf_fp = nullptr;
+ char platform_name[PROPERTY_VALUE_MAX], baseband_name[PROPERTY_VALUE_MAX];
+ char autoplatform_name[PROPERTY_VALUE_MAX];
+ unsigned int loc_service_mask=0;
+ char config_mask = 0;
+ unsigned char proc_list_length=0;
+ int gtp_cell_ap_enabled = 0;
+ char arg_gtp_waa[LOC_PROCESS_MAX_ARG_STR_LENGTH] = "--";
+ char arg_gtp_modem_cell[LOC_PROCESS_MAX_ARG_STR_LENGTH] = "--";
+ char arg_gtp_wifi[LOC_PROCESS_MAX_ARG_STR_LENGTH] = "--";
+ char arg_sap[LOC_PROCESS_MAX_ARG_STR_LENGTH] = "--";
+ char arg_disabled[LOC_PROCESS_MAX_ARG_STR_LENGTH] = LOC_FEATURE_MODE_DISABLED;
+ char arg_basic[LOC_PROCESS_MAX_ARG_STR_LENGTH] = LOC_FEATURE_MODE_BASIC;
+ char arg_premium[LOC_PROCESS_MAX_ARG_STR_LENGTH] = LOC_FEATURE_MODE_PREMIUM;
+
+ if (process_count_ptr == NULL || process_info_table_ptr == NULL) {
+ return -1;
+ }
+
+ //Read gps.conf and fill parameter table
+ UTIL_READ_CONF(LOC_PATH_GPS_CONF, gps_conf_parameter_table);
+
+ //Form argument strings
+ strlcat(arg_gtp_waa, LOC_FEATURE_GTP_WAA, LOC_PROCESS_MAX_ARG_STR_LENGTH-3);
+ strlcat(arg_gtp_modem_cell, LOC_FEATURE_GTP_MODEM_CELL, LOC_PROCESS_MAX_ARG_STR_LENGTH-3);
+ strlcat(arg_gtp_wifi, LOC_FEATURE_GTP_WIFI, LOC_PROCESS_MAX_ARG_STR_LENGTH-3);
+ strlcat(arg_sap, LOC_FEATURE_SAP, LOC_PROCESS_MAX_ARG_STR_LENGTH-3);
+
+ //Get platform name from ro.board.platform property
+ loc_get_platform_name(platform_name, sizeof(platform_name));
+ //Get baseband name from ro.baseband property
+ loc_get_target_baseband(baseband_name, sizeof(baseband_name));
+ //Identify if this is an automotive platform
+ loc_get_auto_platform_name(autoplatform_name,sizeof(autoplatform_name));
+
+ UTIL_READ_CONF(conf_file_name, loc_feature_conf_table);
+
+ //Set service mask for GTP_MODE
+ if(strcmp(conf.feature_gtp_mode, "DISABLED") == 0) {
+ LOC_LOGD("%s:%d]: GTP MODE DISABLED", __func__, __LINE__);
+ }
+ else if(strcmp(conf.feature_gtp_mode, "LEGACY_WWAN") == 0) {
+ LOC_LOGD("%s:%d]: Setting GTP MODE to mode: LEGACY_WWAN", __func__, __LINE__);
+ loc_service_mask |= LOC_FEATURE_MASK_GTP_MODEM_CELL_BASIC;
+ }
+ else if(strcmp(conf.feature_gtp_mode, "SDK") == 0) {
+ LOC_LOGD("%s:%d]: Setting GTP MODE to mode: SDK", __func__, __LINE__);
+ loc_service_mask |= LOC_FEATURE_MASK_GTP_WIFI_BASIC;
+ }
+ //conf file has a garbage value
+ else {
+ LOC_LOGE("%s:%d]: Unrecognized value for GTP MODE Mode."\
+ " Setting GTP WIFI to default mode: DISABLED", __func__, __LINE__);
+ }
+ //Set service mask for GTP_WAA
+ if(strcmp(conf.feature_gtp_waa, "BASIC") == 0) {
+ LOC_LOGD("%s:%d]: Setting GTP WAA to mode: BASIC", __func__, __LINE__);
+ loc_service_mask |= LOC_FEATURE_MASK_GTP_WAA_BASIC;
+ }
+ else if(strcmp(conf.feature_gtp_waa, "DISABLED") == 0) {
+ LOC_LOGD("%s:%d]: GTP WAA DISABLED", __func__, __LINE__);
+ }
+ //conf file has a garbage value
+ else {
+ LOC_LOGE("%s:%d]: Unrecognized value for GTP WAA Mode."\
+ " Setting GTP WAA to default mode: DISABLED", __func__, __LINE__);
+ }
+
+ //Set service mask for SAP
+ if(strcmp(conf.feature_sap, "PREMIUM") == 0) {
+ LOC_LOGD("%s:%d]: Setting SAP to mode: PREMIUM", __func__, __LINE__);
+ loc_service_mask |= LOC_FEATURE_MASK_SAP_PREMIUM;
+ }
+ else if(strcmp(conf.feature_sap, "BASIC") == 0) {
+ LOC_LOGD("%s:%d]: Setting SAP to mode: BASIC", __func__, __LINE__);
+ loc_service_mask |= LOC_FEATURE_MASK_SAP_BASIC;
+ }
+ else if(strcmp(conf.feature_sap, "MODEM_DEFAULT") == 0) {
+ LOC_LOGD("%s:%d]: Setting SAP to mode: MODEM_DEFAULT", __func__, __LINE__);
+ }
+ else if(strcmp(conf.feature_sap, "DISABLED") == 0) {
+ LOC_LOGD("%s:%d]: Setting SAP to mode: DISABLED", __func__, __LINE__);
+ }
+ else {
+ LOC_LOGE("%s:%d]: Unrecognized value for SAP Mode."\
+ " Setting SAP to default mode: BASIC", __func__, __LINE__);
+ loc_service_mask |= LOC_FEATURE_MASK_SAP_BASIC;
+ }
+
+ // Set service mask for ODCPI
+ if(strcmp(conf.feature_odcpi, "BASIC") == 0) {
+ LOC_LOGD("%s:%d]: Setting ODCPI to mode: BASIC", __func__, __LINE__);
+ loc_service_mask |= LOC_FEATURE_MASK_ODCPI;
+ }
+ else if(strcmp(conf.feature_odcpi, "DISABLED") == 0) {
+ LOC_LOGD("%s:%d]: Setting ODCPI to mode: DISABLED", __func__, __LINE__);
+ }
+ else if(strcmp(conf.feature_odcpi, "PREMIUM") == 0) {
+ LOC_LOGD("%s:%d]: Unrecognized value for ODCPI mode."\
+ "Setting ODCPI to default mode: BASIC", __func__, __LINE__);
+ loc_service_mask |= LOC_FEATURE_MASK_ODCPI;
+ }
+
+ // Set service mask for FREE_WIFI_SCAN_INJECT
+ if(strcmp(conf.feature_free_wifi_scan_inject, "BASIC") == 0) {
+ LOC_LOGD("%s:%d]: Setting FREE_WIFI_SCAN_INJECT to mode: BASIC", __func__, __LINE__);
+ loc_service_mask |= LOC_FEATURE_MASK_FREE_WIFI_SCAN_INJECT;
+ }
+ else if(strcmp(conf.feature_free_wifi_scan_inject, "DISABLED") == 0) {
+ LOC_LOGD("%s:%d]: Setting FREE_WIFI_SCAN_INJECT to mode: DISABLED", __func__, __LINE__);
+ }
+ else if(strcmp(conf.feature_free_wifi_scan_inject, "PREMIUM") == 0) {
+ LOC_LOGD("%s:%d]: Unrecognized value for FREE_WIFI_SCAN_INJECT mode."\
+ "Setting FREE_WIFI_SCAN_INJECT to default mode: BASIC", __func__, __LINE__);
+ loc_service_mask |= LOC_FEATURE_MASK_FREE_WIFI_SCAN_INJECT;
+ }
+
+ // Set service mask for SUPL_WIFI
+ if(strcmp(conf.feature_supl_wifi, "BASIC") == 0) {
+ LOC_LOGD("%s:%d]: Setting SUPL_WIFI to mode: BASIC", __func__, __LINE__);
+ loc_service_mask |= LOC_FEATURE_MASK_SUPL_WIFI;
+ }
+ else if(strcmp(conf.feature_supl_wifi, "DISABLED") == 0) {
+ LOC_LOGD("%s:%d]: Setting SUPL_WIFI to mode: DISABLED", __func__, __LINE__);
+ }
+ else if(strcmp(conf.feature_supl_wifi, "PREMIUM") == 0) {
+ LOC_LOGD("%s:%d]: Unrecognized value for SUPL_WIFI mode."\
+ "Setting SUPL_WIFI to default mode: BASIC", __func__, __LINE__);
+ loc_service_mask |= LOC_FEATURE_MASK_SUPL_WIFI;
+ }
+
+ // Set service mask for WIFI_SUPPLICANT_INFO
+ if(strcmp(conf.feature_wifi_supplicant_info, "BASIC") == 0) {
+ LOC_LOGD("%s:%d]: Setting WIFI_SUPPLICANT_INFO to mode: BASIC", __func__, __LINE__);
+ loc_service_mask |= LOC_FEATURE_MASK_WIFI_SUPPLICANT_INFO;
+ }
+ else if(strcmp(conf.feature_wifi_supplicant_info, "DISABLED") == 0) {
+ LOC_LOGD("%s:%d]: Setting WIFI_SUPPLICANT_INFO to mode: DISABLED", __func__, __LINE__);
+ }
+ else if(strcmp(conf.feature_wifi_supplicant_info, "PREMIUM") == 0) {
+ LOC_LOGD("%s:%d]: Unrecognized value for WIFI_SUPPLICANT_INFO mode."\
+ "Setting LOC_FEATURE_MASK_WIFI_SUPPLICANT_INFO to default mode: BASIC", __func__, __LINE__);
+ loc_service_mask |= LOC_FEATURE_MASK_WIFI_SUPPLICANT_INFO;
+ }
+
+ LOC_LOGD("%s:%d]: loc_service_mask: %x\n", __func__, __LINE__, loc_service_mask);
+
+ if((conf_fp = fopen(conf_file_name, "r")) == NULL) {
+ LOC_LOGE("%s:%d]: Error opening %s %s\n", __func__,
+ __LINE__, conf_file_name, strerror(errno));
+ ret = -1;
+ goto err;
+ }
+
+ //Parse through the file to find out how many processes are to be launched
+ proc_list_length = 0;
+ do {
+ conf.proc_name[0] = 0;
+ //Here note that the 3rd parameter is passed as 1.
+ //This is so that only the first parameter in the table which is "PROCESS_NAME"
+ //is read. We do not want to read the entire block of parameters at this time
+ //since we are only counting the number of processes to launch.
+ //Therefore, only counting the occurrences of PROCESS_NAME parameter
+ //should suffice
+ if(loc_read_conf_r(conf_fp, loc_process_conf_parameter_table, 1)) {
+ LOC_LOGE("%s:%d]: Unable to read conf file. Failing\n", __func__, __LINE__);
+ ret = -1;
+ goto err;
+ }
+ name_length=(int)strlen(conf.proc_name);
+ if(name_length) {
+ proc_list_length++;
+ LOC_LOGD("Process name:%s", conf.proc_name);
+ }
+ } while(name_length);
+ LOC_LOGD("Process cnt = %d", proc_list_length);
+
+ child_proc = (loc_process_info_s_type *)calloc(proc_list_length, sizeof(loc_process_info_s_type));
+ if(child_proc == NULL) {
+ LOC_LOGE("%s:%d]: ERROR: Malloc returned NULL\n", __func__, __LINE__);
+ ret = -1;
+ goto err;
+ }
+
+ //Move file descriptor to the beginning of the file
+ //so that the parameters can be read
+ rewind(conf_fp);
+
+ for(j=0; j<proc_list_length; j++) {
+ //Set defaults for all the child process structs
+ child_proc[j].proc_status = DISABLED;
+ memset(child_proc[j].group_list, 0, sizeof(child_proc[j].group_list));
+ config_mask=0;
+ if(loc_read_conf_r(conf_fp, loc_process_conf_parameter_table,
+ sizeof(loc_process_conf_parameter_table)/sizeof(loc_process_conf_parameter_table[0]))) {
+ LOC_LOGE("%s:%d]: Unable to read conf file. Failing\n", __func__, __LINE__);
+ ret = -1;
+ goto err;
+ }
+
+ name_length=(int)strlen(conf.proc_name);
+ group_list_length=(int)strlen(conf.group_list);
+ platform_length = (int)strlen(conf.platform_list);
+ baseband_length = (int)strlen(conf.baseband);
+ status_length = (int)strlen(conf.proc_status);
+ auto_platform_length = (int)strlen(conf.auto_platform);
+
+ if(!name_length || !group_list_length || !platform_length ||
+ !baseband_length || !status_length || !auto_platform_length) {
+ LOC_LOGE("%s:%d]: Error: i: %d; One of the parameters not specified in conf file",
+ __func__, __LINE__, i);
+ continue;
+ }
+
+ if (!isVendorEnhanced() && (conf.vendor_enhanced_process != 0)) {
+ LOC_LOGD("%s:%d]: Process %s is disabled via vendor enhanced process check",
+ __func__, __LINE__, conf.proc_name);
+ child_proc[j].proc_status = DISABLED_VIA_VENDOR_ENHANCED_CHECK;
+ continue;
+ }
+
+ if(strcmp(conf.proc_status, "DISABLED") == 0) {
+ LOC_LOGD("%s:%d]: Process %s is disabled in conf file",
+ __func__, __LINE__, conf.proc_name);
+ child_proc[j].proc_status = DISABLED_FROM_CONF;
+ continue;
+ }
+ else if(strcmp(conf.proc_status, "ENABLED") == 0) {
+ LOC_LOGD("%s:%d]: Process %s is enabled in conf file",
+ __func__, __LINE__, conf.proc_name);
+ }
+
+ //Since strlcpy copies length-1 characters, we add 1 to name_length
+ if((name_length+1) > LOC_MAX_PARAM_STRING) {
+ LOC_LOGE("%s:%d]: i: %d; Length of name parameter too long. Max length: %d",
+ __func__, __LINE__, i, LOC_MAX_PARAM_STRING);
+ continue;
+ }
+ strlcpy(child_proc[j].name[0], conf.proc_name, sizeof (child_proc[j].name[0]));
+
+ child_proc[j].num_groups = 0;
+ ngroups = loc_util_split_string(conf.group_list, split_strings, MAX_NUM_STRINGS, ' ');
+ for(i=0; i<ngroups; i++) {
+ struct group* grp = getgrnam(split_strings[i]);
+ if (grp) {
+ child_proc[j].group_list[child_proc[j].num_groups] = grp->gr_gid;
+ child_proc[j].num_groups++;
+ LOC_LOGd("Group %s = %d", split_strings[i], grp->gr_gid);
+ }
+ }
+
+ nstrings = loc_util_split_string(conf.platform_list, split_strings, MAX_NUM_STRINGS, ' ');
+ if(strcmp("all", split_strings[0]) == 0) {
+ if (nstrings == 1 || (nstrings == 2 && (strcmp("exclude", split_strings[1]) == 0))) {
+ LOC_LOGD("%s:%d]: Enabled for all targets\n", __func__, __LINE__);
+ config_mask |= CONFIG_MASK_TARGET_ALL;
+ }
+ else if (nstrings > 2 && (strcmp("exclude", split_strings[1]) == 0)) {
+ config_mask |= CONFIG_MASK_TARGET_FOUND;
+ for (i=2; i<nstrings; i++) {
+ if(strcmp(platform_name, split_strings[i]) == 0) {
+ LOC_LOGD("%s:%d]: Disabled platform %s\n", __func__, __LINE__, platform_name);
+ config_mask &= ~CONFIG_MASK_TARGET_FOUND;
+ break;
+ }
+ }
+ }
+ }
+ else {
+ for(i=0; i<nstrings; i++) {
+ if(strcmp(platform_name, split_strings[i]) == 0) {
+ LOC_LOGD("%s:%d]: Matched platform: %s\n",
+ __func__, __LINE__, split_strings[i]);
+ config_mask |= CONFIG_MASK_TARGET_FOUND;
+ break;
+ }
+ }
+ }
+
+ nstrings = loc_util_split_string(conf.baseband, split_strings, MAX_NUM_STRINGS, ' ');
+ if(strcmp("all", split_strings[0]) == 0) {
+ if (nstrings == 1 || (nstrings == 2 && (strcmp("exclude", split_strings[1]) == 0))) {
+ LOC_LOGD("%s:%d]: Enabled for all basebands\n", __func__, __LINE__);
+ config_mask |= CONFIG_MASK_BASEBAND_ALL;
+ }
+ else if (nstrings > 2 && (strcmp("exclude", split_strings[1]) == 0)) {
+ config_mask |= CONFIG_MASK_BASEBAND_FOUND;
+ for (i=2; i<nstrings; i++) {
+ if(strcmp(baseband_name, split_strings[i]) == 0) {
+ LOC_LOGD("%s:%d]: Disabled band %s\n", __func__, __LINE__, baseband_name);
+ config_mask &= ~CONFIG_MASK_BASEBAND_FOUND;
+ break;
+ }
+ }
+ }
+ }
+ else {
+ for(i=0; i<nstrings; i++) {
+ if(strcmp(baseband_name, split_strings[i]) == 0) {
+ LOC_LOGD("%s:%d]: Matched baseband: %s\n",
+ __func__, __LINE__, split_strings[i]);
+ config_mask |= CONFIG_MASK_BASEBAND_FOUND;
+ break;
+ }
+ //Since ro.baseband is not a reliable source for detecting sglte
+ //the alternative is to read the SGLTE_TARGET parameter from gps.conf
+ //this parameter is read into conf_sglte_target
+ else if((strcmp("sglte", split_strings[i]) == 0 ) && conf.sglte_target) {
+ LOC_LOGD("%s:%d]: Matched baseband SGLTE\n", __func__, __LINE__);
+ config_mask |= CONFIG_MASK_BASEBAND_FOUND;
+ break;
+ }
+ }
+ }
+
+ nstrings = loc_util_split_string(conf.auto_platform, split_strings, MAX_NUM_STRINGS, ' ');
+ if(strcmp("all", split_strings[0]) == 0) {
+ LOC_LOGD("%s:%d]: Enabled for all auto platforms\n", __func__, __LINE__);
+ config_mask |= CONFIG_MASK_AUTOPLATFORM_ALL;
+ }
+ else {
+ for(i=0; i<nstrings; i++) {
+ if(strcmp(autoplatform_name, split_strings[i]) == 0) {
+ LOC_LOGD("%s:%d]: Matched auto platform: %s\n",
+ __func__, __LINE__, split_strings[i]);
+ config_mask |= CONFIG_MASK_AUTOPLATFORM_FOUND;
+ break;
+ }
+ }
+ }
+
+ if((config_mask & CONFIG_MASK_TARGET_CHECK) &&
+ (config_mask & CONFIG_MASK_BASEBAND_CHECK) &&
+ (config_mask & CONFIG_MASK_AUTOPLATFORM_CHECK) &&
+ (child_proc[j].proc_status != DISABLED_FROM_CONF) &&
+ (child_proc[j].proc_status != DISABLED_VIA_VENDOR_ENHANCED_CHECK)) {
+
+ //Set args
+ //The first argument passed through argv is usually the name of the
+ //binary when started from commandline.
+ //getopt() seems to ignore this first argument and hence we assign it
+ //to the process name for consistency with command line args
+ i = 0;
+ char* temp_arg = ('/' == child_proc[j].name[0][0]) ?
+ (strrchr(child_proc[j].name[0], '/') + 1) : child_proc[j].name[0];
+ strlcpy (child_proc[j].args[i++], temp_arg, sizeof (child_proc[j].args[i++]));
+
+ if(conf.premium_feature) {
+ if(conf.loc_feature_mask & loc_service_mask) {
+ LOC_LOGD("%s:%d]: Enabled. %s has service mask: %x\n",
+ __func__, __LINE__, child_proc[j].name[0], conf.loc_feature_mask);
+ child_proc[j].proc_status = ENABLED;
+
+ if(conf.loc_feature_mask &
+ (LOC_FEATURE_MASK_GTP_WIFI_BASIC | LOC_FEATURE_MASK_GTP_WIFI_PREMIUM)) {
+ if(loc_service_mask & LOC_FEATURE_MASK_GTP_WIFI_BASIC) {
+ strlcpy(child_proc[j].args[i++], arg_gtp_wifi,
+ LOC_PROCESS_MAX_ARG_STR_LENGTH);
+ strlcpy(child_proc[j].args[i++], arg_basic,
+ LOC_PROCESS_MAX_ARG_STR_LENGTH);
+ }
+ else if(loc_service_mask & LOC_FEATURE_MASK_GTP_WIFI_PREMIUM) {
+ strlcpy(child_proc[j].args[i++], arg_gtp_wifi,
+ LOC_PROCESS_MAX_ARG_STR_LENGTH);
+ strlcpy(child_proc[j].args[i++], arg_premium,
+ LOC_PROCESS_MAX_ARG_STR_LENGTH);
+ }
+ else
+ {
+ strlcpy(child_proc[j].args[i++], arg_gtp_wifi,
+ LOC_PROCESS_MAX_ARG_STR_LENGTH);
+ strlcpy(child_proc[j].args[i++], arg_disabled,
+ LOC_PROCESS_MAX_ARG_STR_LENGTH);
+ }
+ }
+ if(conf.loc_feature_mask &
+ (LOC_FEATURE_MASK_GTP_CELL_BASIC | LOC_FEATURE_MASK_GTP_CELL_PREMIUM )) {
+ if(loc_service_mask & LOC_FEATURE_MASK_GTP_MODEM_CELL_BASIC) {
+ strlcpy(child_proc[j].args[i++], arg_gtp_modem_cell,
+ LOC_PROCESS_MAX_ARG_STR_LENGTH);
+ strlcpy(child_proc[j].args[i++], arg_basic,
+ LOC_PROCESS_MAX_ARG_STR_LENGTH);
+ }
+ else {
+ strlcpy(child_proc[j].args[i++], arg_gtp_modem_cell,
+ LOC_PROCESS_MAX_ARG_STR_LENGTH);
+ strlcpy(child_proc[j].args[i++], arg_disabled,
+ LOC_PROCESS_MAX_ARG_STR_LENGTH);
+ }
+ }
+ if(conf.loc_feature_mask &
+ (LOC_FEATURE_MASK_SAP_BASIC | LOC_FEATURE_MASK_SAP_PREMIUM)) {
+ if(loc_service_mask & LOC_FEATURE_MASK_SAP_BASIC) {
+ strlcpy(child_proc[j].args[i++], arg_sap,
+ LOC_PROCESS_MAX_ARG_STR_LENGTH);
+ strlcpy(child_proc[j].args[i++], arg_basic,
+ LOC_PROCESS_MAX_ARG_STR_LENGTH);
+ }
+ else if(loc_service_mask & LOC_FEATURE_MASK_SAP_PREMIUM) {
+ strlcpy(child_proc[j].args[i++], arg_sap,
+ LOC_PROCESS_MAX_ARG_STR_LENGTH);
+ strlcpy(child_proc[j].args[i++], arg_premium,
+ LOC_PROCESS_MAX_ARG_STR_LENGTH);
+ }
+ else
+ {
+ strlcpy(child_proc[j].args[i++], arg_sap,
+ LOC_PROCESS_MAX_ARG_STR_LENGTH);
+ strlcpy(child_proc[j].args[i++], arg_disabled,
+ LOC_PROCESS_MAX_ARG_STR_LENGTH);
+ }
+ }
+
+ if(conf.loc_feature_mask & LOC_FEATURE_MASK_GTP_WAA_BASIC) {
+ if(loc_service_mask & LOC_FEATURE_MASK_GTP_WAA_BASIC) {
+ strlcpy(child_proc[j].args[i++], arg_gtp_waa,
+ LOC_PROCESS_MAX_ARG_STR_LENGTH);
+ strlcpy(child_proc[j].args[i++], arg_basic,
+ LOC_PROCESS_MAX_ARG_STR_LENGTH);
+ }
+ else
+ {
+ strlcpy(child_proc[j].args[i++], arg_gtp_waa,
+ LOC_PROCESS_MAX_ARG_STR_LENGTH);
+ strlcpy(child_proc[j].args[i++], arg_disabled,
+ LOC_PROCESS_MAX_ARG_STR_LENGTH);
+ }
+ }
+ IF_LOC_LOGD {
+ LOC_LOGD("%s:%d]: %s args\n", __func__, __LINE__, child_proc[j].name[0]);
+ for(unsigned int k=0; k<LOC_PROCESS_MAX_NUM_ARGS; k++) {
+ if(child_proc[j].args[k][0] != '\0') {
+ LOC_LOGD("%s:%d]: k: %d, %s\n", __func__, __LINE__, k,
+ child_proc[j].args[k]);
+ }
+ }
+ LOC_LOGD("%s:%d]: \n", __func__, __LINE__);
+ }
+ }
+ else {
+ LOC_LOGD("%s:%d]: Disabled. %s has service mask: %x \n",
+ __func__, __LINE__, child_proc[j].name[0], conf.loc_feature_mask);
+ }
+ }
+ else {
+ LOC_LOGD("%s:%d]: %s not a premium feature. Enabled\n",
+ __func__, __LINE__, child_proc[j].name[0]);
+ child_proc[j].proc_status = ENABLED;
+ }
+
+ /*Fill up the remaining arguments from configuration file*/
+ LOC_LOGD("%s] Parsing Process_Arguments from Configuration: %s \n",
+ __func__, conf.proc_argument);
+ if(0 != conf.proc_argument[0])
+ {
+ /**************************************
+ ** conf_proc_argument is shared by all the programs getting launched,
+ ** hence copy to process specific argument string and parse the same.
+ ***************************************/
+ strlcpy(child_proc[j].argumentString, conf.proc_argument,
+ sizeof(child_proc[j].argumentString));
+ char *temp_args[LOC_PROCESS_MAX_NUM_ARGS];
+ memset (temp_args, 0, sizeof (temp_args));
+ loc_util_split_string(child_proc[j].argumentString, &temp_args[i],
+ (LOC_PROCESS_MAX_NUM_ARGS - i), ' ');
+ // copy argument from the pointer to the memory
+ for (unsigned int index = i; index < LOC_PROCESS_MAX_NUM_ARGS; index++) {
+ if (temp_args[index] == NULL) {
+ break;
+ }
+ strlcpy (child_proc[j].args[index], temp_args[index],
+ sizeof (child_proc[j].args[index]));
+ }
+ }
+ }
+ else {
+ LOC_LOGD("%s:%d]: Process %s is disabled\n",
+ __func__, __LINE__, child_proc[j].name[0]);
+ }
+ }
+
+err:
+ if (conf_fp) {
+ fclose(conf_fp);
+ }
+ if (ret != 0) {
+ LOC_LOGE("%s:%d]: ret: %d", __func__, __LINE__, ret);
+ if (child_proc) {
+ free (child_proc);
+ child_proc = nullptr;
+ }
+ *process_count_ptr = 0;
+ *process_info_table_ptr = nullptr;
+
+ }
+ else {
+ *process_count_ptr = proc_list_length;
+ *process_info_table_ptr = child_proc;
+ }
+
+ return ret;
+}
diff --git a/utils/loc_cfg.h b/utils/loc_cfg.h
new file mode 100644
index 0000000..5c77dc6
--- /dev/null
+++ b/utils/loc_cfg.h
@@ -0,0 +1,143 @@
+/* Copyright (c) 2011-2015, 2018 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 LOC_CFG_H
+#define LOC_CFG_H
+
+#include <stdio.h>
+#include <stdint.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <grp.h>
+
+#define LOC_MAX_PARAM_NAME 80
+#define LOC_MAX_PARAM_STRING 172
+#define LOC_MAX_PARAM_LINE (LOC_MAX_PARAM_NAME + LOC_MAX_PARAM_STRING)
+
+#define LOC_FEATURE_MODE_DISABLED "DISABLED"
+#define LOC_FEATURE_MODE_BASIC "BASIC"
+#define LOC_FEATURE_MODE_PREMIUM "PREMIUM"
+
+#define LOC_FEATURE_GTP_AP_CELL "gtp-ap-cell"
+#define LOC_FEATURE_GTP_MODEM_CELL "gtp-modem-cell"
+#define LOC_FEATURE_GTP_CELL_ENH "gtp-cell-enh"
+#define LOC_FEATURE_GTP_WIFI "gtp-wifi"
+#define LOC_FEATURE_GTP_WAA "gtp-waa"
+#define LOC_FEATURE_SAP "sap"
+
+#define LOC_PROCESS_MAX_NUM_GROUPS 20
+#define LOC_PROCESS_MAX_NUM_ARGS 25
+#define LOC_PROCESS_MAX_ARG_STR_LENGTH 32
+
+#define UTIL_UPDATE_CONF(conf_data, len, config_table) \
+ loc_update_conf((conf_data), (len), (config_table), \
+ sizeof(config_table) / sizeof(config_table[0]))
+
+#define UTIL_READ_CONF_DEFAULT(filename) \
+ loc_read_conf((filename), NULL, 0);
+
+#define UTIL_READ_CONF(filename, config_table) \
+ loc_read_conf((filename), (config_table), sizeof(config_table) / sizeof(config_table[0]))
+
+/*=============================================================================
+ *
+ * MODULE TYPE DECLARATION
+ *
+ *============================================================================*/
+typedef struct
+{
+ const char *param_name;
+ void *param_ptr; /* for string type, buf size need to be LOC_MAX_PARAM_STRING */
+ uint8_t *param_set; /* indicate value set by config file */
+ char param_type; /* 'n' for number,
+ 's' for string, NOTE: buf size need to be LOC_MAX_PARAM_STRING
+ 'f' for double */
+} loc_param_s_type;
+
+typedef enum {
+ ENABLED,
+ RUNNING,
+ DISABLED,
+ DISABLED_FROM_CONF,
+ DISABLED_VIA_VENDOR_ENHANCED_CHECK
+} loc_process_e_status;
+
+typedef struct {
+ loc_process_e_status proc_status;
+ pid_t proc_id;
+ char name[2][LOC_MAX_PARAM_STRING];
+ gid_t group_list[LOC_PROCESS_MAX_NUM_GROUPS];
+ unsigned char num_groups;
+ char args[LOC_PROCESS_MAX_NUM_ARGS][LOC_PROCESS_MAX_ARG_STR_LENGTH];
+ char argumentString[LOC_MAX_PARAM_STRING];
+} loc_process_info_s_type;
+
+/*=============================================================================
+ *
+ * MODULE EXTERNAL DATA
+ *
+ *============================================================================*/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*=============================================================================
+ *
+ * MODULE EXPORTED FUNCTIONS
+ *
+ *============================================================================*/
+bool isVendorEnhanced();
+void setVendorEnhanced(bool vendorEnhanced);
+void loc_read_conf(const char* conf_file_name,
+ const loc_param_s_type* config_table,
+ uint32_t table_length);
+int loc_read_conf_r(FILE *conf_fp, const loc_param_s_type* config_table,
+ uint32_t table_length);
+int loc_update_conf(const char* conf_data, int32_t length,
+ const loc_param_s_type* config_table, uint32_t table_length);
+
+// Below are the location conf file paths
+extern const char LOC_PATH_GPS_CONF[];
+extern const char LOC_PATH_IZAT_CONF[];
+extern const char LOC_PATH_FLP_CONF[];
+extern const char LOC_PATH_LOWI_CONF[];
+extern const char LOC_PATH_SAP_CONF[];
+extern const char LOC_PATH_APDR_CONF[];
+extern const char LOC_PATH_XTWIFI_CONF[];
+extern const char LOC_PATH_QUIPC_CONF[];
+
+int loc_read_process_conf(const char* conf_file_name, uint32_t * process_count_ptr,
+ loc_process_info_s_type** process_info_table_ptr);
+int loc_get_datum_type();
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* LOC_CFG_H */
diff --git a/utils/loc_gps.h b/utils/loc_gps.h
new file mode 100644
index 0000000..eae7383
--- /dev/null
+++ b/utils/loc_gps.h
@@ -0,0 +1,2229 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef LOC_GPS_H
+#define LOC_GPS_H
+
+#include <stdint.h>
+#include <sys/cdefs.h>
+#include <sys/types.h>
+#include <pthread.h>
+#include <sys/socket.h>
+#include <stdbool.h>
+
+__BEGIN_DECLS
+
+#define LOC_FLP_STATUS_LOCATION_AVAILABLE 0
+#define LOC_FLP_STATUS_LOCATION_UNAVAILABLE 1
+#define LOC_CAPABILITY_GNSS (1U<<0)
+#define LOC_CAPABILITY_WIFI (1U<<1)
+#define LOC_CAPABILITY_CELL (1U<<3)
+
+/** Milliseconds since January 1, 1970 */
+typedef int64_t LocGpsUtcTime;
+
+/** Maximum number of SVs for loc_gps_sv_status_callback(). */
+#define LOC_GPS_MAX_SVS 32
+/** Maximum number of SVs for loc_gps_sv_status_callback(). */
+#define LOC_GNSS_MAX_SVS 64
+
+/** Maximum number of Measurements in loc_gps_measurement_callback(). */
+#define LOC_GPS_MAX_MEASUREMENT 32
+
+/** Maximum number of Measurements in loc_gnss_measurement_callback(). */
+#define LOC_GNSS_MAX_MEASUREMENT 64
+
+/** Requested operational mode for GPS operation. */
+typedef uint32_t LocGpsPositionMode;
+/* IMPORTANT: Note that the following values must match
+ * constants in GpsLocationProvider.java. */
+/** Mode for running GPS standalone (no assistance). */
+#define LOC_GPS_POSITION_MODE_STANDALONE 0
+/** AGPS MS-Based mode. */
+#define LOC_GPS_POSITION_MODE_MS_BASED 1
+/**
+ * AGPS MS-Assisted mode. This mode is not maintained by the platform anymore.
+ * It is strongly recommended to use LOC_GPS_POSITION_MODE_MS_BASED instead.
+ */
+#define LOC_GPS_POSITION_MODE_MS_ASSISTED 2
+
+/** Requested recurrence mode for GPS operation. */
+typedef uint32_t LocGpsPositionRecurrence;
+/* IMPORTANT: Note that the following values must match
+ * constants in GpsLocationProvider.java. */
+/** Receive GPS fixes on a recurring basis at a specified period. */
+#define LOC_GPS_POSITION_RECURRENCE_PERIODIC 0
+/** Request a single shot GPS fix. */
+#define LOC_GPS_POSITION_RECURRENCE_SINGLE 1
+
+/** GPS status event values. */
+typedef uint16_t LocGpsStatusValue;
+/* IMPORTANT: Note that the following values must match
+ * constants in GpsLocationProvider.java. */
+/** GPS status unknown. */
+#define LOC_GPS_STATUS_NONE 0
+/** GPS has begun navigating. */
+#define LOC_GPS_STATUS_SESSION_BEGIN 1
+/** GPS has stopped navigating. */
+#define LOC_GPS_STATUS_SESSION_END 2
+/** GPS has powered on but is not navigating. */
+#define LOC_GPS_STATUS_ENGINE_ON 3
+/** GPS is powered off. */
+#define LOC_GPS_STATUS_ENGINE_OFF 4
+
+/** Flags to indicate which values are valid in a LocGpsLocation. */
+typedef uint16_t LocGpsLocationFlags;
+/* IMPORTANT: Note that the following values must match
+ * constants in GpsLocationProvider.java. */
+/** LocGpsLocation has valid latitude and longitude. */
+#define LOC_GPS_LOCATION_HAS_LAT_LONG 0x0001
+/** LocGpsLocation has valid altitude. */
+#define LOC_GPS_LOCATION_HAS_ALTITUDE 0x0002
+/** LocGpsLocation has valid speed. */
+#define LOC_GPS_LOCATION_HAS_SPEED 0x0004
+/** LocGpsLocation has valid bearing. */
+#define LOC_GPS_LOCATION_HAS_BEARING 0x0008
+/** LocGpsLocation has valid accuracy. */
+#define LOC_GPS_LOCATION_HAS_ACCURACY 0x0010
+/** LocGpsLocation has valid vertical uncertainity */
+#define LOC_GPS_LOCATION_HAS_VERT_UNCERTAINITY 0x0040
+/** LocGpsLocation has valid spoof mask */
+#define LOC_GPS_LOCATION_HAS_SPOOF_MASK 0x0080
+/** LocGpsLocation has valid speed accuracy */
+#define LOC_GPS_LOCATION_HAS_SPEED_ACCURACY 0x0100
+/** LocGpsLocation has valid bearing accuracy */
+#define LOC_GPS_LOCATION_HAS_BEARING_ACCURACY 0x0200
+
+/** Spoof mask in LocGpsLocation */
+typedef uint32_t LocGpsSpoofMask;
+#define LOC_GPS_LOCATION_NONE_SPOOFED 0x0000
+#define LOC_GPS_LOCATION_POSITION_SPOOFED 0x0001
+#define LOC_GPS_LOCATION_TIME_SPOOFED 0x0002
+#define LOC_GPS_LOCATION_NAVIGATION_DATA_SPOOFED 0x0004
+
+/** Flags for the loc_gps_set_capabilities callback. */
+
+/**
+ * GPS HAL schedules fixes for LOC_GPS_POSITION_RECURRENCE_PERIODIC mode. If this is
+ * not set, then the framework will use 1000ms for min_interval and will start
+ * and call start() and stop() to schedule the GPS.
+ */
+#define LOC_GPS_CAPABILITY_SCHEDULING (1 << 0)
+/** GPS supports MS-Based AGPS mode */
+#define LOC_GPS_CAPABILITY_MSB (1 << 1)
+/** GPS supports MS-Assisted AGPS mode */
+#define LOC_GPS_CAPABILITY_MSA (1 << 2)
+/** GPS supports single-shot fixes */
+#define LOC_GPS_CAPABILITY_SINGLE_SHOT (1 << 3)
+/** GPS supports on demand time injection */
+#define LOC_GPS_CAPABILITY_ON_DEMAND_TIME (1 << 4)
+/** GPS supports Geofencing */
+#define LOC_GPS_CAPABILITY_GEOFENCING (1 << 5)
+/** GPS supports Measurements. */
+#define LOC_GPS_CAPABILITY_MEASUREMENTS (1 << 6)
+/** GPS supports Navigation Messages */
+#define LOC_GPS_CAPABILITY_NAV_MESSAGES (1 << 7)
+
+/**
+ * Flags used to specify which aiding data to delete when calling
+ * delete_aiding_data().
+ */
+typedef uint16_t LocGpsAidingData;
+/* IMPORTANT: Note that the following values must match
+ * constants in GpsLocationProvider.java. */
+#define LOC_GPS_DELETE_EPHEMERIS 0x0001
+#define LOC_GPS_DELETE_ALMANAC 0x0002
+#define LOC_GPS_DELETE_POSITION 0x0004
+#define LOC_GPS_DELETE_TIME 0x0008
+#define LOC_GPS_DELETE_IONO 0x0010
+#define LOC_GPS_DELETE_UTC 0x0020
+#define LOC_GPS_DELETE_HEALTH 0x0040
+#define LOC_GPS_DELETE_SVDIR 0x0080
+#define LOC_GPS_DELETE_SVSTEER 0x0100
+#define LOC_GPS_DELETE_SADATA 0x0200
+#define LOC_GPS_DELETE_RTI 0x0400
+#define LOC_GPS_DELETE_MB_DATA 0x0800
+#define LOC_GPS_DELETE_CELLDB_INFO 0x8000
+#define LOC_GPS_DELETE_ALL 0xFFFF
+
+/** AGPS type */
+typedef uint16_t LocAGpsType;
+#define LOC_AGPS_TYPE_ANY 0
+#define LOC_AGPS_TYPE_SUPL 1
+#define LOC_AGPS_TYPE_C2K 2
+#define LOC_AGPS_TYPE_WWAN_ANY 3
+#define LOC_AGPS_TYPE_WIFI 4
+#define LOC_AGPS_TYPE_SUPL_ES 5
+
+typedef uint16_t LocAGpsSetIDType;
+#define LOC_AGPS_SETID_TYPE_NONE 0
+#define LOC_AGPS_SETID_TYPE_IMSI 1
+#define LOC_AGPS_SETID_TYPE_MSISDN 2
+
+typedef uint16_t LocApnIpType;
+#define LOC_APN_IP_INVALID 0
+#define LOC_APN_IP_IPV4 1
+#define LOC_APN_IP_IPV6 2
+#define LOC_APN_IP_IPV4V6 3
+
+/**
+ * String length constants
+ */
+#define LOC_GPS_NI_SHORT_STRING_MAXLEN 256
+#define LOC_GPS_NI_LONG_STRING_MAXLEN 2048
+
+/**
+ * LocGpsNiType constants
+ */
+typedef uint32_t LocGpsNiType;
+#define LOC_GPS_NI_TYPE_VOICE 1
+#define LOC_GPS_NI_TYPE_UMTS_SUPL 2
+#define LOC_GPS_NI_TYPE_UMTS_CTRL_PLANE 3
+/*Emergency SUPL*/
+#define LOC_GPS_NI_TYPE_EMERGENCY_SUPL 4
+
+/**
+ * LocGpsNiNotifyFlags constants
+ */
+typedef uint32_t LocGpsNiNotifyFlags;
+/** NI requires notification */
+#define LOC_GPS_NI_NEED_NOTIFY 0x0001
+/** NI requires verification */
+#define LOC_GPS_NI_NEED_VERIFY 0x0002
+/** NI requires privacy override, no notification/minimal trace */
+#define LOC_GPS_NI_PRIVACY_OVERRIDE 0x0004
+
+/**
+ * GPS NI responses, used to define the response in
+ * NI structures
+ */
+typedef int LocGpsUserResponseType;
+#define LOC_GPS_NI_RESPONSE_ACCEPT 1
+#define LOC_GPS_NI_RESPONSE_DENY 2
+#define LOC_GPS_NI_RESPONSE_NORESP 3
+
+/**
+ * NI data encoding scheme
+ */
+typedef int LocGpsNiEncodingType;
+#define LOC_GPS_ENC_NONE 0
+#define LOC_GPS_ENC_SUPL_GSM_DEFAULT 1
+#define LOC_GPS_ENC_SUPL_UTF8 2
+#define LOC_GPS_ENC_SUPL_UCS2 3
+#define LOC_GPS_ENC_UNKNOWN -1
+
+/** AGPS status event values. */
+typedef uint8_t LocAGpsStatusValue;
+/** GPS requests data connection for AGPS. */
+#define LOC_GPS_REQUEST_AGPS_DATA_CONN 1
+/** GPS releases the AGPS data connection. */
+#define LOC_GPS_RELEASE_AGPS_DATA_CONN 2
+/** AGPS data connection initiated */
+#define LOC_GPS_AGPS_DATA_CONNECTED 3
+/** AGPS data connection completed */
+#define LOC_GPS_AGPS_DATA_CONN_DONE 4
+/** AGPS data connection failed */
+#define LOC_GPS_AGPS_DATA_CONN_FAILED 5
+
+typedef uint16_t LocAGpsRefLocationType;
+#define LOC_AGPS_REF_LOCATION_TYPE_GSM_CELLID 1
+#define LOC_AGPS_REF_LOCATION_TYPE_UMTS_CELLID 2
+#define LOC_AGPS_REF_LOCATION_TYPE_MAC 3
+#define LOC_AGPS_REF_LOCATION_TYPE_LTE_CELLID 4
+
+/* Deprecated, to be removed in the next Android release. */
+#define LOC_AGPS_REG_LOCATION_TYPE_MAC 3
+
+/** Network types for update_network_state "type" parameter */
+#define LOC_AGPS_RIL_NETWORK_TYPE_MOBILE 0
+#define LOC_AGPS_RIL_NETWORK_TYPE_WIFI 1
+#define LOC_AGPS_RIL_NETWORK_TYPE_MOBILE_MMS 2
+#define LOC_AGPS_RIL_NETWORK_TYPE_MOBILE_SUPL 3
+#define LOC_AGPS_RIL_NETWORK_TTYPE_MOBILE_DUN 4
+#define LOC_AGPS_RIL_NETWORK_TTYPE_MOBILE_HIPRI 5
+#define LOC_AGPS_RIL_NETWORK_TTYPE_WIMAX 6
+
+/* The following typedef together with its constants below are deprecated, and
+ * will be removed in the next release. */
+typedef uint16_t LocGpsClockFlags;
+#define LOC_GPS_CLOCK_HAS_LEAP_SECOND (1<<0)
+#define LOC_GPS_CLOCK_HAS_TIME_UNCERTAINTY (1<<1)
+#define LOC_GPS_CLOCK_HAS_FULL_BIAS (1<<2)
+#define LOC_GPS_CLOCK_HAS_BIAS (1<<3)
+#define LOC_GPS_CLOCK_HAS_BIAS_UNCERTAINTY (1<<4)
+#define LOC_GPS_CLOCK_HAS_DRIFT (1<<5)
+#define LOC_GPS_CLOCK_HAS_DRIFT_UNCERTAINTY (1<<6)
+
+/**
+ * Flags to indicate what fields in LocGnssClock are valid.
+ */
+typedef uint16_t LocGnssClockFlags;
+/** A valid 'leap second' is stored in the data structure. */
+#define LOC_GNSS_CLOCK_HAS_LEAP_SECOND (1<<0)
+/** A valid 'time uncertainty' is stored in the data structure. */
+#define LOC_GNSS_CLOCK_HAS_TIME_UNCERTAINTY (1<<1)
+/** A valid 'full bias' is stored in the data structure. */
+#define LOC_GNSS_CLOCK_HAS_FULL_BIAS (1<<2)
+/** A valid 'bias' is stored in the data structure. */
+#define LOC_GNSS_CLOCK_HAS_BIAS (1<<3)
+/** A valid 'bias uncertainty' is stored in the data structure. */
+#define LOC_GNSS_CLOCK_HAS_BIAS_UNCERTAINTY (1<<4)
+/** A valid 'drift' is stored in the data structure. */
+#define LOC_GNSS_CLOCK_HAS_DRIFT (1<<5)
+/** A valid 'drift uncertainty' is stored in the data structure. */
+#define LOC_GNSS_CLOCK_HAS_DRIFT_UNCERTAINTY (1<<6)
+
+/* The following typedef together with its constants below are deprecated, and
+ * will be removed in the next release. */
+typedef uint8_t LocGpsClockType;
+#define LOC_GPS_CLOCK_TYPE_UNKNOWN 0
+#define LOC_GPS_CLOCK_TYPE_LOCAL_HW_TIME 1
+#define LOC_GPS_CLOCK_TYPE_GPS_TIME 2
+
+/* The following typedef together with its constants below are deprecated, and
+ * will be removed in the next release. */
+typedef uint32_t LocGpsMeasurementFlags;
+#define LOC_GPS_MEASUREMENT_HAS_SNR (1<<0)
+#define LOC_GPS_MEASUREMENT_HAS_ELEVATION (1<<1)
+#define LOC_GPS_MEASUREMENT_HAS_ELEVATION_UNCERTAINTY (1<<2)
+#define LOC_GPS_MEASUREMENT_HAS_AZIMUTH (1<<3)
+#define LOC_GPS_MEASUREMENT_HAS_AZIMUTH_UNCERTAINTY (1<<4)
+#define LOC_GPS_MEASUREMENT_HAS_PSEUDORANGE (1<<5)
+#define LOC_GPS_MEASUREMENT_HAS_PSEUDORANGE_UNCERTAINTY (1<<6)
+#define LOC_GPS_MEASUREMENT_HAS_CODE_PHASE (1<<7)
+#define LOC_GPS_MEASUREMENT_HAS_CODE_PHASE_UNCERTAINTY (1<<8)
+#define LOC_GPS_MEASUREMENT_HAS_CARRIER_FREQUENCY (1<<9)
+#define LOC_GPS_MEASUREMENT_HAS_CARRIER_CYCLES (1<<10)
+#define LOC_GPS_MEASUREMENT_HAS_CARRIER_PHASE (1<<11)
+#define LOC_GPS_MEASUREMENT_HAS_CARRIER_PHASE_UNCERTAINTY (1<<12)
+#define LOC_GPS_MEASUREMENT_HAS_BIT_NUMBER (1<<13)
+#define LOC_GPS_MEASUREMENT_HAS_TIME_FROM_LAST_BIT (1<<14)
+#define LOC_GPS_MEASUREMENT_HAS_DOPPLER_SHIFT (1<<15)
+#define LOC_GPS_MEASUREMENT_HAS_DOPPLER_SHIFT_UNCERTAINTY (1<<16)
+#define LOC_GPS_MEASUREMENT_HAS_USED_IN_FIX (1<<17)
+#define LOC_GPS_MEASUREMENT_HAS_UNCORRECTED_PSEUDORANGE_RATE (1<<18)
+
+/**
+ * Flags to indicate what fields in LocGnssMeasurement are valid.
+ */
+typedef uint32_t LocGnssMeasurementFlags;
+/** A valid 'snr' is stored in the data structure. */
+#define LOC_GNSS_MEASUREMENT_HAS_SNR (1<<0)
+/** A valid 'carrier frequency' is stored in the data structure. */
+#define LOC_GNSS_MEASUREMENT_HAS_CARRIER_FREQUENCY (1<<9)
+/** A valid 'carrier cycles' is stored in the data structure. */
+#define LOC_GNSS_MEASUREMENT_HAS_CARRIER_CYCLES (1<<10)
+/** A valid 'carrier phase' is stored in the data structure. */
+#define LOC_GNSS_MEASUREMENT_HAS_CARRIER_PHASE (1<<11)
+/** A valid 'carrier phase uncertainty' is stored in the data structure. */
+#define LOC_GNSS_MEASUREMENT_HAS_CARRIER_PHASE_UNCERTAINTY (1<<12)
+
+/* The following typedef together with its constants below are deprecated, and
+ * will be removed in the next release. */
+typedef uint8_t LocGpsLossOfLock;
+#define LOC_GPS_LOSS_OF_LOCK_UNKNOWN 0
+#define LOC_GPS_LOSS_OF_LOCK_OK 1
+#define LOC_GPS_LOSS_OF_LOCK_CYCLE_SLIP 2
+
+/* The following typedef together with its constants below are deprecated, and
+ * will be removed in the next release. Use LocGnssMultipathIndicator instead.
+ */
+typedef uint8_t LocGpsMultipathIndicator;
+#define LOC_GPS_MULTIPATH_INDICATOR_UNKNOWN 0
+#define LOC_GPS_MULTIPATH_INDICATOR_DETECTED 1
+#define LOC_GPS_MULTIPATH_INDICATOR_NOT_USED 2
+
+/**
+ * Enumeration of available values for the GNSS Measurement's multipath
+ * indicator.
+ */
+typedef uint8_t LocGnssMultipathIndicator;
+/** The indicator is not available or unknown. */
+#define LOC_GNSS_MULTIPATH_INDICATOR_UNKNOWN 0
+/** The measurement is indicated to be affected by multipath. */
+#define LOC_GNSS_MULTIPATH_INDICATOR_PRESENT 1
+/** The measurement is indicated to be not affected by multipath. */
+#define LOC_GNSS_MULTIPATH_INDICATOR_NOT_PRESENT 2
+
+/* The following typedef together with its constants below are deprecated, and
+ * will be removed in the next release. */
+typedef uint16_t LocGpsMeasurementState;
+#define LOC_GPS_MEASUREMENT_STATE_UNKNOWN 0
+#define LOC_GPS_MEASUREMENT_STATE_CODE_LOCK (1<<0)
+#define LOC_GPS_MEASUREMENT_STATE_BIT_SYNC (1<<1)
+#define LOC_GPS_MEASUREMENT_STATE_SUBFRAME_SYNC (1<<2)
+#define LOC_GPS_MEASUREMENT_STATE_TOW_DECODED (1<<3)
+#define LOC_GPS_MEASUREMENT_STATE_MSEC_AMBIGUOUS (1<<4)
+
+/**
+ * Flags indicating the GNSS measurement state.
+ *
+ * The expected behavior here is for GPS HAL to set all the flags that applies.
+ * For example, if the state for a satellite is only C/A code locked and bit
+ * synchronized, and there is still millisecond ambiguity, the state should be
+ * set as:
+ *
+ * LOC_GNSS_MEASUREMENT_STATE_CODE_LOCK | LOC_GNSS_MEASUREMENT_STATE_BIT_SYNC |
+ * LOC_GNSS_MEASUREMENT_STATE_MSEC_AMBIGUOUS
+ *
+ * If GNSS is still searching for a satellite, the corresponding state should be
+ * set to LOC_GNSS_MEASUREMENT_STATE_UNKNOWN(0).
+ */
+typedef uint32_t LocGnssMeasurementState;
+#define LOC_GNSS_MEASUREMENT_STATE_UNKNOWN 0
+#define LOC_GNSS_MEASUREMENT_STATE_CODE_LOCK (1<<0)
+#define LOC_GNSS_MEASUREMENT_STATE_BIT_SYNC (1<<1)
+#define LOC_GNSS_MEASUREMENT_STATE_SUBFRAME_SYNC (1<<2)
+#define LOC_GNSS_MEASUREMENT_STATE_TOW_DECODED (1<<3)
+#define LOC_GNSS_MEASUREMENT_STATE_MSEC_AMBIGUOUS (1<<4)
+#define LOC_GNSS_MEASUREMENT_STATE_SYMBOL_SYNC (1<<5)
+#define LOC_GNSS_MEASUREMENT_STATE_GLO_STRING_SYNC (1<<6)
+#define LOC_GNSS_MEASUREMENT_STATE_GLO_TOD_DECODED (1<<7)
+#define LOC_GNSS_MEASUREMENT_STATE_BDS_D2_BIT_SYNC (1<<8)
+#define LOC_GNSS_MEASUREMENT_STATE_BDS_D2_SUBFRAME_SYNC (1<<9)
+#define LOC_GNSS_MEASUREMENT_STATE_GAL_E1BC_CODE_LOCK (1<<10)
+#define LOC_GNSS_MEASUREMENT_STATE_GAL_E1C_2ND_CODE_LOCK (1<<11)
+#define LOC_GNSS_MEASUREMENT_STATE_GAL_E1B_PAGE_SYNC (1<<12)
+#define LOC_GNSS_MEASUREMENT_STATE_SBAS_SYNC (1<<13)
+
+/* The following typedef together with its constants below are deprecated, and
+ * will be removed in the next release. */
+typedef uint16_t LocGpsAccumulatedDeltaRangeState;
+#define LOC_GPS_ADR_STATE_UNKNOWN 0
+#define LOC_GPS_ADR_STATE_VALID (1<<0)
+#define LOC_GPS_ADR_STATE_RESET (1<<1)
+#define LOC_GPS_ADR_STATE_CYCLE_SLIP (1<<2)
+
+/**
+ * Flags indicating the Accumulated Delta Range's states.
+ */
+typedef uint16_t LocGnssAccumulatedDeltaRangeState;
+#define LOC_GNSS_ADR_STATE_UNKNOWN 0
+#define LOC_GNSS_ADR_STATE_VALID (1<<0)
+#define LOC_GNSS_ADR_STATE_RESET (1<<1)
+#define LOC_GNSS_ADR_STATE_CYCLE_SLIP (1<<2)
+
+#if 0
+/* The following typedef together with its constants below are deprecated, and
+ * will be removed in the next release. */
+typedef uint8_t GpsNavigationMessageType;
+#define GPS_NAVIGATION_MESSAGE_TYPE_UNKNOWN 0
+#define GPS_NAVIGATION_MESSAGE_TYPE_L1CA 1
+#define GPS_NAVIGATION_MESSAGE_TYPE_L2CNAV 2
+#define GPS_NAVIGATION_MESSAGE_TYPE_L5CNAV 3
+#define GPS_NAVIGATION_MESSAGE_TYPE_CNAV2 4
+
+/**
+ * Enumeration of available values to indicate the GNSS Navigation message
+ * types.
+ *
+ * For convenience, first byte is the LocGnssConstellationType on which that signal
+ * is typically transmitted
+ */
+typedef int16_t GnssNavigationMessageType;
+
+#define GNSS_NAVIGATION_MESSAGE_TYPE_UNKNOWN 0
+/** GPS L1 C/A message contained in the structure. */
+#define GNSS_NAVIGATION_MESSAGE_TYPE_GPS_L1CA 0x0101
+/** GPS L2-CNAV message contained in the structure. */
+#define GNSS_NAVIGATION_MESSAGE_TYPE_GPS_L2CNAV 0x0102
+/** GPS L5-CNAV message contained in the structure. */
+#define GNSS_NAVIGATION_MESSAGE_TYPE_GPS_L5CNAV 0x0103
+/** GPS CNAV-2 message contained in the structure. */
+#define GNSS_NAVIGATION_MESSAGE_TYPE_GPS_CNAV2 0x0104
+/** Glonass L1 CA message contained in the structure. */
+#define GNSS_NAVIGATION_MESSAGE_TYPE_GLO_L1CA 0x0301
+/** Beidou D1 message contained in the structure. */
+#define GNSS_NAVIGATION_MESSAGE_TYPE_BDS_D1 0x0501
+/** Beidou D2 message contained in the structure. */
+#define GNSS_NAVIGATION_MESSAGE_TYPE_BDS_D2 0x0502
+/** Galileo I/NAV message contained in the structure. */
+#define GNSS_NAVIGATION_MESSAGE_TYPE_GAL_I 0x0601
+/** Galileo F/NAV message contained in the structure. */
+#define GNSS_NAVIGATION_MESSAGE_TYPE_GAL_F 0x0602
+
+/**
+ * Status of Navigation Message
+ * When a message is received properly without any parity error in its navigation words, the
+ * status should be set to NAV_MESSAGE_STATUS_PARITY_PASSED. But if a message is received
+ * with words that failed parity check, but GPS is able to correct those words, the status
+ * should be set to NAV_MESSAGE_STATUS_PARITY_REBUILT.
+ * No need to send any navigation message that contains words with parity error and cannot be
+ * corrected.
+ */
+typedef uint16_t NavigationMessageStatus;
+#define NAV_MESSAGE_STATUS_UNKNOWN 0
+#define NAV_MESSAGE_STATUS_PARITY_PASSED (1<<0)
+#define NAV_MESSAGE_STATUS_PARITY_REBUILT (1<<1)
+
+/* This constant is deprecated, and will be removed in the next release. */
+#define NAV_MESSAGE_STATUS_UNKONW 0
+#endif
+
+/**
+ * Flags that indicate information about the satellite
+ */
+typedef uint8_t LocGnssSvFlags;
+#define LOC_GNSS_SV_FLAGS_NONE 0
+#define LOC_GNSS_SV_FLAGS_HAS_EPHEMERIS_DATA (1 << 0)
+#define LOC_GNSS_SV_FLAGS_HAS_ALMANAC_DATA (1 << 1)
+#define LOC_GNSS_SV_FLAGS_USED_IN_FIX (1 << 2)
+
+/**
+ * Constellation type of LocGnssSvInfo
+ */
+typedef uint8_t LocGnssConstellationType;
+#define LOC_GNSS_CONSTELLATION_UNKNOWN 0
+#define LOC_GNSS_CONSTELLATION_GPS 1
+#define LOC_GNSS_CONSTELLATION_SBAS 2
+#define LOC_GNSS_CONSTELLATION_GLONASS 3
+#define LOC_GNSS_CONSTELLATION_QZSS 4
+#define LOC_GNSS_CONSTELLATION_BEIDOU 5
+#define LOC_GNSS_CONSTELLATION_GALILEO 6
+
+/**
+ * Name for the GPS XTRA interface.
+ */
+#define LOC_GPS_XTRA_INTERFACE "gps-xtra"
+
+/**
+ * Name for the GPS DEBUG interface.
+ */
+#define LOC_GPS_DEBUG_INTERFACE "gps-debug"
+
+/**
+ * Name for the AGPS interface.
+ */
+
+#define LOC_AGPS_INTERFACE "agps"
+
+/**
+ * Name of the Supl Certificate interface.
+ */
+#define LOC_SUPL_CERTIFICATE_INTERFACE "supl-certificate"
+
+/**
+ * Name for NI interface
+ */
+#define LOC_GPS_NI_INTERFACE "gps-ni"
+
+/**
+ * Name for the AGPS-RIL interface.
+ */
+#define LOC_AGPS_RIL_INTERFACE "agps_ril"
+
+/**
+ * Name for the GPS_Geofencing interface.
+ */
+#define LOC_GPS_GEOFENCING_INTERFACE "gps_geofencing"
+
+/**
+ * Name of the GPS Measurements interface.
+ */
+#define LOC_GPS_MEASUREMENT_INTERFACE "gps_measurement"
+
+/**
+ * Name of the GPS navigation message interface.
+ */
+#define LOC_GPS_NAVIGATION_MESSAGE_INTERFACE "gps_navigation_message"
+
+/**
+ * Name of the GNSS/GPS configuration interface.
+ */
+#define LOC_GNSS_CONFIGURATION_INTERFACE "gnss_configuration"
+
+/** Represents a location. */
+typedef struct {
+ /** set to sizeof(LocGpsLocation) */
+ uint32_t size;
+ /** Contains LocGpsLocationFlags bits. */
+ uint16_t flags;
+ /** The spoof mask */
+ LocGpsSpoofMask spoof_mask;
+ /** Represents latitude in degrees. */
+ double latitude;
+ /** Represents longitude in degrees. */
+ double longitude;
+ /**
+ * Represents altitude in meters above the WGS 84 reference ellipsoid.
+ */
+ double altitude;
+ /** Represents horizontal speed in meters per second. */
+ float speed;
+ /** Represents heading in degrees. */
+ float bearing;
+ /** Represents expected accuracy in meters. */
+ float accuracy;
+ /** Represents the expected vertical uncertainity in meters*/
+ float vertUncertainity;
+ /** Timestamp for the location fix. */
+ LocGpsUtcTime timestamp;
+} LocGpsLocation;
+
+/** Represents the status. */
+typedef struct {
+ /** set to sizeof(LocGpsStatus) */
+ size_t size;
+ LocGpsStatusValue status;
+} LocGpsStatus;
+
+/**
+ * Legacy struct to represents SV information.
+ * Deprecated, to be removed in the next Android release.
+ * Use LocGnssSvInfo instead.
+ */
+typedef struct {
+ /** set to sizeof(LocGpsSvInfo) */
+ size_t size;
+ /** Pseudo-random number for the SV. */
+ int prn;
+ /** Signal to noise ratio. */
+ float snr;
+ /** Elevation of SV in degrees. */
+ float elevation;
+ /** Azimuth of SV in degrees. */
+ float azimuth;
+} LocGpsSvInfo;
+
+typedef struct {
+ /** set to sizeof(LocGnssSvInfo) */
+ size_t size;
+
+ /**
+ * Pseudo-random number for the SV, or FCN/OSN number for Glonass. The
+ * distinction is made by looking at constellation field. Values should be
+ * in the range of:
+ *
+ * - GPS: 1-32
+ * - SBAS: 120-151, 183-192
+ * - GLONASS: 1-24, the orbital slot number (OSN), if known. Or, if not:
+ * 93-106, the frequency channel number (FCN) (-7 to +6) offset by + 100
+ * i.e. report an FCN of -7 as 93, FCN of 0 as 100, and FCN of +6 as 106.
+ * - QZSS: 193-200
+ * - Galileo: 1-36
+ * - Beidou: 1-37
+ */
+ int16_t svid;
+
+ /**
+ * Defines the constellation of the given SV. Value should be one of those
+ * LOC_GNSS_CONSTELLATION_* constants
+ */
+ LocGnssConstellationType constellation;
+
+ /**
+ * Carrier-to-noise density in dB-Hz, typically in the range [0, 63].
+ * It contains the measured C/N0 value for the signal at the antenna port.
+ *
+ * This is a mandatory value.
+ */
+ float c_n0_dbhz;
+
+ /** Elevation of SV in degrees. */
+ float elevation;
+
+ /** Azimuth of SV in degrees. */
+ float azimuth;
+
+ /**
+ * Contains additional data about the given SV. Value should be one of those
+ * LOC_GNSS_SV_FLAGS_* constants
+ */
+ LocGnssSvFlags flags;
+
+} LocGnssSvInfo;
+
+/**
+ * Legacy struct to represents SV status.
+ * Deprecated, to be removed in the next Android release.
+ * Use LocGnssSvStatus instead.
+ */
+typedef struct {
+ /** set to sizeof(LocGpsSvStatus) */
+ size_t size;
+ int num_svs;
+ LocGpsSvInfo sv_list[LOC_GPS_MAX_SVS];
+ uint32_t ephemeris_mask;
+ uint32_t almanac_mask;
+ uint32_t used_in_fix_mask;
+} LocGpsSvStatus;
+
+/**
+ * Represents SV status.
+ */
+typedef struct {
+ /** set to sizeof(LocGnssSvStatus) */
+ size_t size;
+
+ /** Number of GPS SVs currently visible, refers to the SVs stored in sv_list */
+ int num_svs;
+ /**
+ * Pointer to an array of SVs information for all GNSS constellations,
+ * except GPS, which is reported using sv_list
+ */
+ LocGnssSvInfo gnss_sv_list[LOC_GNSS_MAX_SVS];
+
+} LocGnssSvStatus;
+
+/* CellID for 2G, 3G and LTE, used in AGPS. */
+typedef struct {
+ LocAGpsRefLocationType type;
+ /** Mobile Country Code. */
+ uint16_t mcc;
+ /** Mobile Network Code .*/
+ uint16_t mnc;
+ /** Location Area Code in 2G, 3G and LTE. In 3G lac is discarded. In LTE,
+ * lac is populated with tac, to ensure that we don't break old clients that
+ * might rely in the old (wrong) behavior.
+ */
+ uint16_t lac;
+ /** Cell id in 2G. Utran Cell id in 3G. Cell Global Id EUTRA in LTE. */
+ uint32_t cid;
+ /** Tracking Area Code in LTE. */
+ uint16_t tac;
+ /** Physical Cell id in LTE (not used in 2G and 3G) */
+ uint16_t pcid;
+} LocAGpsRefLocationCellID;
+
+typedef struct {
+ uint8_t mac[6];
+} LocAGpsRefLocationMac;
+
+/** Represents ref locations */
+typedef struct {
+ LocAGpsRefLocationType type;
+ union {
+ LocAGpsRefLocationCellID cellID;
+ LocAGpsRefLocationMac mac;
+ } u;
+} LocAGpsRefLocation;
+
+/**
+ * Callback with location information. Can only be called from a thread created
+ * by create_thread_cb.
+ */
+typedef void (* loc_gps_location_callback)(LocGpsLocation* location);
+
+/**
+ * Callback with status information. Can only be called from a thread created by
+ * create_thread_cb.
+ */
+typedef void (* loc_gps_status_callback)(LocGpsStatus* status);
+/**
+ * Legacy callback with SV status information.
+ * Can only be called from a thread created by create_thread_cb.
+ *
+ * This callback is deprecated, and will be removed in the next release. Use
+ * loc_gnss_sv_status_callback() instead.
+ */
+typedef void (* loc_gps_sv_status_callback)(LocGpsSvStatus* sv_info);
+
+/**
+ * Callback with SV status information.
+ * Can only be called from a thread created by create_thread_cb.
+ */
+typedef void (* loc_gnss_sv_status_callback)(LocGnssSvStatus* sv_info);
+
+/**
+ * Callback for reporting NMEA sentences. Can only be called from a thread
+ * created by create_thread_cb.
+ */
+typedef void (* loc_gps_nmea_callback)(LocGpsUtcTime timestamp, const char* nmea, int length);
+
+/**
+ * Callback to inform framework of the GPS engine's capabilities. Capability
+ * parameter is a bit field of LOC_GPS_CAPABILITY_* flags.
+ */
+typedef void (* loc_gps_set_capabilities)(uint32_t capabilities);
+
+/**
+ * Callback utility for acquiring the GPS wakelock. This can be used to prevent
+ * the CPU from suspending while handling GPS events.
+ */
+typedef void (* loc_gps_acquire_wakelock)();
+
+/** Callback utility for releasing the GPS wakelock. */
+typedef void (* loc_gps_release_wakelock)();
+
+/** Callback for requesting NTP time */
+typedef void (* loc_gps_request_utc_time)();
+
+/**
+ * Callback for creating a thread that can call into the Java framework code.
+ * This must be used to create any threads that report events up to the
+ * framework.
+ */
+typedef pthread_t (* loc_gps_create_thread)(const char* name, void (*start)(void *), void* arg);
+
+/**
+ * Provides information about how new the underlying GPS/GNSS hardware and
+ * software is.
+ *
+ * This information will be available for Android Test Applications. If a GPS
+ * HAL does not provide this information, it will be considered "2015 or
+ * earlier".
+ *
+ * If a GPS HAL does provide this information, then newer years will need to
+ * meet newer CTS standards. E.g. if the date are 2016 or above, then N+ level
+ * LocGpsMeasurement support will be verified.
+ */
+typedef struct {
+ /** Set to sizeof(LocGnssSystemInfo) */
+ size_t size;
+ /* year in which the last update was made to the underlying hardware/firmware
+ * used to capture GNSS signals, e.g. 2016 */
+ uint16_t year_of_hw;
+} LocGnssSystemInfo;
+
+/**
+ * Callback to inform framework of the engine's hardware version information.
+ */
+typedef void (*loc_gnss_set_system_info)(const LocGnssSystemInfo* info);
+
+/** New GPS callback structure. */
+typedef struct {
+ /** set to sizeof(LocGpsCallbacks) */
+ size_t size;
+ loc_gps_location_callback location_cb;
+ loc_gps_status_callback status_cb;
+ loc_gps_sv_status_callback sv_status_cb;
+ loc_gps_nmea_callback nmea_cb;
+ loc_gps_set_capabilities set_capabilities_cb;
+ loc_gps_acquire_wakelock acquire_wakelock_cb;
+ loc_gps_release_wakelock release_wakelock_cb;
+ loc_gps_create_thread create_thread_cb;
+ loc_gps_request_utc_time request_utc_time_cb;
+
+ loc_gnss_set_system_info set_system_info_cb;
+ loc_gnss_sv_status_callback gnss_sv_status_cb;
+} LocGpsCallbacks;
+
+/** Represents the standard GPS interface. */
+typedef struct {
+ /** set to sizeof(LocGpsInterface) */
+ size_t size;
+ /**
+ * Opens the interface and provides the callback routines
+ * to the implementation of this interface.
+ */
+ int (*init)( LocGpsCallbacks* callbacks );
+
+ /** Starts navigating. */
+ int (*start)( void );
+
+ /** Stops navigating. */
+ int (*stop)( void );
+
+ /** Closes the interface. */
+ void (*cleanup)( void );
+
+ /** Injects the current time. */
+ int (*inject_time)(LocGpsUtcTime time, int64_t timeReference,
+ int uncertainty);
+
+ /**
+ * Injects current location from another location provider (typically cell
+ * ID). Latitude and longitude are measured in degrees expected accuracy is
+ * measured in meters
+ */
+ int (*inject_location)(double latitude, double longitude, float accuracy);
+
+ /**
+ * Specifies that the next call to start will not use the
+ * information defined in the flags. LOC_GPS_DELETE_ALL is passed for
+ * a cold start.
+ */
+ void (*delete_aiding_data)(LocGpsAidingData flags);
+
+ /**
+ * min_interval represents the time between fixes in milliseconds.
+ * preferred_accuracy represents the requested fix accuracy in meters.
+ * preferred_time represents the requested time to first fix in milliseconds.
+ *
+ * 'mode' parameter should be one of LOC_GPS_POSITION_MODE_MS_BASED
+ * or LOC_GPS_POSITION_MODE_STANDALONE.
+ * It is allowed by the platform (and it is recommended) to fallback to
+ * LOC_GPS_POSITION_MODE_MS_BASED if LOC_GPS_POSITION_MODE_MS_ASSISTED is passed in, and
+ * LOC_GPS_POSITION_MODE_MS_BASED is supported.
+ */
+ int (*set_position_mode)(LocGpsPositionMode mode, LocGpsPositionRecurrence recurrence,
+ uint32_t min_interval, uint32_t preferred_accuracy, uint32_t preferred_time);
+
+ /** Get a pointer to extension information. */
+ const void* (*get_extension)(const char* name);
+} LocGpsInterface;
+
+/**
+ * Callback to request the client to download XTRA data. The client should
+ * download XTRA data and inject it by calling inject_xtra_data(). Can only be
+ * called from a thread created by create_thread_cb.
+ */
+typedef void (* loc_gps_xtra_download_request)();
+
+/** Callback structure for the XTRA interface. */
+typedef struct {
+ loc_gps_xtra_download_request download_request_cb;
+ loc_gps_create_thread create_thread_cb;
+} LocGpsXtraCallbacks;
+
+/** Extended interface for XTRA support. */
+typedef struct {
+ /** set to sizeof(LocGpsXtraInterface) */
+ size_t size;
+ /**
+ * Opens the XTRA interface and provides the callback routines
+ * to the implementation of this interface.
+ */
+ int (*init)( LocGpsXtraCallbacks* callbacks );
+ /** Injects XTRA data into the GPS. */
+ int (*inject_xtra_data)( char* data, int length );
+} LocGpsXtraInterface;
+
+#if 0
+/** Extended interface for DEBUG support. */
+typedef struct {
+ /** set to sizeof(LocGpsDebugInterface) */
+ size_t size;
+
+ /**
+ * This function should return any information that the native
+ * implementation wishes to include in a bugreport.
+ */
+ size_t (*get_internal_state)(char* buffer, size_t bufferSize);
+} LocGpsDebugInterface;
+#endif
+
+/*
+ * Represents the status of AGPS augmented to support IPv4 and IPv6.
+ */
+typedef struct {
+ /** set to sizeof(LocAGpsStatus) */
+ size_t size;
+
+ LocAGpsType type;
+ LocAGpsStatusValue status;
+
+ /**
+ * Must be set to a valid IPv4 address if the field 'addr' contains an IPv4
+ * address, or set to INADDR_NONE otherwise.
+ */
+ uint32_t ipaddr;
+
+ /**
+ * Must contain the IPv4 (AF_INET) or IPv6 (AF_INET6) address to report.
+ * Any other value of addr.ss_family will be rejected.
+ */
+ struct sockaddr_storage addr;
+} LocAGpsStatus;
+
+/**
+ * Callback with AGPS status information. Can only be called from a thread
+ * created by create_thread_cb.
+ */
+typedef void (* loc_agps_status_callback)(LocAGpsStatus* status);
+
+/** Callback structure for the AGPS interface. */
+typedef struct {
+ loc_agps_status_callback status_cb;
+ loc_gps_create_thread create_thread_cb;
+} LocAGpsCallbacks;
+
+/**
+ * Extended interface for AGPS support, it is augmented to enable to pass
+ * extra APN data.
+ */
+typedef struct {
+ /** set to sizeof(LocAGpsInterface) */
+ size_t size;
+
+ /**
+ * Opens the AGPS interface and provides the callback routines to the
+ * implementation of this interface.
+ */
+ void (*init)(LocAGpsCallbacks* callbacks);
+ /**
+ * Deprecated.
+ * If the HAL supports LocAGpsInterface_v2 this API will not be used, see
+ * data_conn_open_with_apn_ip_type for more information.
+ */
+ int (*data_conn_open)(const char* apn);
+ /**
+ * Notifies that the AGPS data connection has been closed.
+ */
+ int (*data_conn_closed)();
+ /**
+ * Notifies that a data connection is not available for AGPS.
+ */
+ int (*data_conn_failed)();
+ /**
+ * Sets the hostname and port for the AGPS server.
+ */
+ int (*set_server)(LocAGpsType type, const char* hostname, int port);
+
+ /**
+ * Notifies that a data connection is available and sets the name of the
+ * APN, and its IP type, to be used for SUPL connections.
+ */
+ int (*data_conn_open_with_apn_ip_type)(
+ const char* apn,
+ LocApnIpType apnIpType);
+} LocAGpsInterface;
+
+/** Error codes associated with certificate operations */
+#define LOC_AGPS_CERTIFICATE_OPERATION_SUCCESS 0
+#define LOC_AGPS_CERTIFICATE_ERROR_GENERIC -100
+#define LOC_AGPS_CERTIFICATE_ERROR_TOO_MANY_CERTIFICATES -101
+
+/** A data structure that represents an X.509 certificate using DER encoding */
+typedef struct {
+ size_t length;
+ u_char* data;
+} LocDerEncodedCertificate;
+
+/**
+ * A type definition for SHA1 Fingerprints used to identify X.509 Certificates
+ * The Fingerprint is a digest of the DER Certificate that uniquely identifies it.
+ */
+typedef struct {
+ u_char data[20];
+} LocSha1CertificateFingerprint;
+
+/** AGPS Interface to handle SUPL certificate operations */
+typedef struct {
+ /** set to sizeof(LocSuplCertificateInterface) */
+ size_t size;
+
+ /**
+ * Installs a set of Certificates used for SUPL connections to the AGPS server.
+ * If needed the HAL should find out internally any certificates that need to be removed to
+ * accommodate the certificates to install.
+ * The certificates installed represent a full set of valid certificates needed to connect to
+ * AGPS SUPL servers.
+ * The list of certificates is required, and all must be available at the same time, when trying
+ * to establish a connection with the AGPS Server.
+ *
+ * Parameters:
+ * certificates - A pointer to an array of DER encoded certificates that are need to be
+ * installed in the HAL.
+ * length - The number of certificates to install.
+ * Returns:
+ * LOC_AGPS_CERTIFICATE_OPERATION_SUCCESS if the operation is completed successfully
+ * LOC_AGPS_CERTIFICATE_ERROR_TOO_MANY_CERTIFICATES if the HAL cannot store the number of
+ * certificates attempted to be installed, the state of the certificates stored should
+ * remain the same as before on this error case.
+ *
+ * IMPORTANT:
+ * If needed the HAL should find out internally the set of certificates that need to be
+ * removed to accommodate the certificates to install.
+ */
+ int (*install_certificates) ( const LocDerEncodedCertificate* certificates, size_t length );
+
+ /**
+ * Notifies the HAL that a list of certificates used for SUPL connections are revoked. It is
+ * expected that the given set of certificates is removed from the internal store of the HAL.
+ *
+ * Parameters:
+ * fingerprints - A pointer to an array of SHA1 Fingerprints to identify the set of
+ * certificates to revoke.
+ * length - The number of fingerprints provided.
+ * Returns:
+ * LOC_AGPS_CERTIFICATE_OPERATION_SUCCESS if the operation is completed successfully.
+ *
+ * IMPORTANT:
+ * If any of the certificates provided (through its fingerprint) is not known by the HAL,
+ * it should be ignored and continue revoking/deleting the rest of them.
+ */
+ int (*revoke_certificates) ( const LocSha1CertificateFingerprint* fingerprints, size_t length );
+} LocSuplCertificateInterface;
+
+/** Represents an NI request */
+typedef struct {
+ /** set to sizeof(LocGpsNiNotification) */
+ size_t size;
+
+ /**
+ * An ID generated by HAL to associate NI notifications and UI
+ * responses
+ */
+ int notification_id;
+
+ /**
+ * An NI type used to distinguish different categories of NI
+ * events, such as LOC_GPS_NI_TYPE_VOICE, LOC_GPS_NI_TYPE_UMTS_SUPL, ...
+ */
+ LocGpsNiType ni_type;
+
+ /**
+ * Notification/verification options, combinations of LocGpsNiNotifyFlags constants
+ */
+ LocGpsNiNotifyFlags notify_flags;
+
+ /**
+ * Timeout period to wait for user response.
+ * Set to 0 for no time out limit.
+ */
+ int timeout;
+
+ /**
+ * Default response when time out.
+ */
+ LocGpsUserResponseType default_response;
+
+ /**
+ * Requestor ID
+ */
+ char requestor_id[LOC_GPS_NI_SHORT_STRING_MAXLEN];
+
+ /**
+ * Notification message. It can also be used to store client_id in some cases
+ */
+ char text[LOC_GPS_NI_LONG_STRING_MAXLEN];
+
+ /**
+ * Client name decoding scheme
+ */
+ LocGpsNiEncodingType requestor_id_encoding;
+
+ /**
+ * Client name decoding scheme
+ */
+ LocGpsNiEncodingType text_encoding;
+
+ /**
+ * A pointer to extra data. Format:
+ * key_1 = value_1
+ * key_2 = value_2
+ */
+ char extras[LOC_GPS_NI_LONG_STRING_MAXLEN];
+
+} LocGpsNiNotification;
+
+/**
+ * Callback with NI notification. Can only be called from a thread created by
+ * create_thread_cb.
+ */
+typedef void (*loc_gps_ni_notify_callback)(LocGpsNiNotification *notification);
+
+/** GPS NI callback structure. */
+typedef struct
+{
+ /**
+ * Sends the notification request from HAL to GPSLocationProvider.
+ */
+ loc_gps_ni_notify_callback notify_cb;
+ loc_gps_create_thread create_thread_cb;
+} LocGpsNiCallbacks;
+
+/**
+ * Extended interface for Network-initiated (NI) support.
+ */
+typedef struct
+{
+ /** set to sizeof(LocGpsNiInterface) */
+ size_t size;
+
+ /** Registers the callbacks for HAL to use. */
+ void (*init) (LocGpsNiCallbacks *callbacks);
+
+ /** Sends a response to HAL. */
+ void (*respond) (int notif_id, LocGpsUserResponseType user_response);
+} LocGpsNiInterface;
+
+#define LOC_AGPS_RIL_REQUEST_SETID_IMSI (1<<0L)
+#define LOC_AGPS_RIL_REQUEST_SETID_MSISDN (1<<1L)
+
+#define LOC_AGPS_RIL_REQUEST_REFLOC_CELLID (1<<0L)
+#define LOC_AGPS_RIL_REQUEST_REFLOC_MAC (1<<1L)
+
+typedef void (*loc_agps_ril_request_set_id)(uint32_t flags);
+typedef void (*loc_agps_ril_request_ref_loc)(uint32_t flags);
+
+typedef struct {
+ loc_agps_ril_request_set_id request_setid;
+ loc_agps_ril_request_ref_loc request_refloc;
+ loc_gps_create_thread create_thread_cb;
+} LocAGpsRilCallbacks;
+
+/** Extended interface for AGPS_RIL support. */
+typedef struct {
+ /** set to sizeof(LocAGpsRilInterface) */
+ size_t size;
+ /**
+ * Opens the AGPS interface and provides the callback routines
+ * to the implementation of this interface.
+ */
+ void (*init)( LocAGpsRilCallbacks* callbacks );
+
+ /**
+ * Sets the reference location.
+ */
+ void (*set_ref_location) (const LocAGpsRefLocation *agps_reflocation, size_t sz_struct);
+ /**
+ * Sets the set ID.
+ */
+ void (*set_set_id) (LocAGpsSetIDType type, const char* setid);
+
+ /**
+ * Send network initiated message.
+ */
+ void (*ni_message) (uint8_t *msg, size_t len);
+
+ /**
+ * Notify GPS of network status changes.
+ * These parameters match values in the android.net.NetworkInfo class.
+ */
+ void (*update_network_state) (int connected, int type, int roaming, const char* extra_info);
+
+ /**
+ * Notify GPS of network status changes.
+ * These parameters match values in the android.net.NetworkInfo class.
+ */
+ void (*update_network_availability) (int avaiable, const char* apn);
+} LocAGpsRilInterface;
+
+/**
+ * GPS Geofence.
+ * There are 3 states associated with a Geofence: Inside, Outside, Unknown.
+ * There are 3 transitions: ENTERED, EXITED, UNCERTAIN.
+ *
+ * An example state diagram with confidence level: 95% and Unknown time limit
+ * set as 30 secs is shown below. (confidence level and Unknown time limit are
+ * explained latter)
+ * ____________________________
+ * | Unknown (30 secs) |
+ * """"""""""""""""""""""""""""
+ * ^ | | ^
+ * UNCERTAIN| |ENTERED EXITED| |UNCERTAIN
+ * | v v |
+ * ________ EXITED _________
+ * | Inside | -----------> | Outside |
+ * | | <----------- | |
+ * """""""" ENTERED """""""""
+ *
+ * Inside state: We are 95% confident that the user is inside the geofence.
+ * Outside state: We are 95% confident that the user is outside the geofence
+ * Unknown state: Rest of the time.
+ *
+ * The Unknown state is better explained with an example:
+ *
+ * __________
+ * | c|
+ * | ___ | _______
+ * | |a| | | b |
+ * | """ | """""""
+ * | |
+ * """"""""""
+ * In the diagram above, "a" and "b" are 2 geofences and "c" is the accuracy
+ * circle reported by the GPS subsystem. Now with regard to "b", the system is
+ * confident that the user is outside. But with regard to "a" is not confident
+ * whether it is inside or outside the geofence. If the accuracy remains the
+ * same for a sufficient period of time, the UNCERTAIN transition would be
+ * triggered with the state set to Unknown. If the accuracy improves later, an
+ * appropriate transition should be triggered. This "sufficient period of time"
+ * is defined by the parameter in the add_geofence_area API.
+ * In other words, Unknown state can be interpreted as a state in which the
+ * GPS subsystem isn't confident enough that the user is either inside or
+ * outside the Geofence. It moves to Unknown state only after the expiry of the
+ * timeout.
+ *
+ * The geofence callback needs to be triggered for the ENTERED and EXITED
+ * transitions, when the GPS system is confident that the user has entered
+ * (Inside state) or exited (Outside state) the Geofence. An implementation
+ * which uses a value of 95% as the confidence is recommended. The callback
+ * should be triggered only for the transitions requested by the
+ * add_geofence_area call.
+ *
+ * Even though the diagram and explanation talks about states and transitions,
+ * the callee is only interested in the transistions. The states are mentioned
+ * here for illustrative purposes.
+ *
+ * Startup Scenario: When the device boots up, if an application adds geofences,
+ * and then we get an accurate GPS location fix, it needs to trigger the
+ * appropriate (ENTERED or EXITED) transition for every Geofence it knows about.
+ * By default, all the Geofences will be in the Unknown state.
+ *
+ * When the GPS system is unavailable, loc_gps_geofence_status_callback should be
+ * called to inform the upper layers of the same. Similarly, when it becomes
+ * available the callback should be called. This is a global state while the
+ * UNKNOWN transition described above is per geofence.
+ *
+ * An important aspect to note is that users of this API (framework), will use
+ * other subsystems like wifi, sensors, cell to handle Unknown case and
+ * hopefully provide a definitive state transition to the third party
+ * application. GPS Geofence will just be a signal indicating what the GPS
+ * subsystem knows about the Geofence.
+ *
+ */
+#define LOC_GPS_GEOFENCE_ENTERED (1<<0L)
+#define LOC_GPS_GEOFENCE_EXITED (1<<1L)
+#define LOC_GPS_GEOFENCE_UNCERTAIN (1<<2L)
+
+#define LOC_GPS_GEOFENCE_UNAVAILABLE (1<<0L)
+#define LOC_GPS_GEOFENCE_AVAILABLE (1<<1L)
+
+#define LOC_GPS_GEOFENCE_OPERATION_SUCCESS 0
+#define LOC_GPS_GEOFENCE_ERROR_TOO_MANY_GEOFENCES -100
+#define LOC_GPS_GEOFENCE_ERROR_ID_EXISTS -101
+#define LOC_GPS_GEOFENCE_ERROR_ID_UNKNOWN -102
+#define LOC_GPS_GEOFENCE_ERROR_INVALID_TRANSITION -103
+#define LOC_GPS_GEOFENCE_ERROR_GENERIC -149
+
+/**
+ * The callback associated with the geofence.
+ * Parameters:
+ * geofence_id - The id associated with the add_geofence_area.
+ * location - The current GPS location.
+ * transition - Can be one of LOC_GPS_GEOFENCE_ENTERED, LOC_GPS_GEOFENCE_EXITED,
+ * LOC_GPS_GEOFENCE_UNCERTAIN.
+ * timestamp - Timestamp when the transition was detected.
+ *
+ * The callback should only be called when the caller is interested in that
+ * particular transition. For instance, if the caller is interested only in
+ * ENTERED transition, then the callback should NOT be called with the EXITED
+ * transition.
+ *
+ * IMPORTANT: If a transition is triggered resulting in this callback, the GPS
+ * subsystem will wake up the application processor, if its in suspend state.
+ */
+typedef void (*loc_gps_geofence_transition_callback) (int32_t geofence_id, LocGpsLocation* location,
+ int32_t transition, LocGpsUtcTime timestamp);
+
+/**
+ * The callback associated with the availability of the GPS system for geofencing
+ * monitoring. If the GPS system determines that it cannot monitor geofences
+ * because of lack of reliability or unavailability of the GPS signals, it will
+ * call this callback with LOC_GPS_GEOFENCE_UNAVAILABLE parameter.
+ *
+ * Parameters:
+ * status - LOC_GPS_GEOFENCE_UNAVAILABLE or LOC_GPS_GEOFENCE_AVAILABLE.
+ * last_location - Last known location.
+ */
+typedef void (*loc_gps_geofence_status_callback) (int32_t status, LocGpsLocation* last_location);
+
+/**
+ * The callback associated with the add_geofence call.
+ *
+ * Parameter:
+ * geofence_id - Id of the geofence.
+ * status - LOC_GPS_GEOFENCE_OPERATION_SUCCESS
+ * LOC_GPS_GEOFENCE_ERROR_TOO_MANY_GEOFENCES - geofence limit has been reached.
+ * LOC_GPS_GEOFENCE_ERROR_ID_EXISTS - geofence with id already exists
+ * LOC_GPS_GEOFENCE_ERROR_INVALID_TRANSITION - the monitorTransition contains an
+ * invalid transition
+ * LOC_GPS_GEOFENCE_ERROR_GENERIC - for other errors.
+ */
+typedef void (*loc_gps_geofence_add_callback) (int32_t geofence_id, int32_t status);
+
+/**
+ * The callback associated with the remove_geofence call.
+ *
+ * Parameter:
+ * geofence_id - Id of the geofence.
+ * status - LOC_GPS_GEOFENCE_OPERATION_SUCCESS
+ * LOC_GPS_GEOFENCE_ERROR_ID_UNKNOWN - for invalid id
+ * LOC_GPS_GEOFENCE_ERROR_GENERIC for others.
+ */
+typedef void (*loc_gps_geofence_remove_callback) (int32_t geofence_id, int32_t status);
+
+
+/**
+ * The callback associated with the pause_geofence call.
+ *
+ * Parameter:
+ * geofence_id - Id of the geofence.
+ * status - LOC_GPS_GEOFENCE_OPERATION_SUCCESS
+ * LOC_GPS_GEOFENCE_ERROR_ID_UNKNOWN - for invalid id
+ * LOC_GPS_GEOFENCE_ERROR_INVALID_TRANSITION -
+ * when monitor_transitions is invalid
+ * LOC_GPS_GEOFENCE_ERROR_GENERIC for others.
+ */
+typedef void (*loc_gps_geofence_pause_callback) (int32_t geofence_id, int32_t status);
+
+/**
+ * The callback associated with the resume_geofence call.
+ *
+ * Parameter:
+ * geofence_id - Id of the geofence.
+ * status - LOC_GPS_GEOFENCE_OPERATION_SUCCESS
+ * LOC_GPS_GEOFENCE_ERROR_ID_UNKNOWN - for invalid id
+ * LOC_GPS_GEOFENCE_ERROR_GENERIC for others.
+ */
+typedef void (*loc_gps_geofence_resume_callback) (int32_t geofence_id, int32_t status);
+
+typedef struct {
+ loc_gps_geofence_transition_callback geofence_transition_callback;
+ loc_gps_geofence_status_callback geofence_status_callback;
+ loc_gps_geofence_add_callback geofence_add_callback;
+ loc_gps_geofence_remove_callback geofence_remove_callback;
+ loc_gps_geofence_pause_callback geofence_pause_callback;
+ loc_gps_geofence_resume_callback geofence_resume_callback;
+ loc_gps_create_thread create_thread_cb;
+} LocGpsGeofenceCallbacks;
+
+/** Extended interface for GPS_Geofencing support */
+typedef struct {
+ /** set to sizeof(LocGpsGeofencingInterface) */
+ size_t size;
+
+ /**
+ * Opens the geofence interface and provides the callback routines
+ * to the implementation of this interface.
+ */
+ void (*init)( LocGpsGeofenceCallbacks* callbacks );
+
+ /**
+ * Add a geofence area. This api currently supports circular geofences.
+ * Parameters:
+ * geofence_id - The id for the geofence. If a geofence with this id
+ * already exists, an error value (LOC_GPS_GEOFENCE_ERROR_ID_EXISTS)
+ * should be returned.
+ * latitude, longtitude, radius_meters - The lat, long and radius
+ * (in meters) for the geofence
+ * last_transition - The current state of the geofence. For example, if
+ * the system already knows that the user is inside the geofence,
+ * this will be set to LOC_GPS_GEOFENCE_ENTERED. In most cases, it
+ * will be LOC_GPS_GEOFENCE_UNCERTAIN.
+ * monitor_transition - Which transitions to monitor. Bitwise OR of
+ * LOC_GPS_GEOFENCE_ENTERED, LOC_GPS_GEOFENCE_EXITED and
+ * LOC_GPS_GEOFENCE_UNCERTAIN.
+ * notification_responsiveness_ms - Defines the best-effort description
+ * of how soon should the callback be called when the transition
+ * associated with the Geofence is triggered. For instance, if set
+ * to 1000 millseconds with LOC_GPS_GEOFENCE_ENTERED, the callback
+ * should be called 1000 milliseconds within entering the geofence.
+ * This parameter is defined in milliseconds.
+ * NOTE: This is not to be confused with the rate that the GPS is
+ * polled at. It is acceptable to dynamically vary the rate of
+ * sampling the GPS for power-saving reasons; thus the rate of
+ * sampling may be faster or slower than this.
+ * unknown_timer_ms - The time limit after which the UNCERTAIN transition
+ * should be triggered. This parameter is defined in milliseconds.
+ * See above for a detailed explanation.
+ */
+ void (*add_geofence_area) (int32_t geofence_id, double latitude, double longitude,
+ double radius_meters, int last_transition, int monitor_transitions,
+ int notification_responsiveness_ms, int unknown_timer_ms);
+
+ /**
+ * Pause monitoring a particular geofence.
+ * Parameters:
+ * geofence_id - The id for the geofence.
+ */
+ void (*pause_geofence) (int32_t geofence_id);
+
+ /**
+ * Resume monitoring a particular geofence.
+ * Parameters:
+ * geofence_id - The id for the geofence.
+ * monitor_transitions - Which transitions to monitor. Bitwise OR of
+ * LOC_GPS_GEOFENCE_ENTERED, LOC_GPS_GEOFENCE_EXITED and
+ * LOC_GPS_GEOFENCE_UNCERTAIN.
+ * This supersedes the value associated provided in the
+ * add_geofence_area call.
+ */
+ void (*resume_geofence) (int32_t geofence_id, int monitor_transitions);
+
+ /**
+ * Remove a geofence area. After the function returns, no notifications
+ * should be sent.
+ * Parameter:
+ * geofence_id - The id for the geofence.
+ */
+ void (*remove_geofence_area) (int32_t geofence_id);
+} LocGpsGeofencingInterface;
+
+/**
+ * Legacy struct to represent an estimate of the GPS clock time.
+ * Deprecated, to be removed in the next Android release.
+ * Use LocGnssClock instead.
+ */
+typedef struct {
+ /** set to sizeof(LocGpsClock) */
+ size_t size;
+ LocGpsClockFlags flags;
+ int16_t leap_second;
+ LocGpsClockType type;
+ int64_t time_ns;
+ double time_uncertainty_ns;
+ int64_t full_bias_ns;
+ double bias_ns;
+ double bias_uncertainty_ns;
+ double drift_nsps;
+ double drift_uncertainty_nsps;
+} LocGpsClock;
+
+/**
+ * Represents an estimate of the GPS clock time.
+ */
+typedef struct {
+ /** set to sizeof(LocGnssClock) */
+ size_t size;
+
+ /**
+ * A set of flags indicating the validity of the fields in this data
+ * structure.
+ */
+ LocGnssClockFlags flags;
+
+ /**
+ * Leap second data.
+ * The sign of the value is defined by the following equation:
+ * utc_time_ns = time_ns - (full_bias_ns + bias_ns) - leap_second *
+ * 1,000,000,000
+ *
+ * If the data is available 'flags' must contain LOC_GNSS_CLOCK_HAS_LEAP_SECOND.
+ */
+ int16_t leap_second;
+
+ /**
+ * The GNSS receiver internal clock value. This is the local hardware clock
+ * value.
+ *
+ * For local hardware clock, this value is expected to be monotonically
+ * increasing while the hardware clock remains power on. (For the case of a
+ * HW clock that is not continuously on, see the
+ * hw_clock_discontinuity_count field). The receiver's estimate of GPS time
+ * can be derived by substracting the sum of full_bias_ns and bias_ns (when
+ * available) from this value.
+ *
+ * This GPS time is expected to be the best estimate of current GPS time
+ * that GNSS receiver can achieve.
+ *
+ * Sub-nanosecond accuracy can be provided by means of the 'bias_ns' field.
+ * The value contains the 'time uncertainty' in it.
+ *
+ * This field is mandatory.
+ */
+ int64_t time_ns;
+
+ /**
+ * 1-Sigma uncertainty associated with the clock's time in nanoseconds.
+ * The uncertainty is represented as an absolute (single sided) value.
+ *
+ * If the data is available, 'flags' must contain
+ * LOC_GNSS_CLOCK_HAS_TIME_UNCERTAINTY. This value is effectively zero (it is
+ * the reference local clock, by which all other times and time
+ * uncertainties are measured.) (And thus this field can be not provided,
+ * per LOC_GNSS_CLOCK_HAS_TIME_UNCERTAINTY flag, or provided & set to 0.)
+ */
+ double time_uncertainty_ns;
+
+ /**
+ * The difference between hardware clock ('time' field) inside GPS receiver
+ * and the true GPS time since 0000Z, January 6, 1980, in nanoseconds.
+ *
+ * The sign of the value is defined by the following equation:
+ * local estimate of GPS time = time_ns - (full_bias_ns + bias_ns)
+ *
+ * This value is mandatory if the receiver has estimated GPS time. If the
+ * computed time is for a non-GPS constellation, the time offset of that
+ * constellation to GPS has to be applied to fill this value. The error
+ * estimate for the sum of this and the bias_ns is the bias_uncertainty_ns,
+ * and the caller is responsible for using this uncertainty (it can be very
+ * large before the GPS time has been solved for.) If the data is available
+ * 'flags' must contain LOC_GNSS_CLOCK_HAS_FULL_BIAS.
+ */
+ int64_t full_bias_ns;
+
+ /**
+ * Sub-nanosecond bias.
+ * The error estimate for the sum of this and the full_bias_ns is the
+ * bias_uncertainty_ns
+ *
+ * If the data is available 'flags' must contain LOC_GNSS_CLOCK_HAS_BIAS. If GPS
+ * has computed a position fix. This value is mandatory if the receiver has
+ * estimated GPS time.
+ */
+ double bias_ns;
+
+ /**
+ * 1-Sigma uncertainty associated with the local estimate of GPS time (clock
+ * bias) in nanoseconds. The uncertainty is represented as an absolute
+ * (single sided) value.
+ *
+ * If the data is available 'flags' must contain
+ * LOC_GNSS_CLOCK_HAS_BIAS_UNCERTAINTY. This value is mandatory if the receiver
+ * has estimated GPS time.
+ */
+ double bias_uncertainty_ns;
+
+ /**
+ * The clock's drift in nanoseconds (per second).
+ *
+ * A positive value means that the frequency is higher than the nominal
+ * frequency, and that the (full_bias_ns + bias_ns) is growing more positive
+ * over time.
+ *
+ * The value contains the 'drift uncertainty' in it.
+ * If the data is available 'flags' must contain LOC_GNSS_CLOCK_HAS_DRIFT.
+ *
+ * This value is mandatory if the receiver has estimated GNSS time
+ */
+ double drift_nsps;
+
+ /**
+ * 1-Sigma uncertainty associated with the clock's drift in nanoseconds (per second).
+ * The uncertainty is represented as an absolute (single sided) value.
+ *
+ * If the data is available 'flags' must contain
+ * LOC_GNSS_CLOCK_HAS_DRIFT_UNCERTAINTY. If GPS has computed a position fix this
+ * field is mandatory and must be populated.
+ */
+ double drift_uncertainty_nsps;
+
+ /**
+ * When there are any discontinuities in the HW clock, this field is
+ * mandatory.
+ *
+ * A "discontinuity" is meant to cover the case of a switch from one source
+ * of clock to another. A single free-running crystal oscillator (XO)
+ * should generally not have any discontinuities, and this can be set and
+ * left at 0.
+ *
+ * If, however, the time_ns value (HW clock) is derived from a composite of
+ * sources, that is not as smooth as a typical XO, or is otherwise stopped &
+ * restarted, then this value shall be incremented each time a discontinuity
+ * occurs. (E.g. this value may start at zero at device boot-up and
+ * increment each time there is a change in clock continuity. In the
+ * unlikely event that this value reaches full scale, rollover (not
+ * clamping) is required, such that this value continues to change, during
+ * subsequent discontinuity events.)
+ *
+ * While this number stays the same, between LocGnssClock reports, it can be
+ * safely assumed that the time_ns value has been running continuously, e.g.
+ * derived from a single, high quality clock (XO like, or better, that's
+ * typically used during continuous GNSS signal sampling.)
+ *
+ * It is expected, esp. during periods where there are few GNSS signals
+ * available, that the HW clock be discontinuity-free as long as possible,
+ * as this avoids the need to use (waste) a GNSS measurement to fully
+ * re-solve for the GPS clock bias and drift, when using the accompanying
+ * measurements, from consecutive LocGnssData reports.
+ */
+ uint32_t hw_clock_discontinuity_count;
+
+} LocGnssClock;
+
+/**
+ * Legacy struct to represent a GPS Measurement, it contains raw and computed
+ * information.
+ * Deprecated, to be removed in the next Android release.
+ * Use LocGnssMeasurement instead.
+ */
+typedef struct {
+ /** set to sizeof(LocGpsMeasurement) */
+ size_t size;
+ LocGpsMeasurementFlags flags;
+ int8_t prn;
+ double time_offset_ns;
+ LocGpsMeasurementState state;
+ int64_t received_gps_tow_ns;
+ int64_t received_gps_tow_uncertainty_ns;
+ double c_n0_dbhz;
+ double pseudorange_rate_mps;
+ double pseudorange_rate_uncertainty_mps;
+ LocGpsAccumulatedDeltaRangeState accumulated_delta_range_state;
+ double accumulated_delta_range_m;
+ double accumulated_delta_range_uncertainty_m;
+ double pseudorange_m;
+ double pseudorange_uncertainty_m;
+ double code_phase_chips;
+ double code_phase_uncertainty_chips;
+ float carrier_frequency_hz;
+ int64_t carrier_cycles;
+ double carrier_phase;
+ double carrier_phase_uncertainty;
+ LocGpsLossOfLock loss_of_lock;
+ int32_t bit_number;
+ int16_t time_from_last_bit_ms;
+ double doppler_shift_hz;
+ double doppler_shift_uncertainty_hz;
+ LocGpsMultipathIndicator multipath_indicator;
+ double snr_db;
+ double elevation_deg;
+ double elevation_uncertainty_deg;
+ double azimuth_deg;
+ double azimuth_uncertainty_deg;
+ bool used_in_fix;
+} LocGpsMeasurement;
+
+/**
+ * Represents a GNSS Measurement, it contains raw and computed information.
+ *
+ * Independence - All signal measurement information (e.g. sv_time,
+ * pseudorange_rate, multipath_indicator) reported in this struct should be
+ * based on GNSS signal measurements only. You may not synthesize measurements
+ * by calculating or reporting expected measurements based on known or estimated
+ * position, velocity, or time.
+ */
+typedef struct {
+ /** set to sizeof(LocGnssMeasurement) */
+ size_t size;
+
+ /** A set of flags indicating the validity of the fields in this data structure. */
+ LocGnssMeasurementFlags flags;
+
+ /**
+ * Satellite vehicle ID number, as defined in LocGnssSvInfo::svid
+ * This is a mandatory value.
+ */
+ int16_t svid;
+
+ /**
+ * Defines the constellation of the given SV. Value should be one of those
+ * LOC_GNSS_CONSTELLATION_* constants
+ */
+ LocGnssConstellationType constellation;
+
+ /**
+ * Time offset at which the measurement was taken in nanoseconds.
+ * The reference receiver's time is specified by LocGpsData::clock::time_ns and should be
+ * interpreted in the same way as indicated by LocGpsClock::type.
+ *
+ * The sign of time_offset_ns is given by the following equation:
+ * measurement time = LocGpsClock::time_ns + time_offset_ns
+ *
+ * It provides an individual time-stamp for the measurement, and allows sub-nanosecond accuracy.
+ * This is a mandatory value.
+ */
+ double time_offset_ns;
+
+ /**
+ * Per satellite sync state. It represents the current sync state for the associated satellite.
+ * Based on the sync state, the 'received GPS tow' field should be interpreted accordingly.
+ *
+ * This is a mandatory value.
+ */
+ LocGnssMeasurementState state;
+
+ /**
+ * The received GNSS Time-of-Week at the measurement time, in nanoseconds.
+ * Ensure that this field is independent (see comment at top of
+ * LocGnssMeasurement struct.)
+ *
+ * For GPS & QZSS, this is:
+ * Received GPS Time-of-Week at the measurement time, in nanoseconds.
+ * The value is relative to the beginning of the current GPS week.
+ *
+ * Given the highest sync state that can be achieved, per each satellite, valid range
+ * for this field can be:
+ * Searching : [ 0 ] : LOC_GNSS_MEASUREMENT_STATE_UNKNOWN
+ * C/A code lock : [ 0 1ms ] : LOC_GNSS_MEASUREMENT_STATE_CODE_LOCK is set
+ * Bit sync : [ 0 20ms ] : LOC_GNSS_MEASUREMENT_STATE_BIT_SYNC is set
+ * Subframe sync : [ 0 6s ] : LOC_GNSS_MEASUREMENT_STATE_SUBFRAME_SYNC is set
+ * TOW decoded : [ 0 1week ] : LOC_GNSS_MEASUREMENT_STATE_TOW_DECODED is set
+ *
+ * Note well: if there is any ambiguity in integer millisecond,
+ * LOC_GNSS_MEASUREMENT_STATE_MSEC_AMBIGUOUS should be set accordingly, in the 'state' field.
+ *
+ * This value must be populated if 'state' != LOC_GNSS_MEASUREMENT_STATE_UNKNOWN.
+ *
+ * For Glonass, this is:
+ * Received Glonass time of day, at the measurement time in nanoseconds.
+ *
+ * Given the highest sync state that can be achieved, per each satellite, valid range for
+ * this field can be:
+ * Searching : [ 0 ] : LOC_GNSS_MEASUREMENT_STATE_UNKNOWN
+ * C/A code lock : [ 0 1ms ] : LOC_GNSS_MEASUREMENT_STATE_CODE_LOCK is set
+ * Symbol sync : [ 0 10ms ] : LOC_GNSS_MEASUREMENT_STATE_SYMBOL_SYNC is set
+ * Bit sync : [ 0 20ms ] : LOC_GNSS_MEASUREMENT_STATE_BIT_SYNC is set
+ * String sync : [ 0 2s ] : LOC_GNSS_MEASUREMENT_STATE_GLO_STRING_SYNC is set
+ * Time of day : [ 0 1day ] : LOC_GNSS_MEASUREMENT_STATE_GLO_TOD_DECODED is set
+ *
+ * For Beidou, this is:
+ * Received Beidou time of week, at the measurement time in nanoseconds.
+ *
+ * Given the highest sync state that can be achieved, per each satellite, valid range for
+ * this field can be:
+ * Searching : [ 0 ] : LOC_GNSS_MEASUREMENT_STATE_UNKNOWN
+ * C/A code lock: [ 0 1ms ] : LOC_GNSS_MEASUREMENT_STATE_CODE_LOCK is set
+ * Bit sync (D2): [ 0 2ms ] : LOC_GNSS_MEASUREMENT_STATE_BDS_D2_BIT_SYNC is set
+ * Bit sync (D1): [ 0 20ms ] : LOC_GNSS_MEASUREMENT_STATE_BIT_SYNC is set
+ * Subframe (D2): [ 0 0.6s ] : LOC_GNSS_MEASUREMENT_STATE_BDS_D2_SUBFRAME_SYNC is set
+ * Subframe (D1): [ 0 6s ] : LOC_GNSS_MEASUREMENT_STATE_SUBFRAME_SYNC is set
+ * Time of week : [ 0 1week ] : LOC_GNSS_MEASUREMENT_STATE_TOW_DECODED is set
+ *
+ * For Galileo, this is:
+ * Received Galileo time of week, at the measurement time in nanoseconds.
+ *
+ * E1BC code lock : [ 0 4ms ] : LOC_GNSS_MEASUREMENT_STATE_GAL_E1BC_CODE_LOCK is set
+ * E1C 2nd code lock: [ 0 100ms ] :
+ * LOC_GNSS_MEASUREMENT_STATE_GAL_E1C_2ND_CODE_LOCK is set
+ *
+ * E1B page : [ 0 2s ] : LOC_GNSS_MEASUREMENT_STATE_GAL_E1B_PAGE_SYNC is set
+ * Time of week: [ 0 1week ] : LOC_GNSS_MEASUREMENT_STATE_TOW_DECODED is set
+ *
+ * For SBAS, this is:
+ * Received SBAS time, at the measurement time in nanoseconds.
+ *
+ * Given the highest sync state that can be achieved, per each satellite,
+ * valid range for this field can be:
+ * Searching : [ 0 ] : LOC_GNSS_MEASUREMENT_STATE_UNKNOWN
+ * C/A code lock: [ 0 1ms ] : LOC_GNSS_MEASUREMENT_STATE_CODE_LOCK is set
+ * Symbol sync : [ 0 2ms ] : LOC_GNSS_MEASUREMENT_STATE_SYMBOL_SYNC is set
+ * Message : [ 0 1s ] : LOC_GNSS_MEASUREMENT_STATE_SBAS_SYNC is set
+ */
+ int64_t received_sv_time_in_ns;
+
+ /**
+ * 1-Sigma uncertainty of the Received GPS Time-of-Week in nanoseconds.
+ *
+ * This value must be populated if 'state' != LOC_GPS_MEASUREMENT_STATE_UNKNOWN.
+ */
+ int64_t received_sv_time_uncertainty_in_ns;
+
+ /**
+ * Carrier-to-noise density in dB-Hz, typically in the range [0, 63].
+ * It contains the measured C/N0 value for the signal at the antenna port.
+ *
+ * This is a mandatory value.
+ */
+ double c_n0_dbhz;
+
+ /**
+ * Pseudorange rate at the timestamp in m/s. The correction of a given
+ * Pseudorange Rate value includes corrections for receiver and satellite
+ * clock frequency errors. Ensure that this field is independent (see
+ * comment at top of LocGnssMeasurement struct.)
+ *
+ * It is mandatory to provide the 'uncorrected' 'pseudorange rate', and provide LocGpsClock's
+ * 'drift' field as well (When providing the uncorrected pseudorange rate, do not apply the
+ * corrections described above.)
+ *
+ * The value includes the 'pseudorange rate uncertainty' in it.
+ * A positive 'uncorrected' value indicates that the SV is moving away from the receiver.
+ *
+ * The sign of the 'uncorrected' 'pseudorange rate' and its relation to the sign of 'doppler
+ * shift' is given by the equation:
+ * pseudorange rate = -k * doppler shift (where k is a constant)
+ *
+ * This should be the most accurate pseudorange rate available, based on
+ * fresh signal measurements from this channel.
+ *
+ * It is mandatory that this value be provided at typical carrier phase PRR
+ * quality (few cm/sec per second of uncertainty, or better) - when signals
+ * are sufficiently strong & stable, e.g. signals from a GPS simulator at >=
+ * 35 dB-Hz.
+ */
+ double pseudorange_rate_mps;
+
+ /**
+ * 1-Sigma uncertainty of the pseudorange_rate_mps.
+ * The uncertainty is represented as an absolute (single sided) value.
+ *
+ * This is a mandatory value.
+ */
+ double pseudorange_rate_uncertainty_mps;
+
+ /**
+ * Accumulated delta range's state. It indicates whether ADR is reset or there is a cycle slip
+ * (indicating loss of lock).
+ *
+ * This is a mandatory value.
+ */
+ LocGnssAccumulatedDeltaRangeState accumulated_delta_range_state;
+
+ /**
+ * Accumulated delta range since the last channel reset in meters.
+ * A positive value indicates that the SV is moving away from the receiver.
+ *
+ * The sign of the 'accumulated delta range' and its relation to the sign of 'carrier phase'
+ * is given by the equation:
+ * accumulated delta range = -k * carrier phase (where k is a constant)
+ *
+ * This value must be populated if 'accumulated delta range state' != LOC_GPS_ADR_STATE_UNKNOWN.
+ * However, it is expected that the data is only accurate when:
+ * 'accumulated delta range state' == LOC_GPS_ADR_STATE_VALID.
+ */
+ double accumulated_delta_range_m;
+
+ /**
+ * 1-Sigma uncertainty of the accumulated delta range in meters.
+ * This value must be populated if 'accumulated delta range state' != LOC_GPS_ADR_STATE_UNKNOWN.
+ */
+ double accumulated_delta_range_uncertainty_m;
+
+ /**
+ * Carrier frequency at which codes and messages are modulated, it can be L1 or L2.
+ * If the field is not set, the carrier frequency is assumed to be L1.
+ *
+ * If the data is available, 'flags' must contain
+ * LOC_GNSS_MEASUREMENT_HAS_CARRIER_FREQUENCY.
+ */
+ float carrier_frequency_hz;
+
+ /**
+ * The number of full carrier cycles between the satellite and the receiver.
+ * The reference frequency is given by the field 'carrier_frequency_hz'.
+ * Indications of possible cycle slips and resets in the accumulation of
+ * this value can be inferred from the accumulated_delta_range_state flags.
+ *
+ * If the data is available, 'flags' must contain
+ * LOC_GNSS_MEASUREMENT_HAS_CARRIER_CYCLES.
+ */
+ int64_t carrier_cycles;
+
+ /**
+ * The RF phase detected by the receiver, in the range [0.0, 1.0].
+ * This is usually the fractional part of the complete carrier phase measurement.
+ *
+ * The reference frequency is given by the field 'carrier_frequency_hz'.
+ * The value contains the 'carrier-phase uncertainty' in it.
+ *
+ * If the data is available, 'flags' must contain
+ * LOC_GNSS_MEASUREMENT_HAS_CARRIER_PHASE.
+ */
+ double carrier_phase;
+
+ /**
+ * 1-Sigma uncertainty of the carrier-phase.
+ * If the data is available, 'flags' must contain
+ * LOC_GNSS_MEASUREMENT_HAS_CARRIER_PHASE_UNCERTAINTY.
+ */
+ double carrier_phase_uncertainty;
+
+ /**
+ * An enumeration that indicates the 'multipath' state of the event.
+ *
+ * The multipath Indicator is intended to report the presence of overlapping
+ * signals that manifest as distorted correlation peaks.
+ *
+ * - if there is a distorted correlation peak shape, report that multipath
+ * is LOC_GNSS_MULTIPATH_INDICATOR_PRESENT.
+ * - if there is not a distorted correlation peak shape, report
+ * LOC_GNSS_MULTIPATH_INDICATOR_NOT_PRESENT
+ * - if signals are too weak to discern this information, report
+ * LOC_GNSS_MULTIPATH_INDICATOR_UNKNOWN
+ *
+ * Example: when doing the standardized overlapping Multipath Performance
+ * test (3GPP TS 34.171) the Multipath indicator should report
+ * LOC_GNSS_MULTIPATH_INDICATOR_PRESENT for those signals that are tracked, and
+ * contain multipath, and LOC_GNSS_MULTIPATH_INDICATOR_NOT_PRESENT for those
+ * signals that are tracked and do not contain multipath.
+ */
+ LocGnssMultipathIndicator multipath_indicator;
+
+ /**
+ * Signal-to-noise ratio at correlator output in dB.
+ * If the data is available, 'flags' must contain LOC_GNSS_MEASUREMENT_HAS_SNR.
+ * This is the power ratio of the "correlation peak height above the
+ * observed noise floor" to "the noise RMS".
+ */
+ double snr_db;
+} LocGnssMeasurement;
+
+/**
+ * Legacy struct to represents a reading of GPS measurements.
+ * Deprecated, to be removed in the next Android release.
+ * Use LocGnssData instead.
+ */
+typedef struct {
+ /** set to sizeof(LocGpsData) */
+ size_t size;
+ size_t measurement_count;
+ LocGpsMeasurement measurements[LOC_GPS_MAX_MEASUREMENT];
+
+ /** The GPS clock time reading. */
+ LocGpsClock clock;
+} LocGpsData;
+
+/**
+ * Represents a reading of GNSS measurements. For devices where LocGnssSystemInfo's
+ * year_of_hw is set to 2016+, it is mandatory that these be provided, on
+ * request, when the GNSS receiver is searching/tracking signals.
+ *
+ * - Reporting of GPS constellation measurements is mandatory.
+ * - Reporting of all tracked constellations are encouraged.
+ */
+typedef struct {
+ /** set to sizeof(LocGnssData) */
+ size_t size;
+
+ /** Number of measurements. */
+ size_t measurement_count;
+
+ /** The array of measurements. */
+ LocGnssMeasurement measurements[LOC_GNSS_MAX_MEASUREMENT];
+
+ /** The GPS clock time reading. */
+ LocGnssClock clock;
+} LocGnssData;
+
+/**
+ * The legacy callback for to report measurements from the HAL.
+ *
+ * This callback is deprecated, and will be removed in the next release. Use
+ * loc_gnss_measurement_callback() instead.
+ *
+ * Parameters:
+ * data - A data structure containing the measurements.
+ */
+typedef void (*loc_gps_measurement_callback) (LocGpsData* data);
+
+/**
+ * The callback for to report measurements from the HAL.
+ *
+ * Parameters:
+ * data - A data structure containing the measurements.
+ */
+typedef void (*loc_gnss_measurement_callback) (LocGnssData* data);
+
+typedef struct {
+ /** set to sizeof(LocGpsMeasurementCallbacks) */
+ size_t size;
+ loc_gps_measurement_callback measurement_callback;
+ loc_gnss_measurement_callback loc_gnss_measurement_callback;
+} LocGpsMeasurementCallbacks;
+
+#define LOC_GPS_MEASUREMENT_OPERATION_SUCCESS 0
+#define LOC_GPS_MEASUREMENT_ERROR_ALREADY_INIT -100
+#define LOC_GPS_MEASUREMENT_ERROR_GENERIC -101
+
+/**
+ * Extended interface for GPS Measurements support.
+ */
+typedef struct {
+ /** Set to sizeof(LocGpsMeasurementInterface) */
+ size_t size;
+
+ /**
+ * Initializes the interface and registers the callback routines with the HAL.
+ * After a successful call to 'init' the HAL must begin to provide updates at its own phase.
+ *
+ * Status:
+ * LOC_GPS_MEASUREMENT_OPERATION_SUCCESS
+ * LOC_GPS_MEASUREMENT_ERROR_ALREADY_INIT - if a callback has already been registered without a
+ * corresponding call to 'close'
+ * LOC_GPS_MEASUREMENT_ERROR_GENERIC - if any other error occurred, it is expected that the HAL
+ * will not generate any updates upon returning this error code.
+ */
+ int (*init) (LocGpsMeasurementCallbacks* callbacks);
+
+ /**
+ * Stops updates from the HAL, and unregisters the callback routines.
+ * After a call to stop, the previously registered callbacks must be considered invalid by the
+ * HAL.
+ * If stop is invoked without a previous 'init', this function should perform no work.
+ */
+ void (*close) ();
+
+} LocGpsMeasurementInterface;
+
+#if 0
+/**
+ * Legacy struct to represents a GPS navigation message (or a fragment of it).
+ * Deprecated, to be removed in the next Android release.
+ * Use GnssNavigationMessage instead.
+ */
+typedef struct {
+ /** set to sizeof(GpsNavigationMessage) */
+ size_t size;
+ int8_t prn;
+ GpsNavigationMessageType type;
+ NavigationMessageStatus status;
+ int16_t message_id;
+ int16_t submessage_id;
+ size_t data_length;
+ uint8_t* data;
+} GpsNavigationMessage;
+
+/** Represents a GPS navigation message (or a fragment of it). */
+typedef struct {
+ /** set to sizeof(GnssNavigationMessage) */
+ size_t size;
+
+ /**
+ * Satellite vehicle ID number, as defined in LocGnssSvInfo::svid
+ * This is a mandatory value.
+ */
+ int16_t svid;
+
+ /**
+ * The type of message contained in the structure.
+ * This is a mandatory value.
+ */
+ GnssNavigationMessageType type;
+
+ /**
+ * The status of the received navigation message.
+ * No need to send any navigation message that contains words with parity error and cannot be
+ * corrected.
+ */
+ NavigationMessageStatus status;
+
+ /**
+ * Message identifier. It provides an index so the complete Navigation
+ * Message can be assembled.
+ *
+ * - For GPS L1 C/A subframe 4 and 5, this value corresponds to the 'frame
+ * id' of the navigation message, in the range of 1-25 (Subframe 1, 2, 3
+ * does not contain a 'frame id' and this value can be set to -1.)
+ *
+ * - For Glonass L1 C/A, this refers to the frame ID, in the range of 1-5.
+ *
+ * - For BeiDou D1, this refers to the frame number in the range of 1-24
+ *
+ * - For Beidou D2, this refers to the frame number, in the range of 1-120
+ *
+ * - For Galileo F/NAV nominal frame structure, this refers to the subframe
+ * number, in the range of 1-12
+ *
+ * - For Galileo I/NAV nominal frame structure, this refers to the subframe
+ * number in the range of 1-24
+ */
+ int16_t message_id;
+
+ /**
+ * Sub-message identifier. If required by the message 'type', this value
+ * contains a sub-index within the current message (or frame) that is being
+ * transmitted.
+ *
+ * - For GPS L1 C/A, BeiDou D1 & BeiDou D2, the submessage id corresponds to
+ * the subframe number of the navigation message, in the range of 1-5.
+ *
+ * - For Glonass L1 C/A, this refers to the String number, in the range from
+ * 1-15
+ *
+ * - For Galileo F/NAV, this refers to the page type in the range 1-6
+ *
+ * - For Galileo I/NAV, this refers to the word type in the range 1-10+
+ */
+ int16_t submessage_id;
+
+ /**
+ * The length of the data (in bytes) contained in the current message.
+ * If this value is different from zero, 'data' must point to an array of the same size.
+ * e.g. for L1 C/A the size of the sub-frame will be 40 bytes (10 words, 30 bits/word).
+ *
+ * This is a mandatory value.
+ */
+ size_t data_length;
+
+ /**
+ * The data of the reported GPS message. The bytes (or words) specified
+ * using big endian format (MSB first).
+ *
+ * - For GPS L1 C/A, Beidou D1 & Beidou D2, each subframe contains 10 30-bit
+ * words. Each word (30 bits) should be fit into the last 30 bits in a
+ * 4-byte word (skip B31 and B32), with MSB first, for a total of 40
+ * bytes, covering a time period of 6, 6, and 0.6 seconds, respectively.
+ *
+ * - For Glonass L1 C/A, each string contains 85 data bits, including the
+ * checksum. These bits should be fit into 11 bytes, with MSB first (skip
+ * B86-B88), covering a time period of 2 seconds.
+ *
+ * - For Galileo F/NAV, each word consists of 238-bit (sync & tail symbols
+ * excluded). Each word should be fit into 30-bytes, with MSB first (skip
+ * B239, B240), covering a time period of 10 seconds.
+ *
+ * - For Galileo I/NAV, each page contains 2 page parts, even and odd, with
+ * a total of 2x114 = 228 bits, (sync & tail excluded) that should be fit
+ * into 29 bytes, with MSB first (skip B229-B232).
+ */
+ uint8_t* data;
+
+} GnssNavigationMessage;
+
+/**
+ * The legacy callback to report an available fragment of a GPS navigation
+ * messages from the HAL.
+ *
+ * This callback is deprecated, and will be removed in the next release. Use
+ * gnss_navigation_message_callback() instead.
+ *
+ * Parameters:
+ * message - The GPS navigation submessage/subframe representation.
+ */
+typedef void (*gps_navigation_message_callback) (GpsNavigationMessage* message);
+
+/**
+ * The callback to report an available fragment of a GPS navigation messages from the HAL.
+ *
+ * Parameters:
+ * message - The GPS navigation submessage/subframe representation.
+ */
+typedef void (*gnss_navigation_message_callback) (GnssNavigationMessage* message);
+
+typedef struct {
+ /** set to sizeof(GpsNavigationMessageCallbacks) */
+ size_t size;
+ gps_navigation_message_callback navigation_message_callback;
+ gnss_navigation_message_callback gnss_navigation_message_callback;
+} GpsNavigationMessageCallbacks;
+
+#define GPS_NAVIGATION_MESSAGE_OPERATION_SUCCESS 0
+#define GPS_NAVIGATION_MESSAGE_ERROR_ALREADY_INIT -100
+#define GPS_NAVIGATION_MESSAGE_ERROR_GENERIC -101
+
+/**
+ * Extended interface for GPS navigation message reporting support.
+ */
+typedef struct {
+ /** Set to sizeof(GpsNavigationMessageInterface) */
+ size_t size;
+
+ /**
+ * Initializes the interface and registers the callback routines with the HAL.
+ * After a successful call to 'init' the HAL must begin to provide updates as they become
+ * available.
+ *
+ * Status:
+ * GPS_NAVIGATION_MESSAGE_OPERATION_SUCCESS
+ * GPS_NAVIGATION_MESSAGE_ERROR_ALREADY_INIT - if a callback has already been registered
+ * without a corresponding call to 'close'.
+ * GPS_NAVIGATION_MESSAGE_ERROR_GENERIC - if any other error occurred, it is expected that
+ * the HAL will not generate any updates upon returning this error code.
+ */
+ int (*init) (GpsNavigationMessageCallbacks* callbacks);
+
+ /**
+ * Stops updates from the HAL, and unregisters the callback routines.
+ * After a call to stop, the previously registered callbacks must be considered invalid by the
+ * HAL.
+ * If stop is invoked without a previous 'init', this function should perform no work.
+ */
+ void (*close) ();
+
+} GpsNavigationMessageInterface;
+#endif
+
+/**
+ * Interface for passing GNSS configuration contents from platform to HAL.
+ */
+typedef struct {
+ /** Set to sizeof(LocGnssConfigurationInterface) */
+ size_t size;
+
+ /**
+ * Deliver GNSS configuration contents to HAL.
+ * Parameters:
+ * config_data - a pointer to a char array which holds what usually is expected from
+ file(/vendor/etc/gps.conf), i.e., a sequence of UTF8 strings separated by '\n'.
+ * length - total number of UTF8 characters in configuraiton data.
+ *
+ * IMPORTANT:
+ * GPS HAL should expect this function can be called multiple times. And it may be
+ * called even when GpsLocationProvider is already constructed and enabled. GPS HAL
+ * should maintain the existing requests for various callback regardless the change
+ * in configuration data.
+ */
+ void (*configuration_update) (const char* config_data, int32_t length);
+} LocGnssConfigurationInterface;
+
+__END_DECLS
+
+#endif /* LOC_GPS_H */
+
diff --git a/utils/loc_log.cpp b/utils/loc_log.cpp
new file mode 100644
index 0000000..ab28998
--- /dev/null
+++ b/utils/loc_log.cpp
@@ -0,0 +1,238 @@
+/* Copyright (c) 2011-2012, 2015, 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_NDEBUG 0
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/time.h>
+#include "log_util.h"
+#include "loc_log.h"
+#include "msg_q.h"
+#include <loc_pla.h>
+
+#define BUFFER_SIZE 120
+
+// Logging Improvements
+const char *loc_logger_boolStr[]={"False","True"};
+const char VOID_RET[] = "None";
+const char FROM_AFW[] = "===>";
+const char TO_MODEM[] = "--->";
+const char FROM_MODEM[] = "<---";
+const char TO_AFW[] = "<===";
+const char EXIT_TAG[] = "Exiting";
+const char ENTRY_TAG[] = "Entering";
+const char EXIT_ERROR_TAG[] = "Exiting with error";
+
+/* Logging Mechanism */
+loc_logger_s_type loc_logger;
+
+/* Get names from value */
+const char* loc_get_name_from_mask(const loc_name_val_s_type table[], size_t table_size, long mask)
+{
+ size_t i;
+ for (i = 0; i < table_size; i++)
+ {
+ if (table[i].val & (long) mask)
+ {
+ return table[i].name;
+ }
+ }
+ return UNKNOWN_STR;
+}
+
+/* Get names from value */
+const char* loc_get_name_from_val(const loc_name_val_s_type table[], size_t table_size, long value)
+{
+ size_t i;
+ for (i = 0; i < table_size; i++)
+ {
+ if (table[i].val == (long) value)
+ {
+ return table[i].name;
+ }
+ }
+ return UNKNOWN_STR;
+}
+
+static const loc_name_val_s_type loc_msg_q_status[] =
+{
+ NAME_VAL( eMSG_Q_SUCCESS ),
+ NAME_VAL( eMSG_Q_FAILURE_GENERAL ),
+ NAME_VAL( eMSG_Q_INVALID_PARAMETER ),
+ NAME_VAL( eMSG_Q_INVALID_HANDLE ),
+ NAME_VAL( eMSG_Q_UNAVAILABLE_RESOURCE ),
+ NAME_VAL( eMSG_Q_INSUFFICIENT_BUFFER )
+};
+static const size_t loc_msg_q_status_num = LOC_TABLE_SIZE(loc_msg_q_status);
+
+/* Find msg_q status name */
+const char* loc_get_msg_q_status(int status)
+{
+ return loc_get_name_from_val(loc_msg_q_status, loc_msg_q_status_num, (long) status);
+}
+
+const char* log_succ_fail_string(int is_succ)
+{
+ return is_succ? "successful" : "failed";
+}
+
+//Target names
+static const loc_name_val_s_type target_name[] =
+{
+ NAME_VAL(GNSS_NONE),
+ NAME_VAL(GNSS_MSM),
+ NAME_VAL(GNSS_GSS),
+ NAME_VAL(GNSS_MDM),
+ NAME_VAL(GNSS_AUTO),
+ NAME_VAL(GNSS_UNKNOWN)
+};
+
+static const size_t target_name_num = LOC_TABLE_SIZE(target_name);
+
+/*===========================================================================
+
+FUNCTION loc_get_target_name
+
+DESCRIPTION
+ Returns pointer to a string that contains name of the target
+
+ XX:XX:XX.000\0
+
+RETURN VALUE
+ The target name string
+
+===========================================================================*/
+const char *loc_get_target_name(unsigned int target)
+{
+ int index = 0;
+ static char ret[BUFFER_SIZE];
+
+ index = getTargetGnssType(target);
+ if( index < 0 || (unsigned)index >= target_name_num )
+ index = target_name_num - 1;
+
+ if( (target & HAS_SSC) == HAS_SSC ) {
+ snprintf(ret, sizeof(ret), " %s with SSC",
+ loc_get_name_from_val(target_name, target_name_num, (long)index) );
+ }
+ else {
+ snprintf(ret, sizeof(ret), " %s without SSC",
+ loc_get_name_from_val(target_name, target_name_num, (long)index) );
+ }
+ return ret;
+}
+
+
+/*===========================================================================
+
+FUNCTION loc_get_time
+
+DESCRIPTION
+ Logs a callback event header.
+ The pointer time_string should point to a buffer of at least 13 bytes:
+
+ XX:XX:XX.000\0
+
+RETURN VALUE
+ The time string
+
+===========================================================================*/
+char *loc_get_time(char *time_string, size_t buf_size)
+{
+ struct timeval now; /* sec and usec */
+ struct tm now_tm; /* broken-down time */
+ char hms_string[80]; /* HH:MM:SS */
+
+ gettimeofday(&now, NULL);
+ localtime_r(&now.tv_sec, &now_tm);
+
+ strftime(hms_string, sizeof hms_string, "%H:%M:%S", &now_tm);
+ snprintf(time_string, buf_size, "%s.%03d", hms_string, (int) (now.tv_usec / 1000));
+
+ return time_string;
+}
+
+
+/*===========================================================================
+FUNCTION loc_logger_init
+
+DESCRIPTION
+ Initializes the state of DEBUG_LEVEL and TIMESTAMP
+
+DEPENDENCIES
+ N/A
+
+RETURN VALUE
+ None
+
+SIDE EFFECTS
+ N/A
+===========================================================================*/
+void loc_logger_init(unsigned long debug, unsigned long timestamp)
+{
+ loc_logger.DEBUG_LEVEL = debug;
+#ifdef TARGET_BUILD_VARIANT_USER
+ // force user builds to 2 or less
+ if (loc_logger.DEBUG_LEVEL > 2) {
+ loc_logger.DEBUG_LEVEL = 2;
+ }
+#endif
+ loc_logger.TIMESTAMP = timestamp;
+}
+
+
+/*===========================================================================
+FUNCTION get_timestamp
+
+DESCRIPTION
+ Generates a timestamp using the current system time
+
+DEPENDENCIES
+ N/A
+
+RETURN VALUE
+ Char pointer to the parameter str
+
+SIDE EFFECTS
+ N/A
+===========================================================================*/
+char * get_timestamp(char *str, unsigned long buf_size)
+{
+ struct timeval tv;
+ struct timezone tz;
+ int hh, mm, ss;
+ gettimeofday(&tv, &tz);
+ hh = tv.tv_sec/3600%24;
+ mm = (tv.tv_sec%3600)/60;
+ ss = tv.tv_sec%60;
+ snprintf(str, buf_size, "%02d:%02d:%02d.%06ld", hh, mm, ss, tv.tv_usec);
+ return str;
+}
+
diff --git a/utils/loc_log.h b/utils/loc_log.h
new file mode 100644
index 0000000..be492b1
--- /dev/null
+++ b/utils/loc_log.h
@@ -0,0 +1,71 @@
+/* Copyright (c) 2011-2012, 2015 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 LOC_LOG_H
+#define LOC_LOG_H
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include <ctype.h>
+#include <stdlib.h>
+#include "loc_target.h"
+
+typedef struct
+{
+ const char *name;
+ long val;
+} loc_name_val_s_type;
+
+#define NAME_VAL(x) {"" #x "", x }
+
+#define UNKNOWN_STR "UNKNOWN"
+
+#define CHECK_MASK(type, value, mask_var, mask) \
+ (((mask_var) & (mask)) ? (type) (value) : (type) (-1))
+
+#define LOC_TABLE_SIZE(table) (sizeof(table)/sizeof((table)[0]))
+
+/* Get names from value */
+const char* loc_get_name_from_mask(const loc_name_val_s_type table[], size_t table_size, long mask);
+const char* loc_get_name_from_val(const loc_name_val_s_type table[], size_t table_size, long value);
+const char* loc_get_msg_q_status(int status);
+const char* loc_get_target_name(unsigned int target);
+
+extern const char* log_succ_fail_string(int is_succ);
+
+extern char *loc_get_time(char *time_string, size_t buf_size);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* LOC_LOG_H */
diff --git a/utils/loc_misc_utils.cpp b/utils/loc_misc_utils.cpp
new file mode 100644
index 0000000..70fdbc3
--- /dev/null
+++ b/utils/loc_misc_utils.cpp
@@ -0,0 +1,145 @@
+/* Copyright (c) 2014, 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_NDEBUG 0
+#define LOG_TAG "LocSvc_misc_utils"
+#include <stdio.h>
+#include <string.h>
+#include <dlfcn.h>
+#include <log_util.h>
+#include <loc_misc_utils.h>
+#include <ctype.h>
+
+
+int loc_util_split_string(char *raw_string, char **split_strings_ptr,
+ int max_num_substrings, char delimiter)
+{
+ int raw_string_index=0;
+ int num_split_strings=0;
+ unsigned char end_string=0;
+ int raw_string_length=0;
+
+ if(!raw_string || !split_strings_ptr) {
+ LOC_LOGE("%s:%d]: NULL parameters", __func__, __LINE__);
+ num_split_strings = -1;
+ goto err;
+ }
+ LOC_LOGD("%s:%d]: raw string: %s\n", __func__, __LINE__, raw_string);
+ raw_string_length = strlen(raw_string) + 1;
+ split_strings_ptr[num_split_strings] = &raw_string[raw_string_index];
+ for(raw_string_index=0; raw_string_index < raw_string_length; raw_string_index++) {
+ if(raw_string[raw_string_index] == '\0')
+ end_string=1;
+ if((raw_string[raw_string_index] == delimiter) || end_string) {
+ raw_string[raw_string_index] = '\0';
+ LOC_LOGD("%s:%d]: split string: %s\n",
+ __func__, __LINE__, split_strings_ptr[num_split_strings]);
+ num_split_strings++;
+ if(((raw_string_index + 1) < raw_string_length) &&
+ (num_split_strings < max_num_substrings)) {
+ split_strings_ptr[num_split_strings] = &raw_string[raw_string_index+1];
+ }
+ else {
+ break;
+ }
+ }
+ if(end_string)
+ break;
+ }
+err:
+ LOC_LOGD("%s:%d]: num_split_strings: %d\n", __func__, __LINE__, num_split_strings);
+ return num_split_strings;
+}
+
+void loc_util_trim_space(char *org_string)
+{
+ char *scan_ptr, *write_ptr;
+ char *first_nonspace = NULL, *last_nonspace = NULL;
+
+ if(org_string == NULL) {
+ LOC_LOGE("%s:%d]: NULL parameter", __func__, __LINE__);
+ goto err;
+ }
+
+ scan_ptr = write_ptr = org_string;
+
+ while (*scan_ptr) {
+ //Find the first non-space character
+ if ( !isspace(*scan_ptr) && first_nonspace == NULL) {
+ first_nonspace = scan_ptr;
+ }
+ //Once the first non-space character is found in the
+ //above check, keep shifting the characters to the left
+ //to replace the spaces
+ if (first_nonspace != NULL) {
+ *(write_ptr++) = *scan_ptr;
+ //Keep track of which was the last non-space character
+ //encountered
+ //last_nonspace will not be updated in the case where
+ //the string ends with spaces
+ if ( !isspace(*scan_ptr)) {
+ last_nonspace = write_ptr;
+ }
+ }
+ scan_ptr++;
+ }
+ //Add NULL terminator after the last non-space character
+ if (last_nonspace) { *last_nonspace = '\0'; }
+err:
+ return;
+}
+
+inline void logDlError(const char* failedCall) {
+ const char * err = dlerror();
+ LOC_LOGe("%s error: %s", failedCall, (nullptr == err) ? "unknown" : err);
+}
+
+void* dlGetSymFromLib(void*& libHandle, const char* libName, const char* symName)
+{
+ void* sym = nullptr;
+ if ((nullptr != libHandle || nullptr != libName) && nullptr != symName) {
+ if (nullptr == libHandle) {
+ libHandle = dlopen(libName, RTLD_NOW);
+ if (nullptr == libHandle) {
+ logDlError("dlopen");
+ }
+ }
+ // NOT else, as libHandle gets assigned 5 line above
+ if (nullptr != libHandle) {
+ sym = dlsym(libHandle, symName);
+ if (nullptr == sym) {
+ logDlError("dlsym");
+ }
+ }
+ } else {
+ LOC_LOGe("Either libHandle (%p) or libName (%p) must not be null; "
+ "symName (%p) can not be null.", libHandle, libName, symName);
+ }
+
+ return sym;
+}
diff --git a/utils/loc_misc_utils.h b/utils/loc_misc_utils.h
new file mode 100644
index 0000000..fad1b6d
--- /dev/null
+++ b/utils/loc_misc_utils.h
@@ -0,0 +1,127 @@
+/* Copyright (c) 2014, 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 _LOC_MISC_UTILS_H_
+#define _LOC_MISC_UTILS_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*===========================================================================
+FUNCTION loc_split_string
+
+DESCRIPTION:
+ This function is used to split a delimiter separated string into
+ sub-strings. This function does not allocate new memory to store the split
+ strings. Instead, it places '\0' in places of delimiters and assings the
+ starting address of the substring within the raw string as the string address
+ The input raw_string no longer remains to be a collection of sub-strings
+ after this function is executed.
+ Please make a copy of the input string before calling this function if
+ necessary
+
+PARAMETERS:
+ char *raw_string: is the original string with delimiter separated substrings
+ char **split_strings_ptr: is the arraw of pointers which will hold the addresses
+ of individual substrings
+ int max_num_substrings: is the maximum number of substrings that are expected
+ by the caller. The array of pointers in the above parameter
+ is usually this long
+ char delimiter: is the delimiter that separates the substrings. Examples: ' ', ';'
+
+DEPENDENCIES
+ N/A
+
+RETURN VALUE
+ int Number of split strings
+
+SIDE EFFECTS
+ The input raw_string no longer remains a delimiter separated single string.
+
+EXAMPLE
+ delimiter = ' ' //space
+ raw_string = "hello new user" //delimiter is space ' '
+ addresses = 0123456789abcd
+ split_strings_ptr[0] = &raw_string[0]; //split_strings_ptr[0] contains "hello"
+ split_strings_ptr[1] = &raw_string[6]; //split_strings_ptr[1] contains "new"
+ split_strings_ptr[2] = &raw_string[a]; //split_strings_ptr[2] contains "user"
+
+===========================================================================*/
+int loc_util_split_string(char *raw_string, char **split_strings_ptr, int max_num_substrings,
+ char delimiter);
+
+/*===========================================================================
+FUNCTION trim_space
+
+DESCRIPTION
+ Removes leading and trailing spaces of the string
+
+DEPENDENCIES
+ N/A
+
+RETURN VALUE
+ None
+
+SIDE EFFECTS
+ N/A
+===========================================================================*/
+void loc_util_trim_space(char *org_string);
+
+/*===========================================================================
+FUNCTION dlGetSymFromLib
+
+DESCRIPTION
+ Handy function to get a pointer to a symbol from a library.
+
+ If libHandle is not null, it will be used as the handle to the library. In
+ that case libName wll not be used;
+ libHandle is an in / out parameter.
+ If libHandle is null, libName will be used to dlopen.
+ Either libHandle or libName must not be nullptr.
+ symName must not be null.
+
+DEPENDENCIES
+ N/A
+
+RETURN VALUE
+ pointer to symName. Could be nullptr if
+ Parameters are incorrect; or
+ libName can not be opened; or
+ symName can not be found.
+
+SIDE EFFECTS
+ N/A
+===========================================================================*/
+void* dlGetSymFromLib(void*& libHandle, const char* libName, const char* symName);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif //_LOC_MISC_UTILS_H_
diff --git a/utils/loc_nmea.cpp b/utils/loc_nmea.cpp
new file mode 100644
index 0000000..41a707d
--- /dev/null
+++ b/utils/loc_nmea.cpp
@@ -0,0 +1,2088 @@
+/* Copyright (c) 2012-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_NDEBUG 0
+#define LOG_TAG "LocSvc_nmea"
+#include <loc_nmea.h>
+#include <math.h>
+#include <log_util.h>
+#include <loc_pla.h>
+#include <loc_cfg.h>
+
+#define GLONASS_SV_ID_OFFSET 64
+#define QZSS_SV_ID_OFFSET (-192)
+#define MAX_SV_COUNT_SUPPORTED_IN_ONE_CONSTELLATION 64
+#define MAX_SATELLITES_IN_USE 12
+#define MSEC_IN_ONE_WEEK 604800000ULL
+#define UTC_GPS_OFFSET_MSECS 315964800000ULL
+
+// GNSS system id according to NMEA spec
+#define SYSTEM_ID_GPS 1
+#define SYSTEM_ID_GLONASS 2
+#define SYSTEM_ID_GALILEO 3
+#define SYSTEM_ID_BDS 4
+#define SYSTEM_ID_QZSS 5
+#define SYSTEM_ID_NAVIC 6
+
+//GNSS signal id according to NMEA spec
+#define SIGNAL_ID_ALL_SIGNALS 0
+#define SIGNAL_ID_GPS_L1CA 1
+#define SIGNAL_ID_GPS_L1P 2
+#define SIGNAL_ID_GPS_L1M 3
+#define SIGNAL_ID_GPS_L2P 4
+#define SIGNAL_ID_GPS_L2CM 5
+#define SIGNAL_ID_GPS_L2CL 6
+#define SIGNAL_ID_GPS_L5I 7
+#define SIGNAL_ID_GPS_L5Q 8
+
+
+#define SIGNAL_ID_GLO_G1CA 1
+#define SIGNAL_ID_GLO_G1P 2
+#define SIGNAL_ID_GLO_G2CA 3
+#define SIGNAL_ID_GLO_G2P 4
+
+
+#define SIGNAL_ID_GAL_E5A 1
+#define SIGNAL_ID_GAL_E5B 2
+#define SIGNAL_ID_GAL_E5AB 3
+#define SIGNAL_ID_GAL_E6A 4
+#define SIGNAL_ID_GAL_E6BC 5
+#define SIGNAL_ID_GAL_L1A 6
+#define SIGNAL_ID_GAL_L1BC 7
+
+#define SIGNAL_ID_BDS_B1I 1
+#define SIGNAL_ID_BDS_B1Q 2
+#define SIGNAL_ID_BDS_B1C 3
+#define SIGNAL_ID_BDS_B1A 4
+#define SIGNAL_ID_BDS_B2A 5
+#define SIGNAL_ID_BDS_B2B 6
+#define SIGNAL_ID_BDS_B2AB 7
+#define SIGNAL_ID_BDS_B3I 8
+#define SIGNAL_ID_BDS_B3Q 9
+#define SIGNAL_ID_BDS_B3A 0xA
+#define SIGNAL_ID_BDS_B2I 0xB
+#define SIGNAL_ID_BDS_B2Q 0xC
+
+#define SIGNAL_ID_QZSS_L1CA 1
+#define SIGNAL_ID_QZSS_L1CD 2
+#define SIGNAL_ID_QZSS_L1CP 3
+#define SIGNAL_ID_QZSS_LIS 4
+#define SIGNAL_ID_QZSS_L2CM 5
+#define SIGNAL_ID_QZSS_L2CL 6
+#define SIGNAL_ID_QZSS_L5I 7
+#define SIGNAL_ID_QZSS_L5Q 8
+#define SIGNAL_ID_QZSS_L6D 9
+#define SIGNAL_ID_QZSS_L6E 0xA
+
+#define SIGNAL_ID_NAVIC_L5SPS 1
+#define SIGNAL_ID_NAVIC_SSPS 2
+#define SIGNAL_ID_NAVIC_L5RS 3
+#define SIGNAL_ID_NAVIC_SRS 4
+#define SIGNAL_ID_NAVIC_L1SPS 5
+
+
+typedef struct loc_nmea_sv_meta_s
+{
+ char talker[3];
+ LocGnssConstellationType svType;
+ uint64_t mask;
+ uint32_t svCount;
+ uint32_t totalSvUsedCount;
+ uint32_t svIdOffset;
+ uint32_t signalId;
+ uint32_t systemId;
+} loc_nmea_sv_meta;
+
+typedef struct loc_sv_cache_info_s
+{
+ uint64_t gps_used_mask;
+ uint64_t glo_used_mask;
+ uint64_t gal_used_mask;
+ uint64_t qzss_used_mask;
+ uint64_t bds_used_mask;
+ uint64_t navic_used_mask;
+ uint32_t gps_l1_count;
+ uint32_t gps_l5_count;
+ uint32_t glo_g1_count;
+ uint32_t glo_g2_count;
+ uint32_t gal_e1_count;
+ uint32_t gal_e5_count;
+ uint32_t qzss_l1_count;
+ uint32_t qzss_l5_count;
+ uint32_t bds_b1_count;
+ uint32_t bds_b2_count;
+ uint32_t navic_l5_count;
+ float hdop;
+ float pdop;
+ float vdop;
+} loc_sv_cache_info;
+
+/*===========================================================================
+FUNCTION convert_Lla_to_Ecef
+
+DESCRIPTION
+ Convert LLA to ECEF
+
+DEPENDENCIES
+ NONE
+
+RETURN VALUE
+ NONE
+
+SIDE EFFECTS
+ N/A
+
+===========================================================================*/
+static void convert_Lla_to_Ecef(const LocLla& plla, LocEcef& pecef)
+{
+ double r;
+
+ r = MAJA / sqrt(1.0 - ESQR * sin(plla.lat) * sin(plla.lat));
+ pecef.X = (r + plla.alt) * cos(plla.lat) * cos(plla.lon);
+ pecef.Y = (r + plla.alt) * cos(plla.lat) * sin(plla.lon);
+ pecef.Z = (r * OMES + plla.alt) * sin(plla.lat);
+}
+
+/*===========================================================================
+FUNCTION convert_WGS84_to_PZ90
+
+DESCRIPTION
+ Convert datum from WGS84 to PZ90
+
+DEPENDENCIES
+ NONE
+
+RETURN VALUE
+ NONE
+
+SIDE EFFECTS
+ N/A
+
+===========================================================================*/
+static void convert_WGS84_to_PZ90(const LocEcef& pWGS84, LocEcef& pPZ90)
+{
+ double deltaX = DatumConstFromWGS84[0];
+ double deltaY = DatumConstFromWGS84[1];
+ double deltaZ = DatumConstFromWGS84[2];
+ double deltaScale = DatumConstFromWGS84[3];
+ double rotX = DatumConstFromWGS84[4];
+ double rotY = DatumConstFromWGS84[5];
+ double rotZ = DatumConstFromWGS84[6];
+
+ pPZ90.X = deltaX + deltaScale * (pWGS84.X + rotZ * pWGS84.Y - rotY * pWGS84.Z);
+ pPZ90.Y = deltaY + deltaScale * (pWGS84.Y - rotZ * pWGS84.X + rotX * pWGS84.Z);
+ pPZ90.Z = deltaZ + deltaScale * (pWGS84.Z + rotY * pWGS84.X - rotX * pWGS84.Y);
+}
+
+/*===========================================================================
+FUNCTION convert_Ecef_to_Lla
+
+DESCRIPTION
+ Convert ECEF to LLA
+
+DEPENDENCIES
+ NONE
+
+RETURN VALUE
+ NONE
+
+SIDE EFFECTS
+ N/A
+
+===========================================================================*/
+static void convert_Ecef_to_Lla(const LocEcef& pecef, LocLla& plla)
+{
+ double p, r;
+ double EcefA = C_PZ90A;
+ double EcefB = C_PZ90B;
+ double Ecef1Mf;
+ double EcefE2;
+ double Mu;
+ double Smu;
+ double Cmu;
+ double Phi;
+ double Sphi;
+ double N;
+
+ p = sqrt(pecef.X * pecef.X + pecef.Y * pecef.Y);
+ r = sqrt(p * p + pecef.Z * pecef.Z);
+ if (r < 1.0) {
+ plla.lat = 1.0;
+ plla.lon = 1.0;
+ plla.alt = 1.0;
+ }
+ Ecef1Mf = 1.0 - (EcefA - EcefB) / EcefA;
+ EcefE2 = 1.0 - (EcefB * EcefB) / (EcefA * EcefA);
+ if (p > 1.0) {
+ Mu = atan2(pecef.Z * (Ecef1Mf + EcefE2 * EcefA / r), p);
+ } else {
+ if (pecef.Z > 0.0) {
+ Mu = M_PI / 2.0;
+ } else {
+ Mu = -M_PI / 2.0;
+ }
+ }
+ Smu = sin(Mu);
+ Cmu = cos(Mu);
+ Phi = atan2(pecef.Z * Ecef1Mf + EcefE2 * EcefA * Smu * Smu * Smu,
+ Ecef1Mf * (p - EcefE2 * EcefA * Cmu * Cmu * Cmu));
+ Sphi = sin(Phi);
+ N = EcefA / sqrt(1.0 - EcefE2 * Sphi * Sphi);
+ plla.alt = p * cos(Phi) + pecef.Z * Sphi - EcefA * EcefA/N;
+ plla.lat = Phi;
+ if ( p > 1.0) {
+ plla.lon = atan2(pecef.Y, pecef.X);
+ } else {
+ plla.lon = 0.0;
+ }
+}
+
+/*===========================================================================
+FUNCTION convert_signalType_to_signalId
+
+DESCRIPTION
+ convert signalType to signal ID
+
+DEPENDENCIES
+ NONE
+
+RETURN VALUE
+ value of signal ID
+
+SIDE EFFECTS
+ N/A
+
+===========================================================================*/
+static uint32_t convert_signalType_to_signalId(GnssSignalTypeMask signalType)
+{
+ uint32_t signalId = SIGNAL_ID_ALL_SIGNALS;
+
+ switch (signalType) {
+ case GNSS_SIGNAL_GPS_L1CA:
+ signalId = SIGNAL_ID_GPS_L1CA;
+ break;
+ case GNSS_SIGNAL_GPS_L2:
+ signalId = SIGNAL_ID_GPS_L2CL;
+ break;
+ case GNSS_SIGNAL_GPS_L5:
+ signalId = SIGNAL_ID_GPS_L5Q;
+ break;
+ case GNSS_SIGNAL_GLONASS_G1:
+ signalId = SIGNAL_ID_GLO_G1CA;
+ break;
+ case GNSS_SIGNAL_GLONASS_G2:
+ signalId = SIGNAL_ID_GLO_G2CA;
+ break;
+ case GNSS_SIGNAL_GALILEO_E1:
+ signalId = SIGNAL_ID_GAL_L1BC;
+ break;
+ case GNSS_SIGNAL_GALILEO_E5A:
+ signalId = SIGNAL_ID_GAL_E5A;
+ break;
+ case GNSS_SIGNAL_GALILEO_E5B:
+ signalId = SIGNAL_ID_GAL_E5B;
+ break;
+ case GNSS_SIGNAL_QZSS_L1CA:
+ signalId = SIGNAL_ID_QZSS_L1CA;
+ break;
+ case GNSS_SIGNAL_QZSS_L2:
+ signalId = SIGNAL_ID_QZSS_L2CL;
+ break;
+ case GNSS_SIGNAL_QZSS_L5:
+ signalId = SIGNAL_ID_QZSS_L5Q;
+ break;
+ case GNSS_SIGNAL_BEIDOU_B1I:
+ signalId = SIGNAL_ID_BDS_B1I;
+ break;
+ case GNSS_SIGNAL_BEIDOU_B1C:
+ signalId = SIGNAL_ID_BDS_B1C;
+ break;
+ case GNSS_SIGNAL_BEIDOU_B2I:
+ signalId = SIGNAL_ID_BDS_B2I;
+ break;
+ case GNSS_SIGNAL_BEIDOU_B2AI:
+ case GNSS_SIGNAL_BEIDOU_B2AQ:
+ signalId = SIGNAL_ID_BDS_B2A;
+ break;
+ case GNSS_SIGNAL_NAVIC_L5:
+ signalId = SIGNAL_ID_NAVIC_L5SPS;
+ break;
+ default:
+ signalId = SIGNAL_ID_ALL_SIGNALS;
+ }
+
+ return signalId;
+
+}
+
+/*===========================================================================
+FUNCTION get_sv_count_from_mask
+
+DESCRIPTION
+ get the sv count from bit mask
+
+DEPENDENCIES
+ NONE
+
+RETURN VALUE
+ value of sv count
+
+SIDE EFFECTS
+ N/A
+
+===========================================================================*/
+static uint32_t get_sv_count_from_mask(uint64_t svMask, int totalSvCount)
+{
+ int index = 0;
+ uint32_t svCount = 0;
+
+ if(totalSvCount > MAX_SV_COUNT_SUPPORTED_IN_ONE_CONSTELLATION) {
+ LOC_LOGE("total SV count in this constellation %d exceeded limit %d",
+ totalSvCount, MAX_SV_COUNT_SUPPORTED_IN_ONE_CONSTELLATION);
+ }
+ for(index = 0; index < totalSvCount; index++) {
+ if(svMask & 0x1)
+ svCount += 1;
+ svMask >>= 1;
+ }
+ return svCount;
+}
+
+/*===========================================================================
+FUNCTION loc_nmea_sv_meta_init
+
+DESCRIPTION
+ Init loc_nmea_sv_meta passed in
+
+DEPENDENCIES
+ NONE
+
+RETURN VALUE
+ Pointer to loc_nmea_sv_meta
+
+SIDE EFFECTS
+ N/A
+
+===========================================================================*/
+static loc_nmea_sv_meta* loc_nmea_sv_meta_init(loc_nmea_sv_meta& sv_meta,
+ loc_sv_cache_info& sv_cache_info,
+ GnssSvType svType,
+ GnssSignalTypeMask signalType,
+ bool needCombine)
+{
+ memset(&sv_meta, 0, sizeof(sv_meta));
+ sv_meta.svType = svType;
+
+ switch (svType)
+ {
+ case GNSS_SV_TYPE_GPS:
+ sv_meta.talker[0] = 'G';
+ sv_meta.talker[1] = 'P';
+ sv_meta.mask = sv_cache_info.gps_used_mask;
+ sv_meta.systemId = SYSTEM_ID_GPS;
+ if (GNSS_SIGNAL_GPS_L1CA == signalType) {
+ sv_meta.svCount = sv_cache_info.gps_l1_count;
+ } else if (GNSS_SIGNAL_GPS_L5 == signalType) {
+ sv_meta.svCount = sv_cache_info.gps_l5_count;
+ }
+ break;
+ case GNSS_SV_TYPE_GLONASS:
+ sv_meta.talker[0] = 'G';
+ sv_meta.talker[1] = 'L';
+ sv_meta.mask = sv_cache_info.glo_used_mask;
+ // GLONASS SV ids are from 65-96
+ sv_meta.svIdOffset = GLONASS_SV_ID_OFFSET;
+ sv_meta.systemId = SYSTEM_ID_GLONASS;
+ if (GNSS_SIGNAL_GLONASS_G1 == signalType) {
+ sv_meta.svCount = sv_cache_info.glo_g1_count;
+ } else if (GNSS_SIGNAL_GLONASS_G2 == signalType) {
+ sv_meta.svCount = sv_cache_info.glo_g2_count;
+ }
+ break;
+ case GNSS_SV_TYPE_GALILEO:
+ sv_meta.talker[0] = 'G';
+ sv_meta.talker[1] = 'A';
+ sv_meta.mask = sv_cache_info.gal_used_mask;
+ sv_meta.systemId = SYSTEM_ID_GALILEO;
+ if (GNSS_SIGNAL_GALILEO_E1 == signalType) {
+ sv_meta.svCount = sv_cache_info.gal_e1_count;
+ } else if (GNSS_SIGNAL_GALILEO_E5A == signalType) {
+ sv_meta.svCount = sv_cache_info.gal_e5_count;
+ }
+ break;
+ case GNSS_SV_TYPE_QZSS:
+ sv_meta.talker[0] = 'G';
+ sv_meta.talker[1] = 'Q';
+ sv_meta.mask = sv_cache_info.qzss_used_mask;
+ // QZSS SV ids are from 193-199. So keep svIdOffset -192
+ sv_meta.svIdOffset = QZSS_SV_ID_OFFSET;
+ sv_meta.systemId = SYSTEM_ID_QZSS;
+ if (GNSS_SIGNAL_QZSS_L1CA == signalType) {
+ sv_meta.svCount = sv_cache_info.qzss_l1_count;
+ } else if (GNSS_SIGNAL_QZSS_L5 == signalType) {
+ sv_meta.svCount = sv_cache_info.qzss_l5_count;
+ }
+ break;
+ case GNSS_SV_TYPE_BEIDOU:
+ sv_meta.talker[0] = 'G';
+ sv_meta.talker[1] = 'B';
+ sv_meta.mask = sv_cache_info.bds_used_mask;
+ // BDS SV ids are from 201-235. So keep svIdOffset 0
+ sv_meta.systemId = SYSTEM_ID_BDS;
+ if (GNSS_SIGNAL_BEIDOU_B1I == signalType) {
+ sv_meta.svCount = sv_cache_info.bds_b1_count;
+ } else if (GNSS_SIGNAL_BEIDOU_B2AI == signalType) {
+ sv_meta.svCount = sv_cache_info.bds_b2_count;
+ }
+ break;
+ case GNSS_SV_TYPE_NAVIC:
+ sv_meta.talker[0] = 'G';
+ sv_meta.talker[1] = 'I';
+ sv_meta.mask = sv_cache_info.navic_used_mask;
+ // NAVIC SV ids are from 401-414. So keep svIdOffset 0
+ sv_meta.systemId = SYSTEM_ID_NAVIC;
+ if (GNSS_SIGNAL_NAVIC_L5 == signalType) {
+ sv_meta.svCount = sv_cache_info.navic_l5_count;
+ }
+ break;
+ default:
+ LOC_LOGE("NMEA Error unknow constellation type: %d", svType);
+ return NULL;
+ }
+ sv_meta.signalId = convert_signalType_to_signalId(signalType);
+ sv_meta.totalSvUsedCount =
+ get_sv_count_from_mask(sv_cache_info.gps_used_mask,
+ GPS_SV_PRN_MAX - GPS_SV_PRN_MIN + 1) +
+ get_sv_count_from_mask(sv_cache_info.glo_used_mask,
+ GLO_SV_PRN_MAX - GLO_SV_PRN_MIN + 1) +
+ get_sv_count_from_mask(sv_cache_info.gal_used_mask,
+ GAL_SV_PRN_MAX - GAL_SV_PRN_MIN + 1) +
+ get_sv_count_from_mask(sv_cache_info.qzss_used_mask,
+ QZSS_SV_PRN_MAX - QZSS_SV_PRN_MIN + 1) +
+ get_sv_count_from_mask(sv_cache_info.bds_used_mask,
+ BDS_SV_PRN_MAX - BDS_SV_PRN_MIN + 1) +
+ get_sv_count_from_mask(sv_cache_info.navic_used_mask,
+ NAVIC_SV_PRN_MAX - NAVIC_SV_PRN_MIN + 1);
+ if (needCombine &&
+ (sv_cache_info.gps_used_mask ? 1 : 0) +
+ (sv_cache_info.glo_used_mask ? 1 : 0) +
+ (sv_cache_info.gal_used_mask ? 1 : 0) +
+ (sv_cache_info.qzss_used_mask ? 1 : 0) +
+ (sv_cache_info.bds_used_mask ? 1 : 0) +
+ (sv_cache_info.navic_used_mask ? 1 : 0) > 1)
+ {
+ // If GPS, GLONASS, Galileo, QZSS, BDS etc. are combined
+ // to obtain the reported position solution,
+ // talker shall be set to GN, to indicate that
+ // the satellites are used in a combined solution
+ sv_meta.talker[0] = 'G';
+ sv_meta.talker[1] = 'N';
+ }
+ return &sv_meta;
+}
+
+/*===========================================================================
+FUNCTION loc_nmea_put_checksum
+
+DESCRIPTION
+ Generate NMEA sentences generated based on position report
+
+DEPENDENCIES
+ NONE
+
+RETURN VALUE
+ Total length of the nmea sentence
+
+SIDE EFFECTS
+ N/A
+
+===========================================================================*/
+static int loc_nmea_put_checksum(char *pNmea, int maxSize)
+{
+ uint8_t checksum = 0;
+ int length = 0;
+ if(NULL == pNmea)
+ return 0;
+
+ pNmea++; //skip the $
+ while (*pNmea != '\0')
+ {
+ checksum ^= *pNmea++;
+ length++;
+ }
+
+ // length now contains nmea sentence string length not including $ sign.
+ int checksumLength = snprintf(pNmea,(maxSize-length-1),"*%02X\r\n", checksum);
+
+ // total length of nmea sentence is length of nmea sentence inc $ sign plus
+ // length of checksum (+1 is to cover the $ character in the length).
+ return (length + checksumLength + 1);
+}
+
+/*===========================================================================
+FUNCTION loc_nmea_generate_GSA
+
+DESCRIPTION
+ Generate NMEA GSA sentences generated based on position report
+ Currently below sentences are generated:
+ - $GPGSA : GPS DOP and active SVs
+ - $GLGSA : GLONASS DOP and active SVs
+ - $GAGSA : GALILEO DOP and active SVs
+ - $GNGSA : GNSS DOP and active SVs
+
+DEPENDENCIES
+ NONE
+
+RETURN VALUE
+ Number of SVs used
+
+SIDE EFFECTS
+ N/A
+
+===========================================================================*/
+static uint32_t loc_nmea_generate_GSA(const GpsLocationExtended &locationExtended,
+ char* sentence,
+ int bufSize,
+ loc_nmea_sv_meta* sv_meta_p,
+ std::vector<std::string> &nmeaArraystr)
+{
+ if (!sentence || bufSize <= 0 || !sv_meta_p)
+ {
+ LOC_LOGE("NMEA Error invalid arguments.");
+ return 0;
+ }
+
+ char* pMarker = sentence;
+ int lengthRemaining = bufSize;
+ int length = 0;
+
+ uint32_t svUsedCount = 0;
+ uint32_t svUsedList[64] = {0};
+
+ char fixType = '\0';
+
+ const char* talker = sv_meta_p->talker;
+ uint32_t svIdOffset = sv_meta_p->svIdOffset;
+ uint64_t mask = sv_meta_p->mask;
+
+ if(sv_meta_p->svType != GNSS_SV_TYPE_GLONASS) {
+ svIdOffset = 0;
+ }
+
+ for (uint8_t i = 1; mask > 0 && svUsedCount < 64; i++)
+ {
+ if (mask & 1)
+ svUsedList[svUsedCount++] = i + svIdOffset;
+ mask = mask >> 1;
+ }
+
+ if (svUsedCount == 0)
+ return 0;
+
+ if (sv_meta_p->totalSvUsedCount == 0)
+ fixType = '1'; // no fix
+ else if (sv_meta_p->totalSvUsedCount <= 3)
+ fixType = '2'; // 2D fix
+ else
+ fixType = '3'; // 3D fix
+
+ // Start printing the sentence
+ // Format: $--GSA,a,x,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,p.p,h.h,v.v,s*cc
+ // a : Mode : A : Automatic, allowed to automatically switch 2D/3D
+ // x : Fixtype : 1 (no fix), 2 (2D fix), 3 (3D fix)
+ // xx : 12 SV ID
+ // p.p : Position DOP (Dilution of Precision)
+ // h.h : Horizontal DOP
+ // v.v : Vertical DOP
+ // s : GNSS System Id
+ // cc : Checksum value
+ length = snprintf(pMarker, lengthRemaining, "$%sGSA,A,%c,", talker, fixType);
+
+ if (length < 0 || length >= lengthRemaining)
+ {
+ LOC_LOGE("NMEA Error in string formatting");
+ return 0;
+ }
+ pMarker += length;
+ lengthRemaining -= length;
+
+ // Add first 12 satellite IDs
+ for (uint8_t i = 0; i < 12; i++)
+ {
+ if (i < svUsedCount)
+ length = snprintf(pMarker, lengthRemaining, "%02d,", svUsedList[i]);
+ else
+ length = snprintf(pMarker, lengthRemaining, ",");
+
+ if (length < 0 || length >= lengthRemaining)
+ {
+ LOC_LOGE("NMEA Error in string formatting");
+ return 0;
+ }
+ pMarker += length;
+ lengthRemaining -= length;
+ }
+
+ // Add the position/horizontal/vertical DOP values
+ if (locationExtended.flags & GPS_LOCATION_EXTENDED_HAS_DOP)
+ {
+ length = snprintf(pMarker, lengthRemaining, "%.1f,%.1f,%.1f,",
+ locationExtended.pdop,
+ locationExtended.hdop,
+ locationExtended.vdop);
+ }
+ else
+ { // no dop
+ length = snprintf(pMarker, lengthRemaining, ",,,");
+ }
+ pMarker += length;
+ lengthRemaining -= length;
+
+ // system id
+ length = snprintf(pMarker, lengthRemaining, "%d", sv_meta_p->systemId);
+ pMarker += length;
+ lengthRemaining -= length;
+
+ /* Sentence is ready, add checksum and broadcast */
+ length = loc_nmea_put_checksum(sentence, bufSize);
+ nmeaArraystr.push_back(sentence);
+
+ return svUsedCount;
+}
+
+/*===========================================================================
+FUNCTION loc_nmea_generate_GSV
+
+DESCRIPTION
+ Generate NMEA GSV sentences generated based on sv report
+ Currently below sentences are generated:
+ - $GPGSV: GPS Satellites in View
+ - $GLGSV: GLONASS Satellites in View
+ - $GAGSV: GALILEO Satellites in View
+
+DEPENDENCIES
+ NONE
+
+RETURN VALUE
+ NONE
+
+SIDE EFFECTS
+ N/A
+
+===========================================================================*/
+static void loc_nmea_generate_GSV(const GnssSvNotification &svNotify,
+ char* sentence,
+ int bufSize,
+ loc_nmea_sv_meta* sv_meta_p,
+ std::vector<std::string> &nmeaArraystr)
+{
+ if (!sentence || bufSize <= 0)
+ {
+ LOC_LOGE("NMEA Error invalid argument.");
+ return;
+ }
+
+ char* pMarker = sentence;
+ int lengthRemaining = bufSize;
+ int length = 0;
+ int sentenceCount = 0;
+ int sentenceNumber = 1;
+ size_t svNumber = 1;
+
+ const char* talker = sv_meta_p->talker;
+ uint32_t svIdOffset = sv_meta_p->svIdOffset;
+ int svCount = sv_meta_p->svCount;
+ if (svCount <= 0)
+ {
+ LOC_LOGV("No SV in view for talker ID:%s, signal ID:%X", talker, sv_meta_p->signalId);
+ return;
+ }
+
+ svNumber = 1;
+ sentenceNumber = 1;
+ sentenceCount = svCount / 4 + (svCount % 4 != 0);
+
+ while (sentenceNumber <= sentenceCount)
+ {
+ pMarker = sentence;
+ lengthRemaining = bufSize;
+
+ length = snprintf(pMarker, lengthRemaining, "$%sGSV,%d,%d,%02d",
+ talker, sentenceCount, sentenceNumber, svCount);
+
+ if (length < 0 || length >= lengthRemaining)
+ {
+ LOC_LOGE("NMEA Error in string formatting");
+ return;
+ }
+ pMarker += length;
+ lengthRemaining -= length;
+
+ for (int i=0; (svNumber <= svNotify.count) && (i < 4); svNumber++)
+ {
+ GnssSignalTypeMask signalType = svNotify.gnssSvs[svNumber-1].gnssSignalTypeMask;
+ if (0 == signalType) {
+ // If no signal type in report, it means default L1,G1,E1,B1I
+ switch (svNotify.gnssSvs[svNumber - 1].type)
+ {
+ case GNSS_SV_TYPE_GPS:
+ signalType = GNSS_SIGNAL_GPS_L1CA;
+ break;
+ case GNSS_SV_TYPE_GLONASS:
+ signalType = GNSS_SIGNAL_GLONASS_G1;
+ break;
+ case GNSS_SV_TYPE_GALILEO:
+ signalType = GNSS_SIGNAL_GALILEO_E1;
+ break;
+ case GNSS_SV_TYPE_QZSS:
+ signalType = GNSS_SIGNAL_QZSS_L1CA;
+ break;
+ case GNSS_SV_TYPE_BEIDOU:
+ signalType = GNSS_SIGNAL_BEIDOU_B1I;
+ break;
+ case GNSS_SV_TYPE_SBAS:
+ signalType = GNSS_SIGNAL_SBAS_L1;
+ break;
+ case GNSS_SV_TYPE_NAVIC:
+ signalType = GNSS_SIGNAL_NAVIC_L5;
+ break;
+ default:
+ LOC_LOGE("NMEA Error unknow constellation type: %d",
+ svNotify.gnssSvs[svNumber - 1].type);
+ continue;
+ }
+ }
+
+ if (sv_meta_p->svType == svNotify.gnssSvs[svNumber - 1].type &&
+ sv_meta_p->signalId == convert_signalType_to_signalId(signalType))
+ {
+ length = snprintf(pMarker, lengthRemaining,",%02d,%02d,%03d,",
+ svNotify.gnssSvs[svNumber - 1].svId + svIdOffset,
+ (int)(0.5 + svNotify.gnssSvs[svNumber - 1].elevation), //float to int
+ (int)(0.5 + svNotify.gnssSvs[svNumber - 1].azimuth)); //float to int
+
+ if (length < 0 || length >= lengthRemaining)
+ {
+ LOC_LOGE("NMEA Error in string formatting");
+ return;
+ }
+ pMarker += length;
+ lengthRemaining -= length;
+
+ if (svNotify.gnssSvs[svNumber - 1].cN0Dbhz > 0)
+ {
+ length = snprintf(pMarker, lengthRemaining,"%02d",
+ (int)(0.5 + svNotify.gnssSvs[svNumber - 1].cN0Dbhz)); //float to int
+
+ if (length < 0 || length >= lengthRemaining)
+ {
+ LOC_LOGE("NMEA Error in string formatting");
+ return;
+ }
+ pMarker += length;
+ lengthRemaining -= length;
+ }
+
+ i++;
+ }
+
+ }
+
+ // append signalId
+ length = snprintf(pMarker, lengthRemaining,",%X",sv_meta_p->signalId);
+ pMarker += length;
+ lengthRemaining -= length;
+
+ length = loc_nmea_put_checksum(sentence, bufSize);
+ nmeaArraystr.push_back(sentence);
+ sentenceNumber++;
+
+ } //while
+}
+
+/*===========================================================================
+FUNCTION loc_nmea_generate_DTM
+
+DESCRIPTION
+ Generate NMEA DTM sentences generated based on position report
+
+DEPENDENCIES
+ NONE
+
+RETURN VALUE
+ NONE
+
+SIDE EFFECTS
+ N/A
+
+===========================================================================*/
+static void loc_nmea_generate_DTM(const LocLla &ref_lla,
+ const LocLla &local_lla,
+ char *talker,
+ char *sentence,
+ int bufSize)
+{
+ char* pMarker = sentence;
+ int lengthRemaining = bufSize;
+ int length = 0;
+ int datum_type;
+ char ref_datum[4] = {0};
+ char local_datum[4] = {0};
+ double lla_offset[3] = {0};
+ char latHem, longHem;
+ double latMins, longMins;
+
+
+
+ datum_type = loc_get_datum_type();
+ switch (datum_type) {
+ case LOC_GNSS_DATUM_WGS84:
+ ref_datum[0] = 'W';
+ ref_datum[1] = '8';
+ ref_datum[2] = '4';
+ local_datum[0] = 'P';
+ local_datum[1] = '9';
+ local_datum[2] = '0';
+ break;
+ case LOC_GNSS_DATUM_PZ90:
+ ref_datum[0] = 'P';
+ ref_datum[1] = '9';
+ ref_datum[2] = '0';
+ local_datum[0] = 'W';
+ local_datum[1] = '8';
+ local_datum[2] = '4';
+ break;
+ default:
+ break;
+ }
+ length = snprintf(pMarker , lengthRemaining , "$%sDTM,%s,," , talker, local_datum);
+ if (length < 0 || length >= lengthRemaining) {
+ LOC_LOGE("NMEA Error in string formatting");
+ return;
+ }
+ pMarker += length;
+ lengthRemaining -= length;
+
+ lla_offset[0] = local_lla.lat - ref_lla.lat;
+ lla_offset[1] = fmod(local_lla.lon - ref_lla.lon, 360.0);
+ if (lla_offset[1] < -180.0) {
+ lla_offset[1] += 360.0;
+ } else if ( lla_offset[1] > 180.0) {
+ lla_offset[1] -= 360.0;
+ }
+ lla_offset[2] = local_lla.alt - ref_lla.alt;
+ if (lla_offset[0] > 0.0) {
+ latHem = 'N';
+ } else {
+ latHem = 'S';
+ lla_offset[0] *= -1.0;
+ }
+ latMins = fmod(lla_offset[0] * 60.0, 60.0);
+ if (lla_offset[1] < 0.0) {
+ longHem = 'W';
+ lla_offset[1] *= -1.0;
+ }else {
+ longHem = 'E';
+ }
+ longMins = fmod(lla_offset[1] * 60.0, 60.0);
+ length = snprintf(pMarker, lengthRemaining, "%02d%09.6lf,%c,%03d%09.6lf,%c,%.3lf,",
+ (uint8_t)floor(lla_offset[0]), latMins, latHem,
+ (uint8_t)floor(lla_offset[1]), longMins, longHem, lla_offset[2]);
+ if (length < 0 || length >= lengthRemaining) {
+ LOC_LOGE("NMEA Error in string formatting");
+ return;
+ }
+ pMarker += length;
+ lengthRemaining -= length;
+ length = snprintf(pMarker , lengthRemaining , "%s" , ref_datum);
+ if (length < 0 || length >= lengthRemaining) {
+ LOC_LOGE("NMEA Error in string formatting");
+ return;
+ }
+ pMarker += length;
+ lengthRemaining -= length;
+
+ length = loc_nmea_put_checksum(sentence, bufSize);
+}
+
+/*===========================================================================
+FUNCTION get_utctime_with_leapsecond_transition
+
+DESCRIPTION
+ This function returns true if the position report is generated during
+ leap second transition period. If not, then the utc timestamp returned
+ will be set to the timestamp in the position report. If it is,
+ then the utc timestamp returned will need to take into account
+ of the leap second transition so that proper calendar year/month/date
+ can be calculated from the returned utc timestamp.
+
+DEPENDENCIES
+ NONE
+
+RETURN VALUE
+ true: position report is generated in leap second transition period.
+
+SIDE EFFECTS
+ N/A
+
+===========================================================================*/
+static bool get_utctime_with_leapsecond_transition(
+ const UlpLocation &location,
+ const GpsLocationExtended &locationExtended,
+ const LocationSystemInfo &systemInfo,
+ LocGpsUtcTime &utcPosTimestamp)
+{
+ bool inTransition = false;
+
+ // position report is not generated during leap second transition,
+ // we can use the UTC timestamp from position report as is
+ utcPosTimestamp = location.gpsLocation.timestamp;
+
+ // Check whether we are in leap second transition.
+ // If so, per NMEA spec, we need to display the extra second in format of 23:59:60
+ // with year/month/date not getting advanced.
+ if ((locationExtended.flags & GPS_LOCATION_EXTENDED_HAS_GPS_TIME) &&
+ ((systemInfo.systemInfoMask & LOCATION_SYS_INFO_LEAP_SECOND) &&
+ (systemInfo.leapSecondSysInfo.leapSecondInfoMask &
+ LEAP_SECOND_SYS_INFO_LEAP_SECOND_CHANGE_BIT))) {
+
+ const LeapSecondChangeInfo &leapSecondChangeInfo =
+ systemInfo.leapSecondSysInfo.leapSecondChangeInfo;
+ const GnssSystemTimeStructType &gpsTimestampLsChange =
+ leapSecondChangeInfo.gpsTimestampLsChange;
+
+ uint64_t gpsTimeLsChange = gpsTimestampLsChange.systemWeek * MSEC_IN_ONE_WEEK +
+ gpsTimestampLsChange.systemMsec;
+ uint64_t gpsTimePosReport = locationExtended.gpsTime.gpsWeek * MSEC_IN_ONE_WEEK +
+ locationExtended.gpsTime.gpsTimeOfWeekMs;
+ // we are only dealing with positive leap second change, as negative
+ // leap second change has never occurred and should not occur in future
+ if (leapSecondChangeInfo.leapSecondsAfterChange >
+ leapSecondChangeInfo.leapSecondsBeforeChange) {
+ // leap second adjustment is always 1 second at a time. It can happen
+ // every quarter end and up to four times per year.
+ if ((gpsTimePosReport >= gpsTimeLsChange) &&
+ (gpsTimePosReport < (gpsTimeLsChange + 1000))) {
+ inTransition = true;
+ utcPosTimestamp = gpsTimeLsChange + UTC_GPS_OFFSET_MSECS -
+ leapSecondChangeInfo.leapSecondsBeforeChange * 1000;
+
+ // we substract 1000 milli-seconds from UTC timestmap in order to calculate the
+ // proper year, month and date during leap second transtion.
+ // Let us give an example, assuming leap second transition is scheduled on 2019,
+ // Dec 31st mid night. When leap second transition is happening,
+ // instead of outputting the time as 2020, Jan, 1st, 00 hour, 00 min, and 00 sec.
+ // The time need to be displayed as 2019, Dec, 31st, 23 hour, 59 min and 60 sec.
+ utcPosTimestamp -= 1000;
+ }
+ }
+ }
+ return inTransition;
+}
+
+/*===========================================================================
+FUNCTION loc_nmea_get_fix_quality
+
+DESCRIPTION
+ This function obtains the fix quality for GGA sentence, mode indicator
+ for RMC and VTG sentence based on nav solution mask and tech mask in
+ the postion report.
+
+DEPENDENCIES
+ NONE
+
+Output parameter
+ ggaGpsQuality: gps quality field in GGA sentence
+ rmcModeIndicator: mode indicator field in RMC sentence
+ vtgModeIndicator: mode indicator field in VTG sentence
+
+SIDE EFFECTS
+ N/A
+
+===========================================================================*/
+static void loc_nmea_get_fix_quality(const UlpLocation & location,
+ const GpsLocationExtended & locationExtended,
+ char & ggaGpsQuality,
+ char & rmcModeIndicator,
+ char & vtgModeIndicator) {
+
+ ggaGpsQuality = '0';
+ rmcModeIndicator = 'N';
+ vtgModeIndicator = 'N';
+
+ do {
+ if (!(location.gpsLocation.flags & LOC_GPS_LOCATION_HAS_LAT_LONG)){
+ ggaGpsQuality = '0'; // 0 means no fix
+ rmcModeIndicator = 'N';
+ vtgModeIndicator = 'N';
+ break;
+ }
+ // NOTE: Order of the check is important
+ if (locationExtended.flags & GPS_LOCATION_EXTENDED_HAS_NAV_SOLUTION_MASK) {
+ if (LOC_NAV_MASK_PPP_CORRECTION & locationExtended.navSolutionMask) {
+ ggaGpsQuality = '2'; // 2 means DGPS fix
+ rmcModeIndicator = 'P'; // P means precise
+ vtgModeIndicator = 'P'; // P means precise
+ break;
+ } else if (LOC_NAV_MASK_RTK_FIXED_CORRECTION & locationExtended.navSolutionMask){
+ ggaGpsQuality = '4'; // 4 means RTK Fixed fix
+ rmcModeIndicator = 'R'; // use R (RTK fixed)
+ vtgModeIndicator = 'D'; // use D (differential) as
+ // no RTK fixed defined for VTG in NMEA 183 spec
+ break;
+ } else if (LOC_NAV_MASK_RTK_CORRECTION & locationExtended.navSolutionMask){
+ ggaGpsQuality = '5'; // 5 means RTK float fix
+ rmcModeIndicator = 'F'; // F means RTK float fix
+ vtgModeIndicator = 'D'; // use D (differential) as
+ // no RTK float defined for VTG in NMEA 183 spec
+ break;
+ } else if (LOC_NAV_MASK_DGNSS_CORRECTION & locationExtended.navSolutionMask){
+ ggaGpsQuality = '2'; // 2 means DGPS fix
+ rmcModeIndicator = 'D'; // D means differential
+ vtgModeIndicator = 'D'; // D means differential
+ break;
+ } else if (LOC_NAV_MASK_SBAS_CORRECTION_IONO & locationExtended.navSolutionMask){
+ ggaGpsQuality = '2'; // 2 means DGPS fix
+ rmcModeIndicator = 'D'; // D means differential
+ vtgModeIndicator = 'D'; // D means differential
+ break;
+ }
+ }
+ // NOTE: Order of the check is important
+ if (locationExtended.flags & GPS_LOCATION_EXTENDED_HAS_POS_TECH_MASK) {
+ if (LOC_POS_TECH_MASK_SATELLITE & locationExtended.tech_mask){
+ ggaGpsQuality = '1'; // 1 means GPS
+ rmcModeIndicator = 'A'; // A means autonomous
+ vtgModeIndicator = 'A'; // A means autonomous
+ break;
+ } else if (LOC_POS_TECH_MASK_SENSORS & locationExtended.tech_mask){
+ ggaGpsQuality = '6'; // 6 means estimated (dead reckoning)
+ rmcModeIndicator = 'E'; // E means estimated (dead reckoning)
+ vtgModeIndicator = 'E'; // E means estimated (dead reckoning)
+ break;
+ }
+ }
+ } while (0);
+
+ LOC_LOGv("gps quality: %c, rmc mode indicator: %c, vtg mode indicator: %c",
+ ggaGpsQuality, rmcModeIndicator, vtgModeIndicator);
+}
+
+/*===========================================================================
+FUNCTION loc_nmea_generate_pos
+
+DESCRIPTION
+ Generate NMEA sentences generated based on position report
+ Currently below sentences are generated within this function:
+ - $GPGSA : GPS DOP and active SVs
+ - $GLGSA : GLONASS DOP and active SVs
+ - $GAGSA : GALILEO DOP and active SVs
+ - $GNGSA : GNSS DOP and active SVs
+ - $--VTG : Track made good and ground speed
+ - $--RMC : Recommended minimum navigation information
+ - $--GGA : Time, position and fix related data
+
+DEPENDENCIES
+ NONE
+
+RETURN VALUE
+ 0
+
+SIDE EFFECTS
+ N/A
+
+===========================================================================*/
+void loc_nmea_generate_pos(const UlpLocation &location,
+ const GpsLocationExtended &locationExtended,
+ const LocationSystemInfo &systemInfo,
+ unsigned char generate_nmea,
+ std::vector<std::string> &nmeaArraystr)
+{
+ ENTRY_LOG();
+
+ LocGpsUtcTime utcPosTimestamp = 0;
+ bool inLsTransition = false;
+
+ inLsTransition = get_utctime_with_leapsecond_transition
+ (location, locationExtended, systemInfo, utcPosTimestamp);
+
+ time_t utcTime(utcPosTimestamp/1000);
+ tm * pTm = gmtime(&utcTime);
+ if (NULL == pTm) {
+ LOC_LOGE("gmtime failed");
+ return;
+ }
+
+ char sentence[NMEA_SENTENCE_MAX_LENGTH] = {0};
+ char sentence_DTM[NMEA_SENTENCE_MAX_LENGTH] = {0};
+ char sentence_RMC[NMEA_SENTENCE_MAX_LENGTH] = {0};
+ char sentence_GNS[NMEA_SENTENCE_MAX_LENGTH] = {0};
+ char sentence_GGA[NMEA_SENTENCE_MAX_LENGTH] = {0};
+ char* pMarker = sentence;
+ int lengthRemaining = sizeof(sentence);
+ int length = 0;
+ int utcYear = pTm->tm_year % 100; // 2 digit year
+ int utcMonth = pTm->tm_mon + 1; // tm_mon starts at zero
+ int utcDay = pTm->tm_mday;
+ int utcHours = pTm->tm_hour;
+ int utcMinutes = pTm->tm_min;
+ int utcSeconds = pTm->tm_sec;
+ int utcMSeconds = (location.gpsLocation.timestamp)%1000;
+ int datum_type = loc_get_datum_type();
+ LocEcef ecef_w84;
+ LocEcef ecef_p90;
+ LocLla lla_w84;
+ LocLla lla_p90;
+ LocLla ref_lla;
+ LocLla local_lla;
+
+ if (inLsTransition) {
+ // During leap second transition, we need to display the extra
+ // leap second of hour, minute, second as (23:59:60)
+ utcHours = 23;
+ utcMinutes = 59;
+ utcSeconds = 60;
+ // As UTC timestamp is freezing during leap second transition,
+ // retrieve milli-seconds portion from GPS timestamp.
+ utcMSeconds = locationExtended.gpsTime.gpsTimeOfWeekMs % 1000;
+ }
+
+ loc_sv_cache_info sv_cache_info = {};
+
+ if (GPS_LOCATION_EXTENDED_HAS_GNSS_SV_USED_DATA & locationExtended.flags) {
+ sv_cache_info.gps_used_mask =
+ locationExtended.gnss_sv_used_ids.gps_sv_used_ids_mask;
+ sv_cache_info.glo_used_mask =
+ locationExtended.gnss_sv_used_ids.glo_sv_used_ids_mask;
+ sv_cache_info.gal_used_mask =
+ locationExtended.gnss_sv_used_ids.gal_sv_used_ids_mask;
+ sv_cache_info.bds_used_mask =
+ locationExtended.gnss_sv_used_ids.bds_sv_used_ids_mask;
+ sv_cache_info.qzss_used_mask =
+ locationExtended.gnss_sv_used_ids.qzss_sv_used_ids_mask;
+ sv_cache_info.navic_used_mask =
+ locationExtended.gnss_sv_used_ids.navic_sv_used_ids_mask;
+ }
+
+ if (generate_nmea) {
+ char talker[3] = {'G', 'P', '\0'};
+ char modeIndicator[7] = {0};
+ uint32_t svUsedCount = 0;
+ uint32_t count = 0;
+ loc_nmea_sv_meta sv_meta;
+ // -------------------
+ // ---$GPGSA/$GNGSA---
+ // -------------------
+
+ count = loc_nmea_generate_GSA(locationExtended, sentence, sizeof(sentence),
+ loc_nmea_sv_meta_init(sv_meta, sv_cache_info, GNSS_SV_TYPE_GPS,
+ GNSS_SIGNAL_GPS_L1CA, true), nmeaArraystr);
+ if (count > 0)
+ {
+ svUsedCount += count;
+ talker[0] = sv_meta.talker[0];
+ talker[1] = sv_meta.talker[1];
+ }
+
+ // -------------------
+ // ---$GLGSA/$GNGSA---
+ // -------------------
+
+ count = loc_nmea_generate_GSA(locationExtended, sentence, sizeof(sentence),
+ loc_nmea_sv_meta_init(sv_meta, sv_cache_info, GNSS_SV_TYPE_GLONASS,
+ GNSS_SIGNAL_GLONASS_G1, true), nmeaArraystr);
+ if (count > 0)
+ {
+ svUsedCount += count;
+ talker[0] = sv_meta.talker[0];
+ talker[1] = sv_meta.talker[1];
+ }
+
+ // -------------------
+ // ---$GAGSA/$GNGSA---
+ // -------------------
+
+ count = loc_nmea_generate_GSA(locationExtended, sentence, sizeof(sentence),
+ loc_nmea_sv_meta_init(sv_meta, sv_cache_info, GNSS_SV_TYPE_GALILEO,
+ GNSS_SIGNAL_GALILEO_E1, true), nmeaArraystr);
+ if (count > 0)
+ {
+ svUsedCount += count;
+ talker[0] = sv_meta.talker[0];
+ talker[1] = sv_meta.talker[1];
+ }
+
+ // ----------------------------
+ // ---$GBGSA/$GNGSA (BEIDOU)---
+ // ----------------------------
+ count = loc_nmea_generate_GSA(locationExtended, sentence, sizeof(sentence),
+ loc_nmea_sv_meta_init(sv_meta, sv_cache_info, GNSS_SV_TYPE_BEIDOU,
+ GNSS_SIGNAL_BEIDOU_B1I, true), nmeaArraystr);
+ if (count > 0)
+ {
+ svUsedCount += count;
+ talker[0] = sv_meta.talker[0];
+ talker[1] = sv_meta.talker[1];
+ }
+
+ // --------------------------
+ // ---$GQGSA/$GNGSA (QZSS)---
+ // --------------------------
+
+ count = loc_nmea_generate_GSA(locationExtended, sentence, sizeof(sentence),
+ loc_nmea_sv_meta_init(sv_meta, sv_cache_info, GNSS_SV_TYPE_QZSS,
+ GNSS_SIGNAL_QZSS_L1CA, true), nmeaArraystr);
+ if (count > 0)
+ {
+ svUsedCount += count;
+ talker[0] = sv_meta.talker[0];
+ talker[1] = sv_meta.talker[1];
+ }
+
+ char ggaGpsQuality = '0';
+ char rmcModeIndicator = 'N';
+ char vtgModeIndicator = 'N';
+ loc_nmea_get_fix_quality(location, locationExtended,
+ ggaGpsQuality, rmcModeIndicator, vtgModeIndicator);
+
+ // -------------------
+ // ------$--VTG-------
+ // -------------------
+
+ pMarker = sentence;
+ lengthRemaining = sizeof(sentence);
+
+ if (location.gpsLocation.flags & LOC_GPS_LOCATION_HAS_BEARING)
+ {
+ float magTrack = location.gpsLocation.bearing;
+ if (locationExtended.flags & GPS_LOCATION_EXTENDED_HAS_MAG_DEV)
+ {
+ float magTrack = location.gpsLocation.bearing - locationExtended.magneticDeviation;
+ if (magTrack < 0.0)
+ magTrack += 360.0;
+ else if (magTrack > 360.0)
+ magTrack -= 360.0;
+ }
+
+ length = snprintf(pMarker, lengthRemaining, "$%sVTG,%.1lf,T,%.1lf,M,", talker, location.gpsLocation.bearing, magTrack);
+ }
+ else
+ {
+ length = snprintf(pMarker, lengthRemaining, "$%sVTG,,T,,M,", talker);
+ }
+
+ if (length < 0 || length >= lengthRemaining)
+ {
+ LOC_LOGE("NMEA Error in string formatting");
+ return;
+ }
+ pMarker += length;
+ lengthRemaining -= length;
+
+ if (location.gpsLocation.flags & LOC_GPS_LOCATION_HAS_SPEED)
+ {
+ float speedKnots = location.gpsLocation.speed * (3600.0/1852.0);
+ float speedKmPerHour = location.gpsLocation.speed * 3.6;
+
+ length = snprintf(pMarker, lengthRemaining, "%.1lf,N,%.1lf,K,", speedKnots, speedKmPerHour);
+ }
+ else
+ {
+ length = snprintf(pMarker, lengthRemaining, ",N,,K,");
+ }
+
+ if (length < 0 || length >= lengthRemaining)
+ {
+ LOC_LOGE("NMEA Error in string formatting");
+ return;
+ }
+ pMarker += length;
+ lengthRemaining -= length;
+
+ length = snprintf(pMarker, lengthRemaining, "%c", vtgModeIndicator);
+
+ length = loc_nmea_put_checksum(sentence, sizeof(sentence));
+ nmeaArraystr.push_back(sentence);
+
+ memset(&ecef_w84, 0, sizeof(ecef_w84));
+ memset(&ecef_p90, 0, sizeof(ecef_p90));
+ memset(&lla_w84, 0, sizeof(lla_w84));
+ memset(&lla_p90, 0, sizeof(lla_p90));
+ memset(&ref_lla, 0, sizeof(ref_lla));
+ memset(&local_lla, 0, sizeof(local_lla));
+ lla_w84.lat = location.gpsLocation.latitude / 180.0 * M_PI;
+ lla_w84.lon = location.gpsLocation.longitude / 180.0 * M_PI;
+ lla_w84.alt = location.gpsLocation.altitude;
+
+ convert_Lla_to_Ecef(lla_w84, ecef_w84);
+ convert_WGS84_to_PZ90(ecef_w84, ecef_p90);
+ convert_Ecef_to_Lla(ecef_p90, lla_p90);
+
+ switch (datum_type) {
+ case LOC_GNSS_DATUM_WGS84:
+ ref_lla.lat = location.gpsLocation.latitude;
+ ref_lla.lon = location.gpsLocation.longitude;
+ ref_lla.alt = location.gpsLocation.altitude;
+ local_lla.lat = lla_p90.lat / M_PI * 180.0;
+ local_lla.lon = lla_p90.lon / M_PI * 180.0;
+ local_lla.alt = lla_p90.alt;
+ break;
+ case LOC_GNSS_DATUM_PZ90:
+ ref_lla.lat = lla_p90.lat / M_PI * 180.0;
+ ref_lla.lon = lla_p90.lon / M_PI * 180.0;
+ ref_lla.alt = lla_p90.alt;
+ local_lla.lat = location.gpsLocation.latitude;
+ local_lla.lon = location.gpsLocation.longitude;
+ local_lla.alt = location.gpsLocation.altitude;
+ break;
+ default:
+ break;
+ }
+
+ // -------------------
+ // ------$--DTM-------
+ // -------------------
+ loc_nmea_generate_DTM(ref_lla, local_lla, talker, sentence_DTM, sizeof(sentence_DTM));
+
+ // -------------------
+ // ------$--RMC-------
+ // -------------------
+
+ pMarker = sentence_RMC;
+ lengthRemaining = sizeof(sentence_RMC);
+
+ length = snprintf(pMarker, lengthRemaining, "$%sRMC,%02d%02d%02d.%02d,A," ,
+ talker, utcHours, utcMinutes, utcSeconds,utcMSeconds/10);
+
+ if (length < 0 || length >= lengthRemaining)
+ {
+ LOC_LOGE("NMEA Error in string formatting");
+ return;
+ }
+ pMarker += length;
+ lengthRemaining -= length;
+
+ if (location.gpsLocation.flags & LOC_GPS_LOCATION_HAS_LAT_LONG)
+ {
+ double latitude = ref_lla.lat;
+ double longitude = ref_lla.lon;
+ char latHemisphere;
+ char lonHemisphere;
+ double latMinutes;
+ double lonMinutes;
+
+ if (latitude > 0)
+ {
+ latHemisphere = 'N';
+ }
+ else
+ {
+ latHemisphere = 'S';
+ latitude *= -1.0;
+ }
+
+ if (longitude < 0)
+ {
+ lonHemisphere = 'W';
+ longitude *= -1.0;
+ }
+ else
+ {
+ lonHemisphere = 'E';
+ }
+
+ latMinutes = fmod(latitude * 60.0 , 60.0);
+ lonMinutes = fmod(longitude * 60.0 , 60.0);
+
+ length = snprintf(pMarker, lengthRemaining, "%02d%09.6lf,%c,%03d%09.6lf,%c,",
+ (uint8_t)floor(latitude), latMinutes, latHemisphere,
+ (uint8_t)floor(longitude),lonMinutes, lonHemisphere);
+ }
+ else
+ {
+ length = snprintf(pMarker, lengthRemaining,",,,,");
+ }
+
+ if (length < 0 || length >= lengthRemaining)
+ {
+ LOC_LOGE("NMEA Error in string formatting");
+ return;
+ }
+ pMarker += length;
+ lengthRemaining -= length;
+
+ if (location.gpsLocation.flags & LOC_GPS_LOCATION_HAS_SPEED)
+ {
+ float speedKnots = location.gpsLocation.speed * (3600.0/1852.0);
+ length = snprintf(pMarker, lengthRemaining, "%.1lf,", speedKnots);
+ }
+ else
+ {
+ length = snprintf(pMarker, lengthRemaining, ",");
+ }
+
+ if (length < 0 || length >= lengthRemaining)
+ {
+ LOC_LOGE("NMEA Error in string formatting");
+ return;
+ }
+ pMarker += length;
+ lengthRemaining -= length;
+
+ if (location.gpsLocation.flags & LOC_GPS_LOCATION_HAS_BEARING)
+ {
+ length = snprintf(pMarker, lengthRemaining, "%.1lf,", location.gpsLocation.bearing);
+ }
+ else
+ {
+ length = snprintf(pMarker, lengthRemaining, ",");
+ }
+
+ if (length < 0 || length >= lengthRemaining)
+ {
+ LOC_LOGE("NMEA Error in string formatting");
+ return;
+ }
+ pMarker += length;
+ lengthRemaining -= length;
+
+ length = snprintf(pMarker, lengthRemaining, "%2.2d%2.2d%2.2d,",
+ utcDay, utcMonth, utcYear);
+
+ if (length < 0 || length >= lengthRemaining)
+ {
+ LOC_LOGE("NMEA Error in string formatting");
+ return;
+ }
+ pMarker += length;
+ lengthRemaining -= length;
+
+ if (locationExtended.flags & GPS_LOCATION_EXTENDED_HAS_MAG_DEV)
+ {
+ float magneticVariation = locationExtended.magneticDeviation;
+ char direction;
+ if (magneticVariation < 0.0)
+ {
+ direction = 'W';
+ magneticVariation *= -1.0;
+ }
+ else
+ {
+ direction = 'E';
+ }
+
+ length = snprintf(pMarker, lengthRemaining, "%.1lf,%c,",
+ magneticVariation, direction);
+ }
+ else
+ {
+ length = snprintf(pMarker, lengthRemaining, ",,");
+ }
+
+ if (length < 0 || length >= lengthRemaining)
+ {
+ LOC_LOGE("NMEA Error in string formatting");
+ return;
+ }
+ pMarker += length;
+ lengthRemaining -= length;
+
+ length = snprintf(pMarker, lengthRemaining, "%c", rmcModeIndicator);
+ pMarker += length;
+ lengthRemaining -= length;
+
+ // hardcode Navigation Status field to 'V'
+ length = snprintf(pMarker, lengthRemaining, ",%c", 'V');
+ pMarker += length;
+ lengthRemaining -= length;
+
+ length = loc_nmea_put_checksum(sentence_RMC, sizeof(sentence_RMC));
+
+ // -------------------
+ // ------$--GNS-------
+ // -------------------
+
+ pMarker = sentence_GNS;
+ lengthRemaining = sizeof(sentence_GNS);
+
+ length = snprintf(pMarker, lengthRemaining, "$%sGNS,%02d%02d%02d.%02d," ,
+ talker, utcHours, utcMinutes, utcSeconds, utcMSeconds/10);
+
+ if (length < 0 || length >= lengthRemaining)
+ {
+ LOC_LOGE("NMEA Error in string formatting");
+ return;
+ }
+ pMarker += length;
+ lengthRemaining -= length;
+
+ if (location.gpsLocation.flags & LOC_GPS_LOCATION_HAS_LAT_LONG)
+ {
+ double latitude = ref_lla.lat;
+ double longitude = ref_lla.lon;
+ char latHemisphere;
+ char lonHemisphere;
+ double latMinutes;
+ double lonMinutes;
+
+ if (latitude > 0)
+ {
+ latHemisphere = 'N';
+ }
+ else
+ {
+ latHemisphere = 'S';
+ latitude *= -1.0;
+ }
+
+ if (longitude < 0)
+ {
+ lonHemisphere = 'W';
+ longitude *= -1.0;
+ }
+ else
+ {
+ lonHemisphere = 'E';
+ }
+
+ latMinutes = fmod(latitude * 60.0 , 60.0);
+ lonMinutes = fmod(longitude * 60.0 , 60.0);
+
+ length = snprintf(pMarker, lengthRemaining, "%02d%09.6lf,%c,%03d%09.6lf,%c,",
+ (uint8_t)floor(latitude), latMinutes, latHemisphere,
+ (uint8_t)floor(longitude),lonMinutes, lonHemisphere);
+ }
+ else
+ {
+ length = snprintf(pMarker, lengthRemaining,",,,,");
+ }
+
+ if (length < 0 || length >= lengthRemaining)
+ {
+ LOC_LOGE("NMEA Error in string formatting");
+ return;
+ }
+ pMarker += length;
+ lengthRemaining -= length;
+
+ if(!(sv_cache_info.gps_used_mask ? 1 : 0))
+ modeIndicator[0] = 'N';
+ else if (LOC_NAV_MASK_SBAS_CORRECTION_IONO & locationExtended.navSolutionMask)
+ modeIndicator[0] = 'D';
+ else if (LOC_POS_TECH_MASK_SENSORS == locationExtended.tech_mask)
+ modeIndicator[0] = 'E';
+ else
+ modeIndicator[0] = 'A';
+ if(!(sv_cache_info.glo_used_mask ? 1 : 0))
+ modeIndicator[1] = 'N';
+ else if (LOC_POS_TECH_MASK_SENSORS == locationExtended.tech_mask)
+ modeIndicator[1] = 'E';
+ else
+ modeIndicator[1] = 'A';
+ if(!(sv_cache_info.gal_used_mask ? 1 : 0))
+ modeIndicator[2] = 'N';
+ else if (LOC_POS_TECH_MASK_SENSORS == locationExtended.tech_mask)
+ modeIndicator[2] = 'E';
+ else
+ modeIndicator[2] = 'A';
+ if(!(sv_cache_info.bds_used_mask ? 1 : 0))
+ modeIndicator[3] = 'N';
+ else if (LOC_POS_TECH_MASK_SENSORS == locationExtended.tech_mask)
+ modeIndicator[3] = 'E';
+ else
+ modeIndicator[3] = 'A';
+ if(!(sv_cache_info.qzss_used_mask ? 1 : 0))
+ modeIndicator[4] = 'N';
+ else if (LOC_POS_TECH_MASK_SENSORS == locationExtended.tech_mask)
+ modeIndicator[4] = 'E';
+ else
+ modeIndicator[4] = 'A';
+ if(!(sv_cache_info.navic_used_mask ? 1 : 0))
+ modeIndicator[5] = 'N';
+ else if (LOC_POS_TECH_MASK_SENSORS == locationExtended.tech_mask)
+ modeIndicator[5] = 'E';
+ else
+ modeIndicator[5] = 'A';
+ modeIndicator[6] = '\0';
+ for(int index = 5; index > 0 && 'N' == modeIndicator[index]; index--) {
+ modeIndicator[index] = '\0';
+ }
+ length = snprintf(pMarker, lengthRemaining,"%s,", modeIndicator);
+
+ pMarker += length;
+ lengthRemaining -= length;
+
+ if (locationExtended.flags & GPS_LOCATION_EXTENDED_HAS_DOP) {
+ length = snprintf(pMarker, lengthRemaining, "%02d,%.1f,",
+ svUsedCount, locationExtended.hdop);
+ }
+ else { // no hdop
+ length = snprintf(pMarker, lengthRemaining, "%02d,,",
+ svUsedCount);
+ }
+
+ if (length < 0 || length >= lengthRemaining)
+ {
+ LOC_LOGE("NMEA Error in string formatting");
+ return;
+ }
+ pMarker += length;
+ lengthRemaining -= length;
+
+ if (locationExtended.flags & GPS_LOCATION_EXTENDED_HAS_ALTITUDE_MEAN_SEA_LEVEL)
+ {
+ length = snprintf(pMarker, lengthRemaining, "%.1lf,",
+ locationExtended.altitudeMeanSeaLevel);
+ }
+ else
+ {
+ length = snprintf(pMarker, lengthRemaining,",");
+ }
+
+ if (length < 0 || length >= lengthRemaining)
+ {
+ LOC_LOGE("NMEA Error in string formatting");
+ return;
+ }
+ pMarker += length;
+ lengthRemaining -= length;
+
+ if ((location.gpsLocation.flags & LOC_GPS_LOCATION_HAS_ALTITUDE) &&
+ (locationExtended.flags & GPS_LOCATION_EXTENDED_HAS_ALTITUDE_MEAN_SEA_LEVEL))
+ {
+ length = snprintf(pMarker, lengthRemaining, "%.1lf,,",
+ ref_lla.alt - locationExtended.altitudeMeanSeaLevel);
+ }
+ else
+ {
+ length = snprintf(pMarker, lengthRemaining,",,");
+ }
+
+ pMarker += length;
+ lengthRemaining -= length;
+
+ // hardcode Navigation Status field to 'V'
+ length = snprintf(pMarker, lengthRemaining, ",%c", 'V');
+ pMarker += length;
+ lengthRemaining -= length;
+
+ length = loc_nmea_put_checksum(sentence_GNS, sizeof(sentence_GNS));
+
+
+ // -------------------
+ // ------$--GGA-------
+ // -------------------
+
+ pMarker = sentence_GGA;
+ lengthRemaining = sizeof(sentence_GGA);
+
+ length = snprintf(pMarker, lengthRemaining, "$%sGGA,%02d%02d%02d.%02d," ,
+ talker, utcHours, utcMinutes, utcSeconds, utcMSeconds/10);
+
+ if (length < 0 || length >= lengthRemaining)
+ {
+ LOC_LOGE("NMEA Error in string formatting");
+ return;
+ }
+ pMarker += length;
+ lengthRemaining -= length;
+
+ if (location.gpsLocation.flags & LOC_GPS_LOCATION_HAS_LAT_LONG)
+ {
+ double latitude = ref_lla.lat;
+ double longitude = ref_lla.lon;
+ char latHemisphere;
+ char lonHemisphere;
+ double latMinutes;
+ double lonMinutes;
+
+ if (latitude > 0)
+ {
+ latHemisphere = 'N';
+ }
+ else
+ {
+ latHemisphere = 'S';
+ latitude *= -1.0;
+ }
+
+ if (longitude < 0)
+ {
+ lonHemisphere = 'W';
+ longitude *= -1.0;
+ }
+ else
+ {
+ lonHemisphere = 'E';
+ }
+
+ latMinutes = fmod(latitude * 60.0 , 60.0);
+ lonMinutes = fmod(longitude * 60.0 , 60.0);
+
+ length = snprintf(pMarker, lengthRemaining, "%02d%09.6lf,%c,%03d%09.6lf,%c,",
+ (uint8_t)floor(latitude), latMinutes, latHemisphere,
+ (uint8_t)floor(longitude),lonMinutes, lonHemisphere);
+ }
+ else
+ {
+ length = snprintf(pMarker, lengthRemaining,",,,,");
+ }
+
+ if (length < 0 || length >= lengthRemaining)
+ {
+ LOC_LOGE("NMEA Error in string formatting");
+ return;
+ }
+ pMarker += length;
+ lengthRemaining -= length;
+
+ // Number of satellites in use, 00-12
+ if (svUsedCount > MAX_SATELLITES_IN_USE)
+ svUsedCount = MAX_SATELLITES_IN_USE;
+ if (locationExtended.flags & GPS_LOCATION_EXTENDED_HAS_DOP)
+ {
+ length = snprintf(pMarker, lengthRemaining, "%c,%02d,%.1f,",
+ ggaGpsQuality, svUsedCount, locationExtended.hdop);
+ }
+ else
+ { // no hdop
+ length = snprintf(pMarker, lengthRemaining, "%c,%02d,,",
+ ggaGpsQuality, svUsedCount);
+ }
+
+ if (length < 0 || length >= lengthRemaining)
+ {
+ LOC_LOGE("NMEA Error in string formatting");
+ return;
+ }
+ pMarker += length;
+ lengthRemaining -= length;
+
+ if (locationExtended.flags & GPS_LOCATION_EXTENDED_HAS_ALTITUDE_MEAN_SEA_LEVEL)
+ {
+ length = snprintf(pMarker, lengthRemaining, "%.1lf,M,",
+ locationExtended.altitudeMeanSeaLevel);
+ }
+ else
+ {
+ length = snprintf(pMarker, lengthRemaining,",,");
+ }
+
+ if (length < 0 || length >= lengthRemaining)
+ {
+ LOC_LOGE("NMEA Error in string formatting");
+ return;
+ }
+ pMarker += length;
+ lengthRemaining -= length;
+
+ if ((location.gpsLocation.flags & LOC_GPS_LOCATION_HAS_ALTITUDE) &&
+ (locationExtended.flags & GPS_LOCATION_EXTENDED_HAS_ALTITUDE_MEAN_SEA_LEVEL))
+ {
+ length = snprintf(pMarker, lengthRemaining, "%.1lf,M,,",
+ ref_lla.alt - locationExtended.altitudeMeanSeaLevel);
+ }
+ else
+ {
+ length = snprintf(pMarker, lengthRemaining,",,,");
+ }
+
+ length = loc_nmea_put_checksum(sentence_GGA, sizeof(sentence_GGA));
+
+ // ------$--DTM-------
+ nmeaArraystr.push_back(sentence_DTM);
+ // ------$--RMC-------
+ nmeaArraystr.push_back(sentence_RMC);
+ if(LOC_GNSS_DATUM_PZ90 == datum_type) {
+ // ------$--DTM-------
+ nmeaArraystr.push_back(sentence_DTM);
+ }
+ // ------$--GNS-------
+ nmeaArraystr.push_back(sentence_GNS);
+ if(LOC_GNSS_DATUM_PZ90 == datum_type) {
+ // ------$--DTM-------
+ nmeaArraystr.push_back(sentence_DTM);
+ }
+ // ------$--GGA-------
+ nmeaArraystr.push_back(sentence_GGA);
+
+ }
+ //Send blank NMEA reports for non-final fixes
+ else {
+ strlcpy(sentence, "$GPGSA,A,1,,,,,,,,,,,,,,,,", sizeof(sentence));
+ length = loc_nmea_put_checksum(sentence, sizeof(sentence));
+ nmeaArraystr.push_back(sentence);
+
+ strlcpy(sentence, "$GPVTG,,T,,M,,N,,K,N", sizeof(sentence));
+ length = loc_nmea_put_checksum(sentence, sizeof(sentence));
+ nmeaArraystr.push_back(sentence);
+
+ strlcpy(sentence, "$GPDTM,,,,,,,,", sizeof(sentence));
+ length = loc_nmea_put_checksum(sentence, sizeof(sentence));
+ nmeaArraystr.push_back(sentence);
+
+ strlcpy(sentence, "$GPRMC,,V,,,,,,,,,,N,V", sizeof(sentence));
+ length = loc_nmea_put_checksum(sentence, sizeof(sentence));
+ nmeaArraystr.push_back(sentence);
+
+ strlcpy(sentence, "$GPGNS,,,,,,N,,,,,,,V", sizeof(sentence));
+ length = loc_nmea_put_checksum(sentence, sizeof(sentence));
+ nmeaArraystr.push_back(sentence);
+
+ strlcpy(sentence, "$GPGGA,,,,,,0,,,,,,,,", sizeof(sentence));
+ length = loc_nmea_put_checksum(sentence, sizeof(sentence));
+ nmeaArraystr.push_back(sentence);
+ }
+
+ EXIT_LOG(%d, 0);
+}
+
+
+
+/*===========================================================================
+FUNCTION loc_nmea_generate_sv
+
+DESCRIPTION
+ Generate NMEA sentences generated based on sv report
+
+DEPENDENCIES
+ NONE
+
+RETURN VALUE
+ 0
+
+SIDE EFFECTS
+ N/A
+
+===========================================================================*/
+void loc_nmea_generate_sv(const GnssSvNotification &svNotify,
+ std::vector<std::string> &nmeaArraystr)
+{
+ ENTRY_LOG();
+
+ char sentence[NMEA_SENTENCE_MAX_LENGTH] = {0};
+ int svCount = svNotify.count;
+ int svNumber = 1;
+ loc_sv_cache_info sv_cache_info = {};
+
+ //Count GPS SVs for saparating GPS from GLONASS and throw others
+ for(svNumber=1; svNumber <= svCount; svNumber++) {
+ if (GNSS_SV_TYPE_GPS == svNotify.gnssSvs[svNumber - 1].type)
+ {
+ // cache the used in fix mask, as it will be needed to send $GPGSA
+ // during the position report
+ if (GNSS_SV_OPTIONS_USED_IN_FIX_BIT ==
+ (svNotify.gnssSvs[svNumber - 1].gnssSvOptionsMask &
+ GNSS_SV_OPTIONS_USED_IN_FIX_BIT))
+ {
+ sv_cache_info.gps_used_mask |= (1 << (svNotify.gnssSvs[svNumber - 1].svId - 1));
+ }
+ if (GNSS_SIGNAL_GPS_L5 == svNotify.gnssSvs[svNumber - 1].gnssSignalTypeMask) {
+ sv_cache_info.gps_l5_count++;
+ } else {
+ // GNSS_SIGNAL_GPS_L1CA or default
+ // If no signal type in report, it means default L1
+ sv_cache_info.gps_l1_count++;
+ }
+ }
+ else if (GNSS_SV_TYPE_GLONASS == svNotify.gnssSvs[svNumber - 1].type)
+ {
+ // cache the used in fix mask, as it will be needed to send $GNGSA
+ // during the position report
+ if (GNSS_SV_OPTIONS_USED_IN_FIX_BIT ==
+ (svNotify.gnssSvs[svNumber - 1].gnssSvOptionsMask &
+ GNSS_SV_OPTIONS_USED_IN_FIX_BIT))
+ {
+ sv_cache_info.glo_used_mask |= (1 << (svNotify.gnssSvs[svNumber - 1].svId - 1));
+ }
+ if (GNSS_SIGNAL_GLONASS_G2 == svNotify.gnssSvs[svNumber - 1].gnssSignalTypeMask){
+ sv_cache_info.glo_g2_count++;
+ } else {
+ // GNSS_SIGNAL_GLONASS_G1 or default
+ // If no signal type in report, it means default G1
+ sv_cache_info.glo_g1_count++;
+ }
+ }
+ else if (GNSS_SV_TYPE_GALILEO == svNotify.gnssSvs[svNumber - 1].type)
+ {
+ // cache the used in fix mask, as it will be needed to send $GAGSA
+ // during the position report
+ if (GNSS_SV_OPTIONS_USED_IN_FIX_BIT ==
+ (svNotify.gnssSvs[svNumber - 1].gnssSvOptionsMask &
+ GNSS_SV_OPTIONS_USED_IN_FIX_BIT))
+ {
+ sv_cache_info.gal_used_mask |= (1 << (svNotify.gnssSvs[svNumber - 1].svId - 1));
+ }
+ if(GNSS_SIGNAL_GALILEO_E5A == svNotify.gnssSvs[svNumber - 1].gnssSignalTypeMask){
+ sv_cache_info.gal_e5_count++;
+ } else {
+ // GNSS_SIGNAL_GALILEO_E1 or default
+ // If no signal type in report, it means default E1
+ sv_cache_info.gal_e1_count++;
+ }
+ }
+ else if (GNSS_SV_TYPE_QZSS == svNotify.gnssSvs[svNumber - 1].type)
+ {
+ // cache the used in fix mask, as it will be needed to send $PQGSA
+ // during the position report
+ if (GNSS_SV_OPTIONS_USED_IN_FIX_BIT ==
+ (svNotify.gnssSvs[svNumber - 1].gnssSvOptionsMask &
+ GNSS_SV_OPTIONS_USED_IN_FIX_BIT))
+ {
+ sv_cache_info.qzss_used_mask |= (1 << (svNotify.gnssSvs[svNumber - 1].svId - 1));
+ }
+ if (GNSS_SIGNAL_QZSS_L5 == svNotify.gnssSvs[svNumber - 1].gnssSignalTypeMask) {
+ sv_cache_info.qzss_l5_count++;
+ } else {
+ // GNSS_SIGNAL_QZSS_L1CA or default
+ // If no signal type in report, it means default L1
+ sv_cache_info.qzss_l1_count++;
+ }
+ }
+ else if (GNSS_SV_TYPE_BEIDOU == svNotify.gnssSvs[svNumber - 1].type)
+ {
+ // cache the used in fix mask, as it will be needed to send $PQGSA
+ // during the position report
+ if (GNSS_SV_OPTIONS_USED_IN_FIX_BIT ==
+ (svNotify.gnssSvs[svNumber - 1].gnssSvOptionsMask &
+ GNSS_SV_OPTIONS_USED_IN_FIX_BIT))
+ {
+ sv_cache_info.bds_used_mask |= (1 << (svNotify.gnssSvs[svNumber - 1].svId - 1));
+ }
+ if(GNSS_SIGNAL_BEIDOU_B2AI == svNotify.gnssSvs[svNumber - 1].gnssSignalTypeMask){
+ sv_cache_info.bds_b2_count++;
+ } else {
+ // GNSS_SIGNAL_BEIDOU_B1I or default
+ // If no signal type in report, it means default B1I
+ sv_cache_info.bds_b1_count++;
+ }
+ }
+ else if (GNSS_SV_TYPE_NAVIC == svNotify.gnssSvs[svNumber - 1].type)
+ {
+ // cache the used in fix mask, as it will be needed to send $PQGSA
+ // during the position report
+ if (GNSS_SV_OPTIONS_USED_IN_FIX_BIT ==
+ (svNotify.gnssSvs[svNumber - 1].gnssSvOptionsMask &
+ GNSS_SV_OPTIONS_USED_IN_FIX_BIT))
+ {
+ sv_cache_info.navic_used_mask |= (1 << (svNotify.gnssSvs[svNumber - 1].svId - 1));
+ }
+ // GNSS_SIGNAL_NAVIC_L5 is the only signal type for NAVIC
+ sv_cache_info.navic_l5_count++;
+ }
+ }
+
+ loc_nmea_sv_meta sv_meta;
+ // ---------------------
+ // ------$GPGSV:L1CA----
+ // ---------------------
+
+ loc_nmea_generate_GSV(svNotify, sentence, sizeof(sentence),
+ loc_nmea_sv_meta_init(sv_meta, sv_cache_info, GNSS_SV_TYPE_GPS,
+ GNSS_SIGNAL_GPS_L1CA, false), nmeaArraystr);
+
+ // ---------------------
+ // ------$GPGSV:L5------
+ // ---------------------
+
+ loc_nmea_generate_GSV(svNotify, sentence, sizeof(sentence),
+ loc_nmea_sv_meta_init(sv_meta, sv_cache_info, GNSS_SV_TYPE_GPS,
+ GNSS_SIGNAL_GPS_L5, false), nmeaArraystr);
+ // ---------------------
+ // ------$GLGSV:G1------
+ // ---------------------
+
+ loc_nmea_generate_GSV(svNotify, sentence, sizeof(sentence),
+ loc_nmea_sv_meta_init(sv_meta, sv_cache_info, GNSS_SV_TYPE_GLONASS,
+ GNSS_SIGNAL_GLONASS_G1, false), nmeaArraystr);
+
+ // ---------------------
+ // ------$GLGSV:G2------
+ // ---------------------
+
+ loc_nmea_generate_GSV(svNotify, sentence, sizeof(sentence),
+ loc_nmea_sv_meta_init(sv_meta, sv_cache_info, GNSS_SV_TYPE_GLONASS,
+ GNSS_SIGNAL_GLONASS_G2, false), nmeaArraystr);
+
+ // ---------------------
+ // ------$GAGSV:E1------
+ // ---------------------
+
+ loc_nmea_generate_GSV(svNotify, sentence, sizeof(sentence),
+ loc_nmea_sv_meta_init(sv_meta, sv_cache_info, GNSS_SV_TYPE_GALILEO,
+ GNSS_SIGNAL_GALILEO_E1, false), nmeaArraystr);
+
+ // -------------------------
+ // ------$GAGSV:E5A---------
+ // -------------------------
+ loc_nmea_generate_GSV(svNotify, sentence, sizeof(sentence),
+ loc_nmea_sv_meta_init(sv_meta, sv_cache_info, GNSS_SV_TYPE_GALILEO,
+ GNSS_SIGNAL_GALILEO_E5A, false), nmeaArraystr);
+
+ // -----------------------------
+ // ------$PQGSV (QZSS):L1CA-----
+ // -----------------------------
+
+ loc_nmea_generate_GSV(svNotify, sentence, sizeof(sentence),
+ loc_nmea_sv_meta_init(sv_meta, sv_cache_info, GNSS_SV_TYPE_QZSS,
+ GNSS_SIGNAL_QZSS_L1CA, false), nmeaArraystr);
+
+ // -----------------------------
+ // ------$PQGSV (QZSS):L5-------
+ // -----------------------------
+
+ loc_nmea_generate_GSV(svNotify, sentence, sizeof(sentence),
+ loc_nmea_sv_meta_init(sv_meta, sv_cache_info, GNSS_SV_TYPE_QZSS,
+ GNSS_SIGNAL_QZSS_L5, false), nmeaArraystr);
+ // -----------------------------
+ // ------$PQGSV (BEIDOU:B1I)----
+ // -----------------------------
+
+ loc_nmea_generate_GSV(svNotify, sentence, sizeof(sentence),
+ loc_nmea_sv_meta_init(sv_meta, sv_cache_info, GNSS_SV_TYPE_BEIDOU,
+ GNSS_SIGNAL_BEIDOU_B1I,false), nmeaArraystr);
+
+ // -----------------------------
+ // ------$PQGSV (BEIDOU:B2AI)---
+ // -----------------------------
+
+ loc_nmea_generate_GSV(svNotify, sentence, sizeof(sentence),
+ loc_nmea_sv_meta_init(sv_meta, sv_cache_info, GNSS_SV_TYPE_BEIDOU,
+ GNSS_SIGNAL_BEIDOU_B2AI,false), nmeaArraystr);
+
+ // -----------------------------
+ // ------$GIGSV (NAVIC:L5)------
+ // -----------------------------
+
+ loc_nmea_generate_GSV(svNotify, sentence, sizeof(sentence),
+ loc_nmea_sv_meta_init(sv_meta, sv_cache_info, GNSS_SV_TYPE_NAVIC,
+ GNSS_SIGNAL_NAVIC_L5,false), nmeaArraystr);
+
+ EXIT_LOG(%d, 0);
+}
diff --git a/utils/loc_nmea.h b/utils/loc_nmea.h
new file mode 100644
index 0000000..c6c83db
--- /dev/null
+++ b/utils/loc_nmea.h
@@ -0,0 +1,92 @@
+/* Copyright (c) 2012-2013, 2015-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 LOC_ENG_NMEA_H
+#define LOC_ENG_NMEA_H
+
+#include <gps_extended.h>
+#include <vector>
+#include <string>
+#define NMEA_SENTENCE_MAX_LENGTH 200
+
+/** gnss datum type */
+#define LOC_GNSS_DATUM_WGS84 0
+#define LOC_GNSS_DATUM_PZ90 1
+
+/* len of semi major axis of ref ellips*/
+#define MAJA (6378137.0)
+/* flattening coef of ref ellipsoid*/
+#define FLAT (1.0/298.2572235630)
+/* 1st eccentricity squared*/
+#define ESQR (FLAT*(2.0 - FLAT))
+/*1 minus eccentricity squared*/
+#define OMES (1.0 - ESQR)
+#define MILARCSEC2RAD (4.848136811095361e-09)
+/*semi major axis */
+#define C_PZ90A (6378136.0)
+/*semi minor axis */
+#define C_PZ90B (6356751.3618)
+/* Transformation from WGS84 to PZ90
+ * Cx,Cy,Cz,Rs,Rx,Ry,Rz,C_SYS_A,C_SYS_B*/
+const double DatumConstFromWGS84[9] =
+ {+0.003, +0.001, 0.000, (1.0+(0.000*1E-6)), (-0.019*MILARCSEC2RAD),
+ (+0.042*MILARCSEC2RAD), (-0.002*MILARCSEC2RAD), C_PZ90A, C_PZ90B};
+
+/** Represents a LTP*/
+typedef struct {
+ double lat;
+ double lon;
+ double alt;
+} LocLla;
+
+/** Represents a ECEF*/
+typedef struct {
+ double X;
+ double Y;
+ double Z;
+} LocEcef;
+
+void loc_nmea_generate_sv(const GnssSvNotification &svNotify,
+ std::vector<std::string> &nmeaArraystr);
+
+void loc_nmea_generate_pos(const UlpLocation &location,
+ const GpsLocationExtended &locationExtended,
+ const LocationSystemInfo &systemInfo,
+ unsigned char generate_nmea,
+ std::vector<std::string> &nmeaArraystr);
+
+#define DEBUG_NMEA_MINSIZE 6
+#define DEBUG_NMEA_MAXSIZE 4096
+inline bool loc_nmea_is_debug(const char* nmea, int length) {
+ return ((nullptr != nmea) &&
+ (length >= DEBUG_NMEA_MINSIZE) && (length <= DEBUG_NMEA_MAXSIZE) &&
+ (nmea[0] == '$') && (nmea[1] == 'P') && (nmea[2] == 'Q') && (nmea[3] == 'W'));
+}
+
+#endif // LOC_ENG_NMEA_H
diff --git a/utils/loc_target.cpp b/utils/loc_target.cpp
new file mode 100644
index 0000000..f6fd728
--- /dev/null
+++ b/utils/loc_target.cpp
@@ -0,0 +1,210 @@
+/* Copyright (c) 2012-2015, 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.
+ *
+ */
+
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <log_util.h>
+#include "loc_target.h"
+#include "loc_log.h"
+#include <loc_pla.h>
+
+#define APQ8064_ID_1 "109"
+#define APQ8064_ID_2 "153"
+#define MPQ8064_ID_1 "130"
+#define MSM8930_ID_1 "142"
+#define MSM8930_ID_2 "116"
+#define APQ8030_ID_1 "157"
+#define APQ8074_ID_1 "184"
+
+#define LINE_LEN 100
+#define STR_LIQUID "Liquid"
+#define STR_SURF "Surf"
+#define STR_MTP "MTP"
+#define STR_APQ "apq"
+#define STR_SDC "sdc" // alternative string for APQ targets
+#define STR_QCS "qcs" // string for Gen9 APQ targets
+#define STR_MSM "msm"
+#define STR_SDM "sdm" // alternative string for MSM targets
+#define STR_APQ_NO_WGR "baseband_apq_nowgr"
+#define STR_AUTO "auto"
+#define IS_STR_END(c) ((c) == '\0' || (c) == '\n' || (c) == '\r')
+#define LENGTH(s) (sizeof(s) - 1)
+#define GPS_CHECK_NO_ERROR 0
+#define GPS_CHECK_NO_GPS_HW 1
+
+static unsigned int gTarget = (unsigned int)-1;
+
+static int read_a_line(const char * file_path, char * line, int line_size)
+{
+ FILE *fp;
+ int result = 0;
+
+ * line = '\0';
+ fp = fopen(file_path, "r" );
+ if( fp == NULL ) {
+ LOC_LOGE("open failed: %s: %s\n", file_path, strerror(errno));
+ result = -1;
+ } else {
+ int len;
+ fgets(line, line_size, fp);
+ len = strlen(line);
+ len = len < line_size - 1? len : line_size - 1;
+ line[len] = '\0';
+ LOC_LOGD("cat %s: %s", file_path, line);
+ fclose(fp);
+ }
+ return result;
+}
+
+/*The character array passed to this function should have length
+ of atleast PROPERTY_VALUE_MAX*/
+void loc_get_target_baseband(char *baseband, int array_length)
+{
+ if(baseband && (array_length >= PROPERTY_VALUE_MAX)) {
+ property_get("ro.baseband", baseband, "");
+ LOC_LOGD("%s:%d]: Baseband: %s\n", __func__, __LINE__, baseband);
+ }
+ else {
+ LOC_LOGE("%s:%d]: NULL parameter or array length less than PROPERTY_VALUE_MAX\n",
+ __func__, __LINE__);
+ }
+}
+
+/*The character array passed to this function should have length
+ of atleast PROPERTY_VALUE_MAX*/
+void loc_get_platform_name(char *platform_name, int array_length)
+{
+ if(platform_name && (array_length >= PROPERTY_VALUE_MAX)) {
+ property_get("ro.board.platform", platform_name, "");
+ LOC_LOGD("%s:%d]: Target name: %s\n", __func__, __LINE__, platform_name);
+ }
+ else {
+ LOC_LOGE("%s:%d]: Null parameter or array length less than PROPERTY_VALUE_MAX\n",
+ __func__, __LINE__);
+ }
+}
+
+/*The character array passed to this function should have length
+ of atleast PROPERTY_VALUE_MAX*/
+void loc_get_auto_platform_name(char *platform_name, int array_length)
+{
+ if(platform_name && (array_length >= PROPERTY_VALUE_MAX)) {
+ property_get("ro.hardware.type", platform_name, "");
+ LOC_LOGD("%s:%d]: Autoplatform name: %s\n", __func__, __LINE__, platform_name);
+ }
+ else {
+ LOC_LOGE("%s:%d]: Null parameter or array length less than PROPERTY_VALUE_MAX\n",
+ __func__, __LINE__);
+ }
+}
+
+unsigned int loc_get_target(void)
+{
+ if (gTarget != (unsigned int)-1)
+ return gTarget;
+
+ static const char hw_platform[] = "/sys/devices/soc0/hw_platform";
+ static const char id[] = "/sys/devices/soc0/soc_id";
+ static const char hw_platform_dep[] =
+ "/sys/devices/system/soc/soc0/hw_platform";
+ static const char id_dep[] = "/sys/devices/system/soc/soc0/id";
+ static const char mdm[] = "/target"; // mdm target we are using
+
+ char rd_hw_platform[LINE_LEN];
+ char rd_id[LINE_LEN];
+ char rd_mdm[LINE_LEN];
+ char baseband[LINE_LEN];
+ char rd_auto_platform[LINE_LEN];
+
+ loc_get_target_baseband(baseband, sizeof(baseband));
+
+ if (!access(hw_platform, F_OK)) {
+ read_a_line(hw_platform, rd_hw_platform, LINE_LEN);
+ } else {
+ read_a_line(hw_platform_dep, rd_hw_platform, LINE_LEN);
+ }
+ if (!access(id, F_OK)) {
+ read_a_line(id, rd_id, LINE_LEN);
+ } else {
+ read_a_line(id_dep, rd_id, LINE_LEN);
+ }
+
+ /*check automotive platform*/
+ loc_get_auto_platform_name(rd_auto_platform, sizeof(rd_auto_platform));
+ if( !memcmp(rd_auto_platform, STR_AUTO, LENGTH(STR_AUTO)) )
+ {
+ gTarget = TARGET_AUTO;
+ goto detected;
+ }
+
+ if( !memcmp(baseband, STR_APQ_NO_WGR, LENGTH(STR_APQ_NO_WGR)) ){
+
+ gTarget = TARGET_NO_GNSS;
+ goto detected;
+ }
+
+ if( !memcmp(baseband, STR_APQ, LENGTH(STR_APQ)) ||
+ !memcmp(baseband, STR_SDC, LENGTH(STR_SDC)) ||
+ !memcmp(baseband, STR_QCS, LENGTH(STR_QCS)) ) {
+
+ if( !memcmp(rd_id, MPQ8064_ID_1, LENGTH(MPQ8064_ID_1))
+ && IS_STR_END(rd_id[LENGTH(MPQ8064_ID_1)]) )
+ gTarget = TARGET_NO_GNSS;
+ else
+ gTarget = TARGET_APQ_SA;
+ } else if (((!memcmp(rd_hw_platform, STR_LIQUID, LENGTH(STR_LIQUID))
+ && IS_STR_END(rd_hw_platform[LENGTH(STR_LIQUID)])) ||
+ (!memcmp(rd_hw_platform, STR_SURF, LENGTH(STR_SURF))
+ && IS_STR_END(rd_hw_platform[LENGTH(STR_SURF)])) ||
+ (!memcmp(rd_hw_platform, STR_MTP, LENGTH(STR_MTP))
+ && IS_STR_END(rd_hw_platform[LENGTH(STR_MTP)]))) &&
+ !read_a_line( mdm, rd_mdm, LINE_LEN)) {
+ gTarget = TARGET_MDM;
+ } else if( (!memcmp(rd_id, MSM8930_ID_1, LENGTH(MSM8930_ID_1))
+ && IS_STR_END(rd_id[LENGTH(MSM8930_ID_1)])) ||
+ (!memcmp(rd_id, MSM8930_ID_2, LENGTH(MSM8930_ID_2))
+ && IS_STR_END(rd_id[LENGTH(MSM8930_ID_2)])) ) {
+ gTarget = TARGET_MSM_NO_SSC;
+ } else if ( !memcmp(baseband, STR_MSM, LENGTH(STR_MSM)) ||
+ !memcmp(baseband, STR_SDM, LENGTH(STR_SDM)) ) {
+ gTarget = TARGET_DEFAULT;
+ } else {
+ gTarget = TARGET_UNKNOWN;
+ }
+
+detected:
+ LOC_LOGW("HAL: %s returned %d", __FUNCTION__, gTarget);
+ return gTarget;
+}
diff --git a/utils/loc_target.h b/utils/loc_target.h
new file mode 100644
index 0000000..172b475
--- /dev/null
+++ b/utils/loc_target.h
@@ -0,0 +1,78 @@
+/* Copyright (c) 2012-2014, 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 LOC_TARGET_H
+#define LOC_TARGET_H
+#define TARGET_SET(gnss,ssc) ( (gnss<<1)|ssc )
+#define TARGET_DEFAULT TARGET_SET(GNSS_MSM, HAS_SSC)
+#define TARGET_MDM TARGET_SET(GNSS_MDM, HAS_SSC)
+#define TARGET_APQ_SA TARGET_SET(GNSS_GSS, NO_SSC)
+#define TARGET_NO_GNSS TARGET_SET(GNSS_NONE, NO_SSC)
+#define TARGET_MSM_NO_SSC TARGET_SET(GNSS_MSM, NO_SSC)
+#define TARGET_AUTO TARGET_SET(GNSS_AUTO, NO_SSC)
+#define TARGET_UNKNOWN TARGET_SET(GNSS_UNKNOWN, NO_SSC)
+#define getTargetGnssType(target) (target>>1)
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+unsigned int loc_get_target(void);
+
+/*The character array passed to this function should have length
+ of atleast PROPERTY_VALUE_MAX*/
+void loc_get_target_baseband(char *baseband, int array_length);
+/*The character array passed to this function should have length
+ of atleast PROPERTY_VALUE_MAX*/
+void loc_get_platform_name(char *platform_name, int array_length);
+/*The character array passed to this function should have length
+ of atleast PROPERTY_VALUE_MAX*/
+void loc_get_auto_platform_name(char *platform_name, int array_length);
+
+/* Please remember to update 'target_name' in loc_log.cpp,
+ if do any changes to this enum. */
+typedef enum {
+ GNSS_NONE = 0,
+ GNSS_MSM,
+ GNSS_GSS,
+ GNSS_MDM,
+ GNSS_AUTO,
+ GNSS_UNKNOWN
+}GNSS_TARGET;
+
+typedef enum {
+ NO_SSC = 0,
+ HAS_SSC
+}SSC_TYPE;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /*LOC_TARGET_H*/
diff --git a/utils/loc_timer.h b/utils/loc_timer.h
new file mode 100644
index 0000000..fff0c46
--- /dev/null
+++ b/utils/loc_timer.h
@@ -0,0 +1,74 @@
+/* Copyright (c) 2013,2015 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 __LOC_DELAY_H__
+#define __LOC_DELAY_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+#include <stddef.h>
+#include <stdint.h>
+#include <loc_pla.h>
+/*
+ user_data: client context pointer, passthrough. Originally received
+ from calling client when loc_timer_start() is called.
+ result: 0 if timer successfully timed out; else timer failed.
+*/
+typedef void (*loc_timer_callback)(void *user_data, int32_t result);
+
+
+/*
+ delay_msec: timeout value for the timer.
+ cb_func: callback function pointer, implemented by client.
+ Can not be NULL.
+ user_data: client context pointer, passthrough. Will be
+ returned when loc_timer_callback() is called.
+ wakeOnExpire: true if to wake up CPU (if sleeping) upon timer
+ expiration and notify the client.
+ false if to wait until next time CPU wakes up (if
+ sleeping) and then notify the client.
+ Returns the handle, which can be used to stop the timer
+ NULL, if timer start fails (e.g. if cb_func is NULL).
+*/
+void* loc_timer_start(uint64_t delay_msec,
+ loc_timer_callback cb_func,
+ void *user_data,
+ bool wake_on_expire=false);
+
+/*
+ handle becomes invalid upon the return of the callback
+*/
+void loc_timer_stop(void*& handle);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif //__LOC_DELAY_H__
diff --git a/utils/log_util.h b/utils/log_util.h
new file mode 100644
index 0000000..ed7e19e
--- /dev/null
+++ b/utils/log_util.h
@@ -0,0 +1,203 @@
+/* Copyright (c) 2011-2014 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 __LOG_UTIL_H__
+#define __LOG_UTIL_H__
+
+#if defined (USE_ANDROID_LOGGING) || defined (ANDROID)
+// Android and LE targets with logcat support
+#include <utils/Log.h>
+
+#elif defined (USE_GLIB)
+// LE targets with no logcat support
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <unistd.h>
+
+#ifndef LOG_TAG
+#define LOG_TAG "GPS_UTILS"
+#endif /* LOG_TAG */
+
+// LE targets with no logcat support
+#ifdef FEATURE_EXTERNAL_AP
+#include <syslog.h>
+#define ALOGE(...) syslog(LOG_ERR, "LOC_LOGE: " __VA_ARGS__);
+#define ALOGW(...) syslog(LOG_WARNING, "LOC_LOGW: " __VA_ARGS__);
+#define ALOGI(...) syslog(LOG_NOTICE, "LOC_LOGI: " __VA_ARGS__);
+#define ALOGD(...) syslog(LOG_DEBUG, "LOC_LOGD: " __VA_ARGS__);
+#define ALOGV(...) syslog(LOG_NOTICE, "LOC_LOGV: " __VA_ARGS__);
+#else /* FEATURE_EXTERNAL_AP */
+#define TS_PRINTF(format, x...) \
+{ \
+ struct timeval tv; \
+ struct timezone tz; \
+ int hh, mm, ss; \
+ gettimeofday(&tv, &tz); \
+ hh = tv.tv_sec/3600%24; \
+ mm = (tv.tv_sec%3600)/60; \
+ ss = tv.tv_sec%60; \
+ fprintf(stdout,"%02d:%02d:%02d.%06ld]" format "\n", hh, mm, ss, tv.tv_usec, ##x); \
+}
+
+#define ALOGE(format, x...) TS_PRINTF("E/%s (%d): " format , LOG_TAG, getpid(), ##x)
+#define ALOGW(format, x...) TS_PRINTF("W/%s (%d): " format , LOG_TAG, getpid(), ##x)
+#define ALOGI(format, x...) TS_PRINTF("I/%s (%d): " format , LOG_TAG, getpid(), ##x)
+#define ALOGD(format, x...) TS_PRINTF("D/%s (%d): " format , LOG_TAG, getpid(), ##x)
+#define ALOGV(format, x...) TS_PRINTF("V/%s (%d): " format , LOG_TAG, getpid(), ##x)
+#endif /* FEATURE_EXTERNAL_AP */
+
+#endif /* #if defined (USE_ANDROID_LOGGING) || defined (ANDROID) */
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+/*=============================================================================
+ *
+ * LOC LOGGER TYPE DECLARATION
+ *
+ *============================================================================*/
+/* LOC LOGGER */
+typedef struct loc_logger_s
+{
+ unsigned long DEBUG_LEVEL;
+ unsigned long TIMESTAMP;
+} loc_logger_s_type;
+
+/*=============================================================================
+ *
+ * EXTERNAL DATA
+ *
+ *============================================================================*/
+extern loc_logger_s_type loc_logger;
+
+// Logging Improvements
+extern const char *loc_logger_boolStr[];
+
+extern const char *boolStr[];
+extern const char VOID_RET[];
+extern const char FROM_AFW[];
+extern const char TO_MODEM[];
+extern const char FROM_MODEM[];
+extern const char TO_AFW[];
+extern const char EXIT_TAG[];
+extern const char ENTRY_TAG[];
+extern const char EXIT_ERROR_TAG[];
+
+/*=============================================================================
+ *
+ * MODULE EXPORTED FUNCTIONS
+ *
+ *============================================================================*/
+extern void loc_logger_init(unsigned long debug, unsigned long timestamp);
+extern char* get_timestamp(char* str, unsigned long buf_size);
+
+#ifndef DEBUG_DMN_LOC_API
+
+/* LOGGING MACROS */
+/*loc_logger.DEBUG_LEVEL is initialized to 0xff in loc_cfg.cpp
+ if that value remains unchanged, it means gps.conf did not
+ provide a value and we default to the initial value to use
+ Android's logging levels*/
+#define IF_LOC_LOGE if((loc_logger.DEBUG_LEVEL >= 1) && (loc_logger.DEBUG_LEVEL <= 5))
+#define IF_LOC_LOGW if((loc_logger.DEBUG_LEVEL >= 2) && (loc_logger.DEBUG_LEVEL <= 5))
+#define IF_LOC_LOGI if((loc_logger.DEBUG_LEVEL >= 3) && (loc_logger.DEBUG_LEVEL <= 5))
+#define IF_LOC_LOGD if((loc_logger.DEBUG_LEVEL >= 4) && (loc_logger.DEBUG_LEVEL <= 5))
+#define IF_LOC_LOGV if((loc_logger.DEBUG_LEVEL >= 5) && (loc_logger.DEBUG_LEVEL <= 5))
+
+#define LOC_LOGE(...) IF_LOC_LOGE { ALOGE(__VA_ARGS__); }
+#define LOC_LOGW(...) IF_LOC_LOGW { ALOGW(__VA_ARGS__); }
+#define LOC_LOGI(...) IF_LOC_LOGI { ALOGI(__VA_ARGS__); }
+#define LOC_LOGD(...) IF_LOC_LOGD { ALOGD(__VA_ARGS__); }
+#define LOC_LOGV(...) IF_LOC_LOGV { ALOGV(__VA_ARGS__); }
+
+#else /* DEBUG_DMN_LOC_API */
+
+#define LOC_LOGE(...) ALOGE(__VA_ARGS__)
+#define LOC_LOGW(...) ALOGW(__VA_ARGS__)
+#define LOC_LOGI(...) ALOGI(__VA_ARGS__)
+#define LOC_LOGD(...) ALOGD(__VA_ARGS__)
+#define LOC_LOGV(...) ALOGV(__VA_ARGS__)
+
+#endif /* DEBUG_DMN_LOC_API */
+
+/*=============================================================================
+ *
+ * LOGGING IMPROVEMENT MACROS
+ *
+ *============================================================================*/
+#define LOG_(LOC_LOG, ID, WHAT, SPEC, VAL) \
+ do { \
+ if (loc_logger.TIMESTAMP) { \
+ char ts[32]; \
+ LOC_LOG("[%s] %s %s line %d " #SPEC, \
+ get_timestamp(ts, sizeof(ts)), ID, WHAT, __LINE__, VAL); \
+ } else { \
+ LOC_LOG("%s %s line %d " #SPEC, \
+ ID, WHAT, __LINE__, VAL); \
+ } \
+ } while(0)
+
+#define LOC_LOG_HEAD(fmt) "%s:%d] " fmt
+#define LOC_LOGv(fmt,...) LOC_LOGV(LOC_LOG_HEAD(fmt), __FUNCTION__, __LINE__, ##__VA_ARGS__)
+#define LOC_LOGw(fmt,...) LOC_LOGW(LOC_LOG_HEAD(fmt), __FUNCTION__, __LINE__, ##__VA_ARGS__)
+#define LOC_LOGi(fmt,...) LOC_LOGI(LOC_LOG_HEAD(fmt), __FUNCTION__, __LINE__, ##__VA_ARGS__)
+#define LOC_LOGd(fmt,...) LOC_LOGD(LOC_LOG_HEAD(fmt), __FUNCTION__, __LINE__, ##__VA_ARGS__)
+#define LOC_LOGe(fmt,...) LOC_LOGE(LOC_LOG_HEAD(fmt), __FUNCTION__, __LINE__, ##__VA_ARGS__)
+
+#define LOG_I(ID, WHAT, SPEC, VAL) LOG_(LOC_LOGI, ID, WHAT, SPEC, VAL)
+#define LOG_V(ID, WHAT, SPEC, VAL) LOG_(LOC_LOGV, ID, WHAT, SPEC, VAL)
+#define LOG_E(ID, WHAT, SPEC, VAL) LOG_(LOC_LOGE, ID, WHAT, SPEC, VAL)
+
+#define ENTRY_LOG() LOG_V(ENTRY_TAG, __FUNCTION__, %s, "")
+#define EXIT_LOG(SPEC, VAL) LOG_V(EXIT_TAG, __FUNCTION__, SPEC, VAL)
+#define EXIT_LOG_WITH_ERROR(SPEC, VAL) \
+ if (VAL != 0) { \
+ LOG_E(EXIT_ERROR_TAG, __FUNCTION__, SPEC, VAL); \
+ } else { \
+ LOG_V(EXIT_TAG, __FUNCTION__, SPEC, VAL); \
+ }
+
+
+// Used for logging callflow from Android Framework
+#define ENTRY_LOG_CALLFLOW() LOG_I(FROM_AFW, __FUNCTION__, %s, "")
+// Used for logging callflow to Modem
+#define EXIT_LOG_CALLFLOW(SPEC, VAL) LOG_I(TO_MODEM, __FUNCTION__, SPEC, VAL)
+// Used for logging callflow from Modem(TO_MODEM, __FUNCTION__, %s, "")
+#define MODEM_LOG_CALLFLOW(SPEC, VAL) LOG_I(FROM_MODEM, __FUNCTION__, SPEC, VAL)
+// Used for logging callflow to Android Framework
+#define CALLBACK_LOG_CALLFLOW(CB, SPEC, VAL) LOG_I(TO_AFW, CB, SPEC, VAL)
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // __LOG_UTIL_H__
diff --git a/utils/msg_q.c b/utils/msg_q.c
new file mode 100644
index 0000000..2d49b4a
--- /dev/null
+++ b/utils/msg_q.c
@@ -0,0 +1,378 @@
+/* Copyright (c) 2011-2012, 2014, 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_utils_q"
+#include <stdio.h>
+#include <stdlib.h>
+#include <pthread.h>
+#include <loc_pla.h>
+#include <log_util.h>
+#include "linked_list.h"
+#include "msg_q.h"
+
+typedef struct msg_q {
+ void* msg_list; /* Linked list to store information */
+ pthread_cond_t list_cond; /* Condition variable for waiting on msg queue */
+ pthread_mutex_t list_mutex; /* Mutex for exclusive access to message queue */
+ int unblocked; /* Has this message queue been unblocked? */
+} msg_q;
+
+/*===========================================================================
+FUNCTION convert_linked_list_err_type
+
+DESCRIPTION
+ Converts from one set of enum values to another.
+
+ linked_list_val: Value to convert to msg_q_enum_type
+
+DEPENDENCIES
+ N/A
+
+RETURN VALUE
+ Corresponding linked_list_enum_type in msg_q_enum_type
+
+SIDE EFFECTS
+ N/A
+
+===========================================================================*/
+static msq_q_err_type convert_linked_list_err_type(linked_list_err_type linked_list_val)
+{
+ switch( linked_list_val )
+ {
+ case eLINKED_LIST_SUCCESS:
+ return eMSG_Q_SUCCESS;
+ case eLINKED_LIST_INVALID_PARAMETER:
+ return eMSG_Q_INVALID_PARAMETER;
+ case eLINKED_LIST_INVALID_HANDLE:
+ return eMSG_Q_INVALID_HANDLE;
+ case eLINKED_LIST_UNAVAILABLE_RESOURCE:
+ return eMSG_Q_UNAVAILABLE_RESOURCE;
+ case eLINKED_LIST_INSUFFICIENT_BUFFER:
+ return eMSG_Q_INSUFFICIENT_BUFFER;
+
+ case eLINKED_LIST_FAILURE_GENERAL:
+ default:
+ return eMSG_Q_FAILURE_GENERAL;
+ }
+}
+
+/* ----------------------- END INTERNAL FUNCTIONS ---------------------------------------- */
+
+/*===========================================================================
+
+ FUNCTION: msg_q_init
+
+ ===========================================================================*/
+msq_q_err_type msg_q_init(void** msg_q_data)
+{
+ if( msg_q_data == NULL )
+ {
+ LOC_LOGE("%s: Invalid msg_q_data parameter!\n", __FUNCTION__);
+ return eMSG_Q_INVALID_PARAMETER;
+ }
+
+ msg_q* tmp_msg_q;
+ tmp_msg_q = (msg_q*)calloc(1, sizeof(msg_q));
+ if( tmp_msg_q == NULL )
+ {
+ LOC_LOGE("%s: Unable to allocate space for message queue!\n", __FUNCTION__);
+ return eMSG_Q_FAILURE_GENERAL;
+ }
+
+ if( linked_list_init(&tmp_msg_q->msg_list) != 0 )
+ {
+ LOC_LOGE("%s: Unable to initialize storage list!\n", __FUNCTION__);
+ free(tmp_msg_q);
+ return eMSG_Q_FAILURE_GENERAL;
+ }
+
+ if( pthread_mutex_init(&tmp_msg_q->list_mutex, NULL) != 0 )
+ {
+ LOC_LOGE("%s: Unable to initialize list mutex!\n", __FUNCTION__);
+ linked_list_destroy(&tmp_msg_q->msg_list);
+ free(tmp_msg_q);
+ return eMSG_Q_FAILURE_GENERAL;
+ }
+
+ if( pthread_cond_init(&tmp_msg_q->list_cond, NULL) != 0 )
+ {
+ LOC_LOGE("%s: Unable to initialize msg q cond var!\n", __FUNCTION__);
+ linked_list_destroy(&tmp_msg_q->msg_list);
+ pthread_mutex_destroy(&tmp_msg_q->list_mutex);
+ free(tmp_msg_q);
+ return eMSG_Q_FAILURE_GENERAL;
+ }
+
+ tmp_msg_q->unblocked = 0;
+
+ *msg_q_data = tmp_msg_q;
+
+ return eMSG_Q_SUCCESS;
+}
+
+/*===========================================================================
+
+ FUNCTION: msg_q_init2
+
+ ===========================================================================*/
+const void* msg_q_init2()
+{
+ void* q = NULL;
+ if (eMSG_Q_SUCCESS != msg_q_init(&q)) {
+ q = NULL;
+ }
+ return q;
+}
+
+/*===========================================================================
+
+ FUNCTION: msg_q_destroy
+
+ ===========================================================================*/
+msq_q_err_type msg_q_destroy(void** msg_q_data)
+{
+ if( msg_q_data == NULL )
+ {
+ LOC_LOGE("%s: Invalid msg_q_data parameter!\n", __FUNCTION__);
+ return eMSG_Q_INVALID_HANDLE;
+ }
+
+ msg_q* p_msg_q = (msg_q*)*msg_q_data;
+
+ linked_list_destroy(&p_msg_q->msg_list);
+ pthread_mutex_destroy(&p_msg_q->list_mutex);
+ pthread_cond_destroy(&p_msg_q->list_cond);
+
+ p_msg_q->unblocked = 0;
+
+ free(*msg_q_data);
+ *msg_q_data = NULL;
+
+ return eMSG_Q_SUCCESS;
+}
+
+/*===========================================================================
+
+ FUNCTION: msg_q_snd
+
+ ===========================================================================*/
+msq_q_err_type msg_q_snd(void* msg_q_data, void* msg_obj, void (*dealloc)(void*))
+{
+ msq_q_err_type rv;
+ if( msg_q_data == NULL )
+ {
+ LOC_LOGE("%s: Invalid msg_q_data parameter!\n", __FUNCTION__);
+ return eMSG_Q_INVALID_HANDLE;
+ }
+ if( msg_obj == NULL )
+ {
+ LOC_LOGE("%s: Invalid msg_obj parameter!\n", __FUNCTION__);
+ return eMSG_Q_INVALID_PARAMETER;
+ }
+
+ msg_q* p_msg_q = (msg_q*)msg_q_data;
+
+ pthread_mutex_lock(&p_msg_q->list_mutex);
+ LOC_LOGV("%s: Sending message with handle = %p\n", __FUNCTION__, msg_obj);
+
+ if( p_msg_q->unblocked )
+ {
+ LOC_LOGE("%s: Message queue has been unblocked.\n", __FUNCTION__);
+ pthread_mutex_unlock(&p_msg_q->list_mutex);
+ return eMSG_Q_UNAVAILABLE_RESOURCE;
+ }
+
+ rv = convert_linked_list_err_type(linked_list_add(p_msg_q->msg_list, msg_obj, dealloc));
+
+ /* Show data is in the message queue. */
+ pthread_cond_signal(&p_msg_q->list_cond);
+
+ pthread_mutex_unlock(&p_msg_q->list_mutex);
+
+ LOC_LOGV("%s: Finished Sending message with handle = %p\n", __FUNCTION__, msg_obj);
+
+ return rv;
+}
+
+/*===========================================================================
+
+ FUNCTION: msg_q_rcv
+
+ ===========================================================================*/
+msq_q_err_type msg_q_rcv(void* msg_q_data, void** msg_obj)
+{
+ msq_q_err_type rv;
+ if( msg_q_data == NULL )
+ {
+ LOC_LOGE("%s: Invalid msg_q_data parameter!\n", __FUNCTION__);
+ return eMSG_Q_INVALID_HANDLE;
+ }
+
+ if( msg_obj == NULL )
+ {
+ LOC_LOGE("%s: Invalid msg_obj parameter!\n", __FUNCTION__);
+ return eMSG_Q_INVALID_PARAMETER;
+ }
+
+ msg_q* p_msg_q = (msg_q*)msg_q_data;
+
+ pthread_mutex_lock(&p_msg_q->list_mutex);
+
+ if( p_msg_q->unblocked )
+ {
+ LOC_LOGE("%s: Message queue has been unblocked.\n", __FUNCTION__);
+ pthread_mutex_unlock(&p_msg_q->list_mutex);
+ return eMSG_Q_UNAVAILABLE_RESOURCE;
+ }
+
+ /* Wait for data in the message queue */
+ while( linked_list_empty(p_msg_q->msg_list) && !p_msg_q->unblocked )
+ {
+ pthread_cond_wait(&p_msg_q->list_cond, &p_msg_q->list_mutex);
+ }
+
+ rv = convert_linked_list_err_type(linked_list_remove(p_msg_q->msg_list, msg_obj));
+
+ pthread_mutex_unlock(&p_msg_q->list_mutex);
+
+ LOC_LOGV("%s: Received message %p rv = %d\n", __FUNCTION__, *msg_obj, rv);
+
+ return rv;
+}
+
+/*===========================================================================
+
+ FUNCTION: msg_q_rmv
+
+ ===========================================================================*/
+msq_q_err_type msg_q_rmv(void* msg_q_data, void** msg_obj)
+{
+ msq_q_err_type rv;
+ if (msg_q_data == NULL) {
+ LOC_LOGE("%s: Invalid msg_q_data parameter!\n", __FUNCTION__);
+ return eMSG_Q_INVALID_HANDLE;
+ }
+
+ if (msg_obj == NULL) {
+ LOC_LOGE("%s: Invalid msg_obj parameter!\n", __FUNCTION__);
+ return eMSG_Q_INVALID_PARAMETER;
+ }
+
+ msg_q* p_msg_q = (msg_q*)msg_q_data;
+
+ pthread_mutex_lock(&p_msg_q->list_mutex);
+
+ if (p_msg_q->unblocked) {
+ LOC_LOGE("%s: Message queue has been unblocked.\n", __FUNCTION__);
+ pthread_mutex_unlock(&p_msg_q->list_mutex);
+ return eMSG_Q_UNAVAILABLE_RESOURCE;
+ }
+
+ if (linked_list_empty(p_msg_q->msg_list)) {
+ LOC_LOGW("%s: list is empty !!\n", __FUNCTION__);
+ pthread_mutex_unlock(&p_msg_q->list_mutex);
+ return eLINKED_LIST_EMPTY;
+ }
+
+ rv = convert_linked_list_err_type(linked_list_remove(p_msg_q->msg_list, msg_obj));
+
+ pthread_mutex_unlock(&p_msg_q->list_mutex);
+
+ LOC_LOGV("%s: Removed message %p rv = %d\n", __FUNCTION__, *msg_obj, rv);
+
+ return rv;
+}
+
+
+
+/*===========================================================================
+
+ FUNCTION: msg_q_flush
+
+ ===========================================================================*/
+msq_q_err_type msg_q_flush(void* msg_q_data)
+{
+ msq_q_err_type rv;
+ if ( msg_q_data == NULL )
+ {
+ LOC_LOGE("%s: Invalid msg_q_data parameter!\n", __FUNCTION__);
+ return eMSG_Q_INVALID_HANDLE;
+ }
+
+ msg_q* p_msg_q = (msg_q*)msg_q_data;
+
+ LOC_LOGD("%s: Flushing Message Queue\n", __FUNCTION__);
+
+ pthread_mutex_lock(&p_msg_q->list_mutex);
+
+ /* Remove all elements from the list */
+ rv = convert_linked_list_err_type(linked_list_flush(p_msg_q->msg_list));
+
+ pthread_mutex_unlock(&p_msg_q->list_mutex);
+
+ LOC_LOGD("%s: Message Queue flushed\n", __FUNCTION__);
+
+ return rv;
+}
+
+/*===========================================================================
+
+ FUNCTION: msg_q_unblock
+
+ ===========================================================================*/
+msq_q_err_type msg_q_unblock(void* msg_q_data)
+{
+ if ( msg_q_data == NULL )
+ {
+ LOC_LOGE("%s: Invalid msg_q_data parameter!\n", __FUNCTION__);
+ return eMSG_Q_INVALID_HANDLE;
+ }
+
+ msg_q* p_msg_q = (msg_q*)msg_q_data;
+ pthread_mutex_lock(&p_msg_q->list_mutex);
+
+ if( p_msg_q->unblocked )
+ {
+ LOC_LOGE("%s: Message queue has been unblocked.\n", __FUNCTION__);
+ pthread_mutex_unlock(&p_msg_q->list_mutex);
+ return eMSG_Q_UNAVAILABLE_RESOURCE;
+ }
+
+ LOC_LOGD("%s: Unblocking Message Queue\n", __FUNCTION__);
+ /* Unblocking message queue */
+ p_msg_q->unblocked = 1;
+
+ /* Allow all the waiters to wake up */
+ pthread_cond_broadcast(&p_msg_q->list_cond);
+
+ pthread_mutex_unlock(&p_msg_q->list_mutex);
+
+ LOC_LOGD("%s: Message Queue unblocked\n", __FUNCTION__);
+
+ return eMSG_Q_SUCCESS;
+}
diff --git a/utils/msg_q.h b/utils/msg_q.h
new file mode 100644
index 0000000..16df494
--- /dev/null
+++ b/utils/msg_q.h
@@ -0,0 +1,230 @@
+/* Copyright (c) 2011, 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 __MSG_Q_H__
+#define __MSG_Q_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+#include <stdlib.h>
+
+/** Linked List Return Codes */
+typedef enum
+{
+ eMSG_Q_SUCCESS = 0,
+ /**< Request was successful. */
+ eMSG_Q_FAILURE_GENERAL = -1,
+ /**< Failed because of a general failure. */
+ eMSG_Q_INVALID_PARAMETER = -2,
+ /**< Failed because the request contained invalid parameters. */
+ eMSG_Q_INVALID_HANDLE = -3,
+ /**< Failed because an invalid handle was specified. */
+ eMSG_Q_UNAVAILABLE_RESOURCE = -4,
+ /**< Failed because an there were not enough resources. */
+ eMSG_Q_INSUFFICIENT_BUFFER = -5,
+ /**< Failed because an the supplied buffer was too small. */
+}msq_q_err_type;
+
+/*===========================================================================
+FUNCTION msg_q_init
+
+DESCRIPTION
+ Initializes internal structures for message queue.
+
+ msg_q_data: pointer to an opaque Q handle to be returned; NULL if fails
+
+DEPENDENCIES
+ N/A
+
+RETURN VALUE
+ Look at error codes above.
+
+SIDE EFFECTS
+ N/A
+
+===========================================================================*/
+msq_q_err_type msg_q_init(void** msg_q_data);
+
+/*===========================================================================
+FUNCTION msg_q_init2
+
+DESCRIPTION
+ Initializes internal structures for message queue.
+
+DEPENDENCIES
+ N/A
+
+RETURN VALUE
+ opaque handle to the Q created; NULL if create fails
+
+SIDE EFFECTS
+ N/A
+
+===========================================================================*/
+const void* msg_q_init2();
+
+/*===========================================================================
+FUNCTION msg_q_destroy
+
+DESCRIPTION
+ Releases internal structures for message queue.
+
+ msg_q_data: State of message queue to be released.
+
+DEPENDENCIES
+ N/A
+
+RETURN VALUE
+ Look at error codes above.
+
+SIDE EFFECTS
+ N/A
+
+===========================================================================*/
+msq_q_err_type msg_q_destroy(void** msg_q_data);
+
+/*===========================================================================
+FUNCTION msg_q_snd
+
+DESCRIPTION
+ Sends data to the message queue. The passed in data pointer
+ is not modified or freed. Passed in msg_obj is expected to live throughout
+ the use of the msg_q (i.e. data is not allocated internally)
+
+ msg_q_data: Message Queue to add the element to.
+ msgp: Pointer to data to add into message queue.
+ dealloc: Function used to deallocate memory for this element. Pass NULL
+ if you do not want data deallocated during a flush operation
+
+DEPENDENCIES
+ N/A
+
+RETURN VALUE
+ Look at error codes above.
+
+SIDE EFFECTS
+ N/A
+
+===========================================================================*/
+msq_q_err_type msg_q_snd(void* msg_q_data, void* msg_obj, void (*dealloc)(void*));
+
+/*===========================================================================
+FUNCTION msg_q_rcv
+
+DESCRIPTION
+ Retrieves data from the message queue. msg_obj is the oldest message received
+ and pointer is simply removed from message queue.
+
+ msg_q_data: Message Queue to copy data from into msgp.
+ msg_obj: Pointer to space to copy msg_q contents to.
+
+DEPENDENCIES
+ N/A
+
+RETURN VALUE
+ Look at error codes above.
+
+SIDE EFFECTS
+ N/A
+
+===========================================================================*/
+msq_q_err_type msg_q_rcv(void* msg_q_data, void** msg_obj);
+
+/*===========================================================================
+FUNCTION msg_q_rmv
+
+DESCRIPTION
+ Remove data from the message queue. msg_obj is the oldest message received
+ and pointer is simply removed from message queue.
+
+ msg_q_data: Message Queue to copy data from into msgp.
+ msg_obj: Pointer to space to copy msg_q contents to.
+
+DEPENDENCIES
+ N/A
+
+RETURN VALUE
+ Look at error codes above.
+
+SIDE EFFECTS
+ N/A
+
+===========================================================================*/
+msq_q_err_type msg_q_rmv(void* msg_q_data, void** msg_obj);
+
+
+/*===========================================================================
+FUNCTION msg_q_flush
+
+DESCRIPTION
+ Function removes all elements from the message queue.
+
+ msg_q_data: Message Queue to remove elements from.
+
+DEPENDENCIES
+ N/A
+
+RETURN VALUE
+ Look at error codes above.
+
+SIDE EFFECTS
+ N/A
+
+===========================================================================*/
+msq_q_err_type msg_q_flush(void* msg_q_data);
+
+/*===========================================================================
+FUNCTION msg_q_unblock
+
+DESCRIPTION
+ This function will stop use of the message queue. All waiters will wake up
+ and likely receive nothing from the queue resulting in a negative return
+ value. The message queue can no longer be used until it is destroyed
+ and initialized again after calling this function.
+
+ msg_q_data: Message queue to unblock.
+
+DEPENDENCIES
+ N/A
+
+RETURN VALUE
+ Look at error codes above.
+
+SIDE EFFECTS
+ N/A
+
+===========================================================================*/
+msq_q_err_type msg_q_unblock(void* msg_q_data);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* __MSG_Q_H__ */