blob: 1f1dcb12f00e2059e5cf20873870e495be3efd50 [file] [log] [blame]
use crate::callback::Identity1Consumer;
use crate::futures;
use crate::result::TockError;
use crate::result::TockResult;
use crate::syscalls;
use core::cell::Cell;
use core::fmt;
use core::fmt::Display;
use core::marker::PhantomData;
use core::mem;
const DRIVER_NUMBER: usize = 0x60000;
mod command_nr {
pub const IS_DRIVER_AVAILABLE: usize = 0;
pub const START_MEASUREMENT: usize = 1;
}
mod subscribe_nr {
pub const SUBSCRIBE_CALLBACK: usize = 0;
}
#[non_exhaustive]
pub struct TemperatureDriverFactory;
impl TemperatureDriverFactory {
pub fn init_driver(&mut self) -> TockResult<TemperatureDriver> {
syscalls::command(DRIVER_NUMBER, command_nr::IS_DRIVER_AVAILABLE, 0, 0)?;
let driver = TemperatureDriver {
lifetime: PhantomData,
};
Ok(driver)
}
}
pub struct TemperatureDriver<'a> {
lifetime: PhantomData<&'a ()>,
}
impl<'a> TemperatureDriver<'a> {
pub async fn measure_temperature(&mut self) -> Result<Temperature, TockError> {
let temperature = Cell::new(None);
let mut callback = |centi_celsius| temperature.set(Some(centi_celsius as isize));
let subscription = syscalls::subscribe::<Identity1Consumer, _>(
DRIVER_NUMBER,
subscribe_nr::SUBSCRIBE_CALLBACK,
&mut callback,
)?;
syscalls::command(DRIVER_NUMBER, command_nr::START_MEASUREMENT, 0, 0)?;
let result = Temperature {
centi_celsius: futures::wait_for_value(|| temperature.get()).await,
};
mem::drop(subscription);
Ok(result)
}
}
#[derive(Copy, Clone)]
pub struct Temperature {
centi_celsius: isize,
}
impl Temperature {
pub fn in_celsius(self) -> isize {
self.centi_celsius / 100
}
pub fn in_centi_celsius(self) -> isize {
self.centi_celsius
}
}
impl Display for Temperature {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"{}.{:02}°C",
self.centi_celsius / 100,
self.centi_celsius.abs() % 100
)
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn render_temperature() {
assert_eq!(render_temperature_for(0), "0.00°C");
assert_eq!(render_temperature_for(5), "0.05°C");
assert_eq!(render_temperature_for(105), "1.05°C");
assert_eq!(render_temperature_for(125), "1.25°C");
assert_eq!(render_temperature_for(1025), "10.25°C");
assert_eq!(render_temperature_for(-1025), "-10.25°C");
}
fn render_temperature_for(centi_celsius: isize) -> String {
Temperature { centi_celsius }.to_string()
}
}