Skip to content

Commit

Permalink
26-pattern-to-orchestrate-the-tasks-throughout-the-application (#32)
Browse files Browse the repository at this point in the history
  • Loading branch information
1-rafael-1 authored Jul 24, 2024
1 parent e2be835 commit de3fb3f
Show file tree
Hide file tree
Showing 3 changed files with 83 additions and 67 deletions.
51 changes: 29 additions & 22 deletions src/task/buttons.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use crate::task::resources::{BlueButtonResources, GreenButtonResources, YellowButtonResources};
use crate::task::state::{BLUE_BTN_CHANNEL, GREEN_BTN_CHANNEL, YELLOW_BTN_CHANNEL};
use crate::task::state::{Events, EVENT_CHANNEL};
use defmt::info;
use embassy_executor::Spawner;
use embassy_rp::gpio::{self, Input, Level};
Expand All @@ -14,20 +14,20 @@ use {defmt_rtt as _, panic_probe as _};
pub struct ButtonManager<'a> {
input: Input<'a>,
debounce_duration: Duration,
id: &'a str,
sender: Sender<'a, CriticalSectionRawMutex, u8, 1>,
events: Events,
sender: Sender<'a, CriticalSectionRawMutex, Events, 10>,
}

impl<'a> ButtonManager<'a> {
pub fn new(
input: Input<'a>,
id: &'a str,
sender: Sender<'a, CriticalSectionRawMutex, u8, 1>,
events: Events,
sender: Sender<'a, CriticalSectionRawMutex, Events, 10>,
) -> Self {
Self {
input,
debounce_duration: Duration::from_millis(100), // hardcoding, all buttons have the same debounce duration
id,
events,
sender,
}
}
Expand All @@ -37,39 +37,46 @@ impl<'a> ButtonManager<'a> {
// button pressed
let _debounce = self.debounce().await;
let start = Instant::now();
info!("{} Press", self.id);
info!("{} Press", self.events);

// send button press to channel -> this is a ToDo, we will want to do this reacting to the length of the press somehow
// maybe we need a pipe instead of a channel to stream the button presses to the orchestrator
self.sender.send(1).await;
let presses: u32 = 0;
let event = match self.events {
Events::BlueBtn(0) => Events::BlueBtn(presses + 1),
Events::GreenBtn(0) => Events::GreenBtn(presses + 1),
Events::YellowBtn(0) => Events::YellowBtn(presses + 1),
_ => panic!("Invalid Event"),
};
self.sender.send(event).await;

match with_deadline(start + Duration::from_secs(1), self.debounce()).await {
// Button Released < 1s
Ok(_) => {
info!("{} pressed for: {}ms", self.id, start.elapsed().as_millis());
info!("pressed for: {}ms", start.elapsed().as_millis());
continue;
}
// button held for > 1s
Err(_) => {
info!("{} Held", self.id);
info!("Held");
}
}

match with_deadline(start + Duration::from_secs(5), self.debounce()).await {
// Button released <5s
Ok(_) => {
info!("{} pressed for: {}ms", self.id, start.elapsed().as_millis());
info!("pressed for: {}ms", start.elapsed().as_millis());
continue;
}
// button held for > >5s
Err(_) => {
info!("{} Long Held", self.id);
info!("Long Held");
}
}

// wait for button release before handling another press
self.debounce().await;
info!("{} pressed for: {}ms", self.id, start.elapsed().as_millis());
info!("pressed for: {}ms", start.elapsed().as_millis());
}
}

