Skip to content

Remove the GpioToken entirely #111

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Jun 29, 2025
Merged
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
11 changes: 3 additions & 8 deletions samples/blinky/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@

use log::warn;

use zephyr::raw::GPIO_OUTPUT_ACTIVE;
use zephyr::raw::ZR_GPIO_OUTPUT_ACTIVE;
use zephyr::time::{sleep, Duration};

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

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

if !led0.is_ready() {
warn!("LED is not ready");
loop {}
}

unsafe {
led0.configure(&mut gpio_token, GPIO_OUTPUT_ACTIVE);
}
led0.configure(ZR_GPIO_OUTPUT_ACTIVE);
let duration = Duration::millis_at_least(500);
loop {
unsafe {
led0.toggle_pin(&mut gpio_token);
}
led0.toggle_pin();
sleep(duration);
}
}
Expand Down
1 change: 1 addition & 0 deletions zephyr-sys/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
#![allow(clippy::transmute_int_to_bool)]
#![allow(clippy::useless_transmute)]
#![allow(clippy::len_without_is_empty)]
#![allow(unnecessary_transmutes)]
include!(concat!(env!("OUT_DIR"), "/bindings.rs"));

// We have directed bindgen to not generate copy for any times. It unfortunately doesn't have an
Expand Down
82 changes: 21 additions & 61 deletions zephyr/src/device/gpio.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ mod async_io {

use crate::sync::atomic::{AtomicBool, AtomicU32};

use super::{GpioPin, GpioToken};
use super::GpioPin;

pub(crate) struct GpioStatic {
/// The wakers for each of the gpios.
Expand Down Expand Up @@ -158,26 +158,17 @@ mod async_io {
///
/// # Safety
///
/// The `_token` enforces single use of gpios. Note that this makes it impossible to wait for
/// more than one GPIO.
///
pub unsafe fn wait_for_high(
&mut self,
_token: &mut GpioToken,
) -> impl Future<Output = ()> + use<'_> {
/// Safety of multiple GPIOs depends on the underlying controller.
pub unsafe fn wait_for_high(&mut self) -> impl Future<Output = ()> + use<'_> {
GpioWait::new(self, 1)
}

/// Asynchronously wait for a gpio pin to become low.
///
/// # Safety
///
/// The `_token` enforces single use of gpios. Note that this makes it impossible to wait
/// for more than one GPIO.
pub unsafe fn wait_for_low(
&mut self,
_token: &mut GpioToken,
) -> impl Future<Output = ()> + use<'_> {
/// Safety of multiple GPIOs depends on the underlying controller.
pub unsafe fn wait_for_low(&mut self) -> impl Future<Output = ()> + use<'_> {
GpioWait::new(self, 0)
}
}
Expand Down Expand Up @@ -245,35 +236,6 @@ mod async_io {

pub(crate) use async_io::*;

/// Global instance to help make gpio in Rust slightly safer.
///
/// # Safety
///
/// To help with safety, the rust types use a global instance of a gpio-token. Methods will
/// take a mutable reference to this, which will require either a single thread in the
/// application code, or something like a mutex or critical section to manage. The operation
/// methods are still unsafe, because we have no control over what happens with the gpio
/// operations outside of Rust code, but this will help make the Rust usage at least better.
pub struct GpioToken(());

static GPIO_TOKEN: Unique = Unique::new();

impl GpioToken {
/// Retrieves the gpio token.
///
/// # Safety
/// This is unsafe because lots of code in zephyr operates on the gpio drivers. The user of the
/// gpio subsystem, in general should either coordinate all gpio access across the system (the
/// token coordinates this only within Rust code), or verify that the particular gpio driver and
/// methods are thread safe.
pub unsafe fn get_instance() -> Option<GpioToken> {
if !GPIO_TOKEN.once() {
return None;
}
Some(GpioToken(()))
}
}

/// A single instance of a zephyr device to manage a gpio controller. A gpio controller
/// represents a set of gpio pins, that are generally operated on by the same hardware block.
pub struct Gpio {
Expand Down Expand Up @@ -312,9 +274,7 @@ impl Gpio {

/// A GpioPin represents a single pin on a gpio device.
///
/// This is a lightweight wrapper around the Zephyr `gpio_dt_spec` structure. Note that
/// multiple pins may share a gpio controller, and as such, all methods on this are both unsafe,
/// and require a mutable reference to the [`GpioToken`].
/// This is a lightweight wrapper around the Zephyr `gpio_dt_spec` structure.
#[allow(dead_code)]
pub struct GpioPin {
pub(crate) pin: raw::gpio_dt_spec,
Expand Down Expand Up @@ -366,10 +326,8 @@ impl GpioPin {
///
/// # Safety
///
/// The `_token` enforces single threaded use of gpios from Rust code. However, many drivers
/// within Zephyr use GPIOs, and to use gpios safely, the caller must ensure that there is
/// either not simultaneous use, or the gpio driver in question is thread safe.
pub unsafe fn configure(&mut self, _token: &mut GpioToken, extra_flags: raw::gpio_flags_t) {
/// Concurrency safety is determined by the underlying driver.
pub fn configure(&mut self, extra_flags: raw::gpio_flags_t) {
// TODO: Error?
unsafe {
raw::gpio_pin_configure(
Expand All @@ -384,27 +342,29 @@ impl GpioPin {
///
/// # Safety
///
/// The `_token` enforces single threaded use of gpios from Rust code. However, many drivers
/// within Zephyr use GPIOs, and to use gpios safely, the caller must ensure that there is
/// either not simultaneous use, or the gpio driver in question is thread safe.
pub unsafe fn toggle_pin(&mut self, _token: &mut GpioToken) {
/// Concurrency safety is determined by the underlying driver.
pub fn toggle_pin(&mut self) {
// TODO: Error?
unsafe {
raw::gpio_pin_toggle_dt(&self.pin);
}
}

/// Set the logical level of the pin.
pub unsafe fn set(&mut self, _token: &mut GpioToken, value: bool) {
raw::gpio_pin_set_dt(&self.pin, value as c_int);
pub fn set(&mut self, value: bool) {
unsafe {
raw::gpio_pin_set_dt(&self.pin, value as c_int);
}
}

/// Read the logical level of the pin.
pub unsafe fn get(&mut self, _token: &mut GpioToken) -> bool {
match raw::gpio_pin_get_dt(&self.pin) {
0 => false,
1 => true,
_ => panic!("TODO: Handle gpio get error"),
pub fn get(&mut self) -> bool {
unsafe {
match raw::gpio_pin_get_dt(&self.pin) {
0 => false,
1 => true,
_ => panic!("TODO: Handle gpio get error"),
}
}
}
}