Skip to content

Commit 089f5c6

Browse files
author
Johnathan Van Why
authored
Merge pull request #524 from CosminGGeorgescu/rng_api
Rng API
2 parents 4d14230 + 9695aed commit 089f5c6

File tree

6 files changed

+212
-4
lines changed

6 files changed

+212
-4
lines changed

Cargo.toml

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,12 @@ version = "0.1.0"
1616
rust-version = "1.70"
1717

1818
[dependencies]
19-
libtock_adc = { path = "apis/adc"}
19+
libtock_adc = { path = "apis/adc" }
2020
libtock_air_quality = { path = "apis/air_quality" }
2121
libtock_alarm = { path = "apis/alarm" }
2222
libtock_ambient_light = { path = "apis/ambient_light" }
2323
libtock_buttons = { path = "apis/buttons" }
24-
libtock_buzzer = {path = "apis/buzzer"}
24+
libtock_buzzer = { path = "apis/buzzer" }
2525
libtock_console = { path = "apis/console" }
2626
libtock_debug_panic = { path = "panic_handlers/debug_panic" }
2727
libtock_gpio = { path = "apis/gpio" }
@@ -31,12 +31,13 @@ libtock_low_level_debug = { path = "apis/low_level_debug" }
3131
libtock_ninedof = { path = "apis/ninedof" }
3232
libtock_platform = { path = "platform" }
3333
libtock_proximity = { path = "apis/proximity" }
34+
libtock_rng = { path = "apis/rng" }
3435
libtock_runtime = { path = "runtime" }
35-
libtock_sound_pressure = {path = "apis/sound_pressure"}
36+
libtock_sound_pressure = { path = "apis/sound_pressure" }
3637
libtock_temperature = { path = "apis/temperature" }
3738

3839
[build-dependencies]
39-
libtock_build_scripts = { path = "build_scripts"}
40+
libtock_build_scripts = { path = "build_scripts" }
4041

4142
[profile.dev]
4243
debug = true
@@ -64,6 +65,7 @@ members = [
6465
"apis/low_level_debug",
6566
"apis/ninedof",
6667
"apis/proximity",
68+
"apis/rng",
6769
"apis/temperature",
6870
"panic_handlers/debug_panic",
6971
"panic_handlers/small_panic",

apis/rng/Cargo.toml

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
[package]
2+
name = "libtock_rng"
3+
version = "0.1.0"
4+
authors = [
5+
"Tock Project Developers <tock-dev@googlegroups.com>",
6+
"Cosmin Gabriel Georgescu <cosmingg2013@gmail.com>",
7+
]
8+
license = "Apache-2.0 OR MIT"
9+
edition = "2021"
10+
repository = "https://www.github.com/tock/libtock-rs"
11+
rust-version.workspace = true
12+
description = "libtock rng driver"
13+
14+
[dependencies]
15+
libtock_platform = { path = "../../platform" }
16+
17+
[dev-dependencies]
18+
libtock_unittest = { path = "../../unittest" }

apis/rng/src/lib.rs

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
#![no_std]
2+
3+
use core::cell::Cell;
4+
use libtock_platform::{
5+
share, subscribe::OneId, AllowRw, DefaultConfig, ErrorCode, Subscribe, Syscalls, Upcall,
6+
};
7+
8+
pub struct Rng<S: Syscalls>(S);
9+
10+
impl<S: Syscalls> Rng<S> {
11+
/// Check if the RNG kernel driver exists
12+
pub fn exists() -> Result<(), ErrorCode> {
13+
S::command(DRIVER_NUM, EXISTS, 0, 0).to_result()
14+
}
15+
16+
/// Request `n` bytes of randomness in an asynchronous way.
17+
/// Users must first share a buffer slice with the kernel and register an Rng listener
18+
pub fn get_bytes_async(n: u32) -> Result<(), ErrorCode> {
19+
S::command(DRIVER_NUM, GET_BYTES, n, 0).to_result()
20+
}
21+
22+
/// Share a buffer slice with the kernel.
23+
/// Must be used in conjunction with the `share::scope` function
24+
pub fn allow_buffer<'share>(
25+
buf: &'share mut [u8],
26+
allow_rw: share::Handle<AllowRw<'share, S, DRIVER_NUM, 0>>,
27+
) -> Result<(), ErrorCode> {
28+
S::allow_rw::<DefaultConfig, DRIVER_NUM, 0>(allow_rw, buf)
29+
}
30+
31+
pub fn unallow_buffer() {
32+
S::unallow_rw(DRIVER_NUM, 0)
33+
}
34+
35+
/// Register an Rng listener to be called when an upcall is serviced
36+
/// Must be used in conjunction with the `share::scope` function
37+
pub fn register_listener<'share, F: Fn(u32)>(
38+
listener: &'share RngListener<F>,
39+
subscribe: share::Handle<Subscribe<'share, S, DRIVER_NUM, 0>>,
40+
) -> Result<(), ErrorCode> {
41+
S::subscribe::<_, _, DefaultConfig, DRIVER_NUM, 0>(subscribe, listener)
42+
}
43+
44+
pub fn unregister_listener() {
45+
S::unsubscribe(DRIVER_NUM, 0)
46+
}
47+
48+
/// Ask to fill the provided `buf` with `n` random bytes.
49+
/// If `n > buf.len()`, it will simply fill the whole buffer.
50+
pub fn get_bytes_sync(buf: &mut [u8], n: u32) -> Result<(), ErrorCode> {
51+
let called = Cell::new(false);
52+
share::scope::<(AllowRw<S, DRIVER_NUM, 0>, Subscribe<S, DRIVER_NUM, 0>), _, _>(|handle| {
53+
let (allow_rw, subscribe) = handle.split();
54+
55+
// Share the provided buffer with the kernel
56+
S::allow_rw::<DefaultConfig, DRIVER_NUM, 0>(allow_rw, buf)?;
57+
58+
// Subscribe for an upcall with the kernel
59+
S::subscribe::<_, _, DefaultConfig, DRIVER_NUM, 0>(subscribe, &called)?;
60+
61+
// Send the command to the kernel driver to fill the allowed_readwrite buffer
62+
S::command(DRIVER_NUM, GET_BYTES, n, 0).to_result()?;
63+
64+
// Wait for a callback to happen
65+
while !called.get() {
66+
S::yield_wait();
67+
}
68+
69+
Ok(())
70+
})
71+
}
72+
}
73+
74+
/// The provided listener to be called.
75+
/// Interior function operates on the number of random bytes filled into the buffer
76+
pub struct RngListener<F: Fn(u32)>(pub F);
77+
78+
impl<F: Fn(u32)> Upcall<OneId<DRIVER_NUM, 0>> for RngListener<F> {
79+
fn upcall(&self, _: u32, arg1: u32, _: u32) {
80+
(self.0)(arg1)
81+
}
82+
}
83+
84+
// -------------
85+
// DRIVER NUMBER
86+
// -------------
87+
const DRIVER_NUM: u32 = 0x40001;
88+
89+
// ---------------
90+
// COMMAND NUMBERS
91+
// ---------------
92+
const EXISTS: u32 = 0;
93+
const GET_BYTES: u32 = 1;

