Skip to content
This repository has been archived by the owner on Jun 19, 2024. It is now read-only.

Commit

Permalink
add: WaitUntilButtonPressed and WaitUntil futures
Browse files Browse the repository at this point in the history
  • Loading branch information
Gavin-Niederman committed Mar 14, 2024
1 parent d1e9972 commit 44f7330
Show file tree
Hide file tree
Showing 4 changed files with 106 additions and 36 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ Before releasing:
- Added support for internal motor PID tuning. Feature gated behind `dangerous_motor_tuning`, as this can cause hardware damage and is not recommended.
- Added various constants for convenience around `Motor` and `Gearset`.
- Added `Controller` API to the `pros::prelude` module. (#108)
- Added a new future to `pros-async` (`WaitUntilFuture`).
- Added `Controller::wait_until_button_pressed` function and its respective future type.

### Fixed

Expand All @@ -52,6 +54,7 @@ Before releasing:
- Status structs containing device bits now use the `bitflags!` crate. (**Breaking Change**) (#66)
- Renamed `InertialSensor::calibrating` to `InertialSensor::calibrating` (**Breaking CHange**) (#66)
- AdiEncoder now returns `Position` rather than just degrees (**Breaking Change**) (#106).
- Refactored `pros-async` with a new futures module.

### Removed

Expand Down
65 changes: 65 additions & 0 deletions packages/pros-async/src/futures.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
//! Commonly used futures designed for the pros-rs async runtime.
use core::{future::Future, task::Poll};

use crate::executor::EXECUTOR;

/// A future that will complete after the given duration.
/// Sleep futures that are closer to completion are prioritized to improve accuracy.
#[derive(Debug)]
pub struct SleepFuture {
target_millis: u32,
}
impl Future for SleepFuture {
type Output = ();

fn poll(
self: core::pin::Pin<&mut Self>,
cx: &mut core::task::Context<'_>,
) -> core::task::Poll<Self::Output> {
if self.target_millis < unsafe { pros_sys::millis() } {
Poll::Ready(())
} else {
EXECUTOR.with(|e| {
e.reactor
.borrow_mut()
.sleepers
.push(cx.waker().clone(), self.target_millis)
});
Poll::Pending
}
}
}

/// Returns a future that will complete after the given duration.
pub fn sleep(duration: core::time::Duration) -> SleepFuture {
SleepFuture {
target_millis: unsafe { pros_sys::millis() + duration.as_millis() as u32 },
}
}

#[derive(Debug)]
/// A future that completes once a predicate returns true.
pub struct WaitUntilFuture<F: Fn() -> bool> {
predicate: F,
}
impl<F: Fn() -> bool> Future for WaitUntilFuture<F> {
type Output = ();

fn poll(
self: core::pin::Pin<&mut Self>,
cx: &mut core::task::Context<'_>,
) -> Poll<Self::Output> {
if (self.predicate)() {
Poll::Ready(())
} else {
cx.waker().wake_by_ref();
Poll::Pending
}
}
}

/// Returns a future that completes once the given predicate returns true.
pub fn wait_until<F: Fn() -> bool>(predicate: F) -> WaitUntilFuture<F> {
WaitUntilFuture { predicate }
}
40 changes: 4 additions & 36 deletions packages/pros-async/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,17 @@

extern crate alloc;

use core::{future::Future, task::Poll};
use core::future::Future;

use async_task::Task;
use executor::EXECUTOR;
use pros_core::error::Result;

mod executor;
pub mod futures;
mod reactor;

pub use futures::*;

/// Runs a future in the background without having to await it
/// To get the the return value you can await a task.
pub fn spawn<T>(future: impl Future<Output = T> + 'static) -> Task<T> {
Expand All @@ -30,40 +32,6 @@ pub fn block_on<F: Future + 'static>(future: F) -> F::Output {
executor::EXECUTOR.with(|e| e.block_on(spawn(future)))
}

/// A future that will complete after the given duration.
/// Sleep futures that are closer to completion are prioritized to improve accuracy.
#[derive(Debug)]
pub struct SleepFuture {
target_millis: u32,
}
impl Future for SleepFuture {
type Output = ();

fn poll(
self: core::pin::Pin<&mut Self>,
cx: &mut core::task::Context<'_>,
) -> core::task::Poll<Self::Output> {
if self.target_millis < unsafe { pros_sys::millis() } {
Poll::Ready(())
} else {
EXECUTOR.with(|e| {
e.reactor
.borrow_mut()
.sleepers
.push(cx.waker().clone(), self.target_millis)
});
Poll::Pending
}
}
}

/// Returns a future that will complete after the given duration.
pub fn sleep(duration: core::time::Duration) -> SleepFuture {
SleepFuture {
target_millis: unsafe { pros_sys::millis() + duration.as_millis() as u32 },
}
}

/// A trait for robot code that spins up the pros-rs async executor.
/// This is the preferred trait to run robot code.
pub trait AsyncRobot {
Expand Down
34 changes: 34 additions & 0 deletions packages/pros-devices/src/controller.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
//! State of a controller can be checked by calling [`Controller::state`] which will return a struct with all of the buttons' and joysticks' state.
use alloc::{ffi::CString, vec::Vec};
use core::future::Future;

use pros_core::{bail_on, map_errno};
use pros_sys::{controller_id_e_t, PROS_ERR};
Expand Down Expand Up @@ -151,6 +152,28 @@ pub enum JoystickAxis {
RightY = pros_sys::E_CONTROLLER_ANALOG_RIGHT_Y,
}

/// A future that completes once the given button is pressed.
pub struct WaitUntilButtonPressedFuture<'a> {
controller: &'a Controller,
button: ControllerButton,
}
impl<'a> Future for WaitUntilButtonPressedFuture<'a> {
type Output = ();

fn poll(
self: core::pin::Pin<&mut Self>,
cx: &mut core::task::Context<'_>,
) -> core::task::Poll<Self::Output> {
let pressed = self.controller.button(self.button).unwrap_or(false);
if pressed {
core::task::Poll::Ready(())
} else {
cx.waker().wake_by_ref();
core::task::Poll::Pending
}
}
}

/// The basic type for a controller.
/// Used to get the state of its joysticks and controllers.
#[repr(u32)]
Expand Down Expand Up @@ -323,6 +346,17 @@ impl Controller {
}) == 1)
}

/// Returns a future that completes once the given button is pressed.
pub fn wait_until_button_pressed<'a>(
&'a self,
button: ControllerButton,
) -> WaitUntilButtonPressedFuture<'a> {
WaitUntilButtonPressedFuture {
controller: self,
button,
}
}

/// Gets the state of a specific joystick axis on the controller.
pub fn joystick_axis(&self, axis: JoystickAxis) -> Result<f32, ControllerError> {
Ok(bail_on!(PROS_ERR, unsafe {
Expand Down

0 comments on commit 44f7330

Please sign in to comment.