Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /*
- * TaskScheduler.hpp
- *
- * Created: 16.11.2015 3:44:02
- * Author: dx
- * Very simple tiny task scheduler designed with minimal overhead in mind
- * You pay for what you are using only!
- * General use case with default settings:
- * TinyScheduler< MakeTasklist<Task1, Task2, TaskN> > TaskScheduler;
- * Defaults:
- * timer resolution 8Bit Timer8Bit
- * task disable feature is turned off TaskDisable_OFF
- * critical section is global interrupts disable(AVR) CriticalSection_IntDisable
- * task timers are NOT loaded in constructor! use TS_INIT_TIMERS or ReloadAllTaskTimers()
- see description below
- * MakeTasklist<Task1, Task2, TaskN> supports up to 16 tasks
- * Task must be a class with _STATIC_ uint8_t Period and _STATIC_ Run() func
- * static is required!
- * You may optionally add other functions and variables - this will have no effect on scheduler's work
- struct task1
- {
- static const uint32_t Period = 22;
- static void Run()
- { //this is non member function call
- Task1_func();
- //also you may call some instance func
- //SomeClass.Foo();
- //you may implement task code right here if you want
- //PORTB |= (1<< PINB3);
- }
- };
- * By default timers are NOT LOADED with task period at scheduler instantiation!
- * You may pass TS_INIT_TIMERS to constructor to fix this:
- * TinyScheduler< MakeTasklist<Task1, Task2, TaskN> > TaskScheduler(TS_INIT_TIMERS);
- * or call somewhere:
- * TaskScheduler.ReloadAllTaskTimers(); //preferred way of doing timer initialization. Costs less Flash bytes.
- * TS_INIT_TIMERS method will cost you more Flash bytes! Don't know why constructor is so heavy.
- *
- * Please note: usually TaskScheduler is a global variable(i.e. has static duration) then all timers will be initialized by 0
- * which means _FIRST CALL_ of RunScheduled() will fire up ALL your tasks immidiately and timers will be reloaded.
- * Often it's OK, sometimes not. It's your choice :)
- * Timer resolution: Timer8Bit, Timer16Bit or Timer32Bit
- * TinyScheduler< MakeTasklist<Task1, Task2, TaskN>, Timer32Bit > TaskScheduler;
- * Task disable feature TaskDisable_ON TaskDisable_OFF
- * TinyScheduler< MakeTasklist<Task1, Task2, TaskN>, Timer8Bit, TaskDisable_ON > TaskScheduler;
- * TinyScheduler< MakeTasklist<Task1, Task2, TaskN>, Timer8Bit, TaskDisable_OFF > TaskScheduler; //also valid code
- * Critical section implementation
- * ReloadTaskTimer() and RunScheduled() uses critical section to reload task timer.
- * Calling TimerISR() form timer interrupt and RunScheduled() from main() IS NOT THE SAME THREAD! You need critical section in this case!
- * Provided implementations:
- * CriticalSection_IntDisable - global interrupts disable(AVR). Default setting.
- * CriticalSection_OFF - does nothing. Useful when TimerISR() and RunScheduled() are called from the same thread.
- * Use as follows:
- * TinyScheduler< MakeTasklist<Task1, Task2, TaskN>, Timer8Bit, TaskDisable_ON, CriticalSection_OFF > TaskScheduler;
- //custom critical section implementation example:
- struct CriticalSection_Custom
- {
- static void EnterCriticalSection(){ Custom enter implementation };
- static void LeaveCriticalSection(){ Custom leave implementation };
- };
- */
- #include <stdint.h>
- #include "loki/Typelist.h"
- #include "loki/TypeManip.h"
- #ifndef TASKSCHEDULER_H_
- #define TASKSCHEDULER_H_
- //encapsulates Loki library for end user
- //Use as follows:
- //TinyScheduler< MakeTasklist<Task1, Task2, TaskN> > TaskScheduler;
- template< typename T1 = Loki::NullType, typename T2 = Loki::NullType, typename T3 = Loki::NullType,
- typename T4 = Loki::NullType, typename T5 = Loki::NullType, typename T6 = Loki::NullType,
- typename T7 = Loki::NullType, typename T8 = Loki::NullType, typename T9 = Loki::NullType,
- typename T10 = Loki::NullType, typename T11 = Loki::NullType, typename T12 = Loki::NullType,
- typename T13 = Loki::NullType, typename T14 = Loki::NullType, typename T15 = Loki::NullType,
- typename T16 = Loki::NullType >
- struct MakeTasklist {
- typedef typename Loki::TL::MakeTypelist<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16>::Result Result;
- };
- template<> struct MakeTasklist<>{ typedef typename Loki::TL::MakeTypelist<>::Result Result; };
- //you can pass this to TinyScheduler constructor if you want reload timers at construction
- //this will cost >= 48 bytes of Flash.
- //TinyScheduler< MakeTasklist<Task1, Task2, TaskN> > TaskScheduler( TS_INIT_TIMERS );
- enum{ TS_INIT_TIMERS };
- //TimerResolution template param
- struct Timer8Bit{ typedef uint8_t TimerType; };
- struct Timer16Bit{ typedef uint16_t TimerType; };
- struct Timer32Bit{ typedef uint32_t TimerType; };
- //TaskDisableFeature template param
- struct TaskDisable_ON{};
- struct TaskDisable_OFF{};
- //CriticalSection template param
- struct CriticalSection_IntDisable
- {
- static void EnterCriticalSection(){ cli(); }; //global interrupt disable
- static void LeaveCriticalSection(){ sei(); }; //global interrupt enable
- };
- struct CriticalSection_OFF //dummy
- {
- static void EnterCriticalSection(){ };
- static void LeaveCriticalSection(){ };
- };
- //To enable empty base optimization TaskDisable feature is moved to dedicated class
- //empty base optimization gives us 1 byte RAM when TaskDisableFeature is turned off
- //Dummy methods are also static to allow completely optimize them away.
- template<typename TList, typename TaskDisableFeature> class TaskDisableImplementation;
- template<typename TList>
- class TaskDisableImplementation<TList, TaskDisable_OFF>
- {
- protected:
- static bool IsTaskEnabled_impl(const int& i){return true;}
- static void TaskDisable_impl(const int& i){}
- static void TaskEnable_impl(const int& i){}
- };
- template<typename TList>
- class TaskDisableImplementation<TList, TaskDisable_ON>
- {
- protected:
- bool IsTaskEnabled_impl(const int& i){ return !( TaskDisableMask & (1 << i) ); }
- void TaskDisable_impl(const int& i){ TaskDisableMask |= 1 << i; }
- void TaskEnable_impl(const int& i){ TaskDisableMask &= ~(1 << i); }
- private:
- static const int TaskListLen = Loki::TL::Length< typename TList::Result >::value;
- //select type depending on task list length. To support task list of up to 16 tasks
- typename Loki::Select< (TaskListLen > 8), uint16_t, uint8_t >::Result TaskDisableMask;
- };
- template< typename TList, typename TimerResolution=Timer8Bit,
- typename TaskDisableFeature=TaskDisable_OFF, typename CriticalSection=CriticalSection_IntDisable>
- class TinyScheduler : TaskDisableImplementation<TList, TaskDisableFeature>
- {
- typedef TaskDisableImplementation<TList, TaskDisableFeature> BaseClass;
- public:
- TinyScheduler(){};
- //this will fire up when TS_INIT_TIMERS is used
- explicit TinyScheduler(const int& i) { ReloadAll_impl( Loki::Int2Type<TaskListLen-1>() ); }
- void RunScheduled(){ RunScheduled_imp( Loki::Int2Type<TaskListLen-1>() ); }
- template<typename T>
- void TaskDisable(const T&){ BaseClass::TaskDisable_impl( Loki::TL::IndexOf<TaskList, T>::value ); }
- template<typename T>
- void TaskEnable(const T&){ BaseClass::TaskEnable_impl( Loki::TL::IndexOf<TaskList, T>::value ); }
- void ReloadAllTaskTimers(){ ReloadAll_impl( Loki::Int2Type<TaskListLen-1>() ); }
- //sometimes needed(for synchronization)
- template<typename T>
- void ReloadTaskTimer(const T&)
- {
- CriticalSection::EnterCriticalSection();
- timers[ Loki::TL::IndexOf<TaskList, T>::value ] = T::Period;
- CriticalSection::LeaveCriticalSection();
- }
- //scheduler heartbeat
- void TimerISR()
- {
- for(uint8_t i=0; i < TaskListLen; i++)
- timers[i] = (timers[i]>0)? (timers[i]-1):(timers[i]);
- }
- private:
- typedef typename TList::Result TaskList;
- static const int TaskListLen = Loki::TL::Length< TaskList >::value;
- typename TimerResolution::TimerType timers[TaskListLen];
- TinyScheduler(const TinyScheduler&);
- TinyScheduler& operator=(const TinyScheduler&);
- //recursive iteration over TaskList and reload task timers
- template<int I>
- void ReloadAll_impl(Loki::Int2Type<I>)
- {
- ReloadAll_impl( Loki::Int2Type<I-1>() );
- timers[I] = Loki::TL::TypeAt<TaskList, I>::Result::Period;
- }
- void ReloadAll_impl(Loki::Int2Type<0>)
- {
- timers[0] = Loki::TL::TypeAt<TaskList, 0>::Result::Period;
- }
- //recursive iteration over TaskList and check of task timer, run task if zero
- template<int I>
- void RunScheduled_imp(Loki::Int2Type<I>)
- {
- RunScheduled_imp( Loki::Int2Type<I-1>() );
- if( BaseClass::IsTaskEnabled_impl(I) )
- {
- typedef typename Loki::TL::TypeAt<TaskList, I>::Result Task;
- if( timers[I] == 0 )
- {
- Task::Run();
- ReloadTaskTimer( Task() );
- }
- }
- }
- void RunScheduled_imp(Loki::Int2Type<0>)
- {
- if( BaseClass::IsTaskEnabled_impl(0) )
- {
- typedef typename Loki::TL::TypeAt<TaskList, 0>::Result Task;
- if( timers[0] == 0 )
- {
- Task::Run();
- ReloadTaskTimer( Task() );
- }
- }
- }
- };
- #endif /* TASKSCHEDULER_H_ */
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement