From 2f52f142b88d140fdf6e8a2f63e2d18e91d11b66 Mon Sep 17 00:00:00 2001 From: Ivan Li Date: Sun, 11 Sep 2022 21:31:36 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=85=85=E7=94=B5=E6=8E=A7=E5=88=B6?= =?UTF-8?q?=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/charge_controller.rs | 179 +++++++++++---------------------------- src/main.rs | 35 +++++++- 2 files changed, 81 insertions(+), 133 deletions(-) diff --git a/src/charge_controller.rs b/src/charge_controller.rs index 3c4c222..831e82f 100644 --- a/src/charge_controller.rs +++ b/src/charge_controller.rs @@ -1,189 +1,100 @@ -use std::{ - sync::{ - Arc, Mutex, MutexGuard, - }, -}; +use std::sync::{Arc, Mutex, MutexGuard}; use embedded_hal::digital::v2::{OutputPin, PinState}; use embedded_svc::event_bus::{EventBus, Postbox}; -use esp_idf_hal::gpio::{Gpio6, Output}; +use esp_idf_hal::gpio::{Gpio7, Output}; use esp_idf_svc::eventloop::{ Background, EspBackgroundEventLoop, EspEventFetchData, EspEventLoop, EspEventPostData, EspSubscription, EspTypedEventDeserializer, EspTypedEventSerializer, EspTypedEventSource, User, }; use esp_idf_sys::c_types; -use log::{info, warn, debug}; +use log::{warn}; use serde_json::json; use crate::voltage_detection::{VoltageDetectionWorker, VOLTAGE_EVENTLOOP}; -const WAITING_OFF_SECONDS: u8 = 60; - -pub static mut DC_OUT_STATE_EVENT_LOOP: Option< +pub static mut CHARGE_STATE_EVENT_LOOP: Option< EspEventLoop>, > = None; #[derive(Debug, Clone, Copy, PartialEq)] -pub enum DcOutStatus { - WaitingOn(u8), - On, - Off, - WaitingOff, - TurningOff(u8), +pub enum ChargeStatus { + Charging, + Charged, } #[derive(Debug, Clone, Copy)] -pub struct DcOutControllerState { - pub status: DcOutStatus, +pub struct ChargeControllerState { + pub status: ChargeStatus, pub pin_state: PinState, } -impl DcOutControllerState { +impl ChargeControllerState { pub fn new() -> Self { Self { - status: DcOutStatus::On, + status: ChargeStatus::Charging, pin_state: PinState::Low, } } - fn handle_adapter_down(&mut self) { - info!("status: {:?}", self); - match self.status { - DcOutStatus::On => { - self.status = DcOutStatus::WaitingOff; - } - DcOutStatus::WaitingOn(_) => { - self.status = DcOutStatus::Off; - } - DcOutStatus::TurningOff(seconds) => { - let seconds = seconds - 1; - if seconds > 0 { - self.status = DcOutStatus::TurningOff(seconds); - } else { - self.status = DcOutStatus::Off; - } - } - _ => {} - }; - } - - fn turn_off(&mut self) { - match self.status { - DcOutStatus::On => { - self.status = DcOutStatus::TurningOff(WAITING_OFF_SECONDS); - } - DcOutStatus::WaitingOff => { - self.status = DcOutStatus::TurningOff(WAITING_OFF_SECONDS); - } - DcOutStatus::WaitingOn(_) => { - self.status = DcOutStatus::Off; - } - DcOutStatus::TurningOff(seconds) => { - let seconds = seconds - 1; - if seconds > 0 { - self.status = DcOutStatus::TurningOff(seconds); - } else { - self.status = DcOutStatus::Off; - } - } - _ => {} - }; - } - - fn turn_on(&mut self) { - match self.status { - DcOutStatus::WaitingOff => { - self.status = DcOutStatus::On; - } - DcOutStatus::Off => { - self.status = DcOutStatus::WaitingOn(WAITING_OFF_SECONDS); - } - DcOutStatus::WaitingOn(seconds) => { - let seconds = seconds - 1; - if seconds > 0 { - self.status = DcOutStatus::WaitingOn(seconds); - } else { - self.status = DcOutStatus::On; - } - } - DcOutStatus::TurningOff(seconds) => { - let seconds = seconds - 1; - if seconds > 0 { - self.status = DcOutStatus::TurningOff(seconds); - } else { - self.status = DcOutStatus::On; - } - } - _ => {} - }; - } - pub fn to_json(&self) -> String { let status = match self.status { - DcOutStatus::WaitingOn(_) => "WaitingOn", - DcOutStatus::On => "On", - DcOutStatus::Off => "Off", - DcOutStatus::WaitingOff => "WaitingOff", - DcOutStatus::TurningOff(_) => "TurningOff", + ChargeStatus::Charging => "Charging", + ChargeStatus::Charged => "Charged", }; let pin_state = match self.pin_state { PinState::Low => "Low", PinState::High => "High", }; - let seconds: i16 = match self.status { - DcOutStatus::WaitingOn(seconds) => seconds.into(), - DcOutStatus::TurningOff(seconds) => seconds.into(), - _ => -1, - }; - json!({ "status": status, "pin_state": pin_state, "seconds": seconds }).to_string() + json!({ "status": status, "pin_state": pin_state}).to_string() } } -impl EspTypedEventSource for DcOutControllerState { +impl EspTypedEventSource for ChargeControllerState { fn source() -> *const c_types::c_char { b"Charge\0".as_ptr() as *const _ } } -impl EspTypedEventSerializer for DcOutControllerState { +impl EspTypedEventSerializer for ChargeControllerState { fn serialize( - event: &DcOutControllerState, + event: &ChargeControllerState, f: impl for<'a> FnOnce(&'a EspEventPostData) -> R, ) -> R { f(&unsafe { EspEventPostData::new(Self::source(), Self::event_id(), event) }) } } -impl EspTypedEventDeserializer for DcOutControllerState { +impl EspTypedEventDeserializer for ChargeControllerState { fn deserialize( data: &EspEventFetchData, - f: &mut impl for<'a> FnMut(&'a DcOutControllerState) -> R, + f: &mut impl for<'a> FnMut(&'a ChargeControllerState) -> R, ) -> R { f(unsafe { data.as_payload() }) } } -type DcOutPin = Gpio6; +type ChargeCtlPin = Gpio7; -pub struct DcOutController { - pub state: DcOutControllerState, +pub struct ChargeController { + pub state: ChargeControllerState, voltage_subscription: Option>>, - pin: Arc>, + pin: Arc>, } -impl DcOutController { +impl ChargeController { pub fn new() -> anyhow::Result { - let pin = unsafe { Gpio6::::new() } + let pin = unsafe { Gpio7::::new() } .into_output() .map_err(|err| anyhow::anyhow!("Make Gpio6 Into output Failed. {}", err))?; match EspBackgroundEventLoop::new(&Default::default()) { - Ok(eventloop) => unsafe { DC_OUT_STATE_EVENT_LOOP = Some(eventloop) }, + Ok(eventloop) => unsafe { CHARGE_STATE_EVENT_LOOP = Some(eventloop) }, Err(err) => anyhow::bail!("Init Event Loop failed. {:?}", err), } anyhow::Ok(Self { - state: DcOutControllerState::new(), + state: ChargeControllerState::new(), voltage_subscription: None, pin: Arc::new(Mutex::new(pin)), }) @@ -196,33 +107,39 @@ impl DcOutController { if let Some(event_loop) = unsafe { VOLTAGE_EVENTLOOP.as_mut() } { let voltage_subscription = event_loop .subscribe(move |obj: &VoltageDetectionWorker| { - if obj.adapter_voltage < 1000 { - if obj.battery_voltage < 1000 { - state.turn_off(); - } else { - state.handle_adapter_down(); + match state.status { + ChargeStatus::Charging => { + if obj.battery_voltage < 12600 { + state.status = ChargeStatus::Charging; + } else { + state.status = ChargeStatus::Charged; + } + } + ChargeStatus::Charged => { + if obj.battery_voltage < 10500 { + state.status = ChargeStatus::Charging; + } else { + state.status = ChargeStatus::Charged; + } } - } else { - state.turn_on(); } match pin.lock() { Ok(pin) => { - if let Err(err) = Self::output_ctl(state, pin) { + if let Err(err) = Self::output_ctl(&mut state, pin) { warn!("Put Control Pin State Failed. {}", err); } } Err(_) => todo!(), } - if let Some(event_loop) = unsafe { DC_OUT_STATE_EVENT_LOOP.as_mut() } { + if let Some(event_loop) = unsafe { CHARGE_STATE_EVENT_LOOP.as_mut() } { if let Err(err) = event_loop.post(&state, None) { warn!("Post DC Out Status Failed. {}", err); } } else { - warn!("DC_OUT_STATE_EVENT_LOOP is None"); + warn!("CHARGE_STATE_EVENT_LOOP is None"); } - debug!("status: {:?}", state); }) .map_err(|err| anyhow::anyhow!("Subscribe Voltage Failed. {}", err))?; self.voltage_subscription = Some(voltage_subscription); @@ -232,14 +149,14 @@ impl DcOutController { anyhow::Ok(()) } fn output_ctl( - mut state: DcOutControllerState, - mut pin: MutexGuard, + state: &mut ChargeControllerState, + mut pin: MutexGuard, ) -> anyhow::Result<()> { - if DcOutStatus::Off == state.status && state.pin_state == PinState::Low { + if ChargeStatus::Charging == state.status { pin.set_high() .map_err(|err| anyhow::anyhow!("Set DC Output Control Pin High Failed. {}", err))?; state.pin_state = PinState::High; - } else if DcOutStatus::On == state.status && state.pin_state == PinState::High { + } else if ChargeStatus::Charged == state.status { pin.set_low() .map_err(|err| anyhow::anyhow!("Set DC Output Control Pin Low Failed. {}", err))?; state.pin_state = PinState::Low; diff --git a/src/main.rs b/src/main.rs index 02c7b81..76e4e02 100644 --- a/src/main.rs +++ b/src/main.rs @@ -15,12 +15,13 @@ mod message_queue; mod time; mod voltage_detection; mod wifi; +mod charge_controller; use crate::{ beep::{ringtone, Beep}, dc_out_controller::{DcOutController, DcOutControllerState, DC_OUT_STATE_EVENT_LOOP}, message_queue::MqDto, - voltage_detection::{VoltageDetectionWorker, VOLTAGE_EVENTLOOP}, + voltage_detection::{VoltageDetectionWorker, VOLTAGE_EVENTLOOP}, charge_controller::{CHARGE_STATE_EVENT_LOOP, ChargeControllerState, ChargeController}, }; use crate::{ message_queue::MessageQueue, time::Time, voltage_detection::VoltageDetection, wifi::Internet, @@ -56,7 +57,7 @@ fn main() { blink.play(); }); - let mut voltage_detection = VoltageDetection::new(); + let voltage_detection = VoltageDetection::new(); voltage_detection.unwrap() .watching() @@ -77,6 +78,12 @@ fn main() { .watch() .expect("Can not watch for dc_out_controller"); + let mut charge_controller = ChargeController::new().expect("Can not get ChargeController instance"); + charge_controller + .watch() + .expect("Can not watch for charge_controller"); + + sleep(Duration::from_millis(100)); let mut _mq = MessageQueue::new(); @@ -91,6 +98,7 @@ fn main() { let _mq_tx_for_voltage = _mq.tx.clone(); let _mq_tx_for_dc_out_state = _mq.tx.clone(); + let _mq_tx_for_charge_state = _mq.tx.clone(); let _voltage_subscription; if let Some(voltage_event_loop) = unsafe { VOLTAGE_EVENTLOOP.as_mut() } { @@ -151,6 +159,29 @@ fn main() { panic!("DC_OUT_STATE_EVENT_LOOP is undefined!"); } + let _charge_state_subscription; + if let Some(charge_state_event_loop) = unsafe { CHARGE_STATE_EVENT_LOOP.as_mut() } { + _charge_state_subscription = charge_state_event_loop + .subscribe(move |message: &ChargeControllerState| { + match _mq_tx_for_charge_state.lock() { + Ok(tx) => { + let result = tx.send(MqDto { + topic: "charge_state".to_string(), + message: message.to_json(), + }); + + if let Err(err) = result { + warn!("send charge_state message failed. {}", err) + } + } + Err(err) => warn!("send charge_state to mq message failed. {}", err), + } + }) + .expect(" Listening Event Loop Failed"); + } else { + panic!("CHARGE_STATE_EVENT_LOOP is undefined!"); + } + loop { sleep(Duration::from_millis(100)); }