use std::num::NonZeroU32;
use std::sync::mpsc::Receiver;
use std::sync::{mpsc, Arc};
use std::thread;
use std::time::Duration;
use duration_toggler::Toggler;
use esp_idf_svc::hal::peripherals::Peripherals;
use esp_idf_svc::hal::task::notification::{Notification, Notifier};
use esp_idf_svc::hal::{delay, gpio::*};
use led_button_manager::led_button_toggle_handler::LedButtonToggle;
use led_button_manager::LedButtonsManager; // wokwi
// use led_button_manager::manager::LedButtonsManager; // local
mod duration_toggler;
mod led_button_manager;
const TOGGLE_LED_NOTIFICATION_CODE: u32 = 1;
struct PeripheralsToUse {
led: PinDriver<'static, Gpio4, Output>,
led_blinking_duration_change_button: PinDriver<'static, Gpio0, Input>,
}
fn prepare_peripherals(peripherals: Peripherals, notifier: Arc<Notifier>) -> PeripheralsToUse {
let led = PinDriver::output(peripherals.pins.gpio4).unwrap();
println!("Prepared LED.");
let mut led_blinking_duration_change_button = PinDriver::input(peripherals.pins.gpio0).unwrap();
println!("Prepared led blinking .");
led_blinking_duration_change_button
.set_pull(Pull::Up)
.unwrap();
led_blinking_duration_change_button
.set_interrupt_type(InterruptType::PosEdge)
.unwrap();
unsafe {
let notifier_clone = notifier.clone();
led_blinking_duration_change_button
.subscribe(move || {
notifier_clone
.notify_and_yield(NonZeroU32::new(TOGGLE_LED_NOTIFICATION_CODE).unwrap());
})
.unwrap();
}
led_blinking_duration_change_button
.enable_interrupt()
.unwrap();
PeripheralsToUse {
led,
led_blinking_duration_change_button,
}
}
fn main() {
// It is necessary to call this function once. Otherwise some patches to the runtime
// implemented by esp-idf-sys might not link properly. See https://github.com/esp-rs/esp-idf-template/issues/71
esp_idf_svc::sys::link_patches();
let (transmitter, receiver) = mpsc::channel::<Duration>();
let toggler = Toggler::new(vec![]);
let default_led_toggle_duration = toggler.get_duration();
let mut manager = LedButtonsManager::new(vec![Box::new(LedButtonToggle::new(
1,
transmitter,
toggler,
))])
.unwrap();
let peripherals = Peripherals::take().unwrap();
let notification = Notification::new();
let notifier = notification.notifier();
let notifier_clone = notifier.clone();
let mut peripherals_to_use = prepare_peripherals(peripherals, notifier_clone);
let blinking_led_handle = thread::spawn(move || {
blinking_led(
receiver,
peripherals_to_use.led,
default_led_toggle_duration,
)
});
loop {
peripherals_to_use
.led_blinking_duration_change_button
.enable_interrupt()
.unwrap();
let noification_code = notification.wait(delay::BLOCK);
if let Some(code) = noification_code {
manager.handle(code.into()).unwrap();
}
blinking_led_handle.thread().unpark();
}
}
fn blinking_led(
receiver: Receiver<Duration>,
mut led: PinDriver<'static, Gpio4, Output>,
default_duration: Duration,
) {
let original_duration = default_duration;
loop {
let new_duration = receiver.try_recv().unwrap_or(original_duration);
led.toggle().unwrap();
std::thread::park_timeout(new_duration);
}
}