use std::{ sync::{Arc, Mutex}, thread::{sleep, spawn}, time::Duration, }; use embedded_hal::{adc::Channel, prelude::_embedded_hal_adc_OneShot}; use embedded_svc::event_bus::Postbox; use esp_idf_hal::{ adc::{ config::{self}, Analog, Atten6dB, PoweredAdc, ADC1, }, gpio::{Gpio1, Gpio2, Gpio3, Input}, }; use esp_idf_svc::eventloop::{ Background, EspBackgroundEventLoop, EspEventFetchData, EspEventLoop, EspEventPostData, EspTypedEventDeserializer, EspTypedEventSerializer, EspTypedEventSource, }; use esp_idf_sys::c_types; use log::{debug, warn}; use serde::{Deserialize, Serialize}; use crate::time::Time; pub static mut VOLTAGE_EVENTLOOP: Option>> = None; const ADAPTER_OFFSET: f32 = 12002f32 / 900f32; const BATTERY_OFFSET: f32 = 12002f32 / 900f32; const OUTPUT_OFFSET: f32 = 12002f32 / 900f32; pub struct VoltageDetection { pub worker: VoltageDetectionWorker, } #[derive(Clone, Copy, Serialize, Deserialize)] pub struct VoltageDetectionWorker { pub adapter_voltage: u16, pub battery_voltage: u16, pub output_voltage: u16, } impl VoltageDetection { pub fn new() -> anyhow::Result { return anyhow::Ok(Self { worker: VoltageDetectionWorker::new(), }); } pub fn watching(&mut self) -> anyhow::Result<()> { match EspBackgroundEventLoop::new(&Default::default()) { Ok(eventloop) => unsafe { VOLTAGE_EVENTLOOP = Some(eventloop) }, Err(err) => anyhow::bail!("Init Event Loop failed. {:?}", err), } let worker = Arc::new(Mutex::new(self.worker)); spawn(move || { let handler = || -> anyhow::Result<()> { let mut adapter_pin = unsafe { Gpio1::::new() } .into_analog_atten_6db() .map_err(|err| { anyhow::anyhow!("Failed to set GPIO 1 as analog input. {}", err) })?; let mut battery_pin = unsafe { Gpio2::::new() } .into_analog_atten_6db() .map_err(|err| { anyhow::anyhow!("Failed to set GPIO 2 as analog input. {}", err) })?; let mut output_pin = unsafe { Gpio3::::new() } .into_analog_atten_6db() .map_err(|err| { anyhow::anyhow!("Failed to set GPIO 3 as analog input. {}", err) })?; let mut adc = PoweredAdc::new(unsafe { ADC1::new() }, config::Config::new())?; let mut worker = worker.lock().map_err(|err| { anyhow::anyhow!("Lock VoltageDetection Worker Failed. {}", err) })?; let mut last_runing_at; loop { last_runing_at = Time::new().get_time(); match worker.read_once( &mut adc, &mut adapter_pin, &mut battery_pin, &mut output_pin, ) { Ok(_) => debug!( "Adapter: {},\tBattery: {},\t Output: {}", worker.adapter_voltage, worker.battery_voltage, worker.output_voltage ), Err(err) => warn!("Read Failed. {}", err), } if let Some(eventloop) = unsafe { VOLTAGE_EVENTLOOP.as_mut() } { if let Err(err) = eventloop.post( &mut VoltageDetectionWorker { adapter_voltage: worker.adapter_voltage, battery_voltage: worker.battery_voltage, output_voltage: worker.output_voltage, }, None, ) { warn!("Post Result to Event Loop failed. {}", err); } } else { warn!("EVENTLOOP IS NONE"); } let mut delta = Time::new().get_time() - last_runing_at; if delta >= Duration::from_millis(5000) { delta = Duration::ZERO } sleep(Duration::from_millis(5000) - delta); } }; if let Err(err) = handler() { warn!("init failed. {}", err) } }); return anyhow::Ok(()); } } impl VoltageDetectionWorker { pub fn new() -> Self { return Self { adapter_voltage: 0, battery_voltage: 0, output_voltage: 0, }; } pub fn read_once( &mut self, adc: &mut PoweredAdc, adapter_pin: &mut Gpio1>, battery_pin: &mut Gpio2>, output_pin: &mut Gpio3>, ) -> anyhow::Result<()> { match self.read_pin_once(adc, adapter_pin) { Ok(voltage) => { self.adapter_voltage = ((voltage as f32) * ADAPTER_OFFSET) as u16; } Err(err) => { warn!("Adapter Voltage read failed: {:?}", err); } } match self.read_pin_once(adc, battery_pin) { Ok(voltage) => { self.battery_voltage = ((voltage as f32) * BATTERY_OFFSET) as u16; } Err(err) => { warn!("Adapter Voltage read failed: {:?}", err); } } match self.read_pin_once(adc, output_pin) { Ok(voltage) => { self.output_voltage = ((voltage as f32) * OUTPUT_OFFSET) as u16; } Err(err) => { warn!("Adapter Voltage read failed: {:?}", err); } } return anyhow::Ok(()); } pub fn read_pin_once, PIN: Channel>( &mut self, adc: &mut PoweredAdc, pin: &mut PIN, ) -> anyhow::Result { let mut avg_voltage: u16 = 0; for _ in 0..10 { let voltage = adc.read(pin); match voltage { Ok(voltage) => { avg_voltage += voltage; } Err(err) => { anyhow::bail!("Adapter Voltage read failed: {:?}", err) } }; sleep(Duration::from_millis(100)); } anyhow::Ok(avg_voltage / 10) } } impl EspTypedEventSource for VoltageDetectionWorker { fn source() -> *const c_types::c_char { b"VOLTAGES\0".as_ptr() as *const _ } } impl EspTypedEventSerializer for VoltageDetectionWorker { fn serialize( event: &VoltageDetectionWorker, f: impl for<'a> FnOnce(&'a EspEventPostData) -> R, ) -> R { f(&unsafe { EspEventPostData::new(Self::source(), Self::event_id(), event) }) } } impl EspTypedEventDeserializer for VoltageDetectionWorker { fn deserialize( data: &EspEventFetchData, f: &mut impl for<'a> FnMut(&'a VoltageDetectionWorker) -> R, ) -> R { f(unsafe { data.as_payload() }) } }