planner.hpp 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157
  1. // SPDX-License-Identifier: MIT
  2. // SPDX-FileCopyrightText: 2022 Ivan Baidakou
  3. #pragma once
  4. #include "definitions.hpp"
  5. #include "rotor-light-bsp.h"
  6. #include <cstddef>
  7. #include <type_traits>
  8. namespace rotor_light {
  9. /** \struct TimeEvent
  10. * \brief links together callback, data, timepoint and event id */
  11. struct TimeEvent {
  12. TimeEvent() = default;
  13. TimeEvent(TimeEvent &&) = delete;
  14. TimeEvent(const TimeEvent &) = delete;
  15. /** copy-assignment operator */
  16. TimeEvent &operator=(const TimeEvent &other) = default;
  17. /** callback */
  18. Callback callback = nullptr;
  19. /** user-supplied data pointer */
  20. void *data;
  21. /** timepoint of the event expiration */
  22. TimePoint when = 0;
  23. /** unique event id */
  24. EventId event_id = 0;
  25. };
  26. struct PlannerBase;
  27. /** \struct EventConsumer
  28. * \brief iterator-like struct over expired time events */
  29. struct EventConsumer {
  30. /** invokes expired event */
  31. void call_next();
  32. /** returns true if there are more exprired events */
  33. operator bool() const;
  34. ~EventConsumer();
  35. private:
  36. friend struct PlannerBase;
  37. EventConsumer(TimePoint deadline, PlannerBase *watchdog);
  38. TimePoint deadline;
  39. PlannerBase *watchdog;
  40. int32_t index;
  41. };
  42. /** \struct PlannerBase
  43. * \brief bookeeper of future events */
  44. struct PlannerBase {
  45. /** records events storage pointer and maximum amount of events */
  46. PlannerBase(TimeEvent *events, int32_t events_count);
  47. PlannerBase(const PlannerBase &) = delete;
  48. PlannerBase(PlannerBase &&) = delete;
  49. /** \brief records the new event
  50. *
  51. * the contextt is either ctx::thread (mask interrupts) or
  52. * ctx::interrupt (do not mask interrupts).
  53. *
  54. * returns cancellable event_id
  55. */
  56. template <typename Ctx>
  57. EventId add_event(TimePoint when, Callback callback, void *data) {
  58. if constexpr (std::is_same_v<Ctx, ctx::thread>) {
  59. ROTOR_LIGHT_DISABLE_INTERRUPTS();
  60. }
  61. EventId r;
  62. if (last_event + 1 >= events_count) {
  63. r = 0;
  64. } else {
  65. EventId future_id = next_id + 1;
  66. bool recheck = false;
  67. int i = last_event + 1;
  68. // find the insertion point (skip previous events)
  69. for (int j = 0; j <= last_event; ++j) {
  70. auto &event = events[j];
  71. if (event.event_id == future_id) {
  72. ++future_id;
  73. recheck = true;
  74. }
  75. if (event.when <= when) {
  76. continue;
  77. } else {
  78. i = j;
  79. }
  80. }
  81. while (recheck || !future_id) {
  82. recheck = false;
  83. if (!future_id) {
  84. ++future_id;
  85. }
  86. for (int j = 0; j <= last_event; ++j) {
  87. auto &event = events[j];
  88. if (event.event_id == future_id) {
  89. ++future_id;
  90. recheck = true;
  91. break;
  92. }
  93. }
  94. }
  95. // copy next events into the next position
  96. for (int j = last_event; j >= i; --j) {
  97. events[j + 1] = events[j];
  98. }
  99. events[i] = TimeEvent{callback, data, when, next_id};
  100. next_id = future_id;
  101. ++last_event;
  102. r = events[i].event_id;
  103. }
  104. if constexpr (std::is_same_v<Ctx, ctx::thread>) {
  105. ROTOR_LIGHT_ENABLE_INTERRUPTS();
  106. }
  107. return r;
  108. }
  109. /** cancels (removes) the specified event */
  110. void remove_event(EventId event_id);
  111. /** returns expired event iterator upto the deadline */
  112. EventConsumer consume(TimePoint deadline);
  113. /** returns timepoint of the next event */
  114. TimePoint next_event();
  115. private:
  116. friend struct EventConsumer;
  117. void commit(size_t index);
  118. TimeEvent *events;
  119. int32_t events_count;
  120. int32_t last_event;
  121. EventId next_id;
  122. };
  123. /** \struct Planner
  124. * \brief bookeeper of future events, templated for fixed amount of events */
  125. template <size_t TimeEventsCount> struct Planner : PlannerBase {
  126. static_assert(TimeEventsCount > 0, "at least one event have to be allocated");
  127. Planner() : PlannerBase(events_holder, TimeEventsCount) {}
  128. /** storage for events */
  129. TimeEvent events_holder[TimeEventsCount];
  130. };
  131. } // namespace rotor_light