Red Bird Racing VCU v2
 
Loading...
Searching...
No Matches
Scheduler.tpp
Go to the documentation of this file.
1/**
2 * @file Scheduler.tpp
3 * @author Planeson, Red Bird Racing
4 * @brief Implementation of the Scheduler class template
5 * @version 1.2
6 * @date 2026-02-28
7 * @see Scheduler.hpp
8 */
9
10#include "Enums.hpp"
11#include "Scheduler.hpp" // Scheduler class template declaration
12
13/**
14 * @brief Construct a new Scheduler object
15 *
16 * @tparam NUM_TASKS Number of tasks per MCP2515
17 * @tparam NUM_MCP2515 Number of MCP2515 instances
18 * @param[in] period_us_ Period of the scheduler in microseconds
19 * @param[in] spin_threshold_us_ Spin-wait threshold in microseconds
20 */
21template <uint8_t NUM_TASKS, uint8_t NUM_MCP2515>
23 uint32_t spin_threshold_us_,
24 unsigned long (*const current_time_us)())
25 : tasks{nullptr},
26 task_ticks{0},
27 task_counters{0}, // run on first tick
28 task_cnt{0},
29 PERIOD_US(period_us_),
30 SPIN_US(spin_threshold_us_),
31 last_fire_us(0),
32 CURRENT_TIME_US(current_time_us)
33{
34}
35
36/**
37 * @brief Update the scheduler, checking if tasks need to be run based on the current time
38 *
39 * @tparam NUM_TASKS Number of tasks per MCP2515
40 * @tparam NUM_MCP2515 Number of MCP2515 instances
41 * @param[in] current_time_us Function pointer to a function returning the current time in microseconds
42 */
43template <uint8_t NUM_TASKS, uint8_t NUM_MCP2515>
45{
46 uint32_t delta = CURRENT_TIME_US() - last_fire_us;
47 if (delta >= PERIOD_US)
48 {
49 runTasks();
50 if (delta >= 2 * PERIOD_US)
51 // we missed more than one period, override last_fire_us to avoid bursts
52 last_fire_us = CURRENT_TIME_US();
53 else
54 last_fire_us += PERIOD_US;
55
56 return;
57 }
58 // not time yet, check if we should spin-wait or return
59 if (delta >= PERIOD_US - SPIN_US)
60 {
61 // spin-wait
62 while ((uint32_t)(CURRENT_TIME_US() - last_fire_us) < PERIOD_US)
63 ;
64 // now it's time, run the tasks
65 runTasks();
66 last_fire_us += PERIOD_US;
67 }
68 return;
69}
70
71/**
72 * @brief Synchonize the scheduler to the current time, resetting all task counters, used when starting multiple Schedulers across different boards together
73 *
74 * @tparam NUM_TASKS Number of tasks per MCP2515
75 * @tparam NUM_MCP2515 Number of MCP2515 instances
76 * @param[in] current_time_us Function pointer to a function returning the current time in microseconds
77 */
78template <uint8_t NUM_TASKS, uint8_t NUM_MCP2515>
79void Scheduler<NUM_TASKS, NUM_MCP2515>::synchronize(unsigned long (*const current_time_us)())
80{
81 if (current_time_us == nullptr)
82 return;
83
84 last_fire_us = current_time_us();
85 for (uint8_t mcp_index = 0; mcp_index < NUM_MCP2515; ++mcp_index)
86 {
87 for (uint8_t task_index = 0; task_index < NUM_TASKS; ++task_index)
88 {
89 task_counters[mcp_index][task_index] = task_ticks[mcp_index][task_index];
90 }
91 }
92}
93
94/**
95 * @brief Add a task to the scheduler for a specific MCP2515 index
96 *
97 * @tparam NUM_TASKS Number of tasks per MCP2515
98 * @tparam NUM_MCP2515 Number of MCP2515 instances
99 * @param[in] mcp_index Index of the MCP2515 instance
100 * @param[in] task Function pointer to the task to be added
101 * @param[in] tick_interval Number of ticks between task executions, so 1 for every tick, 10 for every 10 ticks; 0 makes the given task disabled from repeating.
102 * @return true if the task was added successfully, false otherwise
103 */
104template <uint8_t NUM_TASKS, uint8_t NUM_MCP2515>
105bool Scheduler<NUM_TASKS, NUM_MCP2515>::addTask(const McpIndex mcp_index, const TaskFn task, const uint8_t tick_interval)
106{
107 uint8_t mcp_idx = static_cast<uint8_t>(mcp_index);
108 if (mcp_idx >= NUM_MCP2515 || task == nullptr)
109 return false;
110
111 if (task_cnt[mcp_idx] >= NUM_TASKS)
112 return false; // full
113
114 tasks[mcp_idx][task_cnt[mcp_idx]] = task;
115 task_ticks[mcp_idx][task_cnt[mcp_idx]] = tick_interval;
116 task_counters[mcp_idx][task_cnt[mcp_idx]] = 1; // run on first tick
117 ++task_cnt[mcp_idx];
118 return true;
119}
120
121/**
122 * @brief Remove a task from the scheduler for a specific MCP2515 instance
123 *
124 * @tparam NUM_TASKS Number of tasks per MCP2515
125 * @tparam NUM_MCP2515 Number of MCP2515 instances
126 * @param[in] mcp_index Index of the MCP2515 instance
127 * @param[in] task Function pointer to the task to be removed
128 * @return true if the task was removed successfully, false otherwise
129 */
130template <uint8_t NUM_TASKS, uint8_t NUM_MCP2515>
132{
133 uint8_t mcp_idx = static_cast<uint8_t>(mcp_index);
134 if (mcp_idx >= NUM_MCP2515 || task == nullptr)
135 return false;
136
137 for (uint8_t i = 0; i < task_cnt[mcp_idx]; ++i)
138 {
139 if (tasks[mcp_idx][i] == task)
140 {
141 // shift left remaining tasks
142 for (uint8_t j = i; j < task_cnt[mcp_idx] - 1; ++j)
143 {
144 tasks[mcp_idx][j] = tasks[mcp_idx][j + 1];
145 task_ticks[mcp_idx][j] = task_ticks[mcp_idx][j + 1];
146 task_counters[mcp_idx][j] = task_counters[mcp_idx][j + 1];
147 }
148
149 // clean last slot
150 tasks[mcp_idx][task_cnt[mcp_idx] - 1] = nullptr;
151 task_ticks[mcp_idx][task_cnt[mcp_idx] - 1] = 0;
152 task_counters[mcp_idx][task_cnt[mcp_idx] - 1] = 0;
153
154 --task_cnt[mcp_idx];
155 return true;
156 }
157 }
158 return false;
159}
160
161/**
162 * @brief Helper function to run scheduled tasks
163 *
164 * @tparam NUM_TASKS Number of tasks per MCP2515
165 * @tparam NUM_MCP2515 Number of MCP2515 instances
166 */
167template <uint8_t NUM_TASKS, uint8_t NUM_MCP2515>
169{
170 for (uint8_t task_index = 0; task_index < NUM_TASKS; ++task_index)
171 {
172 for (uint8_t mcp_index = 0; mcp_index < NUM_MCP2515; ++mcp_index)
173 {
174 if (task_counters[mcp_index][task_index] == 0)
175 continue; // task slot empty
176
177 if (task_counters[mcp_index][task_index] == 1)
178 {
179 if (tasks[mcp_index][task_index] == nullptr)
180 continue; // no task to run
181
182 // call functions
183 (tasks[mcp_index][task_index])();
184
185 // reset counter
186 task_counters[mcp_index][task_index] = task_ticks[mcp_index][task_index];
187 continue;
188 }
189 // not time yet, decrement counter
190 --task_counters[mcp_index][task_index];
191 }
192 }
193}
Enumeration definitions for the VCU.
McpIndex
MCP2515 instance indices.
Definition: Enums.hpp:66
Declaration of the Scheduler class template, for scheduling tasks on multiple MCP2515 instances.
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
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
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
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
void runTasks()
Helper function to run scheduled tasks.
Definition: Scheduler.tpp:168