/* Copyright (c) 2011-2012, 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 Code Aurora Forum, Inc. 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_adapter"

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <stdint.h>
#include <stdbool.h>

#include <hardware/gps.h>
#include <utils/SystemClock.h>
#include "LocApiV02Adapter.h"
#include "loc_api_v02_client.h"
#include "loc_api_v02_log.h"
#include "loc_api_sync_req.h"
#include "LocApiAdapter.h"
#include "loc_util_log.h"


/* Default session id ; TBD needs incrementing for each */
#define LOC_API_V02_DEF_SESSION_ID (1)

/* Default minimium interval in ms */
#define LOC_API_V02_DEF_MIN_INTERVAL (1000)

/* Default horizontal accuracy  in meters*/
#define LOC_API_V02_DEF_HORZ_ACCURACY (50)

/* Default timeout in ms; TBD: needs implementing */
#define LOC_API_V02_DEF_TIMEOUT (120000)

/* UMTS CP Address key*/
#define LOC_NI_NOTIF_KEY_ADDRESS           "Address"

/* GPS SV Id offset */
#define GPS_SV_ID_OFFSET        (1)

/* GLONASS SV Id offset */
#define GLONASS_SV_ID_OFFSET    (65)

/* SV ID range */
#define SV_ID_RANGE             (32)



/* static event callbacks that call the LocApiV02Adapter callbacks*/

/* global event callback, call the eventCb function in loc api adapter v02
   instance */
static void globalEventCb(locClientHandleType clientHandle,
                          uint32_t eventId,
                          const locClientEventIndUnionType eventPayload,
                          void*  pClientCookie)
{
  MODEM_LOG_CALLFLOW(%s, loc_get_v02_event_name(eventId));
  LocApiV02Adapter *locApiV02AdapterInstance =
      (LocApiV02Adapter *)pClientCookie;

  LOC_LOGV ("%s:%d] client = %p, event id = %d, client cookie ptr = %p\n",
                  __func__,  __LINE__,  clientHandle, eventId, pClientCookie);

  // return if null is passed
  if( NULL == locApiV02AdapterInstance)
  {
    LOC_LOGE ("%s:%d] NULL object passed : client = %p, event id = %d\n",
                  __func__,  __LINE__,  clientHandle, eventId);
    return;
  }
  locApiV02AdapterInstance->eventCb(clientHandle,
                                    eventId,
                                    eventPayload);
}

/* global response callback, it calls the sync request process
   indication function to unblock the request that is waiting on this
   response indication*/
static void globalRespCb(locClientHandleType clientHandle,
                         uint32_t respId,
                         const locClientRespIndUnionType respPayload,
                         void*  pClientCookie)
{
  MODEM_LOG_CALLFLOW(%s, loc_get_v02_event_name(respId));
  LocApiV02Adapter *locApiV02AdapterInstance =
        (LocApiV02Adapter *)pClientCookie;


  LOC_LOGV ("%s:%d] client = %p, resp id = %d, client cookie ptr = %p\n",
                  __func__,  __LINE__,  clientHandle, respId, pClientCookie);

  if( NULL == locApiV02AdapterInstance)
  {
    LOC_LOGE ("%s:%d] NULL object passed : client = %p, resp id = %d\n",
                  __func__,  __LINE__,  clientHandle, respId);
    return;
  }
    // process the sync call
    // use pDeleteAssistDataInd as a dummy pointer
  loc_sync_process_ind(clientHandle, respId,
                       (void *)respPayload.pDeleteAssistDataInd);
}

/* global error callback, it will call the handle service down
   function in the loc api adapter instance. */
static void globalErrorCb (locClientHandleType clientHandle,
                           locClientErrorEnumType errorId,
                           void *pClientCookie)
{
  LocApiV02Adapter *locApiV02AdapterInstance =
          (LocApiV02Adapter *)pClientCookie;

  LOC_LOGV ("%s:%d] client = %p, error id = %d\n, client cookie ptr = %p\n",
                  __func__,  __LINE__,  clientHandle, errorId, pClientCookie);
  if( NULL == locApiV02AdapterInstance)
  {
    LOC_LOGE ("%s:%d] NULL object passed : client = %p, error id = %d\n",
                  __func__,  __LINE__,  clientHandle, errorId);
    return;
  }
  locApiV02AdapterInstance->errorCb(clientHandle,
                                    errorId);
}

/* global structure containing the callbacks */
locClientCallbacksType globalCallbacks =
{
    sizeof(locClientCallbacksType),
    globalEventCb,
    globalRespCb,
    globalErrorCb
};

/* Constructor for LocApiV02Adapter */
LocApiV02Adapter :: LocApiV02Adapter(LocEng &locEng):
  LocApiAdapter(locEng), clientHandle( LOC_CLIENT_INVALID_HANDLE_VALUE),
  eventMask(convertMask(locEng.eventMask))
{
  // initialize loc_sync_req interface
  loc_sync_req_init();
}

/* Destructor for LocApiV02Adapter */
LocApiV02Adapter :: ~LocApiV02Adapter()
{
  deInitLocClient();
}

/* close Loc API V02 client */
int LocApiV02Adapter :: deInitLocClient()
{
  return ( eLOC_CLIENT_SUCCESS == locClientClose(&clientHandle)) ? 0 : -1 ;
}

/* Initialize a loc api v02 client */
enum loc_api_adapter_err LocApiV02Adapter :: reinit()
{
  locClientStatusEnumType status;
  /* If the client is already open close it first */
  if(LOC_CLIENT_INVALID_HANDLE_VALUE != clientHandle)
  {
     status = locClientClose(&clientHandle);
     if( eLOC_CLIENT_SUCCESS != status)
     {
        LOC_LOGE ("%s:%d]: locClientClose failed, status = %d\n", __func__,
                     __LINE__, status);
        return (LOC_API_ADAPTER_ERR_FAILURE);
     }
  }

  LOC_LOGV ("%s:%d]: reference to this = %p passed in \n", __func__,
                       __LINE__, this);
  /* initialize the loc api v02 interface, note that
     the locClientOpen() function will block if the
     service is unavailable for a fixed time out */

  status = locClientOpen(
    eventMask, &globalCallbacks, &clientHandle, (void *)this);

  if (eLOC_CLIENT_SUCCESS != status ||
        clientHandle == LOC_CLIENT_INVALID_HANDLE_VALUE )
  {
      LOC_LOGE ("%s:%d]: locClientOpen failed, status = %s\n", __func__,
                __LINE__, loc_get_v02_client_status_name(status));
      return (LOC_API_ADAPTER_ERR_FAILURE);
  }

  // return SUCCESS
  return (LOC_API_ADAPTER_ERR_SUCCESS);
}

/* start positioning session */
enum loc_api_adapter_err LocApiV02Adapter :: startFix()
{
  locClientStatusEnumType status;
  locClientReqUnionType req_union;

  qmiLocStartReqMsgT_v02 start_msg;

  qmiLocSetOperationModeReqMsgT_v02 set_mode_msg;
  qmiLocSetOperationModeIndMsgT_v02 set_mode_ind;

    // clear all fields, validity masks
  memset (&start_msg, 0, sizeof(start_msg));
  memset (&set_mode_msg, 0, sizeof(set_mode_msg));
  memset (&set_mode_ind, 0, sizeof(set_mode_ind));

  LOC_LOGV("%s:%d]: start \n", __func__, __LINE__);
  fixCriteria.logv();

  // fill in the start request
  switch(fixCriteria.mode)
  {
    case LOC_POSITION_MODE_MS_BASED:
      set_mode_msg.operationMode = eQMI_LOC_OPER_MODE_MSB_V02;
      break;

    case LOC_POSITION_MODE_MS_ASSISTED:
      set_mode_msg.operationMode = eQMI_LOC_OPER_MODE_MSA_V02;
      break;

    case LOC_POSITION_MODE_RESERVED_4:
      set_mode_msg.operationMode = eQMI_LOC_OPER_MODE_CELL_ID_V02;
        break;

    default:
      set_mode_msg.operationMode = eQMI_LOC_OPER_MODE_STANDALONE_V02;
      break;
  }

  req_union.pSetOperationModeReq = &set_mode_msg;

  // send the mode first, before the start message.
  status = loc_sync_send_req(clientHandle,
                             QMI_LOC_SET_OPERATION_MODE_REQ_V02,
                             req_union, LOC_ENGINE_SYNC_REQUEST_TIMEOUT,
                             QMI_LOC_SET_OPERATION_MODE_IND_V02,
                             &set_mode_ind); // NULL?

  if (status != eLOC_CLIENT_SUCCESS ||
      eQMI_LOC_SUCCESS_V02 != set_mode_ind.status)
  {
    LOC_LOGE ("%s:%d]: set opertion mode failed status = %s, "
                   "ind..status = %s\n", __func__, __LINE__,
              loc_get_v02_client_status_name(status),
              loc_get_v02_qmi_status_name(set_mode_ind.status));

    return LOC_API_ADAPTER_ERR_GENERAL_FAILURE; // error
  }

  start_msg.minInterval_valid = 1;
  start_msg.minInterval = fixCriteria.min_interval;

  if (fixCriteria.preferred_accuracy > 0) {
      start_msg.horizontalAccuracyLevel_valid = 1;

      if (fixCriteria.preferred_accuracy <= 100)
      {
          // fix needs high accuracy
          start_msg.horizontalAccuracyLevel =  eQMI_LOC_ACCURACY_HIGH_V02;
      }
      else if (fixCriteria.preferred_accuracy <= 1000)
      {
          //fix needs med accuracy
          start_msg.horizontalAccuracyLevel =  eQMI_LOC_ACCURACY_MED_V02;
      }
      else
      {
          //fix needs low accuracy
          start_msg.horizontalAccuracyLevel =  eQMI_LOC_ACCURACY_LOW_V02;
      }
  }

  start_msg.fixRecurrence_valid = 1;
  if(GPS_POSITION_RECURRENCE_SINGLE == fixCriteria.recurrence)
  {
    start_msg.fixRecurrence = eQMI_LOC_RECURRENCE_SINGLE_V02;
  }
  else
  {
    start_msg.fixRecurrence = eQMI_LOC_RECURRENCE_PERIODIC_V02;
  }

  //dummy session id
  // TBD: store session ID, check for session id in pos reports.
  start_msg.sessionId = LOC_API_V02_DEF_SESSION_ID;

  if (fixCriteria.credentials[0] != 0) {
      int size1 = sizeof(start_msg.applicationId.applicationName);
      int size2 = sizeof(fixCriteria.credentials);
      int len = ((size1 < size2) ? size1 : size2) - 1;
      memcpy(start_msg.applicationId.applicationName,
             fixCriteria.credentials,
             len);

      size1 = sizeof(start_msg.applicationId.applicationProvider);
      size2 = sizeof(fixCriteria.provider);
      len = ((size1 < size2) ? size1 : size2) - 1;
      memcpy(start_msg.applicationId.applicationProvider,
             fixCriteria.provider,
             len);

      start_msg.applicationId_valid = 1;
  }

  req_union.pStartReq = &start_msg;

  status = locClientSendReq (clientHandle, QMI_LOC_START_REQ_V02,
                            req_union );

  if( eLOC_CLIENT_SUCCESS == status)
  {
    return LOC_API_ADAPTER_ERR_SUCCESS;
  }

  return LOC_API_ADAPTER_ERR_GENERAL_FAILURE;
}

/* stop a positioning session */
enum loc_api_adapter_err LocApiV02Adapter :: stopFix()
{
  locClientStatusEnumType status;
  locClientReqUnionType req_union;

  qmiLocStopReqMsgT_v02 stop_msg;

  LOC_LOGD(" %s:%d]: stop called \n", __func__, __LINE__);

  memset(&stop_msg, 0, sizeof(stop_msg));

  // dummy session id
  stop_msg.sessionId = LOC_API_V02_DEF_SESSION_ID;

  req_union.pStopReq = &stop_msg;

  status = locClientSendReq(clientHandle,
                            QMI_LOC_STOP_REQ_V02,
                            req_union);

  if( eLOC_CLIENT_SUCCESS == status)
  {
    return LOC_API_ADAPTER_ERR_SUCCESS;
  }

  LOC_LOGE("%s:%d]: error = %s\n",__func__, __LINE__,
           loc_get_v02_client_status_name(status));
  return (LOC_API_ADAPTER_ERR_GENERAL_FAILURE);
}

/* set the positioning fix criteria */
enum loc_api_adapter_err LocApiV02Adapter ::  setPositionMode(
  const LocPosMode *posMode)
{
    LOC_LOGV ("%s:%d]: posMode %p",__func__, __LINE__, posMode);

    if (NULL != posMode &&
        !fixCriteria.equals(*posMode)) {
        //making a copy of the fix criteria
        fixCriteria = *posMode;

        LOC_LOGD ("%s:%d]: new fix criteria", __func__, __LINE__);

        if(true == navigating)
        {
            //fix is in progress, send a restart
            LOC_LOGD ("%s:%d]: fix is in progress restarting the fix with new "
                      "criteria\n", __func__, __LINE__);

            return( startFix());
        }
    }

    return LOC_API_ADAPTER_ERR_SUCCESS;
}

/* inject time into the position engine */
enum loc_api_adapter_err LocApiV02Adapter ::
    setTime(GpsUtcTime time, int64_t timeReference, int uncertainty)
{
  locClientReqUnionType req_union;
  locClientStatusEnumType status;
  qmiLocInjectUtcTimeReqMsgT_v02  inject_time_msg;
  qmiLocInjectUtcTimeIndMsgT_v02 inject_time_ind;

  memset(&inject_time_msg, 0, sizeof(inject_time_msg));

  inject_time_ind.status = eQMI_LOC_GENERAL_FAILURE_V02;

  inject_time_msg.timeUtc = time;

  inject_time_msg.timeUtc += (int64_t)(android::elapsedRealtime() - timeReference);

  inject_time_msg.timeUnc = uncertainty;

  req_union.pInjectUtcTimeReq = &inject_time_msg;

  LOC_LOGV ("%s:%d]: uncertainty = %d\n", __func__, __LINE__,
                 uncertainty);

  status = loc_sync_send_req(clientHandle,
                             QMI_LOC_INJECT_UTC_TIME_REQ_V02,
                             req_union, LOC_ENGINE_SYNC_REQUEST_TIMEOUT,
                             QMI_LOC_INJECT_UTC_TIME_IND_V02,
                             &inject_time_ind);

  if (status != eLOC_CLIENT_SUCCESS ||
      eQMI_LOC_SUCCESS_V02 != inject_time_ind.status)
  {
    LOC_LOGE ("%s:%d] status = %s, ind..status = %s\n", __func__,  __LINE__,
              loc_get_v02_client_status_name(status),
              loc_get_v02_qmi_status_name(inject_time_ind.status));

    return LOC_API_ADAPTER_ERR_GENERAL_FAILURE;
  }

  return LOC_API_ADAPTER_ERR_SUCCESS;
}

/* inject position into the position engine */
enum loc_api_adapter_err LocApiV02Adapter ::
    injectPosition(double latitude, double longitude, float accuracy)
{
  locClientReqUnionType req_union;
  locClientStatusEnumType status;
  qmiLocInjectPositionReqMsgT_v02 inject_pos_msg;
  qmiLocInjectPositionIndMsgT_v02 inject_pos_ind;

  memset(&inject_pos_msg, 0, sizeof(inject_pos_msg));

  inject_pos_msg.latitude_valid = 1;
  inject_pos_msg.latitude = latitude;

  inject_pos_msg.longitude_valid = 1;
  inject_pos_msg.longitude = longitude;

  inject_pos_msg.horUncCircular_valid = 1;

  inject_pos_msg.horUncCircular = accuracy; //meters assumed

  inject_pos_msg.horConfidence_valid = 1;

  inject_pos_msg.horConfidence = 63; // 63% (1 std dev assumed)

    /* Log */
  LOC_LOGD("%s:%d]: Lat=%lf, Lon=%lf, Acc=%.2lf\n", __func__, __LINE__,
                inject_pos_msg.latitude, inject_pos_msg.longitude,
                inject_pos_msg.horUncCircular);

  req_union.pInjectPositionReq = &inject_pos_msg;

  status = loc_sync_send_req(clientHandle,
                             QMI_LOC_INJECT_POSITION_REQ_V02,
                             req_union, LOC_ENGINE_SYNC_REQUEST_TIMEOUT,
                             QMI_LOC_INJECT_POSITION_IND_V02,
                             &inject_pos_ind);

  if (status != eLOC_CLIENT_SUCCESS ||
      eQMI_LOC_SUCCESS_V02 != inject_pos_ind.status)
  {
    LOC_LOGE ("%s:%d]: error! status = %s, inject_pos_ind.status = %s\n",
              __func__, __LINE__,
              loc_get_v02_client_status_name(status),
              loc_get_v02_qmi_status_name(inject_pos_ind.status));

   return LOC_API_ADAPTER_ERR_GENERAL_FAILURE;
  }

  return LOC_API_ADAPTER_ERR_SUCCESS;
}

/* delete assistance date */
enum loc_api_adapter_err LocApiV02Adapter ::  deleteAidingData(GpsAidingData f)
{
  locClientReqUnionType req_union;
  locClientStatusEnumType status;
  qmiLocDeleteAssistDataReqMsgT_v02 delete_req;
  qmiLocDeleteAssistDataIndMsgT_v02 delete_resp;

  memset(&delete_req, 0, sizeof(delete_req));
  memset(&delete_resp, 0, sizeof(delete_resp));

  if( f == GPS_DELETE_ALL )
  {
    delete_req.deleteAllFlag = true;
  }

  else
  {
    /* to keep track of svInfoList for GPS and GLO*/
    uint32_t curr_sv_len = 0;
    uint32_t curr_sv_idx = 0;
    uint32_t sv_id =  0;

    if((f & GPS_DELETE_EPHEMERIS ) || ( f & GPS_DELETE_ALMANAC ))
    {
      /* do delete for all GPS SV's */

      curr_sv_len += SV_ID_RANGE;

      sv_id = GPS_SV_ID_OFFSET;

      delete_req.deleteSvInfoList_valid = 1;

      delete_req.deleteSvInfoList_len = curr_sv_len;

      LOC_LOGV("%s:%d]: Delete GPS SV info for index %d to %d"
                    "and sv id %d to %d \n",
                    __func__, __LINE__, curr_sv_idx, curr_sv_len - 1,
                    sv_id, sv_id+SV_ID_RANGE);

      for( uint32_t i = curr_sv_idx; i< curr_sv_len ; i++, sv_id++ )
      {
        delete_req.deleteSvInfoList[i].gnssSvId = sv_id;

        delete_req.deleteSvInfoList[i].system = eQMI_LOC_SV_SYSTEM_GPS_V02;

        if(f & GPS_DELETE_EPHEMERIS )
        {
          // set ephemeris mask for all GPS SV's
          delete_req.deleteSvInfoList[i].deleteSvInfoMask |=
            QMI_LOC_MASK_DELETE_EPHEMERIS_V02;
        }

        if( f & GPS_DELETE_ALMANAC )
        {
          delete_req.deleteSvInfoList[i].deleteSvInfoMask |=
            QMI_LOC_MASK_DELETE_ALMANAC_V02;
        }
      }
      // increment the current index
      curr_sv_idx += SV_ID_RANGE;

    }

    if( f & GPS_DELETE_TIME_GPS )
    {
      delete_req.deleteGnssDataMask_valid = 1;
      delete_req.deleteGnssDataMask |= QMI_LOC_MASK_DELETE_GPS_TIME_V02;
    }

    if(f & GPS_DELETE_POSITION )
    {
      delete_req.deleteGnssDataMask_valid = 1;
      delete_req.deleteGnssDataMask |= QMI_LOC_MASK_DELETE_POSITION_V02;
    }

    if(f & GPS_DELETE_TIME )
    {
      delete_req.deleteGnssDataMask_valid = 1;
      delete_req.deleteGnssDataMask |= QMI_LOC_MASK_DELETE_TIME_V02;
    }

    if(f & GPS_DELETE_IONO )
    {
      delete_req.deleteGnssDataMask_valid = 1;
      delete_req.deleteGnssDataMask |= QMI_LOC_MASK_DELETE_IONO_V02;
    }

    if(f & GPS_DELETE_UTC )
    {
      delete_req.deleteGnssDataMask_valid = 1;
      delete_req.deleteGnssDataMask |= QMI_LOC_MASK_DELETE_UTC_V02;
    }

    if(f & GPS_DELETE_HEALTH )
    {
      delete_req.deleteGnssDataMask_valid = 1;
      delete_req.deleteGnssDataMask |= QMI_LOC_MASK_DELETE_HEALTH_V02;
    }

    if(f & GPS_DELETE_SVDIR )
    {
      delete_req.deleteGnssDataMask_valid = 1;
      delete_req.deleteGnssDataMask |= QMI_LOC_MASK_DELETE_GPS_SVDIR_V02;
    }
    if(f & GPS_DELETE_SADATA )
    {
      delete_req.deleteGnssDataMask_valid = 1;
      delete_req.deleteGnssDataMask |= QMI_LOC_MASK_DELETE_SADATA_V02;
    }
    if(f & GPS_DELETE_RTI )
    {
      delete_req.deleteGnssDataMask_valid = 1;
      delete_req.deleteGnssDataMask |= QMI_LOC_MASK_DELETE_RTI_V02;
    }
    if(f & GPS_DELETE_CELLDB_INFO )
    {
      delete_req.deleteCellDbDataMask_valid = 1;
      delete_req.deleteCellDbDataMask =
        ( QMI_LOC_MASK_DELETE_CELLDB_POS_V02 |
          QMI_LOC_MASK_DELETE_CELLDB_LATEST_GPS_POS_V02 |
          QMI_LOC_MASK_DELETE_CELLDB_OTA_POS_V02 |
          QMI_LOC_MASK_DELETE_CELLDB_EXT_REF_POS_V02 |
          QMI_LOC_MASK_DELETE_CELLDB_TIMETAG_V02 |
          QMI_LOC_MASK_DELETE_CELLDB_CELLID_V02 |
          QMI_LOC_MASK_DELETE_CELLDB_CACHED_CELLID_V02 |
          QMI_LOC_MASK_DELETE_CELLDB_LAST_SRV_CELL_V02 |
          QMI_LOC_MASK_DELETE_CELLDB_CUR_SRV_CELL_V02 |
          QMI_LOC_MASK_DELETE_CELLDB_NEIGHBOR_INFO_V02) ;

    }
    if(f & GPS_DELETE_ALMANAC_CORR )
    {
      delete_req.deleteGnssDataMask_valid = 1;
      delete_req.deleteGnssDataMask |= QMI_LOC_MASK_DELETE_GPS_ALM_CORR_V02;
    }
    if(f & GPS_DELETE_FREQ_BIAS_EST )
    {
      delete_req.deleteGnssDataMask_valid = 1;
      delete_req.deleteGnssDataMask |= QMI_LOC_MASK_DELETE_FREQ_BIAS_EST_V02;
    }
    if ( (f & GPS_DELETE_EPHEMERIS_GLO ) || (f & GPS_DELETE_ALMANAC_GLO ))
    {
      /* do delete for all GLONASS SV's (65 - 96)
      */
      curr_sv_len += SV_ID_RANGE;

      sv_id = GLONASS_SV_ID_OFFSET;

      delete_req.deleteSvInfoList_valid = 1;

      delete_req.deleteSvInfoList_len = curr_sv_len;

      LOC_LOGV("%s:%d]: Delete GLO SV info for index %d to %d"
                    "and sv id %d to %d \n",
                    __func__, __LINE__, curr_sv_idx, curr_sv_len - 1,
                    sv_id, sv_id+SV_ID_RANGE);


      for( uint32_t i = curr_sv_idx; i< curr_sv_len ; i++, sv_id++ )
      {
        delete_req.deleteSvInfoList[i].gnssSvId = sv_id;

        delete_req.deleteSvInfoList[i].system = eQMI_LOC_SV_SYSTEM_GLONASS_V02;

        if(f & GPS_DELETE_EPHEMERIS )
        {
          // set ephemeris mask for all GPS SV's
          delete_req.deleteSvInfoList[i].deleteSvInfoMask |=
            QMI_LOC_MASK_DELETE_EPHEMERIS_V02;
        }

        if( f & GPS_DELETE_ALMANAC )
        {
          delete_req.deleteSvInfoList[i].deleteSvInfoMask |=
            QMI_LOC_MASK_DELETE_ALMANAC_V02;
        }
      }
      curr_sv_idx += SV_ID_RANGE;
    }

    if(f & GPS_DELETE_SVDIR_GLO )
    {
      delete_req.deleteGnssDataMask_valid = 1;
      delete_req.deleteGnssDataMask |= QMI_LOC_MASK_DELETE_GLO_SVDIR_V02;
    }

    if(f & GPS_DELETE_SVSTEER_GLO )
    {
      delete_req.deleteGnssDataMask_valid = 1;
      delete_req.deleteGnssDataMask |= QMI_LOC_MASK_DELETE_GLO_SVSTEER_V02;
    }

    if(f & GPS_DELETE_ALMANAC_CORR_GLO )
    {
      delete_req.deleteGnssDataMask_valid = 1;
      delete_req.deleteGnssDataMask |= QMI_LOC_MASK_DELETE_GLO_ALM_CORR_V02;
    }

    if(f & GPS_DELETE_TIME_GLO )
    {
      delete_req.deleteGnssDataMask_valid = 1;
      delete_req.deleteGnssDataMask |= QMI_LOC_MASK_DELETE_GLO_TIME_V02;
    }
  }

