From 751b16391f3bec5e9b4d2359184efbf33978f349 Mon Sep 17 00:00:00 2001 From: Anshul Gupta Date: Wed, 3 Jan 2024 17:07:38 -0800 Subject: [PATCH] Adds temperature dumping --- src/main.rs | 12 ++-- src/storage/mod.rs | 29 ++++++++++ src/terminal.rs | 136 ++++++++++++++++++++++++++++++++++----------- 3 files changed, 139 insertions(+), 38 deletions(-) diff --git a/src/main.rs b/src/main.rs index 48adee6..ca17818 100644 --- a/src/main.rs +++ b/src/main.rs @@ -242,22 +242,22 @@ mod app { // Append to buffer if buffer.push_back(b).is_err() { - panic!("Buffer overflow"); + error!("Buffer overflow"); } } Err(nb::Error::WouldBlock) => break, Err(nb::Error::Other(serial::Error::Framing)) => { - panic!("USART error: Framing"); + error!("USART error: Framing"); } - Err(nb::Error::Other(serial::Error::Noise)) => panic!("USART error: Noise"), + Err(nb::Error::Other(serial::Error::Noise)) => error!("USART error: Noise"), Err(nb::Error::Other(serial::Error::Overrun)) => { - panic!("USART error: Overrun"); + error!("USART error: Overrun"); } Err(nb::Error::Other(serial::Error::Parity)) => { - panic!("USART error: Parity"); + error!("USART error: Parity"); } - Err(nb::Error::Other(_)) => defmt::panic!("USART error: Unknown"), + Err(nb::Error::Other(_)) => defmt::error!("USART error: Unknown"), // Err(nb::Error::Other(e)) => core::panic!("USART error: {:?}", e), } }); diff --git a/src/storage/mod.rs b/src/storage/mod.rs index f5c4ce5..9d70a53 100644 --- a/src/storage/mod.rs +++ b/src/storage/mod.rs @@ -20,6 +20,12 @@ impl Storage { let temp = Temp::now_from_temp(temp); self.temps.write(temp); } + + pub fn oldest(&self) -> OldestOrdered<'_, N> { + OldestOrdered { + iter: self.temps.oldest_ordered(), + } + } } #[derive(Debug, Copy, Clone)] @@ -52,4 +58,27 @@ impl Temp { fn now_from_temp(temp: Temperature) -> Self { Self::now(temp.saturating_to_num()) } + + #[inline] + const fn secs(self) -> u32 { + u32::from_le_bytes([self.secs[0], self.secs[1], self.secs[2], 0]) + } + + #[inline] + fn value(self) -> Temperature { + self.value.to_num() + } +} + +#[derive(Clone)] +pub struct OldestOrdered<'a, const N: usize> { + iter: heapless::OldestOrdered<'a, Temp, N>, +} + +impl<'a, const N: usize> Iterator for OldestOrdered<'a, N> { + type Item = (u32, Temperature); + + fn next(&mut self) -> Option { + self.iter.next().map(|temp| (temp.secs(), temp.value())) + } } diff --git a/src/terminal.rs b/src/terminal.rs index 4f38431..3a15e8c 100644 --- a/src/terminal.rs +++ b/src/terminal.rs @@ -1,16 +1,32 @@ use core::fmt::Write; -use defmt::*; +use defmt::{panic, *}; use embedded_hal::digital::v2::OutputPin; use heapless::{Deque, Vec}; +use num_traits::AsPrimitive; use rtic::Mutex; use stm32f0xx_hal::prelude::*; -use crate::{app::terminal::Context, ds18b20::Resolution}; +use crate::{app::terminal::Context, ds18b20::Resolution, thermometer::Temperature}; pub const BUFFER_SIZE: usize = 32; const OK_STR: &str = "ok\r\n"; +const HELP_STR: &str = "Commands:\r + help\r + devices\r + resolution <9|10|11|12>?\r + pid\r + pid \r + temp\r + cooler ?\r + watch temp\r + dump temps\r + dump events\r + erase\r + reset\r +"; + /// Terminal handler /// /// Commands: @@ -83,6 +99,20 @@ pub fn terminal(mut cx: Context<'_>) { } Some(b) => unknown_argument(&mut cx, b), }, + Some(b"dump") => match args.next() { + None | Some(&[]) => print_uart(&mut cx, "Missing argument\r\n"), + Some(b"temps") => cx.shared.storage.lock(|storage| { + for (secs, temp) in storage.oldest() { + cx.shared.usart.lock(|tx| { + print_uint(tx, secs); + print_uart_locked(tx, " "); + print_temp(tx, temp); + print_uart_locked(tx, "\r\n"); + }); + } + }), + Some(b) => unknown_argument(&mut cx, b), + }, Some(b"reset") => { print_uart(&mut cx, "Resetting...\r\n"); cortex_m::peripheral::SCB::sys_reset(); @@ -120,22 +150,6 @@ fn get_line(buffer: &mut Deque) -> Option> Some(line) } -fn print_uart(cx: &mut Context, str: &str) { - cx.shared.usart.lock(|tx| { - if tx.write_str(str).is_err() { - defmt::panic!("Failed to write to UART"); - } - }); -} - -fn unknown_argument(cx: &mut Context, arg: &[u8]) { - print_uart(cx, "Unknown argument: '"); - // SAFETY: b may not be valid UTF-8, but we don't care cause we're just printing it - // Also, including UTF8 checks would add a lot to the binary size - print_uart(cx, unsafe { core::str::from_utf8_unchecked(arg) }); - print_uart(cx, "'\r\n"); -} - #[inline] pub const fn is_newline(b: u8) -> bool { b == b'\n' || b == b'\r' @@ -146,17 +160,75 @@ pub const fn is_whitespace(b: u8) -> bool { b == b' ' || b == b'\n' || b == b'\r' || b == b'\t' } -const HELP_STR: &str = "Commands:\r - help\r - devices\r - resolution <9|10|11|12>?\r - pid\r - pid \r - temp\r - cooler ?\r - watch temp\r - dump temps\r - dump events\r - erase\r - reset\r -"; +fn print_uart(cx: &mut Context, str: &str) { + cx.shared.usart.lock(|tx| print_uart_locked(tx, str)); +} + +fn print_uart_locked(tx: &mut W, str: &str) { + if tx.write_str(str).is_err() { + panic!("Failed to write to UART"); + } +} + +fn unknown_argument(cx: &mut Context, arg: &[u8]) { + cx.shared.usart.lock(|tx| { + print_uart_locked(tx, "Unknown argument: '"); + // SAFETY: b may not be valid UTF-8, but we don't care cause we're just printing it + // Also, including UTF8 checks would add a lot to the binary size + print_uart_locked(tx, unsafe { core::str::from_utf8_unchecked(arg) }); + print_uart_locked(tx, "'\r\n"); + }); +} + +fn print_temp(tx: &mut W, temp: Temperature) { + const FRAC_TOTAL: u32 = 10u32.pow(Temperature::FRAC_NBITS); + + let sign = temp.is_negative(); + + let int_part = temp.to_bits().unsigned_abs() >> Temperature::FRAC_NBITS; + let frac_part = temp.frac().to_bits().unsigned_abs(); + + let mut total = 0; + for i in 0..Temperature::FRAC_NBITS { + let bit = (frac_part >> i) & 1; + let value = FRAC_TOTAL / (1 << (Temperature::FRAC_NBITS - i)); + total += bit * value; + } + + trace!( + "int_part: {=u32}, total: {=u32}, sign: {=bool}", + int_part, + total, + sign + ); + + if sign { + print_uart_locked(tx, "-"); + } + print_uint(tx, int_part); + print_uart_locked(tx, "."); + print_uint(tx, total); +} + +fn print_uint(tx: &mut W, mut num: u32) { + const BUF_SIZE: usize = 10; + + let mut buf = [0u8; BUF_SIZE]; + let mut idx = 0; + + loop { + let digit: u8 = (num % 10).as_(); + num /= 10; + + buf[BUF_SIZE - idx - 1] = b'0' + digit; + idx += 1; + + if num == 0 { + break; + } + } + + let buf = &buf[BUF_SIZE - idx..]; + // SAFETY: buf is guaranteed to be valid ASCII + print_uart_locked(tx, unsafe { core::str::from_utf8_unchecked(buf) }); +}