Arduino-Scheduler
Portable Collaborative Multi-Tasking Scheduler for Arduino
Scheduler.cpp
Go to the documentation of this file.
1 
19 #include "Scheduler.h"
20 #include <Arduino.h>
21 
22 // Configuration: SRAM and heap handling
23 #if defined(TEENSYDUINO)
24 #undef ARDUINO_ARCH_AVR
25 #define TEENSY_ARCH_ARM
26 #if defined(__MK20DX256__)
27 #define RAMEND 0x20008000
28 #elif defined(__MK64FX512__)
29 #define RAMEND 0x20020000
30 #elif defined(__MK66FX1M0__)
31 #define RAMEND 0x20030000
32 #endif
33 
34 #elif defined(ARDUINO_ARCH_AVR)
35 extern int __heap_start, *__brkval;
36 extern char* __malloc_heap_end;
37 extern size_t __malloc_margin;
38 
39 #elif defined(ARDUINO_ARCH_SAM)
40 #if !defined(RAMEND)
41 #define RAMEND 0x20088000
42 #endif
43 #elif defined(ARDUINO_ARCH_SAMD)
44 #if !defined(RAMEND)
45 #define RAMEND 0x20008000
46 #endif
47 #endif
48 
49 // Stack magic pattern
50 const uint8_t MAGIC = 0xa5;
51 
52 // Single-ton
54 
55 // Main task and run queue
59  { 0 },
60  NULL
61 };
62 
63 // Reference running task
65 
66 // Initial top stack for task allocation
67 size_t SchedulerClass::s_top = SchedulerClass::DEFAULT_MAIN_STACK_SIZE;
68 
69 bool SchedulerClass::begin(size_t stackSize)
70 {
71  // Set main task stack size
72  s_top = stackSize;
73  return (true);
74 }
75 
76 bool SchedulerClass::start(func_t taskSetup, func_t taskLoop, size_t stackSize)
77 {
78  // Check called from main task and valid task loop function
79  if ((s_running != &s_main) || (taskLoop == NULL)) return (false);
80 
81  // Adjust stack size with size of task context
82  stackSize += sizeof(task_t);
83 
84  // Allocate stack(s) and check if main stack top should be set
85  size_t frame = RAMEND - (size_t) &frame;
86  uint8_t stack[s_top - frame];
87  if (s_main.stack == NULL) {
88  s_main.stack = stack;
89  memset(stack, MAGIC, s_top - frame);
90  }
91 
92 #if defined(ARDUINO_ARCH_AVR)
93  // Check that the task can be allocated
94  int HEAPEND = (__brkval == 0 ? (int) &__heap_start : (int) __brkval);
95  int STACKSTART = ((int) stack) - stackSize;
96  HEAPEND += __malloc_margin;
97  if (STACKSTART < HEAPEND) return (false);
98 
99  // Adjust heap limit
100  __malloc_heap_end = (char*) STACKSTART;
101 #else
102  // Check that the task can be allocated
103  if (s_top + stackSize > STACK_MAX) return (false);
104 #endif
105 
106  // Adjust stack top for next task allocation
107  s_top += stackSize;
108 
109  // Fill stack with magic pattern to allow detect of stack usage
110  memset(stack - stackSize, MAGIC, stackSize - sizeof(task_t));
111 
112  // Initiate task with given functions and stack top
113  init(taskSetup, taskLoop, stack - stackSize);
114  return (true);
115 }
116 
118 {
119  // Caller will continue here on yield
120  if (setjmp(s_running->context)) return;
121 
122  // Next task in run queue will continue
124  longjmp(s_running->context, true);
125 }
126 
128 {
129  const uint8_t* sp = s_running->stack;
130  size_t bytes = 0;
131  while (*sp++ == MAGIC) bytes++;
132  return (bytes);
133 }
134 
136 {
137  // Add task last in run queue (main task)
138  task_t task;
139  task.next = &s_main;
140  task.prev = s_main.prev;
141  s_main.prev->next = &task;
142  s_main.prev = &task;
143  task.stack = stack;
144 
145  // Create context for new task, caller will return
146  if (setjmp(task.context)) {
147  if (setup != NULL) setup();
148  while (1) loop();
149  }
150 }
151 
152 extern "C"
153 void yield(void)
154 {
155  Scheduler.yield();
156 }
const uint8_t MAGIC
Definition: Scheduler.cpp:50
static size_t s_top
Definition: Scheduler.h:150
void loop()
Definition: Alarm.h:35
SchedulerClass::func_t task_t
static task_t * s_running
Definition: Scheduler.h:147
const uint8_t * stack
Task stack top.
Definition: Scheduler.h:102
void(* func_t)()
Definition: Scheduler.h:31
void setup()
Definition: Alarm.h:31
static task_t s_main
Definition: Scheduler.h:144
task_t * next
Next task.
Definition: Scheduler.h:99
static bool begin(size_t stackSize)
Definition: Scheduler.cpp:69
task_t * prev
Previous task.
Definition: Scheduler.h:100
static size_t stack()
Definition: Scheduler.cpp:127
static void yield()
Definition: Scheduler.cpp:117
static void init(func_t setup, func_t loop, const uint8_t *stack)
Definition: Scheduler.cpp:135
SchedulerClass Scheduler
Definition: Scheduler.cpp:53
jmp_buf context
Task context.
Definition: Scheduler.h:101
static bool start(func_t taskSetup, func_t taskLoop, size_t stackSize=DEFAULT_STACK_SIZE)
Definition: Scheduler.cpp:76