123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157 |
- // SPDX-License-Identifier: MIT
- // SPDX-FileCopyrightText: 2022 Ivan Baidakou
- #pragma once
- #include "definitions.hpp"
- #include "rotor-light-bsp.h"
- #include <cstddef>
- #include <type_traits>
- namespace rotor_light {
- /** \struct TimeEvent
- * \brief links together callback, data, timepoint and event id */
- struct TimeEvent {
- TimeEvent() = default;
- TimeEvent(TimeEvent &&) = delete;
- TimeEvent(const TimeEvent &) = delete;
- /** copy-assignment operator */
- TimeEvent &operator=(const TimeEvent &other) = default;
- /** callback */
- Callback callback = nullptr;
- /** user-supplied data pointer */
- void *data;
- /** timepoint of the event expiration */
- TimePoint when = 0;
- /** unique event id */
- EventId event_id = 0;
- };
- struct PlannerBase;
- /** \struct EventConsumer
- * \brief iterator-like struct over expired time events */
- struct EventConsumer {
- /** invokes expired event */
- void call_next();
- /** returns true if there are more exprired events */
- operator bool() const;
- ~EventConsumer();
- private:
- friend struct PlannerBase;
- EventConsumer(TimePoint deadline, PlannerBase *watchdog);
- TimePoint deadline;
- PlannerBase *watchdog;
- int32_t index;
- };
- /** \struct PlannerBase
- * \brief bookeeper of future events */
- struct PlannerBase {
- /** records events storage pointer and maximum amount of events */
- PlannerBase(TimeEvent *events, int32_t events_count);
- PlannerBase(const PlannerBase &) = delete;
- PlannerBase(PlannerBase &&) = delete;
- /** \brief records the new event
- *
- * the contextt is either ctx::thread (mask interrupts) or
- * ctx::interrupt (do not mask interrupts).
- *
- * returns cancellable event_id
- */
- template <typename Ctx>
- EventId add_event(TimePoint when, Callback callback, void *data) {
- if constexpr (std::is_same_v<Ctx, ctx::thread>) {
- ROTOR_LIGHT_DISABLE_INTERRUPTS();
- }
- EventId r;
- if (last_event + 1 >= events_count) {
- r = 0;
- } else {
- EventId future_id = next_id + 1;
- bool recheck = false;
- int i = last_event + 1;
- // find the insertion point (skip previous events)
- for (int j = 0; j <= last_event; ++j) {
- auto &event = events[j];
- if (event.event_id == future_id) {
- ++future_id;
- recheck = true;
- }
- if (event.when <= when) {
- continue;
- } else {
- i = j;
- }
- }
- while (recheck || !future_id) {
- recheck = false;
- if (!future_id) {
- ++future_id;
- }
- for (int j = 0; j <= last_event; ++j) {
- auto &event = events[j];
- if (event.event_id == future_id) {
- ++future_id;
- recheck = true;
- break;
- }
- }
- }
- // copy next events into the next position
- for (int j = last_event; j >= i; --j) {
- events[j + 1] = events[j];
- }
- events[i] = TimeEvent{callback, data, when, next_id};
- next_id = future_id;
- ++last_event;
- r = events[i].event_id;
- }
- if constexpr (std::is_same_v<Ctx, ctx::thread>) {
- ROTOR_LIGHT_ENABLE_INTERRUPTS();
- }
- return r;
- }
- /** cancels (removes) the specified event */
- void remove_event(EventId event_id);
- /** returns expired event iterator upto the deadline */
- EventConsumer consume(TimePoint deadline);
- /** returns timepoint of the next event */
- TimePoint next_event();
- private:
- friend struct EventConsumer;
- void commit(size_t index);
- TimeEvent *events;
- int32_t events_count;
- int32_t last_event;
- EventId next_id;
- };
- /** \struct Planner
- * \brief bookeeper of future events, templated for fixed amount of events */
- template <size_t TimeEventsCount> struct Planner : PlannerBase {
- static_assert(TimeEventsCount > 0, "at least one event have to be allocated");
- Planner() : PlannerBase(events_holder, TimeEventsCount) {}
- /** storage for events */
- TimeEvent events_holder[TimeEventsCount];
- };
- } // namespace rotor_light
|