Expand All @@ -92,26 +99,26 @@ impl<'a> ButtonManager<'a> {
#[embassy_executor::task]
pub async fn green_button(_spawner: Spawner, r: GreenButtonResources) {
let input = gpio::Input::new(r.button_pin, gpio::Pull::Up);
let sender = GREEN_BTN_CHANNEL.sender();
let mut btn = ButtonManager::new(input, "green_button", sender);
info!("{} task started", btn.id);
let sender = EVENT_CHANNEL.sender();
let mut btn = ButtonManager::new(input, Events::GreenBtn(0), sender);
info!("{} task started", btn.events);
btn.handle_button_press().await;
}

#[embassy_executor::task]
pub async fn blue_button(_spawner: Spawner, r: BlueButtonResources) {
let input = gpio::Input::new(r.button_pin, gpio::Pull::Up);
let sender = BLUE_BTN_CHANNEL.sender();
let mut btn = ButtonManager::new(input, "blue_button", sender);
info!("{} task started", btn.id);
let sender = EVENT_CHANNEL.sender();
let mut btn = ButtonManager::new(input, Events::BlueBtn(0), sender);
info!("{} task started", btn.events);
btn.handle_button_press().await;
}

#[embassy_executor::task]
pub async fn yellow_button(_spawner: Spawner, r: YellowButtonResources) {
let input = gpio::Input::new(r.button_pin, gpio::Pull::Up);
let sender = YELLOW_BTN_CHANNEL.sender();
let mut btn = ButtonManager::new(input, "yellow_button", sender);
info!("{} task started", btn.id);
let sender = EVENT_CHANNEL.sender();
let mut btn = ButtonManager::new(input, Events::YellowBtn(0), sender);
info!("{} task started", btn.events);
btn.handle_button_press().await;
}
10 changes: 6 additions & 4 deletions src/task/power.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
//! Detremine the supply voltage of the system.
use crate::task::resources::{Irqs, UsbPowerResources};
use crate::task::state::VBUS_CHANNEL;
use crate::task::state::{Events, EVENT_CHANNEL};
use crate::VsysResources;
use defmt::*;
use embassy_executor::Spawner;
Expand All @@ -20,10 +20,10 @@ use embassy_time::{Duration, Timer};
pub async fn usb_power(_spawner: Spawner, r: UsbPowerResources) {
info!("usb_power task started");
let mut vbus_in = Input::new(r.vbus_pin, Pull::None);
let sender = VBUS_CHANNEL.sender();
let sender = EVENT_CHANNEL.sender();
loop {
info!("usb_power task loop");
sender.send(vbus_in.is_high().into()).await;
sender.send(Events::Vbus(vbus_in.is_high())).await;
vbus_in.wait_for_any_edge().await;
info!("usb_power edge detected");
}
Expand All @@ -40,6 +40,7 @@ pub async fn vsys_voltage(_spawner: Spawner, r: VsysResources) {
let mut adc = Adc::new(r.adc, Irqs, Config::default());
let vsys_in = r.pin_27;
let mut channel = Channel::new_pin(vsys_in, Pull::None);
let sender = EVENT_CHANNEL.sender();
let refresh_after_secs = 600; // 10 minutes
loop {
// read the adc value
Expand All @@ -48,8 +49,9 @@ pub async fn vsys_voltage(_spawner: Spawner, r: VsysResources) {

info!(
"vsys_voltage: adc_value: {}, voltage: {}",
adc_value, voltage
adc_value, &voltage
);
sender.send(Events::Vsys(voltage)).await;
Timer::after(Duration::from_secs(refresh_after_secs)).await;
}
}
89 changes: 48 additions & 41 deletions src/task/state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
use core::cell::RefCell;
use defmt::*;
use embassy_executor::Spawner;
use embassy_futures::select::select_array;
use embassy_rp::peripherals::RTC;
use embassy_rp::rtc::Rtc;
use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
Expand Down Expand Up @@ -51,13 +50,19 @@ impl TaskConfig {
}
}

/// Channels for the events that we want to react to
/// we will need more channels for the other events, and we may need to use pipes instead of channels in some cases
/// see below in the orchestrate task for the ToDo
pub static GREEN_BTN_CHANNEL: Channel<CriticalSectionRawMutex, u8, 1> = Channel::new();
pub static BLUE_BTN_CHANNEL: Channel<CriticalSectionRawMutex, u8, 1> = Channel::new();
pub static YELLOW_BTN_CHANNEL: Channel<CriticalSectionRawMutex, u8, 1> = Channel::new();
pub static VBUS_CHANNEL: Channel<CriticalSectionRawMutex, u8, 1> = Channel::new();
/// Events that we want to react to together with the data that we need to react to the event
#[derive(PartialEq, Debug, Format)]
pub enum Events {
BlueBtn(u32),
GreenBtn(u32),
YellowBtn(u32),
Vbus(bool),
Vsys(f32),
// more
}

/// Channel for the events that we want to react to, all state events are of the type Enum Events
pub static EVENT_CHANNEL: Channel<CriticalSectionRawMutex, Events, 10> = Channel::new();

#[derive(PartialEq, Debug, Format)]
pub struct StateManager {
Expand Down Expand Up @@ -149,52 +154,54 @@ pub enum PowerState {
/// and once we reached states we will need to trigger display updates, sound, etc.
#[embassy_executor::task]
pub async fn orchestrate(_spawner: Spawner, rtc_ref: &'static RefCell<Rtc<'static, RTC>>) {
let mut state_manager = StateManager::new();

let blue_btn_receiver = BLUE_BTN_CHANNEL.receiver();
let green_btn_receiver = GREEN_BTN_CHANNEL.receiver();
let yellow_btn_receiver = YELLOW_BTN_CHANNEL.receiver();
let vbus_receiver = VBUS_CHANNEL.receiver();
let state_manager = StateManager::new();
let event_receiver = EVENT_CHANNEL.receiver();

info!("Orchestrate task started");

loop {
info!("Orchestrate loop");

// determine the state of the system by checking the button presses
let blue_btn_future = blue_btn_receiver.receive();
let green_btn_future = green_btn_receiver.receive();
let yellow_btn_future = yellow_btn_receiver.receive();

// determine the state of the system by checking the power state
let vbus_future = vbus_receiver.receive();
// receive the events
let event = event_receiver.receive().await;

let futures = [
blue_btn_future,
green_btn_future,
yellow_btn_future,
vbus_future,
];

match select_array(futures).await {
(_, 0) => {
info!("BLUE");
// react to the events
match event {
Events::BlueBtn(presses) => {
info!("Blue button pressed, presses: {}", presses);
}
(_, 1) => {
info!("GREEN");
state_manager.state.toggle_alarm_active();
Events::GreenBtn(presses) => {
info!("Green button pressed, presses: {}", presses);
}
(_, 2) => {
info!("YELLOW");
Events::YellowBtn(presses) => {
info!("Yellow button pressed, presses: {}", presses);
}
(vbus_value, 3) => {
info!("VBUS");
info!("VBUS value: {}", vbus_value);
Events::Vbus(usb) => {
info!("Vbus event, usb: {}", usb);
}
_ => {
info!("unreachable");
Events::Vsys(voltage) => {
info!("Vsys event, voltage: {}", voltage);
}
}
// match event {
// Ok(Events::BlueBtn(presses)) => {
// info!("Blue button pressed, presses: {}", presses);
// }
// Ok(Events::GreenBtn(presses)) => {
// info!("Green button pressed, presses: {}", presses);
// }
// Ok(Events::YellowBtn(presses)) => {
// info!("Yellow button pressed, presses: {}", presses);
// }
// Ok(Events::Vbus(usb)) => {
// info!("Vbus event, usb: {}", usb);
// }
// Ok(Events::Vsys(voltage)) => {
// info!("Vsys event, voltage: {}", voltage);
// }
// // more events
// _ => {}
// }

info!("StateManager: {:?}", state_manager);

Expand Down

0 comments on commit de3fb3f

Please sign in to comment.