use embedded_hal::blocking::spi::{Transfer, Write}; use embedded_hal::digital::v2::OutputPin; use embedded_nal::Ipv4Addr; use crate::bus::{Bus, FourWire, ThreeWire}; use crate::device::Device; use crate::host::{Dhcp, Host, Manual}; use crate::raw_device::RawDevice; use crate::register; use crate::{MacAddress, Mode}; pub struct UninitializedDevice { bus: SpiBus, } #[derive(Debug)] #[repr(u8)] pub enum InitializeError { SpiError(SpiError), ChipNotConnected, } impl From for InitializeError { fn from(error: SpiError) -> InitializeError { InitializeError::SpiError(error) } } impl UninitializedDevice { pub fn new(bus: SpiBus) -> UninitializedDevice { UninitializedDevice { bus } } /// Initialize the device with a MAC address and mode settings. /// /// Consider using freely available private/locally administered mac /// addresses that match the following hex pattern: /// /// ```code /// x2-xx-xx-xx-xx-xx /// x6-xx-xx-xx-xx-xx /// xA-xx-xx-xx-xx-xx /// xE-xx-xx-xx-xx-xx /// ``` /// /// "Universally administered and locally administered addresses are /// distinguished by setting the second-least-significant bit of the first /// octet of the address" /// [Wikipedia](https://en.wikipedia.org/wiki/MAC_address#Universal_vs._local) pub fn initialize( self, mac: MacAddress, mode_options: Mode, ) -> Result, InitializeError> { let host = Dhcp::new(mac); self.initialize_with_host(host, mode_options) } pub fn initialize_manual( self, mac: MacAddress, ip: Ipv4Addr, mode_options: Mode, ) -> Result, InitializeError> { let mut ip_bytes = ip.octets(); ip_bytes[3] = 1; let gateway = Ipv4Addr::from(ip_bytes); let subnet = Ipv4Addr::new(255, 255, 255, 0); self.initialize_advanced(mac, ip, gateway, subnet, mode_options) } pub fn initialize_advanced( self, mac: MacAddress, ip: Ipv4Addr, gateway: Ipv4Addr, subnet: Ipv4Addr, mode_options: Mode, ) -> Result, InitializeError> { let host = Manual::new(mac, ip, gateway, subnet); self.initialize_with_host(host, mode_options) } fn initialize_with_host( mut self, mut host: HostImpl, mode_options: Mode, ) -> Result, InitializeError> { #[cfg(not(feature = "no-chip-version-assertion"))] self.assert_chip_version(0x4)?; // RESET let mode = [0b10000000]; self.bus .write_frame(register::COMMON, register::common::MODE, &mode)?; self.set_mode(mode_options)?; host.refresh(&mut self.bus)?; Ok(Device::new(self.bus, host)) } pub fn initialize_macraw( mut self, mac: MacAddress, ) -> Result, InitializeError> { // Reset the device. self.bus .write_frame(register::COMMON, register::common::MODE, &[0x80])?; self.bus .write_frame(register::COMMON, register::common::MAC, &mac.octets)?; RawDevice::new(self.bus) } #[cfg(not(feature = "no-chip-version-assertion"))] fn assert_chip_version( &mut self, expected_version: u8, ) -> Result<(), InitializeError> { let mut version = [0]; self.bus .read_frame(register::COMMON, register::common::VERSION, &mut version)?; if version[0] != expected_version { Err(InitializeError::ChipNotConnected) } else { Ok(()) } } fn set_mode(&mut self, mode_options: Mode) -> Result<(), SpiBus::Error> { let mut mode = [0]; mode[0] |= mode_options.on_wake_on_lan as u8; mode[0] |= mode_options.on_ping_request as u8; mode[0] |= mode_options.connection_type as u8; mode[0] |= mode_options.arp_responses as u8; self.bus .write_frame(register::COMMON, register::common::MODE, &mode)?; Ok(()) } } impl + Write, ChipSelect: OutputPin> UninitializedDevice> { pub fn deactivate(self) -> (Spi, ChipSelect) { self.bus.release() } } impl + Write> UninitializedDevice> { pub fn deactivate(self) -> Spi { self.bus.release() } }