1use crate::error::{Result, TargetDriverError};
8use futures::channel::mpsc;
9use futures::prelude::*;
10use std::pin::Pin;
11use uart_fpl::{
12 AckOutcome, DEFAULT_RETRANSMISSION_TIMEOUT, FrameType, MAX_PAYLOAD_SIZE, ResendSender,
13};
14
15#[derive(Clone, Debug, PartialEq, Eq)]
17pub enum SenderMessage {
18 Data { channel_id: u16, payload: Vec<u8> },
20 Close { channel_id: u16, reason: Option<String> },
23}
24
25fn truncate_utf8_bytes(s: &str, max_bytes: usize) -> Vec<u8> {
27 if s.len() <= max_bytes {
28 return s.as_bytes().to_vec();
29 }
30 let end = s.floor_char_boundary(max_bytes);
31 s.as_bytes()[..end].to_vec()
32}
33
34fn handle_sender_ack(
39 sender: &mut ResendSender,
40 ack_event: Option<u8>,
41 active_timer: &mut Option<Pin<Box<fuchsia_async::Timer>>>,
42) -> Result<()> {
43 let Some(ack_seq) = ack_event else {
44 return Err(TargetDriverError::AckChannelClosed);
45 };
46 if let AckOutcome::Advanced { all_acked, .. } = sender.handle_ack(ack_seq) {
47 if all_acked {
48 *active_timer = None;
49 } else {
50 *active_timer =
51 Some(Box::pin(fuchsia_async::Timer::new(DEFAULT_RETRANSMISSION_TIMEOUT)));
52 }
53 }
54 Ok(())
55}
56
57async fn send_data_frame(
62 frame: Vec<u8>,
63 sender: &mut ResendSender,
64 ack_rx: &mut mpsc::Receiver<u8>,
65 data_tx: &mut mpsc::Sender<Vec<u8>>,
66 active_timer: &mut Option<Pin<Box<fuchsia_async::Timer>>>,
67) -> Result<()> {
68 let mut send_fut = std::pin::pin!(data_tx.send(frame).fuse());
69 loop {
70 futures::select_biased! {
71 ack_event = ack_rx.next().fuse() => {
72 handle_sender_ack(sender, ack_event, active_timer)?;
73 }
74 res = send_fut => {
75 return res.map_err(|e| {
76 TargetDriverError::ChannelSend(format!(
77 "Failed to send frame to writer: {e:?}"
78 ))
79 });
80 }
81 }
82 }
83}
84
85async fn retransmit_window(
88 sender: &mut ResendSender,
89 ack_rx: &mut mpsc::Receiver<u8>,
90 data_tx: &mut mpsc::Sender<Vec<u8>>,
91 active_timer: &mut Option<Pin<Box<fuchsia_async::Timer>>>,
92) -> Result<()> {
93 let retransmit_frames = sender.handle_timeout()?;
94 for frame in retransmit_frames {
95 if sender.is_idle() {
96 break;
97 }
98 send_data_frame(frame, sender, ack_rx, data_tx, active_timer).await?;
99 }
100 if !sender.is_idle() {
101 *active_timer = Some(Box::pin(fuchsia_async::Timer::new(DEFAULT_RETRANSMISSION_TIMEOUT)));
102 }
103 Ok(())
104}
105
106async fn send_next_in_flight(
112 sender: &mut ResendSender,
113 session_id: u32,
114 in_flight_msg: &mut Option<SenderMessage>,
115 ack_rx: &mut mpsc::Receiver<u8>,
116 data_tx: &mut mpsc::Sender<Vec<u8>>,
117 active_timer: &mut Option<Pin<Box<fuchsia_async::Timer>>>,
118) -> Result<()> {
119 if !sender.can_send() {
120 return Ok(());
121 }
122 let Some(msg) = in_flight_msg.take() else {
123 return Ok(());
124 };
125 let (frame_type, channel_id, payload) = match msg {
126 SenderMessage::Data { channel_id, payload } => (FrameType::Data, channel_id, payload),
127 SenderMessage::Close { channel_id, reason } => {
128 let payload =
129 reason.map(|r| truncate_utf8_bytes(&r, MAX_PAYLOAD_SIZE)).unwrap_or_default();
130 (FrameType::Close, channel_id, payload)
131 }
132 };
133 let (_seq, frame) = sender.enqueue_frame(session_id, channel_id, frame_type, &payload)?;
134 if sender.in_flight() == 1 {
135 *active_timer = Some(Box::pin(fuchsia_async::Timer::new(DEFAULT_RETRANSMISSION_TIMEOUT)));
136 }
137 send_data_frame(frame, sender, ack_rx, data_tx, active_timer).await
138}
139
140async fn wait_active_timer(active_timer: &mut Option<Pin<Box<fuchsia_async::Timer>>>) {
142 if let Some(timer) = active_timer {
143 timer.as_mut().await;
144 } else {
145 futures::future::pending::<()>().await;
146 }
147}
148
149async fn next_sender_msg(
152 sender_rx: &mut mpsc::Receiver<SenderMessage>,
153 enabled: bool,
154) -> Option<SenderMessage> {
155 if enabled { sender_rx.next().await } else { futures::future::pending().await }
156}
157
158pub async fn sender_task(
167 mut sender_rx: mpsc::Receiver<SenderMessage>,
168 mut data_tx: mpsc::Sender<Vec<u8>>,
169 mut ack_rx: mpsc::Receiver<u8>,
170 session_id: u32,
171) -> Result<()> {
172 let mut sender = ResendSender::default();
173 let mut active_timer: Option<Pin<Box<fuchsia_async::Timer>>> = None;
174 let mut in_flight_msg: Option<SenderMessage> = None;
175 let mut sender_rx_closed = false;
176 loop {
177 let can_recv = sender.can_send() && in_flight_msg.is_none() && !sender_rx_closed;
180 futures::select_biased! {
183 ack_event = ack_rx.next().fuse() => {
184 handle_sender_ack(&mut sender, ack_event, &mut active_timer)?;
185 }
186 _ = wait_active_timer(&mut active_timer).fuse() => {
187 retransmit_window(&mut sender, &mut ack_rx, &mut data_tx, &mut active_timer).await?;
188 }
189 msg = next_sender_msg(&mut sender_rx, can_recv).fuse() => match msg {
190 Some(message) => in_flight_msg = Some(message),
191 None => sender_rx_closed = true,
192 },
193 }
194 if in_flight_msg.is_none() && sender_rx_closed && sender.is_idle() {
197 return Ok(());
198 }
199 send_next_in_flight(
200 &mut sender,
201 session_id,
202 &mut in_flight_msg,
203 &mut ack_rx,
204 &mut data_tx,
205 &mut active_timer,
206 )
207 .await?;
208 }
209}
210
211#[cfg(test)]
212mod tests {
213 use super::*;
214 use uart_fpl::encode_frame;
215
216 #[fuchsia::test]
217 async fn test_sender_task_happy_path() {
218 let (outgoing_tx, mut outgoing_rx) = mpsc::channel(10);
219 let (mut ack_tx, ack_rx) = mpsc::channel(10);
220 let (mut sender_tx, sender_rx) = mpsc::channel(10);
221 let session_id = 12345u32;
222 let tx_handle = fuchsia_async::Task::spawn(async move {
223 sender_task(sender_rx, outgoing_tx, ack_rx, session_id).await
224 });
225 let payload = b"data to serial";
226 let channel_id = 42u16;
227 sender_tx
228 .send(SenderMessage::Data { channel_id, payload: payload.to_vec() })
229 .await
230 .unwrap();
231 let frame = outgoing_rx.next().await.unwrap();
232 let expected_frame =
233 encode_frame(session_id, channel_id, 0, FrameType::Data, payload).unwrap();
234 assert_eq!(frame, expected_frame);
235 ack_tx.send(0).await.unwrap();
236 drop(sender_tx);
237 let res = tx_handle.await;
238 assert!(res.is_ok());
239 }
240
241 #[fuchsia::test]
242 async fn test_sender_task_close_message() {
243 let (outgoing_tx, mut outgoing_rx) = mpsc::channel(10);
244 let (mut ack_tx, ack_rx) = mpsc::channel(10);
245 let (mut sender_tx, sender_rx) = mpsc::channel(10);
246 let session_id = 67890u32;
247 let tx_handle = fuchsia_async::Task::spawn(async move {
248 sender_task(sender_rx, outgoing_tx, ack_rx, session_id).await
249 });
250 sender_tx.send(SenderMessage::Close { channel_id: 7, reason: None }).await.unwrap();
251 let frame = outgoing_rx.next().await.unwrap();
252 let expected_frame = encode_frame(session_id, 7, 0, FrameType::Close, &[]).unwrap();
253 assert_eq!(frame, expected_frame);
254 ack_tx.send(0).await.unwrap();
255
256 sender_tx
257 .send(SenderMessage::Close {
258 channel_id: 8,
259 reason: Some("RCS socket read error: PEER_CLOSED".to_string()),
260 })
261 .await
262 .unwrap();
263 let err_frame = outgoing_rx.next().await.unwrap();
264 let expected_err_frame =
265 encode_frame(session_id, 8, 1, FrameType::Close, b"RCS socket read error: PEER_CLOSED")
266 .unwrap();
267 assert_eq!(err_frame, expected_err_frame);
268 ack_tx.send(1).await.unwrap();
269
270 drop(sender_tx);
271 assert!(tx_handle.await.is_ok());
272 }
273
274 #[fuchsia::test]
275 async fn test_sender_task_ack_channel_closed_error() {
276 let (outgoing_tx, _outgoing_rx) = mpsc::channel(10);
277 let (ack_tx, ack_rx) = mpsc::channel(10);
278 let (_sender_tx, sender_rx) = mpsc::channel(10);
279 drop(ack_tx);
280 let res = sender_task(sender_rx, outgoing_tx, ack_rx, 12345).await;
281 assert!(matches!(res, Err(TargetDriverError::AckChannelClosed)));
282 }
283
284 #[fuchsia::test]
285 async fn test_sender_task_retransmits_on_timeout() {
286 let (outgoing_tx, mut outgoing_rx) = mpsc::channel(10);
287 let (mut ack_tx, ack_rx) = mpsc::channel(10);
288 let (mut sender_tx, sender_rx) = mpsc::channel(10);
289 let tx_handle = fuchsia_async::Task::spawn(async move {
290 sender_task(sender_rx, outgoing_tx, ack_rx, 12345).await
291 });
292 sender_tx
293 .send(SenderMessage::Data { channel_id: 1, payload: b"retransmit".to_vec() })
294 .await
295 .unwrap();
296 let first_frame = outgoing_rx.next().await.unwrap();
297 let retransmitted_frame = outgoing_rx.next().await.unwrap();
298 assert_eq!(first_frame, retransmitted_frame);
299 ack_tx.send(0).await.unwrap();
300 drop(sender_tx);
301 assert!(tx_handle.await.is_ok());
302 }
303
304 #[fuchsia::test]
305 async fn test_sender_task_drains_acks_while_data_tx_backpressured() {
306 let (outgoing_tx, mut outgoing_rx) = mpsc::channel(1);
312 let (mut ack_tx, ack_rx) = mpsc::channel(10);
313 let (mut sender_tx, sender_rx) = mpsc::channel(10);
314 let session_id = 12345u32;
315 let tx_handle = fuchsia_async::Task::spawn(async move {
316 sender_task(sender_rx, outgoing_tx, ack_rx, session_id).await
317 });
318 sender_tx
319 .send(SenderMessage::Data { channel_id: 1, payload: b"frame0".to_vec() })
320 .await
321 .unwrap();
322 sender_tx
323 .send(SenderMessage::Data { channel_id: 1, payload: b"frame1".to_vec() })
324 .await
325 .unwrap();
326 drop(sender_tx);
327 fuchsia_async::yield_now().await;
334 ack_tx.send(1).await.unwrap();
337 fuchsia_async::yield_now().await;
340 let _f0 = outgoing_rx.next().await.unwrap();
343 let _f1 = outgoing_rx.next().await.unwrap();
344 assert!(tx_handle.await.is_ok());
345 }
346}