148 lines
4.5 KiB
Rust
148 lines
4.5 KiB
Rust
use anyhow::{anyhow, Result};
|
|
use embedded_hal::digital::blocking::OutputPin;
|
|
use embedded_hal_0_2::adc::OneShot;
|
|
use esp_idf_hal::{
|
|
adc::{Atten11dB, PoweredAdc, ADC1},
|
|
gpio::{Gpio1, Gpio2},
|
|
};
|
|
use log::*;
|
|
use std::{
|
|
sync::mpsc,
|
|
thread,
|
|
time::{Duration, SystemTime},
|
|
};
|
|
|
|
use crate::{beep::ringtone, dc_out_controller::DcOutController, screen::Screen};
|
|
|
|
type AdapterGpio = Gpio1<Atten11dB<ADC1>>;
|
|
type BatteryGpio = Gpio2<Atten11dB<ADC1>>;
|
|
|
|
pub struct Manager<C>
|
|
where
|
|
C: OutputPin + Send,
|
|
{
|
|
dc_out_controller: DcOutController<C>,
|
|
screen: Screen,
|
|
adc: PoweredAdc<ADC1>,
|
|
adapter_pin: AdapterGpio,
|
|
battery_pin: BatteryGpio,
|
|
tx: mpsc::Sender<ringtone::Type>,
|
|
adapter_downed_at: Option<SystemTime>,
|
|
}
|
|
|
|
impl<C> Manager<C>
|
|
where
|
|
C: OutputPin + Send,
|
|
C: 'static,
|
|
C: std::marker::Sync,
|
|
{
|
|
pub fn new(
|
|
dc_out_controller: DcOutController<C>,
|
|
screen: Screen,
|
|
adc1: ADC1,
|
|
adapter_pin: AdapterGpio,
|
|
battery_pin: BatteryGpio,
|
|
tx: mpsc::Sender<ringtone::Type>,
|
|
) -> Result<Self> {
|
|
let adc = PoweredAdc::new(
|
|
adc1,
|
|
esp_idf_hal::adc::config::Config::new().calibration(true),
|
|
)
|
|
.map_err(|err| anyhow!("Can not init Adc: {}", err))?;
|
|
return Ok(Manager {
|
|
dc_out_controller,
|
|
screen,
|
|
adc,
|
|
adapter_pin,
|
|
battery_pin,
|
|
tx,
|
|
adapter_downed_at: None,
|
|
});
|
|
}
|
|
|
|
pub fn get_adapter_voltage(&mut self) -> Result<f32> {
|
|
return Ok(self
|
|
.adc
|
|
.read(&mut self.adapter_pin)
|
|
.map_err(|err| anyhow!("Can not read adapter voltage. {:?}", err))?
|
|
as f32);
|
|
}
|
|
pub fn get_battery_voltage(&mut self) -> Result<f32> {
|
|
return Ok(self
|
|
.adc
|
|
.read(&mut self.battery_pin)
|
|
.map_err(|err| anyhow!("Can not read battery voltage. {:?}", err))?
|
|
as f32);
|
|
}
|
|
|
|
pub fn handling_once(&mut self) -> Result<()> {
|
|
let mut adapter = 0.0_f32;
|
|
let mut battery = 0.0_f32;
|
|
for _ in 0..10 {
|
|
adapter += self.get_adapter_voltage()?;
|
|
battery += self.get_battery_voltage()?;
|
|
thread::sleep(Duration::from_millis(10));
|
|
}
|
|
|
|
adapter /= 10.0_f32;
|
|
battery /= 10.0_f32;
|
|
|
|
if is_adapter_down(adapter) {
|
|
if self.dc_out_controller.get_status().is_off() {
|
|
self.tx
|
|
.send(ringtone::SILENCE)
|
|
.map_err(|err| anyhow!("Can not send silence to Beep. {:?}", err))?;
|
|
} else if is_battery_down(battery) {
|
|
self.tx
|
|
.send(ringtone::BATTERY_LOW)
|
|
.expect("Can not send message");
|
|
} else if is_battery_low(battery) {
|
|
self.dc_out_controller.shutdown();
|
|
if self.adapter_downed_at.is_none() {
|
|
info!("Recording adapter downed at: {:?}", SystemTime::now());
|
|
self.adapter_downed_at = Some(SystemTime::now());
|
|
} else if self
|
|
.adapter_downed_at
|
|
.is_some_and(|at| at.elapsed().is_ok_and(|dur| *dur > Duration::from_secs(5)))
|
|
{
|
|
self.tx
|
|
.send(ringtone::SHUTDOWN)
|
|
.map_err(|err| anyhow!("Can not send shutdown to Beep. {:?}", err))?;
|
|
}
|
|
} else {
|
|
self.tx
|
|
.send(ringtone::ADAPTER_DOWN)
|
|
.map_err(|err| anyhow!("Can not send adapter down to Beep. {:?}", err))?;
|
|
self.dc_out_controller
|
|
.stop_shutdown()
|
|
.map_err(|err| anyhow!("Can not stop shutdown. {:?}", err))?;
|
|
self.adapter_downed_at = None;
|
|
}
|
|
} else {
|
|
self.dc_out_controller
|
|
.stop_shutdown()
|
|
.expect("Can not stop shutdown");
|
|
self.tx.send(ringtone::SILENCE).map_err(|err| anyhow!("Can not send silence to Beep. {:?}", err))?;
|
|
self.adapter_downed_at = None;
|
|
self.dc_out_controller.open()?;
|
|
}
|
|
self.screen
|
|
.draw_voltage(adapter, battery)
|
|
.map_err(|err| anyhow!("Can not draw voltage. {:?}", err))?;
|
|
|
|
Ok(())
|
|
}
|
|
}
|
|
|
|
fn is_battery_low(battery: f32) -> bool {
|
|
battery < 1500.0
|
|
}
|
|
|
|
fn is_battery_down(battery: f32) -> bool {
|
|
battery < 500.0
|
|
}
|
|
|
|
fn is_adapter_down(adapter: f32) -> bool {
|
|
adapter < 1000.0
|
|
}
|