lokey 0.0.1

An extensible keyboard firmware
Documentation
use super::Rp2040;
use crate::external::{self, usb};
use crate::{internal, util::channel::Channel, util::unwrap};
use alloc::boxed::Box;
use core::{future::Future, pin::Pin};
use embassy_executor::Spawner;
use embassy_rp::bind_interrupts;
use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
use once_cell::sync::OnceCell;

impl usb::CreateDriver for Rp2040 {
    fn create_driver<'a>(&'static self) -> impl embassy_usb::driver::Driver<'a> {
        bind_interrupts!(struct Irqs {
            USBCTRL_IRQ => embassy_rp::usb::InterruptHandler<embassy_rp::peripherals::USB>;
        });

        let usbd = unsafe { embassy_rp::peripherals::USB::steal() };

        embassy_rp::usb::Driver::new(usbd, Irqs)
    }
}

static CHANNEL: Channel<CriticalSectionRawMutex, external::Message> = Channel::new();
static ACTIVATION_REQUEST: OnceCell<usb::ActivationRequest> = OnceCell::new();

pub struct ExternalTransport {}

impl external::Transport for ExternalTransport {
    fn send(&self, message: external::Message) {
        CHANNEL.send(message);
    }

    fn wait_for_activation_request(&self) -> Pin<Box<dyn Future<Output = ()> + '_>> {
        Box::pin(async {
            if let Some(activation_request) = ACTIVATION_REQUEST.get() {
                activation_request.wait().await;
            }
        })
    }
}

impl external::TransportConfig<Rp2040> for usb::TransportConfig {
    type Transport = ExternalTransport;

    async fn init(
        self,
        mcu: &'static Rp2040,
        spawner: Spawner,
        _internal_channel: internal::DynChannel,
    ) -> Self::Transport {
        if ACTIVATION_REQUEST.get().is_some() {
            // Channel was already intialized
            return ExternalTransport {};
        }

        let (handler, activation_request) = usb::Handler::new(self, mcu);
        unwrap!(spawner.spawn(task(handler)));
        let _ = ACTIVATION_REQUEST.set(activation_request);
        ExternalTransport {}
    }
}

#[embassy_executor::task]
async fn task(handler: usb::Handler<Rp2040>) {
    handler.run(CHANNEL.receiver()).await
}