From b39f3f3ada9ca12906377a75387e41665316875e Mon Sep 17 00:00:00 2001
From: Samuel Tardieu <sam@rfc1149.net>
Date: Wed, 17 Jul 2024 00:47:56 +0200
Subject: [PATCH] Separate watchdog code into a module

---
 controller/src/logic/mod.rs      | 63 +++-----------------------------
 controller/src/logic/watchdog.rs | 61 +++++++++++++++++++++++++++++++
 2 files changed, 67 insertions(+), 57 deletions(-)
 create mode 100644 controller/src/logic/watchdog.rs

diff --git a/controller/src/logic/mod.rs b/controller/src/logic/mod.rs
index 00ee9fc..3ed0269 100644
--- a/controller/src/logic/mod.rs
+++ b/controller/src/logic/mod.rs
@@ -1,20 +1,12 @@
 use crate::{encoders::Encoders, tb6612fng::Tb6612fng};
-use core::sync::atomic::{AtomicU8, Ordering};
 use embassy_executor::Spawner;
-use embassy_stm32::{
-    pac::{self, wwdg::vals::Wdgtb},
-    peripherals::WWDG,
-    time::hz,
-};
-use embassy_sync::{blocking_mutex::raw::CriticalSectionRawMutex, signal::Signal};
-use embassy_time::{Duration, Instant, Ticker};
+use embassy_stm32::{peripherals::WWDG, time::hz};
 use futures::FutureExt;
 use heapless::Deque;
 use i2c2_target::{I2C2, MESSAGE_SIZE};
 
 mod motor_control;
