Created
November 30, 2021 16:31
-
-
Save bobmcwhirter/cf159e8bc4058fe271f09f19880f65b4 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#![no_std] | |
#![feature(generic_associated_types)] | |
#![feature(type_alias_impl_trait)] | |
use core::future::Future; | |
use core::marker::PhantomData; | |
use core::pin::Pin; | |
use core::task::{Context, Poll}; | |
use drogue_device::actors::button::{ButtonEvent, ButtonEventDispatcher, FromButtonEvent}; | |
use drogue_device::actors::led::LedMessage; | |
use drogue_device::kernel::actor::InboxMessage; | |
use drogue_device::ActorContext; | |
use drogue_device::{actors, Actor, Address, Inbox}; | |
use drogue_device::{traits, DeviceContext}; | |
use embassy::executor::Spawner; | |
use embassy::util::Forever; | |
unsafe fn forever<T>(t: &mut T) -> &'static T { | |
let p = t as *mut T; | |
&mut *p | |
} | |
// framework trait | |
pub trait Board {} | |
pub async fn boot<A: App<B, D> + 'static, B: Board, D: 'static>(ctx: &'static DeviceContext<D>, mut board: B, spawner: Spawner) { | |
let device = A::main(&mut board); | |
ctx.configure(device); | |
ctx.mount(|device| async move { | |
A::mount(device, spawner).await | |
}).await; | |
defmt::info!("howdy"); | |
} | |
// framework trait | |
pub trait App<B: Board, D: 'static> : Actor { | |
fn main(board: &mut B) -> D; | |
#[rustfmt::skip] | |
type MountFuture<'m>: Future<Output = () > | |
where | |
Self: 'm; | |
fn mount<'m>(device: &'static D, spawner: Spawner) -> Self::MountFuture<'m>; | |
} | |
// BSP impl | |
pub struct BlinkyComponents<B: BlinkyBoard> { | |
pub red_led: B::RedLed, | |
pub control_button: B::ControlButton, | |
} | |
pub trait BlinkyBoard: Board + Sized { | |
type RedLed: traits::led::Led; | |
type ControlButton: traits::button::Button; | |
fn components(&mut self) -> BlinkyComponents<Self>; | |
} | |
pub struct BlinkyApp<B: BlinkyBoard + 'static> { | |
red_led: Option<Address<'static, actors::led::Led<B::RedLed>>>, | |
_marker: PhantomData<B>, | |
} | |
impl<B: BlinkyBoard + 'static> BlinkyApp<B> { | |
pub fn new() -> Self { | |
Self { | |
red_led: None, | |
_marker: Default::default() | |
} | |
} | |
} | |
impl<B: BlinkyBoard + 'static> App<B, BlinkyDevice<B>> for BlinkyApp<B> { | |
fn main(board: &mut B) -> BlinkyDevice<B> { | |
let mut components = board.components(); | |
BlinkyDevice { | |
app: ActorContext::new( Self::new()), | |
led: ActorContext::new(actors::led::Led::new(components.red_led)), | |
button: ActorContext::new(actors::button::Button::new(components.control_button)), | |
_marker: Default::default(), | |
} | |
} | |
#[rustfmt::skip] | |
type MountFuture<'m> | |
where | |
Self: 'm = impl Future<Output=()>; | |
fn mount<'m>(device: &'static BlinkyDevice<B>, spawner: Spawner) -> Self::MountFuture<'m> { | |
async move { | |
let led = device.led.mount((), spawner); | |
let app = device.app.mount( (led), spawner); | |
device.button.mount(app.into(), spawner); | |
} | |
} | |
} | |
// Device | |
pub enum Command { | |
TurnOn, | |
TurnOff, | |
} | |
impl<B: BlinkyBoard + 'static> Actor for BlinkyApp<B> { | |
type Configuration = (Address<'static, actors::led::Led<B::RedLed>>); | |
type Message<'m> = Command; | |
type OnMountFuture<'m, M> | |
where | |
M: 'm, | |
= impl Future<Output = ()> + 'm; | |
fn on_mount<'m, M>( | |
&'m mut self, | |
config: Self::Configuration, | |
_: Address<'static, Self>, | |
inbox: &'m mut M, | |
) -> Self::OnMountFuture<'m, M> | |
where | |
M: Inbox<'m, Self> + 'm, | |
{ | |
self.red_led.replace(config); | |
async move { | |
defmt::info!("about to app loop"); | |
loop { | |
match inbox.next().await { | |
Some(mut msg) => match msg.message() { | |
Command::TurnOn => { | |
defmt::info!("got inbox ON"); | |
self.red_led.unwrap().notify(LedMessage::On); | |
} | |
Command::TurnOff => { | |
defmt::info!("got inbox OFF"); | |
self.red_led.unwrap().notify(LedMessage::Off); | |
} | |
}, | |
None => { | |
defmt::info!("got inbox NONE"); | |
} | |
} | |
} | |
} | |
} | |
} | |
impl<B: BlinkyBoard> FromButtonEvent<Command> for BlinkyApp<B> { | |
fn from(event: ButtonEvent) -> Option<Command> | |
where | |
Self: Sized, | |
{ | |
match event { | |
ButtonEvent::Pressed => Some(Command::TurnOn), | |
ButtonEvent::Released => Some(Command::TurnOff), | |
} | |
} | |
} | |
//static DEVICE: DeviceContext<BlinkyDevice> = DeviceContext::new(); | |
pub struct BlinkyDevice<B: BlinkyBoard + 'static> { | |
app: ActorContext<'static, BlinkyApp<B>>, | |
led: ActorContext<'static, actors::led::Led<B::RedLed>>, | |
button: ActorContext< | |
'static, | |
actors::button::Button<B::ControlButton, ButtonEventDispatcher<BlinkyApp<B>>>, | |
>, | |
_marker: PhantomData<B>, | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment