#![no_std] use core::fmt; /// STM32F4xx-HAL specific implementations pub mod spi; use stm32f4xx_hal::{ hal::{ blocking::spi::Transfer, digital::v2::OutputPin, } }; pub mod rx; #[cfg(feature="smoltcp")] pub mod smoltcp_phy; pub trait EthController { fn init_dev(&mut self) -> Result<(), EthControllerError>; fn init_rxbuf(&mut self) -> Result<(), EthControllerError>; fn receive_next(&mut self) -> Result; fn set_promiscuous(&mut self) -> Result<(), EthControllerError>; fn read_from_mac(&mut self, mac: &mut [u8]) -> Result<(), EthControllerError>; } /// TODO: Improve these error types pub enum EthControllerError { SpiPortError, GeneralError } impl From for EthControllerError { fn from(e: spi::SpiPortError) -> EthControllerError { EthControllerError::SpiPortError } } /// Ethernet controller using SPI interface pub struct SpiEth, NSS: OutputPin> { spi_port: spi::SpiPort, rx_buf: rx::RxBuffer } impl , NSS: OutputPin> SpiEth { pub fn new(spi: SPI, mut nss: NSS) -> Self { SpiEth { spi_port: spi::SpiPort::new(spi, nss), rx_buf: rx::RxBuffer::new(), // TODO: tx_buf } } } impl , NSS: OutputPin> EthController for SpiEth { fn init_dev(&mut self) -> Result<(), EthControllerError> { // Write 0x1234 to EUDAST self.spi_port.write_reg_16b(spi::EUDAST, 0x1234)?; // Verify that EUDAST is 0x1234 let mut eudast = self.spi_port.read_reg_16b(spi::EUDAST)?; if eudast != 0x1234 { return Err(EthControllerError::GeneralError) } // Poll CLKRDY (ESTAT<12>) to check if it is set loop { let estat = self.spi_port.read_reg_16b(spi::ESTAT)?; if estat & 0x1000 == 0x1000 { break } } // Set ETHRST (ECON2<4>) to 1 let econ2 = self.spi_port.read_reg_8b(spi::ECON2)?; self.spi_port.write_reg_8b(spi::ECON2, 0x10 | (econ2 & 0b11101111))?; // Verify that EUDAST is 0x0000 eudast = self.spi_port.read_reg_16b(spi::EUDAST)?; if eudast != 0x0000 { return Err(EthControllerError::GeneralError) } Ok(()) } fn init_rxbuf(&mut self) -> Result<(), EthControllerError> { // Set ERXST pointer self.spi_port.write_reg_16b(spi::ERXST, self.rx_buf.get_wrap_addr()); // Set ERXTAIL pointer self.spi_port.write_reg_16b(spi::ERXTAIL, self.rx_buf.get_tail_addr()); // Set MAMXFL to maximum number of bytes in each accepted packet self.spi_port.write_reg_16b(spi::MAMXFL, rx::RAW_FRAME_LENGTH_MAX as u16); // Enable RXEN (ECON1<0>) let econ1 = self.spi_port.read_reg_16b(spi::ECON1)?; self.spi_port.write_reg_16b(spi::ECON1, 0x1 | (econ1 & 0xfffe)); Ok(()) } /// Receive the next packet fn receive_next(&mut self) -> Result { // Poll PKTIF (EIR<4>) to check if it is set loop { let eir = self.spi_port.read_reg_16b(spi::EIR)?; if eir & 0x40 == 0x40 { break } } // Set ERXRDPT pointer to next_addr self.spi_port.write_reg_16b(spi::ERXRDPT, self.rx_buf.get_next_addr())?; // Read 2 bytes to update next_addr let mut next_addr_buf = [0; 3]; self.spi_port.read_rxdat(&mut next_addr_buf, 2)?; self.rx_buf.set_next_addr((next_addr_buf[1] as u16) | ((next_addr_buf[2] as u16) << 8)); // Read 6 bytes to update rsv let mut rsv_buf = [0; 7]; self.spi_port.read_rxdat(&mut rsv_buf, 6)?; // Construct an RxPacket // TODO: can we directly assign to fields instead of using functions? let mut rx_packet = rx::RxPacket::new(); // Get and update frame length rx_packet.write_to_rsv(&rsv_buf[1..]); rx_packet.update_frame_length(); // Read frame bytes let mut frame_buf = [0; rx::RAW_FRAME_LENGTH_MAX]; self.spi_port.read_rxdat(&mut frame_buf, rx_packet.get_frame_length() as u32)?; rx_packet.write_to_frame(&frame_buf[1..]); // Set ERXTAIL pointer to (next_addr - 2) if self.rx_buf.get_next_addr() > rx::ERXST_DEFAULT { self.spi_port.write_reg_16b(spi::ERXTAIL, self.rx_buf.get_next_addr() - 2)?; } else { self.spi_port.write_reg_16b(spi::ERXTAIL, rx::RX_MAX_ADDRESS - 1)?; } // Set PKTDEC to decrement PKTCNT let econ1_hi = self.spi_port.read_reg_8b(spi::ECON1 + 1)?; self.spi_port.write_reg_8b(spi::ECON1 + 1, 0x01 | (econ1_hi & 0xfe))?; // Return the RxPacket Ok(rx_packet) } /// Set controller to Promiscuous Mode fn set_promiscuous(&mut self) -> Result<(), EthControllerError> { // From ENC424J600 Data Sheet Section 10.12: // "To accept all incoming frames regardless of content (Promiscuous mode), // set the CRCEN, RUNTEN, UCEN, NOTMEEN and MCEN bits." let mut erxfcon_lo = self.spi_port.read_reg_8b(spi::ERXFCON)?; self.spi_port.write_reg_8b(spi::ERXFCON, 0b0101_1110 | (erxfcon_lo & 0b1010_0001)); Ok(()) } /// Read MAC to [u8; 6] fn read_from_mac(&mut self, mac: &mut [u8]) -> Result<(), EthControllerError> { mac[0] = self.spi_port.read_reg_8b(spi::MAADR1)?; mac[1] = self.spi_port.read_reg_8b(spi::MAADR1 + 1)?; mac[2] = self.spi_port.read_reg_8b(spi::MAADR2)?; mac[3] = self.spi_port.read_reg_8b(spi::MAADR2 + 1)?; mac[4] = self.spi_port.read_reg_8b(spi::MAADR3)?; mac[5] = self.spi_port.read_reg_8b(spi::MAADR3 + 1)?; Ok(()) } }