3      Copyright (C) Dean Camera, 2011. 
   5   dean [at] fourwalledcubicle [dot] com 
  10   Copyright 2011  Dean Camera (dean [at] fourwalledcubicle [dot] com) 
  12   Permission to use, copy, modify, distribute, and sell this 
  13   software and its documentation for any purpose is hereby granted 
  14   without fee, provided that the above copyright notice appear in 
  15   all 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 
  32  *  \brief Simple round-robbin pseudo-task scheduler. 
  34  *  Simple round-robbin cooperative scheduler for use in basic projects where non real-time tasks need 
  35  *  to be executed. Each task is executed in sequence, and can be enabled or disabled individually or as a group. 
  37  *  \deprecated This module is deprecated and will be removed in a future library release. 
  40 /** \defgroup Group_Scheduler Simple Task Scheduler - LUFA/Scheduler/Scheduler.h 
  41  *  \brief Simple round-robbin pseudo-task scheduler. 
  43  *  \deprecated This module is deprecated and will be removed in a future library release. 
  45  *  \section Sec_Dependencies Module Source Dependencies 
  46  *  The following files must be built with any user project that uses this module: 
  47  *    - LUFA/Scheduler/Scheduler.c <i>(Makefile source module name: LUFA_SRC_SCHEDULER)</i> 
  49  *  \section Sec_ModDescription Module Description 
  50  *  Simple round-robbin cooperative scheduler for use in basic projects where non real-time tasks need 
  51  *  to be executed. Each task is executed in sequence, and can be enabled or disabled individually or as a group. 
  53  *  For a task to yield it must \c return, thus each task should have persistent data marked with the \c static keyword. 
  55  *  Each LUFA scheduler task should be written similar to an ISR; it should execute quickly (so that no one task 
  56  *  hogs the processor, preventing another from running before some sort of timeout is exceeded). Unlike normal RTOS 
  57  *  tasks, each LUFA scheduler task is a regular function, and thus must be designed to be called, and designed to 
  58  *  return to the calling scheduler function repeatedly. Data which must be preserved between task calls should be 
  59  *  declared as global or (preferably) as a \c static local variable inside the task. 
  61  *  The scheduler consists of a task list, listing all the tasks which can be executed by the scheduler. Once started, 
  62  *  each task is then called one after another, unless the task is stopped by another running task or interrupt. 
  66  *      #include <LUFA/Scheduler/Scheduler.h> 
  68  *      TASK(MyTask1); // Task prototype 
  69  *      TASK(MyTask2); // Task prototype 
  73  *          { .Task = MyTask1, .TaskStatus = TASK_RUN, .GroupID = 1  }, 
  74  *          { .Task = MyTask2, .TaskStatus = TASK_RUN, .GroupID = 1  }, 
  81  *          // Other initialisation here 
  88  *          // Task implementation here 
  93  *          // Task implementation here 
  97  *  If desired, the LUFA scheduler <b>does not need to be used</b> in a LUFA powered application. A more conventional 
  98  *  approach to application design can be used, or a proper scheduling RTOS inserted in the place of the LUFA scheduler. 
  99  *  In the case of the former the USB task must be run manually repeatedly to maintain USB communications, and in the 
 100  *  case of the latter a proper RTOS task must be set up to do the same. 
 105 #ifndef __SCHEDULER_H__ 
 106 #define __SCHEDULER_H__ 
 109                 #include "../Common/Common.h" 
 111         /* Enable C linkage for C++ Compilers: */ 
 112                 #if defined(__cplusplus) 
 116         /* Public Interface - May be used in end-application: */ 
 118                         /** Creates a new scheduler task body or prototype. Should be used in the form: 
 120                          *      TASK(TaskName); // Prototype 
 128                         #define TASK(name)              void name (void) 
 130                         /** Defines a task list array, containing one or more task entries of the type \ref TaskEntry_t. Each task list 
 131                          *  should be encased in curly braces and ended with a comma. 
 137                          *           { .Task = MyTask1, .TaskStatus = TASK_RUN, .GroupID = 1 }, 
 138                          *           // More task entries here 
 142                         #define TASK_LIST               TaskEntry_t Scheduler_TaskList[] = 
 144                         /** Constant, giving the maximum delay in scheduler ticks which can be stored in a variable of type 
 145                          *  \ref SchedulerDelayCounter_t. 
 147                         #define TASK_MAX_DELAY          (MAX_DELAYCTR_COUNT - 1) 
 149                         /** Task status mode constant, for passing to \ref Scheduler_SetTaskMode() or \ref Scheduler_SetGroupTaskMode(). */ 
 150                         #define TASK_RUN                true 
 152                         /** Task status mode constant, for passing to \ref Scheduler_SetTaskMode() or \ref Scheduler_SetGroupTaskMode(). */ 
 153                         #define TASK_STOP               false 
 155                 /* Pseudo-Function Macros: */ 
 156                         #if defined(__DOXYGEN__) 
 157                                 /** Starts the scheduler in its infinite loop, executing running tasks. This should be placed at the end 
 158                                  *  of the user application's \c main() function, as it can never return to the calling function. 
 160                                 void Scheduler_Start(void); 
 162                                 /** Initialises the scheduler so that the scheduler functions can be called before the scheduler itself 
 163                                  *  is started. This must be executed before any scheduler function calls other than \ref Scheduler_Start(), 
 164                                  *  and can be omitted if no such functions could be called before the scheduler is started. 
 166                                 void Scheduler_Init(void); 
 168                                 #define Scheduler_Start()    Scheduler_GoSchedule(TOTAL_TASKS); 
 169                                 #define Scheduler_Init()     Scheduler_InitScheduler(TOTAL_TASKS); 
 173                         /** Type define for a pointer to a scheduler task. */ 
 174                         typedef void (*TaskPtr_t
)(void); 
 176                         /** Type define for a variable which can hold a tick delay value for the scheduler up to the maximum delay 
 179                         typedef uint_least16_t SchedulerDelayCounter_t
; 
 181                         /** \brief Scheduler Task List Entry Structure. 
 183                          *  Structure for holding a single task's information in the scheduler task list. 
 187                                 TaskPtr_t     Task
;       /**< Pointer to the task to execute. */ 
 188                                 bool          TaskStatus
