WPILibC++ 2027.0.0-alpha-4
Loading...
Searching...
No Matches
SimDataValue.hpp
Go to the documentation of this file.
1// Copyright (c) FIRST and other WPILib contributors.
2// Open Source Software; you can modify and/or share it under the terms of
3// the WPILib BSD license file in the root directory of this project.
4
5#pragma once
6
7#include <mutex>
8
11#include "wpi/util/Compiler.hpp"
12#include "wpi/util/spinlock.hpp"
13
14namespace wpi::hal {
15
16namespace impl {
17template <typename T, HAL_Value (*MakeValue)(T)>
19 public:
20 explicit SimDataValueBase(T value) : m_value(value) {}
21
22 LLVM_ATTRIBUTE_ALWAYS_INLINE void CancelCallback(int32_t uid) { Cancel(uid); }
23
24 T Get() const {
25 std::scoped_lock lock(m_mutex);
26 return m_value;
27 }
28
29 LLVM_ATTRIBUTE_ALWAYS_INLINE operator T() const { return Get(); } // NOLINT
30
31 void Reset(T value) {
32 std::scoped_lock lock(m_mutex);
33 DoReset();
34 m_value = value;
35 }
36
38
39 protected:
40 int32_t DoRegisterCallback(HAL_NotifyCallback callback, void* param,
41 HAL_Bool initialNotify, const char* name) {
42 std::unique_lock lock(m_mutex);
43 int32_t newUid = DoRegister(reinterpret_cast<RawFunctor>(callback), param);
44 if (newUid == -1) {
45 return -1;
46 }
47 if (initialNotify) {
48 // We know that the callback is not null because of earlier null check
49 HAL_Value value = MakeValue(m_value);
50 lock.unlock();
51 callback(name, param, &value);
52 }
53 return newUid;
54 }
55
56 void DoSet(T value, const char* name) {
57 std::scoped_lock lock(this->m_mutex);
58 if (m_value != value) {
59 m_value = value;
60 if (m_callbacks) {
61 HAL_Value halValue = MakeValue(value);
62 for (auto&& cb : *m_callbacks) {
63 reinterpret_cast<HAL_NotifyCallback>(cb.callback)(name, cb.param,
64 &halValue);
65 }
66 }
67 }
68 }
69
71};
72} // namespace impl
73
74/**
75 * Simulation data value wrapper. Provides callback functionality when the
76 * data value is changed.
77 *
78 * @tparam T value type (e.g. double)
79 * @tparam MakeValue function that takes a T and returns a HAL_Value
80 * @tparam GetName function that returns a const char* for the name
81 * @tparam GetDefault function that returns the default T (used only for
82 * default constructor)
83 */
84template <typename T, HAL_Value (*MakeValue)(T), const char* (*GetName)(),
85 T (*GetDefault)() = nullptr>
86class SimDataValue final : public impl::SimDataValueBase<T, MakeValue> {
87 public:
88// FIXME: GCC gives the false positive "the address of <GetDefault> will never
89// be NULL" because it doesn't realize the default template parameter can make
90// GetDefault nullptr. Fixed in GCC 13.
91// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=94554
92// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=105885
93#if __GNUC__
94#pragma GCC diagnostic push
95#pragma GCC diagnostic ignored "-Waddress"
96#endif // __GNUC__
98 : impl::SimDataValueBase<T, MakeValue>(
99 GetDefault != nullptr ? GetDefault() : T()) {}
100#if __GNUC__
101#pragma GCC diagnostic pop
102#endif // __GNUC__
103 explicit SimDataValue(T value)
104 : impl::SimDataValueBase<T, MakeValue>(value) {}
105
106 LLVM_ATTRIBUTE_ALWAYS_INLINE int32_t RegisterCallback(
107 HAL_NotifyCallback callback, void* param, HAL_Bool initialNotify) {
108 return this->DoRegisterCallback(callback, param, initialNotify, GetName());
109 }
110
111 LLVM_ATTRIBUTE_ALWAYS_INLINE void Set(T value) {
112 this->DoSet(value, GetName());
113 }
114
115 LLVM_ATTRIBUTE_ALWAYS_INLINE SimDataValue& operator=(T value) {
116 Set(value);
117 return *this;
118 }
119};
120
121/**
122 * Define a name functor for use with SimDataValue.
123 * This creates a function named GetNAMEName() that returns "NAME".
124 * @param NAME the name to return
125 */
126#define HAL_SIMDATAVALUE_DEFINE_NAME(NAME) \
127 static LLVM_ATTRIBUTE_ALWAYS_INLINE constexpr const char* \
128 Get##NAME##Name() { \
129 return #NAME; \
130 }
131
132/**
133 * Define a standard C API for simulation data.
134 *
135 * Functions defined:
136 * - int32 NS_RegisterCAPINAMECallback(
137 * int32_t index, HAL_NotifyCallback callback, void* param,
138 * HAL_Bool initialNotify)
139 * - void NS_CancelCAPINAMECallback(int32_t index, int32_t uid)
140 * - TYPE NS_GetCAPINAME(int32_t index)
141 * - void NS_SetCAPINAME(int32_t index, TYPE value)
142 *
143 * @param TYPE the underlying value type (e.g. double)
144 * @param NS the "namespace" (e.g. HALSIM)
145 * @param CAPINAME the C API name (usually first letter capitalized)
146 * @param DATA the backing data array
147 * @param LOWERNAME the lowercase name of the backing data variable
148 */
149#define HAL_SIMDATAVALUE_DEFINE_CAPI(TYPE, NS, CAPINAME, DATA, LOWERNAME) \
150 int32_t NS##_Register##CAPINAME##Callback( \
151 int32_t index, HAL_NotifyCallback callback, void* param, \
152 HAL_Bool initialNotify) { \
153 return DATA[index].LOWERNAME.RegisterCallback(callback, param, \
154 initialNotify); \
155 } \
156 \
157 void NS##_Cancel##CAPINAME##Callback(int32_t index, int32_t uid) { \
158 DATA[index].LOWERNAME.CancelCallback(uid); \
159 } \
160 \
161 TYPE NS##_Get##CAPINAME(int32_t index) { \
162 return DATA[index].LOWERNAME; \
163 } \
164 \
165 void NS##_Set##CAPINAME(int32_t index, TYPE LOWERNAME) { \
166 DATA[index].LOWERNAME = LOWERNAME; \
167 }
168
169/**
170 * Define a standard C API for simulation data (channel variant).
171 *
172 * Functions defined:
173 * - int32 NS_RegisterCAPINAMECallback(
174 * int32_t index, int32_t channel, HAL_NotifyCallback callback,
175 * void* param, HAL_Bool initialNotify)
176 * - void NS_CancelCAPINAMECallback(int32_t index, int32_t channel, int32_t uid)
177 * - TYPE NS_GetCAPINAME(int32_t index, int32_t channel)
178 * - void NS_SetCAPINAME(int32_t index, int32_t channel, TYPE value)
179 *
180 * @param TYPE the underlying value type (e.g. double)
181 * @param NS the "namespace" (e.g. HALSIM)
182 * @param CAPINAME the C API name (usually first letter capitalized)
183 * @param DATA the backing data array
184 * @param LOWERNAME the lowercase name of the backing data variable array
185 */
186#define HAL_SIMDATAVALUE_DEFINE_CAPI_CHANNEL(TYPE, NS, CAPINAME, DATA, \
187 LOWERNAME) \
188 int32_t NS##_Register##CAPINAME##Callback( \
189 int32_t index, int32_t channel, HAL_NotifyCallback callback, \
190 void* param, HAL_Bool initialNotify) { \
191 return DATA[index].LOWERNAME[channel].RegisterCallback(callback, param, \
192 initialNotify); \
193 } \
194 \
195 void NS##_Cancel##CAPINAME##Callback(int32_t index, int32_t channel, \
196 int32_t uid) { \
197 DATA[index].LOWERNAME[channel].CancelCallback(uid); \
198 } \
199 \
200 TYPE NS##_Get##CAPINAME(int32_t index, int32_t channel) { \
201 return DATA[index].LOWERNAME[channel]; \
202 } \
203 \
204 void NS##_Set##CAPINAME(int32_t index, int32_t channel, TYPE LOWERNAME) { \
205 DATA[index].LOWERNAME[channel] = LOWERNAME; \
206 }
207
208/**
209 * Define a standard C API for simulation data (no index variant).
210 *
211 * Functions defined:
212 * - int32 NS_RegisterCAPINAMECallback(
213 * HAL_NotifyCallback callback, void* param, HAL_Bool initialNotify)
214 * - void NS_CancelCAPINAMECallback(int32_t uid)
215 * - TYPE NS_GetCAPINAME(void)
216 * - void NS_SetCAPINAME(TYPE value)
217 *
218 * @param TYPE the underlying value type (e.g. double)
219 * @param NS the "namespace" (e.g. HALSIM)
220 * @param CAPINAME the C API name (usually first letter capitalized)
221 * @param DATA the backing data pointer
222 * @param LOWERNAME the lowercase name of the backing data variable
223 */
224#define HAL_SIMDATAVALUE_DEFINE_CAPI_NOINDEX(TYPE, NS, CAPINAME, DATA, \
225 LOWERNAME) \
226 int32_t NS##_Register##CAPINAME##Callback( \
227 HAL_NotifyCallback callback, void* param, HAL_Bool initialNotify) { \
228 return DATA->LOWERNAME.RegisterCallback(callback, param, initialNotify); \
229 } \
230 \
231 void NS##_Cancel##CAPINAME##Callback(int32_t uid) { \
232 DATA->LOWERNAME.CancelCallback(uid); \
233 } \
234 \
235 TYPE NS##_Get##CAPINAME(void) { \
236 return DATA->LOWERNAME; \
237 } \
238 \
239 void NS##_Set##CAPINAME(TYPE LOWERNAME) { \
240 DATA->LOWERNAME = LOWERNAME; \
241 }
242
243/**
244 * Define a stub standard C API for simulation data.
245 *
246 * Functions defined:
247 * - int32 NS_RegisterCAPINAMECallback(
248 * int32_t index, HAL_NotifyCallback callback, void* param,
249 * HAL_Bool initialNotify)
250 * - void NS_CancelCAPINAMECallback(int32_t index, int32_t uid)
251 * - TYPE NS_GetCAPINAME(int32_t index)
252 * - void NS_SetCAPINAME(int32_t index, TYPE value)
253 *
254 * @param TYPE the underlying value type (e.g. double)
255 * @param NS the "namespace" (e.g. HALSIM)
256 * @param CAPINAME the C API name (usually first letter capitalized)
257 * @param RETURN what to return from the Get function
258 */
259#define HAL_SIMDATAVALUE_STUB_CAPI(TYPE, NS, CAPINAME, RETURN) \
260 int32_t NS##_Register##CAPINAME##Callback( \
261 int32_t index, HAL_NotifyCallback callback, void* param, \
262 HAL_Bool initialNotify) { \
263 return 0; \
264 } \
265 \
266 void NS##_Cancel##CAPINAME##Callback(int32_t index, int32_t uid) {} \
267 \
268 TYPE NS##_Get##CAPINAME(int32_t index) { \
269 return RETURN; \
270 } \
271 \
272 void NS##_Set##CAPINAME(int32_t index, TYPE) {}
273
274/**
275 * Define a stub standard C API for simulation data (channel variant).
276 *
277 * Functions defined:
278 * - int32 NS_RegisterCAPINAMECallback(
279 * int32_t index, int32_t channel, HAL_NotifyCallback callback,
280 * void* param, HAL_Bool initialNotify)
281 * - void NS_CancelCAPINAMECallback(int32_t index, int32_t channel, int32_t uid)
282 * - TYPE NS_GetCAPINAME(int32_t index, int32_t channel)
283 * - void NS_SetCAPINAME(int32_t index, int32_t channel, TYPE value)
284 *
285 * @param TYPE the underlying value type (e.g. double)
286 * @param NS the "namespace" (e.g. HALSIM)
287 * @param CAPINAME the C API name (usually first letter capitalized)
288 * @param RETURN what to return from the Get function
289 */
290#define HAL_SIMDATAVALUE_STUB_CAPI_CHANNEL(TYPE, NS, CAPINAME, RETURN) \
291 int32_t NS##_Register##CAPINAME##Callback( \
292 int32_t index, int32_t channel, HAL_NotifyCallback callback, \
293 void* param, HAL_Bool initialNotify) { \
294 return 0; \
295 } \
296 \
297 void NS##_Cancel##CAPINAME##Callback(int32_t index, int32_t channel, \
298 int32_t uid) {} \
299 \
300 TYPE NS##_Get##CAPINAME(int32_t index, int32_t channel) { \
301 return RETURN; \
302 } \
303 \
304 void NS##_Set##CAPINAME(int32_t index, int32_t channel, TYPE) {}
305
306/**
307 * Define a stub standard C API for simulation data (no index variant).
308 *
309 * Functions defined:
310 * - int32 NS_RegisterCAPINAMECallback(
311 * HAL_NotifyCallback callback, void* param, HAL_Bool initialNotify)
312 * - void NS_CancelCAPINAMECallback(int32_t uid)
313 * - TYPE NS_GetCAPINAME(void)
314 * - void NS_SetCAPINAME(TYPE value)
315 *
316 * @param TYPE the underlying value type (e.g. double)
317 * @param NS the "namespace" (e.g. HALSIM)
318 * @param CAPINAME the C API name (usually first letter capitalized)
319 * @param RETURN what to return from the Get function
320 */
321#define HAL_SIMDATAVALUE_STUB_CAPI_NOINDEX(TYPE, NS, CAPINAME, RETURN) \
322 int32_t NS##_Register##CAPINAME##Callback( \
323 HAL_NotifyCallback callback, void* param, HAL_Bool initialNotify) { \
324 return 0; \
325 } \
326 \
327 void NS##_Cancel##CAPINAME##Callback(int32_t uid) {} \
328 \
329 TYPE NS##_Get##CAPINAME(void) { \
330 return RETURN; \
331 } \
332 \
333 void NS##_Set##CAPINAME(TYPE) {}
334
335} // namespace wpi::hal
void(* HAL_NotifyCallback)(const char *name, void *param, const struct HAL_Value *value)
Definition NotifyListener.h:9
@ name
Definition base.h:690
SimDataValue()
Definition SimDataValue.hpp:97
LLVM_ATTRIBUTE_ALWAYS_INLINE void Set(T value)
Definition SimDataValue.hpp:111
LLVM_ATTRIBUTE_ALWAYS_INLINE int32_t RegisterCallback(HAL_NotifyCallback callback, void *param, HAL_Bool initialNotify)
Definition SimDataValue.hpp:106
SimDataValue(T value)
Definition SimDataValue.hpp:103
LLVM_ATTRIBUTE_ALWAYS_INLINE SimDataValue & operator=(T value)
Definition SimDataValue.hpp:115
Definition SimCallbackRegistry.hpp:19
void(*)() RawFunctor
Definition SimCallbackRegistry.hpp:21
std::unique_ptr< CallbackVector > m_callbacks
Definition SimCallbackRegistry.hpp:61
wpi::util::recursive_spinlock m_mutex
Definition SimCallbackRegistry.hpp:60
int32_t DoRegister(RawFunctor callback, void *param)
Definition SimCallbackRegistry.hpp:43
LLVM_ATTRIBUTE_ALWAYS_INLINE void DoReset()
Definition SimCallbackRegistry.hpp:54
void Cancel(int32_t uid)
Definition SimCallbackRegistry.hpp:28
T m_value
Definition SimDataValue.hpp:70
SimDataValueBase(T value)
Definition SimDataValue.hpp:20
void Reset(T value)
Definition SimDataValue.hpp:31
wpi::util::recursive_spinlock & GetMutex()
Definition SimDataValue.hpp:37
LLVM_ATTRIBUTE_ALWAYS_INLINE void CancelCallback(int32_t uid)
Definition SimDataValue.hpp:22
void DoSet(T value, const char *name)
Definition SimDataValue.hpp:56
int32_t DoRegisterCallback(HAL_NotifyCallback callback, void *param, HAL_Bool initialNotify, const char *name)
Definition SimDataValue.hpp:40
T Get() const
Definition SimDataValue.hpp:24
int32_t HAL_Bool
Definition Types.h:75
Definition SimCallbackRegistry.hpp:17
WPILib Hardware Abstraction Layer (HAL) namespace.
Definition Types.hpp:9
recursive_spinlock1 recursive_spinlock
Definition spinlock.hpp:141
HAL Entry Value.
Definition Value.h:26