fix: Beep 有概率崩溃问题。

This commit is contained in:
Ivan Li 2022-09-10 16:10:13 +08:00
parent eb96ce4afb
commit 8bc4be194b
4 changed files with 37 additions and 28 deletions

View File

@ -4,9 +4,9 @@ use esp_idf_hal::ledc::{config::TimerConfig, Channel, Timer};
use esp_idf_hal::ledc::{CHANNEL0, TIMER0}; use esp_idf_hal::ledc::{CHANNEL0, TIMER0};
use esp_idf_hal::prelude::*; use esp_idf_hal::prelude::*;
use esp_idf_svc::timer::{EspTimer, EspTimerService}; use esp_idf_svc::timer::{EspTimer, EspTimerService};
use esp_idf_sys::EspError; use esp_idf_sys::{ledc_mode_t_LEDC_LOW_SPEED_MODE, ledc_set_freq, EspError};
use log::{info, warn}; use log::{info, warn};
use std::sync::{Arc, Mutex}; use std::sync::{Arc, Mutex, MutexGuard};
use std::time::Duration; use std::time::Duration;
type LedcChannel<P, T, C> = Channel<C, T, Timer<T>, P>; type LedcChannel<P, T, C> = Channel<C, T, Timer<T>, P>;
@ -28,16 +28,28 @@ impl BeepState {
} }
} }
type BeepChannel = Channel<CHANNEL0, TIMER0, Timer<TIMER0>, Gpio4<Output>>;
pub struct Beep { pub struct Beep {
watch_timer: Option<EspTimer>, watch_timer: Option<EspTimer>,
state: BeepState, state: BeepState,
channel: Arc<Mutex<BeepChannel>>,
} }
impl Beep { impl Beep {
pub fn new() -> Self { pub fn new() -> anyhow::Result<Self> {
return Beep { 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 mut channel = Self::init_channel(pin, hw_timer, hw_channel, 1000.Hz().into())
.map_err(|err| anyhow::anyhow!("Failed to initialize channel. {}", err))?;
return anyhow::Ok(Beep {
watch_timer: None, watch_timer: None,
state: BeepState::new(), state: BeepState::new(),
}; channel: Arc::new(Mutex::new(channel)),
});
} }
fn init_channel( fn init_channel(
pin: Gpio4<Output>, pin: Gpio4<Output>,
@ -58,40 +70,37 @@ impl Beep {
return Ok(()); return Ok(());
} }
let state = Arc::new(Mutex::new(self.state)); let state = Arc::new(Mutex::new(self.state));
let mut timer = EspTimerService::new()?.timer(move || { let channel = self.channel.to_owned();
match state.lock().as_mut() { let mut timer = EspTimerService::new()?
.timer(move || match state.lock().as_mut() {
Ok(state) => { Ok(state) => {
if let Err(err) = Self::play_once(state) { if let Err(err) = Self::play_once(state, channel.lock().unwrap()) {
warn!("{}", err); warn!("{}", err);
} }
} }
Err(err) => { Err(err) => {
warn!("Failed to lock state. {}", err); warn!("Failed to lock state. {}", err);
} }
} })
}).map_err(|err| anyhow::anyhow!("Init Timer Failed. {}", err))?; .map_err(|err| anyhow::anyhow!("Init Timer Failed. {}", err))?;
timer.every(Duration::from_millis(250))?; timer.every(Duration::from_millis(250))?;
self.watch_timer = Some(timer); self.watch_timer = Some(timer);
return anyhow::Ok(()); return anyhow::Ok(());
} }
fn play_once(state: &mut BeepState) -> anyhow::Result<()> { fn play_once(
let pin = unsafe { Gpio4::<Output>::new() } state: &mut BeepState,
.into_output() mut channel: MutexGuard<BeepChannel>,
.map_err(|err| anyhow::anyhow!("Failed to set GPIO 4 as ledc output. {}", err))?; ) -> anyhow::Result<()> {
let hw_timer = unsafe { TIMER0::new() };
let hw_channel = unsafe { CHANNEL0::new() };
if state.ringtone.len() <= state.beat as usize { if state.ringtone.len() <= state.beat as usize {
state.beat = 0; state.beat = 0;
} }
let curr = state.ringtone[state.beat as usize]; 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()} ) if curr == 0 {
.map_err(|err| anyhow::anyhow!("Failed to initialize channel. {}", err))?;
if curr < 1000 {
channel.set_duty(0).expect("Failed to set duty"); channel.set_duty(0).expect("Failed to set duty");
} else { } else {
unsafe { ledc_set_freq(ledc_mode_t_LEDC_LOW_SPEED_MODE, 0, curr); }
channel.set_duty(60).expect("Failed to set duty"); channel.set_duty(60).expect("Failed to set duty");
} }
@ -105,7 +114,11 @@ impl Beep {
pub mod ringtone { pub mod ringtone {
pub type Type = [u32; 16]; pub type Type = [u32; 16];
pub const ADAPTER_DOWN: Type = [2300, 2000, 2250, 1950, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; pub const ADAPTER_DOWN: Type = [2300, 2000, 2250, 1950, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
pub const BATTERY_LOW: Type = [2000, 1950, 0, 0, 1980, 1900, 0, 0, 2000, 1900, 0, 0, 1980, 1900, 0, 0]; pub const BATTERY_LOW: Type = [
2000, 1950, 0, 0, 1980, 1900, 0, 0, 2000, 1900, 0, 0, 1980, 1900, 0, 0,
];
pub const SILENCE: Type = [0; 16]; pub const SILENCE: Type = [0; 16];
pub const SHUTDOWN: Type = [3450, 3500, 0, 3500, 3050, 3000, 0, 3000, 3050, 1000, 1000, 1000, 0, 0, 0, 0]; pub const SHUTDOWN: Type = [
3450, 3500, 0, 3500, 3050, 3000, 0, 3000, 3050, 1000, 1000, 1000, 0, 0, 0, 0,
];
} }

View File

View File

@ -44,7 +44,6 @@ fn main() {
let blink_pin = peripherals.pins.gpio5; let blink_pin = peripherals.pins.gpio5;
info!("About to start a background event loop");
match EspBackgroundEventLoop::new(&Default::default()) { match EspBackgroundEventLoop::new(&Default::default()) {
Ok(eventloop) => unsafe { VOLTAGE_EVENTLOOP = Some(eventloop) }, Ok(eventloop) => unsafe { VOLTAGE_EVENTLOOP = Some(eventloop) },
Err(err) => error!("Init Event Loop failed. {:?}", err), Err(err) => error!("Init Event Loop failed. {:?}", err),
@ -72,7 +71,7 @@ fn main() {
sleep(Duration::from_millis(100)); sleep(Duration::from_millis(100));
let mut beep = Beep::new(); let mut beep = Beep::new().unwrap();
let mut dc_out_controller = let mut dc_out_controller =
DcOutController::get_instance().expect("Can not get DcOutController instance"); DcOutController::get_instance().expect("Can not get DcOutController instance");

View File

@ -9,10 +9,7 @@ use std::{
use anyhow::Result; use anyhow::Result;
use embedded_svc::mqtt::client::{utils::ConnState, Client, Connection, MessageImpl, Publish, QoS}; use embedded_svc::mqtt::client::{utils::ConnState, Client, Connection, MessageImpl, Publish, QoS};
use esp_idf_svc::{ use esp_idf_svc::mqtt::client::{EspMqttClient, MqttClientConfiguration};
eventloop::{Background, EspEventLoop},
mqtt::client::{EspMqttClient, MqttClientConfiguration},
};
use esp_idf_sys::EspError; use esp_idf_sys::EspError;
use log::*; use log::*;