Merge "force undefined symbols to treat as errors"
diff --git a/android/Android.mk b/android/Android.mk
index b493f5e..000cd59 100644
--- a/android/Android.mk
+++ b/android/Android.mk
@@ -12,6 +12,7 @@
     GnssMeasurement.cpp \
     GnssNi.cpp \
     GnssConfiguration.cpp \
+    GnssDebug.cpp \
 
 LOCAL_SRC_FILES += \
     location_api/LocationUtil.cpp \
diff --git a/android/Gnss.cpp b/android/Gnss.cpp
index 1412883..d17077c 100644
--- a/android/Gnss.cpp
+++ b/android/Gnss.cpp
@@ -121,6 +121,7 @@
     if (api != nullptr) {
         api->gnssUpdateCallbacks(mGnssCbIface, mGnssNiCbIface);
         api->locAPIEnable(LOCATION_TECHNOLOGY_TYPE_GNSS);
+        api->requestCapabilities();
     }
     return true;
 }
@@ -309,6 +310,12 @@
     return mGnssBatching;
 }
 
+Return<sp<IGnssDebug>> Gnss::getExtensionGnssDebug() {
+    ENTRY_LOG_CALLFLOW();
+    mGnssDebug = new GnssDebug(this);
+    return mGnssDebug;
+}
+
 IGnss* HIDL_FETCH_IGnss(const char* hal) {
     ENTRY_LOG_CALLFLOW();
     IGnss* iface = nullptr;
diff --git a/android/Gnss.h b/android/Gnss.h
index b338b08..99c5e40 100644
--- a/android/Gnss.h
+++ b/android/Gnss.h
@@ -27,6 +27,7 @@
 #include <GnssGeofencing.h>
 #include <GnssMeasurement.h>
 #include <GnssNi.h>
+#include <GnssDebug.h>
 
 #include <android/hardware/gnss/1.0/IGnss.h>
 #include <hidl/Status.h>
@@ -102,9 +103,7 @@
         return nullptr;
     }
 
-    inline Return<sp<IGnssDebug>> getExtensionGnssDebug() override {
-        return nullptr;
-    }
+    Return<sp<IGnssDebug>> getExtensionGnssDebug() override;
 
     // These methods are not part of the IGnss base class.
     GnssAPIClient* getApi();
@@ -130,6 +129,7 @@
     sp<GnssConfiguration> mGnssConfig = nullptr;
     sp<GnssGeofencing> mGnssGeofencingIface = nullptr;
     sp<GnssBatching> mGnssBatching = nullptr;
+    sp<IGnssDebug> mGnssDebug = nullptr;
 
     GnssAPIClient* mApi = nullptr;
     sp<IGnssCallback> mGnssCbIface = nullptr;
diff --git a/android/GnssDebug.cpp b/android/GnssDebug.cpp
new file mode 100644
index 0000000..3ab94d3
--- /dev/null
+++ b/android/GnssDebug.cpp
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "LocSvc_GnssDebugInterface"
+
+#include <log/log.h>
+#include <log_util.h>
+#include "Gnss.h"
+#include "GnssDebug.h"
+#include "LocationUtil.h"
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace V1_0 {
+namespace implementation {
+
+using ::android::hardware::hidl_vec;
+
+GnssDebug::GnssDebug(Gnss* gnss) : mGnss(gnss)
+{
+}
+
+/*
+ * This methods requests position, time and satellite ephemeris debug information
+ * from the HAL.
+ *
+ * @return void
+*/
+Return<void> GnssDebug::getDebugData(getDebugData_cb _hidl_cb)
+{
+    LOC_LOGI("GnssDebug - 0317a");
+
+    DebugData data = { };
+
+    if((nullptr == mGnss) || (nullptr == mGnss->getGnssInterface())){
+        LOC_LOGE("GnssDebug - Null GNSS interface");
+        _hidl_cb(data);
+        return Void();
+    }
+
+    // get debug report snapshot via hal interface
+    GnssDebugReport reports = { };
+    mGnss->getGnssInterface()->getDebugReport(reports);
+
+    // location block
+    data.position.valid                    = true;
+    data.position.latitudeDegrees          = reports.mLocation.mLocation.latitude;
+    data.position.longitudeDegrees         = reports.mLocation.mLocation.longitude;
+    data.position.altitudeMeters           = reports.mLocation.mLocation.altitude;
+    data.position.speedMetersPerSec        = (double)(reports.mLocation.mLocation.speed);
+    data.position.bearingDegrees           = (double)(reports.mLocation.mLocation.bearing);
+    data.position.horizontalAccuracyMeters = (double)(reports.mLocation.mLocation.accuracy);
+    data.position.verticalAccuracyMeters   = reports.mLocation.verticalAccuracyMeters;
+    data.position.speedAccuracyMetersPerSecond = reports.mLocation.speedAccuracyMetersPerSecond;
+    data.position.bearingAccuracyDegrees   = reports.mLocation.bearingAccuracyDegrees;
+
+    LOC_LOGV("GnssDebug - lat=%f lon=%f", data.position.latitudeDegrees, data.position.longitudeDegrees);
+
+    timeval tv_now, tv_report;
+    tv_report.tv_sec  = reports.mLocation.mLocation.timestamp / 1000ULL;
+    tv_report.tv_usec = (reports.mLocation.mLocation.timestamp % 1000ULL) * 1000ULL;
+    gettimeofday(&tv_now, NULL);
+    data.position.ageSeconds =
+        (tv_now.tv_sec - tv_report.tv_sec) + (float)((tv_now.tv_usec - tv_report.tv_usec)) / 1000000;
+
+    LOC_LOGV("GnssDebug - time now=%lld:%lld", tv_now.tv_sec, tv_now.tv_usec);
+    LOC_LOGV("GnssDebug - time rep=%lld:%lld", tv_report.tv_sec, tv_report.tv_usec);
+    LOC_LOGV("GnssDebug - age=%f", data.position.ageSeconds);
+
+    // time block
+    data.time.valid             = true;
+    data.time.timeEstimate      = reports.mTime.timeEstimate;
+    data.time.timeUncertaintyNs = reports.mTime.timeUncertaintyNs;
+
+    LOC_LOGV("GnssDebug - timeestimate=%lld", data.time.timeEstimate);
+
+    // satellite data block
+    SatelliteData s = { };
+    std::vector<SatelliteData> s_array = { };
+
+    for (uint32_t i=0; i<reports.mSatelliteInfo.size(); i++) {
+        memset(&s, 0, sizeof(s));
+        s.svid = reports.mSatelliteInfo[i].svid;
+        convertGnssConstellationType(reports.mSatelliteInfo[i].constellation, s.constellation);
+        s.ephemerisType = SatelliteEphemerisType::UNKNOWN;
+        s.ephemerisAgeSeconds = reports.mSatelliteInfo[i].ephemerisAgeSeconds;
+        s_array.push_back(s);
+    }
+    data.satelliteDataArray = s_array;
+    LOC_LOGV("GnssDebug - satellite=%d", data.satelliteDataArray.size());
+
+    // callback HIDL with collected debug data
+    _hidl_cb(data);
+
+    LOC_LOGV("GnssDebug - done");
+    return Void();
+}
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace gnss
+}  // namespace hardware
+}  // namespace android
diff --git a/android/GnssDebug.h b/android/GnssDebug.h
new file mode 100644
index 0000000..7d29131
--- /dev/null
+++ b/android/GnssDebug.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HARDWARE_GNSS_V1_1_GNSSDEBUG_H
+#define ANDROID_HARDWARE_GNSS_V1_1_GNSSDEBUG_H
+
+
+#include <android/hardware/gnss/1.0/IGnssDebug.h>
+#include <hidl/Status.h>
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace V1_0 {
+namespace implementation {
+
+using ::android::hardware::gnss::V1_0::IGnssDebug;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::hidl_string;
+using ::android::sp;
+
+/* Interface for GNSS Debug support. */
+struct Gnss;
+struct GnssDebug : public IGnssDebug {
+    GnssDebug(Gnss* gnss);
+    ~GnssDebug() {};
+
+    /*
+     * Methods from ::android::hardware::gnss::V1_0::IGnssDebug follow.
+     * These declarations were generated from IGnssDebug.hal.
+     */
+    Return<void> getDebugData(getDebugData_cb _hidl_cb) override;
+
+private:
+    Gnss* mGnss = nullptr;
+};
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace gnss
+}  // namespace hardware
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_GNSS_V1_1_GNSSDEBUG_H
diff --git a/android/location_api/GeofenceAPIClient.cpp b/android/location_api/GeofenceAPIClient.cpp
index 5be1cff..ee4bfc3 100644
--- a/android/location_api/GeofenceAPIClient.cpp
+++ b/android/location_api/GeofenceAPIClient.cpp
@@ -100,7 +100,10 @@
     data.longitude = longitude;
     data.radius = radius_meters;
 
-    locAPIAddGeofences(1, &geofence_id, &options, &data);
+    LocationError err = (LocationError)locAPIAddGeofences(1, &geofence_id, &options, &data);
+    if (LOCATION_ERROR_SUCCESS != err) {
+        onAddGeofencesCb(1, &err, &geofence_id);
+    }
 }
 
 void GeofenceAPIClient::geofencePause(uint32_t geofence_id)
diff --git a/android/location_api/GnssAPIClient.cpp b/android/location_api/GnssAPIClient.cpp
index b4f0406..4cb3f7d 100644
--- a/android/location_api/GnssAPIClient.cpp
+++ b/android/location_api/GnssAPIClient.cpp
@@ -49,7 +49,8 @@
     LocationAPIClientBase(),
     mGnssCbIface(nullptr),
     mGnssNiCbIface(nullptr),
-    mLocationCapabilitiesMask(0)
+    mLocationCapabilitiesMask(0),
+    mLocationCapabilitiesCached(false)
 {
     LOC_LOGD("%s]: (%p %p)", __FUNCTION__, &gpsCb, &niCb);
 
@@ -218,11 +219,20 @@
     locAPIGnssUpdateConfig(gnssConfig);
 }
 
+void GnssAPIClient::requestCapabilities() {
+    // only send capablities if it's already cached, otherwise the first time LocationAPI
+    // is initialized, capabilities will be sent by LocationAPI
+    if (mLocationCapabilitiesCached) {
+        onCapabilitiesCb(mLocationCapabilitiesMask);
+    }
+}
+
 // callbacks
 void GnssAPIClient::onCapabilitiesCb(LocationCapabilitiesMask capabilitiesMask)
 {
     LOC_LOGD("%s]: (%02x)", __FUNCTION__, capabilitiesMask);
     mLocationCapabilitiesMask = capabilitiesMask;
+    mLocationCapabilitiesCached = true;
     if (mGnssCbIface != nullptr) {
         uint32_t data = 0;
         if ((capabilitiesMask & LOCATION_CAPABILITIES_TIME_BASED_TRACKING_BIT) ||
diff --git a/android/location_api/GnssAPIClient.h b/android/location_api/GnssAPIClient.h
index 1809c09..d447157 100644
--- a/android/location_api/GnssAPIClient.h
+++ b/android/location_api/GnssAPIClient.h
@@ -74,6 +74,7 @@
     inline LocationCapabilitiesMask gnssGetCapabilities() const {
         return mLocationCapabilitiesMask;
     }
+    void requestCapabilities();
 
     // callbacks we are interested in
     void onCapabilitiesCb(LocationCapabilitiesMask capabilitiesMask) final;
@@ -90,6 +91,7 @@
     sp<IGnssNiCallback> mGnssNiCbIface;
 
     LocationCapabilitiesMask mLocationCapabilitiesMask;
+    bool mLocationCapabilitiesCached;
 
     LocationOptions mLocationOptions;
 };
diff --git a/android/location_api/LocationUtil.cpp b/android/location_api/LocationUtil.cpp
index dbafe5d..d782375 100644
--- a/android/location_api/LocationUtil.cpp
+++ b/android/location_api/LocationUtil.cpp
@@ -46,21 +46,23 @@
         out.gnssLocationFlags |= GnssLocationFlags::HAS_SPEED;
     if (in.flags & LOCATION_HAS_BEARING_BIT)
         out.gnssLocationFlags |= GnssLocationFlags::HAS_BEARING;
-    if (in.flags & LOCATION_HAS_ACCURACY_BIT) {
+    if (in.flags & LOCATION_HAS_ACCURACY_BIT)
         out.gnssLocationFlags |= GnssLocationFlags::HAS_HORIZONTAL_ACCURACY;
-        //out.gnssLocationFlags |= GnssLocationFlags::HAS_VERTICAL_ACCURACY;
-        //out.gnssLocationFlags |= GnssLocationFlags::HAS_SPEED_ACCURACY;
-        //out.gnssLocationFlags |= GnssLocationFlags::HAS_BEARING_ACCURACY;
-    }
+    if (in.flags & LOCATION_HAS_VERTICAL_ACCURACY_BIT)
+        out.gnssLocationFlags |= GnssLocationFlags::HAS_VERTICAL_ACCURACY;
+    if (in.flags & LOCATION_HAS_SPEED_ACCURACY_BIT)
+        out.gnssLocationFlags |= GnssLocationFlags::HAS_SPEED_ACCURACY;
+    if (in.flags & LOCATION_HAS_BEARING_ACCURACY_BIT)
+        out.gnssLocationFlags |= GnssLocationFlags::HAS_BEARING_ACCURACY;
     out.latitudeDegrees = in.latitude;
     out.longitudeDegrees = in.longitude;
     out.altitudeMeters = in.altitude;
     out.speedMetersPerSec = in.speed;
     out.bearingDegrees = in.bearing;
     out.horizontalAccuracyMeters = in.accuracy;
-    //out.verticalAccuracyMeters = in.accuracy;
-    //out.speedAccuracyMetersPerSecond = in.accuracy;
-    //out.bearingAccuracyDegrees = in.accuracy;
+    out.verticalAccuracyMeters = in.verticalAccuracy;
+    out.speedAccuracyMetersPerSecond = in.speedAccuracy;
+    out.bearingAccuracyDegrees = in.bearingAccuracy;
     out.timestamp = static_cast<GnssUtcTime>(in.timestamp);
 }
 
diff --git a/core/Android.mk b/core/Android.mk
index b260b1d..b8e25a9 100644
--- a/core/Android.mk
+++ b/core/Android.mk
@@ -30,7 +30,8 @@
     LocAdapterBase.cpp \
     ContextBase.cpp \
     LocDualContext.cpp \
-    loc_core_log.cpp
+    loc_core_log.cpp \
+    SystemStatus.cpp
 
 LOCAL_CFLAGS += \
      -fno-short-enums \
@@ -53,7 +54,8 @@
     gps_extended_c.h \
     gps_extended.h \
     loc_core_log.h \
-    LocAdapterProxyBase.h
+    LocAdapterProxyBase.h \
+    SystemStatus.h
 
 include $(BUILD_SHARED_LIBRARY)
 
diff --git a/core/ContextBase.cpp b/core/ContextBase.cpp
index a9858e2..849a7d3 100644
--- a/core/ContextBase.cpp
+++ b/core/ContextBase.cpp
@@ -96,7 +96,7 @@
    mGps_conf.NMEA_PROVIDER = 0;
    mGps_conf.GPS_LOCK = 0;
    mGps_conf.SUPL_VER = 0x10000;
-   mGps_conf.SUPL_MODE = 0x3;
+   mGps_conf.SUPL_MODE = 0x1;
    mGps_conf.SUPL_ES = 0;
    mGps_conf.CAPABILITIES = 0x7;
    /* LTE Positioning Profile configuration is disable by default*/
@@ -145,10 +145,8 @@
    /* inject supl config to modem with config values from config.xml or gps.conf, default 1 */
    mGps_conf.AGPS_CONFIG_INJECT = 1;
 
-   const char* GPS_CONF_FILE = "/etc/gps.conf";
-   const char* SAP_CONF_FILE = "/etc/sap.conf";
-   UTIL_READ_CONF(GPS_CONF_FILE, mGps_conf_table);
-   UTIL_READ_CONF(SAP_CONF_FILE, mSap_conf_table);
+   UTIL_READ_CONF(LOC_PATH_GPS_CONF, mGps_conf_table);
+   UTIL_READ_CONF(LOC_PATH_SAP_CONF, mSap_conf_table);
 }
 
 uint32_t ContextBase::getCarrierCapabilities() {
diff --git a/core/LocApiBase.cpp b/core/LocApiBase.cpp
index 3bbbf8f..0036d88 100644
--- a/core/LocApiBase.cpp
+++ b/core/LocApiBase.cpp
@@ -26,7 +26,7 @@
  * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *
  */
-#define LOG_NDDEBUG 0
+#define LOG_NDEBUG 0 //Define to enable LOGV
 #define LOG_TAG "LocSvc_LocApiBase"
 
 #include <dlfcn.h>
diff --git a/core/LocDualContext.cpp b/core/LocDualContext.cpp
index fd465e9..c6a8896 100644
--- a/core/LocDualContext.cpp
+++ b/core/LocDualContext.cpp
@@ -35,6 +35,7 @@
 #include <msg_q.h>
 #include <platform_lib_log_util.h>
 #include <loc_log.h>
+#include <SystemStatus.h>
 
 namespace loc_core {
 
@@ -56,6 +57,7 @@
 ContextBase* LocDualContext::mFgContext = NULL;
 ContextBase* LocDualContext::mBgContext = NULL;
 ContextBase* LocDualContext::mInjectContext = NULL;
+SystemStatus* LocDualContext::mSystemStatus = NULL;
 // the name must be shorter than 15 chars
 const char* LocDualContext::mLocationHalName = "Loc_hal_worker";
 #ifndef USE_GLIB
@@ -147,4 +149,14 @@
 {
 }
 
+SystemStatus* LocDualContext::getSystemStatus(void)
+{
+    pthread_mutex_lock(&LocDualContext::mGetLocContextMutex);
+    if (NULL == mSystemStatus) {
+        mSystemStatus = new SystemStatus();
+    }
+    pthread_mutex_unlock(&LocDualContext::mGetLocContextMutex);
+    return  mSystemStatus;
+}
+
 }
diff --git a/core/LocDualContext.h b/core/LocDualContext.h
index ce77a1a..7642152 100644
--- a/core/LocDualContext.h
+++ b/core/LocDualContext.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2014, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2011-2014, 2017 The Linux Foundation. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are
@@ -36,6 +36,8 @@
 
 namespace loc_core {
 
+class SystemStatus;
+
 class LocDualContext : public ContextBase {
     static const MsgTask* mMsgTask;
     static ContextBase* mFgContext;
@@ -45,6 +47,7 @@
                                      const char* name, bool joinable = true);
     static const MsgTask* getMsgTask(const char* name, bool joinable = true);
     static pthread_mutex_t mGetLocContextMutex;
+    static SystemStatus* mSystemStatus;
 
 protected:
     LocDualContext(const MsgTask* msgTask,
@@ -69,6 +72,7 @@
     }
 
     static void injectFeatureConfig(ContextBase *context);
+    static SystemStatus* getSystemStatus(void);
 };
 
 }
