|
| 1 | +/* |
| 2 | + * Scheduler.hpp |
| 3 | + * |
| 4 | + * Created on: 17 nov. 2025 |
| 5 | + * Author: Victor (coauthor Stephan) |
| 6 | + */ |
| 7 | +#pragma once |
| 8 | + |
| 9 | +/* Uso del scheduler, descrito en la wiki: https://wiki.hyperloopupv.com/es/firmware/Timing/Scheduler */ |
| 10 | + |
| 11 | +#ifndef TESTING_ENV |
| 12 | +#include "stm32h7xx_ll_tim.h" |
| 13 | +#else |
| 14 | +#include "MockedDrivers/stm32h7xx_ll_tim_wrapper.h" |
| 15 | +#endif |
| 16 | +#include <array> |
| 17 | +#include <cstdint> |
| 18 | +#include <functional> |
| 19 | + |
| 20 | +/* NOTE(vic): Esto cambiará pronto */ |
| 21 | +#ifndef SCHEDULER_TIMER_IDX |
| 22 | +# define SCHEDULER_TIMER_IDX 2 |
| 23 | +#endif |
| 24 | + |
| 25 | +#define glue_(a,b) a ## b |
| 26 | +#define glue(a,b) glue_(a,b) |
| 27 | +#define SCHEDULER_TIMER_BASE glue(TIM, glue(SCHEDULER_TIMER_IDX, _BASE)) |
| 28 | + |
| 29 | +// Used to reserve a TimerPeripheral |
| 30 | +#ifndef TESTING_ENV |
| 31 | +#include "stm32h7xx_hal_tim.h" |
| 32 | +#define SCHEDULER_HAL_TIM glue(htim, SCHEDULER_TIMER_IDX) |
| 33 | +extern TIM_HandleTypeDef SCHEDULER_HAL_TIM; |
| 34 | +#endif |
| 35 | + |
| 36 | +struct Scheduler { |
| 37 | + using callback_t = void (*)(); |
| 38 | + static constexpr uint32_t INVALID_ID = 0xFFu; |
| 39 | + |
| 40 | + static void start(); |
| 41 | + static void update(); |
| 42 | + static inline uint64_t get_global_tick(); |
| 43 | + |
| 44 | + static uint16_t register_task(uint32_t period_us, callback_t func); |
| 45 | + static bool unregister_task(uint16_t id); |
| 46 | + |
| 47 | + static uint16_t set_timeout(uint32_t microseconds, callback_t func); |
| 48 | + static bool cancel_timeout(uint16_t id); |
| 49 | + |
| 50 | + // static void global_timer_callback(); |
| 51 | + |
| 52 | + // Have to be public because SCHEDULER_GLOBAL_TIMER_CALLBACK won't work otherwise |
| 53 | + //static const uint32_t global_timer_base = SCHEDULER_TIMER_BASE; |
| 54 | + static void on_timer_update(); |
| 55 | + |
| 56 | +#ifndef TESTING_ENV |
| 57 | + private: |
| 58 | +#endif |
| 59 | + struct Task { |
| 60 | + uint32_t next_fire_us{0}; |
| 61 | + callback_t callback{}; |
| 62 | + uint32_t period_us{0}; |
| 63 | + uint16_t id; |
| 64 | + bool repeating{false}; |
| 65 | + }; |
| 66 | + |
| 67 | + static constexpr std::size_t kMaxTasks = 16; |
| 68 | + static_assert((kMaxTasks & (kMaxTasks - 1)) == 0, "kMaxTasks must be a power of two"); |
| 69 | + static constexpr uint32_t FREQUENCY = 1'000'000u; // 1 MHz -> 1us precision |
| 70 | + |
| 71 | + static std::array<Task, kMaxTasks> tasks_; |
| 72 | + static_assert(kMaxTasks == 16, "kMaxTasks must be 16, if more is needed, sorted_task_ids_ must change"); |
| 73 | + /* sorted_task_ids_ is a sorted queue with 4bits for each id in the scheduler's current ids */ |
| 74 | + static uint64_t sorted_task_ids_; |
| 75 | + |
| 76 | + static uint32_t active_task_count_; |
| 77 | + static_assert(kMaxTasks <= 32, "kMaxTasks must be <= 32, if more is needed, the bitmaps must change"); |
| 78 | + static uint32_t ready_bitmap_; |
| 79 | + static uint32_t free_bitmap_; |
| 80 | + static uint64_t global_tick_us_; |
| 81 | + static uint32_t current_interval_us_; |
| 82 | + static uint16_t timeout_idx_; |
| 83 | + |
| 84 | + static inline uint8_t allocate_slot(); |
| 85 | + static inline void release_slot(uint8_t id); |
| 86 | + static void insert_sorted(uint8_t id); |
| 87 | + static void remove_sorted(uint8_t id); |
| 88 | + static void schedule_next_interval(); |
| 89 | + static inline void configure_timer_for_interval(uint32_t microseconds); |
| 90 | + |
| 91 | + // helpers |
| 92 | + static inline uint8_t get_at(uint8_t idx); |
| 93 | + static inline void set_at(uint8_t idx, uint8_t id); |
| 94 | + static inline void pop_front(); |
| 95 | + static inline uint8_t front_id(); |
| 96 | + |
| 97 | + static inline void global_timer_disable(); |
| 98 | + static inline void global_timer_enable(); |
| 99 | +}; |
0 commit comments