net: split driver trait to a separate crate.
This commit is contained in:
@ -15,7 +15,7 @@ target = "thumbv7em-none-eabi"
|
||||
default = []
|
||||
std = []
|
||||
|
||||
defmt = ["dep:defmt", "smoltcp/defmt"]
|
||||
defmt = ["dep:defmt", "smoltcp/defmt", "embassy-net-driver/defmt"]
|
||||
|
||||
nightly = ["dep:embedded-io", "embedded-io?/async", "dep:embedded-nal-async"]
|
||||
unstable-traits = []
|
||||
@ -33,6 +33,7 @@ medium-ip = ["smoltcp/medium-ip"]
|
||||
defmt = { version = "0.3", optional = true }
|
||||
log = { version = "0.4.14", optional = true }
|
||||
|
||||
embassy-net-driver = { version = "0.1.0", path = "../embassy-net-driver" }
|
||||
embassy-time = { version = "0.1.0", path = "../embassy-time" }
|
||||
embassy-sync = { version = "0.1.0", path = "../embassy-sync" }
|
||||
embedded-io = { version = "0.4.0", optional = true }
|
||||
|
@ -1,93 +1,20 @@
|
||||
use core::task::Context;
|
||||
|
||||
use embassy_net_driver::{Capabilities, Checksum, Driver, Medium, RxToken, TxToken};
|
||||
use smoltcp::phy;
|
||||
pub use smoltcp::phy::{Checksum, ChecksumCapabilities, DeviceCapabilities, Medium};
|
||||
|
||||
#[derive(PartialEq, Eq, Clone, Copy)]
|
||||
pub enum LinkState {
|
||||
Down,
|
||||
Up,
|
||||
}
|
||||
|
||||
pub trait Device {
|
||||
type RxToken<'a>: RxToken
|
||||
where
|
||||
Self: 'a;
|
||||
type TxToken<'a>: TxToken
|
||||
where
|
||||
Self: 'a;
|
||||
|
||||
fn receive(&mut self, cx: &mut Context) -> Option<(Self::RxToken<'_>, Self::TxToken<'_>)>;
|
||||
fn transmit(&mut self, cx: &mut Context) -> Option<Self::TxToken<'_>>;
|
||||
fn link_state(&mut self, cx: &mut Context) -> LinkState;
|
||||
|
||||
fn capabilities(&self) -> phy::DeviceCapabilities;
|
||||
fn ethernet_address(&self) -> [u8; 6];
|
||||
}
|
||||
|
||||
impl<T: ?Sized + Device> Device for &mut T {
|
||||
type RxToken<'a> = T::RxToken<'a>
|
||||
where
|
||||
Self: 'a;
|
||||
type TxToken<'a> = T::TxToken<'a>
|
||||
where
|
||||
Self: 'a;
|
||||
|
||||
fn transmit(&mut self, cx: &mut Context) -> Option<Self::TxToken<'_>> {
|
||||
T::transmit(self, cx)
|
||||
}
|
||||
fn receive(&mut self, cx: &mut Context) -> Option<(Self::RxToken<'_>, Self::TxToken<'_>)> {
|
||||
T::receive(self, cx)
|
||||
}
|
||||
fn capabilities(&self) -> phy::DeviceCapabilities {
|
||||
T::capabilities(self)
|
||||
}
|
||||
fn link_state(&mut self, cx: &mut Context) -> LinkState {
|
||||
T::link_state(self, cx)
|
||||
}
|
||||
fn ethernet_address(&self) -> [u8; 6] {
|
||||
T::ethernet_address(self)
|
||||
}
|
||||
}
|
||||
|
||||
/// A token to receive a single network packet.
|
||||
pub trait RxToken {
|
||||
/// Consumes the token to receive a single network packet.
|
||||
///
|
||||
/// This method receives a packet and then calls the given closure `f` with the raw
|
||||
/// packet bytes as argument.
|
||||
fn consume<R, F>(self, f: F) -> R
|
||||
where
|
||||
F: FnOnce(&mut [u8]) -> R;
|
||||
}
|
||||
|
||||
/// A token to transmit a single network packet.
|
||||
pub trait TxToken {
|
||||
/// Consumes the token to send a single network packet.
|
||||
///
|
||||
/// This method constructs a transmit buffer of size `len` and calls the passed
|
||||
/// closure `f` with a mutable reference to that buffer. The closure should construct
|
||||
/// a valid network packet (e.g. an ethernet packet) in the buffer. When the closure
|
||||
/// returns, the transmit buffer is sent out.
|
||||
fn consume<R, F>(self, len: usize, f: F) -> R
|
||||
where
|
||||
F: FnOnce(&mut [u8]) -> R;
|
||||
}
|
||||
|
||||
///////////////////////////
|
||||
|
||||
pub(crate) struct DeviceAdapter<'d, 'c, T>
|
||||
pub(crate) struct DriverAdapter<'d, 'c, T>
|
||||
where
|
||||
T: Device,
|
||||
T: Driver,
|
||||
{
|
||||
// must be Some when actually using this to rx/tx
|
||||
pub cx: Option<&'d mut Context<'c>>,
|
||||
pub inner: &'d mut T,
|
||||
}
|
||||
|
||||
impl<'d, 'c, T> phy::Device for DeviceAdapter<'d, 'c, T>
|
||||
impl<'d, 'c, T> phy::Device for DriverAdapter<'d, 'c, T>
|
||||
where
|
||||
T: Device,
|
||||
T: Driver,
|
||||
{
|
||||
type RxToken<'a> = RxTokenAdapter<T::RxToken<'a>> where Self: 'a;
|
||||
type TxToken<'a> = TxTokenAdapter<T::TxToken<'a>> where Self: 'a;
|
||||
@ -105,7 +32,39 @@ where
|
||||
|
||||
/// Get a description of device capabilities.
|
||||
fn capabilities(&self) -> phy::DeviceCapabilities {
|
||||
self.inner.capabilities()
|
||||
fn convert(c: Checksum) -> phy::Checksum {
|
||||
match c {
|
||||
Checksum::Both => phy::Checksum::Both,
|
||||
Checksum::Tx => phy::Checksum::Tx,
|
||||
Checksum::Rx => phy::Checksum::Rx,
|
||||
Checksum::None => phy::Checksum::None,
|
||||
}
|
||||
}
|
||||
let caps: Capabilities = self.inner.capabilities();
|
||||
let mut smolcaps = phy::DeviceCapabilities::default();
|
||||
|
||||
smolcaps.max_transmission_unit = caps.max_transmission_unit;
|
||||
smolcaps.max_burst_size = caps.max_burst_size;
|
||||
smolcaps.medium = match caps.medium {
|
||||
#[cfg(feature = "medium-ethernet")]
|
||||
Medium::Ethernet => phy::Medium::Ethernet,
|
||||
#[cfg(feature = "medium-ip")]
|
||||
Medium::Ip => phy::Medium::Ip,
|
||||
_ => panic!(
|
||||
"Unsupported medium {:?}. MAke sure to enable it in embassy-net's Cargo features.",
|
||||
caps.medium
|
||||
),
|
||||
};
|
||||
smolcaps.checksum.ipv4 = convert(caps.checksum.ipv4);
|
||||
#[cfg(feature = "proto-ipv6")]
|
||||
{
|
||||
smolcaps.checksum.ipv6 = convert(caps.checksum.ipv6);
|
||||
}
|
||||
smolcaps.checksum.tcp = convert(caps.checksum.tcp);
|
||||
smolcaps.checksum.udp = convert(caps.checksum.udp);
|
||||
smolcaps.checksum.icmpv4 = convert(caps.checksum.icmpv4);
|
||||
|
||||
smolcaps
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -18,6 +18,7 @@ use core::cell::RefCell;
|
||||
use core::future::{poll_fn, Future};
|
||||
use core::task::{Context, Poll};
|
||||
|
||||
use embassy_net_driver::{Driver, LinkState, Medium};
|
||||
use embassy_sync::waitqueue::WakerRegistration;
|
||||
use embassy_time::{Instant, Timer};
|
||||
use futures::pin_mut;
|
||||
@ -27,8 +28,6 @@ use smoltcp::iface::SocketHandle;
|
||||
use smoltcp::iface::{Interface, InterfaceBuilder, SocketSet, SocketStorage};
|
||||
#[cfg(feature = "medium-ethernet")]
|
||||
use smoltcp::iface::{Neighbor, NeighborCache, Route, Routes};
|
||||
#[cfg(feature = "medium-ethernet")]
|
||||
use smoltcp::phy::Medium;
|
||||
#[cfg(feature = "dhcpv4")]
|
||||
use smoltcp::socket::dhcpv4;
|
||||
// smoltcp reexports
|
||||
@ -41,7 +40,7 @@ pub use smoltcp::wire::{Ipv6Address, Ipv6Cidr};
|
||||
#[cfg(feature = "udp")]
|
||||
pub use smoltcp::{socket::udp::PacketMetadata, wire::IpListenEndpoint};
|
||||
|
||||
use crate::device::{Device, DeviceAdapter, LinkState};
|
||||
use crate::device::DriverAdapter;
|
||||
|
||||
const LOCAL_PORT_MIN: u16 = 1025;
|
||||
const LOCAL_PORT_MAX: u16 = 65535;
|
||||
@ -82,12 +81,12 @@ pub enum ConfigStrategy {
|
||||
Dhcp,
|
||||
}
|
||||
|
||||
pub struct Stack<D: Device> {
|
||||
pub struct Stack<D: Driver> {
|
||||
pub(crate) socket: RefCell<SocketStack>,
|
||||
inner: RefCell<Inner<D>>,
|
||||
}
|
||||
|
||||
struct Inner<D: Device> {
|
||||
struct Inner<D: Driver> {
|
||||
device: D,
|
||||
link_up: bool,
|
||||
config: Option<Config>,
|
||||
@ -102,7 +101,7 @@ pub(crate) struct SocketStack {
|
||||
next_local_port: u16,
|
||||
}
|
||||
|
||||
impl<D: Device + 'static> Stack<D> {
|
||||
impl<D: Driver + 'static> Stack<D> {
|
||||
pub fn new<const ADDR: usize, const SOCK: usize, const NEIGH: usize>(
|
||||
mut device: D,
|
||||
config: ConfigStrategy,
|
||||
@ -130,7 +129,7 @@ impl<D: Device + 'static> Stack<D> {
|
||||
b = b.routes(Routes::new(&mut resources.routes[..]));
|
||||
}
|
||||
|
||||
let iface = b.finalize(&mut DeviceAdapter {
|
||||
let iface = b.finalize(&mut DriverAdapter {
|
||||
inner: &mut device,
|
||||
cx: None,
|
||||
});
|
||||
@ -211,7 +210,7 @@ impl SocketStack {
|
||||
}
|
||||
}
|
||||
|
||||
impl<D: Device + 'static> Inner<D> {
|
||||
impl<D: Driver + 'static> Inner<D> {
|
||||
fn apply_config(&mut self, s: &mut SocketStack, config: Config) {
|
||||
#[cfg(feature = "medium-ethernet")]
|
||||
let medium = self.device.capabilities().medium;
|
||||
@ -263,7 +262,7 @@ impl<D: Device + 'static> Inner<D> {
|
||||
s.waker.register(cx.waker());
|
||||
|
||||
let timestamp = instant_to_smoltcp(Instant::now());
|
||||
let mut smoldev = DeviceAdapter {
|
||||
let mut smoldev = DriverAdapter {
|
||||
cx: Some(cx),
|
||||
inner: &mut self.device,
|
||||
};
|
||||
|
@ -3,12 +3,12 @@ use core::future::poll_fn;
|
||||
use core::mem;
|
||||
use core::task::Poll;
|
||||
|
||||
use embassy_net_driver::Driver;
|
||||
use smoltcp::iface::{Interface, SocketHandle};
|
||||
use smoltcp::socket::tcp;
|
||||
use smoltcp::time::Duration;
|
||||
use smoltcp::wire::{IpEndpoint, IpListenEndpoint};
|
||||
|
||||
use crate::device::Device;
|
||||
use crate::{SocketStack, Stack};
|
||||
|
||||
#[derive(PartialEq, Eq, Clone, Copy, Debug)]
|
||||
@ -66,7 +66,7 @@ impl<'a> TcpWriter<'a> {
|
||||
}
|
||||
|
||||
impl<'a> TcpSocket<'a> {
|
||||
pub fn new<D: Device>(stack: &'a Stack<D>, rx_buffer: &'a mut [u8], tx_buffer: &'a mut [u8]) -> Self {
|
||||
pub fn new<D: Driver>(stack: &'a Stack<D>, rx_buffer: &'a mut [u8], tx_buffer: &'a mut [u8]) -> Self {
|
||||
let s = &mut *stack.socket.borrow_mut();
|
||||
let rx_buffer: &'static mut [u8] = unsafe { mem::transmute(rx_buffer) };
|
||||
let tx_buffer: &'static mut [u8] = unsafe { mem::transmute(tx_buffer) };
|
||||
@ -336,19 +336,19 @@ pub mod client {
|
||||
use super::*;
|
||||
|
||||
/// TCP client capable of creating up to N multiple connections with tx and rx buffers according to TX_SZ and RX_SZ.
|
||||
pub struct TcpClient<'d, D: Device, const N: usize, const TX_SZ: usize = 1024, const RX_SZ: usize = 1024> {
|
||||
pub struct TcpClient<'d, D: Driver, const N: usize, const TX_SZ: usize = 1024, const RX_SZ: usize = 1024> {
|
||||
stack: &'d Stack<D>,
|
||||
state: &'d TcpClientState<N, TX_SZ, RX_SZ>,
|
||||
}
|
||||
|
||||
impl<'d, D: Device, const N: usize, const TX_SZ: usize, const RX_SZ: usize> TcpClient<'d, D, N, TX_SZ, RX_SZ> {
|
||||
impl<'d, D: Driver, const N: usize, const TX_SZ: usize, const RX_SZ: usize> TcpClient<'d, D, N, TX_SZ, RX_SZ> {
|
||||
/// Create a new TcpClient
|
||||
pub fn new(stack: &'d Stack<D>, state: &'d TcpClientState<N, TX_SZ, RX_SZ>) -> Self {
|
||||
Self { stack, state }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'d, D: Device, const N: usize, const TX_SZ: usize, const RX_SZ: usize> embedded_nal_async::TcpConnect
|
||||
impl<'d, D: Driver, const N: usize, const TX_SZ: usize, const RX_SZ: usize> embedded_nal_async::TcpConnect
|
||||
for TcpClient<'d, D, N, TX_SZ, RX_SZ>
|
||||
{
|
||||
type Error = Error;
|
||||
@ -386,7 +386,7 @@ pub mod client {
|
||||
}
|
||||
|
||||
impl<'d, const N: usize, const TX_SZ: usize, const RX_SZ: usize> TcpConnection<'d, N, TX_SZ, RX_SZ> {
|
||||
fn new<D: Device>(stack: &'d Stack<D>, state: &'d TcpClientState<N, TX_SZ, RX_SZ>) -> Result<Self, Error> {
|
||||
fn new<D: Driver>(stack: &'d Stack<D>, state: &'d TcpClientState<N, TX_SZ, RX_SZ>) -> Result<Self, Error> {
|
||||
let mut bufs = state.pool.alloc().ok_or(Error::ConnectionReset)?;
|
||||
Ok(Self {
|
||||
socket: unsafe { TcpSocket::new(stack, &mut bufs.as_mut().0, &mut bufs.as_mut().1) },
|
||||
|
@ -3,11 +3,12 @@ use core::future::poll_fn;
|
||||
use core::mem;
|
||||
use core::task::Poll;
|
||||
|
||||
use embassy_net_driver::Driver;
|
||||
use smoltcp::iface::{Interface, SocketHandle};
|
||||
use smoltcp::socket::udp::{self, PacketMetadata};
|
||||
use smoltcp::wire::{IpEndpoint, IpListenEndpoint};
|
||||
|
||||
use crate::{Device, SocketStack, Stack};
|
||||
use crate::{SocketStack, Stack};
|
||||
|
||||
#[derive(PartialEq, Eq, Clone, Copy, Debug)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
@ -31,7 +32,7 @@ pub struct UdpSocket<'a> {
|
||||
}
|
||||
|
||||
impl<'a> UdpSocket<'a> {
|
||||
pub fn new<D: Device>(
|
||||
pub fn new<D: Driver>(
|
||||
stack: &'a Stack<D>,
|
||||
rx_meta: &'a mut [PacketMetadata],
|
||||
rx_buffer: &'a mut [u8],
|
||||
|
Reference in New Issue
Block a user