| #include <Arduino.h> | #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; | class EventResponder; | ||||
| typedef EventResponder& EventResponderRef; | typedef EventResponder& EventResponderRef; | ||||
| typedef void (*EventResponderFunction)(EventResponderRef); | typedef void (*EventResponderFunction)(EventResponderRef); | ||||
| ~EventResponder() { | ~EventResponder() { | ||||
| detach(); | detach(); | ||||
| } | } | ||||
| enum EventType { | |||||
| enum EventType { // these are not meant for public consumption... | |||||
| EventTypeDetached = 0, // no function is called | EventTypeDetached = 0, // no function is called | ||||
| EventTypeYield, // function is called from yield() | EventTypeYield, // function is called from yield() | ||||
| EventTypeImmediate, // function is called immediately | EventTypeImmediate, // function is called immediately | ||||
| EventTypeInterrupt, // function is called from interrupt | EventTypeInterrupt, // function is called from interrupt | ||||
| EventTypeThread // function is run as a new thread | 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) { | void attach(EventResponderFunction function) { | ||||
| detach(); | detach(); | ||||
| _function = function; | _function = function; | ||||
| _type = EventTypeYield; | _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) { | void attachImmediate(EventResponderFunction function) { | ||||
| detach(); | detach(); | ||||
| _function = function; | _function = function; | ||||
| _type = EventTypeImmediate; | _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) { | void attachInterrupt(EventResponderFunction function) { | ||||
| detach(); | detach(); | ||||
| _function = function; | _function = function; | ||||
| _type = EventTypeInterrupt; | _type = EventTypeInterrupt; | ||||
| // TODO: configure PendSV | // 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) { | void attachThread(EventResponderFunction function, void *param=nullptr) { | ||||
| attach(function); // for non-RTOS usage, compile as default attach | 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(); | 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) { | virtual void triggerEvent(int status=0, void *data=nullptr) { | ||||
| _status = status; | _status = status; | ||||
| _data = data; | _data = data; | ||||
| triggerEventNotImmediate(); | triggerEventNotImmediate(); | ||||
| } | } | ||||
| } | } | ||||
| // Clear an event which has been triggered, but has not yet caused a | |||||
| // function to be called. | |||||
| bool clearEvent(); | 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; } | 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 setContext(void *context) { _context = context; } | ||||
| void * getContext() { return _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); | bool waitForEvent(EventResponderRef event, int timeout); | ||||
| EventResponder * waitForEvent(EventResponder *list, int listsize, int timeout); | EventResponder * waitForEvent(EventResponder *list, int listsize, int timeout); | ||||
| static void runFromYield() { | static void runFromYield() { | ||||
| EventResponder *first = firstYield; | EventResponder *first = firstYield; | ||||
| if (first && !runningFromYield) { | if (first && !runningFromYield) { |