|
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299 |
- /* EventResponder - Simple event-based programming for Arduino
- * Copyright 2017 Paul Stoffregen
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files (the
- * "Software"), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sublicense, and/or sell copies of the Software, and to
- * permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice shall be
- * included in all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
- /* EventResponder is an experimental API, almost certain to
- * incompatibly change as it develops. Please understand any
- * programs you write now using EventResponder may need to be
- * updated as EventResponder develops.
- *
- * Please post EventResponder post your feedback here:
- * https://forum.pjrc.com/threads/44723-Arduino-Events
- */
-
- #include "EventResponder.h"
-
- EventResponder * EventResponder::firstYield = nullptr;
- EventResponder * EventResponder::lastYield = nullptr;
- EventResponder * EventResponder::firstInterrupt = nullptr;
- EventResponder * EventResponder::lastInterrupt = nullptr;
- bool EventResponder::runningFromYield = false;
-
- // TODO: interrupt disable/enable needed in many places!!!
-
- void EventResponder::triggerEventNotImmediate()
- {
- bool irq = disableInterrupts();
- if (_triggered == false) {
- // not already triggered
- if (_type == EventTypeYield) {
- // normal type, called from yield()
- if (firstYield == nullptr) {
- _next = nullptr;
- _prev = nullptr;
- firstYield = this;
- lastYield = this;
- } else {
- _next = nullptr;
- _prev = lastYield;
- _prev->_next = this;
- lastYield = this;
- }
- } else if (_type == EventTypeInterrupt) {
- // interrupt, called from software interrupt
- if (firstInterrupt == nullptr) {
- _next = nullptr;
- _prev = nullptr;
- firstInterrupt = this;
- lastInterrupt = this;
- } else {
- _next = nullptr;
- _prev = lastInterrupt;
- _prev->_next = this;
- lastInterrupt = this;
- }
- SCB_ICSR = SCB_ICSR_PENDSVSET; // set PendSV interrupt
- } else {
- // detached, easy :-)
- }
- _triggered = true;
- }
- enableInterrupts(irq);
- }
-
- void pendablesrvreq_isr(void)
- {
- EventResponder::runFromInterrupt();
- }
-
- void EventResponder::runFromInterrupt()
- {
- while (1) {
- bool irq = disableInterrupts();
- EventResponder *first = firstInterrupt;
- if (first) {
- firstInterrupt = first->_next;
- if (firstInterrupt) {
- firstInterrupt->_prev = nullptr;
- } else {
- lastInterrupt = nullptr;
- }
- enableInterrupts(irq);
- first->_triggered = false;
- (*(first->_function))(*first);
- } else {
- enableInterrupts(irq);
- break;
- }
- }
- }
-
- bool EventResponder::clearEvent()
- {
- bool ret = false;
- bool irq = disableInterrupts();
- if (_triggered) {
- if (_type == EventTypeYield) {
- if (_prev) {
- _prev->_next = _next;
- } else {
- firstYield = _next;
- }
- if (_next) {
- _next->_prev = _prev;
- } else {
- lastYield = _prev;
- }
- } else if (_type == EventTypeInterrupt) {
- if (_prev) {
- _prev->_next = _next;
- } else {
- firstInterrupt = _next;
- }
- if (_next) {
- _next->_prev = _prev;
- } else {
- lastInterrupt = _prev;
- }
- }
- _triggered = false;
- ret = true;
- }
- enableInterrupts(irq);
- return ret;
- }
-
- void EventResponder::detach()
- {
- bool irq = disableInterrupts();
- if (_type == EventTypeYield) {
- if (_triggered) {
- if (_prev) {
- _prev->_next = _next;
- } else {
- firstYield = _next;
- }
- if (_next) {
- _next->_prev = _prev;
- } else {
- lastYield = _prev;
- }
- }
- _type = EventTypeDetached;
- } else if (_type == EventTypeInterrupt) {
- if (_triggered) {
- if (_prev) {
- _prev->_next = _next;
- } else {
- firstInterrupt = _next;
- }
- if (_next) {
- _next->_prev = _prev;
- } else {
- lastInterrupt = _prev;
- }
- }
- _type = EventTypeDetached;
- }
- enableInterrupts(irq);
- }
-
-
- //-------------------------------------------------------------
-
-
- MillisTimer * MillisTimer::list = nullptr;
-
- void MillisTimer::begin(unsigned long milliseconds, EventResponderRef event)
- {
- end();
- if (!milliseconds) return;
- _event = &event;
- _ms = milliseconds;
- _reload = 0;
- addToList();
- }
-
- void MillisTimer::beginRepeating(unsigned long milliseconds, EventResponderRef event)
- {
- end();
- if (!milliseconds) return;
- _event = &event;
- _ms = milliseconds;
- _reload = milliseconds;
- addToList();
- }
-
- void MillisTimer::addToList()
- {
- bool irq = disableTimerInterrupt();
- if (list == nullptr) {
- // list is empty, easy case
- _next = nullptr;
- _prev = nullptr;
- list = this;
- } else if (_ms < list->_ms) {
- // this timer triggers before any on the list
- _next = list;
- _prev = nullptr;
- list->_prev = this;
- list = this;
- } else {
- // add this timer somewhere after the first already on the list
- MillisTimer *timer = list;
- while (timer->_next) {
- _ms -= timer->_ms;
- timer = timer->_next;
- if (_ms < timer->_ms) {
- // found the right place in the middle of list
- _next = timer;
- _prev = timer->_prev;
- timer->_prev = this;
- _prev->_next = this;
- isQueued = true;
- enableTimerInterrupt(irq);
- return;
- }
- }
- // add this time at the end of the list
- _ms -= timer->_ms;
- _next = nullptr;
- _prev = timer;
- timer->_next = this;
- }
- isQueued = true;
- enableTimerInterrupt(irq);
- }
-
- void MillisTimer::end()
- {
- bool irq = disableTimerInterrupt();
- if (isQueued) {
- if (_next) {
- _next->_prev = _prev;
- }
- if (_prev) {
- _prev->_next = _next;
- } else {
- list = _next;
- }
- isQueued = false;
- }
- enableTimerInterrupt(irq);
- }
-
- void MillisTimer::runFromTimer()
- {
- bool irq = disableTimerInterrupt();
- MillisTimer *timer = list;
- while (timer) {
- if (timer->_ms > 0) {
- timer->_ms--;
- break;
- } else {
- MillisTimer *next = timer->_next;
- if (next) next->_prev = nullptr;
- list = next;
- enableTimerInterrupt(irq);
- timer->isQueued = false;
- EventResponderRef event = *(timer->_event);
- event.triggerEvent(0, timer);
- if (timer->_reload) {
- timer->_ms = timer->_reload;
- timer->addToList();
- }
- irq = disableTimerInterrupt();
- timer = list;
- }
- }
- enableTimerInterrupt(irq);
- }
-
- extern "C" volatile uint32_t systick_millis_count;
- void systick_isr(void)
- {
- systick_millis_count++;
- MillisTimer::runFromTimer();
- }
-
-
|