use crate::device::sys_timer; use core::cell::RefCell; use cortex_m::interrupt::{CriticalSection, Mutex}; use log::{debug, info}; use smoltcp::{ iface::{ self, Interface, SocketHandle, SocketSet, SocketStorage }, socket::tcp::{State, SocketBuffer, Socket}, wire::{EthernetAddress, IpAddress, IpCidr, Ipv4Address, Ipv4Cidr}, time::Instant, }; use stm32_eth::{ Parts, EthPins, PartsIn, mac::{Speed, EthernetMACWithMii}, dma::{ TxRingEntry, RxRingEntry, EthernetDMA }}; use stm32f4xx_hal::{ gpio::{gpioa::*, gpiob::*, gpioc::*, Alternate, Input, Pin}, rcc::Clocks, interrupt, }; use serde::{Deserialize, Serialize}; #[derive(Debug, Clone, Copy, Deserialize, Serialize)] pub struct IpSettings { addr: [u8; 4], port: u16, prefix_len: u8, gateway: [u8; 4], } impl Default for IpSettings { fn default() -> Self { IpSettings { addr: [192, 168, 1, 132], port: 1337, prefix_len: 24, gateway: [192, 168, 1, 1] } } } /// Interrupt pending flag: set by the `ETH` interrupt handler, should /// be cleared before polling the interface. static NET_PENDING: Mutex> = Mutex::new(RefCell::new(false)); pub struct ServerHandle { socket_handle: SocketHandle, socket_set: SocketSet<'static>, socket_addr: (IpAddress, u16), iface: EthInterface, dma: EthernetDMA<'static, 'static>, phy: EthernetPhy>, Pin<'C', 1, Alternate<11>>>>, link_was_up: bool, } pub type EthernetPins = EthPins, PA7, PB11, PB12, PB13, PC4, PC5>; pub struct EthernetMgmtPins { pub mdio: PA2>, pub mdc: PC1>, } pub type EthInterface = Interface; static mut RX_RING: Option<[RxRingEntry; 8]> = None; static mut TX_RING: Option<[TxRingEntry; 2]> = None; static mut SOCKET_STORAGE: Option<[SocketStorage<'static>; 1]> = None; static mut TCP_SOCKET_STORAGE : Option = None; #[derive(Copy, Clone)] pub struct TcpSocketStorage { rx_storage: [u8; 2048], tx_storage: [u8; 2048], } impl TcpSocketStorage { const fn new() -> Self { Self { rx_storage: [0; 2048], tx_storage: [0; 2048], } } } fn now_fn() -> smoltcp::time::Instant { Instant::from_millis(i64::from(sys_timer::now())) } static mut SERVER_HANDLE : Option = None; impl ServerHandle { pub fn new (eth_pins: EthernetPins, eth_mgmt_pins: EthernetMgmtPins, ethernet_parts_in: PartsIn, clocks: Clocks, mac_addr: [u8; 6], ip_settings: IpSettings, ) { let rx_ring = unsafe { RX_RING.get_or_insert(Default::default()) }; let tx_ring = unsafe { TX_RING.get_or_insert(Default::default()) }; let tcp_socket_storage = unsafe { TCP_SOCKET_STORAGE.get_or_insert(TcpSocketStorage::new()) }; let socket_storage = unsafe { SOCKET_STORAGE.get_or_insert([SocketStorage::EMPTY; 1]) }; let Parts { mut dma, mac, #[cfg(feature = "ptp")] .. } = stm32_eth::new_with_mii( ethernet_parts_in, &mut rx_ring[..], &mut tx_ring[..], clocks, eth_pins, eth_mgmt_pins.mdio, eth_mgmt_pins.mdc ).unwrap(); let ip_init = IpCidr::Ipv4(Ipv4Cidr::new( Ipv4Address::new(ip_settings.addr[0], ip_settings.addr[1], ip_settings.addr[2], ip_settings.addr[3]), ip_settings.prefix_len, )); let socket_addr: (IpAddress, u16) = ( IpAddress::Ipv4(Ipv4Address::new( ip_settings.addr[0], ip_settings.addr[1], ip_settings.addr[2], ip_settings.addr[3], )), ip_settings.port, ); let mut routes = smoltcp::iface::Routes::new(); routes .add_default_ipv4_route(Ipv4Address::new(ip_settings.gateway[0], ip_settings.gateway[1], ip_settings.gateway[2], ip_settings.gateway[3])) .ok(); dma.enable_interrupt(); let rx_buffer = SocketBuffer::new(&mut tcp_socket_storage.rx_storage[..]); let tx_buffer = SocketBuffer::new(&mut tcp_socket_storage.tx_storage[..]); let socket = Socket::new(rx_buffer, tx_buffer); let config = iface::Config::new(EthernetAddress::from_bytes(&mac_addr).into()); let mut iface = Interface::new(config, &mut &mut dma, smoltcp::time::Instant::ZERO); iface.set_hardware_addr(EthernetAddress(mac_addr).into()); debug!("MAC ADDRESS: {:02X?}", EthernetAddress(mac_addr)); debug!("IP Settings: {:?}", ip_settings); iface.update_ip_addrs(|addr| { addr.push(ip_init).unwrap(); }); let mut sockets = SocketSet::new(&mut socket_storage[..]); let tcp_handle = sockets.add(socket); let socket = sockets.get_mut::(tcp_handle); socket.listen(socket_addr).ok(); iface.poll(Instant::from_millis(i64::from(sys_timer::now())), &mut &mut dma, &mut sockets); if let Ok(mut phy) = EthernetPhy::from_miim(mac, 0) { info!( "Resetting PHY as an extra step. Type: {}", phy.ident_string() ); phy.phy_init(); let server = ServerHandle { socket_handle: tcp_handle, socket_set: sockets, socket_addr: socket_addr, iface: iface, dma: dma, phy: phy, link_was_up: false, }; unsafe { SERVER_HANDLE = Some(server); } } else { panic!("Ethernet Phy is not supported"); } } pub fn update_link_speed(&mut self) { if !self.link_was_up & self.phy.phy_link_up() { if let Some(speed) = self.phy.speed().map(|s| match s { PhySpeed::HalfDuplexBase10T => Speed::HalfDuplexBase10T, PhySpeed::FullDuplexBase10T => Speed::FullDuplexBase10T, PhySpeed::HalfDuplexBase100Tx => Speed::HalfDuplexBase100Tx, PhySpeed::FullDuplexBase100Tx => Speed::FullDuplexBase100Tx, }) { info!("New eth link is up. Setting detected PhySpeed: {:?}", speed); self.phy.get_miim().set_speed(speed); } else { debug!("Failed to detect link speed."); } } self.link_was_up = self.phy.phy_link_up(); } pub fn recv(&mut self, buffer: &mut [u8])-> Result { self.iface.poll(now_fn(), &mut &mut self.dma, &mut self.socket_set); let socket = self.socket_set.get_mut::(self.socket_handle); socket.recv_slice(buffer) } pub fn send(&mut self, buffer: &mut [u8], num_bytes: usize) { let socket = self.socket_set.get_mut::(self.socket_handle); if num_bytes > 0 { socket.send_slice(&buffer[..num_bytes]).ok(); info!("Sent {} bytes.", num_bytes); } // Send bytes out self.iface.poll(now_fn(), &mut &mut self.dma, &mut self.socket_set); } pub fn poll_socket_status(&mut self)-> bool { let socket = self.socket_set.get_mut::(self.socket_handle); if !socket.is_listening() && !socket.is_open() || socket.state() == State::CloseWait { socket.abort(); socket.listen(self.socket_addr).ok(); info!("Disconnected... Reopening listening socket."); return false; } else if socket.state() == State::Closed || socket.state() == State::Closing { return false; } return true; } pub fn close_socket(&mut self) { let socket = self.socket_set.get_mut::(self.socket_handle); socket.abort(); } } use ieee802_3_miim::{ phy::{ lan87xxa::{LAN8720A, LAN8742A}, BarePhy, KSZ8081R, PhySpeed }, Miim, Pause, Phy, }; /// An ethernet PHY pub enum EthernetPhy { /// LAN8720A LAN8720A(LAN8720A), /// LAN8742A LAN8742A(LAN8742A), /// KSZ8081R KSZ8081R(KSZ8081R), } impl Phy for EthernetPhy { fn best_supported_advertisement(&self) -> ieee802_3_miim::AutoNegotiationAdvertisement { unimplemented!() } fn get_miim(&mut self) -> &mut M { match self { EthernetPhy::LAN8720A(phy) => phy.get_miim(), EthernetPhy::LAN8742A(phy) => phy.get_miim(), EthernetPhy::KSZ8081R(phy) => phy.get_miim(), } } fn get_phy_addr(&self) -> u8 { match self { EthernetPhy::LAN8720A(phy) => phy.get_phy_addr(), EthernetPhy::LAN8742A(phy) => phy.get_phy_addr(), EthernetPhy::KSZ8081R(phy) => phy.get_phy_addr(), } } } impl EthernetPhy { /// Attempt to create one of the known PHYs from the given /// MIIM. /// /// Returns an error if the PHY does not support the extended register /// set, or if the PHY's identifier does not correspond to a known PHY. pub fn from_miim(miim: M, phy_addr: u8) -> Result { let mut bare = BarePhy::new(miim, phy_addr, Pause::NoPause); let phy_ident = if let Some(id) = bare.phy_ident() { id.raw_u32() } else { return Err(bare.release()); }; let miim = bare.release(); match phy_ident & 0xFFFFFFF0 { 0x0007C0F0 => Ok(Self::LAN8720A(LAN8720A::new(miim, phy_addr))), 0x0007C130 => Ok(Self::LAN8742A(LAN8742A::new(miim, phy_addr))), 0x00221560 => Ok(Self::KSZ8081R(KSZ8081R::new(miim, phy_addr))), _ => Err(miim), } } /// Get a string describing the type of PHY pub const fn ident_string(&self) -> &'static str { match self { EthernetPhy::LAN8720A(_) => "LAN8720A", EthernetPhy::LAN8742A(_) => "LAN8742A", EthernetPhy::KSZ8081R(_) => "KSZ8081R", } } /// Initialize the PHY pub fn phy_init(&mut self) { match self { EthernetPhy::LAN8720A(phy) => phy.phy_init(), EthernetPhy::LAN8742A(phy) => phy.phy_init(), EthernetPhy::KSZ8081R(phy) => { phy.set_autonegotiation_advertisement(phy.best_supported_advertisement()); } } } #[allow(dead_code)] pub fn speed(&mut self) -> Option { match self { EthernetPhy::LAN8720A(phy) => phy.link_speed(), EthernetPhy::LAN8742A(phy) => phy.link_speed(), EthernetPhy::KSZ8081R(phy) => phy.link_speed(), } } #[allow(dead_code)] pub fn release(self) -> M { match self { EthernetPhy::LAN8720A(phy) => phy.release(), EthernetPhy::LAN8742A(phy) => phy.release(), EthernetPhy::KSZ8081R(phy) => phy.release(), } } } pub fn eth_poll_and_update_link_speed() { unsafe { if let Some(ref mut server_handle ) = SERVER_HANDLE { server_handle.update_link_speed(); } else { panic!("eth_poll_and_update_link_speed is called before init"); } } } pub fn eth_send(buffer: &mut [u8], num_bytes: usize) { unsafe { if let Some(ref mut server_handle ) = SERVER_HANDLE { server_handle.send(buffer, num_bytes); } else { panic!("eth_send is called before init"); } } } pub fn eth_recv(buffer: &mut [u8])-> usize{ unsafe { if let Some(ref mut server_handle ) = SERVER_HANDLE { match server_handle.recv(buffer){ Ok(recv_bytes) => {return recv_bytes} Err(err) => { debug!("TCP Recv Error: {}", err); return 0 } }; } else { panic!("eth_send is called before init"); } } } pub fn eth_is_socket_active() -> bool { unsafe { if let Some(ref mut server_handle ) = SERVER_HANDLE { server_handle.poll_socket_status() } else { panic!("eth_is_socket_active is called before init"); } } } pub fn eth_close_socket() { unsafe { if let Some(ref mut server_handle ) = SERVER_HANDLE { server_handle.close_socket() } else { panic!("eth_close_socket is called before init"); } } } /// Potentially wake up from `wfi()`, set the interrupt pending flag, /// clear interrupt flags. #[interrupt] fn ETH() { let interrupt_reason = stm32_eth::eth_interrupt_handler(); cortex_m::interrupt::free(|cs| { *NET_PENDING.borrow(cs) .borrow_mut() = true; }); debug!("Ethernet Interrupt{:?}", interrupt_reason); } /// Has an interrupt occurred since last call to `clear_pending()`? pub fn is_pending(cs: &CriticalSection) -> bool { *NET_PENDING.borrow(cs) .borrow() } /// Clear the interrupt pending flag before polling the interface for /// data. pub fn clear_pending(cs: &CriticalSection) { *NET_PENDING.borrow(cs) .borrow_mut() = false; }