From e8aaf5f66b6734fefd59f4c3ea22c87d1dbc97b0 Mon Sep 17 00:00:00 2001 From: linuswck Date: Thu, 2 May 2024 10:25:13 +0800 Subject: [PATCH] net: Implement iface polling timer - iface needs to be polled with ref to iface.poll_at time to ensure quality of service - iface.poll() also services TCP related Timers --- src/device/boot.rs | 1 + src/main.rs | 6 +-- src/net/net.rs | 132 +++++++++++++++++++++++++++++++++++++++++++-- 3 files changed, 131 insertions(+), 8 deletions(-) diff --git a/src/device/boot.rs b/src/device/boot.rs index 33dd3d7..9be22ec 100644 --- a/src/device/boot.rs +++ b/src/device/boot.rs @@ -109,6 +109,7 @@ pub fn bootup( eth_mgmt_pins, ethernet_parts_in, clocks, + perif.TIM5.counter(&clocks), mac_addr, ip_settings, ); diff --git a/src/main.rs b/src/main.rs index a089df5..fd6fe87 100644 --- a/src/main.rs +++ b/src/main.rs @@ -142,6 +142,8 @@ fn main() -> ! { State::MainLoop => { laser.poll_and_update_output_current(); + net::net::eth_update_iface_poll_timer(); + if thermostat.poll_adc() { thermostat.update_pid(); if thermostat.get_temp_mon_status().over_temp_alarm { @@ -160,8 +162,6 @@ fn main() -> ! { &mut thermostat, &mut socket, ); - } else { - debug!("Socket {:?} is not ready to send status report", id) } } } else { @@ -191,8 +191,6 @@ fn main() -> ! { &mut active_report[id], ); } - } else { - debug!("Socket {:?} is not ready to process command", id); } } }) diff --git a/src/net/net.rs b/src/net/net.rs index b186971..81ad010 100644 --- a/src/net/net.rs +++ b/src/net/net.rs @@ -1,5 +1,6 @@ use core::mem::{self, MaybeUninit}; +use fugit::TimerDurationU32; use log::{debug, info}; use serde::{Deserialize, Serialize}; use smoltcp::{iface::{self, Interface, SocketHandle, SocketSet, SocketStorage}, @@ -10,8 +11,10 @@ use stm32_eth::{dma::{EthernetDMA, RxRingEntry, TxRingEntry}, mac::{EthernetMACWithMii, Speed}, EthPins, Parts, PartsIn}; use stm32f4xx_hal::{gpio::{gpioa::*, gpiob::*, gpioc::*, Alternate, Input, Pin}, - interrupt, - rcc::Clocks}; + pac::{interrupt, Interrupt, Peripherals, TIM5}, + rcc::Clocks, + timer::{Counter, Event}, + Listen}; use crate::device::sys_timer; @@ -34,6 +37,8 @@ impl Default for IpSettings { } } +static mut IFACE_TIMER: Option = None; + pub struct ServerHandle { socket_handles: [SocketHandle; NUM_OF_SOCKETS], socket_set: SocketSet<'static>, @@ -62,12 +67,15 @@ fn now_fn() -> smoltcp::time::Instant { 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, ) { @@ -154,7 +162,9 @@ impl ServerHandle { for i in 0..NUM_OF_SOCKETS { let socket = socket_set.get_mut::(tcp_handles[i]); socket.listen(socket_addr).ok(); - socket.set_keep_alive(Some(Duration::from_secs(1))); + 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); } @@ -164,6 +174,8 @@ impl ServerHandle { &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()); @@ -211,6 +223,14 @@ impl ServerHandle { 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], @@ -402,7 +422,17 @@ pub fn eth_poll_link_status_and_update_link_speed() -> bool { } } -pub fn eth_poll_iface() { +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(); @@ -492,3 +522,97 @@ fn ETH() { }); 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(); + }); +}