Loading [MathJax]/extensions/tex2jax.js
CTRE Phoenix 6 C++ 23.10.0-alpha-8
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros
ParentDevice.hpp
Go to the documentation of this file.
1/*
2 * Copyright (C) Cross The Road Electronics.  All rights reserved.
3 * License information can be found in CTRE_LICENSE.txt
4 * For support and suggestions contact support@ctr-electronics.com or file
5 * an issue tracker at https://github.com/CrossTheRoadElec/Phoenix-Releases
6 */
7#pragma once
8
17#include <map>
18#include <memory>
19#include <mutex>
20#include <units/dimensionless.h>
21
22namespace ctre {
23namespace phoenix6 {
24namespace hardware {
25
26 /**
27 * Parent class for all devices
28 */
30 {
31 protected:
33
34 virtual void ReportIfTooOld() = 0;
35
36 /**
37 * \brief Type trait to verify that all types passed in are convertible to ParentDevice references.
38 */
39 template <typename... Devices>
41 std::conjunction<std::is_convertible<Devices &, ParentDevice &>...>
42 {};
43
44 /**
45 * \brief Whether all types passed in are convertible to ParentDevice references.
46 */
47 template <typename... Devices>
48 static constexpr bool is_all_device_v = is_all_device<Devices...>::value;
49
50 private:
51 std::map<uint32_t, std::unique_ptr<BaseStatusSignal>> _signalValues;
52 std::recursive_mutex _signalValuesLck;
53 /**
54 * Use a shared pointer so users that access the control request via #GetAppliedControl has a copy
55 * of the pointer without risk of it becoming a dangling pointer due to parallel operations
56 */
57 std::shared_ptr<controls::ControlRequest> _controlReq = std::make_shared<controls::EmptyControl>();
58 std::mutex _controlReqLck;
59
60 template <typename T>
61 StatusSignal<T> &LookupCommon(uint16_t spn, uint16_t mapper_iter, std::function<std::map<int, StatusSignal<T>>()> map_filler, std::string signalName, bool reportOnConstruction)
62 {
63 BaseStatusSignal *toFind;
64 {
65 /* lock access to the map */
66 std::lock_guard<std::recursive_mutex> lock{_signalValuesLck};
67
68 const uint32_t totalHash = spn | ((uint32_t)mapper_iter << 16);
69 /* lookup and return if found */
70 auto iter = _signalValues.find(totalHash);
71 if (iter != _signalValues.end())
72 {
73 /* Found it, toFind is now the found StatusSignal */
74 toFind = iter->second.get();
75 /* since we didn't construct, report errors */
76 reportOnConstruction = true;
77 }
78 else
79 {
80 /* insert into map */
81 /* Mapper_iter is 0 when using straight SPNs, otherwise it's nonzero for switchable SPNs */
82 if (mapper_iter != 0)
83 {
84 /* Switchable spn, so generate the map to switch with */
85 _signalValues.emplace(totalHash, std::unique_ptr<StatusSignal<T>>{new StatusSignal<T>{
86 deviceIdentifier, spn, [this]()
87 { ReportIfTooOld(); },
88 map_filler, std::move(signalName)}});
89 }
90 else
91 {
92 /* Non-switchable spn, so just add the SPN plain */
93 _signalValues.emplace(totalHash, std::unique_ptr<StatusSignal<T>>{new StatusSignal<T>{
94 deviceIdentifier, spn, [this]()
95 { ReportIfTooOld(); },
96 std::move(signalName)}});
97 }
98
99 /* look up and return */
100 iter = _signalValues.find(totalHash);
101 toFind = iter->second.get();
102 }
103 }
104
105 /* Now cast it up to the StatusSignal */
106 StatusSignal<T> *ret = dynamic_cast<StatusSignal<T> *>(toFind);
107 /* If ret is null, that means the cast failed. Otherwise we can return it */
108 if (ret == nullptr)
109 {
110 /* Cast failed, let user know this doesn't exist */
111 static StatusSignal<T> failure{ctre::phoenix::StatusCode::InvalidParamValue};
112 return failure;
113 }
114 else
115 {
116 /* Good cast, refresh it and return this now */
117 ret->Refresh(reportOnConstruction);
118 return *ret;
119 }
120 }
121
122 public:
123 ParentDevice(int deviceID, std::string model, std::string canbus) :
124 deviceIdentifier{DeviceIdentifier{deviceID, std::move(model), std::move(canbus)}}
125 {
127 }
128
129 /**
130 * \returns The device ID of this device [0,62].
131 */
132 int GetDeviceID() const
133 {
135 }
136
137 /**
138 * \returns Name of the network this device is on.
139 */
140 const std::string &GetNetwork() const
141 {
143 }
144
145 /**
146 * \brief Gets a number unique for this device's hardware type and ID.
147 * This number is not unique across networks.
148 *
149 * \details This can be used to easily reference hardware devices on
150 * the same network in collections such as maps.
151 *
152 * \returns Hash of this device.
153 */
154 uint64_t GetDeviceHash() const
155 {
157 }
158
159 static constexpr double kDefaultControlRatePeriodsSec = 0.010;
160
161 /**
162 * \brief Get the latest applied control.
163 * Caller can cast this to the derived class if they know its type. Otherwise,
164 * use controls#ControlRequest#GetControlInfo to get info out of it.
165 *
166 * \details This returns a shared pointer to avoid becoming a dangling pointer
167 * due to parallel operations changing the underlying data. Make sure
168 * to save the shared_ptr to a variable before chaining function calls,
169 * otherwise the data may be freed early.
170 *
171 * \returns Latest applied control
172 */
173 std::shared_ptr<const controls::ControlRequest> GetAppliedControl() const
174 {
175 return _controlReq;
176 }
177
178 /**
179 * \brief Get the latest applied control.
180 * Caller can cast this to the derived class if they know its type. Otherwise,
181 * use controls#ControlRequest#GetControlInfo to get info out of it.
182 *
183 * \details This returns a shared pointer to avoid becoming a dangling pointer
184 * due to parallel operations changing the underlying data. Make sure
185 * to save the shared_ptr to a variable before chaining function calls,
186 * otherwise the data may be freed early.
187 *
188 * \returns Latest applied control
189 */
190 std::shared_ptr<controls::ControlRequest> GetAppliedControl()
191 {
192 return _controlReq;
193 }
194
195 /**
196 * \brief This is a reserved routine for internal testing. Use the other get routines to retrieve signal values.
197 *
198 * \param signal Signal to get.
199 * \return StatusSignalValue holding value
200 */
202 {
203 return LookupStatusSignal<double>((uint16_t)signal, "Generic", true);
204 }
205
206 /**
207 * \brief Optimizes the device's bus utilization by reducing the update frequencies of its status signals.
208 *
209 * All status signals that have not been explicitly given an update frequency using
210 * BaseStatusSignal#SetUpdateFrequency will be disabled. Note that if other status
211 * signals in the same status frame have been given an update frequency, the update
212 * frequency will be honored for the entire frame.
213 *
214 * This function only needs to be called once on this device in the robot program. Additionally, this
215 * method does not necessarily need to be called after setting the update frequencies of other signals.
216 *
217 * To restore the default status update frequencies, remove this method call, redeploy the robot
218 * application, and power-cycle the devices on the bus. Alternatively, the user can override
219 * individual status update frequencies using BaseStatusSignal#SetUpdateFrequency.
220 *
221 * \param timeoutSeconds Maximum amount of time to wait for each status frame when performing the action
222 * \return Status code of the first failed update frequency set call, or OK if all succeeded
223 */
224 ctre::phoenix::StatusCode OptimizeBusUtilization(units::time::second_t timeoutSeconds = 50_ms);
225
226 /**
227 * \brief Optimizes the bus utilization of the provided devices by reducing the update
228 * frequencies of their status signals.
229 *
230 * All status signals that have not been explicitly given an update frequency using
231 * BaseStatusSignal#SetUpdateFrequency will be disabled. Note that if other status
232 * signals in the same status frame have been given an update frequency, the update
233 * frequency will be honored for the entire frame.
234 *
235 * This function only needs to be called once in the robot program for the provided devices.
236 * Additionally, this method does not necessarily need to be called after setting the update
237 * frequencies of other signals.
238 *
239 * To restore the default status update frequencies, remove this method call, redeploy the robot
240 * application, and power-cycle the devices on the bus. Alternatively, the user can override
241 * individual status update frequencies using BaseStatusSignal#SetUpdateFrequency.
242 *
243 * This will wait up to 0.050 seconds (50ms) for each status frame.
244 *
245 * \param devices Devices for which to optimize bus utilization, passed as a comma-separated list of device references.
246 * \return Status code of the first failed optimize call, or OK if all succeeded
247 */
248 template <typename... Devices, typename = std::enable_if_t<is_all_device_v<Devices...>>>
249 static ctre::phoenix::StatusCode OptimizeBusUtilizationForAll(Devices &... devices)
250 {
251 return OptimizeBusUtilizationForAll(std::array<ParentDevice *, sizeof...(Devices)>{(&devices)...});
252 }
253
254 /**
255 * \brief Optimizes the bus utilization of the provided devices by reducing the update
256 * frequencies of their status signals.
257 *
258 * All status signals that have not been explicitly given an update frequency using
259 * BaseStatusSignal#SetUpdateFrequency will be disabled. Note that if other status
260 * signals in the same status frame have been given an update frequency, the update
261 * frequency will be honored for the entire frame.
262 *
263 * This function only needs to be called once in the robot program for the provided devices.
264 * Additionally, this method does not necessarily need to be called after setting the update
265 * frequencies of other signals.
266 *
267 * To restore the default status update frequencies, remove this method call, redeploy the robot
268 * application, and power-cycle the devices on the bus. Alternatively, the user can override
269 * individual status update frequencies using BaseStatusSignal#SetUpdateFrequency.
270 *
271 * This will wait up to 0.050 seconds (50ms) for each status frame.
272 *
273 * \param devices Devices for which to optimize bus utilization, passed as a vector or initializer list of device addresses.
274 * \return Status code of the first failed optimize call, or OK if all succeeded
275 */
276 static ctre::phoenix::StatusCode OptimizeBusUtilizationForAll(const std::vector<ParentDevice *> &devices)
277 {
278 ctre::phoenix::StatusCode retval = ctre::phoenix::StatusCode::OK;
279 for (auto device : devices) {
280 const auto err = device->OptimizeBusUtilization();
281 if (retval.IsOK()) {
282 retval = err;
283 }
284 }
285 return retval;
286 }
287
288 /**
289 * \brief Optimizes the bus utilization of the provided devices by reducing the update
290 * frequencies of their status signals.
291 *
292 * All status signals that have not been explicitly given an update frequency using
293 * BaseStatusSignal#SetUpdateFrequency will be disabled. Note that if other status
294 * signals in the same status frame have been given an update frequency, the update
295 * frequency will be honored for the entire frame.
296 *
297 * This function only needs to be called once in the robot program for the provided devices.
298 * Additionally, this method does not necessarily need to be called after setting the update
299 * frequencies of other signals.
300 *
301 * To restore the default status update frequencies, remove this method call, redeploy the robot
302 * application, and power-cycle the devices on the bus. Alternatively, the user can override
303 * individual status update frequencies using BaseStatusSignal#SetUpdateFrequency.
304 *
305 * This will wait up to 0.050 seconds (50ms) for each status frame.
306 *
307 * \param devices Devices for which to optimize bus utilization, passed as an array of device addresses.
308 * \return Status code of the first failed optimize call, or OK if all succeeded
309 */
310 template <size_t N>
311 static ctre::phoenix::StatusCode OptimizeBusUtilizationForAll(const std::array<ParentDevice *, N> &devices)
312 {
313 ctre::phoenix::StatusCode retval = ctre::phoenix::StatusCode::OK;
314 for (auto device : devices) {
315 const auto err = device->OptimizeBusUtilization();
316 if (retval.IsOK()) {
317 retval = err;
318 }
319 }
320 return retval;
321 }
322
323 protected:
324 virtual ctre::phoenix::StatusCode SetControlPrivate(controls::ControlRequest &request);
325
326 template <typename T>
327 StatusSignal<T> &LookupStatusSignal(uint16_t spn, std::string signalName, bool reportOnConstruction)
328 {
329 std::function<std::map<int, StatusSignal<T>>()> emptyMapFiller = []
330 {
331 return std::map<int, StatusSignal<T>>{};
332 };
333 return LookupCommon<T>(spn, 0, emptyMapFiller, std::move(signalName), reportOnConstruction);
334 }
335
336 template <typename T>
337 StatusSignal<T> &LookupStatusSignal(uint16_t spn, uint16_t mapper_iter, std::function<std::map<int, StatusSignal<T>>()> map_filler, std::string signalName, bool reportOnConstruction)
338 {
339 return LookupCommon<T>(spn, mapper_iter, map_filler, std::move(signalName), reportOnConstruction);
340 }
341
342 /** Returns a unitless version of the StatusSignal by value. Do not store the result in a reference. */
343 template <typename T, typename U>
344 StatusSignal<T> LookupDimensionlessStatusSignal(uint16_t spn, std::string signalName)
345 {
346 return StatusSignal<T>{LookupStatusSignal<U>(spn, std::move(signalName), true)};
347 }
348 };
349
350}
351}
352}
Cross the Road Electronics End User License Agreement This Software License or “Customer” and Cross The Road Electronics a Michigan based company with its principal place of business located at MI Terms Agreement means this End User License Agreement that forms the entire agreement between You and the Company regarding the use of the Software Leone USA Content refers to content such as or other information that can be linked to or otherwise made available by regardless of the form of that content Device means a hardware product or sold by Company Software means a collection of software supplied by Company that interacts with Devices and or simulates the behavior of Devices
Definition: CTRE_LICENSE.txt:22
@ OK
No Error.
Definition: StatusCodes.h:1169
@ InvalidParamValue
Incorrect argument passed into function/VI.
Definition: StatusCodes.h:1501
Class that provides operations to retrieve information about a status signal.
Definition: StatusSignal.hpp:45
Represents a status signal with data of type T, and operations available to retrieve information abou...
Definition: StatusSignal.hpp:626
Abstract Control Request class that other control requests extend for use.
Definition: ControlRequest.hpp:28
Definition: DeviceIdentifier.hpp:19
std::string model
Definition: DeviceIdentifier.hpp:22
int deviceID
Definition: DeviceIdentifier.hpp:23
uint32_t deviceHash
Definition: DeviceIdentifier.hpp:24
std::string network
Definition: DeviceIdentifier.hpp:21
Parent class for all devices.
Definition: ParentDevice.hpp:30
const std::string & GetNetwork() const
Definition: ParentDevice.hpp:140
static constexpr bool is_all_device_v
Whether all types passed in are convertible to ParentDevice references.
Definition: ParentDevice.hpp:48
std::shared_ptr< controls::ControlRequest > GetAppliedControl()
Get the latest applied control.
Definition: ParentDevice.hpp:190
virtual ctre::phoenix::StatusCode SetControlPrivate(controls::ControlRequest &request)
DeviceIdentifier deviceIdentifier
Definition: ParentDevice.hpp:32
StatusSignal< T > & LookupStatusSignal(uint16_t spn, std::string signalName, bool reportOnConstruction)
Definition: ParentDevice.hpp:327
std::shared_ptr< const controls::ControlRequest > GetAppliedControl() const
Get the latest applied control.
Definition: ParentDevice.hpp:173
ctre::phoenix::StatusCode OptimizeBusUtilization(units::time::second_t timeoutSeconds=50_ms)
Optimizes the device's bus utilization by reducing the update frequencies of its status signals.
static ctre::phoenix::StatusCode OptimizeBusUtilizationForAll(const std::array< ParentDevice *, N > &devices)
Optimizes the bus utilization of the provided devices by reducing the update frequencies of their sta...
Definition: ParentDevice.hpp:311
static ctre::phoenix::StatusCode OptimizeBusUtilizationForAll(Devices &... devices)
Optimizes the bus utilization of the provided devices by reducing the update frequencies of their sta...
Definition: ParentDevice.hpp:249
StatusSignal< double > & GetGenericSignal(uint32_t signal)
This is a reserved routine for internal testing.
Definition: ParentDevice.hpp:201
StatusSignal< T > LookupDimensionlessStatusSignal(uint16_t spn, std::string signalName)
Returns a unitless version of the StatusSignal by value.
Definition: ParentDevice.hpp:344
int GetDeviceID() const
Definition: ParentDevice.hpp:132
ParentDevice(int deviceID, std::string model, std::string canbus)
Definition: ParentDevice.hpp:123
uint64_t GetDeviceHash() const
Gets a number unique for this device's hardware type and ID.
Definition: ParentDevice.hpp:154
static constexpr double kDefaultControlRatePeriodsSec
Definition: ParentDevice.hpp:159
StatusSignal< T > & LookupStatusSignal(uint16_t spn, uint16_t mapper_iter, std::function< std::map< int, StatusSignal< T > >()> map_filler, std::string signalName, bool reportOnConstruction)
Definition: ParentDevice.hpp:337
static ctre::phoenix::StatusCode OptimizeBusUtilizationForAll(const std::vector< ParentDevice * > &devices)
Optimizes the bus utilization of the provided devices by reducing the update frequencies of their sta...
Definition: ParentDevice.hpp:276
CTREXPORT int FRC_Report(int resource, int instanceNumber, std::string const &canbus="", int callerIdx=0, int context=0, const char *feature=nullptr)
Definition: ManualEvent.hpp:12
Type trait to verify that all types passed in are convertible to ParentDevice references.
Definition: ParentDevice.hpp:42