Skip to content

Commit

Permalink
Merge #462
Browse files Browse the repository at this point in the history
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
bors[bot] and alexandruCarp authored Apr 17, 2023
2 parents 4719e4e + 73efc7d commit 34127ed
Show file tree
Hide file tree
Showing 9 changed files with 457 additions and 1 deletion.
2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ libtock_gpio = { path = "apis/gpio" }
libtock_leds = { path = "apis/leds" }
libtock_low_level_debug = { path = "apis/low_level_debug" }
libtock_platform = { path = "platform" }
libtock_proximity = { path = "apis/proximity" }
libtock_runtime = { path = "runtime" }
libtock_temperature = { path = "apis/temperature" }

Expand All @@ -40,6 +41,7 @@ members = [
"apis/console",
"apis/leds",
"apis/low_level_debug",
"apis/proximity",
"apis/temperature",
"panic_handlers/debug_panic",
"panic_handlers/small_panic",
Expand Down
15 changes: 15 additions & 0 deletions apis/proximity/Cargo.toml
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" }

107 changes: 107 additions & 0 deletions apis/proximity/src/lib.rs
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;
86 changes: 86 additions & 0 deletions apis/proximity/src/tests.rs
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)
);
}
31 changes: 31 additions & 0 deletions examples/proximity.rs
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();
}
}
5 changes: 4 additions & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,10 @@ pub mod low_level_debug {
pub type LowLevelDebug = lldb::LowLevelDebug<super::runtime::TockSyscalls>;
pub use lldb::AlertCode;
}

pub mod proximity {
use libtock_proximity as proximity;
pub type Proximity = proximity::Proximity<super::runtime::TockSyscalls>;
}
pub mod temperature {
use libtock_temperature as temperature;
pub type Temperature = temperature::Temperature<super::runtime::TockSyscalls>;
Expand Down
2 changes: 2 additions & 0 deletions unittest/src/fake/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ mod gpio;
mod kernel;
mod leds;
mod low_level_debug;
mod proximity;
mod syscall_driver;
mod syscalls;
mod temperature;
Expand All @@ -27,6 +28,7 @@ pub use gpio::{Gpio, GpioMode, InterruptEdge, PullMode};
pub use kernel::Kernel;
pub use leds::Leds;
pub use low_level_debug::{LowLevelDebug, Message};
pub use proximity::Proximity;
pub use syscall_driver::SyscallDriver;
pub use syscalls::Syscalls;
pub use temperature::Temperature;
Expand Down
Loading

0 comments on commit 34127ed

Please sign in to comment.