3      Copyright (C) Dean Camera, 2009. 
   5   dean [at] fourwalledcubicle [dot] com 
   6       www.fourwalledcubicle.com 
  10   Copyright 2009  Dean Camera (dean [at] fourwalledcubicle [dot] com) 
  12   Permission to use, copy, modify, and distribute this software 
  13   and its documentation for any purpose and without fee is hereby 
  14   granted, provided that the above copyright notice appear in all 
  15   copies and that both that the copyright notice and this 
  16   permission notice and warranty disclaimer appear in supporting 
  17   documentation, and that the name of the author not be used in 
  18   advertising or publicity pertaining to distribution of the 
  19   software without specific, written prior permission. 
  21   The author disclaim all warranties with regard to this 
  22   software, including all implied warranties of merchantability 
  23   and fitness.  In no event shall the author be liable for any 
  24   special, indirect or consequential damages or any damages 
  25   whatsoever resulting from loss of use, data or profits, whether 
  26   in an action of contract, negligence or other tortious action, 
  27   arising out of or in connection with the use or performance of 
  33  *  Simple round-robbin cooperative scheduler for use in basic projects where non real-time tasks need 
  34  *  to be executed. Each task is executed in sequence, and can be enabled or disabled individually or as a group. 
  37 /** @defgroup Group_Scheduler Simple Task Scheduler - LUFA/Scheduler/Scheduler.h 
  39  *  \section Sec_Dependencies Module Source Dependencies 
  40  *  The following files must be built with any user project that uses this module: 
  41  *    - LUFA/Scheduler/Scheduler.c 
  43  *  \section Module Description 
  44  *  Simple round-robbin cooperative scheduler for use in basic projects where non real-time tasks need 
  45  *  to be executed. Each task is executed in sequence, and can be enabled or disabled individually or as a group. 
  47  *  For a task to yield it must return, thus each task should have persistent data marked with the static attribute. 
  51  *      #include <LUFA/Scheduler/Scheduler.h> 
  58  *              { .Task = MyTask1, .TaskStatus = TASK_RUN, .GroupID = 1  }, 
  59  *              { .Task = MyTask2, .TaskStatus = TASK_RUN, .GroupID = 1  }, 
  69  *              // Implementation Here 
  74  *              // Implementation Here 
  81 #ifndef __SCHEDULER_H__ 
  82 #define __SCHEDULER_H__ 
  88                 #include <util/atomic.h> 
  90                 #include "../Common/Common.h" 
  92         /* Enable C linkage for C++ Compilers: */ 
  93                 #if defined(__cplusplus) 
  97         /* Public Interface - May be used in end-application: */ 
  99                         /** Creates a new scheduler task body or prototype. Should be used in the form: 
 101                          *      TASK(TaskName); // Prototype 
 109                         #define TASK(name)                        void name (void) 
 111                         /** Defines a task list array, containing one or more task entries of the type TaskEntry_t. Each task list 
 112                          *  should be encased in curly braces and ended with a comma. 
 118                          *           { .Task = MyTask1, .TaskStatus = TASK_RUN, .GroupID = 1 }, 
 119                          *           // More task entries here 
 123                         #define TASK_LIST                         TaskEntry_t Scheduler_TaskList[] =  
 125                         /** Constant, giving the maximum delay in scheduler ticks which can be stored in a variable of type 
 126                          *  SchedulerDelayCounter_t. 
 128                         #define TASK_MAX_DELAY                    (MAX_DELAYCTR_COUNT - 1) 
 130                         /** Task status mode constant, for passing to Scheduler_SetTaskMode() or Scheduler_SetGroupTaskMode(). */ 
 131                         #define TASK_RUN                          true 
 133                         /** Task status mode constant, for passing to Scheduler_SetTaskMode() or Scheduler_SetGroupTaskMode(). */ 
 134                         #define TASK_STOP                         false 
 136                 /* Pseudo-Function Macros: */ 
 137                         #if defined(__DOXYGEN__) 
 138                                 /** Starts the scheduler in its infinite loop, executing running tasks. This should be placed at the end 
 139                                  *  of the user application's main() function, as it can never return to the calling function. 
 141                                 void Scheduler_Start(void); 
 143                                 /** Initializes the scheduler so that the scheduler functions can be called before the scheduler itself 
 144                                  *  is started. This must be executed before any scheduler function calls other than Scheduler_Start(), 
 145                                  *  and can be omitted if no such functions could be called before the scheduler is started. 
 147                                 void Scheduler_Init(void); 
 149                                 #define Scheduler_Start()                 Scheduler_GoSchedule(TOTAL_TASKS); 
 151                                 #define Scheduler_Init()                  Scheduler_InitScheduler(TOTAL_TASKS); 
 155                         /** Type define for a pointer to a scheduler task. */ 
 156                         typedef void (*TaskPtr_t
)(void); 
 158                         /** Type define for a variable which can hold a tick delay value for the scheduler up to the maximum delay 
 161                         typedef uint16_t SchedulerDelayCounter_t
; 
 163                         /** Structure for holding a single task's information in the scheduler task list. */ 
 166                                 TaskPtr_t Task
