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.

284 lines
6.2KB

  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. if (_pending) {
  42. // already triggered
  43. return;
  44. }
  45. if (_type == EventTypeYield) {
  46. // normal type, called from yield()
  47. if (firstYield == nullptr) {
  48. _next = nullptr;
  49. _prev = nullptr;
  50. firstYield = this;
  51. lastYield = this;
  52. } else {
  53. _next = nullptr;
  54. _prev = lastYield;
  55. _prev->_next = this;
  56. lastYield = this;
  57. }
  58. _pending = true;
  59. } else if (_type == EventTypeInterrupt) {
  60. // interrupt, called from software interrupt
  61. if (firstInterrupt == nullptr) {
  62. _next = nullptr;
  63. _prev = nullptr;
  64. firstInterrupt = this;
  65. lastInterrupt = this;
  66. } else {
  67. _next = nullptr;
  68. _prev = lastInterrupt;
  69. _prev->_next = this;
  70. lastInterrupt = this;
  71. }
  72. _pending = true;
  73. SCB_ICSR = SCB_ICSR_PENDSVSET; // set PendSV interrupt
  74. } else {
  75. // detached, easy :-)
  76. _pending = true;
  77. }
  78. }
  79. void pendablesrvreq_isr(void)
  80. {
  81. EventResponder::runFromInterrupt();
  82. }
  83. void EventResponder::runFromInterrupt()
  84. {
  85. while (1) {
  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. first->_pending = false;
  95. (*(first->_function))(*first);
  96. } else {
  97. break;
  98. }
  99. }
  100. }
  101. bool EventResponder::clearEvent()
  102. {
  103. if (_pending) {
  104. if (_type == EventTypeYield) {
  105. if (_prev) {
  106. _prev->_next = _next;
  107. } else {
  108. firstYield = _next;
  109. }
  110. if (_next) {
  111. _next->_prev = _prev;
  112. } else {
  113. lastYield = _prev;
  114. }
  115. } else if (_type == EventTypeInterrupt) {
  116. if (_prev) {
  117. _prev->_next = _next;
  118. } else {
  119. firstInterrupt = _next;
  120. }
  121. if (_next) {
  122. _next->_prev = _prev;
  123. } else {
  124. lastInterrupt = _prev;
  125. }
  126. }
  127. _pending = false;
  128. return true;
  129. }
  130. return false;
  131. }
  132. void EventResponder::detach()
  133. {
  134. if (_type == EventTypeYield) {
  135. if (_pending) {
  136. if (_prev) {
  137. _prev->_next = _next;
  138. } else {
  139. firstYield = _next;
  140. }
  141. if (_next) {
  142. _next->_prev = _prev;
  143. } else {
  144. lastYield = _prev;
  145. }
  146. }
  147. _type = EventTypeDetached;
  148. } else if (_type == EventTypeInterrupt) {
  149. if (_pending) {
  150. if (_prev) {
  151. _prev->_next = _next;
  152. } else {
  153. firstInterrupt = _next;
  154. }
  155. if (_next) {
  156. _next->_prev = _prev;
  157. } else {
  158. lastInterrupt = _prev;
  159. }
  160. }
  161. _type = EventTypeDetached;
  162. }
  163. }
  164. //-------------------------------------------------------------
  165. MillisTimer * MillisTimer::list = nullptr;
  166. void MillisTimer::begin(unsigned long milliseconds, EventResponderRef event)
  167. {
  168. end();
  169. if (!milliseconds) return;
  170. _event = &event;
  171. _ms = milliseconds;
  172. _reload = 0;
  173. addToList();
  174. }
  175. void MillisTimer::beginRepeat(unsigned long milliseconds, EventResponderRef event)
  176. {
  177. end();
  178. if (!milliseconds) return;
  179. _event = &event;
  180. _ms = milliseconds;
  181. _reload = milliseconds;
  182. addToList();
  183. }
  184. void MillisTimer::addToList()
  185. {
  186. if (list == nullptr) {
  187. // list is empty, easy case
  188. _next = nullptr;
  189. _prev = nullptr;
  190. list = this;
  191. } else if (_ms < list->_ms) {
  192. // this timer triggers before any on the list
  193. _next = list;
  194. _prev = nullptr;
  195. list->_prev = this;
  196. list = this;
  197. } else {
  198. // add this timer somewhere after the first already on the list
  199. MillisTimer *timer = list;
  200. while (timer->_next) {
  201. _ms -= timer->_ms;
  202. timer = timer->_next;
  203. if (_ms < timer->_ms) {
  204. // found the right place in the middle of list
  205. _next = timer;
  206. _prev = timer->_prev;
  207. timer->_prev = this;
  208. _prev->_next = this;
  209. isQueued = true;
  210. return;
  211. }
  212. }
  213. // add this time at the end of the list
  214. _ms -= timer->_ms;
  215. _next = nullptr;
  216. _prev = timer;
  217. timer->_next = this;
  218. }
  219. isQueued = true;
  220. }
  221. void MillisTimer::end()
  222. {
  223. if (isQueued) {
  224. if (_next) {
  225. _next->_prev = _prev;
  226. }
  227. if (_prev) {
  228. _prev->_next = _next;
  229. } else {
  230. list = _next;
  231. }
  232. isQueued = false;
  233. }
  234. }
  235. void MillisTimer::runFromTimer()
  236. {
  237. MillisTimer *timer = list;
  238. while (timer) {
  239. if (timer->_ms > 0) {
  240. timer->_ms--;
  241. break;
  242. } else {
  243. MillisTimer *next = timer->_next;
  244. if (next) next->_prev = nullptr;
  245. list = next;
  246. timer->isQueued = false;
  247. EventResponderRef event = *(timer->_event);
  248. event.triggerEvent(0, timer);
  249. if (timer->_reload) {
  250. timer->_ms = timer->_reload;
  251. timer->addToList();
  252. }
  253. timer = list;
  254. }
  255. }
  256. }
  257. extern "C" volatile uint32_t systick_millis_count;
  258. void systick_isr(void)
  259. {
  260. systick_millis_count++;
  261. MillisTimer::runFromTimer();
  262. }