diff --git a/Cargo.toml b/Cargo.toml index 584a5581..f9cecff3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,6 +20,7 @@ libtock_adc = { path = "apis/adc" } libtock_air_quality = { path = "apis/air_quality" } libtock_alarm = { path = "apis/alarm" } libtock_ambient_light = { path = "apis/ambient_light" } +libtock_analog_comparator = { path = "apis/analog_comparator" } libtock_buttons = { path = "apis/buttons" } libtock_buzzer = { path = "apis/buzzer" } libtock_console = { path = "apis/console" } diff --git a/apis/analog_comparator/Cargo.toml b/apis/analog_comparator/Cargo.toml new file mode 100644 index 00000000..7aed3e63 --- /dev/null +++ b/apis/analog_comparator/Cargo.toml @@ -0,0 +1,15 @@ +[package] +name = "libtock_analog_comparator" +version = "0.1.0" +authors = ["Tock Project Developers "] +license = "Apache-2.0 OR MIT" +edition = "2018" +repository = "https://www.github.com/tock/libtock-rs" +rust-version.workspace = true +description = "libtock analog comparator driver" + +[dependencies] +libtock_platform = { path = "../../platform" } + +[dev-dependencies] +libtock_unittest = { path = "../../unittest" } diff --git a/apis/analog_comparator/src/lib.rs b/apis/analog_comparator/src/lib.rs new file mode 100644 index 00000000..4e3278dd --- /dev/null +++ b/apis/analog_comparator/src/lib.rs @@ -0,0 +1,50 @@ +#![no_std] + +use libtock_platform::{ + share::Handle, subscribe::OneId, DefaultConfig, ErrorCode, Subscribe, Syscalls, Upcall, +}; + +pub struct AnalogComparator(S); + +impl AnalogComparator { + pub fn exists() -> Result<(), ErrorCode> { + S::command(DRIVER_NUM, EXISTS, 0, 0).to_result() + } + + pub fn analog_comparator_comparison(channel: u32) -> Result<(), ErrorCode> { + S::command(DRIVER_NUM, 1, channel, 0).to_result() + } + + pub fn analog_comparator_start_comparing(channel: u32) -> Result<(), ErrorCode> { + S::command(DRIVER_NUM, 2, channel, 0).to_result() + } + + pub fn analog_comparator_stop_comparing(channel: u32) -> Result<(), ErrorCode> { + S::command(DRIVER_NUM, 3, channel, 0).to_result() + } + + pub fn analog_comparator_count() -> Result { + S::command(DRIVER_NUM, 4, 0, 0).to_result() + } + + pub fn analog_comparator_interrupt_subscribe<'share, F: Fn(u32)>( + listener: &'share AnalogComparatorListener, + subscribe: Handle>, + ) -> Result<(), ErrorCode> { + S::subscribe::<_, _, DefaultConfig, DRIVER_NUM, 0>(subscribe, listener) + } +} + +pub struct AnalogComparatorListener(F); +impl Upcall> for AnalogComparatorListener { + fn upcall(&self, arg0: u32, _arg1: u32, _arg2: u32) { + (self.0)(arg0); + } +} +#[cfg(test)] +mod tests; +// ----------------------------------------------------------------------------- +// Driver number and command IDs +// ----------------------------------------------------------------------------- +const DRIVER_NUM: u32 = 0x7; +const EXISTS: u32 = 0; diff --git a/apis/analog_comparator/src/tests.rs b/apis/analog_comparator/src/tests.rs new file mode 100644 index 00000000..6b023bf1 --- /dev/null +++ b/apis/analog_comparator/src/tests.rs @@ -0,0 +1,39 @@ +use libtock_unittest::fake; + +type Ac = super::AnalogComparator; + +#[test] +fn exists() { + let kernel = fake::Kernel::new(); + let ac = fake::AnalogComparator::new(); + kernel.add_driver(&ac); + + assert_eq!(Ac::exists(), Ok(())); +} + +#[test] +fn analog_comparator_comparison() { + let kernel = fake::Kernel::new(); + let ac = fake::AnalogComparator::new(); + kernel.add_driver(&ac); + + assert_eq!(Ac::analog_comparator_comparison(1), Ok(())); +} + +#[test] +fn analog_comparator_start_comparing() { + let kernel = fake::Kernel::new(); + let ac = fake::AnalogComparator::new(); + kernel.add_driver(&ac); + + assert_eq!(Ac::analog_comparator_start_comparing(1), Ok(())); +} + +#[test] +fn analog_comparator_stop_comparing() { + let kernel = fake::Kernel::new(); + let ac = fake::AnalogComparator::new(); + kernel.add_driver(&ac); + + assert_eq!(Ac::analog_comparator_stop_comparing(1), Ok(())); +} diff --git a/src/lib.rs b/src/lib.rs index 90d0ff29..eaaa0263 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -28,6 +28,10 @@ pub mod ambient_light { pub type AmbientLight = ambient_light::AmbientLight; pub use ambient_light::IntensityListener; } +pub mod analog_comparator { + use libtock_analog_comparator as analog_comparator; + pub type AnalogComparator = analog_comparator::AnalogComparator; +} pub mod buttons { use libtock_buttons as buttons; pub type Buttons = buttons::Buttons; diff --git a/unittest/src/fake/analog_comparator/mod.rs b/unittest/src/fake/analog_comparator/mod.rs new file mode 100644 index 00000000..a54ae052 --- /dev/null +++ b/unittest/src/fake/analog_comparator/mod.rs @@ -0,0 +1,80 @@ +use crate::{DriverInfo, DriverShareRef}; +use libtock_platform::{CommandReturn, ErrorCode}; +use std::cell::Cell; + +pub struct AnalogComparator { + busy: Cell, + share_ref: DriverShareRef, +} + +impl AnalogComparator { + pub fn new() -> std::rc::Rc { + std::rc::Rc::new(AnalogComparator { + busy: Cell::new(false), + share_ref: Default::default(), + }) + } + + pub fn is_busy(&self) -> bool { + self.busy.get() + } + + pub fn set_value(&self, value: u32) { + if self.busy.get() { + self.share_ref + .schedule_upcall(0, (value, 0, 0)) + .expect("Unable to schedule upcall"); + self.busy.set(false); + } + } + + pub fn set_value_sync(&self, value: u32) { + self.set_value(value); + } +} + +impl crate::fake::SyscallDriver for AnalogComparator { + 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(), + + 1 => { + if self.busy.get() { + return crate::command_return::failure(ErrorCode::Busy); + } + self.busy.set(true); + crate::command_return::success() + } + 2 => { + if self.busy.get() { + return crate::command_return::failure(ErrorCode::Busy); + } + self.busy.set(true); + crate::command_return::success() + } + 3 => { + if self.busy.get() { + return crate::command_return::failure(ErrorCode::Busy); + } + self.busy.set(true); + crate::command_return::success() + } + 4 => crate::command_return::success(), + _ => crate::command_return::failure(ErrorCode::NoSupport), + } + } +} + +#[cfg(test)] +mod tests; + +const DRIVER_NUM: u32 = 0x7; +const EXISTS: u32 = 0; diff --git a/unittest/src/fake/analog_comparator/tests.rs b/unittest/src/fake/analog_comparator/tests.rs new file mode 100644 index 00000000..5332ada1 --- /dev/null +++ b/unittest/src/fake/analog_comparator/tests.rs @@ -0,0 +1,35 @@ +use crate::fake::{self, SyscallDriver}; +use fake::analog_comparator::*; +use libtock_platform::ErrorCode; + +#[test] +fn command() { + let analog_comparator = AnalogComparator::new(); + assert!(analog_comparator.command(EXISTS, 1, 2).is_success()); + + assert!(analog_comparator.command(1, 0, 0).is_success()); + + assert_eq!( + analog_comparator.command(1, 0, 0).get_failure(), + Some(ErrorCode::Busy) + ); + + analog_comparator.set_value(100); + assert!(analog_comparator.command(1, 0, 1).is_success()); +} + +#[test] +fn kernel_integration() { + use libtock_platform::Syscalls; + let kernel = fake::Kernel::new(); + let analog_comparator = AnalogComparator::new(); + kernel.add_driver(&analog_comparator); + assert!(fake::Syscalls::command(DRIVER_NUM, EXISTS, 1, 2).is_success()); + assert!(fake::Syscalls::command(DRIVER_NUM, 1, 0, 0).is_success()); + assert_eq!( + fake::Syscalls::command(DRIVER_NUM, 1, 0, 0).get_failure(), + Some(ErrorCode::Busy) + ); + analog_comparator.set_value(100); + assert!(fake::Syscalls::command(DRIVER_NUM, 1, 0, 1).is_success()); +} diff --git a/unittest/src/fake/mod.rs b/unittest/src/fake/mod.rs index ba042ab0..d681dad9 100644 --- a/unittest/src/fake/mod.rs +++ b/unittest/src/fake/mod.rs @@ -13,6 +13,7 @@ mod adc; mod air_quality; mod alarm; mod ambient_light; +mod analog_comparator; mod buttons; mod buzzer; mod console; @@ -32,6 +33,7 @@ pub use adc::Adc; pub use air_quality::AirQuality; pub use alarm::Alarm; pub use ambient_light::AmbientLight; +pub use analog_comparator::AnalogComparator; pub use buttons::Buttons; pub use buzzer::Buzzer; pub use console::Console;