1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
#pragma once
#include <stdint.h>
#include <atomic>
#include <concepts>
#include <functional>
#include <string_view>
#include <thread>
#include <utility>
#include <hal/Types.h>
#include <units/frequency.h>
#include <units/time.h>
#include <wpi/mutex.h>
namespace frc {
/**
* Notifiers run a user-provided callback function on a separate thread.
*
* If StartSingle() is used, the callback will run once. If StartPeriodic() is
* used, the callback will run repeatedly with the given period until stop() is
* called.
*/
class Notifier {
public:
/**
* Create a Notifier with the given callback.
*
* Configure when the callback runs with StartSingle() or StartPeriodic().
*
* @param callback The callback to run.
*/
explicit Notifier(std::function<void()> callback);
template <typename Arg, typename... Args>
Notifier(std::invocable<Arg, Args...> auto&& callback, Arg&& arg,
Args&&... args)
: Notifier(std::bind(std::forward<decltype(callback)>(callback),
std::forward<Arg>(arg),
std::forward<Args>(args)...)) {}
/**
* Create a Notifier with the given callback.
*
* Configure when the callback runs with StartSingle() or StartPeriodic().
*
* This overload makes the underlying thread run with a real-time priority.
* This is useful for reducing scheduling jitter on processes which are
* sensitive to timing variance, like model-based control.
*
* @param priority The FIFO real-time scheduler priority ([1..99] where a
* higher number represents higher priority). See "man 7
* sched" for more details.
* @param callback The callback to run.
*/
explicit Notifier(int priority, std::function<void()> callback);
template <typename Arg, typename... Args>
Notifier(int priority, std::invocable<Arg, Args...> auto&& callback,
Arg&& arg, Args&&... args)
: Notifier(priority, std::bind(std::forward<decltype(callback)>(callback),
std::forward<Arg>(arg),
std::forward<Args>(args)...)) {}
/**
* Free the resources for a timer event.
*/
~Notifier();
Notifier(Notifier&& rhs);
Notifier& operator=(Notifier&& rhs);
/**
* Sets the name of the notifier. Used for debugging purposes only.
*
* @param name Name
*/
void SetName(std::string_view name);
/**
* Change the callback function.
*
* @param callback The callback function.
*/
void SetCallback(std::function<void()> callback);
/**
* Run the callback once after the given delay.
*
* @param delay Time to wait before the callback is called.
*/
void StartSingle(units::second_t delay);
/**
* Run the callback periodically with the given period.
*
* The user-provided callback should be written so that it completes before
* the next time it's scheduled to run.
*
* @param period Period after which to call the callback starting one
* period after the call to this method.
*/
void StartPeriodic(units::second_t period);
/**
* Run the callback periodically with the given frequency.
*
* The user-provided callback should be written so that it completes before
* the next time it's scheduled to run.
*
* @param frequency Frequency after which to call the callback starting one
* period after the call to this method.
*/
void StartPeriodic(units::hertz_t frequency);
/**
* Stop further callback invocations.
*
* No further periodic callbacks will occur. Single invocations will also be
* cancelled if they haven't yet occurred.
*
* If a callback invocation is in progress, this function will block until the
* callback is complete.
*/
void Stop();
/**
* Sets the HAL notifier thread priority.
*
* The HAL notifier thread is responsible for managing the FPGA's notifier
* interrupt and waking up user's Notifiers when it's their time to run.
* Giving the HAL notifier thread real-time priority helps ensure the user's
* real-time Notifiers, if any, are notified to run in a timely manner.
*
* @param realTime Set to true to set a real-time priority, false for standard
* priority.
* @param priority Priority to set the thread to. For real-time, this is 1-99
* with 99 being highest. For non-real-time, this is forced to
* 0. See "man 7 sched" for more details.
* @return True on success.
*/
static bool SetHALThreadPriority(bool realTime, int32_t priority);
private:
/**
* Update the HAL alarm time.
*
* @param triggerTime the time at which the next alarm will be triggered
*/
void UpdateAlarm(uint64_t triggerTime);
/**
* Update the HAL alarm time based on m_expirationTime.
*/
void UpdateAlarm();
// The thread waiting on the HAL alarm
std::thread m_thread;
// The mutex held while updating process information
wpi::mutex m_processMutex;
// HAL handle (atomic for proper destruction)
std::atomic<HAL_NotifierHandle> m_notifier{0};
// The user-provided callback
std::function<void()> m_callback;
// The time at which the callback should be called. Has the same zero as
// Timer::GetFPGATimestamp().
units::second_t m_expirationTime = 0_s;
// If periodic, stores the callback period; if single, stores the time until
// the callback call.
units::second_t m_period = 0_s;
// True if the callback is periodic
bool m_periodic = false;
};
} // namespace frc