CTRE Phoenix 6 C++ 26.70.0-alpha-2
Loading...
Searching...
No Matches
HootReplay.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
12#include <wpi/units/time.hpp>
13#include <string>
14#include <vector>
15
16#if __has_include(<wpi/util/struct/Struct.hpp>)
17#include <wpi/util/struct/Struct.hpp>
18#endif
19#if __has_include(<wpi/util/protobuf/Protobuf.hpp>)
20#include <wpi/util/protobuf/Protobuf.hpp>
21#endif
22
23namespace ctre {
24namespace phoenix6 {
25
26/**
27 * \brief Static class for controlling Phoenix 6 hoot log replay.
28 *
29 * This replays all signals in the given hoot log in simulation. Hoot logs can
30 * be created by a robot program using SignalLogger. Only one hoot log may be
31 * replayed at a time.
32 *
33 * The signal logger always runs while replay is running. All custom signals written
34 * during replay will be automatically placed under `hoot_replay/`. Additionally, the
35 * log will contain all status signals and custom signals from the original log.
36 *
37 * During replay, all transmits from the robot program are ignored. This includes
38 * features such as control requests, configs, and setting signal update frequency.
39 * Additionally, Tuner X is not functional during log replay.
40 *
41 * To use Hoot Replay, construct a HootReplay(char const *) before any devices are constructed
42 * to load a hoot file and start replay. It is recommended that this is constructed immediately
43 * before a CANBus to fulfill this requirement. Non-critical failures from opening and reading
44 * the file can be fetched using GetStatus().
45 *
46 * After devices are constructed, Hoot Replay can be controlled using Play(), Pause(), Stop(),
47 * and Restart(). Additionally, Hoot Replay supports StepTiming(wpi::units::second_t) while paused.
48 * The current file can be closed by calling Close() or destroying the HootReplay instance, after
49 * which a new file may be loaded.
50 */
53
54public:
55 /**
56 * \brief Loads the given file and starts signal log replay. Only one
57 * hoot log may be replayed at a time.
58 *
59 * This must be constructed before constructing any devices or checking
60 * CAN bus status. It is recommended that this is constructed
61 * immediately before a CANBus to fulfill this requirement.
62 *
63 * When using relative paths, the file path is typically relative
64 * to the top-level folder of the robot project.
65 *
66 * This API is blocking on the file read.
67 *
68 * \param filepath Path and name of the hoot file to load
69 * \throws std::invalid_argument - The file is invalid, unlicensed, or
70 * targets a different version of Phoenix 6
71 */
72 HootReplay(char const *filepath);
73
76
78
79 /**
80 * \brief Ends the hoot log replay. This stops the replay if it is running,
81 * closes the hoot log, and clears all signals read from the file.
82 */
83 void Close();
84
85 /**
86 * \brief Gets the status from opening and reading the file for replay.
87 *
88 * \returns Status from opening and reading the file for replay
89 */
90 ctre::phoenix::StatusCode GetStatus() const { return status; }
91
92 /**
93 * \brief Gets whether a valid hoot log file is currently loaded.
94 *
95 * \returns true if a valid hoot log file is loaded
96 */
97 static bool IsFileLoaded();
98
99 /**
100 * \brief Starts or resumes the hoot log replay.
101 *
102 * \returns Status of starting or resuming replay
103 */
105 /**
106 * \brief Pauses the hoot log replay. This maintains the current position
107 * in the log replay so it can be resumed later.
108 *
109 * \returns Status of pausing replay
110 */
112 /**
113 * \brief Stops the hoot log replay. This resets the current position in
114 * the log replay to the start.
115 *
116 * \returns Status of stopping replay
117 */
119 /**
120 * \brief Restarts the hoot log replay from the start of the log.
121 * This is equivalent to calling #Stop followed by #Play.
122 *
123 * \returns Status of restarting replay
124 */
126 {
127 auto retval = Stop();
128 if (retval.IsOK()) {
129 retval = Play();
130 }
131 return retval;
132 }
133
134 /**
135 * \brief Gets whether hoot log replay is actively playing.
136 *
137 * This API will return true in programs that do not support
138 * replay, making it safe to call without first checking if
139 * the program supports replay.
140 *
141 * \returns true if replay is playing back signals
142 */
143 static bool IsPlaying()
144 {
145 return WaitForPlaying(0_s);
146 }
147
148 /**
149 * \brief Waits until hoot log replay is actively playing.
150 *
151 * This API will immediately return true in programs that do
152 * not support replay, making it safe to call without first
153 * checking if the program supports replay
154 *
155 * Since this can block the calling thread, this should not
156 * be called with a non-zero timeout on the main thread.
157 *
158 * This can also be used with a timeout of 0 to perform
159 * a non-blocking check, which is equivalent to #IsPlaying.
160 *
161 * \param timeout Max time to wait for replay to start playing
162 * \returns true if replay is playing back signals
163 */
164 static bool WaitForPlaying(wpi::units::second_t timeout)
165 {
166 return WaitForPlayingImpl(timeout.value());
167 }
168
169 /**
170 * \brief Gets whether hoot log replay has reached the end of the log.
171 *
172 * \returns true if replay has reached the end of the log, or
173 * if no log is currently loaded
174 */
175 static bool IsFinished();
176
177 /**
178 * \brief Sets the speed of the hoot log replay. A speed of 1.0 corresponds
179 * to replaying the file in real time, and larger values increase the speed.
180 *
181 * - Minimum Value: 0.01
182 * - Maximum Value: 100.0
183 * - Default Value: 1.0
184 *
185 * \param speed Speed of the hoot log replay
186 */
187 static void SetSpeed(double speed);
188 /**
189 * \brief Advances the hoot log replay time by the given value. Replay must
190 * be paused or stopped before advancing its time.
191 *
192 * \param stepTimeSeconds The amount of time to advance
193 * \returns Status of advancing the replay time
194 */
195 static ctre::phoenix::StatusCode StepTiming(wpi::units::second_t stepTimeSeconds)
196 {
197 return StepTimingImpl(stepTimeSeconds.value());
198 }
199
200 /**
201 * \brief Gets a schema-serialized user signal.
202 *
203 * In an FRC robot program, users can call #GetStruct, #GetStructArray,
204 * and #GetProtobuf to directly get schema values instead.
205 *
206 * \param name Name of the signal
207 * \param type Type of the associated schema, such as struct or protobuf
208 * \returns Structure with all information about the signal
209 */
211 {
212 return GetSchemaValueImpl(name, type).ToSignalMeasurement();
213 }
214
215#if __has_include(<wpi/util/struct/Struct.hpp>) || defined(_CTRE_DOCS_)
216 /**
217 * \brief Gets a WPILib Struct user signal.
218 *
219 * \tparam T Struct type
220 * \tparam I Struct info types
221 * \param name Name of the signal
222 * \param info Optional struct type info
223 * \returns Structure with all information about the signal
224 */
225 template <typename T, typename... I>
226 requires wpi::util::StructSerializable<T, I...>
227 static SignalMeasurement<std::optional<T>> GetStruct(std::string_view name, I const &... info)
228 {
229 auto rawSig = GetSchemaValue(name, HootSchemaType::Struct);
230
231 std::optional<T> value;
232 if (rawSig.status.IsOK()) {
233 if (rawSig.value.size() == wpi::util::Struct<T>::GetSize(info...)) {
234 value = wpi::util::Struct<T>::Unpack(rawSig.value, info...);
235 } else {
236 value = std::nullopt;
238 }
239 } else {
240 value = std::nullopt;
241 }
242
243 return {
244 rawSig.name,
245 std::move(value),
246 rawSig.timestamp,
247 std::move(rawSig.units),
248 rawSig.status
249 };
250 }
251 /**
252 * \brief Gets a WPILib Struct array user signal.
253 *
254 * \tparam T Struct type
255 * \tparam I Struct info types
256 * \param name Name of the signal
257 * \param info Optional struct type info
258 * \returns Structure with all information about the signal
259 */
260 template <typename T, typename... I>
261 requires wpi::util::StructSerializable<T, I...>
262 static SignalMeasurement<std::optional<std::vector<T>>> GetStructArray(std::string_view name, I const &... info)
263 {
264 auto rawSig = GetSchemaValue(name, HootSchemaType::Struct);
265
266 std::optional<std::vector<T>> value;
267 if (rawSig.status.IsOK()) {
268 std::span<uint8_t const> data{rawSig.value};
269 auto const size = wpi::util::Struct<T>::GetSize(info...);
270 size_t const arr_size = data.size() / size;
271
272 if (arr_size * size == data.size()) {
273 std::vector<T> arr;
274 arr.reserve(arr_size);
275 for (size_t i = 0; i < arr_size; ++i) {
276 arr.emplace_back(wpi::util::UnpackStruct<T>(data, info...));
277 data = data.subspan(size);
278 }
279 value = std::move(arr);
280 } else {
281 value = std::nullopt;
283 }
284 } else {
285 value = std::nullopt;
286 }
287
288 return {
289 rawSig.name,
290 std::move(value),
291 rawSig.timestamp,
292 std::move(rawSig.units),
293 rawSig.status
294 };
295 }
296#endif
297
298#if __has_include(<wpi/util/protobuf/Protobuf.hpp>) || defined(_CTRE_DOCS_)
299 /**
300 * \brief Gets a Protobuf user signal.
301 *
302 * \tparam T Protobuf type
303 * \param name Name of the signal
304 * \returns Structure with all information about the signal
305 */
306 template <wpi::util::ProtobufSerializable T>
307 static SignalMeasurement<std::optional<T>> GetProtobuf(std::string_view name)
308 {
309 auto rawSig = GetSchemaValue(name, HootSchemaType::Protobuf);
310 return {
311 rawSig.name,
312 rawSig.status.IsOK()
313 ? wpi::util::ProtobufMessage<T>{}.Unpack(rawSig.value)
314 : std::nullopt,
315 rawSig.timestamp,
316 std::move(rawSig.units),
317 rawSig.status
318 };
319 }
320#endif
321
322 /**
323 * \brief Gets a raw-bytes user signal.
324 *
325 * \param name Name of the signal
326 * \returns Structure with all information about the signal
327 */
328 static SignalMeasurement<std::vector<uint8_t>> GetRaw(std::string_view name)
329 {
330 return GetRawImpl(name).ToSignalMeasurement();
331 }
332 /**
333 * \brief Gets a boolean user signal.
334 *
335 * \param name Name of the signal
336 * \returns Structure with all information about the signal
337 */
338 static SignalMeasurement<bool> GetBoolean(std::string_view name)
339 {
340 return GetBooleanImpl(name).ToSignalMeasurement();
341 }
342 /**
343 * \brief Gets an integer user signal.
344 *
345 * \param name Name of the signal
346 * \returns Structure with all information about the signal
347 */
348 static SignalMeasurement<int64_t> GetInteger(std::string_view name)
349 {
350 return GetIntegerImpl(name).ToSignalMeasurement();
351 }
352 /**
353 * \brief Gets a float user signal.
354 *
355 * \param name Name of the signal
356 * \returns Structure with all information about the signal
357 */
358 static SignalMeasurement<float> GetFloat(std::string_view name)
359 {
360 return GetFloatImpl(name).ToSignalMeasurement();
361 }
362 /**
363 * \brief Gets a double user signal.
364 *
365 * \param name Name of the signal
366 * \returns Structure with all information about the signal
367 */
368 static SignalMeasurement<double> GetDouble(std::string_view name)
369 {
370 return GetDoubleImpl(name).ToSignalMeasurement();
371 }
372
373 /**
374 * \brief Gets a unit value user signal.
375 *
376 * \tparam U Unit type
377 * \param name Name of the signal
378 * \returns Structure with all information about the signal
379 */
380 template <typename U>
381 requires wpi::units::traits::is_unit_t_v<U>
382 static SignalMeasurement<U> GetValue(std::string_view name)
383 {
384 SignalMeasurement<double> doubleSig = GetDouble(name);
385 return {
386 doubleSig.name,
387 U{doubleSig.value},
388 doubleSig.timestamp,
389 std::move(doubleSig.units),
390 doubleSig.status
391 };
392 }
393
394 /**
395 * \brief Gets a string user signal.
396 *
397 * \param name Name of the signal
398 * \returns Structure with all information about the signal
399 */
400 static SignalMeasurement<std::string> GetString(std::string_view name)
401 {
402 return GetStringImpl(name).ToSignalMeasurement();
403 }
404 /**
405 * \brief Get a boolean array user signal.
406 *
407 * \param name Name of the signal
408 * \returns Structure with all information about the signal
409 */
411 {
412 return GetBooleanArrayImpl(name).ToSignalMeasurement();
413 }
414 /**
415 * \brief Get an integer array user signal.
416 *
417 * \param name Name of the signal
418 * \returns Structure with all information about the signal
419 */
421 {
422 return GetIntegerArrayImpl(name).ToSignalMeasurement();
423 }
424 /**
425 * \brief Get a float array user signal.
426 *
427 * \param name Name of the signal
428 * \returns Structure with all information about the signal
429 */
431 {
432 return GetFloatArrayImpl(name).ToSignalMeasurement();
433 }
434 /**
435 * \brief Get a double array user signal.
436 *
437 * \param name Name of the signal
438 * \returns Structure with all information about the signal
439 */
441 {
442 return GetDoubleArrayImpl(name).ToSignalMeasurement();
443 }
444 /**
445 * \brief Get a string array user signal.
446 *
447 * \param name Name of the signal
448 * \returns Structure with all information about the signal
449 */
451 {
452 return GetStringArrayImpl(name).ToSignalMeasurement();
453 }
454
455private:
456 static bool WaitForPlayingImpl(double timeoutSeconds);
457 static ctre::phoenix::StatusCode StepTimingImpl(double stepTimeSeconds);
458
459 template <typename T>
460 struct UnitlessSignalData {
461 std::string_view name;
462 T value;
463 double timestampSec;
464 std::string units;
466
467 SignalMeasurement<T> ToSignalMeasurement() &&
468 {
469 return {
470 name,
471 std::move(value),
472 timestampSec * 1_s,
473 std::move(units),
474 status
475 };
476 }
477 };
478
479 static UnitlessSignalData<std::vector<uint8_t>> GetSchemaValueImpl(std::string_view name, HootSchemaType type);
480 static UnitlessSignalData<std::vector<uint8_t>> GetRawImpl(std::string_view name);
481 static UnitlessSignalData<bool> GetBooleanImpl(std::string_view name);
482 static UnitlessSignalData<int64_t> GetIntegerImpl(std::string_view name);
483 static UnitlessSignalData<float> GetFloatImpl(std::string_view name);
484 static UnitlessSignalData<double> GetDoubleImpl(std::string_view name);
485 static UnitlessSignalData<std::string> GetStringImpl(std::string_view name);
486 static UnitlessSignalData<std::vector<uint8_t>> GetBooleanArrayImpl(std::string_view name);
487 static UnitlessSignalData<std::vector<int64_t>> GetIntegerArrayImpl(std::string_view name);
488 static UnitlessSignalData<std::vector<float>> GetFloatArrayImpl(std::string_view name);
489 static UnitlessSignalData<std::vector<double>> GetDoubleArrayImpl(std::string_view name);
490 static UnitlessSignalData<std::vector<std::string>> GetStringArrayImpl(std::string_view name);
491};
492
493}
494}
static ctre::phoenix::StatusCode Play()
Starts or resumes the hoot log replay.
static SignalMeasurement< std::vector< int64_t > > GetIntegerArray(std::string_view name)
Get an integer array user signal.
Definition HootReplay.hpp:420
static SignalMeasurement< std::vector< float > > GetFloatArray(std::string_view name)
Get a float array user signal.
Definition HootReplay.hpp:430
static ctre::phoenix::StatusCode Stop()
Stops the hoot log replay.
static SignalMeasurement< std::optional< T > > GetStruct(std::string_view name, I const &... info)
Gets a WPILib Struct user signal.
Definition HootReplay.hpp:227
static SignalMeasurement< std::vector< double > > GetDoubleArray(std::string_view name)
Get a double array user signal.
Definition HootReplay.hpp:440
void Close()
Ends the hoot log replay.
static bool IsFileLoaded()
Gets whether a valid hoot log file is currently loaded.
static void SetSpeed(double speed)
Sets the speed of the hoot log replay.
static SignalMeasurement< std::optional< std::vector< T > > > GetStructArray(std::string_view name, I const &... info)
Gets a WPILib Struct array user signal.
Definition HootReplay.hpp:262
static SignalMeasurement< int64_t > GetInteger(std::string_view name)
Gets an integer user signal.
Definition HootReplay.hpp:348
static bool IsPlaying()
Gets whether hoot log replay is actively playing.
Definition HootReplay.hpp:143
HootReplay(HootReplay &&other)
static SignalMeasurement< U > GetValue(std::string_view name)
Gets a unit value user signal.
Definition HootReplay.hpp:382
~HootReplay()
Definition HootReplay.hpp:77
static SignalMeasurement< std::vector< uint8_t > > GetSchemaValue(std::string_view name, HootSchemaType type)
Gets a schema-serialized user signal.
Definition HootReplay.hpp:210
static SignalMeasurement< std::vector< uint8_t > > GetRaw(std::string_view name)
Gets a raw-bytes user signal.
Definition HootReplay.hpp:328
static ctre::phoenix::StatusCode Restart()
Restarts the hoot log replay from the start of the log.
Definition HootReplay.hpp:125
static SignalMeasurement< std::string > GetString(std::string_view name)
Gets a string user signal.
Definition HootReplay.hpp:400
static ctre::phoenix::StatusCode StepTiming(wpi::units::second_t stepTimeSeconds)
Advances the hoot log replay time by the given value.
Definition HootReplay.hpp:195
HootReplay & operator=(HootReplay &&other)
static SignalMeasurement< std::optional< T > > GetProtobuf(std::string_view name)
Gets a Protobuf user signal.
Definition HootReplay.hpp:307
static bool IsFinished()
Gets whether hoot log replay has reached the end of the log.
HootReplay(char const *filepath)
Loads the given file and starts signal log replay.
static SignalMeasurement< bool > GetBoolean(std::string_view name)
Gets a boolean user signal.
Definition HootReplay.hpp:338
static SignalMeasurement< std::vector< uint8_t > > GetBooleanArray(std::string_view name)
Get a boolean array user signal.
Definition HootReplay.hpp:410
static SignalMeasurement< double > GetDouble(std::string_view name)
Gets a double user signal.
Definition HootReplay.hpp:368
static bool WaitForPlaying(wpi::units::second_t timeout)
Waits until hoot log replay is actively playing.
Definition HootReplay.hpp:164
ctre::phoenix::StatusCode GetStatus() const
Gets the status from opening and reading the file for replay.
Definition HootReplay.hpp:90
static SignalMeasurement< float > GetFloat(std::string_view name)
Gets a float user signal.
Definition HootReplay.hpp:358
static SignalMeasurement< std::vector< std::string > > GetStringArray(std::string_view name)
Get a string array user signal.
Definition HootReplay.hpp:450
static ctre::phoenix::StatusCode Pause()
Pauses the hoot log replay.
Status codes reported by APIs, including OK, warnings, and errors.
Definition StatusCodes.h:28
static constexpr int InvalidParamValue
An invalid argument was passed into the function/VI, such as a null pointer.
Definition StatusCodes.h:370
Definition ExternalFeedbackConfigs.hpp:16
HootSchemaType
Supported schema types for a hoot user signal.
Definition HootSchemaType.hpp:15
@ Struct
Serialize using the WPILib Struct format.
Definition HootSchemaType.hpp:19
@ Protobuf
Serialize using the Protobuf format.
Definition HootSchemaType.hpp:23
Definition motor_constants.h:14
Information from a single measurement of a status signal.
Definition SignalMeasurement.hpp:25
T value
The value of the signal.
Definition SignalMeasurement.hpp:33
wpi::units::second_t timestamp
Timestamp of when the data point was taken.
Definition SignalMeasurement.hpp:37
std::string units
The units of the signal measurement.
Definition SignalMeasurement.hpp:41
ctre::phoenix::StatusCode status
Status code response of getting the data.
Definition SignalMeasurement.hpp:45
std::string_view name
The name of the signal.
Definition SignalMeasurement.hpp:29