blob: d749147d1565e4b2d89d661c9dbc0d34d2559df5 [file] [log] [blame]
Charlie Boutierd572dd02023-04-10 18:14:23 +00001use android_hardware_uwb::aidl::android::hardware::uwb::{
2 IUwbChip::IUwbChipAsyncServer, IUwbClientCallback::IUwbClientCallback, UwbEvent::UwbEvent,
3 UwbStatus::UwbStatus,
4};
5use android_hardware_uwb::binder;
6use async_trait::async_trait;
ziyiw4fec12a2023-09-27 21:00:25 +00007use binder::{DeathRecipient, IBinder, Result, Strong};
Charlie Boutierd572dd02023-04-10 18:14:23 +00008
ziyiw4fec12a2023-09-27 21:00:25 +00009use std::sync::Arc;
10use tokio::io::unix::AsyncFd;
11use tokio::select;
Charlie Boutierd572dd02023-04-10 18:14:23 +000012use tokio::sync::Mutex;
ziyiw4fec12a2023-09-27 21:00:25 +000013use tokio_util::sync::CancellationToken;
Charlie Boutierd572dd02023-04-10 18:14:23 +000014
ziyiw4fec12a2023-09-27 21:00:25 +000015use std::fs::{File, OpenOptions};
16use std::io::{self, Read, Write};
Henri Chataing7e798082023-10-05 16:14:12 +000017use std::os::unix::fs::OpenOptionsExt;
Charlie Boutierd572dd02023-04-10 18:14:23 +000018
ziyiw49aa3352023-12-08 22:40:55 +000019use pdl_runtime::Packet;
20use uwb_uci_packets::{DeviceResetCmdBuilder, ResetConfig, UciControlPacket, UciControlPacketHal};
21
Charlie Boutierd572dd02023-04-10 18:14:23 +000022enum State {
23 Closed,
24 Opened {
25 callbacks: Strong<dyn IUwbClientCallback>,
Henri Chataing7e798082023-10-05 16:14:12 +000026 handle: tokio::task::JoinHandle<()>,
Henri Chataing77971b32023-08-16 16:55:24 +000027 serial: File,
ziyiw4fec12a2023-09-27 21:00:25 +000028 death_recipient: DeathRecipient,
29 token: CancellationToken,
Charlie Boutierd572dd02023-04-10 18:14:23 +000030 },
31}
32
33pub struct UwbChip {
34 name: String,
35 path: String,
ziyiw4fec12a2023-09-27 21:00:25 +000036 state: Arc<Mutex<State>>,
Charlie Boutierd572dd02023-04-10 18:14:23 +000037}
38
39impl UwbChip {
40 pub fn new(name: String, path: String) -> Self {
41 Self {
42 name,
43 path,
ziyiw4fec12a2023-09-27 21:00:25 +000044 state: Arc::new(Mutex::new(State::Closed)),
Charlie Boutierd572dd02023-04-10 18:14:23 +000045 }
46 }
47}
48
ziyiw4fec12a2023-09-27 21:00:25 +000049impl State {
50 /// Terminate the reader task.
Henri Chataing7e798082023-10-05 16:14:12 +000051 async fn close(&mut self) -> Result<()> {
ziyiw49aa3352023-12-08 22:40:55 +000052 if let State::Opened {
53 ref mut token,
54 ref callbacks,
55 ref mut death_recipient,
56 ref mut handle,
57 ref mut serial,
58 } = *self
59 {
ziyiw4fec12a2023-09-27 21:00:25 +000060 log::info!("waiting for task cancellation");
61 callbacks.as_binder().unlink_to_death(death_recipient)?;
62 token.cancel();
Henri Chataing7e798082023-10-05 16:14:12 +000063 handle.await.unwrap();
ziyiw49aa3352023-12-08 22:40:55 +000064 consume_device_reset_rsp_and_ntf(
65 &mut serial
66 .try_clone()
67 .map_err(|_| binder::StatusCode::UNKNOWN_ERROR)?,
68 );
ziyiw4fec12a2023-09-27 21:00:25 +000069 log::info!("task successfully cancelled");
70 callbacks.onHalEvent(UwbEvent::CLOSE_CPLT, UwbStatus::OK)?;
71 *self = State::Closed;
72 }
73 Ok(())
74 }
75}
76
ziyiw49aa3352023-12-08 22:40:55 +000077fn consume_device_reset_rsp_and_ntf(reader: &mut File) {
78 // Poll the DeviceResetRsp and DeviceStatusNtf before hal is closed to prevent
79 // the host from getting response and notifications from a 'powered down' UWBS.
80 // Do nothing when these packets are received.
81 const DEVICE_RESET_RSP: [u8; 5] = [64, 0, 0, 1, 0];
82 const DEVICE_STATUS_NTF: [u8; 5] = [96, 1, 0, 1, 1];
83 let mut buffer = vec![0; DEVICE_RESET_RSP.len() + DEVICE_STATUS_NTF.len()];
84 read_exact(reader, &mut buffer).unwrap();
85
86 // Make sure received packets are the expected ones.
87 assert_eq!(&buffer[0..DEVICE_RESET_RSP.len()], &DEVICE_RESET_RSP);
88 assert_eq!(&buffer[DEVICE_RESET_RSP.len()..], &DEVICE_STATUS_NTF);
89}
90
Charlie Boutierd572dd02023-04-10 18:14:23 +000091pub fn makeraw(file: File) -> io::Result<File> {
Andrew Walbran116bf2a2023-12-05 16:17:24 +000092 // Configure the file descriptor as raw fd.
ziyiw4fec12a2023-09-27 21:00:25 +000093 use nix::sys::termios::*;
Andrew Walbran116bf2a2023-12-05 16:17:24 +000094 let mut attrs = tcgetattr(&file)?;
ziyiw4fec12a2023-09-27 21:00:25 +000095 cfmakeraw(&mut attrs);
Andrew Walbran116bf2a2023-12-05 16:17:24 +000096 tcsetattr(&file, SetArg::TCSANOW, &attrs)?;
Charlie Boutierd572dd02023-04-10 18:14:23 +000097
Charlie Boutierd572dd02023-04-10 18:14:23 +000098 Ok(file)
99}
100
ziyiw4fec12a2023-09-27 21:00:25 +0000101/// Wrapper around Read::read to handle EWOULDBLOCK.
102/// /!\ will actively wait for more data, make sure to call
103/// this method only when data is immediately expected.
104fn read_exact(file: &mut File, mut buf: &mut [u8]) -> io::Result<()> {
105 while buf.len() > 0 {
106 match file.read(buf) {
107 Ok(0) => panic!("unexpectedly reached end of file"),
108 Ok(read_len) => buf = &mut buf[read_len..],
109 Err(err) if err.kind() == io::ErrorKind::WouldBlock => continue,
110 Err(err) => return Err(err),
111 }
112 }
113 Ok(())
114}
115
Charlie Boutierd572dd02023-04-10 18:14:23 +0000116impl binder::Interface for UwbChip {}
117
118#[async_trait]
119impl IUwbChipAsyncServer for UwbChip {
120 async fn getName(&self) -> Result<String> {
121 Ok(self.name.clone())
122 }
123
124 async fn open(&self, callbacks: &Strong<dyn IUwbClientCallback>) -> Result<()> {
125 log::debug!("open: {:?}", &self.path);
126
ziyiw4fec12a2023-09-27 21:00:25 +0000127 let mut state = self.state.lock().await;
128
129 if matches!(*state, State::Opened { .. }) {
130 log::error!("the state is already opened");
131 return Err(binder::ExceptionCode::ILLEGAL_STATE.into());
132 }
133
Henri Chataing77971b32023-08-16 16:55:24 +0000134 let serial = OpenOptions::new()
135 .read(true)
136 .write(true)
137 .create(false)
Henri Chataing7e798082023-10-05 16:14:12 +0000138 .custom_flags(libc::O_NONBLOCK)
Henri Chataing77971b32023-08-16 16:55:24 +0000139 .open(&self.path)
Charlie Boutierd572dd02023-04-10 18:14:23 +0000140 .and_then(makeraw)
141 .map_err(|_| binder::StatusCode::UNKNOWN_ERROR)?;
142
ziyiw4fec12a2023-09-27 21:00:25 +0000143 let state_death_recipient = self.state.clone();
144 let mut death_recipient = DeathRecipient::new(move || {
145 let mut state = state_death_recipient.blocking_lock();
146 log::info!("Uwb service has died");
Henri Chataing7e798082023-10-05 16:14:12 +0000147 if let State::Opened { ref mut token, .. } = *state {
148 token.cancel();
149 *state = State::Closed;
150 }
ziyiw4fec12a2023-09-27 21:00:25 +0000151 });
Charlie Boutierd572dd02023-04-10 18:14:23 +0000152
ziyiw4fec12a2023-09-27 21:00:25 +0000153 callbacks.as_binder().link_to_death(&mut death_recipient)?;
Charlie Boutierd572dd02023-04-10 18:14:23 +0000154
ziyiw4fec12a2023-09-27 21:00:25 +0000155 let token = CancellationToken::new();
156 let cloned_token = token.clone();
Charlie Boutierd572dd02023-04-10 18:14:23 +0000157
ziyiw4fec12a2023-09-27 21:00:25 +0000158 let client_callbacks = callbacks.clone();
Charlie Boutierd572dd02023-04-10 18:14:23 +0000159
ziyiw4fec12a2023-09-27 21:00:25 +0000160 let reader = serial
161 .try_clone()
162 .map_err(|_| binder::StatusCode::UNKNOWN_ERROR)?;
Charlie Boutierd572dd02023-04-10 18:14:23 +0000163
ziyiw4fec12a2023-09-27 21:00:25 +0000164 let join_handle = tokio::task::spawn(async move {
Henri Chataing7e798082023-10-05 16:14:12 +0000165 log::info!("UCI reader task started");
ziyiw4fec12a2023-09-27 21:00:25 +0000166 let mut reader = AsyncFd::new(reader).unwrap();
Charlie Boutierd572dd02023-04-10 18:14:23 +0000167
ziyiw4fec12a2023-09-27 21:00:25 +0000168 loop {
169 const UWB_HEADER_SIZE: usize = 4;
170 let mut buffer = vec![0; UWB_HEADER_SIZE];
Charlie Boutierd572dd02023-04-10 18:14:23 +0000171
ziyiw4fec12a2023-09-27 21:00:25 +0000172 // The only time where the task can be safely
173 // cancelled is when no packet bytes have been read.
174 //
175 // - read_exact() cannot be used here since it is not
176 // cancellation safe.
177 // - read() cannot be used because it cannot be cancelled:
178 // the syscall is executed blocking on the threadpool
179 // and completes after termination of the task when
180 // the pipe receives more data.
181 let read_len = loop {
182 // On some platforms, the readiness detecting mechanism
183 // relies on edge-triggered notifications. This means that
184 // the OS will only notify Tokio when the file descriptor
185 // transitions from not-ready to ready. For this to work
186 // you should first try to read or write and only poll for
Henri Chataing7e798082023-10-05 16:14:12 +0000187 // readiness if that fails with an error of
ziyiw4fec12a2023-09-27 21:00:25 +0000188 // std::io::ErrorKind::WouldBlock.
189 match reader.get_mut().read(&mut buffer) {
190 Ok(0) => {
191 log::error!("file unexpectedly closed");
192 return;
193 }
194 Ok(read_len) => break read_len,
195 Err(err) if err.kind() == io::ErrorKind::WouldBlock => (),
196 Err(_) => panic!("unexpected read failure"),
197 }
Charlie Boutierd572dd02023-04-10 18:14:23 +0000198
ziyiw4fec12a2023-09-27 21:00:25 +0000199 let mut guard = select! {
200 _ = cloned_token.cancelled() => {
Henri Chataing7e798082023-10-05 16:14:12 +0000201 log::info!("task is cancelled!");
ziyiw4fec12a2023-09-27 21:00:25 +0000202 return;
203 },
204 result = reader.readable() => result.unwrap()
205 };
Charlie Boutierd572dd02023-04-10 18:14:23 +0000206
ziyiw4fec12a2023-09-27 21:00:25 +0000207 guard.clear_ready();
208 };
Charlie Boutierd572dd02023-04-10 18:14:23 +0000209
ziyiw4fec12a2023-09-27 21:00:25 +0000210 // Read the remaining header bytes, if truncated.
211 read_exact(reader.get_mut(), &mut buffer[read_len..]).unwrap();
212
213 let length = buffer[3] as usize + UWB_HEADER_SIZE;
214 buffer.resize(length, 0);
215
216 // Read the payload bytes.
217 read_exact(reader.get_mut(), &mut buffer[UWB_HEADER_SIZE..]).unwrap();
218
219 client_callbacks.onUciMessage(&buffer).unwrap();
220 }
221 });
222
223 callbacks.onHalEvent(UwbEvent::OPEN_CPLT, UwbStatus::OK)?;
224
225 *state = State::Opened {
226 callbacks: callbacks.clone(),
Henri Chataing7e798082023-10-05 16:14:12 +0000227 handle: join_handle,
ziyiw4fec12a2023-09-27 21:00:25 +0000228 serial,
229 death_recipient,
230 token,
231 };
232
233 Ok(())
Charlie Boutierd572dd02023-04-10 18:14:23 +0000234 }
235
236 async fn close(&self) -> Result<()> {
237 log::debug!("close");
238
239 let mut state = self.state.lock().await;
240
ziyiw49aa3352023-12-08 22:40:55 +0000241 if let State::Opened { ref mut serial, .. } = *state {
242 let packet: UciControlPacket = DeviceResetCmdBuilder {
243 reset_config: ResetConfig::UwbsReset,
244 }
245 .build()
246 .into();
247 // DeviceResetCmd need to be send to reset the device to stop all running
248 // activities on UWBS.
249 let packet_vec: Vec<UciControlPacketHal> = packet.into();
250 for hal_packet in packet_vec.into_iter() {
251 serial
252 .write(&hal_packet.to_vec())
253 .map(|written| written as i32)
254 .map_err(|_| binder::StatusCode::UNKNOWN_ERROR)?;
255 }
Henri Chataing7e798082023-10-05 16:14:12 +0000256 state.close().await
Charlie Boutierd572dd02023-04-10 18:14:23 +0000257 } else {
258 Err(binder::ExceptionCode::ILLEGAL_STATE.into())
259 }
260 }
261
262 async fn coreInit(&self) -> Result<()> {
263 log::debug!("coreInit");
264
265 if let State::Opened { ref callbacks, .. } = *self.state.lock().await {
266 callbacks.onHalEvent(UwbEvent::POST_INIT_CPLT, UwbStatus::OK)?;
267 Ok(())
268 } else {
269 Err(binder::ExceptionCode::ILLEGAL_STATE.into())
270 }
271 }
272
273 async fn sessionInit(&self, _id: i32) -> Result<()> {
274 log::debug!("sessionInit");
275
276 Ok(())
277 }
278
279 async fn getSupportedAndroidUciVersion(&self) -> Result<i32> {
280 Ok(1)
281 }
282
283 async fn sendUciMessage(&self, data: &[u8]) -> Result<i32> {
284 log::debug!("sendUciMessage");
285
Henri Chataing77971b32023-08-16 16:55:24 +0000286 if let State::Opened { ref mut serial, .. } = &mut *self.state.lock().await {
287 serial
288 .write(data)
Henri Chataing77971b32023-08-16 16:55:24 +0000289 .map(|written| written as i32)
Charlie Boutierd572dd02023-04-10 18:14:23 +0000290 .map_err(|_| binder::StatusCode::UNKNOWN_ERROR.into())
291 } else {
292 Err(binder::ExceptionCode::ILLEGAL_STATE.into())
293 }
294 }
295}