summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndroid Build Coastguard Worker <android-build-coastguard-worker@google.com>2023-12-15 09:31:28 +0000
committerAndroid Build Coastguard Worker <android-build-coastguard-worker@google.com>2023-12-15 09:31:28 +0000
commitb004512285dfbcaada78815c6a40509a38ddabfa (patch)
tree38957bc15fe1779c276bcfdce3f459a2c3b7d7b0
parentab0a82bbae99ec1a6183ddb39082cf977d61e476 (diff)
parent5100eb322e6fa1ed6dc7db36501a42774de885ef (diff)
downloaduwb-aml_tz5_341510010.tar.gz
Snap for 11224086 from 5100eb322e6fa1ed6dc7db36501a42774de885ef to mainline-tzdata5-releaseaml_tz5_341510070aml_tz5_341510050aml_tz5_341510010aml_tz5_341510010
Change-Id: Ib74ce235da75abac429642f71554453509d30198
-rwxr-xr-xsrc/Android.bp3
-rw-r--r--src/rust/uwb_core/examples/main.rs1
-rw-r--r--src/rust/uwb_core/protos/uwb_service.proto20
-rw-r--r--src/rust/uwb_core/src/error.rs3
-rw-r--r--src/rust/uwb_core/src/params/app_config_params.rs6
-rw-r--r--src/rust/uwb_core/src/params/uci_packets.rs48
-rw-r--r--src/rust/uwb_core/src/proto/mappings.rs14
-rw-r--r--src/rust/uwb_core/src/service/uwb_service.rs25
-rw-r--r--src/rust/uwb_core/src/session/session_manager.rs13
-rw-r--r--src/rust/uwb_core/src/uci.rs4
-rw-r--r--src/rust/uwb_core/src/uci/command.rs68
-rw-r--r--src/rust/uwb_core/src/uci/error.rs5
-rw-r--r--src/rust/uwb_core/src/uci/mock_uci_manager.rs186
-rw-r--r--src/rust/uwb_core/src/uci/notification.rs162
-rw-r--r--src/rust/uwb_core/src/uci/response.rs29
-rw-r--r--src/rust/uwb_core/src/uci/uci_manager.rs410
-rw-r--r--src/rust/uwb_core/src/uci/uci_manager_sync.rs97
-rw-r--r--src/rust/uwb_uci_packets/src/lib.rs72
-rw-r--r--src/rust/uwb_uci_packets/uci_packets.pdl141
19 files changed, 1180 insertions, 127 deletions
diff --git a/src/Android.bp b/src/Android.bp
index 193ac98..c0448b7 100755
--- a/src/Android.bp
+++ b/src/Android.bp
@@ -331,6 +331,9 @@ rust_test {
"libcutils",
"liblog",
"libutils",
+ "libbinder_ndk",
+ "libbinder",
+ "libc++",
],
// See b/268061150
stem: "libuci_hal_android_tests_host",
diff --git a/src/rust/uwb_core/examples/main.rs b/src/rust/uwb_core/examples/main.rs
index 63317b1..5f298c6 100644
--- a/src/rust/uwb_core/examples/main.rs
+++ b/src/rust/uwb_core/examples/main.rs
@@ -52,6 +52,7 @@ fn main() {
UwbError::Timeout => {}
UwbError::CommandRetry => {}
UwbError::DuplicatedSessionId => {}
+ UwbError::RegulationUwbOff => {}
UwbError::Unknown => {}
// UwbError is non_exhaustive so we need to add a wild branch here.
diff --git a/src/rust/uwb_core/protos/uwb_service.proto b/src/rust/uwb_core/protos/uwb_service.proto
index e13765e..d7c4c38 100644
--- a/src/rust/uwb_core/protos/uwb_service.proto
+++ b/src/rust/uwb_core/protos/uwb_service.proto
@@ -56,8 +56,11 @@ enum Status {
// Duplicated SessionId.
DUPLICATED_SESSION_ID = 8;
+ //Regulation UWB off
+ REGULATION_UWB_OFF = 9;
+
// The unknown error.
- UNKNOWN = 9;
+ UNKNOWN = 10;
}
// Represent uwb_uci_packets::StatusCode.
@@ -73,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;
@@ -103,6 +107,7 @@ enum StatusCode {
UCI_STATUS_ERROR_CCC_SE_BUSY = 80;
UCI_STATUS_ERROR_CCC_LIFECYCLE = 81;
UCI_STATUS_ERROR_STOPPED_DUE_TO_OTHER_SESSION_CONFLICT = 82;
+ UCI_STATUS_REGULATION_UWB_OFF = 83;
// All vendor specific status code will be mapped to UCI_STATUS_VENDOR_SPECIFIC.
UCI_STATUS_RFU_OR_VENDOR_SPECIFIC = 255;
}
@@ -183,10 +188,15 @@ enum RangingMeasurementType {
// Represent uwb_uci_packets::SessionType.
enum SessionType {
- FIRA_RANGING_SESSION = 0;
- FIRA_DATA_TRANSFER = 1;
- CCC = 2;
- DEVICE_TEST_MODE = 3;
+ FIRA_RANGING_SESSION = 0x00;
+ FIRA_RANGING_AND_IN_BAND_DATA_SESSION = 0x01;
+ FIRA_DATA_TRANSFER = 0x02;
+ FIRA_RANGING_ONLY_PHASE = 0x03;
+ FIRA_IN_BAND_DATA_PHASE = 0x04;
+ FIRA_RANGING_WITH_DATA_PHASE = 0x05;
+ CCC = 0xA0;
+ RADAR_SESSION = 0xA1;
+ DEVICE_TEST_MODE = 0xD0;
}
// Represent uwb_uci_packets::UpdateMulticastListAction.
diff --git a/src/rust/uwb_core/src/error.rs b/src/rust/uwb_core/src/error.rs
index 0b9c6b3..5889448 100644
--- a/src/rust/uwb_core/src/error.rs
+++ b/src/rust/uwb_core/src/error.rs
@@ -49,6 +49,9 @@ pub enum Error {
/// Packet Tx Error
#[error("The packet send failed with an error")]
PacketTxError,
+ /// Country code regulation UWB Off
+ #[error("The country code command failed with a UWB regulatory error")]
+ RegulationUwbOff,
/// The unknown error.
#[error("The unknown error")]
Unknown,
diff --git a/src/rust/uwb_core/src/params/app_config_params.rs b/src/rust/uwb_core/src/params/app_config_params.rs
index bb06d52..a264002 100644
--- a/src/rust/uwb_core/src/params/app_config_params.rs
+++ b/src/rust/uwb_core/src/params/app_config_params.rs
@@ -94,8 +94,12 @@ impl AppConfigParams {
pub fn is_type_matched(&self, session_type: SessionType) -> bool {
match self {
Self::Fira(_) => {
- session_type == SessionType::FiraDataTransfer
+ session_type == SessionType::FiraDataTransferSession
|| session_type == SessionType::FiraRangingSession
+ || session_type == SessionType::FiraRangingAndInBandDataSession
+ || session_type == SessionType::FiraRangingOnlyPhase
+ || session_type == SessionType::FiraInBandDataPhase
+ || session_type == SessionType::FiraRangingWithDataPhase
}
Self::Ccc(_) | Self::CccStarted(_) => session_type == SessionType::Ccc,
}
diff --git a/src/rust/uwb_core/src/params/uci_packets.rs b/src/rust/uwb_core/src/params/uci_packets.rs
index 5cd5822..e3a7722 100644
--- a/src/rust/uwb_core/src/params/uci_packets.rs
+++ b/src/rust/uwb_core/src/params/uci_packets.rs
@@ -20,12 +20,13 @@ 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,
- PowerStats, RangingMeasurementType, ReasonCode, ResetConfig, SessionState, SessionType,
+ PhaseList, PowerStats, RadarConfigStatus, RadarConfigTlv, RadarConfigTlvType, RadarDataType,
+ RangingMeasurementType, ReasonCode, ResetConfig, SessionState, SessionType,
ShortAddressDlTdoaRangingMeasurement, ShortAddressOwrAoaRangingMeasurement,
ShortAddressTwoWayRangingMeasurement, StatusCode, UpdateMulticastListAction,
};
@@ -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 {
@@ -184,9 +207,28 @@ impl TryFrom<String> for CountryCode {
}
}
+/// absolute time in UWBS Time domain(ms) when this configuration applies
+#[derive(Debug, Clone, PartialEq, Copy)]
+pub struct UpdateTime([u8; 8]);
+
+impl UpdateTime {
+ /// Create a UpdateTime instance.
+ pub fn new(update_time: &[u8; 8]) -> Option<Self> {
+ Some(Self(*update_time))
+ }
+}
+
+impl From<UpdateTime> for [u8; 8] {
+ fn from(item: UpdateTime) -> [u8; 8] {
+ item.0
+ }
+}
+
/// 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 a08046d..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,
@@ -179,6 +180,7 @@ impl From<ProtoStatusCode> for StatusCode {
ProtoStatusCode::UCI_STATUS_ERROR_STOPPED_DUE_TO_OTHER_SESSION_CONFLICT => {
StatusCode::UciStatusErrorStoppedDueToOtherSessionConflict
}
+ ProtoStatusCode::UCI_STATUS_REGULATION_UWB_OFF => StatusCode::UciStatusRegulationUwbOff,
_ => StatusCode::VendorSpecificStatusCode2,
}
}
@@ -198,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,
@@ -270,6 +273,9 @@ impl From<StatusCode> for ProtoStatusCode {
StatusCode::UciStatusErrorStoppedDueToOtherSessionConflict => {
ProtoStatusCode::UCI_STATUS_ERROR_STOPPED_DUE_TO_OTHER_SESSION_CONFLICT
}
+ StatusCode::UciStatusRegulationUwbOff => {
+ ProtoStatusCode::UCI_STATUS_REGULATION_UWB_OFF
+ }
_ => ProtoStatusCode::UCI_STATUS_RFU_OR_VENDOR_SPECIFIC,
}
}
@@ -526,8 +532,13 @@ enum_mapping! {
enum_mapping! {
ProtoSessionType => SessionType,
FIRA_RANGING_SESSION => FiraRangingSession,
- FIRA_DATA_TRANSFER => FiraDataTransfer,
+ FIRA_DATA_TRANSFER => FiraDataTransferSession,
+ FIRA_RANGING_AND_IN_BAND_DATA_SESSION => FiraRangingAndInBandDataSession,
+ FIRA_RANGING_ONLY_PHASE => FiraRangingOnlyPhase,
+ FIRA_IN_BAND_DATA_PHASE => FiraInBandDataPhase,
+ FIRA_RANGING_WITH_DATA_PHASE => FiraRangingWithDataPhase,
CCC => Ccc,
+ RADAR_SESSION => RadarSession,
DEVICE_TEST_MODE => DeviceTestMode,
}
@@ -703,6 +714,7 @@ impl<T> From<Result<T>> for ProtoStatus {
Err(Error::Timeout) => Self::TIMEOUT,
Err(Error::CommandRetry) => Self::COMMAND_RETRY,
Err(Error::DuplicatedSessionId) => Self::DUPLICATED_SESSION_ID,
+ Err(Error::RegulationUwbOff) => Self::REGULATION_UWB_OFF,
Err(_) => Self::UNKNOWN,
}
}
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 2afb5a8..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,
+ 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};
/// The enum to represent the UCI commands. The definition of each field should follow UCI spec.
#[allow(missing_docs)]
@@ -80,10 +83,24 @@ pub enum UciCommand {
SessionGetRangingCount {
session_token: SessionToken,
},
+ SessionSetHybridConfig {
+ session_token: SessionToken,
+ number_of_phases: u8,
+ update_time: UpdateTime,
+ phase_list: Vec<PhaseList>,
+ },
AndroidSetCountryCode {
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,
@@ -148,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,
@@ -189,6 +222,19 @@ impl TryFrom<UciCommand> for uwb_uci_packets::UciControlPacket {
UciCommand::SessionQueryMaxDataSize { session_token } => {
uwb_uci_packets::SessionQueryMaxDataSizeCmdBuilder { session_token }.build().into()
}
+ UciCommand::SessionSetHybridConfig {
+ session_token,
+ number_of_phases,
+ update_time,
+ phase_list,
+ } => uwb_uci_packets::SessionSetHybridConfigCmdBuilder {
+ session_token,
+ number_of_phases,
+ update_time: update_time.into(),
+ phase_list,
+ }
+ .build()
+ .into(),
};
Ok(packet)
}
@@ -387,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/error.rs b/src/rust/uwb_core/src/uci/error.rs
index 3101eec..3f040eb 100644
--- a/src/rust/uwb_core/src/uci/error.rs
+++ b/src/rust/uwb_core/src/uci/error.rs
@@ -22,7 +22,10 @@ pub(crate) fn status_code_to_result(status: StatusCode) -> Result<()> {
StatusCode::UciStatusInvalidParam
| StatusCode::UciStatusInvalidRange
| StatusCode::UciStatusInvalidMsgSize => Err(Error::BadParameters),
- StatusCode::UciStatusSessionNotExist
+ StatusCode::UciStatusSessionDuplicate => Err(Error::DuplicatedSessionId),
+ StatusCode::UciStatusFailed
+ | StatusCode::UciStatusSessionNotExist
+ | StatusCode::UciStatusSessionNotConfigured
| StatusCode::UciStatusErrorCccSeBusy
| StatusCode::UciStatusErrorCccLifecycle => Err(Error::ProtocolSpecific),
StatusCode::UciStatusCommandRetry => Err(Error::CommandRetry),
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 21e1ddb..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,
- PowerStats, RawUciMessage, ResetConfig, SessionId, SessionState, SessionToken, SessionType,
- SessionUpdateDtTagRangingRoundsResponse, SetAppConfigResponse, UpdateMulticastListAction,
+ 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.
@@ -408,6 +452,26 @@ impl MockUciManager {
});
}
+ /// Prepare Mock to expect session_set_hybrid_config.
+ ///
+ /// MockUciManager expects call with parameters, returns out as response
+ pub fn expect_session_set_hybrid_config(
+ &mut self,
+ expected_session_id: SessionId,
+ expected_number_of_phases: u8,
+ expected_update_time: UpdateTime,
+ expected_phase_list: Vec<PhaseList>,
+ out: Result<()>,
+ ) {
+ self.expected_calls.lock().unwrap().push_back(ExpectedCall::SessionSetHybridConfig {
+ expected_session_id,
+ expected_number_of_phases,
+ expected_update_time,
+ expected_phase_list,
+ out,
+ });
+ }
+
/// Call Mock to send notifications.
fn send_notifications(&self, notfs: Vec<UciNotification>) {
for notf in notfs.into_iter() {
@@ -461,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 }) => {
@@ -873,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,
@@ -941,13 +1061,45 @@ impl UciManager for MockUciManager {
) -> Result<SessionToken> {
Ok(1) // No uci call here, no mock required.
}
+
+ async fn session_set_hybrid_config(
+ &self,
+ session_id: SessionId,
+ number_of_phases: u8,
+ update_time: UpdateTime,
+ phase_list: Vec<PhaseList>,
+ ) -> Result<()> {
+ let mut expected_calls = self.expected_calls.lock().unwrap();
+ match expected_calls.pop_front() {
+ Some(ExpectedCall::SessionSetHybridConfig {
+ expected_session_id,
+ expected_number_of_phases,
+ expected_update_time,
+ expected_phase_list,
+ out,
+ }) if expected_session_id == session_id
+ && expected_number_of_phases == number_of_phases
+ && expected_update_time == update_time
+ && expected_phase_list.len() == phase_list.len()
+ && expected_phase_list == phase_list =>
+ {
+ self.expect_call_consumed.notify_one();
+ out
+ }
+ Some(call) => {
+ expected_calls.push_front(call);
+ Err(Error::MockUndefined)
+ }
+ None => Err(Error::MockUndefined),
+ }
+ }
}
#[derive(Clone)]
enum ExpectedCall {
OpenHal {
notfs: Vec<UciNotification>,
- out: Result<()>,
+ out: Result<GetDeviceInfoResponse>,
},
CloseHal {
expected_force: bool,
@@ -1040,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,
@@ -1054,4 +1217,11 @@ enum ExpectedCall {
expected_app_payload_data: Vec<u8>,
out: Result<()>,
},
+ SessionSetHybridConfig {
+ expected_session_id: SessionId,
+ expected_number_of_phases: u8,
+ expected_update_time: UpdateTime,
+ expected_phase_list: Vec<PhaseList>,
+ out: Result<()>,
+ },
}
diff --git a/src/rust/uwb_core/src/uci/notification.rs b/src/rust/uwb_core/src/uci/notification.rs
index eab8233..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,
};
@@ -81,8 +86,8 @@ pub enum SessionNotification {
DataTransferStatus {
/// SessionToken : u32
session_token: SessionToken,
- /// Sequence Number: u8
- uci_sequence_number: u8,
+ /// Sequence Number: u16
+ uci_sequence_number: u16,
/// Data Transfer Status Code
status: DataTransferNtfStatusCode,
/// Transmission count
@@ -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 dfeb6c8..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,8 +48,11 @@ 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<()>),
}
impl UciResponse {
@@ -75,7 +78,10 @@ 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),
Self::CoreSetConfig(resp) => Self::matches_status_retry(&resp.status),
Self::SessionSetAppConfig(resp) => Self::matches_status_retry(&resp.status),
@@ -120,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(),
@@ -204,7 +211,12 @@ 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())))
}
_ => Err(Error::Unknown),
}
@@ -247,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 24c0737..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,
+ 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;
@@ -41,7 +43,7 @@ use crate::uci::uci_hal::{UciHal, UciHalPacket};
use crate::uci::uci_logger::{UciLogger, UciLoggerMode, UciLoggerWrapper};
use crate::utils::{clean_mpsc_receiver, PinSleep};
use std::collections::{HashMap, VecDeque};
-use uwb_uci_packets::{Packet, RawUciControlPacket, UciDataSnd, UciDefragPacket};
+use uwb_uci_packets::{Packet, PhaseList, RawUciControlPacket, UciDataSnd, UciDefragPacket};
const UCI_TIMEOUT_MS: u64 = 800;
const MAX_RETRY_COUNT: usize = 3;
@@ -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(
@@ -150,6 +166,14 @@ pub trait UciManager: 'static + Send + Sync + Clone {
&self,
session_id: SessionId,
) -> Result<SessionToken>;
+ /// Send UCI command for setting hybrid config
+ async fn session_set_hybrid_config(
+ &self,
+ session_id: SessionId,
+ number_of_phases: u8,
+ update_time: UpdateTime,
+ phase_list: Vec<PhaseList>,
+ ) -> Result<()>;
}
/// UciManagerImpl is the main implementation of UciManager. Using the actor model, UciManagerImpl
@@ -246,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),
@@ -502,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,
@@ -552,6 +623,27 @@ impl UciManager for UciManagerImpl {
) -> Result<SessionToken> {
Ok(self.get_session_token(&session_id).await?)
}
+
+ /// Send UCI command for setting hybrid config
+ async fn session_set_hybrid_config(
+ &self,
+ session_id: SessionId,
+ number_of_phases: u8,
+ update_time: UpdateTime,
+ phase_list: Vec<PhaseList>,
+ ) -> Result<()> {
+ let cmd = UciCommand::SessionSetHybridConfig {
+ session_token: self.get_session_token(&session_id).await?,
+ number_of_phases,
+ update_time,
+ phase_list,
+ };
+ match self.send_cmd(UciManagerCmd::SendUciCommand { cmd }).await {
+ Ok(UciResponse::SessionSetHybridConfig(resp)) => resp,
+ Ok(_) => Err(Error::Unknown),
+ Err(e) => Err(e),
+ }
+ }
}
struct UciManagerActor<T: UciHal, U: UciLogger> {
@@ -605,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.
@@ -645,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,
}
@@ -778,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.");
@@ -1064,7 +1162,7 @@ impl<T: UciHal, U: UciLogger> UciManagerActor<T, U> {
}
UciDefragPacket::Data(packet) => {
self.logger.log_uci_data(&packet);
- self.handle_data_rcv(packet);
+ self.handle_data_rcv(packet).await;
}
UciDefragPacket::Raw(result, raw_uci_control_packet) => {
// Handle response to raw UCI cmd. We want to send it back as
@@ -1275,14 +1373,42 @@ impl<T: UciHal, U: UciLogger> UciManagerActor<T, U> {
}
}
- fn handle_data_rcv(&mut self, packet: UciDataPacket) {
- match packet.try_into() {
- Ok(data_rcv) => {
- let _ = self.data_rcv_notf_sender.send(data_rcv);
+ async fn handle_data_rcv(&mut self, packet: UciDataPacket) {
+ 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);
}
}
@@ -1371,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,
@@ -1383,7 +1512,7 @@ enum UciManagerCmd {
},
}
-#[cfg(any(test))]
+#[cfg(test)]
mod tests {
use super::*;
@@ -1392,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;
@@ -1582,6 +1712,7 @@ mod tests {
.await;
let expected_result = GetDeviceInfoResponse {
+ status,
uci_version,
mac_version,
phy_version,
@@ -1897,6 +2028,47 @@ mod tests {
}
#[tokio::test]
+ async fn test_session_set_hybrid_config_ok() {
+ let session_id = 0x123;
+ let session_token = 0x123;
+ let number_of_phases = 0x02;
+ let update_time = UpdateTime::new(&[0x0; 8]).unwrap();
+ let phase_list = vec![
+ PhaseList { session_token: 0x12, start_slot_index: 0x13, end_slot_index: 0x01 },
+ PhaseList { session_token: 0x14, start_slot_index: 0x13, end_slot_index: 0x01 },
+ ];
+ let phase_list_clone = phase_list.clone();
+
+ let (uci_manager, mut mock_hal) = setup_uci_manager_with_session_active(
+ |mut hal| async move {
+ let cmd = UciCommand::SessionSetHybridConfig {
+ session_token,
+ number_of_phases,
+ update_time,
+ phase_list: phase_list_clone,
+ };
+ let resp =
+ into_uci_hal_packets(uwb_uci_packets::SessionSetHybridConfigRspBuilder {
+ status: uwb_uci_packets::StatusCode::UciStatusOk,
+ });
+
+ hal.expected_send_command(cmd, resp, Ok(()));
+ },
+ UciLoggerMode::Disabled,
+ mpsc::unbounded_channel::<UciLogEvent>().0,
+ session_id,
+ session_token,
+ )
+ .await;
+
+ let result = uci_manager
+ .session_set_hybrid_config(session_token, number_of_phases, update_time, phase_list)
+ .await;
+ assert!(result.is_ok());
+ assert!(mock_hal.wait_expected_calls_done().await);
+ }
+
+ #[tokio::test]
async fn test_session_get_app_config_ok() {
let session_id = 0x123;
let session_token = 0x123;
@@ -2197,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.
@@ -2346,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 {
@@ -2623,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
@@ -2633,8 +2875,8 @@ mod tests {
// Setup the DataPacketRcv (Rx by HAL) and the expected DataRcvNotification.
let data_packet_rcv = build_uci_packet(mt_data, pbf, dpf, oid, data_rcv_payload);
let expected_data_rcv_notification = DataRcvNotification {
- session_token,
- status: DataRcvStatusCode::UciStatusSuccess,
+ session_token: session_id,
+ status: StatusCode::UciStatusOk,
uci_sequence_num,
source_address,
payload: app_data,
@@ -2683,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)
@@ -2704,8 +2946,8 @@ mod tests {
let data_packet_rcv_fragment_2 =
build_uci_packet(mt_data, pbf_fragment_2, dpf, oid, data_rcv_payload_fragment_2);
let expected_data_rcv_notification = DataRcvNotification {
- session_token,
- status: DataRcvStatusCode::UciStatusSuccess,
+ session_token: session_id,
+ status: StatusCode::UciStatusOk,
uci_sequence_num,
source_address,
payload: app_data,
@@ -2743,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).
@@ -2777,8 +3122,7 @@ mod tests {
ntfs.append(&mut into_uci_hal_packets(
uwb_uci_packets::DataTransferStatusNtfBuilder {
session_token,
- // TODO(b/282230468): Remove the u16-to-u8 conversion once spec is updated.
- uci_sequence_number: uci_sequence_number.try_into().unwrap(),
+ uci_sequence_number,
status,
tx_count,
},
@@ -2868,8 +3212,7 @@ mod tests {
ntfs.append(&mut into_uci_hal_packets(
uwb_uci_packets::DataTransferStatusNtfBuilder {
session_token,
- // TODO(b/282230468): Remove the u16-to-u8 conversion once spec is updated.
- uci_sequence_number: uci_sequence_number.try_into().unwrap(),
+ uci_sequence_number,
status,
tx_count,
},
@@ -2932,8 +3275,7 @@ mod tests {
ntfs.append(&mut into_uci_hal_packets(
uwb_uci_packets::DataTransferStatusNtfBuilder {
session_token,
- // TODO(b/282230468): Remove the u16-to-u8 conversion once spec is updated.
- uci_sequence_number: uci_sequence_number.try_into().unwrap(),
+ uci_sequence_number,
status,
tx_count,
},
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 4b1cf25..27a213b 100644
--- a/src/rust/uwb_core/src/uci/uci_manager_sync.rs
+++ b/src/rust/uwb_core/src/uci/uci_manager_sync.rs
@@ -26,18 +26,21 @@ 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,
- UpdateMulticastListAction,
+ 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};
-use uwb_uci_packets::Controlees;
+use uwb_uci_packets::{Controlees, PhaseList};
/// The NotificationManager processes UciNotification relayed from UciManagerSync in a sync fashion.
/// The UciManagerSync assumes the NotificationManager takes the responsibility to properly handle
@@ -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,
@@ -368,10 +411,27 @@ impl<U: UciManager> UciManagerSync<U> {
app_payload_data,
))
}
+
/// Get session token for session id.
pub fn get_session_token(&self, session_id: SessionId) -> Result<u32> {
self.runtime_handle.block_on(self.uci_manager.get_session_token_from_session_id(session_id))
}
+
+ /// Send UCI command for setting hybrid configuration
+ pub fn session_set_hybrid_config(
+ &self,
+ session_id: SessionId,
+ number_of_phases: u8,
+ update_time: UpdateTime,
+ phase_list: Vec<PhaseList>,
+ ) -> Result<()> {
+ self.runtime_handle.block_on(self.uci_manager.session_set_hybrid_config(
+ session_id,
+ number_of_phases,
+ update_time,
+ phase_list,
+ ))
+ }
}
impl UciManagerSync<UciManagerImpl> {
@@ -432,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.
@@ -467,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.
@@ -499,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 38b0910..eab7f9f 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,
@@ -123,8 +128,8 @@ impl DlTdoaRangingMeasurement {
let initiator_responder_tof = extract_u16(bytes, &mut ptr, 2)?;
let dt_location_type = (message_control >> 5) & 0x3;
let dt_anchor_location = match DTAnchorLocationType::from_u16(dt_location_type)? {
- DTAnchorLocationType::Wgs84 => extract_vec(bytes, &mut ptr, 10)?,
- DTAnchorLocationType::Relative => extract_vec(bytes, &mut ptr, 12)?,
+ DTAnchorLocationType::Wgs84 => extract_vec(bytes, &mut ptr, 12)?,
+ DTAnchorLocationType::Relative => extract_vec(bytes, &mut ptr, 10)?,
_ => vec![],
};
let active_ranging_rounds = ((message_control >> 7) & 0xf) as u8;
@@ -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,10 +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)
- if action == UpdateMulticastListAction::AddControlee
- || action == UpdateMulticastListAction::RemoveControlee =>
- {
+ 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));
@@ -868,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::*;
@@ -1012,7 +1035,7 @@ mod tests {
// All Fields in Little Endian (LE)
// First measurement
0x0a, 0x01, 0x33, 0x05, // 2(Mac address), Status, Message Type
- 0x33, 0x05, 0x02, 0x05, // 2(Message control), 2(Block Index)
+ 0x53, 0x05, 0x02, 0x05, // 2(Message control), 2(Block Index)
0x07, 0x09, 0x0a, 0x01, // Round Index, NLoS, 2(AoA Azimuth)
0x02, 0x05, 0x07, 0x09, // AoA Azimuth FOM, 2(AoA Elevation), AoA Elevation FOM
0x0a, 0x01, 0x02, 0x05, // RSSI, 3(Tx Timestamp..)
@@ -1041,9 +1064,10 @@ mod tests {
0x0a, 0x01, 0x02, 0x05, // 2(Responder Reply Time), 2(Initiator-Responder ToF)
0x07, 0x09, 0x07, 0x09, // 4(Anchor Location..)
0x05, 0x07, 0x09, 0x0a, // 4(Anchor Location..)
- 0x01, 0x02, 0x05, 0x07, // 2(Anchor Location..), 2(Active Ranging Rounds..)
- 0x09, 0x0a, 0x01, 0x02, // 4(Active Ranging Rounds..)
- 0x05, 0x07, 0x09, 0x05, // 4(Active Ranging Rounds)
+ 0x01, 0x02, 0x01, 0x02, // 4(Anchor Location)
+ 0x05, 0x07, 0x09, 0x0a, // 4(Active Ranging Rounds..)
+ 0x01, 0x02, 0x05, 0x07, // 4(Active Ranging Rounds..)
+ 0x09, 0x05, // 2(Active Ranging Rounds)
];
let measurements = ShortAddressDlTdoaRangingMeasurement::parse(&bytes, 2).unwrap();
@@ -1053,7 +1077,7 @@ mod tests {
assert_eq!(*mac_address_1, 0x010a);
assert_eq!(measurement_1.status, 0x33);
assert_eq!(measurement_1.message_type, 0x05);
- assert_eq!(measurement_1.message_control, 0x0533);
+ assert_eq!(measurement_1.message_control, 0x0553);
assert_eq!(measurement_1.block_index, 0x0502);
assert_eq!(measurement_1.round_index, 0x07);
assert_eq!(measurement_1.nlos, 0x09);
@@ -1100,11 +1124,11 @@ mod tests {
assert_eq!(measurement_2.responder_reply_time, 0x010a0907);
assert_eq!(measurement_2.initiator_responder_tof, 0x0502);
assert_eq!(
- measurement_1.dt_anchor_location,
- vec![0x07, 0x09, 0x07, 0x09, 0x05, 0x07, 0x09, 0x0a, 0x01, 0x02]
+ measurement_2.dt_anchor_location,
+ vec![0x07, 0x09, 0x07, 0x09, 0x05, 0x07, 0x09, 0x0a, 0x01, 0x02, 0x01, 0x02]
);
assert_eq!(
- measurement_1.ranging_rounds,
+ measurement_2.ranging_rounds,
vec![0x05, 0x07, 0x09, 0x0a, 0x01, 0x02, 0x05, 0x07, 0x09, 0x05,]
);
}
diff --git a/src/rust/uwb_uci_packets/uci_packets.pdl b/src/rust/uwb_uci_packets/uci_packets.pdl
index 12bdb6c..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 {
@@ -144,6 +147,7 @@ enum StatusCode : 8 {
UCI_STATUS_ERROR_CCC_SE_BUSY = 0x50,
UCI_STATUS_ERROR_CCC_LIFECYCLE = 0x51,
UCI_STATUS_ERROR_STOPPED_DUE_TO_OTHER_SESSION_CONFLICT = 0x52,
+ UCI_STATUS_REGULATION_UWB_OFF = 0x53,
},
// For internal usage, we will use 0xFF as default.
@@ -172,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 {
@@ -245,11 +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,
- RFU_APP_CFG_TLV_TYPE_RANGE_2 = 0x48..0x9F,
+ SESSION_TIME_BASE = 0x48,
+ RFU_APP_CFG_TLV_TYPE_RANGE_3 = 0x49..0x9F,
VENDOR_SPECIFIC_APP_CFG_TLV_TYPE_RANGE_1 = 0xA0..0xDF {
// CCC specific
@@ -263,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.
@@ -315,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,
@@ -416,9 +426,12 @@ 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,
}
enum MacAddressIndicator : 8 {
@@ -428,8 +441,13 @@ enum MacAddressIndicator : 8 {
enum SessionType: 8 {
FIRA_RANGING_SESSION = 0x00,
- FIRA_DATA_TRANSFER = 0x01,
+ FIRA_RANGING_AND_IN_BAND_DATA_SESSION = 0x01,
+ FIRA_DATA_TRANSFER_SESSION = 0x02,
+ FIRA_RANGING_ONLY_PHASE = 0x03,
+ FIRA_IN_BAND_DATA_PHASE = 0x04,
+ FIRA_RANGING_WITH_DATA_PHASE = 0x05,
CCC = 0xA0,
+ RADAR_SESSION = 0xA1,
DEVICE_TEST_MODE = 0xD0,
}
@@ -519,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,
@@ -922,6 +940,23 @@ packet SessionUpdateControllerMulticastListCmd : SessionConfigCommand (opcode =
_payload_,
}
+struct PhaseList {
+ session_token: 32,
+ start_slot_index: 16,
+ end_slot_index: 16,
+}
+
+packet SessionSetHybridConfigCmd : SessionConfigCommand (opcode = 0x0c) { //SESSION_SET_HUS_CONFIG
+ session_token: 32,
+ number_of_phases: 8,
+ update_time: 8[8],
+ phase_list: PhaseList[],
+}
+
+packet SessionSetHybridConfigRsp : SessionConfigResponse (opcode = 0x0c) { //SESSION_SET_HUS_CONFIG
+ status: StatusCode,
+}
+
struct SessionUpdateControllerMulticastListCmdPayload {
_count_(controlees): 8,
controlees: Controlee[],
@@ -973,7 +1008,7 @@ test DataCreditNtf {
packet DataTransferStatusNtf : SessionControlNotification (opcode = 0x05) { // SESSION_DATA_TRANSFER_STATUS_NTF
session_token: 32, // Session ID or Session Handle (based on UWBS version)
- uci_sequence_number: 8,
+ uci_sequence_number: 16,
status: DataTransferNtfStatusCode,
tx_count: 8,
}
@@ -992,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
@@ -1348,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[],
+}
+