diff options
Diffstat (limited to 'gps/gnss')
| -rw-r--r-- | gps/gnss/Agps.cpp | 675 | ||||
| -rw-r--r-- | gps/gnss/Agps.h | 318 | ||||
| -rw-r--r-- | gps/gnss/Android.bp | 35 | ||||
| -rw-r--r-- | gps/gnss/GnssAdapter.cpp | 6916 | ||||
| -rw-r--r-- | gps/gnss/GnssAdapter.h | 648 | ||||
| -rw-r--r-- | gps/gnss/Makefile.am | 32 | ||||
| -rw-r--r-- | gps/gnss/NativeAgpsHandler.cpp | 127 | ||||
| -rw-r--r-- | gps/gnss/NativeAgpsHandler.h | 64 | ||||
| -rw-r--r-- | gps/gnss/XtraSystemStatusObserver.cpp | 384 | ||||
| -rw-r--r-- | gps/gnss/XtraSystemStatusObserver.h | 112 | ||||
| -rw-r--r-- | gps/gnss/location_gnss.cpp | 593 | 
11 files changed, 9904 insertions, 0 deletions
| diff --git a/gps/gnss/Agps.cpp b/gps/gnss/Agps.cpp new file mode 100644 index 0000000..9255f88 --- /dev/null +++ b/gps/gnss/Agps.cpp @@ -0,0 +1,675 @@ +/* Copyright (c) 2012-2019, The Linux Foundation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + *     * Redistributions of source code must retain the above copyright + *       notice, this list of conditions and the following disclaimer. + *     * Redistributions in binary form must reproduce the above + *       copyright notice, this list of conditions and the following + *       disclaimer in the documentation and/or other materials provided + *       with the distribution. + *     * Neither the name of The Linux Foundation, nor the names of its + *       contributors may be used to endorse or promote products derived + *       from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT + * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ +#define LOG_NDEBUG 0 +#define LOG_TAG "LocSvc_Agps" + +#include <Agps.h> +#include <loc_pla.h> +#include <ContextBase.h> +#include <loc_timer.h> +#include <inttypes.h> + +/* -------------------------------------------------------------------- + *   AGPS State Machine Methods + * -------------------------------------------------------------------*/ +void AgpsStateMachine::processAgpsEvent(AgpsEvent event){ + +    LOC_LOGD("processAgpsEvent(): SM %p, Event %d, State %d", +               this, event, mState); + +    switch (event) { + +        case AGPS_EVENT_SUBSCRIBE: +            processAgpsEventSubscribe(); +            break; + +        case AGPS_EVENT_UNSUBSCRIBE: +            processAgpsEventUnsubscribe(); +            break; + +        case AGPS_EVENT_GRANTED: +            processAgpsEventGranted(); +            break; + +        case AGPS_EVENT_RELEASED: +            processAgpsEventReleased(); +            break; + +        case AGPS_EVENT_DENIED: +            processAgpsEventDenied(); +            break; + +        default: +            LOC_LOGE("Invalid Loc Agps Event"); +    } +} + +void AgpsStateMachine::processAgpsEventSubscribe(){ + +    switch (mState) { + +        case AGPS_STATE_RELEASED: +            /* Add subscriber to list +             * No notifications until we get RSRC_GRANTED */ +            addSubscriber(mCurrentSubscriber); +            requestOrReleaseDataConn(true); +            transitionState(AGPS_STATE_PENDING); +            break; + +        case AGPS_STATE_PENDING: +            /* Already requested for data connection, +             * do nothing until we get RSRC_GRANTED event; +             * Just add this subscriber to the list, for notifications */ +            addSubscriber(mCurrentSubscriber); +            break; + +        case AGPS_STATE_ACQUIRED: +            /* We already have the data connection setup, +             * Notify current subscriber with GRANTED event, +             * And add it to the subscriber list for further notifications. */ +            notifyEventToSubscriber(AGPS_EVENT_GRANTED, mCurrentSubscriber, false); +            addSubscriber(mCurrentSubscriber); +            break; + +        case AGPS_STATE_RELEASING: +            addSubscriber(mCurrentSubscriber); +            break; + +        default: +            LOC_LOGE("Invalid state: %d", mState); +    } +} + +void AgpsStateMachine::processAgpsEventUnsubscribe(){ + +    switch (mState) { + +        case AGPS_STATE_RELEASED: +            notifyEventToSubscriber( +                    AGPS_EVENT_UNSUBSCRIBE, mCurrentSubscriber, false); +            break; + +        case AGPS_STATE_PENDING: +        case AGPS_STATE_ACQUIRED: +            /* If the subscriber wishes to wait for connection close, +             * before being removed from list, move to inactive state +             * and notify */ +            if (mCurrentSubscriber->mWaitForCloseComplete) { +                mCurrentSubscriber->mIsInactive = true; +            } +            else { +                /* Notify only current subscriber and then delete it from +                 * subscriberList */ +                notifyEventToSubscriber( +                        AGPS_EVENT_UNSUBSCRIBE, mCurrentSubscriber, true); +            } + +            /* If no subscribers in list, release data connection */ +            if (mSubscriberList.empty()) { +                transitionState(AGPS_STATE_RELEASED); +                requestOrReleaseDataConn(false); +            } +            /* Some subscribers in list, but all inactive; +             * Release data connection */ +            else if(!anyActiveSubscribers()) { +                transitionState(AGPS_STATE_RELEASING); +                requestOrReleaseDataConn(false); +            } +            break; + +        case AGPS_STATE_RELEASING: +            /* If the subscriber wishes to wait for connection close, +             * before being removed from list, move to inactive state +             * and notify */ +            if (mCurrentSubscriber->mWaitForCloseComplete) { +                mCurrentSubscriber->mIsInactive = true; +            } +            else { +                /* Notify only current subscriber and then delete it from +                 * subscriberList */ +                notifyEventToSubscriber( +                        AGPS_EVENT_UNSUBSCRIBE, mCurrentSubscriber, true); +            } + +            /* If no subscribers in list, just move the state. +             * Request for releasing data connection should already have been +             * sent */ +            if (mSubscriberList.empty()) { +                transitionState(AGPS_STATE_RELEASED); +            } +            break; + +        default: +            LOC_LOGE("Invalid state: %d", mState); +    } +} + +void AgpsStateMachine::processAgpsEventGranted(){ + +    switch (mState) { + +        case AGPS_STATE_RELEASED: +        case AGPS_STATE_ACQUIRED: +        case AGPS_STATE_RELEASING: +            LOC_LOGE("Unexpected event GRANTED in state %d", mState); +            break; + +        case AGPS_STATE_PENDING: +            // Move to acquired state +            transitionState(AGPS_STATE_ACQUIRED); +            notifyAllSubscribers( +                    AGPS_EVENT_GRANTED, false, +                    AGPS_NOTIFICATION_TYPE_FOR_ACTIVE_SUBSCRIBERS); +            break; + +        default: +            LOC_LOGE("Invalid state: %d", mState); +    } +} + +void AgpsStateMachine::processAgpsEventReleased(){ + +    switch (mState) { + +        case AGPS_STATE_RELEASED: +            /* Subscriber list should be empty if we are in released state */ +            if (!mSubscriberList.empty()) { +                LOC_LOGE("Unexpected event RELEASED in RELEASED state"); +            } +            break; + +        case AGPS_STATE_ACQUIRED: +            /* Force release received */ +            LOC_LOGW("Force RELEASED event in ACQUIRED state"); +            transitionState(AGPS_STATE_RELEASED); +            notifyAllSubscribers( +                    AGPS_EVENT_RELEASED, true, +                    AGPS_NOTIFICATION_TYPE_FOR_ALL_SUBSCRIBERS); +            break; + +        case AGPS_STATE_RELEASING: +            /* Notify all inactive subscribers about the event */ +            notifyAllSubscribers( +                    AGPS_EVENT_RELEASED, true, +                    AGPS_NOTIFICATION_TYPE_FOR_INACTIVE_SUBSCRIBERS); + +            /* If we have active subscribers now, they must be waiting for +             * data conn setup */ +            if (anyActiveSubscribers()) { +                transitionState(AGPS_STATE_PENDING); +                requestOrReleaseDataConn(true); +            } +            /* No active subscribers, move to released state */ +            else { +                transitionState(AGPS_STATE_RELEASED); +            } +            break; + +        case AGPS_STATE_PENDING: +            /* NOOP */ +            break; + +        default: +            LOC_LOGE("Invalid state: %d", mState); +    } +} + +void AgpsStateMachine::processAgpsEventDenied(){ + +    switch (mState) { + +        case AGPS_STATE_RELEASED: +            LOC_LOGE("Unexpected event DENIED in state %d", mState); +            break; + +        case AGPS_STATE_ACQUIRED: +            /* NOOP */ +            break; + +        case AGPS_STATE_RELEASING: +            /* Notify all inactive subscribers about the event */ +            notifyAllSubscribers( +                    AGPS_EVENT_RELEASED, true, +                    AGPS_NOTIFICATION_TYPE_FOR_INACTIVE_SUBSCRIBERS); + +            /* If we have active subscribers now, they must be waiting for +             * data conn setup */ +            if (anyActiveSubscribers()) { +                transitionState(AGPS_STATE_PENDING); +                requestOrReleaseDataConn(true); +            } +            /* No active subscribers, move to released state */ +            else { +                transitionState(AGPS_STATE_RELEASED); +            } +            break; + +        case AGPS_STATE_PENDING: +            transitionState(AGPS_STATE_RELEASED); +            notifyAllSubscribers( +                    AGPS_EVENT_DENIED, true, +                    AGPS_NOTIFICATION_TYPE_FOR_ALL_SUBSCRIBERS); +            break; + +        default: +            LOC_LOGE("Invalid state: %d", mState); +    } +} + +/* Request or Release data connection + * bool request : + *      true  = Request data connection + *      false = Release data connection */ +void AgpsStateMachine::requestOrReleaseDataConn(bool request){ + +    AGnssExtStatusIpV4 nifRequest; +    memset(&nifRequest, 0, sizeof(nifRequest)); + +    nifRequest.type = mAgpsType; +    nifRequest.apnTypeMask = mApnTypeMask; +    if (request) { +        LOC_LOGD("AGPS Data Conn Request mAgpsType=%d mApnTypeMask=0x%X", +                 mAgpsType, mApnTypeMask); +        nifRequest.status = LOC_GPS_REQUEST_AGPS_DATA_CONN; +    } +    else{ +        LOC_LOGD("AGPS Data Conn Release mAgpsType=%d mApnTypeMask=0x%X", +                 mAgpsType, mApnTypeMask); +        nifRequest.status = LOC_GPS_RELEASE_AGPS_DATA_CONN; +    } + +    mFrameworkStatusV4Cb(nifRequest); +} + +void AgpsStateMachine::notifyAllSubscribers( +        AgpsEvent event, bool deleteSubscriberPostNotify, +        AgpsNotificationType notificationType){ + +    LOC_LOGD("notifyAllSubscribers(): " +            "SM %p, Event %d Delete %d Notification Type %d", +            this, event, deleteSubscriberPostNotify, notificationType); + +    std::list<AgpsSubscriber*>::const_iterator it = mSubscriberList.begin(); +    while ( it != mSubscriberList.end() ) { + +        AgpsSubscriber* subscriber = *it; + +        if (notificationType == AGPS_NOTIFICATION_TYPE_FOR_ALL_SUBSCRIBERS || +                (notificationType == AGPS_NOTIFICATION_TYPE_FOR_INACTIVE_SUBSCRIBERS && +                        subscriber->mIsInactive) || +                (notificationType == AGPS_NOTIFICATION_TYPE_FOR_ACTIVE_SUBSCRIBERS && +                        !subscriber->mIsInactive)) { + +            /* Deleting via this call would require another traversal +             * through subscriber list, inefficient; hence pass in false*/ +            notifyEventToSubscriber(event, subscriber, false); + +            if (deleteSubscriberPostNotify) { +                it = mSubscriberList.erase(it); +                delete subscriber; +            } else { +                it++; +            } +        } else { +            it++; +        } +    } +} + +void AgpsStateMachine::notifyEventToSubscriber( +        AgpsEvent event, AgpsSubscriber* subscriberToNotify, +        bool deleteSubscriberPostNotify) { + +    LOC_LOGD("notifyEventToSubscriber(): " +            "SM %p, Event %d Subscriber %p Delete %d", +            this, event, subscriberToNotify, deleteSubscriberPostNotify); + +    switch (event) { + +        case AGPS_EVENT_GRANTED: +            mAgpsManager->mAtlOpenStatusCb( +                    subscriberToNotify->mConnHandle, 1, getAPN(), getAPNLen(), +                    getBearer(), mAgpsType, mApnTypeMask); +            break; + +        case AGPS_EVENT_DENIED: +            mAgpsManager->mAtlOpenStatusCb( +                    subscriberToNotify->mConnHandle, 0, getAPN(), getAPNLen(), +                    getBearer(), mAgpsType, mApnTypeMask); +            break; + +        case AGPS_EVENT_UNSUBSCRIBE: +        case AGPS_EVENT_RELEASED: +            mAgpsManager->mAtlCloseStatusCb(subscriberToNotify->mConnHandle, 1); +            break; + +        default: +            LOC_LOGE("Invalid event %d", event); +    } + +    /* Search this subscriber in list and delete */ +    if (deleteSubscriberPostNotify) { +        deleteSubscriber(subscriberToNotify); +    } +} + +void AgpsStateMachine::transitionState(AgpsState newState){ + +    LOC_LOGD("transitionState(): SM %p, old %d, new %d", +               this, mState, newState); + +    mState = newState; + +    // notify state transitions to all subscribers ? +} + +void AgpsStateMachine::addSubscriber(AgpsSubscriber* subscriberToAdd){ + +    LOC_LOGD("addSubscriber(): SM %p, Subscriber %p", +               this, subscriberToAdd); + +    // Check if subscriber is already present in the current list +    // If not, then add +    std::list<AgpsSubscriber*>::const_iterator it = mSubscriberList.begin(); +    for (; it != mSubscriberList.end(); it++) { +        AgpsSubscriber* subscriber = *it; +        if (subscriber->equals(subscriberToAdd)) { +            LOC_LOGE("Subscriber already in list"); +            return; +        } +    } + +    AgpsSubscriber* cloned = subscriberToAdd->clone(); +    LOC_LOGD("addSubscriber(): cloned subscriber: %p", cloned); +    mSubscriberList.push_back(cloned); +} + +void AgpsStateMachine::deleteSubscriber(AgpsSubscriber* subscriberToDelete){ + +    LOC_LOGD("deleteSubscriber(): SM %p, Subscriber %p", +               this, subscriberToDelete); + +    std::list<AgpsSubscriber*>::const_iterator it = mSubscriberList.begin(); +    while ( it != mSubscriberList.end() ) { + +        AgpsSubscriber* subscriber = *it; +        if (subscriber && subscriber->equals(subscriberToDelete)) { + +            it = mSubscriberList.erase(it); +            delete subscriber; +        } else { +            it++; +        } +    } +} + +bool AgpsStateMachine::anyActiveSubscribers(){ + +    std::list<AgpsSubscriber*>::const_iterator it = mSubscriberList.begin(); +    for (; it != mSubscriberList.end(); it++) { +        AgpsSubscriber* subscriber = *it; +        if (!subscriber->mIsInactive) { +            return true; +        } +    } +    return false; +} + +void AgpsStateMachine::setAPN(char* apn, unsigned int len){ + +    if (NULL != mAPN) { +        delete mAPN; +        mAPN  = NULL; +    } + +    if (NULL == apn || len <= 0 || len > MAX_APN_LEN || strlen(apn) != len) { +        LOC_LOGD("Invalid apn len (%d) or null apn", len); +        mAPN = NULL; +        mAPNLen = 0; +    } else { +        mAPN = new char[len+1]; +        if (NULL != mAPN) { +            memcpy(mAPN, apn, len); +            mAPN[len] = '\0'; +            mAPNLen = len; +        } +    } +} + +AgpsSubscriber* AgpsStateMachine::getSubscriber(int connHandle){ + +    /* Go over the subscriber list */ +    std::list<AgpsSubscriber*>::const_iterator it = mSubscriberList.begin(); +    for (; it != mSubscriberList.end(); it++) { +        AgpsSubscriber* subscriber = *it; +        if (subscriber->mConnHandle == connHandle) { +            return subscriber; +        } +    } + +    /* Not found, return NULL */ +    return NULL; +} + +AgpsSubscriber* AgpsStateMachine::getFirstSubscriber(bool isInactive){ + +    /* Go over the subscriber list */ +    std::list<AgpsSubscriber*>::const_iterator it = mSubscriberList.begin(); +    for (; it != mSubscriberList.end(); it++) { +        AgpsSubscriber* subscriber = *it; +        if(subscriber->mIsInactive == isInactive) { +            return subscriber; +        } +    } + +    /* Not found, return NULL */ +    return NULL; +} + +void AgpsStateMachine::dropAllSubscribers(){ + +    LOC_LOGD("dropAllSubscribers(): SM %p", this); + +    /* Go over the subscriber list */ +    std::list<AgpsSubscriber*>::const_iterator it = mSubscriberList.begin(); +    while ( it != mSubscriberList.end() ) { +        AgpsSubscriber* subscriber = *it; +        it = mSubscriberList.erase(it); +        delete subscriber; +    } +} + +/* -------------------------------------------------------------------- + *   Loc AGPS Manager Methods + * -------------------------------------------------------------------*/ + +/* CREATE AGPS STATE MACHINES + * Must be invoked in Msg Handler context */ +void AgpsManager::createAgpsStateMachines(const AgpsCbInfo& cbInfo) { + +    LOC_LOGD("AgpsManager::createAgpsStateMachines"); + +    bool agpsCapable = +            ((loc_core::ContextBase::mGps_conf.CAPABILITIES & LOC_GPS_CAPABILITY_MSA) || +                    (loc_core::ContextBase::mGps_conf.CAPABILITIES & LOC_GPS_CAPABILITY_MSB)); + +    if (NULL == mInternetNif && (cbInfo.atlType & AGPS_ATL_TYPE_WWAN)) { +        mInternetNif = new AgpsStateMachine(this, LOC_AGPS_TYPE_WWAN_ANY); +        mInternetNif->registerFrameworkStatusCallback((AgnssStatusIpV4Cb)cbInfo.statusV4Cb); +        LOC_LOGD("Internet NIF: %p", mInternetNif); +    } +    if (agpsCapable) { +        if (NULL == mAgnssNif && (cbInfo.atlType & AGPS_ATL_TYPE_SUPL) && +                (cbInfo.atlType & AGPS_ATL_TYPE_SUPL_ES)) { +            mAgnssNif = new AgpsStateMachine(this, LOC_AGPS_TYPE_SUPL); +            mAgnssNif->registerFrameworkStatusCallback((AgnssStatusIpV4Cb)cbInfo.statusV4Cb); +            LOC_LOGD("AGNSS NIF: %p", mAgnssNif); +        } +    } +} + +AgpsStateMachine* AgpsManager::getAgpsStateMachine(AGpsExtType agpsType) { + +    LOC_LOGD("AgpsManager::getAgpsStateMachine(): agpsType %d", agpsType); + +    switch (agpsType) { + +        case LOC_AGPS_TYPE_INVALID: +        case LOC_AGPS_TYPE_SUPL: +        case LOC_AGPS_TYPE_SUPL_ES: +            if (mAgnssNif == NULL) { +                LOC_LOGE("NULL AGNSS NIF !"); +            } +            return mAgnssNif; +        case LOC_AGPS_TYPE_WWAN_ANY: +            if (mInternetNif == NULL) { +                LOC_LOGE("NULL Internet NIF !"); +            } +            return mInternetNif; +        default: +            return mInternetNif; +    } + +    LOC_LOGE("No SM found !"); +    return NULL; +} + +void AgpsManager::requestATL(int connHandle, AGpsExtType agpsType, +                             LocApnTypeMask apnTypeMask){ + +    LOC_LOGD("AgpsManager::requestATL(): connHandle %d, agpsType 0x%X apnTypeMask: 0x%X", +               connHandle, agpsType, apnTypeMask); + +    if (0 == loc_core::ContextBase::mGps_conf.USE_EMERGENCY_PDN_FOR_EMERGENCY_SUPL && +        LOC_AGPS_TYPE_SUPL_ES == agpsType) { +        agpsType = LOC_AGPS_TYPE_SUPL; +        apnTypeMask &= ~LOC_APN_TYPE_MASK_EMERGENCY; +        apnTypeMask |= LOC_APN_TYPE_MASK_SUPL; +        LOC_LOGD("Changed agpsType to non-emergency when USE_EMERGENCY... is 0" +                 "and removed LOC_APN_TYPE_MASK_EMERGENCY from apnTypeMask" +                 "agpsType 0x%X apnTypeMask : 0x%X", +                 agpsType, apnTypeMask); +    } +    AgpsStateMachine* sm = getAgpsStateMachine(agpsType); + +    if (sm == NULL) { + +        LOC_LOGE("No AGPS State Machine for agpsType: %d apnTypeMask: 0x%X", +                 agpsType, apnTypeMask); +        mAtlOpenStatusCb( +                connHandle, 0, NULL, 0, AGPS_APN_BEARER_INVALID, agpsType, apnTypeMask); +        return; +    } +    sm->setType(agpsType); +    sm->setApnTypeMask(apnTypeMask); + +    /* Invoke AGPS SM processing */ +    AgpsSubscriber subscriber(connHandle, false, false, apnTypeMask); +    sm->setCurrentSubscriber(&subscriber); +    /* Send subscriber event */ +    sm->processAgpsEvent(AGPS_EVENT_SUBSCRIBE); +} + +void AgpsManager::releaseATL(int connHandle){ + +    LOC_LOGD("AgpsManager::releaseATL(): connHandle %d", connHandle); + +    /* First find the subscriber with specified handle. +     * We need to search in all state machines. */ +    AgpsStateMachine* sm = NULL; +    AgpsSubscriber* subscriber = NULL; + +    if (mAgnssNif && +            (subscriber = mAgnssNif->getSubscriber(connHandle)) != NULL) { +        sm = mAgnssNif; +    } +    else if (mInternetNif && +            (subscriber = mInternetNif->getSubscriber(connHandle)) != NULL) { +        sm = mInternetNif; +    } +    if (sm == NULL) { +        LOC_LOGE("Subscriber with connHandle %d not found in any SM", +                    connHandle); +        return; +    } + +    /* Now send unsubscribe event */ +    sm->setCurrentSubscriber(subscriber); +    sm->processAgpsEvent(AGPS_EVENT_UNSUBSCRIBE); +} + +void AgpsManager::reportAtlOpenSuccess( +        AGpsExtType agpsType, char* apnName, int apnLen, +        AGpsBearerType bearerType){ + +    LOC_LOGD("AgpsManager::reportAtlOpenSuccess(): " +             "AgpsType %d, APN [%s], Len %d, BearerType %d", +             agpsType, apnName, apnLen, bearerType); + +    /* Find the state machine instance */ +    AgpsStateMachine* sm = getAgpsStateMachine(agpsType); + +    /* Set bearer and apn info in state machine instance */ +    sm->setBearer(bearerType); +    sm->setAPN(apnName, apnLen); + +    /* Send GRANTED event to state machine */ +    sm->processAgpsEvent(AGPS_EVENT_GRANTED); +} + +void AgpsManager::reportAtlOpenFailed(AGpsExtType agpsType){ + +    LOC_LOGD("AgpsManager::reportAtlOpenFailed(): AgpsType %d", agpsType); + +    /* Fetch SM and send DENIED event */ +    AgpsStateMachine* sm = getAgpsStateMachine(agpsType); +    sm->processAgpsEvent(AGPS_EVENT_DENIED); +} + +void AgpsManager::reportAtlClosed(AGpsExtType agpsType){ + +    LOC_LOGD("AgpsManager::reportAtlClosed(): AgpsType %d", agpsType); + +    /* Fetch SM and send RELEASED event */ +    AgpsStateMachine* sm = getAgpsStateMachine(agpsType); +    sm->processAgpsEvent(AGPS_EVENT_RELEASED); +} + +void AgpsManager::handleModemSSR(){ + +    LOC_LOGD("AgpsManager::handleModemSSR"); + +    /* Drop subscribers from all state machines */ +    if (mAgnssNif) { +        mAgnssNif->dropAllSubscribers(); +    } +    if (mInternetNif) { +        mInternetNif->dropAllSubscribers(); +    } +} diff --git a/gps/gnss/Agps.h b/gps/gnss/Agps.h new file mode 100644 index 0000000..6b43bf5 --- /dev/null +++ b/gps/gnss/Agps.h @@ -0,0 +1,318 @@ +/* Copyright (c) 2012-2018, 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. + * + */ + +#ifndef AGPS_H +#define AGPS_H + +#include <functional> +#include <list> +#include <MsgTask.h> +#include <gps_extended_c.h> +#include <loc_pla.h> +#include <log_util.h> + +using namespace loc_util; + +/* ATL callback function pointers + * Passed in by Adapter to AgpsManager */ +typedef std::function<void( +        int handle, int isSuccess, char* apn, uint32_t apnLen, +        AGpsBearerType bearerType, AGpsExtType agpsType, +        LocApnTypeMask mask)> AgpsAtlOpenStatusCb; + +typedef std::function<void(int handle, int isSuccess)> AgpsAtlCloseStatusCb; + +/* Post message to adapter's message queue */ +typedef std::function<void(LocMsg* msg)>     SendMsgToAdapterMsgQueueFn; + +/* AGPS States */ +typedef enum { +    AGPS_STATE_INVALID = 0, +    AGPS_STATE_RELEASED, +    AGPS_STATE_PENDING, +    AGPS_STATE_ACQUIRED, +    AGPS_STATE_RELEASING +} AgpsState; + +typedef enum { +    AGPS_EVENT_INVALID = 0, +    AGPS_EVENT_SUBSCRIBE, +    AGPS_EVENT_UNSUBSCRIBE, +    AGPS_EVENT_GRANTED, +    AGPS_EVENT_RELEASED, +    AGPS_EVENT_DENIED +} AgpsEvent; + +/* Notification Types sent to subscribers */ +typedef enum { +    AGPS_NOTIFICATION_TYPE_INVALID = 0, + +    /* Meant for all subscribers, either active or inactive */ +    AGPS_NOTIFICATION_TYPE_FOR_ALL_SUBSCRIBERS, + +    /* Meant for only inactive subscribers */ +    AGPS_NOTIFICATION_TYPE_FOR_INACTIVE_SUBSCRIBERS, + +    /* Meant for only active subscribers */ +    AGPS_NOTIFICATION_TYPE_FOR_ACTIVE_SUBSCRIBERS +} AgpsNotificationType; + +/* Classes in this header */ +class AgpsSubscriber; +class AgpsManager; +class AgpsStateMachine; + +/* SUBSCRIBER + * Each Subscriber instance corresponds to one AGPS request, + * received by the AGPS state machine */ +class AgpsSubscriber { + +public: +    int mConnHandle; + +    /* Does this subscriber wait for data call close complete, +     * before being notified ATL close ? +     * While waiting for data call close, subscriber will be in +     * inactive state. */ +    bool mWaitForCloseComplete; +    bool mIsInactive; +    LocApnTypeMask mApnTypeMask; + +    inline AgpsSubscriber( +            int connHandle, bool waitForCloseComplete, bool isInactive, +            LocApnTypeMask apnTypeMask) : +            mConnHandle(connHandle), +            mWaitForCloseComplete(waitForCloseComplete), +            mIsInactive(isInactive), +            mApnTypeMask(apnTypeMask) {} +    inline virtual ~AgpsSubscriber() {} + +    inline virtual bool equals(const AgpsSubscriber *s) const +    { return (mConnHandle == s->mConnHandle); } + +    inline virtual AgpsSubscriber* clone() +    { return new AgpsSubscriber( +            mConnHandle, mWaitForCloseComplete, mIsInactive, mApnTypeMask); } +}; + +/* AGPS STATE MACHINE */ +class AgpsStateMachine { +protected: +    /* AGPS Manager instance, from where this state machine is created */ +    AgpsManager* mAgpsManager; + +    /* List of all subscribers for this State Machine. +     * Once a subscriber is notified for ATL open/close status, +     * it is deleted */ +    std::list<AgpsSubscriber*> mSubscriberList; + +    /* Current subscriber, whose request this State Machine is +     * currently processing */ +    AgpsSubscriber* mCurrentSubscriber; + +    /* Current state for this state machine */ +    AgpsState mState; + +    AgnssStatusIpV4Cb     mFrameworkStatusV4Cb; +private: +    /* AGPS Type for this state machine +       LOC_AGPS_TYPE_ANY           0 +       LOC_AGPS_TYPE_SUPL          1 +       LOC_AGPS_TYPE_WWAN_ANY      3 +       LOC_AGPS_TYPE_SUPL_ES       5 */ +    AGpsExtType mAgpsType; +    LocApnTypeMask mApnTypeMask; + +    /* APN and IP Type info for AGPS Call */ +    char* mAPN; +    unsigned int mAPNLen; +    AGpsBearerType mBearer; + +public: +    /* CONSTRUCTOR */ +    AgpsStateMachine(AgpsManager* agpsManager, AGpsExtType agpsType): +        mFrameworkStatusV4Cb(NULL), +        mAgpsManager(agpsManager), mSubscriberList(), +        mCurrentSubscriber(NULL), mState(AGPS_STATE_RELEASED), +        mAgpsType(agpsType), mAPN(NULL), mAPNLen(0), +        mBearer(AGPS_APN_BEARER_INVALID) {}; + +    virtual ~AgpsStateMachine() { if(NULL != mAPN) delete[] mAPN; }; + +    /* Getter/Setter methods */ +    void setAPN(char* apn, unsigned int len); +    inline char* getAPN() const { return (char*)mAPN; } +    inline uint32_t getAPNLen() const { return mAPNLen; } +    inline void setBearer(AGpsBearerType bearer) { mBearer = bearer; } +    inline LocApnTypeMask getApnTypeMask() const { return mApnTypeMask; } +    inline void setApnTypeMask(LocApnTypeMask apnTypeMask) +    { mApnTypeMask = apnTypeMask; } +    inline AGpsBearerType getBearer() const { return mBearer; } +    inline void setType(AGpsExtType type) { mAgpsType = type; } +    inline AGpsExtType getType() const { return mAgpsType; } +    inline void setCurrentSubscriber(AgpsSubscriber* subscriber) +    { mCurrentSubscriber = subscriber; } + +    inline void registerFrameworkStatusCallback(AgnssStatusIpV4Cb frameworkStatusV4Cb) { +        mFrameworkStatusV4Cb = frameworkStatusV4Cb; +    } + +    /* Fetch subscriber with specified handle */ +    AgpsSubscriber* getSubscriber(int connHandle); + +    /* Fetch first active or inactive subscriber in list +     * isInactive = true : fetch first inactive subscriber +     * isInactive = false : fetch first active subscriber */ +    AgpsSubscriber* getFirstSubscriber(bool isInactive); + +    /* Process LOC AGPS Event being passed in +     * onRsrcEvent */ +    virtual void processAgpsEvent(AgpsEvent event); + +    /* Drop all subscribers, in case of Modem SSR */ +    void dropAllSubscribers(); + +protected: +    /* Remove the specified subscriber from list if present. +     * Also delete the subscriber instance. */ +    void deleteSubscriber(AgpsSubscriber* subscriber); + +private: +    /* Send call setup request to framework +     * sendRsrcRequest(LOC_GPS_REQUEST_AGPS_DATA_CONN) +     * sendRsrcRequest(LOC_GPS_RELEASE_AGPS_DATA_CONN) */ +    void requestOrReleaseDataConn(bool request); + +    /* Individual event processing methods */ +    void processAgpsEventSubscribe(); +    void processAgpsEventUnsubscribe(); +    void processAgpsEventGranted(); +    void processAgpsEventReleased(); +    void processAgpsEventDenied(); + +    /* Clone the passed in subscriber and add to the subscriber list +     * if not already present */ +    void addSubscriber(AgpsSubscriber* subscriber); + +    /* Notify subscribers about AGPS events */ +    void notifyAllSubscribers( +            AgpsEvent event, bool deleteSubscriberPostNotify, +            AgpsNotificationType notificationType); +    virtual void notifyEventToSubscriber( +            AgpsEvent event, AgpsSubscriber* subscriber, +            bool deleteSubscriberPostNotify); + +    /* Do we have any subscribers in active state */ +    bool anyActiveSubscribers(); + +    /* Transition state */ +    void transitionState(AgpsState newState); +}; + +/* LOC AGPS MANAGER */ +class AgpsManager { + +    friend class AgpsStateMachine; +public: +    /* CONSTRUCTOR */ +    AgpsManager(): +        mAtlOpenStatusCb(), mAtlCloseStatusCb(), +        mAgnssNif(NULL), mInternetNif(NULL)/*, mDsNif(NULL)*/ {} + +    /* Register callbacks */ +    inline void registerATLCallbacks(AgpsAtlOpenStatusCb  atlOpenStatusCb, +            AgpsAtlCloseStatusCb                atlCloseStatusCb) { + +        mAtlOpenStatusCb = atlOpenStatusCb; +        mAtlCloseStatusCb = atlCloseStatusCb; +    } + +    /* Check if AGPS client is registered */ +    inline bool isRegistered() { return nullptr != mAgnssNif || nullptr != mInternetNif; } + +    /* Create all AGPS state machines */ +    void createAgpsStateMachines(const AgpsCbInfo& cbInfo); + +    /* Process incoming ATL requests */ +    void requestATL(int connHandle, AGpsExtType agpsType, LocApnTypeMask apnTypeMask); +    void releaseATL(int connHandle); +    /* Process incoming framework data call events */ +    void reportAtlOpenSuccess(AGpsExtType agpsType, char* apnName, int apnLen, +            AGpsBearerType bearerType); +    void reportAtlOpenFailed(AGpsExtType agpsType); +    void reportAtlClosed(AGpsExtType agpsType); + +    /* Handle Modem SSR */ +    void handleModemSSR(); + +protected: + +    AgpsAtlOpenStatusCb   mAtlOpenStatusCb; +    AgpsAtlCloseStatusCb  mAtlCloseStatusCb; +    AgpsStateMachine*   mAgnssNif; +    AgpsStateMachine*   mInternetNif; +private: +    /* Fetch state machine for handling request ATL call */ +    AgpsStateMachine* getAgpsStateMachine(AGpsExtType agpsType); +}; + +/* Request SUPL/INTERNET/SUPL_ES ATL + * This LocMsg is defined in this header since it has to be used from more + * than one place, other Agps LocMsg are restricted to GnssAdapter and + * declared inline */ +struct AgpsMsgRequestATL: public LocMsg { + +    AgpsManager* mAgpsManager; +    int mConnHandle; +    AGpsExtType mAgpsType; +    LocApnTypeMask mApnTypeMask; + +    inline AgpsMsgRequestATL(AgpsManager* agpsManager, int connHandle, +            AGpsExtType agpsType, LocApnTypeMask apnTypeMask) : +            LocMsg(), mAgpsManager(agpsManager), mConnHandle(connHandle), +            mAgpsType(agpsType), mApnTypeMask(apnTypeMask){ + +        LOC_LOGV("AgpsMsgRequestATL"); +    } + +    inline virtual void proc() const { + +        LOC_LOGV("AgpsMsgRequestATL::proc()"); +        mAgpsManager->requestATL(mConnHandle, mAgpsType, mApnTypeMask); +    } +}; + +namespace AgpsUtils { + +AGpsBearerType ipTypeToBearerType(LocApnIpType ipType); +LocApnIpType bearerTypeToIpType(AGpsBearerType bearerType); + +} + +#endif /* AGPS_H */ diff --git a/gps/gnss/Android.bp b/gps/gnss/Android.bp new file mode 100644 index 0000000..a3e8de9 --- /dev/null +++ b/gps/gnss/Android.bp @@ -0,0 +1,35 @@ + + +cc_library_shared { + +    name: "libgnss", +    vendor: true, + +    sanitize: GNSS_SANITIZE, + +    shared_libs: [ +        "libutils", +        "libcutils", +        "libdl", +        "liblog", +        "libloc_core", +        "libgps.utils", +    ], + +    srcs: [ +        "location_gnss.cpp", +        "GnssAdapter.cpp", +        "Agps.cpp", +        "XtraSystemStatusObserver.cpp", +        "NativeAgpsHandler.cpp", +    ], + +    cflags: ["-fno-short-enums"] + GNSS_CFLAGS, +    header_libs: [ +        "libgps.utils_headers", +        "libloc_core_headers", +        "libloc_pla_headers", +        "liblocation_api_headers", +    ], + +} diff --git a/gps/gnss/GnssAdapter.cpp b/gps/gnss/GnssAdapter.cpp new file mode 100644 index 0000000..cff0298 --- /dev/null +++ b/gps/gnss/GnssAdapter.cpp @@ -0,0 +1,6916 @@ +/* Copyright (c) 2017-2020 The Linux Foundation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + *     * Redistributions of source code must retain the above copyright + *       notice, this list of conditions and the following disclaimer. + *     * Redistributions in binary form must reproduce the above + *       copyright notice, this list of conditions and the following + *       disclaimer in the documentation and/or other materials provided + *       with the distribution. + *     * Neither the name of The Linux Foundation, nor the names of its + *       contributors may be used to endorse or promote products derived + *       from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT + * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ +#define LOG_NDEBUG 0 +#define LOG_TAG "LocSvc_GnssAdapter" + +#include <inttypes.h> +#include <sys/stat.h> +#include <errno.h> +#include <ctype.h> +#include <cutils/properties.h> +#include <math.h> +#include <arpa/inet.h> +#include <netinet/in.h> +#include <netdb.h> +#include <GnssAdapter.h> +#include <string> +#include <sstream> +#include <loc_log.h> +#include <loc_nmea.h> +#include <Agps.h> +#include <SystemStatus.h> +#include <vector> +#include <loc_misc_utils.h> +#include <gps_extended_c.h> + +#define RAD2DEG    (180.0 / M_PI) +#define DEG2RAD    (M_PI / 180.0) +#define PROCESS_NAME_ENGINE_SERVICE "engine-service" +#define MIN_TRACKING_INTERVAL (100) // 100 msec + +#define BILLION_NSEC (1000000000ULL) +#define NMEA_MIN_THRESHOLD_MSEC (99) +#define NMEA_MAX_THRESHOLD_MSEC (975) + +#define DGNSS_RANGE_UPDATE_TIME_10MIN_IN_MILLI  600000 + +using namespace loc_core; + +static int loadEngHubForExternalEngine = 0; +static loc_param_s_type izatConfParamTable[] = { +    {"LOAD_ENGHUB_FOR_EXTERNAL_ENGINE", &loadEngHubForExternalEngine, nullptr,'n'} +}; + +/* Method to fetch status cb from loc_net_iface library */ +typedef AgpsCbInfo& (*LocAgpsGetAgpsCbInfo)(LocAgpsOpenResultCb openResultCb, +        LocAgpsCloseResultCb closeResultCb, void* userDataPtr); + +static void agpsOpenResultCb (bool isSuccess, AGpsExtType agpsType, const char* apn, +        AGpsBearerType bearerType, void* userDataPtr); +static void agpsCloseResultCb (bool isSuccess, AGpsExtType agpsType, void* userDataPtr); + +typedef const CdfwInterface* (*getCdfwInterface)(); + +inline bool GnssReportLoggerUtil::isLogEnabled() { +    return (mLogLatency != nullptr); +} + +inline void GnssReportLoggerUtil::log(const GnssLatencyInfo& gnssLatencyMeasInfo) { +    if (mLogLatency != nullptr) { +        mLogLatency(gnssLatencyMeasInfo); +    } +} + +GnssAdapter::GnssAdapter() : +    LocAdapterBase(0, +                   LocContext::getLocContext(LocContext::mLocationHalName), +                   true, nullptr, true), +    mEngHubProxy(new EngineHubProxyBase()), +    mQDgnssListenerHDL(nullptr), +    mCdfwInterface(nullptr), +    mDGnssNeedReport(false), +    mDGnssDataUsage(false), +    mLocPositionMode(), +    mNHzNeeded(false), +    mSPEAlreadyRunningAtHighestInterval(false), +    mGnssSvIdUsedInPosition(), +    mGnssSvIdUsedInPosAvail(false), +    mControlCallbacks(), +    mAfwControlId(0), +    mNmeaMask(0), +    mGnssSvIdConfig(), +    mGnssSeconaryBandConfig(), +    mGnssSvTypeConfig(), +    mGnssSvTypeConfigCb(nullptr), +    mLocConfigInfo{}, +    mNiData(), +    mAgpsManager(), +    mOdcpiRequestCb(nullptr), +    mOdcpiRequestActive(false), +    mOdcpiTimer(this), +    mOdcpiRequest(), +    mCallbackPriority(OdcpiPrioritytype::ODCPI_HANDLER_PRIORITY_LOW), +    mSystemStatus(SystemStatus::getInstance(mMsgTask)), +    mServerUrl(":"), +    mXtraObserver(mSystemStatus->getOsObserver(), mMsgTask), +    mBlockCPIInfo{}, +    mDreIntEnabled(false), +    mLocSystemInfo{}, +    mNfwCb(NULL), +    mPowerOn(false), +    mAllowFlpNetworkFixes(0), +    mGnssEnergyConsumedCb(nullptr), +    mPowerStateCb(nullptr), +    mIsE911Session(NULL), +    mGnssMbSvIdUsedInPosition{}, +    mGnssMbSvIdUsedInPosAvail(false), +    mSupportNfwControl(true), +    mSystemPowerState(POWER_STATE_UNKNOWN), +    mIsMeasCorrInterfaceOpen(false), +    mIsAntennaInfoInterfaceOpened(false), +    mLastDeleteAidingDataTime(0), +    mDgnssState(0), +    mSendNmeaConsent(false), +    mDgnssLastNmeaBootTimeMilli(0), +    mNativeAgpsHandler(mSystemStatus->getOsObserver(), *this) +{ +    LOC_LOGD("%s]: Constructor %p", __func__, this); +    mLocPositionMode.mode = LOC_POSITION_MODE_INVALID; + +    pthread_condattr_t condAttr; +    pthread_condattr_init(&condAttr); +    pthread_condattr_setclock(&condAttr, CLOCK_MONOTONIC); +    pthread_cond_init(&mNiData.session.tCond, &condAttr); +    pthread_cond_init(&mNiData.sessionEs.tCond, &condAttr); +    pthread_condattr_destroy(&condAttr); + +    /* Set ATL open/close callbacks */ +    AgpsAtlOpenStatusCb atlOpenStatusCb = +            [this](int handle, int isSuccess, char* apn, uint32_t apnLen, +                    AGpsBearerType bearerType, AGpsExtType agpsType, LocApnTypeMask mask) { + +                mLocApi->atlOpenStatus( +                        handle, isSuccess, apn, apnLen, bearerType, agpsType, mask); +            }; +    AgpsAtlCloseStatusCb atlCloseStatusCb = +            [this](int handle, int isSuccess) { + +                mLocApi->atlCloseStatus(handle, isSuccess); +            }; +    mAgpsManager.registerATLCallbacks(atlOpenStatusCb, atlCloseStatusCb); + +    readConfigCommand(); +    initDefaultAgpsCommand(); +    initEngHubProxyCommand(); + +    // at last step, let us inform adapater base that we are done +    // with initialization, e.g.: ready to process handleEngineUpEvent +    doneInit(); +} + +void +GnssAdapter::setControlCallbacksCommand(LocationControlCallbacks& controlCallbacks) +{ +    struct MsgSetControlCallbacks : public LocMsg { +        GnssAdapter& mAdapter; +        const LocationControlCallbacks mControlCallbacks; +        inline MsgSetControlCallbacks(GnssAdapter& adapter, +                                      LocationControlCallbacks& controlCallbacks) : +            LocMsg(), +            mAdapter(adapter), +            mControlCallbacks(controlCallbacks) {} +        inline virtual void proc() const { +            mAdapter.setControlCallbacks(mControlCallbacks); +        } +    }; + +    sendMsg(new MsgSetControlCallbacks(*this, controlCallbacks)); +} + +void +GnssAdapter::convertOptions(LocPosMode& out, const TrackingOptions& trackingOptions) +{ +    switch (trackingOptions.mode) { +    case GNSS_SUPL_MODE_MSB: +        out.mode = LOC_POSITION_MODE_MS_BASED; +        break; +    case GNSS_SUPL_MODE_MSA: +        out.mode = LOC_POSITION_MODE_MS_ASSISTED; +        break; +    default: +        out.mode = LOC_POSITION_MODE_STANDALONE; +        break; +    } +    out.share_position = true; +    out.min_interval = trackingOptions.minInterval; +    out.powerMode = trackingOptions.powerMode; +    out.timeBetweenMeasurements = trackingOptions.tbm; +} + +bool +GnssAdapter::checkAndSetSPEToRunforNHz(TrackingOptions & out) { + +    // first check if NHz meas is needed at all, if not, just return false +    // if a NHz capable engine is subscribed for NHz measurement or NHz positions, +    // always run the SPE only session at 100ms TBF. +    // If SPE session is already set to highest interval, no need to start it again. + +    bool isSPERunningAtHighestInterval = false; + +    if (!mNHzNeeded) { +        LOC_LOGd("No nHz session needed."); +    } else if (mSPEAlreadyRunningAtHighestInterval) { +        LOC_LOGd("SPE is already running at highest interval."); +        isSPERunningAtHighestInterval = true; +    } else if (out.minInterval > MIN_TRACKING_INTERVAL) { +        out.minInterval = MIN_TRACKING_INTERVAL; +        LOC_LOGd("nHz session is needed, starting SPE only session at 100ms TBF."); +        mSPEAlreadyRunningAtHighestInterval = true; +    } + +    return isSPERunningAtHighestInterval; +} + + +void +GnssAdapter::convertLocation(Location& out, const UlpLocation& ulpLocation, +                             const GpsLocationExtended& locationExtended) +{ +    memset(&out, 0, sizeof(Location)); +    out.size = sizeof(Location); +    if (LOC_GPS_LOCATION_HAS_LAT_LONG & ulpLocation.gpsLocation.flags) { +        out.flags |= LOCATION_HAS_LAT_LONG_BIT; +        out.latitude = ulpLocation.gpsLocation.latitude; +        out.longitude = ulpLocation.gpsLocation.longitude; +    } +    if (LOC_GPS_LOCATION_HAS_ALTITUDE & ulpLocation.gpsLocation.flags) { +        out.flags |= LOCATION_HAS_ALTITUDE_BIT; +        out.altitude = ulpLocation.gpsLocation.altitude; +    } +    if (LOC_GPS_LOCATION_HAS_SPEED & ulpLocation.gpsLocation.flags) { +        out.flags |= LOCATION_HAS_SPEED_BIT; +        out.speed = ulpLocation.gpsLocation.speed; +    } +    if (LOC_GPS_LOCATION_HAS_BEARING & ulpLocation.gpsLocation.flags) { +        out.flags |= LOCATION_HAS_BEARING_BIT; +        out.bearing = ulpLocation.gpsLocation.bearing; +    } +    if (LOC_GPS_LOCATION_HAS_ACCURACY & ulpLocation.gpsLocation.flags) { +        out.flags |= LOCATION_HAS_ACCURACY_BIT; +        out.accuracy = ulpLocation.gpsLocation.accuracy; +    } +    if (GPS_LOCATION_EXTENDED_HAS_VERT_UNC & locationExtended.flags) { +        out.flags |= LOCATION_HAS_VERTICAL_ACCURACY_BIT; +        out.verticalAccuracy = locationExtended.vert_unc; +    } +    if (GPS_LOCATION_EXTENDED_HAS_SPEED_UNC & locationExtended.flags) { +        out.flags |= LOCATION_HAS_SPEED_ACCURACY_BIT; +        out.speedAccuracy = locationExtended.speed_unc; +    } +    if (GPS_LOCATION_EXTENDED_HAS_BEARING_UNC & locationExtended.flags) { +        out.flags |= LOCATION_HAS_BEARING_ACCURACY_BIT; +        out.bearingAccuracy = locationExtended.bearing_unc; +    } +    if (GPS_LOCATION_EXTENDED_HAS_CONFORMITY_INDEX & locationExtended.flags) { +        out.flags |= LOCATION_HAS_CONFORMITY_INDEX_BIT; +        out.conformityIndex = locationExtended.conformityIndex; +    } +    out.timestamp = ulpLocation.gpsLocation.timestamp; +    if (LOC_POS_TECH_MASK_SATELLITE & locationExtended.tech_mask) { +        out.techMask |= LOCATION_TECHNOLOGY_GNSS_BIT; +    } +    if (LOC_POS_TECH_MASK_CELLID & locationExtended.tech_mask) { +        out.techMask |= LOCATION_TECHNOLOGY_CELL_BIT; +    } +    if (LOC_POS_TECH_MASK_WIFI & locationExtended.tech_mask) { +        out.techMask |= LOCATION_TECHNOLOGY_WIFI_BIT; +    } +    if (LOC_POS_TECH_MASK_SENSORS & locationExtended.tech_mask) { +        out.techMask |= LOCATION_TECHNOLOGY_SENSORS_BIT; +    } +    if (LOC_POS_TECH_MASK_REFERENCE_LOCATION & locationExtended.tech_mask) { +        out.techMask |= LOCATION_TECHNOLOGY_REFERENCE_LOCATION_BIT; +    } +    if (LOC_POS_TECH_MASK_INJECTED_COARSE_POSITION & locationExtended.tech_mask) { +        out.techMask |= LOCATION_TECHNOLOGY_INJECTED_COARSE_POSITION_BIT; +    } +    if (LOC_POS_TECH_MASK_AFLT & locationExtended.tech_mask) { +        out.techMask |= LOCATION_TECHNOLOGY_AFLT_BIT; +    } +    if (LOC_POS_TECH_MASK_HYBRID & locationExtended.tech_mask) { +        out.techMask |= LOCATION_TECHNOLOGY_HYBRID_BIT; +    } +    if (LOC_POS_TECH_MASK_PPE & locationExtended.tech_mask) { +        out.techMask |= LOCATION_TECHNOLOGY_PPE_BIT; +    } +    if (LOC_POS_TECH_MASK_VEH & locationExtended.tech_mask) { +        out.techMask |= LOCATION_TECHNOLOGY_VEH_BIT; +    } +    if (LOC_POS_TECH_MASK_VIS & locationExtended.tech_mask) { +        out.techMask |= LOCATION_TECHNOLOGY_VIS_BIT; +    } +    if (LOC_NAV_MASK_DGNSS_CORRECTION & locationExtended.navSolutionMask) { +        out.techMask |= LOCATION_TECHNOLOGY_DGNSS_BIT; +    } + +    if (LOC_GPS_LOCATION_HAS_SPOOF_MASK & ulpLocation.gpsLocation.flags) { +        out.flags |= LOCATION_HAS_SPOOF_MASK; +        out.spoofMask = ulpLocation.gpsLocation.spoof_mask; +    } +    if (LOC_GPS_LOCATION_HAS_ELAPSED_REAL_TIME & ulpLocation.gpsLocation.flags) { +        out.flags |= LOCATION_HAS_ELAPSED_REAL_TIME; +        out.elapsedRealTime = ulpLocation.gpsLocation.elapsedRealTime; +        out.elapsedRealTimeUnc = ulpLocation.gpsLocation.elapsedRealTimeUnc; +    } +} + +/* This is utility routine that computes number of SV used +   in the fix from the svUsedIdsMask. + */ +#define MAX_SV_CNT_SUPPORTED_IN_ONE_CONSTELLATION 64 +uint16_t GnssAdapter::getNumSvUsed(uint64_t svUsedIdsMask, +                                   int totalSvCntInThisConstellation) +{ +    if (totalSvCntInThisConstellation > MAX_SV_CNT_SUPPORTED_IN_ONE_CONSTELLATION) { +        LOC_LOGe ("error: total SV count in this constellation %d exceeded limit of %d", +                  totalSvCntInThisConstellation, MAX_SV_CNT_SUPPORTED_IN_ONE_CONSTELLATION); +        return 0; +    } + +    uint16_t numSvUsed = 0; +    uint64_t mask = 0x1; +    for (int i = 0; i < totalSvCntInThisConstellation; i++) { +        if (svUsedIdsMask & mask) { +            numSvUsed++; +        } +        mask <<= 1; +    } + +    return numSvUsed; +} + +void +GnssAdapter::convertLocationInfo(GnssLocationInfoNotification& out, +                                 const GpsLocationExtended& locationExtended, +                                 enum loc_sess_status status) +{ +    out.size = sizeof(GnssLocationInfoNotification); +    if (GPS_LOCATION_EXTENDED_HAS_ALTITUDE_MEAN_SEA_LEVEL & locationExtended.flags) { +        out.flags |= GNSS_LOCATION_INFO_ALTITUDE_MEAN_SEA_LEVEL_BIT; +        out.altitudeMeanSeaLevel = locationExtended.altitudeMeanSeaLevel; +    } +    if (GPS_LOCATION_EXTENDED_HAS_EXT_DOP & locationExtended.flags) { +        out.flags |= (GNSS_LOCATION_INFO_DOP_BIT|GNSS_LOCATION_INFO_EXT_DOP_BIT); +        out.pdop = locationExtended.extDOP.PDOP; +        out.hdop = locationExtended.extDOP.HDOP; +        out.vdop = locationExtended.extDOP.VDOP; +        out.gdop = locationExtended.extDOP.GDOP; +        out.tdop = locationExtended.extDOP.TDOP; +    } else if (GPS_LOCATION_EXTENDED_HAS_DOP & locationExtended.flags) { +        out.flags |= GNSS_LOCATION_INFO_DOP_BIT; +        out.pdop = locationExtended.pdop; +        out.hdop = locationExtended.hdop; +        out.vdop = locationExtended.vdop; +    } +    if (GPS_LOCATION_EXTENDED_HAS_MAG_DEV & locationExtended.flags) { +        out.flags |= GNSS_LOCATION_INFO_MAGNETIC_DEVIATION_BIT; +        out.magneticDeviation = locationExtended.magneticDeviation; +    } +    if (GPS_LOCATION_EXTENDED_HAS_HOR_RELIABILITY & locationExtended.flags) { +        out.flags |= GNSS_LOCATION_INFO_HOR_RELIABILITY_BIT; +        switch (locationExtended.horizontal_reliability) { +            case LOC_RELIABILITY_VERY_LOW: +                out.horReliability = LOCATION_RELIABILITY_VERY_LOW; +                break; +            case LOC_RELIABILITY_LOW: +                out.horReliability = LOCATION_RELIABILITY_LOW; +                break; +            case LOC_RELIABILITY_MEDIUM: +                out.horReliability = LOCATION_RELIABILITY_MEDIUM; +                break; +            case LOC_RELIABILITY_HIGH: +                out.horReliability = LOCATION_RELIABILITY_HIGH; +                break; +            default: +                out.horReliability = LOCATION_RELIABILITY_NOT_SET; +                break; +        } +    } +    if (GPS_LOCATION_EXTENDED_HAS_VERT_RELIABILITY & locationExtended.flags) { +        out.flags |= GNSS_LOCATION_INFO_VER_RELIABILITY_BIT; +        switch (locationExtended.vertical_reliability) { +            case LOC_RELIABILITY_VERY_LOW: +                out.verReliability = LOCATION_RELIABILITY_VERY_LOW; +                break; +            case LOC_RELIABILITY_LOW: +                out.verReliability = LOCATION_RELIABILITY_LOW; +                break; +            case LOC_RELIABILITY_MEDIUM: +                out.verReliability = LOCATION_RELIABILITY_MEDIUM; +                break; +            case LOC_RELIABILITY_HIGH: +                out.verReliability = LOCATION_RELIABILITY_HIGH; +                break; +            default: +                out.verReliability = LOCATION_RELIABILITY_NOT_SET; +                break; +        } +    } +    if (GPS_LOCATION_EXTENDED_HAS_HOR_ELIP_UNC_MAJOR & locationExtended.flags) { +        out.flags |= GNSS_LOCATION_INFO_HOR_ACCURACY_ELIP_SEMI_MAJOR_BIT; +        out.horUncEllipseSemiMajor = locationExtended.horUncEllipseSemiMajor; +    } +    if (GPS_LOCATION_EXTENDED_HAS_HOR_ELIP_UNC_MINOR & locationExtended.flags) { +        out.flags |= GNSS_LOCATION_INFO_HOR_ACCURACY_ELIP_SEMI_MINOR_BIT; +        out.horUncEllipseSemiMinor = locationExtended.horUncEllipseSemiMinor; +    } +    if (GPS_LOCATION_EXTENDED_HAS_HOR_ELIP_UNC_AZIMUTH & locationExtended.flags) { +        out.flags |= GNSS_LOCATION_INFO_HOR_ACCURACY_ELIP_AZIMUTH_BIT; +        out.horUncEllipseOrientAzimuth = locationExtended.horUncEllipseOrientAzimuth; +    } +    if (GPS_LOCATION_EXTENDED_HAS_NORTH_STD_DEV & locationExtended.flags) { +        out.flags |= GNSS_LOCATION_INFO_NORTH_STD_DEV_BIT; +        out.northStdDeviation = locationExtended.northStdDeviation; +    } +    if (GPS_LOCATION_EXTENDED_HAS_EAST_STD_DEV & locationExtended.flags) { +        out.flags |= GNSS_LOCATION_INFO_EAST_STD_DEV_BIT; +        out.eastStdDeviation = locationExtended.eastStdDeviation; +    } +    if (GPS_LOCATION_EXTENDED_HAS_NORTH_VEL & locationExtended.flags) { +        out.flags |= GNSS_LOCATION_INFO_NORTH_VEL_BIT; +        out.northVelocity = locationExtended.northVelocity; +    } +    if (GPS_LOCATION_EXTENDED_HAS_NORTH_VEL_UNC & locationExtended.flags) { +        out.flags |= GNSS_LOCATION_INFO_NORTH_VEL_UNC_BIT; +        out.northVelocityStdDeviation = locationExtended.northVelocityStdDeviation; +    } +    if (GPS_LOCATION_EXTENDED_HAS_EAST_VEL & locationExtended.flags) { +        out.flags |= GNSS_LOCATION_INFO_EAST_VEL_BIT; +        out.eastVelocity = locationExtended.eastVelocity; +    } +    if (GPS_LOCATION_EXTENDED_HAS_EAST_VEL_UNC & locationExtended.flags) { +        out.flags |= GNSS_LOCATION_INFO_EAST_VEL_UNC_BIT; +        out.eastVelocityStdDeviation = locationExtended.eastVelocityStdDeviation; +    } +    if (GPS_LOCATION_EXTENDED_HAS_UP_VEL & locationExtended.flags) { +        out.flags |= GNSS_LOCATION_INFO_UP_VEL_BIT; +        out.upVelocity = locationExtended.upVelocity; +    } +    if (GPS_LOCATION_EXTENDED_HAS_UP_VEL_UNC & locationExtended.flags) { +        out.flags |= GNSS_LOCATION_INFO_UP_VEL_UNC_BIT; +        out.upVelocityStdDeviation = locationExtended.upVelocityStdDeviation; +    } +    if (GPS_LOCATION_EXTENDED_HAS_GNSS_SV_USED_DATA & locationExtended.flags) { +        out.flags |= GNSS_LOCATION_INFO_GNSS_SV_USED_DATA_BIT; +        out.svUsedInPosition.gpsSvUsedIdsMask = +                locationExtended.gnss_sv_used_ids.gps_sv_used_ids_mask; +        out.svUsedInPosition.gloSvUsedIdsMask = +                locationExtended.gnss_sv_used_ids.glo_sv_used_ids_mask; +        out.svUsedInPosition.galSvUsedIdsMask = +                locationExtended.gnss_sv_used_ids.gal_sv_used_ids_mask; +        out.svUsedInPosition.bdsSvUsedIdsMask = +                locationExtended.gnss_sv_used_ids.bds_sv_used_ids_mask; +        out.svUsedInPosition.qzssSvUsedIdsMask = +                locationExtended.gnss_sv_used_ids.qzss_sv_used_ids_mask; +        out.svUsedInPosition.navicSvUsedIdsMask = +                locationExtended.gnss_sv_used_ids.navic_sv_used_ids_mask; + +        out.flags |= GNSS_LOCATION_INFO_NUM_SV_USED_IN_POSITION_BIT; +        out.numSvUsedInPosition = getNumSvUsed(out.svUsedInPosition.gpsSvUsedIdsMask, +                                               GPS_SV_PRN_MAX - GPS_SV_PRN_MIN + 1); +        out.numSvUsedInPosition += getNumSvUsed(out.svUsedInPosition.gloSvUsedIdsMask, +                                                GLO_SV_PRN_MAX - GLO_SV_PRN_MIN + 1); +        out.numSvUsedInPosition += getNumSvUsed(out.svUsedInPosition.qzssSvUsedIdsMask, +                                                QZSS_SV_PRN_MAX - QZSS_SV_PRN_MIN + 1); +        out.numSvUsedInPosition += getNumSvUsed(out.svUsedInPosition.bdsSvUsedIdsMask, +                                                BDS_SV_PRN_MAX - BDS_SV_PRN_MIN + 1); +        out.numSvUsedInPosition += getNumSvUsed(out.svUsedInPosition.galSvUsedIdsMask, +                                                GAL_SV_PRN_MAX - GAL_SV_PRN_MIN + 1); +        out.numSvUsedInPosition += getNumSvUsed(out.svUsedInPosition.navicSvUsedIdsMask, +                                                NAVIC_SV_PRN_MAX - NAVIC_SV_PRN_MIN + 1); + +        out.numOfMeasReceived = locationExtended.numOfMeasReceived; +        for (int idx =0; idx < locationExtended.numOfMeasReceived; idx++) { +            out.measUsageInfo[idx].gnssSignalType = +                    locationExtended.measUsageInfo[idx].gnssSignalType; +            out.measUsageInfo[idx].gnssSvId = +                    locationExtended.measUsageInfo[idx].gnssSvId; +            out.measUsageInfo[idx].gnssConstellation = +                    locationExtended.measUsageInfo[idx].gnssConstellation; +        } +    } +    if (GPS_LOCATION_EXTENDED_HAS_NAV_SOLUTION_MASK & locationExtended.flags) { +        out.flags |= GNSS_LOCATION_INFO_NAV_SOLUTION_MASK_BIT; +        out.navSolutionMask = locationExtended.navSolutionMask; +    } +    if (GPS_LOCATION_EXTENDED_HAS_POS_DYNAMICS_DATA & locationExtended.flags) { +        out.flags |= GPS_LOCATION_EXTENDED_HAS_POS_DYNAMICS_DATA; +        if (locationExtended.bodyFrameData.bodyFrameDataMask & +                LOCATION_NAV_DATA_HAS_LONG_ACCEL_BIT) { +            out.bodyFrameData.bodyFrameDataMask |= LOCATION_NAV_DATA_HAS_LONG_ACCEL_BIT; +        } +        if (locationExtended.bodyFrameData.bodyFrameDataMask & +                LOCATION_NAV_DATA_HAS_LAT_ACCEL_BIT) { +            out.bodyFrameData.bodyFrameDataMask |= LOCATION_NAV_DATA_HAS_LAT_ACCEL_BIT; +        } +        if (locationExtended.bodyFrameData.bodyFrameDataMask & +                LOCATION_NAV_DATA_HAS_VERT_ACCEL_BIT) { +            out.bodyFrameData.bodyFrameDataMask |= LOCATION_NAV_DATA_HAS_VERT_ACCEL_BIT; +        } +        if (locationExtended.bodyFrameData.bodyFrameDataMask & +                LOCATION_NAV_DATA_HAS_YAW_RATE_BIT) { +            out.bodyFrameData.bodyFrameDataMask |= LOCATION_NAV_DATA_HAS_YAW_RATE_BIT; +        } +        if (locationExtended.bodyFrameData.bodyFrameDataMask & +            LOCATION_NAV_DATA_HAS_PITCH_BIT) { +            out.bodyFrameData.bodyFrameDataMask |= LOCATION_NAV_DATA_HAS_PITCH_BIT; +        } + +        if (locationExtended.bodyFrameData.bodyFrameDataMask & +                LOCATION_NAV_DATA_HAS_LONG_ACCEL_UNC_BIT) { +            out.bodyFrameData.bodyFrameDataMask |= LOCATION_NAV_DATA_HAS_LONG_ACCEL_UNC_BIT; +        } +        if (locationExtended.bodyFrameData.bodyFrameDataMask & +                LOCATION_NAV_DATA_HAS_LAT_ACCEL_UNC_BIT) { +            out.bodyFrameData.bodyFrameDataMask |= LOCATION_NAV_DATA_HAS_LAT_ACCEL_UNC_BIT; +        } +        if (locationExtended.bodyFrameData.bodyFrameDataMask & +                LOCATION_NAV_DATA_HAS_VERT_ACCEL_UNC_BIT) { +            out.bodyFrameData.bodyFrameDataMask |= LOCATION_NAV_DATA_HAS_VERT_ACCEL_UNC_BIT; +        } +        if (locationExtended.bodyFrameData.bodyFrameDataMask & +                LOCATION_NAV_DATA_HAS_YAW_RATE_UNC_BIT) { +            out.bodyFrameData.bodyFrameDataMask |= LOCATION_NAV_DATA_HAS_YAW_RATE_UNC_BIT; +        } +        if (locationExtended.bodyFrameData.bodyFrameDataMask & +                LOCATION_NAV_DATA_HAS_PITCH_UNC_BIT) { +            out.bodyFrameData.bodyFrameDataMask |= LOCATION_NAV_DATA_HAS_PITCH_UNC_BIT; +        } + +        if (locationExtended.bodyFrameDataExt.bodyFrameDataMask & +                LOCATION_NAV_DATA_HAS_PITCH_RATE_BIT) { +            out.bodyFrameDataExt.bodyFrameDataMask |= LOCATION_NAV_DATA_HAS_PITCH_RATE_BIT; +        } +        if (locationExtended.bodyFrameDataExt.bodyFrameDataMask & +                LOCATION_NAV_DATA_HAS_PITCH_RATE_UNC_BIT) { +            out.bodyFrameDataExt.bodyFrameDataMask |= LOCATION_NAV_DATA_HAS_PITCH_RATE_UNC_BIT; +        } +        if (locationExtended.bodyFrameDataExt.bodyFrameDataMask & +                LOCATION_NAV_DATA_HAS_ROLL_BIT) { +            out.bodyFrameDataExt.bodyFrameDataMask |= LOCATION_NAV_DATA_HAS_ROLL_BIT; +        } +        if (locationExtended.bodyFrameDataExt.bodyFrameDataMask & +                LOCATION_NAV_DATA_HAS_ROLL_UNC_BIT) { +            out.bodyFrameDataExt.bodyFrameDataMask |= LOCATION_NAV_DATA_HAS_ROLL_UNC_BIT; +        } +        if (locationExtended.bodyFrameDataExt.bodyFrameDataMask & +                LOCATION_NAV_DATA_HAS_ROLL_RATE_BIT) { +            out.bodyFrameDataExt.bodyFrameDataMask |= LOCATION_NAV_DATA_HAS_ROLL_RATE_BIT; +        } +        if (locationExtended.bodyFrameDataExt.bodyFrameDataMask & +                LOCATION_NAV_DATA_HAS_ROLL_RATE_UNC_BIT) { +            out.bodyFrameDataExt.bodyFrameDataMask |= LOCATION_NAV_DATA_HAS_ROLL_RATE_UNC_BIT; +        } +        if (locationExtended.bodyFrameDataExt.bodyFrameDataMask & +                LOCATION_NAV_DATA_HAS_YAW_BIT) { +            out.bodyFrameDataExt.bodyFrameDataMask |= LOCATION_NAV_DATA_HAS_YAW_BIT; +        } +        if (locationExtended.bodyFrameDataExt.bodyFrameDataMask & +                LOCATION_NAV_DATA_HAS_YAW_UNC_BIT) { +            out.bodyFrameDataExt.bodyFrameDataMask |= LOCATION_NAV_DATA_HAS_YAW_UNC_BIT; +        } + +        out.bodyFrameData.longAccel = locationExtended.bodyFrameData.longAccel; +        out.bodyFrameData.latAccel = locationExtended.bodyFrameData.latAccel; +        out.bodyFrameData.vertAccel = locationExtended.bodyFrameData.vertAccel; +        out.bodyFrameData.yawRate = locationExtended.bodyFrameData.yawRate; +        out.bodyFrameData.pitch = locationExtended.bodyFrameData.pitch; +        out.bodyFrameData.longAccelUnc = locationExtended.bodyFrameData.longAccelUnc; +        out.bodyFrameData.latAccelUnc  = locationExtended.bodyFrameData.latAccelUnc; +        out.bodyFrameData.vertAccelUnc = locationExtended.bodyFrameData.vertAccelUnc; +        out.bodyFrameData.yawRateUnc   = locationExtended.bodyFrameData.yawRateUnc; +        out.bodyFrameData.pitchUnc     = locationExtended.bodyFrameData.pitchUnc; + +        out.bodyFrameDataExt.pitchRate    = locationExtended.bodyFrameDataExt.pitchRate; +        out.bodyFrameDataExt.pitchRateUnc = locationExtended.bodyFrameDataExt.pitchRateUnc; +        out.bodyFrameDataExt.roll         = locationExtended.bodyFrameDataExt.roll; +        out.bodyFrameDataExt.rollUnc      = locationExtended.bodyFrameDataExt.rollUnc; +        out.bodyFrameDataExt.rollRate     = locationExtended.bodyFrameDataExt.rollRate; +        out.bodyFrameDataExt.rollRateUnc  = locationExtended.bodyFrameDataExt.rollRateUnc; +        out.bodyFrameDataExt.yaw          = locationExtended.bodyFrameDataExt.yaw; +        out.bodyFrameDataExt.yawUnc       = locationExtended.bodyFrameDataExt.yawUnc; +    } + +    // Validity of this structure is established from the timeSrc of the GnssSystemTime structure. +    out.gnssSystemTime = locationExtended.gnssSystemTime; + +    if (GPS_LOCATION_EXTENDED_HAS_LEAP_SECONDS & locationExtended.flags) { +        out.flags |= GNSS_LOCATION_INFO_LEAP_SECONDS_BIT; +        out.leapSeconds = locationExtended.leapSeconds; +    } + +    if (GPS_LOCATION_EXTENDED_HAS_TIME_UNC & locationExtended.flags) { +        out.flags |= GNSS_LOCATION_INFO_TIME_UNC_BIT; +        out.timeUncMs = locationExtended.timeUncMs; +    } + +    if (GPS_LOCATION_EXTENDED_HAS_CALIBRATION_CONFIDENCE & locationExtended.flags) { +        out.flags |= GNSS_LOCATION_INFO_CALIBRATION_CONFIDENCE_BIT; +        out.calibrationConfidence = locationExtended.calibrationConfidence; +    } + +    if (GPS_LOCATION_EXTENDED_HAS_CALIBRATION_STATUS & locationExtended.flags) { +        out.flags |= GNSS_LOCATION_INFO_CALIBRATION_STATUS_BIT; +        out.calibrationStatus = locationExtended.calibrationStatus; +    } + +    if (GPS_LOCATION_EXTENDED_HAS_OUTPUT_ENG_TYPE & locationExtended.flags) { +        out.flags |= GNSS_LOCATION_INFO_OUTPUT_ENG_TYPE_BIT; +        out.locOutputEngType = locationExtended.locOutputEngType; +    } + +    if (GPS_LOCATION_EXTENDED_HAS_OUTPUT_ENG_MASK & locationExtended.flags) { +        out.flags |= GNSS_LOCATION_INFO_OUTPUT_ENG_MASK_BIT; +        out.locOutputEngMask = locationExtended.locOutputEngMask; +    } + +    if (GPS_LOCATION_EXTENDED_HAS_CONFORMITY_INDEX & locationExtended.flags) { +        out.flags |= GNSS_LOCATION_INFO_CONFORMITY_INDEX_BIT; +        out.conformityIndex = locationExtended.conformityIndex; +    } + +    if (GPS_LOCATION_EXTENDED_HAS_LLA_VRP_BASED & locationExtended.flags) { +        out.flags |= GNSS_LOCATION_INFO_LLA_VRP_BASED_BIT; +        out.llaVRPBased = locationExtended.llaVRPBased; +    } + +    if (GPS_LOCATION_EXTENDED_HAS_ENU_VELOCITY_LLA_VRP_BASED & locationExtended.flags) { +        out.flags |= GNSS_LOCATION_INFO_ENU_VELOCITY_VRP_BASED_BIT; +        // copy over east, north and up vrp based velocity +        out.enuVelocityVRPBased[0] = locationExtended.enuVelocityVRPBased[0]; +        out.enuVelocityVRPBased[1] = locationExtended.enuVelocityVRPBased[1]; +        out.enuVelocityVRPBased[2] = locationExtended.enuVelocityVRPBased[2]; +    } + +    if (GPS_LOCATION_EXTENDED_HAS_DR_SOLUTION_STATUS_MASK & locationExtended.flags) { +        out.flags |= GNSS_LOCATION_INFO_DR_SOLUTION_STATUS_MASK_BIT; +        out.drSolutionStatusMask = locationExtended.drSolutionStatusMask; +    } + +    if (GPS_LOCATION_EXTENDED_HAS_ALTITUDE_ASSUMED & locationExtended.flags) { +        out.flags |= GNSS_LOCATION_INFO_ALTITUDE_ASSUMED_BIT; +        out.altitudeAssumed = locationExtended.altitudeAssumed; +    } + +    out.flags |= GNSS_LOCATION_INFO_SESSION_STATUS_BIT; +    out.sessionStatus = status; +} + +inline uint32_t +GnssAdapter::convertSuplVersion(const GnssConfigSuplVersion suplVersion) +{ +    switch (suplVersion) { +        case GNSS_CONFIG_SUPL_VERSION_2_0_4: +            return 0x00020004; +        case GNSS_CONFIG_SUPL_VERSION_2_0_0: +            return 0x00020000; +        case GNSS_CONFIG_SUPL_VERSION_2_0_2: +            return 0x00020002; +        case GNSS_CONFIG_SUPL_VERSION_1_0_0: +        default: +            return 0x00010000; +    } +} + +uint32_t +GnssAdapter::convertLppeCp(const GnssConfigLppeControlPlaneMask lppeControlPlaneMask) +{ +    uint32_t mask = 0; +    if (GNSS_CONFIG_LPPE_CONTROL_PLANE_DBH_BIT & lppeControlPlaneMask) { +        mask |= (1<<0); +    } +    if (GNSS_CONFIG_LPPE_CONTROL_PLANE_WLAN_AP_MEASUREMENTS_BIT & lppeControlPlaneMask) { +        mask |= (1<<1); +    } +    if (GNSS_CONFIG_LPPE_CONTROL_PLANE_SRN_AP_MEASUREMENTS_BIT & lppeControlPlaneMask) { +        mask |= (1<<2); +    } +    if (GNSS_CONFIG_LPPE_CONTROL_PLANE_SENSOR_BARO_MEASUREMENTS_BIT & lppeControlPlaneMask) { +        mask |= (1<<3); +    } +    return mask; +} + +uint32_t +GnssAdapter::convertLppeUp(const GnssConfigLppeUserPlaneMask lppeUserPlaneMask) +{ +    uint32_t mask = 0; +    if (GNSS_CONFIG_LPPE_USER_PLANE_DBH_BIT & lppeUserPlaneMask) { +        mask |= (1<<0); +    } +    if (GNSS_CONFIG_LPPE_USER_PLANE_WLAN_AP_MEASUREMENTS_BIT & lppeUserPlaneMask) { +        mask |= (1<<1); +    } +    if (GNSS_CONFIG_LPPE_USER_PLANE_SRN_AP_MEASUREMENTS_BIT & lppeUserPlaneMask) { +        mask |= (1<<2); +    } +    if (GNSS_CONFIG_LPPE_USER_PLANE_SENSOR_BARO_MEASUREMENTS_BIT & lppeUserPlaneMask) { +        mask |= (1<<3); +    } +    return mask; +} + +uint32_t +GnssAdapter::convertAGloProt(const GnssConfigAGlonassPositionProtocolMask aGloPositionProtocolMask) +{ +    uint32_t mask = 0; +    if (GNSS_CONFIG_RRC_CONTROL_PLANE_BIT & aGloPositionProtocolMask) { +        mask |= (1<<0); +    } +    if (GNSS_CONFIG_RRLP_USER_PLANE_BIT & aGloPositionProtocolMask) { +        mask |= (1<<1); +    } +    if (GNSS_CONFIG_LLP_USER_PLANE_BIT & aGloPositionProtocolMask) { +        mask |= (1<<2); +    } +    if (GNSS_CONFIG_LLP_CONTROL_PLANE_BIT & aGloPositionProtocolMask) { +        mask |= (1<<3); +    } +    return mask; +} + +uint32_t +GnssAdapter::convertEP4ES(const GnssConfigEmergencyPdnForEmergencySupl emergencyPdnForEmergencySupl) +{ +    switch (emergencyPdnForEmergencySupl) { +       case GNSS_CONFIG_EMERGENCY_PDN_FOR_EMERGENCY_SUPL_YES: +           return 1; +       case GNSS_CONFIG_EMERGENCY_PDN_FOR_EMERGENCY_SUPL_NO: +       default: +           return 0; +    } +} + +uint32_t +GnssAdapter::convertSuplEs(const GnssConfigSuplEmergencyServices suplEmergencyServices) +{ +    switch (suplEmergencyServices) { +       case GNSS_CONFIG_SUPL_EMERGENCY_SERVICES_YES: +           return 1; +       case GNSS_CONFIG_SUPL_EMERGENCY_SERVICES_NO: +       default: +           return 0; +    } +} + +uint32_t +GnssAdapter::convertSuplMode(const GnssConfigSuplModeMask suplModeMask) +{ +    uint32_t mask = 0; +    if (GNSS_CONFIG_SUPL_MODE_MSB_BIT & suplModeMask) { +        mask |= (1<<0); +    } +    if (GNSS_CONFIG_SUPL_MODE_MSA_BIT & suplModeMask) { +        mask |= (1<<1); +    } +    return mask; +} + +void +GnssAdapter::readConfigCommand() +{ +    LOC_LOGD("%s]: ", __func__); + +    struct MsgReadConfig : public LocMsg { +        GnssAdapter* mAdapter; +        ContextBase& mContext; +        inline MsgReadConfig(GnssAdapter* adapter, +                             ContextBase& context) : +            LocMsg(), +            mAdapter(adapter), +            mContext(context) {} +        inline virtual void proc() const { +            static bool confReadDone = false; +            if (!confReadDone) { +                confReadDone = true; +                // reads config into mContext->mGps_conf +                mContext.readConfig(); + +                uint32_t allowFlpNetworkFixes = 0; +                static const loc_param_s_type flp_conf_param_table[] = +                { +                    {"ALLOW_NETWORK_FIXES", &allowFlpNetworkFixes, NULL, 'n'}, +                }; +                UTIL_READ_CONF(LOC_PATH_FLP_CONF, flp_conf_param_table); +                LOC_LOGd("allowFlpNetworkFixes %u", allowFlpNetworkFixes); +                mAdapter->setAllowFlpNetworkFixes(allowFlpNetworkFixes); +            } +        } +    }; + +    if (mContext != NULL) { +        sendMsg(new MsgReadConfig(this, *mContext)); +    } +} + +void +GnssAdapter::setSuplHostServer(const char* server, int port, LocServerType type) +{ +    if (ContextBase::mGps_conf.AGPS_CONFIG_INJECT) { +        char serverUrl[MAX_URL_LEN] = {}; +        int32_t length = -1; +        const char noHost[] = "NONE"; + +        if ((NULL == server) || (server[0] == 0) || +                (strncasecmp(noHost, server, sizeof(noHost)) == 0)) { +            serverUrl[0] = '\0'; +            length = 0; +        } else if (port > 0) { +            length = snprintf(serverUrl, sizeof(serverUrl), "%s:%u", server, port); +        } +        if (LOC_AGPS_SUPL_SERVER != type && LOC_AGPS_MO_SUPL_SERVER != type) { +            LOC_LOGe("Invalid type=%d", type); +        } else if (length >= 0) { +            if (LOC_AGPS_SUPL_SERVER == type) { +                getServerUrl().assign(serverUrl); +                strlcpy(ContextBase::mGps_conf.SUPL_HOST, +                        (nullptr == server) ? serverUrl : server, +                        LOC_MAX_PARAM_STRING); +                ContextBase::mGps_conf.SUPL_PORT = port; +            } else { +                if (strncasecmp(getMoServerUrl().c_str(), serverUrl, sizeof(serverUrl)) != 0) { +                    getMoServerUrl().assign(serverUrl); +                } +            } +        } +    } +} + +void +GnssAdapter::setConfig() +{ +    LOC_LOGD("%s]: ", __func__); + +    // set nmea mask type +    uint32_t mask = 0; +    if (NMEA_PROVIDER_MP == ContextBase::mGps_conf.NMEA_PROVIDER) { +        mask |= LOC_NMEA_ALL_GENERAL_SUPPORTED_MASK; +        if (ContextBase::mGps_conf.NMEA_TAG_BLOCK_GROUPING_ENABLED) { +            mask |= LOC_NMEA_MASK_TAGBLOCK_V02; +        } +    } +    if (ContextBase::isFeatureSupported(LOC_SUPPORTED_FEATURE_DEBUG_NMEA_V02)) { +        mask |= LOC_NMEA_MASK_DEBUG_V02; +    } +    if (mNmeaMask != mask) { +        mNmeaMask = mask; +        if (mNmeaMask) { +            for (auto it=mClientData.begin(); it != mClientData.end(); ++it) { +                if ((it->second.gnssNmeaCb != nullptr)) { +                    updateEvtMask(LOC_API_ADAPTER_BIT_NMEA_1HZ_REPORT, +                                  LOC_REGISTRATION_MASK_ENABLED); +                    break; +                } +            } +        } +    } + +    std::string oldMoServerUrl = getMoServerUrl(); +    setSuplHostServer(ContextBase::mGps_conf.SUPL_HOST, +                      ContextBase::mGps_conf.SUPL_PORT, +                      LOC_AGPS_SUPL_SERVER); +    setSuplHostServer(ContextBase::mGps_conf.MO_SUPL_HOST, +                      ContextBase::mGps_conf.MO_SUPL_PORT, +                      LOC_AGPS_MO_SUPL_SERVER); + +    // inject the configurations into modem +    loc_gps_cfg_s gpsConf = ContextBase::mGps_conf; +    loc_sap_cfg_s_type sapConf = ContextBase::mSap_conf; + +    //cache the injected configuration with GnssConfigRequested struct +    GnssConfig gnssConfigRequested = {}; +    gnssConfigRequested.flags |= GNSS_CONFIG_FLAGS_GPS_LOCK_VALID_BIT | +            GNSS_CONFIG_FLAGS_BLACKLISTED_SV_IDS_BIT; +    /* Here we process an SSR. We need to set the GPS_LOCK to the proper values, as follows: +    1. Q behavior. This is identified by mSupportNfwControl being 1. In this case +    ContextBase::mGps_conf.GPS_LOCK is a "state", meaning it should reflect the +    NV value. Therefore we will set the NV to ContextBase::mGps_conf.GPS_LOCK +    2. P behavior. This is identified by mSupportNfwControl being 0. In this case +    ContextBase::mGps_conf.GPS_LOCK is a "configuration", meaning it should hold +    the "mask" for NI. There are two subcases: +    a. Location enabled in GUI (1 == getAfwControlId()). We need to set +    the NV to GNSS_CONFIG_GPS_LOCK_NONE (both MO and NI enabled) +    b. Location disabled in GUI (0 == getAfwControlId()). We need to set +    the NV to ContextBase::mGps_conf.GPS_LOCK (the "mask", which is SIM-card +    specific) +    */ +    if (mSupportNfwControl || (0 == getAfwControlId())) { +        gnssConfigRequested.gpsLock = gpsConf.GPS_LOCK; +    } else { +        gnssConfigRequested.gpsLock = GNSS_CONFIG_GPS_LOCK_NONE; +    } +    gnssConfigRequested.flags |= GNSS_CONFIG_FLAGS_SET_ASSISTANCE_DATA_VALID_BIT | +            GNSS_CONFIG_FLAGS_SUPL_VERSION_VALID_BIT | +            GNSS_CONFIG_FLAGS_AGLONASS_POSITION_PROTOCOL_VALID_BIT | +            GNSS_CONFIG_FLAGS_LPP_PROFILE_VALID_BIT; +    gnssConfigRequested.suplVersion = mLocApi->convertSuplVersion(gpsConf.SUPL_VER); +    gnssConfigRequested.lppProfileMask = gpsConf.LPP_PROFILE; +    gnssConfigRequested.aGlonassPositionProtocolMask = gpsConf.A_GLONASS_POS_PROTOCOL_SELECT; +    if (gpsConf.LPPE_CP_TECHNOLOGY) { +        gnssConfigRequested.flags |= GNSS_CONFIG_FLAGS_LPPE_CONTROL_PLANE_VALID_BIT; +        gnssConfigRequested.lppeControlPlaneMask = +                mLocApi->convertLppeCp(gpsConf.LPPE_CP_TECHNOLOGY); +    } + +    if (gpsConf.LPPE_UP_TECHNOLOGY) { +        gnssConfigRequested.flags |= GNSS_CONFIG_FLAGS_LPPE_USER_PLANE_VALID_BIT; +        gnssConfigRequested.lppeUserPlaneMask = +                mLocApi->convertLppeUp(gpsConf.LPPE_UP_TECHNOLOGY); +    } +    gnssConfigRequested.blacklistedSvIds.assign(mBlacklistedSvIds.begin(), +                                                mBlacklistedSvIds.end()); +    mLocApi->sendMsg(new LocApiMsg( +            [this, gpsConf, sapConf, oldMoServerUrl, gnssConfigRequested] () mutable { +        gnssUpdateConfig(oldMoServerUrl, gnssConfigRequested, gnssConfigRequested); + +        // set nmea mask type +        uint32_t mask = 0; +        if (NMEA_PROVIDER_MP == gpsConf.NMEA_PROVIDER) { +            mask |= LOC_NMEA_ALL_GENERAL_SUPPORTED_MASK; +            if (gpsConf.NMEA_TAG_BLOCK_GROUPING_ENABLED) { +                mask |= LOC_NMEA_MASK_TAGBLOCK_V02; +            } +        } +        if (ContextBase::isFeatureSupported(LOC_SUPPORTED_FEATURE_DEBUG_NMEA_V02)) { +            mask |= LOC_NMEA_MASK_DEBUG_V02; +        } + +        if (mask != 0) { +            mLocApi->setNMEATypesSync(mask); +        } + +        // load tunc configuration from config file on first boot-up, +        // e.g.: adapter.mLocConfigInfo.tuncConfigInfo.isValid is false +        if (mLocConfigInfo.tuncConfigInfo.isValid == false) { +            mLocConfigInfo.tuncConfigInfo.isValid = true; +            mLocConfigInfo.tuncConfigInfo.enable = +                    (gpsConf.CONSTRAINED_TIME_UNCERTAINTY_ENABLED == 1); +            mLocConfigInfo.tuncConfigInfo.tuncThresholdMs = +                   (float)gpsConf.CONSTRAINED_TIME_UNCERTAINTY_THRESHOLD; +            mLocConfigInfo.tuncConfigInfo.energyBudget = +                   gpsConf.CONSTRAINED_TIME_UNCERTAINTY_ENERGY_BUDGET; +        } + +        mLocApi->setConstrainedTuncMode( +                mLocConfigInfo.tuncConfigInfo.enable, +                mLocConfigInfo.tuncConfigInfo.tuncThresholdMs, +                mLocConfigInfo.tuncConfigInfo.energyBudget); + +        // load pace configuration from config file on first boot-up, +        // e.g.: adapter.mLocConfigInfo.paceConfigInfo.isValid is false +        if (mLocConfigInfo.paceConfigInfo.isValid == false) { +            mLocConfigInfo.paceConfigInfo.isValid = true; +            mLocConfigInfo.paceConfigInfo.enable = +                    (gpsConf.POSITION_ASSISTED_CLOCK_ESTIMATOR_ENABLED==1); +        } +        mLocApi->setPositionAssistedClockEstimatorMode( +                mLocConfigInfo.paceConfigInfo.enable); + +        // we do not support control robust location from gps.conf +        if (mLocConfigInfo.robustLocationConfigInfo.isValid == true) { +            mLocApi->configRobustLocation( +                    mLocConfigInfo.robustLocationConfigInfo.enable, +                    mLocConfigInfo.robustLocationConfigInfo.enableFor911); +        } + +        if (sapConf.GYRO_BIAS_RANDOM_WALK_VALID || +            sapConf.ACCEL_RANDOM_WALK_SPECTRAL_DENSITY_VALID || +            sapConf.ANGLE_RANDOM_WALK_SPECTRAL_DENSITY_VALID || +            sapConf.RATE_RANDOM_WALK_SPECTRAL_DENSITY_VALID || +            sapConf.VELOCITY_RANDOM_WALK_SPECTRAL_DENSITY_VALID ) { +            mLocApi->setSensorPropertiesSync( +                sapConf.GYRO_BIAS_RANDOM_WALK_VALID, +                sapConf.GYRO_BIAS_RANDOM_WALK, +                sapConf.ACCEL_RANDOM_WALK_SPECTRAL_DENSITY_VALID, +                sapConf.ACCEL_RANDOM_WALK_SPECTRAL_DENSITY, +                sapConf.ANGLE_RANDOM_WALK_SPECTRAL_DENSITY_VALID, +                sapConf.ANGLE_RANDOM_WALK_SPECTRAL_DENSITY, +                sapConf.RATE_RANDOM_WALK_SPECTRAL_DENSITY_VALID, +                sapConf.RATE_RANDOM_WALK_SPECTRAL_DENSITY, +                sapConf.VELOCITY_RANDOM_WALK_SPECTRAL_DENSITY_VALID, +                sapConf.VELOCITY_RANDOM_WALK_SPECTRAL_DENSITY); +        } +        mLocApi->setSensorPerfControlConfigSync( +                sapConf.SENSOR_CONTROL_MODE, +                sapConf.SENSOR_ACCEL_SAMPLES_PER_BATCH, +                sapConf.SENSOR_ACCEL_BATCHES_PER_SEC, +                sapConf.SENSOR_GYRO_SAMPLES_PER_BATCH, +                sapConf.SENSOR_GYRO_BATCHES_PER_SEC, +                sapConf.SENSOR_ACCEL_SAMPLES_PER_BATCH_HIGH, +                sapConf.SENSOR_ACCEL_BATCHES_PER_SEC_HIGH, +                sapConf.SENSOR_GYRO_SAMPLES_PER_BATCH_HIGH, +                sapConf.SENSOR_GYRO_BATCHES_PER_SEC_HIGH, +                sapConf.SENSOR_ALGORITHM_CONFIG_MASK); +    } )); +    // deal with Measurement Corrections +    if (true == mIsMeasCorrInterfaceOpen) { +        initMeasCorr(true); +    } +} + +std::vector<LocationError> GnssAdapter::gnssUpdateConfig(const std::string& oldMoServerUrl, +        GnssConfig& gnssConfigRequested, GnssConfig& gnssConfigNeedEngineUpdate, size_t count) { +    loc_gps_cfg_s gpsConf = ContextBase::mGps_conf; +    size_t index = 0; +    LocationError err = LOCATION_ERROR_SUCCESS; +    std::vector<LocationError> errsList = {err}; +    if (count > 0) { +        errsList.insert(errsList.begin(), count, LOCATION_ERROR_SUCCESS); +    } + +    std::string serverUrl = getServerUrl(); +    std::string moServerUrl = getMoServerUrl(); + +    int serverUrlLen = serverUrl.length(); +    int moServerUrlLen = moServerUrl.length(); + +    if (!ContextBase::mGps_conf.AGPS_CONFIG_INJECT) { +        LOC_LOGd("AGPS_CONFIG_INJECT is 0. Not setting flags for AGPS configurations"); +        gnssConfigRequested.flags &= ~(GNSS_CONFIG_FLAGS_SET_ASSISTANCE_DATA_VALID_BIT | +                GNSS_CONFIG_FLAGS_SUPL_VERSION_VALID_BIT | +                GNSS_CONFIG_FLAGS_AGLONASS_POSITION_PROTOCOL_VALID_BIT | +                GNSS_CONFIG_FLAGS_LPP_PROFILE_VALID_BIT); +    } + +    if (gnssConfigRequested.flags & GNSS_CONFIG_FLAGS_GPS_LOCK_VALID_BIT) { +        if (gnssConfigNeedEngineUpdate.flags & GNSS_CONFIG_FLAGS_GPS_LOCK_VALID_BIT) { +            err = mLocApi->setGpsLockSync(gnssConfigRequested.gpsLock); +            if (index < count) { +                errsList[index] = err; +            } +        } +        index++; +    } + +    if (gnssConfigRequested.flags & +            GNSS_CONFIG_FLAGS_SET_ASSISTANCE_DATA_VALID_BIT) { +        if (gnssConfigNeedEngineUpdate.flags & +                GNSS_CONFIG_FLAGS_SET_ASSISTANCE_DATA_VALID_BIT) { +            if (gnssConfigNeedEngineUpdate.assistanceServer.type == +                    GNSS_ASSISTANCE_TYPE_SUPL) { +                err = mLocApi->setServerSync( +                        serverUrl.c_str(), serverUrlLen, LOC_AGPS_SUPL_SERVER); +                if (index < count) { +                    errsList[index] = err; +                } +                if (0 != oldMoServerUrl.compare(moServerUrl)) { +                    LocationError locErr = +                        mLocApi->setServerSync(moServerUrl.c_str(), +                                moServerUrlLen, +                                LOC_AGPS_MO_SUPL_SERVER); +                    if (locErr != LOCATION_ERROR_SUCCESS) { +                        LOC_LOGe("Error while setting MO SUPL_HOST server:%s", +                                moServerUrl.c_str()); +                    } +                } +            } else if (gnssConfigNeedEngineUpdate.assistanceServer.type == +                    GNSS_ASSISTANCE_TYPE_C2K) { +                struct in_addr addr; +                struct hostent* hp; +                bool resolveAddrSuccess = true; + +                hp = gethostbyname( +                        gnssConfigNeedEngineUpdate.assistanceServer.hostName); +                if (hp != NULL) { /* DNS OK */ +                    memcpy(&addr, hp->h_addr_list[0], hp->h_length); +                } else { +                    /* Try IP representation */ +                    if (inet_aton( +                                gnssConfigNeedEngineUpdate.assistanceServer.hostName, +                                &addr) == 0) { +                        /* IP not valid */ +                        LOC_LOGE("%s]: hostname '%s' cannot be resolved ", +                                __func__, +                                gnssConfigNeedEngineUpdate.assistanceServer.hostName); +                        if (index < count) { +                            errsList[index] = LOCATION_ERROR_INVALID_PARAMETER; +                        } +                    } else { +                        resolveAddrSuccess = false; +                    } +                } + +                if (resolveAddrSuccess) { +                    unsigned int ip = htonl(addr.s_addr); +                    err = mLocApi->setServerSync(ip, +                            gnssConfigNeedEngineUpdate.assistanceServer.port, +                            LOC_AGPS_CDMA_PDE_SERVER); +                    if (index < count) { +                        errsList[index] = err; +                    } +                } +            } +        } +        index++; +    } + +    if (gnssConfigRequested.flags & GNSS_CONFIG_FLAGS_SUPL_VERSION_VALID_BIT) { +        if (gnssConfigNeedEngineUpdate.flags & +                GNSS_CONFIG_FLAGS_SUPL_VERSION_VALID_BIT) { +            err = mLocApi->setSUPLVersionSync(gnssConfigRequested.suplVersion); +            if (index < count) { +                errsList[index] = err; +            } +        } +        index++; +    } + +    if (gnssConfigRequested.flags & GNSS_CONFIG_FLAGS_LPP_PROFILE_VALID_BIT) { +        if (gnssConfigNeedEngineUpdate.flags & +                GNSS_CONFIG_FLAGS_LPP_PROFILE_VALID_BIT) { +            err = mLocApi->setLPPConfigSync(gnssConfigRequested.lppProfileMask); +            if (index < count) { +                errsList[index] = err; +            } +        } +        index++; +    } + +    if (gnssConfigRequested.flags & GNSS_CONFIG_FLAGS_LPPE_CONTROL_PLANE_VALID_BIT) { +        if (gnssConfigNeedEngineUpdate.flags & +                GNSS_CONFIG_FLAGS_LPPE_CONTROL_PLANE_VALID_BIT) { +            err = mLocApi->setLPPeProtocolCpSync( +                    gnssConfigRequested.lppeControlPlaneMask); +            if (index < count) { +                errsList[index] = err; +            } +        } +        index++; +    } + +    if (gnssConfigRequested.flags & GNSS_CONFIG_FLAGS_LPPE_USER_PLANE_VALID_BIT) { +        if (gnssConfigNeedEngineUpdate.flags & +                GNSS_CONFIG_FLAGS_LPPE_USER_PLANE_VALID_BIT) { +            err = mLocApi->setLPPeProtocolUpSync( +                    gnssConfigRequested.lppeUserPlaneMask); +            if (index < count) { +                errsList[index] = err; +            } +        } +        index++; +    } + +    if (gnssConfigRequested.flags & +            GNSS_CONFIG_FLAGS_AGLONASS_POSITION_PROTOCOL_VALID_BIT) { +        if (gnssConfigNeedEngineUpdate.flags & +                GNSS_CONFIG_FLAGS_AGLONASS_POSITION_PROTOCOL_VALID_BIT) { +            err = mLocApi->setAGLONASSProtocolSync( +                    gnssConfigRequested.aGlonassPositionProtocolMask); +            if (index < count) { +                errsList[index] = err; +            } +        } +        index++; +    } +    if (gnssConfigRequested.flags & GNSS_CONFIG_FLAGS_BLACKLISTED_SV_IDS_BIT) { +        // Check if feature is supported +        if (!ContextBase::isFeatureSupported( +                    LOC_SUPPORTED_FEATURE_CONSTELLATION_ENABLEMENT_V02)) { +            LOC_LOGe("Feature constellation enablement not supported."); +            err = LOCATION_ERROR_NOT_SUPPORTED; +        } else { +            // Send the SV ID Config to Modem +            mBlacklistedSvIds.assign(gnssConfigRequested.blacklistedSvIds.begin(), +                    gnssConfigRequested.blacklistedSvIds.end()); +            err = gnssSvIdConfigUpdateSync(gnssConfigRequested.blacklistedSvIds); +            if (LOCATION_ERROR_SUCCESS != err) { +                LOC_LOGe("Failed to send config to modem, err %d", err); +            } +        } +        if (index < count) { +            errsList[index] = err; +        } +        index++; +    } +    if (gnssConfigRequested.flags & +            GNSS_CONFIG_FLAGS_EMERGENCY_EXTENSION_SECONDS_BIT) { +        if (gnssConfigNeedEngineUpdate.flags & +                GNSS_CONFIG_FLAGS_EMERGENCY_EXTENSION_SECONDS_BIT) { +            err = mLocApi->setEmergencyExtensionWindowSync( +                    gnssConfigRequested.emergencyExtensionSeconds); +            if (index < count) { +                errsList[index] = err; +            } +        } +        index++; +    } + +    if (gnssConfigRequested.flags & GNSS_CONFIG_FLAGS_MIN_SV_ELEVATION_BIT) { +        GnssConfig gnssConfig = {}; +        gnssConfig.flags = GNSS_CONFIG_FLAGS_MIN_SV_ELEVATION_BIT; +        gnssConfig.minSvElevation = gnssConfigRequested.minSvElevation; +        err = mLocApi->setParameterSync(gnssConfig); +        if (index < count) { +            errsList[index] = err; +        } +        index++; +    } + +    return errsList; +} + +uint32_t* +GnssAdapter::gnssUpdateConfigCommand(const GnssConfig& config) +{ +    // count the number of bits set +    GnssConfigFlagsMask flagsCopy = config.flags; +    size_t count = 0; +    while (flagsCopy > 0) { +        if (flagsCopy & 1) { +            count++; +        } +        flagsCopy >>= 1; +    } +    std::string idsString = "["; +    uint32_t* ids = NULL; +    if (count > 0) { +        ids = new uint32_t[count]; +        if (ids == nullptr) { +            LOC_LOGE("%s] new allocation failed, fatal error.", __func__); +            return nullptr; +        } +        for (size_t i=0; i < count; ++i) { +            ids[i] = generateSessionId(); +            IF_LOC_LOGD { +                idsString += std::to_string(ids[i]) + " "; +            } +        } +    } +    idsString += "]"; + +    LOC_LOGD("%s]: ids %s flags 0x%X", __func__, idsString.c_str(), config.flags); + +    struct MsgGnssUpdateConfig : public LocMsg { +        GnssAdapter& mAdapter; +        LocApiBase& mApi; +        GnssConfig mConfig; +        size_t mCount; +        uint32_t* mIds; +        inline MsgGnssUpdateConfig(GnssAdapter& adapter, +                                   LocApiBase& api, +                                   GnssConfig config, +                                   uint32_t* ids, +                                   size_t count) : +            LocMsg(), +            mAdapter(adapter), +            mApi(api), +            mConfig(config), +            mCount(count), +            mIds(nullptr) { +                if (mCount > 0) { +                    mIds = new uint32_t[count]; +                    if (mIds) { +                        for (uint32_t index = 0; index < count; index++) { +                            mIds[index] = ids[index]; +                        } +                    } else { +                        LOC_LOGe("memory allocation for mIds failed"); +                    } +                } +        } + +        inline MsgGnssUpdateConfig(const MsgGnssUpdateConfig& obj) : +                MsgGnssUpdateConfig(obj.mAdapter, obj.mApi, obj.mConfig, +                        obj.mIds, obj.mCount) {} + +        inline virtual ~MsgGnssUpdateConfig() +        { +            if (nullptr != mIds) delete[] mIds; +        } + +        inline virtual void proc() const { +            if (!mAdapter.isEngineCapabilitiesKnown()) { +                mAdapter.mPendingMsgs.push_back(new MsgGnssUpdateConfig(*this)); +                return; +            } +            GnssAdapter& adapter = mAdapter; +            size_t countOfConfigs = mCount; +            GnssConfig gnssConfigRequested = mConfig; +            GnssConfig gnssConfigNeedEngineUpdate = mConfig; + +            std::vector<uint32_t> sessionIds; +            sessionIds.assign(mIds, mIds + mCount); +            std::vector<LocationError> errs(mCount, LOCATION_ERROR_SUCCESS); +            int index = 0; +            bool needSuspendResume = false; + +            if (gnssConfigRequested.flags & GNSS_CONFIG_FLAGS_GPS_LOCK_VALID_BIT) { +                GnssConfigGpsLock newGpsLock = gnssConfigRequested.gpsLock; + +                newGpsLock |= GNSS_CONFIG_GPS_LOCK_MO; +                ContextBase::mGps_conf.GPS_LOCK = newGpsLock; +                /* If we get here it means that the changes in the framework to request for +                   'P' behavior were made, and therefore we need to "behave" as in 'P' +                However, we need to determine if enableCommand function has already been +                called, since it could get called before this function.*/ +                if (0 != mAdapter.getAfwControlId()) { +                    /* enableCommand function has already been called since getAfwControlId +                    returns non zero. Now there are two possible cases: +                    1. This is the first time this function is called +                       (mSupportNfwControl is true). We need to behave as in 'P', but +                       for the first time, meaning MO was enabled, but NI was not, so +                       we need to unlock NI +                    2. This is not the first time this function is called, meaning we +                       are already behaving as in 'P'. No need to update the configuration +                       in this case (return to 'P' code) */ +                    if (mAdapter.mSupportNfwControl) { +                        // case 1 above +                        newGpsLock = GNSS_CONFIG_GPS_LOCK_NONE; +                    } else { +                        // case 2 above +                        gnssConfigNeedEngineUpdate.flags &= ~(GNSS_CONFIG_FLAGS_GPS_LOCK_VALID_BIT); +                    } +                } +                gnssConfigRequested.gpsLock = newGpsLock; +                mAdapter.mSupportNfwControl = false; +                index++; +            } +            if (gnssConfigRequested.flags & GNSS_CONFIG_FLAGS_SUPL_VERSION_VALID_BIT) { +                uint32_t newSuplVersion = +                        mAdapter.convertSuplVersion(gnssConfigRequested.suplVersion); +                ContextBase::mGps_conf.SUPL_VER = newSuplVersion; +                index++; +            } +            if (gnssConfigRequested.flags & GNSS_CONFIG_FLAGS_SET_ASSISTANCE_DATA_VALID_BIT) { +                if (GNSS_ASSISTANCE_TYPE_SUPL == mConfig.assistanceServer.type) { +                    mAdapter.setSuplHostServer(mConfig.assistanceServer.hostName, +                                                     mConfig.assistanceServer.port, +                                                     LOC_AGPS_SUPL_SERVER); +                } else { +                    LOC_LOGE("%s]: Not a valid gnss assistance type %u", +                            __func__, mConfig.assistanceServer.type); +                    errs.at(index) = LOCATION_ERROR_INVALID_PARAMETER; +                    gnssConfigNeedEngineUpdate.flags &= +                            ~(GNSS_CONFIG_FLAGS_SET_ASSISTANCE_DATA_VALID_BIT); +                } +                index++; +            } +            if (gnssConfigRequested.flags & GNSS_CONFIG_FLAGS_LPP_PROFILE_VALID_BIT) { +                uint32_t newLppProfileMask = gnssConfigRequested.lppProfileMask; +                ContextBase::mGps_conf.LPP_PROFILE = newLppProfileMask; +                index++; +            } +            if (gnssConfigRequested.flags & GNSS_CONFIG_FLAGS_LPPE_CONTROL_PLANE_VALID_BIT) { +                uint32_t newLppeControlPlaneMask = +                        mAdapter.convertLppeCp(gnssConfigRequested.lppeControlPlaneMask); +                ContextBase::mGps_conf.LPPE_CP_TECHNOLOGY = newLppeControlPlaneMask; +                index++; +            } +            if (gnssConfigRequested.flags & GNSS_CONFIG_FLAGS_LPPE_USER_PLANE_VALID_BIT) { +                uint32_t newLppeUserPlaneMask = +                        mAdapter.convertLppeUp(gnssConfigRequested.lppeUserPlaneMask); +                ContextBase::mGps_conf.LPPE_UP_TECHNOLOGY = newLppeUserPlaneMask; +                index++; +            } +            if (gnssConfigRequested.flags & +                    GNSS_CONFIG_FLAGS_AGLONASS_POSITION_PROTOCOL_VALID_BIT) { +                uint32_t newAGloProtMask = +                        mAdapter.convertAGloProt(gnssConfigRequested.aGlonassPositionProtocolMask); +                ContextBase::mGps_conf.A_GLONASS_POS_PROTOCOL_SELECT = newAGloProtMask; +                index++; +            } +            if (gnssConfigRequested.flags & GNSS_CONFIG_FLAGS_EM_PDN_FOR_EM_SUPL_VALID_BIT) { +                uint32_t newEP4ES = mAdapter.convertEP4ES( +                        gnssConfigRequested.emergencyPdnForEmergencySupl); +                if (newEP4ES != ContextBase::mGps_conf.USE_EMERGENCY_PDN_FOR_EMERGENCY_SUPL) { +                    ContextBase::mGps_conf.USE_EMERGENCY_PDN_FOR_EMERGENCY_SUPL = newEP4ES; +                } +                index++; +            } +            if (gnssConfigRequested.flags & GNSS_CONFIG_FLAGS_SUPL_EM_SERVICES_BIT) { +                uint32_t newSuplEs = mAdapter.convertSuplEs( +                        gnssConfigRequested.suplEmergencyServices); +                if (newSuplEs != ContextBase::mGps_conf.SUPL_ES) { +                    ContextBase::mGps_conf.SUPL_ES = newSuplEs; +                } +                index++; +            } +            if (gnssConfigRequested.flags & GNSS_CONFIG_FLAGS_SUPL_MODE_BIT) { +                uint32_t newSuplMode = mAdapter.convertSuplMode(gnssConfigRequested.suplModeMask); +                ContextBase::mGps_conf.SUPL_MODE = newSuplMode; +                mAdapter.broadcastCapabilities(mAdapter.getCapabilities()); +                index++; +            } + +            if (gnssConfigRequested.flags & GNSS_CONFIG_FLAGS_MIN_SV_ELEVATION_BIT) { +                needSuspendResume = true; +                index++; +            } + +            if (needSuspendResume == true) { +                mAdapter.suspendSessions(); +            } +            LocApiCollectiveResponse *configCollectiveResponse = new LocApiCollectiveResponse( +                    *adapter.getContext(), +                    [&adapter, sessionIds, countOfConfigs] (std::vector<LocationError> errs) { + +                    std::vector<uint32_t> ids(sessionIds); +                    adapter.reportResponse(countOfConfigs, errs.data(), ids.data()); +            }); + +            mApi.sendMsg(new LocApiMsg( +                    [&adapter, gnssConfigRequested, gnssConfigNeedEngineUpdate, +                    countOfConfigs, configCollectiveResponse, errs] () mutable { +                std::vector<LocationError> errsList = adapter.gnssUpdateConfig("", +                        gnssConfigRequested, gnssConfigNeedEngineUpdate, countOfConfigs); + +                configCollectiveResponse->returnToSender(errsList); +            })); + +            if (needSuspendResume == true) { +                mAdapter.restartSessions(); +            } +        } +    }; + +    if (NULL != ids) { +        sendMsg(new MsgGnssUpdateConfig(*this, *mLocApi, config, ids, count)); +    } else { +        LOC_LOGE("%s]: No GNSS config items to update", __func__); +    } + +    return ids; +} + +void +GnssAdapter::gnssSvIdConfigUpdate(const std::vector<GnssSvIdSource>& blacklistedSvIds) +{ +    // Clear the existing config +    memset(&mGnssSvIdConfig, 0, sizeof(GnssSvIdConfig)); + +    // Convert the sv id lists to masks +    bool convertSuccess = convertToGnssSvIdConfig(blacklistedSvIds, mGnssSvIdConfig); + +    // Now send to Modem if conversion successful +    if (convertSuccess) { +        gnssSvIdConfigUpdate(); +    } else { +        LOC_LOGe("convertToGnssSvIdConfig failed"); +    } +} + +void +GnssAdapter::gnssSvIdConfigUpdate() +{ +    LOC_LOGd("blacklist bds 0x%" PRIx64 ", glo 0x%" PRIx64 +            ", qzss 0x%" PRIx64 ", gal 0x%" PRIx64 ", sbas 0x%" PRIx64 ", navic 0x%" PRIx64, +            mGnssSvIdConfig.bdsBlacklistSvMask, mGnssSvIdConfig.gloBlacklistSvMask, +            mGnssSvIdConfig.qzssBlacklistSvMask, mGnssSvIdConfig.galBlacklistSvMask, +            mGnssSvIdConfig.sbasBlacklistSvMask, mGnssSvIdConfig.navicBlacklistSvMask); +    // Now set required blacklisted SVs +    mLocApi->setBlacklistSv(mGnssSvIdConfig); +} + +LocationError +GnssAdapter::gnssSvIdConfigUpdateSync(const std::vector<GnssSvIdSource>& blacklistedSvIds) +{ +    // Clear the existing config +    memset(&mGnssSvIdConfig, 0, sizeof(GnssSvIdConfig)); + +    // Convert the sv id lists to masks +    convertToGnssSvIdConfig(blacklistedSvIds, mGnssSvIdConfig); + +    // Now send to Modem +    return gnssSvIdConfigUpdateSync(); +} + +LocationError +GnssAdapter::gnssSvIdConfigUpdateSync() +{ +    LOC_LOGd("blacklist bds 0x%" PRIx64 ", glo 0x%" PRIx64 +            ", qzss 0x%" PRIx64 ", gal 0x%" PRIx64 ", sbas 0x%" PRIx64 ", navic 0x%" PRIx64, +            mGnssSvIdConfig.bdsBlacklistSvMask, mGnssSvIdConfig.gloBlacklistSvMask, +            mGnssSvIdConfig.qzssBlacklistSvMask, mGnssSvIdConfig.galBlacklistSvMask, +            mGnssSvIdConfig.sbasBlacklistSvMask, mGnssSvIdConfig.navicBlacklistSvMask); + +    // Now set required blacklisted SVs +    return mLocApi->setBlacklistSvSync(mGnssSvIdConfig); +} + +void +GnssAdapter::gnssSecondaryBandConfigUpdate(LocApiResponse* locApiResponse) +{ +    LOC_LOGd("secondary band config, size %d, enabled constellation 0x%" PRIx64 "," +             "disabled constellation 0x%" PRIx64 "", mGnssSeconaryBandConfig.size, +             mGnssSeconaryBandConfig.enabledSvTypesMask, +             mGnssSeconaryBandConfig.blacklistedSvTypesMask); +    if (mGnssSeconaryBandConfig.size == sizeof(mGnssSeconaryBandConfig)) { +        // Now set required secondary band config +        mLocApi->configConstellationMultiBand(mGnssSeconaryBandConfig, locApiResponse); +    } +} + +uint32_t* +GnssAdapter::gnssGetConfigCommand(GnssConfigFlagsMask configMask) { + +    // count the number of bits set +    GnssConfigFlagsMask flagsCopy = configMask; +    size_t count = 0; +    while (flagsCopy > 0) { +        if (flagsCopy & 1) { +            count++; +        } +        flagsCopy >>= 1; +    } +    std::string idsString = "["; +    uint32_t* ids = NULL; +    if (count > 0) { +        ids = new uint32_t[count]; +        if (nullptr == ids) { +            LOC_LOGe("new allocation failed, fatal error."); +            return nullptr; +        } +        for (size_t i=0; i < count; ++i) { +            ids[i] = generateSessionId(); +            IF_LOC_LOGD { +                idsString += std::to_string(ids[i]) + " "; +            } +        } +    } +    idsString += "]"; + +    LOC_LOGd("ids %s flags 0x%X", idsString.c_str(), configMask); + +    struct MsgGnssGetConfig : public LocMsg { +        GnssAdapter& mAdapter; +        LocApiBase& mApi; +        GnssConfigFlagsMask mConfigMask; +        uint32_t* mIds; +        size_t mCount; +        inline MsgGnssGetConfig(GnssAdapter& adapter, +                                LocApiBase& api, +                                GnssConfigFlagsMask configMask, +                                uint32_t* ids, +                                size_t count) : +            LocMsg(), +            mAdapter(adapter), +            mApi(api), +            mConfigMask(configMask), +            mCount(count), +            mIds(nullptr) { +                if (mCount > 0) { +                    mIds = new uint32_t[count]; +                    if (mIds) { +                        for (uint32_t index = 0; index < count; index++) { +                            mIds[index] = ids[index]; +                        } +                    } else { +                        LOC_LOGe("memory allocation for mIds failed"); +                    } +                } +        } + +        inline MsgGnssGetConfig(const MsgGnssGetConfig& obj) : +                MsgGnssGetConfig(obj.mAdapter, obj.mApi, obj.mConfigMask, +                        obj.mIds, obj.mCount) {} + +        inline virtual ~MsgGnssGetConfig() +        { +            if (nullptr != mIds) delete[] mIds; +        } +        inline virtual void proc() const { +            if (!mAdapter.isEngineCapabilitiesKnown()) { +                mAdapter.mPendingMsgs.push_back(new MsgGnssGetConfig(*this)); +                return; +            } +            LocationError* errs = new LocationError[mCount]; +            LocationError err = LOCATION_ERROR_SUCCESS; +            uint32_t index = 0; + +            if (nullptr == errs) { +                LOC_LOGE("%s] new allocation failed, fatal error.", __func__); +                return; +            } + +            if (mConfigMask & GNSS_CONFIG_FLAGS_GPS_LOCK_VALID_BIT) { +                if (index < mCount) { +                    errs[index++] = LOCATION_ERROR_NOT_SUPPORTED; +                } +            } +            if (mConfigMask & GNSS_CONFIG_FLAGS_SUPL_VERSION_VALID_BIT) { +                if (index < mCount) { +                    errs[index++] = LOCATION_ERROR_NOT_SUPPORTED; +                } +            } +            if (mConfigMask & GNSS_CONFIG_FLAGS_SET_ASSISTANCE_DATA_VALID_BIT) { +                if (index < mCount) { +                    errs[index++] = LOCATION_ERROR_NOT_SUPPORTED; +                } +            } +            if (mConfigMask & GNSS_CONFIG_FLAGS_LPP_PROFILE_VALID_BIT) { +                if (index < mCount) { +                    errs[index++] = LOCATION_ERROR_NOT_SUPPORTED; +                } +            } +            if (mConfigMask & GNSS_CONFIG_FLAGS_LPPE_CONTROL_PLANE_VALID_BIT) { +                if (index < mCount) { +                    errs[index++] = LOCATION_ERROR_NOT_SUPPORTED; +                } +            } +            if (mConfigMask & GNSS_CONFIG_FLAGS_LPPE_USER_PLANE_VALID_BIT) { +                if (index < mCount) { +                    errs[index++] = LOCATION_ERROR_NOT_SUPPORTED; +                } +            } +            if (mConfigMask & GNSS_CONFIG_FLAGS_AGLONASS_POSITION_PROTOCOL_VALID_BIT) { +                if (index < mCount) { +                    errs[index++] = LOCATION_ERROR_NOT_SUPPORTED; +                } +            } +            if (mConfigMask & GNSS_CONFIG_FLAGS_EM_PDN_FOR_EM_SUPL_VALID_BIT) { +                if (index < mCount) { +                    errs[index++] = LOCATION_ERROR_NOT_SUPPORTED; +                } +            } +            if (mConfigMask & GNSS_CONFIG_FLAGS_SUPL_EM_SERVICES_BIT) { +                if (index < mCount) { +                    errs[index++] = LOCATION_ERROR_NOT_SUPPORTED; +                } +            } +            if (mConfigMask & GNSS_CONFIG_FLAGS_SUPL_MODE_BIT) { +                err = LOCATION_ERROR_NOT_SUPPORTED; +                if (index < mCount) { +                    errs[index++] = LOCATION_ERROR_NOT_SUPPORTED; +                } +            } +            if (mConfigMask & GNSS_CONFIG_FLAGS_BLACKLISTED_SV_IDS_BIT) { +                // Check if feature is supported +                if (!ContextBase::isFeatureSupported( +                        LOC_SUPPORTED_FEATURE_CONSTELLATION_ENABLEMENT_V02)) { +                    LOC_LOGe("Feature not supported."); +                    err = LOCATION_ERROR_NOT_SUPPORTED; +                } else { +                    // Send request to Modem to fetch the config +                    mApi.getBlacklistSv(); +                    err = LOCATION_ERROR_SUCCESS; +                } +                if (index < mCount) { +                    errs[index++] = err; +                } +            } +            if (mConfigMask & GNSS_CONFIG_FLAGS_EMERGENCY_EXTENSION_SECONDS_BIT) { +                err = LOCATION_ERROR_NOT_SUPPORTED; +                if (index < mCount) { +                    errs[index++] = LOCATION_ERROR_NOT_SUPPORTED; +                } +            } +            if (mConfigMask & GNSS_CONFIG_FLAGS_ROBUST_LOCATION_BIT) { +                uint32_t sessionId = *(mIds+index); +                LocApiResponse* locApiResponse = +                        new LocApiResponse(*mAdapter.getContext(), +                                           [this, sessionId] (LocationError err) { +                                           mAdapter.reportResponse(err, sessionId);}); +                if (!locApiResponse) { +                    LOC_LOGe("memory alloc failed"); +                    mAdapter.reportResponse(LOCATION_ERROR_GENERAL_FAILURE, sessionId); +                } else { +                   mApi.getRobustLocationConfig(sessionId, locApiResponse); +                } +            } + +            if (mConfigMask & GNSS_CONFIG_FLAGS_MIN_GPS_WEEK_BIT) { +                uint32_t sessionId = *(mIds+index); +                LocApiResponse* locApiResponse = +                        new LocApiResponse(*mAdapter.getContext(), +                                           [this, sessionId] (LocationError err) { +                                           mAdapter.reportResponse(err, sessionId);}); +                if (!locApiResponse) { +                    LOC_LOGe("memory alloc failed"); +                    mAdapter.reportResponse(LOCATION_ERROR_GENERAL_FAILURE, sessionId); +                } else { +                   mApi.getMinGpsWeek(sessionId, locApiResponse); +                } +            } + +            if (mConfigMask & GNSS_CONFIG_FLAGS_MIN_SV_ELEVATION_BIT) { +                uint32_t sessionId = *(mIds+index); +                LocApiResponse* locApiResponse = +                        new LocApiResponse(*mAdapter.getContext(), +                                           [this, sessionId] (LocationError err) { +                                           mAdapter.reportResponse(err, sessionId);}); +                if (!locApiResponse) { +                    LOC_LOGe("memory alloc failed"); +                    mAdapter.reportResponse(LOCATION_ERROR_GENERAL_FAILURE, sessionId); +                } else { +                    mApi.getParameter(sessionId, GNSS_CONFIG_FLAGS_MIN_SV_ELEVATION_BIT, +                                      locApiResponse); +                } +            } + +            mAdapter.reportResponse(index, errs, mIds); +            delete[] errs; + +        } +    }; + +    if (NULL != ids) { +        sendMsg(new MsgGnssGetConfig(*this, *mLocApi, configMask, ids, count)); +    } else { +        LOC_LOGe("No GNSS config items to Get"); +    } + +    return ids; +} + +bool +GnssAdapter::convertToGnssSvIdConfig( +        const std::vector<GnssSvIdSource>& blacklistedSvIds, GnssSvIdConfig& config) +{ +    bool retVal = false; +    config.size = sizeof(GnssSvIdConfig); + +    // Empty vector => Clear any previous blacklisted SVs +    if (0 == blacklistedSvIds.size()) { +        config.gloBlacklistSvMask = 0; +        config.bdsBlacklistSvMask = 0; +        config.qzssBlacklistSvMask = 0; +        config.galBlacklistSvMask = 0; +        config.sbasBlacklistSvMask = 0; +        config.navicBlacklistSvMask = 0; +        retVal = true; +    } else { +        // Parse the vector and convert SV IDs to mask values +        for (GnssSvIdSource source : blacklistedSvIds) { +            uint64_t* svMaskPtr = NULL; +            GnssSvId initialSvId = 0; +            uint16_t svIndexOffset = 0; +            switch(source.constellation) { +            case GNSS_SV_TYPE_GLONASS: +                svMaskPtr = &config.gloBlacklistSvMask; +                initialSvId = GNSS_SV_CONFIG_GLO_INITIAL_SV_ID; +                break; +            case GNSS_SV_TYPE_BEIDOU: +                svMaskPtr = &config.bdsBlacklistSvMask; +                initialSvId = GNSS_SV_CONFIG_BDS_INITIAL_SV_ID; +                break; +            case GNSS_SV_TYPE_QZSS: +                svMaskPtr = &config.qzssBlacklistSvMask; +                initialSvId = GNSS_SV_CONFIG_QZSS_INITIAL_SV_ID; +                break; +            case GNSS_SV_TYPE_GALILEO: +                svMaskPtr = &config.galBlacklistSvMask; +                initialSvId = GNSS_SV_CONFIG_GAL_INITIAL_SV_ID; +                break; +            case GNSS_SV_TYPE_SBAS: +                // SBAS does not support enable/disable whole constellation +                // so do not set up svTypeMask for SBAS +                svMaskPtr = &config.sbasBlacklistSvMask; +                // SBAS currently has two ranges, [120, 158] and [183, 191] +                if (0 == source.svId) { +                    LOC_LOGd("blacklist all SBAS SV"); +                } else if (source.svId >= GNSS_SV_CONFIG_SBAS_INITIAL2_SV_ID) { +                    // handle SV id in range [183, 191] +                    initialSvId = GNSS_SV_CONFIG_SBAS_INITIAL2_SV_ID; +                    svIndexOffset = GNSS_SV_CONFIG_SBAS_INITIAL_SV_LENGTH; +                } else if ((source.svId >= GNSS_SV_CONFIG_SBAS_INITIAL_SV_ID) && +                           (source.svId < (GNSS_SV_CONFIG_SBAS_INITIAL_SV_ID + +                                           GNSS_SV_CONFIG_SBAS_INITIAL_SV_LENGTH))){ +                        // handle SV id in range of [120, 158] +                        initialSvId = GNSS_SV_CONFIG_SBAS_INITIAL_SV_ID; +                    } else { +                        LOC_LOGe("invalid SBAS sv id %d", source.svId); +                        svMaskPtr = nullptr; +                    } +                    break; +            case GNSS_SV_TYPE_NAVIC: +                 svMaskPtr = &config.navicBlacklistSvMask; +                 initialSvId = GNSS_SV_CONFIG_NAVIC_INITIAL_SV_ID; +                break; +            default: +                break; +            } + +            if (NULL == svMaskPtr) { +                LOC_LOGe("Invalid constellation %d", source.constellation); +            } else { +                // SV ID 0 = All SV IDs +                if (0 == source.svId) { +                    *svMaskPtr = GNSS_SV_CONFIG_ALL_BITS_ENABLED_MASK; +                } else if (source.svId < initialSvId || source.svId >= initialSvId + 64) { +                    LOC_LOGe("Invalid sv id %d for sv type %d", +                            source.svId, source.constellation); +                } else { +                    uint32_t shiftCnt = source.svId + svIndexOffset - initialSvId; +                    *svMaskPtr |= (1ULL << shiftCnt); +                } +            } +        } + +        // Return true if any one source is valid +        if (0 != config.gloBlacklistSvMask || +                0 != config.bdsBlacklistSvMask || +                0 != config.galBlacklistSvMask || +                0 != config.qzssBlacklistSvMask || +                0 != config.sbasBlacklistSvMask || +                0 != config.navicBlacklistSvMask) { +            retVal = true; +        } +    } + +    LOC_LOGd("blacklist bds 0x%" PRIx64 ", glo 0x%" PRIx64 +            ", qzss 0x%" PRIx64 ", gal 0x%" PRIx64 ", sbas 0x%" PRIx64 ", navic 0x%" PRIx64, +             config.bdsBlacklistSvMask, config.gloBlacklistSvMask, +             config.qzssBlacklistSvMask, config.galBlacklistSvMask, +            config.sbasBlacklistSvMask, config.navicBlacklistSvMask); + +    return retVal; +} + +void GnssAdapter::convertFromGnssSvIdConfig( +        const GnssSvIdConfig& svConfig, std::vector<GnssSvIdSource>& blacklistedSvIds) +{ +    // Convert blacklisted SV mask values to vectors +    if (svConfig.bdsBlacklistSvMask) { +        convertGnssSvIdMaskToList( +                svConfig.bdsBlacklistSvMask, blacklistedSvIds, +                GNSS_SV_CONFIG_BDS_INITIAL_SV_ID, GNSS_SV_TYPE_BEIDOU); +    } +    if (svConfig.galBlacklistSvMask) { +        convertGnssSvIdMaskToList( +                svConfig.galBlacklistSvMask, blacklistedSvIds, +                GNSS_SV_CONFIG_GAL_INITIAL_SV_ID, GNSS_SV_TYPE_GALILEO); +    } +    if (svConfig.gloBlacklistSvMask) { +        convertGnssSvIdMaskToList( +                svConfig.gloBlacklistSvMask, blacklistedSvIds, +                GNSS_SV_CONFIG_GLO_INITIAL_SV_ID, GNSS_SV_TYPE_GLONASS); +    } +    if (svConfig.qzssBlacklistSvMask) { +        convertGnssSvIdMaskToList( +                svConfig.qzssBlacklistSvMask, blacklistedSvIds, +                GNSS_SV_CONFIG_QZSS_INITIAL_SV_ID, GNSS_SV_TYPE_QZSS); +    } +    if (svConfig.sbasBlacklistSvMask) { +        // SBAS - SV 120 to 158, maps to 0 to 38 +        //        SV 183 to 191, maps to 39 to 47 +        uint64_t sbasBlacklistSvMask = svConfig.sbasBlacklistSvMask; +        // operate on 120 and 158 first +        sbasBlacklistSvMask <<= (64 - GNSS_SV_CONFIG_SBAS_INITIAL_SV_LENGTH); +        sbasBlacklistSvMask >>= (64 - GNSS_SV_CONFIG_SBAS_INITIAL_SV_LENGTH); +        convertGnssSvIdMaskToList( +                sbasBlacklistSvMask, blacklistedSvIds, +                GNSS_SV_CONFIG_SBAS_INITIAL_SV_ID, GNSS_SV_TYPE_SBAS); +        // operate on the second range +        sbasBlacklistSvMask = svConfig.sbasBlacklistSvMask; +        sbasBlacklistSvMask >>= GNSS_SV_CONFIG_SBAS_INITIAL_SV_LENGTH; +        convertGnssSvIdMaskToList( +                sbasBlacklistSvMask, blacklistedSvIds, +                GNSS_SV_CONFIG_SBAS_INITIAL2_SV_ID, GNSS_SV_TYPE_SBAS); +    } +    if (svConfig.navicBlacklistSvMask) { +        convertGnssSvIdMaskToList( +                svConfig.navicBlacklistSvMask, blacklistedSvIds, +                GNSS_SV_CONFIG_NAVIC_INITIAL_SV_ID, GNSS_SV_TYPE_NAVIC); +    } +} + +void GnssAdapter::convertGnssSvIdMaskToList( +        uint64_t svIdMask, std::vector<GnssSvIdSource>& svIds, +        GnssSvId initialSvId, GnssSvType svType) +{ +    GnssSvIdSource source = {}; +    source.size = sizeof(GnssSvIdSource); +    source.constellation = svType; + +    // SV ID 0 => All SV IDs in mask +    if (GNSS_SV_CONFIG_ALL_BITS_ENABLED_MASK == svIdMask) { +        LOC_LOGd("blacklist all SVs in constellation %d", source.constellation); +        source.svId = 0; +        svIds.push_back(source); +        return; +    } + +    // Convert each bit in svIdMask to vector entry +    uint32_t bitNumber = 0; +    while (svIdMask > 0) { +        if (svIdMask & 0x1) { +            source.svId = bitNumber + initialSvId; +            // SBAS has two ranges: +            // SBAS - SV 120 to 158, maps to 0 to 38 +            //        SV 183 to 191, maps to 39 to 47 +            // #define GNSS_SV_CONFIG_SBAS_INITIAL_SV_ID     120 +            // #define GNSS_SV_CONFIG_SBAS_INITIAL_SV_LENGTH 39 +            // #define GNSS_SV_CONFIG_SBAS_INITIAL2_SV_ID    183 +            if (svType == GNSS_SV_TYPE_SBAS) { +                if (bitNumber >= GNSS_SV_CONFIG_SBAS_INITIAL_SV_LENGTH) { +                    source.svId = bitNumber - GNSS_SV_CONFIG_SBAS_INITIAL_SV_LENGTH + +                                  GNSS_SV_CONFIG_SBAS_INITIAL2_SV_ID; +                } +            } +            svIds.push_back(source); +        } +        bitNumber++; +        svIdMask >>= 1; +    } +} + +void GnssAdapter::reportGnssSvIdConfigEvent(const GnssSvIdConfig& config) +{ +    struct MsgReportGnssSvIdConfig : public LocMsg { +        GnssAdapter& mAdapter; +        const GnssSvIdConfig mConfig; +        inline MsgReportGnssSvIdConfig(GnssAdapter& adapter, +                                 const GnssSvIdConfig& config) : +            LocMsg(), +            mAdapter(adapter), +            mConfig(config) {} +        inline virtual void proc() const { +            mAdapter.reportGnssSvIdConfig(mConfig); +        } +    }; + +    sendMsg(new MsgReportGnssSvIdConfig(*this, config)); +} + +void GnssAdapter::reportGnssSvIdConfig(const GnssSvIdConfig& svIdConfig) +{ +    GnssConfig config = {}; +    config.size = sizeof(GnssConfig); + +    // Invoke control clients config callback +    if (nullptr != mControlCallbacks.gnssConfigCb && +            svIdConfig.size == sizeof(GnssSvIdConfig)) { + +        convertFromGnssSvIdConfig(svIdConfig, config.blacklistedSvIds); +        if (config.blacklistedSvIds.size() > 0) { +            config.flags |= GNSS_CONFIG_FLAGS_BLACKLISTED_SV_IDS_BIT; +        } +        LOC_LOGd("blacklist bds 0x%" PRIx64 ", glo 0x%" PRIx64 ", " +                 "qzss 0x%" PRIx64 ", gal 0x%" PRIx64 ", sbas 0x%" PRIx64 ", navic 0x%" PRIx64, +                 svIdConfig.bdsBlacklistSvMask, svIdConfig.gloBlacklistSvMask, +                 svIdConfig.qzssBlacklistSvMask, svIdConfig.galBlacklistSvMask, +                 svIdConfig.sbasBlacklistSvMask,  svIdConfig.navicBlacklistSvMask); +        // use 0 session id to indicate that receiver does not yet care about session id +        mControlCallbacks.gnssConfigCb(0, config); +    } else { +        LOC_LOGe("Failed to report, size %d", (uint32_t)config.size); +    } +} + +void +GnssAdapter::gnssUpdateSvTypeConfigCommand(GnssSvTypeConfig config) +{ +    struct MsgGnssUpdateSvTypeConfig : public LocMsg { +        GnssAdapter* mAdapter; +        LocApiBase* mApi; +        GnssSvTypeConfig mConfig; +        inline MsgGnssUpdateSvTypeConfig( +                GnssAdapter* adapter, +                LocApiBase* api, +                GnssSvTypeConfig& config) : +            LocMsg(), +            mAdapter(adapter), +            mApi(api), +            mConfig(config) {} +        inline virtual void proc() const { +            if (!mAdapter->isEngineCapabilitiesKnown()) { +                mAdapter->mPendingMsgs.push_back(new MsgGnssUpdateSvTypeConfig(*this)); +                return; +            } +            // Check if feature is supported +            if (!ContextBase::isFeatureSupported( +                    LOC_SUPPORTED_FEATURE_CONSTELLATION_ENABLEMENT_V02)) { +                LOC_LOGe("Feature not supported."); +            } else { +                // Send update request to modem +                mAdapter->gnssSvTypeConfigUpdate(mConfig); +            } +        } +    }; + +    sendMsg(new MsgGnssUpdateSvTypeConfig(this, mLocApi, config)); +} + +void +GnssAdapter::gnssSvTypeConfigUpdate(const GnssSvTypeConfig& config) +{ +    // Gather bits removed from enabled mask +    GnssSvTypesMask enabledRemoved = mGnssSvTypeConfig.enabledSvTypesMask & +            (mGnssSvTypeConfig.enabledSvTypesMask ^ config.enabledSvTypesMask); +    // Send reset if any constellation is removed from the enabled list +    bool sendReset = (enabledRemoved != 0); +    // Save new config and update +    gnssSetSvTypeConfig(config); +    gnssSvTypeConfigUpdate(sendReset); +} + +void +GnssAdapter::gnssSvTypeConfigUpdate(bool sendReset) +{ +    LOC_LOGd("size %" PRIu32" constellations blacklisted 0x%" PRIx64 ", enabled 0x%" PRIx64 +             ", sendReset %d", +             mGnssSvTypeConfig.size, mGnssSvTypeConfig.blacklistedSvTypesMask, +             mGnssSvTypeConfig.enabledSvTypesMask, sendReset); + +    LOC_LOGd("blacklist bds 0x%" PRIx64 ", glo 0x%" PRIx64 +            ", qzss 0x%" PRIx64 ", gal 0x%" PRIx64 ", sbas 0x%" PRIx64 ", Navic 0x%" PRIx64, +            mGnssSvIdConfig.bdsBlacklistSvMask, mGnssSvIdConfig.gloBlacklistSvMask, +            mGnssSvIdConfig.qzssBlacklistSvMask, mGnssSvIdConfig.galBlacklistSvMask, +            mGnssSvIdConfig.sbasBlacklistSvMask, mGnssSvIdConfig.navicBlacklistSvMask); + +    LOC_LOGd("blacklist bds 0x%" PRIx64 ", glo 0x%" PRIx64 +            ", qzss 0x%" PRIx64 ", gal 0x%" PRIx64 ", sbas 0x%" PRIx64 ", Navic 0x%" PRIx64, +            mGnssSvIdConfig.bdsBlacklistSvMask, mGnssSvIdConfig.gloBlacklistSvMask, +            mGnssSvIdConfig.qzssBlacklistSvMask, mGnssSvIdConfig.galBlacklistSvMask, +            mGnssSvIdConfig.sbasBlacklistSvMask, mGnssSvIdConfig.navicBlacklistSvMask); + +    if (mGnssSvTypeConfig.size == sizeof(mGnssSvTypeConfig)) { + +        if (sendReset) { +            mLocApi->resetConstellationControl(); +        } + +        GnssSvIdConfig blacklistConfig = {}; +        // Revert to previously blacklisted SVs for each enabled constellation +        blacklistConfig = mGnssSvIdConfig; +        // Blacklist all SVs for each disabled constellation +        if (mGnssSvTypeConfig.blacklistedSvTypesMask) { +            if (mGnssSvTypeConfig.blacklistedSvTypesMask & GNSS_SV_TYPES_MASK_GLO_BIT) { +                blacklistConfig.gloBlacklistSvMask = GNSS_SV_CONFIG_ALL_BITS_ENABLED_MASK; +            } +            if (mGnssSvTypeConfig.blacklistedSvTypesMask & GNSS_SV_TYPES_MASK_BDS_BIT) { +                blacklistConfig.bdsBlacklistSvMask = GNSS_SV_CONFIG_ALL_BITS_ENABLED_MASK; +            } +            if (mGnssSvTypeConfig.blacklistedSvTypesMask & GNSS_SV_TYPES_MASK_QZSS_BIT) { +                blacklistConfig.qzssBlacklistSvMask = GNSS_SV_CONFIG_ALL_BITS_ENABLED_MASK; +            } +            if (mGnssSvTypeConfig.blacklistedSvTypesMask & GNSS_SV_TYPES_MASK_GAL_BIT) { +                blacklistConfig.galBlacklistSvMask = GNSS_SV_CONFIG_ALL_BITS_ENABLED_MASK; +            } +            if (mGnssSvTypeConfig.blacklistedSvTypesMask & GNSS_SV_TYPES_MASK_NAVIC_BIT) { +                blacklistConfig.navicBlacklistSvMask = GNSS_SV_CONFIG_ALL_BITS_ENABLED_MASK; +            } +        } + +        // Send blacklist info +        mLocApi->setBlacklistSv(blacklistConfig); + +        // Send only enabled constellation config +        if (mGnssSvTypeConfig.enabledSvTypesMask) { +            GnssSvTypeConfig svTypeConfig = {sizeof(GnssSvTypeConfig), 0, 0}; +            svTypeConfig.enabledSvTypesMask = mGnssSvTypeConfig.enabledSvTypesMask; +            mLocApi->setConstellationControl(svTypeConfig); +        } +    } +} + +void +GnssAdapter::gnssGetSvTypeConfigCommand(GnssSvTypeConfigCallback callback) +{ +    struct MsgGnssGetSvTypeConfig : public LocMsg { +        GnssAdapter* mAdapter; +        LocApiBase* mApi; +        GnssSvTypeConfigCallback mCallback; +        inline MsgGnssGetSvTypeConfig( +                GnssAdapter* adapter, +                LocApiBase* api, +                GnssSvTypeConfigCallback callback) : +            LocMsg(), +            mAdapter(adapter), +            mApi(api), +            mCallback(callback) {} +        inline virtual void proc() const { +            if (!mAdapter->isEngineCapabilitiesKnown()) { +                mAdapter->mPendingMsgs.push_back(new MsgGnssGetSvTypeConfig(*this)); +                return; +            } +            if (!ContextBase::isFeatureSupported( +                    LOC_SUPPORTED_FEATURE_CONSTELLATION_ENABLEMENT_V02)) { +                LOC_LOGe("Feature not supported."); +            } else { +                // Save the callback +                mAdapter->gnssSetSvTypeConfigCallback(mCallback); +                // Send GET request to modem +                mApi->getConstellationControl(); +            } +        } +    }; + +    sendMsg(new MsgGnssGetSvTypeConfig(this, mLocApi, callback)); +} + +void +GnssAdapter::gnssResetSvTypeConfigCommand() +{ +    struct MsgGnssResetSvTypeConfig : public LocMsg { +        GnssAdapter* mAdapter; +        LocApiBase* mApi; +        inline MsgGnssResetSvTypeConfig( +                GnssAdapter* adapter, +                LocApiBase* api) : +            LocMsg(), +            mAdapter(adapter), +            mApi(api) {} +        inline virtual void proc() const { +            if (!mAdapter->isEngineCapabilitiesKnown()) { +                mAdapter->mPendingMsgs.push_back(new MsgGnssResetSvTypeConfig(*this)); +                return; +            } +            if (!ContextBase::isFeatureSupported( +                    LOC_SUPPORTED_FEATURE_CONSTELLATION_ENABLEMENT_V02)) { +                LOC_LOGe("Feature not supported."); +            } else { +                // Reset constellation config +                mAdapter->gnssSetSvTypeConfig({sizeof(GnssSvTypeConfig), 0, 0}); +                // Re-enforce SV blacklist config +                mAdapter->gnssSvIdConfigUpdate(); +                // Send reset request to modem +                mApi->resetConstellationControl(); +            } +        } +    }; + +    sendMsg(new MsgGnssResetSvTypeConfig(this, mLocApi)); +} + +void GnssAdapter::reportGnssSvTypeConfigEvent(const GnssSvTypeConfig& config) +{ +    struct MsgReportGnssSvTypeConfig : public LocMsg { +        GnssAdapter& mAdapter; +        const GnssSvTypeConfig mConfig; +        inline MsgReportGnssSvTypeConfig(GnssAdapter& adapter, +                                 const GnssSvTypeConfig& config) : +            LocMsg(), +            mAdapter(adapter), +            mConfig(config) {} +        inline virtual void proc() const { +            mAdapter.reportGnssSvTypeConfig(mConfig); +        } +    }; + +    sendMsg(new MsgReportGnssSvTypeConfig(*this, config)); +} + +void GnssAdapter::reportGnssSvTypeConfig(const GnssSvTypeConfig& config) +{ +    // Invoke Get SV Type Callback +    if (NULL != mGnssSvTypeConfigCb && +            config.size == sizeof(GnssSvTypeConfig)) { +        LOC_LOGd("constellations blacklisted 0x%" PRIx64 ", enabled 0x%" PRIx64, +                 config.blacklistedSvTypesMask, config.enabledSvTypesMask); +        mGnssSvTypeConfigCb(config); +    } else { +        LOC_LOGe("Failed to report, size %d", (uint32_t)config.size); +    } +} + +void GnssAdapter::deleteAidingData(const GnssAidingData &data, uint32_t sessionId) { +    struct timespec bootDeleteAidingDataTime; +    int64_t bootDeleteTimeMs; +    if (clock_gettime(CLOCK_BOOTTIME, &bootDeleteAidingDataTime) == 0) { +        bootDeleteTimeMs = bootDeleteAidingDataTime.tv_sec * 1000000; +        int64_t diffTimeBFirSecDelete = bootDeleteTimeMs - mLastDeleteAidingDataTime; +        if (diffTimeBFirSecDelete > DELETE_AIDING_DATA_EXPECTED_TIME_MS) { +            mLocApi->deleteAidingData(data, new LocApiResponse(*getContext(), +                    [this, sessionId] (LocationError err) { +                        reportResponse(err, sessionId); +                    })); +            mLastDeleteAidingDataTime = bootDeleteTimeMs; +       } +   } +} + +uint32_t +GnssAdapter::gnssDeleteAidingDataCommand(GnssAidingData& data) +{ +    uint32_t sessionId = generateSessionId(); +    LOC_LOGD("%s]: id %u", __func__, sessionId); + +    struct MsgDeleteAidingData : public LocMsg { +        GnssAdapter& mAdapter; +        uint32_t mSessionId; +        GnssAidingData mData; +        inline MsgDeleteAidingData(GnssAdapter& adapter, +                                   uint32_t sessionId, +                                   GnssAidingData& data) : +            LocMsg(), +            mAdapter(adapter), +            mSessionId(sessionId), +            mData(data) {} +        inline virtual void proc() const { +            if ((mData.posEngineMask & STANDARD_POSITIONING_ENGINE) != 0) { +                mAdapter.deleteAidingData(mData, mSessionId); +                SystemStatus* s = mAdapter.getSystemStatus(); +                if ((nullptr != s) && (mData.deleteAll)) { +                    s->setDefaultGnssEngineStates(); +                } +            } + +            bool retVal = mAdapter.mEngHubProxy->gnssDeleteAidingData(mData); +            // When SPE engine is invoked, responseCb will be invoked +            // from QMI Loc API call. +            // When SPE engine is not invoked, we also need to deliver responseCb +            if ((mData.posEngineMask & STANDARD_POSITIONING_ENGINE) == 0) { +                LocationError err = LOCATION_ERROR_NOT_SUPPORTED; +                if (retVal == true) { +                    err = LOCATION_ERROR_SUCCESS; +                } +                mAdapter.reportResponse(err, mSessionId); +            } +        } +    }; + +    sendMsg(new MsgDeleteAidingData(*this, sessionId, data)); +    return sessionId; +} + +void +GnssAdapter::gnssUpdateXtraThrottleCommand(const bool enabled) +{ +    LOC_LOGD("%s] enabled:%d", __func__, enabled); + +    struct UpdateXtraThrottleMsg : public LocMsg { +        GnssAdapter& mAdapter; +        const bool mEnabled; +        inline UpdateXtraThrottleMsg(GnssAdapter& adapter, const bool enabled) : +            LocMsg(), +            mAdapter(adapter), +            mEnabled(enabled) {} +        inline virtual void proc() const { +                mAdapter.mXtraObserver.updateXtraThrottle(mEnabled); +        } +    }; + +    sendMsg(new UpdateXtraThrottleMsg(*this, enabled)); +} + +void +GnssAdapter::injectLocationCommand(double latitude, double longitude, float accuracy) +{ +    LOC_LOGD("%s]: latitude %8.4f longitude %8.4f accuracy %8.4f", +             __func__, latitude, longitude, accuracy); + +    struct MsgInjectLocation : public LocMsg { +        LocApiBase& mApi; +        ContextBase& mContext; +        BlockCPIInfo& mBlockCPI; +        double mLatitude; +        double mLongitude; +        float mAccuracy; +        bool mOnDemandCpi; +        inline MsgInjectLocation(LocApiBase& api, +                                 ContextBase& context, +                                 BlockCPIInfo& blockCPIInfo, +                                 double latitude, +                                 double longitude, +                                 float accuracy, +                                 bool onDemandCpi) : +            LocMsg(), +            mApi(api), +            mContext(context), +            mBlockCPI(blockCPIInfo), +            mLatitude(latitude), +            mLongitude(longitude), +            mAccuracy(accuracy), +            mOnDemandCpi(onDemandCpi) {} +        inline virtual void proc() const { +            if ((uptimeMillis() <= mBlockCPI.blockedTillTsMs) && +                (fabs(mLatitude-mBlockCPI.latitude) <= mBlockCPI.latLonDiffThreshold) && +                (fabs(mLongitude-mBlockCPI.longitude) <= mBlockCPI.latLonDiffThreshold)) { + +                LOC_LOGD("%s]: positon injection blocked: lat: %f, lon: %f, accuracy: %f", +                         __func__, mLatitude, mLongitude, mAccuracy); + +            } else { +                mApi.injectPosition(mLatitude, mLongitude, mAccuracy, mOnDemandCpi); +            } +        } +    }; + +    sendMsg(new MsgInjectLocation(*mLocApi, *mContext, mBlockCPIInfo, +                                  latitude, longitude, accuracy, mOdcpiRequestActive)); +} + +void +GnssAdapter::injectLocationExtCommand(const GnssLocationInfoNotification &locationInfo) +{ +    LOC_LOGd("latitude %8.4f longitude %8.4f accuracy %8.4f, tech mask 0x%x", +             locationInfo.location.latitude, locationInfo.location.longitude, +             locationInfo.location.accuracy, locationInfo.location.techMask); + +    struct MsgInjectLocationExt : public LocMsg { +        LocApiBase& mApi; +        ContextBase& mContext; +        GnssLocationInfoNotification mLocationInfo; +        inline MsgInjectLocationExt(LocApiBase& api, +                                    ContextBase& context, +                                    GnssLocationInfoNotification locationInfo) : +            LocMsg(), +            mApi(api), +            mContext(context), +            mLocationInfo(locationInfo) {} +        inline virtual void proc() const { +            // false to indicate for none-ODCPI +            mApi.injectPosition(mLocationInfo, false); +        } +    }; + +    sendMsg(new MsgInjectLocationExt(*mLocApi, *mContext, locationInfo)); +} + +void +GnssAdapter::injectTimeCommand(int64_t time, int64_t timeReference, int32_t uncertainty) +{ +    LOC_LOGD("%s]: time %lld timeReference %lld uncertainty %d", +             __func__, (long long)time, (long long)timeReference, uncertainty); + +    struct MsgInjectTime : public LocMsg { +        LocApiBase& mApi; +        ContextBase& mContext; +        int64_t mTime; +        int64_t mTimeReference; +        int32_t mUncertainty; +        inline MsgInjectTime(LocApiBase& api, +                             ContextBase& context, +                             int64_t time, +                             int64_t timeReference, +                             int32_t uncertainty) : +            LocMsg(), +            mApi(api), +            mContext(context), +            mTime(time), +            mTimeReference(timeReference), +            mUncertainty(uncertainty) {} +        inline virtual void proc() const { +            mApi.setTime(mTime, mTimeReference, mUncertainty); +        } +    }; + +    sendMsg(new MsgInjectTime(*mLocApi, *mContext, time, timeReference, uncertainty)); +} + +// This command is to called to block the position to be injected to the modem. +// This can happen for network position that comes from modem. +void +GnssAdapter::blockCPICommand(double latitude, double longitude, +                             float accuracy, int blockDurationMsec, +                             double latLonDiffThreshold) +{ +    struct MsgBlockCPI : public LocMsg { +        BlockCPIInfo& mDstCPIInfo; +        BlockCPIInfo mSrcCPIInfo; + +        inline MsgBlockCPI(BlockCPIInfo& dstCPIInfo, +                           BlockCPIInfo& srcCPIInfo) : +            mDstCPIInfo(dstCPIInfo), +            mSrcCPIInfo(srcCPIInfo) {} +        inline virtual void proc() const { +            // in the same hal thread, save the cpi to be blocked +            // the global variable +            mDstCPIInfo = mSrcCPIInfo; +        } +    }; + +    // construct the new block CPI info and queue on the same thread +    // for processing +    BlockCPIInfo blockCPIInfo; +    blockCPIInfo.latitude = latitude; +    blockCPIInfo.longitude = longitude; +    blockCPIInfo.accuracy = accuracy; +    blockCPIInfo.blockedTillTsMs = uptimeMillis() + blockDurationMsec; +    blockCPIInfo.latLonDiffThreshold = latLonDiffThreshold; + +    LOC_LOGD("%s]: block CPI lat: %f, lon: %f ", __func__, latitude, longitude); +    // send a message to record down the coarse position +    // to be blocked from injection in the master copy (mBlockCPIInfo) +    sendMsg(new MsgBlockCPI(mBlockCPIInfo, blockCPIInfo)); +} + +void +GnssAdapter::updateSystemPowerState(PowerStateType systemPowerState) { +    if (POWER_STATE_UNKNOWN != systemPowerState) { +        mSystemPowerState = systemPowerState; +        mLocApi->updateSystemPowerState(mSystemPowerState); +    } +} + +void +GnssAdapter::updateSystemPowerStateCommand(PowerStateType systemPowerState) { +    LOC_LOGd("power event %d", systemPowerState); + +    struct MsgUpdatePowerState : public LocMsg { +        GnssAdapter& mAdapter; +        PowerStateType mSystemPowerState; + +        inline MsgUpdatePowerState(GnssAdapter& adapter, +                                   PowerStateType systemPowerState) : +            LocMsg(), +            mAdapter(adapter), +            mSystemPowerState(systemPowerState) {} +        inline virtual void proc() const { +            mAdapter.updateSystemPowerState(mSystemPowerState); +        } +    }; + +    sendMsg(new MsgUpdatePowerState(*this, systemPowerState)); +} + +void +GnssAdapter::addClientCommand(LocationAPI* client, const LocationCallbacks& callbacks) +{ +    LOC_LOGD("%s]: client %p", __func__, client); + +    struct MsgAddClient : public LocMsg { +        GnssAdapter& mAdapter; +        LocationAPI* mClient; +        const LocationCallbacks mCallbacks; +        inline MsgAddClient(GnssAdapter& adapter, +                            LocationAPI* client, +                            const LocationCallbacks& callbacks) : +            LocMsg(), +            mAdapter(adapter), +            mClient(client), +            mCallbacks(callbacks) {} +        inline virtual void proc() const { +            // check whether we need to notify client of cached location system info +            mAdapter.notifyClientOfCachedLocationSystemInfo(mClient, mCallbacks); +            mAdapter.saveClient(mClient, mCallbacks); +        } +    }; + +    sendMsg(new MsgAddClient(*this, client, callbacks)); +} + +void +GnssAdapter::stopClientSessions(LocationAPI* client) +{ +    LOC_LOGD("%s]: client %p", __func__, client); + +    /* Time-based Tracking */ +    std::vector<LocationSessionKey> vTimeBasedTrackingClient; +    for (auto it : mTimeBasedTrackingSessions) { +        if (client == it.first.client) { +            vTimeBasedTrackingClient.emplace_back(it.first.client, it.first.id); +        } +    } +    for (auto key : vTimeBasedTrackingClient) { +        stopTimeBasedTrackingMultiplex(key.client, key.id); +        eraseTrackingSession(key.client, key.id); +    } + +    /* Distance-based Tracking */ +    for (auto it = mDistanceBasedTrackingSessions.begin(); +              it != mDistanceBasedTrackingSessions.end(); /* no increment here*/) { +        if (client == it->first.client) { +            mLocApi->stopDistanceBasedTracking(it->first.id, new LocApiResponse(*getContext(), +                          [this, client, id=it->first.id] (LocationError err) { +                    if (LOCATION_ERROR_SUCCESS == err) { +                        eraseTrackingSession(client, id); +                    } +                } +            )); +        } +        ++it; // increment only when not erasing an iterator +    } + +} + +void +GnssAdapter::updateClientsEventMask() +{ +    // need to register for leap second info +    // for proper nmea generation +    LOC_API_ADAPTER_EVENT_MASK_T mask = LOC_API_ADAPTER_BIT_LOC_SYSTEM_INFO | +            LOC_API_ADAPTER_BIT_EVENT_REPORT_INFO; +    for (auto it=mClientData.begin(); it != mClientData.end(); ++it) { +        if (it->second.trackingCb != nullptr || +            it->second.gnssLocationInfoCb != nullptr || +            it->second.engineLocationsInfoCb != nullptr) { +            mask |= LOC_API_ADAPTER_BIT_PARSED_POSITION_REPORT; +        } +        if (it->second.gnssSvCb != nullptr) { +            mask |= LOC_API_ADAPTER_BIT_SATELLITE_REPORT; +        } +        if ((it->second.gnssNmeaCb != nullptr) && (mNmeaMask)) { +            mask |= LOC_API_ADAPTER_BIT_NMEA_1HZ_REPORT; +        } +        if (it->second.gnssMeasurementsCb != nullptr) { +            mask |= LOC_API_ADAPTER_BIT_GNSS_MEASUREMENT; +        } +        if (it->second.gnssDataCb != nullptr) { +            mask |= LOC_API_ADAPTER_BIT_PARSED_POSITION_REPORT; +            mask |= LOC_API_ADAPTER_BIT_NMEA_1HZ_REPORT; +            updateNmeaMask(mNmeaMask | LOC_NMEA_MASK_DEBUG_V02); +        } +    } + +    /* +    ** For Automotive use cases we need to enable MEASUREMENT, POLY and EPHEMERIS +    ** when QDR is enabled (e.g.: either enabled via conf file or +    ** engine hub is loaded successfully). +    ** Note: this need to be called from msg queue thread. +    */ +    if((1 == ContextBase::mGps_conf.EXTERNAL_DR_ENABLED) || +       (true == initEngHubProxy())) { +        mask |= LOC_API_ADAPTER_BIT_GNSS_MEASUREMENT; +        mask |= LOC_API_ADAPTER_BIT_GNSS_SV_POLYNOMIAL_REPORT; +        mask |= LOC_API_ADAPTER_BIT_PARSED_UNPROPAGATED_POSITION_REPORT; +        mask |= LOC_API_ADAPTER_BIT_GNSS_SV_EPHEMERIS_REPORT; + +        // Nhz measurement bit is set based on callback from loc eng hub +        // for Nhz engines. +        mask |= checkMask(LOC_API_ADAPTER_BIT_GNSS_NHZ_MEASUREMENT); + +        LOC_LOGd("Auto usecase, Enable MEAS/POLY/EPHEMERIS - mask 0x%" PRIx64 "", +                mask); +    } + +    if (mAgpsManager.isRegistered()) { +        mask |= LOC_API_ADAPTER_BIT_LOCATION_SERVER_REQUEST; +    } +    // Add ODCPI handling +    if (nullptr != mOdcpiRequestCb) { +        mask |= LOC_API_ADAPTER_BIT_REQUEST_WIFI; +    } + +    // need to register for leap second info +    // for proper nmea generation +    mask |= LOC_API_ADAPTER_BIT_LOC_SYSTEM_INFO; + +    // always register for NI NOTIFY VERIFY to handle internally in HAL +    mask |= LOC_API_ADAPTER_BIT_NI_NOTIFY_VERIFY_REQUEST; + +    // Enable the latency report +    if (mask & LOC_API_ADAPTER_BIT_GNSS_MEASUREMENT) { +        if (mLogger.isLogEnabled()) { +            mask |= LOC_API_ADAPTER_BIT_LATENCY_INFORMATION; +        } +    } + +    updateEvtMask(mask, LOC_REGISTRATION_MASK_SET); +} + +void +GnssAdapter::handleEngineUpEvent() +{ +    LOC_LOGD("%s]: ", __func__); + +    struct MsgHandleEngineUpEvent : public LocMsg { +        GnssAdapter& mAdapter; +        inline MsgHandleEngineUpEvent(GnssAdapter& adapter) : +            LocMsg(), +            mAdapter(adapter) {} +        virtual void proc() const { +            mAdapter.setEngineCapabilitiesKnown(true); +            mAdapter.broadcastCapabilities(mAdapter.getCapabilities()); +            // must be called only after capabilities are known +            mAdapter.setConfig(); +            mAdapter.gnssSvIdConfigUpdate(); +            mAdapter.gnssSvTypeConfigUpdate(); +            mAdapter.updateSystemPowerState(mAdapter.getSystemPowerState()); +            mAdapter.gnssSecondaryBandConfigUpdate(); +            // start CDFW service +            mAdapter.initCDFWService(); +            // restart sessions +            mAdapter.restartSessions(true); +            for (auto msg: mAdapter.mPendingMsgs) { +                mAdapter.sendMsg(msg); +            } +            mAdapter.mPendingMsgs.clear(); +        } +    }; + +    readConfigCommand(); +    sendMsg(new MsgHandleEngineUpEvent(*this)); +} + +void +GnssAdapter::restartSessions(bool modemSSR) +{ +    LOC_LOGi(":enter"); + +    if (modemSSR) { +        // odcpi session is no longer active after restart +        mOdcpiRequestActive = false; +    } + +    // SPE will be restarted now, so set this variable to false. +    mSPEAlreadyRunningAtHighestInterval = false; + +    if (false == mTimeBasedTrackingSessions.empty()) { +        // inform engine hub that GNSS session is about to start +        mEngHubProxy->gnssSetFixMode(mLocPositionMode); +        mEngHubProxy->gnssStartFix(); +        checkUpdateDgnssNtrip(false); +    } + +    checkAndRestartSPESession(); +} + +void GnssAdapter::checkAndRestartSPESession() +{ +    LOC_LOGD("%s]: ", __func__); + +    // SPE will be restarted now, so set this variable to false. +    mSPEAlreadyRunningAtHighestInterval = false; + +    checkAndRestartTimeBasedSession(); + +    for (auto it = mDistanceBasedTrackingSessions.begin(); +        it != mDistanceBasedTrackingSessions.end(); ++it) { +        mLocApi->startDistanceBasedTracking(it->first.id, it->second, +                                            new LocApiResponse(*getContext(), +                                            [] (LocationError /*err*/) {})); +    } +} + +// suspend all on-going sessions +void +GnssAdapter::suspendSessions() +{ +    LOC_LOGi(":enter"); + +    if (!mTimeBasedTrackingSessions.empty()) { +        // inform engine hub that GNSS session has stopped +        mEngHubProxy->gnssStopFix(); +        mLocApi->stopFix(nullptr); +        if (isDgnssNmeaRequired()) { +            mDgnssState &= ~DGNSS_STATE_NO_NMEA_PENDING; +        } +        stopDgnssNtrip(); +        mSPEAlreadyRunningAtHighestInterval = false; +    } +} + +void GnssAdapter::checkAndRestartTimeBasedSession() +{ +    LOC_LOGD("%s]: ", __func__); + +    if (!mTimeBasedTrackingSessions.empty()) { +        // get the LocationOptions that has the smallest interval, which should be the active one +        TrackingOptions smallestIntervalOptions; // size is zero until set for the first time +        TrackingOptions highestPowerTrackingOptions; +        memset(&smallestIntervalOptions, 0, sizeof(smallestIntervalOptions)); +        memset(&highestPowerTrackingOptions, 0, sizeof(highestPowerTrackingOptions)); +        for (auto it = mTimeBasedTrackingSessions.begin(); +                it != mTimeBasedTrackingSessions.end(); ++it) { +            // size of zero means we havent set it yet +            if (0 == smallestIntervalOptions.size || +                it->second.minInterval < smallestIntervalOptions.minInterval) { +                 smallestIntervalOptions = it->second; +            } +            GnssPowerMode powerMode = it->second.powerMode; +            // Size of zero means we havent set it yet +            if (0 == highestPowerTrackingOptions.size || +                (GNSS_POWER_MODE_INVALID != powerMode && +                        powerMode < highestPowerTrackingOptions.powerMode)) { +                 highestPowerTrackingOptions = it->second; +            } +        } + +        highestPowerTrackingOptions.setLocationOptions(smallestIntervalOptions); +        // want to run SPE session at a fixed min interval in some automotive scenarios +        if(!checkAndSetSPEToRunforNHz(highestPowerTrackingOptions)) { +            mLocApi->startTimeBasedTracking(highestPowerTrackingOptions, nullptr); +        } +    } +} + +LocationCapabilitiesMask +GnssAdapter::getCapabilities() +{ +    LocationCapabilitiesMask mask = 0; +    uint32_t carrierCapabilities = ContextBase::getCarrierCapabilities(); +    // time based tracking always supported +    mask |= LOCATION_CAPABILITIES_TIME_BASED_TRACKING_BIT; +    // geofence always supported +    mask |= LOCATION_CAPABILITIES_GEOFENCE_BIT; +    if (carrierCapabilities & LOC_GPS_CAPABILITY_MSB) { +        mask |= LOCATION_CAPABILITIES_GNSS_MSB_BIT; +    } +    if (LOC_GPS_CAPABILITY_MSA & carrierCapabilities) { +        mask |= LOCATION_CAPABILITIES_GNSS_MSA_BIT; +    } +    if (ContextBase::isMessageSupported(LOC_API_ADAPTER_MESSAGE_DISTANCE_BASE_LOCATION_BATCHING)) { +        mask |= LOCATION_CAPABILITIES_TIME_BASED_BATCHING_BIT | +                LOCATION_CAPABILITIES_DISTANCE_BASED_BATCHING_BIT; +    } +    if (ContextBase::isMessageSupported(LOC_API_ADAPTER_MESSAGE_DISTANCE_BASE_TRACKING)) { +        mask |= LOCATION_CAPABILITIES_DISTANCE_BASED_TRACKING_BIT; +    } +    if (ContextBase::isMessageSupported(LOC_API_ADAPTER_MESSAGE_OUTDOOR_TRIP_BATCHING)) { +        mask |= LOCATION_CAPABILITIES_OUTDOOR_TRIP_BATCHING_BIT; +    } +    if (ContextBase::gnssConstellationConfig()) { +        mask |= LOCATION_CAPABILITIES_GNSS_MEASUREMENTS_BIT; +    } +    if (ContextBase::isFeatureSupported(LOC_SUPPORTED_FEATURE_DEBUG_NMEA_V02)) { +        mask |= LOCATION_CAPABILITIES_DEBUG_NMEA_BIT; +    } +    if (ContextBase::isFeatureSupported(LOC_SUPPORTED_FEATURE_CONSTELLATION_ENABLEMENT_V02)) { +        mask |= LOCATION_CAPABILITIES_CONSTELLATION_ENABLEMENT_BIT; +    } +    if (ContextBase::isFeatureSupported(LOC_SUPPORTED_FEATURE_AGPM_V02)) { +        mask |= LOCATION_CAPABILITIES_AGPM_BIT; +    } +    //Get QWES feature status mask +    mask |= ContextBase::getQwesFeatureStatus(); +    return mask; +} + +void +GnssAdapter::notifyClientOfCachedLocationSystemInfo( +        LocationAPI* client, const LocationCallbacks& callbacks) { + +    if (mLocSystemInfo.systemInfoMask) { +        // client need to be notified if client has not yet previously registered +        // for the info but now register for it. +        bool notifyClientOfSystemInfo = false; +        // check whether we need to notify client of cached location system info +        // +        // client need to be notified if client has not yet previously registered +        // for the info but now register for it. +        if (callbacks.locationSystemInfoCb) { +            notifyClientOfSystemInfo = true; +            auto it = mClientData.find(client); +            if (it != mClientData.end()) { +                LocationCallbacks oldCallbacks = it->second; +                if (oldCallbacks.locationSystemInfoCb) { +                    notifyClientOfSystemInfo = false; +                } +            } +        } + +        if (notifyClientOfSystemInfo) { +            callbacks.locationSystemInfoCb(mLocSystemInfo); +        } +    } +} + +bool +GnssAdapter::isTimeBasedTrackingSession(LocationAPI* client, uint32_t sessionId) +{ +    LocationSessionKey key(client, sessionId); +    return (mTimeBasedTrackingSessions.find(key) != mTimeBasedTrackingSessions.end()); +} + +bool +GnssAdapter::isDistanceBasedTrackingSession(LocationAPI* client, uint32_t sessionId) +{ +    LocationSessionKey key(client, sessionId); +    return (mDistanceBasedTrackingSessions.find(key) != mDistanceBasedTrackingSessions.end()); +} + +bool +GnssAdapter::hasCallbacksToStartTracking(LocationAPI* client) +{ +    bool allowed = false; +    auto it = mClientData.find(client); +    if (it != mClientData.end()) { +        if (it->second.trackingCb || it->second.gnssLocationInfoCb || +                it->second.engineLocationsInfoCb || it->second.gnssMeasurementsCb || +                it->second.gnssDataCb || it->second.gnssSvCb || it->second.gnssNmeaCb) { +            allowed = true; +        } else { +            LOC_LOGi("missing right callback to start tracking") +        } +    } else { +        LOC_LOGi("client %p not found", client) +    } +    return allowed; +} + +bool +GnssAdapter::isTrackingSession(LocationAPI* client, uint32_t sessionId) +{ +    LocationSessionKey key(client, sessionId); +    return (mTimeBasedTrackingSessions.find(key) != mTimeBasedTrackingSessions.end()); +} + +void +GnssAdapter::reportPowerStateIfChanged() +{ +    bool newPowerOn = !mTimeBasedTrackingSessions.empty() || +                      !mDistanceBasedTrackingSessions.empty(); +    if (newPowerOn != mPowerOn) { +        mPowerOn = newPowerOn; +        if (mPowerStateCb != nullptr) { +            mPowerStateCb(mPowerOn); +        } +    } +} + +void +GnssAdapter::getPowerStateChangesCommand(std::function<void(bool)> powerStateCb) +{ +    LOC_LOGD("%s]: ", __func__); + +    struct MsgReportLocation : public LocMsg { +        GnssAdapter& mAdapter; +        std::function<void(bool)> mPowerStateCb; +        inline MsgReportLocation(GnssAdapter& adapter, +                                 std::function<void(bool)> powerStateCb) : +            LocMsg(), +            mAdapter(adapter), +            mPowerStateCb(powerStateCb) {} +        inline virtual void proc() const { +            mAdapter.savePowerStateCallback(mPowerStateCb); +            mPowerStateCb(mAdapter.getPowerState()); +        } +    }; + +    sendMsg(new MsgReportLocation(*this, powerStateCb)); +} + +void +GnssAdapter::saveTrackingSession(LocationAPI* client, uint32_t sessionId, +                                const TrackingOptions& options) +{ +    LocationSessionKey key(client, sessionId); +    if ((options.minDistance > 0) && +            ContextBase::isMessageSupported(LOC_API_ADAPTER_MESSAGE_DISTANCE_BASE_TRACKING)) { +        mDistanceBasedTrackingSessions[key] = options; +    } else { +        mTimeBasedTrackingSessions[key] = options; +    } +    reportPowerStateIfChanged(); +} + +void +GnssAdapter::eraseTrackingSession(LocationAPI* client, uint32_t sessionId) +{ +    LocationSessionKey key(client, sessionId); +    auto it = mTimeBasedTrackingSessions.find(key); +    if (it != mTimeBasedTrackingSessions.end()) { +        mTimeBasedTrackingSessions.erase(it); +    } else { +        auto itr = mDistanceBasedTrackingSessions.find(key); +        if (itr != mDistanceBasedTrackingSessions.end()) { +            mDistanceBasedTrackingSessions.erase(itr); +        } +    } +    reportPowerStateIfChanged(); +} + +bool GnssAdapter::setLocPositionMode(const LocPosMode& mode) { +    if (!mLocPositionMode.equals(mode)) { +        mLocPositionMode = mode; +        return true; +    } else { +        return false; +    } +} + +void +GnssAdapter::reportResponse(LocationAPI* client, LocationError err, uint32_t sessionId) +{ +    LOC_LOGD("%s]: client %p id %u err %u", __func__, client, sessionId, err); + +    auto it = mClientData.find(client); +    if (it != mClientData.end() && it->second.responseCb != nullptr) { +        it->second.responseCb(err, sessionId); +    } else { +        LOC_LOGW("%s]: client %p id %u not found in data", __func__, client, sessionId); +    } +} + +void +GnssAdapter::reportResponse(LocationError err, uint32_t sessionId) +{ +    LOC_LOGD("%s]: id %u err %u", __func__, sessionId, err); + +    if (mControlCallbacks.size > 0 && mControlCallbacks.responseCb != nullptr) { +        mControlCallbacks.responseCb(err, sessionId); +    } else { +        LOC_LOGW("%s]: control client response callback not found", __func__); +    } +} + +void +GnssAdapter::reportResponse(size_t count, LocationError* errs, uint32_t* ids) +{ +    IF_LOC_LOGD { +        std::string idsString = "["; +        std::string errsString = "["; +        if (NULL != ids && NULL != errs) { +            for (size_t i=0; i < count; ++i) { +                idsString += std::to_string(ids[i]) + " "; +                errsString += std::to_string(errs[i]) + " "; +            } +        } +        idsString += "]"; +        errsString += "]"; + +        LOC_LOGD("%s]: ids %s errs %s", +                 __func__, idsString.c_str(), errsString.c_str()); +    } + +    if (mControlCallbacks.size > 0 && mControlCallbacks.collectiveResponseCb != nullptr) { +        mControlCallbacks.collectiveResponseCb(count, errs, ids); +    } else { +        LOC_LOGW("%s]: control client callback not found", __func__); +    } +} + +uint32_t +GnssAdapter::startTrackingCommand(LocationAPI* client, TrackingOptions& options) +{ +    uint32_t sessionId = generateSessionId(); +    LOC_LOGD("%s]: client %p id %u minInterval %u minDistance %u mode %u powermode %u tbm %u", +             __func__, client, sessionId, options.minInterval, options.minDistance, options.mode, +             options.powerMode, options.tbm); + +    struct MsgStartTracking : public LocMsg { +        GnssAdapter& mAdapter; +        LocApiBase& mApi; +        LocationAPI* mClient; +        uint32_t mSessionId; +        mutable TrackingOptions mOptions; +        inline MsgStartTracking(GnssAdapter& adapter, +                               LocApiBase& api, +                               LocationAPI* client, +                               uint32_t sessionId, +                               TrackingOptions options) : +            LocMsg(), +            mAdapter(adapter), +            mApi(api), +            mClient(client), +            mSessionId(sessionId), +            mOptions(options) {} +        inline virtual void proc() const { +            // distance based tracking will need to know engine capabilities before it can start +            if (!mAdapter.isEngineCapabilitiesKnown() && mOptions.minDistance > 0) { +                mAdapter.mPendingMsgs.push_back(new MsgStartTracking(*this)); +                return; +            } +            LocationError err = LOCATION_ERROR_SUCCESS; +            if (!mAdapter.hasCallbacksToStartTracking(mClient)) { +                err = LOCATION_ERROR_CALLBACK_MISSING; +            } else if (0 == mOptions.size) { +                err = LOCATION_ERROR_INVALID_PARAMETER; +            } else { +                if (mOptions.minInterval < MIN_TRACKING_INTERVAL) { +                    mOptions.minInterval = MIN_TRACKING_INTERVAL; +                } +                if (mOptions.minDistance > 0 && +                        ContextBase::isMessageSupported( +                        LOC_API_ADAPTER_MESSAGE_DISTANCE_BASE_TRACKING)) { +                    mAdapter.saveTrackingSession(mClient, mSessionId, mOptions); +                    mApi.startDistanceBasedTracking(mSessionId, mOptions, +                            new LocApiResponse(*mAdapter.getContext(), +                            [&mAdapter = mAdapter, mSessionId = mSessionId, mClient = mClient] +                            (LocationError err) { +                        if (LOCATION_ERROR_SUCCESS != err) { +                            mAdapter.eraseTrackingSession(mClient, mSessionId); +                        } +                        mAdapter.reportResponse(mClient, err, mSessionId); +                    })); +                } else { +                    if (GNSS_POWER_MODE_M4 == mOptions.powerMode && +                            mOptions.tbm > TRACKING_TBM_THRESHOLD_MILLIS) { +                        LOC_LOGd("TBM (%d) > %d Falling back to M2 power mode", +                                mOptions.tbm, TRACKING_TBM_THRESHOLD_MILLIS); +                        mOptions.powerMode = GNSS_POWER_MODE_M2; +                    } +                    // Api doesn't support multiple clients for time based tracking, so mutiplex +                    bool reportToClientWithNoWait = +                            mAdapter.startTimeBasedTrackingMultiplex(mClient, mSessionId, mOptions); +                    mAdapter.saveTrackingSession(mClient, mSessionId, mOptions); + +                    if (reportToClientWithNoWait) { +                        mAdapter.reportResponse(mClient, LOCATION_ERROR_SUCCESS, mSessionId); +                    } +                } +            } +        } +    }; + +    sendMsg(new MsgStartTracking(*this, *mLocApi, client, sessionId, options)); +    return sessionId; + +} + +bool +GnssAdapter::startTimeBasedTrackingMultiplex(LocationAPI* client, uint32_t sessionId, +                                             const TrackingOptions& options) +{ +    bool reportToClientWithNoWait = true; + +    if (mTimeBasedTrackingSessions.empty()) { +        /*Reset previous NMEA reported time stamp */ +        mPrevNmeaRptTimeNsec = 0; +        startTimeBasedTracking(client, sessionId, options); +        // need to wait for QMI callback +        reportToClientWithNoWait = false; +    } else { +        // find the smallest interval and powerMode +        TrackingOptions multiplexedOptions = {}; // size is 0 until set for the first time +        GnssPowerMode multiplexedPowerMode = GNSS_POWER_MODE_INVALID; +        memset(&multiplexedOptions, 0, sizeof(multiplexedOptions)); +        for (auto it = mTimeBasedTrackingSessions.begin(); it != mTimeBasedTrackingSessions.end(); ++it) { +            // if not set or there is a new smallest interval, then set the new interval +            if (0 == multiplexedOptions.size || +                it->second.minInterval < multiplexedOptions.minInterval) { +                multiplexedOptions = it->second; +            } +            // if session is not the one we are updating and either powerMode +            // is not set or there is a new smallest powerMode, then set the new powerMode +            if (GNSS_POWER_MODE_INVALID == multiplexedPowerMode || +                it->second.powerMode < multiplexedPowerMode) { +                multiplexedPowerMode = it->second.powerMode; +            } +        } +        bool updateOptions = false; +        // if session we are starting has smaller interval then next smallest +        if (options.minInterval < multiplexedOptions.minInterval) { +            multiplexedOptions.minInterval = options.minInterval; +            updateOptions = true; +        } + +        // if session we are starting has smaller powerMode then next smallest +        if (options.powerMode < multiplexedPowerMode) { +            multiplexedOptions.powerMode = options.powerMode; +            updateOptions = true; +        } +        if (updateOptions) { +            // restart time based tracking with the newly updated options + +            startTimeBasedTracking(client, sessionId, multiplexedOptions); +            // need to wait for QMI callback +            reportToClientWithNoWait = false; +        } +        // else part: no QMI call is made, need to report back to client right away +    } + +    return reportToClientWithNoWait; +} + +void +GnssAdapter::startTimeBasedTracking(LocationAPI* client, uint32_t sessionId, +        const TrackingOptions& trackingOptions) +{ +    LOC_LOGd("minInterval %u minDistance %u mode %u powermode %u tbm %u", +            trackingOptions.minInterval, trackingOptions.minDistance, +            trackingOptions.mode, trackingOptions.powerMode, trackingOptions.tbm); +    LocPosMode locPosMode = {}; +    convertOptions(locPosMode, trackingOptions); +    // save position mode parameters +    setLocPositionMode(locPosMode); +    // inform engine hub that GNSS session is about to start +    mEngHubProxy->gnssSetFixMode(mLocPositionMode); +    mEngHubProxy->gnssStartFix(); + +    // want to run SPE session at a fixed min interval in some automotive scenarios +    // use a local copy of TrackingOptions as the TBF may get modified in the +    // checkAndSetSPEToRunforNHz function +    TrackingOptions tempOptions(trackingOptions); +    if (!checkAndSetSPEToRunforNHz(tempOptions)) { +        mLocApi->startTimeBasedTracking(tempOptions, new LocApiResponse(*getContext(), +                          [this, client, sessionId] (LocationError err) { +                if (LOCATION_ERROR_SUCCESS != err) { +                    eraseTrackingSession(client, sessionId); +                } else { +                    checkUpdateDgnssNtrip(false); +                } + +                reportResponse(client, err, sessionId); +            } +        )); +    } else { +        reportResponse(client, LOCATION_ERROR_SUCCESS, sessionId); +    } + +} + +void +GnssAdapter::updateTracking(LocationAPI* client, uint32_t sessionId, +        const TrackingOptions& updatedOptions, const TrackingOptions& oldOptions) +{ +    LocPosMode locPosMode = {}; +    convertOptions(locPosMode, updatedOptions); +    // save position mode parameters +    setLocPositionMode(locPosMode); + +    // inform engine hub that GNSS session is about to start +    mEngHubProxy->gnssSetFixMode(mLocPositionMode); +    mEngHubProxy->gnssStartFix(); + +    // want to run SPE session at a fixed min interval in some automotive scenarios +    // use a local copy of TrackingOptions as the TBF may get modified in the +    // checkAndSetSPEToRunforNHz function +    TrackingOptions tempOptions(updatedOptions); +    if(!checkAndSetSPEToRunforNHz(tempOptions)) { +        mLocApi->startTimeBasedTracking(tempOptions, new LocApiResponse(*getContext(), +                          [this, client, sessionId, oldOptions] (LocationError err) { +                if (LOCATION_ERROR_SUCCESS != err) { +                    // restore the old LocationOptions +                    saveTrackingSession(client, sessionId, oldOptions); +                } +                reportResponse(client, err, sessionId); +            } +        )); +    } else { +        reportResponse(client, LOCATION_ERROR_SUCCESS, sessionId); +    } +} + +void +GnssAdapter::updateTrackingOptionsCommand(LocationAPI* client, uint32_t id, +                                          TrackingOptions& options) +{ +    LOC_LOGD("%s]: client %p id %u minInterval %u mode %u", +             __func__, client, id, options.minInterval, options.mode); + +    struct MsgUpdateTracking : public LocMsg { +        GnssAdapter& mAdapter; +        LocApiBase& mApi; +        LocationAPI* mClient; +        uint32_t mSessionId; +        mutable TrackingOptions mOptions; +        inline MsgUpdateTracking(GnssAdapter& adapter, +                                LocApiBase& api, +                                LocationAPI* client, +                                uint32_t sessionId, +                                TrackingOptions options) : +            LocMsg(), +            mAdapter(adapter), +            mApi(api), +            mClient(client), +            mSessionId(sessionId), +            mOptions(options) {} +        inline virtual void proc() const { +            // distance based tracking will need to know engine capabilities before it can start +            if (!mAdapter.isEngineCapabilitiesKnown() && mOptions.minDistance > 0) { +                mAdapter.mPendingMsgs.push_back(new MsgUpdateTracking(*this)); +                return; +            } +            LocationError err = LOCATION_ERROR_SUCCESS; +            bool isTimeBased = mAdapter.isTimeBasedTrackingSession(mClient, mSessionId); +            bool isDistanceBased = mAdapter.isDistanceBasedTrackingSession(mClient, mSessionId); +            if (!isTimeBased && !isDistanceBased) { +                err = LOCATION_ERROR_ID_UNKNOWN; +            } else if (0 == mOptions.size) { +                err = LOCATION_ERROR_INVALID_PARAMETER; +            } +            if (LOCATION_ERROR_SUCCESS != err) { +                mAdapter.reportResponse(mClient, err, mSessionId); +            } else { +                if (GNSS_POWER_MODE_M4 == mOptions.powerMode && +                        mOptions.tbm > TRACKING_TBM_THRESHOLD_MILLIS) { +                    LOC_LOGd("TBM (%d) > %d Falling back to M2 power mode", +                            mOptions.tbm, TRACKING_TBM_THRESHOLD_MILLIS); +                    mOptions.powerMode = GNSS_POWER_MODE_M2; +                } +                if (mOptions.minInterval < MIN_TRACKING_INTERVAL) { +                    mOptions.minInterval = MIN_TRACKING_INTERVAL; +                } +                // Now update session as required +                if (isTimeBased && mOptions.minDistance > 0) { +                    // switch from time based to distance based +                    // Api doesn't support multiple clients for time based tracking, so mutiplex +                    bool reportToClientWithNoWait = +                        mAdapter.stopTimeBasedTrackingMultiplex(mClient, mSessionId); +                    // erases the time based Session +                    mAdapter.eraseTrackingSession(mClient, mSessionId); +                    if (reportToClientWithNoWait) { +                        mAdapter.reportResponse(mClient, LOCATION_ERROR_SUCCESS, mSessionId); +                    } +                    // saves as distance based Session +                    mAdapter.saveTrackingSession(mClient, mSessionId, mOptions); +                    mApi.startDistanceBasedTracking(mSessionId, mOptions, +                            new LocApiResponse(*mAdapter.getContext(), +                                        [] (LocationError /*err*/) {})); +                } else if (isDistanceBased && mOptions.minDistance == 0) { +                    // switch from distance based to time based +                    mAdapter.eraseTrackingSession(mClient, mSessionId); +                    mApi.stopDistanceBasedTracking(mSessionId, new LocApiResponse( +                            *mAdapter.getContext(), +                            [&mAdapter = mAdapter, mSessionId = mSessionId, mOptions = mOptions, +                            mClient = mClient] (LocationError /*err*/) { +                        // Api doesn't support multiple clients for time based tracking, +                        // so mutiplex +                        bool reportToClientWithNoWait = +                                mAdapter.startTimeBasedTrackingMultiplex(mClient, mSessionId, +                                                                         mOptions); +                        mAdapter.saveTrackingSession(mClient, mSessionId, mOptions); + +                        if (reportToClientWithNoWait) { +                            mAdapter.reportResponse(mClient, LOCATION_ERROR_SUCCESS, mSessionId); +                        } +                    })); +                } else if (isTimeBased) { +                    // update time based tracking +                    // Api doesn't support multiple clients for time based tracking, so mutiplex +                    bool reportToClientWithNoWait = +                            mAdapter.updateTrackingMultiplex(mClient, mSessionId, mOptions); +                    mAdapter.saveTrackingSession(mClient, mSessionId, mOptions); + +                    if (reportToClientWithNoWait) { +                        mAdapter.reportResponse(mClient, err, mSessionId); +                    } +                } else if (isDistanceBased) { +                    // restart distance based tracking +                    mApi.stopDistanceBasedTracking(mSessionId, new LocApiResponse( +                            *mAdapter.getContext(), +                            [&mAdapter = mAdapter, mSessionId = mSessionId, mOptions = mOptions, +                            mClient = mClient, &mApi = mApi] (LocationError err) { +                        if (LOCATION_ERROR_SUCCESS == err) { +                            mApi.startDistanceBasedTracking(mSessionId, mOptions, +                                    new LocApiResponse(*mAdapter.getContext(), +                                    [&mAdapter, mClient, mSessionId, mOptions] +                                    (LocationError err) { +                                if (LOCATION_ERROR_SUCCESS == err) { +                                    mAdapter.saveTrackingSession(mClient, mSessionId, mOptions); +                                } +                                mAdapter.reportResponse(mClient, err, mSessionId); +                            })); +                        } +                    })); +                } +            } +        } +    }; + +    sendMsg(new MsgUpdateTracking(*this, *mLocApi, client, id, options)); +} + +bool +GnssAdapter::updateTrackingMultiplex(LocationAPI* client, uint32_t id, +                                     const TrackingOptions& trackingOptions) +{ +    bool reportToClientWithNoWait = true; + +    LocationSessionKey key(client, id); +    // get the session we are updating +    auto it = mTimeBasedTrackingSessions.find(key); + +    // cache the clients existing LocationOptions +    TrackingOptions oldOptions = it->second; + +    // if session we are updating exists and the minInterval or powerMode has changed +    if (it != mTimeBasedTrackingSessions.end() && +       (it->second.minInterval != trackingOptions.minInterval || +        it->second.powerMode != trackingOptions.powerMode)) { +        // find the smallest interval and powerMode, other than the session we are updating +        TrackingOptions multiplexedOptions = {}; // size is 0 until set for the first time +        GnssPowerMode multiplexedPowerMode = GNSS_POWER_MODE_INVALID; +        memset(&multiplexedOptions, 0, sizeof(multiplexedOptions)); +        for (auto it2 = mTimeBasedTrackingSessions.begin(); +             it2 != mTimeBasedTrackingSessions.end(); ++it2) { +            // if session is not the one we are updating and either interval +            // is not set or there is a new smallest interval, then set the new interval +            if (it2->first != key && (0 == multiplexedOptions.size || +                it2->second.minInterval < multiplexedOptions.minInterval)) { +                 multiplexedOptions = it2->second; +            } +            // if session is not the one we are updating and either powerMode +            // is not set or there is a new smallest powerMode, then set the new powerMode +            if (it2->first != key && (GNSS_POWER_MODE_INVALID == multiplexedPowerMode || +                it2->second.powerMode < multiplexedPowerMode)) { +                multiplexedPowerMode = it2->second.powerMode; +            } +            // else part: no QMI call is made, need to report back to client right away +        } +        bool updateOptions = false; +        // if session we are updating has smaller interval then next smallest +        if (trackingOptions.minInterval < multiplexedOptions.minInterval) { +            multiplexedOptions.minInterval = trackingOptions.minInterval; +            updateOptions = true; +        } +        // if session we are updating has smaller powerMode then next smallest +        if (trackingOptions.powerMode < multiplexedPowerMode) { +            multiplexedOptions.powerMode = trackingOptions.powerMode; +            updateOptions = true; +        } +        // if only one session exists, then tracking should be updated with it +        if (1 == mTimeBasedTrackingSessions.size()) { +            multiplexedOptions = trackingOptions; +            updateOptions = true; +        } +        if (updateOptions) { +            // restart time based tracking with the newly updated options +            updateTracking(client, id, multiplexedOptions, oldOptions); +            // need to wait for QMI callback +            reportToClientWithNoWait = false; +        } +    } + +    return reportToClientWithNoWait; +} + +void +GnssAdapter::stopTrackingCommand(LocationAPI* client, uint32_t id) +{ +    LOC_LOGD("%s]: client %p id %u", __func__, client, id); + +    struct MsgStopTracking : public LocMsg { +        GnssAdapter& mAdapter; +        LocApiBase& mApi; +        LocationAPI* mClient; +        uint32_t mSessionId; +        inline MsgStopTracking(GnssAdapter& adapter, +                               LocApiBase& api, +                               LocationAPI* client, +                               uint32_t sessionId) : +            LocMsg(), +            mAdapter(adapter), +            mApi(api), +            mClient(client), +            mSessionId(sessionId) {} +        inline virtual void proc() const { +            bool isTimeBased = mAdapter.isTimeBasedTrackingSession(mClient, mSessionId); +            bool isDistanceBased = mAdapter.isDistanceBasedTrackingSession(mClient, mSessionId); +            if (isTimeBased || isDistanceBased) { +                if (isTimeBased) { +                    // Api doesn't support multiple clients for time based tracking, so mutiplex +                    bool reportToClientWithNoWait = +                        mAdapter.stopTimeBasedTrackingMultiplex(mClient, mSessionId); +                    mAdapter.eraseTrackingSession(mClient, mSessionId); + +                    if (reportToClientWithNoWait) { +                        mAdapter.reportResponse(mClient, LOCATION_ERROR_SUCCESS, mSessionId); +                    } +                } else if (isDistanceBased) { +                    mApi.stopDistanceBasedTracking(mSessionId, new LocApiResponse( +                            *mAdapter.getContext(), +                            [&mAdapter = mAdapter, mSessionId = mSessionId, mClient = mClient] +                            (LocationError err) { +                        if (LOCATION_ERROR_SUCCESS == err) { +                            mAdapter.eraseTrackingSession(mClient, mSessionId); +                        } +                        mAdapter.reportResponse(mClient, err, mSessionId); +                    })); +                } +            } else { +                mAdapter.reportResponse(mClient, LOCATION_ERROR_ID_UNKNOWN, mSessionId); +            } + +        } +    }; + +    sendMsg(new MsgStopTracking(*this, *mLocApi, client, id)); +} + +bool +GnssAdapter::stopTimeBasedTrackingMultiplex(LocationAPI* client, uint32_t id) +{ +    bool reportToClientWithNoWait = true; + +    if (1 == mTimeBasedTrackingSessions.size()) { +        stopTracking(client, id); +        // need to wait for QMI callback +        reportToClientWithNoWait = false; +    } else { +        LocationSessionKey key(client, id); + +        // get the session we are stopping +        auto it = mTimeBasedTrackingSessions.find(key); +        if (it != mTimeBasedTrackingSessions.end()) { +            // find the smallest interval and powerMode, other than the session we are stopping +            TrackingOptions multiplexedOptions = {}; // size is 0 until set for the first time +            GnssPowerMode multiplexedPowerMode = GNSS_POWER_MODE_INVALID; +            memset(&multiplexedOptions, 0, sizeof(multiplexedOptions)); +            for (auto it2 = mTimeBasedTrackingSessions.begin(); +                 it2 != mTimeBasedTrackingSessions.end(); ++it2) { +                // if session is not the one we are stopping and either interval +                // is not set or there is a new smallest interval, then set the new interval +                if (it2->first != key && (0 == multiplexedOptions.size || +                    it2->second.minInterval < multiplexedOptions.minInterval)) { +                     multiplexedOptions = it2->second; +                } +                // if session is not the one we are stopping and either powerMode +                // is not set or there is a new smallest powerMode, then set the new powerMode +                if (it2->first != key && (GNSS_POWER_MODE_INVALID == multiplexedPowerMode || +                    it2->second.powerMode < multiplexedPowerMode)) { +                    multiplexedPowerMode = it2->second.powerMode; +                } +            } +            // if session we are stopping has smaller interval then next smallest or +            // if session we are stopping has smaller powerMode then next smallest +            if (it->second.minInterval < multiplexedOptions.minInterval || +                it->second.powerMode < multiplexedPowerMode) { +                multiplexedOptions.powerMode = multiplexedPowerMode; +                // restart time based tracking with the newly updated options +                startTimeBasedTracking(client, id, multiplexedOptions); +                // need to wait for QMI callback +                reportToClientWithNoWait = false; +            } +            // else part: no QMI call is made, need to report back to client right away +        } +    } +    return reportToClientWithNoWait; +} + +void +GnssAdapter::stopTracking(LocationAPI* client, uint32_t id) +{ +    // inform engine hub that GNSS session has stopped +    mEngHubProxy->gnssStopFix(); + +    mLocApi->stopFix(new LocApiResponse(*getContext(), +                     [this, client, id] (LocationError err) { +        reportResponse(client, err, id); +    })); + +    if (isDgnssNmeaRequired()) { +        mDgnssState &= ~DGNSS_STATE_NO_NMEA_PENDING; +    } +    stopDgnssNtrip(); + +    mSPEAlreadyRunningAtHighestInterval = false; +} + +bool +GnssAdapter::hasNiNotifyCallback(LocationAPI* client) +{ +    auto it = mClientData.find(client); +    return (it != mClientData.end() && it->second.gnssNiCb); +} + +void +GnssAdapter::gnssNiResponseCommand(LocationAPI* client, +                                   uint32_t id, +                                   GnssNiResponse response) +{ +    LOC_LOGD("%s]: client %p id %u response %u", __func__, client, id, response); + +    struct MsgGnssNiResponse : public LocMsg { +        GnssAdapter& mAdapter; +        LocationAPI* mClient; +        uint32_t mSessionId; +        GnssNiResponse mResponse; +        inline MsgGnssNiResponse(GnssAdapter& adapter, +                                 LocationAPI* client, +                                 uint32_t sessionId, +                                 GnssNiResponse response) : +            LocMsg(), +            mAdapter(adapter), +            mClient(client), +            mSessionId(sessionId), +            mResponse(response) {} +        inline virtual void proc() const { +            NiData& niData = mAdapter.getNiData(); +            LocationError err = LOCATION_ERROR_SUCCESS; +            if (!mAdapter.hasNiNotifyCallback(mClient)) { +                err = LOCATION_ERROR_ID_UNKNOWN; +            } else { +                NiSession* pSession = NULL; +                if (mSessionId == niData.sessionEs.reqID && +                    NULL != niData.sessionEs.rawRequest) { +                    pSession = &niData.sessionEs; +                    // ignore any SUPL NI non-Es session if a SUPL NI ES is accepted +                    if (mResponse == GNSS_NI_RESPONSE_ACCEPT && +                        NULL != niData.session.rawRequest) { +                            pthread_mutex_lock(&niData.session.tLock); +                            niData.session.resp = GNSS_NI_RESPONSE_IGNORE; +                            niData.session.respRecvd = true; +                            pthread_cond_signal(&niData.session.tCond); +                            pthread_mutex_unlock(&niData.session.tLock); +                    } +                } else if (mSessionId == niData.session.reqID && +                    NULL != niData.session.rawRequest) { +                    pSession = &niData.session; +                } + +                if (pSession) { +                    LOC_LOGI("%s]: gnssNiResponseCommand: send user mResponse %u for id %u", +                             __func__, mResponse, mSessionId); +                    pthread_mutex_lock(&pSession->tLock); +                    pSession->resp = mResponse; +                    pSession->respRecvd = true; +                    pthread_cond_signal(&pSession->tCond); +                    pthread_mutex_unlock(&pSession->tLock); +                } else { +                    err = LOCATION_ERROR_ID_UNKNOWN; +                    LOC_LOGE("%s]: gnssNiResponseCommand: id %u not an active session", +                             __func__, mSessionId); +                } +            } +            mAdapter.reportResponse(mClient, err, mSessionId); +        } +    }; + +    sendMsg(new MsgGnssNiResponse(*this, client, id, response)); + +} + +void +GnssAdapter::gnssNiResponseCommand(GnssNiResponse response, void* rawRequest) +{ +    LOC_LOGD("%s]: response %u", __func__, response); + +    struct MsgGnssNiResponse : public LocMsg { +        GnssAdapter& mAdapter; +        LocApiBase& mApi; +        const GnssNiResponse mResponse; +        const void* mPayload; +        inline MsgGnssNiResponse(GnssAdapter& adapter, +                                 LocApiBase& api, +                                 const GnssNiResponse response, +                                 const void* rawRequest) : +            LocMsg(), +            mAdapter(adapter), +            mApi(api), +            mResponse(response), +            mPayload(rawRequest) {} +        inline virtual ~MsgGnssNiResponse() { +        } +        inline virtual void proc() const { +            mApi.informNiResponse(mResponse, mPayload); +        } +    }; + +    sendMsg(new MsgGnssNiResponse(*this, *mLocApi, response, rawRequest)); + +} + +uint32_t +GnssAdapter::enableCommand(LocationTechnologyType techType) +{ +    uint32_t sessionId = generateSessionId(); +    LOC_LOGD("%s]: id %u techType %u", __func__, sessionId, techType); + +    struct MsgEnableGnss : public LocMsg { +        GnssAdapter& mAdapter; +        LocApiBase& mApi; +        ContextBase& mContext; +        uint32_t mSessionId; +        LocationTechnologyType mTechType; +        inline MsgEnableGnss(GnssAdapter& adapter, +                             LocApiBase& api, +                             ContextBase& context, +                             uint32_t sessionId, +                             LocationTechnologyType techType) : +            LocMsg(), +            mAdapter(adapter), +            mApi(api), +            mContext(context), +            mSessionId(sessionId), +            mTechType(techType) {} +        inline virtual void proc() const { +            LocationError err = LOCATION_ERROR_SUCCESS; +            uint32_t afwControlId = mAdapter.getAfwControlId(); +            if (mTechType != LOCATION_TECHNOLOGY_TYPE_GNSS) { +                err = LOCATION_ERROR_INVALID_PARAMETER; +            } else if (afwControlId > 0) { +                err = LOCATION_ERROR_ALREADY_STARTED; +            } else { +                mContext.modemPowerVote(true); +                mAdapter.setAfwControlId(mSessionId); + +                GnssConfigGpsLock gpsLock = GNSS_CONFIG_GPS_LOCK_NONE; +                if (mAdapter.mSupportNfwControl) { +                    ContextBase::mGps_conf.GPS_LOCK &= GNSS_CONFIG_GPS_LOCK_NI; +                    gpsLock = ContextBase::mGps_conf.GPS_LOCK; +                } +                mApi.sendMsg(new LocApiMsg([&mApi = mApi, gpsLock]() { +                    mApi.setGpsLockSync(gpsLock); +                })); +                mAdapter.mXtraObserver.updateLockStatus(gpsLock); +            } +            mAdapter.reportResponse(err, mSessionId); +        } +    }; + +    if (mContext != NULL) { +        sendMsg(new MsgEnableGnss(*this, *mLocApi, *mContext, sessionId, techType)); +    } else { +        LOC_LOGE("%s]: Context is NULL", __func__); +    } + +    return sessionId; +} + +void +GnssAdapter::disableCommand(uint32_t id) +{ +    LOC_LOGD("%s]: id %u", __func__, id); + +    struct MsgDisableGnss : public LocMsg { +        GnssAdapter& mAdapter; +        LocApiBase& mApi; +        ContextBase& mContext; +        uint32_t mSessionId; +        inline MsgDisableGnss(GnssAdapter& adapter, +                             LocApiBase& api, +                             ContextBase& context, +                             uint32_t sessionId) : +            LocMsg(), +            mAdapter(adapter), +            mApi(api), +            mContext(context), +            mSessionId(sessionId) {} +        inline virtual void proc() const { +            LocationError err = LOCATION_ERROR_SUCCESS; +            uint32_t afwControlId = mAdapter.getAfwControlId(); +            if (afwControlId != mSessionId) { +                err = LOCATION_ERROR_ID_UNKNOWN; +            } else { +                mContext.modemPowerVote(false); +                mAdapter.setAfwControlId(0); + +                if (mAdapter.mSupportNfwControl) { +                    /* We need to disable MO (AFW) */ +                    ContextBase::mGps_conf.GPS_LOCK |= GNSS_CONFIG_GPS_LOCK_MO; +                } +                GnssConfigGpsLock gpsLock = ContextBase::mGps_conf.GPS_LOCK; +                mApi.sendMsg(new LocApiMsg([&mApi = mApi, gpsLock]() { +                    mApi.setGpsLockSync(gpsLock); +                })); +                mAdapter.mXtraObserver.updateLockStatus(gpsLock); +            } +            mAdapter.reportResponse(err, mSessionId); +        } +    }; + +    if (mContext != NULL) { +        sendMsg(new MsgDisableGnss(*this, *mLocApi, *mContext, id)); +    } + +} + +// This function computes the VRP based latitude, longitude and alittude, and +// north, east and up velocity and save the result into EHubTechReport. +void +GnssAdapter::computeVRPBasedLla(const UlpLocation& loc, GpsLocationExtended& locExt, +                                const LeverArmConfigInfo& leverArmConfigInfo) { + +    float leverArm[3]; +    float rollPitchYaw[3]; +    double lla[3]; + +    uint16_t locFlags = loc.gpsLocation.flags; +    uint64_t locExtFlags = locExt.flags; + +    // check for SPE fix +    if (!((locExtFlags & GPS_LOCATION_EXTENDED_HAS_OUTPUT_ENG_TYPE) && +          (locExt.locOutputEngType == LOC_OUTPUT_ENGINE_SPE))){ +        LOC_LOGv("not SPE fix, return"); +        return; +    } + +    // we can only do translation if we have VRP based lever ARM info +    LeverArmTypeMask leverArmFlags = leverArmConfigInfo.leverArmValidMask; +    if (!(leverArmFlags & LEVER_ARM_TYPE_GNSS_TO_VRP_BIT)) { +        LOC_LOGd("no VRP based lever ARM info"); +        return; +    } + +    leverArm[0] = leverArmConfigInfo.gnssToVRP.forwardOffsetMeters; +    leverArm[1] = leverArmConfigInfo.gnssToVRP.sidewaysOffsetMeters; +    leverArm[2] = leverArmConfigInfo.gnssToVRP.upOffsetMeters; + +    if ((locFlags & LOC_GPS_LOCATION_HAS_LAT_LONG) && +        (locFlags & LOC_GPS_LOCATION_HAS_ALTITUDE) && +        (locFlags & LOCATION_HAS_BEARING_BIT)) { + +        lla[0] = loc.gpsLocation.latitude * DEG2RAD; +        lla[1] = loc.gpsLocation.longitude * DEG2RAD; +        lla[2] = loc.gpsLocation.altitude; + +        rollPitchYaw[0] = 0.0f; +        rollPitchYaw[1] = 0.0f; +        rollPitchYaw[2] = loc.gpsLocation.bearing * DEG2RAD; + +        loc_convert_lla_gnss_to_vrp(lla, rollPitchYaw, leverArm); + +        // assign the converted value into position report and +        // set up valid mask +        locExt.llaVRPBased.latitude  = lla[0] * RAD2DEG; +        locExt.llaVRPBased.longitude = lla[1] * RAD2DEG; +        locExt.llaVRPBased.altitude  = lla[2]; +        locExt.flags |= GPS_LOCATION_EXTENDED_HAS_LLA_VRP_BASED; +    } else { +        LOC_LOGd("SPE fix missing latitude/longitude/alitutde"); +        return; +    } +} + +void +GnssAdapter::reportPositionEvent(const UlpLocation& ulpLocation, +                                 const GpsLocationExtended& locationExtended, +                                 enum loc_sess_status status, +                                 LocPosTechMask techMask, +                                 GnssDataNotification* pDataNotify, +                                 int msInWeek) +{ +    // this position is from QMI LOC API, then send report to engine hub +    // also, send out SPE fix promptly to the clients that have registered +    // with SPE report +    LOC_LOGd("reportPositionEvent, eng type: %d, unpro %d, sess status %d msInWeek %d", +             locationExtended.locOutputEngType, +             ulpLocation.unpropagatedPosition, status, msInWeek); + +    struct MsgReportSPEPosition : public LocMsg { +        GnssAdapter& mAdapter; +        mutable UlpLocation mUlpLocation; +        mutable GpsLocationExtended mLocationExtended; +        enum loc_sess_status mStatus; +        LocPosTechMask mTechMask; +        mutable GnssDataNotification mDataNotify; +        int mMsInWeek; + +        inline MsgReportSPEPosition(GnssAdapter& adapter, +                                    const UlpLocation& ulpLocation, +                                    const GpsLocationExtended& locationExtended, +                                    enum loc_sess_status status, +                                    LocPosTechMask techMask, +                                    GnssDataNotification dataNotify, +                                    int msInWeek) : +            LocMsg(), +            mAdapter(adapter), +            mUlpLocation(ulpLocation), +            mLocationExtended(locationExtended), +            mStatus(status), +            mTechMask(techMask), +            mDataNotify(dataNotify), +            mMsInWeek(msInWeek) {} +        inline virtual void proc() const { +            if (mAdapter.mTimeBasedTrackingSessions.empty() && +                mAdapter.mDistanceBasedTrackingSessions.empty()) { +                LOC_LOGd("reportPositionEvent, no session on-going, throw away the SPE reports"); +                return; +            } + +            if (false == mUlpLocation.unpropagatedPosition && mDataNotify.size != 0) { +                if (mMsInWeek >= 0) { +                    mAdapter.getDataInformation((GnssDataNotification&)mDataNotify, +                                                mMsInWeek); +                } +                mAdapter.reportData(mDataNotify); +            } + +            if (true == mAdapter.initEngHubProxy()){ +                // send the SPE fix to engine hub +                mAdapter.mEngHubProxy->gnssReportPosition(mUlpLocation, mLocationExtended, mStatus); +                // report out all SPE fix if it is not propagated, even for failed fix +                if (false == mUlpLocation.unpropagatedPosition) { +                    EngineLocationInfo engLocationInfo = {}; +                    engLocationInfo.location = mUlpLocation; +                    engLocationInfo.locationExtended = mLocationExtended; +                    engLocationInfo.sessionStatus = mStatus; + +                    // obtain the VRP based latitude/longitude/altitude for SPE fix +                    computeVRPBasedLla(engLocationInfo.location, +                                       engLocationInfo.locationExtended, +                                       mAdapter.mLocConfigInfo.leverArmConfigInfo); +                    mAdapter.reportEnginePositions(1, &engLocationInfo); +                } +                return; +            } + +            // unpropagated report: is only for engine hub to consume and no need +            // to send out to the clients +            if (true == mUlpLocation.unpropagatedPosition) { +                return; +            } + +            // extract bug report info - this returns true if consumed by systemstatus +            SystemStatus* s = mAdapter.getSystemStatus(); +            if ((nullptr != s) && +                    ((LOC_SESS_SUCCESS == mStatus) || (LOC_SESS_INTERMEDIATE == mStatus))){ +                s->eventPosition(mUlpLocation, mLocationExtended); +            } + +            mAdapter.reportPosition(mUlpLocation, mLocationExtended, mStatus, mTechMask); +        } +    }; + +    if (mContext != NULL) { +        GnssDataNotification dataNotifyCopy = {}; +        if (pDataNotify) { +            dataNotifyCopy = *pDataNotify; +            dataNotifyCopy.size = sizeof(dataNotifyCopy); +        } +        sendMsg(new MsgReportSPEPosition(*this, ulpLocation, locationExtended, +                                          status, techMask, dataNotifyCopy, msInWeek)); +    } +} + +void +GnssAdapter::reportEnginePositionsEvent(unsigned int count, +                                        EngineLocationInfo* locationArr) +{ +    struct MsgReportEnginePositions : public LocMsg { +        GnssAdapter& mAdapter; +        unsigned int mCount; +        EngineLocationInfo mEngLocInfo[LOC_OUTPUT_ENGINE_COUNT]; +        inline MsgReportEnginePositions(GnssAdapter& adapter, +                                        unsigned int count, +                                        EngineLocationInfo* locationArr) : +            LocMsg(), +            mAdapter(adapter), +            mCount(count) { +            if (mCount > LOC_OUTPUT_ENGINE_COUNT) { +                mCount = LOC_OUTPUT_ENGINE_COUNT; +            } +            if (mCount > 0) { +                memcpy(mEngLocInfo, locationArr, sizeof(EngineLocationInfo)*mCount); +            } +        } +        inline virtual void proc() const { +            mAdapter.reportEnginePositions(mCount, mEngLocInfo); +        } +    }; + +    sendMsg(new MsgReportEnginePositions(*this, count, locationArr)); +} + +bool +GnssAdapter::needReportForGnssClient(const UlpLocation& ulpLocation, +                                     enum loc_sess_status status, +                                     LocPosTechMask techMask) { +    bool reported = false; + +    // if engine hub is enabled, aka, any of the engine services is enabled, +    // then always output position reported by engine hub to requesting client +    if (true == initEngHubProxy()) { +        reported = true; +    } else { +        reported = LocApiBase::needReport(ulpLocation, status, techMask); +    } +    return reported; +} + +bool +GnssAdapter::needReportForFlpClient(enum loc_sess_status status, +                                    LocPosTechMask techMask) { +    if (((LOC_SESS_INTERMEDIATE == status) && !(techMask & LOC_POS_TECH_MASK_SENSORS) && +        (!getAllowFlpNetworkFixes())) || +        (LOC_SESS_FAILURE == status)) { +        return false; +    } else { +        return true; +    } +} + +bool +GnssAdapter::isFlpClient(LocationCallbacks& locationCallbacks) +{ +    return (locationCallbacks.gnssLocationInfoCb == nullptr && +            locationCallbacks.gnssSvCb == nullptr && +            locationCallbacks.gnssNmeaCb == nullptr && +            locationCallbacks.gnssDataCb == nullptr && +            locationCallbacks.gnssMeasurementsCb == nullptr); +} + +bool GnssAdapter::needToGenerateNmeaReport(const uint32_t &gpsTimeOfWeekMs, +        const struct timespec32_t &apTimeStamp) +{ +    bool retVal = false; +    uint64_t currentTimeNsec = 0; + +    if (NMEA_PROVIDER_AP == ContextBase::mGps_conf.NMEA_PROVIDER && !mTimeBasedTrackingSessions.empty()) { +        currentTimeNsec = (apTimeStamp.tv_sec * BILLION_NSEC + apTimeStamp.tv_nsec); +        if ((GNSS_NMEA_REPORT_RATE_NHZ == ContextBase::sNmeaReportRate) || +                (GPS_DEFAULT_FIX_INTERVAL_MS <= mLocPositionMode.min_interval)) { +            retVal = true; +        } else { /*tbf is less than 1000 milli-seconds and NMEA reporting rate is set to 1Hz */ +            /* Always send NMEA string for first position report +             * Send when gpsTimeOfWeekMs is closely aligned with integer boundary +             */ +            if ((0 == mPrevNmeaRptTimeNsec) || +                (0 != gpsTimeOfWeekMs) && (NMEA_MIN_THRESHOLD_MSEC >= (gpsTimeOfWeekMs % 1000))) { +                retVal = true; +            } else { +                uint64_t timeDiffMsec = ((currentTimeNsec - mPrevNmeaRptTimeNsec) / 1000000); +                // Send when the delta time becomes >= 1 sec +                if (NMEA_MAX_THRESHOLD_MSEC <= timeDiffMsec) { +                    retVal = true; +                } +            } +        } +        if (true == retVal) { +            mPrevNmeaRptTimeNsec = currentTimeNsec; +        } +    } +    return retVal; +} + +void +GnssAdapter::logLatencyInfo() +{ +    if (0 == mGnssLatencyInfoQueue.size()) { +        LOC_LOGv("mGnssLatencyInfoQueue.size is 0"); +        return; +    } +    mGnssLatencyInfoQueue.front().hlosQtimer5 = getQTimerTickCount(); +    if (0 == mGnssLatencyInfoQueue.front().hlosQtimer3) { +        /* if SPE from engine hub is not reported then hlosQtimer3 = 0, set it +        equal to hlosQtimer2 to make sense */ +        LOC_LOGv("hlosQtimer3 is 0, setting it to hlosQtimer2"); +        mGnssLatencyInfoQueue.front().hlosQtimer3 = mGnssLatencyInfoQueue.front().hlosQtimer2; +    } +    if (0 == mGnssLatencyInfoQueue.front().hlosQtimer4) { +        /* if PPE from engine hub is not reported then hlosQtimer4 = 0, set it +        equal to hlosQtimer3 to make sense */ +        LOC_LOGv("hlosQtimer4 is 0, setting it to hlosQtimer3"); +        mGnssLatencyInfoQueue.front().hlosQtimer4 = mGnssLatencyInfoQueue.front().hlosQtimer3; +    } +    if (mGnssLatencyInfoQueue.front().hlosQtimer4 < mGnssLatencyInfoQueue.front().hlosQtimer3) { +        /* hlosQtimer3 is timestamped when SPE from engine hub is reported, +        and hlosQtimer4 is timestamped when PPE from engine hub is reported. +        The order is random though, hence making sure the timestamps are sorted */ +        LOC_LOGv("hlosQtimer4 is < hlosQtimer3, swapping them"); +        std::swap(mGnssLatencyInfoQueue.front().hlosQtimer3, +                  mGnssLatencyInfoQueue.front().hlosQtimer4); +    } +    LOC_LOGv("meQtimer1=%" PRIi64 " " +             "meQtimer2=%" PRIi64 " " +             "meQtimer3=%" PRIi64 " " +             "peQtimer1=%" PRIi64 " " +             "peQtimer2=%" PRIi64 " " +             "peQtimer3=%" PRIi64 " " +             "smQtimer1=%" PRIi64 " " +             "smQtimer2=%" PRIi64 " " +             "smQtimer3=%" PRIi64 " " +             "locMwQtimer=%" PRIi64 " " +             "hlosQtimer1=%" PRIi64 " " +             "hlosQtimer2=%" PRIi64 " " +             "hlosQtimer3=%" PRIi64 " " +             "hlosQtimer4=%" PRIi64 " " +             "hlosQtimer5=%" PRIi64 " ", +             mGnssLatencyInfoQueue.front().meQtimer1, mGnssLatencyInfoQueue.front().meQtimer2, +             mGnssLatencyInfoQueue.front().meQtimer3, mGnssLatencyInfoQueue.front().peQtimer1, +             mGnssLatencyInfoQueue.front().peQtimer2, mGnssLatencyInfoQueue.front().peQtimer3, +             mGnssLatencyInfoQueue.front().smQtimer1, mGnssLatencyInfoQueue.front().smQtimer2, +             mGnssLatencyInfoQueue.front().smQtimer3, mGnssLatencyInfoQueue.front().locMwQtimer, +             mGnssLatencyInfoQueue.front().hlosQtimer1, mGnssLatencyInfoQueue.front().hlosQtimer2, +             mGnssLatencyInfoQueue.front().hlosQtimer3, mGnssLatencyInfoQueue.front().hlosQtimer4, +             mGnssLatencyInfoQueue.front().hlosQtimer5); +    mLogger.log(mGnssLatencyInfoQueue.front()); +    mGnssLatencyInfoQueue.pop(); +    LOC_LOGv("mGnssLatencyInfoQueue.size after pop=%zu", mGnssLatencyInfoQueue.size()); +} + +// only fused report (when engine hub is enabled) or +// SPE report (when engine hub is disabled) will reach this function +void +GnssAdapter::reportPosition(const UlpLocation& ulpLocation, +                            const GpsLocationExtended& locationExtended, +                            enum loc_sess_status status, +                            LocPosTechMask techMask) +{ +    bool reportToGnssClient = needReportForGnssClient(ulpLocation, status, techMask); +    bool reportToFlpClient = needReportForFlpClient(status, techMask); + +    if (reportToGnssClient || reportToFlpClient) { +        GnssLocationInfoNotification locationInfo = {}; +        convertLocationInfo(locationInfo, locationExtended, status); +        convertLocation(locationInfo.location, ulpLocation, locationExtended); +        logLatencyInfo(); +        for (auto it=mClientData.begin(); it != mClientData.end(); ++it) { +            if ((reportToFlpClient && isFlpClient(it->second)) || +                    (reportToGnssClient && !isFlpClient(it->second))) { +                if (nullptr != it->second.gnssLocationInfoCb) { +                    it->second.gnssLocationInfoCb(locationInfo); +                } else if ((nullptr != it->second.engineLocationsInfoCb) && +                           (false == initEngHubProxy())) { +                    // if engine hub is disabled, this is SPE fix from modem +                    // we need to mark one copy marked as fused and one copy marked as PPE +                    // and dispatch it to the engineLocationsInfoCb +                    GnssLocationInfoNotification engLocationsInfo[2]; +                    engLocationsInfo[0] = locationInfo; +                    engLocationsInfo[0].locOutputEngType = LOC_OUTPUT_ENGINE_FUSED; +                    engLocationsInfo[0].flags |= GNSS_LOCATION_INFO_OUTPUT_ENG_TYPE_BIT; +                    engLocationsInfo[1] = locationInfo; +                    it->second.engineLocationsInfoCb(2, engLocationsInfo); +                } else if (nullptr != it->second.trackingCb) { +                    it->second.trackingCb(locationInfo.location); +                } +            } +        } + +        mGnssSvIdUsedInPosAvail = false; +        mGnssMbSvIdUsedInPosAvail = false; +        if (reportToGnssClient) { +            if (locationExtended.flags & GPS_LOCATION_EXTENDED_HAS_GNSS_SV_USED_DATA) { +                mGnssSvIdUsedInPosAvail = true; +                mGnssSvIdUsedInPosition = locationExtended.gnss_sv_used_ids; +                if (locationExtended.flags & GPS_LOCATION_EXTENDED_HAS_MULTIBAND) { +                    mGnssMbSvIdUsedInPosAvail = true; +                    mGnssMbSvIdUsedInPosition = locationExtended.gnss_mb_sv_used_ids; +                } +            } + +            // if PACE is enabled +            if ((true == mLocConfigInfo.paceConfigInfo.isValid) && +                (true == mLocConfigInfo.paceConfigInfo.enable)) { +                // If fix has sensor contribution, and it is fused fix with DRE engine +                // contributing to the fix, inject to modem +                if ((LOC_POS_TECH_MASK_SENSORS & techMask) && +                        (locationInfo.flags & GNSS_LOCATION_INFO_OUTPUT_ENG_TYPE_BIT) && +                        (locationInfo.locOutputEngType == LOC_OUTPUT_ENGINE_FUSED) && +                        (locationInfo.flags & GNSS_LOCATION_INFO_OUTPUT_ENG_MASK_BIT) && +                        (locationInfo.locOutputEngMask & DEAD_RECKONING_ENGINE)) { +                    mLocApi->injectPosition(locationInfo, false); +                } +            } +        } +    } + +    if (needToGenerateNmeaReport(locationExtended.gpsTime.gpsTimeOfWeekMs, +            locationExtended.timeStamp.apTimeStamp)) { +        /*Only BlankNMEA sentence needs to be processed and sent, if both lat, long is 0 & +          horReliability is not set. */ +        bool blank_fix = ((0 == ulpLocation.gpsLocation.latitude) && +                          (0 == ulpLocation.gpsLocation.longitude) && +                          (LOC_RELIABILITY_NOT_SET == locationExtended.horizontal_reliability)); +        uint8_t generate_nmea = (reportToGnssClient && status != LOC_SESS_FAILURE && !blank_fix); +        bool custom_nmea_gga = (1 == ContextBase::mGps_conf.CUSTOM_NMEA_GGA_FIX_QUALITY_ENABLED); +        bool isTagBlockGroupingEnabled = +                (1 == ContextBase::mGps_conf.NMEA_TAG_BLOCK_GROUPING_ENABLED); +        std::vector<std::string> nmeaArraystr; +        int indexOfGGA = -1; +        loc_nmea_generate_pos(ulpLocation, locationExtended, mLocSystemInfo, generate_nmea, +                custom_nmea_gga, nmeaArraystr, indexOfGGA, isTagBlockGroupingEnabled); +        stringstream ss; +        for (auto itor = nmeaArraystr.begin(); itor != nmeaArraystr.end(); ++itor) { +            ss << *itor; +        } +        string s = ss.str(); +        reportNmea(s.c_str(), s.length()); + +        /* DgnssNtrip */ +        if (-1 != indexOfGGA && isDgnssNmeaRequired()) { +            mDgnssState |= DGNSS_STATE_NO_NMEA_PENDING; +            mStartDgnssNtripParams.nmea = std::move(nmeaArraystr[indexOfGGA]); +            bool isLocationValid = (0 != ulpLocation.gpsLocation.latitude) || +                    (0 != ulpLocation.gpsLocation.longitude); +            checkUpdateDgnssNtrip(isLocationValid); +        } +    } +} + +void +GnssAdapter::reportLatencyInfoEvent(const GnssLatencyInfo& gnssLatencyInfo) +{ +    struct MsgReportLatencyInfo : public LocMsg { +        GnssAdapter& mAdapter; +        GnssLatencyInfo mGnssLatencyInfo; +        inline MsgReportLatencyInfo(GnssAdapter& adapter, +            const GnssLatencyInfo& gnssLatencyInfo) : +            mGnssLatencyInfo(gnssLatencyInfo), +            mAdapter(adapter) {} +        inline virtual void proc() const { +            mAdapter.mGnssLatencyInfoQueue.push(mGnssLatencyInfo); +            LOC_LOGv("mGnssLatencyInfoQueue.size after push=%zu", +                      mAdapter.mGnssLatencyInfoQueue.size()); +        } +    }; +    sendMsg(new MsgReportLatencyInfo(*this, gnssLatencyInfo)); +} + +void +GnssAdapter::reportEnginePositions(unsigned int count, +                                   const EngineLocationInfo* locationArr) +{ +    bool needReportEnginePositions = false; +    for (auto it=mClientData.begin(); it != mClientData.end(); ++it) { +        if (nullptr != it->second.engineLocationsInfoCb) { +            needReportEnginePositions = true; +            break; +        } +    } + +    GnssLocationInfoNotification locationInfo[LOC_OUTPUT_ENGINE_COUNT] = {}; +    for (unsigned int i = 0; i < count; i++) { +        const EngineLocationInfo* engLocation = (locationArr+i); +        // if it is fused/default location, call reportPosition maintain legacy behavior +        if ((GPS_LOCATION_EXTENDED_HAS_OUTPUT_ENG_TYPE & engLocation->locationExtended.flags) && +            (LOC_OUTPUT_ENGINE_FUSED == engLocation->locationExtended.locOutputEngType)) { +            reportPosition(engLocation->location, +                           engLocation->locationExtended, +                           engLocation->sessionStatus, +                           engLocation->location.tech_mask); +        } + +        if (needReportEnginePositions) { +            convertLocationInfo(locationInfo[i], engLocation->locationExtended, +                                engLocation->sessionStatus); +            convertLocation(locationInfo[i].location, +                            engLocation->location, +                            engLocation->locationExtended); +        } +    } + +    const EngineLocationInfo* engLocation = locationArr; +    LOC_LOGv("engLocation->locationExtended.locOutputEngType=%d", +             engLocation->locationExtended.locOutputEngType); + +    if (0 != mGnssLatencyInfoQueue.size()) { +        if ((GPS_LOCATION_EXTENDED_HAS_OUTPUT_ENG_TYPE & engLocation->locationExtended.flags) && +            (LOC_OUTPUT_ENGINE_SPE == engLocation->locationExtended.locOutputEngType)) { +            mGnssLatencyInfoQueue.front().hlosQtimer3 = getQTimerTickCount(); +            LOC_LOGv("SPE hlosQtimer3=%" PRIi64 " ", mGnssLatencyInfoQueue.front().hlosQtimer3); +        } +        if ((GPS_LOCATION_EXTENDED_HAS_OUTPUT_ENG_TYPE & engLocation->locationExtended.flags) && +            (LOC_OUTPUT_ENGINE_PPE == engLocation->locationExtended.locOutputEngType)) { +            mGnssLatencyInfoQueue.front().hlosQtimer4 = getQTimerTickCount(); +            LOC_LOGv("PPE hlosQtimer4=%" PRIi64 " ", mGnssLatencyInfoQueue.front().hlosQtimer4); +        } +    } +    if (needReportEnginePositions) { +        for (auto it=mClientData.begin(); it != mClientData.end(); ++it) { +            if (nullptr != it->second.engineLocationsInfoCb) { +                it->second.engineLocationsInfoCb(count, locationInfo); +            } +        } +    } +} + +void +GnssAdapter::reportSvEvent(const GnssSvNotification& svNotify, +                           bool fromEngineHub) +{ +    if (!fromEngineHub) { +        mEngHubProxy->gnssReportSv(svNotify); +        if (true == initEngHubProxy()){ +            return; +        } +    } + +    struct MsgReportSv : public LocMsg { +        GnssAdapter& mAdapter; +        const GnssSvNotification mSvNotify; +        inline MsgReportSv(GnssAdapter& adapter, +                           const GnssSvNotification& svNotify) : +            LocMsg(), +            mAdapter(adapter), +            mSvNotify(svNotify) {} +        inline virtual void proc() const { +            mAdapter.reportSv((GnssSvNotification&)mSvNotify); +        } +    }; + +    sendMsg(new MsgReportSv(*this, svNotify)); +} + +void +GnssAdapter::reportSv(GnssSvNotification& svNotify) +{ +    int numSv = svNotify.count; +    uint16_t gnssSvId = 0; +    uint64_t svUsedIdMask = 0; +    for (int i=0; i < numSv; i++) { +        svUsedIdMask = 0; +        gnssSvId = svNotify.gnssSvs[i].svId; +        GnssSignalTypeMask signalTypeMask = svNotify.gnssSvs[i].gnssSignalTypeMask; +        switch (svNotify.gnssSvs[i].type) { +            case GNSS_SV_TYPE_GPS: +                if (mGnssSvIdUsedInPosAvail) { +                    if (mGnssMbSvIdUsedInPosAvail) { +                        switch (signalTypeMask) { +                        case GNSS_SIGNAL_GPS_L1CA: +                            svUsedIdMask = mGnssMbSvIdUsedInPosition.gps_l1ca_sv_used_ids_mask; +                            break; +                        case GNSS_SIGNAL_GPS_L1C: +                            svUsedIdMask = mGnssMbSvIdUsedInPosition.gps_l1c_sv_used_ids_mask; +                            break; +                        case GNSS_SIGNAL_GPS_L2: +                            svUsedIdMask = mGnssMbSvIdUsedInPosition.gps_l2_sv_used_ids_mask; +                            break; +                        case GNSS_SIGNAL_GPS_L5: +                            svUsedIdMask = mGnssMbSvIdUsedInPosition.gps_l5_sv_used_ids_mask; +                            break; +                        } +                    } else { +                        svUsedIdMask = mGnssSvIdUsedInPosition.gps_sv_used_ids_mask; +                    } +                } +                break; +            case GNSS_SV_TYPE_GLONASS: +                if (mGnssSvIdUsedInPosAvail) { +                    if (mGnssMbSvIdUsedInPosAvail) { +                        switch (signalTypeMask) { +                        case GNSS_SIGNAL_GLONASS_G1: +                            svUsedIdMask = mGnssMbSvIdUsedInPosition.glo_g1_sv_used_ids_mask; +                            break; +                        case GNSS_SIGNAL_GLONASS_G2: +                            svUsedIdMask = mGnssMbSvIdUsedInPosition.glo_g2_sv_used_ids_mask; +                            break; +                        } +                    } else { +                        svUsedIdMask = mGnssSvIdUsedInPosition.glo_sv_used_ids_mask; +                    } +                } +                // map the svid to respective constellation range 1..xx +                // then repective constellation svUsedIdMask map correctly to svid +                gnssSvId = gnssSvId - GLO_SV_PRN_MIN + 1; +                break; +            case GNSS_SV_TYPE_BEIDOU: +                if (mGnssSvIdUsedInPosAvail) { +                    if (mGnssMbSvIdUsedInPosAvail) { +                        switch (signalTypeMask) { +                        case GNSS_SIGNAL_BEIDOU_B1I: +                            svUsedIdMask = mGnssMbSvIdUsedInPosition.bds_b1i_sv_used_ids_mask; +                            break; +                        case GNSS_SIGNAL_BEIDOU_B1C: +                            svUsedIdMask = mGnssMbSvIdUsedInPosition.bds_b1c_sv_used_ids_mask; +                            break; +                        case GNSS_SIGNAL_BEIDOU_B2I: +                            svUsedIdMask = mGnssMbSvIdUsedInPosition.bds_b2i_sv_used_ids_mask; +                            break; +                        case GNSS_SIGNAL_BEIDOU_B2AI: +                            svUsedIdMask = mGnssMbSvIdUsedInPosition.bds_b2ai_sv_used_ids_mask; +                            break; +                        case GNSS_SIGNAL_BEIDOU_B2AQ: +                            svUsedIdMask = mGnssMbSvIdUsedInPosition.bds_b2aq_sv_used_ids_mask; +                            break; +                        } +                    } else { +                        svUsedIdMask = mGnssSvIdUsedInPosition.bds_sv_used_ids_mask; +                    } +                } +                gnssSvId = gnssSvId - BDS_SV_PRN_MIN + 1; +                break; +            case GNSS_SV_TYPE_GALILEO: +                if (mGnssSvIdUsedInPosAvail) { +                    if (mGnssMbSvIdUsedInPosAvail) { +                        switch (signalTypeMask) { +                        case GNSS_SIGNAL_GALILEO_E1: +                            svUsedIdMask = mGnssMbSvIdUsedInPosition.gal_e1_sv_used_ids_mask; +                            break; +                        case GNSS_SIGNAL_GALILEO_E5A: +                            svUsedIdMask = mGnssMbSvIdUsedInPosition.gal_e5a_sv_used_ids_mask; +                            break; +                        case GNSS_SIGNAL_GALILEO_E5B: +                            svUsedIdMask = mGnssMbSvIdUsedInPosition.gal_e5b_sv_used_ids_mask; +                            break; +                        } +                    } else { +                        svUsedIdMask = mGnssSvIdUsedInPosition.gal_sv_used_ids_mask; +                    } +                } +                gnssSvId = gnssSvId - GAL_SV_PRN_MIN + 1; +                break; +            case GNSS_SV_TYPE_QZSS: +                if (mGnssSvIdUsedInPosAvail) { +                    if (mGnssMbSvIdUsedInPosAvail) { +                        switch (signalTypeMask) { +                        case GNSS_SIGNAL_QZSS_L1CA: +                            svUsedIdMask = mGnssMbSvIdUsedInPosition.qzss_l1ca_sv_used_ids_mask; +                            break; +                        case GNSS_SIGNAL_QZSS_L1S: +                            svUsedIdMask = mGnssMbSvIdUsedInPosition.qzss_l1s_sv_used_ids_mask; +                            break; +                        case GNSS_SIGNAL_QZSS_L2: +                            svUsedIdMask = mGnssMbSvIdUsedInPosition.qzss_l2_sv_used_ids_mask; +                            break; +                        case GNSS_SIGNAL_QZSS_L5: +                            svUsedIdMask = mGnssMbSvIdUsedInPosition.qzss_l5_sv_used_ids_mask; +                            break; +                        } +                    } else { +                        svUsedIdMask = mGnssSvIdUsedInPosition.qzss_sv_used_ids_mask; +                    } +                } +                gnssSvId = gnssSvId - QZSS_SV_PRN_MIN + 1; +                break; +            case GNSS_SV_TYPE_NAVIC: +                if (mGnssSvIdUsedInPosAvail) { +                    svUsedIdMask = mGnssSvIdUsedInPosition.navic_sv_used_ids_mask; +                } +                gnssSvId = gnssSvId - NAVIC_SV_PRN_MIN + 1; +                break; +            default: +                svUsedIdMask = 0; +                break; +        } + +        // If SV ID was used in previous position fix, then set USED_IN_FIX +        // flag, else clear the USED_IN_FIX flag. +        if (svFitsMask(svUsedIdMask, gnssSvId) && (svUsedIdMask & (1ULL << (gnssSvId - 1)))) { +            svNotify.gnssSvs[i].gnssSvOptionsMask |= GNSS_SV_OPTIONS_USED_IN_FIX_BIT; +        } +    } + +    for (auto it=mClientData.begin(); it != mClientData.end(); ++it) { +        if (nullptr != it->second.gnssSvCb) { +            it->second.gnssSvCb(svNotify); +        } +    } + +    if (NMEA_PROVIDER_AP == ContextBase::mGps_conf.NMEA_PROVIDER && +        !mTimeBasedTrackingSessions.empty()) { +        std::vector<std::string> nmeaArraystr; +        loc_nmea_generate_sv(svNotify, nmeaArraystr); +        stringstream ss; +        for (auto itor = nmeaArraystr.begin(); itor != nmeaArraystr.end(); ++itor) { +            ss << *itor; +        } +        string s = ss.str(); +        reportNmea(s.c_str(), s.length()); +    } + +    mGnssSvIdUsedInPosAvail = false; +    mGnssMbSvIdUsedInPosAvail = false; +} + +void +GnssAdapter::reportNmeaEvent(const char* nmea, size_t length) +{ +    if (NMEA_PROVIDER_AP == ContextBase::mGps_conf.NMEA_PROVIDER && +        !loc_nmea_is_debug(nmea, length)) { +        return; +    } + +    struct MsgReportNmea : public LocMsg { +        GnssAdapter& mAdapter; +        const char* mNmea; +        size_t mLength; +        inline MsgReportNmea(GnssAdapter& adapter, +                             const char* nmea, +                             size_t length) : +            LocMsg(), +            mAdapter(adapter), +            mNmea(new char[length+1]), +            mLength(length) { +                if (mNmea == nullptr) { +                    LOC_LOGE("%s] new allocation failed, fatal error.", __func__); +                    return; +                } +                strlcpy((char*)mNmea, nmea, length+1); +            } +        inline virtual ~MsgReportNmea() +        { +            delete[] mNmea; +        } +        inline virtual void proc() const { +            // extract bug report info - this returns true if consumed by systemstatus +            bool ret = false; +            SystemStatus* s = mAdapter.getSystemStatus(); +            if (nullptr != s) { +                ret = s->setNmeaString(mNmea, mLength); +            } +            if (false == ret) { +                // forward NMEA message to upper layer +                mAdapter.reportNmea(mNmea, mLength); +                // DgnssNtrip +                mAdapter.reportGGAToNtrip(mNmea); +            } +        } +    }; + +    sendMsg(new MsgReportNmea(*this, nmea, length)); +} + +void +GnssAdapter::reportNmea(const char* nmea, size_t length) +{ +    GnssNmeaNotification nmeaNotification = {}; +    nmeaNotification.size = sizeof(GnssNmeaNotification); + +    struct timeval tv; +    gettimeofday(&tv, (struct timezone *) NULL); +    int64_t now = tv.tv_sec * 1000LL + tv.tv_usec / 1000; +    nmeaNotification.timestamp = now; +    nmeaNotification.nmea = nmea; +    nmeaNotification.length = length; + +    for (auto it=mClientData.begin(); it != mClientData.end(); ++it) { +        if (nullptr != it->second.gnssNmeaCb) { +            it->second.gnssNmeaCb(nmeaNotification); +        } +    } + +    if (isNMEAPrintEnabled()) { +        LOC_LOGd("[%" PRId64 ", %zu] %s", now, length, nmea); +    } +} + +void +GnssAdapter::reportDataEvent(const GnssDataNotification& dataNotify, +                             int msInWeek) +{ +    struct MsgReportData : public LocMsg { +        GnssAdapter& mAdapter; +        GnssDataNotification mDataNotify; +        int mMsInWeek; +        inline MsgReportData(GnssAdapter& adapter, +                             const GnssDataNotification& dataNotify, +                             int msInWeek) : +            LocMsg(), +            mAdapter(adapter), +            mDataNotify(dataNotify), +            mMsInWeek(msInWeek) { +        } +        inline virtual void proc() const { +            if (mMsInWeek >= 0) { +                mAdapter.getDataInformation((GnssDataNotification&)mDataNotify, +                                            mMsInWeek); +            } +            mAdapter.reportData((GnssDataNotification&)mDataNotify); +        } +    }; + +    sendMsg(new MsgReportData(*this, dataNotify, msInWeek)); +} + +void +GnssAdapter::reportData(GnssDataNotification& dataNotify) +{ +    for (int sig = 0; sig < GNSS_LOC_MAX_NUMBER_OF_SIGNAL_TYPES; sig++) { +        if (GNSS_LOC_DATA_JAMMER_IND_BIT == +            (dataNotify.gnssDataMask[sig] & GNSS_LOC_DATA_JAMMER_IND_BIT)) { +            LOC_LOGv("jammerInd[%d]=%f", sig, dataNotify.jammerInd[sig]); +        } +        if (GNSS_LOC_DATA_AGC_BIT == +            (dataNotify.gnssDataMask[sig] & GNSS_LOC_DATA_AGC_BIT)) { +            LOC_LOGv("agc[%d]=%f", sig, dataNotify.agc[sig]); +        } +    } +    for (auto it = mClientData.begin(); it != mClientData.end(); ++it) { +        if (nullptr != it->second.gnssDataCb) { +            it->second.gnssDataCb(dataNotify); +        } +    } +} + +bool +GnssAdapter::requestNiNotifyEvent(const GnssNiNotification ¬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; +} diff --git a/gps/gnss/GnssAdapter.h b/gps/gnss/GnssAdapter.h new file mode 100644 index 0000000..6b8d024 --- /dev/null +++ b/gps/gnss/GnssAdapter.h @@ -0,0 +1,648 @@ +/* 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. + * + */ +#ifndef GNSS_ADAPTER_H +#define GNSS_ADAPTER_H + +#include <LocAdapterBase.h> +#include <LocContext.h> +#include <IOsObserver.h> +#include <EngineHubProxyBase.h> +#include <LocationAPI.h> +#include <Agps.h> +#include <SystemStatus.h> +#include <XtraSystemStatusObserver.h> +#include <map> +#include <functional> +#include <loc_misc_utils.h> +#include <queue> +#include <NativeAgpsHandler.h> + +#define MAX_URL_LEN 256 +#define NMEA_SENTENCE_MAX_LENGTH 200 +#define GLONASS_SV_ID_OFFSET 64 +#define MAX_SATELLITES_IN_USE 12 +#define LOC_NI_NO_RESPONSE_TIME 20 +#define LOC_GPS_NI_RESPONSE_IGNORE 4 +#define ODCPI_EXPECTED_INJECTION_TIME_MS 10000 +#define DELETE_AIDING_DATA_EXPECTED_TIME_MS 5000 + +class GnssAdapter; + +typedef std::map<LocationSessionKey, LocationOptions> LocationSessionMap; +typedef std::map<LocationSessionKey, TrackingOptions> TrackingOptionsMap; + +class OdcpiTimer : public LocTimer { +public: +    OdcpiTimer(GnssAdapter* adapter) : +            LocTimer(), mAdapter(adapter), mActive(false) {} + +    inline void start() { +        mActive = true; +        LocTimer::start(ODCPI_EXPECTED_INJECTION_TIME_MS, false); +    } +    inline void stop() { +        mActive = false; +        LocTimer::stop(); +    } +    inline void restart() { +        stop(); +        start(); +    } +    inline bool isActive() { +        return mActive; +    } + +private: +    // Override +    virtual void timeOutCallback() override; + +    GnssAdapter* mAdapter; +    bool mActive; +}; + +typedef struct { +    pthread_t               thread;        /* NI thread */ +    uint32_t                respTimeLeft;  /* examine time for NI response */ +    bool                    respRecvd;     /* NI User reponse received or not from Java layer*/ +    void*                   rawRequest; +    uint32_t                reqID;         /* ID to check against response */ +    GnssNiResponse          resp; +    pthread_cond_t          tCond; +    pthread_mutex_t         tLock; +    GnssAdapter*            adapter; +} NiSession; +typedef struct { +    NiSession session;    /* SUPL NI Session */ +    NiSession sessionEs;  /* Emergency SUPL NI Session */ +    uint32_t reqIDCounter; +} NiData; + +typedef enum { +    NMEA_PROVIDER_AP = 0, // Application Processor Provider of NMEA +    NMEA_PROVIDER_MP      // Modem Processor Provider of NMEA +} NmeaProviderType; +typedef struct { +    GnssSvType svType; +    const char* talker; +    uint64_t mask; +    uint32_t svIdOffset; +} NmeaSvMeta; + +typedef struct { +    double latitude; +    double longitude; +    float  accuracy; +    // the CPI will be blocked until the boot time +    // specified in blockedTillTsMs +    int64_t blockedTillTsMs; +    // CPIs whose both latitude and longitude differ +    // no more than latLonThreshold will be blocked +    // in units of degree +    double latLonDiffThreshold; +} BlockCPIInfo; + +typedef struct { +    bool isValid; +    bool enable; +    float tuncThresholdMs; // need to be specified if enable is true +    uint32_t energyBudget; // need to be specified if enable is true +} TuncConfigInfo; + +typedef struct { +    bool isValid; +    bool enable; +} PaceConfigInfo; + +typedef struct { +    bool isValid; +    bool enable; +    bool enableFor911; +} RobustLocationConfigInfo; + +typedef struct { +    TuncConfigInfo tuncConfigInfo; +    PaceConfigInfo paceConfigInfo; +    RobustLocationConfigInfo robustLocationConfigInfo; +    LeverArmConfigInfo  leverArmConfigInfo; +} LocIntegrationConfigInfo; + +using namespace loc_core; + +namespace loc_core { +    class SystemStatus; +} + +typedef std::function<void( +    uint64_t gnssEnergyConsumedFromFirstBoot +)> GnssEnergyConsumedCallback; + +typedef void* QDgnssListenerHDL; +typedef std::function<void( +    bool    sessionActive +)> QDgnssSessionActiveCb; + +struct CdfwInterface { +    void (*startDgnssApiService)(const MsgTask& msgTask); +    QDgnssListenerHDL (*createUsableReporter)( +            QDgnssSessionActiveCb sessionActiveCb); +    void (*destroyUsableReporter)(QDgnssListenerHDL handle); +    void (*reportUsable)(QDgnssListenerHDL handle, bool usable); +}; + +typedef uint16_t  DGnssStateBitMask; +#define DGNSS_STATE_ENABLE_NTRIP_COMMAND      0X01 +#define DGNSS_STATE_NO_NMEA_PENDING           0X02 +#define DGNSS_STATE_NTRIP_SESSION_STARTED     0X04 + +class GnssReportLoggerUtil { +public: +    typedef void (*LogGnssLatency)(const GnssLatencyInfo& gnssLatencyMeasInfo); + +    GnssReportLoggerUtil() : mLogLatency(nullptr) { +        const char* libname = "liblocdiagiface.so"; +        void* libHandle = nullptr; +        mLogLatency = (LogGnssLatency)dlGetSymFromLib(libHandle, libname, "LogGnssLatency"); +    } + +    bool isLogEnabled(); +    void log(const GnssLatencyInfo& gnssLatencyMeasInfo); + +private: +    LogGnssLatency mLogLatency; +}; + +class GnssAdapter : public LocAdapterBase { + +    /* ==== Engine Hub ===================================================================== */ +    EngineHubProxyBase* mEngHubProxy; +    bool mNHzNeeded; +    bool mSPEAlreadyRunningAtHighestInterval; + +    /* ==== TRACKING ======================================================================= */ +    TrackingOptionsMap mTimeBasedTrackingSessions; +    LocationSessionMap mDistanceBasedTrackingSessions; +    LocPosMode mLocPositionMode; +    GnssSvUsedInPosition mGnssSvIdUsedInPosition; +    bool mGnssSvIdUsedInPosAvail; +    GnssSvMbUsedInPosition mGnssMbSvIdUsedInPosition; +    bool mGnssMbSvIdUsedInPosAvail; + +    /* ==== CONTROL ======================================================================== */ +    LocationControlCallbacks mControlCallbacks; +    uint32_t mAfwControlId; +    uint32_t mNmeaMask; +    uint64_t mPrevNmeaRptTimeNsec; +    GnssSvIdConfig mGnssSvIdConfig; +    GnssSvTypeConfig mGnssSeconaryBandConfig; +    GnssSvTypeConfig mGnssSvTypeConfig; +    GnssSvTypeConfigCallback mGnssSvTypeConfigCb; +    bool mSupportNfwControl; +    LocIntegrationConfigInfo mLocConfigInfo; + +    /* ==== NI ============================================================================= */ +    NiData mNiData; + +    /* ==== AGPS =========================================================================== */ +    // This must be initialized via initAgps() +    AgpsManager mAgpsManager; +    void initAgps(const AgpsCbInfo& cbInfo); + +    /* ==== NFW =========================================================================== */ +    NfwStatusCb mNfwCb; +    IsInEmergencySession mIsE911Session; +    inline void initNfw(const NfwCbInfo& cbInfo) { +        mNfwCb = (NfwStatusCb)cbInfo.visibilityControlCb; +        mIsE911Session = (IsInEmergencySession)cbInfo.isInEmergencySession; +    } + +    /* ==== Measurement Corrections========================================================= */ +    bool mIsMeasCorrInterfaceOpen; +    measCorrSetCapabilitiesCb mMeasCorrSetCapabilitiesCb; +    bool initMeasCorr(bool bSendCbWhenNotSupported); +    bool mIsAntennaInfoInterfaceOpened; + +    /* ==== DGNSS Data Usable Report======================================================== */ +    QDgnssListenerHDL mQDgnssListenerHDL; +    const CdfwInterface* mCdfwInterface; +    bool mDGnssNeedReport; +    bool mDGnssDataUsage; +    void reportDGnssDataUsable(const GnssSvMeasurementSet &svMeasurementSet); + +    /* ==== ODCPI ========================================================================== */ +    OdcpiRequestCallback mOdcpiRequestCb; +    bool mOdcpiRequestActive; +    OdcpiPrioritytype mCallbackPriority; +    OdcpiTimer mOdcpiTimer; +    OdcpiRequestInfo mOdcpiRequest; +    void odcpiTimerExpire(); + +    /* ==== DELETEAIDINGDATA =============================================================== */ +    int64_t mLastDeleteAidingDataTime; + +    /* === SystemStatus ===================================================================== */ +    SystemStatus* mSystemStatus; +    std::string mServerUrl; +    std::string mMoServerUrl; +    XtraSystemStatusObserver mXtraObserver; +    LocationSystemInfo mLocSystemInfo; +    std::vector<GnssSvIdSource> mBlacklistedSvIds; +    PowerStateType mSystemPowerState; + +    /* === Misc ===================================================================== */ +    BlockCPIInfo mBlockCPIInfo; +    bool mPowerOn; +    uint32_t mAllowFlpNetworkFixes; +    std::queue<GnssLatencyInfo> mGnssLatencyInfoQueue; +    GnssReportLoggerUtil mLogger; +    bool mDreIntEnabled; + +    /* === NativeAgpsHandler ======================================================== */ +    NativeAgpsHandler mNativeAgpsHandler; + +    /* === Misc callback from QMI LOC API ============================================== */ +    GnssEnergyConsumedCallback mGnssEnergyConsumedCb; +    std::function<void(bool)> mPowerStateCb; + +    /*==== CONVERSION ===================================================================*/ +    static void convertOptions(LocPosMode& out, const TrackingOptions& trackingOptions); +    static void convertLocation(Location& out, const UlpLocation& ulpLocation, +                                const GpsLocationExtended& locationExtended); +    static void convertLocationInfo(GnssLocationInfoNotification& out, +                                    const GpsLocationExtended& locationExtended, +                                    loc_sess_status status); +    static uint16_t getNumSvUsed(uint64_t svUsedIdsMask, +                                 int totalSvCntInThisConstellation); + +    /* ======== UTILITIES ================================================================== */ +    inline void initOdcpi(const OdcpiRequestCallback& callback, OdcpiPrioritytype priority); +    inline void injectOdcpi(const Location& location); +    static bool isFlpClient(LocationCallbacks& locationCallbacks); + +    /*==== DGnss Ntrip Source ==========================================================*/ +    StartDgnssNtripParams   mStartDgnssNtripParams; +    bool    mSendNmeaConsent; +    DGnssStateBitMask   mDgnssState; +    void checkUpdateDgnssNtrip(bool isLocationValid); +    void stopDgnssNtrip(); +    uint64_t   mDgnssLastNmeaBootTimeMilli; + +protected: + +    /* ==== CLIENT ========================================================================= */ +    virtual void updateClientsEventMask(); +    virtual void stopClientSessions(LocationAPI* client); +    inline void setNmeaReportRateConfig(); +    void logLatencyInfo(); + +public: + +    GnssAdapter(); +    virtual inline ~GnssAdapter() { } + +    /* ==== SSR ============================================================================ */ +    /* ======== EVENTS ====(Called from QMI Thread)========================================= */ +    virtual void handleEngineUpEvent(); +    /* ======== UTILITIES ================================================================== */ +    void restartSessions(bool modemSSR = false); +    void checkAndRestartTimeBasedSession(); +    void checkAndRestartSPESession(); +    void suspendSessions(); + +    /* ==== CLIENT ========================================================================= */ +    /* ======== COMMANDS ====(Called from Client Thread)==================================== */ +    virtual void addClientCommand(LocationAPI* client, const LocationCallbacks& callbacks); + +    /* ==== TRACKING ======================================================================= */ +    /* ======== COMMANDS ====(Called from Client Thread)==================================== */ +    uint32_t startTrackingCommand( +            LocationAPI* client, TrackingOptions& trackingOptions); +    void updateTrackingOptionsCommand( +            LocationAPI* client, uint32_t id, TrackingOptions& trackingOptions); +    void stopTrackingCommand(LocationAPI* client, uint32_t id); +    /* ======== RESPONSES ================================================================== */ +    void reportResponse(LocationAPI* client, LocationError err, uint32_t sessionId); +    /* ======== UTILITIES ================================================================== */ +    bool isTimeBasedTrackingSession(LocationAPI* client, uint32_t sessionId); +    bool isDistanceBasedTrackingSession(LocationAPI* client, uint32_t sessionId); +    bool hasCallbacksToStartTracking(LocationAPI* client); +    bool isTrackingSession(LocationAPI* client, uint32_t sessionId); +    void saveTrackingSession(LocationAPI* client, uint32_t sessionId, +                             const TrackingOptions& trackingOptions); +    void eraseTrackingSession(LocationAPI* client, uint32_t sessionId); + +    bool setLocPositionMode(const LocPosMode& mode); +    LocPosMode& getLocPositionMode() { return mLocPositionMode; } + +    bool startTimeBasedTrackingMultiplex(LocationAPI* client, uint32_t sessionId, +                                         const TrackingOptions& trackingOptions); +    void startTimeBasedTracking(LocationAPI* client, uint32_t sessionId, +            const TrackingOptions& trackingOptions); +    bool stopTimeBasedTrackingMultiplex(LocationAPI* client, uint32_t id); +    void stopTracking(LocationAPI* client, uint32_t id); +    bool updateTrackingMultiplex(LocationAPI* client, uint32_t id, +            const TrackingOptions& trackingOptions); +    void updateTracking(LocationAPI* client, uint32_t sessionId, +            const TrackingOptions& updatedOptions, const TrackingOptions& oldOptions); +    bool checkAndSetSPEToRunforNHz(TrackingOptions & out); + +    void setConstrainedTunc(bool enable, float tuncConstraint, +                            uint32_t energyBudget, uint32_t sessionId); +    void setPositionAssistedClockEstimator(bool enable, uint32_t sessionId); +    void gnssUpdateSvConfig(uint32_t sessionId, +                        const GnssSvTypeConfig& constellationEnablementConfig, +                        const GnssSvIdConfig& blacklistSvConfig); + +    void gnssUpdateSecondaryBandConfig( +        uint32_t sessionId, const GnssSvTypeConfig& secondaryBandConfig); +    void gnssGetSecondaryBandConfig(uint32_t sessionId); +    void resetSvConfig(uint32_t sessionId); +    void configLeverArm(uint32_t sessionId, const LeverArmConfigInfo& configInfo); +    void configRobustLocation(uint32_t sessionId, bool enable, bool enableForE911); +    void configMinGpsWeek(uint32_t sessionId, uint16_t minGpsWeek); + +    /* ==== NI ============================================================================= */ +    /* ======== COMMANDS ====(Called from Client Thread)==================================== */ +    void gnssNiResponseCommand(LocationAPI* client, uint32_t id, GnssNiResponse response); +    /* ======================(Called from NI Thread)======================================== */ +    void gnssNiResponseCommand(GnssNiResponse response, void* rawRequest); +    /* ======== UTILITIES ================================================================== */ +    bool hasNiNotifyCallback(LocationAPI* client); +    NiData& getNiData() { return mNiData; } + +    /* ==== CONTROL CLIENT ================================================================= */ +    /* ======== COMMANDS ====(Called from Client Thread)==================================== */ +    uint32_t enableCommand(LocationTechnologyType techType); +    void disableCommand(uint32_t id); +    void setControlCallbacksCommand(LocationControlCallbacks& controlCallbacks); +    void readConfigCommand(); +    void requestUlpCommand(); +    void initEngHubProxyCommand(); +    uint32_t* gnssUpdateConfigCommand(const GnssConfig& config); +    uint32_t* gnssGetConfigCommand(GnssConfigFlagsMask mask); +    uint32_t gnssDeleteAidingDataCommand(GnssAidingData& data); +    void deleteAidingData(const GnssAidingData &data, uint32_t sessionId); +    void gnssUpdateXtraThrottleCommand(const bool enabled); +    std::vector<LocationError> gnssUpdateConfig(const std::string& oldMoServerUrl, +            GnssConfig& gnssConfigRequested, +            GnssConfig& gnssConfigNeedEngineUpdate, size_t count = 0); + +    /* ==== GNSS SV TYPE CONFIG ============================================================ */ +    /* ==== COMMANDS ====(Called from Client Thread)======================================== */ +    /* ==== These commands are received directly from client bypassing Location API ======== */ +    void gnssUpdateSvTypeConfigCommand(GnssSvTypeConfig config); +    void gnssGetSvTypeConfigCommand(GnssSvTypeConfigCallback callback); +    void gnssResetSvTypeConfigCommand(); + +    /* ==== UTILITIES ====================================================================== */ +    LocationError gnssSvIdConfigUpdateSync(const std::vector<GnssSvIdSource>& blacklistedSvIds); +    LocationError gnssSvIdConfigUpdateSync(); +    void gnssSvIdConfigUpdate(const std::vector<GnssSvIdSource>& blacklistedSvIds); +    void gnssSvIdConfigUpdate(); +    void gnssSvTypeConfigUpdate(const GnssSvTypeConfig& config); +    void gnssSvTypeConfigUpdate(bool sendReset = false); +    inline void gnssSetSvTypeConfig(const GnssSvTypeConfig& config) +    { mGnssSvTypeConfig = config; } +    inline void gnssSetSvTypeConfigCallback(GnssSvTypeConfigCallback callback) +    { mGnssSvTypeConfigCb = callback; } +    inline GnssSvTypeConfigCallback gnssGetSvTypeConfigCallback() +    { return mGnssSvTypeConfigCb; } +    void setConfig(); +    void gnssSecondaryBandConfigUpdate(LocApiResponse* locApiResponse= nullptr); + +    /* ========= AGPS ====================================================================== */ +    /* ======== COMMANDS ====(Called from Client Thread)==================================== */ +    void initDefaultAgpsCommand(); +    void initAgpsCommand(const AgpsCbInfo& cbInfo); +    void initNfwCommand(const NfwCbInfo& cbInfo); +    void dataConnOpenCommand(AGpsExtType agpsType, +            const char* apnName, int apnLen, AGpsBearerType bearerType); +    void dataConnClosedCommand(AGpsExtType agpsType); +    void dataConnFailedCommand(AGpsExtType agpsType); +    void getGnssEnergyConsumedCommand(GnssEnergyConsumedCallback energyConsumedCb); +    void nfwControlCommand(bool enable); +    uint32_t setConstrainedTuncCommand (bool enable, float tuncConstraint, +                                        uint32_t energyBudget); +    uint32_t setPositionAssistedClockEstimatorCommand (bool enable); +    uint32_t gnssUpdateSvConfigCommand(const GnssSvTypeConfig& constellationEnablementConfig, +                                       const GnssSvIdConfig& blacklistSvConfig); +    uint32_t gnssUpdateSecondaryBandConfigCommand( +                                       const GnssSvTypeConfig& secondaryBandConfig); +    uint32_t gnssGetSecondaryBandConfigCommand(); +    uint32_t configLeverArmCommand(const LeverArmConfigInfo& configInfo); +    uint32_t configRobustLocationCommand(bool enable, bool enableForE911); +    bool openMeasCorrCommand(const measCorrSetCapabilitiesCb setCapabilitiesCb); +    bool measCorrSetCorrectionsCommand(const GnssMeasurementCorrections gnssMeasCorr); +    inline void closeMeasCorrCommand() { mIsMeasCorrInterfaceOpen = false; } +    uint32_t antennaInfoInitCommand(const antennaInfoCb antennaInfoCallback); +    inline void antennaInfoCloseCommand() { mIsAntennaInfoInterfaceOpened = false; } +    uint32_t configMinGpsWeekCommand(uint16_t minGpsWeek); +    uint32_t configDeadReckoningEngineParamsCommand(const DeadReckoningEngineConfig& dreConfig); +    uint32_t configEngineRunStateCommand(PositioningEngineMask engType, +                                         LocEngineRunState engState); + +    /* ========= ODCPI ===================================================================== */ +    /* ======== COMMANDS ====(Called from Client Thread)==================================== */ +    void initOdcpiCommand(const OdcpiRequestCallback& callback, OdcpiPrioritytype priority); +    void injectOdcpiCommand(const Location& location); +    /* ======== RESPONSES ================================================================== */ +    void reportResponse(LocationError err, uint32_t sessionId); +    void reportResponse(size_t count, LocationError* errs, uint32_t* ids); +    /* ======== UTILITIES ================================================================== */ +    LocationControlCallbacks& getControlCallbacks() { return mControlCallbacks; } +    void setControlCallbacks(const LocationControlCallbacks& controlCallbacks) +    { mControlCallbacks = controlCallbacks; } +    void setAfwControlId(uint32_t id) { mAfwControlId = id; } +    uint32_t getAfwControlId() { return mAfwControlId; } +    virtual bool isInSession() { return !mTimeBasedTrackingSessions.empty(); } +    void initDefaultAgps(); +    bool initEngHubProxy(); +    void initCDFWService(); +    void odcpiTimerExpireEvent(); + +    /* ==== REPORTS ======================================================================== */ +    /* ======== EVENTS ====(Called from QMI/EngineHub Thread)===================================== */ +    virtual void reportPositionEvent(const UlpLocation& ulpLocation, +                                     const GpsLocationExtended& locationExtended, +                                     enum loc_sess_status status, +                                     LocPosTechMask techMask, +                                     GnssDataNotification* pDataNotify = nullptr, +                                     int msInWeek = -1); +    virtual void reportEnginePositionsEvent(unsigned int count, +                                            EngineLocationInfo* locationArr); + +    virtual void reportSvEvent(const GnssSvNotification& svNotify, +                               bool fromEngineHub=false); +    virtual void reportNmeaEvent(const char* nmea, size_t length); +    virtual void reportDataEvent(const GnssDataNotification& dataNotify, int msInWeek); +    virtual bool requestNiNotifyEvent(const GnssNiNotification& notify, const void* data, +                                      const LocInEmergency emergencyState); +    virtual void reportGnssMeasurementsEvent(const GnssMeasurements& gnssMeasurements, +                                                int msInWeek); +    virtual void reportSvPolynomialEvent(GnssSvPolynomial &svPolynomial); +    virtual void reportSvEphemerisEvent(GnssSvEphemerisReport & svEphemeris); +    virtual void reportGnssSvIdConfigEvent(const GnssSvIdConfig& config); +    virtual void reportGnssSvTypeConfigEvent(const GnssSvTypeConfig& config); +    virtual void reportGnssConfigEvent(uint32_t sessionId, const GnssConfig& gnssConfig); +    virtual bool reportGnssEngEnergyConsumedEvent(uint64_t energyConsumedSinceFirstBoot); +    virtual void reportLocationSystemInfoEvent(const LocationSystemInfo& locationSystemInfo); + +    virtual bool requestATL(int connHandle, LocAGpsType agps_type, LocApnTypeMask apn_type_mask); +    virtual bool releaseATL(int connHandle); +    virtual bool requestOdcpiEvent(OdcpiRequestInfo& request); +    virtual bool reportDeleteAidingDataEvent(GnssAidingData& aidingData); +    virtual bool reportKlobucharIonoModelEvent(GnssKlobucharIonoModel& ionoModel); +    virtual bool reportGnssAdditionalSystemInfoEvent( +            GnssAdditionalSystemInfo& additionalSystemInfo); +    virtual void reportNfwNotificationEvent(GnssNfwNotification& notification); +    virtual void reportLatencyInfoEvent(const GnssLatencyInfo& gnssLatencyInfo); +    virtual bool reportQwesCapabilities +    ( +        const std::unordered_map<LocationQwesFeatureType, bool> &featureMap +    ); + +    /* ======== UTILITIES ================================================================= */ +    bool needReportForGnssClient(const UlpLocation& ulpLocation, +            enum loc_sess_status status, LocPosTechMask techMask); +    bool needReportForFlpClient(enum loc_sess_status status, LocPosTechMask techMask); +    bool needToGenerateNmeaReport(const uint32_t &gpsTimeOfWeekMs, +        const struct timespec32_t &apTimeStamp); +    void reportPosition(const UlpLocation &ulpLocation, +                        const GpsLocationExtended &locationExtended, +                        enum loc_sess_status status, +                        LocPosTechMask techMask); +    void reportEnginePositions(unsigned int count, +                               const EngineLocationInfo* locationArr); +    void reportSv(GnssSvNotification& svNotify); +    void reportNmea(const char* nmea, size_t length); +    void reportData(GnssDataNotification& dataNotify); +    bool requestNiNotify(const GnssNiNotification& notify, const void* data, +                         const bool bInformNiAccept); +    void reportGnssMeasurementData(const GnssMeasurementsNotification& measurements); +    void reportGnssSvIdConfig(const GnssSvIdConfig& config); +    void reportGnssSvTypeConfig(const GnssSvTypeConfig& config); +    void reportGnssConfig(uint32_t sessionId, const GnssConfig& gnssConfig); +    void requestOdcpi(const OdcpiRequestInfo& request); +    void invokeGnssEnergyConsumedCallback(uint64_t energyConsumedSinceFirstBoot); +    void saveGnssEnergyConsumedCallback(GnssEnergyConsumedCallback energyConsumedCb); +    void reportLocationSystemInfo(const LocationSystemInfo & locationSystemInfo); +    inline void reportNfwNotification(const GnssNfwNotification& notification) { +        if (NULL != mNfwCb) { +            mNfwCb(notification); +        } +    } +    inline bool getE911State(void) { +        if (NULL != mIsE911Session) { +            return mIsE911Session(); +        } +        return false; +    } + +    void updateSystemPowerState(PowerStateType systemPowerState); +    void reportSvPolynomial(const GnssSvPolynomial &svPolynomial); + + +    std::vector<double> parseDoublesString(char* dString); +    void reportGnssAntennaInformation(const antennaInfoCb antennaInfoCallback); + +    /*======== GNSSDEBUG ================================================================*/ +    bool getDebugReport(GnssDebugReport& report); +    /* get AGC information from system status and fill it */ +    void getAgcInformation(GnssMeasurementsNotification& measurements, int msInWeek); +    /* get Data information from system status and fill it */ +    void getDataInformation(GnssDataNotification& data, int msInWeek); + +    /*==== SYSTEM STATUS ================================================================*/ +    inline SystemStatus* getSystemStatus(void) { return mSystemStatus; } +    std::string& getServerUrl(void) { return mServerUrl; } +    std::string& getMoServerUrl(void) { return mMoServerUrl; } + +    /*==== CONVERSION ===================================================================*/ +    static uint32_t convertSuplVersion(const GnssConfigSuplVersion suplVersion); +    static uint32_t convertEP4ES(const GnssConfigEmergencyPdnForEmergencySupl); +    static uint32_t convertSuplEs(const GnssConfigSuplEmergencyServices suplEmergencyServices); +    static uint32_t convertLppeCp(const GnssConfigLppeControlPlaneMask lppeControlPlaneMask); +    static uint32_t convertLppeUp(const GnssConfigLppeUserPlaneMask lppeUserPlaneMask); +    static uint32_t convertAGloProt(const GnssConfigAGlonassPositionProtocolMask); +    static uint32_t convertSuplMode(const GnssConfigSuplModeMask suplModeMask); +    static void convertSatelliteInfo(std::vector<GnssDebugSatelliteInfo>& out, +                                     const GnssSvType& in_constellation, +                                     const SystemStatusReports& in); +    static bool convertToGnssSvIdConfig( +            const std::vector<GnssSvIdSource>& blacklistedSvIds, GnssSvIdConfig& config); +    static void convertFromGnssSvIdConfig( +            const GnssSvIdConfig& svConfig, std::vector<GnssSvIdSource>& blacklistedSvIds); +    static void convertGnssSvIdMaskToList( +            uint64_t svIdMask, std::vector<GnssSvIdSource>& svIds, +            GnssSvId initialSvId, GnssSvType svType); +    static void computeVRPBasedLla(const UlpLocation& loc, GpsLocationExtended& locExt, +                                   const LeverArmConfigInfo& leverArmConfigInfo); + +    void injectLocationCommand(double latitude, double longitude, float accuracy); +    void injectLocationExtCommand(const GnssLocationInfoNotification &locationInfo); + +    void injectTimeCommand(int64_t time, int64_t timeReference, int32_t uncertainty); +    void blockCPICommand(double latitude, double longitude, float accuracy, +                         int blockDurationMsec, double latLonDiffThreshold); + +    /* ==== MISCELLANEOUS ================================================================== */ +    /* ======== COMMANDS ====(Called from Client Thread)==================================== */ +    void getPowerStateChangesCommand(std::function<void(bool)> powerStateCb); +    /* ======== UTILITIES ================================================================== */ +    void reportPowerStateIfChanged(); +    void savePowerStateCallback(std::function<void(bool)> powerStateCb){ +            mPowerStateCb = powerStateCb; } +    bool getPowerState() { return mPowerOn; } +    inline PowerStateType getSystemPowerState() { return mSystemPowerState; } + +    void setAllowFlpNetworkFixes(uint32_t allow) { mAllowFlpNetworkFixes = allow; } +    uint32_t getAllowFlpNetworkFixes() { return mAllowFlpNetworkFixes; } +    void setSuplHostServer(const char* server, int port, LocServerType type); +    void notifyClientOfCachedLocationSystemInfo(LocationAPI* client, +                                                const LocationCallbacks& callbacks); +    LocationCapabilitiesMask getCapabilities(); +    void updateSystemPowerStateCommand(PowerStateType systemPowerState); + +    /*==== DGnss Usable Report Flag ====================================================*/ +    inline void setDGnssUsableFLag(bool dGnssNeedReport) { mDGnssNeedReport = dGnssNeedReport;} +    inline bool isNMEAPrintEnabled() { +       return ((mContext != NULL) && (0 != mContext->mGps_conf.ENABLE_NMEA_PRINT)); +    } + +    /*==== DGnss Ntrip Source ==========================================================*/ +    void updateNTRIPGGAConsentCommand(bool consentAccepted) { mSendNmeaConsent = consentAccepted; } +    void enablePPENtripStreamCommand(const GnssNtripConnectionParams& params, bool enableRTKEngine); +    void disablePPENtripStreamCommand(); +    void handleEnablePPENtrip(const GnssNtripConnectionParams& params); +    void handleDisablePPENtrip(); +    void reportGGAToNtrip(const char* nmea); +    inline bool isDgnssNmeaRequired() { return mSendNmeaConsent && +            mStartDgnssNtripParams.ntripParams.requiresNmeaLocation;} +}; + +#endif //GNSS_ADAPTER_H diff --git a/gps/gnss/Makefile.am b/gps/gnss/Makefile.am new file mode 100644 index 0000000..dd313a1 --- /dev/null +++ b/gps/gnss/Makefile.am @@ -0,0 +1,32 @@ +AM_CFLAGS = \ +     $(LOCPLA_CFLAGS) \ +     $(LOCHAL_CFLAGS) \ +     $(GPSUTILS_CFLAGS) \ +     $(LOCCORE_CFLAGS) \ +     -I./ \ +     -I../utils \ +     -I$(WORKSPACE)/hardware/qcom/gps/core/data-items \ +     -I../location \ +     -std=c++1y + +libgnss_la_SOURCES = \ +    location_gnss.cpp \ +    GnssAdapter.cpp \ +    XtraSystemStatusObserver.cpp \ +    Agps.cpp \ +    NativeAgpsHandler.cpp + +if USE_GLIB +libgnss_la_CFLAGS = -DUSE_GLIB $(AM_CFLAGS) @GLIB_CFLAGS@ +libgnss_la_LDFLAGS = -lstdc++ -Wl,-z,defs -lpthread @GLIB_LIBS@ -shared -avoid-version +libgnss_la_CPPFLAGS = -DUSE_GLIB $(AM_CFLAGS) $(AM_CPPFLAGS) @GLIB_CFLAGS@ +else +libgnss_la_CFLAGS = $(AM_CFLAGS) +libgnss_la_LDFLAGS = -Wl,-z,defs -lpthread -shared -version-info 1:0:0 +libgnss_la_CPPFLAGS = $(AM_CFLAGS) $(AM_CPPFLAGS) +endif + +libgnss_la_LIBADD = -lstdc++ -ldl $(GPSUTILS_LIBS) $(LOCCORE_LIBS) + +#Create and Install libraries +lib_LTLIBRARIES = libgnss.la diff --git a/gps/gnss/NativeAgpsHandler.cpp b/gps/gnss/NativeAgpsHandler.cpp new file mode 100644 index 0000000..ce4c03a --- /dev/null +++ b/gps/gnss/NativeAgpsHandler.cpp @@ -0,0 +1,127 @@ +/* Copyright (c) 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_TAG "LocSvc_NativeAgpsHandler" + +#include <LocAdapterBase.h> +#include <SystemStatus.h> +#include <DataItemId.h> +#include <DataItemsFactoryProxy.h> +#include <DataItemConcreteTypesBase.h> +#include <loc_log.h> +#include <NativeAgpsHandler.h> +#include <GnssAdapter.h> + +using namespace loc_core; + +// IDataItemObserver overrides +void NativeAgpsHandler::getName(string& name) { +    name = "NativeAgpsHandler"; +} + +void NativeAgpsHandler::notify(const list<IDataItemCore*>& dlist) { +    for (auto each : dlist) { +        switch (each->getId()) { +            case NETWORKINFO_DATA_ITEM_ID: { +                    NetworkInfoDataItemBase* networkInfo = +                        static_cast<NetworkInfoDataItemBase*>(each); +                    uint64_t mobileBit = (uint64_t )1 << loc_core::TYPE_MOBILE; +                    uint64_t allTypes = networkInfo->mAllTypes; +                    mConnected = ((networkInfo->mAllTypes & mobileBit) == mobileBit); +                    /** +                     * mApn Telephony preferred Access Point Name to use for +                     * carrier data connection when connected to a cellular network. +                     * Empty string, otherwise. +                     */ +                    mApn = networkInfo->mApn; +                    LOC_LOGd("updated mConnected:%d, mApn: %s", mConnected, mApn.c_str()); +                    break; +            } +            default: +                    break; +        } +    } +} + +NativeAgpsHandler* NativeAgpsHandler::sLocalHandle = nullptr; +NativeAgpsHandler::NativeAgpsHandler(IOsObserver* sysStatObs, GnssAdapter& adapter) : +        mSystemStatusObsrvr(sysStatObs), mConnected(false), mAdapter(adapter) { +    sLocalHandle = this; +    list<DataItemId> subItemIdList = {NETWORKINFO_DATA_ITEM_ID}; +    mSystemStatusObsrvr->subscribe(subItemIdList, this); +} + +NativeAgpsHandler::~NativeAgpsHandler() { +    if (nullptr != mSystemStatusObsrvr) { +        LOC_LOGd("Unsubscribe for network info."); +        list<DataItemId> subItemIdList = {NETWORKINFO_DATA_ITEM_ID}; +        mSystemStatusObsrvr->unsubscribe(subItemIdList, this); +    } +    sLocalHandle = nullptr; +    mSystemStatusObsrvr = nullptr; +} + + +AgpsCbInfo NativeAgpsHandler::getAgpsCbInfo() { +    AgpsCbInfo nativeCbInfo = {}; +    nativeCbInfo.statusV4Cb = (void*)agnssStatusIpV4Cb; +    nativeCbInfo.atlType = AGPS_ATL_TYPE_WWAN; +    return nativeCbInfo; +} + +void NativeAgpsHandler::agnssStatusIpV4Cb(AGnssExtStatusIpV4 statusInfo) { +    if (nullptr != sLocalHandle) { +        sLocalHandle->processATLRequestRelease(statusInfo); +    } else { +        LOC_LOGe("sLocalHandle is null"); +    } +} + +void NativeAgpsHandler::processATLRequestRelease(AGnssExtStatusIpV4 statusInfo) { +    if (LOC_AGPS_TYPE_WWAN_ANY == statusInfo.type) { +        LOC_LOGd("status.type = %d status.apnTypeMask = 0x%X", statusInfo.type, +                 statusInfo.apnTypeMask); +        switch (statusInfo.status) { +        case LOC_GPS_REQUEST_AGPS_DATA_CONN: +            if (mConnected) { +                mAdapter.dataConnOpenCommand(LOC_AGPS_TYPE_WWAN_ANY, mApn.c_str(), mApn.size(), +                    AGPS_APN_BEARER_IPV4); +            } else { +                mAdapter.dataConnFailedCommand(LOC_AGPS_TYPE_WWAN_ANY); +            } +            break; +        case LOC_GPS_RELEASE_AGPS_DATA_CONN: +            mAdapter.dataConnClosedCommand(LOC_AGPS_TYPE_WWAN_ANY); +            break; +        default: +            LOC_LOGe("Invalid Request: %d", statusInfo.status); +        } +    } else { +        LOC_LOGe("mAgpsManger is null or invalid request type!"); +    } +} diff --git a/gps/gnss/NativeAgpsHandler.h b/gps/gnss/NativeAgpsHandler.h new file mode 100644 index 0000000..fb0b46c --- /dev/null +++ b/gps/gnss/NativeAgpsHandler.h @@ -0,0 +1,64 @@ +/* Copyright (c) 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. + * + */ +#ifndef NATIVEAGPSHANDLER_H +#define NATIVEAGPSHANDLER_H + +#include <cinttypes> +#include <string.h> +#include <gps_extended_c.h> +#include <IDataItemObserver.h> +#include <IDataItemCore.h> +#include <IOsObserver.h> + +using namespace std; +using loc_core::IOsObserver; +using loc_core::IDataItemObserver; +using loc_core::IDataItemCore; + +class GnssAdapter; + +class NativeAgpsHandler : public IDataItemObserver { +public: +    NativeAgpsHandler(IOsObserver* sysStatObs, GnssAdapter& adapter); +    ~NativeAgpsHandler(); +    AgpsCbInfo getAgpsCbInfo(); +    // IDataItemObserver overrides +    virtual void notify(const list<IDataItemCore*>& dlist); +    inline virtual void getName(string& name); +private: +    static NativeAgpsHandler* sLocalHandle; +    static void agnssStatusIpV4Cb(AGnssExtStatusIpV4 statusInfo); +    void processATLRequestRelease(AGnssExtStatusIpV4 statusInfo); +    IOsObserver* mSystemStatusObsrvr; +    bool mConnected; +    string mApn; +    GnssAdapter& mAdapter; +}; + +#endif // NATIVEAGPSHANDLER_H diff --git a/gps/gnss/XtraSystemStatusObserver.cpp b/gps/gnss/XtraSystemStatusObserver.cpp new file mode 100644 index 0000000..d65622f --- /dev/null +++ b/gps/gnss/XtraSystemStatusObserver.cpp @@ -0,0 +1,384 @@ +/* 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_TAG "LocSvc_XtraSystemStatusObs" + +#include <sys/stat.h> +#include <sys/un.h> +#include <errno.h> +#include <ctype.h> +#include <cutils/properties.h> +#include <math.h> +#include <arpa/inet.h> +#include <netinet/in.h> +#include <netdb.h> +#include <string> +#include <loc_log.h> +#include <loc_nmea.h> +#include <SystemStatus.h> +#include <vector> +#include <sstream> +#include <XtraSystemStatusObserver.h> +#include <LocAdapterBase.h> +#include <DataItemId.h> +#include <DataItemsFactoryProxy.h> +#include <DataItemConcreteTypesBase.h> + +using namespace loc_util; +using namespace loc_core; + +#ifdef LOG_TAG +#undef LOG_TAG +#endif +#define LOG_TAG "LocSvc_XSSO" + +class XtraIpcListener : public ILocIpcListener { +    IOsObserver*    mSystemStatusObsrvr; +    const MsgTask* mMsgTask; +    XtraSystemStatusObserver& mXSSO; +public: +    inline XtraIpcListener(IOsObserver* observer, const MsgTask* msgTask, +                           XtraSystemStatusObserver& xsso) : +            mSystemStatusObsrvr(observer), mMsgTask(msgTask), mXSSO(xsso) {} +    virtual void onReceive(const char* data, uint32_t length, +                           const LocIpcRecver* recver) override { +#define STRNCMP(str, constStr) strncmp(str, constStr, sizeof(constStr)-1) +        if (!STRNCMP(data, "ping")) { +            LOC_LOGd("ping received"); +#ifdef USE_GLIB +        } else if (!STRNCMP(data, "connectBackhaul")) { +            char clientName[30] = {0}; +            sscanf(data, "%*s %29s", clientName); +            mSystemStatusObsrvr->connectBackhaul(string(clientName)); +        } else if (!STRNCMP(data, "disconnectBackhaul")) { +            char clientName[30] = {0}; +            sscanf(data, "%*s %29s", clientName); +            mSystemStatusObsrvr->disconnectBackhaul(string(clientName)); +#endif +        } else if (!STRNCMP(data, "requestStatus")) { +            int32_t xtraStatusUpdated = 0; +            sscanf(data, "%*s %d", &xtraStatusUpdated); + +            struct HandleStatusRequestMsg : public LocMsg { +                XtraSystemStatusObserver& mXSSO; +                int32_t mXtraStatusUpdated; +                inline HandleStatusRequestMsg(XtraSystemStatusObserver& xsso, +                                              int32_t xtraStatusUpdated) : +                        mXSSO(xsso), mXtraStatusUpdated(xtraStatusUpdated) {} +                inline void proc() const override { +                    mXSSO.onStatusRequested(mXtraStatusUpdated); +                    /* SSR for DGnss Ntrip Source*/ +                    mXSSO.restartDgnssSource(); +                } +            }; +            mMsgTask->sendMsg(new HandleStatusRequestMsg(mXSSO, xtraStatusUpdated)); +        } else { +            LOC_LOGw("unknown event: %s", data); +        } +    } +}; + +XtraSystemStatusObserver::XtraSystemStatusObserver(IOsObserver* sysStatObs, +                                                   const MsgTask* msgTask) : +        mSystemStatusObsrvr(sysStatObs), mMsgTask(msgTask), +        mGpsLock(-1), mConnections(~0), mXtraThrottle(true), +        mReqStatusReceived(false), +        mIsConnectivityStatusKnown(false), +        mSender(LocIpc::getLocIpcLocalSender(LOC_IPC_XTRA)), +        mDelayLocTimer(*mSender) { +    subscribe(true); +    auto recver = LocIpc::getLocIpcLocalRecver( +            make_shared<XtraIpcListener>(sysStatObs, msgTask, *this), +            LOC_IPC_HAL); +    mIpc.startNonBlockingListening(recver); +    mDelayLocTimer.start(100 /*.1 sec*/,  false); +} + +bool XtraSystemStatusObserver::updateLockStatus(GnssConfigGpsLock lock) { +    // mask NI(NFW bit) since from XTRA's standpoint GPS is enabled if +    // MO(AFW bit) is enabled and disabled when MO is disabled +    mGpsLock = lock & ~GNSS_CONFIG_GPS_LOCK_NI; + +    if (!mReqStatusReceived) { +        return true; +    } + +    stringstream ss; +    ss <<  "gpslock"; +    ss << " " << mGpsLock; +    string s = ss.str(); +    return ( LocIpc::send(*mSender, (const uint8_t*)s.data(), s.size()) ); +} + +bool XtraSystemStatusObserver::updateConnections(uint64_t allConnections, +        NetworkInfoType* networkHandleInfo) { +    mIsConnectivityStatusKnown = true; +    mConnections = allConnections; + +    LOC_LOGd("updateConnections mConnections:%" PRIx64, mConnections); +    for (uint8_t i = 0; i < MAX_NETWORK_HANDLES; ++i) { +        mNetworkHandle[i] = networkHandleInfo[i]; +        LOC_LOGd("updateConnections [%d] networkHandle:%" PRIx64 " networkType:%u", +            i, mNetworkHandle[i].networkHandle, mNetworkHandle[i].networkType); +    } + +    if (!mReqStatusReceived) { +        return true; +    } + +    stringstream ss; +    ss << "connection" << endl << mConnections << endl +            << mNetworkHandle[0].toString() << endl +            << mNetworkHandle[1].toString() << endl +            << mNetworkHandle[2].toString() << endl +            << mNetworkHandle[3].toString() << endl +            << mNetworkHandle[4].toString() << endl +            << mNetworkHandle[5].toString() << endl +            << mNetworkHandle[6].toString() << endl +            << mNetworkHandle[7].toString() << endl +            << mNetworkHandle[8].toString() << endl +            << mNetworkHandle[MAX_NETWORK_HANDLES-1].toString(); +    string s = ss.str(); +    return ( LocIpc::send(*mSender, (const uint8_t*)s.data(), s.size()) ); +} + +bool XtraSystemStatusObserver::updateTac(const string& tac) { +    mTac = tac; + +    if (!mReqStatusReceived) { +        return true; +    } + +    stringstream ss; +    ss <<  "tac"; +    ss << " " << tac.c_str(); +    string s = ss.str(); +    return ( LocIpc::send(*mSender, (const uint8_t*)s.data(), s.size()) ); +} + +bool XtraSystemStatusObserver::updateMccMnc(const string& mccmnc) { +    mMccmnc = mccmnc; + +    if (!mReqStatusReceived) { +        return true; +    } + +    stringstream ss; +    ss <<  "mncmcc"; +    ss << " " << mccmnc.c_str(); +    string s = ss.str(); +    return ( LocIpc::send(*mSender, (const uint8_t*)s.data(), s.size()) ); +} + +bool XtraSystemStatusObserver::updateXtraThrottle(const bool enabled) { +    mXtraThrottle = enabled; + +    if (!mReqStatusReceived) { +        return true; +    } + +    stringstream ss; +    ss <<  "xtrathrottle"; +    ss << " " << (enabled ? 1 : 0); +    string s = ss.str(); +    return ( LocIpc::send(*mSender, (const uint8_t*)s.data(), s.size()) ); +} + +inline bool XtraSystemStatusObserver::onStatusRequested(int32_t xtraStatusUpdated) { +    mReqStatusReceived = true; + +    if (xtraStatusUpdated) { +        return true; +    } + +    stringstream ss; + +    ss << "respondStatus" << endl; +    (mGpsLock == -1 ? ss : ss << mGpsLock) << endl; +    (mConnections == (uint64_t)~0 ? ss : ss << mConnections) << endl +            << mNetworkHandle[0].toString() << endl +            << mNetworkHandle[1].toString() << endl +            << mNetworkHandle[2].toString() << endl +            << mNetworkHandle[3].toString() << endl +            << mNetworkHandle[4].toString() << endl +            << mNetworkHandle[5].toString() << endl +            << mNetworkHandle[6].toString() << endl +            << mNetworkHandle[7].toString() << endl +            << mNetworkHandle[8].toString() << endl +            << mNetworkHandle[MAX_NETWORK_HANDLES-1].toString() << endl +            << mTac << endl << mMccmnc << endl << mIsConnectivityStatusKnown; + +    string s = ss.str(); +    return ( LocIpc::send(*mSender, (const uint8_t*)s.data(), s.size()) ); +} + +void XtraSystemStatusObserver::startDgnssSource(const StartDgnssNtripParams& params) { +    stringstream ss; +    const GnssNtripConnectionParams* ntripParams = &(params.ntripParams); + +    ss <<  "startDgnssSource" << endl; +    ss << ntripParams->useSSL << endl; +    ss << ntripParams->hostNameOrIp.data() << endl; +    ss << ntripParams->port << endl; +    ss << ntripParams->mountPoint.data() << endl; +    ss << ntripParams->username.data() << endl; +    ss << ntripParams->password.data() << endl; +    if (ntripParams->requiresNmeaLocation && !params.nmea.empty()) { +        ss << params.nmea.data() << endl; +    } +    string s = ss.str(); + +    LOC_LOGd("%s", s.data()); +    LocIpc::send(*mSender, (const uint8_t*)s.data(), s.size()); +    // make a local copy of the string for SSR +    mNtripParamsString.assign(std::move(s)); +} + +void XtraSystemStatusObserver::restartDgnssSource() { +    if (!mNtripParamsString.empty()) { +        LocIpc::send(*mSender, +            (const uint8_t*)mNtripParamsString.data(), mNtripParamsString.size()); +        LOC_LOGv("Xtra SSR %s", mNtripParamsString.data()); +    } +} + +void XtraSystemStatusObserver::stopDgnssSource() { +    LOC_LOGv(); +    mNtripParamsString.clear(); + +    const char s[] = "stopDgnssSource"; +    LocIpc::send(*mSender, (const uint8_t*)s, strlen(s)); +} + +void XtraSystemStatusObserver::updateNmeaToDgnssServer(const string& nmea) +{ +    stringstream ss; +    ss <<  "updateDgnssServerNmea" << endl; +    ss << nmea.data() << endl; + +    string s = ss.str(); +    LOC_LOGd("%s", s.data()); +    LocIpc::send(*mSender, (const uint8_t*)s.data(), s.size()); +} + +void XtraSystemStatusObserver::subscribe(bool yes) +{ +    // Subscription data list +    list<DataItemId> subItemIdList; +    subItemIdList.push_back(NETWORKINFO_DATA_ITEM_ID); +    subItemIdList.push_back(MCCMNC_DATA_ITEM_ID); + +    if (yes) { +        mSystemStatusObsrvr->subscribe(subItemIdList, this); + +        list<DataItemId> reqItemIdList; +        reqItemIdList.push_back(TAC_DATA_ITEM_ID); + +        mSystemStatusObsrvr->requestData(reqItemIdList, this); + +    } else { +        mSystemStatusObsrvr->unsubscribe(subItemIdList, this); +    } +} + +// IDataItemObserver overrides +void XtraSystemStatusObserver::getName(string& name) +{ +    name = "XtraSystemStatusObserver"; +} + +void XtraSystemStatusObserver::notify(const list<IDataItemCore*>& dlist) +{ +    struct HandleOsObserverUpdateMsg : public LocMsg { +        XtraSystemStatusObserver* mXtraSysStatObj; +        list <IDataItemCore*> mDataItemList; + +        inline HandleOsObserverUpdateMsg(XtraSystemStatusObserver* xtraSysStatObs, +                const list<IDataItemCore*>& dataItemList) : +                mXtraSysStatObj(xtraSysStatObs) { +            for (auto eachItem : dataItemList) { +                IDataItemCore* dataitem = DataItemsFactoryProxy::createNewDataItem( +                        eachItem->getId()); +                if (NULL == dataitem) { +                    break; +                } +                // Copy the contents of the data item +                dataitem->copy(eachItem); + +                mDataItemList.push_back(dataitem); +            } +        } + +        inline ~HandleOsObserverUpdateMsg() { +            for (auto itor = mDataItemList.begin(); itor != mDataItemList.end(); ++itor) { +                if (*itor != nullptr) { +                    delete *itor; +                    *itor = nullptr; +                } +            } +        } + +        inline void proc() const { +            for (auto each : mDataItemList) { +                switch (each->getId()) +                { +                    case NETWORKINFO_DATA_ITEM_ID: +                    { +                        NetworkInfoDataItemBase* networkInfo = +                                static_cast<NetworkInfoDataItemBase*>(each); +                        NetworkInfoType* networkHandleInfo = +                                static_cast<NetworkInfoType*>(networkInfo->getNetworkHandle()); +                        mXtraSysStatObj->updateConnections(networkInfo->getAllTypes(), +                                networkHandleInfo); +                    } +                    break; + +                    case TAC_DATA_ITEM_ID: +                    { +                        TacDataItemBase* tac = +                                 static_cast<TacDataItemBase*>(each); +                        mXtraSysStatObj->updateTac(tac->mValue); +                    } +                    break; + +                    case MCCMNC_DATA_ITEM_ID: +                    { +                        MccmncDataItemBase* mccmnc = +                                static_cast<MccmncDataItemBase*>(each); +                        mXtraSysStatObj->updateMccMnc(mccmnc->mValue); +                    } +                    break; + +                    default: +                    break; +                } +            } +        } +    }; +    mMsgTask->sendMsg(new (nothrow) HandleOsObserverUpdateMsg(this, dlist)); +} diff --git a/gps/gnss/XtraSystemStatusObserver.h b/gps/gnss/XtraSystemStatusObserver.h new file mode 100644 index 0000000..56a3a9c --- /dev/null +++ b/gps/gnss/XtraSystemStatusObserver.h @@ -0,0 +1,112 @@ +/* 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. + * + */ +#ifndef XTRA_SYSTEM_STATUS_OBS_H +#define XTRA_SYSTEM_STATUS_OBS_H + +#include <cinttypes> +#include <MsgTask.h> +#include <LocIpc.h> +#include <LocTimer.h> +#include <stdlib.h> + +using namespace std; +using namespace loc_util; +using loc_core::IOsObserver; +using loc_core::IDataItemObserver; +using loc_core::IDataItemCore; + +struct StartDgnssNtripParams { +    GnssNtripConnectionParams ntripParams; +    string                    nmea; + +    void clear() { +        ntripParams.hostNameOrIp.clear(); +        ntripParams.mountPoint.clear(); +        ntripParams.username.clear(); +        ntripParams.password.clear(); +        ntripParams.port = 0; +        ntripParams.useSSL = false; +        ntripParams.requiresNmeaLocation = false; +        nmea.clear(); +    } +}; + +class XtraSystemStatusObserver : public IDataItemObserver { +public : +    // constructor & destructor +    XtraSystemStatusObserver(IOsObserver* sysStatObs, const MsgTask* msgTask); +    inline virtual ~XtraSystemStatusObserver() { +        subscribe(false); +        mIpc.stopNonBlockingListening(); +    } + +    // IDataItemObserver overrides +    inline virtual void getName(string& name); +    virtual void notify(const list<IDataItemCore*>& dlist); + +    bool updateLockStatus(GnssConfigGpsLock lock); +    bool updateConnections(uint64_t allConnections, +            loc_core::NetworkInfoType* networkHandleInfo); +    bool updateTac(const string& tac); +    bool updateMccMnc(const string& mccmnc); +    bool updateXtraThrottle(const bool enabled); +    inline const MsgTask* getMsgTask() { return mMsgTask; } +    void subscribe(bool yes); +    bool onStatusRequested(int32_t xtraStatusUpdated); +    void startDgnssSource(const StartDgnssNtripParams& params); +    void restartDgnssSource(); +    void stopDgnssSource(); +    void updateNmeaToDgnssServer(const string& nmea); + +private: +    IOsObserver*    mSystemStatusObsrvr; +    const MsgTask* mMsgTask; +    GnssConfigGpsLock mGpsLock; +    LocIpc mIpc; +    uint64_t mConnections; +    loc_core::NetworkInfoType mNetworkHandle[MAX_NETWORK_HANDLES]; +    string mTac; +    string mMccmnc; +    bool mXtraThrottle; +    bool mReqStatusReceived; +    bool mIsConnectivityStatusKnown; +    shared_ptr<LocIpcSender> mSender; +    string mNtripParamsString; + +    class DelayLocTimer : public LocTimer { +        LocIpcSender& mSender; +    public: +        DelayLocTimer(LocIpcSender& sender) : mSender(sender) {} +        void timeOutCallback() override { +            LocIpc::send(mSender, (const uint8_t*)"halinit", sizeof("halinit")); +        } +    } mDelayLocTimer; +}; + +#endif diff --git a/gps/gnss/location_gnss.cpp b/gps/gnss/location_gnss.cpp new file mode 100644 index 0000000..0454a13 --- /dev/null +++ b/gps/gnss/location_gnss.cpp @@ -0,0 +1,593 @@ +/* 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. + * + */ + +#include "GnssAdapter.h" +#include "location_interface.h" + +static GnssAdapter* gGnssAdapter = NULL; + +static void initialize(); +static void deinitialize(); + +static void addClient(LocationAPI* client, const LocationCallbacks& callbacks); +static void removeClient(LocationAPI* client, removeClientCompleteCallback rmClientCb); +static void requestCapabilities(LocationAPI* client); + +static uint32_t startTracking(LocationAPI* client, TrackingOptions&); +static void updateTrackingOptions(LocationAPI* client, uint32_t id, TrackingOptions&); +static void stopTracking(LocationAPI* client, uint32_t id); + +static void gnssNiResponse(LocationAPI* client, uint32_t id, GnssNiResponse response); +static uint32_t gnssDeleteAidingData(GnssAidingData& data); +static void gnssUpdateXtraThrottle(const bool enabled); + +static void setControlCallbacks(LocationControlCallbacks& controlCallbacks); +static uint32_t enable(LocationTechnologyType techType); +static void disable(uint32_t id); +static uint32_t* gnssUpdateConfig(const GnssConfig& config); +static uint32_t* gnssGetConfig(GnssConfigFlagsMask mask); + +static void gnssUpdateSvTypeConfig(GnssSvTypeConfig& config); +static void gnssGetSvTypeConfig(GnssSvTypeConfigCallback& callback); +static void gnssResetSvTypeConfig(); + +static void injectLocation(double latitude, double longitude, float accuracy); +static void injectLocationExt(const GnssLocationInfoNotification &locationInfo); +static void injectTime(int64_t time, int64_t timeReference, int32_t uncertainty); + +static void agpsInit(const AgpsCbInfo& cbInfo); +static void agpsDataConnOpen(AGpsExtType agpsType, const char* apnName, int apnLen, int ipType); +static void agpsDataConnClosed(AGpsExtType agpsType); +static void agpsDataConnFailed(AGpsExtType agpsType); +static void getDebugReport(GnssDebugReport& report); +static void updateConnectionStatus(bool connected, int8_t type, bool roaming, +                                   NetworkHandle networkHandle, string& apn); +static void getGnssEnergyConsumed(GnssEnergyConsumedCallback energyConsumedCb); +static void enableNfwLocationAccess(bool enable); +static void nfwInit(const NfwCbInfo& cbInfo); +static void getPowerStateChanges(std::function<void(bool)> powerStateCb); + +static void odcpiInit(const OdcpiRequestCallback& callback, OdcpiPrioritytype priority); +static void odcpiInject(const Location& location); + +static void blockCPI(double latitude, double longitude, float accuracy, +                     int blockDurationMsec, double latLonDiffThreshold); +static void updateBatteryStatus(bool charging); +static void updateSystemPowerState(PowerStateType systemPowerState); +static uint32_t setConstrainedTunc (bool enable, float tuncConstraint, +                                    uint32_t energyBudget); +static uint32_t setPositionAssistedClockEstimator(bool enable); +static uint32_t gnssUpdateSvConfig(const GnssSvTypeConfig& constellationEnablementConfig, +                                   const GnssSvIdConfig& blacklistSvConfig); +static uint32_t gnssResetSvConfig(); +static uint32_t configLeverArm(const LeverArmConfigInfo& configInfo); +static uint32_t configRobustLocation(bool enable, bool enableForE911); +static uint32_t configMinGpsWeek(uint16_t minGpsWeek); +static uint32_t configDeadReckoningEngineParams(const DeadReckoningEngineConfig& dreConfig); +static uint32_t gnssUpdateSecondaryBandConfig(const GnssSvTypeConfig& secondaryBandConfig); +static uint32_t gnssGetSecondaryBandConfig(); +static void resetNetworkInfo(); + +static void updateNTRIPGGAConsent(bool consentAccepted); +static void enablePPENtripStream(const GnssNtripConnectionParams& params, bool enableRTKEngine); +static void disablePPENtripStream(); + +static bool measCorrInit(const measCorrSetCapabilitiesCb setCapabilitiesCb); +static bool measCorrSetCorrections(const GnssMeasurementCorrections gnssMeasCorr); +static void measCorrClose(); +static uint32_t antennaInfoInit(const antennaInfoCb antennaInfoCallback); +static void antennaInfoClose(); +static uint32_t configEngineRunState(PositioningEngineMask engType, LocEngineRunState engState); + +static const GnssInterface gGnssInterface = { +    sizeof(GnssInterface), +    initialize, +    deinitialize, +    addClient, +    removeClient, +    requestCapabilities, +    startTracking, +    updateTrackingOptions, +    stopTracking, +    gnssNiResponse, +    setControlCallbacks, +    enable, +    disable, +    gnssUpdateConfig, +    gnssGetConfig, +    gnssUpdateSvTypeConfig, +    gnssGetSvTypeConfig, +    gnssResetSvTypeConfig, +    gnssDeleteAidingData, +    gnssUpdateXtraThrottle, +    injectLocation, +    injectTime, +    agpsInit, +    agpsDataConnOpen, +    agpsDataConnClosed, +    agpsDataConnFailed, +    getDebugReport, +    updateConnectionStatus, +    odcpiInit, +    odcpiInject, +    blockCPI, +    getGnssEnergyConsumed, +    enableNfwLocationAccess, +    nfwInit, +    getPowerStateChanges, +    injectLocationExt, +    updateBatteryStatus, +    updateSystemPowerState, +    setConstrainedTunc, +    setPositionAssistedClockEstimator, +    gnssUpdateSvConfig, +    configLeverArm, +    measCorrInit, +    measCorrSetCorrections, +    measCorrClose, +    antennaInfoInit, +    antennaInfoClose, +    configRobustLocation, +    configMinGpsWeek, +    configDeadReckoningEngineParams, +    updateNTRIPGGAConsent, +    enablePPENtripStream, +    disablePPENtripStream, +    gnssUpdateSecondaryBandConfig, +    gnssGetSecondaryBandConfig, +    resetNetworkInfo, +    configEngineRunState +}; + +#ifndef DEBUG_X86 +extern "C" const GnssInterface* getGnssInterface() +#else +const GnssInterface* getGnssInterface() +#endif // DEBUG_X86 +{ +   gGnssInterface.initialize(); +   return &gGnssInterface; +} + +static void initialize() +{ +    if (NULL == gGnssAdapter) { +        gGnssAdapter = new GnssAdapter(); +    } +} + +static void deinitialize() +{ +    if (NULL != gGnssAdapter) { +        delete gGnssAdapter; +        gGnssAdapter = NULL; +    } +} + +static void addClient(LocationAPI* client, const LocationCallbacks& callbacks) +{ +    if (NULL != gGnssAdapter) { +        gGnssAdapter->addClientCommand(client, callbacks); +    } +} + +static void removeClient(LocationAPI* client, removeClientCompleteCallback rmClientCb) +{ +    if (NULL != gGnssAdapter) { +        gGnssAdapter->removeClientCommand(client, rmClientCb); +    } +} + +static void requestCapabilities(LocationAPI* client) +{ +    if (NULL != gGnssAdapter) { +        gGnssAdapter->requestCapabilitiesCommand(client); +    } +} + +static uint32_t startTracking( +        LocationAPI* client, TrackingOptions& trackingOptions) +{ +    if (NULL != gGnssAdapter) { +        return gGnssAdapter->startTrackingCommand(client, trackingOptions); +    } else { +        return 0; +    } +} + +static void updateTrackingOptions( +        LocationAPI* client, uint32_t id, TrackingOptions& trackingOptions) +{ +    if (NULL != gGnssAdapter) { +        gGnssAdapter->updateTrackingOptionsCommand( +                client, id, trackingOptions); +    } +} + +static void stopTracking(LocationAPI* client, uint32_t id) +{ +    if (NULL != gGnssAdapter) { +        gGnssAdapter->stopTrackingCommand(client, id); +    } +} + +static void gnssNiResponse(LocationAPI* client, uint32_t id, GnssNiResponse response) +{ +    if (NULL != gGnssAdapter) { +        gGnssAdapter->gnssNiResponseCommand(client, id, response); +    } +} + +static void setControlCallbacks(LocationControlCallbacks& controlCallbacks) +{ +    if (NULL != gGnssAdapter) { +        gGnssAdapter->setControlCallbacksCommand(controlCallbacks); +    } +} + +static uint32_t enable(LocationTechnologyType techType) +{ +    if (NULL != gGnssAdapter) { +        return gGnssAdapter->enableCommand(techType); +    } else { +        return 0; +    } +} + +static void disable(uint32_t id) +{ +    if (NULL != gGnssAdapter) { +        gGnssAdapter->disableCommand(id); +    } +} + +static uint32_t* gnssUpdateConfig(const GnssConfig& config) +{ +    if (NULL != gGnssAdapter) { +        return gGnssAdapter->gnssUpdateConfigCommand(config); +    } else { +        return NULL; +    } +} + +static uint32_t* gnssGetConfig(GnssConfigFlagsMask mask) +{ +    if (NULL != gGnssAdapter) { +        return gGnssAdapter->gnssGetConfigCommand(mask); +    } else { +        return NULL; +    } +} + +static void gnssUpdateSvTypeConfig(GnssSvTypeConfig& config) +{ +    if (NULL != gGnssAdapter) { +        gGnssAdapter->gnssUpdateSvTypeConfigCommand(config); +    } +} + +static void gnssGetSvTypeConfig(GnssSvTypeConfigCallback& callback) +{ +    if (NULL != gGnssAdapter) { +        gGnssAdapter->gnssGetSvTypeConfigCommand(callback); +    } +} + +static void gnssResetSvTypeConfig() +{ +    if (NULL != gGnssAdapter) { +        gGnssAdapter->gnssResetSvTypeConfigCommand(); +    } +} + +static uint32_t gnssDeleteAidingData(GnssAidingData& data) +{ +    if (NULL != gGnssAdapter) { +        return gGnssAdapter->gnssDeleteAidingDataCommand(data); +    } else { +        return 0; +    } +} + +static void gnssUpdateXtraThrottle(const bool enabled) +{ +    if (NULL != gGnssAdapter) { +        gGnssAdapter->gnssUpdateXtraThrottleCommand(enabled); +    } +} + +static void injectLocation(double latitude, double longitude, float accuracy) +{ +   if (NULL != gGnssAdapter) { +       gGnssAdapter->injectLocationCommand(latitude, longitude, accuracy); +   } +} + +static void injectTime(int64_t time, int64_t timeReference, int32_t uncertainty) +{ +   if (NULL != gGnssAdapter) { +       gGnssAdapter->injectTimeCommand(time, timeReference, uncertainty); +   } +} + +static void agpsInit(const AgpsCbInfo& cbInfo) { + +    if (NULL != gGnssAdapter) { +        gGnssAdapter->initAgpsCommand(cbInfo); +    } +} +static void agpsDataConnOpen( +        AGpsExtType agpsType, const char* apnName, int apnLen, int ipType) { + +    if (NULL != gGnssAdapter) { +        gGnssAdapter->dataConnOpenCommand( +                agpsType, apnName, apnLen, (AGpsBearerType)ipType); +    } +} +static void agpsDataConnClosed(AGpsExtType agpsType) { + +    if (NULL != gGnssAdapter) { +        gGnssAdapter->dataConnClosedCommand(agpsType); +    } +} +static void agpsDataConnFailed(AGpsExtType agpsType) { + +    if (NULL != gGnssAdapter) { +        gGnssAdapter->dataConnFailedCommand(agpsType); +    } +} + +static void getDebugReport(GnssDebugReport& report) { + +    if (NULL != gGnssAdapter) { +        gGnssAdapter->getDebugReport(report); +    } +} + +static void updateConnectionStatus(bool connected, int8_t type, +                                   bool roaming, NetworkHandle networkHandle, +                                   string& apn) { +    if (NULL != gGnssAdapter) { +        gGnssAdapter->getSystemStatus()->eventConnectionStatus( +                connected, type, roaming, networkHandle, apn); +    } +} + +static void odcpiInit(const OdcpiRequestCallback& callback, OdcpiPrioritytype priority) +{ +    if (NULL != gGnssAdapter) { +        gGnssAdapter->initOdcpiCommand(callback, priority); +    } +} + +static void odcpiInject(const Location& location) +{ +    if (NULL != gGnssAdapter) { +        gGnssAdapter->injectOdcpiCommand(location); +    } +} + +static void blockCPI(double latitude, double longitude, float accuracy, +                     int blockDurationMsec, double latLonDiffThreshold) { +    if (NULL != gGnssAdapter) { +        gGnssAdapter->blockCPICommand(latitude, longitude, accuracy, +                                      blockDurationMsec, latLonDiffThreshold); +    } +} + +static void getGnssEnergyConsumed(GnssEnergyConsumedCallback energyConsumedCb) { +    if (NULL != gGnssAdapter) { +        gGnssAdapter->getGnssEnergyConsumedCommand(energyConsumedCb); +    } +} + +static void enableNfwLocationAccess(bool enable) { +    if (NULL != gGnssAdapter) { +        gGnssAdapter->nfwControlCommand(enable); +    } +} + +static void nfwInit(const NfwCbInfo& cbInfo) { +    if (NULL != gGnssAdapter) { +        gGnssAdapter->initNfwCommand(cbInfo); +    } +} + +static void getPowerStateChanges(std::function<void(bool)> powerStateCb) +{ +    if (NULL != gGnssAdapter) { +        gGnssAdapter->getPowerStateChangesCommand(powerStateCb); +    } +} + +static void injectLocationExt(const GnssLocationInfoNotification &locationInfo) +{ +   if (NULL != gGnssAdapter) { +       gGnssAdapter->injectLocationExtCommand(locationInfo); +   } +} + +static void updateBatteryStatus(bool charging) { +    if (NULL != gGnssAdapter) { +        gGnssAdapter->getSystemStatus()->updatePowerConnectState(charging); +    } +} + +static void resetNetworkInfo() { +    if (NULL != gGnssAdapter) { +        gGnssAdapter->getSystemStatus()->resetNetworkInfo(); +    } +} + +static void updateSystemPowerState(PowerStateType systemPowerState) { +   if (NULL != gGnssAdapter) { +       gGnssAdapter->updateSystemPowerStateCommand(systemPowerState); +   } +} + +static uint32_t setConstrainedTunc (bool enable, float tuncConstraint, uint32_t energyBudget) { +    if (NULL != gGnssAdapter) { +        return gGnssAdapter->setConstrainedTuncCommand(enable, tuncConstraint, energyBudget); +    } else { +        return 0; +    } +} + +static uint32_t setPositionAssistedClockEstimator(bool enable) { +    if (NULL != gGnssAdapter) { +        return gGnssAdapter->setPositionAssistedClockEstimatorCommand(enable); +    } else { +        return 0; +    } +} + +static uint32_t gnssUpdateSvConfig( +        const GnssSvTypeConfig& constellationEnablementConfig, +        const GnssSvIdConfig&   blacklistSvConfig) { +    if (NULL != gGnssAdapter) { +        return gGnssAdapter->gnssUpdateSvConfigCommand( +                constellationEnablementConfig, blacklistSvConfig); +    } else { +        return 0; +    } +} + +static uint32_t configLeverArm(const LeverArmConfigInfo& configInfo){ +    if (NULL != gGnssAdapter) { +        return gGnssAdapter->configLeverArmCommand(configInfo); +    } else { +        return 0; +    } +} + +static bool measCorrInit(const measCorrSetCapabilitiesCb setCapabilitiesCb) { +    if (NULL != gGnssAdapter) { +        return gGnssAdapter->openMeasCorrCommand(setCapabilitiesCb); +    } else { +        return false; +    } +} + +static bool measCorrSetCorrections(const GnssMeasurementCorrections gnssMeasCorr) { +    if (NULL != gGnssAdapter) { +        return gGnssAdapter->measCorrSetCorrectionsCommand(gnssMeasCorr); +    } else { +        return false; +    } +} + +static void measCorrClose() { +    if (NULL != gGnssAdapter) { +        gGnssAdapter->closeMeasCorrCommand(); +    } +} + +static uint32_t antennaInfoInit(const antennaInfoCb antennaInfoCallback) { +    if (NULL != gGnssAdapter) { +        return gGnssAdapter->antennaInfoInitCommand(antennaInfoCallback); +    } else { +        return ANTENNA_INFO_ERROR_GENERIC; +    } +} + +static void antennaInfoClose() { +    if (NULL != gGnssAdapter) { +        return gGnssAdapter->antennaInfoCloseCommand(); +	} +} + +static uint32_t configRobustLocation(bool enable, bool enableForE911){ +    if (NULL != gGnssAdapter) { +        return gGnssAdapter->configRobustLocationCommand(enable, enableForE911); +    } else { +        return 0; +    } +} + +static uint32_t configMinGpsWeek(uint16_t minGpsWeek){ +    if (NULL != gGnssAdapter) { +        return gGnssAdapter->configMinGpsWeekCommand(minGpsWeek); +    } else { +        return 0; +    } +} + +static uint32_t configDeadReckoningEngineParams(const DeadReckoningEngineConfig& dreConfig){ +    if (NULL != gGnssAdapter) { +        return gGnssAdapter->configDeadReckoningEngineParamsCommand(dreConfig); +    } else { +        return 0; +    } +} + +static uint32_t gnssUpdateSecondaryBandConfig( +        const GnssSvTypeConfig& secondaryBandConfig) { +    if (NULL != gGnssAdapter) { +        return gGnssAdapter->gnssUpdateSecondaryBandConfigCommand(secondaryBandConfig); +    } else { +        return 0; +    } +} + +static uint32_t gnssGetSecondaryBandConfig(){ +    if (NULL != gGnssAdapter) { +        return gGnssAdapter->gnssGetSecondaryBandConfigCommand(); +    } else { +        return 0; +    } +} + +static void updateNTRIPGGAConsent(bool consentAccepted){ +    if (NULL != gGnssAdapter) { +        // Call will be enabled once GnssAdapter impl. is ready. +        gGnssAdapter->updateNTRIPGGAConsentCommand(consentAccepted); +    } +} + +static void enablePPENtripStream(const GnssNtripConnectionParams& params, bool enableRTKEngine){ +    if (NULL != gGnssAdapter) { +        // Call will be enabled once GnssAdapter impl. is ready. +        gGnssAdapter->enablePPENtripStreamCommand(params, enableRTKEngine); +    } +} + +static void disablePPENtripStream(){ +    if (NULL != gGnssAdapter) { +        // Call will be enabled once GnssAdapter impl. is ready. +        gGnssAdapter->disablePPENtripStreamCommand(); +    } +} + +static uint32_t configEngineRunState(PositioningEngineMask engType, LocEngineRunState engState) { +    if (NULL != gGnssAdapter) { +        return gGnssAdapter->configEngineRunStateCommand(engType, engState); +    } else { +        return 0; +    } +} | 
