From a6927ac39e631eb549e327f17a3662561f0f12b4 Mon Sep 17 00:00:00 2001 From: Frederik Menke Date: Sat, 3 Aug 2024 22:09:43 +0200 Subject: [PATCH] Don't crash on every error --- Cargo.lock | 6 +-- Cargo.toml | 2 +- src/main.rs | 130 +++++++++++++++++++++++++++++++++++----------------- 3 files changed, 92 insertions(+), 46 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 0c9f2c1..02341b1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -742,13 +742,13 @@ dependencies = [ [[package]] name = "embedded-sdmmc" -version = "0.7.0" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da528dbf3f1c1f0b321552bc334d04799bb17c1936de55bccfb643a4f39300d8" +checksum = "150f320125310e179b9e73b081173b349e63c5c7d4ca44db4e5b9121b10387ec" dependencies = [ "byteorder", "embedded-hal 1.0.0", - "heapless 0.7.17", + "heapless 0.8.0", "log", ] diff --git a/Cargo.toml b/Cargo.toml index 6158a6d..f8050a3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -49,7 +49,7 @@ log = "0.4" pio-proc = "0.2" pio = "0.2.1" 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 byteorder = {version = "1", default-features = false} diff --git a/src/main.rs b/src/main.rs index dbcee04..12d3a5d 100644 --- a/src/main.rs +++ b/src/main.rs @@ -8,6 +8,8 @@ mod co2; +use core::fmt::Debug; + use byteorder::ByteOrder; use core2::io::{Cursor, Write}; use defmt::*; @@ -20,8 +22,8 @@ use embassy_rp::{gpio, spi}; use embassy_sync::blocking_mutex::raw::ThreadModeRawMutex; use embassy_sync::channel::Channel; use embedded_hal_bus::spi::ExclusiveDevice; -use embedded_sdmmc::sdcard::{DummyCsPin, SdCard}; -use embedded_sdmmc::{Block, BlockDevice, BlockIdx, VolumeIdx}; +use embedded_sdmmc::sdcard::SdCard; +use embedded_sdmmc::{Block, BlockDevice, BlockIdx, File, VolumeIdx}; use gpio::{Level, Output}; use {defmt_rtt as _, panic_probe as _}; @@ -70,43 +72,77 @@ async fn main(spawner: Spawner) { // Wait for sensor to boot 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 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; + if co2::get_status(&mut i2c).await.unwrap() & 128u8 == 0 { + error!("App still not running after boot! Aborting initialization..."); + // FIXME: Can't be bothered to come up with a different error type + return Err(embassy_rp::i2c::Error::Abort(i2c::AbortReason::Other(1337))); + } + } else { + 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 { - error!("App still not running after boot! Terminating..."); - return; + if let Err(e) = init_sensor.await { + error!( + "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 { - let status = co2::get_status(&mut i2c).await.unwrap(); - let measured_value = co2::get_measurement(&mut i2c).await.unwrap(); - info!( - "Reported status: {}\tMeasured value: {}", - status, measured_value - ); + let read_value_if_available = async { + let status = co2::get_status(&mut i2c).await?; + // Bit 3 is `DATA_READY` + if status & 0b00001000u8 != 0 { + let measured_value = co2::get_measurement(&mut i2c).await?; + return Ok::, embassy_rp::i2c::Error>(Some(( + status, + measured_value, + ))); + } + Ok(None) + }; - MEASUREMENT_VALUES.send(measured_value).await; - - Timer::after(Duration::from_secs(2)).await; + match read_value_if_available.await { + Ok(Some((status, measured_value))) => { + 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(); config.frequency = 400_000; 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 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()); @@ -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); + let mut file = root_dir + .open_file_in_dir(file_name, embedded_sdmmc::Mode::ReadWriteCreateOrAppend) + .unwrap(); loop { let new_value = MEASUREMENT_VALUES.receive().await; - let mut file = root_dir - .open_file_in_dir(file_name, embedded_sdmmc::Mode::ReadWriteCreateOrAppend) - .unwrap(); - - info!("Writing measurement value {} to file", new_value); + info!( + "Writing measurement value {} to file {}.TXT", + new_value, + file_count + 1 + ); // Space for five characters to fit numbers up to 65535 + '\n' 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) .expect("We have more than enough bytes to fit an u16"); 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) + ); + } } }