diff options
| -rw-r--r-- | README | 89 | ||||
| -rw-r--r-- | extras/TaskScheduler.doc | bin | 178688 -> 201216 bytes | |||
| -rw-r--r-- | extras/TaskScheduler.html | 636 | ||||
| -rw-r--r-- | library.properties | 2 | ||||
| -rw-r--r-- | src/TaskScheduler.h | 28 |
5 files changed, 686 insertions, 69 deletions
@@ -1,5 +1,5 @@ Task Scheduler – cooperative multitasking for Arduino microcontrollers -Version 1.8.3: 2015-11-05 +Version 1.8.4: 2015-11-17 OVERVIEW: A lightweight implementation of cooperative multitasking (task scheduling) supporting: @@ -13,33 +13,28 @@ A lightweight implementation of cooperative multitasking (task scheduling) suppo 8. Support for Local Task Storage pointer (allowing use of same callback code for multiple tasks) Changelog: -v1.0.0: - 2015-02-24 - Initial release - 2015-02-28 - added delay() and disableOnLastIteration() functions - 2015-03-25 - changed scheduler execute() function for a more precise delay calculation: - 1. Do not delay if any of the tasks ran (making request for immediate execution redundant) - 2. Delay is invoked only if none of the tasks ran - 3. Delay is based on the min anticipated wait until next task _AND_ the runtime of execute function itself. - 2015-05-11 - added restart() and restartDelayed() functions to restart tasks which are on hold after running all iterations - 2015-05-19 - completely removed delay from the scheduler since there are no power saving there. using 1 ms sleep instead +v1.8.4: + 2015-11-15 - bug fix: Task alignment with millis() for scheduling purposes should be done after OnEnable, not before. Especially since OnEnable method can change the interval + +v1.8.3: + 2015-11-05 - support for task activation on a status request with arbitrary interval and number of iterations (0 and 1 are still default values) + 2015-11-05 - implement waitForDelayed() method to allow task activation on the status request completion delayed for one current interval + 2015-11-09 - added callback methods prototypes to all examples for Arduino IDE 1.6.6 compatibility + 2015-11-14 - added several constants to be used as task parameters for readability (e.g, TASK_FOREVER, TASK_SECOND, etc.) + 2015-11-14 - significant optimization of the scheduler's execute loop, including millis() rollover fix option + +v1.8.2: + 2015-10-27 - implement Local Task Storage Pointer (allow use of same callback code for different tasks) + 2015-10-27 - bug: currentTask() method returns incorrect Task reference if called within OnEnable and OnDisable methods + 2015-10-27 - protection against infinite loop in OnEnable (if enable() methods are called within OnEnable) + 2015-10-29 - new currentLts() method in the scheduler class returns current task's LTS pointer in one call -v1.4.1: - 2015-09-15 - more careful placement of AVR-specific includes for sleep functions (compatibility with DUE) - sleep on idle run is no longer a default and should be explicitly compiled with _TASK_SLEEP_ON_IDLE_RUN defined - -v1.5.0: - 2015-09-20 - access to currently executing task (for callback functions) - 2015-09-20 - pass scheduler as a parameter to the task constructor to append the task to the end of the chain - 2015-09-20 - option to create a task already enabled +v1.8.1: + 2015-10-22 - implement Task id and control points to support identification of failure points for watchdog timer logging -v1.5.1: - 2015-09-21 - bug fix: incorrect handling of active tasks via set() and setIterations(). - Thanks to Hannes Morgenstern for catching this one - -v1.6.0: - 2015-09-22 - revert back to having all tasks disable on last iteration. - 2015-09-22 - deprecated disableOnLastIteration method as a result - 2015-10-01 - made version numbers semver compliant (documentation only) +v1.8.0: + 2015-10-13 - support for status request objects allowing tasks waiting on requests + 2015-10-13 - moved to a single header file to allow compilation control via #defines from the main sketch v1.7.0: 2015-10-08 - introduced callback run counter - callback functions can branch on the iteration number. @@ -48,23 +43,31 @@ v1.7.0: 2015-10-11 - introduced callback functions "on enable" and "on disable". On enable runs every time enable is called, on disable runs only if task was enabled 2015-10-12 - new Task method: forceNextIteration() - makes next iteration happen immediately during the next pass regardless how much time is left -v1.8.0: - 2015-10-13 - support for status request objects allowing tasks waiting on requests - 2015-10-13 - moved to a single header file to allow compilation control via #defines from the main sketch +v1.6.0: + 2015-09-22 - revert back to having all tasks disable on last iteration. + 2015-09-22 - deprecated disableOnLastIteration method as a result + 2015-10-01 - made version numbers semver compliant (documentation only) -v1.8.1: - 2015-10-22 - implement Task id and control points to support identification of failure points for watchdog timer logging - -v1.8.2: - 2015-10-27 - implement Local Task Storage Pointer (allow use of same callback code for different tasks) - 2015-10-27 - bug: currentTask() method returns incorrect Task reference if called within OnEnable and OnDisable methods - 2015-10-27 - protection against infinite loop in OnEnable (if enable() methods are called within OnEnable) - 2015-10-29 - new currentLts() method in the scheduler class returns current task's LTS pointer in one call +v1.5.1: + 2015-09-21 - bug fix: incorrect handling of active tasks via set() and setIterations(). + Thanks to Hannes Morgenstern for catching this one + +v1.5.0: + 2015-09-20 - access to currently executing task (for callback functions) + 2015-09-20 - pass scheduler as a parameter to the task constructor to append the task to the end of the chain + 2015-09-20 - option to create a task already enabled -v1.8.3: - 2015-11-05 - support for task activation on a status request with arbitrary interval and number of iterations (0 and 1 are still default values) - 2015-11-05 - implement waitForDelayed() method to allow task activation on the status request completion delayed for one current interval - 2015-11-09 - added callback methods prototypes to all examples for Arduino IDE 1.6.6 compatibility - 2015-11-14 - added several constants to be used as task parameters for readability (e.g, TASK_FOREVER, TASK_SECOND, etc.) - 2015-11-14 - significant optimization of the scheduler's execute loop, including millis() rollover fix option +v1.4.1: + 2015-09-15 - more careful placement of AVR-specific includes for sleep functions (compatibility with DUE) + sleep on idle run is no longer a default and should be explicitly compiled with _TASK_SLEEP_ON_IDLE_RUN defined + +v1.0.0: + 2015-02-24 - Initial release + 2015-02-28 - added delay() and disableOnLastIteration() functions + 2015-03-25 - changed scheduler execute() function for a more precise delay calculation: + 1. Do not delay if any of the tasks ran (making request for immediate execution redundant) + 2. Delay is invoked only if none of the tasks ran + 3. Delay is based on the min anticipated wait until next task _AND_ the runtime of execute function itself. + 2015-05-11 - added restart() and restartDelayed() functions to restart tasks which are on hold after running all iterations + 2015-05-19 - completely removed delay from the scheduler since there are no power saving there. using 1 ms sleep instead diff --git a/extras/TaskScheduler.doc b/extras/TaskScheduler.doc Binary files differindex 85331e7..f73af96 100644 --- a/extras/TaskScheduler.doc +++ b/extras/TaskScheduler.doc diff --git a/extras/TaskScheduler.html b/extras/TaskScheduler.html index 8d83085..b295af4 100644 --- a/extras/TaskScheduler.html +++ b/extras/TaskScheduler.html @@ -6,7 +6,7 @@ <META NAME="GENERATOR" CONTENT="LibreOffice 3.5 (Linux)"> <META NAME="CREATED" CONTENT="20150206;16300000"> <META NAME="CHANGEDBY" CONTENT="Anatoli Arkhipenko"> - <META NAME="CHANGED" CONTENT="20151105;22050000"> + <META NAME="CHANGED" CONTENT="20151115;15470000"> <META NAME="Info 1" CONTENT=""> <META NAME="Info 2" CONTENT=""> <META NAME="Info 3" CONTENT=""> @@ -28,7 +28,7 @@ Scheduler</B></FONT></P> <P CLASS="western" STYLE="margin-bottom: 0in"><B>cooperative multitasking for Arduino microcontrollers</B></P> <P CLASS="western" STYLE="margin-bottom: 0in; border-top: none; border-bottom: 1px solid #000000; border-left: none; border-right: none; padding-top: 0in; padding-bottom: 0.01in; padding-left: 0in; padding-right: 0in"> -<FONT SIZE=2 STYLE="font-size: 11pt"><B>Version 1.8.3: 2015-11-05</B></FONT></P> +<FONT SIZE=2 STYLE="font-size: 11pt"><B>Version 1.8.4: 2015-11-17</B></FONT></P> <P CLASS="western" STYLE="margin-bottom: 0in"><BR> </P> <P CLASS="western" STYLE="margin-bottom: 0in"><B>OVERVIEW</B>:</P> @@ -122,7 +122,7 @@ than the Scheduler's <B>execute</B>() method).</P> </P> <P CLASS="western" STYLE="margin-bottom: 0in; page-break-after: avoid"> <B>Below is the flowchart of a Task lifecycle:</B></P> -<P CLASS="western" STYLE="margin-bottom: 0in"><IMG SRC="TaskScheduler_html_m68472eb8.png" NAME="graphics1" ALIGN=BOTTOM WIDTH=664 HEIGHT=655 BORDER=0></P> +<P CLASS="western" STYLE="margin-bottom: 0in"><IMG SRC="TaskScheduler_html.png" NAME="graphics1" ALIGN=BOTTOM WIDTH=664 HEIGHT=616 BORDER=0></P> <P CLASS="western" STYLE="margin-bottom: 0in"><BR> </P> <P CLASS="western" STYLE="margin-bottom: 0in"><B>TaskScheduler</B> @@ -297,6 +297,611 @@ enabled by placing appropriate #define statements in front of the </P> <P CLASS="western" STYLE="margin-bottom: 0in"><BR> </P> +<P CLASS="western" STYLE="margin-bottom: 0in"><B>TASK PRIORITY AND +COOPERATIVE MULTITASKING:</B></P> +<P CLASS="western" STYLE="margin-bottom: 0in">TaskScheduler <B>does +not support</B> task priority functionality. I have been thinking a +lot about it (especially since Symbian's Active Objects, which +TaskScheduler is inspired by, support it), but decided against it. +</P> +<P CLASS="western" STYLE="margin-bottom: 0in"><BR> +</P> +<P CLASS="western" STYLE="margin-bottom: 0in">This is why:</P> +<P CLASS="western" STYLE="margin-bottom: 0in"><BR> +</P> +<P CLASS="western" STYLE="margin-bottom: 0in"><BR> +</P> +<P CLASS="western" STYLE="margin-bottom: 0in"><BR> +</P> +<P CLASS="western" STYLE="margin-bottom: 0in">1. Execution chains are +simple and efficient. The main idea is to minimize scheduling +overhead by Scheduler going through the chain. Implementing true +priority would require looking ahead through the entire chain, +ranking and aging tasks by priorities. It would slow the <FONT FACE="FreeMono, monospace"><FONT SIZE=2 STYLE="font-size: 10pt">execute() +</FONT></FONT>loop significantly.</P> +<P CLASS="western" STYLE="margin-bottom: 0in"><BR> +</P> +<P CLASS="western" STYLE="margin-bottom: 0in"><BR> +</P> +<P CLASS="western" STYLE="margin-bottom: 0in"><BR> +</P> +<P CLASS="western" STYLE="margin-bottom: 0in">2. TaskScheduler is <B>NOT</B> +a pre-emptive multi-tasking library. Nor is it a Real-Time OS. There +is no way to break execution of one task in favor of another. +Therefore callback methods require careful programming for +cooperative behavior.</P> +<P CLASS="western" STYLE="margin-bottom: 0in">This has, however, +significant benefits: you don't need to worry about concurrency +inside the callback method, since only one callback method runs at a +time, and could not be interrupted. All resources are yours for that +period of time, noone can switch the value of variables (except +interrupt functions of course...), etc. It is a stable and +predictable environment, and it helps a lot with writing stable code. +</P> +<P CLASS="western" STYLE="margin-bottom: 0in"><BR> +</P> +<P CLASS="western" STYLE="margin-bottom: 0in"><BR> +</P> +<P CLASS="western" STYLE="margin-bottom: 0in"><BR> +</P> +<P CLASS="western" STYLE="margin-bottom: 0in">A number of things +could be done instead of priorities:</P> +<P CLASS="western" STYLE="margin-bottom: 0in"><BR> +</P> +<P CLASS="western" STYLE="margin-bottom: 0in"><BR> +</P> +<P CLASS="western" STYLE="margin-bottom: 0in"><BR> +</P> +<P CLASS="western" STYLE="margin-bottom: 0in">1. Schedule your +critical tasks to run more frequently than the other tasks</P> +<P CLASS="western" STYLE="margin-bottom: 0in">. <BR>(Since you can +control the interval, you could also change the task to run more or +less frequently as the situation demands).</P> +<P CLASS="western" STYLE="margin-bottom: 0in"><BR> +</P> +<P CLASS="western" STYLE="margin-bottom: 0in">2. If one particular +callback routine is critical, create a couple of tasks referring to +the same callback and "sprinkle" them around the chain:</P> +<P CLASS="western" STYLE="margin-bottom: 0in"><BR> +</P> +<P CLASS="western" STYLE="margin-bottom: 0in"><BR> +</P> +<P CLASS="western" STYLE="margin-bottom: 0in"><BR> +</P> +<P CLASS="western" STYLE="margin-bottom: 0in"> <FONT FACE="FreeMono, monospace"><FONT SIZE=2 STYLE="font-size: 10pt">Scheduler +ts;</FONT></FONT></P> +<P CLASS="western" STYLE="margin-bottom: 0in"><BR> +</P> +<P CLASS="western" STYLE="margin-bottom: 0in"> <FONT FACE="FreeMono, monospace"><FONT SIZE=2 STYLE="font-size: 10pt">Task +t1(20, TASK_FOREVER, &callback1, &ts);</FONT></FONT></P> +<P CLASS="western" STYLE="margin-bottom: 0in"><BR> +</P> +<P CLASS="western" STYLE="margin-bottom: 0in"> <FONT FACE="FreeMono, monospace"><FONT SIZE=2 STYLE="font-size: 10pt">Task +t2(1000, TASK_FOREVER, &callback2, &ts);</FONT></FONT></P> +<P CLASS="western" STYLE="margin-bottom: 0in"><BR> +</P> +<P CLASS="western" STYLE="margin-bottom: 0in"> <FONT FACE="FreeMono, monospace"><FONT SIZE=2 STYLE="font-size: 10pt">Task +t3(20, TASK_FOREVER, &callback1, &ts);</FONT></FONT></P> +<P CLASS="western" STYLE="margin-bottom: 0in"><BR> +</P> +<P CLASS="western" STYLE="margin-bottom: 0in"> <FONT FACE="FreeMono, monospace"><FONT SIZE=2 STYLE="font-size: 10pt">Task +t4(1000, TASK_FOREVER, &callback4, &ts);</FONT></FONT></P> +<P CLASS="western" STYLE="margin-bottom: 0in"><BR> +</P> +<P CLASS="western" STYLE="margin-bottom: 0in"> <FONT FACE="FreeMono, monospace"><FONT SIZE=2 STYLE="font-size: 10pt">t3.delay(10);</FONT></FONT></P> +<P CLASS="western" STYLE="margin-bottom: 0in"><BR> +</P> +<P CLASS="western" STYLE="margin-bottom: 0in"><BR> +</P> +<P CLASS="western" STYLE="margin-bottom: 0in"><BR> +</P> +<P CLASS="western" STYLE="margin-bottom: 0in">Note that t1 and t3 +call the same callback method, and are shifted in time by 10 millis. +So effectively callback1 will be called every 10 millis, but would be +"sandwiched" between t2 and t4. +</P> +<P CLASS="western" STYLE="margin-bottom: 0in"><BR> +</P> +<P CLASS="western" STYLE="margin-bottom: 0in"><BR> +</P> +<P CLASS="western" STYLE="margin-bottom: 0in"><BR> +</P> +<P CLASS="western" STYLE="margin-bottom: 0in"><BR> +</P> +<P CLASS="western" STYLE="margin-bottom: 0in">3. Use short efficient +callback methods written for cooperative multitasking.</P> +<P CLASS="western" STYLE="margin-bottom: 0in"><BR> +</P> +<P CLASS="western" STYLE="margin-bottom: 0in"><BR> +</P> +<P CLASS="western" STYLE="margin-bottom: 0in">What that means is:</P> +<P CLASS="western" STYLE="margin-bottom: 0in"><BR> +</P> +<P CLASS="western" STYLE="margin-bottom: 0in"><BR> +</P> +<P CLASS="western" STYLE="margin-bottom: 0in"><BR> +</P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in">a) +<B>DO NOT</B> use Arduino's <FONT FACE="FreeMono, monospace"><FONT SIZE=2 STYLE="font-size: 10pt">delay()</FONT></FONT><FONT FACE="Andale Mono"> +</FONT>function. It is blocking and will hold the entire chain. +Instead break the callback method into two, switch the callback +method of the task where delay is necessary and delay the task by +that number of millis. You get your delay, and other tasks get a +chance to run:</P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR> +</P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR> +</P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR> +</P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in">instead +of:</P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR> +</P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR> +</P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR> +</P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"> + <FONT FACE="FreeMono, monospace"><FONT SIZE=2 STYLE="font-size: 10pt">void +callback() {</FONT></FONT></P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR> +</P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"> + <FONT FACE="FreeMono, monospace"><FONT SIZE=2 STYLE="font-size: 10pt">... +stuff</FONT></FONT></P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR> +</P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"> + <FONT FACE="FreeMono, monospace"><FONT SIZE=2 STYLE="font-size: 10pt">delay(1000);</FONT></FONT></P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR> +</P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"> + <FONT FACE="FreeMono, monospace"><FONT SIZE=2 STYLE="font-size: 10pt">... +more stuff</FONT></FONT></P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR> +</P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"> + <FONT FACE="FreeMono, monospace"><FONT SIZE=2 STYLE="font-size: 10pt">}</FONT></FONT></P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR> +</P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"> + +</P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR> +</P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in">do +this:</P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR> +</P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR> +</P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR> +</P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"> + <FONT FACE="FreeMono, monospace"><FONT SIZE=2 STYLE="font-size: 10pt">void +callback1() {</FONT></FONT></P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR> +</P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"> + <FONT FACE="FreeMono, monospace"><FONT SIZE=2 STYLE="font-size: 10pt">... +stuff</FONT></FONT></P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR> +</P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"> + <FONT FACE="FreeMono, monospace"><FONT SIZE=2 STYLE="font-size: 10pt">t1.setCallback(&callback2);</FONT></FONT></P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR> +</P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"> + <FONT FACE="FreeMono, monospace"><FONT SIZE=2 STYLE="font-size: 10pt">t1.delay(1000);</FONT></FONT></P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR> +</P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"> + <FONT FACE="FreeMono, monospace"><FONT SIZE=2 STYLE="font-size: 10pt">}</FONT></FONT></P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR> +</P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR> +</P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"> + <FONT FACE="FreeMono, monospace"><FONT SIZE=2 STYLE="font-size: 10pt">void +callback2() {</FONT></FONT></P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR> +</P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"> + <FONT FACE="FreeMono, monospace"><FONT SIZE=2 STYLE="font-size: 10pt">... +more stuff</FONT></FONT></P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR> +</P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"> + <FONT FACE="FreeMono, monospace"><FONT SIZE=2 STYLE="font-size: 10pt">t1.setCallback(&callback1);</FONT></FONT></P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR> +</P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"> + <FONT FACE="FreeMono, monospace"><FONT SIZE=2 STYLE="font-size: 10pt">}</FONT></FONT></P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR> +</P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR> +</P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR> +</P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR> +</P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR> +</P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in">b) +Same goes to <FONT FACE="FreeMono, monospace"><FONT SIZE=2 STYLE="font-size: 10pt">pulseIn()</FONT></FONT> +function. If you have to use it, set the timeout parameter such that +it is not a default 1 second. PulseIn functionality could be achieved +via pin interrupts, and that solution is non-blocking.</P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR> +</P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR> +</P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR> +</P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in">c) +Do don run long loops (for or do/while) in you callback methods. Make +the main arduino loop be the loop driver for you:</P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR> +</P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR> +</P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR> +</P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in">instead +of:</P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR> +</P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR> +</P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR> +</P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"> + <FONT FACE="FreeMono, monospace"><FONT SIZE=2 STYLE="font-size: 10pt">void +callback() {</FONT></FONT></P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR> +</P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"> + +</P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR> +</P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"> + <FONT FACE="FreeMono, monospace"><FONT SIZE=2 STYLE="font-size: 10pt">for(int +i=0; i<1000; i++) {</FONT></FONT></P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR> +</P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"> + <FONT FACE="FreeMono, monospace"><FONT SIZE=2 STYLE="font-size: 10pt">... +stuff // one loop action</FONT></FONT></P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR> +</P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"> + <FONT FACE="FreeMono, monospace"><FONT SIZE=2 STYLE="font-size: 10pt">}</FONT></FONT></P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR> +</P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"> + <FONT FACE="FreeMono, monospace"><FONT SIZE=2 STYLE="font-size: 10pt">}</FONT></FONT></P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR> +</P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR> +</P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR> +</P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in">do +this:</P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR> +</P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR> +</P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR> +</P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"> + <FONT FACE="FreeMono, monospace"><FONT SIZE=2 STYLE="font-size: 10pt">Task +t1(TASK_IMMEDIATE, 1000, &callback);</FONT></FONT></P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR> +</P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"> + +</P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR> +</P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"> + <FONT FACE="FreeMono, monospace"><FONT SIZE=2 STYLE="font-size: 10pt">void +callback() {</FONT></FONT></P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR> +</P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"> + <FONT FACE="FreeMono, monospace"><FONT SIZE=2 STYLE="font-size: 10pt">int +i = t1.getRunCounter() -1;</FONT></FONT></P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR> +</P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"> + <FONT FACE="FreeMono, monospace"><FONT SIZE=2 STYLE="font-size: 10pt">... +stuff // one loop action</FONT></FONT></P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR> +</P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"> + <FONT FACE="FreeMono, monospace"><FONT SIZE=2 STYLE="font-size: 10pt">}</FONT></FONT></P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR> +</P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR> +</P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR> +</P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in">or +this:</P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR> +</P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR> +</P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR> +</P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"> + <FONT FACE="FreeMono, monospace"><FONT SIZE=2 STYLE="font-size: 10pt">Task +t1(TASK_IMMEDIATE, 1000, &callback, true, &t1On);</FONT></FONT></P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR> +</P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"> + +</P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR> +</P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"> + <FONT FACE="FreeMono, monospace"><FONT SIZE=2 STYLE="font-size: 10pt">int +i;</FONT></FONT></P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR> +</P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"> + <FONT FACE="FreeMono, monospace"><FONT SIZE=2 STYLE="font-size: 10pt">bool +t1On() {</FONT></FONT></P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR> +</P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"> + <FONT FACE="FreeMono, monospace"><FONT SIZE=2 STYLE="font-size: 10pt">i += 0;</FONT></FONT></P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR> +</P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"> + <FONT FACE="FreeMono, monospace"><FONT SIZE=2 STYLE="font-size: 10pt">return +true;</FONT></FONT></P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR> +</P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"> + <FONT FACE="FreeMono, monospace"><FONT SIZE=2 STYLE="font-size: 10pt">}</FONT></FONT></P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR> +</P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"> + +</P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR> +</P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"> + <FONT FACE="FreeMono, monospace"><FONT SIZE=2 STYLE="font-size: 10pt">void +callback() {</FONT></FONT></P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR> +</P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"> + <FONT FACE="FreeMono, monospace"><FONT SIZE=2 STYLE="font-size: 10pt">... +stuff // one loop action</FONT></FONT></P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR> +</P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"> + <FONT FACE="FreeMono, monospace"><FONT SIZE=2 STYLE="font-size: 10pt">i++;</FONT></FONT></P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR> +</P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"> + <FONT FACE="FreeMono, monospace"><FONT SIZE=2 STYLE="font-size: 10pt">}</FONT></FONT></P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR> +</P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR> +</P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR> +</P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR> +</P> +<P CLASS="western" ALIGN=CENTER STYLE="margin-left: 0.49in; margin-bottom: 0in"> +<B>REMEMBER: you are already inside the loop - take advantage of it. </B> +</P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR> +</P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in">d) +Break long running callback methods into several shorter ones, and +pass control from one to the other via <FONT FACE="FreeMono, monospace"><FONT SIZE=2 STYLE="font-size: 10pt">setCallback() +</FONT></FONT>method:</P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR> +</P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR> +</P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR> +</P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"> + <FONT FACE="FreeMono, monospace"><FONT SIZE=2 STYLE="font-size: 10pt">Task +t1(TASK_IMMEDIATE, TASK_FAREVER, &callback);</FONT></FONT></P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR> +</P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"> + +</P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR> +</P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"> + <FONT FACE="FreeMono, monospace"><FONT SIZE=2 STYLE="font-size: 10pt">void +callback() {</FONT></FONT></P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR> +</P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"> + <FONT FACE="FreeMono, monospace"><FONT SIZE=2 STYLE="font-size: 10pt">... +do some stuff</FONT></FONT></P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR> +</P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"> + <FONT FACE="FreeMono, monospace"><FONT SIZE=2 STYLE="font-size: 10pt">t1.setCallback(&callback_step2);</FONT></FONT></P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR> +</P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"> + <FONT FACE="FreeMono, monospace"><FONT SIZE=2 STYLE="font-size: 10pt">}</FONT></FONT></P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR> +</P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"> + <FONT FACE="FreeMono, monospace"><FONT SIZE=2 STYLE="font-size: 10pt">void +callback_step2() {</FONT></FONT></P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR> +</P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"> + <FONT FACE="FreeMono, monospace"><FONT SIZE=2 STYLE="font-size: 10pt">... +do more stuff</FONT></FONT></P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR> +</P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"> + <FONT FACE="FreeMono, monospace"><FONT SIZE=2 STYLE="font-size: 10pt">t1.setCallback(&callback_step3);</FONT></FONT></P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR> +</P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"> + <FONT FACE="FreeMono, monospace"><FONT SIZE=2 STYLE="font-size: 10pt">}</FONT></FONT></P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR> +</P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"> + <FONT FACE="FreeMono, monospace"><FONT SIZE=2 STYLE="font-size: 10pt">void +callback_step3() {</FONT></FONT></P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR> +</P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"> + <FONT FACE="FreeMono, monospace"><FONT SIZE=2 STYLE="font-size: 10pt">... +do last part of the stuff</FONT></FONT></P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR> +</P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"> + <FONT FACE="FreeMono, monospace"><FONT SIZE=2 STYLE="font-size: 10pt">t1.setCallback(&callback);</FONT></FONT></P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR> +</P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"> + <FONT FACE="FreeMono, monospace"><FONT SIZE=2 STYLE="font-size: 10pt">t1.delay(1000);</FONT></FONT></P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR> +</P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"> + <FONT FACE="FreeMono, monospace"><FONT SIZE=2 STYLE="font-size: 10pt">}</FONT></FONT></P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR> +</P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR> +</P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR> +</P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in">This +will execute all parts of the callback function in three successive +steps, sheduled immediately, but allowing other tasks in the cahin to +run. Notince that task is scheduled to run immediately, and 1 second +period is achieved by delaying the task for 1000 millis at the last +step. +</P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR> +</P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in">Alternatively +you could schedule the task to run every 1000 millis and use +<FONT FACE="FreeMono, monospace"><FONT SIZE=2 STYLE="font-size: 10pt">forceNextIteration()</FONT></FONT> +method in steps 1 and 2 (but not 3!)</P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR> +</P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR> +</P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR> +</P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"> + <FONT FACE="FreeMono, monospace"><FONT SIZE=2 STYLE="font-size: 10pt">Task +t1(1000, TASK_FOREVER, &callback);</FONT></FONT></P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR> +</P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"> + +</P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR> +</P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"> + <FONT FACE="FreeMono, monospace"><FONT SIZE=2 STYLE="font-size: 10pt">void +callback() {</FONT></FONT></P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR> +</P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"> + <FONT FACE="FreeMono, monospace"><FONT SIZE=2 STYLE="font-size: 10pt">... +do some stuff</FONT></FONT></P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR> +</P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"> + <FONT FACE="FreeMono, monospace"><FONT SIZE=2 STYLE="font-size: 10pt">t1.setCallback(&callback_step2);</FONT></FONT></P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR> +</P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"> + <FONT FACE="FreeMono, monospace"><FONT SIZE=2 STYLE="font-size: 10pt">t1.forceNextIteration();</FONT></FONT></P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR> +</P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"> + <FONT FACE="FreeMono, monospace"><FONT SIZE=2 STYLE="font-size: 10pt">}</FONT></FONT></P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR> +</P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"> + <FONT FACE="FreeMono, monospace"><FONT SIZE=2 STYLE="font-size: 10pt">void +callback_step2() {</FONT></FONT></P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR> +</P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"> + <FONT FACE="FreeMono, monospace"><FONT SIZE=2 STYLE="font-size: 10pt">... +do more stuff</FONT></FONT></P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR> +</P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"> + <FONT FACE="FreeMono, monospace"><FONT SIZE=2 STYLE="font-size: 10pt">t1.setCallback(&callback_step3);</FONT></FONT></P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR> +</P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"> + <FONT FACE="FreeMono, monospace"><FONT SIZE=2 STYLE="font-size: 10pt">t1.forceNextIteration();</FONT></FONT></P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR> +</P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"> + <FONT FACE="FreeMono, monospace"><FONT SIZE=2 STYLE="font-size: 10pt">}</FONT></FONT></P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR> +</P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"> + <FONT FACE="FreeMono, monospace"><FONT SIZE=2 STYLE="font-size: 10pt">void +callback_step3() {</FONT></FONT></P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR> +</P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"> + <FONT FACE="FreeMono, monospace"><FONT SIZE=2 STYLE="font-size: 10pt">... +do last part of the stuff</FONT></FONT></P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR> +</P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"> + <FONT FACE="FreeMono, monospace"><FONT SIZE=2 STYLE="font-size: 10pt">t1.setCallback(&callback);</FONT></FONT></P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR> +</P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"> + <FONT FACE="FreeMono, monospace"><FONT SIZE=2 STYLE="font-size: 10pt">}</FONT></FONT></P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR> +</P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR> +</P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR> +</P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR> +</P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR> +</P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in">e) +Compile the library with <FONT FACE="FreeMono, monospace"><FONT SIZE=2 STYLE="font-size: 10pt"><B>_TASK_TIMECRITICAL</B></FONT></FONT> +enabled and check if your tasks are falling behind schedule. If they +are - you need to optimize your code further (or maybe re-evaluate +your schedule). If they are not - all is well and you don't need to +do anything. E.g., I have a spider robot which needs to measure +distance, control motors, and keep track of the angle via querying +gyroscope and accelerometer every 10 ms. The idea was to flash +onboard LED if any of the tasks fall behind. At 10 ms interval for +the gyro the LED does not flash, which means none of the tasks are +blocking the others from starting on time. +</P> +<P CLASS="western" STYLE="margin-bottom: 0in"><BR> +</P> +<P CLASS="western" STYLE="margin-bottom: 0in"><BR> +</P> <P CLASS="western" STYLE="margin-bottom: 0in"><BR> </P> <P CLASS="western" STYLE="margin-bottom: 0in; page-break-after: avoid"> @@ -502,9 +1107,8 @@ is a task which was enabled and requires execution. <P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR> </P> <P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><B>NOTE: -</B><SPAN STYLE="font-weight: normal">if task</SPAN> being enabled is -not assigned to a scheduler and is not part of execution chain, then -task <B>will not</B> be enabled.</P> +</B>if task being enabled is not assigned to a scheduler and is not +part of execution chain, then task <B>will not</B> be enabled.</P> <P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR> </P> <P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><B>NOTE: @@ -513,8 +1117,9 @@ task <B>will not</B> be enabled.</P> must return a value of <B>true</B> for task to be enabled. If <B>OnEnable</B> returns <B>false</B>, task remains disabled. <B>OnEnable</B> is invoked every time <B>enable</B> is called, -regardless if task is already enabled or not. -</P> +regardless if task is already enabled or not. Alignment to current +millis() is performed after <B>OnEnable</B> exits, so any changes to +the interval inside <B>OnEnable</B> is taken into consideration.</P> <P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR> </P> <P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><B>NOTE:</B> @@ -703,8 +1308,7 @@ and number of iterations. default <B>waitForDelayed() </B>sets tasks interval to a supplied value or (if omitted or zero) keeps the current interval, so delayed execution will take place when the event happens. It also sets the -number of <B>iterations to 1</B><SPAN STYLE="font-weight: normal"> by -default if not supplied</SPAN>. +number of <B>iterations to 1</B> by default if not supplied. </P> <P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in">When Status Request object completes, all tasks waiting on it are executed @@ -972,10 +1576,9 @@ statements after <B>execute</B> inside the <B>loop()</B> <P CLASS="western" STYLE="margin-bottom: 0in"><B>bool isOverrun()</B></P> <P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in">If library is compiled with <FONT FACE="Courier New, monospace">_TASK_TIMECRITICAL</FONT> -enabled, this method returns <B>true</B><SPAN STYLE="font-weight: normal"> -if currently invoked task has overrun its scheduled start time when -it was invoked. Returns </SPAN><B>false</B><SPAN STYLE="font-weight: normal"> -if task has been invoked according to schedule.</SPAN></P> +enabled, this method returns <B>true</B> if currently invoked task +has overrun its scheduled start time when it was invoked. Returns +<B>false</B> if task has been invoked according to schedule.</P> <P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR> </P> <P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR> @@ -2145,5 +2748,8 @@ time examples of TaskScheduler are available here:</FONT></FONT></P> </OL> <P CLASS="western" STYLE="margin-bottom: 0in"><BR> </P> +<DIV TYPE=FOOTER> + <P STYLE="margin-top: 0.35in; margin-bottom: 0in"> <SDFIELD TYPE=PAGE SUBTYPE=RANDOM FORMAT=ARABIC>5</SDFIELD></P> +</DIV> </BODY> -</HTML>
\ No newline at end of file +</HTML> diff --git a/library.properties b/library.properties index a442e9d..67b7a7c 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=TaskScheduler -version=1.8.3 +version=1.8.4 author=Anatoli Arkhipenko <arkhipenko@hotmail.com> maintainer=Anatoli Arkhipenko <arkhipenko@hotmail.com> sentence=A light-weight cooperative multitasking library for arduino microcontrollers. diff --git a/src/TaskScheduler.h b/src/TaskScheduler.h index 228a8d0..dbe8dba 100644 --- a/src/TaskScheduler.h +++ b/src/TaskScheduler.h @@ -1,4 +1,4 @@ -// Cooperative multitasking library for Arduino version 1.8.2 +// Cooperative multitasking library for Arduino version 1.8.4 // Copyright (c) 2015 Anatoli Arkhipenko // // Changelog: @@ -57,6 +57,10 @@ // 2015-11-09 - added callback methods prototypes to all examples for Arduino IDE 1.6.6 compatibility // 2015-11-14 - added several constants to be used as task parameters for readability (e.g, TASK_FOREVER, TASK_SECOND, etc.) // 2015-11-14 - significant optimization of the scheduler's execute loop, including millis() rollover fix option +// +// v1.8.4: +// 2015-11-15 - bug fix: Task alignment with millis() for scheduling purposes should be done after OnEnable, not before. Especially since OnEnable method can change the interval +// 2015-11-16 - further optimizations of the task scheduler execute loop /* ============================================ @@ -379,7 +383,6 @@ void Task::setIterations(long aIterations) { void Task::enable() { if (iScheduler) { // activation without active scheduler does not make sense iRunCounter = 0; - iPreviousMillis = millis() - iInterval; if (iOnEnable && !iInOnEnable) { Task *current = iScheduler->iCurrent; iScheduler->iCurrent = this; @@ -391,6 +394,7 @@ void Task::enable() { else { iEnabled = true; } + iPreviousMillis = millis() - iInterval; } } @@ -569,6 +573,7 @@ void Scheduler::execute() { bool idleRun = true; #endif unsigned long targetMillis; + register unsigned long m, i, p; iCurrent = iFirst; @@ -585,13 +590,16 @@ void Scheduler::execute() { iCurrent->disable(); break; } - #ifdef _TASK_STATUS_REQUEST + m = millis(); + p = iCurrent->iPreviousMillis; + i = iCurrent->iInterval; + #ifdef _TASK_STATUS_REQUEST // If StatusRequest object was provided, and still pending, and task is waiting, this task should not run // Otherwise, continue with execution as usual. Tasks waiting to StatusRequest need to be rescheduled according to // how they were placed into waiting state (waitFor or waitForDelayed) if ( iCurrent->iWaiting ) { if ( (iCurrent->iStatusRequest)->pending() ) break; - iCurrent->iPreviousMillis = (iCurrent->iWaiting == _TASK_SR_NODELAY) ? millis()-iCurrent->iInterval : millis(); + iCurrent->iPreviousMillis = (iCurrent->iWaiting == _TASK_SR_NODELAY) ? m - i : m; iCurrent->iWaiting = 0; } #endif @@ -607,20 +615,19 @@ void Scheduler::execute() { // since targetMillis (65) < iPreviousMillis (65000), rollover fix kicks in: // iPreviousMillis(65000) > millis(65500) - iInterval(600) = 64900 - task will not be scheduled - targetMillis = iCurrent->iPreviousMillis + iCurrent->iInterval; + targetMillis = p + i; #ifdef _TASK_ROLLOVER_FIX - if ( targetMillis < iCurrent->iPreviousMillis ) { // targetMillis rolled over! - if ( iCurrent->iPreviousMillis > ( millis() - iCurrent->iInterval) ) break; + if ( targetMillis < p ) { // targetMillis rolled over! + if ( p > ( m - i) ) break; } else #endif - if ( targetMillis > millis() ) break; + if ( targetMillis > m ) break; - iCurrent->iPreviousMillis = targetMillis; #ifdef _TASK_TIMECRITICAL // Updated_previous+current interval should put us into the future, so iOverrun should be positive or zero. // If negative - the task is behind (next execution time is already in the past) - iCurrent->iOverrun = (long) (iCurrent->iPreviousMillis + iCurrent->iInterval - millis()); + iCurrent->iOverrun = (long) ( targetMillis - m + i ); #endif if ( iCurrent->iIterations > 0 ) iCurrent->iIterations--; // do not decrement (-1) being a signal of never-ending task iCurrent->iRunCounter++; @@ -630,6 +637,7 @@ void Scheduler::execute() { idleRun = false; #endif } + iCurrent->iPreviousMillis = targetMillis; } } while (0); //guaranteed single run - allows use of "break" to exit iCurrent = iCurrent->iNext; |
