You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

131 lines
3.4KB

  1. // Copyright 2009 Olivier Gillet.
  2. //
  3. // Author: Olivier Gillet (ol.gillet@gmail.com)
  4. //
  5. // This program is free software: you can redistribute it and/or modify
  6. // it under the terms of the GNU General Public License as published by
  7. // the Free Software Foundation, either version 3 of the License, or
  8. // (at your option) any later version.
  9. // This program is distributed in the hope that it will be useful,
  10. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. // GNU General Public License for more details.
  13. // You should have received a copy of the GNU General Public License
  14. // along with this program. If not, see <http://www.gnu.org/licenses/>.
  15. //
  16. // -----------------------------------------------------------------------------
  17. //
  18. // Implementation of multitasking by coroutines, and naive deterministic
  19. // scheduler.
  20. #ifndef AVRLIB_TASK_H_
  21. #define AVRLIB_TASK_H_
  22. #include "avrlib/base.h"
  23. #define TASK_BEGIN static uint16_t state = 0; \
  24. switch(state) { \
  25. case 0:;
  26. // This is very unreliable because it assumes the line numbers will fit in an
  27. // uint8_t. Don't use this unless you want to save a couple of bytes by using
  28. // 8 bits comparisons instead of 16 bits comparisons.
  29. #define TASK_BEGIN_NEAR static uint8_t state = 0; \
  30. switch(state) { \
  31. case 0:;
  32. #define TASK_RETURN(value) \
  33. do { \
  34. state = __LINE__; \
  35. return (value); \
  36. case __LINE__:; \
  37. } while (0)
  38. #define TASK_SWITCH \
  39. do { \
  40. state = __LINE__; \
  41. return; \
  42. case __LINE__:; \
  43. } while (0)
  44. #define TASK_END } return;
  45. namespace avrlib {
  46. typedef struct {
  47. void (*code)();
  48. uint8_t priority;
  49. } Task;
  50. // This naive deterministic scheduler stores an array of "slots", each element
  51. // of which stores a 0 (nop) or a task id. During initialization, the array is
  52. // filled in such a way that $task.priority occurrences of a task are present in
  53. // the array, and are roughly evenly spaced.
  54. // For example if the tasks/priority are:
  55. // Task 1: 8
  56. // Task 2: 4
  57. // Task 3: 3
  58. // Task 4: 1
  59. //
  60. // The slots will contain:
  61. // 1 2 1 3 1 2 1 4 1 2 1 3 2 3 0 0
  62. //
  63. // And the scheduler will execute the tasks in this sequence.
  64. template<uint8_t num_slots>
  65. class NaiveScheduler {
  66. public:
  67. void Init() {
  68. uint8_t slot = 0;
  69. // For a given task, occupy $priority available slots, spaced apart by
  70. // #total slots / $priority.
  71. for (uint8_t i = 0; i < sizeof(slots_); ++i) {
  72. slots_[i] = 0;
  73. }
  74. for (uint8_t i = 0; i < sizeof(tasks_) / sizeof(Task); ++i) {
  75. for (uint8_t j = 0; j < tasks_[i].priority; ++j) {
  76. // Search for the next available slot.
  77. while (1) {
  78. if (slot >= sizeof(slots_)) {
  79. slot = 0;
  80. }
  81. if (slots_[slot] == 0) {
  82. break;
  83. }
  84. ++slot;
  85. }
  86. slots_[slot] = i + 1;
  87. slot += sizeof(slots_) / tasks_[i].priority;
  88. }
  89. }
  90. }
  91. void Run() {
  92. while (1) {
  93. ++current_slot_;
  94. if (current_slot_ >= sizeof(slots_)) {
  95. current_slot_ = 0;
  96. }
  97. if (slots_[current_slot_]) {
  98. tasks_[slots_[current_slot_] - 1].code();
  99. }
  100. }
  101. }
  102. private:
  103. static Task tasks_[];
  104. static uint8_t slots_[num_slots];
  105. static uint8_t current_slot_;
  106. };
  107. template<uint8_t num_slots>
  108. uint8_t NaiveScheduler<num_slots>::slots_[num_slots];
  109. template<uint8_t num_slots>
  110. uint8_t NaiveScheduler<num_slots>::current_slot_;
  111. } // namespace avrlib
  112. #endif // AVRLIB_TASK_H_