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.

326 lines
7.6KB

  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;
  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;
  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. enableTimerInterrupt(irq);
  198. }
  199. void MillisTimer::addToActiveList() // only called by runFromTimer()
  200. {
  201. if (listActive == nullptr) {
  202. // list is empty, easy case
  203. _next = nullptr;
  204. _prev = nullptr;
  205. listActive = this;
  206. } else if (_ms < listActive->_ms) {
  207. // this timer triggers before any on the list
  208. _next = listActive;
  209. _prev = nullptr;
  210. listActive->_prev = this;
  211. listActive = this;
  212. } else {
  213. // add this timer somewhere after the first already on the list
  214. MillisTimer *timer = listActive;
  215. while (timer->_next) {
  216. _ms -= timer->_ms;
  217. timer = timer->_next;
  218. if (_ms < timer->_ms) {
  219. // found the right place in the middle of list
  220. _next = timer;
  221. _prev = timer->_prev;
  222. timer->_prev = this;
  223. _prev->_next = this;
  224. _state = TimerActive;
  225. return;
  226. }
  227. }
  228. // add this time at the end of the list
  229. _ms -= timer->_ms;
  230. _next = nullptr;
  231. _prev = timer;
  232. timer->_next = this;
  233. }
  234. _state = TimerActive;
  235. }
  236. void MillisTimer::end()
  237. {
  238. bool irq = disableTimerInterrupt();
  239. TimerStateType s = _state;
  240. if (s == TimerActive) {
  241. if (_next) {
  242. _next->_prev = _prev;
  243. }
  244. if (_prev) {
  245. _prev->_next = _next;
  246. } else {
  247. listActive = _next;
  248. }
  249. _state = TimerOff;
  250. } else if (s == TimerWaiting) {
  251. if (listWaiting == this) {
  252. listWaiting = _next;
  253. } else {
  254. MillisTimer *timer = listWaiting;
  255. while (timer) {
  256. if (timer->_next == this) {
  257. timer->_next = _next;
  258. break;
  259. }
  260. timer = timer->_next;
  261. }
  262. }
  263. _state = TimerOff;
  264. }
  265. enableTimerInterrupt(irq);
  266. }
  267. void MillisTimer::runFromTimer()
  268. {
  269. MillisTimer *timer = listActive;
  270. while (timer) {
  271. if (timer->_ms > 0) {
  272. timer->_ms--;
  273. break;
  274. } else {
  275. MillisTimer *next = timer->_next;
  276. if (next) next->_prev = nullptr;
  277. listActive = next;
  278. timer->_state = TimerOff;
  279. EventResponderRef event = *(timer->_event);
  280. event.triggerEvent(0, timer);
  281. if (timer->_reload) {
  282. timer->_ms = timer->_reload;
  283. timer->addToActiveList();
  284. }
  285. timer = listActive;
  286. }
  287. }
  288. bool irq = disableTimerInterrupt();
  289. MillisTimer *waiting = listWaiting;
  290. listWaiting = nullptr; // TODO: use STREX to avoid interrupt disable
  291. enableTimerInterrupt(irq);
  292. while (waiting) {
  293. MillisTimer *next = waiting->_next;
  294. waiting->addToActiveList();
  295. waiting = next;
  296. }
  297. }
  298. extern "C" volatile uint32_t systick_millis_count;
  299. void systick_isr(void)
  300. {
  301. systick_millis_count++;
  302. MillisTimer::runFromTimer();
  303. }