| 
							
							
							
						 |  |  | @@ -1,5 +1,6 @@ | 
		
	
		
			
				|  |  |  |  | #![no_std] | 
		
	
		
			
				|  |  |  |  | #![doc = include_str!("../README.md")] | 
		
	
		
			
				|  |  |  |  | #![warn(missing_docs)] | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | // must go first! | 
		
	
		
			
				|  |  |  |  | mod fmt; | 
		
	
	
		
			
				
					
					|  |  |  | @@ -15,6 +16,9 @@ use embassy_sync::blocking_mutex::Mutex; | 
		
	
		
			
				|  |  |  |  | use embassy_sync::waitqueue::WakerRegistration; | 
		
	
		
			
				|  |  |  |  | use embassy_sync::zerocopy_channel; | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | /// Channel state. | 
		
	
		
			
				|  |  |  |  | /// | 
		
	
		
			
				|  |  |  |  | /// Holds a buffer of packets with size MTU, for both TX and RX. | 
		
	
		
			
				|  |  |  |  | pub struct State<const MTU: usize, const N_RX: usize, const N_TX: usize> { | 
		
	
		
			
				|  |  |  |  |     rx: [PacketBuf<MTU>; N_RX], | 
		
	
		
			
				|  |  |  |  |     tx: [PacketBuf<MTU>; N_TX], | 
		
	
	
		
			
				
					
					|  |  |  | @@ -24,6 +28,7 @@ pub struct State<const MTU: usize, const N_RX: usize, const N_TX: usize> { | 
		
	
		
			
				|  |  |  |  | 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(); | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  |     /// Create a new channel state. | 
		
	
		
			
				|  |  |  |  |     pub const fn new() -> Self { | 
		
	
		
			
				|  |  |  |  |         Self { | 
		
	
		
			
				|  |  |  |  |             rx: [Self::NEW_PACKET; N_RX], | 
		
	
	
		
			
				
					
					|  |  |  | @@ -39,33 +44,45 @@ struct StateInner<'d, const MTU: usize> { | 
		
	
		
			
				|  |  |  |  |     shared: Mutex<NoopRawMutex, RefCell<Shared>>, | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | /// State of the LinkState | 
		
	
		
			
				|  |  |  |  | struct Shared { | 
		
	
		
			
				|  |  |  |  |     link_state: LinkState, | 
		
	
		
			
				|  |  |  |  |     waker: WakerRegistration, | 
		
	
		
			
				|  |  |  |  |     hardware_address: driver::HardwareAddress, | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | /// Channel runner. | 
		
	
		
			
				|  |  |  |  | /// | 
		
	
		
			
				|  |  |  |  | /// Holds the shared state and the lower end of channels for inbound and outbound packets. | 
		
	
		
			
				|  |  |  |  | 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>>, | 
		
	
		
			
				|  |  |  |  |     shared: &'d Mutex<NoopRawMutex, RefCell<Shared>>, | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | /// State runner. | 
		
	
		
			
				|  |  |  |  | /// | 
		
	
		
			
				|  |  |  |  | /// Holds the shared state of the channel such as link state. | 
		
	
		
			
				|  |  |  |  | #[derive(Clone, Copy)] | 
		
	
		
			
				|  |  |  |  | pub struct StateRunner<'d> { | 
		
	
		
			
				|  |  |  |  |     shared: &'d Mutex<NoopRawMutex, RefCell<Shared>>, | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | /// RX runner. | 
		
	
		
			
				|  |  |  |  | /// | 
		
	
		
			
				|  |  |  |  | /// Holds the lower end of the channel for passing inbound packets up the stack. | 
		
	
		
			
				|  |  |  |  | pub struct RxRunner<'d, const MTU: usize> { | 
		
	
		
			
				|  |  |  |  |     rx_chan: zerocopy_channel::Sender<'d, NoopRawMutex, PacketBuf<MTU>>, | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | /// TX runner. | 
		
	
		
			
				|  |  |  |  | /// | 
		
	
		
			
				|  |  |  |  | /// Holds the lower end of the channel for passing outbound packets down the stack. | 
		
	
		
			
				|  |  |  |  | pub struct TxRunner<'d, const MTU: usize> { | 
		
	
		
			
				|  |  |  |  |     tx_chan: zerocopy_channel::Receiver<'d, NoopRawMutex, PacketBuf<MTU>>, | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | impl<'d, const MTU: usize> Runner<'d, MTU> { | 
		
	
		
			
				|  |  |  |  |     /// Split the runner into separate runners for controlling state, rx and tx. | 
		
	
		
			
				|  |  |  |  |     pub fn split(self) -> (StateRunner<'d>, RxRunner<'d, MTU>, TxRunner<'d, MTU>) { | 
		
	
		
			
				|  |  |  |  |         ( | 
		
	
		
			
				|  |  |  |  |             StateRunner { shared: self.shared }, | 
		
	
	
		
			
				
					
					|  |  |  | @@ -74,6 +91,7 @@ impl<'d, const MTU: usize> Runner<'d, MTU> { | 
		
	
		
			
				|  |  |  |  |         ) | 
		
	
		
			
				|  |  |  |  |     } | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  |     /// Split the runner into separate runners for controlling state, rx and tx borrowing the underlying state. | 
		
	
		
			
				|  |  |  |  |     pub fn borrow_split(&mut self) -> (StateRunner<'_>, RxRunner<'_, MTU>, TxRunner<'_, MTU>) { | 
		
	
		
			
				|  |  |  |  |         ( | 
		
	
		
			
				|  |  |  |  |             StateRunner { shared: self.shared }, | 
		
	
	
		
			
				
					
					|  |  |  | @@ -86,10 +104,12 @@ impl<'d, const MTU: usize> Runner<'d, MTU> { | 
		
	
		
			
				|  |  |  |  |         ) | 
		
	
		
			
				|  |  |  |  |     } | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  |     /// Create a state runner sharing the state channel. | 
		
	
		
			
				|  |  |  |  |     pub fn state_runner(&self) -> StateRunner<'d> { | 
		
	
		
			
				|  |  |  |  |         StateRunner { shared: self.shared } | 
		
	
		
			
				|  |  |  |  |     } | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  |     /// Set the link state. | 
		
	
		
			
				|  |  |  |  |     pub fn set_link_state(&mut self, state: LinkState) { | 
		
	
		
			
				|  |  |  |  |         self.shared.lock(|s| { | 
		
	
		
			
				|  |  |  |  |             let s = &mut *s.borrow_mut(); | 
		
	
	
		
			
				
					
					|  |  |  | @@ -98,6 +118,7 @@ impl<'d, const MTU: usize> Runner<'d, MTU> { | 
		
	
		
			
				|  |  |  |  |         }); | 
		
	
		
			
				|  |  |  |  |     } | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  |     /// Set the hardware address. | 
		
	
		
			
				|  |  |  |  |     pub fn set_hardware_address(&mut self, address: driver::HardwareAddress) { | 
		
	
		
			
				|  |  |  |  |         self.shared.lock(|s| { | 
		
	
		
			
				|  |  |  |  |             let s = &mut *s.borrow_mut(); | 
		
	
	
		
			
				
					
					|  |  |  | @@ -106,16 +127,19 @@ impl<'d, const MTU: usize> Runner<'d, MTU> { | 
		
	
		
			
				|  |  |  |  |         }); | 
		
	
		
			
				|  |  |  |  |     } | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  |     /// Wait until there is space for more inbound packets and return a slice they can be copied into. | 
		
	
		
			
				|  |  |  |  |     pub async fn rx_buf(&mut self) -> &mut [u8] { | 
		
	
		
			
				|  |  |  |  |         let p = self.rx_chan.send().await; | 
		
	
		
			
				|  |  |  |  |         &mut p.buf | 
		
	
		
			
				|  |  |  |  |     } | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  |     /// Check if there is space for more inbound packets right now. | 
		
	
		
			
				|  |  |  |  |     pub fn try_rx_buf(&mut self) -> Option<&mut [u8]> { | 
		
	
		
			
				|  |  |  |  |         let p = self.rx_chan.try_send()?; | 
		
	
		
			
				|  |  |  |  |         Some(&mut p.buf) | 
		
	
		
			
				|  |  |  |  |     } | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  |     /// Polling the inbound channel if there is space for packets. | 
		
	
		
			
				|  |  |  |  |     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), | 
		
	
	
		
			
				
					
					|  |  |  | @@ -123,22 +147,26 @@ impl<'d, const MTU: usize> Runner<'d, MTU> { | 
		
	
		
			
				|  |  |  |  |         } | 
		
	
		
			
				|  |  |  |  |     } | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  |     /// Mark packet of len bytes as pushed to the inbound channel. | 
		
	
		
			
				|  |  |  |  |     pub fn rx_done(&mut self, len: usize) { | 
		
	
		
			
				|  |  |  |  |         let p = self.rx_chan.try_send().unwrap(); | 
		
	
		
			
				|  |  |  |  |         p.len = len; | 
		
	
		
			
				|  |  |  |  |         self.rx_chan.send_done(); | 
		
	
		
			
				|  |  |  |  |     } | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  |     /// Wait until there is space for more outbound packets and return a slice they can be copied into. | 
		
	
		
			
				|  |  |  |  |     pub async fn tx_buf(&mut self) -> &mut [u8] { | 
		
	
		
			
				|  |  |  |  |         let p = self.tx_chan.receive().await; | 
		
	
		
			
				|  |  |  |  |         &mut p.buf[..p.len] | 
		
	
		
			
				|  |  |  |  |     } | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  |     /// Check if there is space for more outbound packets right now. | 
		
	
		
			
				|  |  |  |  |     pub fn try_tx_buf(&mut self) -> Option<&mut [u8]> { | 
		
	
		
			
				|  |  |  |  |         let p = self.tx_chan.try_receive()?; | 
		
	
		
			
				|  |  |  |  |         Some(&mut p.buf[..p.len]) | 
		
	
		
			
				|  |  |  |  |     } | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  |     /// Polling the outbound channel if there is space for packets. | 
		
	
		
			
				|  |  |  |  |     pub fn poll_tx_buf(&mut self, cx: &mut Context) -> Poll<&mut [u8]> { | 
		
	
		
			
				|  |  |  |  |         match self.tx_chan.poll_receive(cx) { | 
		
	
		
			
				|  |  |  |  |             Poll::Ready(p) => Poll::Ready(&mut p.buf[..p.len]), | 
		
	
	
		
			
				
					
					|  |  |  | @@ -146,12 +174,14 @@ impl<'d, const MTU: usize> Runner<'d, MTU> { | 
		
	
		
			
				|  |  |  |  |         } | 
		
	
		
			
				|  |  |  |  |     } | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  |     /// Mark outbound packet as copied. | 
		
	
		
			
				|  |  |  |  |     pub fn tx_done(&mut self) { | 
		
	
		
			
				|  |  |  |  |         self.tx_chan.receive_done(); | 
		
	
		
			
				|  |  |  |  |     } | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | impl<'d> StateRunner<'d> { | 
		
	
		
			
				|  |  |  |  |     /// Set link state. | 
		
	
		
			
				|  |  |  |  |     pub fn set_link_state(&self, state: LinkState) { | 
		
	
		
			
				|  |  |  |  |         self.shared.lock(|s| { | 
		
	
		
			
				|  |  |  |  |             let s = &mut *s.borrow_mut(); | 
		
	
	
		
			
				
					
					|  |  |  | @@ -160,6 +190,7 @@ impl<'d> StateRunner<'d> { | 
		
	
		
			
				|  |  |  |  |         }); | 
		
	
		
			
				|  |  |  |  |     } | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  |     /// Set the hardware address. | 
		
	
		
			
				|  |  |  |  |     pub fn set_hardware_address(&self, address: driver::HardwareAddress) { | 
		
	
		
			
				|  |  |  |  |         self.shared.lock(|s| { | 
		
	
		
			
				|  |  |  |  |             let s = &mut *s.borrow_mut(); | 
		
	
	
		
			
				
					
					|  |  |  | @@ -170,16 +201,19 @@ impl<'d> StateRunner<'d> { | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | impl<'d, const MTU: usize> RxRunner<'d, MTU> { | 
		
	
		
			
				|  |  |  |  |     /// Wait until there is space for more inbound packets and return a slice they can be copied into. | 
		
	
		
			
				|  |  |  |  |     pub async fn rx_buf(&mut self) -> &mut [u8] { | 
		
	
		
			
				|  |  |  |  |         let p = self.rx_chan.send().await; | 
		
	
		
			
				|  |  |  |  |         &mut p.buf | 
		
	
		
			
				|  |  |  |  |     } | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  |     /// Check if there is space for more inbound packets right now. | 
		
	
		
			
				|  |  |  |  |     pub fn try_rx_buf(&mut self) -> Option<&mut [u8]> { | 
		
	
		
			
				|  |  |  |  |         let p = self.rx_chan.try_send()?; | 
		
	
		
			
				|  |  |  |  |         Some(&mut p.buf) | 
		
	
		
			
				|  |  |  |  |     } | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  |     /// Polling the inbound channel if there is space for packets. | 
		
	
		
			
				|  |  |  |  |     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), | 
		
	
	
		
			
				
					
					|  |  |  | @@ -187,6 +221,7 @@ impl<'d, const MTU: usize> RxRunner<'d, MTU> { | 
		
	
		
			
				|  |  |  |  |         } | 
		
	
		
			
				|  |  |  |  |     } | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  |     /// Mark packet of len bytes as pushed to the inbound channel. | 
		
	
		
			
				|  |  |  |  |     pub fn rx_done(&mut self, len: usize) { | 
		
	
		
			
				|  |  |  |  |         let p = self.rx_chan.try_send().unwrap(); | 
		
	
		
			
				|  |  |  |  |         p.len = len; | 
		
	
	
		
			
				
					
					|  |  |  | @@ -195,16 +230,19 @@ impl<'d, const MTU: usize> RxRunner<'d, MTU> { | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | impl<'d, const MTU: usize> TxRunner<'d, MTU> { | 
		
	
		
			
				|  |  |  |  |     /// Wait until there is space for more outbound packets and return a slice they can be copied into. | 
		
	
		
			
				|  |  |  |  |     pub async fn tx_buf(&mut self) -> &mut [u8] { | 
		
	
		
			
				|  |  |  |  |         let p = self.tx_chan.receive().await; | 
		
	
		
			
				|  |  |  |  |         &mut p.buf[..p.len] | 
		
	
		
			
				|  |  |  |  |     } | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  |     /// Check if there is space for more outbound packets right now. | 
		
	
		
			
				|  |  |  |  |     pub fn try_tx_buf(&mut self) -> Option<&mut [u8]> { | 
		
	
		
			
				|  |  |  |  |         let p = self.tx_chan.try_receive()?; | 
		
	
		
			
				|  |  |  |  |         Some(&mut p.buf[..p.len]) | 
		
	
		
			
				|  |  |  |  |     } | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  |     /// Polling the outbound channel if there is space for packets. | 
		
	
		
			
				|  |  |  |  |     pub fn poll_tx_buf(&mut self, cx: &mut Context) -> Poll<&mut [u8]> { | 
		
	
		
			
				|  |  |  |  |         match self.tx_chan.poll_receive(cx) { | 
		
	
		
			
				|  |  |  |  |             Poll::Ready(p) => Poll::Ready(&mut p.buf[..p.len]), | 
		
	
	
		
			
				
					
					|  |  |  | @@ -212,11 +250,18 @@ impl<'d, const MTU: usize> TxRunner<'d, MTU> { | 
		
	
		
			
				|  |  |  |  |         } | 
		
	
		
			
				|  |  |  |  |     } | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  |     /// Mark outbound packet as copied. | 
		
	
		
			
				|  |  |  |  |     pub fn tx_done(&mut self) { | 
		
	
		
			
				|  |  |  |  |         self.tx_chan.receive_done(); | 
		
	
		
			
				|  |  |  |  |     } | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | /// Create a channel. | 
		
	
		
			
				|  |  |  |  | /// | 
		
	
		
			
				|  |  |  |  | /// Returns a pair of handles for interfacing with the peripheral and the networking stack. | 
		
	
		
			
				|  |  |  |  | /// | 
		
	
		
			
				|  |  |  |  | /// The runner is interfacing with the peripheral at the lower part of the stack. | 
		
	
		
			
				|  |  |  |  | /// The device is interfacing with the networking stack on the layer above. | 
		
	
		
			
				|  |  |  |  | pub fn new<'d, const MTU: usize, const N_RX: usize, const N_TX: usize>( | 
		
	
		
			
				|  |  |  |  |     state: &'d mut State<MTU, N_RX, N_TX>, | 
		
	
		
			
				|  |  |  |  |     hardware_address: driver::HardwareAddress, | 
		
	
	
		
			
				
					
					|  |  |  | @@ -257,17 +302,22 @@ pub fn new<'d, const MTU: usize, const N_RX: usize, const N_TX: usize>( | 
		
	
		
			
				|  |  |  |  |     ) | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | /// Represents a packet of size MTU. | 
		
	
		
			
				|  |  |  |  | pub struct PacketBuf<const MTU: usize> { | 
		
	
		
			
				|  |  |  |  |     len: usize, | 
		
	
		
			
				|  |  |  |  |     buf: [u8; MTU], | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | impl<const MTU: usize> PacketBuf<MTU> { | 
		
	
		
			
				|  |  |  |  |     /// Create a new packet buffer. | 
		
	
		
			
				|  |  |  |  |     pub const fn new() -> Self { | 
		
	
		
			
				|  |  |  |  |         Self { len: 0, buf: [0; MTU] } | 
		
	
		
			
				|  |  |  |  |     } | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | /// Channel device. | 
		
	
		
			
				|  |  |  |  | /// | 
		
	
		
			
				|  |  |  |  | /// Holds the shared state and upper end of channels for inbound and outbound packets. | 
		
	
		
			
				|  |  |  |  | pub struct Device<'d, const MTU: usize> { | 
		
	
		
			
				|  |  |  |  |     rx: zerocopy_channel::Receiver<'d, NoopRawMutex, PacketBuf<MTU>>, | 
		
	
		
			
				|  |  |  |  |     tx: zerocopy_channel::Sender<'d, NoopRawMutex, PacketBuf<MTU>>, | 
		
	
	
		
			
				
					
					|  |  |  | @@ -314,6 +364,9 @@ impl<'d, const MTU: usize> embassy_net_driver::Driver for Device<'d, MTU> { | 
		
	
		
			
				|  |  |  |  |     } | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | /// A rx token. | 
		
	
		
			
				|  |  |  |  | /// | 
		
	
		
			
				|  |  |  |  | /// Holds inbound receive channel and interfaces with embassy-net-driver. | 
		
	
		
			
				|  |  |  |  | pub struct RxToken<'a, const MTU: usize> { | 
		
	
		
			
				|  |  |  |  |     rx: zerocopy_channel::Receiver<'a, NoopRawMutex, PacketBuf<MTU>>, | 
		
	
		
			
				|  |  |  |  | } | 
		
	
	
		
			
				
					
					|  |  |  | @@ -331,6 +384,9 @@ impl<'a, const MTU: usize> embassy_net_driver::RxToken for RxToken<'a, MTU> { | 
		
	
		
			
				|  |  |  |  |     } | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | /// A tx token. | 
		
	
		
			
				|  |  |  |  | /// | 
		
	
		
			
				|  |  |  |  | /// Holds outbound transmit channel and interfaces with embassy-net-driver. | 
		
	
		
			
				|  |  |  |  | pub struct TxToken<'a, const MTU: usize> { | 
		
	
		
			
				|  |  |  |  |     tx: zerocopy_channel::Sender<'a, NoopRawMutex, PacketBuf<MTU>>, | 
		
	
		
			
				|  |  |  |  | } | 
		
	
	
		
			
				
					
					|  |  |  |   |