// 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 . // // ----------------------------------------------------------------------------- // // 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 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 NaiveScheduler::slots_[num_slots]; template uint8_t NaiveScheduler::current_slot_; } // namespace avrlib #endif // AVRLIB_TASK_H_