Add image logger that only logs when enabled

Looks at joystick readings, starting logging when we get enabled and
stopping it when we're disabled for more than 5 seconds.

Signed-off-by: milind-u <milind.upadhyay@gmail.com>
Change-Id: Icc4e799335ebc97a4d6e9e58b35ca0c5d74dc50a
diff --git a/y2023/BUILD b/y2023/BUILD
index a6fec71..d897c06 100644
--- a/y2023/BUILD
+++ b/y2023/BUILD
@@ -81,6 +81,7 @@
         "//aos/network:web_proxy_main",
         "//aos/starter:irq_affinity",
         "//y2023/vision:camera_reader",
+        "//y2023/vision:image_logger",
         "//aos/events/logging:logger_main",
         "//y2023/vision:game_pieces_detector",
     ],
diff --git a/y2023/vision/BUILD b/y2023/vision/BUILD
index 68ba833..1cdbe36 100644
--- a/y2023/vision/BUILD
+++ b/y2023/vision/BUILD
@@ -247,3 +247,22 @@
     target_compatible_with = ["@platforms//os:linux"],
     visibility = ["//visibility:public"],
 )
+
+cc_binary(
+    name = "image_logger",
+    srcs = [
+        "image_logger.cc",
+    ],
+    target_compatible_with = ["@platforms//os:linux"],
+    visibility = ["//visibility:public"],
+    deps = [
+        "//aos:configuration",
+        "//aos:init",
+        "//aos/events:shm_event_loop",
+        "//aos/events/logging:log_writer",
+        "//aos/logging:log_namer",
+        "//frc971/input:joystick_state_fbs",
+        "@com_github_gflags_gflags//:gflags",
+        "@com_github_google_glog//:glog",
+    ],
+)
diff --git a/y2023/vision/image_logger.cc b/y2023/vision/image_logger.cc
new file mode 100644
index 0000000..b87cec0
--- /dev/null
+++ b/y2023/vision/image_logger.cc
@@ -0,0 +1,95 @@
+#include <sys/resource.h>
+#include <sys/time.h>
+
+#include "aos/configuration.h"
+#include "aos/events/logging/log_writer.h"
+#include "aos/events/shm_event_loop.h"
+#include "aos/init.h"
+#include "aos/logging/log_namer.h"
+#include "frc971/input/joystick_state_generated.h"
+#include "gflags/gflags.h"
+#include "glog/logging.h"
+
+DEFINE_string(config, "aos_config.json", "Config file to use.");
+
+DEFINE_double(rotate_every, 0.0,
+              "If set, rotate the logger after this many seconds");
+DECLARE_int32(flush_size);
+DEFINE_double(disabled_time, 5.0,
+              "Continue logging if disabled for this amount of time or less");
+
+std::unique_ptr<aos::logger::MultiNodeLogNamer> MakeLogNamer(
+    aos::EventLoop *event_loop) {
+  return std::make_unique<aos::logger::MultiNodeLogNamer>(
+      absl::StrCat(aos::logging::GetLogName("fbs_log"), "/"), event_loop);
+}
+
+int main(int argc, char *argv[]) {
+  gflags::SetUsageMessage(
+      "This program provides a simple logger binary that logs all SHMEM data "
+      "directly to a file specified at the command line when the robot is "
+      "enabled and for a bit of time after.");
+  aos::InitGoogle(&argc, &argv);
+
+  aos::FlatbufferDetachedBuffer<aos::Configuration> config =
+      aos::configuration::ReadConfig(FLAGS_config);
+
+  aos::ShmEventLoop event_loop(&config.message());
+
+  bool logging = false;
+  bool enabled = false;
+  aos::monotonic_clock::time_point last_disable_time =
+      event_loop.monotonic_now();
+  aos::monotonic_clock::time_point last_rotation_time =
+      event_loop.monotonic_now();
+  aos::logger::Logger logger(&event_loop);
+
+  if (FLAGS_rotate_every != 0.0) {
+    logger.set_on_logged_period([&] {
+      const auto now = event_loop.monotonic_now();
+      if (logging && now > last_rotation_time + std::chrono::duration<double>(
+                                                    FLAGS_rotate_every)) {
+        logger.Rotate();
+        last_rotation_time = now;
+      }
+    });
+  }
+
+  event_loop.OnRun([]() {
+    errno = 0;
+    setpriority(PRIO_PROCESS, 0, -20);
+    PCHECK(errno == 0) << ": Renicing to -20 failed.";
+  });
+
+  event_loop.MakeWatcher(
+      "/roborio/aos", [&](const aos::JoystickState &joystick_state) {
+        const auto timestamp = event_loop.context().monotonic_event_time;
+        // Store the last time we got disabled
+        if (enabled && !joystick_state.enabled()) {
+          last_disable_time = timestamp;
+        }
+        enabled = joystick_state.enabled();
+
+        if (!logging && enabled) {
+          // Start logging if we just got enabled
+          LOG(INFO) << "Starting logging";
+          logger.StartLogging(MakeLogNamer(&event_loop));
+          logging = true;
+          last_rotation_time = event_loop.monotonic_now();
+        } else if (logging && !enabled &&
+                   (timestamp - last_disable_time) >
+                       std::chrono::duration<double>(FLAGS_disabled_time)) {
+          // Stop logging if we've been disabled for a non-negligible amount of
+          // time
+          LOG(INFO) << "Stopping logging";
+          logger.StopLogging(event_loop.monotonic_now());
+          logging = false;
+        }
+      });
+
+  event_loop.Run();
+
+  LOG(INFO) << "Shutting down";
+
+  return 0;
+}
diff --git a/y2023/y2023_logger.json b/y2023/y2023_logger.json
index f4ac45e..55d201d 100644
--- a/y2023/y2023_logger.json
+++ b/y2023/y2023_logger.json
@@ -446,8 +446,7 @@
     },
     {
       "name": "image_logger",
-      "executable_name": "logger_main",
-      "autostart": false,
+      "executable_name": "image_logger",
       "user": "pi",
       "args": [
         "--logging_folder",
diff --git a/y2023/y2023_pi_template.json b/y2023/y2023_pi_template.json
index baf7031..113e48f 100644
--- a/y2023/y2023_pi_template.json
+++ b/y2023/y2023_pi_template.json
@@ -392,8 +392,7 @@
     },
     {
       "name": "image_logger",
-      "executable_name": "logger_main",
-      "autostart": false,
+      "executable_name": "image_logger",
       "args": [
         "--logging_folder",
         "",
@@ -402,6 +401,7 @@
         "--direct",
         "--flush_size=4194304"
       ],
+      "user": "pi",
       "nodes": [
         "pi{{ NUM }}"
       ]
diff --git a/y2023/y2023_roborio.json b/y2023/y2023_roborio.json
index 03985c0..f3697ac 100644
--- a/y2023/y2023_roborio.json
+++ b/y2023/y2023_roborio.json
@@ -28,6 +28,42 @@
           "timestamp_logger_nodes": [
             "roborio"
           ]
+        },
+        {
+          "name": "pi1",
+          "priority": 5,
+          "time_to_live": 50000000,
+          "timestamp_logger": "LOCAL_AND_REMOTE_LOGGER",
+          "timestamp_logger_nodes": [
+            "roborio"
+          ]
+        },
+        {
+          "name": "pi2",
+          "priority": 5,
+          "time_to_live": 50000000,
+          "timestamp_logger": "LOCAL_AND_REMOTE_LOGGER",
+          "timestamp_logger_nodes": [
+            "roborio"
+          ]
+        },
+        {
+          "name": "pi3",
+          "priority": 5,
+          "time_to_live": 50000000,
+          "timestamp_logger": "LOCAL_AND_REMOTE_LOGGER",
+          "timestamp_logger_nodes": [
+            "roborio"
+          ]
+        },
+        {
+          "name": "pi4",
+          "priority": 5,
+          "time_to_live": 50000000,
+          "timestamp_logger": "LOCAL_AND_REMOTE_LOGGER",
+          "timestamp_logger_nodes": [
+            "roborio"
+          ]
         }
       ]
     },
