use crate::cfg::BuzzerConfig;
use esp_hal::gpio::{DriveMode, interconnect::PeripheralOutput};
use esp_hal::ledc::{
LSGlobalClkSource, Ledc, LowSpeed, channel, channel::ChannelIFace, timer, timer::TimerIFace,
};
use esp_hal::peripherals::LEDC;
use static_cell::StaticCell;
type BuzzerTimer = timer::Timer<'static, LowSpeed>;
type BuzzerChannel = channel::Channel<'static, LowSpeed>;
static BUZZER_TIMER: StaticCell<BuzzerTimer> = StaticCell::new();
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum BuzzerInitError {
Timer(timer::Error),
Channel(channel::Error),
}
impl BuzzerInitError {
pub const fn as_str(self) -> &'static str {
match self {
Self::Timer(_) => "Buzzer timer init failed",
Self::Channel(_) => "Buzzer channel init failed",
}
}
}
pub struct Buzzer {
pub channel: BuzzerChannel,
}
pub fn init_buzzer(
config: BuzzerConfig,
ledc_peripheral: LEDC<'static>,
buzzer_pin: impl PeripheralOutput<'static>,
) -> Result<Buzzer, BuzzerInitError> {
let mut ledc = Ledc::new(ledc_peripheral);
ledc.set_global_slow_clock(LSGlobalClkSource::APBClk);
let timer = BUZZER_TIMER.init(ledc.timer::<LowSpeed>(timer::Number::Timer0));
timer
.configure(timer::config::Config {
duty: config.timer_duty,
clock_source: timer::LSClockSource::APBClk,
frequency: config.frequency,
})
.map_err(BuzzerInitError::Timer)?;
let mut channel = ledc.channel::<LowSpeed>(channel::Number::Channel0, buzzer_pin);
channel
.configure(channel::config::Config {
timer,
duty_pct: config.duty_pct.min(100),
drive_mode: DriveMode::PushPull,
})
.map_err(BuzzerInitError::Channel)?;
Ok(Buzzer { channel })
}