WPILibC++  2019.1.1-beta-1-37-g43d188a
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Modules Pages
SimDataValue.h
1 /*----------------------------------------------------------------------------*/
2 /* Copyright (c) 2018 FIRST. All Rights Reserved. */
3 /* Open Source Software - may be modified and shared by FRC teams. The code */
4 /* must be accompanied by the FIRST BSD license file in the root directory of */
5 /* the project. */
6 /*----------------------------------------------------------------------------*/
7 
8 #pragma once
9 
10 #include <memory>
11 
12 #include <wpi/Compiler.h>
13 #include <wpi/UidVector.h>
14 #include <wpi/spinlock.h>
15 
16 #include "mockdata/NotifyListener.h"
17 #include "mockdata/SimCallbackRegistry.h"
18 
19 namespace hal {
20 
21 namespace impl {
22 template <typename T, HAL_Value (*MakeValue)(T)>
24  public:
25  explicit SimDataValueBase(T value) : m_value(value) {}
26 
27  LLVM_ATTRIBUTE_ALWAYS_INLINE void CancelCallback(int32_t uid) { Cancel(uid); }
28 
29  T Get() const {
30  std::lock_guard<wpi::recursive_spinlock> lock(m_mutex);
31  return m_value;
32  }
33 
34  LLVM_ATTRIBUTE_ALWAYS_INLINE operator T() const { return Get(); }
35 
36  void Reset(T value) {
37  std::lock_guard<wpi::recursive_spinlock> lock(m_mutex);
38  DoReset();
39  m_value = value;
40  }
41 
42  wpi::recursive_spinlock& GetMutex() { return m_mutex; }
43 
44  protected:
45  int32_t DoRegisterCallback(HAL_NotifyCallback callback, void* param,
46  HAL_Bool initialNotify, const char* name) {
47  std::unique_lock<wpi::recursive_spinlock> lock(m_mutex);
48  int32_t newUid = DoRegister(reinterpret_cast<RawFunctor>(callback), param);
49  if (newUid == -1) return -1;
50  if (initialNotify) {
51  // We know that the callback is not null because of earlier null check
52  HAL_Value value = MakeValue(m_value);
53  lock.unlock();
54  callback(name, param, &value);
55  }
56  return newUid + 1;
57  }
58 
59  void DoSet(T value, const char* name) {
60  std::lock_guard<wpi::recursive_spinlock> lock(this->m_mutex);
61  if (m_value != value) {
62  m_value = value;
63  if (m_callbacks) {
64  HAL_Value halValue = MakeValue(value);
65  for (auto&& cb : *m_callbacks)
66  reinterpret_cast<HAL_NotifyCallback>(cb.callback)(name, cb.param,
67  &halValue);
68  }
69  }
70  }
71 
72  T m_value;
73 };
74 } // namespace impl
75 
86 template <typename T, HAL_Value (*MakeValue)(T), const char* (*GetName)(),
87  T (*GetDefault)() = nullptr>
89  public:
90  SimDataValue()
92  GetDefault != nullptr ? GetDefault() : T()) {}
93  explicit SimDataValue(T value)
95 
96  LLVM_ATTRIBUTE_ALWAYS_INLINE int32_t RegisterCallback(
97  HAL_NotifyCallback callback, void* param, HAL_Bool initialNotify) {
98  return this->DoRegisterCallback(callback, param, initialNotify, GetName());
99  }
100 
101  LLVM_ATTRIBUTE_ALWAYS_INLINE void Set(T value) {
102  this->DoSet(value, GetName());
103  }
104 
105  LLVM_ATTRIBUTE_ALWAYS_INLINE SimDataValue& operator=(T value) {
106  Set(value);
107  return *this;
108  }
109 };
110 
116 #define HAL_SIMDATAVALUE_DEFINE_NAME(NAME) \
117  static LLVM_ATTRIBUTE_ALWAYS_INLINE constexpr const char* \
118  Get##NAME##Name() { \
119  return #NAME; \
120  }
121 
139 #define HAL_SIMDATAVALUE_DEFINE_CAPI(TYPE, NS, CAPINAME, DATA, LOWERNAME) \
140  int32_t NS##_Register##CAPINAME##Callback( \
141  int32_t index, HAL_NotifyCallback callback, void* param, \
142  HAL_Bool initialNotify) { \
143  return DATA[index].LOWERNAME.RegisterCallback(callback, param, \
144  initialNotify); \
145  } \
146  \
147  void NS##_Cancel##CAPINAME##Callback(int32_t index, int32_t uid) { \
148  DATA[index].LOWERNAME.CancelCallback(uid); \
149  } \
150  \
151  TYPE NS##_Get##CAPINAME(int32_t index) { return DATA[index].LOWERNAME; } \
152  \
153  void NS##_Set##CAPINAME(int32_t index, TYPE LOWERNAME) { \
154  DATA[index].LOWERNAME = LOWERNAME; \
155  }
156 
174 #define HAL_SIMDATAVALUE_DEFINE_CAPI_CHANNEL(TYPE, NS, CAPINAME, DATA, \
175  LOWERNAME) \
176  int32_t NS##_Register##CAPINAME##Callback( \
177  int32_t index, int32_t channel, HAL_NotifyCallback callback, \
178  void* param, HAL_Bool initialNotify) { \
179  return DATA[index].LOWERNAME[channel].RegisterCallback(callback, param, \
180  initialNotify); \
181  } \
182  \
183  void NS##_Cancel##CAPINAME##Callback(int32_t index, int32_t channel, \
184  int32_t uid) { \
185  DATA[index].LOWERNAME[channel].CancelCallback(uid); \
186  } \
187  \
188  TYPE NS##_Get##CAPINAME(int32_t index, int32_t channel) { \
189  return DATA[index].LOWERNAME[channel]; \
190  } \
191  \
192  void NS##_Set##CAPINAME(int32_t index, int32_t channel, TYPE LOWERNAME) { \
193  DATA[index].LOWERNAME[channel] = LOWERNAME; \
194  }
195 
212 #define HAL_SIMDATAVALUE_DEFINE_CAPI_NOINDEX(TYPE, NS, CAPINAME, DATA, \
213  LOWERNAME) \
214  int32_t NS##_Register##CAPINAME##Callback( \
215  HAL_NotifyCallback callback, void* param, HAL_Bool initialNotify) { \
216  return DATA->LOWERNAME.RegisterCallback(callback, param, initialNotify); \
217  } \
218  \
219  void NS##_Cancel##CAPINAME##Callback(int32_t uid) { \
220  DATA->LOWERNAME.CancelCallback(uid); \
221  } \
222  \
223  TYPE NS##_Get##CAPINAME(void) { return DATA->LOWERNAME; } \
224  \
225  void NS##_Set##CAPINAME(TYPE LOWERNAME) { DATA->LOWERNAME = LOWERNAME; }
226 
227 } // namespace hal
Definition: SimCallbackRegistry.h:23
A recursive spinlock mutex.
Definition: spinlock.h:46
Definition: SimDataValue.h:23
HAL Entry Value.
Definition: HAL_Value.h:25
WPILib Hardware Abstraction Layer (HAL) namespace.
Definition: SimDataValue.h:19
Simulation data value wrapper.
Definition: SimDataValue.h:88