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>; type BatteryGpio = Gpio2>; pub struct Manager where C: OutputPin + Send, { dc_out_controller: DcOutController, screen: Screen, adc: PoweredAdc, adapter_pin: AdapterGpio, battery_pin: BatteryGpio, tx: mpsc::Sender, adapter_downed_at: Option, } impl Manager where C: OutputPin + Send, C: 'static, C: std::marker::Sync, { pub fn new( dc_out_controller: DcOutController, screen: Screen, adc1: ADC1, adapter_pin: AdapterGpio, battery_pin: BatteryGpio, tx: mpsc::Sender, ) -> Result { 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 { 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 { 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 }