Skip to content

Commit 0fd0e2e

Browse files
Merge tock#122
122: Create 'drivers' singleton r=torfmaster a=torfmaster # Overview The drivers as well as the hardware represented by the drivers is only available once. To prevent hacing multiple mutable references to this global mutable state we do the following: * collect all drivers in a `drivers` object which is a singleton * ~if a driver allows to create a mutable reference to a part (e.g. an led) mutably borrow the driver as whole~ # Progress The following drivers have been migrated: [x] Timer [x] Led [x] Console [x] GPIO [x] Temperature [x] Buttons [x] ADC [x] RNG [x] BLE [x] ninedof # Help needed As this PR concerns API design comments are welcome! Moreover, the initialization of the `Hardware` struct is very verbose. However, initialization using a `Default` implementation is not desired as this would make the individual drivers constructible outside the trate which is unsafe. Any ideas are very welcome. Co-authored-by: torfmaster <[email protected]>
2 parents c64b16c + bbd847d commit 0fd0e2e

38 files changed

+729
-409
lines changed

.travis.yml

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ os:
1313
- linux
1414
- osx
1515

16-
cache: rust
16+
cache: cargo
1717

1818
install:
1919
- rustup target add thumbv7em-none-eabi
@@ -22,7 +22,4 @@ install:
2222
- rustup component add clippy
2323

2424
script:
25-
- cargo fmt --all -- --check
26-
- cargo test --workspace
27-
- cargo clippy --workspace --all-targets
28-
- ./build_examples.sh
25+
- ./run_all_checks.sh

CHANGELOG.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,8 @@
1717
- `syscalls::allow_ptr` becomes `syscalls::raw::allow`
1818
- Targets without support for atomics can be built
1919
- Most API functions, including `main()`, return a `Result<T, TockError>`
20-
- The timer now supports to be used simultaneously. To make this safe, `TimerDriver` is now a singleton.
20+
- The library now supports parallel timers
21+
- all drivers can exclusively be retrieved by `retrieve_drivers` which returns a `Drivers`-singleton. Drivers can be shared between different tasks only if it is safe to do so.
2122

2223
## a8bb4fa9be504517d5533511fd8e607ea61f1750 (0.1.0)
2324

examples/adc.rs

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,23 @@
11
#![no_std]
22

33
use core::fmt::Write;
4-
use libtock::adc;
5-
use libtock::console::Console;
64
use libtock::result::TockResult;
7-
use libtock::timer;
85
use libtock::timer::Duration;
6+
use libtock::Drivers;
97

