Skip to content

Commit

Permalink
First cut at one-shot event handlers.
Browse files Browse the repository at this point in the history
This is potentially pretty inefficient. It mallocs up storage for the
EventHandler, and frees is again after it fires. It also uses addHandler
and removeHandler which are both O(n). In practice, this may all be good
enough.
  • Loading branch information
notahat committed Jul 3, 2009
1 parent 1dad083 commit 868b65f
Show file tree
Hide file tree
Showing 6 changed files with 57 additions and 20 deletions.
35 changes: 28 additions & 7 deletions AikoEvents.cpp
Expand Up @@ -3,6 +3,8 @@
#include <stdlib.h>
#include <wiring.h>

#include <iostream>

namespace Aiko {

/* EventHanderList */
Expand Down Expand Up @@ -49,7 +51,7 @@ namespace Aiko {
}

void EventHandlerList::resetIterator() {
nextHandler_ = firstHandler_;
nextHandler_ = firstHandler_;
}


Expand All @@ -61,19 +63,38 @@ namespace Aiko {
handlerList_.add(handler);
}

void EventManager::addHandler(void (*handlerFunction)(), unsigned int interval) {
void EventManager::addHandler(void (*handlerFunction)(), unsigned int period, unsigned int delay) {
EventHandler* handler = static_cast<EventHandler*>(malloc(sizeof(EventHandler)));
handler->interval_ = interval;
handler->handler_ = handlerFunction;
handler->counter_ = 0;
handler->handler_ = handlerFunction;
handler->period_ = period;
handler->countdown_ = delay;
addHandler(handler);
}

void EventManager::addOneShotHandler(void (*handlerFunction)(), unsigned int delay) {
addHandler(handlerFunction, 0, delay);
}

void EventManager::loop(unsigned long time) {
if (!isRunning_) start(time);
unsigned long elapsed = time - lastLoopTime_;
long elapsed = time - lastLoopTime_;

handlerList_.resetIterator();
while (EventHandler* handler = handlerList_.next()) handler->countdown_ -= elapsed;

handlerList_.resetIterator();
while (EventHandler* handler = handlerList_.next()) handler->loop(elapsed);
while (EventHandler* handler = handlerList_.next()) {
if (handler->countdown_ <= 0) {
handler->fire();
if (handler->period_ > 0)
handler->countdown_ += handler->period_;
else {
removeHandler(handler);
free(handler);
}
}
}

lastLoopTime_ = time;
}

Expand Down
19 changes: 8 additions & 11 deletions AikoEvents.h
Expand Up @@ -8,18 +8,12 @@ using namespace std;
namespace Aiko {

struct EventHandler {
void loop(unsigned int elapsed) {
if (counter_ <= elapsed) {
counter_ += interval_;
(*handler_)();
}
counter_ -= elapsed;
}

unsigned int interval_;
void (*handler_)();
unsigned int counter_;
unsigned int period_;
long countdown_;
struct EventHandler* next_;

void fire() { (*handler_)(); }
};

class EventHandlerList {
Expand All @@ -43,13 +37,16 @@ namespace Aiko {
public:
EventManager() { reset(); }
void addHandler(EventHandler* handler);
void addHandler(void (*handler)(), unsigned int interval);
void addHandler(void (*handler)(), unsigned int interval, unsigned int delay = 0);
void addOneShotHandler(void (*handler)(), unsigned int delay);
void loop(unsigned long time = Timing.millis());
void removeHandler(EventHandler* handler);
void reset();

private:
void start(unsigned long time);
void loopRepeatingHandler(EventHandler* handler);
void loopOneShotHandler(EventHandler* handler);

bool isRunning_;
unsigned long lastLoopTime_;
Expand Down
1 change: 1 addition & 0 deletions AikoSExpression.cpp
Expand Up @@ -4,6 +4,7 @@
namespace Aiko {

char* SExpression::scan(char* head, char* tail, SExpression* expression) {
if (expression) expression->head_ = expression->tail_ = 0;
char* s = skipWhitespace(head, tail);
if (s < tail) {
switch(*s) {
Expand Down
8 changes: 8 additions & 0 deletions docs/Events.markdown
Expand Up @@ -34,6 +34,14 @@ will be called after readTemperature() but before logData(). This
ensures the execution order of functions is always predictable.


### Events.addOneShotHandler

Adds a handler that will be called once after a specified delay (in
milliseconds). For example, to invoke myFunction in 1 second, call:

Events.addOneShotHandler(myFunction, 1000):


### Events.loop

To cause event handlers specified using addHandler to be executed the
Expand Down
10 changes: 10 additions & 0 deletions tests/EventManagerTest.h
Expand Up @@ -24,4 +24,14 @@ class EventManagerTests : public CxxTest::TestSuite {
}
}

void test_should_call_a_one_shot_handler_just_once() {
Events.addOneShotHandler(testHandler, 1000);
Events.loop(0);
TS_ASSERT_EQUALS(handlerCallCount, 0);
Events.loop(1000);
TS_ASSERT_EQUALS(handlerCallCount, 1);
Events.loop(2000);
TS_ASSERT_EQUALS(handlerCallCount, 1);
}

};
4 changes: 2 additions & 2 deletions tests/SExpressionTest.h
Expand Up @@ -53,8 +53,8 @@ class SExpressionTests : public CxxTest::TestSuite {

SExpression expression;
char *s = expression.scan(a, b);
TS_ASSERT_EQUALS(expression.head(), (char*)0);
TS_ASSERT_EQUALS(expression.tail(), (char*)0);
TS_ASSERT(expression.head() == (char*)0);
TS_ASSERT(expression.tail() == (char*)0);
TS_ASSERT_EQUALS(s, b);
}

Expand Down

0 comments on commit 868b65f

Please sign in to comment.