/* * Copyright (C) 2019 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. */ #pragma once #include #include #include #include #include #include #include #include #include #include #include #include #include "DeviceFileReader.h" #include "GnssAntennaInfo.h" #include "GnssConfiguration.h" #include "GnssDebug.h" #include "GnssMeasurement.h" #include "GnssMeasurementCorrections.h" #include "GnssReplayUtils.h" #include "MockLocation.h" #include "NmeaFixInfo.h" #include "Utils.h" namespace android::hardware::gnss::common::implementation { constexpr int INPUT_BUFFER_SIZE = 128; constexpr char CMD_GET_LOCATION[] = "CMD_GET_LOCATION"; constexpr char GNSS_PATH[] = "/dev/gnss0"; constexpr int TTFF_MILLIS = 2200; template struct GnssTemplate : public T_IGnss { GnssTemplate(); ~GnssTemplate(); // Methods from V1_0::IGnss follow. Return setCallback(const sp& callback) override; Return start() override; Return stop() override; Return cleanup() override; Return injectTime(int64_t timeMs, int64_t timeReferenceMs, int32_t uncertaintyMs) override; Return injectLocation(double latitudeDegrees, double longitudeDegrees, float accuracyMeters) override; Return deleteAidingData(V1_0::IGnss::GnssAidingData aidingDataFlags) override; Return setPositionMode(V1_0::IGnss::GnssPositionMode mode, V1_0::IGnss::GnssPositionRecurrence recurrence, uint32_t minIntervalMs, uint32_t preferredAccuracyMeters, uint32_t preferredTimeMs) override; Return> getExtensionAGnssRil() override; Return> getExtensionGnssGeofencing() override; Return> getExtensionAGnss() override; Return> getExtensionGnssNi() override; Return> getExtensionGnssMeasurement() override; Return> getExtensionGnssNavigationMessage() override; Return> getExtensionXtra() override; Return> getExtensionGnssConfiguration() override; Return> getExtensionGnssDebug() override; Return> getExtensionGnssBatching() override; // Methods from V1_1::IGnss follow. Return setCallback_1_1(const sp& callback) override; Return setPositionMode_1_1(V1_0::IGnss::GnssPositionMode mode, V1_0::IGnss::GnssPositionRecurrence recurrence, uint32_t minIntervalMs, uint32_t preferredAccuracyMeters, uint32_t preferredTimeMs, bool lowPowerMode) override; Return> getExtensionGnssConfiguration_1_1() override; Return> getExtensionGnssMeasurement_1_1() override; Return injectBestLocation(const V1_0::GnssLocation& location) override; // Methods from V2_0::IGnss follow. Return setCallback_2_0(const sp& callback) override; Return> getExtensionGnssConfiguration_2_0() override; Return> getExtensionGnssDebug_2_0() override; Return> getExtensionAGnss_2_0() override; Return> getExtensionAGnssRil_2_0() override; Return> getExtensionGnssMeasurement_2_0() override; Return> getExtensionMeasurementCorrections() override; Return> getExtensionVisibilityControl() override; Return> getExtensionGnssBatching_2_0() override; Return injectBestLocation_2_0(const V2_0::GnssLocation& location) override; // Methods from V2_1::IGnss follow. Return setCallback_2_1(const sp& callback) override; Return> getExtensionGnssMeasurement_2_1() override; Return> getExtensionGnssConfiguration_2_1() override; Return> getExtensionMeasurementCorrections_1_1() override; Return> getExtensionGnssAntennaInfo() override; Return debug(const hidl_handle& fd, const hidl_vec& options) override; private: std::unique_ptr getLocationFromHW(); void reportLocation(const V2_0::GnssLocation&) const; void reportLocation(const V1_0::GnssLocation&) const; void reportSvStatus(const hidl_vec&) const; void reportGnssStatusValue(const V1_0::IGnssCallback::GnssStatusValue) const; Return help(const hidl_handle& fd); Return setLocation(const hidl_handle& fd, const hidl_vec& options); static sp sGnssCallback_2_1; static sp sGnssCallback_2_0; static sp sGnssCallback_1_1; static sp sGnssCallback_1_0; std::atomic mMinIntervalMs; sp mGnssConfiguration; std::atomic mIsActive; std::atomic mHardwareModeChecked; std::atomic mGnssFd; std::thread mThread; std::atomic mFirstFixReceived; mutable std::mutex mMutex; virtual hidl_vec filterBlocklistedSatellitesV2_1( hidl_vec gnssSvInfoList); virtual void notePowerConsumption(); }; template sp GnssTemplate::sGnssCallback_2_1 = nullptr; template sp GnssTemplate::sGnssCallback_2_0 = nullptr; template sp GnssTemplate::sGnssCallback_1_1 = nullptr; template sp GnssTemplate::sGnssCallback_1_0 = nullptr; template GnssTemplate::GnssTemplate() : mMinIntervalMs(1000), mGnssConfiguration{new V2_1::implementation::GnssConfiguration()}, mHardwareModeChecked(false), mGnssFd(-1), mFirstFixReceived(false) {} template GnssTemplate::~GnssTemplate() { stop(); } template std::unique_ptr GnssTemplate::getLocationFromHW() { mHardwareModeChecked = true; std::string inputStr = ::android::hardware::gnss::common::DeviceFileReader::Instance().getLocationData(); return NmeaFixInfo::getLocationFromInputStr(inputStr); } template Return GnssTemplate::start() { if (mIsActive) { ALOGW("Gnss has started. Restarting..."); stop(); } mIsActive = true; this->reportGnssStatusValue(V1_0::IGnssCallback::GnssStatusValue::SESSION_BEGIN); mThread = std::thread([this]() { auto svStatus = filterBlocklistedSatellitesV2_1(Utils::getMockSvInfoListV2_1()); this->reportSvStatus(svStatus); if (!mFirstFixReceived) { std::this_thread::sleep_for(std::chrono::milliseconds(TTFF_MILLIS)); mFirstFixReceived = true; } while (mIsActive == true) { auto svStatus = filterBlocklistedSatellitesV2_1(Utils::getMockSvInfoListV2_1()); this->reportSvStatus(svStatus); auto currentLocation = getLocationFromHW(); notePowerConsumption(); if (currentLocation != nullptr) { this->reportLocation(*currentLocation); } else { if (sGnssCallback_2_1 != nullptr || sGnssCallback_2_0 != nullptr) { const auto location = Utils::getMockLocationV2_0(); this->reportLocation(location); } else { const auto location = Utils::getMockLocationV1_0(); this->reportLocation(location); } } std::this_thread::sleep_for(std::chrono::milliseconds(mMinIntervalMs)); } }); return true; } template hidl_vec GnssTemplate::filterBlocklistedSatellitesV2_1( hidl_vec gnssSvInfoList) { ALOGD("GnssTemplate::filterBlocklistedSatellitesV2_1"); for (uint32_t i = 0; i < gnssSvInfoList.size(); i++) { if (mGnssConfiguration->isBlacklistedV2_1(gnssSvInfoList[i])) { gnssSvInfoList[i].v2_0.v1_0.svFlag &= ~static_cast(V1_0::IGnssCallback::GnssSvFlags::USED_IN_FIX); } } return gnssSvInfoList; } template void GnssTemplate::notePowerConsumption() { ALOGD("GnssTemplate::notePowerConsumption"); } template Return GnssTemplate::stop() { ALOGD("stop"); mIsActive = false; this->reportGnssStatusValue(V1_0::IGnssCallback::GnssStatusValue::SESSION_END); if (mThread.joinable()) { mThread.join(); } if (mGnssFd != -1) { close(mGnssFd); mGnssFd = -1; mHardwareModeChecked = false; } return true; } // Methods from V1_0::IGnss follow. template Return GnssTemplate::setCallback(const sp& callback) { if (callback == nullptr) { ALOGE("%s: Null callback ignored", __func__); return false; } sGnssCallback_1_0 = callback; uint32_t capabilities = 0x0 | V1_0::IGnssCallback::Capabilities::MEASUREMENTS | V1_0::IGnssCallback::Capabilities::SCHEDULING; auto ret = sGnssCallback_1_0->gnssSetCapabilitesCb(capabilities); if (!ret.isOk()) { ALOGE("%s: Unable to invoke callback", __func__); } V2_1::IGnssCallback::GnssSystemInfo gnssInfo = {.yearOfHw = 2018}; ret = sGnssCallback_1_0->gnssSetSystemInfoCb(gnssInfo); if (!ret.isOk()) { ALOGE("%s: Unable to invoke callback", __func__); } return true; } template Return GnssTemplate::cleanup() { sGnssCallback_2_1 = nullptr; sGnssCallback_2_0 = nullptr; return Void(); } template Return GnssTemplate::injectTime(int64_t, int64_t, int32_t) { return true; } template Return GnssTemplate::injectLocation(double, double, float) { return true; } template Return GnssTemplate::deleteAidingData(V1_0::IGnss::GnssAidingData) { mFirstFixReceived = false; return Void(); } template Return GnssTemplate::setPositionMode(V1_0::IGnss::GnssPositionMode, V1_0::IGnss::GnssPositionRecurrence, uint32_t minIntervalMs, uint32_t, uint32_t) { mMinIntervalMs = minIntervalMs; return true; } template Return> GnssTemplate::getExtensionAGnssRil() { // TODO implement return ::android::sp{}; } template Return> GnssTemplate::getExtensionGnssGeofencing() { // TODO implement return ::android::sp{}; } template Return> GnssTemplate::getExtensionAGnss() { // TODO implement return ::android::sp{}; } template Return> GnssTemplate::getExtensionGnssNi() { // TODO implement return ::android::sp{}; } template Return> GnssTemplate::getExtensionGnssMeasurement() { ALOGD("Gnss::getExtensionGnssMeasurement"); return new V2_1::implementation::GnssMeasurement(); } template Return> GnssTemplate::getExtensionGnssNavigationMessage() { // TODO implement return ::android::sp{}; } template Return> GnssTemplate::getExtensionXtra() { // TODO implement return ::android::sp{}; } template Return> GnssTemplate::getExtensionGnssConfiguration() { // TODO implement return ::android::sp{}; } template Return> GnssTemplate::getExtensionGnssDebug() { return new V1_1::implementation::GnssDebug(); } template Return> GnssTemplate::getExtensionGnssBatching() { // TODO implement return ::android::sp{}; } // Methods from V1_1::IGnss follow. template Return GnssTemplate::setCallback_1_1(const sp& callback) { if (callback == nullptr) { ALOGE("%s: Null callback ignored", __func__); return false; } sGnssCallback_1_1 = callback; uint32_t capabilities = 0x0; auto ret = sGnssCallback_1_1->gnssSetCapabilitesCb(capabilities); if (!ret.isOk()) { ALOGE("%s: Unable to invoke callback", __func__); } V2_1::IGnssCallback::GnssSystemInfo gnssInfo = {.yearOfHw = 2018}; ret = sGnssCallback_1_1->gnssSetSystemInfoCb(gnssInfo); if (!ret.isOk()) { ALOGE("%s: Unable to invoke callback", __func__); } auto gnssName = "Google Mock GNSS Implementation v2.1"; ret = sGnssCallback_1_1->gnssNameCb(gnssName); if (!ret.isOk()) { ALOGE("%s: Unable to invoke callback", __func__); } return true; } template Return GnssTemplate::setPositionMode_1_1(V1_0::IGnss::GnssPositionMode, V1_0::IGnss::GnssPositionRecurrence, uint32_t minIntervalMs, uint32_t, uint32_t, bool) { mMinIntervalMs = minIntervalMs; return true; } template Return> GnssTemplate::getExtensionGnssConfiguration_1_1() { // TODO implement return ::android::sp{}; } template Return> GnssTemplate::getExtensionGnssMeasurement_1_1() { // TODO implement return ::android::sp{}; } template Return GnssTemplate::injectBestLocation(const V1_0::GnssLocation&) { return true; } // Methods from V2_0::IGnss follow. template Return GnssTemplate::setCallback_2_0(const sp& callback) { ALOGD("Gnss::setCallback_2_0"); if (callback == nullptr) { ALOGE("%s: Null callback ignored", __func__); return false; } sGnssCallback_2_0 = callback; using Capabilities = V2_0::IGnssCallback::Capabilities; const auto capabilities = Capabilities::MEASUREMENTS | Capabilities::MEASUREMENT_CORRECTIONS | Capabilities::LOW_POWER_MODE | Capabilities::SATELLITE_BLACKLIST; auto ret = sGnssCallback_2_0->gnssSetCapabilitiesCb_2_0(capabilities); if (!ret.isOk()) { ALOGE("%s: Unable to invoke callback", __func__); } V1_1::IGnssCallback::GnssSystemInfo gnssInfo = {.yearOfHw = 2019}; ret = sGnssCallback_2_0->gnssSetSystemInfoCb(gnssInfo); if (!ret.isOk()) { ALOGE("%s: Unable to invoke callback", __func__); } auto gnssName = "Google Mock GNSS Implementation v2.1"; ret = sGnssCallback_2_0->gnssNameCb(gnssName); if (!ret.isOk()) { ALOGE("%s: Unable to invoke callback", __func__); } return true; } template Return> GnssTemplate::getExtensionGnssConfiguration_2_0() { ALOGD("Gnss::getExtensionGnssConfiguration_2_0"); return mGnssConfiguration; } template Return> GnssTemplate::getExtensionGnssDebug_2_0() { // TODO implement return ::android::sp{}; } template Return> GnssTemplate::getExtensionAGnss_2_0() { // TODO implement return ::android::sp{}; } template Return> GnssTemplate::getExtensionAGnssRil_2_0() { // TODO implement return ::android::sp{}; } template Return> GnssTemplate::getExtensionGnssMeasurement_2_0() { ALOGD("Gnss::getExtensionGnssMeasurement_2_0"); return new V2_1::implementation::GnssMeasurement(); } template Return> GnssTemplate::getExtensionMeasurementCorrections() { ALOGD("Gnss::getExtensionMeasurementCorrections()"); return new measurement_corrections::V1_1::implementation::GnssMeasurementCorrections(); } template Return> GnssTemplate::getExtensionVisibilityControl() { // TODO implement return ::android::sp{}; } template Return> GnssTemplate::getExtensionGnssBatching_2_0() { // TODO implement return ::android::sp{}; } template Return GnssTemplate::injectBestLocation_2_0(const V2_0::GnssLocation&) { // TODO(b/124012850): Implement function. return bool{}; } // Methods from V2_1::IGnss follow. template Return GnssTemplate::setCallback_2_1(const sp& callback) { ALOGD("Gnss::setCallback_2_1"); if (callback == nullptr) { ALOGE("%s: Null callback ignored", __func__); return false; } sGnssCallback_2_1 = callback; using Capabilities = V2_1::IGnssCallback::Capabilities; const auto capabilities = Capabilities::MEASUREMENTS | Capabilities::MEASUREMENT_CORRECTIONS | Capabilities::LOW_POWER_MODE | Capabilities::SATELLITE_BLACKLIST | Capabilities::ANTENNA_INFO | Capabilities::NAV_MESSAGES; auto ret = sGnssCallback_2_1->gnssSetCapabilitiesCb_2_1(capabilities); if (!ret.isOk()) { ALOGE("%s: Unable to invoke callback", __func__); } V1_1::IGnssCallback::GnssSystemInfo gnssInfo = {.yearOfHw = 2020}; ret = sGnssCallback_2_1->gnssSetSystemInfoCb(gnssInfo); if (!ret.isOk()) { ALOGE("%s: Unable to invoke callback", __func__); } auto gnssName = "Android Mock GNSS Implementation v2.1"; ret = sGnssCallback_2_1->gnssNameCb(gnssName); if (!ret.isOk()) { ALOGE("%s: Unable to invoke callback", __func__); } return true; } template Return> GnssTemplate::getExtensionGnssMeasurement_2_1() { ALOGD("Gnss::getExtensionGnssMeasurement_2_1"); return new V2_1::implementation::GnssMeasurement(); } template Return> GnssTemplate::getExtensionGnssConfiguration_2_1() { ALOGD("Gnss::getExtensionGnssConfiguration_2_1"); return mGnssConfiguration; } template Return> GnssTemplate::getExtensionMeasurementCorrections_1_1() { ALOGD("Gnss::getExtensionMeasurementCorrections_1_1()"); return new measurement_corrections::V1_1::implementation::GnssMeasurementCorrections(); } template Return> GnssTemplate::getExtensionGnssAntennaInfo() { ALOGD("Gnss::getExtensionGnssAntennaInfo"); return new V2_1::implementation::GnssAntennaInfo(); } template void GnssTemplate::reportGnssStatusValue( const V1_0::IGnssCallback::GnssStatusValue gnssStatusValue) const { std::unique_lock lock(mMutex); if (sGnssCallback_2_1 == nullptr) { ALOGE("%s: sGnssCallback v2.1 is null.", __func__); return; } auto ret = sGnssCallback_2_1->gnssStatusCb(gnssStatusValue); if (!ret.isOk()) { ALOGE("%s: Unable to invoke callback", __func__); } } template void GnssTemplate::reportSvStatus( const hidl_vec& svInfoList) const { std::unique_lock lock(mMutex); // TODO(skz): update this to call 2_0 callback if non-null if (sGnssCallback_2_1 == nullptr) { ALOGE("%s: sGnssCallback v2.1 is null.", __func__); return; } auto ret = sGnssCallback_2_1->gnssSvStatusCb_2_1(svInfoList); if (!ret.isOk()) { ALOGE("%s: Unable to invoke callback", __func__); } } template void GnssTemplate::reportLocation(const V1_0::GnssLocation& location) const { std::unique_lock lock(mMutex); if (sGnssCallback_1_1 != nullptr) { auto ret = sGnssCallback_1_1->gnssLocationCb(location); if (!ret.isOk()) { ALOGE("%s: Unable to invoke callback v1.1", __func__); } return; } if (sGnssCallback_1_0 == nullptr) { ALOGE("%s: No non-null callback", __func__); return; } auto ret = sGnssCallback_1_0->gnssLocationCb(location); if (!ret.isOk()) { ALOGE("%s: Unable to invoke callback v1.0", __func__); } } template void GnssTemplate::reportLocation(const V2_0::GnssLocation& location) const { std::unique_lock lock(mMutex); if (sGnssCallback_2_1 != nullptr) { auto ret = sGnssCallback_2_1->gnssLocationCb_2_0(location); if (!ret.isOk()) { ALOGE("%s: Unable to invoke callback v2.1", __func__); } return; } if (sGnssCallback_2_0 == nullptr) { ALOGE("%s: No non-null callback", __func__); return; } auto ret = sGnssCallback_2_0->gnssLocationCb_2_0(location); if (!ret.isOk()) { ALOGE("%s: Unable to invoke callback v2.0", __func__); } } template Return GnssTemplate::setLocation(const hidl_handle& fd, const hidl_vec& options) { auto lat = gMockLatitudeDegrees; auto lon = gMockLongitudeDegrees; auto ele = gMockAltitudeMeters; auto bea = gMockBearingDegrees; auto spd = gMockSpeedMetersPerSec; for (size_t i = 1; i < options.size(); ++i) { std::string option = options[i]; if (option.rfind("lat=", 0) == 0) { option = option.substr(4); lat = stof(option); } else if (option.rfind("lon=", 0) == 0) { option = option.substr(4); lon = stof(option); } else if (option.rfind("ele=", 0) == 0) { option = option.substr(4); ele = stof(option); } else if (option.rfind("bea=", 0) == 0) { option = option.substr(4); bea = stof(option); } else if (option.rfind("spd=", 0) == 0) { option = option.substr(4); spd = stof(option); } else { dprintf(fd->data[0], "unsupported location argument: %s\n", option.c_str()); } } gMockLatitudeDegrees = lat; gMockLongitudeDegrees = lon; gMockAltitudeMeters = ele; gMockBearingDegrees = bea; gMockSpeedMetersPerSec = spd; dprintf(fd->data[0], "mock location updated to lat=%f lon=%f ele=%f bea=%f spd=%f\n", gMockLatitudeDegrees, gMockLongitudeDegrees, gMockAltitudeMeters, gMockBearingDegrees, gMockSpeedMetersPerSec); return Void(); } template Return GnssTemplate::help(const hidl_handle& fd) { dprintf(fd->data[0], "invalid option for Gnss HAL; valid options are:\n" "location [lat=..] [lon=..] [ele=..] [bea=..] [spd=..]\n"); return Void(); } template Return GnssTemplate::debug(const hidl_handle& fd, const hidl_vec& options) { if (fd == nullptr || fd->numFds == 0) { return Void(); } if (options.size() == 0) { return help(fd); } else if (options[0] == "location") { return setLocation(fd, options); } else { return help(fd); } return Void(); } } // namespace android::hardware::gnss::common::implementation