aboutsummaryrefslogtreecommitdiff
path: root/gps/gnss/GnssAdapter.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'gps/gnss/GnssAdapter.cpp')
-rw-r--r--gps/gnss/GnssAdapter.cpp6916
1 files changed, 6916 insertions, 0 deletions
diff --git a/gps/gnss/GnssAdapter.cpp b/gps/gnss/GnssAdapter.cpp
new file mode 100644
index 0000000..cff0298
--- /dev/null
+++ b/gps/gnss/GnssAdapter.cpp
@@ -0,0 +1,6916 @@
+/* Copyright (c) 2017-2020 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>
+#include <loc_misc_utils.h>
+#include <gps_extended_c.h>
+
+#define RAD2DEG (180.0 / M_PI)
+#define DEG2RAD (M_PI / 180.0)
+#define PROCESS_NAME_ENGINE_SERVICE "engine-service"
+#define MIN_TRACKING_INTERVAL (100) // 100 msec
+
+#define BILLION_NSEC (1000000000ULL)
+#define NMEA_MIN_THRESHOLD_MSEC (99)
+#define NMEA_MAX_THRESHOLD_MSEC (975)
+
+#define DGNSS_RANGE_UPDATE_TIME_10MIN_IN_MILLI 600000
+
+using namespace loc_core;
+
+static int loadEngHubForExternalEngine = 0;
+static loc_param_s_type izatConfParamTable[] = {
+ {"LOAD_ENGHUB_FOR_EXTERNAL_ENGINE", &loadEngHubForExternalEngine, nullptr,'n'}
+};
+
+/* 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);
+
+typedef const CdfwInterface* (*getCdfwInterface)();
+
+inline bool GnssReportLoggerUtil::isLogEnabled() {
+ return (mLogLatency != nullptr);
+}
+
+inline void GnssReportLoggerUtil::log(const GnssLatencyInfo& gnssLatencyMeasInfo) {
+ if (mLogLatency != nullptr) {
+ mLogLatency(gnssLatencyMeasInfo);
+ }
+}
+
+GnssAdapter::GnssAdapter() :
+ LocAdapterBase(0,
+ LocContext::getLocContext(LocContext::mLocationHalName),
+ true, nullptr, true),
+ mEngHubProxy(new EngineHubProxyBase()),
+ mQDgnssListenerHDL(nullptr),
+ mCdfwInterface(nullptr),
+ mDGnssNeedReport(false),
+ mDGnssDataUsage(false),
+ mLocPositionMode(),
+ mNHzNeeded(false),
+ mSPEAlreadyRunningAtHighestInterval(false),
+ mGnssSvIdUsedInPosition(),
+ mGnssSvIdUsedInPosAvail(false),
+ mControlCallbacks(),
+ mAfwControlId(0),
+ mNmeaMask(0),
+ mGnssSvIdConfig(),
+ mGnssSeconaryBandConfig(),
+ mGnssSvTypeConfig(),
+ mGnssSvTypeConfigCb(nullptr),
+ mLocConfigInfo{},
+ mNiData(),
+ mAgpsManager(),
+ mOdcpiRequestCb(nullptr),
+ mOdcpiRequestActive(false),
+ mOdcpiTimer(this),
+ mOdcpiRequest(),
+ mCallbackPriority(OdcpiPrioritytype::ODCPI_HANDLER_PRIORITY_LOW),
+ mSystemStatus(SystemStatus::getInstance(mMsgTask)),
+ mServerUrl(":"),
+ mXtraObserver(mSystemStatus->getOsObserver(), mMsgTask),
+ mBlockCPIInfo{},
+ mDreIntEnabled(false),
+ mLocSystemInfo{},
+ mNfwCb(NULL),
+ mPowerOn(false),
+ mAllowFlpNetworkFixes(0),
+ mGnssEnergyConsumedCb(nullptr),
+ mPowerStateCb(nullptr),
+ mIsE911Session(NULL),
+ mGnssMbSvIdUsedInPosition{},
+ mGnssMbSvIdUsedInPosAvail(false),
+ mSupportNfwControl(true),
+ mSystemPowerState(POWER_STATE_UNKNOWN),
+ mIsMeasCorrInterfaceOpen(false),
+ mIsAntennaInfoInterfaceOpened(false),
+ mLastDeleteAidingDataTime(0),
+ mDgnssState(0),
+ mSendNmeaConsent(false),
+ mDgnssLastNmeaBootTimeMilli(0),
+ mNativeAgpsHandler(mSystemStatus->getOsObserver(), *this)
+{
+ 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();
+
+ // at last step, let us inform adapater base that we are done
+ // with initialization, e.g.: ready to process handleEngineUpEvent
+ doneInit();
+}
+
+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;
+}
+
+bool
+GnssAdapter::checkAndSetSPEToRunforNHz(TrackingOptions & out) {
+
+ // first check if NHz meas is needed at all, if not, just return false
+ // if a NHz capable engine is subscribed for NHz measurement or NHz positions,
+ // always run the SPE only session at 100ms TBF.
+ // If SPE session is already set to highest interval, no need to start it again.
+
+ bool isSPERunningAtHighestInterval = false;
+
+ if (!mNHzNeeded) {
+ LOC_LOGd("No nHz session needed.");
+ } else if (mSPEAlreadyRunningAtHighestInterval) {
+ LOC_LOGd("SPE is already running at highest interval.");
+ isSPERunningAtHighestInterval = true;
+ } else if (out.minInterval > MIN_TRACKING_INTERVAL) {
+ out.minInterval = MIN_TRACKING_INTERVAL;
+ LOC_LOGd("nHz session is needed, starting SPE only session at 100ms TBF.");
+ mSPEAlreadyRunningAtHighestInterval = true;
+ }
+
+ return isSPERunningAtHighestInterval;
+}
+
+
+void
+GnssAdapter::convertLocation(Location& out, const UlpLocation& ulpLocation,
+ const GpsLocationExtended& locationExtended)
+{
+ 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;
+ }
+ if (GPS_LOCATION_EXTENDED_HAS_CONFORMITY_INDEX & locationExtended.flags) {
+ out.flags |= LOCATION_HAS_CONFORMITY_INDEX_BIT;
+ out.conformityIndex = locationExtended.conformityIndex;
+ }
+ out.timestamp = ulpLocation.gpsLocation.timestamp;
+ if (LOC_POS_TECH_MASK_SATELLITE & locationExtended.tech_mask) {
+ out.techMask |= LOCATION_TECHNOLOGY_GNSS_BIT;
+ }
+ if (LOC_POS_TECH_MASK_CELLID & locationExtended.tech_mask) {
+ out.techMask |= LOCATION_TECHNOLOGY_CELL_BIT;
+ }
+ if (LOC_POS_TECH_MASK_WIFI & locationExtended.tech_mask) {
+ out.techMask |= LOCATION_TECHNOLOGY_WIFI_BIT;
+ }
+ if (LOC_POS_TECH_MASK_SENSORS & locationExtended.tech_mask) {
+ out.techMask |= LOCATION_TECHNOLOGY_SENSORS_BIT;
+ }
+ if (LOC_POS_TECH_MASK_REFERENCE_LOCATION & locationExtended.tech_mask) {
+ out.techMask |= LOCATION_TECHNOLOGY_REFERENCE_LOCATION_BIT;
+ }
+ if (LOC_POS_TECH_MASK_INJECTED_COARSE_POSITION & locationExtended.tech_mask) {
+ out.techMask |= LOCATION_TECHNOLOGY_INJECTED_COARSE_POSITION_BIT;
+ }
+ if (LOC_POS_TECH_MASK_AFLT & locationExtended.tech_mask) {
+ out.techMask |= LOCATION_TECHNOLOGY_AFLT_BIT;
+ }
+ if (LOC_POS_TECH_MASK_HYBRID & locationExtended.tech_mask) {
+ out.techMask |= LOCATION_TECHNOLOGY_HYBRID_BIT;
+ }
+ if (LOC_POS_TECH_MASK_PPE & locationExtended.tech_mask) {
+ out.techMask |= LOCATION_TECHNOLOGY_PPE_BIT;
+ }
+ if (LOC_POS_TECH_MASK_VEH & locationExtended.tech_mask) {
+ out.techMask |= LOCATION_TECHNOLOGY_VEH_BIT;
+ }
+ if (LOC_POS_TECH_MASK_VIS & locationExtended.tech_mask) {
+ out.techMask |= LOCATION_TECHNOLOGY_VIS_BIT;
+ }
+ if (LOC_NAV_MASK_DGNSS_CORRECTION & locationExtended.navSolutionMask) {
+ out.techMask |= LOCATION_TECHNOLOGY_DGNSS_BIT;
+ }
+
+ if (LOC_GPS_LOCATION_HAS_SPOOF_MASK & ulpLocation.gpsLocation.flags) {
+ out.flags |= LOCATION_HAS_SPOOF_MASK;
+ out.spoofMask = ulpLocation.gpsLocation.spoof_mask;
+ }
+ if (LOC_GPS_LOCATION_HAS_ELAPSED_REAL_TIME & ulpLocation.gpsLocation.flags) {
+ out.flags |= LOCATION_HAS_ELAPSED_REAL_TIME;
+ out.elapsedRealTime = ulpLocation.gpsLocation.elapsedRealTime;
+ out.elapsedRealTimeUnc = ulpLocation.gpsLocation.elapsedRealTimeUnc;
+ }
+}
+
+/* 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,
+ enum loc_sess_status status)
+{
+ 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.svUsedInPosition.navicSvUsedIdsMask =
+ locationExtended.gnss_sv_used_ids.navic_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.numSvUsedInPosition += getNumSvUsed(out.svUsedInPosition.navicSvUsedIdsMask,
+ NAVIC_SV_PRN_MAX - NAVIC_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_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;
+ }
+
+ if (locationExtended.bodyFrameData.bodyFrameDataMask &
+ LOCATION_NAV_DATA_HAS_LONG_ACCEL_UNC_BIT) {
+ out.bodyFrameData.bodyFrameDataMask |= LOCATION_NAV_DATA_HAS_LONG_ACCEL_UNC_BIT;
+ }
+ if (locationExtended.bodyFrameData.bodyFrameDataMask &
+ LOCATION_NAV_DATA_HAS_LAT_ACCEL_UNC_BIT) {
+ out.bodyFrameData.bodyFrameDataMask |= LOCATION_NAV_DATA_HAS_LAT_ACCEL_UNC_BIT;
+ }
+ if (locationExtended.bodyFrameData.bodyFrameDataMask &
+ LOCATION_NAV_DATA_HAS_VERT_ACCEL_UNC_BIT) {
+ out.bodyFrameData.bodyFrameDataMask |= LOCATION_NAV_DATA_HAS_VERT_ACCEL_UNC_BIT;
+ }
+ if (locationExtended.bodyFrameData.bodyFrameDataMask &
+ LOCATION_NAV_DATA_HAS_YAW_RATE_UNC_BIT) {
+ out.bodyFrameData.bodyFrameDataMask |= LOCATION_NAV_DATA_HAS_YAW_RATE_UNC_BIT;
+ }
+ if (locationExtended.bodyFrameData.bodyFrameDataMask &
+ LOCATION_NAV_DATA_HAS_PITCH_UNC_BIT) {
+ out.bodyFrameData.bodyFrameDataMask |= LOCATION_NAV_DATA_HAS_PITCH_UNC_BIT;
+ }
+
+ if (locationExtended.bodyFrameDataExt.bodyFrameDataMask &
+ LOCATION_NAV_DATA_HAS_PITCH_RATE_BIT) {
+ out.bodyFrameDataExt.bodyFrameDataMask |= LOCATION_NAV_DATA_HAS_PITCH_RATE_BIT;
+ }
+ if (locationExtended.bodyFrameDataExt.bodyFrameDataMask &
+ LOCATION_NAV_DATA_HAS_PITCH_RATE_UNC_BIT) {
+ out.bodyFrameDataExt.bodyFrameDataMask |= LOCATION_NAV_DATA_HAS_PITCH_RATE_UNC_BIT;
+ }
+ if (locationExtended.bodyFrameDataExt.bodyFrameDataMask &
+ LOCATION_NAV_DATA_HAS_ROLL_BIT) {
+ out.bodyFrameDataExt.bodyFrameDataMask |= LOCATION_NAV_DATA_HAS_ROLL_BIT;
+ }
+ if (locationExtended.bodyFrameDataExt.bodyFrameDataMask &
+ LOCATION_NAV_DATA_HAS_ROLL_UNC_BIT) {
+ out.bodyFrameDataExt.bodyFrameDataMask |= LOCATION_NAV_DATA_HAS_ROLL_UNC_BIT;
+ }
+ if (locationExtended.bodyFrameDataExt.bodyFrameDataMask &
+ LOCATION_NAV_DATA_HAS_ROLL_RATE_BIT) {
+ out.bodyFrameDataExt.bodyFrameDataMask |= LOCATION_NAV_DATA_HAS_ROLL_RATE_BIT;
+ }
+ if (locationExtended.bodyFrameDataExt.bodyFrameDataMask &
+ LOCATION_NAV_DATA_HAS_ROLL_RATE_UNC_BIT) {
+ out.bodyFrameDataExt.bodyFrameDataMask |= LOCATION_NAV_DATA_HAS_ROLL_RATE_UNC_BIT;
+ }
+ if (locationExtended.bodyFrameDataExt.bodyFrameDataMask &
+ LOCATION_NAV_DATA_HAS_YAW_BIT) {
+ out.bodyFrameDataExt.bodyFrameDataMask |= LOCATION_NAV_DATA_HAS_YAW_BIT;
+ }
+ if (locationExtended.bodyFrameDataExt.bodyFrameDataMask &
+ LOCATION_NAV_DATA_HAS_YAW_UNC_BIT) {
+ out.bodyFrameDataExt.bodyFrameDataMask |= LOCATION_NAV_DATA_HAS_YAW_UNC_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;
+ out.bodyFrameData.longAccelUnc = locationExtended.bodyFrameData.longAccelUnc;
+ out.bodyFrameData.latAccelUnc = locationExtended.bodyFrameData.latAccelUnc;
+ out.bodyFrameData.vertAccelUnc = locationExtended.bodyFrameData.vertAccelUnc;
+ out.bodyFrameData.yawRateUnc = locationExtended.bodyFrameData.yawRateUnc;
+ out.bodyFrameData.pitchUnc = locationExtended.bodyFrameData.pitchUnc;
+
+ out.bodyFrameDataExt.pitchRate = locationExtended.bodyFrameDataExt.pitchRate;
+ out.bodyFrameDataExt.pitchRateUnc = locationExtended.bodyFrameDataExt.pitchRateUnc;
+ out.bodyFrameDataExt.roll = locationExtended.bodyFrameDataExt.roll;
+ out.bodyFrameDataExt.rollUnc = locationExtended.bodyFrameDataExt.rollUnc;
+ out.bodyFrameDataExt.rollRate = locationExtended.bodyFrameDataExt.rollRate;
+ out.bodyFrameDataExt.rollRateUnc = locationExtended.bodyFrameDataExt.rollRateUnc;
+ out.bodyFrameDataExt.yaw = locationExtended.bodyFrameDataExt.yaw;
+ out.bodyFrameDataExt.yawUnc = locationExtended.bodyFrameDataExt.yawUnc;
+ }
+
+ // 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;
+ }
+
+ if (GPS_LOCATION_EXTENDED_HAS_CONFORMITY_INDEX & locationExtended.flags) {
+ out.flags |= GNSS_LOCATION_INFO_CONFORMITY_INDEX_BIT;
+ out.conformityIndex = locationExtended.conformityIndex;
+ }
+
+ if (GPS_LOCATION_EXTENDED_HAS_LLA_VRP_BASED & locationExtended.flags) {
+ out.flags |= GNSS_LOCATION_INFO_LLA_VRP_BASED_BIT;
+ out.llaVRPBased = locationExtended.llaVRPBased;
+ }
+
+ if (GPS_LOCATION_EXTENDED_HAS_ENU_VELOCITY_LLA_VRP_BASED & locationExtended.flags) {
+ out.flags |= GNSS_LOCATION_INFO_ENU_VELOCITY_VRP_BASED_BIT;
+ // copy over east, north and up vrp based velocity
+ out.enuVelocityVRPBased[0] = locationExtended.enuVelocityVRPBased[0];
+ out.enuVelocityVRPBased[1] = locationExtended.enuVelocityVRPBased[1];
+ out.enuVelocityVRPBased[2] = locationExtended.enuVelocityVRPBased[2];
+ }
+
+ if (GPS_LOCATION_EXTENDED_HAS_DR_SOLUTION_STATUS_MASK & locationExtended.flags) {
+ out.flags |= GNSS_LOCATION_INFO_DR_SOLUTION_STATUS_MASK_BIT;
+ out.drSolutionStatusMask = locationExtended.drSolutionStatusMask;
+ }
+
+ if (GPS_LOCATION_EXTENDED_HAS_ALTITUDE_ASSUMED & locationExtended.flags) {
+ out.flags |= GNSS_LOCATION_INFO_ALTITUDE_ASSUMED_BIT;
+ out.altitudeAssumed = locationExtended.altitudeAssumed;
+ }
+
+ out.flags |= GNSS_LOCATION_INFO_SESSION_STATUS_BIT;
+ out.sessionStatus = status;
+}
+
+inline uint32_t
+GnssAdapter::convertSuplVersion(const GnssConfigSuplVersion suplVersion)
+{
+ switch (suplVersion) {
+ case GNSS_CONFIG_SUPL_VERSION_2_0_4:
+ return 0x00020004;
+ 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;
+ }
+}
+
+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,
+ (nullptr == server) ? serverUrl : 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::mGps_conf.NMEA_TAG_BLOCK_GROUPING_ENABLED) {
+ mask |= LOC_NMEA_MASK_TAGBLOCK_V02;
+ }
+ }
+ 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;
+ }
+ 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.lppProfileMask = 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] () mutable {
+ 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 (gpsConf.NMEA_TAG_BLOCK_GROUPING_ENABLED) {
+ mask |= LOC_NMEA_MASK_TAGBLOCK_V02;
+ }
+ }
+ if (ContextBase::isFeatureSupported(LOC_SUPPORTED_FEATURE_DEBUG_NMEA_V02)) {
+ mask |= LOC_NMEA_MASK_DEBUG_V02;
+ }
+
+ if (mask != 0) {
+ mLocApi->setNMEATypesSync(mask);
+ }
+
+ // load tunc configuration from config file on first boot-up,
+ // e.g.: adapter.mLocConfigInfo.tuncConfigInfo.isValid is false
+ if (mLocConfigInfo.tuncConfigInfo.isValid == false) {
+ mLocConfigInfo.tuncConfigInfo.isValid = true;
+ mLocConfigInfo.tuncConfigInfo.enable =
+ (gpsConf.CONSTRAINED_TIME_UNCERTAINTY_ENABLED == 1);
+ mLocConfigInfo.tuncConfigInfo.tuncThresholdMs =
+ (float)gpsConf.CONSTRAINED_TIME_UNCERTAINTY_THRESHOLD;
+ mLocConfigInfo.tuncConfigInfo.energyBudget =
+ gpsConf.CONSTRAINED_TIME_UNCERTAINTY_ENERGY_BUDGET;
+ }
+
+ mLocApi->setConstrainedTuncMode(
+ mLocConfigInfo.tuncConfigInfo.enable,
+ mLocConfigInfo.tuncConfigInfo.tuncThresholdMs,
+ mLocConfigInfo.tuncConfigInfo.energyBudget);
+
+ // load pace configuration from config file on first boot-up,
+ // e.g.: adapter.mLocConfigInfo.paceConfigInfo.isValid is false
+ if (mLocConfigInfo.paceConfigInfo.isValid == false) {
+ mLocConfigInfo.paceConfigInfo.isValid = true;
+ mLocConfigInfo.paceConfigInfo.enable =
+ (gpsConf.POSITION_ASSISTED_CLOCK_ESTIMATOR_ENABLED==1);
+ }
+ mLocApi->setPositionAssistedClockEstimatorMode(
+ mLocConfigInfo.paceConfigInfo.enable);
+
+ // we do not support control robust location from gps.conf
+ if (mLocConfigInfo.robustLocationConfigInfo.isValid == true) {
+ mLocApi->configRobustLocation(
+ mLocConfigInfo.robustLocationConfigInfo.enable,
+ mLocConfigInfo.robustLocationConfigInfo.enableFor911);
+ }
+
+ 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);
+ } ));
+ // deal with Measurement Corrections
+ if (true == mIsMeasCorrInterfaceOpen) {
+ initMeasCorr(true);
+ }
+}
+
+std::vector<LocationError> GnssAdapter::gnssUpdateConfig(const std::string& oldMoServerUrl,
+ GnssConfig& gnssConfigRequested, 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 (!ContextBase::mGps_conf.AGPS_CONFIG_INJECT) {
+ LOC_LOGd("AGPS_CONFIG_INJECT is 0. Not setting flags for AGPS configurations");
+ 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);
+ }
+
+ 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.lppProfileMask);
+ 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++;
+ }
+
+ if (gnssConfigRequested.flags & GNSS_CONFIG_FLAGS_MIN_SV_ELEVATION_BIT) {
+ GnssConfig gnssConfig = {};
+ gnssConfig.flags = GNSS_CONFIG_FLAGS_MIN_SV_ELEVATION_BIT;
+ gnssConfig.minSvElevation = gnssConfigRequested.minSvElevation;
+ err = mLocApi->setParameterSync(gnssConfig);
+ if (index < count) {
+ errsList[index] = err;
+ }
+ index++;
+ }
+
+ return errsList;
+}
+
+uint32_t*
+GnssAdapter::gnssUpdateConfigCommand(const 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(nullptr) {
+ if (mCount > 0) {
+ mIds = new uint32_t[count];
+ if (mIds) {
+ for (uint32_t index = 0; index < count; index++) {
+ mIds[index] = ids[index];
+ }
+ } else {
+ LOC_LOGe("memory allocation for mIds failed");
+ }
+ }
+ }
+
+ inline MsgGnssUpdateConfig(const MsgGnssUpdateConfig& obj) :
+ MsgGnssUpdateConfig(obj.mAdapter, obj.mApi, obj.mConfig,
+ obj.mIds, obj.mCount) {}
+
+ inline virtual ~MsgGnssUpdateConfig()
+ {
+ if (nullptr != mIds) 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;
+ bool needSuspendResume = false;
+
+ 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 newLppProfileMask = gnssConfigRequested.lppProfileMask;
+ ContextBase::mGps_conf.LPP_PROFILE = newLppProfileMask;
+ 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++;
+ }
+
+ if (gnssConfigRequested.flags & GNSS_CONFIG_FLAGS_MIN_SV_ELEVATION_BIT) {
+ needSuspendResume = true;
+ index++;
+ }
+
+ if (needSuspendResume == true) {
+ mAdapter.suspendSessions();
+ }
+ 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] () mutable {
+ std::vector<LocationError> errsList = adapter.gnssUpdateConfig("",
+ gnssConfigRequested, gnssConfigNeedEngineUpdate, countOfConfigs);
+
+ configCollectiveResponse->returnToSender(errsList);
+ }));
+
+ if (needSuspendResume == true) {
+ mAdapter.restartSessions();
+ }
+ }
+ };
+
+ 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 ", sbas 0x%" PRIx64 ", navic 0x%" PRIx64,
+ mGnssSvIdConfig.bdsBlacklistSvMask, mGnssSvIdConfig.gloBlacklistSvMask,
+ mGnssSvIdConfig.qzssBlacklistSvMask, mGnssSvIdConfig.galBlacklistSvMask,
+ mGnssSvIdConfig.sbasBlacklistSvMask, mGnssSvIdConfig.navicBlacklistSvMask);
+ // 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 ", sbas 0x%" PRIx64 ", navic 0x%" PRIx64,
+ mGnssSvIdConfig.bdsBlacklistSvMask, mGnssSvIdConfig.gloBlacklistSvMask,
+ mGnssSvIdConfig.qzssBlacklistSvMask, mGnssSvIdConfig.galBlacklistSvMask,
+ mGnssSvIdConfig.sbasBlacklistSvMask, mGnssSvIdConfig.navicBlacklistSvMask);
+
+ // Now set required blacklisted SVs
+ return mLocApi->setBlacklistSvSync(mGnssSvIdConfig);
+}
+
+void
+GnssAdapter::gnssSecondaryBandConfigUpdate(LocApiResponse* locApiResponse)
+{
+ LOC_LOGd("secondary band config, size %d, enabled constellation 0x%" PRIx64 ","
+ "disabled constellation 0x%" PRIx64 "", mGnssSeconaryBandConfig.size,
+ mGnssSeconaryBandConfig.enabledSvTypesMask,
+ mGnssSeconaryBandConfig.blacklistedSvTypesMask);
+ if (mGnssSeconaryBandConfig.size == sizeof(mGnssSeconaryBandConfig)) {
+ // Now set required secondary band config
+ mLocApi->configConstellationMultiBand(mGnssSeconaryBandConfig, locApiResponse);
+ }
+}
+
+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),
+ mCount(count),
+ mIds(nullptr) {
+ if (mCount > 0) {
+ mIds = new uint32_t[count];
+ if (mIds) {
+ for (uint32_t index = 0; index < count; index++) {
+ mIds[index] = ids[index];
+ }
+ } else {
+ LOC_LOGe("memory allocation for mIds failed");
+ }
+ }
+ }
+
+ inline MsgGnssGetConfig(const MsgGnssGetConfig& obj) :
+ MsgGnssGetConfig(obj.mAdapter, obj.mApi, obj.mConfigMask,
+ obj.mIds, obj.mCount) {}
+
+ inline virtual ~MsgGnssGetConfig()
+ {
+ if (nullptr != mIds) 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;
+ }
+ }
+ if (mConfigMask & GNSS_CONFIG_FLAGS_ROBUST_LOCATION_BIT) {
+ uint32_t sessionId = *(mIds+index);
+ LocApiResponse* locApiResponse =
+ new LocApiResponse(*mAdapter.getContext(),
+ [this, sessionId] (LocationError err) {
+ mAdapter.reportResponse(err, sessionId);});
+ if (!locApiResponse) {
+ LOC_LOGe("memory alloc failed");
+ mAdapter.reportResponse(LOCATION_ERROR_GENERAL_FAILURE, sessionId);
+ } else {
+ mApi.getRobustLocationConfig(sessionId, locApiResponse);
+ }
+ }
+
+ if (mConfigMask & GNSS_CONFIG_FLAGS_MIN_GPS_WEEK_BIT) {
+ uint32_t sessionId = *(mIds+index);
+ LocApiResponse* locApiResponse =
+ new LocApiResponse(*mAdapter.getContext(),
+ [this, sessionId] (LocationError err) {
+ mAdapter.reportResponse(err, sessionId);});
+ if (!locApiResponse) {
+ LOC_LOGe("memory alloc failed");
+ mAdapter.reportResponse(LOCATION_ERROR_GENERAL_FAILURE, sessionId);
+ } else {
+ mApi.getMinGpsWeek(sessionId, locApiResponse);
+ }
+ }
+
+ if (mConfigMask & GNSS_CONFIG_FLAGS_MIN_SV_ELEVATION_BIT) {
+ uint32_t sessionId = *(mIds+index);
+ LocApiResponse* locApiResponse =
+ new LocApiResponse(*mAdapter.getContext(),
+ [this, sessionId] (LocationError err) {
+ mAdapter.reportResponse(err, sessionId);});
+ if (!locApiResponse) {
+ LOC_LOGe("memory alloc failed");
+ mAdapter.reportResponse(LOCATION_ERROR_GENERAL_FAILURE, sessionId);
+ } else {
+ mApi.getParameter(sessionId, GNSS_CONFIG_FLAGS_MIN_SV_ELEVATION_BIT,
+ locApiResponse);
+ }
+ }
+
+ 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;
+ config.sbasBlacklistSvMask = 0;
+ config.navicBlacklistSvMask = 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;
+ uint16_t svIndexOffset = 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;
+ case GNSS_SV_TYPE_SBAS:
+ // SBAS does not support enable/disable whole constellation
+ // so do not set up svTypeMask for SBAS
+ svMaskPtr = &config.sbasBlacklistSvMask;
+ // SBAS currently has two ranges, [120, 158] and [183, 191]
+ if (0 == source.svId) {
+ LOC_LOGd("blacklist all SBAS SV");
+ } else if (source.svId >= GNSS_SV_CONFIG_SBAS_INITIAL2_SV_ID) {
+ // handle SV id in range [183, 191]
+ initialSvId = GNSS_SV_CONFIG_SBAS_INITIAL2_SV_ID;
+ svIndexOffset = GNSS_SV_CONFIG_SBAS_INITIAL_SV_LENGTH;
+ } else if ((source.svId >= GNSS_SV_CONFIG_SBAS_INITIAL_SV_ID) &&
+ (source.svId < (GNSS_SV_CONFIG_SBAS_INITIAL_SV_ID +
+ GNSS_SV_CONFIG_SBAS_INITIAL_SV_LENGTH))){
+ // handle SV id in range of [120, 158]
+ initialSvId = GNSS_SV_CONFIG_SBAS_INITIAL_SV_ID;
+ } else {
+ LOC_LOGe("invalid SBAS sv id %d", source.svId);
+ svMaskPtr = nullptr;
+ }
+ break;
+ case GNSS_SV_TYPE_NAVIC:
+ svMaskPtr = &config.navicBlacklistSvMask;
+ initialSvId = GNSS_SV_CONFIG_NAVIC_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 {
+ uint32_t shiftCnt = source.svId + svIndexOffset - initialSvId;
+ *svMaskPtr |= (1ULL << shiftCnt);
+ }
+ }
+ }
+
+ // Return true if any one source is valid
+ if (0 != config.gloBlacklistSvMask ||
+ 0 != config.bdsBlacklistSvMask ||
+ 0 != config.galBlacklistSvMask ||
+ 0 != config.qzssBlacklistSvMask ||
+ 0 != config.sbasBlacklistSvMask ||
+ 0 != config.navicBlacklistSvMask) {
+ retVal = true;
+ }
+ }
+
+ LOC_LOGd("blacklist bds 0x%" PRIx64 ", glo 0x%" PRIx64
+ ", qzss 0x%" PRIx64 ", gal 0x%" PRIx64 ", sbas 0x%" PRIx64 ", navic 0x%" PRIx64,
+ config.bdsBlacklistSvMask, config.gloBlacklistSvMask,
+ config.qzssBlacklistSvMask, config.galBlacklistSvMask,
+ config.sbasBlacklistSvMask, config.navicBlacklistSvMask);
+
+ return retVal;
+}
+
+void GnssAdapter::convertFromGnssSvIdConfig(
+ const GnssSvIdConfig& svConfig, std::vector<GnssSvIdSource>& blacklistedSvIds)
+{
+ // Convert blacklisted SV mask values to vectors
+ if (svConfig.bdsBlacklistSvMask) {
+ convertGnssSvIdMaskToList(
+ svConfig.bdsBlacklistSvMask, blacklistedSvIds,
+ GNSS_SV_CONFIG_BDS_INITIAL_SV_ID, GNSS_SV_TYPE_BEIDOU);
+ }
+ if (svConfig.galBlacklistSvMask) {
+ convertGnssSvIdMaskToList(
+ svConfig.galBlacklistSvMask, blacklistedSvIds,
+ GNSS_SV_CONFIG_GAL_INITIAL_SV_ID, GNSS_SV_TYPE_GALILEO);
+ }
+ if (svConfig.gloBlacklistSvMask) {
+ convertGnssSvIdMaskToList(
+ svConfig.gloBlacklistSvMask, blacklistedSvIds,
+ GNSS_SV_CONFIG_GLO_INITIAL_SV_ID, GNSS_SV_TYPE_GLONASS);
+ }
+ if (svConfig.qzssBlacklistSvMask) {
+ convertGnssSvIdMaskToList(
+ svConfig.qzssBlacklistSvMask, blacklistedSvIds,
+ GNSS_SV_CONFIG_QZSS_INITIAL_SV_ID, GNSS_SV_TYPE_QZSS);
+ }
+ if (svConfig.sbasBlacklistSvMask) {
+ // SBAS - SV 120 to 158, maps to 0 to 38
+ // SV 183 to 191, maps to 39 to 47
+ uint64_t sbasBlacklistSvMask = svConfig.sbasBlacklistSvMask;
+ // operate on 120 and 158 first
+ sbasBlacklistSvMask <<= (64 - GNSS_SV_CONFIG_SBAS_INITIAL_SV_LENGTH);
+ sbasBlacklistSvMask >>= (64 - GNSS_SV_CONFIG_SBAS_INITIAL_SV_LENGTH);
+ convertGnssSvIdMaskToList(
+ sbasBlacklistSvMask, blacklistedSvIds,
+ GNSS_SV_CONFIG_SBAS_INITIAL_SV_ID, GNSS_SV_TYPE_SBAS);
+ // operate on the second range
+ sbasBlacklistSvMask = svConfig.sbasBlacklistSvMask;
+ sbasBlacklistSvMask >>= GNSS_SV_CONFIG_SBAS_INITIAL_SV_LENGTH;
+ convertGnssSvIdMaskToList(
+ sbasBlacklistSvMask, blacklistedSvIds,
+ GNSS_SV_CONFIG_SBAS_INITIAL2_SV_ID, GNSS_SV_TYPE_SBAS);
+ }
+ if (svConfig.navicBlacklistSvMask) {
+ convertGnssSvIdMaskToList(
+ svConfig.navicBlacklistSvMask, blacklistedSvIds,
+ GNSS_SV_CONFIG_NAVIC_INITIAL_SV_ID, GNSS_SV_TYPE_NAVIC);
+ }
+}
+
+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) {
+ LOC_LOGd("blacklist all SVs in constellation %d", source.constellation);
+ 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;
+ // SBAS has two ranges:
+ // SBAS - SV 120 to 158, maps to 0 to 38
+ // SV 183 to 191, maps to 39 to 47
+ // #define GNSS_SV_CONFIG_SBAS_INITIAL_SV_ID 120
+ // #define GNSS_SV_CONFIG_SBAS_INITIAL_SV_LENGTH 39
+ // #define GNSS_SV_CONFIG_SBAS_INITIAL2_SV_ID 183
+ if (svType == GNSS_SV_TYPE_SBAS) {
+ if (bitNumber >= GNSS_SV_CONFIG_SBAS_INITIAL_SV_LENGTH) {
+ source.svId = bitNumber - GNSS_SV_CONFIG_SBAS_INITIAL_SV_LENGTH +
+ GNSS_SV_CONFIG_SBAS_INITIAL2_SV_ID;
+ }
+ }
+ 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.blacklistedSvIds);
+ if (config.blacklistedSvIds.size() > 0) {
+ config.flags |= GNSS_CONFIG_FLAGS_BLACKLISTED_SV_IDS_BIT;
+ }
+ LOC_LOGd("blacklist bds 0x%" PRIx64 ", glo 0x%" PRIx64 ", "
+ "qzss 0x%" PRIx64 ", gal 0x%" PRIx64 ", sbas 0x%" PRIx64 ", navic 0x%" PRIx64,
+ svIdConfig.bdsBlacklistSvMask, svIdConfig.gloBlacklistSvMask,
+ svIdConfig.qzssBlacklistSvMask, svIdConfig.galBlacklistSvMask,
+ svIdConfig.sbasBlacklistSvMask, svIdConfig.navicBlacklistSvMask);
+ // use 0 session id to indicate that receiver does not yet care about session id
+ mControlCallbacks.gnssConfigCb(0, 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);
+
+ LOC_LOGd("blacklist bds 0x%" PRIx64 ", glo 0x%" PRIx64
+ ", qzss 0x%" PRIx64 ", gal 0x%" PRIx64 ", sbas 0x%" PRIx64 ", Navic 0x%" PRIx64,
+ mGnssSvIdConfig.bdsBlacklistSvMask, mGnssSvIdConfig.gloBlacklistSvMask,
+ mGnssSvIdConfig.qzssBlacklistSvMask, mGnssSvIdConfig.galBlacklistSvMask,
+ mGnssSvIdConfig.sbasBlacklistSvMask, mGnssSvIdConfig.navicBlacklistSvMask);
+
+ LOC_LOGd("blacklist bds 0x%" PRIx64 ", glo 0x%" PRIx64
+ ", qzss 0x%" PRIx64 ", gal 0x%" PRIx64 ", sbas 0x%" PRIx64 ", Navic 0x%" PRIx64,
+ mGnssSvIdConfig.bdsBlacklistSvMask, mGnssSvIdConfig.gloBlacklistSvMask,
+ mGnssSvIdConfig.qzssBlacklistSvMask, mGnssSvIdConfig.galBlacklistSvMask,
+ mGnssSvIdConfig.sbasBlacklistSvMask, mGnssSvIdConfig.navicBlacklistSvMask);
+
+ 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;
+ }
+ if (mGnssSvTypeConfig.blacklistedSvTypesMask & GNSS_SV_TYPES_MASK_NAVIC_BIT) {
+ blacklistConfig.navicBlacklistSvMask = 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) {
+ struct timespec bootDeleteAidingDataTime;
+ int64_t bootDeleteTimeMs;
+ if (clock_gettime(CLOCK_BOOTTIME, &bootDeleteAidingDataTime) == 0) {
+ bootDeleteTimeMs = bootDeleteAidingDataTime.tv_sec * 1000000;
+ int64_t diffTimeBFirSecDelete = bootDeleteTimeMs - mLastDeleteAidingDataTime;
+ if (diffTimeBFirSecDelete > DELETE_AIDING_DATA_EXPECTED_TIME_MS) {
+ mLocApi->deleteAidingData(data, new LocApiResponse(*getContext(),
+ [this, sessionId] (LocationError err) {
+ reportResponse(err, sessionId);
+ }));
+ mLastDeleteAidingDataTime = bootDeleteTimeMs;
+ }
+ }
+}
+
+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();
+ }
+ }
+
+ bool retVal = mAdapter.mEngHubProxy->gnssDeleteAidingData(mData);
+ // When SPE engine is invoked, responseCb will be invoked
+ // from QMI Loc API call.
+ // When SPE engine is not invoked, we also need to deliver responseCb
+ if ((mData.posEngineMask & STANDARD_POSITIONING_ENGINE) == 0) {
+ LocationError err = LOCATION_ERROR_NOT_SUPPORTED;
+ if (retVal == true) {
+ err = LOCATION_ERROR_SUCCESS;
+ }
+ mAdapter.reportResponse(err, mSessionId);
+ }
+ }
+ };
+
+ 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;
+ bool mOnDemandCpi;
+ inline MsgInjectLocation(LocApiBase& api,
+ ContextBase& context,
+ BlockCPIInfo& blockCPIInfo,
+ double latitude,
+ double longitude,
+ float accuracy,
+ bool onDemandCpi) :
+ LocMsg(),
+ mApi(api),
+ mContext(context),
+ mBlockCPI(blockCPIInfo),
+ mLatitude(latitude),
+ mLongitude(longitude),
+ mAccuracy(accuracy),
+ mOnDemandCpi(onDemandCpi) {}
+ 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 injection blocked: lat: %f, lon: %f, accuracy: %f",
+ __func__, mLatitude, mLongitude, mAccuracy);
+
+ } else {
+ mApi.injectPosition(mLatitude, mLongitude, mAccuracy, mOnDemandCpi);
+ }
+ }
+ };
+
+ sendMsg(new MsgInjectLocation(*mLocApi, *mContext, mBlockCPIInfo,
+ latitude, longitude, accuracy, mOdcpiRequestActive));
+}
+
+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::updateSystemPowerState(PowerStateType systemPowerState) {
+ if (POWER_STATE_UNKNOWN != systemPowerState) {
+ mSystemPowerState = systemPowerState;
+ mLocApi->updateSystemPowerState(mSystemPowerState);
+ }
+}
+
+void
+GnssAdapter::updateSystemPowerStateCommand(PowerStateType systemPowerState) {
+ LOC_LOGd("power event %d", systemPowerState);
+
+ struct MsgUpdatePowerState : public LocMsg {
+ GnssAdapter& mAdapter;
+ PowerStateType mSystemPowerState;
+
+ inline MsgUpdatePowerState(GnssAdapter& adapter,
+ PowerStateType systemPowerState) :
+ LocMsg(),
+ mAdapter(adapter),
+ mSystemPowerState(systemPowerState) {}
+ inline virtual void proc() const {
+ mAdapter.updateSystemPowerState(mSystemPowerState);
+ }
+ };
+
+ sendMsg(new MsgUpdatePowerState(*this, systemPowerState));
+}
+
+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);
+ eraseTrackingSession(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()
+{
+ // need to register for leap second info
+ // for proper nmea generation
+ LOC_API_ADAPTER_EVENT_MASK_T mask = LOC_API_ADAPTER_BIT_LOC_SYSTEM_INFO |
+ LOC_API_ADAPTER_BIT_EVENT_REPORT_INFO;
+ for (auto it=mClientData.begin(); it != mClientData.end(); ++it) {
+ if (it->second.trackingCb != nullptr ||
+ it->second.gnssLocationInfoCb != nullptr ||
+ it->second.engineLocationsInfoCb != 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_SV_POLYNOMIAL_REPORT;
+ mask |= LOC_API_ADAPTER_BIT_PARSED_UNPROPAGATED_POSITION_REPORT;
+ mask |= LOC_API_ADAPTER_BIT_GNSS_SV_EPHEMERIS_REPORT;
+
+ // Nhz measurement bit is set based on callback from loc eng hub
+ // for Nhz engines.
+ mask |= checkMask(LOC_API_ADAPTER_BIT_GNSS_NHZ_MEASUREMENT);
+
+ 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;
+
+ // Enable the latency report
+ if (mask & LOC_API_ADAPTER_BIT_GNSS_MEASUREMENT) {
+ if (mLogger.isLogEnabled()) {
+ mask |= LOC_API_ADAPTER_BIT_LATENCY_INFORMATION;
+ }
+ }
+
+ 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.gnssSvIdConfigUpdate();
+ mAdapter.gnssSvTypeConfigUpdate();
+ mAdapter.updateSystemPowerState(mAdapter.getSystemPowerState());
+ mAdapter.gnssSecondaryBandConfigUpdate();
+ // start CDFW service
+ mAdapter.initCDFWService();
+ // restart sessions
+ mAdapter.restartSessions(true);
+ for (auto msg: mAdapter.mPendingMsgs) {
+ mAdapter.sendMsg(msg);
+ }
+ mAdapter.mPendingMsgs.clear();
+ }
+ };
+
+ readConfigCommand();
+ sendMsg(new MsgHandleEngineUpEvent(*this));
+}
+
+void
+GnssAdapter::restartSessions(bool modemSSR)
+{
+ LOC_LOGi(":enter");
+
+ if (modemSSR) {
+ // odcpi session is no longer active after restart
+ mOdcpiRequestActive = false;
+ }
+
+ // SPE will be restarted now, so set this variable to false.
+ mSPEAlreadyRunningAtHighestInterval = false;
+
+ if (false == mTimeBasedTrackingSessions.empty()) {
+ // inform engine hub that GNSS session is about to start
+ mEngHubProxy->gnssSetFixMode(mLocPositionMode);
+ mEngHubProxy->gnssStartFix();
+ checkUpdateDgnssNtrip(false);
+ }
+
+ checkAndRestartSPESession();
+}
+
+void GnssAdapter::checkAndRestartSPESession()
+{
+ LOC_LOGD("%s]: ", __func__);
+
+ // SPE will be restarted now, so set this variable to false.
+ mSPEAlreadyRunningAtHighestInterval = false;
+
+ checkAndRestartTimeBasedSession();
+
+ for (auto it = mDistanceBasedTrackingSessions.begin();
+ it != mDistanceBasedTrackingSessions.end(); ++it) {
+ mLocApi->startDistanceBasedTracking(it->first.id, it->second,
+ new LocApiResponse(*getContext(),
+ [] (LocationError /*err*/) {}));
+ }
+}
+
+// suspend all on-going sessions
+void
+GnssAdapter::suspendSessions()
+{
+ LOC_LOGi(":enter");
+
+ if (!mTimeBasedTrackingSessions.empty()) {
+ // inform engine hub that GNSS session has stopped
+ mEngHubProxy->gnssStopFix();
+ mLocApi->stopFix(nullptr);
+ if (isDgnssNmeaRequired()) {
+ mDgnssState &= ~DGNSS_STATE_NO_NMEA_PENDING;
+ }
+ stopDgnssNtrip();
+ mSPEAlreadyRunningAtHighestInterval = false;
+ }
+}
+
+void GnssAdapter::checkAndRestartTimeBasedSession()
+{
+ LOC_LOGD("%s]: ", __func__);
+
+ 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);
+ // want to run SPE session at a fixed min interval in some automotive scenarios
+ if(!checkAndSetSPEToRunforNHz(highestPowerTrackingOptions)) {
+ mLocApi->startTimeBasedTracking(highestPowerTrackingOptions, nullptr);
+ }
+ }
+}
+
+LocationCapabilitiesMask
+GnssAdapter::getCapabilities()
+{
+ LocationCapabilitiesMask mask = 0;
+ uint32_t carrierCapabilities = ContextBase::getCarrierCapabilities();
+ // time based tracking always supported
+ mask |= LOCATION_CAPABILITIES_TIME_BASED_TRACKING_BIT;
+ // geofence always supported
+ mask |= LOCATION_CAPABILITIES_GEOFENCE_BIT;
+ 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::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;
+ }
+ if (ContextBase::gnssConstellationConfig()) {
+ mask |= LOCATION_CAPABILITIES_GNSS_MEASUREMENTS_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;
+ }
+ //Get QWES feature status mask
+ mask |= ContextBase::getQwesFeatureStatus();
+ return mask;
+}
+
+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::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::hasCallbacksToStartTracking(LocationAPI* client)
+{
+ bool allowed = false;
+ auto it = mClientData.find(client);
+ if (it != mClientData.end()) {
+ if (it->second.trackingCb || it->second.gnssLocationInfoCb ||
+ it->second.engineLocationsInfoCb || it->second.gnssMeasurementsCb ||
+ it->second.gnssDataCb || it->second.gnssSvCb || it->second.gnssNmeaCb) {
+ allowed = true;
+ } else {
+ LOC_LOGi("missing right callback to start tracking")
+ }
+ } else {
+ LOC_LOGi("client %p not found", client)
+ }
+ return allowed;
+}
+
+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(std::function<void(bool)> powerStateCb)
+{
+ LOC_LOGD("%s]: ", __func__);
+
+ struct MsgReportLocation : public LocMsg {
+ GnssAdapter& mAdapter;
+ std::function<void(bool)> mPowerStateCb;
+ inline MsgReportLocation(GnssAdapter& adapter,
+ std::function<void(bool)> powerStateCb) :
+ LocMsg(),
+ mAdapter(adapter),
+ mPowerStateCb(powerStateCb) {}
+ inline virtual void proc() const {
+ mAdapter.savePowerStateCallback(mPowerStateCb);
+ mPowerStateCb(mAdapter.getPowerState());
+ }
+ };
+
+ sendMsg(new MsgReportLocation(*this, 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.hasCallbacksToStartTracking(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()) {
+ /*Reset previous NMEA reported time stamp */
+ mPrevNmeaRptTimeNsec = 0;
+ 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);
+ // save position mode parameters
+ setLocPositionMode(locPosMode);
+ // inform engine hub that GNSS session is about to start
+ mEngHubProxy->gnssSetFixMode(mLocPositionMode);
+ mEngHubProxy->gnssStartFix();
+
+ // want to run SPE session at a fixed min interval in some automotive scenarios
+ // use a local copy of TrackingOptions as the TBF may get modified in the
+ // checkAndSetSPEToRunforNHz function
+ TrackingOptions tempOptions(trackingOptions);
+ if (!checkAndSetSPEToRunforNHz(tempOptions)) {
+ mLocApi->startTimeBasedTracking(tempOptions, new LocApiResponse(*getContext(),
+ [this, client, sessionId] (LocationError err) {
+ if (LOCATION_ERROR_SUCCESS != err) {
+ eraseTrackingSession(client, sessionId);
+ } else {
+ checkUpdateDgnssNtrip(false);
+ }
+
+ reportResponse(client, err, sessionId);
+ }
+ ));
+ } else {
+ reportResponse(client, LOCATION_ERROR_SUCCESS, sessionId);
+ }
+
+}
+
+void
+GnssAdapter::updateTracking(LocationAPI* client, uint32_t sessionId,
+ const TrackingOptions& updatedOptions, const TrackingOptions& oldOptions)
+{
+ LocPosMode locPosMode = {};
+ convertOptions(locPosMode, updatedOptions);
+ // save position mode parameters
+ setLocPositionMode(locPosMode);
+
+ // inform engine hub that GNSS session is about to start
+ mEngHubProxy->gnssSetFixMode(mLocPositionMode);
+ mEngHubProxy->gnssStartFix();
+
+ // want to run SPE session at a fixed min interval in some automotive scenarios
+ // use a local copy of TrackingOptions as the TBF may get modified in the
+ // checkAndSetSPEToRunforNHz function
+ TrackingOptions tempOptions(updatedOptions);
+ if(!checkAndSetSPEToRunforNHz(tempOptions)) {
+ mLocApi->startTimeBasedTracking(tempOptions, 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);
+ }
+ ));
+ } else {
+ reportResponse(client, LOCATION_ERROR_SUCCESS, 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);
+ }));
+
+ if (isDgnssNmeaRequired()) {
+ mDgnssState &= ~DGNSS_STATE_NO_NMEA_PENDING;
+ }
+ stopDgnssNtrip();
+
+ mSPEAlreadyRunningAtHighestInterval = false;
+}
+
+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));
+ }
+
+}
+
+// This function computes the VRP based latitude, longitude and alittude, and
+// north, east and up velocity and save the result into EHubTechReport.
+void
+GnssAdapter::computeVRPBasedLla(const UlpLocation& loc, GpsLocationExtended& locExt,
+ const LeverArmConfigInfo& leverArmConfigInfo) {
+
+ float leverArm[3];
+ float rollPitchYaw[3];
+ double lla[3];
+
+ uint16_t locFlags = loc.gpsLocation.flags;
+ uint64_t locExtFlags = locExt.flags;
+
+ // check for SPE fix
+ if (!((locExtFlags & GPS_LOCATION_EXTENDED_HAS_OUTPUT_ENG_TYPE) &&
+ (locExt.locOutputEngType == LOC_OUTPUT_ENGINE_SPE))){
+ LOC_LOGv("not SPE fix, return");
+ return;
+ }
+
+ // we can only do translation if we have VRP based lever ARM info
+ LeverArmTypeMask leverArmFlags = leverArmConfigInfo.leverArmValidMask;
+ if (!(leverArmFlags & LEVER_ARM_TYPE_GNSS_TO_VRP_BIT)) {
+ LOC_LOGd("no VRP based lever ARM info");
+ return;
+ }
+
+ leverArm[0] = leverArmConfigInfo.gnssToVRP.forwardOffsetMeters;
+ leverArm[1] = leverArmConfigInfo.gnssToVRP.sidewaysOffsetMeters;
+ leverArm[2] = leverArmConfigInfo.gnssToVRP.upOffsetMeters;
+
+ if ((locFlags & LOC_GPS_LOCATION_HAS_LAT_LONG) &&
+ (locFlags & LOC_GPS_LOCATION_HAS_ALTITUDE) &&
+ (locFlags & LOCATION_HAS_BEARING_BIT)) {
+
+ lla[0] = loc.gpsLocation.latitude * DEG2RAD;
+ lla[1] = loc.gpsLocation.longitude * DEG2RAD;
+ lla[2] = loc.gpsLocation.altitude;
+
+ rollPitchYaw[0] = 0.0f;
+ rollPitchYaw[1] = 0.0f;
+ rollPitchYaw[2] = loc.gpsLocation.bearing * DEG2RAD;
+
+ loc_convert_lla_gnss_to_vrp(lla, rollPitchYaw, leverArm);
+
+ // assign the converted value into position report and
+ // set up valid mask
+ locExt.llaVRPBased.latitude = lla[0] * RAD2DEG;
+ locExt.llaVRPBased.longitude = lla[1] * RAD2DEG;
+ locExt.llaVRPBased.altitude = lla[2];
+ locExt.flags |= GPS_LOCATION_EXTENDED_HAS_LLA_VRP_BASED;
+ } else {
+ LOC_LOGd("SPE fix missing latitude/longitude/alitutde");
+ return;
+ }
+}
+
+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
+ // also, send out SPE fix promptly to the clients that have registered
+ // with SPE report
+ LOC_LOGd("reportPositionEvent, eng type: %d, unpro %d, sess status %d msInWeek %d",
+ locationExtended.locOutputEngType,
+ ulpLocation.unpropagatedPosition, status, msInWeek);
+
+ struct MsgReportSPEPosition : public LocMsg {
+ GnssAdapter& mAdapter;
+ mutable UlpLocation mUlpLocation;
+ mutable GpsLocationExtended mLocationExtended;
+ enum loc_sess_status mStatus;
+ LocPosTechMask mTechMask;
+ mutable GnssDataNotification mDataNotify;
+ int mMsInWeek;
+
+ inline MsgReportSPEPosition(GnssAdapter& adapter,
+ const UlpLocation& ulpLocation,
+ const GpsLocationExtended& locationExtended,
+ enum loc_sess_status status,
+ LocPosTechMask techMask,
+ GnssDataNotification dataNotify,
+ int msInWeek) :
+ LocMsg(),
+ mAdapter(adapter),
+ mUlpLocation(ulpLocation),
+ mLocationExtended(locationExtended),
+ mStatus(status),
+ mTechMask(techMask),
+ mDataNotify(dataNotify),
+ mMsInWeek(msInWeek) {}
+ inline virtual void proc() const {
+ if (mAdapter.mTimeBasedTrackingSessions.empty() &&
+ mAdapter.mDistanceBasedTrackingSessions.empty()) {
+ LOC_LOGd("reportPositionEvent, no session on-going, throw away the SPE reports");
+ return;
+ }
+
+ if (false == mUlpLocation.unpropagatedPosition && mDataNotify.size != 0) {
+ if (mMsInWeek >= 0) {
+ mAdapter.getDataInformation((GnssDataNotification&)mDataNotify,
+ mMsInWeek);
+ }
+ mAdapter.reportData(mDataNotify);
+ }
+
+ if (true == mAdapter.initEngHubProxy()){
+ // send the SPE fix to engine hub
+ mAdapter.mEngHubProxy->gnssReportPosition(mUlpLocation, mLocationExtended, mStatus);
+ // report out all SPE fix if it is not propagated, even for failed fix
+ if (false == mUlpLocation.unpropagatedPosition) {
+ EngineLocationInfo engLocationInfo = {};
+ engLocationInfo.location = mUlpLocation;
+ engLocationInfo.locationExtended = mLocationExtended;
+ engLocationInfo.sessionStatus = mStatus;
+
+ // obtain the VRP based latitude/longitude/altitude for SPE fix
+ computeVRPBasedLla(engLocationInfo.location,
+ engLocationInfo.locationExtended,
+ mAdapter.mLocConfigInfo.leverArmConfigInfo);
+ mAdapter.reportEnginePositions(1, &engLocationInfo);
+ }
+ return;
+ }
+
+ // unpropagated report: is only for engine hub to consume and no need
+ // to send out to the clients
+ if (true == mUlpLocation.unpropagatedPosition) {
+ return;
+ }
+
+ // 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 (mContext != NULL) {
+ GnssDataNotification dataNotifyCopy = {};
+ if (pDataNotify) {
+ dataNotifyCopy = *pDataNotify;
+ dataNotifyCopy.size = sizeof(dataNotifyCopy);
+ }
+ sendMsg(new MsgReportSPEPosition(*this, ulpLocation, locationExtended,
+ status, techMask, dataNotifyCopy, 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 (((LOC_SESS_INTERMEDIATE == status) && !(techMask & LOC_POS_TECH_MASK_SENSORS) &&
+ (!getAllowFlpNetworkFixes())) ||
+ (LOC_SESS_FAILURE == status)) {
+ 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);
+}
+
+bool GnssAdapter::needToGenerateNmeaReport(const uint32_t &gpsTimeOfWeekMs,
+ const struct timespec32_t &apTimeStamp)
+{
+ bool retVal = false;
+ uint64_t currentTimeNsec = 0;
+
+ if (NMEA_PROVIDER_AP == ContextBase::mGps_conf.NMEA_PROVIDER && !mTimeBasedTrackingSessions.empty()) {
+ currentTimeNsec = (apTimeStamp.tv_sec * BILLION_NSEC + apTimeStamp.tv_nsec);
+ if ((GNSS_NMEA_REPORT_RATE_NHZ == ContextBase::sNmeaReportRate) ||
+ (GPS_DEFAULT_FIX_INTERVAL_MS <= mLocPositionMode.min_interval)) {
+ retVal = true;
+ } else { /*tbf is less than 1000 milli-seconds and NMEA reporting rate is set to 1Hz */
+ /* Always send NMEA string for first position report
+ * Send when gpsTimeOfWeekMs is closely aligned with integer boundary
+ */
+ if ((0 == mPrevNmeaRptTimeNsec) ||
+ (0 != gpsTimeOfWeekMs) && (NMEA_MIN_THRESHOLD_MSEC >= (gpsTimeOfWeekMs % 1000))) {
+ retVal = true;
+ } else {
+ uint64_t timeDiffMsec = ((currentTimeNsec - mPrevNmeaRptTimeNsec) / 1000000);
+ // Send when the delta time becomes >= 1 sec
+ if (NMEA_MAX_THRESHOLD_MSEC <= timeDiffMsec) {
+ retVal = true;
+ }
+ }
+ }
+ if (true == retVal) {
+ mPrevNmeaRptTimeNsec = currentTimeNsec;
+ }
+ }
+ return retVal;
+}
+
+void
+GnssAdapter::logLatencyInfo()
+{
+ if (0 == mGnssLatencyInfoQueue.size()) {
+ LOC_LOGv("mGnssLatencyInfoQueue.size is 0");
+ return;
+ }
+ mGnssLatencyInfoQueue.front().hlosQtimer5 = getQTimerTickCount();
+ if (0 == mGnssLatencyInfoQueue.front().hlosQtimer3) {
+ /* if SPE from engine hub is not reported then hlosQtimer3 = 0, set it
+ equal to hlosQtimer2 to make sense */
+ LOC_LOGv("hlosQtimer3 is 0, setting it to hlosQtimer2");
+ mGnssLatencyInfoQueue.front().hlosQtimer3 = mGnssLatencyInfoQueue.front().hlosQtimer2;
+ }
+ if (0 == mGnssLatencyInfoQueue.front().hlosQtimer4) {
+ /* if PPE from engine hub is not reported then hlosQtimer4 = 0, set it
+ equal to hlosQtimer3 to make sense */
+ LOC_LOGv("hlosQtimer4 is 0, setting it to hlosQtimer3");
+ mGnssLatencyInfoQueue.front().hlosQtimer4 = mGnssLatencyInfoQueue.front().hlosQtimer3;
+ }
+ if (mGnssLatencyInfoQueue.front().hlosQtimer4 < mGnssLatencyInfoQueue.front().hlosQtimer3) {
+ /* hlosQtimer3 is timestamped when SPE from engine hub is reported,
+ and hlosQtimer4 is timestamped when PPE from engine hub is reported.
+ The order is random though, hence making sure the timestamps are sorted */
+ LOC_LOGv("hlosQtimer4 is < hlosQtimer3, swapping them");
+ std::swap(mGnssLatencyInfoQueue.front().hlosQtimer3,
+ mGnssLatencyInfoQueue.front().hlosQtimer4);
+ }
+ LOC_LOGv("meQtimer1=%" PRIi64 " "
+ "meQtimer2=%" PRIi64 " "
+ "meQtimer3=%" PRIi64 " "
+ "peQtimer1=%" PRIi64 " "
+ "peQtimer2=%" PRIi64 " "
+ "peQtimer3=%" PRIi64 " "
+ "smQtimer1=%" PRIi64 " "
+ "smQtimer2=%" PRIi64 " "
+ "smQtimer3=%" PRIi64 " "
+ "locMwQtimer=%" PRIi64 " "
+ "hlosQtimer1=%" PRIi64 " "
+ "hlosQtimer2=%" PRIi64 " "
+ "hlosQtimer3=%" PRIi64 " "
+ "hlosQtimer4=%" PRIi64 " "
+ "hlosQtimer5=%" PRIi64 " ",
+ mGnssLatencyInfoQueue.front().meQtimer1, mGnssLatencyInfoQueue.front().meQtimer2,
+ mGnssLatencyInfoQueue.front().meQtimer3, mGnssLatencyInfoQueue.front().peQtimer1,
+ mGnssLatencyInfoQueue.front().peQtimer2, mGnssLatencyInfoQueue.front().peQtimer3,
+ mGnssLatencyInfoQueue.front().smQtimer1, mGnssLatencyInfoQueue.front().smQtimer2,
+ mGnssLatencyInfoQueue.front().smQtimer3, mGnssLatencyInfoQueue.front().locMwQtimer,
+ mGnssLatencyInfoQueue.front().hlosQtimer1, mGnssLatencyInfoQueue.front().hlosQtimer2,
+ mGnssLatencyInfoQueue.front().hlosQtimer3, mGnssLatencyInfoQueue.front().hlosQtimer4,
+ mGnssLatencyInfoQueue.front().hlosQtimer5);
+ mLogger.log(mGnssLatencyInfoQueue.front());
+ mGnssLatencyInfoQueue.pop();
+ LOC_LOGv("mGnssLatencyInfoQueue.size after pop=%zu", mGnssLatencyInfoQueue.size());
+}
+
+// only fused report (when engine hub is enabled) or
+// SPE report (when engine hub is disabled) will reach this function
+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, status);
+ convertLocation(locationInfo.location, ulpLocation, locationExtended);
+ logLatencyInfo();
+ 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 PACE is enabled
+ if ((true == mLocConfigInfo.paceConfigInfo.isValid) &&
+ (true == mLocConfigInfo.paceConfigInfo.enable)) {
+ // If fix has sensor contribution, and it is fused fix with DRE engine
+ // contributing to the fix, inject to modem
+ if ((LOC_POS_TECH_MASK_SENSORS & techMask) &&
+ (locationInfo.flags & GNSS_LOCATION_INFO_OUTPUT_ENG_TYPE_BIT) &&
+ (locationInfo.locOutputEngType == LOC_OUTPUT_ENGINE_FUSED) &&
+ (locationInfo.flags & GNSS_LOCATION_INFO_OUTPUT_ENG_MASK_BIT) &&
+ (locationInfo.locOutputEngMask & DEAD_RECKONING_ENGINE)) {
+ mLocApi->injectPosition(locationInfo, false);
+ }
+ }
+ }
+ }
+
+ if (needToGenerateNmeaReport(locationExtended.gpsTime.gpsTimeOfWeekMs,
+ locationExtended.timeStamp.apTimeStamp)) {
+ /*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);
+ bool custom_nmea_gga = (1 == ContextBase::mGps_conf.CUSTOM_NMEA_GGA_FIX_QUALITY_ENABLED);
+ bool isTagBlockGroupingEnabled =
+ (1 == ContextBase::mGps_conf.NMEA_TAG_BLOCK_GROUPING_ENABLED);
+ std::vector<std::string> nmeaArraystr;
+ int indexOfGGA = -1;
+ loc_nmea_generate_pos(ulpLocation, locationExtended, mLocSystemInfo, generate_nmea,
+ custom_nmea_gga, nmeaArraystr, indexOfGGA, isTagBlockGroupingEnabled);
+ stringstream ss;
+ for (auto itor = nmeaArraystr.begin(); itor != nmeaArraystr.end(); ++itor) {
+ ss << *itor;
+ }
+ string s = ss.str();
+ reportNmea(s.c_str(), s.length());
+
+ /* DgnssNtrip */
+ if (-1 != indexOfGGA && isDgnssNmeaRequired()) {
+ mDgnssState |= DGNSS_STATE_NO_NMEA_PENDING;
+ mStartDgnssNtripParams.nmea = std::move(nmeaArraystr[indexOfGGA]);
+ bool isLocationValid = (0 != ulpLocation.gpsLocation.latitude) ||
+ (0 != ulpLocation.gpsLocation.longitude);
+ checkUpdateDgnssNtrip(isLocationValid);
+ }
+ }
+}
+
+void
+GnssAdapter::reportLatencyInfoEvent(const GnssLatencyInfo& gnssLatencyInfo)
+{
+ struct MsgReportLatencyInfo : public LocMsg {
+ GnssAdapter& mAdapter;
+ GnssLatencyInfo mGnssLatencyInfo;
+ inline MsgReportLatencyInfo(GnssAdapter& adapter,
+ const GnssLatencyInfo& gnssLatencyInfo) :
+ mGnssLatencyInfo(gnssLatencyInfo),
+ mAdapter(adapter) {}
+ inline virtual void proc() const {
+ mAdapter.mGnssLatencyInfoQueue.push(mGnssLatencyInfo);
+ LOC_LOGv("mGnssLatencyInfoQueue.size after push=%zu",
+ mAdapter.mGnssLatencyInfoQueue.size());
+ }
+ };
+ sendMsg(new MsgReportLatencyInfo(*this, gnssLatencyInfo));
+}
+
+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,
+ engLocation->sessionStatus);
+ convertLocation(locationInfo[i].location,
+ engLocation->location,
+ engLocation->locationExtended);
+ }
+ }
+
+ const EngineLocationInfo* engLocation = locationArr;
+ LOC_LOGv("engLocation->locationExtended.locOutputEngType=%d",
+ engLocation->locationExtended.locOutputEngType);
+
+ if (0 != mGnssLatencyInfoQueue.size()) {
+ if ((GPS_LOCATION_EXTENDED_HAS_OUTPUT_ENG_TYPE & engLocation->locationExtended.flags) &&
+ (LOC_OUTPUT_ENGINE_SPE == engLocation->locationExtended.locOutputEngType)) {
+ mGnssLatencyInfoQueue.front().hlosQtimer3 = getQTimerTickCount();
+ LOC_LOGv("SPE hlosQtimer3=%" PRIi64 " ", mGnssLatencyInfoQueue.front().hlosQtimer3);
+ }
+ if ((GPS_LOCATION_EXTENDED_HAS_OUTPUT_ENG_TYPE & engLocation->locationExtended.flags) &&
+ (LOC_OUTPUT_ENGINE_PPE == engLocation->locationExtended.locOutputEngType)) {
+ mGnssLatencyInfoQueue.front().hlosQtimer4 = getQTimerTickCount();
+ LOC_LOGv("PPE hlosQtimer4=%" PRIi64 " ", mGnssLatencyInfoQueue.front().hlosQtimer4);
+ }
+ }
+ 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;
+ uint16_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;
+ }
+ }
+ // map the svid to respective constellation range 1..xx
+ // then repective constellation svUsedIdMask map correctly to svid
+ gnssSvId = gnssSvId - GLO_SV_PRN_MIN + 1;
+ 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;
+ }
+ }
+ gnssSvId = gnssSvId - BDS_SV_PRN_MIN + 1;
+ 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;
+ }
+ }
+ gnssSvId = gnssSvId - GAL_SV_PRN_MIN + 1;
+ 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;
+ }
+ }
+ gnssSvId = gnssSvId - QZSS_SV_PRN_MIN + 1;
+ break;
+ case GNSS_SV_TYPE_NAVIC:
+ if (mGnssSvIdUsedInPosAvail) {
+ svUsedIdMask = mGnssSvIdUsedInPosition.navic_sv_used_ids_mask;
+ }
+ gnssSvId = gnssSvId - NAVIC_SV_PRN_MIN + 1;
+ 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 (svFitsMask(svUsedIdMask, gnssSvId) && (svUsedIdMask & (1ULL << (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;
+ mGnssMbSvIdUsedInPosAvail = 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);
+ // DgnssNtrip
+ mAdapter.reportGGAToNtrip(mNmea);
+ }
+ }
+ };
+
+ 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);
+ }
+ }
+
+ if (isNMEAPrintEnabled()) {
+ LOC_LOGd("[%" PRId64 ", %zu] %s", now, length, nmea);
+ }
+}
+
+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 (mMsInWeek >= 0) {
+ 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 ((mAdapter.mSupportNfwControl || 0 == mAdapter.getAfwControlId()) &&
+ (GNSS_NI_TYPE_SUPL == mNotify.type || GNSS_NI_TYPE_EMERGENCY_SUPL == mNotify.type)
+ && !bIsInEmergency &&
+ !(GNSS_NI_OPTIONS_PRIVACY_OVERRIDE_BIT & mNotify.options) &&
+ (GNSS_CONFIG_GPS_LOCK_NI & ContextBase::mGps_conf.GPS_LOCK) &&
+ 1 == ContextBase::mGps_conf.NI_SUPL_DENY_ON_NFW_LOCKED) {
+ /* If all these conditions are TRUE, then deny the NI Request:
+ -'Q' Lock behavior OR 'P' Lock behavior and GNSS is Locked
+ -NI SUPL Request type or NI SUPL Emergency Request type
+ -NOT in an Emergency Call Session
+ -NOT Privacy Override option
+ -NFW is locked and config item NI_SUPL_DENY_ON_NFW_LOCKED = 1 */
+ mApi.informNiResponse(GNSS_NI_RESPONSE_DENY, mData);
+ } else 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);
+ if (mDGnssNeedReport) {
+ reportDGnssDataUsable(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::reportDGnssDataUsable(const GnssSvMeasurementSet &svMeasurementSet)
+{
+ uint32_t i;
+ bool preDGnssDataUsage = mDGnssDataUsage;
+
+ mDGnssDataUsage = false;
+ for (i = 0; i < svMeasurementSet.svMeasCount; i++) {
+ const Gnss_SVMeasurementStructType& svMeas = svMeasurementSet.svMeas[i];
+ if (svMeas.dgnssSvMeas.dgnssMeasStatus) {
+ mDGnssDataUsage = true;
+ break;
+ }
+ }
+ if (mDGnssDataUsage != preDGnssDataUsage) {
+ if (mCdfwInterface) {
+ mCdfwInterface->reportUsable(mQDgnssListenerHDL, mDGnssDataUsage);
+ }
+ }
+}
+
+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 if (ODCPI_REQUEST_TYPE_STOP == request.type) {
+ LOC_LOGd("request: type %d, isEmergency %d", request.type, request.isEmergencyMode);
+ mOdcpiRequestCb(request);
+ mOdcpiRequestActive = false;
+ } else {
+ LOC_LOGE("Invalid ODCPI request type..");
+ }
+ } 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;
+}
+
+bool GnssAdapter::reportQwesCapabilities(
+ const std::unordered_map<LocationQwesFeatureType, bool> &featureMap)
+{
+ struct MsgReportQwesFeatureStatus : public LocMsg {
+ GnssAdapter& mAdapter;
+ const std::unordered_map<LocationQwesFeatureType, bool> mFeatureMap;
+ inline MsgReportQwesFeatureStatus(GnssAdapter& adapter,
+ const std::unordered_map<LocationQwesFeatureType, bool> &featureMap) :
+ LocMsg(),
+ mAdapter(adapter),
+ mFeatureMap(std::move(featureMap)) {}
+ inline virtual void proc() const {
+ LOC_LOGi("ReportQwesFeatureStatus before caps %" PRIx64 " ",
+ mAdapter.getCapabilities());
+ ContextBase::setQwesFeatureStatus(mFeatureMap);
+ LOC_LOGi("ReportQwesFeatureStatus After caps %" PRIx64 " ",
+ mAdapter.getCapabilities());
+ mAdapter.broadcastCapabilities(mAdapter.getCapabilities());
+ }
+ };
+
+ sendMsg(new MsgReportQwesFeatureStatus(*this, featureMap));
+ return true;
+}
+
+void GnssAdapter::initOdcpiCommand(const OdcpiRequestCallback& callback,
+ OdcpiPrioritytype priority)
+{
+ struct MsgInitOdcpi : public LocMsg {
+ GnssAdapter& mAdapter;
+ OdcpiRequestCallback mOdcpiCb;
+ OdcpiPrioritytype mPriority;
+ inline MsgInitOdcpi(GnssAdapter& adapter,
+ const OdcpiRequestCallback& callback,
+ OdcpiPrioritytype priority) :
+ LocMsg(),
+ mAdapter(adapter),
+ mOdcpiCb(callback), mPriority(priority){}
+ inline virtual void proc() const {
+ mAdapter.initOdcpi(mOdcpiCb, mPriority);
+ }
+ };
+
+ sendMsg(new MsgInitOdcpi(*this, callback, priority));
+}
+
+void GnssAdapter::initOdcpi(const OdcpiRequestCallback& callback,
+ OdcpiPrioritytype priority)
+{
+ LOC_LOGd("In priority: %d, Curr priority: %d", priority, mCallbackPriority);
+ if (priority >= mCallbackPriority) {
+ mOdcpiRequestCb = callback;
+ mCallbackPriority = priority;
+ /* 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;
+
+ LocAgpsGetAgpsCbInfo getAgpsCbInfo =
+ (LocAgpsGetAgpsCbInfo)dlGetSymFromLib(handle, "libloc_net_iface.so",
+ "LocNetIfaceAgps_getAgpsCbInfo");
+ // Below step is to make sure we init nativeAgpsHandler
+ // for Android platforms only
+ AgpsCbInfo cbInfo = {};
+ if (nullptr != getAgpsCbInfo) {
+ cbInfo = getAgpsCbInfo(agpsOpenResultCb, agpsCloseResultCb, this);
+ } else {
+ cbInfo = mNativeAgpsHandler.getAgpsCbInfo();
+ }
+
+ 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) != (unsigned)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");
+ }
+}
+
+// Set tunc constrained mode, use 0 session id to indicate
+// that no callback is needed. Session id 0 is used for calls that
+// are not invoked from the integration api, e.g.: initial configuration
+// from the configure file
+void
+GnssAdapter::setConstrainedTunc(bool enable, float tuncConstraint,
+ uint32_t energyBudget, uint32_t sessionId) {
+
+ mLocConfigInfo.tuncConfigInfo.isValid = true;
+ mLocConfigInfo.tuncConfigInfo.enable = enable;
+ mLocConfigInfo.tuncConfigInfo.tuncThresholdMs = tuncConstraint;
+ mLocConfigInfo.tuncConfigInfo.energyBudget = energyBudget;
+
+ LocApiResponse* locApiResponse = nullptr;
+ if (sessionId != 0) {
+ locApiResponse =
+ new LocApiResponse(*getContext(),
+ [this, sessionId] (LocationError err) {
+ reportResponse(err, sessionId);});
+ if (!locApiResponse) {
+ LOC_LOGe("memory alloc failed");
+ }
+ }
+ mLocApi->setConstrainedTuncMode(
+ enable, tuncConstraint, energyBudget, locApiResponse);
+}
+
+uint32_t
+GnssAdapter::setConstrainedTuncCommand (bool enable, float tuncConstraint,
+ uint32_t energyBudget) {
+ // generated session id will be none-zero
+ uint32_t sessionId = generateSessionId();
+ LOC_LOGd("session id %u", sessionId);
+
+ struct MsgEnableTUNC : public LocMsg {
+ GnssAdapter& mAdapter;
+ uint32_t mSessionId;
+ bool mEnable;
+ float mTuncConstraint;
+ uint32_t mEnergyBudget;
+
+ inline MsgEnableTUNC(GnssAdapter& adapter,
+ uint32_t sessionId,
+ bool enable,
+ float tuncConstraint,
+ uint32_t energyBudget) :
+ LocMsg(),
+ mAdapter(adapter),
+ mSessionId(sessionId),
+ mEnable(enable),
+ mTuncConstraint(tuncConstraint),
+ mEnergyBudget(energyBudget) {}
+ inline virtual void proc() const {
+ mAdapter.setConstrainedTunc(mEnable, mTuncConstraint,
+ mEnergyBudget, mSessionId);
+ }
+ };
+
+ sendMsg(new MsgEnableTUNC(*this, sessionId, enable,
+ tuncConstraint, energyBudget));
+
+ return sessionId;
+}
+
+// Set position assisted clock estimator, use 0 session id to indicate
+// that no callback is needed. Session id 0 is used for calls that are
+// not invoked from the integration api, e.g.: initial configuration
+// from the configure file.
+void
+GnssAdapter::setPositionAssistedClockEstimator(bool enable,
+ uint32_t sessionId) {
+
+ mLocConfigInfo.paceConfigInfo.isValid = true;
+ mLocConfigInfo.paceConfigInfo.enable = enable;
+ LocApiResponse* locApiResponse = nullptr;
+ if (sessionId != 0) {
+ locApiResponse =
+ new LocApiResponse(*getContext(),
+ [this, sessionId] (LocationError err) {
+ reportResponse(err, sessionId);});
+ if (!locApiResponse) {
+ LOC_LOGe("memory alloc failed");
+ }
+ }
+ mLocApi->setPositionAssistedClockEstimatorMode(enable, locApiResponse);
+}
+
+uint32_t
+GnssAdapter::setPositionAssistedClockEstimatorCommand(bool enable) {
+ // generated session id will be none-zero
+ uint32_t sessionId = generateSessionId();
+ LOC_LOGd("session id %u", sessionId);
+
+ struct MsgEnablePACE : public LocMsg {
+ GnssAdapter& mAdapter;
+ uint32_t mSessionId;
+ bool mEnable;
+ inline MsgEnablePACE(GnssAdapter& adapter,
+ uint32_t sessionId, bool enable) :
+ LocMsg(),
+ mAdapter(adapter),
+ mSessionId(sessionId),
+ mEnable(enable){}
+ inline virtual void proc() const {
+ mAdapter.setPositionAssistedClockEstimator(mEnable, mSessionId);
+ }
+ };
+
+ sendMsg(new MsgEnablePACE(*this, sessionId, enable));
+ return sessionId;
+}
+
+void GnssAdapter::gnssUpdateSvConfig(
+ uint32_t sessionId, const GnssSvTypeConfig& constellationEnablementConfig,
+ const GnssSvIdConfig& blacklistSvConfig) {
+
+ // suspend all tracking sessions to apply the constellation config
+ suspendSessions();
+ if (constellationEnablementConfig.size == sizeof(constellationEnablementConfig)) {
+ // check whether if any constellation is removed from the new config
+ GnssSvTypesMask currentEnabledMask = mGnssSvTypeConfig.enabledSvTypesMask;
+ GnssSvTypesMask newEnabledMask = constellationEnablementConfig.enabledSvTypesMask;
+ GnssSvTypesMask enabledRemoved = currentEnabledMask & (currentEnabledMask ^ newEnabledMask);
+ // Send reset if any constellation is removed from the enabled list
+ if (enabledRemoved != 0) {
+ mLocApi->resetConstellationControl();
+ }
+
+ // if the constellation config is valid, issue request to modem
+ // to enable/disable constellation
+ mLocApi->setConstellationControl(mGnssSvTypeConfig);
+ } else if (constellationEnablementConfig.size == 0) {
+ // when the size is not set, meaning reset to modem default
+ mLocApi->resetConstellationControl();
+ }
+ // save the constellation settings to be used for modem SSR
+ mGnssSvTypeConfig = constellationEnablementConfig;
+
+ // handle blacklisted SV settings
+ mGnssSvIdConfig = blacklistSvConfig;
+ // process blacklist svs info
+ mBlacklistedSvIds.clear();
+ // need to save the balcklisted sv info into mBlacklistedSvIds as well
+ convertFromGnssSvIdConfig(blacklistSvConfig, mBlacklistedSvIds);
+ LocApiResponse* locApiResponse = new LocApiResponse(*getContext(),
+ [this, sessionId] (LocationError err) {
+ reportResponse(err, sessionId);});
+ if (!locApiResponse) {
+ LOC_LOGe("memory alloc failed");
+ }
+ mLocApi->setBlacklistSv(mGnssSvIdConfig, locApiResponse);
+
+ // resume all tracking sessions after the constellation config has been applied
+ restartSessions(false);
+}
+
+uint32_t
+GnssAdapter::gnssUpdateSvConfigCommand(
+ const GnssSvTypeConfig& constellationEnablementConfig,
+ const GnssSvIdConfig& blacklistSvConfig) {
+
+ // generated session id will be none-zero
+ uint32_t sessionId = generateSessionId();
+ LOC_LOGd("session id %u", sessionId);
+
+ struct MsgUpdateSvConfig : public LocMsg {
+ GnssAdapter& mAdapter;
+ uint32_t mSessionId;
+ GnssSvTypeConfig mConstellationEnablementConfig;
+ GnssSvIdConfig mBlacklistSvIdConfig;
+
+ inline MsgUpdateSvConfig(GnssAdapter& adapter,
+ uint32_t sessionId,
+ const GnssSvTypeConfig& constellationEnablementConfig,
+ const GnssSvIdConfig& blacklistSvConfig) :
+ LocMsg(),
+ mAdapter(adapter),
+ mSessionId(sessionId),
+ mConstellationEnablementConfig(constellationEnablementConfig),
+ mBlacklistSvIdConfig(blacklistSvConfig) {}
+ inline virtual void proc() const {
+ mAdapter.gnssUpdateSvConfig(mSessionId, mConstellationEnablementConfig,
+ mBlacklistSvIdConfig);
+ }
+ };
+
+ if (sessionId != 0) {
+ sendMsg(new MsgUpdateSvConfig(*this, sessionId, constellationEnablementConfig,
+ blacklistSvConfig));
+ }
+ return sessionId;
+}
+
+void GnssAdapter::gnssUpdateSecondaryBandConfig(
+ uint32_t sessionId, const GnssSvTypeConfig& secondaryBandConfig) {
+
+ LocApiResponse* locApiResponse = new LocApiResponse(*getContext(),
+ [this, sessionId] (LocationError err) {
+ reportResponse(err, sessionId);});
+ if (!locApiResponse) {
+ LOC_LOGe("memory alloc failed");
+ }
+
+ // handle secondary band info
+ mGnssSeconaryBandConfig = secondaryBandConfig;
+ gnssSecondaryBandConfigUpdate(locApiResponse);
+}
+
+uint32_t
+GnssAdapter::gnssUpdateSecondaryBandConfigCommand(
+ const GnssSvTypeConfig& secondaryBandConfig) {
+
+ // generated session id will be none-zero
+ uint32_t sessionId = generateSessionId();
+ LOC_LOGd("session id %u", sessionId);
+
+ struct MsgUpdateSecondaryBandConfig : public LocMsg {
+ GnssAdapter& mAdapter;
+ uint32_t mSessionId;
+ GnssSvTypeConfig mSecondaryBandConfig;
+
+ inline MsgUpdateSecondaryBandConfig(GnssAdapter& adapter,
+ uint32_t sessionId,
+ const GnssSvTypeConfig& secondaryBandConfig) :
+ LocMsg(),
+ mAdapter(adapter),
+ mSessionId(sessionId),
+ mSecondaryBandConfig(secondaryBandConfig) {}
+ inline virtual void proc() const {
+ mAdapter.gnssUpdateSecondaryBandConfig(mSessionId, mSecondaryBandConfig);
+ }
+ };
+
+ if (sessionId != 0) {
+ sendMsg(new MsgUpdateSecondaryBandConfig(*this, sessionId, secondaryBandConfig));
+ }
+ return sessionId;
+}
+
+// This function currently retrieves secondary band configuration
+// for constellation enablement/disablement.
+void
+GnssAdapter::gnssGetSecondaryBandConfig(uint32_t sessionId) {
+
+ LocApiResponse* locApiResponse = new LocApiResponse(*getContext(),
+ [this, sessionId] (LocationError err) {
+ reportResponse(err, sessionId);});
+ if (!locApiResponse) {
+ LOC_LOGe("memory alloc failed");
+ }
+
+ mLocApi->getConstellationMultiBandConfig(sessionId, locApiResponse);
+}
+
+uint32_t
+GnssAdapter::gnssGetSecondaryBandConfigCommand() {
+
+ // generated session id will be none-zero
+ uint32_t sessionId = generateSessionId();
+ LOC_LOGd("session id %u", sessionId);
+
+ struct MsgGetSecondaryBandConfig : public LocMsg {
+ GnssAdapter& mAdapter;
+ uint32_t mSessionId;
+ inline MsgGetSecondaryBandConfig(GnssAdapter& adapter,
+ uint32_t sessionId) :
+ LocMsg(),
+ mAdapter(adapter),
+ mSessionId(sessionId) {}
+ inline virtual void proc() const {
+ mAdapter.gnssGetSecondaryBandConfig(mSessionId);
+ }
+ };
+
+ if (sessionId != 0) {
+ sendMsg(new MsgGetSecondaryBandConfig(*this, sessionId));
+ }
+ return sessionId;
+}
+
+void
+GnssAdapter::configLeverArm(uint32_t sessionId,
+ const LeverArmConfigInfo& configInfo) {
+
+ LocationError err = LOCATION_ERROR_NOT_SUPPORTED;
+ if (true == mEngHubProxy->configLeverArm(configInfo)) {
+ err = LOCATION_ERROR_SUCCESS;
+ }
+ reportResponse(err, sessionId);
+}
+
+uint32_t
+GnssAdapter::configLeverArmCommand(const LeverArmConfigInfo& configInfo) {
+
+ // generated session id will be none-zero
+ uint32_t sessionId = generateSessionId();
+ LOC_LOGd("session id %u", sessionId);
+
+ struct MsgConfigLeverArm : public LocMsg {
+ GnssAdapter& mAdapter;
+ uint32_t mSessionId;
+ LeverArmConfigInfo mConfigInfo;
+
+ inline MsgConfigLeverArm(GnssAdapter& adapter,
+ uint32_t sessionId,
+ const LeverArmConfigInfo& configInfo) :
+ LocMsg(),
+ mAdapter(adapter),
+ mSessionId(sessionId),
+ mConfigInfo(configInfo) {}
+ inline virtual void proc() const {
+ // save the lever ARM config info for translating position from GNSS antenna based
+ // to VRP based
+ if (mConfigInfo.leverArmValidMask & LEVER_ARM_TYPE_GNSS_TO_VRP_BIT) {
+ mAdapter.mLocConfigInfo.leverArmConfigInfo.leverArmValidMask |=
+ LEVER_ARM_TYPE_GNSS_TO_VRP_BIT;
+ mAdapter.mLocConfigInfo.leverArmConfigInfo.gnssToVRP = mConfigInfo.gnssToVRP;
+ }
+ mAdapter.configLeverArm(mSessionId, mConfigInfo);
+ }
+ };
+
+ sendMsg(new MsgConfigLeverArm(*this, sessionId, configInfo));
+ return sessionId;
+}
+
+bool GnssAdapter::initMeasCorr(bool bSendCbWhenNotSupported) {
+ LOC_LOGv("GnssAdapter::initMeasCorr");
+ /* Message to initialize Measurement Corrections */
+ struct MsgInitMeasCorr : public LocMsg {
+ GnssAdapter& mAdapter;
+ GnssMeasurementCorrectionsCapabilitiesMask mCapMask;
+
+ inline MsgInitMeasCorr(GnssAdapter& adapter,
+ GnssMeasurementCorrectionsCapabilitiesMask capMask) :
+ LocMsg(), mAdapter(adapter), mCapMask(capMask) {
+ LOC_LOGv("MsgInitMeasCorr");
+ }
+
+ inline virtual void proc() const {
+ LOC_LOGv("MsgInitMeasCorr::proc()");
+
+ mAdapter.mMeasCorrSetCapabilitiesCb(mCapMask);
+ }
+ };
+ if (ContextBase::isFeatureSupported(LOC_SUPPORTED_FEATURE_MEASUREMENTS_CORRECTION)) {
+ sendMsg(new MsgInitMeasCorr(*this, GNSS_MEAS_CORR_LOS_SATS |
+ GNSS_MEAS_CORR_EXCESS_PATH_LENGTH | GNSS_MEAS_CORR_REFLECTING_PLANE));
+ return true;
+ } else {
+ LOC_LOGv("MEASUREMENTS_CORRECTION feature is not supported in the modem");
+ if (bSendCbWhenNotSupported) {
+ sendMsg(new MsgInitMeasCorr(*this, 0));
+ }
+ return false;
+ }
+}
+
+bool GnssAdapter::openMeasCorrCommand(const measCorrSetCapabilitiesCb setCapabilitiesCb) {
+ LOC_LOGi("GnssAdapter::openMeasCorrCommand");
+
+ /* Send message to initialize Measurement Corrections */
+ mMeasCorrSetCapabilitiesCb = setCapabilitiesCb;
+ mIsMeasCorrInterfaceOpen = true;
+ if (isEngineCapabilitiesKnown()) {
+ LOC_LOGv("Capabilities are known, proceed with measurement corrections init");
+ return initMeasCorr(false);
+ } else {
+ LOC_LOGv("Capabilities are not known, wait for open");
+ return true;
+ }
+}
+
+bool GnssAdapter::measCorrSetCorrectionsCommand(const GnssMeasurementCorrections gnssMeasCorr) {
+ LOC_LOGi("GnssAdapter::measCorrSetCorrectionsCommand");
+
+ /* Message to set Measurement Corrections */
+ struct MsgSetCorrectionsMeasCorr : public LocMsg {
+ const GnssMeasurementCorrections mGnssMeasCorr;
+ GnssAdapter& mAdapter;
+ LocApiBase& mApi;
+
+ inline MsgSetCorrectionsMeasCorr(
+ const GnssMeasurementCorrections gnssMeasCorr,
+ GnssAdapter& adapter,
+ LocApiBase& api) :
+ LocMsg(),
+ mGnssMeasCorr(gnssMeasCorr),
+ mAdapter(adapter),
+ mApi(api) {
+ LOC_LOGv("MsgSetCorrectionsMeasCorr");
+ }
+
+ inline virtual void proc() const {
+ LOC_LOGv("MsgSetCorrectionsMeasCorr::proc()");
+ mApi.setMeasurementCorrections(mGnssMeasCorr);
+ }
+ };
+
+ if (ContextBase::isFeatureSupported(LOC_SUPPORTED_FEATURE_MEASUREMENTS_CORRECTION)) {
+ sendMsg(new MsgSetCorrectionsMeasCorr(gnssMeasCorr, *this, *mLocApi));
+ return true;
+ } else {
+ LOC_LOGw("Measurement Corrections are not supported!");
+ return false;
+ }
+}
+uint32_t GnssAdapter::antennaInfoInitCommand(const antennaInfoCb antennaInfoCallback) {
+ LOC_LOGi("GnssAdapter::antennaInfoInitCommand");
+
+ /* Message to initialize Antenna Information */
+ struct MsgInitAi : public LocMsg {
+ const antennaInfoCb mAntennaInfoCb;
+ GnssAdapter& mAdapter;
+
+ inline MsgInitAi(const antennaInfoCb antennaInfoCallback, GnssAdapter& adapter) :
+ LocMsg(), mAntennaInfoCb(antennaInfoCallback), mAdapter(adapter) {
+ LOC_LOGv("MsgInitAi");
+ }
+
+ inline virtual void proc() const {
+ LOC_LOGv("MsgInitAi::proc()");
+ mAdapter.reportGnssAntennaInformation(mAntennaInfoCb);
+ }
+ };
+ if (mIsAntennaInfoInterfaceOpened) {
+ return ANTENNA_INFO_ERROR_ALREADY_INIT;
+ } else {
+ mIsAntennaInfoInterfaceOpened = true;
+ sendMsg(new MsgInitAi(antennaInfoCallback, *this));
+ return ANTENNA_INFO_SUCCESS;
+ }
+}
+
+void
+GnssAdapter::configRobustLocation(uint32_t sessionId,
+ bool enable, bool enableForE911) {
+
+ mLocConfigInfo.robustLocationConfigInfo.isValid = true;
+ mLocConfigInfo.robustLocationConfigInfo.enable = enable;
+ mLocConfigInfo.robustLocationConfigInfo.enableFor911 = enableForE911;
+
+ LocApiResponse* locApiResponse = nullptr;
+ if (sessionId != 0) {
+ locApiResponse =
+ new LocApiResponse(*getContext(),
+ [this, sessionId] (LocationError err) {
+ reportResponse(err, sessionId);});
+ if (!locApiResponse) {
+ LOC_LOGe("memory alloc failed");
+ }
+ }
+ mLocApi->configRobustLocation(enable, enableForE911, locApiResponse);
+}
+
+uint32_t GnssAdapter::configRobustLocationCommand(
+ bool enable, bool enableForE911) {
+
+ // generated session id will be none-zero
+ uint32_t sessionId = generateSessionId();
+ LOC_LOGd("session id %u", sessionId);
+
+ struct MsgConfigRobustLocation : public LocMsg {
+ GnssAdapter& mAdapter;
+ uint32_t mSessionId;
+ bool mEnable;
+ bool mEnableForE911;
+
+ inline MsgConfigRobustLocation(GnssAdapter& adapter,
+ uint32_t sessionId,
+ bool enable,
+ bool enableForE911) :
+ LocMsg(),
+ mAdapter(adapter),
+ mSessionId(sessionId),
+ mEnable(enable),
+ mEnableForE911(enableForE911) {}
+ inline virtual void proc() const {
+ mAdapter.configRobustLocation(mSessionId, mEnable, mEnableForE911);
+ }
+ };
+
+ sendMsg(new MsgConfigRobustLocation(*this, sessionId, enable, enableForE911));
+ return sessionId;
+}
+
+void
+GnssAdapter::configMinGpsWeek(uint32_t sessionId, uint16_t minGpsWeek) {
+ // suspend all sessions for modem to take the min GPS week config
+ suspendSessions();
+
+ LocApiResponse* locApiResponse = nullptr;
+ if (sessionId != 0) {
+ locApiResponse =
+ new LocApiResponse(*getContext(),
+ [this, sessionId] (LocationError err) {
+ reportResponse(err, sessionId);});
+ if (!locApiResponse) {
+ LOC_LOGe("memory alloc failed");
+ }
+ }
+ mLocApi->configMinGpsWeek(minGpsWeek, locApiResponse);
+
+ // resume all tracking sessions after the min GPS week config
+ // has been changed
+ restartSessions(false);
+}
+
+uint32_t GnssAdapter::configMinGpsWeekCommand(uint16_t minGpsWeek) {
+ // generated session id will be none-zero
+ uint32_t sessionId = generateSessionId();
+ LOC_LOGd("session id %u", sessionId);
+
+ struct MsgConfigMinGpsWeek : public LocMsg {
+ GnssAdapter& mAdapter;
+ uint32_t mSessionId;
+ uint16_t mMinGpsWeek;
+
+ inline MsgConfigMinGpsWeek(GnssAdapter& adapter,
+ uint32_t sessionId,
+ uint16_t minGpsWeek) :
+ LocMsg(),
+ mAdapter(adapter),
+ mSessionId(sessionId),
+ mMinGpsWeek(minGpsWeek) {}
+ inline virtual void proc() const {
+ mAdapter.configMinGpsWeek(mSessionId, mMinGpsWeek);
+ }
+ };
+
+ sendMsg(new MsgConfigMinGpsWeek(*this, sessionId, minGpsWeek));
+ return sessionId;
+}
+
+uint32_t GnssAdapter::configDeadReckoningEngineParamsCommand(
+ const DeadReckoningEngineConfig& dreConfig) {
+
+ // generated session id will be none-zero
+ uint32_t sessionId = generateSessionId();
+ LOC_LOGd("session id %u", sessionId);
+
+ struct MsgConfigDrEngine : public LocMsg {
+ GnssAdapter& mAdapter;
+ uint32_t mSessionId;
+ DeadReckoningEngineConfig mDreConfig;
+
+ inline MsgConfigDrEngine(GnssAdapter& adapter,
+ uint32_t sessionId,
+ const DeadReckoningEngineConfig& dreConfig) :
+ LocMsg(),
+ mAdapter(adapter),
+ mSessionId(sessionId),
+ mDreConfig(dreConfig) {}
+ inline virtual void proc() const {
+ LocationError err = LOCATION_ERROR_NOT_SUPPORTED;
+ if (true == mAdapter.mEngHubProxy->configDeadReckoningEngineParams(mDreConfig)) {
+ err = LOCATION_ERROR_SUCCESS;
+ }
+ mAdapter.reportResponse(err, mSessionId);
+ }
+ };
+
+ sendMsg(new MsgConfigDrEngine(*this, sessionId, dreConfig));
+ return sessionId;
+}
+
+uint32_t GnssAdapter::configEngineRunStateCommand(
+ PositioningEngineMask engType, LocEngineRunState engState) {
+
+ // generated session id will be none-zero
+ uint32_t sessionId = generateSessionId();
+ LOC_LOGe("session id %u, eng type 0x%x, eng state %d, dre enabled %d",
+ sessionId, engType, engState, mDreIntEnabled);
+
+ struct MsgConfigEngineRunState : public LocMsg {
+ GnssAdapter& mAdapter;
+ uint32_t mSessionId;
+ PositioningEngineMask mEngType;
+ LocEngineRunState mEngState;
+
+ inline MsgConfigEngineRunState(GnssAdapter& adapter,
+ uint32_t sessionId,
+ PositioningEngineMask engType,
+ LocEngineRunState engState) :
+ LocMsg(),
+ mAdapter(adapter),
+ mSessionId(sessionId),
+ mEngType(engType),
+ mEngState(engState) {}
+ inline virtual void proc() const {
+ LocationError err = LOCATION_ERROR_NOT_SUPPORTED;
+ // Currently, only DR engine supports pause/resume request
+ if ((mEngType == DEAD_RECKONING_ENGINE) &&
+ (mAdapter.mDreIntEnabled == true)) {
+ if (true == mAdapter.mEngHubProxy->configEngineRunState(mEngType, mEngState)) {
+ err = LOCATION_ERROR_SUCCESS;
+ }
+ }
+ mAdapter.reportResponse(err, mSessionId);
+ }
+ };
+
+ sendMsg(new MsgConfigEngineRunState(*this, sessionId, engType, engState));
+
+ return sessionId;
+}
+
+void GnssAdapter::reportGnssConfigEvent(uint32_t sessionId, const GnssConfig& gnssConfig)
+{
+ struct MsgReportGnssConfig : public LocMsg {
+ GnssAdapter& mAdapter;
+ uint32_t mSessionId;
+ mutable GnssConfig mGnssConfig;
+ inline MsgReportGnssConfig(GnssAdapter& adapter,
+ uint32_t sessionId,
+ const GnssConfig& gnssConfig) :
+ LocMsg(),
+ mAdapter(adapter),
+ mSessionId(sessionId),
+ mGnssConfig(gnssConfig) {}
+ inline virtual void proc() const {
+ // Invoke control clients config callback
+ if (nullptr != mAdapter.mControlCallbacks.gnssConfigCb) {
+ mAdapter.mControlCallbacks.gnssConfigCb(mSessionId, mGnssConfig);
+ } else {
+ LOC_LOGe("Failed to report, callback not registered");
+ }
+ }
+ };
+
+ sendMsg(new MsgReportGnssConfig(*this, sessionId, gnssConfig));
+}
+
+/* ==== 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;
+ // check if this is DRE-INT engine
+ if ((processInfoList[i].args[1]!= nullptr) &&
+ (strncmp(processInfoList[i].args[1], "DRE-INT", sizeof("DRE-INT")) == 0)) {
+ mDreIntEnabled = true;
+ break;
+ }
+ }
+ }
+
+ // no plugin daemon is enabled for this platform,
+ // check if external engine is present for which we need
+ // libloc_eng_hub.so to be loaded
+ if (pluginDaemonEnabled == false) {
+ UTIL_READ_CONF(LOC_PATH_IZAT_CONF, izatConfParamTable);
+ if (!loadEngHubForExternalEngine) {
+ 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);
+ };
+
+ GnssAdapterUpdateNHzRequirementCb updateNHzRequirementCb =
+ [this] (bool nHzNeeded, bool nHzMeasNeeded) {
+
+ if (nHzMeasNeeded &&
+ (!checkMask(LOC_API_ADAPTER_BIT_GNSS_NHZ_MEASUREMENT))) {
+ updateEvtMask(LOC_API_ADAPTER_BIT_GNSS_NHZ_MEASUREMENT,
+ LOC_REGISTRATION_MASK_ENABLED);
+ } else if (checkMask(LOC_API_ADAPTER_BIT_GNSS_NHZ_MEASUREMENT)) {
+ updateEvtMask(LOC_API_ADAPTER_BIT_GNSS_NHZ_MEASUREMENT,
+ LOC_REGISTRATION_MASK_DISABLED);
+ }
+
+ if (mNHzNeeded != nHzNeeded) {
+ mNHzNeeded = nHzNeeded;
+ checkAndRestartSPESession();
+ }
+ };
+
+ GnssAdapterUpdateQwesFeatureStatusCb updateQwesFeatureStatusCb =
+ [this] (const std::unordered_map<LocationQwesFeatureType, bool> &featureMap) {
+ reportQwesCapabilities(featureMap);
+ };
+
+ getEngHubProxyFn* getter = (getEngHubProxyFn*) dlsym(handle, "getEngHubProxy");
+ if(getter != nullptr) {
+ EngineHubProxyBase* hubProxy = (*getter) (mMsgTask, mSystemStatus->getOsObserver(),
+ reportPositionEventCb,
+ reportSvEventCb, reqAidingDataCb,
+ updateNHzRequirementCb,
+ updateQwesFeatureStatusCb);
+ 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;
+}
+
+std::vector<double>
+GnssAdapter::parseDoublesString(char* dString) {
+ std::vector<double> dVector;
+ char* tmp = NULL;
+ char* substr;
+
+ dVector.clear();
+ for (substr = strtok_r(dString, " ", &tmp);
+ substr != NULL;
+ substr = strtok_r(NULL, " ", &tmp)) {
+ dVector.push_back(std::stod(substr));
+ }
+ return dVector;
+}
+
+void
+GnssAdapter::reportGnssAntennaInformation(const antennaInfoCb antennaInfoCallback)
+{
+#define MAX_TEXT_WIDTH 50
+#define MAX_COLUMN_WIDTH 20
+
+ /* parse antenna_corrections file and fill in
+ a vector of GnssAntennaInformation data structure */
+
+ std::vector<GnssAntennaInformation> gnssAntennaInformations;
+ GnssAntennaInformation gnssAntennaInfo;
+
+ uint32_t antennaInfoVectorSize;
+ loc_param_s_type ant_info_vector_table[] =
+ {
+ { "ANTENNA_INFO_VECTOR_SIZE", &antennaInfoVectorSize, NULL, 'n' }
+ };
+ UTIL_READ_CONF(LOC_PATH_ANT_CORR, ant_info_vector_table);
+
+ for (uint32_t i = 0; i < antennaInfoVectorSize; i++) {
+ double carrierFrequencyMHz;
+ char pcOffsetStr[LOC_MAX_PARAM_STRING];
+ uint32_t numberOfRows = 0;
+ uint32_t numberOfColumns = 0;
+ uint32_t numberOfRowsSGC = 0;
+ uint32_t numberOfColumnsSGC = 0;
+
+ gnssAntennaInfo.phaseCenterVariationCorrectionMillimeters.clear();
+ gnssAntennaInfo.phaseCenterVariationCorrectionUncertaintyMillimeters.clear();
+ gnssAntennaInfo.signalGainCorrectionDbi.clear();
+ gnssAntennaInfo.signalGainCorrectionUncertaintyDbi.clear();
+ string s1 = "CARRIER_FREQUENCY_";
+ s1 += to_string(i);
+ string s2 = "PC_OFFSET_";
+ s2 += to_string(i);
+ string s3 = "NUMBER_OF_ROWS_";
+ s3 += to_string(i);
+ string s4 = "NUMBER_OF_COLUMNS_";
+ s4 += to_string(i);
+ string s5 = "NUMBER_OF_ROWS_SGC_";
+ s5 += to_string(i);
+ string s6 = "NUMBER_OF_COLUMNS_SGC_";
+ s6 += to_string(i);
+
+ gnssAntennaInfo.size = sizeof(gnssAntennaInfo);
+ loc_param_s_type ant_cf_table[] =
+ {
+ { s1.c_str(), &carrierFrequencyMHz, NULL, 'f' },
+ { s2.c_str(), &pcOffsetStr, NULL, 's' },
+ { s3.c_str(), &numberOfRows, NULL, 'n' },
+ { s4.c_str(), &numberOfColumns, NULL, 'n' },
+ { s5.c_str(), &numberOfRowsSGC, NULL, 'n' },
+ { s6.c_str(), &numberOfColumnsSGC, NULL, 'n' },
+ };
+ UTIL_READ_CONF(LOC_PATH_ANT_CORR, ant_cf_table);
+
+ if (0 == numberOfRowsSGC) {
+ numberOfRowsSGC = numberOfRows;
+ }
+ if (0 == numberOfColumnsSGC) {
+ numberOfColumnsSGC = numberOfColumns;
+ }
+
+ gnssAntennaInfo.carrierFrequencyMHz = carrierFrequencyMHz;
+
+ // now parse pcOffsetStr to get each entry
+ std::vector<double> pcOffset;
+ pcOffset = parseDoublesString(pcOffsetStr);
+ gnssAntennaInfo.phaseCenterOffsetCoordinateMillimeters.size =
+ sizeof(gnssAntennaInfo.phaseCenterOffsetCoordinateMillimeters);
+ gnssAntennaInfo.phaseCenterOffsetCoordinateMillimeters.x = pcOffset[0];
+ gnssAntennaInfo.phaseCenterOffsetCoordinateMillimeters.xUncertainty = pcOffset[1];
+ gnssAntennaInfo.phaseCenterOffsetCoordinateMillimeters.y = pcOffset[2];
+ gnssAntennaInfo.phaseCenterOffsetCoordinateMillimeters.yUncertainty = pcOffset[3];
+ gnssAntennaInfo.phaseCenterOffsetCoordinateMillimeters.z = pcOffset[4];
+ gnssAntennaInfo.phaseCenterOffsetCoordinateMillimeters.zUncertainty = pcOffset[5];
+
+ uint16_t array_size = MAX_TEXT_WIDTH + MAX_COLUMN_WIDTH*numberOfColumns;
+ uint16_t array_size_SGC = MAX_TEXT_WIDTH + MAX_COLUMN_WIDTH*numberOfColumnsSGC;
+ for (uint32_t j = 0; j < numberOfRows; j++) {
+ char pcVarCorrStr[array_size];
+ char pcVarCorrUncStr[array_size];
+
+ string s1 = "PC_VARIATION_CORRECTION_" + to_string(i) + "_ROW_";
+ s1 += to_string(j);
+ string s2 = "PC_VARIATION_CORRECTION_UNC_" + to_string(i) + "_ROW_";
+ s2 += to_string(j);
+
+ loc_param_s_type ant_row_table[] =
+ {
+ { s1.c_str(), &pcVarCorrStr, NULL, 's' },
+ { s2.c_str(), &pcVarCorrUncStr, NULL, 's' },
+ };
+ UTIL_READ_CONF_LONG(LOC_PATH_ANT_CORR, ant_row_table, array_size);
+
+ gnssAntennaInfo.phaseCenterVariationCorrectionMillimeters.push_back(
+ parseDoublesString(pcVarCorrStr));
+ gnssAntennaInfo.phaseCenterVariationCorrectionUncertaintyMillimeters.push_back(
+ parseDoublesString(pcVarCorrUncStr));
+ }
+ for (uint32_t j = 0; j < numberOfRowsSGC; j++) {
+ char sigGainCorrStr[array_size_SGC];
+ char sigGainCorrUncStr[array_size_SGC];
+
+ string s3 = "SIGNAL_GAIN_CORRECTION_" + to_string(i) + "_ROW_";
+ s3 += to_string(j);
+ string s4 = "SIGNAL_GAIN_CORRECTION_UNC_" + to_string(i) + "_ROW_";
+ s4 += to_string(j);
+
+ loc_param_s_type ant_row_table[] =
+ {
+ { s3.c_str(), &sigGainCorrStr, NULL, 's' },
+ { s4.c_str(), &sigGainCorrUncStr, NULL, 's' },
+ };
+ UTIL_READ_CONF_LONG(LOC_PATH_ANT_CORR, ant_row_table, array_size_SGC);
+
+ gnssAntennaInfo.signalGainCorrectionDbi.push_back(
+ parseDoublesString(sigGainCorrStr));
+ gnssAntennaInfo.signalGainCorrectionUncertaintyDbi.push_back(
+ parseDoublesString(sigGainCorrUncStr));
+ }
+ gnssAntennaInformations.push_back(std::move(gnssAntennaInfo));
+ }
+ antennaInfoCallback(gnssAntennaInformations);
+}
+
+/* ==== DGnss Usable Reporter ========================================================= */
+/* ======== UTILITIES ================================================================= */
+
+void GnssAdapter::initCDFWService()
+{
+ LOC_LOGv("mCdfwInterface %p", mCdfwInterface);
+ if (nullptr == mCdfwInterface) {
+ void* libHandle = nullptr;
+ const char* libName = "libcdfw.so";
+
+ libHandle = nullptr;
+ getCdfwInterface getter = (getCdfwInterface)dlGetSymFromLib(libHandle,
+ libName, "getQCdfwInterface");
+ if (nullptr == getter) {
+ LOC_LOGe("dlGetSymFromLib getQCdfwInterface failed");
+ } else {
+ mCdfwInterface = getter();
+ }
+
+ if (nullptr != mCdfwInterface) {
+ QDgnssSessionActiveCb qDgnssSessionActiveCb = [this] (bool sessionActive) {
+ mDGnssNeedReport = sessionActive;
+ };
+ mCdfwInterface->startDgnssApiService(*mMsgTask);
+ mQDgnssListenerHDL = mCdfwInterface->createUsableReporter(qDgnssSessionActiveCb);
+ }
+ }
+}
+
+/*==== DGnss Ntrip Source ==========================================================*/
+void GnssAdapter::enablePPENtripStreamCommand(const GnssNtripConnectionParams& params,
+ bool enableRTKEngine) {
+
+ (void)enableRTKEngine; //future parameter, not used
+
+ struct enableNtripMsg : public LocMsg {
+ GnssAdapter& mAdapter;
+ const GnssNtripConnectionParams& mParams;
+
+ inline enableNtripMsg(GnssAdapter& adapter,
+ const GnssNtripConnectionParams& params) :
+ LocMsg(),
+ mAdapter(adapter),
+ mParams(std::move(params)) {}
+ inline virtual void proc() const {
+ mAdapter.handleEnablePPENtrip(mParams);
+ }
+ };
+ sendMsg(new enableNtripMsg(*this, params));
+}
+
+void GnssAdapter::handleEnablePPENtrip(const GnssNtripConnectionParams& params) {
+ LOC_LOGd("%d %s %d %s %s %s %d mSendNmeaConsent %d",
+ params.useSSL, params.hostNameOrIp.data(), params.port,
+ params.mountPoint.data(), params.username.data(), params.password.data(),
+ params.requiresNmeaLocation, mSendNmeaConsent);
+
+ GnssNtripConnectionParams* pNtripParams = &(mStartDgnssNtripParams.ntripParams);
+
+ if (pNtripParams->useSSL == params.useSSL &&
+ 0 == pNtripParams->hostNameOrIp.compare(params.hostNameOrIp) &&
+ pNtripParams->port == params.port &&
+ 0 == pNtripParams->mountPoint.compare(params.mountPoint) &&
+ 0 == pNtripParams->username.compare(params.username) &&
+ 0 == pNtripParams->password.compare(params.password) &&
+ pNtripParams->requiresNmeaLocation == params.requiresNmeaLocation &&
+ mDgnssState & DGNSS_STATE_ENABLE_NTRIP_COMMAND) {
+ LOC_LOGd("received same Ntrip param");
+ return;
+ }
+
+ mDgnssState |= DGNSS_STATE_ENABLE_NTRIP_COMMAND;
+ mDgnssState |= DGNSS_STATE_NO_NMEA_PENDING;
+ mDgnssState &= ~DGNSS_STATE_NTRIP_SESSION_STARTED;
+
+ mStartDgnssNtripParams.ntripParams = std::move(params);
+ mStartDgnssNtripParams.nmea.clear();
+ if (mSendNmeaConsent && pNtripParams->requiresNmeaLocation) {
+ mDgnssState &= ~DGNSS_STATE_NO_NMEA_PENDING;
+ mDgnssLastNmeaBootTimeMilli = 0;
+ return;
+ }
+
+ checkUpdateDgnssNtrip(false);
+}
+
+void GnssAdapter::disablePPENtripStreamCommand() {
+ struct disableNtripMsg : public LocMsg {
+ GnssAdapter& mAdapter;
+
+ inline disableNtripMsg(GnssAdapter& adapter) :
+ LocMsg(),
+ mAdapter(adapter) {}
+ inline virtual void proc() const {
+ mAdapter.handleDisablePPENtrip();
+ }
+ };
+ sendMsg(new disableNtripMsg(*this));
+}
+
+void GnssAdapter::handleDisablePPENtrip() {
+ mDgnssState &= ~DGNSS_STATE_ENABLE_NTRIP_COMMAND;
+ mDgnssState |= DGNSS_STATE_NO_NMEA_PENDING;
+ stopDgnssNtrip();
+}
+
+void GnssAdapter::checkUpdateDgnssNtrip(bool isLocationValid) {
+ LOC_LOGd("isInSession %d mDgnssState 0x%x isLocationValid %d",
+ isInSession(), mDgnssState, isLocationValid);
+ if (isInSession()) {
+ uint64_t curBootTime = getBootTimeMilliSec();
+ if (mDgnssState == (DGNSS_STATE_ENABLE_NTRIP_COMMAND | DGNSS_STATE_NO_NMEA_PENDING)) {
+ mDgnssState |= DGNSS_STATE_NTRIP_SESSION_STARTED;
+ mXtraObserver.startDgnssSource(mStartDgnssNtripParams);
+ if (isDgnssNmeaRequired()) {
+ mDgnssLastNmeaBootTimeMilli = curBootTime;
+ }
+ } else if ((mDgnssState & DGNSS_STATE_NTRIP_SESSION_STARTED) && isLocationValid &&
+ isDgnssNmeaRequired() &&
+ curBootTime - mDgnssLastNmeaBootTimeMilli > DGNSS_RANGE_UPDATE_TIME_10MIN_IN_MILLI ) {
+ mXtraObserver.updateNmeaToDgnssServer(mStartDgnssNtripParams.nmea);
+ mDgnssLastNmeaBootTimeMilli = curBootTime;
+ }
+ }
+}
+
+void GnssAdapter::stopDgnssNtrip() {
+ LOC_LOGd("isInSession %d mDgnssState 0x%x", isInSession(), mDgnssState);
+ mStartDgnssNtripParams.nmea.clear();
+ if (mDgnssState & DGNSS_STATE_NTRIP_SESSION_STARTED) {
+ mDgnssState &= ~DGNSS_STATE_NTRIP_SESSION_STARTED;
+ mXtraObserver.stopDgnssSource();
+ }
+}
+
+void GnssAdapter::reportGGAToNtrip(const char* nmea) {
+
+#define POS_OF_GGA (3) //start position of "GGA"
+#define COMMAS_BEFORE_VALID (6) //"$GPGGA,,,,,,0,,,,,,,,*hh"
+
+ if (!isDgnssNmeaRequired()) {
+ return;
+ }
+
+ if (nullptr == nmea || 0 == strlen(nmea)) {
+ return;
+ }
+
+ string nmeaString(nmea);
+ size_t foundPos = nmeaString.find("GGA");
+ size_t foundNth = 0;
+ string GGAString;
+
+ if (foundPos != string::npos && foundPos >= POS_OF_GGA) {
+ size_t foundNextSentence = nmeaString.find("$", foundPos);
+ if (foundNextSentence != string::npos) {
+ /* remove other sentences after GGA */
+ GGAString = nmeaString.substr(foundPos - POS_OF_GGA, foundNextSentence);
+ } else {
+ /* GGA is the last sentence */
+ GGAString = nmeaString.substr(foundPos - POS_OF_GGA);
+ }
+ LOC_LOGd("GGAString %s", GGAString.c_str());
+
+ foundPos = GGAString.find(",");
+ while (foundPos != string::npos && foundNth < COMMAS_BEFORE_VALID) {
+ foundPos++;
+ foundNth++;
+ foundPos = GGAString.find(",", foundPos);
+ }
+
+ if (COMMAS_BEFORE_VALID == foundNth && GGAString.at(foundPos-1) != '0') {
+ mDgnssState |= DGNSS_STATE_NO_NMEA_PENDING;
+ mStartDgnssNtripParams.nmea = std::move(GGAString);
+ checkUpdateDgnssNtrip(true);
+ }
+ }
+
+ return;
+}