CTRE Phoenix 6 C++ 26.3.0
Loading...
Searching...
No Matches
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
13#include <map>
14#include <mutex>
15
16namespace ctre {
17namespace phoenix6 {
18namespace hardware {
19
20 /**
21 * \brief Parent class for all devices.
22 */
23 class ParentDevice : public virtual traits::CommonDevice {
24 protected:
26
28
29 private:
30 std::map<uint32_t, std::unique_ptr<BaseStatusSignal>> _signalValues;
31 std::recursive_mutex _signalValuesLck;
32 /*
33 * Use a shared pointer so users that access the control request via #GetAppliedControl has a copy
34 * of the pointer without risk of it becoming a dangling pointer due to parallel operations
35 */
36 std::shared_ptr<controls::ControlRequest> _controlReq = std::make_shared<controls::EmptyControl>();
37 std::mutex _controlReqLck;
38
39 struct FirmwareVersChecker {
40 private:
41 DeviceIdentifier _deviceIdentifier;
42
43 public:
44 StatusSignal<int> _compliancy;
45
46 double _creationTime = utils::GetCurrentTimeSeconds();
47 double _timeToRefreshVersion = utils::GetCurrentTimeSeconds();
49
50 FirmwareVersChecker(DeviceIdentifier deviceIdentifier);
51 void ReportIfTooOld();
52 };
53
54 std::shared_ptr<FirmwareVersChecker> _versChecker;
55 StatusSignal<int> _resetSignal;
56
57 template <typename T>
58 StatusSignal<T> &LookupCommon(
59 uint16_t spn, std::string signalName,
60 std::function<std::map<uint16_t, std::string>()> mapFiller,
61 bool reportOnConstruction, bool refresh)
62 {
64
65 BaseStatusSignal *toFind;
66 {
67 /* lock access to the map */
68 std::lock_guard<std::recursive_mutex> lock{_signalValuesLck};
69
70 /* lookup and return if found */
71 auto iter = _signalValues.find(spn);
72 if (iter != _signalValues.end()) {
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 } else {
78 /* insert into map */
79 if (!mapFiller) {
80 _signalValues.emplace(spn,
81 std::unique_ptr<StatusSignal<T>>{new StatusSignal<T>{
83 std::move(signalName),
84 [versChecker=_versChecker]() mutable {
85 versChecker->ReportIfTooOld();
86 }
87 }}
88 );
89 } else {
90 _signalValues.emplace(spn,
91 std::unique_ptr<StatusSignal<T>>{new StatusSignal<T>{
93 std::move(signalName),
94 [versChecker=_versChecker]() mutable {
95 versChecker->ReportIfTooOld();
96 },
97 mapFiller
98 }}
99 );
100 }
101
102 /* look up and return */
103 iter = _signalValues.find(spn);
104 toFind = iter->second.get();
105 }
106 }
107
108 /* Now cast it up to the StatusSignal */
109 StatusSignal<T> *ret = dynamic_cast<StatusSignal<T> *>(toFind);
110 /* If ret is null, that means the cast failed. Otherwise we can return it */
111 if (ret == nullptr) {
112 /* Cast failed, let user know this doesn't exist */
113 return failure;
114 } else {
115 /* Good cast, refresh it and return this now */
116 if (refresh) {
117 ret->Refresh(reportOnConstruction);
118 }
119 return *ret;
120 }
121 }
122
123 public:
124 ParentDevice(int deviceID, std::string model, CANBus canbus);
125 virtual ~ParentDevice() = 0; // Declare virtual destructor to make this class abstract
126
127 ParentDevice(ParentDevice const &) = delete;
129
130 /**
131 * \returns The device ID of this device [0,62].
132 */
133 int GetDeviceID() const final
134 {
136 }
137
138 /**
139 * \returns The network this device is on.
140 */
141 CANBus GetNetwork() const final
142 {
144 }
145
146 /**
147 * \brief Gets a number unique for this device's hardware type and ID.
148 * This number is not unique across networks.
149 *
150 * \details This can be used to easily reference hardware devices on
151 * the same network in collections such as maps.
152 *
153 * \returns Hash of this device.
154 */
155 uint64_t GetDeviceHash() const final
156 {
158 }
159
160 /**
161 * \brief Get the latest applied control.
162 * Caller can cast this to the derived class if they know its type. Otherwise,
163 * use controls#ControlRequest#GetControlInfo to get info out of it.
164 *
165 * \details This returns a shared pointer to avoid becoming a dangling pointer
166 * due to parallel operations changing the underlying data. Make sure
167 * to save the shared_ptr to a variable before chaining function calls,
168 * otherwise the data may be freed early.
169 *
170 * \returns Latest applied control
171 */
172 std::shared_ptr<controls::ControlRequest const> GetAppliedControl() const final
173 {
174 return _controlReq;
175 }
176
177 /**
178 * \brief Get the latest applied control.
179 * Caller can cast this to the derived class if they know its type. Otherwise,
180 * use controls#ControlRequest#GetControlInfo to get info out of it.
181 *
182 * \details This returns a shared pointer to avoid becoming a dangling pointer
183 * due to parallel operations changing the underlying data. Make sure
184 * to save the shared_ptr to a variable before chaining function calls,
185 * otherwise the data may be freed early.
186 *
187 * \returns Latest applied control
188 */
189 std::shared_ptr<controls::ControlRequest> GetAppliedControl() final
190 {
191 return _controlReq;
192 }
193
194 /**
195 * \returns true if device has reset since the previous call of this routine.
196 */
197 bool HasResetOccurred() final
198 {
199 return _resetSignal.Refresh(false).HasUpdated();
200 }
201
202 /**
203 * \returns a function that checks for device resets.
204 */
205 std::function<bool()> GetResetOccurredChecker() const final
206 {
207 return [resetSignal=_resetSignal]() mutable {
208 return resetSignal.Refresh(false).HasUpdated();
209 };
210 }
211
212 /**
213 * \brief Returns whether the device is still connected to the robot.
214 * This is equivalent to refreshing and checking the latency of the
215 * Version status signal.
216 *
217 * \param maxLatencySeconds The maximum latency of the Version status signal
218 * before the device is reported as disconnected
219 * \returns true if the device is connected
220 */
221 bool IsConnected(units::second_t maxLatencySeconds = 500_ms) final
222 {
223 return _versChecker->_compliancy.Refresh(false).GetTimestamp().GetLatency() <= maxLatencySeconds;
224 }
225
226 /**
227 * \brief This is a reserved routine for internal testing. Use the other get routines to retrieve signal values.
228 *
229 * \param signal Signal to get.
230 * \param refresh Whether to refresh
231 * \returns StatusSignalValue holding value
232 */
233 StatusSignal<double> &GetGenericSignal(uint32_t signal, bool refresh = true)
234 {
235 return LookupStatusSignal<double>((uint16_t)signal, "Generic", true, refresh);
236 }
237
238 /**
239 * \brief Optimizes the device's bus utilization by reducing the update frequencies of its status signals.
240 *
241 * All status signals that have not been explicitly given an update frequency using
242 * BaseStatusSignal#SetUpdateFrequency will be slowed down. Note that if other status
243 * signals in the same status frame have been given an update frequency, the update
244 * frequency will be honored for the entire frame.
245 *
246 * This function only needs to be called once on this device in the robot program. Additionally, this
247 * method does not necessarily need to be called after setting the update frequencies of other signals.
248 *
249 * To restore the default status update frequencies, call ResetSignalFrequencies.
250 * Alternatively, remove this method call, redeploy the robot application, and power-cycle
251 * the device on the bus. The user can also override individual status update frequencies
252 * using BaseStatusSignal#SetUpdateFrequency.
253 *
254 * \param optimizedFreqHz The update frequency to apply to the optimized status signals. A frequency
255 * of 0 Hz will turn off the signals. Otherwise, the minimum supported signal
256 * frequency is 4 Hz (default).
257 * \param timeoutSeconds Maximum amount of time to wait for each status frame when performing the action
258 * \returns Status code of the first failed update frequency set call, or OK if all succeeded
259 */
260 ctre::phoenix::StatusCode OptimizeBusUtilization(units::frequency::hertz_t optimizedFreqHz = 4_Hz, units::time::second_t timeoutSeconds = 100_ms) final;
261
262 /**
263 * \brief Optimizes the bus utilization of the provided devices by reducing the update
264 * frequencies of their status signals. This API defaults to an optimized update frequency
265 * of 4 Hz to preserve log data.
266 *
267 * All status signals that have not been explicitly given an update frequency using
268 * BaseStatusSignal#SetUpdateFrequency will be slowed down. Note that if other status
269 * signals in the same status frame have been given an update frequency, the update
270 * frequency will be honored for the entire frame.
271 *
272 * This function only needs to be called once in the robot program for the provided devices.
273 * Additionally, this method does not necessarily need to be called after setting the update
274 * frequencies of other signals.
275 *
276 * To restore the default status update frequencies, call ResetSignalFrequenciesForAll.
277 * Alternatively, remove this method call, redeploy the robot application, and power-cycle
278 * the devices on the bus. The user can also override individual status update frequencies
279 * using BaseStatusSignal#SetUpdateFrequency.
280 *
281 * This will wait up to 0.100 seconds (100ms) for each status frame.
282 *
283 * \param devices Devices for which to optimize bus utilization, passed as a comma-separated list of device references.
284 * \returns Status code of the first failed optimize call, or OK if all succeeded
285 */
286 template <std::derived_from<traits::CommonDevice>... Devices>
288 {
289 return OptimizeBusUtilizationForAll(4_Hz, devices...);
290 }
291
292 /**
293 * \brief Optimizes the bus utilization of the provided devices by reducing the update
294 * frequencies of their status signals. This API defaults to an optimized update frequency
295 * of 4 Hz to preserve log data.
296 *
297 * All status signals that have not been explicitly given an update frequency using
298 * BaseStatusSignal#SetUpdateFrequency will be slowed down. Note that if other status
299 * signals in the same status frame have been given an update frequency, the update
300 * frequency will be honored for the entire frame.
301 *
302 * This function only needs to be called once in the robot program for the provided devices.
303 * Additionally, this method does not necessarily need to be called after setting the update
304 * frequencies of other signals.
305 *
306 * To restore the default status update frequencies, call ResetSignalFrequenciesForAll.
307 * Alternatively, remove this method call, redeploy the robot application, and power-cycle
308 * the devices on the bus. The user can also override individual status update frequencies
309 * using BaseStatusSignal#SetUpdateFrequency.
310 *
311 * This will wait up to 0.100 seconds (100ms) for each status frame.
312 *
313 * \param devices Devices for which to optimize bus utilization, passed as a span of device pointers.
314 * \returns Status code of the first failed optimize call, or OK if all succeeded
315 */
316 static ctre::phoenix::StatusCode OptimizeBusUtilizationForAll(std::span<traits::CommonDevice* const> devices)
317 {
318 return OptimizeBusUtilizationForAll(4_Hz, devices);
319 }
320
321 /**
322 * \brief Optimizes the bus utilization of the provided devices by reducing the update
323 * frequencies of their status signals.
324 *
325 * All status signals that have not been explicitly given an update frequency using
326 * BaseStatusSignal#SetUpdateFrequency will be slowed down. Note that if other status
327 * signals in the same status frame have been given an update frequency, the update
328 * frequency will be honored for the entire frame.
329 *
330 * This function only needs to be called once in the robot program for the provided devices.
331 * Additionally, this method does not necessarily need to be called after setting the update
332 * frequencies of other signals.
333 *
334 * To restore the default status update frequencies, call ResetSignalFrequenciesForAll.
335 * Alternatively, remove this method call, redeploy the robot application, and power-cycle
336 * the devices on the bus. The user can also override individual status update frequencies
337 * using BaseStatusSignal#SetUpdateFrequency.
338 *
339 * This will wait up to 0.100 seconds (100ms) for each status frame.
340 *
341 * \param optimizedFreqHz The update frequency to apply to the optimized status signals. A frequency
342 * of 0 Hz will turn off the signals. Otherwise, the minimum supported signal
343 * frequency is 4 Hz (default).
344 * \param devices Devices for which to optimize bus utilization, passed as a comma-separated list of device references.
345 * \returns Status code of the first failed optimize call, or OK if all succeeded
346 */
347 template <std::derived_from<traits::CommonDevice>... Devices>
348 static ctre::phoenix::StatusCode OptimizeBusUtilizationForAll(units::frequency::hertz_t optimizedFreqHz, Devices &... devices)
349 {
350 return OptimizeBusUtilizationForAll(optimizedFreqHz, std::array<traits::CommonDevice *, sizeof...(Devices)>{(&devices)...});
351 }
352
353 /**
354 * \brief Optimizes the bus utilization of the provided devices by reducing the update
355 * frequencies of their status signals.
356 *
357 * All status signals that have not been explicitly given an update frequency using
358 * BaseStatusSignal#SetUpdateFrequency will be slowed down. Note that if other status
359 * signals in the same status frame have been given an update frequency, the update
360 * frequency will be honored for the entire frame.
361 *
362 * This function only needs to be called once in the robot program for the provided devices.
363 * Additionally, this method does not necessarily need to be called after setting the update
364 * frequencies of other signals.
365 *
366 * To restore the default status update frequencies, call ResetSignalFrequenciesForAll.
367 * Alternatively, remove this method call, redeploy the robot application, and power-cycle
368 * the devices on the bus. The user can also override individual status update frequencies
369 * using BaseStatusSignal#SetUpdateFrequency.
370 *
371 * This will wait up to 0.100 seconds (100ms) for each status frame.
372 *
373 * \param optimizedFreqHz The update frequency to apply to the optimized status signals. A frequency
374 * of 0 Hz will turn off the signals. Otherwise, the minimum supported signal
375 * frequency is 4 Hz (default).
376 * \param devices Devices for which to optimize bus utilization, passed as a span of device pointers.
377 * \returns Status code of the first failed optimize call, or OK if all succeeded
378 */
379 static ctre::phoenix::StatusCode OptimizeBusUtilizationForAll(units::frequency::hertz_t optimizedFreqHz, std::span<traits::CommonDevice* const> devices)
380 {
382 for (auto device : devices) {
383 auto const err = device->OptimizeBusUtilization(optimizedFreqHz);
384 if (retval.IsOK()) {
385 retval = err;
386 }
387 }
388 return retval;
389 }
390
391 /**
392 * \brief Resets the update frequencies of all the device's status signals to the defaults.
393 *
394 * This restores the default update frequency of all status signals, including status signals
395 * explicitly given an update frequency using BaseStatusSignal#SetUpdateFrequency and status
396 * signals optimized out using OptimizeBusUtilization.
397 *
398 * \param timeoutSeconds Maximum amount of time to wait for each status frame when performing the action
399 * \returns Status code of the first failed update frequency set call, or OK if all succeeded
400 */
401 ctre::phoenix::StatusCode ResetSignalFrequencies(units::time::second_t timeoutSeconds = 100_ms) final;
402
403 /**
404 * \brief Resets the update frequencies of all the devices' status signals to the defaults.
405 *
406 * This restores the default update frequency of all status signals, including status signals
407 * explicitly given an update frequency using BaseStatusSignal#SetUpdateFrequency and status
408 * signals optimized out using OptimizeBusUtilizationForAll.
409 *
410 * This will wait up to 0.100 seconds (100ms) for each status frame.
411 *
412 * \param devices Devices for which to restore default update frequencies, passed as a comma-separated list of device references.
413 * \returns Status code of the first failed restore call, or OK if all succeeded
414 */
415 template <std::derived_from<traits::CommonDevice>... Devices>
417 {
418 return ResetSignalFrequenciesForAll(std::array<traits::CommonDevice *, sizeof...(Devices)>{(&devices)...});
419 }
420
421 /**
422 * \brief Resets the update frequencies of all the devices' status signals to the defaults.
423 *
424 * This restores the default update frequency of all status signals, including status signals
425 * explicitly given an update frequency using BaseStatusSignal#SetUpdateFrequency and status
426 * signals optimized out using OptimizeBusUtilizationForAll.
427 *
428 * This will wait up to 0.100 seconds (100ms) for each status frame.
429 *
430 * \param devices Devices for which to restore default update frequencies, passed as a span of device pointers.
431 * \returns Status code of the first failed restore call, or OK if all succeeded
432 */
433 static ctre::phoenix::StatusCode ResetSignalFrequenciesForAll(std::span<traits::CommonDevice* const> devices)
434 {
436 for (auto device : devices) {
437 auto const err = device->ResetSignalFrequencies();
438 if (retval.IsOK()) {
439 retval = err;
440 }
441 }
442 return retval;
443 }
444
445 protected:
447
448 template <typename T>
449 StatusSignal<T> &LookupStatusSignal(uint16_t spn, std::string signalName, bool reportOnConstruction, bool refresh)
450 {
451 return LookupCommon<T>(spn, std::move(signalName), nullptr, reportOnConstruction, refresh);
452 }
453
454 template <typename T>
455 StatusSignal<T> &LookupStatusSignal(uint16_t spn, std::string signalName, std::function<std::map<uint16_t, std::string>()> mapFiller, bool reportOnConstruction, bool refresh)
456 {
457 return LookupCommon<T>(spn, std::move(signalName), std::move(mapFiller), reportOnConstruction, refresh);
458 }
459 };
460
461}
462}
463}
Class for getting information about an available CAN bus.
Definition CANBus.hpp:19
Represents a status signal with data of type T, and operations available to retrieve information abou...
Definition StatusSignal.hpp:567
StatusSignal< T > & Refresh(bool reportError=true)
Refreshes the value of this status signal.
Definition StatusSignal.hpp:638
Common interface implemented by all control requests.
Definition ControlRequest.hpp:27
Generic Empty Control class used to do nothing.
Definition ControlRequest.hpp:65
The unique identifier for a device.
Definition DeviceIdentifier.hpp:19
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:23
virtual ctre::phoenix::StatusCode SetControlPrivate(controls::ControlRequest const &request)
CANBus GetNetwork() const final
Definition ParentDevice.hpp:141
StatusSignal< T > & LookupStatusSignal(uint16_t spn, std::string signalName, std::function< std::map< uint16_t, std::string >()> mapFiller, bool reportOnConstruction, bool refresh)
Definition ParentDevice.hpp:455
static ctre::phoenix::StatusCode ResetSignalFrequenciesForAll(Devices &... devices)
Resets the update frequencies of all the devices' status signals to the defaults.
Definition ParentDevice.hpp:416
DeviceIdentifier deviceIdentifier
Definition ParentDevice.hpp:27
uint64_t GetDeviceHash() const final
Gets a number unique for this device's hardware type and ID.
Definition ParentDevice.hpp:155
StatusSignal< T > & LookupStatusSignal(uint16_t spn, std::string signalName, bool reportOnConstruction, bool refresh)
Definition ParentDevice.hpp:449
ParentDevice(ParentDevice const &)=delete
bool IsConnected(units::second_t maxLatencySeconds=500_ms) final
Returns whether the device is still connected to the robot.
Definition ParentDevice.hpp:221
ctre::phoenix::StatusCode ResetSignalFrequencies(units::time::second_t timeoutSeconds=100_ms) final
Resets the update frequencies of all the device's status signals to the defaults.
static ctre::phoenix::StatusCode ResetSignalFrequenciesForAll(std::span< traits::CommonDevice *const > devices)
Resets the update frequencies of all the devices' status signals to the defaults.
Definition ParentDevice.hpp:433
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:287
static constexpr controls::EmptyControl _emptyControl
Definition ParentDevice.hpp:25
static ctre::phoenix::StatusCode OptimizeBusUtilizationForAll(std::span< traits::CommonDevice *const > devices)
Optimizes the bus utilization of the provided devices by reducing the update frequencies of their sta...
Definition ParentDevice.hpp:316
static ctre::phoenix::StatusCode OptimizeBusUtilizationForAll(units::frequency::hertz_t optimizedFreqHz, std::span< traits::CommonDevice *const > devices)
Optimizes the bus utilization of the provided devices by reducing the update frequencies of their sta...
Definition ParentDevice.hpp:379
int GetDeviceID() const final
Definition ParentDevice.hpp:133
ParentDevice(int deviceID, std::string model, CANBus canbus)
ctre::phoenix::StatusCode OptimizeBusUtilization(units::frequency::hertz_t optimizedFreqHz=4_Hz, units::time::second_t timeoutSeconds=100_ms) final
Optimizes the device's bus utilization by reducing the update frequencies of its status signals.
std::function< bool()> GetResetOccurredChecker() const final
Definition ParentDevice.hpp:205
std::shared_ptr< controls::ControlRequest const > GetAppliedControl() const final
Get the latest applied control.
Definition ParentDevice.hpp:172
StatusSignal< double > & GetGenericSignal(uint32_t signal, bool refresh=true)
This is a reserved routine for internal testing.
Definition ParentDevice.hpp:233
static ctre::phoenix::StatusCode OptimizeBusUtilizationForAll(units::frequency::hertz_t optimizedFreqHz, Devices &... devices)
Optimizes the bus utilization of the provided devices by reducing the update frequencies of their sta...
Definition ParentDevice.hpp:348
std::shared_ptr< controls::ControlRequest > GetAppliedControl() final
Get the latest applied control.
Definition ParentDevice.hpp:189
ParentDevice & operator=(ParentDevice const &)=delete
bool HasResetOccurred() final
Definition ParentDevice.hpp:197
Contains everything common between Phoenix 6 devices.
Definition CommonDevice.hpp:23
Status codes reported by APIs, including OK, warnings, and errors.
Definition StatusCodes.h:28
static constexpr int OK
No Error.
Definition StatusCodes.h:35
static constexpr int InvalidParamValue
An invalid argument was passed into the function/VI, such as a null pointer.
Definition StatusCodes.h:370
static constexpr int CouldNotRetrieveV6Firmware
Device firmware could not be retrieved.
Definition StatusCodes.h:724
constexpr bool IsOK() const
Definition StatusCodes.h:864
CTREXPORT double GetCurrentTimeSeconds()
Get the current timestamp in seconds.
Definition motor_constants.h:14