CTRE Phoenix 6 C++ 26.3.0
Loading...
Searching...
No Matches
StatusSignal.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 <array>
14#include <functional>
15#include <map>
16#include <ostream>
17#include <span>
18#include <sstream>
19#include <string>
20#include <units/frequency.h>
21#include <units/math.h>
22#include <units/time.h>
23
24namespace ctre {
25namespace phoenix6 {
26
27 namespace hardware {
28 class ParentDevice;
29 }
30
31 template <typename T>
32 class StatusSignal;
33
34 /**
35 * \brief Class that provides operations to
36 * retrieve information about a status signal.
37 */
39 private:
40 hardware::DeviceIdentifier deviceIdentifier;
41 uint16_t spn;
42 std::string name;
43 std::function<void()> _checkFirmVersFunction;
44
45 std::map<uint16_t, std::string> _unitStrings{};
46 uint16_t _unitsKey;
47
48 units::time::second_t _lastTimestamp{0_s};
49
50 protected:
51 std::string units;
52 double baseValue = 0;
55
57 hardware::DeviceIdentifier deviceIdentifier,
58 uint16_t spn,
59 std::string signalName,
60 std::function<void()> checkFirmVersFunction
61 ) :
62 deviceIdentifier{std::move(deviceIdentifier)},
63 spn{spn},
64 name{std::move(signalName)},
65 _checkFirmVersFunction{std::move(checkFirmVersFunction)},
66 _unitsKey{spn},
68 {
69 }
70
72 hardware::DeviceIdentifier deviceIdentifier,
73 uint16_t spn,
74 std::string signalName,
75 std::function<void()> checkFirmVersFunction,
76 std::function<std::map<uint16_t, std::string>()> const &unitsGenerator
77 ) :
78 deviceIdentifier{std::move(deviceIdentifier)},
79 spn{spn},
80 name{std::move(signalName)},
81 _checkFirmVersFunction{std::move(checkFirmVersFunction)},
82 _unitStrings{unitsGenerator()},
83 _unitsKey{spn},
85 {
86 for (auto &unitString : _unitStrings) {
87 unitString.second = Status_GetUnits(unitString.first);
88 }
89 }
90
91 /* Constructor for an invalid BaseStatusSignal */
93 deviceIdentifier{hardware::DeviceIdentifier{}},
94 spn{0},
95 name{"Invalid"},
96 _checkFirmVersFunction{[] {}},
97 _unitsKey{spn},
98 error{error}
99 {
100 }
101
102 static std::string Status_GetUnits(uint32_t signal);
103
105 BaseStatusSignal &signal,
106 char const *network,
107 bool bWaitForUpdate,
108 double timeoutSeconds);
110 std::span<BaseStatusSignal* const> signals,
111 char const *network,
112 double timeoutSeconds);
113
115 BaseStatusSignal &signal,
116 double frequencyHz,
117 double timeoutSeconds);
119 std::span<BaseStatusSignal* const> signals,
120 double frequencyHz,
121 double timeoutSeconds);
122 static double Status_GetAppliedUpdateFrequency(char const *canbus, uint32_t deviceHash, uint16_t spn);
123
125 char const *location,
126 units::time::second_t timeoutSeconds,
127 bool reportError,
128 std::span<BaseStatusSignal* const> signals);
129
130 void RefreshValue(bool waitForUpdate, units::time::second_t timeout, bool reportError);
131 void UpdateUnits(uint16_t unitsKey);
132
133 public:
134 virtual ~BaseStatusSignal() = 0; // Declare virtual destructor to make this class abstract
135
136 /**
137 * \brief Gets the name of this signal.
138 *
139 * \returns Name of this signal
140 */
141 std::string const &GetName() const { return name; }
142 /**
143 * \brief Gets the units for this signal.
144 *
145 * \returns String representation of units for this signal
146 */
147 std::string const &GetUnits() const { return units; }
148 /**
149 * \brief Gets the value of this signal as a double.
150 *
151 * \return Value of this signal as a double instead of the generic type
152 */
153 double GetValueAsDouble() const { return baseValue; }
154 /**
155 * \brief Gets the timestamps of this signals.
156 *
157 * \returns All timestamps for this signal
158 */
159 AllTimestamps const &GetAllTimestamps() const { return timestamps; }
160 /**
161 * \brief Gets the most accurate timestamp available for this signal.
162 *
163 * \details The timestamp sources from most to least accurate are:
164 *
165 * - Timestamp#TimestampSource#Device
166 * - Timestamp#TimestampSource#CANivore
167 * - Timestamp#TimestampSource#System
168 *
169 * Note that some of these sources may not be available.
170 *
171 * \returns The most accurate timestamp available for this signal
172 */
173 Timestamp const &GetTimestamp() const { return timestamps.GetBestTimestamp(); }
174 /**
175 * \brief Gets the status code of the last time this signal was refreshed.
176 *
177 * \returns Status code of the last time this signal was refreshed
178 */
179 ctre::phoenix::StatusCode GetStatus() const { return error; }
180
181 /**
182 * \brief Checks whether the signal has been updated since the last check.
183 *
184 * Note that the signal must be refreshed before calling this routine.
185 *
186 * \returns true if the signal has updated since the previous call of this routine
187 */
189 {
190 bool retval = false;
191 /* did we receive an update */
192 auto const &timestamp = GetAllTimestamps().GetSystemTimestamp();
193 if (timestamp.IsValid()) {
194 /* if the update timestamp is new, then a new frame was sent */
195 if (_lastTimestamp != timestamp.GetTime()) {
196 _lastTimestamp = timestamp.GetTime();
197 retval = true;
198 }
199 }
200 return retval;
201 }
202
203 /**
204 * \brief Sets the rate at which the device will publish this signal.
205 *
206 * A frequency of 0 Hz will turn off the signal. Otherwise, the minimum supported signal
207 * frequency is 4 Hz, and the maximum is 1000 Hz. Additionally, some update frequencies are
208 * not supported and will be promoted up to the next highest supported frequency.
209 *
210 * If other StatusSignals in the same status frame have been set to an update frequency,
211 * the fastest requested update frequency will be applied to the frame.
212 *
213 * \param frequencyHz Rate to publish the signal in Hz.
214 * \param timeoutSeconds Maximum amount of time to wait when performing the action
215 * \returns Status code of setting the update frequency
216 */
217 ctre::phoenix::StatusCode SetUpdateFrequency(units::frequency::hertz_t frequencyHz, units::time::second_t timeoutSeconds = 100_ms)
218 {
219 return Status_SetUpdateFrequency(
220 *this,
221 frequencyHz.value(),
222 timeoutSeconds.value()
223 );
224 }
225
226 /**
227 * \brief Gets the rate at which the device will publish this signal.
228 *
229 * This is typically the last value passed into #SetUpdateFrequency. The returned value
230 * may be higher if another StatusSignal in the same status frame has been set to a higher
231 * update frequency.
232 *
233 * \returns Applied update frequency of the signal in Hz
234 */
235 units::frequency::hertz_t GetAppliedUpdateFrequency() const
236 {
237 return units::frequency::hertz_t{
238 Status_GetAppliedUpdateFrequency(
239 this->deviceIdentifier.network.c_str(),
240 this->deviceIdentifier.deviceHash,
241 this->spn
242 )
243 };
244 }
245
246 /**
247 * \brief Performs latency compensation on signal using the signalSlope and signal's latency to determine
248 * the magnitude of compensation. The caller must refresh these StatusSignals beforehand;
249 * this function only does the math required for latency compensation.
250 *
251 * \details Example usage:
252 * \code
253 * units::turn_t compensatedTurns = BaseStatusSignal::GetLatencyCompensatedValue(fx.GetPosition(), fx.GetVelocity());
254 * \endcode
255 *
256 * \tparam U Type of signal's underlying type. This is the type that the function will return.
257 * \tparam U_PER_SEC Type of signalSlope's underlying type. This must be the derivative of U.
258 * \param signal Signal to be latency compensated. Caller must make sure this signal is up to date
259 * either by calling \c Refresh() or \c WaitForUpdate().
260 * \param signalSlope Derivative of signal that informs compensation magnitude. Caller must make sure this
261 * signal is up to date either by calling \c Refresh() or \c WaitForUpdate().
262 * \param maxLatencySeconds The maximum amount of latency to compensate for in seconds. A negative or zero
263 * value disables the max latency cap. This is used to cap the contribution of
264 * latency compensation for stale signals, such as after the device has been
265 * disconnected from the CAN bus.
266 * \returns Latency compensated value from the signal StatusSignal.
267 */
268 template <typename U, typename U_PER_SEC>
269 requires units::traits::is_unit_t_v<U> && units::traits::is_unit_t_v<U_PER_SEC> &&
270 units::traits::is_convertible_unit_v<
271 typename units::traits::unit_t_traits<U>::unit_type,
272 units::compound_unit<typename units::traits::unit_t_traits<U_PER_SEC>::unit_type, units::seconds>
273 >
274 static U GetLatencyCompensatedValue(StatusSignal<U> const &signal, StatusSignal<U_PER_SEC> const &signalSlope, units::time::second_t maxLatencySeconds = 0.300_s)
275 {
276 U const nonCompensatedSignal = signal.GetValue();
277 U_PER_SEC const changeInSignal = signalSlope.GetValue();
278 units::second_t latency = signal.GetTimestamp().GetLatency();
279 if (maxLatencySeconds > 0_s && latency > maxLatencySeconds) {
280 latency = maxLatencySeconds;
281 }
282 return nonCompensatedSignal + (changeInSignal * latency);
283 }
284
285 /**
286 * \brief Waits for new data on all provided signals up to timeout.
287 * This API is typically used with CANivore Bus signals as they will be synced using the
288 * CANivore Timesync feature and arrive simultaneously. Signals on a roboRIO bus cannot
289 * be synced and may require a significantly longer blocking call to receive all signals.
290 *
291 * Note that CANivore Timesync requires Phoenix Pro.
292 *
293 * This can also be used with a timeout of zero to refresh many signals at once, which
294 * is faster than calling Refresh() on every signal. This is equivalent to calling #RefreshAll.
295 *
296 * If a signal arrives multiple times while waiting, such as when *not* using CANivore
297 * Timesync, the newest signal data is fetched. Additionally, if this function times out,
298 * the newest signal data is fetched for all signals (when possible). We recommend checking
299 * the individual status codes using GetStatus() when this happens.
300 *
301 * \param timeoutSeconds Maximum time to wait for all the signals to arrive.
302 * Pass zero to refresh all signals without blocking.
303 * \param signals Signals to wait on, passed as a comma-separated list of signal references.
304 * \return InvalidNetwork if signals are on different CAN bus networks,
305 * RxTimeout if it took longer than timeoutSeconds to receive all the signals,
306 * MultiSignalNotSupported if using the roboRIO bus with more than one signal and a non-zero timeout.
307 * An OK status code means that all signals arrived within timeoutSeconds and they are all OK.
308 *
309 * Any other value represents the StatusCode of the first failed signal.
310 * Call GetStatus() on each signal to determine which ones failed.
311 */
312 template <std::derived_from<BaseStatusSignal>... Signals>
313 static ctre::phoenix::StatusCode WaitForAll(units::time::second_t timeoutSeconds, Signals &... signals)
314 {
315 return WaitForAll(timeoutSeconds, true, signals...);
316 }
317 /**
318 * \brief Waits for new data on all provided signals up to timeout.
319 * This API is typically used with CANivore Bus signals as they will be synced using the
320 * CANivore Timesync feature and arrive simultaneously. Signals on a roboRIO bus cannot
321 * be synced and may require a significantly longer blocking call to receive all signals.
322 *
323 * Note that CANivore Timesync requires Phoenix Pro.
324 *
325 * This can also be used with a timeout of zero to refresh many signals at once, which
326 * is faster than calling Refresh() on every signal. This is equivalent to calling #RefreshAll.
327 *
328 * If a signal arrives multiple times while waiting, such as when *not* using CANivore
329 * Timesync, the newest signal data is fetched. Additionally, if this function times out,
330 * the newest signal data is fetched for all signals (when possible). We recommend checking
331 * the individual status codes using GetStatus() when this happens.
332 *
333 * \param timeoutSeconds Maximum time to wait for all the signals to arrive.
334 * Pass zero to refresh all signals without blocking.
335 * \param signals Signals to wait on, passed as a span of signal pointers.
336 * \return InvalidNetwork if signals are on different CAN bus networks,
337 * RxTimeout if it took longer than timeoutSeconds to receive all the signals,
338 * MultiSignalNotSupported if using the roboRIO bus with more than one signal and a non-zero timeout.
339 * An OK status code means that all signals arrived within timeoutSeconds and they are all OK.
340 *
341 * Any other value represents the StatusCode of the first failed signal.
342 * Call GetStatus() on each signal to determine which ones failed.
343 */
344 static ctre::phoenix::StatusCode WaitForAll(units::time::second_t timeoutSeconds, std::span<BaseStatusSignal* const> signals)
345 {
346 return WaitForAll(timeoutSeconds, true, signals);
347 }
348
349 /**
350 * \brief Waits for new data on all provided signals up to timeout.
351 * This API is typically used with CANivore Bus signals as they will be synced using the
352 * CANivore Timesync feature and arrive simultaneously. Signals on a roboRIO bus cannot
353 * be synced and may require a significantly longer blocking call to receive all signals.
354 *
355 * Note that CANivore Timesync requires Phoenix Pro.
356 *
357 * This can also be used with a timeout of zero to refresh many signals at once, which
358 * is faster than calling Refresh() on every signal. This is equivalent to calling #RefreshAll.
359 *
360 * If a signal arrives multiple times while waiting, such as when *not* using CANivore
361 * Timesync, the newest signal data is fetched. Additionally, if this function times out,
362 * the newest signal data is fetched for all signals (when possible). We recommend checking
363 * the individual status codes using GetStatus() when this happens.
364 *
365 * \param timeoutSeconds Maximum time to wait for all the signals to arrive.
366 * Pass zero to refresh all signals without blocking.
367 * \param reportError Whether to report any errors to the Driver Station/stderr, defaults to true
368 * \param signals Signals to wait on, passed as a comma-separated list of signal references.
369 * \return InvalidNetwork if signals are on different CAN bus networks,
370 * RxTimeout if it took longer than timeoutSeconds to receive all the signals,
371 * MultiSignalNotSupported if using the roboRIO bus with more than one signal and a non-zero timeout.
372 * An OK status code means that all signals arrived within timeoutSeconds and they are all OK.
373 *
374 * Any other value represents the StatusCode of the first failed signal.
375 * Call GetStatus() on each signal to determine which ones failed.
376 */
377 template <std::derived_from<BaseStatusSignal>... Signals>
378 static ctre::phoenix::StatusCode WaitForAll(units::time::second_t timeoutSeconds, bool reportError, Signals &... signals)
379 {
380 return WaitForAll(
381 timeoutSeconds,
382 reportError,
383 std::array<BaseStatusSignal *, sizeof...(Signals)>{(&signals)...}
384 );
385 }
386 /**
387 * \brief Waits for new data on all provided signals up to timeout.
388 * This API is typically used with CANivore Bus signals as they will be synced using the
389 * CANivore Timesync feature and arrive simultaneously. Signals on a roboRIO bus cannot
390 * be synced and may require a significantly longer blocking call to receive all signals.
391 *
392 * Note that CANivore Timesync requires Phoenix Pro.
393 *
394 * This can also be used with a timeout of zero to refresh many signals at once, which
395 * is faster than calling Refresh() on every signal. This is equivalent to calling #RefreshAll.
396 *
397 * If a signal arrives multiple times while waiting, such as when *not* using CANivore
398 * Timesync, the newest signal data is fetched. Additionally, if this function times out,
399 * the newest signal data is fetched for all signals (when possible). We recommend checking
400 * the individual status codes using GetStatus() when this happens.
401 *
402 * \param timeoutSeconds Maximum time to wait for all the signals to arrive.
403 * Pass zero to refresh all signals without blocking.
404 * \param reportError Whether to report any errors to the Driver Station/stderr, defaults to true
405 * \param signals Signals to wait on, passed as a span of signal pointers.
406 * \return InvalidNetwork if signals are on different CAN bus networks,
407 * RxTimeout if it took longer than timeoutSeconds to receive all the signals,
408 * MultiSignalNotSupported if using the roboRIO bus with more than one signal and a non-zero timeout.
409 * An OK status code means that all signals arrived within timeoutSeconds and they are all OK.
410 *
411 * Any other value represents the StatusCode of the first failed signal.
412 * Call GetStatus() on each signal to determine which ones failed.
413 */
414 static ctre::phoenix::StatusCode WaitForAll(units::time::second_t timeoutSeconds, bool reportError, std::span<BaseStatusSignal* const> signals)
415 {
416 static constexpr char kLocation[] = "ctre::phoenix6::BaseStatusSignal::WaitForAll";
417 return WaitForAllImpl(kLocation, timeoutSeconds, reportError, signals);
418 }
419
420 /**
421 * \brief Performs a non-blocking refresh on all provided signals.
422 *
423 * This provides a performance improvement over separately calling Refresh() on each signal.
424 *
425 * \param signals Signals to refresh, passed as a comma-separated list of signal references.
426 * \return InvalidNetwork if signals are on different CAN bus networks.
427 * An OK status code means that all signals are OK.
428 *
429 * Any other value represents the StatusCode of the first failed signal.
430 * Call GetStatus() on each signal to determine which ones failed.
431 */
432 template <std::derived_from<BaseStatusSignal>... Signals>
433 static ctre::phoenix::StatusCode RefreshAll(Signals &... signals)
434 {
435 return RefreshAll(true, signals...);
436 }
437 /**
438 * \brief Performs a non-blocking refresh on all provided signals.
439 *
440 * This provides a performance improvement over separately calling Refresh() on each signal.
441 *
442 * \param signals Signals to refresh, passed as a span of signal pointers.
443 * \return InvalidNetwork if signals are on different CAN bus networks.
444 * An OK status code means that all signals are OK.
445 *
446 * Any other value represents the StatusCode of the first failed signal.
447 * Call GetStatus() on each signal to determine which ones failed.
448 */
449 static ctre::phoenix::StatusCode RefreshAll(std::span<BaseStatusSignal* const> signals)
450 {
451 return RefreshAll(true, signals);
452 }
453
454 /**
455 * \brief Performs a non-blocking refresh on all provided signals.
456 *
457 * This provides a performance improvement over separately calling Refresh() on each signal.
458 *
459 * \param reportError Whether to report any errors to the Driver Station/stderr, defaults to true
460 * \param signals Signals to refresh, passed as a comma-separated list of signal references.
461 * \return InvalidNetwork if signals are on different CAN bus networks.
462 * An OK status code means that all signals are OK.
463 *
464 * Any other value represents the StatusCode of the first failed signal.
465 * Call GetStatus() on each signal to determine which ones failed.
466 */
467 template <std::derived_from<BaseStatusSignal>... Signals>
468 static ctre::phoenix::StatusCode RefreshAll(bool reportError, Signals &... signals)
469 {
470 return RefreshAll(reportError, std::array<BaseStatusSignal *, sizeof...(Signals)>{(&signals)...});
471 }
472 /**
473 * \brief Performs a non-blocking refresh on all provided signals.
474 *
475 * This provides a performance improvement over separately calling Refresh() on each signal.
476 *
477 * \param reportError Whether to report any errors to the Driver Station/stderr, defaults to true
478 * \param signals Signals to refresh, passed as a span of signal pointers.
479 * \return InvalidNetwork if signals are on different CAN bus networks.
480 * An OK status code means that all signals are OK.
481 *
482 * Any other value represents the StatusCode of the first failed signal.
483 * Call GetStatus() on each signal to determine which ones failed.
484 */
485 static ctre::phoenix::StatusCode RefreshAll(bool reportError, std::span<BaseStatusSignal* const> signals)
486 {
487 static constexpr char kLocation[] = "ctre::phoenix6::BaseStatusSignal::RefreshAll";
488 return WaitForAllImpl(kLocation, 0_s, reportError, signals);
489 }
490
491 /**
492 * \brief Checks if all signals have an OK error code.
493 *
494 * \param signals Signals to check error code of, passed as a comma-separated list of signal references.
495 * \returns True if all signals are OK, false otherwise
496 */
497 template <std::derived_from<BaseStatusSignal>... Signals>
498 static bool IsAllGood(Signals const &... signals)
499 {
500 return IsAllGood(std::array<BaseStatusSignal const *, sizeof...(Signals)>{(&signals)...});
501 }
502 /**
503 * \brief Checks if all signals have an OK error code.
504 *
505 * \param signals Signals to check error code of, passed as a span of signal pointers.
506 * \returns True if all signals are OK, false otherwise
507 */
508 static bool IsAllGood(std::span<BaseStatusSignal const *const> signals)
509 {
510 for (auto signal : signals) {
511 if (!signal->GetStatus().IsOK()) {
512 return false;
513 }
514 }
515 return true;
516 }
517
518 /**
519 * \brief Sets the update frequency of all specified status signals to the provided common frequency.
520 *
521 * A frequency of 0 Hz will turn off the signal. Otherwise, the minimum supported signal frequency
522 * is 4 Hz, and the maximum is 1000 Hz. Additionally, some update frequencies are not supported and
523 * will be promoted up to the next highest supported frequency.
524 *
525 * If other StatusSignals in the same status frame have been set to an update frequency,
526 * the fastest requested update frequency will be applied to the frame.
527 *
528 * This will wait up to 0.100 seconds (100ms) for each signal.
529 *
530 * \param frequencyHz Rate to publish the signal in Hz.
531 * \param signals Signals to apply the update frequency to, passed as a comma-separated list of signal references.
532 * \returns Status code of the first failed update frequency set call, or OK if all succeeded
533 */
534 template <std::derived_from<BaseStatusSignal>... Signals>
535 static ctre::phoenix::StatusCode SetUpdateFrequencyForAll(units::frequency::hertz_t frequencyHz, Signals &... signals)
536 {
537 return SetUpdateFrequencyForAll(frequencyHz, std::array<BaseStatusSignal *, sizeof...(Signals)>{(&signals)...});
538 }
539 /**
540 * \brief Sets the update frequency of all specified status signals to the provided common frequency.
541 *
542 * A frequency of 0 Hz will turn off the signal. Otherwise, the minimum supported signal frequency
543 * is 4 Hz, and the maximum is 1000 Hz. Additionally, some update frequencies are not supported and
544 * will be promoted up to the next highest supported frequency.
545 *
546 * If other StatusSignals in the same status frame have been set to an update frequency,
547 * the fastest requested update frequency will be applied to the frame.
548 *
549 * This will wait up to 0.100 seconds (100ms) for each signal.
550 *
551 * \param frequencyHz Rate to publish the signal in Hz.
552 * \param signals Signals to apply the update frequency to, passed as a span of signal pointers.
553 * \returns Status code of the first failed update frequency set call, or OK if all succeeded
554 */
555 static ctre::phoenix::StatusCode SetUpdateFrequencyForAll(units::frequency::hertz_t frequencyHz, std::span<BaseStatusSignal* const> signals)
556 {
557 return Status_SetUpdateFrequencyForAll(signals, frequencyHz.value(), 0.100);
558 }
559 };
560
561 /**
562 * \brief Represents a status signal with data of type T,
563 * and operations available to retrieve information about
564 * the signal.
565 */
566 template <typename T>
569
571 hardware::DeviceIdentifier deviceIdentifier,
572 uint16_t spn,
573 std::string signalName,
574 std::function<void()> checkFirmVersFunction
575 ) :
577 std::move(deviceIdentifier),
578 spn, std::move(signalName),
579 std::move(checkFirmVersFunction)
580 }
581 {
582 }
583
585 hardware::DeviceIdentifier deviceIdentifier,
586 uint16_t spn,
587 std::string signalName,
588 std::function<void()> checkFirmVersFunction,
589 std::function<std::map<uint16_t, std::string>()> const &unitsGenerator
590 ) :
592 std::move(deviceIdentifier),
593 spn, std::move(signalName),
594 std::move(checkFirmVersFunction),
595 unitsGenerator
596 }
597 {
598 }
599
600 /* Constructor for an invalid StatusSignal */
601 StatusSignal(ctre::phoenix::StatusCode error) :
602 BaseStatusSignal{error}
603 {
604 }
605
606 public:
607 /**
608 * \brief Gets the cached value from this status signal.
609 *
610 * \details Gets the cached value. To make sure the value is up-to-date
611 * call \c Refresh() or \c WaitForUpdate()
612 *
613 * \returns Cached value
614 */
615 T GetValue() const
616 {
617 if constexpr(units::traits::is_unit_t_v<T>) {
618 return units::make_unit<T>(this->baseValue);
619 } else {
620 return static_cast<T>(this->baseValue);
621 }
622 }
623
624 /**
625 * \brief Refreshes the value of this status signal.
626 *
627 * If the user application caches this StatusSignal object
628 * instead of periodically fetching it from the hardware device,
629 * this function must be called to fetch fresh data.
630 *
631 * \details This performs a non-blocking refresh operation. If
632 * you want to wait until you receive the signal, call
633 * \c WaitForUpdate() instead.
634 *
635 * \param reportError Whether to report any errors to the Driver Station/stderr
636 * \returns Reference to itself
637 */
638 StatusSignal<T> &Refresh(bool reportError = true)
639 {
640 RefreshValue(false, 0_s, reportError); // Don't block and error if signal is older than a default timeout
641 return *this;
642 }
643 /**
644 * \brief Waits up to timeoutSec to get the up-to-date status signal value.
645 *
646 * \details This performs a blocking refresh operation. If
647 * you want to non-blocking refresh the signal, call
648 * \c Refresh() instead.
649 *
650 * \param timeoutSec Maximum time to wait for the signal to update
651 * \param reportError Whether to report any errors to the Driver Station/stderr
652 * \returns Reference to itself
653 */
654 StatusSignal<T> &WaitForUpdate(units::time::second_t timeoutSec, bool reportError = true)
655 {
656 RefreshValue(true, timeoutSec, reportError);
657 return *this;
658 }
659
660 /**
661 * \brief Checks whether the signal is near a target value within the
662 * given tolerance.
663 *
664 * \param target The target value of the signal
665 * \param tolerance The error tolerance between the target and measured values
666 * \returns Whether the signal is near the target value
667 */
668 bool IsNear(T target, T tolerance) const
669 requires (std::same_as<T, double>)
670 {
671 return fabs(GetValue() - target) <= tolerance;
672 }
673
674 /**
675 * \brief Checks whether the signal is near a target value within the
676 * given tolerance.
677 *
678 * \param target The target value of the signal
679 * \param tolerance The error tolerance between the target and measured values
680 * \returns Whether the signal is near the target value
681 */
682 bool IsNear(T target, T tolerance) const
683 requires (units::traits::is_unit_t_v<T>)
684 {
685 return units::math::abs(GetValue() - target) <= tolerance;
686 }
687
688 /**
689 * \brief Get a basic data-only container with a copy of the current signal data.
690 *
691 * If looking for Phoenix 6 logging features, see the SignalLogger class instead.
692 *
693 * \returns Basic structure with all relevant information
694 */
696 {
698 toRet.name = GetName();
699 toRet.value = GetValue();
700 toRet.timestamp = GetTimestamp().GetTime();
701 toRet.units = GetUnits();
702 toRet.status = GetStatus();
703 return toRet;
704 }
705
706 /**
707 * \brief Returns a lambda that calls #Refresh and #GetValue on this object. This is useful for command-based programming.
708 *
709 * \returns std::function<T()> that calls #Refresh and returns this signal's value.
710 */
711 std::function<T()> AsSupplier()
712 {
713 return [this]() { return Refresh().GetValue(); };
714 }
715
716 friend std::ostream &operator<<(std::ostream &os, StatusSignal<T> const &data)
717 {
718 if constexpr(units::traits::is_unit_t_v<T>) {
719 os << data.GetValue().value() << " " << data.GetUnits();
720 } else {
721 os << data.GetValue() << " " << data.GetUnits();
722 }
723 return os;
724 }
725 std::string ToString() const
726 {
727 std::stringstream ss;
728 ss << *this;
729 return ss.str();
730 }
731 };
732
733}
734}
A collection of timestamps for a received signal.
Definition Timestamp.hpp:125
Class that provides operations to retrieve information about a status signal.
Definition StatusSignal.hpp:38
AllTimestamps timestamps
Definition StatusSignal.hpp:53
AllTimestamps const & GetAllTimestamps() const
Gets the timestamps of this signals.
Definition StatusSignal.hpp:159
ctre::phoenix::StatusCode error
Definition StatusSignal.hpp:54
static std::string Status_GetUnits(uint32_t signal)
static double Status_GetAppliedUpdateFrequency(char const *canbus, uint32_t deviceHash, uint16_t spn)
static ctre::phoenix::StatusCode RefreshAll(std::span< BaseStatusSignal *const > signals)
Performs a non-blocking refresh on all provided signals.
Definition StatusSignal.hpp:449
std::string units
Definition StatusSignal.hpp:51
static ctre::phoenix::StatusCode SetUpdateFrequencyForAll(units::frequency::hertz_t frequencyHz, std::span< BaseStatusSignal *const > signals)
Sets the update frequency of all specified status signals to the provided common frequency.
Definition StatusSignal.hpp:555
std::string const & GetName() const
Gets the name of this signal.
Definition StatusSignal.hpp:141
BaseStatusSignal(hardware::DeviceIdentifier deviceIdentifier, uint16_t spn, std::string signalName, std::function< void()> checkFirmVersFunction, std::function< std::map< uint16_t, std::string >()> const &unitsGenerator)
Definition StatusSignal.hpp:71
ctre::phoenix::StatusCode SetUpdateFrequency(units::frequency::hertz_t frequencyHz, units::time::second_t timeoutSeconds=100_ms)
Sets the rate at which the device will publish this signal.
Definition StatusSignal.hpp:217
ctre::phoenix::StatusCode GetStatus() const
Gets the status code of the last time this signal was refreshed.
Definition StatusSignal.hpp:179
static ctre::phoenix::StatusCode WaitForAll(units::time::second_t timeoutSeconds, std::span< BaseStatusSignal *const > signals)
Waits for new data on all provided signals up to timeout.
Definition StatusSignal.hpp:344
static ctre::phoenix::StatusCode WaitForAll(units::time::second_t timeoutSeconds, Signals &... signals)
Waits for new data on all provided signals up to timeout.
Definition StatusSignal.hpp:313
static ctre::phoenix::StatusCode Status_Get(BaseStatusSignal &signal, char const *network, bool bWaitForUpdate, double timeoutSeconds)
static bool IsAllGood(Signals const &... signals)
Checks if all signals have an OK error code.
Definition StatusSignal.hpp:498
bool HasUpdated()
Checks whether the signal has been updated since the last check.
Definition StatusSignal.hpp:188
void RefreshValue(bool waitForUpdate, units::time::second_t timeout, bool reportError)
static ctre::phoenix::StatusCode RefreshAll(bool reportError, std::span< BaseStatusSignal *const > signals)
Performs a non-blocking refresh on all provided signals.
Definition StatusSignal.hpp:485
BaseStatusSignal(ctre::phoenix::StatusCode error)
Definition StatusSignal.hpp:92
units::frequency::hertz_t GetAppliedUpdateFrequency() const
Gets the rate at which the device will publish this signal.
Definition StatusSignal.hpp:235
static ctre::phoenix::StatusCode WaitForAll(units::time::second_t timeoutSeconds, bool reportError, std::span< BaseStatusSignal *const > signals)
Waits for new data on all provided signals up to timeout.
Definition StatusSignal.hpp:414
double baseValue
Definition StatusSignal.hpp:52
std::string const & GetUnits() const
Gets the units for this signal.
Definition StatusSignal.hpp:147
static U GetLatencyCompensatedValue(StatusSignal< U > const &signal, StatusSignal< U_PER_SEC > const &signalSlope, units::time::second_t maxLatencySeconds=0.300_s)
Performs latency compensation on signal using the signalSlope and signal's latency to determine the m...
Definition StatusSignal.hpp:274
static ctre::phoenix::StatusCode Status_WaitForAll(std::span< BaseStatusSignal *const > signals, char const *network, double timeoutSeconds)
static ctre::phoenix::StatusCode RefreshAll(Signals &... signals)
Performs a non-blocking refresh on all provided signals.
Definition StatusSignal.hpp:433
static ctre::phoenix::StatusCode Status_SetUpdateFrequency(BaseStatusSignal &signal, double frequencyHz, double timeoutSeconds)
static ctre::phoenix::StatusCode SetUpdateFrequencyForAll(units::frequency::hertz_t frequencyHz, Signals &... signals)
Sets the update frequency of all specified status signals to the provided common frequency.
Definition StatusSignal.hpp:535
static ctre::phoenix::StatusCode RefreshAll(bool reportError, Signals &... signals)
Performs a non-blocking refresh on all provided signals.
Definition StatusSignal.hpp:468
double GetValueAsDouble() const
Gets the value of this signal as a double.
Definition StatusSignal.hpp:153
static ctre::phoenix::StatusCode WaitForAllImpl(char const *location, units::time::second_t timeoutSeconds, bool reportError, std::span< BaseStatusSignal *const > signals)
static bool IsAllGood(std::span< BaseStatusSignal const *const > signals)
Checks if all signals have an OK error code.
Definition StatusSignal.hpp:508
Timestamp const & GetTimestamp() const
Gets the most accurate timestamp available for this signal.
Definition StatusSignal.hpp:173
BaseStatusSignal(hardware::DeviceIdentifier deviceIdentifier, uint16_t spn, std::string signalName, std::function< void()> checkFirmVersFunction)
Definition StatusSignal.hpp:56
static ctre::phoenix::StatusCode WaitForAll(units::time::second_t timeoutSeconds, bool reportError, Signals &... signals)
Waits for new data on all provided signals up to timeout.
Definition StatusSignal.hpp:378
void UpdateUnits(uint16_t unitsKey)
static ctre::phoenix::StatusCode Status_SetUpdateFrequencyForAll(std::span< BaseStatusSignal *const > signals, double frequencyHz, double timeoutSeconds)
Represents a status signal with data of type T, and operations available to retrieve information abou...
Definition StatusSignal.hpp:567
std::string ToString() const
Definition StatusSignal.hpp:725
StatusSignal< T > & Refresh(bool reportError=true)
Refreshes the value of this status signal.
Definition StatusSignal.hpp:638
T GetValue() const
Gets the cached value from this status signal.
Definition StatusSignal.hpp:615
friend std::ostream & operator<<(std::ostream &os, StatusSignal< T > const &data)
Definition StatusSignal.hpp:716
StatusSignal< T > & WaitForUpdate(units::time::second_t timeoutSec, bool reportError=true)
Waits up to timeoutSec to get the up-to-date status signal value.
Definition StatusSignal.hpp:654
SignalMeasurement< T > GetDataCopy() const
Get a basic data-only container with a copy of the current signal data.
Definition StatusSignal.hpp:695
bool IsNear(T target, T tolerance) const
Checks whether the signal is near a target value within the given tolerance.
Definition StatusSignal.hpp:682
std::function< T()> AsSupplier()
Returns a lambda that calls Refresh and GetValue on this object.
Definition StatusSignal.hpp:711
bool IsNear(T target, T tolerance) const
Checks whether the signal is near a target value within the given tolerance.
Definition StatusSignal.hpp:668
Information about the timestamp of a signal.
Definition Timestamp.hpp:17
units::time::second_t GetLatency() const
Get the latency of this timestamp compared to now.
Definition Timestamp.hpp:107
The unique identifier for a device.
Definition DeviceIdentifier.hpp:19
std::string network
Definition DeviceIdentifier.hpp:21
Parent class for all devices.
Definition ParentDevice.hpp:23
Status codes reported by APIs, including OK, warnings, and errors.
Definition StatusCodes.h:28
static constexpr int SigNotUpdated
No new response to update signal.
Definition StatusCodes.h:420
Definition motor_constants.h:14
Information from a single measurement of a status signal.
Definition SignalMeasurement.hpp:20
T value
The value of the signal.
Definition SignalMeasurement.hpp:28
std::string units
The units of the signal measurement.
Definition SignalMeasurement.hpp:36
ctre::phoenix::StatusCode status
Status code response of getting the data.
Definition SignalMeasurement.hpp:40
units::time::second_t timestamp
Timestamp of when the data point was taken.
Definition SignalMeasurement.hpp:32
std::string_view name
The name of the signal.
Definition SignalMeasurement.hpp:24