Merge changes Ie82b683f,I31e98b5f,I4b5712fa

* changes:
  Uwb(Uci) Initiate recovery from UWB service in case of Timeout
  Uwb(Uci) Add support for Data transfer feature
  Uwb(uci) Fix for DLTdoa changes
diff --git a/src/Android.bp b/src/Android.bp
index 737caad..5fc7630 100755
--- a/src/Android.bp
+++ b/src/Android.bp
@@ -50,6 +50,7 @@
         },
     },
     auto_gen_config: true,
+    min_sdk_version: "33",
 }
 
 rust_library {
@@ -110,6 +111,16 @@
     ],
 }
 
+// Builds uwb_core library with "mock-utils" enabled.
+// This enables mock methods to be used for testing external crates.
+rust_library {
+    name: "libuwb_core_with_mock",
+    defaults: ["libuwb_core_defaults"],
+    crate_name: "uwb_core",
+    features: ["mock-utils"],
+    host_supported: true,
+}
+
 rust_test {
     name: "libuwb_core_tests",
     defaults: ["libuwb_core_defaults"],
@@ -151,6 +162,7 @@
         },
     },
     auto_gen_config: true,
+    min_sdk_version: "33",
 }
 
 rust_binary {
@@ -236,8 +248,8 @@
     },
 }
 
-rust_library {
-    name: "libuci_hal_android",
+rust_defaults {
+    name: "libuci_hal_android_defaults",
     crate_name: "uci_hal_android",
     lints: "android",
     clippy_lints: "android",
@@ -251,7 +263,6 @@
         "liblog_rust",
         "libthiserror",
         "libtokio",
-        "libuwb_core",
         "libuwb_uci_packets",
     ],
     target: {
@@ -274,6 +285,25 @@
     ],
 }
 
+rust_library {
+    name: "libuci_hal_android",
+    defaults: ["libuci_hal_android_defaults"],
+    rustlibs: [
+        "libuwb_core",
+    ],
+}
+
+// uci_hal_android built with uwb_core_with_mock.
+// Used to replace uci_hal_android in place where mock version of uwb_core is
+// used.
+rust_library {
+    name: "libuci_hal_android_with_mock",
+    defaults: ["libuci_hal_android_defaults"],
+    rustlibs: [
+        "libuwb_core_with_mock",
+    ],
+}
+
 // Generate the artifacts zip for uwb_core library and its dependencies.
 genrule {
     name: "uwb_core_artifacts",
diff --git a/src/rust/uwb_core/protos/uwb_service.proto b/src/rust/uwb_core/protos/uwb_service.proto
index db47aba..c2f6eb7 100644
--- a/src/rust/uwb_core/protos/uwb_service.proto
+++ b/src/rust/uwb_core/protos/uwb_service.proto
@@ -131,12 +131,13 @@
   STATE_CHANGE_WITH_SESSION_MANAGEMENT_COMMANDS = 0;
   MAX_RANGING_ROUND_RETRY_COUNT_REACHED = 1;
   MAX_NUMBER_OF_MEASUREMENTS_REACHED = 2;
-  ERROR_SLOT_LENGTH_NOT_SUPPORTED = 20;
-  ERROR_INSUFFICIENT_SLOTS_PER_RR = 21;
-  ERROR_MAC_ADDRESS_MODE_NOT_SUPPORTED = 22;
-  ERROR_INVALID_RANGING_INTERVAL = 23;
-  ERROR_INVALID_STS_CONFIG = 24;
-  ERROR_INVALID_RFRAME_CONFIG = 25;
+  ERROR_INVALID_UL_TDOA_RANDOM_WINDOW = 29;
+  ERROR_SLOT_LENGTH_NOT_SUPPORTED = 32;
+  ERROR_INSUFFICIENT_SLOTS_PER_RR = 33;
+  ERROR_MAC_ADDRESS_MODE_NOT_SUPPORTED = 34;
+  ERROR_INVALID_RANGING_INTERVAL = 35;
+  ERROR_INVALID_STS_CONFIG = 36;
+  ERROR_INVALID_RFRAME_CONFIG = 37;
 }
 
 // Represent uwb_uci_packets::RangingMeasurementType.
@@ -413,6 +414,31 @@
   OwrAoaStatusCode owr_aoa_status_code = 17;
 }
 
+// Represent uwb_uci_packets::ShortAddressDlTdoaRangingMeasurement or
+// uwb_uci_packets::ExtendedAddressDlTdoaRangingMeasurement.
+message DlTDoARangingMeasurement {
+  uint64 mac_address = 1;
+  StatusCode status = 2;
+  uint32 message_control = 3;
+  uint32 block_index = 4;
+  uint32 round_index = 5;
+  uint32 nlos = 6;
+  uint32 aoa_azimuth = 7;
+  uint32 aoa_azimuth_fom = 8;
+  uint32 aoa_elevation = 9;
+  uint32 aoa_elevation_fom = 10;
+  uint32 rssi = 11;
+  uint64 tx_timestamp = 12;
+  uint64 rx_timestamp = 13;
+  uint32 anchor_cfo = 14;
+  uint32 cfo = 15;
+  uint32 initiator_reply_time = 16;
+  uint32 responder_reply_time = 17;
+  uint32 initiator_responder_tof = 18;
+  repeated uint32 dt_anchor_location = 19;
+  repeated uint32 ranging_rounds = 20;
+}
+
 // Represent uwb_core::uci::notification::SessionRangeData;
 message SessionRangeData {
   uint32 sequence_number = 1;
@@ -420,6 +446,7 @@
   uint32 current_ranging_interval_ms = 3;
   RangingMeasurementType ranging_measurement_type = 4;
   repeated RangingMeasurement ranging_measurements = 5;
+  repeated DlTDoARangingMeasurement dltdoa_ranging_measurements = 6;
 }
 
 // Represent uwb_uci_packets::PowerStats;
