diff options
author | Ayush Jain <ayushjain@google.com> | 2024-03-07 00:31:18 +0000 |
---|---|---|
committer | Gerrit Code Review <noreply-gerritcodereview@google.com> | 2024-03-07 00:31:18 +0000 |
commit | b48caec4723ebfcf4f9d7b6549711e92e41e9f60 (patch) | |
tree | 6c54926a39ac16e34955f10e9dadd50e9e240f35 | |
parent | 762a0c37dc1eacf3d43d4494709519780e337715 (diff) | |
parent | 8f786f4f789fa91eacbd753960b33973956bfdab (diff) | |
download | uwb-b48caec4723ebfcf4f9d7b6549711e92e41e9f60.tar.gz |
Merge "CR1045 Controller/Controlee specific HUS config command updates" into main
-rw-r--r-- | src/rust/uwb_core/protos/uwb_service.proto | 6 | ||||
-rw-r--r-- | src/rust/uwb_core/src/params/uci_packets.rs | 13 | ||||
-rw-r--r-- | src/rust/uwb_core/src/proto/mappings.rs | 21 | ||||
-rw-r--r-- | src/rust/uwb_core/src/uci/command.rs | 34 | ||||
-rw-r--r-- | src/rust/uwb_core/src/uci/mock_uci_manager.rs | 98 | ||||
-rw-r--r-- | src/rust/uwb_core/src/uci/response.rs | 18 | ||||
-rw-r--r-- | src/rust/uwb_core/src/uci/uci_manager.rs | 247 | ||||
-rw-r--r-- | src/rust/uwb_core/src/uci/uci_manager_sync.rs | 23 | ||||
-rw-r--r-- | src/rust/uwb_uci_packets/src/lib.rs | 77 | ||||
-rw-r--r-- | src/rust/uwb_uci_packets/uci_packets.pdl | 78 |
10 files changed, 486 insertions, 129 deletions
diff --git a/src/rust/uwb_core/protos/uwb_service.proto b/src/rust/uwb_core/protos/uwb_service.proto index f9fdca3..aaf6d18 100644 --- a/src/rust/uwb_core/protos/uwb_service.proto +++ b/src/rust/uwb_core/protos/uwb_service.proto @@ -208,6 +208,12 @@ enum UpdateMulticastListAction { ADD_CONTROLEE_WITH_LONG_SUB_SESSION_KEY = 3; } +// Represent uwb_uci_packets::MacAddressIndicator. +enum MacAddressIndicator { + SHORT_ADDRESS = 0x00; + EXTENDED_ADDRESS = 0x01; +} + // Represent uwb_core::params::fira_app_config_params::DeviceType. enum DeviceType { CONTROLEE = 0; diff --git a/src/rust/uwb_core/src/params/uci_packets.rs b/src/rust/uwb_core/src/params/uci_packets.rs index b54680d..6f42e3b 100644 --- a/src/rust/uwb_core/src/params/uci_packets.rs +++ b/src/rust/uwb_core/src/params/uci_packets.rs @@ -21,15 +21,16 @@ use std::iter::FromIterator; // Re-export enums and structs from uwb_uci_packets. pub use uwb_uci_packets::{ AppConfigStatus, AppConfigTlv as RawAppConfigTlv, AppConfigTlvType, BitsPerSample, CapTlv, - CapTlvType, Controlee, ControleeStatus, Controlees, CreditAvailability, DataRcvStatusCode, - DataTransferNtfStatusCode, DataTransferPhaseConfigUpdateStatusCode, DeviceConfigId, - DeviceConfigStatus, DeviceConfigTlv, DeviceState, ExtendedAddressDlTdoaRangingMeasurement, - ExtendedAddressOwrAoaRangingMeasurement, ExtendedAddressTwoWayRangingMeasurement, GroupId, + CapTlvType, Controlee, ControleePhaseList, ControleeStatus, Controlees, CreditAvailability, + DataRcvStatusCode, DataTransferNtfStatusCode, DataTransferPhaseConfigUpdateStatusCode, + DeviceConfigId, DeviceConfigStatus, DeviceConfigTlv, DeviceState, + ExtendedAddressDlTdoaRangingMeasurement, ExtendedAddressOwrAoaRangingMeasurement, + ExtendedAddressTwoWayRangingMeasurement, GroupId, MacAddressIndicator, MessageType, MulticastUpdateStatusCode, PhaseList, PowerStats, RadarConfigStatus, RadarConfigTlv, RadarConfigTlvType, RadarDataType, RangingMeasurementType, ReasonCode, ResetConfig, SessionState, SessionType, ShortAddressDlTdoaRangingMeasurement, - ShortAddressOwrAoaRangingMeasurement, ShortAddressTwoWayRangingMeasurement, StatusCode, - UpdateMulticastListAction, + ShortAddressOwrAoaRangingMeasurement, ShortAddressTwoWayRangingMeasurement, + StatusCode, UpdateMulticastListAction, }; pub(crate) use uwb_uci_packets::{UciControlPacket, UciDataPacket, UciDataPacketHal}; diff --git a/src/rust/uwb_core/src/proto/mappings.rs b/src/rust/uwb_core/src/proto/mappings.rs index fa9a7a8..089af2f 100644 --- a/src/rust/uwb_core/src/proto/mappings.rs +++ b/src/rust/uwb_core/src/proto/mappings.rs @@ -28,8 +28,8 @@ use crate::params::fira_app_config_params::{ }; use crate::params::uci_packets::{ Controlee, DeviceState, ExtendedAddressDlTdoaRangingMeasurement, - ExtendedAddressOwrAoaRangingMeasurement, ExtendedAddressTwoWayRangingMeasurement, PowerStats, - RangingMeasurementType, ReasonCode, SessionState, SessionType, + ExtendedAddressOwrAoaRangingMeasurement, ExtendedAddressTwoWayRangingMeasurement, + MacAddressIndicator, PowerStats, RangingMeasurementType, ReasonCode, SessionState, SessionType, ShortAddressDlTdoaRangingMeasurement, ShortAddressOwrAoaRangingMeasurement, ShortAddressTwoWayRangingMeasurement, StatusCode, UpdateMulticastListAction, }; @@ -39,11 +39,12 @@ use crate::proto::bindings::{ Controlee as ProtoControlee, DeviceRole as ProtoDeviceRole, DeviceState as ProtoDeviceState, DeviceType as ProtoDeviceType, DlTDoARangingMeasurement as ProtoDlTDoARangingMeasurement, FiraAppConfigParams as ProtoFiraAppConfigParams, HoppingMode as ProtoHoppingMode, - KeyRotation as ProtoKeyRotation, MacAddressMode as ProtoMacAddressMode, - MacFcsType as ProtoMacFcsType, MultiNodeMode as ProtoMultiNodeMode, - OwrAoaRangingMeasurement as ProtoOwrAoaRangingMeasurement, PowerStats as ProtoPowerStats, - PreambleDuration as ProtoPreambleDuration, PrfMode as ProtoPrfMode, - PsduDataRate as ProtoPsduDataRate, RangeDataNtfConfig as ProtoRangeDataNtfConfig, + KeyRotation as ProtoKeyRotation, MacAddressIndicator as ProtoMacAddressIndicator, + MacAddressMode as ProtoMacAddressMode, MacFcsType as ProtoMacFcsType, + MultiNodeMode as ProtoMultiNodeMode, OwrAoaRangingMeasurement as ProtoOwrAoaRangingMeasurement, + PowerStats as ProtoPowerStats, PreambleDuration as ProtoPreambleDuration, + PrfMode as ProtoPrfMode, PsduDataRate as ProtoPsduDataRate, + RangeDataNtfConfig as ProtoRangeDataNtfConfig, RangingMeasurementType as ProtoRangingMeasurementType, RangingRoundControl as ProtoRangingRoundControl, RangingRoundUsage as ProtoRangingRoundUsage, RangingTimeStruct as ProtoRangingTimeStruct, ReasonCode as ProtoReasonCode, @@ -697,6 +698,12 @@ enum_mapping! { ADD_CONTROLEE_WITH_LONG_SUB_SESSION_KEY => AddControleeWithLongSubSessionKey, } +enum_mapping! { + ProtoMacAddressIndicator => MacAddressIndicator, + SHORT_ADDRESS => ShortAddress, + EXTENDED_ADDRESS => ExtendedAddress, +} + pub enum ProtoRangingMeasurements { TwoWay(Vec<ProtoTwoWayRangingMeasurement>), OwrAoa(ProtoOwrAoaRangingMeasurement), diff --git a/src/rust/uwb_core/src/uci/command.rs b/src/rust/uwb_core/src/uci/command.rs index fa71b2d..9f0a70e 100644 --- a/src/rust/uwb_core/src/uci/command.rs +++ b/src/rust/uwb_core/src/uci/command.rs @@ -24,8 +24,9 @@ use crate::params::uci_packets::{ UpdateMulticastListAction, UpdateTime, }; use uwb_uci_packets::{ - build_data_transfer_phase_config_cmd, build_session_update_controller_multicast_list_cmd, - GroupId, MessageType, PhaseList, + build_data_transfer_phase_config_cmd, build_session_set_hybrid_controller_config_cmd, + build_session_update_controller_multicast_list_cmd, ControleePhaseList, GroupId, MessageType, + PhaseList, }; /// The enum to represent the UCI commands. The definition of each field should follow UCI spec. @@ -84,11 +85,16 @@ pub enum UciCommand { SessionGetRangingCount { session_token: SessionToken, }, - SessionSetHybridConfig { + SessionSetHybridControllerConfig { session_token: SessionToken, + message_control: u8, number_of_phases: u8, update_time: UpdateTime, - phase_list: Vec<PhaseList>, + phase_list: PhaseList, + }, + SessionSetHybridControleeConfig { + session_token: SessionToken, + controlee_phase_list: Vec<ControleePhaseList>, }, SessionDataTransferPhaseConfig { session_token: SessionToken, @@ -231,19 +237,29 @@ impl TryFrom<UciCommand> for uwb_uci_packets::UciControlPacket { UciCommand::SessionQueryMaxDataSize { session_token } => { uwb_uci_packets::SessionQueryMaxDataSizeCmdBuilder { session_token }.build().into() } - UciCommand::SessionSetHybridConfig { + UciCommand::SessionSetHybridControllerConfig { session_token, + message_control, number_of_phases, update_time, phase_list, - } => uwb_uci_packets::SessionSetHybridConfigCmdBuilder { + } => build_session_set_hybrid_controller_config_cmd( session_token, + message_control, number_of_phases, - update_time: update_time.into(), + update_time.into(), phase_list, - } - .build() + ) + .map_err(|_| Error::BadParameters)? .into(), + UciCommand::SessionSetHybridControleeConfig { session_token, controlee_phase_list } => { + uwb_uci_packets::SessionSetHybridControleeConfigCmdBuilder { + session_token, + controlee_phase_list, + } + .build() + .into() + } UciCommand::SessionDataTransferPhaseConfig { session_token, dtpcm_repetition, 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 7805d19..6dd222f 100644 --- a/src/rust/uwb_core/src/uci/mock_uci_manager.rs +++ b/src/rust/uwb_core/src/uci/mock_uci_manager.rs @@ -28,10 +28,10 @@ use tokio::time::timeout; use crate::error::{Error, Result}; use crate::params::uci_packets::{ 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, + AppConfigTlv, AppConfigTlvType, CapTlv, ControleePhaseList, Controlees, CoreSetConfigResponse, + CountryCode, DeviceConfigId, DeviceConfigTlv, GetDeviceInfoResponse, PhaseList, PowerStats, + RadarConfigTlv, RadarConfigTlvType, RawUciMessage, ResetConfig, SessionId, SessionState, + SessionToken, SessionType, SessionUpdateDtTagRangingRoundsResponse, SetAppConfigResponse, UpdateMulticastListAction, UpdateTime, }; use crate::uci::notification::{ @@ -452,24 +452,46 @@ impl MockUciManager { }); } - /// Prepare Mock to expect session_set_hybrid_config. + /// Prepare Mock to expect session_set_hybrid_controller_config. /// /// MockUciManager expects call with parameters, returns out as response - pub fn expect_session_set_hybrid_config( + pub fn expect_session_set_hybrid_controller_config( &mut self, expected_session_id: SessionId, + expected_message_control: u8, expected_number_of_phases: u8, expected_update_time: UpdateTime, - expected_phase_list: Vec<PhaseList>, + expected_phase_list: 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, - }); + self.expected_calls.lock().unwrap().push_back( + ExpectedCall::SessionSetHybridControllerConfig { + expected_session_id, + expected_message_control, + expected_number_of_phases, + expected_update_time, + expected_phase_list, + out, + }, + ); + } + + /// Prepare Mock to expect session_set_hybrid_controlee_config. + /// + /// MockUciManager expects call with parameters, returns out as response + pub fn expect_session_set_hybrid_controlee_config( + &mut self, + expected_session_id: SessionId, + expected_controlee_phase_list: Vec<ControleePhaseList>, + out: Result<()>, + ) { + self.expected_calls.lock().unwrap().push_back( + ExpectedCall::SessionSetHybridControleeConfig { + expected_session_id, + expected_controlee_phase_list, + out, + }, + ); } /// Prepare Mock to expect session_data_transfer_phase_config @@ -1125,26 +1147,54 @@ impl UciManager for MockUciManager { Ok(1) // No uci call here, no mock required. } - async fn session_set_hybrid_config( + async fn session_set_hybrid_controller_config( &self, session_id: SessionId, + message_control: u8, number_of_phases: u8, update_time: UpdateTime, - phase_list: Vec<PhaseList>, + phase_lists: PhaseList, ) -> Result<()> { let mut expected_calls = self.expected_calls.lock().unwrap(); match expected_calls.pop_front() { - Some(ExpectedCall::SessionSetHybridConfig { + Some(ExpectedCall::SessionSetHybridControllerConfig { expected_session_id, + expected_message_control, expected_number_of_phases, expected_update_time, expected_phase_list, out, }) if expected_session_id == session_id + && expected_message_control == message_control && expected_number_of_phases == number_of_phases && expected_update_time == update_time - && expected_phase_list.len() == phase_list.len() - && expected_phase_list == phase_list => + && expected_phase_list == phase_lists => + { + self.expect_call_consumed.notify_one(); + out + } + Some(call) => { + expected_calls.push_front(call); + Err(Error::MockUndefined) + } + None => Err(Error::MockUndefined), + } + } + + async fn session_set_hybrid_controlee_config( + &self, + session_id: SessionId, + controlee_phase_list: Vec<ControleePhaseList>, + ) -> Result<()> { + let mut expected_calls = self.expected_calls.lock().unwrap(); + match expected_calls.pop_front() { + Some(ExpectedCall::SessionSetHybridControleeConfig { + expected_session_id, + expected_controlee_phase_list, + out, + }) if expected_session_id == session_id + && expected_controlee_phase_list.len() == controlee_phase_list.len() + && expected_controlee_phase_list == controlee_phase_list => { self.expect_call_consumed.notify_one(); out @@ -1280,11 +1330,17 @@ enum ExpectedCall { expected_app_payload_data: Vec<u8>, out: Result<()>, }, - SessionSetHybridConfig { + SessionSetHybridControllerConfig { expected_session_id: SessionId, + expected_message_control: u8, expected_number_of_phases: u8, expected_update_time: UpdateTime, - expected_phase_list: Vec<PhaseList>, + expected_phase_list: PhaseList, + out: Result<()>, + }, + SessionSetHybridControleeConfig { + expected_session_id: SessionId, + expected_controlee_phase_list: Vec<ControleePhaseList>, out: Result<()>, }, SessionDataTransferPhaseConfig { diff --git a/src/rust/uwb_core/src/uci/response.rs b/src/rust/uwb_core/src/uci/response.rs index 68994a6..48313aa 100644 --- a/src/rust/uwb_core/src/uci/response.rs +++ b/src/rust/uwb_core/src/uci/response.rs @@ -52,7 +52,8 @@ pub(super) enum UciResponse { AndroidGetRadarConfig(Result<Vec<RadarConfigTlv>>), RawUciCmd(Result<RawUciMessage>), SendUciData(Result<()>), - SessionSetHybridConfig(Result<()>), + SessionSetHybridControllerConfig(Result<()>), + SessionSetHybridControleeConfig(Result<()>), SessionDataTransferPhaseConfig(Result<()>), } @@ -82,9 +83,9 @@ impl UciResponse { 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::SessionSetHybridControllerConfig(result) => Self::matches_result_retry(result), + Self::SessionSetHybridControleeConfig(result) => Self::matches_result_retry(result), Self::SessionDataTransferPhaseConfig(result) => Self::matches_result_retry(result), - Self::CoreSetConfig(resp) => Self::matches_status_retry(&resp.status), Self::SessionSetAppConfig(resp) => Self::matches_status_retry(&resp.status), @@ -217,8 +218,15 @@ impl TryFrom<uwb_uci_packets::SessionConfigResponse> for UciResponse { 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::SessionSetHybridControllerConfigRsp(evt) => { + Ok(UciResponse::SessionSetHybridControllerConfig(status_code_to_result( + evt.get_status(), + ))) + } + SessionConfigResponseChild::SessionSetHybridControleeConfigRsp(evt) => { + Ok(UciResponse::SessionSetHybridControleeConfig(status_code_to_result( + evt.get_status(), + ))) } SessionConfigResponseChild::SessionDataTransferPhaseConfigRsp(evt) => { Ok(UciResponse::SessionDataTransferPhaseConfig(status_code_to_result( diff --git a/src/rust/uwb_core/src/uci/uci_manager.rs b/src/rust/uwb_core/src/uci/uci_manager.rs index 8548278..f030015 100644 --- a/src/rust/uwb_core/src/uci/uci_manager.rs +++ b/src/rust/uwb_core/src/uci/uci_manager.rs @@ -44,7 +44,8 @@ use crate::utils::{clean_mpsc_receiver, PinSleep}; use pdl_runtime::Packet; use std::collections::{HashMap, VecDeque}; use uwb_uci_packets::{ - fragment_data_msg_send, PhaseList, RawUciControlPacket, UciDataSnd, UciDefragPacket, + fragment_data_msg_send, ControleePhaseList, PhaseList, RawUciControlPacket, UciDataSnd, + UciDefragPacket, }; // Conditional compilation: In production code, use the "prod" variant of the Aconfig flags @@ -190,13 +191,22 @@ 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( + + /// Send UCI command for setting hybrid controller config + async fn session_set_hybrid_controller_config( &self, session_id: SessionId, + message_control: u8, number_of_phases: u8, update_time: UpdateTime, - phase_list: Vec<PhaseList>, + phase_list: PhaseList, + ) -> Result<()>; + + /// Send UCI command for setting hybrid controlee config + async fn session_set_hybrid_controlee_config( + &self, + session_id: SessionId, + controlee_phase_list: Vec<ControleePhaseList>, ) -> Result<()>; } @@ -674,22 +684,41 @@ impl UciManager for UciManagerImpl { Ok(self.get_session_token(&session_id).await?) } - /// Send UCI command for setting hybrid config - async fn session_set_hybrid_config( + /// Send UCI command for setting hybrid controller config + async fn session_set_hybrid_controller_config( &self, session_id: SessionId, + message_control: u8, number_of_phases: u8, update_time: UpdateTime, - phase_list: Vec<PhaseList>, + phase_list: PhaseList, ) -> Result<()> { - let cmd = UciCommand::SessionSetHybridConfig { + let cmd = UciCommand::SessionSetHybridControllerConfig { session_token: self.get_session_token(&session_id).await?, + message_control, number_of_phases, update_time, phase_list, }; match self.send_cmd(UciManagerCmd::SendUciCommand { cmd }).await { - Ok(UciResponse::SessionSetHybridConfig(resp)) => resp, + Ok(UciResponse::SessionSetHybridControllerConfig(resp)) => resp, + Ok(_) => Err(Error::Unknown), + Err(e) => Err(e), + } + } + + /// Send UCI command for setting hybrid controlee config + async fn session_set_hybrid_controlee_config( + &self, + session_id: SessionId, + controlee_phase_list: Vec<ControleePhaseList>, + ) -> Result<()> { + let cmd = UciCommand::SessionSetHybridControleeConfig { + session_token: self.get_session_token(&session_id).await?, + controlee_phase_list, + }; + match self.send_cmd(UciManagerCmd::SendUciCommand { cmd }).await { + Ok(UciResponse::SessionSetHybridControleeConfig(resp)) => resp, Ok(_) => Err(Error::Unknown), Err(e) => Err(e), } @@ -2201,29 +2230,94 @@ mod tests { } #[tokio::test] - async fn test_session_set_hybrid_config_ok() { + async fn test_session_get_app_config_ok() { let session_id = 0x123; let session_token = 0x123; + let config_id = AppConfigTlvType::DeviceType; + let tlv = AppConfigTlv::new(AppConfigTlvType::DeviceType, vec![0x12, 0x34, 0x56]); + let tlv_clone = tlv.clone(); + + let (uci_manager, mut mock_hal) = setup_uci_manager_with_session_initialized( + |mut hal| async move { + let cmd = + UciCommand::SessionGetAppConfig { session_token, app_cfg: vec![config_id] }; + let resp = into_uci_hal_packets(uwb_uci_packets::SessionGetAppConfigRspBuilder { + status: uwb_uci_packets::StatusCode::UciStatusOk, + tlvs: vec![tlv_clone.into_inner()], + }); + + 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.session_get_app_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_session_set_hybrid_controller_config_ok() { + let session_id = 0x123; + let message_control = 0x00; + let message_control_extended = 0x01; + 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 phase_list_short_mac_address = PhaseList::ShortMacAddress(vec![ + uwb_uci_packets::PhaseListShortMacAddress { + session_token: 0x11, + start_slot_index: 0x12, + end_slot_index: 0x13, + phase_participation: 0x01, + mac_address: [0x11, 0x22], + }, + uwb_uci_packets::PhaseListShortMacAddress { + session_token: 0x21, + start_slot_index: 0x22, + end_slot_index: 0x23, + phase_participation: 0x01, + mac_address: [0x11, 0x33], + }, + ]); + let phase_list_extended_mac_address = PhaseList::ExtendedMacAddress(vec![ + uwb_uci_packets::PhaseListExtendedMacAddress { + session_token: 0x11, + start_slot_index: 0x12, + end_slot_index: 0x13, + phase_participation: 0x01, + mac_address: [0x11, 0x22, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38], + }, + uwb_uci_packets::PhaseListExtendedMacAddress { + session_token: 0x21, + start_slot_index: 0x22, + end_slot_index: 0x23, + phase_participation: 0x01, + mac_address: [0x11, 0x22, 0x33, 0x34, 0x35, 0x36, 0x37, 0x39], + }, + ]); + let mut phase_list_clone = phase_list_short_mac_address.clone(); + // short mac address let (uci_manager, mut mock_hal) = setup_uci_manager_with_session_active( |mut hal| async move { - let cmd = UciCommand::SessionSetHybridConfig { + let cmd = UciCommand::SessionSetHybridControllerConfig { session_token, + message_control, number_of_phases, update_time, phase_list: phase_list_clone, }; - let resp = - into_uci_hal_packets(uwb_uci_packets::SessionSetHybridConfigRspBuilder { + let resp = into_uci_hal_packets( + uwb_uci_packets::SessionSetHybridControllerConfigRspBuilder { status: uwb_uci_packets::StatusCode::UciStatusOk, - }); + }, + ); hal.expected_send_command(cmd, resp, Ok(())); }, @@ -2235,12 +2329,93 @@ mod tests { .await; let result = uci_manager - .session_set_hybrid_config(session_token, number_of_phases, update_time, phase_list) + .session_set_hybrid_controller_config( + session_token, + message_control, + number_of_phases, + update_time, + phase_list_short_mac_address, + ) + .await; + assert!(result.is_ok()); + assert!(mock_hal.wait_expected_calls_done().await); + + // extended mac address + phase_list_clone = phase_list_extended_mac_address.clone(); + let (uci_manager, mut mock_hal) = setup_uci_manager_with_session_active( + |mut hal| async move { + let cmd = UciCommand::SessionSetHybridControllerConfig { + session_token, + message_control: message_control_extended, + number_of_phases, + update_time, + phase_list: phase_list_clone, + }; + let resp = into_uci_hal_packets( + uwb_uci_packets::SessionSetHybridControllerConfigRspBuilder { + 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_controller_config( + session_token, + message_control_extended, + number_of_phases, + update_time, + phase_list_extended_mac_address, + ) .await; assert!(result.is_ok()); assert!(mock_hal.wait_expected_calls_done().await); } + #[tokio::test] + async fn test_session_set_hybrid_controlee_config_ok() { + let session_id = 0x123; + let session_token = 0x123; + let phase_list = vec![ + ControleePhaseList { session_token: 0x12, phase_participation: 0x01 }, + ControleePhaseList { session_token: 0x14, phase_participation: 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::SessionSetHybridControleeConfig { + session_token, + controlee_phase_list: phase_list_clone, + }; + let resp = into_uci_hal_packets( + uwb_uci_packets::SessionSetHybridControleeConfigRspBuilder { + 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_controlee_config(session_token, phase_list).await; + assert!(result.is_ok()); + assert!(mock_hal.wait_expected_calls_done().await); + } + #[tokio::test] async fn test_session_data_transfer_phase_config_ok() { let session_id = 0x123; @@ -2293,38 +2468,6 @@ mod tests { } #[tokio::test] - async fn test_session_get_app_config_ok() { - let session_id = 0x123; - let session_token = 0x123; - let config_id = AppConfigTlvType::DeviceType; - let tlv = AppConfigTlv::new(AppConfigTlvType::DeviceType, vec![0x12, 0x34, 0x56]); - let tlv_clone = tlv.clone(); - - let (uci_manager, mut mock_hal) = setup_uci_manager_with_session_initialized( - |mut hal| async move { - let cmd = - UciCommand::SessionGetAppConfig { session_token, app_cfg: vec![config_id] }; - let resp = into_uci_hal_packets(uwb_uci_packets::SessionGetAppConfigRspBuilder { - status: uwb_uci_packets::StatusCode::UciStatusOk, - tlvs: vec![tlv_clone.into_inner()], - }); - - 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.session_get_app_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_session_get_count_ok() { let session_count = 5; 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 3231956..0375f97 100644 --- a/src/rust/uwb_core/src/uci/uci_manager_sync.rs +++ b/src/rust/uwb_core/src/uci/uci_manager_sync.rs @@ -40,7 +40,7 @@ use crate::uci::notification::{ 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, PhaseList}; +use uwb_uci_packets::{ControleePhaseList, Controlees, PhaseList}; /// The NotificationManager processes UciNotification relayed from UciManagerSync in a sync fashion. /// The UciManagerSync assumes the NotificationManager takes the responsibility to properly handle @@ -417,22 +417,35 @@ impl<U: UciManager> UciManagerSync<U> { 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( + /// Send UCI command for setting hybrid controller configuration + pub fn session_set_hybrid_controller_config( &self, session_id: SessionId, + message_control: u8, number_of_phases: u8, update_time: UpdateTime, - phase_list: Vec<PhaseList>, + phase_list: PhaseList, ) -> Result<()> { - self.runtime_handle.block_on(self.uci_manager.session_set_hybrid_config( + self.runtime_handle.block_on(self.uci_manager.session_set_hybrid_controller_config( session_id, + message_control, number_of_phases, update_time, phase_list, )) } + /// Send UCI command for setting hybrid controlee configuration + pub fn session_set_hybrid_controlee_config( + &self, + session_id: SessionId, + controlee_phase_list: Vec<ControleePhaseList>, + ) -> Result<()> { + self.runtime_handle.block_on( + self.uci_manager.session_set_hybrid_controlee_config(session_id, controlee_phase_list), + ) + } + /// Send UCI command for session data transfer phase config pub fn session_data_transfer_phase_config( &self, diff --git a/src/rust/uwb_uci_packets/src/lib.rs b/src/rust/uwb_uci_packets/src/lib.rs index eed65a8..336aed4 100644 --- a/src/rust/uwb_uci_packets/src/lib.rs +++ b/src/rust/uwb_uci_packets/src/lib.rs @@ -368,10 +368,11 @@ fn is_same_control_packet(header: &UciControlPacketHeader, packet: &UciPacketHal } fn is_device_state_err_control_packet(packet: &UciPacketHal) -> bool { - packet.get_message_type() == MessageType::Notification.into() - && packet.get_group_id_or_data_packet_format() == GroupIdOrDataPacketFormat::Core.into() - && get_opcode_from_uci_control_packet(packet) == CoreOpCode::CoreDeviceStatusNtf.into() - && packet.clone().to_vec()[UCI_PACKET_HAL_HEADER_LEN] == DeviceState::DeviceStateError.into() + packet.get_message_type() == MessageType::Notification.into() + && packet.get_group_id_or_data_packet_format() == GroupIdOrDataPacketFormat::Core.into() + && get_opcode_from_uci_control_packet(packet) == CoreOpCode::CoreDeviceStatusNtf.into() + && packet.clone().to_vec()[UCI_PACKET_HAL_HEADER_LEN] + == DeviceState::DeviceStateError.into() } impl UciControlPacket { @@ -406,8 +407,8 @@ impl TryFrom<Vec<UciPacketHal>> for UciControlPacket { // if DEVICE_STATE_ERROR notification is received while waiting for remaining fragments, // process it and send to upper layer for device recovery if is_device_state_err_control_packet(&packet) { - error!("Received device reset error: {:?}", packet); - return UciControlPacket::parse( + error!("Received device reset error: {:?}", packet); + return UciControlPacket::parse( &UciControlPacketBuilder { message_type: packet.get_message_type(), group_id: packet.get_group_id_or_data_packet_format().into(), @@ -416,7 +417,7 @@ impl TryFrom<Vec<UciPacketHal>> for UciControlPacket { } .build() .to_bytes(), - ); + ); } error!("Received unexpected fragment: {:?}", packet); return Err(Error::InvalidPacketError); @@ -953,6 +954,68 @@ impl Drop for AppConfigTlv { } } +#[derive(Debug, Clone, PartialEq)] +pub enum PhaseList { + ShortMacAddress(Vec<PhaseListShortMacAddress>), + ExtendedMacAddress(Vec<PhaseListExtendedMacAddress>), +} + +/// Generate the SessionSetHybridControllerConfig packet. +pub fn build_session_set_hybrid_controller_config_cmd( + session_token: u32, + message_control: u8, + number_of_phases: u8, + update_time: [u8; 8], + phase_list: PhaseList, +) -> Result<SessionSetHybridControllerConfigCmd> { + let mut phase_list_buffer = BytesMut::new(); + match phase_list { + PhaseList::ShortMacAddress(phaseListShortMacAddressVec) => { + for phaseListShortMacAddress in phaseListShortMacAddressVec { + phase_list_buffer.extend_from_slice( + &(phaseListShortMacAddress.session_token.to_le_bytes()[0..4]), + ); + phase_list_buffer.extend_from_slice( + &(phaseListShortMacAddress.start_slot_index.to_le_bytes()[0..2]), + ); + phase_list_buffer.extend_from_slice( + &(phaseListShortMacAddress.end_slot_index.to_le_bytes()[0..2]), + ); + phase_list_buffer.extend_from_slice(std::slice::from_ref( + &phaseListShortMacAddress.phase_participation, + )); + phase_list_buffer.extend_from_slice(&phaseListShortMacAddress.mac_address); + } + } + PhaseList::ExtendedMacAddress(phaseListExtendedMacAddressVec) => { + for phaseListExtendedMacAddress in phaseListExtendedMacAddressVec { + phase_list_buffer.extend_from_slice( + &(phaseListExtendedMacAddress.session_token.to_le_bytes()[0..4]), + ); + phase_list_buffer.extend_from_slice( + &(phaseListExtendedMacAddress.start_slot_index.to_le_bytes()[0..2]), + ); + phase_list_buffer.extend_from_slice( + &(phaseListExtendedMacAddress.end_slot_index.to_le_bytes()[0..2]), + ); + phase_list_buffer.extend_from_slice(std::slice::from_ref( + &phaseListExtendedMacAddress.phase_participation, + )); + phase_list_buffer.extend_from_slice(&phaseListExtendedMacAddress.mac_address); + } + } + _ => return Err(Error::InvalidPacketError), + } + Ok(SessionSetHybridControllerConfigCmdBuilder { + session_token, + message_control, + number_of_phases, + update_time, + payload: Some(phase_list_buffer.freeze()), + } + .build()) +} + // 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. diff --git a/src/rust/uwb_uci_packets/uci_packets.pdl b/src/rust/uwb_uci_packets/uci_packets.pdl index 3c80f87..7b3e174 100644 --- a/src/rust/uwb_uci_packets/uci_packets.pdl +++ b/src/rust/uwb_uci_packets/uci_packets.pdl @@ -66,7 +66,8 @@ enum SessionConfigOpCode : 6 { SESSION_UPDATE_ACTIVE_ROUNDS_DT_TAG = 0x09, SESSION_SET_INITIATOR_DT_ANCHOR_RR_RDM_LIST = 0x0a, SESSION_QUERY_DATA_SIZE_IN_RANGING = 0x0b, - SESSION_SET_HUS_CONFIG = 0x0c, + SESSION_SET_HUS_CONTROLLER_CONFIG = 0x0c, + SESSION_SET_HUS_CONTROLEE_CONFIG = 0x0d, SESSION_DATA_TRANSFER_PHASE_CONFIGURATION = 0x0e, } @@ -972,22 +973,6 @@ 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, @@ -1088,6 +1073,65 @@ test SessionDataTransferPhaseConfigNtf { "\x61\x0E\x00\x05\x00\x00\x00\x00\x00" } +struct PhaseListShortMacAddress { + session_token: 32, + start_slot_index: 16, + end_slot_index: 16, + phase_participation: 8, + mac_address: 8[2], +} + +struct PhaseListExtendedMacAddress { + session_token: 32, + start_slot_index: 16, + end_slot_index: 16, + phase_participation: 8, + mac_address: 8[8], +} + +packet SessionSetHybridControllerConfigCmd : SessionConfigCommand (opcode = 0x0C) { //SESSION_SET_HUS_CONTROLLER_CONFIG + session_token: 32, + message_control: 8, + number_of_phases: 8, + update_time: 8[8], + _payload_, +} + +test SessionSetHybridControllerConfigCmd { +"\x21\x0C\x00\x23\x03\x00\x00\x01\x00\x02\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x05\x01\x00\x19\x00\x00\x30\x00\x02\x00\x00\x03\x1A\x00\x32\x00\x00\x30\x00", +} + +packet SessionSetHybridControllerConfigRsp : SessionConfigResponse (opcode = 0x0C) { //SESSION_SET_HUS_CONTROLLER_CONFIG + status: StatusCode, +} + +test SessionSetHybridControllerConfigRsp { + "\x41\x0C\x00\x01\x00" +} + +struct ControleePhaseList { + session_token: 32, + phase_participation: 8, +} + +packet SessionSetHybridControleeConfigCmd : SessionConfigCommand (opcode = 0x0D) { //SESSION_SET_HUS_CONTROLEE_CONFIG + session_token: 32, + _count_(controlee_phase_list): 8, + controlee_phase_list: ControleePhaseList[], +} + +test SessionSetHybridControleeConfigCmd { + "\x21\x0D\x00\x0F\x03\x00\x00\x01\x02\x01\x00\x00\x05\x02\x02\x00\x00\x03\x02", +} + +packet SessionSetHybridControleeConfigRsp : SessionConfigResponse (opcode = 0x0D) { //SESSION_SET_HUS_CONTROLEE_CONFIG + status: StatusCode, +} + +test SessionSetHybridControleeConfigRsp { + "\x41\x0D\x00\x01\x00" +} + packet SessionStartCmd : SessionControlCommand (opcode = 0x0) { //RANGE_START session_token: 32, // Session ID or Session Handle (based on UWBS version) } |