diff --git a/uwb/aidl/default/Android.bp b/uwb/aidl/default/Android.bp index f9b79de729..8af1678d1a 100644 --- a/uwb/aidl/default/Android.bp +++ b/uwb/aidl/default/Android.bp @@ -24,6 +24,8 @@ rust_binary { "libtokio_util", "libnix", "libanyhow", + "libpdl_runtime", + "libuwb_uci_packets", ], proc_macros: [ "libasync_trait", diff --git a/uwb/aidl/default/src/uwb_chip.rs b/uwb/aidl/default/src/uwb_chip.rs index efb2454323..d749147d15 100644 --- a/uwb/aidl/default/src/uwb_chip.rs +++ b/uwb/aidl/default/src/uwb_chip.rs @@ -16,6 +16,9 @@ use std::fs::{File, OpenOptions}; use std::io::{self, Read, Write}; use std::os::unix::fs::OpenOptionsExt; +use pdl_runtime::Packet; +use uwb_uci_packets::{DeviceResetCmdBuilder, ResetConfig, UciControlPacket, UciControlPacketHal}; + enum State { Closed, Opened { @@ -46,11 +49,23 @@ impl UwbChip { impl State { /// Terminate the reader task. async fn close(&mut self) -> Result<()> { - if let State::Opened { ref mut token, ref callbacks, ref mut death_recipient, ref mut handle, .. } = *self { + if let State::Opened { + ref mut token, + ref callbacks, + ref mut death_recipient, + ref mut handle, + ref mut serial, + } = *self + { log::info!("waiting for task cancellation"); callbacks.as_binder().unlink_to_death(death_recipient)?; token.cancel(); handle.await.unwrap(); + consume_device_reset_rsp_and_ntf( + &mut serial + .try_clone() + .map_err(|_| binder::StatusCode::UNKNOWN_ERROR)?, + ); log::info!("task successfully cancelled"); callbacks.onHalEvent(UwbEvent::CLOSE_CPLT, UwbStatus::OK)?; *self = State::Closed; @@ -59,6 +74,20 @@ impl State { } } +fn consume_device_reset_rsp_and_ntf(reader: &mut File) { + // Poll the DeviceResetRsp and DeviceStatusNtf before hal is closed to prevent + // the host from getting response and notifications from a 'powered down' UWBS. + // Do nothing when these packets are received. + const DEVICE_RESET_RSP: [u8; 5] = [64, 0, 0, 1, 0]; + const DEVICE_STATUS_NTF: [u8; 5] = [96, 1, 0, 1, 1]; + let mut buffer = vec![0; DEVICE_RESET_RSP.len() + DEVICE_STATUS_NTF.len()]; + read_exact(reader, &mut buffer).unwrap(); + + // Make sure received packets are the expected ones. + assert_eq!(&buffer[0..DEVICE_RESET_RSP.len()], &DEVICE_RESET_RSP); + assert_eq!(&buffer[DEVICE_RESET_RSP.len()..], &DEVICE_STATUS_NTF); +} + pub fn makeraw(file: File) -> io::Result { // Configure the file descriptor as raw fd. use nix::sys::termios::*; @@ -209,7 +238,21 @@ impl IUwbChipAsyncServer for UwbChip { let mut state = self.state.lock().await; - if matches!(*state, State::Opened { .. }) { + if let State::Opened { ref mut serial, .. } = *state { + let packet: UciControlPacket = DeviceResetCmdBuilder { + reset_config: ResetConfig::UwbsReset, + } + .build() + .into(); + // DeviceResetCmd need to be send to reset the device to stop all running + // activities on UWBS. + let packet_vec: Vec = packet.into(); + for hal_packet in packet_vec.into_iter() { + serial + .write(&hal_packet.to_vec()) + .map(|written| written as i32) + .map_err(|_| binder::StatusCode::UNKNOWN_ERROR)?; + } state.close().await } else { Err(binder::ExceptionCode::ILLEGAL_STATE.into())