use embassy_sync::blocking_mutex::raw::RawMutex;
use embassy_sync::pubsub::{Error as PubSubError, ImmediatePublisher, Publisher, Subscriber};
use embassy_sync::{channel, watch};
macro_rules! impl_payload_wrapper {
($event:ty, $payload:ty) => {
impl core::ops::Deref for $event {
type Target = $payload;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl From<$event> for $payload {
fn from(event: $event) -> Self {
event.0
}
}
impl From<$payload> for $event {
fn from(payload: $payload) -> Self {
Self(payload)
}
}
};
}
mod action;
mod battery;
mod connection;
#[cfg(feature = "dfu")]
mod dfu;
mod input;
#[cfg(feature = "split")]
mod split;
mod state;
pub use action::ActionEvent;
pub use battery::{BatteryAdcEvent, BatteryStatusEvent, ChargingStateEvent};
pub use connection::{ConnectionStatus, ConnectionStatusChangeEvent, ConnectionType};
#[cfg(feature = "dfu")]
pub use dfu::DfuStatusEvent;
pub use input::{
Axis, AxisEvent, AxisValType, KeyPos, KeyboardEvent, KeyboardEventPos, ModifierEvent, PointingEvent,
PointingProcessorEvent, PointingSetCpiEvent, RotaryEncoderPos,
};
#[cfg(all(feature = "split", feature = "_ble"))]
pub use split::ClearPeerEvent;
#[cfg(feature = "split")]
pub use split::{CentralConnectedEvent, PeripheralBatteryEvent, PeripheralConnectedEvent};
pub use state::{LayerChangeEvent, LedIndicatorEvent, SleepStateEvent, WpmUpdateEvent};
pub trait EventPublisher {
type Event;
fn publish(&self, message: Self::Event);
}
pub trait AsyncEventPublisher {
type Event;
async fn publish_async(&self, message: Self::Event);
}
pub trait EventSubscriber {
type Event;
async fn next_event(&mut self) -> Self::Event;
}
pub trait PublishableEvent: Clone + Send {
type Publisher: EventPublisher<Event = Self>;
const PUBLISH_IS_NOOP: bool;
fn publisher() -> Self::Publisher;
}
pub trait AsyncPublishableEvent: PublishableEvent {
type AsyncPublisher: AsyncEventPublisher<Event = Self>;
fn publisher_async() -> Result<Self::AsyncPublisher, PubSubError>;
}
pub trait SubscribableEvent: Clone + Send {
type Subscriber: EventSubscriber<Event = Self>;
fn subscriber() -> Self::Subscriber;
}
pub trait Event: PublishableEvent + SubscribableEvent {}
impl<T: PublishableEvent + SubscribableEvent> Event for T {}
pub trait AsyncEvent: Event + AsyncPublishableEvent {}
impl<T: Event + AsyncPublishableEvent> AsyncEvent for T {}
impl<'a, M: RawMutex, T: Clone, const CAP: usize, const SUBS: usize, const PUBS: usize> EventPublisher
for ImmediatePublisher<'a, M, T, CAP, SUBS, PUBS>
{
type Event = T;
fn publish(&self, message: T) {
self.publish_immediate(message);
}
}
impl<'a, M: RawMutex, T: Clone, const CAP: usize, const SUBS: usize, const PUBS: usize> AsyncEventPublisher
for Publisher<'a, M, T, CAP, SUBS, PUBS>
{
type Event = T;
async fn publish_async(&self, message: T) {
self.publish(message).await
}
}
impl<'a, M: RawMutex, T: Clone, const CAP: usize, const SUBS: usize, const PUBS: usize> EventSubscriber
for Subscriber<'a, M, T, CAP, SUBS, PUBS>
{
type Event = T;
async fn next_event(&mut self) -> Self::Event {
self.next_message_pure().await
}
}
impl<'a, M: RawMutex, T: Clone, const N: usize> EventPublisher for watch::Sender<'a, M, T, N> {
type Event = T;
fn publish(&self, message: T) {
self.send(message);
}
}
impl<'a, M: RawMutex, T: Clone, const N: usize> EventSubscriber for watch::Receiver<'a, M, T, N> {
type Event = T;
async fn next_event(&mut self) -> Self::Event {
self.changed().await
}
}
impl<'a, M: RawMutex, T: Clone, const N: usize> EventPublisher for channel::Sender<'a, M, T, N> {
type Event = T;
fn publish(&self, message: T) {
if self.try_send(message).is_err() {
error!("Send event to Channel error, channel is full");
}
}
}
impl<'a, M: RawMutex, T: Clone, const N: usize> AsyncEventPublisher for channel::Sender<'a, M, T, N> {
type Event = T;
async fn publish_async(&self, message: T) {
self.send(message).await
}
}
impl<'a, M: RawMutex, T: Clone, const N: usize> EventSubscriber for channel::Receiver<'a, M, T, N> {
type Event = T;
async fn next_event(&mut self) -> Self::Event {
self.receive().await
}
}
pub fn publish_event<E: PublishableEvent>(e: E) {
if !E::PUBLISH_IS_NOOP {
E::publisher().publish(e);
}
}
pub async fn publish_event_async<E: AsyncPublishableEvent>(e: E) {
if !E::PUBLISH_IS_NOOP {
let publisher = match E::publisher_async() {
Ok(p) => p,
Err(_) => {
warn!("publisher slots exhausted, consider raising [event] pubs in keyboard.toml");
loop {
embassy_time::Timer::after_millis(1).await;
if let Ok(p) = E::publisher_async() {
break p;
}
}
}
};
publisher.publish_async(e).await;
}
}