Teensy 4.1 core updated for C++20
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

344 lines
8.5KB

  1. /* EventResponder - Simple event-based programming for Arduino
  2. * Copyright 2017 Paul Stoffregen
  3. *
  4. * Permission is hereby granted, free of charge, to any person obtaining
  5. * a copy of this software and associated documentation files (the
  6. * "Software"), to deal in the Software without restriction, including
  7. * without limitation the rights to use, copy, modify, merge, publish,
  8. * distribute, sublicense, and/or sell copies of the Software, and to
  9. * permit persons to whom the Software is furnished to do so, subject to
  10. * the following conditions:
  11. *
  12. * The above copyright notice and this permission notice shall be
  13. * included in all copies or substantial portions of the Software.
  14. *
  15. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  16. * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  17. * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  18. * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
  19. * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
  20. * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
  21. * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  22. * SOFTWARE.
  23. */
  24. /* EventResponder is an experimental API, almost certain to
  25. * incompatibly change as it develops. Please understand any
  26. * programs you write now using EventResponder may need to be
  27. * updated as EventResponder develops.
  28. *
  29. * Please post EventResponder post your feedback here:
  30. * https://forum.pjrc.com/threads/44723-Arduino-Events
  31. */
  32. #include "EventResponder.h"
  33. EventResponder * EventResponder::firstYield = nullptr;
  34. EventResponder * EventResponder::lastYield = nullptr;
  35. EventResponder * EventResponder::firstInterrupt = nullptr;
  36. EventResponder * EventResponder::lastInterrupt = nullptr;
  37. bool EventResponder::runningFromYield = false;
  38. // TODO: interrupt disable/enable needed in many places!!!
  39. void EventResponder::triggerEventNotImmediate()
  40. {
  41. bool irq = disableInterrupts();
  42. if (_triggered == false) {
  43. // not already triggered
  44. if (_type == EventTypeYield) {
  45. // normal type, called from yield()
  46. if (firstYield == nullptr) {
  47. _next = nullptr;
  48. _prev = nullptr;
  49. firstYield = this;
  50. lastYield = this;
  51. } else {
  52. _next = nullptr;
  53. _prev = lastYield;
  54. _prev->_next = this;
  55. lastYield = this;
  56. }
  57. } else if (_type == EventTypeInterrupt) {
  58. // interrupt, called from software interrupt
  59. if (firstInterrupt == nullptr) {
  60. _next = nullptr;
  61. _prev = nullptr;
  62. firstInterrupt = this;
  63. lastInterrupt = this;
  64. } else {
  65. _next = nullptr;
  66. _prev = lastInterrupt;
  67. _prev->_next = this;
  68. lastInterrupt = this;
  69. }
  70. SCB_ICSR = SCB_ICSR_PENDSVSET; // set PendSV interrupt
  71. } else {
  72. // detached, easy :-)
  73. }
  74. _triggered = true;
  75. }
  76. enableInterrupts(irq);
  77. }
  78. void pendablesrvreq_isr(void)
  79. {
  80. EventResponder::runFromInterrupt();
  81. }
  82. void EventResponder::runFromInterrupt()
  83. {
  84. while (1) {
  85. bool irq = disableInterrupts();
  86. EventResponder *first = firstInterrupt;
  87. if (first) {
  88. firstInterrupt = first->_next;
  89. if (firstInterrupt) {
  90. firstInterrupt->_prev = nullptr;
  91. } else {
  92. lastInterrupt = nullptr;
  93. }
  94. enableInterrupts(irq);
  95. first->_triggered = false;
  96. (*(first->_function))(*first);
  97. } else {
  98. enableInterrupts(irq);
  99. break;
  100. }
  101. }
  102. }
  103. bool EventResponder::clearEvent()
  104. {
  105. bool ret = false;
  106. bool irq = disableInterrupts();
  107. if (_triggered) {
  108. if (_type == EventTypeYield) {
  109. if (_prev) {
  110. _prev->_next = _next;
  111. } else {
  112. firstYield = _next;
  113. }
  114. if (_next) {
  115. _next->_prev = _prev;
  116. } else {
  117. lastYield = _prev;
  118. }
  119. } else if (_type == EventTypeInterrupt) {
  120. if (_prev) {
  121. _prev->_next = _next;
  122. } else {
  123. firstInterrupt = _next;
  124. }
  125. if (_next) {
  126. _next->_prev = _prev;
  127. } else {
  128. lastInterrupt = _prev;
  129. }
  130. }
  131. _triggered = false;
  132. ret = true;
  133. }
  134. enableInterrupts(irq);
  135. return ret;
  136. }
  137. // this detach must be called with interrupts disabled
  138. void EventResponder::detachNoInterrupts()
  139. {
  140. if (_type == EventTypeYield) {
  141. if (_triggered) {
  142. if (_prev) {
  143. _prev->_next = _next;
  144. } else {
  145. firstYield = _next;
  146. }
  147. if (_next) {
  148. _next->_prev = _prev;
  149. } else {
  150. lastYield = _prev;
  151. }
  152. }
  153. _type = EventTypeDetached;
  154. } else if (_type == EventTypeInterrupt) {
  155. if (_triggered) {
  156. if (_prev) {
  157. _prev->_next = _next;
  158. } else {
  159. firstInterrupt = _next;
  160. }
  161. if (_next) {
  162. _next->_prev = _prev;
  163. } else {
  164. lastInterrupt = _prev;
  165. }
  166. }
  167. _type = EventTypeDetached;
  168. }
  169. }
  170. //-------------------------------------------------------------
  171. MillisTimer * MillisTimer::listWaiting = nullptr;
  172. MillisTimer * MillisTimer::listActive = nullptr;
  173. void MillisTimer::begin(unsigned long milliseconds, EventResponderRef event)
  174. {
  175. if (_state != TimerOff) end();
  176. if (!milliseconds) return;
  177. _event = &event;
  178. _ms = (milliseconds > 2)? milliseconds-2 : 0;
  179. _reload = 0;
  180. addToWaitingList();
  181. }
  182. void MillisTimer::beginRepeating(unsigned long milliseconds, EventResponderRef event)
  183. {
  184. if (_state != TimerOff) end();
  185. if (!milliseconds) return;
  186. _event = &event;
  187. _ms = (milliseconds > 2)? milliseconds-2 : 0;
  188. _reload = milliseconds;
  189. addToWaitingList();
  190. }
  191. void MillisTimer::addToWaitingList()
  192. {
  193. _prev = nullptr;
  194. bool irq = disableTimerInterrupt();
  195. _next = listWaiting;
  196. listWaiting = this; // TODO: use STREX to avoid interrupt disable
  197. _state = TimerWaiting;
  198. enableTimerInterrupt(irq);
  199. }
  200. void MillisTimer::addToActiveList() // only called by runFromTimer()
  201. {
  202. if (listActive == nullptr) {
  203. // list is empty, easy case
  204. _next = nullptr;
  205. _prev = nullptr;
  206. listActive = this;
  207. } else if (_ms < listActive->_ms) {
  208. // this timer triggers before any on the list
  209. _next = listActive;
  210. _prev = nullptr;
  211. listActive->_prev = this;
  212. // Decrement the next items wait time be our wait time as to properly handle waits for all other items...
  213. listActive->_ms -= _ms;
  214. listActive = this;
  215. } else {
  216. // add this timer somewhere after the first already on the list
  217. MillisTimer *timer = listActive;
  218. while (timer->_next) {
  219. _ms -= timer->_ms;
  220. timer = timer->_next;
  221. if (_ms < timer->_ms) {
  222. // found the right place in the middle of list
  223. _next = timer;
  224. _prev = timer->_prev;
  225. timer->_prev = this;
  226. _prev->_next = this;
  227. timer->_ms -= _ms;
  228. _state = TimerActive;
  229. return;
  230. }
  231. }
  232. // add this time at the end of the list
  233. _ms -= timer->_ms;
  234. _next = nullptr;
  235. _prev = timer;
  236. timer->_next = this;
  237. }
  238. _state = TimerActive;
  239. }
  240. void MillisTimer::end()
  241. {
  242. bool irq = disableTimerInterrupt();
  243. TimerStateType s = _state;
  244. if (s == TimerActive) {
  245. if (_next) {
  246. _next->_prev = _prev;
  247. _next->_ms += _ms; // add in the rest of our timing to next entry...
  248. }
  249. if (_prev) {
  250. _prev->_next = _next;
  251. } else {
  252. listActive = _next;
  253. }
  254. _state = TimerOff;
  255. } else if (s == TimerWaiting) {
  256. if (listWaiting == this) {
  257. listWaiting = _next;
  258. } else {
  259. MillisTimer *timer = listWaiting;
  260. while (timer) {
  261. if (timer->_next == this) {
  262. timer->_next = _next;
  263. break;
  264. }
  265. timer = timer->_next;
  266. }
  267. }
  268. _state = TimerOff;
  269. }
  270. enableTimerInterrupt(irq);
  271. }
  272. void MillisTimer::runFromTimer()
  273. {
  274. MillisTimer *timer = listActive;
  275. while (timer) {
  276. if (timer->_ms > 0) {
  277. timer->_ms--;
  278. break;
  279. } else {
  280. MillisTimer *next = timer->_next;
  281. if (next) next->_prev = nullptr;
  282. listActive = next;
  283. timer->_state = TimerOff;
  284. EventResponderRef event = *(timer->_event);
  285. event.triggerEvent(0, timer);
  286. if (timer->_reload) {
  287. timer->_ms = timer->_reload;
  288. timer->addToActiveList();
  289. }
  290. timer = listActive;
  291. }
  292. }
  293. bool irq = disableTimerInterrupt();
  294. MillisTimer *waiting = listWaiting;
  295. listWaiting = nullptr; // TODO: use STREX to avoid interrupt disable
  296. enableTimerInterrupt(irq);
  297. while (waiting) {
  298. MillisTimer *next = waiting->_next;
  299. waiting->addToActiveList();
  300. waiting = next;
  301. }
  302. }
  303. // Long ago you could install your own systick interrupt handler by just
  304. // creating your own systick_isr() function. No longer. But if you
  305. // *really* want to commandeer systick, you can still do so by writing
  306. // your function into the RAM-based vector table.
  307. //
  308. // _VectorsRam[15] = my_systick_function;
  309. //
  310. // However, for long-term portability, use a MillisTimer object to
  311. // generate an event every millisecond, and attach your function to
  312. // its EventResponder. You can attach as a software interrupt, so your
  313. // code will run at lower interrupt priority for better compatibility
  314. // with libraries using mid-to-high priority interrupts.
  315. extern "C" volatile uint32_t systick_millis_count;
  316. void systick_isr(void)
  317. {
  318. systick_millis_count++;
  319. MillisTimer::runFromTimer();
  320. }