diff --git a/core/Makefile.am b/core/Makefile.am
index 0a9d3e2..ccbff94 100644
--- a/core/Makefile.am
+++ b/core/Makefile.am
@@ -16,14 +16,16 @@
            gps_extended_c.h \
            gps_extended.h \
            loc_core_log.h \
-           LocAdapterProxyBase.h
+           LocAdapterProxyBase.h \
+           SystemStatus.h
 
 libloc_core_la_c_sources = \
            LocApiBase.cpp \
            LocAdapterBase.cpp \
            ContextBase.cpp \
            LocDualContext.cpp \
-           loc_core_log.cpp
+           loc_core_log.cpp \
+           SystemStatus.cpp
 
 library_includedir = $(pkgincludedir)/core
 
diff --git a/core/SystemStatus.cpp b/core/SystemStatus.cpp
new file mode 100644
index 0000000..7791410
--- /dev/null
+++ b/core/SystemStatus.cpp
@@ -0,0 +1,1488 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer in the documentation and/or other materials provided
+ *       with the distribution.
+ *     * Neither the name of The Linux Foundation, nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+#define LOG_TAG "LocSvc_SystemStatus"
+
+#include <string>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/time.h>
+#include <pthread.h>
+#include <platform_lib_log_util.h>
+#include <SystemStatus.h>
+
+namespace loc_core
+{
+
+/******************************************************************************
+ SystemStatusNmeaBase - base class for all NMEA parsers
+******************************************************************************/
+class SystemStatusNmeaBase
+{
+protected:
+    std::vector<std::string> mField;
+    timespec setUtcTime(std::string sutctime);
+
+public:
+    static const uint32_t NMEA_MINSIZE = 6;
+    static const uint32_t NMEA_MAXSIZE = 256;
+
+    SystemStatusNmeaBase(const char *str_in, uint32_t len_in)
+    {
+        // check size and talker
+        if (len_in > NMEA_MAXSIZE || len_in < NMEA_MINSIZE || (str_in[0] != '$')) {
+            return;
+        }
+
+        std::string parser(str_in);
+        std::string::size_type index = 0;
+
+        // verify checksum field
+        index = parser.find("*");
+        if (index == std::string::npos) {
+            return;
+        }
+        parser[index] = ',';
+
+        // tokenize parser
+        while (1) {
+            std::string str;
+            index = parser.find(",");
+            if (index == std::string::npos) {
+                break;
+            }
+            str = parser.substr(0, index);
+            parser = parser.substr(index + 1);
+            mField.push_back(str);
+        }
+    }
+
+    virtual ~SystemStatusNmeaBase() { }
+};
+
+timespec SystemStatusNmeaBase::setUtcTime(std::string sutctime)
+{
+    timespec ts = { 0ULL, 0ULL };
+    uint64_t utctime_ns = atof(sutctime.c_str()) * 1000000000ULL;
+    ts.tv_nsec = utctime_ns % 1000000000ULL;
+    uint64_t utctime_s = utctime_ns / 1000000000ULL;
+
+    uint64_t hour = utctime_s / 10000ULL;
+    uint64_t min =  (utctime_s / 100LL) % 100ULL;
+    uint64_t sec =  utctime_s % 100ULL;
+    ts.tv_sec = hour * 3600ULL + min * 60ULL + sec;
+
+    timeval tv;
+    gettimeofday(&tv, NULL);
+    ts.tv_sec += (uint64_t(tv.tv_sec / (24ULL * 60ULL * 60ULL))) * (24ULL * 60ULL * 60ULL);
+    return ts;
+}
+
+/******************************************************************************
+ SystemStatusPQWM1
+******************************************************************************/
+class SystemStatusPQWM1
+{
+public:
+    timespec mUtcTime;
+    uint16_t mGpsWeek;    // x1
+    uint32_t mGpsTowMs;   // x2
+    uint8_t  mTimeValid;  // x3
+    uint8_t  mTimeSource; // x4
+    int32_t  mTimeUnc;    // x5
+    int32_t  mClockFreqBias; // x6
+    int32_t  mClockFreqBiasUnc; // x7
+    uint8_t  mXoState;    // x8
+    int32_t  mPgaGain;    // x9
+    uint32_t mGpsBpAmpI;  // xA
+    uint32_t mGpsBpAmpQ;  // xB
+    uint32_t mAdcI;       // xC
+    uint32_t mAdcQ;       // xD
+    uint32_t mJammerGps;  // xE
+    uint32_t mJammerGlo;  // xF
+    uint32_t mJammerBds;  // x10
+    uint32_t mJammerGal;  // x11
+    uint32_t mRecErrorRecovery; // x12
+};
+
+// parser
+class SystemStatusPQWM1parser : public SystemStatusNmeaBase
+{
+private:
+    enum
+    {
+        eTalker = 0,
+        eGpsWeek = 1,
+        eGpsTowMs = 2,
+        eTimeValid = 3,
+        eTimeSource = 4,
+        eTimeUnc = 5,
+        eClockFreqBias = 6,
+        eClockFreqBiasUnc = 7,
+        eXoState = 8,
+        ePgaGain = 9,
+        eGpsBpAmpI = 10,
+        eGpsBpAmpQ = 11,
+        eAdcI = 12,
+        eAdcQ = 13,
+        eJammerGps = 14,
+        eJammerGlo = 15,
+        eJammerBds = 16,
+        eJammerGal = 17,
+        eRecErrorRecovery = 18,
+        eMax = eRecErrorRecovery
+    };
+    SystemStatusPQWM1 mM1;
+
+public:
+    inline uint16_t   getGpsWeek()    { return mM1.mGpsWeek; }
+    inline uint32_t   getGpsTowMs()   { return mM1.mGpsTowMs; }
+    inline uint8_t    getTimeValid()  { return mM1.mTimeValid; }
+    inline uint8_t    getTimeSource() { return mM1.mTimeSource; }
+    inline int32_t    getTimeUnc()    { return mM1.mTimeUnc; }
+    inline int32_t    getClockFreqBias() { return mM1.mClockFreqBias; }
+    inline int32_t    getClockFreqBiasUnc() { return mM1.mClockFreqBiasUnc; }
+    inline uint8_t    getXoState()    { return mM1.mXoState;}
+    inline int32_t    getPgaGain()    { return mM1.mPgaGain;          }
+    inline uint32_t   getGpsBpAmpI()  { return mM1.mGpsBpAmpI;        }
+    inline uint32_t   getGpsBpAmpQ()  { return mM1.mGpsBpAmpQ;        }
+    inline uint32_t   getAdcI()       { return mM1.mAdcI;             }
+    inline uint32_t   getAdcQ()       { return mM1.mAdcQ;             }
+    inline uint32_t   getJammerGps()  { return mM1.mJammerGps;        }
+    inline uint32_t   getJammerGlo()  { return mM1.mJammerGlo;        }
+    inline uint32_t   getJammerBds()  { return mM1.mJammerBds;        }
+    inline uint32_t   getJammerGal()  { return mM1.mJammerGal;        }
+    inline uint32_t   getRecErrorRecovery() { return mM1.mRecErrorRecovery; }
+
+    SystemStatusPQWM1parser(const char *str_in, uint32_t len_in)
+        : SystemStatusNmeaBase(str_in, len_in)
+    {
+        if (mField.size() < eMax) {
+            return;
+        }
+        memset(&mM1, 0, sizeof(mM1));
+
+        timeval tv;
+        gettimeofday(&tv, NULL);
+        mM1.mUtcTime.tv_sec = tv.tv_sec;
+        mM1.mUtcTime.tv_nsec = tv.tv_usec * 1000UL;
+        mM1.mGpsWeek = atoi(mField[eGpsWeek].c_str());
+        mM1.mGpsTowMs = atoi(mField[eGpsTowMs].c_str());
+        mM1.mTimeValid = atoi(mField[eTimeValid].c_str());
+        mM1.mTimeSource = atoi(mField[eTimeSource].c_str());
+        mM1.mTimeUnc = atoi(mField[eTimeUnc].c_str());
+        mM1.mClockFreqBias = atoi(mField[eClockFreqBias].c_str());
+        mM1.mClockFreqBiasUnc = atoi(mField[eClockFreqBiasUnc].c_str());
+        mM1.mXoState = atoi(mField[eXoState].c_str());
+        mM1.mPgaGain = atoi(mField[ePgaGain].c_str());
+        mM1.mGpsBpAmpI = atoi(mField[eGpsBpAmpI].c_str());
+        mM1.mGpsBpAmpQ = atoi(mField[eGpsBpAmpQ].c_str());
+        mM1.mAdcI = atoi(mField[eAdcI].c_str());
+        mM1.mAdcQ = atoi(mField[eAdcQ].c_str());
+        mM1.mJammerGps = atoi(mField[eJammerGps].c_str());
+        mM1.mJammerGlo = atoi(mField[eJammerGlo].c_str());
+        mM1.mJammerBds = atoi(mField[eJammerBds].c_str());
+        mM1.mJammerGal = atoi(mField[eJammerGal].c_str());
+        mM1.mRecErrorRecovery = atoi(mField[eRecErrorRecovery].c_str());
+    }
+
+    inline SystemStatusPQWM1& get() { return mM1;} //getparser
+};
+
+/******************************************************************************
+ SystemStatusPQWP1
+******************************************************************************/
+class SystemStatusPQWP1
+{
+public:
+    timespec mUtcTime;
+    uint8_t  mEpiValidity; // x4
+    float    mEpiLat;    // x5
+    float    mEpiLon;    // x6
+    float    mEpiAlt;    // x7
+    float    mEpiHepe;   // x8
+    float    mEpiAltUnc; // x9
+    uint8_t  mEpiSrc;    // x10
+};
+
+class SystemStatusPQWP1parser : public SystemStatusNmeaBase
+{
+private:
+    enum
+    {
+        eTalker = 0,
+        eUtcTime = 1,
+        eEpiValidity = 2,
+        eEpiLat = 3,
+        eEpiLon = 4,
+        eEpiAlt = 5,
+        eEpiHepe = 6,
+        eEpiAltUnc = 7,
+        eEpiSrc = 8,
+        eMax = eEpiSrc
+    };
+    SystemStatusPQWP1 mP1;
+
+public:
+    inline timespec   getUtcTime() { return mP1.mUtcTime;           }
+    inline uint8_t    getEpiValidity() { return mP1.mEpiValidity;      }
+    inline float      getEpiLat() { return mP1.mEpiLat;           }
+    inline float      getEpiLon() { return mP1.mEpiLon;           }
+    inline float      getEpiAlt() { return mP1.mEpiAlt;           }
+    inline float      getEpiHepe() { return mP1.mEpiHepe;          }
+    inline float      getEpiAltUnc() { return mP1.mEpiAltUnc;        }
+    inline uint8_t    getEpiSrc() { return mP1.mEpiSrc;           }
+
+    SystemStatusPQWP1parser(const char *str_in, uint32_t len_in)
+        : SystemStatusNmeaBase(str_in, len_in)
+    {
+        if (mField.size() < eMax) {
+            return;
+        }
+        memset(&mP1, 0, sizeof(mP1));
+        mP1.mUtcTime = setUtcTime(mField[eUtcTime]);
+        mP1.mEpiValidity = strtol(mField[eEpiValidity].c_str(), NULL, 16);
+        mP1.mEpiLat = atof(mField[eEpiLat].c_str());
+        mP1.mEpiLon = atof(mField[eEpiLon].c_str());
+        mP1.mEpiAlt = atof(mField[eEpiAlt].c_str());
+        mP1.mEpiHepe = atoi(mField[eEpiHepe].c_str());
+        mP1.mEpiAltUnc = atof(mField[eEpiAltUnc].c_str());
+        mP1.mEpiSrc = atoi(mField[eEpiSrc].c_str());
+    }
+
+    inline SystemStatusPQWP1& get() { return mP1;}
+};
+
+/******************************************************************************
+ SystemStatusPQWP2
+******************************************************************************/
+class SystemStatusPQWP2
+{
+public:
+    timespec mUtcTime;
+    float    mBestLat;   // x4
+    float    mBestLon;   // x5
+    float    mBestAlt;   // x6
+    float    mBestHepe;  // x7
+    float    mBestAltUnc; // x8
+};
+
+class SystemStatusPQWP2parser : public SystemStatusNmeaBase
+{
+private:
+    enum
+    {
+        eTalker = 0,
+        eUtcTime = 1,
+        eBestLat = 2,
+        eBestLon = 3,
+        eBestAlt = 4,
+        eBestHepe = 5,
+        eBestAltUnc = 6,
+        eMax = eBestAltUnc
+    };
+    SystemStatusPQWP2 mP2;
+
+public:
+    inline float      getBestLat() { return mP2.mBestLat;          }
+    inline float      getBestLon() { return mP2.mBestLon;          }
+    inline float      getBestAlt() { return mP2.mBestAlt;          }
+    inline float      getBestHepe() { return mP2.mBestHepe;         }
+    inline float      getBestAltUnc() { return mP2.mBestAltUnc;       }
+
+    SystemStatusPQWP2parser(const char *str_in, uint32_t len_in)
+        : SystemStatusNmeaBase(str_in, len_in)
+    {
+        if (mField.size() < eMax) {
+            return;
+        }
+        memset(&mP2, 0, sizeof(mP2));
+        mP2.mUtcTime = setUtcTime(mField[eUtcTime]);
+        mP2.mBestLat = atof(mField[eBestLat].c_str());
+        mP2.mBestLon = atof(mField[eBestLon].c_str());
+        mP2.mBestAlt = atof(mField[eBestAlt].c_str());
+        mP2.mBestHepe = atof(mField[eBestHepe].c_str());
+        mP2.mBestAltUnc = atof(mField[eBestAltUnc].c_str());
+    }
+
+    inline SystemStatusPQWP2& get() { return mP2;}
+};
+
+/******************************************************************************
+ SystemStatusPQWP3
+******************************************************************************/
+class SystemStatusPQWP3
+{
+public:
+    timespec  mUtcTime;
+    uint8_t   mXtraValidMask;
+    uint32_t  mGpsXtraAge;
+    uint32_t  mGloXtraAge;
+    uint32_t  mBdsXtraAge;
+    uint32_t  mGalXtraAge;
+    uint32_t  mQzssXtraAge;
+    uint32_t  mGpsXtraValid;
+    uint32_t  mGloXtraValid;
+    uint64_t  mBdsXtraValid;
+    uint64_t  mGalXtraValid;
+    uint8_t   mQzssXtraValid;
+};
+
+class SystemStatusPQWP3parser : public SystemStatusNmeaBase
+{
+private:
+    enum
+    {
+        eTalker = 0,
+        eUtcTime = 1,
+        eXtraValidMask = 2,
+        eGpsXtraAge = 3,
+        eGloXtraAge = 4,
+        eBdsXtraAge = 5,
+        eGalXtraAge = 6,
+        eQzssXtraAge = 7,
+        eGpsXtraValid = 8,
+        eGloXtraValid = 9,
+        eBdsXtraValid = 10,
+        eGalXtraValid = 11,
+        eQzssXtraValid = 12,
+        eMax = eQzssXtraValid
+    };
+    SystemStatusPQWP3 mP3;
+
+public:
+    inline uint8_t    getXtraValid() { return mP3.mXtraValidMask;   }
+    inline uint32_t   getGpsXtraAge() { return mP3.mGpsXtraAge;       }
+    inline uint32_t   getGloXtraAge() { return mP3.mGloXtraAge;       }
+    inline uint32_t   getBdsXtraAge() { return mP3.mBdsXtraAge;       }
+    inline uint32_t   getGalXtraAge() { return mP3.mGalXtraAge;       }
+    inline uint32_t   getQzssXtraAge() { return mP3.mQzssXtraAge;      }
+    inline uint32_t   getGpsXtraValid() { return mP3.mGpsXtraValid;     }
+    inline uint32_t   getGloXtraValid() { return mP3.mGloXtraValid;     }
+    inline uint64_t   getBdsXtraValid() { return mP3.mBdsXtraValid;     }
+    inline uint64_t   getGalXtraValid() { return mP3.mGalXtraValid;     }
+    inline uint8_t    getQzssXtraValid() { return mP3.mQzssXtraValid;    }
+
+    SystemStatusPQWP3parser(const char *str_in, uint32_t len_in)
+        : SystemStatusNmeaBase(str_in, len_in)
+    {
+        if (mField.size() < eMax) {
+            return;
+        }
+        memset(&mP3, 0, sizeof(mP3));
+        mP3.mUtcTime = setUtcTime(mField[eUtcTime]);
+        mP3.mXtraValidMask = strtol(mField[eXtraValidMask].c_str(), NULL, 16);
+        mP3.mGpsXtraAge = atoi(mField[eGpsXtraAge].c_str());
+        mP3.mGloXtraAge = atoi(mField[eGloXtraAge].c_str());
+        mP3.mBdsXtraAge = atoi(mField[eBdsXtraAge].c_str());
+        mP3.mGalXtraAge = atoi(mField[eGalXtraAge].c_str());
+        mP3.mQzssXtraAge = atoi(mField[eQzssXtraAge].c_str());
+        mP3.mGpsXtraValid = strtol(mField[eGpsXtraValid].c_str(), NULL, 16);
+        mP3.mGloXtraValid = strtol(mField[eGloXtraValid].c_str(), NULL, 16);
+        mP3.mBdsXtraValid = strtol(mField[eBdsXtraValid].c_str(), NULL, 16);
+        mP3.mGalXtraValid = strtol(mField[eGalXtraValid].c_str(), NULL, 16);
+        mP3.mQzssXtraValid = strtol(mField[eQzssXtraValid].c_str(), NULL, 16);
+    }
+
+    inline SystemStatusPQWP3& get() { return mP3;}
+};
+
+/******************************************************************************
+ SystemStatusPQWP4
+******************************************************************************/
+class SystemStatusPQWP4
+{
+public:
+    timespec  mUtcTime;
+    uint32_t  mGpsEpheValid;
+    uint32_t  mGloEpheValid;
+    uint64_t  mBdsEpheValid;
+    uint64_t  mGalEpheValid;
+    uint8_t   mQzssEpheValid;
+};
+
+class SystemStatusPQWP4parser : public SystemStatusNmeaBase
+{
+private:
+    enum
+    {
+        eTalker = 0,
+        eUtcTime = 1,
+        eGpsEpheValid = 2,
+        eGloEpheValid = 3,
+        eBdsEpheValid = 4,
+        eGalEpheValid = 5,
+        eQzssEpheValid = 6,
+        eMax = eQzssEpheValid
+    };
+    SystemStatusPQWP4 mP4;
+
+public:
+    inline uint32_t   getGpsEpheValid() { return mP4.mGpsEpheValid;     }
+    inline uint32_t   getGloEpheValid() { return mP4.mGloEpheValid;     }
+    inline uint64_t   getBdsEpheValid() { return mP4.mBdsEpheValid;     }
+    inline uint64_t   getGalEpheValid() { return mP4.mGalEpheValid;     }
+    inline uint8_t    getQzssEpheValid() { return mP4.mQzssEpheValid;    }
+
+    SystemStatusPQWP4parser(const char *str_in, uint32_t len_in)
+        : SystemStatusNmeaBase(str_in, len_in)
+    {
+        if (mField.size() < eMax) {
+            return;
+        }
+        memset(&mP4, 0, sizeof(mP4));
+        mP4.mUtcTime = setUtcTime(mField[eUtcTime]);
+        mP4.mGpsEpheValid = strtol(mField[eGpsEpheValid].c_str(), NULL, 16);
+        mP4.mGloEpheValid = strtol(mField[eGloEpheValid].c_str(), NULL, 16);
+        mP4.mBdsEpheValid = strtol(mField[eBdsEpheValid].c_str(), NULL, 16);
+        mP4.mGalEpheValid = strtol(mField[eGalEpheValid].c_str(), NULL, 16);
+        mP4.mQzssEpheValid = strtol(mField[eQzssEpheValid].c_str(), NULL, 16);
+    }
+
+    inline SystemStatusPQWP4& get() { return mP4;}
+};
+
+/******************************************************************************
+ SystemStatusPQWP5
+******************************************************************************/
+class SystemStatusPQWP5
+{
+public:
+    timespec  mUtcTime;
+    uint32_t  mGpsUnknownMask;
+    uint32_t  mGloUnknownMask;
+    uint64_t  mBdsUnknownMask;
+    uint64_t  mGalUnknownMask;
+    uint8_t   mQzssUnknownMask;
+    uint32_t  mGpsGoodMask;
+    uint32_t  mGloGoodMask;
+    uint64_t  mBdsGoodMask;
+    uint64_t  mGalGoodMask;
+    uint8_t   mQzssGoodMask;
+    uint32_t  mGpsBadMask;
+    uint32_t  mGloBadMask;
+    uint64_t  mBdsBadMask;
+    uint64_t  mGalBadMask;
+    uint8_t   mQzssBadMask;
+};
+
+class SystemStatusPQWP5parser : public SystemStatusNmeaBase
+{
+private:
+    enum
+    {
+        eTalker = 0,
+        eUtcTime = 1,
+        eGpsUnknownMask = 2,
+        eGloUnknownMask = 3,
+        eBdsUnknownMask = 4,
+        eGalUnknownMask = 5,
+        eQzssUnknownMask = 6,
+        eGpsGoodMask = 7,
+        eGloGoodMask = 8,
+        eBdsGoodMask = 9,
+        eGalGoodMask = 10,
+        eQzssGoodMask = 11,
+        eGpsBadMask = 12,
+        eGloBadMask = 13,
+        eBdsBadMask = 14,
+        eGalBadMask = 15,
+        eQzssBadMask = 16,
+        eMax = eQzssBadMask
+    };
+    SystemStatusPQWP5 mP5;
+
+public:
+    inline uint32_t   getGpsUnknownMask() { return mP5.mGpsUnknownMask;   }
+    inline uint32_t   getGloUnknownMask() { return mP5.mGloUnknownMask;   }
+    inline uint64_t   getBdsUnknownMask() { return mP5.mBdsUnknownMask;   }
+    inline uint64_t   getGalUnknownMask() { return mP5.mGalUnknownMask;   }
+    inline uint8_t    getQzssUnknownMask() { return mP5.mQzssUnknownMask;  }
+    inline uint32_t   getGpsGoodMask() { return mP5.mGpsGoodMask;      }
+    inline uint32_t   getGloGoodMask() { return mP5.mGloGoodMask;      }
+    inline uint64_t   getBdsGoodMask() { return mP5.mBdsGoodMask;      }
+    inline uint64_t   getGalGoodMask() { return mP5.mGalGoodMask;      }
+    inline uint8_t    getQzssGoodMask() { return mP5.mQzssGoodMask;     }
+    inline uint32_t   getGpsBadMask() { return mP5.mGpsBadMask;       }
+    inline uint32_t   getGloBadMask() { return mP5.mGloBadMask;       }
+    inline uint64_t   getBdsBadMask() { return mP5.mBdsBadMask;       }
+    inline uint64_t   getGalBadMask() { return mP5.mGalBadMask;       }
+    inline uint8_t    getQzssBadMask() { return mP5.mQzssBadMask;      }
+
+    SystemStatusPQWP5parser(const char *str_in, uint32_t len_in)
+        : SystemStatusNmeaBase(str_in, len_in)
+    {
+        if (mField.size() < eMax) {
+            return;
+        }
+        memset(&mP5, 0, sizeof(mP5));
+        mP5.mUtcTime = setUtcTime(mField[eUtcTime]);
+        mP5.mGpsUnknownMask = strtol(mField[eGpsUnknownMask].c_str(), NULL, 16);
+        mP5.mGloUnknownMask = strtol(mField[eGloUnknownMask].c_str(), NULL, 16);
+        mP5.mBdsUnknownMask = strtol(mField[eBdsUnknownMask].c_str(), NULL, 16);
+        mP5.mGalUnknownMask = strtol(mField[eGalUnknownMask].c_str(), NULL, 16);
+        mP5.mQzssUnknownMask = strtol(mField[eQzssUnknownMask].c_str(), NULL, 16);
+        mP5.mGpsGoodMask = strtol(mField[eGpsGoodMask].c_str(), NULL, 16);
+        mP5.mGloGoodMask = strtol(mField[eGloGoodMask].c_str(), NULL, 16);
+        mP5.mBdsGoodMask = strtol(mField[eBdsGoodMask].c_str(), NULL, 16);
+        mP5.mGalGoodMask = strtol(mField[eGalGoodMask].c_str(), NULL, 16);
+        mP5.mQzssGoodMask = strtol(mField[eQzssGoodMask].c_str(), NULL, 16);
+        mP5.mGpsBadMask = strtol(mField[eGpsBadMask].c_str(), NULL, 16);
+        mP5.mGloBadMask = strtol(mField[eGloBadMask].c_str(), NULL, 16);
+        mP5.mBdsBadMask = strtol(mField[eBdsBadMask].c_str(), NULL, 16);
+        mP5.mGalBadMask = strtol(mField[eGalBadMask].c_str(), NULL, 16);
+        mP5.mQzssBadMask = strtol(mField[eQzssBadMask].c_str(), NULL, 16);
+    }
+
+    inline SystemStatusPQWP5& get() { return mP5;}
+};
+
+/******************************************************************************
+ SystemStatusPQWP6parser
+******************************************************************************/
+class SystemStatusPQWP6
+{
+public:
+    timespec  mUtcTime;
+    uint32_t  mFixInfoMask;
+};
+
+class SystemStatusPQWP6parser : public SystemStatusNmeaBase
+{
+private:
+    enum
+    {
+        eTalker = 0,
+        eUtcTime = 1,
+        eFixInfoMask = 2,
+        eMax = eFixInfoMask
+    };
+    SystemStatusPQWP6 mP6;
+
+public:
+    inline uint32_t   getFixInfoMask() { return mP6.mFixInfoMask;      }
+
+    SystemStatusPQWP6parser(const char *str_in, uint32_t len_in)
+        : SystemStatusNmeaBase(str_in, len_in)
+    {
+        if (mField.size() < eMax) {
+            return;
+        }
+        memset(&mP6, 0, sizeof(mP6));
+        mP6.mUtcTime = setUtcTime(mField[eUtcTime]);
+        mP6.mFixInfoMask = strtol(mField[eFixInfoMask].c_str(), NULL, 16);
+    }
+
+    inline SystemStatusPQWP6& get() { return mP6;}
+};
+
+/******************************************************************************
+ SystemStatusPQWS1parser
+******************************************************************************/
+class SystemStatusPQWS1
+{
+public:
+    timespec  mUtcTime;
+    uint32_t  mFixInfoMask;
+    uint32_t  mHepeLimit;
+};
+
+class SystemStatusPQWS1parser : public SystemStatusNmeaBase
+{
+private:
+    enum
+    {
+        eTalker = 0,
+        eUtcTime = 1,
+        eFixInfoMask = 2,
+        eHepeLimit = 3,
+        eMax = eHepeLimit
+    };
+    SystemStatusPQWS1 mS1;
+
+public:
+    inline uint16_t   getFixInfoMask() { return mS1.mFixInfoMask;      }
+    inline uint32_t   getHepeLimit()   { return mS1.mHepeLimit;      }
+
+    SystemStatusPQWS1parser(const char *str_in, uint32_t len_in)
+        : SystemStatusNmeaBase(str_in, len_in)
+    {
+        if (mField.size() < eMax) {
+            return;
+        }
+        memset(&mS1, 0, sizeof(mS1));
+        mS1.mUtcTime = setUtcTime(mField[eUtcTime]);
+        mS1.mFixInfoMask = atoi(mField[eFixInfoMask].c_str());
+        mS1.mHepeLimit = atoi(mField[eHepeLimit].c_str());
+    }
+
+    inline SystemStatusPQWS1& get() { return mS1;}
+};
+
+/******************************************************************************
+ SystemStatusTimeAndClock
+******************************************************************************/
+SystemStatusTimeAndClock::SystemStatusTimeAndClock(const SystemStatusPQWM1& nmea) :
+    SystemStatusItemBase(nmea.mUtcTime),
+    mGpsWeek(nmea.mGpsWeek),
+    mGpsTowMs(nmea.mGpsTowMs),
+    mTimeValid(nmea.mTimeValid),
+    mTimeSource(nmea.mTimeSource),
+    mTimeUnc(nmea.mTimeUnc),
+    mClockFreqBias(nmea.mClockFreqBias),
+    mClockFreqBiasUnc(nmea.mClockFreqBiasUnc)
+{
+}
+
+bool SystemStatusTimeAndClock::equals(SystemStatusTimeAndClock& peer)
+{
+    if ((mGpsWeek != peer.mGpsWeek) ||
+        (mGpsTowMs != peer.mGpsTowMs) ||
+        (mTimeValid != peer.mTimeValid) ||
+        (mTimeSource != peer.mTimeSource) ||
+        (mTimeUnc != peer.mTimeUnc) ||
+        (mClockFreqBias != peer.mClockFreqBias) ||
+        (mClockFreqBiasUnc != peer.mClockFreqBiasUnc)) {
+        return false;
+    }
+    return true;
+}
+
+void SystemStatusTimeAndClock::dump()
+{
+    LOC_LOGV("TimeAndClock: u=%ld:%ld g=%d:%d v=%d s=%d u=%d b=%d bu=%d",
+             mUtcTime.tv_sec, mUtcTime.tv_nsec,
+             mGpsWeek,
+             mGpsTowMs,
+             mTimeValid,
+             mTimeSource,
+             mTimeUnc,
+             mClockFreqBias,
+             mClockFreqBiasUnc);
+    return;
+}
+
+/******************************************************************************
+ SystemStatusXoState
+******************************************************************************/
+SystemStatusXoState::SystemStatusXoState(const SystemStatusPQWM1& nmea) :
+    SystemStatusItemBase(nmea.mUtcTime),
+    mXoState(nmea.mXoState)
+{
+}
+
+bool SystemStatusXoState::equals(SystemStatusXoState& peer)
+{
+    if (mXoState != peer.mXoState) {
+        return false;
+    }
+    return true;
+}
+
+void SystemStatusXoState::dump()
+{
+    LOC_LOGV("XoState: u=%ld:%ld x=%d",
+             mUtcTime.tv_sec, mUtcTime.tv_nsec,
+             mXoState);
+    return;
+}
+
+/******************************************************************************
+ SystemStatusRfAndParams
+******************************************************************************/
+SystemStatusRfAndParams::SystemStatusRfAndParams(const SystemStatusPQWM1& nmea) :
+    SystemStatusItemBase(nmea.mUtcTime),
+    mPgaGain(nmea.mPgaGain),
+    mGpsBpAmpI(nmea.mGpsBpAmpI),
+    mGpsBpAmpQ(nmea.mGpsBpAmpQ),
+    mAdcI(nmea.mAdcI),
+    mAdcQ(nmea.mAdcQ),
+    mJammerGps(nmea.mJammerGps),
+    mJammerGlo(nmea.mJammerGlo),
+    mJammerBds(nmea.mJammerBds),
+    mJammerGal(nmea.mJammerGal)
+{
+}
+
+bool SystemStatusRfAndParams::equals(SystemStatusRfAndParams& peer)
+{
+    if ((mPgaGain != peer.mPgaGain) ||
+        (mGpsBpAmpI != peer.mGpsBpAmpI) ||
+        (mGpsBpAmpQ != peer.mGpsBpAmpQ) ||
+        (mAdcI != peer.mAdcI) ||
+        (mAdcQ != peer.mAdcQ) ||
+        (mJammerGps != peer.mJammerGps) ||
+        (mJammerGlo != peer.mJammerGlo) ||
+        (mJammerBds != peer.mJammerBds) ||
+        (mJammerGal != peer.mJammerGal)) {
+        return false;
+    }
+    return true;
+}
+
+void SystemStatusRfAndParams::dump()
+{
+    LOC_LOGV("RfAndParams: u=%ld:%ld p=%d bi=%d bq=%d ai=%d aq=%d gp=%d gl=%d bd=%d ga=%d",
+             mUtcTime.tv_sec, mUtcTime.tv_nsec,
+             mPgaGain,
+             mGpsBpAmpI,
+             mGpsBpAmpQ,
+             mAdcI,
+             mAdcQ,
+             mJammerGps,
+             mJammerGlo,
+             mJammerBds,
+             mJammerGal);
+    return;
+}
+
+/******************************************************************************
+ SystemStatusErrRecovery
+******************************************************************************/
+SystemStatusErrRecovery::SystemStatusErrRecovery(const SystemStatusPQWM1& nmea) :
+    SystemStatusItemBase(nmea.mUtcTime),
+    mRecErrorRecovery(nmea.mRecErrorRecovery)
+{
+}
+
+bool SystemStatusErrRecovery::equals(SystemStatusErrRecovery& peer)
+{
+    if (mRecErrorRecovery != peer.mRecErrorRecovery) {
+        return false;
+    }
+    return true;
+}
+
+void SystemStatusErrRecovery::dump()
+{
+    LOC_LOGV("ErrRecovery: u=%ld:%ld e=%d",
+             mUtcTime.tv_sec, mUtcTime.tv_nsec,
+             mRecErrorRecovery);
+    return;
+}
+
+/******************************************************************************
+ SystemStatusInjectedPosition
+******************************************************************************/
+SystemStatusInjectedPosition::SystemStatusInjectedPosition(const SystemStatusPQWP1& nmea) :
+    SystemStatusItemBase(nmea.mUtcTime),
+    mEpiValidity(nmea.mEpiValidity),
+    mEpiLat(nmea.mEpiLat),
+    mEpiLon(nmea.mEpiLon),
+    mEpiAlt(nmea.mEpiAlt),
+    mEpiHepe(nmea.mEpiHepe),
+    mEpiAltUnc(nmea.mEpiAltUnc),
+    mEpiSrc(nmea.mEpiSrc)
+{
+}
+
+bool SystemStatusInjectedPosition::equals(SystemStatusInjectedPosition& peer)
+{
+    if ((mEpiValidity != peer.mEpiValidity) ||
+        (mEpiLat != peer.mEpiLat) ||
+        (mEpiLon != peer.mEpiLon) ||
+        (mEpiAlt != peer.mEpiAlt) ||
+        (mEpiHepe != peer.mEpiHepe) ||
+        (mEpiAltUnc != peer.mEpiAltUnc) ||
+        (mEpiSrc != peer.mEpiSrc)) {
+        return false;
+    }
+    return true;
+}
+
+void SystemStatusInjectedPosition::dump()
+{
+    LOC_LOGV("InjectedPosition: u=%ld:%ld v=%x la=%f lo=%f al=%f he=%f au=%f es=%d",
+             mUtcTime.tv_sec, mUtcTime.tv_nsec,
+             mEpiValidity,
+             mEpiLat,
+             mEpiLon,
+             mEpiAlt,
+             mEpiHepe,
+             mEpiAltUnc,
+             mEpiSrc);
+    return;
+}
+
+/******************************************************************************
+ SystemStatusBestPosition
+******************************************************************************/
+SystemStatusBestPosition::SystemStatusBestPosition(const SystemStatusPQWP2& nmea) :
+    SystemStatusItemBase(nmea.mUtcTime),
+    mBestLat(nmea.mBestLat),
+    mBestLon(nmea.mBestLon),
+    mBestAlt(nmea.mBestAlt),
+    mBestHepe(nmea.mBestHepe),
+    mBestAltUnc(nmea.mBestAltUnc)
+{
+}
+
+bool SystemStatusBestPosition::equals(SystemStatusBestPosition& peer)
+{
+    if ((mBestLat != peer.mBestLat) ||
+        (mBestLon != peer.mBestLon) ||
+        (mBestAlt != peer.mBestAlt) ||
+        (mBestHepe != peer.mBestHepe) ||
+        (mBestAltUnc != peer.mBestAltUnc)) {
+        return false;
+    }
+    return true;
+}
+
+void SystemStatusBestPosition::dump()
+{
+    LOC_LOGV("BestPosition: u=%ld:%ld la=%f lo=%f al=%f he=%f au=%f",
+             mUtcTime.tv_sec, mUtcTime.tv_nsec,
+             mBestLat,
+             mBestLon,
+             mBestAlt,
+             mBestHepe,
+             mBestAltUnc);
+    return;
+}
+
+/******************************************************************************
+ SystemStatusXtra
+******************************************************************************/
+SystemStatusXtra::SystemStatusXtra(const SystemStatusPQWP3& nmea) :
+    SystemStatusItemBase(nmea.mUtcTime),
+    mXtraValidMask(nmea.mXtraValidMask),
+    mGpsXtraAge(nmea.mGpsXtraAge),
+    mGloXtraAge(nmea.mGloXtraAge),
+    mBdsXtraAge(nmea.mBdsXtraAge),
+    mGalXtraAge(nmea.mGalXtraAge),
+    mQzssXtraAge(nmea.mQzssXtraAge),
+    mGpsXtraValid(nmea.mGpsXtraValid),
+    mGloXtraValid(nmea.mGloXtraValid),
+    mBdsXtraValid(nmea.mBdsXtraValid),
+    mGalXtraValid(nmea.mGalXtraValid),
+    mQzssXtraValid(nmea.mQzssXtraValid)
+{
+}
+
+bool SystemStatusXtra::equals(SystemStatusXtra& peer)
+{
+    if ((mXtraValidMask != peer.mXtraValidMask) ||
+        (mGpsXtraAge != peer.mGpsXtraAge) ||
+        (mGloXtraAge != peer.mGloXtraAge) ||
+        (mBdsXtraAge != peer.mBdsXtraAge) ||
+        (mGalXtraAge != peer.mGalXtraAge) ||
+        (mQzssXtraAge != peer.mQzssXtraAge) ||
+        (mGpsXtraValid != peer.mGpsXtraValid) ||
+        (mGloXtraValid != peer.mGloXtraValid) ||
+        (mBdsXtraValid != peer.mBdsXtraValid) ||
+        (mGalXtraValid != peer.mGalXtraValid) ||
+        (mQzssXtraValid != peer.mQzssXtraValid)) {
+        return false;
+    }
+    return true;
+}
+
+void SystemStatusXtra::dump()
+{
+    LOC_LOGV("SystemStatusXtra: u=%ld:%ld m=%x a=%d:%d:%d:%d:%d v=%x:%x:%x:%x:%x",
+             mUtcTime.tv_sec, mUtcTime.tv_nsec,
+             mXtraValidMask,
+             mGpsXtraAge,
+             mGloXtraAge,
+             mBdsXtraAge,
+             mGalXtraAge,
+             mQzssXtraAge,
+             mGpsXtraValid,
+             mGloXtraValid,
+             mBdsXtraValid,
+             mGalXtraValid,
+             mQzssXtraValid);
+    return;
+}
+
+/******************************************************************************
+ SystemStatusEphemeris
+******************************************************************************/
+SystemStatusEphemeris::SystemStatusEphemeris(const SystemStatusPQWP4& nmea) :
+    SystemStatusItemBase(nmea.mUtcTime),
+    mGpsEpheValid(nmea.mGpsEpheValid),
+    mGloEpheValid(nmea.mGloEpheValid),
+    mBdsEpheValid(nmea.mBdsEpheValid),
+    mGalEpheValid(nmea.mGalEpheValid),
+    mQzssEpheValid(nmea.mQzssEpheValid)
+{
+}
+
+bool SystemStatusEphemeris::equals(SystemStatusEphemeris& peer)
+{
+    if ((mGpsEpheValid != peer.mGpsEpheValid) ||
+        (mGloEpheValid != peer.mGloEpheValid) ||
+        (mBdsEpheValid != peer.mBdsEpheValid) ||
+        (mGalEpheValid != peer.mGalEpheValid) ||
+        (mQzssEpheValid != peer.mQzssEpheValid)) {
+        return false;
+    }
+    return true;
+}
+
+void SystemStatusEphemeris::dump()
+{
+    LOC_LOGV("Ephemeris: u=%ld:%ld ev=%x:%x:%x:%x:%x",
+             mUtcTime.tv_sec, mUtcTime.tv_nsec,
+             mGpsEpheValid,
+             mGloEpheValid,
+             mBdsEpheValid,
+             mGalEpheValid,
+             mQzssEpheValid);
+    return;
+}
+
+/******************************************************************************
+ SystemStatusSvHealth
+******************************************************************************/
+SystemStatusSvHealth::SystemStatusSvHealth(const SystemStatusPQWP5& nmea) :
+    SystemStatusItemBase(nmea.mUtcTime),
+    mGpsUnknownMask(nmea.mGpsUnknownMask),
+    mGloUnknownMask(nmea.mGloUnknownMask),
+    mBdsUnknownMask(nmea.mBdsUnknownMask),
+    mGalUnknownMask(nmea.mGalUnknownMask),
+    mQzssUnknownMask(nmea.mQzssUnknownMask),
+    mGpsGoodMask(nmea.mGpsGoodMask),
+    mGloGoodMask(nmea.mGloGoodMask),
+    mBdsGoodMask(nmea.mBdsGoodMask),
+    mGalGoodMask(nmea.mGalGoodMask),
+    mQzssGoodMask(nmea.mQzssGoodMask),
+    mGpsBadMask(nmea.mGpsBadMask),
+    mGloBadMask(nmea.mGloBadMask),
+    mBdsBadMask(nmea.mBdsBadMask),
+    mGalBadMask(nmea.mGalBadMask),
+    mQzssBadMask(nmea.mQzssBadMask)
+{
+}
+
+bool SystemStatusSvHealth::equals(SystemStatusSvHealth& peer)
+{
+    if ((mGpsUnknownMask != peer.mGpsUnknownMask) ||
+        (mGloUnknownMask != peer.mGloUnknownMask) ||
+        (mBdsUnknownMask != peer.mBdsUnknownMask) ||
+        (mGalUnknownMask != peer.mGalUnknownMask) ||
+        (mQzssUnknownMask != peer.mQzssUnknownMask) ||
+        (mGpsGoodMask != peer.mGpsGoodMask) ||
+        (mGloGoodMask != peer.mGloGoodMask) ||
+        (mBdsGoodMask != peer.mBdsGoodMask) ||
+        (mGalGoodMask != peer.mGalGoodMask) ||
+        (mQzssGoodMask != peer.mQzssGoodMask) ||
+        (mGpsBadMask != peer.mGpsBadMask) ||
+        (mGloBadMask != peer.mGloBadMask) ||
+        (mBdsBadMask != peer.mBdsBadMask) ||
+        (mGalBadMask != peer.mGalBadMask) ||
+        (mQzssBadMask != peer.mQzssBadMask)) {
+        return false;
+    }
+    return true;
+}
+
+void SystemStatusSvHealth::dump()
+{
+    LOC_LOGV("SvHealth: u=%ld:%ld u=%x:%x:%x:%x:%x g=%x:%x:%x:%x:%x b=%x:%x:%x:%x:%x",
+             mUtcTime.tv_sec, mUtcTime.tv_nsec,
+             mGpsUnknownMask,
+             mGloUnknownMask,
+             mBdsUnknownMask,
+             mGalUnknownMask,
+             mQzssUnknownMask,
+             mGpsGoodMask,
+             mGloGoodMask,
+             mBdsGoodMask,
+             mGalGoodMask,
+             mQzssGoodMask,
+             mGpsBadMask,
+             mGloBadMask,
+             mBdsBadMask,
+             mGalBadMask,
+             mQzssBadMask);
+    return;
+}
+
+/******************************************************************************
+ SystemStatusPdr
+******************************************************************************/
+SystemStatusPdr::SystemStatusPdr(const SystemStatusPQWP6& nmea) :
+    SystemStatusItemBase(nmea.mUtcTime),
+    mFixInfoMask(nmea.mFixInfoMask)
+{
+}
+
+bool SystemStatusPdr::equals(SystemStatusPdr& peer)
+{
+    if (mFixInfoMask != peer.mFixInfoMask) {
+        return false;
+    }
+    return true;
+}
+
+void SystemStatusPdr::dump()
+{
+    LOC_LOGV("Pdr: u=%ld:%ld m=%x",
+             mUtcTime.tv_sec, mUtcTime.tv_nsec,
+             mFixInfoMask);
+    return;
+}
+
+/******************************************************************************
+ SystemStatusPositionFailure
+******************************************************************************/
+SystemStatusPositionFailure::SystemStatusPositionFailure(const SystemStatusPQWS1& nmea) :
+    SystemStatusItemBase(nmea.mUtcTime),
+    mFixInfoMask(nmea.mFixInfoMask),
+    mHepeLimit(nmea.mHepeLimit)
+{
+}
+
+bool SystemStatusPositionFailure::equals(SystemStatusPositionFailure& peer)
+{
+    if ((mFixInfoMask != peer.mFixInfoMask) ||
+        (mHepeLimit != peer.mHepeLimit)) {
+        return false;
+    }
+    return true;
+}
+
+void SystemStatusPositionFailure::dump()
+{
+    LOC_LOGV("PositionFailure: u=%ld:%ld m=%d h=%d",
+             mUtcTime.tv_sec, mUtcTime.tv_nsec,
+             mFixInfoMask,
+             mHepeLimit);
+    return;
+}
+
+/******************************************************************************
+ SystemStatusLocation
+******************************************************************************/
+bool SystemStatusLocation::equals(SystemStatusLocation& peer)
+{
+    if ((mLocation.gpsLocation.latitude != peer.mLocation.gpsLocation.latitude) ||
+        (mLocation.gpsLocation.longitude != peer.mLocation.gpsLocation.longitude) ||
+        (mLocation.gpsLocation.altitude != peer.mLocation.gpsLocation.altitude)) {
+        return false;
+    }
+    return true;
+}
+
+void SystemStatusLocation::dump()
+{
+    LOC_LOGV("Location: lat=%f lon=%f alt=%f spd=%f",
+             mLocation.gpsLocation.latitude,
+             mLocation.gpsLocation.longitude,
+             mLocation.gpsLocation.altitude,
+             mLocation.gpsLocation.speed);
+    return;
+}
+
+/******************************************************************************
+ SystemStatus
+******************************************************************************/
+pthread_mutex_t SystemStatus::mMutexSystemStatus = PTHREAD_MUTEX_INITIALIZER;
+
+SystemStatus::SystemStatus()
+{
+    mCache.mLocation.clear();
+
+    mCache.mTimeAndClock.clear();
+    mCache.mXoState.clear();
+    mCache.mRfAndParams.clear();
+    mCache.mErrRecovery.clear();
+
+    mCache.mInjectedPosition.clear();
+    mCache.mBestPosition.clear();
+    mCache.mXtra.clear();
+    mCache.mEphemeris.clear();
+    mCache.mSvHealth.clear();
+    mCache.mPdr.clear();
+    mCache.mPositionFailure.clear();
+}
+
+/******************************************************************************
+ SystemStatus - M1 functions
+******************************************************************************/
+bool SystemStatus::setTimeAndCLock(const SystemStatusPQWM1& nmea)
+{
+    SystemStatusTimeAndClock s(nmea);
+    if (mCache.mTimeAndClock.empty() || !mCache.mTimeAndClock.back().equals(s)) {
+        mCache.mTimeAndClock.push_back(s);
+        if (mCache.mTimeAndClock.size() > maxTimeAndClock) {
+            mCache.mTimeAndClock.erase(mCache.mTimeAndClock.begin());
+        }
+    }
+    return true;
+}
+
+bool SystemStatus::setXoState(const SystemStatusPQWM1& nmea)
+{
+    SystemStatusXoState s(nmea);
+    if (mCache.mXoState.empty() || !mCache.mXoState.back().equals(s)) {
+        mCache.mXoState.push_back(s);
+        if (mCache.mXoState.size() > maxXoState) {
+            mCache.mXoState.erase(mCache.mXoState.begin());
+        }
+    }
+    return true;
+}
+
+bool SystemStatus::setRfAndParams(const SystemStatusPQWM1& nmea)
+{
+    SystemStatusRfAndParams s(nmea);
+    if (mCache.mRfAndParams.empty() || !mCache.mRfAndParams.back().equals(s)) {
+        mCache.mRfAndParams.push_back(s);
+        if (mCache.mRfAndParams.size() > maxRfAndParams) {
+            mCache.mRfAndParams.erase(mCache.mRfAndParams.begin());
+        }
+    }
+    return true;
+}
+
+bool SystemStatus::setErrRecovery(const SystemStatusPQWM1& nmea)
+{
+    SystemStatusErrRecovery s(nmea);
+    if (mCache.mErrRecovery.empty() || !mCache.mErrRecovery.back().equals(s)) {
+        mCache.mErrRecovery.push_back(s);
+        if (mCache.mErrRecovery.size() > maxErrRecovery) {
+            mCache.mErrRecovery.erase(mCache.mErrRecovery.begin());
+        }
+    }
+    return true;
+}
+
+/******************************************************************************
+ SystemStatus - Px functions
+******************************************************************************/
+bool SystemStatus::setInjectedPosition(const SystemStatusPQWP1& nmea)
+{
+    SystemStatusInjectedPosition s(nmea);
+    if (mCache.mInjectedPosition.empty() || !mCache.mInjectedPosition.back().equals(s)) {
+        mCache.mInjectedPosition.push_back(s);
+        if (mCache.mInjectedPosition.size() > maxInjectedPosition) {
+            mCache.mInjectedPosition.erase(mCache.mInjectedPosition.begin());
+        }
+    }
+    return true;
+}
+
+bool SystemStatus::setBestPosition(const SystemStatusPQWP2& nmea)
+{
+    SystemStatusBestPosition s(nmea);
+    if (mCache.mBestPosition.empty() || !mCache.mBestPosition.back().equals(s)) {
+        mCache.mBestPosition.push_back(s);
+        if (mCache.mBestPosition.size() > maxBestPosition) {
+            mCache.mBestPosition.erase(mCache.mBestPosition.begin());
+        }
+    }
+    return true;
+}
+
+bool SystemStatus::setXtra(const SystemStatusPQWP3& nmea)
+{
+    SystemStatusXtra s(nmea);
+    if (mCache.mXtra.empty() || !mCache.mXtra.back().equals(s)) {
+        mCache.mXtra.push_back(s);
+        if (mCache.mXtra.size() > maxXtra) {
+            mCache.mXtra.erase(mCache.mXtra.begin());
+        }
+    }
+    return true;
+}
+
+bool SystemStatus::setEphemeris(const SystemStatusPQWP4& nmea)
+{
+    SystemStatusEphemeris s(nmea);
+    if (mCache.mEphemeris.empty() || !mCache.mEphemeris.back().equals(s)) {
+        mCache.mEphemeris.push_back(s);
+        if (mCache.mEphemeris.size() > maxEphemeris) {
+            mCache.mEphemeris.erase(mCache.mEphemeris.begin());
+        }
+    }
+    return true;
+}
+
+bool SystemStatus::setSvHealth(const SystemStatusPQWP5& nmea)
+{
+    SystemStatusSvHealth s(nmea);
+    if (mCache.mSvHealth.empty() || !mCache.mSvHealth.back().equals(s)) {
+        mCache.mSvHealth.push_back(s);
+        if (mCache.mSvHealth.size() > maxSvHealth) {
+            mCache.mSvHealth.erase(mCache.mSvHealth.begin());
+        }
+    }
+    return true;
+}
+
+bool SystemStatus::setPdr(const SystemStatusPQWP6& nmea)
+{
+    SystemStatusPdr s(nmea);
+    if (mCache.mPdr.empty() || !mCache.mPdr.back().equals(s)) {
+        mCache.mPdr.push_back(s);
+        if (mCache.mPdr.size() > maxPdr) {
+            mCache.mPdr.erase(mCache.mPdr.begin());
+        }
+    }
+    return true;
+}
+
+/******************************************************************************
+ SystemStatus - Sx functions
+******************************************************************************/
+bool SystemStatus::setPositionFailure(const SystemStatusPQWS1& nmea)
+{
+    SystemStatusPositionFailure s(nmea);
+    if (mCache.mPositionFailure.empty() || !mCache.mPositionFailure.back().equals(s)) {
+        mCache.mPositionFailure.push_back(s);
+        if (mCache.mPositionFailure.size() > maxPositionFailure) {
+            mCache.mPositionFailure.erase(mCache.mPositionFailure.begin());
+        }
+    }
+    return true;
+}
+
+/******************************************************************************
+@brief      API to set report data into internal buffer
+
+@param[In]  data pointer to the NMEA string
+@param[In]  len  length of the NMEA string
+
+@return     true when successfully done
+******************************************************************************/
+static uint32_t cnt = 0;
+static uint32_t cnt_m1 = 0;
+static uint32_t cnt_p1 = 0;
+static uint32_t cnt_p2 = 0;
+static uint32_t cnt_p3 = 0;
+static uint32_t cnt_p4 = 0;
+static uint32_t cnt_p5 = 0;
+static uint32_t cnt_p6 = 0;
+static uint32_t cnt_s1 = 0;
+
+bool SystemStatus::setNmeaString(const char *data, uint32_t len)
+{
+    bool ret = false;
+    if (NULL == data
+        || (len < SystemStatusNmeaBase::NMEA_MINSIZE)
+        || (len > SystemStatusNmeaBase::NMEA_MAXSIZE)) {
+        return false;
+    }
+
+    char buf[SystemStatusNmeaBase::NMEA_MAXSIZE + 1] = { 0 };
+    strncpy(buf, data, len);
+    LOC_LOGI("setNmeaString-0321a: nmea=%s", buf);
+
+    pthread_mutex_lock(&mMutexSystemStatus);
+
+    // parse the received nmea strings here
+    if      (0 == strncmp(data, "$PQWM1", SystemStatusNmeaBase::NMEA_MINSIZE)) {
+        SystemStatusPQWM1 s = SystemStatusPQWM1parser(buf, len).get();
+        ret  = setTimeAndCLock(s);
+        ret |= setXoState(s);
+        ret |= setRfAndParams(s);
+        ret |= setErrRecovery(s);
+        cnt_m1++;
+    }
+    else if (0 == strncmp(data, "$PQWP1", SystemStatusNmeaBase::NMEA_MINSIZE)) {
+        ret = setInjectedPosition(SystemStatusPQWP1parser(buf, len).get());
+        cnt_p1++;
+    }
+    else if (0 == strncmp(data, "$PQWP2", SystemStatusNmeaBase::NMEA_MINSIZE)) {
+        ret = setBestPosition(SystemStatusPQWP2parser(buf, len).get());
+        cnt_p2++;
+    }
+    else if (0 == strncmp(data, "$PQWP3", SystemStatusNmeaBase::NMEA_MINSIZE)) {
+        ret = setXtra(SystemStatusPQWP3parser(buf, len).get());
+        cnt_p3++;
+    }
+    else if (0 == strncmp(data, "$PQWP4", SystemStatusNmeaBase::NMEA_MINSIZE)) {
+        ret = setEphemeris(SystemStatusPQWP4parser(buf, len).get());
+        cnt_p4++;
+    }
+    else if (0 == strncmp(data, "$PQWP5", SystemStatusNmeaBase::NMEA_MINSIZE)) {
+        ret = setSvHealth(SystemStatusPQWP5parser(buf, len).get());
+        cnt_p5++;
+    }
+    else if (0 == strncmp(data, "$PQWP6", SystemStatusNmeaBase::NMEA_MINSIZE)) {
+        ret = setPdr(SystemStatusPQWP6parser(buf, len).get());
+        cnt_p6++;
+    }
+    else if (0 == strncmp(data, "$PQWS1", SystemStatusNmeaBase::NMEA_MINSIZE)) {
+        ret = setPositionFailure(SystemStatusPQWS1parser(buf, len).get());
+        cnt_s1++;
+    }
+    else {
+        // do nothing
+    }
+    cnt++;
+    LOC_LOGV("setNmeaString: cnt=%d M:%d 1:%d 2:%d 3:%d 4:%d 5:%d 6:%d S:%d",
+             cnt,
+             cnt_m1,
+             cnt_p1,
+             cnt_p2,
+             cnt_p3,
+             cnt_p4,
+             cnt_p5,
+             cnt_p6,
+             cnt_s1);
+
+    pthread_mutex_unlock(&mMutexSystemStatus);
+    return ret;
+}
+
+/******************************************************************************
+@brief      API to set report position data into internal buffer
+
+@param[In]  UlpLocation
+
+@return     true when successfully done
+******************************************************************************/
+bool SystemStatus::eventPosition(const UlpLocation& location,
+                                 const GpsLocationExtended& locationEx)
+{
+    timespec ts;
+    ts.tv_sec = location.gpsLocation.timestamp / 1000ULL;
+    ts.tv_nsec = (location.gpsLocation.timestamp % 1000ULL) * 1000000ULL;
+    SystemStatusLocation s(location, locationEx, ts);
+    if ((mCache.mLocation.empty()) || !mCache.mLocation.back().equals(s)) {
+        mCache.mLocation.push_back(s);
+        if (mCache.mLocation.size() > maxLocation) {
+            mCache.mLocation.erase(mCache.mLocation.begin());
+        }
+
+        LOC_LOGV("eventPosition - lat=%f lon=%f alt=%f speed=%f",
+                 s.mLocation.gpsLocation.latitude,
+                 s.mLocation.gpsLocation.longitude,
+                 s.mLocation.gpsLocation.altitude,
+                 s.mLocation.gpsLocation.speed);
+
+    }
+    return true;
+}
+
+/******************************************************************************
+@brief      API to get report data into a given buffer
+
+@param[In]  reference to report buffer
+@param[In]  bool flag to identify latest only or entire buffer
+
+@return     true when successfully done
+******************************************************************************/
+bool SystemStatus::getReport(SystemStatusReports& report, bool isLatestOnly) const
+{
+    pthread_mutex_lock(&mMutexSystemStatus);
+
+    if (isLatestOnly) {
+        // push back only the latest report and return it
+        report.mLocation.clear();
+        if (mCache.mLocation.size() >= 1) {
+            report.mLocation.push_back(mCache.mLocation.back());
+            report.mLocation.back().dump();
+        }
+
+        report.mTimeAndClock.clear();
+        if (mCache.mTimeAndClock.size() >= 1) {
+            report.mTimeAndClock.push_back(mCache.mTimeAndClock.back());
+            report.mTimeAndClock.back().dump();
+        }
+        report.mXoState.clear();
+        if (mCache.mXoState.size() >= 1) {
+            report.mXoState.push_back(mCache.mXoState.back());
+            report.mXoState.back().dump();
+        }
+        report.mRfAndParams.clear();
+        if (mCache.mRfAndParams.size() >= 1) {
+            report.mRfAndParams.push_back(mCache.mRfAndParams.back());
+            report.mRfAndParams.back().dump();
+        }
+        report.mErrRecovery.clear();
+        if (mCache.mErrRecovery.size() >= 1) {
+            report.mErrRecovery.push_back(mCache.mErrRecovery.back());
+            report.mErrRecovery.back().dump();
+        }
+
+        report.mInjectedPosition.clear();
+        if (mCache.mInjectedPosition.size() >= 1) {
+            report.mInjectedPosition.push_back(mCache.mInjectedPosition.back());
+            report.mInjectedPosition.back().dump();
+        }
+        report.mBestPosition.clear();
+        if (mCache.mBestPosition.size() >= 1) {
+            report.mBestPosition.push_back(mCache.mBestPosition.back());
+            report.mBestPosition.back().dump();
+        }
+        report.mXtra.clear();
+        if (mCache.mXtra.size() >= 1) {
+            report.mXtra.push_back(mCache.mXtra.back());
+            report.mXtra.back().dump();
+        }
+        report.mEphemeris.clear();
+        if (mCache.mEphemeris.size() >= 1) {
+            report.mEphemeris.push_back(mCache.mEphemeris.back());
+            report.mEphemeris.back().dump();
+        }
+        report.mSvHealth.clear();
+        if (mCache.mSvHealth.size() >= 1) {
+            report.mSvHealth.push_back(mCache.mSvHealth.back());
+            report.mSvHealth.back().dump();
+        }
+        report.mPdr.clear();
+        if (mCache.mPdr.size() >= 1) {
+            report.mPdr.push_back(mCache.mPdr.back());
+            report.mPdr.back().dump();
+        }
+        report.mPositionFailure.clear();
+        if (mCache.mPositionFailure.size() >= 1) {
+            report.mPositionFailure.push_back(mCache.mPositionFailure.back());
+            report.mPositionFailure.back().dump();
+        }
+    }
+    else {
+        // copy entire reports and return them
+        report.mLocation.clear();
+
+        report.mTimeAndClock.clear();
+        report.mXoState.clear();
+        report.mRfAndParams.clear();
+        report.mErrRecovery.clear();
+
+        report.mInjectedPosition.clear();
+        report.mBestPosition.clear();
+        report.mXtra.clear();
+        report.mEphemeris.clear();
+        report.mSvHealth.clear();
+        report.mPdr.clear();
+        report.mPositionFailure.clear();
+        report = mCache;
+    }
+
+    pthread_mutex_unlock(&mMutexSystemStatus);
+    return true;
+}
+
+} // namespace loc_core
+
diff --git a/core/SystemStatus.h b/core/SystemStatus.h
new file mode 100644
index 0000000..208c669
--- /dev/null
+++ b/core/SystemStatus.h
@@ -0,0 +1,306 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer in the documentation and/or other materials provided
+ *       with the distribution.
+ *     * Neither the name of The Linux Foundation, nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+#ifndef __SYSTEM_STATUS__
+#define __SYSTEM_STATUS__
+
+#include <stdint.h>
+#include <vector>
+#include <gps_extended_c.h>
+
+#define GPS_MIN  (1)
+#define SBAS_MIN (33)
+#define GLO_MIN  (65)
+#define BDS_MIN  (201)
+#define QZSS_MIN (193)
+#define GAL_MIN  (301)
+
+namespace loc_core
+{
+
+/******************************************************************************
+ SystemStatus report data structure
+******************************************************************************/
+class SystemStatusItemBase
+{
+public:
+    timespec mUtcTime;
+    SystemStatusItemBase(timespec utctime) : mUtcTime(utctime) { };
+    virtual ~SystemStatusItemBase() { };
+    virtual void dump(void) { };
+};
+
+class SystemStatusLocation : public SystemStatusItemBase
+{
+public:
+    UlpLocation mLocation;
+    GpsLocationExtended mLocationEx;
+    SystemStatusLocation(const UlpLocation& location,
+                         const GpsLocationExtended& locationEx,
+                         const timespec& ts) :
+        SystemStatusItemBase(ts),
+        mLocation(location),
+        mLocationEx(locationEx){ };
+    bool equals(SystemStatusLocation& peer);
+    void dump(void);
+};
+
+class SystemStatusPQWM1;
+class SystemStatusTimeAndClock : public SystemStatusItemBase
+{
+public:
+    uint16_t mGpsWeek;
+    uint32_t mGpsTowMs;
+    uint8_t  mTimeValid;
+    uint8_t  mTimeSource;
+    int32_t  mTimeUnc;
+    int32_t  mClockFreqBias;
+    int32_t  mClockFreqBiasUnc;
+    SystemStatusTimeAndClock(const SystemStatusPQWM1& nmea);
+    bool equals(SystemStatusTimeAndClock& peer);
+    void dump(void);
+};
+
+class SystemStatusXoState : public SystemStatusItemBase
+{
+public:
+    uint8_t  mXoState;
+    SystemStatusXoState(const SystemStatusPQWM1& nmea);
+    bool equals(SystemStatusXoState& peer);
+    void dump(void);
+};
+
+class SystemStatusRfAndParams : public SystemStatusItemBase
+{
+public:
+    int32_t  mPgaGain;
+    uint32_t mGpsBpAmpI;
+    uint32_t mGpsBpAmpQ;
+    uint32_t mAdcI;
+    uint32_t mAdcQ;
+    uint32_t mJammerGps;
+    uint32_t mJammerGlo;
+    uint32_t mJammerBds;
+    uint32_t mJammerGal;
+    SystemStatusRfAndParams(const SystemStatusPQWM1& nmea);
+    bool equals(SystemStatusRfAndParams& peer);
+    void dump(void);
+};
+
+class SystemStatusErrRecovery : public SystemStatusItemBase
+{
+public:
+    uint32_t mRecErrorRecovery;
+    SystemStatusErrRecovery(const SystemStatusPQWM1& nmea);
+    bool equals(SystemStatusErrRecovery& peer);
+    void dump(void);
+};
+
+class SystemStatusPQWP1;
+class SystemStatusInjectedPosition : public SystemStatusItemBase
+{
+public:
+    uint8_t  mEpiValidity;
+    float    mEpiLat;
+    float    mEpiLon;
+    float    mEpiAlt;
+    float    mEpiHepe;
+    float    mEpiAltUnc;
+    uint8_t  mEpiSrc;
+    SystemStatusInjectedPosition(const SystemStatusPQWP1& nmea);
+    bool equals(SystemStatusInjectedPosition& peer);
+    void dump(void);
+};
+
+class SystemStatusPQWP2;
+class SystemStatusBestPosition : public SystemStatusItemBase
+{
+public:
+    float    mBestLat;
+    float    mBestLon;
+    float    mBestAlt;
+    float    mBestHepe;
+    float    mBestAltUnc;
+    SystemStatusBestPosition(const SystemStatusPQWP2& nmea);
+    bool equals(SystemStatusBestPosition& peer);
+    void dump(void);
+};
+
+class SystemStatusPQWP3;
+class SystemStatusXtra : public SystemStatusItemBase
+{
+public:
+    uint8_t   mXtraValidMask;
+    uint32_t  mGpsXtraAge;
+    uint32_t  mGloXtraAge;
+    uint32_t  mBdsXtraAge;
+    uint32_t  mGalXtraAge;
+    uint32_t  mQzssXtraAge;
+    uint32_t  mGpsXtraValid;
+    uint32_t  mGloXtraValid;
+    uint64_t  mBdsXtraValid;
+    uint64_t  mGalXtraValid;
+    uint8_t   mQzssXtraValid;
+    SystemStatusXtra(const SystemStatusPQWP3& nmea);
+    bool equals(SystemStatusXtra& peer);
+    void dump(void);
+};
+
+class SystemStatusPQWP4;
+class SystemStatusEphemeris : public SystemStatusItemBase
+{
+public:
+    uint32_t  mGpsEpheValid;
+    uint32_t  mGloEpheValid;
+    uint64_t  mBdsEpheValid;
+    uint64_t  mGalEpheValid;
+    uint8_t   mQzssEpheValid;
+    SystemStatusEphemeris(const SystemStatusPQWP4& nmea);
+    bool equals(SystemStatusEphemeris& peer);
+    void dump(void);
+};
+
+class SystemStatusPQWP5;
+class SystemStatusSvHealth : public SystemStatusItemBase
+{
+public:
+    uint32_t  mGpsUnknownMask;
+    uint32_t  mGloUnknownMask;
+    uint64_t  mBdsUnknownMask;
+    uint64_t  mGalUnknownMask;
+    uint8_t   mQzssUnknownMask;
+    uint32_t  mGpsGoodMask;
+    uint32_t  mGloGoodMask;
+    uint64_t  mBdsGoodMask;
+    uint64_t  mGalGoodMask;
+    uint8_t   mQzssGoodMask;
+    uint32_t  mGpsBadMask;
+    uint32_t  mGloBadMask;
+    uint64_t  mBdsBadMask;
+    uint64_t  mGalBadMask;
+    uint8_t   mQzssBadMask;
+    SystemStatusSvHealth(const SystemStatusPQWP5& nmea);
+    bool equals(SystemStatusSvHealth& peer);
+    void dump(void);
+};
+
+class SystemStatusPQWP6;
+class SystemStatusPdr : public SystemStatusItemBase
+{
+public:
+    uint32_t  mFixInfoMask;
+    SystemStatusPdr(const SystemStatusPQWP6& nmea);
+    bool equals(SystemStatusPdr& peer);
+    void dump(void);
+};
+
+class SystemStatusPQWS1;
+class SystemStatusPositionFailure : public SystemStatusItemBase
+{
+public:
+    uint32_t  mFixInfoMask;
+    uint32_t  mHepeLimit;
+    SystemStatusPositionFailure(const SystemStatusPQWS1& nmea);
+    bool equals(SystemStatusPositionFailure& peer);
+    void dump(void);
+};
+
+/******************************************************************************
+ SystemStatusReports
+******************************************************************************/
+class SystemStatusReports
+{
+public:
+    std::vector<SystemStatusLocation>         mLocation;
+
+    std::vector<SystemStatusTimeAndClock>     mTimeAndClock;
+    std::vector<SystemStatusXoState>          mXoState;
+    std::vector<SystemStatusRfAndParams>      mRfAndParams;
+    std::vector<SystemStatusErrRecovery>      mErrRecovery;
+
+    std::vector<SystemStatusInjectedPosition> mInjectedPosition;
+    std::vector<SystemStatusBestPosition>     mBestPosition;
+    std::vector<SystemStatusXtra>             mXtra;
+    std::vector<SystemStatusEphemeris>        mEphemeris;
+    std::vector<SystemStatusSvHealth>         mSvHealth;
+    std::vector<SystemStatusPdr>              mPdr;
+    std::vector<SystemStatusPositionFailure>  mPositionFailure;
+};
+
+/******************************************************************************
+ SystemStatus
+******************************************************************************/
+class SystemStatus
+{
+    static pthread_mutex_t mMutexSystemStatus;
+
+    static const uint32_t                     maxLocation = 5;
+
+    static const uint32_t                     maxTimeAndClock = 5;
+    static const uint32_t                     maxXoState = 5;
+    static const uint32_t                     maxRfAndParams = 5;
+    static const uint32_t                     maxErrRecovery = 5;
+
+    static const uint32_t                     maxInjectedPosition = 5;
+    static const uint32_t                     maxBestPosition = 5;
+    static const uint32_t                     maxXtra = 5;
+    static const uint32_t                     maxEphemeris = 5;
+    static const uint32_t                     maxSvHealth = 5;
+    static const uint32_t                     maxPdr = 5;
+    static const uint32_t                     maxPositionFailure = 5;
+
+    SystemStatusReports mCache;
+
+    bool setLocation(const UlpLocation& location);
+
+    bool setTimeAndCLock(const SystemStatusPQWM1& nmea);
+    bool setXoState(const SystemStatusPQWM1& nmea);
+    bool setRfAndParams(const SystemStatusPQWM1& nmea);
+    bool setErrRecovery(const SystemStatusPQWM1& nmea);
+
+    bool setInjectedPosition(const SystemStatusPQWP1& nmea);
+    bool setBestPosition(const SystemStatusPQWP2& nmea);
+    bool setXtra(const SystemStatusPQWP3& nmea);
+    bool setEphemeris(const SystemStatusPQWP4& nmea);
+    bool setSvHealth(const SystemStatusPQWP5& nmea);
+    bool setPdr(const SystemStatusPQWP6& nmea);
+    bool setPositionFailure(const SystemStatusPQWS1& nmea);
+
+public:
+    SystemStatus();
+    ~SystemStatus() { }
+
+    bool eventPosition(const UlpLocation& location,const GpsLocationExtended& locationEx);
+    bool setNmeaString(const char *data, uint32_t len);
+    bool getReport(SystemStatusReports& reports, bool isLatestonly = false) const;
+};
+
+} // namespace loc_core
+
+#endif //__SYSTEM_STATUS__
+
diff --git a/core/gps_extended_c.h b/core/gps_extended_c.h
index 55fd03e..1433768 100644
--- a/core/gps_extended_c.h
+++ b/core/gps_extended_c.h
@@ -87,6 +87,17 @@
 #define LOC_AGPS_CERTIFICATE_MAX_LENGTH 2000
 #define LOC_AGPS_CERTIFICATE_MAX_SLOTS 10
 
+typedef uint32_t LocPosTechMask;
+#define LOC_POS_TECH_MASK_DEFAULT ((LocPosTechMask)0x00000000)
+#define LOC_POS_TECH_MASK_SATELLITE ((LocPosTechMask)0x00000001)
+#define LOC_POS_TECH_MASK_CELLID ((LocPosTechMask)0x00000002)
+#define LOC_POS_TECH_MASK_WIFI ((LocPosTechMask)0x00000004)
+#define LOC_POS_TECH_MASK_SENSORS ((LocPosTechMask)0x00000008)
+#define LOC_POS_TECH_MASK_REFERENCE_LOCATION ((LocPosTechMask)0x00000010)
+#define LOC_POS_TECH_MASK_INJECTED_COARSE_POSITION ((LocPosTechMask)0x00000020)
+#define LOC_POS_TECH_MASK_AFLT ((LocPosTechMask)0x00000040)
+#define LOC_POS_TECH_MASK_HYBRID ((LocPosTechMask)0x00000080)
+
 enum loc_registration_mask_status {
     LOC_REGISTRATION_MASK_ENABLED,
     LOC_REGISTRATION_MASK_DISABLED,
@@ -104,6 +115,7 @@
     LocGpsLocation     gpsLocation;
     /* Provider indicator for HYBRID or GPS */
     uint16_t        position_source;
+    LocPosTechMask  tech_mask;
     /*allows HAL to pass additional information related to the location */
     int             rawDataSize;         /* in # of bytes */
     void            * rawData;
@@ -266,6 +278,18 @@
 #define GPS_LOCATION_EXTENDED_HAS_HOR_ELIP_UNC_AZIMUTH 0x0800
 /** GpsLocationExtended has valid gnss sv used in position data */
 #define GPS_LOCATION_EXTENDED_HAS_GNSS_SV_USED_DATA 0x1000
+/** GpsLocationExtended has valid navSolutionMask */
+#define GPS_LOCATION_EXTENDED_HAS_NAV_SOLUTION_MASK 0x2000
+
+typedef uint32_t LocNavSolutionMask;
+/* Bitmask to specify whether SBAS ionospheric correction is used  */
+#define LOC_NAV_MASK_SBAS_CORRECTION_IONO ((LocNavSolutionMask)0x0001)
+/* Bitmask to specify whether SBAS fast correction is used  */
+#define LOC_NAV_MASK_SBAS_CORRECTION_FAST ((LocNavSolutionMask)0x0002)
+/**<  Bitmask to specify whether SBAS long-tem correction is used  */
+#define LOC_NAV_MASK_SBAS_CORRECTION_LONG ((LocNavSolutionMask)0x0004)
+/**<  Bitmask to specify whether SBAS integrity information is used  */
+#define LOC_NAV_MASK_SBAS_INTEGRITY ((LocNavSolutionMask)0x0008)
 
 /** GPS PRN Range */
 #define GPS_SV_PRN_MIN      1
@@ -277,6 +301,17 @@
 #define GAL_SV_PRN_MIN      301
 #define GAL_SV_PRN_MAX      336
 
+typedef uint32_t LocPosTechMask;
+#define LOC_POS_TECH_MASK_DEFAULT ((LocPosTechMask)0x00000000)
+#define LOC_POS_TECH_MASK_SATELLITE ((LocPosTechMask)0x00000001)
+#define LOC_POS_TECH_MASK_CELLID ((LocPosTechMask)0x00000002)
+#define LOC_POS_TECH_MASK_WIFI ((LocPosTechMask)0x00000004)
+#define LOC_POS_TECH_MASK_SENSORS ((LocPosTechMask)0x00000008)
+#define LOC_POS_TECH_MASK_REFERENCE_LOCATION ((LocPosTechMask)0x00000010)
+#define LOC_POS_TECH_MASK_INJECTED_COARSE_POSITION ((LocPosTechMask)0x00000020)
+#define LOC_POS_TECH_MASK_AFLT ((LocPosTechMask)0x00000040)
+#define LOC_POS_TECH_MASK_HYBRID ((LocPosTechMask)0x00000080)
+
 typedef enum {
     LOC_RELIABILITY_NOT_SET = 0,
     LOC_RELIABILITY_VERY_LOW = 1,
@@ -335,6 +370,10 @@
     Gnss_ApTimeStampStructType               timeStamp;
     /** Gnss sv used in position data */
     GnssSvUsedInPosition gnss_sv_used_ids;
+    /** Nav solution mask to indicate sbas corrections */
+    LocNavSolutionMask  navSolutionMask;
+    /** Position technology used in computing this fix */
+    LocPosTechMask tech_mask;
 } GpsLocationExtended;
 
 enum loc_sess_status {
@@ -343,17 +382,6 @@
     LOC_SESS_FAILURE
 };
 
-typedef uint32_t LocPosTechMask;
-#define LOC_POS_TECH_MASK_DEFAULT ((LocPosTechMask)0x00000000)
-#define LOC_POS_TECH_MASK_SATELLITE ((LocPosTechMask)0x00000001)
-#define LOC_POS_TECH_MASK_CELLID ((LocPosTechMask)0x00000002)
-#define LOC_POS_TECH_MASK_WIFI ((LocPosTechMask)0x00000004)
-#define LOC_POS_TECH_MASK_SENSORS ((LocPosTechMask)0x00000008)
-#define LOC_POS_TECH_MASK_REFERENCE_LOCATION ((LocPosTechMask)0x00000010)
-#define LOC_POS_TECH_MASK_INJECTED_COARSE_POSITION ((LocPosTechMask)0x00000020)
-#define LOC_POS_TECH_MASK_AFLT ((LocPosTechMask)0x00000040)
-#define LOC_POS_TECH_MASK_HYBRID ((LocPosTechMask)0x00000080)
-
 // Nmea sentence types mask
 typedef uint32_t NmeaSentenceTypesMask;
 #define LOC_NMEA_MASK_GGA_V02   ((NmeaSentenceTypesMask)0x00000001) /**<  Enable GGA type  */
@@ -373,14 +401,15 @@
 #define LOC_NMEA_MASK_GAGGA_V02 ((NmeaSentenceTypesMask)0x00004000) /**<  Enable GAGGA type  */
 #define LOC_NMEA_MASK_PQGSA_V02 ((NmeaSentenceTypesMask)0x00008000) /**<  Enable PQGSA type  */
 #define LOC_NMEA_MASK_PQGSV_V02 ((NmeaSentenceTypesMask)0x00010000) /**<  Enable PQGSV type  */
+#define LOC_NMEA_MASK_DEBUG_V02 ((NmeaSentenceTypesMask)0x00020000) /**<  Enable DEBUG type  */
+
 #define LOC_NMEA_ALL_SUPPORTED_MASK  (LOC_NMEA_MASK_GGA_V02 | LOC_NMEA_MASK_RMC_V02 | \
               LOC_NMEA_MASK_GSV_V02 | LOC_NMEA_MASK_GSA_V02 | LOC_NMEA_MASK_VTG_V02 | \
         LOC_NMEA_MASK_PQXFI_V02 | LOC_NMEA_MASK_PSTIS_V02 | LOC_NMEA_MASK_GLGSV_V02 | \
         LOC_NMEA_MASK_GNGSA_V02 | LOC_NMEA_MASK_GNGNS_V02 | LOC_NMEA_MASK_GARMC_V02 | \
         LOC_NMEA_MASK_GAGSV_V02 | LOC_NMEA_MASK_GAGSA_V02 | LOC_NMEA_MASK_GAVTG_V02 | \
-        LOC_NMEA_MASK_GAGGA_V02 | LOC_NMEA_MASK_PQGSA_V02 | LOC_NMEA_MASK_PQGSV_V02 )
-
-
+        LOC_NMEA_MASK_GAGGA_V02 | LOC_NMEA_MASK_PQGSA_V02 | LOC_NMEA_MASK_PQGSV_V02 | \
+        LOC_NMEA_MASK_DEBUG_V02 )
 
 typedef enum {
   LOC_ENG_IF_REQUEST_SENDER_ID_QUIPC = 0,
@@ -876,8 +905,10 @@
     */
     uint64_t                        measurementStatus;
     /**< Bitmask indicating SV measurement status.
-         Valid bitmasks: \n
-         @MASK()
+        Valid bitmasks: \n
+        If any MSB bit in 0xFFC0000000000000 DONT_USE is set, the measurement
+        must not be used by the client.
+        @MASK()
     */
     uint16_t                        CNo;
     /**< Carrier to Noise ratio  \n
diff --git a/core/loc_gps.h b/core/loc_gps.h
index cdb1af6..2e495b8 100644
--- a/core/loc_gps.h
+++ b/core/loc_gps.h
@@ -2187,7 +2187,7 @@
      * Deliver GNSS configuration contents to HAL.
      * Parameters:
      *     config_data - a pointer to a char array which holds what usually is expected from
-                         file(/etc/gps.conf), i.e., a sequence of UTF8 strings separated by '\n'.
+                         file(/vendor/etc/gps.conf), i.e., a sequence of UTF8 strings separated by '\n'.
      *     length - total number of UTF8 characters in configuraiton data.
      *
      * IMPORTANT:
diff --git a/etc/Android.mk b/etc/Android.mk
index 025d3f7..d9eb0e1 100644
--- a/etc/Android.mk
+++ b/etc/Android.mk
@@ -5,7 +5,7 @@
 LOCAL_MODULE := gps.conf
 LOCAL_MODULE_TAGS := optional
 LOCAL_MODULE_CLASS := ETC
-LOCAL_MODULE_PATH  := $(TARGET_OUT_ETC)/
+LOCAL_MODULE_PATH  := $(TARGET_OUT_VENDOR)/etc/
 LOCAL_SRC_FILES := gps.conf
 
 include $(BUILD_PREBUILT)
diff --git a/etc/gps.conf b/etc/gps.conf
index 4b48558..cc66792 100644
--- a/etc/gps.conf
+++ b/etc/gps.conf
@@ -138,43 +138,63 @@
 # 0: disable
 # 1: enable
 AGPS_CONFIG_INJECT = 1
+
+##################################################
+# GNSS settings for automotive use cases
+# Configurations in following section are
+# specific to automotive use cases, others
+# please do not change, keep the default values
+##################################################
+
 # AP Coarse Timestamp Uncertainty
 ##################################################
 # default : 10
-# or as per clock uncertainty of product
+# AP time stamp uncertainty, until GNSS receiver
+# is able to acquire better timing information
 AP_TIMESTAMP_UNCERTAINTY = 10
 
-#####################################
-# GNSS PPS settings
-#####################################
-#AP DR engine availability status
-# 0 : NO AP DR (default)
-# 1 : AP DR enabled
+##################################################
+# QDR engine availability status
+##################################################
+# 0 : NO QDR (default)
+# 1 : QDR enabled
+# This settings enables QDR Configuration for
+# automotive use case, if enabled then
+# DR_AP_Service needs to be enabled in izat.conf
 #EXTERNAL_DR_ENABLED = 0
 
 #####################################
-#DR_SYNC Pulse Availability
+# DR_SYNC Pulse Availability
 #####################################
 # 0 : DR_SYNC pulse not available (default)
 # 1 : DR_SYNC pulse available
+# This configuration enables the driver to make use
+# of PPS events generated by DR_SYNC pulse
+# Standard Linux PPS driver needs to be enabled
 DR_SYNC_ENABLED = 0
 
 #####################################
-#PPS Device name
+# PPS Device name
 #####################################
 PPS_DEVICENAME = /dev/pps0
 
 #####################################
-#AP Clock Accuracy
+# AP Clock Accuracy
 #####################################
+# Quality of APPS processor clock (in PPM).
+# Value specified is used for calculation of
+# APPS time stamp uncertainty
 AP_CLOCK_PPM = 100
 
 #####################################
-#MAX ms difference to detect missing pulse
+# MAX ms difference to detect missing pulse
 #####################################
+# Specifies time threshold in ms to validate any missing PPS pulses
 MISSING_PULSE_TIME_DELTA = 900
 
 #####################################
-#Propagation time uncertainty
+# Propagation time uncertainty
 #####################################
+# This settings enables time uncertainty propagation
+# logic incase of missing PPS pulse
 PROPAGATION_TIME_UNCERTAINTY = 1
diff --git a/gnss/GnssAdapter.cpp b/gnss/GnssAdapter.cpp
index e37a992..6621171 100644
--- a/gnss/GnssAdapter.cpp
+++ b/gnss/GnssAdapter.cpp
@@ -40,6 +40,7 @@
 #include <string>
 #include <loc_log.h>
 #include <Agps.h>
+#include <SystemStatus.h>
 
 using namespace loc_core;
 
@@ -113,6 +114,7 @@
 
 void
 GnssAdapter::convertLocation(Location& out, const LocGpsLocation& locGpsLocation,
+                             const GpsLocationExtended& locationExtended,
                              const LocPosTechMask techMask)
 {
     out.size = sizeof(Location);
@@ -137,6 +139,18 @@
         out.flags |= LOCATION_HAS_ACCURACY_BIT;
         out.accuracy = locGpsLocation.accuracy;
     }
+    if (GPS_LOCATION_EXTENDED_HAS_VERT_UNC & locationExtended.flags) {
+        out.flags |= LOCATION_HAS_VERTICAL_ACCURACY_BIT;
+        out.verticalAccuracy = locationExtended.vert_unc;
+    }
+    if (GPS_LOCATION_EXTENDED_HAS_SPEED_UNC & locationExtended.flags) {
+        out.flags |= LOCATION_HAS_SPEED_ACCURACY_BIT;
+        out.speedAccuracy = locationExtended.speed_unc;
+    }
+    if (GPS_LOCATION_EXTENDED_HAS_BEARING_UNC & locationExtended.flags) {
+        out.flags |= LOCATION_HAS_BEARING_ACCURACY_BIT;
+        out.bearingAccuracy = locationExtended.bearing_unc;
+    }
     out.timestamp = locGpsLocation.timestamp;
     if (LOC_POS_TECH_MASK_SATELLITE & techMask) {
         out.techMask |= LOCATION_TECHNOLOGY_GNSS_BIT;
@@ -171,18 +185,6 @@
         out.flags |= GNSS_LOCATION_INFO_MAGNETIC_DEVIATION_BIT;
         out.magneticDeviation = locationExtended.magneticDeviation;
     }
-    if (GPS_LOCATION_EXTENDED_HAS_VERT_UNC & locationExtended.flags) {
-        out.flags |= GNSS_LOCATION_INFO_VER_ACCURACY_BIT;
-        out.verAccuracy = locationExtended.vert_unc;
-    }
-    if (GPS_LOCATION_EXTENDED_HAS_SPEED_UNC & locationExtended.flags) {
-        out.flags |= GNSS_LOCATION_INFO_SPEED_ACCURACY_BIT;
-        out.speedAccuracy = locationExtended.speed_unc;
-    }
-    if (GPS_LOCATION_EXTENDED_HAS_BEARING_UNC & locationExtended.flags) {
-        out.flags |= GNSS_LOCATION_INFO_BEARING_ACCURACY_BIT;
-        out.bearingAccuracy = locationExtended.bearing_unc;
-    }
     if (GPS_LOCATION_EXTENDED_HAS_HOR_RELIABILITY & locationExtended.flags) {
         out.flags |= GNSS_LOCATION_INFO_HOR_RELIABILITY_BIT;
         switch (locationExtended.horizontal_reliability) {
@@ -509,9 +511,16 @@
                 mAdapter.convertLppeCp(ContextBase::mGps_conf.LPPE_CP_TECHNOLOGY));
             mApi.setLPPeProtocolUp(
                 mAdapter.convertLppeUp(ContextBase::mGps_conf.LPPE_UP_TECHNOLOGY));
+
+            // set nmea mask type
+            uint32_t mask = 0;
             if (NMEA_PROVIDER_MP == ContextBase::mGps_conf.NMEA_PROVIDER) {
-                mApi.setNMEATypes(LOC_NMEA_ALL_SUPPORTED_MASK);
+                mask = LOC_NMEA_ALL_SUPPORTED_MASK;
+            } else {
+                mask = LOC_NMEA_MASK_DEBUG_V02;
             }
+            mApi.setNMEATypes(mask);
+
             mApi.setXtraVersionCheck(ContextBase::mGps_conf.XTRA_VERSION_CHECK);
             if (ContextBase::mSap_conf.GYRO_BIAS_RANDOM_WALK_VALID ||
                 ContextBase::mSap_conf.ACCEL_RANDOM_WALK_SPECTRAL_DENSITY_VALID ||
@@ -999,8 +1008,7 @@
         if (it->second.gnssSvCb != nullptr) {
             mask |= LOC_API_ADAPTER_BIT_SATELLITE_REPORT;
         }
-        if (it->second.gnssNmeaCb != nullptr &&
-            NMEA_PROVIDER_MP == ContextBase::mGps_conf.NMEA_PROVIDER) {
+        if (it->second.gnssNmeaCb != nullptr) {
             mask |= LOC_API_ADAPTER_BIT_NMEA_1HZ_REPORT;
         }
         if (it->second.gnssMeasurementsCb != nullptr) {
@@ -1806,6 +1814,11 @@
             mStatus(status),
             mTechMask(techMask) {}
         inline virtual void proc() const {
+            // extract bug report info - this returns true if consumed by systemstatus
+            SystemStatus* s = LocDualContext::getSystemStatus();
+            if (nullptr != s) {
+                s->eventPosition(mUlpLocation, mLocationExtended);
+            }
             mAdapter.reportPosition(mUlpLocation, mLocationExtended, mStatus, mTechMask);
         }
     };
@@ -1858,7 +1871,7 @@
         for (auto it=mClientData.begin(); it != mClientData.end(); ++it) {
             if (nullptr != it->second.trackingCb) {
                 Location location = {};
-                convertLocation(location, ulpLocation.gpsLocation, techMask);
+                convertLocation(location, ulpLocation.gpsLocation, locationExtended, techMask);
                 it->second.trackingCb(location);
             }
             if (nullptr != it->second.gnssLocationInfoCb) {
@@ -1923,27 +1936,30 @@
     if (mGnssSvIdUsedInPosAvail) {
         int numSv = svNotify.count;
         int16_t gnssSvId = 0;
-        int prnMin = 0;
         uint64_t svUsedIdMask = 0;
         for (int i=0; i < numSv; i++) {
             gnssSvId = svNotify.gnssSvs[i].svId;
-            if (gnssSvId <= GPS_SV_PRN_MAX) {
-                svUsedIdMask = mGnssSvIdUsedInPosition.gps_sv_used_ids_mask;
-                prnMin = GPS_SV_PRN_MIN;
-            } else if ((gnssSvId >= GLO_SV_PRN_MIN) && (gnssSvId <= GLO_SV_PRN_MAX)) {
-                svUsedIdMask = mGnssSvIdUsedInPosition.glo_sv_used_ids_mask;
-                prnMin = GLO_SV_PRN_MIN;
-            } else if ((gnssSvId >= BDS_SV_PRN_MIN) && (gnssSvId <= BDS_SV_PRN_MAX)) {
-                svUsedIdMask = mGnssSvIdUsedInPosition.bds_sv_used_ids_mask;
-                prnMin = BDS_SV_PRN_MIN;
-            } else if ((gnssSvId >= GAL_SV_PRN_MIN) && (gnssSvId <= GAL_SV_PRN_MAX)) {
-                svUsedIdMask = mGnssSvIdUsedInPosition.gal_sv_used_ids_mask;
-                prnMin = GAL_SV_PRN_MIN;
+            switch (svNotify.gnssSvs[i].type) {
+                case GNSS_SV_TYPE_GPS:
+                    svUsedIdMask = mGnssSvIdUsedInPosition.gps_sv_used_ids_mask;
+                    break;
+                case GNSS_SV_TYPE_GLONASS:
+                    svUsedIdMask = mGnssSvIdUsedInPosition.glo_sv_used_ids_mask;
+                    break;
+                case GNSS_SV_TYPE_BEIDOU:
+                    svUsedIdMask = mGnssSvIdUsedInPosition.bds_sv_used_ids_mask;
+                    break;
+                case GNSS_SV_TYPE_GALILEO:
+                    svUsedIdMask = mGnssSvIdUsedInPosition.gal_sv_used_ids_mask;
+                    break;
+                default:
+                    svUsedIdMask = 0;
+                    break;
             }
 
             // If SV ID was used in previous position fix, then set USED_IN_FIX
             // flag, else clear the USED_IN_FIX flag.
-            if (svUsedIdMask & (1 << (gnssSvId - prnMin))) {
+            if (svUsedIdMask & (1 << (gnssSvId - 1))) {
                 svNotify.gnssSvs[i].gnssSvOptionsMask |= GNSS_SV_OPTIONS_USED_IN_FIX_BIT;
             } else {
                 svNotify.gnssSvs[i].gnssSvOptionsMask &= ~GNSS_SV_OPTIONS_USED_IN_FIX_BIT;
@@ -1967,7 +1983,6 @@
 void
 GnssAdapter::reportNmeaEvent(const char* nmea, size_t length, bool fromUlp)
 {
-    //LOC_LOGD("%s]: fromUlp %u", __func__, fromUlp);
 
     // if this event is not called from ULP, then try to call into ULP and return if successfull
     if (!fromUlp) {
@@ -1994,7 +2009,16 @@
             delete[] mNmea;
         }
         inline virtual void proc() const {
-            mAdapter.reportNmea(mNmea, mLength);
+            // extract bug report info - this returns true if consumed by systemstatus
+            bool ret = false;
+            SystemStatus* s = LocDualContext::getSystemStatus();
+            if (nullptr != s) {
+                ret = s->setNmeaString(mNmea, mLength);
+            }
+            if (false == ret) {
+                // forward NMEA message to upper layer
+                mAdapter.reportNmea(mNmea, mLength);
+            }
         }
     };
 
@@ -3223,3 +3247,121 @@
 
     sendMsg( new AgpsMsgAtlOpenFailed(&mAgpsManager, (AGpsExtType)agpsType));
 }
+
+void GnssAdapter::convertSatelliteInfo(std::vector<GnssDebugSatelliteInfo>& out,
+                                  const GnssSvType& in_constellation,
+                                  const SystemStatusReports& in)
+{
+    GnssDebugSatelliteInfo s = {};
+    uint64_t mask = 0ULL;
+    float age = 0.0;
+    uint32_t svid_min = 0;
+    uint32_t mask_size = 0;
+
+    switch (in_constellation) {
+        case GNSS_SV_TYPE_GPS:
+            svid_min = GPS_MIN;
+            mask_size = 32;
+            break;
+        case GNSS_SV_TYPE_GLONASS:
+            svid_min = GLO_MIN;
+            mask_size = 32;
+            break;
+        case GNSS_SV_TYPE_BEIDOU:
+            svid_min = BDS_MIN;
+            mask_size = 64;
+            break;
+        case GNSS_SV_TYPE_QZSS:
+            svid_min = QZSS_MIN;
+            mask_size = 32;
+            break;
+        case GNSS_SV_TYPE_GALILEO:
+            svid_min = GAL_MIN;
+            mask_size = 64;
+            break;
+        default:
+            return;
+    }
+
+    if(!in.mEphemeris.empty()) {
+        mask = in.mEphemeris.back().mGpsEpheValid;
+        if(!in.mXtra.empty()) {
+            age = (float)(in.mXtra.back().mGpsXtraAge);
+        }
+        else {
+            age = 0.0;
+        }
+
+        for(uint32_t i=0; i<mask_size; i++) {
+            if (0 != (mask & (1<<i))) {
+                s.size = sizeof(s);
+                s.svid = i + svid_min;
+                s.constellation = in_constellation;
+                s.ephemerisType = 0;
+                s.ephemerisAgeSeconds = age;
+                out.push_back(s);
+            }
+        }
+    }
+
+    return;
+}
+
+bool GnssAdapter::getDebugReport(GnssDebugReport& r)
+{
+    LOC_LOGD("%s]: ", __func__);
+
+    SystemStatus* systemstatus = LocDualContext::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()) {
+        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;
+    }
+    else if(!reports.mBestPosition.empty()) {
+        r.mLocation.mLocation.latitude  = (double)(reports.mBestPosition.back().mBestLat);
+        r.mLocation.mLocation.longitude = (double)(reports.mBestPosition.back().mBestLon);
+        r.mLocation.mLocation.altitude  = reports.mBestPosition.back().mBestAlt;
+    }
+    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
+    if(!reports.mBestPosition.empty()) {
+        r.mTime.size                    = sizeof(r.mTime);
+        r.mTime.timeEstimate            = reports.mBestPosition.back().mUtcTime.tv_sec;
+        r.mTime.timeUncertaintyNs       = (float)(reports.mTimeAndClock.back().mTimeUnc);
+    }
+    LOC_LOGV("getDebugReport - timeestimate=%lld", r.mTime.timeEstimate);
+
+    // 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_BEIDOU, reports);
+    convertSatelliteInfo(r.mSatelliteInfo, GNSS_SV_TYPE_QZSS, reports);
+    convertSatelliteInfo(r.mSatelliteInfo, GNSS_SV_TYPE_GALILEO, reports);
+    LOC_LOGV("getDebugReport - satellite=%d", r.mSatelliteInfo.size());
+
+    return true;
+}
+
diff --git a/gnss/GnssAdapter.h b/gnss/GnssAdapter.h
index f5a5300..46afc06 100644
--- a/gnss/GnssAdapter.h
+++ b/gnss/GnssAdapter.h
@@ -34,6 +34,7 @@
 #include <UlpProxyBase.h>
 #include <LocationAPI.h>
 #include <Agps.h>
+#include <SystemStatus.h>
 
 #define MAX_URL_LEN 256
 #define NMEA_SENTENCE_MAX_LENGTH 200
@@ -103,6 +104,7 @@
     /*==== CONVERSION ===================================================================*/
     static void convertOptions(LocPosMode& out, const LocationOptions& options);
     static void convertLocation(Location& out, const LocGpsLocation& locGpsLocation,
+                                const GpsLocationExtended& locationExtended,
                                 const LocPosTechMask techMask);
     static void convertLocationInfo(GnssLocationInfoNotification& out,
                                     const GpsLocationExtended& locationExtended);
@@ -255,6 +257,9 @@
     /*======== UTILITIES ================================================================*/
     int nmeaPutChecksum(char *nmea, size_t maxSize);
 
+    /*======== GNSSDEBUG ================================================================*/
+    bool getDebugReport(GnssDebugReport& report);
+
     /*==== CONVERSION ===================================================================*/
     static uint32_t convertGpsLock(const GnssConfigGpsLock gpsLock);
     static GnssConfigGpsLock convertGpsLock(const uint32_t gpsLock);
@@ -270,6 +275,9 @@
     static GnssConfigLppeUserPlaneMask convertLppeUp(const uint32_t 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);
 
     void injectLocationCommand(double latitude, double longitude, float accuracy);
     void injectTimeCommand(int64_t time, int64_t timeReference, int32_t uncertainty);
diff --git a/gnss/location_gnss.cpp b/gnss/location_gnss.cpp
index 0995f4b..018b7f7 100644
--- a/gnss/location_gnss.cpp
+++ b/gnss/location_gnss.cpp
@@ -58,6 +58,7 @@
 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 const GnssInterface gGnssInterface = {
     sizeof(GnssInterface),
@@ -80,7 +81,8 @@
     agpsInit,
     agpsDataConnOpen,
     agpsDataConnClosed,
-    agpsDataConnFailed
+    agpsDataConnFailed,
+    getDebugReport,
 };
 
 #ifndef DEBUG_X86
@@ -239,3 +241,10 @@
         gGnssAdapter->dataConnFailedCommand(agpsType);
     }
 }
