diff options
author | Android Build Coastguard Worker <android-build-coastguard-worker@google.com> | 2023-10-16 20:21:59 +0000 |
---|---|---|
committer | Android Build Coastguard Worker <android-build-coastguard-worker@google.com> | 2023-10-16 20:21:59 +0000 |
commit | ef4a95ceb69fcad719a2b87b25f8dd7bfc5b5d79 (patch) | |
tree | 576362cb77c8ca2a427821afdd65110a100e39bf | |
parent | 916812682d317bf2f25cafc63ed2e4ca03dc141b (diff) | |
parent | 85f38f76787c158c3b2fdc3ac115aa5f8412958c (diff) | |
download | uwb-ef4a95ceb69fcad719a2b87b25f8dd7bfc5b5d79.tar.gz |
Snap for 10957012 from 85f38f76787c158c3b2fdc3ac115aa5f8412958c to simpleperf-release
Change-Id: Ib048ae20b5ed38b1d45e2b42f470af52151dba92
-rw-r--r-- | src/TEST_MAPPING | 3 | ||||
-rw-r--r-- | src/rust/uwb_core/protos/uwb_service.proto | 2 | ||||
-rw-r--r-- | src/rust/uwb_core/src/params/uci_packets.rs | 33 | ||||
-rw-r--r-- | src/rust/uwb_core/src/proto/mappings.rs | 3 | ||||
-rw-r--r-- | src/rust/uwb_core/src/service/uwb_service.rs | 25 | ||||
-rw-r--r-- | src/rust/uwb_core/src/session/session_manager.rs | 13 | ||||
-rw-r--r-- | src/rust/uwb_core/src/uci.rs | 4 | ||||
-rw-r--r-- | src/rust/uwb_core/src/uci/command.rs | 49 | ||||
-rw-r--r-- | src/rust/uwb_core/src/uci/mock_uci_manager.rs | 127 | ||||
-rw-r--r-- | src/rust/uwb_core/src/uci/notification.rs | 158 | ||||
-rw-r--r-- | src/rust/uwb_core/src/uci/response.rs | 30 | ||||
-rw-r--r-- | src/rust/uwb_core/src/uci/uci_manager.rs | 332 | ||||
-rw-r--r-- | src/rust/uwb_core/src/uci/uci_manager_sync.rs | 78 | ||||
-rw-r--r-- | src/rust/uwb_uci_packets/src/lib.rs | 49 | ||||
-rw-r--r-- | src/rust/uwb_uci_packets/uci_packets.pdl | 112 |
15 files changed, 910 insertions, 108 deletions
diff --git a/src/TEST_MAPPING b/src/TEST_MAPPING index 4676de2..3713fda 100644 --- a/src/TEST_MAPPING +++ b/src/TEST_MAPPING @@ -5,6 +5,9 @@ }, { "name": "libuwb_core_tests" + }, + { + "name": "CtsUwbTestCases" } ] } diff --git a/src/rust/uwb_core/protos/uwb_service.proto b/src/rust/uwb_core/protos/uwb_service.proto index e979bcc..d7c4c38 100644 --- a/src/rust/uwb_core/protos/uwb_service.proto +++ b/src/rust/uwb_core/protos/uwb_service.proto @@ -76,6 +76,7 @@ enum StatusCode { UCI_STATUS_UNKNOWN_OID = 8; UCI_STATUS_READ_ONLY = 9; UCI_STATUS_COMMAND_RETRY = 10; + UCI_STATUS_UNKNOWN = 11; UCI_STATUS_SESSION_NOT_EXIST = 17; UCI_STATUS_SESSION_DUPLICATE = 18; @@ -194,6 +195,7 @@ enum SessionType { FIRA_IN_BAND_DATA_PHASE = 0x04; FIRA_RANGING_WITH_DATA_PHASE = 0x05; CCC = 0xA0; + RADAR_SESSION = 0xA1; DEVICE_TEST_MODE = 0xD0; } diff --git a/src/rust/uwb_core/src/params/uci_packets.rs b/src/rust/uwb_core/src/params/uci_packets.rs index 23597ce..e3a7722 100644 --- a/src/rust/uwb_core/src/params/uci_packets.rs +++ b/src/rust/uwb_core/src/params/uci_packets.rs @@ -20,13 +20,14 @@ use std::iter::FromIterator; // Re-export enums and structs from uwb_uci_packets. pub use uwb_uci_packets::{ - AppConfigStatus, AppConfigTlv as RawAppConfigTlv, AppConfigTlvType, CapTlv, CapTlvType, - Controlee, ControleeStatus, Controlees, CreditAvailability, DataRcvStatusCode, + AppConfigStatus, AppConfigTlv as RawAppConfigTlv, AppConfigTlvType, BitsPerSample, CapTlv, + CapTlvType, Controlee, ControleeStatus, Controlees, CreditAvailability, DataRcvStatusCode, DataTransferNtfStatusCode, DeviceConfigId, DeviceConfigStatus, DeviceConfigTlv, DeviceState, ExtendedAddressDlTdoaRangingMeasurement, ExtendedAddressOwrAoaRangingMeasurement, ExtendedAddressTwoWayRangingMeasurement, GroupId, MessageType, MulticastUpdateStatusCode, - PhaseList, PowerStats, RangingMeasurementType, ReasonCode, ResetConfig, SessionState, - SessionType, ShortAddressDlTdoaRangingMeasurement, ShortAddressOwrAoaRangingMeasurement, + PhaseList, PowerStats, RadarConfigStatus, RadarConfigTlv, RadarConfigTlvType, RadarDataType, + RangingMeasurementType, ReasonCode, ResetConfig, SessionState, SessionType, + ShortAddressDlTdoaRangingMeasurement, ShortAddressOwrAoaRangingMeasurement, ShortAddressTwoWayRangingMeasurement, StatusCode, UpdateMulticastListAction, }; pub(crate) use uwb_uci_packets::{UciControlPacket, UciDataPacket, UciDataPacketHal}; @@ -124,6 +125,19 @@ fn device_config_tlvs_to_map( HashMap::from_iter(tlvs.iter().map(|config| (config.cfg_id, &config.v))) } +/// Compare if two RadarConfigTlv array are equal. Convert the array to HashMap before comparing +/// because the order of TLV elements doesn't matter. +#[allow(dead_code)] +pub fn radar_config_tlvs_eq(a: &[RadarConfigTlv], b: &[RadarConfigTlv]) -> bool { + radar_config_tlvs_to_map(a) == radar_config_tlvs_to_map(b) +} + +fn radar_config_tlvs_to_map( + tlvs: &[RadarConfigTlv], +) -> HashMap<RadarConfigTlvType, &Vec<u8>, RandomState> { + HashMap::from_iter(tlvs.iter().map(|config| (config.cfg_id, &config.v))) +} + /// The response of the UciManager::core_set_config() method. #[derive(Debug, Clone, PartialEq)] pub struct CoreSetConfigResponse { @@ -142,6 +156,15 @@ pub struct SetAppConfigResponse { pub config_status: Vec<AppConfigStatus>, } +/// The response of the UciManager::android_set_radar_config() method. +#[derive(Debug, Clone, PartialEq)] +pub struct AndroidRadarConfigResponse { + /// The status code of the response. + pub status: StatusCode, + /// The status of each config TLV. + pub config_status: Vec<RadarConfigStatus>, +} + /// The response from UciManager::session_update_dt_tag_ranging_rounds() method. #[derive(Debug, Clone, PartialEq, Eq)] pub struct SessionUpdateDtTagRangingRoundsResponse { @@ -204,6 +227,8 @@ impl From<UpdateTime> for [u8; 8] { /// The response of the UciManager::core_get_device_info() method. #[derive(Debug, Clone, PartialEq, Eq)] pub struct GetDeviceInfoResponse { + /// Status + pub status: StatusCode, /// The UCI version. pub uci_version: u16, /// The MAC version. diff --git a/src/rust/uwb_core/src/proto/mappings.rs b/src/rust/uwb_core/src/proto/mappings.rs index 1b14711..c10cf0e 100644 --- a/src/rust/uwb_core/src/proto/mappings.rs +++ b/src/rust/uwb_core/src/proto/mappings.rs @@ -116,6 +116,7 @@ impl From<ProtoStatusCode> for StatusCode { ProtoStatusCode::UCI_STATUS_UNKNOWN_OID => StatusCode::UciStatusUnknownOid, ProtoStatusCode::UCI_STATUS_READ_ONLY => StatusCode::UciStatusReadOnly, ProtoStatusCode::UCI_STATUS_COMMAND_RETRY => StatusCode::UciStatusCommandRetry, + ProtoStatusCode::UCI_STATUS_UNKNOWN => StatusCode::UciStatusUnknown, ProtoStatusCode::UCI_STATUS_SESSION_NOT_EXIST => StatusCode::UciStatusSessionNotExist, ProtoStatusCode::UCI_STATUS_SESSION_DUPLICATE => StatusCode::UciStatusSessionDuplicate, ProtoStatusCode::UCI_STATUS_SESSION_ACTIVE => StatusCode::UciStatusSessionActive, @@ -199,6 +200,7 @@ impl From<StatusCode> for ProtoStatusCode { StatusCode::UciStatusUnknownOid => ProtoStatusCode::UCI_STATUS_UNKNOWN_OID, StatusCode::UciStatusReadOnly => ProtoStatusCode::UCI_STATUS_READ_ONLY, StatusCode::UciStatusCommandRetry => ProtoStatusCode::UCI_STATUS_COMMAND_RETRY, + StatusCode::UciStatusUnknown => ProtoStatusCode::UCI_STATUS_UNKNOWN, StatusCode::UciStatusSessionNotExist => ProtoStatusCode::UCI_STATUS_SESSION_NOT_EXIST, StatusCode::UciStatusSessionDuplicate => ProtoStatusCode::UCI_STATUS_SESSION_DUPLICATE, StatusCode::UciStatusSessionActive => ProtoStatusCode::UCI_STATUS_SESSION_ACTIVE, @@ -536,6 +538,7 @@ enum_mapping! { FIRA_IN_BAND_DATA_PHASE => FiraInBandDataPhase, FIRA_RANGING_WITH_DATA_PHASE => FiraRangingWithDataPhase, CCC => Ccc, + RADAR_SESSION => RadarSession, DEVICE_TEST_MODE => DeviceTestMode, } diff --git a/src/rust/uwb_core/src/service/uwb_service.rs b/src/rust/uwb_core/src/service/uwb_service.rs index ce00f95..012fbda 100644 --- a/src/rust/uwb_core/src/service/uwb_service.rs +++ b/src/rust/uwb_core/src/service/uwb_service.rs @@ -576,6 +576,7 @@ mod tests { use tokio::runtime::Runtime; use crate::params::uci_packets::{SessionState, SetAppConfigResponse, StatusCode}; + use crate::params::GetDeviceInfoResponse; use crate::service::mock_uwb_service_callback::MockUwbServiceCallback; use crate::service::uwb_service_builder::default_runtime; use crate::service::uwb_service_callback_builder::UwbServiceCallbackSendBuilder; @@ -584,6 +585,16 @@ mod tests { }; use crate::uci::mock_uci_manager::MockUciManager; use crate::uci::notification::UciNotification; + use uwb_uci_packets::StatusCode::UciStatusOk; + + const GET_DEVICE_INFO_RSP: GetDeviceInfoResponse = GetDeviceInfoResponse { + status: UciStatusOk, + uci_version: 0, + mac_version: 0, + phy_version: 0, + uci_test_version: 0, + vendor_spec_info: vec![], + }; fn setup_uwb_service( uci_manager: MockUciManager, @@ -599,7 +610,7 @@ mod tests { #[test] fn test_open_close_uci() { let mut uci_manager = MockUciManager::new(); - uci_manager.expect_open_hal(vec![], Ok(())); + uci_manager.expect_open_hal(vec![], Ok(GET_DEVICE_INFO_RSP)); uci_manager.expect_close_hal(false, Ok(())); let (service, _, _runtime) = setup_uwb_service(uci_manager); @@ -618,7 +629,7 @@ mod tests { let range_data = session_range_data(session_id); let mut uci_manager = MockUciManager::new(); - uci_manager.expect_open_hal(vec![], Ok(())); + uci_manager.expect_open_hal(vec![], Ok(GET_DEVICE_INFO_RSP)); uci_manager.expect_session_init( session_id, session_type, @@ -788,7 +799,7 @@ mod tests { let mut uci_manager = MockUciManager::new(); uci_manager.expect_open_hal( vec![UciNotification::Vendor(RawUciMessage { gid, oid, payload: payload.clone() })], - Ok(()), + Ok(GET_DEVICE_INFO_RSP), ); let (service, mut callback, _runtime) = setup_uwb_service(uci_manager); @@ -804,7 +815,7 @@ mod tests { let mut uci_manager = MockUciManager::new(); uci_manager.expect_open_hal( vec![UciNotification::Core(CoreNotification::DeviceStatus(state))], - Ok(()), + Ok(GET_DEVICE_INFO_RSP), ); let (service, mut callback, _runtime) = setup_uwb_service(uci_manager); callback.expect_on_uci_device_status_changed(state); @@ -819,7 +830,7 @@ mod tests { uci_manager.expect_open_hal(vec![], Err(Error::Timeout)); // Then UwbService should close_hal() and open_hal() to reset the HAL. uci_manager.expect_close_hal(true, Ok(())); - uci_manager.expect_open_hal(vec![], Ok(())); + uci_manager.expect_open_hal(vec![], Ok(GET_DEVICE_INFO_RSP)); let (service, mut callback, _runtime) = setup_uwb_service(uci_manager.clone()); callback.expect_on_service_reset(true); @@ -838,11 +849,11 @@ mod tests { vec![UciNotification::Core(CoreNotification::DeviceStatus( DeviceState::DeviceStateError, ))], - Ok(()), + Ok(GET_DEVICE_INFO_RSP), ); // Then UwbService should close_hal() and open_hal() to reset the HAL. uci_manager.expect_close_hal(true, Ok(())); - uci_manager.expect_open_hal(vec![], Ok(())); + uci_manager.expect_open_hal(vec![], Ok(GET_DEVICE_INFO_RSP)); let (service, mut callback, _runtime) = setup_uwb_service(uci_manager.clone()); callback.expect_on_service_reset(true); diff --git a/src/rust/uwb_core/src/session/session_manager.rs b/src/rust/uwb_core/src/session/session_manager.rs index e49dd9c..449d50d 100644 --- a/src/rust/uwb_core/src/session/session_manager.rs +++ b/src/rust/uwb_core/src/session/session_manager.rs @@ -443,9 +443,20 @@ pub(crate) mod test_utils { use crate::params::uci_packets::{ RangingMeasurementType, ReasonCode, ShortAddressTwoWayRangingMeasurement, StatusCode, }; + use crate::params::GetDeviceInfoResponse; use crate::uci::mock_uci_manager::MockUciManager; use crate::uci::notification::{RangingMeasurements, UciNotification}; use crate::utils::init_test_logging; + use uwb_uci_packets::StatusCode::UciStatusOk; + + const GET_DEVICE_INFO_RSP: GetDeviceInfoResponse = GetDeviceInfoResponse { + status: UciStatusOk, + uci_version: 0, + mac_version: 0, + phy_version: 0, + uci_test_version: 0, + vendor_spec_info: vec![], + }; pub(crate) fn generate_params() -> AppConfigParams { FiraAppConfigParamsBuilder::new() @@ -533,7 +544,7 @@ pub(crate) mod test_utils { let (uci_notf_sender, uci_notf_receiver) = mpsc::unbounded_channel(); let (session_notf_sender, session_notf_receiver) = mpsc::unbounded_channel(); let mut uci_manager = MockUciManager::new(); - uci_manager.expect_open_hal(vec![], Ok(())); + uci_manager.expect_open_hal(vec![], Ok(GET_DEVICE_INFO_RSP)); setup_uci_manager_fn(&mut uci_manager); uci_manager.set_session_notification_sender(uci_notf_sender).await; let _ = uci_manager.open_hal().await; diff --git a/src/rust/uwb_core/src/uci.rs b/src/rust/uwb_core/src/uci.rs index cac1be2..4364966 100644 --- a/src/rust/uwb_core/src/uci.rs +++ b/src/rust/uwb_core/src/uci.rs @@ -41,8 +41,8 @@ pub mod mock_uci_manager; // Re-export the public elements. pub use command::UciCommand; pub use notification::{ - CoreNotification, DataRcvNotification, RangingMeasurements, SessionNotification, - SessionRangeData, UciNotification, + CoreNotification, DataRcvNotification, RadarDataRcvNotification, RadarSweepData, + RangingMeasurements, SessionNotification, SessionRangeData, UciNotification, }; pub use uci_hal::{NopUciHal, UciHal, UciHalPacket}; pub use uci_logger_factory::{NopUciLoggerFactory, UciLoggerFactory}; diff --git a/src/rust/uwb_core/src/uci/command.rs b/src/rust/uwb_core/src/uci/command.rs index 8693073..864ca8f 100644 --- a/src/rust/uwb_core/src/uci/command.rs +++ b/src/rust/uwb_core/src/uci/command.rs @@ -20,9 +20,12 @@ use log::error; use crate::error::{Error, Result}; use crate::params::uci_packets::{ AppConfigTlv, AppConfigTlvType, Controlees, CountryCode, DeviceConfigId, DeviceConfigTlv, - ResetConfig, SessionId, SessionToken, SessionType, UpdateMulticastListAction, UpdateTime, + RadarConfigTlv, RadarConfigTlvType, ResetConfig, SessionId, SessionToken, SessionType, + UpdateMulticastListAction, UpdateTime, +}; +use uwb_uci_packets::{ + build_session_update_controller_multicast_list_cmd, GroupId, MessageType, PhaseList, }; -use uwb_uci_packets::{ build_session_update_controller_multicast_list_cmd, GroupId, MessageType, PhaseList,}; /// The enum to represent the UCI commands. The definition of each field should follow UCI spec. #[allow(missing_docs)] @@ -90,6 +93,14 @@ pub enum UciCommand { country_code: CountryCode, }, AndroidGetPowerStats, + AndroidSetRadarConfig { + session_token: SessionToken, + config_tlvs: Vec<RadarConfigTlv>, + }, + AndroidGetRadarConfig { + session_token: SessionToken, + radar_cfg: Vec<RadarConfigTlvType>, + }, RawUciCmd { mt: u32, gid: u32, @@ -154,6 +165,22 @@ impl TryFrom<UciCommand> for uwb_uci_packets::UciControlPacket { .build() .into() } + UciCommand::AndroidSetRadarConfig { session_token, config_tlvs } => { + uwb_uci_packets::AndroidSetRadarConfigCmdBuilder { + session_token, + tlvs: config_tlvs, + } + .build() + .into() + } + UciCommand::AndroidGetRadarConfig { session_token, radar_cfg } => { + uwb_uci_packets::AndroidGetRadarConfigCmdBuilder { + session_token, + tlvs: radar_cfg.into_iter().map(u8::from).collect(), + } + .build() + .into() + } UciCommand::SessionUpdateDtTagRangingRounds { session_token, ranging_round_indexes, @@ -406,5 +433,23 @@ mod tests { cmd = UciCommand::AndroidGetPowerStats {}; packet = uwb_uci_packets::UciControlPacket::try_from(cmd).unwrap(); assert_eq!(packet, uwb_uci_packets::AndroidGetPowerStatsCmdBuilder {}.build().into()); + + cmd = UciCommand::AndroidSetRadarConfig { session_token: 1, config_tlvs: vec![] }; + packet = uwb_uci_packets::UciControlPacket::try_from(cmd.clone()).unwrap(); + assert_eq!( + packet, + uwb_uci_packets::AndroidSetRadarConfigCmdBuilder { session_token: 1, tlvs: vec![] } + .build() + .into() + ); + + cmd = UciCommand::AndroidGetRadarConfig { session_token: 1, radar_cfg: vec![] }; + packet = uwb_uci_packets::UciControlPacket::try_from(cmd).unwrap(); + assert_eq!( + packet, + uwb_uci_packets::AndroidGetRadarConfigCmdBuilder { session_token: 1, tlvs: vec![] } + .build() + .into() + ); } } 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 d7f944a..f6e84ba 100644 --- a/src/rust/uwb_core/src/uci/mock_uci_manager.rs +++ b/src/rust/uwb_core/src/uci/mock_uci_manager.rs @@ -27,13 +27,16 @@ use tokio::time::timeout; use crate::error::{Error, Result}; use crate::params::uci_packets::{ - app_config_tlvs_eq, device_config_tlvs_eq, AppConfigTlv, AppConfigTlvType, CapTlv, Controlees, - CoreSetConfigResponse, CountryCode, DeviceConfigId, DeviceConfigTlv, GetDeviceInfoResponse, PhaseList, - PowerStats, RawUciMessage, ResetConfig, SessionId, SessionState, SessionToken, SessionType, - SessionUpdateDtTagRangingRoundsResponse, SetAppConfigResponse, UpdateMulticastListAction, UpdateTime, + app_config_tlvs_eq, device_config_tlvs_eq, radar_config_tlvs_eq, AndroidRadarConfigResponse, + AppConfigTlv, AppConfigTlvType, CapTlv, Controlees, CoreSetConfigResponse, CountryCode, + DeviceConfigId, DeviceConfigTlv, GetDeviceInfoResponse, PhaseList, PowerStats, RadarConfigTlv, + RadarConfigTlvType, RawUciMessage, ResetConfig, SessionId, SessionState, SessionToken, + SessionType, SessionUpdateDtTagRangingRoundsResponse, SetAppConfigResponse, + UpdateMulticastListAction, UpdateTime, }; use crate::uci::notification::{ - CoreNotification, DataRcvNotification, SessionNotification, UciNotification, + CoreNotification, DataRcvNotification, RadarDataRcvNotification, SessionNotification, + UciNotification, }; use crate::uci::uci_logger::UciLoggerMode; use crate::uci::uci_manager::UciManager; @@ -47,6 +50,7 @@ pub struct MockUciManager { session_notf_sender: mpsc::UnboundedSender<SessionNotification>, vendor_notf_sender: mpsc::UnboundedSender<RawUciMessage>, data_rcv_notf_sender: mpsc::UnboundedSender<DataRcvNotification>, + radar_data_rcv_notf_sender: mpsc::UnboundedSender<RadarDataRcvNotification>, } #[allow(dead_code)] @@ -60,6 +64,7 @@ impl MockUciManager { session_notf_sender: mpsc::unbounded_channel().0, vendor_notf_sender: mpsc::unbounded_channel().0, data_rcv_notf_sender: mpsc::unbounded_channel().0, + radar_data_rcv_notf_sender: mpsc::unbounded_channel().0, } } @@ -79,7 +84,11 @@ impl MockUciManager { /// Prepare Mock to expect for open_hal. /// /// MockUciManager expects call, returns out as response, followed by notfs sent. - pub fn expect_open_hal(&mut self, notfs: Vec<UciNotification>, out: Result<()>) { + pub fn expect_open_hal( + &mut self, + notfs: Vec<UciNotification>, + out: Result<GetDeviceInfoResponse>, + ) { self.expected_calls.lock().unwrap().push_back(ExpectedCall::OpenHal { notfs, out }); } @@ -368,6 +377,41 @@ impl MockUciManager { self.expected_calls.lock().unwrap().push_back(ExpectedCall::AndroidGetPowerStats { out }); } + /// Prepare Mock to expect android_set_radar_config. + /// + /// MockUciManager expects call with parameters, returns out as response, followed by notfs + /// sent. + pub fn expect_android_set_radar_config( + &mut self, + expected_session_id: SessionId, + expected_config_tlvs: Vec<RadarConfigTlv>, + notfs: Vec<UciNotification>, + out: Result<AndroidRadarConfigResponse>, + ) { + self.expected_calls.lock().unwrap().push_back(ExpectedCall::AndroidSetRadarConfig { + expected_session_id, + expected_config_tlvs, + notfs, + out, + }); + } + + /// Prepare Mock to expect android_get_app_config. + /// + /// MockUciManager expects call with parameters, returns out as response. + pub fn expect_android_get_radar_config( + &mut self, + expected_session_id: SessionId, + expected_config_ids: Vec<RadarConfigTlvType>, + out: Result<Vec<RadarConfigTlv>>, + ) { + self.expected_calls.lock().unwrap().push_back(ExpectedCall::AndroidGetRadarConfig { + expected_session_id, + expected_config_ids, + out, + }); + } + /// Prepare Mock to expect raw_uci_cmd. /// /// MockUciManager expects call with parameters, returns out as response. @@ -481,8 +525,14 @@ impl UciManager for MockUciManager { ) { self.data_rcv_notf_sender = data_rcv_notf_sender; } + async fn set_radar_data_rcv_notification_sender( + &mut self, + radar_data_rcv_notf_sender: mpsc::UnboundedSender<RadarDataRcvNotification>, + ) { + self.radar_data_rcv_notf_sender = radar_data_rcv_notf_sender; + } - async fn open_hal(&self) -> Result<()> { + async fn open_hal(&self) -> Result<GetDeviceInfoResponse> { let mut expected_calls = self.expected_calls.lock().unwrap(); match expected_calls.pop_front() { Some(ExpectedCall::OpenHal { notfs, out }) => { @@ -893,6 +943,56 @@ impl UciManager for MockUciManager { } } + async fn android_set_radar_config( + &self, + session_id: SessionId, + config_tlvs: Vec<RadarConfigTlv>, + ) -> Result<AndroidRadarConfigResponse> { + let mut expected_calls = self.expected_calls.lock().unwrap(); + match expected_calls.pop_front() { + Some(ExpectedCall::AndroidSetRadarConfig { + expected_session_id, + expected_config_tlvs, + notfs, + out, + }) if expected_session_id == session_id + && radar_config_tlvs_eq(&expected_config_tlvs, &config_tlvs) => + { + self.expect_call_consumed.notify_one(); + self.send_notifications(notfs); + out + } + Some(call) => { + expected_calls.push_front(call); + Err(Error::MockUndefined) + } + None => Err(Error::MockUndefined), + } + } + + async fn android_get_radar_config( + &self, + session_id: SessionId, + config_ids: Vec<RadarConfigTlvType>, + ) -> Result<Vec<RadarConfigTlv>> { + let mut expected_calls = self.expected_calls.lock().unwrap(); + match expected_calls.pop_front() { + Some(ExpectedCall::AndroidGetRadarConfig { + expected_session_id, + expected_config_ids, + out, + }) if expected_session_id == session_id && expected_config_ids == config_ids => { + self.expect_call_consumed.notify_one(); + out + } + Some(call) => { + expected_calls.push_front(call); + Err(Error::MockUndefined) + } + None => Err(Error::MockUndefined), + } + } + async fn raw_uci_cmd( &self, mt: u32, @@ -999,7 +1099,7 @@ impl UciManager for MockUciManager { enum ExpectedCall { OpenHal { notfs: Vec<UciNotification>, - out: Result<()>, + out: Result<GetDeviceInfoResponse>, }, CloseHal { expected_force: bool, @@ -1092,6 +1192,17 @@ enum ExpectedCall { AndroidGetPowerStats { out: Result<PowerStats>, }, + AndroidSetRadarConfig { + expected_session_id: SessionId, + expected_config_tlvs: Vec<RadarConfigTlv>, + notfs: Vec<UciNotification>, + out: Result<AndroidRadarConfigResponse>, + }, + AndroidGetRadarConfig { + expected_session_id: SessionId, + expected_config_ids: Vec<RadarConfigTlvType>, + out: Result<Vec<RadarConfigTlv>>, + }, RawUciCmd { expected_mt: u32, expected_gid: u32, diff --git a/src/rust/uwb_core/src/uci/notification.rs b/src/rust/uwb_core/src/uci/notification.rs index 90231ae..d99f602 100644 --- a/src/rust/uwb_core/src/uci/notification.rs +++ b/src/rust/uwb_core/src/uci/notification.rs @@ -15,15 +15,20 @@ use std::convert::{TryFrom, TryInto}; use log::{debug, error}; -use uwb_uci_packets::{parse_diagnostics_ntf, Packet, UCI_PACKET_HEADER_LEN}; +use uwb_uci_packets::{ + parse_diagnostics_ntf, radar_bytes_per_sample_value, Packet, RadarDataRcv, RadarSweepDataRaw, + UCI_PACKET_HEADER_LEN, UCI_RADAR_SEQUENCE_NUMBER_LEN, UCI_RADAR_TIMESTAMP_LEN, + UCI_RADAR_VENDOR_DATA_LEN_LEN, +}; use crate::error::{Error, Result}; use crate::params::fira_app_config_params::UwbAddress; use crate::params::uci_packets::{ - ControleeStatus, CreditAvailability, DataRcvStatusCode, DataTransferNtfStatusCode, DeviceState, - ExtendedAddressDlTdoaRangingMeasurement, ExtendedAddressOwrAoaRangingMeasurement, - ExtendedAddressTwoWayRangingMeasurement, RangingMeasurementType, RawUciMessage, SessionState, - SessionToken, ShortAddressDlTdoaRangingMeasurement, ShortAddressOwrAoaRangingMeasurement, + BitsPerSample, ControleeStatus, CreditAvailability, DataRcvStatusCode, + DataTransferNtfStatusCode, DeviceState, ExtendedAddressDlTdoaRangingMeasurement, + ExtendedAddressOwrAoaRangingMeasurement, ExtendedAddressTwoWayRangingMeasurement, + RadarDataType, RangingMeasurementType, RawUciMessage, SessionState, SessionToken, + ShortAddressDlTdoaRangingMeasurement, ShortAddressOwrAoaRangingMeasurement, ShortAddressTwoWayRangingMeasurement, StatusCode, }; @@ -145,7 +150,7 @@ pub struct DataRcvNotification { pub session_token: SessionToken, /// The status of the data rx. - pub status: DataRcvStatusCode, + pub status: StatusCode, /// The sequence number of the data packet. pub uci_sequence_num: u16, @@ -157,6 +162,142 @@ pub struct DataRcvNotification { pub payload: Vec<u8>, } +/// The Radar sweep data struct +#[derive(Debug, Clone, std::cmp::PartialEq)] +pub struct RadarSweepData { + /// Counter of a single radar sweep per receiver. Starting + /// with 0 when the radar session is started. + pub sequence_number: u32, + + /// Timestamp when this radar sweep is received. Unit is + /// based on the PRF. + pub timestamp: u32, + + /// The radar vendor specific data. + pub vendor_specific_data: Vec<u8>, + + /// The radar sample data. + pub sample_data: Vec<u8>, +} + +/// The RADAR_DATA_RCV packet +#[derive(Debug, Clone, std::cmp::PartialEq)] +pub struct RadarDataRcvNotification { + /// The identifier of the session on which radar data transfer is happening. + pub session_token: SessionToken, + + /// The status of the radar data rx. + pub status: DataRcvStatusCode, + + /// The radar data type. + pub radar_data_type: RadarDataType, + + /// The number of sweeps. + pub number_of_sweeps: u8, + + /// Number of samples captured for each radar sweep. + pub samples_per_sweep: u8, + + /// Bits per sample in the radar sweep. + pub bits_per_sample: BitsPerSample, + + /// Defines the start offset with respect to 0cm distance. Unit in samples. + pub sweep_offset: u16, + + /// Radar sweep data. + pub sweep_data: Vec<RadarSweepData>, +} + +impl From<&uwb_uci_packets::RadarSweepDataRaw> for RadarSweepData { + fn from(evt: &uwb_uci_packets::RadarSweepDataRaw) -> Self { + Self { + sequence_number: evt.sequence_number, + timestamp: evt.timestamp, + vendor_specific_data: evt.vendor_specific_data.clone(), + sample_data: evt.sample_data.clone(), + } + } +} + +impl TryFrom<uwb_uci_packets::UciDataPacket> for RadarDataRcvNotification { + type Error = Error; + fn try_from(evt: uwb_uci_packets::UciDataPacket) -> std::result::Result<Self, Self::Error> { + match evt.specialize() { + uwb_uci_packets::UciDataPacketChild::RadarDataRcv(evt) => parse_radar_data(evt), + _ => Err(Error::Unknown), + } + } +} + +fn parse_radar_data(data: RadarDataRcv) -> Result<RadarDataRcvNotification> { + let session_token = data.get_session_handle(); + let status = data.get_status(); + let radar_data_type = data.get_radar_data_type(); + let number_of_sweeps = data.get_number_of_sweeps(); + let samples_per_sweep = data.get_samples_per_sweep(); + let bits_per_sample = data.get_bits_per_sample(); + let bytes_per_sample_value = radar_bytes_per_sample_value(bits_per_sample); + let sweep_offset = data.get_sweep_offset(); + + Ok(RadarDataRcvNotification { + session_token, + status, + radar_data_type, + number_of_sweeps, + samples_per_sweep, + bits_per_sample, + sweep_offset, + sweep_data: parse_radar_sweep_data( + number_of_sweeps, + samples_per_sweep, + bytes_per_sample_value, + data.get_sweep_data().clone(), + )?, + }) +} + +fn parse_radar_sweep_data( + number_of_sweeps: u8, + samples_per_sweep: u8, + bytes_per_sample_value: u8, + data: Vec<u8>, +) -> Result<Vec<RadarSweepData>> { + let mut radar_sweep_data: Vec<RadarSweepData> = Vec::new(); + let mut sweep_data_cursor = 0; + for _ in 0..number_of_sweeps { + let vendor_data_len_index = + sweep_data_cursor + UCI_RADAR_SEQUENCE_NUMBER_LEN + UCI_RADAR_TIMESTAMP_LEN; + if data.len() <= vendor_data_len_index { + error!("Invalid radar sweep data length for vendor, data: {:?}", &data); + return Err(Error::BadParameters); + } + let vendor_specific_data_len = data[vendor_data_len_index] as usize; + let sweep_data_len = UCI_RADAR_SEQUENCE_NUMBER_LEN + + UCI_RADAR_TIMESTAMP_LEN + + UCI_RADAR_VENDOR_DATA_LEN_LEN + + vendor_specific_data_len + + (samples_per_sweep * bytes_per_sample_value) as usize; + if data.len() < sweep_data_cursor + sweep_data_len { + error!("Invalid radar sweep data length, data: {:?}", &data); + return Err(Error::BadParameters); + } + radar_sweep_data.push( + (&RadarSweepDataRaw::parse( + &data[sweep_data_cursor..sweep_data_cursor + sweep_data_len], + ) + .map_err(|e| { + error!("Failed to parse raw Radar Sweep Data {:?}, data: {:?}", e, &data); + Error::BadParameters + })?) + .into(), + ); + + sweep_data_cursor += sweep_data_len; + } + + Ok(radar_sweep_data) +} + impl TryFrom<uwb_uci_packets::UciDataPacket> for DataRcvNotification { type Error = Error; fn try_from(evt: uwb_uci_packets::UciDataPacket) -> std::result::Result<Self, Self::Error> { @@ -168,10 +309,7 @@ impl TryFrom<uwb_uci_packets::UciDataPacket> for DataRcvNotification { source_address: UwbAddress::Extended(evt.get_source_mac_address().to_le_bytes()), payload: evt.get_data().to_vec(), }), - _ => { - error!("Unknown UciData packet: {:?}", evt); - Err(Error::Unknown) - } + _ => Err(Error::Unknown), } } } diff --git a/src/rust/uwb_core/src/uci/response.rs b/src/rust/uwb_core/src/uci/response.rs index 23279c9..d70f9f7 100644 --- a/src/rust/uwb_core/src/uci/response.rs +++ b/src/rust/uwb_core/src/uci/response.rs @@ -16,8 +16,8 @@ use std::convert::{TryFrom, TryInto}; use crate::error::{Error, Result}; use crate::params::uci_packets::{ - AppConfigTlv, CapTlv, CoreSetConfigResponse, DeviceConfigTlv, GetDeviceInfoResponse, - PowerStats, RawUciMessage, SessionHandle, SessionState, + AndroidRadarConfigResponse, AppConfigTlv, CapTlv, CoreSetConfigResponse, DeviceConfigTlv, + GetDeviceInfoResponse, PowerStats, RadarConfigTlv, RawUciMessage, SessionHandle, SessionState, SessionUpdateDtTagRangingRoundsResponse, SetAppConfigResponse, StatusCode, UciControlPacket, }; use crate::uci::error::status_code_to_result; @@ -48,6 +48,8 @@ pub(super) enum UciResponse { SessionGetRangingCount(Result<usize>), AndroidSetCountryCode(Result<()>), AndroidGetPowerStats(Result<PowerStats>), + AndroidSetRadarConfig(AndroidRadarConfigResponse), + AndroidGetRadarConfig(Result<Vec<RadarConfigTlv>>), RawUciCmd(Result<RawUciMessage>), SendUciData(Result<()>), SessionSetHybridConfig(Result<()>), @@ -76,6 +78,8 @@ impl UciResponse { Self::SessionGetRangingCount(result) => Self::matches_result_retry(result), Self::AndroidSetCountryCode(result) => Self::matches_result_retry(result), Self::AndroidGetPowerStats(result) => Self::matches_result_retry(result), + Self::AndroidGetRadarConfig(result) => Self::matches_result_retry(result), + Self::AndroidSetRadarConfig(resp) => Self::matches_status_retry(&resp.status), Self::RawUciCmd(result) => Self::matches_result_retry(result), Self::SessionSetHybridConfig(result) => Self::matches_result_retry(result), @@ -122,6 +126,7 @@ impl TryFrom<uwb_uci_packets::CoreResponse> for UciResponse { match evt.specialize() { CoreResponseChild::GetDeviceInfoRsp(evt) => Ok(UciResponse::CoreGetDeviceInfo( status_code_to_result(evt.get_status()).map(|_| GetDeviceInfoResponse { + status: evt.get_status(), uci_version: evt.get_uci_version(), mac_version: evt.get_mac_version(), phy_version: evt.get_phy_version(), @@ -206,11 +211,13 @@ impl TryFrom<uwb_uci_packets::SessionConfigResponse> for UciResponse { )) } SessionConfigResponseChild::SessionQueryMaxDataSizeRsp(evt) => { - Ok(UciResponse::SessionQueryMaxDataSize(Ok(evt.get_max_data_size()))) + Ok(UciResponse::SessionQueryMaxDataSize( + status_code_to_result(evt.get_status()).map(|_| evt.get_max_data_size()), + )) + } + SessionConfigResponseChild::SessionSetHybridConfigRsp(evt) => { + Ok(UciResponse::SessionSetHybridConfig(status_code_to_result(evt.get_status()))) } - SessionConfigResponseChild::SessionSetHybridConfigRsp(evt) => Ok( - UciResponse::SessionSetHybridConfig(status_code_to_result(evt.get_status())), - ), _ => Err(Error::Unknown), } } @@ -252,6 +259,17 @@ impl TryFrom<uwb_uci_packets::AndroidResponse> for UciResponse { status_code_to_result(evt.get_stats().status).map(|_| evt.get_stats().clone()), )) } + AndroidResponseChild::AndroidSetRadarConfigRsp(evt) => { + Ok(UciResponse::AndroidSetRadarConfig(AndroidRadarConfigResponse { + status: evt.get_status(), + config_status: evt.get_cfg_status().clone(), + })) + } + AndroidResponseChild::AndroidGetRadarConfigRsp(evt) => { + Ok(UciResponse::AndroidGetRadarConfig( + status_code_to_result(evt.get_status()).map(|_| evt.get_tlvs().clone()), + )) + } _ => Err(Error::Unknown), } } diff --git a/src/rust/uwb_core/src/uci/uci_manager.rs b/src/rust/uwb_core/src/uci/uci_manager.rs index 53595e4..a1a97f1 100644 --- a/src/rust/uwb_core/src/uci/uci_manager.rs +++ b/src/rust/uwb_core/src/uci/uci_manager.rs @@ -24,16 +24,18 @@ use crate::uci::command::UciCommand; //use crate::uci::error::{Error, Result}; use crate::error::{Error, Result}; use crate::params::uci_packets::{ - AppConfigTlv, AppConfigTlvType, CapTlv, Controlees, CoreSetConfigResponse, CountryCode, - CreditAvailability, DeviceConfigId, DeviceConfigTlv, DeviceState, GetDeviceInfoResponse, - GroupId, MessageType, PowerStats, RawUciMessage, ResetConfig, SessionId, SessionState, - SessionToken, SessionType, SessionUpdateDtTagRangingRoundsResponse, SetAppConfigResponse, - UciDataPacket, UciDataPacketHal, UpdateMulticastListAction, UpdateTime, + AndroidRadarConfigResponse, AppConfigTlv, AppConfigTlvType, CapTlv, Controlees, + CoreSetConfigResponse, CountryCode, CreditAvailability, DeviceConfigId, DeviceConfigTlv, + DeviceState, GetDeviceInfoResponse, GroupId, MessageType, PowerStats, RadarConfigTlv, + RadarConfigTlvType, RawUciMessage, ResetConfig, SessionId, SessionState, SessionToken, + SessionType, SessionUpdateDtTagRangingRoundsResponse, SetAppConfigResponse, UciDataPacket, + UciDataPacketHal, UpdateMulticastListAction, UpdateTime, }; use crate::params::utils::bytes_to_u64; use crate::uci::message::UciMessage; use crate::uci::notification::{ - CoreNotification, DataRcvNotification, SessionNotification, SessionRangeData, UciNotification, + CoreNotification, DataRcvNotification, RadarDataRcvNotification, SessionNotification, + SessionRangeData, UciNotification, }; use crate::uci::response::UciResponse; use crate::uci::timeout_uci_hal::TimeoutUciHal; @@ -68,10 +70,14 @@ pub trait UciManager: 'static + Send + Sync + Clone { &mut self, data_rcv_notf_sender: mpsc::UnboundedSender<DataRcvNotification>, ); + async fn set_radar_data_rcv_notification_sender( + &mut self, + radar_data_rcv_notf_sender: mpsc::UnboundedSender<RadarDataRcvNotification>, + ); // Open the UCI HAL. // All the UCI commands should be called after the open_hal() completes successfully. - async fn open_hal(&self) -> Result<()>; + async fn open_hal(&self) -> Result<GetDeviceInfoResponse>; // Close the UCI HAL. async fn close_hal(&self, force: bool) -> Result<()>; @@ -126,6 +132,16 @@ pub trait UciManager: 'static + Send + Sync + Clone { // Send the Android-specific UCI commands async fn android_set_country_code(&self, country_code: CountryCode) -> Result<()>; async fn android_get_power_stats(&self) -> Result<PowerStats>; + async fn android_set_radar_config( + &self, + session_id: SessionId, + config_tlvs: Vec<RadarConfigTlv>, + ) -> Result<AndroidRadarConfigResponse>; + async fn android_get_radar_config( + &self, + session_id: SessionId, + config_ids: Vec<RadarConfigTlvType>, + ) -> Result<Vec<RadarConfigTlv>>; // Send a raw uci command. async fn raw_uci_cmd( @@ -254,17 +270,32 @@ impl UciManager for UciManagerImpl { .send_cmd(UciManagerCmd::SetDataRcvNotificationSender { data_rcv_notf_sender }) .await; } + async fn set_radar_data_rcv_notification_sender( + &mut self, + radar_data_rcv_notf_sender: mpsc::UnboundedSender<RadarDataRcvNotification>, + ) { + let _ = self + .send_cmd(UciManagerCmd::SetRadarDataRcvNotificationSender { + radar_data_rcv_notf_sender, + }) + .await; + } - async fn open_hal(&self) -> Result<()> { + async fn open_hal(&self) -> Result<GetDeviceInfoResponse> { match self.send_cmd(UciManagerCmd::OpenHal).await { Ok(UciResponse::OpenHal) => { // According to the UCI spec: "The Host shall send CORE_GET_DEVICE_INFO_CMD to // retrieve the device information.", we call get_device_info() after successfully // opening the HAL. - let device_info = self.core_get_device_info().await; + let device_info = match self.core_get_device_info().await { + Ok(resp) => resp, + Err(e) => { + return Err(e); + } + }; debug!("UCI device info: {:?}", device_info); - Ok(()) + Ok(device_info) } Ok(_) => Err(Error::Unknown), Err(e) => Err(e), @@ -510,6 +541,38 @@ impl UciManager for UciManagerImpl { } } + async fn android_set_radar_config( + &self, + session_id: SessionId, + config_tlvs: Vec<RadarConfigTlv>, + ) -> Result<AndroidRadarConfigResponse> { + let cmd = UciCommand::AndroidSetRadarConfig { + session_token: self.get_session_token(&session_id).await?, + config_tlvs, + }; + match self.send_cmd(UciManagerCmd::SendUciCommand { cmd }).await { + Ok(UciResponse::AndroidSetRadarConfig(resp)) => Ok(resp), + Ok(_) => Err(Error::Unknown), + Err(e) => Err(e), + } + } + + async fn android_get_radar_config( + &self, + session_id: SessionId, + radar_cfg: Vec<RadarConfigTlvType>, + ) -> Result<Vec<RadarConfigTlv>> { + let cmd = UciCommand::AndroidGetRadarConfig { + session_token: self.get_session_token(&session_id).await?, + radar_cfg, + }; + match self.send_cmd(UciManagerCmd::SendUciCommand { cmd }).await { + Ok(UciResponse::AndroidGetRadarConfig(resp)) => resp, + Ok(_) => Err(Error::Unknown), + Err(e) => Err(e), + } + } + async fn raw_uci_cmd( &self, mt: u32, @@ -634,6 +697,7 @@ struct UciManagerActor<T: UciHal, U: UciLogger> { session_notf_sender: mpsc::UnboundedSender<SessionNotification>, vendor_notf_sender: mpsc::UnboundedSender<RawUciMessage>, data_rcv_notf_sender: mpsc::UnboundedSender<DataRcvNotification>, + radar_data_rcv_notf_sender: mpsc::UnboundedSender<RadarDataRcvNotification>, // Used to store the last init session id to help map the session handle sent // in session int response can be correctly mapped. @@ -674,6 +738,7 @@ impl<T: UciHal, U: UciLogger> UciManagerActor<T, U> { session_notf_sender: mpsc::unbounded_channel().0, vendor_notf_sender: mpsc::unbounded_channel().0, data_rcv_notf_sender: mpsc::unbounded_channel().0, + radar_data_rcv_notf_sender: mpsc::unbounded_channel().0, last_init_session_id: None, session_id_to_token_map, } @@ -807,6 +872,10 @@ impl<T: UciHal, U: UciLogger> UciManagerActor<T, U> { self.data_rcv_notf_sender = data_rcv_notf_sender; let _ = result_sender.send(Ok(UciResponse::SetNotification)); } + UciManagerCmd::SetRadarDataRcvNotificationSender { radar_data_rcv_notf_sender } => { + self.radar_data_rcv_notf_sender = radar_data_rcv_notf_sender; + let _ = result_sender.send(Ok(UciResponse::SetNotification)); + } UciManagerCmd::OpenHal => { if self.is_hal_opened { warn!("The UCI HAL is already opened, skip."); @@ -1305,28 +1374,41 @@ impl<T: UciHal, U: UciLogger> UciManagerActor<T, U> { } async fn handle_data_rcv(&mut self, packet: UciDataPacket) { - match packet.try_into() { - Ok(DataRcvNotification { session_token, status, uci_sequence_num, - source_address, payload }) => { - match self.get_session_id(&session_token).await { - Ok(session_id) => { - let data_recv = DataRcvNotification { - session_token: session_id, - status, - uci_sequence_num, - source_address, - payload, - }; - let _ = self.data_rcv_notf_sender.send(data_recv); - } - Err(e) => { - error!("Unable to find session Id, error {:?}", e); - } + if let Ok(data) = DataRcvNotification::try_from(packet.clone()) { + match self.get_session_id(&data.session_token).await { + Ok(session_id) => { + let _ = self.data_rcv_notf_sender.send(DataRcvNotification { + session_token: session_id, + status: data.status, + uci_sequence_num: data.uci_sequence_num, + source_address: data.source_address, + payload: data.payload, + }); + } + Err(e) => { + error!("Unable to find session Id, error {:?}", e); } } - Err(e) => { - error!("Unable to parse incoming Data packet, error {:?}", e); + } else if let Ok(data) = RadarDataRcvNotification::try_from(packet.clone()) { + match self.get_session_id(&data.session_token).await { + Ok(session_id) => { + let _ = self.radar_data_rcv_notf_sender.send(RadarDataRcvNotification { + session_token: session_id, + status: data.status, + radar_data_type: data.radar_data_type, + number_of_sweeps: data.number_of_sweeps, + samples_per_sweep: data.samples_per_sweep, + bits_per_sample: data.bits_per_sample, + sweep_offset: data.sweep_offset, + sweep_data: data.sweep_data, + }); + } + Err(e) => { + error!("Unable to find session Id, error {:?}", e); + } } + } else { + error!("Unable to parse incoming Data packet, packet {:?}", packet); } } @@ -1415,6 +1497,9 @@ enum UciManagerCmd { SetDataRcvNotificationSender { data_rcv_notf_sender: mpsc::UnboundedSender<DataRcvNotification>, }, + SetRadarDataRcvNotificationSender { + radar_data_rcv_notf_sender: mpsc::UnboundedSender<RadarDataRcvNotification>, + }, OpenHal, CloseHal { force: bool, @@ -1436,12 +1521,13 @@ mod tests { use uwb_uci_packets::{SessionGetCountCmdBuilder, SessionGetCountRspBuilder}; use crate::params::uci_packets::{ - AppConfigStatus, AppConfigTlvType, CapTlvType, Controlee, DataRcvStatusCode, - DataTransferNtfStatusCode, StatusCode, + AppConfigStatus, AppConfigTlvType, BitsPerSample, CapTlvType, Controlee, DataRcvStatusCode, + DataTransferNtfStatusCode, RadarDataType, StatusCode, }; use crate::params::UwbAddress; use crate::uci::mock_uci_hal::MockUciHal; use crate::uci::mock_uci_logger::{MockUciLogger, UciLogEvent}; + use crate::uci::notification::RadarSweepData; use crate::uci::uci_logger::NopUciLogger; use crate::utils::init_test_logging; @@ -1626,6 +1712,7 @@ mod tests { .await; let expected_result = GetDeviceInfoResponse { + status, uci_version, mac_version, phy_version, @@ -2282,6 +2369,76 @@ mod tests { } #[tokio::test] + async fn test_android_set_radar_config_ok() { + let session_id = 0x123; + let session_token = 0x123; + let config_tlv = + RadarConfigTlv { cfg_id: RadarConfigTlvType::SamplesPerSweep, v: vec![0x12, 0x34] }; + let config_tlv_clone = config_tlv.clone(); + + let (uci_manager, mut mock_hal) = setup_uci_manager_with_session_initialized( + |mut hal| async move { + let cmd = UciCommand::AndroidSetRadarConfig { + session_token, + config_tlvs: vec![config_tlv_clone], + }; + let resp = into_uci_hal_packets(uwb_uci_packets::AndroidSetRadarConfigRspBuilder { + status: uwb_uci_packets::StatusCode::UciStatusOk, + cfg_status: vec![], + }); + + hal.expected_send_command(cmd, resp, Ok(())); + }, + UciLoggerMode::Disabled, + mpsc::unbounded_channel::<UciLogEvent>().0, + session_id, + session_token, + ) + .await; + + let expected_result = + AndroidRadarConfigResponse { status: StatusCode::UciStatusOk, config_status: vec![] }; + let result = + uci_manager.android_set_radar_config(session_id, vec![config_tlv]).await.unwrap(); + assert_eq!(result, expected_result); + assert!(mock_hal.wait_expected_calls_done().await); + } + + #[tokio::test] + async fn test_android_get_radar_config_ok() { + let session_id = 0x123; + let session_token = 0x123; + let config_id = RadarConfigTlvType::SamplesPerSweep; + let tlv = + RadarConfigTlv { cfg_id: RadarConfigTlvType::SamplesPerSweep, v: vec![0x12, 0x34] }; + let tlv_clone = tlv.clone(); + + let (uci_manager, mut mock_hal) = setup_uci_manager_with_session_initialized( + |mut hal| async move { + let cmd = + UciCommand::AndroidGetRadarConfig { session_token, radar_cfg: vec![config_id] }; + let resp = into_uci_hal_packets(uwb_uci_packets::AndroidGetRadarConfigRspBuilder { + status: uwb_uci_packets::StatusCode::UciStatusOk, + tlvs: vec![tlv_clone], + }); + + hal.expected_send_command(cmd, resp, Ok(())); + }, + UciLoggerMode::Disabled, + mpsc::unbounded_channel::<UciLogEvent>().0, + session_id, + session_token, + ) + .await; + + let expected_result = vec![tlv]; + let result = + uci_manager.android_get_radar_config(session_id, vec![config_id]).await.unwrap(); + assert_eq!(result, expected_result); + assert!(mock_hal.wait_expected_calls_done().await); + } + + #[tokio::test] async fn test_raw_uci_cmd_vendor_gid_ok() { let mt = 0x1; let gid = 0xF; // Vendor reserved GID. @@ -2431,7 +2588,7 @@ mod tests { let resp_payload_fragment_1 = vec![0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08]; let resp_payload_fragment_2 = vec![0x09, 0x0a, 0x0b]; let mut resp_payload_expected = resp_payload_fragment_1.clone(); - resp_payload_expected.extend(resp_payload_fragment_2.clone().into_iter()); + resp_payload_expected.extend(resp_payload_fragment_2.clone()); let (uci_manager, mut mock_hal) = setup_uci_manager_with_open_hal( |mut hal| async move { @@ -2708,7 +2865,7 @@ mod tests { let app_data = vec![0x01, 0x02, 0x03]; let data_rcv_payload = vec![ 0x05, 0x00, 0x00, 0x00, // SessionToken - 0x00, // DataRcvStatusCode + 0x00, // StatusCode 0xa0, 0xb0, 0xc0, 0xd0, 0xa1, 0xb1, 0xc1, 0xd1, // MacAddress 0x0a, 0x00, // UciSequenceNumber 0x03, 0x00, // AppDataLen @@ -2719,7 +2876,7 @@ mod tests { let data_packet_rcv = build_uci_packet(mt_data, pbf, dpf, oid, data_rcv_payload); let expected_data_rcv_notification = DataRcvNotification { session_token: session_id, - status: DataRcvStatusCode::UciStatusSuccess, + status: StatusCode::UciStatusOk, uci_sequence_num, source_address, payload: app_data, @@ -2768,7 +2925,7 @@ mod tests { let app_data_fragment_1_len = 200; let mut data_rcv_payload_fragment_1: Vec<u8> = vec![ 0x05, 0x00, 0x00, 0x00, // SessionToken - 0x00, // DataRcvStatusCode + 0x00, // StatusCode 0xa0, 0xb0, 0xc0, 0xd0, 0xa1, 0xb1, 0xc1, 0xd1, // MacAddress 0x0a, 0x00, // UciSequenceNumber 0x2c, 0x01, // AppData Length (300) @@ -2790,7 +2947,7 @@ mod tests { build_uci_packet(mt_data, pbf_fragment_2, dpf, oid, data_rcv_payload_fragment_2); let expected_data_rcv_notification = DataRcvNotification { session_token: session_id, - status: DataRcvStatusCode::UciStatusSuccess, + status: StatusCode::UciStatusOk, uci_sequence_num, source_address, payload: app_data, @@ -2828,6 +2985,109 @@ mod tests { #[tokio::test] async fn test_data_packet_recv_bad_payload_len_failure() {} + // Test Radar Data packet receive for a single packet (on an active UWB session). + #[tokio::test] + async fn test_radar_data_packet_recv_ok() { + let mt_data = 0x0; + let pbf = 0x0; + let dpf = 0xf; + let oid = 0x0; + let session_id = 0x3; + let session_token = 0x5; + let radar_data_type = RadarDataType::RadarSweepSamples; + let number_of_sweeps = 0x02; + let samples_per_sweep = 0x02; + let bits_per_sample = BitsPerSample::Value32; + let sweep_offset = 0x0; + let sequence_number_1 = 0xa; + let sequence_number_2 = 0xb; + let timestamp_1 = 0xc; + let timestamp_2 = 0xd; + let vendor_specific_data_1 = vec![0x0b]; + let vendor_specific_data_2 = vec![0x0b, 0x0c]; + let sample_data_1 = vec![0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa]; + let sample_data_2 = vec![0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8]; + let radar_data_rcv_payload = vec![ + 0x05, 0x00, 0x00, 0x00, // session_handle + 0x00, // status + 0x00, // radar data type + 0x02, // number of sweeps + 0x02, // samples per sweep + 0x00, // bits per sample + 0x00, 0x00, // sweep offset + 0x10, 0x11, // sweep data size + // sweep data 1 + 0x0a, 0x00, 0x00, 0x00, // sequence number + 0x0c, 0x00, 0x00, 0x00, // timestamp + 0x01, // vendor specific data length + 0x0b, // vendor specific data + 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, // sample data + // sweep data 2 + 0x0b, 0x00, 0x00, 0x00, // sequence number + 0x0d, 0x00, 0x00, 0x00, // timestamp + 0x02, // vendor specific data length + 0x0b, 0x0c, // vendor specific data + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, // sample data + ]; + + // Setup the DataPacketRcv (Rx by HAL) and the expected DataRcvNotification. + let radar_data_packet_rcv = + build_uci_packet(mt_data, pbf, dpf, oid, radar_data_rcv_payload); + let expected_radar_data_rcv_notification = RadarDataRcvNotification { + session_token: session_id, + status: DataRcvStatusCode::UciStatusSuccess, + radar_data_type, + number_of_sweeps, + samples_per_sweep, + bits_per_sample, + sweep_offset, + sweep_data: vec![ + RadarSweepData { + sequence_number: sequence_number_1, + timestamp: timestamp_1, + vendor_specific_data: vendor_specific_data_1, + sample_data: sample_data_1, + }, + RadarSweepData { + sequence_number: sequence_number_2, + timestamp: timestamp_2, + vendor_specific_data: vendor_specific_data_2, + sample_data: sample_data_2, + }, + ], + }; + + // Setup an active UWBS session over which the DataPacket will be received by the Host. + let (mut uci_manager, mut mock_hal) = setup_uci_manager_with_session_active( + |_| async move {}, + UciLoggerMode::Disabled, + mpsc::unbounded_channel::<UciLogEvent>().0, + session_id, + session_token, + ) + .await; + + let (radar_data_rcv_notification_sender, mut radar_data_rcv_notification_receiver) = + mpsc::unbounded_channel::<RadarDataRcvNotification>(); + uci_manager + .set_radar_data_rcv_notification_sender(radar_data_rcv_notification_sender) + .await; + + // Inject the UCI DataPacketRcv into HAL. + let result = mock_hal.receive_packet(radar_data_packet_rcv); + assert!(result.is_ok()); + + // UciManager should send a DataRcvNotification (for the valid Rx packet). + let result = tokio::time::timeout( + Duration::from_millis(100), + radar_data_rcv_notification_receiver.recv(), + ) + .await; + assert!(result.is_ok()); + assert_eq!(result.unwrap(), Some(expected_radar_data_rcv_notification)); + assert!(mock_hal.wait_expected_calls_done().await); + } + #[tokio::test] async fn test_data_packet_send_ok() { // Test Data packet send for a single packet (on a UWB session). diff --git a/src/rust/uwb_core/src/uci/uci_manager_sync.rs b/src/rust/uwb_core/src/uci/uci_manager_sync.rs index 688f1e9..27a213b 100644 --- a/src/rust/uwb_core/src/uci/uci_manager_sync.rs +++ b/src/rust/uwb_core/src/uci/uci_manager_sync.rs @@ -1,4 +1,4 @@ - // Copyright 2022, The Android Open Source Project +// 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. @@ -26,14 +26,17 @@ use tokio::task; use crate::error::{Error, Result}; use crate::params::{ - AppConfigTlv, AppConfigTlvType, CapTlv, CoreSetConfigResponse, CountryCode, DeviceConfigId, - DeviceConfigTlv, GetDeviceInfoResponse, PowerStats, RawUciMessage, ResetConfig, SessionId, - SessionState, SessionType, SessionUpdateDtTagRangingRoundsResponse, SetAppConfigResponse, + AndroidRadarConfigResponse, AppConfigTlv, AppConfigTlvType, CapTlv, CoreSetConfigResponse, + CountryCode, DeviceConfigId, DeviceConfigTlv, GetDeviceInfoResponse, PowerStats, + RadarConfigTlv, RadarConfigTlvType, RawUciMessage, ResetConfig, SessionId, SessionState, + SessionType, SessionUpdateDtTagRangingRoundsResponse, SetAppConfigResponse, UpdateMulticastListAction, UpdateTime, }; #[cfg(any(test, feature = "mock-utils"))] use crate::uci::mock_uci_manager::MockUciManager; -use crate::uci::notification::{CoreNotification, DataRcvNotification, SessionNotification}; +use crate::uci::notification::{ + CoreNotification, DataRcvNotification, RadarDataRcvNotification, SessionNotification, +}; use crate::uci::uci_hal::UciHal; use crate::uci::uci_logger::{UciLogger, UciLoggerMode}; use crate::uci::uci_manager::{UciManager, UciManagerImpl}; @@ -59,6 +62,12 @@ pub trait NotificationManager: 'static { &mut self, data_rcv_notification: DataRcvNotification, ) -> Result<()>; + + /// Callback for RadarDataRcvNotification. + fn on_radar_data_rcv_notification( + &mut self, + radar_data_rcv_notification: RadarDataRcvNotification, + ) -> Result<()>; } /// Builder for NotificationManager. Builder is sent between threads. @@ -74,6 +83,7 @@ struct NotificationDriver<U: NotificationManager> { session_notification_receiver: mpsc::UnboundedReceiver<SessionNotification>, vendor_notification_receiver: mpsc::UnboundedReceiver<RawUciMessage>, data_rcv_notification_receiver: mpsc::UnboundedReceiver<DataRcvNotification>, + radar_data_rcv_notification_receiver: mpsc::UnboundedReceiver<RadarDataRcvNotification>, notification_manager: U, } impl<U: NotificationManager> NotificationDriver<U> { @@ -82,6 +92,7 @@ impl<U: NotificationManager> NotificationDriver<U> { session_notification_receiver: mpsc::UnboundedReceiver<SessionNotification>, vendor_notification_receiver: mpsc::UnboundedReceiver<RawUciMessage>, data_rcv_notification_receiver: mpsc::UnboundedReceiver<DataRcvNotification>, + radar_data_rcv_notification_receiver: mpsc::UnboundedReceiver<RadarDataRcvNotification>, notification_manager: U, ) -> Self { Self { @@ -89,6 +100,7 @@ impl<U: NotificationManager> NotificationDriver<U> { session_notification_receiver, vendor_notification_receiver, data_rcv_notification_receiver, + radar_data_rcv_notification_receiver, notification_manager, } } @@ -115,6 +127,11 @@ impl<U: NotificationManager> NotificationDriver<U> { error!("NotificationDriver: OnDataRcv callback error: {:?}",e); }); } + Some(data) = self.radar_data_rcv_notification_receiver.recv() =>{ + self.notification_manager.on_radar_data_rcv_notification(data).unwrap_or_else(|e|{ + error!("NotificationDriver: OnRadarDataRcv callback error: {:?}",e); + }); + } else =>{ debug!("NotificationDriver dropping."); break; @@ -149,11 +166,16 @@ impl<U: UciManager> UciManagerSync<U> { mpsc::unbounded_channel::<RawUciMessage>(); let (data_rcv_notification_sender, data_rcv_notification_receiver) = mpsc::unbounded_channel::<DataRcvNotification>(); + let (radar_data_rcv_notification_sender, radar_data_rcv_notification_receiver) = + mpsc::unbounded_channel::<RadarDataRcvNotification>(); self.runtime_handle.to_owned().block_on(async { self.uci_manager.set_core_notification_sender(core_notification_sender).await; self.uci_manager.set_session_notification_sender(session_notification_sender).await; self.uci_manager.set_vendor_notification_sender(vendor_notification_sender).await; self.uci_manager.set_data_rcv_notification_sender(data_rcv_notification_sender).await; + self.uci_manager + .set_radar_data_rcv_notification_sender(radar_data_rcv_notification_sender) + .await; }); // The potentially !Send NotificationManager is created in a separate thread. let (driver_status_sender, mut driver_status_receiver) = mpsc::unbounded_channel::<bool>(); @@ -186,6 +208,7 @@ impl<U: UciManager> UciManagerSync<U> { session_notification_receiver, vendor_notification_receiver, data_rcv_notification_receiver, + radar_data_rcv_notification_receiver, notification_manager, ); local.spawn_local(async move { @@ -204,7 +227,7 @@ impl<U: UciManager> UciManagerSync<U> { self.runtime_handle.block_on(self.uci_manager.set_logger_mode(logger_mode)) } /// Start UCI HAL and blocking until UCI commands can be sent. - pub fn open_hal(&self) -> Result<()> { + pub fn open_hal(&self) -> Result<GetDeviceInfoResponse> { self.runtime_handle.block_on(self.uci_manager.open_hal()) } @@ -342,6 +365,26 @@ impl<U: UciManager> UciManagerSync<U> { self.runtime_handle.block_on(self.uci_manager.android_get_power_stats()) } + /// Set radar config. Android-specific method. + pub fn android_set_radar_config( + &self, + session_id: SessionId, + config_tlvs: Vec<RadarConfigTlv>, + ) -> Result<AndroidRadarConfigResponse> { + self.runtime_handle + .block_on(self.uci_manager.android_set_radar_config(session_id, config_tlvs)) + } + + /// Get radar config. Android-specific method. + pub fn android_get_radar_config( + &self, + session_id: SessionId, + config_ids: Vec<RadarConfigTlvType>, + ) -> Result<Vec<RadarConfigTlv>> { + self.runtime_handle + .block_on(self.uci_manager.android_get_radar_config(session_id, config_ids)) + } + /// Send a raw UCI command. pub fn raw_uci_cmd( &self, @@ -449,6 +492,7 @@ mod tests { use crate::params::uci_packets::GetDeviceInfoResponse; use crate::uci::mock_uci_manager::MockUciManager; use crate::uci::{CoreNotification, UciNotification}; + use uwb_uci_packets::StatusCode::UciStatusOk; /// Mock NotificationManager forwarding notifications received. /// The nonsend_counter is deliberately !send to check UciManagerSync::redirect_notification. @@ -484,6 +528,13 @@ mod tests { self.nonsend_counter.replace_with(|&mut prev| prev + 1); Ok(()) } + fn on_radar_data_rcv_notification( + &mut self, + _data_rcv_notf: RadarDataRcvNotification, + ) -> Result<()> { + self.nonsend_counter.replace_with(|&mut prev| prev + 1); + Ok(()) + } } /// Builder for MockNotificationManager. @@ -516,17 +567,20 @@ mod tests { let test_rt = Builder::new_multi_thread().enable_all().build().unwrap(); let (notf_sender, mut notf_receiver) = mpsc::unbounded_channel::<UciNotification>(); let mut uci_manager_impl = MockUciManager::new(); - uci_manager_impl.expect_open_hal( - vec![UciNotification::Core(CoreNotification::DeviceStatus(DeviceStateReady))], - Ok(()), - ); - uci_manager_impl.expect_core_get_device_info(Ok(GetDeviceInfoResponse { + let get_device_info_rsp = GetDeviceInfoResponse { + status: UciStatusOk, uci_version: 0, mac_version: 0, phy_version: 0, uci_test_version: 0, vendor_spec_info: vec![], - })); + }; + + uci_manager_impl.expect_open_hal( + vec![UciNotification::Core(CoreNotification::DeviceStatus(DeviceStateReady))], + Ok(get_device_info_rsp.clone()), + ); + uci_manager_impl.expect_core_get_device_info(Ok(get_device_info_rsp)); let uci_manager_sync = UciManagerSync::new_mock( uci_manager_impl, test_rt.handle().to_owned(), diff --git a/src/rust/uwb_uci_packets/src/lib.rs b/src/rust/uwb_uci_packets/src/lib.rs index 0c9fa3c..d3e7c8a 100644 --- a/src/rust/uwb_uci_packets/src/lib.rs +++ b/src/rust/uwb_uci_packets/src/lib.rs @@ -53,6 +53,11 @@ const UCI_CONTROL_HEADER_GID_MASK: u8 = 0xF; const UCI_CONTROL_HEADER_OID_BYTE_POSITION: usize = 1; const UCI_CONTROL_HEADER_OID_MASK: u8 = 0x3F; +// Radar field lengths +pub const UCI_RADAR_SEQUENCE_NUMBER_LEN: usize = 4; +pub const UCI_RADAR_TIMESTAMP_LEN: usize = 4; +pub const UCI_RADAR_VENDOR_DATA_LEN_LEN: usize = 1; + #[derive(Debug, Clone, PartialEq, FromPrimitive)] pub enum TimeStampLength { Timestamp40Bit = 0x0, @@ -432,16 +437,21 @@ impl RawUciControlPacket { } } -// UCI Data packet functions. -fn is_uci_data_rcv_packet(message_type: MessageType, data_packet_format: DataPacketFormat) -> bool { - message_type == MessageType::Data && data_packet_format == DataPacketFormat::DataRcv +fn is_uci_data_packet(message_type: MessageType) -> bool { + message_type == MessageType::Data +} + +fn is_data_rcv_or_radar_format(data_packet_format: DataPacketFormat) -> bool { + data_packet_format == DataPacketFormat::DataRcv + || data_packet_format == DataPacketFormat::RadarDataMessage } -fn try_into_data_payload(packet: UciPacketHal) -> Result<Bytes> { - if is_uci_data_rcv_packet( - packet.get_message_type(), - packet.get_group_id_or_data_packet_format().try_into()?, - ) { +fn try_into_data_payload( + packet: UciPacketHal, + expected_data_packet_format: DataPacketFormat, +) -> Result<Bytes> { + let dpf: DataPacketFormat = packet.get_group_id_or_data_packet_format().try_into()?; + if is_uci_data_packet(packet.get_message_type()) && dpf == expected_data_packet_format { Ok(packet.to_bytes().slice(UCI_PACKET_HAL_HEADER_LEN..)) } else { error!("Received unexpected data packet fragment: {:?}", packet); @@ -459,12 +469,17 @@ impl TryFrom<Vec<UciPacketHal>> for UciDataPacket { return Err(Error::InvalidPacketError); } + let dpf: DataPacketFormat = packets[0].get_group_id_or_data_packet_format().try_into()?; + if !is_data_rcv_or_radar_format(dpf) { + error!("Unexpected data packet format {:?}", dpf); + } + // Create the reassembled payload. let mut payload_buf = Bytes::new(); for packet in packets { // Ensure that the fragment is a Data Rcv packet. // Get payload by stripping the header. - payload_buf = [payload_buf, try_into_data_payload(packet)?].concat().into(); + payload_buf = [payload_buf, try_into_data_payload(packet, dpf)?].concat().into(); } // Create assembled |UciDataPacket| and convert to bytes again since we need to @@ -472,7 +487,7 @@ impl TryFrom<Vec<UciPacketHal>> for UciDataPacket { UciDataPacket::parse( &UciDataPacketBuilder { message_type: MessageType::Data, - data_packet_format: DataPacketFormat::DataRcv, + data_packet_format: dpf, payload: Some(payload_buf.into()), } .build() @@ -824,8 +839,7 @@ pub fn build_session_update_controller_multicast_list_cmd( ) -> Result<SessionUpdateControllerMulticastListCmd> { let mut controlees_buf = BytesMut::new(); match controlees { - Controlees::NoSessionKey(controlee_v1) => - { + Controlees::NoSessionKey(controlee_v1) => { controlees_buf.extend_from_slice(&(controlee_v1.len() as u8).to_le_bytes()); for controlee in controlee_v1 { controlees_buf.extend_from_slice(&write_controlee(&controlee)); @@ -866,6 +880,17 @@ impl Drop for AppConfigTlv { } } +// Radar data 'bits per sample' field isn't a raw value, instead it's an enum +// that maps to the raw value. We need this mapping to get the max sample size +// length. +pub fn radar_bytes_per_sample_value(bps: BitsPerSample) -> u8 { + match bps { + BitsPerSample::Value32 => 4, + BitsPerSample::Value48 => 6, + BitsPerSample::Value64 => 8, + } +} + #[cfg(test)] mod tests { use super::*; diff --git a/src/rust/uwb_uci_packets/uci_packets.pdl b/src/rust/uwb_uci_packets/uci_packets.pdl index cfa548d..1f3969c 100644 --- a/src/rust/uwb_uci_packets/uci_packets.pdl +++ b/src/rust/uwb_uci_packets/uci_packets.pdl @@ -22,6 +22,7 @@ enum GroupId : 4 { enum DataPacketFormat: 4 { DATA_SND = 0x01, DATA_RCV = 0x02, + RADAR_DATA_MESSAGE = 0x0f, } // Define a merged enum across GroupId & DataPacketFormat as they are at the same bits in @@ -87,6 +88,8 @@ enum AndroidOpCode : 6 { ANDROID_GET_POWER_STATS = 0x0, ANDROID_SET_COUNTRY_CODE = 0x1, ANDROID_FIRA_RANGE_DIAGNOSTICS = 0x2, + ANDROID_RADAR_SET_APP_CONFIG = 0x11, + ANDROID_RADAR_GET_APP_CONFIG = 0x12, } enum StatusCode : 8 { @@ -173,6 +176,7 @@ enum DataTransferNtfStatusCode : 8 { UCI_DATA_TRANSFER_STATUS_ERROR_REJECTED = 0x04, UCI_DATA_TRANSFER_STATUS_SESSION_TYPE_NOT_SUPPORTED = 0x05, UCI_DATA_TRANSFER_STATUS_ERROR_DATA_TRANSFER_IS_ONGOING = 0x06, + UCI_DATA_TRANSFER_STATUS_INVALID_FORMAT = 0x07, } enum ResetConfig : 8 { @@ -246,12 +250,14 @@ enum AppConfigTlvType : 8 { MIN_FRAMES_PER_RR = 0x3A, MTU_SIZE = 0x3B, INTER_FRAME_INTERVAL = 0x3C, - RFU_APP_CFG_TLV_TYPE_RANGE_1 = 0x3D..0x44, + RFU_APP_CFG_TLV_TYPE_RANGE_1 = 0x3D..0x42, + DLTDOA_BLOCK_STRIDING = 0x43, + RFU_APP_CFG_TLV_TYPE_RANGE_2 = 0x44, SESSION_KEY = 0x45, SUBSESSION_KEY = 0x46, SESSION_DATA_TRANSFER_STATUS_NTF_CONFIG = 0x47, SESSION_TIME_BASE = 0x48, - RFU_APP_CFG_TLV_TYPE_RANGE_2 = 0x49..0x9F, + RFU_APP_CFG_TLV_TYPE_RANGE_3 = 0x49..0x9F, VENDOR_SPECIFIC_APP_CFG_TLV_TYPE_RANGE_1 = 0xA0..0xDF { // CCC specific @@ -265,7 +271,7 @@ enum AppConfigTlvType : 8 { }, // Reserved for extension IDs. - RFU_APP_CFG_TLV_TYPE_RANGE_3 = 0xE0..0xE2, + RFU_APP_CFG_TLV_TYPE_RANGE_4 = 0xE0..0xE2, VENDOR_SPECIFIC_APP_CFG_TLV_TYPE_RANGE_2 = 0xE3..0xFF { // Interleaving ratio if AOA_RESULT_REQ is set to 0xF0. @@ -317,6 +323,8 @@ enum CapTlvType : 8 { CCC_SUPPORTED_PULSE_SHAPE_COMBOS = 0xA6, CCC_SUPPORTED_RAN_MULTIPLIER = 0xA7, CCC_SUPPORTED_MAX_RANGING_SESSION_NUMBER = 0xA8, + // RADAR specific + RADAR_SUPPORT = 0xB0 }, SUPPORTED_POWER_STATS = 0xC0, @@ -418,9 +426,10 @@ enum MulticastUpdateStatusCode : 8 { STATUS_ERROR_MULTICAST_LIST_FULL = 0x01, STATUS_ERROR_KEY_FETCH_FAIL = 0x02, STATUS_ERROR_SUB_SESSION_ID_NOT_FOUND = 0x03, - STATUS_ERROR_SUB_SESSION_KEY_NOT_FOUND = 0x05, - STATUS_ERROR_SUB_SESSION_KEY_NOT_APPLICABLE = 0x06, - STATUS_ERROR_SESSION_KEY_NOT_FOUND = 0x07, + STATUS_ERROR_SUB_SESSION_KEY_NOT_FOUND = 0x04, + STATUS_ERROR_SUB_SESSION_KEY_NOT_APPLICABLE = 0x05, + STATUS_ERROR_SESSION_KEY_NOT_FOUND = 0x06, + STATUS_ERROR_ADDRESS_NOT_FOUND = 0x07, STATUS_ERROR_ADDRESS_ALREADY_PRESENT = 0x08, RFU_STATUS_CODE_RANGE_1 = 0x09..0xFF, } @@ -438,6 +447,7 @@ enum SessionType: 8 { FIRA_IN_BAND_DATA_PHASE = 0x04, FIRA_RANGING_WITH_DATA_PHASE = 0x05, CCC = 0xA0, + RADAR_SESSION = 0xA1, DEVICE_TEST_MODE = 0xD0, } @@ -527,7 +537,7 @@ packet UciDataSnd : UciDataPacket (data_packet_format = DATA_SND, message_type = packet UciDataRcv : UciDataPacket (data_packet_format = DATA_RCV, message_type = DATA) { session_token: 32, // Session ID or Session Handle (based on UWBS version) - status: DataRcvStatusCode, + status: StatusCode, source_mac_address: 64, uci_sequence_number: 16, _size_(data): 16, @@ -1017,11 +1027,12 @@ test SessionQueryMaxDataSizeCmd { packet SessionQueryMaxDataSizeRsp : SessionConfigResponse (opcode = 0xB) { //QUER_MAX_DATA_SIZE session_token: 32, // Session ID or Session Handle (based on UWBS version) + status: StatusCode, max_data_size: 16, } test SessionQueryMaxDataSizeRsp { - "\x41\x0B\x00\x06\x00\x00\x00\x00\x0E7\0x07", + "\x41\x0B\x00\x06\x00\x00\x00\x00\x00\x0E7\0x07", } packet SessionStartCmd : SessionControlCommand (opcode = 0x0) { //RANGE_START @@ -1373,3 +1384,88 @@ packet UciVendor_F_Notification : UciNotification (group_id = VENDOR_RESERVED_F) packet TestNotification : UciNotification (group_id = TEST) { _payload_, } + +enum RadarDataType : 8 { + RADAR_SWEEP_SAMPLES = 0x00, +} + +enum RadarConfigTlvType : 8 { + RADAR_TIMING_PARAMS = 0x00, + SAMPLES_PER_SWEEP = 0x01, + CHANNEL_NUMBER = 0x02, + SWEEP_OFFSET = 0x03, + RFRAME_CONFIG = 0x04, + PREAMBLE_DURATION = 0x05, + PREAMBLE_CODE_INDEX = 0x06, + SESSION_PRIORITY = 0x07, + BITS_PER_SAMPLE = 0x08, + PRF_MODE = 0x09, + NUMBER_OF_BURSTS = 0x0A, + RADAR_DATA_TYPE = 0x0B, + + RFU_RADAR_APP_CFG_TLV_TYPE_RANGE = 0x0C..0x9F, + + VENDOR_SPECIFIC_RADAR_APP_CFG_TLV_TYPE_RANGE = 0xA0..0xDF, +} + +struct RadarConfigTlv { + cfg_id: RadarConfigTlvType, + _count_(v): 8, + v: 8[], +} + +struct RadarConfigStatus { + cfg_id: RadarConfigTlvType, + status: StatusCode, +} + +packet AndroidSetRadarConfigCmd: AndroidCommand (opcode = 0x11) { + session_token: 32, + _count_(tlvs): 8, + tlvs: RadarConfigTlv[] +} + +packet AndroidSetRadarConfigRsp : AndroidResponse (opcode = 0x11) { + status: StatusCode, + _count_(cfg_status): 8, + cfg_status: RadarConfigStatus[], +} + +packet AndroidGetRadarConfigCmd: AndroidCommand (opcode = 0x12) { + session_token: 32, + _count_(tlvs): 8, + tlvs: 8[], // RadarConfigTlvType (Infra does not allow array of enums) +} + +packet AndroidGetRadarConfigRsp : AndroidResponse (opcode = 0x12) { + status: StatusCode, + _count_(tlvs): 8, + tlvs: RadarConfigTlv[], +} + +enum BitsPerSample : 8 { + VALUE_32 = 0x00, + VALUE_48 = 0x01, + VALUE_64 = 0x02 +} + +struct RadarSweepDataRaw { + sequence_number: 32, + timestamp: 32, + _count_(vendor_specific_data): 8, + vendor_specific_data: 8[], + sample_data: 8[], +} + +packet RadarDataRcv : UciDataPacket (data_packet_format = RADAR_DATA_MESSAGE, message_type = DATA) { + session_handle: 32, + status: DataRcvStatusCode, + radar_data_type: RadarDataType, + number_of_sweeps: 8, + samples_per_sweep: 8, + bits_per_sample: BitsPerSample, + sweep_offset: 16, + sweep_data_size: 16, + sweep_data: 8[], +} + |