-
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.
Merge branch 'master' into air_quality_api
- Loading branch information
Showing
33 changed files
with
2,245 additions
and
0 deletions.
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,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" } |
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,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; |
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,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)); | ||
} |
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,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" } |
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,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; |
Oops, something went wrong.