diff --git a/services/dns/src/api.rs b/services/dns/src/api.rs index 75f0500fd..69ba1136c 100644 --- a/services/dns/src/api.rs +++ b/services/dns/src/api.rs @@ -19,7 +19,8 @@ pub(crate) enum Opcode { /// used internally to update the TTL field, and eventually expire the cache (unless cache is frozen) UpdateTtl = 2, - /// issuing this opcode causes all future attempts to change the DNS server configs to be ignored. This also freezes the cache. + /// issuing this opcode causes all future attempts to change the DNS server configs to be ignored. This + /// also freezes the cache. FreezeConfig = 3, /// this allows automatic updates to the DNS server configs based on DHCP. This is the default state. @@ -52,14 +53,7 @@ pub(crate) enum Opcode { } #[derive( - Debug, - num_derive::FromPrimitive, - num_derive::ToPrimitive, - Archive, - Serialize, - Deserialize, - Copy, - Clone, + Debug, num_derive::FromPrimitive, num_derive::ToPrimitive, Archive, Serialize, Deserialize, Copy, Clone, )] #[repr(u16)] pub enum DnsResponseCode { diff --git a/services/dns/src/hosted.rs b/services/dns/src/hosted.rs index c70abf68e..86f6f4810 100644 --- a/services/dns/src/hosted.rs +++ b/services/dns/src/hosted.rs @@ -1,39 +1,37 @@ -use net::NetIpAddr; use std::net::ToSocketAddrs; + +use net::NetIpAddr; + use crate::DnsResponseCode; #[derive(Debug)] -pub struct Dns { -} +pub struct Dns {} impl Dns { - pub fn new(_xns: &xous_names::XousNames) -> Result { - Ok(Dns { - }) - } + pub fn new(_xns: &xous_names::XousNames) -> Result { Ok(Dns {}) } /// Checks first to see if the name could be just an IPv4 or IPv6 in string form, /// then tries to pass it to the DNS resolver. pub fn lookup(&self, name: &str) -> Result { log::debug!("looking up {}", name); - match (name, 80).to_socket_addrs() { // we throw away the port because we just want the IP address... - Ok(mut iter) => { - match iter.next() { - Some(addr) => { - log::debug!("{:?}", addr); - Ok(NetIpAddr::from(addr)) - }, - None => { - log::debug!("name error"); - Err(DnsResponseCode::NameError) - } + match (name, 80).to_socket_addrs() { + // we throw away the port because we just want the IP address... + Ok(mut iter) => match iter.next() { + Some(addr) => { + log::debug!("{:?}", addr); + Ok(NetIpAddr::from(addr)) } - } + None => { + log::debug!("name error"); + Err(DnsResponseCode::NameError) + } + }, Err(e) => { log::debug!("format error: {:?}", e); Err(DnsResponseCode::FormatError) } } } + pub fn flush_cache(&self) -> Result<(), xous::Error> { log::warn!("DNS cache flush not implemented in hosted mode!"); Ok(()) diff --git a/services/dns/src/hw.rs b/services/dns/src/hw.rs index 1294ad5ba..12c0ffc31 100644 --- a/services/dns/src/hw.rs +++ b/services/dns/src/hw.rs @@ -1,10 +1,10 @@ #![cfg_attr(target_os = "none", no_std)] -use xous::CID; -use xous_ipc::{Buffer, String}; -use num_traits::ToPrimitive; +use std::net::IpAddr; use net::NetIpAddr; -use std::net::IpAddr; +use num_traits::ToPrimitive; +use xous::CID; +use xous_ipc::{Buffer, String}; use crate::api::*; @@ -15,10 +15,10 @@ pub struct Dns { impl Dns { pub fn new(xns: &xous_names::XousNames) -> Result { REFCOUNT.fetch_add(1, Ordering::Relaxed); - let conn = xns.request_connection_blocking(crate::api::SERVER_NAME_DNS).expect("Can't connect to Dns server"); - Ok(Dns { - conn - }) + let conn = xns + .request_connection_blocking(crate::api::SERVER_NAME_DNS) + .expect("Can't connect to Dns server"); + Ok(Dns { conn }) } /// Checks first to see if the name could be just an IPv4 or IPv6 in string form, @@ -31,19 +31,17 @@ impl Dns { let mut buf = Buffer::into_buf(alloc_name).or(Err(DnsResponseCode::UnknownError))?; buf.lend_mut(self.conn, Opcode::Lookup.to_u32().unwrap()) .or(Err(DnsResponseCode::UnknownError))?; - let response = buf.to_original::().or(Err(DnsResponseCode::UnknownError))?; - if let Some(addr) = response.addr { - Ok(addr) - } else { - Err(response.code) - } + let response = buf.to_original::().or(Err(DnsResponseCode::UnknownError))?; + if let Some(addr) = response.addr { Ok(addr) } else { Err(response.code) } } } + pub fn flush_cache(&self) -> Result<(), xous::Error> { xous::send_message( self.conn, - xous::Message::new_scalar(Opcode::Flush.to_usize().unwrap(), 0, 0, 0, 0) - ).map(|_| ()) + xous::Message::new_scalar(Opcode::Flush.to_usize().unwrap(), 0, 0, 0, 0), + ) + .map(|_| ()) } } @@ -51,13 +49,17 @@ use core::sync::atomic::{AtomicU32, Ordering}; static REFCOUNT: AtomicU32 = AtomicU32::new(0); impl Drop for Dns { fn drop(&mut self) { - // the connection to the server side must be reference counted, so that multiple instances of this object within - // a single process do not end up de-allocating the CID on other threads before they go out of scope. - // Note to future me: you want this. Don't get rid of it because you think, "nah, nobody will ever make more than one copy of this object". + // the connection to the server side must be reference counted, so that multiple instances of this + // object within a single process do not end up de-allocating the CID on other threads before + // they go out of scope. Note to future me: you want this. Don't get rid of it because you + // think, "nah, nobody will ever make more than one copy of this object". if REFCOUNT.fetch_sub(1, Ordering::Relaxed) == 1 { - unsafe{xous::disconnect(self.conn).unwrap();} + unsafe { + xous::disconnect(self.conn).unwrap(); + } } - // if there was object-specific state (such as a one-time use server for async callbacks, specific to the object instance), - // de-allocate those items here. They don't need a reference count because they are object-specific + // if there was object-specific state (such as a one-time use server for async callbacks, specific to + // the object instance), de-allocate those items here. They don't need a reference count + // because they are object-specific } -} \ No newline at end of file +} diff --git a/services/dns/src/lib.rs b/services/dns/src/lib.rs index eef26ee40..4f71b2d42 100644 --- a/services/dns/src/lib.rs +++ b/services/dns/src/lib.rs @@ -2,9 +2,9 @@ pub mod api; #[allow(unused_imports)] pub use api::*; -#[cfg(any(feature="precursor", feature="renode"))] +#[cfg(any(feature = "precursor", feature = "renode"))] mod hw; -#[cfg(any(feature="precursor", feature="renode"))] +#[cfg(any(feature = "precursor", feature = "renode"))] pub use hw::*; #[cfg(not(target_os = "xous"))] diff --git a/services/dns/src/main.rs b/services/dns/src/main.rs index 565562f42..2467e5b44 100644 --- a/services/dns/src/main.rs +++ b/services/dns/src/main.rs @@ -3,18 +3,17 @@ mod api; mod time; // why is this here? because it's the only place it'll fit. :-/ -use api::*; - -use net::NetIpAddr; -use num_traits::*; -use xous::msg_scalar_unpack; - use std::collections::HashMap; use std::convert::TryInto; use std::io::ErrorKind; use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr, UdpSocket}; -use std::time::Duration; use std::thread; +use std::time::Duration; + +use api::*; +use net::NetIpAddr; +use num_traits::*; +use xous::msg_scalar_unpack; use xous_ipc::{Buffer, String}; // KISS DNS @@ -47,11 +46,7 @@ struct Message { const FLAG_RD: u16 = 0x0100; // Recursion desired impl Message { - pub fn from(datagram: &[u8]) -> Self { - Self { - datagram: Vec::from(datagram), - } - } + pub fn from(datagram: &[u8]) -> Self { Self { datagram: Vec::from(datagram) } } pub fn query(qname: &str, qtype: QueryType, qclass: QueryClass, id: u16) -> Self { let mut datagram = Vec::new(); @@ -85,21 +80,11 @@ impl Message { Self { datagram } } - pub fn id(&self) -> u16 { - u16::from_be_bytes(self.datagram[0..2].try_into().unwrap()) - } + pub fn id(&self) -> u16 { u16::from_be_bytes(self.datagram[0..2].try_into().unwrap()) } - pub fn header(&self) -> u16 { - u16::from_be_bytes(self.datagram[2..4].try_into().unwrap()) - } + pub fn header(&self) -> u16 { u16::from_be_bytes(self.datagram[2..4].try_into().unwrap()) } - pub fn is_response(&self) -> bool { - if (self.header() & (1 << 15)) == 0 { - false - } else { - true - } - } + pub fn is_response(&self) -> bool { if (self.header() & (1 << 15)) == 0 { false } else { true } } fn fast_foward_name(&self, start: usize) -> Result { use DnsResponseCode::FormatError; @@ -156,9 +141,7 @@ impl Message { // pointer index += 1; if self.datagram[index] != 0xc { - log::error!( - "Found aname pointer, but value does not conform to length of aname header" - ); + log::error!("Found aname pointer, but value does not conform to length of aname header"); return Err(FormatError); } index += 1; @@ -195,10 +178,10 @@ impl Message { log::error!("Got a 4-byte address, but ATYPE != A (1)"); return Err(FormatError); } - // this copy happens because I can't figure out how to get Ipv4Addr::from() to realize it's casting from a [u8;4] + // this copy happens because I can't figure out how to get Ipv4Addr::from() to realize + // it's casting from a [u8;4] let mut rdata: [u8; 4] = [0; 4]; - for (&src, dst) in self.datagram[index..index + 4].iter().zip(rdata.iter_mut()) - { + for (&src, dst) in self.datagram[index..index + 4].iter().zip(rdata.iter_mut()) { *dst = src; } let addr = IpAddr::V4(Ipv4Addr::from(rdata)); @@ -211,12 +194,10 @@ impl Message { log::error!("Got a 16-byte address, but ATYPE != AAAA (28)"); return Err(FormatError); } - // this copy happens because I can't figure out how to get Ipv6Addr::from() to realize it's casting from a [u8;4] + // this copy happens because I can't figure out how to get Ipv6Addr::from() to realize + // it's casting from a [u8;4] let mut rdata: [u8; 16] = [0; 16]; - for (&src, dst) in self.datagram[index..index + 16] - .iter() - .zip(rdata.iter_mut()) - { + for (&src, dst) in self.datagram[index..index + 16].iter().zip(rdata.iter_mut()) { *dst = src; } let addr = IpAddr::V6(Ipv6Addr::from(rdata)); @@ -317,15 +298,13 @@ impl Resolver { pub fn new(xns: &xous_names::XousNames) -> Resolver { let trng = trng::Trng::new(&xns).unwrap(); let local_port = (49152 + trng.get_u32().unwrap() % 16384) as u16; - let socket = UdpSocket::bind( - format!("0.0.0.0:{}", local_port), - ) - .expect("couldn't create socket for DNS resolver"); + let socket = UdpSocket::bind(format!("0.0.0.0:{}", local_port)) + .expect("couldn't create socket for DNS resolver"); let timeout = Duration::from_millis(10_000); // 10 seconds for DNS to resolve by default socket.set_read_timeout(Some(timeout)).unwrap(); socket.set_nonblocking(false).unwrap(); // we want this to block. - // we /could/ do a non-blocking DNS resolver, but...what would you do in the meantime?? - // blocking is probably what we actually want this time. + // we /could/ do a non-blocking DNS resolver, but...what would you do in the meantime?? + // blocking is probably what we actually want this time. Resolver { mgr: net::protocols::DnsServerManager::register(&xns) @@ -336,26 +315,23 @@ impl Resolver { freeze: false, } } - pub fn add_server(&mut self, addr: IpAddr) { - self.mgr.add_server(addr); - } - pub fn remove_server(&mut self, addr: IpAddr) { - self.mgr.remove_server(addr); - } - pub fn clear_all_servers(&mut self) { - self.mgr.clear(); - } + + pub fn add_server(&mut self, addr: IpAddr) { self.mgr.add_server(addr); } + + pub fn remove_server(&mut self, addr: IpAddr) { self.mgr.remove_server(addr); } + + pub fn clear_all_servers(&mut self) { self.mgr.clear(); } + pub fn set_freeze_config(&mut self, freeze: bool) { self.freeze = freeze; self.mgr.set_freeze(freeze); } - pub fn get_freeze(&self) -> bool { - self.freeze - } + + pub fn get_freeze(&self) -> bool { self.freeze } + /// this allows us to re-use the TRNG object - pub fn trng_u32(&self) -> u32 { - self.trng.get_u32().unwrap() - } + pub fn trng_u32(&self) -> u32 { self.trng.get_u32().unwrap() } + pub fn resolve(&mut self, name: &str) -> Result, DnsResponseCode> { if let Some(dns_address) = self.mgr.get_random() { let dns_port = 53; @@ -366,9 +342,7 @@ impl Resolver { let qclass = QueryClass::IN; let query = Message::query(qname, qtype, qclass, self.trng.get_u32().unwrap() as u16); - self.socket - .send_to(&query.datagram, &server) - .map_err(|_| DnsResponseCode::NetworkError)?; + self.socket.send_to(&query.datagram, &server).map_err(|_| DnsResponseCode::NetworkError)?; match self.socket.recv(&mut self.buf) { Ok(len) => { @@ -407,10 +381,7 @@ enum NameConversionError { } fn name_from_msg(env: &xous::MessageEnvelope) -> Result<&str, NameConversionError> { - let msg = env - .body - .memory_message() - .ok_or(NameConversionError::InvalidMessageType)?; + let msg = env.body.memory_message().ok_or(NameConversionError::InvalidMessageType)?; let valid_bytes = msg.valid.map(|v| v.get()).unwrap_or_else(|| msg.buf.len()); if valid_bytes > DNS_NAME_LENGTH_LIMIT || valid_bytes < 1 { log::error!("valid bytes exceeded DNS name limit"); @@ -418,8 +389,7 @@ fn name_from_msg(env: &xous::MessageEnvelope) -> Result<&str, NameConversionErro } // Safe because we've already validated that it's a valid range let str_slice = unsafe { core::slice::from_raw_parts(msg.buf.as_ptr(), valid_bytes) }; - let name_string = - core::str::from_utf8(str_slice).map_err(|_| NameConversionError::InvalidString)?; + let name_string = core::str::from_utf8(str_slice).map_err(|_| NameConversionError::InvalidString)?; Ok(name_string) } @@ -494,9 +464,7 @@ fn main() -> ! { time::start_time_ux(); let xns = xous_names::XousNames::new().unwrap(); - let dns_sid = xns - .register_name(api::SERVER_NAME_DNS, None) - .expect("can't register server"); + let dns_sid = xns.register_name(api::SERVER_NAME_DNS, None).expect("can't register server"); log::trace!("registered with NS -- {:?}", dns_sid); // this will magically populate a list of DNS servers when they become available @@ -572,12 +540,9 @@ fn main() -> ! { }; } Some(Opcode::Lookup) => { - let mut buf = unsafe { - Buffer::from_memory_message_mut(msg.body.memory_message_mut().unwrap()) - }; - let name = buf - .to_original::, _>() - .unwrap(); + let mut buf = + unsafe { Buffer::from_memory_message_mut(msg.body.memory_message_mut().unwrap()) }; + let name = buf.to_original::, _>().unwrap(); let name_std = std::string::String::from(name.as_str().unwrap()); if let Some(cache_entry) = dns_cache.get(&name_std) { // pick a random entry @@ -617,30 +582,20 @@ fn main() -> ! { } } else { // no names found - let response = DnsResponse { - addr: None, - code: DnsResponseCode::NameError, - }; + let response = DnsResponse { addr: None, code: DnsResponseCode::NameError }; buf.replace(response).unwrap(); } } Err(e) => { log::debug!("DNS query failed: {}->{:?}", name, e); - let response = DnsResponse { - addr: None, - code: e, - }; + let response = DnsResponse { addr: None, code: e }; buf.replace(response).unwrap(); } } } } Some(Opcode::UpdateTtl) => msg_scalar_unpack!(msg, incr_secs, _, _, _, { - let increment = if incr_secs < u32::MAX as usize { - incr_secs as u32 - } else { - u32::MAX - }; + let increment = if incr_secs < u32::MAX as usize { incr_secs as u32 } else { u32::MAX }; if !resolver.get_freeze() { let mut expired_names = Vec::::new(); for (name, cache_map) in dns_cache.iter_mut() { diff --git a/services/dns/src/time.rs b/services/dns/src/time.rs index 47e1755ae..204fdc4b3 100644 --- a/services/dns/src/time.rs +++ b/services/dns/src/time.rs @@ -1,3 +1,7 @@ +use std::net::{SocketAddr, ToSocketAddrs, UdpSocket}; +use std::num::ParseIntError; +use std::sync::atomic::{AtomicBool, Ordering}; +use std::sync::Arc; /// The `time_server` is unique is that it is written for exclusive use by `libstd` to extract time. /// /// It also has a single hook that is callable from the PDDB to initialize a time value once the @@ -22,21 +26,18 @@ /// read RTC, plus you get milliseconds resolution. Time "T" can be updated at any time by just /// reading the RTC and noting the ticktimer offset at the point of reading. use std::thread; -use std::sync::Arc; -use std::sync::atomic::{AtomicBool, Ordering}; -#[cfg(any(feature="precursor", feature="renode"))] + +use chrono::prelude::*; +use gam::modal::*; +#[cfg(any(feature = "precursor", feature = "renode"))] use llio::*; -use pddb::PddbMountPoller; -use num_traits::*; // imports for time ux use locales::t; -use chrono::prelude::*; -use xous::{Message, send_message}; -use gam::modal::*; +use num_traits::*; +use pddb::PddbMountPoller; // ntp imports use sntpc::{Error, NtpContext, NtpTimestampGenerator, NtpUdpSocket, Result}; -use std::net::{SocketAddr, ToSocketAddrs, UdpSocket}; -use std::num::ParseIntError; +use xous::{send_message, Message}; /// This is a "well known name" used by `libstd` to connect to the time server /// Anyone who wants to check if time has been initialized would use this name. @@ -97,30 +98,20 @@ struct StdTimestampGen { } impl NtpTimestampGenerator for StdTimestampGen { fn init(&mut self) { - self.duration = std::time::SystemTime::now() - .duration_since(std::time::SystemTime::UNIX_EPOCH) - .unwrap(); + self.duration = + std::time::SystemTime::now().duration_since(std::time::SystemTime::UNIX_EPOCH).unwrap(); } - fn timestamp_sec(&self) -> u64 { - self.duration.as_secs() - } + fn timestamp_sec(&self) -> u64 { self.duration.as_secs() } - fn timestamp_subsec_micros(&self) -> u32 { - self.duration.subsec_micros() - } + fn timestamp_subsec_micros(&self) -> u32 { self.duration.subsec_micros() } } - #[derive(Debug)] struct UdpSocketWrapper(UdpSocket); impl NtpUdpSocket for UdpSocketWrapper { - fn send_to( - &self, - buf: &[u8], - addr: T, - ) -> Result { + fn send_to(&self, buf: &[u8], addr: T) -> Result { match self.0.send_to(buf, addr) { Ok(usize) => Ok(usize), Err(_) => Err(Error::Network), @@ -134,7 +125,7 @@ impl NtpUdpSocket for UdpSocketWrapper { } } } -#[cfg(any(feature="precursor", feature="renode"))] +#[cfg(any(feature = "precursor", feature = "renode"))] pub fn reset_rtc(i2c: &mut llio::I2c, start_time: u64, tt: &ticktimer_server::Ticktimer) { log::info!("performing rtc reset"); i2c.i2c_mutex_acquire(); @@ -152,16 +143,16 @@ pub fn reset_rtc(i2c: &mut llio::I2c, start_time: u64, tt: &ticktimer_server::Ti } let reset_vals = [ - 0, // clear interrupts, normal run - 0, // clear interrupts - RTC_PWR_MODE, // power mode - to_bcd((start_time & 0xFF) as u8 % 60), // seconds - to_bcd(((start_time >> 8) & 0xFF) as u8 % 60), // minutes - to_bcd(((start_time >> 16) & 0xFF) as u8 % 24), // hours + 0, // clear interrupts, normal run + 0, // clear interrupts + RTC_PWR_MODE, // power mode + to_bcd((start_time & 0xFF) as u8 % 60), // seconds + to_bcd(((start_time >> 8) & 0xFF) as u8 % 60), // minutes + to_bcd(((start_time >> 16) & 0xFF) as u8 % 24), // hours to_bcd(((start_time >> 24) & 0xFF) as u8 % 28 + 1), // days - 0, // sunday + 0, // sunday to_bcd(((start_time >> 32) & 0xFF) as u8 % 12 + 1), // months - to_bcd(((start_time >> 40) & 0xFF) as u8 % 5 + 1), // years + to_bcd(((start_time >> 40) & 0xFF) as u8 % 5 + 1), // years ]; i2c.i2c_mutex_acquire(); log::info!("writing: {:x?}", reset_vals); @@ -180,12 +171,12 @@ pub fn start_time_server() { let rtc_checked = Arc::new(AtomicBool::new(false)); // the public SID is well known and accessible by anyone who uses `libstd` - let pub_sid = xous::create_server_with_address(&TIME_SERVER_PUBLIC) - .expect("Couldn't create Ticktimer server"); + let pub_sid = + xous::create_server_with_address(&TIME_SERVER_PUBLIC).expect("Couldn't create Ticktimer server"); let self_cid = xous::connect(pub_sid).unwrap(); // this thread handles more sensitive operations on the RTC. - #[cfg(any(feature="precursor", feature="renode"))] + #[cfg(any(feature = "precursor", feature = "renode"))] thread::spawn({ let rtc_checked = rtc_checked.clone(); let self_cid = self_cid.clone(); @@ -205,8 +196,9 @@ pub fn start_time_server() { Some(susres::SuspendOrder::Early), &xns, PrivTimeOp::SusRes as u32, - priv_conn - ).expect("couldn't create suspend/resume object"); + priv_conn, + ) + .expect("couldn't create suspend/resume object"); // on boot, do the validation checks of the RTC. If it is not initialized or corrupted, fix it. let mut settings = [0u8; 8]; @@ -215,13 +207,13 @@ pub fn start_time_server() { match i2c.i2c_read_no_repeated_start(ABRTCMC_I2C_ADR, ABRTCMC_CONTROL3, &mut settings) { Ok(I2cStatus::ResponseReadOk) => { i2c.i2c_mutex_release(); - break - }, + break; + } _ => { i2c.i2c_mutex_release(); log::error!("Couldn't check RTC, retrying!"); xous::yield_slice(); // recheck in a fast loop, we really should be able to grab this resource on boot. - }, + } }; } if is_rtc_invalid(&settings) { @@ -239,11 +231,14 @@ pub fn start_time_server() { }), Some(PrivTimeOp::SusRes) => xous::msg_scalar_unpack!(msg, token, _, _, _, { susres.suspend_until_resume(token).expect("couldn't execute suspend/resume"); - // resync time on resume, but give a little time for other processes to clear as this is not urgent + // resync time on resume, but give a little time for other processes to clear as this + // is not urgent tt.sleep_ms(180).unwrap(); - send_message(self_cid, - Message::new_scalar(TimeOp::HwSync.to_usize().unwrap(), 0, 0, 0, 0) - ).expect("couldn't queue sync request"); + send_message( + self_cid, + Message::new_scalar(TimeOp::HwSync.to_usize().unwrap(), 0, 0, 0, 0), + ) + .expect("couldn't queue sync request"); }), _ => log::error!("Time server private thread received unknown opcode: {:?}", msg), } @@ -257,7 +252,7 @@ pub fn start_time_server() { move || { let xns = xous_names::XousNames::new().unwrap(); let llio = llio::Llio::new(&xns); - #[cfg(not(feature="minimal-testing"))] + #[cfg(not(feature = "minimal-testing"))] let prefs = userprefs::Manager::new(); let tt = ticktimer_server::Ticktimer::new().unwrap(); @@ -266,7 +261,8 @@ pub fn start_time_server() { tt.sleep_ms(42).unwrap(); } let mut start_rtc_secs: u64; - // this loop allows us to fail slightly more gracefully in the case that there is an RTC hardware failure + // this loop allows us to fail slightly more gracefully in the case that there is an RTC hardware + // failure loop { match llio.get_rtc_secs() { Ok(s) => { @@ -283,17 +279,19 @@ pub fn start_time_server() { log::trace!("start_rtc_secs: {}", start_rtc_secs); log::trace!("start_tt_ms: {}", start_tt_ms); - #[cfg(not(feature="minimal-testing"))] + #[cfg(not(feature = "minimal-testing"))] let pddb_poller = PddbMountPoller::new(); // enqueue a the first mount poll message - #[cfg(not(feature="minimal-testing"))] - xous::send_message(self_cid, - xous::Message::new_scalar(TimeOp::PddbMountPoll.to_usize().unwrap(), 0, 0, 0, 0) - ).expect("couldn't check mount poll"); + #[cfg(not(feature = "minimal-testing"))] + xous::send_message( + self_cid, + xous::Message::new_scalar(TimeOp::PddbMountPoll.to_usize().unwrap(), 0, 0, 0, 0), + ) + .expect("couldn't check mount poll"); // an initial behavior which just retuns the raw RTC time, until the PDDB is mounted. let mut temp = 0; loop { - #[cfg(not(feature="minimal-testing"))] + #[cfg(not(feature = "minimal-testing"))] if pddb_poller.is_mounted_nonblocking() { log::debug!("PDDB mount detected, transitioning to real-time adjusted server"); break; @@ -308,35 +306,37 @@ pub fn start_time_server() { log::trace!("mount poll"); } temp += 1; - xous::send_message(self_cid, - xous::Message::new_scalar(TimeOp::PddbMountPoll.to_usize().unwrap(), 0, 0, 0, 0) - ).expect("couldn't check mount poll"); + xous::send_message( + self_cid, + xous::Message::new_scalar(TimeOp::PddbMountPoll.to_usize().unwrap(), 0, 0, 0, 0), + ) + .expect("couldn't check mount poll"); } Some(TimeOp::HwSync) => { start_rtc_secs = llio.get_rtc_secs().expect("couldn't read RTC offset value"); start_tt_ms = tt.elapsed_ms(); - }, + } Some(TimeOp::GetUtcTimeMs) => xous::msg_blocking_scalar_unpack!(msg, _, _, _, _, { - let t = - start_rtc_secs as i64 * 1000i64 - + (tt.elapsed_ms() - start_tt_ms) as i64; + let t = start_rtc_secs as i64 * 1000i64 + (tt.elapsed_ms() - start_tt_ms) as i64; log::debug!("hw only UTC ms {}", t); // NOTE: endian swap for compatibility with `std` - xous::return_scalar2(msg.sender, + xous::return_scalar2( + msg.sender, (t as u64 & 0xFFFF_FFFF) as usize, (((t as u64) >> 32) & 0xFFFF_FFFF) as usize, - ).expect("couldn't respond to GetUtcTimeMs"); + ) + .expect("couldn't respond to GetUtcTimeMs"); }), Some(TimeOp::GetLocalTimeMs) => xous::msg_blocking_scalar_unpack!(msg, _, _, _, _, { - let t = - start_rtc_secs as i64 * 1000i64 - + (tt.elapsed_ms() - start_tt_ms) as i64; + let t = start_rtc_secs as i64 * 1000i64 + (tt.elapsed_ms() - start_tt_ms) as i64; assert!(t > 0, "time result is negative, this is an error"); log::debug!("hw only local ms {}", t); - xous::return_scalar2(msg.sender, + xous::return_scalar2( + msg.sender, (((t as u64) >> 32) & 0xFFFF_FFFF) as usize, (t as u64 & 0xFFFF_FFFF) as usize, - ).expect("couldn't respond to GetLocalTimeMs"); + ) + .expect("couldn't respond to GetLocalTimeMs"); }), Some(TimeOp::WallClockTimeInit) => xous::msg_blocking_scalar_unpack!(msg, _, _, _, _, { // definitely not initialized @@ -345,19 +345,22 @@ pub fn start_time_server() { _ => log::warn!("Time server can't handle this message yet: {:?}", msg), } } - #[cfg(not(feature="minimal-testing"))] + #[cfg(not(feature = "minimal-testing"))] let mut utc_offset_ms = prefs.utc_offset().unwrap_or_else(|error| { log::error!("cannot read utc offset: {:?}", error); 0 }); - #[cfg(not(feature="minimal-testing"))] - let mut tz_offset_ms = prefs.timezone_offset().unwrap_or_else(|error| { - log::error!("cannot read timezone offset: {:?}", error); - None - }).unwrap_or_default(); - #[cfg(feature="minimal-testing")] + #[cfg(not(feature = "minimal-testing"))] + let mut tz_offset_ms = prefs + .timezone_offset() + .unwrap_or_else(|error| { + log::error!("cannot read timezone offset: {:?}", error); + None + }) + .unwrap_or_default(); + #[cfg(feature = "minimal-testing")] let mut utc_offset_ms = 0; - #[cfg(feature="minimal-testing")] + #[cfg(feature = "minimal-testing")] let mut tz_offset_ms = 0; log::debug!("offset_key: {}", utc_offset_ms / 1000); @@ -372,86 +375,96 @@ pub fn start_time_server() { Some(TimeOp::PddbMountPoll) => { // do nothing, we're mounted now. continue; - }, - Some(TimeOp::HwSync) => { - match llio.get_rtc_secs() { - Ok(val) => { - start_rtc_secs = val; - start_tt_ms = tt.elapsed_ms(); - } - Err(e) => { - log::warn!("Error syncing time: {:?}; retrying!", e); - tt.sleep_ms(82).unwrap(); - send_message(self_cid, - Message::new_scalar(TimeOp::HwSync.to_usize().unwrap(), 0, 0, 0, 0) - ).expect("couldn't queue sync request"); - } + } + Some(TimeOp::HwSync) => match llio.get_rtc_secs() { + Ok(val) => { + start_rtc_secs = val; + start_tt_ms = tt.elapsed_ms(); + } + Err(e) => { + log::warn!("Error syncing time: {:?}; retrying!", e); + tt.sleep_ms(82).unwrap(); + send_message( + self_cid, + Message::new_scalar(TimeOp::HwSync.to_usize().unwrap(), 0, 0, 0, 0), + ) + .expect("couldn't queue sync request"); } }, Some(TimeOp::GetUtcTimeMs) => xous::msg_blocking_scalar_unpack!(msg, _, _, _, _, { - let t = - start_rtc_secs as i64 * 1000i64 + let t = start_rtc_secs as i64 * 1000i64 + (tt.elapsed_ms() - start_tt_ms) as i64 + utc_offset_ms; - if t < 0 { // the offset has some error in it, perhaps due to an RTC reset. reset the offset! - log::warn!("Time was negative, recovering from time setting error by clearing utc offset to 0"); + if t < 0 { + // the offset has some error in it, perhaps due to an RTC reset. reset the offset! + log::warn!( + "Time was negative, recovering from time setting error by clearing utc offset to 0" + ); prefs.set_utc_offset(0).ok(); utc_offset_ms = 0; } log::trace!("utc ms {}", t); // NOTE: endian swap for compatibility with `std` - xous::return_scalar2(msg.sender, + xous::return_scalar2( + msg.sender, (t as u64 & 0xFFFF_FFFF) as usize, (((t as u64) >> 32) & 0xFFFF_FFFF) as usize, - ).expect("couldn't respond to GetUtcTimeMs"); + ) + .expect("couldn't respond to GetUtcTimeMs"); }), Some(TimeOp::GetLocalTimeMs) => xous::msg_blocking_scalar_unpack!(msg, _, _, _, _, { - log::trace!("current offset {}", (start_rtc_secs as i64 * 1000i64 + (tt.elapsed_ms() - start_tt_ms) as i64) / 1000); - let t = - start_rtc_secs as i64 * 1000i64 + log::trace!( + "current offset {}", + (start_rtc_secs as i64 * 1000i64 + (tt.elapsed_ms() - start_tt_ms) as i64) / 1000 + ); + let t = start_rtc_secs as i64 * 1000i64 + (tt.elapsed_ms() - start_tt_ms) as i64 + utc_offset_ms + tz_offset_ms; if t < 0 { - log::warn!("Time was negative, recovering from time setting error by clearing utc and timezone offsets to 0."); + log::warn!( + "Time was negative, recovering from time setting error by clearing utc and timezone offsets to 0." + ); prefs.set_utc_offset(0).ok(); prefs.set_timezone_offset(0).ok(); utc_offset_ms = 0; tz_offset_ms = 0; } log::trace!("local since epoch {}", t / 1000); - xous::return_scalar2(msg.sender, + xous::return_scalar2( + msg.sender, (((t as u64) >> 32) & 0xFFFF_FFFF) as usize, (t as u64 & 0xFFFF_FFFF) as usize, - ).expect("couldn't respond to GetLocalTimeMs"); - }), - Some(TimeOp::SetUtcTimeMs) => xous::msg_scalar_unpack!(msg, utc_hi_ms, utc_lo_ms, _, _, { - let utc_time_ms = (utc_hi_ms as i64) << 32 | (utc_lo_ms as i64); - start_rtc_secs = llio.get_rtc_secs().expect("couldn't read RTC offset value"); - start_tt_ms = tt.elapsed_ms(); - log::info!("utc_time: {}", utc_time_ms / 1000); - log::info!("rtc_secs: {}", start_rtc_secs); - log::info!("start_tt_ms: {}", start_tt_ms); - let offset = - utc_time_ms - - (start_rtc_secs as i64) * 1000; - utc_offset_ms = offset; - #[cfg(not(feature="minimal-testing"))] - prefs.set_utc_offset(offset).unwrap_or_else(|err| { - log::error!("cannot set utc offset: {:?}", err); - }); + ) + .expect("couldn't respond to GetLocalTimeMs"); }), + Some(TimeOp::SetUtcTimeMs) => { + xous::msg_scalar_unpack!(msg, utc_hi_ms, utc_lo_ms, _, _, { + let utc_time_ms = (utc_hi_ms as i64) << 32 | (utc_lo_ms as i64); + start_rtc_secs = llio.get_rtc_secs().expect("couldn't read RTC offset value"); + start_tt_ms = tt.elapsed_ms(); + log::info!("utc_time: {}", utc_time_ms / 1000); + log::info!("rtc_secs: {}", start_rtc_secs); + log::info!("start_tt_ms: {}", start_tt_ms); + let offset = utc_time_ms - (start_rtc_secs as i64) * 1000; + utc_offset_ms = offset; + #[cfg(not(feature = "minimal-testing"))] + prefs.set_utc_offset(offset).unwrap_or_else(|err| { + log::error!("cannot set utc offset: {:?}", err); + }); + }) + } Some(TimeOp::SetTzOffsetMs) => xous::msg_scalar_unpack!(msg, tz_hi_ms, tz_lo_ms, _, _, { let tz_ms = ((tz_hi_ms as i64) << 32) | (tz_lo_ms as i64); - // sanity check with very broad bounds: I don't know of any time zones that are more than +/2 days from UTC - // 86400 seconds in a day, times 1000 milliseconds, times 2 days - if tz_ms < -(86400 * 1000 * 2) || - tz_ms > 86400 * 1000 * 2 { + // sanity check with very broad bounds: I don't know of any time zones that are more + // than +/2 days from UTC 86400 seconds in a day, times 1000 + // milliseconds, times 2 days + if tz_ms < -(86400 * 1000 * 2) || tz_ms > 86400 * 1000 * 2 { log::warn!("Requested timezone offset {} is out of bounds, ignoring!", tz_ms); continue; } else { tz_offset_ms = tz_ms; - #[cfg(not(feature="minimal-testing"))] + #[cfg(not(feature = "minimal-testing"))] prefs.set_timezone_offset(tz_ms).unwrap_or_else(|err| { log::error!("cannot set timezone offset: {:?}", err); }); @@ -505,9 +518,7 @@ fn is_rtc_invalid(settings: &[u8]) -> bool { } #[allow(dead_code)] -fn to_binary(bcd: u8) -> u8 { - (bcd & 0xf) + ((bcd >> 4) * 10) -} +fn to_binary(bcd: u8) -> u8 { (bcd & 0xf) + ((bcd >> 4) * 10) } #[allow(dead_code)] fn to_bcd(binary: u8) -> u8 { let mut lsd: u8 = binary % 10; @@ -542,7 +553,7 @@ fn simple_kilofloat_parse(input: &str) -> core::result::Result() // you can't create a ParseIntError any other way + return "z".parse::(); // you can't create a ParseIntError any other way } } Ok(result) @@ -552,14 +563,15 @@ fn simple_kilofloat_parse(input: &str) -> core::result::Result xous::msg_scalar_unpack!(msg, _, _, _, _, { if !pddb_poller.is_mounted_nonblocking() { - modals.show_notification(t!("stats.please_mount", locales::LANG), None).expect("couldn't show notification"); + modals + .show_notification(t!("stats.please_mount", locales::LANG), None) + .expect("couldn't show notification"); continue; } let mut tz_set = false; @@ -579,7 +593,7 @@ pub (crate) fn start_time_ux() { Some(data) => { tz_set = true; data - }, + } None => { tz_set = false; 0i64 @@ -595,40 +609,52 @@ pub (crate) fn start_time_ux() { // a key exists, but nothing was written to it (length of key was 0 or inappropriate) if !tz_set { log::info!("{}RTC.TZ,{}", xous::BOOKEND_START, xous::BOOKEND_END); - let tz_str = modals.alert_builder(t!("rtc.timezone", locales::LANG)) + let tz_str = modals + .alert_builder(t!("rtc.timezone", locales::LANG)) .field(None, Some(tz_ux_validator)) .build() .expect("couldn't get timezone") .first(); - let tz = simple_kilofloat_parse(tz_str.as_str()).expect("pre-validated input failed to re-parse!"); + let tz = simple_kilofloat_parse(tz_str.as_str()) + .expect("pre-validated input failed to re-parse!"); log::info!("got tz offset {}", tz); tz_offset_ms = (tz * 3600) as i64; - xous::send_message(timeserver_cid, + xous::send_message( + timeserver_cid, Message::new_scalar( crate::time::TimeOp::SetTzOffsetMs.to_usize().unwrap(), (tz_offset_ms >> 32) as usize, (tz_offset_ms & 0xFFFF_FFFF) as usize, - 0, 0, - ) - ).expect("couldn't set timezone"); + 0, + 0, + ), + ) + .expect("couldn't set timezone"); } // see if we want to try to use NTP or not log::info!("{}RTC.NTP,{}", xous::BOOKEND_START, xous::BOOKEND_END); - modals.add_list_item(t!("pddb.yes", locales::LANG)).expect("couldn't build radio item list"); - modals.add_list_item(t!("pddb.no", locales::LANG)).expect("couldn't build radio item list"); + modals + .add_list_item(t!("pddb.yes", locales::LANG)) + .expect("couldn't build radio item list"); + modals + .add_list_item(t!("pddb.no", locales::LANG)) + .expect("couldn't build radio item list"); let mut try_ntp = true; match modals.get_radiobutton(t!("rtc.try_ntp", locales::LANG)) { Ok(selection) => { if selection == t!("pddb.no", locales::LANG) { try_ntp = false; } - }, + } _ => log::error!("get_radiobutton failed"), } if try_ntp { let local_port = (trng.get_u32().unwrap() % 16384 + 49152) as u16; - let socket_addr = SocketAddr::new(std::net::IpAddr::V4(std::net::Ipv4Addr::new(0, 0, 0, 0)), local_port); + let socket_addr = SocketAddr::new( + std::net::IpAddr::V4(std::net::Ipv4Addr::new(0, 0, 0, 0)), + local_port, + ); let socket = UdpSocket::bind(socket_addr).expect("Unable to create UDP socket"); log::debug!("NTP rx socket created {:?}", socket); socket @@ -640,24 +666,30 @@ pub (crate) fn start_time_ux() { match result { Ok(time) => { log::info!("Got NTP time: {}.{}", time.sec(), time.sec_fraction()); - let current_time = Utc.ymd(1970, 1, 1).and_hms(0, 0, 0) + chrono::Duration::seconds(time.sec() as i64); + let current_time = Utc.ymd(1970, 1, 1).and_hms(0, 0, 0) + + chrono::Duration::seconds(time.sec() as i64); log::info!("Setting UTC time: {:?}", current_time.to_string()); - xous::send_message(timeserver_cid, + xous::send_message( + timeserver_cid, Message::new_scalar( crate::time::TimeOp::SetUtcTimeMs.to_usize().unwrap(), ((current_time.timestamp_millis() as u64) >> 32) as usize, (current_time.timestamp_millis() as u64 & 0xFFFF_FFFF) as usize, - 0, 0, - ) - ).expect("couldn't set time"); + 0, + 0, + ), + ) + .expect("couldn't set time"); log::info!("{}RTC.NTPOK,{}", xous::BOOKEND_START, xous::BOOKEND_END); continue; } Err(err) => { log::info!("Err: {:?}", err); log::info!("{}RTC.NTPFAIL,{}", xous::BOOKEND_START, xous::BOOKEND_END); - modals.show_notification(t!("rtc.ntp_fail", locales::LANG), None).expect("couldn't show NTP error"); - }, + modals + .show_notification(t!("rtc.ntp_fail", locales::LANG), None) + .expect("couldn't show NTP error"); + } } } @@ -668,18 +700,38 @@ pub (crate) fn start_time_ux() { let mut days: u8 = 0; let mut years: u8 = 0; - let date = modals.alert_builder(t!("rtc.set_time_modal", locales::LANG)) - .field(Some(String::from(t!("rtc.month", locales::LANG))), Some(rtc_ux_validate_month)) - .field(Some(String::from(t!("rtc.day", locales::LANG))), Some(rtc_ux_validate_day)) - .field(Some(String::from(t!("rtc.year", locales::LANG))), Some(rtc_ux_validate_year)) - .field(Some(String::from(t!("rtc.hour", locales::LANG))), Some(rtc_ux_validate_hour)) - .field(Some(String::from(t!("rtc.minute", locales::LANG))), Some(rtc_ux_validate_minute)) - .field(Some(String::from(t!("rtc.seconds", locales::LANG))), Some(rtc_ux_validate_seconds)) + let date = modals + .alert_builder(t!("rtc.set_time_modal", locales::LANG)) + .field( + Some(String::from(t!("rtc.month", locales::LANG))), + Some(rtc_ux_validate_month), + ) + .field( + Some(String::from(t!("rtc.day", locales::LANG))), + Some(rtc_ux_validate_day), + ) + .field( + Some(String::from(t!("rtc.year", locales::LANG))), + Some(rtc_ux_validate_year), + ) + .field( + Some(String::from(t!("rtc.hour", locales::LANG))), + Some(rtc_ux_validate_hour), + ) + .field( + Some(String::from(t!("rtc.minute", locales::LANG))), + Some(rtc_ux_validate_minute), + ) + .field( + Some(String::from(t!("rtc.seconds", locales::LANG))), + Some(rtc_ux_validate_seconds), + ) .build() .expect("cannot get date from user"); for (index, elem) in date.content().iter().enumerate() { - let elem = elem.as_str().parse::().expect("pre-validated input failed to re-parse!"); + let elem = + elem.as_str().parse::().expect("pre-validated input failed to re-parse!"); match index { 0 => months = elem, 1 => days = elem, @@ -687,29 +739,36 @@ pub (crate) fn start_time_ux() { 3 => hours = elem, 4 => mins = elem, 5 => secs = elem, - _ => {}, + _ => {} } } log::info!("Setting time: {}/{}/{} {}:{}:{}", months, days, years, hours, mins, secs); - let new_dt = chrono::FixedOffset::east((tz_offset_ms / 1000) as i32).ymd(years as i32 + 2000, months as u32, days as u32) - .and_hms(hours as u32, mins as u32, secs as u32); - xous::send_message(timeserver_cid, + let new_dt = chrono::FixedOffset::east((tz_offset_ms / 1000) as i32) + .ymd(years as i32 + 2000, months as u32, days as u32) + .and_hms(hours as u32, mins as u32, secs as u32); + xous::send_message( + timeserver_cid, Message::new_scalar( crate::time::TimeOp::SetUtcTimeMs.to_usize().unwrap(), ((new_dt.timestamp_millis() as u64) >> 32) as usize, (new_dt.timestamp_millis() as u64 & 0xFFFF_FFFF) as usize, - 0, 0, - ) - ).expect("couldn't set time"); + 0, + 0, + ), + ) + .expect("couldn't set time"); }), Some(crate::TimeUxOp::SetTimeZone) => xous::msg_scalar_unpack!(msg, _, _, _, _, { if !pddb_poller.is_mounted_nonblocking() { - modals.show_notification(t!("stats.please_mount", locales::LANG), None).expect("couldn't show notification"); + modals + .show_notification(t!("stats.please_mount", locales::LANG), None) + .expect("couldn't show notification"); continue; } - let tz_str = modals.alert_builder(t!("rtc.timezone", locales::LANG)) + let tz_str = modals + .alert_builder(t!("rtc.timezone", locales::LANG)) .field(None, Some(tz_ux_validator)) .build() .expect("couldn't get timezone") @@ -718,14 +777,17 @@ pub (crate) fn start_time_ux() { .expect("pre-validated input failed to re-parse!"); log::info!("got tz offset {}", tz); let tzoff_ms = (tz * 3600) as i64; - xous::send_message(timeserver_cid, + xous::send_message( + timeserver_cid, Message::new_scalar( crate::time::TimeOp::SetTzOffsetMs.to_usize().unwrap(), (tzoff_ms >> 32) as usize, (tzoff_ms & 0xFFFF_FFFF) as usize, - 0, 0, - ) - ).expect("couldn't set timezone"); + 0, + 0, + ), + ) + .expect("couldn't set timezone"); }), Some(crate::TimeUxOp::Quit) => { xous::return_scalar(msg.sender, 0).unwrap(); @@ -756,9 +818,11 @@ fn tz_ux_validator(input: TextEntryPayload) -> Option { let text_str = input.as_str(); match simple_kilofloat_parse(text_str) { - Ok(input) => if input < -12_000 || input > 14_000 { - return Some(ValidatorErr::from_str(t!("rtc.range_err", locales::LANG))); - }, + Ok(input) => { + if input < -12_000 || input > 14_000 { + return Some(ValidatorErr::from_str(t!("rtc.range_err", locales::LANG))); + } + } _ => return Some(ValidatorErr::from_str(t!("rtc.integer_err", locales::LANG))), } None @@ -773,7 +837,7 @@ fn rtc_ux_validate_month(input: TextEntryPayload) -> Option { }; if input < 1 || input > 12 { - return Some(ValidatorErr::from_str(t!("rtc.range_err", locales::LANG))) + return Some(ValidatorErr::from_str(t!("rtc.range_err", locales::LANG))); } None @@ -788,7 +852,7 @@ fn rtc_ux_validate_day(input: TextEntryPayload) -> Option { }; if input < 1 || input > 31 { - return Some(ValidatorErr::from_str(t!("rtc.range_err", locales::LANG))) + return Some(ValidatorErr::from_str(t!("rtc.range_err", locales::LANG))); } None @@ -803,7 +867,7 @@ fn rtc_ux_validate_year(input: TextEntryPayload) -> Option { }; if input > 99 { - return Some(ValidatorErr::from_str(t!("rtc.range_err", locales::LANG))) + return Some(ValidatorErr::from_str(t!("rtc.range_err", locales::LANG))); } None @@ -818,7 +882,7 @@ fn rtc_ux_validate_hour(input: TextEntryPayload) -> Option { }; if input > 23 { - return Some(ValidatorErr::from_str(t!("rtc.range_err", locales::LANG))) + return Some(ValidatorErr::from_str(t!("rtc.range_err", locales::LANG))); } None @@ -833,7 +897,7 @@ fn rtc_ux_validate_minute(input: TextEntryPayload) -> Option { }; if input > 59 { - return Some(ValidatorErr::from_str(t!("rtc.range_err", locales::LANG))) + return Some(ValidatorErr::from_str(t!("rtc.range_err", locales::LANG))); } None @@ -848,9 +912,8 @@ fn rtc_ux_validate_seconds(input: TextEntryPayload) -> Option { }; if input > 59 { - return Some(ValidatorErr::from_str(t!("rtc.range_err", locales::LANG))) + return Some(ValidatorErr::from_str(t!("rtc.range_err", locales::LANG))); } None } -