summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndroid Build Coastguard Worker <android-build-coastguard-worker@google.com>2022-07-21 20:35:26 +0000
committerAndroid Build Coastguard Worker <android-build-coastguard-worker@google.com>2022-07-21 20:35:26 +0000
commitae7b20087858ddb4019e59f799658e85732c1cc3 (patch)
tree3bb1202e781ae4a03690f444889db8d34e60b201
parent3007b82d01ba24fd57b29b3332ed84e0b3a867a7 (diff)
parente177c03e15f8d05ca724173217f9cb43f8efed87 (diff)
downloaduwb-android13-mainline-go-media-release.tar.gz
Snap for 8857176 from e177c03e15f8d05ca724173217f9cb43f8efed87 to mainline-go-media-releaseaml_go_med_330913000android13-mainline-go-media-release
Change-Id: I4233d2c0bc3403abae3d7fc76a59e114763af80b
-rw-r--r--src/rust/uwb_core/Cargo.toml9
-rw-r--r--src/rust/uwb_core/rustfmt.toml1
-rw-r--r--src/rust/uwb_core/src/session/session_manager.rs98
-rw-r--r--src/rust/uwb_core/src/uci.rs1
-rw-r--r--src/rust/uwb_core/src/uci/mock_uci_manager.rs6
-rw-r--r--src/rust/uwb_core/src/uci/notification.rs6
-rw-r--r--src/rust/uwb_core/src/uci/response.rs4
-rw-r--r--src/rust/uwb_core/src/uci/uci_manager.rs4
-rw-r--r--src/rust/uwb_core/src/uci/uci_manager_sync.rs344
-rw-r--r--src/rust/uwb_uci_packets/uci_packets.pdl56
10 files changed, 514 insertions, 15 deletions
diff --git a/src/rust/uwb_core/Cargo.toml b/src/rust/uwb_core/Cargo.toml
index a22cd90..c9294f1 100644
--- a/src/rust/uwb_core/Cargo.toml
+++ b/src/rust/uwb_core/Cargo.toml
@@ -4,15 +4,14 @@ version = "0.0.1"
edition = "2018"
[dependencies]
-async-trait = "0.1.52"
+async-trait = "0.1.32"
bytes = "1.1.0"
-num-traits = "0.2.14"
log = "0.4.14"
+num-traits = "0.2.12"
thiserror = "1.0.30"
-tokio = {version = "1.14.0", features = ["sync", "rt", "macros", "time"]}
+tokio = { version = "1.14.0", features = ["macros", "rt", "rt-multi-thread", "sync", "time"] }
-uwb_uci_packets = { path = "../uwb_uci_packets"}
+uwb_uci_packets = { path = "../uwb_uci_packets" } # provided by ebuild
[dev-dependencies]
env_logger = "0.9.0"
-tokio = {version = "1.14.0", features = ["rt-multi-thread"]}
diff --git a/src/rust/uwb_core/rustfmt.toml b/src/rust/uwb_core/rustfmt.toml
index 12c133b..5831856 100644
--- a/src/rust/uwb_core/rustfmt.toml
+++ b/src/rust/uwb_core/rustfmt.toml
@@ -1,3 +1,4 @@
edition = "2018"
use_small_heuristics = "Max"
newline_style = "Unix"
+max_width = 100 \ No newline at end of file
diff --git a/src/rust/uwb_core/src/session/session_manager.rs b/src/rust/uwb_core/src/session/session_manager.rs
index 8233766..f2280ad 100644
--- a/src/rust/uwb_core/src/session/session_manager.rs
+++ b/src/rust/uwb_core/src/session/session_manager.rs
@@ -481,6 +481,7 @@ mod tests {
SetAppConfigResponse, StatusCode,
};
use crate::params::utils::{u32_to_bytes, u64_to_bytes, u8_to_bytes};
+ use crate::params::{FiraAppConfigParamsBuilder, KeyRotation};
use crate::uci::notification::UciNotification;
#[tokio::test]
@@ -889,4 +890,101 @@ mod tests {
assert!(mock_uci_manager.wait_expected_calls_done().await);
}
+
+ #[tokio::test]
+ async fn test_reconfigure_app_config() {
+ let session_id = 0x123;
+ let session_type = SessionType::FiraRangingSession;
+
+ let initial_params = generate_params();
+ let initial_tlvs = initial_params.generate_tlvs();
+
+ let non_default_key_rotation_val = KeyRotation::Enable;
+ let idle_params = FiraAppConfigParamsBuilder::from_params(&initial_params)
+ .unwrap()
+ .key_rotation(non_default_key_rotation_val)
+ .build()
+ .unwrap();
+ let idle_tlvs = idle_params
+ .generate_updated_tlvs(&initial_params, SessionState::SessionStateIdle)
+ .unwrap();
+
+ let non_default_block_stride_val = 2u8;
+ let active_params = FiraAppConfigParamsBuilder::from_params(&idle_params)
+ .unwrap()
+ .block_stride_length(non_default_block_stride_val)
+ .build()
+ .unwrap();
+ let active_tlvs = active_params
+ .generate_updated_tlvs(&idle_params, SessionState::SessionStateIdle)
+ .unwrap();
+
+ let (mut session_manager, mut mock_uci_manager, _) =
+ setup_session_manager(move |uci_manager| {
+ uci_manager.expect_session_init(
+ session_id,
+ session_type,
+ vec![session_status_notf(session_id, SessionState::SessionStateInit)],
+ Ok(()),
+ );
+ uci_manager.expect_session_set_app_config(
+ session_id,
+ initial_tlvs,
+ vec![session_status_notf(session_id, SessionState::SessionStateIdle)],
+ Ok(SetAppConfigResponse {
+ status: StatusCode::UciStatusOk,
+ config_status: vec![],
+ }),
+ );
+ uci_manager.expect_session_set_app_config(
+ session_id,
+ idle_tlvs,
+ vec![],
+ Ok(SetAppConfigResponse {
+ status: StatusCode::UciStatusOk,
+ config_status: vec![],
+ }),
+ );
+ uci_manager.expect_range_start(
+ session_id,
+ vec![session_status_notf(session_id, SessionState::SessionStateActive)],
+ Ok(()),
+ );
+ uci_manager.expect_session_set_app_config(
+ session_id,
+ active_tlvs,
+ vec![],
+ Ok(SetAppConfigResponse {
+ status: StatusCode::UciStatusOk,
+ config_status: vec![],
+ }),
+ );
+ })
+ .await;
+
+ // Reconfiguring without first initing a session should fail.
+ let result = session_manager.reconfigure(session_id, initial_params.clone()).await;
+ assert_eq!(result, Err(Error::BadParameters));
+
+ let result =
+ session_manager.init_session(session_id, session_type, initial_params.clone()).await;
+ assert_eq!(result, Ok(()));
+
+ // Reconfiguring any parameters during idle state should succeed.
+ let result = session_manager.reconfigure(session_id, idle_params.clone()).await;
+ assert_eq!(result, Ok(()));
+
+ let result = session_manager.start_ranging(session_id).await;
+ assert_eq!(result, Ok(idle_params));
+
+ // Reconfiguring most parameters during active state should fail.
+ let result = session_manager.reconfigure(session_id, initial_params).await;
+ assert_eq!(result, Err(Error::BadParameters));
+
+ // Only some parameters are allowed to be reconfigured during active state.
+ let result = session_manager.reconfigure(session_id, active_params).await;
+ assert_eq!(result, Ok(()));
+
+ assert!(mock_uci_manager.wait_expected_calls_done().await);
+ }
}
diff --git a/src/rust/uwb_core/src/uci.rs b/src/rust/uwb_core/src/uci.rs
index 38456ad..55fe794 100644
--- a/src/rust/uwb_core/src/uci.rs
+++ b/src/rust/uwb_core/src/uci.rs
@@ -24,6 +24,7 @@ pub(crate) mod notification;
pub(crate) mod uci_manager;
pub mod uci_hal;
+pub mod uci_manager_sync;
#[cfg(test)]
pub(crate) mod mock_uci_hal;
diff --git a/src/rust/uwb_core/src/uci/mock_uci_manager.rs b/src/rust/uwb_core/src/uci/mock_uci_manager.rs
index 9a9eaac..6b9086d 100644
--- a/src/rust/uwb_core/src/uci/mock_uci_manager.rs
+++ b/src/rust/uwb_core/src/uci/mock_uci_manager.rs
@@ -166,7 +166,7 @@ impl MockUciManager {
});
}
- pub fn expect_session_get_count(&mut self, out: Result<usize>) {
+ pub fn expect_session_get_count(&mut self, out: Result<u8>) {
self.expected_calls.lock().unwrap().push_back(ExpectedCall::SessionGetCount { out });
}
@@ -516,7 +516,7 @@ impl UciManager for MockUciManager {
}
}
- async fn session_get_count(&mut self) -> Result<usize> {
+ async fn session_get_count(&mut self) -> Result<u8> {
let mut expected_calls = self.expected_calls.lock().unwrap();
match expected_calls.pop_front() {
Some(ExpectedCall::SessionGetCount { out }) => {
@@ -742,7 +742,7 @@ enum ExpectedCall {
out: Result<Vec<AppConfigTlv>>,
},
SessionGetCount {
- out: Result<usize>,
+ out: Result<u8>,
},
SessionGetState {
expected_session_id: SessionId,
diff --git a/src/rust/uwb_core/src/uci/notification.rs b/src/rust/uwb_core/src/uci/notification.rs
index 714aeb1..79d382e 100644
--- a/src/rust/uwb_core/src/uci/notification.rs
+++ b/src/rust/uwb_core/src/uci/notification.rs
@@ -25,20 +25,20 @@ use crate::params::uci_packets::{
};
#[derive(Debug, Clone, PartialEq)]
-pub(crate) enum UciNotification {
+pub enum UciNotification {
Core(CoreNotification),
Session(SessionNotification),
Vendor(RawVendorMessage),
}
#[derive(Debug, Clone, PartialEq)]
-pub(crate) enum CoreNotification {
+pub enum CoreNotification {
DeviceStatus(DeviceState),
GenericError(StatusCode),
}
#[derive(Debug, Clone, PartialEq)]
-pub(crate) enum SessionNotification {
+pub enum SessionNotification {
Status {
session_id: SessionId,
session_state: SessionState,
diff --git a/src/rust/uwb_core/src/uci/response.rs b/src/rust/uwb_core/src/uci/response.rs
index 0037a0c..efcf466 100644
--- a/src/rust/uwb_core/src/uci/response.rs
+++ b/src/rust/uwb_core/src/uci/response.rs
@@ -38,7 +38,7 @@ pub(super) enum UciResponse {
SessionDeinit(Result<()>),
SessionSetAppConfig(SetAppConfigResponse),
SessionGetAppConfig(Result<Vec<AppConfigTlv>>),
- SessionGetCount(Result<usize>),
+ SessionGetCount(Result<u8>),
SessionGetState(Result<SessionState>),
SessionUpdateControllerMulticastList(Result<()>),
RangeStart(Result<()>),
@@ -156,7 +156,7 @@ impl TryFrom<uwb_uci_packets::SessionResponsePacket> for UciResponse {
Ok(UciResponse::SessionDeinit(status_code_to_result(evt.get_status())))
}
SessionResponseChild::SessionGetCountRsp(evt) => Ok(UciResponse::SessionGetCount(
- status_code_to_result(evt.get_status()).map(|_| evt.get_session_count() as usize),
+ status_code_to_result(evt.get_status()).map(|_| evt.get_session_count()),
)),
SessionResponseChild::SessionGetStateRsp(evt) => Ok(UciResponse::SessionGetState(
status_code_to_result(evt.get_status()).map(|_| evt.get_session_state()),
diff --git a/src/rust/uwb_core/src/uci/uci_manager.rs b/src/rust/uwb_core/src/uci/uci_manager.rs
index 2a4d682..b86f862 100644
--- a/src/rust/uwb_core/src/uci/uci_manager.rs
+++ b/src/rust/uwb_core/src/uci/uci_manager.rs
@@ -92,7 +92,7 @@ pub(crate) trait UciManager: 'static + Send + Clone {
session_id: SessionId,
config_ids: Vec<AppConfigTlvType>,
) -> Result<Vec<AppConfigTlv>>;
- async fn session_get_count(&mut self) -> Result<usize>;
+ async fn session_get_count(&mut self) -> Result<u8>;
async fn session_get_state(&mut self, session_id: SessionId) -> Result<SessionState>;
async fn session_update_controller_multicast_list(
&mut self,
@@ -285,7 +285,7 @@ impl UciManager for UciManagerImpl {
}
}
- async fn session_get_count(&mut self) -> Result<usize> {
+ async fn session_get_count(&mut self) -> Result<u8> {
let cmd = UciCommand::SessionGetCount;
match self.send_cmd(UciManagerCmd::SendUciCommand { cmd }).await {
Ok(UciResponse::SessionGetCount(resp)) => resp,
diff --git a/src/rust/uwb_core/src/uci/uci_manager_sync.rs b/src/rust/uwb_core/src/uci/uci_manager_sync.rs
new file mode 100644
index 0000000..027a98d
--- /dev/null
+++ b/src/rust/uwb_core/src/uci/uci_manager_sync.rs
@@ -0,0 +1,344 @@
+// Copyright 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.
+
+//! This module offers a synchornized interface at UCI level.
+//!
+//! The module is designed with the replacement for Android UCI JNI adaptation in mind. The handling
+//! of UciNotifications is different in UciManager and UciManagerSync as the sync version has its
+//! behavior aligned with the Android JNI UCI, and routes the UciNotifications to NotificationManager.
+
+use log::{error, info};
+use tokio::runtime::Runtime;
+use tokio::sync::mpsc;
+
+use crate::error::Result;
+use crate::params::{
+ AppConfigTlv, AppConfigTlvType, CapTlv, Controlee, CoreSetConfigResponse, CountryCode,
+ DeviceConfigId, DeviceConfigTlv, GetDeviceInfoResponse, PowerStats, RawVendorMessage,
+ ResetConfig, SessionId, SessionState, SessionType, SetAppConfigResponse,
+ UpdateMulticastListAction,
+};
+use crate::uci::notification::{CoreNotification, SessionNotification};
+use crate::uci::uci_hal::UciHal;
+use crate::uci::uci_manager::{UciManager, UciManagerImpl};
+
+/// The NotificationManager trait is needed to process UciNotification relayed from UciManagerSync.
+///
+/// The UciManagerSync assumes the NotificationManager takes the responsibility to properly handle
+/// the notifications, including tracking the state of HAL. UciManagerSync and lower levels only
+/// redirect and categorize the notifications. The notifications are processed through callbacks.
+pub trait NotificationManager: 'static + Send {
+ /// Callback for CoreNotification.
+ fn on_core_notification(&mut self, core_notification: CoreNotification) -> Result<()>;
+
+ /// Callback for SessionNotification.
+ fn on_session_notification(&mut self, session_notification: SessionNotification) -> Result<()>;
+
+ /// Callback for RawVendorMessage.
+ fn on_vendor_notification(&mut self, vendor_notification: RawVendorMessage) -> Result<()>;
+}
+struct NotificationDriver<U: NotificationManager> {
+ core_notification_receiver: mpsc::UnboundedReceiver<CoreNotification>,
+ session_notification_receiver: mpsc::UnboundedReceiver<SessionNotification>,
+ vendor_notification_receiver: mpsc::UnboundedReceiver<RawVendorMessage>,
+ notification_manager: U,
+}
+impl<U: NotificationManager> NotificationDriver<U> {
+ fn new(notification_manager: U) -> Self {
+ Self {
+ core_notification_receiver: mpsc::unbounded_channel::<CoreNotification>().1,
+ session_notification_receiver: mpsc::unbounded_channel::<SessionNotification>().1,
+ vendor_notification_receiver: mpsc::unbounded_channel::<RawVendorMessage>().1,
+ notification_manager,
+ }
+ }
+ fn set_core_notification_receiver(
+ &mut self,
+ core_notification_receiver: mpsc::UnboundedReceiver<CoreNotification>,
+ ) {
+ self.core_notification_receiver = core_notification_receiver;
+ }
+ fn set_session_notification_receiver(
+ &mut self,
+ session_notification_receiver: mpsc::UnboundedReceiver<SessionNotification>,
+ ) {
+ self.session_notification_receiver = session_notification_receiver;
+ }
+ fn set_vendor_notification_receiver(
+ &mut self,
+ vendor_notification_receiver: mpsc::UnboundedReceiver<RawVendorMessage>,
+ ) {
+ self.vendor_notification_receiver = vendor_notification_receiver;
+ }
+ async fn run(&mut self) {
+ loop {
+ tokio::select! {
+ Some(ntf) = self.core_notification_receiver.recv() =>{
+ self.notification_manager.on_core_notification(ntf).unwrap_or_else(|e|{
+ error!("NotificationDriver: CoreNotification callback error: {:?}",e);
+ });
+ }
+ Some(ntf) = self.session_notification_receiver.recv() =>{
+ self.notification_manager.on_session_notification(ntf).unwrap_or_else(|e|{
+ error!("NotificationDriver: SessionNotification callback error: {:?}",e);
+ });
+ }
+ Some(ntf) = self.vendor_notification_receiver.recv() =>{
+ self.notification_manager.on_vendor_notification(ntf).unwrap_or_else(|e|{
+ error!("NotificationDriver: RawVendorMessage callback error: {:?}",e);
+ });
+ }
+ else =>{
+ info!("NotificationDriver dropping.");
+ }
+ }
+ }
+ }
+}
+/// The UciManagerSync provides a synchornized version of UciManager using the runtime supplied
+/// at its initialization.
+///
+/// Note the processing of UciNotification is different: they are handled by NotificationManager
+/// provided at construction, and the async version set_X_notification_sender methods are removed.
+pub struct UciManagerSync {
+ runtime: Runtime,
+ uci_manager_impl: UciManagerImpl,
+}
+impl UciManagerSync {
+ /// UciHal and NotificationManager required at construction as they are required before open_hal
+ /// called. runtime is taken with ownership for blocking on async steps only.
+ pub fn new<T: UciHal, U: NotificationManager>(
+ runtime: Runtime,
+ hal: T,
+ notification_manager: U,
+ ) -> Self {
+ // UciManagerImpl::new uses tokio::spawn, so it is called inside the runtime as async fn.
+ let mut uci_manager_impl = runtime.block_on(async { UciManagerImpl::new(hal) });
+ let mut notification_driver = NotificationDriver::new(notification_manager);
+ runtime.block_on(async {
+ let (core_notification_sender, core_notification_receiver) =
+ mpsc::unbounded_channel::<CoreNotification>();
+ uci_manager_impl.set_core_notification_sender(core_notification_sender).await;
+ notification_driver.set_core_notification_receiver(core_notification_receiver);
+ });
+ runtime.block_on(async {
+ let (session_notification_sender, session_notification_receiver) =
+ mpsc::unbounded_channel::<SessionNotification>();
+ uci_manager_impl.set_session_notification_sender(session_notification_sender).await;
+ notification_driver.set_session_notification_receiver(session_notification_receiver);
+ });
+ runtime.block_on(async {
+ let (vendor_notification_sender, vendor_notification_receiver) =
+ mpsc::unbounded_channel::<RawVendorMessage>();
+ uci_manager_impl.set_vendor_notification_sender(vendor_notification_sender).await;
+ notification_driver.set_vendor_notification_receiver(vendor_notification_receiver);
+ });
+ runtime.spawn(async move { notification_driver.run().await });
+ Self { runtime, uci_manager_impl }
+ }
+
+ /// Start UCI HAL and blocking until UCI commands can be sent.
+ pub fn open_hal(&mut self) -> Result<()> {
+ self.runtime.block_on(self.uci_manager_impl.open_hal())
+ }
+
+ /// Stop the UCI HAL.
+ pub fn close_hal(&mut self, force: bool) -> Result<()> {
+ self.runtime.block_on(self.uci_manager_impl.close_hal(force))
+ }
+
+ // Methods for sending UCI commands. Functions are blocked until UCI response is received.
+ /// Send UCI command for device reset.
+ pub fn device_reset(&mut self, reset_config: ResetConfig) -> Result<()> {
+ self.runtime.block_on(self.uci_manager_impl.device_reset(reset_config))
+ }
+
+ /// Send UCI command for getting device info.
+ pub fn core_get_device_info(&mut self) -> Result<GetDeviceInfoResponse> {
+ self.runtime.block_on(self.uci_manager_impl.core_get_device_info())
+ }
+
+ /// Send UCI command for getting capability info
+ pub fn core_get_caps_info(&mut self) -> Result<Vec<CapTlv>> {
+ self.runtime.block_on(self.uci_manager_impl.core_get_caps_info())
+ }
+
+ /// Send UCI command for setting core configuration.
+ pub fn core_set_config(
+ &mut self,
+ config_tlvs: Vec<DeviceConfigTlv>,
+ ) -> Result<CoreSetConfigResponse> {
+ self.runtime.block_on(self.uci_manager_impl.core_set_config(config_tlvs))
+ }
+
+ /// Send UCI command for getting core configuration.
+ pub fn core_get_config(
+ &mut self,
+ config_ids: Vec<DeviceConfigId>,
+ ) -> Result<Vec<DeviceConfigTlv>> {
+ self.runtime.block_on(self.uci_manager_impl.core_get_config(config_ids))
+ }
+
+ /// Send UCI command for initiating session.
+ pub fn session_init(&mut self, session_id: SessionId, session_type: SessionType) -> Result<()> {
+ self.runtime.block_on(self.uci_manager_impl.session_init(session_id, session_type))
+ }
+
+ /// Send UCI command for deinitiating session.
+ pub fn session_deinit(&mut self, session_id: SessionId) -> Result<()> {
+ self.runtime.block_on(self.uci_manager_impl.session_deinit(session_id))
+ }
+
+ /// Send UCI command for setting app config.
+ pub fn session_set_app_config(
+ &mut self,
+ session_id: SessionId,
+ config_tlvs: Vec<AppConfigTlv>,
+ ) -> Result<SetAppConfigResponse> {
+ self.runtime.block_on(self.uci_manager_impl.session_set_app_config(session_id, config_tlvs))
+ }
+
+ /// Send UCI command for getting app config.
+ pub fn session_get_app_config(
+ &mut self,
+ session_id: SessionId,
+ config_ids: Vec<AppConfigTlvType>,
+ ) -> Result<Vec<AppConfigTlv>> {
+ self.runtime.block_on(self.uci_manager_impl.session_get_app_config(session_id, config_ids))
+ }
+
+ /// Send UCI command for getting count of sessions.
+ pub fn session_get_count(&mut self) -> Result<u8> {
+ self.runtime.block_on(self.uci_manager_impl.session_get_count())
+ }
+
+ /// Send UCI command for getting state of session.
+ pub fn session_get_state(&mut self, session_id: SessionId) -> Result<SessionState> {
+ self.runtime.block_on(self.uci_manager_impl.session_get_state(session_id))
+ }
+
+ /// Send UCI command for updating multicast list for multicast session.
+ pub fn session_update_controller_multicast_list(
+ &mut self,
+ session_id: SessionId,
+ action: UpdateMulticastListAction,
+ controlees: Vec<Controlee>,
+ ) -> Result<()> {
+ self.runtime.block_on(
+ self.uci_manager_impl
+ .session_update_controller_multicast_list(session_id, action, controlees),
+ )
+ }
+
+ /// Send UCI command for starting ranging of the session.
+ pub fn range_start(&mut self, session_id: SessionId) -> Result<()> {
+ self.runtime.block_on(self.uci_manager_impl.range_start(session_id))
+ }
+
+ /// Send UCI command for stopping ranging of the session.
+ pub fn range_stop(&mut self, session_id: SessionId) -> Result<()> {
+ self.runtime.block_on(self.uci_manager_impl.range_stop(session_id))
+ }
+
+ /// Send UCI command for getting ranging count.
+ pub fn range_get_ranging_count(&mut self, session_id: SessionId) -> Result<usize> {
+ self.runtime.block_on(self.uci_manager_impl.range_get_ranging_count(session_id))
+ }
+
+ /// Set the country code. Android-specific method.
+ pub fn android_set_country_code(&mut self, country_code: CountryCode) -> Result<()> {
+ self.runtime.block_on(self.uci_manager_impl.android_set_country_code(country_code))
+ }
+
+ /// Get the power statistics. Android-specific method.
+ pub fn android_get_power_stats(&mut self) -> Result<PowerStats> {
+ self.runtime.block_on(self.uci_manager_impl.android_get_power_stats())
+ }
+
+ /// Send UCI command for a vendor-specific message.
+ pub fn raw_vendor_cmd(
+ &mut self,
+ gid: u32,
+ oid: u32,
+ payload: Vec<u8>,
+ ) -> Result<RawVendorMessage> {
+ self.runtime.block_on(self.uci_manager_impl.raw_vendor_cmd(gid, oid, payload))
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ use tokio::runtime::Builder;
+ use uwb_uci_packets::DeviceState;
+
+ use crate::error::Error;
+ use crate::uci::mock_uci_hal::MockUciHal;
+ use crate::uci::uci_hal::RawUciMessage;
+
+ struct MockNotificationManager {
+ device_state_sender: mpsc::UnboundedSender<DeviceState>,
+ }
+ impl MockNotificationManager {
+ fn new(device_state_sender: mpsc::UnboundedSender<DeviceState>) -> Self {
+ MockNotificationManager { device_state_sender }
+ }
+ }
+ impl NotificationManager for MockNotificationManager {
+ fn on_core_notification(&mut self, core_notification: CoreNotification) -> Result<()> {
+ match core_notification {
+ CoreNotification::DeviceStatus(device_state) => {
+ self.device_state_sender.send(device_state).map_err(|_| Error::Unknown)?;
+ }
+ CoreNotification::GenericError(_) => {}
+ };
+ Ok(())
+ }
+ fn on_session_notification(
+ &mut self,
+ _session_notification: SessionNotification,
+ ) -> Result<()> {
+ Ok(())
+ }
+ fn on_vendor_notification(&mut self, _vendor_notification: RawVendorMessage) -> Result<()> {
+ Ok(())
+ }
+ }
+ fn into_raw_messages<T: Into<uwb_uci_packets::UciPacketPacket>>(
+ builder: T,
+ ) -> Vec<RawUciMessage> {
+ let packets: Vec<uwb_uci_packets::UciPacketHalPacket> = builder.into().into();
+ packets.into_iter().map(|packet| packet.into()).collect()
+ }
+ #[test]
+ fn test_sync_uci_open_hal() {
+ let mut hal = MockUciHal::new();
+ let notf = into_raw_messages(uwb_uci_packets::DeviceStatusNtfBuilder {
+ device_state: uwb_uci_packets::DeviceState::DeviceStateReady,
+ });
+ hal.expected_open(Some(notf), Ok(()));
+ let test_rt = Builder::new_multi_thread().enable_all().build().unwrap();
+ let (device_state_sender, mut device_state_receiver) =
+ mpsc::unbounded_channel::<DeviceState>();
+ let mut uci_manager_sync = UciManagerSync::new(
+ Builder::new_multi_thread().enable_all().build().unwrap(),
+ hal,
+ MockNotificationManager::new(device_state_sender),
+ );
+ assert!(uci_manager_sync.open_hal().is_ok());
+ let device_state = test_rt.block_on(async { device_state_receiver.recv().await });
+ assert_eq!(device_state, Some(DeviceState::DeviceStateReady));
+ }
+}
diff --git a/src/rust/uwb_uci_packets/uci_packets.pdl b/src/rust/uwb_uci_packets/uci_packets.pdl
index 3ad5d5f..28263fb 100644
--- a/src/rust/uwb_uci_packets/uci_packets.pdl
+++ b/src/rust/uwb_uci_packets/uci_packets.pdl
@@ -57,6 +57,7 @@ enum AppDataOpCode : 6 {
enum AndroidOpCode : 6 {
ANDROID_GET_POWER_STATS = 0x0,
ANDROID_SET_COUNTRY_CODE = 0x1,
+ ANDROID_FIRA_RANGE_DIAGNOSTICS = 0x2,
}
enum StatusCode : 8 {
@@ -177,6 +178,15 @@ enum AppConfigTlvType : 8 {
NB_OF_RANGE_MEASUREMENTS = 0xE3,
NB_OF_AZIMUTH_MEASUREMENTS = 0xE4,
NB_OF_ELEVATION_MEASUREMENTS = 0xE5,
+
+ ENABLE_DIAGNOSTICS = 0xE8,
+ DIAGRAMS_FRAME_REPORTS_FIELDS = 0xE9,
+}
+
+enum FrameReportTlvType : 8 {
+ RSSI = 0x0,
+ AOA = 0x1,
+ CIR = 0x2,
}
enum CapTlvType : 8 {
@@ -827,6 +837,52 @@ test AndroidSetCountryCodeRsp {
"\x4c\x01\x00\x01\x00\x00\x00\x00",
}
+struct FrameReportTlv {
+ t: FrameReportTlvType,
+ length: 8,
+ v: 8[],
+}
+
+packet AoaMeasurement {
+ tdoa: 16,
+ pdoa: 16,
+ aoa: 16,
+ fom: 8,
+ t: 8,
+}
+
+packet Cir {
+ first_path_index : 16,
+ first_path_snr: 16,
+ first_path_ns: 16,
+ peak_path_index: 16,
+ peak_path_snr: 16,
+ peak_path_ns: 16,
+ first_path_sample_offset: 8,
+ sample_size: 8,
+ samples_number: 8,
+ sample_window: 8[],
+}
+
+struct FrameReport {
+ uwb_msg_id: 8,
+ action: 8,
+ antenna_set: 8,
+ _count_(frame_report_tlvs): 8,
+ frame_report_tlvs: FrameReportTlv[],
+}
+
+packet AndroidFiraRangeDiagnosticsNtf : AndroidNotification (opcode = 0x2) { //QORVO_FIRA_RANGE_DIAGNOSTICS
+ session_id: 32,
+ sequence_number: 32,
+ _count_(frame_reports): 8,
+ frame_reports: FrameReport[],
+}
+
+test AndroidFiraRangeDiagnosticsNtf {
+ "\x6c\x02\x00\x10\x00\x00\x00\x01\x01\x01\x01\x02\x02\x02\x02\x01\x00\x01\x02\x01\x00\x01\x00",
+}
+
packet UciVendor_9_Command : UciCommand (group_id = VENDOR_RESERVED_9) {
_payload_,
}