-
Notifications
You must be signed in to change notification settings - Fork 0
/
EventManager.h
453 lines (340 loc) · 13.8 KB
/
EventManager.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
/*
* EventManager.h
*
* An event handling system for Arduino.
*
* Author: igormt@alumni.caltech.edu
* Copyright (c) 2013 Igor Mikolic-Torreira
*
* Inspired by and adapted from the
* Arduino Event System library by
* Author: mromani@ottotecnica.com
* Copyright (c) 2010 OTTOTECNICA Italy
*
* This library is free software; you can redistribute it
* and/or modify it under the terms of the GNU Lesser
* General Public License as published by the Free Software
* Foundation; either version 2.1 of the License, or (at
* your option) any later version.
*
* This library is distributed in the hope that it will
* be useful, but WITHOUT ANY WARRANTY; without even the
* implied warranty of MERCHANTABILITY or FITNESS FOR A
* PARTICULAR PURPOSE. See the GNU Lesser General Public
* License for more details.
*
* You should have received a copy of the GNU Lesser
* General Public License along with this library; if not,
* write to the Free Software Foundation, Inc.,
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
*/
#ifndef EventManager_h
#define EventManager_h
#include <Arduino.h>
// Size of the listener list. Adjust as appropriate for your application.
// Requires a total of sizeof(*f())+sizeof(int)+sizeof(boolean) bytes of RAM for each unit of size
#ifndef EVENTMANAGER_LISTENER_LIST_SIZE
#define EVENTMANAGER_LISTENER_LIST_SIZE 8
#endif
// Size of the event two queues. Adjust as appropriate for your application.
// Requires a total of 4 * sizeof(int) bytes of RAM for each unit of size
#ifndef EVENTMANAGER_EVENT_QUEUE_SIZE
#define EVENTMANAGER_EVENT_QUEUE_SIZE 8
#endif
class EventManager
{
public:
// Type for an event listener (a.k.a. callback) function
typedef void ( *EventListener )( int eventCode, int eventParam );
// EventManager recognizes two kinds of events. By default, events are
// are queued as low priority, but these constants can be used to explicitly
// set the priority when queueing events
//
// NOTE high priority events are always handled before any low priority events.
enum EventPriority { kHighPriority, kLowPriority };
// Various pre-defined event type codes. These are completely optional and
// provided for convenience. Any integer value can be used as an event code.
enum EventType
{
// No event occurred; param: none
kEventNone = 200,
// A key was pressed; param: key code
kEventKeyPress,
// A key was released; param: key code
kEventKeyRelease,
// Use this to notify a character; param: the character to be notified
kEventChar,
// Generic time event
// param: a time value (exact meaning is defined by the code inserting this event into the queue)
kEventTime,
// Generic timer events; param: same as EV_TIME
kEventTimer0,
kEventTimer1,
kEventTimer2,
kEventTimer3,
// Analog read (last number = analog channel); param: value read
kEventAnalog0,
kEventAnalog1,
kEventAnalog2,
kEventAnalog3,
kEventAnalog4,
kEventAnalog5,
// Menu events
kEventMenu0,
kEventMenu1,
kEventMenu2,
kEventMenu3,
kEventMenu4,
kEventMenu5,
kEventMenu6,
kEventMenu7,
kEventMenu8,
kEventMenu9,
// Serial event, example: a new char is available
// param: the return value of Serial.read()
kEventSerial,
// LCD screen needs to be refreshed
kEventPaint,
// User events
kEventUser0,
kEventUser1,
kEventUser2,
kEventUser3,
kEventUser4,
kEventUser5,
kEventUser6,
kEventUser7,
kEventUser8,
kEventUser9
};
// Create an event manager
// It always operates in interrupt safe mode, allowing you to queue events from interrupt handlers
EventManager();
// Add a listener
// Returns true if the listener is successfully installed, false otherwise (e.g. the dispatch table is full)
boolean addListener( int eventCode, EventListener listener );
// Remove (event, listener) pair (all occurrences)
// Other listeners with the same function or event code will not be affected
boolean removeListener( int eventCode, EventListener listener );
// Remove all occurrances of a listener
// Removes this listener regardless of the event code; returns number removed
// Useful when one listener handles many different events
int removeListener( EventListener listener );
// Enable or disable a listener
// Return true if the listener was successfully enabled or disabled, false if the listener was not found
boolean enableListener( int eventCode, EventListener listener, boolean enable );
// Returns the current enabled/disabled state of the (eventCode, listener) combo
boolean isListenerEnabled( int eventCode, EventListener listener );
// The default listener is a callback function that is called when an event with no listener is processed
// These functions set, clear, and enable/disable the default listener
boolean setDefaultListener( EventListener listener );
void removeDefaultListener();
void enableDefaultListener( boolean enable );
// Is the ListenerList empty?
boolean isListenerListEmpty();
// Is the ListenerList full?
boolean isListenerListFull();
int numListeners();
// Returns true if no events are in the queue
boolean isEventQueueEmpty( EventPriority pri = kLowPriority );
// Returns true if no more events can be inserted into the queue
boolean isEventQueueFull( EventPriority pri = kLowPriority );
// Actual number of events in queue
int getNumEventsInQueue( EventPriority pri = kLowPriority );
// tries to insert an event into the queue;
// returns true if successful, false if the
// queue if full and the event cannot be inserted
boolean queueEvent( int eventCode, int eventParam, EventPriority pri = kLowPriority );
// this must be called regularly (usually by calling it inside the loop() function)
int processEvent();
// this function can be called to process ALL events in the queue
// WARNING: if interrupts are adding events as fast as they are being processed
// this function might never return. YOU HAVE BEEN WARNED.
int processAllEvents();
private:
// EventQueue class used internally by EventManager
class EventQueue
{
public:
// Queue constructor
EventQueue();
// Returns true if no events are in the queue
boolean isEmpty();
// Returns true if no more events can be inserted into the queue
boolean isFull();
// Actual number of events in queue
int getNumEvents();
// Tries to insert an event into the queue;
// Returns true if successful, false if the queue if full and the event cannot be inserted
//
// NOTE: if EventManager is instantiated in interrupt safe mode, this function can be called
// from interrupt handlers. This is the ONLY EventManager function that can be called from
// an interrupt.
boolean queueEvent( int eventCode, int eventParam );
// Tries to extract an event from the queue;
// Returns true if successful, false if the queue is empty (the parameteres are not touched in this case)
boolean popEvent( int* eventCode, int* eventParam );
private:
// Event queue size.
// The maximum number of events the queue can hold is kEventQueueSize
// Increasing this number will consume 2 * sizeof(int) bytes of RAM for each unit.
static const int kEventQueueSize = EVENTMANAGER_EVENT_QUEUE_SIZE;
struct EventElement
{
int code; // each event is represented by an integer code
int param; // each event has a single integer parameter
};
// The event queue
EventElement mEventQueue[ kEventQueueSize ];
// Index of event queue head
int mEventQueueHead;
// Index of event queue tail
int mEventQueueTail;
// Actual number of events in queue
int mNumEvents;
};
// ListenerList class used internally by EventManager
class ListenerList
{
public:
// Create an event manager
ListenerList();
// Add a listener
// Returns true if the listener is successfully installed, false otherwise (e.g. the dispatch table is full)
boolean addListener( int eventCode, EventListener listener );
// Remove event listener pair (all occurrences)
// Other listeners with the same function or eventCode will not be affected
boolean removeListener( int eventCode, EventListener listener );
// Remove all occurrances of a listener
// Removes this listener regardless of the eventCode; returns number removed
int removeListener( EventListener listener );
// Enable or disable a listener
// Return true if the listener was successfully enabled or disabled, false if the listener was not found
boolean enableListener( int eventCode, EventListener listener, boolean enable );
boolean isListenerEnabled( int eventCode, EventListener listener );
// The default listener is a callback function that is called when an event with no listener is processed
boolean setDefaultListener( EventListener listener );
void removeDefaultListener();
void enableDefaultListener( boolean enable );
// Is the ListenerList empty?
boolean isEmpty();
// Is the ListenerList full?
boolean isFull();
// Send an event to the listeners; returns number of listeners that handled the event
int sendEvent( int eventCode, int param );
int numListeners();
private:
// Maximum number of event/callback entries
// Can be changed to save memory or allow more events to be dispatched
static const int kMaxListeners = EVENTMANAGER_LISTENER_LIST_SIZE;
// Actual number of event listeners
int mNumListeners;
// Listener structure and corresponding array
struct ListenerItem
{
EventListener callback; // The listener function
int eventCode; // The event code
boolean enabled; // Each listener can be enabled or disabled
};
ListenerItem mListeners[ kMaxListeners ];
// Callback function to be called for event types which have no listener
EventListener mDefaultCallback;
// Once set, the default callback function can be enabled or disabled
boolean mDefaultCallbackEnabled;
// get the current number of entries in the dispatch table
int getNumEntries();
// returns the array index of the specified listener or -1 if no such event/function couple is found
int searchListeners( int eventCode, EventListener listener);
int searchListeners( EventListener listener );
int searchEventCode( int eventCode );
};
EventQueue mHighPriorityQueue;
EventQueue mLowPriorityQueue;
ListenerList mListeners;
};
//********* INLINES EventManager:: ***********
inline boolean EventManager::addListener( int eventCode, EventListener listener )
{
return mListeners.addListener( eventCode, listener );
}
inline boolean EventManager::removeListener( int eventCode, EventListener listener )
{
return mListeners.removeListener( eventCode, listener );
}
inline int EventManager::removeListener( EventListener listener )
{
return mListeners.removeListener( listener );
}
inline boolean EventManager::enableListener( int eventCode, EventListener listener, boolean enable )
{
return mListeners.enableListener( eventCode, listener, enable );
}
inline boolean EventManager::isListenerEnabled( int eventCode, EventListener listener )
{
return mListeners.isListenerEnabled( eventCode, listener );
}
inline boolean EventManager::setDefaultListener( EventListener listener )
{
return mListeners.setDefaultListener( listener );
}
inline void EventManager::removeDefaultListener()
{
mListeners.removeDefaultListener();
}
inline void EventManager::enableDefaultListener( boolean enable )
{
mListeners.enableDefaultListener( enable );
}
inline boolean EventManager::isListenerListEmpty()
{
return mListeners.isEmpty();
}
inline boolean EventManager::isListenerListFull()
{
return mListeners.isFull();
}
inline boolean EventManager::isEventQueueEmpty( EventPriority pri )
{
return ( pri == kHighPriority ) ? mHighPriorityQueue.isEmpty() : mLowPriorityQueue.isEmpty();
}
inline boolean EventManager::isEventQueueFull( EventPriority pri )
{
return ( pri == kHighPriority ) ? mHighPriorityQueue.isFull() : mLowPriorityQueue.isFull();
}
inline int EventManager::getNumEventsInQueue( EventPriority pri )
{
return ( pri == kHighPriority ) ? mHighPriorityQueue.getNumEvents() : mLowPriorityQueue.getNumEvents();
}
inline boolean EventManager::queueEvent( int eventCode, int eventParam, EventPriority pri )
{
return ( pri == kHighPriority ) ?
mHighPriorityQueue.queueEvent( eventCode, eventParam ) : mLowPriorityQueue.queueEvent( eventCode, eventParam );
}
//********* INLINES EventManager::EventQueue:: ***********
inline boolean EventManager::EventQueue::isEmpty()
{
return ( mNumEvents == 0 );
}
inline boolean EventManager::EventQueue::isFull()
{
return ( mNumEvents == kEventQueueSize );
}
inline int EventManager::EventQueue::getNumEvents()
{
return mNumEvents;
}
//********* INLINES EventManager::ListenerList:: ***********
inline boolean EventManager::ListenerList::isEmpty()
{
return (mNumListeners == 0);
}
inline boolean EventManager::ListenerList::isFull()
{
return (mNumListeners == kMaxListeners);
}
inline int EventManager::ListenerList::getNumEntries()
{
return mNumListeners;
}
#endif