Make v4l2_reader use epoll

It no longer needs to be polled in a loop
and sends images directly to the channel

Signed-off-by: Ravago Jones <ravagojones@gmail.com>
Change-Id: I8fc3efc3fd2cd67836294d9dc47d5342cd7d5de4
diff --git a/frc971/vision/BUILD b/frc971/vision/BUILD
index 159c779..4a8d50b 100644
--- a/frc971/vision/BUILD
+++ b/frc971/vision/BUILD
@@ -28,6 +28,7 @@
     visibility = ["//visibility:public"],
     deps = [
         ":vision_fbs",
+        "//aos/events:epoll",
         "//aos/events:event_loop",
         "//aos/scoped:scoped_fd",
         "@com_github_google_glog//:glog",
diff --git a/frc971/vision/v4l2_reader.cc b/frc971/vision/v4l2_reader.cc
index f3640db..e549ae5 100644
--- a/frc971/vision/v4l2_reader.cc
+++ b/frc971/vision/v4l2_reader.cc
@@ -302,9 +302,19 @@
 }
 
 RockchipV4L2Reader::RockchipV4L2Reader(aos::EventLoop *event_loop,
+                                       aos::internal::EPoll *epoll,
                                        const std::string &device_name)
-    : V4L2ReaderBase(event_loop, device_name) {
+    : V4L2ReaderBase(event_loop, device_name), epoll_(epoll) {
   StreamOn();
+  epoll_->OnReadable(fd().get(), [this]() { OnImageReady(); });
+}
+
+void RockchipV4L2Reader::OnImageReady() {
+  if (!ReadLatestImage()) {
+    return;
+  }
+
+  SendLatestImage();
 }
 
 }  // namespace vision
diff --git a/frc971/vision/v4l2_reader.h b/frc971/vision/v4l2_reader.h
index a2b4c25..334ad81 100644
--- a/frc971/vision/v4l2_reader.h
+++ b/frc971/vision/v4l2_reader.h
@@ -5,6 +5,7 @@
 #include <string>
 
 #include "absl/types/span.h"
+#include "aos/events/epoll.h"
 #include "aos/events/event_loop.h"
 #include "aos/ftrace.h"
 #include "aos/scoped/scoped_fd.h"
@@ -62,6 +63,8 @@
   // H.264 frames.
   size_t ImageSize() const { return rows_ * cols_ * 2 /* bytes per pixel */; }
 
+  const aos::ScopedFD &fd() { return fd_; };
+
  private:
   static constexpr int kNumberBuffers = 4;
 
@@ -139,7 +142,13 @@
 // properly configured before this class is constructed.
 class RockchipV4L2Reader : public V4L2ReaderBase {
  public:
-  RockchipV4L2Reader(aos::EventLoop *event_loop, const std::string &device_name);
+  RockchipV4L2Reader(aos::EventLoop *event_loop, aos::internal::EPoll *epoll,
+                     const std::string &device_name);
+
+ private:
+  void OnImageReady();
+
+  aos::internal::EPoll *epoll_;
 };
 
 }  // namespace vision
diff --git a/y2023/vision/camera_reader.cc b/y2023/vision/camera_reader.cc
index 965296f..0e86c32 100644
--- a/y2023/vision/camera_reader.cc
+++ b/y2023/vision/camera_reader.cc
@@ -13,34 +13,6 @@
 
 using namespace frc971::vision;
 
-class CameraReader {
- public:
-  CameraReader(aos::EventLoop *event_loop, V4L2ReaderBase *reader)
-      : event_loop_(event_loop),
-        reader_(reader),
-        read_image_timer_(event_loop->AddTimer([this]() { ReadImage(); })) {
-    event_loop->OnRun(
-        [this]() { read_image_timer_->Setup(event_loop_->monotonic_now()); });
-  }
-
-  void ReadImage() {
-    if (!reader_->ReadLatestImage()) {
-      read_image_timer_->Setup(event_loop_->monotonic_now() +
-                               std::chrono::milliseconds(10));
-      return;
-    }
-    reader_->SendLatestImage();
-
-    read_image_timer_->Setup(event_loop_->monotonic_now());
-  }
-
- private:
-  aos::EventLoop *event_loop_;
-  V4L2ReaderBase *reader_;
-
-  aos::TimerHandler *const read_image_timer_;
-};
-
 void CameraReaderMain() {
   std::optional<MediaDevice> media_device = FindMediaDevice("platform:rkisp1");
 
@@ -105,7 +77,8 @@
 
   event_loop.SetRuntimeRealtimePriority(55);
 
-  RockchipV4L2Reader v4l2_reader(&event_loop, rkisp1_selfpath->device());
+  RockchipV4L2Reader v4l2_reader(&event_loop, event_loop.epoll(),
+                                 rkisp1_selfpath->device());
 
   // TODO(austin): Figure out exposure and stuff.
   /*
@@ -122,8 +95,6 @@
   }
   */
 
-  CameraReader camera_reader(&event_loop, &v4l2_reader);
-
   event_loop.Run();
 }