-
Notifications
You must be signed in to change notification settings - Fork 109
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
462: Proximity API r=jrvanwhy a=alexandruCarp ### Pull Request Overview This pull request adds: - a Proximity API which provides a function that simulates a synchronous proximity reading, functions to only read a value between some thresholds (sync and async), and also functions to initiate a reading, register/ unregister a listener and check for driver existence. - an example app which samples the proximity sensor every 2 seconds and prints the measured value. - a `fake` proximity driver, for testing purposes. - unit tests for the fake driver and for the user space library ### Testing Strategy This pull request was tested with the unit tests. ### TODO or Help Wanted Feedback is much appreciated. ### Documentation Updated - [x] no updates are required. Co-authored-by: Alexandru Carp <alexandrucarp02@gmail.com>
- Loading branch information
Showing
9 changed files
with
457 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
[package] | ||
name = "libtock_proximity" | ||
version = "0.1.0" | ||
authors = ["Tock Project Developers <tock-dev@googlegroups.com>"] | ||
license = "MIT/Apache-2.0" | ||
edition = "2021" | ||
repository = "https://www.github.com/tock/libtock-rs" | ||
description = "libtock proximity driver" | ||
|
||
[dependencies] | ||
libtock_platform = { path = "../../platform" } | ||
|
||
[dev-dependencies] | ||
libtock_unittest = { path = "../../unittest" } | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,107 @@ | ||
#![no_std] | ||
|
||
use core::cell::Cell; | ||
|
||
use libtock_platform::{share, DefaultConfig, ErrorCode, Subscribe, Syscalls}; | ||
|
||
pub struct Proximity<S: Syscalls>(S); | ||
|
||
impl<S: Syscalls> Proximity<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() | ||
} | ||
|
||
/// Register an events listener | ||
pub fn register_listener<'share>( | ||
listener: &'share Cell<Option<(u32,)>>, | ||
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 proximity measurement | ||
pub fn read() -> Result<(), ErrorCode> { | ||
S::command(DRIVER_NUM, READ, 0, 0).to_result() | ||
} | ||
|
||
/// Initiate a synchronous proximity measurement. | ||
/// Returns Ok(proximity_value) if the operation was successful | ||
/// proximity_value is in [0, 255] range, | ||
/// where '255' indicates the closest measurable distance and '0' that no object is detected | ||
pub fn read_sync() -> Result<u8, ErrorCode> { | ||
let listener: Cell<Option<(u32,)>> = Cell::new(None); | ||
share::scope(|subscribe| { | ||
if let Ok(()) = Self::register_listener(&listener, subscribe) { | ||
if let Ok(()) = Self::read() { | ||
S::yield_wait(); | ||
} | ||
} | ||
}); | ||
|
||
match listener.get() { | ||
None => Err(ErrorCode::Busy), | ||
Some(proximity) => Ok(proximity.0 as u8), | ||
} | ||
} | ||
|
||
/// Initiate an on_interrupt proximity measurement | ||
/// The sensor reads values continuously and executes the callback only if | ||
/// proximity_value < lower or proximity_value > upper | ||
/// lower - lower interrupt threshold for sensor --> range is [0,255] | ||
/// upper - upper interrupt threshold for sensor --> range is [0,255] | ||
/// lower <= upper | ||
pub fn read_on_interrupt(lower: u8, upper: u8) -> Result<(), ErrorCode> { | ||
S::command(DRIVER_NUM, READ_ON_INT, lower as u32, upper as u32).to_result() | ||
} | ||
|
||
/// Initiate a synchronous on_interrupt proximity measurement. | ||
/// Returns Ok(proximity_value) if the operation was successful | ||
/// proximity_value is in [0, 255] range, | ||
/// where '255' indicates the closest measurable distance and '0' that no object is detected | ||
/// Returns only when proximity_value < lower or proximity_value > upper | ||
/// lower - lower interrupt threshold for sensor --> range is [0,255] | ||
/// upper - upper interrupt threshold for sensor --> range is [0,255] | ||
/// lower <= upper | ||
pub fn wait_for_value_between(lower: u8, upper: u8) -> Result<u8, ErrorCode> { | ||
if lower > upper { | ||
return Err(ErrorCode::Invalid); | ||
} | ||
let listener: Cell<Option<(u32,)>> = Cell::new(None); | ||
share::scope(|subscribe| { | ||
if let Ok(()) = Self::register_listener(&listener, subscribe) { | ||
if let Ok(()) = Self::read_on_interrupt(lower, upper) { | ||
while listener.get() == None { | ||
S::yield_wait(); | ||
} | ||
} | ||
} | ||
}); | ||
|
||
match listener.get() { | ||
None => Err(ErrorCode::Busy), | ||
Some(proximity) => Ok(proximity.0 as u8), | ||
} | ||
} | ||
} | ||
|
||
#[cfg(test)] | ||
mod tests; | ||
|
||
// ----------------------------------------------------------------------------- | ||
// Driver number and command IDs | ||
// ----------------------------------------------------------------------------- | ||
|
||
const DRIVER_NUM: u32 = 0x60005; | ||
|
||
// Command IDs | ||
|
||
const EXISTS: u32 = 0; | ||
const READ: u32 = 1; | ||
const READ_ON_INT: u32 = 2; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,86 @@ | ||
use core::cell::Cell; | ||
use libtock_platform::{share, ErrorCode, Syscalls, YieldNoWaitReturn}; | ||
use libtock_unittest::fake; | ||
|
||
type Proximity = super::Proximity<fake::Syscalls>; | ||
|
||
#[test] | ||
fn no_driver() { | ||
let _kernel = fake::Kernel::new(); | ||
assert_eq!(Proximity::exists(), Err(ErrorCode::NoDevice)); | ||
} | ||
|
||
#[test] | ||
fn driver_check() { | ||
let kernel = fake::Kernel::new(); | ||
let driver = fake::Proximity::new(); | ||
kernel.add_driver(&driver); | ||
|
||
assert_eq!(Proximity::exists(), Ok(())); | ||
} | ||
|
||
#[test] | ||
fn busy_driver() { | ||
let kernel = fake::Kernel::new(); | ||
let driver = fake::Proximity::new(); | ||
kernel.add_driver(&driver); | ||
|
||
assert_eq!(Proximity::read(), Ok(())); | ||
assert_eq!(Proximity::read(), Err(ErrorCode::Busy)); | ||
assert_eq!(Proximity::read_on_interrupt(0, 0), Err(ErrorCode::Busy)); | ||
|
||
driver.set_value(100); | ||
|
||
assert_eq!(Proximity::read_on_interrupt(0, 0), Ok(())); | ||
assert_eq!(Proximity::read(), Err(ErrorCode::Busy)); | ||
} | ||
|
||
#[test] | ||
fn async_readings() { | ||
let kernel = fake::Kernel::new(); | ||
let driver = fake::Proximity::new(); | ||
kernel.add_driver(&driver); | ||
|
||
let listener = Cell::<Option<(u32,)>>::new(None); | ||
|
||
share::scope(|subscribe| { | ||
assert_eq!(Proximity::read(), Ok(())); | ||
driver.set_value(100); | ||
assert_eq!(fake::Syscalls::yield_no_wait(), YieldNoWaitReturn::NoUpcall); | ||
|
||
assert_eq!(Proximity::register_listener(&listener, subscribe), Ok(())); | ||
assert_eq!(Proximity::read(), Ok(())); | ||
driver.set_value(100); | ||
assert_eq!(fake::Syscalls::yield_no_wait(), YieldNoWaitReturn::Upcall); | ||
assert_eq!(listener.get(), Some((100,))); | ||
|
||
assert_eq!(Proximity::read_on_interrupt(100, 200), Ok(())); | ||
driver.set_value(150); | ||
assert_eq!(fake::Syscalls::yield_no_wait(), YieldNoWaitReturn::NoUpcall); | ||
|
||
driver.set_value(99); | ||
assert_eq!(fake::Syscalls::yield_no_wait(), YieldNoWaitReturn::Upcall); | ||
assert_eq!(listener.get(), Some((99,))); | ||
}) | ||
} | ||
|
||
#[test] | ||
fn sync_readings() { | ||
let kernel = fake::Kernel::new(); | ||
let driver = fake::Proximity::new(); | ||
kernel.add_driver(&driver); | ||
|
||
driver.set_value_sync(100); | ||
assert_eq!(Proximity::read_sync(), Ok(100)); | ||
|
||
driver.set_value_sync(250); | ||
assert_eq!(Proximity::wait_for_value_between(100, 200), Ok(250)); | ||
} | ||
|
||
#[test] | ||
fn bad_arguments() { | ||
assert_eq!( | ||
Proximity::wait_for_value_between(200, 100), | ||
Err(ErrorCode::Invalid) | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
//! A simple libtock-rs example. Checks for proximity 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::proximity::Proximity; | ||
use libtock::runtime::{set_main, stack_size}; | ||
|
||
set_main! {main} | ||
stack_size! {0x200} | ||
|
||
fn main() { | ||
if Proximity::exists().is_err() { | ||
writeln!(Console::writer(), "proximity driver unavailable").unwrap(); | ||
return; | ||
} | ||
writeln!(Console::writer(), "proximity driver available").unwrap(); | ||
loop { | ||
match Proximity::read_sync() { | ||
Ok(prox_val) => writeln!(Console::writer(), "Proximity: {}\n", prox_val).unwrap(), | ||
Err(_) => writeln!(Console::writer(), "error while reading proximity",).unwrap(), | ||
} | ||
|
||
Alarm::sleep_for(Milliseconds(2000)).unwrap(); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.