|
|
@@ -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) { |