aboutsummaryrefslogtreecommitdiff
path: root/embassy-net-enc28j60/src/lib.rs
diff options
context:
space:
mode:
Diffstat (limited to 'embassy-net-enc28j60/src/lib.rs')
-rw-r--r--embassy-net-enc28j60/src/lib.rs693
1 files changed, 693 insertions, 0 deletions
diff --git a/embassy-net-enc28j60/src/lib.rs b/embassy-net-enc28j60/src/lib.rs
new file mode 100644
index 000000000..4f129b6b2
--- /dev/null
+++ b/embassy-net-enc28j60/src/lib.rs
@@ -0,0 +1,693 @@
1#![no_std]
2#![doc = include_str!("../README.md")]
3
4// must go first.
5mod fmt;
6
7#[macro_use]
8mod macros;
9mod bank0;
10mod bank1;
11mod bank2;
12mod bank3;
13mod common;
14mod header;
15mod phy;
16mod traits;
17
18use core::cmp;
19use core::convert::TryInto;
20
21use embassy_net_driver::{Capabilities, HardwareAddress, LinkState, Medium};
22use embassy_time::Duration;
23use embedded_hal::digital::OutputPin;
24use embedded_hal::spi::{Operation, SpiDevice};
25use traits::U16Ext;
26
27// Total buffer size (see section 3.2)
28const BUF_SZ: u16 = 8 * 1024;
29
30// Maximum frame length
31const MAX_FRAME_LENGTH: u16 = 1518; // value recommended in the data sheet
32
33// Size of the Frame check sequence (32-bit CRC)
34const CRC_SZ: u16 = 4;
35
36// define the boundaries of the TX and RX buffers
37// to workaround errata #5 we do the opposite of what section 6.1 of the data sheet
38// says: we place the RX buffer at address 0 and the TX buffer after it
39const RXST: u16 = 0x0000;
40const RXND: u16 = 0x19ff;
41const TXST: u16 = 0x1a00;
42const _TXND: u16 = 0x1fff;
43
44const MTU: usize = 1514; // 1500 IP + 14 ethernet header
45
46pub struct Enc28j60<S, O> {
47 mac_addr: [u8; 6],
48
49 spi: S,
50 rst: Option<O>,
51
52 bank: Bank,
53
54 // address of the next packet in buffer memory
55 next_packet: u16,
56}
57
58impl<S, O> Enc28j60<S, O>
59where
60 S: SpiDevice,
61 O: OutputPin,
62{
63 pub fn new(spi: S, rst: Option<O>, mac_addr: [u8; 6]) -> Self {
64 let mut res = Self {
65 mac_addr,
66 spi,
67 rst,
68
69 bank: Bank::Bank0,
70 next_packet: RXST,
71 };
72 res.init();
73 res
74 }
75
76 fn init(&mut self) {
77 if let Some(rst) = &mut self.rst {
78 rst.set_low().unwrap();
79 embassy_time::block_for(Duration::from_millis(5));
80 rst.set_high().unwrap();
81 embassy_time::block_for(Duration::from_millis(5));
82 } else {
83 embassy_time::block_for(Duration::from_millis(5));
84 self.soft_reset();
85 embassy_time::block_for(Duration::from_millis(5));
86 }
87
88 debug!(
89 "enc28j60: erevid {=u8:x}",
90 self.read_control_register(bank3::Register::EREVID)
91 );
92 debug!("enc28j60: waiting for clk");
93 while common::ESTAT(self.read_control_register(common::Register::ESTAT)).clkrdy() == 0 {}
94 debug!("enc28j60: clk ok");
95
96 if self.read_control_register(bank3::Register::EREVID) == 0 {
97 panic!("ErevidIsZero");
98 }
99
100 // disable CLKOUT output
101 self.write_control_register(bank3::Register::ECOCON, 0);
102
103 // RX start
104 // "It is recommended that the ERXST Pointer be programmed with an even address"
105 self.write_control_register(bank0::Register::ERXSTL, RXST.low());
106 self.write_control_register(bank0::Register::ERXSTH, RXST.high());
107
108 // RX read pointer
109 // NOTE Errata #14 so we are using an *odd* address here instead of ERXST
110 self.write_control_register(bank0::Register::ERXRDPTL, RXND.low());
111 self.write_control_register(bank0::Register::ERXRDPTH, RXND.high());
112
113 // RX end
114 self.write_control_register(bank0::Register::ERXNDL, RXND.low());
115 self.write_control_register(bank0::Register::ERXNDH, RXND.high());
116
117 // TX start
118 // "It is recommended that an even address be used for ETXST"
119 debug_assert_eq!(TXST % 2, 0);
120 self.write_control_register(bank0::Register::ETXSTL, TXST.low());
121 self.write_control_register(bank0::Register::ETXSTH, TXST.high());
122
123 // TX end is set in `transmit`
124
125 // MAC initialization (see section 6.5)
126 // 1. Set the MARXEN bit in MACON1 to enable the MAC to receive frames.
127 self.write_control_register(
128 bank2::Register::MACON1,
129 bank2::MACON1::default().marxen(1).passall(0).rxpaus(1).txpaus(1).bits(),
130 );
131
132 // 2. Configure the PADCFG, TXCRCEN and FULDPX bits of MACON3.
133 self.write_control_register(
134 bank2::Register::MACON3,
135 bank2::MACON3::default().frmlnen(1).txcrcen(1).padcfg(0b001).bits(),
136 );
137
138 // 4. Program the MAMXFL registers with the maximum frame length to be permitted to be
139 // received or transmitted
140 self.write_control_register(bank2::Register::MAMXFLL, MAX_FRAME_LENGTH.low());
141 self.write_control_register(bank2::Register::MAMXFLH, MAX_FRAME_LENGTH.high());
142
143 // 5. Configure the Back-to-Back Inter-Packet Gap register, MABBIPG.
144 // Use recommended value of 0x12
145 self.write_control_register(bank2::Register::MABBIPG, 0x12);
146
147 // 6. Configure the Non-Back-to-Back Inter-Packet Gap register low byte, MAIPGL.
148 // Use recommended value of 0x12
149 self.write_control_register(bank2::Register::MAIPGL, 0x12);
150 self.write_control_register(bank2::Register::MAIPGH, 0x0c);
151
152 // 9. Program the local MAC address into the MAADR1:MAADR6 registers
153 self.write_control_register(bank3::Register::MAADR1, self.mac_addr[0]);
154 self.write_control_register(bank3::Register::MAADR2, self.mac_addr[1]);
155 self.write_control_register(bank3::Register::MAADR3, self.mac_addr[2]);
156 self.write_control_register(bank3::Register::MAADR4, self.mac_addr[3]);
157 self.write_control_register(bank3::Register::MAADR5, self.mac_addr[4]);
158 self.write_control_register(bank3::Register::MAADR6, self.mac_addr[5]);
159
160 // Set the PHCON2.HDLDIS bit to prevent automatic loopback of the data which is transmitted
161 self.write_phy_register(phy::Register::PHCON2, phy::PHCON2::default().hdldis(1).bits());
162
163 // Globally enable interrupts
164 //self.bit_field_set(common::Register::EIE, common::EIE::mask().intie());
165
166 // Set the per packet control byte; we'll always use the value 0
167 self.write_buffer_memory(Some(TXST), &mut [0]);
168
169 // decrease the packet count to 0
170 while self.read_control_register(bank1::Register::EPKTCNT) != 0 {
171 self.bit_field_set(common::Register::ECON2, common::ECON2::mask().pktdec());
172 }
173
174 // Enable reception
175 self.bit_field_set(common::Register::ECON1, common::ECON1::mask().rxen());
176 }
177
178 /// Flushes the transmit buffer, ensuring all pending transmissions have completed
179 /// NOTE: The returned packet *must* be `read` or `ignore`-d, otherwise this method will always
180 /// return `None` on subsequent invocations
181 pub fn receive<'a>(&mut self, buf: &'a mut [u8]) -> Option<&'a mut [u8]> {
182 if self.pending_packets() == 0 {
183 // Errata #6: we can't rely on PKTIF so we check PKTCNT
184 return None;
185 }
186
187 let curr_packet = self.next_packet;
188
189 // read out the first 6 bytes
190 let mut temp_buf = [0; 6];
191 self.read_buffer_memory(Some(curr_packet), &mut temp_buf);
192
193 // next packet pointer
194 let next_packet = u16::from_parts(temp_buf[0], temp_buf[1]);
195 if next_packet > RXND {
196 panic!("CorruptRxBuffer");
197 }
198
199 // status vector
200 let status = header::RxStatus(u32::from_le_bytes(temp_buf[2..].try_into().unwrap()));
201 let len = status.byte_count() as u16 - CRC_SZ;
202
203 if len > RXND {
204 panic!("CorruptRxBuffer 2");
205 }
206
207 self.read_buffer_memory(None, &mut buf[..len as usize]);
208
209 // update ERXRDPT
210 // due to Errata #14 we must write an odd address to ERXRDPT
211 // we know that ERXST = 0, that ERXND is odd and that next_packet is even
212 let rxrdpt = if self.next_packet < 1 || self.next_packet > RXND + 1 {
213 RXND
214 } else {
215 self.next_packet - 1
216 };
217 // "To move ERXRDPT, the host controller must write to ERXRDPTL first."
218 self.write_control_register(bank0::Register::ERXRDPTL, rxrdpt.low());
219 self.write_control_register(bank0::Register::ERXRDPTH, rxrdpt.high());
220
221 // decrease the packet count
222 self.bit_field_set(common::Register::ECON2, common::ECON2::mask().pktdec());
223
224 self.next_packet = next_packet;
225
226 Some(&mut buf[..len as usize])
227 }
228
229 fn wait_tx_ready(&mut self) {
230 for _ in 0u32..10000 {
231 if common::ECON1(self.read_control_register(common::Register::ECON1)).txrts() == 0 {
232 return;
233 }
234 }
235
236 // work around errata #12 by resetting the transmit logic before every new
237 // transmission
238 self.bit_field_set(common::Register::ECON1, common::ECON1::mask().txrst());
239 self.bit_field_clear(common::Register::ECON1, common::ECON1::mask().txrst());
240 //self.bit_field_clear(common::Register::EIR, {
241 // let mask = common::EIR::mask();
242 // mask.txerif() | mask.txif()
243 //});
244 }
245
246 /// Starts the transmission of `bytes`
247 ///
248 /// It's up to the caller to ensure that `bytes` is a valid Ethernet frame. The interface will
249 /// take care of appending a (4 byte) CRC to the frame and of padding the frame to the minimum
250 /// size allowed by the Ethernet specification (64 bytes, or 46 bytes of payload).
251 ///
252 /// NOTE This method will flush any previous transmission that's in progress
253 ///
254 /// # Panics
255 ///
256 /// If `bytes` length is greater than 1514, the maximum frame length allowed by the interface,
257 /// or greater than the transmit buffer
258 pub fn transmit(&mut self, bytes: &[u8]) {
259 assert!(bytes.len() <= self.mtu() as usize);
260
261 self.wait_tx_ready();
262
263 // NOTE the plus one is to not overwrite the per packet control byte
264 let wrpt = TXST + 1;
265
266 // 1. ETXST was set during initialization
267
268 // 2. write the frame to the IC memory
269 self.write_buffer_memory(Some(wrpt), bytes);
270
271 let txnd = wrpt + bytes.len() as u16 - 1;
272
273 // 3. Set the end address of the transmit buffer
274 self.write_control_register(bank0::Register::ETXNDL, txnd.low());
275 self.write_control_register(bank0::Register::ETXNDH, txnd.high());
276
277 // 4. reset interrupt flag
278 //self.bit_field_clear(common::Register::EIR, common::EIR::mask().txif());
279
280 // 5. start transmission
281 self.bit_field_set(common::Register::ECON1, common::ECON1::mask().txrts());
282
283 // Wait until transmission finishes
284 //while common::ECON1(self.read_control_register(common::Register::ECON1)).txrts() == 1 {}
285
286 /*
287 // read the transmit status vector
288 let mut tx_stat = [0; 7];
289 self.read_buffer_memory(None, &mut tx_stat);
290
291 let stat = common::ESTAT(self.read_control_register(common::Register::ESTAT));
292
293 if stat.txabrt() == 1 {
294 // work around errata #12 by reading the transmit status vector
295 if stat.latecol() == 1 || (tx_stat[2] & (1 << 5)) != 0 {
296 panic!("LateCollision")
297 } else {
298 panic!("TransmitAbort")
299 }
300 }*/
301 }
302
303 pub fn is_link_up(&mut self) -> bool {
304 let bits = self.read_phy_register(phy::Register::PHSTAT2);
305 phy::PHSTAT2(bits).lstat() == 1
306 }
307
308 /// Returns the interface Maximum Transmission Unit (MTU)
309 ///
310 /// The value returned by this function will never exceed 1514 bytes. The actual value depends
311 /// on the memory assigned to the transmission buffer when initializing the device
312 pub fn mtu(&self) -> u16 {
313 cmp::min(BUF_SZ - RXND - 1, MAX_FRAME_LENGTH - CRC_SZ)
314 }
315
316 /* Miscellaneous */
317 /// Returns the number of packets that have been received but have not been processed yet
318 pub fn pending_packets(&mut self) -> u8 {
319 self.read_control_register(bank1::Register::EPKTCNT)
320 }
321
322 /// Adjusts the receive filter to *accept* these packet types
323 pub fn accept(&mut self, packets: &[Packet]) {
324 let mask = bank1::ERXFCON::mask();
325 let mut val = 0;
326 for packet in packets {
327 match packet {
328 Packet::Broadcast => val |= mask.bcen(),
329 Packet::Multicast => val |= mask.mcen(),
330 Packet::Unicast => val |= mask.ucen(),
331 }
332 }
333
334 self.bit_field_set(bank1::Register::ERXFCON, val)
335 }
336
337 /// Adjusts the receive filter to *ignore* these packet types
338 pub fn ignore(&mut self, packets: &[Packet]) {
339 let mask = bank1::ERXFCON::mask();
340 let mut val = 0;
341 for packet in packets {
342 match packet {
343 Packet::Broadcast => val |= mask.bcen(),
344 Packet::Multicast => val |= mask.mcen(),
345 Packet::Unicast => val |= mask.ucen(),
346 }
347 }
348
349 self.bit_field_clear(bank1::Register::ERXFCON, val)
350 }
351
352 /* Private */
353 /* Read */
354 fn read_control_register<R>(&mut self, register: R) -> u8
355 where
356 R: Into<Register>,
357 {
358 self._read_control_register(register.into())
359 }
360
361 fn _read_control_register(&mut self, register: Register) -> u8 {
362 self.change_bank(register);
363
364 let mut buffer = [Instruction::RCR.opcode() | register.addr(), 0];
365 self.spi.transfer_in_place(&mut buffer).unwrap();
366
367 buffer[1]
368 }
369
370 fn read_phy_register(&mut self, register: phy::Register) -> u16 {
371 embassy_time::block_for(Duration::from_millis(1));
372
373 // set PHY register address
374 self.write_control_register(bank2::Register::MIREGADR, register.addr());
375
376 // start read operation
377 self.write_control_register(bank2::Register::MICMD, bank2::MICMD::default().miird(1).bits());
378
379 // wait until the read operation finishes
380 while self.read_control_register(bank3::Register::MISTAT) & 0b1 != 0 {}
381
382 let h = self.read_control_register(bank2::Register::MIRDH);
383 let l = self.read_control_register(bank2::Register::MIRDL);
384
385 self.write_control_register(bank2::Register::MICMD, bank2::MICMD::default().miird(0).bits());
386
387 (l as u16) | (h as u16) << 8
388 }
389
390 /* Write */
391 fn _write_control_register(&mut self, register: Register, value: u8) {
392 self.change_bank(register);
393
394 let buffer = [Instruction::WCR.opcode() | register.addr(), value];
395 self.spi.write(&buffer).unwrap();
396 }
397
398 fn write_control_register<R>(&mut self, register: R, value: u8)
399 where
400 R: Into<Register>,
401 {
402 self._write_control_register(register.into(), value)
403 }
404
405 fn write_phy_register(&mut self, register: phy::Register, value: u16) {
406 // set PHY register address
407 self.write_control_register(bank2::Register::MIREGADR, register.addr());
408
409 self.write_control_register(bank2::Register::MIWRL, (value & 0xff) as u8);
410 // this starts the write operation
411 self.write_control_register(bank2::Register::MIWRH, (value >> 8) as u8);
412
413 // wait until the write operation finishes
414 while self.read_control_register(bank3::Register::MISTAT) & 0b1 != 0 {}
415 }
416
417 /* RMW */
418 fn modify_control_register<R, F>(&mut self, register: R, f: F)
419 where
420 F: FnOnce(u8) -> u8,
421 R: Into<Register>,
422 {
423 self._modify_control_register(register.into(), f)
424 }
425
426 fn _modify_control_register<F>(&mut self, register: Register, f: F)
427 where
428 F: FnOnce(u8) -> u8,
429 {
430 let r = self._read_control_register(register);
431 self._write_control_register(register, f(r))
432 }
433
434 /* Auxiliary */
435 fn change_bank(&mut self, register: Register) {
436 let bank = register.bank();
437
438 if let Some(bank) = bank {
439 if self.bank == bank {
440 // already on the register bank
441 return;
442 }
443
444 // change bank
445 self.bank = bank;
446 match bank {
447 Bank::Bank0 => self.bit_field_clear(common::Register::ECON1, 0b11),
448 Bank::Bank1 => self.modify_control_register(common::Register::ECON1, |r| (r & !0b11) | 0b01),
449 Bank::Bank2 => self.modify_control_register(common::Register::ECON1, |r| (r & !0b11) | 0b10),
450 Bank::Bank3 => self.bit_field_set(common::Register::ECON1, 0b11),
451 }
452 } else {
453 // common register
454 }
455 }
456
457 /* Primitive operations */
458 fn bit_field_clear<R>(&mut self, register: R, mask: u8)
459 where
460 R: Into<Register>,
461 {
462 self._bit_field_clear(register.into(), mask)
463 }
464
465 fn _bit_field_clear(&mut self, register: Register, mask: u8) {
466 debug_assert!(register.is_eth_register());
467
468 self.change_bank(register);
469
470 self.spi
471 .write(&[Instruction::BFC.opcode() | register.addr(), mask])
472 .unwrap();
473 }
474
475 fn bit_field_set<R>(&mut self, register: R, mask: u8)
476 where
477 R: Into<Register>,
478 {
479 self._bit_field_set(register.into(), mask)
480 }
481
482 fn _bit_field_set(&mut self, register: Register, mask: u8) {
483 debug_assert!(register.is_eth_register());
484
485 self.change_bank(register);
486
487 self.spi
488 .write(&[Instruction::BFS.opcode() | register.addr(), mask])
489 .unwrap();
490 }
491
492 fn read_buffer_memory(&mut self, addr: Option<u16>, buf: &mut [u8]) {
493 if let Some(addr) = addr {
494 self.write_control_register(bank0::Register::ERDPTL, addr.low());
495 self.write_control_register(bank0::Register::ERDPTH, addr.high());
496 }
497
498 self.spi
499 .transaction(&mut [Operation::Write(&[Instruction::RBM.opcode()]), Operation::Read(buf)])
500 .unwrap();
501 }
502
503 fn soft_reset(&mut self) {
504 self.spi.write(&[Instruction::SRC.opcode()]).unwrap();
505 }
506
507 fn write_buffer_memory(&mut self, addr: Option<u16>, buffer: &[u8]) {
508 if let Some(addr) = addr {
509 self.write_control_register(bank0::Register::EWRPTL, addr.low());
510 self.write_control_register(bank0::Register::EWRPTH, addr.high());
511 }
512
513 self.spi
514 .transaction(&mut [Operation::Write(&[Instruction::WBM.opcode()]), Operation::Write(buffer)])
515 .unwrap();
516 }
517}
518
519#[derive(Clone, Copy, PartialEq)]
520enum Bank {
521 Bank0,
522 Bank1,
523 Bank2,
524 Bank3,
525}
526
527#[derive(Clone, Copy)]
528enum Instruction {
529 /// Read Control Register
530 RCR = 0b000_00000,
531 /// Read Buffer Memory
532 RBM = 0b001_11010,
533 /// Write Control Register
534 WCR = 0b010_00000,
535 /// Write Buffer Memory
536 WBM = 0b011_11010,
537 /// Bit Field Set
538 BFS = 0b100_00000,
539 /// Bit Field Clear
540 BFC = 0b101_00000,
541 /// System Reset Command
542 SRC = 0b111_11111,
543}
544
545impl Instruction {
546 fn opcode(&self) -> u8 {
547 *self as u8
548 }
549}
550
551#[derive(Clone, Copy)]
552enum Register {
553 Bank0(bank0::Register),
554 Bank1(bank1::Register),
555 Bank2(bank2::Register),
556 Bank3(bank3::Register),
557 Common(common::Register),
558}
559
560impl Register {
561 fn addr(&self) -> u8 {
562 match *self {
563 Register::Bank0(r) => r.addr(),
564 Register::Bank1(r) => r.addr(),
565 Register::Bank2(r) => r.addr(),
566 Register::Bank3(r) => r.addr(),
567 Register::Common(r) => r.addr(),
568 }
569 }
570
571 fn bank(&self) -> Option<Bank> {
572 Some(match *self {
573 Register::Bank0(_) => Bank::Bank0,
574 Register::Bank1(_) => Bank::Bank1,
575 Register::Bank2(_) => Bank::Bank2,
576 Register::Bank3(_) => Bank::Bank3,
577 Register::Common(_) => return None,
578 })
579 }
580
581 fn is_eth_register(&self) -> bool {
582 match *self {
583 Register::Bank0(r) => r.is_eth_register(),
584 Register::Bank1(r) => r.is_eth_register(),
585 Register::Bank2(r) => r.is_eth_register(),
586 Register::Bank3(r) => r.is_eth_register(),
587 Register::Common(r) => r.is_eth_register(),
588 }
589 }
590}
591
592/// Packet type, used to configure receive filters
593#[non_exhaustive]
594#[derive(Clone, Copy, Eq, PartialEq)]
595pub enum Packet {
596 /// Broadcast packets
597 Broadcast,
598 /// Multicast packets
599 Multicast,
600 /// Unicast packets
601 Unicast,
602}
603
604static mut TX_BUF: [u8; MTU] = [0; MTU];
605static mut RX_BUF: [u8; MTU] = [0; MTU];
606
607impl<S, O> embassy_net_driver::Driver for Enc28j60<S, O>
608where
609 S: SpiDevice,
610 O: OutputPin,
611{
612 type RxToken<'a> = RxToken<'a>
613 where
614 Self: 'a;
615
616 type TxToken<'a> = TxToken<'a, S, O>
617 where
618 Self: 'a;
619
620 fn receive(&mut self, cx: &mut core::task::Context) -> Option<(Self::RxToken<'_>, Self::TxToken<'_>)> {
621 let rx_buf = unsafe { &mut RX_BUF };
622 let tx_buf = unsafe { &mut TX_BUF };
623 if let Some(pkt) = self.receive(rx_buf) {
624 let n = pkt.len();
625 Some((RxToken { buf: &mut pkt[..n] }, TxToken { buf: tx_buf, eth: self }))
626 } else {
627 cx.waker().wake_by_ref();
628 None
629 }
630 }
631
632 fn transmit(&mut self, _cx: &mut core::task::Context) -> Option<Self::TxToken<'_>> {
633 let tx_buf = unsafe { &mut TX_BUF };
634 Some(TxToken { buf: tx_buf, eth: self })
635 }
636
637 fn link_state(&mut self, cx: &mut core::task::Context) -> LinkState {
638 cx.waker().wake_by_ref();
639 match self.is_link_up() {
640 true => LinkState::Up,
641 false => LinkState::Down,
642 }
643 }
644
645 fn capabilities(&self) -> Capabilities {
646 let mut caps = Capabilities::default();
647 caps.max_transmission_unit = MTU;
648 caps.medium = Medium::Ethernet;
649 caps
650 }
651
652 fn hardware_address(&self) -> HardwareAddress {
653 HardwareAddress::Ethernet(self.mac_addr)
654 }
655}
656
657pub struct RxToken<'a> {
658 buf: &'a mut [u8],
659}
660
661impl<'a> embassy_net_driver::RxToken for RxToken<'a> {
662 fn consume<R, F>(self, f: F) -> R
663 where
664 F: FnOnce(&mut [u8]) -> R,
665 {
666 f(self.buf)
667 }
668}
669
670pub struct TxToken<'a, S, O>
671where
672 S: SpiDevice,
673 O: OutputPin,
674{
675 eth: &'a mut Enc28j60<S, O>,
676 buf: &'a mut [u8],
677}
678
679impl<'a, S, O> embassy_net_driver::TxToken for TxToken<'a, S, O>
680where
681 S: SpiDevice,
682 O: OutputPin,
683{
684 fn consume<R, F>(self, len: usize, f: F) -> R
685 where
686 F: FnOnce(&mut [u8]) -> R,
687 {
688 assert!(len <= self.buf.len());
689 let r = f(&mut self.buf[..len]);
690 self.eth.transmit(&self.buf[..len]);
691 r
692 }
693}