From 97238b56f7d339c6f2b921a0baa9d984c30a5590 Mon Sep 17 00:00:00 2001 From: macronova Date: Mon, 14 Oct 2024 00:41:59 -0700 Subject: [PATCH] Resolve DNS A record --- Cargo.lock | 16 +++++++++++ Cargo.toml | 1 + src/main.rs | 53 ++++++++++++++++++++++++++++++------- src/picow_time.rs | 67 +++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 128 insertions(+), 9 deletions(-) create mode 100644 src/picow_time.rs diff --git a/Cargo.lock b/Cargo.lock index f23b4b4..185bc3e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -902,6 +902,12 @@ version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "650eef8c711430f1a879fdd01d4745a7deea475becfb90269c06775983bbf086" +[[package]] +name = "no-std-net" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43794a0ace135be66a25d3ae77d41b91615fb68ae937f904090203e81f755b65" + [[package]] name = "num-traits" version = "0.2.19" @@ -1009,6 +1015,7 @@ dependencies = [ "rand", "serde", "serde_yaml", + "sntpc", "static_cell", ] @@ -1341,6 +1348,15 @@ dependencies = [ "managed", ] +[[package]] +name = "sntpc" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de6292f240a2bf33ae7156cb354802bca8ecfacf96b820a6ec2f2e9f5c01f260" +dependencies = [ + "no-std-net", +] + [[package]] name = "ssmarshal" version = "1.0.0" diff --git a/Cargo.toml b/Cargo.toml index a5791ac..a991e0b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -21,6 +21,7 @@ log ="*" panic-halt = "*" portable-atomic = { version = "*", features = ["critical-section"] } rand = { version = "*", default-features = false } +sntpc = { version = "*", default-features = false } static_cell = "*" [profile.release] diff --git a/src/main.rs b/src/main.rs index 3099e2f..652c187 100644 --- a/src/main.rs +++ b/src/main.rs @@ -2,12 +2,17 @@ #![no_std] #![no_main] +mod picow_time; + extern crate panic_halt; use cyw43::JoinOptions; use cyw43_pio::PioSpi; use embassy_executor::Spawner; -use embassy_net::{Config, DhcpConfig, StackResources}; +use embassy_net::{ + dns::{DnsQueryType, DnsSocket}, + Config, DhcpConfig, IpAddress, StackResources, +}; use embassy_rp::{ bind_interrupts, clocks::RoscRng, @@ -18,15 +23,16 @@ use embassy_rp::{ }; use embassy_time::Timer; use log::info; +use picow_time::PicowUDPBuffer; use rand::RngCore; use static_cell::StaticCell; const HOSTNAME: &str = "picow"; +const NTP_ENDPOINT: &str = "time.google.com"; +const WAIT_SECOND: u64 = 7; const WIRELESS_CREDENTIALS: &[(&str, &str)] = &include!(concat!(env!("OUT_DIR"), "/wireless-credentials.rs")); -const WIRELESS_SCAN_PERIOD_SECOND: u64 = 7; - bind_interrupts!(struct Irqs { PIO0_IRQ_0 => pio::InterruptHandler; USBCTRL_IRQ => usb::InterruptHandler; @@ -107,11 +113,11 @@ async fn main(spawner: Spawner) -> ! { .set_power_management(cyw43::PowerManagementMode::PowerSave) .await; - // set hostname + // hostname let mut dhcpv4_config = DhcpConfig::default(); dhcpv4_config.hostname = HOSTNAME.try_into().ok(); - // setup network stack + // network stack static RESOURCES: StaticCell> = StaticCell::new(); let (network_stack, network_runner) = embassy_net::new( network_device, @@ -141,8 +147,8 @@ async fn main(spawner: Spawner) -> ! { .0 { info!("Unable to join any wireless network with provided credentials"); - info!("Sleep for {WIRELESS_SCAN_PERIOD_SECOND} seconds before rescan"); - Timer::after_secs(WIRELESS_SCAN_PERIOD_SECOND).await; + info!("Sleep for {WAIT_SECOND} seconds before rescan"); + Timer::after_secs(WAIT_SECOND).await; } } @@ -156,8 +162,37 @@ async fn main(spawner: Spawner) -> ! { // turn on led to indicate network connection wireless_control.gpio_set(0, true).await; + // dns client + let dns_client = DnsSocket::new(network_stack); + + // udp client + // let mut udp_buffer = PicowUDPBuffer::default(); + // let udp_client = udp_buffer.socket(network_stack); + loop { - info!("System is idle"); - Timer::after_secs(1).await; + let ntp_ipv4 = match dns_client.query(NTP_ENDPOINT, DnsQueryType::A).await { + Ok(address) => match address.first() { + Some(IpAddress::Ipv4(ipv4)) => ipv4.octets(), + None => { + info!( + "DNS A record lookup returned no IPv4 address: {}", + NTP_ENDPOINT + ); + continue; + } + }, + Err(error) => { + info!( + "DNS A record lookup returned error: {}, {:?}", + NTP_ENDPOINT, error + ); + continue; + } + }; + info!( + "Resolved IPv4 address for {}: {}.{}.{}.{}", + NTP_ENDPOINT, ntp_ipv4[0], ntp_ipv4[1], ntp_ipv4[1], ntp_ipv4[3] + ); + Timer::after_secs(WAIT_SECOND).await; } } diff --git a/src/picow_time.rs b/src/picow_time.rs new file mode 100644 index 0000000..b45d184 --- /dev/null +++ b/src/picow_time.rs @@ -0,0 +1,67 @@ +use embassy_net::{ + udp::{PacketMetadata, UdpSocket}, + Stack, +}; +use embassy_time::{Duration, Instant}; +use sntpc::NtpTimestampGenerator; + +const UDP_BUFFER_SIZE_BYTE: usize = 1 << 12; +const UDP_METADATA_SIZE: usize = 1 << 3; + +#[derive(Copy, Clone)] +pub struct PicowTimestampGenerator { + duration: Duration, +} + +impl Default for PicowTimestampGenerator { + fn default() -> Self { + Self { + duration: Instant::now().duration_since(Instant::MIN), + } + } +} + +impl NtpTimestampGenerator for PicowTimestampGenerator { + fn init(&mut self) { + self.duration = Instant::now().duration_since(Instant::MIN); + } + + fn timestamp_sec(&self) -> u64 { + self.duration.as_secs() + } + + fn timestamp_subsec_micros(&self) -> u32 { + (self.duration.as_micros() % 1000000) as u32 + } +} + +#[derive(Debug)] +pub struct PicowUDPBuffer { + receive_buffer: [u8; UDP_BUFFER_SIZE_BYTE], + receive_metadata: [PacketMetadata; UDP_METADATA_SIZE], + transmit_buffer: [u8; UDP_BUFFER_SIZE_BYTE], + transmit_metadata: [PacketMetadata; UDP_METADATA_SIZE], +} + +impl Default for PicowUDPBuffer { + fn default() -> Self { + Self { + receive_buffer: [0; UDP_BUFFER_SIZE_BYTE], + receive_metadata: [PacketMetadata::EMPTY; UDP_METADATA_SIZE], + transmit_buffer: [0; UDP_BUFFER_SIZE_BYTE], + transmit_metadata: [PacketMetadata::EMPTY; UDP_METADATA_SIZE], + } + } +} + +impl PicowUDPBuffer { + pub fn socket<'me>(&'me mut self, network_stack: Stack<'me>) -> UdpSocket<'me> { + UdpSocket::new( + network_stack, + &mut self.receive_metadata, + &mut self.receive_buffer, + &mut self.transmit_metadata, + &mut self.transmit_buffer, + ) + } +}