Advertisement
Guest User

TinyScheduler

a guest
Feb 25th, 2017
150
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 8.94 KB | None | 0 0
  1. /*
  2.  * TaskScheduler.hpp
  3.  *
  4.  * Created: 16.11.2015 3:44:02
  5.  *  Author: dx
  6.  
  7.  * Very simple tiny task scheduler designed with minimal overhead in mind
  8.  * You pay for what you are using only!
  9.  * General use case with default settings:
  10.  *   TinyScheduler< MakeTasklist<Task1, Task2, TaskN> > TaskScheduler;
  11.  
  12.  * Defaults:
  13.  *  timer resolution 8Bit                               Timer8Bit
  14.  *  task disable feature is turned off                  TaskDisable_OFF
  15.  *  critical section is global interrupts disable(AVR)  CriticalSection_IntDisable
  16.  *  task timers are NOT loaded in constructor!          use TS_INIT_TIMERS or ReloadAllTaskTimers()
  17.                                                         see description below                                                  
  18.  * MakeTasklist<Task1, Task2, TaskN> supports up to 16 tasks
  19.  
  20.  * Task must be a class with _STATIC_ uint8_t Period and _STATIC_ Run() func
  21.  * static is required!
  22.  * You may optionally add other functions and variables - this will have no effect on scheduler's work
  23. struct task1
  24. {
  25.     static const uint32_t Period = 22;
  26.     static void Run()
  27.     {   //this is non member function call
  28.         Task1_func();
  29.          
  30.         //also you may call some instance func
  31.         //SomeClass.Foo();
  32.        
  33.         //you may implement task code right here if you want
  34.         //PORTB |= (1<< PINB3);
  35.     }
  36. };
  37.  
  38.  * By default timers are NOT LOADED with task period at scheduler instantiation!
  39.  * You may pass TS_INIT_TIMERS to constructor to fix this:
  40.  *   TinyScheduler< MakeTasklist<Task1, Task2, TaskN> > TaskScheduler(TS_INIT_TIMERS);
  41.  * or call somewhere:
  42.  *   TaskScheduler.ReloadAllTaskTimers(); //preferred way of doing timer initialization. Costs less Flash bytes.
  43.  * TS_INIT_TIMERS method will cost you more Flash bytes! Don't know why constructor is so heavy.
  44.  *
  45.  * Please note: usually TaskScheduler is a global variable(i.e. has static duration) then all timers will be initialized by 0
  46.  * which means _FIRST CALL_ of RunScheduled() will fire up ALL your tasks immidiately and timers will be reloaded.
  47.  * Often it's OK, sometimes not. It's your choice :)
  48.  
  49.  
  50.  * Timer resolution: Timer8Bit, Timer16Bit or Timer32Bit
  51.  *   TinyScheduler< MakeTasklist<Task1, Task2, TaskN>, Timer32Bit > TaskScheduler;
  52.    
  53.  * Task disable feature TaskDisable_ON TaskDisable_OFF
  54.  *   TinyScheduler< MakeTasklist<Task1, Task2, TaskN>, Timer8Bit, TaskDisable_ON > TaskScheduler;
  55.  *   TinyScheduler< MakeTasklist<Task1, Task2, TaskN>, Timer8Bit, TaskDisable_OFF > TaskScheduler; //also valid code
  56.  
  57.  * Critical section implementation
  58.  * ReloadTaskTimer() and RunScheduled() uses critical section to reload task timer.
  59.  * Calling TimerISR() form timer interrupt and RunScheduled() from main() IS NOT THE SAME THREAD! You need critical section in this case!
  60.  * Provided implementations:
  61.  *   CriticalSection_IntDisable - global interrupts disable(AVR). Default setting.
  62.  *   CriticalSection_OFF - does nothing. Useful when TimerISR() and RunScheduled() are called from the same thread.
  63.  * Use as follows:
  64.  *   TinyScheduler< MakeTasklist<Task1, Task2, TaskN>, Timer8Bit, TaskDisable_ON, CriticalSection_OFF > TaskScheduler;
  65.  
  66. //custom critical section implementation example:
  67. struct CriticalSection_Custom
  68. {  
  69.     static void EnterCriticalSection(){ Custom enter implementation };
  70.     static void LeaveCriticalSection(){ Custom leave implementation };
  71. };
  72. */
  73.  
  74. #include <stdint.h>
  75. #include "loki/Typelist.h"
  76. #include "loki/TypeManip.h"
  77.  
  78. #ifndef TASKSCHEDULER_H_
  79. #define TASKSCHEDULER_H_   
  80.    
  81. //encapsulates Loki library for end user
  82. //Use as follows:
  83. //TinyScheduler< MakeTasklist<Task1, Task2, TaskN> > TaskScheduler;
  84. template<   typename T1  = Loki::NullType, typename T2  = Loki::NullType, typename T3  = Loki::NullType,
  85.             typename T4  = Loki::NullType, typename T5  = Loki::NullType, typename T6  = Loki::NullType,
  86.             typename T7  = Loki::NullType, typename T8  = Loki::NullType, typename T9  = Loki::NullType,
  87.             typename T10 = Loki::NullType, typename T11 = Loki::NullType, typename T12 = Loki::NullType,
  88.             typename T13 = Loki::NullType, typename T14 = Loki::NullType, typename T15 = Loki::NullType,
  89.             typename T16 = Loki::NullType >
  90. struct MakeTasklist {
  91.     typedef typename Loki::TL::MakeTypelist<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16>::Result Result;
  92. };
  93. template<> struct MakeTasklist<>{ typedef typename Loki::TL::MakeTypelist<>::Result Result; };
  94.  
  95.  
  96. //you can pass this to TinyScheduler constructor if you want reload timers at construction
  97. //this will cost >= 48 bytes of Flash.
  98. //TinyScheduler< MakeTasklist<Task1, Task2, TaskN> > TaskScheduler( TS_INIT_TIMERS );
  99. enum{ TS_INIT_TIMERS };
  100.  
  101. //TimerResolution template param
  102. struct Timer8Bit{ typedef uint8_t TimerType; };
  103. struct Timer16Bit{ typedef uint16_t TimerType; };
  104. struct Timer32Bit{ typedef uint32_t TimerType; };
  105.  
  106. //TaskDisableFeature template param
  107. struct TaskDisable_ON{};
  108. struct TaskDisable_OFF{};
  109.    
  110. //CriticalSection template param
  111. struct CriticalSection_IntDisable
  112. {
  113.     static void EnterCriticalSection(){ cli(); }; //global interrupt disable
  114.     static void LeaveCriticalSection(){ sei(); }; //global interrupt enable
  115. };
  116. struct CriticalSection_OFF  //dummy
  117. {
  118.     static void EnterCriticalSection(){ };
  119.     static void LeaveCriticalSection(){ };
  120. };
  121.  
  122.    
  123. //To enable empty base optimization TaskDisable feature is moved to dedicated class
  124. //empty base optimization gives us 1 byte RAM when TaskDisableFeature is turned off
  125. //Dummy methods are also static to allow completely optimize them away.
  126. template<typename TList, typename TaskDisableFeature> class TaskDisableImplementation;
  127. template<typename TList>
  128. class TaskDisableImplementation<TList, TaskDisable_OFF>
  129. {  
  130. protected:
  131.     static bool IsTaskEnabled_impl(const int& i){return true;}
  132.     static void TaskDisable_impl(const int& i){}
  133.     static void TaskEnable_impl(const int& i){}
  134. };
  135. template<typename TList>
  136. class TaskDisableImplementation<TList, TaskDisable_ON>
  137. {
  138. protected:
  139.     bool IsTaskEnabled_impl(const int& i){ return !( TaskDisableMask & (1 << i) ); }
  140.     void TaskDisable_impl(const int& i){ TaskDisableMask |= 1 << i; }
  141.     void TaskEnable_impl(const int& i){  TaskDisableMask &= ~(1 << i); }
  142. private:   
  143.     static const int TaskListLen = Loki::TL::Length< typename TList::Result >::value;              
  144.     //select type depending on task list length. To support task list of up to 16 tasks
  145.     typename Loki::Select< (TaskListLen > 8), uint16_t, uint8_t >::Result TaskDisableMask;
  146. };
  147.  
  148. template< typename TList, typename TimerResolution=Timer8Bit,
  149.           typename TaskDisableFeature=TaskDisable_OFF, typename CriticalSection=CriticalSection_IntDisable>
  150. class TinyScheduler : TaskDisableImplementation<TList, TaskDisableFeature>
  151. {
  152. typedef TaskDisableImplementation<TList, TaskDisableFeature> BaseClass;
  153. public:        
  154.     TinyScheduler(){};
  155.        
  156.     //this will fire up when TS_INIT_TIMERS is used
  157.     explicit TinyScheduler(const int& i) { ReloadAll_impl( Loki::Int2Type<TaskListLen-1>() ); }
  158.    
  159.     void RunScheduled(){ RunScheduled_imp( Loki::Int2Type<TaskListLen-1>() ); }
  160.    
  161.     template<typename T>
  162.     void TaskDisable(const T&){ BaseClass::TaskDisable_impl( Loki::TL::IndexOf<TaskList, T>::value ); }    
  163.        
  164.     template<typename T>
  165.     void TaskEnable(const T&){  BaseClass::TaskEnable_impl( Loki::TL::IndexOf<TaskList, T>::value ); }         
  166.    
  167.     void ReloadAllTaskTimers(){ ReloadAll_impl( Loki::Int2Type<TaskListLen-1>() ); }
  168.    
  169.     //sometimes needed(for synchronization)
  170.     template<typename T>
  171.     void ReloadTaskTimer(const T&)
  172.     {      
  173.         CriticalSection::EnterCriticalSection();
  174.         timers[ Loki::TL::IndexOf<TaskList, T>::value ] = T::Period;
  175.         CriticalSection::LeaveCriticalSection();       
  176.     }  
  177.    
  178.     //scheduler heartbeat
  179.     void TimerISR()
  180.     {          
  181.         for(uint8_t i=0; i < TaskListLen; i++) 
  182.             timers[i] = (timers[i]>0)? (timers[i]-1):(timers[i]);          
  183.     }
  184.    
  185. private:                       
  186.     typedef typename TList::Result TaskList;
  187.     static const int TaskListLen = Loki::TL::Length< TaskList >::value;    
  188.        
  189.     typename TimerResolution::TimerType timers[TaskListLen];
  190.    
  191.     TinyScheduler(const TinyScheduler&);
  192.     TinyScheduler& operator=(const TinyScheduler&);
  193.    
  194.     //recursive iteration over TaskList and reload task timers
  195.     template<int I>
  196.     void ReloadAll_impl(Loki::Int2Type<I>)
  197.     {
  198.         ReloadAll_impl( Loki::Int2Type<I-1>() );       
  199.         timers[I] = Loki::TL::TypeAt<TaskList, I>::Result::Period;     
  200.     }  
  201.     void ReloadAll_impl(Loki::Int2Type<0>)
  202.     {      
  203.         timers[0] = Loki::TL::TypeAt<TaskList, 0>::Result::Period; 
  204.     }
  205.    
  206.     //recursive iteration over TaskList and check of task timer, run task if zero
  207.     template<int I>
  208.     void RunScheduled_imp(Loki::Int2Type<I>)
  209.     {          
  210.         RunScheduled_imp( Loki::Int2Type<I-1>() );                                             
  211.         if( BaseClass::IsTaskEnabled_impl(I) )
  212.         {
  213.             typedef typename Loki::TL::TypeAt<TaskList, I>::Result Task;                               
  214.             if( timers[I] == 0 )
  215.             {              
  216.                 Task::Run();               
  217.                 ReloadTaskTimer( Task() );
  218.             }
  219.         }      
  220.     }      
  221.     void RunScheduled_imp(Loki::Int2Type<0>)
  222.     {                          
  223.         if( BaseClass::IsTaskEnabled_impl(0) )
  224.         {
  225.             typedef typename Loki::TL::TypeAt<TaskList, 0>::Result Task;
  226.             if( timers[0] == 0 )
  227.             {
  228.                 Task::Run();               
  229.                 ReloadTaskTimer( Task() );
  230.             }
  231.         }              
  232.     }
  233. };
  234.  
  235. #endif /* TASKSCHEDULER_H_ */
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement