All Projects → jamesmunns → cassette

jamesmunns / cassette

Licence: MPL-2.0 license
A simple, single-future, non-blocking executor intended for building state machines. Designed to be no-std and embedded friendly.

Programming Languages

rust
11053 projects

Projects that are alternatives of or similar to cassette

gdbstub
An ergonomic and easy-to-integrate implementation of the GDB Remote Serial Protocol in Rust, with full no_std support.
Stars: ✭ 158 (+236.17%)
Mutual labels:  embedded, no-std
pwm-pca9685-rs
Platform-agnostic Rust driver for the PCA9685 I2C 16-channel, 12-bit PWM/Servo/LED controller
Stars: ✭ 19 (-59.57%)
Mutual labels:  embedded, no-std
atat
no_std crate for parsing AT commands
Stars: ✭ 50 (+6.38%)
Mutual labels:  embedded, no-std
Wyhash Rs
wyhash fast portable non-cryptographic hashing algorithm and random number generator in Rust
Stars: ✭ 44 (-6.38%)
Mutual labels:  embedded, no-std
Drone Core
The core crate for Drone, an Embedded Operating System.
Stars: ✭ 263 (+459.57%)
Mutual labels:  embedded, no-std
drone-cortexm
ARM® Cortex®-M platform crate for Drone, an Embedded Operating System.
Stars: ✭ 31 (-34.04%)
Mutual labels:  embedded, no-std
async-stm32f1xx
Abstractions for asynchronous programming on the STM32F1xx family of microcontrollers.
Stars: ✭ 24 (-48.94%)
Mutual labels:  embedded, no-std
littlefs2
Idiomatic Rust API for littlefs
Stars: ✭ 19 (-59.57%)
Mutual labels:  embedded, no-std
Rhai
Rhai - An embedded scripting language for Rust.
Stars: ✭ 958 (+1938.3%)
Mutual labels:  embedded, no-std
Drone
CLI utility for Drone, an Embedded Operating System.
Stars: ✭ 114 (+142.55%)
Mutual labels:  embedded, no-std
zephyr-rtos-tutorial
Zephyr tutorial for beginners
Stars: ✭ 94 (+100%)
Mutual labels:  embedded
cast.rs
Machine scalar casting that meets your expectations
Stars: ✭ 70 (+48.94%)
Mutual labels:  no-std
rauc-hawkbit-updater
The RAUC hawkBit updater is a simple commandline tool/daemon that runs on your target and interfaces between RAUC and hawkBit's DDI API.
Stars: ✭ 40 (-14.89%)
Mutual labels:  embedded
micropython-micropower
Support for building ultra low power systems based on the Pyboard (1.x and D series).
Stars: ✭ 44 (-6.38%)
Mutual labels:  embedded
libe4
C library of Teserakt's E4 end-to-end security protocol
Stars: ✭ 15 (-68.09%)
Mutual labels:  embedded
rebuild
Zero-dependency, reproducible build environments
Stars: ✭ 48 (+2.13%)
Mutual labels:  embedded
Emma
Emma Memory and Mapfile Analyser
Stars: ✭ 21 (-55.32%)
Mutual labels:  embedded
uevloop
A fast and lightweight event loop for embedded platforms.
Stars: ✭ 61 (+29.79%)
Mutual labels:  embedded
FreeRTOS-rust
Rust crate for FreeRTOS
Stars: ✭ 159 (+238.3%)
Mutual labels:  embedded
lv lib split jpg
JPG decoder for LVGL
Stars: ✭ 22 (-53.19%)
Mutual labels:  embedded

Cassette

A simple, single-future, non-blocking executor intended for building state machines. Designed to be no-std and embedded friendly.

This executor TOTALLY IGNORES wakers and context, meaning that all async functions should expect to be polled repeatedly until completion.

Inspiration

So, I'm really not good at async, but I like the idea of being able to use the ability to yield or await on tasks that will require some time to complete.

The idea here is that you would write one, top level async function that would either eventually resolve to some value, or that will run forever (to act as a state machine).

How it works

  1. You write some async functions
  2. You call the "top level" async function
  3. You poll on it until it resolves (or forever)

Note: This demo is available in the demo/ folder of this repo.

Step 1 - You write some async functions

Here's the "context" of our state machine, describing a couple of high level behaviors, as well as individual substeps.

struct Demo {
    lol: u32,
}

impl Demo {
    async fn entry(&mut self) {
        for _ in 0..10 {
            self.entry_1().await;
            self.entry_2().await;
        }
    }

    async fn entry_1(&mut self) {
        self.start_at_zero().await;
        self.add_one_until_ten().await;
        self.sub_one_until_zero().await;
    }

    async fn entry_2(&mut self) {
        self.start_at_five().await;
        self.sub_one_until_zero().await;
        self.add_one_until_ten().await;
    }

    async fn start_at_zero(&mut self) {
        self.lol = 0;
    }

    async fn start_at_five(&mut self) {
        self.lol = 5;
    }

    async fn add_one_until_ten(&mut self) {
        loop {
            delay(self).await; // simulate fake delays/not ready state
            self.lol += 1;
            if self.lol >= 10 {
                return;
            }
        }
    }

    async fn sub_one_until_zero(&mut self) {
        loop {
            delay(self).await; // simulate fake delays/not ready state
            self.lol -= 1;
            if self.lol == 0 {
                return;
            }
        }
    }
}

We can also make simple little futures for code that needs to be polled until ready:

static FAKE: AtomicU32 = AtomicU32::new(0);
struct CountFuture;
impl Future for CountFuture {
    type Output = ();
    fn poll(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<Self::Output> {
        let x = FAKE.fetch_add(1, Ordering::SeqCst);
        print!("{}, ", x);
        if (x % 5) == 0 {
            Poll::Ready(())
        } else {
            Poll::Pending
        }
    }
}

async fn delay(ctxt: &mut Demo) {
    println!("delay says lol: {}", ctxt.lol);
    let x = CountFuture;
    x.await;
    println!("and delay!");
}

Step 2 - You call the "top level" async function

fn main() {
    // Make a new struct
    let mut demo = Demo { lol: 100 };

    // Call the entry point future, and pin it
    let x = demo.entry();
    pin_mut!(x);

    // Give the pinned future to Cassette
    // for execution
    let mut cm = Cassette::new(x);

    /* ... */
}

Step 3 - You poll on it until it resolves (or forever)

fn main() {
    /* ... */

    loop {
        if let Some(x) = cm.poll_on() {
            println!("Done!: `{:?}`", x);
            break;
        }
    }
}

A larger demo

If you'd like to see a larger demo, I used Cassette to implement an I2C peripheral bootloader state machine for a thumbv6m target. You can check out that PR for more context.

License

This crate is licensed under the MPL v2.0.

The futures module includes code licensed under the MIT+Apache2.0 dual licenses from the futures-rs crate. Please see the upstream repository at https://github.com/rust-lang/futures-rs, and details of the license here: https://github.com/rust-lang/futures-rs#license

Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].