Skip to content

Commit

Permalink
Merge branch 'master' into air_quality_api
Browse files Browse the repository at this point in the history
  • Loading branch information
RaresCon committed May 18, 2023
2 parents 35cd6b7 + 617b21a commit 04f500a
Show file tree
Hide file tree
Showing 33 changed files with 2,245 additions and 0 deletions.
9 changes: 9 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,17 +10,22 @@ repository = "https://github.com/tock/libtock-rs"
version = "0.1.0"

[dependencies]
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_buttons = { path = "apis/buttons" }
libtock_buzzer = {path = "apis/buzzer"}
libtock_console = { path = "apis/console" }
libtock_debug_panic = { path = "panic_handlers/debug_panic" }
libtock_gpio = { path = "apis/gpio" }
libtock_leds = { path = "apis/leds" }
libtock_low_level_debug = { path = "apis/low_level_debug" }
libtock_ninedof = { path = "apis/ninedof" }
libtock_platform = { path = "platform" }
libtock_proximity = { path = "apis/proximity" }
libtock_runtime = { path = "runtime" }
libtock_sound_pressure = {path = "apis/sound_pressure"}
libtock_temperature = { path = "apis/temperature" }

[profile.dev]
Expand All @@ -36,15 +41,19 @@ debug = true
[workspace]
exclude = ["tock"]
members = [
"apis/adc",
"apis/air_quality",
"apis/alarm",
"apis/gpio",
"apis/buttons",
"apis/buzzer",
"apis/console",
"apis/leds",
"apis/low_level_debug",
"apis/ninedof",
"apis/proximity",
"apis/temperature",
"apis/ambient_light",
"panic_handlers/debug_panic",
"panic_handlers/small_panic",
"platform",
Expand Down
14 changes: 14 additions & 0 deletions apis/adc/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
[package]
name = "libtock_adc"
version = "0.1.0"
authors = ["Tock Project Developers <tock-dev@googlegroups.com>"]
license = "MIT/Apache-2.0"
edition = "2021"
repository = "https://github.com/tock/libtock-rs"
description = "libtock adc driver"

[dependencies]
libtock_platform = { path = "../../platform" }

[dev-dependencies]
libtock_unittest = { path = "../../unittest" }
93 changes: 93 additions & 0 deletions apis/adc/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
#![no_std]

use core::cell::Cell;
use libtock_platform::{
share, subscribe::OneId, DefaultConfig, ErrorCode, Subscribe, Syscalls, Upcall,
};

pub struct Adc<S: Syscalls>(S);

impl<S: Syscalls> Adc<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 sample reading
pub fn read_single_sample() -> Result<(), ErrorCode> {
S::command(DRIVER_NUM, SINGLE_SAMPLE, 0, 0).to_result()
}

// Register a listener to be called when the ADC conversion is finished
pub fn register_listener<'share, F: Fn(u16)>(
listener: &'share ADCListener<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)
}

/// Initiates a synchronous ADC conversion
/// Returns the converted ADC value or an error
pub fn read_single_sample_sync() -> Result<u16, ErrorCode> {
let sample: Cell<Option<u16>> = Cell::new(None);
let listener = ADCListener(|adc_val| {
sample.set(Some(adc_val));
});
share::scope(|subscribe| {
Self::register_listener(&listener, subscribe)?;
Self::read_single_sample()?;
while sample.get() == None {
S::yield_wait();
}

match sample.get() {
None => Err(ErrorCode::Busy),
Some(adc_val) => Ok(adc_val),
}
})
}

/// Returns the number of ADC resolution bits
pub fn get_resolution_bits() -> Result<u32, ErrorCode> {
S::command(DRIVER_NUM, GET_RES_BITS, 0, 0).to_result()
}

/// Returns the reference voltage in millivolts (mV)
pub fn get_reference_voltage_mv() -> Result<u32, ErrorCode> {
S::command(DRIVER_NUM, GET_VOLTAGE_REF, 0, 0).to_result()
}
}

pub struct ADCListener<F: Fn(u16)>(pub F);

impl<F: Fn(u16)> Upcall<OneId<DRIVER_NUM, 0>> for ADCListener<F> {
fn upcall(&self, adc_val: u32, _arg1: u32, _arg2: u32) {
self.0(adc_val as u16)
}
}

#[cfg(test)]
mod tests;

// -----------------------------------------------------------------------------
// Driver number and command IDs
// -----------------------------------------------------------------------------

const DRIVER_NUM: u32 = 0x5;

// Command IDs

const EXISTS: u32 = 0;
const SINGLE_SAMPLE: u32 = 1;
// const REPEAT_SINGLE_SAMPLE: u32 = 2;
// const MULTIPLE_SAMPLE: u32 = 3;
// const CONTINUOUS_BUFF_SAMPLE: u32 = 4;
// const STOP_SAMPLE: u32 = 5;
const GET_RES_BITS: u32 = 101;
const GET_VOLTAGE_REF: u32 = 102;
71 changes: 71 additions & 0 deletions apis/adc/src/tests.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
use core::cell::Cell;
use libtock_platform::{share, ErrorCode, Syscalls, YieldNoWaitReturn};
use libtock_unittest::fake;

