Don't crash on every error

This commit is contained in:
Frederik Menke 2024-08-03 22:09:43 +02:00
parent 4aa87dedc9
commit a6927ac39e
3 changed files with 92 additions and 46 deletions

6
Cargo.lock generated
View file

@ -742,13 +742,13 @@ dependencies = [
[[package]] [[package]]
name = "embedded-sdmmc" name = "embedded-sdmmc"
version = "0.7.0" version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "da528dbf3f1c1f0b321552bc334d04799bb17c1936de55bccfb643a4f39300d8" checksum = "150f320125310e179b9e73b081173b349e63c5c7d4ca44db4e5b9121b10387ec"
dependencies = [ dependencies = [
"byteorder", "byteorder",
"embedded-hal 1.0.0", "embedded-hal 1.0.0",
"heapless 0.7.17", "heapless 0.8.0",
"log", "log",
] ]

View file

@ -49,7 +49,7 @@ log = "0.4"
pio-proc = "0.2" pio-proc = "0.2"
pio = "0.2.1" pio = "0.2.1"
rand = { version = "0.8.5", default-features = false } rand = { version = "0.8.5", default-features = false }
embedded-sdmmc = "0.7.0" embedded-sdmmc = "0.8.0"
# Dependencies of embedded-sdmmc that I need to use directly # Dependencies of embedded-sdmmc that I need to use directly
byteorder = {version = "1", default-features = false} byteorder = {version = "1", default-features = false}

View file

@ -8,6 +8,8 @@
mod co2; mod co2;
use core::fmt::Debug;
use byteorder::ByteOrder; use byteorder::ByteOrder;
use core2::io::{Cursor, Write}; use core2::io::{Cursor, Write};
use defmt::*; use defmt::*;
@ -20,8 +22,8 @@ use embassy_rp::{gpio, spi};
use embassy_sync::blocking_mutex::raw::ThreadModeRawMutex; use embassy_sync::blocking_mutex::raw::ThreadModeRawMutex;
use embassy_sync::channel::Channel; use embassy_sync::channel::Channel;
use embedded_hal_bus::spi::ExclusiveDevice; use embedded_hal_bus::spi::ExclusiveDevice;
use embedded_sdmmc::sdcard::{DummyCsPin, SdCard}; use embedded_sdmmc::sdcard::SdCard;
use embedded_sdmmc::{Block, BlockDevice, BlockIdx, VolumeIdx}; use embedded_sdmmc::{Block, BlockDevice, BlockIdx, File, VolumeIdx};
use gpio::{Level, Output}; use gpio::{Level, Output};
use {defmt_rtt as _, panic_probe as _}; use {defmt_rtt as _, panic_probe as _};
@ -70,43 +72,77 @@ async fn main(spawner: Spawner) {
// Wait for sensor to boot // Wait for sensor to boot
Timer::after(Duration::from_secs(1)).await; Timer::after(Duration::from_secs(1)).await;
let status = co2::get_status(&mut i2c).await.unwrap(); loop {
let init_sensor = async {
let status = co2::get_status(&mut i2c).await?;
info!("CO2 sesor reported status on boot: {}", status); info!("CO2 sesor reported status on boot: {}", status);
// Byte 7 is FW_MODE which indicates if the app is already running.
if status & 128u8 == 0 {
info!("App is not running yet. Booting sensor...");
// App is not running
co2::start_app(&mut i2c).await.unwrap();
// After APP_START, we have to wait at least 1 ms (according to datasheet)
Timer::after(Duration::from_millis(2)).await;
// Byte 7 is FW_MODE which indicates if the app is already running. if co2::get_status(&mut i2c).await.unwrap() & 128u8 == 0 {
if status & 128u8 == 0 { error!("App still not running after boot! Aborting initialization...");
info!("App is not running yet. Booting sensor..."); // FIXME: Can't be bothered to come up with a different error type
// App is not running return Err(embassy_rp::i2c::Error::Abort(i2c::AbortReason::Other(1337)));
co2::start_app(&mut i2c).await.unwrap(); }
// After APP_START, we have to wait at least 1 ms (according to datasheet) } else {
Timer::after(Duration::from_millis(2)).await; info!("App is already running. Skipping boot...");
}
// 16 is measurement mode 1 => do 1 measurement per second
co2::set_measurement_mode(&mut i2c, 16).await?;
co2::set_environment_values(&mut i2c, 25000, 660).await
};
if co2::get_status(&mut i2c).await.unwrap() & 128u8 == 0 { if let Err(e) = init_sensor.await {
error!("App still not running after boot! Terminating..."); error!(
return; "Failed to init CO2 sensor: {:?}. Retrying...",
defmt::Debug2Format(&e)
);
continue;
} else {
break;
} }
} else {
info!("App is already running. Skipping boot...");
} }
// 16 is measurement mode 1 => 1 measurement per second
co2::set_measurement_mode(&mut i2c, 16).await.unwrap();
co2::set_environment_values(&mut i2c, 25000, 660)
.await
.unwrap();
loop { loop {
let status = co2::get_status(&mut i2c).await.unwrap(); let read_value_if_available = async {
let measured_value = co2::get_measurement(&mut i2c).await.unwrap(); let status = co2::get_status(&mut i2c).await?;
info!( // Bit 3 is `DATA_READY`
"Reported status: {}\tMeasured value: {}", if status & 0b00001000u8 != 0 {
status, measured_value let measured_value = co2::get_measurement(&mut i2c).await?;
); return Ok::<Option<(u8, u16)>, embassy_rp::i2c::Error>(Some((
status,
measured_value,
)));
}
Ok(None)
};
MEASUREMENT_VALUES.send(measured_value).await; match read_value_if_available.await {
Ok(Some((status, measured_value))) => {
Timer::after(Duration::from_secs(2)).await; info!(
"Reported status: {}\tMeasured value: {}",
status, measured_value
);
MEASUREMENT_VALUES.send(measured_value).await;
}
Ok(None) => {
info!("No value available. Waiting for new value...")
}
Err(e) => {
error!(
"Failed to read value from CO2 sensor: {:?}. Retrying...",
defmt::Debug2Format(&e)
);
}
}
// Wait a little shorter than the measurement interval to catch all values
Timer::after(Duration::from_millis(900)).await;
} }
} }
@ -116,12 +152,10 @@ async fn write_to_sd(spi1: SPI1, pin10: PIN_10, pin11: PIN_11, pin12: PIN_12, pi
let mut config = spi::Config::default(); let mut config = spi::Config::default();
config.frequency = 400_000; config.frequency = 400_000;
let spi = Spi::new_blocking(spi1, pin10, pin11, pin12, config); let spi = Spi::new_blocking(spi1, pin10, pin11, pin12, config);
// Use a dummy cs pin here, for embedded-hal SpiDevice compatibility reasons
let spi_dev = ExclusiveDevice::new_no_delay(spi, DummyCsPin);
// Real cs pin
let cs = Output::new(pin16, Level::High); let cs = Output::new(pin16, Level::High);
let spi_dev = ExclusiveDevice::new_no_delay(spi, cs);
let sdcard = SdCard::new(spi_dev, cs, embassy_time::Delay); let sdcard = SdCard::new(spi_dev, embassy_time::Delay);
info!("Card size is {} bytes", sdcard.num_bytes().unwrap()); info!("Card size is {} bytes", sdcard.num_bytes().unwrap());
@ -171,14 +205,17 @@ async fn write_to_sd(spi1: SPI1, pin10: PIN_10, pin11: PIN_11, pin12: PIN_12, pi
info!("Creating new text file: {}", file_name); info!("Creating new text file: {}", file_name);
let mut file = root_dir
.open_file_in_dir(file_name, embedded_sdmmc::Mode::ReadWriteCreateOrAppend)
.unwrap();
loop { loop {
let new_value = MEASUREMENT_VALUES.receive().await; let new_value = MEASUREMENT_VALUES.receive().await;
let mut file = root_dir info!(
.open_file_in_dir(file_name, embedded_sdmmc::Mode::ReadWriteCreateOrAppend) "Writing measurement value {} to file {}.TXT",
.unwrap(); new_value,
file_count + 1
info!("Writing measurement value {} to file", new_value); );
// Space for five characters to fit numbers up to 65535 + '\n' // Space for five characters to fit numbers up to 65535 + '\n'
let mut to_write = [b' '; 6]; let mut to_write = [b' '; 6];
@ -186,8 +223,17 @@ async fn write_to_sd(spi1: SPI1, pin10: PIN_10, pin11: PIN_11, pin12: PIN_12, pi
core::write!(&mut cursor, "{}", new_value) core::write!(&mut cursor, "{}", new_value)
.expect("We have more than enough bytes to fit an u16"); .expect("We have more than enough bytes to fit an u16");
to_write[5] = b'\n'; to_write[5] = b'\n';
file.write(&to_write).unwrap();
drop(file); let mut write_flush = || {
file.write(&to_write)?;
file.flush()
};
if let Err(e) = write_flush() {
error!(
"Failed to write measuement: {:?}.\nIgnoring missing value...",
defmt::Debug2Format(&e)
);
}
} }
} }