|
- // Copyright 2009 Olivier Gillet.
- //
- // Author: Olivier Gillet (ol.gillet@gmail.com)
- //
- // This program is free software: you can redistribute it and/or modify
- // it under the terms of the GNU General Public License as published by
- // the Free Software Foundation, either version 3 of the License, or
- // (at your option) any later version.
- // This program is distributed in the hope that it will be useful,
- // but WITHOUT ANY WARRANTY; without even the implied warranty of
- // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- // GNU General Public License for more details.
- // You should have received a copy of the GNU General Public License
- // along with this program. If not, see <http://www.gnu.org/licenses/>.
- //
- // -----------------------------------------------------------------------------
- //
- // Implementation of multitasking by coroutines, and naive deterministic
- // scheduler.
-
- #ifndef AVRLIB_TASK_H_
- #define AVRLIB_TASK_H_
-
- #include "avrlib/base.h"
-
- #define TASK_BEGIN static uint16_t state = 0; \
- switch(state) { \
- case 0:;
-
- // This is very unreliable because it assumes the line numbers will fit in an
- // uint8_t. Don't use this unless you want to save a couple of bytes by using
- // 8 bits comparisons instead of 16 bits comparisons.
- #define TASK_BEGIN_NEAR static uint8_t state = 0; \
- switch(state) { \
- case 0:;
-
- #define TASK_RETURN(value) \
- do { \
- state = __LINE__; \
- return (value); \
- case __LINE__:; \
- } while (0)
-
- #define TASK_SWITCH \
- do { \
- state = __LINE__; \
- return; \
- case __LINE__:; \
- } while (0)
-
- #define TASK_END } return;
-
- namespace avrlib {
-
- typedef struct {
- void (*code)();
- uint8_t priority;
- } Task;
-
- // This naive deterministic scheduler stores an array of "slots", each element
- // of which stores a 0 (nop) or a task id. During initialization, the array is
- // filled in such a way that $task.priority occurrences of a task are present in
- // the array, and are roughly evenly spaced.
- // For example if the tasks/priority are:
- // Task 1: 8
- // Task 2: 4
- // Task 3: 3
- // Task 4: 1
- //
- // The slots will contain:
- // 1 2 1 3 1 2 1 4 1 2 1 3 2 3 0 0
- //
- // And the scheduler will execute the tasks in this sequence.
- template<uint8_t num_slots>
- class NaiveScheduler {
- public:
- void Init() {
- uint8_t slot = 0;
-
- // For a given task, occupy $priority available slots, spaced apart by
- // #total slots / $priority.
- for (uint8_t i = 0; i < sizeof(slots_); ++i) {
- slots_[i] = 0;
- }
-
- for (uint8_t i = 0; i < sizeof(tasks_) / sizeof(Task); ++i) {
- for (uint8_t j = 0; j < tasks_[i].priority; ++j) {
- // Search for the next available slot.
- while (1) {
- if (slot >= sizeof(slots_)) {
- slot = 0;
- }
- if (slots_[slot] == 0) {
- break;
- }
- ++slot;
- }
- slots_[slot] = i + 1;
- slot += sizeof(slots_) / tasks_[i].priority;
- }
- }
- }
-
- void Run() {
- while (1) {
- ++current_slot_;
- if (current_slot_ >= sizeof(slots_)) {
- current_slot_ = 0;
- }
- if (slots_[current_slot_]) {
- tasks_[slots_[current_slot_] - 1].code();
- }
- }
- }
-
- private:
- static Task tasks_[];
- static uint8_t slots_[num_slots];
- static uint8_t current_slot_;
- };
-
- template<uint8_t num_slots>
- uint8_t NaiveScheduler<num_slots>::slots_[num_slots];
-
- template<uint8_t num_slots>
- uint8_t NaiveScheduler<num_slots>::current_slot_;
-
- } // namespace avrlib
-
- #endif // AVRLIB_TASK_H_
|