Skip to content

Commit c901780

Browse files
committed
zephyr: gpio: Simplify usage
The gpio driver's 'token' to ensure uniqueness doesn't really help with correctness (as C code can use the gpio device as well). Short of re-defining the gpio interfaces, remove this token entirely, and make only the `get_instance` of gpio unsafe, to indicate that the safety of GPIO operations is dependent on the underlying controller. This should improve the hygeine of the GPIO API significantly, and allow uses, such as waiting on multiple pins, to be possible. Signed-off-by: David Brown <[email protected]>
1 parent 2b75fc5 commit c901780

File tree

2 files changed

+21
-62
lines changed

2 files changed

+21
-62
lines changed

samples/blinky/src/lib.rs

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010

1111
use log::warn;
1212

13-
use zephyr::raw::GPIO_OUTPUT_ACTIVE;
13+
use zephyr::raw::ZR_GPIO_OUTPUT_ACTIVE;
1414
use zephyr::time::{sleep, Duration};
1515

1616
#[no_mangle]
@@ -29,21 +29,16 @@ fn do_blink() {
2929
warn!("Inside of blinky");
3030

3131
let mut led0 = zephyr::devicetree::aliases::led0::get_instance().unwrap();
32-
let mut gpio_token = unsafe { zephyr::device::gpio::GpioToken::get_instance().unwrap() };
3332

3433
if !led0.is_ready() {
3534
warn!("LED is not ready");
3635
loop {}
3736
}
3837

39-
unsafe {
40-
led0.configure(&mut gpio_token, GPIO_OUTPUT_ACTIVE);
41-
}
38+
led0.configure(ZR_GPIO_OUTPUT_ACTIVE);
4239
let duration = Duration::millis_at_least(500);
4340
loop {
44-
unsafe {
45-
led0.toggle_pin(&mut gpio_token);
46-
}
41+
led0.toggle_pin();
4742
sleep(duration);
4843
}
4944
}

zephyr/src/device/gpio.rs

Lines changed: 18 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -158,12 +158,9 @@ mod async_io {
158158
///
159159
/// # Safety
160160
///
161-
/// The `_token` enforces single use of gpios. Note that this makes it impossible to wait for
162-
/// more than one GPIO.
163-
///
161+
/// Safety of multiple GPIOs depends on the underlying controller.
164162
pub unsafe fn wait_for_high(
165163
&mut self,
166-
_token: &mut GpioToken,
167164
) -> impl Future<Output = ()> + use<'_> {
168165
GpioWait::new(self, 1)
169166
}
@@ -172,11 +169,9 @@ mod async_io {
172169
///
173170
/// # Safety
174171
///
175-
/// The `_token` enforces single use of gpios. Note that this makes it impossible to wait
176-
/// for more than one GPIO.
172+
/// Safety of multiple GPIOs depends on the underlying controller.
177173
pub unsafe fn wait_for_low(
178174
&mut self,
179-
_token: &mut GpioToken,
180175
) -> impl Future<Output = ()> + use<'_> {
181176
GpioWait::new(self, 0)
182177
}
@@ -245,35 +240,6 @@ mod async_io {
245240

246241
pub(crate) use async_io::*;
247242

248-
/// Global instance to help make gpio in Rust slightly safer.
249-
///
250-
/// # Safety
251-
///
252-
/// To help with safety, the rust types use a global instance of a gpio-token. Methods will
253-
/// take a mutable reference to this, which will require either a single thread in the
254-
/// application code, or something like a mutex or critical section to manage. The operation
255-
/// methods are still unsafe, because we have no control over what happens with the gpio
256-
/// operations outside of Rust code, but this will help make the Rust usage at least better.
257-
pub struct GpioToken(());
258-
259-
static GPIO_TOKEN: Unique = Unique::new();
260-
261-
impl GpioToken {
262-
/// Retrieves the gpio token.
263-
///
264-
/// # Safety
265-
/// This is unsafe because lots of code in zephyr operates on the gpio drivers. The user of the
266-
/// gpio subsystem, in general should either coordinate all gpio access across the system (the
267-
/// token coordinates this only within Rust code), or verify that the particular gpio driver and
268-
/// methods are thread safe.
269-
pub unsafe fn get_instance() -> Option<GpioToken> {
270-
if !GPIO_TOKEN.once() {
271-
return None;
272-
}
273-
Some(GpioToken(()))
274-
}
275-
}
276-
277243
/// A single instance of a zephyr device to manage a gpio controller. A gpio controller
278244
/// represents a set of gpio pins, that are generally operated on by the same hardware block.
279245
pub struct Gpio {
@@ -312,9 +278,7 @@ impl Gpio {
312278

313279
/// A GpioPin represents a single pin on a gpio device.
314280
///
315-
/// This is a lightweight wrapper around the Zephyr `gpio_dt_spec` structure. Note that
316-
/// multiple pins may share a gpio controller, and as such, all methods on this are both unsafe,
317-
/// and require a mutable reference to the [`GpioToken`].
281+
/// This is a lightweight wrapper around the Zephyr `gpio_dt_spec` structure.
318282
#[allow(dead_code)]
319283
pub struct GpioPin {
320284
pub(crate) pin: raw::gpio_dt_spec,
@@ -366,10 +330,8 @@ impl GpioPin {
366330
///
367331
/// # Safety
368332
///
369-
/// The `_token` enforces single threaded use of gpios from Rust code. However, many drivers
370-
/// within Zephyr use GPIOs, and to use gpios safely, the caller must ensure that there is
371-
/// either not simultaneous use, or the gpio driver in question is thread safe.
372-
pub unsafe fn configure(&mut self, _token: &mut GpioToken, extra_flags: raw::gpio_flags_t) {
333+
/// Concurrency safety is determined by the underlying driver.
334+
pub fn configure(&mut self, extra_flags: raw::gpio_flags_t) {
373335
// TODO: Error?
374336
unsafe {
375337
raw::gpio_pin_configure(
@@ -384,27 +346,29 @@ impl GpioPin {
384346
///
385347
/// # Safety
386348
///
387-
/// The `_token` enforces single threaded use of gpios from Rust code. However, many drivers
388-
/// within Zephyr use GPIOs, and to use gpios safely, the caller must ensure that there is
389-
/// either not simultaneous use, or the gpio driver in question is thread safe.
390-
pub unsafe fn toggle_pin(&mut self, _token: &mut GpioToken) {
349+
/// Concurrency safety is determined by the underlying driver.
350+
pub fn toggle_pin(&mut self) {
391351
// TODO: Error?
392352
unsafe {
393353
raw::gpio_pin_toggle_dt(&self.pin);
394354
}
395355
}
396356

397357
/// Set the logical level of the pin.
398-
pub unsafe fn set(&mut self, _token: &mut GpioToken, value: bool) {
399-
raw::gpio_pin_set_dt(&self.pin, value as c_int);
358+
pub fn set(&mut self, value: bool) {
359+
unsafe {
360+
raw::gpio_pin_set_dt(&self.pin, value as c_int);
361+
}
400362
}
401363

402364
/// Read the logical level of the pin.
403-
pub unsafe fn get(&mut self, _token: &mut GpioToken) -> bool {
404-
match raw::gpio_pin_get_dt(&self.pin) {
405-
0 => false,
406-
1 => true,
407-
_ => panic!("TODO: Handle gpio get error"),
365+
pub fn get(&mut self) -> bool {
366+
unsafe {
367+
match raw::gpio_pin_get_dt(&self.pin) {
368+
0 => false,
369+
1 => true,
370+
_ => panic!("TODO: Handle gpio get error"),
371+
}
408372
}
409373
}
410374
}

0 commit comments

Comments
 (0)