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