@@ -50,6 +86,42 @@
       "max_size": 200
     },
     {
+      "name": "/roborio/aos/remote_timestamps/pi1/roborio/aos/aos-JoystickState",
+      "type": "aos.message_bridge.RemoteMessage",
+      "source_node": "roborio",
+      "logger": "NOT_LOGGED",
+      "frequency": 300,
+      "num_senders": 2,
+      "max_size": 200
+    },
+    {
+      "name": "/roborio/aos/remote_timestamps/pi2/roborio/aos/aos-JoystickState",
+      "type": "aos.message_bridge.RemoteMessage",
+      "source_node": "roborio",
+      "logger": "NOT_LOGGED",
+      "frequency": 300,
+      "num_senders": 2,
+      "max_size": 200
+    },
+    {
+      "name": "/roborio/aos/remote_timestamps/pi3/roborio/aos/aos-JoystickState",
+      "type": "aos.message_bridge.RemoteMessage",
+      "source_node": "roborio",
+      "logger": "NOT_LOGGED",
+      "frequency": 300,
+      "num_senders": 2,
+      "max_size": 200
+    },
+    {
+      "name": "/roborio/aos/remote_timestamps/pi4/roborio/aos/aos-JoystickState",
+      "type": "aos.message_bridge.RemoteMessage",
+      "source_node": "roborio",
+      "logger": "NOT_LOGGED",
+      "frequency": 300,
+      "num_senders": 2,
+      "max_size": 200
+    },
+    {
       "name": "/roborio/aos",
       "type": "aos.RobotState",
       "source_node": "roborio",