Don't crash on every error
This commit is contained in:
parent
4aa87dedc9
commit
a6927ac39e
6
Cargo.lock
generated
6
Cargo.lock
generated
|
@ -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",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
|
@ -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}
|
||||||
|
|
130
src/main.rs
130
src/main.rs
|
@ -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)
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue