Red Bird Racing VCU v2
 
Loading...
Searching...
No Matches
Scheduler.hpp
Go to the documentation of this file.
1/**
2 * @file Scheduler.hpp
3 * @author Planeson, Red Bird Racing
4 * @brief Declaration of the Scheduler class template, for scheduling tasks on multiple MCP2515 instances
5 * @version 1.2
6 * @date 2026-02-28
7 * @see Scheduler.tpp
8 * @dir Scheduler @brief The Scheduler library contains the Scheduler class template, which manages the scheduling of tasks for multiple MCP2515 instances, allowing for periodic execution of functions based on a specified time interval and spin-wait threshold.
9 */
10
11#ifndef SCHEDULER_HPP
12#define SCHEDULER_HPP
13
14#include "Enums.hpp"
15
16/**
17 * @brief Scheduler class template for scheduling tasks on multiple MCP2515 instances
18 * Takes in function pointers to member functions of MCP2515 class,
19 * and calls them at specified intervals, using a unified central ticker.
20 *
21 * @details The Scheduler class holds function pointers to tasks to be run on multiple MCP2515 instances.
22 * Because how most MCP2515 are dedicated to a specific function (e.g., motor control, BMS, datalogger),
23 * instead of the scheduler holding a queue of messages to send and a queue of read messages,
24 * it holds function pointers to tasks that handle sending and receiving messages for each MCP2515.
25 * The object wishing to send/receive messages holds their own MCP2515 object (reference).
26 *
27 * The Scheduler runs on a fixed period. When Scheduler.update() is called, it checks if a period has already passed.
28 * If not, it checks if it is almost passed. If the time to the next cycle is less than SPIN_US, it spin-waits until the period is reached.
29 * Otherwise, it returns immediately, allowing other non-scheduler tasks to run.
30 * Once the time to fire is reached, it runs the tasks via the pointers in a round-robin fashion, going from one MCP2515 to another.
31 *
32 * With a modified mcp2515.h that doesn't directly use SPI.h, we can skip waiting for the SPI transaction to complete,
33 * and instead work on compiling the next message while the previous SPI transaction is still ongoing.
34 * Although it would be easier to only have a single queue (instead NUM_MCP2515 queues),
35 * we give room for the CAN-bus to be busy on one MCP2515, while another MCP2515 can still send/receive messages,
36 * i.e. we distribute the load across multiple CAN buses more evenly, instead of having one bus burst at one time
37 *
38 * In the rare case where the system is busy and misses more than one period, the scheduler will skip to the next period, preventing bursts.
39 *
40 * @tparam NUM_TASKS Number of tasks per MCP2515, choose highest of all, but keep as low as possible
41 * @tparam NUM_MCP2515 Number of MCP2515 instances
42 */
43template <uint8_t NUM_TASKS, uint8_t NUM_MCP2515>
45{
46 using TaskFn = void (*)();
47
48public:
49 Scheduler() = delete; /**< all arguments must be provided */
50 Scheduler(uint32_t period_us_, uint32_t spin_threshold_us_, unsigned long (*const current_time_us)());
51 // no need destructor, since no dynamic memory allocation, and won't destruct in the middle of the program anyway
52
53 void update();
54 void synchronize(unsigned long (*const current_time_us)());
55 bool addTask(const McpIndex mcp_index, const TaskFn task, const uint8_t tick_interval);
56 bool removeTask(const McpIndex mcp_index, const TaskFn task);
57
58 /**
59 * @brief Returns the period of the scheduler in microseconds.
60 * @return The period in microseconds.
61 */
62 constexpr uint32_t getPeriodUs() const { return PERIOD_US; }
63
64 /**
65 * @brief Returns the number of cycles needed for a given interval in microseconds.
66 * @param[in] interval_us The interval in microseconds.
67 * @return The number of cycles needed.
68 */
69 constexpr uint32_t cyclesNeeded(const uint32_t interval_us) const { return interval_us / PERIOD_US; }
70
71private:
72 TaskFn tasks[NUM_MCP2515][NUM_TASKS]; /**< Array of tasks, sorted by each MCP2515. */
73 uint8_t task_ticks[NUM_MCP2515][NUM_TASKS]; /**< Period (in ticks) of each function, 1 is fire every tick, 0 is disabled. */
74 uint8_t task_counters[NUM_MCP2515][NUM_TASKS]; /**< Counter to hold firing for n ticks, "how many ticks left before firing?". */
75 uint8_t task_cnt[NUM_MCP2515]; /**< Array of number of tasks per MCP2515. */
76 const uint32_t PERIOD_US; /**< Period (tick length). */
77 const uint32_t SPIN_US; /**< Threshold to switch from letting non-scheduler task in loop() run, to spin-locking (to ensure on time firing). */
78 uint32_t last_fire_us; /**< Last time scheduler fired, overridden if missed more than one period. */
79 unsigned long (*const CURRENT_TIME_US)(); /**< Function pointer to a function returning the current time in microseconds. */
80
81 inline void runTasks();
82};
83
84#include "Scheduler.tpp"
85
86#endif // SCHEDULER_HPP
Enumeration definitions for the VCU.
McpIndex
MCP2515 instance indices.
Definition: Enums.hpp:66
Implementation of the Scheduler class template.
Scheduler class template for scheduling tasks on multiple MCP2515 instances Takes in function pointer...
Definition: Scheduler.hpp:45
Scheduler()=delete
bool removeTask(const McpIndex mcp_index, const TaskFn task)
Remove a task from the scheduler for a specific MCP2515 instance.
Definition: Scheduler.tpp:131
uint8_t task_cnt[NUM_MCP2515]
Definition: Scheduler.hpp:75
void synchronize(unsigned long(*const current_time_us)())
Synchonize the scheduler to the current time, resetting all task counters, used when starting multipl...
Definition: Scheduler.tpp:79
uint32_t last_fire_us
Definition: Scheduler.hpp:78
uint8_t task_counters[NUM_MCP2515][NUM_TASKS]
Definition: Scheduler.hpp:74
const uint32_t PERIOD_US
Definition: Scheduler.hpp:76
constexpr uint32_t getPeriodUs() const
Returns the period of the scheduler in microseconds.
Definition: Scheduler.hpp:62
bool addTask(const McpIndex mcp_index, const TaskFn task, const uint8_t tick_interval)
Add a task to the scheduler for a specific MCP2515 index.
Definition: Scheduler.tpp:105
TaskFn tasks[NUM_MCP2515][NUM_TASKS]
Definition: Scheduler.hpp:72
constexpr uint32_t cyclesNeeded(const uint32_t interval_us) const
Returns the number of cycles needed for a given interval in microseconds.
Definition: Scheduler.hpp:69
uint8_t task_ticks[NUM_MCP2515][NUM_TASKS]
Definition: Scheduler.hpp:73
void update()
Update the scheduler, checking if tasks need to be run based on the current time.
Definition: Scheduler.tpp:44
void(*)() TaskFn
Definition: Scheduler.hpp:46
const uint32_t SPIN_US
Definition: Scheduler.hpp:77
void runTasks()
Helper function to run scheduled tasks.
Definition: Scheduler.tpp:168
unsigned long(*const CURRENT_TIME_US)()
Definition: Scheduler.hpp:79