Merge "Convert joystick_reader over to event loops."
diff --git a/aos/input/BUILD b/aos/input/BUILD
index f27bf98..dd79c5e 100644
--- a/aos/input/BUILD
+++ b/aos/input/BUILD
@@ -1,49 +1,50 @@
-package(default_visibility = ['//visibility:public'])
+package(default_visibility = ["//visibility:public"])
 
 cc_library(
-  name = 'joystick_input',
-  srcs = [
-    'joystick_input.cc',
-  ],
-  hdrs = [
-    'joystick_input.h',
-  ],
-  deps = [
-    '//aos/input:driver_station_data',
-    '//aos/robot_state:robot_state',
-    '//aos/logging',
-    '//aos/logging:queue_logging',
-  ],
+    name = "joystick_input",
+    srcs = [
+        "joystick_input.cc",
+    ],
+    hdrs = [
+        "joystick_input.h",
+    ],
+    deps = [
+        "//aos/events:event-loop",
+        "//aos/input:driver_station_data",
+        "//aos/logging",
+        "//aos/logging:queue_logging",
+        "//aos/robot_state",
+    ],
 )
 
 cc_library(
-  name = 'drivetrain_input',
-  srcs = [
-    'drivetrain_input.cc'
-  ],
-  hdrs = [
-    'drivetrain_input.h',
-  ],
-  deps = [
-    '//aos/input:driver_station_data',
-    '//aos/logging',
-    '//aos/logging:queue_logging',
-    '//aos/robot_state:robot_state',
-    '//aos:math',
-    '//frc971/control_loops/drivetrain:drivetrain_queue',
-    '//frc971/control_loops/drivetrain:drivetrain_config',
-  ],
+    name = "drivetrain_input",
+    srcs = [
+        "drivetrain_input.cc",
+    ],
+    hdrs = [
+        "drivetrain_input.h",
+    ],
+    deps = [
+        "//aos:math",
+        "//aos/input:driver_station_data",
+        "//aos/logging",
+        "//aos/logging:queue_logging",
+        "//aos/robot_state",
+        "//frc971/control_loops/drivetrain:drivetrain_config",
+        "//frc971/control_loops/drivetrain:drivetrain_queue",
+    ],
 )
 
 cc_library(
-  name = 'driver_station_data',
-  srcs = [
-    'driver_station_data.cc',
-  ],
-  hdrs = [
-    'driver_station_data.h',
-  ],
-  deps = [
-    '//aos/robot_state:robot_state',
-  ],
+    name = "driver_station_data",
+    srcs = [
+        "driver_station_data.cc",
+    ],
+    hdrs = [
+        "driver_station_data.h",
+    ],
+    deps = [
+        "//aos/robot_state",
+    ],
 )
diff --git a/aos/input/joystick_input.cc b/aos/input/joystick_input.cc
index 1620fdb..a208f1e 100644
--- a/aos/input/joystick_input.cc
+++ b/aos/input/joystick_input.cc
@@ -14,7 +14,63 @@
 
 void JoystickInput::Quit(int /*signum*/) { run_ = false; }
 