; /**< Status of the task (either TASK_RUN or TASK_STOP). */ 
 189                                 uint_least8_t GroupID
;    /**< Group ID of the task so that its status can be changed as a group. */ 
 192                 /* Global Variables: */ 
 193                         /** Task entry list, containing the scheduler tasks, task statuses and group IDs. Each entry is of type 
 194                          *  \ref TaskEntry_t and can be manipulated as desired, although it is preferred that the proper Scheduler 
 195                          *  functions should be used instead of direct manipulation. 
 197                         extern TaskEntry_t Scheduler_TaskList
[]; 
 199                         /** Contains the total number of tasks in the task list, irrespective of if the task's status is set to 
 200                          *  \ref TASK_RUN or \ref TASK_STOP. 
 202                          *  \note This value should be treated as read-only, and never altered in user-code. 
 204                         extern volatile uint_least8_t Scheduler_TotalTasks
; 
 206                         /**  Contains the current scheduler tick count, for use with the delay functions. If the delay functions 
 207                          *   are used in the user code, this should be incremented each tick period so that the delays can be 
 210                         extern volatile SchedulerDelayCounter_t Scheduler_TickCounter
; 
 212                 /* Inline Functions: */ 
 213                         /** Resets the delay counter value to the current tick count. This should be called to reset the period 
 214                          *  for a delay in a task which is dependant on the current tick value. 
 216                          *  \param[out] DelayCounter  Counter which is storing the starting tick count for a given delay. 
 218                         static inline void Scheduler_ResetDelay(SchedulerDelayCounter_t
* const DelayCounter
) 
 219                                                                 ATTR_NON_NULL_PTR_ARG(1) ATTR_ALWAYS_INLINE
; 
 220                         static inline void Scheduler_ResetDelay(SchedulerDelayCounter_t
* const DelayCounter
) 
 222                                 ATOMIC_BLOCK(ATOMIC_RESTORESTATE
) 
 224                                         *DelayCounter 
= Scheduler_TickCounter
; 
 228                 /* Function Prototypes: */ 
 229                         /** Determines if the given tick delay has elapsed, based on the given delay period and tick counter value. 
 231                          *  \param[in] Delay         The delay to test for, measured in ticks. 
 232                          *  \param[in] DelayCounter  The counter which is storing the starting tick value for the delay. 
 234                          *  \return Boolean \c true if the delay has elapsed, \c false otherwise. 
 238                          *      static SchedulerDelayCounter_t DelayCounter = 10000; // Force immediate run on start-up 
 240                          *      // Task runs every 10000 ticks, 10 seconds for this demo 
 241                          *      if (Scheduler_HasDelayElapsed(10000, &DelayCounter)) 
 243                          *           // Code to execute after delay interval elapsed here 
 247                         bool Scheduler_HasDelayElapsed(const uint_least16_t Delay
, 
 248                                                        SchedulerDelayCounter_t
* const DelayCounter
) 
 249                                                        ATTR_WARN_UNUSED_RESULT 
ATTR_NON_NULL_PTR_ARG(2); 
 251                         /** Sets the task mode for a given task. 
 253                          *  \param[in] Task        Name of the task whose status is to be changed. 
 254                          *  \param[in] TaskStatus  New task status for the task (\ref TASK_RUN or \ref TASK_STOP). 
 256                         void Scheduler_SetTaskMode(const TaskPtr_t Task
, 
 257                                                    const bool TaskStatus
); 
 259                         /** Sets the task mode for a given task group ID, allowing for an entire group of tasks to have their 
 260                          *  statuses changed at once. 
 262                          *  \param[in] GroupID     Value of the task group ID whose status is to be changed. 
 263                          *  \param[in] TaskStatus  New task status for tasks in the specified group (\ref TASK_RUN or \ref TASK_STOP). 
 265                         void Scheduler_SetGroupTaskMode(const uint_least8_t GroupID
, 
 266                                                         const bool TaskStatus
); 
 268         /* Private Interface - For use in library only: */ 
 269         #if !defined(__DOXYGEN__) 
 271                         #define TOTAL_TASKS                       (sizeof(Scheduler_TaskList) / sizeof(TaskEntry_t)) 
 272                         #define MAX_DELAYCTR_COUNT                UINT_LEAST16_MAX 
 274                 /* Inline Functions: */ 
 275                         static inline void Scheduler_InitScheduler(const uint_least8_t TotalTasks
) ATTR_ALWAYS_INLINE
; 
 276                         static inline void Scheduler_InitScheduler(const uint_least8_t TotalTasks
) 
 278                                 Scheduler_TotalTasks 
= TotalTasks
; 
 281                         static inline void Scheduler_GoSchedule(const uint_least8_t TotalTasks
) 
 282                                                                 ATTR_NO_RETURN ATTR_ALWAYS_INLINE ATTR_DEPRECATED
; 
 283                         static inline void Scheduler_GoSchedule(const uint_least8_t TotalTasks
) 
 285                                 Scheduler_InitScheduler(TotalTasks
); 
 289                                         TaskEntry_t
* CurrTask 
= &Scheduler_TaskList
[0]; 
 291                                         while (CurrTask 
!= &Scheduler_TaskList
[TotalTasks
]) 
 293                                                 if (CurrTask
->TaskStatus 
== TASK_RUN
) 
 302         /* Disable C linkage for C++ Compilers: */ 
 303                 #if defined(__cplusplus)