pw_touchscreen, snake: Reduce event rate

Reduce the Snake game frame rate and modify DirectionalTouchButtons
interface to allow customizing the frame at which touch events are
processed.

Bug: 306403638
Change-Id: Ibdc7635cbc9f30a722efae775ff2e5a91a36aed7
Reviewed-on: https://pigweed-review.googlesource.com/c/pigweed/kudzu/+/177970
Commit-Queue: Carlos Chinchilla <cachinchilla@google.com>
Reviewed-by: Erik Gilling <konkers@google.com>
Pigweed-Auto-Submit: Carlos Chinchilla <cachinchilla@google.com>
diff --git a/applications/snake/main.cc b/applications/snake/main.cc
index 1649f42..47197f6 100644
--- a/applications/snake/main.cc
+++ b/applications/snake/main.cc
@@ -28,12 +28,39 @@
 #include "pw_system/target_hooks.h"
 #include "pw_system/work_queue.h"
 #include "pw_thread/detached_thread.h"
+#include "pw_thread/thread_core.h"
 #include "pw_touchscreen/buttons.h"
 #include "pw_touchscreen/touchscreen.h"
 #include "snake/game.h"
 
 namespace {
 
+constexpr uint32_t kFramesPerSecond = 16;
+constexpr uint32_t kWaitMillis = 1000 / kFramesPerSecond;
+
+class PollingTouchButtonsThread : public pw::thread::ThreadCore {
+ public:
+  PollingTouchButtonsThread(
+      pw::touchscreen::Touchscreen& touchscreen,
+      pw::touchscreen::DirectionButtonListener& button_listener,
+      int32_t display_width,
+      int32_t display_height)
+      : touchscreen_(touchscreen),
+        buttons_(button_listener, display_width, display_height) {}
+
+  void Run() override {
+    while (true) {
+      pw::touchscreen::TouchEvent touch_event = touchscreen_.GetTouchPoint();
+      buttons_.OnTouchEvent(touch_event);
+      pw::spin_delay::WaitMillis(kWaitMillis);
+    }
+  }
+
+ private:
+  pw::touchscreen::Touchscreen& touchscreen_;
+  pw::touchscreen::DirectionTouchButtons buttons_;
+};
+
 void MainTask(void*) {
   pw::board_led::Init();
   PW_CHECK_OK(Common::Init());
@@ -54,8 +81,8 @@
   display.ReleaseFramebuffer(std::move(framebuffer));
 
   snake::Game game(display_width, display_height);
-  pw::touchscreen::DirectionTouchButtonsThread touch_buttons_thread{
-      game, Common::GetTouchscreen(), display_width, display_height};
+  PollingTouchButtonsThread touch_buttons_thread{
+      Common::GetTouchscreen(), game, display_width, display_height};
   pw::thread::DetachedThread(Common::TouchscreenThreadOptions(),
                              touch_buttons_thread);
 
@@ -63,8 +90,8 @@
 
   // Display and app loop.
   kudzu::FrameCounter frame_counter = kudzu::FrameCounter();
-  uint32_t frame_start_millis = pw::spin_delay::Millis();
-  while (1) {
+  uint32_t last_report_time = pw::spin_delay::Millis();
+  while (true) {
     frame_counter.StartFrame();
 
     // Get frame buffer.
@@ -84,12 +111,14 @@
     display.ReleaseFramebuffer(std::move(framebuffer));
     frame_counter.EndFlush();
 
-    // Every second make a log message.
     frame_counter.EndFrame();
 
-    if (pw::spin_delay::Millis() > frame_start_millis + 10000) {
+    pw::spin_delay::WaitMillis(kWaitMillis);
+
+    // Periodically make a log message.
+    if (pw::spin_delay::Millis() > last_report_time + 10000) {
       Common::EndOfFrameCallback();
-      frame_start_millis = pw::spin_delay::Millis();
+      last_report_time = pw::spin_delay::Millis();
     }
   }
 }
diff --git a/lib/pw_touchscreen/BUILD.gn b/lib/pw_touchscreen/BUILD.gn
index d59fdd5..90b199f 100644
--- a/lib/pw_touchscreen/BUILD.gn
+++ b/lib/pw_touchscreen/BUILD.gn
@@ -35,7 +35,6 @@
   sources = [ "buttons.cc" ]
   public_deps = [
     ":pw_touchscreen",
-    "$dir_pw_thread:thread_core",
     "$pw_dir_third_party_32blit:32blit",
   ]
   deps = [ "$dir_pw_log" ]
diff --git a/lib/pw_touchscreen/buttons.cc b/lib/pw_touchscreen/buttons.cc
index ea74a5d..1fe621e 100644
--- a/lib/pw_touchscreen/buttons.cc
+++ b/lib/pw_touchscreen/buttons.cc
@@ -26,13 +26,11 @@
 
 }  // namespace
 
-DirectionTouchButtonsThread::DirectionTouchButtonsThread(
+DirectionTouchButtons::DirectionTouchButtons(
     DirectionButtonListener& button_listener,
-    Touchscreen& touchscreen,
     int32_t display_width,
     int32_t display_height)
     : button_listener_(button_listener),
-      touchscreen_(touchscreen),
       up_button_(display_width / 2, display_height / 4, display_width / 4, 0),
       down_button_(display_width / 2,
                    display_height / 4,
@@ -45,32 +43,26 @@
                     display_width - display_width / 4,
                     display_height / 4) {}
 
-void DirectionTouchButtonsThread::Run() {
-  while (true) {
-    // TODO(b/306403638): Make the polling configurable and set it at a low
-    // rate no higher than the frame rate.
-    TouchEvent touch_event = touchscreen_.GetTouchPoint();
-    if (touch_event.type == TouchEventType::Start ||
-        touch_event.type == TouchEventType::Stop) {
-      const bool pressed = touch_event.type == TouchEventType::Start;
-      PW_LOG_DEBUG(
-          "Touch at: %d, %d", touch_event.point.x, touch_event.point.y);
-      if (up_button_.contains(touch_event.point.x, touch_event.point.y)) {
-        PW_LOG_DEBUG("Up button %s", pressed ? kPressedText : kReleasedText);
-        button_listener_.OnButtonUp(pressed);
-      } else if (down_button_.contains(touch_event.point.x,
-                                       touch_event.point.y)) {
-        PW_LOG_DEBUG("Down button %s", pressed ? kPressedText : kReleasedText);
-        button_listener_.OnButtonDown(pressed);
-      } else if (left_button_.contains(touch_event.point.x,
-                                       touch_event.point.y)) {
-        PW_LOG_DEBUG("Left button %s", pressed ? kPressedText : kReleasedText);
-        button_listener_.OnButtonLeft(pressed);
-      } else if (right_button_.contains(touch_event.point.x,
-                                        touch_event.point.y)) {
-        PW_LOG_DEBUG("Right button %s", pressed ? kPressedText : kReleasedText);
-        button_listener_.OnButtonRight(pressed);
-      }
+void DirectionTouchButtons::OnTouchEvent(const TouchEvent& touch_event) {
+  if (touch_event.type == TouchEventType::Start ||
+      touch_event.type == TouchEventType::Stop) {
+    const bool pressed = touch_event.type == TouchEventType::Start;
+    PW_LOG_DEBUG("Touch at: %d, %d", touch_event.point.x, touch_event.point.y);
+    if (up_button_.contains(touch_event.point.x, touch_event.point.y)) {
+      PW_LOG_DEBUG("Up button %s", pressed ? kPressedText : kReleasedText);
+      button_listener_.OnButtonUp(pressed);
+    } else if (down_button_.contains(touch_event.point.x,
+                                     touch_event.point.y)) {
+      PW_LOG_DEBUG("Down button %s", pressed ? kPressedText : kReleasedText);
+      button_listener_.OnButtonDown(pressed);
+    } else if (left_button_.contains(touch_event.point.x,
+                                     touch_event.point.y)) {
+      PW_LOG_DEBUG("Left button %s", pressed ? kPressedText : kReleasedText);
+      button_listener_.OnButtonLeft(pressed);
+    } else if (right_button_.contains(touch_event.point.x,
+                                      touch_event.point.y)) {
+      PW_LOG_DEBUG("Right button %s", pressed ? kPressedText : kReleasedText);
+      button_listener_.OnButtonRight(pressed);
     }
   }
 }
diff --git a/lib/pw_touchscreen/public/pw_touchscreen/buttons.h b/lib/pw_touchscreen/public/pw_touchscreen/buttons.h
index f417a73..c4f995b 100644
--- a/lib/pw_touchscreen/public/pw_touchscreen/buttons.h
+++ b/lib/pw_touchscreen/public/pw_touchscreen/buttons.h
@@ -15,7 +15,6 @@
 
 #include <cstdint>
 
-#include "pw_thread/thread_core.h"
 #include "pw_touchscreen/touchscreen.h"
 #include "types/point.hpp"
 #include "types/rect.hpp"
@@ -53,21 +52,17 @@
 };
 
 // Creates a set of direction buttons (up, down, left, and right) on the given
-// touch screen.
-// TODO(b/306403638): Make the polling rate configurable and poll at a lower
-// rate.
-class DirectionTouchButtonsThread : public pw::thread::ThreadCore {
+// touch screen and redirects touch events to button listener when applicable.
+class DirectionTouchButtons {
  public:
-  DirectionTouchButtonsThread(DirectionButtonListener& button_listener,
-                              Touchscreen& touchscreen,
-                              int32_t display_width,
-                              int32_t display_height);
+  DirectionTouchButtons(DirectionButtonListener& button_listener,
+                        int32_t display_width,
+                        int32_t display_height);
 
-  void Run() override;
+  void OnTouchEvent(const TouchEvent& touch_event);
 
  private:
   DirectionButtonListener& button_listener_;
-  Touchscreen& touchscreen_;
   TouchButton up_button_;
   TouchButton down_button_;
   TouchButton left_button_;