From d6e34f7aa17ddee05d6d1d5f72bf325f8b523557 Mon Sep 17 00:00:00 2001 From: Shuzhen Wang Date: Wed, 19 Jan 2022 00:01:04 +0000 Subject: [PATCH 01/16] Camera: VTS: Remove GRF MultiCamera for Android 12 Certain OEMs' new S launches with vendor freeze cannot implement multi-camera API. Bug: 189053514 Bug: 211709637 Change-Id: I71b46f1e8343a5848cbe3fa55bbcd427c87b05dd (cherry picked from commit 30a198ded0bf3e03ac37470d8c2a58504c9b75d3) (cherry picked from commit 2b2846855fecf4d9942bbb483b15c6c493d6b8f6) --- .../VtsHalCameraProviderV2_4TargetTest.cpp | 153 ------------------ 1 file changed, 153 deletions(-) diff --git a/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp b/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp index d02547c81e..052103d784 100644 --- a/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp +++ b/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp @@ -939,7 +939,6 @@ public: void getPrivacyTestPatternModes( const camera_metadata_t* staticMetadata, std::unordered_set* privacyTestPatternModes/*out*/); - static bool isColorCamera(const camera_metadata_t *metadata); static V3_2::DataspaceFlags getDataspace(PixelFormat format); @@ -6199,141 +6198,6 @@ TEST_P(CameraHidlTest, configureInjectionStreamsWithSessionParameters) { } } -// Test the multi-camera API requirement for Google Requirement Freeze S -// Note that this requirement can only be partially tested. If a vendor -// device doesn't expose a physical camera in any shape or form, there is no way -// the test can catch it. -TEST_P(CameraHidlTest, grfSMultiCameraTest) { - const int socGrfApi = property_get_int32("ro.board.first_api_level", /*default*/ -1); - if (socGrfApi < 31 /*S*/) { - // Non-GRF devices, or version < 31 Skip - ALOGI("%s: socGrfApi level is %d. Skipping", __FUNCTION__, socGrfApi); - return; - } - - // Test that if more than one rear-facing color camera is - // supported, there must be at least one rear-facing logical camera. - hidl_vec cameraDeviceNames = getCameraDeviceNames(mProvider); - // Back facing non-logical color cameras - std::set rearColorCameras; - // Back facing logical cameras' physical camera Id sets - std::set> rearPhysicalIds; - for (const auto& name : cameraDeviceNames) { - std::string cameraId; - int deviceVersion = getCameraDeviceVersionAndId(name, mProviderType, &cameraId); - switch (deviceVersion) { - case CAMERA_DEVICE_API_VERSION_3_7: - case CAMERA_DEVICE_API_VERSION_3_6: - case CAMERA_DEVICE_API_VERSION_3_5: - case CAMERA_DEVICE_API_VERSION_3_4: - case CAMERA_DEVICE_API_VERSION_3_3: - case CAMERA_DEVICE_API_VERSION_3_2: { - ::android::sp<::android::hardware::camera::device::V3_2::ICameraDevice> device3_x; - ALOGI("getCameraCharacteristics: Testing camera device %s", name.c_str()); - Return ret; - ret = mProvider->getCameraDeviceInterface_V3_x( - name, [&](auto status, const auto& device) { - ALOGI("getCameraDeviceInterface_V3_x returns status:%d", (int)status); - ASSERT_EQ(Status::OK, status); - ASSERT_NE(device, nullptr); - device3_x = device; - }); - ASSERT_TRUE(ret.isOk()); - - ret = device3_x->getCameraCharacteristics([&](auto status, const auto& chars) { - ASSERT_EQ(Status::OK, status); - const camera_metadata_t* metadata = (camera_metadata_t*)chars.data(); - - // Skip if this is not a color camera. - if (!CameraHidlTest::isColorCamera(metadata)) { - return; - } - - // Check camera facing. Skip if facing is not BACK. - // If this is not a logical camera, only note down - // the camera ID, and skip. - camera_metadata_ro_entry entry; - int retcode = find_camera_metadata_ro_entry( - metadata, ANDROID_LENS_FACING, &entry); - ASSERT_EQ(retcode, 0); - ASSERT_GT(entry.count, 0); - uint8_t facing = entry.data.u8[0]; - bool isLogicalCamera = (isLogicalMultiCamera(metadata) == Status::OK); - if (facing != ANDROID_LENS_FACING_BACK) { - // Not BACK facing. Skip. - return; - } - if (!isLogicalCamera) { - rearColorCameras.insert(cameraId); - return; - } - - // Check logical camera's physical camera IDs for color - // cameras. - std::unordered_set physicalCameraIds; - Status s = getPhysicalCameraIds(metadata, &physicalCameraIds); - ASSERT_EQ(Status::OK, s); - rearPhysicalIds.emplace(physicalCameraIds.begin(), physicalCameraIds.end()); - for (const auto& physicalId : physicalCameraIds) { - // Skip if the physicalId is publicly available - for (auto& deviceName : cameraDeviceNames) { - std::string publicVersion, publicId; - ASSERT_TRUE(::matchDeviceName(deviceName, mProviderType, - &publicVersion, &publicId)); - if (physicalId == publicId) { - // Skip because public Ids will be iterated in outer loop. - return; - } - } - - auto castResult = device::V3_5::ICameraDevice::castFrom(device3_x); - ASSERT_TRUE(castResult.isOk()); - ::android::sp<::android::hardware::camera::device::V3_5::ICameraDevice> - device3_5 = castResult; - ASSERT_NE(device3_5, nullptr); - - // Check camera characteristics for hidden camera id - Return ret = device3_5->getPhysicalCameraCharacteristics( - physicalId, [&](auto status, const auto& chars) { - ASSERT_EQ(Status::OK, status); - const camera_metadata_t* physicalMetadata = - (camera_metadata_t*)chars.data(); - - if (CameraHidlTest::isColorCamera(physicalMetadata)) { - rearColorCameras.insert(physicalId); - } - }); - ASSERT_TRUE(ret.isOk()); - } - }); - ASSERT_TRUE(ret.isOk()); - } break; - case CAMERA_DEVICE_API_VERSION_1_0: { - // Not applicable - } break; - default: { - ALOGE("%s: Unsupported device version %d", __func__, deviceVersion); - ADD_FAILURE(); - } break; - } - } - - // If there are more than one rear-facing color camera, a logical - // multi-camera must be defined consisting of all rear-facing color - // cameras. - if (rearColorCameras.size() > 1) { - bool hasRearLogical = false; - for (const auto& physicalIds : rearPhysicalIds) { - if (std::includes(physicalIds.begin(), physicalIds.end(), - rearColorCameras.begin(), rearColorCameras.end())) { - hasRearLogical = true; - break; - } - } - ASSERT_TRUE(hasRearLogical); - } -} - // Retrieve all valid output stream resolutions from the camera // static characteristics. Status CameraHidlTest::getAvailableOutputStreams(const camera_metadata_t* staticMeta, @@ -6825,23 +6689,6 @@ Status CameraHidlTest::isMonochromeCamera(const camera_metadata_t *staticMeta) { return ret; } -bool CameraHidlTest::isColorCamera(const camera_metadata_t *metadata) { - camera_metadata_ro_entry entry; - int retcode = find_camera_metadata_ro_entry( - metadata, ANDROID_REQUEST_AVAILABLE_CAPABILITIES, &entry); - if ((0 == retcode) && (entry.count > 0)) { - bool isBackwardCompatible = (std::find(entry.data.u8, entry.data.u8 + entry.count, - ANDROID_REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE) != - entry.data.u8 + entry.count); - bool isMonochrome = (std::find(entry.data.u8, entry.data.u8 + entry.count, - ANDROID_REQUEST_AVAILABLE_CAPABILITIES_MONOCHROME) != - entry.data.u8 + entry.count); - bool isColor = isBackwardCompatible && !isMonochrome; - return isColor; - } - return false; -} - // Retrieve the reprocess input-output format map from the static // camera characteristics. Status CameraHidlTest::getZSLInputOutputMap(camera_metadata_t *staticMeta, From cb8474d7b6693f2d8f5194fd25df30394f1e2c91 Mon Sep 17 00:00:00 2001 From: Yuchen He Date: Thu, 10 Jun 2021 17:10:15 -0700 Subject: [PATCH 02/16] Refactor and reuse some read device file logic Add skeleton on HAL for Gnss raw measurement injection Bug: 190757198 Test: manual test Merged-In: I9b58043d5ed321aa71ff4f23031df251ae89c407 Change-Id: I9b58043d5ed321aa71ff4f23031df251ae89c407 --- .../aidl/default/GnssMeasurementInterface.cpp | 21 ++++- gnss/common/utils/default/Android.bp | 1 + gnss/common/utils/default/GnssReplayUtils.cpp | 88 +++++++++++++++++++ gnss/common/utils/default/include/Constants.h | 12 +++ .../utils/default/include/GnssReplayUtils.h | 54 ++++++++++++ .../utils/default/include/NmeaFixInfo.h | 7 -- .../utils/default/include/v2_1/GnssTemplate.h | 42 ++------- 7 files changed, 178 insertions(+), 47 deletions(-) create mode 100644 gnss/common/utils/default/GnssReplayUtils.cpp create mode 100644 gnss/common/utils/default/include/GnssReplayUtils.h diff --git a/gnss/aidl/default/GnssMeasurementInterface.cpp b/gnss/aidl/default/GnssMeasurementInterface.cpp index fcc1f986cc..0e489c59e4 100644 --- a/gnss/aidl/default/GnssMeasurementInterface.cpp +++ b/gnss/aidl/default/GnssMeasurementInterface.cpp @@ -19,11 +19,13 @@ #include "GnssMeasurementInterface.h" #include #include +#include "GnssReplayUtils.h" #include "Utils.h" namespace aidl::android::hardware::gnss { using Utils = ::android::hardware::gnss::common::Utils; +using ReplayUtils = ::android::hardware::gnss::common::ReplayUtils; std::shared_ptr GnssMeasurementInterface::sCallback = nullptr; @@ -63,9 +65,22 @@ void GnssMeasurementInterface::start(const bool enableCorrVecOutputs) { mIsActive = true; mThread = std::thread([this, enableCorrVecOutputs]() { while (mIsActive == true) { - auto measurement = Utils::getMockMeasurement(enableCorrVecOutputs); - this->reportMeasurement(measurement); - + std::string rawMeasurementStr = ""; + if (ReplayUtils::hasGnssDeviceFile() && + ReplayUtils::isGnssRawMeasurement( + rawMeasurementStr = ReplayUtils::getDataFromDeviceFile( + std::string( + ::android::hardware::gnss::common::CMD_GET_RAWMEASUREMENT), + mMinIntervalMillis))) { + // TODO: implement rawMeasurementStr parser and report measurement. + ALOGD("rawMeasurementStr(size: %zu) from device file: %s", rawMeasurementStr.size(), + rawMeasurementStr.c_str()); + auto measurement = Utils::getMockMeasurement(enableCorrVecOutputs); + this->reportMeasurement(measurement); + } else { + auto measurement = Utils::getMockMeasurement(enableCorrVecOutputs); + this->reportMeasurement(measurement); + } std::this_thread::sleep_for(std::chrono::milliseconds(mMinIntervalMillis)); } }); diff --git a/gnss/common/utils/default/Android.bp b/gnss/common/utils/default/Android.bp index 43db8739d1..f9225c24d0 100644 --- a/gnss/common/utils/default/Android.bp +++ b/gnss/common/utils/default/Android.bp @@ -41,6 +41,7 @@ cc_library_static { "MockLocation.cpp", "Utils.cpp", "NmeaFixInfo.cpp", + "GnssReplayUtils.cpp", ], export_include_dirs: ["include"], shared_libs: [ diff --git a/gnss/common/utils/default/GnssReplayUtils.cpp b/gnss/common/utils/default/GnssReplayUtils.cpp new file mode 100644 index 0000000000..6dcf6ea252 --- /dev/null +++ b/gnss/common/utils/default/GnssReplayUtils.cpp @@ -0,0 +1,88 @@ +/* + * Copyright (C) 2021 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. + */ + +#include "GnssReplayUtils.h" + +namespace android { +namespace hardware { +namespace gnss { +namespace common { + +const char* ReplayUtils::getGnssPath() { + const char* gnss_dev_path = GNSS_PATH; + char devname_value[PROPERTY_VALUE_MAX] = ""; + if (property_get("debug.location.gnss.devname", devname_value, NULL) > 0) { + gnss_dev_path = devname_value; + } + return gnss_dev_path; +} + +bool ReplayUtils::hasGnssDeviceFile() { + struct stat sb; + return stat(getGnssPath(), &sb) != -1; +} + +bool ReplayUtils::isGnssRawMeasurement(const std::string& inputStr) { + // TODO: add more logic check to by pass invalid data. + return !inputStr.empty() && (inputStr.find("Raw") != std::string::npos); +} + +bool ReplayUtils::isNMEA(const std::string& inputStr) { + return !inputStr.empty() && + (inputStr.rfind("$GPRMC,", 0) == 0 || inputStr.rfind("$GPRMA,", 0) == 0); +} + +std::string ReplayUtils::getDataFromDeviceFile(const std::string& command, int mMinIntervalMs) { + char inputBuffer[INPUT_BUFFER_SIZE]; + int mGnssFd = open(getGnssPath(), O_RDWR | O_NONBLOCK); + + if (mGnssFd == -1) { + return ""; + } + + int bytes_write = write(mGnssFd, command.c_str(), command.size()); + if (bytes_write <= 0) { + return ""; + } + + struct epoll_event ev, events[1]; + ev.data.fd = mGnssFd; + ev.events = EPOLLIN; + int epoll_fd = epoll_create1(0); + epoll_ctl(epoll_fd, EPOLL_CTL_ADD, mGnssFd, &ev); + int bytes_read = -1; + std::string inputStr = ""; + int epoll_ret = epoll_wait(epoll_fd, events, 1, mMinIntervalMs); + + if (epoll_ret == -1) { + return ""; + } + while (true) { + memset(inputBuffer, 0, INPUT_BUFFER_SIZE); + bytes_read = read(mGnssFd, &inputBuffer, INPUT_BUFFER_SIZE); + if (bytes_read <= 0) { + break; + } + inputStr += std::string(inputBuffer, bytes_read); + } + + return inputStr; +} + +} // namespace common +} // namespace gnss +} // namespace hardware +} // namespace android diff --git a/gnss/common/utils/default/include/Constants.h b/gnss/common/utils/default/include/Constants.h index 22afee1ad1..f205ba603c 100644 --- a/gnss/common/utils/default/include/Constants.h +++ b/gnss/common/utils/default/include/Constants.h @@ -34,6 +34,18 @@ const float kGpsL5FreqHz = 1176.45 * 1e6; const float kGloG1FreqHz = 1602.0 * 1e6; const float kIrnssL5FreqHz = 1176.45 * 1e6; +// Location replay constants +constexpr char GNSS_PATH[] = "/dev/gnss0"; +constexpr int INPUT_BUFFER_SIZE = 256; +constexpr char CMD_GET_LOCATION[] = "CMD_GET_LOCATION"; +constexpr char CMD_GET_RAWMEASUREMENT[] = "CMD_GET_RAWMEASUREMENT"; +constexpr char LINE_SEPARATOR = '\n'; +constexpr char COMMA_SEPARATOR = ','; +constexpr char GPGA_RECORD_TAG[] = "$GPGGA"; +constexpr char GPRMC_RECORD_TAG[] = "$GPRMC"; +constexpr double TIMESTAMP_EPSILON = 0.001; +constexpr int MIN_COL_NUM = 13; + } // namespace common } // namespace gnss } // namespace hardware diff --git a/gnss/common/utils/default/include/GnssReplayUtils.h b/gnss/common/utils/default/include/GnssReplayUtils.h new file mode 100644 index 0000000000..d7530f741a --- /dev/null +++ b/gnss/common/utils/default/include/GnssReplayUtils.h @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2021 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_common_GnssReplayUtils_H_ +#define android_hardware_gnss_common_GnssReplayUtils_H_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "Constants.h" + +namespace android { +namespace hardware { +namespace gnss { +namespace common { + +struct ReplayUtils { + static const char* getGnssPath(); + + static std::string getDataFromDeviceFile(const std::string& command, int mMinIntervalMs); + + static bool hasGnssDeviceFile(); + + static bool isGnssRawMeasurement(const std::string& inputStr); + + static bool isNMEA(const std::string& inputStr); +}; + +} // namespace common +} // namespace gnss +} // namespace hardware +} // namespace android + +#endif // android_hardware_gnss_common_GnssReplayUtils_H_ diff --git a/gnss/common/utils/default/include/NmeaFixInfo.h b/gnss/common/utils/default/include/NmeaFixInfo.h index c96eecea00..5c27045316 100644 --- a/gnss/common/utils/default/include/NmeaFixInfo.h +++ b/gnss/common/utils/default/include/NmeaFixInfo.h @@ -27,13 +27,6 @@ namespace hardware { namespace gnss { namespace common { -constexpr char GPGA_RECORD_TAG[] = "$GPGGA"; -constexpr char GPRMC_RECORD_TAG[] = "$GPRMC"; -constexpr char LINE_SEPARATOR = '\n'; -constexpr char COMMA_SEPARATOR = ','; -constexpr double TIMESTAMP_EPSILON = 0.001; -constexpr int MIN_COL_NUM = 13; - /** Helper class to parse and store the GNSS fix details information. */ class NmeaFixInfo { private: diff --git a/gnss/common/utils/default/include/v2_1/GnssTemplate.h b/gnss/common/utils/default/include/v2_1/GnssTemplate.h index 131af24fbe..66c23d4719 100644 --- a/gnss/common/utils/default/include/v2_1/GnssTemplate.h +++ b/gnss/common/utils/default/include/v2_1/GnssTemplate.h @@ -35,6 +35,7 @@ #include "GnssDebug.h" #include "GnssMeasurement.h" #include "GnssMeasurementCorrections.h" +#include "GnssReplayUtils.h" #include "MockLocation.h" #include "NmeaFixInfo.h" #include "Utils.h" @@ -159,15 +160,9 @@ GnssTemplate::~GnssTemplate() { template std::unique_ptr GnssTemplate::getLocationFromHW() { - char inputBuffer[INPUT_BUFFER_SIZE]; if (!mHardwareModeChecked) { - // default using gnss0 - const char * gnss_dev_path = GNSS_PATH; - char devname_value[PROPERTY_VALUE_MAX] = ""; - if (property_get("debug.location.gnss.devname", devname_value, NULL) > 0) { - gnss_dev_path = devname_value; - ALOGD("using %s instead of the default %s", gnss_dev_path, GNSS_PATH); - } + // default using /dev/gnss0 + const char* gnss_dev_path = ReplayUtils::getGnssPath(); mGnssFd = open(gnss_dev_path, O_RDWR | O_NONBLOCK); if (mGnssFd == -1) { @@ -176,35 +171,8 @@ std::unique_ptr GnssTemplate::getLocationFromHW() { mHardwareModeChecked = true; } - if (mGnssFd == -1) { - return nullptr; - } - - int bytes_write = write(mGnssFd, CMD_GET_LOCATION, strlen(CMD_GET_LOCATION)); - if (bytes_write <= 0) { - return nullptr; - } - - struct epoll_event ev, events[1]; - ev.data.fd = mGnssFd; - ev.events = EPOLLIN; - int epoll_fd = epoll_create1(0); - epoll_ctl(epoll_fd, EPOLL_CTL_ADD, mGnssFd, &ev); - int bytes_read = -1; - std::string inputStr = ""; - int epoll_ret = epoll_wait(epoll_fd, events, 1, mMinIntervalMs); - - if (epoll_ret == -1) { - return nullptr; - } - while (true) { - memset(inputBuffer, 0, INPUT_BUFFER_SIZE); - bytes_read = read(mGnssFd, &inputBuffer, INPUT_BUFFER_SIZE); - if (bytes_read <= 0) { - break; - } - inputStr += std::string(inputBuffer, bytes_read); - } + std::string inputStr = ::android::hardware::gnss::common::ReplayUtils::getDataFromDeviceFile( + CMD_GET_LOCATION, mMinIntervalMs); return NmeaFixInfo::getLocationFromInputStr(inputStr); } From 3f467bd10f520cc9d939098b5bf13058e4cdbaaa Mon Sep 17 00:00:00 2001 From: George Burgess IV Date: Wed, 7 Jul 2021 09:59:32 -0700 Subject: [PATCH 03/16] fix potential use-after-frees of stack memory `devname_value` is a local variable; if `property_get` succeeds, we'll return a pointer to it. Returning a `std::string` instead sidesteps this problem. Bug: 190757198 Test: TreeHugger Change-Id: If9ca733dd21128706f2a9f62e8460b1286631aa5 Merged-In: If9ca733dd21128706f2a9f62e8460b1286631aa5 --- gnss/common/utils/default/GnssReplayUtils.cpp | 11 +++++------ gnss/common/utils/default/include/GnssReplayUtils.h | 2 +- gnss/common/utils/default/include/v2_1/GnssTemplate.h | 6 +++--- 3 files changed, 9 insertions(+), 10 deletions(-) diff --git a/gnss/common/utils/default/GnssReplayUtils.cpp b/gnss/common/utils/default/GnssReplayUtils.cpp index 6dcf6ea252..fc4c477ae8 100644 --- a/gnss/common/utils/default/GnssReplayUtils.cpp +++ b/gnss/common/utils/default/GnssReplayUtils.cpp @@ -21,18 +21,17 @@ namespace hardware { namespace gnss { namespace common { -const char* ReplayUtils::getGnssPath() { - const char* gnss_dev_path = GNSS_PATH; +std::string ReplayUtils::getGnssPath() { char devname_value[PROPERTY_VALUE_MAX] = ""; if (property_get("debug.location.gnss.devname", devname_value, NULL) > 0) { - gnss_dev_path = devname_value; + return devname_value; } - return gnss_dev_path; + return GNSS_PATH; } bool ReplayUtils::hasGnssDeviceFile() { struct stat sb; - return stat(getGnssPath(), &sb) != -1; + return stat(getGnssPath().c_str(), &sb) != -1; } bool ReplayUtils::isGnssRawMeasurement(const std::string& inputStr) { @@ -47,7 +46,7 @@ bool ReplayUtils::isNMEA(const std::string& inputStr) { std::string ReplayUtils::getDataFromDeviceFile(const std::string& command, int mMinIntervalMs) { char inputBuffer[INPUT_BUFFER_SIZE]; - int mGnssFd = open(getGnssPath(), O_RDWR | O_NONBLOCK); + int mGnssFd = open(getGnssPath().c_str(), O_RDWR | O_NONBLOCK); if (mGnssFd == -1) { return ""; diff --git a/gnss/common/utils/default/include/GnssReplayUtils.h b/gnss/common/utils/default/include/GnssReplayUtils.h index d7530f741a..32c0e58c0c 100644 --- a/gnss/common/utils/default/include/GnssReplayUtils.h +++ b/gnss/common/utils/default/include/GnssReplayUtils.h @@ -35,7 +35,7 @@ namespace gnss { namespace common { struct ReplayUtils { - static const char* getGnssPath(); + static std::string getGnssPath(); static std::string getDataFromDeviceFile(const std::string& command, int mMinIntervalMs); diff --git a/gnss/common/utils/default/include/v2_1/GnssTemplate.h b/gnss/common/utils/default/include/v2_1/GnssTemplate.h index 66c23d4719..4e07af9853 100644 --- a/gnss/common/utils/default/include/v2_1/GnssTemplate.h +++ b/gnss/common/utils/default/include/v2_1/GnssTemplate.h @@ -162,11 +162,11 @@ template std::unique_ptr GnssTemplate::getLocationFromHW() { if (!mHardwareModeChecked) { // default using /dev/gnss0 - const char* gnss_dev_path = ReplayUtils::getGnssPath(); + std::string gnss_dev_path = ReplayUtils::getGnssPath(); - mGnssFd = open(gnss_dev_path, O_RDWR | O_NONBLOCK); + mGnssFd = open(gnss_dev_path.c_str(), O_RDWR | O_NONBLOCK); if (mGnssFd == -1) { - ALOGW("Failed to open %s errno: %d", gnss_dev_path, errno); + ALOGW("Failed to open %s errno: %d", gnss_dev_path.c_str(), errno); } mHardwareModeChecked = true; } From 31493d1dc49ae26bd3ed489ffaffaa01d3e0f0e7 Mon Sep 17 00:00:00 2001 From: Yuchen He Date: Thu, 12 Aug 2021 21:40:26 +0000 Subject: [PATCH 04/16] Add raw measurement parser Test: manual test (data cross verified with GnssLogger app) Bug: 190757198 Change-Id: I8d57826c6aa2a9d1a09b4847aadfda8c9160b36f Merged-In: I8d57826c6aa2a9d1a09b4847aadfda8c9160b36f --- gnss/common/utils/default/Android.bp | 2 + .../default/GnssRawMeasurementParser.cpp | 305 ++++++++++++++++++ gnss/common/utils/default/ParseUtils.cpp | 127 ++++++++ .../include/GnssRawMeasurementParser.h | 56 ++++ .../common/utils/default/include/ParseUtils.h | 46 +++ 5 files changed, 536 insertions(+) create mode 100644 gnss/common/utils/default/GnssRawMeasurementParser.cpp create mode 100644 gnss/common/utils/default/ParseUtils.cpp create mode 100644 gnss/common/utils/default/include/GnssRawMeasurementParser.h create mode 100644 gnss/common/utils/default/include/ParseUtils.h diff --git a/gnss/common/utils/default/Android.bp b/gnss/common/utils/default/Android.bp index f9225c24d0..188b2d28bb 100644 --- a/gnss/common/utils/default/Android.bp +++ b/gnss/common/utils/default/Android.bp @@ -42,6 +42,8 @@ cc_library_static { "Utils.cpp", "NmeaFixInfo.cpp", "GnssReplayUtils.cpp", + "ParseUtils.cpp", + "GnssRawMeasurementParser.cpp", ], export_include_dirs: ["include"], shared_libs: [ diff --git a/gnss/common/utils/default/GnssRawMeasurementParser.cpp b/gnss/common/utils/default/GnssRawMeasurementParser.cpp new file mode 100644 index 0000000000..c066229ae9 --- /dev/null +++ b/gnss/common/utils/default/GnssRawMeasurementParser.cpp @@ -0,0 +1,305 @@ +/* + * Copyright (C) 2021 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. + */ + +#include "GnssRawMeasurementParser.h" + +namespace android { +namespace hardware { +namespace gnss { +namespace common { + +using aidl::android::hardware::gnss::ElapsedRealtime; +using aidl::android::hardware::gnss::GnssClock; +using aidl::android::hardware::gnss::GnssConstellationType; +using aidl::android::hardware::gnss::GnssData; +using aidl::android::hardware::gnss::GnssMeasurement; +using aidl::android::hardware::gnss::GnssMultipathIndicator; +using aidl::android::hardware::gnss::GnssSignalType; + +using ParseUtils = ::android::hardware::gnss::common::ParseUtils; + +std::unordered_map GnssRawMeasurementParser::getColumnIdNameMappingFromHeader( + const std::string& header) { + std::vector columnNames; + std::unordered_map columnNameIdMapping; + std::string s = header; + // Trim left spaces + s.erase(s.begin(), + std::find_if(s.begin(), s.end(), [](unsigned char ch) { return !std::isspace(ch); })); + // Trim right spaces + s.erase(std::find_if(s.rbegin(), s.rend(), [](unsigned char ch) { return !std::isspace(ch); }) + .base(), + s.end()); + // Remove comment symbol, start from `Raw`. + s = s.substr(s.find("Raw")); + + ParseUtils::splitStr(s, COMMA_SEPARATOR, columnNames); + int columnId = 0; + for (auto& name : columnNames) { + columnNameIdMapping[name] = columnId++; + } + + return columnNameIdMapping; +} + +int GnssRawMeasurementParser::getClockFlags( + const std::vector& rawMeasurementRecordValues, + const std::unordered_map& columnNameIdMapping) { + int clockFlags = 0; + if (!rawMeasurementRecordValues[columnNameIdMapping.at("LeapSecond")].empty()) { + clockFlags |= GnssClock::HAS_LEAP_SECOND; + } + if (!rawMeasurementRecordValues[columnNameIdMapping.at("FullBiasNanos")].empty()) { + clockFlags |= GnssClock::HAS_FULL_BIAS; + } + if (!rawMeasurementRecordValues[columnNameIdMapping.at("BiasNanos")].empty()) { + clockFlags |= GnssClock::HAS_BIAS; + } + if (!rawMeasurementRecordValues[columnNameIdMapping.at("BiasUncertaintyNanos")].empty()) { + clockFlags |= GnssClock::HAS_BIAS_UNCERTAINTY; + } + if (!rawMeasurementRecordValues[columnNameIdMapping.at("DriftNanosPerSecond")].empty()) { + clockFlags |= GnssClock::HAS_DRIFT; + } + if (!rawMeasurementRecordValues[columnNameIdMapping.at("DriftUncertaintyNanosPerSecond")] + .empty()) { + clockFlags |= GnssClock::HAS_DRIFT_UNCERTAINTY; + } + return clockFlags; +} + +int GnssRawMeasurementParser::getElapsedRealtimeFlags( + const std::vector& rawMeasurementRecordValues, + const std::unordered_map& columnNameIdMapping) { + int elapsedRealtimeFlags = ElapsedRealtime::HAS_TIMESTAMP_NS; + if (!rawMeasurementRecordValues[columnNameIdMapping.at("TimeUncertaintyNanos")].empty()) { + elapsedRealtimeFlags |= ElapsedRealtime::HAS_TIME_UNCERTAINTY_NS; + } + return elapsedRealtimeFlags; +} + +int GnssRawMeasurementParser::getRawMeasurementFlags( + const std::vector& rawMeasurementRecordValues, + const std::unordered_map& columnNameIdMapping) { + int rawMeasurementFlags = 0; + if (!rawMeasurementRecordValues[columnNameIdMapping.at("SnrInDb")].empty()) { + rawMeasurementFlags |= GnssMeasurement::HAS_SNR; + } + if (!rawMeasurementRecordValues[columnNameIdMapping.at("CarrierFrequencyHz")].empty()) { + rawMeasurementFlags |= GnssMeasurement::HAS_CARRIER_FREQUENCY; + } + if (!rawMeasurementRecordValues[columnNameIdMapping.at("CarrierCycles")].empty()) { + rawMeasurementFlags |= GnssMeasurement::HAS_CARRIER_CYCLES; + } + if (!rawMeasurementRecordValues[columnNameIdMapping.at("CarrierPhase")].empty()) { + rawMeasurementFlags |= GnssMeasurement::HAS_CARRIER_PHASE; + } + if (!rawMeasurementRecordValues[columnNameIdMapping.at("CarrierPhaseUncertainty")].empty()) { + rawMeasurementFlags |= GnssMeasurement::HAS_CARRIER_PHASE_UNCERTAINTY; + } + if (!rawMeasurementRecordValues[columnNameIdMapping.at("AgcDb")].empty()) { + rawMeasurementFlags |= GnssMeasurement::HAS_AUTOMATIC_GAIN_CONTROL; + } + if (!rawMeasurementRecordValues[columnNameIdMapping.at("FullInterSignalBiasNanos")].empty()) { + rawMeasurementFlags |= GnssMeasurement::HAS_FULL_ISB; + } + if (!rawMeasurementRecordValues[columnNameIdMapping.at("FullInterSignalBiasUncertaintyNanos")] + .empty()) { + rawMeasurementFlags |= GnssMeasurement::HAS_FULL_ISB_UNCERTAINTY; + } + if (!rawMeasurementRecordValues[columnNameIdMapping.at("SatelliteInterSignalBiasNanos")] + .empty()) { + rawMeasurementFlags |= GnssMeasurement::HAS_SATELLITE_ISB; + } + if (!rawMeasurementRecordValues[columnNameIdMapping.at( + "SatelliteInterSignalBiasUncertaintyNanos")] + .empty()) { + rawMeasurementFlags |= GnssMeasurement::HAS_SATELLITE_ISB_UNCERTAINTY; + } + // HAS_SATELLITE_PVT and HAS_CORRELATION_VECTOR fields currently not in rawmeasurement + // output, need add them later. + return rawMeasurementFlags; +} + +GnssConstellationType GnssRawMeasurementParser::getGnssConstellationType(int constellationType) { + GnssConstellationType gnssConstellationType = + aidl::android::hardware::gnss::GnssConstellationType::UNKNOWN; + + switch (constellationType) { + case 1: + gnssConstellationType = aidl::android::hardware::gnss::GnssConstellationType::GPS; + break; + case 2: + gnssConstellationType = aidl::android::hardware::gnss::GnssConstellationType::SBAS; + break; + case 3: + gnssConstellationType = aidl::android::hardware::gnss::GnssConstellationType::GLONASS; + break; + case 4: + gnssConstellationType = aidl::android::hardware::gnss::GnssConstellationType::QZSS; + break; + case 5: + gnssConstellationType = aidl::android::hardware::gnss::GnssConstellationType::BEIDOU; + break; + case 6: + gnssConstellationType = aidl::android::hardware::gnss::GnssConstellationType::GALILEO; + break; + default: + gnssConstellationType = aidl::android::hardware::gnss::GnssConstellationType::UNKNOWN; + } + + return gnssConstellationType; +} + +std::unique_ptr GnssRawMeasurementParser::getMeasurementFromStrs( + std::string& rawMeasurementStr) { + /* + * Raw,utcTimeMillis,TimeNanos,LeapSecond,TimeUncertaintyNanos,FullBiasNanos,BiasNanos, + * BiasUncertaintyNanos,DriftNanosPerSecond,DriftUncertaintyNanosPerSecond, + * HardwareClockDiscontinuityCount,Svid,TimeOffsetNanos,State,ReceivedSvTimeNanos, + * ReceivedSvTimeUncertaintyNanos,Cn0DbHz,PseudorangeRateMetersPerSecond, + * PseudorangeRateUncertaintyMetersPerSecond,AccumulatedDeltaRangeState, + * AccumulatedDeltaRangeMeters,AccumulatedDeltaRangeUncertaintyMeters,CarrierFrequencyHz, + * CarrierCycles,CarrierPhase,CarrierPhaseUncertainty,MultipathIndicator,SnrInDb, + * ConstellationType,AgcDb,BasebandCn0DbHz,FullInterSignalBiasNanos, + * FullInterSignalBiasUncertaintyNanos,SatelliteInterSignalBiasNanos, + * SatelliteInterSignalBiasUncertaintyNanos,CodeType,ChipsetElapsedRealtimeNanos + */ + ALOGD("Parsing %zu bytes rawMeasurementStr.", rawMeasurementStr.size()); + if (rawMeasurementStr.empty()) { + return nullptr; + } + std::vector rawMeasurementStrRecords; + ParseUtils::splitStr(rawMeasurementStr, LINE_SEPARATOR, rawMeasurementStrRecords); + if (rawMeasurementStrRecords.size() <= 1) { + ALOGE("Raw GNSS Measurements parser failed. (No records) "); + return nullptr; + } + + // Get the column name mapping from the header. + std::unordered_map columnNameIdMapping = + getColumnIdNameMappingFromHeader(rawMeasurementStrRecords[0]); + + if (columnNameIdMapping.size() < 37 || !ParseUtils::isValidHeader(columnNameIdMapping)) { + ALOGE("Raw GNSS Measurements parser failed. (No header or missing columns.) "); + return nullptr; + } + + // Set GnssClock from 1st record. + std::size_t pointer = 1; + std::vector firstRecordValues; + ParseUtils::splitStr(rawMeasurementStrRecords[pointer], COMMA_SEPARATOR, firstRecordValues); + GnssClock clock = { + .gnssClockFlags = getClockFlags(firstRecordValues, columnNameIdMapping), + .timeNs = ParseUtils::tryParseLongLong( + firstRecordValues[columnNameIdMapping.at("TimeNanos")], 0), + .fullBiasNs = ParseUtils::tryParseLongLong( + firstRecordValues[columnNameIdMapping.at("FullBiasNanos")], 0), + .biasNs = ParseUtils::tryParseDouble( + firstRecordValues[columnNameIdMapping.at("BiasNanos")], 0), + .biasUncertaintyNs = ParseUtils::tryParseDouble( + firstRecordValues[columnNameIdMapping.at("BiasUncertaintyNanos")], 0), + .driftNsps = ParseUtils::tryParseDouble( + firstRecordValues[columnNameIdMapping.at("DriftNanosPerSecond")], 0), + .driftUncertaintyNsps = ParseUtils::tryParseDouble( + firstRecordValues[columnNameIdMapping.at("DriftNanosPerSecond")], 0), + .hwClockDiscontinuityCount = ParseUtils::tryParseInt( + firstRecordValues[columnNameIdMapping.at("HardwareClockDiscontinuityCount")], + 0)}; + + ElapsedRealtime timestamp = { + .flags = getElapsedRealtimeFlags(firstRecordValues, columnNameIdMapping), + .timestampNs = ParseUtils::tryParseLongLong( + firstRecordValues[columnNameIdMapping.at("ChipsetElapsedRealtimeNanos")]), + .timeUncertaintyNs = ParseUtils::tryParseDouble( + firstRecordValues[columnNameIdMapping.at("TimeUncertaintyNanos")], 0)}; + + std::vector measurementsVec; + for (pointer = 1; pointer < rawMeasurementStrRecords.size(); pointer++) { + std::vector rawMeasurementValues; + std::string line = rawMeasurementStrRecords[pointer]; + ParseUtils::splitStr(line, COMMA_SEPARATOR, rawMeasurementValues); + GnssSignalType signalType = { + .constellation = getGnssConstellationType(ParseUtils::tryParseInt( + rawMeasurementValues[columnNameIdMapping.at("ConstellationType")], 0)), + .carrierFrequencyHz = ParseUtils::tryParseDouble( + rawMeasurementValues[columnNameIdMapping.at("CarrierFrequencyHz")], 0), + .codeType = rawMeasurementValues[columnNameIdMapping.at("CodeType")], + }; + GnssMeasurement measurement = { + .flags = getRawMeasurementFlags(rawMeasurementValues, columnNameIdMapping), + .svid = ParseUtils::tryParseInt( + rawMeasurementValues[columnNameIdMapping.at("Svid")], 0), + .signalType = signalType, + .receivedSvTimeInNs = ParseUtils::tryParseLongLong( + rawMeasurementValues[columnNameIdMapping.at("ReceivedSvTimeNanos")], 0), + .receivedSvTimeUncertaintyInNs = + ParseUtils::tryParseLongLong(rawMeasurementValues[columnNameIdMapping.at( + "ReceivedSvTimeUncertaintyNanos")], + 0), + .antennaCN0DbHz = ParseUtils::tryParseDouble( + rawMeasurementValues[columnNameIdMapping.at("Cn0DbHz")], 0), + .basebandCN0DbHz = ParseUtils::tryParseDouble( + rawMeasurementValues[columnNameIdMapping.at("BasebandCn0DbHz")], 0), + .agcLevelDb = ParseUtils::tryParseDouble( + rawMeasurementValues[columnNameIdMapping.at("AgcDb")], 0), + .pseudorangeRateMps = + ParseUtils::tryParseDouble(rawMeasurementValues[columnNameIdMapping.at( + "PseudorangeRateMetersPerSecond")], + 0), + .pseudorangeRateUncertaintyMps = ParseUtils::tryParseDouble( + rawMeasurementValues[columnNameIdMapping.at( + "PseudorangeRateUncertaintyMetersPerSecond")], + 0), + .accumulatedDeltaRangeState = ParseUtils::tryParseInt( + rawMeasurementValues[columnNameIdMapping.at("AccumulatedDeltaRangeState")], + 0), + .accumulatedDeltaRangeM = ParseUtils::tryParseDouble( + rawMeasurementValues[columnNameIdMapping.at("AccumulatedDeltaRangeMeters")], + 0), + .accumulatedDeltaRangeUncertaintyM = ParseUtils::tryParseDouble( + rawMeasurementValues[columnNameIdMapping.at( + "AccumulatedDeltaRangeUncertaintyMeters")], + 0), + .multipathIndicator = GnssMultipathIndicator::UNKNOWN, // Not in GnssLogger yet. + .state = ParseUtils::tryParseInt( + rawMeasurementValues[columnNameIdMapping.at("State")], 0), + .fullInterSignalBiasNs = ParseUtils::tryParseDouble(rawMeasurementValues[31], 0), + .fullInterSignalBiasUncertaintyNs = ParseUtils::tryParseDouble( + rawMeasurementValues[columnNameIdMapping.at("FullInterSignalBiasNanos")], + 0), + .satelliteInterSignalBiasNs = + ParseUtils::tryParseDouble(rawMeasurementValues[columnNameIdMapping.at( + "SatelliteInterSignalBiasNanos")], + 0), + .satelliteInterSignalBiasUncertaintyNs = ParseUtils::tryParseDouble( + rawMeasurementValues[columnNameIdMapping.at( + "SatelliteInterSignalBiasUncertaintyNanos")], + 0), + .satellitePvt = {}, + .correlationVectors = {}}; + measurementsVec.push_back(measurement); + } + + GnssData gnssData = { + .measurements = measurementsVec, .clock = clock, .elapsedRealtime = timestamp}; + return std::make_unique(gnssData); +} + +} // namespace common +} // namespace gnss +} // namespace hardware +} // namespace android diff --git a/gnss/common/utils/default/ParseUtils.cpp b/gnss/common/utils/default/ParseUtils.cpp new file mode 100644 index 0000000000..648edf7ecd --- /dev/null +++ b/gnss/common/utils/default/ParseUtils.cpp @@ -0,0 +1,127 @@ +/* + * Copyright (C) 2021 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. + */ + +#include +#include +#include + +namespace android { +namespace hardware { +namespace gnss { +namespace common { + +int ParseUtils::tryParseInt(const std::string& s, int defaultVal) { + if (s.empty()) { + return defaultVal; + } else { + return std::stoi(s); + } +} + +float ParseUtils::tryParsefloat(const std::string& s, float defaultVal) { + if (s.empty()) { + return defaultVal; + } else { + return std::stof(s); + } +} + +double ParseUtils::tryParseDouble(const std::string& s, double defaultVal) { + if (s.empty()) { + return defaultVal; + } else { + return std::stod(s); + } +} + +long ParseUtils::tryParseLong(const std::string& s, long defaultVal) { + if (s.empty()) { + return defaultVal; + } else { + return std::stol(s); + } +} + +long long ParseUtils::tryParseLongLong(const std::string& s, long long defaultVal) { + if (s.empty()) { + return defaultVal; + } else { + return std::stoll(s); + } +} + +void ParseUtils::splitStr(const std::string& line, const char& delimiter, + std::vector& out) { + std::istringstream iss(line); + std::string item; + while (std::getline(iss, item, delimiter)) { + out.push_back(item); + } +} + +bool ParseUtils::isValidHeader(const std::unordered_map& columnNameIdMapping) { + std::vector requiredHeaderColumns = {"Raw", + "utcTimeMillis", + "TimeNanos", + "LeapSecond", + "TimeUncertaintyNanos", + "FullBiasNanos", + "BiasNanos", + "BiasUncertaintyNanos", + "DriftNanosPerSecond", + "DriftUncertaintyNanosPerSecond", + "HardwareClockDiscontinuityCount", + "Svid", + "TimeOffsetNanos", + "State", + "ReceivedSvTimeNanos", + "ReceivedSvTimeUncertaintyNanos", + "Cn0DbHz", + "PseudorangeRateMetersPerSecond", + "PseudorangeRateUncertaintyMetersPerSecond", + "AccumulatedDeltaRangeState", + "AccumulatedDeltaRangeMeters", + "AccumulatedDeltaRangeUncertaintyMeters", + "CarrierFrequencyHz", + "CarrierCycles", + "CarrierPhase", + "CarrierPhaseUncertainty", + "MultipathIndicator", + "SnrInDb", + "ConstellationType", + "AgcDb", + "BasebandCn0DbHz", + "FullInterSignalBiasNanos", + "FullInterSignalBiasUncertaintyNanos", + "SatelliteInterSignalBiasNanos", + "SatelliteInterSignalBiasUncertaintyNanos", + "CodeType", + "ChipsetElapsedRealtimeNanos"}; + + for (const auto& columnName : requiredHeaderColumns) { + if (columnNameIdMapping.find(columnName) == columnNameIdMapping.end()) { + ALOGE("Missing column %s in header.", columnName.c_str()); + return false; + } + } + + return true; +} + +} // namespace common +} // namespace gnss +} // namespace hardware +} // namespace android diff --git a/gnss/common/utils/default/include/GnssRawMeasurementParser.h b/gnss/common/utils/default/include/GnssRawMeasurementParser.h new file mode 100644 index 0000000000..7d6b4efdd1 --- /dev/null +++ b/gnss/common/utils/default/include/GnssRawMeasurementParser.h @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2021 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_common_default_GnssRawMeasurementParser_H_ +#define android_hardware_gnss_common_default_GnssRawMeasurementParser_H_ + +#include +#include +#include +#include +#include + +#include "Constants.h" +#include "ParseUtils.h" + +namespace android { +namespace hardware { +namespace gnss { +namespace common { + +struct GnssRawMeasurementParser { + static std::unique_ptr getMeasurementFromStrs( + std::string& rawMeasurementStr); + static int getClockFlags(const std::vector& rawMeasurementRecordValues, + const std::unordered_map& columnNameIdMapping); + static int getElapsedRealtimeFlags( + const std::vector& rawMeasurementRecordValues, + const std::unordered_map& columnNameIdMapping); + static int getRawMeasurementFlags( + const std::vector& rawMeasurementRecordValues, + const std::unordered_map& columnNameIdMapping); + static std::unordered_map getColumnIdNameMappingFromHeader( + const std::string& header); + static aidl::android::hardware::gnss::GnssConstellationType getGnssConstellationType( + int constellationType); +}; + +} // namespace common +} // namespace gnss +} // namespace hardware +} // namespace android + +#endif // android_hardware_gnss_common_default_GnssRawMeasurementParser_H_ \ No newline at end of file diff --git a/gnss/common/utils/default/include/ParseUtils.h b/gnss/common/utils/default/include/ParseUtils.h new file mode 100644 index 0000000000..3a5631342e --- /dev/null +++ b/gnss/common/utils/default/include/ParseUtils.h @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2021 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_common_default_ParseUtils_H_ +#define android_hardware_gnss_common_default_ParseUtils_H_ + +#include +#include +#include +#include + +namespace android { +namespace hardware { +namespace gnss { +namespace common { + +struct ParseUtils { + static int tryParseInt(const std::string& s, int defaultVal = 0); + static float tryParsefloat(const std::string& s, float defaultVal = 0.0); + static double tryParseDouble(const std::string& s, double defaultVal = 0.0); + static long tryParseLong(const std::string& s, long defaultVal = 0); + static long long tryParseLongLong(const std::string& s, long long defaultVal = 0); + static void splitStr(const std::string& line, const char& delimiter, + std::vector& out); + static bool isValidHeader(const std::unordered_map& columnNameIdMapping); +}; + +} // namespace common +} // namespace gnss +} // namespace hardware +} // namespace android + +#endif // android_hardware_gnss_common_default_ParseUtils_H_ \ No newline at end of file From 65569272ad5cef751b23db89db799305938027d1 Mon Sep 17 00:00:00 2001 From: Yuchen He Date: Mon, 30 Aug 2021 22:20:30 +0000 Subject: [PATCH 05/16] Read GNSS measurement from device file when available Test: atest CtsLocationGnssTestCases GtsLocationTestCases on CF Bug: 190757198 Change-Id: Ic03d56a5df6b99f7b20c5840e7091ead138316b1 Merged-In: Ic03d56a5df6b99f7b20c5840e7091ead138316b1 --- .../aidl/default/GnssMeasurementInterface.cpp | 18 ++-- gnss/common/utils/default/Android.bp | 11 ++- .../common/utils/default/DeviceFileReader.cpp | 97 +++++++++++++++++++ gnss/common/utils/default/GnssReplayUtils.cpp | 41 +------- .../utils/default/include/DeviceFileReader.h | 53 ++++++++++ .../utils/default/include/v2_1/GnssTemplate.h | 17 +--- 6 files changed, 173 insertions(+), 64 deletions(-) create mode 100644 gnss/common/utils/default/DeviceFileReader.cpp create mode 100644 gnss/common/utils/default/include/DeviceFileReader.h diff --git a/gnss/aidl/default/GnssMeasurementInterface.cpp b/gnss/aidl/default/GnssMeasurementInterface.cpp index 0e489c59e4..9e4f7c7f25 100644 --- a/gnss/aidl/default/GnssMeasurementInterface.cpp +++ b/gnss/aidl/default/GnssMeasurementInterface.cpp @@ -19,6 +19,8 @@ #include "GnssMeasurementInterface.h" #include #include +#include "DeviceFileReader.h" +#include "GnssRawMeasurementParser.h" #include "GnssReplayUtils.h" #include "Utils.h" @@ -26,6 +28,8 @@ namespace aidl::android::hardware::gnss { using Utils = ::android::hardware::gnss::common::Utils; using ReplayUtils = ::android::hardware::gnss::common::ReplayUtils; +using GnssRawMeasurementParser = ::android::hardware::gnss::common::GnssRawMeasurementParser; +using DeviceFileReader = ::android::hardware::gnss::common::DeviceFileReader; std::shared_ptr GnssMeasurementInterface::sCallback = nullptr; @@ -68,15 +72,15 @@ void GnssMeasurementInterface::start(const bool enableCorrVecOutputs) { std::string rawMeasurementStr = ""; if (ReplayUtils::hasGnssDeviceFile() && ReplayUtils::isGnssRawMeasurement( - rawMeasurementStr = ReplayUtils::getDataFromDeviceFile( - std::string( - ::android::hardware::gnss::common::CMD_GET_RAWMEASUREMENT), - mMinIntervalMillis))) { - // TODO: implement rawMeasurementStr parser and report measurement. + rawMeasurementStr = + DeviceFileReader::Instance().getGnssRawMeasurementData())) { ALOGD("rawMeasurementStr(size: %zu) from device file: %s", rawMeasurementStr.size(), rawMeasurementStr.c_str()); - auto measurement = Utils::getMockMeasurement(enableCorrVecOutputs); - this->reportMeasurement(measurement); + auto measurement = + GnssRawMeasurementParser::getMeasurementFromStrs(rawMeasurementStr); + if (measurement != nullptr) { + this->reportMeasurement(*measurement); + } } else { auto measurement = Utils::getMockMeasurement(enableCorrVecOutputs); this->reportMeasurement(measurement); diff --git a/gnss/common/utils/default/Android.bp b/gnss/common/utils/default/Android.bp index 188b2d28bb..ea445a276a 100644 --- a/gnss/common/utils/default/Android.bp +++ b/gnss/common/utils/default/Android.bp @@ -38,12 +38,13 @@ cc_library_static { "v2_1/GnssDebug.cpp", "v2_1/GnssMeasurement.cpp", "v2_1/GnssMeasurementCorrections.cpp", - "MockLocation.cpp", - "Utils.cpp", - "NmeaFixInfo.cpp", - "GnssReplayUtils.cpp", - "ParseUtils.cpp", + "DeviceFileReader.cpp", "GnssRawMeasurementParser.cpp", + "GnssReplayUtils.cpp", + "MockLocation.cpp", + "NmeaFixInfo.cpp", + "ParseUtils.cpp", + "Utils.cpp", ], export_include_dirs: ["include"], shared_libs: [ diff --git a/gnss/common/utils/default/DeviceFileReader.cpp b/gnss/common/utils/default/DeviceFileReader.cpp new file mode 100644 index 0000000000..7d4fb04339 --- /dev/null +++ b/gnss/common/utils/default/DeviceFileReader.cpp @@ -0,0 +1,97 @@ +/* + * Copyright (C) 2021 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. + */ +#include "DeviceFileReader.h" + +namespace android { +namespace hardware { +namespace gnss { +namespace common { + +void DeviceFileReader::getDataFromDeviceFile(const std::string& command, int mMinIntervalMs) { + char inputBuffer[INPUT_BUFFER_SIZE]; + int mGnssFd = open(ReplayUtils::getGnssPath().c_str(), + O_RDWR | O_NONBLOCK); + + if (mGnssFd == -1) { + return; + } + + int bytes_write = write(mGnssFd, command.c_str(), command.size()); + if (bytes_write <= 0) { + close(mGnssFd); + return; + } + + struct epoll_event ev, events[1]; + ev.data.fd = mGnssFd; + ev.events = EPOLLIN; + int epoll_fd = epoll_create1(0); + epoll_ctl(epoll_fd, EPOLL_CTL_ADD, mGnssFd, &ev); + int bytes_read = -1; + std::string inputStr = ""; + int epoll_ret = epoll_wait(epoll_fd, events, 1, mMinIntervalMs); + + if (epoll_ret == -1) { + close(mGnssFd); + return; + } + while (true) { + memset(inputBuffer, 0, INPUT_BUFFER_SIZE); + bytes_read = read(mGnssFd, &inputBuffer, INPUT_BUFFER_SIZE); + if (bytes_read <= 0) { + break; + } + s_buffer_ += std::string(inputBuffer, bytes_read); + } + close(mGnssFd); + + // Trim end of file mark(\n\n\n\n). + auto pos = s_buffer_.find("\n\n\n\n"); + if (pos != std::string::npos) { + inputStr = s_buffer_.substr(0, pos); + s_buffer_ = s_buffer_.substr(pos + 4); + } else { + return; + } + + // Cache the injected data. + if (ReplayUtils::isGnssRawMeasurement(inputStr)) { + data_[CMD_GET_RAWMEASUREMENT] = inputStr; + } else if (ReplayUtils::isNMEA(inputStr)) { + data_[CMD_GET_LOCATION] = inputStr; + } +} + +std::string DeviceFileReader::getLocationData() { + std::unique_lock lock(mMutex); + getDataFromDeviceFile(CMD_GET_LOCATION, 20); + return data_[CMD_GET_LOCATION]; +} + +std::string DeviceFileReader::getGnssRawMeasurementData() { + std::unique_lock lock(mMutex); + getDataFromDeviceFile(CMD_GET_RAWMEASUREMENT, 20); + return data_[CMD_GET_RAWMEASUREMENT]; +} + +DeviceFileReader::DeviceFileReader() {} + +DeviceFileReader::~DeviceFileReader() {} + +} // namespace common +} // namespace gnss +} // namespace hardware +} // namespace android diff --git a/gnss/common/utils/default/GnssReplayUtils.cpp b/gnss/common/utils/default/GnssReplayUtils.cpp index fc4c477ae8..e3f4ff82a0 100644 --- a/gnss/common/utils/default/GnssReplayUtils.cpp +++ b/gnss/common/utils/default/GnssReplayUtils.cpp @@ -40,45 +40,8 @@ bool ReplayUtils::isGnssRawMeasurement(const std::string& inputStr) { } bool ReplayUtils::isNMEA(const std::string& inputStr) { - return !inputStr.empty() && - (inputStr.rfind("$GPRMC,", 0) == 0 || inputStr.rfind("$GPRMA,", 0) == 0); -} - -std::string ReplayUtils::getDataFromDeviceFile(const std::string& command, int mMinIntervalMs) { - char inputBuffer[INPUT_BUFFER_SIZE]; - int mGnssFd = open(getGnssPath().c_str(), O_RDWR | O_NONBLOCK); - - if (mGnssFd == -1) { - return ""; - } - - int bytes_write = write(mGnssFd, command.c_str(), command.size()); - if (bytes_write <= 0) { - return ""; - } - - struct epoll_event ev, events[1]; - ev.data.fd = mGnssFd; - ev.events = EPOLLIN; - int epoll_fd = epoll_create1(0); - epoll_ctl(epoll_fd, EPOLL_CTL_ADD, mGnssFd, &ev); - int bytes_read = -1; - std::string inputStr = ""; - int epoll_ret = epoll_wait(epoll_fd, events, 1, mMinIntervalMs); - - if (epoll_ret == -1) { - return ""; - } - while (true) { - memset(inputBuffer, 0, INPUT_BUFFER_SIZE); - bytes_read = read(mGnssFd, &inputBuffer, INPUT_BUFFER_SIZE); - if (bytes_read <= 0) { - break; - } - inputStr += std::string(inputBuffer, bytes_read); - } - - return inputStr; + return !inputStr.empty() && (inputStr.find("$GPRMC,", 0) != std::string::npos || + inputStr.find("$GPRMA,", 0) != std::string::npos); } } // namespace common diff --git a/gnss/common/utils/default/include/DeviceFileReader.h b/gnss/common/utils/default/include/DeviceFileReader.h new file mode 100644 index 0000000000..c2a5c5f59b --- /dev/null +++ b/gnss/common/utils/default/include/DeviceFileReader.h @@ -0,0 +1,53 @@ + +/* + * Copyright (C) 2021 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_common_default_DeviceFileReader_H_ +#define android_hardware_gnss_common_default_DeviceFileReader_H_ + +#include +#include +#include +#include +#include "Constants.h" +#include "GnssReplayUtils.h" + +namespace android { +namespace hardware { +namespace gnss { +namespace common { +class DeviceFileReader { + public: + static DeviceFileReader& Instance() { + static DeviceFileReader reader; + return reader; + } + std::string getLocationData(); + std::string getGnssRawMeasurementData(); + void getDataFromDeviceFile(const std::string& command, int mMinIntervalMs); + + private: + DeviceFileReader(); + ~DeviceFileReader(); + std::unordered_map data_; + std::string s_buffer_; + std::mutex mMutex; +}; +} // namespace common +} // namespace gnss +} // namespace hardware +} // namespace android + +#endif // android_hardware_gnss_common_default_DeviceFileReader_H_ \ No newline at end of file diff --git a/gnss/common/utils/default/include/v2_1/GnssTemplate.h b/gnss/common/utils/default/include/v2_1/GnssTemplate.h index 4e07af9853..6950cf8f85 100644 --- a/gnss/common/utils/default/include/v2_1/GnssTemplate.h +++ b/gnss/common/utils/default/include/v2_1/GnssTemplate.h @@ -30,6 +30,7 @@ #include +#include "DeviceFileReader.h" #include "GnssAntennaInfo.h" #include "GnssConfiguration.h" #include "GnssDebug.h" @@ -160,19 +161,9 @@ GnssTemplate::~GnssTemplate() { template std::unique_ptr GnssTemplate::getLocationFromHW() { - if (!mHardwareModeChecked) { - // default using /dev/gnss0 - std::string gnss_dev_path = ReplayUtils::getGnssPath(); - - mGnssFd = open(gnss_dev_path.c_str(), O_RDWR | O_NONBLOCK); - if (mGnssFd == -1) { - ALOGW("Failed to open %s errno: %d", gnss_dev_path.c_str(), errno); - } - mHardwareModeChecked = true; - } - - std::string inputStr = ::android::hardware::gnss::common::ReplayUtils::getDataFromDeviceFile( - CMD_GET_LOCATION, mMinIntervalMs); + mHardwareModeChecked = true; + std::string inputStr = + ::android::hardware::gnss::common::DeviceFileReader::Instance().getLocationData(); return NmeaFixInfo::getLocationFromInputStr(inputStr); } From d20063ad90c1ab55c532ce0a51ba2a499c4c33dd Mon Sep 17 00:00:00 2001 From: Yuchen He Date: Mon, 11 Oct 2021 21:15:20 +0000 Subject: [PATCH 06/16] Merge fix to AOSP: Report default location when location is not available in /dev/gnss0 Change-Id: I3ce672aa1a7a39c256dd1396658859c205b61399 Merged-In: I3ce672aa1a7a39c256dd1396658859c205b61399 Test: atest VtsHalGnssTargetTest Bug: 197579774 --- gnss/common/utils/default/include/v2_1/GnssTemplate.h | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/gnss/common/utils/default/include/v2_1/GnssTemplate.h b/gnss/common/utils/default/include/v2_1/GnssTemplate.h index 6950cf8f85..fbf04b3c41 100644 --- a/gnss/common/utils/default/include/v2_1/GnssTemplate.h +++ b/gnss/common/utils/default/include/v2_1/GnssTemplate.h @@ -182,14 +182,8 @@ Return GnssTemplate::start() { this->reportSvStatus(svStatus); auto currentLocation = getLocationFromHW(); notePowerConsumption(); - if (mGnssFd != -1) { - // Only report location if the return from hardware is valid - // note that we can not merge these two "if" together, if didn't - // get location from hardware, we shouldn't report location, not - // report the "default" one. - if (currentLocation != nullptr) { - this->reportLocation(*currentLocation); - } + if (currentLocation != nullptr) { + this->reportLocation(*currentLocation); } else { if (sGnssCallback_2_1 != nullptr || sGnssCallback_2_0 != nullptr) { const auto location = Utils::getMockLocationV2_0(); From be47920e9ff70fcf5b372c7cd149ba78a127554a Mon Sep 17 00:00:00 2001 From: Yuchen He Date: Thu, 13 Jan 2022 18:39:50 +0000 Subject: [PATCH 07/16] Add parser to support CSV location data Bug: 213225295 Test: launch_cvd -cpus 16 -memory_mb 16192 --start_gnss_proxy --gnss_file_path=/google/data/rw/users/yu/yuchenhe/input.txt (Running blue dot in Google Maps) Almost a cherry-pick but changed the data type from AIDL GnssLocation to the HIDL type, since there are no AIDL GnssLocation Type in SC-V2. Merged-In: I572315888c2f57ce701e695acb03aa6b28787f31 Change-Id: I572315888c2f57ce701e695acb03aa6b28787f31 --- gnss/common/utils/default/Android.bp | 1 + .../utils/default/FixLocationParser.cpp | 76 +++++++++++++++++++ .../utils/default/include/FixLocationParser.h | 47 ++++++++++++ 3 files changed, 124 insertions(+) create mode 100644 gnss/common/utils/default/FixLocationParser.cpp create mode 100644 gnss/common/utils/default/include/FixLocationParser.h diff --git a/gnss/common/utils/default/Android.bp b/gnss/common/utils/default/Android.bp index ea445a276a..bdb1569105 100644 --- a/gnss/common/utils/default/Android.bp +++ b/gnss/common/utils/default/Android.bp @@ -39,6 +39,7 @@ cc_library_static { "v2_1/GnssMeasurement.cpp", "v2_1/GnssMeasurementCorrections.cpp", "DeviceFileReader.cpp", + "FixLocationParser.cpp", "GnssRawMeasurementParser.cpp", "GnssReplayUtils.cpp", "MockLocation.cpp", diff --git a/gnss/common/utils/default/FixLocationParser.cpp b/gnss/common/utils/default/FixLocationParser.cpp new file mode 100644 index 0000000000..f0177b49c5 --- /dev/null +++ b/gnss/common/utils/default/FixLocationParser.cpp @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2022 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. + */ + +#include "FixLocationParser.h" + +#include + +namespace android { +namespace hardware { +namespace gnss { +namespace common { + +std::unique_ptr FixLocationParser::getLocationFromInputStr( + const std::string& locationStr) { + /* + * Fix,Provider,LatitudeDegrees,LongitudeDegrees,AltitudeMeters,SpeedMps, + * AccuracyMeters,BearingDegrees,UnixTimeMillis,SpeedAccuracyMps,BearingAccuracyDegrees, + * elapsedRealtimeNanos + */ + if (locationStr.empty()) { + return nullptr; + } + std::vector locationStrRecords; + ParseUtils::splitStr(locationStr, LINE_SEPARATOR, locationStrRecords); + if (locationStrRecords.empty()) { + return nullptr; + } + + std::vector locationValues; + ParseUtils::splitStr(locationStrRecords[0], COMMA_SEPARATOR, locationValues); + if (locationValues.size() < 12) { + return nullptr; + } + V2_0::ElapsedRealtime elapsedRealtime = { + .flags = V2_0::ElapsedRealtimeFlags::HAS_TIMESTAMP_NS | + V2_0::ElapsedRealtimeFlags::HAS_TIME_UNCERTAINTY_NS, + .timestampNs = static_cast(::android::elapsedRealtimeNano()), + // This is an hardcoded value indicating a 1ms of uncertainty between the two clocks. + // In an actual implementation provide an estimate of the synchronization uncertainty + // or don't set the field. + .timeUncertaintyNs = 1020400}; + + V1_0::GnssLocation locationV1 = { + .gnssLocationFlags = 0xFF, + .latitudeDegrees = ParseUtils::tryParseDouble(locationValues[2], 0), + .longitudeDegrees = ParseUtils::tryParseDouble(locationValues[3], 0), + .altitudeMeters = ParseUtils::tryParseDouble(locationValues[4], 0), + .speedMetersPerSec = ParseUtils::tryParsefloat(locationValues[5], 0), + .bearingDegrees = ParseUtils::tryParsefloat(locationValues[7], 0), + .horizontalAccuracyMeters = ParseUtils::tryParsefloat(locationValues[6], 0), + .verticalAccuracyMeters = ParseUtils::tryParsefloat(locationValues[6], 0), + .speedAccuracyMetersPerSecond = ParseUtils::tryParsefloat(locationValues[9], 0), + .bearingAccuracyDegrees = ParseUtils::tryParsefloat(locationValues[10], 0), + .timestamp = ParseUtils::tryParseLongLong(locationValues[8], 0)}; + + V2_0::GnssLocation locationV2 = {.v1_0 = locationV1, .elapsedRealtime = elapsedRealtime}; + return std::make_unique(locationV2); +} + +} // namespace common +} // namespace gnss +} // namespace hardware +} // namespace android diff --git a/gnss/common/utils/default/include/FixLocationParser.h b/gnss/common/utils/default/include/FixLocationParser.h new file mode 100644 index 0000000000..19748a9dd1 --- /dev/null +++ b/gnss/common/utils/default/include/FixLocationParser.h @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2022 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_common_default_FixLocationParser_H_ +#define android_hardware_gnss_common_default_FixLocationParser_H_ + +#include + +#include +#include +#include + +#include +#include +#include +#include "Constants.h" +#include "ParseUtils.h" + +namespace android { +namespace hardware { +namespace gnss { +namespace common { + +struct FixLocationParser { + public: + static std::unique_ptr getLocationFromInputStr(const std::string& inputStr); +}; + +} // namespace common +} // namespace gnss +} // namespace hardware +} // namespace android + +#endif // android_hardware_gnss_common_default_FixLocationParser_H_ From 55c22f897eafc6eb0177bc5e93cd8f86fa4dcd95 Mon Sep 17 00:00:00 2001 From: Yuchen He Date: Thu, 20 Jan 2022 22:57:09 +0000 Subject: [PATCH 08/16] Supported synchronized fixed location and measurement from device files Replace NMEA by one row fixed location data Test: atest VtsHalGnssTargetTest Test: launch_cvd -cpus 16 -memory_mb 16192 --start_gnss_proxy --gnss_file_path=/usr/local/google/home/yuchenhe/Downloads/raw.txt --fixed_location_file_path=/google/data/rw/users/yu/yuchenhe/input.txt Bug: 213225295 Merged-In: Ide7bbb3e81a90414496084691227bd95a2e7af18 Change-Id: Ide7bbb3e81a90414496084691227bd95a2e7af18 --- .../common/utils/default/DeviceFileReader.cpp | 22 ++++++++++++++----- gnss/common/utils/default/GnssReplayUtils.cpp | 13 +++++++++++ gnss/common/utils/default/include/Constants.h | 1 + .../utils/default/include/GnssReplayUtils.h | 4 ++++ .../utils/default/include/v2_1/GnssTemplate.h | 7 ++++-- 5 files changed, 40 insertions(+), 7 deletions(-) diff --git a/gnss/common/utils/default/DeviceFileReader.cpp b/gnss/common/utils/default/DeviceFileReader.cpp index 7d4fb04339..dfc086a8b8 100644 --- a/gnss/common/utils/default/DeviceFileReader.cpp +++ b/gnss/common/utils/default/DeviceFileReader.cpp @@ -22,8 +22,17 @@ namespace common { void DeviceFileReader::getDataFromDeviceFile(const std::string& command, int mMinIntervalMs) { char inputBuffer[INPUT_BUFFER_SIZE]; - int mGnssFd = open(ReplayUtils::getGnssPath().c_str(), - O_RDWR | O_NONBLOCK); + std::string deviceFilePath = ""; + if (command == CMD_GET_LOCATION) { + deviceFilePath = ReplayUtils::getFixedLocationPath(); + } else if (command == CMD_GET_RAWMEASUREMENT) { + deviceFilePath = ReplayUtils::getGnssPath(); + } else { + // Invalid command + return; + } + + int mGnssFd = open(deviceFilePath.c_str(), O_RDWR | O_NONBLOCK); if (mGnssFd == -1) { return; @@ -68,10 +77,13 @@ void DeviceFileReader::getDataFromDeviceFile(const std::string& command, int mMi } // Cache the injected data. - if (ReplayUtils::isGnssRawMeasurement(inputStr)) { - data_[CMD_GET_RAWMEASUREMENT] = inputStr; - } else if (ReplayUtils::isNMEA(inputStr)) { + if (command == CMD_GET_LOCATION) { + // TODO validate data data_[CMD_GET_LOCATION] = inputStr; + } else if (command == CMD_GET_RAWMEASUREMENT) { + if (ReplayUtils::isGnssRawMeasurement(inputStr)) { + data_[CMD_GET_RAWMEASUREMENT] = inputStr; + } } } diff --git a/gnss/common/utils/default/GnssReplayUtils.cpp b/gnss/common/utils/default/GnssReplayUtils.cpp index e3f4ff82a0..b27943e6ed 100644 --- a/gnss/common/utils/default/GnssReplayUtils.cpp +++ b/gnss/common/utils/default/GnssReplayUtils.cpp @@ -29,11 +29,24 @@ std::string ReplayUtils::getGnssPath() { return GNSS_PATH; } +std::string ReplayUtils::getFixedLocationPath() { + char devname_value[PROPERTY_VALUE_MAX] = ""; + if (property_get("debug.location.fixedlocation.devname", devname_value, NULL) > 0) { + return devname_value; + } + return FIXED_LOCATION_PATH; +} + bool ReplayUtils::hasGnssDeviceFile() { struct stat sb; return stat(getGnssPath().c_str(), &sb) != -1; } +bool ReplayUtils::hasFixedLocationDeviceFile() { + struct stat sb; + return stat(getFixedLocationPath().c_str(), &sb) != -1; +} + bool ReplayUtils::isGnssRawMeasurement(const std::string& inputStr) { // TODO: add more logic check to by pass invalid data. return !inputStr.empty() && (inputStr.find("Raw") != std::string::npos); diff --git a/gnss/common/utils/default/include/Constants.h b/gnss/common/utils/default/include/Constants.h index f205ba603c..489413e21d 100644 --- a/gnss/common/utils/default/include/Constants.h +++ b/gnss/common/utils/default/include/Constants.h @@ -36,6 +36,7 @@ const float kIrnssL5FreqHz = 1176.45 * 1e6; // Location replay constants constexpr char GNSS_PATH[] = "/dev/gnss0"; +constexpr char FIXED_LOCATION_PATH[] = "/dev/gnss1"; constexpr int INPUT_BUFFER_SIZE = 256; constexpr char CMD_GET_LOCATION[] = "CMD_GET_LOCATION"; constexpr char CMD_GET_RAWMEASUREMENT[] = "CMD_GET_RAWMEASUREMENT"; diff --git a/gnss/common/utils/default/include/GnssReplayUtils.h b/gnss/common/utils/default/include/GnssReplayUtils.h index 32c0e58c0c..d1bbed4b41 100644 --- a/gnss/common/utils/default/include/GnssReplayUtils.h +++ b/gnss/common/utils/default/include/GnssReplayUtils.h @@ -37,10 +37,14 @@ namespace common { struct ReplayUtils { static std::string getGnssPath(); + static std::string getFixedLocationPath(); + static std::string getDataFromDeviceFile(const std::string& command, int mMinIntervalMs); static bool hasGnssDeviceFile(); + static bool hasFixedLocationDeviceFile(); + static bool isGnssRawMeasurement(const std::string& inputStr); static bool isNMEA(const std::string& inputStr); diff --git a/gnss/common/utils/default/include/v2_1/GnssTemplate.h b/gnss/common/utils/default/include/v2_1/GnssTemplate.h index fbf04b3c41..473e587762 100644 --- a/gnss/common/utils/default/include/v2_1/GnssTemplate.h +++ b/gnss/common/utils/default/include/v2_1/GnssTemplate.h @@ -31,6 +31,7 @@ #include #include "DeviceFileReader.h" +#include "FixLocationParser.h" #include "GnssAntennaInfo.h" #include "GnssConfiguration.h" #include "GnssDebug.h" @@ -38,7 +39,6 @@ #include "GnssMeasurementCorrections.h" #include "GnssReplayUtils.h" #include "MockLocation.h" -#include "NmeaFixInfo.h" #include "Utils.h" namespace android::hardware::gnss::common::implementation { @@ -162,9 +162,12 @@ GnssTemplate::~GnssTemplate() { template std::unique_ptr GnssTemplate::getLocationFromHW() { mHardwareModeChecked = true; + if (!ReplayUtils::hasFixedLocationDeviceFile()) { + return nullptr; + } std::string inputStr = ::android::hardware::gnss::common::DeviceFileReader::Instance().getLocationData(); - return NmeaFixInfo::getLocationFromInputStr(inputStr); + return FixLocationParser::getLocationFromInputStr(inputStr); } template From 95276a229b6abfe8111e6b92b9ca8f3043ec0515 Mon Sep 17 00:00:00 2001 From: Yuchen He Date: Thu, 10 Jun 2021 17:10:15 -0700 Subject: [PATCH 09/16] Refactor and reuse some read device file logic Add skeleton on HAL for Gnss raw measurement injection Bug: 190757198 Test: manual test Merged-In: I9b58043d5ed321aa71ff4f23031df251ae89c407 Change-Id: I9b58043d5ed321aa71ff4f23031df251ae89c407 --- .../aidl/default/GnssMeasurementInterface.cpp | 21 ++++- gnss/common/utils/default/Android.bp | 1 + gnss/common/utils/default/GnssReplayUtils.cpp | 88 +++++++++++++++++++ gnss/common/utils/default/include/Constants.h | 12 +++ .../utils/default/include/GnssReplayUtils.h | 54 ++++++++++++ .../utils/default/include/NmeaFixInfo.h | 7 -- .../utils/default/include/v2_1/GnssTemplate.h | 42 ++------- 7 files changed, 178 insertions(+), 47 deletions(-) create mode 100644 gnss/common/utils/default/GnssReplayUtils.cpp create mode 100644 gnss/common/utils/default/include/GnssReplayUtils.h diff --git a/gnss/aidl/default/GnssMeasurementInterface.cpp b/gnss/aidl/default/GnssMeasurementInterface.cpp index fcc1f986cc..0e489c59e4 100644 --- a/gnss/aidl/default/GnssMeasurementInterface.cpp +++ b/gnss/aidl/default/GnssMeasurementInterface.cpp @@ -19,11 +19,13 @@ #include "GnssMeasurementInterface.h" #include #include +#include "GnssReplayUtils.h" #include "Utils.h" namespace aidl::android::hardware::gnss { using Utils = ::android::hardware::gnss::common::Utils; +using ReplayUtils = ::android::hardware::gnss::common::ReplayUtils; std::shared_ptr GnssMeasurementInterface::sCallback = nullptr; @@ -63,9 +65,22 @@ void GnssMeasurementInterface::start(const bool enableCorrVecOutputs) { mIsActive = true; mThread = std::thread([this, enableCorrVecOutputs]() { while (mIsActive == true) { - auto measurement = Utils::getMockMeasurement(enableCorrVecOutputs); - this->reportMeasurement(measurement); - + std::string rawMeasurementStr = ""; + if (ReplayUtils::hasGnssDeviceFile() && + ReplayUtils::isGnssRawMeasurement( + rawMeasurementStr = ReplayUtils::getDataFromDeviceFile( + std::string( + ::android::hardware::gnss::common::CMD_GET_RAWMEASUREMENT), + mMinIntervalMillis))) { + // TODO: implement rawMeasurementStr parser and report measurement. + ALOGD("rawMeasurementStr(size: %zu) from device file: %s", rawMeasurementStr.size(), + rawMeasurementStr.c_str()); + auto measurement = Utils::getMockMeasurement(enableCorrVecOutputs); + this->reportMeasurement(measurement); + } else { + auto measurement = Utils::getMockMeasurement(enableCorrVecOutputs); + this->reportMeasurement(measurement); + } std::this_thread::sleep_for(std::chrono::milliseconds(mMinIntervalMillis)); } }); diff --git a/gnss/common/utils/default/Android.bp b/gnss/common/utils/default/Android.bp index a1d3123500..ac94cc1bc0 100644 --- a/gnss/common/utils/default/Android.bp +++ b/gnss/common/utils/default/Android.bp @@ -41,6 +41,7 @@ cc_library_static { "MockLocation.cpp", "Utils.cpp", "NmeaFixInfo.cpp", + "GnssReplayUtils.cpp", ], export_include_dirs: ["include"], shared_libs: [ diff --git a/gnss/common/utils/default/GnssReplayUtils.cpp b/gnss/common/utils/default/GnssReplayUtils.cpp new file mode 100644 index 0000000000..6dcf6ea252 --- /dev/null +++ b/gnss/common/utils/default/GnssReplayUtils.cpp @@ -0,0 +1,88 @@ +/* + * Copyright (C) 2021 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. + */ + +#include "GnssReplayUtils.h" + +namespace android { +namespace hardware { +namespace gnss { +namespace common { + +const char* ReplayUtils::getGnssPath() { + const char* gnss_dev_path = GNSS_PATH; + char devname_value[PROPERTY_VALUE_MAX] = ""; + if (property_get("debug.location.gnss.devname", devname_value, NULL) > 0) { + gnss_dev_path = devname_value; + } + return gnss_dev_path; +} + +bool ReplayUtils::hasGnssDeviceFile() { + struct stat sb; + return stat(getGnssPath(), &sb) != -1; +} + +bool ReplayUtils::isGnssRawMeasurement(const std::string& inputStr) { + // TODO: add more logic check to by pass invalid data. + return !inputStr.empty() && (inputStr.find("Raw") != std::string::npos); +} + +bool ReplayUtils::isNMEA(const std::string& inputStr) { + return !inputStr.empty() && + (inputStr.rfind("$GPRMC,", 0) == 0 || inputStr.rfind("$GPRMA,", 0) == 0); +} + +std::string ReplayUtils::getDataFromDeviceFile(const std::string& command, int mMinIntervalMs) { + char inputBuffer[INPUT_BUFFER_SIZE]; + int mGnssFd = open(getGnssPath(), O_RDWR | O_NONBLOCK); + + if (mGnssFd == -1) { + return ""; + } + + int bytes_write = write(mGnssFd, command.c_str(), command.size()); + if (bytes_write <= 0) { + return ""; + } + + struct epoll_event ev, events[1]; + ev.data.fd = mGnssFd; + ev.events = EPOLLIN; + int epoll_fd = epoll_create1(0); + epoll_ctl(epoll_fd, EPOLL_CTL_ADD, mGnssFd, &ev); + int bytes_read = -1; + std::string inputStr = ""; + int epoll_ret = epoll_wait(epoll_fd, events, 1, mMinIntervalMs); + + if (epoll_ret == -1) { + return ""; + } + while (true) { + memset(inputBuffer, 0, INPUT_BUFFER_SIZE); + bytes_read = read(mGnssFd, &inputBuffer, INPUT_BUFFER_SIZE); + if (bytes_read <= 0) { + break; + } + inputStr += std::string(inputBuffer, bytes_read); + } + + return inputStr; +} + +} // namespace common +} // namespace gnss +} // namespace hardware +} // namespace android diff --git a/gnss/common/utils/default/include/Constants.h b/gnss/common/utils/default/include/Constants.h index 22afee1ad1..f205ba603c 100644 --- a/gnss/common/utils/default/include/Constants.h +++ b/gnss/common/utils/default/include/Constants.h @@ -34,6 +34,18 @@ const float kGpsL5FreqHz = 1176.45 * 1e6; const float kGloG1FreqHz = 1602.0 * 1e6; const float kIrnssL5FreqHz = 1176.45 * 1e6; +// Location replay constants +constexpr char GNSS_PATH[] = "/dev/gnss0"; +constexpr int INPUT_BUFFER_SIZE = 256; +constexpr char CMD_GET_LOCATION[] = "CMD_GET_LOCATION"; +constexpr char CMD_GET_RAWMEASUREMENT[] = "CMD_GET_RAWMEASUREMENT"; +constexpr char LINE_SEPARATOR = '\n'; +constexpr char COMMA_SEPARATOR = ','; +constexpr char GPGA_RECORD_TAG[] = "$GPGGA"; +constexpr char GPRMC_RECORD_TAG[] = "$GPRMC"; +constexpr double TIMESTAMP_EPSILON = 0.001; +constexpr int MIN_COL_NUM = 13; + } // namespace common } // namespace gnss } // namespace hardware diff --git a/gnss/common/utils/default/include/GnssReplayUtils.h b/gnss/common/utils/default/include/GnssReplayUtils.h new file mode 100644 index 0000000000..d7530f741a --- /dev/null +++ b/gnss/common/utils/default/include/GnssReplayUtils.h @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2021 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_common_GnssReplayUtils_H_ +#define android_hardware_gnss_common_GnssReplayUtils_H_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "Constants.h" + +namespace android { +namespace hardware { +namespace gnss { +namespace common { + +struct ReplayUtils { + static const char* getGnssPath(); + + static std::string getDataFromDeviceFile(const std::string& command, int mMinIntervalMs); + + static bool hasGnssDeviceFile(); + + static bool isGnssRawMeasurement(const std::string& inputStr); + + static bool isNMEA(const std::string& inputStr); +}; + +} // namespace common +} // namespace gnss +} // namespace hardware +} // namespace android + +#endif // android_hardware_gnss_common_GnssReplayUtils_H_ diff --git a/gnss/common/utils/default/include/NmeaFixInfo.h b/gnss/common/utils/default/include/NmeaFixInfo.h index c96eecea00..5c27045316 100644 --- a/gnss/common/utils/default/include/NmeaFixInfo.h +++ b/gnss/common/utils/default/include/NmeaFixInfo.h @@ -27,13 +27,6 @@ namespace hardware { namespace gnss { namespace common { -constexpr char GPGA_RECORD_TAG[] = "$GPGGA"; -constexpr char GPRMC_RECORD_TAG[] = "$GPRMC"; -constexpr char LINE_SEPARATOR = '\n'; -constexpr char COMMA_SEPARATOR = ','; -constexpr double TIMESTAMP_EPSILON = 0.001; -constexpr int MIN_COL_NUM = 13; - /** Helper class to parse and store the GNSS fix details information. */ class NmeaFixInfo { private: diff --git a/gnss/common/utils/default/include/v2_1/GnssTemplate.h b/gnss/common/utils/default/include/v2_1/GnssTemplate.h index 48cab99a10..75bcd33766 100644 --- a/gnss/common/utils/default/include/v2_1/GnssTemplate.h +++ b/gnss/common/utils/default/include/v2_1/GnssTemplate.h @@ -35,6 +35,7 @@ #include "GnssDebug.h" #include "GnssMeasurement.h" #include "GnssMeasurementCorrections.h" +#include "GnssReplayUtils.h" #include "MockLocation.h" #include "NmeaFixInfo.h" #include "Utils.h" @@ -159,15 +160,9 @@ GnssTemplate::~GnssTemplate() { template std::unique_ptr GnssTemplate::getLocationFromHW() { - char inputBuffer[INPUT_BUFFER_SIZE]; if (!mHardwareModeChecked) { - // default using gnss0 - const char * gnss_dev_path = GNSS_PATH; - char devname_value[PROPERTY_VALUE_MAX] = ""; - if (property_get("debug.location.gnss.devname", devname_value, NULL) > 0) { - gnss_dev_path = devname_value; - ALOGD("using %s instead of the default %s", gnss_dev_path, GNSS_PATH); - } + // default using /dev/gnss0 + const char* gnss_dev_path = ReplayUtils::getGnssPath(); mGnssFd = open(gnss_dev_path, O_RDWR | O_NONBLOCK); if (mGnssFd == -1) { @@ -176,35 +171,8 @@ std::unique_ptr GnssTemplate::getLocationFromHW() { mHardwareModeChecked = true; } - if (mGnssFd == -1) { - return nullptr; - } - - int bytes_write = write(mGnssFd, CMD_GET_LOCATION, strlen(CMD_GET_LOCATION)); - if (bytes_write <= 0) { - return nullptr; - } - - struct epoll_event ev, events[1]; - ev.data.fd = mGnssFd; - ev.events = EPOLLIN; - int epoll_fd = epoll_create1(0); - epoll_ctl(epoll_fd, EPOLL_CTL_ADD, mGnssFd, &ev); - int bytes_read = -1; - std::string inputStr = ""; - int epoll_ret = epoll_wait(epoll_fd, events, 1, mMinIntervalMs); - - if (epoll_ret == -1) { - return nullptr; - } - while (true) { - memset(inputBuffer, 0, INPUT_BUFFER_SIZE); - bytes_read = read(mGnssFd, &inputBuffer, INPUT_BUFFER_SIZE); - if (bytes_read <= 0) { - break; - } - inputStr += std::string(inputBuffer, bytes_read); - } + std::string inputStr = ::android::hardware::gnss::common::ReplayUtils::getDataFromDeviceFile( + CMD_GET_LOCATION, mMinIntervalMs); return NmeaFixInfo::getLocationFromInputStr(inputStr); } From e7d2bbadcab9ba7ab2450c0d61e5bf3ae08b2d47 Mon Sep 17 00:00:00 2001 From: George Burgess IV Date: Wed, 7 Jul 2021 09:59:32 -0700 Subject: [PATCH 10/16] fix potential use-after-frees of stack memory `devname_value` is a local variable; if `property_get` succeeds, we'll return a pointer to it. Returning a `std::string` instead sidesteps this problem. Bug: 190757198 Test: TreeHugger Change-Id: If9ca733dd21128706f2a9f62e8460b1286631aa5 Merged-In: If9ca733dd21128706f2a9f62e8460b1286631aa5 --- gnss/common/utils/default/GnssReplayUtils.cpp | 11 +++++------ gnss/common/utils/default/include/GnssReplayUtils.h | 2 +- gnss/common/utils/default/include/v2_1/GnssTemplate.h | 6 +++--- 3 files changed, 9 insertions(+), 10 deletions(-) diff --git a/gnss/common/utils/default/GnssReplayUtils.cpp b/gnss/common/utils/default/GnssReplayUtils.cpp index 6dcf6ea252..fc4c477ae8 100644 --- a/gnss/common/utils/default/GnssReplayUtils.cpp +++ b/gnss/common/utils/default/GnssReplayUtils.cpp @@ -21,18 +21,17 @@ namespace hardware { namespace gnss { namespace common { -const char* ReplayUtils::getGnssPath() { - const char* gnss_dev_path = GNSS_PATH; +std::string ReplayUtils::getGnssPath() { char devname_value[PROPERTY_VALUE_MAX] = ""; if (property_get("debug.location.gnss.devname", devname_value, NULL) > 0) { - gnss_dev_path = devname_value; + return devname_value; } - return gnss_dev_path; + return GNSS_PATH; } bool ReplayUtils::hasGnssDeviceFile() { struct stat sb; - return stat(getGnssPath(), &sb) != -1; + return stat(getGnssPath().c_str(), &sb) != -1; } bool ReplayUtils::isGnssRawMeasurement(const std::string& inputStr) { @@ -47,7 +46,7 @@ bool ReplayUtils::isNMEA(const std::string& inputStr) { std::string ReplayUtils::getDataFromDeviceFile(const std::string& command, int mMinIntervalMs) { char inputBuffer[INPUT_BUFFER_SIZE]; - int mGnssFd = open(getGnssPath(), O_RDWR | O_NONBLOCK); + int mGnssFd = open(getGnssPath().c_str(), O_RDWR | O_NONBLOCK); if (mGnssFd == -1) { return ""; diff --git a/gnss/common/utils/default/include/GnssReplayUtils.h b/gnss/common/utils/default/include/GnssReplayUtils.h index d7530f741a..32c0e58c0c 100644 --- a/gnss/common/utils/default/include/GnssReplayUtils.h +++ b/gnss/common/utils/default/include/GnssReplayUtils.h @@ -35,7 +35,7 @@ namespace gnss { namespace common { struct ReplayUtils { - static const char* getGnssPath(); + static std::string getGnssPath(); static std::string getDataFromDeviceFile(const std::string& command, int mMinIntervalMs); diff --git a/gnss/common/utils/default/include/v2_1/GnssTemplate.h b/gnss/common/utils/default/include/v2_1/GnssTemplate.h index 75bcd33766..b834a1f0c2 100644 --- a/gnss/common/utils/default/include/v2_1/GnssTemplate.h +++ b/gnss/common/utils/default/include/v2_1/GnssTemplate.h @@ -162,11 +162,11 @@ template std::unique_ptr GnssTemplate::getLocationFromHW() { if (!mHardwareModeChecked) { // default using /dev/gnss0 - const char* gnss_dev_path = ReplayUtils::getGnssPath(); + std::string gnss_dev_path = ReplayUtils::getGnssPath(); - mGnssFd = open(gnss_dev_path, O_RDWR | O_NONBLOCK); + mGnssFd = open(gnss_dev_path.c_str(), O_RDWR | O_NONBLOCK); if (mGnssFd == -1) { - ALOGW("Failed to open %s errno: %d", gnss_dev_path, errno); + ALOGW("Failed to open %s errno: %d", gnss_dev_path.c_str(), errno); } mHardwareModeChecked = true; } From 6ceb09d60c9dc711ef1573842d91a0e69c17fe24 Mon Sep 17 00:00:00 2001 From: Yuchen He Date: Thu, 12 Aug 2021 21:40:26 +0000 Subject: [PATCH 11/16] Add raw measurement parser Test: manual test (data cross verified with GnssLogger app) Bug: 190757198 Change-Id: I8d57826c6aa2a9d1a09b4847aadfda8c9160b36f Merged-In: I8d57826c6aa2a9d1a09b4847aadfda8c9160b36f --- gnss/common/utils/default/Android.bp | 2 + .../default/GnssRawMeasurementParser.cpp | 305 ++++++++++++++++++ gnss/common/utils/default/ParseUtils.cpp | 127 ++++++++ .../include/GnssRawMeasurementParser.h | 56 ++++ .../common/utils/default/include/ParseUtils.h | 46 +++ 5 files changed, 536 insertions(+) create mode 100644 gnss/common/utils/default/GnssRawMeasurementParser.cpp create mode 100644 gnss/common/utils/default/ParseUtils.cpp create mode 100644 gnss/common/utils/default/include/GnssRawMeasurementParser.h create mode 100644 gnss/common/utils/default/include/ParseUtils.h diff --git a/gnss/common/utils/default/Android.bp b/gnss/common/utils/default/Android.bp index ac94cc1bc0..fd3d939e7b 100644 --- a/gnss/common/utils/default/Android.bp +++ b/gnss/common/utils/default/Android.bp @@ -42,6 +42,8 @@ cc_library_static { "Utils.cpp", "NmeaFixInfo.cpp", "GnssReplayUtils.cpp", + "ParseUtils.cpp", + "GnssRawMeasurementParser.cpp", ], export_include_dirs: ["include"], shared_libs: [ diff --git a/gnss/common/utils/default/GnssRawMeasurementParser.cpp b/gnss/common/utils/default/GnssRawMeasurementParser.cpp new file mode 100644 index 0000000000..c066229ae9 --- /dev/null +++ b/gnss/common/utils/default/GnssRawMeasurementParser.cpp @@ -0,0 +1,305 @@ +/* + * Copyright (C) 2021 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. + */ + +#include "GnssRawMeasurementParser.h" + +namespace android { +namespace hardware { +namespace gnss { +namespace common { + +using aidl::android::hardware::gnss::ElapsedRealtime; +using aidl::android::hardware::gnss::GnssClock; +using aidl::android::hardware::gnss::GnssConstellationType; +using aidl::android::hardware::gnss::GnssData; +using aidl::android::hardware::gnss::GnssMeasurement; +using aidl::android::hardware::gnss::GnssMultipathIndicator; +using aidl::android::hardware::gnss::GnssSignalType; + +using ParseUtils = ::android::hardware::gnss::common::ParseUtils; + +std::unordered_map GnssRawMeasurementParser::getColumnIdNameMappingFromHeader( + const std::string& header) { + std::vector columnNames; + std::unordered_map columnNameIdMapping; + std::string s = header; + // Trim left spaces + s.erase(s.begin(), + std::find_if(s.begin(), s.end(), [](unsigned char ch) { return !std::isspace(ch); })); + // Trim right spaces + s.erase(std::find_if(s.rbegin(), s.rend(), [](unsigned char ch) { return !std::isspace(ch); }) + .base(), + s.end()); + // Remove comment symbol, start from `Raw`. + s = s.substr(s.find("Raw")); + + ParseUtils::splitStr(s, COMMA_SEPARATOR, columnNames); + int columnId = 0; + for (auto& name : columnNames) { + columnNameIdMapping[name] = columnId++; + } + + return columnNameIdMapping; +} + +int GnssRawMeasurementParser::getClockFlags( + const std::vector& rawMeasurementRecordValues, + const std::unordered_map& columnNameIdMapping) { + int clockFlags = 0; + if (!rawMeasurementRecordValues[columnNameIdMapping.at("LeapSecond")].empty()) { + clockFlags |= GnssClock::HAS_LEAP_SECOND; + } + if (!rawMeasurementRecordValues[columnNameIdMapping.at("FullBiasNanos")].empty()) { + clockFlags |= GnssClock::HAS_FULL_BIAS; + } + if (!rawMeasurementRecordValues[columnNameIdMapping.at("BiasNanos")].empty()) { + clockFlags |= GnssClock::HAS_BIAS; + } + if (!rawMeasurementRecordValues[columnNameIdMapping.at("BiasUncertaintyNanos")].empty()) { + clockFlags |= GnssClock::HAS_BIAS_UNCERTAINTY; + } + if (!rawMeasurementRecordValues[columnNameIdMapping.at("DriftNanosPerSecond")].empty()) { + clockFlags |= GnssClock::HAS_DRIFT; + } + if (!rawMeasurementRecordValues[columnNameIdMapping.at("DriftUncertaintyNanosPerSecond")] + .empty()) { + clockFlags |= GnssClock::HAS_DRIFT_UNCERTAINTY; + } + return clockFlags; +} + +int GnssRawMeasurementParser::getElapsedRealtimeFlags( + const std::vector& rawMeasurementRecordValues, + const std::unordered_map& columnNameIdMapping) { + int elapsedRealtimeFlags = ElapsedRealtime::HAS_TIMESTAMP_NS; + if (!rawMeasurementRecordValues[columnNameIdMapping.at("TimeUncertaintyNanos")].empty()) { + elapsedRealtimeFlags |= ElapsedRealtime::HAS_TIME_UNCERTAINTY_NS; + } + return elapsedRealtimeFlags; +} + +int GnssRawMeasurementParser::getRawMeasurementFlags( + const std::vector& rawMeasurementRecordValues, + const std::unordered_map& columnNameIdMapping) { + int rawMeasurementFlags = 0; + if (!rawMeasurementRecordValues[columnNameIdMapping.at("SnrInDb")].empty()) { + rawMeasurementFlags |= GnssMeasurement::HAS_SNR; + } + if (!rawMeasurementRecordValues[columnNameIdMapping.at("CarrierFrequencyHz")].empty()) { + rawMeasurementFlags |= GnssMeasurement::HAS_CARRIER_FREQUENCY; + } + if (!rawMeasurementRecordValues[columnNameIdMapping.at("CarrierCycles")].empty()) { + rawMeasurementFlags |= GnssMeasurement::HAS_CARRIER_CYCLES; + } + if (!rawMeasurementRecordValues[columnNameIdMapping.at("CarrierPhase")].empty()) { + rawMeasurementFlags |= GnssMeasurement::HAS_CARRIER_PHASE; + } + if (!rawMeasurementRecordValues[columnNameIdMapping.at("CarrierPhaseUncertainty")].empty()) { + rawMeasurementFlags |= GnssMeasurement::HAS_CARRIER_PHASE_UNCERTAINTY; + } + if (!rawMeasurementRecordValues[columnNameIdMapping.at("AgcDb")].empty()) { + rawMeasurementFlags |= GnssMeasurement::HAS_AUTOMATIC_GAIN_CONTROL; + } + if (!rawMeasurementRecordValues[columnNameIdMapping.at("FullInterSignalBiasNanos")].empty()) { + rawMeasurementFlags |= GnssMeasurement::HAS_FULL_ISB; + } + if (!rawMeasurementRecordValues[columnNameIdMapping.at("FullInterSignalBiasUncertaintyNanos")] + .empty()) { + rawMeasurementFlags |= GnssMeasurement::HAS_FULL_ISB_UNCERTAINTY; + } + if (!rawMeasurementRecordValues[columnNameIdMapping.at("SatelliteInterSignalBiasNanos")] + .empty()) { + rawMeasurementFlags |= GnssMeasurement::HAS_SATELLITE_ISB; + } + if (!rawMeasurementRecordValues[columnNameIdMapping.at( + "SatelliteInterSignalBiasUncertaintyNanos")] + .empty()) { + rawMeasurementFlags |= GnssMeasurement::HAS_SATELLITE_ISB_UNCERTAINTY; + } + // HAS_SATELLITE_PVT and HAS_CORRELATION_VECTOR fields currently not in rawmeasurement + // output, need add them later. + return rawMeasurementFlags; +} + +GnssConstellationType GnssRawMeasurementParser::getGnssConstellationType(int constellationType) { + GnssConstellationType gnssConstellationType = + aidl::android::hardware::gnss::GnssConstellationType::UNKNOWN; + + switch (constellationType) { + case 1: + gnssConstellationType = aidl::android::hardware::gnss::GnssConstellationType::GPS; + break; + case 2: + gnssConstellationType = aidl::android::hardware::gnss::GnssConstellationType::SBAS; + break; + case 3: + gnssConstellationType = aidl::android::hardware::gnss::GnssConstellationType::GLONASS; + break; + case 4: + gnssConstellationType = aidl::android::hardware::gnss::GnssConstellationType::QZSS; + break; + case 5: + gnssConstellationType = aidl::android::hardware::gnss::GnssConstellationType::BEIDOU; + break; + case 6: + gnssConstellationType = aidl::android::hardware::gnss::GnssConstellationType::GALILEO; + break; + default: + gnssConstellationType = aidl::android::hardware::gnss::GnssConstellationType::UNKNOWN; + } + + return gnssConstellationType; +} + +std::unique_ptr GnssRawMeasurementParser::getMeasurementFromStrs( + std::string& rawMeasurementStr) { + /* + * Raw,utcTimeMillis,TimeNanos,LeapSecond,TimeUncertaintyNanos,FullBiasNanos,BiasNanos, + * BiasUncertaintyNanos,DriftNanosPerSecond,DriftUncertaintyNanosPerSecond, + * HardwareClockDiscontinuityCount,Svid,TimeOffsetNanos,State,ReceivedSvTimeNanos, + * ReceivedSvTimeUncertaintyNanos,Cn0DbHz,PseudorangeRateMetersPerSecond, + * PseudorangeRateUncertaintyMetersPerSecond,AccumulatedDeltaRangeState, + * AccumulatedDeltaRangeMeters,AccumulatedDeltaRangeUncertaintyMeters,CarrierFrequencyHz, + * CarrierCycles,CarrierPhase,CarrierPhaseUncertainty,MultipathIndicator,SnrInDb, + * ConstellationType,AgcDb,BasebandCn0DbHz,FullInterSignalBiasNanos, + * FullInterSignalBiasUncertaintyNanos,SatelliteInterSignalBiasNanos, + * SatelliteInterSignalBiasUncertaintyNanos,CodeType,ChipsetElapsedRealtimeNanos + */ + ALOGD("Parsing %zu bytes rawMeasurementStr.", rawMeasurementStr.size()); + if (rawMeasurementStr.empty()) { + return nullptr; + } + std::vector rawMeasurementStrRecords; + ParseUtils::splitStr(rawMeasurementStr, LINE_SEPARATOR, rawMeasurementStrRecords); + if (rawMeasurementStrRecords.size() <= 1) { + ALOGE("Raw GNSS Measurements parser failed. (No records) "); + return nullptr; + } + + // Get the column name mapping from the header. + std::unordered_map columnNameIdMapping = + getColumnIdNameMappingFromHeader(rawMeasurementStrRecords[0]); + + if (columnNameIdMapping.size() < 37 || !ParseUtils::isValidHeader(columnNameIdMapping)) { + ALOGE("Raw GNSS Measurements parser failed. (No header or missing columns.) "); + return nullptr; + } + + // Set GnssClock from 1st record. + std::size_t pointer = 1; + std::vector firstRecordValues; + ParseUtils::splitStr(rawMeasurementStrRecords[pointer], COMMA_SEPARATOR, firstRecordValues); + GnssClock clock = { + .gnssClockFlags = getClockFlags(firstRecordValues, columnNameIdMapping), + .timeNs = ParseUtils::tryParseLongLong( + firstRecordValues[columnNameIdMapping.at("TimeNanos")], 0), + .fullBiasNs = ParseUtils::tryParseLongLong( + firstRecordValues[columnNameIdMapping.at("FullBiasNanos")], 0), + .biasNs = ParseUtils::tryParseDouble( + firstRecordValues[columnNameIdMapping.at("BiasNanos")], 0), + .biasUncertaintyNs = ParseUtils::tryParseDouble( + firstRecordValues[columnNameIdMapping.at("BiasUncertaintyNanos")], 0), + .driftNsps = ParseUtils::tryParseDouble( + firstRecordValues[columnNameIdMapping.at("DriftNanosPerSecond")], 0), + .driftUncertaintyNsps = ParseUtils::tryParseDouble( + firstRecordValues[columnNameIdMapping.at("DriftNanosPerSecond")], 0), + .hwClockDiscontinuityCount = ParseUtils::tryParseInt( + firstRecordValues[columnNameIdMapping.at("HardwareClockDiscontinuityCount")], + 0)}; + + ElapsedRealtime timestamp = { + .flags = getElapsedRealtimeFlags(firstRecordValues, columnNameIdMapping), + .timestampNs = ParseUtils::tryParseLongLong( + firstRecordValues[columnNameIdMapping.at("ChipsetElapsedRealtimeNanos")]), + .timeUncertaintyNs = ParseUtils::tryParseDouble( + firstRecordValues[columnNameIdMapping.at("TimeUncertaintyNanos")], 0)}; + + std::vector measurementsVec; + for (pointer = 1; pointer < rawMeasurementStrRecords.size(); pointer++) { + std::vector rawMeasurementValues; + std::string line = rawMeasurementStrRecords[pointer]; + ParseUtils::splitStr(line, COMMA_SEPARATOR, rawMeasurementValues); + GnssSignalType signalType = { + .constellation = getGnssConstellationType(ParseUtils::tryParseInt( + rawMeasurementValues[columnNameIdMapping.at("ConstellationType")], 0)), + .carrierFrequencyHz = ParseUtils::tryParseDouble( + rawMeasurementValues[columnNameIdMapping.at("CarrierFrequencyHz")], 0), + .codeType = rawMeasurementValues[columnNameIdMapping.at("CodeType")], + }; + GnssMeasurement measurement = { + .flags = getRawMeasurementFlags(rawMeasurementValues, columnNameIdMapping), + .svid = ParseUtils::tryParseInt( + rawMeasurementValues[columnNameIdMapping.at("Svid")], 0), + .signalType = signalType, + .receivedSvTimeInNs = ParseUtils::tryParseLongLong( + rawMeasurementValues[columnNameIdMapping.at("ReceivedSvTimeNanos")], 0), + .receivedSvTimeUncertaintyInNs = + ParseUtils::tryParseLongLong(rawMeasurementValues[columnNameIdMapping.at( + "ReceivedSvTimeUncertaintyNanos")], + 0), + .antennaCN0DbHz = ParseUtils::tryParseDouble( + rawMeasurementValues[columnNameIdMapping.at("Cn0DbHz")], 0), + .basebandCN0DbHz = ParseUtils::tryParseDouble( + rawMeasurementValues[columnNameIdMapping.at("BasebandCn0DbHz")], 0), + .agcLevelDb = ParseUtils::tryParseDouble( + rawMeasurementValues[columnNameIdMapping.at("AgcDb")], 0), + .pseudorangeRateMps = + ParseUtils::tryParseDouble(rawMeasurementValues[columnNameIdMapping.at( + "PseudorangeRateMetersPerSecond")], + 0), + .pseudorangeRateUncertaintyMps = ParseUtils::tryParseDouble( + rawMeasurementValues[columnNameIdMapping.at( + "PseudorangeRateUncertaintyMetersPerSecond")], + 0), + .accumulatedDeltaRangeState = ParseUtils::tryParseInt( + rawMeasurementValues[columnNameIdMapping.at("AccumulatedDeltaRangeState")], + 0), + .accumulatedDeltaRangeM = ParseUtils::tryParseDouble( + rawMeasurementValues[columnNameIdMapping.at("AccumulatedDeltaRangeMeters")], + 0), + .accumulatedDeltaRangeUncertaintyM = ParseUtils::tryParseDouble( + rawMeasurementValues[columnNameIdMapping.at( + "AccumulatedDeltaRangeUncertaintyMeters")], + 0), + .multipathIndicator = GnssMultipathIndicator::UNKNOWN, // Not in GnssLogger yet. + .state = ParseUtils::tryParseInt( + rawMeasurementValues[columnNameIdMapping.at("State")], 0), + .fullInterSignalBiasNs = ParseUtils::tryParseDouble(rawMeasurementValues[31], 0), + .fullInterSignalBiasUncertaintyNs = ParseUtils::tryParseDouble( + rawMeasurementValues[columnNameIdMapping.at("FullInterSignalBiasNanos")], + 0), + .satelliteInterSignalBiasNs = + ParseUtils::tryParseDouble(rawMeasurementValues[columnNameIdMapping.at( + "SatelliteInterSignalBiasNanos")], + 0), + .satelliteInterSignalBiasUncertaintyNs = ParseUtils::tryParseDouble( + rawMeasurementValues[columnNameIdMapping.at( + "SatelliteInterSignalBiasUncertaintyNanos")], + 0), + .satellitePvt = {}, + .correlationVectors = {}}; + measurementsVec.push_back(measurement); + } + + GnssData gnssData = { + .measurements = measurementsVec, .clock = clock, .elapsedRealtime = timestamp}; + return std::make_unique(gnssData); +} + +} // namespace common +} // namespace gnss +} // namespace hardware +} // namespace android diff --git a/gnss/common/utils/default/ParseUtils.cpp b/gnss/common/utils/default/ParseUtils.cpp new file mode 100644 index 0000000000..648edf7ecd --- /dev/null +++ b/gnss/common/utils/default/ParseUtils.cpp @@ -0,0 +1,127 @@ +/* + * Copyright (C) 2021 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. + */ + +#include +#include +#include + +namespace android { +namespace hardware { +namespace gnss { +namespace common { + +int ParseUtils::tryParseInt(const std::string& s, int defaultVal) { + if (s.empty()) { + return defaultVal; + } else { + return std::stoi(s); + } +} + +float ParseUtils::tryParsefloat(const std::string& s, float defaultVal) { + if (s.empty()) { + return defaultVal; + } else { + return std::stof(s); + } +} + +double ParseUtils::tryParseDouble(const std::string& s, double defaultVal) { + if (s.empty()) { + return defaultVal; + } else { + return std::stod(s); + } +} + +long ParseUtils::tryParseLong(const std::string& s, long defaultVal) { + if (s.empty()) { + return defaultVal; + } else { + return std::stol(s); + } +} + +long long ParseUtils::tryParseLongLong(const std::string& s, long long defaultVal) { + if (s.empty()) { + return defaultVal; + } else { + return std::stoll(s); + } +} + +void ParseUtils::splitStr(const std::string& line, const char& delimiter, + std::vector& out) { + std::istringstream iss(line); + std::string item; + while (std::getline(iss, item, delimiter)) { + out.push_back(item); + } +} + +bool ParseUtils::isValidHeader(const std::unordered_map& columnNameIdMapping) { + std::vector requiredHeaderColumns = {"Raw", + "utcTimeMillis", + "TimeNanos", + "LeapSecond", + "TimeUncertaintyNanos", + "FullBiasNanos", + "BiasNanos", + "BiasUncertaintyNanos", + "DriftNanosPerSecond", + "DriftUncertaintyNanosPerSecond", + "HardwareClockDiscontinuityCount", + "Svid", + "TimeOffsetNanos", + "State", + "ReceivedSvTimeNanos", + "ReceivedSvTimeUncertaintyNanos", + "Cn0DbHz", + "PseudorangeRateMetersPerSecond", + "PseudorangeRateUncertaintyMetersPerSecond", + "AccumulatedDeltaRangeState", + "AccumulatedDeltaRangeMeters", + "AccumulatedDeltaRangeUncertaintyMeters", + "CarrierFrequencyHz", + "CarrierCycles", + "CarrierPhase", + "CarrierPhaseUncertainty", + "MultipathIndicator", + "SnrInDb", + "ConstellationType", + "AgcDb", + "BasebandCn0DbHz", + "FullInterSignalBiasNanos", + "FullInterSignalBiasUncertaintyNanos", + "SatelliteInterSignalBiasNanos", + "SatelliteInterSignalBiasUncertaintyNanos", + "CodeType", + "ChipsetElapsedRealtimeNanos"}; + + for (const auto& columnName : requiredHeaderColumns) { + if (columnNameIdMapping.find(columnName) == columnNameIdMapping.end()) { + ALOGE("Missing column %s in header.", columnName.c_str()); + return false; + } + } + + return true; +} + +} // namespace common +} // namespace gnss +} // namespace hardware +} // namespace android diff --git a/gnss/common/utils/default/include/GnssRawMeasurementParser.h b/gnss/common/utils/default/include/GnssRawMeasurementParser.h new file mode 100644 index 0000000000..7d6b4efdd1 --- /dev/null +++ b/gnss/common/utils/default/include/GnssRawMeasurementParser.h @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2021 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_common_default_GnssRawMeasurementParser_H_ +#define android_hardware_gnss_common_default_GnssRawMeasurementParser_H_ + +#include +#include +#include +#include +#include + +#include "Constants.h" +#include "ParseUtils.h" + +namespace android { +namespace hardware { +namespace gnss { +namespace common { + +struct GnssRawMeasurementParser { + static std::unique_ptr getMeasurementFromStrs( + std::string& rawMeasurementStr); + static int getClockFlags(const std::vector& rawMeasurementRecordValues, + const std::unordered_map& columnNameIdMapping); + static int getElapsedRealtimeFlags( + const std::vector& rawMeasurementRecordValues, + const std::unordered_map& columnNameIdMapping); + static int getRawMeasurementFlags( + const std::vector& rawMeasurementRecordValues, + const std::unordered_map& columnNameIdMapping); + static std::unordered_map getColumnIdNameMappingFromHeader( + const std::string& header); + static aidl::android::hardware::gnss::GnssConstellationType getGnssConstellationType( + int constellationType); +}; + +} // namespace common +} // namespace gnss +} // namespace hardware +} // namespace android + +#endif // android_hardware_gnss_common_default_GnssRawMeasurementParser_H_ \ No newline at end of file diff --git a/gnss/common/utils/default/include/ParseUtils.h b/gnss/common/utils/default/include/ParseUtils.h new file mode 100644 index 0000000000..3a5631342e --- /dev/null +++ b/gnss/common/utils/default/include/ParseUtils.h @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2021 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_common_default_ParseUtils_H_ +#define android_hardware_gnss_common_default_ParseUtils_H_ + +#include +#include +#include +#include + +namespace android { +namespace hardware { +namespace gnss { +namespace common { + +struct ParseUtils { + static int tryParseInt(const std::string& s, int defaultVal = 0); + static float tryParsefloat(const std::string& s, float defaultVal = 0.0); + static double tryParseDouble(const std::string& s, double defaultVal = 0.0); + static long tryParseLong(const std::string& s, long defaultVal = 0); + static long long tryParseLongLong(const std::string& s, long long defaultVal = 0); + static void splitStr(const std::string& line, const char& delimiter, + std::vector& out); + static bool isValidHeader(const std::unordered_map& columnNameIdMapping); +}; + +} // namespace common +} // namespace gnss +} // namespace hardware +} // namespace android + +#endif // android_hardware_gnss_common_default_ParseUtils_H_ \ No newline at end of file From 4eb8cf8f6a1799f5abd05f4beda2780491f8efc7 Mon Sep 17 00:00:00 2001 From: Yuchen He Date: Mon, 30 Aug 2021 22:20:30 +0000 Subject: [PATCH 12/16] Read GNSS measurement from device file when available Test: atest CtsLocationGnssTestCases GtsLocationTestCases on CF Bug: 190757198 Change-Id: Ic03d56a5df6b99f7b20c5840e7091ead138316b1 Merged-In: Ic03d56a5df6b99f7b20c5840e7091ead138316b1 --- .../aidl/default/GnssMeasurementInterface.cpp | 18 ++-- gnss/common/utils/default/Android.bp | 11 ++- .../common/utils/default/DeviceFileReader.cpp | 97 +++++++++++++++++++ gnss/common/utils/default/GnssReplayUtils.cpp | 41 +------- .../utils/default/include/DeviceFileReader.h | 53 ++++++++++ .../utils/default/include/v2_1/GnssTemplate.h | 17 +--- 6 files changed, 173 insertions(+), 64 deletions(-) create mode 100644 gnss/common/utils/default/DeviceFileReader.cpp create mode 100644 gnss/common/utils/default/include/DeviceFileReader.h diff --git a/gnss/aidl/default/GnssMeasurementInterface.cpp b/gnss/aidl/default/GnssMeasurementInterface.cpp index 0e489c59e4..9e4f7c7f25 100644 --- a/gnss/aidl/default/GnssMeasurementInterface.cpp +++ b/gnss/aidl/default/GnssMeasurementInterface.cpp @@ -19,6 +19,8 @@ #include "GnssMeasurementInterface.h" #include #include +#include "DeviceFileReader.h" +#include "GnssRawMeasurementParser.h" #include "GnssReplayUtils.h" #include "Utils.h" @@ -26,6 +28,8 @@ namespace aidl::android::hardware::gnss { using Utils = ::android::hardware::gnss::common::Utils; using ReplayUtils = ::android::hardware::gnss::common::ReplayUtils; +using GnssRawMeasurementParser = ::android::hardware::gnss::common::GnssRawMeasurementParser; +using DeviceFileReader = ::android::hardware::gnss::common::DeviceFileReader; std::shared_ptr GnssMeasurementInterface::sCallback = nullptr; @@ -68,15 +72,15 @@ void GnssMeasurementInterface::start(const bool enableCorrVecOutputs) { std::string rawMeasurementStr = ""; if (ReplayUtils::hasGnssDeviceFile() && ReplayUtils::isGnssRawMeasurement( - rawMeasurementStr = ReplayUtils::getDataFromDeviceFile( - std::string( - ::android::hardware::gnss::common::CMD_GET_RAWMEASUREMENT), - mMinIntervalMillis))) { - // TODO: implement rawMeasurementStr parser and report measurement. + rawMeasurementStr = + DeviceFileReader::Instance().getGnssRawMeasurementData())) { ALOGD("rawMeasurementStr(size: %zu) from device file: %s", rawMeasurementStr.size(), rawMeasurementStr.c_str()); - auto measurement = Utils::getMockMeasurement(enableCorrVecOutputs); - this->reportMeasurement(measurement); + auto measurement = + GnssRawMeasurementParser::getMeasurementFromStrs(rawMeasurementStr); + if (measurement != nullptr) { + this->reportMeasurement(*measurement); + } } else { auto measurement = Utils::getMockMeasurement(enableCorrVecOutputs); this->reportMeasurement(measurement); diff --git a/gnss/common/utils/default/Android.bp b/gnss/common/utils/default/Android.bp index fd3d939e7b..5294409321 100644 --- a/gnss/common/utils/default/Android.bp +++ b/gnss/common/utils/default/Android.bp @@ -38,12 +38,13 @@ cc_library_static { "v2_1/GnssDebug.cpp", "v2_1/GnssMeasurement.cpp", "v2_1/GnssMeasurementCorrections.cpp", - "MockLocation.cpp", - "Utils.cpp", - "NmeaFixInfo.cpp", - "GnssReplayUtils.cpp", - "ParseUtils.cpp", + "DeviceFileReader.cpp", "GnssRawMeasurementParser.cpp", + "GnssReplayUtils.cpp", + "MockLocation.cpp", + "NmeaFixInfo.cpp", + "ParseUtils.cpp", + "Utils.cpp", ], export_include_dirs: ["include"], shared_libs: [ diff --git a/gnss/common/utils/default/DeviceFileReader.cpp b/gnss/common/utils/default/DeviceFileReader.cpp new file mode 100644 index 0000000000..7d4fb04339 --- /dev/null +++ b/gnss/common/utils/default/DeviceFileReader.cpp @@ -0,0 +1,97 @@ +/* + * Copyright (C) 2021 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. + */ +#include "DeviceFileReader.h" + +namespace android { +namespace hardware { +namespace gnss { +namespace common { + +void DeviceFileReader::getDataFromDeviceFile(const std::string& command, int mMinIntervalMs) { + char inputBuffer[INPUT_BUFFER_SIZE]; + int mGnssFd = open(ReplayUtils::getGnssPath().c_str(), + O_RDWR | O_NONBLOCK); + + if (mGnssFd == -1) { + return; + } + + int bytes_write = write(mGnssFd, command.c_str(), command.size()); + if (bytes_write <= 0) { + close(mGnssFd); + return; + } + + struct epoll_event ev, events[1]; + ev.data.fd = mGnssFd; + ev.events = EPOLLIN; + int epoll_fd = epoll_create1(0); + epoll_ctl(epoll_fd, EPOLL_CTL_ADD, mGnssFd, &ev); + int bytes_read = -1; + std::string inputStr = ""; + int epoll_ret = epoll_wait(epoll_fd, events, 1, mMinIntervalMs); + + if (epoll_ret == -1) { + close(mGnssFd); + return; + } + while (true) { + memset(inputBuffer, 0, INPUT_BUFFER_SIZE); + bytes_read = read(mGnssFd, &inputBuffer, INPUT_BUFFER_SIZE); + if (bytes_read <= 0) { + break; + } + s_buffer_ += std::string(inputBuffer, bytes_read); + } + close(mGnssFd); + + // Trim end of file mark(\n\n\n\n). + auto pos = s_buffer_.find("\n\n\n\n"); + if (pos != std::string::npos) { + inputStr = s_buffer_.substr(0, pos); + s_buffer_ = s_buffer_.substr(pos + 4); + } else { + return; + } + + // Cache the injected data. + if (ReplayUtils::isGnssRawMeasurement(inputStr)) { + data_[CMD_GET_RAWMEASUREMENT] = inputStr; + } else if (ReplayUtils::isNMEA(inputStr)) { + data_[CMD_GET_LOCATION] = inputStr; + } +} + +std::string DeviceFileReader::getLocationData() { + std::unique_lock lock(mMutex); + getDataFromDeviceFile(CMD_GET_LOCATION, 20); + return data_[CMD_GET_LOCATION]; +} + +std::string DeviceFileReader::getGnssRawMeasurementData() { + std::unique_lock lock(mMutex); + getDataFromDeviceFile(CMD_GET_RAWMEASUREMENT, 20); + return data_[CMD_GET_RAWMEASUREMENT]; +} + +DeviceFileReader::DeviceFileReader() {} + +DeviceFileReader::~DeviceFileReader() {} + +} // namespace common +} // namespace gnss +} // namespace hardware +} // namespace android diff --git a/gnss/common/utils/default/GnssReplayUtils.cpp b/gnss/common/utils/default/GnssReplayUtils.cpp index fc4c477ae8..e3f4ff82a0 100644 --- a/gnss/common/utils/default/GnssReplayUtils.cpp +++ b/gnss/common/utils/default/GnssReplayUtils.cpp @@ -40,45 +40,8 @@ bool ReplayUtils::isGnssRawMeasurement(const std::string& inputStr) { } bool ReplayUtils::isNMEA(const std::string& inputStr) { - return !inputStr.empty() && - (inputStr.rfind("$GPRMC,", 0) == 0 || inputStr.rfind("$GPRMA,", 0) == 0); -} - -std::string ReplayUtils::getDataFromDeviceFile(const std::string& command, int mMinIntervalMs) { - char inputBuffer[INPUT_BUFFER_SIZE]; - int mGnssFd = open(getGnssPath().c_str(), O_RDWR | O_NONBLOCK); - - if (mGnssFd == -1) { - return ""; - } - - int bytes_write = write(mGnssFd, command.c_str(), command.size()); - if (bytes_write <= 0) { - return ""; - } - - struct epoll_event ev, events[1]; - ev.data.fd = mGnssFd; - ev.events = EPOLLIN; - int epoll_fd = epoll_create1(0); - epoll_ctl(epoll_fd, EPOLL_CTL_ADD, mGnssFd, &ev); - int bytes_read = -1; - std::string inputStr = ""; - int epoll_ret = epoll_wait(epoll_fd, events, 1, mMinIntervalMs); - - if (epoll_ret == -1) { - return ""; - } - while (true) { - memset(inputBuffer, 0, INPUT_BUFFER_SIZE); - bytes_read = read(mGnssFd, &inputBuffer, INPUT_BUFFER_SIZE); - if (bytes_read <= 0) { - break; - } - inputStr += std::string(inputBuffer, bytes_read); - } - - return inputStr; + return !inputStr.empty() && (inputStr.find("$GPRMC,", 0) != std::string::npos || + inputStr.find("$GPRMA,", 0) != std::string::npos); } } // namespace common diff --git a/gnss/common/utils/default/include/DeviceFileReader.h b/gnss/common/utils/default/include/DeviceFileReader.h new file mode 100644 index 0000000000..c2a5c5f59b --- /dev/null +++ b/gnss/common/utils/default/include/DeviceFileReader.h @@ -0,0 +1,53 @@ + +/* + * Copyright (C) 2021 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_common_default_DeviceFileReader_H_ +#define android_hardware_gnss_common_default_DeviceFileReader_H_ + +#include +#include +#include +#include +#include "Constants.h" +#include "GnssReplayUtils.h" + +namespace android { +namespace hardware { +namespace gnss { +namespace common { +class DeviceFileReader { + public: + static DeviceFileReader& Instance() { + static DeviceFileReader reader; + return reader; + } + std::string getLocationData(); + std::string getGnssRawMeasurementData(); + void getDataFromDeviceFile(const std::string& command, int mMinIntervalMs); + + private: + DeviceFileReader(); + ~DeviceFileReader(); + std::unordered_map data_; + std::string s_buffer_; + std::mutex mMutex; +}; +} // namespace common +} // namespace gnss +} // namespace hardware +} // namespace android + +#endif // android_hardware_gnss_common_default_DeviceFileReader_H_ \ No newline at end of file diff --git a/gnss/common/utils/default/include/v2_1/GnssTemplate.h b/gnss/common/utils/default/include/v2_1/GnssTemplate.h index b834a1f0c2..fbf04b3c41 100644 --- a/gnss/common/utils/default/include/v2_1/GnssTemplate.h +++ b/gnss/common/utils/default/include/v2_1/GnssTemplate.h @@ -30,6 +30,7 @@ #include +#include "DeviceFileReader.h" #include "GnssAntennaInfo.h" #include "GnssConfiguration.h" #include "GnssDebug.h" @@ -160,19 +161,9 @@ GnssTemplate::~GnssTemplate() { template std::unique_ptr GnssTemplate::getLocationFromHW() { - if (!mHardwareModeChecked) { - // default using /dev/gnss0 - std::string gnss_dev_path = ReplayUtils::getGnssPath(); - - mGnssFd = open(gnss_dev_path.c_str(), O_RDWR | O_NONBLOCK); - if (mGnssFd == -1) { - ALOGW("Failed to open %s errno: %d", gnss_dev_path.c_str(), errno); - } - mHardwareModeChecked = true; - } - - std::string inputStr = ::android::hardware::gnss::common::ReplayUtils::getDataFromDeviceFile( - CMD_GET_LOCATION, mMinIntervalMs); + mHardwareModeChecked = true; + std::string inputStr = + ::android::hardware::gnss::common::DeviceFileReader::Instance().getLocationData(); return NmeaFixInfo::getLocationFromInputStr(inputStr); } From 76ff33b72d974b93b15c4e6697c580262db71955 Mon Sep 17 00:00:00 2001 From: Yuchen He Date: Thu, 13 Jan 2022 18:39:50 +0000 Subject: [PATCH 13/16] Add parser to support CSV location data Bug: 213225295 Test: launch_cvd -cpus 16 -memory_mb 16192 --start_gnss_proxy --gnss_file_path=/google/data/rw/users/yu/yuchenhe/input.txt (Running blue dot in Google Maps) Almost a cherry-pick but changed the data type from AIDL GnssLocation to the HIDL type, since there are no AIDL GnssLocation Type in SC-V2. Merged-In: I572315888c2f57ce701e695acb03aa6b28787f31 Change-Id: I572315888c2f57ce701e695acb03aa6b28787f31 --- gnss/common/utils/default/Android.bp | 1 + .../utils/default/FixLocationParser.cpp | 76 +++++++++++++++++++ .../utils/default/include/FixLocationParser.h | 47 ++++++++++++ 3 files changed, 124 insertions(+) create mode 100644 gnss/common/utils/default/FixLocationParser.cpp create mode 100644 gnss/common/utils/default/include/FixLocationParser.h diff --git a/gnss/common/utils/default/Android.bp b/gnss/common/utils/default/Android.bp index 5294409321..dda8a441e3 100644 --- a/gnss/common/utils/default/Android.bp +++ b/gnss/common/utils/default/Android.bp @@ -39,6 +39,7 @@ cc_library_static { "v2_1/GnssMeasurement.cpp", "v2_1/GnssMeasurementCorrections.cpp", "DeviceFileReader.cpp", + "FixLocationParser.cpp", "GnssRawMeasurementParser.cpp", "GnssReplayUtils.cpp", "MockLocation.cpp", diff --git a/gnss/common/utils/default/FixLocationParser.cpp b/gnss/common/utils/default/FixLocationParser.cpp new file mode 100644 index 0000000000..f0177b49c5 --- /dev/null +++ b/gnss/common/utils/default/FixLocationParser.cpp @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2022 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. + */ + +#include "FixLocationParser.h" + +#include + +namespace android { +namespace hardware { +namespace gnss { +namespace common { + +std::unique_ptr FixLocationParser::getLocationFromInputStr( + const std::string& locationStr) { + /* + * Fix,Provider,LatitudeDegrees,LongitudeDegrees,AltitudeMeters,SpeedMps, + * AccuracyMeters,BearingDegrees,UnixTimeMillis,SpeedAccuracyMps,BearingAccuracyDegrees, + * elapsedRealtimeNanos + */ + if (locationStr.empty()) { + return nullptr; + } + std::vector locationStrRecords; + ParseUtils::splitStr(locationStr, LINE_SEPARATOR, locationStrRecords); + if (locationStrRecords.empty()) { + return nullptr; + } + + std::vector locationValues; + ParseUtils::splitStr(locationStrRecords[0], COMMA_SEPARATOR, locationValues); + if (locationValues.size() < 12) { + return nullptr; + } + V2_0::ElapsedRealtime elapsedRealtime = { + .flags = V2_0::ElapsedRealtimeFlags::HAS_TIMESTAMP_NS | + V2_0::ElapsedRealtimeFlags::HAS_TIME_UNCERTAINTY_NS, + .timestampNs = static_cast(::android::elapsedRealtimeNano()), + // This is an hardcoded value indicating a 1ms of uncertainty between the two clocks. + // In an actual implementation provide an estimate of the synchronization uncertainty + // or don't set the field. + .timeUncertaintyNs = 1020400}; + + V1_0::GnssLocation locationV1 = { + .gnssLocationFlags = 0xFF, + .latitudeDegrees = ParseUtils::tryParseDouble(locationValues[2], 0), + .longitudeDegrees = ParseUtils::tryParseDouble(locationValues[3], 0), + .altitudeMeters = ParseUtils::tryParseDouble(locationValues[4], 0), + .speedMetersPerSec = ParseUtils::tryParsefloat(locationValues[5], 0), + .bearingDegrees = ParseUtils::tryParsefloat(locationValues[7], 0), + .horizontalAccuracyMeters = ParseUtils::tryParsefloat(locationValues[6], 0), + .verticalAccuracyMeters = ParseUtils::tryParsefloat(locationValues[6], 0), + .speedAccuracyMetersPerSecond = ParseUtils::tryParsefloat(locationValues[9], 0), + .bearingAccuracyDegrees = ParseUtils::tryParsefloat(locationValues[10], 0), + .timestamp = ParseUtils::tryParseLongLong(locationValues[8], 0)}; + + V2_0::GnssLocation locationV2 = {.v1_0 = locationV1, .elapsedRealtime = elapsedRealtime}; + return std::make_unique(locationV2); +} + +} // namespace common +} // namespace gnss +} // namespace hardware +} // namespace android diff --git a/gnss/common/utils/default/include/FixLocationParser.h b/gnss/common/utils/default/include/FixLocationParser.h new file mode 100644 index 0000000000..19748a9dd1 --- /dev/null +++ b/gnss/common/utils/default/include/FixLocationParser.h @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2022 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_common_default_FixLocationParser_H_ +#define android_hardware_gnss_common_default_FixLocationParser_H_ + +#include + +#include +#include +#include + +#include +#include +#include +#include "Constants.h" +#include "ParseUtils.h" + +namespace android { +namespace hardware { +namespace gnss { +namespace common { + +struct FixLocationParser { + public: + static std::unique_ptr getLocationFromInputStr(const std::string& inputStr); +}; + +} // namespace common +} // namespace gnss +} // namespace hardware +} // namespace android + +#endif // android_hardware_gnss_common_default_FixLocationParser_H_ From f46bb4ac80c5729da401de11d2f96355e4364a6b Mon Sep 17 00:00:00 2001 From: Yuchen He Date: Thu, 20 Jan 2022 22:57:09 +0000 Subject: [PATCH 14/16] Supported synchronized fixed location and measurement from device files Replace NMEA by one row fixed location data Test: atest VtsHalGnssTargetTest Test: launch_cvd -cpus 16 -memory_mb 16192 --start_gnss_proxy --gnss_file_path=/usr/local/google/home/yuchenhe/Downloads/raw.txt --fixed_location_file_path=/google/data/rw/users/yu/yuchenhe/input.txt Bug: 213225295 Merged-In: Ide7bbb3e81a90414496084691227bd95a2e7af18 Change-Id: Ide7bbb3e81a90414496084691227bd95a2e7af18 --- .../common/utils/default/DeviceFileReader.cpp | 22 ++++++++++++++----- gnss/common/utils/default/GnssReplayUtils.cpp | 13 +++++++++++ gnss/common/utils/default/include/Constants.h | 1 + .../utils/default/include/GnssReplayUtils.h | 4 ++++ .../utils/default/include/v2_1/GnssTemplate.h | 7 ++++-- 5 files changed, 40 insertions(+), 7 deletions(-) diff --git a/gnss/common/utils/default/DeviceFileReader.cpp b/gnss/common/utils/default/DeviceFileReader.cpp index 7d4fb04339..dfc086a8b8 100644 --- a/gnss/common/utils/default/DeviceFileReader.cpp +++ b/gnss/common/utils/default/DeviceFileReader.cpp @@ -22,8 +22,17 @@ namespace common { void DeviceFileReader::getDataFromDeviceFile(const std::string& command, int mMinIntervalMs) { char inputBuffer[INPUT_BUFFER_SIZE]; - int mGnssFd = open(ReplayUtils::getGnssPath().c_str(), - O_RDWR | O_NONBLOCK); + std::string deviceFilePath = ""; + if (command == CMD_GET_LOCATION) { + deviceFilePath = ReplayUtils::getFixedLocationPath(); + } else if (command == CMD_GET_RAWMEASUREMENT) { + deviceFilePath = ReplayUtils::getGnssPath(); + } else { + // Invalid command + return; + } + + int mGnssFd = open(deviceFilePath.c_str(), O_RDWR | O_NONBLOCK); if (mGnssFd == -1) { return; @@ -68,10 +77,13 @@ void DeviceFileReader::getDataFromDeviceFile(const std::string& command, int mMi } // Cache the injected data. - if (ReplayUtils::isGnssRawMeasurement(inputStr)) { - data_[CMD_GET_RAWMEASUREMENT] = inputStr; - } else if (ReplayUtils::isNMEA(inputStr)) { + if (command == CMD_GET_LOCATION) { + // TODO validate data data_[CMD_GET_LOCATION] = inputStr; + } else if (command == CMD_GET_RAWMEASUREMENT) { + if (ReplayUtils::isGnssRawMeasurement(inputStr)) { + data_[CMD_GET_RAWMEASUREMENT] = inputStr; + } } } diff --git a/gnss/common/utils/default/GnssReplayUtils.cpp b/gnss/common/utils/default/GnssReplayUtils.cpp index e3f4ff82a0..b27943e6ed 100644 --- a/gnss/common/utils/default/GnssReplayUtils.cpp +++ b/gnss/common/utils/default/GnssReplayUtils.cpp @@ -29,11 +29,24 @@ std::string ReplayUtils::getGnssPath() { return GNSS_PATH; } +std::string ReplayUtils::getFixedLocationPath() { + char devname_value[PROPERTY_VALUE_MAX] = ""; + if (property_get("debug.location.fixedlocation.devname", devname_value, NULL) > 0) { + return devname_value; + } + return FIXED_LOCATION_PATH; +} + bool ReplayUtils::hasGnssDeviceFile() { struct stat sb; return stat(getGnssPath().c_str(), &sb) != -1; } +bool ReplayUtils::hasFixedLocationDeviceFile() { + struct stat sb; + return stat(getFixedLocationPath().c_str(), &sb) != -1; +} + bool ReplayUtils::isGnssRawMeasurement(const std::string& inputStr) { // TODO: add more logic check to by pass invalid data. return !inputStr.empty() && (inputStr.find("Raw") != std::string::npos); diff --git a/gnss/common/utils/default/include/Constants.h b/gnss/common/utils/default/include/Constants.h index f205ba603c..489413e21d 100644 --- a/gnss/common/utils/default/include/Constants.h +++ b/gnss/common/utils/default/include/Constants.h @@ -36,6 +36,7 @@ const float kIrnssL5FreqHz = 1176.45 * 1e6; // Location replay constants constexpr char GNSS_PATH[] = "/dev/gnss0"; +constexpr char FIXED_LOCATION_PATH[] = "/dev/gnss1"; constexpr int INPUT_BUFFER_SIZE = 256; constexpr char CMD_GET_LOCATION[] = "CMD_GET_LOCATION"; constexpr char CMD_GET_RAWMEASUREMENT[] = "CMD_GET_RAWMEASUREMENT"; diff --git a/gnss/common/utils/default/include/GnssReplayUtils.h b/gnss/common/utils/default/include/GnssReplayUtils.h index 32c0e58c0c..d1bbed4b41 100644 --- a/gnss/common/utils/default/include/GnssReplayUtils.h +++ b/gnss/common/utils/default/include/GnssReplayUtils.h @@ -37,10 +37,14 @@ namespace common { struct ReplayUtils { static std::string getGnssPath(); + static std::string getFixedLocationPath(); + static std::string getDataFromDeviceFile(const std::string& command, int mMinIntervalMs); static bool hasGnssDeviceFile(); + static bool hasFixedLocationDeviceFile(); + static bool isGnssRawMeasurement(const std::string& inputStr); static bool isNMEA(const std::string& inputStr); diff --git a/gnss/common/utils/default/include/v2_1/GnssTemplate.h b/gnss/common/utils/default/include/v2_1/GnssTemplate.h index fbf04b3c41..473e587762 100644 --- a/gnss/common/utils/default/include/v2_1/GnssTemplate.h +++ b/gnss/common/utils/default/include/v2_1/GnssTemplate.h @@ -31,6 +31,7 @@ #include #include "DeviceFileReader.h" +#include "FixLocationParser.h" #include "GnssAntennaInfo.h" #include "GnssConfiguration.h" #include "GnssDebug.h" @@ -38,7 +39,6 @@ #include "GnssMeasurementCorrections.h" #include "GnssReplayUtils.h" #include "MockLocation.h" -#include "NmeaFixInfo.h" #include "Utils.h" namespace android::hardware::gnss::common::implementation { @@ -162,9 +162,12 @@ GnssTemplate::~GnssTemplate() { template std::unique_ptr GnssTemplate::getLocationFromHW() { mHardwareModeChecked = true; + if (!ReplayUtils::hasFixedLocationDeviceFile()) { + return nullptr; + } std::string inputStr = ::android::hardware::gnss::common::DeviceFileReader::Instance().getLocationData(); - return NmeaFixInfo::getLocationFromInputStr(inputStr); + return FixLocationParser::getLocationFromInputStr(inputStr); } template From 9447139c92acc9958a3705cee54a9a6d2556bb4b Mon Sep 17 00:00:00 2001 From: Enrico Granata Date: Wed, 23 Feb 2022 10:50:35 -0700 Subject: [PATCH 15/16] Support vendor GNSS file properties for AAOS virtualization The Android Automotive trout device uses GNSS HAL for fetching location data from a live GNSS adapter, not a mock file. We also have an established naming convention for console port names that is carried over from the Bluetooth use case. Add support for a vendor uart port for GNSS in addition to the existing Cuttlefish debug property, in order to enable trout to establish a connection to the host GNSS agent Bug: 213489959 Test: build flash and boot Change-Id: Id2d2134bb6ea60adef1072295c4f623463bfb010 --- gnss/common/utils/default/GnssReplayUtils.cpp | 30 +++++++++++++++---- 1 file changed, 24 insertions(+), 6 deletions(-) diff --git a/gnss/common/utils/default/GnssReplayUtils.cpp b/gnss/common/utils/default/GnssReplayUtils.cpp index b27943e6ed..d6769bdacc 100644 --- a/gnss/common/utils/default/GnssReplayUtils.cpp +++ b/gnss/common/utils/default/GnssReplayUtils.cpp @@ -16,24 +16,42 @@ #include "GnssReplayUtils.h" +#include + namespace android { namespace hardware { namespace gnss { namespace common { std::string ReplayUtils::getGnssPath() { - char devname_value[PROPERTY_VALUE_MAX] = ""; - if (property_get("debug.location.gnss.devname", devname_value, NULL) > 0) { - return devname_value; + std::array devname_value; + + devname_value.fill(0); + if (property_get("debug.location.gnss.devname", devname_value.begin(), NULL) > 0) { + return devname_value.begin(); } + + devname_value.fill(0); + if (property_get("vendor.ser.gnss-uart", devname_value.begin(), NULL) > 0) { + return devname_value.begin(); + } + return GNSS_PATH; } std::string ReplayUtils::getFixedLocationPath() { - char devname_value[PROPERTY_VALUE_MAX] = ""; - if (property_get("debug.location.fixedlocation.devname", devname_value, NULL) > 0) { - return devname_value; + std::array devname_value; + + devname_value.fill(0); + if (property_get("debug.location.fixedlocation.devname", devname_value.begin(), NULL) > 0) { + return devname_value.begin(); } + + devname_value.fill(0); + if (property_get("vendor.ser.gnss-uart", devname_value.begin(), NULL) > 0) { + return devname_value.begin(); + } + return FIXED_LOCATION_PATH; } From 6e7fcb1de6a4f61426b16572932eb6e52b4707d5 Mon Sep 17 00:00:00 2001 From: Tom Pratt Date: Fri, 11 Feb 2022 10:18:11 +0100 Subject: [PATCH 16/16] Add vintf fragment for default broadcastradio Bug: b/145694104 Test: Build and boot emulator locally. Observe that CarRadio app shows static data provided by default broadcast radio. Change-Id: Ia70e8a040cb281f3d0e8fc7f3a8dd25bcd6d09bd Merged-In: Ia70e8a040cb281f3d0e8fc7f3a8dd25bcd6d09bd --- broadcastradio/2.0/default/Android.bp | 5 ++++- .../android.hardware.broadcastradio@2.0-service.xml | 12 ++++++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) create mode 100644 broadcastradio/2.0/default/android.hardware.broadcastradio@2.0-service.xml diff --git a/broadcastradio/2.0/default/Android.bp b/broadcastradio/2.0/default/Android.bp index 870c944d75..38eeb15cdb 100644 --- a/broadcastradio/2.0/default/Android.bp +++ b/broadcastradio/2.0/default/Android.bp @@ -25,6 +25,9 @@ package { cc_binary { name: "android.hardware.broadcastradio@2.0-service", + vintf_fragments: [ + "android.hardware.broadcastradio@2.0-service.xml", + ], init_rc: ["android.hardware.broadcastradio@2.0-service.rc"], vendor: true, relative_install_path: "hw", @@ -41,7 +44,7 @@ cc_binary { "TunerSession.cpp", "VirtualProgram.cpp", "VirtualRadio.cpp", - "service.cpp" + "service.cpp", ], static_libs: [ "android.hardware.broadcastradio@common-utils-2x-lib", diff --git a/broadcastradio/2.0/default/android.hardware.broadcastradio@2.0-service.xml b/broadcastradio/2.0/default/android.hardware.broadcastradio@2.0-service.xml new file mode 100644 index 0000000000..97f2e4d848 --- /dev/null +++ b/broadcastradio/2.0/default/android.hardware.broadcastradio@2.0-service.xml @@ -0,0 +1,12 @@ + + + android.hardware.broadcastradio + hwbinder + 2.0 + + IBroadcastRadio + amfm + dab + + +