examples/rng.rs

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
#![no_std]
2+
#![no_main]
3+
4+
use core::fmt::Write;
5+
use libtock::alarm::{Alarm, Milliseconds};
6+
use libtock::console::Console;
7+
use libtock::rng::Rng;
8+
use libtock::runtime::{set_main, stack_size};
9+
10+
stack_size! {0x300}
11+
set_main! {main}
12+
13+
struct Randomness<'a, const N: usize>(&'a [u8; N]);
14+
15+
impl<'a, const N: usize> core::fmt::Display for Randomness<'a, N> {
16+
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
17+
let mut bytes = self.0.iter();
18+
while let Some(&byte) = bytes.next() {
19+
write!(f, "{byte:02x}")?;
20+
}
21+
Ok(())
22+
}
23+
}
24+
25+
fn main() {
26+
if let Err(e) = Rng::exists() {
27+
writeln!(Console::writer(), "RNG DRIVER ERROR: {e:?}").unwrap();
28+
return;
29+
}
30+
31+
let mut console_writer = Console::writer();
32+
let mut buffer: [u8; 32] = Default::default();
33+
let n: u32 = 32;
34+
35+
loop {
36+
match Rng::get_bytes_sync(&mut buffer, n) {
37+
Ok(()) => {
38+
let _ = writeln!(console_writer, "Randomness: {}", Randomness(&buffer));
39+
}
40+
Err(e) => {
41+
let _ = writeln!(console_writer, "Error while getting bytes {e:?}");
42+
}
43+
}
44+
let _ = Alarm::sleep_for(Milliseconds(2000));
45+
}
46+
}

examples/rng_async.rs

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
#![no_std]
2+
#![no_main]
3+
4+
use core::fmt::Write;
5+
use libtock::alarm::{Alarm, Milliseconds};
6+
use libtock::rng::RngListener;
7+
use libtock::{console::Console, rng::Rng};
8+
use libtock_platform::{share, Syscalls};
9+
use libtock_runtime::{set_main, stack_size, TockSyscalls};
10+
11+
stack_size! {0x300}
12+
set_main! {main}
13+
14+
fn main() {
15+
if let Err(e) = Rng::exists() {
16+
writeln!(Console::writer(), "RNG DRIVER ERROR: {e:?}").unwrap();
17+
return;
18+
}
19+
20+
let mut console_writer = Console::writer();
21+
let rng_listener = RngListener(|_| write!(Console::writer(), "Randomness: ").unwrap());
22+
let mut buffer: [u8; 32] = Default::default();
23+
let n: u32 = 32;
24+
25+
loop {
26+
share::scope(|allow_rw| {
27+
Rng::allow_buffer(&mut buffer, allow_rw).unwrap();
28+
29+
share::scope(|subscribe| {
30+
Rng::register_listener(&rng_listener, subscribe).unwrap();
31+
32+
Rng::get_bytes_async(n).unwrap();
33+
TockSyscalls::yield_wait();
34+
});
35+
});
36+
37+
buffer.iter().for_each(|&byte| {
38+
let _ = write!(console_writer, "{byte:02x}");
39+
});
40+
let _ = writeln!(console_writer, "");
41+
42+
let _ = Alarm::sleep_for(Milliseconds(2000));
43+
}
44+
}

src/lib.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,11 @@ pub mod proximity {
7373
use libtock_proximity as proximity;
7474
pub type Proximity = proximity::Proximity<super::runtime::TockSyscalls>;
7575
}
76+
pub mod rng {
77+
use libtock_rng as rng;
78+
pub type Rng = rng::Rng<super::runtime::TockSyscalls>;
79+
pub use rng::RngListener;
80+
}
7681
pub mod sound_pressure {
7782
use libtock_sound_pressure as sound_pressure;
7883
pub type SoundPressure = sound_pressure::SoundPressure<super::runtime::TockSyscalls>;

0 commit comments

Comments
 (0)