blob: 58da8d29caaac154db1abad3558b2e27f69be50b [file] [log] [blame]
Henry Speisere5f05aa2022-05-02 21:24:26 -07001#ifndef FRC971_CONSTANTS_CONSTANTS_SENDER_H_
2#define FRC971_CONSTANTS_CONSTANTS_SENDER_H_
3
Austin Schuh99f7c6a2024-06-25 22:07:44 -07004#include "absl/flags/flag.h"
5#include "absl/log/check.h"
6#include "absl/log/log.h"
Philipp Schrader790cb542023-07-05 21:06:52 -07007
Henry Speisere5f05aa2022-05-02 21:24:26 -07008#include "aos/events/event_loop.h"
James Kuszmauld463cb42023-02-05 17:32:31 -08009#include "aos/events/shm_event_loop.h"
Henry Speisere5f05aa2022-05-02 21:24:26 -070010#include "aos/flatbuffer_merge.h"
11#include "aos/json_to_flatbuffer.h"
12#include "aos/network/team_number.h"
Henry Speisere5f05aa2022-05-02 21:24:26 -070013
14namespace frc971::constants {
15
16// Publishes the constants specific to the current robot
17template <typename ConstantsData, typename ConstantsList>
18class ConstantSender {
19 public:
James Kuszmaul9776b392023-01-14 14:08:08 -080020 ConstantSender(aos::EventLoop *event_loop, std::string constants_path,
21 std::string_view channel_name = "/constants")
Henry Speisere5f05aa2022-05-02 21:24:26 -070022 : ConstantSender<ConstantsData, ConstantsList>(
23 event_loop, constants_path, aos::network::GetTeamNumber(),
24 channel_name) {}
25
James Kuszmaul9776b392023-01-14 14:08:08 -080026 ConstantSender(aos::EventLoop *event_loop, std::string constants_path,
27 const uint16_t team_number, std::string_view channel_name)
Henry Speisere5f05aa2022-05-02 21:24:26 -070028 : team_number_(team_number),
29 channel_name_(channel_name),
30 constants_path_(constants_path),
31 event_loop_(event_loop),
32 sender_(event_loop_->MakeSender<ConstantsData>(channel_name_)) {
James Kuszmauld463cb42023-02-05 17:32:31 -080033 typename aos::Sender<ConstantsData>::Builder builder =
34 sender_.MakeBuilder();
35 builder.CheckOk(builder.Send(GetConstantsForTeamNumber(builder.fbb())));
Henry Speisere5f05aa2022-05-02 21:24:26 -070036 }
37
38 private:
39 const uint16_t team_number_ = 0;
40 std::string_view channel_name_;
41 flatbuffers::Offset<ConstantsData> GetConstantsForTeamNumber(
42 flatbuffers::FlatBufferBuilder *fbb) {
43 aos::FlatbufferDetachedBuffer<ConstantsList> fb =
44 aos::JsonFileToFlatbuffer<ConstantsList>(constants_path_);
45 const ConstantsList &message = fb.message();
46 const auto *constants = message.constants();
47 // Search through the constants for the one matching our team number.
48 for (const auto &constant_data : *constants) {
49 if (team_number_ == constant_data->team()) {
50 // Values is equal to the constants meant for the specific robot.
51 const ConstantsData *values = constant_data->data();
52 flatbuffers::Offset<ConstantsData> flatbuffer_constants =
53 aos::RecursiveCopyFlatBuffer(values, fbb);
54 return flatbuffer_constants;
55 }
56 }
57 LOG(FATAL) << "There was no match for " << team_number_
58 << ". Check the constants.json file for the team number that is "
59 "missing.";
60 }
61
62 std::string constants_path_;
63 aos::EventLoop *event_loop_;
64 aos::Sender<ConstantsData> sender_;
65};
66
James Kuszmauld463cb42023-02-05 17:32:31 -080067// This class fetches the current constants for the device, with appropriate
68// CHECKs to ensure that (a) the constants never change and (b) that the
69// constants are always available. This can be paired with WaitForConstants to
70// create the conditions for (b). In simulation, the constants should simply be
71// sent before starting up other EventLoops.
72template <typename ConstantsData>
73class ConstantsFetcher {
74 public:
75 ConstantsFetcher(aos::EventLoop *event_loop,
76 std::string_view channel = "/constants")
77 : fetcher_(event_loop->MakeFetcher<ConstantsData>(channel)) {
78 CHECK(fetcher_.Fetch())
79 << "Constants information must be available at startup.";
80 event_loop->MakeNoArgWatcher<ConstantsData>(channel, []() {
81 LOG(FATAL)
82 << "Don't know how to handle changes to constants information.";
83 });
84 }
85
Austin Schuh6bdcc372024-06-27 14:49:11 -070086 const ConstantsData &constants() const {
87 CHECK(fetcher_.get() != nullptr);
88 return *fetcher_.get();
89 }
James Kuszmauld463cb42023-02-05 17:32:31 -080090
91 private:
92 aos::Fetcher<ConstantsData> fetcher_;
93};
94
95// Blocks until data is available on the requested channel using a ShmEventLoop.
96// This is for use during initialization in C++ binaries so that we can delay
97// initialization until everything is available. This allows applications to
98// depend on constants data during their initialization.
99template <typename ConstantsData>
100void WaitForConstants(const aos::Configuration *config,
101 std::string_view channel = "/constants") {
102 aos::ShmEventLoop event_loop(config);
103 aos::Fetcher fetcher = event_loop.MakeFetcher<ConstantsData>(channel);
104 event_loop.MakeNoArgWatcher<ConstantsData>(
105 channel, [&event_loop]() { event_loop.Exit(); });
106 event_loop.OnRun([&event_loop, &fetcher]() {
107 // If the constants were already published, we don't need to wait for them.
108 if (fetcher.Fetch()) {
109 event_loop.Exit();
110 }
111 });
112 LOG(INFO) << "Waiting for constants data on " << channel << " "
113 << ConstantsData::GetFullyQualifiedName();
114 event_loop.Run();
115 LOG(INFO) << "Got constants data.";
116}
117
Henry Speisere5f05aa2022-05-02 21:24:26 -0700118} // namespace frc971::constants
119
120#endif // FRC971_CONSTANTS_CONSTANTS_SENDER_H_