+void JoystickInput::HandleData(const ::aos::JoystickState &joystick_state) {
+  data_.Update(joystick_state);
+
+  mode_ = static_cast<int>(joystick_state.switch_left) |
+          (static_cast<int>(joystick_state.scale_left) << 1);
+
+  {
+    using driver_station::JoystickFeature;
+    using driver_station::ButtonLocation;
+    for (int joystick = 1; joystick <= JoystickFeature::kJoysticks;
+         ++joystick) {
+      for (int button = 1; button <= ButtonLocation::kButtons; ++button) {
+        ButtonLocation location(joystick, button);
+        if (data_.PosEdge(location)) {
+          LOG(INFO, "PosEdge(%d, %d)\n", joystick, button);
+        }
+        if (data_.NegEdge(location)) {
+          LOG(INFO, "NegEdge(%d, %d)\n", joystick, button);
+        }
+      }
+      if (data_.GetPOV(joystick) != data_.GetOldPOV(joystick)) {
+        LOG(INFO, "POV %d %d->%d\n", joystick, data_.GetOldPOV(joystick),
+            data_.GetPOV(joystick));
+      }
+    }
+  }
+  {
+    using driver_station::ControlBit;
+    if (data_.PosEdge(ControlBit::kFmsAttached)) {
+      LOG(INFO, "PosEdge(kFmsAttached)\n");
+    }
+    if (data_.NegEdge(ControlBit::kFmsAttached)) {
+      LOG(INFO, "NegEdge(kFmsAttached)\n");
+    }
+    if (data_.PosEdge(ControlBit::kAutonomous)) {
+      LOG(INFO, "PosEdge(kAutonomous)\n");
+    }
+    if (data_.NegEdge(ControlBit::kAutonomous)) {
+      LOG(INFO, "NegEdge(kAutonomous)\n");
+    }
+    if (data_.PosEdge(ControlBit::kEnabled)) {
+      LOG(INFO, "PosEdge(kEnabled)\n");
+    }
+    if (data_.NegEdge(ControlBit::kEnabled)) {
+      LOG(INFO, "NegEdge(kEnabled)\n");
+    }
+  }
+
+  RunIteration(data_);
+
+  if (!run_) {
+    event_loop_->Exit();
+  }
+}
+
 void JoystickInput::Run() {
+  // TODO(austin): We need a better sigint story for event loops in general.
   run_ = true;
   struct sigaction action;
   action.sa_handler = &JoystickInput::Quit;
@@ -25,56 +81,8 @@
   PCHECK(sigaction(SIGQUIT, &action, nullptr));
   PCHECK(sigaction(SIGINT, &action, nullptr));
 
-  driver_station::Data data;
-  while (run_) {
-    joystick_state.FetchAnother();
+  event_loop_->Run();
 
-    data.Update(*joystick_state);
-
-    {
-      using driver_station::JoystickFeature;
-      using driver_station::ButtonLocation;
-      for (int joystick = 1; joystick <= JoystickFeature::kJoysticks;
-           ++joystick) {
-        for (int button = 1; button <= ButtonLocation::kButtons; ++button) {
-          ButtonLocation location(joystick, button);
-          if (data.PosEdge(location)) {
-            LOG(INFO, "PosEdge(%d, %d)\n", joystick, button);
-          }
-          if (data.NegEdge(location)) {
-            LOG(INFO, "NegEdge(%d, %d)\n", joystick, button);
-          }
-        }
-        if (data.GetPOV(joystick) != data.GetOldPOV(joystick)) {
-          LOG(INFO, "POV %d %d->%d\n", joystick, data.GetOldPOV(joystick),
-              data.GetPOV(joystick));
-        }
-      }
-    }
-    {
-      using driver_station::ControlBit;
-      if (data.PosEdge(ControlBit::kFmsAttached)) {
-        LOG(INFO, "PosEdge(kFmsAttached)\n");
-      }
-      if (data.NegEdge(ControlBit::kFmsAttached)) {
-        LOG(INFO, "NegEdge(kFmsAttached)\n");
-      }
-      if (data.PosEdge(ControlBit::kAutonomous)) {
-        LOG(INFO, "PosEdge(kAutonomous)\n");
-      }
-      if (data.NegEdge(ControlBit::kAutonomous)) {
-        LOG(INFO, "NegEdge(kAutonomous)\n");
-      }
-      if (data.PosEdge(ControlBit::kEnabled)) {
-        LOG(INFO, "PosEdge(kEnabled)\n");
-      }
-      if (data.NegEdge(ControlBit::kEnabled)) {
-        LOG(INFO, "NegEdge(kEnabled)\n");
-      }
-    }
-
-    RunIteration(data);
-  }
   LOG(INFO, "Shutting down\n");
 }
 
diff --git a/aos/input/joystick_input.h b/aos/input/joystick_input.h
index 4b5c5a6..98a89b1 100644
--- a/aos/input/joystick_input.h
+++ b/aos/input/joystick_input.h
@@ -3,6 +3,7 @@
 
 #include <atomic>
 