  req_union.pDeleteAssistDataReq = &delete_req;

  status = loc_sync_send_req(clientHandle,
                             QMI_LOC_DELETE_ASSIST_DATA_REQ_V02,
                             req_union, LOC_ENGINE_SYNC_REQUEST_TIMEOUT,
                             QMI_LOC_DELETE_ASSIST_DATA_IND_V02,
                             &delete_resp);

  if (status != eLOC_CLIENT_SUCCESS ||
      eQMI_LOC_SUCCESS_V02 != delete_resp.status)
  {
    LOC_LOGE ("%s:%d]: error! status = %s, delete_resp.status = %s\n",
              __func__, __LINE__,
              loc_get_v02_client_status_name(status),
              loc_get_v02_qmi_status_name(delete_resp.status));

   return LOC_API_ADAPTER_ERR_GENERAL_FAILURE;
  }

  return LOC_API_ADAPTER_ERR_SUCCESS;
}

/* send NI user repsonse to the engine */
enum loc_api_adapter_err LocApiV02Adapter ::
    informNiResponse(GpsUserResponseType userResponse,
                     const void* passThroughData)
{
  locClientReqUnionType req_union;
  locClientStatusEnumType status;

  qmiLocNiUserRespReqMsgT_v02 ni_resp;
  qmiLocNiUserRespIndMsgT_v02 ni_resp_ind;

  qmiLocEventNiNotifyVerifyReqIndMsgT_v02 *request_pass_back =
    (qmiLocEventNiNotifyVerifyReqIndMsgT_v02 *)passThroughData;

  memset(&ni_resp,0, sizeof(ni_resp));

  memset(&ni_resp_ind,0, sizeof(ni_resp_ind));

  switch (userResponse)
  {
    case GPS_NI_RESPONSE_ACCEPT:
      ni_resp.userResp = eQMI_LOC_NI_LCS_NOTIFY_VERIFY_ACCEPT_V02;
      break;
   case GPS_NI_RESPONSE_DENY:
      ni_resp.userResp = eQMI_LOC_NI_LCS_NOTIFY_VERIFY_DENY_V02;
      break;
   case GPS_NI_RESPONSE_NORESP:
      ni_resp.userResp = eQMI_LOC_NI_LCS_NOTIFY_VERIFY_NORESP_V02;
      break;
   default:
      return LOC_API_ADAPTER_ERR_INVALID_PARAMETER;
  }

  LOC_LOGV(" %s:%d]: NI response: %d\n", __func__, __LINE__,
                ni_resp.userResp);

  ni_resp.notificationType = request_pass_back->notificationType;

  // copy SUPL payload from request
  if(request_pass_back->NiSuplInd_valid == 1)
  {
     ni_resp.NiSuplPayload_valid = 1;
     memcpy(&(ni_resp.NiSuplPayload), &(request_pass_back->NiSuplInd),
            sizeof(qmiLocNiSuplNotifyVerifyStructT_v02));

  }
  // should this be an "else if"?? we don't need to decide

  // copy UMTS-CP payload from request
  if( request_pass_back->NiUmtsCpInd_valid == 1 )
  {
     ni_resp.NiUmtsCpPayload_valid = 1;
     memcpy(&(ni_resp.NiUmtsCpPayload), &(request_pass_back->NiUmtsCpInd),
            sizeof(qmiLocNiUmtsCpNotifyVerifyStructT_v02));
  }

  //copy Vx payload from the request
  if( request_pass_back->NiVxInd_valid == 1)
  {
     ni_resp.NiVxPayload_valid = 1;
     memcpy(&(ni_resp.NiVxPayload), &(request_pass_back->NiVxInd),
            sizeof(qmiLocNiVxNotifyVerifyStructT_v02));
  }

  // copy Vx service interaction payload from the request
  if(request_pass_back->NiVxServiceInteractionInd_valid == 1)
  {
     ni_resp.NiVxServiceInteractionPayload_valid = 1;
     memcpy(&(ni_resp.NiVxServiceInteractionPayload),
            &(request_pass_back->NiVxServiceInteractionInd),
            sizeof(qmiLocNiVxServiceInteractionStructT_v02));
  }

  req_union.pNiUserRespReq = &ni_resp;

  status = loc_sync_send_req (
     clientHandle, QMI_LOC_NI_USER_RESPONSE_REQ_V02,
     req_union, LOC_ENGINE_SYNC_REQUEST_TIMEOUT,
     QMI_LOC_NI_USER_RESPONSE_IND_V02, &ni_resp_ind);

  if (status != eLOC_CLIENT_SUCCESS ||
      eQMI_LOC_SUCCESS_V02 != ni_resp_ind.status)
  {
    LOC_LOGE ("%s:%d]: error! status = %s, ni_resp_ind.status = %s\n",
              __func__, __LINE__,
              loc_get_v02_client_status_name(status),
              loc_get_v02_qmi_status_name(ni_resp_ind.status));

   return LOC_API_ADAPTER_ERR_GENERAL_FAILURE;
  }

  return LOC_API_ADAPTER_ERR_SUCCESS;
}

/* Set UMTs SLP server URL */
enum loc_api_adapter_err LocApiV02Adapter :: setServer(
  const char* url, int len)
{
  locClientReqUnionType req_union;
  locClientStatusEnumType status;
  qmiLocSetServerReqMsgT_v02 set_server_req;
  qmiLocSetServerIndMsgT_v02 set_server_ind;

  if(len <=0 || len > sizeof(set_server_req.urlAddr))
  {
    LOC_LOGE("%s:%d]: len = %d greater than max allowed url length\n",
                  __func__, __LINE__, len);

    return LOC_API_ADAPTER_ERR_INVALID_PARAMETER;
  }

  memset(&set_server_req, 0, sizeof(set_server_req));

  LOC_LOGD("%s:%d]:, url = %s, len = %d\n", __func__, __LINE__, url, len);

  set_server_req.serverType = eQMI_LOC_SERVER_TYPE_UMTS_SLP_V02;

  set_server_req.urlAddr_valid = 1;

  strlcpy(set_server_req.urlAddr, url, sizeof(set_server_req.urlAddr));

  req_union.pSetServerReq = &set_server_req;

  status = loc_sync_send_req(clientHandle,
                             QMI_LOC_SET_SERVER_REQ_V02,
                             req_union, LOC_ENGINE_SYNC_REQUEST_TIMEOUT,
                             QMI_LOC_SET_SERVER_IND_V02,
                             &set_server_ind);

  if (status != eLOC_CLIENT_SUCCESS ||
         eQMI_LOC_SUCCESS_V02 != set_server_ind.status)
  {
    LOC_LOGE ("%s:%d]: error status = %s, set_server_ind.status = %s\n",
              __func__,__LINE__,
              loc_get_v02_client_status_name(status),
              loc_get_v02_qmi_status_name(set_server_ind.status));

    return LOC_API_ADAPTER_ERR_GENERAL_FAILURE;
  }

  return LOC_API_ADAPTER_ERR_SUCCESS;
}

