feat: beep module.
This commit is contained in:
parent
3c8fdd124b
commit
3b2497cb7f
108
src/beep.rs
Normal file
108
src/beep.rs
Normal file
@ -0,0 +1,108 @@
|
||||
use embedded_svc::timer::{PeriodicTimer, TimerService};
|
||||
use esp_idf_hal::gpio::{Gpio4, Output};
|
||||
use esp_idf_hal::ledc::{config::TimerConfig, Channel, Timer};
|
||||
use esp_idf_hal::ledc::{CHANNEL0, TIMER0};
|
||||
use esp_idf_hal::prelude::*;
|
||||
use esp_idf_svc::timer::{EspTimer, EspTimerService};
|
||||
use esp_idf_sys::EspError;
|
||||
use log::{info, warn};
|
||||
use std::sync::{Arc, Mutex};
|
||||
use std::time::Duration;
|
||||
type LedcChannel<P, T, C> = Channel<C, T, Timer<T>, P>;
|
||||
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
struct BeepState {
|
||||
beat: u8,
|
||||
ringtone: ringtone::Type,
|
||||
}
|
||||
|
||||
impl BeepState {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
beat: 0,
|
||||
ringtone: ringtone::SILENCE,
|
||||
}
|
||||
}
|
||||
pub fn from_ringtone(ringtone: ringtone::Type) -> Self {
|
||||
Self { beat: 0, ringtone }
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Beep {
|
||||
watch_timer: Option<EspTimer>,
|
||||
state: BeepState,
|
||||
}
|
||||
impl Beep {
|
||||
pub fn new() -> Self {
|
||||
return Beep {
|
||||
watch_timer: None,
|
||||
state: BeepState::new(),
|
||||
};
|
||||
}
|
||||
fn init_channel(
|
||||
pin: Gpio4<Output>,
|
||||
timer: TIMER0,
|
||||
channel: CHANNEL0,
|
||||
frequency: Hertz,
|
||||
) -> Result<LedcChannel<Gpio4<Output>, TIMER0, CHANNEL0>, EspError> {
|
||||
let config = TimerConfig::default().frequency(frequency);
|
||||
let timer = Timer::new(timer, &config)?;
|
||||
let channel = Channel::new(channel, timer, pin)?;
|
||||
return Ok(channel);
|
||||
}
|
||||
pub fn play(&mut self, ringtone: ringtone::Type) -> anyhow::Result<()> {
|
||||
if self.state.ringtone != ringtone {
|
||||
self.state = BeepState::from_ringtone(ringtone);
|
||||
}
|
||||
let state = Arc::new(Mutex::new(self.state));
|
||||
let mut timer = EspTimerService::new()?.timer(move || {
|
||||
info!("One-shot timer triggered");
|
||||
match state.lock().as_mut() {
|
||||
Ok(state) => {
|
||||
info!("B state.beat: {}", state.beat);
|
||||
if let Err(err) = Self::play_once(state) {
|
||||
warn!("{}", err);
|
||||
}
|
||||
info!("A state.beat: {}", state.beat);
|
||||
}
|
||||
Err(err) => {
|
||||
warn!("Failed to lock state. {}", err);
|
||||
}
|
||||
}
|
||||
})?;
|
||||
timer.every(Duration::from_millis(250))?;
|
||||
|
||||
self.watch_timer = Some(timer);
|
||||
return anyhow::Ok(());
|
||||
}
|
||||
|
||||
fn play_once(state: &mut BeepState) -> anyhow::Result<()> {
|
||||
let pin = unsafe { Gpio4::<Output>::new() }
|
||||
.into_output()
|
||||
.map_err(|err| anyhow::anyhow!("Failed to set GPIO 4 as ledc output. {}", err))?;
|
||||
let hw_timer = unsafe { TIMER0::new() };
|
||||
let hw_channel = unsafe { CHANNEL0::new() };
|
||||
let curr = state.ringtone[state.beat as usize];
|
||||
let mut channel = Self::init_channel(pin, hw_timer, hw_channel, if curr < 1000 { 1000.Hz().into()} else {curr.Hz().into()} )
|
||||
.map_err(|err| anyhow::anyhow!("Failed to initialize channel. {}", err))?;
|
||||
|
||||
if curr < 1000 {
|
||||
channel.set_duty(0).expect("Failed to set duty");
|
||||
} else {
|
||||
channel.set_duty(60).expect("Failed to set duty");
|
||||
}
|
||||
|
||||
state.beat += 1;
|
||||
if state.beat == 16 {
|
||||
state.beat = 0;
|
||||
}
|
||||
return anyhow::Ok(());
|
||||
}
|
||||
}
|
||||
pub mod ringtone {
|
||||
pub type Type = [u32; 16];
|
||||
pub const ADAPTER_DOWN: Type = [2000, 1950, 1900, 1800, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
|
||||
pub const BATTERY_LOW: Type = [2000, 1950, 0, 0, 1930, 1900, 0, 0, 2000, 1900, 0, 0, 1930, 1900, 0, 0];
|
||||
pub const SILENCE: Type = [0; 16];
|
||||
pub const SHUTDOWN: Type = [2300, 0, 2300, 2000, 2100, 2000, 0, 2300, 2000, 2100, 2000, 1900, 0, 0, 0, 0];
|
||||
}
|
19
src/main.rs
19
src/main.rs
@ -8,13 +8,14 @@ use std::{
|
||||
time::Duration,
|
||||
};
|
||||
|
||||
mod beep;
|
||||
mod blink;
|
||||
mod message_queue;
|
||||
mod time;
|
||||
mod voltage_detection;
|
||||
mod wifi;
|
||||
|
||||
use crate::voltage_detection::VoltageDetectionWorker;
|
||||
use crate::{beep::{Beep, ringtone}, voltage_detection::VoltageDetectionWorker};
|
||||
use crate::{
|
||||
message_queue::MessageQueue, time::Time, voltage_detection::VoltageDetection, wifi::Internet,
|
||||
};
|
||||
@ -58,6 +59,8 @@ fn main() {
|
||||
);
|
||||
blink.play();
|
||||
});
|
||||
let mut beep = Beep::new();
|
||||
beep.play(ringtone::ADAPTER_DOWN).expect("Can not beep.");
|
||||
|
||||
let mut voltage_detection = VoltageDetection::new();
|
||||
|
||||
@ -89,19 +92,5 @@ fn main() {
|
||||
|
||||
loop {
|
||||
sleep(Duration::from_millis(1000));
|
||||
// if let Some(ref mut mq_client) = mq.client {
|
||||
// let timestamps = time.get_time().as_millis();
|
||||
|
||||
// info!("timestamps {}", timestamps);
|
||||
// mq_client
|
||||
// .publish(
|
||||
// "ups-0.2/heartbeat",
|
||||
// QoS::AtMostOnce,
|
||||
// false,
|
||||
// timestamps.to_string().as_bytes(),
|
||||
// )
|
||||
// .map_err(|err| warn!("publish heartbeat failed {}", err))
|
||||
// .unwrap();
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user