mirror of
https://github.com/kidfromjupiter/nearby.git
synced 2026-09-14 14:46:12 -04:00
FPPRust - Implement FPP Manager class in C++
PiperOrigin-RevId: 544182126
This commit is contained in:
committed by
Copybara-Service
parent
d55caf0c4b
commit
f0f0643754
@@ -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",
|
||||
],
|
||||
}),
|
||||
)
|
||||
@@ -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
|
||||
|
||||
@@ -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<u64, ProximityEstimate>,
|
||||
transition_history: VecDeque<ProximityState>,
|
||||
@@ -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<ProximityEstimate> {
|
||||
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<ProximityEstimate> {
|
||||
self.best_proximity_estimate_per_device
|
||||
.get(&device_id)
|
||||
.copied()
|
||||
self.best_proximity_estimate_per_device.get(&device_id).copied()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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 <cstdint>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
|
||||
#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<int8_t> 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<int8_t> 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<RangingData> 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<float>(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<DeviceMotion>()};
|
||||
}
|
||||
|
||||
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
|
||||
@@ -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 <cstdint>
|
||||
#include <optional>
|
||||
|
||||
#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<int8_t> 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<RangingData> GetRangingData(uint64_t device_id);
|
||||
|
||||
private:
|
||||
void CheckPresenceZoneChanged(uint64_t device_id,
|
||||
ProximityEstimate old_estimate,
|
||||
ProximityEstimate new_estimate);
|
||||
absl::flat_hash_map<uint64_t, ProximityEstimate> current_proximity_estimates_;
|
||||
absl::flat_hash_map<uint64_t, ZoneTransitionCallback>
|
||||
zone_transition_callbacks_;
|
||||
PresenceDetectorHandle presence_detector_handle_;
|
||||
};
|
||||
} // namespace presence
|
||||
} // namespace nearby
|
||||
|
||||
#endif // THIRD_PARTY_NEARBY_PRESENCE_FPP_FPP_MANAGER_H_
|
||||
@@ -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 <cstdint>
|
||||
|
||||
#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
|
||||
@@ -15,8 +15,8 @@
|
||||
#ifndef THIRD_PARTY_NEARBY_PRESENCE_IMPLEMENTATION_SENSOR_FUSION_H_
|
||||
#define THIRD_PARTY_NEARBY_PRESENCE_IMPLEMENTATION_SENSOR_FUSION_H_
|
||||
|
||||
#include <cstdint>
|
||||
#include <functional>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "absl/types/optional.h"
|
||||
@@ -52,7 +52,7 @@ struct ZoneTransition {
|
||||
};
|
||||
|
||||
struct RangingData {
|
||||
std::vector<DataSource> data_sources;
|
||||
DataSource data_source;
|
||||
RangingPosition position;
|
||||
absl::optional<ZoneTransition> zone_transition;
|
||||
std::vector<DeviceMotion> device_motions;
|
||||
@@ -64,7 +64,7 @@ class SensorFusion {
|
||||
|
||||
// Called when the proximity zone to a nearby peer device has changed.
|
||||
typedef std::function<void(
|
||||
std::string device_id,
|
||||
uint64_t device_id,
|
||||
PresenceZone::DistanceBoundary::RangeType proximity_zone)>
|
||||
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<int8_t> 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<RangingData> getRangingData(std::string device_id);
|
||||
virtual absl::optional<RangingData> getRangingData(uint64_t device_id);
|
||||
};
|
||||
|
||||
} // namespace presence
|
||||
|
||||
Reference in New Issue
Block a user