| 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() |
| } |
| } |