108
#[libtock::main]
119
async fn main() -> TockResult<()> {
12-
let context = timer::DriverContext::create()?;
13-
let mut driver = context.create_timer_driver()?;
14-
let timer_driver = driver.activate()?;
10+
let Drivers {
11+
console_driver,
12+
timer_context,
13+
adc_driver,
14+
..
15+
} = libtock::retrieve_drivers()?;
1516

16-
let mut console = Console::default();
17-
let mut with_callback = adc::with_callback(|channel: usize, value: usize| {
17+
let mut driver = timer_context.create_timer_driver();
18+
let timer_driver = driver.activate()?;
19+
let mut console = console_driver.create_console();
20+
let mut with_callback = adc_driver.with_callback(|channel: usize, value: usize| {
1821
writeln!(console, "channel: {}, value: {}", channel, value).unwrap();
1922
});
2023

examples/adc_buffer.rs

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,26 @@
11
#![no_std]
22

33
use core::fmt::Write;
4-
use libtock::adc;
54
use libtock::adc::AdcBuffer;
6-
use libtock::console::Console;
75
use libtock::result::TockResult;
86
use libtock::syscalls;
7+
use libtock::Drivers;
98

109
#[libtock::main]
1110
/// Reads a 128 byte sample into a buffer and prints the first value to the console.
1211
async fn main() -> TockResult<()> {
13-
let mut console = Console::default();
12+
let Drivers {
13+
console_driver,
14+
adc_driver,
15+
..
16+
} = libtock::retrieve_drivers()?;
17+
let mut console = console_driver.create_console();
1418
let mut adc_buffer = AdcBuffer::default();
1519
let mut temp_buffer = [0; libtock::adc::BUFFER_SIZE];
1620

1721
let adc_buffer = libtock::adc::Adc::init_buffer(&mut adc_buffer)?;
1822

19-
let mut with_callback = adc::with_callback(|_, _| {
23+
let mut with_callback = adc_driver.with_callback(|_, _| {
2024
adc_buffer.read_bytes(&mut temp_buffer[..]);
2125
writeln!(console, "First sample in buffer: {}", temp_buffer[0]).unwrap();
2226
});

examples/ble_scanning.rs

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,11 @@
22

33
use futures::future;
44
use libtock::ble_parser;
5-
use libtock::led;
65
use libtock::result::TockResult;
76
use libtock::simple_ble;
87
use libtock::simple_ble::BleCallback;
9-
use libtock::simple_ble::BleDriver;
8+
use libtock::simple_ble::BleScanningDriver;
9+
use libtock::Drivers;
1010
use serde::Deserialize;
1111

1212
#[derive(Deserialize)]
@@ -17,19 +17,31 @@ struct LedCommand {
1717

1818
#[libtock::main]
1919
async fn main() -> TockResult<()> {
20-
let mut shared_buffer = BleDriver::create_scan_buffer();
21-
let mut my_buffer = BleDriver::create_scan_buffer();
22-
let shared_memory = BleDriver::share_memory(&mut shared_buffer)?;
20+
let Drivers {
21+
led_driver_factory,
22+
mut ble_scanning_driver,
23+
..
24+
} = libtock::retrieve_drivers()?;
25+
26+
let led_driver = led_driver_factory.create_driver()?;
27+
28+
let mut shared_buffer = BleScanningDriver::create_scan_buffer();
29+
let mut my_buffer = BleScanningDriver::create_scan_buffer();
30+
let shared_memory = ble_scanning_driver.share_memory(&mut shared_buffer)?;
2331

2432
let mut callback = BleCallback::new(|_: usize, _: usize| {
2533
shared_memory.read_bytes(&mut my_buffer[..]);
2634
ble_parser::find(&my_buffer, simple_ble::gap_data::SERVICE_DATA as u8)
2735
.and_then(|service_data| ble_parser::extract_for_service([91, 79], service_data))
2836
.and_then(|payload| corepack::from_bytes::<LedCommand>(&payload).ok())
29-
.and_then(|msg| led::get(msg.nr as usize).map(|led| led.set_state(msg.st)));
37+
.and_then(|msg| {
38+
led_driver
39+
.get(msg.nr as usize)
40+
.map(|led| led.set_state(msg.st))
41+
});
3042
});
3143

32-
let _subscription = BleDriver::start(&mut callback)?;
44+
let _subscription = ble_scanning_driver.start(&mut callback)?;
3345

3446
future::pending().await
3547
}

examples/blink.rs

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,31 @@
11
#![no_std]
22

3-
use libtock::led;
43
use libtock::result::TockResult;
5-
use libtock::timer;
64
use libtock::timer::Duration;
5+
use libtock::Drivers;
76

87
#[libtock::main]
98
async fn main() -> TockResult<()> {
10-
let num_leds = led::count()?;
11-
let context = timer::DriverContext::create()?;
12-
let mut driver = context.create_timer_driver()?;
9+
let Drivers {
10+
led_driver_factory,
11+
timer_context,
12+
..
13+
} = libtock::retrieve_drivers()?;
14+
15+
let mut driver = timer_context.create_timer_driver();
1316
let timer_driver = driver.activate()?;
17+
let led_driver = led_driver_factory.create_driver()?;
1418

1519
// Blink the LEDs in a binary count pattern and scale
1620
// to the number of LEDs on the board.
1721
let mut count: usize = 0;
1822
loop {
19-
for i in 0..num_leds {
23+
for led in led_driver.all() {
24+
let i = led.number();
2025
if count & (1 << i) == (1 << i) {
21-
led::get(i).unwrap().on()?;
26+
led.on()?;
2227
} else {
23-
led::get(i).unwrap().off()?;
28+
led.off()?;
2429
}
2530
}
2631
count = count.wrapping_add(1);

examples/blink_random.rs

Lines changed: 18 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,38 +1,45 @@
11
#![no_std]
22

3-
use libtock::led;
3+
use libtock::led::LedDriver;
44
use libtock::result::TockResult;
5-
use libtock::rng;
6-
use libtock::timer;
75
use libtock::timer::Duration;
6+
use libtock::Drivers;
87

98
#[libtock::main]
109
async fn main() -> TockResult<()> {
11-
let context = timer::DriverContext::create()?;
12-
let mut driver = context.create_timer_driver()?;
10+
let Drivers {
11+
timer_context,
12+
mut rng_driver,
13+
led_driver_factory,
14+
..
15+
} = libtock::retrieve_drivers()?;
16+
17+
let led_driver = led_driver_factory.create_driver()?;
18+
19+
let mut driver = timer_context.create_timer_driver();
1320
let timer_driver = driver.activate()?;
1421

15-
let num_leds = led::count()?;
22+
let num_leds = led_driver.count()?;
1623
// blink_nibble assumes 4 leds.
1724
assert_eq!(num_leds, 4);
1825

1926
let mut buf = [0; 64];
2027
loop {
21-
rng::fill_buffer(&mut buf).await?;
28+
rng_driver.fill_buffer(&mut buf).await?;
2229

2330
for &x in buf.iter() {
24-
blink_nibble(x)?;
31+
blink_nibble(x, &led_driver)?;
2532
timer_driver.sleep(Duration::from_ms(100)).await?;
26-
blink_nibble(x >> 4)?;
33+
blink_nibble(x >> 4, &led_driver)?;
2734
timer_driver.sleep(Duration::from_ms(100)).await?;
2835
}
2936
}
3037
}
3138

3239
// Takes the 4 least-significant bits of x, and turn the 4 leds on/off accordingly.
33-
fn blink_nibble(x: u8) -> TockResult<()> {
40+
fn blink_nibble(x: u8, led_driver: &LedDriver) -> TockResult<()> {
3441
for i in 0..4 {
35-
let led = led::get(i).unwrap();
42+
let led = led_driver.get(i).unwrap();
3643
if (x >> i) & 1 != 0 {
3744
led.on()?;
3845
} else {

examples/button_leds.rs

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,23 @@
11
#![no_std]
22

33
use futures::future;
4-
use libtock::buttons;
54
use libtock::buttons::ButtonState;
6-
use libtock::led;
75
use libtock::result::TockResult;
6+
use libtock::Drivers;
87

98
#[libtock::main]
109
async fn main() -> TockResult<()> {
11-
let mut with_callback = buttons::with_callback(|button_num: usize, state| {
10+
let Drivers {
11+
led_driver_factory,
12+
button_driver,
13+
..
14+
} = libtock::retrieve_drivers()?;
15+
16+
let led_driver = led_driver_factory.create_driver()?;
17+
18+
let mut with_callback = button_driver.with_callback(|button_num: usize, state| {
1219
match state {
13-
ButtonState::Pressed => led::get(button_num).unwrap().toggle().ok().unwrap(),
20+
ButtonState::Pressed => led_driver.get(button_num).unwrap().toggle().ok().unwrap(),
1421
ButtonState::Released => (),
1522
};
1623
});

examples/button_read.rs

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,26 @@
11
#![no_std]
22

33
use core::fmt::Write;
4-
use libtock::buttons;
54
use libtock::buttons::ButtonState;
6-
use libtock::console::Console;
75
use libtock::result::TockResult;
8-
use libtock::timer;
96
use libtock::timer::Duration;
7+
use libtock::Drivers;
108

119
#[libtock::main]
1210
async fn main() -> TockResult<()> {
13-
let mut console = Console::default();
14-
let mut with_callback = buttons::with_callback(|_, _| {});
11+
let Drivers {
12+
console_driver,
13+
timer_context,
14+
button_driver,
15+
..
16+
} = libtock::retrieve_drivers()?;
17+
let mut console = console_driver.create_console();
18+
let mut with_callback = button_driver.with_callback(|_, _| {});
1519
let mut buttons = with_callback.init()?;
1620
let mut button = buttons.iter_mut().next().unwrap();
1721
let button = button.enable()?;
1822

19-
let context = timer::DriverContext::create()?;
20-
let mut driver = context.create_timer_driver()?;
23+
let mut driver = timer_context.create_timer_driver();
2124
let timer_driver = driver.activate()?;
2225

2326
loop {

examples/button_subscribe.rs

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,20 @@
22

33
use core::fmt::Write;
44
use futures::future;
5-
use libtock::buttons;
65
use libtock::buttons::ButtonState;
7-
use libtock::console::Console;
86
use libtock::result::TockResult;
7+
use libtock::Drivers;
98

109
// FIXME: Hangs up when buttons are pressed rapidly. Yielding in callback leads to stack overflow.
1110
#[libtock::main]
1211
async fn main() -> TockResult<()> {
13-
let mut console = Console::default();
14-
15-
let mut with_callback = buttons::with_callback(|button_num: usize, state| {
12+
let Drivers {
13+
console_driver,
14+
button_driver,
15+
..
16+
} = libtock::retrieve_drivers()?;
17+
let mut console = console_driver.create_console();
18+
let mut with_callback = button_driver.with_callback(|button_num: usize, state| {
1619
writeln!(
1720
console,
1821
"Button: {} - State: {}",

examples/gpio.rs

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,20 @@
11
#![no_std]
22

3-
use libtock::gpio::GpioPinUnitialized;
43
use libtock::result::TockResult;
5-
use libtock::timer;
64
use libtock::timer::Duration;
5+
use libtock::Drivers;
76

87
// Example works on P0.03
98
#[libtock::main]
109
async fn main() -> TockResult<()> {
11-
let pin = GpioPinUnitialized::new(0);
10+
let Drivers {
11+
timer_context,
12+
gpio_driver,
13+
..
14+
} = libtock::retrieve_drivers()?;
15+
let pin = gpio_driver.pin(0)?;
1216
let pin = pin.open_for_write()?;
13-
let context = timer::DriverContext::create()?;
14-
let mut driver = context.create_timer_driver()?;
17+
let mut driver = timer_context.create_timer_driver();
1518
let timer_driver = driver.activate()?;
1619

1720
loop {

examples/gpio_read.rs

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,24 @@
11
#![no_std]
22

33
use core::fmt::Write;
4-
use libtock::console::Console;
5-
use libtock::gpio::GpioPinUnitialized;
64
use libtock::gpio::InputMode;
75
use libtock::result::TockResult;
8-
use libtock::timer;
96
use libtock::timer::Duration;
7+
use libtock::Drivers;
108

119
// example works on p0.03
1210
#[libtock::main]
1311
async fn main() -> TockResult<()> {
14-
let mut console = Console::default();
15-
let pin = GpioPinUnitialized::new(0);
12+
let Drivers {
13+
console_driver,
14+
timer_context,
15+
gpio_driver,
16+
..
17+
} = libtock::retrieve_drivers()?;
18+
let mut console = console_driver.create_console();
19+
let pin = gpio_driver.pin(0)?;
1620
let pin = pin.open_for_read(None, InputMode::PullDown)?;
17-
let context = timer::DriverContext::create()?;
18-
let mut driver = context.create_timer_driver()?;
21+
let mut driver = timer_context.create_timer_driver();
1922
let timer_driver = driver.activate()?;
2023

2124
loop {

0 commit comments

Comments
 (0)