use std::{ sync::{Arc, Mutex}, time::Duration, }; use embedded_hal::{adc::Channel, prelude::_embedded_hal_adc_OneShot}; use embedded_svc::{ event_bus::Postbox, timer::{PeriodicTimer, TimerService}, }; use esp_idf_hal::{ adc::{ config::{self}, Analog, PoweredAdc, ADC1, }, gpio::{Gpio1, Gpio2, Gpio3, Input}, }; use esp_idf_svc::{ eventloop::{ EspEventFetchData, EspEventPostData, EspTypedEventDeserializer, EspTypedEventSerializer, EspTypedEventSource, }, timer::{EspTimer, EspTimerService}, }; use esp_idf_sys::c_types; use log::{info, warn}; use serde::{Deserialize, Serialize}; use crate::EVENTLOOP; const ADAPTER_OFFSET: f32 = 12002f32 / 900f32; const BATTERY_OFFSET: f32 = 12002f32 / 900f32; const OUTPUT_OFFSET: f32 = 12002f32 / 900f32; pub struct VoltageDetection { pub worker: VoltageDetectionWorker, watch_timer: Option, } #[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() -> Self { return Self { worker: VoltageDetectionWorker::new(), watch_timer: None, }; } pub fn watching(&mut self) -> anyhow::Result<()> { let worker = Arc::new(Mutex::new(self.worker)); let mut timer = EspTimerService::new()?.timer(move || { info!("One-shot timer triggered"); match worker.lock().as_mut() { Ok(worker) => { if let Err(err) = worker.read_once() { warn!("Read Failed. {}", err); } info!( "Adapter: {},\tBattery: {},\t Output: {}", worker.adapter_voltage, worker.battery_voltage, worker.output_voltage ); if let Some(eventloop) = unsafe { 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 { info!("Event Loop Post"); } } else { warn!("EVENTLOOP IS NONE"); } } Err(err) => { warn!("Lock VoltageDetection Worker Failed. {}", err) } } })?; timer.every(Duration::from_secs(1))?; self.watch_timer = Some(timer); 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) -> anyhow::Result<()> { let adapter_pin = unsafe { Gpio1::::new() } .into_analog_atten_6db() .map_err(|err| anyhow::anyhow!("Failed to set GPIO 1 as analog input. {}", err))?; match self.read_pin_once(adapter_pin) { Ok(voltage) => { self.adapter_voltage = ((voltage as f32) * ADAPTER_OFFSET) as u16; } Err(err) => { warn!("Adapter Voltage read failed: {:?}", err); } } let battery_pin = unsafe { Gpio2::::new() } .into_analog_atten_6db() .map_err(|err| anyhow::anyhow!("Failed to set GPIO 2 as analog input. {}", err))?; match self.read_pin_once(battery_pin) { Ok(voltage) => { self.battery_voltage = ((voltage as f32) * BATTERY_OFFSET) as u16; } Err(err) => { warn!("Adapter Voltage read failed: {:?}", err); } } let output_pin = unsafe { Gpio3::::new() } .into_analog_atten_6db() .map_err(|err| anyhow::anyhow!("Failed to set GPIO 3 as analog input. {}", err))?; match self.read_pin_once(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, mut pin: PIN, ) -> anyhow::Result { let mut adc = PoweredAdc::new(unsafe { ADC1::new() }, config::Config::new())?; let voltage = adc.read(&mut pin); match voltage { Ok(voltage) => anyhow::Ok(voltage), Err(err) => { anyhow::bail!("Adapter Voltage read failed: {:?}", err) } } } } 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() }) } }