A personal rust firmware for the Badger 2040 W

Time working well enough

Changed files
+121 -20
src
+121 -20
src/main.rs
··· 4 4 5 5 #![no_std] 6 6 #![no_main] 7 + use core::str::from_utf8; 8 + use core::time; 9 + 7 10 use badge_display::display_image::DisplayImage; 8 11 use badge_display::{run_the_display, CHANGE_IMAGE, CURRENT_IMAGE, RTC_TIME_STRING}; 9 - use bt_hci::cmd::info; 10 12 use cyw43_driver::setup_cyw43; 11 13 use cyw43_pio::PioSpi; 12 14 use defmt::info; 15 + use defmt::*; 13 16 use embassy_executor::Spawner; 17 + use embassy_net::dns::DnsSocket; 18 + use embassy_net::tcp::client::{TcpClient, TcpClientState}; 14 19 use embassy_net::{Stack, StackResources}; 15 20 use embassy_rp::clocks::RoscRng; 16 21 use embassy_rp::gpio; ··· 24 29 use embassy_time::{Duration, Timer}; 25 30 use env::env_value; 26 31 use gpio::{Level, Output, Pull}; 32 + use heapless::Vec; 27 33 use helpers::easy_format; 28 34 use rand::RngCore; 35 + use reqwless::client::{HttpClient, TlsConfig, TlsVerify}; 36 + use reqwless::request::Method; 37 + use serde::Deserialize; 29 38 use static_cell::StaticCell; 30 39 use temp_sensor::run_the_temp_sensor; 31 40 use {defmt_rtt as _, panic_probe as _}; ··· 100 109 RESOURCES.init(StackResources::<5>::new()), 101 110 seed, 102 111 )); 112 + //rtc setup 113 + let mut rtc = embassy_rp::rtc::Rtc::new(p.RTC); 103 114 104 115 spawner.must_spawn(net_task(stack)); 105 116 //Attempt to connect to wifi to get RTC time loop for 2 minutes ··· 123 134 wifi_connection_attempts += 1; 124 135 } 125 136 137 + let mut time_was_set = false; 126 138 if connected_to_wifi { 127 139 info!("waiting for DHCP..."); 128 140 while !stack.is_config_up() { ··· 139 151 info!("waiting for stack to be up..."); 140 152 stack.wait_config_up().await; 141 153 info!("Stack is up!"); 142 - } 154 + 155 + //RTC Web request 156 + let mut rx_buffer = [0; 8192]; 157 + let mut tls_read_buffer = [0; 16640]; 158 + let mut tls_write_buffer = [0; 16640]; 159 + let client_state = TcpClientState::<1, 1024, 1024>::new(); 160 + let tcp_client = TcpClient::new(stack, &client_state); 161 + let dns_client = DnsSocket::new(stack); 162 + let tls_config = TlsConfig::new( 163 + seed, 164 + &mut tls_read_buffer, 165 + &mut tls_write_buffer, 166 + TlsVerify::None, 167 + ); 168 + 169 + let mut http_client = HttpClient::new_with_tls(&tcp_client, &dns_client, tls_config); 170 + let url = env_value("TIME_API"); 171 + info!("connecting to {}", &url); 172 + 173 + let mut request = match http_client.request(Method::GET, &url).await { 174 + Ok(req) => req, 175 + Err(e) => { 176 + error!("Failed to make HTTP request: {:?}", e); 177 + return; // handle the error 178 + } 179 + }; 143 180 144 - //rtc setup 145 - let mut rtc = embassy_rp::rtc::Rtc::new(p.RTC); 146 - if !rtc.is_running() { 147 - info!("Start RTC"); 148 - let now = DateTime { 149 - year: 2000, 150 - month: 1, 151 - day: 1, 152 - day_of_week: DayOfWeek::Saturday, 153 - hour: 18, 154 - minute: 31, 155 - second: 0, 181 + let response = match request.send(&mut rx_buffer).await { 182 + Ok(resp) => resp, 183 + Err(_e) => { 184 + error!("Failed to send HTTP request"); 185 + return; // handle the error; 186 + } 187 + }; 188 + 189 + let body = match from_utf8(response.body().read_to_end().await.unwrap()) { 190 + Ok(b) => b, 191 + Err(_e) => { 192 + error!("Failed to read response body"); 193 + return; // handle the error 194 + } 156 195 }; 157 - rtc.set_datetime(now).unwrap(); 196 + info!("Response body: {:?}", &body); 197 + 198 + let bytes = body.as_bytes(); 199 + match serde_json_core::de::from_slice::<TimeApiResponse>(bytes) { 200 + Ok((output, _used)) => { 201 + //Deadlines am i right? 202 + info!("Datetime: {:?}", output.datetime); 203 + //split at T 204 + let datetime = output.datetime.split('T').collect::<Vec<&str, 2>>(); 205 + //split at - 206 + let date = datetime[0].split('-').collect::<Vec<&str, 3>>(); 207 + let year = date[0].parse::<u16>().unwrap(); 208 + let month = date[1].parse::<u8>().unwrap(); 209 + let day = date[2].parse::<u8>().unwrap(); 210 + //split at : 211 + let time = datetime[1].split(':').collect::<Vec<&str, 4>>(); 212 + let hour = time[0].parse::<u8>().unwrap(); 213 + let minute = time[1].parse::<u8>().unwrap(); 214 + //split at . 215 + let second_split = time[2].split('.').collect::<Vec<&str, 2>>(); 216 + let second = second_split[0].parse::<f64>().unwrap(); 217 + let rtc_time = DateTime { 218 + year: year, 219 + month: month, 220 + day: day, 221 + day_of_week: match output.day_of_week { 222 + 0 => DayOfWeek::Sunday, 223 + 1 => DayOfWeek::Monday, 224 + 2 => DayOfWeek::Tuesday, 225 + 3 => DayOfWeek::Wednesday, 226 + 4 => DayOfWeek::Thursday, 227 + 5 => DayOfWeek::Friday, 228 + 6 => DayOfWeek::Saturday, 229 + _ => DayOfWeek::Sunday, 230 + }, 231 + hour, 232 + minute, 233 + second: second as u8, 234 + }; 235 + rtc.set_datetime(rtc_time).unwrap(); 236 + time_was_set = true; 237 + } 238 + Err(_e) => { 239 + error!("Failed to parse response body"); 240 + return; // handle the error 241 + } 242 + } 158 243 } 159 244 245 + // 246 + 160 247 //Task spawning 161 248 spawner.must_spawn(run_the_temp_sensor(p.I2C0, p.PIN_5, p.PIN_4)); 162 249 spawner.must_spawn(run_the_display(spi_bus, cs, dc, busy, reset)); ··· 174 261 continue; 175 262 } 176 263 177 - let now = rtc.now(); 178 - match now { 179 - Ok(time) => set_display_time(time), 180 - Err(_) => { 181 - info!("Error getting time"); 264 + if time_was_set { 265 + let now = rtc.now(); 266 + match now { 267 + Ok(time) => set_display_time(time), 268 + Err(_) => { 269 + info!("Error getting time"); 270 + } 182 271 } 272 + } else { 273 + RTC_TIME_STRING.lock(|rtc_time_string| { 274 + rtc_time_string.borrow_mut().clear(); 275 + rtc_time_string.borrow_mut().push_str("No Wifi").unwrap(); 276 + }); 183 277 } 184 278 185 279 Timer::after(Duration::from_millis(100)).await; ··· 217 311 async fn net_task(stack: &'static Stack<cyw43::NetDriver<'static>>) -> ! { 218 312 stack.run().await 219 313 } 314 + 315 + #[derive(Deserialize)] 316 + struct TimeApiResponse<'a> { 317 + datetime: &'a str, 318 + day_of_week: u8, 319 + // other fields as needed 320 + }