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