blob: 0853ea5f472801a44a3e2f2fb538abe6de9c1db9 [file] [log] [blame]
James Kuszmaul14d7ea12023-12-09 15:41:14 -08001#include <optional>
2
3#include "gflags/gflags.h"
4
5#include "aos/events/logging/log_reader.h"
6#include "aos/init.h"
7#include "aos/util/simulation_logger.h"
8#include "frc971/input/joystick_state_generated.h"
9
10DEFINE_string(output_folder, "/tmp/trimmed/",
11 "Name of the folder to write the trimmed log to.");
12DEFINE_double(pre_enable_time_sec, 10.0,
13 "Amount of time to leave in the new log before the first enable "
14 "signal happens.");
15DEFINE_double(post_enable_time_sec, 1.0,
16 "Amount of time to leave in the new log after the final enable "
17 "signal ends.");
18
19int main(int argc, char *argv[]) {
20 gflags::SetUsageMessage(
21 "Trims the sections at the start/end of a log where the robot is "
22 "disabled.");
23 aos::InitGoogle(&argc, &argv);
24 const std::vector<aos::logger::LogFile> logfiles =
25 aos::logger::SortParts(aos::logger::FindLogs(argc, argv));
26 std::optional<aos::monotonic_clock::time_point> start_time;
27 std::optional<aos::monotonic_clock::time_point> end_time;
28 bool printed_match = false;
29 // We need to do two passes through the logfile; one to figure out when the
30 // start/end times are, one to actually do the trimming.
31 {
32 aos::logger::LogReader reader(logfiles);
33 const aos::Node *roborio =
34 aos::configuration::GetNode(reader.configuration(), "roborio");
35 reader.Register();
36 std::unique_ptr<aos::EventLoop> event_loop =
37 reader.event_loop_factory()->MakeEventLoop("roborio", roborio);
38 event_loop->MakeWatcher(
39 "/aos", [&start_time, &end_time, &printed_match,
40 &event_loop](const aos::JoystickState &msg) {
41 if (!printed_match && msg.match_type() != aos::MatchType::kNone) {
42 LOG(INFO) << "Match Type: "
43 << aos::EnumNameMatchType(msg.match_type());
44 LOG(INFO) << "Match #: " << msg.match_number();
45 printed_match = true;
46 }
47
48 if (msg.enabled()) {
49 // Note that time is monotonic, so we don't need to e.g. do min's or
50 // max's on the start/end time.
51 if (!start_time.has_value()) {
52 start_time = event_loop->context().monotonic_event_time;
53 }
54 end_time = event_loop->context().monotonic_event_time;
55 }
56 });
57
58 reader.event_loop_factory()->Run();
59
60 if (!printed_match) {
61 LOG(INFO) << "No match info.";
62 }
63 }
64 if (!start_time.has_value()) {
65 LOG(WARNING) << "Log does not ontain any JoystickState messages.";
66 return 1;
67 }
68 LOG(INFO) << "First enable at " << start_time.value();
69 LOG(INFO) << "Final enable at " << end_time.value();
70 start_time.value() -= std::chrono::duration_cast<std::chrono::nanoseconds>(
71 std::chrono::duration<double>(FLAGS_pre_enable_time_sec));
72 end_time.value() += std::chrono::duration_cast<std::chrono::nanoseconds>(
73 std::chrono::duration<double>(FLAGS_post_enable_time_sec));
74
75 {
76 aos::logger::LogReader reader(logfiles);
77 const aos::Node *roborio =
78 aos::configuration::GetNode(reader.configuration(), "roborio");
79 reader.Register();
80 std::unique_ptr<aos::EventLoop> event_loop =
81 reader.event_loop_factory()->MakeEventLoop("roborio", roborio);
82 auto exit_timer = event_loop->AddTimer(
83 [&reader]() { reader.event_loop_factory()->Exit(); });
84 exit_timer->Schedule(start_time.value());
85 reader.event_loop_factory()->Run();
86 const std::set<std::string> logger_nodes =
87 aos::logger::LoggerNodes(logfiles);
88 // Only start up loggers that generated the original set of logfiles.
89 // This mostly exists to make it so that utilities like log_to_mcap can
90 // easily auto-detect which node to replay as when consuming the input logs.
91 auto loggers = aos::util::MakeLoggersForNodes(
92 reader.event_loop_factory(), {logger_nodes.begin(), logger_nodes.end()},
93 FLAGS_output_folder);
94 exit_timer->Schedule(end_time.value());
95
96 reader.event_loop_factory()->Run();
97 }
98
99 LOG(INFO) << "Trimmed logs written to " << FLAGS_output_folder;
100
101 return EXIT_SUCCESS;
102}