Valkyrie 2026
Loading...
Searching...
No Matches
Loggable.h
1#pragma once
2#include <algorithm>
3#include <memory>
4#include <string>
5#include <tuple>
6#include <unordered_map>
7#include <utility>
8#include <vector>
9
10#include <frc/smartdashboard/SmartDashboard.h>
11#include <magic_enum/magic_enum.hpp>
12#include <networktables/StructArrayTopic.h>
13#include <networktables/StructTopic.h>
14#include <units/base.h>
15#include <wpi/sendable/Sendable.h>
16#include <wpi/struct/Struct.h>
17
18namespace valor {
19
20namespace detail {
21
23 using is_transparent = void;
24
25 size_t operator()(std::string_view sv) const { return std::hash<std::string_view>{}(sv); }
26
27 size_t operator()(const std::string& s) const { return std::hash<std::string>{}(s); }
28};
29
31 using is_transparent = void;
32
33 bool operator()(std::string_view lhs, std::string_view rhs) const { return lhs == rhs; }
34};
35
36} // namespace detail
37
53class Loggable {
54 std::unordered_map<std::string, std::unique_ptr<nt::Publisher>, detail::string_hash, detail::string_equal> publishers;
55
56 public:
68 explicit Loggable(std::string_view name);
69
90 explicit Loggable(std::shared_ptr<nt::NetworkTable> table);
91
99 Loggable() = default;
100
112 void LogChild(std::string_view name, Loggable* child);
113
129 void LogChild(std::string_view name, wpi::Sendable* child);
130
131 inline bool WriteLog(std::string_view field, bool data) {
132 if (table)
133 frc::SmartDashboard::PutBoolean(smartDashboardPrefix + std::string{field}, data);
134 return data;
135 }
136
137 inline double WriteLog(std::string_view field, double data) {
138 if (table)
139 frc::SmartDashboard::PutNumber(smartDashboardPrefix + std::string{field}, data);
140 return data;
141 }
142
143 inline void WriteLog(std::string_view field, const std::vector<double>& data) {
144 if (table)
145 frc::SmartDashboard::PutNumberArray(smartDashboardPrefix + std::string{field}, data);
146 }
147
148 template <typename U>
149 requires units::traits::is_unit_t_v<U>
150 inline U WriteLog(std::string_view field, U data) {
151 WriteLog(field, data.value());
152 return data;
153 }
154
155 inline void WriteLog(std::string_view field, std::string_view data) {
156 if (table)
157 frc::SmartDashboard::PutString(smartDashboardPrefix + std::string{field}, data);
158 }
159
160 template <typename E>
161 requires std::is_enum_v<E>
162 inline void WriteLog(std::string_view field, E data) {
163 WriteLog(field, magic_enum::enum_name(data));
164 }
165
166 template <typename T>
167 requires wpi::StructSerializable<T> && (!std::is_arithmetic_v<T>)
168 inline void WriteLog(std::string_view field, const T& data) {
169 if (!table)
170 return;
171 auto pub = publishers.find(field);
172 if (pub == publishers.end())
173 pub = publishers
174 .try_emplace(std::string{field}, std::make_unique<nt::StructPublisher<T>>(table->GetStructTopic<T>(field).Publish()))
175 .first;
176 static_cast<nt::StructPublisher<T>*>(pub->second.get())->Set(data);
177 }
178
179 template <typename T>
180 requires wpi::StructSerializable<T> && (!std::is_arithmetic_v<T>)
181 inline void WriteLog(std::string_view field, const std::vector<T>& data) {
182 if (!table)
183 return;
184 auto pub = publishers.find(field);
185 if (pub == publishers.end())
186 pub = publishers
187 .try_emplace(std::string{field},
188 std::make_unique<nt::StructArrayPublisher<T>>(table->GetStructArrayTopic<T>(field).Publish()))
189 .first;
190 static_cast<nt::StructArrayPublisher<T>*>(pub->second.get())->Set(data);
191 }
192
193 inline bool ReadLog(std::string_view field, bool defaultValue) {
194 if (table)
195 return frc::SmartDashboard::GetBoolean(smartDashboardPrefix + std::string{field}, defaultValue);
196 return defaultValue;
197 }
198
199 inline double ReadLog(std::string_view field, double defaultValue) {
200 if (table)
201 return frc::SmartDashboard::GetNumber(smartDashboardPrefix + std::string{field}, defaultValue);
202 return defaultValue;
203 }
204
205 template <typename U>
206 requires units::traits::is_unit_t_v<U>
207 inline U ReadLog(std::string_view field, U defaultValue) {
208 return U{ReadLog(field, defaultValue.value())};
209 }
210
211 static constexpr Loggable& GetRoot() { return rootLoggable; }
212
213 protected:
220 virtual void OnLoggingStart() {}
221
229 virtual void LoggablePeriodic() {}
230
231 private:
232 std::string GetSmartDashboardPrefix() const;
233
234 std::shared_ptr<nt::NetworkTable> table;
235 std::string smartDashboardPrefix;
236 std::unordered_map<std::string, Loggable*> loggableChildren;
237 std::unordered_map<std::string, wpi::Sendable*> sendableChildren;
238 static Loggable rootLoggable;
239};
240
241} // namespace valor
Base helper for publishing and subscribing values to NetworkTables.
Definition Loggable.h:53
virtual void OnLoggingStart()
Hook invoked when logging is started for this object.
Definition Loggable.h:220
Loggable()=default
Default construct an uninitialized Loggable.
void LogChild(std::string_view name, Loggable *child)
Register a child Loggable under a named subtree.
void LogChild(std::string_view name, wpi::Sendable *child)
Register a child Sendable under a named subtree.
virtual void LoggablePeriodic()
Periodic callback for logging updates.
Definition Loggable.h:229
Loggable(std::string_view name)
Construct a Loggable that registers a top-level table name.
Loggable(std::shared_ptr< nt::NetworkTable > table)
Construct a Loggable that uses an existing NetworkTable.
Definition Loggable.h:30
Definition Loggable.h:22