summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorTreeHugger Robot <treehugger-gerrit@google.com>2022-02-26 04:22:17 +0000
committerAndroid (Google) Code Review <android-gerrit@google.com>2022-02-26 04:22:17 +0000
commitc3aab1e047396f54d95cd76ca09ccba797e5bac2 (patch)
tree0e7091ae381c7e3207adc55eb0bea6e8f64ae567 /src
parentbf494c749999349deb9ad3b0d5cf3a96f9658a7d (diff)
parent290fcf2943e1d065c056ca0199a14f1d902813ad (diff)
downloaduwb-c3aab1e047396f54d95cd76ca09ccba797e5bac2.tar.gz
Merge "uwb(uci-rust): Uci Logging" into tm-dev
Diffstat (limited to 'src')
-rw-r--r--src/rust/adaptation/mod.rs498
-rw-r--r--src/rust/uci/mod.rs21
-rw-r--r--src/rust/uci/uci_hrcv.rs4
-rw-r--r--src/rust/uci/uci_logger.rs292
4 files changed, 566 insertions, 249 deletions
diff --git a/src/rust/adaptation/mod.rs b/src/rust/adaptation/mod.rs
index f12870d..2dfbcc1 100644
--- a/src/rust/adaptation/mod.rs
+++ b/src/rust/adaptation/mod.rs
@@ -2,6 +2,7 @@
use crate::error::UwbErr;
use crate::uci::uci_hrcv;
+use crate::uci::uci_logger::{UciLogMode, UciLogger, UciLoggerImpl};
use crate::uci::HalCallback;
use android_hardware_uwb::aidl::android::hardware::uwb::{
IUwb::IUwbAsync,
@@ -14,19 +15,30 @@ use android_hardware_uwb::binder::{BinderFeatures, Interface, Result as BinderRe
use async_trait::async_trait;
use binder_tokio::{Tokio, TokioRuntime};
use log::error;
+use std::sync::Arc;
use tokio::runtime::Handle;
use tokio::sync::mpsc;
-use uwb_uci_packets::UciPacketPacket;
+use uwb_uci_packets::{Packet, UciCommandPacket, UciPacketChild, UciPacketPacket};
type Result<T> = std::result::Result<T, UwbErr>;
+type SyncUciLogger = Arc<dyn UciLogger + Send + Sync>;
pub struct UwbClientCallback {
rsp_sender: mpsc::UnboundedSender<HalCallback>,
+ logger: SyncUciLogger,
}
impl UwbClientCallback {
- fn new(rsp_sender: mpsc::UnboundedSender<HalCallback>) -> Self {
- UwbClientCallback { rsp_sender }
+ fn new(rsp_sender: mpsc::UnboundedSender<HalCallback>, logger: SyncUciLogger) -> Self {
+ UwbClientCallback { rsp_sender, logger }
+ }
+
+ async fn log_uci_packet(&self, packet: UciPacketPacket) {
+ match packet.specialize() {
+ UciPacketChild::UciResponse(pkt) => self.logger.log_uci_response(pkt).await,
+ UciPacketChild::UciNotification(pkt) => self.logger.log_uci_notification(pkt).await,
+ _ => {}
+ }
}
}
@@ -43,19 +55,18 @@ impl IUwbClientCallbackAsyncServer for UwbClientCallback {
async fn onUciMessage(&self, data: &[u8]) -> BinderResult<()> {
match UciPacketPacket::parse(data) {
- Ok(evt) => {
- let packet_msg = uci_hrcv::uci_message(evt);
+ Ok(packet) => {
+ self.log_uci_packet(packet.clone()).await;
+ let packet_msg = uci_hrcv::uci_message(packet);
match packet_msg {
Ok(uci_hrcv::UciMessage::Response(evt)) => self
.rsp_sender
.send(HalCallback::UciRsp(evt))
.unwrap_or_else(|e| error!("Error sending uci response: {:?}", e)),
-
Ok(uci_hrcv::UciMessage::Notification(evt)) => self
.rsp_sender
.send(HalCallback::UciNtf(evt))
.unwrap_or_else(|e| error!("Error sending uci notification: {:?}", e)),
-
_ => error!("UCI message which is neither a UCI RSP or NTF: {:?}", data),
}
}
@@ -80,19 +91,21 @@ pub trait UwbAdaptation {
async fn hal_close(&self) -> Result<()>;
async fn core_initialization(&self) -> Result<()>;
async fn session_initialization(&self, session_id: i32) -> Result<()>;
- async fn send_uci_message(&self, data: &[u8]) -> Result<()>;
+ async fn send_uci_message(&self, cmd: UciCommandPacket) -> Result<()>;
}
#[derive(Clone)]
pub struct UwbAdaptationImpl {
hal: Strong<dyn IUwbChipAsync<Tokio>>,
rsp_sender: mpsc::UnboundedSender<HalCallback>,
+ logger: SyncUciLogger,
}
impl UwbAdaptationImpl {
pub async fn new(rsp_sender: mpsc::UnboundedSender<HalCallback>) -> Result<Self> {
let hal = get_hal_service().await?;
- Ok(UwbAdaptationImpl { hal, rsp_sender })
+ let logger = UciLoggerImpl::new(UciLogMode::Filtered).await;
+ Ok(UwbAdaptationImpl { hal, rsp_sender, logger: Arc::new(logger) })
}
}
@@ -102,7 +115,7 @@ impl UwbAdaptation for UwbAdaptationImpl {
async fn hal_open(&self) -> Result<()> {
let m_cback = BnUwbClientCallback::new_async_binder(
- UwbClientCallback::new(self.rsp_sender.clone()),
+ UwbClientCallback::new(self.rsp_sender.clone(), self.logger.clone()),
TokioRuntime(Handle::current()),
BinderFeatures::default(),
);
@@ -110,6 +123,7 @@ impl UwbAdaptation for UwbAdaptationImpl {
}
async fn hal_close(&self) -> Result<()> {
+ self.logger.close_file().await;
Ok(self.hal.close().await?)
}
@@ -121,287 +135,297 @@ impl UwbAdaptation for UwbAdaptationImpl {
Ok(self.hal.sessionInit(session_id).await?)
}
- async fn send_uci_message(&self, data: &[u8]) -> Result<()> {
- self.hal.sendUciMessage(data).await?;
+ async fn send_uci_message(&self, cmd: UciCommandPacket) -> Result<()> {
+ self.logger.log_uci_command(cmd.clone()).await;
+ self.hal.sendUciMessage(&cmd.to_vec()).await?;
// TODO should we be validating the returned number?
Ok(())
}
}
#[cfg(test)]
-use log::warn;
-#[cfg(test)]
-use std::collections::VecDeque;
-#[cfg(test)]
-use std::sync::Mutex;
-
-#[cfg(test)]
-enum ExpectedCall {
- Finalize {
- expected_exit_status: bool,
- },
- HalOpen {
- out: Result<()>,
- },
- HalClose {
- out: Result<()>,
- },
- CoreInitialization {
- out: Result<()>,
- },
- SessionInitialization {
- expected_session_id: i32,
- out: Result<()>,
- },
- SendUciMessage {
- expected_data: Vec<u8>,
- rsp_data: Option<Vec<u8>>,
- notf_data: Option<Vec<u8>>,
- out: Result<()>,
- },
-}
-
-#[cfg(test)]
-pub struct MockUwbAdaptation {
- rsp_sender: mpsc::UnboundedSender<HalCallback>,
- expected_calls: Mutex<VecDeque<ExpectedCall>>,
-}
-
-#[cfg(test)]
-impl MockUwbAdaptation {
- pub fn new(rsp_sender: mpsc::UnboundedSender<HalCallback>) -> Self {
- Self { rsp_sender, expected_calls: Mutex::new(VecDeque::new()) }
+pub mod tests {
+ #![allow(non_snake_case)]
+ use super::*;
+ use crate::uci::uci_logger::MockUciLogger;
+ use log::warn;
+ use std::collections::VecDeque;
+ use std::sync::Mutex as StdMutex;
+
+ enum ExpectedCall {
+ Finalize {
+ expected_exit_status: bool,
+ },
+ HalOpen {
+ out: Result<()>,
+ },
+ HalClose {
+ out: Result<()>,
+ },
+ CoreInitialization {
+ out: Result<()>,
+ },
+ SessionInitialization {
+ expected_session_id: i32,
+ out: Result<()>,
+ },
+ SendUciMessage {
+ expected_data: Vec<u8>,
+ rsp_data: Option<Vec<u8>>,
+ notf_data: Option<Vec<u8>>,
+ out: Result<()>,
+ },
}
- #[allow(dead_code)]
- pub fn expect_finalize(&mut self, expected_exit_status: bool) {
- self.expected_calls
- .lock()
- .unwrap()
- .push_back(ExpectedCall::Finalize { expected_exit_status });
- }
- #[allow(dead_code)]
- pub fn expect_hal_open(&mut self, out: Result<()>) {
- self.expected_calls.lock().unwrap().push_back(ExpectedCall::HalOpen { out });
- }
- #[allow(dead_code)]
- pub fn expect_hal_close(&mut self, out: Result<()>) {
- self.expected_calls.lock().unwrap().push_back(ExpectedCall::HalClose { out });
- }
- #[allow(dead_code)]
- pub fn expect_core_initialization(&mut self, out: Result<()>) {
- self.expected_calls.lock().unwrap().push_back(ExpectedCall::CoreInitialization { out });
- }
- #[allow(dead_code)]
- pub fn expect_session_initialization(&mut self, expected_session_id: i32, out: Result<()>) {
- self.expected_calls
- .lock()
- .unwrap()
- .push_back(ExpectedCall::SessionInitialization { expected_session_id, out });
- }
- #[allow(dead_code)]
- pub fn expect_send_uci_message(
- &mut self,
- expected_data: Vec<u8>,
- rsp_data: Option<Vec<u8>>,
- notf_data: Option<Vec<u8>>,
- out: Result<()>,
- ) {
- self.expected_calls.lock().unwrap().push_back(ExpectedCall::SendUciMessage {
- expected_data,
- rsp_data,
- notf_data,
- out,
- });
+ pub struct MockUwbAdaptation {
+ rsp_sender: mpsc::UnboundedSender<HalCallback>,
+ expected_calls: StdMutex<VecDeque<ExpectedCall>>,
}
- async fn send_client_event(&self, event: UwbEvent, status: UwbStatus) {
- let uwb_client_callback = UwbClientCallback::new(self.rsp_sender.clone());
- let _ = uwb_client_callback.onHalEvent(event, status).await;
- }
+ impl MockUwbAdaptation {
+ pub fn new(rsp_sender: mpsc::UnboundedSender<HalCallback>) -> Self {
+ Self { rsp_sender, expected_calls: StdMutex::new(VecDeque::new()) }
+ }
- async fn send_client_message(&self, rsp_data: Vec<u8>) {
- let uwb_client_callback = UwbClientCallback::new(self.rsp_sender.clone());
- let _ = uwb_client_callback.onUciMessage(&rsp_data).await;
- }
-}
+ #[allow(dead_code)]
+ pub fn expect_finalize(&mut self, expected_exit_status: bool) {
+ self.expected_calls
+ .lock()
+ .unwrap()
+ .push_back(ExpectedCall::Finalize { expected_exit_status });
+ }
+ #[allow(dead_code)]
+ pub fn expect_hal_open(&mut self, out: Result<()>) {
+ self.expected_calls.lock().unwrap().push_back(ExpectedCall::HalOpen { out });
+ }
+ #[allow(dead_code)]
+ pub fn expect_hal_close(&mut self, out: Result<()>) {
+ self.expected_calls.lock().unwrap().push_back(ExpectedCall::HalClose { out });
+ }
+ #[allow(dead_code)]
+ pub fn expect_core_initialization(&mut self, out: Result<()>) {
+ self.expected_calls.lock().unwrap().push_back(ExpectedCall::CoreInitialization { out });
+ }
+ #[allow(dead_code)]
+ pub fn expect_session_initialization(&mut self, expected_session_id: i32, out: Result<()>) {
+ self.expected_calls
+ .lock()
+ .unwrap()
+ .push_back(ExpectedCall::SessionInitialization { expected_session_id, out });
+ }
+ #[allow(dead_code)]
+ pub fn expect_send_uci_message(
+ &mut self,
+ expected_data: Vec<u8>,
+ rsp_data: Option<Vec<u8>>,
+ notf_data: Option<Vec<u8>>,
+ out: Result<()>,
+ ) {
+ self.expected_calls.lock().unwrap().push_back(ExpectedCall::SendUciMessage {
+ expected_data,
+ rsp_data,
+ notf_data,
+ out,
+ });
+ }
-#[cfg(test)]
-impl Drop for MockUwbAdaptation {
- fn drop(&mut self) {
- assert!(self.expected_calls.lock().unwrap().is_empty());
+ fn create_uwb_client_callback(
+ rsp_sender: mpsc::UnboundedSender<HalCallback>,
+ ) -> UwbClientCallback {
+ // Add tests for the mock logger.
+ UwbClientCallback::new(rsp_sender, Arc::new(MockUciLogger::new()))
+ }
+
+ async fn send_client_event(&self, event: UwbEvent, status: UwbStatus) {
+ let uwb_client_callback =
+ MockUwbAdaptation::create_uwb_client_callback(self.rsp_sender.clone());
+ let _ = uwb_client_callback.onHalEvent(event, status).await;
+ }
+
+ async fn send_client_message(&self, rsp_data: Vec<u8>) {
+ let uwb_client_callback =
+ MockUwbAdaptation::create_uwb_client_callback(self.rsp_sender.clone());
+ let _ = uwb_client_callback.onUciMessage(&rsp_data).await;
+ }
}
-}
-#[cfg(test)]
-#[async_trait]
-impl UwbAdaptation for MockUwbAdaptation {
- async fn finalize(&mut self, exit_status: bool) {
- let mut expected_calls = self.expected_calls.lock().unwrap();
- match expected_calls.pop_front() {
- Some(ExpectedCall::Finalize { expected_exit_status })
- if expected_exit_status == exit_status =>
- {
- return;
- }
- Some(call) => {
- expected_calls.push_front(call);
- }
- None => {}
+ impl Drop for MockUwbAdaptation {
+ fn drop(&mut self) {
+ assert!(self.expected_calls.lock().unwrap().is_empty());
}
- warn!("unpected finalize() called");
}
- async fn hal_open(&self) -> Result<()> {
- let expected_out = {
+ #[async_trait]
+ impl UwbAdaptation for MockUwbAdaptation {
+ async fn finalize(&mut self, exit_status: bool) {
let mut expected_calls = self.expected_calls.lock().unwrap();
match expected_calls.pop_front() {
- Some(ExpectedCall::HalOpen { out }) => Some(out),
+ Some(ExpectedCall::Finalize { expected_exit_status })
+ if expected_exit_status == exit_status =>
+ {
+ return;
+ }
Some(call) => {
expected_calls.push_front(call);
- None
}
- None => None,
- }
- };
-
- match expected_out {
- Some(out) => {
- let status = if out.is_ok() { UwbStatus::OK } else { UwbStatus::FAILED };
- self.send_client_event(UwbEvent::OPEN_CPLT, status).await;
- out
- }
- None => {
- warn!("unpected hal_open() called");
- Err(UwbErr::Undefined)
+ None => {}
}
+ warn!("unpected finalize() called");
}
- }
- async fn hal_close(&self) -> Result<()> {
- let expected_out = {
- let mut expected_calls = self.expected_calls.lock().unwrap();
- match expected_calls.pop_front() {
- Some(ExpectedCall::HalClose { out }) => Some(out),
- Some(call) => {
- expected_calls.push_front(call);
- None
+ async fn hal_open(&self) -> Result<()> {
+ let expected_out = {
+ let mut expected_calls = self.expected_calls.lock().unwrap();
+ match expected_calls.pop_front() {
+ Some(ExpectedCall::HalOpen { out }) => Some(out),
+ Some(call) => {
+ expected_calls.push_front(call);
+ None
+ }
+ None => None,
}
- None => None,
- }
- };
+ };
- match expected_out {
- Some(out) => {
- let status = if out.is_ok() { UwbStatus::OK } else { UwbStatus::FAILED };
- self.send_client_event(UwbEvent::CLOSE_CPLT, status).await;
- out
- }
- None => {
- warn!("unpected hal_close() called");
- Err(UwbErr::Undefined)
+ match expected_out {
+ Some(out) => {
+ let status = if out.is_ok() { UwbStatus::OK } else { UwbStatus::FAILED };
+ self.send_client_event(UwbEvent::OPEN_CPLT, status).await;
+ out
+ }
+ None => {
+ warn!("unpected hal_open() called");
+ Err(UwbErr::Undefined)
+ }
}
}
- }
- async fn core_initialization(&self) -> Result<()> {
- let expected_out = {
- let mut expected_calls = self.expected_calls.lock().unwrap();
- match expected_calls.pop_front() {
- Some(ExpectedCall::CoreInitialization { out }) => Some(out),
- Some(call) => {
- expected_calls.push_front(call);
- None
+ async fn hal_close(&self) -> Result<()> {
+ let expected_out = {
+ let mut expected_calls = self.expected_calls.lock().unwrap();
+ match expected_calls.pop_front() {
+ Some(ExpectedCall::HalClose { out }) => Some(out),
+ Some(call) => {
+ expected_calls.push_front(call);
+ None
+ }
+ None => None,
}
- None => None,
- }
- };
+ };
- match expected_out {
- Some(out) => {
- let status = if out.is_ok() { UwbStatus::OK } else { UwbStatus::FAILED };
- self.send_client_event(UwbEvent::POST_INIT_CPLT, status).await;
- out
- }
- None => {
- warn!("unpected core_initialization() called");
- Err(UwbErr::Undefined)
+ match expected_out {
+ Some(out) => {
+ let status = if out.is_ok() { UwbStatus::OK } else { UwbStatus::FAILED };
+ self.send_client_event(UwbEvent::CLOSE_CPLT, status).await;
+ out
+ }
+ None => {
+ warn!("unpected hal_close() called");
+ Err(UwbErr::Undefined)
+ }
}
}
- }
- async fn session_initialization(&self, session_id: i32) -> Result<()> {
- let expected_out = {
- let mut expected_calls = self.expected_calls.lock().unwrap();
- match expected_calls.pop_front() {
- Some(ExpectedCall::SessionInitialization { expected_session_id, out })
- if expected_session_id == session_id =>
- {
- Some(out)
- }
- Some(call) => {
- expected_calls.push_front(call);
- None
+ async fn core_initialization(&self) -> Result<()> {
+ let expected_out = {
+ let mut expected_calls = self.expected_calls.lock().unwrap();
+ match expected_calls.pop_front() {
+ Some(ExpectedCall::CoreInitialization { out }) => Some(out),
+ Some(call) => {
+ expected_calls.push_front(call);
+ None
+ }
+ None => None,
}
- None => None,
- }
- };
+ };
- match expected_out {
- Some(out) => out,
- None => {
- warn!("unpected session_initialization() called");
- Err(UwbErr::Undefined)
+ match expected_out {
+ Some(out) => {
+ let status = if out.is_ok() { UwbStatus::OK } else { UwbStatus::FAILED };
+ self.send_client_event(UwbEvent::POST_INIT_CPLT, status).await;
+ out
+ }
+ None => {
+ warn!("unpected core_initialization() called");
+ Err(UwbErr::Undefined)
+ }
}
}
- }
- async fn send_uci_message(&self, data: &[u8]) -> Result<()> {
- let expected_out = {
- let mut expected_calls = self.expected_calls.lock().unwrap();
- match expected_calls.pop_front() {
- Some(ExpectedCall::SendUciMessage { expected_data, rsp_data, notf_data, out })
- if expected_data == data =>
- {
- Some((rsp_data, notf_data, out))
+ async fn session_initialization(&self, session_id: i32) -> Result<()> {
+ let expected_out = {
+ let mut expected_calls = self.expected_calls.lock().unwrap();
+ match expected_calls.pop_front() {
+ Some(ExpectedCall::SessionInitialization { expected_session_id, out })
+ if expected_session_id == session_id =>
+ {
+ Some(out)
+ }
+ Some(call) => {
+ expected_calls.push_front(call);
+ None
+ }
+ None => None,
}
- Some(call) => {
- expected_calls.push_front(call);
- None
+ };
+
+ match expected_out {
+ Some(out) => out,
+ None => {
+ warn!("unpected session_initialization() called");
+ Err(UwbErr::Undefined)
}
- None => None,
}
- };
+ }
- match expected_out {
- Some((rsp_data, notf_data, out)) => {
- if let Some(rsp) = rsp_data {
- self.send_client_message(rsp).await;
+ async fn send_uci_message(&self, cmd: UciCommandPacket) -> Result<()> {
+ let expected_out = {
+ let mut expected_calls = self.expected_calls.lock().unwrap();
+ match expected_calls.pop_front() {
+ Some(ExpectedCall::SendUciMessage {
+ expected_data,
+ rsp_data,
+ notf_data,
+ out,
+ }) if expected_data == cmd.to_vec() => Some((rsp_data, notf_data, out)),
+ Some(call) => {
+ expected_calls.push_front(call);
+ None
+ }
+ None => None,
}
- if let Some(notf) = notf_data {
- self.send_client_message(notf).await;
+ };
+
+ match expected_out {
+ Some((rsp_data, notf_data, out)) => {
+ if let Some(rsp) = rsp_data {
+ self.send_client_message(rsp).await;
+ }
+ if let Some(notf) = notf_data {
+ self.send_client_message(notf).await;
+ }
+ out
+ }
+ None => {
+ warn!("unpected send_uci_message() called");
+ Err(UwbErr::Undefined)
}
- out
- }
- None => {
- warn!("unpected send_uci_message() called");
- Err(UwbErr::Undefined)
}
}
}
-}
-#[cfg(test)]
-mod tests {
- #![allow(non_snake_case)]
- use super::*;
+ fn create_uwb_client_callback(
+ rsp_sender: mpsc::UnboundedSender<HalCallback>,
+ ) -> UwbClientCallback {
+ // Add tests for the mock logger.
+ UwbClientCallback::new(rsp_sender, Arc::new(MockUciLogger::new()))
+ }
#[tokio::test]
async fn test_onHalEvent() {
let uwb_event_test = UwbEvent(0);
let uwb_status_test = UwbStatus(1);
let (rsp_sender, _) = mpsc::unbounded_channel::<HalCallback>();
- let uwb_client_callback_test = UwbClientCallback::new(rsp_sender);
+ let uwb_client_callback_test = create_uwb_client_callback(rsp_sender);
let result = uwb_client_callback_test.onHalEvent(uwb_event_test, uwb_status_test).await;
assert_eq!(result, Ok(()));
}
@@ -413,7 +437,7 @@ mod tests {
0x0a,
];
let (rsp_sender, mut rsp_receiver) = mpsc::unbounded_channel::<HalCallback>();
- let uwb_client_callback_test = UwbClientCallback::new(rsp_sender);
+ let uwb_client_callback_test = create_uwb_client_callback(rsp_sender);
let result = uwb_client_callback_test.onUciMessage(&data).await;
assert_eq!(result, Ok(()));
let response = rsp_receiver.recv().await;
@@ -430,7 +454,7 @@ mod tests {
0x0a,
];
let (rsp_sender, mut rsp_receiver) = mpsc::unbounded_channel::<HalCallback>();
- let uwb_client_callback_test = UwbClientCallback::new(rsp_sender);
+ let uwb_client_callback_test = create_uwb_client_callback(rsp_sender);
let result = uwb_client_callback_test.onUciMessage(&data).await;
assert_eq!(result, Ok(()));
let response = rsp_receiver.try_recv();
diff --git a/src/rust/uci/mod.rs b/src/rust/uci/mod.rs
index 6c0cad1..44acf11 100644
--- a/src/rust/uci/mod.rs
+++ b/src/rust/uci/mod.rs
@@ -16,6 +16,7 @@
pub mod uci_hmsgs;
pub mod uci_hrcv;
+pub mod uci_logger;
use crate::adaptation::{UwbAdaptation, UwbAdaptationImpl};
use crate::error::UwbErr;
@@ -33,9 +34,9 @@ use tokio::sync::{mpsc, oneshot, Notify};
use tokio::{select, task};
use uwb_uci_packets::{
AndroidGetPowerStatsCmdBuilder, GetCapsInfoCmdBuilder, GetDeviceInfoCmdBuilder,
- GetDeviceInfoRspPacket, Packet, RangeStartCmdBuilder, RangeStopCmdBuilder,
- SessionDeinitCmdBuilder, SessionGetAppConfigCmdBuilder, SessionGetCountCmdBuilder,
- SessionGetStateCmdBuilder, SessionState, SessionStatusNtfPacket, StatusCode, UciCommandPacket,
+ GetDeviceInfoRspPacket, RangeStartCmdBuilder, RangeStopCmdBuilder, SessionDeinitCmdBuilder,
+ SessionGetAppConfigCmdBuilder, SessionGetCountCmdBuilder, SessionGetStateCmdBuilder,
+ SessionState, SessionStatusNtfPacket, StatusCode, UciCommandPacket,
};
pub type Result<T> = std::result::Result<T, UwbErr>;
@@ -150,11 +151,11 @@ impl Retryer {
self.failed.notify_one()
}
- fn send_with_retry(self, adaptation: Arc<SyncUwbAdaptation>, bytes: Vec<u8>) {
+ fn send_with_retry(self, adaptation: Arc<SyncUwbAdaptation>, cmd: UciCommandPacket) {
tokio::task::spawn(async move {
let mut received_response = false;
for retry in 0..MAX_RETRIES {
- adaptation.send_uci_message(&bytes).await.unwrap_or_else(|e| {
+ adaptation.send_uci_message(cmd.clone()).await.unwrap_or_else(|e| {
error!("Sending UCI message failed: {:?}", e);
});
select! {
@@ -202,14 +203,14 @@ async fn drive<T: EventManager + Send + Sync>(
cmd_receiver: mpsc::UnboundedReceiver<(JNICommand, Option<UciResponseHandle>)>,
rsp_receiver: mpsc::UnboundedReceiver<HalCallback>,
) -> Result<()> {
- Driver::new(Arc::new(adaptation), event_manager, cmd_receiver, rsp_receiver).drive().await
+ Driver::new(Arc::new(adaptation), event_manager, cmd_receiver, rsp_receiver).await.drive().await
}
const MAX_RETRIES: usize = 5;
const RETRY_DELAY_MS: u64 = 800;
impl<T: EventManager> Driver<T> {
- fn new(
+ async fn new(
adaptation: Arc<SyncUwbAdaptation>,
event_manager: T,
cmd_receiver: mpsc::UnboundedReceiver<(JNICommand, Option<UciResponseHandle>)>,
@@ -314,7 +315,7 @@ impl<T: EventManager> Driver<T> {
let retryer = Retryer::new();
self.response_channel = Some((tx, retryer.clone()));
- retryer.send_with_retry(self.adaptation.clone(), command.to_vec());
+ retryer.send_with_retry(self.adaptation.clone(), command);
self.set_state(UwbState::W4UciResp);
Ok(())
}
@@ -533,9 +534,9 @@ impl Dispatcher {
#[cfg(test)]
mod tests {
use super::*;
- use crate::adaptation::MockUwbAdaptation;
+ use crate::adaptation::tests::MockUwbAdaptation;
use crate::event_manager::MockEventManager;
- use uwb_uci_packets::{DeviceState, DeviceStatusNtfBuilder, GetDeviceInfoRspBuilder};
+ use uwb_uci_packets::{DeviceState, DeviceStatusNtfBuilder, GetDeviceInfoRspBuilder, Packet};
fn setup_dispatcher(
config_fn: fn(&mut Box<MockUwbAdaptation>, &mut MockEventManager),
diff --git a/src/rust/uci/uci_hrcv.rs b/src/rust/uci/uci_hrcv.rs
index 8a8dae6..bf6562b 100644
--- a/src/rust/uci/uci_hrcv.rs
+++ b/src/rust/uci/uci_hrcv.rs
@@ -23,7 +23,7 @@ pub enum UciMessage {
Notification(UciNotification),
}
-#[derive(Debug)]
+#[derive(Debug, Clone)]
pub enum UciResponse {
GetDeviceInfoRsp(GetDeviceInfoRspPacket),
GetCapsInfoRsp(GetCapsInfoRspPacket),
@@ -46,7 +46,7 @@ pub enum UciResponse {
DisableRsp,
}
-#[derive(Debug)]
+#[derive(Debug, Clone)]
pub enum UciNotification {
GenericError(GenericErrorPacket),
DeviceStatusNtf(DeviceStatusNtfPacket),
diff --git a/src/rust/uci/uci_logger.rs b/src/rust/uci/uci_logger.rs
new file mode 100644
index 0000000..ad7ae0b
--- /dev/null
+++ b/src/rust/uci/uci_logger.rs
@@ -0,0 +1,292 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+use crate::uci::UwbErr;
+use async_trait::async_trait;
+use bytes::{BufMut, BytesMut};
+use log::{error, info};
+use std::time::SystemTime;
+use tokio::fs::{create_dir, rename, File, OpenOptions};
+use tokio::io::AsyncWriteExt;
+use tokio::sync::Mutex;
+use uwb_uci_packets::{
+ AppConfigTlv, AppConfigTlvType, MessageType, Packet, SessionCommandChild,
+ SessionGetAppConfigRspBuilder, SessionResponseChild, SessionSetAppConfigCmdBuilder,
+ UciCommandChild, UciCommandPacket, UciNotificationPacket, UciPacketPacket, UciResponseChild,
+ UciResponsePacket,
+};
+
+// micros since 0000-01-01
+const UCI_EPOCH_DELTA: u64 = 0x00dcddb30f2f8000;
+const MAX_FILE_SIZE: usize = 4096;
+const PKT_LOG_HEADER_SIZE: usize = 25;
+const VENDOR_ID: u64 = AppConfigTlvType::VendorId as u64;
+const STATIC_STS_IV: u64 = AppConfigTlvType::StaticStsIv as u64;
+const LOG_DIR: &str = "/data/misc/apexdata/com.android.uwb/log";
+const FILE_NAME: &str = "uwb_uci.log";
+
+#[derive(Clone, PartialEq, Eq)]
+pub enum UciLogMode {
+ Disabled,
+ Filtered,
+}
+
+#[derive(Clone)]
+enum Type {
+ Command = 1,
+ Response,
+ Notification,
+}
+
+#[derive(Clone)]
+struct UciLogConfig {
+ path: String,
+ max_file_size: usize,
+ mode: UciLogMode,
+}
+
+impl UciLogConfig {
+ pub fn new(mode: UciLogMode) -> Self {
+ Self { path: format!("{}/{}", LOG_DIR, FILE_NAME), max_file_size: MAX_FILE_SIZE, mode }
+ }
+}
+
+#[async_trait]
+pub trait UciLogger {
+ async fn log_uci_command(&self, cmd: UciCommandPacket);
+ async fn log_uci_response(&self, rsp: UciResponsePacket);
+ async fn log_uci_notification(&self, ntf: UciNotificationPacket);
+ async fn close_file(&self);
+}
+
+struct BufferedFile {
+ file: Option<File>,
+ size_count: usize,
+ buffer: BytesMut,
+}
+
+pub struct UciLoggerImpl {
+ config: UciLogConfig,
+ buf_file: Mutex<BufferedFile>,
+}
+
+impl UciLoggerImpl {
+ pub async fn new(mode: UciLogMode) -> Self {
+ let config = UciLogConfig::new(mode);
+ let file = match OpenOptions::new().append(true).open(&config.path).await.ok() {
+ Some(f) => Some(f),
+ None => {
+ if create_dir(LOG_DIR).await.is_err() {
+ error!("Failed to create dir");
+ }
+ let new_file = match File::create(&config.path).await {
+ Ok(mut f) => {
+ if f.write_all(b"ucilogging").await.is_err() {
+ error!("failed to write");
+ }
+ if f.flush().await.is_err() {
+ error!("Failed to flush");
+ }
+ Some(f)
+ }
+ Err(e) => {
+ error!("Failed to create file {:?}", e);
+ None
+ }
+ };
+ new_file
+ }
+ };
+ let buf_file = BufferedFile {
+ size_count: match file {
+ Some(ref f) => f.metadata().await.unwrap().len().try_into().unwrap(),
+ None => 0,
+ },
+ file,
+ buffer: BytesMut::new(),
+ };
+ let ret = Self { config, buf_file: Mutex::new(buf_file) };
+ info!("UCI logger created");
+ ret
+ }
+
+ async fn log_uci_packet(&self, packet: UciPacketPacket) {
+ let mt = packet.get_message_type();
+ let bytes = packet.to_vec();
+ let mt_byte = match mt {
+ MessageType::Command => Type::Command as u8,
+ MessageType::Response => Type::Response as u8,
+ MessageType::Notification => Type::Notification as u8,
+ };
+ let flags = match mt {
+ MessageType::Command => 0b10, // down direction
+ MessageType::Response => 0b01, // up direction
+ MessageType::Notification => 0b01, // up direction
+ };
+ let timestamp = u64::try_from(
+ SystemTime::now().duration_since(SystemTime::UNIX_EPOCH).unwrap().as_micros(),
+ )
+ .unwrap()
+ + UCI_EPOCH_DELTA;
+
+ let length = u32::try_from(bytes.len()).unwrap() + 1;
+
+ // Check whether exceeded the size limit
+ let mut buf_file = self.buf_file.lock().await;
+ if buf_file.size_count + bytes.len() + PKT_LOG_HEADER_SIZE > self.config.max_file_size {
+ match self.open_next_file().await {
+ Ok(()) => info!("New file created"),
+ Err(e) => error!("Open next file failed: {:?}", e),
+ }
+ }
+ buf_file.buffer.put_u32(length); // original length
+ buf_file.buffer.put_u32(length); // captured length
+ buf_file.buffer.put_u32(flags); // flags
+ buf_file.buffer.put_u32(0); // dropped packets
+ buf_file.buffer.put_u64(timestamp); // timestamp
+ buf_file.buffer.put_u8(mt_byte); // type
+ buf_file.buffer.put_slice(&bytes); // full packet.
+ buf_file.size_count += bytes.len() + PKT_LOG_HEADER_SIZE;
+ }
+
+ async fn open_next_file(&self) -> Result<(), UwbErr> {
+ info!("Open next file");
+ self.close_file().await;
+ if create_dir(LOG_DIR).await.is_err() {
+ error!("Failed to create dir");
+ }
+ if rename(&self.config.path, self.config.path.clone() + ".last").await.is_err() {
+ error!("Failed to rename the file");
+ }
+ let mut file = File::create(&self.config.path).await?;
+ file.write_all(b"ucilogging").await?;
+ if file.flush().await.is_err() {
+ error!("Failed to flush");
+ }
+ self.buf_file.lock().await.file = Some(file);
+ Ok(())
+ }
+}
+
+#[async_trait]
+impl UciLogger for UciLoggerImpl {
+ async fn log_uci_command(&self, cmd: UciCommandPacket) {
+ if let UciLogMode::Disabled = self.config.mode {
+ return;
+ }
+ // Only filter SET_APP_CONFIG_CMD
+ let filtered_cmd: UciCommandPacket = 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();
+ let mut filtered_tlvs = Vec::new();
+ for tlv in tlvs {
+ if VENDOR_ID == tlv.cfg_id as u64 || STATIC_STS_IV == tlv.cfg_id as u64 {
+ filtered_tlvs
+ .push(AppConfigTlv { cfg_id: tlv.cfg_id, v: vec![0; tlv.v.len()] });
+ } else {
+ filtered_tlvs.push(tlv.clone());
+ }
+ }
+ SessionSetAppConfigCmdBuilder { session_id, tlvs: filtered_tlvs }.build().into()
+ }
+ _ => session_cmd.into(),
+ },
+ _ => cmd,
+ };
+ self.log_uci_packet(filtered_cmd.into()).await;
+ }
+
+ async fn log_uci_response(&self, rsp: UciResponsePacket) {
+ if let UciLogMode::Disabled = self.config.mode {
+ return;
+ }
+ // Only filter GET_APP_CONFIG_RSP
+ let filtered_rsp: UciResponsePacket = match rsp.specialize() {
+ UciResponseChild::SessionResponse(session_rsp) => match session_rsp.specialize() {
+ SessionResponseChild::SessionGetAppConfigRsp(rsp) => {
+ let status = rsp.get_status();
+ let tlvs = rsp.get_tlvs();
+ let mut filtered_tlvs = Vec::new();
+ for tlv in tlvs {
+ if VENDOR_ID == tlv.cfg_id as u64 || STATIC_STS_IV == tlv.cfg_id as u64 {
+ filtered_tlvs
+ .push(AppConfigTlv { cfg_id: tlv.cfg_id, v: vec![0; tlv.v.len()] });
+ } else {
+ filtered_tlvs.push(tlv.clone());
+ }
+ }
+ SessionGetAppConfigRspBuilder { status, tlvs: filtered_tlvs }.build().into()
+ }
+ _ => session_rsp.into(),
+ },
+ _ => rsp,
+ };
+ self.log_uci_packet(filtered_rsp.into()).await;
+ }
+
+ async fn log_uci_notification(&self, ntf: UciNotificationPacket) {
+ if self.config.mode == UciLogMode::Disabled {
+ return;
+ }
+ // No notifications to be filtered.
+ self.log_uci_packet(ntf.into()).await;
+ }
+
+ async fn close_file(&self) {
+ info!("UCI log file closing");
+ let mut buf_file = self.buf_file.lock().await;
+ let buffer = buf_file.buffer.clone();
+ if let Some(file) = &mut buf_file.file {
+ if file.write_all(&buffer).await.is_err() {
+ error!("Failed to write");
+ }
+ if file.flush().await.is_err() {
+ error!("Failed to flush");
+ }
+ buf_file.file = None;
+ buf_file.buffer.clear();
+ }
+ buf_file.size_count = 0;
+ }
+}
+
+#[cfg(test)]
+pub struct MockUciLogger {}
+
+#[cfg(test)]
+impl MockUciLogger {
+ pub fn new() -> Self {
+ MockUciLogger {}
+ }
+}
+
+#[cfg(test)]
+impl Default for MockUciLogger {
+ fn default() -> Self {
+ Self::new()
+ }
+}
+
+#[cfg(test)]
+#[async_trait]
+impl UciLogger for MockUciLogger {
+ async fn log_uci_command(&self, _cmd: UciCommandPacket) {}
+ async fn log_uci_response(&self, _rsp: UciResponsePacket) {}
+ async fn log_uci_notification(&self, _ntf: UciNotificationPacket) {}
+ async fn close_file(&self) {}
+}