Hi there! I've got this monster of a function I'd like to make more readable:
fn read_bme280(
tx: &Sender<String>,
// previous: &Option<Measurements<I2cError>>,
expected_temperature_step: f32,
expected_humidity_step: f32,
expected_pressure_step: f32,
) -> Result<Measurements<I2cError>, Option<(Measurements<I2cError>, f32, f32, f32)>> {
trace!("read_bme280 start");
match APP_STATE.bme280.lock() {
Ok(mut bme280_lock) => match bme280_lock.get_mut() {
Some(bme280) => match bme280.measure(&mut delay::FreeRtos) {
Ok(measurements) => {
info!("{:?}", measurements);
match APP_STATE.bme280_last.read().as_ref() {
Ok(last_lock) => {
match last_lock.as_ref() {
Some(last) => {
debug!("comparing to last measurements: {:?}", last);
let suspect_temperature =
(measurements.temperature - last.temperature).abs() > expected_temperature_step;
let suspect_humdity =
(measurements.humidity - last.humidity).abs() > expected_humidity_step;
let suspect_pressure =
(measurements.pressure - last.pressure).abs() > expected_pressure_step;
if suspect_temperature || suspect_humdity || suspect_pressure {
warn!("rejected: {:?} (reasons: temperature={suspect_temperature}, humidity={suspect_humdity}, pressure={suspect_pressure})", measurements);
let next_temperature_step = expected_temperature_step
+ (expected_temperature_step
* 0.1
* suspect_temperature as u8 as f32);
let next_humidity_step = expected_humidity_step
+ (expected_humidity_step * 0.1 * suspect_humdity as u8 as f32);
let next_pressure_step = expected_pressure_step
+ (expected_pressure_step * 0.1 * suspect_pressure as u8 as f32);
info!("temperature step: expected={expected_temperature_step}, observed={}, next={}", (measurements.temperature - last.temperature).abs(), next_temperature_step);
info!(
"humidity step expected={expected_humidity_step}, observed={}, next={}",
(measurements.humidity - last.humidity).abs(),
next_humidity_step
);
info!(
"pressure step expected={expected_pressure_step}, observed={}, next={}",
(measurements.pressure - last.pressure).abs(),
next_pressure_step
);
return Err(Some((
measurements,
next_temperature_step,
next_humidity_step,
next_pressure_step,
)));
}
debug!("no reason to reject, close enough to previous");
},
None => warn!("can't validate measurements, no previous measurements available for comparison!"),
}
},
Err(error) => {
error!("last measurements store poisoned! {error}");
return Err(None);
},
};
send_measurements(&measurements, tx);
debug!("measurements have been sent!");
Ok(measurements)
}
Err(error) => {
error!("reinit bme280 becaue of read failure: {:?}", error);
bme280
.init_with_config(&mut delay::FreeRtos, BME280_CONFIG.clone())
.ok();
Err(None)
}
},
None => {
error!("bme280 has not been initialized yet!");
Err(None)
}
},
Err(error) => {
error!("couldn't aquire lock on bme280: {error}");
Err(None)
}
}
}
This is my draft so far, I've not implemented the verification process the above function have, I think I'll put that in a seperate function that uses this one instead:
fn read_bme280_try() -> Result<Measurements<I2cError>, String> {
let mut bme280_lock = APP_STATE
.bme280
.lock()
.map_err(|error| format!("couldn't aquire lock on bme280: {error}"))?;
let bme280 = bme280_lock
.get_mut()
.ok_or_else(|| "bme280 sensor is None")?;
bme280.measure(&mut delay::FreeRtos).map_err(|error|
bme280
.init_with_config(&mut delay::FreeRtos, BME280_CONFIG.clone())
.map_err(|init_error| {
format!(
"bme280.measure failed: {:?}, reinit failed too: {:?}",
error, init_error
)
})
.err()
.or(Some(format!(
"bme280.measure failed: {:?}, reinit succeeded.",
error
)))
.unwrap()
)
}
What I'm wondering now: Is there a way to unpack the Option with an .or(String)
instead of the ugly .or(Some(String)).unwrap()
that my new function has at the end?