+
+static void getDebugReport(GnssDebugReport& report) {
+
+    if (NULL != gGnssAdapter) {
+        gGnssAdapter->getDebugReport(report);
+    }
+}
diff --git a/location/LocationAPI.h b/location/LocationAPI.h
index cc15ddd..a41d772 100644
--- a/location/LocationAPI.h
+++ b/location/LocationAPI.h
@@ -29,6 +29,7 @@
 #ifndef LOCATION_H
 #define LOCATION_H
 
+#include <vector>
 #include <stdint.h>
 #include <functional>
 
@@ -52,11 +53,14 @@
 // Flags to indicate which values are valid in a Location
 typedef uint16_t LocationFlagsMask;
 typedef enum {
-    LOCATION_HAS_LAT_LONG_BIT = (1<<0), // location has valid latitude and longitude
-    LOCATION_HAS_ALTITUDE_BIT = (1<<1), // location has valid altitude
-    LOCATION_HAS_SPEED_BIT    = (1<<2), // location has valid speed
-    LOCATION_HAS_BEARING_BIT  = (1<<3), // location has valid bearing
-    LOCATION_HAS_ACCURACY_BIT = (1<<4), // location has valid accuracy
+    LOCATION_HAS_LAT_LONG_BIT          = (1<<0), // location has valid latitude and longitude
+    LOCATION_HAS_ALTITUDE_BIT          = (1<<1), // location has valid altitude
+    LOCATION_HAS_SPEED_BIT             = (1<<2), // location has valid speed
+    LOCATION_HAS_BEARING_BIT           = (1<<3), // location has valid bearing
+    LOCATION_HAS_ACCURACY_BIT          = (1<<4), // location has valid accuracy
+    LOCATION_HAS_VERTICAL_ACCURACY_BIT = (1<<5), // location has valid vertical accuracy
+    LOCATION_HAS_SPEED_ACCURACY_BIT    = (1<<6), // location has valid speed accuracy
+    LOCATION_HAS_BEARING_ACCURACY_BIT  = (1<<7), // location has valid bearing accuracy
 } LocationFlagsBits;
 
 typedef uint16_t LocationTechnologyMask;
