Skip to content

Instantly share code, notes, and snippets.

@bobmcwhirter
Created November 30, 2021 16:31
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save bobmcwhirter/cf159e8bc4058fe271f09f19880f65b4 to your computer and use it in GitHub Desktop.
Save bobmcwhirter/cf159e8bc4058fe271f09f19880f65b4 to your computer and use it in GitHub Desktop.
#![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