Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.

346 lines
8.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 <Arduino.h>
  33. #include "EventResponder.h"
  34. EventResponder * EventResponder::firstYield = nullptr;
  35. EventResponder * EventResponder::lastYield = nullptr;
  36. EventResponder * EventResponder::firstInterrupt = nullptr;
  37. EventResponder * EventResponder::lastInterrupt = nullptr;
  38. bool EventResponder::runningFromYield = false;
  39. // TODO: interrupt disable/enable needed in many places!!!
  40. void EventResponder::triggerEventNotImmediate()
  41. {
  42. bool irq = disableInterrupts();
  43. if (_triggered == false) {
  44. // not already triggered
  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. } else if (_type == EventTypeInterrupt) {
  59. // interrupt, called from software interrupt
  60. if (firstInterrupt == nullptr) {
  61. _next = nullptr;
  62. _prev = nullptr;
  63. firstInterrupt = this;
  64. lastInterrupt = this;
  65. } else {
  66. _next = nullptr;
  67. _prev = lastInterrupt;
  68. _prev->_next = this;
  69. lastInterrupt = this;
  70. }
  71. SCB_ICSR = SCB_ICSR_PENDSVSET; // set PendSV interrupt
  72. } else {
  73. // detached, easy :-)
  74. }
  75. _triggered = true;
  76. }
  77. enableInterrupts(irq);
  78. }
  79. void pendablesrvreq_isr(void)
  80. {
  81. EventResponder::runFromInterrupt();
  82. }
  83. void EventResponder::runFromInterrupt()
  84. {
  85. while (1) {
  86. bool irq = disableInterrupts();
  87. EventResponder *first = firstInterrupt;
  88. if (first) {
  89. firstInterrupt = first->_next;
  90. if (firstInterrupt) {
  91. firstInterrupt->_prev = nullptr;
  92. } else {
  93. lastInterrupt = nullptr;
  94. }
  95. enableInterrupts(irq);
  96. first->_triggered = false;
  97. (*(first->_function))(*first);
  98. } else {
  99. enableInterrupts(irq);
  100. break;
  101. }
  102. }
  103. }
  104. bool EventResponder::clearEvent()
  105. {
  106. bool ret = false;
  107. bool irq = disableInterrupts();
  108. if (_triggered) {
  109. if (_type == EventTypeYield) {
  110. if (_prev) {
  111. _prev->_next = _next;
  112. } else {
  113. firstYield = _next;
  114. }
  115. if (_next) {
  116. _next->_prev = _prev;
  117. } else {
  118. lastYield = _prev;
  119. }
  120. } else if (_type == EventTypeInterrupt) {
  121. if (_prev) {
  122. _prev->_next = _next;
  123. } else {
  124. firstInterrupt = _next;
  125. }
  126. if (_next) {
  127. _next->_prev = _prev;
  128. } else {
  129. lastInterrupt = _prev;
  130. }
  131. }
  132. _triggered = false;
  133. ret = true;
  134. }
  135. enableInterrupts(irq);
  136. return ret;
  137. }
  138. // this detach must be called with interrupts disabled
  139. void EventResponder::detachNoInterrupts()
  140. {
  141. if (_type == EventTypeYield) {
  142. if (_triggered) {
  143. if (_prev) {
  144. _prev->_next = _next;
  145. } else {
  146. firstYield = _next;
  147. }
  148. if (_next) {
  149. _next->_prev = _prev;
  150. } else {
  151. lastYield = _prev;
  152. }
  153. }
  154. _type = EventTypeDetached;
  155. } else if (_type == EventTypeInterrupt) {
  156. if (_triggered) {
  157. if (_prev) {
  158. _prev->_next = _next;
  159. } else {
  160. firstInterrupt = _next;
  161. }
  162. if (_next) {
  163. _next->_prev = _prev;
  164. } else {
  165. lastInterrupt = _prev;
  166. }
  167. }
  168. _type = EventTypeDetached;
  169. }
  170. }
  171. //-------------------------------------------------------------
  172. MillisTimer * MillisTimer::listWaiting = nullptr;
  173. MillisTimer * MillisTimer::listActive = nullptr;
  174. void MillisTimer::begin(unsigned long milliseconds, EventResponderRef event)
  175. {
  176. if (_state != TimerOff) end();
  177. if (!milliseconds) return;
  178. _event = &event;
  179. _ms = (milliseconds > 2)? milliseconds-2 : 0;
  180. _reload = 0;
  181. addToWaitingList();
  182. }
  183. void MillisTimer::beginRepeating(unsigned long milliseconds, EventResponderRef event)
  184. {
  185. if (_state != TimerOff) end();
  186. if (!milliseconds) return;
  187. _event = &event;
  188. _ms = (milliseconds > 2)? milliseconds-2 : 0;
  189. _reload = milliseconds;
  190. addToWaitingList();
  191. }
  192. void MillisTimer::addToWaitingList()
  193. {
  194. _prev = nullptr;
  195. bool irq = disableTimerInterrupt();
  196. _next = listWaiting;
  197. listWaiting = this; // TODO: use STREX to avoid interrupt disable
  198. _state = TimerWaiting;
  199. enableTimerInterrupt(irq);
  200. }
  201. void MillisTimer::addToActiveList() // only called by runFromTimer()
  202. {
  203. if (listActive == nullptr) {
  204. // list is empty, easy case
  205. _next = nullptr;
  206. _prev = nullptr;
  207. listActive = this;
  208. } else if (_ms < listActive->_ms) {
  209. // this timer triggers before any on the list
  210. _next = listActive;
  211. _prev = nullptr;
  212. listActive->_prev = this;
  213. // Decrement the next items wait time be our wait time as to properly handle waits for all other items...
  214. listActive->_ms -= _ms;
  215. listActive = this;
  216. } else {
  217. // add this timer somewhere after the first already on the list
  218. MillisTimer *timer = listActive;
  219. while (timer->_next) {
  220. _ms -= timer->_ms;
  221. timer = timer->_next;
  222. if (_ms < timer->_ms) {
  223. // found the right place in the middle of list
  224. _next = timer;
  225. _prev = timer->_prev;
  226. timer->_prev = this;
  227. _prev->_next = this;
  228. timer->_ms -= _ms;
  229. _state = TimerActive;
  230. return;
  231. }
  232. }
  233. // add this time at the end of the list
  234. _ms -= timer->_ms;
  235. _next = nullptr;
  236. _prev = timer;
  237. timer->_next = this;
  238. }
  239. _state = TimerActive;
  240. }
  241. void MillisTimer::end()
  242. {
  243. bool irq = disableTimerInterrupt();
  244. TimerStateType s = _state;
  245. if (s == TimerActive) {
  246. if (_next) {
  247. _next->_prev = _prev;
  248. _next->_ms += _ms; // add in the rest of our timing to next entry...
  249. }
  250. if (_prev) {
  251. _prev->_next = _next;
  252. } else {
  253. listActive = _next;
  254. }
  255. _state = TimerOff;
  256. } else if (s == TimerWaiting) {
  257. if (listWaiting == this) {
  258. listWaiting = _next;
  259. } else {
  260. MillisTimer *timer = listWaiting;
  261. while (timer) {
  262. if (timer->_next == this) {
  263. timer->_next = _next;
  264. break;
  265. }
  266. timer = timer->_next;
  267. }
  268. }
  269. _state = TimerOff;
  270. }
  271. enableTimerInterrupt(irq);
  272. }
  273. void MillisTimer::runFromTimer()
  274. {
  275. MillisTimer *timer = listActive;
  276. while (timer) {
  277. if (timer->_ms > 0) {
  278. timer->_ms--;
  279. break;
  280. } else {
  281. MillisTimer *next = timer->_next;
  282. if (next) next->_prev = nullptr;
  283. listActive = next;
  284. timer->_state = TimerOff;
  285. EventResponderRef event = *(timer->_event);
  286. event.triggerEvent(0, timer);
  287. if (timer->_reload) {
  288. timer->_ms = timer->_reload;
  289. timer->addToActiveList();
  290. }
  291. timer = listActive;
  292. }
  293. }
  294. bool irq = disableTimerInterrupt();
  295. MillisTimer *waiting = listWaiting;
  296. listWaiting = nullptr; // TODO: use STREX to avoid interrupt disable
  297. enableTimerInterrupt(irq);
  298. while (waiting) {
  299. MillisTimer *next = waiting->_next;
  300. waiting->addToActiveList();
  301. waiting = next;
  302. }
  303. }
  304. // Long ago you could install your own systick interrupt handler by just
  305. // creating your own systick_isr() function. No longer. But if you
  306. // *really* want to commandeer systick, you can still do so by writing
  307. // your function into the RAM-based vector table.
  308. //
  309. // _VectorsRam[15] = my_systick_function;
  310. //
  311. // However, for long-term portability, use a MillisTimer object to
  312. // generate an event every millisecond, and attach your function to
  313. // its EventResponder. You can attach as a software interrupt, so your
  314. // code will run at lower interrupt priority for better compatibility
  315. // with libraries using mid-to-high priority interrupts.
  316. // TODO: this doesn't work for IMXRT - no longer using predefined names
  317. extern "C" volatile uint32_t systick_millis_count;
  318. void systick_isr(void)
  319. {
  320. systick_millis_count++;
  321. MillisTimer::runFromTimer();
  322. }