@@ -80,14 +84,11 @@
     GNSS_LOCATION_INFO_ALTITUDE_MEAN_SEA_LEVEL_BIT      = (1<<0), // valid altitude mean sea level
     GNSS_LOCATION_INFO_DOP_BIT                          = (1<<1), // valid pdop, hdop, and vdop
     GNSS_LOCATION_INFO_MAGNETIC_DEVIATION_BIT           = (1<<2), // valid magnetic deviation
-    GNSS_LOCATION_INFO_VER_ACCURACY_BIT                 = (1<<3), // valid vertical accuracy
-    GNSS_LOCATION_INFO_SPEED_ACCURACY_BIT               = (1<<4), // valid speed accuracy
-    GNSS_LOCATION_INFO_BEARING_ACCURACY_BIT             = (1<<5), // valid bearing accuracy
-    GNSS_LOCATION_INFO_HOR_RELIABILITY_BIT              = (1<<6), // valid horizontal reliability
-    GNSS_LOCATION_INFO_VER_RELIABILITY_BIT              = (1<<7), // valid vertical reliability
-    GNSS_LOCATION_INFO_HOR_ACCURACY_ELIP_SEMI_MAJOR_BIT = (1<<8), // valid elipsode semi major
-    GNSS_LOCATION_INFO_HOR_ACCURACY_ELIP_SEMI_MINOR_BIT = (1<<9), // valid elipsode semi minor
-    GNSS_LOCATION_INFO_HOR_ACCURACY_ELIP_AZIMUTH_BIT    = (1<<10),// valid accuracy elipsode azimuth
+    GNSS_LOCATION_INFO_HOR_RELIABILITY_BIT              = (1<<3), // valid horizontal reliability
+    GNSS_LOCATION_INFO_VER_RELIABILITY_BIT              = (1<<4), // valid vertical reliability
+    GNSS_LOCATION_INFO_HOR_ACCURACY_ELIP_SEMI_MAJOR_BIT = (1<<5), // valid elipsode semi major
+    GNSS_LOCATION_INFO_HOR_ACCURACY_ELIP_SEMI_MINOR_BIT = (1<<6), // valid elipsode semi minor
+    GNSS_LOCATION_INFO_HOR_ACCURACY_ELIP_AZIMUTH_BIT    = (1<<7),// valid accuracy elipsode azimuth
 } GnssLocationInfoFlagBits;
 
 typedef enum {
@@ -393,6 +394,9 @@
     float speed;             // in meters per second
     float bearing;           // in degrees; range [0, 360)
     float accuracy;          // in meters
+    float verticalAccuracy;  // in meters
+    float speedAccuracy;     // in meters/second
+    float bearingAccuracy;   // in degrees (0 to 359.999)
     LocationTechnologyMask techMask;
 } Location;
 