-
-static WATCHDOG_TICKS: AtomicU8 = AtomicU8::new(5);
+mod watchdog;
 
 struct State {
     i2c: I2C2,
@@ -32,28 +24,6 @@ impl State {
 
 static mut STATE: Option<State> = None;
 
-fn wwdg_configure() {
-    // Enable WWDG clock
-    pac::RCC.apb1enr().modify(|w| w.set_wwdgen(true));
-    // With PCLK1 at 36MHz, 63 as a timeout value with wdgtb at /8
-    // means ~58ms.  Comparing with a value of 45 means that at
-    // least ~42ms must have passed before the watchdog can be
-    // petted, so we have 8ms on each side.
-    pac::WWDG.cfr().write(|w| {
-        w.set_wdgtb(Wdgtb::DIV8);
-        w.set_w((1 << 6) | 31);
-    });
-    wwdg_pet();
-}
-
-fn wwdg_pet() {
-    // Reset watchdog and start it if not started yet
-    pac::WWDG.cr().write(|w| {
-        w.set_t((1 << 6) | 63);
-        w.set_wdga(true);
-    });
-}
-
 #[allow(clippy::needless_pass_by_value, clippy::used_underscore_binding)] // Clippy bug
 pub fn start_i2c_target(
     spawner: Spawner,
@@ -66,36 +36,15 @@ pub fn start_i2c_target(
         STATE = Some(State::new(i2c2, encoders));
         STATE.as_mut().unwrap().i2c.start(&i2c_callback);
     }
-    spawner.spawn(watchdog()).unwrap();
+    spawner.spawn(watchdog::watchdog()).unwrap();
     spawner.spawn(motor_control::motor_control(motors)).unwrap();
 }
 
-static WATCHDOG_PING: Signal<CriticalSectionRawMutex, Instant> = Signal::new();
-
-#[embassy_executor::task]
-async fn watchdog() {
-    wwdg_configure();
-    let mut ticker = Ticker::every(Duration::from_millis(50));
-    let mut watchdog_expiration: Instant = Instant::now();
-    loop {
-        ticker.next().await;
-        wwdg_pet();
-        if let Some(ping) = WATCHDOG_PING.try_take() {
-            watchdog_expiration = ping
-                + Duration::from_millis(100 * u64::from(WATCHDOG_TICKS.load(Ordering::Relaxed)));
-        }
-        if motor_control::is_moving() && Instant::now() >= watchdog_expiration {
-            defmt::debug!("stopping motors after watchdog has expired");
-            motor_control::standby().await;
-        }
-    }
-}
-
 fn i2c_callback(command: &[u8], response: &mut Deque<u8, MESSAGE_SIZE>) {
     #[allow(static_mut_refs)]
     let state = unsafe { STATE.as_mut().unwrap() };
     if process_command(state, command, response) {
-        WATCHDOG_PING.signal(Instant::now());
+        watchdog::ping();
     } else {
         // If this does not succeed, this will reset due to
         // a lack of petting the window watchdog.
@@ -180,7 +129,7 @@ fn process_command(
         }
         &[CMD_MOTOR_SHUTDOWN_TIMEOUT, ticks] => {
             if (1..=100).contains(&ticks) {
-                WATCHDOG_TICKS.store(ticks, Ordering::Relaxed);
+                watchdog::set_shutdown_timeout(ticks);
             } else {
                 defmt::warn!("ticks out of range: {}", ticks);
                 return false;
@@ -188,7 +137,7 @@ fn process_command(
         }
         [CMD_MOTOR_SHUTDOWN_TIMEOUT] => {
             response
-                .push_back(WATCHDOG_TICKS.load(Ordering::Relaxed))
+                .push_back(watchdog::get_shutdown_timeout())
                 .unwrap();
         }
         [CMD_ENCODER_TICKS] => {
diff --git a/controller/src/logic/watchdog.rs b/controller/src/logic/watchdog.rs
new file mode 100644
index 0000000..a31917e
--- /dev/null
+++ b/controller/src/logic/watchdog.rs
@@ -0,0 +1,61 @@
+use super::motor_control;
+use core::sync::atomic::{AtomicU8, Ordering};
+use embassy_stm32::pac::{self, wwdg::vals::Wdgtb};
+use embassy_sync::{blocking_mutex::raw::CriticalSectionRawMutex, signal::Signal};
+use embassy_time::{Duration, Instant, Ticker};
+
+static WATCHDOG_PING: Signal<CriticalSectionRawMutex, Instant> = Signal::new();
+static WATCHDOG_TICKS: AtomicU8 = AtomicU8::new(5);
+
+pub fn ping() {
+    WATCHDOG_PING.signal(Instant::now());
+}
+
+pub fn set_shutdown_timeout(ticks: u8) {
+    WATCHDOG_TICKS.store(ticks, Ordering::Relaxed);
+}
+
+pub fn get_shutdown_timeout() -> u8 {
+    WATCHDOG_TICKS.load(Ordering::Relaxed)
+}
+
+#[embassy_executor::task]
+pub async fn watchdog() {
+    wwdg_configure();
+    let mut ticker = Ticker::every(Duration::from_millis(50));
+    let mut watchdog_expiration: Instant = Instant::now();
+    loop {
+        ticker.next().await;
+        wwdg_pet();
+        if let Some(ping) = WATCHDOG_PING.try_take() {
+            watchdog_expiration = ping
+                + Duration::from_millis(100 * u64::from(WATCHDOG_TICKS.load(Ordering::Relaxed)));
+        }
+        if motor_control::is_moving() && Instant::now() >= watchdog_expiration {
+            defmt::debug!("stopping motors after watchdog has expired");
+            motor_control::standby().await;
+        }
+    }
+}
+
+fn wwdg_configure() {
+    // Enable WWDG clock
+    pac::RCC.apb1enr().modify(|w| w.set_wwdgen(true));
+    // With PCLK1 at 36MHz, 63 as a timeout value with wdgtb at /8
+    // means ~58ms.  Comparing with a value of 45 means that at
+    // least ~42ms must have passed before the watchdog can be
+    // petted, so we have 8ms on each side.
+    pac::WWDG.cfr().write(|w| {
+        w.set_wdgtb(Wdgtb::DIV8);
+        w.set_w((1 << 6) | 31);
+    });
+    wwdg_pet();
+}
+
+fn wwdg_pet() {
+    // Reset watchdog and start it if not started yet
+    pac::WWDG.cr().write(|w| {
+        w.set_t((1 << 6) | 63);
+        w.set_wdga(true);
+    });
+}
-- 
GitLab