ups-esp32c3-rust/src/voltage_detection.rs

125 lines
3.8 KiB
Rust

use std::{
sync::{Arc, Mutex},
time::Duration,
};
use embedded_hal::{adc::Channel, prelude::_embedded_hal_adc_OneShot, digital::v2::OutputPin};
use embedded_svc::timer::{PeriodicTimer, TimerService};
use esp_idf_hal::{
adc::{
config::{self},
Analog, PoweredAdc, ADC1,
},
gpio::{Gpio1, Gpio2, Gpio3, Input, Pull},
};
use esp_idf_svc::timer::{EspTimer, EspTimerService};
use log::{info, warn};
pub struct VoltageDetection {
pub worker: VoltageDetectionWorker,
watch_timer: Option<EspTimer>,
}
#[derive(Clone, Copy)]
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.as_ref().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
);
}
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::<Input>::new() }
.into_analog_atten_11db()
.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;
}
Err(err) => {
warn!("Adapter Voltage read failed: {:?}", err);
}
}
let battery_pin = unsafe { Gpio2::<Input>::new() }
.into_analog_atten_11db()
.map_err(|err| anyhow::anyhow!("Failed to set GPIO 1 as analog input. {}", err))?;
match self.read_pin_once(battery_pin) {
Ok(voltage) => {
self.battery_voltage = voltage;
}
Err(err) => {
warn!("Adapter Voltage read failed: {:?}", err);
}
}
let output_pin = unsafe { Gpio3::<Input>::new() }
.into_analog_atten_11db()
.map_err(|err| anyhow::anyhow!("Failed to set GPIO 1 as analog input. {}", err))?;
match self.read_pin_once(output_pin) {
Ok(voltage) => {
self.output_voltage = voltage;
}
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,
mut pin: PIN,
) -> anyhow::Result<u16> {
let mut adc = PoweredAdc::new(unsafe { ADC1::new() }, config::Config::new())?;
let voltage = adc.read(&mut pin);
match voltage {
Ok(voltage) => anyhow::Ok((self.adapter_voltage + voltage * 10) / 11),
Err(err) => {
anyhow::bail!("Adapter Voltage read failed: {:?}", err)
}
}
}
}