@@ -441,9 +445,6 @@
     float hdop;                         // horizontal dilusion of precision
     float vdop;                         // vertical dilusion of precision
     float magneticDeviation;            // magnetic deviation
-    float verAccuracy;                  // vertical accuracy in meters
-    float speedAccuracy;                // speed accuracy in meters/second
-    float bearingAccuracy;              // bearing accuracy in degrees (0 to 359.999)
     LocationReliability horReliability; // horizontal reliability
     LocationReliability verReliability; // vertical reliability
     float horUncEllipseSemiMajor;       // horizontal elliptical accuracy semi-major axis
@@ -553,6 +554,35 @@
     GnssConfigSuplModeMask suplModeMask; //bitwise OR of GnssConfigSuplModeBits
 } GnssConfig;
 
+typedef struct {
+    size_t size;                        // set to sizeof
+    Location                            mLocation;
+    double                              verticalAccuracyMeters;
+    double                              speedAccuracyMetersPerSecond;
+    double                              bearingAccuracyDegrees;
+} GnssDebugLocation;
+
+typedef struct {
+    size_t size;                        // set to sizeof
+    int64_t                             timeEstimate;
+    float                               timeUncertaintyNs;
+} GnssDebugTime;
+
+typedef struct {
+    size_t size;                        // set to sizeof
+    uint32_t                            svid;
+    GnssSvType                          constellation;
+    uint32_t                            ephemerisType;
+    float                               ephemerisAgeSeconds;
+} GnssDebugSatelliteInfo;
+
+typedef struct {
+    size_t size;                        // set to sizeof
+    GnssDebugLocation                   mLocation;
+    GnssDebugTime                       mTime;
+    std::vector<GnssDebugSatelliteInfo> mSatelliteInfo;
+} GnssDebugReport;
+
 /* Provides the capabilities of the system
    capabilities callback is called once soon after createInstance is called */
 typedef std::function<void(
diff --git a/location/LocationAPIClientBase.cpp b/location/LocationAPIClientBase.cpp
index da56440..6ced55a 100644
--- a/location/LocationAPIClientBase.cpp
+++ b/location/LocationAPIClientBase.cpp
@@ -409,17 +409,18 @@
             delete requests;
         }
         uint32_t* sessions = mLocationAPI->addGeofences(count, options, data);
