CTRE Phoenix 6 C++ 26.0.0-beta-1
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 double _creationTime = utils::GetCurrentTimeSeconds();
45 double _timeToRefreshVersion = utils::GetCurrentTimeSeconds();
47
48 std::unique_ptr<StatusSignal<int>> _compliancy;
49
50 FirmwareVersChecker(DeviceIdentifier deviceIdentifier) :
51 _deviceIdentifier{std::move(deviceIdentifier)}
52 {}
53 void ReportIfTooOld();
54 };
55
56 std::shared_ptr<FirmwareVersChecker> _versChecker;
57 StatusSignal<int> _resetSignal;
58
59 template <typename T>
60 StatusSignal<T> &LookupCommon(
61 uint16_t spn, std::string signalName,
62 std::function<std::map<uint16_t, std::string>()> mapFiller,
63 bool reportOnConstruction, bool refresh)
64 {
65 static StatusSignal<T> failure{ctre::phoenix::StatusCode::InvalidParamValue};
66
67 BaseStatusSignal *toFind;
68 {
69 /* lock access to the map */
70 std::lock_guard<std::recursive_mutex> lock{_signalValuesLck};
71
72 /* lookup and return if found */
73 auto iter = _signalValues.find(spn);
74 if (iter != _signalValues.end()) {
75 /* Found it, toFind is now the found StatusSignal */
76 toFind = iter->second.get();
77 /* since we didn't construct, report errors */
78 reportOnConstruction = true;
79 } else {
80 /* insert into map */
81 if (!mapFiller) {
82 _signalValues.emplace(spn,
83 std::unique_ptr<StatusSignal<T>>{new StatusSignal<T>{
85 std::move(signalName),
86 [versChecker=_versChecker]() mutable {
87 versChecker->ReportIfTooOld();
88 }
89 }}
90 );
91 } else {
92 _signalValues.emplace(spn,
93 std::unique_ptr<StatusSignal<T>>{new StatusSignal<T>{
95 std::move(signalName),
96 [versChecker=_versChecker]() mutable {
97 versChecker->ReportIfTooOld();
98 },
99 mapFiller
100 }}
101 );
102 }
103
104 /* look up and return */
105 iter = _signalValues.find(spn);
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 {
138 }
139
140 /**
141 * \returns The network this device is on.
142 */
143 CANBus GetNetwork() const final
144 {
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 uint64_t GetDeviceHash() const final
158 {
160 }
161
162 /**
163 * \brief Get the latest applied control.
164 * Caller can cast this to the derived class if they know its type. Otherwise,
165 * use controls#ControlRequest#GetControlInfo to get info out of it.
166 *
167 * \details This returns a shared pointer to avoid becoming a dangling pointer
168 * due to parallel operations changing the underlying data. Make sure
169 * to save the shared_ptr to a variable before chaining function calls,
170 * otherwise the data may be freed early.
171 *
172 * \returns Latest applied control
173 */
174 std::shared_ptr<controls::ControlRequest const> GetAppliedControl() const final
175 {
176 return _controlReq;
177 }
178
179 /**
180 * \brief Get the latest applied control.
181 * Caller can cast this to the derived class if they know its type. Otherwise,
182 * use controls#ControlRequest#GetControlInfo to get info out of it.
183 *
184 * \details This returns a shared pointer to avoid becoming a dangling pointer
185 * due to parallel operations changing the underlying data. Make sure
186 * to save the shared_ptr to a variable before chaining function calls,
187 * otherwise the data may be freed early.
188 *
189 * \returns Latest applied control
190 */
191 std::shared_ptr<controls::ControlRequest> GetAppliedControl() final
192 {
193 return _controlReq;
194 }
195
196 /**
197 * \returns true if device has reset since the previous call of this routine.
198 */
199 bool HasResetOccurred() final
200 {
201 return _resetSignal.Refresh(false).HasUpdated();
202 }
203
204 /**
205 * \returns a function that checks for device resets.
206 */
207 std::function<bool()> GetResetOccurredChecker() const final
208 {
209 return [resetSignal=_resetSignal]() mutable {
210 return resetSignal.Refresh(false).HasUpdated();
211 };
212 }
213
214 /**
215 * \brief Returns whether the device is still connected to the robot.
216 * This is equivalent to refreshing and checking the latency of the
217 * Version status signal.
218 *
219 * \param maxLatencySeconds The maximum latency of the Version status signal
220 * before the device is reported as disconnected
221 * \returns true if the device is connected
222 */
223 bool IsConnected(units::second_t maxLatencySeconds = 500_ms) final
224 {
225 return _versChecker->_compliancy &&
226 _versChecker->_compliancy->Refresh(false).GetTimestamp().GetLatency() <= maxLatencySeconds;
227 }
228
229 /**
230 * \brief This is a reserved routine for internal testing. Use the other get routines to retrieve signal values.
231 *
232 * \param signal Signal to get.
233 * \param refresh Whether to refresh
234 * \returns StatusSignalValue holding value
235 */
236 StatusSignal<double> &GetGenericSignal(uint32_t signal, bool refresh = true)
237 {
238 return LookupStatusSignal<double>((uint16_t)signal, "Generic", true, refresh);
239 }
240
241 /**
242 * \brief Optimizes the device's bus utilization by reducing the update frequencies of its status signals.
243 *
244 * All status signals that have not been explicitly given an update frequency using
245 * BaseStatusSignal#SetUpdateFrequency will be slowed down. Note that if other status
246 * signals in the same status frame have been given an update frequency, the update
247 * frequency will be honored for the entire frame.
248 *
249 * This function only needs to be called once on this device in the robot program. Additionally, this
250 * method does not necessarily need to be called after setting the update frequencies of other signals.
251 *
252 * To restore the default status update frequencies, call ResetSignalFrequencies.
253 * Alternatively, remove this method call, redeploy the robot application, and power-cycle
254 * the device on the bus. The user can also override individual status update frequencies
255 * using BaseStatusSignal#SetUpdateFrequency.
256 *
257 * \param optimizedFreqHz The update frequency to apply to the optimized status signals. A frequency
258 * of 0 Hz will turn off the signals. Otherwise, the minimum supported signal
259 * frequency is 4 Hz (default).
260 * \param timeoutSeconds Maximum amount of time to wait for each status frame when performing the action
261 * \returns Status code of the first failed update frequency set call, or OK if all succeeded
262 */
263 ctre::phoenix::StatusCode OptimizeBusUtilization(units::frequency::hertz_t optimizedFreqHz = 4_Hz, units::time::second_t timeoutSeconds = 100_ms) final;
264
265 /**
266 * \brief Optimizes the bus utilization of the provided devices by reducing the update
267 * frequencies of their status signals. This API defaults to an optimized update frequency
268 * of 4 Hz to preserve log data.
269 *
270 * All status signals that have not been explicitly given an update frequency using
271 * BaseStatusSignal#SetUpdateFrequency will be slowed down. Note that if other status
272 * signals in the same status frame have been given an update frequency, the update
273 * frequency will be honored for the entire frame.
274 *
275 * This function only needs to be called once in the robot program for the provided devices.
276 * Additionally, this method does not necessarily need to be called after setting the update
277 * frequencies of other signals.
278 *
279 * To restore the default status update frequencies, call ResetSignalFrequenciesForAll.
280 * Alternatively, remove this method call, redeploy the robot application, and power-cycle
281 * the devices on the bus. The user can also override individual status update frequencies
282 * using BaseStatusSignal#SetUpdateFrequency.
283 *
284 * This will wait up to 0.100 seconds (100ms) for each status frame.
285 *
286 * \param devices Devices for which to optimize bus utilization, passed as a comma-separated list of device references.
287 * \returns Status code of the first failed optimize call, or OK if all succeeded
288 */
289 template <std::derived_from<traits::CommonDevice>... Devices>
291 {
292 return OptimizeBusUtilizationForAll(4_Hz, devices...);
293 }
294
295 /**
296 * \brief Optimizes the bus utilization of the provided devices by reducing the update
297 * frequencies of their status signals. This API defaults to an optimized update frequency
298 * of 4 Hz to preserve log data.
299 *
300 * All status signals that have not been explicitly given an update frequency using
301 * BaseStatusSignal#SetUpdateFrequency will be slowed down. Note that if other status
302 * signals in the same status frame have been given an update frequency, the update
303 * frequency will be honored for the entire frame.
304 *
305 * This function only needs to be called once in the robot program for the provided devices.
306 * Additionally, this method does not necessarily need to be called after setting the update
307 * frequencies of other signals.
308 *
309 * To restore the default status update frequencies, call ResetSignalFrequenciesForAll.
310 * Alternatively, remove this method call, redeploy the robot application, and power-cycle
311 * the devices on the bus. The user can also override individual status update frequencies
312 * using BaseStatusSignal#SetUpdateFrequency.
313 *
314 * This will wait up to 0.100 seconds (100ms) for each status frame.
315 *
316 * \param devices Devices for which to optimize bus utilization, passed as a span of device pointers.
317 * \returns Status code of the first failed optimize call, or OK if all succeeded
318 */
319 static ctre::phoenix::StatusCode OptimizeBusUtilizationForAll(std::span<traits::CommonDevice* const> devices)
320 {
321 return OptimizeBusUtilizationForAll(4_Hz, devices);
322 }
323
324 /**
325 * \brief Optimizes the bus utilization of the provided devices by reducing the update
326 * frequencies of their status signals.
327 *
328 * All status signals that have not been explicitly given an update frequency using
329 * BaseStatusSignal#SetUpdateFrequency will be slowed down. Note that if other status
330 * signals in the same status frame have been given an update frequency, the update
331 * frequency will be honored for the entire frame.
332 *
333 * This function only needs to be called once in the robot program for the provided devices.
334 * Additionally, this method does not necessarily need to be called after setting the update
335 * frequencies of other signals.
336 *
337 * To restore the default status update frequencies, call ResetSignalFrequenciesForAll.
338 * Alternatively, remove this method call, redeploy the robot application, and power-cycle
339 * the devices on the bus. The user can also override individual status update frequencies
340 * using BaseStatusSignal#SetUpdateFrequency.
341 *
342 * This will wait up to 0.100 seconds (100ms) for each status frame.
343 *
344 * \param optimizedFreqHz The update frequency to apply to the optimized status signals. A frequency
345 * of 0 Hz will turn off the signals. Otherwise, the minimum supported signal
346 * frequency is 4 Hz (default).
347 * \param devices Devices for which to optimize bus utilization, passed as a comma-separated list of device references.
348 * \returns Status code of the first failed optimize call, or OK if all succeeded
349 */
350 template <std::derived_from<traits::CommonDevice>... Devices>
351 static ctre::phoenix::StatusCode OptimizeBusUtilizationForAll(units::frequency::hertz_t optimizedFreqHz, Devices &... devices)
352 {
353 return OptimizeBusUtilizationForAll(optimizedFreqHz, std::array<traits::CommonDevice *, sizeof...(Devices)>{(&devices)...});
354 }
355
356 /**
357 * \brief Optimizes the bus utilization of the provided devices by reducing the update
358 * frequencies of their status signals.
359 *
360 * All status signals that have not been explicitly given an update frequency using
361 * BaseStatusSignal#SetUpdateFrequency will be slowed down. Note that if other status
362 * signals in the same status frame have been given an update frequency, the update
363 * frequency will be honored for the entire frame.
364 *
365 * This function only needs to be called once in the robot program for the provided devices.
366 * Additionally, this method does not necessarily need to be called after setting the update
367 * frequencies of other signals.
368 *
369 * To restore the default status update frequencies, call ResetSignalFrequenciesForAll.
370 * Alternatively, remove this method call, redeploy the robot application, and power-cycle
371 * the devices on the bus. The user can also override individual status update frequencies
372 * using BaseStatusSignal#SetUpdateFrequency.
373 *
374 * This will wait up to 0.100 seconds (100ms) for each status frame.
375 *
376 * \param optimizedFreqHz The update frequency to apply to the optimized status signals. A frequency
377 * of 0 Hz will turn off the signals. Otherwise, the minimum supported signal
378 * frequency is 4 Hz (default).
379 * \param devices Devices for which to optimize bus utilization, passed as a span of device pointers.
380 * \returns Status code of the first failed optimize call, or OK if all succeeded
381 */
382 static ctre::phoenix::StatusCode OptimizeBusUtilizationForAll(units::frequency::hertz_t optimizedFreqHz, std::span<traits::CommonDevice* const> devices)
383 {
385 for (auto device : devices) {
386 auto const err = device->OptimizeBusUtilization(optimizedFreqHz);
387 if (retval.IsOK()) {
388 retval = err;
389 }
390 }
391 return retval;
392 }
393
394 /**
395 * \brief Resets the update frequencies of all the device's status signals to the defaults.
396 *
397 * This restores the default update frequency of all status signals, including status signals
398 * explicitly given an update frequency using BaseStatusSignal#SetUpdateFrequency and status
399 * signals optimized out using OptimizeBusUtilization.
400 *
401 * \param timeoutSeconds Maximum amount of time to wait for each status frame when performing the action
402 * \returns Status code of the first failed update frequency set call, or OK if all succeeded
403 */
404 ctre::phoenix::StatusCode ResetSignalFrequencies(units::time::second_t timeoutSeconds = 100_ms) final;
405
406 /**
407 * \brief Resets the update frequencies of all the devices' status signals to the defaults.
408 *
409 * This restores the default update frequency of all status signals, including status signals
410 * explicitly given an update frequency using BaseStatusSignal#SetUpdateFrequency and status
411 * signals optimized out using OptimizeBusUtilizationForAll.
412 *
413 * This will wait up to 0.100 seconds (100ms) for each status frame.
414 *
415 * \param devices Devices for which to restore default update frequencies, passed as a comma-separated list of device references.
416 * \returns Status code of the first failed restore call, or OK if all succeeded
417 */
418 template <std::derived_from<traits::CommonDevice>... Devices>
420 {
421 return ResetSignalFrequenciesForAll(std::array<traits::CommonDevice *, sizeof...(Devices)>{(&devices)...});
422 }
423
424 /**
425 * \brief Resets the update frequencies of all the devices' status signals to the defaults.
426 *
427 * This restores the default update frequency of all status signals, including status signals
428 * explicitly given an update frequency using BaseStatusSignal#SetUpdateFrequency and status
429 * signals optimized out using OptimizeBusUtilizationForAll.
430 *
431 * This will wait up to 0.100 seconds (100ms) for each status frame.
432 *
433 * \param devices Devices for which to restore default update frequencies, passed as a span of device pointers.
434 * \returns Status code of the first failed restore call, or OK if all succeeded
435 */
436 static ctre::phoenix::StatusCode ResetSignalFrequenciesForAll(std::span<traits::CommonDevice* const> devices)
437 {
439 for (auto device : devices) {
440 auto const err = device->ResetSignalFrequencies();
441 if (retval.IsOK()) {
442 retval = err;
443 }
444 }
445 return retval;
446 }
447
448 protected:
450
451 template <typename T>
452 StatusSignal<T> &LookupStatusSignal(uint16_t spn, std::string signalName, bool reportOnConstruction, bool refresh)
453 {
454 return LookupCommon<T>(spn, std::move(signalName), nullptr, reportOnConstruction, refresh);
455 }
456
457 template <typename T>
458 StatusSignal<T> &LookupStatusSignal(uint16_t spn, std::string signalName, std::function<std::map<uint16_t, std::string>()> mapFiller, bool reportOnConstruction, bool refresh)
459 {
460 return LookupCommon<T>(spn, std::move(signalName), std::move(mapFiller), reportOnConstruction, refresh);
461 }
462 };
463
464}
465}
466}
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:474
Common interface implemented by all control requests.
Definition ControlRequest.hpp:27
Generic Empty Control class used to do nothing.
Definition ControlRequest.hpp:65
Definition DeviceIdentifier.hpp:16
int deviceID
Definition DeviceIdentifier.hpp:20
uint32_t deviceHash
Definition DeviceIdentifier.hpp:21
std::string network
Definition DeviceIdentifier.hpp:18
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: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:458
static ctre::phoenix::StatusCode ResetSignalFrequenciesForAll(Devices &... devices)
Resets the update frequencies of all the devices' status signals to the defaults.
Definition ParentDevice.hpp:419
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:157
StatusSignal< T > & LookupStatusSignal(uint16_t spn, std::string signalName, bool reportOnConstruction, bool refresh)
Definition ParentDevice.hpp:452
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:223
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:436
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:290
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:319
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:382
int GetDeviceID() const final
Definition ParentDevice.hpp:135
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:207
std::shared_ptr< controls::ControlRequest const > GetAppliedControl() const final
Get the latest applied control.
Definition ParentDevice.hpp:174
StatusSignal< double > & GetGenericSignal(uint32_t signal, bool refresh=true)
This is a reserved routine for internal testing.
Definition ParentDevice.hpp:236
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:351
std::shared_ptr< controls::ControlRequest > GetAppliedControl() final
Get the latest applied control.
Definition ParentDevice.hpp:191
ParentDevice & operator=(ParentDevice const &)=delete
bool HasResetOccurred() final
Definition ParentDevice.hpp:199
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:369
static constexpr int CouldNotRetrieveV6Firmware
Device firmware could not be retrieved.
Definition StatusCodes.h:723
constexpr bool IsOK() const
Definition StatusCodes.h:858
CTREXPORT double GetCurrentTimeSeconds()
Get the current timestamp in seconds.
Definition motor_constants.h:14