Merge "Fix wrist oscillations"
diff --git a/aos/events/logging/BUILD b/aos/events/logging/BUILD
index 07a751c..1edc142 100644
--- a/aos/events/logging/BUILD
+++ b/aos/events/logging/BUILD
@@ -642,6 +642,19 @@
)
cc_test(
+ name = "log_reader_utils_test",
+ srcs = ["log_reader_utils_test.cc"],
+ data = [
+ ":multinode_pingpong_combined_config",
+ ],
+ target_compatible_with = ["@platforms//os:linux"],
+ deps = [
+ ":log_reader_utils",
+ ":multinode_logger_test_lib",
+ ],
+)
+
+cc_test(
name = "multinode_logger_test",
srcs = ["multinode_logger_test.cc"],
copts = select({
@@ -729,3 +742,21 @@
"@com_google_absl//absl/strings",
],
)
+
+cc_binary(
+ name = "log_config_extractor",
+ srcs = [
+ "log_config_extractor.cc",
+ ],
+ target_compatible_with = ["@platforms//os:linux"],
+ visibility = ["//visibility:public"],
+ deps = [
+ "//aos:aos_cli_utils",
+ "//aos:configuration",
+ "//aos:init",
+ "//aos:json_to_flatbuffer",
+ "//aos/events/logging:log_reader",
+ "@com_github_gflags_gflags//:gflags",
+ "@com_github_google_glog//:glog",
+ ],
+)
diff --git a/aos/events/logging/log_config_extractor.cc b/aos/events/logging/log_config_extractor.cc
new file mode 100644
index 0000000..aa2eed0
--- /dev/null
+++ b/aos/events/logging/log_config_extractor.cc
@@ -0,0 +1,133 @@
+#include <iostream>
+#include <filesystem>
+#include <vector>
+
+#include "aos/configuration_generated.h"
+#include "aos/events/logging/log_reader.h"
+#include "aos/events/logging/logfile_sorting.h"
+#include "aos/flatbuffer_merge.h"
+#include "aos/init.h"
+#include "aos/json_to_flatbuffer.h"
+#include "flatbuffers/flatbuffers.h"
+#include "gflags/gflags.h"
+#include "glog/logging.h"
+
+DEFINE_string(output_path, "/tmp/",
+ "Destination folder for output files. If this flag is not used, "
+ "it stores the files in /tmp/.");
+DEFINE_bool(convert_to_json, false,
+ "If true, can be used to convert bfbs to json.");
+DEFINE_bool(bfbs, false,
+ "If true, write as a binary flatbuffer inside the output_path.");
+DEFINE_bool(json, false, "If true, write as a json inside the output_path.");
+DEFINE_bool(stripped, false,
+ "If true, write as a stripped json inside the output_path.");
+DEFINE_bool(quiet, false,
+ "If true, do not print configuration to stdout. If false, print "
+ "stripped json");
+
+namespace aos {
+
+void WriteConfig(const aos::Configuration *config, std::string output_path) {
+ // In order to deduplicate the reflection schemas in the resulting config
+ // flatbuffer (and thus reduce the size of the final flatbuffer), use
+ // MergeConfiguration() rather than the more generic
+ // RecursiveCopyFlatBuffer(). RecursiveCopyFlatBuffer() is sometimes used to
+ // reduce flatbuffer memory usage, but it only does so by rearranging memory
+ // locations, not by actually deduplicating identical flatbuffers.
+ std::vector<aos::FlatbufferVector<reflection::Schema>> schemas;
+ for (const Channel *c : *config->channels()) {
+ schemas.emplace_back(RecursiveCopyFlatBuffer(c->schema()));
+ }
+ auto config_flatbuffer = configuration::MergeConfiguration(
+ RecursiveCopyFlatBuffer(config), schemas);
+
+ if (FLAGS_bfbs) {
+ WriteFlatbufferToFile(output_path + ".bfbs", config_flatbuffer);
+ LOG(INFO) << "Done writing bfbs to " << output_path << ".bfbs";
+ }
+
+ if (FLAGS_json) {
+ WriteFlatbufferToJson(output_path + ".json", config_flatbuffer);
+ LOG(INFO) << "Done writing json to " << output_path << ".json";
+ }
+
+ if (FLAGS_stripped || !FLAGS_quiet) {
+ auto *channels = config_flatbuffer.mutable_message()->mutable_channels();
+ for (size_t i = 0; i < channels->size(); i++) {
+ channels->GetMutableObject(i)->clear_schema();
+ }
+ if (FLAGS_stripped) {
+ WriteFlatbufferToJson(output_path + ".stripped.json", config_flatbuffer);
+ LOG(INFO) << "Done writing stripped json to " << output_path
+ << ".stripped.json";
+ }
+ if (!FLAGS_quiet) {
+ std::cout << FlatbufferToJson(config_flatbuffer) << std::endl;
+ }
+ }
+}
+
+int Main(int argc, char *argv[]) {
+ CHECK(argc > 1) << "Must provide an argument";
+
+ std::string output_path = FLAGS_output_path;
+ if (output_path.back() != '/') {
+ output_path += "/";
+ }
+ if (!std::filesystem::exists(output_path)) {
+ LOG(ERROR)
+ << "Output path is invalid. Make sure the path exists before running.";
+ return EXIT_FAILURE;
+ }
+ output_path += "aos_config";
+
+ std::shared_ptr<const aos::Configuration> config;
+ // Check if the user wants to use stdin (denoted by '-') which will help
+ // convert configs in json to bfbs (see example in SetUsageMessage)
+ std::string_view arg{argv[1]};
+ if (arg == "-") {
+ // Read in everything from stdin, blocks when there's no data on stdin
+ std::string stdin_data(std::istreambuf_iterator(std::cin), {});
+ aos::FlatbufferDetachedBuffer<aos::Configuration> buffer(
+ aos::JsonToFlatbuffer(stdin_data, aos::ConfigurationTypeTable()));
+ WriteConfig(&buffer.message(), output_path);
+ } else if (FLAGS_convert_to_json) {
+ aos::FlatbufferDetachedBuffer config = aos::configuration::ReadConfig(arg);
+ WriteFlatbufferToJson(output_path + ".json", config);
+ LOG(INFO) << "Done writing json to " << output_path << ".json";
+ } else {
+ const std::vector<std::string> unsorted_logfiles =
+ aos::logger::FindLogs(argc, argv);
+
+ const std::vector<aos::logger::LogFile> logfiles =
+ aos::logger::SortParts(unsorted_logfiles);
+
+ WriteConfig(logfiles[0].config.get(), output_path);
+ }
+ return EXIT_SUCCESS;
+}
+
+} // namespace aos
+
+int main(int argc, char *argv[]) {
+ gflags::SetUsageMessage(
+ "Binary to output the configuration of a log.\n"
+ "# print config as stripped json to stdout\n"
+ "# path to log should always be absolute path.\n"
+ "log_config_extractor /path/to/log\n"
+ "# write config to ~/work/results/aos_config.bfbs and "
+ "~/work/results/aos_config.json with no stdout "
+ "output\n"
+ "# make sure the output paths are valid and absolute paths.\n"
+ "log_config_extractor /path/to/log --output_path=~/work/results/ --bfbs "
+ "--json --quiet\n"
+ "# pass json config by stdin and output as bfbs\n"
+ "cat aos_config.json | log_config_extractor - --output_path "
+ "/absolute/path/to/dir --bfbs\n"
+ "# This can also be used to convert a bfbs file of config to json\n"
+ "log_config_extractor /path/to/config.bfbs --convert_to_json");
+
+ aos::InitGoogle(&argc, &argv);
+ return aos::Main(argc, argv);
+}
diff --git a/aos/events/logging/log_reader.cc b/aos/events/logging/log_reader.cc
index fb63e79..fa5e5d5 100644
--- a/aos/events/logging/log_reader.cc
+++ b/aos/events/logging/log_reader.cc
@@ -618,7 +618,7 @@
? nullptr
: std::make_unique<TimestampMapper>(std::move(filtered_parts)),
filters_.get(), std::bind(&LogReader::NoticeRealtimeEnd, this), node,
- State::ThreadedBuffering::kNo, MaybeMakeReplayChannelIndicies(node));
+ State::ThreadedBuffering::kNo, MaybeMakeReplayChannelIndices(node));
State *state = states_[node_index].get();
state->SetNodeEventLoopFactory(
event_loop_factory_->GetNodeEventLoopFactory(node),
@@ -809,7 +809,7 @@
? nullptr
: std::make_unique<TimestampMapper>(std::move(filtered_parts)),
filters_.get(), std::bind(&LogReader::NoticeRealtimeEnd, this), node,
- State::ThreadedBuffering::kYes, MaybeMakeReplayChannelIndicies(node));
+ State::ThreadedBuffering::kYes, MaybeMakeReplayChannelIndices(node));
State *state = states_[node_index].get();
state->SetChannelCount(logged_configuration()->channels()->size());
@@ -1333,7 +1333,8 @@
RemapConflict conflict_handling) {
if (replay_channels_ != nullptr) {
CHECK(std::find(replay_channels_->begin(), replay_channels_->end(),
- std::make_pair(name, type)) != replay_channels_->end())
+ std::make_pair(std::string{name}, std::string{type})) !=
+ replay_channels_->end())
<< "Attempted to remap channel " << name << " " << type
<< " which is not included in the replay channels passed to LogReader.";
}
@@ -1668,13 +1669,13 @@
// TODO(austin): Lazily re-build to save CPU?
}
-std::unique_ptr<const ReplayChannelIndicies>
-LogReader::MaybeMakeReplayChannelIndicies(const Node *node) {
+std::unique_ptr<const ReplayChannelIndices>
+LogReader::MaybeMakeReplayChannelIndices(const Node *node) {
if (replay_channels_ == nullptr) {
return nullptr;
} else {
- std::unique_ptr<ReplayChannelIndicies> replay_channel_indicies =
- std::make_unique<ReplayChannelIndicies>();
+ std::unique_ptr<ReplayChannelIndices> replay_channel_indices =
+ std::make_unique<ReplayChannelIndices>();
for (auto const &channel : *replay_channels_) {
const Channel *ch = configuration::GetChannel(
logged_configuration(), channel.first, channel.second, "", node);
@@ -1686,10 +1687,10 @@
}
const size_t channel_index =
configuration::ChannelIndex(logged_configuration(), ch);
- replay_channel_indicies->emplace_back(channel_index);
+ replay_channel_indices->emplace_back(channel_index);
}
- std::sort(replay_channel_indicies->begin(), replay_channel_indicies->end());
- return replay_channel_indicies;
+ std::sort(replay_channel_indices->begin(), replay_channel_indices->end());
+ return replay_channel_indices;
}
}
@@ -1748,16 +1749,19 @@
message_bridge::MultiNodeNoncausalOffsetEstimator *multinode_filters,
std::function<void()> notice_realtime_end, const Node *node,
LogReader::State::ThreadedBuffering threading,
- std::unique_ptr<const ReplayChannelIndicies> replay_channel_indicies)
+ std::unique_ptr<const ReplayChannelIndices> replay_channel_indices)
: timestamp_mapper_(std::move(timestamp_mapper)),
notice_realtime_end_(notice_realtime_end),
node_(node),
multinode_filters_(multinode_filters),
threading_(threading),
- replay_channel_indicies_(std::move(replay_channel_indicies)) {
- if (replay_channel_indicies_ != nullptr) {
+ replay_channel_indices_(std::move(replay_channel_indices)) {
+ // If timestamp_mapper_ is nullptr, then there are no log parts associated
+ // with this node. If there are no log parts for the node, there will be no
+ // log data, and so we do not need to worry about the replay channel filters.
+ if (replay_channel_indices_ != nullptr && timestamp_mapper_ != nullptr) {
timestamp_mapper_->set_replay_channels_callback(
- [filter = replay_channel_indicies_.get()](
+ [filter = replay_channel_indices_.get()](
const TimestampedMessage &message) -> bool {
auto const begin = filter->cbegin();
auto const end = filter->cend();
diff --git a/aos/events/logging/log_reader.h b/aos/events/logging/log_reader.h
index fd5a935..d4936f1 100644
--- a/aos/events/logging/log_reader.h
+++ b/aos/events/logging/log_reader.h
@@ -33,9 +33,9 @@
// Vector of pair of name and type of the channel
using ReplayChannels =
- std::vector<std::pair<std::string_view, std::string_view>>;
+ std::vector<std::pair<std::string, std::string>>;
// Vector of channel indices
-using ReplayChannelIndicies = std::vector<size_t>;
+using ReplayChannelIndices = std::vector<size_t>;
// We end up with one of the following 3 log file types.
//
@@ -350,7 +350,7 @@
message_bridge::MultiNodeNoncausalOffsetEstimator *multinode_filters,
std::function<void()> notice_realtime_end, const Node *node,
ThreadedBuffering threading,
- std::unique_ptr<const ReplayChannelIndicies> replay_channel_indicies);
+ std::unique_ptr<const ReplayChannelIndices> replay_channel_indices);
// Connects up the timestamp mappers.
void AddPeer(State *peer);
@@ -753,12 +753,12 @@
// If a ReplayChannels was passed to LogReader, this will hold the
// indices of the channels to replay for the Node represented by
// the instance of LogReader::State.
- std::unique_ptr<const ReplayChannelIndicies> replay_channel_indicies_;
+ std::unique_ptr<const ReplayChannelIndices> replay_channel_indices_;
};
// If a ReplayChannels was passed to LogReader then creates a
- // ReplayChannelIndicies for the given node. Otherwise, returns a nullptr.
- std::unique_ptr<const ReplayChannelIndicies> MaybeMakeReplayChannelIndicies(
+ // ReplayChannelIndices for the given node. Otherwise, returns a nullptr.
+ std::unique_ptr<const ReplayChannelIndices> MaybeMakeReplayChannelIndices(
const Node *node);
// Node index -> State.
diff --git a/aos/events/logging/log_reader_utils_test.cc b/aos/events/logging/log_reader_utils_test.cc
new file mode 100644
index 0000000..9977be9
--- /dev/null
+++ b/aos/events/logging/log_reader_utils_test.cc
@@ -0,0 +1,129 @@
+#include "aos/events/logging/log_reader_utils.h"
+
+#include "aos/events/logging/multinode_logger_test_lib.h"
+#include "aos/events/ping_lib.h"
+#include "aos/events/pong_lib.h"
+#include "aos/testing/tmpdir.h"
+
+namespace aos::logger::testing {
+
+namespace chrono = std::chrono;
+// Created this test fixture because the test case checks for channel names
+// which are different in different configs
+using MultinodeLoggerOneConfigTest = MultinodeLoggerTest;
+
+INSTANTIATE_TEST_SUITE_P(
+ All, MultinodeLoggerOneConfigTest,
+ ::testing::Combine(::testing::Values(ConfigParams{
+ "multinode_pingpong_combined_config.json", true,
+ kCombinedConfigSha1(), kCombinedConfigSha1()}),
+ ::testing::ValuesIn(SupportedCompressionAlgorithms())));
+
+// This test is to check if we are able to get the right channels from a log
+// given nodes and applications using the function ChannelsInLog
+TEST_P(MultinodeLoggerOneConfigTest, ChannelsInLogTest) {
+ // Run the logger
+ time_converter_.StartEqual();
+ {
+ LoggerState pi1_logger = MakeLogger(pi1_);
+ LoggerState pi2_logger = MakeLogger(pi2_);
+
+ event_loop_factory_.RunFor(chrono::milliseconds(95));
+
+ StartLogger(&pi1_logger);
+ StartLogger(&pi2_logger);
+
+ event_loop_factory_.RunFor(chrono::milliseconds(20000));
+ }
+
+ auto sorted_parts = SortParts(logfiles_);
+ // Read all the sorted log files
+ LogReader reader(sorted_parts);
+
+ std::vector<const Node *> active_nodes;
+ std::vector<std::string> applications;
+ // Get the active node
+ active_nodes.emplace_back(
+ configuration::GetNode(reader.configuration(), "pi1"));
+
+ // Get the application for which you want to check channels
+ applications.push_back("ping");
+ aos::logger::ChannelsInLogResult channels =
+ aos::logger::ChannelsInLog(sorted_parts, active_nodes, applications);
+
+ // Check for the right sender channels
+ std::vector<std::string> expected_senders;
+ expected_senders.push_back("/pi1/aos aos.logging.LogMessageFbs");
+ expected_senders.push_back("/pi1/aos aos.timing.Report");
+ expected_senders.push_back("/test aos.examples.Ping");
+
+ std::vector<std::string> check_senders;
+ for (const auto &sender : channels.senders.value()) {
+ check_senders.push_back(sender.name + " " + sender.type);
+ }
+ ASSERT_THAT(check_senders,
+ ::testing::UnorderedElementsAreArray(expected_senders));
+ ASSERT_EQ(channels.senders.value().size(), 3);
+
+ // Check for the right watcher channels
+ std::vector<std::string> expected_watchers;
+ expected_watchers.push_back("/test aos.examples.Pong");
+ std::vector<std::string> check_watchers;
+ for (const auto &watcher : channels.watchers.value()) {
+ check_watchers.push_back(watcher.name + " " + watcher.type);
+ }
+ ASSERT_THAT(check_watchers,
+ ::testing::UnorderedElementsAreArray(expected_watchers));
+ ASSERT_EQ(channels.watchers.value().size(), 1);
+
+ // There no fetcher channels, check for none
+ ASSERT_EQ(channels.fetchers.value().size(), 0);
+}
+
+// Test to run log reader with replay channels via simulated event loop
+TEST_P(MultinodeLoggerOneConfigTest, SingleNodeLogReplay) {
+ time_converter_.StartEqual();
+ std::vector<std::string> actual_filenames;
+ const std::string kLogfile1_1 =
+ aos::testing::TestTmpDir() + "/multi_logfile1/";
+ util::UnlinkRecursive(kLogfile1_1);
+
+ {
+ LoggerState pi1_logger = MakeLoggerState(
+ pi1_, &event_loop_factory_, SupportedCompressionAlgorithms()[0]);
+ pi2_->DisableStatistics();
+ pi2_->Disconnect(pi1_->node());
+ pi1_->Disconnect(pi2_->node());
+ pi1_logger.StartLogger(kLogfile1_1);
+ event_loop_factory_.RunFor(chrono::milliseconds(20000));
+ pi1_logger.AppendAllFilenames(&actual_filenames);
+ }
+
+ ReplayChannels replay_channels{{"/test", "aos.examples.Ping"}};
+ LogReader reader(logger::SortParts(actual_filenames), &config_.message(),
+ &replay_channels);
+ SimulatedEventLoopFactory log_reader_factory(reader.configuration());
+ int ping_count = 0;
+ int pong_count = 0;
+
+ // This sends out the fetched messages and advances time to the start of the
+ // log file.
+ reader.Register(&log_reader_factory);
+
+ const Node *pi1 =
+ configuration::GetNode(log_reader_factory.configuration(), "pi1");
+
+ std::unique_ptr<EventLoop> pi1_event_loop =
+ log_reader_factory.MakeEventLoop("test", pi1);
+ pi1_event_loop->MakeWatcher(
+ "/test", [&ping_count](const examples::Ping &) { ++ping_count; });
+ pi1_event_loop->MakeWatcher(
+ "/test", [&pong_count](const examples::Pong &) { ++pong_count; });
+
+ int sent_messages = 1999;
+ reader.event_loop_factory()->Run();
+ EXPECT_EQ(ping_count, sent_messages);
+ EXPECT_EQ(pong_count, 0);
+ reader.Deregister();
+}
+} // namespace aos::logger::testing
diff --git a/aos/events/logging/log_replayer.cc b/aos/events/logging/log_replayer.cc
index 0f7444a..c91464c 100644
--- a/aos/events/logging/log_replayer.cc
+++ b/aos/events/logging/log_replayer.cc
@@ -57,19 +57,16 @@
const std::vector<aos::logger::LogFile> logfiles =
aos::logger::SortParts(unsorted_logfiles);
+ aos::logger::LogReader config_reader(logfiles);
aos::FlatbufferDetachedBuffer<aos::Configuration> config =
FLAGS_config.empty()
- ? aos::FlatbufferDetachedBuffer<aos::Configuration>::Empty()
+ ? CopyFlatBuffer<aos::Configuration>(config_reader.configuration())
: aos::configuration::ReadConfig(FLAGS_config);
if (FLAGS_plot_timing) {
- aos::logger::LogReader config_reader(logfiles);
-
// Go through the effort to add a ReplayTiming channel to ensure that we
// can capture timing information from the replay.
- const aos::Configuration *raw_config = FLAGS_config.empty()
- ? config_reader.configuration()
- : &config.message();
+ const aos::Configuration *raw_config = &config.message();
aos::ChannelT channel_overrides;
channel_overrides.max_size = 10000;
channel_overrides.frequency = 10000;
@@ -90,8 +87,7 @@
? std::nullopt
: std::make_optional(aos::JsonToFlatbuffer<ReplayConfig>(
aos::util::ReadFileToStringOrDie(FLAGS_replay_config.data())));
-
- std::vector<std::pair<std::string_view, std::string_view>> message_filter;
+ std::vector<std::pair<std::string, std::string>> message_filter;
if (FLAGS_skip_sender_channels && replay_config.has_value()) {
CHECK(replay_config.value().message().has_active_nodes());
std::vector<const Node *> active_nodes;
@@ -112,7 +108,7 @@
ChannelsInLog(logfiles, active_nodes, applications);
for (auto const &channel :
channels.watchers_and_fetchers_without_senders.value()) {
- message_filter.emplace_back(std::make_pair(channel.name, channel.type));
+ message_filter.emplace_back(channel.name, channel.type);
}
}
@@ -120,7 +116,8 @@
logfiles, &config.message(),
message_filter.empty() ? nullptr : &message_filter);
- if (replay_config.has_value()) {
+ if (replay_config.has_value() &&
+ replay_config.value().message().has_remap_channels()) {
for (auto const &remap_channel :
*replay_config.value().message().remap_channels()) {
auto const &channel = remap_channel->channel();
diff --git a/aos/events/logging/multinode_logger_test.cc b/aos/events/logging/multinode_logger_test.cc
index bc1f5b8..f1784bf 100644
--- a/aos/events/logging/multinode_logger_test.cc
+++ b/aos/events/logging/multinode_logger_test.cc
@@ -18,21 +18,14 @@
using aos::testing::ArtifactPath;
using aos::testing::MessageCounter;
-constexpr std::string_view kCombinedConfigSha1(
- "5d73fe35bacaa59d24f8f0c1a806fe10b783b0fcc80809ee30a9db824e82538b");
-constexpr std::string_view kSplitConfigSha1(
- "f25e8f6f90d61f41c41517e652300566228b077e44cd86f1af2af4a9bed31ad4");
-constexpr std::string_view kReloggedSplitConfigSha1(
- "f1fabd629bdf8735c3d81bc791d7a454e8e636951c26cba6426545cbc97f911f");
-
INSTANTIATE_TEST_SUITE_P(
All, MultinodeLoggerTest,
::testing::Combine(
::testing::Values(
ConfigParams{"multinode_pingpong_combined_config.json", true,
- kCombinedConfigSha1, kCombinedConfigSha1},
+ kCombinedConfigSha1(), kCombinedConfigSha1()},
ConfigParams{"multinode_pingpong_split_config.json", false,
- kSplitConfigSha1, kReloggedSplitConfigSha1}),
+ kSplitConfigSha1(), kReloggedSplitConfigSha1()}),
::testing::ValuesIn(SupportedCompressionAlgorithms())));
INSTANTIATE_TEST_SUITE_P(
@@ -40,9 +33,9 @@
::testing::Combine(
::testing::Values(
ConfigParams{"multinode_pingpong_combined_config.json", true,
- kCombinedConfigSha1, kCombinedConfigSha1},
+ kCombinedConfigSha1(), kCombinedConfigSha1()},
ConfigParams{"multinode_pingpong_split_config.json", false,
- kSplitConfigSha1, kReloggedSplitConfigSha1}),
+ kSplitConfigSha1(), kReloggedSplitConfigSha1()}),
::testing::ValuesIn(SupportedCompressionAlgorithms())));
// Tests that we can write and read simple multi-node log files.
diff --git a/aos/events/logging/multinode_logger_test_lib.h b/aos/events/logging/multinode_logger_test_lib.h
index d3754e4..f3f322e 100644
--- a/aos/events/logging/multinode_logger_test_lib.h
+++ b/aos/events/logging/multinode_logger_test_lib.h
@@ -55,6 +55,16 @@
~LoggerState();
};
+constexpr std::string_view kCombinedConfigSha1() {
+ return "5d73fe35bacaa59d24f8f0c1a806fe10b783b0fcc80809ee30a9db824e82538b";
+}
+constexpr std::string_view kSplitConfigSha1() {
+ return "f25e8f6f90d61f41c41517e652300566228b077e44cd86f1af2af4a9bed31ad4";
+}
+constexpr std::string_view kReloggedSplitConfigSha1() {
+ return "f1fabd629bdf8735c3d81bc791d7a454e8e636951c26cba6426545cbc97f911f";
+}
+
LoggerState MakeLoggerState(NodeEventLoopFactory *node,
SimulatedEventLoopFactory *factory,
CompressionParams params,
diff --git a/aos/events/logging/realtime_replay_test.cc b/aos/events/logging/realtime_replay_test.cc
index 888b043..2a5703a 100644
--- a/aos/events/logging/realtime_replay_test.cc
+++ b/aos/events/logging/realtime_replay_test.cc
@@ -150,20 +150,24 @@
shm_event_loop.AddTimer([]() { LOG(INFO) << "Hello, World!"; })
->Setup(shm_event_loop.monotonic_now(), std::chrono::seconds(1));
- auto *const end_timer = shm_event_loop.AddTimer([&shm_event_loop]() {
- LOG(INFO) << "All done, quitting now";
- shm_event_loop.Exit();
- });
-
- // TODO(EricS) reader.OnEnd() is not working as expected when
- // using a channel filter.
- // keep looking for 3 seconds if some message comes, just in case
+ // End timer should not be called in this case, it should automatically quit
+ // the event loop and check for number of fetches messages
+ // This is added to make sure OnEnd is called consistently
+ // When OnEnd is not called after finishing of the log, this will eventually
+ // quit due to the end timer but will report a failure
size_t run_seconds = 3;
+ auto *const end_timer =
+ shm_event_loop.AddTimer([&shm_event_loop, run_seconds]() {
+ shm_event_loop.Exit();
+ FAIL() << "OnEnd wasn't called on log end so quitting after "
+ << run_seconds << " seconds.";
+ });
shm_event_loop.OnRun([&shm_event_loop, end_timer, run_seconds]() {
LOG(INFO) << "Quitting in: " << run_seconds;
end_timer->Setup(shm_event_loop.monotonic_now() +
std::chrono::seconds(run_seconds));
});
+
shm_event_loop.Run();
reader.Deregister();
diff --git a/aos/starter/roborio_irq_config.json b/aos/starter/roborio_irq_config.json
index 7b1d536..874de5a 100644
--- a/aos/starter/roborio_irq_config.json
+++ b/aos/starter/roborio_irq_config.json
@@ -35,7 +35,7 @@
{
"name": "FRC_NetCommDaem",
"scheduler": "SCHEDULER_FIFO",
- "priority": 15
+ "priority": 25
}
]
}
diff --git a/aos/time/BUILD b/aos/time/BUILD
index c0bd99d..04ae38f 100644
--- a/aos/time/BUILD
+++ b/aos/time/BUILD
@@ -8,7 +8,10 @@
],
visibility = ["//visibility:public"],
deps = select({
- "@platforms//os:linux": ["@com_github_google_glog//:glog"],
+ "@platforms//os:linux": [
+ "@com_github_google_glog//:glog",
+ "@com_google_absl//absl/strings",
+ ],
"//conditions:default": ["//motors/core"],
}),
)
diff --git a/aos/time/time.cc b/aos/time/time.cc
index 05510e9..4f39c36 100644
--- a/aos/time/time.cc
+++ b/aos/time/time.cc
@@ -9,6 +9,7 @@
#ifdef __linux__
+#include "absl/strings/numbers.h"
#include "glog/logging.h"
#else // __linux__
@@ -80,6 +81,7 @@
return stream;
}
+#ifdef __linux__
std::optional<monotonic_clock::time_point> monotonic_clock::FromString(
const std::string_view now) {
// This should undo the operator << above.
@@ -97,18 +99,28 @@
bool negative = now[0] == '-';
- std::string sec(
+ std::string_view sec(
now.substr(negative ? 1 : 0, now.size() - (negative ? 14 : 13)));
- std::string nsec(now.substr(now.size() - 12, 9));
+ std::string_view nsec(now.substr(now.size() - 12, 9));
if (!std::all_of(sec.begin(), sec.end(), ::isdigit) ||
!std::all_of(nsec.begin(), nsec.end(), ::isdigit)) {
return std::nullopt;
}
+ std::chrono::seconds::rep seconds_data;
+ if (!absl::SimpleAtoi(sec, &seconds_data)) {
+ return std::nullopt;
+ }
+
+ std::chrono::nanoseconds::rep nanoseconds_data;
+ if (!absl::SimpleAtoi(nsec, &nanoseconds_data)) {
+ return std::nullopt;
+ }
+
return monotonic_clock::time_point(
- std::chrono::seconds((negative ? -1 : 1) * atoll(sec.c_str())) +
- std::chrono::nanoseconds((negative ? -1 : 1) * atoll(nsec.c_str())));
+ std::chrono::seconds((negative ? -1 : 1) * seconds_data) +
+ std::chrono::nanoseconds((negative ? -1 : 1) * nanoseconds_data));
}
std::optional<realtime_clock::time_point> realtime_clock::FromString(
@@ -123,7 +135,7 @@
return std::nullopt;
}
- std::string nsec(now.substr(now.size() - 9, 9));
+ std::string_view nsec(now.substr(now.size() - 9, 9));
if (!std::all_of(nsec.begin(), nsec.end(), ::isdigit)) {
return std::nullopt;
@@ -139,10 +151,16 @@
time_t seconds = mktime(&tm);
+ std::chrono::nanoseconds::rep nanoseconds_data;
+ if (!absl::SimpleAtoi(nsec, &nanoseconds_data)) {
+ return std::nullopt;
+ }
+
return realtime_clock::time_point(
std::chrono::seconds(seconds) +
- std::chrono::nanoseconds(atoll(nsec.c_str())));
+ std::chrono::nanoseconds(nanoseconds_data));
}
+#endif
std::ostream &operator<<(std::ostream &stream,
const aos::realtime_clock::time_point &now) {
diff --git a/aos/time/time.h b/aos/time/time.h
index 52d763f..cd4ecda 100644
--- a/aos/time/time.h
+++ b/aos/time/time.h
@@ -26,8 +26,10 @@
// Converts the time string to a time_point if it is well formatted. This is
// designed to reverse operator <<.
+#ifdef __linux__
static std::optional<monotonic_clock::time_point> FromString(
const std::string_view now);
+#endif
// Returns the epoch (0).
static constexpr monotonic_clock::time_point epoch() {
@@ -56,8 +58,10 @@
// Converts the time string to a time_point if it is well formatted. This is
// designed to reverse operator <<.
+#ifdef __linux__
static std::optional<realtime_clock::time_point> FromString(
const std::string_view now);
+#endif
// Returns the epoch (0).
static constexpr realtime_clock::time_point epoch() {
diff --git a/scouting/www/entry/entry.component.ts b/scouting/www/entry/entry.component.ts
index aef97f7..bc6049f 100644
--- a/scouting/www/entry/entry.component.ts
+++ b/scouting/www/entry/entry.component.ts
@@ -281,12 +281,18 @@
actionOffsets.push(actionOffset);
}
}
+ const teamNumberFb = builder.createString(this.teamNumber.toString());
+ const compLevelFb = builder.createString(this.compLevel);
const actionsVector = SubmitActions.createActionsListVector(
builder,
actionOffsets
);
SubmitActions.startSubmitActions(builder);
+ SubmitActions.addTeamNumber(builder, teamNumberFb);
+ SubmitActions.addMatchNumber(builder, this.matchNumber);
+ SubmitActions.addSetNumber(builder, this.setNumber);
+ SubmitActions.addCompLevel(builder, compLevelFb);
SubmitActions.addActionsList(builder, actionsVector);
builder.finish(SubmitActions.endSubmitActions(builder));
diff --git a/y2023/constants/971.json b/y2023/constants/971.json
index 9f783fa..35a9a1e 100644
--- a/y2023/constants/971.json
+++ b/y2023/constants/971.json
@@ -7,7 +7,7 @@
"calibration": {% include 'y2023/vision/calib_files/calibration_pi-971-2_cam-23-06_ext_2023-03-25.json' %}
},
{
- "calibration": {% include 'y2023/vision/calib_files/calibration_pi-971-3_cam-23-07_ext_2023-02-22.json' %}
+ "calibration": {% include 'y2023/vision/calib_files/calibration_pi-971-3_cam-23-07_ext_2023-03-26.json' %}
},
{
"calibration": {% include 'y2023/vision/calib_files/calibration_pi-971-4_cam-23-08_ext_2023-02-22.json' %}
diff --git a/y2023/control_loops/superstructure/end_effector.cc b/y2023/control_loops/superstructure/end_effector.cc
index 444be0d..b600bbb 100644
--- a/y2023/control_loops/superstructure/end_effector.cc
+++ b/y2023/control_loops/superstructure/end_effector.cc
@@ -109,6 +109,9 @@
if (!beambreak_status && !preloaded_with_cone) {
state_ = EndEffectorState::INTAKING;
}
+ if (game_piece_ != vision::Class::CUBE) {
+ *roller_voltage = 1.3;
+ }
break;
case EndEffectorState::SPITTING:
// If spit requested, spit
diff --git a/y2023/vision/calib_files/calibration_pi-971-3_cam-23-07_ext_2023-03-26.json b/y2023/vision/calib_files/calibration_pi-971-3_cam-23-07_ext_2023-03-26.json
new file mode 100644
index 0000000..64d1c95
--- /dev/null
+++ b/y2023/vision/calib_files/calibration_pi-971-3_cam-23-07_ext_2023-03-26.json
@@ -0,0 +1 @@
+{ "node_name": "pi3", "team_number": 971, "intrinsics": [ 892.627869, 0.0, 629.289978, 0.0, 891.73761, 373.299896, 0.0, 0.0, 1.0 ], "fixed_extrinsics": { "data": [0.514403, -0.183311, -0.837728, -0.0051253, -0.851817, 0.00353495, -0.523827, -0.214622, 0.0989849, 0.983049, -0.154329, 0.62819, 0.0, 0.0, 0.0, 1.0 ] }, "dist_coeffs": [ -0.454901, 0.266778, -0.000316, -0.000469, -0.091357 ], "calibration_timestamp": 1358500316768663953, "camera_id": "23-07" }