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