stm32_eth/dma/
smoltcp_phy.rs

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