| @@ -36,6 +36,19 @@ | |||
| #include <Arduino.h> | |||
| /* EventResponder lets you control how your program responds to an event. | |||
| * Imagine a basketball or football (American soccer) player who gets the | |||
| * ball. Usually they will pass to another player who has the best | |||
| * opportunity to score. Similarly in Arduino programming, events are | |||
| * often triggered within interrupts or other timing sensitive code. | |||
| * EventResponder can call your function a short time later, giving you | |||
| * the ability to use Arduino functions and libraries which would not | |||
| * be safe to use from an interrupt. However, some situations do call | |||
| * for the most immediate response, even if doing so is more difficult. | |||
| * EventResponder lets you choose how your function will be called, | |||
| * without editing the timers or libraries which trigger the events. | |||
| */ | |||
| class EventResponder; | |||
| typedef EventResponder& EventResponderRef; | |||
| typedef void (*EventResponderFunction)(EventResponderRef); | |||
| @@ -47,33 +60,57 @@ public: | |||
| ~EventResponder() { | |||
| detach(); | |||
| } | |||
| enum EventType { | |||
| enum EventType { // these are not meant for public consumption... | |||
| EventTypeDetached = 0, // no function is called | |||
| EventTypeYield, // function is called from yield() | |||
| EventTypeImmediate, // function is called immediately | |||
| EventTypeInterrupt, // function is called from interrupt | |||
| EventTypeThread // function is run as a new thread | |||
| }; | |||
| // Attach a function to be called from yield(). This should be the | |||
| // default way to use EventResponder. Calls from yield() allow use | |||
| // of Arduino libraries, String, Serial, etc. | |||
| void attach(EventResponderFunction function) { | |||
| detach(); | |||
| _function = function; | |||
| _type = EventTypeYield; | |||
| } | |||
| // Attach a function to be called immediately. This provides the | |||
| // fastest possible response, but your function must be carefully | |||
| // designed. | |||
| void attachImmediate(EventResponderFunction function) { | |||
| detach(); | |||
| _function = function; | |||
| _type = EventTypeImmediate; | |||
| } | |||
| // Attach a function to be called from a low priority interrupt. | |||
| // Boards not supporting software triggered interrupts will implement | |||
| // this as attachImmediate. On ARM and other platforms with software | |||
| // interrupts, this allow fast interrupt-based response, but with less | |||
| // disruption to other libraries requiring their own interrupts. | |||
| void attachInterrupt(EventResponderFunction function) { | |||
| detach(); | |||
| _function = function; | |||
| _type = EventTypeInterrupt; | |||
| // TODO: configure PendSV | |||
| } | |||
| // Attach a function to be called as its own thread. Boards not running | |||
| // a RTOS or pre-emptive scheduler shall implement this as attach(). | |||
| void attachThread(EventResponderFunction function, void *param=nullptr) { | |||
| attach(function); // for non-RTOS usage, compile as default attach | |||
| } | |||
| // Do not call any function. The user's program must occasionally check | |||
| // whether the event has occurred, or use one of the wait functions. | |||
| void detach(); | |||
| // Trigger the event. An optional status code and data may be provided. | |||
| // The code triggering the event does NOT control which of the above | |||
| // response methods will be used. | |||
| virtual void triggerEvent(int status=0, void *data=nullptr) { | |||
| _status = status; | |||
| _data = data; | |||
| @@ -83,13 +120,34 @@ public: | |||
| triggerEventNotImmediate(); | |||
| } | |||
| } | |||
| // Clear an event which has been triggered, but has not yet caused a | |||
| // function to be called. | |||
| bool clearEvent(); | |||
| // Get the event's status code. Typically this will indicate if the event was | |||
| // triggered due to successful completion, or how much data was successfully | |||
| // processed (positive numbers) or an error (negative numbers). The | |||
| // exact meaning of this status code depends on the code or library which | |||
| // triggers the event. | |||
| int getStatus() { return _status; } | |||
| // Get the optional data pointer associated with the event. Often this | |||
| // will be NULL, or will be the object instance which triggered the event. | |||
| // Some libraries may use this to pass data associated with the event. | |||
| void * getData() { return _data; } | |||
| // An optional "context" may be associated with each EventResponder. | |||
| // When more than one EventResponder has the same function attached, these | |||
| // may be used to allow the function to obtain extra information needed | |||
| // depending on which EventResponder called it. | |||
| void setContext(void *context) { _context = context; } | |||
| void * getContext() { return _context; } | |||
| void * getData() { return _data; } | |||
| // Wait for event(s) to occur. These are most likely to be useful when | |||
| // used with a scheduler or RTOS. | |||
| bool waitForEvent(EventResponderRef event, int timeout); | |||
| EventResponder * waitForEvent(EventResponder *list, int listsize, int timeout); | |||
| static void runFromYield() { | |||
| EventResponder *first = firstYield; | |||
| if (first && !runningFromYield) { | |||