-        LOC_LOGI("%s:%d] start new sessions: %p", __FUNCTION__, __LINE__, sessions);
-        requests = new RequestQueue(-1);
-        requests->push(new AddGeofencesRequest(*this));
-        mRequestQueues[REQUEST_GEOFENCE] = requests;
+        if (sessions) {
+            LOC_LOGI("%s:%d] start new sessions: %p", __FUNCTION__, __LINE__, sessions);
+            requests = new RequestQueue(-1);
+            requests->push(new AddGeofencesRequest(*this));
+            mRequestQueues[REQUEST_GEOFENCE] = requests;
 
-        for (size_t i = 0; i < count; i++) {
-            mGeofenceBiDict.set(ids[i], sessions[i], options[i].breachTypeMask);
+            for (size_t i = 0; i < count; i++) {
+                mGeofenceBiDict.set(ids[i], sessions[i], options[i].breachTypeMask);
+            }
+            retVal = LOCATION_ERROR_SUCCESS;
         }
         pthread_mutex_unlock(&mMutex);
-
-        retVal = LOCATION_ERROR_SUCCESS;
     }
 
     return retVal;
diff --git a/location/location_interface.h b/location/location_interface.h
index b084b65..86febd3 100644
--- a/location/location_interface.h
+++ b/location/location_interface.h
@@ -53,6 +53,7 @@
     void (*agpsDataConnOpen)(short agpsType, const char* apnName, int apnLen, int ipType);
     void (*agpsDataConnClosed)(short agpsType);
     void (*agpsDataConnFailed)(short agpsType);
