From 85bf78ef70dc89cffc03bb0c2d3a99e05451c2cd Mon Sep 17 00:00:00 2001 From: Joy Babafemi Date: Thu, 10 Aug 2023 15:23:16 -0700 Subject: [PATCH] Add sensor fusion implementation to presence C++ PiperOrigin-RevId: 555676715 --- presence/fpp/BUILD | 37 +++++++- presence/fpp/fpp_c_ffi/src/lib.rs | 46 +++++----- presence/fpp/fpp_manager.cc | 58 +++++++------ presence/fpp/fpp_manager.h | 5 ++ presence/fpp/fpp_manager_test.cc | 74 +++++++++++++--- presence/fpp/sensor_fusion_impl.cc | 68 +++++++++++++++ presence/fpp/sensor_fusion_impl.h | 51 +++++++++++ presence/fpp/sensor_fusion_test.cc | 110 ++++++++++++++++++++++++ presence/implementation/BUILD | 1 + presence/implementation/sensor_fusion.h | 23 ++--- 10 files changed, 400 insertions(+), 73 deletions(-) create mode 100644 presence/fpp/sensor_fusion_impl.cc create mode 100644 presence/fpp/sensor_fusion_impl.h create mode 100644 presence/fpp/sensor_fusion_test.cc diff --git a/presence/fpp/BUILD b/presence/fpp/BUILD index 5aa6744a..931c75a2 100644 --- a/presence/fpp/BUILD +++ b/presence/fpp/BUILD @@ -30,7 +30,22 @@ cc_library( "//presence/implementation:sensor_fusion", "@com_google_absl//absl/container:flat_hash_map", "@com_google_absl//absl/status", - "@com_google_absl//absl/types:optional", + ], +) + +cc_library( + name = "sensor_fusion_impl", + srcs = [ + "sensor_fusion_impl.cc", + ], + hdrs = ["sensor_fusion_impl.h"], + visibility = [ + "//presence:__subpackages__", + ], + deps = [ + ":fpp_manager", + "//presence/implementation:sensor_fusion", + "@com_google_absl//absl/status", ], ) @@ -53,3 +68,23 @@ cc_test( ], }), ) + +cc_test( + name = "sensor_fusion_test", + size = "small", + srcs = ["sensor_fusion_test.cc"], + deps = [ + ":sensor_fusion_impl", + "//presence/implementation:sensor_fusion", + "@com_github_protobuf_matchers//protobuf-matchers", + "@com_google_absl//absl/status", + "@com_google_googletest//:gtest_main", + ] + select({ + "@platforms//os:windows": [ + "//internal/platform/implementation/windows", + ], + "//conditions:default": [ + "//internal/platform/implementation/g3", + ], + }), +) diff --git a/presence/fpp/fpp_c_ffi/src/lib.rs b/presence/fpp/fpp_c_ffi/src/lib.rs index 6300a64b..b0c536f7 100644 --- a/presence/fpp/fpp_c_ffi/src/lib.rs +++ b/presence/fpp/fpp_c_ffi/src/lib.rs @@ -35,29 +35,31 @@ pub struct PresenceDetectorHandle { handle: u64, } -/// Error enum class representing possible errors +/// Enum class representing possible outputs of proximity data processing call #[repr(C)] -pub enum ProximityEstimateError { - /// Returned if the handle is invalid - InvalidPresenceDetectorHandle, - /// Returned if the output parameter is null - NullOutputParameter, +pub enum ComputationStatus { + /// Returned if the proximity estimate calculation was successful + Success, /// Returned if there is no computed proximity estimate NoComputedProximityEstimate, + /// Returned if the handle is invalid + InvalidPresenceDetectorHandleError, + /// Returned if the output parameter is null + NullOutputParameterError, } -impl ProximityEstimateError { - fn to_error_code(&self) -> i32 { +impl ComputationStatus { + fn to_status_code(&self) -> i32 { match self { - Self::InvalidPresenceDetectorHandle => -1, - Self::NullOutputParameter => -2, - Self::NoComputedProximityEstimate => -3, + /// Status codes 100+ are considered errors + Self::Success => 1, + Self::NoComputedProximityEstimate => 2, + Self::InvalidPresenceDetectorHandleError => 101, + Self::NullOutputParameterError => 102, } } } -const SUCCESS: i32 = 0; - /// Creates a new presence detector object and returns the handle for the new /// object #[no_mangle] @@ -86,15 +88,15 @@ pub unsafe extern "C" fn update_ble_scan_result( { if let Some(proximity_estimate) = proximity_estimate.as_mut() { *proximity_estimate = current_proximity_estimate; - SUCCESS + ComputationStatus::Success.to_status_code() } else { - ProximityEstimateError::NullOutputParameter.to_error_code() + ComputationStatus::NullOutputParameterError.to_status_code() } } else { - ProximityEstimateError::NoComputedProximityEstimate.to_error_code() + ComputationStatus::NoComputedProximityEstimate.to_status_code() } } else { - ProximityEstimateError::InvalidPresenceDetectorHandle.to_error_code() + ComputationStatus::InvalidPresenceDetectorHandleError.to_status_code() } } @@ -115,13 +117,13 @@ pub unsafe extern "C" fn get_proximity_estimate( presence_detector.get_proximity_estimate(device_id).map(|current_proximity_estimate| { if let Some(proximity_estimate) = proximity_estimate.as_mut() { *proximity_estimate = current_proximity_estimate; - return SUCCESS; + return ComputationStatus::Success.to_status_code(); } - ProximityEstimateError::NullOutputParameter.to_error_code() + ComputationStatus::NullOutputParameterError.to_status_code() }); } - ProximityEstimateError::InvalidPresenceDetectorHandle.to_error_code() + ComputationStatus::InvalidPresenceDetectorHandleError.to_status_code() } /// De-allocates memory for a presence detector object @@ -133,7 +135,7 @@ pub extern "C" fn presence_detector_free( get_presence_detector_handle_map().remove(&presence_detector_handle.handle) { let _ = *presence_detector; - return SUCCESS; + return ComputationStatus::Success.to_status_code(); } - ProximityEstimateError::InvalidPresenceDetectorHandle.to_error_code() + ComputationStatus::InvalidPresenceDetectorHandleError.to_status_code() } diff --git a/presence/fpp/fpp_manager.cc b/presence/fpp/fpp_manager.cc index f0ce1ec2..dfe2f4d4 100644 --- a/presence/fpp/fpp_manager.cc +++ b/presence/fpp/fpp_manager.cc @@ -29,30 +29,22 @@ namespace nearby { namespace presence { namespace { -constexpr int kSuccess = 0; -constexpr int kInvalidPresenceDetectorHandle = -1; -constexpr int kNullOutputParameter = -2; -constexpr int kNoComputedProximityEstimate = -3; +// See +// https://source.corp.google.com/piper///depot/google3/third_party/nearby/presence/fpp/fpp_c_ffi/src/lib.rs;l=49 +// for constants definition +constexpr int kSuccess = 1; +constexpr int kNoComputedProximityEstimate = 2; +constexpr int kInvalidPresenceDetectorHandleError = 101; +constexpr int kNullOutputParameterError = 102; // Converts optional tx power to the rust api compatible equivalent -MaybeTxPower ConvertTxPower(absl::optional txPower) { +MaybeTxPower ConvertTxPower(std::optional txPower) { if (txPower.has_value()) { return {MaybeTxPower::Tag::Valid, {txPower.value()}}; } return {MaybeTxPower::Tag::Invalid, {}}; } -std::string GetStatusStringFromCode(int status_code) { - switch (status_code) { - case kInvalidPresenceDetectorHandle: - return "INVALID_PRESENCE_DETECTOR_HANDLE"; - case kNullOutputParameter: - return "NULL_OUTPUT_PARAMETER"; - default: - return "UNKNOWN_ERROR"; - } -} - // Converts FPP ProximityState struct to NP RangeType struct PresenceZone::DistanceBoundary::RangeType ConvertProximityStateToRangeType( ProximityState proximity_state) { @@ -67,6 +59,7 @@ PresenceZone::DistanceBoundary::RangeType ConvertProximityStateToRangeType( return PresenceZone::DistanceBoundary::RangeType::kFar; case ProximityState::Unknown: default: + NEARBY_LOGS(WARNING) << "Proximity state is unknown"; return PresenceZone::DistanceBoundary::RangeType::kRangeUnknown; } } @@ -76,13 +69,16 @@ absl::Status FppManager::UpdateBleScanResult(uint64_t device_id, std::optional txPower, int rssi, uint64_t elapsed_realtime_millis) { + if (zone_transition_callbacks_.empty()) { + return absl::InternalError("No callback registered"); + } BleScanResult ble_scan_result = {device_id, ConvertTxPower(txPower), rssi, elapsed_realtime_millis}; ProximityEstimate default_proximity_estimate = ProximityEstimate{device_id, - 0.0, + /*distanceMeters=*/0.0, MeasurementConfidence::Unknown, - 0, + /*elapsedRealtime=*/0, ProximityState::Unknown, PresenceDataSource::Ble}; ProximityEstimate old_proximity_estimate = @@ -106,8 +102,7 @@ absl::Status FppManager::UpdateBleScanResult(uint64_t device_id, NEARBY_LOGS(WARNING) << "Could not successfully update FPP with new scan result: Error code=" << status_code; - return absl::Status(absl::StatusCode::kInternal, - GetStatusStringFromCode(status_code)); + return absl::InternalError(GetStatusStringFromCode(status_code)); } void FppManager::RegisterZoneTransitionListener( @@ -132,12 +127,13 @@ std::optional FppManager::GetRangingData(uint64_t device_id) { RangingData FppManager::ConvertProximityEstimateToRangingData( ProximityEstimate estimate) { RangingMeasurement ranging_measurement = { - 0.0, static_cast(estimate.distance_meters)}; - RangingPosition ranging_position = {ranging_measurement, absl::nullopt, - absl::nullopt, - estimate.elapsed_real_time_millis}; + /*confidenceLevel=*/0.0, static_cast(estimate.distance_meters)}; + RangingPosition ranging_position = { + ranging_measurement, /*azimuth=*/std::nullopt, + /*elevation=*/std::nullopt, estimate.elapsed_real_time_millis}; ZoneTransition zone_transition = { - ConvertProximityStateToRangeType(estimate.proximity_state), 0.0}; + ConvertProximityStateToRangeType(estimate.proximity_state), + /*confidenceLevel=*/0.0}; return {DataSource::kBle, ranging_position, zone_transition, std::vector()}; } @@ -157,5 +153,17 @@ void FppManager::CheckPresenceZoneChanged(uint64_t device_id, } } +std::string FppManager::GetStatusStringFromCode(int status_code) { + switch (status_code) { + case kInvalidPresenceDetectorHandleError: + return "INVALID_PRESENCE_DETECTOR_HANDLE"; + case kNullOutputParameterError: + return "NULL_OUTPUT_PARAMETER"; + default: + NEARBY_LOGS(WARNING) << "Error code is unknown"; + return "UNKNOWN_ERROR"; + } +} + } // namespace presence } // namespace nearby diff --git a/presence/fpp/fpp_manager.h b/presence/fpp/fpp_manager.h index d13e4adb..cecdb21e 100644 --- a/presence/fpp/fpp_manager.h +++ b/presence/fpp/fpp_manager.h @@ -66,6 +66,11 @@ class FppManager { */ std::optional GetRangingData(uint64_t device_id); + /* + * Converts a status code to a string representation + */ + std::string GetStatusStringFromCode(int status_code); + private: void CheckPresenceZoneChanged(uint64_t device_id, ProximityEstimate old_estimate, diff --git a/presence/fpp/fpp_manager_test.cc b/presence/fpp/fpp_manager_test.cc index 76dc2fc2..6911e06f 100644 --- a/presence/fpp/fpp_manager_test.cc +++ b/presence/fpp/fpp_manager_test.cc @@ -19,6 +19,7 @@ #include "gmock/gmock.h" #include "protobuf-matchers/protocol-buffer-matchers.h" #include "gtest/gtest.h" +#include "absl/status/status.h" #include "presence/implementation/sensor_fusion.h" namespace nearby { @@ -40,11 +41,11 @@ TEST(FppManager, UpdateBleScanResultSuccess) { PresenceZone::DistanceBoundary::RangeType range_type) { callback_called = true; }}); - EXPECT_OK(manager.UpdateBleScanResult(kDeviceId, /*txPower=*/absl::nullopt, + EXPECT_OK(manager.UpdateBleScanResult(kDeviceId, /*txPower=*/std::nullopt, kReachRssi, /*elapsed_real_time_millis=*/0)); // State is only computed after second consecutive scan is fulfilled - EXPECT_OK(manager.UpdateBleScanResult(kDeviceId, /*txPower=*/absl::nullopt, + EXPECT_OK(manager.UpdateBleScanResult(kDeviceId, /*txPower=*/std::nullopt, kReachRssi, /*elapsed_real_time_millis=*/2000)); EXPECT_EQ(manager.GetRangingData(kDeviceId) @@ -66,10 +67,10 @@ TEST(FppManager, ZoneTransitionDetected) { callback_called = true; }}); // ProximityEstimate is only computed after consecutive scans is fulfilled - EXPECT_OK(manager.UpdateBleScanResult(kDeviceId, /*txPower=*/absl::nullopt, + EXPECT_OK(manager.UpdateBleScanResult(kDeviceId, /*txPower=*/std::nullopt, kReachRssi, /*elapsed_real_time_millis=*/0)); - EXPECT_OK(manager.UpdateBleScanResult(kDeviceId, /*txPower=*/absl::nullopt, + EXPECT_OK(manager.UpdateBleScanResult(kDeviceId, /*txPower=*/std::nullopt, kReachRssi, /*elapsed_real_time_millis=*/2000)); EXPECT_EQ(manager.GetRangingData(kDeviceId) @@ -80,7 +81,7 @@ TEST(FppManager, ZoneTransitionDetected) { callback_called = false; // Update with new zone - EXPECT_OK(manager.UpdateBleScanResult(kDeviceId, /*txPower=*/absl::nullopt, + EXPECT_OK(manager.UpdateBleScanResult(kDeviceId, /*txPower=*/std::nullopt, kShortRangeRssi, /*elapsed_real_time_millis=*/0)); EXPECT_EQ(manager.GetRangingData(kDeviceId) @@ -89,7 +90,7 @@ TEST(FppManager, ZoneTransitionDetected) { PresenceZone::DistanceBoundary::RangeType::kWithinReach); EXPECT_FALSE(callback_called); // Update with consecutive scan of new zone - EXPECT_OK(manager.UpdateBleScanResult(kDeviceId, /*txPower=*/absl::nullopt, + EXPECT_OK(manager.UpdateBleScanResult(kDeviceId, /*txPower=*/std::nullopt, kShortRangeRssi, /*elapsed_real_time_millis=*/0)); EXPECT_EQ(manager.GetRangingData(kDeviceId) @@ -172,10 +173,10 @@ TEST(FppManager, UnregisterZoneTransitionListener) { PresenceZone::DistanceBoundary::RangeType range_type) { callback_called = true; }}); - EXPECT_OK(manager.UpdateBleScanResult(kDeviceId, /*txPower=*/absl::nullopt, + EXPECT_OK(manager.UpdateBleScanResult(kDeviceId, /*txPower=*/std::nullopt, kReachRssi, /*elapsed_real_time_millis=*/0)); - EXPECT_OK(manager.UpdateBleScanResult(kDeviceId, /*txPower=*/absl::nullopt, + EXPECT_OK(manager.UpdateBleScanResult(kDeviceId, /*txPower=*/std::nullopt, kReachRssi, /*elapsed_real_time_millis=*/2000)); EXPECT_TRUE(callback_called); @@ -183,15 +184,60 @@ TEST(FppManager, UnregisterZoneTransitionListener) { // Unregister listener and update with new zone manager.UnregisterZoneTransitionListener(kCallbackId); - EXPECT_OK(manager.UpdateBleScanResult(kDeviceId, /*txPower=*/absl::nullopt, - kShortRangeRssi, - /*elapsed_real_time_millis=*/0)); - EXPECT_OK(manager.UpdateBleScanResult(kDeviceId, /*txPower=*/absl::nullopt, - kShortRangeRssi, - /*elapsed_real_time_millis=*/0)); + EXPECT_EQ(manager + .UpdateBleScanResult(kDeviceId, /*txPower=*/std::nullopt, + kShortRangeRssi, + /*elapsed_real_time_millis=*/0) + .code(), + absl::StatusCode::kInternal); + EXPECT_EQ(manager + .UpdateBleScanResult(kDeviceId, /*txPower=*/std::nullopt, + kShortRangeRssi, + /*elapsed_real_time_millis=*/0) + .code(), + absl::StatusCode::kInternal); EXPECT_FALSE(callback_called); } +TEST(FppManager, ResetProximityStateData) { + FppManager manager; + bool callback_called = false; + manager.RegisterZoneTransitionListener( + kCallbackId, + {.on_proximity_zone_changed = + [&callback_called]( + uint64_t device_id, + PresenceZone::DistanceBoundary::RangeType range_type) { + callback_called = true; + }}); + ASSERT_OK(manager.UpdateBleScanResult(kDeviceId, /*txPower=*/std::nullopt, + kReachRssi, + /*elapsed_real_time_millis=*/0)); + // State is only computed after second consecutive scan is fulfilled + ASSERT_OK(manager.UpdateBleScanResult(kDeviceId, /*txPower=*/std::nullopt, + kReachRssi, + /*elapsed_real_time_millis=*/2000)); + EXPECT_EQ(manager.GetRangingData(kDeviceId) + ->zone_transition.value() + .distance_range_type, + PresenceZone::DistanceBoundary::RangeType::kWithinReach); + EXPECT_TRUE(callback_called); + + // Reset proximity state data + manager.ResetProximityStateData(); + EXPECT_EQ(manager.GetRangingData(kDeviceId) + ->zone_transition.value() + .distance_range_type, + PresenceZone::DistanceBoundary::RangeType::kRangeUnknown); +} + +TEST(FppManager, GetStatusStringFromCode) { + FppManager manager; + EXPECT_EQ(manager.GetStatusStringFromCode(101), + "INVALID_PRESENCE_DETECTOR_HANDLE"); + EXPECT_EQ(manager.GetStatusStringFromCode(102), "NULL_OUTPUT_PARAMETER"); +} + } // namespace } // namespace presence } // namespace nearby diff --git a/presence/fpp/sensor_fusion_impl.cc b/presence/fpp/sensor_fusion_impl.cc new file mode 100644 index 00000000..2bda18b5 --- /dev/null +++ b/presence/fpp/sensor_fusion_impl.cc @@ -0,0 +1,68 @@ +// Copyright 2023 Google LLC +// +// 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 "presence/fpp/sensor_fusion_impl.h" + +#include +#include +#include + +#include "absl/status/status.h" +#include "presence/fpp/fpp_manager.h" + +namespace nearby { +namespace presence { +std::vector SensorFusionImpl::GetDataSources( + uint64_t elapsed_realtime_millis, + const std::vector& available_sources) { + // TODO(b/264547688) - Implement + return std::vector(); +} +absl::Status SensorFusionImpl::UpdateBleScanResult( + uint64_t device_id, std::optional txPower, int rssi, + uint64_t elapsed_realtime_millis) { + return fpp_manager_.UpdateBleScanResult(device_id, txPower, rssi, + elapsed_realtime_millis); +} +void SensorFusionImpl::UpdateUwbRangingResult(uint64_t device_id, + RangingPosition position) { + // TODO(b/264547688) - Implement +} + +void SensorFusionImpl::RequestZoneTransitionUpdates( + ZoneTransitionCallback callback) { + int callback_id = ++id_generator_; + callback.on_callback_id_generated(callback_id); + fpp_manager_.RegisterZoneTransitionListener(callback_id, std::move(callback)); +} + +void SensorFusionImpl::RequestDeviceMotionUpdates( + SensorFusion::DeviceMotionCallback callback) { + // TODO(b/264547688) - Implement +} +void SensorFusionImpl::RemoveDeviceMotionUpdates( + SensorFusion::DeviceMotionCallback callback) { + // TODO(b/264547688) - Implement +} + +void SensorFusionImpl::RemoveZoneTransitionUpdates(uint64_t callback_id) { + fpp_manager_.UnregisterZoneTransitionListener(callback_id); +} + +std::optional SensorFusionImpl::GetRangingData( + uint64_t device_id) { + return fpp_manager_.GetRangingData(device_id); +} +} // namespace presence +} // namespace nearby diff --git a/presence/fpp/sensor_fusion_impl.h b/presence/fpp/sensor_fusion_impl.h new file mode 100644 index 00000000..ac37b6a8 --- /dev/null +++ b/presence/fpp/sensor_fusion_impl.h @@ -0,0 +1,51 @@ +// Copyright 2023 Google LLC +// +// 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 THIRD_PARTY_NEARBY_PRESENCE_FPP_SENSOR_FUSION_IMPL_H_ +#define THIRD_PARTY_NEARBY_PRESENCE_FPP_SENSOR_FUSION_IMPL_H_ + +#include +#include + +#include "presence/fpp/fpp_manager.h" +#include "presence/implementation/sensor_fusion.h" + +namespace nearby { +namespace presence { + +class SensorFusionImpl : public SensorFusion { + public: + ~SensorFusionImpl() = default; + std::vector GetDataSources( + uint64_t elapsed_realtime_millis, + const std::vector& available_sources) override; + absl::Status UpdateBleScanResult(uint64_t device_id, + std::optional txPower, int rssi, + uint64_t elapsed_realtime_millis) override; + void UpdateUwbRangingResult(uint64_t device_id, + RangingPosition position) override; + void RequestZoneTransitionUpdates(ZoneTransitionCallback callback) override; + void RemoveZoneTransitionUpdates(uint64_t callback_id) override; + void RequestDeviceMotionUpdates(DeviceMotionCallback callback) override; + void RemoveDeviceMotionUpdates(DeviceMotionCallback callback) override; + std::optional GetRangingData(uint64_t device_id) override; + + private: + FppManager fpp_manager_; + int id_generator_ = 0; +}; +} // namespace presence +} // namespace nearby + +#endif // THIRD_PARTY_NEARBY_PRESENCE_FPP_SENSOR_FUSION_IMPL_H_ diff --git a/presence/fpp/sensor_fusion_test.cc b/presence/fpp/sensor_fusion_test.cc new file mode 100644 index 00000000..aee34d7b --- /dev/null +++ b/presence/fpp/sensor_fusion_test.cc @@ -0,0 +1,110 @@ +// Copyright 2023 Google LLC +// +// 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 "gmock/gmock.h" +#include "protobuf-matchers/protocol-buffer-matchers.h" +#include "gtest/gtest.h" +#include "absl/status/status.h" +#include "presence/fpp/sensor_fusion_impl.h" + +namespace nearby { +namespace presence { +namespace { +constexpr uint64_t kDeviceId = 1234; +constexpr int kReachRssi = -40; + +TEST(SensorFusion, RequestZoneTransitionUpdatesSuccess) { + SensorFusionImpl sensor_fusion_impl; + bool callback_called = false; + bool callback2_called = false; + sensor_fusion_impl.RequestZoneTransitionUpdates( + {.on_callback_id_generated = [&callback_called](uint64_t callback_id) { + callback_called = true; + EXPECT_EQ(callback_id, 1); + }}); + sensor_fusion_impl.RequestZoneTransitionUpdates( + {.on_callback_id_generated = [&callback2_called](uint64_t callback_id2) { + callback2_called = true; + EXPECT_EQ(callback_id2, 2); + }}); + EXPECT_TRUE(callback2_called); +} + +TEST(SensorFusion, RemoveZoneTransitionUpdates) { + SensorFusionImpl sensor_fusion_impl; + bool callback_called = false; + sensor_fusion_impl.RequestZoneTransitionUpdates( + {.on_callback_id_generated = [&callback_called](uint64_t callback_id) { + callback_called = true; + EXPECT_EQ(callback_id, 1); + }}); + sensor_fusion_impl.RemoveZoneTransitionUpdates(1); + EXPECT_EQ( + sensor_fusion_impl + .UpdateBleScanResult(kDeviceId, /*txPower=*/std::nullopt, kReachRssi, + /*elapsed_real_time_millis=*/0) + .code(), + absl::StatusCode::kInternal); +} + +TEST(SensorFusion, UpdateBleScanResult) { + SensorFusionImpl sensor_fusion_impl; + bool proximity_zone_changed_called = false; + sensor_fusion_impl.RequestZoneTransitionUpdates( + {.on_proximity_zone_changed = + [&proximity_zone_changed_called]( + uint64_t device_id, + PresenceZone::DistanceBoundary::RangeType range_type) { + proximity_zone_changed_called = true; + }}); + EXPECT_OK(sensor_fusion_impl.UpdateBleScanResult( + kDeviceId, /*txPower=*/std::nullopt, kReachRssi, + /*elapsed_real_time_millis=*/0)); + EXPECT_OK(sensor_fusion_impl.UpdateBleScanResult( + kDeviceId, /*txPower=*/std::nullopt, kReachRssi, + /*elapsed_real_time_millis=*/0)); + + EXPECT_TRUE(proximity_zone_changed_called); +} + +TEST(SensorFusion, GetRangingData) { + SensorFusionImpl sensor_fusion_impl; + bool proximity_zone_changed_called = false; + sensor_fusion_impl.RequestZoneTransitionUpdates( + {.on_proximity_zone_changed = + [&proximity_zone_changed_called]( + uint64_t device_id, + PresenceZone::DistanceBoundary::RangeType range_type) { + proximity_zone_changed_called = true; + }}); + EXPECT_OK(sensor_fusion_impl.UpdateBleScanResult( + kDeviceId, /*txPower=*/std::nullopt, kReachRssi, + /*elapsed_real_time_millis=*/0)); + EXPECT_OK(sensor_fusion_impl.UpdateBleScanResult( + kDeviceId, /*txPower=*/std::nullopt, kReachRssi, + /*elapsed_real_time_millis=*/0)); + + EXPECT_TRUE(proximity_zone_changed_called); + + EXPECT_EQ(sensor_fusion_impl.GetRangingData(kDeviceId) + ->zone_transition.value() + .distance_range_type, + PresenceZone::DistanceBoundary::RangeType::kWithinReach); +} +} // namespace +} // namespace presence +} // namespace nearby diff --git a/presence/implementation/BUILD b/presence/implementation/BUILD index febab2ed..a7b9de53 100644 --- a/presence/implementation/BUILD +++ b/presence/implementation/BUILD @@ -126,6 +126,7 @@ cc_library( deps = [ "//presence:types", "@com_google_absl//absl/functional:any_invocable", + "@com_google_absl//absl/status", ], ) diff --git a/presence/implementation/sensor_fusion.h b/presence/implementation/sensor_fusion.h index facec76e..31639bd7 100644 --- a/presence/implementation/sensor_fusion.h +++ b/presence/implementation/sensor_fusion.h @@ -21,6 +21,7 @@ #include #include "absl/functional/any_invocable.h" +#include "absl/status/status.h" #include "presence/device_motion.h" #include "presence/presence_zone.h" @@ -92,7 +93,7 @@ class SensorFusion { */ virtual std::vector GetDataSources( uint64_t elapsed_realtime_millis, - const std::vector& available_sources); + const std::vector& available_sources) = 0; /** * Updates BLE scanned results to Sensor Fusion. @@ -104,10 +105,9 @@ class SensorFusion { * @param elapsed_realtime_millis Elapsed timestamp since boot when the * scan result is discovered. */ - virtual void UpdateBleScanResult(uint64_t device_id, - std::optional txPower, int rssi, - uint64_t elapsed_realtime_millis); - + virtual absl::Status UpdateBleScanResult( + uint64_t device_id, std::optional txPower, int rssi, + uint64_t elapsed_realtime_millis) = 0; /** * Updates UWB ranging results to Sensor Fusion. * @@ -115,27 +115,28 @@ class SensorFusion { * @param position UWB ranging result (distance and optionally angle) */ virtual void UpdateUwbRangingResult(uint64_t device_id, - RangingPosition position); + RangingPosition position) = 0; /** * Adds callback for updates of proximity zone transitions. */ - virtual void RequestZoneTransitionUpdates(ZoneTransitionCallback callback); + virtual void RequestZoneTransitionUpdates( + ZoneTransitionCallback callback) = 0; /** * Removes callback for updates of proximity zone transitions. */ - virtual void RemoveZoneTransitionUpdates(ZoneTransitionCallback callback); + virtual void RemoveZoneTransitionUpdates(uint64_t callback_id) = 0; /** * Adds callback for updates of device motion events. */ - virtual void RequestDeviceMotionUpdates(DeviceMotionCallback callback); + virtual void RequestDeviceMotionUpdates(DeviceMotionCallback callback) = 0; /** * Remove callback for updates of device motion events. */ - virtual void RemoveDeviceMotionUpdates(DeviceMotionCallback callback); + virtual void RemoveDeviceMotionUpdates(DeviceMotionCallback callback) = 0; /** * Returns the best ranging estimate to a given device. Returns {@code @@ -143,7 +144,7 @@ class SensorFusion { * * @param device_id Id of the peer device. */ - virtual std::optional GetRangingData(uint64_t device_id); + virtual std::optional GetRangingData(uint64_t device_id) = 0; }; } // namespace presence