diff --git a/src/eth/mod.rs b/src/eth/mod.rs index 5d108f9d..17c2842b 100644 --- a/src/eth/mod.rs +++ b/src/eth/mod.rs @@ -265,8 +265,12 @@ impl Eth { .speed(true) .no_broadcast(false) .multi_hash_en(true) - // Promiscuous mode + // Promiscuous mode (TODO?) .copy_all(true) + // Remove 4-byte Frame CheckSum + .fcs_remove(true) + // One of the slower speeds + // TODO: calculate properly .mdc_clk_div(0b110) ); @@ -327,14 +331,73 @@ impl Eth { new_self } + // pub fn start_tx<'tx>(self, tx_buffers: [&'tx [u8]; tx::DESCS]) -> Eth> { + // let new_self = Eth { + // regs: self.regs, + // rx: self.rx, + // tx: tx::DescList::new(tx_buffers), + // }; + // let list_addr = &new_self.tx as *const _ as u32; + // assert!(list_addr & 0b11 == 0); + // new_self.regs.tx_qbar.write( + // regs::TxQbar::zeroed() + // .tx_q_baseaddr(list_addr >> 2) + // ); + // new_self.regs.net_ctrl.modify(|_, w| + // w.tx_en(true) + // ); + // new_self + // } + fn wait_phy_idle(&self) { while !self.regs.net_status.read().phy_mgmt_idle() {} } } impl<'rx, TX> Eth, TX> { - pub fn recv_next(&mut self) -> Option { - self.rx.recv_next() + pub fn recv_next(&mut self) -> Result, rx::Error> { + let status = self.regs.rx_status.read(); + if status.hresp_not_ok() { + // Clear + self.regs.rx_status.write( + regs::RxStatus::zeroed() + .hresp_not_ok(true) + ); + return Err(rx::Error::HrespNotOk); + } + if status.rx_overrun() { + // Clear + self.regs.rx_status.write( + regs::RxStatus::zeroed() + .rx_overrun(true) + ); + return Err(rx::Error::RxOverrun); + } + if status.buffer_not_avail() { + // Clear + self.regs.rx_status.write( + regs::RxStatus::zeroed() + .buffer_not_avail(true) + ); + return Err(rx::Error::BufferNotAvail); + } + + if status.frame_recd() { + let result = self.rx.recv_next(); + match result { + Ok(None) => { + // No packet, clear status bit + self.regs.rx_status.write( + regs::RxStatus::zeroed() + .frame_recd(true) + ); + } + _ => {} + } + result + } else { + Ok(None) + } } } diff --git a/src/eth/rx.rs b/src/eth/rx.rs index 896c0ec0..36586bb2 100644 --- a/src/eth/rx.rs +++ b/src/eth/rx.rs @@ -1,6 +1,14 @@ use core::ops::Deref; use crate::{register, register_bit, register_bits, register_bits_typed, regs::*}; +#[derive(Debug)] +pub enum Error { + HrespNotOk, + RxOverrun, + BufferNotAvail, + Truncated, +} + /// Descriptor entry #[repr(C)] pub struct DescEntry { @@ -44,7 +52,6 @@ impl<'a> DescList<'a> { let last = list.len().min(buffers.len()) - 1; for (i, (entry, buffer)) in list.iter_mut().zip(buffers.iter_mut()).enumerate() { let is_last = i == last; - assert!(buffer.len() >= 1536); let buffer_addr = &mut buffer[0] as *mut _ as u32; assert!(buffer_addr & 0b11 == 0); entry.word0.write( @@ -69,13 +76,12 @@ impl<'a> DescList<'a> { &self.list[0] as *const _ as u32 } - pub fn recv_next<'s: 'p, 'p>(&'s mut self) -> Option> { + pub fn recv_next<'s: 'p, 'p>(&'s mut self) -> Result>, Error> { let list_len = self.list.len(); let entry = &mut self.list[self.next]; if entry.word0.read().used() { - let len = entry.word1.read() - .frame_length_lsbs().into(); - // TODO: check no split pkt across multiple buffers + let word1 = entry.word1.read(); + let len = word1.frame_length_lsbs().into(); let buffer = &self.buffers[self.next][0..len]; self.next += 1; @@ -83,9 +89,14 @@ impl<'a> DescList<'a> { self.next = 0; } - Some(PktRef { entry, buffer }) + let pkt = PktRef { entry, buffer }; + if word1.start_of_frame() && word1.end_of_frame() { + Ok(Some(pkt)) + } else { + Err(Error::Truncated) + } } else { - None + Ok(None) } } } diff --git a/src/main.rs b/src/main.rs index c585a7a5..b466b2b0 100644 --- a/src/main.rs +++ b/src/main.rs @@ -98,9 +98,16 @@ fn main() { loop { match eth.recv_next() { - None => {} - Some(pkt) => { - println!("eth: received {} bytes", pkt.len()); + Ok(Some(pkt)) => { + print!("eth: rx {} bytes", pkt.len()); + for b in pkt.iter() { + print!(" {:02X}", b); + } + println!(""); + } + Ok(None) => {} + Err(e) => { + println!("eth rx error: {:?}", e); } } }