type Adc = super::Adc<fake::Syscalls>;

#[test]
fn no_driver() {
let _kernel = fake::Kernel::new();
assert_eq!(Adc::exists(), Err(ErrorCode::NoDevice));
}

#[test]
fn driver_check() {
let kernel = fake::Kernel::new();
let driver = fake::Adc::new();
kernel.add_driver(&driver);

assert_eq!(Adc::exists(), Ok(()));
}

#[test]
fn read_single_sample() {
let kernel = fake::Kernel::new();
let driver = fake::Adc::new();
kernel.add_driver(&driver);

assert_eq!(Adc::read_single_sample(), Ok(()));
assert!(driver.is_busy());

assert_eq!(Adc::read_single_sample(), Err(ErrorCode::Busy));
assert_eq!(Adc::read_single_sample_sync(), Err(ErrorCode::Busy));
}

#[test]
fn register_unregister_listener() {
let kernel = fake::Kernel::new();
let driver = fake::Adc::new();
kernel.add_driver(&driver);

let sample: Cell<Option<u16>> = Cell::new(None);
let listener = crate::ADCListener(|adc_val| {
sample.set(Some(adc_val));
});
share::scope(|subscribe| {
assert_eq!(Adc::read_single_sample(), Ok(()));
driver.set_value(100);
assert_eq!(fake::Syscalls::yield_no_wait(), YieldNoWaitReturn::NoUpcall);

assert_eq!(Adc::register_listener(&listener, subscribe), Ok(()));
assert_eq!(Adc::read_single_sample(), Ok(()));
driver.set_value(100);
assert_eq!(fake::Syscalls::yield_no_wait(), YieldNoWaitReturn::Upcall);
assert_eq!(sample.get(), Some(100));

Adc::unregister_listener();
assert_eq!(Adc::read_single_sample(), Ok(()));
driver.set_value(100);
assert_eq!(fake::Syscalls::yield_no_wait(), YieldNoWaitReturn::NoUpcall);
});
}

#[test]
fn read_single_sample_sync() {
let kernel = fake::Kernel::new();
let driver = fake::Adc::new();
kernel.add_driver(&driver);

driver.set_value_sync(1000);
assert_eq!(Adc::read_single_sample_sync(), Ok(1000));
}
14 changes: 14 additions & 0 deletions apis/ambient_light/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
[package]
name = "libtock_ambient_light"
version = "0.1.0"
authors = ["Tock Project Developers <tock-dev@googlegroups.com>"]
license = "MIT/Apache-2.0"
edition = "2021"
repository = "https://github.com/tock/libtock-rs"
description = "libtock ambient light driver"

[dependencies]
libtock_platform = { path = "../../platform" }

[dev-dependencies]
libtock_unittest = { path = "../../unittest" }
87 changes: 87 additions & 0 deletions apis/ambient_light/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
#![no_std]

use core::cell::Cell;
use libtock_platform::{
share, subscribe::OneId, DefaultConfig, ErrorCode, Subscribe, Syscalls, Upcall,
};

pub struct AmbientLight<S: Syscalls>(S);

impl<S: Syscalls> AmbientLight<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 light intensity reading.
pub fn read_intensity() -> Result<(), ErrorCode> {
S::command(DRIVER_NUM, READ_INTENSITY, 0, 0).to_result()
}

/// Register an events listener
pub fn register_listener<'share, F: Fn(u32)>(
listener: &'share IntensityListener<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 light intensity measurement.
/// Returns Ok(intensity_value) if the operation was successful
/// intensity_value is returned in lux
pub fn read_intensity_sync() -> Result<u32, ErrorCode> {
let intensity_cell: Cell<Option<u32>> = Cell::new(None);
let listener = IntensityListener(|intensity_val| {
intensity_cell.set(Some(intensity_val));
});

share::scope(|subscribe| {
Self::register_listener(&listener, subscribe)?;
Self::read_intensity()?;
while intensity_cell.get() == None {
S::yield_wait();
}

match intensity_cell.get() {
None => Err(ErrorCode::Busy),
Some(intensity_val) => Ok(intensity_val),
}
})
}
}

/// A wrapper around a closure to be registered and called when
/// a luminance reading is done.
///
/// ```ignore
/// let listener = IntensityListener(|intensity_val| {
/// // make use of the intensity value
/// });
/// ```
pub struct IntensityListener<F: Fn(u32)>(pub F);

impl<F: Fn(u32)> Upcall<OneId<DRIVER_NUM, 0>> for IntensityListener<F> {
fn upcall(&self, intensity: u32, _arg1: u32, _arg2: u32) {
self.0(intensity)
}
}

#[cfg(test)]
mod tests;

// -----------------------------------------------------------------------------
// Driver number and command IDs
// -----------------------------------------------------------------------------

const DRIVER_NUM: u32 = 0x60002;

// Command IDs

const EXISTS: u32 = 0;
const READ_INTENSITY: u32 = 1;
Loading

0 comments on commit 04f500a

Please sign in to comment.