Revert "Revert "uwb(hal): Implement UCI over serial in the defau..."
Revert submission 2528605-revert-2215484-pica_cf-BZDQSZLKEP
Reason for revert: revert^2
Reverted changes: /q/submissionid:2528605-revert-2215484-pica_cf-BZDQSZLKEP
Change-Id: I0c64b449c5da236a7cd63f88a605d48b9c471c67
diff --git a/uwb/aidl/default/src/service.rs b/uwb/aidl/default/src/service.rs
new file mode 100644
index 0000000..7d5c073
--- /dev/null
+++ b/uwb/aidl/default/src/service.rs
@@ -0,0 +1,47 @@
+use android_hardware_uwb::aidl::android::hardware::uwb::IUwb::{self, IUwb as _};
+use android_hardware_uwb::binder;
+
+use tokio::runtime::Runtime;
+
+use std::env;
+use std::panic;
+
+use log::Level;
+
+mod uwb;
+mod uwb_chip;
+
+fn main() -> anyhow::Result<()> {
+ logger::init(
+ logger::Config::default()
+ .with_min_level(Level::Debug)
+ .with_tag_on_device("android.hardware.uwb"),
+ );
+
+ // Redirect panic messages to logcat.
+ panic::set_hook(Box::new(|panic_info| {
+ log::error!("{}", panic_info);
+ }));
+
+ log::info!("UWB HAL starting up");
+
+ // Create the tokio runtime
+ let rt = Runtime::new()?;
+
+ let chips = env::args()
+ .skip(1) // Skip binary name
+ .enumerate()
+ .map(|(i, arg)| uwb_chip::UwbChip::new(i.to_string(), arg));
+
+ binder::add_service(
+ &format!("{}/default", IUwb::BpUwb::get_descriptor()),
+ IUwb::BnUwb::new_binder(
+ uwb::Uwb::from_chips(chips, rt.handle().clone()),
+ binder::BinderFeatures::default(),
+ )
+ .as_binder(),
+ )?;
+
+ binder::ProcessState::join_thread_pool();
+ Ok(())
+}
diff --git a/uwb/aidl/default/src/uwb.rs b/uwb/aidl/default/src/uwb.rs
new file mode 100644
index 0000000..428f08f
--- /dev/null
+++ b/uwb/aidl/default/src/uwb.rs
@@ -0,0 +1,53 @@
+use android_hardware_uwb::aidl::android::hardware::uwb::{IUwb, IUwbChip};
+use android_hardware_uwb::binder;
+use binder::{Result, Strong};
+use binder_tokio::TokioRuntime;
+use tokio::runtime::Handle as TokioHandle;
+
+use crate::uwb_chip;
+
+pub struct Uwb {
+ chips: Vec<Strong<dyn IUwbChip::IUwbChip>>,
+}
+
+impl Uwb {
+ pub fn from_chips(
+ chips: impl IntoIterator<Item = uwb_chip::UwbChip>,
+ handle: TokioHandle,
+ ) -> Self {
+ Self {
+ chips: chips
+ .into_iter()
+ .map(|chip| {
+ IUwbChip::BnUwbChip::new_async_binder(
+ chip,
+ TokioRuntime(handle.clone()),
+ binder::BinderFeatures::default(),
+ )
+ })
+ .collect(),
+ }
+ }
+}
+
+impl binder::Interface for Uwb {}
+
+impl IUwb::IUwb for Uwb {
+ fn getChips(&self) -> Result<Vec<String>> {
+ log::debug!("getChips");
+ self.chips.iter().map(|chip| chip.getName()).collect()
+ }
+
+ fn getChip(&self, name: &str) -> Result<Strong<dyn IUwbChip::IUwbChip>> {
+ log::debug!("getChip {}", name);
+ let chip = self
+ .chips
+ .iter()
+ .find(|chip| chip.getName().as_deref() == Ok(name));
+ if let Some(chip) = chip {
+ Ok(chip.clone())
+ } else {
+ Err(binder::ExceptionCode::ILLEGAL_ARGUMENT.into())
+ }
+ }
+}
diff --git a/uwb/aidl/default/src/uwb_chip.rs b/uwb/aidl/default/src/uwb_chip.rs
new file mode 100644
index 0000000..7c2c300
--- /dev/null
+++ b/uwb/aidl/default/src/uwb_chip.rs
@@ -0,0 +1,168 @@
+use android_hardware_uwb::aidl::android::hardware::uwb::{
+ IUwbChip::IUwbChipAsyncServer, IUwbClientCallback::IUwbClientCallback, UwbEvent::UwbEvent,
+ UwbStatus::UwbStatus,
+};
+use android_hardware_uwb::binder;
+use async_trait::async_trait;
+use binder::{Result, Strong};
+
+use tokio::fs::File;
+use tokio::io::{AsyncReadExt, AsyncWriteExt};
+use tokio::sync::Mutex;
+
+use std::os::fd::AsRawFd;
+
+use std::io;
+
+use nix::sys::termios;
+
+enum State {
+ Closed,
+ Opened {
+ callbacks: Strong<dyn IUwbClientCallback>,
+ #[allow(dead_code)]
+ tasks: tokio::task::JoinSet<()>,
+ write: File,
+ },
+}
+
+pub struct UwbChip {
+ name: String,
+ path: String,
+ state: Mutex<State>,
+}
+
+impl UwbChip {
+ pub fn new(name: String, path: String) -> Self {
+ Self {
+ name,
+ path,
+ state: Mutex::new(State::Closed),
+ }
+ }
+}
+
+pub fn makeraw(file: File) -> io::Result<File> {
+ let fd = file.as_raw_fd();
+
+ let mut attrs = termios::tcgetattr(fd)?;
+
+ termios::cfmakeraw(&mut attrs);
+
+ termios::tcsetattr(fd, termios::SetArg::TCSANOW, &attrs)?;
+
+ Ok(file)
+}
+
+impl binder::Interface for UwbChip {}
+
+#[async_trait]
+impl IUwbChipAsyncServer for UwbChip {
+ async fn getName(&self) -> Result<String> {
+ Ok(self.name.clone())
+ }
+
+ async fn open(&self, callbacks: &Strong<dyn IUwbClientCallback>) -> Result<()> {
+ log::debug!("open: {:?}", &self.path);
+
+ let serial = File::open(&self.path)
+ .await
+ .and_then(makeraw)
+ .map_err(|_| binder::StatusCode::UNKNOWN_ERROR)?;
+
+ let mut read = serial
+ .try_clone()
+ .await
+ .map_err(|_| binder::StatusCode::UNKNOWN_ERROR)?;
+ let write = serial;
+
+ let mut state = self.state.lock().await;
+
+ if let State::Closed = *state {
+ let client_callbacks = callbacks.clone();
+
+ let mut tasks = tokio::task::JoinSet::new();
+
+ tasks.spawn(async move {
+ loop {
+ const UWB_HEADER_SIZE: usize = 4;
+
+ let mut buffer = vec![0; UWB_HEADER_SIZE];
+ read.read_exact(&mut buffer[0..UWB_HEADER_SIZE])
+ .await
+ .unwrap();
+
+ let length = buffer[3] as usize + UWB_HEADER_SIZE;
+
+ buffer.resize(length, 0);
+ read.read_exact(&mut buffer[UWB_HEADER_SIZE..length])
+ .await
+ .unwrap();
+
+ client_callbacks.onUciMessage(&buffer[..]).unwrap();
+ }
+ });
+
+ callbacks.onHalEvent(UwbEvent::OPEN_CPLT, UwbStatus::OK)?;
+
+ *state = State::Opened {
+ callbacks: callbacks.clone(),
+ tasks,
+ write,
+ };
+
+ Ok(())
+ } else {
+ Err(binder::ExceptionCode::ILLEGAL_STATE.into())
+ }
+ }
+
+ async fn close(&self) -> Result<()> {
+ log::debug!("close");
+
+ let mut state = self.state.lock().await;
+
+ if let State::Opened { ref callbacks, .. } = *state {
+ callbacks.onHalEvent(UwbEvent::CLOSE_CPLT, UwbStatus::OK)?;
+ *state = State::Closed;
+ Ok(())
+ } else {
+ Err(binder::ExceptionCode::ILLEGAL_STATE.into())
+ }
+ }
+
+ async fn coreInit(&self) -> Result<()> {
+ log::debug!("coreInit");
+
+ if let State::Opened { ref callbacks, .. } = *self.state.lock().await {
+ callbacks.onHalEvent(UwbEvent::POST_INIT_CPLT, UwbStatus::OK)?;
+ Ok(())
+ } else {
+ Err(binder::ExceptionCode::ILLEGAL_STATE.into())
+ }
+ }
+
+ async fn sessionInit(&self, _id: i32) -> Result<()> {
+ log::debug!("sessionInit");
+
+ Ok(())
+ }
+
+ async fn getSupportedAndroidUciVersion(&self) -> Result<i32> {
+ Ok(1)
+ }
+
+ async fn sendUciMessage(&self, data: &[u8]) -> Result<i32> {
+ log::debug!("sendUciMessage");
+
+ if let State::Opened { write, .. } = &mut *self.state.lock().await {
+ write
+ .write(data)
+ .await
+ .map(|written| written as i32)
+ .map_err(|_| binder::StatusCode::UNKNOWN_ERROR.into())
+ } else {
+ Err(binder::ExceptionCode::ILLEGAL_STATE.into())
+ }
+ }
+}