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.

300 lines
6.8KB

  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. void EventResponder::detach()
  138. {
  139. bool irq = disableInterrupts();
  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. enableInterrupts(irq);
  170. }
  171. //-------------------------------------------------------------
  172. MillisTimer * MillisTimer::list = nullptr;
  173. void MillisTimer::begin(unsigned long milliseconds, EventResponderRef event)
  174. {
  175. end();
  176. if (!milliseconds) return;
  177. _event = &event;
  178. _ms = milliseconds;
  179. _reload = 0;
  180. addToList();
  181. }
  182. void MillisTimer::beginRepeating(unsigned long milliseconds, EventResponderRef event)
  183. {
  184. end();
  185. if (!milliseconds) return;
  186. _event = &event;
  187. _ms = milliseconds;
  188. _reload = milliseconds;
  189. addToList();
  190. }
  191. void MillisTimer::addToList()
  192. {
  193. bool irq = disableTimerInterrupt();
  194. if (list == nullptr) {
  195. // list is empty, easy case
  196. _next = nullptr;
  197. _prev = nullptr;
  198. list = this;
  199. } else if (_ms < list->_ms) {
  200. // this timer triggers before any on the list
  201. _next = list;
  202. _prev = nullptr;
  203. list->_prev = this;
  204. list = this;
  205. } else {
  206. // add this timer somewhere after the first already on the list
  207. MillisTimer *timer = list;
  208. while (timer->_next) {
  209. _ms -= timer->_ms;
  210. timer = timer->_next;
  211. if (_ms < timer->_ms) {
  212. // found the right place in the middle of list
  213. _next = timer;
  214. _prev = timer->_prev;
  215. timer->_prev = this;
  216. _prev->_next = this;
  217. isQueued = true;
  218. enableTimerInterrupt(irq);
  219. return;
  220. }
  221. }
  222. // add this time at the end of the list
  223. _ms -= timer->_ms;
  224. _next = nullptr;
  225. _prev = timer;
  226. timer->_next = this;
  227. }
  228. isQueued = true;
  229. enableTimerInterrupt(irq);
  230. }
  231. void MillisTimer::end()
  232. {
  233. bool irq = disableTimerInterrupt();
  234. if (isQueued) {
  235. if (_next) {
  236. _next->_prev = _prev;
  237. }
  238. if (_prev) {
  239. _prev->_next = _next;
  240. } else {
  241. list = _next;
  242. }
  243. isQueued = false;
  244. }
  245. enableTimerInterrupt(irq);
  246. }
  247. void MillisTimer::runFromTimer()
  248. {
  249. bool irq = disableTimerInterrupt();
  250. MillisTimer *timer = list;
  251. while (timer) {
  252. if (timer->_ms > 0) {
  253. timer->_ms--;
  254. break;
  255. } else {
  256. MillisTimer *next = timer->_next;
  257. if (next) next->_prev = nullptr;
  258. list = next;
  259. enableTimerInterrupt(irq);
  260. timer->isQueued = false;
  261. EventResponderRef event = *(timer->_event);
  262. event.triggerEvent(0, timer);
  263. if (timer->_reload) {
  264. timer->_ms = timer->_reload;
  265. timer->addToList();
  266. }
  267. irq = disableTimerInterrupt();
  268. timer = list;
  269. }
  270. }
  271. enableTimerInterrupt(irq);
  272. }
  273. extern "C" volatile uint32_t systick_millis_count;
  274. void systick_isr(void)
  275. {
  276. systick_millis_count++;
  277. MillisTimer::runFromTimer();
  278. }