use core::future::Future;
use embassy_futures::select::select;
use embedded_io_async::{Read, Write};
use log::{debug, warn};
pub trait BufferedSerial: Sync {
fn read(&self, buf: &mut [u8]) -> impl Future<Output = usize>;
fn write(&self, buf: &[u8]) -> impl Future<Output = ()>;
fn check_dropped_bytes(&self) -> usize;
}
pub async fn serial_bridge<U: BufferedSerial>(
chan_read: impl Read<Error = sunset::Error>,
chan_write: impl Write<Error = sunset::Error>,
uart: &U,
) -> Result<(), sunset::Error> {
debug!("Starting serial <--> SSH bridge");
select(uart_to_ssh(uart, chan_write), ssh_to_uart(chan_read, uart)).await;
debug!("Stopping serial <--> SSH bridge");
Ok(())
}
async fn uart_to_ssh<U: BufferedSerial>(
uart_buf: &U,
mut chan_write: impl Write<Error = sunset::Error>,
) -> Result<(), sunset::Error> {
let mut ssh_tx_buf = [0u8; 512];
loop {
let dropped = uart_buf.check_dropped_bytes();
if dropped > 0 {
warn!("UART RX dropped {dropped} bytes");
}
let n = uart_buf.read(&mut ssh_tx_buf).await;
chan_write.write_all(&ssh_tx_buf[..n]).await?;
}
}
async fn ssh_to_uart<U: BufferedSerial>(
mut chan_read: impl Read<Error = sunset::Error>,
uart_buf: &U,
) -> Result<(), sunset::Error> {
let mut uart_tx_buf = [0u8; 64];
loop {
let n = chan_read.read(&mut uart_tx_buf).await?;
if n == 0 {
return Err(sunset::Error::ChannelEOF);
}
uart_buf.write(&uart_tx_buf[..n]).await;
}
}