@@ -548,6 +575,7 @@
   uint32 gid = 1;
   uint32 oid = 2;
   bytes payload = 3;
+  uint32 mt = 4;
 }
 
 // Response of the UwbService::SendVendorCmd() method.
diff --git a/src/rust/uwb_core/src/proto/mappings.rs b/src/rust/uwb_core/src/proto/mappings.rs
index 35622b7..7da6c3c 100644
--- a/src/rust/uwb_core/src/proto/mappings.rs
+++ b/src/rust/uwb_core/src/proto/mappings.rs
@@ -16,6 +16,7 @@
 
 use std::convert::{TryFrom, TryInto};
 
+use num_traits::FromPrimitive;
 use protobuf::RepeatedField;
 use zeroize::Zeroize;
 
@@ -28,22 +29,24 @@
     ScheduledMode, StsConfig, StsLength, TxAdaptivePayloadPower, UwbAddress, UwbChannel,
 };
 use crate::params::uci_packets::{
-    Controlee, DeviceState, ExtendedAddressOwrAoaRangingMeasurement,
-    ExtendedAddressTwoWayRangingMeasurement, OwrAoaStatusCode, PowerStats, RangingMeasurementType,
-    ReasonCode, SessionState, SessionType, ShortAddressOwrAoaRangingMeasurement,
+    Controlee, DeviceState, ExtendedAddressDlTdoaRangingMeasurement,
+    ExtendedAddressOwrAoaRangingMeasurement, ExtendedAddressTwoWayRangingMeasurement,
+    OwrAoaStatusCode, PowerStats, RangingMeasurementType, ReasonCode, SessionState, SessionType,
+    ShortAddressDlTdoaRangingMeasurement, ShortAddressOwrAoaRangingMeasurement,
     ShortAddressTwoWayRangingMeasurement, StatusCode, UpdateMulticastListAction,
 };
 use crate::params::AppConfigParams;
 use crate::proto::bindings::{
     AoaResultRequest as ProtoAoaResultRequest, BprfPhrDataRate as ProtoBprfPhrDataRate,
     Controlee as ProtoControlee, DeviceRole as ProtoDeviceRole, DeviceState as ProtoDeviceState,
-    DeviceType as ProtoDeviceType, FiraAppConfigParams as ProtoFiraAppConfigParams,
-    HoppingMode as ProtoHoppingMode, KeyRotation as ProtoKeyRotation,
-    MacAddressMode as ProtoMacAddressMode, MacFcsType as ProtoMacFcsType,
-    MultiNodeMode as ProtoMultiNodeMode, OwrAoaStatusCode as ProtoOwrAoaStatusCode,
-    PowerStats as ProtoPowerStats, PreambleDuration as ProtoPreambleDuration,
-    PrfMode as ProtoPrfMode, PsduDataRate as ProtoPsduDataRate,
-    RangeDataNtfConfig as ProtoRangeDataNtfConfig, RangingMeasurement as ProtoRangingMeasurement,
+    DeviceType as ProtoDeviceType, DlTDoARangingMeasurement as ProtoDlTDoARangingMeasurement,
+    FiraAppConfigParams as ProtoFiraAppConfigParams, HoppingMode as ProtoHoppingMode,
+    KeyRotation as ProtoKeyRotation, MacAddressMode as ProtoMacAddressMode,
+    MacFcsType as ProtoMacFcsType, MultiNodeMode as ProtoMultiNodeMode,
+    OwrAoaStatusCode as ProtoOwrAoaStatusCode, PowerStats as ProtoPowerStats,
+    PreambleDuration as ProtoPreambleDuration, PrfMode as ProtoPrfMode,
+    PsduDataRate as ProtoPsduDataRate, RangeDataNtfConfig as ProtoRangeDataNtfConfig,
+    RangingMeasurement as ProtoRangingMeasurement,
     RangingMeasurementType as ProtoRangingMeasurementType,
     RangingRoundControl as ProtoRangingRoundControl, RangingRoundUsage as ProtoRangingRoundUsage,
     RangingTimeStruct as ProtoRangingTimeStruct, ReasonCode as ProtoReasonCode,
@@ -169,6 +172,7 @@
     STATE_CHANGE_WITH_SESSION_MANAGEMENT_COMMANDS => StateChangeWithSessionManagementCommands,
     MAX_RANGING_ROUND_RETRY_COUNT_REACHED => MaxRangingRoundRetryCountReached,
     MAX_NUMBER_OF_MEASUREMENTS_REACHED => MaxNumberOfMeasurementsReached,
+    ERROR_INVALID_UL_TDOA_RANDOM_WINDOW => ErrorInvalidUlTdoaRandomWindow,
     ERROR_SLOT_LENGTH_NOT_SUPPORTED => ErrorSlotLengthNotSupported,
     ERROR_INSUFFICIENT_SLOTS_PER_RR => ErrorInsufficientSlotsPerRr,
     ERROR_MAC_ADDRESS_MODE_NOT_SUPPORTED => ErrorMacAddressModeNotSupported,
@@ -353,6 +357,11 @@
     ADD_CONTROLEE_WITH_LONG_SUB_SESSION_KEY => AddControleeWithLongSubSessionKey,
 }
 
