Merge "[uwb-core] Add support support for custom vendor message type"
diff --git a/src/rust/uwb_core/protos/uwb_service.proto b/src/rust/uwb_core/protos/uwb_service.proto
index bc71f8f..35e989e 100644
--- a/src/rust/uwb_core/protos/uwb_service.proto
+++ b/src/rust/uwb_core/protos/uwb_service.proto
@@ -549,6 +549,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/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 f511551..249b563 100644
--- a/src/rust/uwb_core/src/uci/mock_uci_manager.rs
+++ b/src/rust/uwb_core/src/uci/mock_uci_manager.rs
@@ -352,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,
@@ -798,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
@@ -907,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/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 3e9a39f..6c99fa7 100644
--- a/src/rust/uwb_uci_packets/uci_packets.pdl
+++ b/src/rust/uwb_uci_packets/uci_packets.pdl
@@ -340,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.