mod err; use std::{ fs, io::{Read, Write}, net::{SocketAddr, TcpStream}, time::{self, Duration, Instant}, }; use chrono::Utc; fn main() { let cur = Utc::now().format("%s"); let mut log_file = fs::File::create(format!("logs/log_{}.csv", cur)).unwrap(); writeln!(log_file, "Unix TS, Temp, Read, Hi, Lo").unwrap(); let sleep_time = time::Duration::from_millis(100); loop { let last_check = Instant::now(); while last_check.elapsed().as_secs() < 5 { std::thread::sleep(sleep_time); } write!(log_file, "{}, ", Utc::now().format("%s")).unwrap(); match get_pico_update() { Ok(vals) => { let vals_str: Vec = vals.iter().map(|v| format!("{v}")).collect(); writeln!(log_file, "{}", vals_str.join(", ")).unwrap(); } Err(_) => writeln!(log_file, "E, E, E, E").unwrap(), } } } fn get_pico_update() -> Result<[u16; 4], err::RemotePicoError> { let socket_addr: SocketAddr = "192.168.1.201:1234".parse().unwrap(); let Ok(mut stream) = TcpStream::connect_timeout(&socket_addr, Duration::from_secs_f32(1.5)) else { return Err(err::RemotePicoError::ConnectionRefused); }; match stream.write("Hello Pico!".as_bytes()) { Err(_) => return Err(err::RemotePicoError::StreamWriteError), _ => (), } let mut buf = [0u8; 4096]; match stream.read(&mut buf) { Err(_) => return Err(err::RemotePicoError::StreamReadError), _ => (), } let buf = buf; let mut vals = [0u16; 4]; for (i, v) in vals.iter_mut().enumerate() { let mut u16_buf = [0u8; 2]; u16_buf.copy_from_slice(&buf[i * 2..i * 2 + 2]); *v = u16::from_le_bytes(u16_buf); } match buf[vals.len() * 2] { b'E' => (), _ => return Err(err::RemotePicoError::CorruptReadError), } println!("Values: {vals:?}"); let t = vals[0]; println!("Int Temp: {}°C", convert_to_celsius(t)); let mx = vals[2]; println!("3V Ref: {}", mx); let mn = vals[3]; println!("GND Ref: {}", mn); let mv = convert_to_mv(vals[1], mn, mx); println!("Read {mv}mV"); let v_divider_inv = convert_voltage_div(mv); println!("{}mV", v_divider_inv); return Ok(vals); } fn convert_voltage_div(mv: u32) -> f32 { let r1 = 22300.; let r2 = 3300.; mv as f32 / (r2 / (r1 + r2)) } fn convert_to_mv(raw_adc_val: u16, adc_min: u16, adc_max: u16) -> u32 { (raw_adc_val.saturating_sub(adc_min)) as u32 * 3000 / adc_max as u32 } fn convert_to_celsius(raw_temp: u16) -> f32 { // According to chapter 4.9.5. Temperature Sensor in RP2040 datasheet let temp = 27.0 - (raw_temp as f32 * 3. / 4096.0 - 0.706) / 0.001721; let sign = if temp < 0.0 { -1.0 } else { 1.0 }; let rounded_temp_x10: i16 = ((temp * 10.0) + 0.5 * sign) as i16; (rounded_temp_x10 as f32) / 10.0 }