1 use android_hardware_uwb::aidl::android::hardware::uwb::{
2 IUwbChip::IUwbChipAsyncServer, IUwbClientCallback::IUwbClientCallback, UwbEvent::UwbEvent,
3 UwbStatus::UwbStatus,
4 };
5 use android_hardware_uwb::binder;
6 use async_trait::async_trait;
7 use binder::{DeathRecipient, IBinder, Result, Strong};
8
9 use std::sync::Arc;
10 use tokio::fs;
11 use tokio::io::{AsyncReadExt, AsyncWriteExt};
12 use tokio::sync::Mutex;
13
14 enum ClientState {
15 Closed,
16 Opened {
17 callbacks: Strong<dyn IUwbClientCallback>,
18 _death_recipient: DeathRecipient,
19 },
20 }
21
22 struct ServiceState {
23 client_state: ClientState,
24 writer: fs::File,
25 }
26
27 pub struct UwbChip {
28 name: String,
29 _handle: tokio::task::JoinHandle<()>,
30 service_state: Arc<Mutex<ServiceState>>,
31 }
32
33 /// Configure a file descriptor as raw fd.
makeraw(file: fs::File) -> std::io::Result<fs::File>34 pub fn makeraw(file: fs::File) -> std::io::Result<fs::File> {
35 use nix::sys::termios::*;
36 let mut attrs = tcgetattr(&file)?;
37 cfmakeraw(&mut attrs);
38 tcsetattr(&file, SetArg::TCSANOW, &attrs)?;
39 Ok(file)
40 }
41
42 impl UwbChip {
new(name: String, path: String) -> Self43 pub async fn new(name: String, path: String) -> Self {
44 // Open the serial file and configure it as raw file
45 // descriptor.
46 let mut reader = fs::OpenOptions::new()
47 .read(true)
48 .write(true)
49 .create(false)
50 .open(&path)
51 .await
52 .and_then(makeraw)
53 .expect("failed to open the serial device");
54 let writer = reader
55 .try_clone()
56 .await
57 .expect("failed to clone serial for writing");
58
59 // Create the chip
60 let service_state = Arc::new(Mutex::new(ServiceState {
61 writer,
62 client_state: ClientState::Closed,
63 }));
64
65 // Spawn the task that will run the polling loop.
66 let handle = {
67 let service_state = service_state.clone();
68
69 tokio::task::spawn(async move {
70 log::info!("UCI reader task started");
71
72 const MESSAGE_TYPE_MASK: u8 = 0b11100000;
73 const DATA_MESSAGE_TYPE: u8 = 0b000;
74 const UCI_HEADER_SIZE: usize = 4;
75 const UCI_BUFFER_SIZE: usize = 1024;
76
77 let mut buffer = [0; UCI_BUFFER_SIZE];
78
79 loop {
80 reader
81 .read_exact(&mut buffer[0..UCI_HEADER_SIZE])
82 .await
83 .expect("failed to read uci header bytes");
84 let common_header = buffer[0];
85 let mt = (common_header & MESSAGE_TYPE_MASK) >> 5;
86 let payload_length = if mt == DATA_MESSAGE_TYPE {
87 u16::from_le_bytes([buffer[2], buffer[3]]) as usize
88 } else {
89 buffer[3] as usize
90 };
91
92 let total_packet_length = payload_length + UCI_HEADER_SIZE;
93 reader
94 .read_exact(&mut buffer[UCI_HEADER_SIZE..total_packet_length])
95 .await
96 .expect("failed to read uci payload bytes");
97
98 log::debug!(" <-- {:?}", &buffer[0..total_packet_length]);
99
100 let service_state = service_state.lock().await;
101 if let ClientState::Opened { ref callbacks, .. } = service_state.client_state {
102 callbacks
103 .onUciMessage(&buffer[0..total_packet_length])
104 .unwrap();
105 }
106 }
107 })
108 };
109
110 Self {
111 name,
112 _handle: handle,
113 service_state,
114 }
115 }
116 }
117 impl binder::Interface for UwbChip {}
118
119 #[async_trait]
120 impl IUwbChipAsyncServer for UwbChip {
getName(&self) -> Result<String>121 async fn getName(&self) -> Result<String> {
122 Ok(self.name.clone())
123 }
124
open(&self, callbacks: &Strong<dyn IUwbClientCallback>) -> Result<()>125 async fn open(&self, callbacks: &Strong<dyn IUwbClientCallback>) -> Result<()> {
126 log::debug!("open");
127
128 let mut service_state = self.service_state.lock().await;
129
130 if matches!(service_state.client_state, ClientState::Opened { .. }) {
131 log::error!("the state is already opened");
132 return Err(binder::ExceptionCode::ILLEGAL_STATE.into());
133 }
134
135 let mut death_recipient = {
136 let service_state = self.service_state.clone();
137 DeathRecipient::new(move || {
138 log::info!("Uwb service has died");
139 let mut service_state = service_state.blocking_lock();
140 service_state.client_state = ClientState::Closed;
141 })
142 };
143
144 callbacks.as_binder().link_to_death(&mut death_recipient)?;
145 callbacks.onHalEvent(UwbEvent::OPEN_CPLT, UwbStatus::OK)?;
146
147 service_state.client_state = ClientState::Opened {
148 callbacks: callbacks.clone(),
149 _death_recipient: death_recipient,
150 };
151
152 Ok(())
153 }
154
close(&self) -> Result<()>155 async fn close(&self) -> Result<()> {
156 log::debug!("close");
157
158 let mut service_state = self.service_state.lock().await;
159
160 if matches!(service_state.client_state, ClientState::Closed) {
161 log::error!("the state is already closed");
162 return Err(binder::ExceptionCode::ILLEGAL_STATE.into());
163 }
164
165 // Send the command Device Reset to stop all running activities
166 // on the UWBS emulator. This is necessary because the emulator
167 // is otherwise not notified of the power down (the serial stays
168 // open).
169 //
170 // The response to the command will be dropped by the polling loop,
171 // as the callbacks will have been removed then.
172 let uci_core_device_reset_cmd = [0x20, 0x00, 0x00, 0x01, 0x00];
173
174 service_state
175 .writer
176 .write_all(&uci_core_device_reset_cmd)
177 .await
178 .expect("failed to write UCI Device Reset command");
179
180 if let ClientState::Opened { ref callbacks, .. } = service_state.client_state {
181 callbacks.onHalEvent(UwbEvent::CLOSE_CPLT, UwbStatus::OK)?;
182 }
183
184 service_state.client_state = ClientState::Closed;
185 Ok(())
186 }
187
coreInit(&self) -> Result<()>188 async fn coreInit(&self) -> Result<()> {
189 log::debug!("coreInit");
190
191 let service_state = self.service_state.lock().await;
192
193 if let ClientState::Opened { ref callbacks, .. } = service_state.client_state {
194 callbacks.onHalEvent(UwbEvent::POST_INIT_CPLT, UwbStatus::OK)?;
195 Ok(())
196 } else {
197 Err(binder::ExceptionCode::ILLEGAL_STATE.into())
198 }
199 }
200
sessionInit(&self, _id: i32) -> Result<()>201 async fn sessionInit(&self, _id: i32) -> Result<()> {
202 log::debug!("sessionInit");
203
204 Ok(())
205 }
206
getSupportedAndroidUciVersion(&self) -> Result<i32>207 async fn getSupportedAndroidUciVersion(&self) -> Result<i32> {
208 log::debug!("getSupportedAndroidUciVersion");
209
210 Ok(1)
211 }
212
sendUciMessage(&self, data: &[u8]) -> Result<i32>213 async fn sendUciMessage(&self, data: &[u8]) -> Result<i32> {
214 log::debug!("sendUciMessage");
215
216 let mut service_state = self.service_state.lock().await;
217
218 if matches!(service_state.client_state, ClientState::Closed) {
219 log::error!("the state is not opened");
220 return Err(binder::ExceptionCode::ILLEGAL_STATE.into());
221 }
222
223 log::debug!(" --> {:?}", data);
224 service_state
225 .writer
226 .write_all(data)
227 .await
228 .map(|_| data.len() as i32)
229 .map_err(|_| binder::StatusCode::UNKNOWN_ERROR.into())
230 }
231 }
232