stm32_eth/dma/
smoltcp_phy.rs

1use crate::dma::RxError;
2
3use super::rx::RxRing;
4use super::tx::TxRing;
5use super::EthernetDMA;
6
7#[cfg(feature = "ptp")]
8use super::PacketId;
9
10use smoltcp::phy::{ChecksumCapabilities, Device, DeviceCapabilities, RxToken, TxToken};
11use smoltcp::time::Instant;
12
13/// Use this Ethernet driver with [smoltcp](https://github.com/smoltcp-rs/smoltcp)
14impl<'a, 'rx, 'tx> Device for &'a mut EthernetDMA<'rx, 'tx> {
15    type RxToken<'token>
16        = EthRxToken<'token, 'rx>
17    where
18        Self: 'token;
19    type TxToken<'token>
20        = EthTxToken<'token, 'tx>
21    where
22        Self: 'token;
23
24    fn capabilities(&self) -> DeviceCapabilities {
25        let mut caps = DeviceCapabilities::default();
26        caps.max_transmission_unit = crate::dma::MTU;
27        caps.max_burst_size = Some(1);
28        caps.checksum = ChecksumCapabilities::ignored();
29        caps
30    }
31
32    fn receive(&mut self, _timestamp: Instant) -> Option<(Self::RxToken<'_>, Self::TxToken<'_>)> {
33        if self.tx_available() && self.rx_available() {
34            #[cfg(feature = "ptp")]
35            let rx_packet_id = self.next_packet_id();
36
37            let EthernetDMA {
38                rx_ring, tx_ring, ..
39            } = self;
40
41            let rx = EthRxToken {
42                rx_ring,
43                #[cfg(feature = "ptp")]
44                meta: rx_packet_id,
45            };
46
47            let tx = EthTxToken {
48                tx_ring,
49                #[cfg(feature = "ptp")]
50                meta: None,
51            };
52            Some((rx, tx))
53        } else {
54            None
55        }
56    }
57
58    fn transmit(&mut self, _timestamp: Instant) -> Option<Self::TxToken<'_>> {
59        if self.tx_available() {
60            let EthernetDMA { tx_ring, .. } = self;
61            Some(EthTxToken {
62                tx_ring,
63                #[cfg(feature = "ptp")]
64                meta: None,
65            })
66        } else {
67            None
68        }
69    }
70}
71
72/// An Ethernet RX token that can be consumed in order to receive
73/// an ethernet packet.
74pub struct EthRxToken<'a, 'rx> {
75    rx_ring: &'a mut RxRing<'rx>,
76    #[cfg(feature = "ptp")]
77    meta: PacketId,
78}
79
80impl<'dma, 'rx> RxToken for EthRxToken<'dma, 'rx> {
81    fn consume<R, F>(self, f: F) -> R
82    where
83        F: FnOnce(&[u8]) -> R,
84    {
85        #[cfg(feature = "ptp")]
86        let meta = Some(self.meta.into());
87
88        #[cfg(not(feature = "ptp"))]
89        let meta = None;
90
91        match self.rx_ring.recv_next(meta) {
92            Ok(v) => {
93                let result = f(&v);
94                v.free();
95                result
96            }
97            Err(RxError::WouldBlock) => {
98                #[cfg(feature = "defmt")]
99                defmt::error!("EthRxToken: RX would block");
100                f(&[])
101            }
102            Err(_e) => {
103                #[cfg(feature = "defmt")]
104                defmt::debug!("Failed to receive packet: {}", _e);
105                f(&[])
106            }
107        }
108    }
109
110    #[cfg(feature = "ptp")]
111    fn meta(&self) -> smoltcp::phy::PacketMeta {
112        self.meta.clone().into()
113    }
114}
115
116/// Just a reference to [`EthernetDMA`] for sending a
117/// packet later with [`TxToken::consume()`].
118pub struct EthTxToken<'a, 'tx> {
119    tx_ring: &'a mut TxRing<'tx>,
120    #[cfg(feature = "ptp")]
121    meta: Option<PacketId>,
122}
123
124impl<'dma, 'tx> TxToken for EthTxToken<'dma, 'tx> {
125    fn consume<R, F>(self, len: usize, f: F) -> R
126    where
127        F: FnOnce(&mut [u8]) -> R,
128    {
129        #[cfg(feature = "ptp")]
130        let meta = self.meta.map(Into::into);
131        #[cfg(not(feature = "ptp"))]
132        let meta = None;
133
134        // NOTE(unwrap): an `EthTxToken` is only created if
135        // there is a descriptor available for sending.
136        let mut tx_packet = self.tx_ring.send_next(len, meta).ok().unwrap();
137        let res = f(&mut tx_packet);
138        tx_packet.send();
139        res
140    }
141
142    #[cfg(feature = "ptp")]
143    fn set_meta(&mut self, meta: smoltcp::phy::PacketMeta) {
144        self.meta = Some(meta.into());
145    }
146}