Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ libtock_low_level_debug = { path = "apis/low_level_debug" }
libtock_platform = { path = "platform" }
libtock_runtime = { path = "runtime" }
libtock_temperature = { path = "apis/temperature" }
libtock_humidity = { path = "apis/humidity" }

[profile.dev]
panic = "abort"
Expand Down
14 changes: 14 additions & 0 deletions apis/humidity/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
[package]
name = "libtock_humidity"
version = "0.1.0"
authors = ["Tock Project Developers <[email protected]>"]
license = "MIT/Apache-2.0"
edition = "2021"
repository = "https://www.github.com/tock/libtock-rs"
description = "libtock humidity driver"

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

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

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

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

impl<S: Syscalls> Humidity<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 humidity measurement.
///
/// This function is used both for synchronous and asynchronous readings
pub fn humidity_read() -> Result<(), ErrorCode> {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
pub fn humidity_read() -> Result<(), ErrorCode> {
pub fn read() -> Result<(), ErrorCode> {

S::command(DRIVER_NUM, READ_HUMIDITY, 0, 0).to_result()
}

/// Register an events listener
pub fn register_listener<'share, F: Fn(i32)>(
listener: &'share HumidityListener<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 humidity measurement.
/// ## Hello
/// Returns Ok(humidity_value) if the operation was successful
/// humidity_value is returned in hundreds of centigrades
pub fn humidity_read_sync() -> Result<i32, ErrorCode> {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
pub fn humidity_read_sync() -> Result<i32, ErrorCode> {
pub fn read_sync() -> Result<i32, ErrorCode> {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are there any negative values for the humidity? You are using i32.

let humidity_cell: Cell<Option<i32>> = Cell::new(None);
let listener = HumidityListener(|hum_val| {
humidity_cell.set(Some(hum_val));
});
share::scope(|subscribe| {
if let Ok(()) = Self::register_listener(&listener, subscribe) {
if let Ok(()) = Self::humidity_read() {
while humidity_cell.get() == None {
S::yield_wait();
}
}
}
});

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

pub struct HumidityListener<F: Fn(i32)>(pub F);
impl<F: Fn(i32)> Upcall<OneId<DRIVER_NUM, 0>> for HumidityListener<F> {
fn upcall(&self, hum_val: u32, _arg1: u32, _arg2: u32) {
self.0(hum_val as i32)
}
}

#[cfg(test)]
mod tests;

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

const DRIVER_NUM: u32 = 0x60001;

// Command IDs

const EXISTS: u32 = 0;
const READ_HUMIDITY: u32 = 1;
81 changes: 81 additions & 0 deletions apis/humidity/src/tests.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
use core::cell::Cell;
use libtock_platform::{share, ErrorCode, Syscalls, YieldNoWaitReturn};
use libtock_unittest::fake;

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

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

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

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

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

assert_eq!(Humidity::humidity_read(), Ok(()));
assert!(driver.is_busy());

assert_eq!(Humidity::humidity_read(), Err(ErrorCode::Busy));
assert_eq!(Humidity::humidity_read_sync(), Err(ErrorCode::Busy));
}

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

let humidity_cell: Cell<Option<i32>> = Cell::new(None);
let listener = crate::HumidityListener(|temp_val| {
humidity_cell.set(Some(temp_val));
});
share::scope(|subscribe| {
assert_eq!(Humidity::humidity_read(), Ok(()));
driver.set_value(100);
assert_eq!(fake::Syscalls::yield_no_wait(), YieldNoWaitReturn::NoUpcall);

assert_eq!(Humidity::register_listener(&listener, subscribe), Ok(()));
assert_eq!(Humidity::humidity_read(), Ok(()));
driver.set_value(100);
assert_eq!(fake::Syscalls::yield_no_wait(), YieldNoWaitReturn::Upcall);
assert_eq!(humidity_cell.get(), Some(100));

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

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

driver.set_value_sync(1000);
assert_eq!(Humidity::humidity_read_sync(), Ok(1000));
}

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

driver.set_value_sync(-1000);
assert_eq!(Humidity::humidity_read_sync(), Ok(-1000));
}
41 changes: 41 additions & 0 deletions examples/humidity.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
//! A simple libtock-rs example. Checks for humidity 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::runtime::{set_main, stack_size};
use libtock::humidity::Humidity;

set_main! {main}
stack_size! {0x200}

fn main() {
match Humidity::exists() {
Ok(()) => writeln!(Console::writer(), "humidity driver available").unwrap(),
Err(_) => {
writeln!(Console::writer(), "humidity driver unavailable").unwrap();
return;
}
}

loop {
match Humidity::humidity_read_sync() {
Ok(hum_val) => writeln!(
Console::writer(),
"Humidity: {}{}.{}%\n",
if hum_val > 0 { "" } else { "-" },
i32::abs(hum_val) / 100,
i32::abs(hum_val) % 100
)
.unwrap(),
Err(_) => writeln!(Console::writer(), "error while reading humidity",).unwrap(),
}

Alarm::sleep_for(Milliseconds(2000)).unwrap();
}
Comment on lines +26 to +40

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Move this in the Ok branch of the previous match.

}
6 changes: 3 additions & 3 deletions runner/src/tockloader.rs

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please revert this file.

Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ pub fn deploy(cli: &Cli, platform: String, tab_path: PathBuf) -> Child {
}

// Invoke tockloader uninstall to remove the process binary, if present.
let mut uninstall = Command::new("tockloader");
let mut uninstall = Command::new("/Users/radueduard39/Library/Python/3.10/bin/tockloader");
uninstall.arg("uninstall");
uninstall.args(flags);
if cli.verbose {
Expand All @@ -75,7 +75,7 @@ pub fn deploy(cli: &Cli, platform: String, tab_path: PathBuf) -> Child {
}

// Invoke tockloader install to deploy the new process binary.
let mut install = Command::new("tockloader");
let mut install = Command::new("/Users/radueduard39/Library/Python/3.10/bin/tockloader");
install.arg("install");
install.args(flags);
install.arg(tab_path);
Expand All @@ -94,7 +94,7 @@ pub fn deploy(cli: &Cli, platform: String, tab_path: PathBuf) -> Child {
);

// Invoke tockloader listen to receive messages from the Tock system.
let mut listen = Command::new("tockloader");
let mut listen = Command::new("/Users/radueduard39/Library/Python/3.10/bin/tockloader");
listen.arg("listen");
listen.args(flags);
listen.stdout(Stdio::piped());
Expand Down
2 changes: 1 addition & 1 deletion runtime/layouts/microbit_v2.ld
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

MEMORY {
FLASH (X) : ORIGIN = 0x00040000, LENGTH = 256K
RAM (W) : ORIGIN = 0x20004000, LENGTH = 112K
RAM (W) : ORIGIN = 0x20004800, LENGTH = 112K

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Revert this file

}

TBF_HEADER_SIZE = 0x60;
Expand Down
6 changes: 6 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,3 +44,9 @@ pub mod temperature {
pub type Temperature = temperature::Temperature<super::runtime::TockSyscalls>;
pub use temperature::TemperatureListener;
}

pub mod humidity {
use libtock_humidity as humidity;
pub type Humidity = humidity::Humidity<super::runtime::TockSyscalls>;
pub use humidity::HumidityListener;
}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add a newline.

84 changes: 84 additions & 0 deletions unittest/src/fake/humidity/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
//! Fake implementation of the Humidity API, documented here:
//!
//! Like the real API, `Humidity` controls a fake humidity sensor. It provides
//! a function `set_value` used to immediately call an upcall with a humidity value read by the sensor
//! and a function 'set_value_sync' used to call the upcall when the read command is received.
use crate::{DriverInfo, DriverShareRef};
use libtock_platform::{CommandReturn, ErrorCode};
use std::cell::Cell;

// The `upcall_on_command` field is set to Some(value) if an upcall(with value as its argument) should be called when read command is received,
// or None otherwise. It was needed for testing `read_sync` library function which simulates a synchronous temperature read,
// because it was impossible to schedule an upcall during the `synchronous` read in other ways.
Comment on lines +11 to +13

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Move this comment next to the field using ///

pub struct Humidity {
busy: Cell<bool>,
upcall_on_command: Cell<Option<i32>>,
share_ref: DriverShareRef,
}

impl Humidity {
pub fn new() -> std::rc::Rc<Humidity> {
std::rc::Rc::new(Humidity {
busy: Cell::new(false),
upcall_on_command: Cell::new(None),
share_ref: Default::default(),
})
}

pub fn is_busy(&self) -> bool {
self.busy.get()
}
pub fn set_value(&self, value: i32) {
if self.busy.get() {
self.share_ref
.schedule_upcall(0, (value as u32, 0, 0))
.expect("Unable to schedule upcall");
self.busy.set(false);
}
}
pub fn set_value_sync(&self, value: i32) {
self.upcall_on_command.set(Some(value));
}
}

impl crate::fake::SyscallDriver for Humidity {
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(),

READ_HUM => {
if self.busy.get() {
return crate::command_return::failure(ErrorCode::Busy);
}
self.busy.set(true);
if let Some(val) = self.upcall_on_command.take() {
self.set_value(val);
}
crate::command_return::success()
}
_ => crate::command_return::failure(ErrorCode::NoSupport),
}
}
}

#[cfg(test)]
mod tests;
// -----------------------------------------------------------------------------
// Driver number and command IDs
// -----------------------------------------------------------------------------

const DRIVER_NUM: u32 = 0x60001;

// Command IDs

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