75da4c0eee
Change-Id: I134d6418f1357a4d7ce37358481d6b765d93e1a5
6917 lines
270 KiB
C++
6917 lines
270 KiB
C++
/* 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 ¬ify, 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;
|
|
}
|