use core::mem::{self, MaybeUninit}; use fugit::TimerDurationU32; use log::{debug, info}; use serde::{Deserialize, Serialize}; use smoltcp::{iface::{self, Interface, SocketHandle, SocketSet, SocketStorage}, socket::tcp::{Socket, SocketBuffer, State}, time::{Duration, Instant}, wire::{EthernetAddress, IpAddress, IpCidr, Ipv4Address, Ipv4Cidr}}; use stm32_eth::{dma::{EthernetDMA, RxRingEntry, TxRingEntry}, mac::{EthernetMACWithMii, Speed}, EthPins, Parts, PartsIn}; use stm32f4xx_hal::{gpio::{gpioa::*, gpiob::*, gpioc::*, Alternate, Input, Pin}, pac::{interrupt, Interrupt, Peripherals, TIM5}, rcc::Clocks, timer::{Counter, Event}, Listen}; use crate::device::sys_timer; #[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, 128], port: 1337, prefix_len: 24, gateway: [192, 168, 1, 1], } } } static mut IFACE_TIMER: Option = None; pub struct ServerHandle { socket_handles: [SocketHandle; NUM_OF_SOCKETS], 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; pub const NUM_OF_SOCKETS: usize = 4; const TCP_BUFFER_SIZE: usize = 4096; static mut RX_RING: Option<[RxRingEntry; 8]> = None; static mut TX_RING: Option<[TxRingEntry; 8]> = None; static mut SOCKET_STORAGE: Option<[SocketStorage<'static>; NUM_OF_SOCKETS]> = None; fn now_fn() -> smoltcp::time::Instant { Instant::from_millis(i64::from(sys_timer::now())) } static mut SERVER_HANDLE: Option = None; pub const FREQ: u32 = 1000000; impl ServerHandle { pub fn new( eth_pins: EthernetPins, eth_mgmt_pins: EthernetMgmtPins, ethernet_parts_in: PartsIn, clocks: Clocks, tim5: Counter, 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 socket_storage = unsafe { SOCKET_STORAGE.get_or_insert([SocketStorage::EMPTY; NUM_OF_SOCKETS]) }; let Parts { mut dma, mac, .. } = 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 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 socket_set = SocketSet::new(&mut socket_storage[..]); let tcp_handles = { // Do not use NUM_OF_SOCKETS to define array size to // remind developers to create/remove tcp_handles accordingly after changing NUM_OF_SOCKETS let mut tcp_handles: [MaybeUninit; 4] = unsafe { MaybeUninit::uninit().assume_init() }; macro_rules! create_tcp_handle { ($rx_storage:ident, $tx_storage:ident, $handle:expr) => { static mut $rx_storage: [u8; TCP_BUFFER_SIZE] = [0; TCP_BUFFER_SIZE]; static mut $tx_storage: [u8; TCP_BUFFER_SIZE] = [0; TCP_BUFFER_SIZE]; unsafe { let rx_buffer = SocketBuffer::new(&mut $rx_storage[..]); let tx_buffer = SocketBuffer::new(&mut $tx_storage[..]); $handle.write(socket_set.add(Socket::new(rx_buffer, tx_buffer))); } }; } create_tcp_handle!(RX_STORAGE0, TX_STORAGE0, tcp_handles[0]); create_tcp_handle!(RX_STORAGE1, TX_STORAGE1, tcp_handles[1]); create_tcp_handle!(RX_STORAGE2, TX_STORAGE2, tcp_handles[2]); create_tcp_handle!(RX_STORAGE3, TX_STORAGE3, tcp_handles[3]); unsafe { mem::transmute::<_, [SocketHandle; 4]>(tcp_handles) } }; for i in 0..NUM_OF_SOCKETS { let socket = socket_set.get_mut::(tcp_handles[i]); socket.listen(socket_addr).ok(); socket.set_timeout(Some(Duration::from_secs(5))); // Value from Linux net.ipv4.tcp_keepalive_time socket.set_keep_alive(Some(Duration::from_secs(7200))); socket.set_nagle_enabled(false); } iface.poll( Instant::from_millis(i64::from(sys_timer::now())), &mut &mut dma, &mut socket_set, ); IfacePollTimer::setup(tim5); 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_handles: tcp_handles, socket_set: socket_set, 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) -> bool { 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); self.link_was_up = self.phy.phy_link_up(); return true; } else { debug!("Failed to detect link speed."); } } self.link_was_up = self.phy.phy_link_up(); return false; } pub fn poll_iface(&mut self) { self.iface.poll(now_fn(), &mut &mut self.dma, &mut self.socket_set); } pub fn poll_at_iface(&mut self) -> Option { self.iface.poll_at(now_fn(), &mut self.socket_set) } pub fn poll_delay_iface(&mut self) -> Option { self.iface.poll_delay(now_fn(), &mut self.socket_set) } pub fn recv( &mut self, buffer: &mut [u8], socket_handles: SocketHandle, ) -> Result { let socket = self.socket_set.get_mut::(socket_handles); socket.recv_slice(buffer) } pub fn send(&mut self, buffer: &mut [u8], num_bytes: usize, socket_handles: SocketHandle) { let socket = self.socket_set.get_mut::(socket_handles); if num_bytes > 0 { match socket.send_slice(&buffer[..num_bytes]) { Ok(_) => { self.poll_iface(); info!("Sent {} bytes.", num_bytes); } Err(err) => { info!("Bytes cannot be sent. Error: {:?}", err) } }; } } pub fn is_socket_connected(&mut self, socket_handles: SocketHandle) -> bool { let socket = self.socket_set.get_mut::(socket_handles); socket.state() == State::Established } pub fn poll_socket_status(&mut self, socket_handles: SocketHandle) -> bool { let socket = self.socket_set.get_mut::(socket_handles); 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, socket_handles: SocketHandle) { let socket = self.socket_set.get_mut::(socket_handles); socket.abort(); } pub fn can_send(&mut self, socket_handles: SocketHandle) -> bool { self.socket_set.get_mut::(socket_handles).can_send() } pub fn can_recv(&mut self, socket_handles: SocketHandle) -> bool { self.socket_set.get_mut::(socket_handles).can_recv() } } use ieee802_3_miim::{phy::{lan87xxa::{LAN8720A, LAN8742A}, BarePhy, PhySpeed, KSZ8081R}, 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_can_sock_send(socket_handles: SocketHandle) -> bool { unsafe { if let Some(ref mut server_handle) = SERVER_HANDLE { server_handle.can_send(socket_handles) } else { panic!("eth_check_if_sock_can_send is called before init"); } } } pub fn eth_can_sock_recv(socket_handles: SocketHandle) -> bool { unsafe { if let Some(ref mut server_handle) = SERVER_HANDLE { server_handle.can_recv(socket_handles) } else { panic!("eth_check_if_sock_can_recv is called before init"); } } } pub fn eth_poll_link_status_and_update_link_speed() -> bool { unsafe { if let Some(ref mut server_handle) = SERVER_HANDLE { let new_link_is_up = server_handle.update_link_speed(); if new_link_is_up { info!("Resetting TCP Sockets"); for_each(|socket, _| { eth_close_socket(socket); }); } return new_link_is_up; } else { panic!("eth_poll_link_status_and_update_link_speed is called before init"); } } } pub fn eth_update_iface_poll_timer() { unsafe { if let Some(ref mut server_handle) = SERVER_HANDLE { IfacePollTimer::set_timer(server_handle.poll_at_iface(), server_handle.poll_delay_iface()) } else { panic!("eth_update_iface_poll_timer is called before init") } } } fn eth_poll_iface() { unsafe { if let Some(ref mut server_handle) = SERVER_HANDLE { server_handle.poll_iface(); } else { panic!("eth_poll_packet is called before init"); } } } pub fn eth_send(buffer: &mut [u8], num_bytes: usize, socket_handles: SocketHandle) { unsafe { if let Some(ref mut server_handle) = SERVER_HANDLE { server_handle.send(buffer, num_bytes, socket_handles); } else { panic!("eth_send is called before init"); } } } pub fn eth_recv(buffer: &mut [u8], socket_handles: SocketHandle) -> usize { unsafe { if let Some(ref mut server_handle) = SERVER_HANDLE { match server_handle.recv(buffer, socket_handles) { 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_connected(socket_handles: SocketHandle) -> bool { unsafe { if let Some(ref mut server_handle) = SERVER_HANDLE { server_handle.is_socket_connected(socket_handles) } else { panic!("eth_is_socket_connected is called before init"); } } } pub fn eth_is_socket_active(socket_handles: SocketHandle) -> bool { unsafe { if let Some(ref mut server_handle) = SERVER_HANDLE { server_handle.poll_socket_status(socket_handles) } else { panic!("eth_is_socket_active is called before init"); } } } pub fn eth_close_socket(socket_handles: SocketHandle) { unsafe { if let Some(ref mut server_handle) = SERVER_HANDLE { server_handle.close_socket(socket_handles) } else { panic!("eth_close_socket is called before init"); } } } pub fn for_each(mut callback: F) { unsafe { if let Some(ref mut server_handle) = SERVER_HANDLE { for i in 0..NUM_OF_SOCKETS { callback(server_handle.socket_handles[i], i); } } 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(|_| { if interrupt_reason.rx { eth_poll_iface(); } }); debug!("Ethernet Interrupt{:?}", interrupt_reason); } pub struct IfacePollTimer { timer: Counter, poll_at_set: Instant, } impl IfacePollTimer { fn get() -> Option<&'static mut Self> { unsafe { IFACE_TIMER.as_mut() } } pub fn setup(tim5: Counter) { unsafe { cortex_m::peripheral::NVIC::unmask(Interrupt::TIM5); IFACE_TIMER = Some(IfacePollTimer { timer: tim5, poll_at_set: Instant::from_micros(u32::max_value()), }) } } fn is_timer_running() -> bool { unsafe { Peripherals::steal().TIM5.cr1.read().cen().bit() } } pub fn set_timer(poll_at: Option, delay: Option) { if let Some(ref mut iface_timer) = IfacePollTimer::get() { if !IfacePollTimer::is_timer_running() { match poll_at { Some(val) => { IfacePollTimer::set_timer_delay(delay); iface_timer.poll_at_set = val; } None => {} } } else { match poll_at { Some(val) => { if iface_timer.poll_at_set != val { IfacePollTimer::stop_listening(); IfacePollTimer::set_timer_delay(delay); iface_timer.poll_at_set = val; } } None => {} } } } } fn set_timer_delay(delay: Option) { if let Some(ref mut iface_timer) = IfacePollTimer::get() { match delay { Some(val) => { if val.micros() != 0 { match iface_timer.timer.start(TimerDurationU32::micros(val.micros() as u32)) { Ok(_) => { iface_timer.timer.listen(Event::Update); } Err(e) => { debug!("Timer cannot be set {:?}", e) } }; } else { eth_poll_iface(); } } None => {} } } } pub fn clear_irq_flag() { if let Some(ref mut iface_timer) = IfacePollTimer::get() { iface_timer.timer.wait().ok(); } } pub fn stop_listening() { if let Some(ref mut iface_timer) = IfacePollTimer::get() { iface_timer.timer.unlisten(Event::Update); iface_timer.timer.cancel().ok(); } } } #[interrupt] fn TIM5() { eth_poll_iface(); cortex_m::interrupt::free(|_| { IfacePollTimer::stop_listening(); IfacePollTimer::clear_irq_flag(); }); }