6#include <unordered_map>
11#include <magic_enum/magic_enum.hpp>
12#include <frc2/command/RunCommand.h>
13#include <networktables/BooleanArrayTopic.h>
14#include <networktables/BooleanTopic.h>
15#include <networktables/DoubleArrayTopic.h>
16#include <networktables/DoubleTopic.h>
17#include <networktables/FloatTopic.h>
18#include <networktables/ProtobufTopic.h>
19#include <networktables/IntegerArrayTopic.h>
20#include <networktables/IntegerTopic.h>
21#include <networktables/NetworkTableInstance.h>
22#include <networktables/StringArrayTopic.h>
23#include <networktables/StringTopic.h>
24#include <networktables/StructArrayTopic.h>
25#include <networktables/StructTopic.h>
26#include <units/base.h>
27#include <wpi/protobuf/Protobuf.h>
28#include <wpi/sendable/Sendable.h>
29#include <wpi/struct/Struct.h>
31#include <units/angular_velocity.h>
32#include <units/acceleration.h>
33#include <units/angular_acceleration.h>
34#include <units/time.h>
35#include <units/temperature.h>
36#include <units/current.h>
43inline constexpr bool is_unit_vector =
false;
46inline constexpr bool is_unit_vector<std::vector<T>> = units::traits::is_unit_t_v<T>;
50 static_assert(
sizeof(T) == 0,
"No valid NetworkTables trait found for the specified data type");
55 static constexpr auto func = &nt::NetworkTable::GetBooleanTopic;
56 static constexpr std::string_view type =
"boolean";
61 static constexpr auto func = &nt::NetworkTable::GetFloatTopic;
62 static constexpr std::string_view type =
"float";
67 static constexpr auto func = &nt::NetworkTable::GetDoubleTopic;
68 static constexpr std::string_view type =
"double";
72 requires units::traits::is_unit_t_v<T>
75template <std::
integral T>
77 static constexpr auto func = &nt::NetworkTable::GetIntegerTopic;
78 static constexpr std::string_view type =
"int";
82 requires std::convertible_to<T, std::string_view>
84 static constexpr auto func = &nt::NetworkTable::GetStringTopic;
85 static constexpr std::string_view type =
"string";
89 requires std::is_enum_v<T>
90struct nt_traits<T> : nt_traits<std::string_view> {};
93 requires wpi::StructSerializable<T> && (!std::is_arithmetic_v<T>)
95 static constexpr auto func = &nt::NetworkTable::GetStructTopic<T>;
96 inline static std::string type =
"struct:" + std::string{wpi::Struct<T>::GetTypeName()};
100 requires wpi::ProtobufSerializable<T> && (!wpi::StructSerializable<T>)
102 static constexpr auto func = &nt::NetworkTable::GetProtobufTopic<T>;
103 static constexpr std::string_view type =
"proto:";
108 static constexpr auto func = &nt::NetworkTable::GetBooleanArrayTopic;
109 static constexpr std::string_view type =
"boolean[]";
114 static constexpr auto func = &nt::NetworkTable::GetFloatArrayTopic;
115 static constexpr std::string_view type =
"float[]";
120 static constexpr auto func = &nt::NetworkTable::GetDoubleArrayTopic;
121 static constexpr std::string_view type =
"double[]";
125 requires is_unit_vector<T>
128template <std::
integral T>
130 static constexpr auto func = &nt::NetworkTable::GetIntegerArrayTopic;
131 static constexpr std::string_view type =
"int64[]";
135 requires std::convertible_to<T, std::string_view>
137 static constexpr auto func = &nt::NetworkTable::GetStringArrayTopic;
138 static constexpr std::string_view type =
"string[]";
142 requires wpi::StructSerializable<T> && (!std::is_arithmetic_v<T>)
143struct nt_traits<std::vector<T>> {
144 static constexpr auto func = &nt::NetworkTable::GetStructArrayTopic<T>;
145 inline static std::string type =
"struct:" + std::string{wpi::Struct<T>::GetTypeName()} +
"[]";
149inline constexpr std::string_view unit_string =
"";
151#define UNIT_STRING(unit, str) \
153 inline constexpr std::string_view unit_string<units::unit##_t> = str
154UNIT_STRING(turn,
"rot");
156UNIT_STRING(radians_per_second,
"rad per sec");
157UNIT_STRING(degrees_per_second,
"deg per sec");
158UNIT_STRING(turns_per_second,
"rps");
160UNIT_STRING(meters_per_second_squared,
"mps2");
161UNIT_STRING(feet_per_second_squared,
"fps2");
162UNIT_STRING(standard_gravity,
"g");
164UNIT_STRING(radians_per_second_squared,
"rad per sec2");
165UNIT_STRING(degrees_per_second_squared,
"deg per sec2");
166UNIT_STRING(turns_per_second_squared,
"rps2");
168UNIT_STRING(day,
"day");
170UNIT_STRING(celsius,
"c");
171UNIT_STRING(fahrenheit,
"f");
173UNIT_STRING(ampere,
"amp");
177 using is_transparent = void;
178 size_t operator()(std::string_view sv)
const {
return std::hash<std::string_view>{}(sv); }
179 size_t operator()(
const std::string& s)
const {
return std::hash<std::string>{}(s); }
183 using is_transparent = void;
184 bool operator()(std::string_view lhs, std::string_view rhs)
const {
return lhs == rhs; }
239 static units::millisecond_t GetLoggingTime();
312 template <
typename T>
314 loggingProfiler.Start();
316 loggingProfiler.Stop();
320 if (
pub == publishers.end())
324 WriteLogImpl(
pub->second.get(),
data);
325 loggingProfiler.Stop();
342 template <
typename T>
344 loggingProfiler.Start();
346 loggingProfiler.Stop();
350 if (
sub == subscribers.end())
357 loggingProfiler.Stop();
362 template <
typename T>
363 using TopicType =
decltype((std::declval<nt::NetworkTable>().*detail::nt_traits<T>::func)(
""));
375 void EnableLogging();
383 template <
typename T>
384 inline void WriteLogImpl(nt::Publisher*
pub,
const T&
data) {
388 template <
typename T>
389 requires units::traits::is_unit_t_v<T>
390 inline void WriteLogImpl(nt::Publisher*
pub,
const T&
data) {
391 WriteLogImpl(
pub,
data.value());
394 template <
typename T>
395 requires detail::is_unit_vector<T>
396 void WriteLogImpl(nt::Publisher*
pub,
const T&
data) {
399 std::transform(
data.begin(),
data.end(), std::back_inserter(
castedData), [](
auto val) { return val.value(); });
403 template <
typename T>
404 requires std::is_enum_v<T>
405 void WriteLogImpl(nt::Publisher*
pub,
const T&
data) {
406 WriteLogImpl(
pub, magic_enum::enum_name(
data));
414 template <
typename T>
415 inline T ReadLogImpl(nt::Subscriber*
sub) {
416 return static_cast<TopicType<T>::SubscriberType*
>(
sub)->Get();
419 template <
typename T>
420 requires units::traits::is_unit_t_v<T>
421 inline T ReadLogImpl(nt::Subscriber*
sub) {
425 template <
typename T>
426 requires detail::is_unit_vector<T>
427 T ReadLogImpl(nt::Subscriber*
sub) {
436 template <
typename T>
437 requires std::is_enum_v<T>
438 T ReadLogImpl(nt::Subscriber*
sub) {
447 template <
typename T>
448 inline decltype(publishers)
::iterator addPublisher(std::string_view
field) {
451 std::make_unique<
typename TopicType<T>::PublisherType>((table.get()->*detail::nt_traits<T>::func)(
field).Publish()))
455 template <
typename T>
456 requires units::traits::is_unit_t_v<T>
458 std::string
unitValue{detail::unit_string<T>};
463 .emplace(
field, std::make_unique<nt::DoublePublisher>(table->GetDoubleTopic(
field).PublishEx(
"double", {{
"unit",
unitValue}})))
473 template <
typename T>
476 .emplace(
field, std::make_unique<
typename TopicType<T>::SubscriberType>(
481 template <
typename T>
482 requires units::traits::is_unit_t_v<T>
487 template <
typename T>
488 requires detail::is_unit_vector<T>
497 template <
typename T>
498 requires std::is_enum_v<T>
513 template <
typename T>
514 void checkTopicType(std::string_view
topicType, std::string_view
field) {
518 "Current type of '{}' doesn't match original topic type (received '{}', expected '{}')",
field,
522 std::shared_ptr<nt::NetworkTable> table;
523 std::unordered_map<std::string, Loggable*> loggableChildren;
524 std::unordered_map<std::string, wpi::Sendable*> sendableChildren;
525 frc::Timer periodicProfiler;
526 frc::Timer loggingPeriodTimer;
527 units::millisecond_t loggingPeriod{0
_ms};
528 static frc::Timer loggingProfiler;
532inline decltype(Loggable::subscribers)::iterator Loggable::addSubscriber(std::string_view field,
const std::vector<bool>& defaultValue) {
534 .emplace(field, std::make_unique<nt::BooleanArraySubscriber>(
535 table->GetBooleanArrayTopic(field).Subscribe(std::vector<int>{defaultValue.begin(), defaultValue.end()})))
540inline void Loggable::WriteLogImpl(nt::Publisher* pub,
const std::vector<bool>& data) {
541 static_cast<nt::BooleanArrayPublisher*
>(
pub)->
Set(std::vector<int>{
data.begin(),
data.end()});
545inline std::vector<bool> Loggable::ReadLogImpl(nt::Subscriber* sub) {
546 auto data =
static_cast<nt::BooleanArraySubscriber*
>(
sub)->Get();
Base helper for publishing and subscribing values to NetworkTables.
Definition Loggable.h:204
T ReadLog(std::string_view field, const T &defaultValue={})
Read a value from NetworkTables for the given field.
Definition Loggable.h:343
T WriteLog(std::string_view field, const T &data)
Publish a value to NetworkTables under the given field.
Definition Loggable.h:313
virtual void OnLoggingStart()
Hook invoked when logging is started for this object.
Definition Loggable.h:287
void LogChild(std::string_view name, Loggable *child)
Register a child Loggable under a named subtree.
void setLoggingPeriod(units::millisecond_t period)
Set the minimum period between LoggablePeriodic() invocations.
Definition Loggable.h:251
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:296
Loggable()
Default construct an uninitialized Loggable.
virtual ~Loggable()=default
Virtual destructor.
Loggable(std::string_view name)
Construct a Loggable that registers a top-level table name.
Definition Loggable.h:182
Definition Loggable.h:176