-
Notifications
You must be signed in to change notification settings - Fork 9
humidity #23
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
humidity #23
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,14 @@ | ||
| [package] | ||
| name = "libtock_humidity" | ||
| version = "0.1.0" | ||
| authors = ["Tock Project Developers <[email protected]>"] | ||
| license = "MIT/Apache-2.0" | ||
| edition = "2021" | ||
| repository = "https://www.github.com/tock/libtock-rs" | ||
| description = "libtock humidity driver" | ||
|
|
||
| [dependencies] | ||
| libtock_platform = { path = "../../platform" } | ||
|
|
||
| [dev-dependencies] | ||
| libtock_unittest = { path = "../../unittest" } |
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
| @@ -0,0 +1,83 @@ | ||||||
| #![no_std] | ||||||
|
|
||||||
| use core::cell::Cell; | ||||||
| use libtock_platform::{ | ||||||
| share, subscribe::OneId, DefaultConfig, ErrorCode, Subscribe, Syscalls, Upcall, | ||||||
| }; | ||||||
|
|
||||||
| pub struct Humidity<S: Syscalls>(S); | ||||||
|
|
||||||
| impl<S: Syscalls> Humidity<S> { | ||||||
| /// Returns Ok() if the driver was present.This does not necessarily mean | ||||||
| /// that the driver is working. | ||||||
| pub fn exists() -> Result<(), ErrorCode> { | ||||||
| S::command(DRIVER_NUM, EXISTS, 0, 0).to_result() | ||||||
| } | ||||||
|
|
||||||
| /// Initiate a humidity measurement. | ||||||
| /// | ||||||
| /// This function is used both for synchronous and asynchronous readings | ||||||
| pub fn humidity_read() -> Result<(), ErrorCode> { | ||||||
| S::command(DRIVER_NUM, READ_HUMIDITY, 0, 0).to_result() | ||||||
| } | ||||||
|
|
||||||
| /// Register an events listener | ||||||
| pub fn register_listener<'share, F: Fn(i32)>( | ||||||
| listener: &'share HumidityListener<F>, | ||||||
| subscribe: share::Handle<Subscribe<'share, S, DRIVER_NUM, 0>>, | ||||||
| ) -> Result<(), ErrorCode> { | ||||||
| S::subscribe::<_, _, DefaultConfig, DRIVER_NUM, 0>(subscribe, listener) | ||||||
| } | ||||||
|
|
||||||
| /// Unregister the events listener | ||||||
| pub fn unregister_listener() { | ||||||
| S::unsubscribe(DRIVER_NUM, 0) | ||||||
| } | ||||||
|
|
||||||
| /// Initiate a synchronous humidity measurement. | ||||||
| /// ## Hello | ||||||
| /// Returns Ok(humidity_value) if the operation was successful | ||||||
| /// humidity_value is returned in hundreds of centigrades | ||||||
| pub fn humidity_read_sync() -> Result<i32, ErrorCode> { | ||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Are there any negative values for the humidity? You are using |
||||||
| let humidity_cell: Cell<Option<i32>> = Cell::new(None); | ||||||
| let listener = HumidityListener(|hum_val| { | ||||||
| humidity_cell.set(Some(hum_val)); | ||||||
| }); | ||||||
| share::scope(|subscribe| { | ||||||
| if let Ok(()) = Self::register_listener(&listener, subscribe) { | ||||||
| if let Ok(()) = Self::humidity_read() { | ||||||
| while humidity_cell.get() == None { | ||||||
| S::yield_wait(); | ||||||
| } | ||||||
| } | ||||||
| } | ||||||
| }); | ||||||
|
|
||||||
| match humidity_cell.get() { | ||||||
| None => Err(ErrorCode::Busy), | ||||||
| Some(hum_val) => Ok(hum_val), | ||||||
| } | ||||||
| } | ||||||
| } | ||||||
|
|
||||||
| pub struct HumidityListener<F: Fn(i32)>(pub F); | ||||||
| impl<F: Fn(i32)> Upcall<OneId<DRIVER_NUM, 0>> for HumidityListener<F> { | ||||||
| fn upcall(&self, hum_val: u32, _arg1: u32, _arg2: u32) { | ||||||
| self.0(hum_val as i32) | ||||||
| } | ||||||
| } | ||||||
|
|
||||||
| #[cfg(test)] | ||||||
| mod tests; | ||||||
|
|
||||||
| // ----------------------------------------------------------------------------- | ||||||
| // Driver number and command IDs | ||||||
| // ----------------------------------------------------------------------------- | ||||||
|
|
||||||
| const DRIVER_NUM: u32 = 0x60001; | ||||||
|
|
||||||
| // Command IDs | ||||||
|
|
||||||
| const EXISTS: u32 = 0; | ||||||
| const READ_HUMIDITY: u32 = 1; | ||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,81 @@ | ||
| use core::cell::Cell; | ||
| use libtock_platform::{share, ErrorCode, Syscalls, YieldNoWaitReturn}; | ||
| use libtock_unittest::fake; | ||
|
|
||
| type Humidity = super::Humidity<fake::Syscalls>; | ||
|
|
||
| #[test] | ||
| fn no_driver() { | ||
| let _kernel = fake::Kernel::new(); | ||
| assert_eq!(Humidity::exists(), Err(ErrorCode::NoDevice)); | ||
| } | ||
|
|
||
| #[test] | ||
| fn driver_check() { | ||
| let kernel = fake::Kernel::new(); | ||
| let driver = fake::Humidity::new(); | ||
| kernel.add_driver(&driver); | ||
|
|
||
| assert_eq!(Humidity::exists(), Ok(())); | ||
| } | ||
|
|
||
| #[test] | ||
| fn humidity_read() { | ||
| let kernel = fake::Kernel::new(); | ||
| let driver = fake::Humidity::new(); | ||
| kernel.add_driver(&driver); | ||
|
|
||
| assert_eq!(Humidity::humidity_read(), Ok(())); | ||
| assert!(driver.is_busy()); | ||
|
|
||
| assert_eq!(Humidity::humidity_read(), Err(ErrorCode::Busy)); | ||
| assert_eq!(Humidity::humidity_read_sync(), Err(ErrorCode::Busy)); | ||
| } | ||
|
|
||
| #[test] | ||
| fn register_unregister_listener() { | ||
| let kernel = fake::Kernel::new(); | ||
| let driver = fake::Humidity::new(); | ||
| kernel.add_driver(&driver); | ||
|
|
||
| let humidity_cell: Cell<Option<i32>> = Cell::new(None); | ||
| let listener = crate::HumidityListener(|temp_val| { | ||
| humidity_cell.set(Some(temp_val)); | ||
| }); | ||
| share::scope(|subscribe| { | ||
| assert_eq!(Humidity::humidity_read(), Ok(())); | ||
| driver.set_value(100); | ||
| assert_eq!(fake::Syscalls::yield_no_wait(), YieldNoWaitReturn::NoUpcall); | ||
|
|
||
| assert_eq!(Humidity::register_listener(&listener, subscribe), Ok(())); | ||
| assert_eq!(Humidity::humidity_read(), Ok(())); | ||
| driver.set_value(100); | ||
| assert_eq!(fake::Syscalls::yield_no_wait(), YieldNoWaitReturn::Upcall); | ||
| assert_eq!(humidity_cell.get(), Some(100)); | ||
|
|
||
| Humidity::unregister_listener(); | ||
| assert_eq!(Humidity::humidity_read(), Ok(())); | ||
| driver.set_value(100); | ||
| assert_eq!(fake::Syscalls::yield_no_wait(), YieldNoWaitReturn::NoUpcall); | ||
| }); | ||
| } | ||
|
|
||
| #[test] | ||
| fn humidity_read_sync() { | ||
| let kernel = fake::Kernel::new(); | ||
| let driver = fake::Humidity::new(); | ||
| kernel.add_driver(&driver); | ||
|
|
||
| driver.set_value_sync(1000); | ||
| assert_eq!(Humidity::humidity_read_sync(), Ok(1000)); | ||
| } | ||
|
|
||
| #[test] | ||
| fn negative_value() { | ||
| let kernel = fake::Kernel::new(); | ||
| let driver = fake::Humidity::new(); | ||
| kernel.add_driver(&driver); | ||
|
|
||
| driver.set_value_sync(-1000); | ||
| assert_eq!(Humidity::humidity_read_sync(), Ok(-1000)); | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,41 @@ | ||
| //! A simple libtock-rs example. Checks for humidity driver | ||
| //! and samples the sensor every 2 seconds. | ||
| #![no_main] | ||
| #![no_std] | ||
|
|
||
| use core::fmt::Write; | ||
| use libtock::console::Console; | ||
|
|
||
| use libtock::alarm::{Alarm, Milliseconds}; | ||
| use libtock::runtime::{set_main, stack_size}; | ||
| use libtock::humidity::Humidity; | ||
|
|
||
| set_main! {main} | ||
| stack_size! {0x200} | ||
|
|
||
| fn main() { | ||
| match Humidity::exists() { | ||
| Ok(()) => writeln!(Console::writer(), "humidity driver available").unwrap(), | ||
| Err(_) => { | ||
| writeln!(Console::writer(), "humidity driver unavailable").unwrap(); | ||
| return; | ||
| } | ||
| } | ||
|
|
||
| loop { | ||
| match Humidity::humidity_read_sync() { | ||
| Ok(hum_val) => writeln!( | ||
| Console::writer(), | ||
| "Humidity: {}{}.{}%\n", | ||
| if hum_val > 0 { "" } else { "-" }, | ||
| i32::abs(hum_val) / 100, | ||
| i32::abs(hum_val) % 100 | ||
| ) | ||
| .unwrap(), | ||
| Err(_) => writeln!(Console::writer(), "error while reading humidity",).unwrap(), | ||
| } | ||
|
|
||
| Alarm::sleep_for(Milliseconds(2000)).unwrap(); | ||
| } | ||
|
Comment on lines
+26
to
+40
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Move this in the |
||
| } | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please revert this file. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -2,7 +2,7 @@ | |
|
|
||
| MEMORY { | ||
| FLASH (X) : ORIGIN = 0x00040000, LENGTH = 256K | ||
| RAM (W) : ORIGIN = 0x20004000, LENGTH = 112K | ||
| RAM (W) : ORIGIN = 0x20004800, LENGTH = 112K | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Revert this file |
||
| } | ||
|
|
||
| TBF_HEADER_SIZE = 0x60; | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -44,3 +44,9 @@ pub mod temperature { | |
| pub type Temperature = temperature::Temperature<super::runtime::TockSyscalls>; | ||
| pub use temperature::TemperatureListener; | ||
| } | ||
|
|
||
| pub mod humidity { | ||
| use libtock_humidity as humidity; | ||
| pub type Humidity = humidity::Humidity<super::runtime::TockSyscalls>; | ||
| pub use humidity::HumidityListener; | ||
| } | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Add a newline. |
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,84 @@ | ||
| //! Fake implementation of the Humidity API, documented here: | ||
| //! | ||
| //! Like the real API, `Humidity` controls a fake humidity sensor. It provides | ||
| //! a function `set_value` used to immediately call an upcall with a humidity value read by the sensor | ||
| //! and a function 'set_value_sync' used to call the upcall when the read command is received. | ||
| use crate::{DriverInfo, DriverShareRef}; | ||
| use libtock_platform::{CommandReturn, ErrorCode}; | ||
| use std::cell::Cell; | ||
|
|
||
| // The `upcall_on_command` field is set to Some(value) if an upcall(with value as its argument) should be called when read command is received, | ||
| // or None otherwise. It was needed for testing `read_sync` library function which simulates a synchronous temperature read, | ||
| // because it was impossible to schedule an upcall during the `synchronous` read in other ways. | ||
|
Comment on lines
+11
to
+13
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Move this comment next to the field using |
||
| pub struct Humidity { | ||
| busy: Cell<bool>, | ||
| upcall_on_command: Cell<Option<i32>>, | ||
| share_ref: DriverShareRef, | ||
| } | ||
|
|
||
| impl Humidity { | ||
| pub fn new() -> std::rc::Rc<Humidity> { | ||
| std::rc::Rc::new(Humidity { | ||
| busy: Cell::new(false), | ||
| upcall_on_command: Cell::new(None), | ||
| share_ref: Default::default(), | ||
| }) | ||
| } | ||
|
|
||
| pub fn is_busy(&self) -> bool { | ||
| self.busy.get() | ||
| } | ||
| pub fn set_value(&self, value: i32) { | ||
| if self.busy.get() { | ||
| self.share_ref | ||
| .schedule_upcall(0, (value as u32, 0, 0)) | ||
| .expect("Unable to schedule upcall"); | ||
| self.busy.set(false); | ||
| } | ||
| } | ||
| pub fn set_value_sync(&self, value: i32) { | ||
| self.upcall_on_command.set(Some(value)); | ||
| } | ||
| } | ||
|
|
||
| impl crate::fake::SyscallDriver for Humidity { | ||
| fn info(&self) -> DriverInfo { | ||
| DriverInfo::new(DRIVER_NUM).upcall_count(1) | ||
| } | ||
|
|
||
| fn register(&self, share_ref: DriverShareRef) { | ||
| self.share_ref.replace(share_ref); | ||
| } | ||
|
|
||
| fn command(&self, command_id: u32, _argument0: u32, _argument1: u32) -> CommandReturn { | ||
| match command_id { | ||
| EXISTS => crate::command_return::success(), | ||
|
|
||
| READ_HUM => { | ||
| if self.busy.get() { | ||
| return crate::command_return::failure(ErrorCode::Busy); | ||
| } | ||
| self.busy.set(true); | ||
| if let Some(val) = self.upcall_on_command.take() { | ||
| self.set_value(val); | ||
| } | ||
| crate::command_return::success() | ||
| } | ||
| _ => crate::command_return::failure(ErrorCode::NoSupport), | ||
| } | ||
| } | ||
| } | ||
|
|
||
| #[cfg(test)] | ||
| mod tests; | ||
| // ----------------------------------------------------------------------------- | ||
| // Driver number and command IDs | ||
| // ----------------------------------------------------------------------------- | ||
|
|
||
| const DRIVER_NUM: u32 = 0x60001; | ||
|
|
||
| // Command IDs | ||
|
|
||
| const EXISTS: u32 = 0; | ||
| const READ_HUM: u32 = 1; | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.