+    void (*getDebugReport)(GnssDebugReport& report);
 };
 
 struct FlpInterface {
diff --git a/utils/MsgTask.cpp b/utils/MsgTask.cpp
index 2163511..636dd4c 100644
--- a/utils/MsgTask.cpp
+++ b/utils/MsgTask.cpp
@@ -62,9 +62,9 @@
 }
 
 void MsgTask::destroy() {
+    LocThread* thread = mThread;
     msg_q_unblock((void*)mQ);
-    if (mThread) {
-        LocThread* thread = mThread;
+    if (thread) {
         mThread = NULL;
         delete thread;
     } else {
@@ -73,7 +73,11 @@
 }
 
 void MsgTask::sendMsg(const LocMsg* msg) const {
-    msg_q_snd((void*)mQ, (void*)msg, LocMsgDestroy);
+    if (msg) {
+        msg_q_snd((void*)mQ, (void*)msg, LocMsgDestroy);
+    } else {
+        LOC_LOGE("%s: msg is NULL", __func__);
+    }
 }
 
 void MsgTask::prerun() {
diff --git a/utils/loc_target.cpp b/utils/loc_target.cpp
index 1016861..7e475eb 100644
--- a/utils/loc_target.cpp
+++ b/utils/loc_target.cpp
@@ -52,6 +52,9 @@
 #define STR_SURF        "Surf"
 #define STR_MTP         "MTP"
 #define STR_APQ         "apq"
+#define STR_SDC         "sdc"  // alternative string for APQ targets
+#define STR_MSM         "msm"
+#define STR_SDM         "sdm"  // alternative string for MSM targets
 #define STR_APQ_NO_WGR  "baseband_apq_nowgr"
 #define STR_AUTO        "auto"
 #define IS_STR_END(c) ((c) == '\0' || (c) == '\n' || (c) == '\r')
@@ -198,7 +201,7 @@
     static const char hw_platform_dep[]  =
         "/sys/devices/system/soc/soc0/hw_platform";
     static const char id_dep[]           = "/sys/devices/system/soc/soc0/id";
-    static const char mdm[]              = "/dev/mdm"; // No such file or directory
+    static const char mdm[]              = "/target"; // mdm target we are using
 
     char rd_hw_platform[LINE_LEN];
     char rd_id[LINE_LEN];
@@ -238,7 +241,8 @@
         goto detected;
     }
 
-    if( !memcmp(baseband, STR_APQ, LENGTH(STR_APQ)) ){
+    if( !memcmp(baseband, STR_APQ, LENGTH(STR_APQ)) ||
+            !memcmp(baseband, STR_SDC, LENGTH(STR_SDC)) ){
 
         if( !memcmp(rd_id, MPQ8064_ID_1, LENGTH(MPQ8064_ID_1))
             && IS_STR_END(rd_id[LENGTH(MPQ8064_ID_1)]) )
@@ -257,11 +261,17 @@
             if (!read_a_line( mdm, rd_mdm, LINE_LEN))
                 gTarget = TARGET_MDM;
         }
+
         else if( (!memcmp(rd_id, MSM8930_ID_1, LENGTH(MSM8930_ID_1))
                    && IS_STR_END(rd_id[LENGTH(MSM8930_ID_1)])) ||
                   (!memcmp(rd_id, MSM8930_ID_2, LENGTH(MSM8930_ID_2))
                    && IS_STR_END(rd_id[LENGTH(MSM8930_ID_2)])) )
              gTarget = TARGET_MSM_NO_SSC;
+
+        else if ( !memcmp(baseband, STR_MSM, LENGTH(STR_MSM)) ||
+                    !memcmp(baseband, STR_SDM, LENGTH(STR_SDM)) )
+             gTarget = TARGET_DEFAULT;
+
         else
              gTarget = TARGET_UNKNOWN;
     }
diff --git a/utils/platform_lib_abstractions/loc_pla/include/platform_lib_gettid.h b/utils/platform_lib_abstractions/loc_pla/include/platform_lib_gettid.h
index 9956937..340c3c5 100644
--- a/utils/platform_lib_abstractions/loc_pla/include/platform_lib_gettid.h
+++ b/utils/platform_lib_abstractions/loc_pla/include/platform_lib_gettid.h
@@ -34,6 +34,10 @@
 #ifdef __cplusplus
 extern "C" {
 #endif
+#ifdef USE_GLIB
+const char* getprogname();
+#endif /* USE_GLIB */
+
 pid_t platform_lib_abstraction_gettid();
 #ifdef __cplusplus
 }
diff --git a/utils/platform_lib_abstractions/loc_pla/include/platform_lib_macros.h b/utils/platform_lib_abstractions/loc_pla/include/platform_lib_macros.h
index c712122..d0795eb 100644
--- a/utils/platform_lib_abstractions/loc_pla/include/platform_lib_macros.h
+++ b/utils/platform_lib_abstractions/loc_pla/include/platform_lib_macros.h
@@ -66,6 +66,18 @@
 
 #endif /* USE_GLIB */
 
+
+// Below are the location conf file paths
+extern const char LOC_PATH_GPS_CONF[];
+extern const char LOC_PATH_IZAT_CONF[];
+extern const char LOC_PATH_FLP_CONF[];
+extern const char LOC_PATH_LOWI_CONF[];
+extern const char LOC_PATH_SAP_CONF[];
+extern const char LOC_PATH_APDR_CONF[];
+extern const char LOC_PATH_XTWIFI_CONF[];
+extern const char LOC_PATH_QUIPC_CONF[];
+
+
 #ifdef __cplusplus
 }
 #endif /*__cplusplus */
diff --git a/utils/platform_lib_abstractions/loc_pla/src/platform_lib_gettid.cpp b/utils/platform_lib_abstractions/loc_pla/src/platform_lib_gettid.cpp
index 8686327..1b7aa32 100644
--- a/utils/platform_lib_abstractions/loc_pla/src/platform_lib_gettid.cpp
+++ b/utils/platform_lib_abstractions/loc_pla/src/platform_lib_gettid.cpp
@@ -30,6 +30,12 @@
 
 #ifdef USE_GLIB
 #include <loc_stub_gettid.h>
+
+#include <errno.h>
+const char* getprogname() {
+    return program_invocation_short_name;
+}
+
 #else
 #include <unistd.h>
 #endif /* USE_GLIB */
diff --git a/utils/platform_lib_abstractions/loc_pla/src/platform_lib_log_util.cpp b/utils/platform_lib_abstractions/loc_pla/src/platform_lib_log_util.cpp
index ef23201..3cb51a3 100644
--- a/utils/platform_lib_abstractions/loc_pla/src/platform_lib_log_util.cpp
+++ b/utils/platform_lib_abstractions/loc_pla/src/platform_lib_log_util.cpp
@@ -26,6 +26,7 @@
  * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 #include "platform_lib_log_util.h"
+#include "platform_lib_macros.h"
 
 char * get_timestamp(char *str, unsigned long buf_size)
 {
@@ -40,3 +41,38 @@
   return str;
 }
 
+// Below are the location conf file paths
+#ifdef __ANDROID__
+
+#define LOC_PATH_GPS_CONF_STR      "/vendor/etc/gps.conf"
+#define LOC_PATH_IZAT_CONF_STR     "/vendor/etc/izat.conf"
+#define LOC_PATH_FLP_CONF_STR      "/vendor/etc/flp.conf"
+#define LOC_PATH_LOWI_CONF_STR     "/vendor/etc/lowi.conf"
+#define LOC_PATH_SAP_CONF_STR      "/vendor/etc/sap.conf"
+#define LOC_PATH_APDR_CONF_STR     "/vendor/etc/apdr.conf"
+#define LOC_PATH_XTWIFI_CONF_STR   "/vendor/etc/xtwifi.conf"
+#define LOC_PATH_QUIPC_CONF_STR    "/vendor/etc/quipc.conf"
+
+#else
+
+#define LOC_PATH_GPS_CONF_STR      "/etc/gps.conf"
+#define LOC_PATH_IZAT_CONF_STR     "/etc/izat.conf"
+#define LOC_PATH_FLP_CONF_STR      "/etc/flp.conf"
+#define LOC_PATH_LOWI_CONF_STR     "/etc/lowi.conf"
+#define LOC_PATH_SAP_CONF_STR      "/etc/sap.conf"
+#define LOC_PATH_APDR_CONF_STR     "/etc/apdr.conf"
+#define LOC_PATH_XTWIFI_CONF_STR   "/etc/xtwifi.conf"
+#define LOC_PATH_QUIPC_CONF_STR    "/etc/quipc.conf"
+
+#endif // __ANDROID__
+
+// Reference below arrays wherever needed to avoid duplicating
+// same conf path string over and again in location code.
+const char LOC_PATH_GPS_CONF[]    = LOC_PATH_GPS_CONF_STR;
+const char LOC_PATH_IZAT_CONF[]   = LOC_PATH_IZAT_CONF_STR;
+const char LOC_PATH_FLP_CONF[]    = LOC_PATH_FLP_CONF_STR;
+const char LOC_PATH_LOWI_CONF[]   = LOC_PATH_LOWI_CONF_STR;
+const char LOC_PATH_SAP_CONF[]    = LOC_PATH_SAP_CONF_STR;
+const char LOC_PATH_APDR_CONF[]   = LOC_PATH_APDR_CONF_STR;
+const char LOC_PATH_XTWIFI_CONF[] = LOC_PATH_XTWIFI_CONF_STR;
+const char LOC_PATH_QUIPC_CONF[]  = LOC_PATH_QUIPC_CONF_STR;