diff --git a/presence/fpp/BUILD b/presence/fpp/BUILD new file mode 100644 index 00000000..f551c07b --- /dev/null +++ b/presence/fpp/BUILD @@ -0,0 +1,54 @@ +# 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. + +licenses(["notice"]) + +cc_library( + name = "fpp_manager", + srcs = [ + "fpp_manager.cc", + ], + hdrs = ["fpp_manager.h"], + visibility = [ + "//presence:__subpackages__", + ], + deps = [ + "//internal/platform:logging", + "//presence:types", + "//presence/fpp/fpp_c_ffi", + "//presence/implementation:sensor_fusion", + "@com_google_absl//absl/container:flat_hash_map", + "@com_google_absl//absl/status", + "@com_google_absl//absl/types:optional", + ], +) + +cc_test( + name = "fpp_manager_test", + size = "small", + srcs = ["fpp_manager_test.cc"], + deps = [ + ":fpp_manager", + "@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/src/fused_presence_utils.rs b/presence/fpp/fpp/src/fused_presence_utils.rs index 789cb29d..48b2dd0e 100644 --- a/presence/fpp/fpp/src/fused_presence_utils.rs +++ b/presence/fpp/fpp/src/fused_presence_utils.rs @@ -97,8 +97,9 @@ pub struct ProximityEstimate { pub distance_meters: f64, /// Measurement confidence of the estimate pub distance_confidence: MeasurementConfidence, - /// The time the proximity estimate was obtained - pub elapsed_real_time_millis: u128, + /// The time the proximity estimate was obtained (milliseconds since the + /// program start time) + pub elapsed_real_time_millis: u64, /// Proximity state zone of the nearby device pub proximity_state: ProximityState, /// Medium through which the proximity estimate was computed diff --git a/presence/fpp/fpp/src/presence_detector.rs b/presence/fpp/fpp/src/presence_detector.rs index 904f9e44..7f613ab5 100644 --- a/presence/fpp/fpp/src/presence_detector.rs +++ b/presence/fpp/fpp/src/presence_detector.rs @@ -13,7 +13,7 @@ // limitations under the License. use std::collections::{HashMap, VecDeque}; -use std::time::Instant; +use std::time::{Instant, SystemTime}; use itertools::Itertools; @@ -47,6 +47,7 @@ fn get_proximity_state_from_threshold(distance_meters: f64) -> ProximityState { /// Tracks and computes proximity/presence state events. pub struct PresenceDetector { + start_time: Instant, last_range_update_time: RangingUpdateTime, best_proximity_estimate_per_device: HashMap, transition_history: VecDeque, @@ -60,8 +61,8 @@ impl RangingUpdateTime { elapsed_real_time_millis - self.0 > DEFAULT_ESTIMATED_DISTANCE_DATA_TTL_MILLIS } - pub fn update(&mut self) { - self.0 = Instant::now().elapsed().as_millis(); + pub fn update(&mut self, start_time: Instant) { + self.0 = Instant::now().duration_since(start_time).as_millis(); } } @@ -69,6 +70,7 @@ impl PresenceDetector { /// Creates a new instance of presence detector pub fn new() -> Self { PresenceDetector { + start_time: Instant::now(), last_range_update_time: RangingUpdateTime(0), best_proximity_estimate_per_device: HashMap::new(), transition_history: VecDeque::with_capacity( @@ -77,17 +79,15 @@ impl PresenceDetector { } } - /// Updates the presence detector with a new scan result and returns the current proximity estimate + /// Updates the presence detector with a new scan result and returns the + /// current proximity estimate pub fn on_ble_scan_result( &mut self, ble_scan_result: BleScanResult, ) -> Option { let device_id = ble_scan_result.device_id; if ble_scan_result.rssi > MAX_RSSI_FILTER_VALUE { - return self - .best_proximity_estimate_per_device - .get(&device_id) - .copied(); + return self.best_proximity_estimate_per_device.get(&device_id).copied(); } if self.last_range_update_time.is_expired() { self.transition_history.clear(); @@ -103,30 +103,24 @@ impl PresenceDetector { distance_confidence: MeasurementConfidence::Low, distance_meters, proximity_state: get_proximity_state_from_threshold(distance_meters), - elapsed_real_time_millis: Instant::now().elapsed().as_millis(), + elapsed_real_time_millis: Instant::now().duration_since(self.start_time).as_millis() + as u64, source: PresenceDataSource::Ble, }; - self.transition_history - .push_front(new_proximity_estimate.proximity_state); - self.transition_history - .truncate(DEFAULT_CONSECUTIVE_SCANS_REQUIRED.into()); + self.transition_history.push_front(new_proximity_estimate.proximity_state); + self.transition_history.truncate(DEFAULT_CONSECUTIVE_SCANS_REQUIRED.into()); if self.transition_history.iter().unique().count() == 1 && self.transition_history.len() == DEFAULT_CONSECUTIVE_SCANS_REQUIRED.into() { - self.best_proximity_estimate_per_device - .insert(device_id, new_proximity_estimate); - self.last_range_update_time.update(); + self.best_proximity_estimate_per_device.insert(device_id, new_proximity_estimate); + self.last_range_update_time.update(self.start_time); } - self.best_proximity_estimate_per_device - .get(&device_id) - .copied() + self.best_proximity_estimate_per_device.get(&device_id).copied() } /// Returns the current proximity estimate for a given device pub fn get_proximity_estimate(&self, device_id: u64) -> Option { - self.best_proximity_estimate_per_device - .get(&device_id) - .copied() + self.best_proximity_estimate_per_device.get(&device_id).copied() } } diff --git a/presence/fpp/fpp_c_ffi/src/lib.rs b/presence/fpp/fpp_c_ffi/src/lib.rs index 43850a9d..6300a64b 100644 --- a/presence/fpp/fpp_c_ffi/src/lib.rs +++ b/presence/fpp/fpp_c_ffi/src/lib.rs @@ -42,6 +42,8 @@ pub enum ProximityEstimateError { InvalidPresenceDetectorHandle, /// Returned if the output parameter is null NullOutputParameter, + /// Returned if there is no computed proximity estimate + NoComputedProximityEstimate, } impl ProximityEstimateError { @@ -49,20 +51,23 @@ impl ProximityEstimateError { match self { Self::InvalidPresenceDetectorHandle => -1, Self::NullOutputParameter => -2, + Self::NoComputedProximityEstimate => -3, } } } const SUCCESS: i32 = 0; -/// Creates a new presence detector object and returns the handle for the new object +/// Creates a new presence detector object and returns the handle for the new +/// object #[no_mangle] pub extern "C" fn presence_detector_create() -> PresenceDetectorHandle { let handle = get_presence_detector_handle_map().insert(Box::new(PresenceDetector::new())); PresenceDetectorHandle { handle } } -/// Updates PresenceDetector with a new scan result and returns an error code if unsuccessful +/// Updates PresenceDetector with a new scan result and returns an error code if +/// unsuccessful /// /// # Safety /// @@ -76,17 +81,21 @@ pub unsafe extern "C" fn update_ble_scan_result( if let Some(presence_detector) = get_presence_detector_handle_map().get(&presence_detector_handle.handle) { - presence_detector - .on_ble_scan_result(ble_scan_result) - .map(|current_proximity_estimate| { - proximity_estimate.as_mut().map(|proximity_estimate| { - *proximity_estimate = current_proximity_estimate; - Some(SUCCESS) - }); + if let Some(current_proximity_estimate) = + presence_detector.on_ble_scan_result(ble_scan_result) + { + if let Some(proximity_estimate) = proximity_estimate.as_mut() { + *proximity_estimate = current_proximity_estimate; + SUCCESS + } else { ProximityEstimateError::NullOutputParameter.to_error_code() - }); + } + } else { + ProximityEstimateError::NoComputedProximityEstimate.to_error_code() + } + } else { + ProximityEstimateError::InvalidPresenceDetectorHandle.to_error_code() } - ProximityEstimateError::InvalidPresenceDetectorHandle.to_error_code() } /// Gets the current proximity estimate for a given device ID @@ -103,15 +112,13 @@ pub unsafe extern "C" fn get_proximity_estimate( if let Some(presence_detector) = get_presence_detector_handle_map().get(&presence_detector_handle.handle) { - 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; - } - ProximityEstimateError::NullOutputParameter.to_error_code() - }); + 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; + } + ProximityEstimateError::NullOutputParameter.to_error_code() + }); } ProximityEstimateError::InvalidPresenceDetectorHandle.to_error_code() diff --git a/presence/fpp/fpp_manager.cc b/presence/fpp/fpp_manager.cc new file mode 100644 index 00000000..a70265a4 --- /dev/null +++ b/presence/fpp/fpp_manager.cc @@ -0,0 +1,158 @@ +// 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/fpp_manager.h" + +#include +#include +#include + +#include "absl/status/status.h" +#include "internal/platform/logging.h" +#include "presence/fpp/fpp_c_ffi/include/presence_detector.h" +#include "presence/presence_zone.h" + +namespace nearby { +namespace presence { + +namespace { +constexpr int kSuccess = 0; +constexpr int kInvalidPresenceDetectorHandle = -1; +constexpr int kNullOutputParameter = -2; +constexpr int kNoComputedProximityEstimate = -3; + +// Converts optional tx power to the rust api compatible equivalent +MaybeTxPower ConvertTxPower(absl::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) { + switch (proximity_state) { + case ProximityState::Tap: + return PresenceZone::DistanceBoundary::RangeType::kWithinTap; + case ProximityState::Reach: + return PresenceZone::DistanceBoundary::RangeType::kWithinReach; + case ProximityState::ShortRange: + case ProximityState::LongRange: + case ProximityState::Far: + return PresenceZone::DistanceBoundary::RangeType::kFar; + case ProximityState::Unknown: + default: + return PresenceZone::DistanceBoundary::RangeType::kRangeUnknown; + } +} +} // namespace + +absl::Status FppManager::UpdateBleScanResult(uint64_t device_id, + std::optional txPower, + int rssi, + uint64_t elapsed_realtime_millis) { + BleScanResult ble_scan_result = {device_id, ConvertTxPower(txPower), rssi, + elapsed_realtime_millis}; + ProximityEstimate default_proximity_estimate = + ProximityEstimate{device_id, + 0.0, + MeasurementConfidence::Unknown, + 0, + ProximityState::Unknown, + PresenceDataSource::Ble}; + ProximityEstimate old_proximity_estimate = + current_proximity_estimates_.contains(device_id) + ? current_proximity_estimates_[device_id] + : default_proximity_estimate; + ProximityEstimate new_proximity_estimate = default_proximity_estimate; + int status_code = update_ble_scan_result( + presence_detector_handle_, ble_scan_result, &new_proximity_estimate); + if (status_code == kNoComputedProximityEstimate) { + NEARBY_LOGS(INFO) << "Insufficient number of scan results available to " + "compute proximity state"; + return absl::OkStatus(); + } + if (status_code == kSuccess) { + current_proximity_estimates_[device_id] = new_proximity_estimate; + CheckPresenceZoneChanged(device_id, old_proximity_estimate, + new_proximity_estimate); + return absl::OkStatus(); + } + 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)); +} + +void FppManager::RegisterZoneTransitionListener( + uint64_t callback_id, ZoneTransitionCallback callback) { + zone_transition_callbacks_[callback_id] = callback; +} + +void FppManager::UnregisterZoneTransitionListener(uint64_t callback_id) { + zone_transition_callbacks_.erase(callback_id); +} + +void FppManager::ResetProximityStateData() { + current_proximity_estimates_.clear(); +} + +std::optional FppManager::GetRangingData(uint64_t device_id) { + return ConvertProximityEstimateToRangingData( + current_proximity_estimates_[device_id]); +} + +// Converts FPP ProximityEstimate struct to NP RangingData struct +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}; + ZoneTransition zone_transition = { + ConvertProximityStateToRangeType(estimate.proximity_state), 0.0}; + return {DataSource::kBle, ranging_position, zone_transition, + std::vector()}; +} + +void FppManager::CheckPresenceZoneChanged(uint64_t device_id, + ProximityEstimate old_estimate, + ProximityEstimate new_estimate) { + if (old_estimate.proximity_state != new_estimate.proximity_state) { + NEARBY_LOG(WARNING, + "Updating zone transition callbacks with new zone. Zone=%p", + new_estimate.proximity_state); + for (const auto& pair : zone_transition_callbacks_) { + pair.second(device_id, ConvertProximityStateToRangeType( + new_estimate.proximity_state)); + } + } +} + +} // namespace presence +} // namespace nearby diff --git a/presence/fpp/fpp_manager.h b/presence/fpp/fpp_manager.h new file mode 100644 index 00000000..50b616af --- /dev/null +++ b/presence/fpp/fpp_manager.h @@ -0,0 +1,82 @@ +// 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_FPP_MANAGER_H_ +#define THIRD_PARTY_NEARBY_PRESENCE_FPP_FPP_MANAGER_H_ + +#include +#include + +#include "absl/container/flat_hash_map.h" +#include "absl/status/status.h" +#include "presence/fpp/fpp_c_ffi/include/presence_detector.h" +#include "presence/implementation/sensor_fusion.h" +#include "presence/presence_zone.h" + +namespace nearby { +namespace presence { + +// Manages fused presence updates and serves as a sync -> async converter class +// between fpp and NP sensor fusion +class FppManager { + public: + using ZoneTransitionCallback = SensorFusion::ZoneTransitionCallback; + using RangeType = PresenceZone::DistanceBoundary::RangeType; + + FppManager() { presence_detector_handle_ = presence_detector_create(); } + ~FppManager() { presence_detector_free(presence_detector_handle_); } + + /** Updates FPP with new BLE scan results. Returns status code */ + absl::Status UpdateBleScanResult(uint64_t device_id, + std::optional txPower, int rssi, + uint64_t elapsed_realtime_millis); + /** + * Adds callback for updates of proximity zone transitions. + */ + void RegisterZoneTransitionListener(uint64_t callback_id, + ZoneTransitionCallback callback); + + /** + * Unregister callback for updates of proximity zone transitions. + */ + void UnregisterZoneTransitionListener(uint64_t callback_id); + + /** + * Clears all proximity state data + */ + void ResetProximityStateData(); + + /* + * Converts ProximityEstimate to a NP compatible struct + */ + RangingData ConvertProximityEstimateToRangingData(ProximityEstimate estimate); + + /** + * Gets the most recent ranging data for a given device + */ + std::optional GetRangingData(uint64_t device_id); + + private: + void CheckPresenceZoneChanged(uint64_t device_id, + ProximityEstimate old_estimate, + ProximityEstimate new_estimate); + absl::flat_hash_map current_proximity_estimates_; + absl::flat_hash_map + zone_transition_callbacks_; + PresenceDetectorHandle presence_detector_handle_; +}; +} // namespace presence +} // namespace nearby + +#endif // THIRD_PARTY_NEARBY_PRESENCE_FPP_FPP_MANAGER_H_ diff --git a/presence/fpp/fpp_manager_test.cc b/presence/fpp/fpp_manager_test.cc new file mode 100644 index 00000000..b7ed5e72 --- /dev/null +++ b/presence/fpp/fpp_manager_test.cc @@ -0,0 +1,188 @@ +// 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/fpp_manager.h" + +#include + +#include "gmock/gmock.h" +#include "protobuf-matchers/protocol-buffer-matchers.h" +#include "gtest/gtest.h" + +namespace nearby { +namespace presence { +namespace { +constexpr uint64_t kDeviceId = 1234; +constexpr int kReachRssi = -40; +constexpr int kShortRangeRssi = -60; +constexpr int kCallbackId = 12345; + +TEST(FppManager, UpdateBleScanResultSuccess) { + FppManager manager; + bool callback_called = false; + manager.RegisterZoneTransitionListener( + kCallbackId, + [&callback_called](uint64_t device_id, + PresenceZone::DistanceBoundary::RangeType range_type) { + callback_called = true; + }); + EXPECT_OK(manager.UpdateBleScanResult(kDeviceId, /*txPower=*/absl::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, + 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); +} + +TEST(FppManager, ZoneTransitionDetected) { + FppManager manager; + bool callback_called = false; + manager.RegisterZoneTransitionListener( + kCallbackId, + [&callback_called](uint64_t device_id, + PresenceZone::DistanceBoundary::RangeType range_type) { + callback_called = true; + }); + // ProximityEstimate is only computed after consecutive scans is fulfilled + EXPECT_OK(manager.UpdateBleScanResult(kDeviceId, /*txPower=*/absl::nullopt, + kReachRssi, + /*elapsed_real_time_millis=*/0)); + EXPECT_OK(manager.UpdateBleScanResult(kDeviceId, /*txPower=*/absl::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); + callback_called = false; + + // Update with new zone + EXPECT_OK(manager.UpdateBleScanResult(kDeviceId, /*txPower=*/absl::nullopt, + kShortRangeRssi, + /*elapsed_real_time_millis=*/0)); + EXPECT_EQ(manager.GetRangingData(kDeviceId) + ->zone_transition.value() + .distance_range_type, + PresenceZone::DistanceBoundary::RangeType::kWithinReach); + EXPECT_FALSE(callback_called); + // Update with consecutive scan of new zone + EXPECT_OK(manager.UpdateBleScanResult(kDeviceId, /*txPower=*/absl::nullopt, + kShortRangeRssi, + /*elapsed_real_time_millis=*/0)); + EXPECT_EQ(manager.GetRangingData(kDeviceId) + ->zone_transition.value() + .distance_range_type, + PresenceZone::DistanceBoundary::RangeType::kFar); + EXPECT_TRUE(callback_called); +} + +TEST(FppManager, ConvertProximityEstimateToRangingData) { + FppManager manager; + ProximityEstimate proximity_estimate = + ProximityEstimate{kDeviceId, + 0.1, + MeasurementConfidence::Low, + 0, + ProximityState::Reach, + PresenceDataSource::Ble}; + RangingData rangingData = + manager.ConvertProximityEstimateToRangingData(proximity_estimate); + EXPECT_EQ(rangingData.data_source, DataSource::kBle); + EXPECT_EQ(rangingData.position.distance.value, 0.1f); + EXPECT_EQ(rangingData.zone_transition->confidence_level, 0.0f); + EXPECT_EQ(rangingData.zone_transition->distance_range_type, + PresenceZone::DistanceBoundary::RangeType::kWithinReach); + ProximityEstimate unknown_proximity_estimate = + ProximityEstimate{kDeviceId, + 0.0, + MeasurementConfidence::Low, + 0, + ProximityState::Unknown, + PresenceDataSource::Ble}; + RangingData unknown_rangingData = + manager.ConvertProximityEstimateToRangingData(unknown_proximity_estimate); + EXPECT_EQ(unknown_rangingData.zone_transition->distance_range_type, + PresenceZone::DistanceBoundary::RangeType::kRangeUnknown); + ProximityEstimate tap_proximity_estimate = + ProximityEstimate{kDeviceId, + 0.03, + MeasurementConfidence::Low, + 0, + ProximityState::Tap, + PresenceDataSource::Ble}; + RangingData tap_rangingData = + manager.ConvertProximityEstimateToRangingData(tap_proximity_estimate); + EXPECT_EQ(tap_rangingData.zone_transition->distance_range_type, + PresenceZone::DistanceBoundary::RangeType::kWithinTap); +} + +TEST(FppManager, UpdateBleScanResultWithTxPowerSuccess) { + FppManager manager; + bool callback_called = false; + manager.RegisterZoneTransitionListener( + kCallbackId, + [&callback_called](uint64_t device_id, + PresenceZone::DistanceBoundary::RangeType range_type) { + callback_called = true; + }); + EXPECT_OK(manager.UpdateBleScanResult(kDeviceId, /*txPower=*/20, kReachRssi, + /*elapsed_real_time_millis=*/0)); + EXPECT_OK(manager.UpdateBleScanResult(kDeviceId, /*txPower=*/20, kReachRssi, + /*elapsed_real_time_millis=*/2000)); + EXPECT_EQ(manager.GetRangingData(kDeviceId) + ->zone_transition.value() + .distance_range_type, + PresenceZone::DistanceBoundary::RangeType::kWithinTap); + EXPECT_TRUE(callback_called); +} + +TEST(FppManager, UnregisterZoneTransitionListener) { + FppManager manager; + bool callback_called = false; + manager.RegisterZoneTransitionListener( + kCallbackId, + [&callback_called](uint64_t device_id, + PresenceZone::DistanceBoundary::RangeType range_type) { + callback_called = true; + }); + EXPECT_OK(manager.UpdateBleScanResult(kDeviceId, /*txPower=*/absl::nullopt, + kReachRssi, + /*elapsed_real_time_millis=*/0)); + EXPECT_OK(manager.UpdateBleScanResult(kDeviceId, /*txPower=*/absl::nullopt, + kReachRssi, + /*elapsed_real_time_millis=*/2000)); + EXPECT_TRUE(callback_called); + callback_called = false; + + // 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_FALSE(callback_called); +} + +} // namespace +} // namespace presence +} // namespace nearby diff --git a/presence/implementation/sensor_fusion.h b/presence/implementation/sensor_fusion.h index 587100e8..452b01fd 100644 --- a/presence/implementation/sensor_fusion.h +++ b/presence/implementation/sensor_fusion.h @@ -15,8 +15,8 @@ #ifndef THIRD_PARTY_NEARBY_PRESENCE_IMPLEMENTATION_SENSOR_FUSION_H_ #define THIRD_PARTY_NEARBY_PRESENCE_IMPLEMENTATION_SENSOR_FUSION_H_ +#include #include -#include #include #include "absl/types/optional.h" @@ -52,7 +52,7 @@ struct ZoneTransition { }; struct RangingData { - std::vector data_sources; + DataSource data_source; RangingPosition position; absl::optional zone_transition; std::vector device_motions; @@ -64,7 +64,7 @@ class SensorFusion { // Called when the proximity zone to a nearby peer device has changed. typedef std::function ZoneTransitionCallback; @@ -98,7 +98,7 @@ class SensorFusion { * @param elapsed_realtime_millis Elapsed timestamp since boot when the * scan result is discovered. */ - virtual void updateBleScanResult(std::string device_id, + virtual void updateBleScanResult(uint64_t device_id, absl::optional txPower, int rssi, uint64_t elapsed_realtime_millis); @@ -108,7 +108,7 @@ class SensorFusion { * @param device_id A unique device id of the peer device. * @param position UWB ranging result (distance and optionally angle) */ - virtual void updateUwbRangingResult(std::string device_id, + virtual void updateUwbRangingResult(uint64_t device_id, RangingPosition position); /** @@ -137,7 +137,7 @@ class SensorFusion { * * @param device_id Id of the peer device. */ - virtual absl::optional getRangingData(std::string device_id); + virtual absl::optional getRangingData(uint64_t device_id); }; } // namespace presence