+#include "aos/events/event-loop.h"
 #include "aos/input/driver_station_data.h"
 
 namespace aos {
@@ -15,15 +16,34 @@
 // (at INFO) button edges.
 class JoystickInput {
  public:
+  explicit JoystickInput(::aos::EventLoop *event_loop)
+      : event_loop_(event_loop) {
+    event_loop_->MakeWatcher(
+        ".aos.joystick_state",
+        [this](const ::aos::JoystickState &joystick_state) {
+          this->HandleData(joystick_state);
+        });
+  }
+
   void Run();
 
+ protected:
+  int mode() const { return mode_; }
+
  private:
+  void HandleData(const ::aos::JoystickState &joystick_state);
+
   // Subclasses should do whatever they want with data here.
   virtual void RunIteration(const driver_station::Data &data) = 0;
 
   static void Quit(int /*signum*/);
 
   static ::std::atomic<bool> run_;
+
+  EventLoop *event_loop_;
+  driver_station::Data data_;
+
+  int mode_;
 };
 
 // Class which will proxy joystick information from UDP packets to the queues.
diff --git a/y2012/joystick_reader.cc b/y2012/joystick_reader.cc
index e48eaf6..46b20f6 100644
--- a/y2012/joystick_reader.cc
+++ b/y2012/joystick_reader.cc
@@ -3,12 +3,13 @@
 #include <unistd.h>
 #include <math.h>
 
+#include "aos/actions/actions.h"
+#include "aos/events/shm-event-loop.h"
 #include "aos/init.h"
-#include "aos/input/joystick_input.h"
 #include "aos/input/driver_station_data.h"
+#include "aos/input/joystick_input.h"
 #include "aos/logging/logging.h"
 #include "aos/time/time.h"
-#include "aos/actions/actions.h"
 
 #include "frc971/control_loops/drivetrain/drivetrain.q.h"
 #include "y2012/control_loops/accessories/accessories.q.h"
@@ -80,8 +81,8 @@
 
 class Reader : public ::aos::input::JoystickInput {
  public:
-  Reader()
-      : is_high_gear_(false) {}
+  Reader(::aos::EventLoop *event_loop)
+      : ::aos::input::JoystickInput(event_loop), is_high_gear_(false) {}
 
   void RunIteration(const ::aos::input::driver_station::Data &data) override {
     if (!data.GetControlBit(ControlBit::kAutonomous)) {
@@ -144,7 +145,8 @@
 
 int main() {
   ::aos::Init(-1);
-  ::y2012::input::joysticks::Reader reader;
+  ::aos::ShmEventLoop event_loop;
+  ::y2012::input::joysticks::Reader reader(&event_loop);
   reader.Run();
   ::aos::Cleanup();
 }
diff --git a/y2014/joystick_reader.cc b/y2014/joystick_reader.cc
index 72c76ef..cc29bcb 100644
--- a/y2014/joystick_reader.cc
+++ b/y2014/joystick_reader.cc
@@ -155,8 +155,9 @@
 
 class Reader : public ::aos::input::JoystickInput {
  public:
-  Reader()
-      : is_high_gear_(false),
+  Reader(::aos::EventLoop *event_loop)
+      : ::aos::input::JoystickInput(event_loop),
+        is_high_gear_(false),
         shot_power_(80.0),
         goal_angle_(0.0),
         separation_angle_(kGrabSeparation),
@@ -523,7 +524,8 @@
 
 int main() {
   ::aos::Init(-1);
-  ::y2014::input::joysticks::Reader reader;
+  ::aos::ShmEventLoop event_loop;
+  ::y2014::input::joysticks::Reader reader(&event_loop);
   reader.Run();
   ::aos::Cleanup();
 }
diff --git a/y2014_bot3/joystick_reader.cc b/y2014_bot3/joystick_reader.cc
index 70eff54..e2acb8b 100644
--- a/y2014_bot3/joystick_reader.cc
+++ b/y2014_bot3/joystick_reader.cc
@@ -48,7 +48,8 @@
 
 class Reader : public ::aos::input::JoystickInput {
  public:
-  Reader() {
+  Reader(::aos::EventLoop *event_loop)
+      : ::aos::input::JoystickInput(event_loop) {
     drivetrain_input_reader_ = DrivetrainInputReader::Make(
         DrivetrainInputReader::InputType::kSteeringWheel,
         ::y2014_bot3::control_loops::drivetrain::GetDrivetrainConfig());
@@ -134,7 +135,8 @@
 
 int main() {
   ::aos::Init(-1);
-  ::y2014_bot3::input::joysticks::Reader reader;
+  ::aos::ShmEventLoop event_loop;
+  ::y2014_bot3::input::joysticks::Reader reader(&event_loop);
   reader.Run();
   ::aos::Cleanup();
 }
diff --git a/y2016/joystick_reader.cc b/y2016/joystick_reader.cc
index 8f99e4c..6887a53 100644
--- a/y2016/joystick_reader.cc
+++ b/y2016/joystick_reader.cc
@@ -71,8 +71,9 @@
 
 class Reader : public ::aos::input::JoystickInput {
  public:
-  Reader()
-      : is_high_gear_(true),
+  Reader(::aos::EventLoop *event_loop)
+      : ::aos::input::JoystickInput(event_loop),
+        is_high_gear_(true),
         intake_goal_(0.0),
         shoulder_goal_(M_PI / 2.0),
         wrist_goal_(0.0),
@@ -498,7 +499,8 @@
 
 int main() {
   ::aos::Init(-1);
-  ::y2016::input::joysticks::Reader reader;
+  ::aos::ShmEventLoop event_loop;
+  ::y2016::input::joysticks::Reader reader(&event_loop);
   reader.Run();
   ::aos::Cleanup();
 }
diff --git a/y2017/joystick_reader.cc b/y2017/joystick_reader.cc
index c7869b4..d9bca58 100644
--- a/y2017/joystick_reader.cc
+++ b/y2017/joystick_reader.cc
@@ -53,7 +53,8 @@
 
 class Reader : public ::aos::input::JoystickInput {
  public:
-  Reader() {
+  Reader(::aos::EventLoop *event_loop)
+      : ::aos::input::JoystickInput(event_loop) {
     drivetrain_input_reader_ = DrivetrainInputReader::Make(
         DrivetrainInputReader::InputType::kSteeringWheel,
         ::y2017::control_loops::drivetrain::GetDrivetrainConfig());
@@ -324,7 +325,8 @@
 
 int main() {
   ::aos::Init(-1);
-  ::y2017::input::joysticks::Reader reader;
+  ::aos::ShmEventLoop event_loop;
+  ::y2017::input::joysticks::Reader reader(&event_loop);
   reader.Run();
   ::aos::Cleanup();
 }
diff --git a/y2017_bot3/joystick_reader.cc b/y2017_bot3/joystick_reader.cc
index 811617e..c3cc9cb 100644
--- a/y2017_bot3/joystick_reader.cc
+++ b/y2017_bot3/joystick_reader.cc
@@ -39,7 +39,8 @@
 
 class Reader : public ::aos::input::JoystickInput {
  public:
-  Reader() {
+  Reader(::aos::EventLoop *event_loop)
+      : ::aos::input::JoystickInput(event_loop) {
     // Setting driver station type to Steering Wheel
     drivetrain_input_reader_ = DrivetrainInputReader::Make(
         DrivetrainInputReader::InputType::kSteeringWheel,
@@ -149,7 +150,8 @@
 
 int main() {
   ::aos::Init(-1);
-  ::y2017_bot3::input::joysticks::Reader reader;
+  ::aos::ShmEventLoop event_loop;
+  ::y2017_bot3::input::joysticks::Reader reader(&event_loop);
   reader.Run();
   ::aos::Cleanup();
 }
diff --git a/y2018/joystick_reader.cc b/y2018/joystick_reader.cc
index 41efc00..41b4d14 100644
--- a/y2018/joystick_reader.cc
+++ b/y2018/joystick_reader.cc
@@ -87,7 +87,8 @@
 
 class Reader : public ::aos::input::JoystickInput {
  public:
-  Reader() {
+  Reader(::aos::EventLoop *event_loop)
+      : ::aos::input::JoystickInput(event_loop) {
     const uint16_t team = ::aos::network::GetTeamNumber();
 
     drivetrain_input_reader_ = DrivetrainInputReader::Make(
@@ -370,9 +371,8 @@
       LOG(WARNING, "no auto mode values\n");
       params.mode = 0;
     }
-    // TODO(austin): use the mode later if we care.  We don't care right now.
-    params.mode = static_cast<int>(::aos::joystick_state->switch_left) |
-                  (static_cast<int>(::aos::joystick_state->scale_left) << 1);
+    // Low bit is switch, high bit is scale.  1 means left, 0 means right.
+    params.mode = mode();
     action_queue_.EnqueueAction(
         ::frc971::autonomous::MakeAutonomousAction(params));
   }
@@ -408,7 +408,8 @@
 
 int main() {
   ::aos::Init(-1);
-  ::y2018::input::joysticks::Reader reader;
+  ::aos::ShmEventLoop event_loop;
+  ::y2018::input::joysticks::Reader reader(&event_loop);
   reader.Run();
   ::aos::Cleanup();
 }