1pub mod coordinator;
26pub mod error;
27pub mod receiver;
28pub mod sender;
29pub mod serial;
30
31use crate::coordinator::{
32 DEFAULT_CHANNEL_CAPACITY, DEFAULT_CLIENT_DATA_CAPACITY, coordinator_task,
33};
34use crate::error::TargetDriverError;
35use crate::receiver::receiver_task;
36use crate::sender::sender_task;
37use crate::serial::{
38 SerialRead, SerialReader, SerialWrite, open_serial_device,
39 run_target_handshake_with_initial_data, writer_task,
40};
41pub use error::Result;
42use fidl_fuchsia_developer_remotecontrol_connector::{ConnectorMarker, ConnectorProxy};
43use fidl_fuchsia_hardware_serial::DeviceProxy;
44use fuchsia_component::client::connect_to_protocol;
45use futures::channel::mpsc;
46use log::{error, info, warn};
47use std::time::Duration;
48use uart_fpl::{AckTracker, CONTROL_CHANNEL_ID, FrameType, ProtocolId, encode_frame};
49
50const BOOT_ARG_ENABLED: &str = "dev.fdomain.uart";
52
53const BOOT_ARG_BAUD_RATE: &str = "dev.fdomain.uart.baud";
55
56const DEFAULT_BAUD_RATE: u32 = 1_000_000;
58
59const RETRY_DELAY: Duration = Duration::from_secs(1);
61
62async fn is_enabled() -> bool {
65 if let Ok(args) = connect_to_protocol::<fidl_fuchsia_boot::ArgumentsMarker>() {
66 match args.get_bool(BOOT_ARG_ENABLED, false).await {
67 Ok(val) => val,
68 Err(e) => {
69 warn!("Failed to get {} boot arg: {:?}", BOOT_ARG_ENABLED, e);
70 false
71 }
72 }
73 } else {
74 warn!("Failed to connect to fuchsia.boot.Arguments");
75 false
76 }
77}
78
79async fn read_baud_rate() -> u32 {
82 let Ok(args) = connect_to_protocol::<fidl_fuchsia_boot::ArgumentsMarker>() else {
83 warn!("Failed to connect to fuchsia.boot.Arguments to get baud rate");
84 return DEFAULT_BAUD_RATE;
85 };
86 match args.get_string(BOOT_ARG_BAUD_RATE).await {
87 Ok(Some(value)) => match value.parse::<u32>() {
88 Ok(baud) if baud > 0 => baud,
89 _ => {
90 warn!("Failed to parse {} '{}', using default", BOOT_ARG_BAUD_RATE, value);
91 DEFAULT_BAUD_RATE
92 }
93 },
94 Ok(None) => DEFAULT_BAUD_RATE,
95 Err(e) => {
96 warn!("Failed to get {} boot arg: {:?}", BOOT_ARG_BAUD_RATE, e);
97 DEFAULT_BAUD_RATE
98 }
99 }
100}
101
102async fn negotiate_session<S: SerialRead + SerialWrite + Clone>(
108 device: &S,
109 is_initial_start: &mut bool,
110 initial_data: &[u8],
111) -> Result<(ProtocolId, u32, Vec<u8>)> {
112 if *is_initial_start {
113 let reset_frame = encode_frame(0, CONTROL_CHANNEL_ID, 0, FrameType::Reset, &[])?;
118 let mut device_writer = device.clone();
119 if let Err(e) = device_writer.serial_write(&reset_frame).await {
120 warn!("Failed to send reset frame: {:?}", e);
121 } else {
122 *is_initial_start = false;
123 }
124 }
125 let mut device_reader = device.clone();
126 run_target_handshake_with_initial_data(&mut device_reader, initial_data).await
127}
128
129async fn run_bridge_session<S: SerialRead + SerialWrite + Clone>(
136 device: S,
137 session_id: u32,
138 unconsumed: &[u8],
139 rcs_connector: ConnectorProxy,
140) -> (Result<((), (), (), ())>, Vec<u8>) {
141 let ack_tracker = AckTracker::new();
142 let (data_tx, data_rx) = mpsc::channel(DEFAULT_CHANNEL_CAPACITY);
143 let (ack_tx, ack_rx) = mpsc::channel(DEFAULT_CLIENT_DATA_CAPACITY);
144 let (sender_tx, sender_rx) = mpsc::channel(DEFAULT_CHANNEL_CAPACITY);
145 let (serial_tx, serial_rx) = mpsc::channel(DEFAULT_CLIENT_DATA_CAPACITY);
146 let mut reader = SerialReader::with_initial_data(device.clone(), unconsumed);
147 let res = {
148 let writer = writer_task(device, ack_tracker.clone(), data_rx);
149 let receiver =
150 receiver_task(&mut reader, serial_tx, ack_tracker, ack_tx, session_id, data_tx.clone());
151 let sender = sender_task(sender_rx, data_tx, ack_rx, session_id);
152 let coordinator = coordinator_task(serial_rx, sender_tx, rcs_connector);
153 info!("Bridge tasks started");
154 futures::try_join!(writer, receiver, sender, coordinator)
155 };
156 (res, reader.take_unconsumed())
157}
158
159async fn run_device_sessions<S: SerialRead + SerialWrite + Clone>(
167 device: S,
168 rcs_connector: &ConnectorProxy,
169 is_initial_start: &mut bool,
170) {
171 let mut carry_over = Vec::new();
172 loop {
173 let (proto, session_id, unconsumed) =
174 match negotiate_session(&device, is_initial_start, &carry_over).await {
175 Ok(negotiated) => negotiated,
176 Err(e) => {
177 error!("Handshake failed ({:?}); reopening serial device in 1s...", e);
178 drop(device);
179 fuchsia_async::Timer::new(RETRY_DELAY).await;
180 return;
181 }
182 };
183 info!("Handshake succeeded. Negotiated protocol: {:?}", proto);
184 let (res, remaining) =
185 run_bridge_session(device.clone(), session_id, &unconsumed, rcs_connector.clone())
186 .await;
187 match res {
188 Err(TargetDriverError::SessionIdChanged) => {
189 info!("Session ID changed; renegotiating on existing serial device");
190 carry_over = remaining;
191 }
192 Err(TargetDriverError::ResetRequested) => {
193 info!("Session reset requested; renegotiating on existing serial device");
194 carry_over = remaining;
195 }
196 Err(e) => {
197 warn!(
198 "Bridge session ended with error ({:?}); reopening serial device in 1s...",
199 e
200 );
201 drop(device);
202 fuchsia_async::Timer::new(RETRY_DELAY).await;
203 return;
204 }
205 Ok(_) => {
206 drop(device);
207 fuchsia_async::Timer::new(RETRY_DELAY).await;
208 return;
209 }
210 }
211 }
212}
213
214async fn run_driver_iteration(
220 baud_rate: u32,
221 rcs_connector: &ConnectorProxy,
222 is_initial_start: &mut bool,
223) -> Result<()> {
224 let device: DeviceProxy = match open_serial_device(baud_rate).await {
225 Ok(device) => device,
226 Err(TargetDriverError::NoSerialPorts | TargetDriverError::Io(_)) => {
230 fuchsia_async::Timer::new(RETRY_DELAY).await;
231 return Ok(());
232 }
233 Err(e) => {
234 warn!("Failed to open serial device: {:?}. Retrying in 1s...", e);
235 fuchsia_async::Timer::new(RETRY_DELAY).await;
236 return Ok(());
237 }
238 };
239 run_device_sessions(device, rcs_connector, is_initial_start).await;
240 Ok(())
241}
242
243pub async fn run_driver() -> Result<()> {
250 info!("Starting FDomain UART Driver");
251 if !is_enabled().await {
252 info!(
253 "FDomain UART Driver is disabled by boot argument '{}'. Sleeping forever.",
254 BOOT_ARG_ENABLED
255 );
256 futures::future::pending::<()>().await;
257 }
258 let baud_rate = read_baud_rate().await;
259 let rcs_connector = connect_to_protocol::<ConnectorMarker>()
260 .map_err(|e| TargetDriverError::RcsConnect(format!("{e:#}")))?;
261 let mut is_initial_start = true;
262 loop {
263 run_driver_iteration(baud_rate, &rcs_connector, &mut is_initial_start).await?;
264 }
265}
266
267#[cfg(test)]
268mod tests {
269 use super::*;
270 use crate::serial::MockSerial;
271 use std::cell::RefCell;
272 use std::rc::Rc;
273 use uart_fpl::{FrameParser, HostHandshake};
274
275 #[derive(Clone)]
276 struct SharedMockSerial(Rc<RefCell<MockSerial>>);
277
278 impl SerialRead for SharedMockSerial {
279 async fn serial_read(&mut self) -> Result<Vec<u8>> {
280 let mut inner = self.0.borrow_mut();
281 if inner.read_data.is_empty() {
282 return Ok(Vec::new());
283 }
284 Ok(inner.read_data.remove(0))
285 }
286 }
287
288 impl SerialWrite for SharedMockSerial {
289 async fn serial_write(&mut self, data: &[u8]) -> Result<()> {
290 self.0.borrow_mut().write_data.push(data.to_vec());
291 Ok(())
292 }
293 }
294
295 #[fuchsia::test]
296 async fn test_negotiate_session_initial_start_sends_reset() {
297 let host = HostHandshake::new(vec![ProtocolId::ResendSP]);
298 let (frame_type, payload) = host.start().unwrap();
299 let req_1 = encode_frame(111, CONTROL_CHANNEL_ID, 0, frame_type, &payload).unwrap();
300 let req_2 = encode_frame(222, CONTROL_CHANNEL_ID, 0, frame_type, &payload).unwrap();
301 let mock = SharedMockSerial(Rc::new(RefCell::new(MockSerial {
302 read_data: vec![req_1],
303 write_data: Vec::new(),
304 })));
305 let mut is_initial_start = true;
306 let (proto_1, sid_1, _) =
307 negotiate_session(&mock, &mut is_initial_start, &[]).await.unwrap();
308 assert!(!is_initial_start);
309 assert_eq!(proto_1, ProtocolId::ResendSP);
310 assert_eq!(sid_1, 111);
311 let mut parser = FrameParser::new();
312 for chunk in &mock.0.borrow().write_data {
313 parser.feed(chunk);
314 }
315 let first_written = parser.next_frame().unwrap();
316 assert_eq!(first_written.frame_type, FrameType::Reset);
317 let second_written = parser.next_frame().unwrap();
318 assert_eq!(second_written.frame_type, FrameType::NegotiateResp);
319
320 mock.0.borrow_mut().write_data.clear();
321 let (proto_2, sid_2, _) =
322 negotiate_session(&mock, &mut is_initial_start, &req_2).await.unwrap();
323 assert_eq!(proto_2, ProtocolId::ResendSP);
324 assert_eq!(sid_2, 222);
325 let mut parser_2 = FrameParser::new();
326 for chunk in &mock.0.borrow().write_data {
327 parser_2.feed(chunk);
328 }
329 let only_written = parser_2.next_frame().unwrap();
330 assert_eq!(only_written.frame_type, FrameType::NegotiateResp);
331 assert!(parser_2.next_frame().is_none());
332 }
333
334 #[fuchsia::test]
335 async fn test_run_bridge_session_preserves_remaining_bytes_on_reset() {
336 let host = HostHandshake::new(vec![ProtocolId::ResendSP]);
337 let (frame_type, payload) = host.start().unwrap();
338 let session_1 = 111u32;
339 let session_2 = 222u32;
340 let reset_1 =
341 encode_frame(session_1, CONTROL_CHANNEL_ID, 0, FrameType::Reset, &[]).unwrap();
342 let req_2 = encode_frame(session_2, CONTROL_CHANNEL_ID, 0, frame_type, &payload).unwrap();
343 let coalesced = [reset_1, req_2.clone()].concat();
345 let mock = SharedMockSerial(Rc::new(RefCell::new(MockSerial {
346 read_data: vec![coalesced],
347 write_data: Vec::new(),
348 })));
349 let (connector_proxy, _connector_stream) =
350 fidl::endpoints::create_proxy_and_stream::<ConnectorMarker>();
351 let (res, remaining) =
352 run_bridge_session(mock.clone(), session_1, &[], connector_proxy).await;
353 assert!(matches!(res, Err(TargetDriverError::ResetRequested)));
354 assert_eq!(remaining, req_2);
355
356 let mut is_initial_start = false;
358 let (proto, sid, _) =
359 negotiate_session(&mock, &mut is_initial_start, &remaining).await.unwrap();
360 assert_eq!(proto, ProtocolId::ResendSP);
361 assert_eq!(sid, session_2);
362 }
363}