AVRToolsPlus
A library wof higher-level tools for AVR ATmega328 and ATmega2560 Microcontrollers
|
Using an event-driven design is a common way to code AVR projects that interact with the environment around them. With EventManager you register functions that "listen" for particular events. When things happen you "post" events to EventManager. You then periodically call an EventManager function which processes events by dispatching them so that he appropriate listeners are called.
EventManger is interrupt safe, so that you can post events from interrupt handlers. The corresponding listeners will be called from outside the interrupt handler in your main thread of execution when you call the EventManager function to process events.
In keeping with the limited resources of an AVR system, EventManager is light-weight. There is no dynamic memory allocation. Event queuing is very fast, so you can be comfortable queuing events from interrupt handlers. To keep the footprint minimal, the event queue and the listener list (also known as the dispatch table) are both small (although you can make them bigger if needed).
EventManager supports both high priority and low priority events, and will process high priority events ahead of any low priority events.
EventManager is implemented as a set of functions contained with the namespace EventManager. Implementing EventManager this was instead of as a class removes the need to create and share an EventManager object across your code. However, it does limit your code to a single EventManager and therefore a single set of event queues.
Using EventManager is straightforward. You include EventManager.h in files that access the EventManager and link against the file EventManager.cpp
. You register listener functions using EventManager::addListener(), you post events using EventManager::queueEvent(), and you process events by calling EventManager::processEvent().
The following sections explain this in more detail.
EventManager events consist of an event code and an event parameter. Both of these are integer values. The event code identifies the type of event. For convenience, EventManager.h provides a set of constants you can use to identify events:
These are purely for your convenience; EventManager only uses the numerical value to match events to listeners, so you are free to use any event codes you wish.
The event parameter is also whatever you want it to be. EventManager simply passes the event parameter to every listener function that is associated with that event code. For example, for a key press event the event parameter could be the corresponding key code. For an analog event it could be the value read from that analog pin or a pin number.
You post events using the EventManager::queueEvent() function, like this:
The EventManager::queueEvent() function is lightweight and interrupt safe, so you can call it from inside an interrupt handler.
By default the event queue holds 8 events, but you can make the event queue any size you want by defining the macro EVENTMANAGER_EVENT_QUEUE_SIZE to whatever value you desire (see Increasing Event Queue Size below).
Listeners are functions of type
You add listeners using the EventManager::addListener() function, like this:
By default the list of listeners holds 8 listeners, but you can make the list any size you want by defining the macro EVENTMANAGER_DISPATCH_TABLE_SIZE to whatever value you desire (see Increasing Listener List Size below).
To process events in the event queue and dispatch them to listeners you call EventManager::processEvent() from a top-level event handling loop:
This call processes one event from the event queue every time it is called. Usually EventManager::processEvent() is called once in the inside of some main event loop so that one event is handled every time through the loop. This is usually more than adequate to keep up with incoming events. Events are normally processed in a first-in, first-out fashion (but see the section on Event Priority below).
The remaining sections provide additional details about Event Manager that allowed more tailor and flexible usage.
EventManager recognizes high and low priority events. You can specify the priority when you queue the event. By default, events are considered low priority. You indicate an event is high priority by passing an additional constant to EventManager::queueEvent(), like so:
The difference between high and low priority events is that EventManager::processEvent() will process a high priority event ahead of any low priority events. In effect, high priority events jump to the front of the queue (multiple high priority events are processed first-in, first-out, but all of them are processed before any low priority events).
EventManager is interrupt safe, so that you can queue events both from within interrupt handlers and also from normal functions without having to worry about queue corruption. This safety is achieved by globally disabling interrupts while certain small snippets of code are executing.
Normally calling EventManager::processEvent() once every time through a top-level event processing loop is more than adequate to service incoming events. However, there may be times when you want to process all the events in the queue. For this purpose you can call EventManager::processAllEvents(). Note that if you call this function at the same time that a series of events are being rapidly added to the queue asynchronously (for example, via interrupt handlers), the EventManager::processAllEvents() function might not return until the series of additions to the event queue stops.
Define the macro EVENTMANAGER_EVENT_QUEUE_SIZE
to whatever size you need at compile time by passing it to the compiler on the command line using something like: -DEVENTMANAGER_EVENT_QUEUE_SIZE=32
The event queue requires 4 * sizeof(int) = 8
bytes for each unit of size. There is a factor of 4 (instead of 2) because internally EventManager maintains two separate queues: a high-priority queue and a low-priority queue.
Define the macro EVENTMANAGER_LISTENER_LIST_SIZE
to whatever size you need at compile time by passing it to the compiler on the command line using something like: : -DEVENTMANAGER_LISTENER_LIST_SIZE=32
The listener list requires sizeof(*f()) + sizeof(int) + sizeof(boolean) = 5
bytes for each unit of size.
There are various functions for managing the listeners:
There are various class functions that provide information about the event queue:
For details on these functions you should review EventManager.h documentation.
EventManager was inspired by the Arduino Event System by mroma of OTTOTECNICA Italy. ni@o ttote cnic a.com