;       /**< Pointer to the task to execute. */ 
 167                                 bool      TaskStatus
; /**< Status of the task (either TASK_RUN or TASK_STOP). */ 
 168                                 uint8_t   GroupID
;    /**< Group ID of the task so that its status can be changed as a group. */ 
 171                 /* Global Variables: */ 
 172                         /** Task entry list, containing the scheduler tasks, task statuses and group IDs. Each entry is of type 
 173                          *  TaskEntry_t and can be manipulated as desired, although it is preferential that the proper Scheduler 
 174                          *  functions should be used instead of direct manipulation. 
 176                         extern          TaskEntry_t               Scheduler_TaskList
[]; 
 178                         /** Contains the total number of tasks in the task list, irrespective of if the task's status is set to 
 179                          *  TASK_RUN or TASK_STOP. 
 181                          *  \note This value should be treated as read-only, and never altered in user-code. 
 183                         extern volatile uint8_t                   Scheduler_TotalTasks
; 
 185                         /**  Contains the current scheduler tick count, for use with the delay functions. If the delay functions 
 186                          *   are used in the user code, this should be incremented each tick period so that the delays can be 
 189                         extern volatile SchedulerDelayCounter_t   Scheduler_TickCounter
; 
 191                 /* Inline Functions: */ 
 192                         /** Resets the delay counter value to the current tick count. This should be called to reset the period 
 193                          *  for a delay in a task which is dependant on the current tick value. 
 195                          *  \param DelayCounter  Counter which is storing the starting tick count for a given delay. 
 197                         static inline void Scheduler_ResetDelay(SchedulerDelayCounter_t
* const DelayCounter
) 
 198                                                                 ATTR_NON_NULL_PTR_ARG(1) ATTR_ALWAYS_INLINE
; 
 199                         static inline void Scheduler_ResetDelay(SchedulerDelayCounter_t
* const DelayCounter
) 
 201                                 ATOMIC_BLOCK(ATOMIC_RESTORESTATE
) 
 203                                         *DelayCounter 
= Scheduler_TickCounter
; 
 207                 /* Function Prototypes: */ 
 208                         /** Determines if the given tick delay has elapsed, based on the given . 
 210                          *  \param Delay         The delay to test for, measured in ticks 
 211                          *  \param DelayCounter  The counter which is storing the starting tick value for the delay 
 213                          *  \return Boolean true if the delay has elapsed, false otherwise 
 217                          *      static SchedulerDelayCounter_t DelayCounter = 10000; // Force immediate run on start-up 
 219                          *      // Task runs every 10000 ticks, 10 seconds for this demo 
 220                          *      if (Scheduler_HasDelayElapsed(10000, &DelayCounter)) 
 222                          *           // Code to execute after delay interval elapsed here 
 226                         bool Scheduler_HasDelayElapsed(const uint16_t Delay
, 
 227                                                        SchedulerDelayCounter_t
* const DelayCounter
) 
 228                                                                                    ATTR_WARN_UNUSED_RESULT 
ATTR_NON_NULL_PTR_ARG(2); 
 230                         /** Sets the task mode for a given task. 
 232                          *  \param Task        Name of the task whose status is to be changed 
 233                          *  \param TaskStatus  New task status for the task (TASK_RUN or TASK_STOP) 
 235                         void Scheduler_SetTaskMode(const TaskPtr_t Task
, const bool TaskStatus
); 
 237                         /** Sets the task mode for a given task group ID, allowing for an entire group of tasks to have their 
 238                          *  statuses changed at once. 
 240                          *  \param GroupID     Value of the task group ID whose status is to be changed 
 241                          *  \param TaskStatus  New task status for tasks in the specified group (TASK_RUN or TASK_STOP) 
 243                         void Scheduler_SetGroupTaskMode(const uint8_t GroupID
, const bool TaskStatus
); 
 245         /* Private Interface - For use in library only: */               
 246         #if !defined(__DOXYGEN__) 
 248                         #define TOTAL_TASKS                       (sizeof(Scheduler_TaskList) / sizeof(TaskEntry_t)) 
 249                         #define MAX_DELAYCTR_COUNT                0xFFFF 
 251                 /* Inline Functions: */ 
 252                         static inline void Scheduler_InitScheduler(const uint8_t TotalTasks
) ATTR_ALWAYS_INLINE
; 
 253                         static inline void Scheduler_InitScheduler(const uint8_t TotalTasks
) 
 255                                 Scheduler_TotalTasks 
= TotalTasks
; 
 258                         static inline void Scheduler_GoSchedule(const uint8_t TotalTasks
) ATTR_NO_RETURN ATTR_ALWAYS_INLINE
; 
 259                         static inline void Scheduler_GoSchedule(const uint8_t TotalTasks
) 
 261                                 Scheduler_InitScheduler(TotalTasks
); 
 265                                         TaskEntry_t
* CurrTask 
= &Scheduler_TaskList
[0]; 
 267                                         while (CurrTask 
!= &Scheduler_TaskList
[TotalTasks
]) 
 269                                                 if (CurrTask
->TaskStatus 
== TASK_RUN
) 
 278         /* Disable C linkage for C++ Compilers: */ 
 279                 #if defined(__cplusplus)