use avr_oxide::private::ringq::{Coalesce, QueueError};
use avr_oxide::devices::button::ButtonState;
use avr_oxide::devices::serialport::SerialState;
use avr_oxide::hal::generic::timer::TimerIdentity;
use avr_oxide::hal::generic::port::PinIdentity;
use avr_oxide::hal::generic::serial::SerialPortIdentity;
use ufmt::derive::uDebug;
use avr_oxide::concurrency::Isolated;
use oxide_macros::Persist;
use avr_oxide::OxideResult;
use avr_oxide::OxideResult::{Ok,Err};
#[derive(Clone,Copy,PartialEq,Eq,uDebug,Persist)]
pub enum OxideEvent {
Initialise,
ClockTick(TimerIdentity, u16),
ButtonEvent(PinIdentity, ButtonState),
SerialEvent(SerialPortIdentity, SerialState)
}
#[derive(Clone,Copy)]
pub struct OxideEventEnvelope<'e> {
receiver: Option<&'e dyn EventSource>,
event: OxideEvent
}
pub trait EventSource {
fn listen(&'static self);
fn process_event(&self, evt: OxideEvent);
}
pub trait EventSink {
fn event(isotoken: Isolated, event: OxideEventEnvelope);
}
pub struct EventDevNull {
}
impl<'e> OxideEventEnvelope<'e> {
pub fn to(receiver: &'e dyn EventSource, event: OxideEvent) -> Self {
OxideEventEnvelope {
receiver: Some(receiver),
event
}
}
pub fn anon(event: OxideEvent) -> Self {
OxideEventEnvelope {
receiver: None,
event
}
}
pub fn open_event(&self) -> OxideEvent {
self.event
}
pub(crate) fn invoke_recipient(&self) {
match self.receiver {
Some(ev_src) => {
ev_src.process_event(self.event);
},
None => {}
}
}
}
impl Coalesce for OxideEvent {
fn coalesced(&self, with: &Self) -> OxideResult<Self, QueueError> {
match self {
OxideEvent::ClockTick(source1, myticks) => {
match with {
OxideEvent::ClockTick(source2, ticks) => {
if (source1 == source2) && (u16::MAX - *myticks) > *ticks {
Ok(OxideEvent::ClockTick(*source1,*myticks + *ticks))
} else {
Err(QueueError::CannotCoalesce)
}
},
_ => Err(QueueError::CannotCoalesce)
}
},
OxideEvent::SerialEvent(source1, state) => {
match with {
OxideEvent::SerialEvent(source2, with_state) => {
if (source1 == source2) && (state == with_state) {
Ok(self.clone())
} else {
Err(QueueError::CannotCoalesce)
}
},
_ => Err(QueueError::CannotCoalesce)
}
},
_ => Err(QueueError::CannotCoalesce)
}
}
}
impl Coalesce for OxideEventEnvelope<'_> {
fn coalesced(&self, with: &Self) -> OxideResult<Self, QueueError> {
match (self.receiver, with.receiver) {
(Some(my_receiver),Some(with_receiver)) => {
if my_receiver as *const _ == with_receiver as *const _ {
match self.event.coalesced(&with.event) {
Ok(coalesced_event) => {
Ok(OxideEventEnvelope {
receiver: self.receiver,
event: coalesced_event
})
},
Err(_) => {
Err(QueueError::CannotCoalesce)
}
}
} else {
Err(QueueError::CannotCoalesce)
}
}
_=> Err(QueueError::CannotCoalesce)
}
}
}
impl EventSink for EventDevNull {
fn event(_isotoken: Isolated, _event: OxideEventEnvelope) {
}
}
#[cfg(test)]
mod tests {
use avr_oxide::event::{EventSource, OxideEvent, OxideEventEnvelope};
use avr_oxide::private::ringq::Coalesce;
use avr_oxide::event::OxideEvent::{ButtonEvent, ClockTick, SerialEvent};
use avr_oxide::devices::serialport::SerialState;
use avr_oxide::devices::button::ButtonState;
use avr_oxide::hal::generic::timer::TimerIdentity;
use avr_oxide::hal::generic::serial::SerialPortIdentity;
use avr_oxide::hal::generic::port::PinIdentity;
struct DummyEventSource {
}
impl EventSource for DummyEventSource {
fn listen(&'static self) {
unimplemented!()
}
fn process_event(&self, evt: OxideEvent) {
unimplemented!()
}
}
#[test]
fn test_event_coalesce_masterclockevent() {
static DES : DummyEventSource = DummyEventSource {};
let mut event1 = OxideEventEnvelope::to(&DES, ClockTick(TimerIdentity::Tcb0, 12));
let event2 = OxideEventEnvelope::to(&DES, ClockTick(TimerIdentity::Tcb0, 14));
let coalesced = event1.coalesced(&event2).unwrap();
if let ClockTick(TimerIdentity::Tcb0, ticks) = coalesced.open_event() {
println!("Coalesced MasterClockEvent (ticks == {})", ticks);
assert_eq!(ticks, 26);
}
}
#[test]
fn test_event_coalesce_serialevent_ok() {
static DES : DummyEventSource = DummyEventSource {};
let mut event1 = OxideEventEnvelope::to(&DES, SerialEvent(SerialPortIdentity::Usart0, SerialState::ReadAvailable));
let event2 = OxideEventEnvelope::to(&DES, SerialEvent(SerialPortIdentity::Usart0, SerialState::ReadAvailable));
event1.coalesced(&event2).unwrap();
let mut event1 = OxideEventEnvelope::to(&DES, SerialEvent(SerialPortIdentity::Usart0, SerialState::BreakDetected));
let event2 = OxideEventEnvelope::to(&DES, SerialEvent(SerialPortIdentity::Usart0, SerialState::BreakDetected));
event1.coalesced(&event2).unwrap();
}
#[test]
#[should_panic]
fn test_event_coalesce_serialevent_fail() {
static DES : DummyEventSource = DummyEventSource {};
let mut event1 = OxideEventEnvelope::to(&DES, SerialEvent(SerialPortIdentity::Usart0, SerialState::ReadAvailable));
let event2 = OxideEventEnvelope::to(&DES, SerialEvent(SerialPortIdentity::Usart0, SerialState::BreakDetected));
event1.coalesced(&event2).unwrap();
}
#[test]
#[should_panic]
fn test_event_coalesce_fail() {
static DES : DummyEventSource = DummyEventSource {};
let mut event1 = OxideEventEnvelope::to(&DES, ClockTick(TimerIdentity::Tcb0, 42));
let event2 = OxideEventEnvelope::to(&DES, ButtonEvent(PinIdentity::PortA(0),ButtonState::Pressed));
event1.coalesced(&event2).unwrap();
}
}