enum loc_api_adapter_err LocApiV02Adapter ::
    setServer(unsigned int ip, int port, LocServerType type)
{
  locClientReqUnionType req_union;
  locClientStatusEnumType status;
  qmiLocSetServerReqMsgT_v02 set_server_req;
  qmiLocSetServerIndMsgT_v02 set_server_ind;
  qmiLocServerTypeEnumT_v02 set_server_cmd;

  switch (type) {
  case LOC_AGPS_MPC_SERVER:
      set_server_cmd = eQMI_LOC_SERVER_TYPE_CDMA_MPC_V02;
      break;
  case LOC_AGPS_CUSTOM_PDE_SERVER:
      set_server_cmd = eQMI_LOC_SERVER_TYPE_CUSTOM_PDE_V02;
      break;
  default:
      set_server_cmd = eQMI_LOC_SERVER_TYPE_CDMA_PDE_V02;
      break;
  }

  memset(&set_server_req, 0, sizeof(set_server_req));

  LOC_LOGD("%s:%d]:, ip = %u, port = %d\n", __func__, __LINE__, ip, port);

  set_server_req.serverType = set_server_cmd;
  set_server_req.ipv4Addr_valid = 1;
  set_server_req.ipv4Addr.addr = ip;
  set_server_req.ipv4Addr.port = port;

  req_union.pSetServerReq = &set_server_req;

  status = loc_sync_send_req(clientHandle,
                             QMI_LOC_SET_SERVER_REQ_V02,
                             req_union, LOC_ENGINE_SYNC_REQUEST_TIMEOUT,
                             QMI_LOC_SET_SERVER_IND_V02,
                             &set_server_ind);

    if (status != eLOC_CLIENT_SUCCESS ||
         eQMI_LOC_SUCCESS_V02 != set_server_ind.status)
    {
      LOC_LOGE ("%s:%d]: error status = %s, set_server_ind.status = %s\n",
                __func__,__LINE__,
                loc_get_v02_client_status_name(status),
                loc_get_v02_qmi_status_name(set_server_ind.status));

      return LOC_API_ADAPTER_ERR_GENERAL_FAILURE;
    }

    return LOC_API_ADAPTER_ERR_SUCCESS;
}

/* Inject XTRA data, this module breaks down the XTRA
   file into "chunks" and injects them one at a time */
enum loc_api_adapter_err LocApiV02Adapter :: setXtraData(
  char* data, int length)
{
  locClientStatusEnumType status = eLOC_CLIENT_SUCCESS;
  int     total_parts;
  uint8_t   part;
  uint16_t  len_injected;

  locClientReqUnionType req_union;
  qmiLocInjectPredictedOrbitsDataReqMsgT_v02 inject_xtra;
  qmiLocInjectPredictedOrbitsDataIndMsgT_v02 inject_xtra_ind;

  req_union.pInjectPredictedOrbitsDataReq = &inject_xtra;

  LOC_LOGD("%s:%d]: xtra size = %d\n", __func__, __LINE__, length);

  inject_xtra.formatType_valid = 1;
  inject_xtra.formatType = eQMI_LOC_PREDICTED_ORBITS_XTRA_V02;
  inject_xtra.totalSize = length;

  total_parts = ((length - 1) / QMI_LOC_MAX_PREDICTED_ORBITS_PART_LEN_V02) + 1;

  inject_xtra.totalParts = total_parts;

  len_injected = 0; // O bytes injected

  // XTRA injection starts with part 1
  for (part = 1; part <= total_parts; part++)
  {
    inject_xtra.partNum = part;

    if (QMI_LOC_MAX_PREDICTED_ORBITS_PART_LEN_V02 > (length - len_injected))
    {
      inject_xtra.partData_len = length - len_injected;
    }
    else
    {
      inject_xtra.partData_len = QMI_LOC_MAX_PREDICTED_ORBITS_PART_LEN_V02;
    }

    // copy data into the message
    memcpy(inject_xtra.partData, data+len_injected, inject_xtra.partData_len);

    LOC_LOGD("[%s:%d] part %d/%d, len = %d, total injected = %d\n",
                  __func__, __LINE__,
                  inject_xtra.partNum, total_parts, inject_xtra.partData_len,
                  len_injected);

    status = loc_sync_send_req( clientHandle,
                                QMI_LOC_INJECT_PREDICTED_ORBITS_DATA_REQ_V02,
                                req_union, LOC_ENGINE_SYNC_REQUEST_TIMEOUT,
                                QMI_LOC_INJECT_PREDICTED_ORBITS_DATA_IND_V02,
                                &inject_xtra_ind);

    if (status != eLOC_CLIENT_SUCCESS ||
        eQMI_LOC_SUCCESS_V02 != inject_xtra_ind.status ||
        inject_xtra.partNum != inject_xtra_ind.partNum)
    {
      LOC_LOGE ("%s:%d]: failed status = %s, inject_pos_ind.status = %s,"
                     " part num = %d, ind.partNum = %d\n", __func__, __LINE__,
                loc_get_v02_client_status_name(status),
                loc_get_v02_qmi_status_name(inject_xtra_ind.status),
                inject_xtra.partNum, inject_xtra_ind.partNum);

      return LOC_API_ADAPTER_ERR_GENERAL_FAILURE;
      break;
    }

    len_injected += inject_xtra.partData_len;
    LOC_LOGD("%s:%d]: XTRA injected length: %d\n", __func__, __LINE__,
        len_injected);
  }

  return LOC_API_ADAPTER_ERR_SUCCESS;
}

enum loc_api_adapter_err LocApiV02Adapter :: atlOpenStatus(
  int handle, int is_succ, char* apn, AGpsBearerType bear,
  AGpsType agpsType)
{
  locClientStatusEnumType result = eLOC_CLIENT_SUCCESS;
  locClientReqUnionType req_union;
  qmiLocInformLocationServerConnStatusReqMsgT_v02 conn_status_req;
  qmiLocInformLocationServerConnStatusIndMsgT_v02 conn_status_ind;

  LOC_LOGD("%s:%d]: ATL open handle = %d, is_succ = %d, "
                "APN = [%s], bearer = %d \n",  __func__, __LINE__,
                handle, is_succ, apn, bear);

  memset(&conn_status_req, 0, sizeof(conn_status_req));
  memset(&conn_status_ind, 0, sizeof(conn_status_ind));

        // Fill in data
  conn_status_req.connHandle = handle;

  conn_status_req.requestType = eQMI_LOC_SERVER_REQUEST_OPEN_V02;

  if(is_succ)
  {
    conn_status_req.statusType = eQMI_LOC_SERVER_REQ_STATUS_SUCCESS_V02;

    strlcpy(conn_status_req.apnProfile.apnName, apn,
            sizeof(conn_status_req.apnProfile.apnName) );

    switch(bear)
    {
      case AGPS_APN_BEARER_IPV4:
        conn_status_req.apnProfile.pdnType =
          eQMI_LOC_APN_PROFILE_PDN_TYPE_IPV4_V02;
        break;

      case AGPS_APN_BEARER_IPV6:
        conn_status_req.apnProfile.pdnType =
          eQMI_LOC_APN_PROFILE_PDN_TYPE_IPV6_V02;
        break;

      case AGPS_APN_BEARER_IPV4V6:
        conn_status_req.apnProfile.pdnType =
          eQMI_LOC_APN_PROFILE_PDN_TYPE_IPV4V6_V02;
        break;

      default:
        LOC_LOGE("%s:%d]:invalid bearer type\n",__func__,__LINE__);
        return LOC_API_ADAPTER_ERR_INVALID_HANDLE;
    }

    conn_status_req.apnProfile_valid = 1;
  }
  else
  {
    conn_status_req.statusType = eQMI_LOC_SERVER_REQ_STATUS_FAILURE_V02;
  }

  req_union.pInformLocationServerConnStatusReq = &conn_status_req;

  result = loc_sync_send_req(clientHandle,
                             QMI_LOC_INFORM_LOCATION_SERVER_CONN_STATUS_REQ_V02,
                             req_union, LOC_ENGINE_SYNC_REQUEST_TIMEOUT,
                             QMI_LOC_INFORM_LOCATION_SERVER_CONN_STATUS_IND_V02,
                             &conn_status_ind);

  if(result != eLOC_CLIENT_SUCCESS ||
     eQMI_LOC_SUCCESS_V02 != conn_status_ind.status)
  {
    LOC_LOGE ("%s:%d]: Error status = %s, ind..status = %s ",
              __func__, __LINE__,
              loc_get_v02_client_status_name(result),
              loc_get_v02_qmi_status_name(conn_status_ind.status));

    return LOC_API_ADAPTER_ERR_GENERAL_FAILURE;
  }

  return LOC_API_ADAPTER_ERR_SUCCESS;

}

/* close atl connection */
enum loc_api_adapter_err LocApiV02Adapter :: atlCloseStatus(
  int handle, int is_succ)
{
  locClientStatusEnumType result = eLOC_CLIENT_SUCCESS;
  locClientReqUnionType req_union;
  qmiLocInformLocationServerConnStatusReqMsgT_v02 conn_status_req;
  qmiLocInformLocationServerConnStatusIndMsgT_v02 conn_status_ind;

  LOC_LOGD("%s:%d]: ATL close handle = %d, is_succ = %d\n",
                 __func__, __LINE__,  handle, is_succ);

  memset(&conn_status_req, 0, sizeof(conn_status_req));
  memset(&conn_status_ind, 0, sizeof(conn_status_ind));

        // Fill in data
  conn_status_req.connHandle = handle;

  conn_status_req.requestType = eQMI_LOC_SERVER_REQUEST_CLOSE_V02;

  if(is_succ)
  {
    conn_status_req.statusType = eQMI_LOC_SERVER_REQ_STATUS_SUCCESS_V02;
  }
  else
  {
    conn_status_req.statusType = eQMI_LOC_SERVER_REQ_STATUS_FAILURE_V02;
  }

  req_union.pInformLocationServerConnStatusReq = &conn_status_req;

  result = loc_sync_send_req(clientHandle,
                             QMI_LOC_INFORM_LOCATION_SERVER_CONN_STATUS_REQ_V02,
                             req_union, LOC_ENGINE_SYNC_REQUEST_TIMEOUT,
                             QMI_LOC_INFORM_LOCATION_SERVER_CONN_STATUS_IND_V02,
                             &conn_status_ind);

  if(result != eLOC_CLIENT_SUCCESS ||
     eQMI_LOC_SUCCESS_V02 != conn_status_ind.status)
  {
    LOC_LOGE ("%s:%d]: Error status = %s, ind..status = %s ",
              __func__, __LINE__,
              loc_get_v02_client_status_name(result),
              loc_get_v02_qmi_status_name(conn_status_ind.status));

    return LOC_API_ADAPTER_ERR_GENERAL_FAILURE;
  }

  return LOC_API_ADAPTER_ERR_SUCCESS;
}

/* set the SUPL version */
enum loc_api_adapter_err LocApiV02Adapter :: setSUPLVersion(uint32_t version)
{
  locClientStatusEnumType result = eLOC_CLIENT_SUCCESS;
  locClientReqUnionType req_union;

  qmiLocSetProtocolConfigParametersReqMsgT_v02 supl_config_req;
  qmiLocSetProtocolConfigParametersIndMsgT_v02 supl_config_ind;

  LOC_LOGD("%s:%d]: supl version = %d\n",  __func__, __LINE__, version);


  memset(&supl_config_req, 0, sizeof(supl_config_req));
  memset(&supl_config_ind, 0, sizeof(supl_config_ind));

   supl_config_req.suplVersion_valid = 1;
   // SUPL version from MSByte to LSByte:
   // (reserved)(major version)(minor version)(serviceIndicator)

   supl_config_req.suplVersion = (version == 0x00020000)?
     eQMI_LOC_SUPL_VERSION_2_0_V02 : eQMI_LOC_SUPL_VERSION_1_0_V02;

  req_union.pSetProtocolConfigParametersReq = &supl_config_req;

  result = loc_sync_send_req(clientHandle,
                             QMI_LOC_SET_PROTOCOL_CONFIG_PARAMETERS_REQ_V02,
                             req_union, LOC_ENGINE_SYNC_REQUEST_TIMEOUT,
                             QMI_LOC_SET_PROTOCOL_CONFIG_PARAMETERS_IND_V02,
                             &supl_config_ind);

  if(result != eLOC_CLIENT_SUCCESS ||
     eQMI_LOC_SUCCESS_V02 != supl_config_ind.status)
  {
    LOC_LOGE ("%s:%d]: Error status = %s, ind..status = %s ",
              __func__, __LINE__,
              loc_get_v02_client_status_name(result),
              loc_get_v02_qmi_status_name(supl_config_ind.status));

    return LOC_API_ADAPTER_ERR_GENERAL_FAILURE;
  }

  return LOC_API_ADAPTER_ERR_SUCCESS;
}

/* set the configuration for LTE positioning profile (LPP) */
enum loc_api_adapter_err LocApiV02Adapter :: setLPPConfig(uint32_t profile)
{
  locClientStatusEnumType result = eLOC_CLIENT_SUCCESS;
  locClientReqUnionType req_union;
  qmiLocSetProtocolConfigParametersReqMsgT_v02 lpp_config_req;
  qmiLocSetProtocolConfigParametersIndMsgT_v02 lpp_config_ind;

  LOC_LOGD("%s:%d]: lpp profile = %d\n",  __func__, __LINE__, profile);

  memset(&lpp_config_req, 0, sizeof(lpp_config_req));
  memset(&lpp_config_ind, 0, sizeof(lpp_config_ind));

  lpp_config_req.lppConfig_valid = 1;

  lpp_config_req.lppConfig = profile;

  req_union.pSetProtocolConfigParametersReq = &lpp_config_req;

  result = loc_sync_send_req(clientHandle,
                             QMI_LOC_SET_PROTOCOL_CONFIG_PARAMETERS_REQ_V02,
                             req_union, LOC_ENGINE_SYNC_REQUEST_TIMEOUT,
                             QMI_LOC_SET_PROTOCOL_CONFIG_PARAMETERS_IND_V02,
                             &lpp_config_ind);

  if(result != eLOC_CLIENT_SUCCESS ||
     eQMI_LOC_SUCCESS_V02 != lpp_config_ind.status)
  {
    LOC_LOGE ("%s:%d]: Error status = %s, ind..status = %s ",
              __func__, __LINE__,
              loc_get_v02_client_status_name(result),
              loc_get_v02_qmi_status_name(lpp_config_ind.status));

    return LOC_API_ADAPTER_ERR_GENERAL_FAILURE;
  }
  return LOC_API_ADAPTER_ERR_SUCCESS;
}

/* set the Sensor Configuration */
enum loc_api_adapter_err LocApiV02Adapter :: setSensorControlConfig(int sensorsDisabled)
{
  locClientStatusEnumType result = eLOC_CLIENT_SUCCESS;
  locClientReqUnionType req_union;

  qmiLocSetSensorControlConfigReqMsgT_v02 sensor_config_req;
  qmiLocSetSensorControlConfigIndMsgT_v02 sensor_config_ind;

  LOC_LOGD("%s:%d]: sensors disabled = %d\n",  __func__, __LINE__, sensorsDisabled);

  memset(&sensor_config_req, 0, sizeof(sensor_config_req));
  memset(&sensor_config_ind, 0, sizeof(sensor_config_ind));

  sensor_config_req.sensorsUsage_valid = 1;
  sensor_config_req.sensorsUsage = (sensorsDisabled == 1) ? eQMI_LOC_SENSOR_CONFIG_SENSOR_USE_DISABLE_V02
                                    : eQMI_LOC_SENSOR_CONFIG_SENSOR_USE_ENABLE_V02;

  req_union.pSetSensorControlConfigReq = &sensor_config_req;

  result = loc_sync_send_req(clientHandle,
                             QMI_LOC_SET_SENSOR_CONTROL_CONFIG_REQ_V02,
                             req_union, LOC_ENGINE_SYNC_REQUEST_TIMEOUT,
                             QMI_LOC_SET_SENSOR_CONTROL_CONFIG_IND_V02,
                             &sensor_config_ind);

  if(result != eLOC_CLIENT_SUCCESS ||
     eQMI_LOC_SUCCESS_V02 != sensor_config_ind.status)
  {
    LOC_LOGE ("%s:%d]: Error status = %s, ind..status = %s ",
              __func__, __LINE__,
              loc_get_v02_client_status_name(result),
              loc_get_v02_qmi_status_name(sensor_config_ind.status));

    return LOC_API_ADAPTER_ERR_GENERAL_FAILURE;
  }

  return LOC_API_ADAPTER_ERR_SUCCESS;
}

/* set the Sensor Properties */
enum loc_api_adapter_err LocApiV02Adapter :: setSensorProperties(bool gyroBiasVarianceRandomWalk_valid, float gyroBiasVarianceRandomWalk,
                            bool accelBiasVarianceRandomWalk_valid, float accelBiasVarianceRandomWalk,
                            bool angleBiasVarianceRandomWalk_valid, float angleBiasVarianceRandomWalk,
                            bool rateBiasVarianceRandomWalk_valid, float rateBiasVarianceRandomWalk,
                            bool velocityBiasVarianceRandomWalk_valid, float velocityBiasVarianceRandomWalk)
{
  locClientStatusEnumType result = eLOC_CLIENT_SUCCESS;
  locClientReqUnionType req_union;

  qmiLocSetSensorPropertiesReqMsgT_v02 sensor_prop_req;
  qmiLocSetSensorPropertiesIndMsgT_v02 sensor_prop_ind;

  LOC_LOGI("%s:%d]: sensors prop: gyroBiasRandomWalk = %f, accelRandomWalk = %f, "
           "angleRandomWalk = %f, rateRandomWalk = %f, velocityRandomWalk = %f\n",
                 __func__, __LINE__, gyroBiasVarianceRandomWalk, accelBiasVarianceRandomWalk,
           angleBiasVarianceRandomWalk, rateBiasVarianceRandomWalk, velocityBiasVarianceRandomWalk);

  memset(&sensor_prop_req, 0, sizeof(sensor_prop_req));
  memset(&sensor_prop_ind, 0, sizeof(sensor_prop_ind));

  /* Set the validity bit and value for each sensor property */
  sensor_prop_req.gyroBiasVarianceRandomWalk_valid = gyroBiasVarianceRandomWalk_valid;
  sensor_prop_req.gyroBiasVarianceRandomWalk = gyroBiasVarianceRandomWalk;

  sensor_prop_req.accelerationRandomWalkSpectralDensity_valid = accelBiasVarianceRandomWalk_valid;
  sensor_prop_req.accelerationRandomWalkSpectralDensity = accelBiasVarianceRandomWalk;

  sensor_prop_req.angleRandomWalkSpectralDensity_valid = angleBiasVarianceRandomWalk_valid;
  sensor_prop_req.angleRandomWalkSpectralDensity = angleBiasVarianceRandomWalk;

  sensor_prop_req.rateRandomWalkSpectralDensity_valid = rateBiasVarianceRandomWalk_valid;
  sensor_prop_req.rateRandomWalkSpectralDensity = rateBiasVarianceRandomWalk;

  sensor_prop_req.velocityRandomWalkSpectralDensity_valid = velocityBiasVarianceRandomWalk_valid;
  sensor_prop_req.velocityRandomWalkSpectralDensity = velocityBiasVarianceRandomWalk;

  req_union.pSetSensorPropertiesReq = &sensor_prop_req;

  result = loc_sync_send_req(clientHandle,
                             QMI_LOC_SET_SENSOR_PROPERTIES_REQ_V02,
                             req_union, LOC_ENGINE_SYNC_REQUEST_TIMEOUT,
                             QMI_LOC_SET_SENSOR_PROPERTIES_IND_V02,
                             &sensor_prop_ind);

  if(result != eLOC_CLIENT_SUCCESS ||
     eQMI_LOC_SUCCESS_V02 != sensor_prop_ind.status)
  {
    LOC_LOGE ("%s:%d]: Error status = %s, ind..status = %s ",
              __func__, __LINE__,
              loc_get_v02_client_status_name(result),
              loc_get_v02_qmi_status_name(sensor_prop_ind.status));

    return LOC_API_ADAPTER_ERR_GENERAL_FAILURE;
  }

  return LOC_API_ADAPTER_ERR_SUCCESS;
}

/* set the Sensor Performance Config */
enum loc_api_adapter_err LocApiV02Adapter :: setSensorPerfControlConfig(int controlMode,
                                                                        int accelSamplesPerBatch, int accelBatchesPerSec,
                                                                        int gyroSamplesPerBatch, int gyroBatchesPerSec,
                                                                        int accelSamplesPerBatchHigh, int accelBatchesPerSecHigh,
                                                                        int gyroSamplesPerBatchHigh, int gyroBatchesPerSecHigh,
                                                                        int algorithmConfig)
{
  locClientStatusEnumType result = eLOC_CLIENT_SUCCESS;
  locClientReqUnionType req_union;

  qmiLocSetSensorPerformanceControlConfigReqMsgT_v02 sensor_perf_config_req;
  qmiLocSetSensorPerformanceControlConfigIndMsgT_v02 sensor_perf_config_ind;

  LOC_LOGD("%s:%d]: Sensor Perf Control Config (performanceControlMode)(%u) "
                "accel(#smp,#batches) (%u,%u) gyro(#smp,#batches) (%u,%u) "
                "accel_high(#smp,#batches) (%u,%u) gyro_high(#smp,#batches) (%u,%u) "
                "algorithmConfig(%u)\n",
                __FUNCTION__,
                __LINE__,
                controlMode,
                accelSamplesPerBatch,
                accelBatchesPerSec,
                gyroSamplesPerBatch,
                gyroBatchesPerSec,
                accelSamplesPerBatchHigh,
                accelBatchesPerSecHigh,
                gyroSamplesPerBatchHigh,
                gyroBatchesPerSecHigh,
                algorithmConfig
                );

  memset(&sensor_perf_config_req, 0, sizeof(sensor_perf_config_req));
  memset(&sensor_perf_config_ind, 0, sizeof(sensor_perf_config_ind));

  sensor_perf_config_req.performanceControlMode_valid = 1;
  sensor_perf_config_req.performanceControlMode = (qmiLocSensorPerformanceControlModeEnumT_v02)controlMode;
  sensor_perf_config_req.accelSamplingSpec_valid = 1;
  sensor_perf_config_req.accelSamplingSpec.batchesPerSecond = accelBatchesPerSec;
  sensor_perf_config_req.accelSamplingSpec.samplesPerBatch = accelSamplesPerBatch;
  sensor_perf_config_req.gyroSamplingSpec_valid = 1;
  sensor_perf_config_req.gyroSamplingSpec.batchesPerSecond = gyroBatchesPerSec;
  sensor_perf_config_req.gyroSamplingSpec.samplesPerBatch = gyroSamplesPerBatch;
  sensor_perf_config_req.accelSamplingSpecHigh_valid = 1;
  sensor_perf_config_req.accelSamplingSpecHigh.batchesPerSecond = accelBatchesPerSecHigh;
  sensor_perf_config_req.accelSamplingSpecHigh.samplesPerBatch = accelSamplesPerBatchHigh;
  sensor_perf_config_req.gyroSamplingSpecHigh_valid = 1;
  sensor_perf_config_req.gyroSamplingSpecHigh.batchesPerSecond = gyroBatchesPerSecHigh;
  sensor_perf_config_req.gyroSamplingSpecHigh.samplesPerBatch = gyroSamplesPerBatchHigh;
  sensor_perf_config_req.algorithmConfig_valid = 1;
  sensor_perf_config_req.algorithmConfig = algorithmConfig;

  req_union.pSetSensorPerformanceControlConfigReq = &sensor_perf_config_req;

  result = loc_sync_send_req(clientHandle,
                             QMI_LOC_SET_SENSOR_PERFORMANCE_CONTROL_CONFIGURATION_REQ_V02,
                             req_union, LOC_ENGINE_SYNC_REQUEST_TIMEOUT,
                             QMI_LOC_SET_SENSOR_PERFORMANCE_CONTROL_CONFIGURATION_IND_V02,
                             &sensor_perf_config_ind);

  if(result != eLOC_CLIENT_SUCCESS ||
     eQMI_LOC_SUCCESS_V02 != sensor_perf_config_ind.status)
  {
    LOC_LOGE ("%s:%d]: Error status = %s, ind..status = %s ",
              __func__, __LINE__,
              loc_get_v02_client_status_name(result),
              loc_get_v02_qmi_status_name(sensor_perf_config_ind.status));

    return LOC_API_ADAPTER_ERR_GENERAL_FAILURE;
  }

  return LOC_API_ADAPTER_ERR_SUCCESS;
}

