Skip to content

Commit 034ae24

Browse files
bors[bot]Woyten
andauthored
Merge tock#131
131: Better subscribe API r=Woyten a=Woyten This PR improves the usability of the `subscribe` API. The current API has the following problems: - It is impossible to implement `SubscribableCallback` for different `FnMut` traits. This is the reason why the odd `WithCallback` helper objects were introduced. - `SubscribableCallback` is crate private by accident. As a result, it is hard to reason what types actually implement `SubscribableCallback` Besides that, the following APIs have been made more consistent: - LEDs - Buttons - GPIO - Temperature Co-authored-by: Woyten <[email protected]>
2 parents 0838210 + e22bc2b commit 034ae24

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

42 files changed

+940
-839
lines changed

.travis.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ cache: cargo
1818
install:
1919
- rustup target add thumbv7em-none-eabi
2020
- rustup target add riscv32imc-unknown-none-elf
21-
- rustup component add rustfmt-preview
21+
- rustup component add rustfmt
2222
- rustup component add clippy
2323

2424
script:

CHANGELOG.md

+23-5
Original file line numberDiff line numberDiff line change
@@ -2,23 +2,41 @@
22

33
## 0.2.0 (WIP)
44

5+
### Comprehensive Changes
6+
57
- Many functions are asynchronous
6-
- To make create an `async` main function you can use the attribute `#[libtock::main]`
8+
- To create an `async` main function you can use the attribute `#[libtock::main]`
79
- To retrieve the value of an asynchronous `value`, use `value.await`
810
- This is only possible within an `async fn`, so either
911
- Make the caller `fn` of `.await` an `async fn`
1012
- Not recommended: Use `core::executor::block_on(value)` to retrieve the `value`
13+
- Most API functions, including `main()`, return a `Result<T, TockError>`
14+
- 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.
15+
16+
### Changed APIs
17+
18+
- The basic APIs have been made consistent. They are initialized via driver factories and no longer require a `WithCallback` object, s.t. the callback subscription is more intuitive. The affected APIs are:
19+
- LEDs
20+
- Buttons
21+
- GPIO
22+
- Temperature
23+
- ADC (partially)
24+
- The timer API now supports concurrent sleep operations
25+
26+
### Syscalls
27+
28+
- `syscalls::subscribe` is actually usable
1129
- `syscalls::yieldk_for` is no longer available
1230
- Yielding manually is discouraged as it conflicts with Rust's safety guarantees. If you need to wait for a condition, use `futures::wait_until` and `.await`.
1331
- `syscalls::yieldk` has become `unsafe` for the same reason
14-
- Commands are no longer `unsafe`
32+
- `syscalls::command` is no longer `unsafe`
1533
- The low-level syscalls have been moved to `syscalls::raw`
1634
- `syscalls::subscribe_ptr` becomes `syscalls::raw::subscribe`
1735
- `syscalls::allow_ptr` becomes `syscalls::raw::allow`
36+
37+
### Miscellaneous
38+
1839
- Targets without support for atomics can be built
19-
- Most API functions, including `main()`, return a `Result<T, TockError>`
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.
2240

2341
## a8bb4fa9be504517d5533511fd8e607ea61f1750 (0.1.0)
2442

examples/adc.rs

+10-14
Original file line numberDiff line numberDiff line change
@@ -3,28 +3,24 @@
33
use core::fmt::Write;
44
use libtock::result::TockResult;
55
use libtock::timer::Duration;
6-
use libtock::Drivers;
76

87
#[libtock::main]
98
async fn main() -> TockResult<()> {
10-
let Drivers {
11-
console_driver,
12-
timer_context,
13-
adc_driver,
14-
..
15-
} = libtock::retrieve_drivers()?;
9+
let mut drivers = libtock::retrieve_drivers()?;
1610

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| {
11+
let adc_driver = drivers.adc.init_driver()?;
12+
let mut timer_driver = drivers.timer.create_timer_driver();
13+
let timer_driver = timer_driver.activate()?;
14+
let mut console = drivers.console.create_console();
15+
16+
let mut callback = |channel, value| {
2117
writeln!(console, "channel: {}, value: {}", channel, value).unwrap();
22-
});
18+
};
2319

24-
let adc = with_callback.init()?;
20+
let _subscription = adc_driver.subscribe(&mut callback)?;
2521

2622
loop {
27-
adc.sample(0)?;
23+
adc_driver.sample(0)?;
2824
timer_driver.sleep(Duration::from_ms(2000)).await?;
2925
}
3026
}

examples/adc_buffer.rs

+10-12
Original file line numberDiff line numberDiff line change
@@ -4,31 +4,29 @@ use core::fmt::Write;
44
use libtock::adc::AdcBuffer;
55
use libtock::result::TockResult;
66
use libtock::syscalls;
7-
use libtock::Drivers;
87

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

21-
let adc_buffer = libtock::adc::Adc::init_buffer(&mut adc_buffer)?;
19+
let adc_buffer = adc_driver.init_buffer(&mut adc_buffer)?;
2220

23-
let mut with_callback = adc_driver.with_callback(|_, _| {
21+
let mut callback = |_, _| {
2422
adc_buffer.read_bytes(&mut temp_buffer[..]);
2523
writeln!(console, "First sample in buffer: {}", temp_buffer[0]).unwrap();
26-
});
24+
};
2725

28-
let adc = with_callback.init()?;
26+
let _subscription = adc_driver.subscribe(&mut callback)?;
2927

3028
loop {
31-
adc.sample_continuous_buffered(0, 128)?;
29+
adc_driver.sample_continuous_buffered(0, 128)?;
3230
unsafe { syscalls::raw::yieldk() };
3331
}
3432
}

examples/alloc_error.rs

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
// Triggers the out-of-memory handler. Should make all LEDs cycle.
2+
3+
#![no_std]
4+
5+
extern crate alloc;
6+
7+
use alloc::vec::Vec;
8+
use libtock::result::TockResult;
9+
10+
#[libtock::main]
11+
fn main() -> TockResult<()> {
12+
let mut vec = Vec::new();
13+
loop {
14+
vec.push(0);
15+
}
16+
}

examples/ble_scanning.rs

+7-11
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ use libtock::result::TockResult;
66
use libtock::simple_ble;
77
use libtock::simple_ble::BleCallback;
88
use libtock::simple_ble::BleScanningDriver;
9-
use libtock::Drivers;
109
use serde::Deserialize;
1110

