avr-classes
|
The main components of the event system are Event, EventReceiver, EventDispatcher and QueuedEventDispatcher. Events are basically numbers (event IDs) and don't carry additional parameters. The pure fact that an event occurred is all information that is distributed. This might seem a bit limiting on the first view, but avoids awkward conditions where associated status information might be outdated when an event finally reaches its observer.
Event IDs are assigned by the user. The classes from core will only use event IDs that have been passed for a specific use. The only event ID known by the core classes is INVALID_EVENT_ID to mark events as invalid (e.g. when for a specific use-case an event should not be sent).
EventReceiver is an interface that can be implemented by components that wish to receive events. It contains only a single method, EventReceiver::onEvent.
EventDispatcher also implements EventReceiver, but is designed to handle events by dispatching them to a list of subscribers. Since it implements the same EventReceiver interface as the "normal" receivers, it is possible to substitute a single receiver by a group of receivers on any level. Yes, that means that EventDispatcher instances can be cascaded and you even can build nasty loops.
The QueuedEventDispatcher is an extension of EventDispatcher that doesn't dispatch the events immediately, but puts them into a queue instead. To a call to QueuedEventDispatcher::dispatch the queued events are dispatched to the subscribers. By doing this the QueuedEventDispatcher can be used to decouple calling contexts, e.g. enqueuing events from the ISR context and dispatch them in the interruptible main context. See notes below.
The basic idea of having the same interface is, that components like the NotifyingBufferedUsart expect a pointer to an EventReceiver instance to report to. The user of the class is then free to use either a single receiver, or an EventDispatcher instance as multiplier. It also allows to manipulate the event distribution by adding filtering components into the dispatching chain. For this the classes EventFilter and EventTranslator exist, which can be subclassed to implement specific behavior.
Subscribe or unsubscribe | Dispatching | Result |
---|---|---|
Main context | Main context | OK: no interruption can happen |
Main context | ISR context | OK: dispatching can't be interrupted, list modifications are protected against interrupts |
ISR context | Main context | Problem: dispatching can be interrupted by subscribe/unsubscribe |
ISR context | ISR context | OK: no interruption can happen |