ups-esp32c3-rust/src/voltage_detection.rs

220 lines
7.2 KiB
Rust

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<EspEventLoop<esp_idf_svc::eventloop::User<Background>>> =
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<Self> {
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::<Input>::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::<Input>::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::<Input>::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<ADC1>,
adapter_pin: &mut Gpio1<Atten6dB<ADC1>>,
battery_pin: &mut Gpio2<Atten6dB<ADC1>>,
output_pin: &mut Gpio3<Atten6dB<ADC1>>,
) -> 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<AN: Analog<ADC1>, PIN: Channel<AN, ID = u8>>(
&mut self,
adc: &mut PoweredAdc<ADC1>,
pin: &mut PIN,
) -> anyhow::Result<u16> {
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<VoltageDetectionWorker> for VoltageDetectionWorker {
fn serialize<R>(
event: &VoltageDetectionWorker,
f: impl for<'a> FnOnce(&'a EspEventPostData) -> R,
) -> R {
f(&unsafe { EspEventPostData::new(Self::source(), Self::event_id(), event) })
}
}
impl EspTypedEventDeserializer<VoltageDetectionWorker> for VoltageDetectionWorker {
fn deserialize<R>(
data: &EspEventFetchData,
f: &mut impl for<'a> FnMut(&'a VoltageDetectionWorker) -> R,
) -> R {
f(unsafe { data.as_payload() })
}
}