Add VTS tests for measurementInterval, stopSvStatus, and stopNmea

Bug: 206670536
Test: atest VtsHalGnssTargetTest

Change-Id: Id597c772fbe63789cb394b2aa14faeb755196f64
This commit is contained in:
Yu-Han Yang
2022-04-27 09:57:01 -07:00
parent dd890b5845
commit 19a32b6270
13 changed files with 527 additions and 158 deletions

View File

@@ -19,6 +19,7 @@
#include "Gnss.h"
#include <inttypes.h>
#include <log/log.h>
#include <utils/Timers.h>
#include "AGnss.h"
#include "AGnssRil.h"
#include "DeviceFileReader.h"
@@ -28,7 +29,6 @@
#include "GnssConfiguration.h"
#include "GnssDebug.h"
#include "GnssGeofence.h"
#include "GnssMeasurementInterface.h"
#include "GnssNavigationMessageInterface.h"
#include "GnssPsds.h"
#include "GnssVisibilityControl.h"
@@ -95,6 +95,9 @@ ScopedAStatus Gnss::start() {
}
mIsActive = true;
mThreadBlocker.reset();
// notify measurement engine to update measurement interval
mGnssMeasurementInterface->setLocationEnabled(true);
this->reportGnssStatusValue(IGnssCallback::GnssStatusValue::SESSION_BEGIN);
mThread = std::thread([this]() {
this->reportSvStatus();
@@ -102,8 +105,12 @@ ScopedAStatus Gnss::start() {
std::this_thread::sleep_for(std::chrono::milliseconds(TTFF_MILLIS));
mFirstFixReceived = true;
}
while (mIsActive == true) {
do {
if (!mIsActive) {
break;
}
this->reportSvStatus();
this->reportNmea();
auto currentLocation = getLocationFromHW();
mGnssPowerIndication->notePowerConsumption();
@@ -113,12 +120,29 @@ ScopedAStatus Gnss::start() {
const auto location = Utils::getMockLocation();
this->reportLocation(location);
}
std::this_thread::sleep_for(std::chrono::milliseconds(mMinIntervalMs));
}
} while (mIsActive && mThreadBlocker.wait_for(std::chrono::milliseconds(mMinIntervalMs)));
});
return ScopedAStatus::ok();
}
ScopedAStatus Gnss::stop() {
ALOGD("stop");
mIsActive = false;
mGnssMeasurementInterface->setLocationEnabled(false);
this->reportGnssStatusValue(IGnssCallback::GnssStatusValue::SESSION_END);
mThreadBlocker.notify();
if (mThread.joinable()) {
mThread.join();
}
return ScopedAStatus::ok();
}
ScopedAStatus Gnss::close() {
ALOGD("close");
sGnssCallback = nullptr;
return ScopedAStatus::ok();
}
void Gnss::reportLocation(const GnssLocation& location) const {
std::unique_lock<std::mutex> lock(mMutex);
if (sGnssCallback == nullptr) {
@@ -153,7 +177,6 @@ void Gnss::reportSvStatus(const std::vector<GnssSvInfo>& svInfoList) const {
std::vector<GnssSvInfo> Gnss::filterBlocklistedSatellites(
std::vector<GnssSvInfo> gnssSvInfoList) const {
ALOGD("filterBlocklistedSatellites");
for (uint32_t i = 0; i < gnssSvInfoList.size(); i++) {
if (mGnssConfiguration->isBlocklisted(gnssSvInfoList[i])) {
gnssSvInfoList[i].svFlag &= ~(uint32_t)IGnssCallback::GnssSvFlags::USED_IN_FIX;
@@ -174,14 +197,19 @@ void Gnss::reportGnssStatusValue(const IGnssCallback::GnssStatusValue gnssStatus
}
}
ScopedAStatus Gnss::stop() {
ALOGD("stop");
mIsActive = false;
this->reportGnssStatusValue(IGnssCallback::GnssStatusValue::SESSION_END);
if (mThread.joinable()) {
mThread.join();
void Gnss::reportNmea() const {
if (mIsNmeaActive) {
std::unique_lock<std::mutex> lock(mMutex);
if (sGnssCallback == nullptr) {
ALOGE("%s: sGnssCallback is null.", __func__);
return;
}
nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
auto status = sGnssCallback->gnssNmeaCb(now, "$TEST,0,1,2,3,4,5");
if (!status.isOk()) {
ALOGE("%s: Unable to invoke callback", __func__);
}
}
return ScopedAStatus::ok();
}
ScopedAStatus Gnss::startSvStatus() {
@@ -197,16 +225,12 @@ ScopedAStatus Gnss::stopSvStatus() {
}
ScopedAStatus Gnss::startNmea() {
ALOGD("startNmea");
mIsNmeaActive = true;
return ScopedAStatus::ok();
}
ScopedAStatus Gnss::stopNmea() {
ALOGD("stopNmea");
return ScopedAStatus::ok();
}
ScopedAStatus Gnss::close() {
ALOGD("close");
sGnssCallback = nullptr;
mIsNmeaActive = false;
return ScopedAStatus::ok();
}
@@ -249,7 +273,8 @@ ScopedAStatus Gnss::deleteAidingData(GnssAidingData aidingDataFlags) {
ScopedAStatus Gnss::setPositionMode(const PositionModeOptions& options) {
ALOGD("setPositionMode. minIntervalMs:%d, lowPowerMode:%d", options.minIntervalMs,
(int)options.lowPowerMode);
mMinIntervalMs = options.minIntervalMs;
mMinIntervalMs = std::max(1000, options.minIntervalMs);
mGnssMeasurementInterface->setLocationInterval(mMinIntervalMs);
return ScopedAStatus::ok();
}
@@ -283,8 +308,10 @@ ScopedAStatus Gnss::getExtensionGnssPowerIndication(
ScopedAStatus Gnss::getExtensionGnssMeasurement(
std::shared_ptr<IGnssMeasurementInterface>* iGnssMeasurement) {
ALOGD("getExtensionGnssMeasurement");
*iGnssMeasurement = SharedRefBase::make<GnssMeasurementInterface>();
if (mGnssMeasurementInterface == nullptr) {
mGnssMeasurementInterface = SharedRefBase::make<GnssMeasurementInterface>();
}
*iGnssMeasurement = mGnssMeasurementInterface;
return ScopedAStatus::ok();
}

View File

@@ -32,7 +32,9 @@
#include <mutex>
#include <thread>
#include "GnssConfiguration.h"
#include "GnssMeasurementInterface.h"
#include "GnssPowerIndication.h"
#include "Utils.h"
namespace aidl::android::hardware::gnss {
@@ -84,6 +86,7 @@ class Gnss : public BnGnss {
std::shared_ptr<GnssConfiguration> mGnssConfiguration;
std::shared_ptr<GnssPowerIndication> mGnssPowerIndication;
std::shared_ptr<GnssMeasurementInterface> mGnssMeasurementInterface;
private:
void reportLocation(const GnssLocation&) const;
@@ -93,14 +96,17 @@ class Gnss : public BnGnss {
std::vector<IGnssCallback::GnssSvInfo> gnssSvInfoList) const;
void reportGnssStatusValue(const IGnssCallback::GnssStatusValue gnssStatusValue) const;
std::unique_ptr<GnssLocation> getLocationFromHW();
void reportNmea() const;
static std::shared_ptr<IGnssCallback> sGnssCallback;
std::atomic<long> mMinIntervalMs;
std::atomic<bool> mIsActive;
std::atomic<bool> mIsSvStatusActive;
std::atomic<bool> mIsNmeaActive;
std::atomic<bool> mFirstFixReceived;
std::thread mThread;
::android::hardware::gnss::common::ThreadBlocker mThreadBlocker;
mutable std::mutex mMutex;
};

View File

@@ -33,10 +33,11 @@ using DeviceFileReader = ::android::hardware::gnss::common::DeviceFileReader;
std::shared_ptr<IGnssMeasurementCallback> GnssMeasurementInterface::sCallback = nullptr;
GnssMeasurementInterface::GnssMeasurementInterface() : mMinIntervalMillis(1000) {}
GnssMeasurementInterface::GnssMeasurementInterface()
: mIntervalMs(1000), mLocationIntervalMs(1000), mFutures(std::vector<std::future<void>>()) {}
GnssMeasurementInterface::~GnssMeasurementInterface() {
stop();
waitForStoppingThreads();
}
ndk::ScopedAStatus GnssMeasurementInterface::setCallback(
@@ -44,8 +45,10 @@ ndk::ScopedAStatus GnssMeasurementInterface::setCallback(
const bool enableCorrVecOutputs) {
ALOGD("setCallback: enableFullTracking: %d enableCorrVecOutputs: %d", (int)enableFullTracking,
(int)enableCorrVecOutputs);
std::unique_lock<std::mutex> lock(mMutex);
sCallback = callback;
{
std::unique_lock<std::mutex> lock(mMutex);
sCallback = callback;
}
if (mIsActive) {
ALOGW("GnssMeasurement callback already set. Resetting the callback...");
@@ -60,14 +63,16 @@ ndk::ScopedAStatus GnssMeasurementInterface::setCallbackWithOptions(
const std::shared_ptr<IGnssMeasurementCallback>& callback, const Options& options) {
ALOGD("setCallbackWithOptions: fullTracking:%d, corrVec:%d, intervalMs:%d",
(int)options.enableFullTracking, (int)options.enableCorrVecOutputs, options.intervalMs);
std::unique_lock<std::mutex> lock(mMutex);
sCallback = callback;
{
std::unique_lock<std::mutex> lock(mMutex);
sCallback = callback;
}
if (mIsActive) {
ALOGW("GnssMeasurement callback already set. Resetting the callback...");
stop();
}
mMinIntervalMillis = options.intervalMs;
mIntervalMs = std::max(options.intervalMs, 1000);
start(options.enableCorrVecOutputs);
return ndk::ScopedAStatus::ok();
@@ -75,18 +80,35 @@ ndk::ScopedAStatus GnssMeasurementInterface::setCallbackWithOptions(
ndk::ScopedAStatus GnssMeasurementInterface::close() {
ALOGD("close");
stop();
std::unique_lock<std::mutex> lock(mMutex);
sCallback = nullptr;
mMinIntervalMillis = 1000;
if (mIsActive) {
stop();
}
{
std::unique_lock<std::mutex> lock(mMutex);
sCallback = nullptr;
}
mIntervalMs = 1000;
return ndk::ScopedAStatus::ok();
}
void GnssMeasurementInterface::start(const bool enableCorrVecOutputs) {
ALOGD("start");
if (mIsActive) {
ALOGD("restarting since measurement has started");
stop();
}
// Wait for stopping previous thread.
waitForStoppingThreads();
mIsActive = true;
mThreadBlocker.reset();
mThread = std::thread([this, enableCorrVecOutputs]() {
while (mIsActive == true) {
int intervalMs;
do {
if (!mIsActive) {
break;
}
std::string rawMeasurementStr = "";
if (ReplayUtils::hasGnssDeviceFile() &&
ReplayUtils::isGnssRawMeasurement(
@@ -103,15 +125,19 @@ void GnssMeasurementInterface::start(const bool enableCorrVecOutputs) {
auto measurement = Utils::getMockMeasurement(enableCorrVecOutputs);
this->reportMeasurement(measurement);
}
std::this_thread::sleep_for(std::chrono::milliseconds(mMinIntervalMillis));
}
intervalMs =
(mLocationEnabled) ? std::min(mLocationIntervalMs, mIntervalMs) : mIntervalMs;
} while (mIsActive && mThreadBlocker.wait_for(std::chrono::milliseconds(intervalMs)));
});
mThread.detach();
}
void GnssMeasurementInterface::stop() {
ALOGD("stop");
mIsActive = false;
mThreadBlocker.notify();
if (mThread.joinable()) {
mFutures.push_back(std::async(std::launch::async, [this] { mThread.join(); }));
}
}
void GnssMeasurementInterface::reportMeasurement(const GnssData& data) {
@@ -128,4 +154,21 @@ void GnssMeasurementInterface::reportMeasurement(const GnssData& data) {
callbackCopy->gnssMeasurementCb(data);
}
void GnssMeasurementInterface::setLocationInterval(const int intervalMs) {
mLocationIntervalMs = intervalMs;
}
void GnssMeasurementInterface::setLocationEnabled(const bool enabled) {
mLocationEnabled = enabled;
}
void GnssMeasurementInterface::waitForStoppingThreads() {
for (auto& future : mFutures) {
ALOGD("Stopping previous thread.");
future.wait();
ALOGD("Done stopping thread.");
}
mFutures.clear();
}
} // namespace aidl::android::hardware::gnss

View File

@@ -19,8 +19,10 @@
#include <aidl/android/hardware/gnss/BnGnssMeasurementCallback.h>
#include <aidl/android/hardware/gnss/BnGnssMeasurementInterface.h>
#include <atomic>
#include <future>
#include <mutex>
#include <thread>
#include "Utils.h"
namespace aidl::android::hardware::gnss {
@@ -35,15 +37,22 @@ struct GnssMeasurementInterface : public BnGnssMeasurementInterface {
ndk::ScopedAStatus setCallbackWithOptions(
const std::shared_ptr<IGnssMeasurementCallback>& callback,
const Options& options) override;
void setLocationInterval(const int intervalMs);
void setLocationEnabled(const bool enabled);
private:
void start(const bool enableCorrVecOutputs);
void stop();
void reportMeasurement(const GnssData&);
void waitForStoppingThreads();
std::atomic<long> mMinIntervalMillis;
std::atomic<long> mIntervalMs;
std::atomic<long> mLocationIntervalMs;
std::atomic<bool> mIsActive;
std::atomic<bool> mLocationEnabled;
std::thread mThread;
std::vector<std::future<void>> mFutures;
::android::hardware::gnss::common::ThreadBlocker mThreadBlocker;
// Guarded by mMutex
static std::shared_ptr<IGnssMeasurementCallback> sCallback;

View File

@@ -32,7 +32,7 @@ std::shared_ptr<IGnssNavigationMessageCallback> GnssNavigationMessageInterface::
GnssNavigationMessageInterface::GnssNavigationMessageInterface() : mMinIntervalMillis(1000) {}
GnssNavigationMessageInterface::~GnssNavigationMessageInterface() {
stop();
waitForStoppingThreads();
}
ndk::ScopedAStatus GnssNavigationMessageInterface::setCallback(
@@ -46,7 +46,9 @@ ndk::ScopedAStatus GnssNavigationMessageInterface::setCallback(
ndk::ScopedAStatus GnssNavigationMessageInterface::close() {
ALOGD("close");
stop();
if (mIsActive) {
stop();
}
std::unique_lock<std::mutex> lock(mMutex);
sCallback = nullptr;
return ndk::ScopedAStatus::ok();
@@ -54,9 +56,20 @@ ndk::ScopedAStatus GnssNavigationMessageInterface::close() {
void GnssNavigationMessageInterface::start() {
ALOGD("start");
if (mIsActive) {
ALOGD("restarting since nav msg has started");
stop();
}
// Wait for stopping previous thread.
waitForStoppingThreads();
mIsActive = true;
mThread = std::thread([this]() {
while (mIsActive == true) {
do {
if (!mIsActive) {
break;
}
GnssNavigationMessage message = {
.svid = 19,
.type = GnssNavigationMessageType::GPS_L1CA,
@@ -66,15 +79,18 @@ void GnssNavigationMessageInterface::start() {
.data = std::vector<uint8_t>(40, 0xF9),
};
this->reportMessage(message);
std::this_thread::sleep_for(std::chrono::milliseconds(mMinIntervalMillis));
}
} while (mIsActive &&
mThreadBlocker.wait_for(std::chrono::milliseconds(mMinIntervalMillis)));
});
mThread.detach();
}
void GnssNavigationMessageInterface::stop() {
ALOGD("stop");
mIsActive = false;
mThreadBlocker.notify();
if (mThread.joinable()) {
mFutures.push_back(std::async(std::launch::async, [this] { mThread.join(); }));
}
}
void GnssNavigationMessageInterface::reportMessage(const GnssNavigationMessage& message) {
@@ -91,4 +107,13 @@ void GnssNavigationMessageInterface::reportMessage(const GnssNavigationMessage&
callbackCopy->gnssNavigationMessageCb(message);
}
void GnssNavigationMessageInterface::waitForStoppingThreads() {
for (auto& future : mFutures) {
ALOGD("Stopping previous thread.");
future.wait();
ALOGD("Done stopping thread.");
}
mFutures.clear();
}
} // namespace aidl::android::hardware::gnss

View File

@@ -18,7 +18,9 @@
#include <aidl/android/hardware/gnss/BnGnssNavigationMessageInterface.h>
#include <atomic>
#include <future>
#include <thread>
#include "Utils.h"
namespace aidl::android::hardware::gnss {
@@ -34,10 +36,13 @@ struct GnssNavigationMessageInterface : public BnGnssNavigationMessageInterface
void start();
void stop();
void reportMessage(const IGnssNavigationMessageCallback::GnssNavigationMessage& message);
void waitForStoppingThreads();
std::atomic<long> mMinIntervalMillis;
std::atomic<bool> mIsActive;
std::thread mThread;
std::vector<std::future<void>> mFutures;
::android::hardware::gnss::common::ThreadBlocker mThreadBlocker;
// Guarded by mMutex
static std::shared_ptr<IGnssNavigationMessageCallback> sCallback;

View File

@@ -31,7 +31,7 @@ Status GnssCallbackAidl::gnssSetCapabilitiesCb(const int capabilities) {
}
Status GnssCallbackAidl::gnssStatusCb(const GnssStatusValue /* status */) {
ALOGI("gnssSvStatusCb");
ALOGI("gnssStatusCb");
return Status::ok();
}
@@ -47,7 +47,8 @@ Status GnssCallbackAidl::gnssLocationCb(const GnssLocation& location) {
return Status::ok();
}
Status GnssCallbackAidl::gnssNmeaCb(const int64_t /* timestamp */, const std::string& /* nmea */) {
Status GnssCallbackAidl::gnssNmeaCb(const int64_t timestamp, const std::string& nmea) {
nmea_cbq_.store(std::make_pair(timestamp, nmea));
return Status::ok();
}

View File

@@ -17,6 +17,7 @@
#pragma once
#include <android/hardware/gnss/BnGnssCallback.h>
#include <utility>
#include "GnssCallbackEventQueue.h"
/* Callback class for data & Event. */
@@ -26,7 +27,8 @@ class GnssCallbackAidl : public android::hardware::gnss::BnGnssCallback {
: capabilities_cbq_("capabilities"),
info_cbq_("system_info"),
location_cbq_("location"),
sv_info_list_cbq_("sv_info"){};
sv_info_list_cbq_("sv_info"),
nmea_cbq_("nmea"){};
~GnssCallbackAidl(){};
android::binder::Status gnssSetCapabilitiesCb(const int capabilities) override;
@@ -55,4 +57,6 @@ class GnssCallbackAidl : public android::hardware::gnss::BnGnssCallback {
android::hardware::gnss::common::GnssCallbackEventQueue<
std::vector<android::hardware::gnss::IGnssCallback::GnssSvInfo>>
sv_info_list_cbq_;
android::hardware::gnss::common::GnssCallbackEventQueue<std::pair<int64_t, std::string>>
nmea_cbq_;
};

View File

@@ -24,12 +24,10 @@ using android::hardware::gnss::GnssData;
android::binder::Status GnssMeasurementCallbackAidl::gnssMeasurementCb(const GnssData& gnssData) {
ALOGI("gnssMeasurementCb");
ALOGI("elapsedRealtime: flags = %d, timestampNs: %" PRId64 ", timeUncertaintyNs=%lf",
ALOGV("elapsedRealtime: flags = 0x%X, timestampNs: %" PRId64 ", timeUncertaintyNs=%lf",
gnssData.elapsedRealtime.flags, gnssData.elapsedRealtime.timestampNs,
gnssData.elapsedRealtime.timeUncertaintyNs);
for (const auto& measurement : gnssData.measurements) {
ALOGI("measurement.receivedSvTimeInNs=%" PRId64, measurement.receivedSvTimeInNs);
}
gnss_data_cbq_.store(gnssData);
return android::binder::Status::ok();
}

View File

@@ -18,15 +18,50 @@
#include "gnss_hal_test.h"
#include <hidl/ServiceManagement.h>
#include <algorithm>
#include <cmath>
#include "Utils.h"
using android::hardware::gnss::GnssClock;
using android::hardware::gnss::GnssConstellationType;
using android::hardware::gnss::GnssData;
using android::hardware::gnss::GnssLocation;
using android::hardware::gnss::GnssMeasurement;
using android::hardware::gnss::IGnss;
using android::hardware::gnss::IGnssCallback;
using android::hardware::gnss::IGnssMeasurementInterface;
using android::hardware::gnss::common::Utils;
using GnssConstellationTypeV2_0 = android::hardware::gnss::V2_0::GnssConstellationType;
namespace {
// The difference between the mean of the received intervals and the requested interval should not
// be larger mInterval * ALLOWED_MEAN_ERROR_RATIO
constexpr double ALLOWED_MEAN_ERROR_RATIO = 0.25;
// The standard deviation computed for the deltas should not be bigger
// than mInterval * ALLOWED_STDEV_ERROR_RATIO or MIN_STDEV_MS, whichever is higher.
constexpr double ALLOWED_STDEV_ERROR_RATIO = 0.50;
constexpr double MIN_STDEV_MS = 1000;
double computeMean(std::vector<int>& deltas) {
long accumulator = 0;
for (auto& d : deltas) {
accumulator += d;
}
return accumulator / deltas.size();
}
double computeStdev(double mean, std::vector<int>& deltas) {
double accumulator = 0;
for (auto& d : deltas) {
double diff = d - mean;
accumulator += diff * diff;
}
return std::sqrt(accumulator / (deltas.size() - 1));
}
} // anonymous namespace
void GnssHalTest::SetUp() {
// Get AIDL handle
aidl_gnss_hal_ = android::waitForDeclaredService<IGnssAidl>(String16(GetParam().c_str()));
@@ -97,20 +132,26 @@ void GnssHalTest::SetPositionMode(const int min_interval_msec, const bool low_po
ASSERT_TRUE(status.isOk());
}
bool GnssHalTest::StartAndCheckFirstLocation(const int min_interval_msec,
const bool low_power_mode) {
bool GnssHalTest::StartAndCheckFirstLocation(const int min_interval_msec, const bool low_power_mode,
const bool start_sv_status, const bool start_nmea) {
if (aidl_gnss_hal_->getInterfaceVersion() <= 1) {
// Invoke the super method.
return GnssHalTestTemplate<IGnss_V2_1>::StartAndCheckFirstLocation(min_interval_msec,
low_power_mode);
}
SetPositionMode(min_interval_msec, low_power_mode);
auto status = aidl_gnss_hal_->start();
EXPECT_TRUE(status.isOk());
status = aidl_gnss_hal_->startSvStatus();
EXPECT_TRUE(status.isOk());
if (start_sv_status) {
status = aidl_gnss_hal_->startSvStatus();
EXPECT_TRUE(status.isOk());
}
if (start_nmea) {
status = aidl_gnss_hal_->startNmea();
EXPECT_TRUE(status.isOk());
}
/*
* GnssLocationProvider support of AGPS SUPL & XtraDownloader is not available in VTS,
@@ -131,6 +172,12 @@ bool GnssHalTest::StartAndCheckFirstLocation(const int min_interval_msec,
return false;
}
bool GnssHalTest::StartAndCheckFirstLocation(const int min_interval_msec,
const bool low_power_mode) {
return StartAndCheckFirstLocation(min_interval_msec, low_power_mode,
/* start_sv_status= */ true, /* start_nmea= */ true);
}
void GnssHalTest::StopAndClearLocations() {
ALOGD("StopAndClearLocations");
if (aidl_gnss_hal_->getInterfaceVersion() <= 1) {
@@ -139,6 +186,8 @@ void GnssHalTest::StopAndClearLocations() {
}
auto status = aidl_gnss_hal_->stopSvStatus();
EXPECT_TRUE(status.isOk());
status = aidl_gnss_hal_->stopNmea();
EXPECT_TRUE(status.isOk());
status = aidl_gnss_hal_->stop();
EXPECT_TRUE(status.isOk());
@@ -153,7 +202,8 @@ void GnssHalTest::StopAndClearLocations() {
aidl_gnss_cb_->location_cbq_.reset();
}
void GnssHalTest::StartAndCheckLocations(int count) {
void GnssHalTest::StartAndCheckLocations(const int count, const bool start_sv_status,
const bool start_nmea) {
if (aidl_gnss_hal_->getInterfaceVersion() <= 1) {
// Invoke the super method.
return GnssHalTestTemplate<IGnss_V2_1>::StartAndCheckLocations(count);
@@ -162,7 +212,8 @@ void GnssHalTest::StartAndCheckLocations(int count) {
const int kLocationTimeoutSubsequentSec = 2;
const bool kLowPowerMode = false;
EXPECT_TRUE(StartAndCheckFirstLocation(kMinIntervalMsec, kLowPowerMode));
EXPECT_TRUE(StartAndCheckFirstLocation(kMinIntervalMsec, kLowPowerMode, start_sv_status,
start_nmea));
for (int i = 1; i < count; i++) {
EXPECT_TRUE(aidl_gnss_cb_->location_cbq_.retrieve(aidl_gnss_cb_->last_location_,
@@ -177,6 +228,10 @@ void GnssHalTest::StartAndCheckLocations(int count) {
}
}
void GnssHalTest::StartAndCheckLocations(const int count) {
StartAndCheckLocations(count, /* start_sv_status= */ true, /* start_nmea= */ true);
}
std::list<std::vector<IGnssCallback::GnssSvInfo>> GnssHalTest::convertToAidl(
const std::list<hidl_vec<IGnssCallback_2_1::GnssSvInfo>>& sv_info_list) {
std::list<std::vector<IGnssCallback::GnssSvInfo>> aidl_sv_info_list;
@@ -313,3 +368,109 @@ GnssConstellationType GnssHalTest::startLocationAndGetNonGpsConstellation(
return constellation_to_blocklist;
}
void GnssHalTest::checkGnssMeasurementClockFields(const GnssData& measurement) {
Utils::checkElapsedRealtime(measurement.elapsedRealtime);
ASSERT_TRUE(measurement.clock.gnssClockFlags >= 0 &&
measurement.clock.gnssClockFlags <=
(GnssClock::HAS_LEAP_SECOND | GnssClock::HAS_TIME_UNCERTAINTY |
GnssClock::HAS_FULL_BIAS | GnssClock::HAS_BIAS |
GnssClock::HAS_BIAS_UNCERTAINTY | GnssClock::HAS_DRIFT |
GnssClock::HAS_DRIFT_UNCERTAINTY));
}
void GnssHalTest::checkGnssMeasurementFlags(const GnssMeasurement& measurement) {
ASSERT_TRUE(measurement.flags >= 0 &&
measurement.flags <=
(GnssMeasurement::HAS_SNR | GnssMeasurement::HAS_CARRIER_FREQUENCY |
GnssMeasurement::HAS_CARRIER_CYCLES | GnssMeasurement::HAS_CARRIER_PHASE |
GnssMeasurement::HAS_CARRIER_PHASE_UNCERTAINTY |
GnssMeasurement::HAS_AUTOMATIC_GAIN_CONTROL |
GnssMeasurement::HAS_FULL_ISB | GnssMeasurement::HAS_FULL_ISB_UNCERTAINTY |
GnssMeasurement::HAS_SATELLITE_ISB |
GnssMeasurement::HAS_SATELLITE_ISB_UNCERTAINTY |
GnssMeasurement::HAS_SATELLITE_PVT |
GnssMeasurement::HAS_CORRELATION_VECTOR));
}
void GnssHalTest::checkGnssMeasurementFields(const GnssMeasurement& measurement,
const GnssData& data) {
checkGnssMeasurementFlags(measurement);
// Verify CodeType is valid.
ASSERT_NE(measurement.signalType.codeType, "");
// Verify basebandCn0DbHz is valid.
ASSERT_TRUE(measurement.basebandCN0DbHz > 0.0 && measurement.basebandCN0DbHz <= 65.0);
if (((measurement.flags & GnssMeasurement::HAS_FULL_ISB) > 0) &&
((measurement.flags & GnssMeasurement::HAS_FULL_ISB_UNCERTAINTY) > 0) &&
((measurement.flags & GnssMeasurement::HAS_SATELLITE_ISB) > 0) &&
((measurement.flags & GnssMeasurement::HAS_SATELLITE_ISB_UNCERTAINTY) > 0)) {
GnssConstellationType referenceConstellation =
data.clock.referenceSignalTypeForIsb.constellation;
double carrierFrequencyHz = data.clock.referenceSignalTypeForIsb.carrierFrequencyHz;
std::string codeType = data.clock.referenceSignalTypeForIsb.codeType;
ASSERT_TRUE(referenceConstellation >= GnssConstellationType::UNKNOWN &&
referenceConstellation <= GnssConstellationType::IRNSS);
ASSERT_TRUE(carrierFrequencyHz > 0);
ASSERT_NE(codeType, "");
ASSERT_TRUE(std::abs(measurement.fullInterSignalBiasNs) < 1.0e6);
ASSERT_TRUE(measurement.fullInterSignalBiasUncertaintyNs >= 0);
ASSERT_TRUE(std::abs(measurement.satelliteInterSignalBiasNs) < 1.0e6);
ASSERT_TRUE(measurement.satelliteInterSignalBiasUncertaintyNs >= 0);
}
}
void GnssHalTest::startMeasurementWithInterval(
int intervalMs, const sp<IGnssMeasurementInterface>& iGnssMeasurement,
sp<GnssMeasurementCallbackAidl>& callback) {
ALOGD("Start requesting measurement at interval of %d millis.", intervalMs);
IGnssMeasurementInterface::Options options;
options.intervalMs = intervalMs;
auto status = iGnssMeasurement->setCallbackWithOptions(callback, options);
ASSERT_TRUE(status.isOk());
}
void GnssHalTest::collectMeasurementIntervals(const sp<GnssMeasurementCallbackAidl>& callback,
const int numMeasurementEvents,
const int timeoutSeconds,
std::vector<int>& deltasMs) {
int64_t lastElapsedRealtimeMillis = 0;
for (int i = 0; i < numMeasurementEvents; i++) {
GnssData lastGnssData;
ASSERT_TRUE(callback->gnss_data_cbq_.retrieve(lastGnssData, timeoutSeconds));
EXPECT_EQ(callback->gnss_data_cbq_.calledCount(), i + 1);
ASSERT_TRUE(lastGnssData.measurements.size() > 0);
// Validity check GnssData fields
checkGnssMeasurementClockFields(lastGnssData);
for (const auto& measurement : lastGnssData.measurements) {
checkGnssMeasurementFields(measurement, lastGnssData);
}
long currentElapsedRealtimeMillis = lastGnssData.elapsedRealtime.timestampNs * 1e-6;
if (lastElapsedRealtimeMillis != 0) {
deltasMs.push_back(currentElapsedRealtimeMillis - lastElapsedRealtimeMillis);
}
lastElapsedRealtimeMillis = currentElapsedRealtimeMillis;
}
}
void GnssHalTest::assertMeanAndStdev(int intervalMs, std::vector<int>& deltasMs) {
double mean = computeMean(deltasMs);
double stdev = computeStdev(mean, deltasMs);
EXPECT_TRUE(std::abs(mean - intervalMs) <= intervalMs * ALLOWED_MEAN_ERROR_RATIO)
<< "Test failed, because the mean of intervals is " << mean
<< " millis. The test requires that abs(" << mean << " - " << intervalMs
<< ") <= " << intervalMs * ALLOWED_MEAN_ERROR_RATIO
<< " millis, when the requested interval is " << intervalMs << " millis.";
double maxStdev = std::max(MIN_STDEV_MS, intervalMs * ALLOWED_STDEV_ERROR_RATIO);
EXPECT_TRUE(stdev <= maxStdev)
<< "Test failed, because the stdev of intervals is " << stdev
<< " millis, which must be <= " << maxStdev
<< " millis, when the requested interval is " << intervalMs << " millis.";
ALOGD("Mean of interval deltas in millis: %.1lf", mean);
ALOGD("Stdev of interval deltas in millis: %.1lf", stdev);
}

View File

@@ -25,6 +25,7 @@
#include <android/hardware/gnss/2.1/IGnss.h>
#include "GnssBatchingCallback.h"
#include "GnssCallbackAidl.h"
#include "GnssMeasurementCallbackAidl.h"
#include "v2_1/gnss_hal_test_template.h"
using IGnss_V2_1 = android::hardware::gnss::V2_1::IGnss;
@@ -68,8 +69,11 @@ class GnssHalTest : public android::hardware::gnss::common::GnssHalTestTemplate<
const bool check_speed);
void SetPositionMode(const int min_interval_msec, const bool low_power_mode);
bool StartAndCheckFirstLocation(const int min_interval_msec, const bool low_power_mode);
bool StartAndCheckFirstLocation(const int min_interval_msec, const bool low_power_mode,
const bool start_sv_status, const bool start_nmea);
void StopAndClearLocations();
void StartAndCheckLocations(int count);
void StartAndCheckLocations(const int count);
void StartAndCheckLocations(const int count, const bool start_sv_status, const bool start_nmea);
android::hardware::gnss::GnssConstellationType startLocationAndGetNonGpsConstellation(
const int locations_to_await, const int gnss_sv_info_list_timeout);
@@ -85,6 +89,19 @@ class GnssHalTest : public android::hardware::gnss::common::GnssHalTestTemplate<
sv_info_list,
const int min_observations);
void checkGnssMeasurementClockFields(const android::hardware::gnss::GnssData& measurement);
void checkGnssMeasurementFlags(const android::hardware::gnss::GnssMeasurement& measurement);
void checkGnssMeasurementFields(const android::hardware::gnss::GnssMeasurement& measurement,
const android::hardware::gnss::GnssData& data);
void startMeasurementWithInterval(
int intervalMillis,
const sp<android::hardware::gnss::IGnssMeasurementInterface>& iMeasurement,
sp<GnssMeasurementCallbackAidl>& callback);
void collectMeasurementIntervals(const sp<GnssMeasurementCallbackAidl>& callback,
const int numMeasurementEvents, const int timeoutSeconds,
std::vector<int>& deltaMs);
void assertMeanAndStdev(int intervalMillis, std::vector<int>& deltasMillis);
sp<IGnssAidl> aidl_gnss_hal_;
sp<GnssCallbackAidl> aidl_gnss_cb_; // Primary callback interface
};

View File

@@ -28,7 +28,9 @@
#include <android/hardware/gnss/measurement_corrections/IMeasurementCorrectionsInterface.h>
#include <android/hardware/gnss/visibility_control/IGnssVisibilityControl.h>
#include <cutils/properties.h>
#include <utils/SystemClock.h>
#include <cmath>
#include <utility>
#include "AGnssCallbackAidl.h"
#include "AGnssRilCallbackAidl.h"
#include "GnssAntennaInfoCallbackAidl.h"
@@ -376,58 +378,6 @@ void CheckSatellitePvt(const SatellitePvt& satellitePvt, const int interfaceVers
}
}
void CheckGnssMeasurementClockFields(const GnssData& measurement) {
Utils::checkElapsedRealtime(measurement.elapsedRealtime);
ASSERT_TRUE(measurement.clock.gnssClockFlags >= 0 &&
measurement.clock.gnssClockFlags <=
(GnssClock::HAS_LEAP_SECOND | GnssClock::HAS_TIME_UNCERTAINTY |
GnssClock::HAS_FULL_BIAS | GnssClock::HAS_BIAS |
GnssClock::HAS_BIAS_UNCERTAINTY | GnssClock::HAS_DRIFT |
GnssClock::HAS_DRIFT_UNCERTAINTY));
}
void CheckGnssMeasurementFlags(const GnssMeasurement& measurement) {
ASSERT_TRUE(measurement.flags >= 0 &&
measurement.flags <=
(GnssMeasurement::HAS_SNR | GnssMeasurement::HAS_CARRIER_FREQUENCY |
GnssMeasurement::HAS_CARRIER_CYCLES | GnssMeasurement::HAS_CARRIER_PHASE |
GnssMeasurement::HAS_CARRIER_PHASE_UNCERTAINTY |
GnssMeasurement::HAS_AUTOMATIC_GAIN_CONTROL |
GnssMeasurement::HAS_FULL_ISB | GnssMeasurement::HAS_FULL_ISB_UNCERTAINTY |
GnssMeasurement::HAS_SATELLITE_ISB |
GnssMeasurement::HAS_SATELLITE_ISB_UNCERTAINTY |
GnssMeasurement::HAS_SATELLITE_PVT |
GnssMeasurement::HAS_CORRELATION_VECTOR));
}
void CheckGnssMeasurementFields(const GnssMeasurement& measurement, const GnssData& data) {
CheckGnssMeasurementFlags(measurement);
// Verify CodeType is valid.
ASSERT_NE(measurement.signalType.codeType, "");
// Verify basebandCn0DbHz is valid.
ASSERT_TRUE(measurement.basebandCN0DbHz > 0.0 && measurement.basebandCN0DbHz <= 65.0);
if (((measurement.flags & GnssMeasurement::HAS_FULL_ISB) > 0) &&
((measurement.flags & GnssMeasurement::HAS_FULL_ISB_UNCERTAINTY) > 0) &&
((measurement.flags & GnssMeasurement::HAS_SATELLITE_ISB) > 0) &&
((measurement.flags & GnssMeasurement::HAS_SATELLITE_ISB_UNCERTAINTY) > 0)) {
GnssConstellationType referenceConstellation =
data.clock.referenceSignalTypeForIsb.constellation;
double carrierFrequencyHz = data.clock.referenceSignalTypeForIsb.carrierFrequencyHz;
std::string codeType = data.clock.referenceSignalTypeForIsb.codeType;
ASSERT_TRUE(referenceConstellation >= GnssConstellationType::UNKNOWN &&
referenceConstellation <= GnssConstellationType::IRNSS);
ASSERT_TRUE(carrierFrequencyHz > 0);
ASSERT_NE(codeType, "");
ASSERT_TRUE(std::abs(measurement.fullInterSignalBiasNs) < 1.0e6);
ASSERT_TRUE(measurement.fullInterSignalBiasUncertaintyNs >= 0);
ASSERT_TRUE(std::abs(measurement.satelliteInterSignalBiasNs) < 1.0e6);
ASSERT_TRUE(measurement.satelliteInterSignalBiasUncertaintyNs >= 0);
}
}
/*
* TestGnssMeasurementExtensionAndSatellitePvt:
* 1. Gets the GnssMeasurementExtension and verifies that it returns a non-null extension.
@@ -465,10 +415,10 @@ TEST_P(GnssHalTest, TestGnssMeasurementExtensionAndSatellitePvt) {
ASSERT_TRUE(lastMeasurement.measurements.size() > 0);
// Validity check GnssData fields
CheckGnssMeasurementClockFields(lastMeasurement);
checkGnssMeasurementClockFields(lastMeasurement);
for (const auto& measurement : lastMeasurement.measurements) {
CheckGnssMeasurementFields(measurement, lastMeasurement);
checkGnssMeasurementFields(measurement, lastMeasurement);
if (measurement.flags & GnssMeasurement::HAS_SATELLITE_PVT &&
kIsSatellitePvtSupported == true) {
ALOGD("Found a measurement with SatellitePvt");
@@ -525,10 +475,10 @@ TEST_P(GnssHalTest, TestCorrelationVector) {
ASSERT_TRUE(lastMeasurement.measurements.size() > 0);
// Validity check GnssData fields
CheckGnssMeasurementClockFields(lastMeasurement);
checkGnssMeasurementClockFields(lastMeasurement);
for (const auto& measurement : lastMeasurement.measurements) {
CheckGnssMeasurementFields(measurement, lastMeasurement);
checkGnssMeasurementFields(measurement, lastMeasurement);
if (measurement.flags & GnssMeasurement::HAS_CORRELATION_VECTOR) {
correlationVectorFound = true;
ASSERT_TRUE(measurement.correlationVectors.size() > 0);
@@ -1241,48 +1191,6 @@ TEST_P(GnssHalTest, TestGnssVisibilityControlExtension) {
ASSERT_TRUE(status.isOk());
}
/*
* TestGnssMeasurementSetCallbackWithOptions:
* 1. Gets the GnssMeasurementExtension and verifies that it returns a non-null extension.
* 2. Sets a GnssMeasurementCallback with intervalMillis option, waits for measurements reported,
* and verifies mandatory fields are valid.
*/
TEST_P(GnssHalTest, TestGnssMeasurementSetCallbackWithOptions) {
if (aidl_gnss_hal_->getInterfaceVersion() <= 1) {
return;
}
const int kFirstGnssMeasurementTimeoutSeconds = 10;
const int kNumMeasurementEvents = 5;
sp<IGnssMeasurementInterface> iGnssMeasurement;
auto status = aidl_gnss_hal_->getExtensionGnssMeasurement(&iGnssMeasurement);
ASSERT_TRUE(status.isOk());
ASSERT_TRUE(iGnssMeasurement != nullptr);
auto callback = sp<GnssMeasurementCallbackAidl>::make();
IGnssMeasurementInterface::Options options;
options.intervalMs = 2000;
status = iGnssMeasurement->setCallbackWithOptions(callback, options);
ASSERT_TRUE(status.isOk());
for (int i = 0; i < kNumMeasurementEvents; i++) {
GnssData lastMeasurement;
ASSERT_TRUE(callback->gnss_data_cbq_.retrieve(lastMeasurement,
kFirstGnssMeasurementTimeoutSeconds));
EXPECT_EQ(callback->gnss_data_cbq_.calledCount(), i + 1);
ASSERT_TRUE(lastMeasurement.measurements.size() > 0);
// Validity check GnssData fields
CheckGnssMeasurementClockFields(lastMeasurement);
for (const auto& measurement : lastMeasurement.measurements) {
CheckGnssMeasurementFields(measurement, lastMeasurement);
}
}
status = iGnssMeasurement->close();
ASSERT_TRUE(status.isOk());
}
/*
* TestGnssAgcInGnssMeasurement:
* 1. Gets the GnssMeasurementExtension and verifies that it returns a non-null extension.
@@ -1293,7 +1201,7 @@ TEST_P(GnssHalTest, TestGnssAgcInGnssMeasurement) {
return;
}
const int kFirstGnssMeasurementTimeoutSeconds = 10;
const int kNumMeasurementEvents = 15;
const int kNumMeasurementEvents = 5;
sp<IGnssMeasurementInterface> iGnssMeasurement;
auto status = aidl_gnss_hal_->getExtensionGnssMeasurement(&iGnssMeasurement);
@@ -1313,7 +1221,7 @@ TEST_P(GnssHalTest, TestGnssAgcInGnssMeasurement) {
ASSERT_TRUE(lastMeasurement.measurements.size() > 0);
// Validity check GnssData fields
CheckGnssMeasurementClockFields(lastMeasurement);
checkGnssMeasurementClockFields(lastMeasurement);
ASSERT_TRUE(lastMeasurement.gnssAgcs.size() > 0);
for (const auto& gnssAgc : lastMeasurement.gnssAgcs) {
@@ -1444,3 +1352,143 @@ TEST_P(GnssHalTest, TestGnssMeasurementCorrections) {
Utils::getMockMeasurementCorrections_aidl());
ASSERT_TRUE(status.isOk());
}
/*
* TestStopSvStatusAndNmea:
* 1. Call stopSvStatus and stopNmea.
* 2. Start location and verify that
* - no SvStatus is received.
* - no Nmea is received.
*/
TEST_P(GnssHalTest, TestStopSvStatusAndNmea) {
if (aidl_gnss_hal_->getInterfaceVersion() <= 1) {
return;
}
auto status = aidl_gnss_hal_->stopSvStatus();
EXPECT_TRUE(status.isOk());
status = aidl_gnss_hal_->stopNmea();
EXPECT_TRUE(status.isOk());
int kLocationsToAwait = 5;
aidl_gnss_cb_->location_cbq_.reset();
aidl_gnss_cb_->sv_info_list_cbq_.reset();
aidl_gnss_cb_->nmea_cbq_.reset();
StartAndCheckLocations(/* count= */ kLocationsToAwait,
/* start_sv_status= */ false, /* start_nmea= */ false);
int location_called_count = aidl_gnss_cb_->location_cbq_.calledCount();
ALOGD("Observed %d GnssSvStatus, and %d Nmea while awaiting %d locations (%d received)",
aidl_gnss_cb_->sv_info_list_cbq_.size(), aidl_gnss_cb_->nmea_cbq_.size(),
kLocationsToAwait, location_called_count);
// Ensure that no SvStatus & no Nmea is received.
EXPECT_EQ(aidl_gnss_cb_->sv_info_list_cbq_.size(), 0);
EXPECT_EQ(aidl_gnss_cb_->nmea_cbq_.size(), 0);
StopAndClearLocations();
}
/*
* TestGnssMeasurementIntervals_WithoutLocation:
* 1. start measurement with interval
* 2. verify that the received measurement intervals have expected mean and stdev
*/
TEST_P(GnssHalTest, TestGnssMeasurementIntervals_WithoutLocation) {
if (aidl_gnss_hal_->getInterfaceVersion() <= 1) {
return;
}
std::vector<int> intervals({2000, 4000});
std::vector<int> numEvents({10, 5});
sp<IGnssMeasurementInterface> iGnssMeasurement;
auto status = aidl_gnss_hal_->getExtensionGnssMeasurement(&iGnssMeasurement);
ASSERT_TRUE(status.isOk());
ASSERT_TRUE(iGnssMeasurement != nullptr);
ALOGD("TestGnssMeasurementIntervals_WithoutLocation");
for (int i = 0; i < intervals.size(); i++) {
auto callback = sp<GnssMeasurementCallbackAidl>::make();
startMeasurementWithInterval(intervals[i], iGnssMeasurement, callback);
std::vector<int> deltas;
collectMeasurementIntervals(callback, numEvents[i], /* timeoutSeconds= */ 10, deltas);
status = iGnssMeasurement->close();
ASSERT_TRUE(status.isOk());
assertMeanAndStdev(intervals[i], deltas);
}
}
/*
* TestGnssMeasurementIntervals_LocationOnBeforeMeasurement:
* 1. start measurement with interval
* 2. verify that the received measurement intervals have expected mean and stdev
*/
TEST_P(GnssHalTest, TestGnssMeasurementIntervals_LocationOnBeforeMeasurement) {
if (aidl_gnss_hal_->getInterfaceVersion() <= 1) {
return;
}
std::vector<int> intervals({2000});
sp<IGnssMeasurementInterface> iGnssMeasurement;
auto status = aidl_gnss_hal_->getExtensionGnssMeasurement(&iGnssMeasurement);
ASSERT_TRUE(status.isOk());
ASSERT_TRUE(iGnssMeasurement != nullptr);
int locationIntervalMs = 1000;
// Start location first and then start measurement
ALOGD("TestGnssMeasurementIntervals_LocationOnBeforeMeasurement");
StartAndCheckFirstLocation(locationIntervalMs, /* lowPowerMode= */ false);
for (auto& intervalMs : intervals) {
auto callback = sp<GnssMeasurementCallbackAidl>::make();
startMeasurementWithInterval(intervalMs, iGnssMeasurement, callback);
std::vector<int> deltas;
collectMeasurementIntervals(callback, /*numEvents=*/10, /*timeoutSeconds=*/10, deltas);
status = iGnssMeasurement->close();
ASSERT_TRUE(status.isOk());
assertMeanAndStdev(locationIntervalMs, deltas);
}
StopAndClearLocations();
}
/*
* TestGnssMeasurementIntervals:
* 1. start measurement with interval
* 2. verify that the received measurement intervals have expected mean and stdev
*/
TEST_P(GnssHalTest, TestGnssMeasurementIntervals_LocationOnAfterMeasurement) {
if (aidl_gnss_hal_->getInterfaceVersion() <= 1) {
return;
}
std::vector<int> intervals({2000});
sp<IGnssMeasurementInterface> iGnssMeasurement;
auto status = aidl_gnss_hal_->getExtensionGnssMeasurement(&iGnssMeasurement);
ASSERT_TRUE(status.isOk());
ASSERT_TRUE(iGnssMeasurement != nullptr);
int locationIntervalMs = 1000;
// Start location first and then start measurement
ALOGD("TestGnssMeasurementIntervals_LocationOnAfterMeasurement");
for (auto& intervalMs : intervals) {
auto callback = sp<GnssMeasurementCallbackAidl>::make();
startMeasurementWithInterval(intervalMs, iGnssMeasurement, callback);
StartAndCheckFirstLocation(locationIntervalMs, /* lowPowerMode= */ false);
std::vector<int> deltas;
collectMeasurementIntervals(callback, /*numEvents=*/10, /*timeoutSeconds=*/10, deltas);
StopAndClearLocations();
status = iGnssMeasurement->close();
ASSERT_TRUE(status.isOk());
assertMeanAndStdev(locationIntervalMs, deltas);
}
}

View File

@@ -56,6 +56,31 @@ struct Utils {
static hidl_vec<V2_1::IGnssAntennaInfoCallback::GnssAntennaInfo> getMockAntennaInfos();
};
struct ThreadBlocker {
// returns false if unblocked:
template <class R, class P>
bool wait_for(std::chrono::duration<R, P> const& time) {
std::unique_lock<std::mutex> lock(m);
return !cv.wait_for(lock, time, [&] { return terminate; });
}
void notify() {
std::unique_lock<std::mutex> lock(m);
terminate = true;
cv.notify_all();
}
void reset() {
std::unique_lock<std::mutex> lock(m);
terminate = false;
}
private:
std::condition_variable cv;
std::mutex m;
bool terminate = false;
};
} // namespace common
} // namespace gnss
} // namespace hardware