From 5f6b04a843538623e72a81c7b3b978a1d595eb77 Mon Sep 17 00:00:00 2001 From: rafael Date: Sat, 17 Aug 2024 22:44:48 +0200 Subject: [PATCH] automatically stop a running alarm after 5 minutes --- src/main.rs | 3 ++- src/task/orchestrate.rs | 32 ++++++++++++++++++++++++-------- src/task/state.rs | 8 +++++++- src/task/task_messages.rs | 5 +++++ 4 files changed, 38 insertions(+), 10 deletions(-) diff --git a/src/main.rs b/src/main.rs index 9936c99..4f2a4c4 100644 --- a/src/main.rs +++ b/src/main.rs @@ -7,7 +7,7 @@ use crate::task::alarm_settings::alarm_settings_handler; use crate::task::buttons::{blue_button_handler, green_button_handler, yellow_button_handler}; use crate::task::display::display_handler; -use crate::task::orchestrate::{orchestrator, scheduler}; +use crate::task::orchestrate::{alarm_expirer, orchestrator, scheduler}; use crate::task::power::{usb_power_detector, vsys_voltage_reader}; use crate::task::resources::*; use crate::task::sound::sound_handler; @@ -62,6 +62,7 @@ async fn main(_spawner: Spawner) { if task_config.orchestrator { spawner.spawn(orchestrator()).unwrap(); spawner.spawn(scheduler()).unwrap(); + spawner.spawn(alarm_expirer()).unwrap(); } // Low priority executor: runs in thread mode, using WFE/SEV diff --git a/src/task/orchestrate.rs b/src/task/orchestrate.rs index 6ed8de0..6d14a13 100644 --- a/src/task/orchestrate.rs +++ b/src/task/orchestrate.rs @@ -70,12 +70,13 @@ pub async fn orchestrator() { } Events::Scheduler((hour, minute, second)) => { info!("Scheduler event"); - // we only update the light effects if the alarm is not enabled and the alarm state is None + // update the light effects if the alarm is not enabled and the alarm state is None if state_manager.alarm_state == AlarmState::None && !state_manager.alarm_settings.get_enabled() { LIGHTFX_SIGNAL.signal(Commands::LightFXUpdate((hour, minute, second))); } + // update the display DISPLAY_SIGNAL.signal(Commands::DisplayUpdate); } Events::RtcUpdated => { @@ -116,14 +117,17 @@ pub async fn orchestrator() { state_manager.set_alarm_mode(); DISPLAY_SIGNAL.signal(Commands::DisplayUpdate); LIGHTFX_SIGNAL.signal(Commands::LightFXUpdate((0, 0, 0))); + ALARM_EXPIRER_SIGNAL.signal(Commands::AlarmExpiry); } Events::AlarmStop => { info!("Alarm stop event"); - state_manager.set_normal_mode(); - DISPLAY_SIGNAL.signal(Commands::DisplayUpdate); - LIGHTFX_STOP_SIGNAL.signal(Commands::LightFXUpdate((0, 0, 0))); - LIGHTFX_SIGNAL.signal(Commands::LightFXUpdate((0, 0, 0))); - SOUND_STOP_SIGNAL.signal(Commands::SoundUpdate); + if state_manager.alarm_state.is_active() { + state_manager.set_normal_mode(); + DISPLAY_SIGNAL.signal(Commands::DisplayUpdate); + LIGHTFX_STOP_SIGNAL.signal(Commands::LightFXUpdate((0, 0, 0))); + LIGHTFX_SIGNAL.signal(Commands::LightFXUpdate((0, 0, 0))); + SOUND_STOP_SIGNAL.signal(Commands::SoundUpdate); + }; } Events::SunriseEffectFinished => { info!("Sunrise effect finished event"); @@ -132,8 +136,6 @@ pub async fn orchestrator() { LIGHTFX_SIGNAL.signal(Commands::LightFXUpdate((0, 0, 0))); } } - // log the state of the system - info!("{}", state_manager); drop(state_manager_guard); } } @@ -244,3 +246,17 @@ pub async fn scheduler() { select(downtime_timer, SCHEDULER_WAKE_SIGNAL.wait()).await; } } + +/// This task handles the expiration of the alarm after 5 minutes. +#[embassy_executor::task] +pub async fn alarm_expirer() { + info!("Alarm expirer task started"); + '_mainloop: loop { + // wait for the alarm expiry watcher signal + ALARM_EXPIRER_SIGNAL.wait().await; + // wait for 5 minutes + Timer::after(Duration::from_secs(300)).await; + // send the alarm stop event + EVENT_CHANNEL.sender().send(Events::AlarmStop).await; + } +} diff --git a/src/task/state.rs b/src/task/state.rs index 62a8059..19e76ca 100644 --- a/src/task/state.rs +++ b/src/task/state.rs @@ -346,7 +346,7 @@ impl AlarmSettings { /// The state of the alarm #[derive(PartialEq, Debug, Format, Clone)] pub enum AlarmState { - /// The alarm is not active, the alarm time has not been reached + /// The alarm is not active None, /// The alarm time has been reached, the alarm is active and the sunrise effect is displayed on the neopixel ring. The user /// can stop the alarm by pressing the buttons in the correct sequence. @@ -356,6 +356,12 @@ pub enum AlarmState { Noise, } +impl AlarmState { + pub fn is_active(&self) -> bool { + self != &AlarmState::None + } +} + /// The battery level of the system in steps of 20% from 0 to 100. One additional state is provided for charging. #[derive(PartialEq, Debug, Format, Clone)] pub enum BatteryLevel { diff --git a/src/task/task_messages.rs b/src/task/task_messages.rs index df4e94a..78b7ba9 100644 --- a/src/task/task_messages.rs +++ b/src/task/task_messages.rs @@ -71,6 +71,8 @@ pub enum Commands { SchedulerWakeUp, /// Wake the vsys_voltage_reader task early when awaiting the next iteration VsysWakeUp, + /// Handle the expiry of a running alarm + AlarmExpiry, } /// For the events that we want the orchestrator to react to, all state events are of the type Enum Events. @@ -100,3 +102,6 @@ pub static SOUND_STOP_SIGNAL: Signal = Signal /// Signal for the wake command that we want the orchestrator to send to the vsys_voltage_reader task. pub static VSYS_WAKE_SIGNAL: Signal = Signal::new(); + +/// Signal for the alarm expiry command that we want the orchestrator to send to the alarm expiration task. +pub static ALARM_EXPIRER_SIGNAL: Signal = Signal::new();