Very simple cooperative round-robin task scheduler. See examples.

Dependents:   Garage_Control

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers SimpleScheduler.h Source File

SimpleScheduler.h

00001 /*
00002     Copyright (c) 2011 Andy Kirkham
00003  
00004     Permission is hereby granted, free of charge, to any person obtaining a copy
00005     of this software and associated documentation files (the "Software"), to deal
00006     in the Software without restriction, including without limitation the rights
00007     to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
00008     copies of the Software, and to permit persons to whom the Software is
00009     furnished to do so, subject to the following conditions:
00010  
00011     The above copyright notice and this permission notice shall be included in
00012     all copies or substantial portions of the Software.
00013  
00014     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
00015     IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
00016     FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
00017     AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
00018     LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
00019     OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
00020     THE SOFTWARE.
00021     
00022     @file          SimpleScheduler.h 
00023     @purpose       Simple round-robin cooperative scheduler
00024     @version       see ChangeLog.c
00025     @date          Mar 2011
00026     @author        Andy Kirkham
00027 */
00028 
00029 #ifndef AJK_SIMPLESCHEDULER_H
00030 #define AJK_SIMPLESCHEDULER_H
00031 
00032 #include "mbed.h"
00033 #include <list>
00034 #include "STcallback.h"
00035 
00036 namespace AjK {
00037 
00038 /** SimpleTask
00039  *
00040  * A defined function task requires a "holder" for SimpleScheduler
00041  * to manage it. This is the holder class.
00042  *
00043  * @see SimpleScheduler
00044  * @see example1.h
00045  * @see example2.h
00046  * @see example3.h
00047  * @see example4.h
00048  * @see http://mbed.org/cookbook/SimpleScheduler
00049  *
00050  * @code
00051  *     SimpleTask *task = new SimpleTask(100);
00052  *     task->attach(func);
00053  * @endcode
00054  * @code
00055  *     SimpleTask *task = new SimpleTask(100, func); // Every 100ms
00056  *     SimpleTask *task = new SimpleTask(1.0, func); // Every 1second
00057  * @endcode
00058  * 
00059  * When creating new SimpleTasks you pass the time as a frequency
00060  * of how often to call the task function. If the time is an integer
00061  * then milliseconds is assumed. If the number you pass is a read (double)
00062  * number then the time assumed is seconds.
00063  */
00064 class SimpleTask {
00065 public:
00066 
00067     friend class SimpleScheduler;
00068     
00069     void attach(void (*fptr)(SimpleTask *pST)) {        
00070         _callback->attach(fptr);
00071     }
00072     
00073     template<typename T>
00074     void attach(T* tptr, void (T::*mptr)(SimpleTask *pST)) {  
00075         if((mptr != NULL) && (tptr != NULL)) { 
00076             _callback->attach(tptr, mptr);
00077         }        
00078     }
00079     
00080     bool suspend(bool b) {
00081         bool prev = _suspended;
00082         _suspended = b;
00083         return prev;
00084     }
00085     
00086     // Constructor with frequency in miliseconds
00087     SimpleTask(int f) { init(f); }
00088     
00089     // Constructor with frequency in miliseconds
00090     SimpleTask(double f) { init(1000.0 * f); }
00091     
00092     // Constructor with frequency in miliseconds and function
00093     SimpleTask(int f, void (*fptr)(SimpleTask *pST)) { 
00094         init(f); 
00095         _callback->attach(fptr);
00096     }
00097     
00098     // Constructor with frequency in miliseconds and obj/method
00099     template<typename T>
00100     SimpleTask(int f, T* tptr, void (T::*mptr)(SimpleTask *pST)) {  
00101         init(f);
00102         if((mptr != NULL) && (tptr != NULL)) { 
00103             _callback->attach(tptr, mptr);
00104         }        
00105     }
00106     
00107     // Constructor with frequency in miliseconds and function to call
00108     SimpleTask(double f, void (*fptr)(SimpleTask *pST)) { 
00109         init(f * 1000.0); 
00110         _callback->attach(fptr);
00111     }
00112     
00113     // Constructor with frequency in miliseconds and obj/method to call
00114     template<typename T>
00115     SimpleTask(double f, T* tptr, void (T::*mptr)(SimpleTask *pST)) {  
00116         init(f * 1000.0);
00117         if((mptr != NULL) && (tptr != NULL)) { 
00118             _callback->attach(tptr, mptr);
00119         }        
00120     }
00121     
00122     ~SimpleTask() { 
00123         delete(_callback);
00124     }
00125     
00126 protected:
00127     STcallback      *_callback;
00128     uint32_t        _counter;
00129     uint32_t        _reload;
00130     bool            _suspended;
00131     
00132     void init(int f = 0) {
00133         _counter = f;
00134         _reload = f;
00135         _suspended = false;
00136         _callback = new STcallback;
00137     }
00138 };
00139 
00140 /** SimpleScheduler
00141  *
00142  * Manages a set of function or class.methods as tasks to
00143  * be called at a scheduled frquency. Simple round-robin
00144  * task caller. Note, it's cooperative. That means your
00145  * task functions must return BEFORE another task can be
00146  * called.
00147  *
00148  * @see http://mbed.org/cookbook/SimpleScheduler
00149  * @see example1.h
00150  * @see example2.h
00151  *
00152  * @code
00153  * #include "mbed.h"
00154  * #include "SimpleScheduler.h"
00155  * 
00156  * DigitalOut led1(LED1);
00157  * DigitalOut led2(LED2);
00158  * DigitalOut led3(LED3);
00159  * 
00160  * void f1(SimpleTask *task) { led1 = !led1; }
00161  * void f2(SimpleTask *task) { led2 = !led2; }
00162  * void f3(SimpleTask *task) { led3 = !led3; }
00163  * 
00164  * SimpleScheduler *scheduler;
00165  * 
00166  * int main() {
00167  * 
00168  *     scheduler = new SimpleScheduler;
00169  *     
00170  *     scheduler
00171  *         ->addTask( new SimpleTask(0,   f1) ) // As often as possible
00172  *         ->addTask( new SimpleTask(200, f2) ) // Every 200milliseconds
00173  *         ->addTask( new SimpleTask(1.0, f3) ) // Once a second
00174  *     ;
00175  *     
00176  *     scheduler->run();    
00177  * }
00178  * @endcode
00179  */
00180 class SimpleScheduler {
00181 protected:
00182     Ticker _tick;
00183     list<SimpleTask *> _tasks;
00184     list<SimpleTask *>::iterator _itor;
00185     
00186     friend class Ticker;
00187     
00188     void ticktock(void) {
00189         for (list<SimpleTask *>::iterator itor = _tasks.begin(); itor != _tasks.end(); ++itor) {
00190             if ((*itor)->_counter && !(*itor)->_suspended) {
00191                 (*itor)->_counter--;
00192             }                
00193         }
00194     }
00195      
00196 public:
00197     
00198     SimpleScheduler * addTask(SimpleTask *t) {
00199         _tasks.push_back(t);
00200         return this;
00201     }
00202     
00203     void run(void) {        
00204         _tick.attach_us(this, &SimpleScheduler::ticktock, 1000);
00205         while(1) {
00206             for (list<SimpleTask *>::iterator itor = _tasks.begin(); itor != _tasks.end(); ++itor) {
00207                 if((*itor)->_counter == 0) {
00208                     (*itor)->_counter = (*itor)->_reload;
00209                     if (!(*itor)->_suspended) {
00210                         (*itor)->_callback->call((*itor));  
00211                     }                  
00212                 }
00213             }
00214         }
00215     }
00216 };
00217 
00218 }; // namespace AjK ends.
00219 
00220 using namespace AjK;
00221 
00222 #endif