mirror of
https://github.com/embassy-rs/embassy.git
synced 2024-11-26 08:42:32 +00:00
Merge pull request #1129 from embassy-rs/net-driver
net: driver crate split
This commit is contained in:
commit
147609d3bd
1
.github/workflows/doc.yml
vendored
1
.github/workflows/doc.yml
vendored
@ -69,6 +69,7 @@ jobs:
|
|||||||
builder ./embassy-futures crates/embassy-futures/git.zup
|
builder ./embassy-futures crates/embassy-futures/git.zup
|
||||||
builder ./embassy-lora crates/embassy-lora/git.zup
|
builder ./embassy-lora crates/embassy-lora/git.zup
|
||||||
builder ./embassy-net crates/embassy-net/git.zup
|
builder ./embassy-net crates/embassy-net/git.zup
|
||||||
|
builder ./embassy-net-driver crates/embassy-net-driver/git.zup
|
||||||
builder ./embassy-nrf crates/embassy-nrf/git.zup
|
builder ./embassy-nrf crates/embassy-nrf/git.zup
|
||||||
builder ./embassy-rp crates/embassy-rp/git.zup
|
builder ./embassy-rp crates/embassy-rp/git.zup
|
||||||
builder ./embassy-sync crates/embassy-sync/git.zup
|
builder ./embassy-sync crates/embassy-sync/git.zup
|
||||||
|
23
.vscode/settings.json
vendored
23
.vscode/settings.json
vendored
@ -4,28 +4,21 @@
|
|||||||
"rust-analyzer.checkOnSave.noDefaultFeatures": true,
|
"rust-analyzer.checkOnSave.noDefaultFeatures": true,
|
||||||
"rust-analyzer.cargo.noDefaultFeatures": true,
|
"rust-analyzer.cargo.noDefaultFeatures": true,
|
||||||
"rust-analyzer.procMacro.enable": true,
|
"rust-analyzer.procMacro.enable": true,
|
||||||
//"rust-analyzer.cargo.target": "thumbv7em-none-eabi",
|
"rust-analyzer.cargo.target": "thumbv7em-none-eabi",
|
||||||
"rust-analyzer.cargo.target": "thumbv8m.main-none-eabihf",
|
//"rust-analyzer.cargo.target": "thumbv8m.main-none-eabihf",
|
||||||
"rust-analyzer.cargo.features": [
|
"rust-analyzer.cargo.features": [
|
||||||
// These are needed to prevent embassy-net from failing to build
|
"nightly",
|
||||||
//"embassy-net/medium-ethernet",
|
|
||||||
//"embassy-net/tcp",
|
|
||||||
//"embassy-net/pool-16",
|
|
||||||
//"time-tick-16mhz",
|
|
||||||
//"defmt-timestamp-uptime",
|
|
||||||
//"nightly",
|
|
||||||
//"unstable-traits",
|
|
||||||
],
|
],
|
||||||
"rust-analyzer.linkedProjects": [
|
"rust-analyzer.linkedProjects": [
|
||||||
// Declare for the target you wish to develop
|
// Declare for the target you wish to develop
|
||||||
//"embassy-executor/Cargo.toml",
|
// "embassy-executor/Cargo.toml",
|
||||||
//"embassy-sync/Cargo.toml",
|
// "embassy-sync/Cargo.toml",
|
||||||
//"examples/nrf/Cargo.toml",
|
"examples/nrf/Cargo.toml",
|
||||||
// "examples/nrf-rtos-trace/Cargo.toml",
|
// "examples/nrf-rtos-trace/Cargo.toml",
|
||||||
// "examples/rp/Cargo.toml",
|
// "examples/rp/Cargo.toml",
|
||||||
// "examples/std/Cargo.toml",
|
// "examples/std/Cargo.toml",
|
||||||
// "examples/stm32f0/Cargo.toml",
|
// "examples/stm32f0/Cargo.toml",
|
||||||
//"examples/stm32f1/Cargo.toml",
|
// "examples/stm32f1/Cargo.toml",
|
||||||
// "examples/stm32f2/Cargo.toml",
|
// "examples/stm32f2/Cargo.toml",
|
||||||
// "examples/stm32f3/Cargo.toml",
|
// "examples/stm32f3/Cargo.toml",
|
||||||
// "examples/stm32f4/Cargo.toml",
|
// "examples/stm32f4/Cargo.toml",
|
||||||
@ -36,7 +29,7 @@
|
|||||||
// "examples/stm32l0/Cargo.toml",
|
// "examples/stm32l0/Cargo.toml",
|
||||||
// "examples/stm32l1/Cargo.toml",
|
// "examples/stm32l1/Cargo.toml",
|
||||||
// "examples/stm32l4/Cargo.toml",
|
// "examples/stm32l4/Cargo.toml",
|
||||||
"examples/stm32l5/Cargo.toml",
|
// "examples/stm32l5/Cargo.toml",
|
||||||
// "examples/stm32u5/Cargo.toml",
|
// "examples/stm32u5/Cargo.toml",
|
||||||
// "examples/stm32wb/Cargo.toml",
|
// "examples/stm32wb/Cargo.toml",
|
||||||
// "examples/stm32wb55/Cargo.toml",
|
// "examples/stm32wb55/Cargo.toml",
|
||||||
|
8
ci.sh
8
ci.sh
@ -38,10 +38,10 @@ cargo batch \
|
|||||||
--- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv6m-none-eabi --features nightly,defmt \
|
--- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv6m-none-eabi --features nightly,defmt \
|
||||||
--- build --release --manifest-path embassy-sync/Cargo.toml --target thumbv6m-none-eabi --features nightly,defmt \
|
--- build --release --manifest-path embassy-sync/Cargo.toml --target thumbv6m-none-eabi --features nightly,defmt \
|
||||||
--- build --release --manifest-path embassy-time/Cargo.toml --target thumbv6m-none-eabi --features nightly,unstable-traits,defmt,defmt-timestamp-uptime,tick-hz-32_768,generic-queue-8 \
|
--- build --release --manifest-path embassy-time/Cargo.toml --target thumbv6m-none-eabi --features nightly,unstable-traits,defmt,defmt-timestamp-uptime,tick-hz-32_768,generic-queue-8 \
|
||||||
--- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,dhcpv4,medium-ethernet,pool-16 \
|
--- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,dhcpv4,medium-ethernet \
|
||||||
--- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,dhcpv4,medium-ethernet,pool-16,unstable-traits \
|
--- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,dhcpv4,medium-ethernet,unstable-traits \
|
||||||
--- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,dhcpv4,medium-ethernet,pool-16,nightly \
|
--- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,dhcpv4,medium-ethernet,nightly \
|
||||||
--- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,dhcpv4,medium-ethernet,pool-16,unstable-traits,nightly \
|
--- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,dhcpv4,medium-ethernet,unstable-traits,nightly \
|
||||||
--- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv7em-none-eabi --features nightly,nrf52805,gpiote,time-driver-rtc1 \
|
--- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv7em-none-eabi --features nightly,nrf52805,gpiote,time-driver-rtc1 \
|
||||||
--- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv7em-none-eabi --features nightly,nrf52810,gpiote,time-driver-rtc1 \
|
--- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv7em-none-eabi --features nightly,nrf52810,gpiote,time-driver-rtc1 \
|
||||||
--- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv7em-none-eabi --features nightly,nrf52811,gpiote,time-driver-rtc1 \
|
--- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv7em-none-eabi --features nightly,nrf52811,gpiote,time-driver-rtc1 \
|
||||||
|
@ -13,8 +13,8 @@ cargo batch \
|
|||||||
--- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features log \
|
--- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features log \
|
||||||
--- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features defmt \
|
--- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features defmt \
|
||||||
--- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv6m-none-eabi --features defmt \
|
--- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv6m-none-eabi --features defmt \
|
||||||
--- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,dhcpv4,medium-ethernet,pool-16 \
|
--- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,dhcpv4,medium-ethernet \
|
||||||
--- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,dhcpv4,medium-ethernet,pool-16,unstable-traits \
|
--- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,dhcpv4,medium-ethernet,unstable-traits \
|
||||||
--- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv7em-none-eabi --features nrf52805,gpiote,time-driver-rtc1 \
|
--- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv7em-none-eabi --features nrf52805,gpiote,time-driver-rtc1 \
|
||||||
--- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv7em-none-eabi --features nrf52810,gpiote,time-driver-rtc1 \
|
--- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv7em-none-eabi --features nrf52810,gpiote,time-driver-rtc1 \
|
||||||
--- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv7em-none-eabi --features nrf52811,gpiote,time-driver-rtc1 \
|
--- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv7em-none-eabi --features nrf52811,gpiote,time-driver-rtc1 \
|
||||||
|
12
embassy-net-driver-channel/Cargo.toml
Normal file
12
embassy-net-driver-channel/Cargo.toml
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
[package]
|
||||||
|
name = "embassy-net-driver-channel"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
defmt = { version = "0.3", optional = true }
|
||||||
|
log = { version = "0.4.14", optional = true }
|
||||||
|
|
||||||
|
embassy-sync = { version = "0.1.0", path = "../embassy-sync" }
|
||||||
|
embassy-futures = { version = "0.1.0", path = "../embassy-futures" }
|
||||||
|
embassy-net-driver = { version = "0.1.0", path = "../embassy-net-driver" }
|
225
embassy-net-driver-channel/src/fmt.rs
Normal file
225
embassy-net-driver-channel/src/fmt.rs
Normal file
@ -0,0 +1,225 @@
|
|||||||
|
#![macro_use]
|
||||||
|
#![allow(unused_macros)]
|
||||||
|
|
||||||
|
#[cfg(all(feature = "defmt", feature = "log"))]
|
||||||
|
compile_error!("You may not enable both `defmt` and `log` features.");
|
||||||
|
|
||||||
|
macro_rules! assert {
|
||||||
|
($($x:tt)*) => {
|
||||||
|
{
|
||||||
|
#[cfg(not(feature = "defmt"))]
|
||||||
|
::core::assert!($($x)*);
|
||||||
|
#[cfg(feature = "defmt")]
|
||||||
|
::defmt::assert!($($x)*);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! assert_eq {
|
||||||
|
($($x:tt)*) => {
|
||||||
|
{
|
||||||
|
#[cfg(not(feature = "defmt"))]
|
||||||
|
::core::assert_eq!($($x)*);
|
||||||
|
#[cfg(feature = "defmt")]
|
||||||
|
::defmt::assert_eq!($($x)*);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! assert_ne {
|
||||||
|
($($x:tt)*) => {
|
||||||
|
{
|
||||||
|
#[cfg(not(feature = "defmt"))]
|
||||||
|
::core::assert_ne!($($x)*);
|
||||||
|
#[cfg(feature = "defmt")]
|
||||||
|
::defmt::assert_ne!($($x)*);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! debug_assert {
|
||||||
|
($($x:tt)*) => {
|
||||||
|
{
|
||||||
|
#[cfg(not(feature = "defmt"))]
|
||||||
|
::core::debug_assert!($($x)*);
|
||||||
|
#[cfg(feature = "defmt")]
|
||||||
|
::defmt::debug_assert!($($x)*);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! debug_assert_eq {
|
||||||
|
($($x:tt)*) => {
|
||||||
|
{
|
||||||
|
#[cfg(not(feature = "defmt"))]
|
||||||
|
::core::debug_assert_eq!($($x)*);
|
||||||
|
#[cfg(feature = "defmt")]
|
||||||
|
::defmt::debug_assert_eq!($($x)*);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! debug_assert_ne {
|
||||||
|
($($x:tt)*) => {
|
||||||
|
{
|
||||||
|
#[cfg(not(feature = "defmt"))]
|
||||||
|
::core::debug_assert_ne!($($x)*);
|
||||||
|
#[cfg(feature = "defmt")]
|
||||||
|
::defmt::debug_assert_ne!($($x)*);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! todo {
|
||||||
|
($($x:tt)*) => {
|
||||||
|
{
|
||||||
|
#[cfg(not(feature = "defmt"))]
|
||||||
|
::core::todo!($($x)*);
|
||||||
|
#[cfg(feature = "defmt")]
|
||||||
|
::defmt::todo!($($x)*);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! unreachable {
|
||||||
|
($($x:tt)*) => {
|
||||||
|
{
|
||||||
|
#[cfg(not(feature = "defmt"))]
|
||||||
|
::core::unreachable!($($x)*);
|
||||||
|
#[cfg(feature = "defmt")]
|
||||||
|
::defmt::unreachable!($($x)*);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! panic {
|
||||||
|
($($x:tt)*) => {
|
||||||
|
{
|
||||||
|
#[cfg(not(feature = "defmt"))]
|
||||||
|
::core::panic!($($x)*);
|
||||||
|
#[cfg(feature = "defmt")]
|
||||||
|
::defmt::panic!($($x)*);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! trace {
|
||||||
|
($s:literal $(, $x:expr)* $(,)?) => {
|
||||||
|
{
|
||||||
|
#[cfg(feature = "log")]
|
||||||
|
::log::trace!($s $(, $x)*);
|
||||||
|
#[cfg(feature = "defmt")]
|
||||||
|
::defmt::trace!($s $(, $x)*);
|
||||||
|
#[cfg(not(any(feature = "log", feature="defmt")))]
|
||||||
|
let _ = ($( & $x ),*);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! debug {
|
||||||
|
($s:literal $(, $x:expr)* $(,)?) => {
|
||||||
|
{
|
||||||
|
#[cfg(feature = "log")]
|
||||||
|
::log::debug!($s $(, $x)*);
|
||||||
|
#[cfg(feature = "defmt")]
|
||||||
|
::defmt::debug!($s $(, $x)*);
|
||||||
|
#[cfg(not(any(feature = "log", feature="defmt")))]
|
||||||
|
let _ = ($( & $x ),*);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! info {
|
||||||
|
($s:literal $(, $x:expr)* $(,)?) => {
|
||||||
|
{
|
||||||
|
#[cfg(feature = "log")]
|
||||||
|
::log::info!($s $(, $x)*);
|
||||||
|
#[cfg(feature = "defmt")]
|
||||||
|
::defmt::info!($s $(, $x)*);
|
||||||
|
#[cfg(not(any(feature = "log", feature="defmt")))]
|
||||||
|
let _ = ($( & $x ),*);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! warn {
|
||||||
|
($s:literal $(, $x:expr)* $(,)?) => {
|
||||||
|
{
|
||||||
|
#[cfg(feature = "log")]
|
||||||
|
::log::warn!($s $(, $x)*);
|
||||||
|
#[cfg(feature = "defmt")]
|
||||||
|
::defmt::warn!($s $(, $x)*);
|
||||||
|
#[cfg(not(any(feature = "log", feature="defmt")))]
|
||||||
|
let _ = ($( & $x ),*);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! error {
|
||||||
|
($s:literal $(, $x:expr)* $(,)?) => {
|
||||||
|
{
|
||||||
|
#[cfg(feature = "log")]
|
||||||
|
::log::error!($s $(, $x)*);
|
||||||
|
#[cfg(feature = "defmt")]
|
||||||
|
::defmt::error!($s $(, $x)*);
|
||||||
|
#[cfg(not(any(feature = "log", feature="defmt")))]
|
||||||
|
let _ = ($( & $x ),*);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "defmt")]
|
||||||
|
macro_rules! unwrap {
|
||||||
|
($($x:tt)*) => {
|
||||||
|
::defmt::unwrap!($($x)*)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(feature = "defmt"))]
|
||||||
|
macro_rules! unwrap {
|
||||||
|
($arg:expr) => {
|
||||||
|
match $crate::fmt::Try::into_result($arg) {
|
||||||
|
::core::result::Result::Ok(t) => t,
|
||||||
|
::core::result::Result::Err(e) => {
|
||||||
|
::core::panic!("unwrap of `{}` failed: {:?}", ::core::stringify!($arg), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
($arg:expr, $($msg:expr),+ $(,)? ) => {
|
||||||
|
match $crate::fmt::Try::into_result($arg) {
|
||||||
|
::core::result::Result::Ok(t) => t,
|
||||||
|
::core::result::Result::Err(e) => {
|
||||||
|
::core::panic!("unwrap of `{}` failed: {}: {:?}", ::core::stringify!($arg), ::core::format_args!($($msg,)*), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
|
||||||
|
pub struct NoneError;
|
||||||
|
|
||||||
|
pub trait Try {
|
||||||
|
type Ok;
|
||||||
|
type Error;
|
||||||
|
fn into_result(self) -> Result<Self::Ok, Self::Error>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> Try for Option<T> {
|
||||||
|
type Ok = T;
|
||||||
|
type Error = NoneError;
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn into_result(self) -> Result<T, NoneError> {
|
||||||
|
self.ok_or(NoneError)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T, E> Try for Result<T, E> {
|
||||||
|
type Ok = T;
|
||||||
|
type Error = E;
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn into_result(self) -> Self {
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
525
embassy-net-driver-channel/src/lib.rs
Normal file
525
embassy-net-driver-channel/src/lib.rs
Normal file
@ -0,0 +1,525 @@
|
|||||||
|
#![no_std]
|
||||||
|
|
||||||
|
// must go first!
|
||||||
|
mod fmt;
|
||||||
|
|
||||||
|
use core::cell::RefCell;
|
||||||
|
use core::mem::MaybeUninit;
|
||||||
|
use core::task::{Context, Poll};
|
||||||
|
|
||||||
|
pub use embassy_net_driver as driver;
|
||||||
|
use embassy_net_driver::{Capabilities, LinkState, Medium};
|
||||||
|
use embassy_sync::blocking_mutex::raw::NoopRawMutex;
|
||||||
|
use embassy_sync::blocking_mutex::Mutex;
|
||||||
|
use embassy_sync::waitqueue::WakerRegistration;
|
||||||
|
|
||||||
|
pub struct State<const MTU: usize, const N_RX: usize, const N_TX: usize> {
|
||||||
|
rx: [PacketBuf<MTU>; N_RX],
|
||||||
|
tx: [PacketBuf<MTU>; N_TX],
|
||||||
|
inner: MaybeUninit<StateInner<'static, MTU>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<const MTU: usize, const N_RX: usize, const N_TX: usize> State<MTU, N_RX, N_TX> {
|
||||||
|
const NEW_PACKET: PacketBuf<MTU> = PacketBuf::new();
|
||||||
|
|
||||||
|
pub const fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
rx: [Self::NEW_PACKET; N_RX],
|
||||||
|
tx: [Self::NEW_PACKET; N_TX],
|
||||||
|
inner: MaybeUninit::uninit(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct StateInner<'d, const MTU: usize> {
|
||||||
|
rx: zerocopy_channel::Channel<'d, NoopRawMutex, PacketBuf<MTU>>,
|
||||||
|
tx: zerocopy_channel::Channel<'d, NoopRawMutex, PacketBuf<MTU>>,
|
||||||
|
link_state: Mutex<NoopRawMutex, RefCell<LinkStateState>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// State of the LinkState
|
||||||
|
struct LinkStateState {
|
||||||
|
state: LinkState,
|
||||||
|
waker: WakerRegistration,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Runner<'d, const MTU: usize> {
|
||||||
|
tx_chan: zerocopy_channel::Receiver<'d, NoopRawMutex, PacketBuf<MTU>>,
|
||||||
|
rx_chan: zerocopy_channel::Sender<'d, NoopRawMutex, PacketBuf<MTU>>,
|
||||||
|
link_state: &'d Mutex<NoopRawMutex, RefCell<LinkStateState>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct RxRunner<'d, const MTU: usize> {
|
||||||
|
rx_chan: zerocopy_channel::Sender<'d, NoopRawMutex, PacketBuf<MTU>>,
|
||||||
|
link_state: &'d Mutex<NoopRawMutex, RefCell<LinkStateState>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct TxRunner<'d, const MTU: usize> {
|
||||||
|
tx_chan: zerocopy_channel::Receiver<'d, NoopRawMutex, PacketBuf<MTU>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'d, const MTU: usize> Runner<'d, MTU> {
|
||||||
|
pub fn split(self) -> (RxRunner<'d, MTU>, TxRunner<'d, MTU>) {
|
||||||
|
(
|
||||||
|
RxRunner {
|
||||||
|
link_state: self.link_state,
|
||||||
|
rx_chan: self.rx_chan,
|
||||||
|
},
|
||||||
|
TxRunner { tx_chan: self.tx_chan },
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_link_state(&mut self, state: LinkState) {
|
||||||
|
self.link_state.lock(|s| {
|
||||||
|
let s = &mut *s.borrow_mut();
|
||||||
|
s.state = state;
|
||||||
|
s.waker.wake();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn rx_buf(&mut self) -> &mut [u8] {
|
||||||
|
let p = self.rx_chan.send().await;
|
||||||
|
&mut p.buf
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn try_rx_buf(&mut self) -> Option<&mut [u8]> {
|
||||||
|
let p = self.rx_chan.try_send()?;
|
||||||
|
Some(&mut p.buf)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn poll_rx_buf(&mut self, cx: &mut Context) -> Poll<&mut [u8]> {
|
||||||
|
match self.rx_chan.poll_send(cx) {
|
||||||
|
Poll::Ready(p) => Poll::Ready(&mut p.buf),
|
||||||
|
Poll::Pending => Poll::Pending,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn rx_done(&mut self, len: usize) {
|
||||||
|
let p = self.rx_chan.try_send().unwrap();
|
||||||
|
p.len = len;
|
||||||
|
self.rx_chan.send_done();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn tx_buf(&mut self) -> &mut [u8] {
|
||||||
|
let p = self.tx_chan.recv().await;
|
||||||
|
&mut p.buf[..p.len]
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn try_tx_buf(&mut self) -> Option<&mut [u8]> {
|
||||||
|
let p = self.tx_chan.try_recv()?;
|
||||||
|
Some(&mut p.buf[..p.len])
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn poll_tx_buf(&mut self, cx: &mut Context) -> Poll<&mut [u8]> {
|
||||||
|
match self.tx_chan.poll_recv(cx) {
|
||||||
|
Poll::Ready(p) => Poll::Ready(&mut p.buf[..p.len]),
|
||||||
|
Poll::Pending => Poll::Pending,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn tx_done(&mut self) {
|
||||||
|
self.tx_chan.recv_done();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'d, const MTU: usize> RxRunner<'d, MTU> {
|
||||||
|
pub fn set_link_state(&mut self, state: LinkState) {
|
||||||
|
self.link_state.lock(|s| {
|
||||||
|
let s = &mut *s.borrow_mut();
|
||||||
|
s.state = state;
|
||||||
|
s.waker.wake();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn rx_buf(&mut self) -> &mut [u8] {
|
||||||
|
let p = self.rx_chan.send().await;
|
||||||
|
&mut p.buf
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn try_rx_buf(&mut self) -> Option<&mut [u8]> {
|
||||||
|
let p = self.rx_chan.try_send()?;
|
||||||
|
Some(&mut p.buf)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn poll_rx_buf(&mut self, cx: &mut Context) -> Poll<&mut [u8]> {
|
||||||
|
match self.rx_chan.poll_send(cx) {
|
||||||
|
Poll::Ready(p) => Poll::Ready(&mut p.buf),
|
||||||
|
Poll::Pending => Poll::Pending,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn rx_done(&mut self, len: usize) {
|
||||||
|
let p = self.rx_chan.try_send().unwrap();
|
||||||
|
p.len = len;
|
||||||
|
self.rx_chan.send_done();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'d, const MTU: usize> TxRunner<'d, MTU> {
|
||||||
|
pub async fn tx_buf(&mut self) -> &mut [u8] {
|
||||||
|
let p = self.tx_chan.recv().await;
|
||||||
|
&mut p.buf[..p.len]
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn try_tx_buf(&mut self) -> Option<&mut [u8]> {
|
||||||
|
let p = self.tx_chan.try_recv()?;
|
||||||
|
Some(&mut p.buf[..p.len])
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn poll_tx_buf(&mut self, cx: &mut Context) -> Poll<&mut [u8]> {
|
||||||
|
match self.tx_chan.poll_recv(cx) {
|
||||||
|
Poll::Ready(p) => Poll::Ready(&mut p.buf[..p.len]),
|
||||||
|
Poll::Pending => Poll::Pending,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn tx_done(&mut self) {
|
||||||
|
self.tx_chan.recv_done();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn new<'d, const MTU: usize, const N_RX: usize, const N_TX: usize>(
|
||||||
|
state: &'d mut State<MTU, N_RX, N_TX>,
|
||||||
|
ethernet_address: [u8; 6],
|
||||||
|
) -> (Runner<'d, MTU>, Device<'d, MTU>) {
|
||||||
|
let mut caps = Capabilities::default();
|
||||||
|
caps.max_transmission_unit = MTU;
|
||||||
|
caps.medium = Medium::Ethernet;
|
||||||
|
|
||||||
|
// safety: this is a self-referential struct, however:
|
||||||
|
// - it can't move while the `'d` borrow is active.
|
||||||
|
// - when the borrow ends, the dangling references inside the MaybeUninit will never be used again.
|
||||||
|
let state_uninit: *mut MaybeUninit<StateInner<'d, MTU>> =
|
||||||
|
(&mut state.inner as *mut MaybeUninit<StateInner<'static, MTU>>).cast();
|
||||||
|
let state = unsafe { &mut *state_uninit }.write(StateInner {
|
||||||
|
rx: zerocopy_channel::Channel::new(&mut state.rx[..]),
|
||||||
|
tx: zerocopy_channel::Channel::new(&mut state.tx[..]),
|
||||||
|
link_state: Mutex::new(RefCell::new(LinkStateState {
|
||||||
|
state: LinkState::Down,
|
||||||
|
waker: WakerRegistration::new(),
|
||||||
|
})),
|
||||||
|
});
|
||||||
|
|
||||||
|
let (rx_sender, rx_receiver) = state.rx.split();
|
||||||
|
let (tx_sender, tx_receiver) = state.tx.split();
|
||||||
|
|
||||||
|
(
|
||||||
|
Runner {
|
||||||
|
tx_chan: tx_receiver,
|
||||||
|
rx_chan: rx_sender,
|
||||||
|
link_state: &state.link_state,
|
||||||
|
},
|
||||||
|
Device {
|
||||||
|
caps,
|
||||||
|
ethernet_address,
|
||||||
|
link_state: &state.link_state,
|
||||||
|
rx: rx_receiver,
|
||||||
|
tx: tx_sender,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct PacketBuf<const MTU: usize> {
|
||||||
|
len: usize,
|
||||||
|
buf: [u8; MTU],
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<const MTU: usize> PacketBuf<MTU> {
|
||||||
|
pub const fn new() -> Self {
|
||||||
|
Self { len: 0, buf: [0; MTU] }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Device<'d, const MTU: usize> {
|
||||||
|
rx: zerocopy_channel::Receiver<'d, NoopRawMutex, PacketBuf<MTU>>,
|
||||||
|
tx: zerocopy_channel::Sender<'d, NoopRawMutex, PacketBuf<MTU>>,
|
||||||
|
link_state: &'d Mutex<NoopRawMutex, RefCell<LinkStateState>>,
|
||||||
|
caps: Capabilities,
|
||||||
|
ethernet_address: [u8; 6],
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'d, const MTU: usize> embassy_net_driver::Driver for Device<'d, MTU> {
|
||||||
|
type RxToken<'a> = RxToken<'a, MTU> where Self: 'a ;
|
||||||
|
type TxToken<'a> = TxToken<'a, MTU> where Self: 'a ;
|
||||||
|
|
||||||
|
fn receive(&mut self, cx: &mut Context) -> Option<(Self::RxToken<'_>, Self::TxToken<'_>)> {
|
||||||
|
if self.rx.poll_recv(cx).is_ready() && self.tx.poll_send(cx).is_ready() {
|
||||||
|
Some((RxToken { rx: self.rx.borrow() }, TxToken { tx: self.tx.borrow() }))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Construct a transmit token.
|
||||||
|
fn transmit(&mut self, cx: &mut Context) -> Option<Self::TxToken<'_>> {
|
||||||
|
if self.tx.poll_send(cx).is_ready() {
|
||||||
|
Some(TxToken { tx: self.tx.borrow() })
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get a description of device capabilities.
|
||||||
|
fn capabilities(&self) -> Capabilities {
|
||||||
|
self.caps.clone()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn ethernet_address(&self) -> [u8; 6] {
|
||||||
|
self.ethernet_address
|
||||||
|
}
|
||||||
|
|
||||||
|
fn link_state(&mut self, cx: &mut Context) -> LinkState {
|
||||||
|
self.link_state.lock(|s| {
|
||||||
|
let s = &mut *s.borrow_mut();
|
||||||
|
s.waker.register(cx.waker());
|
||||||
|
s.state
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct RxToken<'a, const MTU: usize> {
|
||||||
|
rx: zerocopy_channel::Receiver<'a, NoopRawMutex, PacketBuf<MTU>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, const MTU: usize> embassy_net_driver::RxToken for RxToken<'a, MTU> {
|
||||||
|
fn consume<R, F>(mut self, f: F) -> R
|
||||||
|
where
|
||||||
|
F: FnOnce(&mut [u8]) -> R,
|
||||||
|
{
|
||||||
|
// NOTE(unwrap): we checked the queue wasn't full when creating the token.
|
||||||
|
let pkt = unwrap!(self.rx.try_recv());
|
||||||
|
let r = f(&mut pkt.buf[..pkt.len]);
|
||||||
|
self.rx.recv_done();
|
||||||
|
r
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct TxToken<'a, const MTU: usize> {
|
||||||
|
tx: zerocopy_channel::Sender<'a, NoopRawMutex, PacketBuf<MTU>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, const MTU: usize> embassy_net_driver::TxToken for TxToken<'a, MTU> {
|
||||||
|
fn consume<R, F>(mut self, len: usize, f: F) -> R
|
||||||
|
where
|
||||||
|
F: FnOnce(&mut [u8]) -> R,
|
||||||
|
{
|
||||||
|
// NOTE(unwrap): we checked the queue wasn't full when creating the token.
|
||||||
|
let pkt = unwrap!(self.tx.try_send());
|
||||||
|
let r = f(&mut pkt.buf[..len]);
|
||||||
|
pkt.len = len;
|
||||||
|
self.tx.send_done();
|
||||||
|
r
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mod zerocopy_channel {
|
||||||
|
use core::cell::RefCell;
|
||||||
|
use core::future::poll_fn;
|
||||||
|
use core::marker::PhantomData;
|
||||||
|
use core::task::{Context, Poll};
|
||||||
|
|
||||||
|
use embassy_sync::blocking_mutex::raw::RawMutex;
|
||||||
|
use embassy_sync::blocking_mutex::Mutex;
|
||||||
|
use embassy_sync::waitqueue::WakerRegistration;
|
||||||
|
|
||||||
|
pub struct Channel<'a, M: RawMutex, T> {
|
||||||
|
buf: *mut T,
|
||||||
|
phantom: PhantomData<&'a mut T>,
|
||||||
|
state: Mutex<M, RefCell<State>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, M: RawMutex, T> Channel<'a, M, T> {
|
||||||
|
pub fn new(buf: &'a mut [T]) -> Self {
|
||||||
|
let len = buf.len();
|
||||||
|
assert!(len != 0);
|
||||||
|
|
||||||
|
Self {
|
||||||
|
buf: buf.as_mut_ptr(),
|
||||||
|
phantom: PhantomData,
|
||||||
|
state: Mutex::new(RefCell::new(State {
|
||||||
|
len,
|
||||||
|
front: 0,
|
||||||
|
back: 0,
|
||||||
|
full: false,
|
||||||
|
send_waker: WakerRegistration::new(),
|
||||||
|
recv_waker: WakerRegistration::new(),
|
||||||
|
})),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn split(&mut self) -> (Sender<'_, M, T>, Receiver<'_, M, T>) {
|
||||||
|
(Sender { channel: self }, Receiver { channel: self })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Sender<'a, M: RawMutex, T> {
|
||||||
|
channel: &'a Channel<'a, M, T>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, M: RawMutex, T> Sender<'a, M, T> {
|
||||||
|
pub fn borrow(&mut self) -> Sender<'_, M, T> {
|
||||||
|
Sender { channel: self.channel }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn try_send(&mut self) -> Option<&mut T> {
|
||||||
|
self.channel.state.lock(|s| {
|
||||||
|
let s = &mut *s.borrow_mut();
|
||||||
|
match s.push_index() {
|
||||||
|
Some(i) => Some(unsafe { &mut *self.channel.buf.add(i) }),
|
||||||
|
None => None,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn poll_send(&mut self, cx: &mut Context) -> Poll<&mut T> {
|
||||||
|
self.channel.state.lock(|s| {
|
||||||
|
let s = &mut *s.borrow_mut();
|
||||||
|
match s.push_index() {
|
||||||
|
Some(i) => Poll::Ready(unsafe { &mut *self.channel.buf.add(i) }),
|
||||||
|
None => {
|
||||||
|
s.recv_waker.register(cx.waker());
|
||||||
|
Poll::Pending
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn send(&mut self) -> &mut T {
|
||||||
|
let i = poll_fn(|cx| {
|
||||||
|
self.channel.state.lock(|s| {
|
||||||
|
let s = &mut *s.borrow_mut();
|
||||||
|
match s.push_index() {
|
||||||
|
Some(i) => Poll::Ready(i),
|
||||||
|
None => {
|
||||||
|
s.recv_waker.register(cx.waker());
|
||||||
|
Poll::Pending
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.await;
|
||||||
|
unsafe { &mut *self.channel.buf.add(i) }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn send_done(&mut self) {
|
||||||
|
self.channel.state.lock(|s| s.borrow_mut().push_done())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub struct Receiver<'a, M: RawMutex, T> {
|
||||||
|
channel: &'a Channel<'a, M, T>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, M: RawMutex, T> Receiver<'a, M, T> {
|
||||||
|
pub fn borrow(&mut self) -> Receiver<'_, M, T> {
|
||||||
|
Receiver { channel: self.channel }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn try_recv(&mut self) -> Option<&mut T> {
|
||||||
|
self.channel.state.lock(|s| {
|
||||||
|
let s = &mut *s.borrow_mut();
|
||||||
|
match s.pop_index() {
|
||||||
|
Some(i) => Some(unsafe { &mut *self.channel.buf.add(i) }),
|
||||||
|
None => None,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn poll_recv(&mut self, cx: &mut Context) -> Poll<&mut T> {
|
||||||
|
self.channel.state.lock(|s| {
|
||||||
|
let s = &mut *s.borrow_mut();
|
||||||
|
match s.pop_index() {
|
||||||
|
Some(i) => Poll::Ready(unsafe { &mut *self.channel.buf.add(i) }),
|
||||||
|
None => {
|
||||||
|
s.send_waker.register(cx.waker());
|
||||||
|
Poll::Pending
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn recv(&mut self) -> &mut T {
|
||||||
|
let i = poll_fn(|cx| {
|
||||||
|
self.channel.state.lock(|s| {
|
||||||
|
let s = &mut *s.borrow_mut();
|
||||||
|
match s.pop_index() {
|
||||||
|
Some(i) => Poll::Ready(i),
|
||||||
|
None => {
|
||||||
|
s.send_waker.register(cx.waker());
|
||||||
|
Poll::Pending
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.await;
|
||||||
|
unsafe { &mut *self.channel.buf.add(i) }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn recv_done(&mut self) {
|
||||||
|
self.channel.state.lock(|s| s.borrow_mut().pop_done())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct State {
|
||||||
|
len: usize,
|
||||||
|
|
||||||
|
/// Front index. Always 0..=(N-1)
|
||||||
|
front: usize,
|
||||||
|
/// Back index. Always 0..=(N-1).
|
||||||
|
back: usize,
|
||||||
|
|
||||||
|
/// Used to distinguish "empty" and "full" cases when `front == back`.
|
||||||
|
/// May only be `true` if `front == back`, always `false` otherwise.
|
||||||
|
full: bool,
|
||||||
|
|
||||||
|
send_waker: WakerRegistration,
|
||||||
|
recv_waker: WakerRegistration,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl State {
|
||||||
|
fn increment(&self, i: usize) -> usize {
|
||||||
|
if i + 1 == self.len {
|
||||||
|
0
|
||||||
|
} else {
|
||||||
|
i + 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_full(&self) -> bool {
|
||||||
|
self.full
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_empty(&self) -> bool {
|
||||||
|
self.front == self.back && !self.full
|
||||||
|
}
|
||||||
|
|
||||||
|
fn push_index(&mut self) -> Option<usize> {
|
||||||
|
match self.is_full() {
|
||||||
|
true => None,
|
||||||
|
false => Some(self.back),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn push_done(&mut self) {
|
||||||
|
assert!(!self.is_full());
|
||||||
|
self.back = self.increment(self.back);
|
||||||
|
if self.back == self.front {
|
||||||
|
self.full = true;
|
||||||
|
}
|
||||||
|
self.send_waker.wake();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn pop_index(&mut self) -> Option<usize> {
|
||||||
|
match self.is_empty() {
|
||||||
|
true => None,
|
||||||
|
false => Some(self.front),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn pop_done(&mut self) {
|
||||||
|
assert!(!self.is_empty());
|
||||||
|
self.front = self.increment(self.front);
|
||||||
|
self.full = false;
|
||||||
|
self.recv_waker.wake();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
15
embassy-net-driver/Cargo.toml
Normal file
15
embassy-net-driver/Cargo.toml
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
[package]
|
||||||
|
name = "embassy-net-driver"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
license = "MIT OR Apache-2.0"
|
||||||
|
|
||||||
|
|
||||||
|
[package.metadata.embassy_docs]
|
||||||
|
src_base = "https://github.com/embassy-rs/embassy/blob/embassy-net-driver-v$VERSION/embassy-net/src/"
|
||||||
|
src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-net-driver/src/"
|
||||||
|
features = ["defmt"]
|
||||||
|
target = "thumbv7em-none-eabi"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
defmt = { version = "0.3", optional = true }
|
175
embassy-net-driver/src/lib.rs
Normal file
175
embassy-net-driver/src/lib.rs
Normal file
@ -0,0 +1,175 @@
|
|||||||
|
#![no_std]
|
||||||
|
|
||||||
|
use core::task::Context;
|
||||||
|
|
||||||
|
pub trait Driver {
|
||||||
|
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) -> Capabilities;
|
||||||
|
fn ethernet_address(&self) -> [u8; 6];
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: ?Sized + Driver> Driver 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) -> Capabilities {
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A description of device capabilities.
|
||||||
|
///
|
||||||
|
/// Higher-level protocols may achieve higher throughput or lower latency if they consider
|
||||||
|
/// the bandwidth or packet size limitations.
|
||||||
|
#[derive(Debug, Clone, Default)]
|
||||||
|
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||||
|
#[non_exhaustive]
|
||||||
|
pub struct Capabilities {
|
||||||
|
/// Medium of the device.
|
||||||
|
///
|
||||||
|
/// This indicates what kind of packet the sent/received bytes are, and determines
|
||||||
|
/// some behaviors of Interface. For example, ARP/NDISC address resolution is only done
|
||||||
|
/// for Ethernet mediums.
|
||||||
|
pub medium: Medium,
|
||||||
|
|
||||||
|
/// Maximum transmission unit.
|
||||||
|
///
|
||||||
|
/// The network device is unable to send or receive frames larger than the value returned
|
||||||
|
/// by this function.
|
||||||
|
///
|
||||||
|
/// For Ethernet devices, this is the maximum Ethernet frame size, including the Ethernet header (14 octets), but
|
||||||
|
/// *not* including the Ethernet FCS (4 octets). Therefore, Ethernet MTU = IP MTU + 14.
|
||||||
|
///
|
||||||
|
/// Note that in Linux and other OSes, "MTU" is the IP MTU, not the Ethernet MTU, even for Ethernet
|
||||||
|
/// devices. This is a common source of confusion.
|
||||||
|
///
|
||||||
|
/// Most common IP MTU is 1500. Minimum is 576 (for IPv4) or 1280 (for IPv6). Maximum is 9216 octets.
|
||||||
|
pub max_transmission_unit: usize,
|
||||||
|
|
||||||
|
/// Maximum burst size, in terms of MTU.
|
||||||
|
///
|
||||||
|
/// The network device is unable to send or receive bursts large than the value returned
|
||||||
|
/// by this function.
|
||||||
|
///
|
||||||
|
/// If `None`, there is no fixed limit on burst size, e.g. if network buffers are
|
||||||
|
/// dynamically allocated.
|
||||||
|
pub max_burst_size: Option<usize>,
|
||||||
|
|
||||||
|
/// Checksum behavior.
|
||||||
|
///
|
||||||
|
/// If the network device is capable of verifying or computing checksums for some protocols,
|
||||||
|
/// it can request that the stack not do so in software to improve performance.
|
||||||
|
pub checksum: ChecksumCapabilities,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Type of medium of a device.
|
||||||
|
#[derive(Debug, Eq, PartialEq, Copy, Clone)]
|
||||||
|
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||||
|
pub enum Medium {
|
||||||
|
/// Ethernet medium. Devices of this type send and receive Ethernet frames,
|
||||||
|
/// and interfaces using it must do neighbor discovery via ARP or NDISC.
|
||||||
|
///
|
||||||
|
/// Examples of devices of this type are Ethernet, WiFi (802.11), Linux `tap`, and VPNs in tap (layer 2) mode.
|
||||||
|
Ethernet,
|
||||||
|
|
||||||
|
/// IP medium. Devices of this type send and receive IP frames, without an
|
||||||
|
/// Ethernet header. MAC addresses are not used, and no neighbor discovery (ARP, NDISC) is done.
|
||||||
|
///
|
||||||
|
/// Examples of devices of this type are the Linux `tun`, PPP interfaces, VPNs in tun (layer 3) mode.
|
||||||
|
Ip,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for Medium {
|
||||||
|
fn default() -> Medium {
|
||||||
|
Medium::Ethernet
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A description of checksum behavior for every supported protocol.
|
||||||
|
#[derive(Debug, Clone, Default)]
|
||||||
|
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||||
|
#[non_exhaustive]
|
||||||
|
pub struct ChecksumCapabilities {
|
||||||
|
pub ipv4: Checksum,
|
||||||
|
pub udp: Checksum,
|
||||||
|
pub tcp: Checksum,
|
||||||
|
pub icmpv4: Checksum,
|
||||||
|
pub icmpv6: Checksum,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A description of checksum behavior for a particular protocol.
|
||||||
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||||
|
pub enum Checksum {
|
||||||
|
/// Verify checksum when receiving and compute checksum when sending.
|
||||||
|
Both,
|
||||||
|
/// Verify checksum when receiving.
|
||||||
|
Rx,
|
||||||
|
/// Compute checksum before sending.
|
||||||
|
Tx,
|
||||||
|
/// Ignore checksum completely.
|
||||||
|
None,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for Checksum {
|
||||||
|
fn default() -> Checksum {
|
||||||
|
Checksum::Both
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(PartialEq, Eq, Clone, Copy)]
|
||||||
|
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||||
|
pub enum LinkState {
|
||||||
|
Down,
|
||||||
|
Up,
|
||||||
|
}
|
@ -8,14 +8,14 @@ license = "MIT OR Apache-2.0"
|
|||||||
[package.metadata.embassy_docs]
|
[package.metadata.embassy_docs]
|
||||||
src_base = "https://github.com/embassy-rs/embassy/blob/embassy-net-v$VERSION/embassy-net/src/"
|
src_base = "https://github.com/embassy-rs/embassy/blob/embassy-net-v$VERSION/embassy-net/src/"
|
||||||
src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-net/src/"
|
src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-net/src/"
|
||||||
features = ["pool-4", "defmt", "tcp", "dns", "dhcpv4", "proto-ipv6", "medium-ethernet", "medium-ip"]
|
features = ["defmt", "tcp", "dns", "dhcpv4", "proto-ipv6", "medium-ethernet", "medium-ip"]
|
||||||
target = "thumbv7em-none-eabi"
|
target = "thumbv7em-none-eabi"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = []
|
default = []
|
||||||
std = []
|
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"]
|
nightly = ["dep:embedded-io", "embedded-io?/async", "dep:embedded-nal-async"]
|
||||||
unstable-traits = []
|
unstable-traits = []
|
||||||
@ -28,18 +28,12 @@ proto-ipv6 = ["smoltcp/proto-ipv6"]
|
|||||||
medium-ethernet = ["smoltcp/medium-ethernet"]
|
medium-ethernet = ["smoltcp/medium-ethernet"]
|
||||||
medium-ip = ["smoltcp/medium-ip"]
|
medium-ip = ["smoltcp/medium-ip"]
|
||||||
|
|
||||||
pool-4 = []
|
|
||||||
pool-8 = []
|
|
||||||
pool-16 = []
|
|
||||||
pool-32 = []
|
|
||||||
pool-64 = []
|
|
||||||
pool-128 = []
|
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
|
||||||
defmt = { version = "0.3", optional = true }
|
defmt = { version = "0.3", optional = true }
|
||||||
log = { version = "0.4.14", 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-time = { version = "0.1.0", path = "../embassy-time" }
|
||||||
embassy-sync = { version = "0.1.0", path = "../embassy-sync" }
|
embassy-sync = { version = "0.1.0", path = "../embassy-sync" }
|
||||||
embedded-io = { version = "0.4.0", optional = true }
|
embedded-io = { version = "0.4.0", optional = true }
|
||||||
@ -52,6 +46,7 @@ stable_deref_trait = { version = "1.2.0", default-features = false }
|
|||||||
futures = { version = "0.3.17", default-features = false, features = [ "async-await" ] }
|
futures = { version = "0.3.17", default-features = false, features = [ "async-await" ] }
|
||||||
atomic-pool = "1.0"
|
atomic-pool = "1.0"
|
||||||
embedded-nal-async = { version = "0.3.0", optional = true }
|
embedded-nal-async = { version = "0.3.0", optional = true }
|
||||||
|
atomic-polyfill = { version = "1.0" }
|
||||||
|
|
||||||
[dependencies.smoltcp]
|
[dependencies.smoltcp]
|
||||||
version = "0.8.0"
|
version = "0.8.0"
|
||||||
|
@ -1,93 +1,20 @@
|
|||||||
use core::task::Context;
|
use core::task::Context;
|
||||||
|
|
||||||
|
use embassy_net_driver::{Capabilities, Checksum, Driver, Medium, RxToken, TxToken};
|
||||||
use smoltcp::phy;
|
use smoltcp::phy;
|
||||||
pub use smoltcp::phy::{Checksum, ChecksumCapabilities, DeviceCapabilities, Medium};
|
|
||||||
|
|
||||||
#[derive(PartialEq, Eq, Clone, Copy)]
|
pub(crate) struct DriverAdapter<'d, 'c, T>
|
||||||
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>
|
|
||||||
where
|
where
|
||||||
T: Device,
|
T: Driver,
|
||||||
{
|
{
|
||||||
// must be Some when actually using this to rx/tx
|
// must be Some when actually using this to rx/tx
|
||||||
pub cx: Option<&'d mut Context<'c>>,
|
pub cx: Option<&'d mut Context<'c>>,
|
||||||
pub inner: &'d mut T,
|
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
|
where
|
||||||
T: Device,
|
T: Driver,
|
||||||
{
|
{
|
||||||
type RxToken<'a> = RxTokenAdapter<T::RxToken<'a>> where Self: 'a;
|
type RxToken<'a> = RxTokenAdapter<T::RxToken<'a>> where Self: 'a;
|
||||||
type TxToken<'a> = TxTokenAdapter<T::TxToken<'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.
|
/// Get a description of device capabilities.
|
||||||
fn capabilities(&self) -> phy::DeviceCapabilities {
|
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::future::{poll_fn, Future};
|
||||||
use core::task::{Context, Poll};
|
use core::task::{Context, Poll};
|
||||||
|
|
||||||
|
use embassy_net_driver::{Driver, LinkState, Medium};
|
||||||
use embassy_sync::waitqueue::WakerRegistration;
|
use embassy_sync::waitqueue::WakerRegistration;
|
||||||
use embassy_time::{Instant, Timer};
|
use embassy_time::{Instant, Timer};
|
||||||
use futures::pin_mut;
|
use futures::pin_mut;
|
||||||
@ -27,8 +28,6 @@ use smoltcp::iface::SocketHandle;
|
|||||||
use smoltcp::iface::{Interface, InterfaceBuilder, SocketSet, SocketStorage};
|
use smoltcp::iface::{Interface, InterfaceBuilder, SocketSet, SocketStorage};
|
||||||
#[cfg(feature = "medium-ethernet")]
|
#[cfg(feature = "medium-ethernet")]
|
||||||
use smoltcp::iface::{Neighbor, NeighborCache, Route, Routes};
|
use smoltcp::iface::{Neighbor, NeighborCache, Route, Routes};
|
||||||
#[cfg(feature = "medium-ethernet")]
|
|
||||||
use smoltcp::phy::Medium;
|
|
||||||
#[cfg(feature = "dhcpv4")]
|
#[cfg(feature = "dhcpv4")]
|
||||||
use smoltcp::socket::dhcpv4;
|
use smoltcp::socket::dhcpv4;
|
||||||
// smoltcp reexports
|
// smoltcp reexports
|
||||||
@ -41,7 +40,7 @@ pub use smoltcp::wire::{Ipv6Address, Ipv6Cidr};
|
|||||||
#[cfg(feature = "udp")]
|
#[cfg(feature = "udp")]
|
||||||
pub use smoltcp::{socket::udp::PacketMetadata, wire::IpListenEndpoint};
|
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_MIN: u16 = 1025;
|
||||||
const LOCAL_PORT_MAX: u16 = 65535;
|
const LOCAL_PORT_MAX: u16 = 65535;
|
||||||
@ -82,12 +81,12 @@ pub enum ConfigStrategy {
|
|||||||
Dhcp,
|
Dhcp,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Stack<D: Device> {
|
pub struct Stack<D: Driver> {
|
||||||
pub(crate) socket: RefCell<SocketStack>,
|
pub(crate) socket: RefCell<SocketStack>,
|
||||||
inner: RefCell<Inner<D>>,
|
inner: RefCell<Inner<D>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Inner<D: Device> {
|
struct Inner<D: Driver> {
|
||||||
device: D,
|
device: D,
|
||||||
link_up: bool,
|
link_up: bool,
|
||||||
config: Option<Config>,
|
config: Option<Config>,
|
||||||
@ -102,7 +101,7 @@ pub(crate) struct SocketStack {
|
|||||||
next_local_port: u16,
|
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>(
|
pub fn new<const ADDR: usize, const SOCK: usize, const NEIGH: usize>(
|
||||||
mut device: D,
|
mut device: D,
|
||||||
config: ConfigStrategy,
|
config: ConfigStrategy,
|
||||||
@ -130,7 +129,7 @@ impl<D: Device + 'static> Stack<D> {
|
|||||||
b = b.routes(Routes::new(&mut resources.routes[..]));
|
b = b.routes(Routes::new(&mut resources.routes[..]));
|
||||||
}
|
}
|
||||||
|
|
||||||
let iface = b.finalize(&mut DeviceAdapter {
|
let iface = b.finalize(&mut DriverAdapter {
|
||||||
inner: &mut device,
|
inner: &mut device,
|
||||||
cx: None,
|
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) {
|
fn apply_config(&mut self, s: &mut SocketStack, config: Config) {
|
||||||
#[cfg(feature = "medium-ethernet")]
|
#[cfg(feature = "medium-ethernet")]
|
||||||
let medium = self.device.capabilities().medium;
|
let medium = self.device.capabilities().medium;
|
||||||
@ -263,7 +262,7 @@ impl<D: Device + 'static> Inner<D> {
|
|||||||
s.waker.register(cx.waker());
|
s.waker.register(cx.waker());
|
||||||
|
|
||||||
let timestamp = instant_to_smoltcp(Instant::now());
|
let timestamp = instant_to_smoltcp(Instant::now());
|
||||||
let mut smoldev = DeviceAdapter {
|
let mut smoldev = DriverAdapter {
|
||||||
cx: Some(cx),
|
cx: Some(cx),
|
||||||
inner: &mut self.device,
|
inner: &mut self.device,
|
||||||
};
|
};
|
||||||
|
@ -3,12 +3,12 @@ use core::future::poll_fn;
|
|||||||
use core::mem;
|
use core::mem;
|
||||||
use core::task::Poll;
|
use core::task::Poll;
|
||||||
|
|
||||||
|
use embassy_net_driver::Driver;
|
||||||
use smoltcp::iface::{Interface, SocketHandle};
|
use smoltcp::iface::{Interface, SocketHandle};
|
||||||
use smoltcp::socket::tcp;
|
use smoltcp::socket::tcp;
|
||||||
use smoltcp::time::Duration;
|
use smoltcp::time::Duration;
|
||||||
use smoltcp::wire::{IpEndpoint, IpListenEndpoint};
|
use smoltcp::wire::{IpEndpoint, IpListenEndpoint};
|
||||||
|
|
||||||
use crate::device::Device;
|
|
||||||
use crate::{SocketStack, Stack};
|
use crate::{SocketStack, Stack};
|
||||||
|
|
||||||
#[derive(PartialEq, Eq, Clone, Copy, Debug)]
|
#[derive(PartialEq, Eq, Clone, Copy, Debug)]
|
||||||
@ -66,7 +66,7 @@ impl<'a> TcpWriter<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> TcpSocket<'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 s = &mut *stack.socket.borrow_mut();
|
||||||
let rx_buffer: &'static mut [u8] = unsafe { mem::transmute(rx_buffer) };
|
let rx_buffer: &'static mut [u8] = unsafe { mem::transmute(rx_buffer) };
|
||||||
let tx_buffer: &'static mut [u8] = unsafe { mem::transmute(tx_buffer) };
|
let tx_buffer: &'static mut [u8] = unsafe { mem::transmute(tx_buffer) };
|
||||||
@ -329,26 +329,26 @@ pub mod client {
|
|||||||
use core::cell::UnsafeCell;
|
use core::cell::UnsafeCell;
|
||||||
use core::mem::MaybeUninit;
|
use core::mem::MaybeUninit;
|
||||||
use core::ptr::NonNull;
|
use core::ptr::NonNull;
|
||||||
use core::sync::atomic::{AtomicBool, Ordering};
|
|
||||||
|
|
||||||
|
use atomic_polyfill::{AtomicBool, Ordering};
|
||||||
use embedded_nal_async::IpAddr;
|
use embedded_nal_async::IpAddr;
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
/// TCP client capable of creating up to N multiple connections with tx and rx buffers according to TX_SZ and RX_SZ.
|
/// 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>,
|
stack: &'d Stack<D>,
|
||||||
state: &'d TcpClientState<N, TX_SZ, RX_SZ>,
|
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
|
/// Create a new TcpClient
|
||||||
pub fn new(stack: &'d Stack<D>, state: &'d TcpClientState<N, TX_SZ, RX_SZ>) -> Self {
|
pub fn new(stack: &'d Stack<D>, state: &'d TcpClientState<N, TX_SZ, RX_SZ>) -> Self {
|
||||||
Self { stack, state }
|
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>
|
for TcpClient<'d, D, N, TX_SZ, RX_SZ>
|
||||||
{
|
{
|
||||||
type Error = Error;
|
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> {
|
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)?;
|
let mut bufs = state.pool.alloc().ok_or(Error::ConnectionReset)?;
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
socket: unsafe { TcpSocket::new(stack, &mut bufs.as_mut().0, &mut bufs.as_mut().1) },
|
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::mem;
|
||||||
use core::task::Poll;
|
use core::task::Poll;
|
||||||
|
|
||||||
|
use embassy_net_driver::Driver;
|
||||||
use smoltcp::iface::{Interface, SocketHandle};
|
use smoltcp::iface::{Interface, SocketHandle};
|
||||||
use smoltcp::socket::udp::{self, PacketMetadata};
|
use smoltcp::socket::udp::{self, PacketMetadata};
|
||||||
use smoltcp::wire::{IpEndpoint, IpListenEndpoint};
|
use smoltcp::wire::{IpEndpoint, IpListenEndpoint};
|
||||||
|
|
||||||
use crate::{Device, SocketStack, Stack};
|
use crate::{SocketStack, Stack};
|
||||||
|
|
||||||
#[derive(PartialEq, Eq, Clone, Copy, Debug)]
|
#[derive(PartialEq, Eq, Clone, Copy, Debug)]
|
||||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||||
@ -31,7 +32,7 @@ pub struct UdpSocket<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> UdpSocket<'a> {
|
impl<'a> UdpSocket<'a> {
|
||||||
pub fn new<D: Device>(
|
pub fn new<D: Driver>(
|
||||||
stack: &'a Stack<D>,
|
stack: &'a Stack<D>,
|
||||||
rx_meta: &'a mut [PacketMetadata],
|
rx_meta: &'a mut [PacketMetadata],
|
||||||
rx_buffer: &'a mut [u8],
|
rx_buffer: &'a mut [u8],
|
||||||
|
@ -39,7 +39,7 @@ embassy-futures = { version = "0.1.0", path = "../embassy-futures" }
|
|||||||
embassy-cortex-m = { version = "0.1.0", path = "../embassy-cortex-m", features = ["prio-bits-4"]}
|
embassy-cortex-m = { version = "0.1.0", path = "../embassy-cortex-m", features = ["prio-bits-4"]}
|
||||||
embassy-hal-common = {version = "0.1.0", path = "../embassy-hal-common" }
|
embassy-hal-common = {version = "0.1.0", path = "../embassy-hal-common" }
|
||||||
embassy-embedded-hal = {version = "0.1.0", path = "../embassy-embedded-hal" }
|
embassy-embedded-hal = {version = "0.1.0", path = "../embassy-embedded-hal" }
|
||||||
embassy-net = { version = "0.1.0", path = "../embassy-net", optional = true }
|
embassy-net-driver = { version = "0.1.0", path = "../embassy-net-driver" }
|
||||||
embassy-usb-driver = {version = "0.1.0", path = "../embassy-usb-driver", optional = true }
|
embassy-usb-driver = {version = "0.1.0", path = "../embassy-usb-driver", optional = true }
|
||||||
|
|
||||||
embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = ["unproven"] }
|
embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = ["unproven"] }
|
||||||
@ -75,7 +75,7 @@ quote = "1.0.15"
|
|||||||
stm32-metapac = { version = "0.1.0", path = "../stm32-metapac", default-features = false, features = ["metadata"]}
|
stm32-metapac = { version = "0.1.0", path = "../stm32-metapac", default-features = false, features = ["metadata"]}
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
defmt = ["dep:defmt", "bxcan/unstable-defmt", "embassy-sync/defmt", "embassy-executor/defmt", "embassy-embedded-hal/defmt", "embassy-hal-common/defmt", "embedded-io?/defmt", "embassy-usb-driver?/defmt"]
|
defmt = ["dep:defmt", "bxcan/unstable-defmt", "embassy-sync/defmt", "embassy-executor/defmt", "embassy-embedded-hal/defmt", "embassy-hal-common/defmt", "embedded-io?/defmt", "embassy-usb-driver?/defmt", "embassy-net-driver/defmt"]
|
||||||
sdmmc-rs = ["embedded-sdmmc"]
|
sdmmc-rs = ["embedded-sdmmc"]
|
||||||
memory-x = ["stm32-metapac/memory-x"]
|
memory-x = ["stm32-metapac/memory-x"]
|
||||||
subghz = []
|
subghz = []
|
||||||
|
@ -1,14 +1,17 @@
|
|||||||
#![macro_use]
|
#![macro_use]
|
||||||
#![cfg_attr(not(feature = "embassy-net"), allow(unused))]
|
|
||||||
|
|
||||||
#[cfg_attr(any(eth_v1a, eth_v1b, eth_v1c), path = "v1/mod.rs")]
|
#[cfg_attr(any(eth_v1a, eth_v1b, eth_v1c), path = "v1/mod.rs")]
|
||||||
#[cfg_attr(eth_v2, path = "v2/mod.rs")]
|
#[cfg_attr(eth_v2, path = "v2/mod.rs")]
|
||||||
mod _version;
|
mod _version;
|
||||||
pub mod generic_smi;
|
pub mod generic_smi;
|
||||||
|
|
||||||
pub use _version::*;
|
use core::task::Context;
|
||||||
|
|
||||||
|
use embassy_net_driver::{Capabilities, LinkState};
|
||||||
use embassy_sync::waitqueue::AtomicWaker;
|
use embassy_sync::waitqueue::AtomicWaker;
|
||||||
|
|
||||||
|
pub use self::_version::*;
|
||||||
|
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
const MTU: usize = 1514;
|
const MTU: usize = 1514;
|
||||||
const TX_BUFFER_SIZE: usize = 1514;
|
const TX_BUFFER_SIZE: usize = 1514;
|
||||||
@ -40,92 +43,84 @@ impl<const TX: usize, const RX: usize> PacketQueue<TX, RX> {
|
|||||||
|
|
||||||
static WAKER: AtomicWaker = AtomicWaker::new();
|
static WAKER: AtomicWaker = AtomicWaker::new();
|
||||||
|
|
||||||
#[cfg(feature = "embassy-net")]
|
impl<'d, T: Instance, P: PHY> embassy_net_driver::Driver for Ethernet<'d, T, P> {
|
||||||
mod embassy_net_impl {
|
type RxToken<'a> = RxToken<'a, 'd> where Self: 'a;
|
||||||
use core::task::Context;
|
type TxToken<'a> = TxToken<'a, 'd> where Self: 'a;
|
||||||
|
|
||||||
use embassy_net::device::{Device, DeviceCapabilities, LinkState};
|
fn receive(&mut self, cx: &mut Context) -> Option<(Self::RxToken<'_>, Self::TxToken<'_>)> {
|
||||||
|
WAKER.register(cx.waker());
|
||||||
use super::*;
|
if self.rx.available().is_some() && self.tx.available().is_some() {
|
||||||
|
Some((RxToken { rx: &mut self.rx }, TxToken { tx: &mut self.tx }))
|
||||||
impl<'d, T: Instance, P: PHY> Device for Ethernet<'d, T, P> {
|
} else {
|
||||||
type RxToken<'a> = RxToken<'a, 'd> where Self: 'a;
|
None
|
||||||
type TxToken<'a> = TxToken<'a, 'd> where Self: 'a;
|
|
||||||
|
|
||||||
fn receive(&mut self, cx: &mut Context) -> Option<(Self::RxToken<'_>, Self::TxToken<'_>)> {
|
|
||||||
WAKER.register(cx.waker());
|
|
||||||
if self.rx.available().is_some() && self.tx.available().is_some() {
|
|
||||||
Some((RxToken { rx: &mut self.rx }, TxToken { tx: &mut self.tx }))
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn transmit(&mut self, cx: &mut Context) -> Option<Self::TxToken<'_>> {
|
|
||||||
WAKER.register(cx.waker());
|
|
||||||
if self.tx.available().is_some() {
|
|
||||||
Some(TxToken { tx: &mut self.tx })
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn capabilities(&self) -> DeviceCapabilities {
|
|
||||||
let mut caps = DeviceCapabilities::default();
|
|
||||||
caps.max_transmission_unit = MTU;
|
|
||||||
caps.max_burst_size = Some(self.tx.len());
|
|
||||||
caps
|
|
||||||
}
|
|
||||||
|
|
||||||
fn link_state(&mut self, cx: &mut Context) -> LinkState {
|
|
||||||
// TODO: wake cx.waker on link state change
|
|
||||||
cx.waker().wake_by_ref();
|
|
||||||
if P::poll_link(self) {
|
|
||||||
LinkState::Up
|
|
||||||
} else {
|
|
||||||
LinkState::Down
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn ethernet_address(&self) -> [u8; 6] {
|
|
||||||
self.mac_addr
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct RxToken<'a, 'd> {
|
fn transmit(&mut self, cx: &mut Context) -> Option<Self::TxToken<'_>> {
|
||||||
rx: &'a mut RDesRing<'d>,
|
WAKER.register(cx.waker());
|
||||||
}
|
if self.tx.available().is_some() {
|
||||||
|
Some(TxToken { tx: &mut self.tx })
|
||||||
impl<'a, 'd> embassy_net::device::RxToken for RxToken<'a, 'd> {
|
} else {
|
||||||
fn consume<R, F>(self, f: F) -> R
|
None
|
||||||
where
|
|
||||||
F: FnOnce(&mut [u8]) -> R,
|
|
||||||
{
|
|
||||||
// NOTE(unwrap): we checked the queue wasn't full when creating the token.
|
|
||||||
let pkt = unwrap!(self.rx.available());
|
|
||||||
let r = f(pkt);
|
|
||||||
self.rx.pop_packet();
|
|
||||||
r
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct TxToken<'a, 'd> {
|
fn capabilities(&self) -> Capabilities {
|
||||||
tx: &'a mut TDesRing<'d>,
|
let mut caps = Capabilities::default();
|
||||||
|
caps.max_transmission_unit = MTU;
|
||||||
|
caps.max_burst_size = Some(self.tx.len());
|
||||||
|
caps
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'd> embassy_net::device::TxToken for TxToken<'a, 'd> {
|
fn link_state(&mut self, cx: &mut Context) -> LinkState {
|
||||||
fn consume<R, F>(self, len: usize, f: F) -> R
|
// TODO: wake cx.waker on link state change
|
||||||
where
|
cx.waker().wake_by_ref();
|
||||||
F: FnOnce(&mut [u8]) -> R,
|
if P::poll_link(self) {
|
||||||
{
|
LinkState::Up
|
||||||
// NOTE(unwrap): we checked the queue wasn't full when creating the token.
|
} else {
|
||||||
let pkt = unwrap!(self.tx.available());
|
LinkState::Down
|
||||||
let r = f(&mut pkt[..len]);
|
|
||||||
self.tx.transmit(len);
|
|
||||||
r
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn ethernet_address(&self) -> [u8; 6] {
|
||||||
|
self.mac_addr
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct RxToken<'a, 'd> {
|
||||||
|
rx: &'a mut RDesRing<'d>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, 'd> embassy_net_driver::RxToken for RxToken<'a, 'd> {
|
||||||
|
fn consume<R, F>(self, f: F) -> R
|
||||||
|
where
|
||||||
|
F: FnOnce(&mut [u8]) -> R,
|
||||||
|
{
|
||||||
|
// NOTE(unwrap): we checked the queue wasn't full when creating the token.
|
||||||
|
let pkt = unwrap!(self.rx.available());
|
||||||
|
let r = f(pkt);
|
||||||
|
self.rx.pop_packet();
|
||||||
|
r
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct TxToken<'a, 'd> {
|
||||||
|
tx: &'a mut TDesRing<'d>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, 'd> embassy_net_driver::TxToken for TxToken<'a, 'd> {
|
||||||
|
fn consume<R, F>(self, len: usize, f: F) -> R
|
||||||
|
where
|
||||||
|
F: FnOnce(&mut [u8]) -> R,
|
||||||
|
{
|
||||||
|
// NOTE(unwrap): we checked the queue wasn't full when creating the token.
|
||||||
|
let pkt = unwrap!(self.tx.available());
|
||||||
|
let r = f(&mut pkt[..len]);
|
||||||
|
self.tx.transmit(len);
|
||||||
|
r
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Station Management Interface (SMI) on an ethernet PHY
|
/// Station Management Interface (SMI) on an ethernet PHY
|
||||||
///
|
///
|
||||||
/// # Safety
|
/// # Safety
|
||||||
|
@ -13,7 +13,7 @@ pub(crate) use self::rx_desc::{RDes, RDesRing};
|
|||||||
pub(crate) use self::tx_desc::{TDes, TDesRing};
|
pub(crate) use self::tx_desc::{TDes, TDesRing};
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::gpio::sealed::{AFType, Pin as __GpioPin};
|
use crate::gpio::sealed::{AFType, Pin as __GpioPin};
|
||||||
use crate::gpio::{AnyPin, Speed};
|
use crate::gpio::AnyPin;
|
||||||
#[cfg(eth_v1a)]
|
#[cfg(eth_v1a)]
|
||||||
use crate::pac::AFIO;
|
use crate::pac::AFIO;
|
||||||
#[cfg(any(eth_v1b, eth_v1c))]
|
#[cfg(any(eth_v1b, eth_v1c))]
|
||||||
@ -66,7 +66,7 @@ macro_rules! config_pins {
|
|||||||
critical_section::with(|_| {
|
critical_section::with(|_| {
|
||||||
$(
|
$(
|
||||||
$pin.set_as_af($pin.af_num(), AFType::OutputPushPull);
|
$pin.set_as_af($pin.af_num(), AFType::OutputPushPull);
|
||||||
$pin.set_speed(Speed::VeryHigh);
|
$pin.set_speed(crate::gpio::Speed::VeryHigh);
|
||||||
)*
|
)*
|
||||||
})
|
})
|
||||||
};
|
};
|
||||||
|
@ -14,4 +14,3 @@ target = "thumbv7em-none-eabi"
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
defmt = { version = "0.3", optional = true }
|
defmt = { version = "0.3", optional = true }
|
||||||
log = { version = "0.4.14", optional = true }
|
|
||||||
|
@ -19,7 +19,7 @@ default = ["usbd-hid"]
|
|||||||
embassy-futures = { version = "0.1.0", path = "../embassy-futures" }
|
embassy-futures = { version = "0.1.0", path = "../embassy-futures" }
|
||||||
embassy-usb-driver = { version = "0.1.0", path = "../embassy-usb-driver" }
|
embassy-usb-driver = { version = "0.1.0", path = "../embassy-usb-driver" }
|
||||||
embassy-sync = { version = "0.1.0", path = "../embassy-sync" }
|
embassy-sync = { version = "0.1.0", path = "../embassy-sync" }
|
||||||
embassy-net = { version = "0.1.0", path = "../embassy-net", optional = true }
|
embassy-net-driver-channel = { version = "0.1.0", path = "../embassy-net-driver-channel" }
|
||||||
|
|
||||||
defmt = { version = "0.3", optional = true }
|
defmt = { version = "0.3", optional = true }
|
||||||
log = { version = "0.4.14", optional = true }
|
log = { version = "0.4.14", optional = true }
|
||||||
|
@ -1,81 +1,45 @@
|
|||||||
use core::cell::RefCell;
|
|
||||||
use core::mem::MaybeUninit;
|
|
||||||
use core::task::Context;
|
|
||||||
|
|
||||||
use embassy_futures::select::{select, Either};
|
use embassy_futures::select::{select, Either};
|
||||||
use embassy_net::device::{Device as DeviceTrait, DeviceCapabilities, LinkState, Medium};
|
use embassy_net_driver_channel as ch;
|
||||||
use embassy_sync::blocking_mutex::raw::NoopRawMutex;
|
use embassy_net_driver_channel::driver::LinkState;
|
||||||
use embassy_sync::blocking_mutex::Mutex;
|
|
||||||
use embassy_sync::waitqueue::WakerRegistration;
|
|
||||||
use embassy_usb_driver::Driver;
|
use embassy_usb_driver::Driver;
|
||||||
|
|
||||||
use super::{CdcNcmClass, Receiver, Sender};
|
use super::{CdcNcmClass, Receiver, Sender};
|
||||||
|
|
||||||
pub struct State<'d, const MTU: usize, const N_RX: usize, const N_TX: usize> {
|
pub struct State<const MTU: usize, const N_RX: usize, const N_TX: usize> {
|
||||||
rx: [PacketBuf<MTU>; N_RX],
|
ch_state: ch::State<MTU, N_RX, N_TX>,
|
||||||
tx: [PacketBuf<MTU>; N_TX],
|
|
||||||
inner: MaybeUninit<StateInner<'d, MTU>>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'d, const MTU: usize, const N_RX: usize, const N_TX: usize> State<'d, MTU, N_RX, N_TX> {
|
impl<const MTU: usize, const N_RX: usize, const N_TX: usize> State<MTU, N_RX, N_TX> {
|
||||||
const NEW_PACKET: PacketBuf<MTU> = PacketBuf::new();
|
|
||||||
|
|
||||||
pub const fn new() -> Self {
|
pub const fn new() -> Self {
|
||||||
Self {
|
Self {
|
||||||
rx: [Self::NEW_PACKET; N_RX],
|
ch_state: ch::State::new(),
|
||||||
tx: [Self::NEW_PACKET; N_TX],
|
|
||||||
inner: MaybeUninit::uninit(),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct StateInner<'d, const MTU: usize> {
|
|
||||||
rx: zerocopy_channel::Channel<'d, NoopRawMutex, PacketBuf<MTU>>,
|
|
||||||
tx: zerocopy_channel::Channel<'d, NoopRawMutex, PacketBuf<MTU>>,
|
|
||||||
link_state: Mutex<NoopRawMutex, RefCell<LinkStateState>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// State of the LinkState
|
|
||||||
struct LinkStateState {
|
|
||||||
state: LinkState,
|
|
||||||
waker: WakerRegistration,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct Runner<'d, D: Driver<'d>, const MTU: usize> {
|
pub struct Runner<'d, D: Driver<'d>, const MTU: usize> {
|
||||||
tx_usb: Sender<'d, D>,
|
tx_usb: Sender<'d, D>,
|
||||||
tx_chan: zerocopy_channel::Receiver<'d, NoopRawMutex, PacketBuf<MTU>>,
|
|
||||||
rx_usb: Receiver<'d, D>,
|
rx_usb: Receiver<'d, D>,
|
||||||
rx_chan: zerocopy_channel::Sender<'d, NoopRawMutex, PacketBuf<MTU>>,
|
ch: ch::Runner<'d, MTU>,
|
||||||
link_state: &'d Mutex<NoopRawMutex, RefCell<LinkStateState>>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'d, D: Driver<'d>, const MTU: usize> Runner<'d, D, MTU> {
|
impl<'d, D: Driver<'d>, const MTU: usize> Runner<'d, D, MTU> {
|
||||||
pub async fn run(mut self) -> ! {
|
pub async fn run(mut self) -> ! {
|
||||||
|
let (mut rx_chan, mut tx_chan) = self.ch.split();
|
||||||
let rx_fut = async move {
|
let rx_fut = async move {
|
||||||
loop {
|
loop {
|
||||||
trace!("WAITING for connection");
|
trace!("WAITING for connection");
|
||||||
self.link_state.lock(|s| {
|
rx_chan.set_link_state(LinkState::Down);
|
||||||
let s = &mut *s.borrow_mut();
|
|
||||||
s.state = LinkState::Down;
|
|
||||||
s.waker.wake();
|
|
||||||
});
|
|
||||||
|
|
||||||
self.rx_usb.wait_connection().await.unwrap();
|
self.rx_usb.wait_connection().await.unwrap();
|
||||||
|
|
||||||
trace!("Connected");
|
trace!("Connected");
|
||||||
self.link_state.lock(|s| {
|
rx_chan.set_link_state(LinkState::Up);
|
||||||
let s = &mut *s.borrow_mut();
|
|
||||||
s.state = LinkState::Up;
|
|
||||||
s.waker.wake();
|
|
||||||
});
|
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
let p = self.rx_chan.send().await;
|
let p = rx_chan.rx_buf().await;
|
||||||
match self.rx_usb.read_packet(&mut p.buf).await {
|
match self.rx_usb.read_packet(p).await {
|
||||||
Ok(n) => {
|
Ok(n) => rx_chan.rx_done(n),
|
||||||
p.len = n;
|
|
||||||
self.rx_chan.send_done();
|
|
||||||
}
|
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
warn!("error reading packet: {:?}", e);
|
warn!("error reading packet: {:?}", e);
|
||||||
break;
|
break;
|
||||||
@ -86,11 +50,11 @@ impl<'d, D: Driver<'d>, const MTU: usize> Runner<'d, D, MTU> {
|
|||||||
};
|
};
|
||||||
let tx_fut = async move {
|
let tx_fut = async move {
|
||||||
loop {
|
loop {
|
||||||
let p = self.tx_chan.recv().await;
|
let p = tx_chan.tx_buf().await;
|
||||||
if let Err(e) = self.tx_usb.write_packet(&p.buf[..p.len]).await {
|
if let Err(e) = self.tx_usb.write_packet(p).await {
|
||||||
warn!("Failed to TX packet: {:?}", e);
|
warn!("Failed to TX packet: {:?}", e);
|
||||||
}
|
}
|
||||||
self.tx_chan.recv_done();
|
tx_chan.tx_done();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
match select(rx_fut, tx_fut).await {
|
match select(rx_fut, tx_fut).await {
|
||||||
@ -100,350 +64,26 @@ impl<'d, D: Driver<'d>, const MTU: usize> Runner<'d, D, MTU> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// would be cool to use a TAIT here, but it gives a "may not live long enough". rustc bug?
|
||||||
|
//pub type Device<'d, const MTU: usize> = impl embassy_net_driver_channel::driver::Driver + 'd;
|
||||||
|
pub type Device<'d, const MTU: usize> = embassy_net_driver_channel::Device<'d, MTU>;
|
||||||
|
|
||||||
impl<'d, D: Driver<'d>> CdcNcmClass<'d, D> {
|
impl<'d, D: Driver<'d>> CdcNcmClass<'d, D> {
|
||||||
pub fn into_embassy_net_device<const MTU: usize, const N_RX: usize, const N_TX: usize>(
|
pub fn into_embassy_net_device<const MTU: usize, const N_RX: usize, const N_TX: usize>(
|
||||||
self,
|
self,
|
||||||
state: &'d mut State<'d, MTU, N_RX, N_TX>,
|
state: &'d mut State<MTU, N_RX, N_TX>,
|
||||||
ethernet_address: [u8; 6],
|
ethernet_address: [u8; 6],
|
||||||
) -> (Runner<'d, D, MTU>, Device<'d, MTU>) {
|
) -> (Runner<'d, D, MTU>, Device<'d, MTU>) {
|
||||||
let (tx_usb, rx_usb) = self.split();
|
let (tx_usb, rx_usb) = self.split();
|
||||||
|
let (runner, device) = ch::new(&mut state.ch_state, ethernet_address);
|
||||||
let mut caps = DeviceCapabilities::default();
|
|
||||||
caps.max_transmission_unit = 1514; // 1500 IP + 14 ethernet header
|
|
||||||
caps.medium = Medium::Ethernet;
|
|
||||||
|
|
||||||
let state = state.inner.write(StateInner {
|
|
||||||
rx: zerocopy_channel::Channel::new(&mut state.rx[..]),
|
|
||||||
tx: zerocopy_channel::Channel::new(&mut state.tx[..]),
|
|
||||||
link_state: Mutex::new(RefCell::new(LinkStateState {
|
|
||||||
state: LinkState::Down,
|
|
||||||
waker: WakerRegistration::new(),
|
|
||||||
})),
|
|
||||||
});
|
|
||||||
|
|
||||||
let (rx_sender, rx_receiver) = state.rx.split();
|
|
||||||
let (tx_sender, tx_receiver) = state.tx.split();
|
|
||||||
|
|
||||||
(
|
(
|
||||||
Runner {
|
Runner {
|
||||||
tx_usb,
|
tx_usb,
|
||||||
tx_chan: tx_receiver,
|
|
||||||
rx_usb,
|
rx_usb,
|
||||||
rx_chan: rx_sender,
|
ch: runner,
|
||||||
link_state: &state.link_state,
|
|
||||||
},
|
|
||||||
Device {
|
|
||||||
caps,
|
|
||||||
ethernet_address,
|
|
||||||
link_state: &state.link_state,
|
|
||||||
rx: rx_receiver,
|
|
||||||
tx: tx_sender,
|
|
||||||
},
|
},
|
||||||
|
device,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct PacketBuf<const MTU: usize> {
|
|
||||||
len: usize,
|
|
||||||
buf: [u8; MTU],
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<const MTU: usize> PacketBuf<MTU> {
|
|
||||||
pub const fn new() -> Self {
|
|
||||||
Self { len: 0, buf: [0; MTU] }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct Device<'d, const MTU: usize> {
|
|
||||||
rx: zerocopy_channel::Receiver<'d, NoopRawMutex, PacketBuf<MTU>>,
|
|
||||||
tx: zerocopy_channel::Sender<'d, NoopRawMutex, PacketBuf<MTU>>,
|
|
||||||
link_state: &'d Mutex<NoopRawMutex, RefCell<LinkStateState>>,
|
|
||||||
caps: DeviceCapabilities,
|
|
||||||
ethernet_address: [u8; 6],
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'d, const MTU: usize> DeviceTrait for Device<'d, MTU> {
|
|
||||||
type RxToken<'a> = RxToken<'a, MTU> where Self: 'a ;
|
|
||||||
type TxToken<'a> = TxToken<'a, MTU> where Self: 'a ;
|
|
||||||
|
|
||||||
fn receive(&mut self, cx: &mut Context) -> Option<(Self::RxToken<'_>, Self::TxToken<'_>)> {
|
|
||||||
if self.rx.poll_recv(cx).is_ready() && self.tx.poll_send(cx).is_ready() {
|
|
||||||
Some((RxToken { rx: self.rx.borrow() }, TxToken { tx: self.tx.borrow() }))
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Construct a transmit token.
|
|
||||||
fn transmit(&mut self, cx: &mut Context) -> Option<Self::TxToken<'_>> {
|
|
||||||
if self.tx.poll_send(cx).is_ready() {
|
|
||||||
Some(TxToken { tx: self.tx.borrow() })
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Get a description of device capabilities.
|
|
||||||
fn capabilities(&self) -> DeviceCapabilities {
|
|
||||||
self.caps.clone()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn ethernet_address(&self) -> [u8; 6] {
|
|
||||||
self.ethernet_address
|
|
||||||
}
|
|
||||||
|
|
||||||
fn link_state(&mut self, cx: &mut Context) -> LinkState {
|
|
||||||
self.link_state.lock(|s| {
|
|
||||||
let s = &mut *s.borrow_mut();
|
|
||||||
s.waker.register(cx.waker());
|
|
||||||
s.state
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct RxToken<'a, const MTU: usize> {
|
|
||||||
rx: zerocopy_channel::Receiver<'a, NoopRawMutex, PacketBuf<MTU>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a, const MTU: usize> embassy_net::device::RxToken for RxToken<'a, MTU> {
|
|
||||||
fn consume<R, F>(mut self, f: F) -> R
|
|
||||||
where
|
|
||||||
F: FnOnce(&mut [u8]) -> R,
|
|
||||||
{
|
|
||||||
// NOTE(unwrap): we checked the queue wasn't full when creating the token.
|
|
||||||
let pkt = unwrap!(self.rx.try_recv());
|
|
||||||
let r = f(&mut pkt.buf[..pkt.len]);
|
|
||||||
self.rx.recv_done();
|
|
||||||
r
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct TxToken<'a, const MTU: usize> {
|
|
||||||
tx: zerocopy_channel::Sender<'a, NoopRawMutex, PacketBuf<MTU>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a, const MTU: usize> embassy_net::device::TxToken for TxToken<'a, MTU> {
|
|
||||||
fn consume<R, F>(mut self, len: usize, f: F) -> R
|
|
||||||
where
|
|
||||||
F: FnOnce(&mut [u8]) -> R,
|
|
||||||
{
|
|
||||||
// NOTE(unwrap): we checked the queue wasn't full when creating the token.
|
|
||||||
let pkt = unwrap!(self.tx.try_send());
|
|
||||||
let r = f(&mut pkt.buf[..len]);
|
|
||||||
pkt.len = len;
|
|
||||||
self.tx.send_done();
|
|
||||||
r
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
mod zerocopy_channel {
|
|
||||||
use core::cell::RefCell;
|
|
||||||
use core::future::poll_fn;
|
|
||||||
use core::marker::PhantomData;
|
|
||||||
use core::task::{Context, Poll};
|
|
||||||
|
|
||||||
use embassy_sync::blocking_mutex::raw::RawMutex;
|
|
||||||
use embassy_sync::blocking_mutex::Mutex;
|
|
||||||
use embassy_sync::waitqueue::WakerRegistration;
|
|
||||||
|
|
||||||
pub struct Channel<'a, M: RawMutex, T> {
|
|
||||||
buf: *mut T,
|
|
||||||
phantom: PhantomData<&'a mut T>,
|
|
||||||
state: Mutex<M, RefCell<State>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a, M: RawMutex, T> Channel<'a, M, T> {
|
|
||||||
pub fn new(buf: &'a mut [T]) -> Self {
|
|
||||||
let len = buf.len();
|
|
||||||
assert!(len != 0);
|
|
||||||
|
|
||||||
Self {
|
|
||||||
buf: buf.as_mut_ptr(),
|
|
||||||
phantom: PhantomData,
|
|
||||||
state: Mutex::new(RefCell::new(State {
|
|
||||||
len,
|
|
||||||
front: 0,
|
|
||||||
back: 0,
|
|
||||||
full: false,
|
|
||||||
send_waker: WakerRegistration::new(),
|
|
||||||
recv_waker: WakerRegistration::new(),
|
|
||||||
})),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn split(&mut self) -> (Sender<'_, M, T>, Receiver<'_, M, T>) {
|
|
||||||
(Sender { channel: self }, Receiver { channel: self })
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct Sender<'a, M: RawMutex, T> {
|
|
||||||
channel: &'a Channel<'a, M, T>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a, M: RawMutex, T> Sender<'a, M, T> {
|
|
||||||
pub fn borrow(&mut self) -> Sender<'_, M, T> {
|
|
||||||
Sender { channel: self.channel }
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn try_send(&mut self) -> Option<&mut T> {
|
|
||||||
self.channel.state.lock(|s| {
|
|
||||||
let s = &mut *s.borrow_mut();
|
|
||||||
match s.push_index() {
|
|
||||||
Some(i) => Some(unsafe { &mut *self.channel.buf.add(i) }),
|
|
||||||
None => None,
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn poll_send(&mut self, cx: &mut Context) -> Poll<&mut T> {
|
|
||||||
self.channel.state.lock(|s| {
|
|
||||||
let s = &mut *s.borrow_mut();
|
|
||||||
match s.push_index() {
|
|
||||||
Some(i) => Poll::Ready(unsafe { &mut *self.channel.buf.add(i) }),
|
|
||||||
None => {
|
|
||||||
s.recv_waker.register(cx.waker());
|
|
||||||
Poll::Pending
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn send(&mut self) -> &mut T {
|
|
||||||
let i = poll_fn(|cx| {
|
|
||||||
self.channel.state.lock(|s| {
|
|
||||||
let s = &mut *s.borrow_mut();
|
|
||||||
match s.push_index() {
|
|
||||||
Some(i) => Poll::Ready(i),
|
|
||||||
None => {
|
|
||||||
s.recv_waker.register(cx.waker());
|
|
||||||
Poll::Pending
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
})
|
|
||||||
.await;
|
|
||||||
unsafe { &mut *self.channel.buf.add(i) }
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn send_done(&mut self) {
|
|
||||||
self.channel.state.lock(|s| s.borrow_mut().push_done())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pub struct Receiver<'a, M: RawMutex, T> {
|
|
||||||
channel: &'a Channel<'a, M, T>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a, M: RawMutex, T> Receiver<'a, M, T> {
|
|
||||||
pub fn borrow(&mut self) -> Receiver<'_, M, T> {
|
|
||||||
Receiver { channel: self.channel }
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn try_recv(&mut self) -> Option<&mut T> {
|
|
||||||
self.channel.state.lock(|s| {
|
|
||||||
let s = &mut *s.borrow_mut();
|
|
||||||
match s.pop_index() {
|
|
||||||
Some(i) => Some(unsafe { &mut *self.channel.buf.add(i) }),
|
|
||||||
None => None,
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn poll_recv(&mut self, cx: &mut Context) -> Poll<&mut T> {
|
|
||||||
self.channel.state.lock(|s| {
|
|
||||||
let s = &mut *s.borrow_mut();
|
|
||||||
match s.pop_index() {
|
|
||||||
Some(i) => Poll::Ready(unsafe { &mut *self.channel.buf.add(i) }),
|
|
||||||
None => {
|
|
||||||
s.send_waker.register(cx.waker());
|
|
||||||
Poll::Pending
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn recv(&mut self) -> &mut T {
|
|
||||||
let i = poll_fn(|cx| {
|
|
||||||
self.channel.state.lock(|s| {
|
|
||||||
let s = &mut *s.borrow_mut();
|
|
||||||
match s.pop_index() {
|
|
||||||
Some(i) => Poll::Ready(i),
|
|
||||||
None => {
|
|
||||||
s.send_waker.register(cx.waker());
|
|
||||||
Poll::Pending
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
})
|
|
||||||
.await;
|
|
||||||
unsafe { &mut *self.channel.buf.add(i) }
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn recv_done(&mut self) {
|
|
||||||
self.channel.state.lock(|s| s.borrow_mut().pop_done())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct State {
|
|
||||||
len: usize,
|
|
||||||
|
|
||||||
/// Front index. Always 0..=(N-1)
|
|
||||||
front: usize,
|
|
||||||
/// Back index. Always 0..=(N-1).
|
|
||||||
back: usize,
|
|
||||||
|
|
||||||
/// Used to distinguish "empty" and "full" cases when `front == back`.
|
|
||||||
/// May only be `true` if `front == back`, always `false` otherwise.
|
|
||||||
full: bool,
|
|
||||||
|
|
||||||
send_waker: WakerRegistration,
|
|
||||||
recv_waker: WakerRegistration,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl State {
|
|
||||||
fn increment(&self, i: usize) -> usize {
|
|
||||||
if i + 1 == self.len {
|
|
||||||
0
|
|
||||||
} else {
|
|
||||||
i + 1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn is_full(&self) -> bool {
|
|
||||||
self.full
|
|
||||||
}
|
|
||||||
|
|
||||||
fn is_empty(&self) -> bool {
|
|
||||||
self.front == self.back && !self.full
|
|
||||||
}
|
|
||||||
|
|
||||||
fn push_index(&mut self) -> Option<usize> {
|
|
||||||
match self.is_full() {
|
|
||||||
true => None,
|
|
||||||
false => Some(self.back),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn push_done(&mut self) {
|
|
||||||
assert!(!self.is_full());
|
|
||||||
self.back = self.increment(self.back);
|
|
||||||
if self.back == self.front {
|
|
||||||
self.full = true;
|
|
||||||
}
|
|
||||||
self.send_waker.wake();
|
|
||||||
}
|
|
||||||
|
|
||||||
fn pop_index(&mut self) -> Option<usize> {
|
|
||||||
match self.is_empty() {
|
|
||||||
true => None,
|
|
||||||
false => Some(self.front),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn pop_done(&mut self) {
|
|
||||||
assert!(!self.is_empty());
|
|
||||||
self.front = self.increment(self.front);
|
|
||||||
self.full = false;
|
|
||||||
self.recv_waker.wake();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -21,7 +21,6 @@ use crate::driver::{Driver, Endpoint, EndpointError, EndpointIn, EndpointOut};
|
|||||||
use crate::types::*;
|
use crate::types::*;
|
||||||
use crate::Builder;
|
use crate::Builder;
|
||||||
|
|
||||||
#[cfg(feature = "embassy-net")]
|
|
||||||
pub mod embassy_net;
|
pub mod embassy_net;
|
||||||
|
|
||||||
/// This should be used as `device_class` when building the `UsbDevice`.
|
/// This should be used as `device_class` when building the `UsbDevice`.
|
||||||
|
@ -15,8 +15,8 @@ embassy-sync = { version = "0.1.0", path = "../../embassy-sync", features = ["de
|
|||||||
embassy-executor = { version = "0.1.0", path = "../../embassy-executor", features = ["defmt", "integrated-timers"] }
|
embassy-executor = { version = "0.1.0", path = "../../embassy-executor", features = ["defmt", "integrated-timers"] }
|
||||||
embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] }
|
embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] }
|
||||||
embassy-nrf = { version = "0.1.0", path = "../../embassy-nrf", features = ["defmt", "nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac"] }
|
embassy-nrf = { version = "0.1.0", path = "../../embassy-nrf", features = ["defmt", "nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac"] }
|
||||||
embassy-net = { version = "0.1.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "pool-16"], optional = true }
|
embassy-net = { version = "0.1.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet"], optional = true }
|
||||||
embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt", "embassy-net"], optional = true }
|
embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"], optional = true }
|
||||||
embedded-io = "0.4.0"
|
embedded-io = "0.4.0"
|
||||||
embassy-lora = { version = "0.1.0", path = "../../embassy-lora", features = ["sx126x", "time", "defmt"], optional = true }
|
embassy-lora = { version = "0.1.0", path = "../../embassy-lora", features = ["sx126x", "time", "defmt"], optional = true }
|
||||||
|
|
||||||
|
@ -10,8 +10,8 @@ embassy-sync = { version = "0.1.0", path = "../../embassy-sync", features = ["de
|
|||||||
embassy-executor = { version = "0.1.0", path = "../../embassy-executor", features = ["defmt", "integrated-timers"] }
|
embassy-executor = { version = "0.1.0", path = "../../embassy-executor", features = ["defmt", "integrated-timers"] }
|
||||||
embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] }
|
embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] }
|
||||||
embassy-rp = { version = "0.1.0", path = "../../embassy-rp", features = ["defmt", "unstable-traits", "nightly", "unstable-pac", "time-driver", "pio", "critical-section-impl"] }
|
embassy-rp = { version = "0.1.0", path = "../../embassy-rp", features = ["defmt", "unstable-traits", "nightly", "unstable-pac", "time-driver", "pio", "critical-section-impl"] }
|
||||||
embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt", "embassy-net"] }
|
embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] }
|
||||||
embassy-net = { version = "0.1.0", path = "../../embassy-net", features = ["defmt", "nightly", "tcp", "dhcpv4", "medium-ethernet", "pool-16"] }
|
embassy-net = { version = "0.1.0", path = "../../embassy-net", features = ["defmt", "nightly", "tcp", "dhcpv4", "medium-ethernet"] }
|
||||||
embassy-futures = { version = "0.1.0", path = "../../embassy-futures" }
|
embassy-futures = { version = "0.1.0", path = "../../embassy-futures" }
|
||||||
embassy-usb-logger = { version = "0.1.0", path = "../../embassy-usb-logger" }
|
embassy-usb-logger = { version = "0.1.0", path = "../../embassy-usb-logger" }
|
||||||
|
|
||||||
|
@ -8,7 +8,8 @@ license = "MIT OR Apache-2.0"
|
|||||||
embassy-sync = { version = "0.1.0", path = "../../embassy-sync", features = ["log"] }
|
embassy-sync = { version = "0.1.0", path = "../../embassy-sync", features = ["log"] }
|
||||||
embassy-executor = { version = "0.1.0", path = "../../embassy-executor", features = ["log", "std", "nightly", "integrated-timers"] }
|
embassy-executor = { version = "0.1.0", path = "../../embassy-executor", features = ["log", "std", "nightly", "integrated-timers"] }
|
||||||
embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["log", "std", "nightly"] }
|
embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["log", "std", "nightly"] }
|
||||||
embassy-net = { version = "0.1.0", path = "../../embassy-net", features=[ "std", "nightly", "log", "medium-ethernet", "tcp", "udp", "dhcpv4", "pool-16"] }
|
embassy-net = { version = "0.1.0", path = "../../embassy-net", features=[ "std", "nightly", "log", "medium-ethernet", "tcp", "udp", "dhcpv4"] }
|
||||||
|
embassy-net-driver = { version = "0.1.0", path = "../../embassy-net-driver" }
|
||||||
embedded-io = { version = "0.4.0", features = ["async", "std", "futures"] }
|
embedded-io = { version = "0.4.0", features = ["async", "std", "futures"] }
|
||||||
critical-section = { version = "1.1", features = ["std"] }
|
critical-section = { version = "1.1", features = ["std"] }
|
||||||
|
|
||||||
|
@ -4,7 +4,7 @@ use std::os::unix::io::{AsRawFd, RawFd};
|
|||||||
use std::task::Context;
|
use std::task::Context;
|
||||||
|
|
||||||
use async_io::Async;
|
use async_io::Async;
|
||||||
use embassy_net::device::{self, Device, DeviceCapabilities, LinkState};
|
use embassy_net_driver::{self, Capabilities, Driver, LinkState};
|
||||||
use log::*;
|
use log::*;
|
||||||
|
|
||||||
pub const SIOCGIFMTU: libc::c_ulong = 0x8921;
|
pub const SIOCGIFMTU: libc::c_ulong = 0x8921;
|
||||||
@ -137,7 +137,7 @@ impl TunTapDevice {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Device for TunTapDevice {
|
impl Driver for TunTapDevice {
|
||||||
type RxToken<'a> = RxToken where Self: 'a;
|
type RxToken<'a> = RxToken where Self: 'a;
|
||||||
type TxToken<'a> = TxToken<'a> where Self: 'a;
|
type TxToken<'a> = TxToken<'a> where Self: 'a;
|
||||||
|
|
||||||
@ -170,8 +170,8 @@ impl Device for TunTapDevice {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn capabilities(&self) -> DeviceCapabilities {
|
fn capabilities(&self) -> Capabilities {
|
||||||
let mut caps = DeviceCapabilities::default();
|
let mut caps = Capabilities::default();
|
||||||
caps.max_transmission_unit = self.device.get_ref().mtu;
|
caps.max_transmission_unit = self.device.get_ref().mtu;
|
||||||
caps
|
caps
|
||||||
}
|
}
|
||||||
@ -190,7 +190,7 @@ pub struct RxToken {
|
|||||||
buffer: Vec<u8>,
|
buffer: Vec<u8>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl device::RxToken for RxToken {
|
impl embassy_net_driver::RxToken for RxToken {
|
||||||
fn consume<R, F>(mut self, f: F) -> R
|
fn consume<R, F>(mut self, f: F) -> R
|
||||||
where
|
where
|
||||||
F: FnOnce(&mut [u8]) -> R,
|
F: FnOnce(&mut [u8]) -> R,
|
||||||
@ -204,7 +204,7 @@ pub struct TxToken<'a> {
|
|||||||
device: &'a mut Async<TunTap>,
|
device: &'a mut Async<TunTap>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> device::TxToken for TxToken<'a> {
|
impl<'a> embassy_net_driver::TxToken for TxToken<'a> {
|
||||||
fn consume<R, F>(self, len: usize, f: F) -> R
|
fn consume<R, F>(self, len: usize, f: F) -> R
|
||||||
where
|
where
|
||||||
F: FnOnce(&mut [u8]) -> R,
|
F: FnOnce(&mut [u8]) -> R,
|
||||||
|
@ -8,8 +8,8 @@ license = "MIT OR Apache-2.0"
|
|||||||
embassy-sync = { version = "0.1.0", path = "../../embassy-sync", features = ["defmt"] }
|
embassy-sync = { version = "0.1.0", path = "../../embassy-sync", features = ["defmt"] }
|
||||||
embassy-executor = { version = "0.1.0", path = "../../embassy-executor", features = ["defmt", "integrated-timers"] }
|
embassy-executor = { version = "0.1.0", path = "../../embassy-executor", features = ["defmt", "integrated-timers"] }
|
||||||
embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
|
embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
|
||||||
embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "embassy-net", "stm32f767zi", "unstable-pac", "time-driver-any", "exti"] }
|
embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "stm32f767zi", "unstable-pac", "time-driver-any", "exti"] }
|
||||||
embassy-net = { path = "../../embassy-net", features = ["defmt", "nightly", "tcp", "dhcpv4", "medium-ethernet", "pool-16"] }
|
embassy-net = { path = "../../embassy-net", features = ["defmt", "nightly", "tcp", "dhcpv4", "medium-ethernet"] }
|
||||||
embedded-io = { version = "0.4.0", features = ["async"] }
|
embedded-io = { version = "0.4.0", features = ["async"] }
|
||||||
|
|
||||||
defmt = "0.3"
|
defmt = "0.3"
|
||||||
|
@ -8,8 +8,8 @@ license = "MIT OR Apache-2.0"
|
|||||||
embassy-sync = { version = "0.1.0", path = "../../embassy-sync", features = ["defmt"] }
|
embassy-sync = { version = "0.1.0", path = "../../embassy-sync", features = ["defmt"] }
|
||||||
embassy-executor = { version = "0.1.0", path = "../../embassy-executor", features = ["defmt", "integrated-timers"] }
|
embassy-executor = { version = "0.1.0", path = "../../embassy-executor", features = ["defmt", "integrated-timers"] }
|
||||||
embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "unstable-traits", "tick-hz-32_768"] }
|
embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "unstable-traits", "tick-hz-32_768"] }
|
||||||
embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "stm32h743bi", "embassy-net", "time-driver-any", "exti", "unstable-pac", "unstable-traits"] }
|
embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "stm32h743bi", "time-driver-any", "exti", "unstable-pac", "unstable-traits"] }
|
||||||
embassy-net = { path = "../../embassy-net", features = ["defmt", "nightly", "tcp", "dhcpv4", "medium-ethernet", "pool-16", "unstable-traits"] }
|
embassy-net = { path = "../../embassy-net", features = ["defmt", "nightly", "tcp", "dhcpv4", "medium-ethernet", "unstable-traits"] }
|
||||||
embedded-io = { version = "0.4.0", features = ["async"] }
|
embedded-io = { version = "0.4.0", features = ["async"] }
|
||||||
|
|
||||||
defmt = "0.3"
|
defmt = "0.3"
|
||||||
|
@ -11,8 +11,8 @@ embassy-sync = { version = "0.1.0", path = "../../embassy-sync", features = ["de
|
|||||||
embassy-executor = { version = "0.1.0", path = "../../embassy-executor", features = ["defmt", "integrated-timers"] }
|
embassy-executor = { version = "0.1.0", path = "../../embassy-executor", features = ["defmt", "integrated-timers"] }
|
||||||
embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
|
embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
|
||||||
embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "unstable-pac", "stm32l552ze", "time-driver-any", "exti", "unstable-traits", "memory-x"] }
|
embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "unstable-pac", "stm32l552ze", "time-driver-any", "exti", "unstable-traits", "memory-x"] }
|
||||||
embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt", "embassy-net"] }
|
embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] }
|
||||||
embassy-net = { version = "0.1.0", path = "../../embassy-net", features = ["defmt", "nightly", "tcp", "dhcpv4", "medium-ethernet", "pool-16"] }
|
embassy-net = { version = "0.1.0", path = "../../embassy-net", features = ["defmt", "nightly", "tcp", "dhcpv4", "medium-ethernet"] }
|
||||||
embassy-futures = { version = "0.1.0", path = "../../embassy-futures" }
|
embassy-futures = { version = "0.1.0", path = "../../embassy-futures" }
|
||||||
usbd-hid = "0.6.0"
|
usbd-hid = "0.6.0"
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user