/* set the External Power Config */
enum loc_api_adapter_err LocApiV02Adapter :: setExtPowerConfig(int isBatteryCharging)
{
  locClientStatusEnumType result = eLOC_CLIENT_SUCCESS;
  locClientReqUnionType req_union;

  qmiLocSetExternalPowerConfigReqMsgT_v02 ext_pwr_req;
  qmiLocGetExternalPowerConfigIndMsgT_v02 ext_pwr_ind;

  LOC_LOGI("%s:%d]: Ext Pwr Config (isBatteryCharging)(%u)",
                __FUNCTION__,
                __LINE__,
                isBatteryCharging
                );

  memset(&ext_pwr_req, 0, sizeof(ext_pwr_req));
  memset(&ext_pwr_ind, 0, sizeof(ext_pwr_ind));

  switch(isBatteryCharging)
  {
    /* Charging */
    case 1:
      ext_pwr_req.externalPowerState = eQMI_LOC_EXTERNAL_POWER_CONNECTED_V02;
      break;

    /* Not charging */
    case 0:
      ext_pwr_req.externalPowerState = eQMI_LOC_EXTERNAL_POWER_NOT_CONNECTED_V02;
      break;

    default:
      LOC_LOGE("%s:%d]: Invalid ext power state = %d!",
                    __FUNCTION__,
                    __LINE__,
                    isBatteryCharging);
      return LOC_API_ADAPTER_ERR_INVALID_PARAMETER;
      break;
  }

  req_union.pSetExternalPowerConfigReq = &ext_pwr_req;

  result = loc_sync_send_req(clientHandle,
                             QMI_LOC_SET_EXTERNAL_POWER_CONFIG_REQ_V02,
                             req_union, LOC_ENGINE_SYNC_REQUEST_TIMEOUT,
                             QMI_LOC_SET_EXTERNAL_POWER_CONFIG_IND_V02,
                             &ext_pwr_ind);

  if(result != eLOC_CLIENT_SUCCESS ||
     eQMI_LOC_SUCCESS_V02 != ext_pwr_ind.status)
  {
    LOC_LOGE ("%s:%d]: Error status = %d, ind..status = %d ",
                    __func__, __LINE__, result, ext_pwr_ind.status);

    return LOC_API_ADAPTER_ERR_GENERAL_FAILURE;
  }

  return LOC_API_ADAPTER_ERR_SUCCESS;
}

/* Convert event mask from loc eng to loc_api_v02 format */
locClientEventMaskType LocApiV02Adapter :: convertMask(
  LOC_API_ADAPTER_EVENT_MASK_T mask)
{
  locClientEventMaskType eventMask = 0;
  LOC_LOGD("%s:%d]: adapter mask = %u\n", __func__, __LINE__, mask);

  if(mask & LOC_API_ADAPTER_BIT_PARSED_POSITION_REPORT)
    eventMask |= QMI_LOC_EVENT_MASK_POSITION_REPORT_V02;

  if(mask & LOC_API_ADAPTER_BIT_SATELLITE_REPORT)
    eventMask |= QMI_LOC_EVENT_MASK_GNSS_SV_INFO_V02;

  /* treat NMEA_1Hz and NMEA_POSITION_REPORT the same*/
  if( (mask & LOC_API_ADAPTER_BIT_NMEA_POSITION_REPORT) ||
      (mask & LOC_API_ADAPTER_BIT_NMEA_1HZ_REPORT) )
    eventMask |= QMI_LOC_EVENT_MASK_NMEA_V02;

  if(mask & LOC_API_ADAPTER_BIT_NI_NOTIFY_VERIFY_REQUEST)
    eventMask |= QMI_LOC_EVENT_MASK_NI_NOTIFY_VERIFY_REQ_V02;

  if(mask & LOC_API_ADAPTER_BIT_ASSISTANCE_DATA_REQUEST)
  {
    // TBD: This needs to be decoupled in the HAL
    eventMask |= QMI_LOC_EVENT_MASK_INJECT_PREDICTED_ORBITS_REQ_V02;
    eventMask |= QMI_LOC_EVENT_MASK_INJECT_TIME_REQ_V02;
    eventMask |= QMI_LOC_EVENT_MASK_INJECT_POSITION_REQ_V02;
  }

  if(mask & LOC_API_ADAPTER_BIT_STATUS_REPORT)
  {
    eventMask |= (QMI_LOC_EVENT_MASK_ENGINE_STATE_V02);
  }

  if(mask & LOC_API_ADAPTER_BIT_LOCATION_SERVER_REQUEST)
    eventMask |= QMI_LOC_EVENT_MASK_LOCATION_SERVER_CONNECTION_REQ_V02;

  return eventMask;
}

/* Convert error from loc_api_v02 to loc eng format*/
enum loc_api_adapter_err LocApiV02Adapter :: convertErr(
  locClientStatusEnumType status)
{
  switch( status)
  {
    case LOC_API_ADAPTER_ERR_SUCCESS:
      return LOC_API_ADAPTER_ERR_SUCCESS;

    case eLOC_CLIENT_FAILURE_GENERAL:
      return LOC_API_ADAPTER_ERR_GENERAL_FAILURE;

    case eLOC_CLIENT_FAILURE_UNSUPPORTED:
      return LOC_API_ADAPTER_ERR_UNSUPPORTED;

    case eLOC_CLIENT_FAILURE_INVALID_PARAMETER:
      return LOC_API_ADAPTER_ERR_INVALID_PARAMETER;

    case eLOC_CLIENT_FAILURE_ENGINE_BUSY:
      return LOC_API_ADAPTER_ERR_ENGINE_BUSY;

    case eLOC_CLIENT_FAILURE_PHONE_OFFLINE:
      return LOC_API_ADAPTER_ERR_PHONE_OFFLINE;

    case eLOC_CLIENT_FAILURE_TIMEOUT:
      return LOC_API_ADAPTER_ERR_TIMEOUT;

    case eLOC_CLIENT_FAILURE_INVALID_HANDLE:
      return LOC_API_ADAPTER_ERR_INVALID_HANDLE;

    case eLOC_CLIENT_FAILURE_SERVICE_NOT_PRESENT:
      return LOC_API_ADAPTER_ERR_SERVICE_NOT_PRESENT;

    default:
      return LOC_API_ADAPTER_ERR_FAILURE;
  }
}

/* convert position report to loc eng format and send the converted
   position to loc eng */

void LocApiV02Adapter :: reportPosition (
  const qmiLocEventPositionReportIndMsgT_v02 *location_report_ptr)
{
    GpsLocation location;
    LocPosTechMask tech_Mask = LOC_POS_TECH_MASK_DEFAULT;
    LOC_LOGD("Reporting postion from V2 Adapter\n");
    memset(&location, 0, sizeof (GpsLocation));
    location.size = sizeof(location);
    GpsLocationExtended locationExtended;
    memset(&locationExtended, 0, sizeof (GpsLocationExtended));
    locationExtended.size = sizeof(locationExtended);
    // Process the position from final and intermediate reports

    if( (location_report_ptr->sessionStatus == eQMI_LOC_SESS_STATUS_SUCCESS_V02) ||
        (location_report_ptr->sessionStatus == eQMI_LOC_SESS_STATUS_IN_PROGRESS_V02)
        )
    {
        // Latitude & Longitude
        if( (location_report_ptr->latitude_valid == 1 ) &&
            (location_report_ptr->longitude_valid == 1)  &&
            (location_report_ptr->latitude != 0 ||
             location_report_ptr->longitude!= 0))
        {
            location.flags  |= GPS_LOCATION_HAS_LAT_LONG;
            location.latitude  = location_report_ptr->latitude;
            location.longitude = location_report_ptr->longitude;

            // Time stamp (UTC)
            if(location_report_ptr->timestampUtc_valid == 1)
            {
                location.timestamp = location_report_ptr->timestampUtc;
            }

            // Altitude
            if(location_report_ptr->altitudeWrtEllipsoid_valid == 1  )
            {
                location.flags  |= GPS_LOCATION_HAS_ALTITUDE;
                location.altitude = location_report_ptr->altitudeWrtEllipsoid;
            }

            // Speed
            if((location_report_ptr->speedHorizontal_valid == 1) &&
               (location_report_ptr->speedVertical_valid ==1 ) )
            {
                location.flags  |= GPS_LOCATION_HAS_SPEED;
                location.speed = sqrt(
                    (location_report_ptr->speedHorizontal *
                     location_report_ptr->speedHorizontal) +
                    (location_report_ptr->speedVertical *
                     location_report_ptr->speedVertical) );
            }

            // Heading
            if(location_report_ptr->heading_valid == 1)
            {
                location.flags  |= GPS_LOCATION_HAS_BEARING;
                location.bearing = location_report_ptr->heading;
            }

            // Uncertainty (circular)
            if( (location_report_ptr->horUncCircular_valid ) )
            {
                location.flags  |= GPS_LOCATION_HAS_ACCURACY;
                location.accuracy = location_report_ptr->horUncCircular;
            }

            // Technology Mask
            tech_Mask  |= location_report_ptr->technologyMask;

            //Mark the location source as from GNSS
            location.flags |= LOCATION_HAS_SOURCE_INFO;
            location.position_source = ULP_LOCATION_IS_FROM_GNSS;

            if (location_report_ptr->magneticDeviation_valid)
            {
                locationExtended.flags |= GPS_LOCATION_EXTENDED_HAS_MAG_DEV;
                locationExtended.magneticDeviation = location_report_ptr->magneticDeviation;
            }

            if (location_report_ptr->DOP_valid)
            {
                locationExtended.flags |= GPS_LOCATION_EXTENDED_HAS_DOP;
                locationExtended.pdop = location_report_ptr->DOP.PDOP;
                locationExtended.hdop = location_report_ptr->DOP.HDOP;
                locationExtended.vdop = location_report_ptr->DOP.VDOP;
            }

            if (location_report_ptr->altitudeWrtMeanSeaLevel_valid)
            {
                locationExtended.flags |= GPS_LOCATION_EXTENDED_HAS_ALTITUDE_MEAN_SEA_LEVEL;
                locationExtended.altitudeMeanSeaLevel = location_report_ptr->altitudeWrtMeanSeaLevel;
            }

            LocApiAdapter::reportPosition( location,
                                           locationExtended,
                                           locEngHandle.extPosInfo((void*)location_report_ptr),
                                           (location_report_ptr->sessionStatus
                                            == eQMI_LOC_SESS_STATUS_IN_PROGRESS_V02 ?
                                            LOC_SESS_INTERMEDIATE : LOC_SESS_SUCCESS),
                                           tech_Mask);
        }
    }
    else
    {
        LocApiAdapter::reportPosition(location,
                                      locationExtended,
                                      NULL,
                                      LOC_SESS_FAILURE);

        LOC_LOGD("%s:%d]: Ignoring position report with sess status = %d, "
                      "fix id = %u\n", __func__, __LINE__,
                      location_report_ptr->sessionStatus,
                      location_report_ptr->fixId );
    }
}

