diff --git a/rust/src/hal/esp.rs b/rust/src/hal/esp.rs index 8c5246f..b91f5b8 100644 --- a/rust/src/hal/esp.rs +++ b/rust/src/hal/esp.rs @@ -17,8 +17,6 @@ use core::net::{IpAddr, Ipv4Addr, SocketAddr}; use core::str::FromStr; use core::sync::atomic::Ordering; use embassy_executor::Spawner; -use embassy_net::dns::DnsQueryType; -use embassy_net::udp::{PacketMetadata, UdpSocket}; use embassy_net::{DhcpConfig, IpAddress, Ipv4Cidr, Runner, Stack, StackResources, StaticConfigV4}; use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; use embassy_sync::mutex::{Mutex, MutexGuard}; @@ -44,7 +42,6 @@ use littlefs2::fs::Filesystem; use littlefs2_core::{FileType, PathBuf, SeekFrom}; use log::{info, warn, error}; use portable_atomic::AtomicBool; -use sntpc::{NtpContext, NtpTimestampGenerator, NtpUdpSocket, get_time}; use super::shared_flash::MutexFlashStorage; use crate::network::{net_task, run_dhcp}; @@ -62,7 +59,6 @@ static mut LAST_CORROSION_PROTECTION_CHECK_DAY: i8 = -1; const CONFIG_FILE: &str = "config.json"; -const NTP_SERVER: &str = "pool.ntp.org"; #[derive(Serialize, Debug)] pub struct FileInfo { @@ -77,11 +73,6 @@ pub struct FileList { files: Vec, } -#[derive(Copy, Clone, Default)] -struct Timestamp { - stamp: DateTime, -} - // Minimal esp-idf equivalent for gpio_hold on esp32c6 via ROM functions extern "C" { fn gpio_pad_hold(gpio_num: u32); @@ -98,53 +89,6 @@ pub fn hold_disable(gpio_num: u8) { unsafe { gpio_pad_unhold(gpio_num as u32) } } -impl NtpTimestampGenerator for Timestamp { - fn init(&mut self) { - self.stamp = DateTime::default(); - } - - fn timestamp_sec(&self) -> u64 { - self.stamp.timestamp() as u64 - } - - fn timestamp_subsec_micros(&self) -> u32 { - self.stamp.timestamp_subsec_micros() - } -} -struct EmbassyNtpSocket<'a, 'b> { - socket: &'a UdpSocket<'b>, -} - -impl<'a, 'b> EmbassyNtpSocket<'a, 'b> { - fn new(socket: &'a UdpSocket<'b>) -> Self { - Self { socket } - } -} - -impl NtpUdpSocket for EmbassyNtpSocket<'_, '_> { - async fn send_to(&self, buf: &[u8], addr: SocketAddr) -> sntpc::Result { - self.socket - .send_to(buf, addr) - .await - .map_err(|_| sntpc::Error::Network)?; - Ok(buf.len()) - } - - async fn recv_from(&self, buf: &mut [u8]) -> sntpc::Result<(usize, SocketAddr)> { - let (len, metadata) = self - .socket - .recv_from(buf) - .await - .map_err(|_| sntpc::Error::Network)?; - let addr = match metadata.endpoint.addr { - IpAddress::Ipv4(ip) => IpAddr::V4(ip), - IpAddress::Ipv6(ip) => IpAddr::V6(ip), - }; - Ok((len, SocketAddr::new(addr, metadata.endpoint.port))) - } -} - - pub struct Esp<'a> { pub fs: Arc>>, pub rng: Rng, @@ -346,66 +290,6 @@ impl Esp<'_> { self.boot_button.is_low() } - pub(crate) async fn sntp( - &mut self, - _max_wait_ms: u32, - stack: Stack<'_>, - ) -> FatResult> { - println!("start sntp"); - let mut rx_meta = [PacketMetadata::EMPTY; 16]; - let mut rx_buffer = [0; 4096]; - let mut tx_meta = [PacketMetadata::EMPTY; 16]; - let mut tx_buffer = [0; 4096]; - - let mut socket = UdpSocket::new( - stack, - &mut rx_meta, - &mut rx_buffer, - &mut tx_meta, - &mut tx_buffer, - ); - socket.bind(123).context("Could not bind UDP socket")?; - - let context = NtpContext::new(Timestamp::default()); - let ntp_socket = EmbassyNtpSocket::new(&socket); - - let ntp_addrs = stack - .dns_query(NTP_SERVER, DnsQueryType::A) - .await - .context("Failed to resolve DNS")?; - - if ntp_addrs.is_empty() { - bail!("No IP addresses found for NTP server"); - } - let ntp = ntp_addrs[0]; - info!("NTP server: {ntp:?}"); - - let mut counter = 0; - loop { - let addr: IpAddr = ntp.into(); - let timeout = get_time(SocketAddr::from((addr, 123)), &ntp_socket, context) - .with_timeout(Duration::from_millis((_max_wait_ms / 10) as u64)) - .await; - - match timeout { - Ok(result) => { - let time = result?; - info!("Time: {time:?}"); - return DateTime::from_timestamp(time.seconds as i64, 0) - .context("Could not convert Sntp result"); - } - Err(err) => { - warn!("sntp timeout, retry: {err:?}"); - counter += 1; - if counter > 10 { - bail!("Failed to get time from NTP server"); - } - Timer::after(Duration::from_millis(100)).await; - } - } - } - } - pub(crate) async fn wifi_scan(&mut self) -> FatResult> { info!("start wifi scan"); let mut lock = self.controller.try_lock()?; diff --git a/rust/src/main.rs b/rust/src/main.rs index 57999fb..446119a 100644 --- a/rust/src/main.rs +++ b/rust/src/main.rs @@ -743,7 +743,7 @@ async fn try_connect_wifi_sntp_mqtt( Ok(stack) => { stack_store.replace(stack); - let sntp_mode: network::SntpMode = match board.board_hal.get_esp().sntp(1000 * 10, stack).await { + let sntp_mode: network::SntpMode = match network::sntp(1000 * 10, stack).await { Ok(new_time) => { info!("Using time from sntp {}", new_time.to_rfc3339()); let _ = board diff --git a/rust/src/network.rs b/rust/src/network.rs index a208bac..789392d 100644 --- a/rust/src/network.rs +++ b/rust/src/network.rs @@ -1,17 +1,133 @@ +use crate::bail; +use crate::fat_error::{ContextExt, FatError, FatResult}; use alloc::string::String; use chrono::{DateTime, Utc}; -use core::net::{Ipv4Addr, SocketAddr, SocketAddrV4}; +use core::net::{IpAddr, Ipv4Addr, SocketAddr, SocketAddrV4}; +use embassy_net::dns::DnsQueryType; +use embassy_net::udp::{PacketMetadata, UdpSocket}; use embassy_net::{Runner, Stack}; -use embassy_time::{Duration, Timer}; +use embassy_time::{Duration, Timer, WithTimeout}; use edge_dhcp::{ io::{self, DEFAULT_SERVER_PORT}, server::{Server, ServerOptions}, }; use edge_nal::UdpBind; use edge_nal_embassy::{Udp, UdpBuffers}; +use esp_println::println; use esp_radio::wifi::Interface; -use log::{warn, error}; +use log::{info, warn, error}; use serde::Serialize; +use sntpc::{NtpContext, NtpTimestampGenerator, NtpUdpSocket, get_time}; + +const NTP_SERVER: &str = "pool.ntp.org"; + +#[derive(Copy, Clone, Default)] +struct Timestamp { + stamp: DateTime, +} + +impl NtpTimestampGenerator for Timestamp { + fn init(&mut self) { + self.stamp = DateTime::default(); + } + + fn timestamp_sec(&self) -> u64 { + self.stamp.timestamp() as u64 + } + + fn timestamp_subsec_micros(&self) -> u32 { + self.stamp.timestamp_subsec_micros() + } +} + +struct EmbassyNtpSocket<'a, 'b> { + socket: &'a UdpSocket<'b>, +} + +impl<'a, 'b> EmbassyNtpSocket<'a, 'b> { + fn new(socket: &'a UdpSocket<'b>) -> Self { + Self { socket } + } +} + +impl NtpUdpSocket for EmbassyNtpSocket<'_, '_> { + async fn send_to(&self, buf: &[u8], addr: SocketAddr) -> sntpc::Result { + self.socket + .send_to(buf, addr) + .await + .map_err(|_| sntpc::Error::Network)?; + Ok(buf.len()) + } + + async fn recv_from(&self, buf: &mut [u8]) -> sntpc::Result<(usize, SocketAddr)> { + let (len, metadata) = self + .socket + .recv_from(buf) + .await + .map_err(|_| sntpc::Error::Network)?; + let addr = match metadata.endpoint.addr { + embassy_net::IpAddress::Ipv4(ip) => IpAddr::V4(ip), + embassy_net::IpAddress::Ipv6(ip) => IpAddr::V6(ip), + }; + Ok((len, SocketAddr::new(addr, metadata.endpoint.port))) + } +} + +pub async fn sntp(max_wait_ms: u32, stack: Stack<'_>) -> FatResult> { + println!("start sntp"); + let mut rx_meta = [PacketMetadata::EMPTY; 16]; + let mut rx_buffer = [0; 4096]; + let mut tx_meta = [PacketMetadata::EMPTY; 16]; + let mut tx_buffer = [0; 4096]; + + let mut socket = UdpSocket::new( + stack, + &mut rx_meta, + &mut rx_buffer, + &mut tx_meta, + &mut tx_buffer, + ); + socket.bind(123).context("Could not bind UDP socket")?; + + let context = NtpContext::new(Timestamp::default()); + let ntp_socket = EmbassyNtpSocket::new(&socket); + + let ntp_addrs = stack + .dns_query(NTP_SERVER, DnsQueryType::A) + .await + .context("Failed to resolve DNS")?; + + if ntp_addrs.is_empty() { + bail!("No IP addresses found for NTP server"); + } + let ntp = ntp_addrs[0]; + info!("NTP server: {ntp:?}"); + + let mut counter = 0; + loop { + let addr: IpAddr = ntp.into(); + let timeout = get_time(SocketAddr::from((addr, 123)), &ntp_socket, context) + .with_timeout(Duration::from_millis((max_wait_ms / 10) as u64)) + .await; + + match timeout { + Ok(result) => { + let time = result?; + info!("Time: {time:?}"); + return DateTime::from_timestamp(time.seconds as i64, 0) + .context("Could not convert Sntp result"); + } + Err(err) => { + warn!("sntp timeout, retry: {err:?}"); + counter += 1; + if counter > 10 { + bail!("Failed to get time from NTP server"); + } + Timer::after(Duration::from_millis(100)).await; + } + } + } +} #[derive(Serialize, Debug, PartialEq)] pub enum SntpMode {