+pub enum ProtoRangingMeasurements {
+    Ranging(Vec<ProtoRangingMeasurement>),
+    DlTDoa(Vec<ProtoDlTDoARangingMeasurement>),
+}
+
 impl<T> From<Result<T>> for ProtoStatus {
     fn from(item: Result<T>) -> Self {
         match item {
@@ -444,6 +453,84 @@
     }
 }
 
+impl From<ShortAddressDlTdoaRangingMeasurement> for ProtoDlTDoARangingMeasurement {
+    fn from(item: ShortAddressDlTdoaRangingMeasurement) -> Self {
+        let mut result = Self::new();
+        result.set_mac_address(item.mac_address.into());
+        result.set_status(
+            StatusCode::from_u8(item.measurement.status)
+                .unwrap_or(StatusCode::UciStatusFailed)
+                .into(),
+        );
+        result.set_message_control(item.measurement.message_control.into());
+        result.set_block_index(item.measurement.block_index.into());
+        result.set_round_index(item.measurement.round_index.into());
+        result.set_nlos(item.measurement.nlos.into());
+        result.set_aoa_azimuth(item.measurement.aoa_azimuth.into());
+        result.set_aoa_azimuth_fom(item.measurement.aoa_azimuth_fom.into());
+        result.set_aoa_elevation(item.measurement.aoa_elevation.into());
+        result.set_aoa_elevation_fom(item.measurement.aoa_elevation_fom.into());
+        result.set_rssi(item.measurement.rssi.into());
+        result.set_tx_timestamp(item.measurement.tx_timestamp);
+        result.set_rx_timestamp(item.measurement.rx_timestamp);
+        result.set_anchor_cfo(item.measurement.anchor_cfo.into());
+        result.set_cfo(item.measurement.cfo.into());
+        result.set_initiator_reply_time(item.measurement.initiator_reply_time);
+        result.set_responder_reply_time(item.measurement.responder_reply_time);
+        result.set_initiator_responder_tof(item.measurement.initiator_responder_tof.into());
+        result.set_dt_anchor_location(
+            item.measurement
+                .dt_anchor_location
+                .into_iter()
+                .map(|val| val as u32)
+                .collect::<Vec<u32>>(),
+        );
+        result.set_ranging_rounds(
+            item.measurement.ranging_rounds.into_iter().map(|val| val as u32).collect::<Vec<u32>>(),
+        );
+        result
+    }
+}
+
+impl From<ExtendedAddressDlTdoaRangingMeasurement> for ProtoDlTDoARangingMeasurement {
+    fn from(item: ExtendedAddressDlTdoaRangingMeasurement) -> Self {
+        let mut result = Self::new();
+        result.set_mac_address(item.mac_address);
+        result.set_status(
+            StatusCode::from_u8(item.measurement.status)
+                .unwrap_or(StatusCode::UciStatusFailed)
+                .into(),
+        );
+        result.set_message_control(item.measurement.message_control.into());
+        result.set_block_index(item.measurement.block_index.into());
+        result.set_round_index(item.measurement.round_index.into());
+        result.set_nlos(item.measurement.nlos.into());
+        result.set_aoa_azimuth(item.measurement.aoa_azimuth.into());
+        result.set_aoa_azimuth_fom(item.measurement.aoa_azimuth_fom.into());
+        result.set_aoa_elevation(item.measurement.aoa_elevation.into());
+        result.set_aoa_elevation_fom(item.measurement.aoa_elevation_fom.into());
+        result.set_rssi(item.measurement.rssi.into());
+        result.set_tx_timestamp(item.measurement.tx_timestamp);
+        result.set_rx_timestamp(item.measurement.rx_timestamp);
+        result.set_anchor_cfo(item.measurement.anchor_cfo.into());
+        result.set_cfo(item.measurement.cfo.into());
+        result.set_initiator_reply_time(item.measurement.initiator_reply_time);
+        result.set_responder_reply_time(item.measurement.responder_reply_time);
+        result.set_initiator_responder_tof(item.measurement.initiator_responder_tof.into());
+        result.set_dt_anchor_location(
+            item.measurement
+                .dt_anchor_location
+                .into_iter()
+                .map(|val| val as u32)
+                .collect::<Vec<u32>>(),
+        );
+        result.set_ranging_rounds(
+            item.measurement.ranging_rounds.into_iter().map(|val| val as u32).collect::<Vec<u32>>(),
+        );
+        result
+    }
+}
+
 impl From<SessionRangeData> for ProtoSessionRangeData {
     fn from(item: SessionRangeData) -> Self {
         let mut result = Self::new();
@@ -451,29 +538,38 @@
         result.set_session_id(item.session_id);
         result.set_current_ranging_interval_ms(item.current_ranging_interval_ms);
         result.set_ranging_measurement_type(item.ranging_measurement_type.into());
-        result.set_ranging_measurements(RepeatedField::from_vec(to_proto_ranging_measurements(
-            item.ranging_measurements,
-        )));
+        match to_proto_ranging_measurements(item.ranging_measurements) {
+            ProtoRangingMeasurements::Ranging(ranging_measurements) => {
+                result.set_ranging_measurements(RepeatedField::from_vec(ranging_measurements))
+            }
+            ProtoRangingMeasurements::DlTDoa(dltdoa_measurements) => {
+                result.set_dltdoa_ranging_measurements(RepeatedField::from_vec(dltdoa_measurements))
+            }
+        }
         result
     }
 }
 
-fn to_proto_ranging_measurements(item: RangingMeasurements) -> Vec<ProtoRangingMeasurement> {
+fn to_proto_ranging_measurements(item: RangingMeasurements) -> ProtoRangingMeasurements {
     match item {
         RangingMeasurements::ShortAddressTwoWay(arr) => {
-            arr.into_iter().map(|item| item.into()).collect()
+            ProtoRangingMeasurements::Ranging(arr.into_iter().map(|item| item.into()).collect())
         }
         RangingMeasurements::ExtendedAddressTwoWay(arr) => {
-            arr.into_iter().map(|item| item.into()).collect()
+            ProtoRangingMeasurements::Ranging(arr.into_iter().map(|item| item.into()).collect())
         }
         RangingMeasurements::ShortAddressOwrAoa(arr) => {
-            arr.into_iter().map(|item| item.into()).collect()
+            ProtoRangingMeasurements::Ranging(arr.into_iter().map(|item| item.into()).collect())
         }
         RangingMeasurements::ExtendedAddressOwrAoa(arr) => {
-            arr.into_iter().map(|item| item.into()).collect()
+            ProtoRangingMeasurements::Ranging(arr.into_iter().map(|item| item.into()).collect())
         }
-        // TODO(b/260499366): Add support for DlTDoA.
-        _ => todo!(),
+        RangingMeasurements::ShortAddressDltdoa(arr) => {
+            ProtoRangingMeasurements::DlTDoa(arr.into_iter().map(|item| item.into()).collect())
+        }
+        RangingMeasurements::ExtendedAddressDltdoa(arr) => {
+            ProtoRangingMeasurements::DlTDoa(arr.into_iter().map(|item| item.into()).collect())
+        }
     }
 }
 
diff --git a/src/rust/uwb_core/src/service/proto_uwb_service.rs b/src/rust/uwb_core/src/service/proto_uwb_service.rs
index 91e3f7a..6cf7d5a 100644
--- a/src/rust/uwb_core/src/service/proto_uwb_service.rs
+++ b/src/rust/uwb_core/src/service/proto_uwb_service.rs
@@ -200,7 +200,7 @@
     pub fn raw_uci_cmd(&self, request: &[u8]) -> Result<Vec<u8>> {
         let request = parse_from_bytes::<SendVendorCmdRequest>(request)?;
         let mut resp = SendVendorCmdResponse::new();
-        match self.service.raw_uci_cmd(request.gid, request.oid, request.payload) {
+        match self.service.raw_uci_cmd(request.mt, request.gid, request.oid, request.payload) {
             Ok(msg) => {
                 resp.set_status(Ok(()).into());
                 resp.set_gid(msg.gid);
diff --git a/src/rust/uwb_core/src/service/uwb_service.rs b/src/rust/uwb_core/src/service/uwb_service.rs
index 8bc594b..8c47243 100644
--- a/src/rust/uwb_core/src/service/uwb_service.rs
+++ b/src/rust/uwb_core/src/service/uwb_service.rs
@@ -229,8 +229,14 @@
     }
 
     /// Send a raw UCI message.
-    pub fn raw_uci_cmd(&self, gid: u32, oid: u32, payload: Vec<u8>) -> Result<RawUciMessage> {
-        match self.block_on_cmd(Command::RawUciCmd { gid, oid, payload })? {
+    pub fn raw_uci_cmd(
+        &self,
+        mt: u32,
+        gid: u32,
+        oid: u32,
+        payload: Vec<u8>,
+    ) -> Result<RawUciMessage> {
+        match self.block_on_cmd(Command::RawUciCmd { mt, gid, oid, payload })? {
             Response::RawUciMessage(msg) => Ok(msg),
             _ => panic!("raw_uci_cmd() should return RawUciMessage"),
         }
@@ -409,8 +415,8 @@
                 let stats = self.uci_manager.android_get_power_stats().await?;
                 Ok(Response::PowerStats(stats))
             }
-            Command::RawUciCmd { gid, oid, payload } => {
-                let msg = self.uci_manager.raw_uci_cmd(gid, oid, payload).await?;
+            Command::RawUciCmd { mt, gid, oid, payload } => {
+                let msg = self.uci_manager.raw_uci_cmd(mt, gid, oid, payload).await?;
                 Ok(Response::RawUciMessage(msg))
             }
             Command::GetParams { session_id } => {
@@ -544,6 +550,7 @@
     },
     AndroidGetPowerStats,
     RawUciCmd {
+        mt: u32,
         gid: u32,
         oid: u32,
         payload: Vec<u8>,
@@ -751,6 +758,7 @@
 
     #[test]
     fn test_send_raw_cmd() {
+        let mt = 0x01;
         let gid = 0x09;
         let oid = 0x35;
         let cmd_payload = vec![0x12, 0x34];
@@ -758,6 +766,7 @@
 
         let mut uci_manager = MockUciManager::new();
         uci_manager.expect_raw_uci_cmd(
+            mt,
             gid,
             oid,
             cmd_payload.clone(),
@@ -765,7 +774,7 @@
         );
         let (service, _, _runtime) = setup_uwb_service(uci_manager);
 
-        let result = service.raw_uci_cmd(gid, oid, cmd_payload).unwrap();
+        let result = service.raw_uci_cmd(mt, gid, oid, cmd_payload).unwrap();
         assert_eq!(result, RawUciMessage { gid, oid, payload: resp_payload });
     }
 
diff --git a/src/rust/uwb_core/src/uci/command.rs b/src/rust/uwb_core/src/uci/command.rs
index 0f2eac0..8168f81 100644
--- a/src/rust/uwb_core/src/uci/command.rs
+++ b/src/rust/uwb_core/src/uci/command.rs
@@ -23,7 +23,7 @@
     AppConfigTlv, AppConfigTlvType, Controlees, CountryCode, DeviceConfigId, DeviceConfigTlv,
     ResetConfig, SessionId, SessionType, UpdateMulticastListAction,
 };
-use uwb_uci_packets::build_session_update_controller_multicast_list_cmd;
+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)]
@@ -82,13 +82,14 @@
     },
     AndroidGetPowerStats,
     RawUciCmd {
+        mt: u32,
         gid: u32,
         oid: u32,
         payload: Vec<u8>,
     },
 }
 
-impl TryFrom<UciCommand> for uwb_uci_packets::UciCommandPacket {
+impl TryFrom<UciCommand> for uwb_uci_packets::UciControlPacketPacket {
     type Error = Error;
     fn try_from(cmd: UciCommand) -> std::result::Result<Self, Self::Error> {
         let packet = match cmd {
@@ -153,8 +154,8 @@
             UciCommand::AndroidGetPowerStats => {
                 uwb_uci_packets::AndroidGetPowerStatsCmdBuilder {}.build().into()
             }
-            UciCommand::RawUciCmd { gid, oid, payload } => {
-                build_raw_uci_cmd_packet(gid, oid, payload)?
+            UciCommand::RawUciCmd { mt, gid, oid, payload } => {
+                build_raw_uci_cmd_packet(mt, gid, oid, payload)?
             }
             UciCommand::SessionGetCount => {
                 uwb_uci_packets::SessionGetCountCmdBuilder {}.build().into()
@@ -178,11 +179,11 @@
 }
 
 fn build_raw_uci_cmd_packet(
+    mt: u32,
     gid: u32,
     oid: u32,
     payload: Vec<u8>,
-) -> Result<uwb_uci_packets::UciCommandPacket> {
-    use uwb_uci_packets::GroupId;
+) -> Result<uwb_uci_packets::UciControlPacketPacket> {
     let group_id = GroupId::from_u32(gid).ok_or_else(|| {
         error!("Invalid GroupId: {}", gid);
         Error::BadParameters
@@ -192,5 +193,12 @@
         error!("Invalid opcod: {}", oid);
         Error::BadParameters
     })?;
-    Ok(uwb_uci_packets::UciCommandBuilder { opcode, group_id, payload }.build())
+    let message_type = MessageType::from_u32(mt).ok_or_else(|| {
+        error!("Invalid MessageType: {}", mt);
+        Error::BadParameters
+    })?;
+    match uwb_uci_packets::build_uci_control_packet(message_type, group_id, opcode, payload) {
+        Some(cmd) => Ok(cmd),
+        None => Err(Error::BadParameters),
+    }
 }
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 04d604d..249b563 100644
--- a/src/rust/uwb_core/src/uci/mock_uci_manager.rs
+++ b/src/rust/uwb_core/src/uci/mock_uci_manager.rs
@@ -12,6 +12,11 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+//! This module offers a mocked version of UciManager for testing.
+//!
+//! The mocked version of UciManager mimics the behavior of the UCI manager and
+//! stacks below it, such that tests can be run on a target without the UWB
+//! hardware.
 use std::collections::VecDeque;
 use std::sync::{Arc, Mutex};
 use std::time::Duration;
@@ -347,12 +352,14 @@
     /// MockUciManager expects call with parameters, returns out as response.
     pub fn expect_raw_uci_cmd(
         &mut self,
+        expected_mt: u32,
         expected_gid: u32,
         expected_oid: u32,
         expected_payload: Vec<u8>,
         out: Result<RawUciMessage>,
     ) {
         self.expected_calls.lock().unwrap().push_back(ExpectedCall::RawUciCmd {
+            expected_mt,
             expected_gid,
             expected_oid,
             expected_payload,
@@ -793,11 +800,25 @@
         }
     }
 
-    async fn raw_uci_cmd(&self, gid: u32, oid: u32, payload: Vec<u8>) -> Result<RawUciMessage> {
+    async fn raw_uci_cmd(
+        &self,
+        mt: u32,
+        gid: u32,
+        oid: u32,
+        payload: Vec<u8>,
+    ) -> Result<RawUciMessage> {
         let mut expected_calls = self.expected_calls.lock().unwrap();
         match expected_calls.pop_front() {
-            Some(ExpectedCall::RawUciCmd { expected_gid, expected_oid, expected_payload, out })
-                if expected_gid == gid && expected_oid == oid && expected_payload == payload =>
+            Some(ExpectedCall::RawUciCmd {
+                expected_mt,
+                expected_gid,
+                expected_oid,
+                expected_payload,
+                out,
+            }) if expected_mt == mt
+                && expected_gid == gid
+                && expected_oid == oid
+                && expected_payload == payload =>
             {
                 self.expect_call_consumed.notify_one();
                 out
@@ -902,6 +923,7 @@
         out: Result<PowerStats>,
     },
     RawUciCmd {
+        expected_mt: u32,
         expected_gid: u32,
         expected_oid: u32,
         expected_payload: Vec<u8>,
diff --git a/src/rust/uwb_core/src/uci/notification.rs b/src/rust/uwb_core/src/uci/notification.rs
index 95f70bf..2463cb4 100644
--- a/src/rust/uwb_core/src/uci/notification.rs
+++ b/src/rust/uwb_core/src/uci/notification.rs
@@ -109,10 +109,10 @@
     ExtendedAddressTwoWay(Vec<ExtendedAddressTwoWayRangingMeasurement>),
 
     /// Dl-TDoA measurement with short address.
-    ShortDltdoa(Vec<ShortAddressDlTdoaRangingMeasurement>),
+    ShortAddressDltdoa(Vec<ShortAddressDlTdoaRangingMeasurement>),
 
     /// Dl-TDoA measurement with extended address.
-    ExtendedDltdoa(Vec<ExtendedAddressDlTdoaRangingMeasurement>),
+    ExtendedAddressDltdoa(Vec<ExtendedAddressDlTdoaRangingMeasurement>),
 
     /// OWR for AoA measurement with short address.
     ShortAddressOwrAoa(Vec<ShortAddressOwrAoaRangingMeasurement>),
@@ -296,7 +296,7 @@
                 match ShortAddressDlTdoaRangingMeasurement::parse(&evt.clone().to_vec()) {
                     Some(v) => {
                         if v.len() == evt.get_no_of_ranging_measurements().into() {
-                            RangingMeasurements::ShortDltdoa(v)
+                            RangingMeasurements::ShortAddressDltdoa(v)
                         } else {
                             error!("Wrong count of ranging measurements {:?}", evt);
                             return Err(Error::BadParameters);
@@ -309,7 +309,7 @@
                 match ExtendedAddressDlTdoaRangingMeasurement::parse(&evt.clone().to_vec()) {
                     Some(v) => {
                         if v.len() == evt.get_no_of_ranging_measurements().into() {
-                            RangingMeasurements::ExtendedDltdoa(v)
+                            RangingMeasurements::ExtendedAddressDltdoa(v)
                         } else {
                             error!("Wrong count of ranging measurements {:?}", evt);
                             return Err(Error::BadParameters);
diff --git a/src/rust/uwb_core/src/uci/uci_hal.rs b/src/rust/uwb_core/src/uci/uci_hal.rs
index f82d20e..27c593d 100644
--- a/src/rust/uwb_core/src/uci/uci_hal.rs
+++ b/src/rust/uwb_core/src/uci/uci_hal.rs
@@ -18,9 +18,7 @@
 
 use async_trait::async_trait;
 use tokio::sync::mpsc;
-use uwb_uci_packets::{
-    Packet, UciCommandPacket, UciControlPacketHalPacket, UciControlPacketPacket,
-};
+use uwb_uci_packets::{Packet, UciControlPacketHalPacket, UciControlPacketPacket};
 
 use crate::error::Result;
 use crate::params::uci_packets::SessionId;
@@ -59,8 +57,7 @@
         // A UCI command message may consist of multiple UCI packets when the payload is over the
         // maximum packet size. We convert the command into list of UciHalPacket, then send the
         // packets via send_packet().
-        let packet: UciCommandPacket = cmd.try_into()?;
-        let packet: UciControlPacketPacket = packet.into();
+        let packet: UciControlPacketPacket = cmd.try_into()?;
         let fragmented_packets: Vec<UciControlPacketHalPacket> = packet.into();
         for packet in fragmented_packets.into_iter() {
             self.send_packet(packet.to_vec()).await?;
diff --git a/src/rust/uwb_core/src/uci/uci_logger.rs b/src/rust/uwb_core/src/uci/uci_logger.rs
index 51a71de..e3e5630 100644
--- a/src/rust/uwb_core/src/uci/uci_logger.rs
+++ b/src/rust/uwb_core/src/uci/uci_logger.rs
@@ -17,7 +17,7 @@
 
 use uwb_uci_packets::{
     AppConfigTlv, AppConfigTlvType, Packet, SessionCommandChild, SessionGetAppConfigRspBuilder,
-    SessionResponseChild, SessionSetAppConfigCmdBuilder, UciCommandChild, UciCommandPacket,
+    SessionResponseChild, SessionSetAppConfigCmdBuilder, UciCommandChild, UciControlPacketChild,
     UciControlPacketPacket, UciDataPacketPacket, UciResponseChild, UciResponsePacket,
     UCI_PACKET_HAL_HEADER_LEN,
 };
@@ -69,16 +69,19 @@
     tlv
 }
 
-fn filter_uci_command(cmd: UciCommandPacket) -> UciCommandPacket {
+fn filter_uci_command(cmd: UciControlPacketPacket) -> UciControlPacketPacket {
     match cmd.specialize() {
-        UciCommandChild::SessionCommand(session_cmd) => match session_cmd.specialize() {
-            SessionCommandChild::SessionSetAppConfigCmd(set_config_cmd) => {
-                let session_id = set_config_cmd.get_session_id();
-                let tlvs = set_config_cmd.get_tlvs().to_owned();
-                let filtered_tlvs = tlvs.into_iter().map(filter_tlv).collect();
-                SessionSetAppConfigCmdBuilder { session_id, tlvs: filtered_tlvs }.build().into()
-            }
-            _ => session_cmd.into(),
+        UciControlPacketChild::UciCommand(control_cmd) => match control_cmd.specialize() {
+            UciCommandChild::SessionCommand(session_cmd) => match session_cmd.specialize() {
+                SessionCommandChild::SessionSetAppConfigCmd(set_config_cmd) => {
+                    let session_id = set_config_cmd.get_session_id();
+                    let tlvs = set_config_cmd.get_tlvs().to_owned();
+                    let filtered_tlvs = tlvs.into_iter().map(filter_tlv).collect();
+                    SessionSetAppConfigCmdBuilder { session_id, tlvs: filtered_tlvs }.build().into()
+                }
+                _ => session_cmd.into(),
+            },
+            _ => cmd,
         },
         _ => cmd,
     }
@@ -145,13 +148,13 @@
         match self.mode {
             UciLoggerMode::Disabled => (),
             UciLoggerMode::Unfiltered => {
-                if let Ok(packet) = UciCommandPacket::try_from(cmd.clone()) {
-                    self.logger.log_uci_control_packet(packet.into());
+                if let Ok(packet) = UciControlPacketPacket::try_from(cmd.clone()) {
+                    self.logger.log_uci_control_packet(packet);
                 };
             }
             UciLoggerMode::Filtered => {
-                if let Ok(packet) = UciCommandPacket::try_from(cmd.clone()) {
-                    self.logger.log_uci_control_packet(filter_uci_command(packet).into());
+                if let Ok(packet) = UciControlPacketPacket::try_from(cmd.clone()) {
+                    self.logger.log_uci_control_packet(filter_uci_command(packet));
                 };
             }
         }
diff --git a/src/rust/uwb_core/src/uci/uci_manager.rs b/src/rust/uwb_core/src/uci/uci_manager.rs
index 81271b7..7367500 100644
--- a/src/rust/uwb_core/src/uci/uci_manager.rs
+++ b/src/rust/uwb_core/src/uci/uci_manager.rs
@@ -122,7 +122,13 @@
     async fn android_get_power_stats(&self) -> Result<PowerStats>;
 
     // Send a raw uci command.
-    async fn raw_uci_cmd(&self, gid: u32, oid: u32, payload: Vec<u8>) -> Result<RawUciMessage>;
+    async fn raw_uci_cmd(
+        &self,
+        mt: u32,
+        gid: u32,
+        oid: u32,
+        payload: Vec<u8>,
+    ) -> Result<RawUciMessage>;
 }
 
 /// UciManagerImpl is the main implementation of UciManager. Using the actor model, UciManagerImpl
@@ -414,8 +420,14 @@
         }
     }
 
-    async fn raw_uci_cmd(&self, gid: u32, oid: u32, payload: Vec<u8>) -> Result<RawUciMessage> {
-        let cmd = UciCommand::RawUciCmd { gid, oid, payload };
+    async fn raw_uci_cmd(
+        &self,
+        mt: u32,
+        gid: u32,
+        oid: u32,
+        payload: Vec<u8>,
+    ) -> Result<RawUciMessage> {
+        let cmd = UciCommand::RawUciCmd { mt, gid, oid, payload };
         match self.send_cmd(UciManagerCmd::SendUciCommand { cmd }).await {
             Ok(UciResponse::RawUciCmd(resp)) => resp,
             Ok(_) => Err(Error::Unknown),
@@ -628,7 +640,7 @@
 
                 // Remember that this command is a raw UCI command, we'll use this later
                 // to send a raw UCI response.
-                if let UciCommand::RawUciCmd { gid, oid, payload: _ } = cmd.clone() {
+                if let UciCommand::RawUciCmd { mt: _, gid, oid, payload: _ } = cmd.clone() {
                     let gid = GroupId::from_u32(gid);
                     let oid = oid.to_u8();
                     if oid.is_none() || gid.is_none() {
@@ -1494,6 +1506,7 @@
 
     #[tokio::test]
     async fn test_raw_uci_cmd_vendor_gid_ok() {
+        let mt = 0x1;
         let gid = 0xF; // Vendor reserved GID.
         let oid = 0x3;
         let cmd_payload = vec![0x11, 0x22, 0x33, 0x44];
@@ -1503,7 +1516,7 @@
 
         let (uci_manager, mut mock_hal) = setup_uci_manager_with_open_hal(
             move |hal| {
-                let cmd = UciCommand::RawUciCmd { gid, oid, payload: cmd_payload_clone };
+                let cmd = UciCommand::RawUciCmd { mt, gid, oid, payload: cmd_payload_clone };
                 let resp = into_uci_hal_packets(uwb_uci_packets::UciVendor_F_ResponseBuilder {
                     opcode: oid as u8,
                     payload: Some(Bytes::from(resp_payload_clone)),
@@ -1517,13 +1530,14 @@
         .await;
 
         let expected_result = RawUciMessage { gid, oid, payload: resp_payload };
-        let result = uci_manager.raw_uci_cmd(gid, oid, cmd_payload).await.unwrap();
+        let result = uci_manager.raw_uci_cmd(mt, gid, oid, cmd_payload).await.unwrap();
         assert_eq!(result, expected_result);
         assert!(mock_hal.wait_expected_calls_done().await);
     }
 
     #[tokio::test]
     async fn test_raw_uci_cmd_fira_gid_ok() {
+        let mt = 0x1;
         let gid = 0x1; // SESSION_CONFIG GID.
         let oid = 0x3;
         let cmd_payload = vec![0x11, 0x22, 0x33, 0x44];
@@ -1536,7 +1550,7 @@
 
         let (uci_manager, mut mock_hal) = setup_uci_manager_with_open_hal(
             move |hal| {
-                let cmd = UciCommand::RawUciCmd { gid, oid, payload: cmd_payload_clone };
+                let cmd = UciCommand::RawUciCmd { mt, gid, oid, payload: cmd_payload_clone };
                 let resp = into_uci_hal_packets(uwb_uci_packets::SessionSetAppConfigRspBuilder {
                     status,
                     cfg_status,
@@ -1550,7 +1564,41 @@
         .await;
 
         let expected_result = RawUciMessage { gid, oid, payload: resp_payload };
-        let result = uci_manager.raw_uci_cmd(gid, oid, cmd_payload).await.unwrap();
+        let result = uci_manager.raw_uci_cmd(mt, gid, oid, cmd_payload).await.unwrap();
+        assert_eq!(result, expected_result);
+        assert!(mock_hal.wait_expected_calls_done().await);
+    }
+
+    #[tokio::test]
+    async fn test_raw_uci_cmd_mt_testing_ok() {
+        let mt = 0x4;
+        let gid = 0x1; // SESSION_CONFIG GID.
+        let oid = 0x3;
+        let cmd_payload = vec![0x11, 0x22, 0x33, 0x44];
+        let cmd_payload_clone = cmd_payload.clone();
+        let resp_payload = vec![0x00, 0x01, 0x07, 0x00];
+        let status = StatusCode::UciStatusOk;
+        let cfg_id = AppConfigTlvType::DstMacAddress;
+        let app_config = AppConfigStatus { cfg_id, status };
+        let cfg_status = vec![app_config];
+
+        let (uci_manager, mut mock_hal) = setup_uci_manager_with_open_hal(
+            move |hal| {
+                let cmd = UciCommand::RawUciCmd { mt, gid, oid, payload: cmd_payload_clone };
+                let resp = into_uci_hal_packets(uwb_uci_packets::SessionSetAppConfigRspBuilder {
+                    status,
+                    cfg_status,
+                });
+
+                hal.expected_send_command(cmd, resp, Ok(()));
+            },
+            UciLoggerMode::Disabled,
+            mpsc::unbounded_channel::<UciLogEvent>().0,
+        )
+        .await;
+
+        let expected_result = RawUciMessage { gid, oid, payload: resp_payload };
+        let result = uci_manager.raw_uci_cmd(mt, gid, oid, cmd_payload).await.unwrap();
         assert_eq!(result, expected_result);
         assert!(mock_hal.wait_expected_calls_done().await);
     }
@@ -1561,6 +1609,7 @@
         // with SESSION_CONFIG GID.
         // In this case, UciManager should return Error::Unknown.
 
+        let mt = 0x1;
         let gid = 0x0; // CORE GID.
         let oid = 0x1;
         let cmd_payload = vec![0x11, 0x22, 0x33, 0x44];
@@ -1572,7 +1621,7 @@
 
         let (uci_manager, mut mock_hal) = setup_uci_manager_with_open_hal(
             move |hal| {
-                let cmd = UciCommand::RawUciCmd { gid, oid, payload: cmd_payload_clone };
+                let cmd = UciCommand::RawUciCmd { mt, gid, oid, payload: cmd_payload_clone };
                 let resp = into_uci_hal_packets(uwb_uci_packets::SessionSetAppConfigRspBuilder {
                     status,
                     cfg_status,
@@ -1586,7 +1635,7 @@
         .await;
 
         let expected_result = Err(Error::Unknown);
-        let result = uci_manager.raw_uci_cmd(gid, oid, cmd_payload).await;
+        let result = uci_manager.raw_uci_cmd(mt, gid, oid, cmd_payload).await;
         assert_eq!(result, expected_result);
         assert!(mock_hal.wait_expected_calls_done().await);
     }
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 c957d37..96c310a 100644
--- a/src/rust/uwb_core/src/uci/uci_manager_sync.rs
+++ b/src/rust/uwb_core/src/uci/uci_manager_sync.rs
@@ -333,8 +333,14 @@
     }
 
     /// Send a raw UCI command.
-    pub fn raw_uci_cmd(&self, gid: u32, oid: u32, payload: Vec<u8>) -> Result<RawUciMessage> {
-        self.runtime_handle.block_on(self.uci_manager.raw_uci_cmd(gid, oid, payload))
+    pub fn raw_uci_cmd(
+        &self,
+        mt: u32,
+        gid: u32,
+        oid: u32,
+        payload: Vec<u8>,
+    ) -> Result<RawUciMessage> {
+        self.runtime_handle.block_on(self.uci_manager.raw_uci_cmd(mt, gid, oid, payload))
     }
 }
 
diff --git a/src/rust/uwb_uci_packets/src/lib.rs b/src/rust/uwb_uci_packets/src/lib.rs
index 049d7da..4a77f1d 100644
--- a/src/rust/uwb_uci_packets/src/lib.rs
+++ b/src/rust/uwb_uci_packets/src/lib.rs
@@ -297,11 +297,28 @@
 
 fn is_uci_control_packet(message_type: MessageType) -> bool {
     match message_type {
-        MessageType::Command | MessageType::Response | MessageType::Notification => true,
+        MessageType::Command
+        | MessageType::Response
+        | MessageType::Notification
+        | MessageType::ReservedForTesting1
+        | MessageType::ReservedForTesting2 => true,
         _ => false,
     }
 }
 
+pub fn build_uci_control_packet(
+    message_type: MessageType,
+    group_id: GroupId,
+    opcode: u8,
+    payload: Option<Bytes>,
+) -> Option<UciControlPacketPacket> {
+    if !is_uci_control_packet(message_type) {
+        error!("Only control packets are allowed, MessageType: {}", message_type);
+        return None;
+    }
+    Some(UciControlPacketBuilder { group_id, message_type, opcode, payload }.build())
+}
+
 // Ensure that the new packet fragment belong to the same packet.
 fn is_same_control_packet(header: &UciControlPacketHeader, packet: &UciPacketHalPacket) -> bool {
     is_uci_control_packet(header.message_type)
diff --git a/src/rust/uwb_uci_packets/uci_packets.pdl b/src/rust/uwb_uci_packets/uci_packets.pdl
index 14408ef..6c99fa7 100644
--- a/src/rust/uwb_uci_packets/uci_packets.pdl
+++ b/src/rust/uwb_uci_packets/uci_packets.pdl
@@ -305,6 +305,7 @@
     STATE_CHANGE_WITH_SESSION_MANAGEMENT_COMMANDS = 0x00,
     MAX_RANGING_ROUND_RETRY_COUNT_REACHED = 0x01,
     MAX_NUMBER_OF_MEASUREMENTS_REACHED = 0x02,
+    ERROR_INVALID_UL_TDOA_RANDOM_WINDOW = 0x1D,
     ERROR_SLOT_LENGTH_NOT_SUPPORTED = 0x20,
     ERROR_INSUFFICIENT_SLOTS_PER_RR = 0x21,
     ERROR_MAC_ADDRESS_MODE_NOT_SUPPORTED = 0x22,
@@ -339,6 +340,8 @@
     COMMAND = 0x01,
     RESPONSE = 0x02,
     NOTIFICATION = 0x03,
+    RESERVED_FOR_TESTING_1 = 0x04,
+    RESERVED_FOR_TESTING_2 = 0x05,
 }
 
 // UCI packet description in compliance with the FIRA UCI spec.