/* convert satellite report to loc eng format and  send the converted
   report to loc eng */
void  LocApiV02Adapter :: reportSv (
  const qmiLocEventGnssSvInfoIndMsgT_v02 *gnss_report_ptr)
{
  GpsSvStatus      SvStatus;
  GpsLocationExtended locationExtended;
  int              num_svs_max, i;
  const qmiLocSvInfoStructT_v02 *sv_info_ptr;

  LOC_LOGV ("%s:%d]: num of sv = %d\n", __func__, __LINE__,
                 gnss_report_ptr->svList_len);

  num_svs_max = 0;
  memset (&SvStatus, 0, sizeof (GpsSvStatus));
  memset(&locationExtended, 0, sizeof (GpsLocationExtended));
  locationExtended.size = sizeof(locationExtended);
  if(gnss_report_ptr->svList_valid == 1)
  {
    num_svs_max = gnss_report_ptr->svList_len;
    if(num_svs_max > GPS_MAX_SVS)
    {
      num_svs_max = GPS_MAX_SVS;
    }
    SvStatus.num_svs = 0;
    for(i = 0; i < num_svs_max; i++)
    {
      sv_info_ptr = &(gnss_report_ptr->svList[i]);
      if((sv_info_ptr->validMask & QMI_LOC_SV_INFO_MASK_VALID_SYSTEM_V02) &&
         (sv_info_ptr->validMask & QMI_LOC_SV_INFO_MASK_VALID_GNSS_SVID_V02)
         && (sv_info_ptr->gnssSvId != 0 ))
      {
        if(sv_info_ptr->system == eQMI_LOC_SV_SYSTEM_GPS_V02)
        {
          SvStatus.sv_list[SvStatus.num_svs].size = sizeof(GpsSvStatus);
          SvStatus.sv_list[SvStatus.num_svs].prn = (int)sv_info_ptr->gnssSvId;

          // We only have the data field to report gps eph and alm mask
          if(sv_info_ptr->validMask &
             QMI_LOC_SV_INFO_MASK_VALID_SVINFO_MASK_V02)
          {
            if(sv_info_ptr->svInfoMask &
               QMI_LOC_SVINFO_MASK_HAS_EPHEMERIS_V02)
            {
              SvStatus.ephemeris_mask |= (1 << (sv_info_ptr->gnssSvId-1));
            }
            if(sv_info_ptr->svInfoMask &
               QMI_LOC_SVINFO_MASK_HAS_ALMANAC_V02)
            {
              SvStatus.almanac_mask |= (1 << (sv_info_ptr->gnssSvId-1));
            }
          }

          if((sv_info_ptr->validMask &
              QMI_LOC_SV_INFO_MASK_VALID_PROCESS_STATUS_V02)
             &&
             (sv_info_ptr->svStatus == eQMI_LOC_SV_STATUS_TRACK_V02))
          {
            SvStatus.used_in_fix_mask |= (1 << (sv_info_ptr->gnssSvId-1));
          }
        }
        // SBAS: GPS RPN: 120-151,
        // In exteneded measurement report, we follow nmea standard,
        // which is from 33-64.
        else if(sv_info_ptr->system == eQMI_LOC_SV_SYSTEM_SBAS_V02)
        {
          SvStatus.sv_list[SvStatus.num_svs].prn =
            sv_info_ptr->gnssSvId + 33 - 120;
        }
        // Gloness: Slot id: 1-32
        // In extended measurement report, we follow nmea standard,
        // which is 65-96
        else if(sv_info_ptr->system == eQMI_LOC_SV_SYSTEM_GLONASS_V02)
        {
          SvStatus.sv_list[SvStatus.num_svs].prn =
            sv_info_ptr->gnssSvId + (65-1);
        }
        // Unsupported SV system
        else
        {
          continue;
        }
      }

      if(sv_info_ptr->validMask & QMI_LOC_SV_INFO_MASK_VALID_SNR_V02 )
      {
        SvStatus.sv_list[SvStatus.num_svs].snr = sv_info_ptr->snr;
      }

      if(sv_info_ptr->validMask & QMI_LOC_SV_INFO_MASK_VALID_ELEVATION_V02)
      {
        SvStatus.sv_list[SvStatus.num_svs].elevation = sv_info_ptr->elevation;
      }

      if(sv_info_ptr->validMask & QMI_LOC_SV_INFO_MASK_VALID_AZIMUTH_V02)
      {
        SvStatus.sv_list[SvStatus.num_svs].azimuth = sv_info_ptr->azimuth;
      }

      SvStatus.num_svs++;
    }
  }

  if (SvStatus.num_svs >= 0)
  {
    LOC_LOGV ("%s:%d]: firing SV callback\n", __func__, __LINE__);
    LocApiAdapter::reportSv(SvStatus,
                            locationExtended,
                            locEngHandle.extSvInfo((void*)gnss_report_ptr));
  }
}

/* convert engine state report to loc eng format and send the converted
   report to loc eng */
void LocApiV02Adapter :: reportEngineState (
    const qmiLocEventEngineStateIndMsgT_v02 *engine_state_ptr)
{

  LOC_LOGV("%s:%d]: state = %d\n", __func__, __LINE__,
                 engine_state_ptr->engineState);

  if (engine_state_ptr->engineState == eQMI_LOC_ENGINE_STATE_ON_V02)
  {
    LocApiAdapter::reportStatus(GPS_STATUS_ENGINE_ON);
    LocApiAdapter::reportStatus(GPS_STATUS_SESSION_BEGIN);
  }
  else if (engine_state_ptr->engineState == eQMI_LOC_ENGINE_STATE_OFF_V02)
  {
    LocApiAdapter::reportStatus(GPS_STATUS_SESSION_END);
    LocApiAdapter::reportStatus(GPS_STATUS_ENGINE_OFF);
  }
  else
  {
      LocApiAdapter::reportStatus(GPS_STATUS_NONE);
  }

}

/* convert fix session state report to loc eng format and send the converted
   report to loc eng */
void LocApiV02Adapter :: reportFixSessionState (
    const qmiLocEventFixSessionStateIndMsgT_v02 *fix_session_state_ptr)
{
  GpsStatusValue status;
  LOC_LOGD("%s:%d]: state = %d\n", __func__, __LINE__,
                fix_session_state_ptr->sessionState);

  status = GPS_STATUS_NONE;
  if (fix_session_state_ptr->sessionState == eQMI_LOC_FIX_SESSION_STARTED_V02)
  {
    status = GPS_STATUS_SESSION_BEGIN;
  }
  else if (fix_session_state_ptr->sessionState
           == eQMI_LOC_FIX_SESSION_FINISHED_V02)
  {
    status = GPS_STATUS_SESSION_END;
  }
  LocApiAdapter::reportStatus(status);
}

/* convert NMEA report to loc eng format and send the converted
   report to loc eng */
void LocApiV02Adapter :: reportNmea (
  const qmiLocEventNmeaIndMsgT_v02 *nmea_report_ptr)
{

  LocApiAdapter::reportNmea(nmea_report_ptr->nmea,
                             strlen(nmea_report_ptr->nmea));

  LOC_LOGD("%s:%d]: $%c%c%c\n", __func__, __LINE__,
                  nmea_report_ptr->nmea[3], nmea_report_ptr->nmea[4],
                  nmea_report_ptr->nmea[5]);
}

/* convert and report an ATL request to loc engine */
void LocApiV02Adapter :: reportAtlRequest(
  const qmiLocEventLocationServerConnectionReqIndMsgT_v02 * server_request_ptr)
{
  uint32_t connHandle = server_request_ptr->connHandle;
  // service ATL open request; copy the WWAN type
  if(server_request_ptr->requestType == eQMI_LOC_SERVER_REQUEST_OPEN_V02 )
  {
    AGpsType agpsType = AGPS_TYPE_WWAN_ANY;
    switch(server_request_ptr->wwanType)
    {
      case eQMI_LOC_WWAN_TYPE_INTERNET_V02:
        agpsType = AGPS_TYPE_WWAN_ANY;
        break;

      case eQMI_LOC_WWAN_TYPE_AGNSS_V02:
        agpsType = AGPS_TYPE_SUPL;
        break;

      default:
        agpsType = AGPS_TYPE_WWAN_ANY;
        break;
    }
    LocApiAdapter::requestATL(connHandle, agpsType);
  }

  // service the ATL close request
  else if (server_request_ptr->requestType == eQMI_LOC_SERVER_REQUEST_CLOSE_V02)
  {
    LocApiAdapter::releaseATL(connHandle);
  }
}

