use core::cell::RefCell;
use core::mem::MaybeUninit;
use embassy_futures::select::{select3, Either3};
use embassy_net_driver_channel::{self as ch, driver::LinkState};
use embassy_sync::{blocking_mutex::raw::CriticalSectionRawMutex, signal::Signal};
use embassy_time::Timer;
pub mod context;
use crate::socket::Socket;
const MTU: usize = 1500;
pub type NetDriver<'a> = ch::Device<'a, MTU>;
pub async fn new<'a>(state: &'a mut State) -> (NetDriver<'a>, Control<'a>, Runner<'a>) {
let state_inner = &*state
.inner
.write(RefCell::new(StateInner { net_socket: None }));
let control = Control {
state: state_inner,
close_signal: &state.close_signal,
};
let (ch_runner, device) = ch::new(&mut state.ch, ch::driver::HardwareAddress::Ip);
let runner = Runner {
ch: ch_runner,
state: state_inner,
close_signal: &state.close_signal,
};
(device, control, runner)
}
pub struct State {
ch: ch::State<MTU, 4, 4>,
inner: MaybeUninit<RefCell<StateInner>>,
close_signal: Signal<CriticalSectionRawMutex, bool>,
}
impl State {
pub const fn new() -> Self {
Self {
ch: ch::State::new(),
inner: MaybeUninit::uninit(),
close_signal: Signal::new(),
}
}
}
impl Default for State {
fn default() -> Self {
Self::new()
}
}
struct StateInner {
net_socket: Option<Socket>,
}
pub struct Control<'a> {
state: &'a RefCell<StateInner>,
close_signal: &'a Signal<CriticalSectionRawMutex, bool>,
}
pub(crate) const CAP_SIZE: usize = 256;
impl<'a> Control<'a> {
async fn open_raw_socket(&self) {
let socket = Socket::create(
crate::socket::SocketFamily::Raw,
crate::socket::SocketType::Raw,
crate::socket::SocketProtocol::IP,
)
.await
.unwrap();
self.close_signal.reset();
self.state.borrow_mut().net_socket = Some(socket);
}
async fn close_raw_socket(&self) {
let socket = self.state.borrow_mut().net_socket.take();
if let Some(s) = socket {
s.deactivate().await.unwrap();
} else {
self.close_signal.signal(true);
}
}
pub async fn at_command(&self, commad: &[u8]) -> arrayvec::ArrayString<CAP_SIZE> {
crate::send_at(core::str::from_utf8(commad).unwrap())
.await
.unwrap()
}
}
pub struct Runner<'a> {
ch: ch::Runner<'a, MTU>,
state: &'a RefCell<StateInner>,
close_signal: &'a Signal<CriticalSectionRawMutex, bool>,
}
impl<'a> Runner<'a> {
pub async fn run(mut self) -> ! {
let mut previous_state = LinkState::Down;
loop {
let (state_chan, mut rx_chan, mut tx_chan) = self.ch.borrow_split();
let net_socket = self.state.borrow_mut().net_socket.take();
let mut rx_buf = [0; 2048];
let token: crate::CancellationToken = Default::default();
if let Some(socket) = net_socket {
if previous_state == LinkState::Down {
state_chan.set_link_state(LinkState::Up);
previous_state = LinkState::Up;
}
let rx_fut = async {
let size = socket
.receive_with_cancellation(&mut rx_buf, &token)
.await
.unwrap();
let buf = rx_chan.rx_buf().await;
(size, buf)
};
let tx_fut = tx_chan.tx_buf();
match select3(rx_fut, tx_fut, self.close_signal.wait()).await {
Either3::First((size, buf)) => {
if size > 0 {
buf[..size].copy_from_slice(&rx_buf[..size]);
rx_chan.rx_done(size);
}
self.state.borrow_mut().net_socket.replace(socket);
}
Either3::Second(buf) => {
let size = buf.len();
let mut remaining = size;
while remaining > 0 {
let size = socket
.write_with_cancellation(&buf[size - remaining..], &token)
.await
.unwrap();
remaining -= size;
}
tx_chan.tx_done();
self.state.borrow_mut().net_socket.replace(socket);
}
Either3::Third(_) => {
let _ = socket.deactivate().await;
}
}
} else {
state_chan.set_link_state(LinkState::Down);
previous_state = LinkState::Down;
Timer::after_millis(100).await
}
}
}
}