1211
#[derive(Deserialize)]
@@ -17,31 +16,28 @@ struct LedCommand {
1716

1817
#[libtock::main]
1918
async fn main() -> TockResult<()> {
20-
let Drivers {
21-
led_driver_factory,
22-
mut ble_scanning_driver,
23-
..
24-
} = libtock::retrieve_drivers()?;
19+
let mut drivers = libtock::retrieve_drivers()?;
2520

26-
let led_driver = led_driver_factory.create_driver()?;
21+
let leds_driver = drivers.leds.init_driver()?;
2722

2823
let mut shared_buffer = BleScanningDriver::create_scan_buffer();
2924
let mut my_buffer = BleScanningDriver::create_scan_buffer();
30-
let shared_memory = ble_scanning_driver.share_memory(&mut shared_buffer)?;
25+
let shared_memory = drivers.ble_scanning.share_memory(&mut shared_buffer)?;
3126

3227
let mut callback = BleCallback::new(|_: usize, _: usize| {
3328
shared_memory.read_bytes(&mut my_buffer[..]);
3429
ble_parser::find(&my_buffer, simple_ble::gap_data::SERVICE_DATA as u8)
3530
.and_then(|service_data| ble_parser::extract_for_service([91, 79], service_data))
3631
.and_then(|payload| corepack::from_bytes::<LedCommand>(&payload).ok())
3732
.and_then(|msg| {
38-
led_driver
33+
leds_driver
3934
.get(msg.nr as usize)
40-
.map(|led| led.set_state(msg.st))
35+
.map(|led| led.set(msg.st))
36+
.into()
4137
});
4238
});
4339

44-
let _subscription = ble_scanning_driver.start(&mut callback)?;
40+
let _subscription = drivers.ble_scanning.start(&mut callback)?;
4541

4642
future::pending().await
4743
}

examples/blink.rs

+6-11
Original file line numberDiff line numberDiff line change
@@ -2,26 +2,21 @@
22

33
use libtock::result::TockResult;
44
use libtock::timer::Duration;
5-
use libtock::Drivers;
65

76
#[libtock::main]
87
async fn main() -> TockResult<()> {
9-
let Drivers {
10-
led_driver_factory,
11-
timer_context,
12-
..
13-
} = libtock::retrieve_drivers()?;
8+
let mut drivers = libtock::retrieve_drivers()?;
149

15-
let mut driver = timer_context.create_timer_driver();
16-
let timer_driver = driver.activate()?;
17-
let led_driver = led_driver_factory.create_driver()?;
10+
let leds_driver = drivers.leds.init_driver()?;
11+
let mut timer_driver = drivers.timer.create_timer_driver();
12+
let timer_driver = timer_driver.activate()?;
1813

1914
// Blink the LEDs in a binary count pattern and scale
2015
// to the number of LEDs on the board.
2116
let mut count: usize = 0;
2217
loop {
23-
for led in led_driver.all() {
24-
let i = led.number();
18+
for led in leds_driver.leds() {
19+
let i = led.led_num();
2520
if count & (1 << i) == (1 << i) {
2621
led.on()?;
2722
} else {

examples/blink_random.rs

+11-19
Original file line numberDiff line numberDiff line change
@@ -1,45 +1,37 @@
11
#![no_std]
22

3-
use libtock::led::LedDriver;
3+
use libtock::leds::LedsDriver;
44
use libtock::result::TockResult;
55
use libtock::timer::Duration;
6-
use libtock::Drivers;
76

87
#[libtock::main]
98
async fn main() -> TockResult<()> {
10-
let Drivers {
11-
timer_context,
12-
mut rng_driver,
13-
led_driver_factory,
14-
..
15-
} = libtock::retrieve_drivers()?;
9+
let mut drivers = libtock::retrieve_drivers()?;
1610

17-
let led_driver = led_driver_factory.create_driver()?;
11+
let leds_driver = drivers.leds.init_driver()?;
12+
let mut timer_driver = drivers.timer.create_timer_driver();
13+
let timer_driver = timer_driver.activate()?;
1814

19-
let mut driver = timer_context.create_timer_driver();
20-
let timer_driver = driver.activate()?;
21-
22-
let num_leds = led_driver.count()?;
2315
// blink_nibble assumes 4 leds.
24-
assert_eq!(num_leds, 4);
16+
assert_eq!(leds_driver.num_leds(), 4);
2517

2618
let mut buf = [0; 64];
2719
loop {
28-
rng_driver.fill_buffer(&mut buf).await?;
20+
drivers.rng.fill_buffer(&mut buf).await?;
2921

3022
for &x in buf.iter() {
31-
blink_nibble(x, &led_driver)?;
23+
blink_nibble(&leds_driver, x)?;
3224
timer_driver.sleep(Duration::from_ms(100)).await?;
33-
blink_nibble(x >> 4, &led_driver)?;
25+
blink_nibble(&leds_driver, x >> 4)?;
3426
timer_driver.sleep(Duration::from_ms(100)).await?;
3527
}
3628
}
3729
}
3830

3931
// Takes the 4 least-significant bits of x, and turn the 4 leds on/off accordingly.
40-
fn blink_nibble(x: u8, led_driver: &LedDriver) -> TockResult<()> {
32+
fn blink_nibble(leds_driver: &LedsDriver, x: u8) -> TockResult<()> {
4133
for i in 0..4 {
42-
let led = led_driver.get(i).unwrap();
34+
let led = leds_driver.get(i)?;
4335
if (x >> i) & 1 != 0 {
4436
led.on()?;
4537
} else {

examples/button_leds.rs

+11-17
Original file line numberDiff line numberDiff line change
@@ -3,29 +3,23 @@
33
use futures::future;
44
use libtock::buttons::ButtonState;
55
use libtock::result::TockResult;
6-
use libtock::Drivers;
76

87
#[libtock::main]
98
async fn main() -> TockResult<()> {
10-
let Drivers {
11-
led_driver_factory,
12-
button_driver,
13-
..
14-
} = libtock::retrieve_drivers()?;
9+
let mut drivers = libtock::retrieve_drivers()?;
1510

16-
let led_driver = led_driver_factory.create_driver()?;
11+
let buttons_driver = drivers.buttons.init_driver()?;
12+
let leds_driver = drivers.leds.init_driver()?;
1713

18-
let mut with_callback = button_driver.with_callback(|button_num: usize, state| {
19-
match state {
20-
ButtonState::Pressed => led_driver.get(button_num).unwrap().toggle().ok().unwrap(),
21-
ButtonState::Released => (),
22-
};
23-
});
14+
let mut callback = |button_num, state| {
15+
if let (ButtonState::Pressed, Ok(led)) = (state, leds_driver.get(button_num)) {
16+
led.toggle().ok().unwrap();
17+
}
18+
};
2419

25-
let mut buttons = with_callback.init()?;
26-
27-
for mut button in &mut buttons {
28-
button.enable()?;
20+
let _subscription = buttons_driver.subscribe(&mut callback)?;
21+
for button in buttons_driver.buttons() {
22+
button.enable_interrupt()?;
2923
}
3024

3125
future::pending().await

examples/button_read.rs

+13-20
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,27 @@
11
#![no_std]
22

33
use core::fmt::Write;
4-
use libtock::buttons::ButtonState;
54
use libtock::result::TockResult;
65
use libtock::timer::Duration;
7-
use libtock::Drivers;
86

97
#[libtock::main]
108
async fn main() -> TockResult<()> {
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(|_, _| {});
19-
let mut buttons = with_callback.init()?;
20-
let mut button = buttons.iter_mut().next().unwrap();
21-
let button = button.enable()?;
9+
let mut drivers = libtock::retrieve_drivers()?;
2210

23-
let mut driver = timer_context.create_timer_driver();
24-
let timer_driver = driver.activate()?;
11+
let buttons_driver = drivers.buttons.init_driver()?;
12+
let mut timer_driver = drivers.timer.create_timer_driver();
13+
let timer_driver = timer_driver.activate()?;
14+
let mut console = drivers.console.create_console();
2515

2616
loop {
27-
match button.read()? {
28-
ButtonState::Pressed => writeln!(console, "pressed"),
29-
ButtonState::Released => writeln!(console, "released"),
30-
}?;
31-
17+
for button in buttons_driver.buttons() {
18+
writeln!(
19+
console,
20+
"button {}: {:?}",
21+
button.button_num(),
22+
button.read()?
23+
)?;
24+
}
3225
timer_driver.sleep(Duration::from_ms(500)).await?;
3326
}
3427
}

0 commit comments

Comments
 (0)