/* conver the NI report to loc eng format and send t loc engine */
void LocApiV02Adapter :: reportNiRequest(
    const qmiLocEventNiNotifyVerifyReqIndMsgT_v02 *ni_req_ptr)
{
  GpsNiNotification notif;

  /* initialize the notification*/
  memset(notif.extras, 0, sizeof notif.extras);
  memset(notif.text, 0, sizeof notif.text);
  memset(notif.requestor_id, 0, sizeof notif.requestor_id);

  /* NI timeout gets overwritten in LocApiAdapter,
     initializing to 0 here */
  notif.timeout     = 0;

  notif.text_encoding = GPS_ENC_NONE ;

  notif.requestor_id_encoding = GPS_ENC_UNKNOWN;

  notif.notify_flags       = 0;

  notif.default_response   = GPS_NI_RESPONSE_NORESP;

  /*Handle Vx request */
  if(ni_req_ptr->NiVxInd_valid == 1)
  {
     const qmiLocNiVxNotifyVerifyStructT_v02 *vx_req = &(ni_req_ptr->NiVxInd);

     notif.ni_type     = GPS_NI_TYPE_VOICE;

     // Requestor ID, the requestor id recieved is NULL terminated
     hexcode(notif.requestor_id, sizeof notif.requestor_id,
             (char *)vx_req->requestorId, vx_req->requestorId_len );
  }

  /* Handle UMTS CP request*/
  else if(ni_req_ptr->NiUmtsCpInd_valid == 1)
  {
    const qmiLocNiUmtsCpNotifyVerifyStructT_v02 *umts_cp_req =
       &ni_req_ptr->NiUmtsCpInd;

    notif.ni_type     = GPS_NI_TYPE_UMTS_CTRL_PLANE;

    /* notificationText should always be a NULL terminated string */
    hexcode(notif.text, sizeof notif.text,
            (char *)umts_cp_req->notificationText,
            umts_cp_req->notificationText_len);

    /* Store requestor ID */
    hexcode(notif.requestor_id, sizeof(notif.requestor_id),
            (char *)umts_cp_req->requestorId.codedString,
            umts_cp_req->requestorId.codedString_len);

   /* convert encodings */
    notif.text_encoding = convertNiEncoding(umts_cp_req->dataCodingScheme);

    notif.requestor_id_encoding =
      convertNiEncoding(umts_cp_req->requestorId.dataCodingScheme);

    /* LCS address (using extras field) */
    if ( umts_cp_req->clientAddress_len != 0)
    {
      char lcs_addr[32]; // Decoded LCS address for UMTS CP NI

      // Copy LCS Address into notif.extras in the format: Address = 012345
      strlcat(notif.extras, LOC_NI_NOTIF_KEY_ADDRESS, sizeof (notif.extras));
      strlcat(notif.extras, " = ", sizeof notif.extras);
      int addr_len = 0;
      const char *address_source = NULL;
      address_source = (char *)umts_cp_req->clientAddress;
      // client Address is always NULL terminated
      addr_len = decodeAddress(lcs_addr, sizeof(lcs_addr), address_source,
                               umts_cp_req->clientAddress_len);

      // The address is ASCII string
      if (addr_len)
      {
        strlcat(notif.extras, lcs_addr, sizeof notif.extras);
      }
    }

  }
  else if(ni_req_ptr->NiSuplInd_valid == 1)
  {
    const qmiLocNiSuplNotifyVerifyStructT_v02 *supl_req =
      &ni_req_ptr->NiSuplInd;

    notif.ni_type     = GPS_NI_TYPE_UMTS_SUPL;

    // Client name
    if (supl_req->valid_flags & QMI_LOC_SUPL_CLIENT_NAME_MASK_V02)
    {
      hexcode(notif.text, sizeof(notif.text),
              (char *)supl_req->clientName.formattedString,
              supl_req->clientName.formattedString_len);
      LOC_LOGV("%s:%d]: SUPL NI: client_name: %s \n", __func__, __LINE__,
          notif.text);
    }
    else
    {
      LOC_LOGV("%s:%d]: SUPL NI: client_name not present.",
          __func__, __LINE__);
    }

    // Requestor ID
    if (supl_req->valid_flags & QMI_LOC_SUPL_REQUESTOR_ID_MASK_V02)
    {
      hexcode(notif.requestor_id, sizeof notif.requestor_id,
              (char*)supl_req->requestorId.formattedString,
              supl_req->requestorId.formattedString_len );

      LOC_LOGV("%s:%d]: SUPL NI: requestor_id: %s \n", __func__, __LINE__,
          notif.requestor_id);
    }
    else
    {
      LOC_LOGV("%s:%d]: SUPL NI: requestor_id not present.",
          __func__, __LINE__);
    }

    // Encoding type
    if (supl_req->valid_flags & QMI_LOC_SUPL_DATA_CODING_SCHEME_MASK_V02)
    {
      notif.text_encoding = convertNiEncoding(supl_req->dataCodingScheme);

      notif.requestor_id_encoding = convertNiEncoding(supl_req->dataCodingScheme);
    }
    else
    {
      notif.text_encoding = notif.requestor_id_encoding = GPS_ENC_UNKNOWN;
    }

  } //ni_req_ptr->NiSuplInd_valid == 1

  else
  {
    LOC_LOGE("%s:%d]: unknown request event \n",__func__, __LINE__);
    return;
  }

  // Set default_response & notify_flags
  convertNiNotifyVerifyType(&notif, ni_req_ptr->notificationType);

  qmiLocEventNiNotifyVerifyReqIndMsgT_v02 *ni_req_copy_ptr =
    (qmiLocEventNiNotifyVerifyReqIndMsgT_v02 *)malloc(sizeof(*ni_req_copy_ptr));

  if( NULL != ni_req_copy_ptr)
  {
    memcpy(ni_req_copy_ptr, ni_req_ptr, sizeof(*ni_req_copy_ptr));

    LocApiAdapter::requestNiNotify(notif, (const void*)ni_req_copy_ptr);
  }
  else
  {
    LOC_LOGE("%s:%d]: Error copying NI request\n", __func__, __LINE__);
  }

}

/* convert Ni Encoding type from QMI_LOC to loc eng format */
GpsNiEncodingType LocApiV02Adapter ::convertNiEncoding(
  qmiLocNiDataCodingSchemeEnumT_v02 loc_encoding)
{
   GpsNiEncodingType enc = GPS_ENC_UNKNOWN;

   switch (loc_encoding)
   {
     case eQMI_LOC_NI_SUPL_UTF8_V02:
       enc = GPS_ENC_SUPL_UTF8;
       break;
     case eQMI_LOC_NI_SUPL_UCS2_V02:
       enc = GPS_ENC_SUPL_UCS2;
       break;
     case eQMI_LOC_NI_SUPL_GSM_DEFAULT_V02:
       enc = GPS_ENC_SUPL_GSM_DEFAULT;
       break;
     case eQMI_LOC_NI_SS_LANGUAGE_UNSPEC_V02:
       enc = GPS_ENC_SUPL_GSM_DEFAULT; // SS_LANGUAGE_UNSPEC = GSM
       break;
     default:
       break;
   }

   return enc;
}

/*convert NI notify verify type from QMI LOC to loc eng format*/
bool LocApiV02Adapter :: convertNiNotifyVerifyType (
  GpsNiNotification *notif,
  qmiLocNiNotifyVerifyEnumT_v02 notif_priv)
{
  switch (notif_priv)
   {
   case eQMI_LOC_NI_USER_NO_NOTIFY_NO_VERIFY_V02:
      notif->notify_flags = 0;
      break;

   case eQMI_LOC_NI_USER_NOTIFY_ONLY_V02:
      notif->notify_flags = GPS_NI_NEED_NOTIFY;
      break;

   case eQMI_LOC_NI_USER_NOTIFY_VERIFY_ALLOW_NO_RESP_V02:
      notif->notify_flags = GPS_NI_NEED_NOTIFY | GPS_NI_NEED_VERIFY;
      notif->default_response = GPS_NI_RESPONSE_ACCEPT;
      break;

   case eQMI_LOC_NI_USER_NOTIFY_VERIFY_NOT_ALLOW_NO_RESP_V02:
      notif->notify_flags = GPS_NI_NEED_NOTIFY | GPS_NI_NEED_VERIFY;
      notif->default_response = GPS_NI_RESPONSE_DENY;
      break;

   case eQMI_LOC_NI_USER_NOTIFY_VERIFY_PRIVACY_OVERRIDE_V02:
      notif->notify_flags = GPS_NI_PRIVACY_OVERRIDE;
      break;

   default:
      return false;
   }

   return true;
}

/* event callback registered with the loc_api v02 interface */
void LocApiV02Adapter :: eventCb(locClientHandleType clientHandle,
  uint32_t eventId, locClientEventIndUnionType eventPayload)
{
  LOC_LOGD("%s:%d]: event id = %d\n", __func__, __LINE__,
                eventId);

  switch(eventId)
  {
    //Position Report
    case QMI_LOC_EVENT_POSITION_REPORT_IND_V02:
      reportPosition(eventPayload.pPositionReportEvent);
      break;

    // Satellite report
    case QMI_LOC_EVENT_GNSS_SV_INFO_IND_V02:
      reportSv(eventPayload.pGnssSvInfoReportEvent);
      break;

    // Status report
    case QMI_LOC_EVENT_ENGINE_STATE_IND_V02:
      reportEngineState(eventPayload.pEngineState);
      break;

    case QMI_LOC_EVENT_FIX_SESSION_STATE_IND_V02:
      reportFixSessionState(eventPayload.pFixSessionState);
      break;

    // NMEA
    case QMI_LOC_EVENT_NMEA_IND_V02:
      reportNmea(eventPayload.pNmeaReportEvent);
      break;

    // XTRA request
    case QMI_LOC_EVENT_INJECT_PREDICTED_ORBITS_REQ_IND_V02:
      LOC_LOGD("%s:%d]: XTRA download request\n", __func__,
                    __LINE__);
      requestXtraData();
      break;

    // time request
    case QMI_LOC_EVENT_INJECT_TIME_REQ_IND_V02:
      LOC_LOGD("%s:%d]: Time request\n", __func__,
                    __LINE__);
      requestTime();
      break;

    //position request
    case QMI_LOC_EVENT_INJECT_POSITION_REQ_IND_V02:
      LOC_LOGD("%s:%d]: Position request\n", __func__,
                    __LINE__);
      //requestPosition();
      break;

    // NI request
    case QMI_LOC_EVENT_NI_NOTIFY_VERIFY_REQ_IND_V02:
      reportNiRequest(eventPayload.pNiNotifyVerifyReqEvent);
      break;

    // AGPS connection request
    case QMI_LOC_EVENT_LOCATION_SERVER_CONNECTION_REQ_IND_V02:
      reportAtlRequest(eventPayload.pLocationServerConnReqEvent);
      break;
  }
}

/* Call the service LocApiAdapter down event*/
void LocApiV02Adapter :: errorCb(locClientHandleType handle,
                                 locClientErrorEnumType errorId)
{
  if(errorId == eLOC_CLIENT_ERROR_SERVICE_UNAVAILABLE)
  {
    LOC_LOGE("%s:%d]: Service unavailable error\n",
                  __func__, __LINE__);

    LocApiAdapter::handleEngineDownEvent();

    /* immediately send the engine up event so that
    the loc engine re-initializes the adapter and the
    loc-api_v02 interface */

    LocApiAdapter::handleEngineUpEvent();
  }
}

/* return a Loc API adapter */
LocApiAdapter* getLocApiAdapter(LocEng &locEng)
{
 return(new LocApiV02Adapter(locEng));
}