diff --git a/src/bin/main.rs b/src/bin/main.rs index f2e355b..e3c7a20 100644 --- a/src/bin/main.rs +++ b/src/bin/main.rs @@ -7,7 +7,7 @@ )] #![deny(clippy::large_stack_frames)] -use cover_theif::wifi::start_wifi; +use cover_theif::{clock::start_ntp_sync, http_api::start_http_api, wifi::start_wifi}; use defmt::info; use embassy_executor::Spawner; use embassy_time::{Duration, Timer}; @@ -16,11 +16,6 @@ use esp_hal::clock::CpuClock; use esp_hal::timer::timg::TimerGroup; use esp_println as _; -use cover_theif::{ - clock, - http_api::{HttpApiProps, HttpApiService}, -}; - extern crate alloc; // This creates a default app-descriptor required by the esp-idf bootloader. @@ -50,16 +45,8 @@ async fn main(spawner: Spawner) -> ! { let net_stack = start_wifi(spawner, peripherals.WIFI); - spawner.spawn(clock::ntp_upkeep_service(net_stack).unwrap()); - - spawner.spawn( - http_api_serve_task(HttpApiService::new( - net_stack, - Default::default(), - Default::default(), - )) - .unwrap(), - ); + start_ntp_sync(spawner, net_stack); + start_http_api(spawner, net_stack); loop { info!("Hello world"); @@ -68,8 +55,3 @@ async fn main(spawner: Spawner) -> ! { // for inspiration have a look at the examples at https://github.com/esp-rs/esp-hal/tree/esp-hal-v1.1.0/examples } - -#[embassy_executor::task] -async fn http_api_serve_task(mut service: HttpApiService<'static, HttpApiProps>) { - service.run().await; -} diff --git a/src/clock.rs b/src/clock.rs index c412967..0c97e9c 100644 --- a/src/clock.rs +++ b/src/clock.rs @@ -1,5 +1,9 @@ use core::net::SocketAddr; -use embassy_net::udp::{PacketMetadata, UdpSocket}; +use embassy_executor::Spawner; +use embassy_net::{ + Stack, + udp::{PacketMetadata, UdpSocket}, +}; use embassy_time::{Duration, Timer}; use portable_atomic::{AtomicU64, Ordering}; use sntpc::{NtpContext, get_time}; @@ -10,11 +14,38 @@ use sntpc_time_embassy::EmbassyTimestampGenerator; const NTP_SERVER: &str = "pool.ntp.org"; const NTP_PORT: u16 = 123; +pub fn now() -> embassy_time::Instant { + embassy_time::Instant::now() + Duration::from_secs(NTP_BOOT_OFFSET.load(Ordering::Relaxed)) +} + +pub fn start_ntp_sync(spawner: Spawner, net_stack: Stack<'static>) { + spawner.spawn(handler(net_stack).unwrap()); +} + +#[embassy_executor::task] +async fn handler(net_stack: Stack<'static>) { + loop { + match fetch_ntp_time(net_stack).await { + Ok(unix_secs) => { + NTP_BOOT_OFFSET.store( + unix_secs - embassy_time::Instant::now().as_secs(), + portable_atomic::Ordering::Relaxed, + ); + Timer::after(Duration::from_secs(6 * 60 * 60)).await + } + Err(err) => { + defmt::error!("Failed to sync the clock from NTP: {}", err); + Timer::after(Duration::from_secs(10)).await + } + } + } +} + static NTP_BOOT_OFFSET: AtomicU64 = AtomicU64::new(0); -pub async fn fetch_ntp_time(stack: embassy_net::Stack<'static>) -> Result { +pub async fn fetch_ntp_time(net_stack: Stack<'static>) -> Result { // Resolve the NTP server hostname - let server_addr = stack + let server_addr = net_stack .dns_query(NTP_SERVER, embassy_net::dns::DnsQueryType::A) .await .map_err(|_| "DNS resolution failed")? @@ -30,7 +61,13 @@ pub async fn fetch_ntp_time(stack: embassy_net::Stack<'static>) -> Result) -> Result embassy_time::Instant { - embassy_time::Instant::now() + Duration::from_secs(NTP_BOOT_OFFSET.load(Ordering::Relaxed)) -} - -#[embassy_executor::task] -pub async fn ntp_upkeep_service(stack: embassy_net::Stack<'static>) { - loop { - match fetch_ntp_time(stack).await { - Ok(unix_secs) => { - NTP_BOOT_OFFSET.store( - unix_secs - embassy_time::Instant::now().as_secs(), - portable_atomic::Ordering::Relaxed, - ); - Timer::after(Duration::from_secs(6 * 60 * 60)).await - } - Err(err) => { - defmt::error!("Failed to sync the clock from NTP: {}", err); - Timer::after(Duration::from_secs(10)).await - } - } - } -} diff --git a/src/http_api.rs b/src/http_api.rs index 5aca8c5..c99f55b 100644 --- a/src/http_api.rs +++ b/src/http_api.rs @@ -1,3 +1,4 @@ +use embassy_executor::Spawner; use embassy_net::Stack; use picoserve::routing::get; use picoserve::{AppBuilder, AppRouter, Config}; @@ -13,6 +14,22 @@ impl AppBuilder for HttpApiProps { } } +pub fn start_http_api(spawner: Spawner, net_stack: Stack<'static>) { + spawner.spawn( + handler(HttpApiApp::new( + net_stack, + Default::default(), + Default::default(), + )) + .unwrap(), + ); +} + +#[embassy_executor::task] +async fn handler(mut service: HttpApiApp<'static, HttpApiProps>) { + service.run().await; +} + pub struct HttpApiConfig { pub port: u16, pub web_serve_config: Config, @@ -27,7 +44,7 @@ impl Default for HttpApiConfig { } } -pub struct HttpApiService<'a, AB: AppBuilder> { +pub struct HttpApiApp<'a, AB: AppBuilder> { config: HttpApiConfig, net_stack: Stack<'a>, @@ -38,7 +55,7 @@ pub struct HttpApiService<'a, AB: AppBuilder> { http_buffer: [u8; 2048], } -impl<'a, AB: AppBuilder> HttpApiService<'a, AB> { +impl<'a, AB: AppBuilder> HttpApiApp<'a, AB> { pub fn new(net_stack: Stack<'a>, config: HttpApiConfig, app: AB) -> Self { Self { config: config,