Skip to content

Instantly share code, notes, and snippets.

@kalkyl
Last active April 15, 2024 08:54
Show Gist options
  • Save kalkyl/907236df2b864bc97639c11c626beea9 to your computer and use it in GitHub Desktop.
Save kalkyl/907236df2b864bc97639c11c626beea9 to your computer and use it in GitHub Desktop.
OnDrop handling
#![no_std]
#![no_main]
use core::mem::{self, MaybeUninit};
use defmt::*;
use embassy_executor::Spawner;
use embassy_futures::join::join;
use embassy_futures::select::{select, Either};
use embassy_rp::gpio::{AnyPin, Input, Level, Output, Pull};
use embassy_sync::blocking_mutex::raw::NoopRawMutex;
use embassy_sync::signal::Signal;
use embassy_time::Timer;
use {defmt_rtt as _, panic_probe as _};
enum Animation {
A,
B,
}
pub struct OnDrop<F: FnOnce()> {
f: MaybeUninit<F>,
}
impl<F: FnOnce()> OnDrop<F> {
pub fn new(f: F) -> Self {
Self { f: MaybeUninit::new(f) }
}
pub fn defuse(self) {
mem::forget(self)
}
}
impl<F: FnOnce()> Drop for OnDrop<F> {
fn drop(&mut self) {
unsafe { self.f.as_ptr().read()() }
}
}
#[embassy_executor::main]
async fn main(_spawner: Spawner) {
let p = embassy_rp::init(Default::default());
let mut led = Output::new(AnyPin::from(p.PIN_25), Level::Low);
let mut switch = Input::new(AnyPin::from(p.PIN_16), Pull::Up);
let signal: Signal<NoopRawMutex, Animation> = Signal::new();
let mut animation = match switch.get_level() {
Level::Low => Animation::A,
Level::High => Animation::B,
};
let sw_fut = async {
loop {
let _ = switch.wait_for_any_edge().await;
Timer::after_millis(20).await; // Debounce
signal.signal(match switch.get_level() {
Level::Low => Animation::A,
Level::High => Animation::B,
});
}
};
let anim_fut = async {
loop {
if let Either::First(new_anim) = select(signal.wait(), run_animation(&mut led, &animation)).await {
animation = new_anim;
}
}
};
join(sw_fut, anim_fut).await;
}
async fn run_animation(led: &mut Output<'_>, animation: &Animation) {
match animation {
Animation::A => animation_a(led).await,
Animation::B => animation_b(led).await,
}
}
async fn animation_a(led: &mut Output<'_>) {
loop {
let drop = OnDrop::new(|| info!("Animation A dropped"));
led.set_high();
Timer::after_millis(100).await;
led.set_low();
Timer::after_millis(100).await;
drop.defuse();
}
}
async fn animation_b(led: &mut Output<'_>) {
loop {
let drop = OnDrop::new(|| info!("Animation B dropped"));
led.set_high();
Timer::after_millis(500).await;
led.set_low();
Timer::after_millis(500).await;
drop.defuse();
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment