blob: fb6b0c614342e9f5e47e27579c5ac3e146db3070 [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.");
James Kuszmaulee525992024-03-15 21:01:16 -070012DEFINE_string(node, "roborio", "");
James Kuszmaul63af2e32024-04-04 21:38:16 -070013DEFINE_bool(auto, false, "If set, trim the log to just the auto mode.");
James Kuszmaul14d7ea12023-12-09 15:41:14 -080014DEFINE_double(pre_enable_time_sec, 10.0,
15 "Amount of time to leave in the new log before the first enable "
16 "signal happens.");
17DEFINE_double(post_enable_time_sec, 1.0,
18 "Amount of time to leave in the new log after the final enable "
19 "signal ends.");
James Kuszmaulee525992024-03-15 21:01:16 -070020DEFINE_double(force_start_monotonic, -1.0,
21 "If set, time, in seconds, at which to forcibly trim the start "
22 "of the log.");
23DEFINE_double(
24 force_end_monotonic, -1.0,
25 "If set, time, in seconds, at which to forcibly trim the end of the log.");
James Kuszmaul14d7ea12023-12-09 15:41:14 -080026
27int main(int argc, char *argv[]) {
28 gflags::SetUsageMessage(
29 "Trims the sections at the start/end of a log where the robot is "
30 "disabled.");
31 aos::InitGoogle(&argc, &argv);
32 const std::vector<aos::logger::LogFile> logfiles =
33 aos::logger::SortParts(aos::logger::FindLogs(argc, argv));
34 std::optional<aos::monotonic_clock::time_point> start_time;
35 std::optional<aos::monotonic_clock::time_point> end_time;
36 bool printed_match = false;
James Kuszmaulee525992024-03-15 21:01:16 -070037 bool force_time_range = FLAGS_force_start_monotonic > 0;
James Kuszmaul14d7ea12023-12-09 15:41:14 -080038 // We need to do two passes through the logfile; one to figure out when the
39 // start/end times are, one to actually do the trimming.
James Kuszmaulee525992024-03-15 21:01:16 -070040 if (!force_time_range) {
James Kuszmaul14d7ea12023-12-09 15:41:14 -080041 aos::logger::LogReader reader(logfiles);
42 const aos::Node *roborio =
James Kuszmaulee525992024-03-15 21:01:16 -070043 aos::configuration::GetNode(reader.configuration(), FLAGS_node);
James Kuszmaul14d7ea12023-12-09 15:41:14 -080044 reader.Register();
45 std::unique_ptr<aos::EventLoop> event_loop =
James Kuszmaulee525992024-03-15 21:01:16 -070046 reader.event_loop_factory()->MakeEventLoop(FLAGS_node, roborio);
James Kuszmaul14d7ea12023-12-09 15:41:14 -080047 event_loop->MakeWatcher(
48 "/aos", [&start_time, &end_time, &printed_match,
49 &event_loop](const aos::JoystickState &msg) {
50 if (!printed_match && msg.match_type() != aos::MatchType::kNone) {
51 LOG(INFO) << "Match Type: "
52 << aos::EnumNameMatchType(msg.match_type());
53 LOG(INFO) << "Match #: " << msg.match_number();
54 printed_match = true;
55 }
56
James Kuszmaul63af2e32024-04-04 21:38:16 -070057 if (msg.enabled() && (!FLAGS_auto || msg.autonomous())) {
James Kuszmaul14d7ea12023-12-09 15:41:14 -080058 // Note that time is monotonic, so we don't need to e.g. do min's or
59 // max's on the start/end time.
60 if (!start_time.has_value()) {
61 start_time = event_loop->context().monotonic_event_time;
62 }
63 end_time = event_loop->context().monotonic_event_time;
64 }
65 });
66
67 reader.event_loop_factory()->Run();
68
69 if (!printed_match) {
70 LOG(INFO) << "No match info.";
71 }
James Kuszmaulee525992024-03-15 21:01:16 -070072 if (!start_time.has_value()) {
73 LOG(WARNING) << "Log does not ontain any JoystickState messages.";
74 return 1;
75 }
76 LOG(INFO) << "First enable at " << start_time.value();
77 LOG(INFO) << "Final enable at " << end_time.value();
78 start_time.value() -= std::chrono::duration_cast<std::chrono::nanoseconds>(
79 std::chrono::duration<double>(FLAGS_pre_enable_time_sec));
80 end_time.value() += std::chrono::duration_cast<std::chrono::nanoseconds>(
81 std::chrono::duration<double>(FLAGS_post_enable_time_sec));
82 } else {
83 CHECK_LT(FLAGS_force_start_monotonic, FLAGS_force_end_monotonic);
84 start_time = aos::monotonic_clock::time_point(
85 std::chrono::duration_cast<std::chrono::nanoseconds>(
86 std::chrono::duration<double>(FLAGS_force_start_monotonic)));
87 end_time = aos::monotonic_clock::time_point(
88 std::chrono::duration_cast<std::chrono::nanoseconds>(
89 std::chrono::duration<double>(FLAGS_force_end_monotonic)));
James Kuszmaul14d7ea12023-12-09 15:41:14 -080090 }
James Kuszmaul14d7ea12023-12-09 15:41:14 -080091
92 {
93 aos::logger::LogReader reader(logfiles);
94 const aos::Node *roborio =
James Kuszmaulee525992024-03-15 21:01:16 -070095 aos::configuration::GetNode(reader.configuration(), FLAGS_node);
James Kuszmaul14d7ea12023-12-09 15:41:14 -080096 reader.Register();
97 std::unique_ptr<aos::EventLoop> event_loop =
James Kuszmaulee525992024-03-15 21:01:16 -070098 reader.event_loop_factory()->MakeEventLoop(FLAGS_node, roborio);
James Kuszmaul14d7ea12023-12-09 15:41:14 -080099 auto exit_timer = event_loop->AddTimer(
100 [&reader]() { reader.event_loop_factory()->Exit(); });
101 exit_timer->Schedule(start_time.value());
102 reader.event_loop_factory()->Run();
103 const std::set<std::string> logger_nodes =
104 aos::logger::LoggerNodes(logfiles);
105 // Only start up loggers that generated the original set of logfiles.
106 // This mostly exists to make it so that utilities like log_to_mcap can
107 // easily auto-detect which node to replay as when consuming the input logs.
108 auto loggers = aos::util::MakeLoggersForNodes(
109 reader.event_loop_factory(), {logger_nodes.begin(), logger_nodes.end()},
110 FLAGS_output_folder);
111 exit_timer->Schedule(end_time.value());
112
113 reader.event_loop_factory()->Run();
114 }
115
116 LOG(INFO) << "Trimmed logs written to " << FLAGS_output_folder;
117
118 return EXIT_SUCCESS;
119}